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.
- package/dist/index.js +303 -160
- 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
|
-
|
|
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
|
|
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
|
-
|
|
1039
|
-
console.warn(
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
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.
|
|
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
|
|
22575
|
-
import { homedir as
|
|
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
|
|
22587
|
-
import { join as
|
|
22588
|
-
import { homedir as
|
|
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 (!
|
|
23586
|
+
if (!existsSync52(filePath))
|
|
23464
23587
|
return null;
|
|
23465
23588
|
try {
|
|
23466
|
-
return JSON.parse(
|
|
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 =
|
|
23488
|
-
if (
|
|
23489
|
-
results.push({ name: skillName, content:
|
|
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 =
|
|
23494
|
-
if (
|
|
23495
|
-
results.push({ name: skillName, content:
|
|
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 (
|
|
23872
|
+
if (existsSync52(".runwork.json")) {
|
|
23737
23873
|
try {
|
|
23738
|
-
const config = JSON.parse(
|
|
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 =
|
|
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 =
|
|
24118
|
-
const userStatePath =
|
|
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" ?
|
|
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" :
|
|
24357
|
-
writeJsonAtomic(
|
|
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" ?
|
|
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
|
|
24386
|
-
import { join as
|
|
24387
|
-
import { homedir as
|
|
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 =
|
|
24390
|
-
const userPath =
|
|
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 (
|
|
24528
|
+
if (existsSync53(p)) {
|
|
24393
24529
|
try {
|
|
24394
|
-
return JSON.parse(
|
|
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
|
|
24454
|
-
import { resolve as resolve3, join as
|
|
24455
|
-
import { homedir as
|
|
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 (!
|
|
24593
|
+
if (!existsSync54(filePath))
|
|
24458
24594
|
return null;
|
|
24459
24595
|
try {
|
|
24460
|
-
return JSON.parse(
|
|
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 =
|
|
24477
|
-
const userStatePath =
|
|
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
|
|
24570
|
-
import { join as
|
|
24571
|
-
import { homedir as
|
|
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 (!
|
|
24709
|
+
if (!existsSync55(filePath))
|
|
24574
24710
|
return null;
|
|
24575
24711
|
try {
|
|
24576
|
-
return JSON.parse(
|
|
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 =
|
|
24583
|
-
const userStatePath =
|
|
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" ?
|
|
24799
|
+
const stateDir = label === "project" ? join52(process.cwd(), ".runwork") : join52(homedir31(), ".runwork");
|
|
24664
24800
|
if (opts.keepAuth && label === "user") {
|
|
24665
|
-
const setupFile =
|
|
24666
|
-
if (
|
|
24801
|
+
const setupFile = join52(stateDir, "setup.json");
|
|
24802
|
+
if (existsSync55(setupFile)) {
|
|
24667
24803
|
try {
|
|
24668
|
-
|
|
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 (
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
24916
|
-
import { join as
|
|
24917
|
-
import { homedir as
|
|
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 =
|
|
24946
|
-
if (
|
|
25081
|
+
const configPath = join53(process.cwd(), ".runwork.json");
|
|
25082
|
+
if (existsSync56(configPath)) {
|
|
24947
25083
|
try {
|
|
24948
|
-
config = JSON.parse(
|
|
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 =
|
|
25050
|
-
const canonicalDir =
|
|
25051
|
-
const canonicalBinary = isWindows2 ?
|
|
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 (
|
|
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 =
|
|
25184
|
-
if (!
|
|
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 (!
|
|
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 =
|
|
25301
|
-
const userPath =
|
|
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 (
|
|
25439
|
+
if (existsSync56(p)) {
|
|
25304
25440
|
try {
|
|
25305
|
-
return JSON.parse(
|
|
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 =
|
|
25321
|
-
if (!
|
|
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(
|
|
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 =
|
|
25380
|
-
if (!
|
|
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(
|
|
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 =
|
|
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 &&
|
|
25580
|
+
if (mcpConfigPath && existsSync56(mcpConfigPath)) {
|
|
25445
25581
|
try {
|
|
25446
|
-
const content =
|
|
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
|
-
|
|
25470
|
-
|
|
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
|
-
|
|
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 =
|
|
25638
|
+
const home = homedir32();
|
|
25496
25639
|
switch (slug) {
|
|
25497
25640
|
case "claude-code":
|
|
25498
|
-
return scope === "project" ?
|
|
25641
|
+
return scope === "project" ? join53(process.cwd(), ".mcp.json") : join53(home, ".claude", "settings.json");
|
|
25499
25642
|
case "cursor":
|
|
25500
|
-
return scope === "project" ?
|
|
25643
|
+
return scope === "project" ? join53(process.cwd(), ".cursor", "mcp.json") : join53(home, ".cursor", "mcp.json");
|
|
25501
25644
|
case "windsurf":
|
|
25502
|
-
return scope === "project" ?
|
|
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" ?
|
|
25648
|
+
return scope === "user" ? join53(home, ".codex", "config.toml") : null;
|
|
25506
25649
|
case "gemini":
|
|
25507
|
-
return scope === "user" ?
|
|
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 =
|
|
25514
|
-
const state =
|
|
25656
|
+
const userStatePath = join53(homedir32(), ".runwork", "setup.json");
|
|
25657
|
+
const state = existsSync56(userStatePath) ? (() => {
|
|
25515
25658
|
try {
|
|
25516
|
-
return JSON.parse(
|
|
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 =
|
|
25689
|
+
const home = homedir32();
|
|
25547
25690
|
switch (slug) {
|
|
25548
25691
|
case "claude-code":
|
|
25549
|
-
return scope === "project" ?
|
|
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" ?
|
|
25695
|
+
return scope === "project" ? join53(process.cwd(), ".agents", "skills") : join53(home, ".agents", "skills");
|
|
25553
25696
|
case "gemini":
|
|
25554
|
-
return scope === "project" ?
|
|
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
|
|
25608
|
-
import { join as
|
|
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:
|
|
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 (!
|
|
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
|
|
25655
|
-
import { homedir as
|
|
25656
|
-
import { join as
|
|
25657
|
-
var RUNWORK_SESSIONS_DIR =
|
|
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 =
|
|
25721
|
-
if (!
|
|
25863
|
+
const path4 = join55(RUNWORK_SESSIONS_DIR, `${sessionId}.json`);
|
|
25864
|
+
if (!existsSync58(path4))
|
|
25722
25865
|
return null;
|
|
25723
25866
|
try {
|
|
25724
|
-
const raw =
|
|
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 =
|
|
25733
|
-
if (!
|
|
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 =
|
|
25743
|
-
if (
|
|
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 =
|
|
25750
|
-
if (!
|
|
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 =
|
|
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 =
|
|
25780
|
-
if (!
|
|
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 =
|
|
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 =
|
|
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 =
|
|
25819
|
-
if (!
|
|
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 =
|
|
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
|
|
26065
|
-
import { join as
|
|
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(
|
|
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(
|
|
26193
|
-
const transcriptFile =
|
|
26194
|
-
|
|
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 (!
|
|
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 =
|
|
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 (!
|
|
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 &&
|
|
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 =
|
|
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(
|
|
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
|
|
26403
|
-
import { homedir as
|
|
26404
|
-
import { join as
|
|
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 =
|
|
26444
|
-
|
|
26445
|
-
const placedAt =
|
|
26446
|
-
|
|
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 =
|
|
26455
|
-
|
|
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 =
|
|
26458
|
-
|
|
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.
|
|
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)",
|