replicas-engine 0.1.363 → 0.1.365
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/src/index.js +346 -42
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/src/index.js
CHANGED
|
@@ -121,9 +121,9 @@ var EXT_TO_LANGUAGE = {
|
|
|
121
121
|
function detectLanguageByPath(filePath) {
|
|
122
122
|
const dot = filePath.lastIndexOf(".");
|
|
123
123
|
if (dot === -1) {
|
|
124
|
-
const
|
|
125
|
-
if (
|
|
126
|
-
if (
|
|
124
|
+
const basename3 = filePath.split("/").pop() ?? "";
|
|
125
|
+
if (basename3 === "Dockerfile") return "dockerfile";
|
|
126
|
+
if (basename3 === "Makefile") return "makefile";
|
|
127
127
|
return null;
|
|
128
128
|
}
|
|
129
129
|
const ext = filePath.slice(dot).toLowerCase();
|
|
@@ -295,7 +295,7 @@ var WORKSPACE_SIZES = ["small", "large"];
|
|
|
295
295
|
var INVALID_WORKSPACE_SIZE_ERROR = `Invalid size: must be one of ${WORKSPACE_SIZES.join(", ")}`;
|
|
296
296
|
|
|
297
297
|
// ../shared/src/e2b.ts
|
|
298
|
-
var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-06-28-
|
|
298
|
+
var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-06-28-v3";
|
|
299
299
|
|
|
300
300
|
// ../shared/src/runtime-env.ts
|
|
301
301
|
function parsePosixEnvFile(content) {
|
|
@@ -427,6 +427,56 @@ function normalizeRepositoryUrl(url, options = {}) {
|
|
|
427
427
|
}
|
|
428
428
|
|
|
429
429
|
// ../shared/src/slash-commands.ts
|
|
430
|
+
function normalizeSlashCommandName(name) {
|
|
431
|
+
const command = name.trim().replace(/^\/+/, "");
|
|
432
|
+
if (!command || /\s/.test(command)) return null;
|
|
433
|
+
return `/${command}`;
|
|
434
|
+
}
|
|
435
|
+
function createProviderSlashCommand(provider, name, description, argumentHint) {
|
|
436
|
+
const command = normalizeSlashCommandName(name);
|
|
437
|
+
if (!command) return null;
|
|
438
|
+
const trimmedDescription = description?.trim();
|
|
439
|
+
const trimmedArgumentHint = argumentHint?.trim();
|
|
440
|
+
return {
|
|
441
|
+
command,
|
|
442
|
+
description: trimmedDescription || `Run ${command}.`,
|
|
443
|
+
...trimmedArgumentHint ? { argumentHint: trimmedArgumentHint } : {},
|
|
444
|
+
providers: [provider]
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
var SLASH_COMMANDS = [
|
|
448
|
+
{
|
|
449
|
+
command: "/plan",
|
|
450
|
+
description: "Switch to plan mode and optionally send a prompt.",
|
|
451
|
+
argumentHint: "[prompt]",
|
|
452
|
+
providers: ["claude", "codex", "cursor", "opencode", "relay"]
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
command: "/fast",
|
|
456
|
+
description: "Use the fast service tier for future turns.",
|
|
457
|
+
providers: ["claude", "codex"]
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
command: "/goal",
|
|
461
|
+
description: "Set or clear a task goal.",
|
|
462
|
+
argumentHint: "<objective | clear>",
|
|
463
|
+
providers: ["codex"]
|
|
464
|
+
}
|
|
465
|
+
];
|
|
466
|
+
function mergeSlashCommands(...commandGroups) {
|
|
467
|
+
const seen = /* @__PURE__ */ new Set();
|
|
468
|
+
const commands = [];
|
|
469
|
+
for (const command of commandGroups.flat()) {
|
|
470
|
+
const key = command.command.toLowerCase();
|
|
471
|
+
if (seen.has(key)) continue;
|
|
472
|
+
seen.add(key);
|
|
473
|
+
commands.push(command);
|
|
474
|
+
}
|
|
475
|
+
return commands;
|
|
476
|
+
}
|
|
477
|
+
function getSlashCommandsForProvider(provider, commands = SLASH_COMMANDS) {
|
|
478
|
+
return commands.filter((command) => command.providers.includes(provider));
|
|
479
|
+
}
|
|
430
480
|
var MAX_CODEX_GOAL_OBJECTIVE_CHARS = 4e3;
|
|
431
481
|
function parseGoalCommand(message) {
|
|
432
482
|
const match = message.trim().match(/^\/goal(?:\s+([\s\S]*))?$/i);
|
|
@@ -5257,7 +5307,7 @@ async function registerDesktopPreview() {
|
|
|
5257
5307
|
|
|
5258
5308
|
// src/services/chat/chat-service.ts
|
|
5259
5309
|
import { existsSync as existsSync7 } from "fs";
|
|
5260
|
-
import { appendFile as appendFile3, copyFile, mkdir as mkdir13, readFile as
|
|
5310
|
+
import { appendFile as appendFile3, copyFile, mkdir as mkdir13, readFile as readFile14, rename as rename2, rm } from "fs/promises";
|
|
5261
5311
|
import { homedir as homedir14 } from "os";
|
|
5262
5312
|
import { join as join19 } from "path";
|
|
5263
5313
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
@@ -6579,6 +6629,16 @@ var MAX_MIDTURN_CONTINUE_RETRIES = 2;
|
|
|
6579
6629
|
var TRANSIENT_RETRY_DELAYS_MS = [1e3, 2500];
|
|
6580
6630
|
var CLAUDE_TRANSIENT_HTTP_STATUSES = [408, 500, 502, 503, 504, 529];
|
|
6581
6631
|
var CLAUDE_MIDTURN_CONTINUE_PROMPT = "Your previous turn was interrupted by a transient network error before it could finish. Continue from exactly where you left off. Do not repeat any tool calls, commits, messages, or other actions you have already completed \u2014 first check what is already done, then do only the remaining work.";
|
|
6632
|
+
function toSlashCommands(command) {
|
|
6633
|
+
const names = [command.name, ...command.aliases ?? []];
|
|
6634
|
+
return names.flatMap((name) => {
|
|
6635
|
+
const result = createProviderSlashCommand("claude", name, command.description, command.argumentHint);
|
|
6636
|
+
return result ? [result] : [];
|
|
6637
|
+
});
|
|
6638
|
+
}
|
|
6639
|
+
function normalizeClaudeSlashCommands(commands) {
|
|
6640
|
+
return mergeSlashCommands(...commands.map(toSlashCommands));
|
|
6641
|
+
}
|
|
6582
6642
|
var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
6583
6643
|
historyFilePath;
|
|
6584
6644
|
historyFile;
|
|
@@ -6602,6 +6662,7 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
6602
6662
|
disallowedToolsOverride;
|
|
6603
6663
|
/** Active tool-input requests keyed by requestId; resolved when the user selects an option. */
|
|
6604
6664
|
pendingToolInputs = /* @__PURE__ */ new Map();
|
|
6665
|
+
supportedSlashCommands = [];
|
|
6605
6666
|
authRetrying = false;
|
|
6606
6667
|
constructor(options) {
|
|
6607
6668
|
super(options);
|
|
@@ -6640,6 +6701,21 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
6640
6701
|
isAuthRetrying() {
|
|
6641
6702
|
return this.authRetrying;
|
|
6642
6703
|
}
|
|
6704
|
+
async listSlashCommands() {
|
|
6705
|
+
await this.initialized;
|
|
6706
|
+
if (!this.activeQuery || this.isProcessing()) {
|
|
6707
|
+
return this.supportedSlashCommands;
|
|
6708
|
+
}
|
|
6709
|
+
try {
|
|
6710
|
+
const commands = await this.activeQuery?.supportedCommands();
|
|
6711
|
+
if (commands) {
|
|
6712
|
+
this.supportedSlashCommands = normalizeClaudeSlashCommands(commands);
|
|
6713
|
+
}
|
|
6714
|
+
} catch (error) {
|
|
6715
|
+
console.warn("[ClaudeManager] Failed to load slash commands:", error);
|
|
6716
|
+
}
|
|
6717
|
+
return this.supportedSlashCommands;
|
|
6718
|
+
}
|
|
6643
6719
|
setAuthRetrying(value) {
|
|
6644
6720
|
if (this.authRetrying === value) return;
|
|
6645
6721
|
this.authRetrying = value;
|
|
@@ -7390,6 +7466,9 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
7390
7466
|
this.handlePartialAssistantMessage(message);
|
|
7391
7467
|
return;
|
|
7392
7468
|
}
|
|
7469
|
+
if (message.type === "system" && message.subtype === "commands_changed") {
|
|
7470
|
+
this.supportedSlashCommands = normalizeClaudeSlashCommands(message.commands);
|
|
7471
|
+
}
|
|
7393
7472
|
this.trackNativeCompaction(message);
|
|
7394
7473
|
await this.recordEvent(message);
|
|
7395
7474
|
}
|
|
@@ -7612,7 +7691,7 @@ var AspClient = class {
|
|
|
7612
7691
|
// src/managers/codex-asp/app-server-process.ts
|
|
7613
7692
|
var DEFAULT_CODEX_BINARY = "codex";
|
|
7614
7693
|
var DEFAULT_CODEX_ARGS = ["app-server", "--listen", "stdio://"];
|
|
7615
|
-
var ENGINE_PACKAGE_VERSION = "0.1.
|
|
7694
|
+
var ENGINE_PACKAGE_VERSION = "0.1.365";
|
|
7616
7695
|
var INITIALIZE_METHOD = "initialize";
|
|
7617
7696
|
var INITIALIZED_NOTIFICATION = "initialized";
|
|
7618
7697
|
var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
|
|
@@ -7867,6 +7946,7 @@ var TURN_START_METHOD = "turn/start";
|
|
|
7867
7946
|
var TURN_INTERRUPT_METHOD = "turn/interrupt";
|
|
7868
7947
|
var ACCOUNT_RATE_LIMITS_READ_METHOD = "account/rateLimits/read";
|
|
7869
7948
|
var MODEL_LIST_METHOD = "model/list";
|
|
7949
|
+
var SKILLS_LIST_METHOD = "skills/list";
|
|
7870
7950
|
var MAX_CODEX_ASP_TRANSCRIPT_OUTPUT_CHARS = DEFAULT_HOOK_OUTPUT_PREVIEW_CHARS;
|
|
7871
7951
|
function codexApprovalPolicyOverrides() {
|
|
7872
7952
|
if (!ENGINE_ENV.REPLICAS_DISABLE_GH_PR_MERGE) {
|
|
@@ -8420,6 +8500,21 @@ var TranscriptUpdateCoalescer = class {
|
|
|
8420
8500
|
};
|
|
8421
8501
|
|
|
8422
8502
|
// src/managers/codex-asp/codex-asp-manager.ts
|
|
8503
|
+
var GOAL_TURN_CONTINUATION_GRACE_MS = 5e3;
|
|
8504
|
+
var CODEX_SLASH_COMMANDS_CACHE_MS = 3e4;
|
|
8505
|
+
function skillToSlashCommand(skill) {
|
|
8506
|
+
if (!skill.enabled) return null;
|
|
8507
|
+
const description = skill.interface?.shortDescription ?? skill.shortDescription ?? skill.description;
|
|
8508
|
+
return createProviderSlashCommand("codex", skill.name, description);
|
|
8509
|
+
}
|
|
8510
|
+
function skillsListToSlashCommands(response) {
|
|
8511
|
+
return mergeSlashCommands(
|
|
8512
|
+
...response.data.map((entry) => entry.skills.flatMap((skill) => {
|
|
8513
|
+
const command = skillToSlashCommand(skill);
|
|
8514
|
+
return command ? [command] : [];
|
|
8515
|
+
}))
|
|
8516
|
+
);
|
|
8517
|
+
}
|
|
8423
8518
|
var CodexAspManager = class extends CodingAgentManager {
|
|
8424
8519
|
currentThreadId = null;
|
|
8425
8520
|
activeTurnId = null;
|
|
@@ -8437,6 +8532,8 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
8437
8532
|
skillRegistriesApplied = false;
|
|
8438
8533
|
modelServiceTierCache = null;
|
|
8439
8534
|
activeServiceTier;
|
|
8535
|
+
slashCommandsCache = null;
|
|
8536
|
+
slashCommandsRequest = null;
|
|
8440
8537
|
constructor(options) {
|
|
8441
8538
|
super(options);
|
|
8442
8539
|
this.historyFile = options.historyFilePath ? new CodexHistoryFile(options.historyFilePath) : null;
|
|
@@ -8515,6 +8612,34 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
8515
8612
|
getGoal() {
|
|
8516
8613
|
return this.currentGoal;
|
|
8517
8614
|
}
|
|
8615
|
+
async listSlashCommands() {
|
|
8616
|
+
await this.initialized;
|
|
8617
|
+
const now = Date.now();
|
|
8618
|
+
if (this.slashCommandsCache && this.slashCommandsCache.expiresAt > now) {
|
|
8619
|
+
return this.slashCommandsCache.commands;
|
|
8620
|
+
}
|
|
8621
|
+
if (!this.slashCommandsRequest) {
|
|
8622
|
+
this.slashCommandsRequest = (async () => {
|
|
8623
|
+
try {
|
|
8624
|
+
const host = await getCodexAspHost();
|
|
8625
|
+
await this.applySkillRegistries(host);
|
|
8626
|
+
const response = await host.client.request(
|
|
8627
|
+
SKILLS_LIST_METHOD,
|
|
8628
|
+
{ cwds: [this.workingDirectory] }
|
|
8629
|
+
);
|
|
8630
|
+
const commands = skillsListToSlashCommands(response);
|
|
8631
|
+
this.slashCommandsCache = { commands, expiresAt: Date.now() + CODEX_SLASH_COMMANDS_CACHE_MS };
|
|
8632
|
+
return commands;
|
|
8633
|
+
} catch (error) {
|
|
8634
|
+
console.warn("[CodexAspManager] Failed to load slash commands:", error);
|
|
8635
|
+
return this.slashCommandsCache?.commands ?? [];
|
|
8636
|
+
} finally {
|
|
8637
|
+
this.slashCommandsRequest = null;
|
|
8638
|
+
}
|
|
8639
|
+
})();
|
|
8640
|
+
}
|
|
8641
|
+
return this.slashCommandsRequest;
|
|
8642
|
+
}
|
|
8518
8643
|
async clearGoal() {
|
|
8519
8644
|
await this.initialized;
|
|
8520
8645
|
if (!this.currentThreadId) {
|
|
@@ -8720,9 +8845,9 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
8720
8845
|
);
|
|
8721
8846
|
this.recordGoalChange(response.goal, true);
|
|
8722
8847
|
return { turn: null, tempImagePaths: [] };
|
|
8723
|
-
});
|
|
8848
|
+
}, { waitForActiveGoal: true });
|
|
8724
8849
|
}
|
|
8725
|
-
async observeTurn(host, threadId, request, startTurn) {
|
|
8850
|
+
async observeTurn(host, threadId, request, startTurn, options = {}) {
|
|
8726
8851
|
let resolveCompleted;
|
|
8727
8852
|
const completed = new Promise((resolve4) => {
|
|
8728
8853
|
resolveCompleted = resolve4;
|
|
@@ -8735,6 +8860,10 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
8735
8860
|
void disposed.catch(() => {
|
|
8736
8861
|
});
|
|
8737
8862
|
let observedTurnId = null;
|
|
8863
|
+
const observedTurnIds = /* @__PURE__ */ new Set();
|
|
8864
|
+
let lastCompletedTurn = null;
|
|
8865
|
+
let completedResolved = false;
|
|
8866
|
+
let goalContinuationTimer = null;
|
|
8738
8867
|
const completedItems = [];
|
|
8739
8868
|
const agentMessageDeltas = /* @__PURE__ */ new Map();
|
|
8740
8869
|
const linearSessionId = ENGINE_ENV.LINEAR_SESSION_ID;
|
|
@@ -8742,6 +8871,26 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
8742
8871
|
let tempImagePaths = [];
|
|
8743
8872
|
const linearForwarder = new LinearEventForwarder(linearSessionId);
|
|
8744
8873
|
const matchesTurn = (notificationThreadId, notificationTurnId) => notificationThreadId === threadId && (!observedTurnId || notificationTurnId === null || notificationTurnId === observedTurnId);
|
|
8874
|
+
const resolveIfGoalIdle = () => {
|
|
8875
|
+
if (!lastCompletedTurn || completedResolved) return;
|
|
8876
|
+
if (!options.waitForActiveGoal || this.currentGoal?.status !== "active") {
|
|
8877
|
+
if (goalContinuationTimer) {
|
|
8878
|
+
clearTimeout(goalContinuationTimer);
|
|
8879
|
+
goalContinuationTimer = null;
|
|
8880
|
+
}
|
|
8881
|
+
completedResolved = true;
|
|
8882
|
+
resolveCompleted(lastCompletedTurn);
|
|
8883
|
+
}
|
|
8884
|
+
};
|
|
8885
|
+
const scheduleGoalContinuationFallback = () => {
|
|
8886
|
+
if (!options.waitForActiveGoal || completedResolved || goalContinuationTimer) return;
|
|
8887
|
+
goalContinuationTimer = setTimeout(() => {
|
|
8888
|
+
goalContinuationTimer = null;
|
|
8889
|
+
if (!lastCompletedTurn || completedResolved) return;
|
|
8890
|
+
completedResolved = true;
|
|
8891
|
+
resolveCompleted(lastCompletedTurn);
|
|
8892
|
+
}, GOAL_TURN_CONTINUATION_GRACE_MS);
|
|
8893
|
+
};
|
|
8745
8894
|
const handlers = {
|
|
8746
8895
|
[ACCOUNT_RATE_LIMITS_UPDATED_METHOD]: (notification) => {
|
|
8747
8896
|
this.handleRateLimits(notification.params.rateLimits);
|
|
@@ -8753,10 +8902,12 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
8753
8902
|
[THREAD_GOAL_UPDATED_METHOD]: (notification) => {
|
|
8754
8903
|
if (notification.params.threadId !== threadId) return;
|
|
8755
8904
|
this.recordGoalChange(notification.params.goal);
|
|
8905
|
+
resolveIfGoalIdle();
|
|
8756
8906
|
},
|
|
8757
8907
|
[THREAD_GOAL_CLEARED_METHOD]: (notification) => {
|
|
8758
8908
|
if (notification.params.threadId !== threadId) return;
|
|
8759
8909
|
this.recordGoalChange(null);
|
|
8910
|
+
resolveIfGoalIdle();
|
|
8760
8911
|
},
|
|
8761
8912
|
[THREAD_COMPACTED_METHOD]: (notification) => {
|
|
8762
8913
|
if (!matchesTurn(notification.params.threadId, notification.params.turnId)) return;
|
|
@@ -8765,7 +8916,15 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
8765
8916
|
[TURN_STARTED_METHOD]: (notification) => {
|
|
8766
8917
|
if (notification.params.threadId !== threadId) return;
|
|
8767
8918
|
observedTurnId = notification.params.turn.id;
|
|
8919
|
+
observedTurnIds.add(notification.params.turn.id);
|
|
8768
8920
|
this.activeTurnId = notification.params.turn.id;
|
|
8921
|
+
if (goalContinuationTimer) {
|
|
8922
|
+
clearTimeout(goalContinuationTimer);
|
|
8923
|
+
goalContinuationTimer = null;
|
|
8924
|
+
}
|
|
8925
|
+
lastCompletedTurn = null;
|
|
8926
|
+
completedItems.length = 0;
|
|
8927
|
+
agentMessageDeltas.clear();
|
|
8769
8928
|
this.mergeTranscriptTurn(notification.params.threadId, notification.params.turn);
|
|
8770
8929
|
this.emitTranscriptUpdated(notification.params.threadId, { immediate: true });
|
|
8771
8930
|
linearForwarder.sendEvent(convertCodexAspNotification(notification, linearSessionId ?? ""));
|
|
@@ -8833,6 +8992,7 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
8833
8992
|
},
|
|
8834
8993
|
[TURN_COMPLETED_METHOD]: (notification) => {
|
|
8835
8994
|
if (notification.params.threadId !== threadId) return;
|
|
8995
|
+
if (!observedTurnIds.has(notification.params.turn.id)) return;
|
|
8836
8996
|
observedTurnId = notification.params.turn.id;
|
|
8837
8997
|
const turn = notification.params.turn;
|
|
8838
8998
|
const items = turn.items.length > 0 ? [...turn.items] : [];
|
|
@@ -8857,7 +9017,12 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
8857
9017
|
const completedTurn = items.length > 0 ? { ...turn, items, itemsView: "full" } : turn;
|
|
8858
9018
|
this.mergeTranscriptTurn(notification.params.threadId, completedTurn);
|
|
8859
9019
|
this.emitTranscriptUpdated(notification.params.threadId, { immediate: true });
|
|
8860
|
-
|
|
9020
|
+
lastCompletedTurn = completedTurn;
|
|
9021
|
+
resolveIfGoalIdle();
|
|
9022
|
+
if (options.waitForActiveGoal && this.currentGoal?.status === "active") {
|
|
9023
|
+
void this.refreshThreadGoal(host, threadId).then(resolveIfGoalIdle).catch(() => {
|
|
9024
|
+
}).finally(scheduleGoalContinuationFallback);
|
|
9025
|
+
}
|
|
8861
9026
|
}
|
|
8862
9027
|
};
|
|
8863
9028
|
const onNotification = (notification) => {
|
|
@@ -8883,6 +9048,7 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
8883
9048
|
tempImagePaths = started.tempImagePaths;
|
|
8884
9049
|
if (started.turn) {
|
|
8885
9050
|
observedTurnId = started.turn.id;
|
|
9051
|
+
observedTurnIds.add(started.turn.id);
|
|
8886
9052
|
this.activeTurnId = started.turn.id;
|
|
8887
9053
|
}
|
|
8888
9054
|
const turn = await Promise.race([completed, disposed]);
|
|
@@ -8892,6 +9058,9 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
8892
9058
|
host.client.off("notification", onNotification);
|
|
8893
9059
|
host.client.off("serverRequest", onServerRequest);
|
|
8894
9060
|
host.client.off("dispose", onDispose);
|
|
9061
|
+
if (goalContinuationTimer) {
|
|
9062
|
+
clearTimeout(goalContinuationTimer);
|
|
9063
|
+
}
|
|
8895
9064
|
this.transcriptUpdateCoalescer.flushPending();
|
|
8896
9065
|
await removeTempImageFiles(tempImagePaths);
|
|
8897
9066
|
if (host.client.isDisposed) {
|
|
@@ -9381,9 +9550,11 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
9381
9550
|
};
|
|
9382
9551
|
|
|
9383
9552
|
// src/managers/cursor-manager.ts
|
|
9384
|
-
import { mkdir as mkdir11 } from "fs/promises";
|
|
9385
|
-
import { dirname as dirname5, join as join15 } from "path";
|
|
9553
|
+
import { mkdir as mkdir11, readFile as readFile10, readdir as readdir4 } from "fs/promises";
|
|
9554
|
+
import { basename, dirname as dirname5, extname, join as join15 } from "path";
|
|
9555
|
+
import { parse as parseYaml2 } from "yaml";
|
|
9386
9556
|
import { Agent as CursorAgent } from "@cursor/sdk";
|
|
9557
|
+
var CURSOR_SLASH_COMMANDS_CACHE_MS = 3e4;
|
|
9387
9558
|
var CURSOR_COMPOSER_CONTEXT_WINDOW = 2e5;
|
|
9388
9559
|
var CURSOR_CATEGORY_COLORS = {
|
|
9389
9560
|
input: "#3eeba3",
|
|
@@ -9394,12 +9565,45 @@ var CURSOR_CATEGORY_COLORS = {
|
|
|
9394
9565
|
function finiteNumber(value) {
|
|
9395
9566
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
9396
9567
|
}
|
|
9568
|
+
function extractCursorCommandDescription(content) {
|
|
9569
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
9570
|
+
if (!match) return void 0;
|
|
9571
|
+
try {
|
|
9572
|
+
const parsed = parseYaml2(match[1]);
|
|
9573
|
+
if (isRecord4(parsed) && typeof parsed.description === "string") return parsed.description;
|
|
9574
|
+
} catch {
|
|
9575
|
+
}
|
|
9576
|
+
return void 0;
|
|
9577
|
+
}
|
|
9578
|
+
async function listCursorCommandsInDirectory(directory) {
|
|
9579
|
+
let entries;
|
|
9580
|
+
try {
|
|
9581
|
+
entries = await readdir4(directory, { withFileTypes: true });
|
|
9582
|
+
} catch (error) {
|
|
9583
|
+
if (isRecord4(error) && error.code === "ENOENT") return [];
|
|
9584
|
+
console.warn("[CursorManager] Failed to read slash command directory:", error);
|
|
9585
|
+
return [];
|
|
9586
|
+
}
|
|
9587
|
+
const commands = await Promise.all(entries.filter((entry) => entry.isFile() && extname(entry.name) === ".md").map(async (entry) => {
|
|
9588
|
+
const name = basename(entry.name, ".md");
|
|
9589
|
+
let description;
|
|
9590
|
+
try {
|
|
9591
|
+
description = extractCursorCommandDescription(await readFile10(join15(directory, entry.name), "utf8"));
|
|
9592
|
+
} catch (error) {
|
|
9593
|
+
console.warn("[CursorManager] Failed to read slash command file:", error);
|
|
9594
|
+
}
|
|
9595
|
+
return createProviderSlashCommand("cursor", name, description);
|
|
9596
|
+
}));
|
|
9597
|
+
return commands.filter((command) => Boolean(command));
|
|
9598
|
+
}
|
|
9397
9599
|
var CursorManager = class extends CodingAgentManager {
|
|
9398
9600
|
agent = null;
|
|
9399
9601
|
activeRun = null;
|
|
9400
9602
|
activeModel = null;
|
|
9401
9603
|
historyFilePath;
|
|
9402
9604
|
historyFile;
|
|
9605
|
+
slashCommandsCache = null;
|
|
9606
|
+
slashCommandsRequest = null;
|
|
9403
9607
|
constructor(options) {
|
|
9404
9608
|
super(options);
|
|
9405
9609
|
this.historyFilePath = options.historyFilePath ?? join15(ENGINE_ENV.HOME_DIR, ".replicas", "cursor", "history.jsonl");
|
|
@@ -9421,6 +9625,26 @@ var CursorManager = class extends CodingAgentManager {
|
|
|
9421
9625
|
goal: null
|
|
9422
9626
|
};
|
|
9423
9627
|
}
|
|
9628
|
+
async listSlashCommands() {
|
|
9629
|
+
await this.initialized;
|
|
9630
|
+
const now = Date.now();
|
|
9631
|
+
if (this.slashCommandsCache && this.slashCommandsCache.expiresAt > now) {
|
|
9632
|
+
return this.slashCommandsCache.commands;
|
|
9633
|
+
}
|
|
9634
|
+
this.slashCommandsRequest ??= (async () => {
|
|
9635
|
+
try {
|
|
9636
|
+
const commands = mergeSlashCommands(
|
|
9637
|
+
await listCursorCommandsInDirectory(join15(this.workingDirectory, ".cursor", "commands")),
|
|
9638
|
+
await listCursorCommandsInDirectory(join15(ENGINE_ENV.HOME_DIR, ".cursor", "commands"))
|
|
9639
|
+
);
|
|
9640
|
+
this.slashCommandsCache = { commands, expiresAt: Date.now() + CURSOR_SLASH_COMMANDS_CACHE_MS };
|
|
9641
|
+
return commands;
|
|
9642
|
+
} finally {
|
|
9643
|
+
this.slashCommandsRequest = null;
|
|
9644
|
+
}
|
|
9645
|
+
})();
|
|
9646
|
+
return this.slashCommandsRequest;
|
|
9647
|
+
}
|
|
9424
9648
|
async ensureAgent(request) {
|
|
9425
9649
|
if (this.agent) return this.agent;
|
|
9426
9650
|
const apiKey = ENGINE_ENV.CURSOR_API_KEY;
|
|
@@ -9560,7 +9784,7 @@ var CursorManager = class extends CodingAgentManager {
|
|
|
9560
9784
|
};
|
|
9561
9785
|
|
|
9562
9786
|
// src/managers/opencode-manager.ts
|
|
9563
|
-
import { mkdir as mkdir12, readFile as
|
|
9787
|
+
import { mkdir as mkdir12, readFile as readFile11 } from "fs/promises";
|
|
9564
9788
|
import { delimiter, dirname as dirname6, join as join16 } from "path";
|
|
9565
9789
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
9566
9790
|
import { fileURLToPath } from "url";
|
|
@@ -9573,6 +9797,7 @@ var OPENCODE_SHIM_DIR = dirname6(fileURLToPath(new URL("../../scripts/opencode",
|
|
|
9573
9797
|
var OPENCODE_CONFIG_PATH = join16(ENGINE_ENV.HOME_DIR, ".config", "opencode", "opencode.json");
|
|
9574
9798
|
var OPENCODE_FETCH_DISPATCHER = new Agent({ headersTimeout: 0, bodyTimeout: 0 });
|
|
9575
9799
|
var OPENCODE_WORKSPACE_PERMISSION = "allow";
|
|
9800
|
+
var OPENCODE_SLASH_COMMANDS_CACHE_MS = 3e4;
|
|
9576
9801
|
var OPENCODE_VARIANT_CANDIDATES_BY_THINKING_LEVEL = {
|
|
9577
9802
|
low: ["low"],
|
|
9578
9803
|
medium: ["medium"],
|
|
@@ -9604,6 +9829,25 @@ async function opencodeConfig(model) {
|
|
|
9604
9829
|
function getConfiguredOpencodeModels(model) {
|
|
9605
9830
|
return [.../* @__PURE__ */ new Set([model, ...AGENT_MODELS.opencode])];
|
|
9606
9831
|
}
|
|
9832
|
+
function opencodeCommandToSlashCommand(command) {
|
|
9833
|
+
return createProviderSlashCommand("opencode", command.name, command.description);
|
|
9834
|
+
}
|
|
9835
|
+
function opencodeSkillToSlashCommand(skill) {
|
|
9836
|
+
if (!skill.slash) return null;
|
|
9837
|
+
return createProviderSlashCommand("opencode", skill.name, skill.description);
|
|
9838
|
+
}
|
|
9839
|
+
function opencodeCommandListToSlashCommands(response) {
|
|
9840
|
+
return mergeSlashCommands(response.data.flatMap((command) => {
|
|
9841
|
+
const result = opencodeCommandToSlashCommand(command);
|
|
9842
|
+
return result ? [result] : [];
|
|
9843
|
+
}));
|
|
9844
|
+
}
|
|
9845
|
+
function opencodeSkillListToSlashCommands(response) {
|
|
9846
|
+
return mergeSlashCommands(response.data.flatMap((skill) => {
|
|
9847
|
+
const result = opencodeSkillToSlashCommand(skill);
|
|
9848
|
+
return result ? [result] : [];
|
|
9849
|
+
}));
|
|
9850
|
+
}
|
|
9607
9851
|
function isOpencodePart(value) {
|
|
9608
9852
|
return typeof value === "object" && value !== null && "type" in value && typeof value.type === "string";
|
|
9609
9853
|
}
|
|
@@ -9627,7 +9871,7 @@ function isOpencodeMcpEntry(value) {
|
|
|
9627
9871
|
async function readProvisionedOpencodeMcpConfig() {
|
|
9628
9872
|
let raw;
|
|
9629
9873
|
try {
|
|
9630
|
-
raw = await
|
|
9874
|
+
raw = await readFile11(OPENCODE_CONFIG_PATH, "utf8");
|
|
9631
9875
|
} catch (error) {
|
|
9632
9876
|
if (isRecord4(error) && error.code === "ENOENT") return void 0;
|
|
9633
9877
|
console.error("[OpencodeManager] Failed to read Opencode config:", error);
|
|
@@ -9699,6 +9943,8 @@ var OpencodeManager = class extends CodingAgentManager {
|
|
|
9699
9943
|
reasoningParts = /* @__PURE__ */ new Map();
|
|
9700
9944
|
nonAssistantMessageIds = /* @__PURE__ */ new Set();
|
|
9701
9945
|
modelVariants = /* @__PURE__ */ new Map();
|
|
9946
|
+
slashCommandsCache = null;
|
|
9947
|
+
slashCommandsRequest = null;
|
|
9702
9948
|
constructor(options) {
|
|
9703
9949
|
super(options);
|
|
9704
9950
|
this.sessionId = options.initialSessionId;
|
|
@@ -9731,6 +9977,35 @@ var OpencodeManager = class extends CodingAgentManager {
|
|
|
9731
9977
|
goal: null
|
|
9732
9978
|
};
|
|
9733
9979
|
}
|
|
9980
|
+
async listSlashCommands() {
|
|
9981
|
+
await this.initialized;
|
|
9982
|
+
const now = Date.now();
|
|
9983
|
+
if (this.slashCommandsCache && this.slashCommandsCache.expiresAt > now) {
|
|
9984
|
+
return this.slashCommandsCache.commands;
|
|
9985
|
+
}
|
|
9986
|
+
this.slashCommandsRequest ??= (async () => {
|
|
9987
|
+
try {
|
|
9988
|
+
const client = await this.ensureClient(DEFAULT_OPENCODE_MODEL);
|
|
9989
|
+
const location = { directory: this.workingDirectory };
|
|
9990
|
+
const [commandResponse, skillResponse] = await Promise.all([
|
|
9991
|
+
client.v2.command.list({ location }, { throwOnError: true }),
|
|
9992
|
+
client.v2.skill.list({ location }, { throwOnError: true })
|
|
9993
|
+
]);
|
|
9994
|
+
const commands = mergeSlashCommands(
|
|
9995
|
+
opencodeCommandListToSlashCommands(commandResponse.data),
|
|
9996
|
+
opencodeSkillListToSlashCommands(skillResponse.data)
|
|
9997
|
+
);
|
|
9998
|
+
this.slashCommandsCache = { commands, expiresAt: Date.now() + OPENCODE_SLASH_COMMANDS_CACHE_MS };
|
|
9999
|
+
return commands;
|
|
10000
|
+
} catch (error) {
|
|
10001
|
+
console.warn("[OpencodeManager] Failed to load slash commands:", error);
|
|
10002
|
+
return this.slashCommandsCache?.commands ?? [];
|
|
10003
|
+
} finally {
|
|
10004
|
+
this.slashCommandsRequest = null;
|
|
10005
|
+
}
|
|
10006
|
+
})();
|
|
10007
|
+
return this.slashCommandsRequest;
|
|
10008
|
+
}
|
|
9734
10009
|
async ensureClient(model) {
|
|
9735
10010
|
if (this.client && this.configuredModels.has(model)) return this.client;
|
|
9736
10011
|
if (!ENGINE_ENV.OPENROUTER_API_KEY) {
|
|
@@ -10545,6 +10820,9 @@ var RelayManager = class {
|
|
|
10545
10820
|
async getHistory() {
|
|
10546
10821
|
return this.inner.getHistory();
|
|
10547
10822
|
}
|
|
10823
|
+
async listSlashCommands() {
|
|
10824
|
+
return this.inner.listSlashCommands?.() ?? [];
|
|
10825
|
+
}
|
|
10548
10826
|
isProcessing() {
|
|
10549
10827
|
return this.inner.isProcessing();
|
|
10550
10828
|
}
|
|
@@ -10604,7 +10882,7 @@ var KeepAliveService = class _KeepAliveService {
|
|
|
10604
10882
|
var keepAliveService = new KeepAliveService();
|
|
10605
10883
|
|
|
10606
10884
|
// src/services/canvas-service.ts
|
|
10607
|
-
import { readdir as
|
|
10885
|
+
import { readdir as readdir5, readFile as readFile12, stat as stat3 } from "fs/promises";
|
|
10608
10886
|
import { homedir as homedir12 } from "os";
|
|
10609
10887
|
import { join as join17 } from "path";
|
|
10610
10888
|
var CANVAS_DIRECTORIES = [
|
|
@@ -10617,7 +10895,7 @@ var CanvasService = class {
|
|
|
10617
10895
|
for (const directory of CANVAS_DIRECTORIES) {
|
|
10618
10896
|
let entries;
|
|
10619
10897
|
try {
|
|
10620
|
-
entries = await
|
|
10898
|
+
entries = await readdir5(directory, { withFileTypes: true });
|
|
10621
10899
|
} catch {
|
|
10622
10900
|
continue;
|
|
10623
10901
|
}
|
|
@@ -10664,7 +10942,7 @@ var CanvasService = class {
|
|
|
10664
10942
|
};
|
|
10665
10943
|
}
|
|
10666
10944
|
try {
|
|
10667
|
-
const bytes = await
|
|
10945
|
+
const bytes = await readFile12(filePath);
|
|
10668
10946
|
return { filename: safe, kind, sizeBytes, mimeType, updatedAt, bytes };
|
|
10669
10947
|
} catch {
|
|
10670
10948
|
continue;
|
|
@@ -10779,8 +11057,8 @@ async function reconcileCanvasItems(filenames) {
|
|
|
10779
11057
|
}
|
|
10780
11058
|
|
|
10781
11059
|
// src/services/upload-chat-transcripts.ts
|
|
10782
|
-
import { readdir as
|
|
10783
|
-
import { basename, join as join18 } from "path";
|
|
11060
|
+
import { readdir as readdir6, readFile as readFile13 } from "fs/promises";
|
|
11061
|
+
import { basename as basename2, join as join18 } from "path";
|
|
10784
11062
|
import { homedir as homedir13 } from "os";
|
|
10785
11063
|
var ENGINE_DIR2 = join18(homedir13(), ".replicas", "engine");
|
|
10786
11064
|
var HISTORY_DIRS = [
|
|
@@ -10795,13 +11073,13 @@ async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map()) {
|
|
|
10795
11073
|
for (const dir of HISTORY_DIRS) {
|
|
10796
11074
|
let entries;
|
|
10797
11075
|
try {
|
|
10798
|
-
entries = await
|
|
11076
|
+
entries = await readdir6(dir);
|
|
10799
11077
|
} catch {
|
|
10800
11078
|
continue;
|
|
10801
11079
|
}
|
|
10802
11080
|
for (const entry of entries) {
|
|
10803
11081
|
if (!entry.endsWith(".jsonl")) continue;
|
|
10804
|
-
const chatId =
|
|
11082
|
+
const chatId = basename2(entry, ".jsonl");
|
|
10805
11083
|
tasks.push(
|
|
10806
11084
|
uploadChatTranscript(chatId, join18(dir, entry), chatsById.get(chatId)).then(() => {
|
|
10807
11085
|
flushed++;
|
|
@@ -10816,7 +11094,7 @@ async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map()) {
|
|
|
10816
11094
|
return { flushed, failed };
|
|
10817
11095
|
}
|
|
10818
11096
|
async function uploadChatTranscript(chatId, filePath, chat) {
|
|
10819
|
-
const bytes = await
|
|
11097
|
+
const bytes = await readFile13(filePath);
|
|
10820
11098
|
if (bytes.byteLength === 0) return;
|
|
10821
11099
|
const form = new FormData();
|
|
10822
11100
|
form.append("chat_id", chatId);
|
|
@@ -11046,6 +11324,21 @@ var ChatService = class {
|
|
|
11046
11324
|
const chat = this.chats.get(chatId);
|
|
11047
11325
|
return chat ? this.toSummary(chat) : null;
|
|
11048
11326
|
}
|
|
11327
|
+
async listSlashCommands(chatId) {
|
|
11328
|
+
const chat = this.requireChat(chatId);
|
|
11329
|
+
const provider = chat.persisted.provider;
|
|
11330
|
+
const discovered = await chat.provider.listSlashCommands?.() ?? [];
|
|
11331
|
+
const providerCommands = discovered.map((command) => ({
|
|
11332
|
+
...command,
|
|
11333
|
+
providers: [provider]
|
|
11334
|
+
}));
|
|
11335
|
+
return {
|
|
11336
|
+
commands: mergeSlashCommands(
|
|
11337
|
+
getSlashCommandsForProvider(provider),
|
|
11338
|
+
providerCommands
|
|
11339
|
+
)
|
|
11340
|
+
};
|
|
11341
|
+
}
|
|
11049
11342
|
async createChat(request) {
|
|
11050
11343
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
11051
11344
|
const title = request.title?.trim() || `${request.provider} chat`;
|
|
@@ -11121,7 +11414,7 @@ var ChatService = class {
|
|
|
11121
11414
|
}
|
|
11122
11415
|
async readSenders(chatId) {
|
|
11123
11416
|
try {
|
|
11124
|
-
const content = await
|
|
11417
|
+
const content = await readFile14(this.senderFilePath(chatId), "utf-8");
|
|
11125
11418
|
const lines = content.split("\n").filter((line) => line.trim().length > 0);
|
|
11126
11419
|
const senders = [];
|
|
11127
11420
|
for (const line of lines) {
|
|
@@ -11531,7 +11824,7 @@ var ChatService = class {
|
|
|
11531
11824
|
}
|
|
11532
11825
|
async loadChats() {
|
|
11533
11826
|
try {
|
|
11534
|
-
const content = await
|
|
11827
|
+
const content = await readFile14(CHATS_FILE, "utf-8");
|
|
11535
11828
|
return parsePersistedChatsContent(content);
|
|
11536
11829
|
} catch (error) {
|
|
11537
11830
|
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
@@ -11546,7 +11839,7 @@ var ChatService = class {
|
|
|
11546
11839
|
console.error("[ChatService] Failed to quarantine corrupt chats file:", renameError);
|
|
11547
11840
|
}
|
|
11548
11841
|
try {
|
|
11549
|
-
const backupContent = await
|
|
11842
|
+
const backupContent = await readFile14(CHATS_BACKUP_FILE, "utf-8");
|
|
11550
11843
|
return parsePersistedChatsContent(backupContent);
|
|
11551
11844
|
} catch (backupError) {
|
|
11552
11845
|
if (backupError && typeof backupError === "object" && "code" in backupError && backupError.code === "ENOENT") {
|
|
@@ -11633,8 +11926,8 @@ var ChatService = class {
|
|
|
11633
11926
|
|
|
11634
11927
|
// src/services/repo-file-service.ts
|
|
11635
11928
|
import { execFile as execFile2 } from "child_process";
|
|
11636
|
-
import { readFile as
|
|
11637
|
-
import { join as join20, resolve as resolve2, extname } from "path";
|
|
11929
|
+
import { readFile as readFile15, realpath, stat as stat4 } from "fs/promises";
|
|
11930
|
+
import { join as join20, resolve as resolve2, extname as extname2 } from "path";
|
|
11638
11931
|
var CACHE_TTL_MS = 3e4;
|
|
11639
11932
|
var SEARCH_TIMEOUT_MS = 15e3;
|
|
11640
11933
|
var MAX_CONTENT_BYTES = 256 * 1024;
|
|
@@ -11642,7 +11935,7 @@ var DEFAULT_LIMIT = 50;
|
|
|
11642
11935
|
var MAX_LIMIT = 5e3;
|
|
11643
11936
|
var EXCLUDED_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", ".next", "dist", "build", "out", "vendor", ".turbo", "__pycache__"]);
|
|
11644
11937
|
function isBinaryExtension(filePath) {
|
|
11645
|
-
const ext =
|
|
11938
|
+
const ext = extname2(filePath).toLowerCase();
|
|
11646
11939
|
const binaryExts = /* @__PURE__ */ new Set([
|
|
11647
11940
|
".png",
|
|
11648
11941
|
".jpg",
|
|
@@ -11694,11 +11987,11 @@ function scoreMatch(query2, filePath) {
|
|
|
11694
11987
|
const lowerQuery = query2.toLowerCase();
|
|
11695
11988
|
const lowerPath = filePath.toLowerCase();
|
|
11696
11989
|
const segments = lowerPath.split("/");
|
|
11697
|
-
const
|
|
11698
|
-
if (
|
|
11699
|
-
if (
|
|
11990
|
+
const basename3 = segments[segments.length - 1] ?? "";
|
|
11991
|
+
if (basename3 === lowerQuery) return 100;
|
|
11992
|
+
if (basename3.startsWith(lowerQuery)) return 90;
|
|
11700
11993
|
if (segments.some((seg) => seg === lowerQuery)) return 80;
|
|
11701
|
-
if (
|
|
11994
|
+
if (basename3.includes(lowerQuery)) return 70;
|
|
11702
11995
|
if (segments.some((seg) => seg.includes(lowerQuery))) return 60;
|
|
11703
11996
|
if (lowerPath.includes(lowerQuery)) return 50;
|
|
11704
11997
|
return 0;
|
|
@@ -11823,7 +12116,7 @@ var RepoFileService = class {
|
|
|
11823
12116
|
tooLarge: true
|
|
11824
12117
|
};
|
|
11825
12118
|
}
|
|
11826
|
-
const content = await
|
|
12119
|
+
const content = await readFile15(fullPath, "utf-8");
|
|
11827
12120
|
return {
|
|
11828
12121
|
repoName,
|
|
11829
12122
|
path: filePath,
|
|
@@ -11901,17 +12194,17 @@ var RepoFileService = class {
|
|
|
11901
12194
|
// src/v1-routes.ts
|
|
11902
12195
|
import { Hono } from "hono";
|
|
11903
12196
|
import { z as z2 } from "zod";
|
|
11904
|
-
import { readdir as
|
|
12197
|
+
import { readdir as readdir8, stat as stat5, readFile as readFile18 } from "fs/promises";
|
|
11905
12198
|
import { join as join23, resolve as resolve3 } from "path";
|
|
11906
12199
|
|
|
11907
12200
|
// src/services/warm-hooks-service.ts
|
|
11908
12201
|
import { spawn as spawn4 } from "child_process";
|
|
11909
|
-
import { readFile as
|
|
12202
|
+
import { readFile as readFile17 } from "fs/promises";
|
|
11910
12203
|
import { existsSync as existsSync8 } from "fs";
|
|
11911
12204
|
import { join as join22 } from "path";
|
|
11912
12205
|
|
|
11913
12206
|
// src/services/warm-hook-logs-service.ts
|
|
11914
|
-
import { mkdir as mkdir14, readFile as
|
|
12207
|
+
import { mkdir as mkdir14, readFile as readFile16, writeFile as writeFile6, readdir as readdir7, appendFile as appendFile4, unlink as unlink3 } from "fs/promises";
|
|
11915
12208
|
import { homedir as homedir15 } from "os";
|
|
11916
12209
|
import { join as join21 } from "path";
|
|
11917
12210
|
var LOGS_DIR2 = join21(homedir15(), ".replicas", "warm-hook-logs");
|
|
@@ -11958,7 +12251,7 @@ var WarmHookLogsService = class {
|
|
|
11958
12251
|
async getAllLogs() {
|
|
11959
12252
|
let files;
|
|
11960
12253
|
try {
|
|
11961
|
-
files = await
|
|
12254
|
+
files = await readdir7(LOGS_DIR2);
|
|
11962
12255
|
} catch (err) {
|
|
11963
12256
|
if (err.code === "ENOENT") {
|
|
11964
12257
|
return [];
|
|
@@ -11971,7 +12264,7 @@ var WarmHookLogsService = class {
|
|
|
11971
12264
|
continue;
|
|
11972
12265
|
}
|
|
11973
12266
|
try {
|
|
11974
|
-
const raw = await
|
|
12267
|
+
const raw = await readFile16(join21(LOGS_DIR2, file), "utf-8");
|
|
11975
12268
|
const stored = JSON.parse(raw);
|
|
11976
12269
|
logs.push(withPreview2(stored));
|
|
11977
12270
|
} catch {
|
|
@@ -12000,7 +12293,7 @@ var WarmHookLogsService = class {
|
|
|
12000
12293
|
}
|
|
12001
12294
|
async getCurrentRunLog() {
|
|
12002
12295
|
try {
|
|
12003
|
-
return await
|
|
12296
|
+
return await readFile16(CURRENT_RUN_LOG, "utf-8");
|
|
12004
12297
|
} catch (err) {
|
|
12005
12298
|
if (err.code === "ENOENT") return null;
|
|
12006
12299
|
throw err;
|
|
@@ -12009,7 +12302,7 @@ var WarmHookLogsService = class {
|
|
|
12009
12302
|
async getFullOutput(hookType, hookName) {
|
|
12010
12303
|
const filename = hookType === "global" ? GLOBAL_FILENAME : hookType === "environment" ? ENVIRONMENT_HOOK_LOG_FILENAME : repoHookLogFilename(hookName);
|
|
12011
12304
|
try {
|
|
12012
|
-
const raw = await
|
|
12305
|
+
const raw = await readFile16(join21(LOGS_DIR2, filename), "utf-8");
|
|
12013
12306
|
const stored = JSON.parse(raw);
|
|
12014
12307
|
if (stored.hookType !== hookType || stored.hookName !== hookName) {
|
|
12015
12308
|
return null;
|
|
@@ -12033,7 +12326,7 @@ async function readRepoWarmHook(repoPath) {
|
|
|
12033
12326
|
continue;
|
|
12034
12327
|
}
|
|
12035
12328
|
try {
|
|
12036
|
-
const raw = await
|
|
12329
|
+
const raw = await readFile17(configPath, "utf-8");
|
|
12037
12330
|
const config = parseReplicasConfigString(raw, filename);
|
|
12038
12331
|
if (!config.warmHook) {
|
|
12039
12332
|
return null;
|
|
@@ -12468,6 +12761,17 @@ function createV1Routes(deps) {
|
|
|
12468
12761
|
return c.json(jsonError("Failed to load chat history", error instanceof Error ? error.message : "Unknown error"), 404);
|
|
12469
12762
|
}
|
|
12470
12763
|
});
|
|
12764
|
+
app2.get("/chats/:chatId/slash-commands", async (c) => {
|
|
12765
|
+
try {
|
|
12766
|
+
const response = await deps.chatService.listSlashCommands(c.req.param("chatId"));
|
|
12767
|
+
return c.json(response);
|
|
12768
|
+
} catch (error) {
|
|
12769
|
+
if (error instanceof ChatNotFoundError) {
|
|
12770
|
+
return c.json(jsonError("Failed to load slash commands", error.message), 404);
|
|
12771
|
+
}
|
|
12772
|
+
return c.json(jsonError("Failed to load slash commands", error instanceof Error ? error.message : "Unknown error"), 500);
|
|
12773
|
+
}
|
|
12774
|
+
});
|
|
12471
12775
|
app2.post("/chats/:chatId/messages", async (c) => {
|
|
12472
12776
|
try {
|
|
12473
12777
|
const body = sendMessageSchema.parse(await c.req.json());
|
|
@@ -12979,7 +13283,7 @@ function createV1Routes(deps) {
|
|
|
12979
13283
|
});
|
|
12980
13284
|
app2.get("/logs", async (c) => {
|
|
12981
13285
|
try {
|
|
12982
|
-
const files = await
|
|
13286
|
+
const files = await readdir8(LOG_DIR).catch(() => []);
|
|
12983
13287
|
const logFiles = files.filter((f) => f.endsWith(".log"));
|
|
12984
13288
|
const sessions = await Promise.all(
|
|
12985
13289
|
logFiles.map(async (filename) => {
|
|
@@ -13020,7 +13324,7 @@ function createV1Routes(deps) {
|
|
|
13020
13324
|
const limit = Math.min(parseInt(c.req.query("limit") || "500", 10), 5e3);
|
|
13021
13325
|
let content;
|
|
13022
13326
|
try {
|
|
13023
|
-
content = await
|
|
13327
|
+
content = await readFile18(filePath, "utf-8");
|
|
13024
13328
|
} catch {
|
|
13025
13329
|
return c.json(jsonError("Log session not found"), 404);
|
|
13026
13330
|
}
|