replicas-engine 0.1.451 → 0.1.453
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 +279 -69
- package/package.json +3 -1
package/dist/src/index.js
CHANGED
|
@@ -43,10 +43,13 @@ function createErrorResult(error) {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
// ../shared/src/agent.ts
|
|
46
|
-
var VALID_AGENT_PROVIDERS = ["claude", "codex", "cursor", "opencode", "relay"];
|
|
46
|
+
var VALID_AGENT_PROVIDERS = ["claude", "codex", "cursor", "opencode", "pi", "relay"];
|
|
47
47
|
var VALID_CODING_AGENT_PROVIDERS = VALID_AGENT_PROVIDERS.filter(
|
|
48
48
|
(provider) => provider !== "relay"
|
|
49
49
|
);
|
|
50
|
+
function isValidAgentProvider(value) {
|
|
51
|
+
return VALID_AGENT_PROVIDERS.some((p) => p === value);
|
|
52
|
+
}
|
|
50
53
|
var VALID_THINKING_LEVELS = ["low", "medium", "high", "xhigh", "max"];
|
|
51
54
|
var CODEX_REASONING_EFFORT_BY_THINKING_LEVEL = {
|
|
52
55
|
low: "low",
|
|
@@ -166,6 +169,7 @@ var DEFAULT_CHAT_TITLES = {
|
|
|
166
169
|
codex: "Codex",
|
|
167
170
|
cursor: "Cursor",
|
|
168
171
|
opencode: "Opencode",
|
|
172
|
+
pi: "Pi",
|
|
169
173
|
relay: "Relay"
|
|
170
174
|
};
|
|
171
175
|
function isDefaultChat(chat) {
|
|
@@ -188,6 +192,13 @@ var GPT_5_6_LUNA_MODEL = "gpt-5.6-luna";
|
|
|
188
192
|
var DEFAULT_CODEX_MODEL = GPT_5_6_SOL_MODEL;
|
|
189
193
|
var DEFAULT_CURSOR_MODEL = "composer-2.5";
|
|
190
194
|
var DEFAULT_OPENCODE_MODEL = "z-ai/glm-5.2";
|
|
195
|
+
var DEFAULT_PI_MODEL = DEFAULT_OPENCODE_MODEL;
|
|
196
|
+
var OPENROUTER_MODELS = [
|
|
197
|
+
DEFAULT_OPENCODE_MODEL,
|
|
198
|
+
"minimax/minimax-m3",
|
|
199
|
+
"xiaomi/mimo-v2.5-pro",
|
|
200
|
+
"moonshotai/kimi-k2.6"
|
|
201
|
+
];
|
|
191
202
|
function normalizeClaudeModel(model) {
|
|
192
203
|
if (model === "opus" || model === CLAUDE_OPUS_1M_MODEL || model === LEGACY_CLAUDE_OPUS_1M_MODEL) {
|
|
193
204
|
return DEFAULT_CLAUDE_MODEL;
|
|
@@ -256,7 +267,8 @@ var AGENT_MODELS = {
|
|
|
256
267
|
CLAUDE_HAIKU_4_5_MODEL,
|
|
257
268
|
"kimi-k2.5"
|
|
258
269
|
],
|
|
259
|
-
opencode:
|
|
270
|
+
opencode: OPENROUTER_MODELS,
|
|
271
|
+
pi: OPENROUTER_MODELS,
|
|
260
272
|
relay: [CLAUDE_FABLE_5_MODEL, DEFAULT_CLAUDE_MODEL, CLAUDE_SONNET_5_MODEL]
|
|
261
273
|
};
|
|
262
274
|
var MODEL_LABELS = {
|
|
@@ -516,7 +528,7 @@ var WORKSPACE_SIZES = ["small", "large"];
|
|
|
516
528
|
var INVALID_WORKSPACE_SIZE_ERROR = `Invalid size: must be one of ${WORKSPACE_SIZES.join(", ")}`;
|
|
517
529
|
|
|
518
530
|
// ../shared/src/e2b.ts
|
|
519
|
-
var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-19-
|
|
531
|
+
var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-19-v5";
|
|
520
532
|
|
|
521
533
|
// ../shared/src/runtime-env.ts
|
|
522
534
|
function shellQuotePosix(value) {
|
|
@@ -672,7 +684,7 @@ var SLASH_COMMANDS = [
|
|
|
672
684
|
command: "/plan",
|
|
673
685
|
description: "Switch to plan mode and optionally send a prompt.",
|
|
674
686
|
argumentHint: "[prompt]",
|
|
675
|
-
providers: ["claude", "codex", "cursor", "opencode", "relay"]
|
|
687
|
+
providers: ["claude", "codex", "cursor", "opencode", "pi", "relay"]
|
|
676
688
|
},
|
|
677
689
|
{
|
|
678
690
|
command: "/fast",
|
|
@@ -2730,6 +2742,9 @@ var DESKTOP_NOVNC_PORT = 6080;
|
|
|
2730
2742
|
|
|
2731
2743
|
// ../shared/src/engine/v1.ts
|
|
2732
2744
|
var MERGED_MESSAGE_SEPARATOR = "\n\n<!-- replicas:merged -->\n\n";
|
|
2745
|
+
var ENGINE_HEALTH_WAIT_HEADER = "X-Replicas-Health-Wait";
|
|
2746
|
+
var ENGINE_HEALTH_WAIT_QUERY_PARAM = "wait_ms";
|
|
2747
|
+
var ENGINE_HEALTH_MAX_WAIT_MS = 2e3;
|
|
2733
2748
|
function normalizeCodexAspTranscriptStatus(status, failed = false) {
|
|
2734
2749
|
if (failed || status === "failed" || status === "declined") return "failed";
|
|
2735
2750
|
if (status === "completed") return "completed";
|
|
@@ -5012,6 +5027,9 @@ function detectCursorAuthMethod() {
|
|
|
5012
5027
|
function detectOpencodeAuthMethod() {
|
|
5013
5028
|
return existsSync3(OPENCODE_AUTH_PATH) || ENGINE_ENV.OPENROUTER_API_KEY ? "api_key" : "none";
|
|
5014
5029
|
}
|
|
5030
|
+
function detectPiAuthMethod() {
|
|
5031
|
+
return ENGINE_ENV.OPENROUTER_API_KEY ? "api_key" : "none";
|
|
5032
|
+
}
|
|
5015
5033
|
async function detectGitIdentityConfigured() {
|
|
5016
5034
|
try {
|
|
5017
5035
|
const { stdout } = await execFileAsync("git", ["config", "--global", "user.name"]);
|
|
@@ -5069,6 +5087,7 @@ function createDefaultDetails() {
|
|
|
5069
5087
|
codexAuthMethod: "none",
|
|
5070
5088
|
cursorAuthMethod: "none",
|
|
5071
5089
|
opencodeAuthMethod: "none",
|
|
5090
|
+
piAuthMethod: "none",
|
|
5072
5091
|
lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5073
5092
|
};
|
|
5074
5093
|
}
|
|
@@ -5104,6 +5123,7 @@ var EnvironmentDetailsService = class {
|
|
|
5104
5123
|
details.codexAuthMethod = detectCodexAuthMethod();
|
|
5105
5124
|
details.cursorAuthMethod = detectCursorAuthMethod();
|
|
5106
5125
|
details.opencodeAuthMethod = detectOpencodeAuthMethod();
|
|
5126
|
+
details.piAuthMethod = detectPiAuthMethod();
|
|
5107
5127
|
details.gitIdentityConfigured = gitIdentityConfigured;
|
|
5108
5128
|
const ghConfigured = existsSync3(GH_HOSTS_PATH);
|
|
5109
5129
|
details.githubAccessConfigured = ghConfigured;
|
|
@@ -5854,9 +5874,9 @@ async function registerDesktopPreview() {
|
|
|
5854
5874
|
|
|
5855
5875
|
// src/services/chat/chat-service.ts
|
|
5856
5876
|
import { existsSync as existsSync7 } from "fs";
|
|
5857
|
-
import { appendFile as appendFile3, copyFile, mkdir as
|
|
5877
|
+
import { appendFile as appendFile3, copyFile, mkdir as mkdir14, readFile as readFile14, rename as rename2, rm as rm2 } from "fs/promises";
|
|
5858
5878
|
import { homedir as homedir15 } from "os";
|
|
5859
|
-
import { join as
|
|
5879
|
+
import { join as join22 } from "path";
|
|
5860
5880
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
5861
5881
|
|
|
5862
5882
|
// src/managers/claude-manager.ts
|
|
@@ -6576,16 +6596,16 @@ var CodingAgentManager = class {
|
|
|
6576
6596
|
});
|
|
6577
6597
|
}
|
|
6578
6598
|
recordHistoryEvent(type, payload, historyFile) {
|
|
6579
|
-
const
|
|
6599
|
+
const eventPayload2 = {};
|
|
6580
6600
|
if (payload && typeof payload === "object") {
|
|
6581
|
-
Object.assign(
|
|
6601
|
+
Object.assign(eventPayload2, payload);
|
|
6582
6602
|
} else {
|
|
6583
|
-
|
|
6603
|
+
eventPayload2.value = payload;
|
|
6584
6604
|
}
|
|
6585
6605
|
const event = {
|
|
6586
6606
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6587
6607
|
type,
|
|
6588
|
-
payload:
|
|
6608
|
+
payload: eventPayload2
|
|
6589
6609
|
};
|
|
6590
6610
|
this.onEvent(event);
|
|
6591
6611
|
historyFile.append(event);
|
|
@@ -8569,7 +8589,7 @@ var DEFAULT_CODEX_ARGS = ["app-server", "--listen", "stdio://"];
|
|
|
8569
8589
|
var MIN_CODEX_CLI_VERSION = "0.144.0";
|
|
8570
8590
|
var CODEX_UPGRADE_TIMEOUT_MS = 12e4;
|
|
8571
8591
|
var codexCliVersionEnsured = null;
|
|
8572
|
-
var ENGINE_PACKAGE_VERSION = "0.1.
|
|
8592
|
+
var ENGINE_PACKAGE_VERSION = "0.1.453";
|
|
8573
8593
|
var INITIALIZE_METHOD = "initialize";
|
|
8574
8594
|
var INITIALIZED_NOTIFICATION = "initialized";
|
|
8575
8595
|
var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
|
|
@@ -9447,12 +9467,14 @@ var RELAY_HISTORY_DIR = join15(ENGINE_DIR2, "relay-histories");
|
|
|
9447
9467
|
var CODEX_HISTORY_DIR = join15(ENGINE_DIR2, "codex-histories");
|
|
9448
9468
|
var CURSOR_HISTORY_DIR = join15(ENGINE_DIR2, "cursor-histories");
|
|
9449
9469
|
var OPENCODE_HISTORY_DIR = join15(ENGINE_DIR2, "opencode-histories");
|
|
9470
|
+
var PI_HISTORY_DIR = join15(ENGINE_DIR2, "pi-histories");
|
|
9450
9471
|
var HISTORY_DIR_BY_PROVIDER = {
|
|
9451
9472
|
claude: CLAUDE_HISTORY_DIR,
|
|
9452
9473
|
relay: RELAY_HISTORY_DIR,
|
|
9453
9474
|
codex: CODEX_HISTORY_DIR,
|
|
9454
9475
|
cursor: CURSOR_HISTORY_DIR,
|
|
9455
|
-
opencode: OPENCODE_HISTORY_DIR
|
|
9476
|
+
opencode: OPENCODE_HISTORY_DIR,
|
|
9477
|
+
pi: PI_HISTORY_DIR
|
|
9456
9478
|
};
|
|
9457
9479
|
|
|
9458
9480
|
// src/services/chat/errors.ts
|
|
@@ -11744,6 +11766,162 @@ var OpencodeManager = class extends CodingAgentManager {
|
|
|
11744
11766
|
}
|
|
11745
11767
|
};
|
|
11746
11768
|
|
|
11769
|
+
// src/managers/pi-manager.ts
|
|
11770
|
+
import { mkdir as mkdir13 } from "fs/promises";
|
|
11771
|
+
import { dirname as dirname7, join as join19 } from "path";
|
|
11772
|
+
import {
|
|
11773
|
+
AuthStorage,
|
|
11774
|
+
createAgentSession,
|
|
11775
|
+
ModelRegistry,
|
|
11776
|
+
SessionManager,
|
|
11777
|
+
DefaultResourceLoader
|
|
11778
|
+
} from "@mariozechner/pi-coding-agent";
|
|
11779
|
+
function eventPayload(event) {
|
|
11780
|
+
return isRecord4(event) ? { ...event } : { value: event };
|
|
11781
|
+
}
|
|
11782
|
+
function registerCommandProtection(cwd) {
|
|
11783
|
+
return (pi) => {
|
|
11784
|
+
pi.on("tool_call", async (event) => {
|
|
11785
|
+
const command = extractToolCommand(event.input);
|
|
11786
|
+
const result = await evaluateCommandProtection({
|
|
11787
|
+
provider: "pi",
|
|
11788
|
+
source: "pi_tool_call",
|
|
11789
|
+
toolName: event.toolName,
|
|
11790
|
+
toolInput: event.input,
|
|
11791
|
+
command,
|
|
11792
|
+
cwd,
|
|
11793
|
+
toolUseId: event.toolCallId
|
|
11794
|
+
});
|
|
11795
|
+
if (!result.allowed) {
|
|
11796
|
+
reportCommandProtectionBlock({ provider: "pi", toolName: event.toolName, command, reason: result.reason });
|
|
11797
|
+
return { block: true, reason: result.reason ?? "Command blocked by Replicas protection." };
|
|
11798
|
+
}
|
|
11799
|
+
return void 0;
|
|
11800
|
+
});
|
|
11801
|
+
};
|
|
11802
|
+
}
|
|
11803
|
+
var PiManager = class extends CodingAgentManager {
|
|
11804
|
+
session = null;
|
|
11805
|
+
unsubscribe = null;
|
|
11806
|
+
activeSessionFile = null;
|
|
11807
|
+
historyFilePath;
|
|
11808
|
+
historyFile;
|
|
11809
|
+
constructor(options) {
|
|
11810
|
+
super(options);
|
|
11811
|
+
this.historyFilePath = options.historyFilePath ?? join19(PI_HISTORY_DIR, `${Date.now()}.jsonl`);
|
|
11812
|
+
this.historyFile = new CodexHistoryFile(this.historyFilePath);
|
|
11813
|
+
this.initializeManager(this.processMessageInternal.bind(this));
|
|
11814
|
+
}
|
|
11815
|
+
async initialize() {
|
|
11816
|
+
await mkdir13(dirname7(this.historyFilePath), { recursive: true });
|
|
11817
|
+
}
|
|
11818
|
+
async interruptActiveTurn() {
|
|
11819
|
+
await this.session?.abort();
|
|
11820
|
+
}
|
|
11821
|
+
async steerRequest(request) {
|
|
11822
|
+
if (!this.session?.isStreaming) return false;
|
|
11823
|
+
await this.session.steer(request.message);
|
|
11824
|
+
return true;
|
|
11825
|
+
}
|
|
11826
|
+
async getHistory() {
|
|
11827
|
+
await this.historyFile.flush();
|
|
11828
|
+
const history = await this.historyFile.load();
|
|
11829
|
+
return { thread_id: this.activeSessionFile ?? this.initialSessionId, events: history.events, goal: null };
|
|
11830
|
+
}
|
|
11831
|
+
async listSlashCommands() {
|
|
11832
|
+
await this.initialized;
|
|
11833
|
+
return mergeSlashCommands(...(this.session?.promptTemplates ?? []).map((template) => createProviderSlashCommand("pi", template.name, template.description)).filter((command) => Boolean(command)));
|
|
11834
|
+
}
|
|
11835
|
+
dispose() {
|
|
11836
|
+
this.unsubscribe?.();
|
|
11837
|
+
this.unsubscribe = null;
|
|
11838
|
+
this.session?.dispose();
|
|
11839
|
+
this.session = null;
|
|
11840
|
+
}
|
|
11841
|
+
async ensureSession(request) {
|
|
11842
|
+
if (this.session) {
|
|
11843
|
+
if (request.model && request.model !== this.session.model?.id) {
|
|
11844
|
+
const model2 = this.session.modelRegistry.find("openrouter", request.model);
|
|
11845
|
+
if (model2) await this.session.setModel(model2);
|
|
11846
|
+
}
|
|
11847
|
+
if (request.thinkingLevel) this.session.setThinkingLevel(request.thinkingLevel);
|
|
11848
|
+
return this.session;
|
|
11849
|
+
}
|
|
11850
|
+
const apiKey = ENGINE_ENV.OPENROUTER_API_KEY;
|
|
11851
|
+
if (!apiKey) throw new Error("OpenRouter API key is not configured for Pi.");
|
|
11852
|
+
const authStorage = AuthStorage.inMemory({ openrouter: { type: "api_key", key: apiKey } });
|
|
11853
|
+
const modelRegistry = ModelRegistry.create(authStorage);
|
|
11854
|
+
const openRouterModels = modelRegistry.getAll().filter((candidate) => candidate.provider === "openrouter");
|
|
11855
|
+
const modelTemplate = openRouterModels[0];
|
|
11856
|
+
if (!modelTemplate) throw new Error("Pi OpenRouter model catalog is empty.");
|
|
11857
|
+
modelRegistry.registerProvider("openrouter", {
|
|
11858
|
+
api: modelTemplate.api,
|
|
11859
|
+
apiKey,
|
|
11860
|
+
baseUrl: modelTemplate.baseUrl,
|
|
11861
|
+
models: [
|
|
11862
|
+
...openRouterModels,
|
|
11863
|
+
...OPENROUTER_MODELS.filter((id) => !openRouterModels.some((candidate) => candidate.id === id)).map((id) => ({
|
|
11864
|
+
id,
|
|
11865
|
+
name: id,
|
|
11866
|
+
api: modelTemplate.api,
|
|
11867
|
+
baseUrl: modelTemplate.baseUrl,
|
|
11868
|
+
reasoning: modelTemplate.reasoning,
|
|
11869
|
+
input: modelTemplate.input,
|
|
11870
|
+
cost: modelTemplate.cost,
|
|
11871
|
+
contextWindow: modelTemplate.contextWindow,
|
|
11872
|
+
maxTokens: modelTemplate.maxTokens
|
|
11873
|
+
}))
|
|
11874
|
+
]
|
|
11875
|
+
});
|
|
11876
|
+
const modelId = request.model ?? DEFAULT_PI_MODEL;
|
|
11877
|
+
const model = modelRegistry.find("openrouter", modelId) ?? modelRegistry.find("openrouter", DEFAULT_PI_MODEL);
|
|
11878
|
+
if (!model) throw new Error(`Pi model is not available through OpenRouter: ${modelId}`);
|
|
11879
|
+
const sessionManager = this.initialSessionId ? SessionManager.open(this.initialSessionId, PI_HISTORY_DIR, this.workingDirectory) : SessionManager.create(this.workingDirectory, PI_HISTORY_DIR);
|
|
11880
|
+
const resourceLoader = new DefaultResourceLoader({
|
|
11881
|
+
cwd: this.workingDirectory,
|
|
11882
|
+
agentDir: join19(ENGINE_ENV.HOME_DIR, ".pi", "agent"),
|
|
11883
|
+
extensionFactories: [registerCommandProtection(this.workingDirectory)],
|
|
11884
|
+
appendSystemPrompt: [this.buildCombinedInstructions() ?? ""]
|
|
11885
|
+
});
|
|
11886
|
+
await resourceLoader.reload();
|
|
11887
|
+
const result = await createAgentSession({
|
|
11888
|
+
cwd: this.workingDirectory,
|
|
11889
|
+
authStorage,
|
|
11890
|
+
modelRegistry,
|
|
11891
|
+
model,
|
|
11892
|
+
sessionManager,
|
|
11893
|
+
resourceLoader
|
|
11894
|
+
});
|
|
11895
|
+
this.session = result.session;
|
|
11896
|
+
if (request.thinkingLevel) this.session.setThinkingLevel(request.thinkingLevel);
|
|
11897
|
+
this.activeSessionFile = sessionManager.getSessionFile() ?? null;
|
|
11898
|
+
await this.onSaveSessionId(this.activeSessionFile);
|
|
11899
|
+
this.unsubscribe = this.session.subscribe((event) => this.handleEvent(event));
|
|
11900
|
+
return this.session;
|
|
11901
|
+
}
|
|
11902
|
+
handleEvent(event) {
|
|
11903
|
+
const payload = eventPayload(event);
|
|
11904
|
+
this.recordHistoryEvent(`pi-${event.type}`, payload, this.historyFile);
|
|
11905
|
+
}
|
|
11906
|
+
async processMessageInternal(request) {
|
|
11907
|
+
const session = await this.ensureSession(request);
|
|
11908
|
+
this.recordHistoryEvent("event_msg", { type: "user_message", message: request.message }, this.historyFile);
|
|
11909
|
+
try {
|
|
11910
|
+
const images = request.images && request.images.length > 0 ? (await normalizeImages(request.images)).map((image) => ({
|
|
11911
|
+
type: "image",
|
|
11912
|
+
data: image.source.data,
|
|
11913
|
+
mimeType: image.source.media_type
|
|
11914
|
+
})) : void 0;
|
|
11915
|
+
await session.prompt(request.message, images ? { images } : void 0);
|
|
11916
|
+
} catch (error) {
|
|
11917
|
+
this.recordHistoryEvent("pi-error", { message: error instanceof Error ? error.message : String(error) }, this.historyFile);
|
|
11918
|
+
throw error;
|
|
11919
|
+
} finally {
|
|
11920
|
+
await this.onTurnComplete();
|
|
11921
|
+
}
|
|
11922
|
+
}
|
|
11923
|
+
};
|
|
11924
|
+
|
|
11747
11925
|
// src/managers/relay-tools.ts
|
|
11748
11926
|
import { createSdkMcpServer, tool } from "@anthropic-ai/claude-agent-sdk";
|
|
11749
11927
|
import { z } from "zod";
|
|
@@ -11753,15 +11931,17 @@ function getAvailableRelayProviders(availability) {
|
|
|
11753
11931
|
const codexAvailable = availability.codexAvailable ?? false;
|
|
11754
11932
|
const cursorAvailable = availability.cursorAvailable ?? false;
|
|
11755
11933
|
const opencodeAvailable = availability.opencodeAvailable ?? false;
|
|
11934
|
+
const piAvailable = availability.piAvailable ?? false;
|
|
11756
11935
|
const providers = ["claude"];
|
|
11757
11936
|
if (codexAvailable) providers.push("codex");
|
|
11758
11937
|
if (cursorAvailable) providers.push("cursor");
|
|
11759
11938
|
if (opencodeAvailable) providers.push("opencode");
|
|
11939
|
+
if (piAvailable) providers.push("pi");
|
|
11760
11940
|
providers.push("relay");
|
|
11761
11941
|
return providers;
|
|
11762
11942
|
}
|
|
11763
11943
|
function getAvailableCodeProviders(availability) {
|
|
11764
|
-
return getAvailableRelayProviders(availability).filter((provider) => provider === "codex" || provider === "cursor" || provider === "opencode");
|
|
11944
|
+
return getAvailableRelayProviders(availability).filter((provider) => provider === "codex" || provider === "cursor" || provider === "opencode" || provider === "pi");
|
|
11765
11945
|
}
|
|
11766
11946
|
|
|
11767
11947
|
// src/managers/relay-tools.ts
|
|
@@ -12115,13 +12295,14 @@ function getUsingToolsSection() {
|
|
|
12115
12295
|
];
|
|
12116
12296
|
return [`# Using your tools`, ...prependBullets(items)].join("\n");
|
|
12117
12297
|
}
|
|
12118
|
-
function getDelegationSection(codexAvailable, cursorAvailable, opencodeAvailable) {
|
|
12119
|
-
const providerList = getAvailableRelayProviders({ codexAvailable, cursorAvailable, opencodeAvailable }).join(", ");
|
|
12298
|
+
function getDelegationSection(codexAvailable, cursorAvailable, opencodeAvailable, piAvailable) {
|
|
12299
|
+
const providerList = getAvailableRelayProviders({ codexAvailable, cursorAvailable, opencodeAvailable, piAvailable }).join(", ");
|
|
12120
12300
|
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).`;
|
|
12121
12301
|
const claudeModelList = AGENT_MODELS.claude.join(", ");
|
|
12122
12302
|
const extraAgentLines = [
|
|
12123
12303
|
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,
|
|
12124
12304
|
opencodeAvailable ? `Use provider 'opencode' for cheaper routine implementation tasks through OpenRouter-backed open source models. Suggested models: ${AGENT_MODELS.opencode.join(", ")}.` : null,
|
|
12305
|
+
piAvailable ? `Use provider 'pi' for coding tasks through Pi's OpenRouter-backed coding agent. Suggested models: ${AGENT_MODELS.pi.join(", ")}.` : null,
|
|
12125
12306
|
cursorAvailable ? `Use provider 'cursor' for fast iteration on code changes. Suggested models: ${AGENT_MODELS.cursor.join(", ")}.` : null
|
|
12126
12307
|
].filter(Boolean);
|
|
12127
12308
|
const agentSelectionLines = extraAgentLines.length > 0 ? `${extraAgentLines.join("\n\n")}
|
|
@@ -12244,14 +12425,14 @@ function getEnvironmentSection() {
|
|
|
12244
12425
|
].join("\n");
|
|
12245
12426
|
}
|
|
12246
12427
|
function buildRelaySystemPrompt(options) {
|
|
12247
|
-
const { customInstructions, codexAvailable, cursorAvailable, opencodeAvailable } = options ?? {};
|
|
12428
|
+
const { customInstructions, codexAvailable, cursorAvailable, opencodeAvailable, piAvailable } = options ?? {};
|
|
12248
12429
|
const sections = [
|
|
12249
12430
|
getIntroSection(),
|
|
12250
12431
|
getSystemSection(),
|
|
12251
12432
|
getDoingTasksSection(),
|
|
12252
12433
|
getActionsSection(),
|
|
12253
12434
|
getUsingToolsSection(),
|
|
12254
|
-
getDelegationSection(codexAvailable ?? false, cursorAvailable ?? false, opencodeAvailable ?? false),
|
|
12435
|
+
getDelegationSection(codexAvailable ?? false, cursorAvailable ?? false, opencodeAvailable ?? false, piAvailable ?? false),
|
|
12255
12436
|
getToneAndStyleSection(),
|
|
12256
12437
|
getOutputEfficiencySection(),
|
|
12257
12438
|
getEnvironmentSection(),
|
|
@@ -12284,12 +12465,13 @@ var RelayManager = class {
|
|
|
12284
12465
|
const codexAvailable = options.codexAvailable ?? false;
|
|
12285
12466
|
const cursorAvailable = options.cursorAvailable ?? false;
|
|
12286
12467
|
const opencodeAvailable = options.opencodeAvailable ?? false;
|
|
12468
|
+
const piAvailable = options.piAvailable ?? false;
|
|
12287
12469
|
this.inner = new ClaudeManager({
|
|
12288
12470
|
...options,
|
|
12289
|
-
systemPromptOverride: (customInstructions) => buildRelaySystemPrompt({ customInstructions, codexAvailable, cursorAvailable, opencodeAvailable }),
|
|
12471
|
+
systemPromptOverride: (customInstructions) => buildRelaySystemPrompt({ customInstructions, codexAvailable, cursorAvailable, opencodeAvailable, piAvailable }),
|
|
12290
12472
|
tools: RELAY_TOOLS,
|
|
12291
12473
|
mcpServers: {
|
|
12292
|
-
"relay-subagent-tools": createRelayMcpServer(options.chatId, { codexAvailable, cursorAvailable, opencodeAvailable })
|
|
12474
|
+
"relay-subagent-tools": createRelayMcpServer(options.chatId, { codexAvailable, cursorAvailable, opencodeAvailable, piAvailable })
|
|
12293
12475
|
},
|
|
12294
12476
|
envOverrides: {
|
|
12295
12477
|
CLAUDE_CODE_STREAM_CLOSE_TIMEOUT: "900000"
|
|
@@ -12381,17 +12563,17 @@ var keepAliveService = new KeepAliveService();
|
|
|
12381
12563
|
// src/services/canvas-service.ts
|
|
12382
12564
|
import { readdir as readdir6, readFile as readFile12, stat as stat3 } from "fs/promises";
|
|
12383
12565
|
import { homedir as homedir13 } from "os";
|
|
12384
|
-
import { join as
|
|
12566
|
+
import { join as join20 } from "path";
|
|
12385
12567
|
var GLOBAL_CANVAS_DIRECTORIES = [
|
|
12386
|
-
|
|
12387
|
-
|
|
12388
|
-
|
|
12568
|
+
join20(homedir13(), ".claude", "plans"),
|
|
12569
|
+
join20(process.env.XDG_DATA_HOME ?? join20(homedir13(), ".local", "share"), "opencode", "plans"),
|
|
12570
|
+
join20(homedir13(), ".replicas", "canvas")
|
|
12389
12571
|
];
|
|
12390
12572
|
async function canvasDirectories() {
|
|
12391
12573
|
const repositories = await gitService.listRepositories().catch(() => []);
|
|
12392
12574
|
return [
|
|
12393
12575
|
...GLOBAL_CANVAS_DIRECTORIES,
|
|
12394
|
-
...repositories.map((repository) =>
|
|
12576
|
+
...repositories.map((repository) => join20(repository.path, ".opencode", "plans"))
|
|
12395
12577
|
];
|
|
12396
12578
|
}
|
|
12397
12579
|
var CanvasService = class {
|
|
@@ -12411,7 +12593,7 @@ var CanvasService = class {
|
|
|
12411
12593
|
const { kind } = classifyCanvasFilename(entry.name);
|
|
12412
12594
|
let sizeBytes = 0;
|
|
12413
12595
|
try {
|
|
12414
|
-
const s = await stat3(
|
|
12596
|
+
const s = await stat3(join20(directory, entry.name));
|
|
12415
12597
|
sizeBytes = s.size;
|
|
12416
12598
|
} catch {
|
|
12417
12599
|
continue;
|
|
@@ -12426,7 +12608,7 @@ var CanvasService = class {
|
|
|
12426
12608
|
if (!safe) return null;
|
|
12427
12609
|
const { kind, mimeType } = classifyCanvasFilename(safe);
|
|
12428
12610
|
for (const directory of await canvasDirectories()) {
|
|
12429
|
-
const filePath =
|
|
12611
|
+
const filePath = join20(directory, safe);
|
|
12430
12612
|
let sizeBytes = 0;
|
|
12431
12613
|
let updatedAt = "";
|
|
12432
12614
|
try {
|
|
@@ -12563,13 +12745,13 @@ async function reconcileCanvasItems(filenames) {
|
|
|
12563
12745
|
|
|
12564
12746
|
// src/services/upload-chat-transcripts.ts
|
|
12565
12747
|
import { readdir as readdir7, readFile as readFile13 } from "fs/promises";
|
|
12566
|
-
import { basename as basename2, join as
|
|
12748
|
+
import { basename as basename2, join as join21 } from "path";
|
|
12567
12749
|
import { homedir as homedir14 } from "os";
|
|
12568
|
-
var ENGINE_DIR3 =
|
|
12750
|
+
var ENGINE_DIR3 = join21(homedir14(), ".replicas", "engine");
|
|
12569
12751
|
var HISTORY_DIRS = [
|
|
12570
|
-
|
|
12571
|
-
|
|
12572
|
-
|
|
12752
|
+
join21(ENGINE_DIR3, "claude-histories"),
|
|
12753
|
+
join21(ENGINE_DIR3, "relay-histories"),
|
|
12754
|
+
join21(ENGINE_DIR3, "codex-histories")
|
|
12573
12755
|
];
|
|
12574
12756
|
async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map()) {
|
|
12575
12757
|
let flushed = 0;
|
|
@@ -12586,7 +12768,7 @@ async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map()) {
|
|
|
12586
12768
|
if (!entry.endsWith(".jsonl")) continue;
|
|
12587
12769
|
const chatId = basename2(entry, ".jsonl");
|
|
12588
12770
|
tasks.push(
|
|
12589
|
-
uploadChatTranscript(chatId,
|
|
12771
|
+
uploadChatTranscript(chatId, join21(dir, entry), chatsById.get(chatId)).then(() => {
|
|
12590
12772
|
flushed++;
|
|
12591
12773
|
}).catch((err) => {
|
|
12592
12774
|
failed++;
|
|
@@ -12665,9 +12847,9 @@ async function flushRepoState() {
|
|
|
12665
12847
|
}
|
|
12666
12848
|
|
|
12667
12849
|
// src/services/chat/chat-service.ts
|
|
12668
|
-
var CHAT_SENDERS_DIR =
|
|
12669
|
-
var CODEX_AUTH_PATH2 =
|
|
12670
|
-
var OPENCODE_AUTH_PATH2 =
|
|
12850
|
+
var CHAT_SENDERS_DIR = join22(ENGINE_DIR2, "chat-senders");
|
|
12851
|
+
var CODEX_AUTH_PATH2 = join22(homedir15(), ".codex", "auth.json");
|
|
12852
|
+
var OPENCODE_AUTH_PATH2 = join22(homedir15(), ".local", "share", "opencode", "auth.json");
|
|
12671
12853
|
var CHATS_BACKUP_FILE = `${CHATS_FILE}.bak`;
|
|
12672
12854
|
function isChatMessageSender(value) {
|
|
12673
12855
|
if (!isRecord4(value)) return false;
|
|
@@ -12679,6 +12861,9 @@ function isCodexAvailable() {
|
|
|
12679
12861
|
function isOpencodeAvailable() {
|
|
12680
12862
|
return existsSync7(OPENCODE_AUTH_PATH2) || Boolean(ENGINE_ENV.OPENROUTER_API_KEY);
|
|
12681
12863
|
}
|
|
12864
|
+
function isPiAvailable() {
|
|
12865
|
+
return Boolean(ENGINE_ENV.OPENROUTER_API_KEY);
|
|
12866
|
+
}
|
|
12682
12867
|
function isCursorAvailable() {
|
|
12683
12868
|
return Boolean(ENGINE_ENV.CURSOR_API_KEY);
|
|
12684
12869
|
}
|
|
@@ -12727,7 +12912,7 @@ function isPersistedChat(value) {
|
|
|
12727
12912
|
return false;
|
|
12728
12913
|
}
|
|
12729
12914
|
const candidate = value;
|
|
12730
|
-
return typeof candidate.id === "string" &&
|
|
12915
|
+
return typeof candidate.id === "string" && typeof candidate.provider === "string" && isValidAgentProvider(candidate.provider) && typeof candidate.title === "string" && typeof candidate.createdAt === "string" && typeof candidate.updatedAt === "string" && (candidate.providerSessionId === null || typeof candidate.providerSessionId === "string") && (candidate.parentChatId === void 0 || candidate.parentChatId === null || typeof candidate.parentChatId === "string") && (candidate.deletedAt === void 0 || candidate.deletedAt === null || typeof candidate.deletedAt === "string");
|
|
12731
12916
|
}
|
|
12732
12917
|
function normalizePersistedChat(chat) {
|
|
12733
12918
|
const isLegacyCodexSdkChat = chat.provider === "codex" && (chat.codexBackend === "sdk" || chat.codexBackend === void 0 && chat.providerSessionId !== null);
|
|
@@ -12779,13 +12964,13 @@ var ChatService = class {
|
|
|
12779
12964
|
persistInFlight = false;
|
|
12780
12965
|
persistQueued = false;
|
|
12781
12966
|
async initialize() {
|
|
12782
|
-
await
|
|
12783
|
-
await
|
|
12784
|
-
await
|
|
12785
|
-
await
|
|
12786
|
-
await
|
|
12787
|
-
await
|
|
12788
|
-
await
|
|
12967
|
+
await mkdir14(ENGINE_DIR2, { recursive: true });
|
|
12968
|
+
await mkdir14(CLAUDE_HISTORY_DIR, { recursive: true });
|
|
12969
|
+
await mkdir14(RELAY_HISTORY_DIR, { recursive: true });
|
|
12970
|
+
await mkdir14(CODEX_HISTORY_DIR, { recursive: true });
|
|
12971
|
+
await mkdir14(CURSOR_HISTORY_DIR, { recursive: true });
|
|
12972
|
+
await mkdir14(OPENCODE_HISTORY_DIR, { recursive: true });
|
|
12973
|
+
await mkdir14(CHAT_SENDERS_DIR, { recursive: true });
|
|
12789
12974
|
const persisted = await this.loadChats();
|
|
12790
12975
|
for (const chat of persisted) {
|
|
12791
12976
|
const runtime = this.createRuntimeChat(chat);
|
|
@@ -12909,7 +13094,7 @@ var ChatService = class {
|
|
|
12909
13094
|
};
|
|
12910
13095
|
}
|
|
12911
13096
|
senderFilePath(chatId) {
|
|
12912
|
-
return
|
|
13097
|
+
return join22(CHAT_SENDERS_DIR, `${chatId}.jsonl`);
|
|
12913
13098
|
}
|
|
12914
13099
|
async appendSender(chatId, sender) {
|
|
12915
13100
|
try {
|
|
@@ -13103,7 +13288,7 @@ var ChatService = class {
|
|
|
13103
13288
|
return descendants;
|
|
13104
13289
|
}
|
|
13105
13290
|
async deleteHistoryFile(persisted) {
|
|
13106
|
-
await rm2(
|
|
13291
|
+
await rm2(join22(HISTORY_DIR_BY_PROVIDER[persisted.provider], `${persisted.id}.jsonl`), { force: true });
|
|
13107
13292
|
await rm2(this.senderFilePath(persisted.id), { force: true });
|
|
13108
13293
|
}
|
|
13109
13294
|
async getChatHistory(chatId, page = {}) {
|
|
@@ -13177,7 +13362,7 @@ var ChatService = class {
|
|
|
13177
13362
|
if (persisted.provider === "claude") {
|
|
13178
13363
|
provider = new ClaudeManager({
|
|
13179
13364
|
workingDirectory: this.workingDirectory,
|
|
13180
|
-
historyFilePath:
|
|
13365
|
+
historyFilePath: join22(CLAUDE_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
13181
13366
|
initialSessionId: persisted.providerSessionId,
|
|
13182
13367
|
onSaveSessionId: saveSession,
|
|
13183
13368
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -13186,7 +13371,7 @@ var ChatService = class {
|
|
|
13186
13371
|
} else if (persisted.provider === "relay") {
|
|
13187
13372
|
provider = new RelayManager({
|
|
13188
13373
|
workingDirectory: this.workingDirectory,
|
|
13189
|
-
historyFilePath:
|
|
13374
|
+
historyFilePath: join22(RELAY_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
13190
13375
|
initialSessionId: persisted.providerSessionId,
|
|
13191
13376
|
onSaveSessionId: saveSession,
|
|
13192
13377
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -13194,12 +13379,13 @@ var ChatService = class {
|
|
|
13194
13379
|
chatId: persisted.id,
|
|
13195
13380
|
codexAvailable: isCodexAvailable(),
|
|
13196
13381
|
opencodeAvailable: isOpencodeAvailable(),
|
|
13382
|
+
piAvailable: isPiAvailable(),
|
|
13197
13383
|
cursorAvailable: isCursorAvailable()
|
|
13198
13384
|
});
|
|
13199
13385
|
} else if (persisted.provider === "cursor") {
|
|
13200
13386
|
provider = new CursorManager({
|
|
13201
13387
|
workingDirectory: this.workingDirectory,
|
|
13202
|
-
historyFilePath:
|
|
13388
|
+
historyFilePath: join22(CURSOR_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
13203
13389
|
initialSessionId: persisted.providerSessionId,
|
|
13204
13390
|
onSaveSessionId: saveSession,
|
|
13205
13391
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -13208,7 +13394,16 @@ var ChatService = class {
|
|
|
13208
13394
|
} else if (persisted.provider === "opencode") {
|
|
13209
13395
|
provider = new OpencodeManager({
|
|
13210
13396
|
workingDirectory: this.workingDirectory,
|
|
13211
|
-
historyFilePath:
|
|
13397
|
+
historyFilePath: join22(OPENCODE_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
13398
|
+
initialSessionId: persisted.providerSessionId,
|
|
13399
|
+
onSaveSessionId: saveSession,
|
|
13400
|
+
onTurnComplete: onProviderTurnComplete,
|
|
13401
|
+
onEvent: onProviderEvent
|
|
13402
|
+
});
|
|
13403
|
+
} else if (persisted.provider === "pi") {
|
|
13404
|
+
provider = new PiManager({
|
|
13405
|
+
workingDirectory: this.workingDirectory,
|
|
13406
|
+
historyFilePath: join22(PI_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
13212
13407
|
initialSessionId: persisted.providerSessionId,
|
|
13213
13408
|
onSaveSessionId: saveSession,
|
|
13214
13409
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -13217,7 +13412,7 @@ var ChatService = class {
|
|
|
13217
13412
|
} else {
|
|
13218
13413
|
provider = new CodexAspManager({
|
|
13219
13414
|
workingDirectory: this.workingDirectory,
|
|
13220
|
-
historyFilePath:
|
|
13415
|
+
historyFilePath: join22(CODEX_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
13221
13416
|
initialSessionId: persisted.providerSessionId,
|
|
13222
13417
|
onSaveSessionId: saveSession,
|
|
13223
13418
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -13357,7 +13552,7 @@ var ChatService = class {
|
|
|
13357
13552
|
});
|
|
13358
13553
|
uploadChatTranscript(
|
|
13359
13554
|
chatId,
|
|
13360
|
-
|
|
13555
|
+
join22(HISTORY_DIR_BY_PROVIDER[chat.persisted.provider], `${chatId}.jsonl`),
|
|
13361
13556
|
this.toSummary(chat)
|
|
13362
13557
|
).catch((err) => {
|
|
13363
13558
|
console.error("[ChatService] Failed to upload chat transcript:", { chatId, err });
|
|
@@ -13484,7 +13679,7 @@ var ChatService = class {
|
|
|
13484
13679
|
// src/services/repo-file-service.ts
|
|
13485
13680
|
import { execFile as execFile2 } from "child_process";
|
|
13486
13681
|
import { readFile as readFile15, realpath, stat as stat4 } from "fs/promises";
|
|
13487
|
-
import { join as
|
|
13682
|
+
import { join as join23, resolve as resolve2, extname as extname2 } from "path";
|
|
13488
13683
|
var CACHE_TTL_MS = 3e4;
|
|
13489
13684
|
var SEARCH_TIMEOUT_MS = 15e3;
|
|
13490
13685
|
var MAX_CONTENT_BYTES = 256 * 1024;
|
|
@@ -13644,7 +13839,7 @@ var RepoFileService = class {
|
|
|
13644
13839
|
const repo = repos.find((r) => r.name === repoName);
|
|
13645
13840
|
if (!repo) return null;
|
|
13646
13841
|
try {
|
|
13647
|
-
const fullPath = await realpath(resolve2(
|
|
13842
|
+
const fullPath = await realpath(resolve2(join23(repo.path, filePath)));
|
|
13648
13843
|
const repoRoot = await realpath(repo.path);
|
|
13649
13844
|
const repoPrefix = repoRoot.endsWith("/") ? repoRoot : repoRoot + "/";
|
|
13650
13845
|
if (!fullPath.startsWith(repoPrefix) && fullPath !== repoRoot) return null;
|
|
@@ -13752,20 +13947,20 @@ var RepoFileService = class {
|
|
|
13752
13947
|
import { Hono } from "hono";
|
|
13753
13948
|
import { z as z2 } from "zod";
|
|
13754
13949
|
import { readdir as readdir9, stat as stat5, readFile as readFile18 } from "fs/promises";
|
|
13755
|
-
import { join as
|
|
13950
|
+
import { join as join26, resolve as resolve3 } from "path";
|
|
13756
13951
|
|
|
13757
13952
|
// src/services/warm-hooks-service.ts
|
|
13758
13953
|
import { spawn as spawn4 } from "child_process";
|
|
13759
13954
|
import { readFile as readFile17 } from "fs/promises";
|
|
13760
13955
|
import { existsSync as existsSync8 } from "fs";
|
|
13761
|
-
import { join as
|
|
13956
|
+
import { join as join25 } from "path";
|
|
13762
13957
|
|
|
13763
13958
|
// src/services/warm-hook-logs-service.ts
|
|
13764
|
-
import { mkdir as
|
|
13959
|
+
import { mkdir as mkdir15, readFile as readFile16, writeFile as writeFile6, readdir as readdir8, appendFile as appendFile4, unlink as unlink3 } from "fs/promises";
|
|
13765
13960
|
import { homedir as homedir16 } from "os";
|
|
13766
|
-
import { join as
|
|
13767
|
-
var LOGS_DIR2 =
|
|
13768
|
-
var CURRENT_RUN_LOG =
|
|
13961
|
+
import { join as join24 } from "path";
|
|
13962
|
+
var LOGS_DIR2 = join24(homedir16(), ".replicas", "warm-hook-logs");
|
|
13963
|
+
var CURRENT_RUN_LOG = join24(LOGS_DIR2, "current-run.log");
|
|
13769
13964
|
var GLOBAL_FILENAME = "global.json";
|
|
13770
13965
|
function withPreview2(stored) {
|
|
13771
13966
|
const preview = buildHookOutputPreview(stored.output);
|
|
@@ -13773,7 +13968,7 @@ function withPreview2(stored) {
|
|
|
13773
13968
|
}
|
|
13774
13969
|
var WarmHookLogsService = class {
|
|
13775
13970
|
async ensureDir() {
|
|
13776
|
-
await
|
|
13971
|
+
await mkdir15(LOGS_DIR2, { recursive: true });
|
|
13777
13972
|
}
|
|
13778
13973
|
async saveGlobalHookLog(entry) {
|
|
13779
13974
|
await this.ensureDir();
|
|
@@ -13782,7 +13977,7 @@ var WarmHookLogsService = class {
|
|
|
13782
13977
|
hookName: "organization",
|
|
13783
13978
|
...entry
|
|
13784
13979
|
};
|
|
13785
|
-
await writeFile6(
|
|
13980
|
+
await writeFile6(join24(LOGS_DIR2, GLOBAL_FILENAME), `${JSON.stringify(log, null, 2)}
|
|
13786
13981
|
`, "utf-8");
|
|
13787
13982
|
}
|
|
13788
13983
|
async saveEnvironmentHookLog(entry) {
|
|
@@ -13792,7 +13987,7 @@ var WarmHookLogsService = class {
|
|
|
13792
13987
|
hookName: "environment",
|
|
13793
13988
|
...entry
|
|
13794
13989
|
};
|
|
13795
|
-
await writeFile6(
|
|
13990
|
+
await writeFile6(join24(LOGS_DIR2, ENVIRONMENT_HOOK_LOG_FILENAME), `${JSON.stringify(log, null, 2)}
|
|
13796
13991
|
`, "utf-8");
|
|
13797
13992
|
}
|
|
13798
13993
|
async saveRepoHookLog(repoName, entry) {
|
|
@@ -13802,7 +13997,7 @@ var WarmHookLogsService = class {
|
|
|
13802
13997
|
hookName: repoName,
|
|
13803
13998
|
...entry
|
|
13804
13999
|
};
|
|
13805
|
-
await writeFile6(
|
|
14000
|
+
await writeFile6(join24(LOGS_DIR2, repoHookLogFilename(repoName)), `${JSON.stringify(log, null, 2)}
|
|
13806
14001
|
`, "utf-8");
|
|
13807
14002
|
}
|
|
13808
14003
|
async getAllLogs() {
|
|
@@ -13821,7 +14016,7 @@ var WarmHookLogsService = class {
|
|
|
13821
14016
|
continue;
|
|
13822
14017
|
}
|
|
13823
14018
|
try {
|
|
13824
|
-
const raw = await readFile16(
|
|
14019
|
+
const raw = await readFile16(join24(LOGS_DIR2, file), "utf-8");
|
|
13825
14020
|
const stored = JSON.parse(raw);
|
|
13826
14021
|
logs.push(withPreview2(stored));
|
|
13827
14022
|
} catch {
|
|
@@ -13859,7 +14054,7 @@ var WarmHookLogsService = class {
|
|
|
13859
14054
|
async getFullOutput(hookType, hookName) {
|
|
13860
14055
|
const filename = hookType === "global" ? GLOBAL_FILENAME : hookType === "environment" ? ENVIRONMENT_HOOK_LOG_FILENAME : repoHookLogFilename(hookName);
|
|
13861
14056
|
try {
|
|
13862
|
-
const raw = await readFile16(
|
|
14057
|
+
const raw = await readFile16(join24(LOGS_DIR2, filename), "utf-8");
|
|
13863
14058
|
const stored = JSON.parse(raw);
|
|
13864
14059
|
if (stored.hookType !== hookType || stored.hookName !== hookName) {
|
|
13865
14060
|
return null;
|
|
@@ -13878,7 +14073,7 @@ var warmHookLogsService = new WarmHookLogsService();
|
|
|
13878
14073
|
// src/services/warm-hooks-service.ts
|
|
13879
14074
|
async function readRepoWarmHook(repoPath) {
|
|
13880
14075
|
for (const filename of REPLICAS_CONFIG_FILENAMES) {
|
|
13881
|
-
const configPath =
|
|
14076
|
+
const configPath = join25(repoPath, filename);
|
|
13882
14077
|
if (!existsSync8(configPath)) {
|
|
13883
14078
|
continue;
|
|
13884
14079
|
}
|
|
@@ -14262,7 +14457,7 @@ var setWorkspaceNameSchema = z2.object({
|
|
|
14262
14457
|
name: z2.string().min(1).max(48)
|
|
14263
14458
|
});
|
|
14264
14459
|
var createChatSchema = z2.object({
|
|
14265
|
-
provider: z2.enum(["claude", "codex", "cursor", "opencode", "relay"]),
|
|
14460
|
+
provider: z2.enum(["claude", "codex", "cursor", "opencode", "pi", "relay"]),
|
|
14266
14461
|
title: z2.string().min(1).optional(),
|
|
14267
14462
|
parentChatId: z2.string().uuid().optional(),
|
|
14268
14463
|
clientRequestId: z2.string().min(1).max(128).optional()
|
|
@@ -15100,7 +15295,7 @@ data: ${JSON.stringify("Terminal session not found")}
|
|
|
15100
15295
|
const logFiles = files.filter((f) => f.endsWith(".log"));
|
|
15101
15296
|
const sessions = await Promise.all(
|
|
15102
15297
|
logFiles.map(async (filename) => {
|
|
15103
|
-
const filePath =
|
|
15298
|
+
const filePath = join26(LOG_DIR, filename);
|
|
15104
15299
|
const fileStat = await stat5(filePath);
|
|
15105
15300
|
const sessionId = filename.replace(/\.log$/, "");
|
|
15106
15301
|
return {
|
|
@@ -15219,6 +15414,11 @@ var heartbeatService = new HeartbeatService();
|
|
|
15219
15414
|
// src/index.ts
|
|
15220
15415
|
var startupStartedAt = performance.now();
|
|
15221
15416
|
var startupTimings = {};
|
|
15417
|
+
var resolveEngineReady = () => {
|
|
15418
|
+
};
|
|
15419
|
+
var engineReadyPromise = new Promise((resolve4) => {
|
|
15420
|
+
resolveEngineReady = resolve4;
|
|
15421
|
+
});
|
|
15222
15422
|
async function timeStartupStep(name, fn) {
|
|
15223
15423
|
const startedAt = performance.now();
|
|
15224
15424
|
try {
|
|
@@ -15288,7 +15488,16 @@ var authMiddleware = async (c, next) => {
|
|
|
15288
15488
|
await next();
|
|
15289
15489
|
};
|
|
15290
15490
|
var chatService = new ChatService(gitService.getWorkspaceRoot());
|
|
15291
|
-
app.get("/health", (c) => {
|
|
15491
|
+
app.get("/health", async (c) => {
|
|
15492
|
+
const requestedWaitMs = Number(c.req.query(ENGINE_HEALTH_WAIT_QUERY_PARAM));
|
|
15493
|
+
const waitMs = Number.isFinite(requestedWaitMs) ? Math.min(Math.max(requestedWaitMs, 0), ENGINE_HEALTH_MAX_WAIT_MS) : 0;
|
|
15494
|
+
if (!engineReady && waitMs > 0) {
|
|
15495
|
+
await Promise.race([
|
|
15496
|
+
engineReadyPromise,
|
|
15497
|
+
new Promise((resolve4) => setTimeout(resolve4, waitMs))
|
|
15498
|
+
]);
|
|
15499
|
+
}
|
|
15500
|
+
c.header(ENGINE_HEALTH_WAIT_HEADER, "1");
|
|
15292
15501
|
const response = {
|
|
15293
15502
|
status: engineReady ? "active" : "initializing",
|
|
15294
15503
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -15477,6 +15686,7 @@ serve(
|
|
|
15477
15686
|
await timeStartupStep("github_token_initialize", () => githubTokenManager.start());
|
|
15478
15687
|
}
|
|
15479
15688
|
engineReady = true;
|
|
15689
|
+
resolveEngineReady();
|
|
15480
15690
|
void registerDesktopPreview();
|
|
15481
15691
|
heartbeatService.start(bootTimeMs);
|
|
15482
15692
|
if (!IS_WARMING_MODE) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "replicas-engine",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.453",
|
|
4
4
|
"description": "Lightweight API server for Replicas workspaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -35,6 +35,8 @@
|
|
|
35
35
|
"@connectrpc/connect-node": "1.7.0",
|
|
36
36
|
"@cursor/sdk": "1.0.19",
|
|
37
37
|
"@hono/node-server": "^1.19.5",
|
|
38
|
+
"@mariozechner/pi-ai": "0.73.1",
|
|
39
|
+
"@mariozechner/pi-coding-agent": "0.73.1",
|
|
38
40
|
"@opencode-ai/sdk": "1.17.9",
|
|
39
41
|
"hono": "^4.10.3",
|
|
40
42
|
"opencode-ai": "1.17.9",
|