runwork 0.26.0 → 0.27.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js
CHANGED
|
@@ -427,6 +427,124 @@ function safeRm(path) {
|
|
|
427
427
|
var MAX_REDIRECTS = 10, transportOverride = "auto";
|
|
428
428
|
var init_http = () => {};
|
|
429
429
|
|
|
430
|
+
// ../../shared/utils/integration-body.ts
|
|
431
|
+
function findHeader(headers, name) {
|
|
432
|
+
if (!headers)
|
|
433
|
+
return;
|
|
434
|
+
const wanted = name.toLowerCase();
|
|
435
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
436
|
+
if (key.toLowerCase() === wanted)
|
|
437
|
+
return value;
|
|
438
|
+
}
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
function setHeader(headers, name, value) {
|
|
442
|
+
const wanted = name.toLowerCase();
|
|
443
|
+
const next = {};
|
|
444
|
+
for (const [key, existing] of Object.entries(headers)) {
|
|
445
|
+
if (key.toLowerCase() !== wanted)
|
|
446
|
+
next[key] = existing;
|
|
447
|
+
}
|
|
448
|
+
next[name] = value;
|
|
449
|
+
return next;
|
|
450
|
+
}
|
|
451
|
+
function mediaType(contentType) {
|
|
452
|
+
return (contentType ?? "").split(";")[0].trim().toLowerCase();
|
|
453
|
+
}
|
|
454
|
+
function isJsonContentType(contentType) {
|
|
455
|
+
const type = mediaType(contentType);
|
|
456
|
+
return type === JSON_CONTENT_TYPE || type.endsWith("+json");
|
|
457
|
+
}
|
|
458
|
+
function isFormContentType(contentType) {
|
|
459
|
+
return mediaType(contentType) === FORM_CONTENT_TYPE;
|
|
460
|
+
}
|
|
461
|
+
function isMultipartContentType(contentType) {
|
|
462
|
+
return mediaType(contentType) === "multipart/form-data";
|
|
463
|
+
}
|
|
464
|
+
function appendFormValue(out, key, value) {
|
|
465
|
+
if (value === undefined)
|
|
466
|
+
return;
|
|
467
|
+
if (value === null) {
|
|
468
|
+
out.append(key, "");
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
if (Array.isArray(value)) {
|
|
472
|
+
value.forEach((item, index) => appendFormValue(out, `${key}[${index}]`, item));
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
if (typeof value === "object") {
|
|
476
|
+
for (const [childKey, childValue] of Object.entries(value)) {
|
|
477
|
+
appendFormValue(out, `${key}[${childKey}]`, childValue);
|
|
478
|
+
}
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
out.append(key, String(value));
|
|
482
|
+
}
|
|
483
|
+
function encodeFormBody(value) {
|
|
484
|
+
if (typeof value === "string")
|
|
485
|
+
return value;
|
|
486
|
+
if (value === undefined || value === null)
|
|
487
|
+
return "";
|
|
488
|
+
const out = new URLSearchParams;
|
|
489
|
+
if (Array.isArray(value) || typeof value === "object") {
|
|
490
|
+
for (const [key, child] of Object.entries(value)) {
|
|
491
|
+
appendFormValue(out, key, child);
|
|
492
|
+
}
|
|
493
|
+
} else {
|
|
494
|
+
out.append("value", String(value));
|
|
495
|
+
}
|
|
496
|
+
return out.toString();
|
|
497
|
+
}
|
|
498
|
+
function looksLikeJson(text) {
|
|
499
|
+
const trimmed = text.trim();
|
|
500
|
+
if (!(trimmed.startsWith("{") || trimmed.startsWith("[")))
|
|
501
|
+
return false;
|
|
502
|
+
try {
|
|
503
|
+
JSON.parse(trimmed);
|
|
504
|
+
return true;
|
|
505
|
+
} catch {
|
|
506
|
+
return false;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
function encodeIntegrationBody(body, contentType) {
|
|
510
|
+
if (body === undefined || body === null) {
|
|
511
|
+
return { body: undefined, contentType };
|
|
512
|
+
}
|
|
513
|
+
if (isMultipartContentType(contentType)) {
|
|
514
|
+
throw new Error("multipart/form-data bodies are not supported by the integrations proxy. Send application/x-www-form-urlencoded or JSON instead.");
|
|
515
|
+
}
|
|
516
|
+
if (typeof body === "string") {
|
|
517
|
+
if (contentType)
|
|
518
|
+
return { body, contentType };
|
|
519
|
+
return { body, contentType: looksLikeJson(body) ? JSON_CONTENT_TYPE : TEXT_CONTENT_TYPE };
|
|
520
|
+
}
|
|
521
|
+
if (isFormContentType(contentType)) {
|
|
522
|
+
return { body: encodeFormBody(body), contentType };
|
|
523
|
+
}
|
|
524
|
+
return { body: JSON.stringify(body), contentType: contentType ?? JSON_CONTENT_TYPE };
|
|
525
|
+
}
|
|
526
|
+
function encodeIntegrationRequest(body, headers = {}) {
|
|
527
|
+
const encoded = encodeIntegrationBody(body, findHeader(headers, "Content-Type"));
|
|
528
|
+
if (encoded.body === undefined) {
|
|
529
|
+
return { body: undefined, headers };
|
|
530
|
+
}
|
|
531
|
+
return {
|
|
532
|
+
body: encoded.body,
|
|
533
|
+
headers: setHeader(headers, "Content-Type", encoded.contentType ?? JSON_CONTENT_TYPE)
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
function parseBodyArgument(text, contentType) {
|
|
537
|
+
try {
|
|
538
|
+
return JSON.parse(text);
|
|
539
|
+
} catch {
|
|
540
|
+
if (contentType && !isJsonContentType(contentType)) {
|
|
541
|
+
return text;
|
|
542
|
+
}
|
|
543
|
+
throw new Error('Body is not valid JSON. To send a raw or form-encoded body, set a matching Content-Type header (for example --header "Content-Type: application/x-www-form-urlencoded").');
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
var JSON_CONTENT_TYPE = "application/json", FORM_CONTENT_TYPE = "application/x-www-form-urlencoded", TEXT_CONTENT_TYPE = "text/plain; charset=utf-8";
|
|
547
|
+
|
|
430
548
|
// src/api/client.ts
|
|
431
549
|
class ApiClient {
|
|
432
550
|
baseUrl;
|
|
@@ -868,22 +986,22 @@ class ApiClient {
|
|
|
868
986
|
return res.data;
|
|
869
987
|
}
|
|
870
988
|
async callIntegrationProxy(integrationDbId, method, path, opts) {
|
|
871
|
-
const targetPath = opts?.query ? `${path}
|
|
989
|
+
const targetPath = opts?.query ? `${path}${path.includes("?") ? "&" : "?"}${opts.query}` : path;
|
|
872
990
|
const url = `${this.baseUrl}/api/proxy/integrations${targetPath}`;
|
|
873
|
-
const
|
|
991
|
+
const upperMethod = method.toUpperCase();
|
|
992
|
+
const hasBody = opts?.body !== undefined && opts?.body !== null && upperMethod !== "GET" && upperMethod !== "HEAD";
|
|
993
|
+
const encoded = encodeIntegrationRequest(hasBody ? opts?.body : undefined, {
|
|
874
994
|
"X-Workspace-Integration-Id": integrationDbId,
|
|
875
|
-
...
|
|
876
|
-
};
|
|
995
|
+
...opts?.headers || {}
|
|
996
|
+
});
|
|
997
|
+
const headers = encoded.headers;
|
|
877
998
|
if (this.apiKey) {
|
|
878
999
|
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
879
1000
|
}
|
|
880
|
-
if (opts?.body) {
|
|
881
|
-
headers["Content-Type"] = "application/json";
|
|
882
|
-
}
|
|
883
1001
|
const response = await httpFetch(url, {
|
|
884
|
-
method,
|
|
1002
|
+
method: upperMethod,
|
|
885
1003
|
headers,
|
|
886
|
-
body:
|
|
1004
|
+
body: encoded.body
|
|
887
1005
|
});
|
|
888
1006
|
if (!response.ok) {
|
|
889
1007
|
const body = await response.text();
|
|
@@ -6212,6 +6330,16 @@ export declare class WorkflowInstanceDO extends DurableObject<Env> {
|
|
|
6212
6330
|
* - Creates WorkflowInstance DOs
|
|
6213
6331
|
* - Maintains an index for querying workflows
|
|
6214
6332
|
* - Routes signals to correct instances
|
|
6333
|
+
*
|
|
6334
|
+
* Index storage: one storage key per instance entry (\`index:<instanceId>\`),
|
|
6335
|
+
* read back with a prefix list. A single-value index hits the 2 MB per-value
|
|
6336
|
+
* limit of SQLite-backed DO storage at roughly 11,000 entries, after which every
|
|
6337
|
+
* write fails with SQLITE_TOOBIG. Apps deployed before the per-key layout still
|
|
6338
|
+
* hold the legacy \`workflow_index\` value; it is migrated on first load.
|
|
6339
|
+
*
|
|
6340
|
+
* Retention: terminal entries older than the retention window are pruned from
|
|
6341
|
+
* a self-armed alarm, and the index is trimmed inline when a write pushes it
|
|
6342
|
+
* past the entry cap, so the index stays bounded without an external caller.
|
|
6215
6343
|
*/
|
|
6216
6344
|
import { DurableObject } from 'cloudflare:workers';
|
|
6217
6345
|
import type { NativeWorkflowStatus, NativeWorkflowConfig, ListWorkflowsOptions, WorkflowInstanceInfo, WorkflowInstanceStub } from './core-workflow-types';
|
|
@@ -6225,8 +6353,14 @@ import { type Env } from './core-utils';
|
|
|
6225
6353
|
*/
|
|
6226
6354
|
export declare class WorkflowCoordinator extends DurableObject<Env> {
|
|
6227
6355
|
private index;
|
|
6356
|
+
/** Entry cap applied inline on writes and by the retention alarm. */
|
|
6357
|
+
readonly retentionMaxEntries = 10000;
|
|
6228
6358
|
/**
|
|
6229
|
-
* Create a new workflow instance
|
|
6359
|
+
* Create a new workflow instance.
|
|
6360
|
+
*
|
|
6361
|
+
* The index entry and stored params are written before the instance starts,
|
|
6362
|
+
* so a completion notification from a fast workflow can never race ahead of
|
|
6363
|
+
* its own pending entry, and an index failure surfaces before any work runs.
|
|
6230
6364
|
*/
|
|
6231
6365
|
create(workflowName: string, params: Record<string, unknown>, config?: Partial<NativeWorkflowConfig>, metadata?: Record<string, unknown>): Promise<string>;
|
|
6232
6366
|
/**
|
|
@@ -6271,16 +6405,38 @@ export declare class WorkflowCoordinator extends DurableObject<Env> {
|
|
|
6271
6405
|
byWorkflow: Record<string, number>;
|
|
6272
6406
|
}>;
|
|
6273
6407
|
/**
|
|
6274
|
-
* Clean up completed/old workflow entries
|
|
6275
|
-
*
|
|
6408
|
+
* Clean up completed/old workflow entries.
|
|
6409
|
+
*
|
|
6410
|
+
* Removes terminal entries older than \`olderThanMs\`, every completed entry
|
|
6411
|
+
* unless \`keepCompleted\` is set, and then the oldest terminal entries until
|
|
6412
|
+
* the index fits within \`maxEntries\`. Active entries (pending, running,
|
|
6413
|
+
* sleeping, waiting, paused) are never removed. Runs from the retention alarm
|
|
6414
|
+
* and inline on writes; explicit calls remain supported.
|
|
6276
6415
|
*/
|
|
6277
6416
|
cleanup(options?: {
|
|
6278
6417
|
olderThanMs?: number;
|
|
6279
6418
|
keepCompleted?: boolean;
|
|
6280
6419
|
maxEntries?: number;
|
|
6281
6420
|
}): Promise<number>;
|
|
6421
|
+
/**
|
|
6422
|
+
* Retention alarm: prune old terminal entries and re-arm while the index
|
|
6423
|
+
* still holds anything.
|
|
6424
|
+
*/
|
|
6425
|
+
alarm(): Promise<void>;
|
|
6282
6426
|
private ensureIndexLoaded;
|
|
6283
|
-
|
|
6427
|
+
/**
|
|
6428
|
+
* Move a legacy single-value index into per-entry keys. Per-entry values
|
|
6429
|
+
* already present win, since they were written after the legacy value.
|
|
6430
|
+
* An unreadable legacy value is dropped: the workflow instances themselves
|
|
6431
|
+
* still hold their state, only the listing loses history.
|
|
6432
|
+
*/
|
|
6433
|
+
private migrateLegacyIndex;
|
|
6434
|
+
private deleteLegacyIndexKey;
|
|
6435
|
+
/**
|
|
6436
|
+
* Remove index entries and their stored params, in storage batches.
|
|
6437
|
+
*/
|
|
6438
|
+
private removeEntries;
|
|
6439
|
+
private ensureRetentionAlarm;
|
|
6284
6440
|
}
|
|
6285
6441
|
`,
|
|
6286
6442
|
"core-integration-entities.d.ts": `/**
|
|
@@ -7962,14 +8118,17 @@ export declare const integrationApiSchema: z.ZodObject<{
|
|
|
7962
8118
|
method: z.ZodDefault<z.ZodEnum<["GET", "POST", "PUT", "PATCH", "DELETE"]>>;
|
|
7963
8119
|
endpoint: z.ZodString;
|
|
7964
8120
|
data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
8121
|
+
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
7965
8122
|
}, "strip", z.ZodTypeAny, {
|
|
7966
8123
|
endpoint: string;
|
|
7967
8124
|
method: "POST" | "GET" | "PUT" | "PATCH" | "DELETE";
|
|
7968
8125
|
data?: Record<string, unknown> | undefined;
|
|
8126
|
+
headers?: Record<string, string> | undefined;
|
|
7969
8127
|
}, {
|
|
7970
8128
|
endpoint: string;
|
|
7971
8129
|
data?: Record<string, unknown> | undefined;
|
|
7972
8130
|
method?: "POST" | "GET" | "PUT" | "PATCH" | "DELETE" | undefined;
|
|
8131
|
+
headers?: Record<string, string> | undefined;
|
|
7973
8132
|
}>;
|
|
7974
8133
|
/**
|
|
7975
8134
|
* Get tool definitions for integration access
|
|
@@ -8205,7 +8364,7 @@ function createKeyboardListener() {
|
|
|
8205
8364
|
}
|
|
8206
8365
|
|
|
8207
8366
|
// src/generated/version.ts
|
|
8208
|
-
var VERSION = "0.
|
|
8367
|
+
var VERSION = "0.27.1";
|
|
8209
8368
|
|
|
8210
8369
|
// src/commands/dev.ts
|
|
8211
8370
|
var exports_dev = {};
|
|
@@ -9184,6 +9343,14 @@ function expandWindowsPathTemplate(path2, resolved) {
|
|
|
9184
9343
|
}
|
|
9185
9344
|
return { path: path2, needsHomeJoin: !/^([A-Za-z]:[\\/]|\\\\|\/)/.test(path2) };
|
|
9186
9345
|
}
|
|
9346
|
+
function parseConfigDeclaredPath(text2, key) {
|
|
9347
|
+
const escapedKey = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
9348
|
+
const match = new RegExp(`^\\s*${escapedKey}\\s*=\\s*"((?:[^"\\\\]|\\\\.)*)"`, "m").exec(text2);
|
|
9349
|
+
if (!match)
|
|
9350
|
+
return null;
|
|
9351
|
+
const path2 = match[1].replace(/\\(.)/g, "$1");
|
|
9352
|
+
return path2 || null;
|
|
9353
|
+
}
|
|
9187
9354
|
var PATH_REFRESH_FAILED_MARKER = "__runwork_path_refresh_failed__", WINDOWS_PATH_REFRESH, COMMAND_NOT_FOUND_EXIT_CODES, WINDOWS_PATH_PLACEHOLDERS;
|
|
9188
9355
|
var init_detection_probes = __esm(() => {
|
|
9189
9356
|
WINDOWS_PATH_REFRESH = "try { $env:Path = [Environment]::GetEnvironmentVariable('Path','Machine') + ';' + " + "[Environment]::GetEnvironmentVariable('Path','User') + ';' + $env:Path } " + `catch { Write-Output '${PATH_REFRESH_FAILED_MARKER}' }; `;
|
|
@@ -9605,6 +9772,9 @@ function getAgent(slug) {
|
|
|
9605
9772
|
function getAgents() {
|
|
9606
9773
|
return AGENT_REGISTRY;
|
|
9607
9774
|
}
|
|
9775
|
+
function getDetectableAgents() {
|
|
9776
|
+
return AGENT_REGISTRY.filter((a) => a.detection);
|
|
9777
|
+
}
|
|
9608
9778
|
function isConnectOnlyAgent(agent) {
|
|
9609
9779
|
if (!agent)
|
|
9610
9780
|
return false;
|
|
@@ -9633,11 +9803,15 @@ function resolveAgentCli(agent) {
|
|
|
9633
9803
|
return;
|
|
9634
9804
|
return detectionBinaryTarget(agent.detection);
|
|
9635
9805
|
}
|
|
9636
|
-
var CLAUDE_CODE_NATIVE_INSTALL_PATHS, CHATGPT_SECURITY_SETTINGS_URL = "https://chatgpt.com/plugins#settings/Security", CHATGPT_CREATE_CONNECTOR_URL = "https://chatgpt.com/plugins#settings/Connectors?create-connector=true&redirectAfter=%2Fplugins", AGENT_REGISTRY, slugIndex, nameIndex, CUSTOM_ADAPTER_SLUGS, getRegistryAgent, getRegistryAgents;
|
|
9806
|
+
var CLAUDE_CODE_NATIVE_INSTALL_PATHS, CODEX_CONFIG_FILE = ".codex/config.toml", CODEX_BUNDLED_CLI_PATHS, CHATGPT_SECURITY_SETTINGS_URL = "https://chatgpt.com/plugins#settings/Security", CHATGPT_CREATE_CONNECTOR_URL = "https://chatgpt.com/plugins#settings/Connectors?create-connector=true&redirectAfter=%2Fplugins", AGENT_REGISTRY, slugIndex, nameIndex, CUSTOM_ADAPTER_SLUGS, getRegistryAgent, getRegistryAgents;
|
|
9637
9807
|
var init_registry_data = __esm(() => {
|
|
9638
9808
|
CLAUDE_CODE_NATIVE_INSTALL_PATHS = [
|
|
9639
9809
|
{ macos: ".local/bin/claude", linux: ".local/bin/claude", windows: ".local/bin/claude.exe" }
|
|
9640
9810
|
];
|
|
9811
|
+
CODEX_BUNDLED_CLI_PATHS = [
|
|
9812
|
+
{ macos: "/Applications/ChatGPT.app/Contents/Resources/codex" },
|
|
9813
|
+
{ macos: "/Applications/Codex.app/Contents/Resources/codex" }
|
|
9814
|
+
];
|
|
9641
9815
|
AGENT_REGISTRY = [
|
|
9642
9816
|
{
|
|
9643
9817
|
slug: "claude-code",
|
|
@@ -9869,8 +10043,18 @@ var init_registry_data = __esm(() => {
|
|
|
9869
10043
|
name: "Codex CLI",
|
|
9870
10044
|
description: "AI in your terminal by OpenAI, great for coding, debugging, and automating dev tasks",
|
|
9871
10045
|
category: "cli",
|
|
9872
|
-
detection: {
|
|
9873
|
-
|
|
10046
|
+
detection: {
|
|
10047
|
+
method: "any",
|
|
10048
|
+
target: [
|
|
10049
|
+
{ method: "binary", target: "codex" },
|
|
10050
|
+
{
|
|
10051
|
+
method: "config-value",
|
|
10052
|
+
target: { file: CODEX_CONFIG_FILE, key: "CODEX_CLI_PATH" }
|
|
10053
|
+
},
|
|
10054
|
+
...CODEX_BUNDLED_CLI_PATHS.map((target) => ({ method: "path", target }))
|
|
10055
|
+
]
|
|
10056
|
+
},
|
|
10057
|
+
launch: { cli: "codex", cliAcceptsPrompt: true, cliWellKnownPaths: CODEX_BUNDLED_CLI_PATHS },
|
|
9874
10058
|
logo: "codex",
|
|
9875
10059
|
downloadUrl: "https://learn.chatgpt.com/docs/codex/cli",
|
|
9876
10060
|
install: {
|
|
@@ -9907,6 +10091,7 @@ var init_registry_data = __esm(() => {
|
|
|
9907
10091
|
launch: { url: "https://chatgpt.com/?prompt={prompt}" },
|
|
9908
10092
|
logo: "openai",
|
|
9909
10093
|
downloadUrl: "https://chatgpt.com",
|
|
10094
|
+
suggestsCli: "codex",
|
|
9910
10095
|
firstClass: true,
|
|
9911
10096
|
resumeCapability: {
|
|
9912
10097
|
mode: "url-prompt",
|
|
@@ -9963,6 +10148,7 @@ var init_registry_data = __esm(() => {
|
|
|
9963
10148
|
]
|
|
9964
10149
|
},
|
|
9965
10150
|
launch: { app: { macos: "ChatGPT Classic", windows: "ChatGPT Classic" }, bundleId: { macos: "com.openai.chat" }, appxPackage: "OpenAI.ChatGPT", url: "https://chatgpt.com/?prompt={prompt}" },
|
|
10151
|
+
suggestsCli: "codex",
|
|
9966
10152
|
logo: "openai",
|
|
9967
10153
|
downloadUrl: "https://chatgpt.com/download",
|
|
9968
10154
|
downloadUrls: {
|
|
@@ -10208,12 +10394,145 @@ var init_registry_data = __esm(() => {
|
|
|
10208
10394
|
getRegistryAgents = getAgents;
|
|
10209
10395
|
});
|
|
10210
10396
|
|
|
10397
|
+
// src/agents/detection.ts
|
|
10398
|
+
import { execFile } from "child_process";
|
|
10399
|
+
import { existsSync as existsSync26, readFileSync as readFileSync23 } from "fs";
|
|
10400
|
+
import { homedir as homedir6, platform as platform2 } from "os";
|
|
10401
|
+
import { join as join22 } from "path";
|
|
10402
|
+
import { promisify } from "util";
|
|
10403
|
+
function isWindows() {
|
|
10404
|
+
return platform2() === "win32";
|
|
10405
|
+
}
|
|
10406
|
+
function toList(value) {
|
|
10407
|
+
return Array.isArray(value) ? value : [value];
|
|
10408
|
+
}
|
|
10409
|
+
async function runPowerShell(script) {
|
|
10410
|
+
const execFileAsync = promisify(execFile);
|
|
10411
|
+
try {
|
|
10412
|
+
await execFileAsync("powershell", ["-NoProfile", "-Command", script]);
|
|
10413
|
+
return true;
|
|
10414
|
+
} catch {
|
|
10415
|
+
return false;
|
|
10416
|
+
}
|
|
10417
|
+
}
|
|
10418
|
+
function resolveDetectionPath(target) {
|
|
10419
|
+
const resolved = resolvePlatformString(target);
|
|
10420
|
+
if (!resolved)
|
|
10421
|
+
return null;
|
|
10422
|
+
const expanded = expandWindowsPathTemplate(resolved, {
|
|
10423
|
+
"%APPDATA%": process.env.APPDATA,
|
|
10424
|
+
"%LOCALAPPDATA%": process.env.LOCALAPPDATA,
|
|
10425
|
+
"%ProgramFiles%": process.env.ProgramFiles
|
|
10426
|
+
});
|
|
10427
|
+
return expanded.needsHomeJoin ? join22(homedir6(), expanded.path) : expanded.path;
|
|
10428
|
+
}
|
|
10429
|
+
function checkPath(target) {
|
|
10430
|
+
const absolute = resolveDetectionPath(target);
|
|
10431
|
+
if (!absolute)
|
|
10432
|
+
return null;
|
|
10433
|
+
return existsSync26(absolute) ? absolute : null;
|
|
10434
|
+
}
|
|
10435
|
+
function checkConfigDeclaredPath(target) {
|
|
10436
|
+
const configPath = resolveDetectionPath(target.file);
|
|
10437
|
+
if (!configPath)
|
|
10438
|
+
return null;
|
|
10439
|
+
let text2;
|
|
10440
|
+
try {
|
|
10441
|
+
if (!existsSync26(configPath))
|
|
10442
|
+
return null;
|
|
10443
|
+
text2 = readFileSync23(configPath, "utf-8");
|
|
10444
|
+
} catch {
|
|
10445
|
+
return null;
|
|
10446
|
+
}
|
|
10447
|
+
const declared = parseConfigDeclaredPath(text2, target.key);
|
|
10448
|
+
return declared && existsSync26(declared) ? declared : null;
|
|
10449
|
+
}
|
|
10450
|
+
async function checkMacosBundleId(target) {
|
|
10451
|
+
if (platform2() !== "darwin")
|
|
10452
|
+
return false;
|
|
10453
|
+
const execFileAsync = promisify(execFile);
|
|
10454
|
+
for (const id of toList(target)) {
|
|
10455
|
+
if (!isValidBundleId(id))
|
|
10456
|
+
continue;
|
|
10457
|
+
try {
|
|
10458
|
+
await execFileAsync("sh", ["-c", macosBundleIdProbeScript(id)]);
|
|
10459
|
+
return true;
|
|
10460
|
+
} catch {}
|
|
10461
|
+
}
|
|
10462
|
+
return false;
|
|
10463
|
+
}
|
|
10464
|
+
async function checkWindowsAppxPackage(target) {
|
|
10465
|
+
if (!isWindows())
|
|
10466
|
+
return false;
|
|
10467
|
+
const probes = toList(target).map((pkg) => runPowerShell(appxPackageProbeScript(pkg)));
|
|
10468
|
+
const results = await Promise.all(probes);
|
|
10469
|
+
return results.some(Boolean);
|
|
10470
|
+
}
|
|
10471
|
+
async function checkWindowsStartApp(target) {
|
|
10472
|
+
if (!isWindows())
|
|
10473
|
+
return false;
|
|
10474
|
+
const probes = toList(target).map((pattern) => runPowerShell(startAppProbeScript(pattern)));
|
|
10475
|
+
const results = await Promise.all(probes);
|
|
10476
|
+
return results.some(Boolean);
|
|
10477
|
+
}
|
|
10478
|
+
async function runAgentDetectionDetailed(detection) {
|
|
10479
|
+
switch (detection.method) {
|
|
10480
|
+
case "binary": {
|
|
10481
|
+
const target = resolvePlatformString(detection.target);
|
|
10482
|
+
const resolved = target ? whichBinary(target) : null;
|
|
10483
|
+
return resolved ? { detected: true, via: "binary", resolvedPath: resolved } : NOT_DETECTED;
|
|
10484
|
+
}
|
|
10485
|
+
case "path": {
|
|
10486
|
+
const resolved = checkPath(detection.target);
|
|
10487
|
+
return resolved ? { detected: true, via: "path", resolvedPath: resolved } : NOT_DETECTED;
|
|
10488
|
+
}
|
|
10489
|
+
case "config-value": {
|
|
10490
|
+
const resolved = checkConfigDeclaredPath(detection.target);
|
|
10491
|
+
return resolved ? { detected: true, via: "config-value", resolvedPath: resolved } : NOT_DETECTED;
|
|
10492
|
+
}
|
|
10493
|
+
case "windows-appx":
|
|
10494
|
+
return await checkWindowsAppxPackage(detection.target) ? { detected: true, via: "windows-appx" } : NOT_DETECTED;
|
|
10495
|
+
case "windows-start-app":
|
|
10496
|
+
return await checkWindowsStartApp(detection.target) ? { detected: true, via: "windows-start-app" } : NOT_DETECTED;
|
|
10497
|
+
case "macos-bundle-id":
|
|
10498
|
+
return await checkMacosBundleId(detection.target) ? { detected: true, via: "macos-bundle-id" } : NOT_DETECTED;
|
|
10499
|
+
case "any": {
|
|
10500
|
+
const probes = await Promise.all(detection.target.map((p) => runAgentDetectionDetailed(p)));
|
|
10501
|
+
return probes.find((p) => p.detected) ?? NOT_DETECTED;
|
|
10502
|
+
}
|
|
10503
|
+
case "always":
|
|
10504
|
+
return { detected: true, via: "always" };
|
|
10505
|
+
default:
|
|
10506
|
+
return NOT_DETECTED;
|
|
10507
|
+
}
|
|
10508
|
+
}
|
|
10509
|
+
async function runAgentDetection(detection) {
|
|
10510
|
+
return (await runAgentDetectionDetailed(detection)).detected;
|
|
10511
|
+
}
|
|
10512
|
+
|
|
10513
|
+
class RegistryDetectedAdapter {
|
|
10514
|
+
async detect() {
|
|
10515
|
+
const def = getRegistryAgent(this.slug);
|
|
10516
|
+
if (!def)
|
|
10517
|
+
return false;
|
|
10518
|
+
return runAgentDetection(def.detection);
|
|
10519
|
+
}
|
|
10520
|
+
}
|
|
10521
|
+
var NOT_DETECTED;
|
|
10522
|
+
var init_detection = __esm(() => {
|
|
10523
|
+
init_which();
|
|
10524
|
+
init_registry_data();
|
|
10525
|
+
init_registry();
|
|
10526
|
+
init_detection_probes();
|
|
10527
|
+
NOT_DETECTED = { detected: false };
|
|
10528
|
+
});
|
|
10529
|
+
|
|
10211
10530
|
// src/agents/registry.ts
|
|
10212
|
-
import { platform as
|
|
10213
|
-
import { isAbsolute as
|
|
10214
|
-
import { existsSync as
|
|
10531
|
+
import { platform as platform3, homedir as homedir7 } from "os";
|
|
10532
|
+
import { isAbsolute as isAbsolute3, join as join23 } from "path";
|
|
10533
|
+
import { existsSync as existsSync27 } from "fs";
|
|
10215
10534
|
function getNodePlatform() {
|
|
10216
|
-
const p =
|
|
10535
|
+
const p = platform3();
|
|
10217
10536
|
if (p === "darwin")
|
|
10218
10537
|
return "macos";
|
|
10219
10538
|
if (p === "win32")
|
|
@@ -10230,7 +10549,7 @@ function resolveToAbsolute(ps, scope) {
|
|
|
10230
10549
|
const resolved = resolvePlatformString(ps);
|
|
10231
10550
|
if (!resolved)
|
|
10232
10551
|
return;
|
|
10233
|
-
return scope === "global" ?
|
|
10552
|
+
return scope === "global" ? join23(homedir7(), resolved) : join23(process.cwd(), resolved);
|
|
10234
10553
|
}
|
|
10235
10554
|
function resolveAgentCliCommand(slug) {
|
|
10236
10555
|
const agent = getAgent(slug);
|
|
@@ -10239,19 +10558,40 @@ function resolveAgentCliCommand(slug) {
|
|
|
10239
10558
|
return null;
|
|
10240
10559
|
if (whichBinary(cli))
|
|
10241
10560
|
return cli;
|
|
10561
|
+
const declared = vendorDeclaredCliPath(slug);
|
|
10562
|
+
if (declared)
|
|
10563
|
+
return declared;
|
|
10242
10564
|
for (const candidate of agent?.launch?.cliWellKnownPaths ?? []) {
|
|
10243
10565
|
const resolved = resolvePlatformString(candidate);
|
|
10244
10566
|
if (!resolved)
|
|
10245
10567
|
continue;
|
|
10246
|
-
const absolute =
|
|
10247
|
-
if (
|
|
10568
|
+
const absolute = isAbsolute3(resolved) ? resolved : join23(homedir7(), resolved);
|
|
10569
|
+
if (existsSync27(absolute))
|
|
10248
10570
|
return absolute;
|
|
10249
10571
|
}
|
|
10250
10572
|
return null;
|
|
10251
10573
|
}
|
|
10574
|
+
function configValueMatchers(detection) {
|
|
10575
|
+
if (!detection)
|
|
10576
|
+
return [];
|
|
10577
|
+
if (detection.method === "config-value")
|
|
10578
|
+
return [detection.target];
|
|
10579
|
+
if (detection.method === "any")
|
|
10580
|
+
return detection.target.flatMap(configValueMatchers);
|
|
10581
|
+
return [];
|
|
10582
|
+
}
|
|
10583
|
+
function vendorDeclaredCliPath(slug) {
|
|
10584
|
+
for (const matcher of configValueMatchers(getAgent(slug)?.detection)) {
|
|
10585
|
+
const resolved = checkConfigDeclaredPath(matcher);
|
|
10586
|
+
if (resolved)
|
|
10587
|
+
return resolved;
|
|
10588
|
+
}
|
|
10589
|
+
return null;
|
|
10590
|
+
}
|
|
10252
10591
|
var init_registry = __esm(() => {
|
|
10253
10592
|
init_which();
|
|
10254
10593
|
init_registry_data();
|
|
10594
|
+
init_detection();
|
|
10255
10595
|
init_registry_data();
|
|
10256
10596
|
});
|
|
10257
10597
|
|
|
@@ -11092,6 +11432,8 @@ function scanClaudeJsonlHead(head) {
|
|
|
11092
11432
|
result.firstTimestamp = o.timestamp;
|
|
11093
11433
|
if (!result.cwd && typeof o.cwd === "string")
|
|
11094
11434
|
result.cwd = o.cwd;
|
|
11435
|
+
if (!result.surface && typeof o.entrypoint === "string")
|
|
11436
|
+
result.surface = o.entrypoint;
|
|
11095
11437
|
if (!result.title && o.type === "ai-title" && typeof o.aiTitle === "string") {
|
|
11096
11438
|
result.title = titleFromText(o.aiTitle);
|
|
11097
11439
|
}
|
|
@@ -11117,7 +11459,7 @@ function scanClaudeJsonlHead(head) {
|
|
|
11117
11459
|
}
|
|
11118
11460
|
}
|
|
11119
11461
|
}
|
|
11120
|
-
if (result.title && result.firstTimestamp && result.cwd)
|
|
11462
|
+
if (result.title && result.firstTimestamp && result.cwd && result.surface)
|
|
11121
11463
|
break;
|
|
11122
11464
|
}
|
|
11123
11465
|
if (!result.title && firstUserText)
|
|
@@ -11146,6 +11488,8 @@ function scanCodexRolloutHead(head) {
|
|
|
11146
11488
|
result.cwd = p.cwd;
|
|
11147
11489
|
if (typeof p.id === "string" && !result.sessionId)
|
|
11148
11490
|
result.sessionId = p.id;
|
|
11491
|
+
if (typeof p.originator === "string" && !result.surface)
|
|
11492
|
+
result.surface = p.originator;
|
|
11149
11493
|
}
|
|
11150
11494
|
if (!result.title && o.type === "response_item" && p.type === "message" && p.role === "user" && Array.isArray(p.content)) {
|
|
11151
11495
|
for (const item of p.content) {
|
|
@@ -11245,23 +11589,23 @@ function skillNameFromPath(path2) {
|
|
|
11245
11589
|
}
|
|
11246
11590
|
|
|
11247
11591
|
// src/utils/trash.ts
|
|
11248
|
-
import { cpSync, existsSync as
|
|
11249
|
-
import { basename as basename2, dirname as dirname6, join as
|
|
11250
|
-
import { homedir as
|
|
11592
|
+
import { cpSync, existsSync as existsSync28, mkdirSync as mkdirSync13, readdirSync as readdirSync5, renameSync as renameSync3, rmSync as rmSync4, statSync as statSync3 } from "fs";
|
|
11593
|
+
import { basename as basename2, dirname as dirname6, join as join24 } from "path";
|
|
11594
|
+
import { homedir as homedir8 } from "os";
|
|
11251
11595
|
function trashRoot() {
|
|
11252
|
-
return
|
|
11596
|
+
return join24(homedir8(), ".runwork", "trash");
|
|
11253
11597
|
}
|
|
11254
11598
|
function batchDir(now) {
|
|
11255
11599
|
const stamp = now.toISOString().replace(/[:.]/g, "-");
|
|
11256
|
-
return
|
|
11600
|
+
return join24(trashRoot(), `${stamp}-${process.pid}`);
|
|
11257
11601
|
}
|
|
11258
11602
|
function pruneTrash(now = new Date) {
|
|
11259
11603
|
const root = trashRoot();
|
|
11260
|
-
if (!
|
|
11604
|
+
if (!existsSync28(root))
|
|
11261
11605
|
return;
|
|
11262
11606
|
const cutoff = now.getTime() - TRASH_RETENTION_DAYS * 24 * 60 * 60 * 1000;
|
|
11263
11607
|
for (const entry of readdirSync5(root)) {
|
|
11264
|
-
const dir =
|
|
11608
|
+
const dir = join24(root, entry);
|
|
11265
11609
|
try {
|
|
11266
11610
|
if (statSync3(dir).mtimeMs < cutoff)
|
|
11267
11611
|
rmSync4(dir, { recursive: true, force: true });
|
|
@@ -11269,7 +11613,7 @@ function pruneTrash(now = new Date) {
|
|
|
11269
11613
|
}
|
|
11270
11614
|
}
|
|
11271
11615
|
function moveToTrash(sourcePath, reason, now = new Date) {
|
|
11272
|
-
if (!
|
|
11616
|
+
if (!existsSync28(sourcePath))
|
|
11273
11617
|
return null;
|
|
11274
11618
|
if (!activeBatch || !activeBatch.startsWith(trashRoot())) {
|
|
11275
11619
|
activeBatch = batchDir(now);
|
|
@@ -11277,8 +11621,8 @@ function moveToTrash(sourcePath, reason, now = new Date) {
|
|
|
11277
11621
|
}
|
|
11278
11622
|
const parent = basename2(dirname6(sourcePath));
|
|
11279
11623
|
const grandparent = basename2(dirname6(dirname6(sourcePath)));
|
|
11280
|
-
const destDir =
|
|
11281
|
-
const dest =
|
|
11624
|
+
const destDir = join24(activeBatch, `${grandparent}__${parent}`.replace(/[^a-zA-Z0-9._-]/g, "-"));
|
|
11625
|
+
const dest = join24(destDir, basename2(sourcePath));
|
|
11282
11626
|
try {
|
|
11283
11627
|
mkdirSync13(destDir, { recursive: true });
|
|
11284
11628
|
try {
|
|
@@ -11290,7 +11634,7 @@ function moveToTrash(sourcePath, reason, now = new Date) {
|
|
|
11290
11634
|
} catch {
|
|
11291
11635
|
return null;
|
|
11292
11636
|
}
|
|
11293
|
-
const manifestPath =
|
|
11637
|
+
const manifestPath = join24(activeBatch, "manifest.json");
|
|
11294
11638
|
const manifest = readJsonOrNull(manifestPath) ?? { entries: [] };
|
|
11295
11639
|
manifest.entries.push({ from: sourcePath, to: dest, reason, at: now.toISOString() });
|
|
11296
11640
|
try {
|
|
@@ -11333,27 +11677,27 @@ function configHash(value) {
|
|
|
11333
11677
|
var init_hash = () => {};
|
|
11334
11678
|
|
|
11335
11679
|
// src/agents/utils/json-config.ts
|
|
11336
|
-
import { readFileSync as
|
|
11680
|
+
import { readFileSync as readFileSync24, writeFileSync as writeFileSync14, mkdirSync as mkdirSync14, existsSync as existsSync29 } from "fs";
|
|
11337
11681
|
import { dirname as dirname7 } from "path";
|
|
11338
11682
|
function isRunworkManagedKey(key) {
|
|
11339
11683
|
return key === RUNWORK_WORKSPACE_MCP_NAME || key.startsWith(RUNWORK_MCP_PREFIX) || key.startsWith(RUNWORK_MCP_PREFIX_LEGACY);
|
|
11340
11684
|
}
|
|
11341
11685
|
function readJsonConfig(filePath) {
|
|
11342
|
-
if (!
|
|
11686
|
+
if (!existsSync29(filePath))
|
|
11343
11687
|
return {};
|
|
11344
11688
|
try {
|
|
11345
|
-
return JSON.parse(
|
|
11689
|
+
return JSON.parse(readFileSync24(filePath, "utf-8"));
|
|
11346
11690
|
} catch (err) {
|
|
11347
11691
|
console.warn(` [config] ${filePath} is not valid JSON: ${err instanceof Error ? err.message : err}`);
|
|
11348
11692
|
return {};
|
|
11349
11693
|
}
|
|
11350
11694
|
}
|
|
11351
11695
|
function existingContentIsUnparseable(filePath) {
|
|
11352
|
-
if (!
|
|
11696
|
+
if (!existsSync29(filePath))
|
|
11353
11697
|
return { bad: false };
|
|
11354
11698
|
let raw;
|
|
11355
11699
|
try {
|
|
11356
|
-
raw =
|
|
11700
|
+
raw = readFileSync24(filePath, "utf-8");
|
|
11357
11701
|
} catch {
|
|
11358
11702
|
return { bad: false };
|
|
11359
11703
|
}
|
|
@@ -11375,7 +11719,7 @@ function writeJsonConfig(filePath, config) {
|
|
|
11375
11719
|
`);
|
|
11376
11720
|
}
|
|
11377
11721
|
function removeRunworkMcpServers(filePath, topKey) {
|
|
11378
|
-
if (!
|
|
11722
|
+
if (!existsSync29(filePath))
|
|
11379
11723
|
return false;
|
|
11380
11724
|
const config = readJsonConfig(filePath);
|
|
11381
11725
|
const existing = config[topKey] || {};
|
|
@@ -11430,25 +11774,25 @@ var init_json_config = __esm(() => {
|
|
|
11430
11774
|
});
|
|
11431
11775
|
|
|
11432
11776
|
// src/agents/utils/skill-removal.ts
|
|
11433
|
-
import { existsSync as
|
|
11434
|
-
import { join as
|
|
11777
|
+
import { existsSync as existsSync30, readdirSync as readdirSync6 } from "fs";
|
|
11778
|
+
import { join as join25 } from "path";
|
|
11435
11779
|
function removeMatchingSkillDirs(dir, allowed, reason = "skill removed") {
|
|
11436
|
-
if (!allowed.size || !
|
|
11780
|
+
if (!allowed.size || !existsSync30(dir))
|
|
11437
11781
|
return;
|
|
11438
11782
|
for (const entry of readdirSync6(dir)) {
|
|
11439
11783
|
if (!allowed.has(entry))
|
|
11440
11784
|
continue;
|
|
11441
|
-
moveToTrash(
|
|
11785
|
+
moveToTrash(join25(dir, entry), reason);
|
|
11442
11786
|
}
|
|
11443
11787
|
}
|
|
11444
11788
|
function removeMatchingSkillFiles(dir, allowed, suffix, reason = "skill removed") {
|
|
11445
|
-
if (!allowed.size || !
|
|
11789
|
+
if (!allowed.size || !existsSync30(dir))
|
|
11446
11790
|
return;
|
|
11447
11791
|
const names = new Set([...allowed].map((slug) => `${slug}${suffix}`));
|
|
11448
11792
|
for (const entry of readdirSync6(dir)) {
|
|
11449
11793
|
if (!names.has(entry))
|
|
11450
11794
|
continue;
|
|
11451
|
-
moveToTrash(
|
|
11795
|
+
moveToTrash(join25(dir, entry), reason);
|
|
11452
11796
|
}
|
|
11453
11797
|
}
|
|
11454
11798
|
var init_skill_removal = __esm(() => {
|
|
@@ -11456,7 +11800,7 @@ var init_skill_removal = __esm(() => {
|
|
|
11456
11800
|
});
|
|
11457
11801
|
|
|
11458
11802
|
// src/agents/utils/instruction-hint.ts
|
|
11459
|
-
import { existsSync as
|
|
11803
|
+
import { existsSync as existsSync31, readFileSync as readFileSync25, writeFileSync as writeFileSync15, mkdirSync as mkdirSync15 } from "fs";
|
|
11460
11804
|
import { dirname as dirname8 } from "path";
|
|
11461
11805
|
function writeHintToFile(filePath, hint) {
|
|
11462
11806
|
mkdirSync15(dirname8(filePath), { recursive: true });
|
|
@@ -11466,8 +11810,8 @@ ${hint}
|
|
|
11466
11810
|
${END_MARKER}`;
|
|
11467
11811
|
}
|
|
11468
11812
|
let content = "";
|
|
11469
|
-
if (
|
|
11470
|
-
content =
|
|
11813
|
+
if (existsSync31(filePath)) {
|
|
11814
|
+
content = readFileSync25(filePath, "utf-8");
|
|
11471
11815
|
}
|
|
11472
11816
|
const startIdx = content.indexOf(START_MARKER);
|
|
11473
11817
|
const endIdx = content.indexOf(END_MARKER);
|
|
@@ -11489,9 +11833,9 @@ ${END_MARKER}`;
|
|
|
11489
11833
|
writeFileSync15(filePath, content);
|
|
11490
11834
|
}
|
|
11491
11835
|
function removeHintFromFile(filePath) {
|
|
11492
|
-
if (!
|
|
11836
|
+
if (!existsSync31(filePath))
|
|
11493
11837
|
return false;
|
|
11494
|
-
let content =
|
|
11838
|
+
let content = readFileSync25(filePath, "utf-8");
|
|
11495
11839
|
const startIdx = content.indexOf(START_MARKER);
|
|
11496
11840
|
const endIdx = content.indexOf(END_MARKER);
|
|
11497
11841
|
if (startIdx < 0 || endIdx < 0)
|
|
@@ -11509,9 +11853,9 @@ function removeHintFromFile(filePath) {
|
|
|
11509
11853
|
return true;
|
|
11510
11854
|
}
|
|
11511
11855
|
function removeTeamInstructionsFromFile(filePath) {
|
|
11512
|
-
if (!
|
|
11856
|
+
if (!existsSync31(filePath))
|
|
11513
11857
|
return false;
|
|
11514
|
-
let content =
|
|
11858
|
+
let content = readFileSync25(filePath, "utf-8");
|
|
11515
11859
|
const startIdx = content.indexOf(TEAM_START_MARKER);
|
|
11516
11860
|
const endIdx = content.indexOf(TEAM_END_MARKER);
|
|
11517
11861
|
if (startIdx < 0 || endIdx < 0)
|
|
@@ -11531,8 +11875,8 @@ function removeTeamInstructionsFromFile(filePath) {
|
|
|
11531
11875
|
function writeTeamInstructionsToFile(filePath, instructions) {
|
|
11532
11876
|
mkdirSync15(dirname8(filePath), { recursive: true });
|
|
11533
11877
|
let content = "";
|
|
11534
|
-
if (
|
|
11535
|
-
content =
|
|
11878
|
+
if (existsSync31(filePath)) {
|
|
11879
|
+
content = readFileSync25(filePath, "utf-8");
|
|
11536
11880
|
}
|
|
11537
11881
|
const block = `${TEAM_START_MARKER}
|
|
11538
11882
|
${instructions}
|
|
@@ -11981,120 +12325,6 @@ function vlog(...args) {
|
|
|
11981
12325
|
}
|
|
11982
12326
|
var verbose = false;
|
|
11983
12327
|
|
|
11984
|
-
// src/agents/detection.ts
|
|
11985
|
-
import { execFile } from "child_process";
|
|
11986
|
-
import { existsSync as existsSync31 } from "fs";
|
|
11987
|
-
import { homedir as homedir8, platform as platform3 } from "os";
|
|
11988
|
-
import { join as join25 } from "path";
|
|
11989
|
-
import { promisify } from "util";
|
|
11990
|
-
function isWindows() {
|
|
11991
|
-
return platform3() === "win32";
|
|
11992
|
-
}
|
|
11993
|
-
function toList(value) {
|
|
11994
|
-
return Array.isArray(value) ? value : [value];
|
|
11995
|
-
}
|
|
11996
|
-
async function runPowerShell(script) {
|
|
11997
|
-
const execFileAsync = promisify(execFile);
|
|
11998
|
-
try {
|
|
11999
|
-
await execFileAsync("powershell", ["-NoProfile", "-Command", script]);
|
|
12000
|
-
return true;
|
|
12001
|
-
} catch {
|
|
12002
|
-
return false;
|
|
12003
|
-
}
|
|
12004
|
-
}
|
|
12005
|
-
function resolveDetectionPath(target) {
|
|
12006
|
-
const resolved = resolvePlatformString(target);
|
|
12007
|
-
if (!resolved)
|
|
12008
|
-
return null;
|
|
12009
|
-
const expanded = expandWindowsPathTemplate(resolved, {
|
|
12010
|
-
"%APPDATA%": process.env.APPDATA,
|
|
12011
|
-
"%LOCALAPPDATA%": process.env.LOCALAPPDATA,
|
|
12012
|
-
"%ProgramFiles%": process.env.ProgramFiles
|
|
12013
|
-
});
|
|
12014
|
-
return expanded.needsHomeJoin ? join25(homedir8(), expanded.path) : expanded.path;
|
|
12015
|
-
}
|
|
12016
|
-
function checkPath(target) {
|
|
12017
|
-
const absolute = resolveDetectionPath(target);
|
|
12018
|
-
if (!absolute)
|
|
12019
|
-
return null;
|
|
12020
|
-
return existsSync31(absolute) ? absolute : null;
|
|
12021
|
-
}
|
|
12022
|
-
async function checkMacosBundleId(target) {
|
|
12023
|
-
if (platform3() !== "darwin")
|
|
12024
|
-
return false;
|
|
12025
|
-
const execFileAsync = promisify(execFile);
|
|
12026
|
-
for (const id of toList(target)) {
|
|
12027
|
-
if (!isValidBundleId(id))
|
|
12028
|
-
continue;
|
|
12029
|
-
try {
|
|
12030
|
-
await execFileAsync("sh", ["-c", macosBundleIdProbeScript(id)]);
|
|
12031
|
-
return true;
|
|
12032
|
-
} catch {}
|
|
12033
|
-
}
|
|
12034
|
-
return false;
|
|
12035
|
-
}
|
|
12036
|
-
async function checkWindowsAppxPackage(target) {
|
|
12037
|
-
if (!isWindows())
|
|
12038
|
-
return false;
|
|
12039
|
-
const probes = toList(target).map((pkg) => runPowerShell(appxPackageProbeScript(pkg)));
|
|
12040
|
-
const results = await Promise.all(probes);
|
|
12041
|
-
return results.some(Boolean);
|
|
12042
|
-
}
|
|
12043
|
-
async function checkWindowsStartApp(target) {
|
|
12044
|
-
if (!isWindows())
|
|
12045
|
-
return false;
|
|
12046
|
-
const probes = toList(target).map((pattern) => runPowerShell(startAppProbeScript(pattern)));
|
|
12047
|
-
const results = await Promise.all(probes);
|
|
12048
|
-
return results.some(Boolean);
|
|
12049
|
-
}
|
|
12050
|
-
async function runAgentDetectionDetailed(detection) {
|
|
12051
|
-
switch (detection.method) {
|
|
12052
|
-
case "binary": {
|
|
12053
|
-
const target = resolvePlatformString(detection.target);
|
|
12054
|
-
const resolved = target ? whichBinary(target) : null;
|
|
12055
|
-
return resolved ? { detected: true, via: "binary", resolvedPath: resolved } : NOT_DETECTED;
|
|
12056
|
-
}
|
|
12057
|
-
case "path": {
|
|
12058
|
-
const resolved = checkPath(detection.target);
|
|
12059
|
-
return resolved ? { detected: true, via: "path", resolvedPath: resolved } : NOT_DETECTED;
|
|
12060
|
-
}
|
|
12061
|
-
case "windows-appx":
|
|
12062
|
-
return await checkWindowsAppxPackage(detection.target) ? { detected: true, via: "windows-appx" } : NOT_DETECTED;
|
|
12063
|
-
case "windows-start-app":
|
|
12064
|
-
return await checkWindowsStartApp(detection.target) ? { detected: true, via: "windows-start-app" } : NOT_DETECTED;
|
|
12065
|
-
case "macos-bundle-id":
|
|
12066
|
-
return await checkMacosBundleId(detection.target) ? { detected: true, via: "macos-bundle-id" } : NOT_DETECTED;
|
|
12067
|
-
case "any": {
|
|
12068
|
-
const probes = await Promise.all(detection.target.map((p) => runAgentDetectionDetailed(p)));
|
|
12069
|
-
return probes.find((p) => p.detected) ?? NOT_DETECTED;
|
|
12070
|
-
}
|
|
12071
|
-
case "always":
|
|
12072
|
-
return { detected: true, via: "always" };
|
|
12073
|
-
default:
|
|
12074
|
-
return NOT_DETECTED;
|
|
12075
|
-
}
|
|
12076
|
-
}
|
|
12077
|
-
async function runAgentDetection(detection) {
|
|
12078
|
-
return (await runAgentDetectionDetailed(detection)).detected;
|
|
12079
|
-
}
|
|
12080
|
-
|
|
12081
|
-
class RegistryDetectedAdapter {
|
|
12082
|
-
async detect() {
|
|
12083
|
-
const def = getRegistryAgent(this.slug);
|
|
12084
|
-
if (!def)
|
|
12085
|
-
return false;
|
|
12086
|
-
return runAgentDetection(def.detection);
|
|
12087
|
-
}
|
|
12088
|
-
}
|
|
12089
|
-
var NOT_DETECTED;
|
|
12090
|
-
var init_detection = __esm(() => {
|
|
12091
|
-
init_which();
|
|
12092
|
-
init_registry_data();
|
|
12093
|
-
init_registry();
|
|
12094
|
-
init_detection_probes();
|
|
12095
|
-
NOT_DETECTED = { detected: false };
|
|
12096
|
-
});
|
|
12097
|
-
|
|
12098
12328
|
// src/agents/transcript-sources.ts
|
|
12099
12329
|
import { accessSync, constants, statSync as statSync4 } from "fs";
|
|
12100
12330
|
function classifyFsErrorCode(code) {
|
|
@@ -12158,7 +12388,7 @@ function summarizeTranscriptSources(sources) {
|
|
|
12158
12388
|
var init_transcript_sources = () => {};
|
|
12159
12389
|
|
|
12160
12390
|
// src/agents/claude-code.ts
|
|
12161
|
-
import { chmodSync, existsSync as existsSync32, mkdirSync as mkdirSync16, readFileSync as
|
|
12391
|
+
import { chmodSync, existsSync as existsSync32, mkdirSync as mkdirSync16, readFileSync as readFileSync26, readdirSync as readdirSync7, rmSync as rmSync5, statSync as statSync5, writeFileSync as writeFileSync16 } from "fs";
|
|
12162
12392
|
import { join as join26 } from "path";
|
|
12163
12393
|
import { homedir as homedir9 } from "os";
|
|
12164
12394
|
function getPluginJson() {
|
|
@@ -12349,7 +12579,7 @@ ${instructions}`;
|
|
|
12349
12579
|
let settings = {};
|
|
12350
12580
|
if (hadFile) {
|
|
12351
12581
|
try {
|
|
12352
|
-
settings = JSON.parse(
|
|
12582
|
+
settings = JSON.parse(readFileSync26(settingsPath, "utf-8"));
|
|
12353
12583
|
} catch {}
|
|
12354
12584
|
}
|
|
12355
12585
|
if (settings.permissions && typeof settings.permissions === "object") {
|
|
@@ -12410,7 +12640,7 @@ ${instructions}`;
|
|
|
12410
12640
|
const settingsPath = join26(homedir9(), ".claude", "settings.json");
|
|
12411
12641
|
if (existsSync32(settingsPath)) {
|
|
12412
12642
|
try {
|
|
12413
|
-
const settings = JSON.parse(
|
|
12643
|
+
const settings = JSON.parse(readFileSync26(settingsPath, "utf-8"));
|
|
12414
12644
|
if (settings.permissions) {
|
|
12415
12645
|
for (const key of ["allow", "deny"]) {
|
|
12416
12646
|
const arr = settings.permissions[key];
|
|
@@ -12508,7 +12738,7 @@ ${instructions}`;
|
|
|
12508
12738
|
continue;
|
|
12509
12739
|
let content;
|
|
12510
12740
|
try {
|
|
12511
|
-
content =
|
|
12741
|
+
content = readFileSync26(filePath, "utf-8");
|
|
12512
12742
|
} catch {
|
|
12513
12743
|
continue;
|
|
12514
12744
|
}
|
|
@@ -12633,7 +12863,7 @@ ${instructions}`;
|
|
|
12633
12863
|
continue;
|
|
12634
12864
|
let content;
|
|
12635
12865
|
try {
|
|
12636
|
-
content =
|
|
12866
|
+
content = readFileSync26(filePath, "utf-8");
|
|
12637
12867
|
} catch {
|
|
12638
12868
|
continue;
|
|
12639
12869
|
}
|
|
@@ -12689,7 +12919,7 @@ ${instructions}`;
|
|
|
12689
12919
|
const sessionId = file.slice(0, -".jsonl".length);
|
|
12690
12920
|
let endedAt = null;
|
|
12691
12921
|
try {
|
|
12692
|
-
const stamp = JSON.parse(
|
|
12922
|
+
const stamp = JSON.parse(readFileSync26(join26(homedir9(), ".runwork", "sessions", `${sessionId}.ended.json`), "utf-8"));
|
|
12693
12923
|
if (stamp && typeof stamp.endedAt === "string")
|
|
12694
12924
|
endedAt = stamp.endedAt;
|
|
12695
12925
|
} catch {}
|
|
@@ -12701,7 +12931,8 @@ ${instructions}`;
|
|
|
12701
12931
|
startedAt: scanned.firstTimestamp,
|
|
12702
12932
|
lastActivityAt: resolveLastActivity(filePath, stat.mtimeMs),
|
|
12703
12933
|
endedAt,
|
|
12704
|
-
transcriptPath: filePath
|
|
12934
|
+
transcriptPath: filePath,
|
|
12935
|
+
surface: scanned.surface ?? null
|
|
12705
12936
|
});
|
|
12706
12937
|
}
|
|
12707
12938
|
}
|
|
@@ -12755,7 +12986,7 @@ ${instructions}`;
|
|
|
12755
12986
|
continue;
|
|
12756
12987
|
let content;
|
|
12757
12988
|
try {
|
|
12758
|
-
content =
|
|
12989
|
+
content = readFileSync26(filePath, "utf-8");
|
|
12759
12990
|
} catch {
|
|
12760
12991
|
continue;
|
|
12761
12992
|
}
|
|
@@ -13003,7 +13234,7 @@ var init_claude_desktop_plugin_tree = __esm(() => {
|
|
|
13003
13234
|
});
|
|
13004
13235
|
|
|
13005
13236
|
// src/agents/claude-desktop.ts
|
|
13006
|
-
import { existsSync as existsSync34, mkdtempSync as mkdtempSync3, readdirSync as readdirSync8, readFileSync as
|
|
13237
|
+
import { existsSync as existsSync34, mkdtempSync as mkdtempSync3, readdirSync as readdirSync8, readFileSync as readFileSync27, rmSync as rmSync7, statSync as statSync6, writeFileSync as writeFileSync18, mkdirSync as mkdirSync18 } from "fs";
|
|
13007
13238
|
import { dirname as dirname9, join as join28 } from "path";
|
|
13008
13239
|
import { homedir as homedir10, platform as platform4, tmpdir as tmpdir3 } from "os";
|
|
13009
13240
|
function isRunworkRpmPluginName(name) {
|
|
@@ -13122,7 +13353,7 @@ function findRpmPluginByName(pluginName) {
|
|
|
13122
13353
|
if (!existsSync34(manifestPath))
|
|
13123
13354
|
return null;
|
|
13124
13355
|
try {
|
|
13125
|
-
const manifest = JSON.parse(
|
|
13356
|
+
const manifest = JSON.parse(readFileSync27(manifestPath, "utf-8"));
|
|
13126
13357
|
const entry = manifest.plugins?.find((p) => p.name === pluginName);
|
|
13127
13358
|
if (!entry?.id)
|
|
13128
13359
|
return null;
|
|
@@ -13303,7 +13534,7 @@ var init_claude_desktop = __esm(() => {
|
|
|
13303
13534
|
let desktopConfig = {};
|
|
13304
13535
|
if (existsSync34(configPath)) {
|
|
13305
13536
|
try {
|
|
13306
|
-
desktopConfig = JSON.parse(
|
|
13537
|
+
desktopConfig = JSON.parse(readFileSync27(configPath, "utf-8"));
|
|
13307
13538
|
} catch {}
|
|
13308
13539
|
}
|
|
13309
13540
|
if (!desktopConfig.preferences)
|
|
@@ -13342,7 +13573,7 @@ var init_claude_desktop = __esm(() => {
|
|
|
13342
13573
|
if (!existsSync34(manifestPath))
|
|
13343
13574
|
continue;
|
|
13344
13575
|
try {
|
|
13345
|
-
const manifest = JSON.parse(
|
|
13576
|
+
const manifest = JSON.parse(readFileSync27(manifestPath, "utf-8"));
|
|
13346
13577
|
if (!Array.isArray(manifest.plugins))
|
|
13347
13578
|
continue;
|
|
13348
13579
|
const ours = manifest.plugins.filter((p) => isRunworkRpmPluginName(p.name));
|
|
@@ -13444,7 +13675,7 @@ var init_claude_desktop = __esm(() => {
|
|
|
13444
13675
|
continue;
|
|
13445
13676
|
let content;
|
|
13446
13677
|
try {
|
|
13447
|
-
content =
|
|
13678
|
+
content = readFileSync27(filePath, "utf-8");
|
|
13448
13679
|
} catch {
|
|
13449
13680
|
continue;
|
|
13450
13681
|
}
|
|
@@ -13484,7 +13715,7 @@ var init_claude_desktop = __esm(() => {
|
|
|
13484
13715
|
const metaPath = join28(orgPath, entry);
|
|
13485
13716
|
let meta;
|
|
13486
13717
|
try {
|
|
13487
|
-
meta = JSON.parse(
|
|
13718
|
+
meta = JSON.parse(readFileSync27(metaPath, "utf-8"));
|
|
13488
13719
|
} catch {
|
|
13489
13720
|
continue;
|
|
13490
13721
|
}
|
|
@@ -13520,7 +13751,8 @@ var init_claude_desktop = __esm(() => {
|
|
|
13520
13751
|
title: typeof meta.title === "string" && meta.title ? meta.title : null,
|
|
13521
13752
|
startedAt: typeof meta.createdAt === "number" ? new Date(meta.createdAt).toISOString() : null,
|
|
13522
13753
|
lastActivityAt: new Date(lastActivityMs).toISOString(),
|
|
13523
|
-
transcriptPath
|
|
13754
|
+
transcriptPath,
|
|
13755
|
+
surface: "local-agent"
|
|
13524
13756
|
});
|
|
13525
13757
|
}
|
|
13526
13758
|
}
|
|
@@ -13586,7 +13818,7 @@ var init_claude_desktop = __esm(() => {
|
|
|
13586
13818
|
const scheduledTasksPath = join28(claudeAppDir, "scheduled-tasks.json");
|
|
13587
13819
|
if (existsSync34(scheduledTasksPath)) {
|
|
13588
13820
|
try {
|
|
13589
|
-
const raw =
|
|
13821
|
+
const raw = readFileSync27(scheduledTasksPath, "utf-8");
|
|
13590
13822
|
const parsed = JSON.parse(raw);
|
|
13591
13823
|
const tasks = Array.isArray(parsed) ? parsed : Object.values(parsed);
|
|
13592
13824
|
for (const task of tasks) {
|
|
@@ -13630,7 +13862,7 @@ var init_claude_desktop = __esm(() => {
|
|
|
13630
13862
|
}
|
|
13631
13863
|
const versionPath = join28(claudeAppDir, "claude-code", "sdk-version");
|
|
13632
13864
|
if (existsSync34(versionPath)) {
|
|
13633
|
-
return
|
|
13865
|
+
return readFileSync27(versionPath, "utf-8").trim();
|
|
13634
13866
|
}
|
|
13635
13867
|
return null;
|
|
13636
13868
|
} catch {
|
|
@@ -13663,7 +13895,7 @@ var init_claude_desktop = __esm(() => {
|
|
|
13663
13895
|
if (!file.endsWith(".json"))
|
|
13664
13896
|
continue;
|
|
13665
13897
|
try {
|
|
13666
|
-
const session = JSON.parse(
|
|
13898
|
+
const session = JSON.parse(readFileSync27(join28(userPath, file), "utf-8"));
|
|
13667
13899
|
onSession(session);
|
|
13668
13900
|
} catch {
|
|
13669
13901
|
continue;
|
|
@@ -14207,7 +14439,7 @@ ${hint}`;
|
|
|
14207
14439
|
});
|
|
14208
14440
|
|
|
14209
14441
|
// src/agents/codex.ts
|
|
14210
|
-
import { existsSync as existsSync37, mkdirSync as mkdirSync21, readdirSync as readdirSync11, readFileSync as
|
|
14442
|
+
import { existsSync as existsSync37, mkdirSync as mkdirSync21, readdirSync as readdirSync11, readFileSync as readFileSync28, statSync as statSync7, writeFileSync as writeFileSync21 } from "fs";
|
|
14211
14443
|
import { basename as basename3, join as join31 } from "path";
|
|
14212
14444
|
import { homedir as homedir13 } from "os";
|
|
14213
14445
|
import { parse, stringify } from "smol-toml";
|
|
@@ -14240,7 +14472,7 @@ var init_codex = __esm(async () => {
|
|
|
14240
14472
|
const configPath = join31(homedir13(), ".codex", "config.toml");
|
|
14241
14473
|
let parsed = {};
|
|
14242
14474
|
if (existsSync37(configPath)) {
|
|
14243
|
-
parsed = parse(
|
|
14475
|
+
parsed = parse(readFileSync28(configPath, "utf-8"));
|
|
14244
14476
|
}
|
|
14245
14477
|
if (!parsed.mcp_servers || typeof parsed.mcp_servers !== "object") {
|
|
14246
14478
|
parsed.mcp_servers = {};
|
|
@@ -14295,7 +14527,7 @@ var init_codex = __esm(async () => {
|
|
|
14295
14527
|
const configPath = scope === "project" ? join31(process.cwd(), ".codex", "config.toml") : join31(homedir13(), ".codex", "config.toml");
|
|
14296
14528
|
let parsed = {};
|
|
14297
14529
|
if (existsSync37(configPath)) {
|
|
14298
|
-
parsed = parse(
|
|
14530
|
+
parsed = parse(readFileSync28(configPath, "utf-8"));
|
|
14299
14531
|
}
|
|
14300
14532
|
if (config.modelPreference) {
|
|
14301
14533
|
parsed.model = config.modelPreference;
|
|
@@ -14354,7 +14586,7 @@ var init_codex = __esm(async () => {
|
|
|
14354
14586
|
const configPath = join31(homedir13(), ".codex", "config.toml");
|
|
14355
14587
|
if (existsSync37(configPath)) {
|
|
14356
14588
|
try {
|
|
14357
|
-
const parsed = parse(
|
|
14589
|
+
const parsed = parse(readFileSync28(configPath, "utf-8"));
|
|
14358
14590
|
if (parsed.mcp_servers && typeof parsed.mcp_servers === "object") {
|
|
14359
14591
|
const mcpServers = parsed.mcp_servers;
|
|
14360
14592
|
for (const key of Object.keys(mcpServers)) {
|
|
@@ -14403,7 +14635,7 @@ var init_codex = __esm(async () => {
|
|
|
14403
14635
|
if (messageCount === 0) {
|
|
14404
14636
|
const historyPath = join31(codexDir, "history.jsonl");
|
|
14405
14637
|
if (existsSync37(historyPath)) {
|
|
14406
|
-
const content =
|
|
14638
|
+
const content = readFileSync28(historyPath, "utf-8").trim();
|
|
14407
14639
|
if (content) {
|
|
14408
14640
|
for (const line of content.split(/[\r\n]+/)) {
|
|
14409
14641
|
try {
|
|
@@ -14483,7 +14715,7 @@ var init_codex = __esm(async () => {
|
|
|
14483
14715
|
continue;
|
|
14484
14716
|
let content;
|
|
14485
14717
|
try {
|
|
14486
|
-
content =
|
|
14718
|
+
content = readFileSync28(file, "utf-8");
|
|
14487
14719
|
} catch {
|
|
14488
14720
|
continue;
|
|
14489
14721
|
}
|
|
@@ -14575,7 +14807,7 @@ var init_codex = __esm(async () => {
|
|
|
14575
14807
|
continue;
|
|
14576
14808
|
let content;
|
|
14577
14809
|
try {
|
|
14578
|
-
content =
|
|
14810
|
+
content = readFileSync28(file, "utf-8");
|
|
14579
14811
|
} catch {
|
|
14580
14812
|
continue;
|
|
14581
14813
|
}
|
|
@@ -14634,7 +14866,8 @@ var init_codex = __esm(async () => {
|
|
|
14634
14866
|
title: scanned.title,
|
|
14635
14867
|
startedAt: scanned.firstTimestamp,
|
|
14636
14868
|
lastActivityAt: resolveLastActivity(file, stat.mtimeMs),
|
|
14637
|
-
transcriptPath: file
|
|
14869
|
+
transcriptPath: file,
|
|
14870
|
+
surface: scanned.surface ?? null
|
|
14638
14871
|
});
|
|
14639
14872
|
}
|
|
14640
14873
|
return sessions;
|
|
@@ -14646,7 +14879,7 @@ var init_codex = __esm(async () => {
|
|
|
14646
14879
|
try {
|
|
14647
14880
|
const versionPath = join31(homedir13(), ".codex", "version.json");
|
|
14648
14881
|
if (existsSync37(versionPath)) {
|
|
14649
|
-
const data = JSON.parse(
|
|
14882
|
+
const data = JSON.parse(readFileSync28(versionPath, "utf-8"));
|
|
14650
14883
|
return data.latest_version ?? null;
|
|
14651
14884
|
}
|
|
14652
14885
|
} catch {}
|
|
@@ -14707,7 +14940,7 @@ var init_codex = __esm(async () => {
|
|
|
14707
14940
|
parseRolloutForSkills(filePath, sinceMs, skillCounts) {
|
|
14708
14941
|
let content;
|
|
14709
14942
|
try {
|
|
14710
|
-
content =
|
|
14943
|
+
content = readFileSync28(filePath, "utf-8");
|
|
14711
14944
|
} catch {
|
|
14712
14945
|
return;
|
|
14713
14946
|
}
|
|
@@ -14760,7 +14993,7 @@ var init_codex = __esm(async () => {
|
|
|
14760
14993
|
let state = {};
|
|
14761
14994
|
if (existsSync37(statePath)) {
|
|
14762
14995
|
try {
|
|
14763
|
-
state = JSON.parse(
|
|
14996
|
+
state = JSON.parse(readFileSync28(statePath, "utf-8"));
|
|
14764
14997
|
} catch {
|
|
14765
14998
|
return "app_running";
|
|
14766
14999
|
}
|
|
@@ -14795,23 +15028,11 @@ var init_codex = __esm(async () => {
|
|
|
14795
15028
|
CodexDesktopAdapter = class CodexDesktopAdapter extends CodexAdapter {
|
|
14796
15029
|
name = "Codex";
|
|
14797
15030
|
slug = "codex-app";
|
|
14798
|
-
async readUsageStats() {
|
|
14799
|
-
return null;
|
|
14800
|
-
}
|
|
14801
|
-
async listSessions() {
|
|
14802
|
-
return null;
|
|
14803
|
-
}
|
|
14804
|
-
async readSessionDigests() {
|
|
14805
|
-
return null;
|
|
14806
|
-
}
|
|
14807
|
-
transcriptSources() {
|
|
14808
|
-
return [];
|
|
14809
|
-
}
|
|
14810
15031
|
};
|
|
14811
15032
|
});
|
|
14812
15033
|
|
|
14813
15034
|
// src/agents/cline.ts
|
|
14814
|
-
import { existsSync as existsSync38, mkdirSync as mkdirSync22, readFileSync as
|
|
15035
|
+
import { existsSync as existsSync38, mkdirSync as mkdirSync22, readFileSync as readFileSync29, readdirSync as readdirSync12, rmSync as rmSync10, unlinkSync as unlinkSync6, writeFileSync as writeFileSync22 } from "fs";
|
|
14815
15036
|
import { join as join32 } from "path";
|
|
14816
15037
|
import { homedir as homedir14 } from "os";
|
|
14817
15038
|
var ClineAdapter;
|
|
@@ -14872,7 +15093,7 @@ var init_cline = __esm(() => {
|
|
|
14872
15093
|
let state = {};
|
|
14873
15094
|
if (existsSync38(globalStatePath)) {
|
|
14874
15095
|
try {
|
|
14875
|
-
state = JSON.parse(
|
|
15096
|
+
state = JSON.parse(readFileSync29(globalStatePath, "utf-8"));
|
|
14876
15097
|
} catch {}
|
|
14877
15098
|
}
|
|
14878
15099
|
if (config.modelPreference) {
|
|
@@ -14929,7 +15150,7 @@ var init_cline = __esm(() => {
|
|
|
14929
15150
|
});
|
|
14930
15151
|
|
|
14931
15152
|
// src/agents/gemini.ts
|
|
14932
|
-
import { existsSync as existsSync39, mkdirSync as mkdirSync23, readdirSync as readdirSync13, readFileSync as
|
|
15153
|
+
import { existsSync as existsSync39, mkdirSync as mkdirSync23, readdirSync as readdirSync13, readFileSync as readFileSync30, statSync as statSync8, writeFileSync as writeFileSync23 } from "fs";
|
|
14933
15154
|
import { basename as basename4, join as join33 } from "path";
|
|
14934
15155
|
import { homedir as homedir15 } from "os";
|
|
14935
15156
|
var GeminiAdapter;
|
|
@@ -14989,7 +15210,7 @@ var init_gemini = __esm(() => {
|
|
|
14989
15210
|
let settings = {};
|
|
14990
15211
|
if (existsSync39(settingsPath)) {
|
|
14991
15212
|
try {
|
|
14992
|
-
settings = JSON.parse(
|
|
15213
|
+
settings = JSON.parse(readFileSync30(settingsPath, "utf-8"));
|
|
14993
15214
|
} catch {}
|
|
14994
15215
|
}
|
|
14995
15216
|
if (config.modelPreference) {
|
|
@@ -15050,7 +15271,7 @@ var init_gemini = __esm(() => {
|
|
|
15050
15271
|
continue;
|
|
15051
15272
|
let session;
|
|
15052
15273
|
try {
|
|
15053
|
-
session = JSON.parse(
|
|
15274
|
+
session = JSON.parse(readFileSync30(filePath, "utf-8"));
|
|
15054
15275
|
} catch {
|
|
15055
15276
|
continue;
|
|
15056
15277
|
}
|
|
@@ -15141,7 +15362,7 @@ var init_gemini = __esm(() => {
|
|
|
15141
15362
|
for (const { filePath, project, mtimeMs } of this.chatFiles(sinceMs)) {
|
|
15142
15363
|
let session;
|
|
15143
15364
|
try {
|
|
15144
|
-
session = JSON.parse(
|
|
15365
|
+
session = JSON.parse(readFileSync30(filePath, "utf-8"));
|
|
15145
15366
|
} catch {
|
|
15146
15367
|
continue;
|
|
15147
15368
|
}
|
|
@@ -15182,7 +15403,7 @@ var init_gemini = __esm(() => {
|
|
|
15182
15403
|
for (const { filePath, project } of this.chatFiles(sinceMs)) {
|
|
15183
15404
|
let content;
|
|
15184
15405
|
try {
|
|
15185
|
-
content =
|
|
15406
|
+
content = readFileSync30(filePath, "utf-8");
|
|
15186
15407
|
} catch {
|
|
15187
15408
|
continue;
|
|
15188
15409
|
}
|
|
@@ -15425,6 +15646,23 @@ function describeScanOutcome(outcome) {
|
|
|
15425
15646
|
function scanOutcomeNeedsAttention(outcome) {
|
|
15426
15647
|
return outcome.status === "permission-denied" || outcome.status === "error";
|
|
15427
15648
|
}
|
|
15649
|
+
function describeStoreOutcome(outcome) {
|
|
15650
|
+
if (outcome.status === "orphaned") {
|
|
15651
|
+
return `not read: nothing on this machine was detected as ${outcome.members.join(" or ")}`;
|
|
15652
|
+
}
|
|
15653
|
+
if (outcome.status === "ok")
|
|
15654
|
+
return null;
|
|
15655
|
+
return describeScanOutcome({
|
|
15656
|
+
agentSlug: outcome.storeId,
|
|
15657
|
+
status: outcome.status,
|
|
15658
|
+
sessions: outcome.sessions,
|
|
15659
|
+
path: outcome.path,
|
|
15660
|
+
...outcome.detail ? { detail: outcome.detail } : {}
|
|
15661
|
+
});
|
|
15662
|
+
}
|
|
15663
|
+
function storeOutcomeNeedsAttention(outcome) {
|
|
15664
|
+
return outcome.status === "orphaned" || outcome.status === "permission-denied" || outcome.status === "error";
|
|
15665
|
+
}
|
|
15428
15666
|
|
|
15429
15667
|
// src/utils/insight-id.ts
|
|
15430
15668
|
import { createHash as createHash3 } from "node:crypto";
|
|
@@ -15437,7 +15675,7 @@ function insightLocalKey(teaches, slug) {
|
|
|
15437
15675
|
var init_insight_id = () => {};
|
|
15438
15676
|
|
|
15439
15677
|
// src/reflect/insight-store.ts
|
|
15440
|
-
import { existsSync as existsSync41, readFileSync as
|
|
15678
|
+
import { existsSync as existsSync41, readFileSync as readFileSync31 } from "fs";
|
|
15441
15679
|
import { join as join35 } from "path";
|
|
15442
15680
|
import { homedir as homedir17 } from "os";
|
|
15443
15681
|
function storePath2() {
|
|
@@ -15448,7 +15686,7 @@ function readAll() {
|
|
|
15448
15686
|
if (!existsSync41(path2))
|
|
15449
15687
|
return {};
|
|
15450
15688
|
try {
|
|
15451
|
-
const parsed = JSON.parse(
|
|
15689
|
+
const parsed = JSON.parse(readFileSync31(path2, "utf-8"));
|
|
15452
15690
|
return parsed && typeof parsed === "object" ? parsed : {};
|
|
15453
15691
|
} catch {
|
|
15454
15692
|
return {};
|
|
@@ -15493,7 +15731,7 @@ var init_insight_store = __esm(() => {
|
|
|
15493
15731
|
var DEFAULT_DAILY_TIER2_BUDGET = 3;
|
|
15494
15732
|
|
|
15495
15733
|
// src/reflect/cadence.ts
|
|
15496
|
-
import { existsSync as existsSync42, readFileSync as
|
|
15734
|
+
import { existsSync as existsSync42, readFileSync as readFileSync32 } from "fs";
|
|
15497
15735
|
import { join as join36 } from "path";
|
|
15498
15736
|
import { homedir as homedir18 } from "os";
|
|
15499
15737
|
function remainingDailyAnalyses(state, now = new Date, budget = DEFAULT_DAILY_TIER2_BUDGET) {
|
|
@@ -15515,7 +15753,7 @@ function loadCadenceState() {
|
|
|
15515
15753
|
const p = statePath();
|
|
15516
15754
|
if (!existsSync42(p))
|
|
15517
15755
|
return { ...DEFAULT_STATE };
|
|
15518
|
-
const parsed = JSON.parse(
|
|
15756
|
+
const parsed = JSON.parse(readFileSync32(p, "utf-8"));
|
|
15519
15757
|
const state = { ...DEFAULT_STATE, ...parsed && typeof parsed === "object" ? parsed : {} };
|
|
15520
15758
|
if (state.enabled === false && state.disabledByUser !== true) {
|
|
15521
15759
|
state.enabled = true;
|
|
@@ -15576,7 +15814,7 @@ __export(exports_run_log, {
|
|
|
15576
15814
|
RUN_LOG_CAP: () => RUN_LOG_CAP,
|
|
15577
15815
|
ANALYST_ERROR_MAX_CHARS: () => ANALYST_ERROR_MAX_CHARS
|
|
15578
15816
|
});
|
|
15579
|
-
import { existsSync as existsSync43, mkdirSync as mkdirSync25, readFileSync as
|
|
15817
|
+
import { existsSync as existsSync43, mkdirSync as mkdirSync25, readFileSync as readFileSync33, readdirSync as readdirSync15, statSync as statSync9, unlinkSync as unlinkSync7, writeFileSync as writeFileSync25 } from "fs";
|
|
15580
15818
|
import { dirname as dirname10, join as join37 } from "path";
|
|
15581
15819
|
import { homedir as homedir19 } from "os";
|
|
15582
15820
|
function runLogPath() {
|
|
@@ -15587,7 +15825,7 @@ function loadRunLog() {
|
|
|
15587
15825
|
const p = runLogPath();
|
|
15588
15826
|
if (!existsSync43(p))
|
|
15589
15827
|
return [];
|
|
15590
|
-
const parsed = JSON.parse(
|
|
15828
|
+
const parsed = JSON.parse(readFileSync33(p, "utf-8"));
|
|
15591
15829
|
return Array.isArray(parsed) ? parsed : [];
|
|
15592
15830
|
} catch {
|
|
15593
15831
|
return [];
|
|
@@ -15755,7 +15993,7 @@ var init_run_log = __esm(() => {
|
|
|
15755
15993
|
});
|
|
15756
15994
|
|
|
15757
15995
|
// src/reflect/conversation-queue.ts
|
|
15758
|
-
import { existsSync as existsSync44, readFileSync as
|
|
15996
|
+
import { existsSync as existsSync44, readFileSync as readFileSync34 } from "fs";
|
|
15759
15997
|
import { join as join38 } from "path";
|
|
15760
15998
|
import { homedir as homedir20 } from "os";
|
|
15761
15999
|
function conversationKey(c) {
|
|
@@ -15769,7 +16007,7 @@ function loadQueueState() {
|
|
|
15769
16007
|
const p = queuePath();
|
|
15770
16008
|
if (!existsSync44(p))
|
|
15771
16009
|
return { entries: {} };
|
|
15772
|
-
const parsed = JSON.parse(
|
|
16010
|
+
const parsed = JSON.parse(readFileSync34(p, "utf-8"));
|
|
15773
16011
|
if (parsed && typeof parsed === "object" && parsed.entries && typeof parsed.entries === "object") {
|
|
15774
16012
|
return { entries: parsed.entries };
|
|
15775
16013
|
}
|
|
@@ -15977,7 +16215,7 @@ function parseHandoffResult(kind, text2) {
|
|
|
15977
16215
|
}
|
|
15978
16216
|
|
|
15979
16217
|
// src/reflect/model-repair.ts
|
|
15980
|
-
import { existsSync as existsSync45, readFileSync as
|
|
16218
|
+
import { existsSync as existsSync45, readFileSync as readFileSync35, writeFileSync as writeFileSync26 } from "fs";
|
|
15981
16219
|
import { homedir as homedir21 } from "os";
|
|
15982
16220
|
import { join as join39 } from "path";
|
|
15983
16221
|
function codexConfigPath() {
|
|
@@ -16014,7 +16252,7 @@ function repairCodexModelPin() {
|
|
|
16014
16252
|
const path2 = codexConfigPath();
|
|
16015
16253
|
if (!existsSync45(path2))
|
|
16016
16254
|
return null;
|
|
16017
|
-
const current =
|
|
16255
|
+
const current = readFileSync35(path2, "utf-8");
|
|
16018
16256
|
const stripped = stripModelPin(current);
|
|
16019
16257
|
if (!stripped)
|
|
16020
16258
|
return null;
|
|
@@ -16837,7 +17075,214 @@ ${all.length} insight(s) from your recent work:
|
|
|
16837
17075
|
});
|
|
16838
17076
|
});
|
|
16839
17077
|
|
|
17078
|
+
// src/agents/transcript-stores.ts
|
|
17079
|
+
function joiner(input) {
|
|
17080
|
+
const sep4 = input.sep ?? (input.platform === "win32" ? "\\" : "/");
|
|
17081
|
+
return (...parts) => parts.join(sep4);
|
|
17082
|
+
}
|
|
17083
|
+
function home(input) {
|
|
17084
|
+
return input.homeDir.replace(/[/\\]+$/, "");
|
|
17085
|
+
}
|
|
17086
|
+
function appDataRoot(input) {
|
|
17087
|
+
const join41 = joiner(input);
|
|
17088
|
+
if (input.platform === "darwin")
|
|
17089
|
+
return join41(home(input), "Library", "Application Support");
|
|
17090
|
+
if (input.platform === "win32") {
|
|
17091
|
+
return input.appData ?? join41(home(input), "AppData", "Roaming");
|
|
17092
|
+
}
|
|
17093
|
+
return join41(home(input), ".config");
|
|
17094
|
+
}
|
|
17095
|
+
function localAppDataRoot(input) {
|
|
17096
|
+
const join41 = joiner(input);
|
|
17097
|
+
return input.localAppData ?? join41(home(input), "AppData", "Local");
|
|
17098
|
+
}
|
|
17099
|
+
function codexOriginator(head) {
|
|
17100
|
+
for (const line of head.split(`
|
|
17101
|
+
`)) {
|
|
17102
|
+
if (!line.trim())
|
|
17103
|
+
continue;
|
|
17104
|
+
let o;
|
|
17105
|
+
try {
|
|
17106
|
+
o = JSON.parse(line);
|
|
17107
|
+
} catch {
|
|
17108
|
+
continue;
|
|
17109
|
+
}
|
|
17110
|
+
if (o.type !== "session_meta")
|
|
17111
|
+
continue;
|
|
17112
|
+
const payload = o.payload;
|
|
17113
|
+
return typeof payload?.originator === "string" ? payload.originator : null;
|
|
17114
|
+
}
|
|
17115
|
+
return null;
|
|
17116
|
+
}
|
|
17117
|
+
function claudeEntrypoint(head) {
|
|
17118
|
+
for (const line of head.split(`
|
|
17119
|
+
`)) {
|
|
17120
|
+
if (!line.trim())
|
|
17121
|
+
continue;
|
|
17122
|
+
let o;
|
|
17123
|
+
try {
|
|
17124
|
+
o = JSON.parse(line);
|
|
17125
|
+
} catch {
|
|
17126
|
+
continue;
|
|
17127
|
+
}
|
|
17128
|
+
if (typeof o.entrypoint === "string")
|
|
17129
|
+
return o.entrypoint;
|
|
17130
|
+
}
|
|
17131
|
+
return null;
|
|
17132
|
+
}
|
|
17133
|
+
function attributeCodexOriginator(marker) {
|
|
17134
|
+
switch (marker) {
|
|
17135
|
+
case "Codex Desktop":
|
|
17136
|
+
case "codex_work_desktop":
|
|
17137
|
+
return "codex-app";
|
|
17138
|
+
case "codex-tui":
|
|
17139
|
+
case "codex_exec":
|
|
17140
|
+
case "Claude Code":
|
|
17141
|
+
return "codex";
|
|
17142
|
+
default:
|
|
17143
|
+
return null;
|
|
17144
|
+
}
|
|
17145
|
+
}
|
|
17146
|
+
function attributeClaudeEntrypoint(marker) {
|
|
17147
|
+
switch (marker) {
|
|
17148
|
+
case "cli":
|
|
17149
|
+
case "sdk-cli":
|
|
17150
|
+
return "claude-code";
|
|
17151
|
+
case "claude-desktop":
|
|
17152
|
+
case "local-agent":
|
|
17153
|
+
return "claude-desktop";
|
|
17154
|
+
default:
|
|
17155
|
+
return null;
|
|
17156
|
+
}
|
|
17157
|
+
}
|
|
17158
|
+
function resolveTranscriptStores(input) {
|
|
17159
|
+
const resolved = [];
|
|
17160
|
+
for (const def of TRANSCRIPT_STORES) {
|
|
17161
|
+
const path2 = def.path(input);
|
|
17162
|
+
if (path2 === null)
|
|
17163
|
+
continue;
|
|
17164
|
+
resolved.push({ def, path: path2, altPaths: def.altPaths?.(input) ?? [] });
|
|
17165
|
+
}
|
|
17166
|
+
return resolved;
|
|
17167
|
+
}
|
|
17168
|
+
function familyMembers(family, table = TRANSCRIPT_STORES) {
|
|
17169
|
+
const slugs = new Set;
|
|
17170
|
+
for (const store of table) {
|
|
17171
|
+
if (store.family !== family)
|
|
17172
|
+
continue;
|
|
17173
|
+
for (const member of store.members)
|
|
17174
|
+
slugs.add(member);
|
|
17175
|
+
}
|
|
17176
|
+
return [...slugs];
|
|
17177
|
+
}
|
|
17178
|
+
function isStoreUnlocked(def, detectedSlugs, table = TRANSCRIPT_STORES) {
|
|
17179
|
+
const detected = detectedSlugs instanceof Set ? detectedSlugs : new Set(detectedSlugs);
|
|
17180
|
+
return familyMembers(def.family, table).some((m) => detected.has(m));
|
|
17181
|
+
}
|
|
17182
|
+
function telemetryOwner(def, detectedSlugs) {
|
|
17183
|
+
const detected = detectedSlugs instanceof Set ? detectedSlugs : new Set(detectedSlugs);
|
|
17184
|
+
if (detected.has(def.readerSlug))
|
|
17185
|
+
return def.readerSlug;
|
|
17186
|
+
return def.members.find((m) => detected.has(m)) ?? null;
|
|
17187
|
+
}
|
|
17188
|
+
function suppressedStoreReaders(detectedSlugs, sharesImplementation, table = TRANSCRIPT_STORES) {
|
|
17189
|
+
const detected = detectedSlugs instanceof Set ? detectedSlugs : new Set(detectedSlugs);
|
|
17190
|
+
const suppressed = new Set;
|
|
17191
|
+
for (const store of table) {
|
|
17192
|
+
const owner = telemetryOwner(store, detected);
|
|
17193
|
+
if (owner === null)
|
|
17194
|
+
continue;
|
|
17195
|
+
for (const member of store.members) {
|
|
17196
|
+
if (member === owner || !detected.has(member))
|
|
17197
|
+
continue;
|
|
17198
|
+
if (sharesImplementation(member, owner))
|
|
17199
|
+
suppressed.add(member);
|
|
17200
|
+
}
|
|
17201
|
+
}
|
|
17202
|
+
return suppressed;
|
|
17203
|
+
}
|
|
17204
|
+
function attributeTranscript(def, head) {
|
|
17205
|
+
if (head === null || !def.marker) {
|
|
17206
|
+
return { agentSlug: def.defaultMember, marker: null, recognised: false };
|
|
17207
|
+
}
|
|
17208
|
+
const marker = def.marker(head);
|
|
17209
|
+
if (marker === null)
|
|
17210
|
+
return { agentSlug: def.defaultMember, marker: null, recognised: false };
|
|
17211
|
+
const slug = def.attribute?.(marker) ?? null;
|
|
17212
|
+
return slug === null ? { agentSlug: def.defaultMember, marker, recognised: false } : { agentSlug: slug, marker, recognised: true };
|
|
17213
|
+
}
|
|
17214
|
+
var CODEX_HEAD, CLAUDE_HEAD, TRANSCRIPT_STORES;
|
|
17215
|
+
var init_transcript_stores = __esm(() => {
|
|
17216
|
+
CODEX_HEAD = 256 * 1024;
|
|
17217
|
+
CLAUDE_HEAD = 64 * 1024;
|
|
17218
|
+
TRANSCRIPT_STORES = [
|
|
17219
|
+
{
|
|
17220
|
+
id: "codex/sessions",
|
|
17221
|
+
readerSlug: "codex",
|
|
17222
|
+
family: "codex",
|
|
17223
|
+
members: ["codex", "codex-app"],
|
|
17224
|
+
defaultMember: "codex",
|
|
17225
|
+
kind: "dir",
|
|
17226
|
+
path: (i) => joiner(i)(home(i), ".codex", "sessions"),
|
|
17227
|
+
matches: (n) => n.startsWith("rollout-") && n.endsWith(".jsonl"),
|
|
17228
|
+
headBytes: CODEX_HEAD,
|
|
17229
|
+
marker: codexOriginator,
|
|
17230
|
+
attribute: attributeCodexOriginator
|
|
17231
|
+
},
|
|
17232
|
+
{
|
|
17233
|
+
id: "claude/projects",
|
|
17234
|
+
readerSlug: "claude-code",
|
|
17235
|
+
family: "claude",
|
|
17236
|
+
members: ["claude-code", "claude-desktop"],
|
|
17237
|
+
defaultMember: "claude-code",
|
|
17238
|
+
kind: "dir",
|
|
17239
|
+
path: (i) => joiner(i)(home(i), ".claude", "projects"),
|
|
17240
|
+
matches: (n) => n.endsWith(".jsonl"),
|
|
17241
|
+
subordinate: (rel) => rel.split(/[\\/]/).length > 2,
|
|
17242
|
+
headBytes: CLAUDE_HEAD,
|
|
17243
|
+
marker: claudeEntrypoint,
|
|
17244
|
+
attribute: attributeClaudeEntrypoint
|
|
17245
|
+
},
|
|
17246
|
+
{
|
|
17247
|
+
id: "claude/cowork",
|
|
17248
|
+
readerSlug: "claude-desktop",
|
|
17249
|
+
family: "claude",
|
|
17250
|
+
members: ["claude-desktop"],
|
|
17251
|
+
defaultMember: "claude-desktop",
|
|
17252
|
+
kind: "dir",
|
|
17253
|
+
path: (i) => joiner(i)(appDataRoot(i), "Claude", "local-agent-mode-sessions"),
|
|
17254
|
+
altPaths: (i) => i.platform === "win32" ? [joiner(i)(localAppDataRoot(i), "Packages", "Claude_pzs8sxrjxfjjc", "LocalCache", "Roaming", "Claude", "local-agent-mode-sessions")] : [],
|
|
17255
|
+
matches: (n) => n.endsWith(".jsonl"),
|
|
17256
|
+
headBytes: CLAUDE_HEAD,
|
|
17257
|
+
marker: claudeEntrypoint,
|
|
17258
|
+
attribute: attributeClaudeEntrypoint,
|
|
17259
|
+
note: "macOS TCC can refuse this while it still exists"
|
|
17260
|
+
},
|
|
17261
|
+
{
|
|
17262
|
+
id: "gemini/tmp",
|
|
17263
|
+
readerSlug: "gemini",
|
|
17264
|
+
family: "gemini",
|
|
17265
|
+
members: ["gemini"],
|
|
17266
|
+
defaultMember: "gemini",
|
|
17267
|
+
kind: "dir",
|
|
17268
|
+
path: (i) => joiner(i)(home(i), ".gemini", "tmp"),
|
|
17269
|
+
matches: (n) => n.endsWith(".json")
|
|
17270
|
+
},
|
|
17271
|
+
{
|
|
17272
|
+
id: "cursor/state",
|
|
17273
|
+
readerSlug: "cursor",
|
|
17274
|
+
family: "cursor",
|
|
17275
|
+
members: ["cursor"],
|
|
17276
|
+
defaultMember: "cursor",
|
|
17277
|
+
kind: "file",
|
|
17278
|
+
path: (i) => joiner(i)(appDataRoot(i), "Cursor", "User", "globalStorage", "state.vscdb"),
|
|
17279
|
+
tool: "sqlite"
|
|
17280
|
+
}
|
|
17281
|
+
];
|
|
17282
|
+
});
|
|
17283
|
+
|
|
16840
17284
|
// src/reflect/conversation-registry.ts
|
|
17285
|
+
import { homedir as homedir22, platform as platform7 } from "os";
|
|
16841
17286
|
function computeStatus(lastActivityAt, nowMs, idleMinutes = DEFAULT_IDLE_MINUTES) {
|
|
16842
17287
|
const lastMs = new Date(lastActivityAt).getTime();
|
|
16843
17288
|
if (Number.isNaN(lastMs))
|
|
@@ -16868,44 +17313,114 @@ function mergeSessionListings(listings, opts) {
|
|
|
16868
17313
|
status: isFreshEndStamp(s.endedAt, s.lastActivityAt) ? "finished" : computeStatus(s.lastActivityAt, opts.nowMs, opts.idleMinutes)
|
|
16869
17314
|
}));
|
|
16870
17315
|
}
|
|
17316
|
+
function machineStores(opts) {
|
|
17317
|
+
return opts.stores ?? resolveTranscriptStores({
|
|
17318
|
+
platform: platform7(),
|
|
17319
|
+
homeDir: homedir22(),
|
|
17320
|
+
appData: process.env.APPDATA ?? null,
|
|
17321
|
+
localAppData: process.env.LOCALAPPDATA ?? null
|
|
17322
|
+
});
|
|
17323
|
+
}
|
|
17324
|
+
function attributeListing(store, sessions) {
|
|
17325
|
+
if (!store.def.attribute)
|
|
17326
|
+
return sessions;
|
|
17327
|
+
return sessions.map((s) => {
|
|
17328
|
+
const surface = s.surface ?? null;
|
|
17329
|
+
const slug = surface === null ? null : store.def.attribute?.(surface) ?? null;
|
|
17330
|
+
return {
|
|
17331
|
+
...s,
|
|
17332
|
+
agentSlug: slug ?? store.def.defaultMember,
|
|
17333
|
+
surface
|
|
17334
|
+
};
|
|
17335
|
+
});
|
|
17336
|
+
}
|
|
16871
17337
|
async function listLocalConversations(opts = {}) {
|
|
16872
|
-
const
|
|
17338
|
+
const detected = opts.detected ?? (await detectAgents()).map((a) => a.slug);
|
|
17339
|
+
const detectedSet = new Set(detected);
|
|
16873
17340
|
const sinceISO = opts.sinceISO ?? null;
|
|
17341
|
+
const maxPerStore = opts.maxPerStore ?? DEFAULT_MAX_PER_STORE;
|
|
16874
17342
|
const listings = [];
|
|
16875
|
-
const
|
|
16876
|
-
|
|
16877
|
-
|
|
16878
|
-
|
|
17343
|
+
const perStore = [];
|
|
17344
|
+
const stores = machineStores(opts);
|
|
17345
|
+
const table = stores.map((s) => s.def);
|
|
17346
|
+
for (const store of stores) {
|
|
17347
|
+
const base = {
|
|
17348
|
+
storeId: store.def.id,
|
|
17349
|
+
family: store.def.family,
|
|
17350
|
+
members: [...familyMembers(store.def.family, table)],
|
|
17351
|
+
path: store.path
|
|
17352
|
+
};
|
|
17353
|
+
if (!isStoreUnlocked(store.def, detectedSet, table)) {
|
|
17354
|
+
perStore.push({ ...base, status: "orphaned", sessions: null });
|
|
17355
|
+
continue;
|
|
17356
|
+
}
|
|
17357
|
+
const reader = (opts.readerFor ?? getAdapterBySlug)(store.def.readerSlug);
|
|
17358
|
+
if (!reader?.listSessions) {
|
|
17359
|
+
perStore.push({ ...base, status: "no-reader", sessions: null });
|
|
16879
17360
|
continue;
|
|
16880
17361
|
}
|
|
16881
17362
|
try {
|
|
16882
|
-
const sessions = await
|
|
17363
|
+
const sessions = await reader.listSessions(sinceISO);
|
|
16883
17364
|
if (sessions === null) {
|
|
16884
|
-
|
|
17365
|
+
const outcome = diagnoseTranscriptRead(reader);
|
|
17366
|
+
perStore.push({ ...base, status: outcome.status, sessions: null, ...outcome.detail ? { detail: outcome.detail } : {} });
|
|
16885
17367
|
continue;
|
|
16886
17368
|
}
|
|
16887
|
-
|
|
16888
|
-
|
|
17369
|
+
const attributed = attributeListing(store, sessions).sort((a, b) => b.lastActivityAt.localeCompare(a.lastActivityAt)).slice(0, maxPerStore);
|
|
17370
|
+
listings.push(attributed);
|
|
17371
|
+
perStore.push({
|
|
17372
|
+
...base,
|
|
17373
|
+
status: "ok",
|
|
17374
|
+
sessions: attributed.length,
|
|
17375
|
+
...sessions.length > attributed.length ? { truncated: sessions.length } : {}
|
|
17376
|
+
});
|
|
16889
17377
|
} catch (err) {
|
|
16890
|
-
|
|
17378
|
+
const outcome = diagnoseTranscriptRead(reader, err);
|
|
17379
|
+
perStore.push({ ...base, status: outcome.status, sessions: null, ...outcome.detail ? { detail: outcome.detail } : {} });
|
|
16891
17380
|
}
|
|
16892
17381
|
}
|
|
16893
17382
|
const conversations = mergeSessionListings(listings, {
|
|
16894
17383
|
nowMs: opts.nowMs ?? Date.now(),
|
|
16895
17384
|
idleMinutes: opts.idleMinutes
|
|
16896
17385
|
});
|
|
16897
|
-
return { conversations, perAgent };
|
|
17386
|
+
return { conversations, perAgent: derivePerAgent(perStore, conversations), perStore };
|
|
16898
17387
|
}
|
|
16899
|
-
|
|
17388
|
+
function derivePerAgent(perStore, conversations) {
|
|
17389
|
+
const counts = new Map;
|
|
17390
|
+
for (const c of conversations)
|
|
17391
|
+
counts.set(c.agentSlug, (counts.get(c.agentSlug) ?? 0) + 1);
|
|
17392
|
+
const rows = new Map;
|
|
17393
|
+
for (const store of perStore) {
|
|
17394
|
+
for (const slug of store.members) {
|
|
17395
|
+
const existing = rows.get(slug);
|
|
17396
|
+
if (store.status === "ok") {
|
|
17397
|
+
rows.set(slug, { agentSlug: slug, status: "ok", sessions: counts.get(slug) ?? 0 });
|
|
17398
|
+
continue;
|
|
17399
|
+
}
|
|
17400
|
+
if (!existing || existing.status !== "ok") {
|
|
17401
|
+
rows.set(slug, {
|
|
17402
|
+
agentSlug: slug,
|
|
17403
|
+
status: store.status === "orphaned" ? "missing-dir" : store.status,
|
|
17404
|
+
sessions: null,
|
|
17405
|
+
...store.path ? { path: store.path } : {},
|
|
17406
|
+
...store.detail ? { detail: store.detail } : {}
|
|
17407
|
+
});
|
|
17408
|
+
}
|
|
17409
|
+
}
|
|
17410
|
+
}
|
|
17411
|
+
return [...rows.values()];
|
|
17412
|
+
}
|
|
17413
|
+
var DEFAULT_IDLE_MINUTES = 10, DEFAULT_MAX_PER_STORE = 500;
|
|
16900
17414
|
var init_conversation_registry = __esm(async () => {
|
|
16901
17415
|
init_transcript_sources();
|
|
17416
|
+
init_transcript_stores();
|
|
16902
17417
|
await init_detect();
|
|
16903
17418
|
});
|
|
16904
17419
|
|
|
16905
17420
|
// src/reflect/session-summary.ts
|
|
16906
17421
|
import { createHash as createHash4 } from "crypto";
|
|
16907
17422
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
16908
|
-
import { readFileSync as
|
|
17423
|
+
import { readFileSync as readFileSync36 } from "fs";
|
|
16909
17424
|
import { isAbsolute as isAbsolute4 } from "path";
|
|
16910
17425
|
function validateAssetMarkers(markers, knownSkills) {
|
|
16911
17426
|
if (!markers || markers.length === 0)
|
|
@@ -17007,7 +17522,7 @@ function digestForEntry(entry) {
|
|
|
17007
17522
|
return null;
|
|
17008
17523
|
let content;
|
|
17009
17524
|
try {
|
|
17010
|
-
content =
|
|
17525
|
+
content = readFileSync36(entry.transcriptPath, "utf-8");
|
|
17011
17526
|
} catch {
|
|
17012
17527
|
return null;
|
|
17013
17528
|
}
|
|
@@ -17135,18 +17650,18 @@ var init_session_summary = __esm(() => {
|
|
|
17135
17650
|
});
|
|
17136
17651
|
|
|
17137
17652
|
// src/reflect/telemetry-outbox.ts
|
|
17138
|
-
import { existsSync as
|
|
17139
|
-
import { join as
|
|
17140
|
-
import { homedir as
|
|
17653
|
+
import { existsSync as existsSync47, readFileSync as readFileSync37 } from "fs";
|
|
17654
|
+
import { join as join42 } from "path";
|
|
17655
|
+
import { homedir as homedir23 } from "os";
|
|
17141
17656
|
function outboxPath() {
|
|
17142
|
-
return
|
|
17657
|
+
return join42(homedir23(), ".runwork", "telemetry-outbox.json");
|
|
17143
17658
|
}
|
|
17144
17659
|
function loadTelemetryOutbox() {
|
|
17145
17660
|
try {
|
|
17146
17661
|
const p = outboxPath();
|
|
17147
|
-
if (!
|
|
17662
|
+
if (!existsSync47(p))
|
|
17148
17663
|
return [];
|
|
17149
|
-
const parsed = JSON.parse(
|
|
17664
|
+
const parsed = JSON.parse(readFileSync37(p, "utf-8"));
|
|
17150
17665
|
if (!Array.isArray(parsed))
|
|
17151
17666
|
return [];
|
|
17152
17667
|
return parsed.filter((e) => !!e && typeof e === "object" && typeof e.dedupeKey === "string" && !!e.event && typeof e.event === "object");
|
|
@@ -17207,8 +17722,8 @@ var init_active_time = __esm(() => {
|
|
|
17207
17722
|
|
|
17208
17723
|
// src/reflect/pattern-store.ts
|
|
17209
17724
|
import { createHash as createHash5 } from "crypto";
|
|
17210
|
-
import { join as
|
|
17211
|
-
import { homedir as
|
|
17725
|
+
import { join as join43 } from "path";
|
|
17726
|
+
import { homedir as homedir24 } from "os";
|
|
17212
17727
|
function addBuckets(a, b) {
|
|
17213
17728
|
if (!a)
|
|
17214
17729
|
return b ? { ...b } : null;
|
|
@@ -17369,7 +17884,7 @@ function buildPatternEvent(payload, nowISO) {
|
|
|
17369
17884
|
};
|
|
17370
17885
|
}
|
|
17371
17886
|
function storePath3() {
|
|
17372
|
-
return
|
|
17887
|
+
return join43(homedir24(), ".runwork", "pattern-store.json");
|
|
17373
17888
|
}
|
|
17374
17889
|
function loadPatternStore() {
|
|
17375
17890
|
const parsed = readJsonOrNull(storePath3());
|
|
@@ -17579,7 +18094,7 @@ var init_triage = __esm(async () => {
|
|
|
17579
18094
|
});
|
|
17580
18095
|
|
|
17581
18096
|
// src/reflect/conversation-analysis.ts
|
|
17582
|
-
import { existsSync as
|
|
18097
|
+
import { existsSync as existsSync48 } from "fs";
|
|
17583
18098
|
import { basename as basename5 } from "path";
|
|
17584
18099
|
function brokenAnalystBinaries() {
|
|
17585
18100
|
return TIER2_ANALYSTS.filter((a) => {
|
|
@@ -17607,7 +18122,7 @@ function isPromptStillValid(key) {
|
|
|
17607
18122
|
if (!standing?.promptPath || standing.promptConversationKey !== key)
|
|
17608
18123
|
return false;
|
|
17609
18124
|
try {
|
|
17610
|
-
return
|
|
18125
|
+
return existsSync48(standing.promptPath);
|
|
17611
18126
|
} catch {
|
|
17612
18127
|
return false;
|
|
17613
18128
|
}
|
|
@@ -19529,17 +20044,10 @@ async function parseCurlToRequest(curlStr) {
|
|
|
19529
20044
|
try {
|
|
19530
20045
|
body = JSON.parse(dataStr);
|
|
19531
20046
|
} catch {
|
|
19532
|
-
|
|
19533
|
-
|
|
19534
|
-
|
|
19535
|
-
|
|
19536
|
-
if (eqIdx > 0) {
|
|
19537
|
-
formData[decodeURIComponent(pair.slice(0, eqIdx))] = decodeURIComponent(pair.slice(eqIdx + 1));
|
|
19538
|
-
}
|
|
19539
|
-
}
|
|
19540
|
-
body = formData;
|
|
19541
|
-
} else {
|
|
19542
|
-
body = dataStr;
|
|
20047
|
+
body = dataStr;
|
|
20048
|
+
const hasContentType = Object.keys(filteredHeaders).some((k) => k.toLowerCase() === "content-type");
|
|
20049
|
+
if (!hasContentType) {
|
|
20050
|
+
filteredHeaders["Content-Type"] = "application/x-www-form-urlencoded";
|
|
19543
20051
|
}
|
|
19544
20052
|
}
|
|
19545
20053
|
}
|
|
@@ -19665,16 +20173,19 @@ Used by your team (${teamOnly.length} more):
|
|
|
19665
20173
|
process.exit(1);
|
|
19666
20174
|
}
|
|
19667
20175
|
});
|
|
19668
|
-
var callCommand = new Command10("call").description("Make a proxy call to a connected integration").argument("<integration>", "Integration name (e.g., hubspot, slack)").argument("[method]", "HTTP method (GET, POST, PUT, DELETE)").argument("[path]", "API path (e.g., /crm/v3/contacts)").option("--workspace <name-or-id>", "Workspace name or ID").option("--body <
|
|
20176
|
+
var callCommand = new Command10("call").description("Make a proxy call to a connected integration").argument("<integration>", "Integration name (e.g., hubspot, slack)").argument("[method]", "HTTP method (GET, POST, PUT, DELETE)").argument("[path]", "API path (e.g., /crm/v3/contacts)").option("--workspace <name-or-id>", "Workspace name or ID").option("--body <body>", "Request body: JSON, or a raw string when a non-JSON Content-Type header is set").option("--form", "Send the body as application/x-www-form-urlencoded (Stripe, Twilio, OAuth token endpoints). Accepts a JSON object (form-encoded, nested keys in bracket notation) or an already-encoded a=b&c=d string").option("--header <header>", "Request header (repeatable). Content-Type decides how --body is encoded", (val, prev) => [...prev, val], []).option("--query <query>", "Query string (e.g., limit=10&offset=0)").option("--curl <command>", 'Parse a curl command (paste from Chrome DevTools "Copy as cURL")').option("--curl-file <file>", "Read curl command from a file").action(async (integration, method, path2, opts, command) => {
|
|
19669
20177
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
19670
20178
|
const credentials = requireAuth();
|
|
19671
20179
|
const client = new ApiClient(credentials);
|
|
19672
20180
|
const { workspaceId } = await resolveWorkspace2(client, opts);
|
|
19673
20181
|
let finalMethod;
|
|
19674
20182
|
let finalPath;
|
|
19675
|
-
|
|
20183
|
+
let headers = {};
|
|
19676
20184
|
let body;
|
|
19677
20185
|
let query = opts.query;
|
|
20186
|
+
if (opts.form) {
|
|
20187
|
+
headers = setHeader(headers, "Content-Type", FORM_CONTENT_TYPE);
|
|
20188
|
+
}
|
|
19678
20189
|
if (opts.curl || opts.curlFile) {
|
|
19679
20190
|
let curlStr = opts.curl;
|
|
19680
20191
|
if (opts.curlFile) {
|
|
@@ -19691,7 +20202,7 @@ var callCommand = new Command10("call").description("Make a proxy call to a conn
|
|
|
19691
20202
|
finalPath = result.path;
|
|
19692
20203
|
if (result.query)
|
|
19693
20204
|
query = query || result.query;
|
|
19694
|
-
|
|
20205
|
+
headers = opts.form ? setHeader({ ...result.headers }, "Content-Type", FORM_CONTENT_TYPE) : { ...result.headers };
|
|
19695
20206
|
body = result.body;
|
|
19696
20207
|
} catch (err) {
|
|
19697
20208
|
console.error("Failed to parse curl command:", err instanceof Error ? err.message : err);
|
|
@@ -19702,13 +20213,13 @@ var callCommand = new Command10("call").description("Make a proxy call to a conn
|
|
|
19702
20213
|
finalPath = path2;
|
|
19703
20214
|
for (const h of opts.header || []) {
|
|
19704
20215
|
const [key, ...rest] = h.split(":");
|
|
19705
|
-
headers
|
|
20216
|
+
headers = setHeader(headers, key.trim(), rest.join(":").trim());
|
|
19706
20217
|
}
|
|
19707
20218
|
if (opts.body) {
|
|
19708
20219
|
try {
|
|
19709
|
-
body =
|
|
19710
|
-
} catch {
|
|
19711
|
-
console.error("Invalid
|
|
20220
|
+
body = parseBodyArgument(opts.body, findHeader(headers, "Content-Type"));
|
|
20221
|
+
} catch (err) {
|
|
20222
|
+
console.error(err instanceof Error ? err.message : "Invalid --body");
|
|
19712
20223
|
process.exit(1);
|
|
19713
20224
|
}
|
|
19714
20225
|
}
|
|
@@ -20661,6 +21172,159 @@ var skillsCommand = new Command13("skills").description("Manage workspace skills
|
|
|
20661
21172
|
// src/index.ts
|
|
20662
21173
|
await init_reflect();
|
|
20663
21174
|
|
|
21175
|
+
// src/commands/conversations.ts
|
|
21176
|
+
init_transcript_stores();
|
|
21177
|
+
await init_detect();
|
|
21178
|
+
import { Command as Command15 } from "commander";
|
|
21179
|
+
import { join as join44 } from "path";
|
|
21180
|
+
import { homedir as homedir25, platform as platform8 } from "os";
|
|
21181
|
+
|
|
21182
|
+
// src/agents/store-census.ts
|
|
21183
|
+
init_transcript_stores();
|
|
21184
|
+
import { readdirSync as readdirSync16, statSync as statSync10, existsSync as existsSync46, openSync as openSync5, readSync as readSync3, closeSync as closeSync5 } from "fs";
|
|
21185
|
+
import { join as join41 } from "path";
|
|
21186
|
+
function sanitizeMarker(raw) {
|
|
21187
|
+
const cleaned = raw.replace(/[^\x20-\x7E]/g, "").trim();
|
|
21188
|
+
return cleaned.length > 64 ? `${cleaned.slice(0, 63)}…` : cleaned;
|
|
21189
|
+
}
|
|
21190
|
+
function readHead(path2, n) {
|
|
21191
|
+
let fd;
|
|
21192
|
+
try {
|
|
21193
|
+
fd = openSync5(path2, "r");
|
|
21194
|
+
const buf = Buffer.alloc(n);
|
|
21195
|
+
const read = readSync3(fd, buf, 0, n, 0);
|
|
21196
|
+
return buf.subarray(0, read).toString("utf-8");
|
|
21197
|
+
} catch {
|
|
21198
|
+
return null;
|
|
21199
|
+
} finally {
|
|
21200
|
+
if (fd !== undefined) {
|
|
21201
|
+
try {
|
|
21202
|
+
closeSync5(fd);
|
|
21203
|
+
} catch {}
|
|
21204
|
+
}
|
|
21205
|
+
}
|
|
21206
|
+
}
|
|
21207
|
+
function isPermissionError(err) {
|
|
21208
|
+
const code = err?.code;
|
|
21209
|
+
return code === "EACCES" || code === "EPERM";
|
|
21210
|
+
}
|
|
21211
|
+
function isMissingError(err) {
|
|
21212
|
+
const code = err?.code;
|
|
21213
|
+
return code === "ENOENT" || code === "ENOTDIR";
|
|
21214
|
+
}
|
|
21215
|
+
function collect(dir, def, out, budget) {
|
|
21216
|
+
if (budget.left <= 0)
|
|
21217
|
+
return;
|
|
21218
|
+
const entries = readdirSync16(dir, { withFileTypes: true });
|
|
21219
|
+
for (const e of entries) {
|
|
21220
|
+
if (budget.left <= 0)
|
|
21221
|
+
return;
|
|
21222
|
+
const full = join41(dir, e.name);
|
|
21223
|
+
if (e.isDirectory()) {
|
|
21224
|
+
try {
|
|
21225
|
+
collect(full, def, out, budget);
|
|
21226
|
+
} catch (err) {
|
|
21227
|
+
if (isPermissionError(err))
|
|
21228
|
+
throw err;
|
|
21229
|
+
}
|
|
21230
|
+
} else if (!def.matches || def.matches(e.name)) {
|
|
21231
|
+
out.push(full);
|
|
21232
|
+
budget.left--;
|
|
21233
|
+
}
|
|
21234
|
+
}
|
|
21235
|
+
}
|
|
21236
|
+
var DEFAULT_MAX_FILES = 2000;
|
|
21237
|
+
function censusStore(store, unlocked, opts = {}) {
|
|
21238
|
+
const { def, path: path2, altPaths } = store;
|
|
21239
|
+
const base = {
|
|
21240
|
+
storeId: def.id,
|
|
21241
|
+
family: def.family,
|
|
21242
|
+
members: def.members,
|
|
21243
|
+
path: path2,
|
|
21244
|
+
unlocked,
|
|
21245
|
+
status: "ok"
|
|
21246
|
+
};
|
|
21247
|
+
const altHits = altPaths.filter((p) => {
|
|
21248
|
+
try {
|
|
21249
|
+
return existsSync46(p);
|
|
21250
|
+
} catch {
|
|
21251
|
+
return false;
|
|
21252
|
+
}
|
|
21253
|
+
});
|
|
21254
|
+
if (altHits.length > 0)
|
|
21255
|
+
base.altHits = altHits;
|
|
21256
|
+
if (!existsSync46(path2))
|
|
21257
|
+
return { ...base, status: "missing" };
|
|
21258
|
+
if (def.kind === "file") {
|
|
21259
|
+
try {
|
|
21260
|
+
const s = statSync10(path2);
|
|
21261
|
+
return { ...base, files: 1, bytes: s.size, newestAt: new Date(s.mtimeMs).toISOString() };
|
|
21262
|
+
} catch (err) {
|
|
21263
|
+
return { ...base, status: isPermissionError(err) ? "permission-denied" : "error", detail: String(err) };
|
|
21264
|
+
}
|
|
21265
|
+
}
|
|
21266
|
+
const all = [];
|
|
21267
|
+
const budget = { left: opts.maxFiles ?? DEFAULT_MAX_FILES };
|
|
21268
|
+
try {
|
|
21269
|
+
collect(path2, def, all, budget);
|
|
21270
|
+
} catch (err) {
|
|
21271
|
+
if (isPermissionError(err))
|
|
21272
|
+
return { ...base, status: "permission-denied", detail: "EACCES" };
|
|
21273
|
+
if (isMissingError(err))
|
|
21274
|
+
return { ...base, status: "missing" };
|
|
21275
|
+
return { ...base, status: "error", detail: err instanceof Error ? err.message : String(err) };
|
|
21276
|
+
}
|
|
21277
|
+
const files = [];
|
|
21278
|
+
let nested = 0;
|
|
21279
|
+
for (const f of all) {
|
|
21280
|
+
const rel = f.slice(path2.length).replace(/^[\\/]+/, "");
|
|
21281
|
+
if (def.subordinate?.(rel))
|
|
21282
|
+
nested++;
|
|
21283
|
+
else
|
|
21284
|
+
files.push(f);
|
|
21285
|
+
}
|
|
21286
|
+
let bytes = 0;
|
|
21287
|
+
let newest = 0;
|
|
21288
|
+
for (const f of all) {
|
|
21289
|
+
try {
|
|
21290
|
+
const s = statSync10(f);
|
|
21291
|
+
bytes += s.size;
|
|
21292
|
+
if (s.mtimeMs > newest)
|
|
21293
|
+
newest = s.mtimeMs;
|
|
21294
|
+
} catch {}
|
|
21295
|
+
}
|
|
21296
|
+
const result = {
|
|
21297
|
+
...base,
|
|
21298
|
+
files: files.length,
|
|
21299
|
+
...nested > 0 ? { nested } : {},
|
|
21300
|
+
bytes,
|
|
21301
|
+
newestAt: newest > 0 ? new Date(newest).toISOString() : null
|
|
21302
|
+
};
|
|
21303
|
+
if (opts.skipMarkers || !def.marker)
|
|
21304
|
+
return result;
|
|
21305
|
+
const counts = new Map;
|
|
21306
|
+
for (const f of files) {
|
|
21307
|
+
const head = readHead(f, def.headBytes ?? 64 * 1024);
|
|
21308
|
+
const { agentSlug, marker, recognised } = attributeTranscript(def, head);
|
|
21309
|
+
const clean = marker === null ? null : sanitizeMarker(marker);
|
|
21310
|
+
const key = clean ?? "\x00none";
|
|
21311
|
+
const existing = counts.get(key);
|
|
21312
|
+
if (existing)
|
|
21313
|
+
existing.count++;
|
|
21314
|
+
else
|
|
21315
|
+
counts.set(key, { marker: clean, count: 1, agentSlug, recognised });
|
|
21316
|
+
}
|
|
21317
|
+
result.markers = [...counts.values()].sort((a, b) => b.count - a.count);
|
|
21318
|
+
return result;
|
|
21319
|
+
}
|
|
21320
|
+
function censusStores(stores, detectedSlugs, opts = {}) {
|
|
21321
|
+
const detected = new Set(detectedSlugs);
|
|
21322
|
+
return stores.map((store) => censusStore(store, isStoreUnlocked(store.def, detected), opts));
|
|
21323
|
+
}
|
|
21324
|
+
function orphanedStoresWithContent(censuses) {
|
|
21325
|
+
return censuses.filter((c) => !c.unlocked && c.status === "ok" && (c.files ?? 0) > 0);
|
|
21326
|
+
}
|
|
21327
|
+
|
|
20664
21328
|
// src/commands/conversations.ts
|
|
20665
21329
|
init_conversation_queue();
|
|
20666
21330
|
init_session_summary();
|
|
@@ -20676,10 +21340,7 @@ await __promiseAll([
|
|
|
20676
21340
|
init_conversation_registry(),
|
|
20677
21341
|
init_conversation_analysis()
|
|
20678
21342
|
]);
|
|
20679
|
-
|
|
20680
|
-
import { join as join43 } from "path";
|
|
20681
|
-
import { homedir as homedir24 } from "os";
|
|
20682
|
-
var DEFAULT_LOOKBACK_DAYS = 30;
|
|
21343
|
+
var DEFAULT_LOOKBACK_DAYS = 0;
|
|
20683
21344
|
function sinceFromDays(days) {
|
|
20684
21345
|
if (days <= 0)
|
|
20685
21346
|
return null;
|
|
@@ -20743,18 +21404,25 @@ function fit(text2, width) {
|
|
|
20743
21404
|
return text2.length > width ? text2.slice(0, width - 1) + "…" : text2;
|
|
20744
21405
|
}
|
|
20745
21406
|
var conversationsCommand = new Command15("conversations").description("Local AI conversations across your agents (registry, end detection)");
|
|
20746
|
-
conversationsCommand.command("list").description("List local conversations across all detected agents (metadata only)").option("--days <n>", "
|
|
21407
|
+
conversationsCommand.command("list").description("List local conversations across all detected agents (metadata only)").option("--days <n>", "Narrow to this many days (0 = no window, the default)", String(DEFAULT_LOOKBACK_DAYS)).option("--idle-minutes <n>", "Idle threshold that marks a conversation finished", String(DEFAULT_IDLE_MINUTES)).action(async (opts, command) => {
|
|
20747
21408
|
const json = command.optsWithGlobals().json === true || !process.stdout.isTTY;
|
|
20748
21409
|
const days = parseDays(opts.days);
|
|
20749
21410
|
const idleMinutes = Math.max(1, Number(opts.idleMinutes) || DEFAULT_IDLE_MINUTES);
|
|
20750
21411
|
const result = await listLocalConversations({ sinceISO: sinceFromDays(days), idleMinutes });
|
|
20751
21412
|
if (json) {
|
|
20752
|
-
jsonOut({ conversations: result.conversations, perAgent: result.perAgent });
|
|
21413
|
+
jsonOut({ conversations: result.conversations, perAgent: result.perAgent, perStore: result.perStore });
|
|
20753
21414
|
return;
|
|
20754
21415
|
}
|
|
20755
21416
|
console.log(bold(days > 0 ? `
|
|
20756
21417
|
Local conversations, last ${days} day(s)` : `
|
|
20757
21418
|
Local conversations (all)`));
|
|
21419
|
+
for (const s of result.perStore) {
|
|
21420
|
+
const reason = describeStoreOutcome(s);
|
|
21421
|
+
if (reason === null)
|
|
21422
|
+
continue;
|
|
21423
|
+
const line = ` ${s.storeId}: ${reason}`;
|
|
21424
|
+
console.log(storeOutcomeNeedsAttention(s) ? yellow(line) : dim(line));
|
|
21425
|
+
}
|
|
20758
21426
|
for (const a of result.perAgent) {
|
|
20759
21427
|
if (a.status === "no-reader")
|
|
20760
21428
|
continue;
|
|
@@ -20780,17 +21448,26 @@ Local conversations (all)`));
|
|
|
20780
21448
|
if (result.conversations.length === 0)
|
|
20781
21449
|
console.log(dim(" none"));
|
|
20782
21450
|
});
|
|
20783
|
-
conversationsCommand.command("status").description("Why each agent did or did not contribute conversations (no conversation data)").option("--days <n>", "
|
|
21451
|
+
conversationsCommand.command("status").description("Why each agent did or did not contribute conversations (no conversation data)").option("--days <n>", "Narrow to this many days (0 = no window, the default)", String(DEFAULT_LOOKBACK_DAYS)).action(async (opts, command) => {
|
|
20784
21452
|
const json = command.optsWithGlobals().json === true || !process.stdout.isTTY;
|
|
20785
21453
|
const days = parseDays(opts.days);
|
|
20786
|
-
const { perAgent } = await listLocalConversations({ sinceISO: sinceFromDays(days) });
|
|
21454
|
+
const { perAgent, perStore } = await listLocalConversations({ sinceISO: sinceFromDays(days) });
|
|
20787
21455
|
if (json) {
|
|
20788
|
-
jsonOut({ perAgent });
|
|
21456
|
+
jsonOut({ perAgent, perStore });
|
|
20789
21457
|
return;
|
|
20790
21458
|
}
|
|
20791
21459
|
console.log(bold(days > 0 ? `
|
|
20792
21460
|
Conversation sources, last ${days} day(s)` : `
|
|
20793
21461
|
Conversation sources`));
|
|
21462
|
+
for (const s of perStore) {
|
|
21463
|
+
const reason = describeStoreOutcome(s);
|
|
21464
|
+
if (reason === null) {
|
|
21465
|
+
console.log(` ${cyan(s.storeId)}: ${s.sessions} conversation(s)`);
|
|
21466
|
+
} else {
|
|
21467
|
+
console.log(` ${cyan(s.storeId)}: ${storeOutcomeNeedsAttention(s) ? yellow(reason) : dim(reason)}`);
|
|
21468
|
+
}
|
|
21469
|
+
}
|
|
21470
|
+
console.log("");
|
|
20794
21471
|
for (const a of perAgent) {
|
|
20795
21472
|
const reason = describeScanOutcome(a);
|
|
20796
21473
|
if (reason === null) {
|
|
@@ -20800,7 +21477,7 @@ Conversation sources`));
|
|
|
20800
21477
|
}
|
|
20801
21478
|
}
|
|
20802
21479
|
});
|
|
20803
|
-
conversationsCommand.command("scan").description("Detect finished conversations (idle threshold) and queue them for reflection").option("--days <n>", "
|
|
21480
|
+
conversationsCommand.command("scan").description("Detect finished conversations (idle threshold) and queue them for reflection").option("--days <n>", "Narrow to this many days (0 = no window, the default)", String(DEFAULT_LOOKBACK_DAYS)).option("--idle-minutes <n>", "Idle threshold that marks a conversation finished", String(DEFAULT_IDLE_MINUTES)).action(async (opts, command) => {
|
|
20804
21481
|
const json = command.optsWithGlobals().json === true || !process.stdout.isTTY;
|
|
20805
21482
|
const days = parseDays(opts.days);
|
|
20806
21483
|
const idleMinutes = Math.max(1, Number(opts.idleMinutes) || DEFAULT_IDLE_MINUTES);
|
|
@@ -20864,9 +21541,10 @@ conversationsCommand.command("scan").description("Detect finished conversations
|
|
|
20864
21541
|
generatedAt: new Date().toISOString(),
|
|
20865
21542
|
idleMinutes,
|
|
20866
21543
|
conversations: [...listed, ...rescued].sort((a, b) => b.lastActivityAt.localeCompare(a.lastActivityAt)),
|
|
20867
|
-
perAgent: result.perAgent
|
|
21544
|
+
perAgent: result.perAgent,
|
|
21545
|
+
perStore: result.perStore
|
|
20868
21546
|
};
|
|
20869
|
-
writeJsonAtomic(
|
|
21547
|
+
writeJsonAtomic(join44(homedir25(), ".runwork", "conversations.json"), snapshot);
|
|
20870
21548
|
if (json) {
|
|
20871
21549
|
jsonOut({ queued: scan.queued, reopened: scan.reopened, pruned: scan.pruned, pending, finished: finished.length, perAgent: result.perAgent });
|
|
20872
21550
|
return;
|
|
@@ -20889,15 +21567,71 @@ conversationsCommand.command("analyze").description("Analyze queued finished con
|
|
|
20889
21567
|
}
|
|
20890
21568
|
console.log(outcome.reason ? dim(describeAnalysisOutcome(outcome)) : green(describeAnalysisOutcome(outcome)));
|
|
20891
21569
|
});
|
|
21570
|
+
conversationsCommand.command("stores").description("Every local transcript store: what is in it, who wrote it, and whether anything reads it").option("--max-files <n>", "Cap transcripts inspected per store", String(DEFAULT_MAX_FILES)).option("--no-markers", "Skip provenance reads; counts, sizes and mtimes only").action(async (opts, command) => {
|
|
21571
|
+
const json = command.optsWithGlobals().json === true || !process.stdout.isTTY;
|
|
21572
|
+
const maxFiles = Math.max(1, Number(opts.maxFiles) || DEFAULT_MAX_FILES);
|
|
21573
|
+
const detected = (await detectAgents()).map((a) => a.slug);
|
|
21574
|
+
const stores = resolveTranscriptStores({
|
|
21575
|
+
platform: platform8(),
|
|
21576
|
+
homeDir: homedir25(),
|
|
21577
|
+
appData: process.env.APPDATA ?? null,
|
|
21578
|
+
localAppData: process.env.LOCALAPPDATA ?? null
|
|
21579
|
+
});
|
|
21580
|
+
const censuses = censusStores(stores, detected, {
|
|
21581
|
+
maxFiles,
|
|
21582
|
+
skipMarkers: opts.markers === false
|
|
21583
|
+
});
|
|
21584
|
+
if (json) {
|
|
21585
|
+
jsonOut({ detected, stores: censuses });
|
|
21586
|
+
return;
|
|
21587
|
+
}
|
|
21588
|
+
console.log(bold(`
|
|
21589
|
+
Transcript stores`));
|
|
21590
|
+
console.log(dim(` detected agents: ${detected.length > 0 ? detected.join(", ") : "none"}
|
|
21591
|
+
`));
|
|
21592
|
+
for (const c of censuses) {
|
|
21593
|
+
const owner = c.unlocked ? green("read") : yellow("ORPHANED");
|
|
21594
|
+
console.log(`${bold(c.storeId)} ${owner} ${dim(`family ${c.family}: ${c.members.join(", ")}`)}`);
|
|
21595
|
+
console.log(dim(` ${c.path}`));
|
|
21596
|
+
if (c.status !== "ok") {
|
|
21597
|
+
console.log(` ${yellow(c.status)}${c.detail ? dim(` (${c.detail})`) : ""}`);
|
|
21598
|
+
} else {
|
|
21599
|
+
const mb = ((c.bytes ?? 0) / 1e6).toFixed(1);
|
|
21600
|
+
const newest = c.newestAt ? c.newestAt.slice(0, 16).replace("T", " ") : "-";
|
|
21601
|
+
const nested = c.nested ? `, plus ${c.nested} subagent transcript(s)` : "";
|
|
21602
|
+
console.log(dim(` ${c.files} conversation(s)${nested}, ${mb} MB, newest ${newest}`));
|
|
21603
|
+
for (const m of c.markers ?? []) {
|
|
21604
|
+
if (m.marker === null) {
|
|
21605
|
+
console.log(` ${String(m.count).padStart(5)} ${dim(`(no marker, pre-dates the field) -> ${m.agentSlug}`)}`);
|
|
21606
|
+
continue;
|
|
21607
|
+
}
|
|
21608
|
+
const flag = m.recognised ? dim(`-> ${m.agentSlug}`) : yellow(`-> ${m.agentSlug} (UNRECOGNISED surface)`);
|
|
21609
|
+
console.log(` ${String(m.count).padStart(5)} ${cyan(m.marker)} ${flag}`);
|
|
21610
|
+
}
|
|
21611
|
+
}
|
|
21612
|
+
for (const alt of c.altHits ?? []) {
|
|
21613
|
+
console.log(` ${yellow("also present:")} ${dim(alt)}`);
|
|
21614
|
+
}
|
|
21615
|
+
console.log("");
|
|
21616
|
+
}
|
|
21617
|
+
const orphans = orphanedStoresWithContent(censuses);
|
|
21618
|
+
if (orphans.length > 0) {
|
|
21619
|
+
console.log(yellow(`${orphans.length} store(s) hold transcripts that no detected agent reads:`));
|
|
21620
|
+
for (const o of orphans) {
|
|
21621
|
+
console.log(` ${o.path} ${dim(`(${o.files} transcripts; needs one of: ${o.members.join(", ")})`)}`);
|
|
21622
|
+
}
|
|
21623
|
+
console.log("");
|
|
21624
|
+
}
|
|
21625
|
+
});
|
|
20892
21626
|
|
|
20893
21627
|
// src/commands/instructions.ts
|
|
20894
21628
|
init_store();
|
|
20895
21629
|
init_client();
|
|
20896
21630
|
init_resolve();
|
|
20897
21631
|
import { Command as Command16 } from "commander";
|
|
20898
|
-
import { readFileSync as
|
|
20899
|
-
import { join as
|
|
20900
|
-
import { homedir as
|
|
21632
|
+
import { readFileSync as readFileSync38, existsSync as existsSync49 } from "fs";
|
|
21633
|
+
import { join as join45 } from "path";
|
|
21634
|
+
import { homedir as homedir26 } from "os";
|
|
20901
21635
|
|
|
20902
21636
|
// ../../shared/agent-instructions/runwork-instructions.ts
|
|
20903
21637
|
function formatList(items, max = 8) {
|
|
@@ -21240,7 +21974,7 @@ function generateIntroSkill(ctx) {
|
|
|
21240
21974
|
lines.push("| `runwork entities list` | Browse data across apps |");
|
|
21241
21975
|
lines.push("| `runwork entities records <name>` | Query entity records |");
|
|
21242
21976
|
lines.push("| `runwork workflows trigger <name>` | Trigger a workflow |");
|
|
21243
|
-
lines.push("| `runwork integrations call <id> <method> <path>` | Call an integration API |");
|
|
21977
|
+
lines.push("| `runwork integrations call <id> <method> <path>` | Call an integration API (`--body` JSON; `--form` for form-encoded APIs such as Stripe) |");
|
|
21244
21978
|
lines.push("| `runwork integrations search <query>` | Search 3,200+ available integrations |");
|
|
21245
21979
|
lines.push("| `runwork logs` | View app logs |");
|
|
21246
21980
|
lines.push("| `runwork doctor` | Check system health (`--fix` auto-remediates git auth/remote; `--check <names>` scopes output) |");
|
|
@@ -21377,13 +22111,13 @@ async function buildInstructionContext(client, workspace) {
|
|
|
21377
22111
|
// src/commands/instructions.ts
|
|
21378
22112
|
function readSetupExtras(workspaceId) {
|
|
21379
22113
|
for (const path2 of [
|
|
21380
|
-
|
|
21381
|
-
|
|
22114
|
+
join45(process.cwd(), ".runwork", "setup.json"),
|
|
22115
|
+
join45(homedir26(), ".runwork", "setup.json")
|
|
21382
22116
|
]) {
|
|
21383
|
-
if (!
|
|
22117
|
+
if (!existsSync49(path2))
|
|
21384
22118
|
continue;
|
|
21385
22119
|
try {
|
|
21386
|
-
const state = JSON.parse(
|
|
22120
|
+
const state = JSON.parse(readFileSync38(path2, "utf-8"));
|
|
21387
22121
|
if (state.workspaceId === workspaceId) {
|
|
21388
22122
|
return { workspaceSlug: state.workspaceSlug, persona: state.persona };
|
|
21389
22123
|
}
|
|
@@ -21427,16 +22161,16 @@ import { Command as Command17 } from "commander";
|
|
|
21427
22161
|
import * as path3 from "node:path";
|
|
21428
22162
|
|
|
21429
22163
|
// src/utils/data-input.ts
|
|
21430
|
-
import { readFileSync as
|
|
22164
|
+
import { readFileSync as readFileSync39, existsSync as existsSync50 } from "fs";
|
|
21431
22165
|
async function parseDataInput(dataFlag) {
|
|
21432
22166
|
if (dataFlag) {
|
|
21433
22167
|
if (dataFlag.startsWith("@")) {
|
|
21434
22168
|
const filePath = dataFlag.slice(1);
|
|
21435
|
-
if (!
|
|
22169
|
+
if (!existsSync50(filePath)) {
|
|
21436
22170
|
console.error(`File not found: ${filePath}`);
|
|
21437
22171
|
process.exit(1);
|
|
21438
22172
|
}
|
|
21439
|
-
const content =
|
|
22173
|
+
const content = readFileSync39(filePath, "utf-8");
|
|
21440
22174
|
return parseJson(content, filePath);
|
|
21441
22175
|
}
|
|
21442
22176
|
return parseJson(dataFlag, "--data");
|
|
@@ -22490,7 +23224,7 @@ init_resolve();
|
|
|
22490
23224
|
init_prompt();
|
|
22491
23225
|
init_http();
|
|
22492
23226
|
import { Command as Command21 } from "commander";
|
|
22493
|
-
import { writeFileSync as writeFileSync29, readFileSync as
|
|
23227
|
+
import { writeFileSync as writeFileSync29, readFileSync as readFileSync40 } from "fs";
|
|
22494
23228
|
import { basename as basename6 } from "path";
|
|
22495
23229
|
function formatSize(bytes) {
|
|
22496
23230
|
if (bytes === undefined)
|
|
@@ -22600,7 +23334,7 @@ var uploadCommand = new Command21("upload").description("Upload a local file to
|
|
|
22600
23334
|
const { workspaceId } = await resolveWorkspace2(client, opts);
|
|
22601
23335
|
const objectKey = key || basename6(localPath);
|
|
22602
23336
|
try {
|
|
22603
|
-
const fileBuffer =
|
|
23337
|
+
const fileBuffer = readFileSync40(localPath);
|
|
22604
23338
|
const { url } = await client.getPresignedUrl(workspaceId, bucket, { action: "write", key: objectKey });
|
|
22605
23339
|
const response = await httpFetch(url, { method: "PUT", body: fileBuffer });
|
|
22606
23340
|
if (!response.ok) {
|
|
@@ -23117,8 +23851,8 @@ init_resolve();
|
|
|
23117
23851
|
init_prompt();
|
|
23118
23852
|
await init_detect();
|
|
23119
23853
|
import { Command as Command27 } from "commander";
|
|
23120
|
-
import { join as
|
|
23121
|
-
import { homedir as
|
|
23854
|
+
import { join as join50 } from "path";
|
|
23855
|
+
import { homedir as homedir29 } from "os";
|
|
23122
23856
|
|
|
23123
23857
|
// src/commands/sync.ts
|
|
23124
23858
|
init_store();
|
|
@@ -23129,9 +23863,9 @@ await __promiseAll([
|
|
|
23129
23863
|
init_codex()
|
|
23130
23864
|
]);
|
|
23131
23865
|
import { Command as Command26 } from "commander";
|
|
23132
|
-
import { readFileSync as
|
|
23133
|
-
import { join as
|
|
23134
|
-
import { homedir as
|
|
23866
|
+
import { readFileSync as readFileSync42, existsSync as existsSync53 } from "fs";
|
|
23867
|
+
import { join as join49 } from "path";
|
|
23868
|
+
import { homedir as homedir28 } from "os";
|
|
23135
23869
|
|
|
23136
23870
|
// src/commands/mcp-entries.ts
|
|
23137
23871
|
init_types();
|
|
@@ -23195,6 +23929,7 @@ var RUNWORK_AGENT_DEFAULTS = {
|
|
|
23195
23929
|
};
|
|
23196
23930
|
var AGENT_DEFAULTS_SCHEMA_VERSION = 1;
|
|
23197
23931
|
// src/commands/sync-telemetry.ts
|
|
23932
|
+
init_transcript_stores();
|
|
23198
23933
|
var TELEMETRY_BACKFILL_MS = 30 * 24 * 60 * 60 * 1000;
|
|
23199
23934
|
function resolveTelemetrySince(state, nowMs = Date.now()) {
|
|
23200
23935
|
if (state.lastTelemetryAt)
|
|
@@ -23205,11 +23940,20 @@ async function collectTelemetryEvents(params) {
|
|
|
23205
23940
|
const now = params.now ?? new Date().toISOString();
|
|
23206
23941
|
const events = [];
|
|
23207
23942
|
const adapterResults = [];
|
|
23943
|
+
const bySlug = new Map(params.adapters.map((a) => [a.slug, a]));
|
|
23944
|
+
const suppressed = suppressedStoreReaders(params.adapters.map((a) => a.slug), (a, b) => {
|
|
23945
|
+
const left = bySlug.get(a);
|
|
23946
|
+
const right = bySlug.get(b);
|
|
23947
|
+
if (!left || !right)
|
|
23948
|
+
return false;
|
|
23949
|
+
return left.readUsageStats !== undefined && left.readUsageStats === right.readUsageStats || left.readSkillUsage !== undefined && left.readSkillUsage === right.readSkillUsage;
|
|
23950
|
+
});
|
|
23208
23951
|
for (const adapter2 of params.adapters) {
|
|
23209
23952
|
let stats = "unsupported";
|
|
23210
23953
|
let skills = "unsupported";
|
|
23211
23954
|
let error;
|
|
23212
|
-
|
|
23955
|
+
const readsStore = !suppressed.has(adapter2.slug);
|
|
23956
|
+
if (adapter2.readUsageStats && readsStore) {
|
|
23213
23957
|
try {
|
|
23214
23958
|
stats = await adapter2.readUsageStats(params.since);
|
|
23215
23959
|
if (stats && stats.hasNewActivity) {
|
|
@@ -23237,7 +23981,7 @@ async function collectTelemetryEvents(params) {
|
|
|
23237
23981
|
stats = null;
|
|
23238
23982
|
}
|
|
23239
23983
|
}
|
|
23240
|
-
if (adapter2.readSkillUsage) {
|
|
23984
|
+
if (adapter2.readSkillUsage && readsStore) {
|
|
23241
23985
|
try {
|
|
23242
23986
|
skills = await adapter2.readSkillUsage(params.since);
|
|
23243
23987
|
if (skills && skills.length > 0) {
|
|
@@ -24013,10 +24757,10 @@ function sameStringSet(a, b) {
|
|
|
24013
24757
|
}
|
|
24014
24758
|
|
|
24015
24759
|
// src/utils/sync-lock.ts
|
|
24016
|
-
import { existsSync as
|
|
24017
|
-
import { join as
|
|
24018
|
-
import { homedir as
|
|
24019
|
-
var LOCK_PATH =
|
|
24760
|
+
import { existsSync as existsSync52, mkdirSync as mkdirSync28, readFileSync as readFileSync41, unlinkSync as unlinkSync8, writeFileSync as writeFileSync30 } from "fs";
|
|
24761
|
+
import { join as join48 } from "path";
|
|
24762
|
+
import { homedir as homedir27 } from "os";
|
|
24763
|
+
var LOCK_PATH = join48(homedir27(), ".runwork", "sync.lock");
|
|
24020
24764
|
var STALE_LOCK_MS = 5 * 60 * 1000;
|
|
24021
24765
|
var DEFAULT_WAIT_MS = 30000;
|
|
24022
24766
|
var exitHandlerRegistered = false;
|
|
@@ -24036,15 +24780,15 @@ function isProcessAlive(pid) {
|
|
|
24036
24780
|
}
|
|
24037
24781
|
function readLock() {
|
|
24038
24782
|
try {
|
|
24039
|
-
return JSON.parse(
|
|
24783
|
+
return JSON.parse(readFileSync41(LOCK_PATH, "utf-8"));
|
|
24040
24784
|
} catch {
|
|
24041
24785
|
return null;
|
|
24042
24786
|
}
|
|
24043
24787
|
}
|
|
24044
24788
|
function writeLockExclusive() {
|
|
24045
24789
|
try {
|
|
24046
|
-
if (!
|
|
24047
|
-
mkdirSync28(
|
|
24790
|
+
if (!existsSync52(join48(homedir27(), ".runwork"))) {
|
|
24791
|
+
mkdirSync28(join48(homedir27(), ".runwork"), { recursive: true });
|
|
24048
24792
|
}
|
|
24049
24793
|
writeFileSync30(LOCK_PATH, JSON.stringify({ pid: process.pid, startedAt: Date.now() }), {
|
|
24050
24794
|
flag: "wx"
|
|
@@ -24113,10 +24857,10 @@ Tip: ${hint.title}`);
|
|
|
24113
24857
|
} catch {}
|
|
24114
24858
|
}
|
|
24115
24859
|
function loadSetupState(filePath) {
|
|
24116
|
-
if (!
|
|
24860
|
+
if (!existsSync53(filePath))
|
|
24117
24861
|
return null;
|
|
24118
24862
|
try {
|
|
24119
|
-
return JSON.parse(
|
|
24863
|
+
return JSON.parse(readFileSync42(filePath, "utf-8"));
|
|
24120
24864
|
} catch {
|
|
24121
24865
|
return null;
|
|
24122
24866
|
}
|
|
@@ -24137,15 +24881,15 @@ function readLocalSkills(state) {
|
|
|
24137
24881
|
if (!baseDir)
|
|
24138
24882
|
continue;
|
|
24139
24883
|
for (const skillName of state.skills) {
|
|
24140
|
-
const skillMdPath =
|
|
24141
|
-
if (
|
|
24142
|
-
results.push({ name: skillName, content:
|
|
24884
|
+
const skillMdPath = join49(baseDir, skillName, "SKILL.md");
|
|
24885
|
+
if (existsSync53(skillMdPath)) {
|
|
24886
|
+
results.push({ name: skillName, content: readFileSync42(skillMdPath, "utf-8") });
|
|
24143
24887
|
continue;
|
|
24144
24888
|
}
|
|
24145
24889
|
const filename = skillName.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
24146
|
-
const flatPath =
|
|
24147
|
-
if (
|
|
24148
|
-
results.push({ name: skillName, content:
|
|
24890
|
+
const flatPath = join49(baseDir, `${filename}.md`);
|
|
24891
|
+
if (existsSync53(flatPath)) {
|
|
24892
|
+
results.push({ name: skillName, content: readFileSync42(flatPath, "utf-8") });
|
|
24149
24893
|
}
|
|
24150
24894
|
}
|
|
24151
24895
|
if (results.length > 0)
|
|
@@ -24399,9 +25143,9 @@ This account is not a member of "${state.workspaceName || state.workspaceId}".`)
|
|
|
24399
25143
|
persona: state.persona
|
|
24400
25144
|
});
|
|
24401
25145
|
let projectAppSkillFilter = null;
|
|
24402
|
-
if (
|
|
25146
|
+
if (existsSync53(".runwork.json")) {
|
|
24403
25147
|
try {
|
|
24404
|
-
const config = JSON.parse(
|
|
25148
|
+
const config = JSON.parse(readFileSync42(".runwork.json", "utf-8"));
|
|
24405
25149
|
if (config.appName) {
|
|
24406
25150
|
projectAppSkillFilter = config.appName.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
24407
25151
|
}
|
|
@@ -24670,7 +25414,7 @@ This account is not a member of "${state.workspaceName || state.workspaceId}".`)
|
|
|
24670
25414
|
}
|
|
24671
25415
|
for (const adapter2 of adapters) {
|
|
24672
25416
|
if (adapter2 instanceof CodexAdapter) {
|
|
24673
|
-
const runworkDir =
|
|
25417
|
+
const runworkDir = join49(homedir28(), ".runwork");
|
|
24674
25418
|
const result = adapter2.registerDesktopWorkspace(runworkDir, "Runwork");
|
|
24675
25419
|
if (result === "written") {
|
|
24676
25420
|
vlog(` [${adapter2.name}] Registered workspace in Codex desktop app`);
|
|
@@ -24830,8 +25574,8 @@ var syncCommand = new Command26("sync").description("Sync skills bidirectionally
|
|
|
24830
25574
|
verbose: !!opts.verbose,
|
|
24831
25575
|
redetect: !!opts.redetect
|
|
24832
25576
|
};
|
|
24833
|
-
const projectStatePath =
|
|
24834
|
-
const userStatePath =
|
|
25577
|
+
const projectStatePath = join49(process.cwd(), ".runwork", "setup.json");
|
|
25578
|
+
const userStatePath = join49(homedir28(), ".runwork", "setup.json");
|
|
24835
25579
|
const projectState = loadSetupState(projectStatePath);
|
|
24836
25580
|
const userState = loadSetupState(userStatePath);
|
|
24837
25581
|
if (!projectState && !userState) {
|
|
@@ -24900,7 +25644,7 @@ function toSkillFilename(name) {
|
|
|
24900
25644
|
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
24901
25645
|
}
|
|
24902
25646
|
function loadSetupStateForScope(scope) {
|
|
24903
|
-
const path4 = scope === "project" ?
|
|
25647
|
+
const path4 = scope === "project" ? join50(process.cwd(), ".runwork", "setup.json") : join50(homedir29(), ".runwork", "setup.json");
|
|
24904
25648
|
return readJsonOrNull(path4);
|
|
24905
25649
|
}
|
|
24906
25650
|
async function parkAndTeardownWorkspace(previous, scopes) {
|
|
@@ -25069,8 +25813,8 @@ Re-run without --dry-run to sync workspace data.`);
|
|
|
25069
25813
|
}
|
|
25070
25814
|
persistDefaultWorkspace(workspaceId, workspaceName);
|
|
25071
25815
|
for (const s of scopes) {
|
|
25072
|
-
const dir = s === "project" ? ".runwork" :
|
|
25073
|
-
writeJsonAtomic(
|
|
25816
|
+
const dir = s === "project" ? ".runwork" : join50(homedir29(), ".runwork");
|
|
25817
|
+
writeJsonAtomic(join50(dir, "setup.json"), state);
|
|
25074
25818
|
}
|
|
25075
25819
|
if (restored)
|
|
25076
25820
|
clearParkedState(workspaceId);
|
|
@@ -25078,7 +25822,7 @@ Re-run without --dry-run to sync workspace data.`);
|
|
|
25078
25822
|
Syncing workspace data...
|
|
25079
25823
|
`);
|
|
25080
25824
|
for (const s of scopes) {
|
|
25081
|
-
const statePath2 = s === "project" ?
|
|
25825
|
+
const statePath2 = s === "project" ? join50(process.cwd(), ".runwork", "setup.json") : join50(homedir29(), ".runwork", "setup.json");
|
|
25082
25826
|
await syncFromState(state, statePath2, credentials, {
|
|
25083
25827
|
dryRun: false,
|
|
25084
25828
|
pullOnly: true,
|
|
@@ -25098,16 +25842,16 @@ init_client();
|
|
|
25098
25842
|
import { Command as Command28 } from "commander";
|
|
25099
25843
|
|
|
25100
25844
|
// src/utils/setup-state.ts
|
|
25101
|
-
import { existsSync as
|
|
25102
|
-
import { join as
|
|
25103
|
-
import { homedir as
|
|
25845
|
+
import { existsSync as existsSync54, readFileSync as readFileSync43 } from "fs";
|
|
25846
|
+
import { join as join51 } from "path";
|
|
25847
|
+
import { homedir as homedir30 } from "os";
|
|
25104
25848
|
function loadSetupState2() {
|
|
25105
|
-
const projectPath =
|
|
25106
|
-
const userPath =
|
|
25849
|
+
const projectPath = join51(process.cwd(), ".runwork", "setup.json");
|
|
25850
|
+
const userPath = join51(homedir30(), ".runwork", "setup.json");
|
|
25107
25851
|
for (const p of [projectPath, userPath]) {
|
|
25108
|
-
if (
|
|
25852
|
+
if (existsSync54(p)) {
|
|
25109
25853
|
try {
|
|
25110
|
-
return JSON.parse(
|
|
25854
|
+
return JSON.parse(readFileSync43(p, "utf-8"));
|
|
25111
25855
|
} catch {
|
|
25112
25856
|
continue;
|
|
25113
25857
|
}
|
|
@@ -25166,14 +25910,14 @@ init_client();
|
|
|
25166
25910
|
init_types();
|
|
25167
25911
|
await init_detect();
|
|
25168
25912
|
import { Command as Command29 } from "commander";
|
|
25169
|
-
import { existsSync as
|
|
25170
|
-
import { resolve as resolve3, join as
|
|
25171
|
-
import { homedir as
|
|
25913
|
+
import { existsSync as existsSync55, readFileSync as readFileSync44 } from "fs";
|
|
25914
|
+
import { resolve as resolve3, join as join52 } from "path";
|
|
25915
|
+
import { homedir as homedir31 } from "os";
|
|
25172
25916
|
function loadSetupState3(filePath) {
|
|
25173
|
-
if (!
|
|
25917
|
+
if (!existsSync55(filePath))
|
|
25174
25918
|
return null;
|
|
25175
25919
|
try {
|
|
25176
|
-
return JSON.parse(
|
|
25920
|
+
return JSON.parse(readFileSync44(filePath, "utf-8"));
|
|
25177
25921
|
} catch {
|
|
25178
25922
|
return null;
|
|
25179
25923
|
}
|
|
@@ -25189,8 +25933,8 @@ var buildPluginCommand = new Command29("build-plugin").description("Build an ins
|
|
|
25189
25933
|
process.exit(1);
|
|
25190
25934
|
}
|
|
25191
25935
|
const credentials = requireAuth();
|
|
25192
|
-
const projectStatePath =
|
|
25193
|
-
const userStatePath =
|
|
25936
|
+
const projectStatePath = join52(process.cwd(), ".runwork", "setup.json");
|
|
25937
|
+
const userStatePath = join52(homedir31(), ".runwork", "setup.json");
|
|
25194
25938
|
const state = loadSetupState3(projectStatePath) ?? loadSetupState3(userStatePath);
|
|
25195
25939
|
if (!state) {
|
|
25196
25940
|
console.error("No setup state found. Run `runwork setup` first.");
|
|
@@ -25283,14 +26027,14 @@ init_prompt();
|
|
|
25283
26027
|
init_subprocess();
|
|
25284
26028
|
await init_detect();
|
|
25285
26029
|
import { Command as Command30 } from "commander";
|
|
25286
|
-
import { existsSync as
|
|
25287
|
-
import { join as
|
|
25288
|
-
import { homedir as
|
|
26030
|
+
import { existsSync as existsSync56, readFileSync as readFileSync45, writeFileSync as writeFileSync32, readdirSync as readdirSync17, rmSync as rmSync12, unlinkSync as unlinkSync9, lstatSync, readlinkSync } from "fs";
|
|
26031
|
+
import { join as join53, resolve as resolve4, relative as relative5, isAbsolute as isAbsolute5 } from "path";
|
|
26032
|
+
import { homedir as homedir32 } from "os";
|
|
25289
26033
|
function loadSetupState4(filePath) {
|
|
25290
|
-
if (!
|
|
26034
|
+
if (!existsSync56(filePath))
|
|
25291
26035
|
return null;
|
|
25292
26036
|
try {
|
|
25293
|
-
return JSON.parse(
|
|
26037
|
+
return JSON.parse(readFileSync45(filePath, "utf-8"));
|
|
25294
26038
|
} catch {
|
|
25295
26039
|
return null;
|
|
25296
26040
|
}
|
|
@@ -25298,22 +26042,22 @@ function loadSetupState4(filePath) {
|
|
|
25298
26042
|
var PRESERVED_ENTRIES = ["bin", "apps", "trash"];
|
|
25299
26043
|
function removeRunworkState(stateDir, opts) {
|
|
25300
26044
|
const result = { removed: [], preserved: [], errors: [] };
|
|
25301
|
-
if (!
|
|
26045
|
+
if (!existsSync56(stateDir))
|
|
25302
26046
|
return result;
|
|
25303
26047
|
const preserve = new Set(PRESERVED_ENTRIES);
|
|
25304
26048
|
if (opts.keepAuth)
|
|
25305
26049
|
preserve.add(".credentials");
|
|
25306
26050
|
let entries;
|
|
25307
26051
|
try {
|
|
25308
|
-
entries =
|
|
26052
|
+
entries = readdirSync17(stateDir);
|
|
25309
26053
|
} catch (err) {
|
|
25310
26054
|
result.errors.push(`${stateDir}: ${err instanceof Error ? err.message : err}`);
|
|
25311
26055
|
return result;
|
|
25312
26056
|
}
|
|
25313
26057
|
for (const entry of entries) {
|
|
25314
|
-
const target =
|
|
26058
|
+
const target = join53(stateDir, entry);
|
|
25315
26059
|
if (preserve.has(entry)) {
|
|
25316
|
-
if (
|
|
26060
|
+
if (existsSync56(target))
|
|
25317
26061
|
result.preserved.push(target);
|
|
25318
26062
|
continue;
|
|
25319
26063
|
}
|
|
@@ -25329,11 +26073,11 @@ function removeRunworkState(stateDir, opts) {
|
|
|
25329
26073
|
var SHELL_PROFILES = [".zshrc", ".zprofile", ".bashrc", ".bash_profile", ".profile"];
|
|
25330
26074
|
var BIN_DIR_PATTERN = /\.runwork[\\/]bin/;
|
|
25331
26075
|
function stripRunworkPathLines(file) {
|
|
25332
|
-
if (!
|
|
26076
|
+
if (!existsSync56(file))
|
|
25333
26077
|
return false;
|
|
25334
26078
|
let content;
|
|
25335
26079
|
try {
|
|
25336
|
-
content =
|
|
26080
|
+
content = readFileSync45(file, "utf-8");
|
|
25337
26081
|
} catch {
|
|
25338
26082
|
return false;
|
|
25339
26083
|
}
|
|
@@ -25362,7 +26106,7 @@ function stripRunworkPathLines(file) {
|
|
|
25362
26106
|
}
|
|
25363
26107
|
}
|
|
25364
26108
|
function cleanShellProfilePathEntries() {
|
|
25365
|
-
return SHELL_PROFILES.map((name) =>
|
|
26109
|
+
return SHELL_PROFILES.map((name) => join53(homedir32(), name)).filter(stripRunworkPathLines);
|
|
25366
26110
|
}
|
|
25367
26111
|
function cleanPowerShellProfilePathEntries() {
|
|
25368
26112
|
if (process.platform !== "win32")
|
|
@@ -25402,7 +26146,7 @@ function removeRunworkSymlink(linkPath) {
|
|
|
25402
26146
|
} catch {
|
|
25403
26147
|
return false;
|
|
25404
26148
|
}
|
|
25405
|
-
const ours = resolve4(
|
|
26149
|
+
const ours = resolve4(join53(homedir32(), ".runwork", "bin"));
|
|
25406
26150
|
const rel = relative5(ours, resolve4(target));
|
|
25407
26151
|
const insideOurs = rel === "" || !rel.startsWith("..") && !isAbsolute5(rel);
|
|
25408
26152
|
if (!insideOurs)
|
|
@@ -25415,8 +26159,8 @@ function removeRunworkSymlink(linkPath) {
|
|
|
25415
26159
|
}
|
|
25416
26160
|
}
|
|
25417
26161
|
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) => {
|
|
25418
|
-
const projectStatePath =
|
|
25419
|
-
const userStatePath =
|
|
26162
|
+
const projectStatePath = join53(process.cwd(), ".runwork", "setup.json");
|
|
26163
|
+
const userStatePath = join53(homedir32(), ".runwork", "setup.json");
|
|
25420
26164
|
const projectState = loadSetupState4(projectStatePath);
|
|
25421
26165
|
const userState = loadSetupState4(userStatePath);
|
|
25422
26166
|
if (!projectState && !userState) {
|
|
@@ -25503,8 +26247,8 @@ This will remove all Runwork configuration from your local agents:
|
|
|
25503
26247
|
}
|
|
25504
26248
|
}
|
|
25505
26249
|
}
|
|
25506
|
-
const stateDir = label === "project" ?
|
|
25507
|
-
if (
|
|
26250
|
+
const stateDir = label === "project" ? join53(process.cwd(), ".runwork") : join53(homedir32(), ".runwork");
|
|
26251
|
+
if (existsSync56(stateDir)) {
|
|
25508
26252
|
const outcome = removeRunworkState(stateDir, {
|
|
25509
26253
|
keepAuth: Boolean(opts.keepAuth) && label === "user"
|
|
25510
26254
|
});
|
|
@@ -25534,7 +26278,7 @@ This will remove all Runwork configuration from your local agents:
|
|
|
25534
26278
|
console.log(` - ${file}`);
|
|
25535
26279
|
}
|
|
25536
26280
|
const removedLinks = [
|
|
25537
|
-
|
|
26281
|
+
join53(homedir32(), ".local", "bin", "runwork"),
|
|
25538
26282
|
"/usr/local/bin/runwork"
|
|
25539
26283
|
].filter(removeRunworkSymlink);
|
|
25540
26284
|
if (removedLinks.length > 0) {
|
|
@@ -25546,7 +26290,7 @@ This will remove all Runwork configuration from your local agents:
|
|
|
25546
26290
|
if (process.platform === "win32") {
|
|
25547
26291
|
console.log("");
|
|
25548
26292
|
console.log(" Still on your PATH (remove by hand if you want it gone):");
|
|
25549
|
-
console.log(` ${
|
|
26293
|
+
console.log(` ${join53(homedir32(), ".runwork", "bin")} in your user PATH`);
|
|
25550
26294
|
}
|
|
25551
26295
|
console.log("");
|
|
25552
26296
|
if (errors > 0) {
|
|
@@ -25672,7 +26416,7 @@ var membersCommand = new Command32("members").description("List workspace member
|
|
|
25672
26416
|
init_store();
|
|
25673
26417
|
init_client();
|
|
25674
26418
|
import { Command as Command33 } from "commander";
|
|
25675
|
-
import { readFileSync as
|
|
26419
|
+
import { readFileSync as readFileSync46 } from "fs";
|
|
25676
26420
|
function normalizeApiPath(rawPath, baseUrl) {
|
|
25677
26421
|
if (/^https?:\/\//i.test(rawPath)) {
|
|
25678
26422
|
const target = new URL(rawPath);
|
|
@@ -25705,7 +26449,7 @@ to be read or pasted manually. Prefer a dedicated command when one exists
|
|
|
25705
26449
|
let curlStr = opts.curl;
|
|
25706
26450
|
if (opts.curlFile) {
|
|
25707
26451
|
try {
|
|
25708
|
-
curlStr =
|
|
26452
|
+
curlStr = readFileSync46(opts.curlFile, "utf-8");
|
|
25709
26453
|
} catch (err) {
|
|
25710
26454
|
console.error(`Could not read --curl-file: ${err instanceof Error ? err.message : err}`);
|
|
25711
26455
|
process.exit(1);
|
|
@@ -25725,7 +26469,7 @@ to be read or pasted manually. Prefer a dedicated command when one exists
|
|
|
25725
26469
|
let raw = opts.body;
|
|
25726
26470
|
if (raw.startsWith("@")) {
|
|
25727
26471
|
try {
|
|
25728
|
-
raw =
|
|
26472
|
+
raw = readFileSync46(raw.slice(1), "utf-8");
|
|
25729
26473
|
} catch (err) {
|
|
25730
26474
|
console.error(`Could not read body file: ${err instanceof Error ? err.message : err}`);
|
|
25731
26475
|
process.exit(1);
|
|
@@ -25779,9 +26523,9 @@ init_preflight();
|
|
|
25779
26523
|
init_credentials();
|
|
25780
26524
|
await init_detect();
|
|
25781
26525
|
import { parse as parse2 } from "smol-toml";
|
|
25782
|
-
import { existsSync as
|
|
25783
|
-
import { join as
|
|
25784
|
-
import { homedir as
|
|
26526
|
+
import { existsSync as existsSync57, readFileSync as readFileSync47 } from "fs";
|
|
26527
|
+
import { join as join54, sep as sep4 } from "path";
|
|
26528
|
+
import { homedir as homedir33, platform as osPlatform2, arch as osArch } from "os";
|
|
25785
26529
|
var BASE_URL2 = process.env.RUNWORK_DOWNLOAD_BASE_URL || "https://runwork.ai";
|
|
25786
26530
|
var LATEST_JSON_URL2 = `${BASE_URL2}/cli/latest.json`;
|
|
25787
26531
|
function detectPlatform() {
|
|
@@ -25809,10 +26553,10 @@ function buildContext() {
|
|
|
25809
26553
|
const credentials = getCredentials();
|
|
25810
26554
|
const client = credentials ? new ApiClient(credentials) : null;
|
|
25811
26555
|
let config = null;
|
|
25812
|
-
const configPath =
|
|
25813
|
-
if (
|
|
26556
|
+
const configPath = join54(process.cwd(), ".runwork.json");
|
|
26557
|
+
if (existsSync57(configPath)) {
|
|
25814
26558
|
try {
|
|
25815
|
-
config = JSON.parse(
|
|
26559
|
+
config = JSON.parse(readFileSync47(configPath, "utf-8"));
|
|
25816
26560
|
} catch {}
|
|
25817
26561
|
}
|
|
25818
26562
|
return { credentials, client, config, cwd: process.cwd() };
|
|
@@ -25866,8 +26610,8 @@ async function checkCliVersion() {
|
|
|
25866
26610
|
};
|
|
25867
26611
|
}
|
|
25868
26612
|
async function checkCliArtifactReachable() {
|
|
25869
|
-
const
|
|
25870
|
-
if (!
|
|
26613
|
+
const platform9 = detectPlatform();
|
|
26614
|
+
if (!platform9.key) {
|
|
25871
26615
|
return {
|
|
25872
26616
|
name: "cli-artifact",
|
|
25873
26617
|
status: "skip",
|
|
@@ -25883,12 +26627,12 @@ async function checkCliArtifactReachable() {
|
|
|
25883
26627
|
fix: "check network / outbound access to runwork.ai"
|
|
25884
26628
|
};
|
|
25885
26629
|
}
|
|
25886
|
-
const entry = manifest.artifacts?.[
|
|
26630
|
+
const entry = manifest.artifacts?.[platform9.key];
|
|
25887
26631
|
if (!entry?.path) {
|
|
25888
26632
|
return {
|
|
25889
26633
|
name: "cli-artifact",
|
|
25890
26634
|
status: "fail",
|
|
25891
|
-
message: `manifest has no artifact for ${
|
|
26635
|
+
message: `manifest has no artifact for ${platform9.key}`
|
|
25892
26636
|
};
|
|
25893
26637
|
}
|
|
25894
26638
|
const artifactUrl = `${BASE_URL2}${entry.path}`;
|
|
@@ -25901,7 +26645,7 @@ async function checkCliArtifactReachable() {
|
|
|
25901
26645
|
message: `${artifactUrl} returned HTTP ${response.status}`
|
|
25902
26646
|
};
|
|
25903
26647
|
}
|
|
25904
|
-
return { name: "cli-artifact", status: "pass", message: `${
|
|
26648
|
+
return { name: "cli-artifact", status: "pass", message: `${platform9.key} reachable` };
|
|
25905
26649
|
} catch (err) {
|
|
25906
26650
|
const msg = err instanceof Error ? err.message : String(err);
|
|
25907
26651
|
return {
|
|
@@ -25913,9 +26657,9 @@ async function checkCliArtifactReachable() {
|
|
|
25913
26657
|
}
|
|
25914
26658
|
async function checkCliInstallLocation() {
|
|
25915
26659
|
const isWindows2 = osPlatform2() === "win32";
|
|
25916
|
-
const
|
|
25917
|
-
const canonicalDir =
|
|
25918
|
-
const canonicalBinary = isWindows2 ?
|
|
26660
|
+
const home2 = homedir33();
|
|
26661
|
+
const canonicalDir = join54(home2, ".runwork", "bin");
|
|
26662
|
+
const canonicalBinary = isWindows2 ? join54(canonicalDir, "runwork.exe") : join54(canonicalDir, "runwork");
|
|
25919
26663
|
const candidates = [process.execPath, process.argv[1] || ""].filter(Boolean);
|
|
25920
26664
|
const runsFromCanonical = candidates.some((p) => normalizePath(p) === normalizePath(canonicalBinary));
|
|
25921
26665
|
if (runsFromCanonical) {
|
|
@@ -25925,7 +26669,7 @@ async function checkCliInstallLocation() {
|
|
|
25925
26669
|
message: `canonical (${canonicalBinary})`
|
|
25926
26670
|
};
|
|
25927
26671
|
}
|
|
25928
|
-
if (
|
|
26672
|
+
if (existsSync57(canonicalBinary)) {
|
|
25929
26673
|
return {
|
|
25930
26674
|
name: "cli-install-location",
|
|
25931
26675
|
status: "warn",
|
|
@@ -26058,8 +26802,8 @@ async function checkGitCredentialHelper(ctx) {
|
|
|
26058
26802
|
};
|
|
26059
26803
|
}
|
|
26060
26804
|
async function checkProjectConfig(ctx) {
|
|
26061
|
-
const configPath =
|
|
26062
|
-
if (!
|
|
26805
|
+
const configPath = join54(ctx.cwd, ".runwork.json");
|
|
26806
|
+
if (!existsSync57(configPath)) {
|
|
26063
26807
|
if (!ctx.credentials) {
|
|
26064
26808
|
return { name: "project-config", status: "skip", message: "no project (not logged in)" };
|
|
26065
26809
|
}
|
|
@@ -26121,7 +26865,7 @@ async function checkGitRemote(ctx) {
|
|
|
26121
26865
|
if (!ctx.config) {
|
|
26122
26866
|
return { name: "git-remote", status: "skip", message: "skipped (no project)" };
|
|
26123
26867
|
}
|
|
26124
|
-
if (!
|
|
26868
|
+
if (!existsSync57(join54(ctx.cwd, ".git"))) {
|
|
26125
26869
|
return {
|
|
26126
26870
|
name: "git-remote",
|
|
26127
26871
|
status: "fail",
|
|
@@ -26175,12 +26919,12 @@ async function checkDeployFreshness(ctx) {
|
|
|
26175
26919
|
return { name: "deploy-freshness", status: "skip", message: "local HEAD unknown" };
|
|
26176
26920
|
}
|
|
26177
26921
|
function loadSetupState5() {
|
|
26178
|
-
const projectPath =
|
|
26179
|
-
const userPath =
|
|
26922
|
+
const projectPath = join54(process.cwd(), ".runwork", "setup.json");
|
|
26923
|
+
const userPath = join54(homedir33(), ".runwork", "setup.json");
|
|
26180
26924
|
for (const p of [projectPath, userPath]) {
|
|
26181
|
-
if (
|
|
26925
|
+
if (existsSync57(p)) {
|
|
26182
26926
|
try {
|
|
26183
|
-
return JSON.parse(
|
|
26927
|
+
return JSON.parse(readFileSync47(p, "utf-8"));
|
|
26184
26928
|
} catch {
|
|
26185
26929
|
continue;
|
|
26186
26930
|
}
|
|
@@ -26195,13 +26939,13 @@ async function checkCodexNetwork() {
|
|
|
26195
26939
|
if (!state || !state.configuredAgents.includes("codex")) {
|
|
26196
26940
|
return { name, status: "skip", message: "Codex not configured for Runwork" };
|
|
26197
26941
|
}
|
|
26198
|
-
const configPath =
|
|
26199
|
-
if (!
|
|
26942
|
+
const configPath = join54(homedir33(), ".codex", "config.toml");
|
|
26943
|
+
if (!existsSync57(configPath)) {
|
|
26200
26944
|
return { name, status: "skip", message: "no Codex config found" };
|
|
26201
26945
|
}
|
|
26202
26946
|
let parsed;
|
|
26203
26947
|
try {
|
|
26204
|
-
parsed = parse2(
|
|
26948
|
+
parsed = parse2(readFileSync47(configPath, "utf-8"));
|
|
26205
26949
|
} catch {
|
|
26206
26950
|
return { name, status: "warn", message: "could not parse ~/.codex/config.toml" };
|
|
26207
26951
|
}
|
|
@@ -26254,19 +26998,19 @@ async function checkCodexDesktopProject() {
|
|
|
26254
26998
|
if (!usesCodex) {
|
|
26255
26999
|
return { name, status: "skip", message: "Codex not configured for Runwork" };
|
|
26256
27000
|
}
|
|
26257
|
-
const statePath2 =
|
|
26258
|
-
if (!
|
|
27001
|
+
const statePath2 = join54(homedir33(), ".codex", ".codex-global-state.json");
|
|
27002
|
+
if (!existsSync57(statePath2)) {
|
|
26259
27003
|
return { name, status: "skip", message: "Codex desktop app not detected" };
|
|
26260
27004
|
}
|
|
26261
27005
|
let savedRoots = [];
|
|
26262
27006
|
try {
|
|
26263
|
-
const parsed = JSON.parse(
|
|
27007
|
+
const parsed = JSON.parse(readFileSync47(statePath2, "utf-8"));
|
|
26264
27008
|
const roots = parsed["electron-saved-workspace-roots"];
|
|
26265
27009
|
savedRoots = Array.isArray(roots) ? roots.filter((r) => typeof r === "string") : [];
|
|
26266
27010
|
} catch {
|
|
26267
27011
|
return { name, status: "warn", message: "could not read Codex desktop state" };
|
|
26268
27012
|
}
|
|
26269
|
-
const runworkDir =
|
|
27013
|
+
const runworkDir = join54(homedir33(), ".runwork");
|
|
26270
27014
|
if (savedRoots.includes(runworkDir)) {
|
|
26271
27015
|
return { name, status: "pass", message: "Runwork project added to Codex desktop sidebar" };
|
|
26272
27016
|
}
|
|
@@ -26320,9 +27064,9 @@ async function checkAgentSetup() {
|
|
|
26320
27064
|
if (!adapter2 || !adapter2.supportsMcpScope("user"))
|
|
26321
27065
|
continue;
|
|
26322
27066
|
const mcpConfigPath = getMcpConfigPath2(slug, "user");
|
|
26323
|
-
if (mcpConfigPath &&
|
|
27067
|
+
if (mcpConfigPath && existsSync57(mcpConfigPath)) {
|
|
26324
27068
|
try {
|
|
26325
|
-
const content =
|
|
27069
|
+
const content = readFileSync47(mcpConfigPath, "utf-8");
|
|
26326
27070
|
const missingMcp = state.mcpServers.filter((name) => !content.includes(name));
|
|
26327
27071
|
if (missingMcp.length > 0) {
|
|
26328
27072
|
details.push(`${missingMcp.length} MCP server(s) missing from ${slug} config`);
|
|
@@ -26353,8 +27097,8 @@ async function checkAgentSetup() {
|
|
|
26353
27097
|
const missingSkills = state.skills.filter((name) => {
|
|
26354
27098
|
if (isCoveredByMcp(name))
|
|
26355
27099
|
return false;
|
|
26356
|
-
const skillPath =
|
|
26357
|
-
return !
|
|
27100
|
+
const skillPath = join54(skillsDir, name, "SKILL.md");
|
|
27101
|
+
return !existsSync57(skillPath);
|
|
26358
27102
|
});
|
|
26359
27103
|
if (missingSkills.length > 0) {
|
|
26360
27104
|
details.push(`${missingSkills.length} skill(s) missing from ${slug}`);
|
|
@@ -26384,28 +27128,28 @@ async function checkAgentSetup() {
|
|
|
26384
27128
|
};
|
|
26385
27129
|
}
|
|
26386
27130
|
function getMcpConfigPath2(slug, scope) {
|
|
26387
|
-
const
|
|
27131
|
+
const home2 = homedir33();
|
|
26388
27132
|
switch (slug) {
|
|
26389
27133
|
case "claude-code":
|
|
26390
|
-
return scope === "project" ?
|
|
27134
|
+
return scope === "project" ? join54(process.cwd(), ".mcp.json") : join54(home2, ".claude", "settings.json");
|
|
26391
27135
|
case "cursor":
|
|
26392
|
-
return scope === "project" ?
|
|
27136
|
+
return scope === "project" ? join54(process.cwd(), ".cursor", "mcp.json") : join54(home2, ".cursor", "mcp.json");
|
|
26393
27137
|
case "windsurf":
|
|
26394
|
-
return scope === "project" ?
|
|
27138
|
+
return scope === "project" ? join54(process.cwd(), ".windsurf", "mcp.json") : join54(home2, ".windsurf", "mcp.json");
|
|
26395
27139
|
case "codex":
|
|
26396
27140
|
case "codex-app":
|
|
26397
|
-
return scope === "user" ?
|
|
27141
|
+
return scope === "user" ? join54(home2, ".codex", "config.toml") : null;
|
|
26398
27142
|
case "gemini":
|
|
26399
|
-
return scope === "user" ?
|
|
27143
|
+
return scope === "user" ? join54(home2, ".gemini", "settings.json") : null;
|
|
26400
27144
|
default:
|
|
26401
27145
|
return null;
|
|
26402
27146
|
}
|
|
26403
27147
|
}
|
|
26404
27148
|
async function checkWorkspacePointers() {
|
|
26405
|
-
const userStatePath =
|
|
26406
|
-
const state =
|
|
27149
|
+
const userStatePath = join54(homedir33(), ".runwork", "setup.json");
|
|
27150
|
+
const state = existsSync57(userStatePath) ? (() => {
|
|
26407
27151
|
try {
|
|
26408
|
-
return JSON.parse(
|
|
27152
|
+
return JSON.parse(readFileSync47(userStatePath, "utf-8"));
|
|
26409
27153
|
} catch {
|
|
26410
27154
|
return null;
|
|
26411
27155
|
}
|
|
@@ -26435,15 +27179,15 @@ async function checkWorkspacePointers() {
|
|
|
26435
27179
|
};
|
|
26436
27180
|
}
|
|
26437
27181
|
function getSkillsDir(slug, scope) {
|
|
26438
|
-
const
|
|
27182
|
+
const home2 = homedir33();
|
|
26439
27183
|
switch (slug) {
|
|
26440
27184
|
case "claude-code":
|
|
26441
|
-
return scope === "project" ?
|
|
27185
|
+
return scope === "project" ? join54(process.cwd(), ".claude", "skills") : join54(home2, ".claude", "skills");
|
|
26442
27186
|
case "codex":
|
|
26443
27187
|
case "codex-app":
|
|
26444
|
-
return scope === "project" ?
|
|
27188
|
+
return scope === "project" ? join54(process.cwd(), ".agents", "skills") : join54(home2, ".agents", "skills");
|
|
26445
27189
|
case "gemini":
|
|
26446
|
-
return scope === "project" ?
|
|
27190
|
+
return scope === "project" ? join54(process.cwd(), ".gemini", "skills") : join54(home2, ".gemini", "skills");
|
|
26447
27191
|
default:
|
|
26448
27192
|
return null;
|
|
26449
27193
|
}
|
|
@@ -26496,8 +27240,8 @@ async function runAllChecks(options) {
|
|
|
26496
27240
|
// src/health/fix.ts
|
|
26497
27241
|
init_credentials();
|
|
26498
27242
|
init_remote();
|
|
26499
|
-
import { existsSync as
|
|
26500
|
-
import { join as
|
|
27243
|
+
import { existsSync as existsSync58 } from "fs";
|
|
27244
|
+
import { join as join55 } from "path";
|
|
26501
27245
|
async function applyDoctorFixes(ctx, failingNames) {
|
|
26502
27246
|
const failing = new Set(failingNames);
|
|
26503
27247
|
const outcomes = [];
|
|
@@ -26524,7 +27268,7 @@ async function applyDoctorFixes(ctx, failingNames) {
|
|
|
26524
27268
|
applied: false,
|
|
26525
27269
|
message: "no project config -- run inside an app directory"
|
|
26526
27270
|
});
|
|
26527
|
-
} else if (!
|
|
27271
|
+
} else if (!existsSync58(join55(ctx.cwd, ".git"))) {
|
|
26528
27272
|
outcomes.push({
|
|
26529
27273
|
name: "git-remote",
|
|
26530
27274
|
applied: false,
|
|
@@ -26543,10 +27287,10 @@ async function applyDoctorFixes(ctx, failingNames) {
|
|
|
26543
27287
|
}
|
|
26544
27288
|
|
|
26545
27289
|
// src/agents/runtime-detection.ts
|
|
26546
|
-
import { existsSync as
|
|
26547
|
-
import { homedir as
|
|
26548
|
-
import { join as
|
|
26549
|
-
var RUNWORK_SESSIONS_DIR =
|
|
27290
|
+
import { existsSync as existsSync59, readFileSync as readFileSync48, statSync as statSync12, readdirSync as readdirSync18 } from "fs";
|
|
27291
|
+
import { homedir as homedir34 } from "os";
|
|
27292
|
+
import { join as join56 } from "path";
|
|
27293
|
+
var RUNWORK_SESSIONS_DIR = join56(homedir34(), ".runwork", "sessions");
|
|
26550
27294
|
function detectCurrentAgent() {
|
|
26551
27295
|
const claudeCodeSessionId = process.env.CLAUDE_CODE_SESSION_ID;
|
|
26552
27296
|
if (claudeCodeSessionId) {
|
|
@@ -26609,11 +27353,11 @@ function detectCurrentAgent() {
|
|
|
26609
27353
|
return null;
|
|
26610
27354
|
}
|
|
26611
27355
|
function readHookSessionInfo(sessionId) {
|
|
26612
|
-
const path4 =
|
|
26613
|
-
if (!
|
|
27356
|
+
const path4 = join56(RUNWORK_SESSIONS_DIR, `${sessionId}.json`);
|
|
27357
|
+
if (!existsSync59(path4))
|
|
26614
27358
|
return null;
|
|
26615
27359
|
try {
|
|
26616
|
-
const raw =
|
|
27360
|
+
const raw = readFileSync48(path4, "utf8");
|
|
26617
27361
|
const parsed = JSON.parse(raw);
|
|
26618
27362
|
return parsed;
|
|
26619
27363
|
} catch {
|
|
@@ -26621,40 +27365,40 @@ function readHookSessionInfo(sessionId) {
|
|
|
26621
27365
|
}
|
|
26622
27366
|
}
|
|
26623
27367
|
function findClaudeCodeSessionFile(sessionId) {
|
|
26624
|
-
const root =
|
|
26625
|
-
if (!
|
|
27368
|
+
const root = join56(homedir34(), ".claude", "projects");
|
|
27369
|
+
if (!existsSync59(root))
|
|
26626
27370
|
return null;
|
|
26627
27371
|
let projectDirs;
|
|
26628
27372
|
try {
|
|
26629
|
-
projectDirs =
|
|
27373
|
+
projectDirs = readdirSync18(root);
|
|
26630
27374
|
} catch {
|
|
26631
27375
|
return null;
|
|
26632
27376
|
}
|
|
26633
27377
|
for (const dir of projectDirs) {
|
|
26634
|
-
const candidate =
|
|
26635
|
-
if (
|
|
27378
|
+
const candidate = join56(root, dir, `${sessionId}.jsonl`);
|
|
27379
|
+
if (existsSync59(candidate))
|
|
26636
27380
|
return candidate;
|
|
26637
27381
|
}
|
|
26638
27382
|
return null;
|
|
26639
27383
|
}
|
|
26640
27384
|
function findCodexRolloutFile(threadId) {
|
|
26641
|
-
const root =
|
|
26642
|
-
if (!
|
|
27385
|
+
const root = join56(homedir34(), ".codex", "sessions");
|
|
27386
|
+
if (!existsSync59(root))
|
|
26643
27387
|
return null;
|
|
26644
27388
|
const stack = [root];
|
|
26645
27389
|
while (stack.length > 0) {
|
|
26646
27390
|
const dir = stack.pop();
|
|
26647
27391
|
let entries;
|
|
26648
27392
|
try {
|
|
26649
|
-
entries =
|
|
27393
|
+
entries = readdirSync18(dir);
|
|
26650
27394
|
} catch {
|
|
26651
27395
|
continue;
|
|
26652
27396
|
}
|
|
26653
27397
|
for (const entry of entries) {
|
|
26654
|
-
const full =
|
|
27398
|
+
const full = join56(dir, entry);
|
|
26655
27399
|
let s;
|
|
26656
27400
|
try {
|
|
26657
|
-
s =
|
|
27401
|
+
s = statSync12(full);
|
|
26658
27402
|
} catch {
|
|
26659
27403
|
continue;
|
|
26660
27404
|
}
|
|
@@ -26668,30 +27412,30 @@ function findCodexRolloutFile(threadId) {
|
|
|
26668
27412
|
return null;
|
|
26669
27413
|
}
|
|
26670
27414
|
function findNewestClaudeCodeSession() {
|
|
26671
|
-
const root =
|
|
26672
|
-
if (!
|
|
27415
|
+
const root = join56(homedir34(), ".claude", "projects");
|
|
27416
|
+
if (!existsSync59(root))
|
|
26673
27417
|
return null;
|
|
26674
27418
|
let projectDirs;
|
|
26675
27419
|
try {
|
|
26676
|
-
projectDirs =
|
|
27420
|
+
projectDirs = readdirSync18(root);
|
|
26677
27421
|
} catch {
|
|
26678
27422
|
return null;
|
|
26679
27423
|
}
|
|
26680
27424
|
let best = null;
|
|
26681
27425
|
for (const dir of projectDirs) {
|
|
26682
|
-
const projectPath =
|
|
27426
|
+
const projectPath = join56(root, dir);
|
|
26683
27427
|
let files;
|
|
26684
27428
|
try {
|
|
26685
|
-
files =
|
|
27429
|
+
files = readdirSync18(projectPath);
|
|
26686
27430
|
} catch {
|
|
26687
27431
|
continue;
|
|
26688
27432
|
}
|
|
26689
27433
|
for (const file of files) {
|
|
26690
27434
|
if (!file.endsWith(".jsonl"))
|
|
26691
27435
|
continue;
|
|
26692
|
-
const full =
|
|
27436
|
+
const full = join56(projectPath, file);
|
|
26693
27437
|
try {
|
|
26694
|
-
const s =
|
|
27438
|
+
const s = statSync12(full);
|
|
26695
27439
|
if (!best || s.mtimeMs > best.mtime) {
|
|
26696
27440
|
best = {
|
|
26697
27441
|
sessionId: file.replace(/\.jsonl$/, ""),
|
|
@@ -26707,8 +27451,8 @@ function findNewestClaudeCodeSession() {
|
|
|
26707
27451
|
return best ? { sessionId: best.sessionId, path: best.path } : null;
|
|
26708
27452
|
}
|
|
26709
27453
|
function findNewestCodexRollout() {
|
|
26710
|
-
const root =
|
|
26711
|
-
if (!
|
|
27454
|
+
const root = join56(homedir34(), ".codex", "sessions");
|
|
27455
|
+
if (!existsSync59(root))
|
|
26712
27456
|
return null;
|
|
26713
27457
|
const stack = [root];
|
|
26714
27458
|
let best = null;
|
|
@@ -26716,15 +27460,15 @@ function findNewestCodexRollout() {
|
|
|
26716
27460
|
const dir = stack.pop();
|
|
26717
27461
|
let entries;
|
|
26718
27462
|
try {
|
|
26719
|
-
entries =
|
|
27463
|
+
entries = readdirSync18(dir);
|
|
26720
27464
|
} catch {
|
|
26721
27465
|
continue;
|
|
26722
27466
|
}
|
|
26723
27467
|
for (const entry of entries) {
|
|
26724
|
-
const full =
|
|
27468
|
+
const full = join56(dir, entry);
|
|
26725
27469
|
let s;
|
|
26726
27470
|
try {
|
|
26727
|
-
s =
|
|
27471
|
+
s = statSync12(full);
|
|
26728
27472
|
} catch {
|
|
26729
27473
|
continue;
|
|
26730
27474
|
}
|
|
@@ -26951,11 +27695,13 @@ var doctorCommand = new Command34("doctor").description("Check system health: au
|
|
|
26951
27695
|
// src/commands/debug.ts
|
|
26952
27696
|
init_colors();
|
|
26953
27697
|
import { Command as Command35 } from "commander";
|
|
26954
|
-
import { readFileSync as
|
|
26955
|
-
import { homedir as
|
|
26956
|
-
import { join as
|
|
27698
|
+
import { readFileSync as readFileSync49 } from "fs";
|
|
27699
|
+
import { homedir as homedir36, platform as platform9, release, arch, type as osType } from "os";
|
|
27700
|
+
import { join as join59 } from "path";
|
|
26957
27701
|
|
|
26958
27702
|
// src/debug/capture-plan.ts
|
|
27703
|
+
init_transcript_stores();
|
|
27704
|
+
init_registry_data();
|
|
26959
27705
|
var CONFIG_MAX_BYTES = 64 * 1024;
|
|
26960
27706
|
var LOG_TAIL_BYTES = 64 * 1024;
|
|
26961
27707
|
var CENSUS_MAX_ENTRIES = 200;
|
|
@@ -26981,9 +27727,9 @@ var ENV_NAMES = [
|
|
|
26981
27727
|
];
|
|
26982
27728
|
function buildCapturePlan(input) {
|
|
26983
27729
|
const sep5 = input.sep ?? (input.platform === "win32" ? "\\" : "/");
|
|
26984
|
-
const
|
|
26985
|
-
const
|
|
26986
|
-
const rw = (...parts) =>
|
|
27730
|
+
const join57 = (...parts) => parts.join(sep5);
|
|
27731
|
+
const home2 = input.homeDir.replace(/[/\\]+$/, "");
|
|
27732
|
+
const rw = (...parts) => join57(home2, ".runwork", ...parts);
|
|
26987
27733
|
const steps = [];
|
|
26988
27734
|
steps.push({ id: "env", kind: "env", names: ENV_NAMES, note: "process environment (proxy credentials stripped)" });
|
|
26989
27735
|
for (const [id, file] of [
|
|
@@ -27013,62 +27759,129 @@ function buildCapturePlan(input) {
|
|
|
27013
27759
|
["codex.agents-md", ".codex", "AGENTS.md"],
|
|
27014
27760
|
["gemini.settings", ".gemini", "settings.json"]
|
|
27015
27761
|
]) {
|
|
27016
|
-
steps.push({ id, kind: "file", path:
|
|
27017
|
-
}
|
|
27762
|
+
steps.push({ id, kind: "file", path: join57(home2, ...parts), maxBytes: CONFIG_MAX_BYTES });
|
|
27763
|
+
}
|
|
27764
|
+
steps.push({
|
|
27765
|
+
id: "claude.desktop-config",
|
|
27766
|
+
kind: "file",
|
|
27767
|
+
path: join57(appDataRootFor(input, join57), "Claude", "claude_desktop_config.json"),
|
|
27768
|
+
maxBytes: CONFIG_MAX_BYTES,
|
|
27769
|
+
note: "the MCP config we write for Claude Desktop, next to its session store"
|
|
27770
|
+
});
|
|
27771
|
+
steps.push({
|
|
27772
|
+
id: "codex.version",
|
|
27773
|
+
kind: "file",
|
|
27774
|
+
path: join57(home2, ".codex", "version.json"),
|
|
27775
|
+
maxBytes: 4096,
|
|
27776
|
+
note: "Codex build, for placing an unrecognised originator value"
|
|
27777
|
+
});
|
|
27018
27778
|
for (const [id, ...parts] of [
|
|
27019
27779
|
["claude.skills", ".claude", "skills"],
|
|
27020
27780
|
["claude.plugins", ".claude", "plugins"],
|
|
27021
27781
|
["agents.skills", ".agents", "skills"],
|
|
27022
27782
|
["codex.skills", ".codex", "skills"]
|
|
27023
27783
|
]) {
|
|
27024
|
-
steps.push({ id, kind: "census", path:
|
|
27784
|
+
steps.push({ id, kind: "census", path: join57(home2, ...parts), depth: 1, maxEntries: CENSUS_MAX_ENTRIES });
|
|
27785
|
+
}
|
|
27786
|
+
for (const store of resolveTranscriptStores({
|
|
27787
|
+
platform: input.platform,
|
|
27788
|
+
homeDir: home2,
|
|
27789
|
+
sep: sep5,
|
|
27790
|
+
appData: input.appData,
|
|
27791
|
+
localAppData: input.localAppData
|
|
27792
|
+
})) {
|
|
27793
|
+
const id = `stores.${store.def.id.replace(/\//g, ".")}`;
|
|
27794
|
+
steps.push(store.def.kind === "file" ? { id, kind: "stat", path: store.path, ...store.def.note ? { note: store.def.note } : {} } : { id, kind: "census", path: store.path, depth: 2, maxEntries: CENSUS_MAX_ENTRIES, ...store.def.note ? { note: store.def.note } : {} });
|
|
27795
|
+
for (const parent of parentsWorthProbing(store.path, sep5)) {
|
|
27796
|
+
steps.push({ id: `${id}.parent`, kind: "census", path: parent, depth: 1, maxEntries: 50, note: "is the vendor directory there at all" });
|
|
27797
|
+
}
|
|
27798
|
+
store.altPaths.forEach((alt, i) => {
|
|
27799
|
+
steps.push({ id: `${id}.alt${i}`, kind: "stat", path: alt, note: "alternate location; a hit means the canonical path is wrong here" });
|
|
27800
|
+
});
|
|
27801
|
+
}
|
|
27802
|
+
if (input.platform === "win32") {
|
|
27803
|
+
steps.push({
|
|
27804
|
+
id: "windows.appx-packages",
|
|
27805
|
+
kind: "census",
|
|
27806
|
+
path: join57(input.localAppData ?? join57(home2, "AppData", "Local"), "Packages"),
|
|
27807
|
+
depth: 1,
|
|
27808
|
+
maxEntries: CENSUS_MAX_ENTRIES,
|
|
27809
|
+
note: "AppX package identities: an MSIX agent can virtualize its writes in here"
|
|
27810
|
+
});
|
|
27025
27811
|
}
|
|
27026
|
-
steps.push({ id: "transcripts.claude-code", kind: "census", path: join56(home, ".claude", "projects"), depth: 1, maxEntries: CENSUS_MAX_ENTRIES }, { id: "transcripts.codex", kind: "census", path: join56(home, ".codex", "sessions"), depth: 2, maxEntries: CENSUS_MAX_ENTRIES }, { id: "transcripts.gemini", kind: "census", path: join56(home, ".gemini", "tmp"), depth: 1, maxEntries: CENSUS_MAX_ENTRIES }, { id: "transcripts.cowork", kind: "census", path: coworkBaseDir(input, join56), depth: 1, maxEntries: CENSUS_MAX_ENTRIES, note: "macOS TCC can refuse this while it still exists" });
|
|
27027
27812
|
for (const profile of shellProfiles(input.platform)) {
|
|
27028
27813
|
steps.push({
|
|
27029
27814
|
id: `shell${profile}`,
|
|
27030
27815
|
kind: "stat",
|
|
27031
|
-
path:
|
|
27816
|
+
path: join57(home2, profile),
|
|
27032
27817
|
note: "presence only: profile bodies can contain the user's own secrets"
|
|
27033
27818
|
});
|
|
27034
27819
|
}
|
|
27035
27820
|
steps.push(...binaryResolutionSteps(input));
|
|
27821
|
+
steps.push(...agentBinaryProbes(input));
|
|
27036
27822
|
if (input.cliPath) {
|
|
27037
|
-
steps.push({ id: "cli.version", kind: "exec", command: input.cliPath, args: ["--version"] }, { id: "cli.doctor", kind: "exec", command: input.cliPath, args: ["--json", "doctor", "-v"] }, { id: "cli.conversations", kind: "exec", command: input.cliPath, args: ["--json", "conversations", "status", "--days", "0"], note: "per-agent scan outcome, no conversation data" });
|
|
27823
|
+
steps.push({ id: "cli.version", kind: "exec", command: input.cliPath, args: ["--version"] }, { id: "cli.doctor", kind: "exec", command: input.cliPath, args: ["--json", "doctor", "-v"] }, { id: "cli.conversations", kind: "exec", command: input.cliPath, args: ["--json", "conversations", "status", "--days", "0"], note: "per-agent scan outcome, no conversation data" }, { id: "cli.stores", kind: "exec", command: input.cliPath, args: ["--json", "conversations", "stores"], note: "per-store contents and provenance, no conversation text" });
|
|
27038
27824
|
}
|
|
27039
27825
|
return steps;
|
|
27040
27826
|
}
|
|
27041
|
-
function
|
|
27042
|
-
const
|
|
27043
|
-
if (
|
|
27044
|
-
return
|
|
27045
|
-
|
|
27046
|
-
|
|
27047
|
-
|
|
27048
|
-
return
|
|
27827
|
+
function parentsWorthProbing(storePath4, sep5) {
|
|
27828
|
+
const idx = storePath4.lastIndexOf(sep5);
|
|
27829
|
+
if (idx <= 0)
|
|
27830
|
+
return [];
|
|
27831
|
+
const parent = storePath4.slice(0, idx);
|
|
27832
|
+
const parentIdx = parent.lastIndexOf(sep5);
|
|
27833
|
+
if (parentIdx <= 0)
|
|
27834
|
+
return [];
|
|
27835
|
+
return [parent];
|
|
27836
|
+
}
|
|
27837
|
+
function agentBinaryProbes(input) {
|
|
27838
|
+
const finder = input.platform === "win32" ? "where.exe" : "which";
|
|
27839
|
+
const args = (binary) => input.platform === "win32" ? [binary] : ["-a", binary];
|
|
27840
|
+
const seen = new Set;
|
|
27841
|
+
const steps = [];
|
|
27842
|
+
for (const agent of getDetectableAgents()) {
|
|
27843
|
+
const binary = agent.launch?.cli;
|
|
27844
|
+
if (!binary || seen.has(binary))
|
|
27845
|
+
continue;
|
|
27846
|
+
seen.add(binary);
|
|
27847
|
+
steps.push({
|
|
27848
|
+
id: `agent-binary.${agent.slug}`,
|
|
27849
|
+
kind: "exec",
|
|
27850
|
+
command: finder,
|
|
27851
|
+
args: args(binary),
|
|
27852
|
+
note: `is ${agent.name}'s CLI on PATH, and where`
|
|
27853
|
+
});
|
|
27049
27854
|
}
|
|
27050
|
-
return
|
|
27855
|
+
return steps;
|
|
27856
|
+
}
|
|
27857
|
+
function appDataRootFor(input, join57) {
|
|
27858
|
+
const home2 = input.homeDir.replace(/[/\\]+$/, "");
|
|
27859
|
+
if (input.platform === "darwin")
|
|
27860
|
+
return join57(home2, "Library", "Application Support");
|
|
27861
|
+
if (input.platform === "win32")
|
|
27862
|
+
return input.appData ?? join57(home2, "AppData", "Roaming");
|
|
27863
|
+
return join57(home2, ".config");
|
|
27051
27864
|
}
|
|
27052
|
-
function shellProfiles(
|
|
27053
|
-
if (
|
|
27865
|
+
function shellProfiles(platform9) {
|
|
27866
|
+
if (platform9 === "win32")
|
|
27054
27867
|
return [];
|
|
27055
27868
|
return [".zshrc", ".zprofile", ".bashrc", ".bash_profile", ".profile"];
|
|
27056
27869
|
}
|
|
27057
27870
|
function binaryResolutionSteps(input) {
|
|
27058
27871
|
const sep5 = input.sep ?? (input.platform === "win32" ? "\\" : "/");
|
|
27059
|
-
const
|
|
27060
|
-
const
|
|
27872
|
+
const join57 = (...parts) => parts.join(sep5);
|
|
27873
|
+
const home2 = input.homeDir.replace(/[/\\]+$/, "");
|
|
27061
27874
|
if (input.platform === "win32") {
|
|
27062
27875
|
return [
|
|
27063
27876
|
{ id: "binaries.where", kind: "exec", command: "where.exe", args: ["runwork"], note: "every match, not just the first" },
|
|
27064
|
-
{ id: "binaries.runwork-bin", kind: "stat", path:
|
|
27877
|
+
{ id: "binaries.runwork-bin", kind: "stat", path: join57(home2, ".runwork", "bin", "runwork.exe") },
|
|
27065
27878
|
{ id: "binaries.user-path", kind: "exec", command: "reg.exe", args: ["query", "HKCU\\Environment", "/v", "Path"], note: "the PATH a NEW shell will inherit, not this one" }
|
|
27066
27879
|
];
|
|
27067
27880
|
}
|
|
27068
27881
|
return [
|
|
27069
27882
|
{ id: "binaries.which", kind: "exec", command: "which", args: ["-a", "runwork"], note: "every match, not just the first" },
|
|
27070
|
-
{ id: "binaries.runwork-bin", kind: "stat", path:
|
|
27071
|
-
{ id: "binaries.local-bin", kind: "stat", path:
|
|
27883
|
+
{ id: "binaries.runwork-bin", kind: "stat", path: join57(home2, ".runwork", "bin", "runwork") },
|
|
27884
|
+
{ id: "binaries.local-bin", kind: "stat", path: join57(home2, ".local", "bin", "runwork") },
|
|
27072
27885
|
...input.platform === "darwin" ? [{ id: "binaries.usr-local-bin", kind: "stat", path: "/usr/local/bin/runwork" }] : []
|
|
27073
27886
|
];
|
|
27074
27887
|
}
|
|
@@ -27284,10 +28097,10 @@ async function runCapture(port, producer, steps, opts = {}) {
|
|
|
27284
28097
|
// src/utils/machine-id.ts
|
|
27285
28098
|
init_atomic_json();
|
|
27286
28099
|
import { randomUUID } from "crypto";
|
|
27287
|
-
import { homedir as
|
|
27288
|
-
import { join as
|
|
28100
|
+
import { homedir as homedir35 } from "os";
|
|
28101
|
+
import { join as join57 } from "path";
|
|
27289
28102
|
function machineIdPath() {
|
|
27290
|
-
return
|
|
28103
|
+
return join57(homedir35(), ".runwork", "machine.json");
|
|
27291
28104
|
}
|
|
27292
28105
|
function isValidId(value) {
|
|
27293
28106
|
return typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
|
|
@@ -27315,8 +28128,8 @@ init_resolve();
|
|
|
27315
28128
|
// src/debug/node-port.ts
|
|
27316
28129
|
init_subprocess();
|
|
27317
28130
|
init_which();
|
|
27318
|
-
import { closeSync as
|
|
27319
|
-
import { dirname as dirname12, join as
|
|
28131
|
+
import { closeSync as closeSync6, fsyncSync, mkdirSync as mkdirSync29, openSync as openSync6, readSync as readSync4, readdirSync as readdirSync19, statSync as statSync13, writeSync } from "fs";
|
|
28132
|
+
import { dirname as dirname12, join as join58 } from "path";
|
|
27320
28133
|
var EXEC_OUTPUT_MAX = 256 * 1024;
|
|
27321
28134
|
var EXEC_TIMEOUT_MS = 20000;
|
|
27322
28135
|
function truncate5(text2, maxBytes) {
|
|
@@ -27324,7 +28137,7 @@ function truncate5(text2, maxBytes) {
|
|
|
27324
28137
|
}
|
|
27325
28138
|
function entryKind(path4) {
|
|
27326
28139
|
try {
|
|
27327
|
-
const s =
|
|
28140
|
+
const s = statSync13(path4);
|
|
27328
28141
|
return s.isDirectory() ? "dir" : s.isFile() ? "file" : "other";
|
|
27329
28142
|
} catch {
|
|
27330
28143
|
return "other";
|
|
@@ -27332,9 +28145,9 @@ function entryKind(path4) {
|
|
|
27332
28145
|
}
|
|
27333
28146
|
function createNodeCapturePort(outputPath) {
|
|
27334
28147
|
mkdirSync29(dirname12(outputPath), { recursive: true });
|
|
27335
|
-
const fd =
|
|
28148
|
+
const fd = openSync6(outputPath, "w");
|
|
27336
28149
|
return {
|
|
27337
|
-
close: () =>
|
|
28150
|
+
close: () => closeSync6(fd),
|
|
27338
28151
|
async append(record) {
|
|
27339
28152
|
writeSync(fd, JSON.stringify(record) + `
|
|
27340
28153
|
`);
|
|
@@ -27350,7 +28163,7 @@ function createNodeCapturePort(outputPath) {
|
|
|
27350
28163
|
const { dir, prefix, level } = queue.shift();
|
|
27351
28164
|
let names;
|
|
27352
28165
|
try {
|
|
27353
|
-
names =
|
|
28166
|
+
names = readdirSync19(dir);
|
|
27354
28167
|
} catch (err) {
|
|
27355
28168
|
if (first)
|
|
27356
28169
|
throw err;
|
|
@@ -27361,12 +28174,12 @@ function createNodeCapturePort(outputPath) {
|
|
|
27361
28174
|
for (const name of names) {
|
|
27362
28175
|
if (out.length >= maxEntries)
|
|
27363
28176
|
break;
|
|
27364
|
-
const full =
|
|
28177
|
+
const full = join58(dir, name);
|
|
27365
28178
|
const kind = entryKind(full);
|
|
27366
28179
|
let bytes;
|
|
27367
28180
|
let modifiedAt;
|
|
27368
28181
|
try {
|
|
27369
|
-
const s =
|
|
28182
|
+
const s = statSync13(full);
|
|
27370
28183
|
bytes = s.size;
|
|
27371
28184
|
modifiedAt = new Date(s.mtimeMs).toISOString();
|
|
27372
28185
|
} catch {}
|
|
@@ -27379,7 +28192,7 @@ function createNodeCapturePort(outputPath) {
|
|
|
27379
28192
|
return out;
|
|
27380
28193
|
},
|
|
27381
28194
|
async stat(path4) {
|
|
27382
|
-
const s =
|
|
28195
|
+
const s = statSync13(path4);
|
|
27383
28196
|
return {
|
|
27384
28197
|
bytes: s.size,
|
|
27385
28198
|
modifiedAt: new Date(s.mtimeMs).toISOString(),
|
|
@@ -27387,16 +28200,16 @@ function createNodeCapturePort(outputPath) {
|
|
|
27387
28200
|
};
|
|
27388
28201
|
},
|
|
27389
28202
|
async readText(path4, maxBytes, tail) {
|
|
27390
|
-
const s =
|
|
28203
|
+
const s = statSync13(path4);
|
|
27391
28204
|
const size = s.size;
|
|
27392
28205
|
const length = Math.min(size, maxBytes);
|
|
27393
28206
|
const start = tail && size > maxBytes ? size - maxBytes : 0;
|
|
27394
28207
|
const buffer = Buffer.alloc(length);
|
|
27395
|
-
const handle =
|
|
28208
|
+
const handle = openSync6(path4, "r");
|
|
27396
28209
|
try {
|
|
27397
|
-
|
|
28210
|
+
readSync4(handle, buffer, 0, length, start);
|
|
27398
28211
|
} finally {
|
|
27399
|
-
|
|
28212
|
+
closeSync6(handle);
|
|
27400
28213
|
}
|
|
27401
28214
|
return { text: buffer.toString("utf-8"), truncated: size > length };
|
|
27402
28215
|
},
|
|
@@ -27429,7 +28242,7 @@ init_which();
|
|
|
27429
28242
|
await init_detect();
|
|
27430
28243
|
function defaultOutputPath(now) {
|
|
27431
28244
|
const stamp = now.toISOString().replace(/[:.]/g, "-").replace("T", "_").slice(0, 19);
|
|
27432
|
-
return
|
|
28245
|
+
return join59(homedir36(), ".runwork", "debug", `runwork-debug-${stamp}.jsonl`);
|
|
27433
28246
|
}
|
|
27434
28247
|
async function cliClaims() {
|
|
27435
28248
|
const records = [];
|
|
@@ -27442,7 +28255,7 @@ async function cliClaims() {
|
|
|
27442
28255
|
execPath: process.execPath,
|
|
27443
28256
|
argv0: process.argv[1] ?? null,
|
|
27444
28257
|
nodeVersion: process.version,
|
|
27445
|
-
platform:
|
|
28258
|
+
platform: platform9(),
|
|
27446
28259
|
osType: osType(),
|
|
27447
28260
|
release: release(),
|
|
27448
28261
|
arch: arch(),
|
|
@@ -27482,9 +28295,10 @@ debugCommand.command("capture").description("Collect a diagnostic bundle to a fi
|
|
|
27482
28295
|
const outputPath = typeof opts.out === "string" && opts.out ? opts.out : defaultOutputPath(new Date);
|
|
27483
28296
|
const cliPath = whichBinary("runwork");
|
|
27484
28297
|
const plan = buildCapturePlan({
|
|
27485
|
-
platform:
|
|
27486
|
-
homeDir:
|
|
28298
|
+
platform: platform9(),
|
|
28299
|
+
homeDir: homedir36(),
|
|
27487
28300
|
appData: process.env.APPDATA ?? null,
|
|
28301
|
+
localAppData: process.env.LOCALAPPDATA ?? null,
|
|
27488
28302
|
cliPath
|
|
27489
28303
|
});
|
|
27490
28304
|
if (!json) {
|
|
@@ -27528,7 +28342,7 @@ Done. ${counted} checks recorded.`));
|
|
|
27528
28342
|
});
|
|
27529
28343
|
async function sendBundle(path4, note) {
|
|
27530
28344
|
try {
|
|
27531
|
-
const content =
|
|
28345
|
+
const content = readFileSync49(path4, "utf-8");
|
|
27532
28346
|
const summary = summarizeBundle(content);
|
|
27533
28347
|
const machineId = getMachineId();
|
|
27534
28348
|
if (!machineId)
|
|
@@ -27547,7 +28361,7 @@ async function sendBundle(path4, note) {
|
|
|
27547
28361
|
...note ? { note } : {},
|
|
27548
28362
|
context: {
|
|
27549
28363
|
cliVersion: VERSION,
|
|
27550
|
-
platform:
|
|
28364
|
+
platform: platform9(),
|
|
27551
28365
|
release: release(),
|
|
27552
28366
|
stepsPlanned: summary.stepsPlanned,
|
|
27553
28367
|
stepsRun: summary.stepsRun,
|
|
@@ -27567,8 +28381,8 @@ init_store();
|
|
|
27567
28381
|
init_client();
|
|
27568
28382
|
init_resolve();
|
|
27569
28383
|
import { Command as Command36 } from "commander";
|
|
27570
|
-
import { readFileSync as
|
|
27571
|
-
import { join as
|
|
28384
|
+
import { readFileSync as readFileSync50, writeFileSync as writeFileSync33, existsSync as existsSync60, mkdtempSync as mkdtempSync4 } from "fs";
|
|
28385
|
+
import { join as join60 } from "path";
|
|
27572
28386
|
import { tmpdir as tmpdir4 } from "os";
|
|
27573
28387
|
import { createHash as createHash6 } from "crypto";
|
|
27574
28388
|
|
|
@@ -27690,13 +28504,13 @@ function resolveLocalSessionShare(opts, conversation) {
|
|
|
27690
28504
|
process.exit(1);
|
|
27691
28505
|
}
|
|
27692
28506
|
const title = opts.title ?? conversation.title ?? conversation.project;
|
|
27693
|
-
const markdown = renderTranscriptMarkdown(
|
|
28507
|
+
const markdown = renderTranscriptMarkdown(readFileSync50(conversation.transcriptPath, "utf8"), family, title);
|
|
27694
28508
|
if (!markdown) {
|
|
27695
28509
|
console.error("Error: this conversation has no shareable content.");
|
|
27696
28510
|
process.exit(1);
|
|
27697
28511
|
}
|
|
27698
|
-
const tempDir = mkdtempSync4(
|
|
27699
|
-
const transcriptFile =
|
|
28512
|
+
const tempDir = mkdtempSync4(join60(tmpdir4(), "runwork-share-"));
|
|
28513
|
+
const transcriptFile = join60(tempDir, "transcript.md");
|
|
27700
28514
|
writeFileSync33(transcriptFile, markdown);
|
|
27701
28515
|
opts.transcriptFile = transcriptFile;
|
|
27702
28516
|
opts.nativeFile = opts.nativeFile ?? conversation.transcriptPath;
|
|
@@ -27734,7 +28548,7 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
|
|
|
27734
28548
|
console.error("Error: --transcript-file is required. Pass the path to the LLM-emitted markdown transcript.");
|
|
27735
28549
|
process.exit(1);
|
|
27736
28550
|
}
|
|
27737
|
-
if (!
|
|
28551
|
+
if (!existsSync60(opts.transcriptFile)) {
|
|
27738
28552
|
console.error(`Error: transcript file does not exist: ${opts.transcriptFile}`);
|
|
27739
28553
|
process.exit(1);
|
|
27740
28554
|
}
|
|
@@ -27755,7 +28569,7 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
|
|
|
27755
28569
|
const credentials = requireAuth();
|
|
27756
28570
|
const client = new ApiClient(credentials);
|
|
27757
28571
|
const { workspaceId } = await resolveWorkspace2(client, { workspace: opts.workspace });
|
|
27758
|
-
const transcriptContent =
|
|
28572
|
+
const transcriptContent = readFileSync50(opts.transcriptFile, "utf8");
|
|
27759
28573
|
const bundles = [
|
|
27760
28574
|
{
|
|
27761
28575
|
format: "transcript",
|
|
@@ -27768,19 +28582,19 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
|
|
|
27768
28582
|
const sourceAgent = opts.sourceAgent ?? detected?.slug ?? "generic";
|
|
27769
28583
|
let nativeFilePath = null;
|
|
27770
28584
|
if (opts.nativeFile) {
|
|
27771
|
-
if (!
|
|
28585
|
+
if (!existsSync60(opts.nativeFile)) {
|
|
27772
28586
|
console.error(`Error: --native-file path does not exist: ${opts.nativeFile}`);
|
|
27773
28587
|
process.exit(1);
|
|
27774
28588
|
}
|
|
27775
28589
|
nativeFilePath = opts.nativeFile;
|
|
27776
|
-
} else if (detected?.sessionFilePath &&
|
|
28590
|
+
} else if (detected?.sessionFilePath && existsSync60(detected.sessionFilePath)) {
|
|
27777
28591
|
nativeFilePath = detected.sessionFilePath;
|
|
27778
28592
|
}
|
|
27779
28593
|
if (nativeFilePath) {
|
|
27780
28594
|
const nativeFormat = nativeBundleFormatForAgent(sourceAgent);
|
|
27781
28595
|
if (nativeFormat) {
|
|
27782
28596
|
try {
|
|
27783
|
-
const content =
|
|
28597
|
+
const content = readFileSync50(nativeFilePath, "utf8");
|
|
27784
28598
|
bundles.push({
|
|
27785
28599
|
format: nativeFormat,
|
|
27786
28600
|
content,
|
|
@@ -27796,7 +28610,7 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
|
|
|
27796
28610
|
let metadata = {};
|
|
27797
28611
|
if (opts.metadataFile) {
|
|
27798
28612
|
try {
|
|
27799
|
-
metadata = JSON.parse(
|
|
28613
|
+
metadata = JSON.parse(readFileSync50(opts.metadataFile, "utf8"));
|
|
27800
28614
|
} catch (err) {
|
|
27801
28615
|
console.error(`Error: --metadata-file is not valid JSON: ${err instanceof Error ? err.message : err}`);
|
|
27802
28616
|
process.exit(1);
|
|
@@ -27906,8 +28720,8 @@ init_resolve();
|
|
|
27906
28720
|
init_registry_data();
|
|
27907
28721
|
import { Command as Command39 } from "commander";
|
|
27908
28722
|
import { writeFileSync as writeFileSync34, mkdirSync as mkdirSync30, realpathSync } from "fs";
|
|
27909
|
-
import { homedir as
|
|
27910
|
-
import { join as
|
|
28723
|
+
import { homedir as homedir37 } from "os";
|
|
28724
|
+
import { join as join61 } from "path";
|
|
27911
28725
|
import { spawn as spawn5 } from "child_process";
|
|
27912
28726
|
init_registry();
|
|
27913
28727
|
init_which();
|
|
@@ -27946,9 +28760,9 @@ function extractCodexUuid(rolloutContent) {
|
|
|
27946
28760
|
}
|
|
27947
28761
|
function placeClaudeJsonl(uuid, content, recipientCwd) {
|
|
27948
28762
|
const encoded = encodeClaudeCodeCwd(recipientCwd);
|
|
27949
|
-
const projectDir =
|
|
28763
|
+
const projectDir = join61(homedir37(), ".claude", "projects", encoded);
|
|
27950
28764
|
mkdirSync30(projectDir, { recursive: true });
|
|
27951
|
-
const placedAt =
|
|
28765
|
+
const placedAt = join61(projectDir, `${uuid}.jsonl`);
|
|
27952
28766
|
writeFileSync34(placedAt, content);
|
|
27953
28767
|
return { placedAt, runFromCwd: recipientCwd };
|
|
27954
28768
|
}
|
|
@@ -27957,10 +28771,10 @@ function placeCodexRollout(uuid, content) {
|
|
|
27957
28771
|
const yyyy = String(now.getUTCFullYear());
|
|
27958
28772
|
const mm = String(now.getUTCMonth() + 1).padStart(2, "0");
|
|
27959
28773
|
const dd = String(now.getUTCDate()).padStart(2, "0");
|
|
27960
|
-
const dir =
|
|
28774
|
+
const dir = join61(homedir37(), ".codex", "sessions", yyyy, mm, dd);
|
|
27961
28775
|
mkdirSync30(dir, { recursive: true });
|
|
27962
28776
|
const ts = now.toISOString().replace(/\.\d+Z$/, "").replace(/:/g, "-");
|
|
27963
|
-
const placedAt =
|
|
28777
|
+
const placedAt = join61(dir, `rollout-${ts}-${uuid}.jsonl`);
|
|
27964
28778
|
writeFileSync34(placedAt, content);
|
|
27965
28779
|
return { placedAt };
|
|
27966
28780
|
}
|