@mindstudio-ai/remy 0.1.268 → 0.1.270
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -18
- package/dist/headless.js +166 -220
- package/dist/index.js +140 -181
- package/dist/prompt/compiled/auth.md +20 -415
- package/dist/prompt/compiled/design.md +4 -2
- package/dist/prompt/compiled/dev-and-deploy.md +1 -8
- package/dist/prompt/compiled/interfaces.md +9 -27
- package/dist/prompt/compiled/methods.md +3 -37
- package/dist/prompt/compiled/msfm.md +1 -16
- package/dist/prompt/compiled/platform.md +7 -17
- package/dist/prompt/skills/auth.md +443 -0
- package/dist/prompt/{compiled → skills}/files.md +6 -0
- package/dist/prompt/{compiled → skills}/scenarios.md +6 -0
- package/dist/prompt/{compiled → skills}/secrets.md +6 -0
- package/dist/prompt/skills/voiceInterfaces.md +30 -10
- package/dist/prompt/static/authoring.md +1 -1
- package/dist/prompt/static/coding.md +4 -2
- package/dist/prompt/static/intake.md +1 -4
- package/dist/prompt/static/spec-maintenance.md +41 -0
- package/dist/prompt/static/team.md +1 -1
- package/package.json +1 -1
package/dist/headless.js
CHANGED
|
@@ -618,7 +618,6 @@ function readJsonAsset(fallback, ...segments) {
|
|
|
618
618
|
|
|
619
619
|
// src/prompt/static/projectContext.ts
|
|
620
620
|
import fs4 from "fs";
|
|
621
|
-
import path3 from "path";
|
|
622
621
|
|
|
623
622
|
// src/projectRoot.ts
|
|
624
623
|
var PROJECT_ROOT = process.cwd();
|
|
@@ -629,80 +628,25 @@ function loadProjectRoot() {
|
|
|
629
628
|
## Project Root
|
|
630
629
|
\`${PROJECT_ROOT}\`
|
|
631
630
|
|
|
632
|
-
File paths are relative to this directory. Every tool operates here and bash commands run
|
|
633
|
-
}
|
|
634
|
-
function loadProjectManifest() {
|
|
635
|
-
try {
|
|
636
|
-
const manifest = fs4.readFileSync("mindstudio.json", "utf-8");
|
|
637
|
-
return `
|
|
638
|
-
## Project Manifest (mindstudio.json)
|
|
639
|
-
\`\`\`json
|
|
640
|
-
${manifest}
|
|
641
|
-
\`\`\``;
|
|
642
|
-
} catch {
|
|
643
|
-
return "";
|
|
644
|
-
}
|
|
631
|
+
File paths are relative to this directory. Every tool operates here and bash commands run in it.`;
|
|
645
632
|
}
|
|
646
|
-
function
|
|
633
|
+
function loadAppIdentity() {
|
|
647
634
|
try {
|
|
648
|
-
const
|
|
649
|
-
|
|
635
|
+
const manifest = JSON.parse(fs4.readFileSync("mindstudio.json", "utf-8"));
|
|
636
|
+
const name = typeof manifest.name === "string" ? manifest.name.trim() : "";
|
|
637
|
+
if (!name) {
|
|
650
638
|
return "";
|
|
651
639
|
}
|
|
652
|
-
const
|
|
653
|
-
for (const filePath of files) {
|
|
654
|
-
const { name, description, type } = parseFrontmatter(filePath);
|
|
655
|
-
let line = `- ${filePath}`;
|
|
656
|
-
if (name) {
|
|
657
|
-
line += ` \u2014 "${name}"`;
|
|
658
|
-
}
|
|
659
|
-
if (type) {
|
|
660
|
-
line += ` (${type})`;
|
|
661
|
-
}
|
|
662
|
-
if (description) {
|
|
663
|
-
line += ` \u2014 ${description}`;
|
|
664
|
-
}
|
|
665
|
-
entries.push(line);
|
|
666
|
-
}
|
|
640
|
+
const description = typeof manifest.description === "string" ? manifest.description.trim() : "";
|
|
667
641
|
return `
|
|
668
|
-
##
|
|
669
|
-
${
|
|
642
|
+
## App
|
|
643
|
+
"${name}"${description ? ` \u2014 ${description}` : ""}
|
|
644
|
+
|
|
645
|
+
Full manifest: \`mindstudio.json\` (read it when you need the app's structure, tables, methods, roles, auth settings, interfaces, and everything else).`;
|
|
670
646
|
} catch {
|
|
671
647
|
return "";
|
|
672
648
|
}
|
|
673
649
|
}
|
|
674
|
-
function walkMdFiles(dir) {
|
|
675
|
-
const results = [];
|
|
676
|
-
try {
|
|
677
|
-
const entries = fs4.readdirSync(dir, { withFileTypes: true });
|
|
678
|
-
for (const entry of entries) {
|
|
679
|
-
const full = path3.join(dir, entry.name);
|
|
680
|
-
if (entry.isDirectory()) {
|
|
681
|
-
results.push(...walkMdFiles(full));
|
|
682
|
-
} else if (entry.name.endsWith(".md")) {
|
|
683
|
-
results.push(full);
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
} catch {
|
|
687
|
-
}
|
|
688
|
-
return results.sort();
|
|
689
|
-
}
|
|
690
|
-
function parseFrontmatter(filePath) {
|
|
691
|
-
try {
|
|
692
|
-
const content = fs4.readFileSync(filePath, "utf-8");
|
|
693
|
-
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
694
|
-
if (!match) {
|
|
695
|
-
return { name: "", description: "", type: "" };
|
|
696
|
-
}
|
|
697
|
-
const fm = match[1];
|
|
698
|
-
const name = fm.match(/^name:\s*(.+)$/m)?.[1]?.trim() ?? "";
|
|
699
|
-
const description = fm.match(/^description:\s*(.+)$/m)?.[1]?.trim() ?? "";
|
|
700
|
-
const type = fm.match(/^type:\s*(.+)$/m)?.[1]?.trim() ?? "";
|
|
701
|
-
return { name, description, type };
|
|
702
|
-
} catch {
|
|
703
|
-
return { name: "", description: "", type: "" };
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
650
|
function loadPlanStatus(onboardingState) {
|
|
707
651
|
try {
|
|
708
652
|
const content = fs4.readFileSync(".remy-plan.md", "utf-8");
|
|
@@ -731,33 +675,12 @@ The user has approved your implementation plan in .remy-plan.md. You may referen
|
|
|
731
675
|
return "";
|
|
732
676
|
}
|
|
733
677
|
}
|
|
734
|
-
function loadProjectFileListing() {
|
|
735
|
-
try {
|
|
736
|
-
const entries = fs4.readdirSync(".", { withFileTypes: true });
|
|
737
|
-
const listing = entries.filter((e) => e.name !== ".git" && e.name !== "node_modules").sort((a, b) => {
|
|
738
|
-
if (a.isDirectory() && !b.isDirectory()) {
|
|
739
|
-
return -1;
|
|
740
|
-
}
|
|
741
|
-
if (!a.isDirectory() && b.isDirectory()) {
|
|
742
|
-
return 1;
|
|
743
|
-
}
|
|
744
|
-
return a.name.localeCompare(b.name);
|
|
745
|
-
}).map((e) => e.isDirectory() ? `${e.name}/` : e.name).join("\n");
|
|
746
|
-
return `
|
|
747
|
-
## Project Files
|
|
748
|
-
\`\`\`
|
|
749
|
-
${listing}
|
|
750
|
-
\`\`\``;
|
|
751
|
-
} catch {
|
|
752
|
-
return "";
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
678
|
|
|
756
679
|
// src/prompt/skills/catalog.ts
|
|
757
680
|
import fs5 from "fs";
|
|
758
|
-
import
|
|
681
|
+
import path3 from "path";
|
|
759
682
|
var SKILLS_DIR = assetPath("prompt", "skills");
|
|
760
|
-
function
|
|
683
|
+
function parseFrontmatter(content) {
|
|
761
684
|
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
762
685
|
if (!match) {
|
|
763
686
|
return {};
|
|
@@ -780,9 +703,9 @@ function loadCatalog() {
|
|
|
780
703
|
}
|
|
781
704
|
const skills = [];
|
|
782
705
|
for (const file of files.sort()) {
|
|
783
|
-
const full =
|
|
706
|
+
const full = path3.join(SKILLS_DIR, file);
|
|
784
707
|
const id = file.replace(/\.md$/, "");
|
|
785
|
-
const fields =
|
|
708
|
+
const fields = parseFrontmatter(fs5.readFileSync(full, "utf-8"));
|
|
786
709
|
if (!fields.name || !fields.what || !fields.when) {
|
|
787
710
|
continue;
|
|
788
711
|
}
|
|
@@ -836,13 +759,7 @@ function resolveIncludes(template) {
|
|
|
836
759
|
);
|
|
837
760
|
return result.replace(/\n{3,}/g, "\n\n").trim();
|
|
838
761
|
}
|
|
839
|
-
function buildSystemPrompt(onboardingState
|
|
840
|
-
const projectContext = [
|
|
841
|
-
loadProjectRoot(),
|
|
842
|
-
loadProjectManifest(),
|
|
843
|
-
loadSpecFileMetadata(),
|
|
844
|
-
loadProjectFileListing()
|
|
845
|
-
].filter(Boolean).join("\n");
|
|
762
|
+
function buildSystemPrompt(onboardingState) {
|
|
846
763
|
const now = (/* @__PURE__ */ new Date()).toLocaleDateString("en-US", {
|
|
847
764
|
month: "long",
|
|
848
765
|
day: "numeric",
|
|
@@ -851,8 +768,6 @@ function buildSystemPrompt(onboardingState, viewContext) {
|
|
|
851
768
|
const template = `
|
|
852
769
|
{{static/identity.md}}
|
|
853
770
|
|
|
854
|
-
Current date: ${now}
|
|
855
|
-
|
|
856
771
|
<platform_docs>
|
|
857
772
|
<platform>
|
|
858
773
|
{{compiled/platform.md}}
|
|
@@ -882,21 +797,9 @@ Current date: ${now}
|
|
|
882
797
|
{{compiled/design.md}}
|
|
883
798
|
</design>
|
|
884
799
|
|
|
885
|
-
<app_files>
|
|
886
|
-
{{compiled/files.md}}
|
|
887
|
-
</app_files>
|
|
888
|
-
|
|
889
800
|
<interfaces>
|
|
890
801
|
{{compiled/interfaces.md}}
|
|
891
802
|
</interfaces>
|
|
892
|
-
|
|
893
|
-
<scenarios>
|
|
894
|
-
{{compiled/scenarios.md}}
|
|
895
|
-
</scenarios>
|
|
896
|
-
|
|
897
|
-
<secrets>
|
|
898
|
-
{{compiled/secrets.md}}
|
|
899
|
-
</secrets>
|
|
900
803
|
</platform_docs>
|
|
901
804
|
|
|
902
805
|
${loadSkillsCatalog()}
|
|
@@ -909,12 +812,12 @@ ${loadSkillsCatalog()}
|
|
|
909
812
|
{{compiled/msfm.md}}
|
|
910
813
|
</mindstudio_flavored_markdown_spec_docs>
|
|
911
814
|
|
|
912
|
-
|
|
815
|
+
${onboardingState === "intake" ? `<intake_mode_instructions>
|
|
913
816
|
{{static/intake.md}}
|
|
914
|
-
</intake_mode_instructions
|
|
817
|
+
</intake_mode_instructions>` : ""}
|
|
915
818
|
|
|
916
819
|
<spec_authoring_instructions>
|
|
917
|
-
{{static/authoring.md}}
|
|
820
|
+
${onboardingState !== void 0 && onboardingState !== "onboardingFinished" ? "{{static/authoring.md}}" : "{{static/spec-maintenance.md}}"}
|
|
918
821
|
</spec_authoring_instructions>
|
|
919
822
|
|
|
920
823
|
<team>
|
|
@@ -932,11 +835,11 @@ ${loadSkillsCatalog()}
|
|
|
932
835
|
<conversation_summaries>
|
|
933
836
|
Your conversation history may include <prior_conversation_summary> blocks in the user's messages. These are automated summaries of earlier messages that have been compacted to save context space. The user does not see this summary, they see the full conversation history in their UI. Treat the summary as ground truth for what happened before, but do not reference it directly to the user ("as mentioned in the summary..."). Just continue naturally as if you remember the prior work.
|
|
934
837
|
|
|
935
|
-
|
|
838
|
+
Tool results generally persist in the conversation until a compaction summarizes them. In rare cases very old tool results may be trimmed when the conversation nears the context limit. Either way, if you need something from an earlier tool call and can't see it anymore, just re-read the file or re-run the query.
|
|
936
839
|
</conversation_summaries>
|
|
937
840
|
|
|
938
841
|
<project_onboarding>
|
|
939
|
-
New projects progress through
|
|
842
|
+
New projects progress through four onboarding states. The user might skip this entirely and jump straight into working on the existing scaffold (which defaults to onboardingFinished), but ideally new projects move through each phase:
|
|
940
843
|
|
|
941
844
|
- **intake**: Gathering requirements. The project has scaffold code (a "hello world" starter) but it's not the user's app yet. Focus on understanding what they want to build, not on the existing code. Intake ends with a plan proposal via writePlan.
|
|
942
845
|
- **building**: The user approved the initial plan. The agent is writing the spec and building the app. This can take a while and involves heavy tool use (spec authoring, design expert consultation, code generation, verification, polishing).
|
|
@@ -944,24 +847,21 @@ New projects progress through three onboarding states. The user might skip this
|
|
|
944
847
|
- **onboardingFinished**: The project is built and ready. Full development mode with all tools available. From here on, keep spec and code in sync as changes are made.
|
|
945
848
|
</project_onboarding>
|
|
946
849
|
|
|
850
|
+
${loadProjectRoot()}
|
|
851
|
+
|
|
852
|
+
${renderOrgContextBlock()}
|
|
853
|
+
|
|
947
854
|
{{static/instructions.md}}
|
|
948
855
|
|
|
949
856
|
<!-- cache_breakpoint -->
|
|
950
857
|
|
|
858
|
+
Current date: ${now}
|
|
859
|
+
|
|
951
860
|
<current_project_onboarding_state>
|
|
952
861
|
${onboardingState ?? "onboardingFinished"}
|
|
953
862
|
</current_project_onboarding_state>
|
|
954
863
|
|
|
955
|
-
|
|
956
|
-
${projectContext}
|
|
957
|
-
</project_context>
|
|
958
|
-
|
|
959
|
-
${renderOrgContextBlock()}
|
|
960
|
-
|
|
961
|
-
<view_context>
|
|
962
|
-
The user is currently in ${viewContext?.mode ?? "code"} mode.
|
|
963
|
-
${viewContext?.activeFile ? `Active file: ${viewContext.activeFile}` : ""}
|
|
964
|
-
</view_context>
|
|
864
|
+
${loadAppIdentity()}
|
|
965
865
|
|
|
966
866
|
${loadPlanStatus(onboardingState)}
|
|
967
867
|
`;
|
|
@@ -1100,7 +1000,7 @@ var readSpecTool = {
|
|
|
1100
1000
|
|
|
1101
1001
|
// src/tools/spec/writeSpec.ts
|
|
1102
1002
|
import fs7 from "fs/promises";
|
|
1103
|
-
import
|
|
1003
|
+
import path4 from "path";
|
|
1104
1004
|
|
|
1105
1005
|
// src/tools/_helpers/diff.ts
|
|
1106
1006
|
var CONTEXT_LINES = 3;
|
|
@@ -1189,7 +1089,7 @@ ${unifiedDiff(partial.path, oldContent, partial.content)}`;
|
|
|
1189
1089
|
}
|
|
1190
1090
|
const release = await acquireFileLock(input.path);
|
|
1191
1091
|
try {
|
|
1192
|
-
await fs7.mkdir(
|
|
1092
|
+
await fs7.mkdir(path4.dirname(input.path), { recursive: true });
|
|
1193
1093
|
let oldContent = null;
|
|
1194
1094
|
try {
|
|
1195
1095
|
oldContent = await fs7.readFile(input.path, "utf-8");
|
|
@@ -1394,7 +1294,7 @@ var editSpecTool = {
|
|
|
1394
1294
|
|
|
1395
1295
|
// src/tools/spec/listSpecFiles.ts
|
|
1396
1296
|
import fs9 from "fs/promises";
|
|
1397
|
-
import
|
|
1297
|
+
import path5 from "path";
|
|
1398
1298
|
var listSpecFilesTool = {
|
|
1399
1299
|
definition: {
|
|
1400
1300
|
name: "listSpecFiles",
|
|
@@ -1433,7 +1333,7 @@ async function listRecursive(dir) {
|
|
|
1433
1333
|
return a.name.localeCompare(b.name);
|
|
1434
1334
|
});
|
|
1435
1335
|
for (const entry of entries) {
|
|
1436
|
-
const fullPath =
|
|
1336
|
+
const fullPath = path5.join(dir, entry.name);
|
|
1437
1337
|
if (entry.isDirectory()) {
|
|
1438
1338
|
results.push(`${fullPath}/`);
|
|
1439
1339
|
results.push(...await listRecursive(fullPath));
|
|
@@ -1466,8 +1366,33 @@ var presentPublishPlanTool = {
|
|
|
1466
1366
|
}
|
|
1467
1367
|
};
|
|
1468
1368
|
|
|
1369
|
+
// src/atomicWrite.ts
|
|
1370
|
+
import fs10 from "fs";
|
|
1371
|
+
import fsp from "fs/promises";
|
|
1372
|
+
var writeFileAtomicSync = (file, data) => {
|
|
1373
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
1374
|
+
const fd2 = fs10.openSync(tmp, "w");
|
|
1375
|
+
try {
|
|
1376
|
+
fs10.writeSync(fd2, data);
|
|
1377
|
+
fs10.fsyncSync(fd2);
|
|
1378
|
+
} finally {
|
|
1379
|
+
fs10.closeSync(fd2);
|
|
1380
|
+
}
|
|
1381
|
+
fs10.renameSync(tmp, file);
|
|
1382
|
+
};
|
|
1383
|
+
var writeFileAtomic = async (file, data) => {
|
|
1384
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
1385
|
+
const handle = await fsp.open(tmp, "w");
|
|
1386
|
+
try {
|
|
1387
|
+
await handle.writeFile(data);
|
|
1388
|
+
await handle.sync();
|
|
1389
|
+
} finally {
|
|
1390
|
+
await handle.close();
|
|
1391
|
+
}
|
|
1392
|
+
await fsp.rename(tmp, file);
|
|
1393
|
+
};
|
|
1394
|
+
|
|
1469
1395
|
// src/tools/spec/writePlan.ts
|
|
1470
|
-
import fs10 from "fs/promises";
|
|
1471
1396
|
var PLAN_FILE = ".remy-plan.md";
|
|
1472
1397
|
var writePlanTool = {
|
|
1473
1398
|
definition: {
|
|
@@ -1491,7 +1416,7 @@ status: pending
|
|
|
1491
1416
|
---
|
|
1492
1417
|
|
|
1493
1418
|
${content}`;
|
|
1494
|
-
await
|
|
1419
|
+
await writeFileAtomic(PLAN_FILE, file);
|
|
1495
1420
|
return "Plan written to .remy-plan.md. Waiting for user approval.";
|
|
1496
1421
|
}
|
|
1497
1422
|
};
|
|
@@ -1527,13 +1452,13 @@ var updatePlanStatusTool = {
|
|
|
1527
1452
|
return "No plan file found.";
|
|
1528
1453
|
}
|
|
1529
1454
|
if (status === "rejected") {
|
|
1530
|
-
await fs11.unlink(PLAN_FILE2)
|
|
1455
|
+
await fs11.unlink(PLAN_FILE2).catch(() => {
|
|
1456
|
+
});
|
|
1531
1457
|
return "Plan rejected and removed.";
|
|
1532
1458
|
}
|
|
1533
|
-
await
|
|
1459
|
+
await writeFileAtomic(
|
|
1534
1460
|
PLAN_FILE2,
|
|
1535
|
-
content.replace(/^status:\s*\w+/m, `status: ${status}`)
|
|
1536
|
-
"utf-8"
|
|
1461
|
+
content.replace(/^status:\s*\w+/m, `status: ${status}`)
|
|
1537
1462
|
);
|
|
1538
1463
|
return "Plan approved. Proceeding with implementation.";
|
|
1539
1464
|
}
|
|
@@ -2271,7 +2196,7 @@ var readFileTool = {
|
|
|
2271
2196
|
|
|
2272
2197
|
// src/tools/code/writeFile.ts
|
|
2273
2198
|
import fs14 from "fs/promises";
|
|
2274
|
-
import
|
|
2199
|
+
import path6 from "path";
|
|
2275
2200
|
var writeFileTool = {
|
|
2276
2201
|
definition: {
|
|
2277
2202
|
name: "writeFile",
|
|
@@ -2316,7 +2241,7 @@ ${unifiedDiff(partial.path, oldContent, completeContent)}`;
|
|
|
2316
2241
|
async execute(input) {
|
|
2317
2242
|
const release = await acquireFileLock(input.path);
|
|
2318
2243
|
try {
|
|
2319
|
-
await fs14.mkdir(
|
|
2244
|
+
await fs14.mkdir(path6.dirname(input.path), { recursive: true });
|
|
2320
2245
|
let oldContent = null;
|
|
2321
2246
|
try {
|
|
2322
2247
|
oldContent = await fs14.readFile(input.path, "utf-8");
|
|
@@ -2425,7 +2350,7 @@ ${unifiedDiff(input.path, content, updated)}`;
|
|
|
2425
2350
|
|
|
2426
2351
|
// src/tools/code/bash.ts
|
|
2427
2352
|
import { spawn as spawn2 } from "child_process";
|
|
2428
|
-
import
|
|
2353
|
+
import path7 from "path";
|
|
2429
2354
|
var DEFAULT_TIMEOUT_MS = 12e4;
|
|
2430
2355
|
var DEFAULT_MAX_LINES2 = 500;
|
|
2431
2356
|
var MAX_OUTPUT_BYTES = 3e4;
|
|
@@ -2463,7 +2388,7 @@ var bashTool = {
|
|
|
2463
2388
|
const child = spawn2("sh", ["-c", input.command], {
|
|
2464
2389
|
// Pinned rather than inherited. `undefined` here means "wherever the
|
|
2465
2390
|
// process happens to be", which is the project root only by luck.
|
|
2466
|
-
cwd: input.cwd ?
|
|
2391
|
+
cwd: input.cwd ? path7.resolve(PROJECT_ROOT, input.cwd) : PROJECT_ROOT,
|
|
2467
2392
|
env: { ...process.env, FORCE_COLOR: "1" }
|
|
2468
2393
|
});
|
|
2469
2394
|
let output = "";
|
|
@@ -2707,7 +2632,7 @@ var globTool = {
|
|
|
2707
2632
|
|
|
2708
2633
|
// src/tools/code/listDir.ts
|
|
2709
2634
|
import fs16 from "fs/promises";
|
|
2710
|
-
import
|
|
2635
|
+
import path8 from "path";
|
|
2711
2636
|
var EXCLUDE = /* @__PURE__ */ new Set([".git", "node_modules"]);
|
|
2712
2637
|
var MAX_CHILDREN = 15;
|
|
2713
2638
|
async function readAndSort(dirPath) {
|
|
@@ -2724,7 +2649,7 @@ async function readAndSort(dirPath) {
|
|
|
2724
2649
|
}
|
|
2725
2650
|
async function collapsePath(basePath, name) {
|
|
2726
2651
|
let display = name;
|
|
2727
|
-
let current =
|
|
2652
|
+
let current = path8.join(basePath, name);
|
|
2728
2653
|
for (; ; ) {
|
|
2729
2654
|
let children;
|
|
2730
2655
|
try {
|
|
@@ -2734,7 +2659,7 @@ async function collapsePath(basePath, name) {
|
|
|
2734
2659
|
}
|
|
2735
2660
|
if (children.length === 1 && children[0].isDirectory()) {
|
|
2736
2661
|
display += "/" + children[0].name;
|
|
2737
|
-
current =
|
|
2662
|
+
current = path8.join(current, children[0].name);
|
|
2738
2663
|
} else {
|
|
2739
2664
|
break;
|
|
2740
2665
|
}
|
|
@@ -2752,7 +2677,7 @@ function formatSize(bytes) {
|
|
|
2752
2677
|
}
|
|
2753
2678
|
async function formatFile(dirPath, name, indent) {
|
|
2754
2679
|
try {
|
|
2755
|
-
const stat2 = await fs16.stat(
|
|
2680
|
+
const stat2 = await fs16.stat(path8.join(dirPath, name));
|
|
2756
2681
|
return `${indent}${name}${" ".repeat(Math.max(1, 30 - indent.length - name.length))}${formatSize(stat2.size)}`;
|
|
2757
2682
|
} catch {
|
|
2758
2683
|
return `${indent}${name}`;
|
|
@@ -3063,7 +2988,8 @@ var CONTENT_TYPES = {
|
|
|
3063
2988
|
".jpg": "image/jpeg",
|
|
3064
2989
|
".jpeg": "image/jpeg",
|
|
3065
2990
|
".gif": "image/gif",
|
|
3066
|
-
".webp": "image/webp"
|
|
2991
|
+
".webp": "image/webp",
|
|
2992
|
+
".svg": "image/svg+xml"
|
|
3067
2993
|
};
|
|
3068
2994
|
var hosted = /* @__PURE__ */ new Map();
|
|
3069
2995
|
function isFetchableUrl(ref) {
|
|
@@ -3215,7 +3141,7 @@ async function captureAndAnalyzeScreenshot(promptOrOptions) {
|
|
|
3215
3141
|
let onLog;
|
|
3216
3142
|
let model;
|
|
3217
3143
|
let apiConfig;
|
|
3218
|
-
let
|
|
3144
|
+
let path13;
|
|
3219
3145
|
let fullPage = true;
|
|
3220
3146
|
let width;
|
|
3221
3147
|
let height;
|
|
@@ -3223,7 +3149,7 @@ async function captureAndAnalyzeScreenshot(promptOrOptions) {
|
|
|
3223
3149
|
if (typeof promptOrOptions === "object" && promptOrOptions !== null) {
|
|
3224
3150
|
prompt = promptOrOptions.prompt;
|
|
3225
3151
|
existingImage = promptOrOptions.image;
|
|
3226
|
-
|
|
3152
|
+
path13 = promptOrOptions.path;
|
|
3227
3153
|
if (promptOrOptions.fullPage !== void 0) {
|
|
3228
3154
|
fullPage = promptOrOptions.fullPage;
|
|
3229
3155
|
}
|
|
@@ -3247,7 +3173,7 @@ async function captureAndAnalyzeScreenshot(promptOrOptions) {
|
|
|
3247
3173
|
const ssResult = await sidecarRequest(
|
|
3248
3174
|
fullPage ? "/screenshot-full-page" : "/screenshot-viewport",
|
|
3249
3175
|
{
|
|
3250
|
-
...
|
|
3176
|
+
...path13 ? { path: path13 } : {},
|
|
3251
3177
|
...width != null ? { width } : {},
|
|
3252
3178
|
...height != null ? { height } : {},
|
|
3253
3179
|
...format ? { format } : {}
|
|
@@ -3670,7 +3596,8 @@ async function runSubAgent(config) {
|
|
|
3670
3596
|
background,
|
|
3671
3597
|
acquireLock,
|
|
3672
3598
|
onBackgroundComplete,
|
|
3673
|
-
captureArtifacts
|
|
3599
|
+
captureArtifacts,
|
|
3600
|
+
cachePolicy = "run"
|
|
3674
3601
|
} = config;
|
|
3675
3602
|
const artifacts = {};
|
|
3676
3603
|
const bgAbort = background ? new AbortController() : null;
|
|
@@ -3765,6 +3692,7 @@ ${partial}` : "[INTERRUPTED] Agent was interrupted before producing output.",
|
|
|
3765
3692
|
system: fullSystem,
|
|
3766
3693
|
messages: cleanMessagesForApi(messages),
|
|
3767
3694
|
tools: tools2,
|
|
3695
|
+
cachePolicy,
|
|
3768
3696
|
signal
|
|
3769
3697
|
},
|
|
3770
3698
|
{
|
|
@@ -4250,15 +4178,15 @@ var BROWSER_EXTERNAL_TOOLS = /* @__PURE__ */ new Set(["browserCommand"]);
|
|
|
4250
4178
|
|
|
4251
4179
|
// src/subagents/common/context.ts
|
|
4252
4180
|
import fs17 from "fs";
|
|
4253
|
-
import
|
|
4254
|
-
function
|
|
4181
|
+
import path9 from "path";
|
|
4182
|
+
function walkMdFiles(dir, skip) {
|
|
4255
4183
|
const files = [];
|
|
4256
4184
|
try {
|
|
4257
4185
|
for (const entry of fs17.readdirSync(dir, { withFileTypes: true })) {
|
|
4258
|
-
const full =
|
|
4186
|
+
const full = path9.join(dir, entry.name);
|
|
4259
4187
|
if (entry.isDirectory()) {
|
|
4260
4188
|
if (!skip?.has(entry.name)) {
|
|
4261
|
-
files.push(...
|
|
4189
|
+
files.push(...walkMdFiles(full, skip));
|
|
4262
4190
|
}
|
|
4263
4191
|
} else if (entry.name.endsWith(".md")) {
|
|
4264
4192
|
files.push(full);
|
|
@@ -4268,7 +4196,7 @@ function walkMdFiles2(dir, skip) {
|
|
|
4268
4196
|
}
|
|
4269
4197
|
return files.sort();
|
|
4270
4198
|
}
|
|
4271
|
-
function
|
|
4199
|
+
function parseFrontmatter2(filePath) {
|
|
4272
4200
|
try {
|
|
4273
4201
|
const content = fs17.readFileSync(filePath, "utf-8");
|
|
4274
4202
|
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
@@ -4290,12 +4218,12 @@ function parseFrontmatter3(filePath) {
|
|
|
4290
4218
|
}
|
|
4291
4219
|
}
|
|
4292
4220
|
function loadSpecIndex() {
|
|
4293
|
-
const files =
|
|
4221
|
+
const files = walkMdFiles("src", /* @__PURE__ */ new Set(["roadmap"]));
|
|
4294
4222
|
if (files.length === 0) {
|
|
4295
4223
|
return "";
|
|
4296
4224
|
}
|
|
4297
4225
|
const lines = files.map((f) => {
|
|
4298
|
-
const fm =
|
|
4226
|
+
const fm = parseFrontmatter2(f);
|
|
4299
4227
|
let line = `- ${f}`;
|
|
4300
4228
|
if (fm.name) {
|
|
4301
4229
|
line += ` \u2014 "${fm.name}"`;
|
|
@@ -4333,10 +4261,10 @@ ${indexJson.standalone.map((s) => `- ${s}`).join("\n")}`
|
|
|
4333
4261
|
}
|
|
4334
4262
|
} catch {
|
|
4335
4263
|
}
|
|
4336
|
-
const files =
|
|
4264
|
+
const files = walkMdFiles("src/roadmap");
|
|
4337
4265
|
if (files.length > 0) {
|
|
4338
4266
|
const lines = files.map((f) => {
|
|
4339
|
-
const fm =
|
|
4267
|
+
const fm = parseFrontmatter2(f);
|
|
4340
4268
|
let line = `- ${f}`;
|
|
4341
4269
|
if (fm.name) {
|
|
4342
4270
|
line += ` \u2014 "${fm.name}"`;
|
|
@@ -5331,7 +5259,7 @@ function load() {
|
|
|
5331
5259
|
}
|
|
5332
5260
|
function save(indices) {
|
|
5333
5261
|
try {
|
|
5334
|
-
|
|
5262
|
+
writeFileAtomicSync(SAMPLE_FILE, JSON.stringify(indices));
|
|
5335
5263
|
} catch {
|
|
5336
5264
|
}
|
|
5337
5265
|
}
|
|
@@ -5582,6 +5510,8 @@ async function runDesignExpert(opts, context) {
|
|
|
5582
5510
|
}),
|
|
5583
5511
|
task: opts.task,
|
|
5584
5512
|
history: history.length > 0 ? history : void 0,
|
|
5513
|
+
// History-carrying thread re-sent across parent turns — 1h-TTL profile.
|
|
5514
|
+
cachePolicy: "conversation",
|
|
5585
5515
|
tools: opts.render ? DESIGN_EXPERT_RENDER_TOOLS : DESIGN_EXPERT_TOOLS,
|
|
5586
5516
|
externalTools: /* @__PURE__ */ new Set(),
|
|
5587
5517
|
executeTool: (name, input, toolCallId, onLog, sams) => {
|
|
@@ -5705,14 +5635,14 @@ var VISION_TOOLS = [
|
|
|
5705
5635
|
|
|
5706
5636
|
// src/subagents/productVision/executor.ts
|
|
5707
5637
|
import fs19 from "fs";
|
|
5708
|
-
import
|
|
5638
|
+
import path10 from "path";
|
|
5709
5639
|
var ROADMAP_DIR = "src/roadmap";
|
|
5710
5640
|
var PITCH_DECK_SHELL = readAsset(
|
|
5711
5641
|
"subagents/productVision",
|
|
5712
5642
|
"pitch-deck-shell.html"
|
|
5713
5643
|
);
|
|
5714
5644
|
function resolve2(filePath) {
|
|
5715
|
-
return
|
|
5645
|
+
return path10.join(ROADMAP_DIR, filePath);
|
|
5716
5646
|
}
|
|
5717
5647
|
async function executeVisionTool(name, input, context) {
|
|
5718
5648
|
switch (name) {
|
|
@@ -5849,6 +5779,8 @@ var productVisionTool = {
|
|
|
5849
5779
|
system: getProductVisionPrompt(),
|
|
5850
5780
|
task: input.task,
|
|
5851
5781
|
history: history.length > 0 ? history : void 0,
|
|
5782
|
+
// History-carrying thread re-sent across parent turns — 1h-TTL profile.
|
|
5783
|
+
cachePolicy: "conversation",
|
|
5852
5784
|
tools: VISION_TOOLS,
|
|
5853
5785
|
externalTools: /* @__PURE__ */ new Set(),
|
|
5854
5786
|
executeTool: (name, input2, toolCallId, _onLog, sams) => {
|
|
@@ -6316,7 +6248,7 @@ var SUBAGENT_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
|
6316
6248
|
"runAutomatedBrowserTest",
|
|
6317
6249
|
"askMindStudioSdk"
|
|
6318
6250
|
]);
|
|
6319
|
-
function getToolDefinitions(
|
|
6251
|
+
function getToolDefinitions() {
|
|
6320
6252
|
return ALL_TOOLS.map((t) => t.definition);
|
|
6321
6253
|
}
|
|
6322
6254
|
function getToolByName(name) {
|
|
@@ -6700,7 +6632,11 @@ Write the summary of the conversation above, following your instructions.`;
|
|
|
6700
6632
|
messages: [{ role: "user", content: userContent }],
|
|
6701
6633
|
// Always empty. With a toolset available the model picks `tool_use` over
|
|
6702
6634
|
// producing a summary, leaving summaryText empty.
|
|
6703
|
-
tools: []
|
|
6635
|
+
tools: [],
|
|
6636
|
+
// Each summary call carries a unique 100-200KB chunk that is never
|
|
6637
|
+
// re-read (parallel siblings can't read each other's in-flight writes
|
|
6638
|
+
// either) — a cache write here is pure waste.
|
|
6639
|
+
cachePolicy: "oneshot"
|
|
6704
6640
|
})) {
|
|
6705
6641
|
if (event.type === "text") {
|
|
6706
6642
|
summaryText += event.text;
|
|
@@ -6732,15 +6668,10 @@ Write the summary of the conversation above, following your instructions.`;
|
|
|
6732
6668
|
|
|
6733
6669
|
// src/session.ts
|
|
6734
6670
|
import fs21 from "fs";
|
|
6735
|
-
import
|
|
6671
|
+
import path11 from "path";
|
|
6736
6672
|
var log10 = createLogger("session");
|
|
6737
6673
|
var SESSION_FILE = ".remy-session.json";
|
|
6738
6674
|
var ARCHIVE_DIR = ".logs/sessions";
|
|
6739
|
-
function writeFileAtomicSync(file, data) {
|
|
6740
|
-
const tmp = `${file}.tmp`;
|
|
6741
|
-
fs21.writeFileSync(tmp, data, "utf-8");
|
|
6742
|
-
fs21.renameSync(tmp, file);
|
|
6743
|
-
}
|
|
6744
6675
|
var ROTATE_THRESHOLD_BYTES = 32 * 1024 * 1024;
|
|
6745
6676
|
var RETAIN_TAIL_BYTES = 16 * 1024 * 1024;
|
|
6746
6677
|
var ARCHIVE_RETENTION_BYTES = 64 * 1024 * 1024;
|
|
@@ -6769,6 +6700,12 @@ function loadSession(state) {
|
|
|
6769
6700
|
return true;
|
|
6770
6701
|
}
|
|
6771
6702
|
} catch {
|
|
6703
|
+
try {
|
|
6704
|
+
const quarantine = `${SESSION_FILE}.corrupt-${Date.now()}`;
|
|
6705
|
+
fs21.renameSync(SESSION_FILE, quarantine);
|
|
6706
|
+
log10.warn(`Session file unreadable \u2014 quarantined to ${quarantine}`);
|
|
6707
|
+
} catch {
|
|
6708
|
+
}
|
|
6772
6709
|
}
|
|
6773
6710
|
return false;
|
|
6774
6711
|
}
|
|
@@ -6831,17 +6768,17 @@ function archiveMessages(messages, label, models) {
|
|
|
6831
6768
|
fs21.mkdirSync(ARCHIVE_DIR, { recursive: true });
|
|
6832
6769
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
6833
6770
|
const count = messages.length;
|
|
6834
|
-
let dest =
|
|
6771
|
+
let dest = path11.join(ARCHIVE_DIR, `${label}-${ts}.c${count}.json`);
|
|
6835
6772
|
let n = 1;
|
|
6836
6773
|
while (fs21.existsSync(dest)) {
|
|
6837
|
-
dest =
|
|
6774
|
+
dest = path11.join(ARCHIVE_DIR, `${label}-${ts}-${n++}.c${count}.json`);
|
|
6838
6775
|
}
|
|
6839
6776
|
const payload = { messages };
|
|
6840
6777
|
if (models && Object.keys(models).length > 0) {
|
|
6841
6778
|
payload.models = models;
|
|
6842
6779
|
}
|
|
6843
6780
|
writeFileAtomicSync(dest, JSON.stringify(payload));
|
|
6844
|
-
archiveCountCache.set(
|
|
6781
|
+
archiveCountCache.set(path11.basename(dest), count);
|
|
6845
6782
|
log10.info("Session archived", { label, dest, messageCount: count });
|
|
6846
6783
|
pruneArchives();
|
|
6847
6784
|
return dest;
|
|
@@ -6854,7 +6791,7 @@ function pruneArchives() {
|
|
|
6854
6791
|
}
|
|
6855
6792
|
const archives = entries.map((name) => ({
|
|
6856
6793
|
name,
|
|
6857
|
-
size: fs21.statSync(
|
|
6794
|
+
size: fs21.statSync(path11.join(ARCHIVE_DIR, name)).size
|
|
6858
6795
|
})).sort(
|
|
6859
6796
|
(a, b) => archiveSortKey(b.name).localeCompare(archiveSortKey(a.name))
|
|
6860
6797
|
);
|
|
@@ -6872,7 +6809,7 @@ function pruneArchives() {
|
|
|
6872
6809
|
let freed = 0;
|
|
6873
6810
|
for (let i = cut; i < archives.length; i++) {
|
|
6874
6811
|
try {
|
|
6875
|
-
fs21.unlinkSync(
|
|
6812
|
+
fs21.unlinkSync(path11.join(ARCHIVE_DIR, archives[i].name));
|
|
6876
6813
|
freed += archives[i].size;
|
|
6877
6814
|
removed++;
|
|
6878
6815
|
} catch {
|
|
@@ -6896,7 +6833,7 @@ function parseArchive(name) {
|
|
|
6896
6833
|
return cached3;
|
|
6897
6834
|
}
|
|
6898
6835
|
try {
|
|
6899
|
-
const raw = fs21.readFileSync(
|
|
6836
|
+
const raw = fs21.readFileSync(path11.join(ARCHIVE_DIR, name), "utf-8");
|
|
6900
6837
|
const data = JSON.parse(raw);
|
|
6901
6838
|
const messages = Array.isArray(data?.messages) ? data.messages : [];
|
|
6902
6839
|
archiveCountCache.set(name, messages.length);
|
|
@@ -7177,7 +7114,7 @@ function triggerCompaction(state, apiConfig, opts = {}) {
|
|
|
7177
7114
|
|
|
7178
7115
|
// src/brandExtraction/index.ts
|
|
7179
7116
|
import fs22 from "fs";
|
|
7180
|
-
import
|
|
7117
|
+
import path12 from "path";
|
|
7181
7118
|
import { createHash } from "crypto";
|
|
7182
7119
|
var log12 = createLogger("brandExtraction");
|
|
7183
7120
|
var EXTRACT_PROMPT = readAsset("brandExtraction", "extract.md");
|
|
@@ -7201,18 +7138,18 @@ async function runExtraction(apiConfig, model) {
|
|
|
7201
7138
|
return brand;
|
|
7202
7139
|
}
|
|
7203
7140
|
function isDedicatedBrandFile(filePath) {
|
|
7204
|
-
if (filePath.split(
|
|
7141
|
+
if (filePath.split(path12.sep).includes("@brand")) {
|
|
7205
7142
|
return true;
|
|
7206
7143
|
}
|
|
7207
|
-
const { type } =
|
|
7144
|
+
const { type } = parseFrontmatter3(filePath);
|
|
7208
7145
|
return type.startsWith("design/color") || type.startsWith("design/typography");
|
|
7209
7146
|
}
|
|
7210
7147
|
function isBrandRelevant(filePath) {
|
|
7211
|
-
return filePath ===
|
|
7148
|
+
return filePath === path12.join("src", "app.md") || isDedicatedBrandFile(filePath);
|
|
7212
7149
|
}
|
|
7213
7150
|
function computeInputHash() {
|
|
7214
7151
|
const entries = [];
|
|
7215
|
-
for (const filePath of
|
|
7152
|
+
for (const filePath of walkMdFiles2("src")) {
|
|
7216
7153
|
if (isBrandRelevant(filePath)) {
|
|
7217
7154
|
entries.push({ path: filePath, content: readSafe(filePath) });
|
|
7218
7155
|
}
|
|
@@ -7253,14 +7190,14 @@ function readBrandManifest() {
|
|
|
7253
7190
|
return "";
|
|
7254
7191
|
}
|
|
7255
7192
|
}
|
|
7256
|
-
function
|
|
7193
|
+
function walkMdFiles2(dir) {
|
|
7257
7194
|
const results = [];
|
|
7258
7195
|
try {
|
|
7259
7196
|
const entries = fs22.readdirSync(dir, { withFileTypes: true });
|
|
7260
7197
|
for (const entry of entries) {
|
|
7261
|
-
const full =
|
|
7198
|
+
const full = path12.join(dir, entry.name);
|
|
7262
7199
|
if (entry.isDirectory()) {
|
|
7263
|
-
results.push(...
|
|
7200
|
+
results.push(...walkMdFiles2(full));
|
|
7264
7201
|
} else if (entry.name.endsWith(".md")) {
|
|
7265
7202
|
results.push(full);
|
|
7266
7203
|
}
|
|
@@ -7269,7 +7206,7 @@ function walkMdFiles3(dir) {
|
|
|
7269
7206
|
}
|
|
7270
7207
|
return results.sort();
|
|
7271
7208
|
}
|
|
7272
|
-
function
|
|
7209
|
+
function parseFrontmatter3(filePath) {
|
|
7273
7210
|
try {
|
|
7274
7211
|
const content = fs22.readFileSync(filePath, "utf-8");
|
|
7275
7212
|
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
@@ -7298,7 +7235,10 @@ async function extractBrand(apiConfig, model) {
|
|
|
7298
7235
|
subAgentId: "brandExtractor",
|
|
7299
7236
|
system: EXTRACT_PROMPT,
|
|
7300
7237
|
messages: [{ role: "user", content: corpus }],
|
|
7301
|
-
tools: []
|
|
7238
|
+
tools: [],
|
|
7239
|
+
// One call per extraction over a corpus that changes with every spec
|
|
7240
|
+
// edit — never re-read, so a cache write is pure waste.
|
|
7241
|
+
cachePolicy: "oneshot"
|
|
7302
7242
|
})) {
|
|
7303
7243
|
if (event.type === "text") {
|
|
7304
7244
|
responseText += event.text;
|
|
@@ -7337,7 +7277,7 @@ async function extractBrand(apiConfig, model) {
|
|
|
7337
7277
|
var HEAD_SLICE_CHARS = 2e3;
|
|
7338
7278
|
var BRAND_CORPUS_CHAR_LIMIT = 24e5;
|
|
7339
7279
|
function buildCorpus() {
|
|
7340
|
-
const all =
|
|
7280
|
+
const all = walkMdFiles2("src");
|
|
7341
7281
|
const ordered = [
|
|
7342
7282
|
...all.filter(isBrandRelevant),
|
|
7343
7283
|
...all.filter((f) => !isBrandRelevant(f))
|
|
@@ -7480,11 +7420,9 @@ function pickFont(raw) {
|
|
|
7480
7420
|
return out;
|
|
7481
7421
|
}
|
|
7482
7422
|
function persistBrand(brand, inputHash) {
|
|
7483
|
-
|
|
7484
|
-
fs22.writeFileSync(tmp, JSON.stringify(brand, null, 2), "utf-8");
|
|
7485
|
-
fs22.renameSync(tmp, BRAND_FILE);
|
|
7423
|
+
writeFileAtomicSync(BRAND_FILE, JSON.stringify(brand, null, 2));
|
|
7486
7424
|
const cache = { inputHash, generatedAt: Date.now() };
|
|
7487
|
-
|
|
7425
|
+
writeFileAtomicSync(CACHE_FILE, JSON.stringify(cache, null, 2));
|
|
7488
7426
|
}
|
|
7489
7427
|
function readCache() {
|
|
7490
7428
|
try {
|
|
@@ -7825,7 +7763,7 @@ async function runTurn(params) {
|
|
|
7825
7763
|
toolRegistry,
|
|
7826
7764
|
onBackgroundComplete
|
|
7827
7765
|
} = params;
|
|
7828
|
-
const tools2 = getToolDefinitions(
|
|
7766
|
+
const tools2 = getToolDefinitions();
|
|
7829
7767
|
const buildModelOverride = buildModel ? filterModelPicks({ parent: buildModel }).parent : void 0;
|
|
7830
7768
|
const baseline = resolveModel("parent", state.models, model);
|
|
7831
7769
|
const parentModel = buildModelOverride ?? baseline;
|
|
@@ -8033,6 +7971,9 @@ async function runTurn(params) {
|
|
|
8033
7971
|
system,
|
|
8034
7972
|
messages: cleanMessagesForApi(state.messages),
|
|
8035
7973
|
tools: tools2,
|
|
7974
|
+
// The parent is one long-lived conversation re-read across turns
|
|
7975
|
+
// with multi-minute gaps — the 1h-TTL profile.
|
|
7976
|
+
cachePolicy: "conversation",
|
|
8036
7977
|
signal
|
|
8037
7978
|
},
|
|
8038
7979
|
{
|
|
@@ -8569,16 +8510,15 @@ ${lines.join("\n")}`;
|
|
|
8569
8510
|
}
|
|
8570
8511
|
|
|
8571
8512
|
// src/headless/planFile.ts
|
|
8572
|
-
import { readFileSync,
|
|
8513
|
+
import { readFileSync, unlinkSync } from "fs";
|
|
8573
8514
|
var PLAN_FILE3 = ".remy-plan.md";
|
|
8574
8515
|
function applyPlanFileSideEffect(rawText) {
|
|
8575
8516
|
if (hasSentinel(rawText, "approvePlan") || hasSentinel(rawText, "approveInitialPlan")) {
|
|
8576
8517
|
try {
|
|
8577
8518
|
const plan = readFileSync(PLAN_FILE3, "utf-8");
|
|
8578
|
-
|
|
8519
|
+
writeFileAtomicSync(
|
|
8579
8520
|
PLAN_FILE3,
|
|
8580
|
-
plan.replace(/^status:\s*pending/m, "status: approved")
|
|
8581
|
-
"utf-8"
|
|
8521
|
+
plan.replace(/^status:\s*pending/m, "status: approved")
|
|
8582
8522
|
);
|
|
8583
8523
|
} catch {
|
|
8584
8524
|
}
|
|
@@ -8591,7 +8531,7 @@ function applyPlanFileSideEffect(rawText) {
|
|
|
8591
8531
|
}
|
|
8592
8532
|
|
|
8593
8533
|
// src/headless/stats.ts
|
|
8594
|
-
import { readFileSync as readFileSync2
|
|
8534
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
8595
8535
|
var STATS_FILE = ".remy-stats.json";
|
|
8596
8536
|
function createSessionStats() {
|
|
8597
8537
|
return {
|
|
@@ -8628,7 +8568,7 @@ function loadPassiveResults() {
|
|
|
8628
8568
|
}
|
|
8629
8569
|
function writeStats(stats, queue, passiveResults) {
|
|
8630
8570
|
try {
|
|
8631
|
-
|
|
8571
|
+
writeFileAtomicSync(
|
|
8632
8572
|
STATS_FILE,
|
|
8633
8573
|
JSON.stringify({
|
|
8634
8574
|
...stats,
|
|
@@ -8857,9 +8797,7 @@ var HeadlessSession = class {
|
|
|
8857
8797
|
name: "compactConversation",
|
|
8858
8798
|
input: {},
|
|
8859
8799
|
startedAt: Date.now(),
|
|
8860
|
-
|
|
8861
|
-
uiOnly: true,
|
|
8862
|
-
result: "Compaction started in the background."
|
|
8800
|
+
uiOnly: true
|
|
8863
8801
|
}
|
|
8864
8802
|
]
|
|
8865
8803
|
});
|
|
@@ -8868,15 +8806,7 @@ var HeadlessSession = class {
|
|
|
8868
8806
|
type: "tool_start",
|
|
8869
8807
|
id,
|
|
8870
8808
|
name: "compactConversation",
|
|
8871
|
-
input: {}
|
|
8872
|
-
background: true
|
|
8873
|
-
});
|
|
8874
|
-
this.onEvent({
|
|
8875
|
-
type: "tool_done",
|
|
8876
|
-
id,
|
|
8877
|
-
name: "compactConversation",
|
|
8878
|
-
result: "Compaction started in the background.",
|
|
8879
|
-
isError: false
|
|
8809
|
+
input: {}
|
|
8880
8810
|
});
|
|
8881
8811
|
}
|
|
8882
8812
|
} else {
|
|
@@ -8885,11 +8815,31 @@ var HeadlessSession = class {
|
|
|
8885
8815
|
if (this.syntheticCompactionId) {
|
|
8886
8816
|
const id = this.syntheticCompactionId;
|
|
8887
8817
|
this.syntheticCompactionId = null;
|
|
8888
|
-
|
|
8818
|
+
const result = event.error ? `Error: ${event.error}` : formatSummariesResult(event.summaries ?? []);
|
|
8819
|
+
const isError = !!event.error;
|
|
8820
|
+
for (let i = this.state.messages.length - 1; i >= 0; i--) {
|
|
8821
|
+
const msg = this.state.messages[i];
|
|
8822
|
+
if (msg.role !== "assistant" || !Array.isArray(msg.content)) {
|
|
8823
|
+
continue;
|
|
8824
|
+
}
|
|
8825
|
+
const block = msg.content.find(
|
|
8826
|
+
(b) => b.type === "tool" && b.id === id
|
|
8827
|
+
);
|
|
8828
|
+
if (block && block.type === "tool") {
|
|
8829
|
+
block.result = result;
|
|
8830
|
+
block.isError = isError;
|
|
8831
|
+
block.completedAt = Date.now();
|
|
8832
|
+
saveSession(this.state);
|
|
8833
|
+
break;
|
|
8834
|
+
}
|
|
8835
|
+
}
|
|
8836
|
+
this.onEvent({
|
|
8837
|
+
type: "tool_done",
|
|
8889
8838
|
id,
|
|
8890
|
-
"compactConversation",
|
|
8891
|
-
|
|
8892
|
-
|
|
8839
|
+
name: "compactConversation",
|
|
8840
|
+
result,
|
|
8841
|
+
isError
|
|
8842
|
+
});
|
|
8893
8843
|
}
|
|
8894
8844
|
this.sessionStats.compactionInProgress = false;
|
|
8895
8845
|
if (!event.error) {
|
|
@@ -9350,10 +9300,7 @@ var HeadlessSession = class {
|
|
|
9350
9300
|
const buildModel = hasSentinel(rawText, "approvePlan") ? parsed.buildModel : void 0;
|
|
9351
9301
|
const onboardingState = parsed.onboardingState ?? "onboardingFinished";
|
|
9352
9302
|
this.currentOnboardingState = onboardingState;
|
|
9353
|
-
const system = buildSystemPrompt(
|
|
9354
|
-
onboardingState,
|
|
9355
|
-
parsed.viewContext
|
|
9356
|
-
);
|
|
9303
|
+
const system = buildSystemPrompt(onboardingState);
|
|
9357
9304
|
if (resolved?.next && !fromChain) {
|
|
9358
9305
|
for (const step of getActionChain(resolved.next)) {
|
|
9359
9306
|
this.queue.push({
|
|
@@ -9430,13 +9377,12 @@ var HeadlessSession = class {
|
|
|
9430
9377
|
}
|
|
9431
9378
|
const onboardingState = batch.find((b) => b.command.onboardingState !== void 0)?.command.onboardingState ?? this.currentOnboardingState ?? "onboardingFinished";
|
|
9432
9379
|
this.currentOnboardingState = onboardingState;
|
|
9433
|
-
const viewContext = [...batch].reverse().find((b) => b.command.viewContext !== void 0)?.command.viewContext;
|
|
9434
9380
|
await this.executeTurn({
|
|
9435
9381
|
entries,
|
|
9436
9382
|
requestId: primaryRid,
|
|
9437
9383
|
absorbedRids,
|
|
9438
9384
|
onboardingState,
|
|
9439
|
-
system: buildSystemPrompt(onboardingState
|
|
9385
|
+
system: buildSystemPrompt(onboardingState)
|
|
9440
9386
|
});
|
|
9441
9387
|
}
|
|
9442
9388
|
/**
|