runwork 0.25.1 → 0.25.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +303 -160
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1020,26 +1020,36 @@ function buildHelperValue(execPath, scriptPath) {
1020
1020
  return `!"${normalised}" git-credential-helper`;
1021
1021
  }
1022
1022
  async function configureGitCredentials(remoteUrl) {
1023
- const origin = new URL(remoteUrl).origin;
1023
+ let origin;
1024
+ try {
1025
+ origin = new URL(remoteUrl).origin;
1026
+ } catch {
1027
+ const message = `"${remoteUrl}" is not a valid URL.`;
1028
+ console.warn(`Note: ${message}`);
1029
+ return { ok: false, reason: "invalid-url", message };
1030
+ }
1024
1031
  const key = `credential.${origin}.helper`;
1025
1032
  const helperValue = buildHelperValue(process.execPath, process.argv[1]);
1026
1033
  try {
1027
1034
  try {
1028
1035
  execFileSync("git", ["config", "--global", "--unset-all", key], { stdio: "pipe" });
1029
- } catch (unsetErr) {
1030
- if (unsetErr?.code === "ENOENT")
1031
- throw unsetErr;
1032
- }
1036
+ } catch {}
1033
1037
  execFileSync("git", ["config", "--global", "--add", key, ""], { stdio: "pipe" });
1034
1038
  execFileSync("git", ["config", "--global", "--add", key, helperValue], { stdio: "pipe" });
1039
+ return { ok: true };
1035
1040
  } catch (err) {
1036
1041
  const code = err?.code;
1037
1042
  if (code === "ENOENT") {
1038
- console.warn("Note: git is not installed. Skipping git credential helper setup.");
1039
- console.warn("Install git before running `runwork init`, `clone`, `dev`, or `deploy`.");
1040
- return;
1043
+ const message2 = "git is not installed. Install git before running `runwork init`, `clone`, `dev`, or `deploy`.";
1044
+ console.warn(`Note: ${message2}`);
1045
+ return { ok: false, reason: "missing", message: message2 };
1041
1046
  }
1042
- throw err;
1047
+ const detail = err instanceof Error ? err.message.split(`
1048
+ `)[0] : String(err);
1049
+ const xcodeHint = process.platform === "darwin" ? " On macOS this usually means the Xcode Command Line Tools are missing; run `xcode-select --install`." : "";
1050
+ const message = `git is installed but could not be run (${detail}).${xcodeHint}`;
1051
+ console.warn(`Note: ${message}`);
1052
+ return { ok: false, reason: "unusable", message };
1043
1053
  }
1044
1054
  }
