runwork 0.20.0 → 0.21.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -943,6 +943,58 @@ var init_store = __esm(() => {
943
943
  CREDENTIALS_FILE = join2(RUNWORK_DIR, ".credentials");
944
944
  });
945
945
 
946
+ // src/utils/workspace-state.ts
947
+ import { join as join3 } from "path";
948
+ import { homedir as homedir2 } from "os";
949
+ function storePath() {
950
+ return join3(homedir2(), ".runwork", "workspaces.json");
951
+ }
952
+ function readFile() {
953
+ const parsed = readJsonOrNull(storePath());
954
+ if (parsed && parsed.workspaces && typeof parsed.workspaces === "object")
955
+ return parsed;
956
+ return { workspaces: {} };
957
+ }
958
+ function loadWorkspaceRecord(workspaceId) {
959
+ return readFile().workspaces[workspaceId] ?? {};
960
+ }
961
+ function updateWorkspaceRecord(workspaceId, patch) {
962
+ if (!workspaceId)
963
+ return;
964
+ const file = readFile();
965
+ file.workspaces[workspaceId] = { ...file.workspaces[workspaceId], ...patch };
966
+ writeJsonAtomic(storePath(), file);
967
+ }
968
+ function clearParkedState(workspaceId) {
969
+ const file = readFile();
970
+ const record = file.workspaces[workspaceId];
971
+ if (!record?.parked)
972
+ return;
973
+ delete record.parked;
974
+ writeJsonAtomic(storePath(), file);
975
+ }
976
+ function forgetWorkspaceSelection() {
977
+ const statePath = join3(homedir2(), ".runwork", "setup.json");
978
+ const state = readJsonOrNull(statePath);
979
+ if (!state)
980
+ return false;
981
+ if (!state.workspaceId && !state.workspaceName && !state.workspaceSlug)
982
+ return false;
983
+ const next = { ...state };
984
+ delete next.workspaceId;
985
+ delete next.workspaceName;
986
+ delete next.workspaceSlug;
987
+ try {
988
+ writeJsonAtomic(statePath, next);
989
+ return true;
990
+ } catch {
991
+ return false;
992
+ }
993
+ }
994
+ var init_workspace_state = __esm(() => {
995
+ init_atomic_json();
996
+ });
997
+
946
998
  // src/utils/subprocess.ts
947
999
  import {
948
1000
  execFileSync as cpExecFileSync,
@@ -1197,18 +1249,32 @@ function extractBaseUrl(loginUrl) {
1197
1249
  return DEFAULT_BASE_URL2;
1198
1250
  }
1199
1251
  }
