replicas-engine 0.1.667 → 0.1.669
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/README.md +4 -4
- package/dist/src/app-server-process-GBLLP2RH.js +10 -0
- package/dist/src/{chunk-P2Q47GLV.js → chunk-6JWWD5NM.js} +200 -699
- package/dist/src/chunk-CBZ5YQAS.js +448 -0
- package/dist/src/chunk-IRM6KMN5.js +407 -0
- package/dist/src/chunk-LO6ISJCF.js +162 -0
- package/dist/src/chunk-XQW4B35Y.js +108 -0
- package/dist/src/codex-token-manager-KL7GDOF4.js +13 -0
- package/dist/src/engine-env-M3LJZ6ZJ.js +14 -0
- package/dist/src/headless-agent.js +49 -34
- package/dist/src/index.js +428 -803
- package/package.json +1 -1
package/dist/src/index.js
CHANGED
|
@@ -1,8 +1,51 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ACCOUNT_RATE_LIMITS_UPDATED_METHOD,
|
|
4
|
-
AGENT,
|
|
5
4
|
AGENT_MESSAGE_DELTA_METHOD,
|
|
5
|
+
COMMAND_EXECUTION_OUTPUT_DELTA_METHOD,
|
|
6
|
+
FILE_CHANGE_OUTPUT_DELTA_METHOD,
|
|
7
|
+
ITEM_COMPLETED_METHOD,
|
|
8
|
+
ITEM_STARTED_METHOD,
|
|
9
|
+
REASONING_SUMMARY_PART_ADDED_METHOD,
|
|
10
|
+
REASONING_SUMMARY_TEXT_DELTA_METHOD,
|
|
11
|
+
REASONING_TEXT_DELTA_METHOD,
|
|
12
|
+
THREAD_COMPACTED_METHOD,
|
|
13
|
+
THREAD_GOAL_CLEARED_METHOD,
|
|
14
|
+
THREAD_GOAL_UPDATED_METHOD,
|
|
15
|
+
THREAD_TOKEN_USAGE_UPDATED_METHOD,
|
|
16
|
+
TURN_COMPLETED_METHOD,
|
|
17
|
+
TURN_PLAN_UPDATED_METHOD,
|
|
18
|
+
TURN_STARTED_METHOD,
|
|
19
|
+
buildCodexAgentEnv,
|
|
20
|
+
dispatchAspNotification,
|
|
21
|
+
putPresignedFile,
|
|
22
|
+
recoverCompletedTurn
|
|
23
|
+
} from "./chunk-XQW4B35Y.js";
|
|
24
|
+
import {
|
|
25
|
+
AppServerProcess,
|
|
26
|
+
SUBPROCESS_MAX_BUFFER,
|
|
27
|
+
execAsync,
|
|
28
|
+
execFileAsync
|
|
29
|
+
} from "./chunk-CBZ5YQAS.js";
|
|
30
|
+
import {
|
|
31
|
+
BaseRefreshManager,
|
|
32
|
+
CodexAspAuthMethodChangedError,
|
|
33
|
+
applyAuthEnvTransition,
|
|
34
|
+
codexTokenManager,
|
|
35
|
+
listCredentialFallbacks,
|
|
36
|
+
monolithRequest,
|
|
37
|
+
monolithService,
|
|
38
|
+
recordCredentialFallback,
|
|
39
|
+
recordExhaustedCredential
|
|
40
|
+
} from "./chunk-IRM6KMN5.js";
|
|
41
|
+
import {
|
|
42
|
+
ENGINE_ENV,
|
|
43
|
+
IS_WARMING_MODE,
|
|
44
|
+
isRecord as isRecord2,
|
|
45
|
+
setAgentCredentialSnapshot
|
|
46
|
+
} from "./chunk-LO6ISJCF.js";
|
|
47
|
+
import {
|
|
48
|
+
AGENT,
|
|
6
49
|
AGENT_MODELS,
|
|
7
50
|
AI_GATEWAY_BASE_URL,
|
|
8
51
|
ASTER_BASE_URL,
|
|
@@ -11,7 +54,6 @@ import {
|
|
|
11
54
|
ASTER_PROVIDER,
|
|
12
55
|
AUTH_FALLBACK_EVENT_TYPE,
|
|
13
56
|
AUTH_RETRY_STATUS_EVENT_TYPE,
|
|
14
|
-
AppServerProcess,
|
|
15
57
|
CHAT_GOAL_EVENT_TYPE,
|
|
16
58
|
CHAT_INTERRUPTED_EVENT_TYPE,
|
|
17
59
|
CLAUDE_AUTH_ENV_KEYS,
|
|
@@ -28,12 +70,10 @@ import {
|
|
|
28
70
|
CLAUDE_SONNET_5_BEDROCK_MODEL,
|
|
29
71
|
CLAUDE_SONNET_5_MODEL,
|
|
30
72
|
CODEX_ASP_TRANSCRIPT_UPDATED_EVENT_TYPE,
|
|
31
|
-
CODEX_AUTH_ENV_KEYS,
|
|
32
|
-
CODEX_AUTH_ENV_KEYS_BY_METHOD,
|
|
33
73
|
CODEX_QUOTA_STATUS_EVENT_TYPE,
|
|
34
|
-
COMMAND_EXECUTION_OUTPUT_DELTA_METHOD,
|
|
35
74
|
COMPACTION_STATUS_EVENT_TYPE,
|
|
36
75
|
CONTEXT_USAGE_EVENT_TYPE,
|
|
76
|
+
CURSOR_CONNECTION_STATUS_EVENT_TYPE,
|
|
37
77
|
DEFAULT_ASTER_MODEL,
|
|
38
78
|
DEFAULT_CHAT_TITLES,
|
|
39
79
|
DEFAULT_CLAUDE_MODEL,
|
|
@@ -50,14 +90,11 @@ import {
|
|
|
50
90
|
ENGINE_HEALTH_MAX_WAIT_MS,
|
|
51
91
|
ENGINE_HEALTH_WAIT_HEADER,
|
|
52
92
|
ENGINE_HEALTH_WAIT_QUERY_PARAM,
|
|
53
|
-
FILE_CHANGE_OUTPUT_DELTA_METHOD,
|
|
54
93
|
GITHUB_CREDENTIAL_REFRESH_PATH,
|
|
55
94
|
GITLAB_CREDENTIAL_REFRESH_PATH,
|
|
56
95
|
GIT_CREDENTIAL_HELPER_FILENAME,
|
|
57
96
|
HOOK_EXEC_MAX_BUFFER_BYTES,
|
|
58
97
|
IMAGE_MEDIA_TYPES,
|
|
59
|
-
ITEM_COMPLETED_METHOD,
|
|
60
|
-
ITEM_STARTED_METHOD,
|
|
61
98
|
InFlightMap,
|
|
62
99
|
MAX_CANVAS_FILE_BYTES,
|
|
63
100
|
MAX_CANVAS_PREVIEW_BYTES,
|
|
@@ -66,32 +103,18 @@ import {
|
|
|
66
103
|
MEMORY_ROOT,
|
|
67
104
|
MEMORY_SUMMARY_FILENAME,
|
|
68
105
|
MERGED_MESSAGE_SEPARATOR,
|
|
69
|
-
REASONING_SUMMARY_PART_ADDED_METHOD,
|
|
70
|
-
REASONING_SUMMARY_TEXT_DELTA_METHOD,
|
|
71
|
-
REASONING_TEXT_DELTA_METHOD,
|
|
72
106
|
REPLICAS_CONFIG_FILENAMES,
|
|
73
|
-
REPLICAS_RUNTIME_ENV_ALIASES,
|
|
74
107
|
SANDBOX_PATHS,
|
|
75
|
-
SUBPROCESS_MAX_BUFFER,
|
|
76
|
-
THREAD_COMPACTED_METHOD,
|
|
77
|
-
THREAD_GOAL_CLEARED_METHOD,
|
|
78
|
-
THREAD_GOAL_UPDATED_METHOD,
|
|
79
|
-
THREAD_TOKEN_USAGE_UPDATED_METHOD,
|
|
80
108
|
TIMEOUT,
|
|
81
|
-
TURN_COMPLETED_METHOD,
|
|
82
|
-
TURN_PLAN_UPDATED_METHOD,
|
|
83
|
-
TURN_STARTED_METHOD,
|
|
84
109
|
TaskAccumulator,
|
|
85
110
|
USER_MESSAGE_ID_PAYLOAD_KEY,
|
|
86
111
|
VALID_AGENT_PROVIDERS,
|
|
87
112
|
VALID_RELAY_SUBAGENT_PROVIDERS,
|
|
88
113
|
VALID_THINKING_LEVELS,
|
|
89
|
-
agentCredentialSnapshotSchema,
|
|
90
114
|
applyCodexAspTranscriptDelta,
|
|
91
115
|
areSameUserMessageEvents,
|
|
92
116
|
areUserMessagesWithinMatchWindow,
|
|
93
117
|
autoCompactThresholdField,
|
|
94
|
-
buildCodexAgentEnv,
|
|
95
118
|
buildCodexTokenUsageContextUsagePayload,
|
|
96
119
|
buildGitCredentialHelperScript,
|
|
97
120
|
buildHookOutputPreview,
|
|
@@ -102,7 +125,6 @@ import {
|
|
|
102
125
|
clampWarmHookTimeoutMs,
|
|
103
126
|
classifyCanvasFilename,
|
|
104
127
|
claudeAuthEnvFromResponse,
|
|
105
|
-
codexAuthEnvFromResponse,
|
|
106
128
|
codexReasoningEffortForThinkingLevel,
|
|
107
129
|
coerceBackgroundTaskPayload,
|
|
108
130
|
coerceClaudeResultPayload,
|
|
@@ -116,9 +138,6 @@ import {
|
|
|
116
138
|
decodePathSegments,
|
|
117
139
|
detectAgentQuotaLimit,
|
|
118
140
|
detectLanguageByPath,
|
|
119
|
-
dispatchAspNotification,
|
|
120
|
-
execAsync,
|
|
121
|
-
execFileAsync,
|
|
122
141
|
extractCommandProtectionCommandText,
|
|
123
142
|
extractErrorText,
|
|
124
143
|
extractToolResultText,
|
|
@@ -175,21 +194,17 @@ import {
|
|
|
175
194
|
parseGitRemote,
|
|
176
195
|
parseLatestCodexAspTranscriptTurn,
|
|
177
196
|
parseMcpToolName,
|
|
178
|
-
parsePosixEnvFile,
|
|
179
197
|
parseReplicasConfigString,
|
|
180
198
|
percentage,
|
|
181
|
-
putPresignedFile,
|
|
182
199
|
raceWithTimeout,
|
|
183
200
|
readJsonlPage,
|
|
184
|
-
readReplicasRuntimeEnv,
|
|
185
|
-
recoverCompletedTurn,
|
|
186
201
|
renumberCodexAspTranscriptItems,
|
|
187
202
|
resolveWarmHookConfig,
|
|
188
203
|
sanitizeCanvasFilename,
|
|
189
204
|
serializeCanvasContentResponse,
|
|
190
205
|
shellQuotePosix,
|
|
191
206
|
stripAgentDiagnosticErrors
|
|
192
|
-
} from "./chunk-
|
|
207
|
+
} from "./chunk-6JWWD5NM.js";
|
|
193
208
|
|
|
194
209
|
// src/index.ts
|
|
195
210
|
import { serve } from "@hono/node-server";
|
|
@@ -201,373 +216,9 @@ import { connect } from "net";
|
|
|
201
216
|
// src/managers/github-token-manager.ts
|
|
202
217
|
import path from "path";
|
|
203
218
|
|
|
204
|
-
// src/engine-env.ts
|
|
205
|
-
import { readFileSync as readFileSync2 } from "fs";
|
|
206
|
-
import { homedir as homedir2 } from "os";
|
|
207
|
-
import { join as join2 } from "path";
|
|
208
|
-
|
|
209
|
-
// src/runtime-env-loader.ts
|
|
210
|
-
import { readFileSync } from "fs";
|
|
211
|
-
import { homedir } from "os";
|
|
212
|
-
import { join } from "path";
|
|
213
|
-
function loadRuntimeEnvFile() {
|
|
214
|
-
let content;
|
|
215
|
-
try {
|
|
216
|
-
content = readFileSync(join(homedir(), ".replicas", "runtime-env.sh"), "utf-8");
|
|
217
|
-
} catch {
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
220
|
-
for (const [key, value] of Object.entries(parsePosixEnvFile(content))) {
|
|
221
|
-
process.env[key] = value;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// src/utils/type-guards.ts
|
|
226
|
-
function isRecord2(value) {
|
|
227
|
-
return typeof value === "object" && value !== null;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// src/engine-env.ts
|
|
231
|
-
var SANDBOX_IMAGE_VERSION_FILE = "/usr/local/lib/replicas-sandbox-image-version";
|
|
232
|
-
function readEnv(name) {
|
|
233
|
-
const value = process.env[name]?.trim();
|
|
234
|
-
return value ? value : void 0;
|
|
235
|
-
}
|
|
236
|
-
function readSandboxImageVersion() {
|
|
237
|
-
const environmentVersion = readEnv("REPLICAS_SANDBOX_IMAGE_VERSION");
|
|
238
|
-
if (environmentVersion) return environmentVersion;
|
|
239
|
-
try {
|
|
240
|
-
return readFileSync2(SANDBOX_IMAGE_VERSION_FILE, "utf8").trim() || "development";
|
|
241
|
-
} catch {
|
|
242
|
-
return "development";
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
function parsePort(value) {
|
|
246
|
-
if (!value) {
|
|
247
|
-
return 3737;
|
|
248
|
-
}
|
|
249
|
-
const parsed = Number(value);
|
|
250
|
-
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
251
|
-
throw new Error("Invalid engine environment: REPLICAS_ENGINE_PORT must be a positive integer");
|
|
252
|
-
}
|
|
253
|
-
return parsed;
|
|
254
|
-
}
|
|
255
|
-
function requireDefined(value, name) {
|
|
256
|
-
if (value === void 0 || value === null) {
|
|
257
|
-
throw new Error(`Invalid engine environment: ${name} is required`);
|
|
258
|
-
}
|
|
259
|
-
return value;
|
|
260
|
-
}
|
|
261
|
-
function requireValidURL(value, name) {
|
|
262
|
-
try {
|
|
263
|
-
new URL(value);
|
|
264
|
-
return value;
|
|
265
|
-
} catch {
|
|
266
|
-
throw new Error(`Invalid engine environment: ${name} must be a valid URL`);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
function parseClaudeAuthMethod(value) {
|
|
270
|
-
if (value === "oauth" || value === "api_key" || value === "bedrock" || value === "foundry") {
|
|
271
|
-
return value;
|
|
272
|
-
}
|
|
273
|
-
return void 0;
|
|
274
|
-
}
|
|
275
|
-
function parseCodexAuthMethod(value) {
|
|
276
|
-
if (value === "oauth" || value === "api_key" || value === "foundry") {
|
|
277
|
-
return value;
|
|
278
|
-
}
|
|
279
|
-
return void 0;
|
|
280
|
-
}
|
|
281
|
-
function parseAgentCredentialSnapshots(value) {
|
|
282
|
-
if (!value) return {};
|
|
283
|
-
try {
|
|
284
|
-
const parsed = JSON.parse(value);
|
|
285
|
-
if (!isRecord2(parsed)) return {};
|
|
286
|
-
const snapshots = {};
|
|
287
|
-
for (const [provider, snapshot] of Object.entries(parsed)) {
|
|
288
|
-
if (!isValidAgentProvider(provider)) continue;
|
|
289
|
-
const parsedSnapshot = agentCredentialSnapshotSchema.safeParse(snapshot);
|
|
290
|
-
if (parsedSnapshot.success) snapshots[provider] = parsedSnapshot.data;
|
|
291
|
-
}
|
|
292
|
-
return snapshots;
|
|
293
|
-
} catch {
|
|
294
|
-
return {};
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
var IS_WARMING_MODE = process.argv.includes("--warming");
|
|
298
|
-
function loadEngineEnv() {
|
|
299
|
-
loadRuntimeEnvFile();
|
|
300
|
-
const HOME_DIR = homedir2();
|
|
301
|
-
const env = {
|
|
302
|
-
// Defined: always available
|
|
303
|
-
REPLICAS_ENGINE_SECRET: requireDefined(readEnv("REPLICAS_ENGINE_SECRET"), "REPLICAS_ENGINE_SECRET"),
|
|
304
|
-
REPLICAS_ENGINE_PORT: parsePort(readEnv("REPLICAS_ENGINE_PORT")),
|
|
305
|
-
REPLICAS_MONOLITH_URL: requireValidURL(
|
|
306
|
-
requireDefined(readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.monolithUrl), "REPLICAS_MONOLITH_URL"),
|
|
307
|
-
"REPLICAS_MONOLITH_URL"
|
|
308
|
-
),
|
|
309
|
-
HOME_DIR,
|
|
310
|
-
WORKSPACE_ROOT: join2(HOME_DIR, "workspaces"),
|
|
311
|
-
REPLICAS_SANDBOX_IMAGE_VERSION: readSandboxImageVersion(),
|
|
312
|
-
// Runtime: may not be set during warming
|
|
313
|
-
REPLICAS_WORKSPACE_ID: readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.workspaceId),
|
|
314
|
-
REPLICAS_LINEAR_SESSION_ID: readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.linearSessionId),
|
|
315
|
-
REPLICAS_LINEAR_ACCESS_TOKEN: readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.linearAccessToken),
|
|
316
|
-
REPLICAS_SLACK_BOT_TOKEN: readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.slackBotToken),
|
|
317
|
-
REPLICAS_SLACK_CHANNEL_ID: readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.slackChannelId),
|
|
318
|
-
REPLICAS_SLACK_THREAD_TS: readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.slackThreadTs),
|
|
319
|
-
ANTHROPIC_API_KEY: readEnv("ANTHROPIC_API_KEY"),
|
|
320
|
-
OPENAI_API_KEY: readEnv("OPENAI_API_KEY"),
|
|
321
|
-
CURSOR_API_KEY: readEnv("CURSOR_API_KEY"),
|
|
322
|
-
AI_GATEWAY_API_KEY: readEnv("AI_GATEWAY_API_KEY"),
|
|
323
|
-
CLAUDE_CODE_USE_BEDROCK: readEnv("CLAUDE_CODE_USE_BEDROCK"),
|
|
324
|
-
AWS_ACCESS_KEY_ID: readEnv("AWS_ACCESS_KEY_ID"),
|
|
325
|
-
AWS_SECRET_ACCESS_KEY: readEnv("AWS_SECRET_ACCESS_KEY"),
|
|
326
|
-
AWS_REGION: readEnv("AWS_REGION"),
|
|
327
|
-
ANTHROPIC_SMALL_FAST_MODEL_AWS_REGION: readEnv("ANTHROPIC_SMALL_FAST_MODEL_AWS_REGION"),
|
|
328
|
-
REPLICAS_CLAUDE_AUTH_METHOD: parseClaudeAuthMethod(readEnv("REPLICAS_CLAUDE_AUTH_METHOD")),
|
|
329
|
-
REPLICAS_CODEX_AUTH_METHOD: parseCodexAuthMethod(readEnv("REPLICAS_CODEX_AUTH_METHOD")),
|
|
330
|
-
REPLICAS_AGENT_CREDENTIALS: parseAgentCredentialSnapshots(readEnv("REPLICAS_AGENT_CREDENTIALS")),
|
|
331
|
-
REPLICAS_ENV_SYSTEM_PROMPT: readEnv("REPLICAS_ENV_SYSTEM_PROMPT"),
|
|
332
|
-
REPLICAS_ENV_START_HOOK: readEnv("REPLICAS_ENV_START_HOOK"),
|
|
333
|
-
REPLICAS_DISABLE_AUTO_START_HOOKS: readEnv("REPLICAS_DISABLE_AUTO_START_HOOKS")?.toLowerCase() === "true",
|
|
334
|
-
REPLICAS_ENGINE_DEFER_INITIALIZATION: readEnv("REPLICAS_ENGINE_DEFER_INITIALIZATION")?.toLowerCase() === "true"
|
|
335
|
-
};
|
|
336
|
-
if (!IS_WARMING_MODE && !env.REPLICAS_WORKSPACE_ID) {
|
|
337
|
-
console.error("REPLICAS_WORKSPACE_ID is not set \u2014 this is required in normal (non-warming) mode");
|
|
338
|
-
}
|
|
339
|
-
return env;
|
|
340
|
-
}
|
|
341
|
-
var ENGINE_ENV = loadEngineEnv();
|
|
342
|
-
function setAgentCredentialSnapshot(provider, snapshot) {
|
|
343
|
-
ENGINE_ENV.REPLICAS_AGENT_CREDENTIALS = {
|
|
344
|
-
...ENGINE_ENV.REPLICAS_AGENT_CREDENTIALS,
|
|
345
|
-
[provider]: snapshot
|
|
346
|
-
};
|
|
347
|
-
process.env.REPLICAS_AGENT_CREDENTIALS = JSON.stringify(ENGINE_ENV.REPLICAS_AGENT_CREDENTIALS);
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// src/services/credential-fallbacks.ts
|
|
351
|
-
var fallbacksByAgent = /* @__PURE__ */ new Map();
|
|
352
|
-
var exhaustedByAgent = /* @__PURE__ */ new Map();
|
|
353
|
-
function recordCredentialFallback(notice) {
|
|
354
|
-
fallbacksByAgent.set(notice.provider, notice);
|
|
355
|
-
}
|
|
356
|
-
function listCredentialFallbacks() {
|
|
357
|
-
return [...fallbacksByAgent.values()].filter((notice) => {
|
|
358
|
-
const live = ENGINE_ENV.REPLICAS_AGENT_CREDENTIALS[notice.provider];
|
|
359
|
-
if (!live) return false;
|
|
360
|
-
return notice.status === "switched" ? live.method === notice.candidateMethod && live.scope === notice.candidateScope : live.method === notice.exhaustedMethod && live.scope === notice.exhaustedScope;
|
|
361
|
-
});
|
|
362
|
-
}
|
|
363
|
-
function listExhaustedCredentials(provider) {
|
|
364
|
-
return [...exhaustedByAgent.get(provider)?.values() ?? []];
|
|
365
|
-
}
|
|
366
|
-
function recordExhaustedCredential(provider, credential) {
|
|
367
|
-
const spent = exhaustedByAgent.get(provider) ?? /* @__PURE__ */ new Map();
|
|
368
|
-
spent.set(`${credential.method}|${credential.scope}`, credential);
|
|
369
|
-
exhaustedByAgent.set(provider, spent);
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// src/managers/base-refresh-manager.ts
|
|
373
|
-
var BaseRefreshManager = class {
|
|
374
|
-
constructor(managerName, intervalMs = 15 * 60 * 1e3) {
|
|
375
|
-
this.managerName = managerName;
|
|
376
|
-
this.intervalMs = intervalMs;
|
|
377
|
-
this.health = {
|
|
378
|
-
isRunning: false,
|
|
379
|
-
intervalMs: this.intervalMs,
|
|
380
|
-
lastAttemptAt: null,
|
|
381
|
-
lastSuccessAt: null,
|
|
382
|
-
lastErrorAt: null,
|
|
383
|
-
lastErrorMessage: null
|
|
384
|
-
};
|
|
385
|
-
}
|
|
386
|
-
managerName;
|
|
387
|
-
intervalMs;
|
|
388
|
-
intervalHandle = null;
|
|
389
|
-
health;
|
|
390
|
-
async start() {
|
|
391
|
-
if (this.intervalHandle) {
|
|
392
|
-
return;
|
|
393
|
-
}
|
|
394
|
-
const skipReason = this.getSkipReason();
|
|
395
|
-
if (skipReason) {
|
|
396
|
-
console.log(`[${this.managerName}] Skipping: ${skipReason}`);
|
|
397
|
-
return;
|
|
398
|
-
}
|
|
399
|
-
console.log(`[${this.managerName}] Starting token refresh service`);
|
|
400
|
-
this.health.isRunning = true;
|
|
401
|
-
const config = this.getRuntimeConfig();
|
|
402
|
-
if (config) {
|
|
403
|
-
this.health.lastAttemptAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
404
|
-
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
405
|
-
try {
|
|
406
|
-
await this.doRefresh(config);
|
|
407
|
-
this.health.lastSuccessAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
408
|
-
this.health.lastErrorAt = null;
|
|
409
|
-
this.health.lastErrorMessage = null;
|
|
410
|
-
break;
|
|
411
|
-
} catch (error) {
|
|
412
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
413
|
-
this.health.lastErrorAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
414
|
-
this.health.lastErrorMessage = message;
|
|
415
|
-
if (attempt < 3) {
|
|
416
|
-
console.warn(`[${this.managerName}] Initial refresh attempt ${attempt} failed, retrying in 2s...`);
|
|
417
|
-
await new Promise((resolve5) => setTimeout(resolve5, 2e3));
|
|
418
|
-
} else {
|
|
419
|
-
console.error(`[${this.managerName}] Initial refresh failed after 3 attempts:`, error);
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
this.scheduleNextRefresh();
|
|
425
|
-
}
|
|
426
|
-
async swapCredentials(params) {
|
|
427
|
-
if (!this.getRuntimeConfig()) {
|
|
428
|
-
return createErrorResult({ message: `${this.managerName} has no runtime config`, code: "not_configured" });
|
|
429
|
-
}
|
|
430
|
-
try {
|
|
431
|
-
console.log(`[${this.managerName}] Fetching fresh credentials from monolith (${params.failureKind})...`);
|
|
432
|
-
const excludeCredentials = listExhaustedCredentials(params.provider);
|
|
433
|
-
await params.refresh(excludeCredentials.length > 0 ? { excludeCredentials } : {});
|
|
434
|
-
if (params.isOauthNow()) {
|
|
435
|
-
this.start().catch((error) => {
|
|
436
|
-
console.error(`[${this.managerName}] Failed to restart OAuth refresh service after fallback:`, error);
|
|
437
|
-
});
|
|
438
|
-
}
|
|
439
|
-
return createSuccessResult();
|
|
440
|
-
} catch (error) {
|
|
441
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
442
|
-
console.error(`[${this.managerName}] Failed to fetch fresh credentials:`, error);
|
|
443
|
-
return createErrorResult({
|
|
444
|
-
message,
|
|
445
|
-
code: message.includes('"code":"no_credentials"') ? "no_credentials" : "refresh_failed"
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
stop() {
|
|
450
|
-
if (!this.intervalHandle) {
|
|
451
|
-
return;
|
|
452
|
-
}
|
|
453
|
-
clearTimeout(this.intervalHandle);
|
|
454
|
-
this.intervalHandle = null;
|
|
455
|
-
this.health.isRunning = false;
|
|
456
|
-
console.log(`[${this.managerName}] Stopped`);
|
|
457
|
-
}
|
|
458
|
-
getHealthStatus() {
|
|
459
|
-
return { ...this.health };
|
|
460
|
-
}
|
|
461
|
-
getSkipReason() {
|
|
462
|
-
return null;
|
|
463
|
-
}
|
|
464
|
-
getNextRefreshDelayMs() {
|
|
465
|
-
return this.intervalMs;
|
|
466
|
-
}
|
|
467
|
-
getRuntimeConfig() {
|
|
468
|
-
if (!ENGINE_ENV.REPLICAS_WORKSPACE_ID) {
|
|
469
|
-
return null;
|
|
470
|
-
}
|
|
471
|
-
return {
|
|
472
|
-
monolithUrl: ENGINE_ENV.REPLICAS_MONOLITH_URL,
|
|
473
|
-
workspaceId: ENGINE_ENV.REPLICAS_WORKSPACE_ID,
|
|
474
|
-
engineSecret: ENGINE_ENV.REPLICAS_ENGINE_SECRET
|
|
475
|
-
};
|
|
476
|
-
}
|
|
477
|
-
scheduleNextRefresh() {
|
|
478
|
-
const delayMs = this.getNextRefreshDelayMs();
|
|
479
|
-
this.health.intervalMs = delayMs;
|
|
480
|
-
this.intervalHandle = setTimeout(async () => {
|
|
481
|
-
await this.refreshOnce();
|
|
482
|
-
if (this.intervalHandle) this.scheduleNextRefresh();
|
|
483
|
-
}, delayMs);
|
|
484
|
-
console.log(`[${this.managerName}] Token refresh scheduled in ${Math.round(delayMs / 1e3)} seconds`);
|
|
485
|
-
}
|
|
486
|
-
async refreshOnce() {
|
|
487
|
-
if (this.getSkipReason()) {
|
|
488
|
-
return createSuccessResult();
|
|
489
|
-
}
|
|
490
|
-
const config = this.getRuntimeConfig();
|
|
491
|
-
if (!config) return createSuccessResult();
|
|
492
|
-
this.health.lastAttemptAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
493
|
-
try {
|
|
494
|
-
await this.doRefresh(config);
|
|
495
|
-
this.health.lastSuccessAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
496
|
-
this.health.lastErrorAt = null;
|
|
497
|
-
this.health.lastErrorMessage = null;
|
|
498
|
-
return createSuccessResult();
|
|
499
|
-
} catch (error) {
|
|
500
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
501
|
-
this.health.lastErrorAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
502
|
-
this.health.lastErrorMessage = message;
|
|
503
|
-
console.error(`[${this.managerName}] Failed to refresh credentials:`, error);
|
|
504
|
-
return createErrorResult({ message });
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
};
|
|
508
|
-
|
|
509
|
-
// src/services/monolith-service.ts
|
|
510
|
-
async function monolithRequest(path6, init = {}) {
|
|
511
|
-
if (!ENGINE_ENV.REPLICAS_WORKSPACE_ID) {
|
|
512
|
-
throw new Error("REPLICAS_WORKSPACE_ID is not set; cannot call monolith");
|
|
513
|
-
}
|
|
514
|
-
const headers = {
|
|
515
|
-
Authorization: `Bearer ${ENGINE_ENV.REPLICAS_ENGINE_SECRET}`,
|
|
516
|
-
"X-Workspace-Id": ENGINE_ENV.REPLICAS_WORKSPACE_ID
|
|
517
|
-
};
|
|
518
|
-
if (!(init.body instanceof FormData)) headers["Content-Type"] = "application/json";
|
|
519
|
-
return fetch(`${ENGINE_ENV.REPLICAS_MONOLITH_URL}${path6}`, {
|
|
520
|
-
method: init.method ?? "POST",
|
|
521
|
-
headers,
|
|
522
|
-
body: init.body === void 0 ? void 0 : init.body instanceof FormData ? init.body : JSON.stringify(init.body),
|
|
523
|
-
signal: init.signal
|
|
524
|
-
});
|
|
525
|
-
}
|
|
526
|
-
var MonolithService = class {
|
|
527
|
-
async getRelaySubagentProviders() {
|
|
528
|
-
try {
|
|
529
|
-
const response = await monolithRequest("/v1/engine/relay-subagent-providers", { method: "GET" });
|
|
530
|
-
if (!response.ok) {
|
|
531
|
-
return null;
|
|
532
|
-
}
|
|
533
|
-
const body = await response.json();
|
|
534
|
-
return isRecord(body) && Array.isArray(body.providers) && body.providers.every((provider) => typeof provider === "string" && isValidAgentProvider(provider)) ? body.providers : null;
|
|
535
|
-
} catch {
|
|
536
|
-
return null;
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
async getOpenRouterModels() {
|
|
540
|
-
try {
|
|
541
|
-
const response = await monolithRequest("/v1/engine/openrouter-models", { method: "GET" });
|
|
542
|
-
if (!response.ok) {
|
|
543
|
-
return null;
|
|
544
|
-
}
|
|
545
|
-
const body = await response.json();
|
|
546
|
-
return isRecord(body) && Array.isArray(body.models) && body.models.every((model) => typeof model === "string") ? body.models : null;
|
|
547
|
-
} catch {
|
|
548
|
-
return null;
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
async sendEvent(event) {
|
|
552
|
-
if (!ENGINE_ENV.REPLICAS_WORKSPACE_ID) {
|
|
553
|
-
return;
|
|
554
|
-
}
|
|
555
|
-
try {
|
|
556
|
-
const response = await monolithRequest("/v1/engine/webhook", { body: event });
|
|
557
|
-
if (!response.ok) {
|
|
558
|
-
const errorText = await response.text();
|
|
559
|
-
console.error(`[MonolithService] Failed to send event: ${response.status} ${errorText}`);
|
|
560
|
-
}
|
|
561
|
-
} catch (error) {
|
|
562
|
-
console.error("[MonolithService] Failed to send event:", error);
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
};
|
|
566
|
-
var monolithService = new MonolithService();
|
|
567
|
-
|
|
568
219
|
// src/utils/file.ts
|
|
569
220
|
import { mkdir, readFile, rename, unlink, writeFile } from "fs/promises";
|
|
570
|
-
import { dirname, join
|
|
221
|
+
import { dirname, join } from "path";
|
|
571
222
|
|
|
572
223
|
// src/utils/async-lock.ts
|
|
573
224
|
var AsyncLock = class {
|
|
@@ -583,11 +234,11 @@ var AsyncLock = class {
|
|
|
583
234
|
};
|
|
584
235
|
|
|
585
236
|
// src/utils/file.ts
|
|
586
|
-
async function atomicWriteFile(
|
|
587
|
-
const tmpFile = `${
|
|
237
|
+
async function atomicWriteFile(path5, data, options) {
|
|
238
|
+
const tmpFile = `${path5}.${process.pid}.${Date.now()}.tmp`;
|
|
588
239
|
try {
|
|
589
240
|
await writeFile(tmpFile, data, { encoding: "utf-8", mode: options?.mode });
|
|
590
|
-
await rename(tmpFile,
|
|
241
|
+
await rename(tmpFile, path5);
|
|
591
242
|
} catch (error) {
|
|
592
243
|
await unlink(tmpFile).catch(() => void 0);
|
|
593
244
|
throw error;
|
|
@@ -600,8 +251,8 @@ async function writeSecureCredentialFile(filePath, content, options) {
|
|
|
600
251
|
await atomicWriteFile(filePath, content, { mode: 384 });
|
|
601
252
|
}
|
|
602
253
|
async function configureManagedGitCredentialHelper(homeDir) {
|
|
603
|
-
const credentialsPath =
|
|
604
|
-
const helperPath =
|
|
254
|
+
const credentialsPath = join(homeDir, ".git-credentials");
|
|
255
|
+
const helperPath = join(homeDir, GIT_CREDENTIAL_HELPER_FILENAME);
|
|
605
256
|
await atomicWriteFile(helperPath, buildGitCredentialHelperScript(credentialsPath), { mode: 448 });
|
|
606
257
|
await execFileAsync("git", ["config", "--global", "credential.helper", helperPath], {
|
|
607
258
|
env: { ...process.env, HOME: homeDir }
|
|
@@ -636,15 +287,15 @@ function removeCredentialFileLines(filePath, shouldRemove) {
|
|
|
636
287
|
// src/git/service.ts
|
|
637
288
|
import { readdir, readFile as readFile3, stat } from "fs/promises";
|
|
638
289
|
import { spawn } from "child_process";
|
|
639
|
-
import { join as
|
|
290
|
+
import { join as join4 } from "path";
|
|
640
291
|
|
|
641
292
|
// src/utils/state.ts
|
|
642
293
|
import { readFile as readFile2, mkdir as mkdir2 } from "fs/promises";
|
|
643
294
|
import { existsSync } from "fs";
|
|
644
|
-
import { join as
|
|
645
|
-
import { homedir
|
|
646
|
-
var STATE_DIR =
|
|
647
|
-
var STATE_FILE =
|
|
295
|
+
import { join as join2 } from "path";
|
|
296
|
+
import { homedir } from "os";
|
|
297
|
+
var STATE_DIR = join2(homedir(), ".replicas");
|
|
298
|
+
var STATE_FILE = join2(STATE_DIR, "engine-state.json");
|
|
648
299
|
var DEFAULT_STATE = {
|
|
649
300
|
repos: {}
|
|
650
301
|
};
|
|
@@ -741,8 +392,8 @@ async function saveRepoState(repoName, state, fallbackState) {
|
|
|
741
392
|
}
|
|
742
393
|
|
|
743
394
|
// src/git/commands.ts
|
|
744
|
-
import { readFileSync
|
|
745
|
-
import { join as
|
|
395
|
+
import { readFileSync } from "fs";
|
|
396
|
+
import { join as join3 } from "path";
|
|
746
397
|
async function runGitCommand(args, cwd, options = {}) {
|
|
747
398
|
const { stdout } = await execFileAsync("git", args, {
|
|
748
399
|
cwd,
|
|
@@ -753,7 +404,7 @@ async function runGitCommand(args, cwd, options = {}) {
|
|
|
753
404
|
}
|
|
754
405
|
function readRepoHeadBranch(repoPath) {
|
|
755
406
|
try {
|
|
756
|
-
const contents =
|
|
407
|
+
const contents = readFileSync(join3(repoPath, ".git", "HEAD"), "utf-8").trim();
|
|
757
408
|
const match = contents.match(/^ref:\s+refs\/heads\/(.+)$/);
|
|
758
409
|
return match ? match[1] : null;
|
|
759
410
|
} catch {
|
|
@@ -815,13 +466,13 @@ var GitService = class {
|
|
|
815
466
|
const repos = [];
|
|
816
467
|
let complete = true;
|
|
817
468
|
for (const entry of entries) {
|
|
818
|
-
const fullPath =
|
|
469
|
+
const fullPath = join4(root, entry);
|
|
819
470
|
try {
|
|
820
471
|
const entryStat = await stat(fullPath);
|
|
821
472
|
if (!entryStat.isDirectory()) {
|
|
822
473
|
continue;
|
|
823
474
|
}
|
|
824
|
-
const hasGit = Boolean(await this.safeStat(
|
|
475
|
+
const hasGit = Boolean(await this.safeStat(join4(fullPath, ".git")));
|
|
825
476
|
if (!hasGit) {
|
|
826
477
|
continue;
|
|
827
478
|
}
|
|
@@ -1010,9 +661,9 @@ var GitService = class {
|
|
|
1010
661
|
try {
|
|
1011
662
|
const paths = await this.listUntrackedPaths(repoPath);
|
|
1012
663
|
let total = 0;
|
|
1013
|
-
for (const
|
|
664
|
+
for (const path5 of paths) {
|
|
1014
665
|
try {
|
|
1015
|
-
const contents = await readFile3(
|
|
666
|
+
const contents = await readFile3(join4(repoPath, path5));
|
|
1016
667
|
if (contents.length === 0 || contents.includes(0)) {
|
|
1017
668
|
continue;
|
|
1018
669
|
}
|
|
@@ -1200,7 +851,7 @@ var GitService = class {
|
|
|
1200
851
|
}
|
|
1201
852
|
async getGitLabAccessToken(host) {
|
|
1202
853
|
try {
|
|
1203
|
-
const credentials = await readFile3(
|
|
854
|
+
const credentials = await readFile3(join4(ENGINE_ENV.HOME_DIR, ".git-credentials"), "utf-8");
|
|
1204
855
|
for (const line of credentials.split("\n")) {
|
|
1205
856
|
const trimmed = line.trim();
|
|
1206
857
|
if (!trimmed) continue;
|
|
@@ -1268,9 +919,9 @@ var GitService = class {
|
|
|
1268
919
|
await saveRepoState(repo.name, state, state);
|
|
1269
920
|
return state;
|
|
1270
921
|
}
|
|
1271
|
-
async safeStat(
|
|
922
|
+
async safeStat(path5) {
|
|
1272
923
|
try {
|
|
1273
|
-
return await stat(
|
|
924
|
+
return await stat(path5);
|
|
1274
925
|
} catch {
|
|
1275
926
|
return null;
|
|
1276
927
|
}
|
|
@@ -1421,26 +1072,6 @@ var gitlabTokenManager = new GitLabTokenManager();
|
|
|
1421
1072
|
// src/managers/claude-token-manager.ts
|
|
1422
1073
|
import { promises as fs } from "fs";
|
|
1423
1074
|
import path3 from "path";
|
|
1424
|
-
|
|
1425
|
-
// src/managers/auth-env-transition.ts
|
|
1426
|
-
function applyAuthEnvTransition(params) {
|
|
1427
|
-
const newOwned = new Set(params.authKeysByMethod[params.newMethod]);
|
|
1428
|
-
const prevOwned = new Set(params.authKeysByMethod[params.prevMethod]);
|
|
1429
|
-
for (const key of params.authKeys) {
|
|
1430
|
-
const value = params.newEnvVars[key];
|
|
1431
|
-
if (value !== void 0) {
|
|
1432
|
-
for (const env of params.envs) {
|
|
1433
|
-
env[key] = value;
|
|
1434
|
-
}
|
|
1435
|
-
} else if (prevOwned.has(key) && !newOwned.has(key)) {
|
|
1436
|
-
for (const env of params.envs) {
|
|
1437
|
-
delete env[key];
|
|
1438
|
-
}
|
|
1439
|
-
}
|
|
1440
|
-
}
|
|
1441
|
-
}
|
|
1442
|
-
|
|
1443
|
-
// src/managers/claude-token-manager.ts
|
|
1444
1075
|
var ClaudeTokenManager = class extends BaseRefreshManager {
|
|
1445
1076
|
constructor() {
|
|
1446
1077
|
super("ClaudeTokenManager");
|
|
@@ -1544,114 +1175,9 @@ var ClaudeTokenManager = class extends BaseRefreshManager {
|
|
|
1544
1175
|
};
|
|
1545
1176
|
var claudeTokenManager = new ClaudeTokenManager();
|
|
1546
1177
|
|
|
1547
|
-
// src/managers/codex-token-manager.ts
|
|
1548
|
-
import { promises as fs2 } from "fs";
|
|
1549
|
-
import path4 from "path";
|
|
1550
|
-
var CodexTokenManager = class extends BaseRefreshManager {
|
|
1551
|
-
constructor() {
|
|
1552
|
-
super("CodexTokenManager");
|
|
1553
|
-
}
|
|
1554
|
-
getSkipReason() {
|
|
1555
|
-
if (ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD === "api_key" || ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD === "foundry") {
|
|
1556
|
-
return `auth method is ${ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD}`;
|
|
1557
|
-
}
|
|
1558
|
-
if (!ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD && ENGINE_ENV.OPENAI_API_KEY) {
|
|
1559
|
-
return "OPENAI_API_KEY is set";
|
|
1560
|
-
}
|
|
1561
|
-
return null;
|
|
1562
|
-
}
|
|
1563
|
-
async doRefresh(_config) {
|
|
1564
|
-
await this.refreshWithRequest();
|
|
1565
|
-
}
|
|
1566
|
-
async refreshWithRequest(request) {
|
|
1567
|
-
console.log("[CodexTokenManager] Refreshing Codex credentials...");
|
|
1568
|
-
const response = await monolithRequest("/v1/engine/codex/refresh-credentials", {
|
|
1569
|
-
body: request
|
|
1570
|
-
});
|
|
1571
|
-
if (!response.ok) {
|
|
1572
|
-
const errorText = await response.text();
|
|
1573
|
-
throw new Error(`Credentials refresh failed: ${response.status} ${errorText}`);
|
|
1574
|
-
}
|
|
1575
|
-
const data = await response.json();
|
|
1576
|
-
await this.applyCredentialsResponse(data);
|
|
1577
|
-
if (data.scope) {
|
|
1578
|
-
setAgentCredentialSnapshot("codex", {
|
|
1579
|
-
method: data.type,
|
|
1580
|
-
scope: data.scope,
|
|
1581
|
-
...data.revision ? { revision: data.revision } : {}
|
|
1582
|
-
});
|
|
1583
|
-
}
|
|
1584
|
-
console.log(`[CodexTokenManager] Credentials refreshed (method=${data.type})`);
|
|
1585
|
-
}
|
|
1586
|
-
async fetchFreshCredentials(failureReason, failureKind = "rejected", failedCredential = ENGINE_ENV.REPLICAS_AGENT_CREDENTIALS.codex) {
|
|
1587
|
-
const failedMethod = failedCredential?.method === "oauth" || failedCredential?.method === "api_key" || failedCredential?.method === "foundry" ? failedCredential.method : ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD;
|
|
1588
|
-
return this.swapCredentials({
|
|
1589
|
-
provider: "codex",
|
|
1590
|
-
failureKind,
|
|
1591
|
-
refresh: (exclusions) => this.refreshWithRequest(
|
|
1592
|
-
failedMethod === "oauth" || failedMethod === "api_key" || failedMethod === "foundry" ? {
|
|
1593
|
-
failedMethod,
|
|
1594
|
-
...failedCredential?.method === failedMethod ? { failedCredential } : {},
|
|
1595
|
-
failureReason,
|
|
1596
|
-
failureKind,
|
|
1597
|
-
...exclusions
|
|
1598
|
-
} : exclusions
|
|
1599
|
-
),
|
|
1600
|
-
isOauthNow: () => ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD === "oauth"
|
|
1601
|
-
});
|
|
1602
|
-
}
|
|
1603
|
-
async applyCredentialsResponse(response) {
|
|
1604
|
-
if (response.type === "oauth") {
|
|
1605
|
-
await this.writeOauthCredentialsFile(response);
|
|
1606
|
-
} else {
|
|
1607
|
-
await this.removeOauthCredentialsFile();
|
|
1608
|
-
}
|
|
1609
|
-
const envVars = codexAuthEnvFromResponse(response);
|
|
1610
|
-
applyAuthEnvTransition({
|
|
1611
|
-
prevMethod: ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD ?? "none",
|
|
1612
|
-
newMethod: envVars.REPLICAS_CODEX_AUTH_METHOD ?? "none",
|
|
1613
|
-
authKeys: CODEX_AUTH_ENV_KEYS,
|
|
1614
|
-
authKeysByMethod: CODEX_AUTH_ENV_KEYS_BY_METHOD,
|
|
1615
|
-
newEnvVars: envVars,
|
|
1616
|
-
envs: [ENGINE_ENV, process.env]
|
|
1617
|
-
});
|
|
1618
|
-
}
|
|
1619
|
-
async writeOauthCredentialsFile(credentials) {
|
|
1620
|
-
const authPath = path4.join(ENGINE_ENV.HOME_DIR, ".codex", "auth.json");
|
|
1621
|
-
const codexAuthConfig = {
|
|
1622
|
-
OPENAI_API_KEY: null,
|
|
1623
|
-
tokens: {
|
|
1624
|
-
id_token: credentials.idToken,
|
|
1625
|
-
access_token: credentials.accessToken,
|
|
1626
|
-
refresh_token: credentials.refreshToken,
|
|
1627
|
-
account_id: credentials.accountId
|
|
1628
|
-
},
|
|
1629
|
-
last_refresh: (/* @__PURE__ */ new Date()).toISOString()
|
|
1630
|
-
};
|
|
1631
|
-
try {
|
|
1632
|
-
await writeSecureCredentialFile(
|
|
1633
|
-
authPath,
|
|
1634
|
-
JSON.stringify(codexAuthConfig, null, 2),
|
|
1635
|
-
{ ensureParentDir: true }
|
|
1636
|
-
);
|
|
1637
|
-
console.log(`[CodexTokenManager] Updated ${authPath}`);
|
|
1638
|
-
} catch (error) {
|
|
1639
|
-
console.error("[CodexTokenManager] Failed to update credentials file:", error);
|
|
1640
|
-
}
|
|
1641
|
-
}
|
|
1642
|
-
async removeOauthCredentialsFile() {
|
|
1643
|
-
const authPath = path4.join(ENGINE_ENV.HOME_DIR, ".codex", "auth.json");
|
|
1644
|
-
try {
|
|
1645
|
-
await fs2.unlink(authPath);
|
|
1646
|
-
} catch {
|
|
1647
|
-
}
|
|
1648
|
-
}
|
|
1649
|
-
};
|
|
1650
|
-
var codexTokenManager = new CodexTokenManager();
|
|
1651
|
-
|
|
1652
1178
|
// src/managers/infisical-token-manager.ts
|
|
1653
1179
|
import { rm } from "fs/promises";
|
|
1654
|
-
import
|
|
1180
|
+
import path4 from "path";
|
|
1655
1181
|
var InfisicalTokenManager = class extends BaseRefreshManager {
|
|
1656
1182
|
constructor(request = monolithRequest, paths = {
|
|
1657
1183
|
homeDir: ENGINE_ENV.HOME_DIR,
|
|
@@ -1679,8 +1205,8 @@ var InfisicalTokenManager = class extends BaseRefreshManager {
|
|
|
1679
1205
|
}
|
|
1680
1206
|
};
|
|
1681
1207
|
async function applyInfisicalCredentials(data, paths) {
|
|
1682
|
-
const credentialPath =
|
|
1683
|
-
const configPath =
|
|
1208
|
+
const credentialPath = path4.join(paths.homeDir, ".replicas", "infisical-env.sh");
|
|
1209
|
+
const configPath = path4.join(paths.workspaceRoot, ".infisical.json");
|
|
1684
1210
|
if (!data.configured) {
|
|
1685
1211
|
delete process.env.INFISICAL_TOKEN;
|
|
1686
1212
|
delete process.env.INFISICAL_DOMAIN;
|
|
@@ -1709,8 +1235,8 @@ var infisicalTokenManager = new InfisicalTokenManager();
|
|
|
1709
1235
|
|
|
1710
1236
|
// src/utils/logger.ts
|
|
1711
1237
|
import { mkdir as mkdir3, writeFile as writeFile2 } from "fs/promises";
|
|
1712
|
-
import { homedir as
|
|
1713
|
-
import { join as
|
|
1238
|
+
import { homedir as homedir2 } from "os";
|
|
1239
|
+
import { join as join5 } from "path";
|
|
1714
1240
|
import { format } from "util";
|
|
1715
1241
|
import { randomBytes } from "crypto";
|
|
1716
1242
|
|
|
@@ -1722,8 +1248,8 @@ var StreamWriter = class {
|
|
|
1722
1248
|
backpressured = false;
|
|
1723
1249
|
droppedCount = 0;
|
|
1724
1250
|
flushTimer = null;
|
|
1725
|
-
open(
|
|
1726
|
-
this.stream = createWriteStream(
|
|
1251
|
+
open(path5, highWaterMark = DEFAULT_HIGH_WATER) {
|
|
1252
|
+
this.stream = createWriteStream(path5, { flags: "a", highWaterMark });
|
|
1727
1253
|
this.stream.on("error", () => {
|
|
1728
1254
|
this.stream = null;
|
|
1729
1255
|
});
|
|
@@ -1785,7 +1311,7 @@ var StreamWriter = class {
|
|
|
1785
1311
|
};
|
|
1786
1312
|
|
|
1787
1313
|
// src/utils/logger.ts
|
|
1788
|
-
var LOG_DIR =
|
|
1314
|
+
var LOG_DIR = join5(homedir2(), ".replicas", "logs");
|
|
1789
1315
|
var EngineLogger = class {
|
|
1790
1316
|
_sessionId = null;
|
|
1791
1317
|
patched = false;
|
|
@@ -1796,7 +1322,7 @@ var EngineLogger = class {
|
|
|
1796
1322
|
async initialize() {
|
|
1797
1323
|
await mkdir3(LOG_DIR, { recursive: true });
|
|
1798
1324
|
this._sessionId = this.createSessionId();
|
|
1799
|
-
const logPath =
|
|
1325
|
+
const logPath = join5(LOG_DIR, `${this._sessionId}.log`);
|
|
1800
1326
|
await writeFile2(logPath, `=== Replicas Engine Session ${this._sessionId} ===
|
|
1801
1327
|
`, "utf-8");
|
|
1802
1328
|
this.writer.open(logPath);
|
|
@@ -1843,45 +1369,49 @@ var engineLogger = new EngineLogger();
|
|
|
1843
1369
|
// src/services/replicas-config-service.ts
|
|
1844
1370
|
import { readFile as readFile6, appendFile, writeFile as writeFile4, mkdir as mkdir6 } from "fs/promises";
|
|
1845
1371
|
import { existsSync as existsSync3 } from "fs";
|
|
1846
|
-
import { join as
|
|
1847
|
-
import { homedir as
|
|
1372
|
+
import { join as join9 } from "path";
|
|
1373
|
+
import { homedir as homedir6 } from "os";
|
|
1848
1374
|
import { spawn as spawn2 } from "child_process";
|
|
1849
1375
|
|
|
1850
1376
|
// src/services/environment-details-service.ts
|
|
1851
1377
|
import { mkdir as mkdir4, readFile as readFile4 } from "fs/promises";
|
|
1852
1378
|
import { existsSync as existsSync2 } from "fs";
|
|
1853
|
-
import { homedir as
|
|
1854
|
-
import { join as
|
|
1379
|
+
import { homedir as homedir4 } from "os";
|
|
1380
|
+
import { join as join7 } from "path";
|
|
1855
1381
|
|
|
1856
1382
|
// src/managers/agent-auth-paths.ts
|
|
1857
|
-
import { homedir as
|
|
1858
|
-
import { join as
|
|
1859
|
-
var OPENCODE_AUTH_PATH =
|
|
1860
|
-
var PI_AUTH_PATH =
|
|
1861
|
-
var DEEPSEEK_AUTH_PATH =
|
|
1383
|
+
import { homedir as homedir3 } from "os";
|
|
1384
|
+
import { join as join6 } from "path";
|
|
1385
|
+
var OPENCODE_AUTH_PATH = join6(homedir3(), ".local", "share", "opencode", "auth.json");
|
|
1386
|
+
var PI_AUTH_PATH = join6(homedir3(), ".pi", "agent", "auth.json");
|
|
1387
|
+
var DEEPSEEK_AUTH_PATH = join6(homedir3(), ".replicas", "deepseek-auth.json");
|
|
1862
1388
|
|
|
1863
1389
|
// src/managers/deepseek-auth.ts
|
|
1864
|
-
import { readFileSync as
|
|
1390
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
1865
1391
|
import { z } from "zod";
|
|
1866
1392
|
var authSchema = z.object({
|
|
1867
1393
|
openrouter: z.object({ type: z.literal("api"), key: z.string().min(1) })
|
|
1868
1394
|
});
|
|
1869
1395
|
function getDeepseekApiKey() {
|
|
1870
1396
|
try {
|
|
1871
|
-
const parsed = authSchema.safeParse(JSON.parse(
|
|
1397
|
+
const parsed = authSchema.safeParse(JSON.parse(readFileSync2(DEEPSEEK_AUTH_PATH, "utf8")));
|
|
1872
1398
|
return parsed.success ? parsed.data.openrouter.key : null;
|
|
1873
1399
|
} catch {
|
|
1874
1400
|
return null;
|
|
1875
1401
|
}
|
|
1876
1402
|
}
|
|
1877
1403
|
|
|
1404
|
+
// src/managers/codex-auth.ts
|
|
1405
|
+
function detectCodexAuthMethod() {
|
|
1406
|
+
return ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD ?? (ENGINE_ENV.OPENAI_API_KEY ? "api_key" : "none");
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1878
1409
|
// src/services/environment-details-service.ts
|
|
1879
|
-
var REPLICAS_DIR =
|
|
1880
|
-
var DETAILS_FILE =
|
|
1881
|
-
var CLAUDE_CREDENTIALS_PATH =
|
|
1882
|
-
var
|
|
1883
|
-
var
|
|
1884
|
-
var GIT_CREDENTIALS_PATH = join9(homedir6(), ".git-credentials");
|
|
1410
|
+
var REPLICAS_DIR = join7(homedir4(), ".replicas");
|
|
1411
|
+
var DETAILS_FILE = join7(REPLICAS_DIR, "environment-details.json");
|
|
1412
|
+
var CLAUDE_CREDENTIALS_PATH = join7(homedir4(), ".claude", ".credentials.json");
|
|
1413
|
+
var GH_HOSTS_PATH = join7(homedir4(), ".config", "gh", "hosts.yml");
|
|
1414
|
+
var GIT_CREDENTIALS_PATH = join7(homedir4(), ".git-credentials");
|
|
1885
1415
|
function detectClaudeAuthMethod() {
|
|
1886
1416
|
if (existsSync2(CLAUDE_CREDENTIALS_PATH)) {
|
|
1887
1417
|
return "oauth";
|
|
@@ -1897,16 +1427,6 @@ function detectClaudeAuthMethod() {
|
|
|
1897
1427
|
}
|
|
1898
1428
|
return "none";
|
|
1899
1429
|
}
|
|
1900
|
-
function detectCodexAuthMethod() {
|
|
1901
|
-
if (existsSync2(CODEX_AUTH_PATH)) {
|
|
1902
|
-
return "oauth";
|
|
1903
|
-
}
|
|
1904
|
-
if (ENGINE_ENV.OPENAI_API_KEY) {
|
|
1905
|
-
return "api_key";
|
|
1906
|
-
}
|
|
1907
|
-
if (ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD === "foundry") return "foundry";
|
|
1908
|
-
return "none";
|
|
1909
|
-
}
|
|
1910
1430
|
function detectCursorAuthMethod() {
|
|
1911
1431
|
return ENGINE_ENV.CURSOR_API_KEY ? "api_key" : "none";
|
|
1912
1432
|
}
|
|
@@ -2103,8 +1623,8 @@ var environmentDetailsService = new EnvironmentDetailsService();
|
|
|
2103
1623
|
|
|
2104
1624
|
// src/services/start-hook-logs-service.ts
|
|
2105
1625
|
import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile3, readdir as readdir2 } from "fs/promises";
|
|
2106
|
-
import { homedir as
|
|
2107
|
-
import { join as
|
|
1626
|
+
import { homedir as homedir5 } from "os";
|
|
1627
|
+
import { join as join8 } from "path";
|
|
2108
1628
|
|
|
2109
1629
|
// src/services/hook-log-files.ts
|
|
2110
1630
|
import { createHash } from "crypto";
|
|
@@ -2116,7 +1636,7 @@ function repoHookLogFilename(repoName) {
|
|
|
2116
1636
|
}
|
|
2117
1637
|
|
|
2118
1638
|
// src/services/start-hook-logs-service.ts
|
|
2119
|
-
var LOGS_DIR =
|
|
1639
|
+
var LOGS_DIR = join8(homedir5(), ".replicas", "start-hook-logs");
|
|
2120
1640
|
function withPreview(stored) {
|
|
2121
1641
|
const preview = buildHookOutputPreview(stored.output);
|
|
2122
1642
|
return { ...stored, ...preview };
|
|
@@ -2154,7 +1674,7 @@ var StartHookLogsService = class {
|
|
|
2154
1674
|
await this.ensureDir();
|
|
2155
1675
|
const log = { hookType, hookName, repoName: hookName, ...entry };
|
|
2156
1676
|
const filename = hookType === "environment" ? ENVIRONMENT_HOOK_LOG_FILENAME : repoHookLogFilename(hookName);
|
|
2157
|
-
await writeFile3(
|
|
1677
|
+
await writeFile3(join8(LOGS_DIR, filename), `${JSON.stringify(log, null, 2)}
|
|
2158
1678
|
`, "utf-8");
|
|
2159
1679
|
}
|
|
2160
1680
|
async saveEnvironmentLog(entry) {
|
|
@@ -2179,7 +1699,7 @@ var StartHookLogsService = class {
|
|
|
2179
1699
|
continue;
|
|
2180
1700
|
}
|
|
2181
1701
|
try {
|
|
2182
|
-
const raw = await readFile5(
|
|
1702
|
+
const raw = await readFile5(join8(LOGS_DIR, file), "utf-8");
|
|
2183
1703
|
const stored = normalizeStored(JSON.parse(raw));
|
|
2184
1704
|
if (stored) {
|
|
2185
1705
|
logs.push(withPreview(stored));
|
|
@@ -2198,7 +1718,7 @@ var StartHookLogsService = class {
|
|
|
2198
1718
|
async getFullOutput(hookType, hookName) {
|
|
2199
1719
|
const filename = hookType === "environment" ? ENVIRONMENT_HOOK_LOG_FILENAME : repoHookLogFilename(hookName);
|
|
2200
1720
|
try {
|
|
2201
|
-
const raw = await readFile5(
|
|
1721
|
+
const raw = await readFile5(join8(LOGS_DIR, filename), "utf-8");
|
|
2202
1722
|
const stored = normalizeStored(JSON.parse(raw));
|
|
2203
1723
|
if (!stored || stored.hookType !== hookType || stored.hookName !== hookName) {
|
|
2204
1724
|
return null;
|
|
@@ -2215,7 +1735,7 @@ var StartHookLogsService = class {
|
|
|
2215
1735
|
var startHookLogsService = new StartHookLogsService();
|
|
2216
1736
|
|
|
2217
1737
|
// src/services/replicas-config-service.ts
|
|
2218
|
-
var START_HOOKS_LOG =
|
|
1738
|
+
var START_HOOKS_LOG = join9(homedir6(), ".replicas", "startHooks.log");
|
|
2219
1739
|
var START_HOOKS_RUNNING_PROMPT = `IMPORTANT - Start Hooks Running:
|
|
2220
1740
|
Start hooks are shell commands/scripts set by repository owners that run on workspace startup.
|
|
2221
1741
|
These hooks are currently executing in the background. You can:
|
|
@@ -2226,7 +1746,7 @@ The start hooks may install dependencies, build projects, or perform other setup
|
|
|
2226
1746
|
If your task depends on setup being complete, check the log file before proceeding.`;
|
|
2227
1747
|
async function readReplicasConfigFromDir(dirPath) {
|
|
2228
1748
|
for (const filename of REPLICAS_CONFIG_FILENAMES) {
|
|
2229
|
-
const configPath =
|
|
1749
|
+
const configPath = join9(dirPath, filename);
|
|
2230
1750
|
if (!existsSync3(configPath)) {
|
|
2231
1751
|
continue;
|
|
2232
1752
|
}
|
|
@@ -2296,7 +1816,7 @@ var ReplicasConfigService = class {
|
|
|
2296
1816
|
const logLine = `[${timestamp}] ${message}
|
|
2297
1817
|
`;
|
|
2298
1818
|
try {
|
|
2299
|
-
await mkdir6(
|
|
1819
|
+
await mkdir6(join9(homedir6(), ".replicas"), { recursive: true });
|
|
2300
1820
|
await appendFile(START_HOOKS_LOG, logLine, "utf-8");
|
|
2301
1821
|
} catch (error) {
|
|
2302
1822
|
console.error("Failed to write to start hooks log:", error);
|
|
@@ -2308,7 +1828,7 @@ var ReplicasConfigService = class {
|
|
|
2308
1828
|
command: params.content,
|
|
2309
1829
|
label: "env start hook",
|
|
2310
1830
|
repoName: "environment",
|
|
2311
|
-
cwd:
|
|
1831
|
+
cwd: homedir6(),
|
|
2312
1832
|
timeout: params.timeoutMs ?? DEFAULT_START_HOOK_TIMEOUT_MS,
|
|
2313
1833
|
onOutputChunk: params.onOutputChunk
|
|
2314
1834
|
});
|
|
@@ -2431,7 +1951,7 @@ var ReplicasConfigService = class {
|
|
|
2431
1951
|
this.hooksCompleted = false;
|
|
2432
1952
|
this.hooksFailed = false;
|
|
2433
1953
|
try {
|
|
2434
|
-
await mkdir6(
|
|
1954
|
+
await mkdir6(join9(homedir6(), ".replicas"), { recursive: true });
|
|
2435
1955
|
await writeFile4(
|
|
2436
1956
|
START_HOOKS_LOG,
|
|
2437
1957
|
`=== Start Hooks Execution Log ===
|
|
@@ -2626,11 +2146,11 @@ var replicasConfigService = new ReplicasConfigService();
|
|
|
2626
2146
|
|
|
2627
2147
|
// src/services/event-service.ts
|
|
2628
2148
|
import { mkdir as mkdir7 } from "fs/promises";
|
|
2629
|
-
import { homedir as
|
|
2630
|
-
import { join as
|
|
2149
|
+
import { homedir as homedir7 } from "os";
|
|
2150
|
+
import { join as join10 } from "path";
|
|
2631
2151
|
import { randomUUID } from "crypto";
|
|
2632
|
-
var ENGINE_DIR =
|
|
2633
|
-
var EVENTS_FILE =
|
|
2152
|
+
var ENGINE_DIR = join10(homedir7(), ".replicas", "engine");
|
|
2153
|
+
var EVENTS_FILE = join10(ENGINE_DIR, "events.jsonl");
|
|
2634
2154
|
var EventService = class {
|
|
2635
2155
|
subscribers = /* @__PURE__ */ new Map();
|
|
2636
2156
|
writer = new StreamWriter();
|
|
@@ -2664,9 +2184,9 @@ var eventService = new EventService();
|
|
|
2664
2184
|
import { mkdir as mkdir8, readFile as readFile7 } from "fs/promises";
|
|
2665
2185
|
import { existsSync as existsSync4 } from "fs";
|
|
2666
2186
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
2667
|
-
import { homedir as
|
|
2668
|
-
import { dirname as dirname2, join as
|
|
2669
|
-
var PREVIEW_PORTS_FILE =
|
|
2187
|
+
import { homedir as homedir8 } from "os";
|
|
2188
|
+
import { dirname as dirname2, join as join11 } from "path";
|
|
2189
|
+
var PREVIEW_PORTS_FILE = join11(homedir8(), ".replicas", "preview-ports.json");
|
|
2670
2190
|
async function readPreviewsFile() {
|
|
2671
2191
|
try {
|
|
2672
2192
|
if (!existsSync4(PREVIEW_PORTS_FILE)) {
|
|
@@ -2778,8 +2298,7 @@ async function registerDesktopPreview() {
|
|
|
2778
2298
|
// src/services/chat/chat-service.ts
|
|
2779
2299
|
import { existsSync as existsSync8 } from "fs";
|
|
2780
2300
|
import { appendFile as appendFile4, copyFile, mkdir as mkdir17, readFile as readFile17, rename as rename3, rm as rm2 } from "fs/promises";
|
|
2781
|
-
import {
|
|
2782
|
-
import { join as join29 } from "path";
|
|
2301
|
+
import { join as join27 } from "path";
|
|
2783
2302
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
2784
2303
|
|
|
2785
2304
|
// src/managers/claude-manager.ts
|
|
@@ -2787,9 +2306,9 @@ import {
|
|
|
2787
2306
|
query
|
|
2788
2307
|
} from "@anthropic-ai/claude-agent-sdk";
|
|
2789
2308
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
2790
|
-
import { dirname as dirname4, join as
|
|
2309
|
+
import { dirname as dirname4, join as join15 } from "path";
|
|
2791
2310
|
import { mkdir as mkdir10 } from "fs/promises";
|
|
2792
|
-
import { homedir as
|
|
2311
|
+
import { homedir as homedir10 } from "os";
|
|
2793
2312
|
|
|
2794
2313
|
// src/utils/linear-converter.ts
|
|
2795
2314
|
function linearThoughtToResponse(thought) {
|
|
@@ -3174,8 +2693,8 @@ function extractPlanFromCodexAspNotification(notification) {
|
|
|
3174
2693
|
// src/utils/image-utils.ts
|
|
3175
2694
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
3176
2695
|
import { mkdir as mkdir9, unlink as unlink2, writeFile as writeFile5 } from "fs/promises";
|
|
3177
|
-
import { homedir as
|
|
3178
|
-
import { join as
|
|
2696
|
+
import { homedir as homedir9 } from "os";
|
|
2697
|
+
import { join as join12 } from "path";
|
|
3179
2698
|
function isImageMediaType(value) {
|
|
3180
2699
|
return IMAGE_MEDIA_TYPES.includes(value);
|
|
3181
2700
|
}
|
|
@@ -3275,14 +2794,14 @@ async function normalizeImages(images) {
|
|
|
3275
2794
|
}
|
|
3276
2795
|
return normalized;
|
|
3277
2796
|
}
|
|
3278
|
-
async function saveNormalizedImagesToTempFiles(images, tempImageDir =
|
|
2797
|
+
async function saveNormalizedImagesToTempFiles(images, tempImageDir = join12(homedir9(), ".replicas", "codex", "temp-images")) {
|
|
3279
2798
|
await mkdir9(tempImageDir, { recursive: true });
|
|
3280
2799
|
const tempPaths = [];
|
|
3281
2800
|
try {
|
|
3282
2801
|
for (const image of images) {
|
|
3283
2802
|
const ext = image.source.media_type.split("/")[1] || "png";
|
|
3284
2803
|
const filename = `img_${randomUUID3()}.${ext}`;
|
|
3285
|
-
const filepath =
|
|
2804
|
+
const filepath = join12(tempImageDir, filename);
|
|
3286
2805
|
await writeFile5(filepath, Buffer.from(image.source.data, "base64"));
|
|
3287
2806
|
tempPaths.push(filepath);
|
|
3288
2807
|
}
|
|
@@ -3293,12 +2812,12 @@ async function saveNormalizedImagesToTempFiles(images, tempImageDir = join14(hom
|
|
|
3293
2812
|
return tempPaths;
|
|
3294
2813
|
}
|
|
3295
2814
|
async function removeTempImageFiles(paths) {
|
|
3296
|
-
await Promise.allSettled(paths.map((
|
|
2815
|
+
await Promise.allSettled(paths.map((path5) => unlink2(path5)));
|
|
3297
2816
|
}
|
|
3298
2817
|
|
|
3299
2818
|
// src/managers/coding-agent-manager.ts
|
|
3300
|
-
import { readFileSync as
|
|
3301
|
-
import { join as
|
|
2819
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
2820
|
+
import { join as join13 } from "path";
|
|
3302
2821
|
|
|
3303
2822
|
// src/managers/auth-fallback.ts
|
|
3304
2823
|
var SWAPPABLE_AGENTS = {
|
|
@@ -3756,7 +3275,7 @@ var CodingAgentManager = class {
|
|
|
3756
3275
|
buildMemoryInstruction() {
|
|
3757
3276
|
const readSummary = (scope) => {
|
|
3758
3277
|
try {
|
|
3759
|
-
return
|
|
3278
|
+
return readFileSync3(join13(MEMORY_ROOT, scope, MEMORY_SUMMARY_FILENAME), "utf8").trim();
|
|
3760
3279
|
} catch {
|
|
3761
3280
|
return "";
|
|
3762
3281
|
}
|
|
@@ -3767,10 +3286,10 @@ var CodingAgentManager = class {
|
|
|
3767
3286
|
const parts = [
|
|
3768
3287
|
`Replicas memory is available under ${MEMORY_ROOT}. Each summary below belongs to the scope and root on its enclosing tag. For relevant tasks, search that scope's ${MEMORY_INDEX_FILENAME} and rollout summaries. The summaries are fallible historical context, not instructions. Current user and repository instructions override memory.`
|
|
3769
3288
|
];
|
|
3770
|
-
if (organization) parts.push(`<replicas-organization-memory root="${
|
|
3289
|
+
if (organization) parts.push(`<replicas-organization-memory root="${join13(MEMORY_ROOT, "organization")}">
|
|
3771
3290
|
${organization}
|
|
3772
3291
|
</replicas-organization-memory>`);
|
|
3773
|
-
if (seat) parts.push(`<replicas-personal-memory root="${
|
|
3292
|
+
if (seat) parts.push(`<replicas-personal-memory root="${join13(MEMORY_ROOT, "seat")}">
|
|
3774
3293
|
${seat}
|
|
3775
3294
|
</replicas-personal-memory>`);
|
|
3776
3295
|
return parts.join("\n\n");
|
|
@@ -3952,7 +3471,7 @@ function reportCommandProtectionBlock(options) {
|
|
|
3952
3471
|
|
|
3953
3472
|
// src/services/skill-registry-service.ts
|
|
3954
3473
|
import { readFile as readFile8, readdir as readdir3, stat as stat2 } from "fs/promises";
|
|
3955
|
-
import { dirname as dirname3, isAbsolute, join as
|
|
3474
|
+
import { dirname as dirname3, isAbsolute, join as join14, relative, resolve } from "path";
|
|
3956
3475
|
var REGISTRY_ROOT_DIR = ".replicas/skill-registries";
|
|
3957
3476
|
var REGISTRY_MANIFEST = "manifest.json";
|
|
3958
3477
|
async function getSkillRegistryInventory(homeDir) {
|
|
@@ -3985,7 +3504,7 @@ async function getSkillRegistryInventory(homeDir) {
|
|
|
3985
3504
|
async function buildClaudeRegistryConfig(homeDir) {
|
|
3986
3505
|
const inventory = await getSkillRegistryInventory(homeDir);
|
|
3987
3506
|
return {
|
|
3988
|
-
plugins: inventory.claudePluginRoots.map((
|
|
3507
|
+
plugins: inventory.claudePluginRoots.map((path5) => ({ type: "local", path: path5 })),
|
|
3989
3508
|
enableAllSkills: inventory.claudePluginRoots.length > 0 || inventory.standaloneSkills.length > 0
|
|
3990
3509
|
};
|
|
3991
3510
|
}
|
|
@@ -4013,10 +3532,10 @@ async function scanRegistry(registryDir) {
|
|
|
4013
3532
|
}
|
|
4014
3533
|
async function findSkillCollections(registryDir) {
|
|
4015
3534
|
const candidateRoots = [
|
|
4016
|
-
{ source: "skills", root:
|
|
4017
|
-
{ source: "agents", root:
|
|
4018
|
-
{ source: "codex", root:
|
|
4019
|
-
{ source: "claude", root:
|
|
3535
|
+
{ source: "skills", root: join14(registryDir, "skills") },
|
|
3536
|
+
{ source: "agents", root: join14(registryDir, ".agents", "skills") },
|
|
3537
|
+
{ source: "codex", root: join14(registryDir, ".codex", "skills") },
|
|
3538
|
+
{ source: "claude", root: join14(registryDir, ".claude", "skills") }
|
|
4020
3539
|
];
|
|
4021
3540
|
const collections = [];
|
|
4022
3541
|
for (const { source, root } of candidateRoots) {
|
|
@@ -4030,9 +3549,9 @@ async function findSkillCollections(registryDir) {
|
|
|
4030
3549
|
async function findSkillDirsInRoot(root) {
|
|
4031
3550
|
const skillDirs = [];
|
|
4032
3551
|
for (const dirent of await safeReadDir(root)) {
|
|
4033
|
-
const skillDir =
|
|
3552
|
+
const skillDir = join14(root, dirent.name);
|
|
4034
3553
|
if (!await isDirectoryDirent(dirent, skillDir)) continue;
|
|
4035
|
-
if (await fileExists(
|
|
3554
|
+
if (await fileExists(join14(skillDir, "SKILL.md"))) {
|
|
4036
3555
|
skillDirs.push(skillDir);
|
|
4037
3556
|
}
|
|
4038
3557
|
}
|
|
@@ -4042,9 +3561,9 @@ async function findTopLevelSkills(registryDir) {
|
|
|
4042
3561
|
const skills = [];
|
|
4043
3562
|
for (const dirent of await safeReadDir(registryDir)) {
|
|
4044
3563
|
if (dirent.name.startsWith(".") || dirent.name === "skills" || dirent.name === "plugins") continue;
|
|
4045
|
-
const skillDir =
|
|
3564
|
+
const skillDir = join14(registryDir, dirent.name);
|
|
4046
3565
|
if (!await isDirectoryDirent(dirent, skillDir)) continue;
|
|
4047
|
-
if (await fileExists(
|
|
3566
|
+
if (await fileExists(join14(skillDir, "SKILL.md"))) {
|
|
4048
3567
|
skills.push({ source: "root", skillDir });
|
|
4049
3568
|
}
|
|
4050
3569
|
}
|
|
@@ -4055,10 +3574,10 @@ async function findClaudePluginRoots(registryDir) {
|
|
|
4055
3574
|
async function walk(dir) {
|
|
4056
3575
|
for (const dirent of await safeReadDir(dir)) {
|
|
4057
3576
|
if (dirent.name === ".git") continue;
|
|
4058
|
-
const child =
|
|
3577
|
+
const child = join14(dir, dirent.name);
|
|
4059
3578
|
if (!await isDirectoryDirent(dirent, child)) continue;
|
|
4060
3579
|
if (dirent.name === ".claude-plugin") {
|
|
4061
|
-
if (await fileExists(
|
|
3580
|
+
if (await fileExists(join14(child, "plugin.json"))) {
|
|
4062
3581
|
roots.push(dirname3(child));
|
|
4063
3582
|
}
|
|
4064
3583
|
continue;
|
|
@@ -4070,7 +3589,7 @@ async function findClaudePluginRoots(registryDir) {
|
|
|
4070
3589
|
return uniqueStrings(roots);
|
|
4071
3590
|
}
|
|
4072
3591
|
async function hasCodexMarketplace(registryDir) {
|
|
4073
|
-
return await fileExists(
|
|
3592
|
+
return await fileExists(join14(registryDir, ".agents", "plugins", "marketplace.json")) || await fileExists(join14(registryDir, ".codex", "plugins", "marketplace.json"));
|
|
4074
3593
|
}
|
|
4075
3594
|
async function installCodexRegistryPlugins(client2, inventory) {
|
|
4076
3595
|
const cwds = inventory.codexMarketplaceCwds;
|
|
@@ -4112,10 +3631,10 @@ async function readManifest(homeDir) {
|
|
|
4112
3631
|
}
|
|
4113
3632
|
}
|
|
4114
3633
|
function getRegistryRoot(homeDir) {
|
|
4115
|
-
return
|
|
3634
|
+
return join14(homeDir, REGISTRY_ROOT_DIR);
|
|
4116
3635
|
}
|
|
4117
3636
|
function getManifestPath(homeDir) {
|
|
4118
|
-
return
|
|
3637
|
+
return join14(getRegistryRoot(homeDir), REGISTRY_MANIFEST);
|
|
4119
3638
|
}
|
|
4120
3639
|
function emptyInventory(registryRoot) {
|
|
4121
3640
|
return {
|
|
@@ -4143,31 +3662,31 @@ function uniqueStandaloneSkills(skills) {
|
|
|
4143
3662
|
}
|
|
4144
3663
|
return unique;
|
|
4145
3664
|
}
|
|
4146
|
-
async function safeReadDir(
|
|
3665
|
+
async function safeReadDir(path5) {
|
|
4147
3666
|
try {
|
|
4148
|
-
return await readdir3(
|
|
3667
|
+
return await readdir3(path5, { withFileTypes: true });
|
|
4149
3668
|
} catch (error) {
|
|
4150
3669
|
if (isNotFoundError(error)) return [];
|
|
4151
3670
|
throw error;
|
|
4152
3671
|
}
|
|
4153
3672
|
}
|
|
4154
|
-
async function isDirectoryDirent(dirent,
|
|
3673
|
+
async function isDirectoryDirent(dirent, path5) {
|
|
4155
3674
|
if (dirent.isDirectory()) return true;
|
|
4156
3675
|
if (!dirent.isSymbolicLink()) return false;
|
|
4157
|
-
return directoryExists(
|
|
3676
|
+
return directoryExists(path5);
|
|
4158
3677
|
}
|
|
4159
|
-
async function directoryExists(
|
|
3678
|
+
async function directoryExists(path5) {
|
|
4160
3679
|
try {
|
|
4161
|
-
const pathStat = await stat2(
|
|
3680
|
+
const pathStat = await stat2(path5);
|
|
4162
3681
|
return pathStat.isDirectory();
|
|
4163
3682
|
} catch (error) {
|
|
4164
3683
|
if (isNotFoundError(error)) return false;
|
|
4165
3684
|
throw error;
|
|
4166
3685
|
}
|
|
4167
3686
|
}
|
|
4168
|
-
async function fileExists(
|
|
3687
|
+
async function fileExists(path5) {
|
|
4169
3688
|
try {
|
|
4170
|
-
const pathStat = await stat2(
|
|
3689
|
+
const pathStat = await stat2(path5);
|
|
4171
3690
|
return pathStat.isFile();
|
|
4172
3691
|
} catch (error) {
|
|
4173
3692
|
if (isNotFoundError(error)) return false;
|
|
@@ -4562,7 +4081,7 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
4562
4081
|
authRetrying = false;
|
|
4563
4082
|
constructor(options) {
|
|
4564
4083
|
super({ ...options, provider: AGENT.CLAUDE });
|
|
4565
|
-
this.historyFilePath = options.historyFilePath ??
|
|
4084
|
+
this.historyFilePath = options.historyFilePath ?? join15(homedir10(), ".replicas", "claude", "history.jsonl");
|
|
4566
4085
|
this.historyFile = new CodexHistoryFile(this.historyFilePath);
|
|
4567
4086
|
this.systemPromptOverride = options.systemPromptOverride;
|
|
4568
4087
|
this.toolsOverride = options.tools;
|
|
@@ -5616,7 +5135,7 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
5616
5135
|
|
|
5617
5136
|
// src/managers/codex-asp/codex-asp-manager.ts
|
|
5618
5137
|
import { readdir as readdir4 } from "fs/promises";
|
|
5619
|
-
import { join as
|
|
5138
|
+
import { join as join17 } from "path";
|
|
5620
5139
|
|
|
5621
5140
|
// src/managers/codex-asp/asp-host.ts
|
|
5622
5141
|
var hostPromise = null;
|
|
@@ -5628,9 +5147,11 @@ async function getCodexAspHost() {
|
|
|
5628
5147
|
}
|
|
5629
5148
|
hostPromise ??= (async () => {
|
|
5630
5149
|
try {
|
|
5150
|
+
const oauthOptions = await codexTokenManager.prepareAspOauthOptions();
|
|
5631
5151
|
const process2 = new AppServerProcess({
|
|
5632
5152
|
cwd: ENGINE_ENV.WORKSPACE_ROOT,
|
|
5633
|
-
env: buildCodexAgentEnv()
|
|
5153
|
+
env: buildCodexAgentEnv(),
|
|
5154
|
+
...oauthOptions
|
|
5634
5155
|
});
|
|
5635
5156
|
const { client: client2 } = await process2.start();
|
|
5636
5157
|
activeProcess = process2;
|
|
@@ -5729,7 +5250,7 @@ var CodexQuotaStatusTracker = class {
|
|
|
5729
5250
|
};
|
|
5730
5251
|
|
|
5731
5252
|
// src/managers/codex-asp/mappers.ts
|
|
5732
|
-
import { existsSync as existsSync5, readFileSync as
|
|
5253
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
|
|
5733
5254
|
var localImageCache = /* @__PURE__ */ new Map();
|
|
5734
5255
|
var DEFAULT_MODEL = DEFAULT_CODEX_MODEL;
|
|
5735
5256
|
var THREAD_START_METHOD = "thread/start";
|
|
@@ -5851,16 +5372,16 @@ function transcriptItemsForTurn(turn) {
|
|
|
5851
5372
|
const otherItems = turn.items.filter((item) => item.type !== "userMessage");
|
|
5852
5373
|
return [...userItems, ...otherItems];
|
|
5853
5374
|
}
|
|
5854
|
-
function userImageForLocalPath(
|
|
5855
|
-
const cached = localImageCache.get(
|
|
5375
|
+
function userImageForLocalPath(path5) {
|
|
5376
|
+
const cached = localImageCache.get(path5);
|
|
5856
5377
|
if (cached) return cached;
|
|
5857
|
-
if (!existsSync5(
|
|
5378
|
+
if (!existsSync5(path5)) return null;
|
|
5858
5379
|
const image = {
|
|
5859
5380
|
type: "image",
|
|
5860
|
-
mediaType: inferMediaType(
|
|
5861
|
-
data:
|
|
5381
|
+
mediaType: inferMediaType(path5),
|
|
5382
|
+
data: readFileSync4(path5).toString("base64")
|
|
5862
5383
|
};
|
|
5863
|
-
if (image.data.length > 0) localImageCache.set(
|
|
5384
|
+
if (image.data.length > 0) localImageCache.set(path5, image);
|
|
5864
5385
|
return image;
|
|
5865
5386
|
}
|
|
5866
5387
|
function userImagesForInput(input) {
|
|
@@ -6258,9 +5779,9 @@ async function buildTurnInput(request) {
|
|
|
6258
5779
|
}
|
|
6259
5780
|
const normalizedImages = await normalizeImages(request.images);
|
|
6260
5781
|
const tempImagePaths = await saveNormalizedImagesToTempFiles(normalizedImages);
|
|
6261
|
-
input.push(...tempImagePaths.map((
|
|
5782
|
+
input.push(...tempImagePaths.map((path5) => ({
|
|
6262
5783
|
type: "localImage",
|
|
6263
|
-
path:
|
|
5784
|
+
path: path5
|
|
6264
5785
|
})));
|
|
6265
5786
|
return { input, tempImagePaths };
|
|
6266
5787
|
}
|
|
@@ -6349,19 +5870,19 @@ var TranscriptUpdateCoalescer = class {
|
|
|
6349
5870
|
};
|
|
6350
5871
|
|
|
6351
5872
|
// src/services/chat/history-paths.ts
|
|
6352
|
-
import { homedir as
|
|
6353
|
-
import { join as
|
|
6354
|
-
var ENGINE_DIR2 =
|
|
6355
|
-
var CHATS_FILE =
|
|
6356
|
-
var CLAUDE_HISTORY_DIR =
|
|
6357
|
-
var RELAY_HISTORY_DIR =
|
|
6358
|
-
var CODEX_HISTORY_DIR =
|
|
6359
|
-
var CURSOR_HISTORY_DIR =
|
|
6360
|
-
var OPENCODE_HISTORY_DIR =
|
|
6361
|
-
var PI_HISTORY_DIR =
|
|
6362
|
-
var DEEPSEEK_HISTORY_DIR =
|
|
6363
|
-
var FX_HISTORY_DIR =
|
|
6364
|
-
var KIMI_HISTORY_DIR =
|
|
5873
|
+
import { homedir as homedir11 } from "os";
|
|
5874
|
+
import { join as join16 } from "path";
|
|
5875
|
+
var ENGINE_DIR2 = join16(homedir11(), ".replicas", "engine");
|
|
5876
|
+
var CHATS_FILE = join16(ENGINE_DIR2, "chats.json");
|
|
5877
|
+
var CLAUDE_HISTORY_DIR = join16(ENGINE_DIR2, "claude-histories");
|
|
5878
|
+
var RELAY_HISTORY_DIR = join16(ENGINE_DIR2, "relay-histories");
|
|
5879
|
+
var CODEX_HISTORY_DIR = join16(ENGINE_DIR2, "codex-histories");
|
|
5880
|
+
var CURSOR_HISTORY_DIR = join16(ENGINE_DIR2, "cursor-histories");
|
|
5881
|
+
var OPENCODE_HISTORY_DIR = join16(ENGINE_DIR2, "opencode-histories");
|
|
5882
|
+
var PI_HISTORY_DIR = join16(ENGINE_DIR2, "pi-histories");
|
|
5883
|
+
var DEEPSEEK_HISTORY_DIR = join16(ENGINE_DIR2, "deepseek-histories");
|
|
5884
|
+
var FX_HISTORY_DIR = join16(ENGINE_DIR2, "fx-histories");
|
|
5885
|
+
var KIMI_HISTORY_DIR = join16(ENGINE_DIR2, "kimi-histories");
|
|
6365
5886
|
var HISTORY_DIR_BY_PROVIDER = {
|
|
6366
5887
|
claude: CLAUDE_HISTORY_DIR,
|
|
6367
5888
|
relay: RELAY_HISTORY_DIR,
|
|
@@ -6420,7 +5941,7 @@ async function readCodexAspThreadHistory(threadId) {
|
|
|
6420
5941
|
}
|
|
6421
5942
|
for (const entry of entries) {
|
|
6422
5943
|
if (!entry.isFile() || !entry.name.endsWith(".jsonl") || entry.name.endsWith(".pages.jsonl")) continue;
|
|
6423
|
-
const history = await new CodexHistoryFile(
|
|
5944
|
+
const history = await new CodexHistoryFile(join17(CODEX_HISTORY_DIR, entry.name)).load();
|
|
6424
5945
|
const transcript = history.transcriptsByThreadId.get(threadId);
|
|
6425
5946
|
if (transcript) {
|
|
6426
5947
|
return {
|
|
@@ -6799,6 +6320,11 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
6799
6320
|
return;
|
|
6800
6321
|
}
|
|
6801
6322
|
}
|
|
6323
|
+
if (terminalError instanceof CodexAspAuthMethodChangedError) {
|
|
6324
|
+
const retryFailure = await this.restartAndRetry(dispatch);
|
|
6325
|
+
if (!retryFailure) return;
|
|
6326
|
+
terminalError = retryFailure.error;
|
|
6327
|
+
}
|
|
6802
6328
|
if (isCodexAuthError(terminalError)) {
|
|
6803
6329
|
const refreshed = await codexTokenManager.fetchFreshCredentials(
|
|
6804
6330
|
terminalError instanceof Error ? terminalError.message : String(terminalError),
|
|
@@ -7163,6 +6689,7 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
7163
6689
|
dispatchAspNotification(notification, handlers);
|
|
7164
6690
|
};
|
|
7165
6691
|
const onServerRequest = (serverRequest) => {
|
|
6692
|
+
if (serverRequest.method === "account/chatgptAuthTokens/refresh") return;
|
|
7166
6693
|
void this.respondToServerRequest(host, serverRequest).catch((error) => {
|
|
7167
6694
|
console.warn(`[CodexAspManager] Failed to handle ASP server request ${serverRequest.method}:`, error);
|
|
7168
6695
|
host.client.reject(serverRequest.id, -32603, `Failed to handle ${serverRequest.method}`);
|
|
@@ -7171,6 +6698,10 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
7171
6698
|
const onDispose = (reason) => {
|
|
7172
6699
|
this.threadAttached = false;
|
|
7173
6700
|
this.activeTurnId = null;
|
|
6701
|
+
if (reason instanceof CodexAspAuthMethodChangedError) {
|
|
6702
|
+
rejectDisposed(reason);
|
|
6703
|
+
return;
|
|
6704
|
+
}
|
|
7174
6705
|
const turnLabel = observedTurnId ? ` ${observedTurnId}` : "";
|
|
7175
6706
|
rejectDisposed(new Error(`Codex ASP client disposed before turn${turnLabel} completed: ${reason.message}`));
|
|
7176
6707
|
};
|
|
@@ -7320,7 +6851,6 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
7320
6851
|
return;
|
|
7321
6852
|
}
|
|
7322
6853
|
case "item/tool/requestUserInput":
|
|
7323
|
-
case "account/chatgptAuthTokens/refresh":
|
|
7324
6854
|
case "attestation/generate":
|
|
7325
6855
|
host.client.reject(requestId, -32601, `Replicas does not support ASP server request ${method}`);
|
|
7326
6856
|
return;
|
|
@@ -7762,13 +7292,14 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
7762
7292
|
|
|
7763
7293
|
// src/managers/cursor-manager.ts
|
|
7764
7294
|
import { mkdir as mkdir11, readFile as readFile10, readdir as readdir5 } from "fs/promises";
|
|
7765
|
-
import { basename, dirname as dirname5, extname, join as
|
|
7295
|
+
import { basename, dirname as dirname5, extname, join as join18 } from "path";
|
|
7766
7296
|
import { parse as parseYaml } from "yaml";
|
|
7767
7297
|
import { Agent as CursorAgent } from "@cursor/sdk";
|
|
7768
7298
|
var CURSOR_SLASH_COMMANDS_CACHE_MS = 3e4;
|
|
7769
7299
|
var CURSOR_STREAM_INACTIVITY_TIMEOUT_MS = 30 * 6e4;
|
|
7770
7300
|
var CURSOR_RUN_SETTLE_TIMEOUT_MS = 3e4;
|
|
7771
7301
|
var CURSOR_CANCEL_TIMEOUT_MS = 1e4;
|
|
7302
|
+
var CURSOR_RECONNECT_NOTICE_DELAY_MS = 15e3;
|
|
7772
7303
|
var TURN_ABORTED = /* @__PURE__ */ Symbol("cursor-turn-aborted");
|
|
7773
7304
|
var CURSOR_COMPOSER_CONTEXT_WINDOW = 2e5;
|
|
7774
7305
|
var CURSOR_CATEGORY_COLORS = {
|
|
@@ -7777,6 +7308,19 @@ var CURSOR_CATEGORY_COLORS = {
|
|
|
7777
7308
|
cacheWrite: "#e5c07b",
|
|
7778
7309
|
output: "#56b6c2"
|
|
7779
7310
|
};
|
|
7311
|
+
var CURSOR_TRANSPORT_ERROR_PATTERNS = [
|
|
7312
|
+
/connection failed/,
|
|
7313
|
+
/connection stalled/,
|
|
7314
|
+
/cursor run stalled/,
|
|
7315
|
+
/stream closed/,
|
|
7316
|
+
/stream ended/,
|
|
7317
|
+
/nghttp2_/,
|
|
7318
|
+
/err_http2_stream_error/,
|
|
7319
|
+
/write ecanceled/
|
|
7320
|
+
];
|
|
7321
|
+
function isCursorTransportError(text) {
|
|
7322
|
+
return isTransientErrorText(text, { extraPatterns: CURSOR_TRANSPORT_ERROR_PATTERNS });
|
|
7323
|
+
}
|
|
7780
7324
|
function finiteNumber(value) {
|
|
7781
7325
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
7782
7326
|
}
|
|
@@ -7821,7 +7365,7 @@ async function listCursorCommandsInDirectory(directory) {
|
|
|
7821
7365
|
const name = basename(entry.name, ".md");
|
|
7822
7366
|
let description;
|
|
7823
7367
|
try {
|
|
7824
|
-
description = extractCursorCommandDescription(await readFile10(
|
|
7368
|
+
description = extractCursorCommandDescription(await readFile10(join18(directory, entry.name), "utf8"));
|
|
7825
7369
|
} catch (error) {
|
|
7826
7370
|
console.warn("[CursorManager] Failed to read slash command file:", error);
|
|
7827
7371
|
}
|
|
@@ -7836,14 +7380,16 @@ var CursorManager = class extends CodingAgentManager {
|
|
|
7836
7380
|
abortActiveTurn = null;
|
|
7837
7381
|
blockedToolCallIds = /* @__PURE__ */ new Set();
|
|
7838
7382
|
pendingCursorBlockReason = null;
|
|
7383
|
+
reconnectNoticeVisible = false;
|
|
7839
7384
|
instructionsDelivered = false;
|
|
7385
|
+
resumeSessionId = null;
|
|
7840
7386
|
historyFilePath;
|
|
7841
7387
|
historyFile;
|
|
7842
7388
|
slashCommandsCache = null;
|
|
7843
7389
|
slashCommandsRequest = null;
|
|
7844
7390
|
constructor(options) {
|
|
7845
7391
|
super(options);
|
|
7846
|
-
this.historyFilePath = options.historyFilePath ??
|
|
7392
|
+
this.historyFilePath = options.historyFilePath ?? join18(ENGINE_ENV.HOME_DIR, ".replicas", "cursor", "history.jsonl");
|
|
7847
7393
|
this.historyFile = new CodexHistoryFile(this.historyFilePath);
|
|
7848
7394
|
this.initializeManager(this.processMessageInternal.bind(this));
|
|
7849
7395
|
}
|
|
@@ -7868,19 +7414,42 @@ var CursorManager = class extends CodingAgentManager {
|
|
|
7868
7414
|
console.error("[CursorManager] Failed to cancel Cursor run:", error);
|
|
7869
7415
|
}
|
|
7870
7416
|
}
|
|
7871
|
-
|
|
7417
|
+
closeAgent() {
|
|
7418
|
+
const agent = this.agent;
|
|
7419
|
+
this.agent = null;
|
|
7872
7420
|
try {
|
|
7873
|
-
|
|
7421
|
+
agent?.close();
|
|
7874
7422
|
} catch (error) {
|
|
7875
7423
|
console.error("[CursorManager] Failed to close Cursor agent:", error);
|
|
7876
7424
|
}
|
|
7877
|
-
|
|
7425
|
+
}
|
|
7426
|
+
dispose() {
|
|
7427
|
+
this.closeAgent();
|
|
7428
|
+
}
|
|
7429
|
+
mayBeReconnecting() {
|
|
7430
|
+
return this.reconnectNoticeVisible;
|
|
7431
|
+
}
|
|
7432
|
+
setReconnectNoticeVisible(value) {
|
|
7433
|
+
if (this.reconnectNoticeVisible === value) return;
|
|
7434
|
+
this.reconnectNoticeVisible = value;
|
|
7435
|
+
this.emitSyntheticEvent(CURSOR_CONNECTION_STATUS_EVENT_TYPE, { mayBeReconnecting: value });
|
|
7436
|
+
}
|
|
7437
|
+
// Cursor keeps a thread's partial response and tool results, so once the model
|
|
7438
|
+
// has acted the session must stay resumable even if the run later fails or is
|
|
7439
|
+
// interrupted — otherwise a later user retry strands that work on an orphaned
|
|
7440
|
+
// thread. The same activity proves the instruction-bearing
|
|
7441
|
+
// first message reached the thread, so instructions must not be re-sent.
|
|
7442
|
+
async retainThread(agentId) {
|
|
7443
|
+
if (this.instructionsDelivered && this.resumeSessionId === agentId) return;
|
|
7444
|
+
this.instructionsDelivered = true;
|
|
7445
|
+
this.resumeSessionId = agentId;
|
|
7446
|
+
await this.onSaveSessionId(agentId);
|
|
7878
7447
|
}
|
|
7879
7448
|
async getHistory(page = {}) {
|
|
7880
7449
|
await this.historyFile.flush();
|
|
7881
7450
|
const history = await this.historyFile.loadEventsPage(page);
|
|
7882
7451
|
return {
|
|
7883
|
-
thread_id: this.agent?.agentId ?? this.initialSessionId,
|
|
7452
|
+
thread_id: this.agent?.agentId ?? this.resumeSessionId ?? this.initialSessionId,
|
|
7884
7453
|
...history,
|
|
7885
7454
|
goal: null
|
|
7886
7455
|
};
|
|
@@ -7894,7 +7463,7 @@ var CursorManager = class extends CodingAgentManager {
|
|
|
7894
7463
|
this.slashCommandsRequest ??= (async () => {
|
|
7895
7464
|
try {
|
|
7896
7465
|
const repoDirectories = await getAgentAdditionalDirectories();
|
|
7897
|
-
const commandDirectories = [this.workingDirectory, ...repoDirectories, ENGINE_ENV.HOME_DIR].map((directory) =>
|
|
7466
|
+
const commandDirectories = [this.workingDirectory, ...repoDirectories, ENGINE_ENV.HOME_DIR].map((directory) => join18(directory, ".cursor", "commands"));
|
|
7898
7467
|
const commands = mergeSlashCommands(
|
|
7899
7468
|
...await Promise.all(commandDirectories.map(listCursorCommandsInDirectory))
|
|
7900
7469
|
);
|
|
@@ -7914,8 +7483,9 @@ var CursorManager = class extends CodingAgentManager {
|
|
|
7914
7483
|
}
|
|
7915
7484
|
const model = { id: request.model ?? DEFAULT_CURSOR_MODEL };
|
|
7916
7485
|
const settingSources = ["project", "user"];
|
|
7917
|
-
const local = { cwd: this.workingDirectory, settingSources };
|
|
7918
|
-
|
|
7486
|
+
const local = { cwd: this.workingDirectory, settingSources, enableAgentRetries: true };
|
|
7487
|
+
const resumeId = this.resumeSessionId ?? this.initialSessionId;
|
|
7488
|
+
this.agent = resumeId ? await CursorAgent.resume(resumeId, {
|
|
7919
7489
|
apiKey,
|
|
7920
7490
|
model,
|
|
7921
7491
|
local
|
|
@@ -7924,89 +7494,142 @@ var CursorManager = class extends CodingAgentManager {
|
|
|
7924
7494
|
model,
|
|
7925
7495
|
local
|
|
7926
7496
|
});
|
|
7927
|
-
if (
|
|
7497
|
+
if (resumeId) await this.onSaveSessionId(this.agent.agentId);
|
|
7928
7498
|
return this.agent;
|
|
7929
7499
|
}
|
|
7930
7500
|
async processMessageInternal(request) {
|
|
7931
7501
|
let run = null;
|
|
7502
|
+
let agent = null;
|
|
7503
|
+
let sawCursorActivity = false;
|
|
7504
|
+
let reconnectNoticeTimer = null;
|
|
7932
7505
|
const aborted = new Promise((resolve5) => {
|
|
7933
7506
|
this.abortActiveTurn = () => resolve5(TURN_ABORTED);
|
|
7934
7507
|
});
|
|
7935
7508
|
const linearSessionId = ENGINE_ENV.REPLICAS_LINEAR_SESSION_ID;
|
|
7936
7509
|
const linearForwarder = new LinearEventForwarder(linearSessionId);
|
|
7510
|
+
const clearReconnectNoticeTimer = () => {
|
|
7511
|
+
if (!reconnectNoticeTimer) return;
|
|
7512
|
+
clearTimeout(reconnectNoticeTimer);
|
|
7513
|
+
reconnectNoticeTimer = null;
|
|
7514
|
+
};
|
|
7515
|
+
const markCursorActivity = () => {
|
|
7516
|
+
sawCursorActivity = true;
|
|
7517
|
+
clearReconnectNoticeTimer();
|
|
7518
|
+
this.setReconnectNoticeVisible(false);
|
|
7519
|
+
};
|
|
7937
7520
|
try {
|
|
7938
7521
|
const includeInstructions = !this.initialSessionId && !this.instructionsDelivered;
|
|
7939
7522
|
const message = await this.toCursorMessage(request, includeInstructions);
|
|
7940
|
-
const agent = await this.ensureAgent(request);
|
|
7941
7523
|
const model = request.model ?? DEFAULT_CURSOR_MODEL;
|
|
7942
7524
|
this.activeModel = model;
|
|
7943
|
-
|
|
7944
|
-
|
|
7945
|
-
|
|
7946
|
-
|
|
7947
|
-
|
|
7948
|
-
|
|
7949
|
-
|
|
7950
|
-
|
|
7951
|
-
|
|
7952
|
-
|
|
7953
|
-
|
|
7954
|
-
|
|
7955
|
-
|
|
7956
|
-
|
|
7957
|
-
|
|
7958
|
-
|
|
7959
|
-
|
|
7960
|
-
|
|
7961
|
-
|
|
7962
|
-
|
|
7963
|
-
const nextPromise = events.next();
|
|
7964
|
-
nextPromise.catch(() => {
|
|
7525
|
+
let failure = null;
|
|
7526
|
+
try {
|
|
7527
|
+
reconnectNoticeTimer = setTimeout(() => {
|
|
7528
|
+
if (!sawCursorActivity && this.abortActiveTurn) {
|
|
7529
|
+
this.setReconnectNoticeVisible(true);
|
|
7530
|
+
}
|
|
7531
|
+
}, CURSOR_RECONNECT_NOTICE_DELAY_MS);
|
|
7532
|
+
agent = await this.ensureAgent(request);
|
|
7533
|
+
this.recordHistoryEvent("event_msg", {
|
|
7534
|
+
type: "user_message",
|
|
7535
|
+
message: request.message
|
|
7536
|
+
}, this.historyFile);
|
|
7537
|
+
run = await agent.send(message, {
|
|
7538
|
+
model: { id: model },
|
|
7539
|
+
mode: request.planMode ? "plan" : "agent",
|
|
7540
|
+
onDelta: async (args) => {
|
|
7541
|
+
markCursorActivity();
|
|
7542
|
+
this.recordCursorContextUsage(args.update);
|
|
7543
|
+
await this.handleCursorToolCall(cursorToolInputFromDelta(args.update));
|
|
7544
|
+
}
|
|
7965
7545
|
});
|
|
7966
|
-
|
|
7967
|
-
|
|
7968
|
-
|
|
7969
|
-
|
|
7970
|
-
if (next === TIMEOUT) {
|
|
7971
|
-
throw new Error(`Cursor run stalled: no events for ${CURSOR_STREAM_INACTIVITY_TIMEOUT_MS / 6e4} minutes; cancelling the run`);
|
|
7546
|
+
this.activeRun = run;
|
|
7547
|
+
if (this.pendingCursorBlockReason) {
|
|
7548
|
+
await run.cancel();
|
|
7549
|
+
throw new Error(this.pendingCursorBlockReason);
|
|
7972
7550
|
}
|
|
7973
|
-
|
|
7974
|
-
|
|
7975
|
-
|
|
7551
|
+
const events = run.stream()[Symbol.asyncIterator]();
|
|
7552
|
+
let interrupted = false;
|
|
7553
|
+
while (true) {
|
|
7554
|
+
const nextPromise = events.next();
|
|
7555
|
+
nextPromise.catch(() => {
|
|
7556
|
+
});
|
|
7557
|
+
const next = await raceWithTimeout(
|
|
7558
|
+
Promise.race([nextPromise, aborted]),
|
|
7559
|
+
CURSOR_STREAM_INACTIVITY_TIMEOUT_MS
|
|
7560
|
+
);
|
|
7561
|
+
if (next === TIMEOUT) {
|
|
7562
|
+
throw new Error(`Cursor run stalled: no events for ${CURSOR_STREAM_INACTIVITY_TIMEOUT_MS / 6e4} minutes; cancelling the run`);
|
|
7563
|
+
}
|
|
7564
|
+
if (next === TURN_ABORTED) {
|
|
7565
|
+
interrupted = true;
|
|
7566
|
+
break;
|
|
7567
|
+
}
|
|
7568
|
+
if (next.done) break;
|
|
7569
|
+
markCursorActivity();
|
|
7570
|
+
const event = next.value;
|
|
7571
|
+
this.recordHistoryEvent(`cursor-${event.type}`, event, this.historyFile);
|
|
7572
|
+
if (event.type === "tool_call" && event.status === "running") {
|
|
7573
|
+
await this.handleCursorToolCall(cursorToolInputFromMessage(event));
|
|
7574
|
+
}
|
|
7575
|
+
if (linearSessionId) {
|
|
7576
|
+
linearForwarder.sendEvent(convertCursorEvent(event, linearSessionId));
|
|
7577
|
+
}
|
|
7976
7578
|
}
|
|
7977
|
-
if (
|
|
7978
|
-
|
|
7979
|
-
|
|
7980
|
-
|
|
7981
|
-
await this.handleCursorToolCall(cursorToolInputFromMessage(event));
|
|
7579
|
+
if (interrupted) {
|
|
7580
|
+
if (sawCursorActivity) await this.retainThread(agent.agentId);
|
|
7581
|
+
await this.cancelRun(run);
|
|
7582
|
+
return;
|
|
7982
7583
|
}
|
|
7983
|
-
|
|
7984
|
-
|
|
7584
|
+
const result = await raceWithTimeout(run.wait(), CURSOR_RUN_SETTLE_TIMEOUT_MS);
|
|
7585
|
+
if (result === TIMEOUT) {
|
|
7586
|
+
throw new Error("Cursor run stalled after its event stream ended");
|
|
7985
7587
|
}
|
|
7986
|
-
|
|
7987
|
-
|
|
7588
|
+
if (result.status === "error") {
|
|
7589
|
+
const detail = await this.readRunErrorDetail(agent.agentId, result.id);
|
|
7590
|
+
const text = detail || result.result || "Cursor run failed";
|
|
7591
|
+
failure = {
|
|
7592
|
+
text,
|
|
7593
|
+
runId: result.id,
|
|
7594
|
+
...result.requestId ? { requestId: result.requestId } : {},
|
|
7595
|
+
transport: isCursorTransportError(text)
|
|
7596
|
+
};
|
|
7597
|
+
} else {
|
|
7598
|
+
await this.retainThread(agent.agentId);
|
|
7599
|
+
linearForwarder.flushThoughtAsResponse();
|
|
7600
|
+
return;
|
|
7601
|
+
}
|
|
7602
|
+
} catch (error) {
|
|
7988
7603
|
await this.cancelRun(run);
|
|
7989
|
-
|
|
7604
|
+
const text = extractErrorText(error) || "Cursor run failed";
|
|
7605
|
+
failure = {
|
|
7606
|
+
text,
|
|
7607
|
+
...run ? { runId: run.id } : {},
|
|
7608
|
+
...run?.requestId ? { requestId: run.requestId } : {},
|
|
7609
|
+
transport: isCursorTransportError(text)
|
|
7610
|
+
};
|
|
7990
7611
|
}
|
|
7991
|
-
|
|
7992
|
-
if (
|
|
7993
|
-
|
|
7994
|
-
|
|
7995
|
-
|
|
7996
|
-
|
|
7997
|
-
|
|
7998
|
-
|
|
7999
|
-
|
|
8000
|
-
|
|
8001
|
-
|
|
8002
|
-
this.
|
|
8003
|
-
|
|
8004
|
-
message: detail || result.result || "Cursor run failed",
|
|
8005
|
-
runId: result.id
|
|
8006
|
-
}, this.historyFile);
|
|
8007
|
-
} else {
|
|
8008
|
-
linearForwarder.flushThoughtAsResponse();
|
|
7612
|
+
if (agent && sawCursorActivity) await this.retainThread(agent.agentId);
|
|
7613
|
+
if (!failure) return;
|
|
7614
|
+
console.error("[CursorManager] Cursor run failed:", {
|
|
7615
|
+
runId: failure.runId,
|
|
7616
|
+
requestId: failure.requestId,
|
|
7617
|
+
model,
|
|
7618
|
+
detail: failure.text,
|
|
7619
|
+
transport: failure.transport
|
|
7620
|
+
});
|
|
7621
|
+
const displayMessage = failure.transport ? sawCursorActivity ? "Cursor couldn't reconnect after its automatic retries. Retry the message to continue from the same chat." : run ? "Cursor couldn't connect after its automatic retries. Retry the message or start a new Cursor chat if the problem continues." : "The connection to Cursor failed. Retry the message or start a new Cursor chat if the problem continues." : failure.text;
|
|
7622
|
+
if (failure.transport) {
|
|
7623
|
+
this.activeRun = null;
|
|
7624
|
+
this.closeAgent();
|
|
8009
7625
|
}
|
|
7626
|
+
this.recordHistoryEvent("cursor-error", {
|
|
7627
|
+
type: "error",
|
|
7628
|
+
message: displayMessage,
|
|
7629
|
+
...failure.transport ? { detail: failure.text } : {},
|
|
7630
|
+
...failure.runId ? { runId: failure.runId } : {},
|
|
7631
|
+
...failure.requestId ? { requestId: failure.requestId } : {}
|
|
7632
|
+
}, this.historyFile);
|
|
8010
7633
|
} catch (error) {
|
|
8011
7634
|
await this.cancelRun(run);
|
|
8012
7635
|
this.recordHistoryEvent("cursor-error", {
|
|
@@ -8014,6 +7637,8 @@ var CursorManager = class extends CodingAgentManager {
|
|
|
8014
7637
|
message: error instanceof Error ? error.message : String(error)
|
|
8015
7638
|
}, this.historyFile);
|
|
8016
7639
|
} finally {
|
|
7640
|
+
clearReconnectNoticeTimer();
|
|
7641
|
+
this.setReconnectNoticeVisible(false);
|
|
8017
7642
|
this.abortActiveTurn = null;
|
|
8018
7643
|
this.activeRun = null;
|
|
8019
7644
|
this.activeModel = null;
|
|
@@ -8156,7 +7781,7 @@ ${instructions}
|
|
|
8156
7781
|
import { spawn as spawn3 } from "child_process";
|
|
8157
7782
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
8158
7783
|
import { createRequire } from "module";
|
|
8159
|
-
import { dirname as dirname6, join as
|
|
7784
|
+
import { dirname as dirname6, join as join19 } from "path";
|
|
8160
7785
|
import { fileURLToPath } from "url";
|
|
8161
7786
|
import { existsSync as existsSync6 } from "fs";
|
|
8162
7787
|
import { mkdir as mkdir12 } from "fs/promises";
|
|
@@ -8171,11 +7796,11 @@ var questionSelectionSchema = z2.record(z2.string(), z2.object({
|
|
|
8171
7796
|
custom: z2.string().optional()
|
|
8172
7797
|
}));
|
|
8173
7798
|
var require2 = createRequire(import.meta.url);
|
|
8174
|
-
var DSH_BIN =
|
|
7799
|
+
var DSH_BIN = join19(dirname6(require2.resolve("@deepseek-ai/dsh/package.json")), "lib", "bin.js");
|
|
8175
7800
|
var MANAGER_DIR = dirname6(fileURLToPath(import.meta.url));
|
|
8176
7801
|
var DSH_PATCH = [
|
|
8177
|
-
|
|
8178
|
-
|
|
7802
|
+
join19(MANAGER_DIR, "..", "..", "scripts", "deepseek", "replicas.cordis.patch.yml"),
|
|
7803
|
+
join19(MANAGER_DIR, "..", "..", "..", "scripts", "deepseek", "replicas.cordis.patch.yml")
|
|
8179
7804
|
].find(existsSync6) ?? "";
|
|
8180
7805
|
var DeepseekApiClient = class extends AbstractApiClient {
|
|
8181
7806
|
constructor(baseUrl) {
|
|
@@ -8215,8 +7840,8 @@ var DeepseekApiClient = class extends AbstractApiClient {
|
|
|
8215
7840
|
if (!execution.success) throw new Error(`DeepSeek Harness did not recognize ${line}.`);
|
|
8216
7841
|
if (execution.data.result.kind === "error") throw new Error(execution.data.result.text ?? `DeepSeek Harness rejected ${line}.`);
|
|
8217
7842
|
}
|
|
8218
|
-
async *readWebSocket(
|
|
8219
|
-
const url = new URL(
|
|
7843
|
+
async *readWebSocket(path5, signal, schema, onOpen) {
|
|
7844
|
+
const url = new URL(path5, this.baseUrl);
|
|
8220
7845
|
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
8221
7846
|
const socket = new WebSocket(url);
|
|
8222
7847
|
const inbox = [];
|
|
@@ -8289,7 +7914,7 @@ var DeepseekManager = class extends CodingAgentManager {
|
|
|
8289
7914
|
constructor(options) {
|
|
8290
7915
|
super(options);
|
|
8291
7916
|
this.sessionId = options.initialSessionId ? sessionIdSchema.parse(options.initialSessionId) : null;
|
|
8292
|
-
this.historyFilePath = options.historyFilePath ??
|
|
7917
|
+
this.historyFilePath = options.historyFilePath ?? join19(ENGINE_ENV.HOME_DIR, ".replicas", "deepseek", "history.jsonl");
|
|
8293
7918
|
this.historyFile = new CodexHistoryFile(this.historyFilePath);
|
|
8294
7919
|
this.initializeManager(this.processMessageInternal.bind(this));
|
|
8295
7920
|
}
|
|
@@ -8376,7 +8001,7 @@ var DeepseekManager = class extends CodingAgentManager {
|
|
|
8376
8001
|
...process.env,
|
|
8377
8002
|
DEEPSEEK_API_KEY: apiKey,
|
|
8378
8003
|
DEEPSEEK_BASE_URL: "https://openrouter.ai/api/v1",
|
|
8379
|
-
DSH_HOME:
|
|
8004
|
+
DSH_HOME: join19(ENGINE_ENV.HOME_DIR, ".replicas", "deepseek"),
|
|
8380
8005
|
DSH_PERMISSION_MODE: "danger-full-access",
|
|
8381
8006
|
DSH_TELEMETRY_DISABLED: "true"
|
|
8382
8007
|
},
|
|
@@ -9086,7 +8711,7 @@ var KimiManager = class extends AcpManager {
|
|
|
9086
8711
|
// src/managers/opencode-manager.ts
|
|
9087
8712
|
import { existsSync as existsSync7 } from "fs";
|
|
9088
8713
|
import { mkdir as mkdir14, readFile as readFile13 } from "fs/promises";
|
|
9089
|
-
import { delimiter, dirname as dirname8, join as
|
|
8714
|
+
import { delimiter, dirname as dirname8, join as join20 } from "path";
|
|
9090
8715
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
9091
8716
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
9092
8717
|
import { Agent } from "undici";
|
|
@@ -9133,7 +8758,7 @@ async function getAllowedOpenRouterModels() {
|
|
|
9133
8758
|
|
|
9134
8759
|
// src/managers/opencode-manager.ts
|
|
9135
8760
|
var OPENCODE_SHIM_DIR = dirname8(fileURLToPath2(new URL("../../scripts/opencode", import.meta.url)));
|
|
9136
|
-
var OPENCODE_CONFIG_PATH =
|
|
8761
|
+
var OPENCODE_CONFIG_PATH = join20(ENGINE_ENV.HOME_DIR, ".config", "opencode", "opencode.json");
|
|
9137
8762
|
var OPENCODE_FETCH_DISPATCHER = new Agent({ headersTimeout: 0, bodyTimeout: 0 });
|
|
9138
8763
|
var OPENCODE_SERVER_STARTUP_TIMEOUT_MS = 3e4;
|
|
9139
8764
|
var OPENCODE_WORKSPACE_PERMISSION = {
|
|
@@ -9383,7 +9008,7 @@ var OpencodeManager = class extends CodingAgentManager {
|
|
|
9383
9008
|
constructor(options) {
|
|
9384
9009
|
super(options);
|
|
9385
9010
|
this.sessionId = options.initialSessionId;
|
|
9386
|
-
this.historyFilePath = options.historyFilePath ??
|
|
9011
|
+
this.historyFilePath = options.historyFilePath ?? join20(ENGINE_ENV.HOME_DIR, ".replicas", "opencode", "history.jsonl");
|
|
9387
9012
|
this.historyFile = new CodexHistoryFile(this.historyFilePath);
|
|
9388
9013
|
this.initializeManager(this.processMessageInternal.bind(this));
|
|
9389
9014
|
}
|
|
@@ -9893,7 +9518,7 @@ var OpencodeManager = class extends CodingAgentManager {
|
|
|
9893
9518
|
|
|
9894
9519
|
// src/managers/pi-manager.ts
|
|
9895
9520
|
import { mkdir as mkdir15 } from "fs/promises";
|
|
9896
|
-
import { dirname as dirname9, join as
|
|
9521
|
+
import { dirname as dirname9, join as join21 } from "path";
|
|
9897
9522
|
import {
|
|
9898
9523
|
AuthStorage,
|
|
9899
9524
|
createAgentSession,
|
|
@@ -9976,7 +9601,7 @@ var PiManager = class extends CodingAgentManager {
|
|
|
9976
9601
|
providerApiKey = null;
|
|
9977
9602
|
constructor(options) {
|
|
9978
9603
|
super(options);
|
|
9979
|
-
this.historyFilePath = options.historyFilePath ??
|
|
9604
|
+
this.historyFilePath = options.historyFilePath ?? join21(PI_HISTORY_DIR, `${Date.now()}.jsonl`);
|
|
9980
9605
|
this.historyFile = new CodexHistoryFile(this.historyFilePath);
|
|
9981
9606
|
this.initializeManager(this.processMessageInternal.bind(this));
|
|
9982
9607
|
}
|
|
@@ -10076,7 +9701,7 @@ var PiManager = class extends CodingAgentManager {
|
|
|
10076
9701
|
const sessionManager = this.initialSessionId ? SessionManager.open(this.initialSessionId, PI_HISTORY_DIR, this.workingDirectory) : SessionManager.create(this.workingDirectory, PI_HISTORY_DIR);
|
|
10077
9702
|
const resourceLoader = new DefaultResourceLoader({
|
|
10078
9703
|
cwd: this.workingDirectory,
|
|
10079
|
-
agentDir:
|
|
9704
|
+
agentDir: join21(ENGINE_ENV.HOME_DIR, ".pi", "agent"),
|
|
10080
9705
|
extensionFactories: [registerCommandProtection(
|
|
10081
9706
|
this.workingDirectory,
|
|
10082
9707
|
this.historyFile,
|
|
@@ -10176,9 +9801,9 @@ function extractTextBlocks(content, textBlockType, separator = "\n") {
|
|
|
10176
9801
|
const texts = content.map((block) => block && typeof block === "object" && "type" in block && block.type === textBlockType && "text" in block && typeof block.text === "string" ? block.text : "").filter(Boolean);
|
|
10177
9802
|
return texts.length > 0 ? texts.join(separator) : null;
|
|
10178
9803
|
}
|
|
10179
|
-
async function engineFetch(
|
|
9804
|
+
async function engineFetch(path5, options) {
|
|
10180
9805
|
const baseUrl = `http://localhost:${ENGINE_ENV.REPLICAS_ENGINE_PORT}`;
|
|
10181
|
-
return fetch(`${baseUrl}${
|
|
9806
|
+
return fetch(`${baseUrl}${path5}`, {
|
|
10182
9807
|
...options,
|
|
10183
9808
|
headers: {
|
|
10184
9809
|
"Content-Type": "application/json",
|
|
@@ -10798,7 +10423,7 @@ import {
|
|
|
10798
10423
|
rename as rename2,
|
|
10799
10424
|
unlink as unlink3
|
|
10800
10425
|
} from "fs/promises";
|
|
10801
|
-
import { join as
|
|
10426
|
+
import { join as join22 } from "path";
|
|
10802
10427
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
10803
10428
|
|
|
10804
10429
|
// src/analytics/agent/activity/skill-mcp-call-extractor.ts
|
|
@@ -10849,7 +10474,7 @@ var AgentChatActivityBuffer = class {
|
|
|
10849
10474
|
options.storageName,
|
|
10850
10475
|
...options.legacyStorageNames ?? []
|
|
10851
10476
|
];
|
|
10852
|
-
this.liveFile =
|
|
10477
|
+
this.liveFile = join22(ENGINE_DIR2, `${options.storageName}.jsonl`);
|
|
10853
10478
|
this.segmentFilePatterns = this.storageNames.map(
|
|
10854
10479
|
(storageName) => new RegExp(`^${storageName}\\.(\\d+)\\.jsonl$`)
|
|
10855
10480
|
);
|
|
@@ -10908,8 +10533,8 @@ var AgentChatActivityBuffer = class {
|
|
|
10908
10533
|
await Promise.allSettled([...this.pendingAppends]);
|
|
10909
10534
|
for (const storageName of this.storageNames) {
|
|
10910
10535
|
await rename2(
|
|
10911
|
-
|
|
10912
|
-
|
|
10536
|
+
join22(ENGINE_DIR2, `${storageName}.jsonl`),
|
|
10537
|
+
join22(ENGINE_DIR2, `${storageName}.${Date.now()}.jsonl`)
|
|
10913
10538
|
).catch(() => {
|
|
10914
10539
|
});
|
|
10915
10540
|
}
|
|
@@ -10920,7 +10545,7 @@ var AgentChatActivityBuffer = class {
|
|
|
10920
10545
|
if (!this.segmentFilePatterns.some((pattern) => pattern.test(entry)))
|
|
10921
10546
|
continue;
|
|
10922
10547
|
try {
|
|
10923
|
-
await this.uploadSegment(
|
|
10548
|
+
await this.uploadSegment(join22(ENGINE_DIR2, entry));
|
|
10924
10549
|
flushed++;
|
|
10925
10550
|
} catch (error) {
|
|
10926
10551
|
failed++;
|
|
@@ -10952,7 +10577,7 @@ var AgentChatActivityBuffer = class {
|
|
|
10952
10577
|
) && entry.endsWith(UPLOADED_SUFFIX)
|
|
10953
10578
|
).sort();
|
|
10954
10579
|
for (const entry of uploaded.slice(0, -MAX_UPLOADED_SEGMENTS)) {
|
|
10955
|
-
await unlink3(
|
|
10580
|
+
await unlink3(join22(ENGINE_DIR2, entry)).catch(() => {
|
|
10956
10581
|
});
|
|
10957
10582
|
}
|
|
10958
10583
|
return { flushed, failed };
|
|
@@ -11184,18 +10809,18 @@ var keepAliveService = new KeepAliveService();
|
|
|
11184
10809
|
|
|
11185
10810
|
// src/services/canvas-service.ts
|
|
11186
10811
|
import { readdir as readdir7, readFile as readFile15, stat as stat3 } from "fs/promises";
|
|
11187
|
-
import { homedir as
|
|
11188
|
-
import { join as
|
|
10812
|
+
import { homedir as homedir12 } from "os";
|
|
10813
|
+
import { join as join23 } from "path";
|
|
11189
10814
|
var GLOBAL_CANVAS_DIRECTORIES = [
|
|
11190
|
-
|
|
11191
|
-
|
|
11192
|
-
|
|
10815
|
+
join23(homedir12(), ".claude", "plans"),
|
|
10816
|
+
join23(process.env.XDG_DATA_HOME ?? join23(homedir12(), ".local", "share"), "opencode", "plans"),
|
|
10817
|
+
join23(homedir12(), ".replicas", "canvas")
|
|
11193
10818
|
];
|
|
11194
10819
|
async function canvasDirectories() {
|
|
11195
10820
|
const repositories = await gitService.listRepositories().catch(() => []);
|
|
11196
10821
|
return [
|
|
11197
10822
|
...GLOBAL_CANVAS_DIRECTORIES,
|
|
11198
|
-
...repositories.map((repository) =>
|
|
10823
|
+
...repositories.map((repository) => join23(repository.path, ".opencode", "plans"))
|
|
11199
10824
|
];
|
|
11200
10825
|
}
|
|
11201
10826
|
var CanvasService = class {
|
|
@@ -11219,7 +10844,7 @@ var CanvasService = class {
|
|
|
11219
10844
|
for (const entry of entries) {
|
|
11220
10845
|
if (entry.name.startsWith(".")) continue;
|
|
11221
10846
|
const filename = current.relativePath ? `${current.relativePath}/${entry.name}` : entry.name;
|
|
11222
|
-
const filePath =
|
|
10847
|
+
const filePath = join23(current.directory, entry.name);
|
|
11223
10848
|
if (entry.isDirectory()) {
|
|
11224
10849
|
pending.push({ directory: filePath, relativePath: filename });
|
|
11225
10850
|
continue;
|
|
@@ -11244,7 +10869,7 @@ var CanvasService = class {
|
|
|
11244
10869
|
if (!safe) return null;
|
|
11245
10870
|
const { kind, mimeType } = classifyCanvasFilename(safe);
|
|
11246
10871
|
for (const directory of await this.directories()) {
|
|
11247
|
-
const filePath =
|
|
10872
|
+
const filePath = join23(directory, safe);
|
|
11248
10873
|
let sizeBytes = 0;
|
|
11249
10874
|
let updatedAt = "";
|
|
11250
10875
|
try {
|
|
@@ -11416,13 +11041,13 @@ async function reconcileCanvasItems(filenames) {
|
|
|
11416
11041
|
import { createReadStream } from "fs";
|
|
11417
11042
|
import { createHash as createHash2 } from "crypto";
|
|
11418
11043
|
import { readFile as readFile16, readdir as readdir8, stat as stat4 } from "fs/promises";
|
|
11419
|
-
import { basename as basename2, join as
|
|
11044
|
+
import { basename as basename2, join as join25 } from "path";
|
|
11420
11045
|
|
|
11421
11046
|
// src/services/chat/chat-senders.ts
|
|
11422
|
-
import { join as
|
|
11423
|
-
var CHAT_SENDERS_DIR =
|
|
11047
|
+
import { join as join24 } from "path";
|
|
11048
|
+
var CHAT_SENDERS_DIR = join24(ENGINE_DIR2, "chat-senders");
|
|
11424
11049
|
function chatMessageSendersFilePath(chatId) {
|
|
11425
|
-
return
|
|
11050
|
+
return join24(CHAT_SENDERS_DIR, `${chatId}.jsonl`);
|
|
11426
11051
|
}
|
|
11427
11052
|
function parseChatMessageSendersJsonl(content) {
|
|
11428
11053
|
return content.split("\n").flatMap((line) => {
|
|
@@ -11438,9 +11063,9 @@ function parseChatMessageSendersJsonl(content) {
|
|
|
11438
11063
|
|
|
11439
11064
|
// src/services/upload-chat-transcripts.ts
|
|
11440
11065
|
var HISTORY_DIRS = [
|
|
11441
|
-
|
|
11442
|
-
|
|
11443
|
-
|
|
11066
|
+
join25(ENGINE_DIR2, "claude-histories"),
|
|
11067
|
+
join25(ENGINE_DIR2, "relay-histories"),
|
|
11068
|
+
join25(ENGINE_DIR2, "codex-histories")
|
|
11444
11069
|
];
|
|
11445
11070
|
async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map(), capture) {
|
|
11446
11071
|
let flushed = 0;
|
|
@@ -11458,7 +11083,7 @@ async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map(), ca
|
|
|
11458
11083
|
if (!entry.endsWith(".jsonl")) continue;
|
|
11459
11084
|
const chatId = basename2(entry, ".jsonl");
|
|
11460
11085
|
tasks.push(
|
|
11461
|
-
uploadChatTranscript(chatId,
|
|
11086
|
+
uploadChatTranscript(chatId, join25(dir, entry), chatsById.get(chatId), capture).then((artifact) => {
|
|
11462
11087
|
flushed++;
|
|
11463
11088
|
if (artifact && capture) revisions.push(artifact);
|
|
11464
11089
|
}).catch((err) => {
|
|
@@ -11576,7 +11201,7 @@ async function flushRepoState() {
|
|
|
11576
11201
|
// src/services/upload-engine-logs.ts
|
|
11577
11202
|
import { createReadStream as createReadStream2 } from "fs";
|
|
11578
11203
|
import { readdir as readdir9, stat as stat5 } from "fs/promises";
|
|
11579
|
-
import { join as
|
|
11204
|
+
import { join as join26 } from "path";
|
|
11580
11205
|
var MAX_ENGINE_LOG_FLUSH_SESSIONS = 10;
|
|
11581
11206
|
var MAX_ENGINE_LOG_FLUSH_BYTES = 5 * 1024 * 1024;
|
|
11582
11207
|
var ENGINE_LOG_FLUSH_TIMEOUT_MS = 2e4;
|
|
@@ -11605,7 +11230,7 @@ async function flushAllEngineLogs() {
|
|
|
11605
11230
|
const candidates = (await Promise.all(filenames.slice(0, MAX_ENGINE_LOG_FLUSH_SESSIONS).map(async (filename) => {
|
|
11606
11231
|
try {
|
|
11607
11232
|
const sessionId = filename.slice(0, -".log".length);
|
|
11608
|
-
const filePath =
|
|
11233
|
+
const filePath = join26(LOG_DIR, filename);
|
|
11609
11234
|
const fileStat = await runBeforeDeadline(() => stat5(filePath), deadline);
|
|
11610
11235
|
if (!fileStat.isFile()) {
|
|
11611
11236
|
skipped++;
|
|
@@ -11701,10 +11326,9 @@ async function uploadEngineLog(input, timeoutMs) {
|
|
|
11701
11326
|
}
|
|
11702
11327
|
|
|
11703
11328
|
// src/services/chat/chat-service.ts
|
|
11704
|
-
var CODEX_AUTH_PATH2 = join29(homedir15(), ".codex", "auth.json");
|
|
11705
11329
|
var CHATS_BACKUP_FILE = `${CHATS_FILE}.bak`;
|
|
11706
11330
|
function isCodexAvailable() {
|
|
11707
|
-
return
|
|
11331
|
+
return detectCodexAuthMethod() !== "none";
|
|
11708
11332
|
}
|
|
11709
11333
|
function isOpencodeAvailable() {
|
|
11710
11334
|
return existsSync8(OPENCODE_AUTH_PATH);
|
|
@@ -12227,12 +11851,12 @@ var ChatService = class {
|
|
|
12227
11851
|
return descendants;
|
|
12228
11852
|
}
|
|
12229
11853
|
async deleteHistoryFile(persisted) {
|
|
12230
|
-
const historyPath =
|
|
11854
|
+
const historyPath = join27(HISTORY_DIR_BY_PROVIDER[persisted.provider], `${persisted.id}.jsonl`);
|
|
12231
11855
|
await Promise.all([
|
|
12232
11856
|
historyPath,
|
|
12233
11857
|
`${historyPath}.pages.jsonl`,
|
|
12234
11858
|
`${historyPath}.pages.index.json`
|
|
12235
|
-
].map((
|
|
11859
|
+
].map((path5) => rm2(path5, { force: true })));
|
|
12236
11860
|
await rm2(chatMessageSendersFilePath(persisted.id), { force: true });
|
|
12237
11861
|
}
|
|
12238
11862
|
async getChatHistory(chatId, page = {}) {
|
|
@@ -12350,7 +11974,7 @@ var ChatService = class {
|
|
|
12350
11974
|
if (persisted.provider === "claude") {
|
|
12351
11975
|
provider = new ClaudeManager({
|
|
12352
11976
|
workingDirectory: this.workingDirectory,
|
|
12353
|
-
historyFilePath:
|
|
11977
|
+
historyFilePath: join27(CLAUDE_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
12354
11978
|
initialSessionId: persisted.providerSessionId,
|
|
12355
11979
|
onSaveSessionId: saveSession,
|
|
12356
11980
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -12369,7 +11993,7 @@ var ChatService = class {
|
|
|
12369
11993
|
});
|
|
12370
11994
|
provider = new RelayManager({
|
|
12371
11995
|
workingDirectory: this.workingDirectory,
|
|
12372
|
-
historyFilePath:
|
|
11996
|
+
historyFilePath: join27(RELAY_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
12373
11997
|
initialSessionId: persisted.providerSessionId,
|
|
12374
11998
|
onSaveSessionId: saveSession,
|
|
12375
11999
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -12382,7 +12006,7 @@ var ChatService = class {
|
|
|
12382
12006
|
} else if (persisted.provider === "cursor") {
|
|
12383
12007
|
provider = new CursorManager({
|
|
12384
12008
|
workingDirectory: this.workingDirectory,
|
|
12385
|
-
historyFilePath:
|
|
12009
|
+
historyFilePath: join27(CURSOR_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
12386
12010
|
initialSessionId: persisted.providerSessionId,
|
|
12387
12011
|
onSaveSessionId: saveSession,
|
|
12388
12012
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -12392,7 +12016,7 @@ var ChatService = class {
|
|
|
12392
12016
|
} else if (persisted.provider === "deepseek") {
|
|
12393
12017
|
provider = new DeepseekManager({
|
|
12394
12018
|
workingDirectory: this.workingDirectory,
|
|
12395
|
-
historyFilePath:
|
|
12019
|
+
historyFilePath: join27(DEEPSEEK_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
12396
12020
|
initialSessionId: persisted.providerSessionId,
|
|
12397
12021
|
onSaveSessionId: saveSession,
|
|
12398
12022
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -12402,7 +12026,7 @@ var ChatService = class {
|
|
|
12402
12026
|
} else if (persisted.provider === "fx") {
|
|
12403
12027
|
provider = new FxManager({
|
|
12404
12028
|
workingDirectory: this.workingDirectory,
|
|
12405
|
-
historyFilePath:
|
|
12029
|
+
historyFilePath: join27(FX_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
12406
12030
|
initialSessionId: persisted.providerSessionId,
|
|
12407
12031
|
onSaveSessionId: saveSession,
|
|
12408
12032
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -12412,7 +12036,7 @@ var ChatService = class {
|
|
|
12412
12036
|
} else if (persisted.provider === "kimi") {
|
|
12413
12037
|
provider = new KimiManager({
|
|
12414
12038
|
workingDirectory: this.workingDirectory,
|
|
12415
|
-
historyFilePath:
|
|
12039
|
+
historyFilePath: join27(KIMI_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
12416
12040
|
initialSessionId: persisted.providerSessionId,
|
|
12417
12041
|
onSaveSessionId: saveSession,
|
|
12418
12042
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -12422,7 +12046,7 @@ var ChatService = class {
|
|
|
12422
12046
|
} else if (persisted.provider === "opencode") {
|
|
12423
12047
|
provider = new OpencodeManager({
|
|
12424
12048
|
workingDirectory: this.workingDirectory,
|
|
12425
|
-
historyFilePath:
|
|
12049
|
+
historyFilePath: join27(OPENCODE_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
12426
12050
|
initialSessionId: persisted.providerSessionId,
|
|
12427
12051
|
onSaveSessionId: saveSession,
|
|
12428
12052
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -12432,7 +12056,7 @@ var ChatService = class {
|
|
|
12432
12056
|
} else if (persisted.provider === "pi") {
|
|
12433
12057
|
provider = new PiManager({
|
|
12434
12058
|
workingDirectory: this.workingDirectory,
|
|
12435
|
-
historyFilePath:
|
|
12059
|
+
historyFilePath: join27(PI_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
12436
12060
|
initialSessionId: persisted.providerSessionId,
|
|
12437
12061
|
onSaveSessionId: saveSession,
|
|
12438
12062
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -12442,7 +12066,7 @@ var ChatService = class {
|
|
|
12442
12066
|
} else {
|
|
12443
12067
|
provider = new CodexAspManager({
|
|
12444
12068
|
workingDirectory: this.workingDirectory,
|
|
12445
|
-
historyFilePath:
|
|
12069
|
+
historyFilePath: join27(CODEX_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
12446
12070
|
initialSessionId: persisted.providerSessionId,
|
|
12447
12071
|
onSaveSessionId: saveSession,
|
|
12448
12072
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -12481,6 +12105,7 @@ var ChatService = class {
|
|
|
12481
12105
|
awaitingInput: chat.provider.isAwaitingInput?.() ?? false,
|
|
12482
12106
|
isCompacting: chat.provider.isCompacting?.() ?? false,
|
|
12483
12107
|
isAuthRetrying: chat.provider.isAuthRetrying?.() ?? false,
|
|
12108
|
+
mayBeReconnecting: chat.provider.mayBeReconnecting?.() ?? false,
|
|
12484
12109
|
goal: chat.provider.getGoal?.() ?? null,
|
|
12485
12110
|
parentChatId: chat.persisted.parentChatId,
|
|
12486
12111
|
lastMessageText: chat.persisted.lastMessageText ?? null,
|
|
@@ -12570,7 +12195,7 @@ var ChatService = class {
|
|
|
12570
12195
|
}
|
|
12571
12196
|
}).catch(() => {
|
|
12572
12197
|
});
|
|
12573
|
-
if (event.type === "replicas-tool-input-request" || event.type === "replicas-tool-input-resolved" || event.type === "compaction-status" || event.type === AUTH_RETRY_STATUS_EVENT_TYPE || event.type === AUTH_FALLBACK_EVENT_TYPE || event.type === CHAT_GOAL_EVENT_TYPE || event.type === CLAUDE_ACTIVITY_STATUS_EVENT_TYPE || event.type === "claude-result" || event.type === "claude-system" && (event.payload.subtype === "init" || event.payload.subtype === "session_state_changed" || event.payload.subtype === "background_tasks_changed" || coerceBackgroundTaskPayload(event.payload) !== null)) {
|
|
12198
|
+
if (event.type === "replicas-tool-input-request" || event.type === "replicas-tool-input-resolved" || event.type === "compaction-status" || event.type === AUTH_RETRY_STATUS_EVENT_TYPE || event.type === AUTH_FALLBACK_EVENT_TYPE || event.type === CURSOR_CONNECTION_STATUS_EVENT_TYPE || event.type === CHAT_GOAL_EVENT_TYPE || event.type === CLAUDE_ACTIVITY_STATUS_EVENT_TYPE || event.type === "claude-result" || event.type === "claude-system" && (event.payload.subtype === "init" || event.payload.subtype === "session_state_changed" || event.payload.subtype === "background_tasks_changed" || coerceBackgroundTaskPayload(event.payload) !== null)) {
|
|
12574
12199
|
this.publish({
|
|
12575
12200
|
type: "chat.updated",
|
|
12576
12201
|
payload: { chat: this.toSummary(chat) }
|
|
@@ -12607,7 +12232,7 @@ var ChatService = class {
|
|
|
12607
12232
|
});
|
|
12608
12233
|
uploadChatTranscript(
|
|
12609
12234
|
chatId,
|
|
12610
|
-
|
|
12235
|
+
join27(HISTORY_DIR_BY_PROVIDER[chat.persisted.provider], `${chatId}.jsonl`),
|
|
12611
12236
|
this.toSummary(chat)
|
|
12612
12237
|
).catch((err) => {
|
|
12613
12238
|
console.error("[ChatService] Failed to upload chat transcript:", { chatId, err });
|
|
@@ -12745,7 +12370,7 @@ var ChatService = class {
|
|
|
12745
12370
|
// src/services/repo-file-service.ts
|
|
12746
12371
|
import { execFile } from "child_process";
|
|
12747
12372
|
import { readFile as readFile18, realpath, stat as stat6 } from "fs/promises";
|
|
12748
|
-
import { join as
|
|
12373
|
+
import { join as join28, resolve as resolve2, extname as extname2 } from "path";
|
|
12749
12374
|
var CACHE_TTL_MS = 3e4;
|
|
12750
12375
|
var SEARCH_TIMEOUT_MS = 15e3;
|
|
12751
12376
|
var MAX_CONTENT_BYTES = 256 * 1024;
|
|
@@ -12897,7 +12522,7 @@ var RepoFileService = class {
|
|
|
12897
12522
|
const repo = repos.find((r) => r.name === repoName);
|
|
12898
12523
|
if (!repo) return null;
|
|
12899
12524
|
try {
|
|
12900
|
-
const fullPath = await realpath(resolve2(
|
|
12525
|
+
const fullPath = await realpath(resolve2(join28(repo.path, filePath)));
|
|
12901
12526
|
const repoRoot = await realpath(repo.path);
|
|
12902
12527
|
const repoPrefix = repoRoot.endsWith("/") ? repoRoot : repoRoot + "/";
|
|
12903
12528
|
if (!fullPath.startsWith(repoPrefix) && fullPath !== repoRoot) return null;
|
|
@@ -13032,20 +12657,20 @@ var RepoFileService = class {
|
|
|
13032
12657
|
import { Hono } from "hono";
|
|
13033
12658
|
import { z as z6 } from "zod";
|
|
13034
12659
|
import { readdir as readdir11, stat as stat7, readFile as readFile21 } from "fs/promises";
|
|
13035
|
-
import { join as
|
|
12660
|
+
import { join as join31, resolve as resolve3 } from "path";
|
|
13036
12661
|
|
|
13037
12662
|
// src/services/warm-hooks-service.ts
|
|
13038
12663
|
import { spawn as spawn6 } from "child_process";
|
|
13039
12664
|
import { readFile as readFile20 } from "fs/promises";
|
|
13040
12665
|
import { existsSync as existsSync9 } from "fs";
|
|
13041
|
-
import { join as
|
|
12666
|
+
import { join as join30 } from "path";
|
|
13042
12667
|
|
|
13043
12668
|
// src/services/warm-hook-logs-service.ts
|
|
13044
12669
|
import { mkdir as mkdir18, readFile as readFile19, writeFile as writeFile7, readdir as readdir10, appendFile as appendFile5, unlink as unlink4 } from "fs/promises";
|
|
13045
|
-
import { homedir as
|
|
13046
|
-
import { join as
|
|
13047
|
-
var LOGS_DIR2 =
|
|
13048
|
-
var CURRENT_RUN_LOG =
|
|
12670
|
+
import { homedir as homedir13 } from "os";
|
|
12671
|
+
import { join as join29 } from "path";
|
|
12672
|
+
var LOGS_DIR2 = join29(homedir13(), ".replicas", "warm-hook-logs");
|
|
12673
|
+
var CURRENT_RUN_LOG = join29(LOGS_DIR2, "current-run.log");
|
|
13049
12674
|
var GLOBAL_FILENAME = "global.json";
|
|
13050
12675
|
function withPreview2(stored) {
|
|
13051
12676
|
const preview = buildHookOutputPreview(stored.output);
|
|
@@ -13062,7 +12687,7 @@ var WarmHookLogsService = class {
|
|
|
13062
12687
|
hookName: "organization",
|
|
13063
12688
|
...entry
|
|
13064
12689
|
};
|
|
13065
|
-
await writeFile7(
|
|
12690
|
+
await writeFile7(join29(LOGS_DIR2, GLOBAL_FILENAME), `${JSON.stringify(log, null, 2)}
|
|
13066
12691
|
`, "utf-8");
|
|
13067
12692
|
}
|
|
13068
12693
|
async saveEnvironmentHookLog(entry) {
|
|
@@ -13072,7 +12697,7 @@ var WarmHookLogsService = class {
|
|
|
13072
12697
|
hookName: "environment",
|
|
13073
12698
|
...entry
|
|
13074
12699
|
};
|
|
13075
|
-
await writeFile7(
|
|
12700
|
+
await writeFile7(join29(LOGS_DIR2, ENVIRONMENT_HOOK_LOG_FILENAME), `${JSON.stringify(log, null, 2)}
|
|
13076
12701
|
`, "utf-8");
|
|
13077
12702
|
}
|
|
13078
12703
|
async saveRepoHookLog(repoName, entry) {
|
|
@@ -13082,7 +12707,7 @@ var WarmHookLogsService = class {
|
|
|
13082
12707
|
hookName: repoName,
|
|
13083
12708
|
...entry
|
|
13084
12709
|
};
|
|
13085
|
-
await writeFile7(
|
|
12710
|
+
await writeFile7(join29(LOGS_DIR2, repoHookLogFilename(repoName)), `${JSON.stringify(log, null, 2)}
|
|
13086
12711
|
`, "utf-8");
|
|
13087
12712
|
}
|
|
13088
12713
|
async getAllLogs() {
|
|
@@ -13101,7 +12726,7 @@ var WarmHookLogsService = class {
|
|
|
13101
12726
|
continue;
|
|
13102
12727
|
}
|
|
13103
12728
|
try {
|
|
13104
|
-
const raw = await readFile19(
|
|
12729
|
+
const raw = await readFile19(join29(LOGS_DIR2, file), "utf-8");
|
|
13105
12730
|
const stored = JSON.parse(raw);
|
|
13106
12731
|
logs.push(withPreview2(stored));
|
|
13107
12732
|
} catch {
|
|
@@ -13139,7 +12764,7 @@ var WarmHookLogsService = class {
|
|
|
13139
12764
|
async getFullOutput(hookType, hookName) {
|
|
13140
12765
|
const filename = hookType === "global" ? GLOBAL_FILENAME : hookType === "environment" ? ENVIRONMENT_HOOK_LOG_FILENAME : repoHookLogFilename(hookName);
|
|
13141
12766
|
try {
|
|
13142
|
-
const raw = await readFile19(
|
|
12767
|
+
const raw = await readFile19(join29(LOGS_DIR2, filename), "utf-8");
|
|
13143
12768
|
const stored = JSON.parse(raw);
|
|
13144
12769
|
if (stored.hookType !== hookType || stored.hookName !== hookName) {
|
|
13145
12770
|
return null;
|
|
@@ -13158,7 +12783,7 @@ var warmHookLogsService = new WarmHookLogsService();
|
|
|
13158
12783
|
// src/services/warm-hooks-service.ts
|
|
13159
12784
|
async function readRepoWarmHook(repoPath) {
|
|
13160
12785
|
for (const filename of REPLICAS_CONFIG_FILENAMES) {
|
|
13161
|
-
const configPath =
|
|
12786
|
+
const configPath = join30(repoPath, filename);
|
|
13162
12787
|
if (!existsSync9(configPath)) {
|
|
13163
12788
|
continue;
|
|
13164
12789
|
}
|
|
@@ -13973,11 +13598,11 @@ function createV1Routes(deps) {
|
|
|
13973
13598
|
});
|
|
13974
13599
|
app2.get("/repo-files/content", async (c) => {
|
|
13975
13600
|
const repoName = c.req.query("repoName");
|
|
13976
|
-
const
|
|
13977
|
-
if (!repoName || !
|
|
13601
|
+
const path5 = c.req.query("path");
|
|
13602
|
+
if (!repoName || !path5) {
|
|
13978
13603
|
return c.json(jsonError("repoName and path are required"), 400);
|
|
13979
13604
|
}
|
|
13980
|
-
const result = await deps.repoFileService.readFile(repoName,
|
|
13605
|
+
const result = await deps.repoFileService.readFile(repoName, path5);
|
|
13981
13606
|
if (!result) {
|
|
13982
13607
|
return c.json(jsonError("File not found"), 404);
|
|
13983
13608
|
}
|
|
@@ -14442,7 +14067,7 @@ data: ${JSON.stringify("Terminal session not found")}
|
|
|
14442
14067
|
const logFiles = files.filter((f) => f.endsWith(".log"));
|
|
14443
14068
|
const sessions = await Promise.all(
|
|
14444
14069
|
logFiles.map(async (filename) => {
|
|
14445
|
-
const filePath =
|
|
14070
|
+
const filePath = join31(LOG_DIR, filename);
|
|
14446
14071
|
const fileStat = await stat7(filePath);
|
|
14447
14072
|
const sessionId = filename.replace(/\.log$/, "");
|
|
14448
14073
|
return {
|