runwork 0.25.3 → 0.27.0
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/bundled-types/client.d.ts +39 -0
- package/bundled-types/core-agent.d.ts +1 -1
- package/bundled-types/core-entity-do.d.ts +0 -2
- package/bundled-types/core-events.d.ts +0 -7
- package/bundled-types/core-file-storage.d.ts +0 -4
- package/bundled-types/core-utils.d.ts +104 -2
- package/bundled-types/core-workflows.d.ts +1 -1
- package/dist/index.js +2256 -535
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -62,7 +62,11 @@ import {
|
|
|
62
62
|
createInflateRaw
|
|
63
63
|
} from "node:zlib";
|
|
64
64
|
function firstEnv(names) {
|
|
65
|
-
|
|
65
|
+
const keys = Object.keys(process.env);
|
|
66
|
+
for (const candidate of names) {
|
|
67
|
+
const variable = keys.find((k) => k === candidate) ?? keys.find((k) => k.toLowerCase() === candidate.toLowerCase());
|
|
68
|
+
if (variable === undefined)
|
|
69
|
+
continue;
|
|
66
70
|
const value = process.env[variable];
|
|
67
71
|
if (value && value.trim() !== "")
|
|
68
72
|
return { variable, value: value.trim() };
|
|
@@ -828,6 +832,10 @@ class ApiClient {
|
|
|
828
832
|
async reportTelemetry(workspaceId, events) {
|
|
829
833
|
await this.request(`/api/workspaces/${workspaceId}/team/telemetry`, { method: "POST", body: JSON.stringify({ events }) });
|
|
830
834
|
}
|
|
835
|
+
async createDebugReport(workspaceId, body) {
|
|
836
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/debug-reports`, { method: "POST", body: JSON.stringify(body) });
|
|
837
|
+
return res.data;
|
|
838
|
+
}
|
|
831
839
|
async createSharedConversation(workspaceId, body) {
|
|
832
840
|
const res = await this.request(`/api/workspaces/${workspaceId}/shared-conversations`, {
|
|
833
841
|
method: "POST",
|
|
@@ -1038,10 +1046,13 @@ var init_workspace_state = __esm(() => {
|
|
|
1038
1046
|
// src/utils/subprocess.ts
|
|
1039
1047
|
import {
|
|
1040
1048
|
execFileSync as cpExecFileSync,
|
|
1041
|
-
spawn as cpSpawn
|
|
1049
|
+
spawn as cpSpawn,
|
|
1050
|
+
spawnSync as cpSpawnSync
|
|
1042
1051
|
} from "child_process";
|
|
1043
1052
|
var execFileSync = (file, args, options) => {
|
|
1044
1053
|
return cpExecFileSync(file, args, { windowsHide: true, ...options ?? {} });
|
|
1054
|
+
}, spawnSync = (file, args, options) => {
|
|
1055
|
+
return cpSpawnSync(file, args, { windowsHide: true, ...options ?? {} });
|
|
1045
1056
|
}, spawn2 = (command, args, options) => {
|
|
1046
1057
|
return cpSpawn(command, args ?? [], { windowsHide: true, ...options ?? {} });
|
|
1047
1058
|
};
|
|
@@ -3135,13 +3146,56 @@ function bufToStr2(val) {
|
|
|
3135
3146
|
return val.toString("utf-8").trim();
|
|
3136
3147
|
return "";
|
|
3137
3148
|
}
|
|
3149
|
+
function pushSyncStash(cwd) {
|
|
3150
|
+
execFileSync("git", ["stash", "push", "-m", SYNC_STASH_TAG], { cwd, stdio: "pipe" });
|
|
3151
|
+
return findSyncStashSha(cwd);
|
|
3152
|
+
}
|
|
3153
|
+
function findSyncStashSha(cwd) {
|
|
3154
|
+
try {
|
|
3155
|
+
const line = execFileSync("git", ["stash", "list", "--format=%H %gs"], { cwd, encoding: "utf-8" }).split(`
|
|
3156
|
+
`).find((l) => l.includes(SYNC_STASH_TAG));
|
|
3157
|
+
return line ? line.split(" ")[0] : null;
|
|
3158
|
+
} catch {
|
|
3159
|
+
return null;
|
|
3160
|
+
}
|
|
3161
|
+
}
|
|
3162
|
+
function stashRefForSha(cwd, sha) {
|
|
3163
|
+
try {
|
|
3164
|
+
const line = execFileSync("git", ["stash", "list", "--format=%H %gd"], { cwd, encoding: "utf-8" }).split(`
|
|
3165
|
+
`).find((l) => l.startsWith(`${sha} `));
|
|
3166
|
+
return line ? line.slice(sha.length + 1).trim() : null;
|
|
3167
|
+
} catch {
|
|
3168
|
+
return null;
|
|
3169
|
+
}
|
|
3170
|
+
}
|
|
3171
|
+
function restoreSyncStash(cwd, sha) {
|
|
3172
|
+
const resolved = sha ?? findSyncStashSha(cwd);
|
|
3173
|
+
if (!resolved)
|
|
3174
|
+
return "missing";
|
|
3175
|
+
const ref = stashRefForSha(cwd, resolved);
|
|
3176
|
+
if (!ref)
|
|
3177
|
+
return "missing";
|
|
3178
|
+
try {
|
|
3179
|
+
execFileSync("git", ["stash", "apply", resolved], { cwd, stdio: "pipe" });
|
|
3180
|
+
} catch {
|
|
3181
|
+
return "conflict";
|
|
3182
|
+
}
|
|
3183
|
+
const dropRef = stashRefForSha(cwd, resolved);
|
|
3184
|
+
if (dropRef) {
|
|
3185
|
+
try {
|
|
3186
|
+
execFileSync("git", ["stash", "drop", dropRef], { cwd, stdio: "pipe" });
|
|
3187
|
+
} catch {}
|
|
3188
|
+
}
|
|
3189
|
+
return "restored";
|
|
3190
|
+
}
|
|
3138
3191
|
function syncWithRemote(cwd) {
|
|
3139
3192
|
if (!hasCommits(cwd)) {
|
|
3140
3193
|
return { status: "skipped", pushed: false };
|
|
3141
3194
|
}
|
|
3142
3195
|
const dirty = hasTrackedChanges(cwd);
|
|
3196
|
+
let stashSha = null;
|
|
3143
3197
|
if (dirty) {
|
|
3144
|
-
|
|
3198
|
+
stashSha = pushSyncStash(cwd);
|
|
3145
3199
|
}
|
|
3146
3200
|
let status = "synced";
|
|
3147
3201
|
let syncError;
|
|
@@ -3182,9 +3236,8 @@ function syncWithRemote(cwd) {
|
|
|
3182
3236
|
syncError = extractGitError(fetchErr);
|
|
3183
3237
|
}
|
|
3184
3238
|
if (dirty) {
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
} catch {
|
|
3239
|
+
const restored = restoreSyncStash(cwd, stashSha);
|
|
3240
|
+
if (restored !== "restored") {
|
|
3188
3241
|
return { status, pushed: false, error: "stash-conflict", keptUntracked, remoteOverwrote };
|
|
3189
3242
|
}
|
|
3190
3243
|
}
|
|
@@ -3201,6 +3254,7 @@ function syncWithRemote(cwd) {
|
|
|
3201
3254
|
}
|
|
3202
3255
|
return { status, pushed, pushError, keptUntracked, remoteOverwrote };
|
|
3203
3256
|
}
|
|
3257
|
+
var SYNC_STASH_TAG = "runwork-dev-sync";
|
|
3204
3258
|
var init_sync = __esm(() => {
|
|
3205
3259
|
init_subprocess();
|
|
3206
3260
|
init_manifest();
|
|
@@ -5105,10 +5159,6 @@ export declare class FileStorageClient {
|
|
|
5105
5159
|
*/
|
|
5106
5160
|
export declare function createFileStorageClient(env: Env): FileStorageClient;
|
|
5107
5161
|
import type { Hono } from 'hono';
|
|
5108
|
-
/**
|
|
5109
|
-
* Mount file storage routes on the Hono app
|
|
5110
|
-
* Provides REST API for R2 bucket operations
|
|
5111
|
-
*/
|
|
5112
5162
|
export declare function fileStorageRoutes(app: Hono<{
|
|
5113
5163
|
Bindings: Env;
|
|
5114
5164
|
}>): void;
|
|
@@ -5285,6 +5335,46 @@ export declare function componentRoutes(app: Hono<{
|
|
|
5285
5335
|
`,
|
|
5286
5336
|
"workspace.d.ts": `export { WorkspaceContext, getWorkspaceContext, listWorkspaceEntity, getWorkspaceEntity, createWorkspaceEntity, updateWorkspaceEntity, deleteWorkspaceEntity, callAppEndpoint, initializeWorkspace, } from './core-workspace';
|
|
5287
5337
|
export type { WorkspaceUser, ListUsersOptions, ListUsersResponse, NotifyUserParams, NotifyUserResult, ListEntityRequest, ListEntityResponse, GetEntityRequest, CreateEntityRequest, UpdateEntityRequest, DeleteEntityRequest, RegisterEntityRequest, RegisterAppRequest, RegisterComponentRequest, RegisterScheduleRequest, RegisterWorkflowRequest, RegisterEndpointRequest, RegisterIntegrationRequest, CallAppEndpointOptions, CallAppEndpointResult, RegisterAgentRequest as WorkspaceRegisterAgentRequest, } from './core-workspace';
|
|
5338
|
+
`,
|
|
5339
|
+
"client.d.ts": `/**
|
|
5340
|
+
* Framework client entry: browser-side helpers an app's frontend imports as
|
|
5341
|
+
* \`@runworkai/framework/client\`, so app code never carries this plumbing
|
|
5342
|
+
* itself.
|
|
5343
|
+
*
|
|
5344
|
+
* Analytics: what people do in the app, reported to the workspace.
|
|
5345
|
+
*
|
|
5346
|
+
* Envelope follows the Segment Spec (the de-facto standard Google Analytics,
|
|
5347
|
+
* Mixpanel, PostHog and friends all map to), so nothing here needs to change
|
|
5348
|
+
* if the workspace later forwards events to a real analytics tool.
|
|
5349
|
+
*
|
|
5350
|
+
* The app does not interpret events. \`/api/analytics\` stamps the app's
|
|
5351
|
+
* identity and forwards to the workspace, which decides what each one means.
|
|
5352
|
+
* Today a \`page\` counts as one USE of the app, the multiplier behind a
|
|
5353
|
+
* standalone app's value in the workspace's reports. \`track\` events are kept
|
|
5354
|
+
* for a later analytics surface.
|
|
5355
|
+
*
|
|
5356
|
+
* A page load is reported here because the document is served before the
|
|
5357
|
+
* app's Worker runs, leaving no server-side trace otherwise. Once per
|
|
5358
|
+
* document, not per route change: the workspace counts an opened tool, and a
|
|
5359
|
+
* person navigating inside it is still one use.
|
|
5360
|
+
*
|
|
5361
|
+
* Fire-and-forget. Nothing here may ever affect the person using the app.
|
|
5362
|
+
*/
|
|
5363
|
+
/** Record a custom event. Use a flat Title Case name ("Report Exported") and put variables in properties. */
|
|
5364
|
+
export declare function track(event: string, properties?: Record<string, unknown>): void;
|
|
5365
|
+
/** Record a named screen or view inside the app. */
|
|
5366
|
+
export declare function screen(name: string, properties?: Record<string, unknown>): void;
|
|
5367
|
+
/**
|
|
5368
|
+
* Tell the workspace who this browser belongs to, in the APP's own terms.
|
|
5369
|
+
* A claim, recorded as data; the workspace never grants anything on it.
|
|
5370
|
+
*/
|
|
5371
|
+
export declare function identify(userId: string, traits?: Record<string, unknown>): void;
|
|
5372
|
+
/** Attach this person to a company, account or team the app knows about. */
|
|
5373
|
+
export declare function group(groupId: string, traits?: Record<string, unknown>): void;
|
|
5374
|
+
/** Link a past anonymous identity to a known one. */
|
|
5375
|
+
export declare function alias(userId: string, previousId?: string): void;
|
|
5376
|
+
/** Record that this app was opened. Called once automatically on load. */
|
|
5377
|
+
export declare function page(): void;
|
|
5288
5378
|
`,
|
|
5289
5379
|
"core-scheduler.d.ts": `/**
|
|
5290
5380
|
* Core Scheduled Jobs Framework
|
|
@@ -5936,8 +6026,6 @@ export type Doc<T> = {
|
|
|
5936
6026
|
* - Security validation on all field names
|
|
5937
6027
|
*/
|
|
5938
6028
|
export declare class EntityDO extends DurableObject<Env> {
|
|
5939
|
-
ctx: DurableObjectState;
|
|
5940
|
-
env: Env;
|
|
5941
6029
|
private _tableReady;
|
|
5942
6030
|
private _migrationDone;
|
|
5943
6031
|
constructor(ctx: DurableObjectState, env: Env);
|
|
@@ -6942,13 +7030,6 @@ export declare function toChannelName(appName: string): string;
|
|
|
6942
7030
|
* these entries in the observability timeline.
|
|
6943
7031
|
*/
|
|
6944
7032
|
export declare function flog(level: 'info' | 'warn' | 'error', system: string, message: string, data?: Record<string, unknown>): void;
|
|
6945
|
-
/**
|
|
6946
|
-
* Emit an event to the workspace unified event stream.
|
|
6947
|
-
* Fire-and-forget: uses ctx.waitUntil so it doesn't block the response.
|
|
6948
|
-
* Silently skips if workspace env vars are not configured (standalone mode).
|
|
6949
|
-
*
|
|
6950
|
-
* Automatically routes events to a channel derived from APP_NAME when available.
|
|
6951
|
-
*/
|
|
6952
7033
|
export declare function emitEvent(ctx: WaitUntilContext, env: EventEnv, event: EmitEventParams): void;
|
|
6953
7034
|
export {};
|
|
6954
7035
|
`,
|
|
@@ -7023,7 +7104,109 @@ export declare const isStr: (s: unknown) => s is string;
|
|
|
7023
7104
|
* that would cause structured clone to fail in ctx.storage.put().
|
|
7024
7105
|
*/
|
|
7025
7106
|
export declare function safeClone<T>(value: T, fallback?: T): T;
|
|
7026
|
-
|
|
7107
|
+
/**
|
|
7108
|
+
* Platform fetch - routes requests through WorkspaceObject DO for production workers.
|
|
7109
|
+
*
|
|
7110
|
+
* Workers for Platforms (WfP) workers cannot reliably make HTTP requests back to their
|
|
7111
|
+
* parent platform worker (they get 522 timeouts). This utility routes platform API calls
|
|
7112
|
+
* through the WorkspaceObject Durable Object binding, which works across worker boundaries.
|
|
7113
|
+
*
|
|
7114
|
+
* Supported paths:
|
|
7115
|
+
* - /api/proxy/integrations/* - Integration proxy (Nango)
|
|
7116
|
+
* - /api/proxy/openai/* - AI Gateway proxy
|
|
7117
|
+
* - /api/storage/presign - Storage presigned URLs
|
|
7118
|
+
*
|
|
7119
|
+
* For preview containers (DEPLOYMENT_MODE !== 'production'), uses standard fetch.
|
|
7120
|
+
*
|
|
7121
|
+
* @example
|
|
7122
|
+
* \`\`\`typescript
|
|
7123
|
+
* // Instead of:
|
|
7124
|
+
* const response = await fetch('https://runwork.ai/api/proxy/integrations/proxy/contacts', options);
|
|
7125
|
+
*
|
|
7126
|
+
* // Use:
|
|
7127
|
+
* const response = await platformFetch(env, 'https://runwork.ai/api/proxy/integrations/proxy/contacts', options);
|
|
7128
|
+
* \`\`\`
|
|
7129
|
+
*/
|
|
7130
|
+
/**
|
|
7131
|
+
* What the app was doing when it made a call.
|
|
7132
|
+
*
|
|
7133
|
+
* Internal plumbing, deliberately not exported from the package: app authors
|
|
7134
|
+
* never set this, the framework establishes it at each entry point (schedule
|
|
7135
|
+
* tick, workflow run, route handler, agent turn) and \`platformFetch\` below
|
|
7136
|
+
* reads it. It lives beside \`platformFetch\` because that is its only consumer.
|
|
7137
|
+
*
|
|
7138
|
+
* WHY IT EXISTS: usage rows record \`appId\` and \`userId\` and nothing about what
|
|
7139
|
+
* was executing, so a HubSpot call made by a nightly schedule cannot be told
|
|
7140
|
+
* apart from one a person made from their own agent. \`runId\` is the field that
|
|
7141
|
+
* cannot be reconstructed later: it links one run's AI calls and integration
|
|
7142
|
+
* calls together, which is what per-run cost is built from.
|
|
7143
|
+
*
|
|
7144
|
+
* Design: docs/plans/2026-08-28-baselines-capture-redesign.md section 4.1.
|
|
7145
|
+
*/
|
|
7146
|
+
export interface RunContext {
|
|
7147
|
+
/**
|
|
7148
|
+
* WHAT was executing. Only constructs the framework itself runs, never
|
|
7149
|
+
* "where the caller was" (a browser, MCP, the CLI): that is a different
|
|
7150
|
+
* question and \`audit_logs.actor_type\` owns it.
|
|
7151
|
+
*/
|
|
7152
|
+
kind: 'schedule' | 'workflow' | 'endpoint' | 'route' | 'agent';
|
|
7153
|
+
/**
|
|
7154
|
+
* Human-readable name, following the convention the audit rows already use:
|
|
7155
|
+
* a schedule/workflow/agent slug, or \`METHOD /path\` for endpoints and routes.
|
|
7156
|
+
*
|
|
7157
|
+
* OMITTED rather than defaulted when genuinely unknown. A placeholder string
|
|
7158
|
+
* like 'unknown' becomes a value every query has to filter out, and it is
|
|
7159
|
+
* indistinguishable from an app that named something 'unknown'.
|
|
7160
|
+
*/
|
|
7161
|
+
name?: string;
|
|
7162
|
+
/**
|
|
7163
|
+
* App-local registry key, so a usage row joins back to a registration. The
|
|
7164
|
+
* app id is a column of its own, so this is the part after it: a slug for
|
|
7165
|
+
* schedules, workflows and agents, \`METHOD /path\` for endpoints.
|
|
7166
|
+
*/
|
|
7167
|
+
resourceKey?: string;
|
|
7168
|
+
/** One id shared by everything emitted inside this execution. */
|
|
7169
|
+
runId: string;
|
|
7170
|
+
/** The enclosing run, for workflow steps, nested calls and sub-agents. */
|
|
7171
|
+
parentRunId?: string;
|
|
7172
|
+
trigger?: 'cron' | 'manual' | 'webhook' | 'chat' | 'api';
|
|
7173
|
+
/**
|
|
7174
|
+
* The person who started this run. Named to match the governance program's
|
|
7175
|
+
* \`DelegationChain.triggererUserId\` (\`worker/types/permissions.ts\`), which is
|
|
7176
|
+
* the same fact: one name for it across both programs.
|
|
7177
|
+
*
|
|
7178
|
+
* ATTRIBUTION, NEVER AUTHORITY. This travels on a header from the app, behind
|
|
7179
|
+
* the shared WORKSPACE_API_KEY, so an app can put any user id here. The
|
|
7180
|
+
* platform may RECORD it; nothing may ever AUTHORIZE on it. Whose authority a
|
|
7181
|
+
* run borrows is resolved platform-side by PermissionService, not stated by
|
|
7182
|
+
* the caller.
|
|
7183
|
+
*/
|
|
7184
|
+
triggererUserId?: string;
|
|
7185
|
+
attempt?: number;
|
|
7186
|
+
}
|
|
7187
|
+
/** Header carrying the context to the platform side, which writes the audit row. */
|
|
7188
|
+
export declare const RUN_CONTEXT_HEADER = "x-runwork-run-context";
|
|
7189
|
+
/**
|
|
7190
|
+
* Run \`fn\` with \`ctx\` as the ambient execution context.
|
|
7191
|
+
*
|
|
7192
|
+
* Nesting is automatic: entering a context inside another records the outer
|
|
7193
|
+
* \`runId\` as \`parentRunId\` unless the caller set one. That is what makes a
|
|
7194
|
+
* sub-agent's calls point at the run that started it. Re-entering the SAME
|
|
7195
|
+
* run id is not nesting (a workflow resumes into its own run across wake-ups)
|
|
7196
|
+
* and must not make a run its own parent.
|
|
7197
|
+
*/
|
|
7198
|
+
export declare function withRunContext<T>(ctx: RunContext, fn: () => T): T;
|
|
7199
|
+
/** The current execution context, or undefined outside any entry point. */
|
|
7200
|
+
export declare function getRunContext(): RunContext | undefined;
|
|
7201
|
+
/**
|
|
7202
|
+
* Merge the context header into request headers.
|
|
7203
|
+
*
|
|
7204
|
+
* One serialised header rather than several, so adding a field never needs a
|
|
7205
|
+
* matching change in the platform's parsing. Never overwrites a header the
|
|
7206
|
+
* caller set: a caller that knows its own context beats the ambient one.
|
|
7207
|
+
*/
|
|
7208
|
+
export declare function withRunContextHeader(init?: HeadersInit): HeadersInit | undefined;
|
|
7209
|
+
export declare function platformFetch(env: Env, url: string | URL, rawInit?: RequestInit): Promise<Response>;
|
|
7027
7210
|
/**
|
|
7028
7211
|
* Workspace API fetch - routes workspace service requests through WorkspaceObject DO
|
|
7029
7212
|
* for production WfP workers, avoiding 522 recursive invocation errors.
|
|
@@ -7036,7 +7219,7 @@ export declare function platformFetch(env: Env, url: string | URL, init?: Reques
|
|
|
7036
7219
|
* @param path - Workspace API sub-path (e.g., '/ingest-event')
|
|
7037
7220
|
* @param init - Standard fetch options
|
|
7038
7221
|
*/
|
|
7039
|
-
export declare function workspaceApiFetch(env: Pick<Env, 'WORKSPACE_API_URL' | 'WORKSPACE_API_KEY' | 'WORKSPACE_ID' | 'DEPLOYMENT_MODE' | 'WorkspaceObject'>, path: string,
|
|
7222
|
+
export declare function workspaceApiFetch(env: Pick<Env, 'WORKSPACE_API_URL' | 'WORKSPACE_API_KEY' | 'WORKSPACE_ID' | 'DEPLOYMENT_MODE' | 'WorkspaceObject'>, path: string, rawInit?: RequestInit): Promise<Response>;
|
|
7040
7223
|
`,
|
|
7041
7224
|
"workflows.d.ts": `import type { WorkflowDefinition } from './core-workflow-types';
|
|
7042
7225
|
/**
|
|
@@ -7231,7 +7414,7 @@ export declare class BaseAgent extends AIChatAgent<Env> {
|
|
|
7231
7414
|
* - Types are defined in core-workflow-types.ts
|
|
7232
7415
|
* - Native DO-based implementation is in core-workflow-instance.ts and core-workflow-coordinator.ts
|
|
7233
7416
|
*/
|
|
7234
|
-
import type
|
|
7417
|
+
import { type Env } from './core-utils';
|
|
7235
7418
|
export type { WorkflowResult, WorkflowStatus, WorkflowInstanceInfo, WorkflowDefinition, WorkflowContext, WorkflowStepUtilities, StepOptions, WaitEventOptions, WorkflowLogger, WorkflowState, WorkflowStatusResponse, } from './core-workflow-types';
|
|
7236
7419
|
import type { WorkflowInstanceInfo } from './core-workflow-types';
|
|
7237
7420
|
/**
|
|
@@ -7780,8 +7963,8 @@ export declare const integrationApiSchema: z.ZodObject<{
|
|
|
7780
7963
|
endpoint: z.ZodString;
|
|
7781
7964
|
data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
7782
7965
|
}, "strip", z.ZodTypeAny, {
|
|
7783
|
-
method: "POST" | "GET" | "PUT" | "PATCH" | "DELETE";
|
|
7784
7966
|
endpoint: string;
|
|
7967
|
+
method: "POST" | "GET" | "PUT" | "PATCH" | "DELETE";
|
|
7785
7968
|
data?: Record<string, unknown> | undefined;
|
|
7786
7969
|
}, {
|
|
7787
7970
|
endpoint: string;
|
|
@@ -8022,7 +8205,7 @@ function createKeyboardListener() {
|
|
|
8022
8205
|
}
|
|
8023
8206
|
|
|
8024
8207
|
// src/generated/version.ts
|
|
8025
|
-
var VERSION = "0.
|
|
8208
|
+
var VERSION = "0.27.0";
|
|
8026
8209
|
|
|
8027
8210
|
// src/commands/dev.ts
|
|
8028
8211
|
var exports_dev = {};
|
|
@@ -8103,6 +8286,7 @@ async function execDev(options) {
|
|
|
8103
8286
|
await ensureGitCredentialHelper(creds.baseUrl);
|
|
8104
8287
|
}
|
|
8105
8288
|
ensureRunworkRemote(cwd, client.getGitRemoteUrl(config.workspaceId, config.appId));
|
|
8289
|
+
let editsUnprotected = false;
|
|
8106
8290
|
const oldManifest = await loadManifest(cwd);
|
|
8107
8291
|
if (oldManifest) {
|
|
8108
8292
|
const userEdits = await detectUserEdits(cwd, oldManifest);
|
|
@@ -8126,9 +8310,22 @@ async function execDev(options) {
|
|
|
8126
8310
|
execFileSync("git", ["add", "--", ...userEdits], { stdio: "pipe" });
|
|
8127
8311
|
execFileSync("git", ["commit", "-m", "sync: user edits"], { stdio: "pipe" });
|
|
8128
8312
|
} catch {}
|
|
8313
|
+
editsUnprotected = hasTrackedChanges(cwd);
|
|
8314
|
+
if (editsUnprotected) {
|
|
8315
|
+
if (useJson) {
|
|
8316
|
+
jsonLine({
|
|
8317
|
+
event: "startup",
|
|
8318
|
+
phase: "user_edits_unprotected",
|
|
8319
|
+
timestamp: ts(),
|
|
8320
|
+
warning: "Could not commit your edits (a commit hook or lock may be interfering). Skipping the template update so they are not lost."
|
|
8321
|
+
});
|
|
8322
|
+
} else {
|
|
8323
|
+
console.warn(yellow("Could not commit your edits (a commit hook or lock may be interfering). Skipping the template update so they are not lost."));
|
|
8324
|
+
}
|
|
8325
|
+
}
|
|
8129
8326
|
}
|
|
8130
8327
|
}
|
|
8131
|
-
if (!noSync) {
|
|
8328
|
+
if (!noSync && !editsUnprotected) {
|
|
8132
8329
|
if (useJson) {
|
|
8133
8330
|
jsonLine({ event: "startup", phase: "template_update", timestamp: ts() });
|
|
8134
8331
|
} else {
|
|
@@ -8971,10 +9168,39 @@ function startAppProbeScript(pattern) {
|
|
|
8971
9168
|
function isCommandNotFoundExit(code) {
|
|
8972
9169
|
return typeof code === "number" && COMMAND_NOT_FOUND_EXIT_CODES.includes(code);
|
|
8973
9170
|
}
|
|
8974
|
-
|
|
9171
|
+
function expandWindowsPathTemplate(path2, resolved) {
|
|
9172
|
+
for (const [placeholder, defaults] of Object.entries(WINDOWS_PATH_PLACEHOLDERS)) {
|
|
9173
|
+
if (!path2.startsWith(placeholder))
|
|
9174
|
+
continue;
|
|
9175
|
+
const rest = path2.slice(placeholder.length).replace(/^[/\\]/, "");
|
|
9176
|
+
const fromEnv = resolved[placeholder];
|
|
9177
|
+
if (fromEnv) {
|
|
9178
|
+
return { path: `${fromEnv.replace(/[/\\]+$/, "")}\\${rest.replace(/\//g, "\\")}`, needsHomeJoin: false };
|
|
9179
|
+
}
|
|
9180
|
+
if ("absoluteDefault" in defaults) {
|
|
9181
|
+
return { path: `${defaults.absoluteDefault}\\${rest.replace(/\//g, "\\")}`, needsHomeJoin: false };
|
|
9182
|
+
}
|
|
9183
|
+
return { path: `${defaults.homeRelativeDefault}/${rest}`, needsHomeJoin: true };
|
|
9184
|
+
}
|
|
9185
|
+
return { path: path2, needsHomeJoin: !/^([A-Za-z]:[\\/]|\\\\|\/)/.test(path2) };
|
|
9186
|
+
}
|
|
9187
|
+
function parseConfigDeclaredPath(text2, key) {
|
|
9188
|
+
const escapedKey = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
9189
|
+
const match = new RegExp(`^\\s*${escapedKey}\\s*=\\s*"((?:[^"\\\\]|\\\\.)*)"`, "m").exec(text2);
|
|
9190
|
+
if (!match)
|
|
9191
|
+
return null;
|
|
9192
|
+
const path2 = match[1].replace(/\\(.)/g, "$1");
|
|
9193
|
+
return path2 || null;
|
|
9194
|
+
}
|
|
9195
|
+
var PATH_REFRESH_FAILED_MARKER = "__runwork_path_refresh_failed__", WINDOWS_PATH_REFRESH, COMMAND_NOT_FOUND_EXIT_CODES, WINDOWS_PATH_PLACEHOLDERS;
|
|
8975
9196
|
var init_detection_probes = __esm(() => {
|
|
8976
9197
|
WINDOWS_PATH_REFRESH = "try { $env:Path = [Environment]::GetEnvironmentVariable('Path','Machine') + ';' + " + "[Environment]::GetEnvironmentVariable('Path','User') + ';' + $env:Path } " + `catch { Write-Output '${PATH_REFRESH_FAILED_MARKER}' }; `;
|
|
8977
9198
|
COMMAND_NOT_FOUND_EXIT_CODES = [127, 9009];
|
|
9199
|
+
WINDOWS_PATH_PLACEHOLDERS = {
|
|
9200
|
+
"%APPDATA%": { homeRelativeDefault: "AppData/Roaming" },
|
|
9201
|
+
"%LOCALAPPDATA%": { homeRelativeDefault: "AppData/Local" },
|
|
9202
|
+
"%ProgramFiles%": { absoluteDefault: "C:\\Program Files" }
|
|
9203
|
+
};
|
|
8978
9204
|
});
|
|
8979
9205
|
|
|
8980
9206
|
// src/utils/which.ts
|
|
@@ -9387,6 +9613,9 @@ function getAgent(slug) {
|
|
|
9387
9613
|
function getAgents() {
|
|
9388
9614
|
return AGENT_REGISTRY;
|
|
9389
9615
|
}
|
|
9616
|
+
function getDetectableAgents() {
|
|
9617
|
+
return AGENT_REGISTRY.filter((a) => a.detection);
|
|
9618
|
+
}
|
|
9390
9619
|
function isConnectOnlyAgent(agent) {
|
|
9391
9620
|
if (!agent)
|
|
9392
9621
|
return false;
|
|
@@ -9415,11 +9644,15 @@ function resolveAgentCli(agent) {
|
|
|
9415
9644
|
return;
|
|
9416
9645
|
return detectionBinaryTarget(agent.detection);
|
|
9417
9646
|
}
|
|
9418
|
-
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;
|
|
9647
|
+
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;
|
|
9419
9648
|
var init_registry_data = __esm(() => {
|
|
9420
9649
|
CLAUDE_CODE_NATIVE_INSTALL_PATHS = [
|
|
9421
9650
|
{ macos: ".local/bin/claude", linux: ".local/bin/claude", windows: ".local/bin/claude.exe" }
|
|
9422
9651
|
];
|
|
9652
|
+
CODEX_BUNDLED_CLI_PATHS = [
|
|
9653
|
+
{ macos: "/Applications/ChatGPT.app/Contents/Resources/codex" },
|
|
9654
|
+
{ macos: "/Applications/Codex.app/Contents/Resources/codex" }
|
|
9655
|
+
];
|
|
9423
9656
|
AGENT_REGISTRY = [
|
|
9424
9657
|
{
|
|
9425
9658
|
slug: "claude-code",
|
|
@@ -9477,7 +9710,7 @@ var init_registry_data = __esm(() => {
|
|
|
9477
9710
|
{
|
|
9478
9711
|
method: "path",
|
|
9479
9712
|
target: {
|
|
9480
|
-
windows: "
|
|
9713
|
+
windows: "%APPDATA%/Claude/claude_desktop_config.json",
|
|
9481
9714
|
linux: ".config/Claude/claude_desktop_config.json"
|
|
9482
9715
|
}
|
|
9483
9716
|
}
|
|
@@ -9490,7 +9723,7 @@ var init_registry_data = __esm(() => {
|
|
|
9490
9723
|
skillsPaths: { global: ".claude/skills", project: ".claude/skills" },
|
|
9491
9724
|
mcpConfigPath: {
|
|
9492
9725
|
macos: "Library/Application Support/Claude/claude_desktop_config.json",
|
|
9493
|
-
windows: "
|
|
9726
|
+
windows: "%APPDATA%/Claude/claude_desktop_config.json",
|
|
9494
9727
|
linux: ".config/Claude/claude_desktop_config.json"
|
|
9495
9728
|
},
|
|
9496
9729
|
mcpConfigKey: "mcpServers",
|
|
@@ -9651,8 +9884,18 @@ var init_registry_data = __esm(() => {
|
|
|
9651
9884
|
name: "Codex CLI",
|
|
9652
9885
|
description: "AI in your terminal by OpenAI, great for coding, debugging, and automating dev tasks",
|
|
9653
9886
|
category: "cli",
|
|
9654
|
-
detection: {
|
|
9655
|
-
|
|
9887
|
+
detection: {
|
|
9888
|
+
method: "any",
|
|
9889
|
+
target: [
|
|
9890
|
+
{ method: "binary", target: "codex" },
|
|
9891
|
+
{
|
|
9892
|
+
method: "config-value",
|
|
9893
|
+
target: { file: CODEX_CONFIG_FILE, key: "CODEX_CLI_PATH" }
|
|
9894
|
+
},
|
|
9895
|
+
...CODEX_BUNDLED_CLI_PATHS.map((target) => ({ method: "path", target }))
|
|
9896
|
+
]
|
|
9897
|
+
},
|
|
9898
|
+
launch: { cli: "codex", cliAcceptsPrompt: true, cliWellKnownPaths: CODEX_BUNDLED_CLI_PATHS },
|
|
9656
9899
|
logo: "codex",
|
|
9657
9900
|
downloadUrl: "https://learn.chatgpt.com/docs/codex/cli",
|
|
9658
9901
|
install: {
|
|
@@ -9689,6 +9932,7 @@ var init_registry_data = __esm(() => {
|
|
|
9689
9932
|
launch: { url: "https://chatgpt.com/?prompt={prompt}" },
|
|
9690
9933
|
logo: "openai",
|
|
9691
9934
|
downloadUrl: "https://chatgpt.com",
|
|
9935
|
+
suggestsCli: "codex",
|
|
9692
9936
|
firstClass: true,
|
|
9693
9937
|
resumeCapability: {
|
|
9694
9938
|
mode: "url-prompt",
|
|
@@ -9745,6 +9989,7 @@ var init_registry_data = __esm(() => {
|
|
|
9745
9989
|
]
|
|
9746
9990
|
},
|
|
9747
9991
|
launch: { app: { macos: "ChatGPT Classic", windows: "ChatGPT Classic" }, bundleId: { macos: "com.openai.chat" }, appxPackage: "OpenAI.ChatGPT", url: "https://chatgpt.com/?prompt={prompt}" },
|
|
9992
|
+
suggestsCli: "codex",
|
|
9748
9993
|
logo: "openai",
|
|
9749
9994
|
downloadUrl: "https://chatgpt.com/download",
|
|
9750
9995
|
downloadUrls: {
|
|
@@ -9800,8 +10045,8 @@ var init_registry_data = __esm(() => {
|
|
|
9800
10045
|
target: [
|
|
9801
10046
|
{ method: "binary", target: "windsurf" },
|
|
9802
10047
|
{ method: "path", target: { macos: "/Applications/Windsurf.app" } },
|
|
9803
|
-
{ method: "path", target: { windows: "
|
|
9804
|
-
{ method: "path", target: { windows: "
|
|
10048
|
+
{ method: "path", target: { windows: "%LOCALAPPDATA%/Programs/Windsurf" } },
|
|
10049
|
+
{ method: "path", target: { windows: "%ProgramFiles%/Windsurf" } }
|
|
9805
10050
|
]
|
|
9806
10051
|
},
|
|
9807
10052
|
launch: { app: { macos: "Windsurf", windows: "Windsurf" } },
|
|
@@ -9881,7 +10126,14 @@ var init_registry_data = __esm(() => {
|
|
|
9881
10126
|
name: "GitHub Copilot (VS Code)",
|
|
9882
10127
|
description: "GitHub's AI pair programmer in VS Code",
|
|
9883
10128
|
category: "extension",
|
|
9884
|
-
detection: {
|
|
10129
|
+
detection: {
|
|
10130
|
+
method: "path",
|
|
10131
|
+
target: {
|
|
10132
|
+
macos: "Library/Application Support/Code/User/globalStorage/github.copilot",
|
|
10133
|
+
windows: "%APPDATA%/Code/User/globalStorage/github.copilot",
|
|
10134
|
+
linux: ".config/Code/User/globalStorage/github.copilot"
|
|
10135
|
+
}
|
|
10136
|
+
},
|
|
9885
10137
|
launch: { app: { macos: "Visual Studio Code", windows: "Code" }, cli: "code" },
|
|
9886
10138
|
logo: "vscode",
|
|
9887
10139
|
downloadUrl: "https://marketplace.visualstudio.com/items?itemName=GitHub.copilot",
|
|
@@ -9983,12 +10235,145 @@ var init_registry_data = __esm(() => {
|
|
|
9983
10235
|
getRegistryAgents = getAgents;
|
|
9984
10236
|
});
|
|
9985
10237
|
|
|
10238
|
+
// src/agents/detection.ts
|
|
10239
|
+
import { execFile } from "child_process";
|
|
10240
|
+
import { existsSync as existsSync26, readFileSync as readFileSync23 } from "fs";
|
|
10241
|
+
import { homedir as homedir6, platform as platform2 } from "os";
|
|
10242
|
+
import { join as join22 } from "path";
|
|
10243
|
+
import { promisify } from "util";
|
|
10244
|
+
function isWindows() {
|
|
10245
|
+
return platform2() === "win32";
|
|
10246
|
+
}
|
|
10247
|
+
function toList(value) {
|
|
10248
|
+
return Array.isArray(value) ? value : [value];
|
|
10249
|
+
}
|
|
10250
|
+
async function runPowerShell(script) {
|
|
10251
|
+
const execFileAsync = promisify(execFile);
|
|
10252
|
+
try {
|
|
10253
|
+
await execFileAsync("powershell", ["-NoProfile", "-Command", script]);
|
|
10254
|
+
return true;
|
|
10255
|
+
} catch {
|
|
10256
|
+
return false;
|
|
10257
|
+
}
|
|
10258
|
+
}
|
|
10259
|
+
function resolveDetectionPath(target) {
|
|
10260
|
+
const resolved = resolvePlatformString(target);
|
|
10261
|
+
if (!resolved)
|
|
10262
|
+
return null;
|
|
10263
|
+
const expanded = expandWindowsPathTemplate(resolved, {
|
|
10264
|
+
"%APPDATA%": process.env.APPDATA,
|
|
10265
|
+
"%LOCALAPPDATA%": process.env.LOCALAPPDATA,
|
|
10266
|
+
"%ProgramFiles%": process.env.ProgramFiles
|
|
10267
|
+
});
|
|
10268
|
+
return expanded.needsHomeJoin ? join22(homedir6(), expanded.path) : expanded.path;
|
|
10269
|
+
}
|
|
10270
|
+
function checkPath(target) {
|
|
10271
|
+
const absolute = resolveDetectionPath(target);
|
|
10272
|
+
if (!absolute)
|
|
10273
|
+
return null;
|
|
10274
|
+
return existsSync26(absolute) ? absolute : null;
|
|
10275
|
+
}
|
|
10276
|
+
function checkConfigDeclaredPath(target) {
|
|
10277
|
+
const configPath = resolveDetectionPath(target.file);
|
|
10278
|
+
if (!configPath)
|
|
10279
|
+
return null;
|
|
10280
|
+
let text2;
|
|
10281
|
+
try {
|
|
10282
|
+
if (!existsSync26(configPath))
|
|
10283
|
+
return null;
|
|
10284
|
+
text2 = readFileSync23(configPath, "utf-8");
|
|
10285
|
+
} catch {
|
|
10286
|
+
return null;
|
|
10287
|
+
}
|
|
10288
|
+
const declared = parseConfigDeclaredPath(text2, target.key);
|
|
10289
|
+
return declared && existsSync26(declared) ? declared : null;
|
|
10290
|
+
}
|
|
10291
|
+
async function checkMacosBundleId(target) {
|
|
10292
|
+
if (platform2() !== "darwin")
|
|
10293
|
+
return false;
|
|
10294
|
+
const execFileAsync = promisify(execFile);
|
|
10295
|
+
for (const id of toList(target)) {
|
|
10296
|
+
if (!isValidBundleId(id))
|
|
10297
|
+
continue;
|
|
10298
|
+
try {
|
|
10299
|
+
await execFileAsync("sh", ["-c", macosBundleIdProbeScript(id)]);
|
|
10300
|
+
return true;
|
|
10301
|
+
} catch {}
|
|
10302
|
+
}
|
|
10303
|
+
return false;
|
|
10304
|
+
}
|
|
10305
|
+
async function checkWindowsAppxPackage(target) {
|
|
10306
|
+
if (!isWindows())
|
|
10307
|
+
return false;
|
|
10308
|
+
const probes = toList(target).map((pkg) => runPowerShell(appxPackageProbeScript(pkg)));
|
|
10309
|
+
const results = await Promise.all(probes);
|
|
10310
|
+
return results.some(Boolean);
|
|
10311
|
+
}
|
|
10312
|
+
async function checkWindowsStartApp(target) {
|
|
10313
|
+
if (!isWindows())
|
|
10314
|
+
return false;
|
|
10315
|
+
const probes = toList(target).map((pattern) => runPowerShell(startAppProbeScript(pattern)));
|
|
10316
|
+
const results = await Promise.all(probes);
|
|
10317
|
+
return results.some(Boolean);
|
|
10318
|
+
}
|
|
10319
|
+
async function runAgentDetectionDetailed(detection) {
|
|
10320
|
+
switch (detection.method) {
|
|
10321
|
+
case "binary": {
|
|
10322
|
+
const target = resolvePlatformString(detection.target);
|
|
10323
|
+
const resolved = target ? whichBinary(target) : null;
|
|
10324
|
+
return resolved ? { detected: true, via: "binary", resolvedPath: resolved } : NOT_DETECTED;
|
|
10325
|
+
}
|
|
10326
|
+
case "path": {
|
|
10327
|
+
const resolved = checkPath(detection.target);
|
|
10328
|
+
return resolved ? { detected: true, via: "path", resolvedPath: resolved } : NOT_DETECTED;
|
|
10329
|
+
}
|
|
10330
|
+
case "config-value": {
|
|
10331
|
+
const resolved = checkConfigDeclaredPath(detection.target);
|
|
10332
|
+
return resolved ? { detected: true, via: "config-value", resolvedPath: resolved } : NOT_DETECTED;
|
|
10333
|
+
}
|
|
10334
|
+
case "windows-appx":
|
|
10335
|
+
return await checkWindowsAppxPackage(detection.target) ? { detected: true, via: "windows-appx" } : NOT_DETECTED;
|
|
10336
|
+
case "windows-start-app":
|
|
10337
|
+
return await checkWindowsStartApp(detection.target) ? { detected: true, via: "windows-start-app" } : NOT_DETECTED;
|
|
10338
|
+
case "macos-bundle-id":
|
|
10339
|
+
return await checkMacosBundleId(detection.target) ? { detected: true, via: "macos-bundle-id" } : NOT_DETECTED;
|
|
10340
|
+
case "any": {
|
|
10341
|
+
const probes = await Promise.all(detection.target.map((p) => runAgentDetectionDetailed(p)));
|
|
10342
|
+
return probes.find((p) => p.detected) ?? NOT_DETECTED;
|
|
10343
|
+
}
|
|
10344
|
+
case "always":
|
|
10345
|
+
return { detected: true, via: "always" };
|
|
10346
|
+
default:
|
|
10347
|
+
return NOT_DETECTED;
|
|
10348
|
+
}
|
|
10349
|
+
}
|
|
10350
|
+
async function runAgentDetection(detection) {
|
|
10351
|
+
return (await runAgentDetectionDetailed(detection)).detected;
|
|
10352
|
+
}
|
|
10353
|
+
|
|
10354
|
+
class RegistryDetectedAdapter {
|
|
10355
|
+
async detect() {
|
|
10356
|
+
const def = getRegistryAgent(this.slug);
|
|
10357
|
+
if (!def)
|
|
10358
|
+
return false;
|
|
10359
|
+
return runAgentDetection(def.detection);
|
|
10360
|
+
}
|
|
10361
|
+
}
|
|
10362
|
+
var NOT_DETECTED;
|
|
10363
|
+
var init_detection = __esm(() => {
|
|
10364
|
+
init_which();
|
|
10365
|
+
init_registry_data();
|
|
10366
|
+
init_registry();
|
|
10367
|
+
init_detection_probes();
|
|
10368
|
+
NOT_DETECTED = { detected: false };
|
|
10369
|
+
});
|
|
10370
|
+
|
|
9986
10371
|
// src/agents/registry.ts
|
|
9987
|
-
import { platform as
|
|
9988
|
-
import { isAbsolute as
|
|
9989
|
-
import { existsSync as
|
|
10372
|
+
import { platform as platform3, homedir as homedir7 } from "os";
|
|
10373
|
+
import { isAbsolute as isAbsolute3, join as join23 } from "path";
|
|
10374
|
+
import { existsSync as existsSync27 } from "fs";
|
|
9990
10375
|
function getNodePlatform() {
|
|
9991
|
-
const p =
|
|
10376
|
+
const p = platform3();
|
|
9992
10377
|
if (p === "darwin")
|
|
9993
10378
|
return "macos";
|
|
9994
10379
|
if (p === "win32")
|
|
@@ -10005,7 +10390,7 @@ function resolveToAbsolute(ps, scope) {
|
|
|
10005
10390
|
const resolved = resolvePlatformString(ps);
|
|
10006
10391
|
if (!resolved)
|
|
10007
10392
|
return;
|
|
10008
|
-
return scope === "global" ?
|
|
10393
|
+
return scope === "global" ? join23(homedir7(), resolved) : join23(process.cwd(), resolved);
|
|
10009
10394
|
}
|
|
10010
10395
|
function resolveAgentCliCommand(slug) {
|
|
10011
10396
|
const agent = getAgent(slug);
|
|
@@ -10014,19 +10399,40 @@ function resolveAgentCliCommand(slug) {
|
|
|
10014
10399
|
return null;
|
|
10015
10400
|
if (whichBinary(cli))
|
|
10016
10401
|
return cli;
|
|
10402
|
+
const declared = vendorDeclaredCliPath(slug);
|
|
10403
|
+
if (declared)
|
|
10404
|
+
return declared;
|
|
10017
10405
|
for (const candidate of agent?.launch?.cliWellKnownPaths ?? []) {
|
|
10018
10406
|
const resolved = resolvePlatformString(candidate);
|
|
10019
10407
|
if (!resolved)
|
|
10020
10408
|
continue;
|
|
10021
|
-
const absolute =
|
|
10022
|
-
if (
|
|
10409
|
+
const absolute = isAbsolute3(resolved) ? resolved : join23(homedir7(), resolved);
|
|
10410
|
+
if (existsSync27(absolute))
|
|
10023
10411
|
return absolute;
|
|
10024
10412
|
}
|
|
10025
10413
|
return null;
|
|
10026
10414
|
}
|
|
10415
|
+
function configValueMatchers(detection) {
|
|
10416
|
+
if (!detection)
|
|
10417
|
+
return [];
|
|
10418
|
+
if (detection.method === "config-value")
|
|
10419
|
+
return [detection.target];
|
|
10420
|
+
if (detection.method === "any")
|
|
10421
|
+
return detection.target.flatMap(configValueMatchers);
|
|
10422
|
+
return [];
|
|
10423
|
+
}
|
|
10424
|
+
function vendorDeclaredCliPath(slug) {
|
|
10425
|
+
for (const matcher of configValueMatchers(getAgent(slug)?.detection)) {
|
|
10426
|
+
const resolved = checkConfigDeclaredPath(matcher);
|
|
10427
|
+
if (resolved)
|
|
10428
|
+
return resolved;
|
|
10429
|
+
}
|
|
10430
|
+
return null;
|
|
10431
|
+
}
|
|
10027
10432
|
var init_registry = __esm(() => {
|
|
10028
10433
|
init_which();
|
|
10029
10434
|
init_registry_data();
|
|
10435
|
+
init_detection();
|
|
10030
10436
|
init_registry_data();
|
|
10031
10437
|
});
|
|
10032
10438
|
|
|
@@ -10867,6 +11273,8 @@ function scanClaudeJsonlHead(head) {
|
|
|
10867
11273
|
result.firstTimestamp = o.timestamp;
|
|
10868
11274
|
if (!result.cwd && typeof o.cwd === "string")
|
|
10869
11275
|
result.cwd = o.cwd;
|
|
11276
|
+
if (!result.surface && typeof o.entrypoint === "string")
|
|
11277
|
+
result.surface = o.entrypoint;
|
|
10870
11278
|
if (!result.title && o.type === "ai-title" && typeof o.aiTitle === "string") {
|
|
10871
11279
|
result.title = titleFromText(o.aiTitle);
|
|
10872
11280
|
}
|
|
@@ -10892,7 +11300,7 @@ function scanClaudeJsonlHead(head) {
|
|
|
10892
11300
|
}
|
|
10893
11301
|
}
|
|
10894
11302
|
}
|
|
10895
|
-
if (result.title && result.firstTimestamp && result.cwd)
|
|
11303
|
+
if (result.title && result.firstTimestamp && result.cwd && result.surface)
|
|
10896
11304
|
break;
|
|
10897
11305
|
}
|
|
10898
11306
|
if (!result.title && firstUserText)
|
|
@@ -10921,6 +11329,8 @@ function scanCodexRolloutHead(head) {
|
|
|
10921
11329
|
result.cwd = p.cwd;
|
|
10922
11330
|
if (typeof p.id === "string" && !result.sessionId)
|
|
10923
11331
|
result.sessionId = p.id;
|
|
11332
|
+
if (typeof p.originator === "string" && !result.surface)
|
|
11333
|
+
result.surface = p.originator;
|
|
10924
11334
|
}
|
|
10925
11335
|
if (!result.title && o.type === "response_item" && p.type === "message" && p.role === "user" && Array.isArray(p.content)) {
|
|
10926
11336
|
for (const item of p.content) {
|
|
@@ -11020,23 +11430,23 @@ function skillNameFromPath(path2) {
|
|
|
11020
11430
|
}
|
|
11021
11431
|
|
|
11022
11432
|
// src/utils/trash.ts
|
|
11023
|
-
import { cpSync, existsSync as
|
|
11024
|
-
import { basename as basename2, dirname as dirname6, join as
|
|
11025
|
-
import { homedir as
|
|
11433
|
+
import { cpSync, existsSync as existsSync28, mkdirSync as mkdirSync13, readdirSync as readdirSync5, renameSync as renameSync3, rmSync as rmSync4, statSync as statSync3 } from "fs";
|
|
11434
|
+
import { basename as basename2, dirname as dirname6, join as join24 } from "path";
|
|
11435
|
+
import { homedir as homedir8 } from "os";
|
|
11026
11436
|
function trashRoot() {
|
|
11027
|
-
return
|
|
11437
|
+
return join24(homedir8(), ".runwork", "trash");
|
|
11028
11438
|
}
|
|
11029
11439
|
function batchDir(now) {
|
|
11030
11440
|
const stamp = now.toISOString().replace(/[:.]/g, "-");
|
|
11031
|
-
return
|
|
11441
|
+
return join24(trashRoot(), `${stamp}-${process.pid}`);
|
|
11032
11442
|
}
|
|
11033
11443
|
function pruneTrash(now = new Date) {
|
|
11034
11444
|
const root = trashRoot();
|
|
11035
|
-
if (!
|
|
11445
|
+
if (!existsSync28(root))
|
|
11036
11446
|
return;
|
|
11037
11447
|
const cutoff = now.getTime() - TRASH_RETENTION_DAYS * 24 * 60 * 60 * 1000;
|
|
11038
11448
|
for (const entry of readdirSync5(root)) {
|
|
11039
|
-
const dir =
|
|
11449
|
+
const dir = join24(root, entry);
|
|
11040
11450
|
try {
|
|
11041
11451
|
if (statSync3(dir).mtimeMs < cutoff)
|
|
11042
11452
|
rmSync4(dir, { recursive: true, force: true });
|
|
@@ -11044,7 +11454,7 @@ function pruneTrash(now = new Date) {
|
|
|
11044
11454
|
}
|
|
11045
11455
|
}
|
|
11046
11456
|
function moveToTrash(sourcePath, reason, now = new Date) {
|
|
11047
|
-
if (!
|
|
11457
|
+
if (!existsSync28(sourcePath))
|
|
11048
11458
|
return null;
|
|
11049
11459
|
if (!activeBatch || !activeBatch.startsWith(trashRoot())) {
|
|
11050
11460
|
activeBatch = batchDir(now);
|
|
@@ -11052,8 +11462,8 @@ function moveToTrash(sourcePath, reason, now = new Date) {
|
|
|
11052
11462
|
}
|
|
11053
11463
|
const parent = basename2(dirname6(sourcePath));
|
|
11054
11464
|
const grandparent = basename2(dirname6(dirname6(sourcePath)));
|
|
11055
|
-
const destDir =
|
|
11056
|
-
const dest =
|
|
11465
|
+
const destDir = join24(activeBatch, `${grandparent}__${parent}`.replace(/[^a-zA-Z0-9._-]/g, "-"));
|
|
11466
|
+
const dest = join24(destDir, basename2(sourcePath));
|
|
11057
11467
|
try {
|
|
11058
11468
|
mkdirSync13(destDir, { recursive: true });
|
|
11059
11469
|
try {
|
|
@@ -11065,7 +11475,7 @@ function moveToTrash(sourcePath, reason, now = new Date) {
|
|
|
11065
11475
|
} catch {
|
|
11066
11476
|
return null;
|
|
11067
11477
|
}
|
|
11068
|
-
const manifestPath =
|
|
11478
|
+
const manifestPath = join24(activeBatch, "manifest.json");
|
|
11069
11479
|
const manifest = readJsonOrNull(manifestPath) ?? { entries: [] };
|
|
11070
11480
|
manifest.entries.push({ from: sourcePath, to: dest, reason, at: now.toISOString() });
|
|
11071
11481
|
try {
|
|
@@ -11108,27 +11518,27 @@ function configHash(value) {
|
|
|
11108
11518
|
var init_hash = () => {};
|
|
11109
11519
|
|
|
11110
11520
|
// src/agents/utils/json-config.ts
|
|
11111
|
-
import { readFileSync as
|
|
11521
|
+
import { readFileSync as readFileSync24, writeFileSync as writeFileSync14, mkdirSync as mkdirSync14, existsSync as existsSync29 } from "fs";
|
|
11112
11522
|
import { dirname as dirname7 } from "path";
|
|
11113
11523
|
function isRunworkManagedKey(key) {
|
|
11114
11524
|
return key === RUNWORK_WORKSPACE_MCP_NAME || key.startsWith(RUNWORK_MCP_PREFIX) || key.startsWith(RUNWORK_MCP_PREFIX_LEGACY);
|
|
11115
11525
|
}
|
|
11116
11526
|
function readJsonConfig(filePath) {
|
|
11117
|
-
if (!
|
|
11527
|
+
if (!existsSync29(filePath))
|
|
11118
11528
|
return {};
|
|
11119
11529
|
try {
|
|
11120
|
-
return JSON.parse(
|
|
11530
|
+
return JSON.parse(readFileSync24(filePath, "utf-8"));
|
|
11121
11531
|
} catch (err) {
|
|
11122
11532
|
console.warn(` [config] ${filePath} is not valid JSON: ${err instanceof Error ? err.message : err}`);
|
|
11123
11533
|
return {};
|
|
11124
11534
|
}
|
|
11125
11535
|
}
|
|
11126
11536
|
function existingContentIsUnparseable(filePath) {
|
|
11127
|
-
if (!
|
|
11537
|
+
if (!existsSync29(filePath))
|
|
11128
11538
|
return { bad: false };
|
|
11129
11539
|
let raw;
|
|
11130
11540
|
try {
|
|
11131
|
-
raw =
|
|
11541
|
+
raw = readFileSync24(filePath, "utf-8");
|
|
11132
11542
|
} catch {
|
|
11133
11543
|
return { bad: false };
|
|
11134
11544
|
}
|
|
@@ -11150,7 +11560,7 @@ function writeJsonConfig(filePath, config) {
|
|
|
11150
11560
|
`);
|
|
11151
11561
|
}
|
|
11152
11562
|
function removeRunworkMcpServers(filePath, topKey) {
|
|
11153
|
-
if (!
|
|
11563
|
+
if (!existsSync29(filePath))
|
|
11154
11564
|
return false;
|
|
11155
11565
|
const config = readJsonConfig(filePath);
|
|
11156
11566
|
const existing = config[topKey] || {};
|
|
@@ -11205,25 +11615,25 @@ var init_json_config = __esm(() => {
|
|
|
11205
11615
|
});
|
|
11206
11616
|
|
|
11207
11617
|
// src/agents/utils/skill-removal.ts
|
|
11208
|
-
import { existsSync as
|
|
11209
|
-
import { join as
|
|
11618
|
+
import { existsSync as existsSync30, readdirSync as readdirSync6 } from "fs";
|
|
11619
|
+
import { join as join25 } from "path";
|
|
11210
11620
|
function removeMatchingSkillDirs(dir, allowed, reason = "skill removed") {
|
|
11211
|
-
if (!allowed.size || !
|
|
11621
|
+
if (!allowed.size || !existsSync30(dir))
|
|
11212
11622
|
return;
|
|
11213
11623
|
for (const entry of readdirSync6(dir)) {
|
|
11214
11624
|
if (!allowed.has(entry))
|
|
11215
11625
|
continue;
|
|
11216
|
-
moveToTrash(
|
|
11626
|
+
moveToTrash(join25(dir, entry), reason);
|
|
11217
11627
|
}
|
|
11218
11628
|
}
|
|
11219
11629
|
function removeMatchingSkillFiles(dir, allowed, suffix, reason = "skill removed") {
|
|
11220
|
-
if (!allowed.size || !
|
|
11630
|
+
if (!allowed.size || !existsSync30(dir))
|
|
11221
11631
|
return;
|
|
11222
11632
|
const names = new Set([...allowed].map((slug) => `${slug}${suffix}`));
|
|
11223
11633
|
for (const entry of readdirSync6(dir)) {
|
|
11224
11634
|
if (!names.has(entry))
|
|
11225
11635
|
continue;
|
|
11226
|
-
moveToTrash(
|
|
11636
|
+
moveToTrash(join25(dir, entry), reason);
|
|
11227
11637
|
}
|
|
11228
11638
|
}
|
|
11229
11639
|
var init_skill_removal = __esm(() => {
|
|
@@ -11231,7 +11641,7 @@ var init_skill_removal = __esm(() => {
|
|
|
11231
11641
|
});
|
|
11232
11642
|
|
|
11233
11643
|
// src/agents/utils/instruction-hint.ts
|
|
11234
|
-
import { existsSync as
|
|
11644
|
+
import { existsSync as existsSync31, readFileSync as readFileSync25, writeFileSync as writeFileSync15, mkdirSync as mkdirSync15 } from "fs";
|
|
11235
11645
|
import { dirname as dirname8 } from "path";
|
|
11236
11646
|
function writeHintToFile(filePath, hint) {
|
|
11237
11647
|
mkdirSync15(dirname8(filePath), { recursive: true });
|
|
@@ -11241,8 +11651,8 @@ ${hint}
|
|
|
11241
11651
|
${END_MARKER}`;
|
|
11242
11652
|
}
|
|
11243
11653
|
let content = "";
|
|
11244
|
-
if (
|
|
11245
|
-
content =
|
|
11654
|
+
if (existsSync31(filePath)) {
|
|
11655
|
+
content = readFileSync25(filePath, "utf-8");
|
|
11246
11656
|
}
|
|
11247
11657
|
const startIdx = content.indexOf(START_MARKER);
|
|
11248
11658
|
const endIdx = content.indexOf(END_MARKER);
|
|
@@ -11264,9 +11674,9 @@ ${END_MARKER}`;
|
|
|
11264
11674
|
writeFileSync15(filePath, content);
|
|
11265
11675
|
}
|
|
11266
11676
|
function removeHintFromFile(filePath) {
|
|
11267
|
-
if (!
|
|
11677
|
+
if (!existsSync31(filePath))
|
|
11268
11678
|
return false;
|
|
11269
|
-
let content =
|
|
11679
|
+
let content = readFileSync25(filePath, "utf-8");
|
|
11270
11680
|
const startIdx = content.indexOf(START_MARKER);
|
|
11271
11681
|
const endIdx = content.indexOf(END_MARKER);
|
|
11272
11682
|
if (startIdx < 0 || endIdx < 0)
|
|
@@ -11284,9 +11694,9 @@ function removeHintFromFile(filePath) {
|
|
|
11284
11694
|
return true;
|
|
11285
11695
|
}
|
|
11286
11696
|
function removeTeamInstructionsFromFile(filePath) {
|
|
11287
|
-
if (!
|
|
11697
|
+
if (!existsSync31(filePath))
|
|
11288
11698
|
return false;
|
|
11289
|
-
let content =
|
|
11699
|
+
let content = readFileSync25(filePath, "utf-8");
|
|
11290
11700
|
const startIdx = content.indexOf(TEAM_START_MARKER);
|
|
11291
11701
|
const endIdx = content.indexOf(TEAM_END_MARKER);
|
|
11292
11702
|
if (startIdx < 0 || endIdx < 0)
|
|
@@ -11306,8 +11716,8 @@ function removeTeamInstructionsFromFile(filePath) {
|
|
|
11306
11716
|
function writeTeamInstructionsToFile(filePath, instructions) {
|
|
11307
11717
|
mkdirSync15(dirname8(filePath), { recursive: true });
|
|
11308
11718
|
let content = "";
|
|
11309
|
-
if (
|
|
11310
|
-
content =
|
|
11719
|
+
if (existsSync31(filePath)) {
|
|
11720
|
+
content = readFileSync25(filePath, "utf-8");
|
|
11311
11721
|
}
|
|
11312
11722
|
const block = `${TEAM_START_MARKER}
|
|
11313
11723
|
${instructions}
|
|
@@ -11756,117 +12166,70 @@ function vlog(...args) {
|
|
|
11756
12166
|
}
|
|
11757
12167
|
var verbose = false;
|
|
11758
12168
|
|
|
11759
|
-
// src/agents/
|
|
11760
|
-
import {
|
|
11761
|
-
|
|
11762
|
-
|
|
11763
|
-
|
|
11764
|
-
|
|
11765
|
-
|
|
11766
|
-
return
|
|
12169
|
+
// src/agents/transcript-sources.ts
|
|
12170
|
+
import { accessSync, constants, statSync as statSync4 } from "fs";
|
|
12171
|
+
function classifyFsErrorCode(code) {
|
|
12172
|
+
if (code === "ENOENT" || code === "ENOTDIR")
|
|
12173
|
+
return "missing-dir";
|
|
12174
|
+
if (code === "EACCES" || code === "EPERM")
|
|
12175
|
+
return "permission-denied";
|
|
12176
|
+
return "error";
|
|
11767
12177
|
}
|
|
11768
|
-
function
|
|
11769
|
-
|
|
12178
|
+
function errorCode(err) {
|
|
12179
|
+
const e = err;
|
|
12180
|
+
return e && typeof e === "object" && typeof e.code === "string" ? e.code : undefined;
|
|
11770
12181
|
}
|
|
11771
|
-
|
|
11772
|
-
|
|
12182
|
+
function probeTranscriptSource(source) {
|
|
12183
|
+
if (source.available && !source.available()) {
|
|
12184
|
+
return { status: "missing-tool", path: source.path, detail: source.tool ?? "unknown tool" };
|
|
12185
|
+
}
|
|
11773
12186
|
try {
|
|
11774
|
-
|
|
11775
|
-
|
|
11776
|
-
|
|
11777
|
-
return false;
|
|
12187
|
+
statSync4(source.path);
|
|
12188
|
+
} catch (err) {
|
|
12189
|
+
return { status: classifyFsErrorCode(errorCode(err)), path: source.path, detail: errorCode(err) };
|
|
11778
12190
|
}
|
|
12191
|
+
try {
|
|
12192
|
+
accessSync(source.path, source.kind === "dir" ? constants.R_OK | constants.X_OK : constants.R_OK);
|
|
12193
|
+
} catch (err) {
|
|
12194
|
+
return { status: classifyFsErrorCode(errorCode(err)), path: source.path, detail: errorCode(err) };
|
|
12195
|
+
}
|
|
12196
|
+
return { status: "ok", path: source.path };
|
|
11779
12197
|
}
|
|
11780
|
-
function
|
|
11781
|
-
const
|
|
11782
|
-
|
|
11783
|
-
|
|
11784
|
-
|
|
12198
|
+
function diagnoseTranscriptRead(agent, thrown) {
|
|
12199
|
+
const probe = summarizeTranscriptSources(agent.transcriptSources?.() ?? []);
|
|
12200
|
+
const base = { agentSlug: agent.slug, sessions: null };
|
|
12201
|
+
if (probe.status !== "ok" && probe.status !== "no-reader") {
|
|
12202
|
+
return {
|
|
12203
|
+
...base,
|
|
12204
|
+
status: probe.status,
|
|
12205
|
+
path: probe.path,
|
|
12206
|
+
...probe.detail ? { detail: probe.detail } : {}
|
|
12207
|
+
};
|
|
12208
|
+
}
|
|
12209
|
+
if (thrown !== undefined) {
|
|
12210
|
+
return { ...base, status: "error", detail: thrown instanceof Error ? thrown.message : String(thrown) };
|
|
12211
|
+
}
|
|
12212
|
+
return probe.status === "ok" ? { ...base, status: "error", path: probe.path, detail: "read returned no result" } : { ...base, status: "no-reader" };
|
|
11785
12213
|
}
|
|
11786
|
-
function
|
|
11787
|
-
|
|
11788
|
-
if (!absolute)
|
|
11789
|
-
return null;
|
|
11790
|
-
return existsSync31(absolute) ? absolute : null;
|
|
11791
|
-
}
|
|
11792
|
-
async function checkMacosBundleId(target) {
|
|
11793
|
-
if (platform3() !== "darwin")
|
|
11794
|
-
return false;
|
|
11795
|
-
const execFileAsync = promisify(execFile);
|
|
11796
|
-
for (const id of toList(target)) {
|
|
11797
|
-
if (!isValidBundleId(id))
|
|
11798
|
-
continue;
|
|
11799
|
-
try {
|
|
11800
|
-
await execFileAsync("sh", ["-c", macosBundleIdProbeScript(id)]);
|
|
11801
|
-
return true;
|
|
11802
|
-
} catch {}
|
|
11803
|
-
}
|
|
11804
|
-
return false;
|
|
11805
|
-
}
|
|
11806
|
-
async function checkWindowsAppxPackage(target) {
|
|
11807
|
-
if (!isWindows())
|
|
11808
|
-
return false;
|
|
11809
|
-
const probes = toList(target).map((pkg) => runPowerShell(appxPackageProbeScript(pkg)));
|
|
11810
|
-
const results = await Promise.all(probes);
|
|
11811
|
-
return results.some(Boolean);
|
|
11812
|
-
}
|
|
11813
|
-
async function checkWindowsStartApp(target) {
|
|
11814
|
-
if (!isWindows())
|
|
11815
|
-
return false;
|
|
11816
|
-
const probes = toList(target).map((pattern) => runPowerShell(startAppProbeScript(pattern)));
|
|
11817
|
-
const results = await Promise.all(probes);
|
|
11818
|
-
return results.some(Boolean);
|
|
11819
|
-
}
|
|
11820
|
-
async function runAgentDetectionDetailed(detection) {
|
|
11821
|
-
switch (detection.method) {
|
|
11822
|
-
case "binary": {
|
|
11823
|
-
const target = resolvePlatformString(detection.target);
|
|
11824
|
-
const resolved = target ? whichBinary(target) : null;
|
|
11825
|
-
return resolved ? { detected: true, via: "binary", resolvedPath: resolved } : NOT_DETECTED;
|
|
11826
|
-
}
|
|
11827
|
-
case "path": {
|
|
11828
|
-
const resolved = checkPath(detection.target);
|
|
11829
|
-
return resolved ? { detected: true, via: "path", resolvedPath: resolved } : NOT_DETECTED;
|
|
11830
|
-
}
|
|
11831
|
-
case "windows-appx":
|
|
11832
|
-
return await checkWindowsAppxPackage(detection.target) ? { detected: true, via: "windows-appx" } : NOT_DETECTED;
|
|
11833
|
-
case "windows-start-app":
|
|
11834
|
-
return await checkWindowsStartApp(detection.target) ? { detected: true, via: "windows-start-app" } : NOT_DETECTED;
|
|
11835
|
-
case "macos-bundle-id":
|
|
11836
|
-
return await checkMacosBundleId(detection.target) ? { detected: true, via: "macos-bundle-id" } : NOT_DETECTED;
|
|
11837
|
-
case "any": {
|
|
11838
|
-
const probes = await Promise.all(detection.target.map((p) => runAgentDetectionDetailed(p)));
|
|
11839
|
-
return probes.find((p) => p.detected) ?? NOT_DETECTED;
|
|
11840
|
-
}
|
|
11841
|
-
case "always":
|
|
11842
|
-
return { detected: true, via: "always" };
|
|
11843
|
-
default:
|
|
11844
|
-
return NOT_DETECTED;
|
|
11845
|
-
}
|
|
11846
|
-
}
|
|
11847
|
-
async function runAgentDetection(detection) {
|
|
11848
|
-
return (await runAgentDetectionDetailed(detection)).detected;
|
|
12214
|
+
function transcriptSourcesReadable(sources) {
|
|
12215
|
+
return summarizeTranscriptSources(sources).status === "ok";
|
|
11849
12216
|
}
|
|
11850
|
-
|
|
11851
|
-
|
|
11852
|
-
|
|
11853
|
-
|
|
11854
|
-
|
|
11855
|
-
|
|
11856
|
-
|
|
12217
|
+
function summarizeTranscriptSources(sources) {
|
|
12218
|
+
if (sources.length === 0)
|
|
12219
|
+
return { status: "no-reader", path: "" };
|
|
12220
|
+
const probes = sources.map(probeTranscriptSource);
|
|
12221
|
+
const rank = ["permission-denied", "missing-tool", "error", "ok", "missing-dir"];
|
|
12222
|
+
for (const status of rank) {
|
|
12223
|
+
const hit = probes.find((p) => p.status === status);
|
|
12224
|
+
if (hit)
|
|
12225
|
+
return hit;
|
|
11857
12226
|
}
|
|
12227
|
+
return probes[0];
|
|
11858
12228
|
}
|
|
11859
|
-
var
|
|
11860
|
-
var init_detection = __esm(() => {
|
|
11861
|
-
init_which();
|
|
11862
|
-
init_registry_data();
|
|
11863
|
-
init_registry();
|
|
11864
|
-
init_detection_probes();
|
|
11865
|
-
NOT_DETECTED = { detected: false };
|
|
11866
|
-
});
|
|
12229
|
+
var init_transcript_sources = () => {};
|
|
11867
12230
|
|
|
11868
12231
|
// src/agents/claude-code.ts
|
|
11869
|
-
import { chmodSync, existsSync as existsSync32, mkdirSync as mkdirSync16, readFileSync as
|
|
12232
|
+
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";
|
|
11870
12233
|
import { join as join26 } from "path";
|
|
11871
12234
|
import { homedir as homedir9 } from "os";
|
|
11872
12235
|
function getPluginJson() {
|
|
@@ -11910,6 +12273,7 @@ var init_claude_code = __esm(() => {
|
|
|
11910
12273
|
init_instruction_hint();
|
|
11911
12274
|
init_session_start_hook();
|
|
11912
12275
|
init_detection();
|
|
12276
|
+
init_transcript_sources();
|
|
11913
12277
|
ClaudeCodeAdapter = class ClaudeCodeAdapter extends RegistryDetectedAdapter {
|
|
11914
12278
|
name = "Claude Code";
|
|
11915
12279
|
slug = "claude-code";
|
|
@@ -12056,7 +12420,7 @@ ${instructions}`;
|
|
|
12056
12420
|
let settings = {};
|
|
12057
12421
|
if (hadFile) {
|
|
12058
12422
|
try {
|
|
12059
|
-
settings = JSON.parse(
|
|
12423
|
+
settings = JSON.parse(readFileSync26(settingsPath, "utf-8"));
|
|
12060
12424
|
} catch {}
|
|
12061
12425
|
}
|
|
12062
12426
|
if (settings.permissions && typeof settings.permissions === "object") {
|
|
@@ -12117,7 +12481,7 @@ ${instructions}`;
|
|
|
12117
12481
|
const settingsPath = join26(homedir9(), ".claude", "settings.json");
|
|
12118
12482
|
if (existsSync32(settingsPath)) {
|
|
12119
12483
|
try {
|
|
12120
|
-
const settings = JSON.parse(
|
|
12484
|
+
const settings = JSON.parse(readFileSync26(settingsPath, "utf-8"));
|
|
12121
12485
|
if (settings.permissions) {
|
|
12122
12486
|
for (const key of ["allow", "deny"]) {
|
|
12123
12487
|
const arr = settings.permissions[key];
|
|
@@ -12207,7 +12571,7 @@ ${instructions}`;
|
|
|
12207
12571
|
const filePath = join26(cwdPath, file);
|
|
12208
12572
|
let stat;
|
|
12209
12573
|
try {
|
|
12210
|
-
stat =
|
|
12574
|
+
stat = statSync5(filePath);
|
|
12211
12575
|
} catch {
|
|
12212
12576
|
continue;
|
|
12213
12577
|
}
|
|
@@ -12215,7 +12579,7 @@ ${instructions}`;
|
|
|
12215
12579
|
continue;
|
|
12216
12580
|
let content;
|
|
12217
12581
|
try {
|
|
12218
|
-
content =
|
|
12582
|
+
content = readFileSync26(filePath, "utf-8");
|
|
12219
12583
|
} catch {
|
|
12220
12584
|
continue;
|
|
12221
12585
|
}
|
|
@@ -12299,9 +12663,15 @@ ${instructions}`;
|
|
|
12299
12663
|
return null;
|
|
12300
12664
|
}
|
|
12301
12665
|
}
|
|
12666
|
+
transcriptRoot() {
|
|
12667
|
+
return join26(homedir9(), ".claude", "projects");
|
|
12668
|
+
}
|
|
12669
|
+
transcriptSources() {
|
|
12670
|
+
return [{ path: this.transcriptRoot(), kind: "dir" }];
|
|
12671
|
+
}
|
|
12302
12672
|
async readSessionDigests(sinceISO) {
|
|
12303
12673
|
try {
|
|
12304
|
-
const projectsDir =
|
|
12674
|
+
const projectsDir = this.transcriptRoot();
|
|
12305
12675
|
if (!existsSync32(projectsDir))
|
|
12306
12676
|
return null;
|
|
12307
12677
|
const sinceMs = sinceISO ? new Date(sinceISO).getTime() : 0;
|
|
@@ -12326,7 +12696,7 @@ ${instructions}`;
|
|
|
12326
12696
|
const filePath = join26(cwdPath, file);
|
|
12327
12697
|
let stat;
|
|
12328
12698
|
try {
|
|
12329
|
-
stat =
|
|
12699
|
+
stat = statSync5(filePath);
|
|
12330
12700
|
} catch {
|
|
12331
12701
|
continue;
|
|
12332
12702
|
}
|
|
@@ -12334,7 +12704,7 @@ ${instructions}`;
|
|
|
12334
12704
|
continue;
|
|
12335
12705
|
let content;
|
|
12336
12706
|
try {
|
|
12337
|
-
content =
|
|
12707
|
+
content = readFileSync26(filePath, "utf-8");
|
|
12338
12708
|
} catch {
|
|
12339
12709
|
continue;
|
|
12340
12710
|
}
|
|
@@ -12350,8 +12720,8 @@ ${instructions}`;
|
|
|
12350
12720
|
}
|
|
12351
12721
|
async listSessions(sinceISO) {
|
|
12352
12722
|
try {
|
|
12353
|
-
const projectsDir =
|
|
12354
|
-
if (!
|
|
12723
|
+
const projectsDir = this.transcriptRoot();
|
|
12724
|
+
if (!transcriptSourcesReadable(this.transcriptSources()))
|
|
12355
12725
|
return null;
|
|
12356
12726
|
const sinceMs = sinceISO ? new Date(sinceISO).getTime() : 0;
|
|
12357
12727
|
let cwdEntries;
|
|
@@ -12375,7 +12745,7 @@ ${instructions}`;
|
|
|
12375
12745
|
const filePath = join26(cwdPath, file);
|
|
12376
12746
|
let stat;
|
|
12377
12747
|
try {
|
|
12378
|
-
stat =
|
|
12748
|
+
stat = statSync5(filePath);
|
|
12379
12749
|
} catch {
|
|
12380
12750
|
continue;
|
|
12381
12751
|
}
|
|
@@ -12390,7 +12760,7 @@ ${instructions}`;
|
|
|
12390
12760
|
const sessionId = file.slice(0, -".jsonl".length);
|
|
12391
12761
|
let endedAt = null;
|
|
12392
12762
|
try {
|
|
12393
|
-
const stamp = JSON.parse(
|
|
12763
|
+
const stamp = JSON.parse(readFileSync26(join26(homedir9(), ".runwork", "sessions", `${sessionId}.ended.json`), "utf-8"));
|
|
12394
12764
|
if (stamp && typeof stamp.endedAt === "string")
|
|
12395
12765
|
endedAt = stamp.endedAt;
|
|
12396
12766
|
} catch {}
|
|
@@ -12402,7 +12772,8 @@ ${instructions}`;
|
|
|
12402
12772
|
startedAt: scanned.firstTimestamp,
|
|
12403
12773
|
lastActivityAt: resolveLastActivity(filePath, stat.mtimeMs),
|
|
12404
12774
|
endedAt,
|
|
12405
|
-
transcriptPath: filePath
|
|
12775
|
+
transcriptPath: filePath,
|
|
12776
|
+
surface: scanned.surface ?? null
|
|
12406
12777
|
});
|
|
12407
12778
|
}
|
|
12408
12779
|
}
|
|
@@ -12413,7 +12784,7 @@ ${instructions}`;
|
|
|
12413
12784
|
}
|
|
12414
12785
|
async readSkillUsage(lastSyncAt) {
|
|
12415
12786
|
try {
|
|
12416
|
-
const projectsDir =
|
|
12787
|
+
const projectsDir = this.transcriptRoot();
|
|
12417
12788
|
if (!existsSync32(projectsDir))
|
|
12418
12789
|
return null;
|
|
12419
12790
|
const sinceMs = lastSyncAt ? new Date(lastSyncAt).getTime() : 0;
|
|
@@ -12448,7 +12819,7 @@ ${instructions}`;
|
|
|
12448
12819
|
const filePath = join26(cwdPath, file);
|
|
12449
12820
|
let fileStat;
|
|
12450
12821
|
try {
|
|
12451
|
-
fileStat =
|
|
12822
|
+
fileStat = statSync5(filePath);
|
|
12452
12823
|
} catch {
|
|
12453
12824
|
continue;
|
|
12454
12825
|
}
|
|
@@ -12456,7 +12827,7 @@ ${instructions}`;
|
|
|
12456
12827
|
continue;
|
|
12457
12828
|
let content;
|
|
12458
12829
|
try {
|
|
12459
|
-
content =
|
|
12830
|
+
content = readFileSync26(filePath, "utf-8");
|
|
12460
12831
|
} catch {
|
|
12461
12832
|
continue;
|
|
12462
12833
|
}
|
|
@@ -12704,7 +13075,7 @@ var init_claude_desktop_plugin_tree = __esm(() => {
|
|
|
12704
13075
|
});
|
|
12705
13076
|
|
|
12706
13077
|
// src/agents/claude-desktop.ts
|
|
12707
|
-
import { existsSync as existsSync34, mkdtempSync as mkdtempSync3, readdirSync as readdirSync8, readFileSync as
|
|
13078
|
+
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";
|
|
12708
13079
|
import { dirname as dirname9, join as join28 } from "path";
|
|
12709
13080
|
import { homedir as homedir10, platform as platform4, tmpdir as tmpdir3 } from "os";
|
|
12710
13081
|
function isRunworkRpmPluginName(name) {
|
|
@@ -12823,7 +13194,7 @@ function findRpmPluginByName(pluginName) {
|
|
|
12823
13194
|
if (!existsSync34(manifestPath))
|
|
12824
13195
|
return null;
|
|
12825
13196
|
try {
|
|
12826
|
-
const manifest = JSON.parse(
|
|
13197
|
+
const manifest = JSON.parse(readFileSync27(manifestPath, "utf-8"));
|
|
12827
13198
|
const entry = manifest.plugins?.find((p) => p.name === pluginName);
|
|
12828
13199
|
if (!entry?.id)
|
|
12829
13200
|
return null;
|
|
@@ -12863,6 +13234,7 @@ function setCoworkPluginEnabled(pluginsDir, enabled) {
|
|
|
12863
13234
|
var PLUGIN_NAME2 = "runwork", PLUGIN_VERSION2 = "1.0.0", PLUGIN_DESCRIPTION = "Skills and tools from your Runwork workspace", PLUGIN_AUTHOR_NAME = "Runwork", ClaudeDesktopAdapter;
|
|
12864
13235
|
var init_claude_desktop = __esm(() => {
|
|
12865
13236
|
init_types();
|
|
13237
|
+
init_transcript_sources();
|
|
12866
13238
|
init_session_digest();
|
|
12867
13239
|
init_json_config();
|
|
12868
13240
|
init_instruction_hint();
|
|
@@ -13003,7 +13375,7 @@ var init_claude_desktop = __esm(() => {
|
|
|
13003
13375
|
let desktopConfig = {};
|
|
13004
13376
|
if (existsSync34(configPath)) {
|
|
13005
13377
|
try {
|
|
13006
|
-
desktopConfig = JSON.parse(
|
|
13378
|
+
desktopConfig = JSON.parse(readFileSync27(configPath, "utf-8"));
|
|
13007
13379
|
} catch {}
|
|
13008
13380
|
}
|
|
13009
13381
|
if (!desktopConfig.preferences)
|
|
@@ -13042,7 +13414,7 @@ var init_claude_desktop = __esm(() => {
|
|
|
13042
13414
|
if (!existsSync34(manifestPath))
|
|
13043
13415
|
continue;
|
|
13044
13416
|
try {
|
|
13045
|
-
const manifest = JSON.parse(
|
|
13417
|
+
const manifest = JSON.parse(readFileSync27(manifestPath, "utf-8"));
|
|
13046
13418
|
if (!Array.isArray(manifest.plugins))
|
|
13047
13419
|
continue;
|
|
13048
13420
|
const ours = manifest.plugins.filter((p) => isRunworkRpmPluginName(p.name));
|
|
@@ -13136,7 +13508,7 @@ var init_claude_desktop = __esm(() => {
|
|
|
13136
13508
|
const filePath = join28(projPath, file);
|
|
13137
13509
|
let stat;
|
|
13138
13510
|
try {
|
|
13139
|
-
stat =
|
|
13511
|
+
stat = statSync6(filePath);
|
|
13140
13512
|
} catch {
|
|
13141
13513
|
continue;
|
|
13142
13514
|
}
|
|
@@ -13144,7 +13516,7 @@ var init_claude_desktop = __esm(() => {
|
|
|
13144
13516
|
continue;
|
|
13145
13517
|
let content;
|
|
13146
13518
|
try {
|
|
13147
|
-
content =
|
|
13519
|
+
content = readFileSync27(filePath, "utf-8");
|
|
13148
13520
|
} catch {
|
|
13149
13521
|
continue;
|
|
13150
13522
|
}
|
|
@@ -13161,10 +13533,13 @@ var init_claude_desktop = __esm(() => {
|
|
|
13161
13533
|
return null;
|
|
13162
13534
|
}
|
|
13163
13535
|
}
|
|
13536
|
+
transcriptSources() {
|
|
13537
|
+
return [{ path: getCoworkBaseDir(), kind: "dir" }];
|
|
13538
|
+
}
|
|
13164
13539
|
async listSessions(sinceISO) {
|
|
13165
13540
|
try {
|
|
13166
13541
|
const baseDir = getCoworkBaseDir();
|
|
13167
|
-
if (!
|
|
13542
|
+
if (!transcriptSourcesReadable(this.transcriptSources()))
|
|
13168
13543
|
return null;
|
|
13169
13544
|
const sinceMs = sinceISO ? new Date(sinceISO).getTime() : 0;
|
|
13170
13545
|
let accounts;
|
|
@@ -13181,7 +13556,7 @@ var init_claude_desktop = __esm(() => {
|
|
|
13181
13556
|
const metaPath = join28(orgPath, entry);
|
|
13182
13557
|
let meta;
|
|
13183
13558
|
try {
|
|
13184
|
-
meta = JSON.parse(
|
|
13559
|
+
meta = JSON.parse(readFileSync27(metaPath, "utf-8"));
|
|
13185
13560
|
} catch {
|
|
13186
13561
|
continue;
|
|
13187
13562
|
}
|
|
@@ -13200,7 +13575,7 @@ var init_claude_desktop = __esm(() => {
|
|
|
13200
13575
|
const filePath = join28(projPath, file);
|
|
13201
13576
|
let stat;
|
|
13202
13577
|
try {
|
|
13203
|
-
stat =
|
|
13578
|
+
stat = statSync6(filePath);
|
|
13204
13579
|
} catch {
|
|
13205
13580
|
continue;
|
|
13206
13581
|
}
|
|
@@ -13217,7 +13592,8 @@ var init_claude_desktop = __esm(() => {
|
|
|
13217
13592
|
title: typeof meta.title === "string" && meta.title ? meta.title : null,
|
|
13218
13593
|
startedAt: typeof meta.createdAt === "number" ? new Date(meta.createdAt).toISOString() : null,
|
|
13219
13594
|
lastActivityAt: new Date(lastActivityMs).toISOString(),
|
|
13220
|
-
transcriptPath
|
|
13595
|
+
transcriptPath,
|
|
13596
|
+
surface: "local-agent"
|
|
13221
13597
|
});
|
|
13222
13598
|
}
|
|
13223
13599
|
}
|
|
@@ -13283,7 +13659,7 @@ var init_claude_desktop = __esm(() => {
|
|
|
13283
13659
|
const scheduledTasksPath = join28(claudeAppDir, "scheduled-tasks.json");
|
|
13284
13660
|
if (existsSync34(scheduledTasksPath)) {
|
|
13285
13661
|
try {
|
|
13286
|
-
const raw =
|
|
13662
|
+
const raw = readFileSync27(scheduledTasksPath, "utf-8");
|
|
13287
13663
|
const parsed = JSON.parse(raw);
|
|
13288
13664
|
const tasks = Array.isArray(parsed) ? parsed : Object.values(parsed);
|
|
13289
13665
|
for (const task of tasks) {
|
|
@@ -13327,7 +13703,7 @@ var init_claude_desktop = __esm(() => {
|
|
|
13327
13703
|
}
|
|
13328
13704
|
const versionPath = join28(claudeAppDir, "claude-code", "sdk-version");
|
|
13329
13705
|
if (existsSync34(versionPath)) {
|
|
13330
|
-
return
|
|
13706
|
+
return readFileSync27(versionPath, "utf-8").trim();
|
|
13331
13707
|
}
|
|
13332
13708
|
return null;
|
|
13333
13709
|
} catch {
|
|
@@ -13341,7 +13717,7 @@ var init_claude_desktop = __esm(() => {
|
|
|
13341
13717
|
continue;
|
|
13342
13718
|
const orgPath = join28(baseDir, orgDir);
|
|
13343
13719
|
try {
|
|
13344
|
-
if (!
|
|
13720
|
+
if (!statSync6(orgPath).isDirectory())
|
|
13345
13721
|
continue;
|
|
13346
13722
|
} catch {
|
|
13347
13723
|
continue;
|
|
@@ -13351,7 +13727,7 @@ var init_claude_desktop = __esm(() => {
|
|
|
13351
13727
|
continue;
|
|
13352
13728
|
const userPath = join28(orgPath, userDir);
|
|
13353
13729
|
try {
|
|
13354
|
-
if (!
|
|
13730
|
+
if (!statSync6(userPath).isDirectory())
|
|
13355
13731
|
continue;
|
|
13356
13732
|
} catch {
|
|
13357
13733
|
continue;
|
|
@@ -13360,7 +13736,7 @@ var init_claude_desktop = __esm(() => {
|
|
|
13360
13736
|
if (!file.endsWith(".json"))
|
|
13361
13737
|
continue;
|
|
13362
13738
|
try {
|
|
13363
|
-
const session = JSON.parse(
|
|
13739
|
+
const session = JSON.parse(readFileSync27(join28(userPath, file), "utf-8"));
|
|
13364
13740
|
onSession(session);
|
|
13365
13741
|
} catch {
|
|
13366
13742
|
continue;
|
|
@@ -13479,6 +13855,7 @@ var init_cursor = __esm(async () => {
|
|
|
13479
13855
|
init_skill_removal();
|
|
13480
13856
|
init_json_config();
|
|
13481
13857
|
init_detection();
|
|
13858
|
+
init_transcript_sources();
|
|
13482
13859
|
await init_sqlite();
|
|
13483
13860
|
CursorAdapter = class CursorAdapter extends RegistryDetectedAdapter {
|
|
13484
13861
|
name = "Cursor";
|
|
@@ -13737,6 +14114,16 @@ ${instructions}`;
|
|
|
13737
14114
|
return null;
|
|
13738
14115
|
}
|
|
13739
14116
|
}
|
|
14117
|
+
transcriptSources() {
|
|
14118
|
+
return [
|
|
14119
|
+
{
|
|
14120
|
+
path: this.globalStorageDbPath(),
|
|
14121
|
+
kind: "file",
|
|
14122
|
+
tool: "sqlite",
|
|
14123
|
+
available: sqliteAvailable
|
|
14124
|
+
}
|
|
14125
|
+
];
|
|
14126
|
+
}
|
|
13740
14127
|
globalStorageDbPath() {
|
|
13741
14128
|
const os2 = platform5();
|
|
13742
14129
|
if (os2 === "darwin") {
|
|
@@ -13764,7 +14151,7 @@ ${instructions}`;
|
|
|
13764
14151
|
async listSessions(sinceISO) {
|
|
13765
14152
|
try {
|
|
13766
14153
|
const dbPath = this.globalStorageDbPath();
|
|
13767
|
-
if (!
|
|
14154
|
+
if (!transcriptSourcesReadable(this.transcriptSources()))
|
|
13768
14155
|
return null;
|
|
13769
14156
|
const rows = queryReadonlySqlite(dbPath, `SELECT json_object('id', json_extract(value,'$.composerId'), 'name', json_extract(value,'$.name'), 'createdAt', json_extract(value,'$.createdAt'), 'lastUpdatedAt', json_extract(value,'$.lastUpdatedAt')) FROM cursorDiskKV WHERE key LIKE 'composerData:%'`);
|
|
13770
14157
|
const sinceMs = sinceISO ? new Date(sinceISO).getTime() : 0;
|
|
@@ -13893,7 +14280,7 @@ ${hint}`;
|
|
|
13893
14280
|
});
|
|
13894
14281
|
|
|
13895
14282
|
// src/agents/codex.ts
|
|
13896
|
-
import { existsSync as existsSync37, mkdirSync as mkdirSync21, readdirSync as readdirSync11, readFileSync as
|
|
14283
|
+
import { existsSync as existsSync37, mkdirSync as mkdirSync21, readdirSync as readdirSync11, readFileSync as readFileSync28, statSync as statSync7, writeFileSync as writeFileSync21 } from "fs";
|
|
13897
14284
|
import { basename as basename3, join as join31 } from "path";
|
|
13898
14285
|
import { homedir as homedir13 } from "os";
|
|
13899
14286
|
import { parse, stringify } from "smol-toml";
|
|
@@ -13903,6 +14290,7 @@ function isRunworkManagedCodexKey(key) {
|
|
|
13903
14290
|
var CodexAdapter, CodexDesktopAdapter;
|
|
13904
14291
|
var init_codex = __esm(async () => {
|
|
13905
14292
|
init_types();
|
|
14293
|
+
init_transcript_sources();
|
|
13906
14294
|
init_session_digest();
|
|
13907
14295
|
init_session_listing();
|
|
13908
14296
|
init_skill_removal();
|
|
@@ -13925,7 +14313,7 @@ var init_codex = __esm(async () => {
|
|
|
13925
14313
|
const configPath = join31(homedir13(), ".codex", "config.toml");
|
|
13926
14314
|
let parsed = {};
|
|
13927
14315
|
if (existsSync37(configPath)) {
|
|
13928
|
-
parsed = parse(
|
|
14316
|
+
parsed = parse(readFileSync28(configPath, "utf-8"));
|
|
13929
14317
|
}
|
|
13930
14318
|
if (!parsed.mcp_servers || typeof parsed.mcp_servers !== "object") {
|
|
13931
14319
|
parsed.mcp_servers = {};
|
|
@@ -13980,7 +14368,7 @@ var init_codex = __esm(async () => {
|
|
|
13980
14368
|
const configPath = scope === "project" ? join31(process.cwd(), ".codex", "config.toml") : join31(homedir13(), ".codex", "config.toml");
|
|
13981
14369
|
let parsed = {};
|
|
13982
14370
|
if (existsSync37(configPath)) {
|
|
13983
|
-
parsed = parse(
|
|
14371
|
+
parsed = parse(readFileSync28(configPath, "utf-8"));
|
|
13984
14372
|
}
|
|
13985
14373
|
if (config.modelPreference) {
|
|
13986
14374
|
parsed.model = config.modelPreference;
|
|
@@ -14039,7 +14427,7 @@ var init_codex = __esm(async () => {
|
|
|
14039
14427
|
const configPath = join31(homedir13(), ".codex", "config.toml");
|
|
14040
14428
|
if (existsSync37(configPath)) {
|
|
14041
14429
|
try {
|
|
14042
|
-
const parsed = parse(
|
|
14430
|
+
const parsed = parse(readFileSync28(configPath, "utf-8"));
|
|
14043
14431
|
if (parsed.mcp_servers && typeof parsed.mcp_servers === "object") {
|
|
14044
14432
|
const mcpServers = parsed.mcp_servers;
|
|
14045
14433
|
for (const key of Object.keys(mcpServers)) {
|
|
@@ -14088,7 +14476,7 @@ var init_codex = __esm(async () => {
|
|
|
14088
14476
|
if (messageCount === 0) {
|
|
14089
14477
|
const historyPath = join31(codexDir, "history.jsonl");
|
|
14090
14478
|
if (existsSync37(historyPath)) {
|
|
14091
|
-
const content =
|
|
14479
|
+
const content = readFileSync28(historyPath, "utf-8").trim();
|
|
14092
14480
|
if (content) {
|
|
14093
14481
|
for (const line of content.split(/[\r\n]+/)) {
|
|
14094
14482
|
try {
|
|
@@ -14121,6 +14509,12 @@ var init_codex = __esm(async () => {
|
|
|
14121
14509
|
return null;
|
|
14122
14510
|
}
|
|
14123
14511
|
}
|
|
14512
|
+
transcriptRoot() {
|
|
14513
|
+
return join31(homedir13(), ".codex", "sessions");
|
|
14514
|
+
}
|
|
14515
|
+
transcriptSources() {
|
|
14516
|
+
return [{ path: this.transcriptRoot(), kind: "dir" }];
|
|
14517
|
+
}
|
|
14124
14518
|
scanRolloutActivity(sinceMs) {
|
|
14125
14519
|
const days = new Set;
|
|
14126
14520
|
const result = {
|
|
@@ -14131,7 +14525,7 @@ var init_codex = __esm(async () => {
|
|
|
14131
14525
|
latestMs: 0,
|
|
14132
14526
|
activeDays: []
|
|
14133
14527
|
};
|
|
14134
|
-
const sessionsDir =
|
|
14528
|
+
const sessionsDir = this.transcriptRoot();
|
|
14135
14529
|
if (!existsSync37(sessionsDir))
|
|
14136
14530
|
return result;
|
|
14137
14531
|
const files = [];
|
|
@@ -14154,7 +14548,7 @@ var init_codex = __esm(async () => {
|
|
|
14154
14548
|
for (const file of files) {
|
|
14155
14549
|
let stat;
|
|
14156
14550
|
try {
|
|
14157
|
-
stat =
|
|
14551
|
+
stat = statSync7(file);
|
|
14158
14552
|
} catch {
|
|
14159
14553
|
continue;
|
|
14160
14554
|
}
|
|
@@ -14162,7 +14556,7 @@ var init_codex = __esm(async () => {
|
|
|
14162
14556
|
continue;
|
|
14163
14557
|
let content;
|
|
14164
14558
|
try {
|
|
14165
|
-
content =
|
|
14559
|
+
content = readFileSync28(file, "utf-8");
|
|
14166
14560
|
} catch {
|
|
14167
14561
|
continue;
|
|
14168
14562
|
}
|
|
@@ -14221,8 +14615,8 @@ var init_codex = __esm(async () => {
|
|
|
14221
14615
|
}
|
|
14222
14616
|
async readSessionDigests(sinceISO) {
|
|
14223
14617
|
try {
|
|
14224
|
-
const sessionsDir =
|
|
14225
|
-
if (!
|
|
14618
|
+
const sessionsDir = this.transcriptRoot();
|
|
14619
|
+
if (!transcriptSourcesReadable(this.transcriptSources()))
|
|
14226
14620
|
return null;
|
|
14227
14621
|
const sinceMs = sinceISO ? new Date(sinceISO).getTime() : 0;
|
|
14228
14622
|
const files = [];
|
|
@@ -14246,7 +14640,7 @@ var init_codex = __esm(async () => {
|
|
|
14246
14640
|
for (const file of files) {
|
|
14247
14641
|
let stat;
|
|
14248
14642
|
try {
|
|
14249
|
-
stat =
|
|
14643
|
+
stat = statSync7(file);
|
|
14250
14644
|
} catch {
|
|
14251
14645
|
continue;
|
|
14252
14646
|
}
|
|
@@ -14254,7 +14648,7 @@ var init_codex = __esm(async () => {
|
|
|
14254
14648
|
continue;
|
|
14255
14649
|
let content;
|
|
14256
14650
|
try {
|
|
14257
|
-
content =
|
|
14651
|
+
content = readFileSync28(file, "utf-8");
|
|
14258
14652
|
} catch {
|
|
14259
14653
|
continue;
|
|
14260
14654
|
}
|
|
@@ -14269,8 +14663,8 @@ var init_codex = __esm(async () => {
|
|
|
14269
14663
|
}
|
|
14270
14664
|
async listSessions(sinceISO) {
|
|
14271
14665
|
try {
|
|
14272
|
-
const sessionsDir =
|
|
14273
|
-
if (!
|
|
14666
|
+
const sessionsDir = this.transcriptRoot();
|
|
14667
|
+
if (!transcriptSourcesReadable(this.transcriptSources()))
|
|
14274
14668
|
return null;
|
|
14275
14669
|
const sinceMs = sinceISO ? new Date(sinceISO).getTime() : 0;
|
|
14276
14670
|
const files = [];
|
|
@@ -14294,7 +14688,7 @@ var init_codex = __esm(async () => {
|
|
|
14294
14688
|
for (const file of files) {
|
|
14295
14689
|
let stat;
|
|
14296
14690
|
try {
|
|
14297
|
-
stat =
|
|
14691
|
+
stat = statSync7(file);
|
|
14298
14692
|
} catch {
|
|
14299
14693
|
continue;
|
|
14300
14694
|
}
|
|
@@ -14313,7 +14707,8 @@ var init_codex = __esm(async () => {
|
|
|
14313
14707
|
title: scanned.title,
|
|
14314
14708
|
startedAt: scanned.firstTimestamp,
|
|
14315
14709
|
lastActivityAt: resolveLastActivity(file, stat.mtimeMs),
|
|
14316
|
-
transcriptPath: file
|
|
14710
|
+
transcriptPath: file,
|
|
14711
|
+
surface: scanned.surface ?? null
|
|
14317
14712
|
});
|
|
14318
14713
|
}
|
|
14319
14714
|
return sessions;
|
|
@@ -14325,7 +14720,7 @@ var init_codex = __esm(async () => {
|
|
|
14325
14720
|
try {
|
|
14326
14721
|
const versionPath = join31(homedir13(), ".codex", "version.json");
|
|
14327
14722
|
if (existsSync37(versionPath)) {
|
|
14328
|
-
const data = JSON.parse(
|
|
14723
|
+
const data = JSON.parse(readFileSync28(versionPath, "utf-8"));
|
|
14329
14724
|
return data.latest_version ?? null;
|
|
14330
14725
|
}
|
|
14331
14726
|
} catch {}
|
|
@@ -14333,7 +14728,7 @@ var init_codex = __esm(async () => {
|
|
|
14333
14728
|
}
|
|
14334
14729
|
async readSkillUsage(lastSyncAt) {
|
|
14335
14730
|
try {
|
|
14336
|
-
const sessionsDir =
|
|
14731
|
+
const sessionsDir = this.transcriptRoot();
|
|
14337
14732
|
if (!existsSync37(sessionsDir))
|
|
14338
14733
|
return null;
|
|
14339
14734
|
const sinceMs = lastSyncAt ? new Date(lastSyncAt).getTime() : 0;
|
|
@@ -14350,7 +14745,7 @@ var init_codex = __esm(async () => {
|
|
|
14350
14745
|
if (entry.endsWith(".jsonl")) {
|
|
14351
14746
|
let fileStat;
|
|
14352
14747
|
try {
|
|
14353
|
-
fileStat =
|
|
14748
|
+
fileStat = statSync7(fullPath);
|
|
14354
14749
|
} catch {
|
|
14355
14750
|
continue;
|
|
14356
14751
|
}
|
|
@@ -14359,7 +14754,7 @@ var init_codex = __esm(async () => {
|
|
|
14359
14754
|
this.parseRolloutForSkills(fullPath, sinceMs, skillCounts);
|
|
14360
14755
|
} else {
|
|
14361
14756
|
try {
|
|
14362
|
-
if (
|
|
14757
|
+
if (statSync7(fullPath).isDirectory())
|
|
14363
14758
|
walkDir2(fullPath);
|
|
14364
14759
|
} catch {
|
|
14365
14760
|
continue;
|
|
@@ -14386,7 +14781,7 @@ var init_codex = __esm(async () => {
|
|
|
14386
14781
|
parseRolloutForSkills(filePath, sinceMs, skillCounts) {
|
|
14387
14782
|
let content;
|
|
14388
14783
|
try {
|
|
14389
|
-
content =
|
|
14784
|
+
content = readFileSync28(filePath, "utf-8");
|
|
14390
14785
|
} catch {
|
|
14391
14786
|
return;
|
|
14392
14787
|
}
|
|
@@ -14439,7 +14834,7 @@ var init_codex = __esm(async () => {
|
|
|
14439
14834
|
let state = {};
|
|
14440
14835
|
if (existsSync37(statePath)) {
|
|
14441
14836
|
try {
|
|
14442
|
-
state = JSON.parse(
|
|
14837
|
+
state = JSON.parse(readFileSync28(statePath, "utf-8"));
|
|
14443
14838
|
} catch {
|
|
14444
14839
|
return "app_running";
|
|
14445
14840
|
}
|
|
@@ -14474,17 +14869,11 @@ var init_codex = __esm(async () => {
|
|
|
14474
14869
|
CodexDesktopAdapter = class CodexDesktopAdapter extends CodexAdapter {
|
|
14475
14870
|
name = "Codex";
|
|
14476
14871
|
slug = "codex-app";
|
|
14477
|
-
async readUsageStats() {
|
|
14478
|
-
return null;
|
|
14479
|
-
}
|
|
14480
|
-
async listSessions() {
|
|
14481
|
-
return null;
|
|
14482
|
-
}
|
|
14483
14872
|
};
|
|
14484
14873
|
});
|
|
14485
14874
|
|
|
14486
14875
|
// src/agents/cline.ts
|
|
14487
|
-
import { existsSync as existsSync38, mkdirSync as mkdirSync22, readFileSync as
|
|
14876
|
+
import { existsSync as existsSync38, mkdirSync as mkdirSync22, readFileSync as readFileSync29, readdirSync as readdirSync12, rmSync as rmSync10, unlinkSync as unlinkSync6, writeFileSync as writeFileSync22 } from "fs";
|
|
14488
14877
|
import { join as join32 } from "path";
|
|
14489
14878
|
import { homedir as homedir14 } from "os";
|
|
14490
14879
|
var ClineAdapter;
|
|
@@ -14545,7 +14934,7 @@ var init_cline = __esm(() => {
|
|
|
14545
14934
|
let state = {};
|
|
14546
14935
|
if (existsSync38(globalStatePath)) {
|
|
14547
14936
|
try {
|
|
14548
|
-
state = JSON.parse(
|
|
14937
|
+
state = JSON.parse(readFileSync29(globalStatePath, "utf-8"));
|
|
14549
14938
|
} catch {}
|
|
14550
14939
|
}
|
|
14551
14940
|
if (config.modelPreference) {
|
|
@@ -14602,7 +14991,7 @@ var init_cline = __esm(() => {
|
|
|
14602
14991
|
});
|
|
14603
14992
|
|
|
14604
14993
|
// src/agents/gemini.ts
|
|
14605
|
-
import { existsSync as existsSync39, mkdirSync as mkdirSync23, readdirSync as readdirSync13, readFileSync as
|
|
14994
|
+
import { existsSync as existsSync39, mkdirSync as mkdirSync23, readdirSync as readdirSync13, readFileSync as readFileSync30, statSync as statSync8, writeFileSync as writeFileSync23 } from "fs";
|
|
14606
14995
|
import { basename as basename4, join as join33 } from "path";
|
|
14607
14996
|
import { homedir as homedir15 } from "os";
|
|
14608
14997
|
var GeminiAdapter;
|
|
@@ -14612,6 +15001,7 @@ var init_gemini = __esm(() => {
|
|
|
14612
15001
|
init_skill_removal();
|
|
14613
15002
|
init_trash();
|
|
14614
15003
|
init_types();
|
|
15004
|
+
init_transcript_sources();
|
|
14615
15005
|
init_instruction_hint();
|
|
14616
15006
|
init_json_config();
|
|
14617
15007
|
init_detection();
|
|
@@ -14661,7 +15051,7 @@ var init_gemini = __esm(() => {
|
|
|
14661
15051
|
let settings = {};
|
|
14662
15052
|
if (existsSync39(settingsPath)) {
|
|
14663
15053
|
try {
|
|
14664
|
-
settings = JSON.parse(
|
|
15054
|
+
settings = JSON.parse(readFileSync30(settingsPath, "utf-8"));
|
|
14665
15055
|
} catch {}
|
|
14666
15056
|
}
|
|
14667
15057
|
if (config.modelPreference) {
|
|
@@ -14684,7 +15074,7 @@ var init_gemini = __esm(() => {
|
|
|
14684
15074
|
}
|
|
14685
15075
|
async readUsageStats(lastSyncAt) {
|
|
14686
15076
|
try {
|
|
14687
|
-
const tmpDir =
|
|
15077
|
+
const tmpDir = this.transcriptRoot();
|
|
14688
15078
|
if (!existsSync39(tmpDir))
|
|
14689
15079
|
return null;
|
|
14690
15080
|
const sinceMs = lastSyncAt ? new Date(lastSyncAt).getTime() : 0;
|
|
@@ -14714,7 +15104,7 @@ var init_gemini = __esm(() => {
|
|
|
14714
15104
|
const filePath = join33(chatsDir, file.name);
|
|
14715
15105
|
let stat;
|
|
14716
15106
|
try {
|
|
14717
|
-
stat =
|
|
15107
|
+
stat = statSync8(filePath);
|
|
14718
15108
|
} catch {
|
|
14719
15109
|
continue;
|
|
14720
15110
|
}
|
|
@@ -14722,7 +15112,7 @@ var init_gemini = __esm(() => {
|
|
|
14722
15112
|
continue;
|
|
14723
15113
|
let session;
|
|
14724
15114
|
try {
|
|
14725
|
-
session = JSON.parse(
|
|
15115
|
+
session = JSON.parse(readFileSync30(filePath, "utf-8"));
|
|
14726
15116
|
} catch {
|
|
14727
15117
|
continue;
|
|
14728
15118
|
}
|
|
@@ -14762,8 +15152,14 @@ var init_gemini = __esm(() => {
|
|
|
14762
15152
|
return null;
|
|
14763
15153
|
}
|
|
14764
15154
|
}
|
|
15155
|
+
transcriptRoot() {
|
|
15156
|
+
return join33(homedir15(), ".gemini", "tmp");
|
|
15157
|
+
}
|
|
15158
|
+
transcriptSources() {
|
|
15159
|
+
return [{ path: this.transcriptRoot(), kind: "dir" }];
|
|
15160
|
+
}
|
|
14765
15161
|
*chatFiles(sinceMs) {
|
|
14766
|
-
const tmpDir =
|
|
15162
|
+
const tmpDir = this.transcriptRoot();
|
|
14767
15163
|
if (!existsSync39(tmpDir))
|
|
14768
15164
|
return;
|
|
14769
15165
|
let projects;
|
|
@@ -14788,7 +15184,7 @@ var init_gemini = __esm(() => {
|
|
|
14788
15184
|
const filePath = join33(chatsDir, file);
|
|
14789
15185
|
let stat;
|
|
14790
15186
|
try {
|
|
14791
|
-
stat =
|
|
15187
|
+
stat = statSync8(filePath);
|
|
14792
15188
|
} catch {
|
|
14793
15189
|
continue;
|
|
14794
15190
|
}
|
|
@@ -14800,12 +15196,14 @@ var init_gemini = __esm(() => {
|
|
|
14800
15196
|
}
|
|
14801
15197
|
async listSessions(sinceISO) {
|
|
14802
15198
|
try {
|
|
15199
|
+
if (!transcriptSourcesReadable(this.transcriptSources()))
|
|
15200
|
+
return null;
|
|
14803
15201
|
const sinceMs = sinceISO ? new Date(sinceISO).getTime() : 0;
|
|
14804
15202
|
const sessions = [];
|
|
14805
15203
|
for (const { filePath, project, mtimeMs } of this.chatFiles(sinceMs)) {
|
|
14806
15204
|
let session;
|
|
14807
15205
|
try {
|
|
14808
|
-
session = JSON.parse(
|
|
15206
|
+
session = JSON.parse(readFileSync30(filePath, "utf-8"));
|
|
14809
15207
|
} catch {
|
|
14810
15208
|
continue;
|
|
14811
15209
|
}
|
|
@@ -14839,12 +15237,14 @@ var init_gemini = __esm(() => {
|
|
|
14839
15237
|
}
|
|
14840
15238
|
async readSessionDigests(sinceISO) {
|
|
14841
15239
|
try {
|
|
15240
|
+
if (!transcriptSourcesReadable(this.transcriptSources()))
|
|
15241
|
+
return null;
|
|
14842
15242
|
const sinceMs = sinceISO ? new Date(sinceISO).getTime() : 0;
|
|
14843
15243
|
const digests = [];
|
|
14844
15244
|
for (const { filePath, project } of this.chatFiles(sinceMs)) {
|
|
14845
15245
|
let content;
|
|
14846
15246
|
try {
|
|
14847
|
-
content =
|
|
15247
|
+
content = readFileSync30(filePath, "utf-8");
|
|
14848
15248
|
} catch {
|
|
14849
15249
|
continue;
|
|
14850
15250
|
}
|
|
@@ -14884,6 +15284,7 @@ var init_generic_adapter = __esm(() => {
|
|
|
14884
15284
|
init_json_config();
|
|
14885
15285
|
init_instruction_hint();
|
|
14886
15286
|
init_registry();
|
|
15287
|
+
init_detection_probes();
|
|
14887
15288
|
init_detection();
|
|
14888
15289
|
init_trash();
|
|
14889
15290
|
GenericAgentAdapter = class GenericAgentAdapter extends RegistryDetectedAdapter {
|
|
@@ -14908,7 +15309,13 @@ var init_generic_adapter = __esm(() => {
|
|
|
14908
15309
|
async writeMcpServers(servers, _scope) {
|
|
14909
15310
|
if (!this.def.mcpConfigPath)
|
|
14910
15311
|
return;
|
|
14911
|
-
const
|
|
15312
|
+
const resolved = resolvePlatformString(this.def.mcpConfigPath) || "";
|
|
15313
|
+
const expanded = expandWindowsPathTemplate(resolved, {
|
|
15314
|
+
"%APPDATA%": process.env.APPDATA,
|
|
15315
|
+
"%LOCALAPPDATA%": process.env.LOCALAPPDATA,
|
|
15316
|
+
"%ProgramFiles%": process.env.ProgramFiles
|
|
15317
|
+
});
|
|
15318
|
+
const filePath = expanded.needsHomeJoin ? join34(homedir16(), expanded.path) : expanded.path;
|
|
14912
15319
|
if (!filePath)
|
|
14913
15320
|
return;
|
|
14914
15321
|
const entries = {};
|
|
@@ -15061,6 +15468,43 @@ var init_detect = __esm(async () => {
|
|
|
15061
15468
|
ALL_ADAPTERS = buildAllAdapters();
|
|
15062
15469
|
});
|
|
15063
15470
|
|
|
15471
|
+
// ../../shared/types/local-conversations.ts
|
|
15472
|
+
function describeScanOutcome(outcome) {
|
|
15473
|
+
switch (outcome.status) {
|
|
15474
|
+
case "ok":
|
|
15475
|
+
case "no-reader":
|
|
15476
|
+
return null;
|
|
15477
|
+
case "missing-dir":
|
|
15478
|
+
return `no conversation history found${outcome.path ? ` at ${outcome.path}` : ""}`;
|
|
15479
|
+
case "permission-denied":
|
|
15480
|
+
return `access denied${outcome.path ? ` to ${outcome.path}` : ""}`;
|
|
15481
|
+
case "missing-tool":
|
|
15482
|
+
return `needs ${outcome.detail ?? "a tool that is not installed"}`;
|
|
15483
|
+
case "error":
|
|
15484
|
+
return `could not be read${outcome.detail ? `: ${outcome.detail}` : ""}`;
|
|
15485
|
+
}
|
|
15486
|
+
}
|
|
15487
|
+
function scanOutcomeNeedsAttention(outcome) {
|
|
15488
|
+
return outcome.status === "permission-denied" || outcome.status === "error";
|
|
15489
|
+
}
|
|
15490
|
+
function describeStoreOutcome(outcome) {
|
|
15491
|
+
if (outcome.status === "orphaned") {
|
|
15492
|
+
return `not read: nothing on this machine was detected as ${outcome.members.join(" or ")}`;
|
|
15493
|
+
}
|
|
15494
|
+
if (outcome.status === "ok")
|
|
15495
|
+
return null;
|
|
15496
|
+
return describeScanOutcome({
|
|
15497
|
+
agentSlug: outcome.storeId,
|
|
15498
|
+
status: outcome.status,
|
|
15499
|
+
sessions: outcome.sessions,
|
|
15500
|
+
path: outcome.path,
|
|
15501
|
+
...outcome.detail ? { detail: outcome.detail } : {}
|
|
15502
|
+
});
|
|
15503
|
+
}
|
|
15504
|
+
function storeOutcomeNeedsAttention(outcome) {
|
|
15505
|
+
return outcome.status === "orphaned" || outcome.status === "permission-denied" || outcome.status === "error";
|
|
15506
|
+
}
|
|
15507
|
+
|
|
15064
15508
|
// src/utils/insight-id.ts
|
|
15065
15509
|
import { createHash as createHash3 } from "node:crypto";
|
|
15066
15510
|
function computeInsightId(userSeed, localKey) {
|
|
@@ -15072,7 +15516,7 @@ function insightLocalKey(teaches, slug) {
|
|
|
15072
15516
|
var init_insight_id = () => {};
|
|
15073
15517
|
|
|
15074
15518
|
// src/reflect/insight-store.ts
|
|
15075
|
-
import { existsSync as existsSync41, readFileSync as
|
|
15519
|
+
import { existsSync as existsSync41, readFileSync as readFileSync31 } from "fs";
|
|
15076
15520
|
import { join as join35 } from "path";
|
|
15077
15521
|
import { homedir as homedir17 } from "os";
|
|
15078
15522
|
function storePath2() {
|
|
@@ -15083,7 +15527,7 @@ function readAll() {
|
|
|
15083
15527
|
if (!existsSync41(path2))
|
|
15084
15528
|
return {};
|
|
15085
15529
|
try {
|
|
15086
|
-
const parsed = JSON.parse(
|
|
15530
|
+
const parsed = JSON.parse(readFileSync31(path2, "utf-8"));
|
|
15087
15531
|
return parsed && typeof parsed === "object" ? parsed : {};
|
|
15088
15532
|
} catch {
|
|
15089
15533
|
return {};
|
|
@@ -15128,7 +15572,7 @@ var init_insight_store = __esm(() => {
|
|
|
15128
15572
|
var DEFAULT_DAILY_TIER2_BUDGET = 3;
|
|
15129
15573
|
|
|
15130
15574
|
// src/reflect/cadence.ts
|
|
15131
|
-
import { existsSync as existsSync42, readFileSync as
|
|
15575
|
+
import { existsSync as existsSync42, readFileSync as readFileSync32 } from "fs";
|
|
15132
15576
|
import { join as join36 } from "path";
|
|
15133
15577
|
import { homedir as homedir18 } from "os";
|
|
15134
15578
|
function remainingDailyAnalyses(state, now = new Date, budget = DEFAULT_DAILY_TIER2_BUDGET) {
|
|
@@ -15150,7 +15594,7 @@ function loadCadenceState() {
|
|
|
15150
15594
|
const p = statePath();
|
|
15151
15595
|
if (!existsSync42(p))
|
|
15152
15596
|
return { ...DEFAULT_STATE };
|
|
15153
|
-
const parsed = JSON.parse(
|
|
15597
|
+
const parsed = JSON.parse(readFileSync32(p, "utf-8"));
|
|
15154
15598
|
const state = { ...DEFAULT_STATE, ...parsed && typeof parsed === "object" ? parsed : {} };
|
|
15155
15599
|
if (state.enabled === false && state.disabledByUser !== true) {
|
|
15156
15600
|
state.enabled = true;
|
|
@@ -15211,7 +15655,7 @@ __export(exports_run_log, {
|
|
|
15211
15655
|
RUN_LOG_CAP: () => RUN_LOG_CAP,
|
|
15212
15656
|
ANALYST_ERROR_MAX_CHARS: () => ANALYST_ERROR_MAX_CHARS
|
|
15213
15657
|
});
|
|
15214
|
-
import { existsSync as existsSync43, mkdirSync as mkdirSync25, readFileSync as
|
|
15658
|
+
import { existsSync as existsSync43, mkdirSync as mkdirSync25, readFileSync as readFileSync33, readdirSync as readdirSync15, statSync as statSync9, unlinkSync as unlinkSync7, writeFileSync as writeFileSync25 } from "fs";
|
|
15215
15659
|
import { dirname as dirname10, join as join37 } from "path";
|
|
15216
15660
|
import { homedir as homedir19 } from "os";
|
|
15217
15661
|
function runLogPath() {
|
|
@@ -15222,7 +15666,7 @@ function loadRunLog() {
|
|
|
15222
15666
|
const p = runLogPath();
|
|
15223
15667
|
if (!existsSync43(p))
|
|
15224
15668
|
return [];
|
|
15225
|
-
const parsed = JSON.parse(
|
|
15669
|
+
const parsed = JSON.parse(readFileSync33(p, "utf-8"));
|
|
15226
15670
|
return Array.isArray(parsed) ? parsed : [];
|
|
15227
15671
|
} catch {
|
|
15228
15672
|
return [];
|
|
@@ -15355,7 +15799,7 @@ function acquireRunLock(nowMs = Date.now()) {
|
|
|
15355
15799
|
return true;
|
|
15356
15800
|
} catch {
|
|
15357
15801
|
try {
|
|
15358
|
-
if (nowMs -
|
|
15802
|
+
if (nowMs - statSync9(p).mtimeMs < RUN_STALE_MS)
|
|
15359
15803
|
return false;
|
|
15360
15804
|
unlinkSync7(p);
|
|
15361
15805
|
} catch {
|
|
@@ -15390,7 +15834,7 @@ var init_run_log = __esm(() => {
|
|
|
15390
15834
|
});
|
|
15391
15835
|
|
|
15392
15836
|
// src/reflect/conversation-queue.ts
|
|
15393
|
-
import { existsSync as existsSync44, readFileSync as
|
|
15837
|
+
import { existsSync as existsSync44, readFileSync as readFileSync34 } from "fs";
|
|
15394
15838
|
import { join as join38 } from "path";
|
|
15395
15839
|
import { homedir as homedir20 } from "os";
|
|
15396
15840
|
function conversationKey(c) {
|
|
@@ -15404,7 +15848,7 @@ function loadQueueState() {
|
|
|
15404
15848
|
const p = queuePath();
|
|
15405
15849
|
if (!existsSync44(p))
|
|
15406
15850
|
return { entries: {} };
|
|
15407
|
-
const parsed = JSON.parse(
|
|
15851
|
+
const parsed = JSON.parse(readFileSync34(p, "utf-8"));
|
|
15408
15852
|
if (parsed && typeof parsed === "object" && parsed.entries && typeof parsed.entries === "object") {
|
|
15409
15853
|
return { entries: parsed.entries };
|
|
15410
15854
|
}
|
|
@@ -15612,7 +16056,7 @@ function parseHandoffResult(kind, text2) {
|
|
|
15612
16056
|
}
|
|
15613
16057
|
|
|
15614
16058
|
// src/reflect/model-repair.ts
|
|
15615
|
-
import { existsSync as existsSync45, readFileSync as
|
|
16059
|
+
import { existsSync as existsSync45, readFileSync as readFileSync35, writeFileSync as writeFileSync26 } from "fs";
|
|
15616
16060
|
import { homedir as homedir21 } from "os";
|
|
15617
16061
|
import { join as join39 } from "path";
|
|
15618
16062
|
function codexConfigPath() {
|
|
@@ -15649,7 +16093,7 @@ function repairCodexModelPin() {
|
|
|
15649
16093
|
const path2 = codexConfigPath();
|
|
15650
16094
|
if (!existsSync45(path2))
|
|
15651
16095
|
return null;
|
|
15652
|
-
const current =
|
|
16096
|
+
const current = readFileSync35(path2, "utf-8");
|
|
15653
16097
|
const stripped = stripModelPin(current);
|
|
15654
16098
|
if (!stripped)
|
|
15655
16099
|
return null;
|
|
@@ -16043,6 +16487,7 @@ var init_reflect = __esm(async () => {
|
|
|
16043
16487
|
init_store();
|
|
16044
16488
|
init_client();
|
|
16045
16489
|
init_resolve();
|
|
16490
|
+
init_transcript_sources();
|
|
16046
16491
|
init_session_digest();
|
|
16047
16492
|
init_insight_id();
|
|
16048
16493
|
init_insight_store();
|
|
@@ -16107,13 +16552,13 @@ var init_reflect = __esm(async () => {
|
|
|
16107
16552
|
const seen = new Set;
|
|
16108
16553
|
for (const adapter2 of adapters) {
|
|
16109
16554
|
if (!adapter2.readSessionDigests) {
|
|
16110
|
-
perAgent.push({
|
|
16555
|
+
perAgent.push({ agentSlug: adapter2.slug, status: "no-reader", sessions: null });
|
|
16111
16556
|
continue;
|
|
16112
16557
|
}
|
|
16113
16558
|
try {
|
|
16114
16559
|
const sessions = await adapter2.readSessionDigests(sinceISO);
|
|
16115
16560
|
if (sessions === null) {
|
|
16116
|
-
perAgent.push(
|
|
16561
|
+
perAgent.push(diagnoseTranscriptRead(adapter2));
|
|
16117
16562
|
continue;
|
|
16118
16563
|
}
|
|
16119
16564
|
let added = 0;
|
|
@@ -16125,20 +16570,26 @@ var init_reflect = __esm(async () => {
|
|
|
16125
16570
|
digests.push(s);
|
|
16126
16571
|
added++;
|
|
16127
16572
|
}
|
|
16128
|
-
perAgent.push({
|
|
16129
|
-
} catch {
|
|
16130
|
-
perAgent.push(
|
|
16573
|
+
perAgent.push({ agentSlug: adapter2.slug, status: "ok", sessions: added });
|
|
16574
|
+
} catch (err) {
|
|
16575
|
+
perAgent.push(diagnoseTranscriptRead(adapter2, err));
|
|
16131
16576
|
}
|
|
16132
16577
|
}
|
|
16133
16578
|
if (!json) {
|
|
16134
16579
|
console.error(bold(`
|
|
16135
16580
|
Reflection over the last ${days} days`));
|
|
16136
|
-
for (const a of perAgent)
|
|
16137
|
-
|
|
16581
|
+
for (const a of perAgent) {
|
|
16582
|
+
const reason = describeScanOutcome(a);
|
|
16583
|
+
if (reason === null) {
|
|
16584
|
+
console.error(` ${cyan(a.agentSlug)}: ${a.status === "no-reader" ? gray("no transcript reader") : `${a.sessions} session(s)`}`);
|
|
16585
|
+
} else {
|
|
16586
|
+
console.error(` ${cyan(a.agentSlug)}: ${scanOutcomeNeedsAttention(a) ? red(reason) : gray(reason)}`);
|
|
16587
|
+
}
|
|
16588
|
+
}
|
|
16138
16589
|
}
|
|
16139
16590
|
if (digests.length === 0) {
|
|
16140
16591
|
if (json) {
|
|
16141
|
-
jsonOut({ insights: [], reason: "no-sessions" });
|
|
16592
|
+
jsonOut({ insights: [], reason: "no-sessions", perAgent });
|
|
16142
16593
|
return;
|
|
16143
16594
|
}
|
|
16144
16595
|
console.error(yellow(`
|
|
@@ -16465,7 +16916,214 @@ ${all.length} insight(s) from your recent work:
|
|
|
16465
16916
|
});
|
|
16466
16917
|
});
|
|
16467
16918
|
|
|
16919
|
+
// src/agents/transcript-stores.ts
|
|
16920
|
+
function joiner(input) {
|
|
16921
|
+
const sep4 = input.sep ?? (input.platform === "win32" ? "\\" : "/");
|
|
16922
|
+
return (...parts) => parts.join(sep4);
|
|
16923
|
+
}
|
|
16924
|
+
function home(input) {
|
|
16925
|
+
return input.homeDir.replace(/[/\\]+$/, "");
|
|
16926
|
+
}
|
|
16927
|
+
function appDataRoot(input) {
|
|
16928
|
+
const join41 = joiner(input);
|
|
16929
|
+
if (input.platform === "darwin")
|
|
16930
|
+
return join41(home(input), "Library", "Application Support");
|
|
16931
|
+
if (input.platform === "win32") {
|
|
16932
|
+
return input.appData ?? join41(home(input), "AppData", "Roaming");
|
|
16933
|
+
}
|
|
16934
|
+
return join41(home(input), ".config");
|
|
16935
|
+
}
|
|
16936
|
+
function localAppDataRoot(input) {
|
|
16937
|
+
const join41 = joiner(input);
|
|
16938
|
+
return input.localAppData ?? join41(home(input), "AppData", "Local");
|
|
16939
|
+
}
|
|
16940
|
+
function codexOriginator(head) {
|
|
16941
|
+
for (const line of head.split(`
|
|
16942
|
+
`)) {
|
|
16943
|
+
if (!line.trim())
|
|
16944
|
+
continue;
|
|
16945
|
+
let o;
|
|
16946
|
+
try {
|
|
16947
|
+
o = JSON.parse(line);
|
|
16948
|
+
} catch {
|
|
16949
|
+
continue;
|
|
16950
|
+
}
|
|
16951
|
+
if (o.type !== "session_meta")
|
|
16952
|
+
continue;
|
|
16953
|
+
const payload = o.payload;
|
|
16954
|
+
return typeof payload?.originator === "string" ? payload.originator : null;
|
|
16955
|
+
}
|
|
16956
|
+
return null;
|
|
16957
|
+
}
|
|
16958
|
+
function claudeEntrypoint(head) {
|
|
16959
|
+
for (const line of head.split(`
|
|
16960
|
+
`)) {
|
|
16961
|
+
if (!line.trim())
|
|
16962
|
+
continue;
|
|
16963
|
+
let o;
|
|
16964
|
+
try {
|
|
16965
|
+
o = JSON.parse(line);
|
|
16966
|
+
} catch {
|
|
16967
|
+
continue;
|
|
16968
|
+
}
|
|
16969
|
+
if (typeof o.entrypoint === "string")
|
|
16970
|
+
return o.entrypoint;
|
|
16971
|
+
}
|
|
16972
|
+
return null;
|
|
16973
|
+
}
|
|
16974
|
+
function attributeCodexOriginator(marker) {
|
|
16975
|
+
switch (marker) {
|
|
16976
|
+
case "Codex Desktop":
|
|
16977
|
+
case "codex_work_desktop":
|
|
16978
|
+
return "codex-app";
|
|
16979
|
+
case "codex-tui":
|
|
16980
|
+
case "codex_exec":
|
|
16981
|
+
case "Claude Code":
|
|
16982
|
+
return "codex";
|
|
16983
|
+
default:
|
|
16984
|
+
return null;
|
|
16985
|
+
}
|
|
16986
|
+
}
|
|
16987
|
+
function attributeClaudeEntrypoint(marker) {
|
|
16988
|
+
switch (marker) {
|
|
16989
|
+
case "cli":
|
|
16990
|
+
case "sdk-cli":
|
|
16991
|
+
return "claude-code";
|
|
16992
|
+
case "claude-desktop":
|
|
16993
|
+
case "local-agent":
|
|
16994
|
+
return "claude-desktop";
|
|
16995
|
+
default:
|
|
16996
|
+
return null;
|
|
16997
|
+
}
|
|
16998
|
+
}
|
|
16999
|
+
function resolveTranscriptStores(input) {
|
|
17000
|
+
const resolved = [];
|
|
17001
|
+
for (const def of TRANSCRIPT_STORES) {
|
|
17002
|
+
const path2 = def.path(input);
|
|
17003
|
+
if (path2 === null)
|
|
17004
|
+
continue;
|
|
17005
|
+
resolved.push({ def, path: path2, altPaths: def.altPaths?.(input) ?? [] });
|
|
17006
|
+
}
|
|
17007
|
+
return resolved;
|
|
17008
|
+
}
|
|
17009
|
+
function familyMembers(family, table = TRANSCRIPT_STORES) {
|
|
17010
|
+
const slugs = new Set;
|
|
17011
|
+
for (const store of table) {
|
|
17012
|
+
if (store.family !== family)
|
|
17013
|
+
continue;
|
|
17014
|
+
for (const member of store.members)
|
|
17015
|
+
slugs.add(member);
|
|
17016
|
+
}
|
|
17017
|
+
return [...slugs];
|
|
17018
|
+
}
|
|
17019
|
+
function isStoreUnlocked(def, detectedSlugs, table = TRANSCRIPT_STORES) {
|
|
17020
|
+
const detected = detectedSlugs instanceof Set ? detectedSlugs : new Set(detectedSlugs);
|
|
17021
|
+
return familyMembers(def.family, table).some((m) => detected.has(m));
|
|
17022
|
+
}
|
|
17023
|
+
function telemetryOwner(def, detectedSlugs) {
|
|
17024
|
+
const detected = detectedSlugs instanceof Set ? detectedSlugs : new Set(detectedSlugs);
|
|
17025
|
+
if (detected.has(def.readerSlug))
|
|
17026
|
+
return def.readerSlug;
|
|
17027
|
+
return def.members.find((m) => detected.has(m)) ?? null;
|
|
17028
|
+
}
|
|
17029
|
+
function suppressedStoreReaders(detectedSlugs, sharesImplementation, table = TRANSCRIPT_STORES) {
|
|
17030
|
+
const detected = detectedSlugs instanceof Set ? detectedSlugs : new Set(detectedSlugs);
|
|
17031
|
+
const suppressed = new Set;
|
|
17032
|
+
for (const store of table) {
|
|
17033
|
+
const owner = telemetryOwner(store, detected);
|
|
17034
|
+
if (owner === null)
|
|
17035
|
+
continue;
|
|
17036
|
+
for (const member of store.members) {
|
|
17037
|
+
if (member === owner || !detected.has(member))
|
|
17038
|
+
continue;
|
|
17039
|
+
if (sharesImplementation(member, owner))
|
|
17040
|
+
suppressed.add(member);
|
|
17041
|
+
}
|
|
17042
|
+
}
|
|
17043
|
+
return suppressed;
|
|
17044
|
+
}
|
|
17045
|
+
function attributeTranscript(def, head) {
|
|
17046
|
+
if (head === null || !def.marker) {
|
|
17047
|
+
return { agentSlug: def.defaultMember, marker: null, recognised: false };
|
|
17048
|
+
}
|
|
17049
|
+
const marker = def.marker(head);
|
|
17050
|
+
if (marker === null)
|
|
17051
|
+
return { agentSlug: def.defaultMember, marker: null, recognised: false };
|
|
17052
|
+
const slug = def.attribute?.(marker) ?? null;
|
|
17053
|
+
return slug === null ? { agentSlug: def.defaultMember, marker, recognised: false } : { agentSlug: slug, marker, recognised: true };
|
|
17054
|
+
}
|
|
17055
|
+
var CODEX_HEAD, CLAUDE_HEAD, TRANSCRIPT_STORES;
|
|
17056
|
+
var init_transcript_stores = __esm(() => {
|
|
17057
|
+
CODEX_HEAD = 256 * 1024;
|
|
17058
|
+
CLAUDE_HEAD = 64 * 1024;
|
|
17059
|
+
TRANSCRIPT_STORES = [
|
|
17060
|
+
{
|
|
17061
|
+
id: "codex/sessions",
|
|
17062
|
+
readerSlug: "codex",
|
|
17063
|
+
family: "codex",
|
|
17064
|
+
members: ["codex", "codex-app"],
|
|
17065
|
+
defaultMember: "codex",
|
|
17066
|
+
kind: "dir",
|
|
17067
|
+
path: (i) => joiner(i)(home(i), ".codex", "sessions"),
|
|
17068
|
+
matches: (n) => n.startsWith("rollout-") && n.endsWith(".jsonl"),
|
|
17069
|
+
headBytes: CODEX_HEAD,
|
|
17070
|
+
marker: codexOriginator,
|
|
17071
|
+
attribute: attributeCodexOriginator
|
|
17072
|
+
},
|
|
17073
|
+
{
|
|
17074
|
+
id: "claude/projects",
|
|
17075
|
+
readerSlug: "claude-code",
|
|
17076
|
+
family: "claude",
|
|
17077
|
+
members: ["claude-code", "claude-desktop"],
|
|
17078
|
+
defaultMember: "claude-code",
|
|
17079
|
+
kind: "dir",
|
|
17080
|
+
path: (i) => joiner(i)(home(i), ".claude", "projects"),
|
|
17081
|
+
matches: (n) => n.endsWith(".jsonl"),
|
|
17082
|
+
subordinate: (rel) => rel.split(/[\\/]/).length > 2,
|
|
17083
|
+
headBytes: CLAUDE_HEAD,
|
|
17084
|
+
marker: claudeEntrypoint,
|
|
17085
|
+
attribute: attributeClaudeEntrypoint
|
|
17086
|
+
},
|
|
17087
|
+
{
|
|
17088
|
+
id: "claude/cowork",
|
|
17089
|
+
readerSlug: "claude-desktop",
|
|
17090
|
+
family: "claude",
|
|
17091
|
+
members: ["claude-desktop"],
|
|
17092
|
+
defaultMember: "claude-desktop",
|
|
17093
|
+
kind: "dir",
|
|
17094
|
+
path: (i) => joiner(i)(appDataRoot(i), "Claude", "local-agent-mode-sessions"),
|
|
17095
|
+
altPaths: (i) => i.platform === "win32" ? [joiner(i)(localAppDataRoot(i), "Packages", "Claude_pzs8sxrjxfjjc", "LocalCache", "Roaming", "Claude", "local-agent-mode-sessions")] : [],
|
|
17096
|
+
matches: (n) => n.endsWith(".jsonl"),
|
|
17097
|
+
headBytes: CLAUDE_HEAD,
|
|
17098
|
+
marker: claudeEntrypoint,
|
|
17099
|
+
attribute: attributeClaudeEntrypoint,
|
|
17100
|
+
note: "macOS TCC can refuse this while it still exists"
|
|
17101
|
+
},
|
|
17102
|
+
{
|
|
17103
|
+
id: "gemini/tmp",
|
|
17104
|
+
readerSlug: "gemini",
|
|
17105
|
+
family: "gemini",
|
|
17106
|
+
members: ["gemini"],
|
|
17107
|
+
defaultMember: "gemini",
|
|
17108
|
+
kind: "dir",
|
|
17109
|
+
path: (i) => joiner(i)(home(i), ".gemini", "tmp"),
|
|
17110
|
+
matches: (n) => n.endsWith(".json")
|
|
17111
|
+
},
|
|
17112
|
+
{
|
|
17113
|
+
id: "cursor/state",
|
|
17114
|
+
readerSlug: "cursor",
|
|
17115
|
+
family: "cursor",
|
|
17116
|
+
members: ["cursor"],
|
|
17117
|
+
defaultMember: "cursor",
|
|
17118
|
+
kind: "file",
|
|
17119
|
+
path: (i) => joiner(i)(appDataRoot(i), "Cursor", "User", "globalStorage", "state.vscdb"),
|
|
17120
|
+
tool: "sqlite"
|
|
17121
|
+
}
|
|
17122
|
+
];
|
|
17123
|
+
});
|
|
17124
|
+
|
|
16468
17125
|
// src/reflect/conversation-registry.ts
|
|
17126
|
+
import { homedir as homedir22, platform as platform7 } from "os";
|
|
16469
17127
|
function computeStatus(lastActivityAt, nowMs, idleMinutes = DEFAULT_IDLE_MINUTES) {
|
|
16470
17128
|
const lastMs = new Date(lastActivityAt).getTime();
|
|
16471
17129
|
if (Number.isNaN(lastMs))
|
|
@@ -16496,43 +17154,114 @@ function mergeSessionListings(listings, opts) {
|
|
|
16496
17154
|
status: isFreshEndStamp(s.endedAt, s.lastActivityAt) ? "finished" : computeStatus(s.lastActivityAt, opts.nowMs, opts.idleMinutes)
|
|
16497
17155
|
}));
|
|
16498
17156
|
}
|
|
17157
|
+
function machineStores(opts) {
|
|
17158
|
+
return opts.stores ?? resolveTranscriptStores({
|
|
17159
|
+
platform: platform7(),
|
|
17160
|
+
homeDir: homedir22(),
|
|
17161
|
+
appData: process.env.APPDATA ?? null,
|
|
17162
|
+
localAppData: process.env.LOCALAPPDATA ?? null
|
|
17163
|
+
});
|
|
17164
|
+
}
|
|
17165
|
+
function attributeListing(store, sessions) {
|
|
17166
|
+
if (!store.def.attribute)
|
|
17167
|
+
return sessions;
|
|
17168
|
+
return sessions.map((s) => {
|
|
17169
|
+
const surface = s.surface ?? null;
|
|
17170
|
+
const slug = surface === null ? null : store.def.attribute?.(surface) ?? null;
|
|
17171
|
+
return {
|
|
17172
|
+
...s,
|
|
17173
|
+
agentSlug: slug ?? store.def.defaultMember,
|
|
17174
|
+
surface
|
|
17175
|
+
};
|
|
17176
|
+
});
|
|
17177
|
+
}
|
|
16499
17178
|
async function listLocalConversations(opts = {}) {
|
|
16500
|
-
const
|
|
17179
|
+
const detected = opts.detected ?? (await detectAgents()).map((a) => a.slug);
|
|
17180
|
+
const detectedSet = new Set(detected);
|
|
16501
17181
|
const sinceISO = opts.sinceISO ?? null;
|
|
17182
|
+
const maxPerStore = opts.maxPerStore ?? DEFAULT_MAX_PER_STORE;
|
|
16502
17183
|
const listings = [];
|
|
16503
|
-
const
|
|
16504
|
-
|
|
16505
|
-
|
|
16506
|
-
|
|
17184
|
+
const perStore = [];
|
|
17185
|
+
const stores = machineStores(opts);
|
|
17186
|
+
const table = stores.map((s) => s.def);
|
|
17187
|
+
for (const store of stores) {
|
|
17188
|
+
const base = {
|
|
17189
|
+
storeId: store.def.id,
|
|
17190
|
+
family: store.def.family,
|
|
17191
|
+
members: [...familyMembers(store.def.family, table)],
|
|
17192
|
+
path: store.path
|
|
17193
|
+
};
|
|
17194
|
+
if (!isStoreUnlocked(store.def, detectedSet, table)) {
|
|
17195
|
+
perStore.push({ ...base, status: "orphaned", sessions: null });
|
|
17196
|
+
continue;
|
|
17197
|
+
}
|
|
17198
|
+
const reader = (opts.readerFor ?? getAdapterBySlug)(store.def.readerSlug);
|
|
17199
|
+
if (!reader?.listSessions) {
|
|
17200
|
+
perStore.push({ ...base, status: "no-reader", sessions: null });
|
|
16507
17201
|
continue;
|
|
16508
17202
|
}
|
|
16509
17203
|
try {
|
|
16510
|
-
const sessions = await
|
|
17204
|
+
const sessions = await reader.listSessions(sinceISO);
|
|
16511
17205
|
if (sessions === null) {
|
|
16512
|
-
|
|
17206
|
+
const outcome = diagnoseTranscriptRead(reader);
|
|
17207
|
+
perStore.push({ ...base, status: outcome.status, sessions: null, ...outcome.detail ? { detail: outcome.detail } : {} });
|
|
16513
17208
|
continue;
|
|
16514
17209
|
}
|
|
16515
|
-
|
|
16516
|
-
|
|
16517
|
-
|
|
16518
|
-
|
|
17210
|
+
const attributed = attributeListing(store, sessions).sort((a, b) => b.lastActivityAt.localeCompare(a.lastActivityAt)).slice(0, maxPerStore);
|
|
17211
|
+
listings.push(attributed);
|
|
17212
|
+
perStore.push({
|
|
17213
|
+
...base,
|
|
17214
|
+
status: "ok",
|
|
17215
|
+
sessions: attributed.length,
|
|
17216
|
+
...sessions.length > attributed.length ? { truncated: sessions.length } : {}
|
|
17217
|
+
});
|
|
17218
|
+
} catch (err) {
|
|
17219
|
+
const outcome = diagnoseTranscriptRead(reader, err);
|
|
17220
|
+
perStore.push({ ...base, status: outcome.status, sessions: null, ...outcome.detail ? { detail: outcome.detail } : {} });
|
|
16519
17221
|
}
|
|
16520
17222
|
}
|
|
16521
17223
|
const conversations = mergeSessionListings(listings, {
|
|
16522
17224
|
nowMs: opts.nowMs ?? Date.now(),
|
|
16523
17225
|
idleMinutes: opts.idleMinutes
|
|
16524
17226
|
});
|
|
16525
|
-
return { conversations, perAgent };
|
|
17227
|
+
return { conversations, perAgent: derivePerAgent(perStore, conversations), perStore };
|
|
17228
|
+
}
|
|
17229
|
+
function derivePerAgent(perStore, conversations) {
|
|
17230
|
+
const counts = new Map;
|
|
17231
|
+
for (const c of conversations)
|
|
17232
|
+
counts.set(c.agentSlug, (counts.get(c.agentSlug) ?? 0) + 1);
|
|
17233
|
+
const rows = new Map;
|
|
17234
|
+
for (const store of perStore) {
|
|
17235
|
+
for (const slug of store.members) {
|
|
17236
|
+
const existing = rows.get(slug);
|
|
17237
|
+
if (store.status === "ok") {
|
|
17238
|
+
rows.set(slug, { agentSlug: slug, status: "ok", sessions: counts.get(slug) ?? 0 });
|
|
17239
|
+
continue;
|
|
17240
|
+
}
|
|
17241
|
+
if (!existing || existing.status !== "ok") {
|
|
17242
|
+
rows.set(slug, {
|
|
17243
|
+
agentSlug: slug,
|
|
17244
|
+
status: store.status === "orphaned" ? "missing-dir" : store.status,
|
|
17245
|
+
sessions: null,
|
|
17246
|
+
...store.path ? { path: store.path } : {},
|
|
17247
|
+
...store.detail ? { detail: store.detail } : {}
|
|
17248
|
+
});
|
|
17249
|
+
}
|
|
17250
|
+
}
|
|
17251
|
+
}
|
|
17252
|
+
return [...rows.values()];
|
|
16526
17253
|
}
|
|
16527
|
-
var DEFAULT_IDLE_MINUTES = 10;
|
|
17254
|
+
var DEFAULT_IDLE_MINUTES = 10, DEFAULT_MAX_PER_STORE = 500;
|
|
16528
17255
|
var init_conversation_registry = __esm(async () => {
|
|
17256
|
+
init_transcript_sources();
|
|
17257
|
+
init_transcript_stores();
|
|
16529
17258
|
await init_detect();
|
|
16530
17259
|
});
|
|
16531
17260
|
|
|
16532
17261
|
// src/reflect/session-summary.ts
|
|
16533
17262
|
import { createHash as createHash4 } from "crypto";
|
|
16534
17263
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
16535
|
-
import { readFileSync as
|
|
17264
|
+
import { readFileSync as readFileSync36 } from "fs";
|
|
16536
17265
|
import { isAbsolute as isAbsolute4 } from "path";
|
|
16537
17266
|
function validateAssetMarkers(markers, knownSkills) {
|
|
16538
17267
|
if (!markers || markers.length === 0)
|
|
@@ -16634,7 +17363,7 @@ function digestForEntry(entry) {
|
|
|
16634
17363
|
return null;
|
|
16635
17364
|
let content;
|
|
16636
17365
|
try {
|
|
16637
|
-
content =
|
|
17366
|
+
content = readFileSync36(entry.transcriptPath, "utf-8");
|
|
16638
17367
|
} catch {
|
|
16639
17368
|
return null;
|
|
16640
17369
|
}
|
|
@@ -16762,18 +17491,18 @@ var init_session_summary = __esm(() => {
|
|
|
16762
17491
|
});
|
|
16763
17492
|
|
|
16764
17493
|
// src/reflect/telemetry-outbox.ts
|
|
16765
|
-
import { existsSync as
|
|
16766
|
-
import { join as
|
|
16767
|
-
import { homedir as
|
|
17494
|
+
import { existsSync as existsSync47, readFileSync as readFileSync37 } from "fs";
|
|
17495
|
+
import { join as join42 } from "path";
|
|
17496
|
+
import { homedir as homedir23 } from "os";
|
|
16768
17497
|
function outboxPath() {
|
|
16769
|
-
return
|
|
17498
|
+
return join42(homedir23(), ".runwork", "telemetry-outbox.json");
|
|
16770
17499
|
}
|
|
16771
17500
|
function loadTelemetryOutbox() {
|
|
16772
17501
|
try {
|
|
16773
17502
|
const p = outboxPath();
|
|
16774
|
-
if (!
|
|
17503
|
+
if (!existsSync47(p))
|
|
16775
17504
|
return [];
|
|
16776
|
-
const parsed = JSON.parse(
|
|
17505
|
+
const parsed = JSON.parse(readFileSync37(p, "utf-8"));
|
|
16777
17506
|
if (!Array.isArray(parsed))
|
|
16778
17507
|
return [];
|
|
16779
17508
|
return parsed.filter((e) => !!e && typeof e === "object" && typeof e.dedupeKey === "string" && !!e.event && typeof e.event === "object");
|
|
@@ -16834,8 +17563,8 @@ var init_active_time = __esm(() => {
|
|
|
16834
17563
|
|
|
16835
17564
|
// src/reflect/pattern-store.ts
|
|
16836
17565
|
import { createHash as createHash5 } from "crypto";
|
|
16837
|
-
import { join as
|
|
16838
|
-
import { homedir as
|
|
17566
|
+
import { join as join43 } from "path";
|
|
17567
|
+
import { homedir as homedir24 } from "os";
|
|
16839
17568
|
function addBuckets(a, b) {
|
|
16840
17569
|
if (!a)
|
|
16841
17570
|
return b ? { ...b } : null;
|
|
@@ -16996,7 +17725,7 @@ function buildPatternEvent(payload, nowISO) {
|
|
|
16996
17725
|
};
|
|
16997
17726
|
}
|
|
16998
17727
|
function storePath3() {
|
|
16999
|
-
return
|
|
17728
|
+
return join43(homedir24(), ".runwork", "pattern-store.json");
|
|
17000
17729
|
}
|
|
17001
17730
|
function loadPatternStore() {
|
|
17002
17731
|
const parsed = readJsonOrNull(storePath3());
|
|
@@ -17206,7 +17935,7 @@ var init_triage = __esm(async () => {
|
|
|
17206
17935
|
});
|
|
17207
17936
|
|
|
17208
17937
|
// src/reflect/conversation-analysis.ts
|
|
17209
|
-
import { existsSync as
|
|
17938
|
+
import { existsSync as existsSync48 } from "fs";
|
|
17210
17939
|
import { basename as basename5 } from "path";
|
|
17211
17940
|
function brokenAnalystBinaries() {
|
|
17212
17941
|
return TIER2_ANALYSTS.filter((a) => {
|
|
@@ -17234,7 +17963,7 @@ function isPromptStillValid(key) {
|
|
|
17234
17963
|
if (!standing?.promptPath || standing.promptConversationKey !== key)
|
|
17235
17964
|
return false;
|
|
17236
17965
|
try {
|
|
17237
|
-
return
|
|
17966
|
+
return existsSync48(standing.promptPath);
|
|
17238
17967
|
} catch {
|
|
17239
17968
|
return false;
|
|
17240
17969
|
}
|
|
@@ -17922,7 +18651,7 @@ var init_welcome = __esm(() => {
|
|
|
17922
18651
|
});
|
|
17923
18652
|
|
|
17924
18653
|
// src/index.ts
|
|
17925
|
-
import { Command as
|
|
18654
|
+
import { Command as Command40 } from "commander";
|
|
17926
18655
|
|
|
17927
18656
|
// src/commands/login.ts
|
|
17928
18657
|
init_login_flow();
|
|
@@ -18231,7 +18960,18 @@ var deployCommand = new Command5("deploy").description("Deploy the current app t
|
|
|
18231
18960
|
console.log("Syncing...");
|
|
18232
18961
|
try {
|
|
18233
18962
|
commitWorkingTree(cwd, `deploy: ${new Date().toISOString().replace("T", " ").slice(0, 19)}`);
|
|
18234
|
-
} catch {
|
|
18963
|
+
} catch (err) {
|
|
18964
|
+
if (hasTrackedChanges(cwd)) {
|
|
18965
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
18966
|
+
if (useJson) {
|
|
18967
|
+
jsonOut(buildErrorResponse("deploy", "Could not commit your changes", `Your working tree has uncommitted changes that could not be committed (${detail.slice(0, 300)}). Deploying now would ship the PREVIOUS commit while reporting success.`, ["Check for a failing pre-commit hook or a stale .git/index.lock", "Commit the changes yourself with git commit", "Then re-run runwork deploy"]));
|
|
18968
|
+
process.exit(1);
|
|
18969
|
+
}
|
|
18970
|
+
console.error("Could not commit your changes, so nothing new would be deployed.");
|
|
18971
|
+
console.error("A pre-commit hook or a stale .git/index.lock may be interfering. Commit manually, then re-run `runwork deploy`.");
|
|
18972
|
+
process.exit(1);
|
|
18973
|
+
}
|
|
18974
|
+
}
|
|
18235
18975
|
if (!hasCommits(cwd)) {
|
|
18236
18976
|
if (useJson) {
|
|
18237
18977
|
jsonOut(buildErrorResponse("deploy", "Nothing to deploy", "No commits exist and the working tree has no changes to commit, so there is nothing to sync or deploy.", ["Make changes to your app first", "Run runwork dev to develop and verify changes", "Then run runwork deploy"]));
|
|
@@ -20278,34 +21018,184 @@ var skillsCommand = new Command13("skills").description("Manage workspace skills
|
|
|
20278
21018
|
await init_reflect();
|
|
20279
21019
|
|
|
20280
21020
|
// src/commands/conversations.ts
|
|
20281
|
-
|
|
20282
|
-
|
|
20283
|
-
init_telemetry_outbox();
|
|
20284
|
-
init_insight_store();
|
|
20285
|
-
init_atomic_json();
|
|
20286
|
-
init_store();
|
|
20287
|
-
init_client();
|
|
20288
|
-
init_resolve();
|
|
20289
|
-
init_workspace_state();
|
|
20290
|
-
init_colors();
|
|
20291
|
-
await __promiseAll([
|
|
20292
|
-
init_conversation_registry(),
|
|
20293
|
-
init_conversation_analysis()
|
|
20294
|
-
]);
|
|
21021
|
+
init_transcript_stores();
|
|
21022
|
+
await init_detect();
|
|
20295
21023
|
import { Command as Command15 } from "commander";
|
|
20296
|
-
import { join as
|
|
20297
|
-
import { homedir as
|
|
20298
|
-
|
|
20299
|
-
|
|
20300
|
-
|
|
21024
|
+
import { join as join44 } from "path";
|
|
21025
|
+
import { homedir as homedir25, platform as platform8 } from "os";
|
|
21026
|
+
|
|
21027
|
+
// src/agents/store-census.ts
|
|
21028
|
+
init_transcript_stores();
|
|
21029
|
+
import { readdirSync as readdirSync16, statSync as statSync10, existsSync as existsSync46, openSync as openSync5, readSync as readSync3, closeSync as closeSync5 } from "fs";
|
|
21030
|
+
import { join as join41 } from "path";
|
|
21031
|
+
function sanitizeMarker(raw) {
|
|
21032
|
+
const cleaned = raw.replace(/[^\x20-\x7E]/g, "").trim();
|
|
21033
|
+
return cleaned.length > 64 ? `${cleaned.slice(0, 63)}…` : cleaned;
|
|
21034
|
+
}
|
|
21035
|
+
function readHead(path2, n) {
|
|
21036
|
+
let fd;
|
|
21037
|
+
try {
|
|
21038
|
+
fd = openSync5(path2, "r");
|
|
21039
|
+
const buf = Buffer.alloc(n);
|
|
21040
|
+
const read = readSync3(fd, buf, 0, n, 0);
|
|
21041
|
+
return buf.subarray(0, read).toString("utf-8");
|
|
21042
|
+
} catch {
|
|
20301
21043
|
return null;
|
|
20302
|
-
|
|
21044
|
+
} finally {
|
|
21045
|
+
if (fd !== undefined) {
|
|
21046
|
+
try {
|
|
21047
|
+
closeSync5(fd);
|
|
21048
|
+
} catch {}
|
|
21049
|
+
}
|
|
21050
|
+
}
|
|
20303
21051
|
}
|
|
20304
|
-
function
|
|
20305
|
-
const
|
|
20306
|
-
|
|
20307
|
-
|
|
20308
|
-
|
|
21052
|
+
function isPermissionError(err) {
|
|
21053
|
+
const code = err?.code;
|
|
21054
|
+
return code === "EACCES" || code === "EPERM";
|
|
21055
|
+
}
|
|
21056
|
+
function isMissingError(err) {
|
|
21057
|
+
const code = err?.code;
|
|
21058
|
+
return code === "ENOENT" || code === "ENOTDIR";
|
|
21059
|
+
}
|
|
21060
|
+
function collect(dir, def, out, budget) {
|
|
21061
|
+
if (budget.left <= 0)
|
|
21062
|
+
return;
|
|
21063
|
+
const entries = readdirSync16(dir, { withFileTypes: true });
|
|
21064
|
+
for (const e of entries) {
|
|
21065
|
+
if (budget.left <= 0)
|
|
21066
|
+
return;
|
|
21067
|
+
const full = join41(dir, e.name);
|
|
21068
|
+
if (e.isDirectory()) {
|
|
21069
|
+
try {
|
|
21070
|
+
collect(full, def, out, budget);
|
|
21071
|
+
} catch (err) {
|
|
21072
|
+
if (isPermissionError(err))
|
|
21073
|
+
throw err;
|
|
21074
|
+
}
|
|
21075
|
+
} else if (!def.matches || def.matches(e.name)) {
|
|
21076
|
+
out.push(full);
|
|
21077
|
+
budget.left--;
|
|
21078
|
+
}
|
|
21079
|
+
}
|
|
21080
|
+
}
|
|
21081
|
+
var DEFAULT_MAX_FILES = 2000;
|
|
21082
|
+
function censusStore(store, unlocked, opts = {}) {
|
|
21083
|
+
const { def, path: path2, altPaths } = store;
|
|
21084
|
+
const base = {
|
|
21085
|
+
storeId: def.id,
|
|
21086
|
+
family: def.family,
|
|
21087
|
+
members: def.members,
|
|
21088
|
+
path: path2,
|
|
21089
|
+
unlocked,
|
|
21090
|
+
status: "ok"
|
|
21091
|
+
};
|
|
21092
|
+
const altHits = altPaths.filter((p) => {
|
|
21093
|
+
try {
|
|
21094
|
+
return existsSync46(p);
|
|
21095
|
+
} catch {
|
|
21096
|
+
return false;
|
|
21097
|
+
}
|
|
21098
|
+
});
|
|
21099
|
+
if (altHits.length > 0)
|
|
21100
|
+
base.altHits = altHits;
|
|
21101
|
+
if (!existsSync46(path2))
|
|
21102
|
+
return { ...base, status: "missing" };
|
|
21103
|
+
if (def.kind === "file") {
|
|
21104
|
+
try {
|
|
21105
|
+
const s = statSync10(path2);
|
|
21106
|
+
return { ...base, files: 1, bytes: s.size, newestAt: new Date(s.mtimeMs).toISOString() };
|
|
21107
|
+
} catch (err) {
|
|
21108
|
+
return { ...base, status: isPermissionError(err) ? "permission-denied" : "error", detail: String(err) };
|
|
21109
|
+
}
|
|
21110
|
+
}
|
|
21111
|
+
const all = [];
|
|
21112
|
+
const budget = { left: opts.maxFiles ?? DEFAULT_MAX_FILES };
|
|
21113
|
+
try {
|
|
21114
|
+
collect(path2, def, all, budget);
|
|
21115
|
+
} catch (err) {
|
|
21116
|
+
if (isPermissionError(err))
|
|
21117
|
+
return { ...base, status: "permission-denied", detail: "EACCES" };
|
|
21118
|
+
if (isMissingError(err))
|
|
21119
|
+
return { ...base, status: "missing" };
|
|
21120
|
+
return { ...base, status: "error", detail: err instanceof Error ? err.message : String(err) };
|
|
21121
|
+
}
|
|
21122
|
+
const files = [];
|
|
21123
|
+
let nested = 0;
|
|
21124
|
+
for (const f of all) {
|
|
21125
|
+
const rel = f.slice(path2.length).replace(/^[\\/]+/, "");
|
|
21126
|
+
if (def.subordinate?.(rel))
|
|
21127
|
+
nested++;
|
|
21128
|
+
else
|
|
21129
|
+
files.push(f);
|
|
21130
|
+
}
|
|
21131
|
+
let bytes = 0;
|
|
21132
|
+
let newest = 0;
|
|
21133
|
+
for (const f of all) {
|
|
21134
|
+
try {
|
|
21135
|
+
const s = statSync10(f);
|
|
21136
|
+
bytes += s.size;
|
|
21137
|
+
if (s.mtimeMs > newest)
|
|
21138
|
+
newest = s.mtimeMs;
|
|
21139
|
+
} catch {}
|
|
21140
|
+
}
|
|
21141
|
+
const result = {
|
|
21142
|
+
...base,
|
|
21143
|
+
files: files.length,
|
|
21144
|
+
...nested > 0 ? { nested } : {},
|
|
21145
|
+
bytes,
|
|
21146
|
+
newestAt: newest > 0 ? new Date(newest).toISOString() : null
|
|
21147
|
+
};
|
|
21148
|
+
if (opts.skipMarkers || !def.marker)
|
|
21149
|
+
return result;
|
|
21150
|
+
const counts = new Map;
|
|
21151
|
+
for (const f of files) {
|
|
21152
|
+
const head = readHead(f, def.headBytes ?? 64 * 1024);
|
|
21153
|
+
const { agentSlug, marker, recognised } = attributeTranscript(def, head);
|
|
21154
|
+
const clean = marker === null ? null : sanitizeMarker(marker);
|
|
21155
|
+
const key = clean ?? "\x00none";
|
|
21156
|
+
const existing = counts.get(key);
|
|
21157
|
+
if (existing)
|
|
21158
|
+
existing.count++;
|
|
21159
|
+
else
|
|
21160
|
+
counts.set(key, { marker: clean, count: 1, agentSlug, recognised });
|
|
21161
|
+
}
|
|
21162
|
+
result.markers = [...counts.values()].sort((a, b) => b.count - a.count);
|
|
21163
|
+
return result;
|
|
21164
|
+
}
|
|
21165
|
+
function censusStores(stores, detectedSlugs, opts = {}) {
|
|
21166
|
+
const detected = new Set(detectedSlugs);
|
|
21167
|
+
return stores.map((store) => censusStore(store, isStoreUnlocked(store.def, detected), opts));
|
|
21168
|
+
}
|
|
21169
|
+
function orphanedStoresWithContent(censuses) {
|
|
21170
|
+
return censuses.filter((c) => !c.unlocked && c.status === "ok" && (c.files ?? 0) > 0);
|
|
21171
|
+
}
|
|
21172
|
+
|
|
21173
|
+
// src/commands/conversations.ts
|
|
21174
|
+
init_conversation_queue();
|
|
21175
|
+
init_session_summary();
|
|
21176
|
+
init_telemetry_outbox();
|
|
21177
|
+
init_insight_store();
|
|
21178
|
+
init_atomic_json();
|
|
21179
|
+
init_store();
|
|
21180
|
+
init_client();
|
|
21181
|
+
init_resolve();
|
|
21182
|
+
init_workspace_state();
|
|
21183
|
+
init_colors();
|
|
21184
|
+
await __promiseAll([
|
|
21185
|
+
init_conversation_registry(),
|
|
21186
|
+
init_conversation_analysis()
|
|
21187
|
+
]);
|
|
21188
|
+
var DEFAULT_LOOKBACK_DAYS = 0;
|
|
21189
|
+
function sinceFromDays(days) {
|
|
21190
|
+
if (days <= 0)
|
|
21191
|
+
return null;
|
|
21192
|
+
return new Date(Date.now() - days * 24 * 3600 * 1000).toISOString();
|
|
21193
|
+
}
|
|
21194
|
+
function parseDays(raw) {
|
|
21195
|
+
const n = Number(raw);
|
|
21196
|
+
if (!Number.isFinite(n) || n < 0)
|
|
21197
|
+
return DEFAULT_LOOKBACK_DAYS;
|
|
21198
|
+
return Math.floor(n);
|
|
20309
21199
|
}
|
|
20310
21200
|
function bareRegistrySkillId(skill) {
|
|
20311
21201
|
if (skill.type !== "external" || typeof skill.id !== "string")
|
|
@@ -20359,22 +21249,34 @@ function fit(text2, width) {
|
|
|
20359
21249
|
return text2.length > width ? text2.slice(0, width - 1) + "…" : text2;
|
|
20360
21250
|
}
|
|
20361
21251
|
var conversationsCommand = new Command15("conversations").description("Local AI conversations across your agents (registry, end detection)");
|
|
20362
|
-
conversationsCommand.command("list").description("List local conversations across all detected agents (metadata only)").option("--days <n>", "
|
|
21252
|
+
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) => {
|
|
20363
21253
|
const json = command.optsWithGlobals().json === true || !process.stdout.isTTY;
|
|
20364
21254
|
const days = parseDays(opts.days);
|
|
20365
21255
|
const idleMinutes = Math.max(1, Number(opts.idleMinutes) || DEFAULT_IDLE_MINUTES);
|
|
20366
21256
|
const result = await listLocalConversations({ sinceISO: sinceFromDays(days), idleMinutes });
|
|
20367
21257
|
if (json) {
|
|
20368
|
-
jsonOut({ conversations: result.conversations, perAgent: result.perAgent });
|
|
21258
|
+
jsonOut({ conversations: result.conversations, perAgent: result.perAgent, perStore: result.perStore });
|
|
20369
21259
|
return;
|
|
20370
21260
|
}
|
|
20371
21261
|
console.log(bold(days > 0 ? `
|
|
20372
21262
|
Local conversations, last ${days} day(s)` : `
|
|
20373
21263
|
Local conversations (all)`));
|
|
21264
|
+
for (const s of result.perStore) {
|
|
21265
|
+
const reason = describeStoreOutcome(s);
|
|
21266
|
+
if (reason === null)
|
|
21267
|
+
continue;
|
|
21268
|
+
const line = ` ${s.storeId}: ${reason}`;
|
|
21269
|
+
console.log(storeOutcomeNeedsAttention(s) ? yellow(line) : dim(line));
|
|
21270
|
+
}
|
|
20374
21271
|
for (const a of result.perAgent) {
|
|
20375
|
-
if (a.
|
|
21272
|
+
if (a.status === "no-reader")
|
|
20376
21273
|
continue;
|
|
20377
|
-
|
|
21274
|
+
const reason = describeScanOutcome(a);
|
|
21275
|
+
if (reason === null) {
|
|
21276
|
+
console.log(dim(` ${a.agentSlug}: ${a.sessions} session(s)`));
|
|
21277
|
+
} else {
|
|
21278
|
+
console.log(` ${a.agentSlug}: ${scanOutcomeNeedsAttention(a) ? yellow(reason) : dim(reason)}`);
|
|
21279
|
+
}
|
|
20378
21280
|
}
|
|
20379
21281
|
console.log("");
|
|
20380
21282
|
const width = process.stdout.columns || 120;
|
|
@@ -20391,7 +21293,36 @@ Local conversations (all)`));
|
|
|
20391
21293
|
if (result.conversations.length === 0)
|
|
20392
21294
|
console.log(dim(" none"));
|
|
20393
21295
|
});
|
|
20394
|
-
conversationsCommand.command("
|
|
21296
|
+
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) => {
|
|
21297
|
+
const json = command.optsWithGlobals().json === true || !process.stdout.isTTY;
|
|
21298
|
+
const days = parseDays(opts.days);
|
|
21299
|
+
const { perAgent, perStore } = await listLocalConversations({ sinceISO: sinceFromDays(days) });
|
|
21300
|
+
if (json) {
|
|
21301
|
+
jsonOut({ perAgent, perStore });
|
|
21302
|
+
return;
|
|
21303
|
+
}
|
|
21304
|
+
console.log(bold(days > 0 ? `
|
|
21305
|
+
Conversation sources, last ${days} day(s)` : `
|
|
21306
|
+
Conversation sources`));
|
|
21307
|
+
for (const s of perStore) {
|
|
21308
|
+
const reason = describeStoreOutcome(s);
|
|
21309
|
+
if (reason === null) {
|
|
21310
|
+
console.log(` ${cyan(s.storeId)}: ${s.sessions} conversation(s)`);
|
|
21311
|
+
} else {
|
|
21312
|
+
console.log(` ${cyan(s.storeId)}: ${storeOutcomeNeedsAttention(s) ? yellow(reason) : dim(reason)}`);
|
|
21313
|
+
}
|
|
21314
|
+
}
|
|
21315
|
+
console.log("");
|
|
21316
|
+
for (const a of perAgent) {
|
|
21317
|
+
const reason = describeScanOutcome(a);
|
|
21318
|
+
if (reason === null) {
|
|
21319
|
+
console.log(` ${cyan(a.agentSlug)}: ${a.status === "no-reader" ? dim("no transcript reader") : `${a.sessions} conversation(s)`}`);
|
|
21320
|
+
} else {
|
|
21321
|
+
console.log(` ${cyan(a.agentSlug)}: ${scanOutcomeNeedsAttention(a) ? yellow(reason) : dim(reason)}`);
|
|
21322
|
+
}
|
|
21323
|
+
}
|
|
21324
|
+
});
|
|
21325
|
+
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) => {
|
|
20395
21326
|
const json = command.optsWithGlobals().json === true || !process.stdout.isTTY;
|
|
20396
21327
|
const days = parseDays(opts.days);
|
|
20397
21328
|
const idleMinutes = Math.max(1, Number(opts.idleMinutes) || DEFAULT_IDLE_MINUTES);
|
|
@@ -20454,11 +21385,13 @@ conversationsCommand.command("scan").description("Detect finished conversations
|
|
|
20454
21385
|
const snapshot = {
|
|
20455
21386
|
generatedAt: new Date().toISOString(),
|
|
20456
21387
|
idleMinutes,
|
|
20457
|
-
conversations: [...listed, ...rescued].sort((a, b) => b.lastActivityAt.localeCompare(a.lastActivityAt))
|
|
21388
|
+
conversations: [...listed, ...rescued].sort((a, b) => b.lastActivityAt.localeCompare(a.lastActivityAt)),
|
|
21389
|
+
perAgent: result.perAgent,
|
|
21390
|
+
perStore: result.perStore
|
|
20458
21391
|
};
|
|
20459
|
-
writeJsonAtomic(
|
|
21392
|
+
writeJsonAtomic(join44(homedir25(), ".runwork", "conversations.json"), snapshot);
|
|
20460
21393
|
if (json) {
|
|
20461
|
-
jsonOut({ queued: scan.queued, reopened: scan.reopened, pruned: scan.pruned, pending, finished: finished.length });
|
|
21394
|
+
jsonOut({ queued: scan.queued, reopened: scan.reopened, pruned: scan.pruned, pending, finished: finished.length, perAgent: result.perAgent });
|
|
20462
21395
|
return;
|
|
20463
21396
|
}
|
|
20464
21397
|
console.log(green(`Scanned ${result.conversations.length} conversation(s): ${scan.queued} newly queued, ${scan.reopened} reopened, ${pending} pending analysis.`));
|
|
@@ -20479,15 +21412,71 @@ conversationsCommand.command("analyze").description("Analyze queued finished con
|
|
|
20479
21412
|
}
|
|
20480
21413
|
console.log(outcome.reason ? dim(describeAnalysisOutcome(outcome)) : green(describeAnalysisOutcome(outcome)));
|
|
20481
21414
|
});
|
|
21415
|
+
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) => {
|
|
21416
|
+
const json = command.optsWithGlobals().json === true || !process.stdout.isTTY;
|
|
21417
|
+
const maxFiles = Math.max(1, Number(opts.maxFiles) || DEFAULT_MAX_FILES);
|
|
21418
|
+
const detected = (await detectAgents()).map((a) => a.slug);
|
|
21419
|
+
const stores = resolveTranscriptStores({
|
|
21420
|
+
platform: platform8(),
|
|
21421
|
+
homeDir: homedir25(),
|
|
21422
|
+
appData: process.env.APPDATA ?? null,
|
|
21423
|
+
localAppData: process.env.LOCALAPPDATA ?? null
|
|
21424
|
+
});
|
|
21425
|
+
const censuses = censusStores(stores, detected, {
|
|
21426
|
+
maxFiles,
|
|
21427
|
+
skipMarkers: opts.markers === false
|
|
21428
|
+
});
|
|
21429
|
+
if (json) {
|
|
21430
|
+
jsonOut({ detected, stores: censuses });
|
|
21431
|
+
return;
|
|
21432
|
+
}
|
|
21433
|
+
console.log(bold(`
|
|
21434
|
+
Transcript stores`));
|
|
21435
|
+
console.log(dim(` detected agents: ${detected.length > 0 ? detected.join(", ") : "none"}
|
|
21436
|
+
`));
|
|
21437
|
+
for (const c of censuses) {
|
|
21438
|
+
const owner = c.unlocked ? green("read") : yellow("ORPHANED");
|
|
21439
|
+
console.log(`${bold(c.storeId)} ${owner} ${dim(`family ${c.family}: ${c.members.join(", ")}`)}`);
|
|
21440
|
+
console.log(dim(` ${c.path}`));
|
|
21441
|
+
if (c.status !== "ok") {
|
|
21442
|
+
console.log(` ${yellow(c.status)}${c.detail ? dim(` (${c.detail})`) : ""}`);
|
|
21443
|
+
} else {
|
|
21444
|
+
const mb = ((c.bytes ?? 0) / 1e6).toFixed(1);
|
|
21445
|
+
const newest = c.newestAt ? c.newestAt.slice(0, 16).replace("T", " ") : "-";
|
|
21446
|
+
const nested = c.nested ? `, plus ${c.nested} subagent transcript(s)` : "";
|
|
21447
|
+
console.log(dim(` ${c.files} conversation(s)${nested}, ${mb} MB, newest ${newest}`));
|
|
21448
|
+
for (const m of c.markers ?? []) {
|
|
21449
|
+
if (m.marker === null) {
|
|
21450
|
+
console.log(` ${String(m.count).padStart(5)} ${dim(`(no marker, pre-dates the field) -> ${m.agentSlug}`)}`);
|
|
21451
|
+
continue;
|
|
21452
|
+
}
|
|
21453
|
+
const flag = m.recognised ? dim(`-> ${m.agentSlug}`) : yellow(`-> ${m.agentSlug} (UNRECOGNISED surface)`);
|
|
21454
|
+
console.log(` ${String(m.count).padStart(5)} ${cyan(m.marker)} ${flag}`);
|
|
21455
|
+
}
|
|
21456
|
+
}
|
|
21457
|
+
for (const alt of c.altHits ?? []) {
|
|
21458
|
+
console.log(` ${yellow("also present:")} ${dim(alt)}`);
|
|
21459
|
+
}
|
|
21460
|
+
console.log("");
|
|
21461
|
+
}
|
|
21462
|
+
const orphans = orphanedStoresWithContent(censuses);
|
|
21463
|
+
if (orphans.length > 0) {
|
|
21464
|
+
console.log(yellow(`${orphans.length} store(s) hold transcripts that no detected agent reads:`));
|
|
21465
|
+
for (const o of orphans) {
|
|
21466
|
+
console.log(` ${o.path} ${dim(`(${o.files} transcripts; needs one of: ${o.members.join(", ")})`)}`);
|
|
21467
|
+
}
|
|
21468
|
+
console.log("");
|
|
21469
|
+
}
|
|
21470
|
+
});
|
|
20482
21471
|
|
|
20483
21472
|
// src/commands/instructions.ts
|
|
20484
21473
|
init_store();
|
|
20485
21474
|
init_client();
|
|
20486
21475
|
init_resolve();
|
|
20487
21476
|
import { Command as Command16 } from "commander";
|
|
20488
|
-
import { readFileSync as
|
|
20489
|
-
import { join as
|
|
20490
|
-
import { homedir as
|
|
21477
|
+
import { readFileSync as readFileSync38, existsSync as existsSync49 } from "fs";
|
|
21478
|
+
import { join as join45 } from "path";
|
|
21479
|
+
import { homedir as homedir26 } from "os";
|
|
20491
21480
|
|
|
20492
21481
|
// ../../shared/agent-instructions/runwork-instructions.ts
|
|
20493
21482
|
function formatList(items, max = 8) {
|
|
@@ -20967,13 +21956,13 @@ async function buildInstructionContext(client, workspace) {
|
|
|
20967
21956
|
// src/commands/instructions.ts
|
|
20968
21957
|
function readSetupExtras(workspaceId) {
|
|
20969
21958
|
for (const path2 of [
|
|
20970
|
-
|
|
20971
|
-
|
|
21959
|
+
join45(process.cwd(), ".runwork", "setup.json"),
|
|
21960
|
+
join45(homedir26(), ".runwork", "setup.json")
|
|
20972
21961
|
]) {
|
|
20973
|
-
if (!
|
|
21962
|
+
if (!existsSync49(path2))
|
|
20974
21963
|
continue;
|
|
20975
21964
|
try {
|
|
20976
|
-
const state = JSON.parse(
|
|
21965
|
+
const state = JSON.parse(readFileSync38(path2, "utf-8"));
|
|
20977
21966
|
if (state.workspaceId === workspaceId) {
|
|
20978
21967
|
return { workspaceSlug: state.workspaceSlug, persona: state.persona };
|
|
20979
21968
|
}
|
|
@@ -21017,16 +22006,16 @@ import { Command as Command17 } from "commander";
|
|
|
21017
22006
|
import * as path3 from "node:path";
|
|
21018
22007
|
|
|
21019
22008
|
// src/utils/data-input.ts
|
|
21020
|
-
import { readFileSync as
|
|
22009
|
+
import { readFileSync as readFileSync39, existsSync as existsSync50 } from "fs";
|
|
21021
22010
|
async function parseDataInput(dataFlag) {
|
|
21022
22011
|
if (dataFlag) {
|
|
21023
22012
|
if (dataFlag.startsWith("@")) {
|
|
21024
22013
|
const filePath = dataFlag.slice(1);
|
|
21025
|
-
if (!
|
|
22014
|
+
if (!existsSync50(filePath)) {
|
|
21026
22015
|
console.error(`File not found: ${filePath}`);
|
|
21027
22016
|
process.exit(1);
|
|
21028
22017
|
}
|
|
21029
|
-
const content =
|
|
22018
|
+
const content = readFileSync39(filePath, "utf-8");
|
|
21030
22019
|
return parseJson(content, filePath);
|
|
21031
22020
|
}
|
|
21032
22021
|
return parseJson(dataFlag, "--data");
|
|
@@ -22080,7 +23069,7 @@ init_resolve();
|
|
|
22080
23069
|
init_prompt();
|
|
22081
23070
|
init_http();
|
|
22082
23071
|
import { Command as Command21 } from "commander";
|
|
22083
|
-
import { writeFileSync as writeFileSync29, readFileSync as
|
|
23072
|
+
import { writeFileSync as writeFileSync29, readFileSync as readFileSync40 } from "fs";
|
|
22084
23073
|
import { basename as basename6 } from "path";
|
|
22085
23074
|
function formatSize(bytes) {
|
|
22086
23075
|
if (bytes === undefined)
|
|
@@ -22190,7 +23179,7 @@ var uploadCommand = new Command21("upload").description("Upload a local file to
|
|
|
22190
23179
|
const { workspaceId } = await resolveWorkspace2(client, opts);
|
|
22191
23180
|
const objectKey = key || basename6(localPath);
|
|
22192
23181
|
try {
|
|
22193
|
-
const fileBuffer =
|
|
23182
|
+
const fileBuffer = readFileSync40(localPath);
|
|
22194
23183
|
const { url } = await client.getPresignedUrl(workspaceId, bucket, { action: "write", key: objectKey });
|
|
22195
23184
|
const response = await httpFetch(url, { method: "PUT", body: fileBuffer });
|
|
22196
23185
|
if (!response.ok) {
|
|
@@ -22707,8 +23696,8 @@ init_resolve();
|
|
|
22707
23696
|
init_prompt();
|
|
22708
23697
|
await init_detect();
|
|
22709
23698
|
import { Command as Command27 } from "commander";
|
|
22710
|
-
import { join as
|
|
22711
|
-
import { homedir as
|
|
23699
|
+
import { join as join50 } from "path";
|
|
23700
|
+
import { homedir as homedir29 } from "os";
|
|
22712
23701
|
|
|
22713
23702
|
// src/commands/sync.ts
|
|
22714
23703
|
init_store();
|
|
@@ -22719,9 +23708,9 @@ await __promiseAll([
|
|
|
22719
23708
|
init_codex()
|
|
22720
23709
|
]);
|
|
22721
23710
|
import { Command as Command26 } from "commander";
|
|
22722
|
-
import { readFileSync as
|
|
22723
|
-
import { join as
|
|
22724
|
-
import { homedir as
|
|
23711
|
+
import { readFileSync as readFileSync42, existsSync as existsSync53 } from "fs";
|
|
23712
|
+
import { join as join49 } from "path";
|
|
23713
|
+
import { homedir as homedir28 } from "os";
|
|
22725
23714
|
|
|
22726
23715
|
// src/commands/mcp-entries.ts
|
|
22727
23716
|
init_types();
|
|
@@ -22785,6 +23774,7 @@ var RUNWORK_AGENT_DEFAULTS = {
|
|
|
22785
23774
|
};
|
|
22786
23775
|
var AGENT_DEFAULTS_SCHEMA_VERSION = 1;
|
|
22787
23776
|
// src/commands/sync-telemetry.ts
|
|
23777
|
+
init_transcript_stores();
|
|
22788
23778
|
var TELEMETRY_BACKFILL_MS = 30 * 24 * 60 * 60 * 1000;
|
|
22789
23779
|
function resolveTelemetrySince(state, nowMs = Date.now()) {
|
|
22790
23780
|
if (state.lastTelemetryAt)
|
|
@@ -22795,11 +23785,20 @@ async function collectTelemetryEvents(params) {
|
|
|
22795
23785
|
const now = params.now ?? new Date().toISOString();
|
|
22796
23786
|
const events = [];
|
|
22797
23787
|
const adapterResults = [];
|
|
23788
|
+
const bySlug = new Map(params.adapters.map((a) => [a.slug, a]));
|
|
23789
|
+
const suppressed = suppressedStoreReaders(params.adapters.map((a) => a.slug), (a, b) => {
|
|
23790
|
+
const left = bySlug.get(a);
|
|
23791
|
+
const right = bySlug.get(b);
|
|
23792
|
+
if (!left || !right)
|
|
23793
|
+
return false;
|
|
23794
|
+
return left.readUsageStats !== undefined && left.readUsageStats === right.readUsageStats || left.readSkillUsage !== undefined && left.readSkillUsage === right.readSkillUsage;
|
|
23795
|
+
});
|
|
22798
23796
|
for (const adapter2 of params.adapters) {
|
|
22799
23797
|
let stats = "unsupported";
|
|
22800
23798
|
let skills = "unsupported";
|
|
22801
23799
|
let error;
|
|
22802
|
-
|
|
23800
|
+
const readsStore = !suppressed.has(adapter2.slug);
|
|
23801
|
+
if (adapter2.readUsageStats && readsStore) {
|
|
22803
23802
|
try {
|
|
22804
23803
|
stats = await adapter2.readUsageStats(params.since);
|
|
22805
23804
|
if (stats && stats.hasNewActivity) {
|
|
@@ -22827,7 +23826,7 @@ async function collectTelemetryEvents(params) {
|
|
|
22827
23826
|
stats = null;
|
|
22828
23827
|
}
|
|
22829
23828
|
}
|
|
22830
|
-
if (adapter2.readSkillUsage) {
|
|
23829
|
+
if (adapter2.readSkillUsage && readsStore) {
|
|
22831
23830
|
try {
|
|
22832
23831
|
skills = await adapter2.readSkillUsage(params.since);
|
|
22833
23832
|
if (skills && skills.length > 0) {
|
|
@@ -23433,7 +24432,11 @@ async function executeSyncPlan(plan, resolvedConflicts, ctx) {
|
|
|
23433
24432
|
if (!action.remoteContent)
|
|
23434
24433
|
continue;
|
|
23435
24434
|
const skillFile = makeSkillFile(action.name, action.remoteContent);
|
|
23436
|
-
await writeSkillToAgents(skillFile, action.source, ctx);
|
|
24435
|
+
const outcome = await writeSkillToAgents(skillFile, action.source, ctx);
|
|
24436
|
+
if (!writeLanded(outcome)) {
|
|
24437
|
+
vlog(` Pull FAILED for ${action.name} (${outcome.succeeded}/${outcome.attempted} agent writes); will retry next sync`);
|
|
24438
|
+
continue;
|
|
24439
|
+
}
|
|
23437
24440
|
newHashes[action.name] = {
|
|
23438
24441
|
localHash: contentHash(buildSkillMd2(skillFile)),
|
|
23439
24442
|
remoteHash: contentHash(action.remoteContent),
|
|
@@ -23475,7 +24478,11 @@ async function executeSyncPlan(plan, resolvedConflicts, ctx) {
|
|
|
23475
24478
|
vlog(` Pushed (conflict resolved): ${action.name}`);
|
|
23476
24479
|
} else if (resolution === "remote" && action.remoteContent) {
|
|
23477
24480
|
const skillFile = makeSkillFile(action.name, action.remoteContent);
|
|
23478
|
-
await writeSkillToAgents(skillFile, action.source, ctx);
|
|
24481
|
+
const outcome = await writeSkillToAgents(skillFile, action.source, ctx);
|
|
24482
|
+
if (!writeLanded(outcome)) {
|
|
24483
|
+
vlog(` Conflict pull FAILED for ${action.name} (${outcome.succeeded}/${outcome.attempted} agent writes); will retry next sync`);
|
|
24484
|
+
continue;
|
|
24485
|
+
}
|
|
23479
24486
|
newHashes[action.name] = {
|
|
23480
24487
|
localHash: contentHash(buildSkillMd2(skillFile)),
|
|
23481
24488
|
remoteHash: contentHash(action.remoteContent),
|
|
@@ -23487,6 +24494,7 @@ async function executeSyncPlan(plan, resolvedConflicts, ctx) {
|
|
|
23487
24494
|
}
|
|
23488
24495
|
for (const _action of plan.skips) {}
|
|
23489
24496
|
const deletionSlugs = plan.deletions.map((action) => toSlug(action.name));
|
|
24497
|
+
let removalsFailed = false;
|
|
23490
24498
|
if (deletionSlugs.length) {
|
|
23491
24499
|
for (const adapter2 of ctx.adapters) {
|
|
23492
24500
|
if (!adapter2.supportsSkills() || !adapter2.removeSkills)
|
|
@@ -23494,14 +24502,19 @@ async function executeSyncPlan(plan, resolvedConflicts, ctx) {
|
|
|
23494
24502
|
for (const scope of ctx.scopes) {
|
|
23495
24503
|
try {
|
|
23496
24504
|
await adapter2.removeSkills(deletionSlugs, scope);
|
|
23497
|
-
} catch {
|
|
24505
|
+
} catch {
|
|
24506
|
+
removalsFailed = true;
|
|
24507
|
+
}
|
|
23498
24508
|
}
|
|
23499
24509
|
}
|
|
23500
24510
|
for (const action of plan.deletions) {
|
|
23501
|
-
vlog(` Deleted locally: ${action.name}`);
|
|
24511
|
+
vlog(removalsFailed ? ` Deletion of ${action.name} incomplete; will retry next sync` : ` Deleted locally: ${action.name}`);
|
|
23502
24512
|
}
|
|
23503
24513
|
}
|
|
23504
|
-
return
|
|
24514
|
+
return {
|
|
24515
|
+
newHashes,
|
|
24516
|
+
failedDeletions: removalsFailed ? plan.deletions.map((action) => action.name) : []
|
|
24517
|
+
};
|
|
23505
24518
|
}
|
|
23506
24519
|
function makeSkillFile(name, content) {
|
|
23507
24520
|
return {
|
|
@@ -23512,17 +24525,25 @@ function makeSkillFile(name, content) {
|
|
|
23512
24525
|
};
|
|
23513
24526
|
}
|
|
23514
24527
|
async function writeSkillToAgents(skillFile, source, ctx) {
|
|
24528
|
+
let attempted = 0;
|
|
24529
|
+
let succeeded = 0;
|
|
23515
24530
|
for (const adapter2 of ctx.adapters) {
|
|
23516
24531
|
if (source === "app" && ctx.hasMcp && adapter2.mcpProvidesSkills)
|
|
23517
24532
|
continue;
|
|
23518
24533
|
for (const scope of ctx.scopes) {
|
|
23519
24534
|
if (!adapter2.supportsSkills())
|
|
23520
24535
|
continue;
|
|
24536
|
+
attempted++;
|
|
23521
24537
|
try {
|
|
23522
24538
|
await adapter2.writeSkills([skillFile], scope);
|
|
24539
|
+
succeeded++;
|
|
23523
24540
|
} catch {}
|
|
23524
24541
|
}
|
|
23525
24542
|
}
|
|
24543
|
+
return { attempted, succeeded };
|
|
24544
|
+
}
|
|
24545
|
+
function writeLanded(outcome) {
|
|
24546
|
+
return outcome.attempted === 0 || outcome.succeeded > 0;
|
|
23526
24547
|
}
|
|
23527
24548
|
function extractDescription(content) {
|
|
23528
24549
|
const match = content.match(/^---\n[\s\S]*?description:\s*(.+)\n[\s\S]*?---/);
|
|
@@ -23581,10 +24602,10 @@ function sameStringSet(a, b) {
|
|
|
23581
24602
|
}
|
|
23582
24603
|
|
|
23583
24604
|
// src/utils/sync-lock.ts
|
|
23584
|
-
import { existsSync as
|
|
23585
|
-
import { join as
|
|
23586
|
-
import { homedir as
|
|
23587
|
-
var LOCK_PATH =
|
|
24605
|
+
import { existsSync as existsSync52, mkdirSync as mkdirSync28, readFileSync as readFileSync41, unlinkSync as unlinkSync8, writeFileSync as writeFileSync30 } from "fs";
|
|
24606
|
+
import { join as join48 } from "path";
|
|
24607
|
+
import { homedir as homedir27 } from "os";
|
|
24608
|
+
var LOCK_PATH = join48(homedir27(), ".runwork", "sync.lock");
|
|
23588
24609
|
var STALE_LOCK_MS = 5 * 60 * 1000;
|
|
23589
24610
|
var DEFAULT_WAIT_MS = 30000;
|
|
23590
24611
|
var exitHandlerRegistered = false;
|
|
@@ -23604,15 +24625,15 @@ function isProcessAlive(pid) {
|
|
|
23604
24625
|
}
|
|
23605
24626
|
function readLock() {
|
|
23606
24627
|
try {
|
|
23607
|
-
return JSON.parse(
|
|
24628
|
+
return JSON.parse(readFileSync41(LOCK_PATH, "utf-8"));
|
|
23608
24629
|
} catch {
|
|
23609
24630
|
return null;
|
|
23610
24631
|
}
|
|
23611
24632
|
}
|
|
23612
24633
|
function writeLockExclusive() {
|
|
23613
24634
|
try {
|
|
23614
|
-
if (!
|
|
23615
|
-
mkdirSync28(
|
|
24635
|
+
if (!existsSync52(join48(homedir27(), ".runwork"))) {
|
|
24636
|
+
mkdirSync28(join48(homedir27(), ".runwork"), { recursive: true });
|
|
23616
24637
|
}
|
|
23617
24638
|
writeFileSync30(LOCK_PATH, JSON.stringify({ pid: process.pid, startedAt: Date.now() }), {
|
|
23618
24639
|
flag: "wx"
|
|
@@ -23681,10 +24702,10 @@ Tip: ${hint.title}`);
|
|
|
23681
24702
|
} catch {}
|
|
23682
24703
|
}
|
|
23683
24704
|
function loadSetupState(filePath) {
|
|
23684
|
-
if (!
|
|
24705
|
+
if (!existsSync53(filePath))
|
|
23685
24706
|
return null;
|
|
23686
24707
|
try {
|
|
23687
|
-
return JSON.parse(
|
|
24708
|
+
return JSON.parse(readFileSync42(filePath, "utf-8"));
|
|
23688
24709
|
} catch {
|
|
23689
24710
|
return null;
|
|
23690
24711
|
}
|
|
@@ -23705,15 +24726,15 @@ function readLocalSkills(state) {
|
|
|
23705
24726
|
if (!baseDir)
|
|
23706
24727
|
continue;
|
|
23707
24728
|
for (const skillName of state.skills) {
|
|
23708
|
-
const skillMdPath =
|
|
23709
|
-
if (
|
|
23710
|
-
results.push({ name: skillName, content:
|
|
24729
|
+
const skillMdPath = join49(baseDir, skillName, "SKILL.md");
|
|
24730
|
+
if (existsSync53(skillMdPath)) {
|
|
24731
|
+
results.push({ name: skillName, content: readFileSync42(skillMdPath, "utf-8") });
|
|
23711
24732
|
continue;
|
|
23712
24733
|
}
|
|
23713
24734
|
const filename = skillName.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
23714
|
-
const flatPath =
|
|
23715
|
-
if (
|
|
23716
|
-
results.push({ name: skillName, content:
|
|
24735
|
+
const flatPath = join49(baseDir, `${filename}.md`);
|
|
24736
|
+
if (existsSync53(flatPath)) {
|
|
24737
|
+
results.push({ name: skillName, content: readFileSync42(flatPath, "utf-8") });
|
|
23717
24738
|
}
|
|
23718
24739
|
}
|
|
23719
24740
|
if (results.length > 0)
|
|
@@ -23937,7 +24958,7 @@ This account is not a member of "${state.workspaceName || state.workspaceId}".`)
|
|
|
23937
24958
|
if (adapters.length > 0) {
|
|
23938
24959
|
console.log(` Syncing to: ${adapters.map((a) => a.name).join(", ")}`);
|
|
23939
24960
|
}
|
|
23940
|
-
const newHashes = await executeSyncPlan(plan, resolvedConflicts, {
|
|
24961
|
+
const { newHashes, failedDeletions } = await executeSyncPlan(plan, resolvedConflicts, {
|
|
23941
24962
|
client,
|
|
23942
24963
|
workspaceId: state.workspaceId,
|
|
23943
24964
|
adapters,
|
|
@@ -23967,9 +24988,9 @@ This account is not a member of "${state.workspaceName || state.workspaceId}".`)
|
|
|
23967
24988
|
persona: state.persona
|
|
23968
24989
|
});
|
|
23969
24990
|
let projectAppSkillFilter = null;
|
|
23970
|
-
if (
|
|
24991
|
+
if (existsSync53(".runwork.json")) {
|
|
23971
24992
|
try {
|
|
23972
|
-
const config = JSON.parse(
|
|
24993
|
+
const config = JSON.parse(readFileSync42(".runwork.json", "utf-8"));
|
|
23973
24994
|
if (config.appName) {
|
|
23974
24995
|
projectAppSkillFilter = config.appName.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
23975
24996
|
}
|
|
@@ -24238,7 +25259,7 @@ This account is not a member of "${state.workspaceName || state.workspaceId}".`)
|
|
|
24238
25259
|
}
|
|
24239
25260
|
for (const adapter2 of adapters) {
|
|
24240
25261
|
if (adapter2 instanceof CodexAdapter) {
|
|
24241
|
-
const runworkDir =
|
|
25262
|
+
const runworkDir = join49(homedir28(), ".runwork");
|
|
24242
25263
|
const result = adapter2.registerDesktopWorkspace(runworkDir, "Runwork");
|
|
24243
25264
|
if (result === "written") {
|
|
24244
25265
|
vlog(` [${adapter2.name}] Registered workspace in Codex desktop app`);
|
|
@@ -24324,7 +25345,10 @@ This account is not a member of "${state.workspaceName || state.workspaceId}".`)
|
|
|
24324
25345
|
for (const [name, hash] of Object.entries(newHashes)) {
|
|
24325
25346
|
mergedHashes[name] = hash;
|
|
24326
25347
|
}
|
|
25348
|
+
const retryDeletions = new Set(failedDeletions);
|
|
24327
25349
|
for (const del of plan.deletions) {
|
|
25350
|
+
if (retryDeletions.has(del.name))
|
|
25351
|
+
continue;
|
|
24328
25352
|
delete mergedHashes[del.name];
|
|
24329
25353
|
}
|
|
24330
25354
|
state.skillHashes = mergedHashes;
|
|
@@ -24395,8 +25419,8 @@ var syncCommand = new Command26("sync").description("Sync skills bidirectionally
|
|
|
24395
25419
|
verbose: !!opts.verbose,
|
|
24396
25420
|
redetect: !!opts.redetect
|
|
24397
25421
|
};
|
|
24398
|
-
const projectStatePath =
|
|
24399
|
-
const userStatePath =
|
|
25422
|
+
const projectStatePath = join49(process.cwd(), ".runwork", "setup.json");
|
|
25423
|
+
const userStatePath = join49(homedir28(), ".runwork", "setup.json");
|
|
24400
25424
|
const projectState = loadSetupState(projectStatePath);
|
|
24401
25425
|
const userState = loadSetupState(userStatePath);
|
|
24402
25426
|
if (!projectState && !userState) {
|
|
@@ -24465,7 +25489,7 @@ function toSkillFilename(name) {
|
|
|
24465
25489
|
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
24466
25490
|
}
|
|
24467
25491
|
function loadSetupStateForScope(scope) {
|
|
24468
|
-
const path4 = scope === "project" ?
|
|
25492
|
+
const path4 = scope === "project" ? join50(process.cwd(), ".runwork", "setup.json") : join50(homedir29(), ".runwork", "setup.json");
|
|
24469
25493
|
return readJsonOrNull(path4);
|
|
24470
25494
|
}
|
|
24471
25495
|
async function parkAndTeardownWorkspace(previous, scopes) {
|
|
@@ -24634,8 +25658,8 @@ Re-run without --dry-run to sync workspace data.`);
|
|
|
24634
25658
|
}
|
|
24635
25659
|
persistDefaultWorkspace(workspaceId, workspaceName);
|
|
24636
25660
|
for (const s of scopes) {
|
|
24637
|
-
const dir = s === "project" ? ".runwork" :
|
|
24638
|
-
writeJsonAtomic(
|
|
25661
|
+
const dir = s === "project" ? ".runwork" : join50(homedir29(), ".runwork");
|
|
25662
|
+
writeJsonAtomic(join50(dir, "setup.json"), state);
|
|
24639
25663
|
}
|
|
24640
25664
|
if (restored)
|
|
24641
25665
|
clearParkedState(workspaceId);
|
|
@@ -24643,7 +25667,7 @@ Re-run without --dry-run to sync workspace data.`);
|
|
|
24643
25667
|
Syncing workspace data...
|
|
24644
25668
|
`);
|
|
24645
25669
|
for (const s of scopes) {
|
|
24646
|
-
const statePath2 = s === "project" ?
|
|
25670
|
+
const statePath2 = s === "project" ? join50(process.cwd(), ".runwork", "setup.json") : join50(homedir29(), ".runwork", "setup.json");
|
|
24647
25671
|
await syncFromState(state, statePath2, credentials, {
|
|
24648
25672
|
dryRun: false,
|
|
24649
25673
|
pullOnly: true,
|
|
@@ -24663,16 +25687,16 @@ init_client();
|
|
|
24663
25687
|
import { Command as Command28 } from "commander";
|
|
24664
25688
|
|
|
24665
25689
|
// src/utils/setup-state.ts
|
|
24666
|
-
import { existsSync as
|
|
24667
|
-
import { join as
|
|
24668
|
-
import { homedir as
|
|
25690
|
+
import { existsSync as existsSync54, readFileSync as readFileSync43 } from "fs";
|
|
25691
|
+
import { join as join51 } from "path";
|
|
25692
|
+
import { homedir as homedir30 } from "os";
|
|
24669
25693
|
function loadSetupState2() {
|
|
24670
|
-
const projectPath =
|
|
24671
|
-
const userPath =
|
|
25694
|
+
const projectPath = join51(process.cwd(), ".runwork", "setup.json");
|
|
25695
|
+
const userPath = join51(homedir30(), ".runwork", "setup.json");
|
|
24672
25696
|
for (const p of [projectPath, userPath]) {
|
|
24673
|
-
if (
|
|
25697
|
+
if (existsSync54(p)) {
|
|
24674
25698
|
try {
|
|
24675
|
-
return JSON.parse(
|
|
25699
|
+
return JSON.parse(readFileSync43(p, "utf-8"));
|
|
24676
25700
|
} catch {
|
|
24677
25701
|
continue;
|
|
24678
25702
|
}
|
|
@@ -24731,14 +25755,14 @@ init_client();
|
|
|
24731
25755
|
init_types();
|
|
24732
25756
|
await init_detect();
|
|
24733
25757
|
import { Command as Command29 } from "commander";
|
|
24734
|
-
import { existsSync as
|
|
24735
|
-
import { resolve as resolve3, join as
|
|
24736
|
-
import { homedir as
|
|
25758
|
+
import { existsSync as existsSync55, readFileSync as readFileSync44 } from "fs";
|
|
25759
|
+
import { resolve as resolve3, join as join52 } from "path";
|
|
25760
|
+
import { homedir as homedir31 } from "os";
|
|
24737
25761
|
function loadSetupState3(filePath) {
|
|
24738
|
-
if (!
|
|
25762
|
+
if (!existsSync55(filePath))
|
|
24739
25763
|
return null;
|
|
24740
25764
|
try {
|
|
24741
|
-
return JSON.parse(
|
|
25765
|
+
return JSON.parse(readFileSync44(filePath, "utf-8"));
|
|
24742
25766
|
} catch {
|
|
24743
25767
|
return null;
|
|
24744
25768
|
}
|
|
@@ -24754,8 +25778,8 @@ var buildPluginCommand = new Command29("build-plugin").description("Build an ins
|
|
|
24754
25778
|
process.exit(1);
|
|
24755
25779
|
}
|
|
24756
25780
|
const credentials = requireAuth();
|
|
24757
|
-
const projectStatePath =
|
|
24758
|
-
const userStatePath =
|
|
25781
|
+
const projectStatePath = join52(process.cwd(), ".runwork", "setup.json");
|
|
25782
|
+
const userStatePath = join52(homedir31(), ".runwork", "setup.json");
|
|
24759
25783
|
const state = loadSetupState3(projectStatePath) ?? loadSetupState3(userStatePath);
|
|
24760
25784
|
if (!state) {
|
|
24761
25785
|
console.error("No setup state found. Run `runwork setup` first.");
|
|
@@ -24848,14 +25872,14 @@ init_prompt();
|
|
|
24848
25872
|
init_subprocess();
|
|
24849
25873
|
await init_detect();
|
|
24850
25874
|
import { Command as Command30 } from "commander";
|
|
24851
|
-
import { existsSync as
|
|
24852
|
-
import { join as
|
|
24853
|
-
import { homedir as
|
|
25875
|
+
import { existsSync as existsSync56, readFileSync as readFileSync45, writeFileSync as writeFileSync32, readdirSync as readdirSync17, rmSync as rmSync12, unlinkSync as unlinkSync9, lstatSync, readlinkSync } from "fs";
|
|
25876
|
+
import { join as join53, resolve as resolve4, relative as relative5, isAbsolute as isAbsolute5 } from "path";
|
|
25877
|
+
import { homedir as homedir32 } from "os";
|
|
24854
25878
|
function loadSetupState4(filePath) {
|
|
24855
|
-
if (!
|
|
25879
|
+
if (!existsSync56(filePath))
|
|
24856
25880
|
return null;
|
|
24857
25881
|
try {
|
|
24858
|
-
return JSON.parse(
|
|
25882
|
+
return JSON.parse(readFileSync45(filePath, "utf-8"));
|
|
24859
25883
|
} catch {
|
|
24860
25884
|
return null;
|
|
24861
25885
|
}
|
|
@@ -24863,22 +25887,22 @@ function loadSetupState4(filePath) {
|
|
|
24863
25887
|
var PRESERVED_ENTRIES = ["bin", "apps", "trash"];
|
|
24864
25888
|
function removeRunworkState(stateDir, opts) {
|
|
24865
25889
|
const result = { removed: [], preserved: [], errors: [] };
|
|
24866
|
-
if (!
|
|
25890
|
+
if (!existsSync56(stateDir))
|
|
24867
25891
|
return result;
|
|
24868
25892
|
const preserve = new Set(PRESERVED_ENTRIES);
|
|
24869
25893
|
if (opts.keepAuth)
|
|
24870
25894
|
preserve.add(".credentials");
|
|
24871
25895
|
let entries;
|
|
24872
25896
|
try {
|
|
24873
|
-
entries =
|
|
25897
|
+
entries = readdirSync17(stateDir);
|
|
24874
25898
|
} catch (err) {
|
|
24875
25899
|
result.errors.push(`${stateDir}: ${err instanceof Error ? err.message : err}`);
|
|
24876
25900
|
return result;
|
|
24877
25901
|
}
|
|
24878
25902
|
for (const entry of entries) {
|
|
24879
|
-
const target =
|
|
25903
|
+
const target = join53(stateDir, entry);
|
|
24880
25904
|
if (preserve.has(entry)) {
|
|
24881
|
-
if (
|
|
25905
|
+
if (existsSync56(target))
|
|
24882
25906
|
result.preserved.push(target);
|
|
24883
25907
|
continue;
|
|
24884
25908
|
}
|
|
@@ -24894,11 +25918,11 @@ function removeRunworkState(stateDir, opts) {
|
|
|
24894
25918
|
var SHELL_PROFILES = [".zshrc", ".zprofile", ".bashrc", ".bash_profile", ".profile"];
|
|
24895
25919
|
var BIN_DIR_PATTERN = /\.runwork[\\/]bin/;
|
|
24896
25920
|
function stripRunworkPathLines(file) {
|
|
24897
|
-
if (!
|
|
25921
|
+
if (!existsSync56(file))
|
|
24898
25922
|
return false;
|
|
24899
25923
|
let content;
|
|
24900
25924
|
try {
|
|
24901
|
-
content =
|
|
25925
|
+
content = readFileSync45(file, "utf-8");
|
|
24902
25926
|
} catch {
|
|
24903
25927
|
return false;
|
|
24904
25928
|
}
|
|
@@ -24927,7 +25951,7 @@ function stripRunworkPathLines(file) {
|
|
|
24927
25951
|
}
|
|
24928
25952
|
}
|
|
24929
25953
|
function cleanShellProfilePathEntries() {
|
|
24930
|
-
return SHELL_PROFILES.map((name) =>
|
|
25954
|
+
return SHELL_PROFILES.map((name) => join53(homedir32(), name)).filter(stripRunworkPathLines);
|
|
24931
25955
|
}
|
|
24932
25956
|
function cleanPowerShellProfilePathEntries() {
|
|
24933
25957
|
if (process.platform !== "win32")
|
|
@@ -24967,7 +25991,7 @@ function removeRunworkSymlink(linkPath) {
|
|
|
24967
25991
|
} catch {
|
|
24968
25992
|
return false;
|
|
24969
25993
|
}
|
|
24970
|
-
const ours = resolve4(
|
|
25994
|
+
const ours = resolve4(join53(homedir32(), ".runwork", "bin"));
|
|
24971
25995
|
const rel = relative5(ours, resolve4(target));
|
|
24972
25996
|
const insideOurs = rel === "" || !rel.startsWith("..") && !isAbsolute5(rel);
|
|
24973
25997
|
if (!insideOurs)
|
|
@@ -24980,8 +26004,8 @@ function removeRunworkSymlink(linkPath) {
|
|
|
24980
26004
|
}
|
|
24981
26005
|
}
|
|
24982
26006
|
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) => {
|
|
24983
|
-
const projectStatePath =
|
|
24984
|
-
const userStatePath =
|
|
26007
|
+
const projectStatePath = join53(process.cwd(), ".runwork", "setup.json");
|
|
26008
|
+
const userStatePath = join53(homedir32(), ".runwork", "setup.json");
|
|
24985
26009
|
const projectState = loadSetupState4(projectStatePath);
|
|
24986
26010
|
const userState = loadSetupState4(userStatePath);
|
|
24987
26011
|
if (!projectState && !userState) {
|
|
@@ -25068,8 +26092,8 @@ This will remove all Runwork configuration from your local agents:
|
|
|
25068
26092
|
}
|
|
25069
26093
|
}
|
|
25070
26094
|
}
|
|
25071
|
-
const stateDir = label === "project" ?
|
|
25072
|
-
if (
|
|
26095
|
+
const stateDir = label === "project" ? join53(process.cwd(), ".runwork") : join53(homedir32(), ".runwork");
|
|
26096
|
+
if (existsSync56(stateDir)) {
|
|
25073
26097
|
const outcome = removeRunworkState(stateDir, {
|
|
25074
26098
|
keepAuth: Boolean(opts.keepAuth) && label === "user"
|
|
25075
26099
|
});
|
|
@@ -25099,7 +26123,7 @@ This will remove all Runwork configuration from your local agents:
|
|
|
25099
26123
|
console.log(` - ${file}`);
|
|
25100
26124
|
}
|
|
25101
26125
|
const removedLinks = [
|
|
25102
|
-
|
|
26126
|
+
join53(homedir32(), ".local", "bin", "runwork"),
|
|
25103
26127
|
"/usr/local/bin/runwork"
|
|
25104
26128
|
].filter(removeRunworkSymlink);
|
|
25105
26129
|
if (removedLinks.length > 0) {
|
|
@@ -25111,7 +26135,7 @@ This will remove all Runwork configuration from your local agents:
|
|
|
25111
26135
|
if (process.platform === "win32") {
|
|
25112
26136
|
console.log("");
|
|
25113
26137
|
console.log(" Still on your PATH (remove by hand if you want it gone):");
|
|
25114
|
-
console.log(` ${
|
|
26138
|
+
console.log(` ${join53(homedir32(), ".runwork", "bin")} in your user PATH`);
|
|
25115
26139
|
}
|
|
25116
26140
|
console.log("");
|
|
25117
26141
|
if (errors > 0) {
|
|
@@ -25237,7 +26261,7 @@ var membersCommand = new Command32("members").description("List workspace member
|
|
|
25237
26261
|
init_store();
|
|
25238
26262
|
init_client();
|
|
25239
26263
|
import { Command as Command33 } from "commander";
|
|
25240
|
-
import { readFileSync as
|
|
26264
|
+
import { readFileSync as readFileSync46 } from "fs";
|
|
25241
26265
|
function normalizeApiPath(rawPath, baseUrl) {
|
|
25242
26266
|
if (/^https?:\/\//i.test(rawPath)) {
|
|
25243
26267
|
const target = new URL(rawPath);
|
|
@@ -25270,7 +26294,7 @@ to be read or pasted manually. Prefer a dedicated command when one exists
|
|
|
25270
26294
|
let curlStr = opts.curl;
|
|
25271
26295
|
if (opts.curlFile) {
|
|
25272
26296
|
try {
|
|
25273
|
-
curlStr =
|
|
26297
|
+
curlStr = readFileSync46(opts.curlFile, "utf-8");
|
|
25274
26298
|
} catch (err) {
|
|
25275
26299
|
console.error(`Could not read --curl-file: ${err instanceof Error ? err.message : err}`);
|
|
25276
26300
|
process.exit(1);
|
|
@@ -25290,7 +26314,7 @@ to be read or pasted manually. Prefer a dedicated command when one exists
|
|
|
25290
26314
|
let raw = opts.body;
|
|
25291
26315
|
if (raw.startsWith("@")) {
|
|
25292
26316
|
try {
|
|
25293
|
-
raw =
|
|
26317
|
+
raw = readFileSync46(raw.slice(1), "utf-8");
|
|
25294
26318
|
} catch (err) {
|
|
25295
26319
|
console.error(`Could not read body file: ${err instanceof Error ? err.message : err}`);
|
|
25296
26320
|
process.exit(1);
|
|
@@ -25344,9 +26368,9 @@ init_preflight();
|
|
|
25344
26368
|
init_credentials();
|
|
25345
26369
|
await init_detect();
|
|
25346
26370
|
import { parse as parse2 } from "smol-toml";
|
|
25347
|
-
import { existsSync as
|
|
25348
|
-
import { join as
|
|
25349
|
-
import { homedir as
|
|
26371
|
+
import { existsSync as existsSync57, readFileSync as readFileSync47 } from "fs";
|
|
26372
|
+
import { join as join54, sep as sep4 } from "path";
|
|
26373
|
+
import { homedir as homedir33, platform as osPlatform2, arch as osArch } from "os";
|
|
25350
26374
|
var BASE_URL2 = process.env.RUNWORK_DOWNLOAD_BASE_URL || "https://runwork.ai";
|
|
25351
26375
|
var LATEST_JSON_URL2 = `${BASE_URL2}/cli/latest.json`;
|
|
25352
26376
|
function detectPlatform() {
|
|
@@ -25374,10 +26398,10 @@ function buildContext() {
|
|
|
25374
26398
|
const credentials = getCredentials();
|
|
25375
26399
|
const client = credentials ? new ApiClient(credentials) : null;
|
|
25376
26400
|
let config = null;
|
|
25377
|
-
const configPath =
|
|
25378
|
-
if (
|
|
26401
|
+
const configPath = join54(process.cwd(), ".runwork.json");
|
|
26402
|
+
if (existsSync57(configPath)) {
|
|
25379
26403
|
try {
|
|
25380
|
-
config = JSON.parse(
|
|
26404
|
+
config = JSON.parse(readFileSync47(configPath, "utf-8"));
|
|
25381
26405
|
} catch {}
|
|
25382
26406
|
}
|
|
25383
26407
|
return { credentials, client, config, cwd: process.cwd() };
|
|
@@ -25431,8 +26455,8 @@ async function checkCliVersion() {
|
|
|
25431
26455
|
};
|
|
25432
26456
|
}
|
|
25433
26457
|
async function checkCliArtifactReachable() {
|
|
25434
|
-
const
|
|
25435
|
-
if (!
|
|
26458
|
+
const platform9 = detectPlatform();
|
|
26459
|
+
if (!platform9.key) {
|
|
25436
26460
|
return {
|
|
25437
26461
|
name: "cli-artifact",
|
|
25438
26462
|
status: "skip",
|
|
@@ -25448,12 +26472,12 @@ async function checkCliArtifactReachable() {
|
|
|
25448
26472
|
fix: "check network / outbound access to runwork.ai"
|
|
25449
26473
|
};
|
|
25450
26474
|
}
|
|
25451
|
-
const entry = manifest.artifacts?.[
|
|
26475
|
+
const entry = manifest.artifacts?.[platform9.key];
|
|
25452
26476
|
if (!entry?.path) {
|
|
25453
26477
|
return {
|
|
25454
26478
|
name: "cli-artifact",
|
|
25455
26479
|
status: "fail",
|
|
25456
|
-
message: `manifest has no artifact for ${
|
|
26480
|
+
message: `manifest has no artifact for ${platform9.key}`
|
|
25457
26481
|
};
|
|
25458
26482
|
}
|
|
25459
26483
|
const artifactUrl = `${BASE_URL2}${entry.path}`;
|
|
@@ -25466,7 +26490,7 @@ async function checkCliArtifactReachable() {
|
|
|
25466
26490
|
message: `${artifactUrl} returned HTTP ${response.status}`
|
|
25467
26491
|
};
|
|
25468
26492
|
}
|
|
25469
|
-
return { name: "cli-artifact", status: "pass", message: `${
|
|
26493
|
+
return { name: "cli-artifact", status: "pass", message: `${platform9.key} reachable` };
|
|
25470
26494
|
} catch (err) {
|
|
25471
26495
|
const msg = err instanceof Error ? err.message : String(err);
|
|
25472
26496
|
return {
|
|
@@ -25478,9 +26502,9 @@ async function checkCliArtifactReachable() {
|
|
|
25478
26502
|
}
|
|
25479
26503
|
async function checkCliInstallLocation() {
|
|
25480
26504
|
const isWindows2 = osPlatform2() === "win32";
|
|
25481
|
-
const
|
|
25482
|
-
const canonicalDir =
|
|
25483
|
-
const canonicalBinary = isWindows2 ?
|
|
26505
|
+
const home2 = homedir33();
|
|
26506
|
+
const canonicalDir = join54(home2, ".runwork", "bin");
|
|
26507
|
+
const canonicalBinary = isWindows2 ? join54(canonicalDir, "runwork.exe") : join54(canonicalDir, "runwork");
|
|
25484
26508
|
const candidates = [process.execPath, process.argv[1] || ""].filter(Boolean);
|
|
25485
26509
|
const runsFromCanonical = candidates.some((p) => normalizePath(p) === normalizePath(canonicalBinary));
|
|
25486
26510
|
if (runsFromCanonical) {
|
|
@@ -25490,7 +26514,7 @@ async function checkCliInstallLocation() {
|
|
|
25490
26514
|
message: `canonical (${canonicalBinary})`
|
|
25491
26515
|
};
|
|
25492
26516
|
}
|
|
25493
|
-
if (
|
|
26517
|
+
if (existsSync57(canonicalBinary)) {
|
|
25494
26518
|
return {
|
|
25495
26519
|
name: "cli-install-location",
|
|
25496
26520
|
status: "warn",
|
|
@@ -25623,8 +26647,8 @@ async function checkGitCredentialHelper(ctx) {
|
|
|
25623
26647
|
};
|
|
25624
26648
|
}
|
|
25625
26649
|
async function checkProjectConfig(ctx) {
|
|
25626
|
-
const configPath =
|
|
25627
|
-
if (!
|
|
26650
|
+
const configPath = join54(ctx.cwd, ".runwork.json");
|
|
26651
|
+
if (!existsSync57(configPath)) {
|
|
25628
26652
|
if (!ctx.credentials) {
|
|
25629
26653
|
return { name: "project-config", status: "skip", message: "no project (not logged in)" };
|
|
25630
26654
|
}
|
|
@@ -25686,7 +26710,7 @@ async function checkGitRemote(ctx) {
|
|
|
25686
26710
|
if (!ctx.config) {
|
|
25687
26711
|
return { name: "git-remote", status: "skip", message: "skipped (no project)" };
|
|
25688
26712
|
}
|
|
25689
|
-
if (!
|
|
26713
|
+
if (!existsSync57(join54(ctx.cwd, ".git"))) {
|
|
25690
26714
|
return {
|
|
25691
26715
|
name: "git-remote",
|
|
25692
26716
|
status: "fail",
|
|
@@ -25740,12 +26764,12 @@ async function checkDeployFreshness(ctx) {
|
|
|
25740
26764
|
return { name: "deploy-freshness", status: "skip", message: "local HEAD unknown" };
|
|
25741
26765
|
}
|
|
25742
26766
|
function loadSetupState5() {
|
|
25743
|
-
const projectPath =
|
|
25744
|
-
const userPath =
|
|
26767
|
+
const projectPath = join54(process.cwd(), ".runwork", "setup.json");
|
|
26768
|
+
const userPath = join54(homedir33(), ".runwork", "setup.json");
|
|
25745
26769
|
for (const p of [projectPath, userPath]) {
|
|
25746
|
-
if (
|
|
26770
|
+
if (existsSync57(p)) {
|
|
25747
26771
|
try {
|
|
25748
|
-
return JSON.parse(
|
|
26772
|
+
return JSON.parse(readFileSync47(p, "utf-8"));
|
|
25749
26773
|
} catch {
|
|
25750
26774
|
continue;
|
|
25751
26775
|
}
|
|
@@ -25760,13 +26784,13 @@ async function checkCodexNetwork() {
|
|
|
25760
26784
|
if (!state || !state.configuredAgents.includes("codex")) {
|
|
25761
26785
|
return { name, status: "skip", message: "Codex not configured for Runwork" };
|
|
25762
26786
|
}
|
|
25763
|
-
const configPath =
|
|
25764
|
-
if (!
|
|
26787
|
+
const configPath = join54(homedir33(), ".codex", "config.toml");
|
|
26788
|
+
if (!existsSync57(configPath)) {
|
|
25765
26789
|
return { name, status: "skip", message: "no Codex config found" };
|
|
25766
26790
|
}
|
|
25767
26791
|
let parsed;
|
|
25768
26792
|
try {
|
|
25769
|
-
parsed = parse2(
|
|
26793
|
+
parsed = parse2(readFileSync47(configPath, "utf-8"));
|
|
25770
26794
|
} catch {
|
|
25771
26795
|
return { name, status: "warn", message: "could not parse ~/.codex/config.toml" };
|
|
25772
26796
|
}
|
|
@@ -25819,19 +26843,19 @@ async function checkCodexDesktopProject() {
|
|
|
25819
26843
|
if (!usesCodex) {
|
|
25820
26844
|
return { name, status: "skip", message: "Codex not configured for Runwork" };
|
|
25821
26845
|
}
|
|
25822
|
-
const statePath2 =
|
|
25823
|
-
if (!
|
|
26846
|
+
const statePath2 = join54(homedir33(), ".codex", ".codex-global-state.json");
|
|
26847
|
+
if (!existsSync57(statePath2)) {
|
|
25824
26848
|
return { name, status: "skip", message: "Codex desktop app not detected" };
|
|
25825
26849
|
}
|
|
25826
26850
|
let savedRoots = [];
|
|
25827
26851
|
try {
|
|
25828
|
-
const parsed = JSON.parse(
|
|
26852
|
+
const parsed = JSON.parse(readFileSync47(statePath2, "utf-8"));
|
|
25829
26853
|
const roots = parsed["electron-saved-workspace-roots"];
|
|
25830
26854
|
savedRoots = Array.isArray(roots) ? roots.filter((r) => typeof r === "string") : [];
|
|
25831
26855
|
} catch {
|
|
25832
26856
|
return { name, status: "warn", message: "could not read Codex desktop state" };
|
|
25833
26857
|
}
|
|
25834
|
-
const runworkDir =
|
|
26858
|
+
const runworkDir = join54(homedir33(), ".runwork");
|
|
25835
26859
|
if (savedRoots.includes(runworkDir)) {
|
|
25836
26860
|
return { name, status: "pass", message: "Runwork project added to Codex desktop sidebar" };
|
|
25837
26861
|
}
|
|
@@ -25879,31 +26903,35 @@ async function checkAgentSetup() {
|
|
|
25879
26903
|
details.push(`${state.configuredAgents.length} agent(s) configured`);
|
|
25880
26904
|
}
|
|
25881
26905
|
let mcpChecked = false;
|
|
26906
|
+
let mcpAllHealthy = true;
|
|
25882
26907
|
for (const slug of state.configuredAgents) {
|
|
25883
26908
|
const adapter2 = getAdapterBySlug(slug);
|
|
25884
26909
|
if (!adapter2 || !adapter2.supportsMcpScope("user"))
|
|
25885
26910
|
continue;
|
|
25886
26911
|
const mcpConfigPath = getMcpConfigPath2(slug, "user");
|
|
25887
|
-
if (mcpConfigPath &&
|
|
26912
|
+
if (mcpConfigPath && existsSync57(mcpConfigPath)) {
|
|
25888
26913
|
try {
|
|
25889
|
-
const content =
|
|
26914
|
+
const content = readFileSync47(mcpConfigPath, "utf-8");
|
|
25890
26915
|
const missingMcp = state.mcpServers.filter((name) => !content.includes(name));
|
|
25891
26916
|
if (missingMcp.length > 0) {
|
|
25892
26917
|
details.push(`${missingMcp.length} MCP server(s) missing from ${slug} config`);
|
|
25893
26918
|
upgrade("warn");
|
|
25894
|
-
|
|
25895
|
-
details.push(`${state.mcpServers.length} MCP server(s) configured`);
|
|
26919
|
+
mcpAllHealthy = false;
|
|
25896
26920
|
}
|
|
25897
26921
|
mcpChecked = true;
|
|
25898
|
-
break;
|
|
25899
26922
|
} catch {}
|
|
25900
26923
|
}
|
|
25901
26924
|
}
|
|
26925
|
+
if (mcpChecked && mcpAllHealthy && state.mcpServers.length > 0) {
|
|
26926
|
+
details.push(`${state.mcpServers.length} MCP server(s) configured`);
|
|
26927
|
+
}
|
|
25902
26928
|
if (!mcpChecked && state.mcpServers.length > 0) {
|
|
25903
26929
|
details.push("could not verify MCP servers");
|
|
25904
26930
|
upgrade("warn");
|
|
25905
26931
|
}
|
|
25906
26932
|
let skillsChecked = false;
|
|
26933
|
+
let skillsAllHealthy = true;
|
|
26934
|
+
let skillsSummaryLine = null;
|
|
25907
26935
|
for (const slug of state.configuredAgents) {
|
|
25908
26936
|
const skillsDir = getSkillsDir(slug, "user");
|
|
25909
26937
|
if (!skillsDir)
|
|
@@ -25914,19 +26942,22 @@ async function checkAgentSetup() {
|
|
|
25914
26942
|
const missingSkills = state.skills.filter((name) => {
|
|
25915
26943
|
if (isCoveredByMcp(name))
|
|
25916
26944
|
return false;
|
|
25917
|
-
const skillPath =
|
|
25918
|
-
return !
|
|
26945
|
+
const skillPath = join54(skillsDir, name, "SKILL.md");
|
|
26946
|
+
return !existsSync57(skillPath);
|
|
25919
26947
|
});
|
|
25920
26948
|
if (missingSkills.length > 0) {
|
|
25921
26949
|
details.push(`${missingSkills.length} skill(s) missing from ${slug}`);
|
|
25922
26950
|
upgrade("warn");
|
|
25923
|
-
|
|
26951
|
+
skillsAllHealthy = false;
|
|
26952
|
+
} else if (state.skills.length > 0 && !skillsSummaryLine) {
|
|
25924
26953
|
const mcpCoveredCount = state.skills.filter(isCoveredByMcp).length;
|
|
25925
26954
|
const onDiskCount = state.skills.length - mcpCoveredCount;
|
|
25926
|
-
|
|
26955
|
+
skillsSummaryLine = mcpCoveredCount > 0 ? `${state.skills.length} skill(s) installed (${onDiskCount} on disk, ${mcpCoveredCount} via MCP)` : `${state.skills.length} skill(s) installed`;
|
|
25927
26956
|
}
|
|
25928
26957
|
skillsChecked = true;
|
|
25929
|
-
|
|
26958
|
+
}
|
|
26959
|
+
if (skillsChecked && skillsAllHealthy && skillsSummaryLine) {
|
|
26960
|
+
details.push(skillsSummaryLine);
|
|
25930
26961
|
}
|
|
25931
26962
|
if (!skillsChecked && state.skills.length > 0) {
|
|
25932
26963
|
details.push("could not verify skills");
|
|
@@ -25942,28 +26973,28 @@ async function checkAgentSetup() {
|
|
|
25942
26973
|
};
|
|
25943
26974
|
}
|
|
25944
26975
|
function getMcpConfigPath2(slug, scope) {
|
|
25945
|
-
const
|
|
26976
|
+
const home2 = homedir33();
|
|
25946
26977
|
switch (slug) {
|
|
25947
26978
|
case "claude-code":
|
|
25948
|
-
return scope === "project" ?
|
|
26979
|
+
return scope === "project" ? join54(process.cwd(), ".mcp.json") : join54(home2, ".claude", "settings.json");
|
|
25949
26980
|
case "cursor":
|
|
25950
|
-
return scope === "project" ?
|
|
26981
|
+
return scope === "project" ? join54(process.cwd(), ".cursor", "mcp.json") : join54(home2, ".cursor", "mcp.json");
|
|
25951
26982
|
case "windsurf":
|
|
25952
|
-
return scope === "project" ?
|
|
26983
|
+
return scope === "project" ? join54(process.cwd(), ".windsurf", "mcp.json") : join54(home2, ".windsurf", "mcp.json");
|
|
25953
26984
|
case "codex":
|
|
25954
26985
|
case "codex-app":
|
|
25955
|
-
return scope === "user" ?
|
|
26986
|
+
return scope === "user" ? join54(home2, ".codex", "config.toml") : null;
|
|
25956
26987
|
case "gemini":
|
|
25957
|
-
return scope === "user" ?
|
|
26988
|
+
return scope === "user" ? join54(home2, ".gemini", "settings.json") : null;
|
|
25958
26989
|
default:
|
|
25959
26990
|
return null;
|
|
25960
26991
|
}
|
|
25961
26992
|
}
|
|
25962
26993
|
async function checkWorkspacePointers() {
|
|
25963
|
-
const userStatePath =
|
|
25964
|
-
const state =
|
|
26994
|
+
const userStatePath = join54(homedir33(), ".runwork", "setup.json");
|
|
26995
|
+
const state = existsSync57(userStatePath) ? (() => {
|
|
25965
26996
|
try {
|
|
25966
|
-
return JSON.parse(
|
|
26997
|
+
return JSON.parse(readFileSync47(userStatePath, "utf-8"));
|
|
25967
26998
|
} catch {
|
|
25968
26999
|
return null;
|
|
25969
27000
|
}
|
|
@@ -25993,15 +27024,15 @@ async function checkWorkspacePointers() {
|
|
|
25993
27024
|
};
|
|
25994
27025
|
}
|
|
25995
27026
|
function getSkillsDir(slug, scope) {
|
|
25996
|
-
const
|
|
27027
|
+
const home2 = homedir33();
|
|
25997
27028
|
switch (slug) {
|
|
25998
27029
|
case "claude-code":
|
|
25999
|
-
return scope === "project" ?
|
|
27030
|
+
return scope === "project" ? join54(process.cwd(), ".claude", "skills") : join54(home2, ".claude", "skills");
|
|
26000
27031
|
case "codex":
|
|
26001
27032
|
case "codex-app":
|
|
26002
|
-
return scope === "project" ?
|
|
27033
|
+
return scope === "project" ? join54(process.cwd(), ".agents", "skills") : join54(home2, ".agents", "skills");
|
|
26003
27034
|
case "gemini":
|
|
26004
|
-
return scope === "project" ?
|
|
27035
|
+
return scope === "project" ? join54(process.cwd(), ".gemini", "skills") : join54(home2, ".gemini", "skills");
|
|
26005
27036
|
default:
|
|
26006
27037
|
return null;
|
|
26007
27038
|
}
|
|
@@ -26054,8 +27085,8 @@ async function runAllChecks(options) {
|
|
|
26054
27085
|
// src/health/fix.ts
|
|
26055
27086
|
init_credentials();
|
|
26056
27087
|
init_remote();
|
|
26057
|
-
import { existsSync as
|
|
26058
|
-
import { join as
|
|
27088
|
+
import { existsSync as existsSync58 } from "fs";
|
|
27089
|
+
import { join as join55 } from "path";
|
|
26059
27090
|
async function applyDoctorFixes(ctx, failingNames) {
|
|
26060
27091
|
const failing = new Set(failingNames);
|
|
26061
27092
|
const outcomes = [];
|
|
@@ -26082,7 +27113,7 @@ async function applyDoctorFixes(ctx, failingNames) {
|
|
|
26082
27113
|
applied: false,
|
|
26083
27114
|
message: "no project config -- run inside an app directory"
|
|
26084
27115
|
});
|
|
26085
|
-
} else if (!
|
|
27116
|
+
} else if (!existsSync58(join55(ctx.cwd, ".git"))) {
|
|
26086
27117
|
outcomes.push({
|
|
26087
27118
|
name: "git-remote",
|
|
26088
27119
|
applied: false,
|
|
@@ -26101,10 +27132,10 @@ async function applyDoctorFixes(ctx, failingNames) {
|
|
|
26101
27132
|
}
|
|
26102
27133
|
|
|
26103
27134
|
// src/agents/runtime-detection.ts
|
|
26104
|
-
import { existsSync as
|
|
26105
|
-
import { homedir as
|
|
26106
|
-
import { join as
|
|
26107
|
-
var RUNWORK_SESSIONS_DIR =
|
|
27135
|
+
import { existsSync as existsSync59, readFileSync as readFileSync48, statSync as statSync12, readdirSync as readdirSync18 } from "fs";
|
|
27136
|
+
import { homedir as homedir34 } from "os";
|
|
27137
|
+
import { join as join56 } from "path";
|
|
27138
|
+
var RUNWORK_SESSIONS_DIR = join56(homedir34(), ".runwork", "sessions");
|
|
26108
27139
|
function detectCurrentAgent() {
|
|
26109
27140
|
const claudeCodeSessionId = process.env.CLAUDE_CODE_SESSION_ID;
|
|
26110
27141
|
if (claudeCodeSessionId) {
|
|
@@ -26167,11 +27198,11 @@ function detectCurrentAgent() {
|
|
|
26167
27198
|
return null;
|
|
26168
27199
|
}
|
|
26169
27200
|
function readHookSessionInfo(sessionId) {
|
|
26170
|
-
const path4 =
|
|
26171
|
-
if (!
|
|
27201
|
+
const path4 = join56(RUNWORK_SESSIONS_DIR, `${sessionId}.json`);
|
|
27202
|
+
if (!existsSync59(path4))
|
|
26172
27203
|
return null;
|
|
26173
27204
|
try {
|
|
26174
|
-
const raw =
|
|
27205
|
+
const raw = readFileSync48(path4, "utf8");
|
|
26175
27206
|
const parsed = JSON.parse(raw);
|
|
26176
27207
|
return parsed;
|
|
26177
27208
|
} catch {
|
|
@@ -26179,40 +27210,40 @@ function readHookSessionInfo(sessionId) {
|
|
|
26179
27210
|
}
|
|
26180
27211
|
}
|
|
26181
27212
|
function findClaudeCodeSessionFile(sessionId) {
|
|
26182
|
-
const root =
|
|
26183
|
-
if (!
|
|
27213
|
+
const root = join56(homedir34(), ".claude", "projects");
|
|
27214
|
+
if (!existsSync59(root))
|
|
26184
27215
|
return null;
|
|
26185
27216
|
let projectDirs;
|
|
26186
27217
|
try {
|
|
26187
|
-
projectDirs =
|
|
27218
|
+
projectDirs = readdirSync18(root);
|
|
26188
27219
|
} catch {
|
|
26189
27220
|
return null;
|
|
26190
27221
|
}
|
|
26191
27222
|
for (const dir of projectDirs) {
|
|
26192
|
-
const candidate =
|
|
26193
|
-
if (
|
|
27223
|
+
const candidate = join56(root, dir, `${sessionId}.jsonl`);
|
|
27224
|
+
if (existsSync59(candidate))
|
|
26194
27225
|
return candidate;
|
|
26195
27226
|
}
|
|
26196
27227
|
return null;
|
|
26197
27228
|
}
|
|
26198
27229
|
function findCodexRolloutFile(threadId) {
|
|
26199
|
-
const root =
|
|
26200
|
-
if (!
|
|
27230
|
+
const root = join56(homedir34(), ".codex", "sessions");
|
|
27231
|
+
if (!existsSync59(root))
|
|
26201
27232
|
return null;
|
|
26202
27233
|
const stack = [root];
|
|
26203
27234
|
while (stack.length > 0) {
|
|
26204
27235
|
const dir = stack.pop();
|
|
26205
27236
|
let entries;
|
|
26206
27237
|
try {
|
|
26207
|
-
entries =
|
|
27238
|
+
entries = readdirSync18(dir);
|
|
26208
27239
|
} catch {
|
|
26209
27240
|
continue;
|
|
26210
27241
|
}
|
|
26211
27242
|
for (const entry of entries) {
|
|
26212
|
-
const full =
|
|
27243
|
+
const full = join56(dir, entry);
|
|
26213
27244
|
let s;
|
|
26214
27245
|
try {
|
|
26215
|
-
s =
|
|
27246
|
+
s = statSync12(full);
|
|
26216
27247
|
} catch {
|
|
26217
27248
|
continue;
|
|
26218
27249
|
}
|
|
@@ -26226,30 +27257,30 @@ function findCodexRolloutFile(threadId) {
|
|
|
26226
27257
|
return null;
|
|
26227
27258
|
}
|
|
26228
27259
|
function findNewestClaudeCodeSession() {
|
|
26229
|
-
const root =
|
|
26230
|
-
if (!
|
|
27260
|
+
const root = join56(homedir34(), ".claude", "projects");
|
|
27261
|
+
if (!existsSync59(root))
|
|
26231
27262
|
return null;
|
|
26232
27263
|
let projectDirs;
|
|
26233
27264
|
try {
|
|
26234
|
-
projectDirs =
|
|
27265
|
+
projectDirs = readdirSync18(root);
|
|
26235
27266
|
} catch {
|
|
26236
27267
|
return null;
|
|
26237
27268
|
}
|
|
26238
27269
|
let best = null;
|
|
26239
27270
|
for (const dir of projectDirs) {
|
|
26240
|
-
const projectPath =
|
|
27271
|
+
const projectPath = join56(root, dir);
|
|
26241
27272
|
let files;
|
|
26242
27273
|
try {
|
|
26243
|
-
files =
|
|
27274
|
+
files = readdirSync18(projectPath);
|
|
26244
27275
|
} catch {
|
|
26245
27276
|
continue;
|
|
26246
27277
|
}
|
|
26247
27278
|
for (const file of files) {
|
|
26248
27279
|
if (!file.endsWith(".jsonl"))
|
|
26249
27280
|
continue;
|
|
26250
|
-
const full =
|
|
27281
|
+
const full = join56(projectPath, file);
|
|
26251
27282
|
try {
|
|
26252
|
-
const s =
|
|
27283
|
+
const s = statSync12(full);
|
|
26253
27284
|
if (!best || s.mtimeMs > best.mtime) {
|
|
26254
27285
|
best = {
|
|
26255
27286
|
sessionId: file.replace(/\.jsonl$/, ""),
|
|
@@ -26265,8 +27296,8 @@ function findNewestClaudeCodeSession() {
|
|
|
26265
27296
|
return best ? { sessionId: best.sessionId, path: best.path } : null;
|
|
26266
27297
|
}
|
|
26267
27298
|
function findNewestCodexRollout() {
|
|
26268
|
-
const root =
|
|
26269
|
-
if (!
|
|
27299
|
+
const root = join56(homedir34(), ".codex", "sessions");
|
|
27300
|
+
if (!existsSync59(root))
|
|
26270
27301
|
return null;
|
|
26271
27302
|
const stack = [root];
|
|
26272
27303
|
let best = null;
|
|
@@ -26274,15 +27305,15 @@ function findNewestCodexRollout() {
|
|
|
26274
27305
|
const dir = stack.pop();
|
|
26275
27306
|
let entries;
|
|
26276
27307
|
try {
|
|
26277
|
-
entries =
|
|
27308
|
+
entries = readdirSync18(dir);
|
|
26278
27309
|
} catch {
|
|
26279
27310
|
continue;
|
|
26280
27311
|
}
|
|
26281
27312
|
for (const entry of entries) {
|
|
26282
|
-
const full =
|
|
27313
|
+
const full = join56(dir, entry);
|
|
26283
27314
|
let s;
|
|
26284
27315
|
try {
|
|
26285
|
-
s =
|
|
27316
|
+
s = statSync12(full);
|
|
26286
27317
|
} catch {
|
|
26287
27318
|
continue;
|
|
26288
27319
|
}
|
|
@@ -26506,13 +27537,697 @@ var doctorCommand = new Command34("doctor").description("Check system health: au
|
|
|
26506
27537
|
}
|
|
26507
27538
|
});
|
|
26508
27539
|
|
|
27540
|
+
// src/commands/debug.ts
|
|
27541
|
+
init_colors();
|
|
27542
|
+
import { Command as Command35 } from "commander";
|
|
27543
|
+
import { readFileSync as readFileSync49 } from "fs";
|
|
27544
|
+
import { homedir as homedir36, platform as platform9, release, arch, type as osType } from "os";
|
|
27545
|
+
import { join as join59 } from "path";
|
|
27546
|
+
|
|
27547
|
+
// src/debug/capture-plan.ts
|
|
27548
|
+
init_transcript_stores();
|
|
27549
|
+
init_registry_data();
|
|
27550
|
+
var CONFIG_MAX_BYTES = 64 * 1024;
|
|
27551
|
+
var LOG_TAIL_BYTES = 64 * 1024;
|
|
27552
|
+
var CENSUS_MAX_ENTRIES = 200;
|
|
27553
|
+
var ENV_NAMES = [
|
|
27554
|
+
"PATH",
|
|
27555
|
+
"SHELL",
|
|
27556
|
+
"HOME",
|
|
27557
|
+
"USERPROFILE",
|
|
27558
|
+
"APPDATA",
|
|
27559
|
+
"LOCALAPPDATA",
|
|
27560
|
+
"XDG_CONFIG_HOME",
|
|
27561
|
+
"HTTP_PROXY",
|
|
27562
|
+
"HTTPS_PROXY",
|
|
27563
|
+
"http_proxy",
|
|
27564
|
+
"https_proxy",
|
|
27565
|
+
"NO_PROXY",
|
|
27566
|
+
"no_proxy",
|
|
27567
|
+
"NODE_EXTRA_CA_CERTS",
|
|
27568
|
+
"RUNWORK_HTTP_TRANSPORT",
|
|
27569
|
+
"RUNWORK_API_URL",
|
|
27570
|
+
"TERM_PROGRAM",
|
|
27571
|
+
"LANG"
|
|
27572
|
+
];
|
|
27573
|
+
function buildCapturePlan(input) {
|
|
27574
|
+
const sep5 = input.sep ?? (input.platform === "win32" ? "\\" : "/");
|
|
27575
|
+
const join57 = (...parts) => parts.join(sep5);
|
|
27576
|
+
const home2 = input.homeDir.replace(/[/\\]+$/, "");
|
|
27577
|
+
const rw = (...parts) => join57(home2, ".runwork", ...parts);
|
|
27578
|
+
const steps = [];
|
|
27579
|
+
steps.push({ id: "env", kind: "env", names: ENV_NAMES, note: "process environment (proxy credentials stripped)" });
|
|
27580
|
+
for (const [id, file] of [
|
|
27581
|
+
["runwork.setup", "setup.json"],
|
|
27582
|
+
["runwork.workspaces", "workspaces.json"],
|
|
27583
|
+
["runwork.reflect-state", "reflect-state.json"],
|
|
27584
|
+
["runwork.reflect-runs", "reflect-runs.json"],
|
|
27585
|
+
["runwork.telemetry-outbox", "telemetry-outbox.json"],
|
|
27586
|
+
["runwork.session-summaries-outbox", "session-summaries-outbox.json"]
|
|
27587
|
+
]) {
|
|
27588
|
+
steps.push({ id, kind: "file", path: rw(file), maxBytes: CONFIG_MAX_BYTES });
|
|
27589
|
+
}
|
|
27590
|
+
for (const [id, file] of [
|
|
27591
|
+
["runwork.conversations", "conversations.json"],
|
|
27592
|
+
["runwork.reflect-queue", "reflect-queue.json"],
|
|
27593
|
+
["runwork.insights", "insights.json"],
|
|
27594
|
+
["runwork.pattern-store", "pattern-store.json"]
|
|
27595
|
+
]) {
|
|
27596
|
+
steps.push({ id, kind: "stat", path: rw(file), note: "size and mtime only: contains conversation text" });
|
|
27597
|
+
}
|
|
27598
|
+
steps.push({ id: "runwork.dir", kind: "census", path: rw(), depth: 1, maxEntries: CENSUS_MAX_ENTRIES }, { id: "runwork.bin", kind: "census", path: rw("bin"), depth: 1, maxEntries: 50, note: "which CLI binaries are installed here" }, { id: "runwork.sessions", kind: "census", path: rw("sessions"), depth: 1, maxEntries: CENSUS_MAX_ENTRIES, note: "written by the agent hooks we install" }, { id: "runwork.log", kind: "file", path: rw("desktop-launch.log"), maxBytes: LOG_TAIL_BYTES, tail: true, note: "tail: this log has no rotation" });
|
|
27599
|
+
for (const [id, ...parts] of [
|
|
27600
|
+
["claude.settings", ".claude", "settings.json"],
|
|
27601
|
+
["claude.md", ".claude", "CLAUDE.md"],
|
|
27602
|
+
["claude.mcp", ".claude", ".mcp.json"],
|
|
27603
|
+
["codex.config", ".codex", "config.toml"],
|
|
27604
|
+
["codex.agents-md", ".codex", "AGENTS.md"],
|
|
27605
|
+
["gemini.settings", ".gemini", "settings.json"]
|
|
27606
|
+
]) {
|
|
27607
|
+
steps.push({ id, kind: "file", path: join57(home2, ...parts), maxBytes: CONFIG_MAX_BYTES });
|
|
27608
|
+
}
|
|
27609
|
+
steps.push({
|
|
27610
|
+
id: "claude.desktop-config",
|
|
27611
|
+
kind: "file",
|
|
27612
|
+
path: join57(appDataRootFor(input, join57), "Claude", "claude_desktop_config.json"),
|
|
27613
|
+
maxBytes: CONFIG_MAX_BYTES,
|
|
27614
|
+
note: "the MCP config we write for Claude Desktop, next to its session store"
|
|
27615
|
+
});
|
|
27616
|
+
steps.push({
|
|
27617
|
+
id: "codex.version",
|
|
27618
|
+
kind: "file",
|
|
27619
|
+
path: join57(home2, ".codex", "version.json"),
|
|
27620
|
+
maxBytes: 4096,
|
|
27621
|
+
note: "Codex build, for placing an unrecognised originator value"
|
|
27622
|
+
});
|
|
27623
|
+
for (const [id, ...parts] of [
|
|
27624
|
+
["claude.skills", ".claude", "skills"],
|
|
27625
|
+
["claude.plugins", ".claude", "plugins"],
|
|
27626
|
+
["agents.skills", ".agents", "skills"],
|
|
27627
|
+
["codex.skills", ".codex", "skills"]
|
|
27628
|
+
]) {
|
|
27629
|
+
steps.push({ id, kind: "census", path: join57(home2, ...parts), depth: 1, maxEntries: CENSUS_MAX_ENTRIES });
|
|
27630
|
+
}
|
|
27631
|
+
for (const store of resolveTranscriptStores({
|
|
27632
|
+
platform: input.platform,
|
|
27633
|
+
homeDir: home2,
|
|
27634
|
+
sep: sep5,
|
|
27635
|
+
appData: input.appData,
|
|
27636
|
+
localAppData: input.localAppData
|
|
27637
|
+
})) {
|
|
27638
|
+
const id = `stores.${store.def.id.replace(/\//g, ".")}`;
|
|
27639
|
+
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 } : {} });
|
|
27640
|
+
for (const parent of parentsWorthProbing(store.path, sep5)) {
|
|
27641
|
+
steps.push({ id: `${id}.parent`, kind: "census", path: parent, depth: 1, maxEntries: 50, note: "is the vendor directory there at all" });
|
|
27642
|
+
}
|
|
27643
|
+
store.altPaths.forEach((alt, i) => {
|
|
27644
|
+
steps.push({ id: `${id}.alt${i}`, kind: "stat", path: alt, note: "alternate location; a hit means the canonical path is wrong here" });
|
|
27645
|
+
});
|
|
27646
|
+
}
|
|
27647
|
+
if (input.platform === "win32") {
|
|
27648
|
+
steps.push({
|
|
27649
|
+
id: "windows.appx-packages",
|
|
27650
|
+
kind: "census",
|
|
27651
|
+
path: join57(input.localAppData ?? join57(home2, "AppData", "Local"), "Packages"),
|
|
27652
|
+
depth: 1,
|
|
27653
|
+
maxEntries: CENSUS_MAX_ENTRIES,
|
|
27654
|
+
note: "AppX package identities: an MSIX agent can virtualize its writes in here"
|
|
27655
|
+
});
|
|
27656
|
+
}
|
|
27657
|
+
for (const profile of shellProfiles(input.platform)) {
|
|
27658
|
+
steps.push({
|
|
27659
|
+
id: `shell${profile}`,
|
|
27660
|
+
kind: "stat",
|
|
27661
|
+
path: join57(home2, profile),
|
|
27662
|
+
note: "presence only: profile bodies can contain the user's own secrets"
|
|
27663
|
+
});
|
|
27664
|
+
}
|
|
27665
|
+
steps.push(...binaryResolutionSteps(input));
|
|
27666
|
+
steps.push(...agentBinaryProbes(input));
|
|
27667
|
+
if (input.cliPath) {
|
|
27668
|
+
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" });
|
|
27669
|
+
}
|
|
27670
|
+
return steps;
|
|
27671
|
+
}
|
|
27672
|
+
function parentsWorthProbing(storePath4, sep5) {
|
|
27673
|
+
const idx = storePath4.lastIndexOf(sep5);
|
|
27674
|
+
if (idx <= 0)
|
|
27675
|
+
return [];
|
|
27676
|
+
const parent = storePath4.slice(0, idx);
|
|
27677
|
+
const parentIdx = parent.lastIndexOf(sep5);
|
|
27678
|
+
if (parentIdx <= 0)
|
|
27679
|
+
return [];
|
|
27680
|
+
return [parent];
|
|
27681
|
+
}
|
|
27682
|
+
function agentBinaryProbes(input) {
|
|
27683
|
+
const finder = input.platform === "win32" ? "where.exe" : "which";
|
|
27684
|
+
const args = (binary) => input.platform === "win32" ? [binary] : ["-a", binary];
|
|
27685
|
+
const seen = new Set;
|
|
27686
|
+
const steps = [];
|
|
27687
|
+
for (const agent of getDetectableAgents()) {
|
|
27688
|
+
const binary = agent.launch?.cli;
|
|
27689
|
+
if (!binary || seen.has(binary))
|
|
27690
|
+
continue;
|
|
27691
|
+
seen.add(binary);
|
|
27692
|
+
steps.push({
|
|
27693
|
+
id: `agent-binary.${agent.slug}`,
|
|
27694
|
+
kind: "exec",
|
|
27695
|
+
command: finder,
|
|
27696
|
+
args: args(binary),
|
|
27697
|
+
note: `is ${agent.name}'s CLI on PATH, and where`
|
|
27698
|
+
});
|
|
27699
|
+
}
|
|
27700
|
+
return steps;
|
|
27701
|
+
}
|
|
27702
|
+
function appDataRootFor(input, join57) {
|
|
27703
|
+
const home2 = input.homeDir.replace(/[/\\]+$/, "");
|
|
27704
|
+
if (input.platform === "darwin")
|
|
27705
|
+
return join57(home2, "Library", "Application Support");
|
|
27706
|
+
if (input.platform === "win32")
|
|
27707
|
+
return input.appData ?? join57(home2, "AppData", "Roaming");
|
|
27708
|
+
return join57(home2, ".config");
|
|
27709
|
+
}
|
|
27710
|
+
function shellProfiles(platform9) {
|
|
27711
|
+
if (platform9 === "win32")
|
|
27712
|
+
return [];
|
|
27713
|
+
return [".zshrc", ".zprofile", ".bashrc", ".bash_profile", ".profile"];
|
|
27714
|
+
}
|
|
27715
|
+
function binaryResolutionSteps(input) {
|
|
27716
|
+
const sep5 = input.sep ?? (input.platform === "win32" ? "\\" : "/");
|
|
27717
|
+
const join57 = (...parts) => parts.join(sep5);
|
|
27718
|
+
const home2 = input.homeDir.replace(/[/\\]+$/, "");
|
|
27719
|
+
if (input.platform === "win32") {
|
|
27720
|
+
return [
|
|
27721
|
+
{ id: "binaries.where", kind: "exec", command: "where.exe", args: ["runwork"], note: "every match, not just the first" },
|
|
27722
|
+
{ id: "binaries.runwork-bin", kind: "stat", path: join57(home2, ".runwork", "bin", "runwork.exe") },
|
|
27723
|
+
{ 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" }
|
|
27724
|
+
];
|
|
27725
|
+
}
|
|
27726
|
+
return [
|
|
27727
|
+
{ id: "binaries.which", kind: "exec", command: "which", args: ["-a", "runwork"], note: "every match, not just the first" },
|
|
27728
|
+
{ id: "binaries.runwork-bin", kind: "stat", path: join57(home2, ".runwork", "bin", "runwork") },
|
|
27729
|
+
{ id: "binaries.local-bin", kind: "stat", path: join57(home2, ".local", "bin", "runwork") },
|
|
27730
|
+
...input.platform === "darwin" ? [{ id: "binaries.usr-local-bin", kind: "stat", path: "/usr/local/bin/runwork" }] : []
|
|
27731
|
+
];
|
|
27732
|
+
}
|
|
27733
|
+
|
|
27734
|
+
// src/debug/capture.ts
|
|
27735
|
+
var CAPTURE_FORMAT = 1;
|
|
27736
|
+
function summarizeBundle(jsonl) {
|
|
27737
|
+
const summary = {
|
|
27738
|
+
formatVersion: CAPTURE_FORMAT,
|
|
27739
|
+
producer: null,
|
|
27740
|
+
stepsPlanned: 0,
|
|
27741
|
+
stepsRun: 0,
|
|
27742
|
+
redactions: 0,
|
|
27743
|
+
withheld: 0,
|
|
27744
|
+
complete: false
|
|
27745
|
+
};
|
|
27746
|
+
for (const line of jsonl.split(`
|
|
27747
|
+
`)) {
|
|
27748
|
+
if (!line.trim())
|
|
27749
|
+
continue;
|
|
27750
|
+
let record;
|
|
27751
|
+
try {
|
|
27752
|
+
record = JSON.parse(line);
|
|
27753
|
+
} catch {
|
|
27754
|
+
continue;
|
|
27755
|
+
}
|
|
27756
|
+
if (record.type === "plan") {
|
|
27757
|
+
summary.formatVersion = record.format;
|
|
27758
|
+
summary.producer = record.producer;
|
|
27759
|
+
summary.stepsPlanned = record.steps.length;
|
|
27760
|
+
} else if (record.type === "step") {
|
|
27761
|
+
summary.stepsRun++;
|
|
27762
|
+
summary.redactions += record.redactions ?? 0;
|
|
27763
|
+
summary.withheld += record.withheld ?? 0;
|
|
27764
|
+
} else if (record.type === "complete") {
|
|
27765
|
+
summary.complete = true;
|
|
27766
|
+
}
|
|
27767
|
+
}
|
|
27768
|
+
return summary;
|
|
27769
|
+
}
|
|
27770
|
+
async function sha256Hex(text2) {
|
|
27771
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(text2));
|
|
27772
|
+
return [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
27773
|
+
}
|
|
27774
|
+
var NEVER_READ = [".credentials", "credentials.json", "auth.json", ".netrc", "id_rsa"];
|
|
27775
|
+
function isForbiddenPath(path4) {
|
|
27776
|
+
const name = path4.split(/[/\\]/).pop()?.toLowerCase() ?? "";
|
|
27777
|
+
return NEVER_READ.some((deny) => name === deny.toLowerCase());
|
|
27778
|
+
}
|
|
27779
|
+
var SECRET_KEY_NAMES = "token|secret|password|passwd|api[-_]?key|apikey|authorization|access[-_]?token|refresh[-_]?token|client[-_]?secret|private[-_]?key|access[-_]?key|credentials?";
|
|
27780
|
+
var SECRET_KEY_PATTERN = `[A-Za-z0-9_-]*?(?:${SECRET_KEY_NAMES})`;
|
|
27781
|
+
var QUOTED_VALUE = String.raw`"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'`;
|
|
27782
|
+
var SECRET_QUERY_PARAMS = "token|key|secret|password|api[-_]?key|apikey|access[-_]?token|sig|signature";
|
|
27783
|
+
function redactSecrets(text2) {
|
|
27784
|
+
let redactions = 0;
|
|
27785
|
+
const mark = () => {
|
|
27786
|
+
redactions++;
|
|
27787
|
+
return "<redacted>";
|
|
27788
|
+
};
|
|
27789
|
+
const out = text2.replace(new RegExp(`([?&](?:${SECRET_QUERY_PARAMS})=)[^&\\s"'\`]+`, "gi"), (_m, prefix) => `${prefix}${mark()}`).replace(/\b(Bearer\s+)[A-Za-z0-9._~+/=-]{8,}/gi, (_m, prefix) => `${prefix}${mark()}`).replace(new RegExp(`("?${SECRET_KEY_PATTERN}"?\\s*[:=]\\s*)(${QUOTED_VALUE}|[^\\s,}\\]&"']+)`, "gi"), (match, prefix, value) => {
|
|
27790
|
+
if (value.includes("<redacted>"))
|
|
27791
|
+
return match;
|
|
27792
|
+
const quote = value.startsWith('"') ? '"' : value.startsWith("'") ? "'" : "";
|
|
27793
|
+
return `${prefix}${quote}${mark()}${quote}`;
|
|
27794
|
+
});
|
|
27795
|
+
return { text: out, redactions };
|
|
27796
|
+
}
|
|
27797
|
+
var CONTENT_KEY_NAMES = "currentTitle|title|prompt|userMessages|summary|body|snippet";
|
|
27798
|
+
function redactUserContent(text2) {
|
|
27799
|
+
let withheld = 0;
|
|
27800
|
+
const out = text2.replace(new RegExp(`("?\\b(?:${CONTENT_KEY_NAMES})"?\\s*[:=]\\s*)(${QUOTED_VALUE})`, "gi"), (match, prefix, value) => {
|
|
27801
|
+
if (value === '""' || value === "''")
|
|
27802
|
+
return match;
|
|
27803
|
+
withheld++;
|
|
27804
|
+
const quote = value[0];
|
|
27805
|
+
return `${prefix}${quote}<withheld>${quote}`;
|
|
27806
|
+
});
|
|
27807
|
+
return { text: out, withheld };
|
|
27808
|
+
}
|
|
27809
|
+
function redactEnvValue(value) {
|
|
27810
|
+
if (value === null)
|
|
27811
|
+
return null;
|
|
27812
|
+
return value.replace(/(\w+:\/\/)[^/@\s]*@/g, "$1<redacted>@");
|
|
27813
|
+
}
|
|
27814
|
+
function classifyCaptureError(err) {
|
|
27815
|
+
const e = err;
|
|
27816
|
+
const code = e && typeof e === "object" && typeof e.code === "string" ? e.code : undefined;
|
|
27817
|
+
const message = e instanceof Error ? e.message : String(err);
|
|
27818
|
+
if (code === "ENOENT" || code === "ENOTDIR")
|
|
27819
|
+
return { status: "missing", detail: code };
|
|
27820
|
+
if (code === "EACCES" || code === "EPERM")
|
|
27821
|
+
return { status: "denied", detail: code };
|
|
27822
|
+
if (code === "ETIMEDOUT" || code === "TIMEOUT")
|
|
27823
|
+
return { status: "timeout", detail: code };
|
|
27824
|
+
if (code === "ESCOPE")
|
|
27825
|
+
return { status: "skipped", detail: message };
|
|
27826
|
+
return { status: "error", detail: code ? `${code}: ${message}` : message };
|
|
27827
|
+
}
|
|
27828
|
+
function stepTarget(step) {
|
|
27829
|
+
switch (step.kind) {
|
|
27830
|
+
case "file":
|
|
27831
|
+
case "census":
|
|
27832
|
+
case "stat":
|
|
27833
|
+
return step.path;
|
|
27834
|
+
case "env":
|
|
27835
|
+
return step.names.join(",");
|
|
27836
|
+
case "exec":
|
|
27837
|
+
return [step.command, ...step.args].join(" ");
|
|
27838
|
+
}
|
|
27839
|
+
}
|
|
27840
|
+
function withDeadline(work, ms) {
|
|
27841
|
+
return new Promise((resolve5, reject) => {
|
|
27842
|
+
const timer = setTimeout(() => reject(Object.assign(new Error("step deadline"), { code: "TIMEOUT" })), ms);
|
|
27843
|
+
work.then((value) => {
|
|
27844
|
+
clearTimeout(timer);
|
|
27845
|
+
resolve5(value);
|
|
27846
|
+
}, (err) => {
|
|
27847
|
+
clearTimeout(timer);
|
|
27848
|
+
reject(err);
|
|
27849
|
+
});
|
|
27850
|
+
});
|
|
27851
|
+
}
|
|
27852
|
+
async function runStep(port, step, deadlineMs) {
|
|
27853
|
+
const startedMs = port.now();
|
|
27854
|
+
const base = { type: "step", id: step.id, kind: step.kind, target: stepTarget(step) };
|
|
27855
|
+
const done = (extra) => ({ ...base, status: "ok", durationMs: port.now() - startedMs, ...extra });
|
|
27856
|
+
if ((step.kind === "file" || step.kind === "stat") && isForbiddenPath(step.path)) {
|
|
27857
|
+
return { ...base, status: "skipped", detail: "excluded by policy", durationMs: 0 };
|
|
27858
|
+
}
|
|
27859
|
+
try {
|
|
27860
|
+
switch (step.kind) {
|
|
27861
|
+
case "file": {
|
|
27862
|
+
const raw = await withDeadline(port.readText(step.path, step.maxBytes, step.tail === true), deadlineMs);
|
|
27863
|
+
const secrets = redactSecrets(raw.text);
|
|
27864
|
+
const content = redactUserContent(secrets.text);
|
|
27865
|
+
return done({
|
|
27866
|
+
text: content.text,
|
|
27867
|
+
truncated: raw.truncated,
|
|
27868
|
+
...secrets.redactions > 0 ? { redactions: secrets.redactions } : {},
|
|
27869
|
+
...content.withheld > 0 ? { withheld: content.withheld } : {}
|
|
27870
|
+
});
|
|
27871
|
+
}
|
|
27872
|
+
case "census": {
|
|
27873
|
+
const entries = await withDeadline(port.listDir(step.path, step.depth, step.maxEntries), deadlineMs);
|
|
27874
|
+
return done({ entries, entryCount: entries.length });
|
|
27875
|
+
}
|
|
27876
|
+
case "stat": {
|
|
27877
|
+
const info = await withDeadline(port.stat(step.path), deadlineMs);
|
|
27878
|
+
return done({ bytes: info.bytes, modifiedAt: info.modifiedAt });
|
|
27879
|
+
}
|
|
27880
|
+
case "env": {
|
|
27881
|
+
const raw = port.env(step.names);
|
|
27882
|
+
return done({
|
|
27883
|
+
env: Object.fromEntries(Object.entries(raw).map(([k, v]) => [k, redactEnvValue(v)]))
|
|
27884
|
+
});
|
|
27885
|
+
}
|
|
27886
|
+
case "exec": {
|
|
27887
|
+
const result = await withDeadline(port.exec(step.command, step.args), deadlineMs);
|
|
27888
|
+
const out = redactSecrets(result.stdout);
|
|
27889
|
+
const err = redactSecrets(result.stderr);
|
|
27890
|
+
const redactions = out.redactions + err.redactions;
|
|
27891
|
+
return done({
|
|
27892
|
+
text: out.text,
|
|
27893
|
+
exitCode: result.exitCode,
|
|
27894
|
+
stderr: err.text,
|
|
27895
|
+
...redactions > 0 ? { redactions } : {}
|
|
27896
|
+
});
|
|
27897
|
+
}
|
|
27898
|
+
}
|
|
27899
|
+
} catch (err) {
|
|
27900
|
+
const { status, detail } = classifyCaptureError(err);
|
|
27901
|
+
return { ...base, status, detail, durationMs: port.now() - startedMs };
|
|
27902
|
+
}
|
|
27903
|
+
}
|
|
27904
|
+
async function runCapture(port, producer, steps, opts = {}) {
|
|
27905
|
+
const deadlineMs = opts.stepDeadlineMs ?? 1e4;
|
|
27906
|
+
const startedMs = port.now();
|
|
27907
|
+
await port.append({
|
|
27908
|
+
type: "plan",
|
|
27909
|
+
format: CAPTURE_FORMAT,
|
|
27910
|
+
producer,
|
|
27911
|
+
startedAt: new Date(startedMs).toISOString(),
|
|
27912
|
+
steps: steps.map((s) => ({ id: s.id, kind: s.kind, ...s.note ? { note: s.note } : {} }))
|
|
27913
|
+
});
|
|
27914
|
+
let stepsRun = 0;
|
|
27915
|
+
for (const step of steps) {
|
|
27916
|
+
await port.append(await runStep(port, step, deadlineMs));
|
|
27917
|
+
stepsRun++;
|
|
27918
|
+
}
|
|
27919
|
+
if (opts.claims) {
|
|
27920
|
+
try {
|
|
27921
|
+
for (const claim of await opts.claims())
|
|
27922
|
+
await port.append(claim);
|
|
27923
|
+
} catch (err) {
|
|
27924
|
+
await port.append({
|
|
27925
|
+
type: "claim",
|
|
27926
|
+
id: "claims-failed",
|
|
27927
|
+
producer,
|
|
27928
|
+
value: { error: err instanceof Error ? err.message : String(err) }
|
|
27929
|
+
});
|
|
27930
|
+
}
|
|
27931
|
+
}
|
|
27932
|
+
await port.append({
|
|
27933
|
+
type: "complete",
|
|
27934
|
+
finishedAt: new Date(port.now()).toISOString(),
|
|
27935
|
+
stepsPlanned: steps.length,
|
|
27936
|
+
stepsRun,
|
|
27937
|
+
durationMs: port.now() - startedMs
|
|
27938
|
+
});
|
|
27939
|
+
return { stepsRun };
|
|
27940
|
+
}
|
|
27941
|
+
|
|
27942
|
+
// src/utils/machine-id.ts
|
|
27943
|
+
init_atomic_json();
|
|
27944
|
+
import { randomUUID } from "crypto";
|
|
27945
|
+
import { homedir as homedir35 } from "os";
|
|
27946
|
+
import { join as join57 } from "path";
|
|
27947
|
+
function machineIdPath() {
|
|
27948
|
+
return join57(homedir35(), ".runwork", "machine.json");
|
|
27949
|
+
}
|
|
27950
|
+
function isValidId(value) {
|
|
27951
|
+
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);
|
|
27952
|
+
}
|
|
27953
|
+
function getMachineId() {
|
|
27954
|
+
const path4 = machineIdPath();
|
|
27955
|
+
const existing = readJsonOrNull(path4);
|
|
27956
|
+
if (existing && isValidId(existing.id))
|
|
27957
|
+
return existing.id;
|
|
27958
|
+
const record = { id: randomUUID(), createdAt: new Date().toISOString() };
|
|
27959
|
+
try {
|
|
27960
|
+
writeJsonAtomic(path4, record);
|
|
27961
|
+
} catch {
|
|
27962
|
+
return null;
|
|
27963
|
+
}
|
|
27964
|
+
const settled = readJsonOrNull(path4);
|
|
27965
|
+
return settled && isValidId(settled.id) ? settled.id : record.id;
|
|
27966
|
+
}
|
|
27967
|
+
|
|
27968
|
+
// src/commands/debug.ts
|
|
27969
|
+
init_store();
|
|
27970
|
+
init_client();
|
|
27971
|
+
init_resolve();
|
|
27972
|
+
|
|
27973
|
+
// src/debug/node-port.ts
|
|
27974
|
+
init_subprocess();
|
|
27975
|
+
init_which();
|
|
27976
|
+
import { closeSync as closeSync6, fsyncSync, mkdirSync as mkdirSync29, openSync as openSync6, readSync as readSync4, readdirSync as readdirSync19, statSync as statSync13, writeSync } from "fs";
|
|
27977
|
+
import { dirname as dirname12, join as join58 } from "path";
|
|
27978
|
+
var EXEC_OUTPUT_MAX = 256 * 1024;
|
|
27979
|
+
var EXEC_TIMEOUT_MS = 20000;
|
|
27980
|
+
function truncate5(text2, maxBytes) {
|
|
27981
|
+
return text2.length > maxBytes ? { text: text2.slice(0, maxBytes), truncated: true } : { text: text2, truncated: false };
|
|
27982
|
+
}
|
|
27983
|
+
function entryKind(path4) {
|
|
27984
|
+
try {
|
|
27985
|
+
const s = statSync13(path4);
|
|
27986
|
+
return s.isDirectory() ? "dir" : s.isFile() ? "file" : "other";
|
|
27987
|
+
} catch {
|
|
27988
|
+
return "other";
|
|
27989
|
+
}
|
|
27990
|
+
}
|
|
27991
|
+
function createNodeCapturePort(outputPath) {
|
|
27992
|
+
mkdirSync29(dirname12(outputPath), { recursive: true });
|
|
27993
|
+
const fd = openSync6(outputPath, "w");
|
|
27994
|
+
return {
|
|
27995
|
+
close: () => closeSync6(fd),
|
|
27996
|
+
async append(record) {
|
|
27997
|
+
writeSync(fd, JSON.stringify(record) + `
|
|
27998
|
+
`);
|
|
27999
|
+
try {
|
|
28000
|
+
fsyncSync(fd);
|
|
28001
|
+
} catch {}
|
|
28002
|
+
},
|
|
28003
|
+
async listDir(path4, depth, maxEntries) {
|
|
28004
|
+
const out = [];
|
|
28005
|
+
const queue = [{ dir: path4, prefix: "", level: 0 }];
|
|
28006
|
+
let first = true;
|
|
28007
|
+
while (queue.length > 0 && out.length < maxEntries) {
|
|
28008
|
+
const { dir, prefix, level } = queue.shift();
|
|
28009
|
+
let names;
|
|
28010
|
+
try {
|
|
28011
|
+
names = readdirSync19(dir);
|
|
28012
|
+
} catch (err) {
|
|
28013
|
+
if (first)
|
|
28014
|
+
throw err;
|
|
28015
|
+
continue;
|
|
28016
|
+
} finally {
|
|
28017
|
+
first = false;
|
|
28018
|
+
}
|
|
28019
|
+
for (const name of names) {
|
|
28020
|
+
if (out.length >= maxEntries)
|
|
28021
|
+
break;
|
|
28022
|
+
const full = join58(dir, name);
|
|
28023
|
+
const kind = entryKind(full);
|
|
28024
|
+
let bytes;
|
|
28025
|
+
let modifiedAt;
|
|
28026
|
+
try {
|
|
28027
|
+
const s = statSync13(full);
|
|
28028
|
+
bytes = s.size;
|
|
28029
|
+
modifiedAt = new Date(s.mtimeMs).toISOString();
|
|
28030
|
+
} catch {}
|
|
28031
|
+
out.push({ name: prefix ? `${prefix}/${name}` : name, kind, ...bytes !== undefined ? { bytes } : {}, ...modifiedAt ? { modifiedAt } : {} });
|
|
28032
|
+
if (kind === "dir" && level + 1 < depth) {
|
|
28033
|
+
queue.push({ dir: full, prefix: prefix ? `${prefix}/${name}` : name, level: level + 1 });
|
|
28034
|
+
}
|
|
28035
|
+
}
|
|
28036
|
+
}
|
|
28037
|
+
return out;
|
|
28038
|
+
},
|
|
28039
|
+
async stat(path4) {
|
|
28040
|
+
const s = statSync13(path4);
|
|
28041
|
+
return {
|
|
28042
|
+
bytes: s.size,
|
|
28043
|
+
modifiedAt: new Date(s.mtimeMs).toISOString(),
|
|
28044
|
+
kind: s.isDirectory() ? "dir" : s.isFile() ? "file" : "other"
|
|
28045
|
+
};
|
|
28046
|
+
},
|
|
28047
|
+
async readText(path4, maxBytes, tail) {
|
|
28048
|
+
const s = statSync13(path4);
|
|
28049
|
+
const size = s.size;
|
|
28050
|
+
const length = Math.min(size, maxBytes);
|
|
28051
|
+
const start = tail && size > maxBytes ? size - maxBytes : 0;
|
|
28052
|
+
const buffer = Buffer.alloc(length);
|
|
28053
|
+
const handle = openSync6(path4, "r");
|
|
28054
|
+
try {
|
|
28055
|
+
readSync4(handle, buffer, 0, length, start);
|
|
28056
|
+
} finally {
|
|
28057
|
+
closeSync6(handle);
|
|
28058
|
+
}
|
|
28059
|
+
return { text: buffer.toString("utf-8"), truncated: size > length };
|
|
28060
|
+
},
|
|
28061
|
+
env(names) {
|
|
28062
|
+
return Object.fromEntries(names.map((n) => [n, process.env[n] ?? null]));
|
|
28063
|
+
},
|
|
28064
|
+
async exec(command, args) {
|
|
28065
|
+
const spec = toSpawnSpec(command, args);
|
|
28066
|
+
const result = spawnSync(spec.command, spec.args, {
|
|
28067
|
+
encoding: "utf-8",
|
|
28068
|
+
timeout: EXEC_TIMEOUT_MS,
|
|
28069
|
+
maxBuffer: EXEC_OUTPUT_MAX,
|
|
28070
|
+
...spec.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
28071
|
+
});
|
|
28072
|
+
if (result.error)
|
|
28073
|
+
throw result.error;
|
|
28074
|
+
return {
|
|
28075
|
+
exitCode: result.status ?? -1,
|
|
28076
|
+
stdout: truncate5(result.stdout ?? "", EXEC_OUTPUT_MAX).text,
|
|
28077
|
+
stderr: truncate5(result.stderr ?? "", 8 * 1024).text
|
|
28078
|
+
};
|
|
28079
|
+
},
|
|
28080
|
+
now: () => Date.now()
|
|
28081
|
+
};
|
|
28082
|
+
}
|
|
28083
|
+
|
|
28084
|
+
// src/commands/debug.ts
|
|
28085
|
+
init_transcript_sources();
|
|
28086
|
+
init_which();
|
|
28087
|
+
await init_detect();
|
|
28088
|
+
function defaultOutputPath(now) {
|
|
28089
|
+
const stamp = now.toISOString().replace(/[:.]/g, "-").replace("T", "_").slice(0, 19);
|
|
28090
|
+
return join59(homedir36(), ".runwork", "debug", `runwork-debug-${stamp}.jsonl`);
|
|
28091
|
+
}
|
|
28092
|
+
async function cliClaims() {
|
|
28093
|
+
const records = [];
|
|
28094
|
+
records.push({
|
|
28095
|
+
type: "claim",
|
|
28096
|
+
id: "producer.process",
|
|
28097
|
+
producer: "cli",
|
|
28098
|
+
value: {
|
|
28099
|
+
cliVersion: VERSION,
|
|
28100
|
+
execPath: process.execPath,
|
|
28101
|
+
argv0: process.argv[1] ?? null,
|
|
28102
|
+
nodeVersion: process.version,
|
|
28103
|
+
platform: platform9(),
|
|
28104
|
+
osType: osType(),
|
|
28105
|
+
release: release(),
|
|
28106
|
+
arch: arch(),
|
|
28107
|
+
cwd: process.cwd()
|
|
28108
|
+
}
|
|
28109
|
+
});
|
|
28110
|
+
records.push({
|
|
28111
|
+
type: "claim",
|
|
28112
|
+
id: "cli.path-resolution",
|
|
28113
|
+
producer: "cli",
|
|
28114
|
+
derivedFrom: ["binaries.which", "binaries.where", "env"],
|
|
28115
|
+
value: { pathResolved: whichBinary("runwork") }
|
|
28116
|
+
});
|
|
28117
|
+
const adapters = await detectAgents();
|
|
28118
|
+
records.push({
|
|
28119
|
+
type: "claim",
|
|
28120
|
+
id: "agents.detected",
|
|
28121
|
+
producer: "cli",
|
|
28122
|
+
derivedFrom: ["transcripts.claude-code", "transcripts.codex", "transcripts.gemini", "transcripts.cowork"],
|
|
28123
|
+
value: adapters.map((adapter2) => {
|
|
28124
|
+
const sources = adapter2.transcriptSources?.() ?? [];
|
|
28125
|
+
return {
|
|
28126
|
+
slug: adapter2.slug,
|
|
28127
|
+
name: adapter2.name,
|
|
28128
|
+
hasListing: typeof adapter2.listSessions === "function",
|
|
28129
|
+
hasDigests: typeof adapter2.readSessionDigests === "function",
|
|
28130
|
+
transcriptSources: sources.map((s) => s.path),
|
|
28131
|
+
readable: sources.length > 0 ? summarizeTranscriptSources(sources) : null
|
|
28132
|
+
};
|
|
28133
|
+
})
|
|
28134
|
+
});
|
|
28135
|
+
return records;
|
|
28136
|
+
}
|
|
28137
|
+
var debugCommand = new Command35("debug").description("Diagnostics for support");
|
|
28138
|
+
debugCommand.command("capture").description("Collect a diagnostic bundle to a file you can send to support").option("--out <path>", "Where to write the bundle (default: ~/.runwork/debug/)").option("--send", "Also send the bundle to Runwork support (requires sign-in)").option("--note <text>", "What went wrong, in your words. Included with --send").action(async (opts, command) => {
|
|
28139
|
+
const json = command.optsWithGlobals().json === true || !process.stdout.isTTY;
|
|
28140
|
+
const outputPath = typeof opts.out === "string" && opts.out ? opts.out : defaultOutputPath(new Date);
|
|
28141
|
+
const cliPath = whichBinary("runwork");
|
|
28142
|
+
const plan = buildCapturePlan({
|
|
28143
|
+
platform: platform9(),
|
|
28144
|
+
homeDir: homedir36(),
|
|
28145
|
+
appData: process.env.APPDATA ?? null,
|
|
28146
|
+
localAppData: process.env.LOCALAPPDATA ?? null,
|
|
28147
|
+
cliPath
|
|
28148
|
+
});
|
|
28149
|
+
if (!json) {
|
|
28150
|
+
console.log(bold(`
|
|
28151
|
+
Collecting diagnostics`));
|
|
28152
|
+
console.log(dim(` ${plan.length} checks, writing to ${outputPath}`));
|
|
28153
|
+
}
|
|
28154
|
+
const port = createNodeCapturePort(outputPath);
|
|
28155
|
+
let stepsRun = 0;
|
|
28156
|
+
try {
|
|
28157
|
+
({ stepsRun } = await runCapture(port, "cli", plan, { claims: cliClaims }));
|
|
28158
|
+
} finally {
|
|
28159
|
+
port.close();
|
|
28160
|
+
}
|
|
28161
|
+
const sent = opts.send === true ? await sendBundle(outputPath, typeof opts.note === "string" ? opts.note : undefined) : null;
|
|
28162
|
+
if (json) {
|
|
28163
|
+
jsonOut({ path: outputPath, stepsPlanned: plan.length, stepsRun, ...sent ? { sent } : {} });
|
|
28164
|
+
return;
|
|
28165
|
+
}
|
|
28166
|
+
const counted = stepsRun === plan.length ? `${stepsRun}` : `${stepsRun} of ${plan.length}`;
|
|
28167
|
+
console.log(green(`
|
|
28168
|
+
Done. ${counted} checks recorded.`));
|
|
28169
|
+
console.log(`
|
|
28170
|
+
${cyan(outputPath)}
|
|
28171
|
+
`);
|
|
28172
|
+
if (!cliPath) {
|
|
28173
|
+
console.log(yellow("Note: no `runwork` was found on PATH, so the doctor report is not included.\n"));
|
|
28174
|
+
}
|
|
28175
|
+
if (!sent) {
|
|
28176
|
+
console.log(dim("Send that file to support. It contains no credentials and no conversation text."));
|
|
28177
|
+
console.log(dim("Or re-run with --send to upload it."));
|
|
28178
|
+
return;
|
|
28179
|
+
}
|
|
28180
|
+
if (sent.ok) {
|
|
28181
|
+
console.log(green(`Sent to Runwork support (report ${sent.id}).`));
|
|
28182
|
+
console.log(dim(`It is kept until ${sent.expiresAt?.slice(0, 10)} and then deleted.`));
|
|
28183
|
+
} else {
|
|
28184
|
+
console.log(yellow(`Could not send: ${sent.error}`));
|
|
28185
|
+
console.log(dim("The file above is saved and can be sent to support by hand."));
|
|
28186
|
+
}
|
|
28187
|
+
});
|
|
28188
|
+
async function sendBundle(path4, note) {
|
|
28189
|
+
try {
|
|
28190
|
+
const content = readFileSync49(path4, "utf-8");
|
|
28191
|
+
const summary = summarizeBundle(content);
|
|
28192
|
+
const machineId = getMachineId();
|
|
28193
|
+
if (!machineId)
|
|
28194
|
+
return { ok: false, error: "could not identify this machine" };
|
|
28195
|
+
const credentials = getCredentials();
|
|
28196
|
+
if (!credentials)
|
|
28197
|
+
return { ok: false, error: "not signed in; run `runwork login`" };
|
|
28198
|
+
const api = new ApiClient(credentials);
|
|
28199
|
+
const workspace = await resolveWorkspace2(api);
|
|
28200
|
+
const result = await api.createDebugReport(workspace.workspaceId, {
|
|
28201
|
+
machineId,
|
|
28202
|
+
producer: "cli",
|
|
28203
|
+
content,
|
|
28204
|
+
sha256: await sha256Hex(content),
|
|
28205
|
+
formatVersion: summary.formatVersion,
|
|
28206
|
+
...note ? { note } : {},
|
|
28207
|
+
context: {
|
|
28208
|
+
cliVersion: VERSION,
|
|
28209
|
+
platform: platform9(),
|
|
28210
|
+
release: release(),
|
|
28211
|
+
stepsPlanned: summary.stepsPlanned,
|
|
28212
|
+
stepsRun: summary.stepsRun,
|
|
28213
|
+
redactions: summary.redactions,
|
|
28214
|
+
withheld: summary.withheld,
|
|
28215
|
+
complete: summary.complete
|
|
28216
|
+
}
|
|
28217
|
+
});
|
|
28218
|
+
return { ok: true, id: result.id, expiresAt: result.expiresAt };
|
|
28219
|
+
} catch (err) {
|
|
28220
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
28221
|
+
}
|
|
28222
|
+
}
|
|
28223
|
+
|
|
26509
28224
|
// src/commands/share-convo.ts
|
|
26510
28225
|
init_store();
|
|
26511
28226
|
init_client();
|
|
26512
28227
|
init_resolve();
|
|
26513
|
-
import { Command as
|
|
26514
|
-
import { readFileSync as
|
|
26515
|
-
import { join as
|
|
28228
|
+
import { Command as Command36 } from "commander";
|
|
28229
|
+
import { readFileSync as readFileSync50, writeFileSync as writeFileSync33, existsSync as existsSync60, mkdtempSync as mkdtempSync4 } from "fs";
|
|
28230
|
+
import { join as join60 } from "path";
|
|
26516
28231
|
import { tmpdir as tmpdir4 } from "os";
|
|
26517
28232
|
import { createHash as createHash6 } from "crypto";
|
|
26518
28233
|
|
|
@@ -26634,13 +28349,13 @@ function resolveLocalSessionShare(opts, conversation) {
|
|
|
26634
28349
|
process.exit(1);
|
|
26635
28350
|
}
|
|
26636
28351
|
const title = opts.title ?? conversation.title ?? conversation.project;
|
|
26637
|
-
const markdown = renderTranscriptMarkdown(
|
|
28352
|
+
const markdown = renderTranscriptMarkdown(readFileSync50(conversation.transcriptPath, "utf8"), family, title);
|
|
26638
28353
|
if (!markdown) {
|
|
26639
28354
|
console.error("Error: this conversation has no shareable content.");
|
|
26640
28355
|
process.exit(1);
|
|
26641
28356
|
}
|
|
26642
|
-
const tempDir = mkdtempSync4(
|
|
26643
|
-
const transcriptFile =
|
|
28357
|
+
const tempDir = mkdtempSync4(join60(tmpdir4(), "runwork-share-"));
|
|
28358
|
+
const transcriptFile = join60(tempDir, "transcript.md");
|
|
26644
28359
|
writeFileSync33(transcriptFile, markdown);
|
|
26645
28360
|
opts.transcriptFile = transcriptFile;
|
|
26646
28361
|
opts.nativeFile = opts.nativeFile ?? conversation.transcriptPath;
|
|
@@ -26657,7 +28372,7 @@ function nativeBundleFormatForAgent(slug) {
|
|
|
26657
28372
|
return "codex-rollout";
|
|
26658
28373
|
return null;
|
|
26659
28374
|
}
|
|
26660
|
-
function
|
|
28375
|
+
function sha256Hex2(content) {
|
|
26661
28376
|
return createHash6("sha256").update(content, "utf8").digest("hex");
|
|
26662
28377
|
}
|
|
26663
28378
|
function utf8ByteLength(content) {
|
|
@@ -26678,7 +28393,7 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
|
|
|
26678
28393
|
console.error("Error: --transcript-file is required. Pass the path to the LLM-emitted markdown transcript.");
|
|
26679
28394
|
process.exit(1);
|
|
26680
28395
|
}
|
|
26681
|
-
if (!
|
|
28396
|
+
if (!existsSync60(opts.transcriptFile)) {
|
|
26682
28397
|
console.error(`Error: transcript file does not exist: ${opts.transcriptFile}`);
|
|
26683
28398
|
process.exit(1);
|
|
26684
28399
|
}
|
|
@@ -26699,37 +28414,37 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
|
|
|
26699
28414
|
const credentials = requireAuth();
|
|
26700
28415
|
const client = new ApiClient(credentials);
|
|
26701
28416
|
const { workspaceId } = await resolveWorkspace2(client, { workspace: opts.workspace });
|
|
26702
|
-
const transcriptContent =
|
|
28417
|
+
const transcriptContent = readFileSync50(opts.transcriptFile, "utf8");
|
|
26703
28418
|
const bundles = [
|
|
26704
28419
|
{
|
|
26705
28420
|
format: "transcript",
|
|
26706
28421
|
content: transcriptContent,
|
|
26707
28422
|
sizeBytes: utf8ByteLength(transcriptContent),
|
|
26708
|
-
sha256:
|
|
28423
|
+
sha256: sha256Hex2(transcriptContent)
|
|
26709
28424
|
}
|
|
26710
28425
|
];
|
|
26711
28426
|
const detected = detectCurrentAgent();
|
|
26712
28427
|
const sourceAgent = opts.sourceAgent ?? detected?.slug ?? "generic";
|
|
26713
28428
|
let nativeFilePath = null;
|
|
26714
28429
|
if (opts.nativeFile) {
|
|
26715
|
-
if (!
|
|
28430
|
+
if (!existsSync60(opts.nativeFile)) {
|
|
26716
28431
|
console.error(`Error: --native-file path does not exist: ${opts.nativeFile}`);
|
|
26717
28432
|
process.exit(1);
|
|
26718
28433
|
}
|
|
26719
28434
|
nativeFilePath = opts.nativeFile;
|
|
26720
|
-
} else if (detected?.sessionFilePath &&
|
|
28435
|
+
} else if (detected?.sessionFilePath && existsSync60(detected.sessionFilePath)) {
|
|
26721
28436
|
nativeFilePath = detected.sessionFilePath;
|
|
26722
28437
|
}
|
|
26723
28438
|
if (nativeFilePath) {
|
|
26724
28439
|
const nativeFormat = nativeBundleFormatForAgent(sourceAgent);
|
|
26725
28440
|
if (nativeFormat) {
|
|
26726
28441
|
try {
|
|
26727
|
-
const content =
|
|
28442
|
+
const content = readFileSync50(nativeFilePath, "utf8");
|
|
26728
28443
|
bundles.push({
|
|
26729
28444
|
format: nativeFormat,
|
|
26730
28445
|
content,
|
|
26731
28446
|
sizeBytes: utf8ByteLength(content),
|
|
26732
|
-
sha256:
|
|
28447
|
+
sha256: sha256Hex2(content)
|
|
26733
28448
|
});
|
|
26734
28449
|
} catch (err) {
|
|
26735
28450
|
console.error(`Warning: could not read native file ${nativeFilePath}: ${err instanceof Error ? err.message : err}`);
|
|
@@ -26740,7 +28455,7 @@ async function runShareConvo(opts, command, isPersonalAlias = false) {
|
|
|
26740
28455
|
let metadata = {};
|
|
26741
28456
|
if (opts.metadataFile) {
|
|
26742
28457
|
try {
|
|
26743
|
-
metadata = JSON.parse(
|
|
28458
|
+
metadata = JSON.parse(readFileSync50(opts.metadataFile, "utf8"));
|
|
26744
28459
|
} catch (err) {
|
|
26745
28460
|
console.error(`Error: --metadata-file is not valid JSON: ${err instanceof Error ? err.message : err}`);
|
|
26746
28461
|
process.exit(1);
|
|
@@ -26795,18 +28510,18 @@ Skipped: ${result.skipped.map((s) => `${s.identifier} (${s.reason})`).join(", ")
|
|
|
26795
28510
|
process.exit(1);
|
|
26796
28511
|
}
|
|
26797
28512
|
}
|
|
26798
|
-
var shareConvoCommand = new
|
|
28513
|
+
var shareConvoCommand = new Command36("share-convo").description("Share the current AI conversation with a teammate").option("--to <email>", "Recipient email (repeatable)", (value, prev = []) => [...prev, value], []).option("--transcript-file <path>", "Path to the LLM-emitted markdown transcript (required unless --session)").option("--session <key>", "Share a LOCAL conversation by registry key (transcript rendered mechanically)").option("--native-file <path>", "Path to the native session file (optional; auto-detected from env vars otherwise)").option("--source-agent <slug>", "Override host-agent detection (e.g. claude-code, codex, claude-desktop)").option("--title <string>", "Short title for the conversation (required)").option("--note <string>", "Optional personal note to recipients").option("--ttl-days <n>", "Days until expiration (1-30, default 7)").option("--metadata-json <json>", "Inline JSON object with workMode, openQuestions, suggestedNextStep, etc.").option("--metadata-file <path>", "Path to a JSON file with the same metadata fields").option("--workspace <name-or-id>", "Workspace name or ID").action((opts, command) => runShareConvo(opts, command, false));
|
|
26799
28514
|
|
|
26800
28515
|
// src/commands/save-convo.ts
|
|
26801
|
-
import { Command as
|
|
26802
|
-
var saveConvoCommand = new
|
|
28516
|
+
import { Command as Command37 } from "commander";
|
|
28517
|
+
var saveConvoCommand = new Command37("save-convo").description("Save the current AI conversation as a personal checkpoint").option("--transcript-file <path>", "Path to the LLM-emitted markdown transcript (required)").option("--native-file <path>", "Path to the native session file (optional; auto-detected from env vars)").option("--source-agent <slug>", "Override host-agent detection").option("--title <string>", "Short title for the conversation (required)").option("--note <string>", "Optional note to your future self").option("--ttl-days <n>", "Days until expiration (1-30, default 7)").option("--metadata-json <json>", "Inline JSON object with workMode, openQuestions, etc.").option("--metadata-file <path>", "Path to a JSON file with metadata fields").option("--workspace <name-or-id>", "Workspace name or ID").action((opts, command) => runShareConvo({ ...opts, personal: true }, command, true));
|
|
26803
28518
|
|
|
26804
28519
|
// src/commands/inbox.ts
|
|
26805
28520
|
init_store();
|
|
26806
28521
|
init_client();
|
|
26807
28522
|
init_resolve();
|
|
26808
|
-
import { Command as
|
|
26809
|
-
var inboxCommand = new
|
|
28523
|
+
import { Command as Command38 } from "commander";
|
|
28524
|
+
var inboxCommand = new Command38("inbox").description("List shared conversations visible to you").option("--filter <scope>", "Filter: all | received | sent | saved", "all").option("--limit <n>", "Max rows to return", "50").option("--workspace <name-or-id>", "Workspace name or ID").action(async (opts, command) => {
|
|
26810
28525
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
26811
28526
|
const scope = opts.filter === "received" || opts.filter === "sent" || opts.filter === "saved" ? opts.filter : "all";
|
|
26812
28527
|
const limit = opts.limit ? parseInt(opts.limit, 10) : 50;
|
|
@@ -26848,10 +28563,10 @@ init_store();
|
|
|
26848
28563
|
init_client();
|
|
26849
28564
|
init_resolve();
|
|
26850
28565
|
init_registry_data();
|
|
26851
|
-
import { Command as
|
|
26852
|
-
import { writeFileSync as writeFileSync34, mkdirSync as
|
|
26853
|
-
import { homedir as
|
|
26854
|
-
import { join as
|
|
28566
|
+
import { Command as Command39 } from "commander";
|
|
28567
|
+
import { writeFileSync as writeFileSync34, mkdirSync as mkdirSync30, realpathSync } from "fs";
|
|
28568
|
+
import { homedir as homedir37 } from "os";
|
|
28569
|
+
import { join as join61 } from "path";
|
|
26855
28570
|
import { spawn as spawn5 } from "child_process";
|
|
26856
28571
|
init_registry();
|
|
26857
28572
|
init_which();
|
|
@@ -26890,9 +28605,9 @@ function extractCodexUuid(rolloutContent) {
|
|
|
26890
28605
|
}
|
|
26891
28606
|
function placeClaudeJsonl(uuid, content, recipientCwd) {
|
|
26892
28607
|
const encoded = encodeClaudeCodeCwd(recipientCwd);
|
|
26893
|
-
const projectDir =
|
|
26894
|
-
|
|
26895
|
-
const placedAt =
|
|
28608
|
+
const projectDir = join61(homedir37(), ".claude", "projects", encoded);
|
|
28609
|
+
mkdirSync30(projectDir, { recursive: true });
|
|
28610
|
+
const placedAt = join61(projectDir, `${uuid}.jsonl`);
|
|
26896
28611
|
writeFileSync34(placedAt, content);
|
|
26897
28612
|
return { placedAt, runFromCwd: recipientCwd };
|
|
26898
28613
|
}
|
|
@@ -26901,10 +28616,10 @@ function placeCodexRollout(uuid, content) {
|
|
|
26901
28616
|
const yyyy = String(now.getUTCFullYear());
|
|
26902
28617
|
const mm = String(now.getUTCMonth() + 1).padStart(2, "0");
|
|
26903
28618
|
const dd = String(now.getUTCDate()).padStart(2, "0");
|
|
26904
|
-
const dir =
|
|
26905
|
-
|
|
28619
|
+
const dir = join61(homedir37(), ".codex", "sessions", yyyy, mm, dd);
|
|
28620
|
+
mkdirSync30(dir, { recursive: true });
|
|
26906
28621
|
const ts = now.toISOString().replace(/\.\d+Z$/, "").replace(/:/g, "-");
|
|
26907
|
-
const placedAt =
|
|
28622
|
+
const placedAt = join61(dir, `rollout-${ts}-${uuid}.jsonl`);
|
|
26908
28623
|
writeFileSync34(placedAt, content);
|
|
26909
28624
|
return { placedAt };
|
|
26910
28625
|
}
|
|
@@ -26924,7 +28639,15 @@ function isAgentInstalled(agent) {
|
|
|
26924
28639
|
}
|
|
26925
28640
|
return false;
|
|
26926
28641
|
}
|
|
26927
|
-
|
|
28642
|
+
function buildResumeCommand(template, uuid, resolvedCli, cliName) {
|
|
28643
|
+
const argv = template.replace(/\{uuid\}/g, uuid).split(" ").filter(Boolean);
|
|
28644
|
+
if (resolvedCli && cliName && argv[0] === cliName) {
|
|
28645
|
+
argv[0] = resolvedCli;
|
|
28646
|
+
}
|
|
28647
|
+
const display = [argv[0]?.includes(" ") ? `"${argv[0]}"` : argv[0], ...argv.slice(1)].filter((part) => Boolean(part)).join(" ");
|
|
28648
|
+
return { argv, display };
|
|
28649
|
+
}
|
|
28650
|
+
var resumeCommand2 = new Command39("resume").description("Resume a shared conversation locally in your agent of choice").argument("<share-id>", "The share ID (sc_*) returned by share-convo or save-convo").option("--agent <slug>", "Override target agent (e.g. claude-code, codex)").option("--into <path>", "Override target cwd (defaults to current $PWD)").option("--dry-run", "Print the resume command instead of executing it").option("--pick", "Show interactive picker (requires TTY) - not yet implemented").option("--workspace <name-or-id>", "Workspace name or ID").action(async (shareId, opts, command) => {
|
|
26928
28651
|
const useJson = shouldOutputJson(command.optsWithGlobals().json);
|
|
26929
28652
|
const credentials = requireAuth();
|
|
26930
28653
|
const client = new ApiClient(credentials);
|
|
@@ -27018,12 +28741,8 @@ Bundle placed at: ${placement.placedAt}`);
|
|
|
27018
28741
|
return;
|
|
27019
28742
|
}
|
|
27020
28743
|
if (cap2.mode === "cli-resume") {
|
|
27021
|
-
|
|
27022
|
-
const
|
|
27023
|
-
const cliName = getAgent(target.slug)?.launch?.cli;
|
|
27024
|
-
if (resolvedCli && cliName && resolvedCli !== cliName && cmd.startsWith(`${cliName} `)) {
|
|
27025
|
-
cmd = `"${resolvedCli}" ${cmd.slice(cliName.length + 1)}`;
|
|
27026
|
-
}
|
|
28744
|
+
const { argv, display } = buildResumeCommand(cap2.cliResumeCommand ?? "", nativeUuid, resolveAgentCliCommand(target.slug), getAgent(target.slug)?.launch?.cli);
|
|
28745
|
+
const cmd = display;
|
|
27027
28746
|
const detected = detectCurrentAgent();
|
|
27028
28747
|
const insideSameAgent = detected && detected.slug === target.slug;
|
|
27029
28748
|
const shouldPrintOnly = opts.dryRun || insideSameAgent;
|
|
@@ -27055,10 +28774,11 @@ Or ask the assistant to continue the conversation in THIS session by ` + `fetchi
|
|
|
27055
28774
|
}
|
|
27056
28775
|
return;
|
|
27057
28776
|
}
|
|
27058
|
-
const
|
|
27059
|
-
const child = spawn5(
|
|
28777
|
+
const spec = toSpawnSpec(argv[0], argv.slice(1));
|
|
28778
|
+
const child = spawn5(spec.command, spec.args, {
|
|
27060
28779
|
cwd: placement.runFromCwd ?? recipientCwd,
|
|
27061
|
-
stdio: "inherit"
|
|
28780
|
+
stdio: "inherit",
|
|
28781
|
+
...spec.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
27062
28782
|
});
|
|
27063
28783
|
child.on("exit", (code) => {
|
|
27064
28784
|
process.exit(code ?? 0);
|
|
@@ -27154,7 +28874,7 @@ process.on("uncaughtException", (err) => {
|
|
|
27154
28874
|
console.error(`Uncaught exception: ${formatError(err)}`);
|
|
27155
28875
|
process.exit(1);
|
|
27156
28876
|
});
|
|
27157
|
-
var program = new
|
|
28877
|
+
var program = new Command40;
|
|
27158
28878
|
program.name("runwork").description("Runwork CLI - local development for Runwork apps").version(VERSION).option("--json", "Output as JSON (auto-enabled when stdout is not a TTY)");
|
|
27159
28879
|
program.addCommand(infoCommand);
|
|
27160
28880
|
program.addCommand(loginCommand);
|
|
@@ -27187,6 +28907,7 @@ program.addCommand(appsCommand);
|
|
|
27187
28907
|
program.addCommand(membersCommand);
|
|
27188
28908
|
program.addCommand(apiCommand);
|
|
27189
28909
|
program.addCommand(doctorCommand);
|
|
28910
|
+
program.addCommand(debugCommand);
|
|
27190
28911
|
program.addCommand(shareConvoCommand);
|
|
27191
28912
|
program.addCommand(saveConvoCommand);
|
|
27192
28913
|
program.addCommand(inboxCommand);
|