runwork 0.18.4 → 0.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +473 -126
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -637,6 +637,35 @@ class ApiClient {
|
|
|
637
637
|
const res = await this.request(`/api/workspaces/${workspaceId}/entities/${encodeURIComponent(entityName)}/${encodeURIComponent(recordId)}`);
|
|
638
638
|
return res.data;
|
|
639
639
|
}
|
|
640
|
+
async createAppExport(workspaceId, appId, body) {
|
|
641
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/apps/${appId}/exports`, { method: "POST", body: JSON.stringify(body) });
|
|
642
|
+
return res.data.job;
|
|
643
|
+
}
|
|
644
|
+
async getExportJob(workspaceId, exportId) {
|
|
645
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/exports/${exportId}`);
|
|
646
|
+
return res.data.job;
|
|
647
|
+
}
|
|
648
|
+
async getExportManifest(workspaceId, exportId) {
|
|
649
|
+
const url = `${this.baseUrl}/api/workspaces/${workspaceId}/exports/${exportId}/manifest`;
|
|
650
|
+
const response = await httpFetch(url, {
|
|
651
|
+
headers: this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {}
|
|
652
|
+
});
|
|
653
|
+
if (!response.ok) {
|
|
654
|
+
throw new Error(`Failed to fetch export manifest: ${response.status} ${await response.text()}`);
|
|
655
|
+
}
|
|
656
|
+
return response.json();
|
|
657
|
+
}
|
|
658
|
+
async downloadExportChunk(workspaceId, exportId, file, chunkIndex) {
|
|
659
|
+
const query = `?file=${encodeURIComponent(file)}&fromChunk=${chunkIndex}&maxChunks=1`;
|
|
660
|
+
const url = `${this.baseUrl}/api/workspaces/${workspaceId}/exports/${exportId}/download${query}`;
|
|
661
|
+
const response = await httpFetch(url, {
|
|
662
|
+
headers: this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {}
|
|
663
|
+
});
|
|
664
|
+
if (!response.ok) {
|
|
665
|
+
throw new Error(`Failed to download export chunk ${chunkIndex}: ${response.status}`);
|
|
666
|
+
}
|
|
667
|
+
return response.arrayBuffer();
|
|
668
|
+
}
|
|
640
669
|
async createEntityRecord(workspaceId, entityName, data) {
|
|
641
670
|
const res = await this.request(`/api/workspaces/${workspaceId}/entities/${encodeURIComponent(entityName)}`, { method: "POST", body: JSON.stringify({ data }) });
|
|
642
671
|
return res.data;
|
|
@@ -1058,10 +1087,21 @@ var init_credentials = __esm(() => {
|
|
|
1058
1087
|
});
|
|
1059
1088
|
|
|
1060
1089
|
// src/auth/login-flow.ts
|
|
1061
|
-
|
|
1090
|
+
function decorateLoginUrl(loginUrl, options) {
|
|
1091
|
+
const params = [];
|
|
1092
|
+
if (options?.register)
|
|
1093
|
+
params.push("mode=register");
|
|
1094
|
+
if (options?.provider)
|
|
1095
|
+
params.push(`provider=${encodeURIComponent(options.provider)}`);
|
|
1096
|
+
if (params.length === 0)
|
|
1097
|
+
return loginUrl;
|
|
1098
|
+
return `${loginUrl}${loginUrl.includes("?") ? "&" : "?"}${params.join("&")}`;
|
|
1099
|
+
}
|
|
1100
|
+
async function performLogin(baseUrl, options) {
|
|
1062
1101
|
const url = baseUrl || DEFAULT_BASE_URL2;
|
|
1063
1102
|
const client = new ApiClient({ apiKey: "", email: "", baseUrl: url });
|
|
1064
|
-
const { sessionId, loginUrl } = await client.initiateLogin();
|
|
1103
|
+
const { sessionId, loginUrl: rawLoginUrl } = await client.initiateLogin();
|
|
1104
|
+
const loginUrl = decorateLoginUrl(rawLoginUrl, options);
|
|
1065
1105
|
const open = await import("open");
|
|
1066
1106
|
await open.default(loginUrl);
|
|
1067
1107
|
console.log(`If browser didn't open, visit: ${loginUrl}`);
|
|
@@ -1136,7 +1176,7 @@ function extractBaseUrl(loginUrl) {
|
|
|
1136
1176
|
}
|
|
1137
1177
|
}
|
|
1138
1178
|
async function pollAndSave(client, sessionId, baseUrl) {
|
|
1139
|
-
const maxAttempts =
|
|
1179
|
+
const maxAttempts = 360;
|
|
1140
1180
|
const pollInterval = 5000;
|
|
1141
1181
|
for (let i = 0;i < maxAttempts; i++) {
|
|
1142
1182
|
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
@@ -7583,7 +7623,7 @@ function createKeyboardListener() {
|
|
|
7583
7623
|
}
|
|
7584
7624
|
|
|
7585
7625
|
// src/generated/version.ts
|
|
7586
|
-
var VERSION = "0.
|
|
7626
|
+
var VERSION = "0.19.1";
|
|
7587
7627
|
|
|
7588
7628
|
// src/commands/dev.ts
|
|
7589
7629
|
var exports_dev = {};
|
|
@@ -8574,7 +8614,7 @@ import { Command as Command36 } from "commander";
|
|
|
8574
8614
|
init_login_flow();
|
|
8575
8615
|
init_colors();
|
|
8576
8616
|
import { Command } from "commander";
|
|
8577
|
-
var loginCommand = new Command("login").description("Authenticate with Runwork platform").argument("[url]", "Login URL from a previous --no-open session").option("--base-url <url>", "Platform URL", "https://runwork.ai").option("--no-open", "Print login URL without opening browser (polls for completion)").option("--print-only", "With --no-open: print URL and exit without polling").option("--api-key <key>", "Authenticate directly with an API key (for CI)").action(async (url, options) => {
|
|
8617
|
+
var loginCommand = new Command("login").description("Authenticate with Runwork platform").argument("[url]", "Login URL from a previous --no-open session").option("--base-url <url>", "Platform URL", "https://runwork.ai").option("--no-open", "Print login URL without opening browser (polls for completion)").option("--print-only", "With --no-open: print URL and exit without polling").option("--api-key <key>", "Authenticate directly with an API key (for CI)").option("--register", "Open the browser on the registration form for a new account").option("--provider <provider>", "Start this OAuth provider flow directly (google, github)").action(async (url, options) => {
|
|
8578
8618
|
if (!options)
|
|
8579
8619
|
return;
|
|
8580
8620
|
if (options.apiKey) {
|
|
@@ -8592,7 +8632,7 @@ var loginCommand = new Command("login").description("Authenticate with Runwork p
|
|
|
8592
8632
|
printNextSteps();
|
|
8593
8633
|
return;
|
|
8594
8634
|
}
|
|
8595
|
-
await performLogin(options.baseUrl);
|
|
8635
|
+
await performLogin(options.baseUrl, { register: options.register, provider: options.provider });
|
|
8596
8636
|
printNextSteps();
|
|
8597
8637
|
});
|
|
8598
8638
|
function printNextSteps() {
|
|
@@ -13747,7 +13787,7 @@ var AGENT_REGISTRY = [
|
|
|
13747
13787
|
{ method: "windows-start-app", target: "Claude" }
|
|
13748
13788
|
]
|
|
13749
13789
|
},
|
|
13750
|
-
launch: { app: { macos: "Claude", windows: "Claude" } },
|
|
13790
|
+
launch: { app: { macos: "Claude", windows: "Claude" }, deepLink: "claude://claude.ai/new?q={prompt}" },
|
|
13751
13791
|
logo: "claude",
|
|
13752
13792
|
downloadUrl: "https://claude.ai/download",
|
|
13753
13793
|
skillsPaths: { global: ".claude/skills", project: ".claude/skills" },
|
|
@@ -13888,7 +13928,7 @@ var AGENT_REGISTRY = [
|
|
|
13888
13928
|
{ method: "windows-start-app", target: "ChatGPT Work" }
|
|
13889
13929
|
]
|
|
13890
13930
|
},
|
|
13891
|
-
launch: { app: { macos: "ChatGPT Work", windows: "ChatGPT Work" }, bundleId: { macos: "com.openai.codex" }, appxPackage: "OpenAI.Codex" },
|
|
13931
|
+
launch: { app: { macos: "ChatGPT Work", windows: "ChatGPT Work" }, bundleId: { macos: "com.openai.codex" }, appxPackage: "OpenAI.Codex", deepLink: "codex://new?prompt={prompt}" },
|
|
13892
13932
|
logo: "openai",
|
|
13893
13933
|
downloadUrl: "https://chatgpt.com/download/",
|
|
13894
13934
|
skillsPaths: { global: ".agents/skills", project: ".agents/skills" },
|
|
@@ -15983,6 +16023,7 @@ ${all.length} insight(s) from your recent work:
|
|
|
15983
16023
|
init_store();
|
|
15984
16024
|
init_client();
|
|
15985
16025
|
import { Command as Command15 } from "commander";
|
|
16026
|
+
import * as path3 from "node:path";
|
|
15986
16027
|
init_prompt();
|
|
15987
16028
|
|
|
15988
16029
|
// src/utils/data-input.ts
|
|
@@ -16024,6 +16065,125 @@ function parseJson(content, source) {
|
|
|
16024
16065
|
}
|
|
16025
16066
|
}
|
|
16026
16067
|
|
|
16068
|
+
// src/export/download-job.ts
|
|
16069
|
+
import * as fs6 from "node:fs";
|
|
16070
|
+
import * as path2 from "node:path";
|
|
16071
|
+
|
|
16072
|
+
// src/export/download.ts
|
|
16073
|
+
function planFileResume(localSizeBytes, chunks) {
|
|
16074
|
+
let boundary = 0;
|
|
16075
|
+
let startChunk = 0;
|
|
16076
|
+
for (const chunk of chunks) {
|
|
16077
|
+
if (boundary + chunk.sizeBytes > localSizeBytes)
|
|
16078
|
+
break;
|
|
16079
|
+
boundary += chunk.sizeBytes;
|
|
16080
|
+
startChunk += 1;
|
|
16081
|
+
}
|
|
16082
|
+
return { startChunk, truncateTo: boundary };
|
|
16083
|
+
}
|
|
16084
|
+
async function downloadExportFile(options) {
|
|
16085
|
+
const retries = options.retriesPerChunk ?? 3;
|
|
16086
|
+
const { startChunk, truncateTo } = planFileResume(options.localSizeBytes, options.chunks);
|
|
16087
|
+
if (truncateTo !== options.localSizeBytes) {
|
|
16088
|
+
await options.truncate(truncateTo);
|
|
16089
|
+
}
|
|
16090
|
+
let downloaded = 0;
|
|
16091
|
+
for (let index = startChunk;index < options.chunks.length; index++) {
|
|
16092
|
+
const expected = options.chunks[index].sizeBytes;
|
|
16093
|
+
let lastError;
|
|
16094
|
+
let bytes = null;
|
|
16095
|
+
for (let attempt = 0;attempt < retries; attempt++) {
|
|
16096
|
+
try {
|
|
16097
|
+
const fetched = await options.fetchChunk(index);
|
|
16098
|
+
if (fetched.byteLength !== expected) {
|
|
16099
|
+
throw new Error(`Chunk ${index} size mismatch: expected ${expected} bytes, got ${fetched.byteLength}`);
|
|
16100
|
+
}
|
|
16101
|
+
bytes = fetched;
|
|
16102
|
+
break;
|
|
16103
|
+
} catch (error) {
|
|
16104
|
+
lastError = error;
|
|
16105
|
+
}
|
|
16106
|
+
}
|
|
16107
|
+
if (!bytes) {
|
|
16108
|
+
throw lastError instanceof Error ? lastError : new Error(String(lastError));
|
|
16109
|
+
}
|
|
16110
|
+
await options.append(bytes);
|
|
16111
|
+
downloaded += 1;
|
|
16112
|
+
options.onProgress?.(startChunk + downloaded, options.chunks.length);
|
|
16113
|
+
}
|
|
16114
|
+
return {
|
|
16115
|
+
downloadedChunks: downloaded,
|
|
16116
|
+
skippedChunks: startChunk,
|
|
16117
|
+
totalBytes: options.chunks.reduce((sum, chunk) => sum + chunk.sizeBytes, 0)
|
|
16118
|
+
};
|
|
16119
|
+
}
|
|
16120
|
+
|
|
16121
|
+
// src/export/download-job.ts
|
|
16122
|
+
async function downloadCompletedJob(client, workspaceId, jobId, outputDir, onProgress) {
|
|
16123
|
+
const manifest = await client.getExportManifest(workspaceId, jobId);
|
|
16124
|
+
const written = [];
|
|
16125
|
+
for (const file of manifest.files) {
|
|
16126
|
+
const localPath = path2.join(outputDir, ...file.name.split("/"));
|
|
16127
|
+
fs6.mkdirSync(path2.dirname(localPath), { recursive: true });
|
|
16128
|
+
const localSizeBytes = fs6.existsSync(localPath) ? fs6.statSync(localPath).size : 0;
|
|
16129
|
+
await downloadExportFile({
|
|
16130
|
+
chunks: file.chunks,
|
|
16131
|
+
localSizeBytes,
|
|
16132
|
+
fetchChunk: (chunkIndex) => client.downloadExportChunk(workspaceId, jobId, file.name, chunkIndex),
|
|
16133
|
+
truncate: async (sizeBytes) => {
|
|
16134
|
+
fs6.truncateSync(localPath, sizeBytes);
|
|
16135
|
+
},
|
|
16136
|
+
append: async (bytes) => {
|
|
16137
|
+
fs6.appendFileSync(localPath, Buffer.from(bytes));
|
|
16138
|
+
},
|
|
16139
|
+
onProgress: (done, total) => onProgress?.(file.name, done, total)
|
|
16140
|
+
});
|
|
16141
|
+
written.push(localPath);
|
|
16142
|
+
}
|
|
16143
|
+
fs6.mkdirSync(outputDir, { recursive: true });
|
|
16144
|
+
const manifestPath = path2.join(outputDir, "manifest.json");
|
|
16145
|
+
fs6.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
16146
|
+
written.push(manifestPath);
|
|
16147
|
+
return { outputDir, files: written };
|
|
16148
|
+
}
|
|
16149
|
+
|
|
16150
|
+
// src/export/targets.ts
|
|
16151
|
+
function resolveExportTargets(entities, filter) {
|
|
16152
|
+
let candidates = entities.filter((e) => e.deploymentMode !== "preview");
|
|
16153
|
+
if (filter.entityName) {
|
|
16154
|
+
candidates = candidates.filter((e) => e.entityName === filter.entityName);
|
|
16155
|
+
if (candidates.length === 0) {
|
|
16156
|
+
return { targets: [], error: `Entity "${filter.entityName}" is not registered in this workspace.` };
|
|
16157
|
+
}
|
|
16158
|
+
}
|
|
16159
|
+
if (filter.appId) {
|
|
16160
|
+
candidates = candidates.filter((e) => e.appId === filter.appId);
|
|
16161
|
+
}
|
|
16162
|
+
const byApp = new Map;
|
|
16163
|
+
for (const entity of candidates) {
|
|
16164
|
+
byApp.set(entity.appId, { appId: entity.appId, appName: entity.appName });
|
|
16165
|
+
}
|
|
16166
|
+
const targets = Array.from(byApp.values());
|
|
16167
|
+
if (filter.entityName && !filter.appId && targets.length > 1) {
|
|
16168
|
+
const names = targets.map((t) => t.appName).join(", ");
|
|
16169
|
+
return {
|
|
16170
|
+
targets: [],
|
|
16171
|
+
error: `Entity "${filter.entityName}" exists in multiple apps (${names}). Pass --app to pick one.`
|
|
16172
|
+
};
|
|
16173
|
+
}
|
|
16174
|
+
if (targets.length === 0) {
|
|
16175
|
+
return { targets: [], error: "No production entities found to export." };
|
|
16176
|
+
}
|
|
16177
|
+
return { targets };
|
|
16178
|
+
}
|
|
16179
|
+
function classifyExportError(message) {
|
|
16180
|
+
return message.includes("not deployed to production") ? "not_deployed" : "error";
|
|
16181
|
+
}
|
|
16182
|
+
function appSlugForPath(appName, appId) {
|
|
16183
|
+
const slug = appName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
16184
|
+
return slug || appId;
|
|
16185
|
+
}
|
|
16186
|
+
|
|
16027
16187
|
// src/commands/entities.ts
|
|
16028
16188
|
var listCommand3 = new Command15("list").description("List entities registered in the workspace").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <id>", "Filter by app name or ID").option("--preview", "Show preview-mode entities only").action(async (opts, command) => {
|
|
16029
16189
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
@@ -16171,7 +16331,194 @@ var deleteCommand = new Command15("delete").description("Delete an entity record
|
|
|
16171
16331
|
process.exit(1);
|
|
16172
16332
|
}
|
|
16173
16333
|
});
|
|
16174
|
-
var
|
|
16334
|
+
var POLL_INTERVAL_MS = 2000;
|
|
16335
|
+
var POLL_TIMEOUT_MS = 60 * 60 * 1000;
|
|
16336
|
+
var ACTIVE_EXPORT_STATUSES = new Set(["pending", "running"]);
|
|
16337
|
+
var sleep = (ms) => new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
16338
|
+
function exportProgressLine(job) {
|
|
16339
|
+
const done = job.entities.reduce((sum, e) => sum + e.exportedRecords, 0);
|
|
16340
|
+
const total = job.entities.reduce((sum, e) => e.totalRecords === null ? sum : sum + e.totalRecords, 0);
|
|
16341
|
+
return total > 0 ? `exporting ${done}/${total} records` : "preparing export";
|
|
16342
|
+
}
|
|
16343
|
+
async function waitForExportJob(client, workspaceId, jobId, onProgress) {
|
|
16344
|
+
const deadline = Date.now() + POLL_TIMEOUT_MS;
|
|
16345
|
+
while (true) {
|
|
16346
|
+
const job = await client.getExportJob(workspaceId, jobId);
|
|
16347
|
+
if (!ACTIVE_EXPORT_STATUSES.has(job.status))
|
|
16348
|
+
return job;
|
|
16349
|
+
onProgress(exportProgressLine(job));
|
|
16350
|
+
if (Date.now() > deadline) {
|
|
16351
|
+
throw new Error(`Export ${jobId} did not finish within ${POLL_TIMEOUT_MS / 60000} minutes`);
|
|
16352
|
+
}
|
|
16353
|
+
await sleep(POLL_INTERVAL_MS);
|
|
16354
|
+
}
|
|
16355
|
+
}
|
|
16356
|
+
async function exportOneApp(client, workspaceId, target, options) {
|
|
16357
|
+
const log = (message) => {
|
|
16358
|
+
if (!options.quiet)
|
|
16359
|
+
console.log(message);
|
|
16360
|
+
};
|
|
16361
|
+
const job = await client.createAppExport(workspaceId, target.appId, {
|
|
16362
|
+
format: options.format,
|
|
16363
|
+
entityName: options.entityName
|
|
16364
|
+
});
|
|
16365
|
+
log(`${target.appName}: export job ${job.id} (${job.status})`);
|
|
16366
|
+
if (!options.wait) {
|
|
16367
|
+
return {
|
|
16368
|
+
appId: target.appId,
|
|
16369
|
+
appName: target.appName,
|
|
16370
|
+
jobId: job.id,
|
|
16371
|
+
status: job.status,
|
|
16372
|
+
records: job.recordCount,
|
|
16373
|
+
sizeBytes: job.sizeBytes,
|
|
16374
|
+
outputDir: null,
|
|
16375
|
+
files: [],
|
|
16376
|
+
error: job.error
|
|
16377
|
+
};
|
|
16378
|
+
}
|
|
16379
|
+
const finished = await waitForExportJob(client, workspaceId, job.id, (line) => {
|
|
16380
|
+
if (!options.quiet)
|
|
16381
|
+
process.stdout.write(`\r${target.appName}: ${line} `);
|
|
16382
|
+
});
|
|
16383
|
+
if (!options.quiet)
|
|
16384
|
+
process.stdout.write("\r");
|
|
16385
|
+
if (finished.status !== "completed") {
|
|
16386
|
+
log(`${target.appName}: export ${finished.status}${finished.error ? `: ${finished.error}` : ""}`);
|
|
16387
|
+
return {
|
|
16388
|
+
appId: target.appId,
|
|
16389
|
+
appName: target.appName,
|
|
16390
|
+
jobId: job.id,
|
|
16391
|
+
status: finished.status,
|
|
16392
|
+
records: finished.recordCount,
|
|
16393
|
+
sizeBytes: finished.sizeBytes,
|
|
16394
|
+
outputDir: null,
|
|
16395
|
+
files: [],
|
|
16396
|
+
error: finished.error
|
|
16397
|
+
};
|
|
16398
|
+
}
|
|
16399
|
+
const outputDir = path3.join(options.outputRoot, appSlugForPath(target.appName, target.appId));
|
|
16400
|
+
const { files: writtenFiles } = await downloadCompletedJob(client, workspaceId, job.id, outputDir, (fileName, done, total) => {
|
|
16401
|
+
if (!options.quiet)
|
|
16402
|
+
process.stdout.write(`\r${target.appName}: downloading ${fileName} (${done}/${total} chunks) `);
|
|
16403
|
+
});
|
|
16404
|
+
if (!options.quiet)
|
|
16405
|
+
process.stdout.write("\r");
|
|
16406
|
+
log(`${target.appName}: ${finished.recordCount} record(s) exported to ${outputDir}`);
|
|
16407
|
+
return {
|
|
16408
|
+
appId: target.appId,
|
|
16409
|
+
appName: target.appName,
|
|
16410
|
+
jobId: job.id,
|
|
16411
|
+
status: finished.status,
|
|
16412
|
+
records: finished.recordCount,
|
|
16413
|
+
sizeBytes: finished.sizeBytes,
|
|
16414
|
+
outputDir,
|
|
16415
|
+
files: writtenFiles,
|
|
16416
|
+
error: null
|
|
16417
|
+
};
|
|
16418
|
+
}
|
|
16419
|
+
var exportCommand = new Command15("export").description("Export entity data to local files (free on every plan; production data only)").argument("[entity]", "Restrict the export to a single entity").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name-or-id>", "App to export; omit to export every app that has entities").option("--format <format>", "Export format: json (newline-delimited JSON) or csv", "json").option("--output <dir>", "Output directory", "runwork-export").option("--no-wait", "Create the export job(s) and exit without downloading").option("--job <exportId>", "Download an existing completed export job instead of starting a new one").action(async (entity, opts, command) => {
|
|
16420
|
+
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
16421
|
+
const credentials = requireAuth();
|
|
16422
|
+
const client = new ApiClient(credentials);
|
|
16423
|
+
const { workspaceId } = await resolveWorkspace2(client, opts);
|
|
16424
|
+
if (opts.job) {
|
|
16425
|
+
try {
|
|
16426
|
+
const job = await client.getExportJob(workspaceId, opts.job);
|
|
16427
|
+
if (job.status !== "completed") {
|
|
16428
|
+
console.error(`Export ${opts.job} is not downloadable (status: ${job.status}${job.error ? `, error: ${job.error}` : ""}).`);
|
|
16429
|
+
process.exit(1);
|
|
16430
|
+
}
|
|
16431
|
+
const apps = await client.listApps(workspaceId);
|
|
16432
|
+
const appName = apps.find((a) => a.id === job.appId)?.name ?? job.appId;
|
|
16433
|
+
const outputDir = path3.join(opts.output, appSlugForPath(appName, job.appId));
|
|
16434
|
+
const result = await downloadCompletedJob(client, workspaceId, job.id, outputDir, (fileName, done, total) => {
|
|
16435
|
+
if (!useJson)
|
|
16436
|
+
process.stdout.write(`\rdownloading ${fileName} (${done}/${total} chunks) `);
|
|
16437
|
+
});
|
|
16438
|
+
if (!useJson)
|
|
16439
|
+
process.stdout.write("\r");
|
|
16440
|
+
if (useJson) {
|
|
16441
|
+
jsonOut({ export: { jobId: job.id, appId: job.appId, appName, status: job.status, records: job.recordCount, sizeBytes: job.sizeBytes, outputDir: result.outputDir, files: result.files } });
|
|
16442
|
+
} else {
|
|
16443
|
+
console.log(`${appName}: ${job.recordCount} record(s) saved to ${result.outputDir}`);
|
|
16444
|
+
}
|
|
16445
|
+
} catch (err) {
|
|
16446
|
+
console.error("Export download failed:", err instanceof Error ? err.message : err);
|
|
16447
|
+
process.exit(1);
|
|
16448
|
+
}
|
|
16449
|
+
return;
|
|
16450
|
+
}
|
|
16451
|
+
const formatInput = String(opts.format).toLowerCase();
|
|
16452
|
+
if (formatInput !== "json" && formatInput !== "ndjson" && formatInput !== "csv") {
|
|
16453
|
+
console.error(`Unknown format "${opts.format}". Use json or csv.`);
|
|
16454
|
+
process.exit(1);
|
|
16455
|
+
}
|
|
16456
|
+
const format = formatInput === "csv" ? "csv" : "ndjson";
|
|
16457
|
+
try {
|
|
16458
|
+
let appId;
|
|
16459
|
+
if (opts.app) {
|
|
16460
|
+
const resolved = await resolveApp2(client, workspaceId, { app: opts.app });
|
|
16461
|
+
appId = resolved.appId;
|
|
16462
|
+
}
|
|
16463
|
+
const entities = await client.listEntities(workspaceId);
|
|
16464
|
+
const { targets, error } = resolveExportTargets(entities, { appId, entityName: entity });
|
|
16465
|
+
if (error) {
|
|
16466
|
+
console.error(error);
|
|
16467
|
+
process.exit(1);
|
|
16468
|
+
}
|
|
16469
|
+
const results = [];
|
|
16470
|
+
for (const target of targets) {
|
|
16471
|
+
try {
|
|
16472
|
+
results.push(await exportOneApp(client, workspaceId, target, {
|
|
16473
|
+
format,
|
|
16474
|
+
entityName: entity,
|
|
16475
|
+
wait: opts.wait !== false,
|
|
16476
|
+
outputRoot: opts.output,
|
|
16477
|
+
quiet: useJson
|
|
16478
|
+
}));
|
|
16479
|
+
} catch (err) {
|
|
16480
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
16481
|
+
const kind = classifyExportError(message);
|
|
16482
|
+
const status = kind === "not_deployed" ? "skipped" : "failed";
|
|
16483
|
+
if (!useJson) {
|
|
16484
|
+
console.error(kind === "not_deployed" ? `${target.appName}: skipped (not deployed to production)` : `${target.appName}: failed: ${message}`);
|
|
16485
|
+
}
|
|
16486
|
+
results.push({
|
|
16487
|
+
appId: target.appId,
|
|
16488
|
+
appName: target.appName,
|
|
16489
|
+
jobId: "",
|
|
16490
|
+
status,
|
|
16491
|
+
records: 0,
|
|
16492
|
+
sizeBytes: 0,
|
|
16493
|
+
outputDir: null,
|
|
16494
|
+
files: [],
|
|
16495
|
+
error: message
|
|
16496
|
+
});
|
|
16497
|
+
}
|
|
16498
|
+
}
|
|
16499
|
+
if (useJson) {
|
|
16500
|
+
jsonOut({ exports: results });
|
|
16501
|
+
return;
|
|
16502
|
+
}
|
|
16503
|
+
const exported = results.filter((r) => r.status === "completed");
|
|
16504
|
+
const skipped = results.filter((r) => r.status === "skipped");
|
|
16505
|
+
const failed = results.filter((r) => r.status === "failed");
|
|
16506
|
+
const summary = [`${exported.length} app(s) exported`];
|
|
16507
|
+
if (skipped.length > 0)
|
|
16508
|
+
summary.push(`${skipped.length} skipped (not deployed)`);
|
|
16509
|
+
if (failed.length > 0)
|
|
16510
|
+
summary.push(`${failed.length} failed`);
|
|
16511
|
+
console.log(`
|
|
16512
|
+
${summary.join(", ")}.`);
|
|
16513
|
+
if (failed.length > 0 || opts.app && skipped.length > 0) {
|
|
16514
|
+
process.exit(1);
|
|
16515
|
+
}
|
|
16516
|
+
} catch (err) {
|
|
16517
|
+
console.error("Export failed:", err instanceof Error ? err.message : err);
|
|
16518
|
+
process.exit(1);
|
|
16519
|
+
}
|
|
16520
|
+
});
|
|
16521
|
+
var entitiesCommand = new Command15("entities").alias("data").description("Manage workspace entity data").addCommand(listCommand3).addCommand(recordsCommand).addCommand(getCommand).addCommand(createCommand).addCommand(updateCommand).addCommand(deleteCommand).addCommand(exportCommand);
|
|
16175
16522
|
|
|
16176
16523
|
// src/commands/workflows.ts
|
|
16177
16524
|
init_store();
|
|
@@ -16575,12 +16922,12 @@ Workspace: ${workspaceName || workspaceId}
|
|
|
16575
16922
|
console.log(" " + "-".repeat(90));
|
|
16576
16923
|
for (const e of endpoints) {
|
|
16577
16924
|
const method = e.method.toUpperCase().padEnd(8);
|
|
16578
|
-
const
|
|
16925
|
+
const path4 = e.endpointPath.padEnd(36);
|
|
16579
16926
|
const app = (e.appName || e.appId).padEnd(20);
|
|
16580
16927
|
const auth = (e.auth || "").padEnd(10);
|
|
16581
16928
|
const desc = truncate3(e.description, 40);
|
|
16582
16929
|
const mode = e.deploymentMode ? ` [${e.deploymentMode}]` : "";
|
|
16583
|
-
console.log(` ${method} ${
|
|
16930
|
+
console.log(` ${method} ${path4} ${app} ${auth} ${desc}${mode}`);
|
|
16584
16931
|
}
|
|
16585
16932
|
console.log("");
|
|
16586
16933
|
} catch (err) {
|
|
@@ -16588,7 +16935,7 @@ Workspace: ${workspaceName || workspaceId}
|
|
|
16588
16935
|
process.exit(1);
|
|
16589
16936
|
}
|
|
16590
16937
|
});
|
|
16591
|
-
var callCommand2 = new Command18("call").description("Call a workspace endpoint directly").argument("<method>", "HTTP method (GET, POST, PUT, DELETE, etc.)").argument("<path>", "Endpoint path (e.g. /my-endpoint)").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name>", "App name or ID (narrows endpoint lookup)").option("--body <json>", "Request body as JSON string").option("--header <header>", 'Request header (format: "Key: Value", repeatable)', (val, prev) => [...prev, val], []).option("--query <string>", 'Query string to append to the URL (e.g. "foo=bar&baz=1")').option("--api-key <key>", "API key for Authorization: Bearer header").action(async (method,
|
|
16938
|
+
var callCommand2 = new Command18("call").description("Call a workspace endpoint directly").argument("<method>", "HTTP method (GET, POST, PUT, DELETE, etc.)").argument("<path>", "Endpoint path (e.g. /my-endpoint)").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name>", "App name or ID (narrows endpoint lookup)").option("--body <json>", "Request body as JSON string").option("--header <header>", 'Request header (format: "Key: Value", repeatable)', (val, prev) => [...prev, val], []).option("--query <string>", 'Query string to append to the URL (e.g. "foo=bar&baz=1")').option("--api-key <key>", "API key for Authorization: Bearer header").action(async (method, path4, opts, command) => {
|
|
16592
16939
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
16593
16940
|
const credentials = requireAuth();
|
|
16594
16941
|
const client = new ApiClient(credentials);
|
|
@@ -16599,9 +16946,9 @@ var callCommand2 = new Command18("call").description("Call a workspace endpoint
|
|
|
16599
16946
|
endpoints = endpoints.filter((e) => e.appId === opts.app || e.appName === opts.app);
|
|
16600
16947
|
}
|
|
16601
16948
|
const targetMethod = method.toUpperCase();
|
|
16602
|
-
const endpoint = endpoints.find((e) => e.method.toUpperCase() === targetMethod && e.endpointPath ===
|
|
16949
|
+
const endpoint = endpoints.find((e) => e.method.toUpperCase() === targetMethod && e.endpointPath === path4);
|
|
16603
16950
|
if (!endpoint) {
|
|
16604
|
-
console.error(`Endpoint not found: ${targetMethod} ${
|
|
16951
|
+
console.error(`Endpoint not found: ${targetMethod} ${path4}`);
|
|
16605
16952
|
if (endpoints.length > 0) {
|
|
16606
16953
|
console.error(`
|
|
16607
16954
|
Available endpoints:`);
|
|
@@ -16620,7 +16967,7 @@ Available endpoints:`);
|
|
|
16620
16967
|
process.exit(1);
|
|
16621
16968
|
}
|
|
16622
16969
|
const baseUrl = `https://${workspaceName}.runwork.ai`;
|
|
16623
|
-
let url = `${baseUrl}/${appSlug}/endpoints${
|
|
16970
|
+
let url = `${baseUrl}/${appSlug}/endpoints${path4}`;
|
|
16624
16971
|
if (opts.query) {
|
|
16625
16972
|
url = `${url}?${opts.query}`;
|
|
16626
16973
|
}
|
|
@@ -16704,7 +17051,7 @@ var endpointsCommand = new Command18("endpoints").alias("routes").description("M
|
|
|
16704
17051
|
init_store();
|
|
16705
17052
|
init_client();
|
|
16706
17053
|
import { Command as Command19 } from "commander";
|
|
16707
|
-
import { writeFileSync as
|
|
17054
|
+
import { writeFileSync as writeFileSync29, readFileSync as readFileSync32 } from "fs";
|
|
16708
17055
|
import { basename as basename2 } from "path";
|
|
16709
17056
|
init_prompt();
|
|
16710
17057
|
init_http();
|
|
@@ -16798,7 +17145,7 @@ var downloadCommand = new Command19("download").description("Download a file fro
|
|
|
16798
17145
|
if (!response.ok) {
|
|
16799
17146
|
throw new Error(`Download failed: ${response.status} ${response.statusText}`);
|
|
16800
17147
|
}
|
|
16801
|
-
|
|
17148
|
+
writeFileSync29(outputPath, Buffer.from(await response.arrayBuffer()));
|
|
16802
17149
|
if (useJson) {
|
|
16803
17150
|
jsonOut({ success: true, bucket, key, outputPath });
|
|
16804
17151
|
return;
|
|
@@ -17315,8 +17662,8 @@ var mcpCommand = new Command23("mcp").description("Manage workspace MCP servers"
|
|
|
17315
17662
|
init_store();
|
|
17316
17663
|
init_client();
|
|
17317
17664
|
import { Command as Command25 } from "commander";
|
|
17318
|
-
import { writeFileSync as
|
|
17319
|
-
import { join as
|
|
17665
|
+
import { writeFileSync as writeFileSync31, mkdirSync as mkdirSync28 } from "fs";
|
|
17666
|
+
import { join as join39 } from "path";
|
|
17320
17667
|
import { homedir as homedir19 } from "os";
|
|
17321
17668
|
init_prompt();
|
|
17322
17669
|
|
|
@@ -17324,8 +17671,8 @@ init_prompt();
|
|
|
17324
17671
|
init_store();
|
|
17325
17672
|
init_client();
|
|
17326
17673
|
import { Command as Command24 } from "commander";
|
|
17327
|
-
import { readFileSync as readFileSync33, writeFileSync as
|
|
17328
|
-
import { join as
|
|
17674
|
+
import { readFileSync as readFileSync33, writeFileSync as writeFileSync30, existsSync as existsSync42 } from "fs";
|
|
17675
|
+
import { join as join37 } from "path";
|
|
17329
17676
|
import { homedir as homedir17 } from "os";
|
|
17330
17677
|
|
|
17331
17678
|
// src/commands/mcp-entries.ts
|
|
@@ -18584,7 +18931,7 @@ Tip: ${hint.title}`);
|
|
|
18584
18931
|
} catch {}
|
|
18585
18932
|
}
|
|
18586
18933
|
function loadSetupState(filePath) {
|
|
18587
|
-
if (!
|
|
18934
|
+
if (!existsSync42(filePath))
|
|
18588
18935
|
return null;
|
|
18589
18936
|
try {
|
|
18590
18937
|
return JSON.parse(readFileSync33(filePath, "utf-8"));
|
|
@@ -18608,14 +18955,14 @@ function readLocalSkills(state) {
|
|
|
18608
18955
|
if (!baseDir)
|
|
18609
18956
|
continue;
|
|
18610
18957
|
for (const skillName of state.skills) {
|
|
18611
|
-
const skillMdPath =
|
|
18612
|
-
if (
|
|
18958
|
+
const skillMdPath = join37(baseDir, skillName, "SKILL.md");
|
|
18959
|
+
if (existsSync42(skillMdPath)) {
|
|
18613
18960
|
results.push({ name: skillName, content: readFileSync33(skillMdPath, "utf-8") });
|
|
18614
18961
|
continue;
|
|
18615
18962
|
}
|
|
18616
18963
|
const filename = skillName.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
18617
|
-
const flatPath =
|
|
18618
|
-
if (
|
|
18964
|
+
const flatPath = join37(baseDir, `${filename}.md`);
|
|
18965
|
+
if (existsSync42(flatPath)) {
|
|
18619
18966
|
results.push({ name: skillName, content: readFileSync33(flatPath, "utf-8") });
|
|
18620
18967
|
}
|
|
18621
18968
|
}
|
|
@@ -18820,7 +19167,7 @@ async function syncFromState(state, statePath2, credentials, opts) {
|
|
|
18820
19167
|
persona: state.persona
|
|
18821
19168
|
});
|
|
18822
19169
|
let projectAppSkillFilter = null;
|
|
18823
|
-
if (
|
|
19170
|
+
if (existsSync42(".runwork.json")) {
|
|
18824
19171
|
try {
|
|
18825
19172
|
const config = JSON.parse(readFileSync33(".runwork.json", "utf-8"));
|
|
18826
19173
|
if (config.appName) {
|
|
@@ -19059,7 +19406,7 @@ async function syncFromState(state, statePath2, credentials, opts) {
|
|
|
19059
19406
|
}
|
|
19060
19407
|
for (const adapter2 of adapters) {
|
|
19061
19408
|
if (adapter2 instanceof CodexAdapter) {
|
|
19062
|
-
const runworkDir =
|
|
19409
|
+
const runworkDir = join37(homedir17(), ".runwork");
|
|
19063
19410
|
const result = adapter2.registerDesktopWorkspace(runworkDir, "Runwork");
|
|
19064
19411
|
if (result === "written") {
|
|
19065
19412
|
vlog(` [${adapter2.name}] Registered workspace in Codex desktop app`);
|
|
@@ -19134,7 +19481,7 @@ async function syncFromState(state, statePath2, credentials, opts) {
|
|
|
19134
19481
|
delete mergedHashes[del.name];
|
|
19135
19482
|
}
|
|
19136
19483
|
state.skillHashes = mergedHashes;
|
|
19137
|
-
|
|
19484
|
+
writeFileSync30(statePath2, JSON.stringify(state, null, 2));
|
|
19138
19485
|
try {
|
|
19139
19486
|
const telemetryNow = new Date().toISOString();
|
|
19140
19487
|
const telemetry = await collectTelemetryEvents({
|
|
@@ -19154,7 +19501,7 @@ async function syncFromState(state, statePath2, credentials, opts) {
|
|
|
19154
19501
|
if (telemetry.healthReported) {
|
|
19155
19502
|
state.lastHealthReportAt = new Date().toISOString();
|
|
19156
19503
|
}
|
|
19157
|
-
|
|
19504
|
+
writeFileSync30(statePath2, JSON.stringify(state, null, 2));
|
|
19158
19505
|
} catch {}
|
|
19159
19506
|
const failedNote = summary.adaptersFailed > 0 ? ` (${summary.adaptersFailed} failed)` : "";
|
|
19160
19507
|
if (isVerbose()) {
|
|
@@ -19192,8 +19539,8 @@ var syncCommand = new Command24("sync").description("Sync skills bidirectionally
|
|
|
19192
19539
|
verbose: !!opts.verbose,
|
|
19193
19540
|
redetect: !!opts.redetect
|
|
19194
19541
|
};
|
|
19195
|
-
const projectStatePath =
|
|
19196
|
-
const userStatePath =
|
|
19542
|
+
const projectStatePath = join37(process.cwd(), ".runwork", "setup.json");
|
|
19543
|
+
const userStatePath = join37(homedir17(), ".runwork", "setup.json");
|
|
19197
19544
|
const projectState = loadSetupState(projectStatePath);
|
|
19198
19545
|
const userState = loadSetupState(userStatePath);
|
|
19199
19546
|
if (!projectState && !userState) {
|
|
@@ -19214,14 +19561,14 @@ Sync complete.`);
|
|
|
19214
19561
|
});
|
|
19215
19562
|
|
|
19216
19563
|
// src/utils/setup-state.ts
|
|
19217
|
-
import { existsSync as
|
|
19218
|
-
import { join as
|
|
19564
|
+
import { existsSync as existsSync43, readFileSync as readFileSync34 } from "fs";
|
|
19565
|
+
import { join as join38 } from "path";
|
|
19219
19566
|
import { homedir as homedir18 } from "os";
|
|
19220
19567
|
function loadSetupState2() {
|
|
19221
|
-
const projectPath =
|
|
19222
|
-
const userPath =
|
|
19568
|
+
const projectPath = join38(process.cwd(), ".runwork", "setup.json");
|
|
19569
|
+
const userPath = join38(homedir18(), ".runwork", "setup.json");
|
|
19223
19570
|
for (const p of [projectPath, userPath]) {
|
|
19224
|
-
if (
|
|
19571
|
+
if (existsSync43(p)) {
|
|
19225
19572
|
try {
|
|
19226
19573
|
return JSON.parse(readFileSync34(p, "utf-8"));
|
|
19227
19574
|
} catch {
|
|
@@ -19343,9 +19690,9 @@ Configuring all agents (--yes).
|
|
|
19343
19690
|
};
|
|
19344
19691
|
const scopes = scope === "both" ? ["project", "user"] : [scope];
|
|
19345
19692
|
for (const s of scopes) {
|
|
19346
|
-
const dir = s === "project" ? ".runwork" :
|
|
19347
|
-
|
|
19348
|
-
|
|
19693
|
+
const dir = s === "project" ? ".runwork" : join39(homedir19(), ".runwork");
|
|
19694
|
+
mkdirSync28(dir, { recursive: true });
|
|
19695
|
+
writeFileSync31(join39(dir, "setup.json"), JSON.stringify(state, null, 2));
|
|
19349
19696
|
}
|
|
19350
19697
|
if (opts.dryRun) {
|
|
19351
19698
|
console.log(`
|
|
@@ -19361,7 +19708,7 @@ Re-run without --dry-run to sync workspace data.`);
|
|
|
19361
19708
|
Syncing workspace data...
|
|
19362
19709
|
`);
|
|
19363
19710
|
for (const s of scopes) {
|
|
19364
|
-
const statePath2 = s === "project" ?
|
|
19711
|
+
const statePath2 = s === "project" ? join39(process.cwd(), ".runwork", "setup.json") : join39(homedir19(), ".runwork", "setup.json");
|
|
19365
19712
|
await syncFromState(state, statePath2, credentials, {
|
|
19366
19713
|
dryRun: false,
|
|
19367
19714
|
pullOnly: true,
|
|
@@ -19378,11 +19725,11 @@ Syncing workspace data...
|
|
|
19378
19725
|
init_store();
|
|
19379
19726
|
init_client();
|
|
19380
19727
|
import { Command as Command26 } from "commander";
|
|
19381
|
-
import { existsSync as
|
|
19382
|
-
import { resolve as resolve3, join as
|
|
19728
|
+
import { existsSync as existsSync44, readFileSync as readFileSync35 } from "fs";
|
|
19729
|
+
import { resolve as resolve3, join as join40 } from "path";
|
|
19383
19730
|
import { homedir as homedir20 } from "os";
|
|
19384
19731
|
function loadSetupState3(filePath) {
|
|
19385
|
-
if (!
|
|
19732
|
+
if (!existsSync44(filePath))
|
|
19386
19733
|
return null;
|
|
19387
19734
|
try {
|
|
19388
19735
|
return JSON.parse(readFileSync35(filePath, "utf-8"));
|
|
@@ -19401,8 +19748,8 @@ var buildPluginCommand = new Command26("build-plugin").description("Build an ins
|
|
|
19401
19748
|
process.exit(1);
|
|
19402
19749
|
}
|
|
19403
19750
|
const credentials = requireAuth();
|
|
19404
|
-
const projectStatePath =
|
|
19405
|
-
const userStatePath =
|
|
19751
|
+
const projectStatePath = join40(process.cwd(), ".runwork", "setup.json");
|
|
19752
|
+
const userStatePath = join40(homedir20(), ".runwork", "setup.json");
|
|
19406
19753
|
const state = loadSetupState3(projectStatePath) ?? loadSetupState3(userStatePath);
|
|
19407
19754
|
if (!state) {
|
|
19408
19755
|
console.error("No setup state found. Run `runwork setup` first.");
|
|
@@ -19492,12 +19839,12 @@ var buildPluginCommand = new Command26("build-plugin").description("Build an ins
|
|
|
19492
19839
|
|
|
19493
19840
|
// src/commands/uninstall.ts
|
|
19494
19841
|
import { Command as Command27 } from "commander";
|
|
19495
|
-
import { existsSync as
|
|
19496
|
-
import { join as
|
|
19842
|
+
import { existsSync as existsSync45, readFileSync as readFileSync36, rmSync as rmSync12, unlinkSync as unlinkSync7 } from "fs";
|
|
19843
|
+
import { join as join41 } from "path";
|
|
19497
19844
|
import { homedir as homedir21 } from "os";
|
|
19498
19845
|
init_prompt();
|
|
19499
19846
|
function loadSetupState4(filePath) {
|
|
19500
|
-
if (!
|
|
19847
|
+
if (!existsSync45(filePath))
|
|
19501
19848
|
return null;
|
|
19502
19849
|
try {
|
|
19503
19850
|
return JSON.parse(readFileSync36(filePath, "utf-8"));
|
|
@@ -19506,8 +19853,8 @@ function loadSetupState4(filePath) {
|
|
|
19506
19853
|
}
|
|
19507
19854
|
}
|
|
19508
19855
|
var uninstallCommand = new Command27("uninstall").description("Remove all Runwork configuration from local agents (MCP servers, skills, instructions)").option("-y, --yes", "Skip confirmation prompt").option("--keep-auth", "Keep authentication credentials (only remove agent configs)").action(async (opts) => {
|
|
19509
|
-
const projectStatePath =
|
|
19510
|
-
const userStatePath =
|
|
19856
|
+
const projectStatePath = join41(process.cwd(), ".runwork", "setup.json");
|
|
19857
|
+
const userStatePath = join41(homedir21(), ".runwork", "setup.json");
|
|
19511
19858
|
const projectState = loadSetupState4(projectStatePath);
|
|
19512
19859
|
const userState = loadSetupState4(userStatePath);
|
|
19513
19860
|
if (!projectState && !userState) {
|
|
@@ -19587,10 +19934,10 @@ This will remove all Runwork configuration from your local agents:
|
|
|
19587
19934
|
}
|
|
19588
19935
|
}
|
|
19589
19936
|
}
|
|
19590
|
-
const stateDir = label === "project" ?
|
|
19937
|
+
const stateDir = label === "project" ? join41(process.cwd(), ".runwork") : join41(homedir21(), ".runwork");
|
|
19591
19938
|
if (opts.keepAuth && label === "user") {
|
|
19592
|
-
const setupFile =
|
|
19593
|
-
if (
|
|
19939
|
+
const setupFile = join41(stateDir, "setup.json");
|
|
19940
|
+
if (existsSync45(setupFile)) {
|
|
19594
19941
|
try {
|
|
19595
19942
|
unlinkSync7(setupFile);
|
|
19596
19943
|
console.log(` Removed ${setupFile} (kept credentials)`);
|
|
@@ -19599,7 +19946,7 @@ This will remove all Runwork configuration from your local agents:
|
|
|
19599
19946
|
errors++;
|
|
19600
19947
|
}
|
|
19601
19948
|
}
|
|
19602
|
-
} else if (
|
|
19949
|
+
} else if (existsSync45(stateDir)) {
|
|
19603
19950
|
try {
|
|
19604
19951
|
rmSync12(stateDir, { recursive: true, force: true });
|
|
19605
19952
|
console.log(` Removed ${stateDir}`);
|
|
@@ -19751,12 +20098,12 @@ Examples:
|
|
|
19751
20098
|
|
|
19752
20099
|
Authentication uses your stored Runwork credentials; the API key never needs
|
|
19753
20100
|
to be read or pasted manually. Prefer a dedicated command when one exists
|
|
19754
|
-
(runwork apps/members/schedules/...).`).action(async (method,
|
|
20101
|
+
(runwork apps/members/schedules/...).`).action(async (method, path4, opts, command) => {
|
|
19755
20102
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
19756
20103
|
const credentials = requireAuth();
|
|
19757
20104
|
const client = new ApiClient(credentials);
|
|
19758
20105
|
let finalMethod = method;
|
|
19759
|
-
let finalPath =
|
|
20106
|
+
let finalPath = path4;
|
|
19760
20107
|
const headers = {};
|
|
19761
20108
|
let body;
|
|
19762
20109
|
const query = opts.query;
|
|
@@ -19833,8 +20180,8 @@ init_subprocess();
|
|
|
19833
20180
|
init_store();
|
|
19834
20181
|
init_client();
|
|
19835
20182
|
import { parse as parse2 } from "smol-toml";
|
|
19836
|
-
import { existsSync as
|
|
19837
|
-
import { join as
|
|
20183
|
+
import { existsSync as existsSync46, readFileSync as readFileSync38 } from "fs";
|
|
20184
|
+
import { join as join42, sep as sep4 } from "path";
|
|
19838
20185
|
import { homedir as homedir22, platform as osPlatform2, arch as osArch } from "os";
|
|
19839
20186
|
init_http();
|
|
19840
20187
|
init_preflight();
|
|
@@ -19866,8 +20213,8 @@ function buildContext() {
|
|
|
19866
20213
|
const credentials = getCredentials();
|
|
19867
20214
|
const client = credentials ? new ApiClient(credentials) : null;
|
|
19868
20215
|
let config = null;
|
|
19869
|
-
const configPath =
|
|
19870
|
-
if (
|
|
20216
|
+
const configPath = join42(process.cwd(), ".runwork.json");
|
|
20217
|
+
if (existsSync46(configPath)) {
|
|
19871
20218
|
try {
|
|
19872
20219
|
config = JSON.parse(readFileSync38(configPath, "utf-8"));
|
|
19873
20220
|
} catch {}
|
|
@@ -19971,8 +20318,8 @@ async function checkCliArtifactReachable() {
|
|
|
19971
20318
|
async function checkCliInstallLocation() {
|
|
19972
20319
|
const isWindows2 = osPlatform2() === "win32";
|
|
19973
20320
|
const home = homedir22();
|
|
19974
|
-
const canonicalDir =
|
|
19975
|
-
const canonicalBinary = isWindows2 ?
|
|
20321
|
+
const canonicalDir = join42(home, ".runwork", "bin");
|
|
20322
|
+
const canonicalBinary = isWindows2 ? join42(canonicalDir, "runwork.exe") : join42(canonicalDir, "runwork");
|
|
19976
20323
|
const candidates = [process.execPath, process.argv[1] || ""].filter(Boolean);
|
|
19977
20324
|
const runsFromCanonical = candidates.some((p) => normalizePath(p) === normalizePath(canonicalBinary));
|
|
19978
20325
|
if (runsFromCanonical) {
|
|
@@ -19982,7 +20329,7 @@ async function checkCliInstallLocation() {
|
|
|
19982
20329
|
message: `canonical (${canonicalBinary})`
|
|
19983
20330
|
};
|
|
19984
20331
|
}
|
|
19985
|
-
if (
|
|
20332
|
+
if (existsSync46(canonicalBinary)) {
|
|
19986
20333
|
return {
|
|
19987
20334
|
name: "cli-install-location",
|
|
19988
20335
|
status: "warn",
|
|
@@ -20104,8 +20451,8 @@ async function checkGitCredentialHelper(ctx) {
|
|
|
20104
20451
|
};
|
|
20105
20452
|
}
|
|
20106
20453
|
async function checkProjectConfig(ctx) {
|
|
20107
|
-
const configPath =
|
|
20108
|
-
if (!
|
|
20454
|
+
const configPath = join42(ctx.cwd, ".runwork.json");
|
|
20455
|
+
if (!existsSync46(configPath)) {
|
|
20109
20456
|
if (!ctx.credentials) {
|
|
20110
20457
|
return { name: "project-config", status: "skip", message: "no project (not logged in)" };
|
|
20111
20458
|
}
|
|
@@ -20167,7 +20514,7 @@ async function checkGitRemote(ctx) {
|
|
|
20167
20514
|
if (!ctx.config) {
|
|
20168
20515
|
return { name: "git-remote", status: "skip", message: "skipped (no project)" };
|
|
20169
20516
|
}
|
|
20170
|
-
if (!
|
|
20517
|
+
if (!existsSync46(join42(ctx.cwd, ".git"))) {
|
|
20171
20518
|
return {
|
|
20172
20519
|
name: "git-remote",
|
|
20173
20520
|
status: "fail",
|
|
@@ -20221,10 +20568,10 @@ async function checkDeployFreshness(ctx) {
|
|
|
20221
20568
|
return { name: "deploy-freshness", status: "skip", message: "local HEAD unknown" };
|
|
20222
20569
|
}
|
|
20223
20570
|
function loadSetupState5() {
|
|
20224
|
-
const projectPath =
|
|
20225
|
-
const userPath =
|
|
20571
|
+
const projectPath = join42(process.cwd(), ".runwork", "setup.json");
|
|
20572
|
+
const userPath = join42(homedir22(), ".runwork", "setup.json");
|
|
20226
20573
|
for (const p of [projectPath, userPath]) {
|
|
20227
|
-
if (
|
|
20574
|
+
if (existsSync46(p)) {
|
|
20228
20575
|
try {
|
|
20229
20576
|
return JSON.parse(readFileSync38(p, "utf-8"));
|
|
20230
20577
|
} catch {
|
|
@@ -20241,8 +20588,8 @@ async function checkCodexNetwork() {
|
|
|
20241
20588
|
if (!state || !state.configuredAgents.includes("codex")) {
|
|
20242
20589
|
return { name, status: "skip", message: "Codex not configured for Runwork" };
|
|
20243
20590
|
}
|
|
20244
|
-
const configPath =
|
|
20245
|
-
if (!
|
|
20591
|
+
const configPath = join42(homedir22(), ".codex", "config.toml");
|
|
20592
|
+
if (!existsSync46(configPath)) {
|
|
20246
20593
|
return { name, status: "skip", message: "no Codex config found" };
|
|
20247
20594
|
}
|
|
20248
20595
|
let parsed;
|
|
@@ -20300,8 +20647,8 @@ async function checkCodexDesktopProject() {
|
|
|
20300
20647
|
if (!usesCodex) {
|
|
20301
20648
|
return { name, status: "skip", message: "Codex not configured for Runwork" };
|
|
20302
20649
|
}
|
|
20303
|
-
const statePath2 =
|
|
20304
|
-
if (!
|
|
20650
|
+
const statePath2 = join42(homedir22(), ".codex", ".codex-global-state.json");
|
|
20651
|
+
if (!existsSync46(statePath2)) {
|
|
20305
20652
|
return { name, status: "skip", message: "Codex desktop app not detected" };
|
|
20306
20653
|
}
|
|
20307
20654
|
let savedRoots = [];
|
|
@@ -20312,7 +20659,7 @@ async function checkCodexDesktopProject() {
|
|
|
20312
20659
|
} catch {
|
|
20313
20660
|
return { name, status: "warn", message: "could not read Codex desktop state" };
|
|
20314
20661
|
}
|
|
20315
|
-
const runworkDir =
|
|
20662
|
+
const runworkDir = join42(homedir22(), ".runwork");
|
|
20316
20663
|
if (savedRoots.includes(runworkDir)) {
|
|
20317
20664
|
return { name, status: "pass", message: "Runwork project added to Codex desktop sidebar" };
|
|
20318
20665
|
}
|
|
@@ -20365,7 +20712,7 @@ async function checkAgentSetup() {
|
|
|
20365
20712
|
if (!adapter2 || !adapter2.supportsMcpScope("user"))
|
|
20366
20713
|
continue;
|
|
20367
20714
|
const mcpConfigPath = getMcpConfigPath2(slug, "user");
|
|
20368
|
-
if (mcpConfigPath &&
|
|
20715
|
+
if (mcpConfigPath && existsSync46(mcpConfigPath)) {
|
|
20369
20716
|
try {
|
|
20370
20717
|
const content = readFileSync38(mcpConfigPath, "utf-8");
|
|
20371
20718
|
const missingMcp = state.mcpServers.filter((name) => !content.includes(name));
|
|
@@ -20390,8 +20737,8 @@ async function checkAgentSetup() {
|
|
|
20390
20737
|
if (!skillsDir)
|
|
20391
20738
|
continue;
|
|
20392
20739
|
const missingSkills = state.skills.filter((name) => {
|
|
20393
|
-
const skillPath =
|
|
20394
|
-
return !
|
|
20740
|
+
const skillPath = join42(skillsDir, name, "SKILL.md");
|
|
20741
|
+
return !existsSync46(skillPath);
|
|
20395
20742
|
});
|
|
20396
20743
|
if (missingSkills.length > 0) {
|
|
20397
20744
|
details.push(`${missingSkills.length} skill(s) missing from ${slug}`);
|
|
@@ -20419,16 +20766,16 @@ function getMcpConfigPath2(slug, scope) {
|
|
|
20419
20766
|
const home = homedir22();
|
|
20420
20767
|
switch (slug) {
|
|
20421
20768
|
case "claude-code":
|
|
20422
|
-
return scope === "project" ?
|
|
20769
|
+
return scope === "project" ? join42(process.cwd(), ".mcp.json") : join42(home, ".claude", "settings.json");
|
|
20423
20770
|
case "cursor":
|
|
20424
|
-
return scope === "project" ?
|
|
20771
|
+
return scope === "project" ? join42(process.cwd(), ".cursor", "mcp.json") : join42(home, ".cursor", "mcp.json");
|
|
20425
20772
|
case "windsurf":
|
|
20426
|
-
return scope === "project" ?
|
|
20773
|
+
return scope === "project" ? join42(process.cwd(), ".windsurf", "mcp.json") : join42(home, ".windsurf", "mcp.json");
|
|
20427
20774
|
case "codex":
|
|
20428
20775
|
case "codex-app":
|
|
20429
|
-
return scope === "user" ?
|
|
20776
|
+
return scope === "user" ? join42(home, ".codex", "config.toml") : null;
|
|
20430
20777
|
case "gemini":
|
|
20431
|
-
return scope === "user" ?
|
|
20778
|
+
return scope === "user" ? join42(home, ".gemini", "settings.json") : null;
|
|
20432
20779
|
default:
|
|
20433
20780
|
return null;
|
|
20434
20781
|
}
|
|
@@ -20437,12 +20784,12 @@ function getSkillsDir(slug, scope) {
|
|
|
20437
20784
|
const home = homedir22();
|
|
20438
20785
|
switch (slug) {
|
|
20439
20786
|
case "claude-code":
|
|
20440
|
-
return scope === "project" ?
|
|
20787
|
+
return scope === "project" ? join42(process.cwd(), ".claude", "skills") : join42(home, ".claude", "skills");
|
|
20441
20788
|
case "codex":
|
|
20442
20789
|
case "codex-app":
|
|
20443
|
-
return scope === "project" ?
|
|
20790
|
+
return scope === "project" ? join42(process.cwd(), ".agents", "skills") : join42(home, ".agents", "skills");
|
|
20444
20791
|
case "gemini":
|
|
20445
|
-
return scope === "project" ?
|
|
20792
|
+
return scope === "project" ? join42(process.cwd(), ".gemini", "skills") : join42(home, ".gemini", "skills");
|
|
20446
20793
|
default:
|
|
20447
20794
|
return null;
|
|
20448
20795
|
}
|
|
@@ -20494,8 +20841,8 @@ async function runAllChecks(options) {
|
|
|
20494
20841
|
// src/health/fix.ts
|
|
20495
20842
|
init_credentials();
|
|
20496
20843
|
init_remote();
|
|
20497
|
-
import { existsSync as
|
|
20498
|
-
import { join as
|
|
20844
|
+
import { existsSync as existsSync47 } from "fs";
|
|
20845
|
+
import { join as join43 } from "path";
|
|
20499
20846
|
async function applyDoctorFixes(ctx, failingNames) {
|
|
20500
20847
|
const failing = new Set(failingNames);
|
|
20501
20848
|
const outcomes = [];
|
|
@@ -20522,7 +20869,7 @@ async function applyDoctorFixes(ctx, failingNames) {
|
|
|
20522
20869
|
applied: false,
|
|
20523
20870
|
message: "no project config -- run inside an app directory"
|
|
20524
20871
|
});
|
|
20525
|
-
} else if (!
|
|
20872
|
+
} else if (!existsSync47(join43(ctx.cwd, ".git"))) {
|
|
20526
20873
|
outcomes.push({
|
|
20527
20874
|
name: "git-remote",
|
|
20528
20875
|
applied: false,
|
|
@@ -20541,10 +20888,10 @@ async function applyDoctorFixes(ctx, failingNames) {
|
|
|
20541
20888
|
}
|
|
20542
20889
|
|
|
20543
20890
|
// src/agents/runtime-detection.ts
|
|
20544
|
-
import { existsSync as
|
|
20891
|
+
import { existsSync as existsSync48, readFileSync as readFileSync39, statSync as statSync8, readdirSync as readdirSync13 } from "fs";
|
|
20545
20892
|
import { homedir as homedir23 } from "os";
|
|
20546
|
-
import { join as
|
|
20547
|
-
var RUNWORK_SESSIONS_DIR =
|
|
20893
|
+
import { join as join44 } from "path";
|
|
20894
|
+
var RUNWORK_SESSIONS_DIR = join44(homedir23(), ".runwork", "sessions");
|
|
20548
20895
|
function detectCurrentAgent() {
|
|
20549
20896
|
const claudeCodeSessionId = process.env.CLAUDE_CODE_SESSION_ID;
|
|
20550
20897
|
if (claudeCodeSessionId) {
|
|
@@ -20607,11 +20954,11 @@ function detectCurrentAgent() {
|
|
|
20607
20954
|
return null;
|
|
20608
20955
|
}
|
|
20609
20956
|
function readHookSessionInfo(sessionId) {
|
|
20610
|
-
const
|
|
20611
|
-
if (!
|
|
20957
|
+
const path4 = join44(RUNWORK_SESSIONS_DIR, `${sessionId}.json`);
|
|
20958
|
+
if (!existsSync48(path4))
|
|
20612
20959
|
return null;
|
|
20613
20960
|
try {
|
|
20614
|
-
const raw = readFileSync39(
|
|
20961
|
+
const raw = readFileSync39(path4, "utf8");
|
|
20615
20962
|
const parsed = JSON.parse(raw);
|
|
20616
20963
|
return parsed;
|
|
20617
20964
|
} catch {
|
|
@@ -20619,8 +20966,8 @@ function readHookSessionInfo(sessionId) {
|
|
|
20619
20966
|
}
|
|
20620
20967
|
}
|
|
20621
20968
|
function findClaudeCodeSessionFile(sessionId) {
|
|
20622
|
-
const root =
|
|
20623
|
-
if (!
|
|
20969
|
+
const root = join44(homedir23(), ".claude", "projects");
|
|
20970
|
+
if (!existsSync48(root))
|
|
20624
20971
|
return null;
|
|
20625
20972
|
let projectDirs;
|
|
20626
20973
|
try {
|
|
@@ -20629,15 +20976,15 @@ function findClaudeCodeSessionFile(sessionId) {
|
|
|
20629
20976
|
return null;
|
|
20630
20977
|
}
|
|
20631
20978
|
for (const dir of projectDirs) {
|
|
20632
|
-
const candidate =
|
|
20633
|
-
if (
|
|
20979
|
+
const candidate = join44(root, dir, `${sessionId}.jsonl`);
|
|
20980
|
+
if (existsSync48(candidate))
|
|
20634
20981
|
return candidate;
|
|
20635
20982
|
}
|
|
20636
20983
|
return null;
|
|
20637
20984
|
}
|
|
20638
20985
|
function findCodexRolloutFile(threadId) {
|
|
20639
|
-
const root =
|
|
20640
|
-
if (!
|
|
20986
|
+
const root = join44(homedir23(), ".codex", "sessions");
|
|
20987
|
+
if (!existsSync48(root))
|
|
20641
20988
|
return null;
|
|
20642
20989
|
const stack = [root];
|
|
20643
20990
|
while (stack.length > 0) {
|
|
@@ -20649,10 +20996,10 @@ function findCodexRolloutFile(threadId) {
|
|
|
20649
20996
|
continue;
|
|
20650
20997
|
}
|
|
20651
20998
|
for (const entry of entries) {
|
|
20652
|
-
const full =
|
|
20999
|
+
const full = join44(dir, entry);
|
|
20653
21000
|
let s;
|
|
20654
21001
|
try {
|
|
20655
|
-
s =
|
|
21002
|
+
s = statSync8(full);
|
|
20656
21003
|
} catch {
|
|
20657
21004
|
continue;
|
|
20658
21005
|
}
|
|
@@ -20666,8 +21013,8 @@ function findCodexRolloutFile(threadId) {
|
|
|
20666
21013
|
return null;
|
|
20667
21014
|
}
|
|
20668
21015
|
function findNewestClaudeCodeSession() {
|
|
20669
|
-
const root =
|
|
20670
|
-
if (!
|
|
21016
|
+
const root = join44(homedir23(), ".claude", "projects");
|
|
21017
|
+
if (!existsSync48(root))
|
|
20671
21018
|
return null;
|
|
20672
21019
|
let projectDirs;
|
|
20673
21020
|
try {
|
|
@@ -20677,7 +21024,7 @@ function findNewestClaudeCodeSession() {
|
|
|
20677
21024
|
}
|
|
20678
21025
|
let best = null;
|
|
20679
21026
|
for (const dir of projectDirs) {
|
|
20680
|
-
const projectPath =
|
|
21027
|
+
const projectPath = join44(root, dir);
|
|
20681
21028
|
let files;
|
|
20682
21029
|
try {
|
|
20683
21030
|
files = readdirSync13(projectPath);
|
|
@@ -20687,9 +21034,9 @@ function findNewestClaudeCodeSession() {
|
|
|
20687
21034
|
for (const file of files) {
|
|
20688
21035
|
if (!file.endsWith(".jsonl"))
|
|
20689
21036
|
continue;
|
|
20690
|
-
const full =
|
|
21037
|
+
const full = join44(projectPath, file);
|
|
20691
21038
|
try {
|
|
20692
|
-
const s =
|
|
21039
|
+
const s = statSync8(full);
|
|
20693
21040
|
if (!best || s.mtimeMs > best.mtime) {
|
|
20694
21041
|
best = {
|
|
20695
21042
|
sessionId: file.replace(/\.jsonl$/, ""),
|
|
@@ -20705,8 +21052,8 @@ function findNewestClaudeCodeSession() {
|
|
|
20705
21052
|
return best ? { sessionId: best.sessionId, path: best.path } : null;
|
|
20706
21053
|
}
|
|
20707
21054
|
function findNewestCodexRollout() {
|
|
20708
|
-
const root =
|
|
20709
|
-
if (!
|
|
21055
|
+
const root = join44(homedir23(), ".codex", "sessions");
|
|
21056
|
+
if (!existsSync48(root))
|
|
20710
21057
|
return null;
|
|
20711
21058
|
const stack = [root];
|
|
20712
21059
|
let best = null;
|
|
@@ -20719,10 +21066,10 @@ function findNewestCodexRollout() {
|
|
|
20719
21066
|
continue;
|
|
20720
21067
|
}
|
|
20721
21068
|
for (const entry of entries) {
|
|
20722
|
-
const full =
|
|
21069
|
+
const full = join44(dir, entry);
|
|
20723
21070
|
let s;
|
|
20724
21071
|
try {
|
|
20725
|
-
s =
|
|
21072
|
+
s = statSync8(full);
|
|
20726
21073
|
} catch {
|
|
20727
21074
|
continue;
|
|
20728
21075
|
}
|
|
@@ -20950,7 +21297,7 @@ var doctorCommand = new Command31("doctor").description("Check system health: au
|
|
|
20950
21297
|
init_store();
|
|
20951
21298
|
init_client();
|
|
20952
21299
|
import { Command as Command32 } from "commander";
|
|
20953
|
-
import { readFileSync as readFileSync40, existsSync as
|
|
21300
|
+
import { readFileSync as readFileSync40, existsSync as existsSync49 } from "fs";
|
|
20954
21301
|
import { createHash as createHash4 } from "crypto";
|
|
20955
21302
|
function nativeBundleFormatForAgent(slug) {
|
|
20956
21303
|
if (slug === "claude-code" || slug === "claude-desktop")
|
|
@@ -20971,7 +21318,7 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
|
|
|
20971
21318
|
console.error("Error: --transcript-file is required. Pass the path to the LLM-emitted markdown transcript.");
|
|
20972
21319
|
process.exit(1);
|
|
20973
21320
|
}
|
|
20974
|
-
if (!
|
|
21321
|
+
if (!existsSync49(opts.transcriptFile)) {
|
|
20975
21322
|
console.error(`Error: transcript file does not exist: ${opts.transcriptFile}`);
|
|
20976
21323
|
process.exit(1);
|
|
20977
21324
|
}
|
|
@@ -21005,12 +21352,12 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
|
|
|
21005
21352
|
const sourceAgent = opts.sourceAgent ?? detected?.slug ?? "generic";
|
|
21006
21353
|
let nativeFilePath = null;
|
|
21007
21354
|
if (opts.nativeFile) {
|
|
21008
|
-
if (!
|
|
21355
|
+
if (!existsSync49(opts.nativeFile)) {
|
|
21009
21356
|
console.error(`Error: --native-file path does not exist: ${opts.nativeFile}`);
|
|
21010
21357
|
process.exit(1);
|
|
21011
21358
|
}
|
|
21012
21359
|
nativeFilePath = opts.nativeFile;
|
|
21013
|
-
} else if (detected?.sessionFilePath &&
|
|
21360
|
+
} else if (detected?.sessionFilePath && existsSync49(detected.sessionFilePath)) {
|
|
21014
21361
|
nativeFilePath = detected.sessionFilePath;
|
|
21015
21362
|
}
|
|
21016
21363
|
if (nativeFilePath) {
|
|
@@ -21139,9 +21486,9 @@ Shared conversations (${scope}, ${total}):
|
|
|
21139
21486
|
init_store();
|
|
21140
21487
|
init_client();
|
|
21141
21488
|
import { Command as Command35 } from "commander";
|
|
21142
|
-
import { writeFileSync as
|
|
21489
|
+
import { writeFileSync as writeFileSync32, mkdirSync as mkdirSync29, realpathSync } from "fs";
|
|
21143
21490
|
import { homedir as homedir24 } from "os";
|
|
21144
|
-
import { join as
|
|
21491
|
+
import { join as join45 } from "path";
|
|
21145
21492
|
import { spawn as spawn5 } from "child_process";
|
|
21146
21493
|
function encodeClaudeCodeCwd(cwd) {
|
|
21147
21494
|
let canonical;
|
|
@@ -21178,10 +21525,10 @@ function extractCodexUuid(rolloutContent) {
|
|
|
21178
21525
|
}
|
|
21179
21526
|
function placeClaudeJsonl(uuid, content, recipientCwd) {
|
|
21180
21527
|
const encoded = encodeClaudeCodeCwd(recipientCwd);
|
|
21181
|
-
const projectDir =
|
|
21182
|
-
|
|
21183
|
-
const placedAt =
|
|
21184
|
-
|
|
21528
|
+
const projectDir = join45(homedir24(), ".claude", "projects", encoded);
|
|
21529
|
+
mkdirSync29(projectDir, { recursive: true });
|
|
21530
|
+
const placedAt = join45(projectDir, `${uuid}.jsonl`);
|
|
21531
|
+
writeFileSync32(placedAt, content);
|
|
21185
21532
|
return { placedAt, runFromCwd: recipientCwd };
|
|
21186
21533
|
}
|
|
21187
21534
|
function placeCodexRollout(uuid, content) {
|
|
@@ -21189,11 +21536,11 @@ function placeCodexRollout(uuid, content) {
|
|
|
21189
21536
|
const yyyy = String(now.getUTCFullYear());
|
|
21190
21537
|
const mm = String(now.getUTCMonth() + 1).padStart(2, "0");
|
|
21191
21538
|
const dd = String(now.getUTCDate()).padStart(2, "0");
|
|
21192
|
-
const dir =
|
|
21193
|
-
|
|
21539
|
+
const dir = join45(homedir24(), ".codex", "sessions", yyyy, mm, dd);
|
|
21540
|
+
mkdirSync29(dir, { recursive: true });
|
|
21194
21541
|
const ts = now.toISOString().replace(/\.\d+Z$/, "").replace(/:/g, "-");
|
|
21195
|
-
const placedAt =
|
|
21196
|
-
|
|
21542
|
+
const placedAt = join45(dir, `rollout-${ts}-${uuid}.jsonl`);
|
|
21543
|
+
writeFileSync32(placedAt, content);
|
|
21197
21544
|
return { placedAt };
|
|
21198
21545
|
}
|
|
21199
21546
|
function pickTargetAgent(opts, sourceAgent) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "runwork",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.1",
|
|
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)",
|