replicas-engine 0.1.262 → 0.1.264
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 +284 -90
- package/package.json +1 -1
package/dist/src/index.js
CHANGED
|
@@ -286,7 +286,7 @@ var WORKSPACE_SIZES = ["small", "large"];
|
|
|
286
286
|
var INVALID_WORKSPACE_SIZE_ERROR = `Invalid size: must be one of ${WORKSPACE_SIZES.join(", ")}`;
|
|
287
287
|
|
|
288
288
|
// ../shared/src/e2b.ts
|
|
289
|
-
var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-06-
|
|
289
|
+
var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-06-05-v1";
|
|
290
290
|
|
|
291
291
|
// ../shared/src/runtime-env.ts
|
|
292
292
|
function parsePosixEnvFile(content) {
|
|
@@ -1096,7 +1096,7 @@ var LINEAR_ABILITY = {
|
|
|
1096
1096
|
|
|
1097
1097
|
// ../shared/src/default-skills/replicas-agent/abilities/media.ts
|
|
1098
1098
|
var SECTION6 = `### Media
|
|
1099
|
-
Share screenshots, screen recordings, generated diagrams, and audio clips inline in the Replicas chat
|
|
1099
|
+
Share screenshots, screen recordings, generated diagrams, and audio clips inline in the Replicas chat and natively embedded in external messages.
|
|
1100
1100
|
|
|
1101
1101
|
**Reference:** \`references/MEDIA.md\`
|
|
1102
1102
|
|
|
@@ -1106,7 +1106,7 @@ Use this when:
|
|
|
1106
1106
|
- You need to embed media in a Slack/Linear/GitHub message AND keep a referenceable copy in the Replicas dashboard`;
|
|
1107
1107
|
var REFERENCE6 = `# Media (Screenshots, Recordings, Audio)
|
|
1108
1108
|
|
|
1109
|
-
This guide covers how to share screenshots, screen recordings, generated diagrams, and audio clips
|
|
1109
|
+
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).
|
|
1110
1110
|
|
|
1111
1111
|
## Prerequisites
|
|
1112
1112
|
|
|
@@ -1122,7 +1122,7 @@ Upload to Replicas in these cases \u2014 and **only** these cases:
|
|
|
1122
1122
|
|
|
1123
1123
|
If none of these apply, don't upload.
|
|
1124
1124
|
|
|
1125
|
-
## Uploading
|
|
1125
|
+
## Uploading to Replicas
|
|
1126
1126
|
|
|
1127
1127
|
\`\`\`bash
|
|
1128
1128
|
replicas media upload <path-to-file> [<path-to-file> ...]
|
|
@@ -1132,47 +1132,185 @@ Pass one or more file paths. Uploading several files in a single invocation is p
|
|
|
1132
1132
|
|
|
1133
1133
|
For each file, the CLI prints two lines:
|
|
1134
1134
|
|
|
1135
|
-
1. \`\` \u2014 the chat embed (renders inline in Replicas chat only
|
|
1135
|
+
1. \`\` \u2014 the chat embed (renders inline in Replicas chat **only** \u2014 see below).
|
|
1136
1136
|
2. \`View in Replicas: <deep-link>\` \u2014 a per-file dashboard URL of the form \`https://tryreplicas.com/workspaces/<workspace-id>?mode=media&media=<media-id>\` that opens directly to that specific file.
|
|
1137
1137
|
|
|
1138
1138
|
Match each "View in Replicas" line to the embed line directly above it \u2014 that's the deep link for that file.
|
|
1139
1139
|
|
|
1140
|
-
##
|
|
1140
|
+
## The two URLs the CLI gives you \u2014 and where each one is allowed
|
|
1141
1141
|
|
|
1142
|
-
|
|
1142
|
+
| URL | What it is | Where it's allowed |
|
|
1143
|
+
|---|---|---|
|
|
1144
|
+
| \`https://api.tryreplicas.com/v1/media/<id>\` (inside \`\`) | Authenticated API redirect to a presigned blob \u2014 requires the Replicas chat session | **Only** in the Replicas chat reply. Nowhere else. |
|
|
1145
|
+
| \`https://tryreplicas.com/workspaces/<workspace-id>?mode=media&media=<media-id>\` | Public dashboard deep link to the media tab, scrolled to that specific file | Everywhere external \u2014 Slack, GitHub, Linear, PR bodies, comments, emails. |
|
|
1143
1146
|
|
|
1144
|
-
|
|
1147
|
+
### NEVER link the API redirect URL outside the Replicas chat reply
|
|
1145
1148
|
|
|
1146
|
-
**
|
|
1149
|
+
The \`api.tryreplicas.com/v1/media/<id>\` URL is **not public**. It's an authenticated redirect that only resolves to a presigned download when the Replicas chat session token is present. Anywhere else (Slack, Linear, GitHub, a browser tab the user opens directly, a customer copy-pasting from chat) it returns \`{"error":"Missing authorization token"}\` and renders as a broken image.
|
|
1147
1150
|
|
|
1148
|
-
|
|
1151
|
+
This rule has no exceptions:
|
|
1152
|
+
- \u274C Never paste it in a Slack message \u2014 upload the actual bytes via the 3-step \`files.getUploadURLExternal\` \u2192 POST bytes \u2192 \`files.completeUploadExternal\` flow instead (see below).
|
|
1153
|
+
- \u274C Never paste it in a GitHub PR description, issue body, review comment, or commit message.
|
|
1154
|
+
- \u274C Never paste it in a Linear issue body or comment \u2014 upload via Linear's \`fileUpload\` mutation instead (see below).
|
|
1155
|
+
- \u274C Never link to it from any external doc, email, or external chat.
|
|
1156
|
+
- \u274C Never include it as a "backup link" in case the dashboard link breaks \u2014 it will always break externally.
|
|
1149
1157
|
|
|
1150
|
-
|
|
1158
|
+
### ALWAYS link the dashboard URL \u2014 never the API URL \u2014 when referencing media externally
|
|
1159
|
+
|
|
1160
|
+
When you reference an uploaded file from anywhere outside the Replicas chat reply, the link must be the dashboard form:
|
|
1151
1161
|
|
|
1152
|
-
\`\`\`
|
|
1153
|
-
|
|
1162
|
+
\`\`\`
|
|
1163
|
+
https://tryreplicas.com/workspaces/<workspace-id>?mode=media&media=<media-id>
|
|
1154
1164
|
\`\`\`
|
|
1155
1165
|
|
|
1156
|
-
|
|
1166
|
+
Both query params are required:
|
|
1167
|
+
- \`mode=media\` opens the media tab in the dashboard.
|
|
1168
|
+
- \`media=<media-id>\` scrolls to and opens that specific file.
|
|
1157
1169
|
|
|
1158
|
-
|
|
1170
|
+
Never link \`tryreplicas.com/workspaces/<id>?mode=media\` without the \`media=<id>\` param when you have a specific file in mind \u2014 that lands on the gallery, not the file. Never link the bare workspace URL.
|
|
1159
1171
|
|
|
1160
|
-
|
|
1161
|
-
- **Media tab link** (no \`media=\` param): \`...?mode=media\` opens the workspace's media tab listing all files. Use this only when you're pointing at the collection, not a specific file (rare \u2014 you almost always have a specific file in mind).
|
|
1172
|
+
Always render as a markdown / mrkdwn hyperlink labeled **View in Replicas** \u2014 never paste a raw URL.
|
|
1162
1173
|
|
|
1163
|
-
|
|
1174
|
+
## In your Replicas chat reply
|
|
1164
1175
|
|
|
1165
1176
|
Include each markdown embed line **verbatim** where you want that file to render inline. The chat substitutes each one with an embedded image, video, or audio player. Multiple embeds can appear in a single reply.
|
|
1166
1177
|
|
|
1167
|
-
After (or alongside) the embeds, include a \`[View in Replicas](<deep-link>)\` hyperlink for each file using the per-file URL the CLI
|
|
1178
|
+
After (or alongside) the embeds, include a \`[View in Replicas](<deep-link>)\` hyperlink for each file using the per-file dashboard URL from the CLI. This lets the user jump to the specific item in the media tab.
|
|
1179
|
+
|
|
1180
|
+
## On external platforms \u2014 upload natively AND link the dashboard
|
|
1181
|
+
|
|
1182
|
+
Sharing media externally is a **two-step requirement** for every file:
|
|
1183
|
+
|
|
1184
|
+
1. **Upload the raw bytes natively to that platform** so the recipient sees the media embedded inline in the message itself.
|
|
1185
|
+
2. **Link the Replicas dashboard deep link** (\`?mode=media&media=<id>\` form) so the user can jump straight to the workspace.
|
|
1186
|
+
|
|
1187
|
+
A link alone is not enough. A native upload alone is not enough. Do both.
|
|
1188
|
+
|
|
1189
|
+
The one exception is GitHub, which has no public image upload API \u2014 there, the dashboard link is the only option (see below).
|
|
1190
|
+
|
|
1191
|
+
### Slack \u2014 embed natively via the 3-step external file upload flow
|
|
1192
|
+
|
|
1193
|
+
A Slack message that just contains a \`tryreplicas.com\` link is not acceptable when the message is supposed to show an image. The recipient should see the image inline in the thread.
|
|
1194
|
+
|
|
1195
|
+
Slack deprecated the single-shot \`files.upload\` endpoint. The raw HTTP replacement is a 3-step flow: reserve an upload URL with \`files.getUploadURLExternal\`, POST the bytes to it, then share into the channel/thread with \`files.completeUploadExternal\`. (\`files.uploadV2\` is **only** an SDK convenience wrapper \u2014 it is NOT a real Web API HTTP endpoint and \`POST https://slack.com/api/files.uploadV2\` will return \`unknown_method\`.)
|
|
1196
|
+
|
|
1197
|
+
\`\`\`bash
|
|
1198
|
+
FILE=/abs/path/to/screenshot.png
|
|
1199
|
+
FILENAME=$(basename "$FILE")
|
|
1200
|
+
LENGTH=$(stat -c%s "$FILE" 2>/dev/null || stat -f%z "$FILE")
|
|
1201
|
+
|
|
1202
|
+
# 1. Reserve an upload URL + file ID.
|
|
1203
|
+
RESERVE=$(curl -s -G "https://slack.com/api/files.getUploadURLExternal" \\
|
|
1204
|
+
-H "Authorization: Bearer $SLACK_BOT_TOKEN" \\
|
|
1205
|
+
--data-urlencode "filename=$FILENAME" \\
|
|
1206
|
+
--data-urlencode "length=$LENGTH")
|
|
1207
|
+
UPLOAD_URL=$(echo "$RESERVE" | jq -r '.upload_url')
|
|
1208
|
+
FILE_ID=$(echo "$RESERVE" | jq -r '.file_id')
|
|
1209
|
+
|
|
1210
|
+
# 2. POST the raw bytes to the reserved URL.
|
|
1211
|
+
# Do not use -F / multipart here \u2014 the presigned URL expects the bytes
|
|
1212
|
+
# directly in the request body.
|
|
1213
|
+
curl -s -X POST "$UPLOAD_URL" \\
|
|
1214
|
+
-H "Content-Type: application/octet-stream" \\
|
|
1215
|
+
--data-binary @"$FILE"
|
|
1216
|
+
|
|
1217
|
+
# 3. Complete the upload, sharing it into the channel/thread with the dashboard link.
|
|
1218
|
+
curl -s -X POST "https://slack.com/api/files.completeUploadExternal" \\
|
|
1219
|
+
-H "Authorization: Bearer $SLACK_BOT_TOKEN" \\
|
|
1220
|
+
-H "Content-Type: application/json; charset=utf-8" \\
|
|
1221
|
+
-d "{
|
|
1222
|
+
\\"files\\": [{\\"id\\": \\"$FILE_ID\\", \\"title\\": \\"Screenshot\\"}],
|
|
1223
|
+
\\"channel_id\\": \\"CHANNEL_ID\\",
|
|
1224
|
+
\\"thread_ts\\": \\"THREAD_TS\\",
|
|
1225
|
+
\\"initial_comment\\": \\"<https://tryreplicas.com/workspaces/<workspace-id>?mode=media&media=<media-id>|View in Replicas>\\"
|
|
1226
|
+
}"
|
|
1227
|
+
\`\`\`
|
|
1228
|
+
|
|
1229
|
+
Notes:
|
|
1230
|
+
- All three steps are required; do not try to POST to \`https://slack.com/api/files.uploadV2\` \u2014 that endpoint does not exist on the Web API.
|
|
1231
|
+
- \`initial_comment\` uses Slack mrkdwn (\`<url|label>\`), not GitHub-flavored markdown.
|
|
1232
|
+
- Omit \`thread_ts\` only when you genuinely want a top-level channel post.
|
|
1233
|
+
- For multiple files in the same message, run steps 1\u20132 per file and pass all \`{id, title}\` objects in the \`files\` array of a single \`files.completeUploadExternal\` call \u2014 they share into the thread together.
|
|
1234
|
+
- If you also need to post a separate text reply in the thread, send it with \`chat.postMessage\` after the upload \u2014 but the upload itself must carry the image.
|
|
1168
1235
|
|
|
1169
|
-
|
|
1236
|
+
Never paste the \`api.tryreplicas.com/v1/media/<id>\` URL into a Slack message body or \`initial_comment\` \u2014 it will render as a broken image attempt.
|
|
1170
1237
|
|
|
1171
|
-
|
|
1238
|
+
### Linear \u2014 embed natively via the GraphQL \`fileUpload\` mutation
|
|
1239
|
+
|
|
1240
|
+
Linear comments and issue bodies support markdown image embeds, but the image URL must be publicly accessible \u2014 so you upload the file to Linear's storage first, then reference the returned \`assetUrl\` in markdown. Three steps:
|
|
1241
|
+
|
|
1242
|
+
Use \`jq\` to build the JSON bodies \u2014 the GraphQL variables (\`size\`, \`filename\`, the comment body) need to be real JSON values, not unquoted placeholders, and \`jq -n --argjson / --arg\` is the safest way to interpolate shell values without quoting bugs.
|
|
1243
|
+
|
|
1244
|
+
\`\`\`bash
|
|
1245
|
+
FILE=/abs/path/to/screenshot.png
|
|
1246
|
+
FILENAME=$(basename "$FILE")
|
|
1247
|
+
SIZE=$(stat -c%s "$FILE" 2>/dev/null || stat -f%z "$FILE")
|
|
1248
|
+
CONTENT_TYPE=image/png
|
|
1249
|
+
ISSUE_UUID=... # the Linear issue's UUID
|
|
1250
|
+
WORKSPACE_ID=... # the Replicas workspace ID
|
|
1251
|
+
MEDIA_ID=... # the media ID printed by \`replicas media upload\`
|
|
1252
|
+
|
|
1253
|
+
# 1. Ask Linear for an upload URL + assetUrl.
|
|
1254
|
+
RESERVE=$(curl -s -X POST https://api.linear.app/graphql \\
|
|
1255
|
+
-H "Authorization: Bearer $LINEAR_ACCESS_TOKEN" \\
|
|
1256
|
+
-H "Content-Type: application/json" \\
|
|
1257
|
+
-d "$(jq -n \\
|
|
1258
|
+
--argjson size "$SIZE" \\
|
|
1259
|
+
--arg contentType "$CONTENT_TYPE" \\
|
|
1260
|
+
--arg filename "$FILENAME" \\
|
|
1261
|
+
'{
|
|
1262
|
+
query: "mutation($size: Int!, $contentType: String!, $filename: String!) { fileUpload(size: $size, contentType: $contentType, filename: $filename) { uploadFile { uploadUrl assetUrl headers { key value } } } }",
|
|
1263
|
+
variables: { size: $size, contentType: $contentType, filename: $filename }
|
|
1264
|
+
}')")
|
|
1265
|
+
UPLOAD_URL=$(echo "$RESERVE" | jq -r '.data.fileUpload.uploadFile.uploadUrl')
|
|
1266
|
+
ASSET_URL=$(echo "$RESERVE" | jq -r '.data.fileUpload.uploadFile.assetUrl')
|
|
1267
|
+
|
|
1268
|
+
# 2. PUT the bytes to uploadUrl, replaying every header Linear returned.
|
|
1269
|
+
# Linear's presigned URL requires the exact Content-Type / Cache-Control /
|
|
1270
|
+
# etc. it gave you back, so forward each {key, value} from the headers array.
|
|
1271
|
+
HEADER_ARGS=()
|
|
1272
|
+
while IFS=$'\\t' read -r k v; do
|
|
1273
|
+
HEADER_ARGS+=(-H "$k: $v")
|
|
1274
|
+
done < <(echo "$RESERVE" | jq -r '.data.fileUpload.uploadFile.headers[] | "\\(.key)\\t\\(.value)"')
|
|
1275
|
+
|
|
1276
|
+
curl -s -X PUT "$UPLOAD_URL" \\
|
|
1277
|
+
"\${HEADER_ARGS[@]}" \\
|
|
1278
|
+
--data-binary @"$FILE"
|
|
1279
|
+
|
|
1280
|
+
# 3. Reference assetUrl inline in the comment body, alongside the dashboard link.
|
|
1281
|
+
BODY=$(printf '\\n\\n[View in Replicas](https://tryreplicas.com/workspaces/%s?mode=media&media=%s)' \\
|
|
1282
|
+
"$ASSET_URL" "$WORKSPACE_ID" "$MEDIA_ID")
|
|
1283
|
+
|
|
1284
|
+
curl -s -X POST https://api.linear.app/graphql \\
|
|
1285
|
+
-H "Authorization: Bearer $LINEAR_ACCESS_TOKEN" \\
|
|
1286
|
+
-H "Content-Type: application/json" \\
|
|
1287
|
+
-d "$(jq -n \\
|
|
1288
|
+
--arg issueId "$ISSUE_UUID" \\
|
|
1289
|
+
--arg body "$BODY" \\
|
|
1290
|
+
'{
|
|
1291
|
+
query: "mutation($issueId: String!, $body: String!) { commentCreate(input: { issueId: $issueId, body: $body }) { success } }",
|
|
1292
|
+
variables: { issueId: $issueId, body: $body }
|
|
1293
|
+
}')"
|
|
1294
|
+
\`\`\`
|
|
1295
|
+
|
|
1296
|
+
The same flow works for issue bodies (use \`issueCreate\` / \`issueUpdate\` with the same markdown body).
|
|
1297
|
+
|
|
1298
|
+
Never paste the \`api.tryreplicas.com/v1/media/<id>\` URL into a Linear body or comment \u2014 it will render as a broken image to anyone outside your Replicas chat.
|
|
1299
|
+
|
|
1300
|
+
### GitHub \u2014 link the dashboard deep link (no public upload API exists)
|
|
1301
|
+
|
|
1302
|
+
GitHub has **no public API** for uploading images to PRs or issues. Their web UI uses an undocumented internal endpoint that's not available to API clients. So for GitHub specifically, the only correct way to share media is the dashboard deep link, rendered as a markdown hyperlink:
|
|
1303
|
+
|
|
1304
|
+
\`\`\`markdown
|
|
1305
|
+
[View in Replicas](https://tryreplicas.com/workspaces/<workspace-id>?mode=media&media=<media-id>)
|
|
1306
|
+
\`\`\`
|
|
1172
1307
|
|
|
1173
|
-
|
|
1308
|
+
Do **not**:
|
|
1309
|
+
- Commit screenshots as files to the repo as a workaround.
|
|
1310
|
+
- Use placeholder image URLs.
|
|
1311
|
+
- Embed the \`api.tryreplicas.com/v1/media/<id>\` URL in markdown \u2014 it renders as a broken image for every viewer.
|
|
1174
1312
|
|
|
1175
|
-
|
|
1313
|
+
This applies to PR descriptions, PR review comments, issue bodies, issue comments, and commit messages.
|
|
1176
1314
|
|
|
1177
1315
|
## Recording defaults
|
|
1178
1316
|
|
|
@@ -1593,14 +1731,42 @@ curl -s "https://slack.com/api/search.messages?query=YOUR_SEARCH_QUERY" \\
|
|
|
1593
1731
|
|
|
1594
1732
|
### Uploading Files
|
|
1595
1733
|
|
|
1734
|
+
Slack deprecated \`files.upload\`; the raw HTTP replacement is a 3-step flow. (\`files.uploadV2\` is **only** an SDK convenience wrapper and is NOT a real Web API HTTP endpoint \u2014 \`POST https://slack.com/api/files.uploadV2\` returns \`unknown_method\`.)
|
|
1735
|
+
|
|
1596
1736
|
\`\`\`bash
|
|
1597
|
-
|
|
1737
|
+
FILE=/path/to/file
|
|
1738
|
+
FILENAME=$(basename "$FILE")
|
|
1739
|
+
LENGTH=$(stat -c%s "$FILE" 2>/dev/null || stat -f%z "$FILE")
|
|
1740
|
+
|
|
1741
|
+
# 1. Reserve an upload URL + file ID.
|
|
1742
|
+
RESERVE=$(curl -s -G "https://slack.com/api/files.getUploadURLExternal" \\
|
|
1743
|
+
-H "Authorization: Bearer $SLACK_BOT_TOKEN" \\
|
|
1744
|
+
--data-urlencode "filename=$FILENAME" \\
|
|
1745
|
+
--data-urlencode "length=$LENGTH")
|
|
1746
|
+
UPLOAD_URL=$(echo "$RESERVE" | jq -r '.upload_url')
|
|
1747
|
+
FILE_ID=$(echo "$RESERVE" | jq -r '.file_id')
|
|
1748
|
+
|
|
1749
|
+
# 2. POST the raw bytes to the reserved URL.
|
|
1750
|
+
# Do not use -F / multipart here \u2014 the presigned URL expects the bytes
|
|
1751
|
+
# directly in the request body.
|
|
1752
|
+
curl -s -X POST "$UPLOAD_URL" \\
|
|
1753
|
+
-H "Content-Type: application/octet-stream" \\
|
|
1754
|
+
--data-binary @"$FILE"
|
|
1755
|
+
|
|
1756
|
+
# 3. Complete the upload and share into a channel (and optionally a thread).
|
|
1757
|
+
curl -s -X POST "https://slack.com/api/files.completeUploadExternal" \\
|
|
1598
1758
|
-H "Authorization: Bearer $SLACK_BOT_TOKEN" \\
|
|
1599
|
-
-
|
|
1600
|
-
-
|
|
1601
|
-
|
|
1759
|
+
-H "Content-Type: application/json; charset=utf-8" \\
|
|
1760
|
+
-d "{
|
|
1761
|
+
\\"files\\": [{\\"id\\": \\"$FILE_ID\\", \\"title\\": \\"File title\\"}],
|
|
1762
|
+
\\"channel_id\\": \\"CHANNEL_ID\\",
|
|
1763
|
+
\\"thread_ts\\": \\"OPTIONAL_THREAD_TS\\",
|
|
1764
|
+
\\"initial_comment\\": \\"Optional message body\\"
|
|
1765
|
+
}"
|
|
1602
1766
|
\`\`\`
|
|
1603
1767
|
|
|
1768
|
+
Omit \`thread_ts\` and/or \`initial_comment\` if you don't need them.
|
|
1769
|
+
|
|
1604
1770
|
### Other Operations
|
|
1605
1771
|
|
|
1606
1772
|
You can list channels, read channel history, add reactions, and perform any other operation supported by the Slack Web API using the same authentication pattern.
|
|
@@ -2287,7 +2453,6 @@ var execFileAsync = promisify(execFile);
|
|
|
2287
2453
|
var SUBPROCESS_MAX_BUFFER = HOOK_EXEC_MAX_BUFFER_BYTES;
|
|
2288
2454
|
|
|
2289
2455
|
// src/managers/github-token-manager.ts
|
|
2290
|
-
import { promises as fs } from "fs";
|
|
2291
2456
|
import path from "path";
|
|
2292
2457
|
|
|
2293
2458
|
// src/engine-env.ts
|
|
@@ -2529,6 +2694,26 @@ var MonolithService = class {
|
|
|
2529
2694
|
};
|
|
2530
2695
|
var monolithService = new MonolithService();
|
|
2531
2696
|
|
|
2697
|
+
// src/utils/file.ts
|
|
2698
|
+
import { mkdir, rename, unlink, writeFile } from "fs/promises";
|
|
2699
|
+
import { dirname } from "path";
|
|
2700
|
+
async function atomicWriteFile(path4, data, options) {
|
|
2701
|
+
const tmpFile = `${path4}.${process.pid}.${Date.now()}.tmp`;
|
|
2702
|
+
try {
|
|
2703
|
+
await writeFile(tmpFile, data, { encoding: "utf-8", mode: options?.mode });
|
|
2704
|
+
await rename(tmpFile, path4);
|
|
2705
|
+
} catch (error) {
|
|
2706
|
+
await unlink(tmpFile).catch(() => void 0);
|
|
2707
|
+
throw error;
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
async function writeSecureCredentialFile(filePath, content, options) {
|
|
2711
|
+
if (options?.ensureParentDir) {
|
|
2712
|
+
await mkdir(dirname(filePath), { recursive: true, mode: 448 });
|
|
2713
|
+
}
|
|
2714
|
+
await atomicWriteFile(filePath, content, { mode: 384 });
|
|
2715
|
+
}
|
|
2716
|
+
|
|
2532
2717
|
// src/managers/github-token-manager.ts
|
|
2533
2718
|
var GitHubTokenManager = class extends BaseRefreshManager {
|
|
2534
2719
|
constructor() {
|
|
@@ -2544,8 +2729,9 @@ var GitHubTokenManager = class extends BaseRefreshManager {
|
|
|
2544
2729
|
const data = await response.json();
|
|
2545
2730
|
await this.updateGitCredentials(data.token);
|
|
2546
2731
|
const ghToken = data.userToken?.token ?? data.token;
|
|
2732
|
+
const ghUsername = data.userToken?.username ?? "x-access-token";
|
|
2547
2733
|
ENGINE_ENV.GH_TOKEN = ghToken;
|
|
2548
|
-
|
|
2734
|
+
await this.updateGhHostsFile(ghToken, ghUsername);
|
|
2549
2735
|
if (data.userToken) {
|
|
2550
2736
|
console.log(`[GitHubTokenManager] Token refreshed with user token for PR attribution, installation token expires at ${data.expiresAt}, user token expires at ${data.userToken.expiresAt}`);
|
|
2551
2737
|
} else {
|
|
@@ -2553,22 +2739,35 @@ var GitHubTokenManager = class extends BaseRefreshManager {
|
|
|
2553
2739
|
}
|
|
2554
2740
|
}
|
|
2555
2741
|
async updateGitCredentials(token) {
|
|
2556
|
-
const
|
|
2557
|
-
const credentialsPath = path.join(workspaceHome, ".git-credentials");
|
|
2742
|
+
const credentialsPath = path.join(ENGINE_ENV.HOME_DIR, ".git-credentials");
|
|
2558
2743
|
const credentialsContent = `https://x-access-token:${token}@github.com
|
|
2559
2744
|
`;
|
|
2560
2745
|
try {
|
|
2561
|
-
await
|
|
2746
|
+
await writeSecureCredentialFile(credentialsPath, credentialsContent);
|
|
2562
2747
|
console.log(`[GitHubTokenManager] Updated ${credentialsPath}`);
|
|
2563
2748
|
} catch (error) {
|
|
2564
2749
|
console.error("[GitHubTokenManager] Failed to update git credentials:", error);
|
|
2565
2750
|
}
|
|
2566
2751
|
}
|
|
2752
|
+
async updateGhHostsFile(token, username) {
|
|
2753
|
+
const hostsPath = path.join(ENGINE_ENV.HOME_DIR, ".config", "gh", "hosts.yml");
|
|
2754
|
+
const content = `github.com:
|
|
2755
|
+
oauth_token: ${JSON.stringify(token)}
|
|
2756
|
+
user: ${JSON.stringify(username)}
|
|
2757
|
+
git_protocol: https
|
|
2758
|
+
`;
|
|
2759
|
+
try {
|
|
2760
|
+
await writeSecureCredentialFile(hostsPath, content, { ensureParentDir: true });
|
|
2761
|
+
console.log(`[GitHubTokenManager] Updated ${hostsPath}`);
|
|
2762
|
+
} catch (error) {
|
|
2763
|
+
console.error("[GitHubTokenManager] Failed to update gh hosts file:", error);
|
|
2764
|
+
}
|
|
2765
|
+
}
|
|
2567
2766
|
};
|
|
2568
2767
|
var githubTokenManager = new GitHubTokenManager();
|
|
2569
2768
|
|
|
2570
2769
|
// src/managers/claude-token-manager.ts
|
|
2571
|
-
import { promises as
|
|
2770
|
+
import { promises as fs } from "fs";
|
|
2572
2771
|
import path2 from "path";
|
|
2573
2772
|
|
|
2574
2773
|
// src/managers/auth-env-transition.ts
|
|
@@ -2661,9 +2860,7 @@ var ClaudeTokenManager = class extends BaseRefreshManager {
|
|
|
2661
2860
|
});
|
|
2662
2861
|
}
|
|
2663
2862
|
async writeOauthCredentialsFile(credentials) {
|
|
2664
|
-
const
|
|
2665
|
-
const claudeDir = path2.join(workspaceHome, ".claude");
|
|
2666
|
-
const credentialsPath = path2.join(claudeDir, ".credentials.json");
|
|
2863
|
+
const credentialsPath = path2.join(ENGINE_ENV.HOME_DIR, ".claude", ".credentials.json");
|
|
2667
2864
|
const claudeCliConfig = {
|
|
2668
2865
|
claudeAiOauth: {
|
|
2669
2866
|
accessToken: credentials.accessToken,
|
|
@@ -2674,8 +2871,11 @@ var ClaudeTokenManager = class extends BaseRefreshManager {
|
|
|
2674
2871
|
}
|
|
2675
2872
|
};
|
|
2676
2873
|
try {
|
|
2677
|
-
await
|
|
2678
|
-
|
|
2874
|
+
await writeSecureCredentialFile(
|
|
2875
|
+
credentialsPath,
|
|
2876
|
+
JSON.stringify(claudeCliConfig, null, 2),
|
|
2877
|
+
{ ensureParentDir: true }
|
|
2878
|
+
);
|
|
2679
2879
|
console.log(`[ClaudeTokenManager] Updated ${credentialsPath}`);
|
|
2680
2880
|
} catch (error) {
|
|
2681
2881
|
console.error("[ClaudeTokenManager] Failed to update credentials file:", error);
|
|
@@ -2684,7 +2884,7 @@ var ClaudeTokenManager = class extends BaseRefreshManager {
|
|
|
2684
2884
|
async removeOauthCredentialsFile() {
|
|
2685
2885
|
const credentialsPath = path2.join(ENGINE_ENV.HOME_DIR, ".claude", ".credentials.json");
|
|
2686
2886
|
try {
|
|
2687
|
-
await
|
|
2887
|
+
await fs.unlink(credentialsPath);
|
|
2688
2888
|
} catch {
|
|
2689
2889
|
}
|
|
2690
2890
|
}
|
|
@@ -2692,7 +2892,7 @@ var ClaudeTokenManager = class extends BaseRefreshManager {
|
|
|
2692
2892
|
var claudeTokenManager = new ClaudeTokenManager();
|
|
2693
2893
|
|
|
2694
2894
|
// src/managers/codex-token-manager.ts
|
|
2695
|
-
import { promises as
|
|
2895
|
+
import { promises as fs2 } from "fs";
|
|
2696
2896
|
import path3 from "path";
|
|
2697
2897
|
var CodexTokenManager = class extends BaseRefreshManager {
|
|
2698
2898
|
constructor() {
|
|
@@ -2761,9 +2961,7 @@ var CodexTokenManager = class extends BaseRefreshManager {
|
|
|
2761
2961
|
});
|
|
2762
2962
|
}
|
|
2763
2963
|
async writeOauthCredentialsFile(credentials) {
|
|
2764
|
-
const
|
|
2765
|
-
const codexDir = path3.join(workspaceHome, ".codex");
|
|
2766
|
-
const authPath = path3.join(codexDir, "auth.json");
|
|
2964
|
+
const authPath = path3.join(ENGINE_ENV.HOME_DIR, ".codex", "auth.json");
|
|
2767
2965
|
const codexAuthConfig = {
|
|
2768
2966
|
OPENAI_API_KEY: null,
|
|
2769
2967
|
tokens: {
|
|
@@ -2775,8 +2973,11 @@ var CodexTokenManager = class extends BaseRefreshManager {
|
|
|
2775
2973
|
last_refresh: (/* @__PURE__ */ new Date()).toISOString()
|
|
2776
2974
|
};
|
|
2777
2975
|
try {
|
|
2778
|
-
await
|
|
2779
|
-
|
|
2976
|
+
await writeSecureCredentialFile(
|
|
2977
|
+
authPath,
|
|
2978
|
+
JSON.stringify(codexAuthConfig, null, 2),
|
|
2979
|
+
{ ensureParentDir: true }
|
|
2980
|
+
);
|
|
2780
2981
|
console.log(`[CodexTokenManager] Updated ${authPath}`);
|
|
2781
2982
|
} catch (error) {
|
|
2782
2983
|
console.error("[CodexTokenManager] Failed to update credentials file:", error);
|
|
@@ -2785,7 +2986,7 @@ var CodexTokenManager = class extends BaseRefreshManager {
|
|
|
2785
2986
|
async removeOauthCredentialsFile() {
|
|
2786
2987
|
const authPath = path3.join(ENGINE_ENV.HOME_DIR, ".codex", "auth.json");
|
|
2787
2988
|
try {
|
|
2788
|
-
await
|
|
2989
|
+
await fs2.unlink(authPath);
|
|
2789
2990
|
} catch {
|
|
2790
2991
|
}
|
|
2791
2992
|
}
|
|
@@ -2799,24 +3000,11 @@ import { spawn } from "child_process";
|
|
|
2799
3000
|
import { join as join5 } from "path";
|
|
2800
3001
|
|
|
2801
3002
|
// src/utils/state.ts
|
|
2802
|
-
import { readFile, mkdir } from "fs/promises";
|
|
3003
|
+
import { readFile, mkdir as mkdir2 } from "fs/promises";
|
|
2803
3004
|
import { existsSync } from "fs";
|
|
2804
3005
|
import { join as join3 } from "path";
|
|
2805
3006
|
import { homedir as homedir3 } from "os";
|
|
2806
3007
|
|
|
2807
|
-
// src/utils/file.ts
|
|
2808
|
-
import { rename, unlink, writeFile } from "fs/promises";
|
|
2809
|
-
async function atomicWriteFile(path4, data) {
|
|
2810
|
-
const tmpFile = `${path4}.${process.pid}.${Date.now()}.tmp`;
|
|
2811
|
-
try {
|
|
2812
|
-
await writeFile(tmpFile, data, "utf-8");
|
|
2813
|
-
await rename(tmpFile, path4);
|
|
2814
|
-
} catch (error) {
|
|
2815
|
-
await unlink(tmpFile).catch(() => void 0);
|
|
2816
|
-
throw error;
|
|
2817
|
-
}
|
|
2818
|
-
}
|
|
2819
|
-
|
|
2820
3008
|
// src/utils/type-guards.ts
|
|
2821
3009
|
function isRecord4(value) {
|
|
2822
3010
|
return typeof value === "object" && value !== null;
|
|
@@ -2836,7 +3024,7 @@ function enqueueStateWrite(operation) {
|
|
|
2836
3024
|
}
|
|
2837
3025
|
async function updateEngineState(updater) {
|
|
2838
3026
|
await enqueueStateWrite(async () => {
|
|
2839
|
-
await
|
|
3027
|
+
await mkdir2(STATE_DIR, { recursive: true });
|
|
2840
3028
|
const currentState = await loadEngineState();
|
|
2841
3029
|
const nextState = updater(currentState);
|
|
2842
3030
|
await atomicWriteFile(STATE_FILE, JSON.stringify(nextState, null, 2));
|
|
@@ -3466,7 +3654,7 @@ var GitService = class {
|
|
|
3466
3654
|
var gitService = new GitService();
|
|
3467
3655
|
|
|
3468
3656
|
// src/utils/logger.ts
|
|
3469
|
-
import { appendFile, mkdir as
|
|
3657
|
+
import { appendFile, mkdir as mkdir3, writeFile as writeFile2 } from "fs/promises";
|
|
3470
3658
|
import { homedir as homedir4 } from "os";
|
|
3471
3659
|
import { join as join6 } from "path";
|
|
3472
3660
|
import { format } from "util";
|
|
@@ -3481,7 +3669,7 @@ var EngineLogger = class {
|
|
|
3481
3669
|
return this._sessionId;
|
|
3482
3670
|
}
|
|
3483
3671
|
async initialize() {
|
|
3484
|
-
await
|
|
3672
|
+
await mkdir3(LOG_DIR, { recursive: true });
|
|
3485
3673
|
this._sessionId = this.createSessionId();
|
|
3486
3674
|
this.filePath = join6(LOG_DIR, `${this._sessionId}.log`);
|
|
3487
3675
|
await writeFile2(this.filePath, `=== Replicas Engine Session ${this._sessionId} ===
|
|
@@ -3534,14 +3722,14 @@ var EngineLogger = class {
|
|
|
3534
3722
|
var engineLogger = new EngineLogger();
|
|
3535
3723
|
|
|
3536
3724
|
// src/services/replicas-config-service.ts
|
|
3537
|
-
import { readFile as readFile5, appendFile as appendFile2, writeFile as writeFile4, mkdir as
|
|
3725
|
+
import { readFile as readFile5, appendFile as appendFile2, writeFile as writeFile4, mkdir as mkdir6 } from "fs/promises";
|
|
3538
3726
|
import { existsSync as existsSync4 } from "fs";
|
|
3539
3727
|
import { join as join9 } from "path";
|
|
3540
3728
|
import { homedir as homedir7 } from "os";
|
|
3541
3729
|
import { spawn as spawn2 } from "child_process";
|
|
3542
3730
|
|
|
3543
3731
|
// src/services/environment-details-service.ts
|
|
3544
|
-
import { mkdir as
|
|
3732
|
+
import { mkdir as mkdir4, readFile as readFile3 } from "fs/promises";
|
|
3545
3733
|
import { existsSync as existsSync3 } from "fs";
|
|
3546
3734
|
import { homedir as homedir5 } from "os";
|
|
3547
3735
|
import { join as join7 } from "path";
|
|
@@ -3625,7 +3813,7 @@ async function readDetails() {
|
|
|
3625
3813
|
}
|
|
3626
3814
|
}
|
|
3627
3815
|
async function writeDetails(details) {
|
|
3628
|
-
await
|
|
3816
|
+
await mkdir4(REPLICAS_DIR, { recursive: true });
|
|
3629
3817
|
await atomicWriteFile(DETAILS_FILE, `${JSON.stringify(details, null, 2)}
|
|
3630
3818
|
`);
|
|
3631
3819
|
}
|
|
@@ -3711,7 +3899,7 @@ var EnvironmentDetailsService = class {
|
|
|
3711
3899
|
var environmentDetailsService = new EnvironmentDetailsService();
|
|
3712
3900
|
|
|
3713
3901
|
// src/services/start-hook-logs-service.ts
|
|
3714
|
-
import { mkdir as
|
|
3902
|
+
import { mkdir as mkdir5, readFile as readFile4, writeFile as writeFile3, readdir as readdir2 } from "fs/promises";
|
|
3715
3903
|
import { homedir as homedir6 } from "os";
|
|
3716
3904
|
import { join as join8 } from "path";
|
|
3717
3905
|
|
|
@@ -3757,7 +3945,7 @@ function normalizeStored(raw) {
|
|
|
3757
3945
|
}
|
|
3758
3946
|
var StartHookLogsService = class {
|
|
3759
3947
|
async ensureDir() {
|
|
3760
|
-
await
|
|
3948
|
+
await mkdir5(LOGS_DIR, { recursive: true });
|
|
3761
3949
|
}
|
|
3762
3950
|
async saveLog(hookType, hookName, entry) {
|
|
3763
3951
|
await this.ensureDir();
|
|
@@ -3905,7 +4093,7 @@ var ReplicasConfigService = class {
|
|
|
3905
4093
|
const logLine = `[${timestamp}] ${message}
|
|
3906
4094
|
`;
|
|
3907
4095
|
try {
|
|
3908
|
-
await
|
|
4096
|
+
await mkdir6(join9(homedir7(), ".replicas"), { recursive: true });
|
|
3909
4097
|
await appendFile2(START_HOOKS_LOG, logLine, "utf-8");
|
|
3910
4098
|
} catch (error) {
|
|
3911
4099
|
console.error("Failed to write to start hooks log:", error);
|
|
@@ -4040,7 +4228,7 @@ var ReplicasConfigService = class {
|
|
|
4040
4228
|
this.hooksCompleted = false;
|
|
4041
4229
|
this.hooksFailed = false;
|
|
4042
4230
|
try {
|
|
4043
|
-
await
|
|
4231
|
+
await mkdir6(join9(homedir7(), ".replicas"), { recursive: true });
|
|
4044
4232
|
await writeFile4(
|
|
4045
4233
|
START_HOOKS_LOG,
|
|
4046
4234
|
`=== Start Hooks Execution Log ===
|
|
@@ -4234,7 +4422,7 @@ ${startHookConfig.commands.join("\n")}`;
|
|
|
4234
4422
|
var replicasConfigService = new ReplicasConfigService();
|
|
4235
4423
|
|
|
4236
4424
|
// src/services/event-service.ts
|
|
4237
|
-
import { appendFile as appendFile3, mkdir as
|
|
4425
|
+
import { appendFile as appendFile3, mkdir as mkdir7 } from "fs/promises";
|
|
4238
4426
|
import { homedir as homedir8 } from "os";
|
|
4239
4427
|
import { join as join10 } from "path";
|
|
4240
4428
|
import { randomUUID } from "crypto";
|
|
@@ -4244,7 +4432,7 @@ var EventService = class {
|
|
|
4244
4432
|
subscribers = /* @__PURE__ */ new Map();
|
|
4245
4433
|
writeChain = Promise.resolve();
|
|
4246
4434
|
async initialize() {
|
|
4247
|
-
await
|
|
4435
|
+
await mkdir7(ENGINE_DIR, { recursive: true });
|
|
4248
4436
|
}
|
|
4249
4437
|
subscribe(subscriber) {
|
|
4250
4438
|
const id = randomUUID();
|
|
@@ -4274,11 +4462,11 @@ var EventService = class {
|
|
|
4274
4462
|
var eventService = new EventService();
|
|
4275
4463
|
|
|
4276
4464
|
// src/services/preview-service.ts
|
|
4277
|
-
import { mkdir as
|
|
4465
|
+
import { mkdir as mkdir8, readFile as readFile6 } from "fs/promises";
|
|
4278
4466
|
import { existsSync as existsSync5 } from "fs";
|
|
4279
4467
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
4280
4468
|
import { homedir as homedir9 } from "os";
|
|
4281
|
-
import { dirname, join as join11 } from "path";
|
|
4469
|
+
import { dirname as dirname2, join as join11 } from "path";
|
|
4282
4470
|
var PREVIEW_PORTS_FILE = join11(homedir9(), ".replicas", "preview-ports.json");
|
|
4283
4471
|
async function readPreviewsFile() {
|
|
4284
4472
|
try {
|
|
@@ -4292,8 +4480,8 @@ async function readPreviewsFile() {
|
|
|
4292
4480
|
}
|
|
4293
4481
|
}
|
|
4294
4482
|
async function writePreviewsFile(data) {
|
|
4295
|
-
const dir =
|
|
4296
|
-
await
|
|
4483
|
+
const dir = dirname2(PREVIEW_PORTS_FILE);
|
|
4484
|
+
await mkdir8(dir, { recursive: true });
|
|
4297
4485
|
await atomicWriteFile(PREVIEW_PORTS_FILE, `${JSON.stringify(data, null, 2)}
|
|
4298
4486
|
`);
|
|
4299
4487
|
}
|
|
@@ -4390,7 +4578,7 @@ async function registerDesktopPreview() {
|
|
|
4390
4578
|
|
|
4391
4579
|
// src/services/chat/chat-service.ts
|
|
4392
4580
|
import { existsSync as existsSync8 } from "fs";
|
|
4393
|
-
import { appendFile as appendFile5, copyFile, mkdir as
|
|
4581
|
+
import { appendFile as appendFile5, copyFile, mkdir as mkdir12, readFile as readFile9, rename as rename2, rm } from "fs/promises";
|
|
4394
4582
|
import { homedir as homedir13 } from "os";
|
|
4395
4583
|
import { join as join15 } from "path";
|
|
4396
4584
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
@@ -4401,7 +4589,7 @@ import {
|
|
|
4401
4589
|
} from "@anthropic-ai/claude-agent-sdk";
|
|
4402
4590
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
4403
4591
|
import { join as join13 } from "path";
|
|
4404
|
-
import { mkdir as
|
|
4592
|
+
import { mkdir as mkdir10, appendFile as appendFile4 } from "fs/promises";
|
|
4405
4593
|
import { homedir as homedir11 } from "os";
|
|
4406
4594
|
|
|
4407
4595
|
// src/utils/jsonl-reader.ts
|
|
@@ -4907,7 +5095,7 @@ function extractPlanFromCodexAspNotification(notification) {
|
|
|
4907
5095
|
|
|
4908
5096
|
// src/utils/image-utils.ts
|
|
4909
5097
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
4910
|
-
import { mkdir as
|
|
5098
|
+
import { mkdir as mkdir9, unlink as unlink2, writeFile as writeFile5 } from "fs/promises";
|
|
4911
5099
|
import { homedir as homedir10 } from "os";
|
|
4912
5100
|
import { join as join12 } from "path";
|
|
4913
5101
|
function isImageMediaType(value) {
|
|
@@ -4988,7 +5176,7 @@ async function normalizeImages(images) {
|
|
|
4988
5176
|
return normalized;
|
|
4989
5177
|
}
|
|
4990
5178
|
async function saveNormalizedImagesToTempFiles(images, tempImageDir = join12(homedir10(), ".replicas", "codex", "temp-images")) {
|
|
4991
|
-
await
|
|
5179
|
+
await mkdir9(tempImageDir, { recursive: true });
|
|
4992
5180
|
const tempPaths = [];
|
|
4993
5181
|
try {
|
|
4994
5182
|
for (const image of images) {
|
|
@@ -5320,6 +5508,9 @@ function buildClaudeAgentEnv(overrides) {
|
|
|
5320
5508
|
if (shouldStripAnthropicApiKey()) {
|
|
5321
5509
|
env.ANTHROPIC_API_KEY = void 0;
|
|
5322
5510
|
}
|
|
5511
|
+
env.GH_TOKEN = void 0;
|
|
5512
|
+
env.GITHUB_TOKEN = void 0;
|
|
5513
|
+
env.GH_CONFIG_DIR = void 0;
|
|
5323
5514
|
env.CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD = "1";
|
|
5324
5515
|
return env;
|
|
5325
5516
|
}
|
|
@@ -5333,6 +5524,9 @@ function buildCodexAgentEnv() {
|
|
|
5333
5524
|
if (shouldStripOpenAIApiKey()) {
|
|
5334
5525
|
delete env.OPENAI_API_KEY;
|
|
5335
5526
|
}
|
|
5527
|
+
delete env.GH_TOKEN;
|
|
5528
|
+
delete env.GITHUB_TOKEN;
|
|
5529
|
+
delete env.GH_CONFIG_DIR;
|
|
5336
5530
|
return env;
|
|
5337
5531
|
}
|
|
5338
5532
|
function resolveCodexApiKey() {
|
|
@@ -6139,7 +6333,7 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
6139
6333
|
}
|
|
6140
6334
|
async initialize() {
|
|
6141
6335
|
const historyDir = join13(homedir11(), ".replicas", "claude");
|
|
6142
|
-
await
|
|
6336
|
+
await mkdir10(historyDir, { recursive: true });
|
|
6143
6337
|
if (this.initialSessionId) {
|
|
6144
6338
|
this.sessionId = this.initialSessionId;
|
|
6145
6339
|
console.log(`[ClaudeManager] Restored session ID from persisted state: ${this.sessionId}`);
|
|
@@ -6373,7 +6567,7 @@ var AspClient = class {
|
|
|
6373
6567
|
// src/managers/codex-asp/app-server-process.ts
|
|
6374
6568
|
var DEFAULT_CODEX_BINARY = "codex";
|
|
6375
6569
|
var DEFAULT_CODEX_ARGS = ["app-server", "--listen", "stdio://"];
|
|
6376
|
-
var ENGINE_PACKAGE_VERSION = "0.1.
|
|
6570
|
+
var ENGINE_PACKAGE_VERSION = "0.1.264";
|
|
6377
6571
|
var INITIALIZE_METHOD = "initialize";
|
|
6378
6572
|
var INITIALIZED_NOTIFICATION = "initialized";
|
|
6379
6573
|
var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
|
|
@@ -7993,7 +8187,7 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
7993
8187
|
|
|
7994
8188
|
// src/managers/codex-manager.ts
|
|
7995
8189
|
import { Codex } from "@openai/codex-sdk";
|
|
7996
|
-
import { readdir as readdir3, stat as stat2, writeFile as writeFile6, mkdir as
|
|
8190
|
+
import { readdir as readdir3, stat as stat2, writeFile as writeFile6, mkdir as mkdir11, readFile as readFile8 } from "fs/promises";
|
|
7997
8191
|
import { existsSync as existsSync7 } from "fs";
|
|
7998
8192
|
import { join as join14 } from "path";
|
|
7999
8193
|
import { homedir as homedir12 } from "os";
|
|
@@ -8077,7 +8271,7 @@ var CodexManager = class extends CodingAgentManager {
|
|
|
8077
8271
|
async updateCodexConfig(developerInstructions) {
|
|
8078
8272
|
try {
|
|
8079
8273
|
const codexDir = join14(homedir12(), ".codex");
|
|
8080
|
-
await
|
|
8274
|
+
await mkdir11(codexDir, { recursive: true });
|
|
8081
8275
|
let config = {};
|
|
8082
8276
|
if (existsSync7(CODEX_CONFIG_PATH)) {
|
|
8083
8277
|
try {
|
|
@@ -9096,10 +9290,10 @@ var ChatService = class {
|
|
|
9096
9290
|
chats = /* @__PURE__ */ new Map();
|
|
9097
9291
|
writeChain = Promise.resolve();
|
|
9098
9292
|
async initialize() {
|
|
9099
|
-
await
|
|
9100
|
-
await
|
|
9101
|
-
await
|
|
9102
|
-
await
|
|
9293
|
+
await mkdir12(ENGINE_DIR2, { recursive: true });
|
|
9294
|
+
await mkdir12(CLAUDE_HISTORY_DIR, { recursive: true });
|
|
9295
|
+
await mkdir12(RELAY_HISTORY_DIR, { recursive: true });
|
|
9296
|
+
await mkdir12(CHAT_SENDERS_DIR, { recursive: true });
|
|
9103
9297
|
const persisted = await this.loadChats();
|
|
9104
9298
|
for (const chat of persisted) {
|
|
9105
9299
|
const runtime = this.createRuntimeChat(chat);
|
|
@@ -10018,7 +10212,7 @@ import { existsSync as existsSync9 } from "fs";
|
|
|
10018
10212
|
import { join as join19 } from "path";
|
|
10019
10213
|
|
|
10020
10214
|
// src/services/warm-hook-logs-service.ts
|
|
10021
|
-
import { mkdir as
|
|
10215
|
+
import { mkdir as mkdir13, readFile as readFile12, writeFile as writeFile7, readdir as readdir5, appendFile as appendFile6, unlink as unlink3 } from "fs/promises";
|
|
10022
10216
|
import { homedir as homedir15 } from "os";
|
|
10023
10217
|
import { join as join18 } from "path";
|
|
10024
10218
|
var LOGS_DIR2 = join18(homedir15(), ".replicas", "warm-hook-logs");
|
|
@@ -10030,7 +10224,7 @@ function withPreview2(stored) {
|
|
|
10030
10224
|
}
|
|
10031
10225
|
var WarmHookLogsService = class {
|
|
10032
10226
|
async ensureDir() {
|
|
10033
|
-
await
|
|
10227
|
+
await mkdir13(LOGS_DIR2, { recursive: true });
|
|
10034
10228
|
}
|
|
10035
10229
|
async saveGlobalHookLog(entry) {
|
|
10036
10230
|
await this.ensureDir();
|