1045
1055
  function lookupCredentialHelper(origin) {
@@ -1097,13 +1107,13 @@ async function ensureGitCredentialHelper(baseUrl) {
1097
1107
  try {
1098
1108
  origin = new URL(baseUrl).origin;
1099
1109
  } catch {
1100
- return;
1110
+ return { ok: false, reason: "invalid-url", message: `"${baseUrl}" is not a valid URL.` };
1101
1111
  }
1102
1112
  const lookup = lookupCredentialHelper(origin);
1103
1113
  if (lookup.status === "registered" && helperBinaryStatus(lookup.value).ok && lookup.hasReset) {
1104
- return;
1114
+ return { ok: true };
1105
1115
  }
1106
- await configureGitCredentials(baseUrl);
1116
+ return configureGitCredentials(baseUrl);
1107
1117
  }
1108
1118
  async function removeGitCredentials(baseUrl) {
1109
1119
  const origin = new URL(baseUrl).origin;
@@ -7973,7 +7983,7 @@ function createKeyboardListener() {
7973
7983
  }
7974
7984
 
7975
7985
  // src/generated/version.ts
7976
- var VERSION = "0.25.1";
7986
+ var VERSION = "0.25.2";
7977
7987
 
7978
7988
  // src/commands/dev.ts
7979
7989
  var exports_dev = {};
@@ -9105,7 +9115,10 @@ var init_resolve = __esm(() => {
9105
9115
 
9106
9116
  // ../../shared/skill/skill-canonical.ts
9107
9117
  function toSkillSlug(value) {
9108
- return value.trim().replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
9118
+ return transliterateLatin(value.trim()).replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
9119
+ }
9120
+ function transliterateLatin(value) {
9121
+ return value.replace(/[ıßøØłŁđĐæÆœŒþÞðÐ]/g, (ch) => NON_DECOMPOSABLE_LATIN[ch] ?? ch).normalize("NFD").replace(/[\u0300-\u036f]/g, "");
9109
9122
  }
9110
9123
  function isStructuredYamlValue(value) {
9111
9124
  if (value.includes(`
@@ -9150,11 +9163,13 @@ function parseSkillMd(content) {
9150
9163
  const lines = content.split(`
9151
9164
  `);
9152
9165
  if (lines[0]?.trim() !== "---") {
9153
- const rawName = lines[0]?.replace(/^#\s*/, "").trim() || "Untitled Skill";
9166
+ const firstLine = lines[0]?.trim() ?? "";
9167
+ const isHeading = /^#+\s/.test(firstLine);
9168
+ const rawName = firstLine.replace(/^#+\s*/, "").trim() || "Untitled Skill";
9154
9169
  return {
9155
9170
  frontmatter: {
9156
9171
  name: toSkillSlug(rawName) || "untitled-skill",
9157
- description: ""
9172
+ description: isHeading ? rawName : ""
9158
9173
  },
9159
9174
  orderedKeys: [],
9160
9175
  body: content,
@@ -9241,6 +9256,27 @@ function buildSkillMd(parts) {
9241
9256
  return lines.join(`
9242
9257
  `);
9243
9258
  }
9259
+ var NON_DECOMPOSABLE_LATIN;
9260
+ var init_skill_canonical = __esm(() => {
9261
+ NON_DECOMPOSABLE_LATIN = {
9262
+ "ı": "i",
9263
+ "ß": "ss",
9264
+ "ø": "o",
9265
+ "Ø": "O",
9266
+ "ł": "l",
9267
+ "Ł": "L",
9268
+ "đ": "d",
9269
+ "Đ": "D",
9270
+ "æ": "ae",
9271
+ "Æ": "AE",
9272
+ "œ": "oe",
9273
+ "Œ": "OE",
9274
+ "þ": "th",
9275
+ "Þ": "TH",
9276
+ "ð": "d",
9277
+ "Ð": "D"
9278
+ };
9279
+ });
9244
9280
 
9245
9281
  // src/agents/registry-data.ts
9246
9282
  function chatgptConnectorSteps(confirmLead) {
@@ -10879,6 +10915,7 @@ function buildSkillMd2(skill) {
10879
10915
  }
10880
10916
  var RUNWORK_MCP_PREFIX = "Runwork: ", RUNWORK_MCP_PREFIX_LEGACY = "runwork-", RUNWORK_WORKSPACE_MCP_NAME = "Runwork", RUNWORK_PLUGIN_MARKETPLACE = "runwork", toSlug;
10881
10917
  var init_types = __esm(() => {
10918
+ init_skill_canonical();
10882
10919
  toSlug = toSkillSlug;
10883
10920
  });
10884
10921
 
@@ -19825,6 +19862,7 @@ var infoCommand = new Command12("info").description("Show app context, registrie
19825
19862
  init_store();
19826
19863
  init_client();
19827
19864
  init_resolve();
19865
+ init_skill_canonical();
19828
19866
  import { Command as Command13 } from "commander";
19829
19867
  import { readFileSync as readFileSync22, existsSync as existsSync25 } from "fs";
19830
19868
  function truncate(text2, max) {
@@ -19899,7 +19937,7 @@ function buildSkillPushPayload(fileContent, nameArg) {
19899
19937
  const name = toSkillSlug(nameArg || "") || docName;
19900
19938
  if (!name)
19901
19939
  return null;
19902
- const description = parsed.hadFrontmatter ? parsed.frontmatter.description : "";
19940
+ const description = parsed.frontmatter.description;
19903
19941
  const extra = {};
19904
19942
  for (const key of parsed.orderedKeys) {
19905
19943
  if (key === "name" || key === "description")
@@ -22571,8 +22609,8 @@ init_resolve();
22571
22609
  init_prompt();
22572
22610
  await init_detect();
22573
22611
  import { Command as Command27 } from "commander";
22574
- import { join as join48 } from "path";
22575
- import { homedir as homedir27 } from "os";
22612
+ import { join as join49 } from "path";
22613
+ import { homedir as homedir28 } from "os";
22576
22614
 
22577
22615
  // src/commands/sync.ts
22578
22616
  init_store();
@@ -22583,9 +22621,9 @@ await __promiseAll([
22583
22621
  init_codex()
22584
22622
  ]);
22585
22623
  import { Command as Command26 } from "commander";
22586
- import { readFileSync as readFileSync40, existsSync as existsSync51 } from "fs";
22587
- import { join as join47 } from "path";
22588
- import { homedir as homedir26 } from "os";
22624
+ import { readFileSync as readFileSync41, existsSync as existsSync52 } from "fs";
22625
+ import { join as join48 } from "path";
22626
+ import { homedir as homedir27 } from "os";
22589
22627
 
22590
22628
  // src/commands/mcp-entries.ts
22591
22629
  init_types();
@@ -23444,6 +23482,91 @@ function sameStringSet(a, b) {
23444
23482
  return true;
23445
23483
  }
23446
23484
 
23485
+ // src/utils/sync-lock.ts
23486
+ import { existsSync as existsSync51, mkdirSync as mkdirSync28, readFileSync as readFileSync40, unlinkSync as unlinkSync8, writeFileSync as writeFileSync30 } from "fs";
23487
+ import { join as join47 } from "path";
23488
+ import { homedir as homedir26 } from "os";
23489
+ var LOCK_PATH = join47(homedir26(), ".runwork", "sync.lock");
23490
+ var STALE_LOCK_MS = 5 * 60 * 1000;
23491
+ var DEFAULT_WAIT_MS = 30000;
23492
+ var exitHandlerRegistered = false;
23493
+ function ensureExitHandler() {
23494
+ if (exitHandlerRegistered)
23495
+ return;
23496
+ exitHandlerRegistered = true;
23497
+ process.once("exit", releaseSyncLock);
23498
+ }
23499
+ function isProcessAlive(pid) {
23500
+ try {
23501
+ process.kill(pid, 0);
23502
+ return true;
23503
+ } catch (err) {
23504
+ return err?.code === "EPERM";
23505
+ }
23506
+ }
23507
+ function readLock() {
23508
+ try {
23509
+ return JSON.parse(readFileSync40(LOCK_PATH, "utf-8"));
23510
+ } catch {
23511
+ return null;
23512
+ }
23513
+ }
23514
+ function writeLockExclusive() {
23515
+ try {
23516
+ if (!existsSync51(join47(homedir26(), ".runwork"))) {
23517
+ mkdirSync28(join47(homedir26(), ".runwork"), { recursive: true });
23518
+ }
23519
+ writeFileSync30(LOCK_PATH, JSON.stringify({ pid: process.pid, startedAt: Date.now() }), {
23520
+ flag: "wx"
23521
+ });
23522
+ return true;
23523
+ } catch {
23524
+ return false;
23525
+ }
23526
+ }
23527
+ function tryAcquireOnce() {
23528
+ if (writeLockExclusive()) {
23529
+ ensureExitHandler();
23530
+ return true;
23531
+ }
23532
+ const existing = readLock();
23533
+ const stale = !existing || Date.now() - existing.startedAt > STALE_LOCK_MS || !isProcessAlive(existing.pid);
23534
+ if (!stale)
23535
+ return false;
23536
+ try {
23537
+ unlinkSync8(LOCK_PATH);
23538
+ } catch {}
23539
+ if (writeLockExclusive()) {
23540
+ ensureExitHandler();
23541
+ return true;
23542
+ }
23543
+ return false;
23544
+ }
23545
+ function sleep2(ms) {
23546
+ return new Promise((resolve3) => setTimeout(resolve3, ms));
23547
+ }
23548
+ async function acquireSyncLock(waitMs = DEFAULT_WAIT_MS) {
23549
+ const deadline = Date.now() + waitMs;
23550
+ let delay = 250;
23551
+ for (;; ) {
23552
+ if (tryAcquireOnce())
23553
+ return true;
23554
+ const remaining = deadline - Date.now();
23555
+ if (remaining <= 0)
23556
+ return false;
23557
+ await sleep2(Math.min(delay, remaining));
23558
+ delay = Math.min(delay * 2, 5000);
23559
+ }
23560
+ }
23561
+ function releaseSyncLock() {
23562
+ const existing = readLock();
23563
+ if (existing?.pid === process.pid) {
23564
+ try {
23565
+ unlinkSync8(LOCK_PATH);
23566
+ } catch {}
23567
+ }
23568
+ }
23569
+
23447
23570
  // src/commands/sync.ts
23448
23571
  async function printAdoptionHint(credentials, workspaceId) {
23449
23572
  if (!workspaceId)
@@ -23460,10 +23583,10 @@ Tip: ${hint.title}`);
23460
23583
  } catch {}
23461
23584
  }
23462
23585
  function loadSetupState(filePath) {
23463
- if (!existsSync51(filePath))
23586
+ if (!existsSync52(filePath))
23464
23587
  return null;
23465
23588
  try {
23466
- return JSON.parse(readFileSync40(filePath, "utf-8"));
23589
+ return JSON.parse(readFileSync41(filePath, "utf-8"));
23467
23590
  } catch {
23468
23591
  return null;
23469
23592
  }
@@ -23484,15 +23607,15 @@ function readLocalSkills(state) {
23484
23607
  if (!baseDir)
23485
23608
  continue;
23486
23609
  for (const skillName of state.skills) {
23487
- const skillMdPath = join47(baseDir, skillName, "SKILL.md");
23488
- if (existsSync51(skillMdPath)) {
23489
- results.push({ name: skillName, content: readFileSync40(skillMdPath, "utf-8") });
23610
+ const skillMdPath = join48(baseDir, skillName, "SKILL.md");
23611
+ if (existsSync52(skillMdPath)) {
23612
+ results.push({ name: skillName, content: readFileSync41(skillMdPath, "utf-8") });
23490
23613
  continue;
23491
23614
  }
23492
23615
  const filename = skillName.toLowerCase().replace(/[^a-z0-9]+/g, "-");
23493
- const flatPath = join47(baseDir, `${filename}.md`);
23494
- if (existsSync51(flatPath)) {
23495
- results.push({ name: skillName, content: readFileSync40(flatPath, "utf-8") });
23616
+ const flatPath = join48(baseDir, `${filename}.md`);
23617
+ if (existsSync52(flatPath)) {
23618
+ results.push({ name: skillName, content: readFileSync41(flatPath, "utf-8") });
23496
23619
  }
23497
23620
  }
23498
23621
  if (results.length > 0)
@@ -23546,6 +23669,19 @@ function ensureWorkspacePointer(state, statePath2, credentials) {
23546
23669
  return true;
23547
23670
  }
23548
23671
  async function syncFromState(state, statePath2, credentials, opts) {
23672
+ const acquired = await acquireSyncLock();
23673
+ if (!acquired) {
23674
+ console.log(" Another sync appears to be in progress on this machine; proceeding anyway.");
23675
+ await runSyncFromState(state, statePath2, credentials, opts);
23676
+ return;
23677
+ }
23678
+ try {
23679
+ await runSyncFromState(state, statePath2, credentials, opts);
23680
+ } finally {
23681
+ releaseSyncLock();
23682
+ }
23683
+ }
23684
+ async function runSyncFromState(state, statePath2, credentials, opts) {
23549
23685
  const client = new ApiClient(credentials);
23550
23686
  setVerbose(!!opts.verbose);
23551
23687
  if (!ensureWorkspacePointer(state, statePath2, credentials)) {
@@ -23733,9 +23869,9 @@ This account is not a member of "${state.workspaceName || state.workspaceId}".`)
23733
23869
  persona: state.persona
23734
23870
  });
23735
23871
  let projectAppSkillFilter = null;
23736
- if (existsSync51(".runwork.json")) {
23872
+ if (existsSync52(".runwork.json")) {
23737
23873
  try {
23738
- const config = JSON.parse(readFileSync40(".runwork.json", "utf-8"));
23874
+ const config = JSON.parse(readFileSync41(".runwork.json", "utf-8"));
23739
23875
  if (config.appName) {
23740
23876
  projectAppSkillFilter = config.appName.toLowerCase().replace(/[^a-z0-9]+/g, "-");
23741
23877
  }
@@ -23972,7 +24108,7 @@ This account is not a member of "${state.workspaceName || state.workspaceId}".`)
23972
24108
  }
23973
24109
  for (const adapter2 of adapters) {
23974
24110
  if (adapter2 instanceof CodexAdapter) {
23975
- const runworkDir = join47(homedir26(), ".runwork");
24111
+ const runworkDir = join48(homedir27(), ".runwork");
23976
24112
  const result = adapter2.registerDesktopWorkspace(runworkDir, "Runwork");
23977
24113
  if (result === "written") {
23978
24114
  vlog(` [${adapter2.name}] Registered workspace in Codex desktop app`);
@@ -24114,8 +24250,8 @@ var syncCommand = new Command26("sync").description("Sync skills bidirectionally
24114
24250
  verbose: !!opts.verbose,
24115
24251
  redetect: !!opts.redetect
24116
24252
  };
24117
- const projectStatePath = join47(process.cwd(), ".runwork", "setup.json");
24118
- const userStatePath = join47(homedir26(), ".runwork", "setup.json");
24253
+ const projectStatePath = join48(process.cwd(), ".runwork", "setup.json");
24254
+ const userStatePath = join48(homedir27(), ".runwork", "setup.json");
24119
24255
  const projectState = loadSetupState(projectStatePath);
24120
24256
  const userState = loadSetupState(userStatePath);
24121
24257
  if (!projectState && !userState) {
@@ -24184,7 +24320,7 @@ function toSkillFilename(name) {
24184
24320
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
24185
24321
  }
24186
24322
  function loadSetupStateForScope(scope) {
24187
- const path4 = scope === "project" ? join48(process.cwd(), ".runwork", "setup.json") : join48(homedir27(), ".runwork", "setup.json");
24323
+ const path4 = scope === "project" ? join49(process.cwd(), ".runwork", "setup.json") : join49(homedir28(), ".runwork", "setup.json");
24188
24324
  return readJsonOrNull(path4);
24189
24325
  }
24190
24326
  async function parkAndTeardownWorkspace(previous, scopes) {
@@ -24353,8 +24489,8 @@ Re-run without --dry-run to sync workspace data.`);
24353
24489
  }
24354
24490
  persistDefaultWorkspace(workspaceId, workspaceName);
24355
24491
  for (const s of scopes) {
24356
- const dir = s === "project" ? ".runwork" : join48(homedir27(), ".runwork");
24357
- writeJsonAtomic(join48(dir, "setup.json"), state);
24492
+ const dir = s === "project" ? ".runwork" : join49(homedir28(), ".runwork");
24493
+ writeJsonAtomic(join49(dir, "setup.json"), state);
24358
24494
  }
24359
24495
  if (restored)
24360
24496
  clearParkedState(workspaceId);
@@ -24362,7 +24498,7 @@ Re-run without --dry-run to sync workspace data.`);
24362
24498
  Syncing workspace data...
24363
24499
  `);
24364
24500
  for (const s of scopes) {
24365
- const statePath2 = s === "project" ? join48(process.cwd(), ".runwork", "setup.json") : join48(homedir27(), ".runwork", "setup.json");
24501
+ const statePath2 = s === "project" ? join49(process.cwd(), ".runwork", "setup.json") : join49(homedir28(), ".runwork", "setup.json");
24366
24502
  await syncFromState(state, statePath2, credentials, {
24367
24503
  dryRun: false,
24368
24504
  pullOnly: true,
@@ -24382,16 +24518,16 @@ init_client();
24382
24518
  import { Command as Command28 } from "commander";
24383
24519
 
24384
24520
  // src/utils/setup-state.ts
24385
- import { existsSync as existsSync52, readFileSync as readFileSync41 } from "fs";
24386
- import { join as join49 } from "path";
24387
- import { homedir as homedir28 } from "os";
24521
+ import { existsSync as existsSync53, readFileSync as readFileSync42 } from "fs";
24522
+ import { join as join50 } from "path";
24523
+ import { homedir as homedir29 } from "os";
24388
24524
  function loadSetupState2() {
24389
- const projectPath = join49(process.cwd(), ".runwork", "setup.json");
24390
- const userPath = join49(homedir28(), ".runwork", "setup.json");
24525
+ const projectPath = join50(process.cwd(), ".runwork", "setup.json");
24526
+ const userPath = join50(homedir29(), ".runwork", "setup.json");
24391
24527
  for (const p of [projectPath, userPath]) {
24392
- if (existsSync52(p)) {
24528
+ if (existsSync53(p)) {
24393
24529
  try {
24394
- return JSON.parse(readFileSync41(p, "utf-8"));
24530
+ return JSON.parse(readFileSync42(p, "utf-8"));
24395
24531
  } catch {
24396
24532
  continue;
24397
24533
  }
@@ -24450,14 +24586,14 @@ init_client();
24450
24586
  init_types();
24451
24587
  await init_detect();
24452
24588
  import { Command as Command29 } from "commander";
24453
- import { existsSync as existsSync53, readFileSync as readFileSync42 } from "fs";
24454
- import { resolve as resolve3, join as join50 } from "path";
24455
- import { homedir as homedir29 } from "os";
24589
+ import { existsSync as existsSync54, readFileSync as readFileSync43 } from "fs";
24590
+ import { resolve as resolve3, join as join51 } from "path";
24591
+ import { homedir as homedir30 } from "os";
24456
24592
  function loadSetupState3(filePath) {
24457
- if (!existsSync53(filePath))
24593
+ if (!existsSync54(filePath))
24458
24594
  return null;
24459
24595
  try {
24460
- return JSON.parse(readFileSync42(filePath, "utf-8"));
24596
+ return JSON.parse(readFileSync43(filePath, "utf-8"));
24461
24597
  } catch {
24462
24598
  return null;
24463
24599
  }
@@ -24473,8 +24609,8 @@ var buildPluginCommand = new Command29("build-plugin").description("Build an ins
24473
24609
  process.exit(1);
24474
24610
  }
24475
24611
  const credentials = requireAuth();
24476
- const projectStatePath = join50(process.cwd(), ".runwork", "setup.json");
24477
- const userStatePath = join50(homedir29(), ".runwork", "setup.json");
24612
+ const projectStatePath = join51(process.cwd(), ".runwork", "setup.json");
24613
+ const userStatePath = join51(homedir30(), ".runwork", "setup.json");
24478
24614
  const state = loadSetupState3(projectStatePath) ?? loadSetupState3(userStatePath);
24479
24615
  if (!state) {
24480
24616
  console.error("No setup state found. Run `runwork setup` first.");
@@ -24566,21 +24702,21 @@ var buildPluginCommand = new Command29("build-plugin").description("Build an ins
24566
24702
  init_prompt();
24567
24703
  await init_detect();
24568
24704
  import { Command as Command30 } from "commander";
24569
- import { existsSync as existsSync54, readFileSync as readFileSync43, rmSync as rmSync13, unlinkSync as unlinkSync8 } from "fs";
24570
- import { join as join51 } from "path";
24571
- import { homedir as homedir30 } from "os";
24705
+ import { existsSync as existsSync55, readFileSync as readFileSync44, rmSync as rmSync13, unlinkSync as unlinkSync9 } from "fs";
24706
+ import { join as join52 } from "path";
24707
+ import { homedir as homedir31 } from "os";
24572
24708
  function loadSetupState4(filePath) {
24573
- if (!existsSync54(filePath))
24709
+ if (!existsSync55(filePath))
24574
24710
  return null;
24575
24711
  try {
24576
- return JSON.parse(readFileSync43(filePath, "utf-8"));
24712
+ return JSON.parse(readFileSync44(filePath, "utf-8"));
24577
24713
  } catch {
24578
24714
  return null;
24579
24715
  }
24580
24716
  }
24581
24717
  var uninstallCommand = new Command30("uninstall").description("Remove all Runwork configuration from local agents (MCP servers, skills, instructions)").option("-y, --yes", "Skip confirmation prompt").option("--keep-auth", "Keep authentication credentials (only remove agent configs)").action(async (opts) => {
24582
- const projectStatePath = join51(process.cwd(), ".runwork", "setup.json");
24583
- const userStatePath = join51(homedir30(), ".runwork", "setup.json");
24718
+ const projectStatePath = join52(process.cwd(), ".runwork", "setup.json");
24719
+ const userStatePath = join52(homedir31(), ".runwork", "setup.json");
24584
24720
  const projectState = loadSetupState4(projectStatePath);
24585
24721
  const userState = loadSetupState4(userStatePath);
24586
24722
  if (!projectState && !userState) {
@@ -24660,19 +24796,19 @@ This will remove all Runwork configuration from your local agents:
24660
24796
  }
24661
24797
  }
24662
24798
  }
24663
- const stateDir = label === "project" ? join51(process.cwd(), ".runwork") : join51(homedir30(), ".runwork");
24799
+ const stateDir = label === "project" ? join52(process.cwd(), ".runwork") : join52(homedir31(), ".runwork");
24664
24800
  if (opts.keepAuth && label === "user") {
24665
- const setupFile = join51(stateDir, "setup.json");
24666
- if (existsSync54(setupFile)) {
24801
+ const setupFile = join52(stateDir, "setup.json");
24802
+ if (existsSync55(setupFile)) {
24667
24803
  try {
24668
- unlinkSync8(setupFile);
24804
+ unlinkSync9(setupFile);
24669
24805
  console.log(` Removed ${setupFile} (kept credentials)`);
24670
24806
  } catch (err) {
24671
24807
  console.warn(` Failed to remove ${setupFile}: ${err instanceof Error ? err.message : err}`);
24672
24808
  errors++;
24673
24809
  }
24674
24810
  }
24675
- } else if (existsSync54(stateDir)) {
24811
+ } else if (existsSync55(stateDir)) {
24676
24812
  try {
24677
24813
  rmSync13(stateDir, { recursive: true, force: true });
24678
24814
  console.log(` Removed ${stateDir}`);
@@ -24806,7 +24942,7 @@ var membersCommand = new Command32("members").description("List workspace member
24806
24942
  init_store();
24807
24943
  init_client();
24808
24944
  import { Command as Command33 } from "commander";
24809
- import { readFileSync as readFileSync44 } from "fs";
24945
+ import { readFileSync as readFileSync45 } from "fs";
24810
24946
  function normalizeApiPath(rawPath, baseUrl) {
24811
24947
  if (/^https?:\/\//i.test(rawPath)) {
24812
24948
  const target = new URL(rawPath);
@@ -24839,7 +24975,7 @@ to be read or pasted manually. Prefer a dedicated command when one exists
24839
24975
  let curlStr = opts.curl;
24840
24976
  if (opts.curlFile) {
24841
24977
  try {
24842
- curlStr = readFileSync44(opts.curlFile, "utf-8");
24978
+ curlStr = readFileSync45(opts.curlFile, "utf-8");
24843
24979
  } catch (err) {
24844
24980
  console.error(`Could not read --curl-file: ${err instanceof Error ? err.message : err}`);
24845
24981
  process.exit(1);
@@ -24859,7 +24995,7 @@ to be read or pasted manually. Prefer a dedicated command when one exists
24859
24995
  let raw = opts.body;
24860
24996
  if (raw.startsWith("@")) {
24861
24997
  try {
24862
- raw = readFileSync44(raw.slice(1), "utf-8");
24998
+ raw = readFileSync45(raw.slice(1), "utf-8");
24863
24999
  } catch (err) {
24864
25000
  console.error(`Could not read body file: ${err instanceof Error ? err.message : err}`);
24865
25001
  process.exit(1);
@@ -24912,9 +25048,9 @@ init_preflight();
24912
25048
  init_credentials();
24913
25049
  await init_detect();
24914
25050
  import { parse as parse2 } from "smol-toml";
24915
- import { existsSync as existsSync55, readFileSync as readFileSync45 } from "fs";
24916
- import { join as join52, sep as sep4 } from "path";
24917
- import { homedir as homedir31, platform as osPlatform2, arch as osArch } from "os";
25051
+ import { existsSync as existsSync56, readFileSync as readFileSync46 } from "fs";
25052
+ import { join as join53, sep as sep4 } from "path";
25053
+ import { homedir as homedir32, platform as osPlatform2, arch as osArch } from "os";
24918
25054
  var BASE_URL2 = process.env.RUNWORK_DOWNLOAD_BASE_URL || "https://runwork.ai";
24919
25055
  var LATEST_JSON_URL2 = `${BASE_URL2}/cli/latest.json`;
24920
25056
  function detectPlatform() {
@@ -24942,10 +25078,10 @@ function buildContext() {
24942
25078
  const credentials = getCredentials();
24943
25079
  const client = credentials ? new ApiClient(credentials) : null;
24944
25080
  let config = null;
24945
- const configPath = join52(process.cwd(), ".runwork.json");
24946
- if (existsSync55(configPath)) {
25081
+ const configPath = join53(process.cwd(), ".runwork.json");
25082
+ if (existsSync56(configPath)) {
24947
25083
  try {
24948
- config = JSON.parse(readFileSync45(configPath, "utf-8"));
25084
+ config = JSON.parse(readFileSync46(configPath, "utf-8"));
24949
25085
  } catch {}
24950
25086
  }
24951
25087
  return { credentials, client, config, cwd: process.cwd() };
@@ -25046,9 +25182,9 @@ async function checkCliArtifactReachable() {
25046
25182
  }
25047
25183
  async function checkCliInstallLocation() {
25048
25184
  const isWindows2 = osPlatform2() === "win32";
25049
- const home = homedir31();
25050
- const canonicalDir = join52(home, ".runwork", "bin");
25051
- const canonicalBinary = isWindows2 ? join52(canonicalDir, "runwork.exe") : join52(canonicalDir, "runwork");
25185
+ const home = homedir32();
25186
+ const canonicalDir = join53(home, ".runwork", "bin");
25187
+ const canonicalBinary = isWindows2 ? join53(canonicalDir, "runwork.exe") : join53(canonicalDir, "runwork");
25052
25188
  const candidates = [process.execPath, process.argv[1] || ""].filter(Boolean);
25053
25189
  const runsFromCanonical = candidates.some((p) => normalizePath(p) === normalizePath(canonicalBinary));
25054
25190
  if (runsFromCanonical) {
@@ -25058,7 +25194,7 @@ async function checkCliInstallLocation() {
25058
25194
  message: `canonical (${canonicalBinary})`
25059
25195
  };
25060
25196
  }
25061
- if (existsSync55(canonicalBinary)) {
25197
+ if (existsSync56(canonicalBinary)) {
25062
25198
  return {
25063
25199
  name: "cli-install-location",
25064
25200
  status: "warn",
@@ -25180,8 +25316,8 @@ async function checkGitCredentialHelper(ctx) {
25180
25316
  };
25181
25317
  }
25182
25318
  async function checkProjectConfig(ctx) {
25183
- const configPath = join52(ctx.cwd, ".runwork.json");
25184
- if (!existsSync55(configPath)) {
25319
+ const configPath = join53(ctx.cwd, ".runwork.json");
25320
+ if (!existsSync56(configPath)) {
25185
25321
  if (!ctx.credentials) {
25186
25322
  return { name: "project-config", status: "skip", message: "no project (not logged in)" };
25187
25323
  }
@@ -25243,7 +25379,7 @@ async function checkGitRemote(ctx) {
25243
25379
  if (!ctx.config) {
25244
25380
  return { name: "git-remote", status: "skip", message: "skipped (no project)" };
25245
25381
  }
25246
- if (!existsSync55(join52(ctx.cwd, ".git"))) {
25382
+ if (!existsSync56(join53(ctx.cwd, ".git"))) {
25247
25383
  return {
25248
25384
  name: "git-remote",
25249
25385
  status: "fail",
@@ -25297,12 +25433,12 @@ async function checkDeployFreshness(ctx) {
25297
25433
  return { name: "deploy-freshness", status: "skip", message: "local HEAD unknown" };
25298
25434
  }
25299
25435
  function loadSetupState5() {
25300
- const projectPath = join52(process.cwd(), ".runwork", "setup.json");
25301
- const userPath = join52(homedir31(), ".runwork", "setup.json");
25436
+ const projectPath = join53(process.cwd(), ".runwork", "setup.json");
25437
+ const userPath = join53(homedir32(), ".runwork", "setup.json");
25302
25438
  for (const p of [projectPath, userPath]) {
25303
- if (existsSync55(p)) {
25439
+ if (existsSync56(p)) {
25304
25440
  try {
25305
- return JSON.parse(readFileSync45(p, "utf-8"));
25441
+ return JSON.parse(readFileSync46(p, "utf-8"));
25306
25442
  } catch {
25307
25443
  continue;
25308
25444
  }
@@ -25317,13 +25453,13 @@ async function checkCodexNetwork() {
25317
25453
  if (!state || !state.configuredAgents.includes("codex")) {
25318
25454
  return { name, status: "skip", message: "Codex not configured for Runwork" };
25319
25455
  }
25320
- const configPath = join52(homedir31(), ".codex", "config.toml");
25321
- if (!existsSync55(configPath)) {
25456
+ const configPath = join53(homedir32(), ".codex", "config.toml");
25457
+ if (!existsSync56(configPath)) {
25322
25458
  return { name, status: "skip", message: "no Codex config found" };
25323
25459
  }
25324
25460
  let parsed;
25325
25461
  try {
25326
- parsed = parse2(readFileSync45(configPath, "utf-8"));
25462
+ parsed = parse2(readFileSync46(configPath, "utf-8"));
25327
25463
  } catch {
25328
25464
  return { name, status: "warn", message: "could not parse ~/.codex/config.toml" };
25329
25465
  }
@@ -25376,19 +25512,19 @@ async function checkCodexDesktopProject() {
25376
25512
  if (!usesCodex) {
25377
25513
  return { name, status: "skip", message: "Codex not configured for Runwork" };
25378
25514
  }
25379
- const statePath2 = join52(homedir31(), ".codex", ".codex-global-state.json");
25380
- if (!existsSync55(statePath2)) {
25515
+ const statePath2 = join53(homedir32(), ".codex", ".codex-global-state.json");
25516
+ if (!existsSync56(statePath2)) {
25381
25517
  return { name, status: "skip", message: "Codex desktop app not detected" };
25382
25518
  }
25383
25519
  let savedRoots = [];
25384
25520
  try {
25385
- const parsed = JSON.parse(readFileSync45(statePath2, "utf-8"));
25521
+ const parsed = JSON.parse(readFileSync46(statePath2, "utf-8"));
25386
25522
  const roots = parsed["electron-saved-workspace-roots"];
25387
25523
  savedRoots = Array.isArray(roots) ? roots.filter((r) => typeof r === "string") : [];
25388
25524
  } catch {
25389
25525
  return { name, status: "warn", message: "could not read Codex desktop state" };
25390
25526
  }
25391
- const runworkDir = join52(homedir31(), ".runwork");
25527
+ const runworkDir = join53(homedir32(), ".runwork");
25392
25528
  if (savedRoots.includes(runworkDir)) {
25393
25529
  return { name, status: "pass", message: "Runwork project added to Codex desktop sidebar" };
25394
25530
  }
@@ -25441,9 +25577,9 @@ async function checkAgentSetup() {
25441
25577
  if (!adapter2 || !adapter2.supportsMcpScope("user"))
25442
25578
  continue;
25443
25579
  const mcpConfigPath = getMcpConfigPath2(slug, "user");
25444
- if (mcpConfigPath && existsSync55(mcpConfigPath)) {
25580
+ if (mcpConfigPath && existsSync56(mcpConfigPath)) {
25445
25581
  try {
25446
- const content = readFileSync45(mcpConfigPath, "utf-8");
25582
+ const content = readFileSync46(mcpConfigPath, "utf-8");
25447
25583
  const missingMcp = state.mcpServers.filter((name) => !content.includes(name));
25448
25584
  if (missingMcp.length > 0) {
25449
25585
  details.push(`${missingMcp.length} MCP server(s) missing from ${slug} config`);
@@ -25465,15 +25601,22 @@ async function checkAgentSetup() {
25465
25601
  const skillsDir = getSkillsDir(slug, "user");
25466
25602
  if (!skillsDir)
25467
25603
  continue;
25604
+ const adapter2 = getAdapterBySlug(slug);
25605
+ const mcpCoversAppSkills = !!adapter2?.mcpProvidesSkills && state.mcpServers.length > 0;
25606
+ const isCoveredByMcp = (name) => mcpCoversAppSkills && state.skillHashes?.[name]?.source === "app";
25468
25607
  const missingSkills = state.skills.filter((name) => {
25469
- const skillPath = join52(skillsDir, name, "SKILL.md");
25470
- return !existsSync55(skillPath);
25608
+ if (isCoveredByMcp(name))
25609
+ return false;
25610
+ const skillPath = join53(skillsDir, name, "SKILL.md");
25611
+ return !existsSync56(skillPath);
25471
25612
  });
25472
25613
  if (missingSkills.length > 0) {
25473
25614
  details.push(`${missingSkills.length} skill(s) missing from ${slug}`);
25474
25615
  upgrade("warn");
25475
25616
  } else if (state.skills.length > 0) {
25476
- details.push(`${state.skills.length} skill(s) installed`);
25617
+ const mcpCoveredCount = state.skills.filter(isCoveredByMcp).length;
25618
+ const onDiskCount = state.skills.length - mcpCoveredCount;
25619
+ details.push(mcpCoveredCount > 0 ? `${state.skills.length} skill(s) installed (${onDiskCount} on disk, ${mcpCoveredCount} via MCP)` : `${state.skills.length} skill(s) installed`);
25477
25620
  }
25478
25621
  skillsChecked = true;
25479
25622
  break;
@@ -25492,28 +25635,28 @@ async function checkAgentSetup() {
25492
25635
  };
25493
25636
  }
25494
25637
  function getMcpConfigPath2(slug, scope) {
25495
- const home = homedir31();
25638
+ const home = homedir32();
25496
25639
  switch (slug) {
25497
25640
  case "claude-code":
25498
- return scope === "project" ? join52(process.cwd(), ".mcp.json") : join52(home, ".claude", "settings.json");
25641
+ return scope === "project" ? join53(process.cwd(), ".mcp.json") : join53(home, ".claude", "settings.json");
25499
25642
  case "cursor":
25500
- return scope === "project" ? join52(process.cwd(), ".cursor", "mcp.json") : join52(home, ".cursor", "mcp.json");
25643
+ return scope === "project" ? join53(process.cwd(), ".cursor", "mcp.json") : join53(home, ".cursor", "mcp.json");
25501
25644
  case "windsurf":
25502
- return scope === "project" ? join52(process.cwd(), ".windsurf", "mcp.json") : join52(home, ".windsurf", "mcp.json");
25645
+ return scope === "project" ? join53(process.cwd(), ".windsurf", "mcp.json") : join53(home, ".windsurf", "mcp.json");
25503
25646
  case "codex":
25504
25647
  case "codex-app":
25505
- return scope === "user" ? join52(home, ".codex", "config.toml") : null;
25648
+ return scope === "user" ? join53(home, ".codex", "config.toml") : null;
25506
25649
  case "gemini":
25507
- return scope === "user" ? join52(home, ".gemini", "settings.json") : null;
25650
+ return scope === "user" ? join53(home, ".gemini", "settings.json") : null;
25508
25651
  default:
25509
25652
  return null;
25510
25653
  }
25511
25654
  }
25512
25655
  async function checkWorkspacePointers() {
25513
- const userStatePath = join52(homedir31(), ".runwork", "setup.json");
25514
- const state = existsSync55(userStatePath) ? (() => {
25656
+ const userStatePath = join53(homedir32(), ".runwork", "setup.json");
25657
+ const state = existsSync56(userStatePath) ? (() => {
25515
25658
  try {
25516
- return JSON.parse(readFileSync45(userStatePath, "utf-8"));
25659
+ return JSON.parse(readFileSync46(userStatePath, "utf-8"));
25517
25660
  } catch {
25518
25661
  return null;
25519
25662
  }
@@ -25543,15 +25686,15 @@ async function checkWorkspacePointers() {
25543
25686
  };
25544
25687
  }
25545
25688
  function getSkillsDir(slug, scope) {
25546
- const home = homedir31();
25689
+ const home = homedir32();
25547
25690
  switch (slug) {
25548
25691
  case "claude-code":
25549
- return scope === "project" ? join52(process.cwd(), ".claude", "skills") : join52(home, ".claude", "skills");
25692
+ return scope === "project" ? join53(process.cwd(), ".claude", "skills") : join53(home, ".claude", "skills");
25550
25693
  case "codex":
25551
25694
  case "codex-app":
25552
- return scope === "project" ? join52(process.cwd(), ".agents", "skills") : join52(home, ".agents", "skills");
25695
+ return scope === "project" ? join53(process.cwd(), ".agents", "skills") : join53(home, ".agents", "skills");
25553
25696
  case "gemini":
25554
- return scope === "project" ? join52(process.cwd(), ".gemini", "skills") : join52(home, ".gemini", "skills");
25697
+ return scope === "project" ? join53(process.cwd(), ".gemini", "skills") : join53(home, ".gemini", "skills");
25555
25698
  default:
25556
25699
  return null;
25557
25700
  }
@@ -25604,18 +25747,18 @@ async function runAllChecks(options) {
25604
25747
  // src/health/fix.ts
25605
25748
  init_credentials();
25606
25749
  init_remote();
25607
- import { existsSync as existsSync56 } from "fs";
25608
- import { join as join53 } from "path";
25750
+ import { existsSync as existsSync57 } from "fs";
25751
+ import { join as join54 } from "path";
25609
25752
  async function applyDoctorFixes(ctx, failingNames) {
25610
25753
  const failing = new Set(failingNames);
25611
25754
  const outcomes = [];
25612
25755
  if (failing.has("git-credential-helper")) {
25613
25756
  if (ctx.credentials?.baseUrl) {
25614
- await ensureGitCredentialHelper(ctx.credentials.baseUrl);
25757
+ const result = await ensureGitCredentialHelper(ctx.credentials.baseUrl);
25615
25758
  outcomes.push({
25616
25759
  name: "git-credential-helper",
25617
- applied: true,
25618
- message: "registered the runwork git credential helper"
25760
+ applied: result.ok,
25761
+ message: result.ok ? "registered the runwork git credential helper" : result.message
25619
25762
  });
25620
25763
  } else {
25621
25764
  outcomes.push({
@@ -25632,7 +25775,7 @@ async function applyDoctorFixes(ctx, failingNames) {
25632
25775
  applied: false,
25633
25776
  message: "no project config -- run inside an app directory"
25634
25777
  });
25635
- } else if (!existsSync56(join53(ctx.cwd, ".git"))) {
25778
+ } else if (!existsSync57(join54(ctx.cwd, ".git"))) {
25636
25779
  outcomes.push({
25637
25780
  name: "git-remote",
25638
25781
  applied: false,
@@ -25651,10 +25794,10 @@ async function applyDoctorFixes(ctx, failingNames) {
25651
25794
  }
25652
25795
 
25653
25796
  // src/agents/runtime-detection.ts
25654
- import { existsSync as existsSync57, readFileSync as readFileSync46, statSync as statSync10, readdirSync as readdirSync16 } from "fs";
25655
- import { homedir as homedir32 } from "os";
25656
- import { join as join54 } from "path";
25657
- var RUNWORK_SESSIONS_DIR = join54(homedir32(), ".runwork", "sessions");
25797
+ import { existsSync as existsSync58, readFileSync as readFileSync47, statSync as statSync10, readdirSync as readdirSync16 } from "fs";
25798
+ import { homedir as homedir33 } from "os";
25799
+ import { join as join55 } from "path";
25800
+ var RUNWORK_SESSIONS_DIR = join55(homedir33(), ".runwork", "sessions");
25658
25801
  function detectCurrentAgent() {
25659
25802
  const claudeCodeSessionId = process.env.CLAUDE_CODE_SESSION_ID;
25660
25803
  if (claudeCodeSessionId) {
@@ -25717,11 +25860,11 @@ function detectCurrentAgent() {
25717
25860
  return null;
25718
25861
  }
25719
25862
  function readHookSessionInfo(sessionId) {
25720
- const path4 = join54(RUNWORK_SESSIONS_DIR, `${sessionId}.json`);
25721
- if (!existsSync57(path4))
25863
+ const path4 = join55(RUNWORK_SESSIONS_DIR, `${sessionId}.json`);
25864
+ if (!existsSync58(path4))
25722
25865
  return null;
25723
25866
  try {
25724
- const raw = readFileSync46(path4, "utf8");
25867
+ const raw = readFileSync47(path4, "utf8");
25725
25868
  const parsed = JSON.parse(raw);
25726
25869
  return parsed;
25727
25870
  } catch {
@@ -25729,8 +25872,8 @@ function readHookSessionInfo(sessionId) {
25729
25872
  }
25730
25873
  }
25731
25874
  function findClaudeCodeSessionFile(sessionId) {
25732
- const root = join54(homedir32(), ".claude", "projects");
25733
- if (!existsSync57(root))
25875
+ const root = join55(homedir33(), ".claude", "projects");
25876
+ if (!existsSync58(root))
25734
25877
  return null;
25735
25878
  let projectDirs;
25736
25879
  try {
@@ -25739,15 +25882,15 @@ function findClaudeCodeSessionFile(sessionId) {
25739
25882
  return null;
25740
25883
  }
25741
25884
  for (const dir of projectDirs) {
25742
- const candidate = join54(root, dir, `${sessionId}.jsonl`);
25743
- if (existsSync57(candidate))
25885
+ const candidate = join55(root, dir, `${sessionId}.jsonl`);
25886
+ if (existsSync58(candidate))
25744
25887
  return candidate;
25745
25888
  }
25746
25889
  return null;
25747
25890
  }
25748
25891
  function findCodexRolloutFile(threadId) {
25749
- const root = join54(homedir32(), ".codex", "sessions");
25750
- if (!existsSync57(root))
25892
+ const root = join55(homedir33(), ".codex", "sessions");
25893
+ if (!existsSync58(root))
25751
25894
  return null;
25752
25895
  const stack = [root];
25753
25896
  while (stack.length > 0) {
@@ -25759,7 +25902,7 @@ function findCodexRolloutFile(threadId) {
25759
25902
  continue;
25760
25903
  }
25761
25904
  for (const entry of entries) {
25762
- const full = join54(dir, entry);
25905
+ const full = join55(dir, entry);
25763
25906
  let s;
25764
25907
  try {
25765
25908
  s = statSync10(full);
@@ -25776,8 +25919,8 @@ function findCodexRolloutFile(threadId) {
25776
25919
  return null;
25777
25920
  }
25778
25921
  function findNewestClaudeCodeSession() {
25779
- const root = join54(homedir32(), ".claude", "projects");
25780
- if (!existsSync57(root))
25922
+ const root = join55(homedir33(), ".claude", "projects");
25923
+ if (!existsSync58(root))
25781
25924
  return null;
25782
25925
  let projectDirs;
25783
25926
  try {
@@ -25787,7 +25930,7 @@ function findNewestClaudeCodeSession() {
25787
25930
  }
25788
25931
  let best = null;
25789
25932
  for (const dir of projectDirs) {
25790
- const projectPath = join54(root, dir);
25933
+ const projectPath = join55(root, dir);
25791
25934
  let files;
25792
25935
  try {
25793
25936
  files = readdirSync16(projectPath);
@@ -25797,7 +25940,7 @@ function findNewestClaudeCodeSession() {
25797
25940
  for (const file of files) {
25798
25941
  if (!file.endsWith(".jsonl"))
25799
25942
  continue;
25800
- const full = join54(projectPath, file);
25943
+ const full = join55(projectPath, file);
25801
25944
  try {
25802
25945
  const s = statSync10(full);
25803
25946
  if (!best || s.mtimeMs > best.mtime) {
@@ -25815,8 +25958,8 @@ function findNewestClaudeCodeSession() {
25815
25958
  return best ? { sessionId: best.sessionId, path: best.path } : null;
25816
25959
  }
25817
25960
  function findNewestCodexRollout() {
25818
- const root = join54(homedir32(), ".codex", "sessions");
25819
- if (!existsSync57(root))
25961
+ const root = join55(homedir33(), ".codex", "sessions");
25962
+ if (!existsSync58(root))
25820
25963
  return null;
25821
25964
  const stack = [root];
25822
25965
  let best = null;
@@ -25829,7 +25972,7 @@ function findNewestCodexRollout() {
25829
25972
  continue;
25830
25973
  }
25831
25974
  for (const entry of entries) {
25832
- const full = join54(dir, entry);
25975
+ const full = join55(dir, entry);
25833
25976
  let s;
25834
25977
  try {
25835
25978
  s = statSync10(full);
@@ -26061,8 +26204,8 @@ init_store();
26061
26204
  init_client();
26062
26205
  init_resolve();
26063
26206
  import { Command as Command35 } from "commander";
26064
- import { readFileSync as readFileSync47, writeFileSync as writeFileSync31, existsSync as existsSync58, mkdtempSync as mkdtempSync4 } from "fs";
26065
- import { join as join55 } from "path";
26207
+ import { readFileSync as readFileSync48, writeFileSync as writeFileSync32, existsSync as existsSync59, mkdtempSync as mkdtempSync4 } from "fs";
26208
+ import { join as join56 } from "path";
26066
26209
  import { tmpdir as tmpdir4 } from "os";
26067
26210
  import { createHash as createHash6 } from "crypto";
26068
26211
 
@@ -26184,14 +26327,14 @@ function resolveLocalSessionShare(opts, conversation) {
26184
26327
  process.exit(1);
26185
26328
  }
26186
26329
  const title = opts.title ?? conversation.title ?? conversation.project;
26187
- const markdown = renderTranscriptMarkdown(readFileSync47(conversation.transcriptPath, "utf8"), family, title);
26330
+ const markdown = renderTranscriptMarkdown(readFileSync48(conversation.transcriptPath, "utf8"), family, title);
26188
26331
  if (!markdown) {
26189
26332
  console.error("Error: this conversation has no shareable content.");
26190
26333
  process.exit(1);
26191
26334
  }
26192
- const tempDir = mkdtempSync4(join55(tmpdir4(), "runwork-share-"));
26193
- const transcriptFile = join55(tempDir, "transcript.md");
26194
- writeFileSync31(transcriptFile, markdown);
26335
+ const tempDir = mkdtempSync4(join56(tmpdir4(), "runwork-share-"));
26336
+ const transcriptFile = join56(tempDir, "transcript.md");
26337
+ writeFileSync32(transcriptFile, markdown);
26195
26338
  opts.transcriptFile = transcriptFile;
26196
26339
  opts.nativeFile = opts.nativeFile ?? conversation.transcriptPath;
26197
26340
  opts.sourceAgent = opts.sourceAgent ?? conversation.agentSlug;
@@ -26228,7 +26371,7 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
26228
26371
  console.error("Error: --transcript-file is required. Pass the path to the LLM-emitted markdown transcript.");
26229
26372
  process.exit(1);
26230
26373
  }
26231
- if (!existsSync58(opts.transcriptFile)) {
26374
+ if (!existsSync59(opts.transcriptFile)) {
26232
26375
  console.error(`Error: transcript file does not exist: ${opts.transcriptFile}`);
26233
26376
  process.exit(1);
26234
26377
  }
@@ -26249,7 +26392,7 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
26249
26392
  const credentials = requireAuth();
26250
26393
  const client = new ApiClient(credentials);
26251
26394
  const { workspaceId } = await resolveWorkspace2(client, { workspace: opts.workspace });
26252
- const transcriptContent = readFileSync47(opts.transcriptFile, "utf8");
26395
+ const transcriptContent = readFileSync48(opts.transcriptFile, "utf8");
26253
26396
  const bundles = [
26254
26397
  {
26255
26398
  format: "transcript",
@@ -26262,19 +26405,19 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
26262
26405
  const sourceAgent = opts.sourceAgent ?? detected?.slug ?? "generic";
26263
26406
  let nativeFilePath = null;
26264
26407
  if (opts.nativeFile) {
26265
- if (!existsSync58(opts.nativeFile)) {
26408
+ if (!existsSync59(opts.nativeFile)) {
26266
26409
  console.error(`Error: --native-file path does not exist: ${opts.nativeFile}`);
26267
26410
  process.exit(1);
26268
26411
  }
26269
26412
  nativeFilePath = opts.nativeFile;
26270
- } else if (detected?.sessionFilePath && existsSync58(detected.sessionFilePath)) {
26413
+ } else if (detected?.sessionFilePath && existsSync59(detected.sessionFilePath)) {
26271
26414
  nativeFilePath = detected.sessionFilePath;
26272
26415
  }
26273
26416
  if (nativeFilePath) {
26274
26417
  const nativeFormat = nativeBundleFormatForAgent(sourceAgent);
26275
26418
  if (nativeFormat) {
26276
26419
  try {
26277
- const content = readFileSync47(nativeFilePath, "utf8");
26420
+ const content = readFileSync48(nativeFilePath, "utf8");
26278
26421
  bundles.push({
26279
26422
  format: nativeFormat,
26280
26423
  content,
@@ -26290,7 +26433,7 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
26290
26433
  let metadata = {};
26291
26434
  if (opts.metadataFile) {
26292
26435
  try {
26293
- metadata = JSON.parse(readFileSync47(opts.metadataFile, "utf8"));
26436
+ metadata = JSON.parse(readFileSync48(opts.metadataFile, "utf8"));
26294
26437
  } catch (err) {
26295
26438
  console.error(`Error: --metadata-file is not valid JSON: ${err instanceof Error ? err.message : err}`);
26296
26439
  process.exit(1);
@@ -26399,9 +26542,9 @@ init_client();
26399
26542
  init_resolve();
26400
26543
  init_registry_data();
26401
26544
  import { Command as Command38 } from "commander";
26402
- import { writeFileSync as writeFileSync32, mkdirSync as mkdirSync28, realpathSync } from "fs";
26403
- import { homedir as homedir33 } from "os";
26404
- import { join as join56 } from "path";
26545
+ import { writeFileSync as writeFileSync33, mkdirSync as mkdirSync29, realpathSync } from "fs";
26546
+ import { homedir as homedir34 } from "os";
26547
+ import { join as join57 } from "path";
26405
26548
  import { spawn as spawn5 } from "child_process";
26406
26549
  init_registry();
26407
26550
  init_which();
@@ -26440,10 +26583,10 @@ function extractCodexUuid(rolloutContent) {
26440
26583
  }
26441
26584
  function placeClaudeJsonl(uuid, content, recipientCwd) {
26442
26585
  const encoded = encodeClaudeCodeCwd(recipientCwd);
26443
- const projectDir = join56(homedir33(), ".claude", "projects", encoded);
26444
- mkdirSync28(projectDir, { recursive: true });
26445
- const placedAt = join56(projectDir, `${uuid}.jsonl`);
26446
- writeFileSync32(placedAt, content);
26586
+ const projectDir = join57(homedir34(), ".claude", "projects", encoded);
26587
+ mkdirSync29(projectDir, { recursive: true });
26588
+ const placedAt = join57(projectDir, `${uuid}.jsonl`);
26589
+ writeFileSync33(placedAt, content);
26447
26590
  return { placedAt, runFromCwd: recipientCwd };
26448
26591
  }
26449
26592
  function placeCodexRollout(uuid, content) {
@@ -26451,11 +26594,11 @@ function placeCodexRollout(uuid, content) {
26451
26594
  const yyyy = String(now.getUTCFullYear());
26452
26595
  const mm = String(now.getUTCMonth() + 1).padStart(2, "0");
26453
26596
  const dd = String(now.getUTCDate()).padStart(2, "0");
26454
- const dir = join56(homedir33(), ".codex", "sessions", yyyy, mm, dd);
26455
- mkdirSync28(dir, { recursive: true });
26597
+ const dir = join57(homedir34(), ".codex", "sessions", yyyy, mm, dd);
26598
+ mkdirSync29(dir, { recursive: true });
26456
26599
  const ts = now.toISOString().replace(/\.\d+Z$/, "").replace(/:/g, "-");
26457
- const placedAt = join56(dir, `rollout-${ts}-${uuid}.jsonl`);
26458
- writeFileSync32(placedAt, content);
26600
+ const placedAt = join57(dir, `rollout-${ts}-${uuid}.jsonl`);
26601
+ writeFileSync33(placedAt, content);
26459
26602
  return { placedAt };
26460
26603
  }
26461
26604
  function pickTargetAgent(opts, sourceAgent) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "runwork",
3
- "version": "0.25.1",
3
+ "version": "0.25.2",
4
4
  "description": "CLI for Runwork: develop, preview, and deploy Runwork apps from your local machine.",
5
5
  "license": "UNLICENSED",
6
6
  "author": "Runwork, Inc. <info@runwork.ai> (https://www.runwork.ai)",