replicas-engine 0.1.318 → 0.1.319
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 +384 -105
- package/package.json +1 -1
package/dist/src/index.js
CHANGED
|
@@ -287,7 +287,7 @@ var WORKSPACE_SIZES = ["small", "large"];
|
|
|
287
287
|
var INVALID_WORKSPACE_SIZE_ERROR = `Invalid size: must be one of ${WORKSPACE_SIZES.join(", ")}`;
|
|
288
288
|
|
|
289
289
|
// ../shared/src/e2b.ts
|
|
290
|
-
var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-06-15-
|
|
290
|
+
var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-06-15-v3";
|
|
291
291
|
|
|
292
292
|
// ../shared/src/runtime-env.ts
|
|
293
293
|
function parsePosixEnvFile(content) {
|
|
@@ -2663,6 +2663,9 @@ function isGitHubUrl(url) {
|
|
|
2663
2663
|
return GITHUB_HOST_RE.test(url);
|
|
2664
2664
|
}
|
|
2665
2665
|
|
|
2666
|
+
// ../shared/src/skill-registry.ts
|
|
2667
|
+
var SKILL_REGISTRY_MANIFEST_VERSION = 1;
|
|
2668
|
+
|
|
2666
2669
|
// src/utils/exec.ts
|
|
2667
2670
|
var execAsync = promisify(exec);
|
|
2668
2671
|
var execFileAsync = promisify(execFile);
|
|
@@ -2816,7 +2819,7 @@ var BaseRefreshManager = class {
|
|
|
2816
2819
|
this.health.lastErrorMessage = message;
|
|
2817
2820
|
if (attempt < 3) {
|
|
2818
2821
|
console.warn(`[${this.managerName}] Initial refresh attempt ${attempt} failed, retrying in 2s...`);
|
|
2819
|
-
await new Promise((
|
|
2822
|
+
await new Promise((resolve4) => setTimeout(resolve4, 2e3));
|
|
2820
2823
|
} else {
|
|
2821
2824
|
console.error(`[${this.managerName}] Initial refresh failed after 3 attempts:`, error);
|
|
2822
2825
|
}
|
|
@@ -3735,7 +3738,7 @@ var GitService = class {
|
|
|
3735
3738
|
}
|
|
3736
3739
|
}
|
|
3737
3740
|
readUntrackedDiff(repoPath, paths) {
|
|
3738
|
-
return new Promise((
|
|
3741
|
+
return new Promise((resolve4) => {
|
|
3739
3742
|
const child = spawn("git", ["diff", "--", ...paths], {
|
|
3740
3743
|
cwd: repoPath,
|
|
3741
3744
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -3756,12 +3759,12 @@ var GitService = class {
|
|
|
3756
3759
|
});
|
|
3757
3760
|
child.stderr.on("data", () => {
|
|
3758
3761
|
});
|
|
3759
|
-
child.on("error", () =>
|
|
3762
|
+
child.on("error", () => resolve4(""));
|
|
3760
3763
|
child.on("close", (code) => {
|
|
3761
3764
|
if (code === 0 || code === 1 || truncated) {
|
|
3762
|
-
|
|
3765
|
+
resolve4(Buffer.concat(chunks).toString("utf-8"));
|
|
3763
3766
|
} else {
|
|
3764
|
-
|
|
3767
|
+
resolve4("");
|
|
3765
3768
|
}
|
|
3766
3769
|
});
|
|
3767
3770
|
});
|
|
@@ -4002,9 +4005,9 @@ var StreamWriter = class {
|
|
|
4002
4005
|
return true;
|
|
4003
4006
|
}
|
|
4004
4007
|
flush() {
|
|
4005
|
-
return new Promise((
|
|
4008
|
+
return new Promise((resolve4) => {
|
|
4006
4009
|
if (!this.stream) {
|
|
4007
|
-
|
|
4010
|
+
resolve4();
|
|
4008
4011
|
return;
|
|
4009
4012
|
}
|
|
4010
4013
|
if (this.flushTimer) {
|
|
@@ -4013,7 +4016,7 @@ var StreamWriter = class {
|
|
|
4013
4016
|
}
|
|
4014
4017
|
const s = this.stream;
|
|
4015
4018
|
this.stream = null;
|
|
4016
|
-
s.end(() =>
|
|
4019
|
+
s.end(() => resolve4());
|
|
4017
4020
|
});
|
|
4018
4021
|
}
|
|
4019
4022
|
scheduleDropWarning() {
|
|
@@ -4494,7 +4497,7 @@ var ReplicasConfigService = class {
|
|
|
4494
4497
|
await this.logToFile(`[${params.repoName}] --- Running: ${params.label} ---`);
|
|
4495
4498
|
emit(`$ ${params.label}
|
|
4496
4499
|
`);
|
|
4497
|
-
return new Promise((
|
|
4500
|
+
return new Promise((resolve4) => {
|
|
4498
4501
|
const proc = spawn2("bash", ["-lc", params.command], {
|
|
4499
4502
|
cwd: params.cwd,
|
|
4500
4503
|
env: process.env,
|
|
@@ -4505,7 +4508,7 @@ var ReplicasConfigService = class {
|
|
|
4505
4508
|
const finish = (result) => {
|
|
4506
4509
|
if (settled) return;
|
|
4507
4510
|
settled = true;
|
|
4508
|
-
|
|
4511
|
+
resolve4(result);
|
|
4509
4512
|
};
|
|
4510
4513
|
const timer = setTimeout(() => {
|
|
4511
4514
|
timedOut = true;
|
|
@@ -4931,7 +4934,7 @@ async function registerDesktopPreview() {
|
|
|
4931
4934
|
if (await attemptRegistration()) {
|
|
4932
4935
|
return;
|
|
4933
4936
|
}
|
|
4934
|
-
await new Promise((
|
|
4937
|
+
await new Promise((resolve4) => setTimeout(resolve4, RETRY_DELAY_MS));
|
|
4935
4938
|
}
|
|
4936
4939
|
console.error(
|
|
4937
4940
|
`[DesktopPreview] Gave up registering port ${DESKTOP_NOVNC_PORT} after ${REGISTRATION_TIMEOUT_MS}ms`
|
|
@@ -4940,9 +4943,9 @@ async function registerDesktopPreview() {
|
|
|
4940
4943
|
|
|
4941
4944
|
// src/services/chat/chat-service.ts
|
|
4942
4945
|
import { existsSync as existsSync7 } from "fs";
|
|
4943
|
-
import { appendFile as appendFile4, copyFile, mkdir as mkdir11, readFile as
|
|
4946
|
+
import { appendFile as appendFile4, copyFile, mkdir as mkdir11, readFile as readFile13, rename as rename2, rm } from "fs/promises";
|
|
4944
4947
|
import { homedir as homedir14 } from "os";
|
|
4945
|
-
import { join as
|
|
4948
|
+
import { join as join17 } from "path";
|
|
4946
4949
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
4947
4950
|
|
|
4948
4951
|
// src/managers/claude-manager.ts
|
|
@@ -4950,7 +4953,7 @@ import {
|
|
|
4950
4953
|
query
|
|
4951
4954
|
} from "@anthropic-ai/claude-agent-sdk";
|
|
4952
4955
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
4953
|
-
import { join as
|
|
4956
|
+
import { join as join14 } from "path";
|
|
4954
4957
|
import { mkdir as mkdir10, appendFile as appendFile2 } from "fs/promises";
|
|
4955
4958
|
import { homedir as homedir11 } from "os";
|
|
4956
4959
|
|
|
@@ -5800,6 +5803,248 @@ function extractToolCommand(input) {
|
|
|
5800
5803
|
return extractCommandProtectionCommandText({ toolInput: input }, { stringifyFallback: false });
|
|
5801
5804
|
}
|
|
5802
5805
|
|
|
5806
|
+
// src/services/skill-registry-service.ts
|
|
5807
|
+
import { readFile as readFile9, readdir as readdir3, stat as stat2 } from "fs/promises";
|
|
5808
|
+
import { dirname as dirname3, isAbsolute, join as join13, relative, resolve } from "path";
|
|
5809
|
+
var REGISTRY_ROOT_DIR = ".replicas/skill-registries";
|
|
5810
|
+
var REGISTRY_MANIFEST = "manifest.json";
|
|
5811
|
+
async function getSkillRegistryInventory(homeDir) {
|
|
5812
|
+
const registryRoot = getRegistryRoot(homeDir);
|
|
5813
|
+
const manifest = await readManifest(homeDir);
|
|
5814
|
+
if (!manifest) {
|
|
5815
|
+
return emptyInventory(registryRoot);
|
|
5816
|
+
}
|
|
5817
|
+
const registries = [];
|
|
5818
|
+
for (const registry of manifest.registries) {
|
|
5819
|
+
if (!isPathInside(registryRoot, registry.checkoutPath)) {
|
|
5820
|
+
console.warn(`[SkillRegistry] Ignoring registry outside root: ${registry.checkoutPath}`);
|
|
5821
|
+
continue;
|
|
5822
|
+
}
|
|
5823
|
+
if (!await directoryExists(registry.checkoutPath)) {
|
|
5824
|
+
console.warn(`[SkillRegistry] Ignoring missing registry checkout: ${registry.checkoutPath}`);
|
|
5825
|
+
continue;
|
|
5826
|
+
}
|
|
5827
|
+
const contents = await scanRegistry(registry.checkoutPath);
|
|
5828
|
+
registries.push({ ...registry, ...contents });
|
|
5829
|
+
}
|
|
5830
|
+
return {
|
|
5831
|
+
registryRoot,
|
|
5832
|
+
registries,
|
|
5833
|
+
claudePluginRoots: uniqueFlat(registries, (registry) => registry.claudePluginRoots),
|
|
5834
|
+
standaloneSkills: uniqueStandaloneSkills(registries.flatMap((registry) => registry.standaloneSkills)),
|
|
5835
|
+
codexMarketplaceCwds: uniqueFlat(registries, (registry) => registry.codexMarketplaceCwds)
|
|
5836
|
+
};
|
|
5837
|
+
}
|
|
5838
|
+
async function buildClaudeRegistryConfig(homeDir) {
|
|
5839
|
+
const inventory = await getSkillRegistryInventory(homeDir);
|
|
5840
|
+
return {
|
|
5841
|
+
plugins: inventory.claudePluginRoots.map((path5) => ({ type: "local", path: path5 })),
|
|
5842
|
+
enableAllSkills: inventory.claudePluginRoots.length > 0 || inventory.standaloneSkills.length > 0
|
|
5843
|
+
};
|
|
5844
|
+
}
|
|
5845
|
+
async function applyCodexSkillRegistries(params) {
|
|
5846
|
+
const inventory = await getSkillRegistryInventory(params.homeDir);
|
|
5847
|
+
if (inventory.registries.length === 0) return;
|
|
5848
|
+
await installCodexRegistryPlugins(params.client, inventory);
|
|
5849
|
+
}
|
|
5850
|
+
async function scanRegistry(registryDir) {
|
|
5851
|
+
const claudePluginRoots = await findClaudePluginRoots(registryDir);
|
|
5852
|
+
const skillCollections = await findSkillCollections(registryDir);
|
|
5853
|
+
const topLevelSkills = await findTopLevelSkills(registryDir);
|
|
5854
|
+
const codexMarketplaceCwds = await hasCodexMarketplace(registryDir) ? [registryDir] : [];
|
|
5855
|
+
return {
|
|
5856
|
+
claudePluginRoots,
|
|
5857
|
+
standaloneSkills: uniqueStandaloneSkills([
|
|
5858
|
+
...skillCollections.flatMap((collection) => collection.skillDirs.map((skillDir) => ({
|
|
5859
|
+
source: collection.source,
|
|
5860
|
+
skillDir
|
|
5861
|
+
}))),
|
|
5862
|
+
...topLevelSkills
|
|
5863
|
+
]),
|
|
5864
|
+
codexMarketplaceCwds
|
|
5865
|
+
};
|
|
5866
|
+
}
|
|
5867
|
+
async function findSkillCollections(registryDir) {
|
|
5868
|
+
const candidateRoots = [
|
|
5869
|
+
{ source: "skills", root: join13(registryDir, "skills") },
|
|
5870
|
+
{ source: "agents", root: join13(registryDir, ".agents", "skills") },
|
|
5871
|
+
{ source: "codex", root: join13(registryDir, ".codex", "skills") },
|
|
5872
|
+
{ source: "claude", root: join13(registryDir, ".claude", "skills") }
|
|
5873
|
+
];
|
|
5874
|
+
const collections = [];
|
|
5875
|
+
for (const { source, root } of candidateRoots) {
|
|
5876
|
+
const skillDirs = await findSkillDirsInRoot(root);
|
|
5877
|
+
if (skillDirs.length > 0) {
|
|
5878
|
+
collections.push({ source, root, skillDirs });
|
|
5879
|
+
}
|
|
5880
|
+
}
|
|
5881
|
+
return collections;
|
|
5882
|
+
}
|
|
5883
|
+
async function findSkillDirsInRoot(root) {
|
|
5884
|
+
const skillDirs = [];
|
|
5885
|
+
for (const dirent of await safeReadDir(root)) {
|
|
5886
|
+
const skillDir = join13(root, dirent.name);
|
|
5887
|
+
if (!await isDirectoryDirent(dirent, skillDir)) continue;
|
|
5888
|
+
if (await fileExists(join13(skillDir, "SKILL.md"))) {
|
|
5889
|
+
skillDirs.push(skillDir);
|
|
5890
|
+
}
|
|
5891
|
+
}
|
|
5892
|
+
return skillDirs;
|
|
5893
|
+
}
|
|
5894
|
+
async function findTopLevelSkills(registryDir) {
|
|
5895
|
+
const skills = [];
|
|
5896
|
+
for (const dirent of await safeReadDir(registryDir)) {
|
|
5897
|
+
if (dirent.name.startsWith(".") || dirent.name === "skills" || dirent.name === "plugins") continue;
|
|
5898
|
+
const skillDir = join13(registryDir, dirent.name);
|
|
5899
|
+
if (!await isDirectoryDirent(dirent, skillDir)) continue;
|
|
5900
|
+
if (await fileExists(join13(skillDir, "SKILL.md"))) {
|
|
5901
|
+
skills.push({ source: "root", skillDir });
|
|
5902
|
+
}
|
|
5903
|
+
}
|
|
5904
|
+
return skills;
|
|
5905
|
+
}
|
|
5906
|
+
async function findClaudePluginRoots(registryDir) {
|
|
5907
|
+
const roots = [];
|
|
5908
|
+
async function walk(dir) {
|
|
5909
|
+
for (const dirent of await safeReadDir(dir)) {
|
|
5910
|
+
if (dirent.name === ".git") continue;
|
|
5911
|
+
const child = join13(dir, dirent.name);
|
|
5912
|
+
if (!await isDirectoryDirent(dirent, child)) continue;
|
|
5913
|
+
if (dirent.name === ".claude-plugin") {
|
|
5914
|
+
if (await fileExists(join13(child, "plugin.json"))) {
|
|
5915
|
+
roots.push(dirname3(child));
|
|
5916
|
+
}
|
|
5917
|
+
continue;
|
|
5918
|
+
}
|
|
5919
|
+
await walk(child);
|
|
5920
|
+
}
|
|
5921
|
+
}
|
|
5922
|
+
await walk(registryDir);
|
|
5923
|
+
return uniqueStrings(roots);
|
|
5924
|
+
}
|
|
5925
|
+
async function hasCodexMarketplace(registryDir) {
|
|
5926
|
+
return await fileExists(join13(registryDir, ".agents", "plugins", "marketplace.json")) || await fileExists(join13(registryDir, ".codex", "plugins", "marketplace.json"));
|
|
5927
|
+
}
|
|
5928
|
+
async function installCodexRegistryPlugins(client, inventory) {
|
|
5929
|
+
const cwds = inventory.codexMarketplaceCwds;
|
|
5930
|
+
if (cwds.length === 0) return;
|
|
5931
|
+
try {
|
|
5932
|
+
const response = await client.request("plugin/list", { cwds });
|
|
5933
|
+
for (const marketplace of response.marketplaces) {
|
|
5934
|
+
if (!marketplace.path || !isPathInside(inventory.registryRoot, marketplace.path)) continue;
|
|
5935
|
+
for (const plugin of marketplace.plugins) {
|
|
5936
|
+
if (plugin.installed || plugin.installPolicy === "NOT_AVAILABLE" || plugin.availability !== "AVAILABLE") {
|
|
5937
|
+
continue;
|
|
5938
|
+
}
|
|
5939
|
+
try {
|
|
5940
|
+
await client.request("plugin/install", {
|
|
5941
|
+
marketplacePath: marketplace.path,
|
|
5942
|
+
pluginName: plugin.name
|
|
5943
|
+
});
|
|
5944
|
+
} catch (error) {
|
|
5945
|
+
console.warn(`[SkillRegistry] Failed to install Codex registry plugin ${plugin.name}:`, error);
|
|
5946
|
+
}
|
|
5947
|
+
}
|
|
5948
|
+
}
|
|
5949
|
+
} catch (error) {
|
|
5950
|
+
console.warn("[SkillRegistry] Failed to list Codex registry plugins:", error);
|
|
5951
|
+
}
|
|
5952
|
+
}
|
|
5953
|
+
async function readManifest(homeDir) {
|
|
5954
|
+
try {
|
|
5955
|
+
const raw = await readFile9(getManifestPath(homeDir), "utf8");
|
|
5956
|
+
const parsed = JSON.parse(raw);
|
|
5957
|
+
if (!isManifest(parsed)) {
|
|
5958
|
+
console.warn("[SkillRegistry] Ignoring invalid skill registry manifest.");
|
|
5959
|
+
return null;
|
|
5960
|
+
}
|
|
5961
|
+
return parsed;
|
|
5962
|
+
} catch (error) {
|
|
5963
|
+
if (isNotFoundError(error)) return null;
|
|
5964
|
+
throw error;
|
|
5965
|
+
}
|
|
5966
|
+
}
|
|
5967
|
+
function isManifest(value) {
|
|
5968
|
+
if (typeof value !== "object" || value === null) return false;
|
|
5969
|
+
return "version" in value && value.version === SKILL_REGISTRY_MANIFEST_VERSION && "registries" in value && Array.isArray(value.registries) && value.registries.every(isSkillRegistryEntry);
|
|
5970
|
+
}
|
|
5971
|
+
function isSkillRegistryEntry(value) {
|
|
5972
|
+
if (typeof value !== "object" || value === null) return false;
|
|
5973
|
+
return "index" in value && typeof value.index === "number" && "name" in value && typeof value.name === "string" && "url" in value && typeof value.url === "string" && "checkoutPath" in value && typeof value.checkoutPath === "string";
|
|
5974
|
+
}
|
|
5975
|
+
function getRegistryRoot(homeDir) {
|
|
5976
|
+
return join13(homeDir, REGISTRY_ROOT_DIR);
|
|
5977
|
+
}
|
|
5978
|
+
function getManifestPath(homeDir) {
|
|
5979
|
+
return join13(getRegistryRoot(homeDir), REGISTRY_MANIFEST);
|
|
5980
|
+
}
|
|
5981
|
+
function emptyInventory(registryRoot) {
|
|
5982
|
+
return {
|
|
5983
|
+
registryRoot,
|
|
5984
|
+
registries: [],
|
|
5985
|
+
claudePluginRoots: [],
|
|
5986
|
+
standaloneSkills: [],
|
|
5987
|
+
codexMarketplaceCwds: []
|
|
5988
|
+
};
|
|
5989
|
+
}
|
|
5990
|
+
function uniqueFlat(items, getValues) {
|
|
5991
|
+
return uniqueStrings(items.flatMap(getValues));
|
|
5992
|
+
}
|
|
5993
|
+
function uniqueStrings(values) {
|
|
5994
|
+
return Array.from(new Set(values));
|
|
5995
|
+
}
|
|
5996
|
+
function uniqueStandaloneSkills(skills) {
|
|
5997
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5998
|
+
const unique = [];
|
|
5999
|
+
for (const skill of skills) {
|
|
6000
|
+
const key = `${skill.source}\0${skill.skillDir}`;
|
|
6001
|
+
if (seen.has(key)) continue;
|
|
6002
|
+
seen.add(key);
|
|
6003
|
+
unique.push(skill);
|
|
6004
|
+
}
|
|
6005
|
+
return unique;
|
|
6006
|
+
}
|
|
6007
|
+
async function safeReadDir(path5) {
|
|
6008
|
+
try {
|
|
6009
|
+
return await readdir3(path5, { withFileTypes: true });
|
|
6010
|
+
} catch (error) {
|
|
6011
|
+
if (isNotFoundError(error)) return [];
|
|
6012
|
+
throw error;
|
|
6013
|
+
}
|
|
6014
|
+
}
|
|
6015
|
+
async function isDirectoryDirent(dirent, path5) {
|
|
6016
|
+
if (dirent.isDirectory()) return true;
|
|
6017
|
+
if (!dirent.isSymbolicLink()) return false;
|
|
6018
|
+
return directoryExists(path5);
|
|
6019
|
+
}
|
|
6020
|
+
async function directoryExists(path5) {
|
|
6021
|
+
try {
|
|
6022
|
+
const pathStat = await stat2(path5);
|
|
6023
|
+
return pathStat.isDirectory();
|
|
6024
|
+
} catch (error) {
|
|
6025
|
+
if (isNotFoundError(error)) return false;
|
|
6026
|
+
throw error;
|
|
6027
|
+
}
|
|
6028
|
+
}
|
|
6029
|
+
async function fileExists(path5) {
|
|
6030
|
+
try {
|
|
6031
|
+
const pathStat = await stat2(path5);
|
|
6032
|
+
return pathStat.isFile();
|
|
6033
|
+
} catch (error) {
|
|
6034
|
+
if (isNotFoundError(error)) return false;
|
|
6035
|
+
throw error;
|
|
6036
|
+
}
|
|
6037
|
+
}
|
|
6038
|
+
function isPathInside(parentPath, childPath) {
|
|
6039
|
+
const parent = resolve(parentPath);
|
|
6040
|
+
const child = resolve(childPath);
|
|
6041
|
+
const childRelativePath = relative(parent, child);
|
|
6042
|
+
return childRelativePath === "" || !childRelativePath.startsWith("..") && !isAbsolute(childRelativePath);
|
|
6043
|
+
}
|
|
6044
|
+
function isNotFoundError(error) {
|
|
6045
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
6046
|
+
}
|
|
6047
|
+
|
|
5803
6048
|
// src/managers/claude-manager.ts
|
|
5804
6049
|
var PromptStream = class {
|
|
5805
6050
|
queue = [];
|
|
@@ -5832,8 +6077,8 @@ var PromptStream = class {
|
|
|
5832
6077
|
if (this.closed) {
|
|
5833
6078
|
return Promise.resolve({ value: void 0, done: true });
|
|
5834
6079
|
}
|
|
5835
|
-
return new Promise((
|
|
5836
|
-
this.waiters.push(
|
|
6080
|
+
return new Promise((resolve4) => {
|
|
6081
|
+
this.waiters.push(resolve4);
|
|
5837
6082
|
});
|
|
5838
6083
|
}
|
|
5839
6084
|
};
|
|
@@ -5997,7 +6242,7 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
5997
6242
|
authRetrying = false;
|
|
5998
6243
|
constructor(options) {
|
|
5999
6244
|
super(options);
|
|
6000
|
-
this.historyFile = options.historyFilePath ??
|
|
6245
|
+
this.historyFile = options.historyFilePath ?? join14(homedir11(), ".replicas", "claude", "history.jsonl");
|
|
6001
6246
|
this.systemPromptOverride = options.systemPromptOverride;
|
|
6002
6247
|
this.toolsOverride = options.tools;
|
|
6003
6248
|
this.mcpServersConfig = options.mcpServers;
|
|
@@ -6071,14 +6316,14 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
6071
6316
|
const requestId = randomUUID4();
|
|
6072
6317
|
const toolUseId = options.toolUseID;
|
|
6073
6318
|
const { options: requestOptions, questions: requestQuestions } = handler.getRequest(input);
|
|
6074
|
-
const result = await new Promise((
|
|
6319
|
+
const result = await new Promise((resolve4) => {
|
|
6075
6320
|
this.pendingToolInputs.set(requestId, {
|
|
6076
6321
|
requestId,
|
|
6077
6322
|
toolUseId,
|
|
6078
6323
|
toolName,
|
|
6079
6324
|
input,
|
|
6080
6325
|
handler,
|
|
6081
|
-
resolve:
|
|
6326
|
+
resolve: resolve4
|
|
6082
6327
|
});
|
|
6083
6328
|
const onAbort = () => {
|
|
6084
6329
|
const pending = this.pendingToolInputs.get(requestId);
|
|
@@ -6275,8 +6520,8 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
6275
6520
|
this.pendingInterrupt = false;
|
|
6276
6521
|
return;
|
|
6277
6522
|
}
|
|
6278
|
-
await new Promise((
|
|
6279
|
-
this.pendingTurn = { resolve:
|
|
6523
|
+
await new Promise((resolve4, reject) => {
|
|
6524
|
+
this.pendingTurn = { resolve: resolve4, reject };
|
|
6280
6525
|
promptStream.push(userMessage);
|
|
6281
6526
|
});
|
|
6282
6527
|
}
|
|
@@ -6351,6 +6596,15 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
6351
6596
|
...useDefaultToolPolicy ? ALWAYS_DISALLOWED_TOOLS : [],
|
|
6352
6597
|
...interactiveAllowed ? [] : INTERACTIVE_TOOL_NAMES
|
|
6353
6598
|
];
|
|
6599
|
+
let registryPlugins = [];
|
|
6600
|
+
let enableRegistrySkills = false;
|
|
6601
|
+
try {
|
|
6602
|
+
const registryConfig = await buildClaudeRegistryConfig(ENGINE_ENV.HOME_DIR);
|
|
6603
|
+
registryPlugins = registryConfig.plugins;
|
|
6604
|
+
enableRegistrySkills = registryConfig.enableAllSkills;
|
|
6605
|
+
} catch (error) {
|
|
6606
|
+
console.warn("[ClaudeManager] Failed to load skill registry config:", error);
|
|
6607
|
+
}
|
|
6354
6608
|
const promptStream = new PromptStream();
|
|
6355
6609
|
const response = query({
|
|
6356
6610
|
prompt: promptStream,
|
|
@@ -6366,6 +6620,8 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
6366
6620
|
settingSources: ["user", "project", "local"],
|
|
6367
6621
|
systemPrompt,
|
|
6368
6622
|
...this.mcpServersConfig ? { mcpServers: this.mcpServersConfig } : {},
|
|
6623
|
+
...registryPlugins.length > 0 ? { plugins: registryPlugins } : {},
|
|
6624
|
+
...enableRegistrySkills ? { skills: "all" } : {},
|
|
6369
6625
|
env: queryEnv,
|
|
6370
6626
|
model: resolvedModel,
|
|
6371
6627
|
includePartialMessages: true,
|
|
@@ -6648,7 +6904,7 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
6648
6904
|
}
|
|
6649
6905
|
}
|
|
6650
6906
|
async initialize() {
|
|
6651
|
-
const historyDir =
|
|
6907
|
+
const historyDir = join14(homedir11(), ".replicas", "claude");
|
|
6652
6908
|
await mkdir10(historyDir, { recursive: true });
|
|
6653
6909
|
if (this.initialSessionId) {
|
|
6654
6910
|
this.sessionId = this.initialSessionId;
|
|
@@ -6731,13 +6987,13 @@ var AspClient = class {
|
|
|
6731
6987
|
}
|
|
6732
6988
|
const id = this.nextId;
|
|
6733
6989
|
this.nextId += 1;
|
|
6734
|
-
const promise = new Promise((
|
|
6990
|
+
const promise = new Promise((resolve4, reject) => {
|
|
6735
6991
|
const timeoutMs = opts?.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
6736
6992
|
const timer = timeoutMs > 0 ? setTimeout(() => {
|
|
6737
6993
|
this.pending.delete(id);
|
|
6738
6994
|
reject(new Error(`ASP request timed out for ${method}`));
|
|
6739
6995
|
}, timeoutMs) : null;
|
|
6740
|
-
this.pending.set(id, { resolve:
|
|
6996
|
+
this.pending.set(id, { resolve: resolve4, reject, method, timer });
|
|
6741
6997
|
});
|
|
6742
6998
|
this.write({ method, id, params });
|
|
6743
6999
|
return promise;
|
|
@@ -6887,7 +7143,7 @@ var AspClient = class {
|
|
|
6887
7143
|
// src/managers/codex-asp/app-server-process.ts
|
|
6888
7144
|
var DEFAULT_CODEX_BINARY = "codex";
|
|
6889
7145
|
var DEFAULT_CODEX_ARGS = ["app-server", "--listen", "stdio://"];
|
|
6890
|
-
var ENGINE_PACKAGE_VERSION = "0.1.
|
|
7146
|
+
var ENGINE_PACKAGE_VERSION = "0.1.319";
|
|
6891
7147
|
var INITIALIZE_METHOD = "initialize";
|
|
6892
7148
|
var INITIALIZED_NOTIFICATION = "initialized";
|
|
6893
7149
|
var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
|
|
@@ -6992,13 +7248,13 @@ var AppServerProcess = class {
|
|
|
6992
7248
|
if (!child || child.killed) {
|
|
6993
7249
|
return;
|
|
6994
7250
|
}
|
|
6995
|
-
await new Promise((
|
|
7251
|
+
await new Promise((resolve4) => {
|
|
6996
7252
|
const timer = setTimeout(() => {
|
|
6997
7253
|
child.kill("SIGKILL");
|
|
6998
7254
|
}, 2e3);
|
|
6999
7255
|
child.once("exit", () => {
|
|
7000
7256
|
clearTimeout(timer);
|
|
7001
|
-
|
|
7257
|
+
resolve4();
|
|
7002
7258
|
});
|
|
7003
7259
|
child.kill("SIGTERM");
|
|
7004
7260
|
});
|
|
@@ -7022,8 +7278,8 @@ var AppServerProcess = class {
|
|
|
7022
7278
|
}
|
|
7023
7279
|
this.shuttingDown = true;
|
|
7024
7280
|
child.kill("SIGKILL");
|
|
7025
|
-
await new Promise((
|
|
7026
|
-
child.once("exit", () =>
|
|
7281
|
+
await new Promise((resolve4) => {
|
|
7282
|
+
child.once("exit", () => resolve4());
|
|
7027
7283
|
});
|
|
7028
7284
|
}
|
|
7029
7285
|
};
|
|
@@ -7690,7 +7946,7 @@ var TranscriptUpdateCoalescer = class {
|
|
|
7690
7946
|
};
|
|
7691
7947
|
|
|
7692
7948
|
// src/managers/codex-asp/codex-history-file.ts
|
|
7693
|
-
import { appendFile as appendFile3, readFile as
|
|
7949
|
+
import { appendFile as appendFile3, readFile as readFile10 } from "fs/promises";
|
|
7694
7950
|
var CodexHistoryFile = class {
|
|
7695
7951
|
constructor(filePath) {
|
|
7696
7952
|
this.filePath = filePath;
|
|
@@ -7708,7 +7964,7 @@ var CodexHistoryFile = class {
|
|
|
7708
7964
|
}
|
|
7709
7965
|
async load() {
|
|
7710
7966
|
try {
|
|
7711
|
-
const content = await
|
|
7967
|
+
const content = await readFile10(this.filePath, "utf-8");
|
|
7712
7968
|
return parseAgentEventJsonlWithCodexAspTranscript(content);
|
|
7713
7969
|
} catch (error) {
|
|
7714
7970
|
if (!(error && typeof error === "object" && "code" in error && error.code === "ENOENT")) {
|
|
@@ -7734,6 +7990,7 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
7734
7990
|
transcriptUpdateCoalescer = new TranscriptUpdateCoalescer((threadId) => {
|
|
7735
7991
|
this.flushTranscriptUpdated(threadId);
|
|
7736
7992
|
});
|
|
7993
|
+
skillRegistriesApplied = false;
|
|
7737
7994
|
constructor(options) {
|
|
7738
7995
|
super(options);
|
|
7739
7996
|
this.historyFile = options.historyFilePath ? new CodexHistoryFile(options.historyFilePath) : null;
|
|
@@ -7919,6 +8176,7 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
7919
8176
|
}
|
|
7920
8177
|
}
|
|
7921
8178
|
async ensureThread(host, request, developerInstructions) {
|
|
8179
|
+
await this.applySkillRegistries(host);
|
|
7922
8180
|
const existingThreadId = this.currentThreadId;
|
|
7923
8181
|
if (existingThreadId) {
|
|
7924
8182
|
if (!this.threadAttached) {
|
|
@@ -7943,6 +8201,18 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
7943
8201
|
await this.onSaveSessionId(this.currentThreadId);
|
|
7944
8202
|
return threadId;
|
|
7945
8203
|
}
|
|
8204
|
+
async applySkillRegistries(host) {
|
|
8205
|
+
if (this.skillRegistriesApplied) return;
|
|
8206
|
+
try {
|
|
8207
|
+
await applyCodexSkillRegistries({
|
|
8208
|
+
client: host.client,
|
|
8209
|
+
homeDir: ENGINE_ENV.HOME_DIR
|
|
8210
|
+
});
|
|
8211
|
+
this.skillRegistriesApplied = true;
|
|
8212
|
+
} catch (error) {
|
|
8213
|
+
console.warn("[CodexAspManager] Failed to apply skill registries:", error);
|
|
8214
|
+
}
|
|
8215
|
+
}
|
|
7946
8216
|
async runTurn(host, threadId, request, developerInstructions) {
|
|
7947
8217
|
const { params, tempImagePaths } = await buildTurnStartParams(threadId, request, developerInstructions);
|
|
7948
8218
|
return this.observeTurn(host, threadId, request, async () => {
|
|
@@ -7965,8 +8235,8 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
7965
8235
|
}
|
|
7966
8236
|
async observeTurn(host, threadId, request, startTurn) {
|
|
7967
8237
|
let resolveCompleted;
|
|
7968
|
-
const completed = new Promise((
|
|
7969
|
-
resolveCompleted =
|
|
8238
|
+
const completed = new Promise((resolve4) => {
|
|
8239
|
+
resolveCompleted = resolve4;
|
|
7970
8240
|
});
|
|
7971
8241
|
let rejectDisposed = () => {
|
|
7972
8242
|
};
|
|
@@ -8166,7 +8436,9 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
8166
8436
|
serverRequest.params.itemId,
|
|
8167
8437
|
serverRequest.params.command ?? "",
|
|
8168
8438
|
result.reason,
|
|
8169
|
-
serverRequest.params.startedAtMs
|
|
8439
|
+
serverRequest.params.startedAtMs,
|
|
8440
|
+
serverRequest.params.cwd,
|
|
8441
|
+
serverRequest.params.commandActions
|
|
8170
8442
|
);
|
|
8171
8443
|
host.client.respond(requestId, { decision: "decline" });
|
|
8172
8444
|
return;
|
|
@@ -8203,7 +8475,9 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
8203
8475
|
serverRequest.params.callId,
|
|
8204
8476
|
command,
|
|
8205
8477
|
result.reason,
|
|
8206
|
-
Date.now()
|
|
8478
|
+
Date.now(),
|
|
8479
|
+
serverRequest.params.cwd,
|
|
8480
|
+
[{ type: "unknown", command }]
|
|
8207
8481
|
);
|
|
8208
8482
|
host.client.respond(requestId, { decision: "denied" });
|
|
8209
8483
|
return;
|
|
@@ -8260,16 +8534,21 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
8260
8534
|
nextTranscriptSequence() {
|
|
8261
8535
|
return this.codexAspSequence++;
|
|
8262
8536
|
}
|
|
8263
|
-
recordBlockedCommand(threadId, turnId, itemId, command, reason, startedAtMs) {
|
|
8537
|
+
recordBlockedCommand(threadId, turnId, itemId, command, reason, startedAtMs, cwd, commandActions) {
|
|
8264
8538
|
const output = reason?.includes("Blocked by organization policy") ? reason : `Blocked by organization policy: ${reason || "agents may not merge pull requests."}`;
|
|
8265
8539
|
const timestamp = timestampFromMilliseconds(startedAtMs);
|
|
8266
8540
|
const blockedItem = {
|
|
8267
8541
|
type: "commandExecution",
|
|
8268
8542
|
id: itemId,
|
|
8269
8543
|
command,
|
|
8544
|
+
cwd: cwd ?? this.workingDirectory,
|
|
8545
|
+
processId: null,
|
|
8546
|
+
source: "agent",
|
|
8547
|
+
commandActions: commandActions ?? [{ type: "unknown", command }],
|
|
8270
8548
|
aggregatedOutput: output,
|
|
8271
8549
|
exitCode: null,
|
|
8272
|
-
status: "declined"
|
|
8550
|
+
status: "declined",
|
|
8551
|
+
durationMs: null
|
|
8273
8552
|
};
|
|
8274
8553
|
this.upsertTranscriptItem(threadId, turnId, blockedItem, timestamp, "failed", "completed");
|
|
8275
8554
|
this.emitTranscriptUpdated(threadId, { immediate: true });
|
|
@@ -9191,12 +9470,12 @@ var KeepAliveService = class _KeepAliveService {
|
|
|
9191
9470
|
var keepAliveService = new KeepAliveService();
|
|
9192
9471
|
|
|
9193
9472
|
// src/services/canvas-service.ts
|
|
9194
|
-
import { readdir as
|
|
9473
|
+
import { readdir as readdir4, readFile as readFile11, stat as stat3 } from "fs/promises";
|
|
9195
9474
|
import { homedir as homedir12 } from "os";
|
|
9196
|
-
import { join as
|
|
9475
|
+
import { join as join15 } from "path";
|
|
9197
9476
|
var CANVAS_DIRECTORIES = [
|
|
9198
|
-
|
|
9199
|
-
|
|
9477
|
+
join15(homedir12(), ".claude", "plans"),
|
|
9478
|
+
join15(homedir12(), ".replicas", "canvas")
|
|
9200
9479
|
];
|
|
9201
9480
|
var CanvasService = class {
|
|
9202
9481
|
async listItems() {
|
|
@@ -9204,7 +9483,7 @@ var CanvasService = class {
|
|
|
9204
9483
|
for (const directory of CANVAS_DIRECTORIES) {
|
|
9205
9484
|
let entries;
|
|
9206
9485
|
try {
|
|
9207
|
-
entries = await
|
|
9486
|
+
entries = await readdir4(directory, { withFileTypes: true });
|
|
9208
9487
|
} catch {
|
|
9209
9488
|
continue;
|
|
9210
9489
|
}
|
|
@@ -9215,7 +9494,7 @@ var CanvasService = class {
|
|
|
9215
9494
|
const { kind } = classifyCanvasFilename(entry.name);
|
|
9216
9495
|
let sizeBytes = 0;
|
|
9217
9496
|
try {
|
|
9218
|
-
const s = await
|
|
9497
|
+
const s = await stat3(join15(directory, entry.name));
|
|
9219
9498
|
sizeBytes = s.size;
|
|
9220
9499
|
} catch {
|
|
9221
9500
|
continue;
|
|
@@ -9230,11 +9509,11 @@ var CanvasService = class {
|
|
|
9230
9509
|
if (!safe) return null;
|
|
9231
9510
|
const { kind, mimeType } = classifyCanvasFilename(safe);
|
|
9232
9511
|
for (const directory of CANVAS_DIRECTORIES) {
|
|
9233
|
-
const filePath =
|
|
9512
|
+
const filePath = join15(directory, safe);
|
|
9234
9513
|
let sizeBytes = 0;
|
|
9235
9514
|
let updatedAt = "";
|
|
9236
9515
|
try {
|
|
9237
|
-
const s = await
|
|
9516
|
+
const s = await stat3(filePath);
|
|
9238
9517
|
sizeBytes = s.size;
|
|
9239
9518
|
updatedAt = s.mtime.toISOString();
|
|
9240
9519
|
} catch {
|
|
@@ -9251,7 +9530,7 @@ var CanvasService = class {
|
|
|
9251
9530
|
};
|
|
9252
9531
|
}
|
|
9253
9532
|
try {
|
|
9254
|
-
const bytes = await
|
|
9533
|
+
const bytes = await readFile11(filePath);
|
|
9255
9534
|
return { filename: safe, kind, sizeBytes, mimeType, updatedAt, bytes };
|
|
9256
9535
|
} catch {
|
|
9257
9536
|
continue;
|
|
@@ -9366,14 +9645,14 @@ async function reconcileCanvasItems(filenames) {
|
|
|
9366
9645
|
}
|
|
9367
9646
|
|
|
9368
9647
|
// src/services/upload-chat-transcripts.ts
|
|
9369
|
-
import { readdir as
|
|
9370
|
-
import { basename, join as
|
|
9648
|
+
import { readdir as readdir5, readFile as readFile12 } from "fs/promises";
|
|
9649
|
+
import { basename, join as join16 } from "path";
|
|
9371
9650
|
import { homedir as homedir13 } from "os";
|
|
9372
|
-
var ENGINE_DIR2 =
|
|
9651
|
+
var ENGINE_DIR2 = join16(homedir13(), ".replicas", "engine");
|
|
9373
9652
|
var HISTORY_DIRS = [
|
|
9374
|
-
|
|
9375
|
-
|
|
9376
|
-
|
|
9653
|
+
join16(ENGINE_DIR2, "claude-histories"),
|
|
9654
|
+
join16(ENGINE_DIR2, "relay-histories"),
|
|
9655
|
+
join16(ENGINE_DIR2, "codex-histories")
|
|
9377
9656
|
];
|
|
9378
9657
|
async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map()) {
|
|
9379
9658
|
let flushed = 0;
|
|
@@ -9382,7 +9661,7 @@ async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map()) {
|
|
|
9382
9661
|
for (const dir of HISTORY_DIRS) {
|
|
9383
9662
|
let entries;
|
|
9384
9663
|
try {
|
|
9385
|
-
entries = await
|
|
9664
|
+
entries = await readdir5(dir);
|
|
9386
9665
|
} catch {
|
|
9387
9666
|
continue;
|
|
9388
9667
|
}
|
|
@@ -9390,7 +9669,7 @@ async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map()) {
|
|
|
9390
9669
|
if (!entry.endsWith(".jsonl")) continue;
|
|
9391
9670
|
const chatId = basename(entry, ".jsonl");
|
|
9392
9671
|
tasks.push(
|
|
9393
|
-
uploadChatTranscript(chatId,
|
|
9672
|
+
uploadChatTranscript(chatId, join16(dir, entry), chatsById.get(chatId)).then(() => {
|
|
9394
9673
|
flushed++;
|
|
9395
9674
|
}).catch((err) => {
|
|
9396
9675
|
failed++;
|
|
@@ -9403,7 +9682,7 @@ async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map()) {
|
|
|
9403
9682
|
return { flushed, failed };
|
|
9404
9683
|
}
|
|
9405
9684
|
async function uploadChatTranscript(chatId, filePath, chat) {
|
|
9406
|
-
const bytes = await
|
|
9685
|
+
const bytes = await readFile12(filePath);
|
|
9407
9686
|
if (bytes.byteLength === 0) return;
|
|
9408
9687
|
const form = new FormData();
|
|
9409
9688
|
form.append("chat_id", chatId);
|
|
@@ -9460,18 +9739,18 @@ var DuplicateDefaultChatError = class extends Error {
|
|
|
9460
9739
|
};
|
|
9461
9740
|
|
|
9462
9741
|
// src/services/chat/chat-service.ts
|
|
9463
|
-
var ENGINE_DIR3 =
|
|
9464
|
-
var CHATS_FILE =
|
|
9465
|
-
var CLAUDE_HISTORY_DIR =
|
|
9466
|
-
var RELAY_HISTORY_DIR =
|
|
9467
|
-
var CODEX_HISTORY_DIR =
|
|
9742
|
+
var ENGINE_DIR3 = join17(homedir14(), ".replicas", "engine");
|
|
9743
|
+
var CHATS_FILE = join17(ENGINE_DIR3, "chats.json");
|
|
9744
|
+
var CLAUDE_HISTORY_DIR = join17(ENGINE_DIR3, "claude-histories");
|
|
9745
|
+
var RELAY_HISTORY_DIR = join17(ENGINE_DIR3, "relay-histories");
|
|
9746
|
+
var CODEX_HISTORY_DIR = join17(ENGINE_DIR3, "codex-histories");
|
|
9468
9747
|
var HISTORY_DIR_BY_PROVIDER = {
|
|
9469
9748
|
claude: CLAUDE_HISTORY_DIR,
|
|
9470
9749
|
relay: RELAY_HISTORY_DIR,
|
|
9471
9750
|
codex: CODEX_HISTORY_DIR
|
|
9472
9751
|
};
|
|
9473
|
-
var CHAT_SENDERS_DIR =
|
|
9474
|
-
var CODEX_AUTH_PATH2 =
|
|
9752
|
+
var CHAT_SENDERS_DIR = join17(ENGINE_DIR3, "chat-senders");
|
|
9753
|
+
var CODEX_AUTH_PATH2 = join17(homedir14(), ".codex", "auth.json");
|
|
9475
9754
|
var CHATS_BACKUP_FILE = `${CHATS_FILE}.bak`;
|
|
9476
9755
|
function isChatMessageSender(value) {
|
|
9477
9756
|
if (!isRecord4(value)) return false;
|
|
@@ -9669,7 +9948,7 @@ var ChatService = class {
|
|
|
9669
9948
|
};
|
|
9670
9949
|
}
|
|
9671
9950
|
senderFilePath(chatId) {
|
|
9672
|
-
return
|
|
9951
|
+
return join17(CHAT_SENDERS_DIR, `${chatId}.jsonl`);
|
|
9673
9952
|
}
|
|
9674
9953
|
async appendSender(chatId, sender) {
|
|
9675
9954
|
try {
|
|
@@ -9680,7 +9959,7 @@ var ChatService = class {
|
|
|
9680
9959
|
}
|
|
9681
9960
|
async readSenders(chatId) {
|
|
9682
9961
|
try {
|
|
9683
|
-
const content = await
|
|
9962
|
+
const content = await readFile13(this.senderFilePath(chatId), "utf-8");
|
|
9684
9963
|
const lines = content.split("\n").filter((line) => line.trim().length > 0);
|
|
9685
9964
|
const senders = [];
|
|
9686
9965
|
for (const line of lines) {
|
|
@@ -9825,7 +10104,7 @@ var ChatService = class {
|
|
|
9825
10104
|
return descendants;
|
|
9826
10105
|
}
|
|
9827
10106
|
async deleteHistoryFile(persisted) {
|
|
9828
|
-
await rm(
|
|
10107
|
+
await rm(join17(HISTORY_DIR_BY_PROVIDER[persisted.provider], `${persisted.id}.jsonl`), { force: true });
|
|
9829
10108
|
await rm(this.senderFilePath(persisted.id), { force: true });
|
|
9830
10109
|
}
|
|
9831
10110
|
async getChatHistory(chatId) {
|
|
@@ -9896,7 +10175,7 @@ var ChatService = class {
|
|
|
9896
10175
|
if (persisted.provider === "claude") {
|
|
9897
10176
|
provider = new ClaudeManager({
|
|
9898
10177
|
workingDirectory: this.workingDirectory,
|
|
9899
|
-
historyFilePath:
|
|
10178
|
+
historyFilePath: join17(CLAUDE_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
9900
10179
|
initialSessionId: persisted.providerSessionId,
|
|
9901
10180
|
onSaveSessionId: saveSession,
|
|
9902
10181
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -9905,7 +10184,7 @@ var ChatService = class {
|
|
|
9905
10184
|
} else if (persisted.provider === "relay") {
|
|
9906
10185
|
provider = new RelayManager({
|
|
9907
10186
|
workingDirectory: this.workingDirectory,
|
|
9908
|
-
historyFilePath:
|
|
10187
|
+
historyFilePath: join17(RELAY_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
9909
10188
|
initialSessionId: persisted.providerSessionId,
|
|
9910
10189
|
onSaveSessionId: saveSession,
|
|
9911
10190
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -9916,7 +10195,7 @@ var ChatService = class {
|
|
|
9916
10195
|
} else {
|
|
9917
10196
|
provider = new CodexAspManager({
|
|
9918
10197
|
workingDirectory: this.workingDirectory,
|
|
9919
|
-
historyFilePath:
|
|
10198
|
+
historyFilePath: join17(CODEX_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
9920
10199
|
initialSessionId: persisted.providerSessionId,
|
|
9921
10200
|
onSaveSessionId: saveSession,
|
|
9922
10201
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -10054,7 +10333,7 @@ var ChatService = class {
|
|
|
10054
10333
|
});
|
|
10055
10334
|
uploadChatTranscript(
|
|
10056
10335
|
chatId,
|
|
10057
|
-
|
|
10336
|
+
join17(HISTORY_DIR_BY_PROVIDER[chat.persisted.provider], `${chatId}.jsonl`),
|
|
10058
10337
|
this.toSummary(chat)
|
|
10059
10338
|
).catch((err) => {
|
|
10060
10339
|
console.error("[ChatService] Failed to upload chat transcript:", { chatId, err });
|
|
@@ -10069,7 +10348,7 @@ var ChatService = class {
|
|
|
10069
10348
|
}
|
|
10070
10349
|
async loadChats() {
|
|
10071
10350
|
try {
|
|
10072
|
-
const content = await
|
|
10351
|
+
const content = await readFile13(CHATS_FILE, "utf-8");
|
|
10073
10352
|
return parsePersistedChatsContent(content);
|
|
10074
10353
|
} catch (error) {
|
|
10075
10354
|
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
@@ -10084,7 +10363,7 @@ var ChatService = class {
|
|
|
10084
10363
|
console.error("[ChatService] Failed to quarantine corrupt chats file:", renameError);
|
|
10085
10364
|
}
|
|
10086
10365
|
try {
|
|
10087
|
-
const backupContent = await
|
|
10366
|
+
const backupContent = await readFile13(CHATS_BACKUP_FILE, "utf-8");
|
|
10088
10367
|
return parsePersistedChatsContent(backupContent);
|
|
10089
10368
|
} catch (backupError) {
|
|
10090
10369
|
if (backupError && typeof backupError === "object" && "code" in backupError && backupError.code === "ENOENT") {
|
|
@@ -10169,8 +10448,8 @@ var ChatService = class {
|
|
|
10169
10448
|
|
|
10170
10449
|
// src/services/repo-file-service.ts
|
|
10171
10450
|
import { execFile as execFile2 } from "child_process";
|
|
10172
|
-
import { readFile as
|
|
10173
|
-
import { join as
|
|
10451
|
+
import { readFile as readFile14, realpath, stat as stat4 } from "fs/promises";
|
|
10452
|
+
import { join as join18, resolve as resolve2, extname } from "path";
|
|
10174
10453
|
var CACHE_TTL_MS = 3e4;
|
|
10175
10454
|
var SEARCH_TIMEOUT_MS = 15e3;
|
|
10176
10455
|
var MAX_CONTENT_BYTES = 256 * 1024;
|
|
@@ -10240,7 +10519,7 @@ function scoreMatch(query2, filePath) {
|
|
|
10240
10519
|
return 0;
|
|
10241
10520
|
}
|
|
10242
10521
|
function execGitAsync(args, cwd, timeoutMs) {
|
|
10243
|
-
return new Promise((
|
|
10522
|
+
return new Promise((resolve4, reject) => {
|
|
10244
10523
|
const child = execFile2("git", args, {
|
|
10245
10524
|
cwd,
|
|
10246
10525
|
encoding: "utf-8",
|
|
@@ -10250,7 +10529,7 @@ function execGitAsync(args, cwd, timeoutMs) {
|
|
|
10250
10529
|
if (error) {
|
|
10251
10530
|
reject(error);
|
|
10252
10531
|
} else {
|
|
10253
|
-
|
|
10532
|
+
resolve4(stdout);
|
|
10254
10533
|
}
|
|
10255
10534
|
});
|
|
10256
10535
|
child.stdin?.end();
|
|
@@ -10330,11 +10609,11 @@ var RepoFileService = class {
|
|
|
10330
10609
|
const repo = repos.find((r) => r.name === repoName);
|
|
10331
10610
|
if (!repo) return null;
|
|
10332
10611
|
try {
|
|
10333
|
-
const fullPath = await realpath(
|
|
10612
|
+
const fullPath = await realpath(resolve2(join18(repo.path, filePath)));
|
|
10334
10613
|
const repoRoot = await realpath(repo.path);
|
|
10335
10614
|
const repoPrefix = repoRoot.endsWith("/") ? repoRoot : repoRoot + "/";
|
|
10336
10615
|
if (!fullPath.startsWith(repoPrefix) && fullPath !== repoRoot) return null;
|
|
10337
|
-
const fileStat = await
|
|
10616
|
+
const fileStat = await stat4(fullPath);
|
|
10338
10617
|
if (!fileStat.isFile()) return null;
|
|
10339
10618
|
const sizeBytes = fileStat.size;
|
|
10340
10619
|
if (isBinaryExtension(filePath)) {
|
|
@@ -10359,7 +10638,7 @@ var RepoFileService = class {
|
|
|
10359
10638
|
tooLarge: true
|
|
10360
10639
|
};
|
|
10361
10640
|
}
|
|
10362
|
-
const content = await
|
|
10641
|
+
const content = await readFile14(fullPath, "utf-8");
|
|
10363
10642
|
return {
|
|
10364
10643
|
repoName,
|
|
10365
10644
|
path: filePath,
|
|
@@ -10437,21 +10716,21 @@ var RepoFileService = class {
|
|
|
10437
10716
|
// src/v1-routes.ts
|
|
10438
10717
|
import { Hono } from "hono";
|
|
10439
10718
|
import { z as z2 } from "zod";
|
|
10440
|
-
import { readdir as
|
|
10441
|
-
import { join as
|
|
10719
|
+
import { readdir as readdir7, stat as stat5, readFile as readFile17 } from "fs/promises";
|
|
10720
|
+
import { join as join21, resolve as resolve3 } from "path";
|
|
10442
10721
|
|
|
10443
10722
|
// src/services/warm-hooks-service.ts
|
|
10444
10723
|
import { spawn as spawn4 } from "child_process";
|
|
10445
|
-
import { readFile as
|
|
10724
|
+
import { readFile as readFile16 } from "fs/promises";
|
|
10446
10725
|
import { existsSync as existsSync8 } from "fs";
|
|
10447
|
-
import { join as
|
|
10726
|
+
import { join as join20 } from "path";
|
|
10448
10727
|
|
|
10449
10728
|
// src/services/warm-hook-logs-service.ts
|
|
10450
|
-
import { mkdir as mkdir12, readFile as
|
|
10729
|
+
import { mkdir as mkdir12, readFile as readFile15, writeFile as writeFile6, readdir as readdir6, appendFile as appendFile5, unlink as unlink3 } from "fs/promises";
|
|
10451
10730
|
import { homedir as homedir15 } from "os";
|
|
10452
|
-
import { join as
|
|
10453
|
-
var LOGS_DIR2 =
|
|
10454
|
-
var CURRENT_RUN_LOG =
|
|
10731
|
+
import { join as join19 } from "path";
|
|
10732
|
+
var LOGS_DIR2 = join19(homedir15(), ".replicas", "warm-hook-logs");
|
|
10733
|
+
var CURRENT_RUN_LOG = join19(LOGS_DIR2, "current-run.log");
|
|
10455
10734
|
var GLOBAL_FILENAME = "global.json";
|
|
10456
10735
|
function withPreview2(stored) {
|
|
10457
10736
|
const preview = buildHookOutputPreview(stored.output);
|
|
@@ -10468,7 +10747,7 @@ var WarmHookLogsService = class {
|
|
|
10468
10747
|
hookName: "organization",
|
|
10469
10748
|
...entry
|
|
10470
10749
|
};
|
|
10471
|
-
await writeFile6(
|
|
10750
|
+
await writeFile6(join19(LOGS_DIR2, GLOBAL_FILENAME), `${JSON.stringify(log, null, 2)}
|
|
10472
10751
|
`, "utf-8");
|
|
10473
10752
|
}
|
|
10474
10753
|
async saveEnvironmentHookLog(entry) {
|
|
@@ -10478,7 +10757,7 @@ var WarmHookLogsService = class {
|
|
|
10478
10757
|
hookName: "environment",
|
|
10479
10758
|
...entry
|
|
10480
10759
|
};
|
|
10481
|
-
await writeFile6(
|
|
10760
|
+
await writeFile6(join19(LOGS_DIR2, ENVIRONMENT_HOOK_LOG_FILENAME), `${JSON.stringify(log, null, 2)}
|
|
10482
10761
|
`, "utf-8");
|
|
10483
10762
|
}
|
|
10484
10763
|
async saveRepoHookLog(repoName, entry) {
|
|
@@ -10488,13 +10767,13 @@ var WarmHookLogsService = class {
|
|
|
10488
10767
|
hookName: repoName,
|
|
10489
10768
|
...entry
|
|
10490
10769
|
};
|
|
10491
|
-
await writeFile6(
|
|
10770
|
+
await writeFile6(join19(LOGS_DIR2, repoHookLogFilename(repoName)), `${JSON.stringify(log, null, 2)}
|
|
10492
10771
|
`, "utf-8");
|
|
10493
10772
|
}
|
|
10494
10773
|
async getAllLogs() {
|
|
10495
10774
|
let files;
|
|
10496
10775
|
try {
|
|
10497
|
-
files = await
|
|
10776
|
+
files = await readdir6(LOGS_DIR2);
|
|
10498
10777
|
} catch (err) {
|
|
10499
10778
|
if (err.code === "ENOENT") {
|
|
10500
10779
|
return [];
|
|
@@ -10507,7 +10786,7 @@ var WarmHookLogsService = class {
|
|
|
10507
10786
|
continue;
|
|
10508
10787
|
}
|
|
10509
10788
|
try {
|
|
10510
|
-
const raw = await
|
|
10789
|
+
const raw = await readFile15(join19(LOGS_DIR2, file), "utf-8");
|
|
10511
10790
|
const stored = JSON.parse(raw);
|
|
10512
10791
|
logs.push(withPreview2(stored));
|
|
10513
10792
|
} catch {
|
|
@@ -10536,7 +10815,7 @@ var WarmHookLogsService = class {
|
|
|
10536
10815
|
}
|
|
10537
10816
|
async getCurrentRunLog() {
|
|
10538
10817
|
try {
|
|
10539
|
-
return await
|
|
10818
|
+
return await readFile15(CURRENT_RUN_LOG, "utf-8");
|
|
10540
10819
|
} catch (err) {
|
|
10541
10820
|
if (err.code === "ENOENT") return null;
|
|
10542
10821
|
throw err;
|
|
@@ -10545,7 +10824,7 @@ var WarmHookLogsService = class {
|
|
|
10545
10824
|
async getFullOutput(hookType, hookName) {
|
|
10546
10825
|
const filename = hookType === "global" ? GLOBAL_FILENAME : hookType === "environment" ? ENVIRONMENT_HOOK_LOG_FILENAME : repoHookLogFilename(hookName);
|
|
10547
10826
|
try {
|
|
10548
|
-
const raw = await
|
|
10827
|
+
const raw = await readFile15(join19(LOGS_DIR2, filename), "utf-8");
|
|
10549
10828
|
const stored = JSON.parse(raw);
|
|
10550
10829
|
if (stored.hookType !== hookType || stored.hookName !== hookName) {
|
|
10551
10830
|
return null;
|
|
@@ -10564,12 +10843,12 @@ var warmHookLogsService = new WarmHookLogsService();
|
|
|
10564
10843
|
// src/services/warm-hooks-service.ts
|
|
10565
10844
|
async function readRepoWarmHook(repoPath) {
|
|
10566
10845
|
for (const filename of REPLICAS_CONFIG_FILENAMES) {
|
|
10567
|
-
const configPath =
|
|
10846
|
+
const configPath = join20(repoPath, filename);
|
|
10568
10847
|
if (!existsSync8(configPath)) {
|
|
10569
10848
|
continue;
|
|
10570
10849
|
}
|
|
10571
10850
|
try {
|
|
10572
|
-
const raw = await
|
|
10851
|
+
const raw = await readFile16(configPath, "utf-8");
|
|
10573
10852
|
const config = parseReplicasConfigString(raw, filename);
|
|
10574
10853
|
if (!config.warmHook) {
|
|
10575
10854
|
return null;
|
|
@@ -10615,7 +10894,7 @@ async function executeHookScriptStreaming(params) {
|
|
|
10615
10894
|
let bufferExceeded = false;
|
|
10616
10895
|
params.onChunk(`$ ${params.label}
|
|
10617
10896
|
`);
|
|
10618
|
-
return new Promise((
|
|
10897
|
+
return new Promise((resolve4) => {
|
|
10619
10898
|
const proc = spawn4("bash", ["-lc", params.content], {
|
|
10620
10899
|
cwd: params.cwd,
|
|
10621
10900
|
env: process.env,
|
|
@@ -10648,7 +10927,7 @@ async function executeHookScriptStreaming(params) {
|
|
|
10648
10927
|
proc.on("close", (code) => {
|
|
10649
10928
|
clearTimeout(timer);
|
|
10650
10929
|
const output = [`$ ${params.label}`, ...outputParts].join("");
|
|
10651
|
-
|
|
10930
|
+
resolve4({
|
|
10652
10931
|
exitCode: bufferExceeded ? 1 : code ?? 1,
|
|
10653
10932
|
output,
|
|
10654
10933
|
timedOut: killed && !bufferExceeded
|
|
@@ -10658,7 +10937,7 @@ async function executeHookScriptStreaming(params) {
|
|
|
10658
10937
|
clearTimeout(timer);
|
|
10659
10938
|
const output = [`$ ${params.label}
|
|
10660
10939
|
`, ...outputParts, err.message].join("");
|
|
10661
|
-
|
|
10940
|
+
resolve4({
|
|
10662
10941
|
exitCode: 1,
|
|
10663
10942
|
output,
|
|
10664
10943
|
timedOut: false
|
|
@@ -11514,12 +11793,12 @@ function createV1Routes(deps) {
|
|
|
11514
11793
|
});
|
|
11515
11794
|
app2.get("/logs", async (c) => {
|
|
11516
11795
|
try {
|
|
11517
|
-
const files = await
|
|
11796
|
+
const files = await readdir7(LOG_DIR).catch(() => []);
|
|
11518
11797
|
const logFiles = files.filter((f) => f.endsWith(".log"));
|
|
11519
11798
|
const sessions = await Promise.all(
|
|
11520
11799
|
logFiles.map(async (filename) => {
|
|
11521
|
-
const filePath =
|
|
11522
|
-
const fileStat = await
|
|
11800
|
+
const filePath = join21(LOG_DIR, filename);
|
|
11801
|
+
const fileStat = await stat5(filePath);
|
|
11523
11802
|
const sessionId = filename.replace(/\.log$/, "");
|
|
11524
11803
|
return {
|
|
11525
11804
|
sessionId,
|
|
@@ -11547,15 +11826,15 @@ function createV1Routes(deps) {
|
|
|
11547
11826
|
if (!sessionId || /[/\\]/.test(sessionId) || sessionId.includes("..")) {
|
|
11548
11827
|
return c.json(jsonError("Invalid session ID"), 400);
|
|
11549
11828
|
}
|
|
11550
|
-
const filePath =
|
|
11551
|
-
if (!filePath.startsWith(
|
|
11829
|
+
const filePath = resolve3(LOG_DIR, `${sessionId}.log`);
|
|
11830
|
+
if (!filePath.startsWith(resolve3(LOG_DIR))) {
|
|
11552
11831
|
return c.json(jsonError("Invalid session ID"), 400);
|
|
11553
11832
|
}
|
|
11554
11833
|
const offset = parseInt(c.req.query("offset") || "0", 10);
|
|
11555
11834
|
const limit = Math.min(parseInt(c.req.query("limit") || "500", 10), 5e3);
|
|
11556
11835
|
let content;
|
|
11557
11836
|
try {
|
|
11558
|
-
content = await
|
|
11837
|
+
content = await readFile17(filePath, "utf-8");
|
|
11559
11838
|
} catch {
|
|
11560
11839
|
return c.json(jsonError("Log session not found"), 404);
|
|
11561
11840
|
}
|