replicas-engine 0.1.652 → 0.1.654
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/src/index.js
CHANGED
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
DEFAULT_CLAUDE_MODEL,
|
|
39
39
|
DEFAULT_CODEX_MODEL,
|
|
40
40
|
DEFAULT_CURSOR_MODEL,
|
|
41
|
+
DEFAULT_DEEPSEEK_MODEL,
|
|
41
42
|
DEFAULT_HOOK_OUTPUT_PREVIEW_CHARS,
|
|
42
43
|
DEFAULT_OPENCODE_MODEL,
|
|
43
44
|
DEFAULT_PI_MODEL,
|
|
@@ -80,6 +81,7 @@ import {
|
|
|
80
81
|
TaskAccumulator,
|
|
81
82
|
USER_MESSAGE_ID_PAYLOAD_KEY,
|
|
82
83
|
VALID_AGENT_PROVIDERS,
|
|
84
|
+
VALID_RELAY_SUBAGENT_PROVIDERS,
|
|
83
85
|
VALID_THINKING_LEVELS,
|
|
84
86
|
agentCredentialSnapshotSchema,
|
|
85
87
|
applyCodexAspTranscriptDelta,
|
|
@@ -120,6 +122,7 @@ import {
|
|
|
120
122
|
getChatHistoryPageWindow,
|
|
121
123
|
getClaudeModelContextWindow,
|
|
122
124
|
getCodexAspTurnResponse,
|
|
125
|
+
getDeepseekAssistantMessageText,
|
|
123
126
|
getDefaultAgentModel,
|
|
124
127
|
getEventTimestampMs,
|
|
125
128
|
getGoalCommand,
|
|
@@ -173,12 +176,12 @@ import {
|
|
|
173
176
|
serializeCanvasContentResponse,
|
|
174
177
|
shellQuotePosix,
|
|
175
178
|
stripAgentDiagnosticErrors
|
|
176
|
-
} from "./chunk-
|
|
179
|
+
} from "./chunk-DDFRCI5Q.js";
|
|
177
180
|
|
|
178
181
|
// src/index.ts
|
|
179
182
|
import { serve } from "@hono/node-server";
|
|
180
183
|
import { Hono as Hono2 } from "hono";
|
|
181
|
-
import { existsSync as
|
|
184
|
+
import { existsSync as existsSync11 } from "fs";
|
|
182
185
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
183
186
|
import { connect } from "net";
|
|
184
187
|
|
|
@@ -1817,6 +1820,22 @@ import { homedir as homedir5 } from "os";
|
|
|
1817
1820
|
import { join as join8 } from "path";
|
|
1818
1821
|
var OPENCODE_AUTH_PATH = join8(homedir5(), ".local", "share", "opencode", "auth.json");
|
|
1819
1822
|
var PI_AUTH_PATH = join8(homedir5(), ".pi", "agent", "auth.json");
|
|
1823
|
+
var DEEPSEEK_AUTH_PATH = join8(homedir5(), ".replicas", "deepseek-auth.json");
|
|
1824
|
+
|
|
1825
|
+
// src/managers/deepseek-auth.ts
|
|
1826
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
1827
|
+
import { z } from "zod";
|
|
1828
|
+
var authSchema = z.object({
|
|
1829
|
+
openrouter: z.object({ type: z.literal("api"), key: z.string().min(1) })
|
|
1830
|
+
});
|
|
1831
|
+
function getDeepseekApiKey() {
|
|
1832
|
+
try {
|
|
1833
|
+
const parsed = authSchema.safeParse(JSON.parse(readFileSync4(DEEPSEEK_AUTH_PATH, "utf8")));
|
|
1834
|
+
return parsed.success ? parsed.data.openrouter.key : null;
|
|
1835
|
+
} catch {
|
|
1836
|
+
return null;
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1820
1839
|
|
|
1821
1840
|
// src/services/environment-details-service.ts
|
|
1822
1841
|
var REPLICAS_DIR = join9(homedir6(), ".replicas");
|
|
@@ -1856,6 +1875,9 @@ function detectCursorAuthMethod() {
|
|
|
1856
1875
|
function detectOpencodeAuthMethod() {
|
|
1857
1876
|
return existsSync2(OPENCODE_AUTH_PATH) ? "api_key" : "none";
|
|
1858
1877
|
}
|
|
1878
|
+
function detectDeepseekAuthMethod() {
|
|
1879
|
+
return getDeepseekApiKey() ? "api_key" : "none";
|
|
1880
|
+
}
|
|
1859
1881
|
function detectPiAuthMethod() {
|
|
1860
1882
|
return existsSync2(PI_AUTH_PATH) ? "api_key" : "none";
|
|
1861
1883
|
}
|
|
@@ -1914,6 +1936,7 @@ function createDefaultDetails() {
|
|
|
1914
1936
|
claudeAuthMethod: "none",
|
|
1915
1937
|
codexAuthMethod: "none",
|
|
1916
1938
|
cursorAuthMethod: "none",
|
|
1939
|
+
deepseekAuthMethod: "none",
|
|
1917
1940
|
opencodeAuthMethod: "none",
|
|
1918
1941
|
piAuthMethod: "none",
|
|
1919
1942
|
lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -1953,6 +1976,7 @@ var EnvironmentDetailsService = class {
|
|
|
1953
1976
|
details.claudeAuthMethod = detectClaudeAuthMethod();
|
|
1954
1977
|
details.codexAuthMethod = detectCodexAuthMethod();
|
|
1955
1978
|
details.cursorAuthMethod = detectCursorAuthMethod();
|
|
1979
|
+
details.deepseekAuthMethod = detectDeepseekAuthMethod();
|
|
1956
1980
|
details.opencodeAuthMethod = detectOpencodeAuthMethod();
|
|
1957
1981
|
details.piAuthMethod = detectPiAuthMethod();
|
|
1958
1982
|
details.credentialFallbacks = listCredentialFallbacks();
|
|
@@ -2707,10 +2731,10 @@ async function registerDesktopPreview() {
|
|
|
2707
2731
|
}
|
|
2708
2732
|
|
|
2709
2733
|
// src/services/chat/chat-service.ts
|
|
2710
|
-
import { existsSync as
|
|
2711
|
-
import { appendFile as appendFile4, copyFile, mkdir as
|
|
2734
|
+
import { existsSync as existsSync8 } from "fs";
|
|
2735
|
+
import { appendFile as appendFile4, copyFile, mkdir as mkdir16, readFile as readFile15, rename as rename3, rm as rm2 } from "fs/promises";
|
|
2712
2736
|
import { homedir as homedir15 } from "os";
|
|
2713
|
-
import { join as
|
|
2737
|
+
import { join as join29 } from "path";
|
|
2714
2738
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
2715
2739
|
|
|
2716
2740
|
// src/managers/claude-manager.ts
|
|
@@ -3228,7 +3252,7 @@ async function removeTempImageFiles(paths) {
|
|
|
3228
3252
|
}
|
|
3229
3253
|
|
|
3230
3254
|
// src/managers/coding-agent-manager.ts
|
|
3231
|
-
import { readFileSync as
|
|
3255
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
3232
3256
|
import { join as join15 } from "path";
|
|
3233
3257
|
|
|
3234
3258
|
// src/managers/auth-fallback.ts
|
|
@@ -3687,7 +3711,7 @@ var CodingAgentManager = class {
|
|
|
3687
3711
|
buildMemoryInstruction() {
|
|
3688
3712
|
const readSummary = (scope) => {
|
|
3689
3713
|
try {
|
|
3690
|
-
return
|
|
3714
|
+
return readFileSync5(join15(MEMORY_ROOT, scope, MEMORY_SUMMARY_FILENAME), "utf8").trim();
|
|
3691
3715
|
} catch {
|
|
3692
3716
|
return "";
|
|
3693
3717
|
}
|
|
@@ -4950,12 +4974,14 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
4950
4974
|
await this.recordEvent(userMessage);
|
|
4951
4975
|
}
|
|
4952
4976
|
const combinedInstructions = this.buildCombinedInstructions(customInstructions, true);
|
|
4977
|
+
const systemPrompt = this.systemPromptOverride?.(combinedInstructions);
|
|
4953
4978
|
const resolvedModel = normalizeClaudeModel(model) || DEFAULT_CLAUDE_MODEL;
|
|
4954
4979
|
const claudeCodeModel = toClaudeCodeModel(resolvedModel);
|
|
4955
4980
|
const resolvedPermissionMode = planMode ? "plan" : "bypassPermissions";
|
|
4956
4981
|
const resolvedFastMode = Boolean(fastMode && canUseClaudeFastMode(resolvedModel));
|
|
4957
4982
|
const signature = {
|
|
4958
4983
|
combinedInstructions,
|
|
4984
|
+
systemPrompt,
|
|
4959
4985
|
thinkingLevel,
|
|
4960
4986
|
// enableInteractiveTools only matters in plan mode; the session signature
|
|
4961
4987
|
// tracks the effective flag so a mode change can hot-swap via setPermissionMode
|
|
@@ -4965,6 +4991,7 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
4965
4991
|
};
|
|
4966
4992
|
await this.ensureSession({
|
|
4967
4993
|
signature,
|
|
4994
|
+
systemPrompt,
|
|
4968
4995
|
combinedInstructions,
|
|
4969
4996
|
resolvedModel,
|
|
4970
4997
|
claudeCodeModel,
|
|
@@ -4989,6 +5016,7 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
4989
5016
|
async ensureSession(args) {
|
|
4990
5017
|
const {
|
|
4991
5018
|
signature,
|
|
5019
|
+
systemPrompt,
|
|
4992
5020
|
combinedInstructions,
|
|
4993
5021
|
resolvedModel,
|
|
4994
5022
|
claudeCodeModel,
|
|
@@ -5021,6 +5049,7 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
5021
5049
|
}
|
|
5022
5050
|
await this.startSession({
|
|
5023
5051
|
combinedInstructions,
|
|
5052
|
+
systemPrompt,
|
|
5024
5053
|
resolvedModel,
|
|
5025
5054
|
claudeCodeModel,
|
|
5026
5055
|
resolvedPermissionMode,
|
|
@@ -5030,7 +5059,7 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
5030
5059
|
});
|
|
5031
5060
|
}
|
|
5032
5061
|
sessionSignaturesMatch(a, b) {
|
|
5033
|
-
return a.combinedInstructions === b.combinedInstructions && a.thinkingLevel === b.thinkingLevel && a.enableInteractiveTools === b.enableInteractiveTools && a.fastMode === b.fastMode;
|
|
5062
|
+
return a.combinedInstructions === b.combinedInstructions && a.systemPrompt === b.systemPrompt && a.thinkingLevel === b.thinkingLevel && a.enableInteractiveTools === b.enableInteractiveTools && a.fastMode === b.fastMode;
|
|
5034
5063
|
}
|
|
5035
5064
|
/** Query inputs shared by real sessions and slash-command discovery. */
|
|
5036
5065
|
async buildSharedQueryOptions() {
|
|
@@ -5050,6 +5079,7 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
5050
5079
|
async startSession(args) {
|
|
5051
5080
|
const {
|
|
5052
5081
|
combinedInstructions,
|
|
5082
|
+
systemPrompt,
|
|
5053
5083
|
resolvedModel,
|
|
5054
5084
|
claudeCodeModel,
|
|
5055
5085
|
resolvedPermissionMode,
|
|
@@ -5059,7 +5089,7 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
5059
5089
|
} = args;
|
|
5060
5090
|
const ultracode = thinkingLevel === "ultracode";
|
|
5061
5091
|
const effort = thinkingLevel === "ultra" || ultracode ? "xhigh" : thinkingLevel;
|
|
5062
|
-
const
|
|
5092
|
+
const resolvedSystemPrompt = systemPrompt ?? {
|
|
5063
5093
|
type: "preset",
|
|
5064
5094
|
preset: "claude_code",
|
|
5065
5095
|
append: combinedInstructions
|
|
@@ -5089,7 +5119,7 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
5089
5119
|
...allowedTools ? { allowedTools } : {},
|
|
5090
5120
|
...disallowedTools.length > 0 ? { disallowedTools } : {},
|
|
5091
5121
|
settingSources: ["user", "project", "local"],
|
|
5092
|
-
systemPrompt,
|
|
5122
|
+
systemPrompt: resolvedSystemPrompt,
|
|
5093
5123
|
...this.mcpServersConfig ? { mcpServers: this.mcpServersConfig } : {},
|
|
5094
5124
|
...shared.plugins.length > 0 ? { plugins: shared.plugins } : {},
|
|
5095
5125
|
...shared.enableAllSkills ? { skills: "all" } : {},
|
|
@@ -5685,7 +5715,7 @@ var CodexQuotaStatusTracker = class {
|
|
|
5685
5715
|
};
|
|
5686
5716
|
|
|
5687
5717
|
// src/managers/codex-asp/mappers.ts
|
|
5688
|
-
import { existsSync as existsSync5, readFileSync as
|
|
5718
|
+
import { existsSync as existsSync5, readFileSync as readFileSync6 } from "fs";
|
|
5689
5719
|
var localImageCache = /* @__PURE__ */ new Map();
|
|
5690
5720
|
var DEFAULT_MODEL = DEFAULT_CODEX_MODEL;
|
|
5691
5721
|
var THREAD_START_METHOD = "thread/start";
|
|
@@ -5813,7 +5843,7 @@ function userImageForLocalPath(path6) {
|
|
|
5813
5843
|
const image = {
|
|
5814
5844
|
type: "image",
|
|
5815
5845
|
mediaType: inferMediaType(path6),
|
|
5816
|
-
data:
|
|
5846
|
+
data: readFileSync6(path6).toString("base64")
|
|
5817
5847
|
};
|
|
5818
5848
|
if (image.data.length > 0) localImageCache.set(path6, image);
|
|
5819
5849
|
return image;
|
|
@@ -6317,11 +6347,13 @@ var CODEX_HISTORY_DIR = join18(ENGINE_DIR2, "codex-histories");
|
|
|
6317
6347
|
var CURSOR_HISTORY_DIR = join18(ENGINE_DIR2, "cursor-histories");
|
|
6318
6348
|
var OPENCODE_HISTORY_DIR = join18(ENGINE_DIR2, "opencode-histories");
|
|
6319
6349
|
var PI_HISTORY_DIR = join18(ENGINE_DIR2, "pi-histories");
|
|
6350
|
+
var DEEPSEEK_HISTORY_DIR = join18(ENGINE_DIR2, "deepseek-histories");
|
|
6320
6351
|
var HISTORY_DIR_BY_PROVIDER = {
|
|
6321
6352
|
claude: CLAUDE_HISTORY_DIR,
|
|
6322
6353
|
relay: RELAY_HISTORY_DIR,
|
|
6323
6354
|
codex: CODEX_HISTORY_DIR,
|
|
6324
6355
|
cursor: CURSOR_HISTORY_DIR,
|
|
6356
|
+
deepseek: DEEPSEEK_HISTORY_DIR,
|
|
6325
6357
|
opencode: OPENCODE_HISTORY_DIR,
|
|
6326
6358
|
pi: PI_HISTORY_DIR
|
|
6327
6359
|
};
|
|
@@ -8060,26 +8092,416 @@ ${instructions}
|
|
|
8060
8092
|
}
|
|
8061
8093
|
};
|
|
8062
8094
|
|
|
8063
|
-
// src/managers/
|
|
8095
|
+
// src/managers/deepseek-manager.ts
|
|
8096
|
+
import { spawn as spawn3 } from "child_process";
|
|
8097
|
+
import { createRequire } from "module";
|
|
8098
|
+
import { dirname as dirname6, join as join21 } from "path";
|
|
8099
|
+
import { fileURLToPath } from "url";
|
|
8064
8100
|
import { existsSync as existsSync6 } from "fs";
|
|
8065
|
-
import { mkdir as mkdir12
|
|
8066
|
-
import {
|
|
8101
|
+
import { mkdir as mkdir12 } from "fs/promises";
|
|
8102
|
+
import { z as z2 } from "zod";
|
|
8103
|
+
import WebSocket from "ws";
|
|
8104
|
+
import { AbstractApiClient } from "@deepseek-ai/dsh-host-apiproxy/client";
|
|
8105
|
+
import { hostFrameSchema, muxFrameSchema } from "@deepseek-ai/dsh-host-apiproxy/api/events.schema";
|
|
8106
|
+
import { serverRequestSchema } from "@deepseek-ai/dsh-host-apiproxy/api/rpc.schema";
|
|
8107
|
+
import { sessionIdSchema } from "@deepseek-ai/dsh-host-apiproxy/api/sessions.schema";
|
|
8108
|
+
var questionSelectionSchema = z2.record(z2.string(), z2.object({
|
|
8109
|
+
options: z2.array(z2.string()).optional(),
|
|
8110
|
+
custom: z2.string().optional()
|
|
8111
|
+
}));
|
|
8112
|
+
var require2 = createRequire(import.meta.url);
|
|
8113
|
+
var DSH_BIN = join21(dirname6(require2.resolve("@deepseek-ai/dsh/package.json")), "lib", "bin.js");
|
|
8114
|
+
var MANAGER_DIR = dirname6(fileURLToPath(import.meta.url));
|
|
8115
|
+
var DSH_PATCH = [
|
|
8116
|
+
join21(MANAGER_DIR, "..", "..", "scripts", "deepseek", "replicas.cordis.patch.yml"),
|
|
8117
|
+
join21(MANAGER_DIR, "..", "..", "..", "scripts", "deepseek", "replicas.cordis.patch.yml")
|
|
8118
|
+
].find(existsSync6) ?? "";
|
|
8119
|
+
var DeepseekApiClient = class extends AbstractApiClient {
|
|
8120
|
+
constructor(baseUrl) {
|
|
8121
|
+
super(3e4);
|
|
8122
|
+
this.baseUrl = baseUrl;
|
|
8123
|
+
}
|
|
8124
|
+
baseUrl;
|
|
8125
|
+
doFetch(input, init) {
|
|
8126
|
+
return fetch(input, init);
|
|
8127
|
+
}
|
|
8128
|
+
resolveBase() {
|
|
8129
|
+
return this.baseUrl;
|
|
8130
|
+
}
|
|
8131
|
+
openMux(_payload, signal, onOpen) {
|
|
8132
|
+
return this.readWebSocket("/api/events.mux", signal, muxFrameSchema, onOpen);
|
|
8133
|
+
}
|
|
8134
|
+
openHost(_payload, signal, onOpen) {
|
|
8135
|
+
return this.readWebSocket("/api/events.host", signal, hostFrameSchema, onOpen);
|
|
8136
|
+
}
|
|
8137
|
+
async *readWebSocket(path6, signal, schema, onOpen) {
|
|
8138
|
+
const url = new URL(path6, this.baseUrl);
|
|
8139
|
+
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
8140
|
+
const socket = new WebSocket(url);
|
|
8141
|
+
const inbox = [];
|
|
8142
|
+
let wake;
|
|
8143
|
+
const enqueue = (item) => {
|
|
8144
|
+
inbox.push(item);
|
|
8145
|
+
wake?.();
|
|
8146
|
+
wake = void 0;
|
|
8147
|
+
};
|
|
8148
|
+
const abort = () => socket.close();
|
|
8149
|
+
socket.on("open", onOpen ?? (() => {
|
|
8150
|
+
}));
|
|
8151
|
+
socket.on("message", (data) => {
|
|
8152
|
+
try {
|
|
8153
|
+
const envelope = serverRequestSchema.parse(JSON.parse(data.toString()));
|
|
8154
|
+
enqueue({ rpcId: envelope.rpcId, payload: schema.parse(envelope.payload) });
|
|
8155
|
+
} catch (error) {
|
|
8156
|
+
console.error("[DeepseekManager] Dropped malformed WebSocket frame:", error);
|
|
8157
|
+
}
|
|
8158
|
+
});
|
|
8159
|
+
socket.once("close", () => enqueue(null));
|
|
8160
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
8161
|
+
try {
|
|
8162
|
+
while (true) {
|
|
8163
|
+
while (inbox.length > 0) {
|
|
8164
|
+
const item = inbox.shift();
|
|
8165
|
+
if (item === null) return;
|
|
8166
|
+
if (item) yield item;
|
|
8167
|
+
}
|
|
8168
|
+
await new Promise((resolve5) => {
|
|
8169
|
+
wake = resolve5;
|
|
8170
|
+
});
|
|
8171
|
+
}
|
|
8172
|
+
} finally {
|
|
8173
|
+
signal.removeEventListener("abort", abort);
|
|
8174
|
+
socket.close();
|
|
8175
|
+
}
|
|
8176
|
+
}
|
|
8177
|
+
};
|
|
8178
|
+
function unwrap(response) {
|
|
8179
|
+
if (!response.result.ok) throw new Error(response.result.error.message);
|
|
8180
|
+
return response.result.value;
|
|
8181
|
+
}
|
|
8182
|
+
function reasoningEffort(level) {
|
|
8183
|
+
if (!level) return void 0;
|
|
8184
|
+
if (level === "low") return "off";
|
|
8185
|
+
return level === "medium" || level === "high" ? "high" : "max";
|
|
8186
|
+
}
|
|
8187
|
+
async function getOpenRouterKey() {
|
|
8188
|
+
const apiKey = getDeepseekApiKey();
|
|
8189
|
+
if (!apiKey) {
|
|
8190
|
+
throw new Error("OpenRouter authentication is missing for DeepSeek Harness. Add an API key in Settings \u2192 Coding agents.");
|
|
8191
|
+
}
|
|
8192
|
+
return apiKey;
|
|
8193
|
+
}
|
|
8194
|
+
var DeepseekManager = class extends CodingAgentManager {
|
|
8195
|
+
historyFilePath;
|
|
8196
|
+
historyFile;
|
|
8197
|
+
process = null;
|
|
8198
|
+
client = null;
|
|
8199
|
+
sessionId;
|
|
8200
|
+
streamController = null;
|
|
8201
|
+
turnCompletion = null;
|
|
8202
|
+
resolveTurnCompletion = null;
|
|
8203
|
+
pendingResponses = /* @__PURE__ */ new Map();
|
|
8204
|
+
contextPressure = {};
|
|
8205
|
+
contextBreakdown = {};
|
|
8206
|
+
tokenUsage = {};
|
|
8207
|
+
selectedModel = DEFAULT_DEEPSEEK_MODEL;
|
|
8208
|
+
constructor(options) {
|
|
8209
|
+
super(options);
|
|
8210
|
+
this.sessionId = options.initialSessionId ? sessionIdSchema.parse(options.initialSessionId) : null;
|
|
8211
|
+
this.historyFilePath = options.historyFilePath ?? join21(ENGINE_ENV.HOME_DIR, ".replicas", "deepseek", "history.jsonl");
|
|
8212
|
+
this.historyFile = new CodexHistoryFile(this.historyFilePath);
|
|
8213
|
+
this.initializeManager(this.processMessageInternal.bind(this));
|
|
8214
|
+
}
|
|
8215
|
+
async initialize() {
|
|
8216
|
+
await mkdir12(dirname6(this.historyFilePath), { recursive: true });
|
|
8217
|
+
}
|
|
8218
|
+
getHistorySink() {
|
|
8219
|
+
return this.historyFile;
|
|
8220
|
+
}
|
|
8221
|
+
async interruptActiveTurn() {
|
|
8222
|
+
if (this.client && this.sessionId) unwrap(await this.client.sessions.cancel({ sessionId: this.sessionId }));
|
|
8223
|
+
}
|
|
8224
|
+
async steerRequest(request) {
|
|
8225
|
+
if (!this.client || !this.sessionId || !this.isProcessing()) return false;
|
|
8226
|
+
unwrap(await this.client.sessions.prompt({
|
|
8227
|
+
sessionId: this.sessionId,
|
|
8228
|
+
mode: "steer",
|
|
8229
|
+
content: [{ type: "text", text: request.message }]
|
|
8230
|
+
}));
|
|
8231
|
+
this.recordHistoryEvent("event_msg", { type: "user_message", message: request.message }, this.historyFile);
|
|
8232
|
+
return true;
|
|
8233
|
+
}
|
|
8234
|
+
async getHistory(page = {}) {
|
|
8235
|
+
await this.historyFile.flush();
|
|
8236
|
+
return { thread_id: this.sessionId ?? this.initialSessionId, ...await this.historyFile.loadEventsPage(page), goal: null };
|
|
8237
|
+
}
|
|
8238
|
+
async listSlashCommands() {
|
|
8239
|
+
await this.initialized;
|
|
8240
|
+
const client = await this.ensureClient();
|
|
8241
|
+
if (!this.sessionId) {
|
|
8242
|
+
this.sessionId = unwrap(await client.sessions.create({ cwd: this.workingDirectory })).sessionId;
|
|
8243
|
+
await this.onSaveSessionId(this.sessionId);
|
|
8244
|
+
}
|
|
8245
|
+
const { skills } = unwrap(await client.skills.list({ sessionId: this.sessionId }));
|
|
8246
|
+
return mergeSlashCommands(skills.map((skill) => createProviderSlashCommand("deepseek", skill.name, skill.description)).filter((command) => Boolean(command)));
|
|
8247
|
+
}
|
|
8248
|
+
isAwaitingInput() {
|
|
8249
|
+
return this.pendingResponses.size > 0;
|
|
8250
|
+
}
|
|
8251
|
+
async respondToToolInput(requestId, selectionId) {
|
|
8252
|
+
const pending = this.pendingResponses.get(requestId);
|
|
8253
|
+
if (!pending || !this.client || !this.sessionId) return false;
|
|
8254
|
+
let result;
|
|
8255
|
+
if (pending.frame.type === "approval/requested") {
|
|
8256
|
+
result = { ok: true, value: { sessionId: this.sessionId, outcome: selectionId === "allow" ? "allowed-once" : "rejected" } };
|
|
8257
|
+
} else {
|
|
8258
|
+
const parsed = questionSelectionSchema.safeParse(selectionId === "declined" ? {} : JSON.parse(selectionId));
|
|
8259
|
+
if (!parsed.success) return false;
|
|
8260
|
+
result = {
|
|
8261
|
+
ok: true,
|
|
8262
|
+
value: {
|
|
8263
|
+
sessionId: this.sessionId,
|
|
8264
|
+
answer: {
|
|
8265
|
+
answers: pending.frame.questions.map((question) => {
|
|
8266
|
+
const answer = parsed.data[question.id];
|
|
8267
|
+
return {
|
|
8268
|
+
id: question.id,
|
|
8269
|
+
selected: (answer?.options ?? []).map((option) => option.startsWith(`${question.id}:`) ? option.slice(question.id.length + 1) : option),
|
|
8270
|
+
...answer?.custom ? { custom: answer.custom } : {}
|
|
8271
|
+
};
|
|
8272
|
+
})
|
|
8273
|
+
}
|
|
8274
|
+
}
|
|
8275
|
+
};
|
|
8276
|
+
}
|
|
8277
|
+
const receipt = await this.client.respond({ type: "client-response", rpcId: pending.rpcId, result });
|
|
8278
|
+
if (!receipt.accepted) return false;
|
|
8279
|
+
this.pendingResponses.delete(requestId);
|
|
8280
|
+
return true;
|
|
8281
|
+
}
|
|
8282
|
+
dispose() {
|
|
8283
|
+
this.streamController?.abort();
|
|
8284
|
+
this.process?.kill("SIGTERM");
|
|
8285
|
+
this.process = null;
|
|
8286
|
+
this.client = null;
|
|
8287
|
+
}
|
|
8288
|
+
async ensureClient() {
|
|
8289
|
+
if (this.client) return this.client;
|
|
8290
|
+
if (!DSH_PATCH) throw new Error("DeepSeek Harness configuration is missing from the engine package.");
|
|
8291
|
+
const apiKey = await getOpenRouterKey();
|
|
8292
|
+
const child = spawn3(process.execPath, [DSH_BIN, "--profile", "web", "--patch", DSH_PATCH, "--host", "127.0.0.1", "--port", "0"], {
|
|
8293
|
+
cwd: this.workingDirectory,
|
|
8294
|
+
env: {
|
|
8295
|
+
...process.env,
|
|
8296
|
+
DEEPSEEK_API_KEY: apiKey,
|
|
8297
|
+
DEEPSEEK_BASE_URL: "https://openrouter.ai/api/v1",
|
|
8298
|
+
DSH_HOME: join21(ENGINE_ENV.HOME_DIR, ".replicas", "deepseek"),
|
|
8299
|
+
DSH_PERMISSION_MODE: "workspace-write",
|
|
8300
|
+
DSH_TELEMETRY_DISABLED: "true"
|
|
8301
|
+
},
|
|
8302
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
8303
|
+
});
|
|
8304
|
+
this.process = child;
|
|
8305
|
+
const baseUrl = await new Promise((resolve5, reject) => {
|
|
8306
|
+
let stdout = "";
|
|
8307
|
+
let stderr = "";
|
|
8308
|
+
const timeout = setTimeout(() => {
|
|
8309
|
+
child.kill("SIGTERM");
|
|
8310
|
+
reject(new Error(`DeepSeek Harness startup timed out: ${stderr.trim()}`));
|
|
8311
|
+
}, 3e4);
|
|
8312
|
+
child.stdout?.on("data", (chunk) => {
|
|
8313
|
+
stdout += chunk.toString();
|
|
8314
|
+
const match = stdout.match(/dsh web:\s+(http:\/\/[^\s]+)/);
|
|
8315
|
+
if (!match?.[1]) return;
|
|
8316
|
+
clearTimeout(timeout);
|
|
8317
|
+
resolve5(match[1]);
|
|
8318
|
+
});
|
|
8319
|
+
child.stderr?.on("data", (chunk) => {
|
|
8320
|
+
stderr = (stderr + chunk.toString()).slice(-8e3);
|
|
8321
|
+
});
|
|
8322
|
+
child.once("exit", (code) => {
|
|
8323
|
+
clearTimeout(timeout);
|
|
8324
|
+
reject(new Error(`DeepSeek Harness exited during startup (${code}): ${stderr.trim()}`));
|
|
8325
|
+
});
|
|
8326
|
+
child.once("error", reject);
|
|
8327
|
+
});
|
|
8328
|
+
const client = new DeepseekApiClient(baseUrl);
|
|
8329
|
+
this.client = client;
|
|
8330
|
+
await this.startStreams(client);
|
|
8331
|
+
return client;
|
|
8332
|
+
}
|
|
8333
|
+
async startStreams(client) {
|
|
8334
|
+
const controller = new AbortController();
|
|
8335
|
+
this.streamController = controller;
|
|
8336
|
+
const muxReady = Promise.withResolvers();
|
|
8337
|
+
const hostReady = Promise.withResolvers();
|
|
8338
|
+
void (async () => {
|
|
8339
|
+
for await (const envelope of client.events.mux({}, controller.signal, muxReady.resolve)) this.handleMuxFrame(envelope.rpcId, envelope.payload);
|
|
8340
|
+
})().catch((error) => {
|
|
8341
|
+
muxReady.reject(error);
|
|
8342
|
+
if (!controller.signal.aborted) this.recordHistoryEvent("deepseek-error", { message: String(error) }, this.historyFile);
|
|
8343
|
+
});
|
|
8344
|
+
void (async () => {
|
|
8345
|
+
for await (const envelope of client.events.host({}, controller.signal, hostReady.resolve)) this.handleHostFrame(envelope.payload);
|
|
8346
|
+
})().catch((error) => {
|
|
8347
|
+
hostReady.reject(error);
|
|
8348
|
+
if (!controller.signal.aborted) this.recordHistoryEvent("deepseek-error", { message: String(error) }, this.historyFile);
|
|
8349
|
+
});
|
|
8350
|
+
await Promise.all([muxReady.promise, hostReady.promise]);
|
|
8351
|
+
}
|
|
8352
|
+
handleMuxFrame(rpcId, frame) {
|
|
8353
|
+
if ("sessionId" in frame && this.sessionId && frame.sessionId !== this.sessionId) return;
|
|
8354
|
+
if (frame.type === "session/event") {
|
|
8355
|
+
this.recordHistoryEvent("deepseek-session-event", { event: frame.event, view: frame.view }, this.historyFile);
|
|
8356
|
+
return;
|
|
8357
|
+
}
|
|
8358
|
+
if (frame.type === "session/jobs") {
|
|
8359
|
+
this.recordHistoryEvent("deepseek-jobs", { jobs: frame.jobs }, this.historyFile);
|
|
8360
|
+
return;
|
|
8361
|
+
}
|
|
8362
|
+
if (frame.type === "session/projection") {
|
|
8363
|
+
if (frame.key === "contextPressure" && isRecord2(frame.value)) this.contextPressure = frame.value;
|
|
8364
|
+
else if (frame.key === "contextBreakdown" && isRecord2(frame.value)) this.contextBreakdown = frame.value;
|
|
8365
|
+
else if (frame.key === "tokenUsage" && isRecord2(frame.value)) this.tokenUsage = frame.value;
|
|
8366
|
+
else return;
|
|
8367
|
+
this.emitDeepseekContextUsage();
|
|
8368
|
+
return;
|
|
8369
|
+
}
|
|
8370
|
+
if (frame.type === "approval/resolved" || frame.type === "question/resolved") {
|
|
8371
|
+
const requestId2 = frame.type === "approval/resolved" ? `approval:${frame.approvalId}` : `question:${frame.questionRpcId}`;
|
|
8372
|
+
this.pendingResponses.delete(requestId2);
|
|
8373
|
+
this.recordHistoryEvent("deepseek-input-resolved", {
|
|
8374
|
+
requestId: requestId2,
|
|
8375
|
+
status: frame.type === "question/resolved" && frame.outcome === "cancelled" ? "aborted" : "resolved"
|
|
8376
|
+
}, this.historyFile);
|
|
8377
|
+
return;
|
|
8378
|
+
}
|
|
8379
|
+
if (frame.type !== "approval/requested" && frame.type !== "question/requested") return;
|
|
8380
|
+
const requestId = frame.type === "approval/requested" ? `approval:${frame.approvalId}` : `question:${rpcId}`;
|
|
8381
|
+
this.pendingResponses.set(requestId, { rpcId, frame });
|
|
8382
|
+
this.recordHistoryEvent("deepseek-input-request", {
|
|
8383
|
+
requestId,
|
|
8384
|
+
kind: frame.type === "approval/requested" ? "approval" : "question",
|
|
8385
|
+
...frame.type === "approval/requested" ? { toolName: frame.toolName, reason: frame.reason } : { questions: frame.questions }
|
|
8386
|
+
}, this.historyFile);
|
|
8387
|
+
}
|
|
8388
|
+
handleHostFrame(frame) {
|
|
8389
|
+
if (!("sessionId" in frame) || !this.sessionId || frame.sessionId !== this.sessionId) return;
|
|
8390
|
+
if (frame.type === "host/agent-error") {
|
|
8391
|
+
this.recordHistoryEvent("deepseek-error", { message: frame.message }, this.historyFile);
|
|
8392
|
+
}
|
|
8393
|
+
if (frame.type === "host/session-status" && !frame.running) {
|
|
8394
|
+
this.resolveTurnCompletion?.();
|
|
8395
|
+
this.resolveTurnCompletion = null;
|
|
8396
|
+
}
|
|
8397
|
+
}
|
|
8398
|
+
emitDeepseekContextUsage() {
|
|
8399
|
+
const totalTokens = typeof this.contextPressure.projectedTokens === "number" ? this.contextPressure.projectedTokens : this.contextPressure.pressureTokens;
|
|
8400
|
+
if (typeof totalTokens !== "number") return;
|
|
8401
|
+
const maxTokens = typeof this.contextPressure.contextWindow === "number" ? this.contextPressure.contextWindow : null;
|
|
8402
|
+
const categories = [
|
|
8403
|
+
["System", this.contextBreakdown.systemTokens],
|
|
8404
|
+
["Tools", this.contextBreakdown.toolsTokens],
|
|
8405
|
+
["Messages", this.contextBreakdown.messageTokens]
|
|
8406
|
+
].flatMap(([name, tokens]) => typeof tokens === "number" ? [{ name: String(name), tokens, percentage: percentage(tokens, maxTokens) }] : []);
|
|
8407
|
+
this.emitContextUsage({
|
|
8408
|
+
provider: "deepseek",
|
|
8409
|
+
source: "provider_usage",
|
|
8410
|
+
model: this.selectedModel,
|
|
8411
|
+
totalTokens,
|
|
8412
|
+
maxTokens,
|
|
8413
|
+
percentage: percentage(totalTokens, maxTokens),
|
|
8414
|
+
compactsAutomatically: true,
|
|
8415
|
+
categories,
|
|
8416
|
+
apiUsage: {
|
|
8417
|
+
inputTokens: typeof this.tokenUsage.uncachedInputTokens === "number" ? this.tokenUsage.uncachedInputTokens : void 0,
|
|
8418
|
+
outputTokens: typeof this.tokenUsage.outputTokens === "number" ? this.tokenUsage.outputTokens : void 0,
|
|
8419
|
+
cacheCreationInputTokens: typeof this.tokenUsage.cacheWriteTokens === "number" ? this.tokenUsage.cacheWriteTokens : void 0,
|
|
8420
|
+
cacheReadInputTokens: typeof this.tokenUsage.cacheReadTokens === "number" ? this.tokenUsage.cacheReadTokens : void 0
|
|
8421
|
+
},
|
|
8422
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
8423
|
+
});
|
|
8424
|
+
}
|
|
8425
|
+
async processMessageInternal(request) {
|
|
8426
|
+
try {
|
|
8427
|
+
const client = await this.ensureClient();
|
|
8428
|
+
if (!this.sessionId) {
|
|
8429
|
+
this.sessionId = unwrap(await client.sessions.create({ cwd: this.workingDirectory })).sessionId;
|
|
8430
|
+
await this.onSaveSessionId(this.sessionId);
|
|
8431
|
+
}
|
|
8432
|
+
const model = request.model ?? DEFAULT_DEEPSEEK_MODEL;
|
|
8433
|
+
this.selectedModel = model;
|
|
8434
|
+
const current = unwrap(await client.sessions.models({ sessionId: this.sessionId })).current;
|
|
8435
|
+
const effort = reasoningEffort(request.thinkingLevel);
|
|
8436
|
+
if (current.model !== model || current.reasoningEffort !== effort) {
|
|
8437
|
+
unwrap(await client.sessions.selectModel({
|
|
8438
|
+
sessionId: this.sessionId,
|
|
8439
|
+
provider: "deepseek-official",
|
|
8440
|
+
model,
|
|
8441
|
+
...effort ? { reasoningEffort: effort } : {}
|
|
8442
|
+
}));
|
|
8443
|
+
}
|
|
8444
|
+
this.recordHistoryEvent("event_msg", { type: "user_message", message: request.message }, this.historyFile);
|
|
8445
|
+
this.turnCompletion = new Promise((resolve5) => {
|
|
8446
|
+
this.resolveTurnCompletion = resolve5;
|
|
8447
|
+
});
|
|
8448
|
+
const images = await normalizeImages(request.images ?? []);
|
|
8449
|
+
const combinedInstructions = this.buildCombinedInstructions(request.customInstructions);
|
|
8450
|
+
const prompt = combinedInstructions ? `<system_instructions>
|
|
8451
|
+
${combinedInstructions}
|
|
8452
|
+
</system_instructions>
|
|
8453
|
+
|
|
8454
|
+
${request.message}` : request.message;
|
|
8455
|
+
if (!request.planMode) {
|
|
8456
|
+
unwrap(await client.sessions.prompt({
|
|
8457
|
+
sessionId: this.sessionId,
|
|
8458
|
+
mode: "queue",
|
|
8459
|
+
content: [{ type: "text", text: "/plan off" }]
|
|
8460
|
+
}));
|
|
8461
|
+
}
|
|
8462
|
+
unwrap(await client.sessions.prompt({
|
|
8463
|
+
sessionId: this.sessionId,
|
|
8464
|
+
mode: "queue",
|
|
8465
|
+
content: [
|
|
8466
|
+
{ type: "text", text: request.planMode ? `/plan ${prompt}` : prompt },
|
|
8467
|
+
...images.map((image) => ({
|
|
8468
|
+
type: "image",
|
|
8469
|
+
mediaType: image.source.media_type,
|
|
8470
|
+
data: image.source.data
|
|
8471
|
+
}))
|
|
8472
|
+
]
|
|
8473
|
+
}));
|
|
8474
|
+
await this.turnCompletion;
|
|
8475
|
+
} catch (error) {
|
|
8476
|
+
this.recordHistoryEvent("deepseek-error", { message: error instanceof Error ? error.message : String(error) }, this.historyFile);
|
|
8477
|
+
} finally {
|
|
8478
|
+
this.turnCompletion = null;
|
|
8479
|
+
await this.historyFile.flush();
|
|
8480
|
+
await this.onTurnComplete();
|
|
8481
|
+
}
|
|
8482
|
+
}
|
|
8483
|
+
};
|
|
8484
|
+
|
|
8485
|
+
// src/managers/opencode-manager.ts
|
|
8486
|
+
import { existsSync as existsSync7 } from "fs";
|
|
8487
|
+
import { mkdir as mkdir13, readFile as readFile11 } from "fs/promises";
|
|
8488
|
+
import { delimiter, dirname as dirname7, join as join22 } from "path";
|
|
8067
8489
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
8068
|
-
import { fileURLToPath } from "url";
|
|
8490
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
8069
8491
|
import { Agent } from "undici";
|
|
8070
|
-
import { z as
|
|
8492
|
+
import { z as z4 } from "zod";
|
|
8071
8493
|
|
|
8072
8494
|
// ../shared/src/credentials/opencode-go.ts
|
|
8073
|
-
import { z } from "zod";
|
|
8495
|
+
import { z as z3 } from "zod";
|
|
8074
8496
|
var OPENCODE_GO_PROVIDER = "opencode-go";
|
|
8075
8497
|
var DEFAULT_OPENCODE_GO_MODEL = "glm-5.2";
|
|
8076
|
-
var opencodeGoModelsDevSchema =
|
|
8077
|
-
"opencode-go":
|
|
8078
|
-
models:
|
|
8079
|
-
id:
|
|
8080
|
-
name:
|
|
8081
|
-
description:
|
|
8082
|
-
status:
|
|
8498
|
+
var opencodeGoModelsDevSchema = z3.object({
|
|
8499
|
+
"opencode-go": z3.object({
|
|
8500
|
+
models: z3.record(z3.string(), z3.object({
|
|
8501
|
+
id: z3.string().optional(),
|
|
8502
|
+
name: z3.string(),
|
|
8503
|
+
description: z3.string().optional(),
|
|
8504
|
+
status: z3.enum(["alpha", "beta", "deprecated"]).optional()
|
|
8083
8505
|
}))
|
|
8084
8506
|
}).optional()
|
|
8085
8507
|
});
|
|
@@ -8109,8 +8531,8 @@ async function getAllowedOpenRouterModels() {
|
|
|
8109
8531
|
}
|
|
8110
8532
|
|
|
8111
8533
|
// src/managers/opencode-manager.ts
|
|
8112
|
-
var OPENCODE_SHIM_DIR =
|
|
8113
|
-
var OPENCODE_CONFIG_PATH =
|
|
8534
|
+
var OPENCODE_SHIM_DIR = dirname7(fileURLToPath2(new URL("../../scripts/opencode", import.meta.url)));
|
|
8535
|
+
var OPENCODE_CONFIG_PATH = join22(ENGINE_ENV.HOME_DIR, ".config", "opencode", "opencode.json");
|
|
8114
8536
|
var OPENCODE_FETCH_DISPATCHER = new Agent({ headersTimeout: 0, bodyTimeout: 0 });
|
|
8115
8537
|
var OPENCODE_SERVER_STARTUP_TIMEOUT_MS = 3e4;
|
|
8116
8538
|
var OPENCODE_WORKSPACE_PERMISSION = {
|
|
@@ -8140,12 +8562,12 @@ var OPENCODE_VARIANT_CANDIDATES_BY_THINKING_LEVEL = {
|
|
|
8140
8562
|
ultra: ["max", "xhigh", "high"],
|
|
8141
8563
|
ultracode: ["max", "xhigh", "high"]
|
|
8142
8564
|
};
|
|
8143
|
-
var opencodeAuthSchema =
|
|
8144
|
-
type:
|
|
8145
|
-
key:
|
|
8565
|
+
var opencodeAuthSchema = z4.record(z4.string(), z4.object({
|
|
8566
|
+
type: z4.string().optional(),
|
|
8567
|
+
key: z4.string().optional()
|
|
8146
8568
|
}));
|
|
8147
8569
|
async function hasOpencodeCredentials(provider) {
|
|
8148
|
-
if (!
|
|
8570
|
+
if (!existsSync7(OPENCODE_AUTH_PATH)) return false;
|
|
8149
8571
|
try {
|
|
8150
8572
|
const auth = opencodeAuthSchema.safeParse(JSON.parse(await readFile11(OPENCODE_AUTH_PATH, "utf8")));
|
|
8151
8573
|
return auth.success && auth.data[provider]?.type === "api" && Boolean(auth.data[provider]?.key);
|
|
@@ -8360,12 +8782,12 @@ var OpencodeManager = class extends CodingAgentManager {
|
|
|
8360
8782
|
constructor(options) {
|
|
8361
8783
|
super(options);
|
|
8362
8784
|
this.sessionId = options.initialSessionId;
|
|
8363
|
-
this.historyFilePath = options.historyFilePath ??
|
|
8785
|
+
this.historyFilePath = options.historyFilePath ?? join22(ENGINE_ENV.HOME_DIR, ".replicas", "opencode", "history.jsonl");
|
|
8364
8786
|
this.historyFile = new CodexHistoryFile(this.historyFilePath);
|
|
8365
8787
|
this.initializeManager(this.processMessageInternal.bind(this));
|
|
8366
8788
|
}
|
|
8367
8789
|
async initialize() {
|
|
8368
|
-
await
|
|
8790
|
+
await mkdir13(dirname7(this.historyFilePath), { recursive: true });
|
|
8369
8791
|
}
|
|
8370
8792
|
getHistorySink() {
|
|
8371
8793
|
return this.historyFile;
|
|
@@ -8869,8 +9291,8 @@ var OpencodeManager = class extends CodingAgentManager {
|
|
|
8869
9291
|
};
|
|
8870
9292
|
|
|
8871
9293
|
// src/managers/pi-manager.ts
|
|
8872
|
-
import { mkdir as
|
|
8873
|
-
import { dirname as
|
|
9294
|
+
import { mkdir as mkdir14 } from "fs/promises";
|
|
9295
|
+
import { dirname as dirname8, join as join23 } from "path";
|
|
8874
9296
|
import {
|
|
8875
9297
|
AuthStorage,
|
|
8876
9298
|
createAgentSession,
|
|
@@ -8953,12 +9375,12 @@ var PiManager = class extends CodingAgentManager {
|
|
|
8953
9375
|
providerApiKey = null;
|
|
8954
9376
|
constructor(options) {
|
|
8955
9377
|
super(options);
|
|
8956
|
-
this.historyFilePath = options.historyFilePath ??
|
|
9378
|
+
this.historyFilePath = options.historyFilePath ?? join23(PI_HISTORY_DIR, `${Date.now()}.jsonl`);
|
|
8957
9379
|
this.historyFile = new CodexHistoryFile(this.historyFilePath);
|
|
8958
9380
|
this.initializeManager(this.processMessageInternal.bind(this));
|
|
8959
9381
|
}
|
|
8960
9382
|
async initialize() {
|
|
8961
|
-
await
|
|
9383
|
+
await mkdir14(dirname8(this.historyFilePath), { recursive: true });
|
|
8962
9384
|
}
|
|
8963
9385
|
getHistorySink() {
|
|
8964
9386
|
return this.historyFile;
|
|
@@ -9053,7 +9475,7 @@ var PiManager = class extends CodingAgentManager {
|
|
|
9053
9475
|
const sessionManager = this.initialSessionId ? SessionManager.open(this.initialSessionId, PI_HISTORY_DIR, this.workingDirectory) : SessionManager.create(this.workingDirectory, PI_HISTORY_DIR);
|
|
9054
9476
|
const resourceLoader = new DefaultResourceLoader({
|
|
9055
9477
|
cwd: this.workingDirectory,
|
|
9056
|
-
agentDir:
|
|
9478
|
+
agentDir: join23(ENGINE_ENV.HOME_DIR, ".pi", "agent"),
|
|
9057
9479
|
extensionFactories: [registerCommandProtection(
|
|
9058
9480
|
this.workingDirectory,
|
|
9059
9481
|
this.historyFile,
|
|
@@ -9119,7 +9541,7 @@ var PiManager = class extends CodingAgentManager {
|
|
|
9119
9541
|
|
|
9120
9542
|
// src/managers/relay-tools.ts
|
|
9121
9543
|
import { createSdkMcpServer, tool } from "@anthropic-ai/claude-agent-sdk";
|
|
9122
|
-
import { z as
|
|
9544
|
+
import { z as z5 } from "zod";
|
|
9123
9545
|
|
|
9124
9546
|
// src/managers/relay-providers.ts
|
|
9125
9547
|
function isRelaySubagentProviderAllowed(provider, allowedProviders) {
|
|
@@ -9128,19 +9550,18 @@ function isRelaySubagentProviderAllowed(provider, allowedProviders) {
|
|
|
9128
9550
|
function getAvailableRelayProviders(availability) {
|
|
9129
9551
|
const codexAvailable = availability.codexAvailable ?? false;
|
|
9130
9552
|
const cursorAvailable = availability.cursorAvailable ?? false;
|
|
9553
|
+
const deepseekAvailable = availability.deepseekAvailable ?? false;
|
|
9131
9554
|
const opencodeAvailable = availability.opencodeAvailable ?? false;
|
|
9132
9555
|
const piAvailable = availability.piAvailable ?? false;
|
|
9133
9556
|
const providers = ["claude"];
|
|
9134
9557
|
if (codexAvailable) providers.push("codex");
|
|
9135
9558
|
if (cursorAvailable) providers.push("cursor");
|
|
9559
|
+
if (deepseekAvailable) providers.push("deepseek");
|
|
9136
9560
|
if (opencodeAvailable) providers.push("opencode");
|
|
9137
9561
|
if (piAvailable) providers.push("pi");
|
|
9138
9562
|
providers.push("relay");
|
|
9139
9563
|
return providers;
|
|
9140
9564
|
}
|
|
9141
|
-
function getAvailableCodeProviders(availability) {
|
|
9142
|
-
return getAvailableRelayProviders(availability).filter((provider) => provider === "codex" || provider === "cursor" || provider === "opencode" || provider === "pi");
|
|
9143
|
-
}
|
|
9144
9565
|
|
|
9145
9566
|
// src/managers/relay-tools.ts
|
|
9146
9567
|
var POLL_INTERVAL_MS = 2e3;
|
|
@@ -9221,6 +9642,10 @@ function extractFinalResponse(history) {
|
|
|
9221
9642
|
const text = extractTextBlocks(message?.content, "text", "");
|
|
9222
9643
|
if (text) return text;
|
|
9223
9644
|
}
|
|
9645
|
+
if (event.type === "deepseek-session-event") {
|
|
9646
|
+
const text = getDeepseekAssistantMessageText(payload.event, "text");
|
|
9647
|
+
if (text) return text;
|
|
9648
|
+
}
|
|
9224
9649
|
}
|
|
9225
9650
|
return null;
|
|
9226
9651
|
}
|
|
@@ -9237,42 +9662,36 @@ async function getChatFinalResponse(chatId) {
|
|
|
9237
9662
|
}
|
|
9238
9663
|
return extractFinalResponse(history) ?? "[No response from subagent]";
|
|
9239
9664
|
}
|
|
9240
|
-
function buildSpawnAgentTool(parentChatId, availability = {}, getAllowedProviders = () => monolithService.getRelaySubagentProviders()) {
|
|
9241
|
-
const
|
|
9242
|
-
const cursorAvailable = availability.cursorAvailable ?? false;
|
|
9243
|
-
const opencodeAvailable = availability.opencodeAvailable ?? false;
|
|
9244
|
-
const availableProviders = getAvailableRelayProviders(availability);
|
|
9245
|
-
const providerEnum = z3.enum(availableProviders);
|
|
9246
|
-
const codeProviders = getAvailableCodeProviders(availability);
|
|
9247
|
-
const providerDesc = codeProviders.length > 0 ? `Which agent to use. Prefer ${codeProviders.join(" or ")} for code writing, claude for exploration/analysis, relay for complex multi-step orchestration.` : "Which agent to use. Use claude for code writing, exploration, and analysis. Use relay for complex multi-step orchestration.";
|
|
9248
|
-
const useCases = codeProviders.length > 0 ? `- Complex code writing tasks (use provider '${codeProviders.join("' or '")}' with a capable model)
|
|
9249
|
-
- Codebase exploration that would consume many tokens (use provider 'claude')` : `- Complex code writing tasks (use provider 'claude')
|
|
9250
|
-
- Codebase exploration that would consume many tokens (use provider 'claude')`;
|
|
9665
|
+
function buildSpawnAgentTool(parentChatId, availability = {}, getAllowedProviders = () => monolithService.getRelaySubagentProviders(), getProviderAvailability = () => availability) {
|
|
9666
|
+
const providerEnum = z5.enum(VALID_RELAY_SUBAGENT_PROVIDERS);
|
|
9251
9667
|
return tool(
|
|
9252
9668
|
"spawn_agent",
|
|
9253
9669
|
`Spawn a new subagent to perform a task. The subagent runs in its own chat with a fresh context window.
|
|
9254
9670
|
|
|
9255
9671
|
Use this for:
|
|
9256
|
-
|
|
9672
|
+
- Complex code writing tasks (use a currently available code provider with a capable model)
|
|
9673
|
+
- Codebase exploration that would consume many tokens (use provider 'claude')
|
|
9257
9674
|
- Browser testing, large test runs, or other token-heavy operations
|
|
9258
9675
|
- Any task you want to delegate to preserve your own context
|
|
9259
9676
|
|
|
9260
9677
|
The tool blocks until the subagent completes and returns its final response.
|
|
9261
9678
|
You will also receive the chatId so you can send follow-up messages or clean up the chat.`,
|
|
9262
9679
|
{
|
|
9263
|
-
provider: providerEnum.describe(
|
|
9264
|
-
prompt:
|
|
9265
|
-
model:
|
|
9680
|
+
provider: providerEnum.describe("Which agent to use. Choose from the providers listed as currently available in Relay guidance. Prefer an available code provider for code writing, claude for exploration/analysis, and relay for complex multi-step orchestration."),
|
|
9681
|
+
prompt: z5.string().describe("The full prompt/instructions for the subagent. Be detailed - it has no context from your conversation."),
|
|
9682
|
+
model: z5.string().optional().describe([
|
|
9266
9683
|
`Model override. Claude: ${AGENT_MODELS.claude.join(", ")} (opus is the default; sonnet is faster).`,
|
|
9267
|
-
|
|
9268
|
-
|
|
9269
|
-
|
|
9270
|
-
|
|
9271
|
-
|
|
9272
|
-
|
|
9684
|
+
`Codex: ${AGENT_MODELS.codex.join(", ")}.`,
|
|
9685
|
+
`Cursor: ${AGENT_MODELS.cursor.join(", ")}.`,
|
|
9686
|
+
`DeepSeek Harness: ${AGENT_MODELS.deepseek.join(", ")}.`,
|
|
9687
|
+
`Opencode: ${AGENT_MODELS.opencode.join(", ")}.`,
|
|
9688
|
+
`Pi: ${AGENT_MODELS.pi.join(", ")}.`
|
|
9689
|
+
].join(" ")),
|
|
9690
|
+
thinking_level: z5.enum(VALID_THINKING_LEVELS).optional().describe(
|
|
9691
|
+
"Controls how much thinking/reasoning the subagent applies. low = light thinking, medium = moderate, high = deep reasoning, xhigh = extended effort, max = maximum effort, ultra = Codex ultra, ultracode = Claude Code dynamic workflows. Defaults: Claude = high; Codex, Cursor, DeepSeek Harness, Opencode, and Pi = medium."
|
|
9273
9692
|
),
|
|
9274
|
-
title:
|
|
9275
|
-
timeout_minutes:
|
|
9693
|
+
title: z5.string().optional().describe("Optional title for the subagent chat (for identification)."),
|
|
9694
|
+
timeout_minutes: z5.number().positive().optional().describe("Timeout in minutes for the subagent to complete (default: 10). Set higher for large tasks to avoid losing work.")
|
|
9276
9695
|
},
|
|
9277
9696
|
async (args) => {
|
|
9278
9697
|
try {
|
|
@@ -9290,6 +9709,12 @@ You will also receive the chatId so you can send follow-up messages or clean up
|
|
|
9290
9709
|
isError: true
|
|
9291
9710
|
};
|
|
9292
9711
|
}
|
|
9712
|
+
if (!isRelaySubagentProviderAllowed(provider, getAvailableRelayProviders(getProviderAvailability()))) {
|
|
9713
|
+
return {
|
|
9714
|
+
content: [{ type: "text", text: `Relay cannot use ${provider} because its credentials are unavailable.` }],
|
|
9715
|
+
isError: true
|
|
9716
|
+
};
|
|
9717
|
+
}
|
|
9293
9718
|
const createBody = {
|
|
9294
9719
|
provider,
|
|
9295
9720
|
title: args.title || `Subagent (${provider})`
|
|
@@ -9347,13 +9772,13 @@ var messageAgentTool = tool(
|
|
|
9347
9772
|
|
|
9348
9773
|
The tool blocks until the subagent completes and returns its response.`,
|
|
9349
9774
|
{
|
|
9350
|
-
chatId:
|
|
9351
|
-
message:
|
|
9352
|
-
model:
|
|
9353
|
-
thinking_level:
|
|
9775
|
+
chatId: z5.string().describe("The chat ID of the subagent (returned by spawn_agent)."),
|
|
9776
|
+
message: z5.string().describe("The follow-up message to send."),
|
|
9777
|
+
model: z5.string().optional().describe("Optional model override for this message."),
|
|
9778
|
+
thinking_level: z5.enum(VALID_THINKING_LEVELS).optional().describe(
|
|
9354
9779
|
"Controls how much thinking/reasoning the subagent applies. low = light thinking, medium = moderate, high = deep reasoning, xhigh = extended effort, max = maximum effort, ultra = Codex ultra, ultracode = Claude Code dynamic workflows. Defaults: Claude = high, Codex = medium, Cursor = medium, Opencode = medium."
|
|
9355
9780
|
),
|
|
9356
|
-
timeout_minutes:
|
|
9781
|
+
timeout_minutes: z5.number().positive().optional().describe("Timeout in minutes for the subagent to complete (default: 10). Set higher for large tasks to avoid losing work.")
|
|
9357
9782
|
},
|
|
9358
9783
|
async (args) => {
|
|
9359
9784
|
try {
|
|
@@ -9391,7 +9816,7 @@ var deleteAgentTool = tool(
|
|
|
9391
9816
|
"delete_agent",
|
|
9392
9817
|
`Delete a subagent chat to free resources. Use this after a subagent has completed its work and you no longer need to send it follow-up messages.`,
|
|
9393
9818
|
{
|
|
9394
|
-
chatId:
|
|
9819
|
+
chatId: z5.string().describe("The chat ID of the subagent to delete.")
|
|
9395
9820
|
},
|
|
9396
9821
|
async (args) => {
|
|
9397
9822
|
try {
|
|
@@ -9409,11 +9834,11 @@ var deleteAgentTool = tool(
|
|
|
9409
9834
|
}
|
|
9410
9835
|
}
|
|
9411
9836
|
);
|
|
9412
|
-
function createRelayMcpServer(parentChatId, availability = {}, getAllowedProviders) {
|
|
9837
|
+
function createRelayMcpServer(parentChatId, availability = {}, getAllowedProviders, getProviderAvailability) {
|
|
9413
9838
|
return createSdkMcpServer({
|
|
9414
9839
|
name: "relay-subagent-tools",
|
|
9415
9840
|
version: "1.0.0",
|
|
9416
|
-
tools: [buildSpawnAgentTool(parentChatId, availability, getAllowedProviders), messageAgentTool, deleteAgentTool]
|
|
9841
|
+
tools: [buildSpawnAgentTool(parentChatId, availability, getAllowedProviders, getProviderAvailability), messageAgentTool, deleteAgentTool]
|
|
9417
9842
|
});
|
|
9418
9843
|
}
|
|
9419
9844
|
|
|
@@ -9515,12 +9940,13 @@ function getUsingToolsSection() {
|
|
|
9515
9940
|
];
|
|
9516
9941
|
return [`# Using your tools`, ...prependBullets(items)].join("\n");
|
|
9517
9942
|
}
|
|
9518
|
-
function getDelegationSection(codexAvailable, cursorAvailable, opencodeAvailable, piAvailable) {
|
|
9519
|
-
const providerList = getAvailableRelayProviders({ codexAvailable, cursorAvailable, opencodeAvailable, piAvailable }).join(", ");
|
|
9943
|
+
function getDelegationSection(codexAvailable, cursorAvailable, deepseekAvailable, opencodeAvailable, piAvailable) {
|
|
9944
|
+
const providerList = getAvailableRelayProviders({ codexAvailable, cursorAvailable, deepseekAvailable, opencodeAvailable, piAvailable }).join(", ");
|
|
9520
9945
|
const spawnDesc = `Create a new subagent with a specific provider (${providerList}), send it a prompt, and wait for its response. Returns the chatId and the agent's final response. You can set a custom timeout via the timeout_minutes parameter (default: 10 minutes).`;
|
|
9521
9946
|
const claudeModelList = AGENT_MODELS.claude.join(", ");
|
|
9522
9947
|
const extraAgentLines = [
|
|
9523
9948
|
codexAvailable ? `Use provider 'codex' for heavy code writing, implementation, and large refactors. Suggested models: ${AGENT_MODELS.codex.join(", ")} (${AGENT_MODELS.codex[0]} is the default).` : null,
|
|
9949
|
+
deepseekAvailable ? `Use provider 'deepseek' for tasks that benefit from the DeepSeek Harness tool loop. Suggested models: ${AGENT_MODELS.deepseek.join(", ")}.` : null,
|
|
9524
9950
|
opencodeAvailable ? `Use provider 'opencode' for cheaper routine implementation tasks through OpenRouter-backed open source models. Suggested models: ${AGENT_MODELS.opencode.join(", ")}.` : null,
|
|
9525
9951
|
piAvailable ? `Use provider 'pi' for coding tasks through Pi's OpenRouter-backed coding agent. Suggested models: ${AGENT_MODELS.pi.join(", ")}.` : null,
|
|
9526
9952
|
cursorAvailable ? `Use provider 'cursor' for fast iteration on code changes. Suggested models: ${AGENT_MODELS.cursor.join(", ")}.` : null
|
|
@@ -9645,14 +10071,14 @@ function getEnvironmentSection() {
|
|
|
9645
10071
|
].join("\n");
|
|
9646
10072
|
}
|
|
9647
10073
|
function buildRelaySystemPrompt(options) {
|
|
9648
|
-
const { customInstructions, codexAvailable, cursorAvailable, opencodeAvailable, piAvailable } = options ?? {};
|
|
10074
|
+
const { customInstructions, codexAvailable, cursorAvailable, deepseekAvailable, opencodeAvailable, piAvailable } = options ?? {};
|
|
9649
10075
|
const sections = [
|
|
9650
10076
|
getIntroSection(),
|
|
9651
10077
|
getSystemSection(),
|
|
9652
10078
|
getDoingTasksSection(),
|
|
9653
10079
|
getActionsSection(),
|
|
9654
10080
|
getUsingToolsSection(),
|
|
9655
|
-
getDelegationSection(codexAvailable ?? false, cursorAvailable ?? false, opencodeAvailable ?? false, piAvailable ?? false),
|
|
10081
|
+
getDelegationSection(codexAvailable ?? false, cursorAvailable ?? false, deepseekAvailable ?? false, opencodeAvailable ?? false, piAvailable ?? false),
|
|
9656
10082
|
getToneAndStyleSection(),
|
|
9657
10083
|
getOutputEfficiencySection(),
|
|
9658
10084
|
getEnvironmentSection(),
|
|
@@ -9684,14 +10110,22 @@ var RelayManager = class {
|
|
|
9684
10110
|
constructor(options) {
|
|
9685
10111
|
const codexAvailable = options.codexAvailable ?? false;
|
|
9686
10112
|
const cursorAvailable = options.cursorAvailable ?? false;
|
|
10113
|
+
const deepseekAvailable = options.deepseekAvailable ?? false;
|
|
9687
10114
|
const opencodeAvailable = options.opencodeAvailable ?? false;
|
|
9688
10115
|
const piAvailable = options.piAvailable ?? false;
|
|
10116
|
+
const availability = { codexAvailable, cursorAvailable, deepseekAvailable, opencodeAvailable, piAvailable };
|
|
10117
|
+
const getProviderAvailability = options.getProviderAvailability ?? (() => availability);
|
|
9689
10118
|
this.inner = new ClaudeManager({
|
|
9690
10119
|
...options,
|
|
9691
|
-
systemPromptOverride: (customInstructions) => buildRelaySystemPrompt({ customInstructions,
|
|
10120
|
+
systemPromptOverride: (customInstructions) => buildRelaySystemPrompt({ customInstructions, ...getProviderAvailability() }),
|
|
9692
10121
|
tools: RELAY_TOOLS,
|
|
9693
10122
|
mcpServers: {
|
|
9694
|
-
"relay-subagent-tools": createRelayMcpServer(
|
|
10123
|
+
"relay-subagent-tools": createRelayMcpServer(
|
|
10124
|
+
options.chatId,
|
|
10125
|
+
availability,
|
|
10126
|
+
void 0,
|
|
10127
|
+
getProviderAvailability
|
|
10128
|
+
)
|
|
9695
10129
|
},
|
|
9696
10130
|
envOverrides: {
|
|
9697
10131
|
CLAUDE_CODE_STREAM_CLOSE_TIMEOUT: "900000"
|
|
@@ -9743,17 +10177,17 @@ var RelayManager = class {
|
|
|
9743
10177
|
// src/analytics/agent/activity/agent-chat-activity-tracker-service.ts
|
|
9744
10178
|
import {
|
|
9745
10179
|
appendFile as appendFile3,
|
|
9746
|
-
mkdir as
|
|
10180
|
+
mkdir as mkdir15,
|
|
9747
10181
|
readFile as readFile12,
|
|
9748
10182
|
readdir as readdir6,
|
|
9749
10183
|
rename as rename2,
|
|
9750
10184
|
unlink as unlink3
|
|
9751
10185
|
} from "fs/promises";
|
|
9752
|
-
import { join as
|
|
10186
|
+
import { join as join24 } from "path";
|
|
9753
10187
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
9754
10188
|
|
|
9755
10189
|
// src/analytics/agent/activity/skill-mcp-call-extractor.ts
|
|
9756
|
-
var NON_MCP_SERVERS = /* @__PURE__ */ new Set(["claude", "cursor", "opencode", "pi", "custom", "dynamic"]);
|
|
10190
|
+
var NON_MCP_SERVERS = /* @__PURE__ */ new Set(["claude", "cursor", "deepseek", "opencode", "pi", "custom", "dynamic"]);
|
|
9757
10191
|
function mcpNameFromToolCall(message) {
|
|
9758
10192
|
const parsedName = parseMcpToolName(message.tool);
|
|
9759
10193
|
if (parsedName) return parsedName.server;
|
|
@@ -9800,7 +10234,7 @@ var AgentChatActivityBuffer = class {
|
|
|
9800
10234
|
options.storageName,
|
|
9801
10235
|
...options.legacyStorageNames ?? []
|
|
9802
10236
|
];
|
|
9803
|
-
this.liveFile =
|
|
10237
|
+
this.liveFile = join24(ENGINE_DIR2, `${options.storageName}.jsonl`);
|
|
9804
10238
|
this.segmentFilePatterns = this.storageNames.map(
|
|
9805
10239
|
(storageName) => new RegExp(`^${storageName}\\.(\\d+)\\.jsonl$`)
|
|
9806
10240
|
);
|
|
@@ -9817,7 +10251,7 @@ var AgentChatActivityBuffer = class {
|
|
|
9817
10251
|
failed: 0
|
|
9818
10252
|
});
|
|
9819
10253
|
append(record) {
|
|
9820
|
-
const pending =
|
|
10254
|
+
const pending = mkdir15(ENGINE_DIR2, { recursive: true }).then(
|
|
9821
10255
|
() => appendFile3(this.liveFile, `${JSON.stringify(record)}
|
|
9822
10256
|
`, "utf-8")
|
|
9823
10257
|
).catch((error) => {
|
|
@@ -9859,8 +10293,8 @@ var AgentChatActivityBuffer = class {
|
|
|
9859
10293
|
await Promise.allSettled([...this.pendingAppends]);
|
|
9860
10294
|
for (const storageName of this.storageNames) {
|
|
9861
10295
|
await rename2(
|
|
9862
|
-
|
|
9863
|
-
|
|
10296
|
+
join24(ENGINE_DIR2, `${storageName}.jsonl`),
|
|
10297
|
+
join24(ENGINE_DIR2, `${storageName}.${Date.now()}.jsonl`)
|
|
9864
10298
|
).catch(() => {
|
|
9865
10299
|
});
|
|
9866
10300
|
}
|
|
@@ -9871,7 +10305,7 @@ var AgentChatActivityBuffer = class {
|
|
|
9871
10305
|
if (!this.segmentFilePatterns.some((pattern) => pattern.test(entry)))
|
|
9872
10306
|
continue;
|
|
9873
10307
|
try {
|
|
9874
|
-
await this.uploadSegment(
|
|
10308
|
+
await this.uploadSegment(join24(ENGINE_DIR2, entry));
|
|
9875
10309
|
flushed++;
|
|
9876
10310
|
} catch (error) {
|
|
9877
10311
|
failed++;
|
|
@@ -9903,7 +10337,7 @@ var AgentChatActivityBuffer = class {
|
|
|
9903
10337
|
) && entry.endsWith(UPLOADED_SUFFIX)
|
|
9904
10338
|
).sort();
|
|
9905
10339
|
for (const entry of uploaded.slice(0, -MAX_UPLOADED_SEGMENTS)) {
|
|
9906
|
-
await unlink3(
|
|
10340
|
+
await unlink3(join24(ENGINE_DIR2, entry)).catch(() => {
|
|
9907
10341
|
});
|
|
9908
10342
|
}
|
|
9909
10343
|
return { flushed, failed };
|
|
@@ -10136,17 +10570,17 @@ var keepAliveService = new KeepAliveService();
|
|
|
10136
10570
|
// src/services/canvas-service.ts
|
|
10137
10571
|
import { readdir as readdir7, readFile as readFile13, stat as stat3 } from "fs/promises";
|
|
10138
10572
|
import { homedir as homedir14 } from "os";
|
|
10139
|
-
import { join as
|
|
10573
|
+
import { join as join25 } from "path";
|
|
10140
10574
|
var GLOBAL_CANVAS_DIRECTORIES = [
|
|
10141
|
-
|
|
10142
|
-
|
|
10143
|
-
|
|
10575
|
+
join25(homedir14(), ".claude", "plans"),
|
|
10576
|
+
join25(process.env.XDG_DATA_HOME ?? join25(homedir14(), ".local", "share"), "opencode", "plans"),
|
|
10577
|
+
join25(homedir14(), ".replicas", "canvas")
|
|
10144
10578
|
];
|
|
10145
10579
|
async function canvasDirectories() {
|
|
10146
10580
|
const repositories = await gitService.listRepositories().catch(() => []);
|
|
10147
10581
|
return [
|
|
10148
10582
|
...GLOBAL_CANVAS_DIRECTORIES,
|
|
10149
|
-
...repositories.map((repository) =>
|
|
10583
|
+
...repositories.map((repository) => join25(repository.path, ".opencode", "plans"))
|
|
10150
10584
|
];
|
|
10151
10585
|
}
|
|
10152
10586
|
var CanvasService = class {
|
|
@@ -10170,7 +10604,7 @@ var CanvasService = class {
|
|
|
10170
10604
|
for (const entry of entries) {
|
|
10171
10605
|
if (entry.name.startsWith(".")) continue;
|
|
10172
10606
|
const filename = current.relativePath ? `${current.relativePath}/${entry.name}` : entry.name;
|
|
10173
|
-
const filePath =
|
|
10607
|
+
const filePath = join25(current.directory, entry.name);
|
|
10174
10608
|
if (entry.isDirectory()) {
|
|
10175
10609
|
pending.push({ directory: filePath, relativePath: filename });
|
|
10176
10610
|
continue;
|
|
@@ -10195,7 +10629,7 @@ var CanvasService = class {
|
|
|
10195
10629
|
if (!safe) return null;
|
|
10196
10630
|
const { kind, mimeType } = classifyCanvasFilename(safe);
|
|
10197
10631
|
for (const directory of await this.directories()) {
|
|
10198
|
-
const filePath =
|
|
10632
|
+
const filePath = join25(directory, safe);
|
|
10199
10633
|
let sizeBytes = 0;
|
|
10200
10634
|
let updatedAt = "";
|
|
10201
10635
|
try {
|
|
@@ -10367,13 +10801,13 @@ async function reconcileCanvasItems(filenames) {
|
|
|
10367
10801
|
import { createReadStream } from "fs";
|
|
10368
10802
|
import { createHash as createHash2 } from "crypto";
|
|
10369
10803
|
import { readdir as readdir8, readFile as readFile14, stat as stat4 } from "fs/promises";
|
|
10370
|
-
import { basename as basename2, join as
|
|
10804
|
+
import { basename as basename2, join as join27 } from "path";
|
|
10371
10805
|
|
|
10372
10806
|
// src/services/chat/chat-senders.ts
|
|
10373
|
-
import { join as
|
|
10374
|
-
var CHAT_SENDERS_DIR =
|
|
10807
|
+
import { join as join26 } from "path";
|
|
10808
|
+
var CHAT_SENDERS_DIR = join26(ENGINE_DIR2, "chat-senders");
|
|
10375
10809
|
function chatMessageSendersFilePath(chatId) {
|
|
10376
|
-
return
|
|
10810
|
+
return join26(CHAT_SENDERS_DIR, `${chatId}.jsonl`);
|
|
10377
10811
|
}
|
|
10378
10812
|
function parseChatMessageSendersJsonl(content) {
|
|
10379
10813
|
return content.split("\n").flatMap((line) => {
|
|
@@ -10389,9 +10823,9 @@ function parseChatMessageSendersJsonl(content) {
|
|
|
10389
10823
|
|
|
10390
10824
|
// src/services/upload-chat-transcripts.ts
|
|
10391
10825
|
var HISTORY_DIRS = [
|
|
10392
|
-
|
|
10393
|
-
|
|
10394
|
-
|
|
10826
|
+
join27(ENGINE_DIR2, "claude-histories"),
|
|
10827
|
+
join27(ENGINE_DIR2, "relay-histories"),
|
|
10828
|
+
join27(ENGINE_DIR2, "codex-histories")
|
|
10395
10829
|
];
|
|
10396
10830
|
async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map(), capture) {
|
|
10397
10831
|
let flushed = 0;
|
|
@@ -10409,7 +10843,7 @@ async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map(), ca
|
|
|
10409
10843
|
if (!entry.endsWith(".jsonl")) continue;
|
|
10410
10844
|
const chatId = basename2(entry, ".jsonl");
|
|
10411
10845
|
tasks.push(
|
|
10412
|
-
uploadChatTranscript(chatId,
|
|
10846
|
+
uploadChatTranscript(chatId, join27(dir, entry), chatsById.get(chatId), capture).then((artifact) => {
|
|
10413
10847
|
flushed++;
|
|
10414
10848
|
if (artifact && capture) revisions.push(artifact);
|
|
10415
10849
|
}).catch((err) => {
|
|
@@ -10511,7 +10945,7 @@ async function flushRepoState() {
|
|
|
10511
10945
|
// src/services/upload-engine-logs.ts
|
|
10512
10946
|
import { createReadStream as createReadStream2 } from "fs";
|
|
10513
10947
|
import { readdir as readdir9, stat as stat5 } from "fs/promises";
|
|
10514
|
-
import { join as
|
|
10948
|
+
import { join as join28 } from "path";
|
|
10515
10949
|
var MAX_ENGINE_LOG_FLUSH_SESSIONS = 10;
|
|
10516
10950
|
var MAX_ENGINE_LOG_FLUSH_BYTES = 5 * 1024 * 1024;
|
|
10517
10951
|
var ENGINE_LOG_FLUSH_TIMEOUT_MS = 2e4;
|
|
@@ -10540,7 +10974,7 @@ async function flushAllEngineLogs() {
|
|
|
10540
10974
|
const candidates = (await Promise.all(filenames.slice(0, MAX_ENGINE_LOG_FLUSH_SESSIONS).map(async (filename) => {
|
|
10541
10975
|
try {
|
|
10542
10976
|
const sessionId = filename.slice(0, -".log".length);
|
|
10543
|
-
const filePath =
|
|
10977
|
+
const filePath = join28(LOG_DIR, filename);
|
|
10544
10978
|
const fileStat = await runBeforeDeadline(() => stat5(filePath), deadline);
|
|
10545
10979
|
if (!fileStat.isFile()) {
|
|
10546
10980
|
skipped++;
|
|
@@ -10636,16 +11070,19 @@ async function uploadEngineLog(input, timeoutMs) {
|
|
|
10636
11070
|
}
|
|
10637
11071
|
|
|
10638
11072
|
// src/services/chat/chat-service.ts
|
|
10639
|
-
var CODEX_AUTH_PATH2 =
|
|
11073
|
+
var CODEX_AUTH_PATH2 = join29(homedir15(), ".codex", "auth.json");
|
|
10640
11074
|
var CHATS_BACKUP_FILE = `${CHATS_FILE}.bak`;
|
|
10641
11075
|
function isCodexAvailable() {
|
|
10642
|
-
return
|
|
11076
|
+
return existsSync8(CODEX_AUTH_PATH2) || Boolean(ENGINE_ENV.OPENAI_API_KEY);
|
|
10643
11077
|
}
|
|
10644
11078
|
function isOpencodeAvailable() {
|
|
10645
|
-
return
|
|
11079
|
+
return existsSync8(OPENCODE_AUTH_PATH);
|
|
11080
|
+
}
|
|
11081
|
+
function isDeepseekAvailable() {
|
|
11082
|
+
return Boolean(getDeepseekApiKey());
|
|
10646
11083
|
}
|
|
10647
11084
|
function isPiAvailable() {
|
|
10648
|
-
return
|
|
11085
|
+
return existsSync8(PI_AUTH_PATH);
|
|
10649
11086
|
}
|
|
10650
11087
|
function isCursorAvailable() {
|
|
10651
11088
|
return Boolean(ENGINE_ENV.CURSOR_API_KEY);
|
|
@@ -10763,13 +11200,13 @@ var ChatService = class {
|
|
|
10763
11200
|
persistInFlight = false;
|
|
10764
11201
|
persistQueued = false;
|
|
10765
11202
|
async initialize() {
|
|
10766
|
-
await
|
|
10767
|
-
await
|
|
10768
|
-
await
|
|
10769
|
-
await
|
|
10770
|
-
await
|
|
10771
|
-
await
|
|
10772
|
-
await
|
|
11203
|
+
await mkdir16(ENGINE_DIR2, { recursive: true });
|
|
11204
|
+
await mkdir16(CLAUDE_HISTORY_DIR, { recursive: true });
|
|
11205
|
+
await mkdir16(RELAY_HISTORY_DIR, { recursive: true });
|
|
11206
|
+
await mkdir16(CODEX_HISTORY_DIR, { recursive: true });
|
|
11207
|
+
await mkdir16(CURSOR_HISTORY_DIR, { recursive: true });
|
|
11208
|
+
await mkdir16(OPENCODE_HISTORY_DIR, { recursive: true });
|
|
11209
|
+
await mkdir16(CHAT_SENDERS_DIR, { recursive: true });
|
|
10773
11210
|
const persisted = await this.loadChats();
|
|
10774
11211
|
for (const chat of persisted) {
|
|
10775
11212
|
const runtime = this.createRuntimeChat(chat);
|
|
@@ -11155,7 +11592,7 @@ var ChatService = class {
|
|
|
11155
11592
|
return descendants;
|
|
11156
11593
|
}
|
|
11157
11594
|
async deleteHistoryFile(persisted) {
|
|
11158
|
-
await rm2(
|
|
11595
|
+
await rm2(join29(HISTORY_DIR_BY_PROVIDER[persisted.provider], `${persisted.id}.jsonl`), { force: true });
|
|
11159
11596
|
await rm2(chatMessageSendersFilePath(persisted.id), { force: true });
|
|
11160
11597
|
}
|
|
11161
11598
|
async getChatHistory(chatId, page = {}) {
|
|
@@ -11260,7 +11697,7 @@ var ChatService = class {
|
|
|
11260
11697
|
if (persisted.provider === "claude") {
|
|
11261
11698
|
provider = new ClaudeManager({
|
|
11262
11699
|
workingDirectory: this.workingDirectory,
|
|
11263
|
-
historyFilePath:
|
|
11700
|
+
historyFilePath: join29(CLAUDE_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
11264
11701
|
initialSessionId: persisted.providerSessionId,
|
|
11265
11702
|
onSaveSessionId: saveSession,
|
|
11266
11703
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -11268,24 +11705,39 @@ var ChatService = class {
|
|
|
11268
11705
|
onProcessingChanged
|
|
11269
11706
|
});
|
|
11270
11707
|
} else if (persisted.provider === "relay") {
|
|
11708
|
+
const getProviderAvailability = () => ({
|
|
11709
|
+
codexAvailable: isCodexAvailable(),
|
|
11710
|
+
opencodeAvailable: isOpencodeAvailable(),
|
|
11711
|
+
piAvailable: isPiAvailable(),
|
|
11712
|
+
cursorAvailable: isCursorAvailable(),
|
|
11713
|
+
deepseekAvailable: isDeepseekAvailable()
|
|
11714
|
+
});
|
|
11271
11715
|
provider = new RelayManager({
|
|
11272
11716
|
workingDirectory: this.workingDirectory,
|
|
11273
|
-
historyFilePath:
|
|
11717
|
+
historyFilePath: join29(RELAY_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
11274
11718
|
initialSessionId: persisted.providerSessionId,
|
|
11275
11719
|
onSaveSessionId: saveSession,
|
|
11276
11720
|
onTurnComplete: onProviderTurnComplete,
|
|
11277
11721
|
onEvent: onProviderEvent,
|
|
11278
11722
|
onProcessingChanged,
|
|
11279
11723
|
chatId: persisted.id,
|
|
11280
|
-
|
|
11281
|
-
|
|
11282
|
-
piAvailable: isPiAvailable(),
|
|
11283
|
-
cursorAvailable: isCursorAvailable()
|
|
11724
|
+
...getProviderAvailability(),
|
|
11725
|
+
getProviderAvailability
|
|
11284
11726
|
});
|
|
11285
11727
|
} else if (persisted.provider === "cursor") {
|
|
11286
11728
|
provider = new CursorManager({
|
|
11287
11729
|
workingDirectory: this.workingDirectory,
|
|
11288
|
-
historyFilePath:
|
|
11730
|
+
historyFilePath: join29(CURSOR_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
11731
|
+
initialSessionId: persisted.providerSessionId,
|
|
11732
|
+
onSaveSessionId: saveSession,
|
|
11733
|
+
onTurnComplete: onProviderTurnComplete,
|
|
11734
|
+
onEvent: onProviderEvent,
|
|
11735
|
+
onProcessingChanged
|
|
11736
|
+
});
|
|
11737
|
+
} else if (persisted.provider === "deepseek") {
|
|
11738
|
+
provider = new DeepseekManager({
|
|
11739
|
+
workingDirectory: this.workingDirectory,
|
|
11740
|
+
historyFilePath: join29(DEEPSEEK_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
11289
11741
|
initialSessionId: persisted.providerSessionId,
|
|
11290
11742
|
onSaveSessionId: saveSession,
|
|
11291
11743
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -11295,7 +11747,7 @@ var ChatService = class {
|
|
|
11295
11747
|
} else if (persisted.provider === "opencode") {
|
|
11296
11748
|
provider = new OpencodeManager({
|
|
11297
11749
|
workingDirectory: this.workingDirectory,
|
|
11298
|
-
historyFilePath:
|
|
11750
|
+
historyFilePath: join29(OPENCODE_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
11299
11751
|
initialSessionId: persisted.providerSessionId,
|
|
11300
11752
|
onSaveSessionId: saveSession,
|
|
11301
11753
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -11305,7 +11757,7 @@ var ChatService = class {
|
|
|
11305
11757
|
} else if (persisted.provider === "pi") {
|
|
11306
11758
|
provider = new PiManager({
|
|
11307
11759
|
workingDirectory: this.workingDirectory,
|
|
11308
|
-
historyFilePath:
|
|
11760
|
+
historyFilePath: join29(PI_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
11309
11761
|
initialSessionId: persisted.providerSessionId,
|
|
11310
11762
|
onSaveSessionId: saveSession,
|
|
11311
11763
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -11315,7 +11767,7 @@ var ChatService = class {
|
|
|
11315
11767
|
} else {
|
|
11316
11768
|
provider = new CodexAspManager({
|
|
11317
11769
|
workingDirectory: this.workingDirectory,
|
|
11318
|
-
historyFilePath:
|
|
11770
|
+
historyFilePath: join29(CODEX_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
11319
11771
|
initialSessionId: persisted.providerSessionId,
|
|
11320
11772
|
onSaveSessionId: saveSession,
|
|
11321
11773
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -11480,7 +11932,7 @@ var ChatService = class {
|
|
|
11480
11932
|
});
|
|
11481
11933
|
uploadChatTranscript(
|
|
11482
11934
|
chatId,
|
|
11483
|
-
|
|
11935
|
+
join29(HISTORY_DIR_BY_PROVIDER[chat.persisted.provider], `${chatId}.jsonl`),
|
|
11484
11936
|
this.toSummary(chat)
|
|
11485
11937
|
).catch((err) => {
|
|
11486
11938
|
console.error("[ChatService] Failed to upload chat transcript:", { chatId, err });
|
|
@@ -11618,7 +12070,7 @@ var ChatService = class {
|
|
|
11618
12070
|
// src/services/repo-file-service.ts
|
|
11619
12071
|
import { execFile } from "child_process";
|
|
11620
12072
|
import { readFile as readFile16, realpath, stat as stat6 } from "fs/promises";
|
|
11621
|
-
import { join as
|
|
12073
|
+
import { join as join30, resolve as resolve2, extname as extname2 } from "path";
|
|
11622
12074
|
var CACHE_TTL_MS = 3e4;
|
|
11623
12075
|
var SEARCH_TIMEOUT_MS = 15e3;
|
|
11624
12076
|
var MAX_CONTENT_BYTES = 256 * 1024;
|
|
@@ -11770,7 +12222,7 @@ var RepoFileService = class {
|
|
|
11770
12222
|
const repo = repos.find((r) => r.name === repoName);
|
|
11771
12223
|
if (!repo) return null;
|
|
11772
12224
|
try {
|
|
11773
|
-
const fullPath = await realpath(resolve2(
|
|
12225
|
+
const fullPath = await realpath(resolve2(join30(repo.path, filePath)));
|
|
11774
12226
|
const repoRoot = await realpath(repo.path);
|
|
11775
12227
|
const repoPrefix = repoRoot.endsWith("/") ? repoRoot : repoRoot + "/";
|
|
11776
12228
|
if (!fullPath.startsWith(repoPrefix) && fullPath !== repoRoot) return null;
|
|
@@ -11903,22 +12355,22 @@ var RepoFileService = class {
|
|
|
11903
12355
|
|
|
11904
12356
|
// src/v1-routes.ts
|
|
11905
12357
|
import { Hono } from "hono";
|
|
11906
|
-
import { z as
|
|
12358
|
+
import { z as z6 } from "zod";
|
|
11907
12359
|
import { readdir as readdir11, stat as stat7, readFile as readFile19 } from "fs/promises";
|
|
11908
|
-
import { join as
|
|
12360
|
+
import { join as join33, resolve as resolve3 } from "path";
|
|
11909
12361
|
|
|
11910
12362
|
// src/services/warm-hooks-service.ts
|
|
11911
|
-
import { spawn as
|
|
12363
|
+
import { spawn as spawn4 } from "child_process";
|
|
11912
12364
|
import { readFile as readFile18 } from "fs/promises";
|
|
11913
|
-
import { existsSync as
|
|
11914
|
-
import { join as
|
|
12365
|
+
import { existsSync as existsSync9 } from "fs";
|
|
12366
|
+
import { join as join32 } from "path";
|
|
11915
12367
|
|
|
11916
12368
|
// src/services/warm-hook-logs-service.ts
|
|
11917
|
-
import { mkdir as
|
|
12369
|
+
import { mkdir as mkdir17, readFile as readFile17, writeFile as writeFile6, readdir as readdir10, appendFile as appendFile5, unlink as unlink4 } from "fs/promises";
|
|
11918
12370
|
import { homedir as homedir16 } from "os";
|
|
11919
|
-
import { join as
|
|
11920
|
-
var LOGS_DIR2 =
|
|
11921
|
-
var CURRENT_RUN_LOG =
|
|
12371
|
+
import { join as join31 } from "path";
|
|
12372
|
+
var LOGS_DIR2 = join31(homedir16(), ".replicas", "warm-hook-logs");
|
|
12373
|
+
var CURRENT_RUN_LOG = join31(LOGS_DIR2, "current-run.log");
|
|
11922
12374
|
var GLOBAL_FILENAME = "global.json";
|
|
11923
12375
|
function withPreview2(stored) {
|
|
11924
12376
|
const preview = buildHookOutputPreview(stored.output);
|
|
@@ -11926,7 +12378,7 @@ function withPreview2(stored) {
|
|
|
11926
12378
|
}
|
|
11927
12379
|
var WarmHookLogsService = class {
|
|
11928
12380
|
async ensureDir() {
|
|
11929
|
-
await
|
|
12381
|
+
await mkdir17(LOGS_DIR2, { recursive: true });
|
|
11930
12382
|
}
|
|
11931
12383
|
async saveGlobalHookLog(entry) {
|
|
11932
12384
|
await this.ensureDir();
|
|
@@ -11935,7 +12387,7 @@ var WarmHookLogsService = class {
|
|
|
11935
12387
|
hookName: "organization",
|
|
11936
12388
|
...entry
|
|
11937
12389
|
};
|
|
11938
|
-
await writeFile6(
|
|
12390
|
+
await writeFile6(join31(LOGS_DIR2, GLOBAL_FILENAME), `${JSON.stringify(log, null, 2)}
|
|
11939
12391
|
`, "utf-8");
|
|
11940
12392
|
}
|
|
11941
12393
|
async saveEnvironmentHookLog(entry) {
|
|
@@ -11945,7 +12397,7 @@ var WarmHookLogsService = class {
|
|
|
11945
12397
|
hookName: "environment",
|
|
11946
12398
|
...entry
|
|
11947
12399
|
};
|
|
11948
|
-
await writeFile6(
|
|
12400
|
+
await writeFile6(join31(LOGS_DIR2, ENVIRONMENT_HOOK_LOG_FILENAME), `${JSON.stringify(log, null, 2)}
|
|
11949
12401
|
`, "utf-8");
|
|
11950
12402
|
}
|
|
11951
12403
|
async saveRepoHookLog(repoName, entry) {
|
|
@@ -11955,7 +12407,7 @@ var WarmHookLogsService = class {
|
|
|
11955
12407
|
hookName: repoName,
|
|
11956
12408
|
...entry
|
|
11957
12409
|
};
|
|
11958
|
-
await writeFile6(
|
|
12410
|
+
await writeFile6(join31(LOGS_DIR2, repoHookLogFilename(repoName)), `${JSON.stringify(log, null, 2)}
|
|
11959
12411
|
`, "utf-8");
|
|
11960
12412
|
}
|
|
11961
12413
|
async getAllLogs() {
|
|
@@ -11974,7 +12426,7 @@ var WarmHookLogsService = class {
|
|
|
11974
12426
|
continue;
|
|
11975
12427
|
}
|
|
11976
12428
|
try {
|
|
11977
|
-
const raw = await readFile17(
|
|
12429
|
+
const raw = await readFile17(join31(LOGS_DIR2, file), "utf-8");
|
|
11978
12430
|
const stored = JSON.parse(raw);
|
|
11979
12431
|
logs.push(withPreview2(stored));
|
|
11980
12432
|
} catch {
|
|
@@ -12012,7 +12464,7 @@ var WarmHookLogsService = class {
|
|
|
12012
12464
|
async getFullOutput(hookType, hookName) {
|
|
12013
12465
|
const filename = hookType === "global" ? GLOBAL_FILENAME : hookType === "environment" ? ENVIRONMENT_HOOK_LOG_FILENAME : repoHookLogFilename(hookName);
|
|
12014
12466
|
try {
|
|
12015
|
-
const raw = await readFile17(
|
|
12467
|
+
const raw = await readFile17(join31(LOGS_DIR2, filename), "utf-8");
|
|
12016
12468
|
const stored = JSON.parse(raw);
|
|
12017
12469
|
if (stored.hookType !== hookType || stored.hookName !== hookName) {
|
|
12018
12470
|
return null;
|
|
@@ -12031,8 +12483,8 @@ var warmHookLogsService = new WarmHookLogsService();
|
|
|
12031
12483
|
// src/services/warm-hooks-service.ts
|
|
12032
12484
|
async function readRepoWarmHook(repoPath) {
|
|
12033
12485
|
for (const filename of REPLICAS_CONFIG_FILENAMES) {
|
|
12034
|
-
const configPath =
|
|
12035
|
-
if (!
|
|
12486
|
+
const configPath = join32(repoPath, filename);
|
|
12487
|
+
if (!existsSync9(configPath)) {
|
|
12036
12488
|
continue;
|
|
12037
12489
|
}
|
|
12038
12490
|
try {
|
|
@@ -12083,7 +12535,7 @@ async function executeHookScriptStreaming(params) {
|
|
|
12083
12535
|
params.onChunk(`$ ${params.label}
|
|
12084
12536
|
`);
|
|
12085
12537
|
return new Promise((resolve5) => {
|
|
12086
|
-
const proc =
|
|
12538
|
+
const proc = spawn4("bash", ["-lc", params.content], {
|
|
12087
12539
|
cwd: params.cwd,
|
|
12088
12540
|
env: process.env,
|
|
12089
12541
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -12293,8 +12745,8 @@ ${combinedScript}` : combinedScript;
|
|
|
12293
12745
|
|
|
12294
12746
|
// src/services/terminal-service.ts
|
|
12295
12747
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
12296
|
-
import { existsSync as
|
|
12297
|
-
import { spawn as
|
|
12748
|
+
import { existsSync as existsSync10 } from "fs";
|
|
12749
|
+
import { spawn as spawn5 } from "node-pty";
|
|
12298
12750
|
var MAX_REPLAY_CHARS = 1024 * 1024;
|
|
12299
12751
|
var MAX_TERMINAL_SESSIONS = 8;
|
|
12300
12752
|
var MAX_PENDING_INPUT = 64;
|
|
@@ -12312,8 +12764,8 @@ var TerminalService = class {
|
|
|
12312
12764
|
});
|
|
12313
12765
|
}
|
|
12314
12766
|
const id = randomUUID7();
|
|
12315
|
-
const shell = process.env.SHELL &&
|
|
12316
|
-
const pty =
|
|
12767
|
+
const shell = process.env.SHELL && existsSync10(process.env.SHELL) ? process.env.SHELL : "/bin/bash";
|
|
12768
|
+
const pty = spawn5(shell, ["-l"], {
|
|
12317
12769
|
name: "xterm-256color",
|
|
12318
12770
|
cols,
|
|
12319
12771
|
rows,
|
|
@@ -12411,75 +12863,75 @@ var TerminalService = class {
|
|
|
12411
12863
|
var terminalService = new TerminalService();
|
|
12412
12864
|
|
|
12413
12865
|
// src/v1-routes.ts
|
|
12414
|
-
var imageMediaTypeSchema =
|
|
12415
|
-
var createPreviewSchema =
|
|
12416
|
-
port:
|
|
12417
|
-
publicUrl:
|
|
12866
|
+
var imageMediaTypeSchema = z6.enum(IMAGE_MEDIA_TYPES);
|
|
12867
|
+
var createPreviewSchema = z6.object({
|
|
12868
|
+
port: z6.number().int().min(1).max(65535),
|
|
12869
|
+
publicUrl: z6.string().min(1)
|
|
12418
12870
|
});
|
|
12419
|
-
var terminalSizeSchema =
|
|
12420
|
-
cols:
|
|
12421
|
-
rows:
|
|
12871
|
+
var terminalSizeSchema = z6.object({
|
|
12872
|
+
cols: z6.number().int().min(2).max(500),
|
|
12873
|
+
rows: z6.number().int().min(1).max(200)
|
|
12422
12874
|
});
|
|
12423
|
-
var writeTerminalSessionSchema =
|
|
12424
|
-
data:
|
|
12425
|
-
generation:
|
|
12426
|
-
sequence:
|
|
12875
|
+
var writeTerminalSessionSchema = z6.object({
|
|
12876
|
+
data: z6.string().max(64 * 1024),
|
|
12877
|
+
generation: z6.number().int().nonnegative(),
|
|
12878
|
+
sequence: z6.number().int().nonnegative()
|
|
12427
12879
|
});
|
|
12428
|
-
var mergePullRequestSchema =
|
|
12429
|
-
prUrl:
|
|
12880
|
+
var mergePullRequestSchema = z6.object({
|
|
12881
|
+
prUrl: z6.string().url()
|
|
12430
12882
|
});
|
|
12431
|
-
var sendMessageSchema =
|
|
12432
|
-
messageId:
|
|
12433
|
-
submittedAt:
|
|
12434
|
-
message:
|
|
12435
|
-
model:
|
|
12436
|
-
customInstructions:
|
|
12437
|
-
planMode:
|
|
12438
|
-
images:
|
|
12439
|
-
type:
|
|
12440
|
-
source:
|
|
12441
|
-
|
|
12442
|
-
type:
|
|
12883
|
+
var sendMessageSchema = z6.object({
|
|
12884
|
+
messageId: z6.string().min(1).optional(),
|
|
12885
|
+
submittedAt: z6.string().datetime().optional(),
|
|
12886
|
+
message: z6.string().min(1),
|
|
12887
|
+
model: z6.string().optional(),
|
|
12888
|
+
customInstructions: z6.string().optional(),
|
|
12889
|
+
planMode: z6.boolean().optional(),
|
|
12890
|
+
images: z6.array(z6.object({
|
|
12891
|
+
type: z6.literal("image"),
|
|
12892
|
+
source: z6.union([
|
|
12893
|
+
z6.object({
|
|
12894
|
+
type: z6.literal("base64"),
|
|
12443
12895
|
media_type: imageMediaTypeSchema,
|
|
12444
|
-
data:
|
|
12896
|
+
data: z6.string().min(1)
|
|
12445
12897
|
}),
|
|
12446
|
-
|
|
12447
|
-
type:
|
|
12448
|
-
url:
|
|
12898
|
+
z6.object({
|
|
12899
|
+
type: z6.literal("url"),
|
|
12900
|
+
url: z6.string().url()
|
|
12449
12901
|
})
|
|
12450
12902
|
])
|
|
12451
12903
|
})).optional(),
|
|
12452
|
-
thinkingLevel:
|
|
12453
|
-
goalMode:
|
|
12454
|
-
fastMode:
|
|
12455
|
-
enableInteractiveTools:
|
|
12456
|
-
type:
|
|
12457
|
-
merge:
|
|
12458
|
-
idempotencyKey:
|
|
12459
|
-
senderUserId:
|
|
12460
|
-
senderEmail:
|
|
12461
|
-
senderDisplayName:
|
|
12462
|
-
senderAvatarUrl:
|
|
12463
|
-
errorNotificationTarget:
|
|
12464
|
-
|
|
12465
|
-
|
|
12466
|
-
|
|
12467
|
-
type:
|
|
12468
|
-
provider:
|
|
12469
|
-
resource:
|
|
12470
|
-
repositoryId:
|
|
12471
|
-
resourceNumber:
|
|
12904
|
+
thinkingLevel: z6.enum(VALID_THINKING_LEVELS).optional(),
|
|
12905
|
+
goalMode: z6.boolean().optional(),
|
|
12906
|
+
fastMode: z6.boolean().optional(),
|
|
12907
|
+
enableInteractiveTools: z6.boolean().optional(),
|
|
12908
|
+
type: z6.string().min(1).optional(),
|
|
12909
|
+
merge: z6.boolean().optional(),
|
|
12910
|
+
idempotencyKey: z6.string().min(1).max(128).optional(),
|
|
12911
|
+
senderUserId: z6.string().optional(),
|
|
12912
|
+
senderEmail: z6.string().optional(),
|
|
12913
|
+
senderDisplayName: z6.string().optional(),
|
|
12914
|
+
senderAvatarUrl: z6.string().optional(),
|
|
12915
|
+
errorNotificationTarget: z6.discriminatedUnion("type", [
|
|
12916
|
+
z6.object({ type: z6.literal("slack") }),
|
|
12917
|
+
z6.object({ type: z6.literal("linear"), sessionId: z6.string().min(1) }),
|
|
12918
|
+
z6.object({
|
|
12919
|
+
type: z6.literal("code_host"),
|
|
12920
|
+
provider: z6.enum(["github", "gitlab"]),
|
|
12921
|
+
resource: z6.enum(["issue", "pull_request"]),
|
|
12922
|
+
repositoryId: z6.string().min(1),
|
|
12923
|
+
resourceNumber: z6.number().int().positive()
|
|
12472
12924
|
}),
|
|
12473
|
-
|
|
12925
|
+
z6.object({ type: z6.literal("automation"), executionId: z6.string().min(1) })
|
|
12474
12926
|
]).optional()
|
|
12475
12927
|
});
|
|
12476
|
-
var respondToolInputSchema =
|
|
12477
|
-
requestId:
|
|
12478
|
-
selectionId:
|
|
12928
|
+
var respondToolInputSchema = z6.object({
|
|
12929
|
+
requestId: z6.string().min(1),
|
|
12930
|
+
selectionId: z6.string().min(1)
|
|
12479
12931
|
});
|
|
12480
|
-
var updateGoalSchema =
|
|
12481
|
-
objective:
|
|
12482
|
-
status:
|
|
12932
|
+
var updateGoalSchema = z6.object({
|
|
12933
|
+
objective: z6.string().trim().min(1).max(MAX_CODEX_GOAL_OBJECTIVE_CHARS).optional(),
|
|
12934
|
+
status: z6.enum(["active", "paused"]).optional()
|
|
12483
12935
|
}).refine((body) => body.objective !== void 0 || body.status !== void 0, {
|
|
12484
12936
|
message: "Goal objective or status required"
|
|
12485
12937
|
});
|
|
@@ -12670,7 +13122,7 @@ function createV1Routes(deps) {
|
|
|
12670
13122
|
const result = await deps.chatService.updateGoal(c.req.param("chatId"), body);
|
|
12671
13123
|
return c.json(result);
|
|
12672
13124
|
} catch (error) {
|
|
12673
|
-
if (error instanceof
|
|
13125
|
+
if (error instanceof z6.ZodError) {
|
|
12674
13126
|
return c.json(jsonError(error.issues[0]?.message || "Invalid goal update"), 400);
|
|
12675
13127
|
}
|
|
12676
13128
|
if (error instanceof ChatNotFoundError) {
|
|
@@ -13295,7 +13747,7 @@ data: ${JSON.stringify("Terminal session not found")}
|
|
|
13295
13747
|
const logFiles = files.filter((f) => f.endsWith(".log"));
|
|
13296
13748
|
const sessions = await Promise.all(
|
|
13297
13749
|
logFiles.map(async (filename) => {
|
|
13298
|
-
const filePath =
|
|
13750
|
+
const filePath = join33(LOG_DIR, filename);
|
|
13299
13751
|
const fileStat = await stat7(filePath);
|
|
13300
13752
|
const sessionId = filename.replace(/\.log$/, "");
|
|
13301
13753
|
return {
|
|
@@ -13401,17 +13853,17 @@ var HeartbeatService = class _HeartbeatService {
|
|
|
13401
13853
|
var heartbeatService = new HeartbeatService();
|
|
13402
13854
|
|
|
13403
13855
|
// src/services/workspace-sdk-service.ts
|
|
13404
|
-
import { cp, mkdir as
|
|
13405
|
-
import { dirname as
|
|
13406
|
-
import { fileURLToPath as
|
|
13856
|
+
import { cp, mkdir as mkdir18 } from "fs/promises";
|
|
13857
|
+
import { dirname as dirname9, resolve as resolve4 } from "path";
|
|
13858
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
13407
13859
|
async function installWorkspaceSdk() {
|
|
13408
|
-
const source = resolve4(
|
|
13860
|
+
const source = resolve4(dirname9(fileURLToPath3(import.meta.url)), "../../workspace-sdk");
|
|
13409
13861
|
const targets = [
|
|
13410
13862
|
resolve4(ENGINE_ENV.HOME_DIR, "node_modules/@replicas/sdk"),
|
|
13411
13863
|
"/tmp/node_modules/@replicas/sdk"
|
|
13412
13864
|
];
|
|
13413
13865
|
await Promise.all(targets.map(async (target) => {
|
|
13414
|
-
await
|
|
13866
|
+
await mkdir18(target, { recursive: true });
|
|
13415
13867
|
await cp(source, target, { recursive: true, force: true });
|
|
13416
13868
|
}));
|
|
13417
13869
|
}
|
|
@@ -13439,7 +13891,7 @@ async function timeStartupStep(name, fn) {
|
|
|
13439
13891
|
async function waitForInitializationGate() {
|
|
13440
13892
|
if (!ENGINE_ENV.REPLICAS_ENGINE_DEFER_INITIALIZATION) return;
|
|
13441
13893
|
const deadline = Date.now() + ENGINE_INIT_GATE_TIMEOUT_MS;
|
|
13442
|
-
while (!
|
|
13894
|
+
while (!existsSync11(SANDBOX_PATHS.ENGINE_INIT_GATE)) {
|
|
13443
13895
|
if (Date.now() >= deadline) {
|
|
13444
13896
|
throw new Error("Timed out waiting for deferred engine initialization gate");
|
|
13445
13897
|
}
|