1252
+ function forgetWorkspaceIfAccountChanged(previousEmail, nextEmail) {
1253
+ if (!previousEmail || previousEmail === nextEmail)
1254
+ return;
1255
+ forgetWorkspaceSelection();
1256
+ }
1200
1257
  async function pollAndSave(client, sessionId, baseUrl) {
1201
- const maxAttempts = 360;
1202
- const pollInterval = 5000;
1203
- for (let i = 0;i < maxAttempts; i++) {
1204
- await new Promise((resolve) => setTimeout(resolve, pollInterval));
1258
+ const deadline = Date.now() + 1800000;
1259
+ const EAGER_INTERVAL = 1000;
1260
+ const EAGER_WINDOW = 30000;
1261
+ const SETTLED_INTERVAL = 5000;
1262
+ const startedAt = Date.now();
1263
+ const previousEmail = getCredentials()?.email;
1264
+ for (;; ) {
1205
1265
  const result = await client.pollLogin(sessionId);
1206
1266
  if (result) {
1267
+ forgetWorkspaceIfAccountChanged(previousEmail, result.email);
1207
1268
  saveCredentials(result);
1208
1269
  await configureGitCredentials(result.baseUrl || baseUrl);
1209
1270
  console.log(`Logged in as ${result.email}`);
1210
1271
  return result;
1211
1272
  }
1273
+ const remaining = deadline - Date.now();
1274
+ if (remaining <= 0)
1275
+ break;
1276
+ const interval = Date.now() - startedAt < EAGER_WINDOW ? EAGER_INTERVAL : SETTLED_INTERVAL;
1277
+ await new Promise((resolve) => setTimeout(resolve, Math.min(interval, remaining)));
1212
1278
  }
1213
1279
  console.error("Login timed out. Please try again.");
1214
1280
  process.exit(1);
@@ -1217,6 +1283,7 @@ var DEFAULT_BASE_URL2 = "https://runwork.ai";
1217
1283
  var init_login_flow = __esm(() => {
1218
1284
  init_client();
1219
1285
  init_store();
1286
+ init_workspace_state();
1220
1287
  init_credentials();
1221
1288
  });
1222
1289
 
@@ -1315,7 +1382,7 @@ var init_identity = __esm(() => {
1315
1382
  // src/git/preflight.ts
1316
1383
  import { existsSync as existsSync4 } from "fs";
1317
1384
  import { win32 as winPath } from "path";
1318
- import { homedir as homedir2 } from "os";
1385
+ import { homedir as homedir3 } from "os";
1319
1386
  function tryRun(bin) {
1320
1387
  try {
1321
1388
  const out = execFileSync(bin, ["--version"], { stdio: ["ignore", "pipe", "pipe"] });
@@ -1377,7 +1444,7 @@ function canonicalGitCandidates() {
1377
1444
  paths.push(winPath.join(...parts));
1378
1445
  }
1379
1446
  };
1380
- const home = homedir2();
1447
+ const home = homedir3();
1381
1448
  push(process.env.ProgramFiles, "Git", "cmd", "git.exe");
1382
1449
  push(process.env["ProgramFiles(x86)"], "Git", "cmd", "git.exe");
1383
1450
  push(process.env.LOCALAPPDATA, "Programs", "Git", "cmd", "git.exe");
@@ -1570,7 +1637,7 @@ async function resolveApp(client, nameOrId, workspaceId) {
1570
1637
 
1571
1638
  // src/utils/ignore-matcher.ts
1572
1639
  import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
1573
- import { basename, join as join3 } from "path";
1640
+ import { basename, join as join4 } from "path";
1574
1641
  function defaultIgnoreSets() {
1575
1642
  return {
1576
1643
  dirs: new Set(DEFAULT_DIR_NAMES),
@@ -1610,7 +1677,7 @@ function parseGitignoreContent(content) {
1610
1677
  return { dirs, files };
1611
1678
  }
1612
1679
  function loadGitignoreFromDir(dir) {
1613
- const path = join3(dir, ".gitignore");
1680
+ const path = join4(dir, ".gitignore");
1614
1681
  if (!existsSync5(path))
1615
1682
  return { dirs: new Set, files: new Set };
1616
1683
  try {
@@ -1671,7 +1738,7 @@ var init_ignore_matcher = __esm(() => {
1671
1738
  // src/template/manifest.ts
1672
1739
  import { createHash } from "crypto";
1673
1740
  import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync6, readdirSync, mkdirSync as mkdirSync2 } from "fs";
1674
- import { join as join4, relative, sep } from "path";
1741
+ import { join as join5, relative, sep } from "path";
1675
1742
  function sha256(data) {
1676
1743
  return "sha256:" + createHash("sha256").update(data).digest("hex");
1677
1744
  }
@@ -1688,7 +1755,7 @@ function walkDir(dir, base, sets) {
1688
1755
  if (dotIndex >= 0 && sets.extensions.has(entry.name.slice(dotIndex)))
1689
1756
  continue;
1690
1757
  }
1691
- const fullPath = join4(dir, entry.name);
1758
+ const fullPath = join5(dir, entry.name);
1692
1759
  if (entry.isDirectory()) {
1693
1760
  results.push(...walkDir(fullPath, base, sets));
1694
1761
  } else if (entry.isFile()) {
@@ -1702,20 +1769,20 @@ async function generateManifest(dir) {
1702
1769
  const sets = buildIgnoreSets(dir);
1703
1770
  const allFiles = walkDir(dir, dir, sets);
1704
1771
  for (const relPath of allFiles) {
1705
- const content = readFileSync5(join4(dir, relPath));
1772
+ const content = readFileSync5(join5(dir, relPath));
1706
1773
  files[relPath] = sha256(content);
1707
1774
  }
1708
1775
  return { version: 1, files };
1709
1776
  }
1710
1777
  async function saveManifest(dir, manifest) {
1711
- const manifestDir = join4(dir, ".runwork");
1778
+ const manifestDir = join5(dir, ".runwork");
1712
1779
  if (!existsSync6(manifestDir)) {
1713
1780
  mkdirSync2(manifestDir, { recursive: true });
1714
1781
  }
1715
- writeFileSync2(join4(manifestDir, "template-manifest.json"), JSON.stringify(manifest, null, 2));
1782
+ writeFileSync2(join5(manifestDir, "template-manifest.json"), JSON.stringify(manifest, null, 2));
1716
1783
  }
1717
1784
  async function loadManifest(dir) {
1718
- const manifestPath = join4(dir, ".runwork", "template-manifest.json");
1785
+ const manifestPath = join5(dir, ".runwork", "template-manifest.json");
1719
1786
  if (!existsSync6(manifestPath))
1720
1787
  return null;
1721
1788
  try {
@@ -1752,7 +1819,7 @@ async function detectUserEdits(dir, manifest) {
1752
1819
  continue;
1753
1820
  const expectedHash = manifest.files[relPath];
1754
1821
  if (expectedHash) {
1755
- const content = readFileSync5(join4(dir, relPath));
1822
+ const content = readFileSync5(join5(dir, relPath));
1756
1823
  if (sha256(content) === expectedHash)
1757
1824
  continue;
1758
1825
  }
@@ -1774,7 +1841,7 @@ async function detectUserEdits(dir, manifest) {
1774
1841
  continue;
1775
1842
  if (trackedFiles.has(relPath))
1776
1843
  continue;
1777
- const filePath = join4(dir, relPath);
1844
+ const filePath = join5(dir, relPath);
1778
1845
  try {
1779
1846
  const content = readFileSync5(filePath);
1780
1847
  if (sha256(content) !== expectedHash) {
@@ -1791,7 +1858,7 @@ var init_manifest = __esm(() => {
1791
1858
 
1792
1859
  // src/utils/zip.ts
1793
1860
  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";
1861
+ import { join as join6, dirname as dirname2, relative as relative2, sep as sep2 } from "path";
1795
1862
  import { unzipSync, zipSync } from "fflate";
1796
1863
  function ensureDirSync(dir) {
1797
1864
  try {
@@ -1804,7 +1871,7 @@ function ensureDirSync(dir) {
1804
1871
  function extractZip(zipData, targetDir) {
1805
1872
  const files = unzipSync(new Uint8Array(zipData));
1806
1873
  for (const [path, data] of Object.entries(files)) {
1807
- const fullPath = join5(targetDir, path);
1874
+ const fullPath = join6(targetDir, path);
1808
1875
  if (path.endsWith("/")) {
1809
1876
  ensureDirSync(fullPath);
1810
1877
  continue;
@@ -1817,7 +1884,7 @@ function createZipFromDir(sourceDir, outputPath) {
1817
1884
  const files = {};
1818
1885
  const walk = (dir) => {
1819
1886
  for (const entry of readdirSync2(dir)) {
1820
- const absPath = join5(dir, entry);
1887
+ const absPath = join6(dir, entry);
1821
1888
  const stats = statSync(absPath);
1822
1889
  if (stats.isDirectory()) {
1823
1890
  walk(absPath);
@@ -1836,14 +1903,14 @@ var init_zip = () => {};
1836
1903
 
1837
1904
  // src/utils/fs.ts
1838
1905
  import { readdirSync as readdirSync3, rmSync as rmSync2 } from "fs";
1839
- import { join as join6, relative as relative3, sep as sep3 } from "path";
1906
+ import { join as join7, relative as relative3, sep as sep3 } from "path";
1840
1907
  function removeNestedGitDirs(rootDir) {
1841
1908
  const entries = readdirSync3(rootDir, { recursive: true, withFileTypes: true });
1842
1909
  for (const entry of entries) {
1843
1910
  if (entry.name !== ".git" || !entry.isDirectory())
1844
1911
  continue;
1845
1912
  const parentPath = "parentPath" in entry ? entry.parentPath : entry.path;
1846
- const fullPath = join6(parentPath, entry.name);
1913
+ const fullPath = join7(parentPath, entry.name);
1847
1914
  const rel = relative3(rootDir, fullPath);
1848
1915
  const depth = rel.split(sep3).length;
1849
1916
  if (depth >= 2) {
@@ -1854,9 +1921,9 @@ function removeNestedGitDirs(rootDir) {
1854
1921
  var init_fs = () => {};
1855
1922
 
1856
1923
  // src/ui/banner.ts
1857
- import { homedir as homedir3 } from "os";
1924
+ import { homedir as homedir4 } from "os";
1858
1925
  function prettyPath(dir) {
1859
- const home = homedir3();
1926
+ const home = homedir4();
1860
1927
  if (dir === home)
1861
1928
  return "~";
1862
1929
  if (dir.startsWith(home + "/"))
@@ -2126,8 +2193,8 @@ __export(exports_init, {
2126
2193
  });
2127
2194
  import { Command as Command2 } from "commander";
2128
2195
  import { writeFileSync as writeFileSync4, existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
2129
- import { join as join7, resolve } from "path";
2130
- import { homedir as homedir4 } from "os";
2196
+ import { join as join8, resolve } from "path";
2197
+ import { homedir as homedir5 } from "os";
2131
2198
  async function execInit(client, appName, workspace, options = {}, creds) {
2132
2199
  const app = await client.initApp(workspace.id, appName);
2133
2200
  const slug = app.slug || appName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
@@ -2135,7 +2202,7 @@ async function execInit(client, appName, workspace, options = {}, creds) {
2135
2202
  if (!options.here && !existsSync7(parentDir)) {
2136
2203
  mkdirSync4(parentDir, { recursive: true });
2137
2204
  }
2138
- const dir = join7(parentDir, slug);
2205
+ const dir = join8(parentDir, slug);
2139
2206
  if (existsSync7(dir)) {
2140
2207
  console.error(`Directory "${dir}" already exists.`);
2141
2208
  process.exit(1);
@@ -2162,8 +2229,8 @@ async function execInit(client, appName, workspace, options = {}, creds) {
2162
2229
  appId: app.id,
2163
2230
  appName: app.name
2164
2231
  };
2165
- writeFileSync4(join7(dir, ".runwork.json"), JSON.stringify(config, null, 2));
2166
- if (!existsSync7(join7(dir, ".git"))) {
2232
+ writeFileSync4(join8(dir, ".runwork.json"), JSON.stringify(config, null, 2));
2233
+ if (!existsSync7(join8(dir, ".git"))) {
2167
2234
  try {
2168
2235
  execFileSync("git", ["init"], { cwd: dir, stdio: "pipe" });
2169
2236
  } catch (err) {
@@ -2181,8 +2248,8 @@ async function execInit(client, appName, workspace, options = {}, creds) {
2181
2248
  } catch {
2182
2249
  execFileSync("git", ["remote", "set-url", "runwork", remoteUrl], { cwd: dir, stdio: "pipe" });
2183
2250
  }
2184
- if (!existsSync7(join7(dir, ".gitignore"))) {
2185
- writeFileSync4(join7(dir, ".gitignore"), `node_modules/
2251
+ if (!existsSync7(join8(dir, ".gitignore"))) {
2252
+ writeFileSync4(join8(dir, ".gitignore"), `node_modules/
2186
2253
  .runwork/
2187
2254
  .dev.vars
2188
2255
  `);
@@ -2273,7 +2340,7 @@ var init_init = __esm(() => {
2273
2340
  init_fs();
2274
2341
  init_banner();
2275
2342
  init_agent_guidance();
2276
- DEFAULT_APPS_DIR = join7(homedir4(), ".runwork", "apps");
2343
+ DEFAULT_APPS_DIR = join8(homedir5(), ".runwork", "apps");
2277
2344
  initCommand = new Command2("init").alias("create").description("Create a new Runwork app").argument("[name]", "App name").option("--workspace <name-or-id>", "Workspace name or ID (skips interactive selection)").option("--here", `Scaffold in the current directory instead of ${DEFAULT_APPS_DIR}/<slug>`).action(async (name, options) => {
2278
2345
  await runCreateFlow(name, options?.workspace, { here: options?.here });
2279
2346
  });
@@ -2435,7 +2502,7 @@ __export(exports_clone, {
2435
2502
  });
2436
2503
  import { Command as Command3 } from "commander";
2437
2504
  import { writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, existsSync as existsSync8 } from "fs";
2438
- import { join as join8, resolve as resolve2 } from "path";
2505
+ import { join as join9, resolve as resolve2 } from "path";
2439
2506
  async function execClone(client, app, directory, creds) {
2440
2507
  const slug = app.slug || app.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
2441
2508
  const dir = directory || slug;
@@ -2452,7 +2519,7 @@ async function execClone(client, app, directory, creds) {
2452
2519
  }
2453
2520
  const manifest = await generateManifest(dir);
2454
2521
  await saveManifest(dir, manifest);
2455
- if (!existsSync8(join8(dir, ".git"))) {
2522
+ if (!existsSync8(join9(dir, ".git"))) {
2456
2523
  try {
2457
2524
  execFileSync("git", ["init"], { cwd: dir, stdio: "pipe" });
2458
2525
  } catch (err) {
@@ -2489,11 +2556,11 @@ async function execClone(client, app, directory, creds) {
2489
2556
  appId: app.id,
2490
2557
  appName: app.name
2491
2558
  };
2492
- writeFileSync5(join8(dir, ".runwork.json"), JSON.stringify(config, null, 2));
2559
+ writeFileSync5(join9(dir, ".runwork.json"), JSON.stringify(config, null, 2));
2493
2560
  try {
2494
2561
  const { skill } = await client.getAppSkill(app.id);
2495
2562
  if (skill) {
2496
- writeFileSync5(join8(dir, "SKILL.md"), skill, "utf-8");
2563
+ writeFileSync5(join9(dir, "SKILL.md"), skill, "utf-8");
2497
2564
  }
2498
2565
  } catch {}
2499
2566
  return {
@@ -2627,7 +2694,7 @@ App "${cloneResult.appName}" cloned to ${cloneResult.directory}`);
2627
2694
  // src/git/auto-commit.ts
2628
2695
  import { readFileSync as readFileSync7 } from "fs";
2629
2696
  import { watch } from "chokidar";
2630
- import { join as join9, relative as relative4 } from "path";
2697
+ import { join as join10, relative as relative4 } from "path";
2631
2698
  async function watchAndAutoCommit(directory, client, appId, callbacks) {
2632
2699
  activeCallbacks = callbacks;
2633
2700
  const ignoreSets = buildIgnoreSets(directory);
@@ -2687,7 +2754,7 @@ async function executeFastSync(directory, client, appId) {
2687
2754
  if (BINARY_EXTENSIONS.has(ext.toLowerCase()))
2688
2755
  continue;
2689
2756
  try {
2690
- const contents = readFileSync7(join9(directory, filePath), "utf-8");
2757
+ const contents = readFileSync7(join10(directory, filePath), "utf-8");
2691
2758
  files.push({ filePath, fileContents: contents });
2692
2759
  } catch {}
2693
2760
  }
@@ -2854,7 +2921,7 @@ var init_auto_commit = __esm(() => {
2854
2921
 
2855
2922
  // src/git/sync.ts
2856
2923
  import { unlinkSync as unlinkSync2 } from "fs";
2857
- import { join as join10 } from "path";
2924
+ import { join as join11 } from "path";
2858
2925
  function hasCommits(cwd) {
2859
2926
  try {
2860
2927
  execFileSync("git", ["rev-parse", "HEAD"], { cwd, stdio: "pipe" });
@@ -2888,7 +2955,7 @@ function removeConflictingUntrackedFiles(cwd) {
2888
2955
  for (const file of remoteFiles) {
2889
2956
  if (untracked.has(file)) {
2890
2957
  try {
2891
- unlinkSync2(join10(cwd, file));
2958
+ unlinkSync2(join11(cwd, file));
2892
2959
  } catch {}
2893
2960
  }
2894
2961
  }
@@ -2982,11 +3049,11 @@ var init_sync = __esm(() => {
2982
3049
 
2983
3050
  // src/git/critical-files.ts
2984
3051
  import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync9 } from "fs";
2985
- import { join as join11 } from "path";
3052
+ import { join as join12 } from "path";
2986
3053
  function snapshotCriticalFiles(cwd) {
2987
3054
  const snapshots = [];
2988
3055
  for (const rel of CRITICAL_FILES) {
2989
- const abs = join11(cwd, rel);
3056
+ const abs = join12(cwd, rel);
2990
3057
  if (!existsSync9(abs))
2991
3058
  continue;
2992
3059
  try {
@@ -2998,7 +3065,7 @@ function snapshotCriticalFiles(cwd) {
2998
3065
  function restoreMissingCriticalFiles(cwd, snapshots) {
2999
3066
  const restored = [];
3000
3067
  for (const snap of snapshots) {
3001
- const abs = join11(cwd, snap.path);
3068
+ const abs = join12(cwd, snap.path);
3002
3069
  if (existsSync9(abs))
3003
3070
  continue;
3004
3071
  try {
@@ -3042,7 +3109,7 @@ function buildStartupSyncSummary(input) {
3042
3109
 
3043
3110
  // src/logs/tailer.ts
3044
3111
  import { appendFileSync, mkdirSync as mkdirSync6, writeFileSync as writeFileSync7 } from "fs";
3045
- import { join as join12, dirname as dirname3 } from "path";
3112
+ import { join as join13, dirname as dirname3 } from "path";
3046
3113
  function formatTime() {
3047
3114
  const now = new Date;
3048
3115
  return [
@@ -3090,7 +3157,7 @@ function startLogTailer(options) {
3090
3157
  toFile,
3091
3158
  intervalMs = 5000
3092
3159
  } = options;
3093
- const logFilePath = join12(projectDir, LOG_FILE);
3160
+ const logFilePath = join13(projectDir, LOG_FILE);
3094
3161
  if (toFile) {
3095
3162
  mkdirSync6(dirname3(logFilePath), { recursive: true });
3096
3163
  writeFileSync7(logFilePath, `# Runwork dev logs - started ${new Date().toISOString()}
@@ -4804,8 +4871,8 @@ export declare class WorkspaceContext {
4804
4871
  /**
4805
4872
  * Send a notification to a workspace user
4806
4873
  * Can only send to verified workspace members
4807
- * The platform wraps your content in a standard notification template
4808
- * (e.g., "You have a new notification from [App Name]")
4874
+ * The platform wraps your content in a standard notification template and
4875
+ * sends it from your app's name, using \`title\` as the subject line
4809
4876
  *
4810
4877
  * @example
4811
4878
  * \`\`\`typescript
@@ -7503,11 +7570,11 @@ export {};
7503
7570
 
7504
7571
  // src/types-manager.ts
7505
7572
  import { existsSync as existsSync14, mkdirSync as mkdirSync9, readdirSync as readdirSync4, copyFileSync, writeFileSync as writeFileSync9 } from "fs";
7506
- import { join as join14 } from "path";
7573
+ import { join as join15 } from "path";
7507
7574
  async function populateTypes(projectDir) {
7508
- const typesDir = join14(projectDir, TYPES_DIR);
7575
+ const typesDir = join15(projectDir, TYPES_DIR);
7509
7576
  mkdirSync9(typesDir, { recursive: true });
7510
- const frameworkDist = join14(projectDir, "node_modules/@runworkai/framework/dist");
7577
+ const frameworkDist = join15(projectDir, "node_modules/@runworkai/framework/dist");
7511
7578
  if (existsSync14(frameworkDist)) {
7512
7579
  copyDtsFiles(frameworkDist, typesDir);
7513
7580
  console.log("Types populated from node_modules/@runworkai/framework");
@@ -7516,7 +7583,7 @@ async function populateTypes(projectDir) {
7516
7583
  const typeEntries = Object.entries(BUNDLED_TYPES);
7517
7584
  if (typeEntries.length > 0) {
7518
7585
  for (const [filename, content] of typeEntries) {
7519
- writeFileSync9(join14(typesDir, filename), content);
7586
+ writeFileSync9(join15(typesDir, filename), content);
7520
7587
  }
7521
7588
  console.log("Types populated from bundled types");
7522
7589
  return;
@@ -7527,7 +7594,7 @@ function copyDtsFiles(srcDir, destDir) {
7527
7594
  const files = readdirSync4(srcDir);
7528
7595
  for (const file of files) {
7529
7596
  if (file.endsWith(".d.ts")) {
7530
- copyFileSync(join14(srcDir, file), join14(destDir, file));
7597
+ copyFileSync(join15(srcDir, file), join15(destDir, file));
7531
7598
  }
7532
7599
  }
7533
7600
  }
@@ -7645,7 +7712,7 @@ function createKeyboardListener() {
7645
7712
  }
7646
7713
 
7647
7714
  // src/generated/version.ts
7648
- var VERSION = "0.20.0";
7715
+ var VERSION = "0.21.1";
7649
7716
 
7650
7717
  // src/commands/dev.ts
7651
7718
  var exports_dev = {};
@@ -7655,12 +7722,12 @@ __export(exports_dev, {
7655
7722
  });
7656
7723
  import { Command as Command4, Option } from "commander";
7657
7724
  import { readFileSync as readFileSync12, writeFileSync as writeFileSync10, existsSync as existsSync15 } from "fs";
7658
- import { join as join15 } from "path";
7725
+ import { join as join16 } from "path";
7659
7726
  async function populateSkill(projectDir, client, appId) {
7660
7727
  try {
7661
7728
  const { skill } = await client.getAppSkill(appId);
7662
7729
  if (skill) {
7663
- writeFileSync10(join15(projectDir, "SKILL.md"), skill, "utf-8");
7730
+ writeFileSync10(join16(projectDir, "SKILL.md"), skill, "utf-8");
7664
7731
  }
7665
7732
  } catch {}
7666
7733
  }
@@ -8682,9 +8749,9 @@ import { readFileSync as readFileSync15, existsSync as existsSync18 } from "fs";
8682
8749
  // src/deploy/deploy-state.ts
8683
8750
  init_subprocess();
8684
8751
  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";
8752
+ import { dirname as dirname4, join as join17 } from "path";
8686
8753
  function deployStatePath(cwd) {
8687
- return join16(cwd, ".runwork", "last-deploy.json");
8754
+ return join17(cwd, ".runwork", "last-deploy.json");
8688
8755
  }
8689
8756
  function getHeadSha(cwd) {
8690
8757
  try {
@@ -8735,7 +8802,7 @@ function getDeploySummary(cwd) {
8735
8802
  // src/deploy/deploy-status.ts
8736
8803
  init_session();
8737
8804
  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";
8805
+ import { dirname as dirname5, join as join18 } from "path";
8739
8806
  function evaluateDeployStatus(status, deps = {}) {
8740
8807
  if (status.state !== "in-progress") {
8741
8808
  return { status, effectiveState: status.state };
@@ -8751,10 +8818,10 @@ function evaluateDeployStatus(status, deps = {}) {
8751
8818
  return { status, effectiveState: "in-progress" };
8752
8819
  }
8753
8820
  function statusPath(cwd) {
8754
- return join17(cwd, ".runwork", "deploy-status.json");
8821
+ return join18(cwd, ".runwork", "deploy-status.json");
8755
8822
  }
8756
8823
  function deployLogPath(cwd) {
8757
- return join17(cwd, ".runwork", "deploy-stdout.log");
8824
+ return join18(cwd, ".runwork", "deploy-stdout.log");
8758
8825
  }
8759
8826
  function writeDeployStatus(cwd, status) {
8760
8827
  const path2 = statusPath(cwd);
@@ -8786,7 +8853,7 @@ init_session();
8786
8853
  init_detach();
8787
8854
  import * as fs5 from "fs";
8788
8855
  import * as child_process2 from "child_process";
8789
- import { join as join18 } from "path";
8856
+ import { join as join19 } from "path";
8790
8857
  var DEPLOY_DETACHED_CHILD_FLAG = "--internal-detached-deploy-child";
8791
8858
  function isInternalDeployChild(argv = process.argv) {
8792
8859
  return argv.includes(DEPLOY_DETACHED_CHILD_FLAG);
@@ -8802,10 +8869,10 @@ function buildDeployChildArgs(parentArgv) {
8802
8869
  return [...filtered, DEPLOY_DETACHED_CHILD_FLAG];
8803
8870
  }
8804
8871
  function spawnDetachedDeploy(childArgs, cwd) {
8805
- const dir = join18(cwd, ".runwork");
8872
+ const dir = join19(cwd, ".runwork");
8806
8873
  fs5.mkdirSync(dir, { recursive: true });
8807
- const stdoutFd = fs5.openSync(join18(dir, "deploy-stdout.log"), "w");
8808
- const stderrFd = fs5.openSync(join18(dir, "deploy-stderr.log"), "w");
8874
+ const stdoutFd = fs5.openSync(join19(dir, "deploy-stdout.log"), "w");
8875
+ const stderrFd = fs5.openSync(join19(dir, "deploy-stderr.log"), "w");
8809
8876
  try {
8810
8877
  const proc = child_process2.spawn(process.execPath, childArgs, {
8811
8878
  cwd,
@@ -9443,7 +9510,7 @@ import { Command as Command8 } from "commander";
9443
9510
  import { execFileSync as execFileSync2 } from "child_process";
9444
9511
  import { platform as osPlatform, tmpdir as tmpdir2 } from "os";
9445
9512
  import { mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync13, rmSync as rmSync3 } from "fs";
9446
- import { join as join19 } from "path";
9513
+ import { join as join20 } from "path";
9447
9514
  var BASE_URL = "https://runwork.ai";
9448
9515
  var LATEST_JSON_URL = `${BASE_URL}/cli/latest.json`;
9449
9516
  var INSTALL_SH_URL = `${BASE_URL}/install.sh`;
@@ -9494,8 +9561,8 @@ Upgrading via PowerShell installer...
9494
9561
  throw new Error(`Failed to download install.ps1: HTTP ${response2.status}`);
9495
9562
  }
9496
9563
  const script2 = await response2.text();
9497
- const tmpDir = mkdtempSync2(join19(tmpdir2(), "runwork-upgrade-"));
9498
- const scriptPath = join19(tmpDir, "install.ps1");
9564
+ const tmpDir = mkdtempSync2(join20(tmpdir2(), "runwork-upgrade-"));
9565
+ const scriptPath = join20(tmpDir, "install.ps1");
9499
9566
  try {
9500
9567
  writeFileSync13(scriptPath, script2);
9501
9568
  execFileSync2("powershell", ["-NoProfile", "-ExecutionPolicy", "Bypass", "-File", scriptPath], { stdio: "inherit" });
@@ -9651,6 +9718,7 @@ Upgrade failed: ${message}`);
9651
9718
  // src/commands/logout.ts
9652
9719
  init_store();
9653
9720
  init_credentials();
9721
+ init_workspace_state();
9654
9722
  import { Command as Command9 } from "commander";
9655
9723
  var logoutCommand = new Command9("logout").description("Remove stored Runwork credentials").action(async () => {
9656
9724
  const creds = getCredentials();
@@ -9658,6 +9726,7 @@ var logoutCommand = new Command9("logout").description("Remove stored Runwork cr
9658
9726
  await removeGitCredentials(creds.baseUrl);
9659
9727
  }
9660
9728
  clearCredentials();
9729
+ forgetWorkspaceSelection();
9661
9730
  console.log("Logged out.");
9662
9731
  });
9663
9732
 
@@ -10193,7 +10262,7 @@ var openCommand = new Command11("open").description("Open app preview or dashboa
10193
10262
  init_agent_guidance();
10194
10263
  import { Command as Command12 } from "commander";
10195
10264
  import { readFileSync as readFileSync21, existsSync as existsSync24 } from "fs";
10196
- import { join as join20 } from "path";
10265
+ import { join as join21 } from "path";
10197
10266
 
10198
10267
  // src/utils/app-info.ts
10199
10268
  init_colors();
@@ -10393,7 +10462,7 @@ function tryReadConfig() {
10393
10462
  }
10394
10463
  }
10395
10464
  function readBlueprint(cwd) {
10396
- const blueprintPath = join20(cwd, "blueprint.json");
10465
+ const blueprintPath = join21(cwd, "blueprint.json");
10397
10466
  if (!existsSync24(blueprintPath))
10398
10467
  return null;
10399
10468
  try {
@@ -10742,6 +10811,110 @@ init_store();
10742
10811
  init_client();
10743
10812
  import { Command as Command13 } from "commander";
10744
10813
  import { readFileSync as readFileSync22, existsSync as existsSync25 } from "fs";
10814
+ // ../../shared/skill/skill-canonical.ts
10815
+ function toSkillSlug(value) {
10816
+ return value.trim().replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
10817
+ }
10818
+ function quoteYamlValue(value) {
10819
+ if (value === "")
10820
+ return '""';
10821
+ if (/[:#[\]{}|>&*!,?'"]/.test(value) || value !== value.trim()) {
10822
+ const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
10823
+ return `"${escaped}"`;
10824
+ }
10825
+ return value;
10826
+ }
10827
+ function unquoteYamlValue(raw) {
10828
+ const value = raw.trim();
10829
+ if (value.length >= 2) {
10830
+ const first = value[0];
10831
+ const last = value[value.length - 1];
10832
+ if (first === '"' && last === '"') {
10833
+ return value.slice(1, -1).replace(/\\(["\\])/g, "$1");
10834
+ }
10835
+ if (first === "'" && last === "'") {
10836
+ return value.slice(1, -1);
10837
+ }
10838
+ }
10839
+ return value;
10840
+ }
10841
+ function parseSkillMd(content) {
10842
+ const lines = content.split(`
10843
+ `);
10844
+ if (lines[0]?.trim() !== "---") {
10845
+ const rawName = lines[0]?.replace(/^#\s*/, "").trim() || "Untitled Skill";
10846
+ return {
10847
+ frontmatter: {
10848
+ name: toSkillSlug(rawName) || "untitled-skill",
10849
+ description: ""
10850
+ },
10851
+ orderedKeys: [],
10852
+ body: content,
10853
+ hadFrontmatter: false
10854
+ };
10855
+ }
10856
+ let closingIndex = -1;
10857
+ for (let i = 1;i < lines.length; i++) {
10858
+ if (lines[i]?.trim() === "---") {
10859
+ closingIndex = i;
10860
+ break;
10861
+ }
10862
+ }
10863
+ if (closingIndex === -1) {
10864
+ return {
10865
+ frontmatter: { name: "untitled-skill", description: "" },
10866
+ orderedKeys: [],
10867
+ body: content,
10868
+ hadFrontmatter: false
10869
+ };
10870
+ }
10871
+ const frontmatterEntries = {};
10872
+ const orderedKeys = [];
10873
+ for (let i = 1;i < closingIndex; i++) {
10874
+ const line = lines[i];
10875
+ if (!line)
10876
+ continue;
10877
+ const colonIndex = line.indexOf(":");
10878
+ if (colonIndex > 0) {
10879
+ const key = line.slice(0, colonIndex).trim();
10880
+ const value = unquoteYamlValue(line.slice(colonIndex + 1));
10881
+ if (!(key in frontmatterEntries))
10882
+ orderedKeys.push(key);
10883
+ frontmatterEntries[key] = value;
10884
+ }
10885
+ }
10886
+ const body = lines.slice(closingIndex + 1).join(`
10887
+ `).trim();
10888
+ return {
10889
+ frontmatter: {
10890
+ ...frontmatterEntries,
10891
+ name: toSkillSlug(frontmatterEntries.name || "") || "untitled-skill",
10892
+ description: frontmatterEntries.description || ""
10893
+ },
10894
+ orderedKeys,
10895
+ body,
10896
+ hadFrontmatter: true
10897
+ };
10898
+ }
10899
+ function buildSkillMd(parts) {
10900
+ const lines = [
10901
+ "---",
10902
+ `name: ${toSkillSlug(parts.name) || "untitled-skill"}`,
10903
+ `description: ${quoteYamlValue(parts.description ?? "")}`
10904
+ ];
10905
+ if (parts.extra) {
10906
+ for (const [key, value] of Object.entries(parts.extra)) {
10907
+ if (key === "name" || key === "description")
10908
+ continue;
10909
+ lines.push(`${key}: ${quoteYamlValue(value)}`);
10910
+ }
10911
+ }
10912
+ lines.push("---", "", (parts.body ?? "").trim());
10913
+ return lines.join(`
10914
+ `);
10915
+ }
10916
+
10917
+ // src/commands/skills.ts
10745
10918
  function truncate(text2, max) {
10746
10919
  if (!text2)
10747
10920
  return "";
@@ -10808,6 +10981,23 @@ async function readStdin2() {
10808
10981
  }
10809
10982
  return Buffer.concat(chunks).toString("utf-8");
10810
10983
  }
10984
+ function buildSkillPushPayload(fileContent, nameArg) {
10985
+ const parsed = parseSkillMd(fileContent);
10986
+ const docName = parsed.hadFrontmatter && parsed.frontmatter.name !== "untitled-skill" ? parsed.frontmatter.name : "";
10987
+ const name = toSkillSlug(nameArg || "") || docName;
10988
+ if (!name)
10989
+ return null;
10990
+ const description = parsed.hadFrontmatter ? parsed.frontmatter.description : "";
10991
+ const extra = {};
10992
+ for (const key of parsed.orderedKeys) {
10993
+ if (key === "name" || key === "description")
10994
+ continue;
10995
+ const value = parsed.frontmatter[key];
10996
+ if (typeof value === "string")
10997
+ extra[key] = value;
10998
+ }
10999
+ return { name, description, content: buildSkillMd({ name, description, body: parsed.body, extra }) };
11000
+ }
10811
11001
  var pushCommand = new Command13("push").description("Upload a local skill file to workspace (upsert by name). Accepts piped content via stdin.").argument("[first]", "Skill name (if piping content) or file path (name from frontmatter)").argument("[second]", "File path (when first arg is the skill name)").option("--workspace <name-or-id>", "Workspace name or ID").action(async (first, second, opts, command) => {
10812
11002
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
10813
11003
  const credentials = requireAuth();
@@ -10849,35 +11039,22 @@ var pushCommand = new Command13("push").description("Upload a local skill file t
10849
11039
  }
10850
11040
  }
10851
11041
  try {
10852
- const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
10853
- let name = nameArg || "";
10854
- let description = "";
10855
- let body = content;
10856
- if (frontmatterMatch) {
10857
- const fm = frontmatterMatch[1];
10858
- body = frontmatterMatch[2];
10859
- const descMatch = fm.match(/^description:\s*(.+)$/m);
10860
- if (descMatch)
10861
- description = descMatch[1].trim();
10862
- if (!name) {
10863
- const nameMatch = fm.match(/^name:\s*(.+)$/m);
10864
- if (nameMatch)
10865
- name = nameMatch[1].trim();
10866
- }
10867
- }
10868
- if (!name) {
11042
+ const payload = buildSkillPushPayload(content, nameArg);
11043
+ if (!payload) {
10869
11044
  console.error(`Skill name required. Provide as first argument or in YAML frontmatter:
10870
11045
  runwork skills push "My Skill" ./skill.md
10871
11046
  cat skill.md | runwork skills push "My Skill"`);
10872
11047
  process.exit(1);
11048
+ return;
10873
11049
  }
11050
+ const { name, description, content: document } = payload;
10874
11051
  const existing = await client.listExternalSkills(workspaceId);
10875
11052
  const match = existing.find((s) => s.name === name);
10876
11053
  if (match) {
10877
11054
  const updated = await client.updateExternalSkill(workspaceId, match.id, {
10878
11055
  name,
10879
11056
  description,
10880
- content: body
11057
+ content: document
10881
11058
  });
10882
11059
  if (useJson) {
10883
11060
  jsonOut({ skill: updated, action: "updated" });
@@ -10888,7 +11065,7 @@ var pushCommand = new Command13("push").description("Upload a local skill file t
10888
11065
  const created = await client.importExternalSkill(workspaceId, {
10889
11066
  name,
10890
11067
  description,
10891
- content: body,
11068
+ content: document,
10892
11069
  importedFrom: "cli"
10893
11070
  });
10894
11071
  if (useJson) {
@@ -11092,111 +11269,8 @@ init_client();
11092
11269
  // src/agents/claude-code.ts
11093
11270
  init_subprocess();
11094
11271
  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";
11097
-
11098
- // ../../shared/skill/skill-canonical.ts
11099
- function toSkillSlug(value) {
11100
- return value.trim().replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
11101
- }
11102
- function quoteYamlValue(value) {
11103
- if (value === "")
11104
- return '""';
11105
- if (/[:#[\]{}|>&*!,?'"]/.test(value) || value !== value.trim()) {
11106
- const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
11107
- return `"${escaped}"`;
11108
- }
11109
- return value;
11110
- }
11111
- function unquoteYamlValue(raw) {
11112
- const value = raw.trim();
11113
- if (value.length >= 2) {
11114
- const first = value[0];
11115
- const last = value[value.length - 1];
11116
- if (first === '"' && last === '"') {
11117
- return value.slice(1, -1).replace(/\\(["\\])/g, "$1");
11118
- }
11119
- if (first === "'" && last === "'") {
11120
- return value.slice(1, -1);
11121
- }
11122
- }
11123
- return value;
11124
- }
11125
- function parseSkillMd(content) {
11126
- const lines = content.split(`
11127
- `);
11128
- if (lines[0]?.trim() !== "---") {
11129
- const rawName = lines[0]?.replace(/^#\s*/, "").trim() || "Untitled Skill";
11130
- return {
11131
- frontmatter: {
11132
- name: toSkillSlug(rawName) || "untitled-skill",
11133
- description: ""
11134
- },
11135
- orderedKeys: [],
11136
- body: content,
11137
- hadFrontmatter: false
11138
- };
11139
- }
11140
- let closingIndex = -1;
11141
- for (let i = 1;i < lines.length; i++) {
11142
- if (lines[i]?.trim() === "---") {
11143
- closingIndex = i;
11144
- break;
11145
- }
11146
- }
11147
- if (closingIndex === -1) {
11148
- return {
11149
- frontmatter: { name: "untitled-skill", description: "" },
11150
- orderedKeys: [],
11151
- body: content,
11152
- hadFrontmatter: false
11153
- };
11154
- }
11155
- const frontmatterEntries = {};
11156
- const orderedKeys = [];
11157
- for (let i = 1;i < closingIndex; i++) {
11158
- const line = lines[i];
11159
- if (!line)
11160
- continue;
11161
- const colonIndex = line.indexOf(":");
11162
- if (colonIndex > 0) {
11163
- const key = line.slice(0, colonIndex).trim();
11164
- const value = unquoteYamlValue(line.slice(colonIndex + 1));
11165
- if (!(key in frontmatterEntries))
11166
- orderedKeys.push(key);
11167
- frontmatterEntries[key] = value;
11168
- }
11169
- }
11170
- const body = lines.slice(closingIndex + 1).join(`
11171
- `).trim();
11172
- return {
11173
- frontmatter: {
11174
- ...frontmatterEntries,
11175
- name: toSkillSlug(frontmatterEntries.name || "") || "untitled-skill",
11176
- description: frontmatterEntries.description || ""
11177
- },
11178
- orderedKeys,
11179
- body,
11180
- hadFrontmatter: true
11181
- };
11182
- }
11183
- function buildSkillMd(parts) {
11184
- const lines = [
11185
- "---",
11186
- `name: ${toSkillSlug(parts.name) || "untitled-skill"}`,
11187
- `description: ${quoteYamlValue(parts.description ?? "")}`
11188
- ];
11189
- if (parts.extra) {
11190
- for (const [key, value] of Object.entries(parts.extra)) {
11191
- if (key === "name" || key === "description")
11192
- continue;
11193
- lines.push(`${key}: ${quoteYamlValue(value)}`);
11194
- }
11195
- }
11196
- lines.push("---", "", (parts.body ?? "").trim());
11197
- return lines.join(`
11198
- `);
11199
- }
11272
+ import { join as join24 } from "path";
11273
+ import { homedir as homedir7, platform as platform2 } from "os";
11200
11274
 
11201
11275
  // src/agents/types.ts
11202
11276
  var RUNWORK_MCP_PREFIX = "Runwork: ";
@@ -11544,15 +11618,15 @@ function skillNameFromPath(path2) {
11544
11618
  // src/utils/trash.ts
11545
11619
  init_atomic_json();
11546
11620
  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";
11621
+ import { basename as basename2, dirname as dirname6, join as join22 } from "path";
11622
+ import { homedir as homedir6 } from "os";
11549
11623
  var TRASH_RETENTION_DAYS = 30;
11550
11624
  function trashRoot() {
11551
- return join21(homedir5(), ".runwork", "trash");
11625
+ return join22(homedir6(), ".runwork", "trash");
11552
11626
  }
11553
11627
  function batchDir(now) {
11554
11628
  const stamp = now.toISOString().replace(/[:.]/g, "-");
11555
- return join21(trashRoot(), `${stamp}-${process.pid}`);
11629
+ return join22(trashRoot(), `${stamp}-${process.pid}`);
11556
11630
  }
11557
11631
  function pruneTrash(now = new Date) {
11558
11632
  const root = trashRoot();
@@ -11560,7 +11634,7 @@ function pruneTrash(now = new Date) {
11560
11634
  return;
11561
11635
  const cutoff = now.getTime() - TRASH_RETENTION_DAYS * 24 * 60 * 60 * 1000;
11562
11636
  for (const entry of readdirSync5(root)) {
11563
- const dir = join21(root, entry);
11637
+ const dir = join22(root, entry);
11564
11638
  try {
11565
11639
  if (statSync3(dir).mtimeMs < cutoff)
11566
11640
  rmSync4(dir, { recursive: true, force: true });
@@ -11577,8 +11651,8 @@ function moveToTrash(sourcePath, reason, now = new Date) {
11577
11651
  }
11578
11652
  const parent = basename2(dirname6(sourcePath));
11579
11653
  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));
11654
+ const destDir = join22(activeBatch, `${grandparent}__${parent}`.replace(/[^a-zA-Z0-9._-]/g, "-"));
11655
+ const dest = join22(destDir, basename2(sourcePath));
11582
11656
  try {
11583
11657
  mkdirSync13(destDir, { recursive: true });
11584
11658
  try {
@@ -11590,7 +11664,7 @@ function moveToTrash(sourcePath, reason, now = new Date) {
11590
11664
  } catch {
11591
11665
  return null;
11592
11666
  }
11593
- const manifestPath = join21(activeBatch, "manifest.json");
11667
+ const manifestPath = join22(activeBatch, "manifest.json");
11594
11668
  const manifest = readJsonOrNull(manifestPath) ?? { entries: [] };
11595
11669
  manifest.entries.push({ from: sourcePath, to: dest, reason, at: now.toISOString() });
11596
11670
  try {
@@ -11691,14 +11765,14 @@ function mergeJsonMcpServers(filePath, servers, topKey) {
11691
11765
 
11692
11766
  // src/agents/utils/skill-removal.ts
11693
11767
  import { existsSync as existsSync28, readdirSync as readdirSync6 } from "fs";
11694
- import { join as join22 } from "path";
11768
+ import { join as join23 } from "path";
11695
11769
  function removeMatchingSkillDirs(dir, allowed, reason = "skill removed") {
11696
11770
  if (!allowed.size || !existsSync28(dir))
11697
11771
  return;
11698
11772
  for (const entry of readdirSync6(dir)) {
11699
11773
  if (!allowed.has(entry))
11700
11774
  continue;
11701
- moveToTrash(join22(dir, entry), reason);
11775
+ moveToTrash(join23(dir, entry), reason);
11702
11776
  }
11703
11777
  }
11704
11778
  function removeMatchingSkillFiles(dir, allowed, suffix, reason = "skill removed") {
@@ -11708,7 +11782,7 @@ function removeMatchingSkillFiles(dir, allowed, suffix, reason = "skill removed"
11708
11782
  for (const entry of readdirSync6(dir)) {
11709
11783
  if (!names.has(entry))
11710
11784
  continue;
11711
- moveToTrash(join22(dir, entry), reason);
11785
+ moveToTrash(join23(dir, entry), reason);
11712
11786
  }
11713
11787
  }
11714
11788
 
@@ -12111,7 +12185,7 @@ class ClaudeCodeAdapter {
12111
12185
  }
12112
12186
  async writeMcpServers(servers, scope) {
12113
12187
  if (scope === "project") {
12114
- const filePath = join23(process.cwd(), ".mcp.json");
12188
+ const filePath = join24(process.cwd(), ".mcp.json");
12115
12189
  const entries = {};
12116
12190
  for (const s of servers) {
12117
12191
  entries[s.name] = {
@@ -12123,7 +12197,7 @@ class ClaudeCodeAdapter {
12123
12197
  }
12124
12198
  mergeJsonMcpServers(filePath, entries, "mcpServers");
12125
12199
  } else {
12126
- const settingsPath = join23(homedir6(), ".claude", "settings.json");
12200
+ const settingsPath = join24(homedir7(), ".claude", "settings.json");
12127
12201
  const entries = {};
12128
12202
  for (const s of servers) {
12129
12203
  entries[s.name] = {
@@ -12136,10 +12210,10 @@ class ClaudeCodeAdapter {
12136
12210
  mergeJsonMcpServers(settingsPath, entries, "mcpServers");
12137
12211
  const pluginDir = this.getPluginDir();
12138
12212
  mkdirSync16(pluginDir, { recursive: true });
12139
- const pluginMcpPath = join23(pluginDir, ".mcp.json");
12213
+ const pluginMcpPath = join24(pluginDir, ".mcp.json");
12140
12214
  const marketDir = this.getMarketplaceDir();
12141
12215
  mkdirSync16(marketDir, { recursive: true });
12142
- const marketplaceMcpPath = join23(marketDir, ".mcp.json");
12216
+ const marketplaceMcpPath = join24(marketDir, ".mcp.json");
12143
12217
  const pluginEntries = {};
12144
12218
  for (const s of servers) {
12145
12219
  pluginEntries[s.name] = {
@@ -12154,44 +12228,44 @@ class ClaudeCodeAdapter {
12154
12228
  }
12155
12229
  }
12156
12230
  installSessionStartHook(pluginDir, label) {
12157
- const hooksDir = join23(pluginDir, "hooks");
12231
+ const hooksDir = join24(pluginDir, "hooks");
12158
12232
  mkdirSync16(hooksDir, { recursive: true });
12159
- const scriptPath = join23(hooksDir, "on-session-start.sh");
12233
+ const scriptPath = join24(hooksDir, "on-session-start.sh");
12160
12234
  writeFileSync16(scriptPath, SESSION_START_HOOK_SCRIPT);
12161
12235
  try {
12162
12236
  chmodSync(scriptPath, 493);
12163
12237
  } catch {}
12164
- writeFileSync16(join23(hooksDir, "hooks.json"), JSON.stringify(SESSION_START_HOOKS_MANIFEST, null, 2));
12238
+ writeFileSync16(join24(hooksDir, "hooks.json"), JSON.stringify(SESSION_START_HOOKS_MANIFEST, null, 2));
12165
12239
  vlog(` [Claude Code] Installed SessionStart hook (${label}) -> ${scriptPath}`);
12166
12240
  }
12167
12241
  async writeSkills(skills, scope) {
12168
- const baseDir = scope === "project" ? join23(process.cwd(), ".claude", "skills") : join23(homedir6(), ".claude", "skills");
12242
+ const baseDir = scope === "project" ? join24(process.cwd(), ".claude", "skills") : join24(homedir7(), ".claude", "skills");
12169
12243
  for (const skill of skills) {
12170
- const skillDir = join23(baseDir, skill.filename);
12244
+ const skillDir = join24(baseDir, skill.filename);
12171
12245
  cleanupOldSkillDir(baseDir, skill);
12172
12246
  mkdirSync16(skillDir, { recursive: true });
12173
- writeFileSync16(join23(skillDir, "SKILL.md"), buildSkillMd2(skill));
12247
+ writeFileSync16(join24(skillDir, "SKILL.md"), buildSkillMd2(skill));
12174
12248
  }
12175
12249
  if (scope === "user") {
12176
12250
  const pluginDir = this.getPluginDir();
12177
- const pluginJsonDir = join23(pluginDir, ".claude-plugin");
12251
+ const pluginJsonDir = join24(pluginDir, ".claude-plugin");
12178
12252
  mkdirSync16(pluginJsonDir, { recursive: true });
12179
- writeFileSync16(join23(pluginJsonDir, "plugin.json"), JSON.stringify(getPluginJson(), null, 2));
12253
+ writeFileSync16(join24(pluginJsonDir, "plugin.json"), JSON.stringify(getPluginJson(), null, 2));
12180
12254
  for (const skill of skills) {
12181
- const skillDir = join23(pluginDir, "skills", skill.filename);
12182
- cleanupOldSkillDir(join23(pluginDir, "skills"), skill);
12255
+ const skillDir = join24(pluginDir, "skills", skill.filename);
12256
+ cleanupOldSkillDir(join24(pluginDir, "skills"), skill);
12183
12257
  mkdirSync16(skillDir, { recursive: true });
12184
- writeFileSync16(join23(skillDir, "SKILL.md"), buildSkillMd2(skill));
12258
+ writeFileSync16(join24(skillDir, "SKILL.md"), buildSkillMd2(skill));
12185
12259
  }
12186
12260
  const marketDir = this.getMarketplaceDir();
12187
- const marketPluginJsonDir = join23(marketDir, ".claude-plugin");
12261
+ const marketPluginJsonDir = join24(marketDir, ".claude-plugin");
12188
12262
  mkdirSync16(marketPluginJsonDir, { recursive: true });
12189
- writeFileSync16(join23(marketPluginJsonDir, "plugin.json"), JSON.stringify(getPluginJson(), null, 2));
12263
+ writeFileSync16(join24(marketPluginJsonDir, "plugin.json"), JSON.stringify(getPluginJson(), null, 2));
12190
12264
  for (const skill of skills) {
12191
- const skillDir = join23(marketDir, "skills", skill.filename);
12192
- cleanupOldSkillDir(join23(marketDir, "skills"), skill);
12265
+ const skillDir = join24(marketDir, "skills", skill.filename);
12266
+ cleanupOldSkillDir(join24(marketDir, "skills"), skill);
12193
12267
  mkdirSync16(skillDir, { recursive: true });
12194
- writeFileSync16(join23(skillDir, "SKILL.md"), buildSkillMd2(skill));
12268
+ writeFileSync16(join24(skillDir, "SKILL.md"), buildSkillMd2(skill));
12195
12269
  }
12196
12270
  this.registerPlugin(pluginDir);
12197
12271
  }
@@ -12210,11 +12284,11 @@ class ClaudeCodeAdapter {
12210
12284
  }
12211
12285
  }
12212
12286
  async writeInstructionHint(hint, scope) {
12213
- const filePath = scope === "project" ? join23(process.cwd(), ".claude", "CLAUDE.md") : join23(homedir6(), ".claude", "CLAUDE.md");
12287
+ const filePath = scope === "project" ? join24(process.cwd(), ".claude", "CLAUDE.md") : join24(homedir7(), ".claude", "CLAUDE.md");
12214
12288
  writeHintToFile(filePath, hint);
12215
12289
  }
12216
12290
  async writeTeamInstructions(instructions, scope) {
12217
- const filePath = scope === "project" ? join23(process.cwd(), ".claude", "CLAUDE.md") : join23(homedir6(), ".claude", "CLAUDE.md");
12291
+ const filePath = scope === "project" ? join24(process.cwd(), ".claude", "CLAUDE.md") : join24(homedir7(), ".claude", "CLAUDE.md");
12218
12292
  writeTeamInstructionsToFile(filePath, instructions);
12219
12293
  if (scope === "user") {
12220
12294
  const skillContent = `---
@@ -12226,16 +12300,16 @@ ${instructions}`;
12226
12300
  const pluginDir = this.getPluginDir();
12227
12301
  const marketDir = this.getMarketplaceDir();
12228
12302
  for (const dir of [
12229
- join23(pluginDir, "skills", "runwork-team-instructions"),
12230
- join23(marketDir, "skills", "runwork-team-instructions")
12303
+ join24(pluginDir, "skills", "runwork-team-instructions"),
12304
+ join24(marketDir, "skills", "runwork-team-instructions")
12231
12305
  ]) {
12232
12306
  mkdirSync16(dir, { recursive: true });
12233
- writeFileSync16(join23(dir, "SKILL.md"), skillContent);
12307
+ writeFileSync16(join24(dir, "SKILL.md"), skillContent);
12234
12308
  }
12235
12309
  }
12236
12310
  }
12237
12311
  async writeAgentConfig(config, scope, baseline) {
12238
- const settingsPath = scope === "project" ? join23(process.cwd(), ".claude", "settings.json") : join23(homedir6(), ".claude", "settings.json");
12312
+ const settingsPath = scope === "project" ? join24(process.cwd(), ".claude", "settings.json") : join24(homedir7(), ".claude", "settings.json");
12239
12313
  const hadFile = existsSync30(settingsPath);
12240
12314
  let settings = {};
12241
12315
  if (hadFile) {
@@ -12270,7 +12344,7 @@ ${instructions}`;
12270
12344
  }
12271
12345
  if (!hadFile && !config.modelPreference && !config.permissionRules)
12272
12346
  return;
12273
- mkdirSync16(join23(settingsPath, ".."), { recursive: true });
12347
+ mkdirSync16(join24(settingsPath, ".."), { recursive: true });
12274
12348
  writeFileSync16(settingsPath, JSON.stringify(settings, null, 2));
12275
12349
  }
12276
12350
  async readManagedBlock(_scope) {
@@ -12280,26 +12354,26 @@ ${instructions}`;
12280
12354
  if (!skillFilenames.length)
12281
12355
  return;
12282
12356
  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")
12357
+ const roots = scope === "project" ? [join24(process.cwd(), ".claude", "skills")] : [
12358
+ join24(homedir7(), ".claude", "skills"),
12359
+ join24(this.getPluginDir(), "skills"),
12360
+ join24(this.getMarketplaceDir(), "skills")
12287
12361
  ];
12288
12362
  for (const dir of roots)
12289
12363
  removeMatchingSkillDirs(dir, allowed);
12290
12364
  }
12291
12365
  async cleanup(scope, manifest) {
12292
12366
  if (scope === "project") {
12293
- removeRunworkMcpServers(join23(process.cwd(), ".mcp.json"), "mcpServers");
12367
+ removeRunworkMcpServers(join24(process.cwd(), ".mcp.json"), "mcpServers");
12294
12368
  } else {
12295
- removeRunworkMcpServers(join23(homedir6(), ".claude", "settings.json"), "mcpServers");
12369
+ removeRunworkMcpServers(join24(homedir7(), ".claude", "settings.json"), "mcpServers");
12296
12370
  }
12297
12371
  await this.removeSkills(manifest?.skillFilenames ?? [], scope);
12298
- const instructionFile = scope === "project" ? join23(process.cwd(), ".claude", "CLAUDE.md") : join23(homedir6(), ".claude", "CLAUDE.md");
12372
+ const instructionFile = scope === "project" ? join24(process.cwd(), ".claude", "CLAUDE.md") : join24(homedir7(), ".claude", "CLAUDE.md");
12299
12373
  removeHintFromFile(instructionFile);
12300
12374
  removeTeamInstructionsFromFile(instructionFile);
12301
12375
  if (scope === "user") {
12302
- const settingsPath = join23(homedir6(), ".claude", "settings.json");
12376
+ const settingsPath = join24(homedir7(), ".claude", "settings.json");
12303
12377
  if (existsSync30(settingsPath)) {
12304
12378
  try {
12305
12379
  const settings = JSON.parse(readFileSync25(settingsPath, "utf-8"));
@@ -12331,7 +12405,7 @@ ${instructions}`;
12331
12405
  }
12332
12406
  }
12333
12407
  const pluginsBase = this.getPluginsBaseDir();
12334
- const installedPath = join23(pluginsBase, "installed_plugins.json");
12408
+ const installedPath = join24(pluginsBase, "installed_plugins.json");
12335
12409
  if (existsSync30(installedPath)) {
12336
12410
  try {
12337
12411
  const installed = readJsonConfig(installedPath);
@@ -12344,7 +12418,7 @@ ${instructions}`;
12344
12418
  }
12345
12419
  } catch {}
12346
12420
  }
12347
- const marketplacesPath = join23(pluginsBase, "known_marketplaces.json");
12421
+ const marketplacesPath = join24(pluginsBase, "known_marketplaces.json");
12348
12422
  if (existsSync30(marketplacesPath)) {
12349
12423
  try {
12350
12424
  const marketplaces = readJsonConfig(marketplacesPath);
@@ -12356,10 +12430,10 @@ ${instructions}`;
12356
12430
  }
12357
12431
  async readUsageStats(lastSyncAt) {
12358
12432
  try {
12359
- const claudeDir = join23(homedir6(), ".claude");
12433
+ const claudeDir = join24(homedir7(), ".claude");
12360
12434
  if (!existsSync30(claudeDir))
12361
12435
  return null;
12362
- const projectsDir = join23(claudeDir, "projects");
12436
+ const projectsDir = join24(claudeDir, "projects");
12363
12437
  if (!existsSync30(projectsDir))
12364
12438
  return null;
12365
12439
  const sinceMs = lastSyncAt ? new Date(lastSyncAt).getTime() : 0;
@@ -12379,7 +12453,7 @@ ${instructions}`;
12379
12453
  return null;
12380
12454
  }
12381
12455
  for (const cwd of cwdEntries) {
12382
- const cwdPath = join23(projectsDir, cwd);
12456
+ const cwdPath = join24(projectsDir, cwd);
12383
12457
  let files;
12384
12458
  try {
12385
12459
  files = readdirSync7(cwdPath);
@@ -12389,7 +12463,7 @@ ${instructions}`;
12389
12463
  for (const file of files) {
12390
12464
  if (!file.endsWith(".jsonl"))
12391
12465
  continue;
12392
- const filePath = join23(cwdPath, file);
12466
+ const filePath = join24(cwdPath, file);
12393
12467
  let stat;
12394
12468
  try {
12395
12469
  stat = statSync4(filePath);
@@ -12486,7 +12560,7 @@ ${instructions}`;
12486
12560
  }
12487
12561
  async readSessionDigests(sinceISO) {
12488
12562
  try {
12489
- const projectsDir = join23(homedir6(), ".claude", "projects");
12563
+ const projectsDir = join24(homedir7(), ".claude", "projects");
12490
12564
  if (!existsSync30(projectsDir))
12491
12565
  return null;
12492
12566
  const sinceMs = sinceISO ? new Date(sinceISO).getTime() : 0;
@@ -12498,7 +12572,7 @@ ${instructions}`;
12498
12572
  }
12499
12573
  const digests = [];
12500
12574
  for (const cwd of cwdEntries) {
12501
- const cwdPath = join23(projectsDir, cwd);
12575
+ const cwdPath = join24(projectsDir, cwd);
12502
12576
  let files;
12503
12577
  try {
12504
12578
  files = readdirSync7(cwdPath);
@@ -12508,7 +12582,7 @@ ${instructions}`;
12508
12582
  for (const file of files) {
12509
12583
  if (!file.endsWith(".jsonl"))
12510
12584
  continue;
12511
- const filePath = join23(cwdPath, file);
12585
+ const filePath = join24(cwdPath, file);
12512
12586
  let stat;
12513
12587
  try {
12514
12588
  stat = statSync4(filePath);
@@ -12535,7 +12609,7 @@ ${instructions}`;
12535
12609
  }
12536
12610
  async readSkillUsage(lastSyncAt) {
12537
12611
  try {
12538
- const projectsDir = join23(homedir6(), ".claude", "projects");
12612
+ const projectsDir = join24(homedir7(), ".claude", "projects");
12539
12613
  if (!existsSync30(projectsDir))
12540
12614
  return null;
12541
12615
  const sinceMs = lastSyncAt ? new Date(lastSyncAt).getTime() : 0;
@@ -12557,7 +12631,7 @@ ${instructions}`;
12557
12631
  return null;
12558
12632
  }
12559
12633
  for (const cwd of cwdEntries) {
12560
- const cwdPath = join23(projectsDir, cwd);
12634
+ const cwdPath = join24(projectsDir, cwd);
12561
12635
  let files;
12562
12636
  try {
12563
12637
  files = readdirSync7(cwdPath);
@@ -12567,7 +12641,7 @@ ${instructions}`;
12567
12641
  for (const file of files) {
12568
12642
  if (!file.endsWith(".jsonl"))
12569
12643
  continue;
12570
- const filePath = join23(cwdPath, file);
12644
+ const filePath = join24(cwdPath, file);
12571
12645
  let fileStat;
12572
12646
  try {
12573
12647
  fileStat = statSync4(filePath);
@@ -12668,21 +12742,21 @@ ${instructions}`;
12668
12742
  }
12669
12743
  }
12670
12744
  getPluginsBaseDir() {
12671
- return join23(homedir6(), ".claude", "plugins");
12745
+ return join24(homedir7(), ".claude", "plugins");
12672
12746
  }
12673
12747
  getPluginDir() {
12674
- return join23(this.getPluginsBaseDir(), "cache", "runwork", PLUGIN_NAME, PLUGIN_VERSION);
12748
+ return join24(this.getPluginsBaseDir(), "cache", "runwork", PLUGIN_NAME, PLUGIN_VERSION);
12675
12749
  }
12676
12750
  getMarketplaceRoot() {
12677
- return join23(this.getPluginsBaseDir(), "marketplaces", "runwork");
12751
+ return join24(this.getPluginsBaseDir(), "marketplaces", "runwork");
12678
12752
  }
12679
12753
  getMarketplaceDir() {
12680
- return join23(this.getMarketplaceRoot(), "plugins", PLUGIN_NAME);
12754
+ return join24(this.getMarketplaceRoot(), "plugins", PLUGIN_NAME);
12681
12755
  }
12682
12756
  registerPlugin(pluginDir) {
12683
12757
  const pluginsBase = this.getPluginsBaseDir();
12684
12758
  mkdirSync16(pluginsBase, { recursive: true });
12685
- const installedPath = join23(pluginsBase, "installed_plugins.json");
12759
+ const installedPath = join24(pluginsBase, "installed_plugins.json");
12686
12760
  const installed = readJsonConfig(installedPath);
12687
12761
  if (!installed.version)
12688
12762
  installed.version = 2;
@@ -12699,10 +12773,10 @@ ${instructions}`;
12699
12773
  }];
12700
12774
  writeJsonConfig(installedPath, installed);
12701
12775
  const marketRoot = this.getMarketplaceRoot();
12702
- const marketCatalogDir = join23(marketRoot, ".claude-plugin");
12776
+ const marketCatalogDir = join24(marketRoot, ".claude-plugin");
12703
12777
  mkdirSync16(marketCatalogDir, { recursive: true });
12704
- writeFileSync16(join23(marketCatalogDir, "marketplace.json"), JSON.stringify(getMarketplaceJson(), null, 2));
12705
- const marketplacesPath = join23(pluginsBase, "known_marketplaces.json");
12778
+ writeFileSync16(join24(marketCatalogDir, "marketplace.json"), JSON.stringify(getMarketplaceJson(), null, 2));
12779
+ const marketplacesPath = join24(pluginsBase, "known_marketplaces.json");
12706
12780
  const marketplaces = readJsonConfig(marketplacesPath);
12707
12781
  marketplaces["runwork"] = {
12708
12782
  source: { source: "directory", path: marketRoot },
@@ -12711,7 +12785,7 @@ ${instructions}`;
12711
12785
  };
12712
12786
  writeJsonConfig(marketplacesPath, marketplaces);
12713
12787
  vlog(` [Claude Code] ${wasRegistered ? "Refreshed" : "Registered"} plugin ` + `${pluginKey} v${PLUGIN_VERSION} -> ${installedPath}`);
12714
- const settingsPath = join23(homedir6(), ".claude", "settings.json");
12788
+ const settingsPath = join24(homedir7(), ".claude", "settings.json");
12715
12789
  const settings = readJsonConfig(settingsPath);
12716
12790
  if (!settings["enabledPlugins"]) {
12717
12791
  settings["enabledPlugins"] = {};
@@ -12726,23 +12800,23 @@ ${instructions}`;
12726
12800
  function cleanupOldSkillDir(baseDir, skill) {
12727
12801
  if (skill.name === skill.filename)
12728
12802
  return;
12729
- const oldDir = join23(baseDir, skill.name);
12803
+ const oldDir = join24(baseDir, skill.name);
12730
12804
  moveToTrash(oldDir, `skill renamed to ${skill.filename}`);
12731
12805
  }
12732
12806
 
12733
12807
  // src/agents/claude-desktop.ts
12734
12808
  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";
12809
+ import { dirname as dirname9, join as join26 } from "path";
12810
+ import { homedir as homedir8, platform as platform3, tmpdir as tmpdir3 } from "os";
12737
12811
  init_zip();
12738
12812
 
12739
12813
  // src/agents/claude-desktop-plugin-tree.ts
12740
12814
  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";
12815
+ import { join as join25 } from "path";
12742
12816
  function writePluginMetadata(destDir, metadata) {
12743
- const pluginJsonDir = join24(destDir, ".claude-plugin");
12817
+ const pluginJsonDir = join25(destDir, ".claude-plugin");
12744
12818
  mkdirSync17(pluginJsonDir, { recursive: true });
12745
- writeFileSync17(join24(pluginJsonDir, "plugin.json"), JSON.stringify({
12819
+ writeFileSync17(join25(pluginJsonDir, "plugin.json"), JSON.stringify({
12746
12820
  name: metadata.pluginName,
12747
12821
  version: metadata.pluginVersion,
12748
12822
  description: metadata.description,
@@ -12769,10 +12843,10 @@ function writePluginMcpConfig(destDir, mcpServers) {
12769
12843
  };
12770
12844
  }
12771
12845
  }
12772
- writeFileSync17(join24(destDir, ".mcp.json"), JSON.stringify({ mcpServers: mcpEntries }, null, 2));
12846
+ writeFileSync17(join25(destDir, ".mcp.json"), JSON.stringify({ mcpServers: mcpEntries }, null, 2));
12773
12847
  }
12774
12848
  function writePluginTeamInstructions(destDir, instructions) {
12775
- const skillDir = join24(destDir, "skills", "runwork-team-instructions");
12849
+ const skillDir = join25(destDir, "skills", "runwork-team-instructions");
12776
12850
  mkdirSync17(skillDir, { recursive: true });
12777
12851
  const skillContent = `---
12778
12852
  name: runwork-team-instructions
@@ -12780,34 +12854,34 @@ description: Team instructions from your Runwork workspace. Always follow these
12780
12854
  ---
12781
12855
 
12782
12856
  ${instructions}`;
12783
- writeFileSync17(join24(skillDir, "SKILL.md"), skillContent);
12857
+ writeFileSync17(join25(skillDir, "SKILL.md"), skillContent);
12784
12858
  }
12785
12859
  function writePluginSkills(destDir, skills) {
12786
- const skillsRoot = join24(destDir, "skills");
12860
+ const skillsRoot = join25(destDir, "skills");
12787
12861
  mkdirSync17(skillsRoot, { recursive: true });
12788
12862
  for (const skill of skills) {
12789
12863
  if (skill.name !== skill.filename) {
12790
- const legacyDir = join24(skillsRoot, skill.name);
12864
+ const legacyDir = join25(skillsRoot, skill.name);
12791
12865
  if (existsSync31(legacyDir)) {
12792
12866
  try {
12793
12867
  rmSync6(legacyDir, { recursive: true, force: true });
12794
12868
  } catch {}
12795
12869
  }
12796
12870
  }
12797
- const skillDir = join24(skillsRoot, skill.filename);
12871
+ const skillDir = join25(skillsRoot, skill.filename);
12798
12872
  mkdirSync17(skillDir, { recursive: true });
12799
- writeFileSync17(join24(skillDir, "SKILL.md"), buildSkillMd2(skill));
12873
+ writeFileSync17(join25(skillDir, "SKILL.md"), buildSkillMd2(skill));
12800
12874
  }
12801
12875
  }
12802
12876
  function writePluginSessionStartHook(destDir) {
12803
- const hooksDir = join24(destDir, "hooks");
12877
+ const hooksDir = join25(destDir, "hooks");
12804
12878
  mkdirSync17(hooksDir, { recursive: true });
12805
- const scriptPath = join24(hooksDir, "on-session-start.sh");
12879
+ const scriptPath = join25(hooksDir, "on-session-start.sh");
12806
12880
  writeFileSync17(scriptPath, SESSION_START_HOOK_SCRIPT);
12807
12881
  try {
12808
12882
  chmodSync2(scriptPath, 493);
12809
12883
  } catch {}
12810
- writeFileSync17(join24(hooksDir, "hooks.json"), JSON.stringify(SESSION_START_HOOKS_MANIFEST, null, 2));
12884
+ writeFileSync17(join25(hooksDir, "hooks.json"), JSON.stringify(SESSION_START_HOOKS_MANIFEST, null, 2));
12811
12885
  console.log(` [Claude Desktop (Cowork)] Bundled SessionStart hook -> ${scriptPath}`);
12812
12886
  }
12813
12887
  function writePluginTree(destDir, input) {
@@ -12842,22 +12916,22 @@ function getPluginMetadata() {
12842
12916
  function getMcpConfigPath() {
12843
12917
  const os2 = platform3();
12844
12918
  if (os2 === "darwin") {
12845
- return join25(homedir7(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
12919
+ return join26(homedir8(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
12846
12920
  }
12847
12921
  if (os2 === "win32") {
12848
- return join25(process.env.APPDATA || join25(homedir7(), "AppData", "Roaming"), "Claude", "claude_desktop_config.json");
12922
+ return join26(process.env.APPDATA || join26(homedir8(), "AppData", "Roaming"), "Claude", "claude_desktop_config.json");
12849
12923
  }
12850
- return join25(homedir7(), ".config", "Claude", "claude_desktop_config.json");
12924
+ return join26(homedir8(), ".config", "Claude", "claude_desktop_config.json");
12851
12925
  }
12852
12926
  function getCoworkBaseDir() {
12853
12927
  const os2 = platform3();
12854
12928
  if (os2 === "darwin") {
12855
- return join25(homedir7(), "Library", "Application Support", "Claude", "local-agent-mode-sessions");
12929
+ return join26(homedir8(), "Library", "Application Support", "Claude", "local-agent-mode-sessions");
12856
12930
  }
12857
12931
  if (os2 === "win32") {
12858
- return join25(process.env.APPDATA || join25(homedir7(), "AppData", "Roaming"), "Claude", "local-agent-mode-sessions");
12932
+ return join26(process.env.APPDATA || join26(homedir8(), "AppData", "Roaming"), "Claude", "local-agent-mode-sessions");
12859
12933
  }
12860
- return join25(homedir7(), ".config", "Claude", "local-agent-mode-sessions");
12934
+ return join26(homedir8(), ".config", "Claude", "local-agent-mode-sessions");
12861
12935
  }
12862
12936
  function listOrgDirs() {
12863
12937
  const baseDir = getCoworkBaseDir();
@@ -12867,10 +12941,10 @@ function listOrgDirs() {
12867
12941
  try {
12868
12942
  const sessionDirs = readdirSync8(baseDir).filter((d) => !d.startsWith(".") && d !== "skills-plugin");
12869
12943
  for (const sessionId of sessionDirs) {
12870
- const sessionPath = join25(baseDir, sessionId);
12944
+ const sessionPath = join26(baseDir, sessionId);
12871
12945
  try {
12872
12946
  for (const orgId of readdirSync8(sessionPath).filter((d) => !d.startsWith("."))) {
12873
- dirs.push(join25(sessionPath, orgId));
12947
+ dirs.push(join26(sessionPath, orgId));
12874
12948
  }
12875
12949
  } catch {
12876
12950
  continue;
@@ -12886,7 +12960,7 @@ function walkOrgDirs(visit) {
12886
12960
  try {
12887
12961
  const sessionDirs = readdirSync8(baseDir).filter((d) => !d.startsWith(".") && d !== "skills-plugin");
12888
12962
  for (const sessionId of sessionDirs) {
12889
- const sessionPath = join25(baseDir, sessionId);
12963
+ const sessionPath = join26(baseDir, sessionId);
12890
12964
  let orgDirs;
12891
12965
  try {
12892
12966
  orgDirs = readdirSync8(sessionPath).filter((d) => !d.startsWith("."));
@@ -12894,7 +12968,7 @@ function walkOrgDirs(visit) {
12894
12968
  continue;
12895
12969
  }
12896
12970
  for (const orgId of orgDirs) {
12897
- const orgDir = join25(sessionPath, orgId);
12971
+ const orgDir = join26(sessionPath, orgId);
12898
12972
  const result = visit(orgDir);
12899
12973
  if (result !== null)
12900
12974
  return result;
@@ -12911,7 +12985,7 @@ function getCoworkMemoryClaudeMdPaths() {
12911
12985
  try {
12912
12986
  const sessionDirs = readdirSync8(baseDir).filter((d) => !d.startsWith(".") && d !== "skills-plugin");
12913
12987
  for (const sessionId of sessionDirs) {
12914
- const sessionPath = join25(baseDir, sessionId);
12988
+ const sessionPath = join26(baseDir, sessionId);
12915
12989
  let orgDirs;
12916
12990
  try {
12917
12991
  orgDirs = readdirSync8(sessionPath).filter((d) => !d.startsWith("."));
@@ -12919,7 +12993,7 @@ function getCoworkMemoryClaudeMdPaths() {
12919
12993
  continue;
12920
12994
  }
12921
12995
  for (const orgId of orgDirs) {
12922
- paths.push(join25(sessionPath, orgId, "memory", "CLAUDE.md"));
12996
+ paths.push(join26(sessionPath, orgId, "memory", "CLAUDE.md"));
12923
12997
  }
12924
12998
  }
12925
12999
  } catch {}
@@ -12927,13 +13001,13 @@ function getCoworkMemoryClaudeMdPaths() {
12927
13001
  }
12928
13002
  function findCoworkPluginsDir() {
12929
13003
  return walkOrgDirs((orgDir) => {
12930
- const pluginsDir = join25(orgDir, "cowork_plugins");
12931
- return existsSync32(join25(pluginsDir, "installed_plugins.json")) ? pluginsDir : null;
13004
+ const pluginsDir = join26(orgDir, "cowork_plugins");
13005
+ return existsSync32(join26(pluginsDir, "installed_plugins.json")) ? pluginsDir : null;
12932
13006
  });
12933
13007
  }
12934
13008
  function findRpmPluginByName(pluginName) {
12935
13009
  return walkOrgDirs((orgDir) => {
12936
- const manifestPath = join25(orgDir, "rpm", "manifest.json");
13010
+ const manifestPath = join26(orgDir, "rpm", "manifest.json");
12937
13011
  if (!existsSync32(manifestPath))
12938
13012
  return null;
12939
13013
  try {
@@ -12942,7 +13016,7 @@ function findRpmPluginByName(pluginName) {
12942
13016
  if (!entry?.id)
12943
13017
  return null;
12944
13018
  return {
12945
- pluginPath: join25(orgDir, "rpm", entry.id),
13019
+ pluginPath: join26(orgDir, "rpm", entry.id),
12946
13020
  orgDir
12947
13021
  };
12948
13022
  } catch {
@@ -12964,7 +13038,7 @@ function getMarketplaceJson2() {
12964
13038
  };
12965
13039
  }
12966
13040
  function getCoworkSettingsPath(pluginsDir) {
12967
- return join25(dirname9(pluginsDir), "cowork_settings.json");
13041
+ return join26(dirname9(pluginsDir), "cowork_settings.json");
12968
13042
  }
12969
13043
  function setCoworkPluginEnabled(pluginsDir, enabled) {
12970
13044
  const settingsPath = getCoworkSettingsPath(pluginsDir);
@@ -13012,8 +13086,8 @@ class ClaudeDesktopAdapter {
13012
13086
  }
13013
13087
  const pluginsDir = findCoworkPluginsDir();
13014
13088
  if (pluginsDir) {
13015
- const cacheDir = join25(pluginsDir, "cache", "runwork", PLUGIN_NAME2, PLUGIN_VERSION2);
13016
- const marketDir = join25(pluginsDir, "marketplaces", "runwork", "plugins", PLUGIN_NAME2);
13089
+ const cacheDir = join26(pluginsDir, "cache", "runwork", PLUGIN_NAME2, PLUGIN_VERSION2);
13090
+ const marketDir = join26(pluginsDir, "marketplaces", "runwork", "plugins", PLUGIN_NAME2);
13017
13091
  for (const dir of [cacheDir, marketDir]) {
13018
13092
  writePluginMcpConfig(dir, servers);
13019
13093
  }
@@ -13031,14 +13105,14 @@ class ClaudeDesktopAdapter {
13031
13105
  console.warn(" [Claude Desktop] Cowork plugins directory not found. Open Claude Desktop at least once first.");
13032
13106
  return 0;
13033
13107
  }
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);
13108
+ const cacheDir = join26(pluginsDir, "cache", "runwork", PLUGIN_NAME2, PLUGIN_VERSION2);
13109
+ const marketRoot = join26(pluginsDir, "marketplaces", "runwork");
13110
+ const marketDir = join26(marketRoot, "plugins", PLUGIN_NAME2);
13037
13111
  for (const dir of [cacheDir, marketDir]) {
13038
13112
  writePluginMetadata(dir, getPluginMetadata());
13039
13113
  writePluginSkills(dir, skills);
13040
13114
  }
13041
- const installedPath = join25(pluginsDir, "installed_plugins.json");
13115
+ const installedPath = join26(pluginsDir, "installed_plugins.json");
13042
13116
  const installed = readJsonConfig(installedPath);
13043
13117
  if (!installed.version)
13044
13118
  installed.version = 2;
@@ -13052,10 +13126,10 @@ class ClaudeDesktopAdapter {
13052
13126
  lastUpdated: new Date().toISOString()
13053
13127
  }];
13054
13128
  writeJsonConfig(installedPath, installed);
13055
- const marketCatalogDir = join25(marketRoot, ".claude-plugin");
13129
+ const marketCatalogDir = join26(marketRoot, ".claude-plugin");
13056
13130
  mkdirSync18(marketCatalogDir, { recursive: true });
13057
- writeFileSync18(join25(marketCatalogDir, "marketplace.json"), JSON.stringify(getMarketplaceJson2(), null, 2));
13058
- const marketplacesPath = join25(pluginsDir, "known_marketplaces.json");
13131
+ writeFileSync18(join26(marketCatalogDir, "marketplace.json"), JSON.stringify(getMarketplaceJson2(), null, 2));
13132
+ const marketplacesPath = join26(pluginsDir, "known_marketplaces.json");
13059
13133
  const marketplaces = readJsonConfig(marketplacesPath);
13060
13134
  marketplaces["runwork"] = {
13061
13135
  source: { source: "directory", path: marketRoot },
@@ -13074,8 +13148,8 @@ class ClaudeDesktopAdapter {
13074
13148
  }
13075
13149
  }
13076
13150
  async buildPluginZip(skills, mcpServers, teamInstructions, outputPath) {
13077
- const stagingRoot = mkdtempSync3(join25(tmpdir3(), "runwork-plugin-"));
13078
- const pluginStagingDir = join25(stagingRoot, PLUGIN_NAME2);
13151
+ const stagingRoot = mkdtempSync3(join26(tmpdir3(), "runwork-plugin-"));
13152
+ const pluginStagingDir = join26(stagingRoot, PLUGIN_NAME2);
13079
13153
  try {
13080
13154
  writePluginTree(pluginStagingDir, {
13081
13155
  ...getPluginMetadata(),
@@ -13106,8 +13180,8 @@ class ClaudeDesktopAdapter {
13106
13180
  const pluginsDir = findCoworkPluginsDir();
13107
13181
  if (!pluginsDir)
13108
13182
  return;
13109
- writePluginTeamInstructions(join25(pluginsDir, "cache", "runwork", PLUGIN_NAME2, PLUGIN_VERSION2), instructions);
13110
- writePluginTeamInstructions(join25(pluginsDir, "marketplaces", "runwork", "plugins", PLUGIN_NAME2), instructions);
13183
+ writePluginTeamInstructions(join26(pluginsDir, "cache", "runwork", PLUGIN_NAME2, PLUGIN_VERSION2), instructions);
13184
+ writePluginTeamInstructions(join26(pluginsDir, "marketplaces", "runwork", "plugins", PLUGIN_NAME2), instructions);
13111
13185
  }
13112
13186
  async writeAgentConfig(config, _scope) {
13113
13187
  const configPath = getMcpConfigPath();
@@ -13149,7 +13223,7 @@ class ClaudeDesktopAdapter {
13149
13223
  } catch {}
13150
13224
  }
13151
13225
  for (const orgDir of listOrgDirs()) {
13152
- const manifestPath = join25(orgDir, "rpm", "manifest.json");
13226
+ const manifestPath = join26(orgDir, "rpm", "manifest.json");
13153
13227
  if (!existsSync32(manifestPath))
13154
13228
  continue;
13155
13229
  try {
@@ -13162,7 +13236,7 @@ class ClaudeDesktopAdapter {
13162
13236
  for (const entry of ours) {
13163
13237
  if (!entry.id)
13164
13238
  continue;
13165
- moveToTrash(join25(orgDir, "rpm", entry.id), `claude-desktop-plugin:${entry.name}`);
13239
+ moveToTrash(join26(orgDir, "rpm", entry.id), `claude-desktop-plugin:${entry.name}`);
13166
13240
  }
13167
13241
  manifest.plugins = manifest.plugins.filter((p) => !isRunworkRpmPluginName(p.name));
13168
13242
  manifest.lastUpdated = Date.now();
@@ -13170,11 +13244,11 @@ class ClaudeDesktopAdapter {
13170
13244
  } catch {}
13171
13245
  }
13172
13246
  for (const orgDir of listOrgDirs()) {
13173
- const pluginsDir = join25(orgDir, "cowork_plugins");
13174
- if (!existsSync32(join25(pluginsDir, "installed_plugins.json")))
13247
+ const pluginsDir = join26(orgDir, "cowork_plugins");
13248
+ if (!existsSync32(join26(pluginsDir, "installed_plugins.json")))
13175
13249
  continue;
13176
- const cacheRunwork = join25(pluginsDir, "cache", "runwork");
13177
- const marketRunwork = join25(pluginsDir, "marketplaces", "runwork");
13250
+ const cacheRunwork = join26(pluginsDir, "cache", "runwork");
13251
+ const marketRunwork = join26(pluginsDir, "marketplaces", "runwork");
13178
13252
  for (const dir of [cacheRunwork, marketRunwork]) {
13179
13253
  if (existsSync32(dir)) {
13180
13254
  try {
@@ -13182,7 +13256,7 @@ class ClaudeDesktopAdapter {
13182
13256
  } catch {}
13183
13257
  }
13184
13258
  }
13185
- const installedPath = join25(pluginsDir, "installed_plugins.json");
13259
+ const installedPath = join26(pluginsDir, "installed_plugins.json");
13186
13260
  try {
13187
13261
  const installed = readJsonConfig(installedPath);
13188
13262
  if (installed.plugins) {
@@ -13193,7 +13267,7 @@ class ClaudeDesktopAdapter {
13193
13267
  writeJsonConfig(installedPath, installed);
13194
13268
  }
13195
13269
  } catch {}
13196
- const marketplacesPath = join25(pluginsDir, "known_marketplaces.json");
13270
+ const marketplacesPath = join26(pluginsDir, "known_marketplaces.json");
13197
13271
  if (existsSync32(marketplacesPath)) {
13198
13272
  try {
13199
13273
  const marketplaces = readJsonConfig(marketplacesPath);
@@ -13224,11 +13298,11 @@ class ClaudeDesktopAdapter {
13224
13298
  const os2 = platform3();
13225
13299
  let claudeAppDir;
13226
13300
  if (os2 === "darwin") {
13227
- claudeAppDir = join25(homedir7(), "Library", "Application Support", "Claude");
13301
+ claudeAppDir = join26(homedir8(), "Library", "Application Support", "Claude");
13228
13302
  } else if (os2 === "win32") {
13229
- claudeAppDir = join25(process.env.APPDATA || join25(homedir7(), "AppData", "Roaming"), "Claude");
13303
+ claudeAppDir = join26(process.env.APPDATA || join26(homedir8(), "AppData", "Roaming"), "Claude");
13230
13304
  } else {
13231
- claudeAppDir = join25(homedir7(), ".config", "Claude");
13305
+ claudeAppDir = join26(homedir8(), ".config", "Claude");
13232
13306
  }
13233
13307
  if (!existsSync32(claudeAppDir))
13234
13308
  return null;
@@ -13237,7 +13311,7 @@ class ClaudeDesktopAdapter {
13237
13311
  let latestActivity = 0;
13238
13312
  const modelsUsed = new Set;
13239
13313
  let maxMcpTools = 0;
13240
- const agentSessionsDir = join25(claudeAppDir, "local-agent-mode-sessions");
13314
+ const agentSessionsDir = join26(claudeAppDir, "local-agent-mode-sessions");
13241
13315
  const activeDays = new Set;
13242
13316
  if (existsSync32(agentSessionsDir)) {
13243
13317
  this.walkSessionDirs(agentSessionsDir, sinceMs, (session) => {
@@ -13257,7 +13331,7 @@ class ClaudeDesktopAdapter {
13257
13331
  }
13258
13332
  });
13259
13333
  }
13260
- const codeSessionsDir = join25(claudeAppDir, "claude-code-sessions");
13334
+ const codeSessionsDir = join26(claudeAppDir, "claude-code-sessions");
13261
13335
  if (existsSync32(codeSessionsDir)) {
13262
13336
  this.walkSessionDirs(codeSessionsDir, sinceMs, (session) => {
13263
13337
  const sessionTime = session.lastActivityAt ?? session.createdAt ?? 0;
@@ -13272,7 +13346,7 @@ class ClaudeDesktopAdapter {
13272
13346
  });
13273
13347
  }
13274
13348
  let scheduledTaskRuns = 0;
13275
- const scheduledTasksPath = join25(claudeAppDir, "scheduled-tasks.json");
13349
+ const scheduledTasksPath = join26(claudeAppDir, "scheduled-tasks.json");
13276
13350
  if (existsSync32(scheduledTasksPath)) {
13277
13351
  try {
13278
13352
  const raw = readFileSync26(scheduledTasksPath, "utf-8");
@@ -13311,13 +13385,13 @@ class ClaudeDesktopAdapter {
13311
13385
  const os2 = platform3();
13312
13386
  let claudeAppDir;
13313
13387
  if (os2 === "darwin") {
13314
- claudeAppDir = join25(homedir7(), "Library", "Application Support", "Claude");
13388
+ claudeAppDir = join26(homedir8(), "Library", "Application Support", "Claude");
13315
13389
  } else if (os2 === "win32") {
13316
- claudeAppDir = join25(process.env.APPDATA || join25(homedir7(), "AppData", "Roaming"), "Claude");
13390
+ claudeAppDir = join26(process.env.APPDATA || join26(homedir8(), "AppData", "Roaming"), "Claude");
13317
13391
  } else {
13318
- claudeAppDir = join25(homedir7(), ".config", "Claude");
13392
+ claudeAppDir = join26(homedir8(), ".config", "Claude");
13319
13393
  }
13320
- const versionPath = join25(claudeAppDir, "claude-code", "sdk-version");
13394
+ const versionPath = join26(claudeAppDir, "claude-code", "sdk-version");
13321
13395
  if (existsSync32(versionPath)) {
13322
13396
  return readFileSync26(versionPath, "utf-8").trim();
13323
13397
  }
@@ -13331,7 +13405,7 @@ class ClaudeDesktopAdapter {
13331
13405
  for (const orgDir of readdirSync8(baseDir)) {
13332
13406
  if (orgDir.startsWith(".") || orgDir === "skills-plugin")
13333
13407
  continue;
13334
- const orgPath = join25(baseDir, orgDir);
13408
+ const orgPath = join26(baseDir, orgDir);
13335
13409
  try {
13336
13410
  if (!statSync5(orgPath).isDirectory())
13337
13411
  continue;
@@ -13341,7 +13415,7 @@ class ClaudeDesktopAdapter {
13341
13415
  for (const userDir of readdirSync8(orgPath)) {
13342
13416
  if (userDir.startsWith("."))
13343
13417
  continue;
13344
- const userPath = join25(orgPath, userDir);
13418
+ const userPath = join26(orgPath, userDir);
13345
13419
  try {
13346
13420
  if (!statSync5(userPath).isDirectory())
13347
13421
  continue;
@@ -13352,7 +13426,7 @@ class ClaudeDesktopAdapter {
13352
13426
  if (!file.endsWith(".json"))
13353
13427
  continue;
13354
13428
  try {
13355
- const session = JSON.parse(readFileSync26(join25(userPath, file), "utf-8"));
13429
+ const session = JSON.parse(readFileSync26(join26(userPath, file), "utf-8"));
13356
13430
  onSession(session);
13357
13431
  } catch {
13358
13432
  continue;
@@ -13367,8 +13441,8 @@ class ClaudeDesktopAdapter {
13367
13441
  // src/agents/cursor.ts
13368
13442
  init_subprocess();
13369
13443
  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";
13444
+ import { join as join27 } from "path";
13445
+ import { homedir as homedir9, platform as platform4 } from "os";
13372
13446
 
13373
13447
  // src/utils/sqlite-adapter.ts
13374
13448
  var adapter = null;
@@ -13471,7 +13545,7 @@ class CursorAdapter {
13471
13545
  return true;
13472
13546
  }
13473
13547
  async writeMcpServers(servers, scope) {
13474
- const filePath = scope === "project" ? join26(process.cwd(), ".cursor", "mcp.json") : join26(homedir8(), ".cursor", "mcp.json");
13548
+ const filePath = scope === "project" ? join27(process.cwd(), ".cursor", "mcp.json") : join27(homedir9(), ".cursor", "mcp.json");
13475
13549
  const entries = {};
13476
13550
  for (const s of servers) {
13477
13551
  entries[s.name] = {
@@ -13484,7 +13558,7 @@ class CursorAdapter {
13484
13558
  async writeSkills(skills, scope) {
13485
13559
  if (scope === "user")
13486
13560
  return 0;
13487
- const rulesDir = join26(process.cwd(), ".cursor", "rules");
13561
+ const rulesDir = join27(process.cwd(), ".cursor", "rules");
13488
13562
  mkdirSync19(rulesDir, { recursive: true });
13489
13563
  for (const skill of skills) {
13490
13564
  const mdcContent = `---
@@ -13493,30 +13567,30 @@ alwaysApply: false
13493
13567
  ---
13494
13568
 
13495
13569
  ${skill.content}`;
13496
- writeFileSync19(join26(rulesDir, `${skill.filename}.mdc`), mdcContent);
13570
+ writeFileSync19(join27(rulesDir, `${skill.filename}.mdc`), mdcContent);
13497
13571
  }
13498
13572
  return skills.length;
13499
13573
  }
13500
13574
  async writeInstructionHint(hint, scope) {
13501
- const filePath = scope === "project" ? join26(process.cwd(), ".cursor", "rules", "runwork.mdc") : join26(homedir8(), ".cursor", "rules", "runwork.mdc");
13575
+ const filePath = scope === "project" ? join27(process.cwd(), ".cursor", "rules", "runwork.mdc") : join27(homedir9(), ".cursor", "rules", "runwork.mdc");
13502
13576
  const mdcContent = `---
13503
13577
  description: "Runwork workspace connection"
13504
13578
  alwaysApply: true
13505
13579
  ---
13506
13580
 
13507
13581
  ${hint}`;
13508
- mkdirSync19(join26(filePath, ".."), { recursive: true });
13582
+ mkdirSync19(join27(filePath, ".."), { recursive: true });
13509
13583
  writeFileSync19(filePath, mdcContent);
13510
13584
  }
13511
13585
  async writeTeamInstructions(instructions, scope) {
13512
- const filePath = scope === "project" ? join26(process.cwd(), ".cursor", "rules", "runwork-team.mdc") : join26(homedir8(), ".cursor", "rules", "runwork-team.mdc");
13586
+ const filePath = scope === "project" ? join27(process.cwd(), ".cursor", "rules", "runwork-team.mdc") : join27(homedir9(), ".cursor", "rules", "runwork-team.mdc");
13513
13587
  const mdcContent = `---
13514
13588
  description: "Team instructions from Runwork workspace"
13515
13589
  alwaysApply: true
13516
13590
  ---
13517
13591
 
13518
13592
  ${instructions}`;
13519
- mkdirSync19(join26(filePath, ".."), { recursive: true });
13593
+ mkdirSync19(join27(filePath, ".."), { recursive: true });
13520
13594
  writeFileSync19(filePath, mdcContent);
13521
13595
  }
13522
13596
  async writeAgentConfig(config, scope, baseline) {
@@ -13562,7 +13636,7 @@ ${instructions}`;
13562
13636
  return;
13563
13637
  }
13564
13638
  mergeSandboxAllowlist(domains) {
13565
- const configPath = join26(homedir8(), ".cursor", "sandbox.json");
13639
+ const configPath = join27(homedir9(), ".cursor", "sandbox.json");
13566
13640
  try {
13567
13641
  const config = readJsonConfig(configPath);
13568
13642
  if (!config.networkPolicy)
@@ -13580,15 +13654,15 @@ ${instructions}`;
13580
13654
  async removeSkills(skillFilenames, scope) {
13581
13655
  if (scope !== "project")
13582
13656
  return;
13583
- removeMatchingSkillFiles(join26(process.cwd(), ".cursor", "rules"), new Set(skillFilenames), ".mdc");
13657
+ removeMatchingSkillFiles(join27(process.cwd(), ".cursor", "rules"), new Set(skillFilenames), ".mdc");
13584
13658
  }
13585
13659
  async cleanup(scope, manifest) {
13586
- const mcpPath = scope === "project" ? join26(process.cwd(), ".cursor", "mcp.json") : join26(homedir8(), ".cursor", "mcp.json");
13660
+ const mcpPath = scope === "project" ? join27(process.cwd(), ".cursor", "mcp.json") : join27(homedir9(), ".cursor", "mcp.json");
13587
13661
  removeRunworkMcpServers(mcpPath, "mcpServers");
13588
- const rulesDir = scope === "project" ? join26(process.cwd(), ".cursor", "rules") : join26(homedir8(), ".cursor", "rules");
13662
+ const rulesDir = scope === "project" ? join27(process.cwd(), ".cursor", "rules") : join27(homedir9(), ".cursor", "rules");
13589
13663
  if (existsSync33(rulesDir)) {
13590
13664
  for (const file of ["runwork.mdc", "runwork-team.mdc"]) {
13591
- const filePath = join26(rulesDir, file);
13665
+ const filePath = join27(rulesDir, file);
13592
13666
  if (existsSync33(filePath)) {
13593
13667
  try {
13594
13668
  unlinkSync4(filePath);
@@ -13670,7 +13744,7 @@ ${instructions}`;
13670
13744
  }
13671
13745
  }
13672
13746
  const sessionCount = newComposersWithoutId + activeComposerIds.size;
13673
- const trackingDbPath = join26(homedir8(), ".cursor", "ai-tracking", "ai-code-tracking.db");
13747
+ const trackingDbPath = join27(homedir9(), ".cursor", "ai-tracking", "ai-code-tracking.db");
13674
13748
  let aiCommitCount = 0;
13675
13749
  let avgAiPercent = 0;
13676
13750
  if (existsSync33(trackingDbPath)) {
@@ -13716,12 +13790,12 @@ ${instructions}`;
13716
13790
  globalStorageDbPath() {
13717
13791
  const os2 = platform4();
13718
13792
  if (os2 === "darwin") {
13719
- return join26(homedir8(), "Library", "Application Support", "Cursor", "User", "globalStorage", "state.vscdb");
13793
+ return join27(homedir9(), "Library", "Application Support", "Cursor", "User", "globalStorage", "state.vscdb");
13720
13794
  }
13721
13795
  if (os2 === "win32") {
13722
- return join26(process.env.APPDATA || join26(homedir8(), "AppData", "Roaming"), "Cursor", "User", "globalStorage", "state.vscdb");
13796
+ return join27(process.env.APPDATA || join27(homedir9(), "AppData", "Roaming"), "Cursor", "User", "globalStorage", "state.vscdb");
13723
13797
  }
13724
- return join26(homedir8(), ".config", "Cursor", "User", "globalStorage", "state.vscdb");
13798
+ return join27(homedir9(), ".config", "Cursor", "User", "globalStorage", "state.vscdb");
13725
13799
  }
13726
13800
  async readSessionDigests(sinceISO) {
13727
13801
  try {
@@ -13741,16 +13815,16 @@ ${instructions}`;
13741
13815
 
13742
13816
  // src/agents/windsurf.ts
13743
13817
  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";
13818
+ import { join as join28 } from "path";
13819
+ import { homedir as homedir10, platform as platform5 } from "os";
13746
13820
  function getWindsurfDataDir() {
13747
13821
  if (platform5() === "win32") {
13748
- return join27(process.env.APPDATA || join27(homedir9(), "AppData", "Roaming"), "Codeium", "windsurf");
13822
+ return join28(process.env.APPDATA || join28(homedir10(), "AppData", "Roaming"), "Codeium", "windsurf");
13749
13823
  }
13750
- return join27(homedir9(), ".codeium", "windsurf");
13824
+ return join28(homedir10(), ".codeium", "windsurf");
13751
13825
  }
13752
13826
  function getConfigPath() {
13753
- return join27(getWindsurfDataDir(), "mcp_config.json");
13827
+ return join28(getWindsurfDataDir(), "mcp_config.json");
13754
13828
  }
13755
13829
 
13756
13830
  class WindsurfAdapter {
@@ -13782,7 +13856,7 @@ class WindsurfAdapter {
13782
13856
  async writeSkills(skills, scope) {
13783
13857
  if (scope === "user")
13784
13858
  return 0;
13785
- const rulesDir = join27(process.cwd(), ".windsurf", "rules");
13859
+ const rulesDir = join28(process.cwd(), ".windsurf", "rules");
13786
13860
  mkdirSync20(rulesDir, { recursive: true });
13787
13861
  for (const skill of skills) {
13788
13862
  const content = `---
@@ -13790,44 +13864,44 @@ trigger: manual
13790
13864
  ---
13791
13865
 
13792
13866
  ${skill.content}`;
13793
- writeFileSync20(join27(rulesDir, `${skill.filename}.md`), content);
13867
+ writeFileSync20(join28(rulesDir, `${skill.filename}.md`), content);
13794
13868
  }
13795
13869
  return skills.length;
13796
13870
  }
13797
13871
  async writeTeamInstructions(instructions, scope) {
13798
- const filePath = scope === "project" ? join27(process.cwd(), ".windsurf", "rules", "runwork-team.md") : join27(getWindsurfDataDir(), "rules", "runwork-team.md");
13872
+ const filePath = scope === "project" ? join28(process.cwd(), ".windsurf", "rules", "runwork-team.md") : join28(getWindsurfDataDir(), "rules", "runwork-team.md");
13799
13873
  const content = `---
13800
13874
  trigger: always_on
13801
13875
  description: "Team instructions from Runwork workspace"
13802
13876
  ---
13803
13877
 
13804
13878
  ${instructions}`;
13805
- mkdirSync20(join27(filePath, ".."), { recursive: true });
13879
+ mkdirSync20(join28(filePath, ".."), { recursive: true });
13806
13880
  writeFileSync20(filePath, content);
13807
13881
  }
13808
13882
  async writeInstructionHint(hint, scope) {
13809
- const filePath = scope === "project" ? join27(process.cwd(), ".windsurf", "rules", "runwork.md") : join27(getWindsurfDataDir(), "rules", "runwork.md");
13883
+ const filePath = scope === "project" ? join28(process.cwd(), ".windsurf", "rules", "runwork.md") : join28(getWindsurfDataDir(), "rules", "runwork.md");
13810
13884
  const content = `---
13811
13885
  trigger: always
13812
13886
  ---
13813
13887
 
13814
13888
  ${hint}`;
13815
- mkdirSync20(join27(filePath, ".."), { recursive: true });
13889
+ mkdirSync20(join28(filePath, ".."), { recursive: true });
13816
13890
  writeFileSync20(filePath, content);
13817
13891
  }
13818
13892
  async removeSkills(skillFilenames, scope) {
13819
13893
  if (scope !== "project")
13820
13894
  return;
13821
- removeMatchingSkillFiles(join27(process.cwd(), ".windsurf", "rules"), new Set(skillFilenames), ".md");
13895
+ removeMatchingSkillFiles(join28(process.cwd(), ".windsurf", "rules"), new Set(skillFilenames), ".md");
13822
13896
  }
13823
13897
  async cleanup(scope, manifest) {
13824
13898
  if (scope === "user") {
13825
13899
  removeRunworkMcpServers(getConfigPath(), "mcpServers");
13826
13900
  }
13827
- const rulesDir = scope === "project" ? join27(process.cwd(), ".windsurf", "rules") : join27(getWindsurfDataDir(), "rules");
13901
+ const rulesDir = scope === "project" ? join28(process.cwd(), ".windsurf", "rules") : join28(getWindsurfDataDir(), "rules");
13828
13902
  if (existsSync34(rulesDir)) {
13829
13903
  for (const file of ["runwork.md", "runwork-team.md"]) {
13830
- const filePath = join27(rulesDir, file);
13904
+ const filePath = join28(rulesDir, file);
13831
13905
  if (existsSync34(filePath)) {
13832
13906
  try {
13833
13907
  unlinkSync5(filePath);
@@ -13841,20 +13915,20 @@ ${hint}`;
13841
13915
 
13842
13916
  // src/agents/codex.ts
13843
13917
  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";
13918
+ import { join as join31 } from "path";
13919
+ import { homedir as homedir13 } from "os";
13846
13920
  import { parse, stringify } from "smol-toml";
13847
13921
 
13848
13922
  // src/agents/detection.ts
13849
13923
  import { execFile } from "child_process";
13850
13924
  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";
13925
+ import { homedir as homedir12, platform as platform7 } from "os";
13926
+ import { isAbsolute as isAbsolute2, join as join30 } from "path";
13853
13927
  import { promisify } from "util";
13854
13928
 
13855
13929
  // src/agents/registry.ts
13856
- import { platform as platform6, homedir as homedir10 } from "os";
13857
- import { isAbsolute, join as join28 } from "path";
13930
+ import { platform as platform6, homedir as homedir11 } from "os";
13931
+ import { isAbsolute, join as join29 } from "path";
13858
13932
  import { existsSync as existsSync35 } from "fs";
13859
13933
 
13860
13934
  // src/agents/registry-data.ts
@@ -14452,7 +14526,7 @@ function resolveToAbsolute(ps, scope) {
14452
14526
  const resolved = resolvePlatformString(ps);
14453
14527
  if (!resolved)
14454
14528
  return;
14455
- return scope === "global" ? join28(homedir10(), resolved) : join28(process.cwd(), resolved);
14529
+ return scope === "global" ? join29(homedir11(), resolved) : join29(process.cwd(), resolved);
14456
14530
  }
14457
14531
  function resolveAgentCliCommand(slug) {
14458
14532
  const agent = getAgent(slug);
@@ -14465,7 +14539,7 @@ function resolveAgentCliCommand(slug) {
14465
14539
  const resolved = resolvePlatformString(candidate);
14466
14540
  if (!resolved)
14467
14541
  continue;
14468
- const absolute = isAbsolute(resolved) ? resolved : join28(homedir10(), resolved);
14542
+ const absolute = isAbsolute(resolved) ? resolved : join29(homedir11(), resolved);
14469
14543
  if (existsSync35(absolute))
14470
14544
  return absolute;
14471
14545
  }
@@ -14509,7 +14583,7 @@ function resolveDetectionPath(target) {
14509
14583
  const resolved = resolvePlatformString(target);
14510
14584
  if (!resolved)
14511
14585
  return null;
14512
- return isAbsolute2(resolved) ? resolved : join29(homedir11(), resolved);
14586
+ return isAbsolute2(resolved) ? resolved : join30(homedir12(), resolved);
14513
14587
  }
14514
14588
  function checkPath(target) {
14515
14589
  const absolute = resolveDetectionPath(target);
@@ -14595,7 +14669,7 @@ class CodexAdapter {
14595
14669
  return true;
14596
14670
  }
14597
14671
  async writeMcpServers(servers, _scope) {
14598
- const configPath = join30(homedir12(), ".codex", "config.toml");
14672
+ const configPath = join31(homedir13(), ".codex", "config.toml");
14599
14673
  let parsed = {};
14600
14674
  if (existsSync37(configPath)) {
14601
14675
  parsed = parse(readFileSync27(configPath, "utf-8"));
@@ -14621,36 +14695,36 @@ class CodexAdapter {
14621
14695
  }
14622
14696
  mcpServers[safeName] = entry;
14623
14697
  }
14624
- mkdirSync21(join30(configPath, ".."), { recursive: true });
14698
+ mkdirSync21(join31(configPath, ".."), { recursive: true });
14625
14699
  writeFileSync21(configPath, stringify(parsed));
14626
14700
  }
14627
14701
  async writeSkills(skills, scope) {
14628
- const root = scope === "project" ? process.cwd() : homedir12();
14629
- const baseDir = join30(root, ".agents", "skills");
14630
- const legacyBaseDir = join30(root, ".codex", "skills");
14702
+ const root = scope === "project" ? process.cwd() : homedir13();
14703
+ const baseDir = join31(root, ".agents", "skills");
14704
+ const legacyBaseDir = join31(root, ".codex", "skills");
14631
14705
  for (const skill of skills) {
14632
14706
  if (skill.name !== skill.filename) {
14633
- for (const dir of [join30(baseDir, skill.name), join30(legacyBaseDir, skill.name)]) {
14707
+ for (const dir of [join31(baseDir, skill.name), join31(legacyBaseDir, skill.name)]) {
14634
14708
  moveToTrash(dir, `skill renamed to ${skill.filename}`);
14635
14709
  }
14636
14710
  }
14637
- moveToTrash(join30(legacyBaseDir, skill.filename), "duplicate skill root consolidated");
14638
- const skillDir = join30(baseDir, skill.filename);
14711
+ moveToTrash(join31(legacyBaseDir, skill.filename), "duplicate skill root consolidated");
14712
+ const skillDir = join31(baseDir, skill.filename);
14639
14713
  mkdirSync21(skillDir, { recursive: true });
14640
- writeFileSync21(join30(skillDir, "SKILL.md"), buildSkillMd2(skill));
14714
+ writeFileSync21(join31(skillDir, "SKILL.md"), buildSkillMd2(skill));
14641
14715
  }
14642
14716
  return skills.length;
14643
14717
  }
14644
14718
  async writeInstructionHint(hint, scope) {
14645
- const filePath = scope === "project" ? join30(process.cwd(), "AGENTS.md") : join30(homedir12(), ".codex", "AGENTS.md");
14719
+ const filePath = scope === "project" ? join31(process.cwd(), "AGENTS.md") : join31(homedir13(), ".codex", "AGENTS.md");
14646
14720
  writeHintToFile(filePath, hint);
14647
14721
  }
14648
14722
  async writeTeamInstructions(instructions, scope) {
14649
- const filePath = scope === "project" ? join30(process.cwd(), "AGENTS.md") : join30(homedir12(), ".codex", "AGENTS.md");
14723
+ const filePath = scope === "project" ? join31(process.cwd(), "AGENTS.md") : join31(homedir13(), ".codex", "AGENTS.md");
14650
14724
  writeTeamInstructionsToFile(filePath, instructions);
14651
14725
  }
14652
14726
  async writeAgentConfig(config, scope) {
14653
- const configPath = scope === "project" ? join30(process.cwd(), ".codex", "config.toml") : join30(homedir12(), ".codex", "config.toml");
14727
+ const configPath = scope === "project" ? join31(process.cwd(), ".codex", "config.toml") : join31(homedir13(), ".codex", "config.toml");
14654
14728
  let parsed = {};
14655
14729
  if (existsSync37(configPath)) {
14656
14730
  parsed = parse(readFileSync27(configPath, "utf-8"));
@@ -14696,20 +14770,20 @@ class CodexAdapter {
14696
14770
  sww.network_access = true;
14697
14771
  }
14698
14772
  }
14699
- mkdirSync21(join30(configPath, ".."), { recursive: true });
14773
+ mkdirSync21(join31(configPath, ".."), { recursive: true });
14700
14774
  writeFileSync21(configPath, stringify(parsed));
14701
14775
  }
14702
14776
  async removeSkills(skillFilenames, scope) {
14703
14777
  if (!skillFilenames.length)
14704
14778
  return;
14705
14779
  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")]) {
14780
+ const root = scope === "project" ? process.cwd() : homedir13();
14781
+ for (const skillsDir of [join31(root, ".agents", "skills"), join31(root, ".codex", "skills")]) {
14708
14782
  removeMatchingSkillDirs(skillsDir, allowed);
14709
14783
  }
14710
14784
  }
14711
14785
  async cleanup(scope, manifest) {
14712
- const configPath = join30(homedir12(), ".codex", "config.toml");
14786
+ const configPath = join31(homedir13(), ".codex", "config.toml");
14713
14787
  if (existsSync37(configPath)) {
14714
14788
  try {
14715
14789
  const parsed = parse(readFileSync27(configPath, "utf-8"));
@@ -14725,13 +14799,13 @@ class CodexAdapter {
14725
14799
  } catch {}
14726
14800
  }
14727
14801
  await this.removeSkills(manifest?.skillFilenames ?? [], scope);
14728
- const instructionFile = scope === "project" ? join30(process.cwd(), "AGENTS.md") : join30(homedir12(), ".codex", "AGENTS.md");
14802
+ const instructionFile = scope === "project" ? join31(process.cwd(), "AGENTS.md") : join31(homedir13(), ".codex", "AGENTS.md");
14729
14803
  removeHintFromFile(instructionFile);
14730
14804
  removeTeamInstructionsFromFile(instructionFile);
14731
14805
  }
14732
14806
  async readUsageStats(lastSyncAt) {
14733
14807
  try {
14734
- const codexDir = join30(homedir12(), ".codex");
14808
+ const codexDir = join31(homedir13(), ".codex");
14735
14809
  if (!existsSync37(codexDir))
14736
14810
  return null;
14737
14811
  const sinceMs = lastSyncAt ? new Date(lastSyncAt).getTime() : 0;
@@ -14741,7 +14815,7 @@ class CodexAdapter {
14741
14815
  let tokensUsed = rollout.tokensUsed;
14742
14816
  let latestMs = rollout.latestMs;
14743
14817
  let versions = [];
14744
- const dbPath = join30(codexDir, "state_5.sqlite");
14818
+ const dbPath = join31(codexDir, "state_5.sqlite");
14745
14819
  if (existsSync37(dbPath)) {
14746
14820
  const countResult = queryReadonlySqlite(dbPath, `SELECT count(*) FROM threads WHERE updated_at > ${sinceSec}`);
14747
14821
  const dbSessionCount = parseInt(countResult) || 0;
@@ -14759,7 +14833,7 @@ class CodexAdapter {
14759
14833
  }
14760
14834
  let messageCount = rollout.messageCount;
14761
14835
  if (messageCount === 0) {
14762
- const historyPath = join30(codexDir, "history.jsonl");
14836
+ const historyPath = join31(codexDir, "history.jsonl");
14763
14837
  if (existsSync37(historyPath)) {
14764
14838
  const content = readFileSync27(historyPath, "utf-8").trim();
14765
14839
  if (content) {
@@ -14804,7 +14878,7 @@ class CodexAdapter {
14804
14878
  latestMs: 0,
14805
14879
  activeDays: []
14806
14880
  };
14807
- const sessionsDir = join30(homedir12(), ".codex", "sessions");
14881
+ const sessionsDir = join31(homedir13(), ".codex", "sessions");
14808
14882
  if (!existsSync37(sessionsDir))
14809
14883
  return result;
14810
14884
  const files = [];
@@ -14816,7 +14890,7 @@ class CodexAdapter {
14816
14890
  return;
14817
14891
  }
14818
14892
  for (const e of entries) {
14819
- const full = join30(dir, e.name);
14893
+ const full = join31(dir, e.name);
14820
14894
  if (e.isDirectory())
14821
14895
  walk(full);
14822
14896
  else if (e.name.startsWith("rollout-") && e.name.endsWith(".jsonl"))
@@ -14894,7 +14968,7 @@ class CodexAdapter {
14894
14968
  }
14895
14969
  async readSessionDigests(sinceISO) {
14896
14970
  try {
14897
- const sessionsDir = join30(homedir12(), ".codex", "sessions");
14971
+ const sessionsDir = join31(homedir13(), ".codex", "sessions");
14898
14972
  if (!existsSync37(sessionsDir))
14899
14973
  return null;
14900
14974
  const sinceMs = sinceISO ? new Date(sinceISO).getTime() : 0;
@@ -14907,7 +14981,7 @@ class CodexAdapter {
14907
14981
  return;
14908
14982
  }
14909
14983
  for (const e of entries) {
14910
- const full = join30(dir, e.name);
14984
+ const full = join31(dir, e.name);
14911
14985
  if (e.isDirectory())
14912
14986
  walk(full);
14913
14987
  else if (e.name.startsWith("rollout-") && e.name.endsWith(".jsonl"))
@@ -14942,7 +15016,7 @@ class CodexAdapter {
14942
15016
  }
14943
15017
  async readVersion() {
14944
15018
  try {
14945
- const versionPath = join30(homedir12(), ".codex", "version.json");
15019
+ const versionPath = join31(homedir13(), ".codex", "version.json");
14946
15020
  if (existsSync37(versionPath)) {
14947
15021
  const data = JSON.parse(readFileSync27(versionPath, "utf-8"));
14948
15022
  return data.latest_version ?? null;
@@ -14952,7 +15026,7 @@ class CodexAdapter {
14952
15026
  }
14953
15027
  async readSkillUsage(lastSyncAt) {
14954
15028
  try {
14955
- const sessionsDir = join30(homedir12(), ".codex", "sessions");
15029
+ const sessionsDir = join31(homedir13(), ".codex", "sessions");
14956
15030
  if (!existsSync37(sessionsDir))
14957
15031
  return null;
14958
15032
  const sinceMs = lastSyncAt ? new Date(lastSyncAt).getTime() : 0;
@@ -14965,7 +15039,7 @@ class CodexAdapter {
14965
15039
  return;
14966
15040
  }
14967
15041
  for (const entry of entries) {
14968
- const fullPath = join30(dir, entry);
15042
+ const fullPath = join31(dir, entry);
14969
15043
  if (entry.endsWith(".jsonl")) {
14970
15044
  let fileStat;
14971
15045
  try {
@@ -15054,7 +15128,7 @@ class CodexAdapter {
15054
15128
  }
15055
15129
  }
15056
15130
  registerDesktopWorkspace(workspacePath, label) {
15057
- const statePath = join30(homedir12(), ".codex", ".codex-global-state.json");
15131
+ const statePath = join31(homedir13(), ".codex", ".codex-global-state.json");
15058
15132
  let state = {};
15059
15133
  if (existsSync37(statePath)) {
15060
15134
  try {
@@ -15085,7 +15159,7 @@ class CodexAdapter {
15085
15159
  }
15086
15160
  labels[workspacePath] = label;
15087
15161
  state["electron-workspace-root-labels"] = labels;
15088
- mkdirSync21(join30(statePath, ".."), { recursive: true });
15162
+ mkdirSync21(join31(statePath, ".."), { recursive: true });
15089
15163
  writeFileSync21(statePath, JSON.stringify(state));
15090
15164
  return "written";
15091
15165
  }
@@ -15107,8 +15181,8 @@ class CodexDesktopAdapter extends CodexAdapter {
15107
15181
 
15108
15182
  // src/agents/cline.ts
15109
15183
  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";
15184
+ import { join as join32 } from "path";
15185
+ import { homedir as homedir14 } from "os";
15112
15186
  class ClineAdapter {
15113
15187
  name = "Cline";
15114
15188
  slug = "cline";
@@ -15123,7 +15197,7 @@ class ClineAdapter {
15123
15197
  return true;
15124
15198
  }
15125
15199
  async writeMcpServers(servers, _scope) {
15126
- const configPath = join31(homedir13(), ".cline", "data", "settings", "cline_mcp_settings.json");
15200
+ const configPath = join32(homedir14(), ".cline", "data", "settings", "cline_mcp_settings.json");
15127
15201
  const entries = {};
15128
15202
  for (const s of servers) {
15129
15203
  entries[s.name] = {
@@ -15136,31 +15210,31 @@ class ClineAdapter {
15136
15210
  async writeSkills(skills, scope) {
15137
15211
  if (scope === "user")
15138
15212
  return 0;
15139
- const rulesDir = join31(process.cwd(), ".clinerules");
15213
+ const rulesDir = join32(process.cwd(), ".clinerules");
15140
15214
  mkdirSync22(rulesDir, { recursive: true });
15141
15215
  for (const skill of skills) {
15142
- writeFileSync22(join31(rulesDir, `${skill.filename}.md`), buildSkillMd2(skill));
15216
+ writeFileSync22(join32(rulesDir, `${skill.filename}.md`), buildSkillMd2(skill));
15143
15217
  }
15144
15218
  return skills.length;
15145
15219
  }
15146
15220
  async writeInstructionHint(hint, scope) {
15147
15221
  if (scope === "user")
15148
15222
  return;
15149
- const filePath = join31(process.cwd(), ".clinerules", "runwork.md");
15150
- mkdirSync22(join31(filePath, ".."), { recursive: true });
15223
+ const filePath = join32(process.cwd(), ".clinerules", "runwork.md");
15224
+ mkdirSync22(join32(filePath, ".."), { recursive: true });
15151
15225
  writeFileSync22(filePath, hint);
15152
15226
  }
15153
15227
  async writeTeamInstructions(instructions, scope) {
15154
15228
  if (scope === "user")
15155
15229
  return;
15156
- const filePath = join31(process.cwd(), ".clinerules", "runwork-team.md");
15157
- mkdirSync22(join31(filePath, ".."), { recursive: true });
15230
+ const filePath = join32(process.cwd(), ".clinerules", "runwork-team.md");
15231
+ mkdirSync22(join32(filePath, ".."), { recursive: true });
15158
15232
  writeFileSync22(filePath, instructions);
15159
15233
  }
15160
15234
  async writeAgentConfig(config, scope) {
15161
15235
  if (scope !== "user")
15162
15236
  return;
15163
- const globalStatePath = join31(homedir13(), ".cline", "data", "globalState.json");
15237
+ const globalStatePath = join32(homedir14(), ".cline", "data", "globalState.json");
15164
15238
  let state = {};
15165
15239
  if (existsSync38(globalStatePath)) {
15166
15240
  try {
@@ -15185,24 +15259,24 @@ class ClineAdapter {
15185
15259
  state.autoApprovalSettings.enabled = false;
15186
15260
  }
15187
15261
  }
15188
- mkdirSync22(join31(globalStatePath, ".."), { recursive: true });
15262
+ mkdirSync22(join32(globalStatePath, ".."), { recursive: true });
15189
15263
  writeFileSync22(globalStatePath, JSON.stringify(state, null, 2));
15190
15264
  }
15191
15265
  async removeSkills(skillFilenames, scope) {
15192
15266
  if (scope !== "project")
15193
15267
  return;
15194
- removeMatchingSkillFiles(join31(process.cwd(), ".clinerules"), new Set(skillFilenames), ".md");
15268
+ removeMatchingSkillFiles(join32(process.cwd(), ".clinerules"), new Set(skillFilenames), ".md");
15195
15269
  }
15196
15270
  async cleanup(scope, manifest) {
15197
15271
  if (scope === "user") {
15198
- const configPath = join31(homedir13(), ".cline", "data", "settings", "cline_mcp_settings.json");
15272
+ const configPath = join32(homedir14(), ".cline", "data", "settings", "cline_mcp_settings.json");
15199
15273
  removeRunworkMcpServers(configPath, "mcpServers");
15200
15274
  }
15201
15275
  if (scope === "project") {
15202
- const rulesDir = join31(process.cwd(), ".clinerules");
15276
+ const rulesDir = join32(process.cwd(), ".clinerules");
15203
15277
  if (existsSync38(rulesDir)) {
15204
15278
  for (const file of ["runwork.md", "runwork-team.md"]) {
15205
- const filePath = join31(rulesDir, file);
15279
+ const filePath = join32(rulesDir, file);
15206
15280
  if (existsSync38(filePath)) {
15207
15281
  try {
15208
15282
  unlinkSync6(filePath);
@@ -15221,8 +15295,8 @@ class ClineAdapter {
15221
15295
 
15222
15296
  // src/agents/gemini.ts
15223
15297
  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";
15298
+ import { join as join33 } from "path";
15299
+ import { homedir as homedir15 } from "os";
15226
15300
  class GeminiAdapter {
15227
15301
  name = "Gemini CLI";
15228
15302
  slug = "gemini";
@@ -15237,7 +15311,7 @@ class GeminiAdapter {
15237
15311
  return true;
15238
15312
  }
15239
15313
  async writeMcpServers(servers, _scope) {
15240
- const configPath = join32(homedir14(), ".gemini", "settings.json");
15314
+ const configPath = join33(homedir15(), ".gemini", "settings.json");
15241
15315
  const entries = {};
15242
15316
  for (const s of servers) {
15243
15317
  entries[s.name] = {
@@ -15248,27 +15322,27 @@ class GeminiAdapter {
15248
15322
  mergeJsonMcpServers(configPath, entries, "mcpServers");
15249
15323
  }
15250
15324
  async writeSkills(skills, scope) {
15251
- const baseDir = scope === "project" ? join32(process.cwd(), ".gemini", "skills") : join32(homedir14(), ".gemini", "skills");
15325
+ const baseDir = scope === "project" ? join33(process.cwd(), ".gemini", "skills") : join33(homedir15(), ".gemini", "skills");
15252
15326
  for (const skill of skills) {
15253
15327
  if (skill.name !== skill.filename) {
15254
- moveToTrash(join32(baseDir, skill.name), `skill renamed to ${skill.filename}`);
15328
+ moveToTrash(join33(baseDir, skill.name), `skill renamed to ${skill.filename}`);
15255
15329
  }
15256
- const skillDir = join32(baseDir, skill.filename);
15330
+ const skillDir = join33(baseDir, skill.filename);
15257
15331
  mkdirSync23(skillDir, { recursive: true });
15258
- writeFileSync23(join32(skillDir, "SKILL.md"), buildSkillMd2(skill));
15332
+ writeFileSync23(join33(skillDir, "SKILL.md"), buildSkillMd2(skill));
15259
15333
  }
15260
15334
  return skills.length;
15261
15335
  }
15262
15336
  async writeInstructionHint(hint, scope) {
15263
- const filePath = scope === "project" ? join32(process.cwd(), "GEMINI.md") : join32(homedir14(), ".gemini", "GEMINI.md");
15337
+ const filePath = scope === "project" ? join33(process.cwd(), "GEMINI.md") : join33(homedir15(), ".gemini", "GEMINI.md");
15264
15338
  writeHintToFile(filePath, hint);
15265
15339
  }
15266
15340
  async writeTeamInstructions(instructions, scope) {
15267
- const filePath = scope === "project" ? join32(process.cwd(), "GEMINI.md") : join32(homedir14(), ".gemini", "GEMINI.md");
15341
+ const filePath = scope === "project" ? join33(process.cwd(), "GEMINI.md") : join33(homedir15(), ".gemini", "GEMINI.md");
15268
15342
  writeTeamInstructionsToFile(filePath, instructions);
15269
15343
  }
15270
15344
  async writeAgentConfig(config, scope) {
15271
- const settingsPath = scope === "project" ? join32(process.cwd(), ".gemini", "settings.json") : join32(homedir14(), ".gemini", "settings.json");
15345
+ const settingsPath = scope === "project" ? join33(process.cwd(), ".gemini", "settings.json") : join33(homedir15(), ".gemini", "settings.json");
15272
15346
  let settings = {};
15273
15347
  if (existsSync39(settingsPath)) {
15274
15348
  try {
@@ -15290,12 +15364,12 @@ class GeminiAdapter {
15290
15364
  settings.tools = {};
15291
15365
  settings.tools.exclude = config.permissionRules.deny;
15292
15366
  }
15293
- mkdirSync23(join32(settingsPath, ".."), { recursive: true });
15367
+ mkdirSync23(join33(settingsPath, ".."), { recursive: true });
15294
15368
  writeFileSync23(settingsPath, JSON.stringify(settings, null, 2));
15295
15369
  }
15296
15370
  async readUsageStats(lastSyncAt) {
15297
15371
  try {
15298
- const tmpDir = join32(homedir14(), ".gemini", "tmp");
15372
+ const tmpDir = join33(homedir15(), ".gemini", "tmp");
15299
15373
  if (!existsSync39(tmpDir))
15300
15374
  return null;
15301
15375
  const sinceMs = lastSyncAt ? new Date(lastSyncAt).getTime() : 0;
@@ -15312,7 +15386,7 @@ class GeminiAdapter {
15312
15386
  for (const project of projects) {
15313
15387
  if (!project.isDirectory())
15314
15388
  continue;
15315
- const chatsDir = join32(tmpDir, project.name, "chats");
15389
+ const chatsDir = join33(tmpDir, project.name, "chats");
15316
15390
  let files;
15317
15391
  try {
15318
15392
  files = readdirSync13(chatsDir, { withFileTypes: true });
@@ -15322,7 +15396,7 @@ class GeminiAdapter {
15322
15396
  for (const file of files) {
15323
15397
  if (!file.name.startsWith("session-") || !file.name.endsWith(".json"))
15324
15398
  continue;
15325
- const filePath = join32(chatsDir, file.name);
15399
+ const filePath = join33(chatsDir, file.name);
15326
15400
  let stat;
15327
15401
  try {
15328
15402
  stat = statSync7(filePath);
@@ -15374,15 +15448,15 @@ class GeminiAdapter {
15374
15448
  }
15375
15449
  }
15376
15450
  async removeSkills(skillFilenames, scope) {
15377
- const skillsDir = scope === "project" ? join32(process.cwd(), ".gemini", "skills") : join32(homedir14(), ".gemini", "skills");
15451
+ const skillsDir = scope === "project" ? join33(process.cwd(), ".gemini", "skills") : join33(homedir15(), ".gemini", "skills");
15378
15452
  removeMatchingSkillDirs(skillsDir, new Set(skillFilenames));
15379
15453
  }
15380
15454
  async cleanup(scope, manifest) {
15381
15455
  if (scope === "user") {
15382
- removeRunworkMcpServers(join32(homedir14(), ".gemini", "settings.json"), "mcpServers");
15456
+ removeRunworkMcpServers(join33(homedir15(), ".gemini", "settings.json"), "mcpServers");
15383
15457
  }
15384
15458
  await this.removeSkills(manifest?.skillFilenames ?? [], scope);
15385
- const instructionFile = scope === "project" ? join32(process.cwd(), "GEMINI.md") : join32(homedir14(), ".gemini", "GEMINI.md");
15459
+ const instructionFile = scope === "project" ? join33(process.cwd(), "GEMINI.md") : join33(homedir15(), ".gemini", "GEMINI.md");
15386
15460
  removeHintFromFile(instructionFile);
15387
15461
  removeTeamInstructionsFromFile(instructionFile);
15388
15462
  }
@@ -15390,8 +15464,8 @@ class GeminiAdapter {
15390
15464
 
15391
15465
  // src/agents/generic-adapter.ts
15392
15466
  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";
15467
+ import { join as join34 } from "path";
15468
+ import { homedir as homedir16 } from "os";
15395
15469
  class GenericAgentAdapter {
15396
15470
  name;
15397
15471
  slug;
@@ -15416,7 +15490,7 @@ class GenericAgentAdapter {
15416
15490
  async writeMcpServers(servers, _scope) {
15417
15491
  if (!this.def.mcpConfigPath)
15418
15492
  return;
15419
- const filePath = join33(homedir15(), resolvePlatformString(this.def.mcpConfigPath) || "");
15493
+ const filePath = join34(homedir16(), resolvePlatformString(this.def.mcpConfigPath) || "");
15420
15494
  if (!filePath)
15421
15495
  return;
15422
15496
  const entries = {};
@@ -15440,16 +15514,16 @@ class GenericAgentAdapter {
15440
15514
  return 0;
15441
15515
  for (const skill of skills) {
15442
15516
  if (skill.name !== skill.filename) {
15443
- const oldDir = join33(baseDir, skill.name);
15517
+ const oldDir = join34(baseDir, skill.name);
15444
15518
  if (existsSync40(oldDir)) {
15445
15519
  try {
15446
15520
  rmSync12(oldDir, { recursive: true, force: true });
15447
15521
  } catch {}
15448
15522
  }
15449
15523
  }
15450
- const skillDir = join33(baseDir, skill.filename);
15524
+ const skillDir = join34(baseDir, skill.filename);
15451
15525
  mkdirSync24(skillDir, { recursive: true });
15452
- writeFileSync24(join33(skillDir, "SKILL.md"), buildSkillMd2(skill));
15526
+ writeFileSync24(join34(skillDir, "SKILL.md"), buildSkillMd2(skill));
15453
15527
  }
15454
15528
  return skills.length;
15455
15529
  }
@@ -15489,7 +15563,7 @@ class GenericAgentAdapter {
15489
15563
  if (this.def.mcpConfigPath && scope === "user") {
15490
15564
  const resolved = resolvePlatformString(this.def.mcpConfigPath);
15491
15565
  if (resolved) {
15492
- const filePath = join33(homedir15(), resolved);
15566
+ const filePath = join34(homedir16(), resolved);
15493
15567
  removeRunworkMcpServers(filePath, this.def.mcpConfigKey || "mcpServers");
15494
15568
  }
15495
15569
  }
@@ -15571,13 +15645,13 @@ function insightLocalKey(teaches, slug) {
15571
15645
  // src/reflect/insight-store.ts
15572
15646
  init_atomic_json();
15573
15647
  import { existsSync as existsSync41, readFileSync as readFileSync30 } from "fs";
15574
- import { join as join34 } from "path";
15575
- import { homedir as homedir16 } from "os";
15576
- function storePath() {
15577
- return join34(homedir16(), ".runwork", "insights.json");
15648
+ import { join as join35 } from "path";
15649
+ import { homedir as homedir17 } from "os";
15650
+ function storePath2() {
15651
+ return join35(homedir17(), ".runwork", "insights.json");
15578
15652
  }
15579
15653
  function readAll() {
15580
- const path2 = storePath();
15654
+ const path2 = storePath2();
15581
15655
  if (!existsSync41(path2))
15582
15656
  return {};
15583
15657
  try {
@@ -15588,7 +15662,7 @@ function readAll() {
15588
15662
  }
15589
15663
  }
15590
15664
  function writeAll(store) {
15591
- writeJsonAtomic(storePath(), store);
15665
+ writeJsonAtomic(storePath2(), store);
15592
15666
  }
15593
15667
  function notExpired(i, now) {
15594
15668
  const t = new Date(i.expiresAt).getTime();
@@ -15622,15 +15696,15 @@ function getInsight(id, opts = {}) {
15622
15696
  // src/reflect/cadence.ts
15623
15697
  init_atomic_json();
15624
15698
  import { existsSync as existsSync42, readFileSync as readFileSync31 } from "fs";
15625
- import { join as join35 } from "path";
15626
- import { homedir as homedir17 } from "os";
15699
+ import { join as join36 } from "path";
15700
+ import { homedir as homedir18 } from "os";
15627
15701
  var DEFAULT_STATE = { enabled: false, lastReflectedAt: null };
15628
15702
  var COOLDOWN_HOURS = 20;
15629
15703
  var ACTIVE_SESSION_THRESHOLD = 10;
15630
15704
  var MAX_INTERVAL_HOURS = 7 * 24;
15631
15705
  var MIN_SESSIONS_FIRST_RUN = 3;
15632
15706
  function statePath() {
15633
- return join35(homedir17(), ".runwork", "reflect-state.json");
15707
+ return join36(homedir18(), ".runwork", "reflect-state.json");
15634
15708
  }
15635
15709
  function loadCadenceState() {
15636
15710
  try {
@@ -15666,39 +15740,8 @@ function isReflectionDue(state, newSessionCount, now = new Date) {
15666
15740
  return hoursSince >= MAX_INTERVAL_HOURS;
15667
15741
  }
15668
15742
 
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
-
15701
15743
  // src/commands/reflect.ts
15744
+ init_workspace_state();
15702
15745
  init_atomic_json();
15703
15746
  init_colors();
15704
15747
  var MAX_NAMES = 40;
@@ -18051,7 +18094,52 @@ function summarizeTelemetryForDryRun(result) {
18051
18094
  return `Telemetry preview: ${plural(result.events.length, "event")} would be sent (${plural(activeCount, "adapter")} with activity). Use --verbose for details.`;
18052
18095
  }
18053
18096
 
18054
- // src/agents/intro-skill.ts
18097
+ // ../../shared/agent-instructions/runwork-instructions.ts
18098
+ function formatList(items, max = 8) {
18099
+ if (items.length <= max)
18100
+ return items.join(", ");
18101
+ return `${items.slice(0, max).join(", ")} + ${items.length - max} more`;
18102
+ }
18103
+ function plural(n, one, many) {
18104
+ return n > 1 ? many : one;
18105
+ }
18106
+ function pushGroup(parts, group, one, many) {
18107
+ if (group.count <= 0)
18108
+ return;
18109
+ const label = `${group.count} ${plural(group.count, one, many)}`;
18110
+ parts.push(group.names.length > 0 ? `${label} (${formatList(group.names, 3)})` : label);
18111
+ }
18112
+ function buildInventoryLine(inv) {
18113
+ const parts = [];
18114
+ if (inv.appCount > 0)
18115
+ parts.push(`${inv.appCount} ${plural(inv.appCount, "app", "apps")}`);
18116
+ if (inv.entityNames.length > 0) {
18117
+ const n = inv.entityNames.length;
18118
+ parts.push(`${n} ${plural(n, "entity", "entities")} (${formatList(inv.entityNames, 5)})`);
18119
+ }
18120
+ if (inv.fileStorageCount > 0) {
18121
+ parts.push(`${inv.fileStorageCount} ${plural(inv.fileStorageCount, "file storage", "file storages")}`);
18122
+ }
18123
+ pushGroup(parts, inv.schedules, "schedule", "schedules");
18124
+ pushGroup(parts, inv.workflows, "workflow", "workflows");
18125
+ pushGroup(parts, inv.agents, "agent", "agents");
18126
+ if (inv.endpointCount > 0) {
18127
+ parts.push(`${inv.endpointCount} ${plural(inv.endpointCount, "endpoint", "endpoints")}`);
18128
+ }
18129
+ if (inv.componentCount > 0) {
18130
+ parts.push(`${inv.componentCount} ${plural(inv.componentCount, "component", "components")}`);
18131
+ }
18132
+ if (inv.integrationIds.length > 0) {
18133
+ const n = inv.integrationIds.length;
18134
+ parts.push(`${n} ${plural(n, "integration", "integrations")} (${formatList(inv.integrationIds, 5)})`);
18135
+ }
18136
+ if (inv.skillCount > 0)
18137
+ parts.push(`${inv.skillCount} ${plural(inv.skillCount, "skill", "skills")}`);
18138
+ if (inv.mcpServerCount > 0) {
18139
+ parts.push(`${inv.mcpServerCount} MCP ${plural(inv.mcpServerCount, "server", "servers")}`);
18140
+ }
18141
+ return parts.length > 0 ? parts.join(", ") : "no resources deployed yet";
18142
+ }
18055
18143
  function buildPersonaBlock(persona) {
18056
18144
  if (!persona || persona.level === 3)
18057
18145
  return [];
@@ -18080,57 +18168,65 @@ function buildPersonaBlock(persona) {
18080
18168
  "- Keep explanations concise and outcome-focused."
18081
18169
  ];
18082
18170
  }
18083
- function formatList(items, max = 8) {
18084
- if (items.length <= max)
18085
- return items.join(", ");
18086
- return `${items.slice(0, max).join(", ")} + ${items.length - max} more`;
18171
+ var ROUTING_TABLE = [
18172
+ "| User asks for | Use Runwork | Don't |",
18173
+ "|---|---|---|",
18174
+ "| save / create / share / update a skill | `save_skill` MCP tool | local SKILL.md files, prompt snippets |",
18175
+ "| store, persist, or remember structured data | `entity_{Name}` MCP tools | local SQLite, JSON files, in-memory |",
18176
+ "| schedule a recurring or cron job | Runwork schedules (`schedule_{name}`, `runwork schedules`) | OS cron, `setInterval`, Celery |",
18177
+ "| multi-step process, pipeline, or durable workflow | Runwork workflows (`workflow_{name}`) | ad-hoc scripts, shell pipelines |",
18178
+ "| call Slack / HubSpot / Gmail / Google / any third-party API | `{id}_api` MCP tools (e.g. `hubspot_api`) | raw `fetch`, hand-built auth, SDK installs |",
18179
+ "| upload, save, or serve a file | Runwork file storage (`list_bucket_files`, `generate_user_presigned_url`) | local filesystem, `fs.writeFile` |",
18180
+ "| expose a public API / webhook endpoint | Runwork endpoints (`endpoint_*`) | standalone Express/Flask servers |",
18181
+ "| share AI prompts, instructions, or expertise with the team | `save_skill` MCP tool | local prompt files, copy-paste |",
18182
+ "| connect an AI tool or MCP server | Runwork MCP servers | manual `settings.json` edits per machine |",
18183
+ "| build a new internal tool, team app, or automation | `runwork init` -> `runwork dev` -> `runwork deploy` | one-off scripts, notebooks |"
18184
+ ];
18185
+ var PRODUCT_DEV_EXCEPTION = "**Exception -- product development:** Editing your current codebase, running tests, git operations, and building features in the product you're working on are NOT Runwork territory. Runwork is for infrastructure and team tooling, not the product itself.";
18186
+ function buildRunworkInstructions(ctx) {
18187
+ const { workspaceName, workspaceId, workspaceSlug, inventory, surface = "machine" } = ctx;
18188
+ const dashboardUrl = workspaceSlug ? `https://${workspaceSlug}.runwork.ai` : "https://runwork.ai";
18189
+ const workspaceIdLine = `Workspace ID: \`${workspaceId}\`${workspaceSlug ? ` | Dashboard: ${dashboardUrl}` : ""}`;
18190
+ const connection = surface === "mcp" ? `You are connected to the **${workspaceName}** Runwork workspace` : `This machine is connected to the **${workspaceName}** Runwork workspace`;
18191
+ const integrationToolHint = inventory.integrationIds.length > 0 ? ` Connected integrations are callable via MCP tools (${inventory.integrationIds.map((id) => `\`${id}_api\``).join(", ")}) or CLI (\`runwork integrations call <id> <method> <path>\`).` : "";
18192
+ const lines = [
18193
+ "## Runwork",
18194
+ "",
18195
+ `${connection} -- your team's shared platform for building and running infrastructure: apps, data & file storage, scheduled jobs, workflows, integrations, AI agents, skills, MCP servers, public APIs, and reusable components.`,
18196
+ "",
18197
+ workspaceIdLine,
18198
+ ""
18199
+ ];
18200
+ lines.push("**Default to Runwork -- team sync beats local files.** When the user asks for any of the following, use the Runwork tool shown. These operations sync across every teammate's AI agents; local alternatives only work for the current user.", "", ...ROUTING_TABLE, "", PRODUCT_DEV_EXCEPTION, "", `**Available now:** ${buildInventoryLine(inventory)}`, "", `Runwork MCP tools are always connected -- use them for data access, integration API calls, skill management, and resource discovery.${integrationToolHint} Use \`runwork\` CLI to create (\`runwork init\`), develop (\`runwork dev\`), and deploy (\`runwork deploy\`) apps. Install CLI: \`curl -fsSL https://runwork.ai/install.sh | sh\`. Web dashboard: ${dashboardUrl}. Invoke the \`runwork\` skill for full capability reference.`, ...buildPersonaBlock(ctx.persona));
18201
+ return lines.join(`
18202
+ `);
18087
18203
  }
18088
- function buildInventoryLine(ctx) {
18089
- const parts = [];
18090
- if (ctx.appCount > 0)
18091
- parts.push(`${ctx.appCount} app${ctx.appCount > 1 ? "s" : ""}`);
18092
- if (ctx.registries) {
18093
- const reg = ctx.registries;
18094
- if (reg.entities.length > 0) {
18095
- const uniqueNames = [...new Set(reg.entities.map((e) => e.entityName))];
18096
- parts.push(`${uniqueNames.length} entit${uniqueNames.length > 1 ? "ies" : "y"} (${formatList(uniqueNames, 5)})`);
18097
- }
18098
- if (reg.fileStorages.length > 0)
18099
- parts.push(`${reg.fileStorages.length} file storage${reg.fileStorages.length > 1 ? "s" : ""}`);
18100
- if (reg.schedules.length > 0) {
18101
- const names = reg.schedules.map((s) => s.name).filter(Boolean);
18102
- if (names.length > 0)
18103
- parts.push(`${reg.schedules.length} schedule${reg.schedules.length > 1 ? "s" : ""} (${formatList(names, 3)})`);
18104
- else
18105
- parts.push(`${reg.schedules.length} schedule${reg.schedules.length > 1 ? "s" : ""}`);
18106
- }
18107
- if (reg.workflows.length > 0) {
18108
- const names = reg.workflows.map((w) => w.name).filter(Boolean);
18109
- if (names.length > 0)
18110
- parts.push(`${reg.workflows.length} workflow${reg.workflows.length > 1 ? "s" : ""} (${formatList(names, 3)})`);
18111
- else
18112
- parts.push(`${reg.workflows.length} workflow${reg.workflows.length > 1 ? "s" : ""}`);
18113
- }
18114
- if (reg.agents.length > 0) {
18115
- const names = reg.agents.map((a) => a.name).filter(Boolean);
18116
- if (names.length > 0)
18117
- parts.push(`${reg.agents.length} agent${reg.agents.length > 1 ? "s" : ""} (${formatList(names, 3)})`);
18118
- else
18119
- parts.push(`${reg.agents.length} agent${reg.agents.length > 1 ? "s" : ""}`);
18120
- }
18121
- if (reg.endpoints.length > 0)
18122
- parts.push(`${reg.endpoints.length} endpoint${reg.endpoints.length > 1 ? "s" : ""}`);
18123
- if (reg.components.length > 0)
18124
- parts.push(`${reg.components.length} component${reg.components.length > 1 ? "s" : ""}`);
18125
- }
18126
- if (ctx.connectedIntegrations.length > 0) {
18127
- parts.push(`${ctx.connectedIntegrations.length} integration${ctx.connectedIntegrations.length > 1 ? "s" : ""} (${formatList(ctx.connectedIntegrations, 5)})`);
18128
- }
18129
- if (ctx.skillCount > 0)
18130
- parts.push(`${ctx.skillCount} skill${ctx.skillCount > 1 ? "s" : ""}`);
18131
- if (ctx.mcpServerCount > 0)
18132
- parts.push(`${ctx.mcpServerCount} MCP server${ctx.mcpServerCount > 1 ? "s" : ""}`);
18133
- return parts.length > 0 ? parts.join(", ") : "no resources deployed yet";
18204
+
18205
+ // src/agents/intro-skill.ts
18206
+ function toRunworkInventory(ctx) {
18207
+ const reg = ctx.registries;
18208
+ return {
18209
+ appCount: ctx.appCount,
18210
+ entityNames: reg ? [...new Set(reg.entities.map((e) => e.entityName))] : [],
18211
+ fileStorageCount: reg?.fileStorages.length ?? 0,
18212
+ schedules: {
18213
+ count: reg?.schedules.length ?? 0,
18214
+ names: reg?.schedules.map((s) => s.name).filter(Boolean) ?? []
18215
+ },
18216
+ workflows: {
18217
+ count: reg?.workflows.length ?? 0,
18218
+ names: reg?.workflows.map((w) => w.name).filter(Boolean) ?? []
18219
+ },
18220
+ agents: {
18221
+ count: reg?.agents.length ?? 0,
18222
+ names: reg?.agents.map((a) => a.name).filter(Boolean) ?? []
18223
+ },
18224
+ endpointCount: reg?.endpoints.length ?? 0,
18225
+ componentCount: reg?.components.length ?? 0,
18226
+ integrationIds: ctx.connectedIntegrations,
18227
+ skillCount: ctx.skillCount,
18228
+ mcpServerCount: ctx.mcpServerCount
18229
+ };
18134
18230
  }
18135
18231
  function buildAppSkillDescription(appName, registries) {
18136
18232
  if (!registries)
@@ -18423,39 +18519,17 @@ function generateIntroSkill(ctx) {
18423
18519
  };
18424
18520
  }
18425
18521
  function generateInstructionHint(ctx) {
18426
- const inventory = buildInventoryLine(ctx);
18427
- const integrationToolHint = ctx.connectedIntegrations.length > 0 ? ` Connected integrations are callable via MCP tools (${ctx.connectedIntegrations.map((id) => `\`${id}_api\``).join(", ")}) or CLI (\`runwork integrations call <id> <method> <path>\`).` : "";
18428
- const dashboardUrl = ctx.workspaceSlug ? `https://${ctx.workspaceSlug}.runwork.ai` : "https://runwork.ai";
18429
- const workspaceIdLine = `Workspace ID: \`${ctx.workspaceId}\`${ctx.workspaceSlug ? ` | Dashboard: ${dashboardUrl}` : ""}`;
18522
+ const body = buildRunworkInstructions({
18523
+ workspaceName: ctx.workspaceName,
18524
+ workspaceId: ctx.workspaceId,
18525
+ workspaceSlug: ctx.workspaceSlug,
18526
+ inventory: toRunworkInventory(ctx),
18527
+ persona: ctx.persona,
18528
+ surface: "machine"
18529
+ });
18430
18530
  return [
18431
18531
  "<!-- runwork:start -->",
18432
- "## Runwork",
18433
- "",
18434
- `This machine is connected to the **${ctx.workspaceName}** Runwork workspace -- your team's shared platform for building and running infrastructure: apps, data & file storage, scheduled jobs, workflows, integrations, AI agents, skills, MCP servers, public APIs, and reusable components.`,
18435
- "",
18436
- workspaceIdLine,
18437
- "",
18438
- "**Default to Runwork -- team sync beats local files.** When the user asks for any of the following, use the Runwork tool shown. These operations sync across every teammate's AI agents; local alternatives only work for the current user.",
18439
- "",
18440
- "| User asks for | Use Runwork | Don't |",
18441
- "|---|---|---|",
18442
- "| save / create / share / update a skill | `save_skill` MCP tool | local SKILL.md files, prompt snippets |",
18443
- "| store, persist, or remember structured data | `entity_{Name}` MCP tools | local SQLite, JSON files, in-memory |",
18444
- "| schedule a recurring or cron job | Runwork schedules (`schedule_{name}`, `runwork schedules`) | OS cron, `setInterval`, Celery |",
18445
- "| multi-step process, pipeline, or durable workflow | Runwork workflows (`workflow_{name}`) | ad-hoc scripts, shell pipelines |",
18446
- "| call Slack / HubSpot / Gmail / Google / any third-party API | `{id}_api` MCP tools (e.g. `hubspot_api`) | raw `fetch`, hand-built auth, SDK installs |",
18447
- "| upload, save, or serve a file | Runwork file storage (`list_bucket_files`, `generate_user_presigned_url`) | local filesystem, `fs.writeFile` |",
18448
- "| expose a public API / webhook endpoint | Runwork endpoints (`endpoint_*`) | standalone Express/Flask servers |",
18449
- "| share AI prompts, instructions, or expertise with the team | `save_skill` MCP tool | local prompt files, copy-paste |",
18450
- "| connect an AI tool or MCP server | Runwork MCP servers | manual `settings.json` edits per machine |",
18451
- "| build a new internal tool, team app, or automation | `runwork init` -> `runwork dev` -> `runwork deploy` | one-off scripts, notebooks |",
18452
- "",
18453
- "**Exception -- product development:** Editing your current codebase, running tests, git operations, and building features in the product you're working on are NOT Runwork territory. Runwork is for infrastructure and team tooling, not the product itself.",
18454
- "",
18455
- `**Available now:** ${inventory}`,
18456
- "",
18457
- `Runwork MCP tools are always connected -- use them for data access, integration API calls, skill management, and resource discovery.${integrationToolHint} Use \`runwork\` CLI to create (\`runwork init\`), develop (\`runwork dev\`), and deploy (\`runwork deploy\`) apps. Install CLI: \`curl -fsSL https://runwork.ai/install.sh | sh\`. Web dashboard: ${dashboardUrl}. Invoke the \`runwork\` skill for full capability reference.`,
18458
- ...buildPersonaBlock(ctx.persona),
18532
+ body,
18459
18533
  "<!-- runwork:end -->"
18460
18534
  ].join(`
18461
18535
  `);
@@ -18801,6 +18875,7 @@ function computeSyncPlan(input) {
18801
18875
 
18802
18876
  // src/commands/sync.ts
18803
18877
  init_atomic_json();
18878
+ init_workspace_state();
18804
18879
 
18805
18880
  // src/sync/conflict-ui.ts
18806
18881
  init_prompt();
@@ -19160,9 +19235,31 @@ async function refreshConfiguredAgents(state) {
19160
19235
  state.lastDetectedAt = new Date().toISOString();
19161
19236
  return added;
19162
19237
  }
19238
+ function isNotAMemberError(err) {
19239
+ const message = err instanceof Error ? err.message : String(err);
19240
+ return message.includes("403") && message.includes("not a member of this workspace");
19241
+ }
19242
+ function ensureWorkspacePointer(state, statePath2, credentials) {
19243
+ if (state.workspaceId)
19244
+ return true;
19245
+ if (!credentials.defaultWorkspaceId) {
19246
+ console.error("No workspace selected for this account.");
19247
+ console.error("Run `runwork setup` (or `runwork info`) to choose one.");
19248
+ return false;
19249
+ }
19250
+ state.workspaceId = credentials.defaultWorkspaceId;
19251
+ state.workspaceName = credentials.defaultWorkspaceName || credentials.defaultWorkspaceId;
19252
+ try {
19253
+ writeJsonAtomic(statePath2, state);
19254
+ } catch {}
19255
+ return true;
19256
+ }
19163
19257
  async function syncFromState(state, statePath2, credentials, opts) {
19164
19258
  const client = new ApiClient(credentials);
19165
19259
  setVerbose(!!opts.verbose);
19260
+ if (!ensureWorkspacePointer(state, statePath2, credentials)) {
19261
+ process.exit(1);
19262
+ }
19166
19263
  if (!state.workspaceName || state.workspaceName === state.workspaceId || !state.workspaceSlug) {
19167
19264
  try {
19168
19265
  const workspaces = await client.listWorkspaces();
@@ -19183,14 +19280,28 @@ async function syncFromState(state, statePath2, credentials, opts) {
19183
19280
  }
19184
19281
  }
19185
19282
  console.log(" Fetching workspace data...");
19186
- const [allSkills, mcpServers, externalSkills, registries, connectedIntegrations, resolvedMcpCredentials] = await Promise.all([
19187
- client.listWorkspaceSkills(state.workspaceId, true),
19188
- client.listMcpServers(state.workspaceId),
19189
- client.listExternalSkills(state.workspaceId),
19190
- client.getWorkspaceAll(state.workspaceId).catch(() => null),
19191
- client.listConnectedIntegrations(state.workspaceId).then((list) => list.map((i) => i.canonicalId ?? i.integrationId)).catch(() => []),
19192
- client.resolveMcpCredentials(state.workspaceId).catch(() => ({}))
19193
- ]);
19283
+ let fetched;
19284
+ try {
19285
+ fetched = await Promise.all([
19286
+ client.listWorkspaceSkills(state.workspaceId, true),
19287
+ client.listMcpServers(state.workspaceId),
19288
+ client.listExternalSkills(state.workspaceId),
19289
+ client.getWorkspaceAll(state.workspaceId).catch(() => null),
19290
+ client.listConnectedIntegrations(state.workspaceId).then((list) => list.map((i) => i.canonicalId ?? i.integrationId)).catch(() => []),
19291
+ client.resolveMcpCredentials(state.workspaceId).catch(() => ({}))
19292
+ ]);
19293
+ } catch (err) {
19294
+ if (isNotAMemberError(err)) {
19295
+ forgetWorkspaceSelection();
19296
+ console.error(`
19297
+ This account is not a member of "${state.workspaceName || state.workspaceId}".`);
19298
+ console.error("That workspace belonged to a previous sign in, so it has been forgotten.");
19299
+ console.error("Run `runwork setup` (or `runwork info`) to choose a workspace for this account.");
19300
+ process.exit(1);
19301
+ }
19302
+ throw err;
19303
+ }
19304
+ const [allSkills, mcpServers, externalSkills, registries, connectedIntegrations, resolvedMcpCredentials] = fetched;
19194
19305
  const appCount = allSkills.filter((s) => s.type === "app").length;
19195
19306
  const parts = [];
19196
19307
  if (appCount > 0)
@@ -19730,6 +19841,7 @@ Sync complete.`);
19730
19841
  });
19731
19842
 
19732
19843
  // src/commands/setup.ts
19844
+ init_workspace_state();
19733
19845
  var PERSONA_LABELS = {
19734
19846
  1: "everyday",
19735
19847
  2: "curious",