replicas-engine 0.1.400 → 0.1.403
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 +327 -135
- package/package.json +1 -1
package/dist/src/index.js
CHANGED
|
@@ -484,7 +484,7 @@ var WORKSPACE_SIZES = ["small", "large"];
|
|
|
484
484
|
var INVALID_WORKSPACE_SIZE_ERROR = `Invalid size: must be one of ${WORKSPACE_SIZES.join(", ")}`;
|
|
485
485
|
|
|
486
486
|
// ../shared/src/e2b.ts
|
|
487
|
-
var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-06-
|
|
487
|
+
var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-06-v5";
|
|
488
488
|
|
|
489
489
|
// ../shared/src/runtime-env.ts
|
|
490
490
|
function parsePosixEnvFile(content) {
|
|
@@ -647,8 +647,8 @@ var SLASH_COMMANDS = [
|
|
|
647
647
|
},
|
|
648
648
|
{
|
|
649
649
|
command: "/goal",
|
|
650
|
-
description: "Set or clear a task goal.",
|
|
651
|
-
argumentHint: "<objective | clear>",
|
|
650
|
+
description: "Set, pause, resume, or clear a task goal.",
|
|
651
|
+
argumentHint: "<objective | pause | resume | clear>",
|
|
652
652
|
providers: ["codex"]
|
|
653
653
|
}
|
|
654
654
|
];
|
|
@@ -667,19 +667,23 @@ function getSlashCommandsForProvider(provider, commands = SLASH_COMMANDS) {
|
|
|
667
667
|
return commands.filter((command) => command.providers.includes(provider));
|
|
668
668
|
}
|
|
669
669
|
var MAX_CODEX_GOAL_OBJECTIVE_CHARS = 4e3;
|
|
670
|
+
function classifyGoalValue(value) {
|
|
671
|
+
if (/^(clear|reset|unset)$/i.test(value)) return { type: "clear" };
|
|
672
|
+
if (/^pause$/i.test(value)) return { type: "pause" };
|
|
673
|
+
if (/^resume$/i.test(value)) return { type: "resume" };
|
|
674
|
+
return { type: "set", objective: value };
|
|
675
|
+
}
|
|
670
676
|
function parseGoalCommand(message) {
|
|
671
677
|
const match = message.trim().match(/^\/goal(?:\s+([\s\S]*))?$/i);
|
|
672
678
|
const value = match?.[1]?.trim();
|
|
673
679
|
if (!value) return null;
|
|
674
|
-
|
|
675
|
-
return { type: "set", objective: value };
|
|
680
|
+
return classifyGoalValue(value);
|
|
676
681
|
}
|
|
677
682
|
function getGoalCommand(message, goalMode) {
|
|
678
683
|
if (!goalMode) return parseGoalCommand(message);
|
|
679
684
|
const value = message.trim();
|
|
680
685
|
if (!value) return null;
|
|
681
|
-
|
|
682
|
-
return { type: "set", objective: value };
|
|
686
|
+
return classifyGoalValue(value);
|
|
683
687
|
}
|
|
684
688
|
function getGoalCommandObjectiveValidationError(message, goalMode) {
|
|
685
689
|
const command = getGoalCommand(message, goalMode);
|
|
@@ -1415,8 +1419,67 @@ var GOOGLE_ABILITY = {
|
|
|
1415
1419
|
referenceFile: { name: "GOOGLE.md", content: REFERENCE5 }
|
|
1416
1420
|
};
|
|
1417
1421
|
|
|
1422
|
+
// ../shared/src/default-skills/replicas-agent/abilities/learnings.ts
|
|
1423
|
+
var SECTION6 = `### Learnings
|
|
1424
|
+
Curated, human-approved organization knowledge that helps you execute correctly \u2014 conventions, gotchas, environment facts, and past user corrections that the codebase alone can't tell you.
|
|
1425
|
+
|
|
1426
|
+
**Reference:** \`references/LEARNINGS.md\`
|
|
1427
|
+
|
|
1428
|
+
Use this when:
|
|
1429
|
+
- You are starting a substantive task and have gathered enough context to write a meaningful query
|
|
1430
|
+
- A user corrects you about a durable fact, preference, or process worth keeping
|
|
1431
|
+
- You find an existing learning contradicted by the current code or docs`;
|
|
1432
|
+
var REFERENCE6 = `# Learnings
|
|
1433
|
+
|
|
1434
|
+
Learnings are curated, human-approved knowledge entries your organization maintains: conventions, gotchas, environment facts, and process rules. Some entries always apply; contextual entries are retrieved by matching your query against their trigger descriptions.
|
|
1435
|
+
|
|
1436
|
+
## Reading Learnings
|
|
1437
|
+
|
|
1438
|
+
\`\`\`bash
|
|
1439
|
+
replicas learnings read --query "<enriched query>"
|
|
1440
|
+
\`\`\`
|
|
1441
|
+
|
|
1442
|
+
**When to read:** once you've collected enough context to write a meaningful query \u2014 typically after your first look at the relevant code. Don't wait until you're deep into execution; learnings are most valuable before you commit to an approach.
|
|
1443
|
+
|
|
1444
|
+
**Enrich the query.** Use codebase specifics (feature area, module/component names), not the raw user request. Triggers describe *situations*, so a query grounded in what the task actually touches matches far better.
|
|
1445
|
+
|
|
1446
|
+
Example: the user asks "remove the PRs chart projections". After locating the chart you know it lives in the platform admin dashboard, so query:
|
|
1447
|
+
|
|
1448
|
+
\`\`\`bash
|
|
1449
|
+
replicas learnings read --query "Remove the PRs chart in the platform admin dashboard"
|
|
1450
|
+
\`\`\`
|
|
1451
|
+
|
|
1452
|
+
This matches a learning triggered on "UI/UX work on the admin panel" that the raw request would have missed.
|
|
1453
|
+
|
|
1454
|
+
Output is a list of blocks \u2014 id, name, and content. Use the ids to propose updates or deletions.
|
|
1455
|
+
|
|
1456
|
+
## Proposing changes
|
|
1457
|
+
|
|
1458
|
+
All writes are proposals: a human reviews them in the dashboard, and nothing takes effect until approved.
|
|
1459
|
+
|
|
1460
|
+
\`\`\`bash
|
|
1461
|
+
replicas learnings add --name "<short name>" --content "<the knowledge>" [--trigger "<when to surface it>"] [--always] [--global]
|
|
1462
|
+
replicas learnings update <id> [--name "..."] [--content "..."] [--trigger "..."] [--always true|false]
|
|
1463
|
+
replicas learnings delete <id>
|
|
1464
|
+
\`\`\`
|
|
1465
|
+
|
|
1466
|
+
\`--always\` marks an entry as always-returned (no trigger needed); \`--global\` proposes org-wide scope instead of this workspace's environment.
|
|
1467
|
+
|
|
1468
|
+
**Be very conservative:**
|
|
1469
|
+
- Propose \`add\` only for durable, org-useful facts: explicit user corrections, hard-won environment or process knowledge.
|
|
1470
|
+
- Never store task-specific details, anything derivable by reading the repo, or secrets/credentials.
|
|
1471
|
+
- Propose \`update\` or \`delete\` when a learning is contradicted by the current code or docs \u2014 flag outdated knowledge instead of silently ignoring it.
|
|
1472
|
+
- Write narrow triggers describing when the entry should surface (e.g. "UI/UX work on the admin panel"), not vague topics.`;
|
|
1473
|
+
var LEARNINGS_ABILITY = {
|
|
1474
|
+
label: "Learnings",
|
|
1475
|
+
description: "Fetch curated org knowledge and propose new learnings for human review.",
|
|
1476
|
+
bullet: "- Fetching organization Learnings (curated, human-approved knowledge) before executing, or proposing new ones",
|
|
1477
|
+
section: SECTION6,
|
|
1478
|
+
referenceFile: { name: "LEARNINGS.md", content: REFERENCE6 }
|
|
1479
|
+
};
|
|
1480
|
+
|
|
1418
1481
|
// ../shared/src/default-skills/replicas-agent/abilities/linear.ts
|
|
1419
|
-
var
|
|
1482
|
+
var SECTION7 = `### Linear
|
|
1420
1483
|
Fetch issues, update state, add comments, and search via the Linear GraphQL API.
|
|
1421
1484
|
|
|
1422
1485
|
**Reference:** \`references/LINEAR.md\`
|
|
@@ -1425,7 +1488,7 @@ Use this when:
|
|
|
1425
1488
|
- You encounter a Linear issue link and need to understand the task
|
|
1426
1489
|
- You need to update an issue's state (e.g. mark as done)
|
|
1427
1490
|
- You need to comment on or search for Linear issues`;
|
|
1428
|
-
var
|
|
1491
|
+
var REFERENCE7 = `# Linear Integration
|
|
1429
1492
|
|
|
1430
1493
|
This guide covers how to interact with Linear from within your Replicas workspace.
|
|
1431
1494
|
|
|
@@ -1514,12 +1577,12 @@ var LINEAR_ABILITY = {
|
|
|
1514
1577
|
label: "Linear",
|
|
1515
1578
|
description: "Fetch issues, post comments, update states via the Linear GraphQL API.",
|
|
1516
1579
|
bullet: "- Interacting with Linear (fetching issues, updating state, commenting, etc.)",
|
|
1517
|
-
section:
|
|
1518
|
-
referenceFile: { name: "LINEAR.md", content:
|
|
1580
|
+
section: SECTION7,
|
|
1581
|
+
referenceFile: { name: "LINEAR.md", content: REFERENCE7 }
|
|
1519
1582
|
};
|
|
1520
1583
|
|
|
1521
1584
|
// ../shared/src/default-skills/replicas-agent/abilities/media.ts
|
|
1522
|
-
var
|
|
1585
|
+
var SECTION8 = `### Media
|
|
1523
1586
|
Share screenshots, screen recordings, generated diagrams, and audio clips inline in the Replicas chat and natively embedded in external messages.
|
|
1524
1587
|
|
|
1525
1588
|
**Reference:** \`references/MEDIA.md\`
|
|
@@ -1528,7 +1591,7 @@ Use this when:
|
|
|
1528
1591
|
- You produce a screenshot, recording, generated image, or audio clip the user should see
|
|
1529
1592
|
- You record video output (browser automation, screen capture) \u2014 including the recommended aspect ratio and FPS
|
|
1530
1593
|
- You need to embed media in a Slack/Linear/GitHub message AND keep a referenceable copy in the Replicas dashboard`;
|
|
1531
|
-
var
|
|
1594
|
+
var REFERENCE8 = `# Media (Screenshots, Recordings, Audio)
|
|
1532
1595
|
|
|
1533
1596
|
This guide covers how to share screenshots, screen recordings, generated diagrams, and audio clips \u2014 both inline in the Replicas chat and natively embedded in external surfaces (Slack, Linear, GitHub).
|
|
1534
1597
|
|
|
@@ -1780,12 +1843,12 @@ var MEDIA_ABILITY = {
|
|
|
1780
1843
|
label: "Media",
|
|
1781
1844
|
description: "Share screenshots, recordings, generated images, and audio clips.",
|
|
1782
1845
|
bullet: "- Producing or showing the user any media \u2014 screenshots, screen recordings, generated images or diagrams, audio clips \u2014 including in your Replicas chat reply, PR descriptions/comments, and other external platforms",
|
|
1783
|
-
section:
|
|
1784
|
-
referenceFile: { name: "MEDIA.md", content:
|
|
1846
|
+
section: SECTION8,
|
|
1847
|
+
referenceFile: { name: "MEDIA.md", content: REFERENCE8 }
|
|
1785
1848
|
};
|
|
1786
1849
|
|
|
1787
1850
|
// ../shared/src/default-skills/replicas-agent/abilities/previews.ts
|
|
1788
|
-
var
|
|
1851
|
+
var SECTION9 = `### Previews
|
|
1789
1852
|
Expose locally running services (web apps, APIs, databases) as public preview URLs so humans can interact with them directly.
|
|
1790
1853
|
|
|
1791
1854
|
**Reference:** \`references/PREVIEWS.md\`
|
|
@@ -1794,7 +1857,7 @@ Use this when:
|
|
|
1794
1857
|
- You need to start a service that a human should view or interact with
|
|
1795
1858
|
- The task involves UI work that benefits from human review
|
|
1796
1859
|
- You are verifying frontend/backend integrations visually`;
|
|
1797
|
-
var
|
|
1860
|
+
var REFERENCE9 = `# Preview URLs
|
|
1798
1861
|
|
|
1799
1862
|
When you run services on ports \u2014 such as a web app, API server, or database \u2014 humans may want to interact with them directly. You can expose your locally running services as public preview URLs.
|
|
1800
1863
|
|
|
@@ -1876,12 +1939,12 @@ var PREVIEWS_ABILITY = {
|
|
|
1876
1939
|
label: "Previews",
|
|
1877
1940
|
description: "Expose locally running services on public preview URLs for humans.",
|
|
1878
1941
|
bullet: "- Creating preview URLs for locally running services",
|
|
1879
|
-
section:
|
|
1880
|
-
referenceFile: { name: "PREVIEWS.md", content:
|
|
1942
|
+
section: SECTION9,
|
|
1943
|
+
referenceFile: { name: "PREVIEWS.md", content: REFERENCE9 }
|
|
1881
1944
|
};
|
|
1882
1945
|
|
|
1883
1946
|
// ../shared/src/default-skills/replicas-agent/abilities/replicas.ts
|
|
1884
|
-
var
|
|
1947
|
+
var SECTION10 = `### Replicas (in-workspace CLI)
|
|
1885
1948
|
Take action *with* Replicas itself \u2014 manage automations, environments (variables, files), repos, and \`replicas.json\` config \u2014 using the pre-installed, pre-authenticated \`replicas\` CLI.
|
|
1886
1949
|
|
|
1887
1950
|
**Reference:** \`references/REPLICAS.md\`
|
|
@@ -1891,7 +1954,7 @@ Use this when:
|
|
|
1891
1954
|
- The user asks you to manage environments, environment variables, or environment files
|
|
1892
1955
|
- The user asks "what envs / repos / automations do I have?"
|
|
1893
1956
|
- The user asks you to scaffold a \`replicas.json\` / \`replicas.yaml\` in a repo`;
|
|
1894
|
-
var
|
|
1957
|
+
var REFERENCE10 = `# Replicas (in-workspace CLI)
|
|
1895
1958
|
|
|
1896
1959
|
This guide covers how to take action *with* Replicas itself from inside a Replicas workspace \u2014 managing automations, environments (and their variables/files), repos, previews, and the user's \`replicas.json\` config \u2014 using the pre-installed \`replicas\` CLI.
|
|
1897
1960
|
|
|
@@ -2093,13 +2156,13 @@ var REPLICAS_ABILITY = {
|
|
|
2093
2156
|
description: "Teach the agent about Replicas itself \u2014 automations, environments, the in-workspace CLI.",
|
|
2094
2157
|
// No bullet — help_instructions covers the `replicas` CLI surface in detail.
|
|
2095
2158
|
bullet: "",
|
|
2096
|
-
section:
|
|
2097
|
-
referenceFile: { name: "REPLICAS.md", content:
|
|
2159
|
+
section: SECTION10,
|
|
2160
|
+
referenceFile: { name: "REPLICAS.md", content: REFERENCE10 },
|
|
2098
2161
|
locked: true
|
|
2099
2162
|
};
|
|
2100
2163
|
|
|
2101
2164
|
// ../shared/src/default-skills/replicas-agent/abilities/slack.ts
|
|
2102
|
-
var
|
|
2165
|
+
var SECTION11 = `### Slack
|
|
2103
2166
|
Send messages, read threads, search conversations, and upload files via the Slack Web API.
|
|
2104
2167
|
|
|
2105
2168
|
**Reference:** \`references/SLACK.md\`
|
|
@@ -2109,7 +2172,7 @@ Use this when:
|
|
|
2109
2172
|
- You need to read or fetch a Slack conversation
|
|
2110
2173
|
- You encounter a Slack message link and need to retrieve its content
|
|
2111
2174
|
- The task asks you to notify, update, or communicate via Slack`;
|
|
2112
|
-
var
|
|
2175
|
+
var REFERENCE11 = `# Slack Integration
|
|
2113
2176
|
|
|
2114
2177
|
This guide covers how to interact with Slack from within your Replicas workspace.
|
|
2115
2178
|
|
|
@@ -2210,8 +2273,8 @@ var SLACK_ABILITY = {
|
|
|
2210
2273
|
label: "Slack",
|
|
2211
2274
|
description: "Send messages, read threads, search conversations, upload files.",
|
|
2212
2275
|
bullet: "- Interacting with Slack (sending messages, reading threads, etc.)",
|
|
2213
|
-
section:
|
|
2214
|
-
referenceFile: { name: "SLACK.md", content:
|
|
2276
|
+
section: SECTION11,
|
|
2277
|
+
referenceFile: { name: "SLACK.md", content: REFERENCE11 }
|
|
2215
2278
|
};
|
|
2216
2279
|
|
|
2217
2280
|
// ../shared/src/default-skills/replicas-agent/registry.ts
|
|
@@ -2222,6 +2285,7 @@ var REPLICAS_AGENT_ABILITY_REGISTRY = {
|
|
|
2222
2285
|
github: GITHUB_ABILITY,
|
|
2223
2286
|
gitlab: GITLAB_ABILITY,
|
|
2224
2287
|
google: GOOGLE_ABILITY,
|
|
2288
|
+
learnings: LEARNINGS_ABILITY,
|
|
2225
2289
|
linear: LINEAR_ABILITY,
|
|
2226
2290
|
media: MEDIA_ABILITY,
|
|
2227
2291
|
previews: PREVIEWS_ABILITY,
|
|
@@ -2970,6 +3034,7 @@ function parseAgentEventJsonl(content, options = {}) {
|
|
|
2970
3034
|
function parseAgentEventJsonlWithCodexAspTranscript(content, options = {}) {
|
|
2971
3035
|
const events = [];
|
|
2972
3036
|
let transcript = null;
|
|
3037
|
+
const transcriptsByThreadId = /* @__PURE__ */ new Map();
|
|
2973
3038
|
for (const event of parseAgentEventJsonl(content, options)) {
|
|
2974
3039
|
if (event.type !== CODEX_ASP_TRANSCRIPT_UPDATED_EVENT_TYPE) {
|
|
2975
3040
|
events.push(event);
|
|
@@ -2977,12 +3042,16 @@ function parseAgentEventJsonlWithCodexAspTranscript(content, options = {}) {
|
|
|
2977
3042
|
}
|
|
2978
3043
|
const delta = event.payload.transcriptDelta;
|
|
2979
3044
|
if (isCodexAspTranscriptDelta(delta)) {
|
|
2980
|
-
|
|
3045
|
+
const previous = transcriptsByThreadId.get(delta.threadId) ?? null;
|
|
3046
|
+
transcript = applyCodexAspTranscriptDelta(previous, delta);
|
|
2981
3047
|
} else if (isCodexAspTranscript(event.payload.transcript)) {
|
|
2982
3048
|
transcript = event.payload.transcript;
|
|
2983
3049
|
}
|
|
3050
|
+
if (transcript) {
|
|
3051
|
+
transcriptsByThreadId.set(transcript.threadId, transcript);
|
|
3052
|
+
}
|
|
2984
3053
|
}
|
|
2985
|
-
return { events, transcript };
|
|
3054
|
+
return { events, transcript, transcriptsByThreadId };
|
|
2986
3055
|
}
|
|
2987
3056
|
|
|
2988
3057
|
// ../shared/src/display-message/parsers/codex-asp-parser.ts
|
|
@@ -4681,6 +4750,7 @@ var EnvironmentDetailsService = class {
|
|
|
4681
4750
|
]);
|
|
4682
4751
|
details.engineVersion = E2B_TEMPLATE_NAME;
|
|
4683
4752
|
details.supportsMidTurnSteering = true;
|
|
4753
|
+
details.supportsGoalUpdates = true;
|
|
4684
4754
|
details.claudeAuthMethod = detectClaudeAuthMethod();
|
|
4685
4755
|
details.codexAuthMethod = detectCodexAuthMethod();
|
|
4686
4756
|
details.cursorAuthMethod = detectCursorAuthMethod();
|
|
@@ -5436,8 +5506,8 @@ async function registerDesktopPreview() {
|
|
|
5436
5506
|
// src/services/chat/chat-service.ts
|
|
5437
5507
|
import { existsSync as existsSync7 } from "fs";
|
|
5438
5508
|
import { appendFile as appendFile3, copyFile, mkdir as mkdir13, readFile as readFile14, rename as rename2, rm } from "fs/promises";
|
|
5439
|
-
import { homedir as
|
|
5440
|
-
import { join as
|
|
5509
|
+
import { homedir as homedir15 } from "os";
|
|
5510
|
+
import { join as join21 } from "path";
|
|
5441
5511
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
5442
5512
|
|
|
5443
5513
|
// src/managers/claude-manager.ts
|
|
@@ -6639,7 +6709,7 @@ var CodexHistoryFile = class {
|
|
|
6639
6709
|
if (!(error && typeof error === "object" && "code" in error && error.code === "ENOENT")) {
|
|
6640
6710
|
console.error("[CodexHistoryFile] Failed to load history file:", error);
|
|
6641
6711
|
}
|
|
6642
|
-
return { events: [], transcript: null };
|
|
6712
|
+
return { events: [], transcript: null, transcriptsByThreadId: /* @__PURE__ */ new Map() };
|
|
6643
6713
|
}
|
|
6644
6714
|
}
|
|
6645
6715
|
};
|
|
@@ -7744,6 +7814,10 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
7744
7814
|
}
|
|
7745
7815
|
};
|
|
7746
7816
|
|
|
7817
|
+
// src/managers/codex-asp/codex-asp-manager.ts
|
|
7818
|
+
import { readdir as readdir4 } from "fs/promises";
|
|
7819
|
+
import { join as join16 } from "path";
|
|
7820
|
+
|
|
7747
7821
|
// src/managers/codex-asp/app-server-process.ts
|
|
7748
7822
|
import { spawn as spawn3 } from "child_process";
|
|
7749
7823
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
@@ -7940,7 +8014,7 @@ var AspClient = class {
|
|
|
7940
8014
|
// src/managers/codex-asp/app-server-process.ts
|
|
7941
8015
|
var DEFAULT_CODEX_BINARY = "codex";
|
|
7942
8016
|
var DEFAULT_CODEX_ARGS = ["app-server", "--listen", "stdio://"];
|
|
7943
|
-
var ENGINE_PACKAGE_VERSION = "0.1.
|
|
8017
|
+
var ENGINE_PACKAGE_VERSION = "0.1.403";
|
|
7944
8018
|
var INITIALIZE_METHOD = "initialize";
|
|
7945
8019
|
var INITIALIZED_NOTIFICATION = "initialized";
|
|
7946
8020
|
var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
|
|
@@ -8374,6 +8448,7 @@ function itemToTranscriptItem(item, timestamp, status) {
|
|
|
8374
8448
|
description: item.receiverThreadIds.length === 1 ? "Codex subagent" : `Codex subagents (${item.receiverThreadIds.length})`,
|
|
8375
8449
|
prompt: item.prompt ?? "",
|
|
8376
8450
|
subagentType: "codex",
|
|
8451
|
+
receiverThreadIds: item.receiverThreadIds,
|
|
8377
8452
|
...item.model ? { model: item.model } : {},
|
|
8378
8453
|
output: stringifyCollabAgentStates(item.agentsStates),
|
|
8379
8454
|
timestamp,
|
|
@@ -8772,9 +8847,84 @@ var TranscriptUpdateCoalescer = class {
|
|
|
8772
8847
|
}
|
|
8773
8848
|
};
|
|
8774
8849
|
|
|
8850
|
+
// src/services/chat/history-paths.ts
|
|
8851
|
+
import { homedir as homedir12 } from "os";
|
|
8852
|
+
import { join as join15 } from "path";
|
|
8853
|
+
var ENGINE_DIR2 = join15(homedir12(), ".replicas", "engine");
|
|
8854
|
+
var CHATS_FILE = join15(ENGINE_DIR2, "chats.json");
|
|
8855
|
+
var CLAUDE_HISTORY_DIR = join15(ENGINE_DIR2, "claude-histories");
|
|
8856
|
+
var RELAY_HISTORY_DIR = join15(ENGINE_DIR2, "relay-histories");
|
|
8857
|
+
var CODEX_HISTORY_DIR = join15(ENGINE_DIR2, "codex-histories");
|
|
8858
|
+
var CURSOR_HISTORY_DIR = join15(ENGINE_DIR2, "cursor-histories");
|
|
8859
|
+
var OPENCODE_HISTORY_DIR = join15(ENGINE_DIR2, "opencode-histories");
|
|
8860
|
+
var HISTORY_DIR_BY_PROVIDER = {
|
|
8861
|
+
claude: CLAUDE_HISTORY_DIR,
|
|
8862
|
+
relay: RELAY_HISTORY_DIR,
|
|
8863
|
+
codex: CODEX_HISTORY_DIR,
|
|
8864
|
+
cursor: CURSOR_HISTORY_DIR,
|
|
8865
|
+
opencode: OPENCODE_HISTORY_DIR
|
|
8866
|
+
};
|
|
8867
|
+
|
|
8868
|
+
// src/services/chat/errors.ts
|
|
8869
|
+
var ChatNotFoundError = class extends Error {
|
|
8870
|
+
constructor(chatId) {
|
|
8871
|
+
super(`Chat not found: ${chatId}`);
|
|
8872
|
+
this.name = "ChatNotFoundError";
|
|
8873
|
+
}
|
|
8874
|
+
};
|
|
8875
|
+
var CodexThreadNotFoundError = class extends Error {
|
|
8876
|
+
constructor(threadId) {
|
|
8877
|
+
super(`Codex thread history not found: ${threadId}`);
|
|
8878
|
+
this.name = "CodexThreadNotFoundError";
|
|
8879
|
+
}
|
|
8880
|
+
};
|
|
8881
|
+
var DefaultChatDeletionError = class extends Error {
|
|
8882
|
+
constructor() {
|
|
8883
|
+
super("Default chats cannot be deleted");
|
|
8884
|
+
this.name = "DefaultChatDeletionError";
|
|
8885
|
+
}
|
|
8886
|
+
};
|
|
8887
|
+
var ChatProcessingDeletionError = class extends Error {
|
|
8888
|
+
constructor() {
|
|
8889
|
+
super("Cannot delete a chat while it is processing");
|
|
8890
|
+
this.name = "ChatProcessingDeletionError";
|
|
8891
|
+
}
|
|
8892
|
+
};
|
|
8893
|
+
var DuplicateDefaultChatError = class extends Error {
|
|
8894
|
+
constructor(provider) {
|
|
8895
|
+
super(`Default chat already exists for provider: ${provider}`);
|
|
8896
|
+
this.name = "DuplicateDefaultChatError";
|
|
8897
|
+
}
|
|
8898
|
+
};
|
|
8899
|
+
|
|
8775
8900
|
// src/managers/codex-asp/codex-asp-manager.ts
|
|
8776
8901
|
var GOAL_TURN_CONTINUATION_GRACE_MS = 5e3;
|
|
8777
8902
|
var CODEX_SLASH_COMMANDS_CACHE_MS = 3e4;
|
|
8903
|
+
async function readCodexAspThreadHistory(threadId) {
|
|
8904
|
+
let entries;
|
|
8905
|
+
try {
|
|
8906
|
+
entries = await readdir4(CODEX_HISTORY_DIR, { withFileTypes: true });
|
|
8907
|
+
} catch (error) {
|
|
8908
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
8909
|
+
throw new CodexThreadNotFoundError(threadId);
|
|
8910
|
+
}
|
|
8911
|
+
throw error;
|
|
8912
|
+
}
|
|
8913
|
+
for (const entry of entries) {
|
|
8914
|
+
if (!entry.isFile() || !entry.name.endsWith(".jsonl")) continue;
|
|
8915
|
+
const history = await new CodexHistoryFile(join16(CODEX_HISTORY_DIR, entry.name)).load();
|
|
8916
|
+
const transcript = history.transcriptsByThreadId.get(threadId);
|
|
8917
|
+
if (transcript) {
|
|
8918
|
+
return {
|
|
8919
|
+
thread_id: threadId,
|
|
8920
|
+
events: [],
|
|
8921
|
+
codexAspTranscript: transcript,
|
|
8922
|
+
goal: null
|
|
8923
|
+
};
|
|
8924
|
+
}
|
|
8925
|
+
}
|
|
8926
|
+
throw new CodexThreadNotFoundError(threadId);
|
|
8927
|
+
}
|
|
8778
8928
|
function skillToSlashCommand(skill) {
|
|
8779
8929
|
if (!skill.enabled) return null;
|
|
8780
8930
|
const description = skill.interface?.shortDescription ?? skill.shortDescription ?? skill.description;
|
|
@@ -8959,6 +9109,21 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
8959
9109
|
this.recordGoalChange(null, true);
|
|
8960
9110
|
return null;
|
|
8961
9111
|
}
|
|
9112
|
+
async updateGoal(request) {
|
|
9113
|
+
await this.initialized;
|
|
9114
|
+
if (!this.currentThreadId) return null;
|
|
9115
|
+
const host = await getCodexAspHost();
|
|
9116
|
+
const response = await host.client.request(
|
|
9117
|
+
THREAD_GOAL_SET_METHOD,
|
|
9118
|
+
{
|
|
9119
|
+
threadId: this.currentThreadId,
|
|
9120
|
+
...request.objective !== void 0 ? { objective: request.objective } : {},
|
|
9121
|
+
...request.status !== void 0 ? { status: request.status } : {}
|
|
9122
|
+
}
|
|
9123
|
+
);
|
|
9124
|
+
this.recordGoalChange(response.goal, true);
|
|
9125
|
+
return this.currentGoal;
|
|
9126
|
+
}
|
|
8962
9127
|
recordUserMessageEvent(request, extraPayload = {}) {
|
|
8963
9128
|
const images = imageContentToUserMessageImages(request.images);
|
|
8964
9129
|
this.recordHistoryEvent("event_msg", {
|
|
@@ -8981,6 +9146,14 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
8981
9146
|
await this.executeGoalClearCommand(request, recordUserMessage);
|
|
8982
9147
|
return;
|
|
8983
9148
|
}
|
|
9149
|
+
if (goalCommand?.type === "pause" || goalCommand?.type === "resume") {
|
|
9150
|
+
await this.executeGoalStatusCommand(
|
|
9151
|
+
request,
|
|
9152
|
+
recordUserMessage,
|
|
9153
|
+
goalCommand.type === "pause" ? "paused" : "active"
|
|
9154
|
+
);
|
|
9155
|
+
return;
|
|
9156
|
+
}
|
|
8984
9157
|
if (goalCommand?.type === "set") {
|
|
8985
9158
|
await this.executeAspTurn(request, recordUserMessage, {
|
|
8986
9159
|
runTurn: (host, threadId) => this.runGoalTurn(host, threadId, request, goalCommand.objective),
|
|
@@ -9013,16 +9186,28 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
9013
9186
|
}
|
|
9014
9187
|
}
|
|
9015
9188
|
async executeGoalClearCommand(request, recordUserMessage) {
|
|
9016
|
-
const host = await
|
|
9017
|
-
const developerInstructions = this.buildCombinedInstructions(request.customInstructions);
|
|
9018
|
-
recordUserMessage({ command: "goal" });
|
|
9019
|
-
const threadId = await this.ensureThread(host, request, developerInstructions);
|
|
9189
|
+
const { host, threadId } = await this.prepareGoalCommand(request, recordUserMessage);
|
|
9020
9190
|
await host.client.request(
|
|
9021
9191
|
THREAD_GOAL_CLEAR_METHOD,
|
|
9022
9192
|
{ threadId }
|
|
9023
9193
|
);
|
|
9024
9194
|
this.recordGoalChange(null, true);
|
|
9025
9195
|
}
|
|
9196
|
+
async executeGoalStatusCommand(request, recordUserMessage, status) {
|
|
9197
|
+
const { host, threadId } = await this.prepareGoalCommand(request, recordUserMessage);
|
|
9198
|
+
const response = await host.client.request(
|
|
9199
|
+
THREAD_GOAL_SET_METHOD,
|
|
9200
|
+
{ threadId, status }
|
|
9201
|
+
);
|
|
9202
|
+
this.recordGoalChange(response.goal, true);
|
|
9203
|
+
}
|
|
9204
|
+
async prepareGoalCommand(request, recordUserMessage) {
|
|
9205
|
+
const host = await getCodexAspHost();
|
|
9206
|
+
const developerInstructions = this.buildCombinedInstructions(request.customInstructions);
|
|
9207
|
+
recordUserMessage({ command: "goal" });
|
|
9208
|
+
const threadId = await this.ensureThread(host, request, developerInstructions);
|
|
9209
|
+
return { host, threadId };
|
|
9210
|
+
}
|
|
9026
9211
|
async executeAspTurn(request, recordUserMessage, options = {}) {
|
|
9027
9212
|
const host = await getCodexAspHost();
|
|
9028
9213
|
if (this.quotaStatus.blocked && this.quotaStatus.latestSnapshot) {
|
|
@@ -9920,8 +10105,8 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
9920
10105
|
};
|
|
9921
10106
|
|
|
9922
10107
|
// src/managers/cursor-manager.ts
|
|
9923
|
-
import { mkdir as mkdir11, readFile as readFile10, readdir as
|
|
9924
|
-
import { basename, dirname as dirname5, extname, join as
|
|
10108
|
+
import { mkdir as mkdir11, readFile as readFile10, readdir as readdir5 } from "fs/promises";
|
|
10109
|
+
import { basename, dirname as dirname5, extname, join as join17 } from "path";
|
|
9925
10110
|
import { parse as parseYaml2 } from "yaml";
|
|
9926
10111
|
import { Agent as CursorAgent } from "@cursor/sdk";
|
|
9927
10112
|
var CURSOR_SLASH_COMMANDS_CACHE_MS = 3e4;
|
|
@@ -9948,7 +10133,7 @@ function extractCursorCommandDescription(content) {
|
|
|
9948
10133
|
async function listCursorCommandsInDirectory(directory) {
|
|
9949
10134
|
let entries;
|
|
9950
10135
|
try {
|
|
9951
|
-
entries = await
|
|
10136
|
+
entries = await readdir5(directory, { withFileTypes: true });
|
|
9952
10137
|
} catch (error) {
|
|
9953
10138
|
if (isRecord4(error) && error.code === "ENOENT") return [];
|
|
9954
10139
|
console.warn("[CursorManager] Failed to read slash command directory:", error);
|
|
@@ -9958,7 +10143,7 @@ async function listCursorCommandsInDirectory(directory) {
|
|
|
9958
10143
|
const name = basename(entry.name, ".md");
|
|
9959
10144
|
let description;
|
|
9960
10145
|
try {
|
|
9961
|
-
description = extractCursorCommandDescription(await readFile10(
|
|
10146
|
+
description = extractCursorCommandDescription(await readFile10(join17(directory, entry.name), "utf8"));
|
|
9962
10147
|
} catch (error) {
|
|
9963
10148
|
console.warn("[CursorManager] Failed to read slash command file:", error);
|
|
9964
10149
|
}
|
|
@@ -9976,7 +10161,7 @@ var CursorManager = class extends CodingAgentManager {
|
|
|
9976
10161
|
slashCommandsRequest = null;
|
|
9977
10162
|
constructor(options) {
|
|
9978
10163
|
super(options);
|
|
9979
|
-
this.historyFilePath = options.historyFilePath ??
|
|
10164
|
+
this.historyFilePath = options.historyFilePath ?? join17(ENGINE_ENV.HOME_DIR, ".replicas", "cursor", "history.jsonl");
|
|
9980
10165
|
this.historyFile = new CodexHistoryFile(this.historyFilePath);
|
|
9981
10166
|
this.initializeManager(this.processMessageInternal.bind(this));
|
|
9982
10167
|
}
|
|
@@ -10004,8 +10189,8 @@ var CursorManager = class extends CodingAgentManager {
|
|
|
10004
10189
|
this.slashCommandsRequest ??= (async () => {
|
|
10005
10190
|
try {
|
|
10006
10191
|
const commands = mergeSlashCommands(
|
|
10007
|
-
await listCursorCommandsInDirectory(
|
|
10008
|
-
await listCursorCommandsInDirectory(
|
|
10192
|
+
await listCursorCommandsInDirectory(join17(this.workingDirectory, ".cursor", "commands")),
|
|
10193
|
+
await listCursorCommandsInDirectory(join17(ENGINE_ENV.HOME_DIR, ".cursor", "commands"))
|
|
10009
10194
|
);
|
|
10010
10195
|
this.slashCommandsCache = { commands, expiresAt: Date.now() + CURSOR_SLASH_COMMANDS_CACHE_MS };
|
|
10011
10196
|
return commands;
|
|
@@ -10155,7 +10340,7 @@ var CursorManager = class extends CodingAgentManager {
|
|
|
10155
10340
|
|
|
10156
10341
|
// src/managers/opencode-manager.ts
|
|
10157
10342
|
import { mkdir as mkdir12, readFile as readFile11 } from "fs/promises";
|
|
10158
|
-
import { delimiter, dirname as dirname6, join as
|
|
10343
|
+
import { delimiter, dirname as dirname6, join as join18 } from "path";
|
|
10159
10344
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
10160
10345
|
import { fileURLToPath } from "url";
|
|
10161
10346
|
import { Agent } from "undici";
|
|
@@ -10164,7 +10349,7 @@ import {
|
|
|
10164
10349
|
createOpencodeServer
|
|
10165
10350
|
} from "@opencode-ai/sdk/v2";
|
|
10166
10351
|
var OPENCODE_SHIM_DIR = dirname6(fileURLToPath(new URL("../../scripts/opencode", import.meta.url)));
|
|
10167
|
-
var OPENCODE_CONFIG_PATH =
|
|
10352
|
+
var OPENCODE_CONFIG_PATH = join18(ENGINE_ENV.HOME_DIR, ".config", "opencode", "opencode.json");
|
|
10168
10353
|
var OPENCODE_FETCH_DISPATCHER = new Agent({ headersTimeout: 0, bodyTimeout: 0 });
|
|
10169
10354
|
var OPENCODE_SERVER_STARTUP_TIMEOUT_MS = 3e4;
|
|
10170
10355
|
var OPENCODE_WORKSPACE_PERMISSION = "allow";
|
|
@@ -10319,7 +10504,7 @@ var OpencodeManager = class extends CodingAgentManager {
|
|
|
10319
10504
|
constructor(options) {
|
|
10320
10505
|
super(options);
|
|
10321
10506
|
this.sessionId = options.initialSessionId;
|
|
10322
|
-
this.historyFilePath = options.historyFilePath ??
|
|
10507
|
+
this.historyFilePath = options.historyFilePath ?? join18(ENGINE_ENV.HOME_DIR, ".replicas", "opencode", "history.jsonl");
|
|
10323
10508
|
this.historyFile = new CodexHistoryFile(this.historyFilePath);
|
|
10324
10509
|
this.initializeManager(this.processMessageInternal.bind(this));
|
|
10325
10510
|
}
|
|
@@ -11257,12 +11442,12 @@ var KeepAliveService = class _KeepAliveService {
|
|
|
11257
11442
|
var keepAliveService = new KeepAliveService();
|
|
11258
11443
|
|
|
11259
11444
|
// src/services/canvas-service.ts
|
|
11260
|
-
import { readdir as
|
|
11261
|
-
import { homedir as
|
|
11262
|
-
import { join as
|
|
11445
|
+
import { readdir as readdir6, readFile as readFile12, stat as stat3 } from "fs/promises";
|
|
11446
|
+
import { homedir as homedir13 } from "os";
|
|
11447
|
+
import { join as join19 } from "path";
|
|
11263
11448
|
var CANVAS_DIRECTORIES = [
|
|
11264
|
-
|
|
11265
|
-
|
|
11449
|
+
join19(homedir13(), ".claude", "plans"),
|
|
11450
|
+
join19(homedir13(), ".replicas", "canvas")
|
|
11266
11451
|
];
|
|
11267
11452
|
var CanvasService = class {
|
|
11268
11453
|
async listItems() {
|
|
@@ -11270,7 +11455,7 @@ var CanvasService = class {
|
|
|
11270
11455
|
for (const directory of CANVAS_DIRECTORIES) {
|
|
11271
11456
|
let entries;
|
|
11272
11457
|
try {
|
|
11273
|
-
entries = await
|
|
11458
|
+
entries = await readdir6(directory, { withFileTypes: true });
|
|
11274
11459
|
} catch {
|
|
11275
11460
|
continue;
|
|
11276
11461
|
}
|
|
@@ -11281,7 +11466,7 @@ var CanvasService = class {
|
|
|
11281
11466
|
const { kind } = classifyCanvasFilename(entry.name);
|
|
11282
11467
|
let sizeBytes = 0;
|
|
11283
11468
|
try {
|
|
11284
|
-
const s = await stat3(
|
|
11469
|
+
const s = await stat3(join19(directory, entry.name));
|
|
11285
11470
|
sizeBytes = s.size;
|
|
11286
11471
|
} catch {
|
|
11287
11472
|
continue;
|
|
@@ -11296,7 +11481,7 @@ var CanvasService = class {
|
|
|
11296
11481
|
if (!safe) return null;
|
|
11297
11482
|
const { kind, mimeType } = classifyCanvasFilename(safe);
|
|
11298
11483
|
for (const directory of CANVAS_DIRECTORIES) {
|
|
11299
|
-
const filePath =
|
|
11484
|
+
const filePath = join19(directory, safe);
|
|
11300
11485
|
let sizeBytes = 0;
|
|
11301
11486
|
let updatedAt = "";
|
|
11302
11487
|
try {
|
|
@@ -11432,14 +11617,14 @@ async function reconcileCanvasItems(filenames) {
|
|
|
11432
11617
|
}
|
|
11433
11618
|
|
|
11434
11619
|
// src/services/upload-chat-transcripts.ts
|
|
11435
|
-
import { readdir as
|
|
11436
|
-
import { basename as basename2, join as
|
|
11437
|
-
import { homedir as
|
|
11438
|
-
var
|
|
11620
|
+
import { readdir as readdir7, readFile as readFile13 } from "fs/promises";
|
|
11621
|
+
import { basename as basename2, join as join20 } from "path";
|
|
11622
|
+
import { homedir as homedir14 } from "os";
|
|
11623
|
+
var ENGINE_DIR3 = join20(homedir14(), ".replicas", "engine");
|
|
11439
11624
|
var HISTORY_DIRS = [
|
|
11440
|
-
|
|
11441
|
-
|
|
11442
|
-
|
|
11625
|
+
join20(ENGINE_DIR3, "claude-histories"),
|
|
11626
|
+
join20(ENGINE_DIR3, "relay-histories"),
|
|
11627
|
+
join20(ENGINE_DIR3, "codex-histories")
|
|
11443
11628
|
];
|
|
11444
11629
|
async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map()) {
|
|
11445
11630
|
let flushed = 0;
|
|
@@ -11448,7 +11633,7 @@ async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map()) {
|
|
|
11448
11633
|
for (const dir of HISTORY_DIRS) {
|
|
11449
11634
|
let entries;
|
|
11450
11635
|
try {
|
|
11451
|
-
entries = await
|
|
11636
|
+
entries = await readdir7(dir);
|
|
11452
11637
|
} catch {
|
|
11453
11638
|
continue;
|
|
11454
11639
|
}
|
|
@@ -11456,7 +11641,7 @@ async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map()) {
|
|
|
11456
11641
|
if (!entry.endsWith(".jsonl")) continue;
|
|
11457
11642
|
const chatId = basename2(entry, ".jsonl");
|
|
11458
11643
|
tasks.push(
|
|
11459
|
-
uploadChatTranscript(chatId,
|
|
11644
|
+
uploadChatTranscript(chatId, join20(dir, entry), chatsById.get(chatId)).then(() => {
|
|
11460
11645
|
flushed++;
|
|
11461
11646
|
}).catch((err) => {
|
|
11462
11647
|
failed++;
|
|
@@ -11499,50 +11684,10 @@ async function uploadChatTranscript(chatId, filePath, chat) {
|
|
|
11499
11684
|
}
|
|
11500
11685
|
}
|
|
11501
11686
|
|
|
11502
|
-
// src/services/chat/errors.ts
|
|
11503
|
-
var ChatNotFoundError = class extends Error {
|
|
11504
|
-
constructor(chatId) {
|
|
11505
|
-
super(`Chat not found: ${chatId}`);
|
|
11506
|
-
this.name = "ChatNotFoundError";
|
|
11507
|
-
}
|
|
11508
|
-
};
|
|
11509
|
-
var DefaultChatDeletionError = class extends Error {
|
|
11510
|
-
constructor() {
|
|
11511
|
-
super("Default chats cannot be deleted");
|
|
11512
|
-
this.name = "DefaultChatDeletionError";
|
|
11513
|
-
}
|
|
11514
|
-
};
|
|
11515
|
-
var ChatProcessingDeletionError = class extends Error {
|
|
11516
|
-
constructor() {
|
|
11517
|
-
super("Cannot delete a chat while it is processing");
|
|
11518
|
-
this.name = "ChatProcessingDeletionError";
|
|
11519
|
-
}
|
|
11520
|
-
};
|
|
11521
|
-
var DuplicateDefaultChatError = class extends Error {
|
|
11522
|
-
constructor(provider) {
|
|
11523
|
-
super(`Default chat already exists for provider: ${provider}`);
|
|
11524
|
-
this.name = "DuplicateDefaultChatError";
|
|
11525
|
-
}
|
|
11526
|
-
};
|
|
11527
|
-
|
|
11528
11687
|
// src/services/chat/chat-service.ts
|
|
11529
|
-
var
|
|
11530
|
-
var
|
|
11531
|
-
var
|
|
11532
|
-
var RELAY_HISTORY_DIR = join19(ENGINE_DIR3, "relay-histories");
|
|
11533
|
-
var CODEX_HISTORY_DIR = join19(ENGINE_DIR3, "codex-histories");
|
|
11534
|
-
var CURSOR_HISTORY_DIR = join19(ENGINE_DIR3, "cursor-histories");
|
|
11535
|
-
var OPENCODE_HISTORY_DIR = join19(ENGINE_DIR3, "opencode-histories");
|
|
11536
|
-
var HISTORY_DIR_BY_PROVIDER = {
|
|
11537
|
-
claude: CLAUDE_HISTORY_DIR,
|
|
11538
|
-
relay: RELAY_HISTORY_DIR,
|
|
11539
|
-
codex: CODEX_HISTORY_DIR,
|
|
11540
|
-
cursor: CURSOR_HISTORY_DIR,
|
|
11541
|
-
opencode: OPENCODE_HISTORY_DIR
|
|
11542
|
-
};
|
|
11543
|
-
var CHAT_SENDERS_DIR = join19(ENGINE_DIR3, "chat-senders");
|
|
11544
|
-
var CODEX_AUTH_PATH2 = join19(homedir14(), ".codex", "auth.json");
|
|
11545
|
-
var OPENCODE_AUTH_PATH2 = join19(homedir14(), ".local", "share", "opencode", "auth.json");
|
|
11688
|
+
var CHAT_SENDERS_DIR = join21(ENGINE_DIR2, "chat-senders");
|
|
11689
|
+
var CODEX_AUTH_PATH2 = join21(homedir15(), ".codex", "auth.json");
|
|
11690
|
+
var OPENCODE_AUTH_PATH2 = join21(homedir15(), ".local", "share", "opencode", "auth.json");
|
|
11546
11691
|
var CHATS_BACKUP_FILE = `${CHATS_FILE}.bak`;
|
|
11547
11692
|
function isChatMessageSender(value) {
|
|
11548
11693
|
if (!isRecord4(value)) return false;
|
|
@@ -11646,7 +11791,7 @@ var ChatService = class {
|
|
|
11646
11791
|
persistInFlight = false;
|
|
11647
11792
|
persistQueued = false;
|
|
11648
11793
|
async initialize() {
|
|
11649
|
-
await mkdir13(
|
|
11794
|
+
await mkdir13(ENGINE_DIR2, { recursive: true });
|
|
11650
11795
|
await mkdir13(CLAUDE_HISTORY_DIR, { recursive: true });
|
|
11651
11796
|
await mkdir13(RELAY_HISTORY_DIR, { recursive: true });
|
|
11652
11797
|
await mkdir13(CODEX_HISTORY_DIR, { recursive: true });
|
|
@@ -11781,7 +11926,7 @@ var ChatService = class {
|
|
|
11781
11926
|
};
|
|
11782
11927
|
}
|
|
11783
11928
|
senderFilePath(chatId) {
|
|
11784
|
-
return
|
|
11929
|
+
return join21(CHAT_SENDERS_DIR, `${chatId}.jsonl`);
|
|
11785
11930
|
}
|
|
11786
11931
|
async appendSender(chatId, sender) {
|
|
11787
11932
|
try {
|
|
@@ -11863,6 +12008,16 @@ var ChatService = class {
|
|
|
11863
12008
|
goal
|
|
11864
12009
|
};
|
|
11865
12010
|
}
|
|
12011
|
+
async updateGoal(chatId, request) {
|
|
12012
|
+
const chat = this.requireChat(chatId);
|
|
12013
|
+
const goal = chat.provider.updateGoal ? await chat.provider.updateGoal(request) : null;
|
|
12014
|
+
this.touch(chat);
|
|
12015
|
+
await this.publish({
|
|
12016
|
+
type: "chat.updated",
|
|
12017
|
+
payload: { chat: this.toSummary(chat) }
|
|
12018
|
+
});
|
|
12019
|
+
return { goal };
|
|
12020
|
+
}
|
|
11866
12021
|
getChatQueue(chatId) {
|
|
11867
12022
|
const chat = this.requireChat(chatId);
|
|
11868
12023
|
return {
|
|
@@ -11941,7 +12096,7 @@ var ChatService = class {
|
|
|
11941
12096
|
return descendants;
|
|
11942
12097
|
}
|
|
11943
12098
|
async deleteHistoryFile(persisted) {
|
|
11944
|
-
await rm(
|
|
12099
|
+
await rm(join21(HISTORY_DIR_BY_PROVIDER[persisted.provider], `${persisted.id}.jsonl`), { force: true });
|
|
11945
12100
|
await rm(this.senderFilePath(persisted.id), { force: true });
|
|
11946
12101
|
}
|
|
11947
12102
|
async getChatHistory(chatId) {
|
|
@@ -12012,7 +12167,7 @@ var ChatService = class {
|
|
|
12012
12167
|
if (persisted.provider === "claude") {
|
|
12013
12168
|
provider = new ClaudeManager({
|
|
12014
12169
|
workingDirectory: this.workingDirectory,
|
|
12015
|
-
historyFilePath:
|
|
12170
|
+
historyFilePath: join21(CLAUDE_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
12016
12171
|
initialSessionId: persisted.providerSessionId,
|
|
12017
12172
|
onSaveSessionId: saveSession,
|
|
12018
12173
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -12021,7 +12176,7 @@ var ChatService = class {
|
|
|
12021
12176
|
} else if (persisted.provider === "relay") {
|
|
12022
12177
|
provider = new RelayManager({
|
|
12023
12178
|
workingDirectory: this.workingDirectory,
|
|
12024
|
-
historyFilePath:
|
|
12179
|
+
historyFilePath: join21(RELAY_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
12025
12180
|
initialSessionId: persisted.providerSessionId,
|
|
12026
12181
|
onSaveSessionId: saveSession,
|
|
12027
12182
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -12034,7 +12189,7 @@ var ChatService = class {
|
|
|
12034
12189
|
} else if (persisted.provider === "cursor") {
|
|
12035
12190
|
provider = new CursorManager({
|
|
12036
12191
|
workingDirectory: this.workingDirectory,
|
|
12037
|
-
historyFilePath:
|
|
12192
|
+
historyFilePath: join21(CURSOR_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
12038
12193
|
initialSessionId: persisted.providerSessionId,
|
|
12039
12194
|
onSaveSessionId: saveSession,
|
|
12040
12195
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -12043,7 +12198,7 @@ var ChatService = class {
|
|
|
12043
12198
|
} else if (persisted.provider === "opencode") {
|
|
12044
12199
|
provider = new OpencodeManager({
|
|
12045
12200
|
workingDirectory: this.workingDirectory,
|
|
12046
|
-
historyFilePath:
|
|
12201
|
+
historyFilePath: join21(OPENCODE_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
12047
12202
|
initialSessionId: persisted.providerSessionId,
|
|
12048
12203
|
onSaveSessionId: saveSession,
|
|
12049
12204
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -12052,7 +12207,7 @@ var ChatService = class {
|
|
|
12052
12207
|
} else {
|
|
12053
12208
|
provider = new CodexAspManager({
|
|
12054
12209
|
workingDirectory: this.workingDirectory,
|
|
12055
|
-
historyFilePath:
|
|
12210
|
+
historyFilePath: join21(CODEX_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
12056
12211
|
initialSessionId: persisted.providerSessionId,
|
|
12057
12212
|
onSaveSessionId: saveSession,
|
|
12058
12213
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -12191,7 +12346,7 @@ var ChatService = class {
|
|
|
12191
12346
|
});
|
|
12192
12347
|
uploadChatTranscript(
|
|
12193
12348
|
chatId,
|
|
12194
|
-
|
|
12349
|
+
join21(HISTORY_DIR_BY_PROVIDER[chat.persisted.provider], `${chatId}.jsonl`),
|
|
12195
12350
|
this.toSummary(chat)
|
|
12196
12351
|
).catch((err) => {
|
|
12197
12352
|
console.error("[ChatService] Failed to upload chat transcript:", { chatId, err });
|
|
@@ -12309,7 +12464,7 @@ var ChatService = class {
|
|
|
12309
12464
|
// src/services/repo-file-service.ts
|
|
12310
12465
|
import { execFile as execFile2 } from "child_process";
|
|
12311
12466
|
import { readFile as readFile15, realpath, stat as stat4 } from "fs/promises";
|
|
12312
|
-
import { join as
|
|
12467
|
+
import { join as join22, resolve as resolve2, extname as extname2 } from "path";
|
|
12313
12468
|
var CACHE_TTL_MS = 3e4;
|
|
12314
12469
|
var SEARCH_TIMEOUT_MS = 15e3;
|
|
12315
12470
|
var MAX_CONTENT_BYTES = 256 * 1024;
|
|
@@ -12469,7 +12624,7 @@ var RepoFileService = class {
|
|
|
12469
12624
|
const repo = repos.find((r) => r.name === repoName);
|
|
12470
12625
|
if (!repo) return null;
|
|
12471
12626
|
try {
|
|
12472
|
-
const fullPath = await realpath(resolve2(
|
|
12627
|
+
const fullPath = await realpath(resolve2(join22(repo.path, filePath)));
|
|
12473
12628
|
const repoRoot = await realpath(repo.path);
|
|
12474
12629
|
const repoPrefix = repoRoot.endsWith("/") ? repoRoot : repoRoot + "/";
|
|
12475
12630
|
if (!fullPath.startsWith(repoPrefix) && fullPath !== repoRoot) return null;
|
|
@@ -12576,21 +12731,21 @@ var RepoFileService = class {
|
|
|
12576
12731
|
// src/v1-routes.ts
|
|
12577
12732
|
import { Hono } from "hono";
|
|
12578
12733
|
import { z as z2 } from "zod";
|
|
12579
|
-
import { readdir as
|
|
12580
|
-
import { join as
|
|
12734
|
+
import { readdir as readdir9, stat as stat5, readFile as readFile18 } from "fs/promises";
|
|
12735
|
+
import { join as join25, resolve as resolve3 } from "path";
|
|
12581
12736
|
|
|
12582
12737
|
// src/services/warm-hooks-service.ts
|
|
12583
12738
|
import { spawn as spawn4 } from "child_process";
|
|
12584
12739
|
import { readFile as readFile17 } from "fs/promises";
|
|
12585
12740
|
import { existsSync as existsSync8 } from "fs";
|
|
12586
|
-
import { join as
|
|
12741
|
+
import { join as join24 } from "path";
|
|
12587
12742
|
|
|
12588
12743
|
// src/services/warm-hook-logs-service.ts
|
|
12589
|
-
import { mkdir as mkdir14, readFile as readFile16, writeFile as writeFile6, readdir as
|
|
12590
|
-
import { homedir as
|
|
12591
|
-
import { join as
|
|
12592
|
-
var LOGS_DIR2 =
|
|
12593
|
-
var CURRENT_RUN_LOG =
|
|
12744
|
+
import { mkdir as mkdir14, readFile as readFile16, writeFile as writeFile6, readdir as readdir8, appendFile as appendFile4, unlink as unlink3 } from "fs/promises";
|
|
12745
|
+
import { homedir as homedir16 } from "os";
|
|
12746
|
+
import { join as join23 } from "path";
|
|
12747
|
+
var LOGS_DIR2 = join23(homedir16(), ".replicas", "warm-hook-logs");
|
|
12748
|
+
var CURRENT_RUN_LOG = join23(LOGS_DIR2, "current-run.log");
|
|
12594
12749
|
var GLOBAL_FILENAME = "global.json";
|
|
12595
12750
|
function withPreview2(stored) {
|
|
12596
12751
|
const preview = buildHookOutputPreview(stored.output);
|
|
@@ -12607,7 +12762,7 @@ var WarmHookLogsService = class {
|
|
|
12607
12762
|
hookName: "organization",
|
|
12608
12763
|
...entry
|
|
12609
12764
|
};
|
|
12610
|
-
await writeFile6(
|
|
12765
|
+
await writeFile6(join23(LOGS_DIR2, GLOBAL_FILENAME), `${JSON.stringify(log, null, 2)}
|
|
12611
12766
|
`, "utf-8");
|
|
12612
12767
|
}
|
|
12613
12768
|
async saveEnvironmentHookLog(entry) {
|
|
@@ -12617,7 +12772,7 @@ var WarmHookLogsService = class {
|
|
|
12617
12772
|
hookName: "environment",
|
|
12618
12773
|
...entry
|
|
12619
12774
|
};
|
|
12620
|
-
await writeFile6(
|
|
12775
|
+
await writeFile6(join23(LOGS_DIR2, ENVIRONMENT_HOOK_LOG_FILENAME), `${JSON.stringify(log, null, 2)}
|
|
12621
12776
|
`, "utf-8");
|
|
12622
12777
|
}
|
|
12623
12778
|
async saveRepoHookLog(repoName, entry) {
|
|
@@ -12627,13 +12782,13 @@ var WarmHookLogsService = class {
|
|
|
12627
12782
|
hookName: repoName,
|
|
12628
12783
|
...entry
|
|
12629
12784
|
};
|
|
12630
|
-
await writeFile6(
|
|
12785
|
+
await writeFile6(join23(LOGS_DIR2, repoHookLogFilename(repoName)), `${JSON.stringify(log, null, 2)}
|
|
12631
12786
|
`, "utf-8");
|
|
12632
12787
|
}
|
|
12633
12788
|
async getAllLogs() {
|
|
12634
12789
|
let files;
|
|
12635
12790
|
try {
|
|
12636
|
-
files = await
|
|
12791
|
+
files = await readdir8(LOGS_DIR2);
|
|
12637
12792
|
} catch (err) {
|
|
12638
12793
|
if (err.code === "ENOENT") {
|
|
12639
12794
|
return [];
|
|
@@ -12646,7 +12801,7 @@ var WarmHookLogsService = class {
|
|
|
12646
12801
|
continue;
|
|
12647
12802
|
}
|
|
12648
12803
|
try {
|
|
12649
|
-
const raw = await readFile16(
|
|
12804
|
+
const raw = await readFile16(join23(LOGS_DIR2, file), "utf-8");
|
|
12650
12805
|
const stored = JSON.parse(raw);
|
|
12651
12806
|
logs.push(withPreview2(stored));
|
|
12652
12807
|
} catch {
|
|
@@ -12684,7 +12839,7 @@ var WarmHookLogsService = class {
|
|
|
12684
12839
|
async getFullOutput(hookType, hookName) {
|
|
12685
12840
|
const filename = hookType === "global" ? GLOBAL_FILENAME : hookType === "environment" ? ENVIRONMENT_HOOK_LOG_FILENAME : repoHookLogFilename(hookName);
|
|
12686
12841
|
try {
|
|
12687
|
-
const raw = await readFile16(
|
|
12842
|
+
const raw = await readFile16(join23(LOGS_DIR2, filename), "utf-8");
|
|
12688
12843
|
const stored = JSON.parse(raw);
|
|
12689
12844
|
if (stored.hookType !== hookType || stored.hookName !== hookName) {
|
|
12690
12845
|
return null;
|
|
@@ -12703,7 +12858,7 @@ var warmHookLogsService = new WarmHookLogsService();
|
|
|
12703
12858
|
// src/services/warm-hooks-service.ts
|
|
12704
12859
|
async function readRepoWarmHook(repoPath) {
|
|
12705
12860
|
for (const filename of REPLICAS_CONFIG_FILENAMES) {
|
|
12706
|
-
const configPath =
|
|
12861
|
+
const configPath = join24(repoPath, filename);
|
|
12707
12862
|
if (!existsSync8(configPath)) {
|
|
12708
12863
|
continue;
|
|
12709
12864
|
}
|
|
@@ -13011,6 +13166,12 @@ var respondToolInputSchema = z2.object({
|
|
|
13011
13166
|
requestId: z2.string().min(1),
|
|
13012
13167
|
selectionId: z2.string().min(1)
|
|
13013
13168
|
});
|
|
13169
|
+
var updateGoalSchema = z2.object({
|
|
13170
|
+
objective: z2.string().trim().min(1).max(MAX_CODEX_GOAL_OBJECTIVE_CHARS).optional(),
|
|
13171
|
+
status: z2.enum(["active", "paused"]).optional()
|
|
13172
|
+
}).refine((body) => body.objective !== void 0 || body.status !== void 0, {
|
|
13173
|
+
message: "Goal objective or status required"
|
|
13174
|
+
});
|
|
13014
13175
|
function jsonError(message, details) {
|
|
13015
13176
|
return { error: message, details };
|
|
13016
13177
|
}
|
|
@@ -13187,6 +13348,21 @@ function createV1Routes(deps) {
|
|
|
13187
13348
|
return c.json(jsonError("Failed to interrupt chat", error instanceof Error ? error.message : "Unknown error"), 404);
|
|
13188
13349
|
}
|
|
13189
13350
|
});
|
|
13351
|
+
app2.patch("/chats/:chatId/goal", async (c) => {
|
|
13352
|
+
try {
|
|
13353
|
+
const body = updateGoalSchema.parse(await c.req.json());
|
|
13354
|
+
const result = await deps.chatService.updateGoal(c.req.param("chatId"), body);
|
|
13355
|
+
return c.json(result);
|
|
13356
|
+
} catch (error) {
|
|
13357
|
+
if (error instanceof z2.ZodError) {
|
|
13358
|
+
return c.json(jsonError(error.issues[0]?.message || "Invalid goal update"), 400);
|
|
13359
|
+
}
|
|
13360
|
+
if (error instanceof ChatNotFoundError) {
|
|
13361
|
+
return c.json(jsonError("Failed to update goal", error.message), 404);
|
|
13362
|
+
}
|
|
13363
|
+
return c.json(jsonError("Failed to update goal", error instanceof Error ? error.message : "Unknown error"), 500);
|
|
13364
|
+
}
|
|
13365
|
+
});
|
|
13190
13366
|
app2.post("/chats/:chatId/goal/clear", async (c) => {
|
|
13191
13367
|
try {
|
|
13192
13368
|
const result = await deps.chatService.clearGoal(c.req.param("chatId"));
|
|
@@ -13397,6 +13573,22 @@ function createV1Routes(deps) {
|
|
|
13397
13573
|
);
|
|
13398
13574
|
}
|
|
13399
13575
|
});
|
|
13576
|
+
app2.get("/codex/threads/:threadId/history", async (c) => {
|
|
13577
|
+
try {
|
|
13578
|
+
return c.json(await readCodexAspThreadHistory(c.req.param("threadId")));
|
|
13579
|
+
} catch (error) {
|
|
13580
|
+
if (error instanceof CodexThreadNotFoundError) {
|
|
13581
|
+
return c.json(
|
|
13582
|
+
jsonError("Failed to load Codex thread history", error.message),
|
|
13583
|
+
404
|
|
13584
|
+
);
|
|
13585
|
+
}
|
|
13586
|
+
return c.json(
|
|
13587
|
+
jsonError("Failed to load Codex thread history", error instanceof Error ? error.message : "Unknown error"),
|
|
13588
|
+
500
|
|
13589
|
+
);
|
|
13590
|
+
}
|
|
13591
|
+
});
|
|
13400
13592
|
app2.post("/environment/track", async (c) => {
|
|
13401
13593
|
try {
|
|
13402
13594
|
const body = await c.req.json();
|
|
@@ -13677,11 +13869,11 @@ function createV1Routes(deps) {
|
|
|
13677
13869
|
});
|
|
13678
13870
|
app2.get("/logs", async (c) => {
|
|
13679
13871
|
try {
|
|
13680
|
-
const files = await
|
|
13872
|
+
const files = await readdir9(LOG_DIR).catch(() => []);
|
|
13681
13873
|
const logFiles = files.filter((f) => f.endsWith(".log"));
|
|
13682
13874
|
const sessions = await Promise.all(
|
|
13683
13875
|
logFiles.map(async (filename) => {
|
|
13684
|
-
const filePath =
|
|
13876
|
+
const filePath = join25(LOG_DIR, filename);
|
|
13685
13877
|
const fileStat = await stat5(filePath);
|
|
13686
13878
|
const sessionId = filename.replace(/\.log$/, "");
|
|
13687
13879
|
return {
|