@mindstudio-ai/remy 0.1.278 → 0.1.280
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/automatedActions/approveInitialPlan.md +1 -3
- package/dist/automatedActions/postBuildPolish.md +1 -1
- package/dist/headless.js +259 -85
- package/dist/index.js +268 -78
- package/dist/prompt/compiled/interfaces.md +34 -0
- package/dist/prompt/compiled/jewels.md +3 -0
- package/dist/prompt/compiled/methods.md +4 -0
- package/dist/prompt/skills/jewels.md +296 -0
- package/dist/prompt/skills/taskAgents.md +1 -1
- package/dist/prompt/static/coding.md +1 -0
- package/dist/prompt/static/team.md +2 -2
- package/dist/subagents/codeSanityCheck/prompt.md +1 -1
- package/dist/subagents/designExpert/prompts/instructions.md +1 -0
- package/dist/subagents/designExpert/prompts/ui-patterns.md +7 -13
- package/package.json +1 -1
package/dist/headless.js
CHANGED
|
@@ -813,6 +813,10 @@ function buildSystemPrompt(onboardingState) {
|
|
|
813
813
|
{{compiled/auth.md}}
|
|
814
814
|
</auth>
|
|
815
815
|
|
|
816
|
+
<jewels>
|
|
817
|
+
{{compiled/jewels.md}}
|
|
818
|
+
</jewels>
|
|
819
|
+
|
|
816
820
|
<dev_and_deploy>
|
|
817
821
|
{{compiled/dev-and-deploy.md}}
|
|
818
822
|
</dev_and_deploy>
|
|
@@ -867,7 +871,7 @@ New projects progress through four onboarding states. The user might skip this e
|
|
|
867
871
|
|
|
868
872
|
- **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.
|
|
869
873
|
- **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).
|
|
870
|
-
- **buildComplete**: The build is done.
|
|
874
|
+
- **buildComplete**: The build is done \u2014 entered via markBuildComplete at the end of the automated post-build flow. Transient: the frontend lands the user on the Build Overview, fully unlocks the editor, and immediately advances to onboardingFinished on its own. The agent does not need to do anything in this state.
|
|
871
875
|
- **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.
|
|
872
876
|
</project_onboarding>
|
|
873
877
|
|
|
@@ -1488,21 +1492,14 @@ var updatePlanStatusTool = {
|
|
|
1488
1492
|
}
|
|
1489
1493
|
};
|
|
1490
1494
|
|
|
1491
|
-
// src/tools/common/
|
|
1492
|
-
var
|
|
1495
|
+
// src/tools/common/markBuildComplete.ts
|
|
1496
|
+
var markBuildCompleteTool = {
|
|
1493
1497
|
definition: {
|
|
1494
|
-
name: "
|
|
1495
|
-
description:
|
|
1498
|
+
name: "markBuildComplete",
|
|
1499
|
+
description: 'Mark the initial build as finished. The frontend lands the user on the Build Overview, fully unlocks the editor, and finishes onboarding; the platform sends the one-time "your first build is ready" email. Normally called as the final step of the automated post-build flow \u2014 don\'t call it early, or you\'ll cut the build experience short. Exception: if the project has been in `building` for a while, the build is clearly done (the user is iterating on a working app, deploying, etc.), and the user reports the editor seems stuck \u2014 disabled Preview/Spec/Code tabs \u2014 call this to unstick them. Refused during intake: the user starts the build via "Start Building", never you.',
|
|
1496
1500
|
inputSchema: {
|
|
1497
1501
|
type: "object",
|
|
1498
|
-
properties: {
|
|
1499
|
-
state: {
|
|
1500
|
-
type: "string",
|
|
1501
|
-
enum: ["building", "buildComplete", "onboardingFinished"],
|
|
1502
|
-
description: "The onboarding state to advance to."
|
|
1503
|
-
}
|
|
1504
|
-
},
|
|
1505
|
-
required: ["state"]
|
|
1502
|
+
properties: {}
|
|
1506
1503
|
}
|
|
1507
1504
|
},
|
|
1508
1505
|
async execute() {
|
|
@@ -2981,6 +2978,35 @@ var runMethodTool = {
|
|
|
2981
2978
|
}
|
|
2982
2979
|
};
|
|
2983
2980
|
|
|
2981
|
+
// src/tools/code/testJewel.ts
|
|
2982
|
+
var testJewelTool = {
|
|
2983
|
+
definition: {
|
|
2984
|
+
name: "testJewel",
|
|
2985
|
+
description: "Run a method's jewel directly against a test input and return its pair record. Use after writing or modifying a jewel to verify the subject projection, the proposal, and the grading \u2014 the method itself is NOT executed (no data changes) and nothing reaches the pair ledger. Pass `humanInput` (the exact input a human would have submitted) for a full graded run: the jewel derives the subject from it, proposes, and grades its proposal against it as ground truth \u2014 the record carries a verdict (agree/disagree/skip). Or pass `subject` for an ungraded eval run (propose only). Returns the full pair record (subject, proposed, reasoning, actual, verdict, notes, error) plus captured console output and duration. A `pair.error` means your jewel code threw in that phase \u2014 fix and re-run. Seed realistic data first (runScenario) so the jewel's reads have a world to look at.",
|
|
2986
|
+
inputSchema: {
|
|
2987
|
+
type: "object",
|
|
2988
|
+
properties: {
|
|
2989
|
+
method: {
|
|
2990
|
+
type: "string",
|
|
2991
|
+
description: 'The shadowed method\'s export name (camelCase, e.g. "updateIssue"). Its manifest entry must have a `jewel` pointer.'
|
|
2992
|
+
},
|
|
2993
|
+
humanInput: {
|
|
2994
|
+
type: "object",
|
|
2995
|
+
description: "Shadow-style run: the exact method input a human would have submitted. The jewel derives its subject from this, proposes, and grades against it \u2014 the record gets a verdict. Use realistic inputs; this is how you verify agreement."
|
|
2996
|
+
},
|
|
2997
|
+
subject: {
|
|
2998
|
+
type: "object",
|
|
2999
|
+
description: "Eval run: a subject to propose against with no ground truth (record is ungraded). Use to probe the jewel on cases where you don't know the right answer yet. Pass exactly one of humanInput or subject."
|
|
3000
|
+
}
|
|
3001
|
+
},
|
|
3002
|
+
required: ["method"]
|
|
3003
|
+
}
|
|
3004
|
+
},
|
|
3005
|
+
async execute() {
|
|
3006
|
+
return "ok";
|
|
3007
|
+
}
|
|
3008
|
+
};
|
|
3009
|
+
|
|
2984
3010
|
// src/tools/code/queryDatabase.ts
|
|
2985
3011
|
var queryDatabaseTool = {
|
|
2986
3012
|
definition: {
|
|
@@ -5524,6 +5550,147 @@ This reference lives at ${skill.path}. Re-read it with readFile if you need it a
|
|
|
5524
5550
|
}
|
|
5525
5551
|
}
|
|
5526
5552
|
|
|
5553
|
+
// src/subagents/designExpert/tools/createWireframe.ts
|
|
5554
|
+
var createWireframe_exports = {};
|
|
5555
|
+
__export(createWireframe_exports, {
|
|
5556
|
+
WIREFRAMES_DIR: () => WIREFRAMES_DIR,
|
|
5557
|
+
definition: () => definition10,
|
|
5558
|
+
execute: () => execute10
|
|
5559
|
+
});
|
|
5560
|
+
import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
|
|
5561
|
+
import { join as join2 } from "path";
|
|
5562
|
+
var log9 = createLogger("createWireframe");
|
|
5563
|
+
var WIREFRAMES_DIR = "src/.wireframes";
|
|
5564
|
+
var UPLOAD_TIMEOUT_MS2 = 3e4;
|
|
5565
|
+
var definition10 = {
|
|
5566
|
+
name: "createWireframe",
|
|
5567
|
+
description: "Create a wireframe from self-contained HTML+CSS. Returns a markdown reference line \u2014 include that exact line in your response wherever the wireframe belongs, with your notes in the surrounding prose. To revise a wireframe, create a new one (read the old file first if you are iterating on it).",
|
|
5568
|
+
inputSchema: {
|
|
5569
|
+
type: "object",
|
|
5570
|
+
properties: {
|
|
5571
|
+
name: {
|
|
5572
|
+
type: "string",
|
|
5573
|
+
description: 'Short display name, e.g. "Feed Post Card". Becomes the caption and the filename slug.'
|
|
5574
|
+
},
|
|
5575
|
+
description: {
|
|
5576
|
+
type: "string",
|
|
5577
|
+
description: "One line on what the wireframe shows \u2014 layout, states, motion."
|
|
5578
|
+
},
|
|
5579
|
+
html: {
|
|
5580
|
+
type: "string",
|
|
5581
|
+
description: "The complete HTML document (<html>\u2026</html>), self-contained vanilla HTML/CSS/JS. No frontmatter \u2014 it is added for you."
|
|
5582
|
+
}
|
|
5583
|
+
},
|
|
5584
|
+
required: ["name", "description", "html"]
|
|
5585
|
+
}
|
|
5586
|
+
};
|
|
5587
|
+
function slugify(name) {
|
|
5588
|
+
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40).replace(/-+$/, "") || "wireframe";
|
|
5589
|
+
}
|
|
5590
|
+
function singleLine(value) {
|
|
5591
|
+
return value.replace(/\s+/g, " ").trim();
|
|
5592
|
+
}
|
|
5593
|
+
function validate(name, html) {
|
|
5594
|
+
const warnings = [];
|
|
5595
|
+
if (!name.trim()) {
|
|
5596
|
+
return { error: "Error: name is required.", warnings };
|
|
5597
|
+
}
|
|
5598
|
+
if (!html.trim()) {
|
|
5599
|
+
return { error: "Error: html is required.", warnings };
|
|
5600
|
+
}
|
|
5601
|
+
if (/^\s*---/.test(html)) {
|
|
5602
|
+
return {
|
|
5603
|
+
error: "Error: html must not include frontmatter \u2014 pass name and description as parameters and the frontmatter is added for you.",
|
|
5604
|
+
warnings
|
|
5605
|
+
};
|
|
5606
|
+
}
|
|
5607
|
+
if (/<img[\s>]/i.test(html)) {
|
|
5608
|
+
return {
|
|
5609
|
+
error: "Error: wireframes must not contain <img> tags. Use skeleton placeholders (grey boxes, gradients) instead of images.",
|
|
5610
|
+
warnings
|
|
5611
|
+
};
|
|
5612
|
+
}
|
|
5613
|
+
if (!/<style[\s>]/i.test(html) && !/style=/i.test(html)) {
|
|
5614
|
+
return {
|
|
5615
|
+
error: "Error: no CSS found. Wireframes are self-contained HTML+CSS \u2014 style the component container (not the body) so it reads against the transparent background.",
|
|
5616
|
+
warnings
|
|
5617
|
+
};
|
|
5618
|
+
}
|
|
5619
|
+
const lines = html.split("\n").length;
|
|
5620
|
+
if (lines > 120) {
|
|
5621
|
+
warnings.push(
|
|
5622
|
+
`The wireframe is ${lines} lines \u2014 past the ~100-line budget. Wireframes isolate one small piece; consider whether this is building too much.`
|
|
5623
|
+
);
|
|
5624
|
+
}
|
|
5625
|
+
return { warnings };
|
|
5626
|
+
}
|
|
5627
|
+
async function uploadMirror(context, slug, content) {
|
|
5628
|
+
const { apiConfig } = context;
|
|
5629
|
+
if (!apiConfig?.appId) {
|
|
5630
|
+
return { ok: false, note: "no app id in this session" };
|
|
5631
|
+
}
|
|
5632
|
+
try {
|
|
5633
|
+
const url = `${apiConfig.baseUrl}/_internal/v2/apps/${apiConfig.appId}/dev/wireframes`;
|
|
5634
|
+
const res = await fetch(url, {
|
|
5635
|
+
method: "POST",
|
|
5636
|
+
headers: {
|
|
5637
|
+
"Content-Type": "application/json",
|
|
5638
|
+
Authorization: `Bearer ${apiConfig.apiKey}`
|
|
5639
|
+
},
|
|
5640
|
+
body: JSON.stringify({ slug, content }),
|
|
5641
|
+
signal: AbortSignal.timeout(UPLOAD_TIMEOUT_MS2)
|
|
5642
|
+
});
|
|
5643
|
+
if (!res.ok) {
|
|
5644
|
+
return { ok: false, note: `HTTP ${res.status}` };
|
|
5645
|
+
}
|
|
5646
|
+
return { ok: true };
|
|
5647
|
+
} catch (err) {
|
|
5648
|
+
return { ok: false, note: err.message };
|
|
5649
|
+
}
|
|
5650
|
+
}
|
|
5651
|
+
async function execute10(input, onLog, context) {
|
|
5652
|
+
if (!context) {
|
|
5653
|
+
return "Error: createWireframe requires execution context";
|
|
5654
|
+
}
|
|
5655
|
+
const name = String(input.name ?? "");
|
|
5656
|
+
const description = String(input.description ?? "");
|
|
5657
|
+
const html = String(input.html ?? "");
|
|
5658
|
+
const { error, warnings } = validate(name, html);
|
|
5659
|
+
if (error) {
|
|
5660
|
+
return error;
|
|
5661
|
+
}
|
|
5662
|
+
const slug = `${slugify(name)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
5663
|
+
const relPath = `${WIREFRAMES_DIR}/${slug}.html`;
|
|
5664
|
+
const content = [
|
|
5665
|
+
"---",
|
|
5666
|
+
`name: ${singleLine(name)}`,
|
|
5667
|
+
`description: ${singleLine(description)}`,
|
|
5668
|
+
"---",
|
|
5669
|
+
html.trim(),
|
|
5670
|
+
""
|
|
5671
|
+
].join("\n");
|
|
5672
|
+
await mkdir2(join2(PROJECT_ROOT, WIREFRAMES_DIR), { recursive: true });
|
|
5673
|
+
await writeFile2(join2(PROJECT_ROOT, relPath), content, "utf8");
|
|
5674
|
+
onLog?.(`Wrote ${relPath}, mirroring for preview...`);
|
|
5675
|
+
const mirror = await uploadMirror(context, slug, content);
|
|
5676
|
+
if (!mirror.ok) {
|
|
5677
|
+
log9.warn("Wireframe mirror upload failed", { slug, note: mirror.note });
|
|
5678
|
+
}
|
|
5679
|
+
const lines = [
|
|
5680
|
+
`Created wireframe "${singleLine(name)}" at ${relPath}.`,
|
|
5681
|
+
`Reference it in your response and in specs with exactly: `
|
|
5682
|
+
];
|
|
5683
|
+
if (!mirror.ok) {
|
|
5684
|
+
lines.push(
|
|
5685
|
+
`Note: the preview mirror upload failed (${mirror.note}) \u2014 the file is intact and usable by the developer, but the wireframe may not render visually in the dashboard. Do not retry; mention the layout in prose as well.`
|
|
5686
|
+
);
|
|
5687
|
+
}
|
|
5688
|
+
if (warnings.length > 0) {
|
|
5689
|
+
lines.push(...warnings.map((w) => `Note: ${w}`));
|
|
5690
|
+
}
|
|
5691
|
+
return lines.join("\n");
|
|
5692
|
+
}
|
|
5693
|
+
|
|
5527
5694
|
// src/subagents/designExpert/tools/index.ts
|
|
5528
5695
|
var tools = {
|
|
5529
5696
|
searchGoogle: searchGoogle_exports,
|
|
@@ -5538,7 +5705,9 @@ var tools = {
|
|
|
5538
5705
|
editImages: editImages_exports,
|
|
5539
5706
|
renderImage: renderImage_exports,
|
|
5540
5707
|
polishCopy: polishCopy_exports,
|
|
5541
|
-
loadSkill: loadSkill_exports
|
|
5708
|
+
loadSkill: loadSkill_exports,
|
|
5709
|
+
// Appended last: tool order is part of the subagent's prompt-cache prefix.
|
|
5710
|
+
createWireframe: createWireframe_exports
|
|
5542
5711
|
};
|
|
5543
5712
|
var DESIGN_EXPERT_TOOLS = [
|
|
5544
5713
|
...COMMON_READ_TOOLS,
|
|
@@ -6516,7 +6685,7 @@ function deriveContext(parent, toolCallId) {
|
|
|
6516
6685
|
}
|
|
6517
6686
|
var ALL_TOOLS = [
|
|
6518
6687
|
// Common
|
|
6519
|
-
|
|
6688
|
+
markBuildCompleteTool,
|
|
6520
6689
|
promptUserTool,
|
|
6521
6690
|
confirmDestructiveActionTool,
|
|
6522
6691
|
askMindStudioSdkTool,
|
|
@@ -6559,7 +6728,8 @@ var ALL_TOOLS = [
|
|
|
6559
6728
|
restartProcessTool,
|
|
6560
6729
|
// Appended rather than grouped: position is part of the cache prefix, so a
|
|
6561
6730
|
// new tool goes at the end to leave every existing session's prefix intact.
|
|
6562
|
-
loadSkillTool
|
|
6731
|
+
loadSkillTool,
|
|
6732
|
+
testJewelTool
|
|
6563
6733
|
];
|
|
6564
6734
|
var SUBAGENT_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
6565
6735
|
"visualDesignExpert",
|
|
@@ -6585,7 +6755,7 @@ function executeTool(name, input, context) {
|
|
|
6585
6755
|
}
|
|
6586
6756
|
|
|
6587
6757
|
// src/compaction/index.ts
|
|
6588
|
-
var
|
|
6758
|
+
var log10 = createLogger("compaction");
|
|
6589
6759
|
var CONVERSATION_SUMMARY_PROMPT = readAsset("compaction", "conversation.md");
|
|
6590
6760
|
var SUBAGENT_SUMMARY_PROMPT = readAsset("compaction", "subagent.md");
|
|
6591
6761
|
var SUMMARIZABLE_SUBAGENTS = ["visualDesignExpert", "productVision"];
|
|
@@ -6634,7 +6804,7 @@ async function compactConversation(messages, apiConfig, model) {
|
|
|
6634
6804
|
if (text) {
|
|
6635
6805
|
summaries.push({ name, text });
|
|
6636
6806
|
} else {
|
|
6637
|
-
|
|
6807
|
+
log10.warn("Subagent summary unusable \u2014 leaving its history intact", {
|
|
6638
6808
|
name
|
|
6639
6809
|
});
|
|
6640
6810
|
}
|
|
@@ -6662,7 +6832,7 @@ async function compactConversation(messages, apiConfig, model) {
|
|
|
6662
6832
|
}
|
|
6663
6833
|
]
|
|
6664
6834
|
}));
|
|
6665
|
-
|
|
6835
|
+
log10.info("Compaction complete", {
|
|
6666
6836
|
summaries: summaries.length,
|
|
6667
6837
|
recentNarrativeChars: recent.length
|
|
6668
6838
|
});
|
|
@@ -6868,7 +7038,7 @@ async function generateSummary(apiConfig, name, compactionPrompt, messagesToSumm
|
|
|
6868
7038
|
messagesToSummarize.slice(0, mid),
|
|
6869
7039
|
messagesToSummarize.slice(mid)
|
|
6870
7040
|
];
|
|
6871
|
-
|
|
7041
|
+
log10.info("Chunking summary", {
|
|
6872
7042
|
name,
|
|
6873
7043
|
messageCount: messagesToSummarize.length,
|
|
6874
7044
|
serializedLength: serialized.length,
|
|
@@ -6898,7 +7068,7 @@ async function generateSummary(apiConfig, name, compactionPrompt, messagesToSumm
|
|
|
6898
7068
|
const parts = results.filter((p) => p !== null);
|
|
6899
7069
|
return parts.length > 0 ? parts.join("\n\n---\n\n") : null;
|
|
6900
7070
|
}
|
|
6901
|
-
|
|
7071
|
+
log10.info("Generating summary", {
|
|
6902
7072
|
name,
|
|
6903
7073
|
messageCount: messagesToSummarize.length,
|
|
6904
7074
|
serializedLength: serialized.length
|
|
@@ -6914,10 +7084,10 @@ async function generateSummary(apiConfig, name, compactionPrompt, messagesToSumm
|
|
|
6914
7084
|
return null;
|
|
6915
7085
|
}
|
|
6916
7086
|
if (summaryText.length >= MIN_SUMMARY_CHARS) {
|
|
6917
|
-
|
|
7087
|
+
log10.info("Summary generated", { name, summaryLength: summaryText.length });
|
|
6918
7088
|
return summaryText;
|
|
6919
7089
|
}
|
|
6920
|
-
|
|
7090
|
+
log10.warn("Summary too short to be real", {
|
|
6921
7091
|
name,
|
|
6922
7092
|
summaryLength: summaryText.length,
|
|
6923
7093
|
minimum: MIN_SUMMARY_CHARS,
|
|
@@ -6977,12 +7147,12 @@ Write the summary of the conversation above, following your instructions.`;
|
|
|
6977
7147
|
toolNames: []
|
|
6978
7148
|
});
|
|
6979
7149
|
} else if (event.type === "error") {
|
|
6980
|
-
|
|
7150
|
+
log10.error("Summary generation failed", { name, error: event.error });
|
|
6981
7151
|
return null;
|
|
6982
7152
|
}
|
|
6983
7153
|
}
|
|
6984
7154
|
if (!summaryText.trim()) {
|
|
6985
|
-
|
|
7155
|
+
log10.warn("Empty summary generated", { name });
|
|
6986
7156
|
return null;
|
|
6987
7157
|
}
|
|
6988
7158
|
return summaryText.trim();
|
|
@@ -6991,7 +7161,7 @@ Write the summary of the conversation above, following your instructions.`;
|
|
|
6991
7161
|
// src/session.ts
|
|
6992
7162
|
import fs21 from "fs";
|
|
6993
7163
|
import path11 from "path";
|
|
6994
|
-
var
|
|
7164
|
+
var log11 = createLogger("session");
|
|
6995
7165
|
var SESSION_FILE = ".remy-session.json";
|
|
6996
7166
|
var ARCHIVE_DIR = ".logs/sessions";
|
|
6997
7167
|
var ARCHIVE_NAME_RE = /^(cleared|rotated)-.*\.json$/;
|
|
@@ -7010,7 +7180,7 @@ function loadSession(state) {
|
|
|
7010
7180
|
}
|
|
7011
7181
|
if (Array.isArray(data.messages) && data.messages.length > 0) {
|
|
7012
7182
|
state.messages = sanitizeMessages(data.messages);
|
|
7013
|
-
|
|
7183
|
+
log11.info("Session loaded", {
|
|
7014
7184
|
messageCount: state.messages.length,
|
|
7015
7185
|
...state.models && { models: state.models }
|
|
7016
7186
|
});
|
|
@@ -7020,7 +7190,7 @@ function loadSession(state) {
|
|
|
7020
7190
|
try {
|
|
7021
7191
|
const quarantine = `${SESSION_FILE}.corrupt-${Date.now()}`;
|
|
7022
7192
|
fs21.renameSync(SESSION_FILE, quarantine);
|
|
7023
|
-
|
|
7193
|
+
log11.warn(`Session file unreadable \u2014 quarantined to ${quarantine}`);
|
|
7024
7194
|
} catch {
|
|
7025
7195
|
}
|
|
7026
7196
|
}
|
|
@@ -7085,7 +7255,7 @@ function archiveMessages(messages, label, models) {
|
|
|
7085
7255
|
}
|
|
7086
7256
|
writeFileAtomicSync(dest, JSON.stringify(payload));
|
|
7087
7257
|
archiveCountCache.set(path11.basename(dest), count);
|
|
7088
|
-
|
|
7258
|
+
log11.info("Session archived", { label, dest, messageCount: count });
|
|
7089
7259
|
pruneArchives();
|
|
7090
7260
|
return dest;
|
|
7091
7261
|
}
|
|
@@ -7122,7 +7292,7 @@ function pruneArchives() {
|
|
|
7122
7292
|
}
|
|
7123
7293
|
}
|
|
7124
7294
|
if (removed > 0) {
|
|
7125
|
-
|
|
7295
|
+
log11.info("Session archives pruned", {
|
|
7126
7296
|
removed,
|
|
7127
7297
|
freedBytes: freed,
|
|
7128
7298
|
keptBytes: kept
|
|
@@ -7156,7 +7326,7 @@ function parseArchive(name) {
|
|
|
7156
7326
|
}
|
|
7157
7327
|
return messages;
|
|
7158
7328
|
} catch (err) {
|
|
7159
|
-
|
|
7329
|
+
log11.warn("Session archive unreadable", { name, error: err?.message });
|
|
7160
7330
|
return null;
|
|
7161
7331
|
}
|
|
7162
7332
|
}
|
|
@@ -7271,7 +7441,7 @@ function getHistoryPage(state, opts) {
|
|
|
7271
7441
|
}
|
|
7272
7442
|
messages.splice(0, cut);
|
|
7273
7443
|
startIndex += cut;
|
|
7274
|
-
|
|
7444
|
+
log11.info("History page trimmed to byte budget", {
|
|
7275
7445
|
dropped: cut,
|
|
7276
7446
|
kept: messages.length,
|
|
7277
7447
|
startIndex
|
|
@@ -7302,7 +7472,7 @@ function rotate(state) {
|
|
|
7302
7472
|
}
|
|
7303
7473
|
archiveMessages(messages.slice(0, cut), "rotated", state.models);
|
|
7304
7474
|
state.messages = messages.slice(cut);
|
|
7305
|
-
|
|
7475
|
+
log11.info("Session rotated", {
|
|
7306
7476
|
archived: cut,
|
|
7307
7477
|
retained: state.messages.length
|
|
7308
7478
|
});
|
|
@@ -7315,9 +7485,9 @@ function saveSession(state) {
|
|
|
7315
7485
|
serialized = JSON.stringify(buildPayload(state));
|
|
7316
7486
|
}
|
|
7317
7487
|
writeFileAtomicSync(SESSION_FILE, serialized);
|
|
7318
|
-
|
|
7488
|
+
log11.info("Session saved", { messageCount: state.messages.length });
|
|
7319
7489
|
} catch (err) {
|
|
7320
|
-
|
|
7490
|
+
log11.warn("Session save failed", { error: err.message });
|
|
7321
7491
|
}
|
|
7322
7492
|
}
|
|
7323
7493
|
function clearSession(state) {
|
|
@@ -7326,7 +7496,7 @@ function clearSession(state) {
|
|
|
7326
7496
|
archiveMessages(state.messages, "cleared", state.models);
|
|
7327
7497
|
}
|
|
7328
7498
|
} catch (err) {
|
|
7329
|
-
|
|
7499
|
+
log11.warn("Session archive on clear failed", { error: err.message });
|
|
7330
7500
|
}
|
|
7331
7501
|
state.messages = [];
|
|
7332
7502
|
try {
|
|
@@ -7334,14 +7504,14 @@ function clearSession(state) {
|
|
|
7334
7504
|
fs21.unlinkSync(SESSION_FILE);
|
|
7335
7505
|
}
|
|
7336
7506
|
} catch (err) {
|
|
7337
|
-
|
|
7507
|
+
log11.warn("Session clear: could not remove live file", {
|
|
7338
7508
|
error: err.message
|
|
7339
7509
|
});
|
|
7340
7510
|
}
|
|
7341
7511
|
}
|
|
7342
7512
|
|
|
7343
7513
|
// src/compaction/trigger.ts
|
|
7344
|
-
var
|
|
7514
|
+
var log12 = createLogger("compaction:trigger");
|
|
7345
7515
|
var pending = null;
|
|
7346
7516
|
var inflightCompaction = null;
|
|
7347
7517
|
function getInflightCompaction() {
|
|
@@ -7380,7 +7550,7 @@ function applyPendingSummaries(state) {
|
|
|
7380
7550
|
idx = at === -1 ? 0 : at + 1;
|
|
7381
7551
|
}
|
|
7382
7552
|
state.messages.splice(idx, 0, ...drained.checkpoints);
|
|
7383
|
-
|
|
7553
|
+
log12.info("Checkpoint applied", {
|
|
7384
7554
|
index: idx,
|
|
7385
7555
|
messageCount: state.messages.length
|
|
7386
7556
|
});
|
|
@@ -7414,7 +7584,7 @@ function triggerCompaction(state, apiConfig, opts = {}) {
|
|
|
7414
7584
|
return inflightCompaction;
|
|
7415
7585
|
}
|
|
7416
7586
|
if (pending) {
|
|
7417
|
-
|
|
7587
|
+
log12.info("Compaction skipped \u2014 a checkpoint is already waiting to apply");
|
|
7418
7588
|
return Promise.resolve(null);
|
|
7419
7589
|
}
|
|
7420
7590
|
const { blocking = false, requestId, model, origin, toolCallId } = opts;
|
|
@@ -7431,12 +7601,12 @@ function triggerCompaction(state, apiConfig, opts = {}) {
|
|
|
7431
7601
|
requestId,
|
|
7432
7602
|
...summaries.length > 0 && { summaries }
|
|
7433
7603
|
});
|
|
7434
|
-
|
|
7604
|
+
log12.info("Compaction complete");
|
|
7435
7605
|
return summaries;
|
|
7436
7606
|
}).catch((err) => {
|
|
7437
7607
|
const message = err.message || "Compaction failed";
|
|
7438
7608
|
listener?.({ type: "complete", error: message, requestId });
|
|
7439
|
-
|
|
7609
|
+
log12.error("Compaction failed", { error: message });
|
|
7440
7610
|
throw err;
|
|
7441
7611
|
}).finally(() => {
|
|
7442
7612
|
inflightCompaction = null;
|
|
@@ -7448,7 +7618,7 @@ function triggerCompaction(state, apiConfig, opts = {}) {
|
|
|
7448
7618
|
import fs22 from "fs";
|
|
7449
7619
|
import path12 from "path";
|
|
7450
7620
|
import { createHash } from "crypto";
|
|
7451
|
-
var
|
|
7621
|
+
var log13 = createLogger("brandExtraction");
|
|
7452
7622
|
var EXTRACT_PROMPT = readAsset("brandExtraction", "extract.md");
|
|
7453
7623
|
var BRAND_FILE = ".remy-brand.json";
|
|
7454
7624
|
var CACHE_FILE = ".remy-brand.cache.json";
|
|
@@ -7456,17 +7626,17 @@ async function runExtraction(apiConfig, model) {
|
|
|
7456
7626
|
const inputHash = computeInputHash();
|
|
7457
7627
|
const cached3 = readCache();
|
|
7458
7628
|
if (cached3 && cached3.inputHash === inputHash) {
|
|
7459
|
-
|
|
7629
|
+
log13.debug("Brand inputs unchanged \u2014 skipping extraction", { inputHash });
|
|
7460
7630
|
return null;
|
|
7461
7631
|
}
|
|
7462
|
-
|
|
7632
|
+
log13.info("Extracting brand", { inputHash });
|
|
7463
7633
|
const brand = await extractBrand(apiConfig, model);
|
|
7464
7634
|
if (!brand) {
|
|
7465
|
-
|
|
7635
|
+
log13.warn("Brand extraction failed \u2014 leaving cache untouched");
|
|
7466
7636
|
return null;
|
|
7467
7637
|
}
|
|
7468
7638
|
persistBrand(brand, inputHash);
|
|
7469
|
-
|
|
7639
|
+
log13.info("Brand persisted", { inputHash });
|
|
7470
7640
|
return brand;
|
|
7471
7641
|
}
|
|
7472
7642
|
function isDedicatedBrandFile(filePath) {
|
|
@@ -7552,7 +7722,7 @@ function parseFrontmatter3(filePath) {
|
|
|
7552
7722
|
async function extractBrand(apiConfig, model) {
|
|
7553
7723
|
const corpus = buildCorpus();
|
|
7554
7724
|
if (!corpus.trim()) {
|
|
7555
|
-
|
|
7725
|
+
log13.debug("No spec corpus \u2014 emitting empty brand");
|
|
7556
7726
|
return { version: 1 };
|
|
7557
7727
|
}
|
|
7558
7728
|
let responseText = "";
|
|
@@ -7586,17 +7756,17 @@ async function extractBrand(apiConfig, model) {
|
|
|
7586
7756
|
toolNames: []
|
|
7587
7757
|
});
|
|
7588
7758
|
} else if (event.type === "error") {
|
|
7589
|
-
|
|
7759
|
+
log13.error("Brand extraction stream error", { error: event.error });
|
|
7590
7760
|
return null;
|
|
7591
7761
|
}
|
|
7592
7762
|
}
|
|
7593
7763
|
} catch (err) {
|
|
7594
|
-
|
|
7764
|
+
log13.error("Brand extraction threw", { error: err?.message });
|
|
7595
7765
|
return null;
|
|
7596
7766
|
}
|
|
7597
7767
|
const parsed = parseJsonResponse(responseText);
|
|
7598
7768
|
if (!parsed) {
|
|
7599
|
-
|
|
7769
|
+
log13.warn("Brand extraction returned unparseable JSON", {
|
|
7600
7770
|
preview: responseText.slice(0, 200)
|
|
7601
7771
|
});
|
|
7602
7772
|
return null;
|
|
@@ -7767,7 +7937,7 @@ function readCache() {
|
|
|
7767
7937
|
}
|
|
7768
7938
|
|
|
7769
7939
|
// src/brandExtraction/trigger.ts
|
|
7770
|
-
var
|
|
7940
|
+
var log14 = createLogger("brandExtraction:trigger");
|
|
7771
7941
|
var inflight = false;
|
|
7772
7942
|
var dirty = false;
|
|
7773
7943
|
function triggerBrandExtraction(apiConfig, model) {
|
|
@@ -7777,7 +7947,7 @@ function triggerBrandExtraction(apiConfig, model) {
|
|
|
7777
7947
|
}
|
|
7778
7948
|
inflight = true;
|
|
7779
7949
|
void runExtraction(apiConfig, model).catch((err) => {
|
|
7780
|
-
|
|
7950
|
+
log14.error("Brand extraction failed", { error: err?.message });
|
|
7781
7951
|
}).finally(() => {
|
|
7782
7952
|
inflight = false;
|
|
7783
7953
|
if (dirty) {
|
|
@@ -8041,7 +8211,7 @@ function friendlyError(raw) {
|
|
|
8041
8211
|
}
|
|
8042
8212
|
|
|
8043
8213
|
// src/agent.ts
|
|
8044
|
-
var
|
|
8214
|
+
var log15 = createLogger("agent");
|
|
8045
8215
|
var BRAND_TRIGGERING_TOOLS = /* @__PURE__ */ new Set([
|
|
8046
8216
|
"writeSpec",
|
|
8047
8217
|
"editSpec",
|
|
@@ -8057,11 +8227,12 @@ function getToolCalls(blocks) {
|
|
|
8057
8227
|
}
|
|
8058
8228
|
var EXTERNAL_TOOLS = /* @__PURE__ */ new Set([
|
|
8059
8229
|
"promptUser",
|
|
8060
|
-
"
|
|
8230
|
+
"markBuildComplete",
|
|
8061
8231
|
"presentPublishPlan",
|
|
8062
8232
|
"confirmDestructiveAction",
|
|
8063
8233
|
"runScenario",
|
|
8064
8234
|
"runMethod",
|
|
8235
|
+
"testJewel",
|
|
8065
8236
|
"queryDatabase",
|
|
8066
8237
|
"browserCommand",
|
|
8067
8238
|
"setProjectMetadata"
|
|
@@ -8105,7 +8276,7 @@ async function runTurn(params) {
|
|
|
8105
8276
|
(n, e) => n + (e.attachments?.length ?? 0),
|
|
8106
8277
|
0
|
|
8107
8278
|
);
|
|
8108
|
-
|
|
8279
|
+
log15.info("Turn started", {
|
|
8109
8280
|
requestId,
|
|
8110
8281
|
model,
|
|
8111
8282
|
buildModel: buildModelOverride,
|
|
@@ -8154,7 +8325,7 @@ async function runTurn(params) {
|
|
|
8154
8325
|
}
|
|
8155
8326
|
const isFirstMessage = state.messages.filter((m) => m.role === "user").length === 1;
|
|
8156
8327
|
const STATUS_EXCLUDED_TOOLS = /* @__PURE__ */ new Set([
|
|
8157
|
-
"
|
|
8328
|
+
"markBuildComplete",
|
|
8158
8329
|
"setProjectMetadata",
|
|
8159
8330
|
"editsFinished"
|
|
8160
8331
|
]);
|
|
@@ -8400,7 +8571,7 @@ async function runTurn(params) {
|
|
|
8400
8571
|
const acc = toolInputAccumulators.get(event.id);
|
|
8401
8572
|
const wasStreamed = acc?.started ?? false;
|
|
8402
8573
|
const isInputStreaming = !!tool?.streaming?.partialInput;
|
|
8403
|
-
|
|
8574
|
+
log15.info("Tool received", {
|
|
8404
8575
|
requestId,
|
|
8405
8576
|
toolCallId: event.id,
|
|
8406
8577
|
name: event.name
|
|
@@ -8519,7 +8690,7 @@ async function runTurn(params) {
|
|
|
8519
8690
|
const toolCalls = getToolCalls(contentBlocks);
|
|
8520
8691
|
if (toolCalls.length === 0 && (stopReason === "repetition" || stopReason === "max_tokens") && abnormalStopRecoveries < MAX_ABNORMAL_STOP_RECOVERIES && !signal?.aborted) {
|
|
8521
8692
|
abnormalStopRecoveries++;
|
|
8522
|
-
|
|
8693
|
+
log15.warn("Abnormal stop \u2014 nudging model to continue", {
|
|
8523
8694
|
requestId,
|
|
8524
8695
|
stopReason,
|
|
8525
8696
|
attempt: abnormalStopRecoveries
|
|
@@ -8547,7 +8718,7 @@ async function runTurn(params) {
|
|
|
8547
8718
|
});
|
|
8548
8719
|
return;
|
|
8549
8720
|
}
|
|
8550
|
-
|
|
8721
|
+
log15.info("Tools executing", {
|
|
8551
8722
|
requestId,
|
|
8552
8723
|
count: toolCalls.length,
|
|
8553
8724
|
tools: toolCalls.map((tc) => tc.name)
|
|
@@ -8594,7 +8765,7 @@ async function runTurn(params) {
|
|
|
8594
8765
|
let result;
|
|
8595
8766
|
if (EXTERNAL_TOOLS.has(tc.name) && resolveExternalTool) {
|
|
8596
8767
|
saveSession(state);
|
|
8597
|
-
|
|
8768
|
+
log15.info("Waiting for external tool result", {
|
|
8598
8769
|
requestId,
|
|
8599
8770
|
toolCallId: tc.id,
|
|
8600
8771
|
name: tc.name
|
|
@@ -8662,7 +8833,7 @@ async function runTurn(params) {
|
|
|
8662
8833
|
if (!isBackgroundCall(tc)) {
|
|
8663
8834
|
toolRegistry?.unregister(tc.id);
|
|
8664
8835
|
}
|
|
8665
|
-
|
|
8836
|
+
log15.info("Tool completed", {
|
|
8666
8837
|
requestId,
|
|
8667
8838
|
toolCallId: tc.id,
|
|
8668
8839
|
name: tc.name,
|
|
@@ -8739,9 +8910,9 @@ async function runTurn(params) {
|
|
|
8739
8910
|
|
|
8740
8911
|
// src/headless/attachments.ts
|
|
8741
8912
|
import { mkdirSync, existsSync } from "fs";
|
|
8742
|
-
import { writeFile as
|
|
8743
|
-
import { basename as basename2, join as
|
|
8744
|
-
var
|
|
8913
|
+
import { writeFile as writeFile3 } from "fs/promises";
|
|
8914
|
+
import { basename as basename2, join as join3, extname as extname2 } from "path";
|
|
8915
|
+
var log16 = createLogger("headless:attachments");
|
|
8745
8916
|
var UPLOADS_DIR = "src/.user-uploads";
|
|
8746
8917
|
function filenameFromUrl(url) {
|
|
8747
8918
|
try {
|
|
@@ -8753,7 +8924,7 @@ function filenameFromUrl(url) {
|
|
|
8753
8924
|
}
|
|
8754
8925
|
}
|
|
8755
8926
|
function resolveUniqueFilename(name, claimed) {
|
|
8756
|
-
const isFree = (candidate) => !claimed.has(candidate) && !existsSync(
|
|
8927
|
+
const isFree = (candidate) => !claimed.has(candidate) && !existsSync(join3(UPLOADS_DIR, candidate));
|
|
8757
8928
|
if (isFree(name)) {
|
|
8758
8929
|
return name;
|
|
8759
8930
|
}
|
|
@@ -8788,7 +8959,7 @@ async function persistAttachments(attachments) {
|
|
|
8788
8959
|
const results = await Promise.allSettled(
|
|
8789
8960
|
nonVoice.map(async (att, i) => {
|
|
8790
8961
|
const name = names[i];
|
|
8791
|
-
const localPath =
|
|
8962
|
+
const localPath = join3(UPLOADS_DIR, name);
|
|
8792
8963
|
const res = await fetch(att.url, {
|
|
8793
8964
|
signal: AbortSignal.timeout(3e4)
|
|
8794
8965
|
});
|
|
@@ -8796,8 +8967,8 @@ async function persistAttachments(attachments) {
|
|
|
8796
8967
|
throw new Error(`HTTP ${res.status} downloading ${att.url}`);
|
|
8797
8968
|
}
|
|
8798
8969
|
const buffer = Buffer.from(await res.arrayBuffer());
|
|
8799
|
-
await
|
|
8800
|
-
|
|
8970
|
+
await writeFile3(localPath, buffer);
|
|
8971
|
+
log16.info("Attachment saved", {
|
|
8801
8972
|
filename: name,
|
|
8802
8973
|
path: localPath,
|
|
8803
8974
|
bytes: buffer.length
|
|
@@ -8810,8 +8981,8 @@ async function persistAttachments(attachments) {
|
|
|
8810
8981
|
});
|
|
8811
8982
|
if (textRes.ok) {
|
|
8812
8983
|
extractedTextPath = `${localPath}.txt`;
|
|
8813
|
-
await
|
|
8814
|
-
|
|
8984
|
+
await writeFile3(extractedTextPath, await textRes.text(), "utf-8");
|
|
8985
|
+
log16.info("Extracted text saved", { path: extractedTextPath });
|
|
8815
8986
|
}
|
|
8816
8987
|
} catch {
|
|
8817
8988
|
}
|
|
@@ -9017,8 +9188,10 @@ var MessageQueue = class {
|
|
|
9017
9188
|
};
|
|
9018
9189
|
|
|
9019
9190
|
// src/headless/index.ts
|
|
9020
|
-
var
|
|
9191
|
+
var log17 = createLogger("headless");
|
|
9021
9192
|
var EXTERNAL_TOOL_TIMEOUT_MS = 3e5;
|
|
9193
|
+
var LONG_RUNNING_TOOLS = /* @__PURE__ */ new Set(["runMethod", "testJewel"]);
|
|
9194
|
+
var LONG_RUNNING_TOOL_TIMEOUT_MS = 18e5;
|
|
9022
9195
|
var USER_FACING_TOOLS = /* @__PURE__ */ new Set([
|
|
9023
9196
|
"promptUser",
|
|
9024
9197
|
"confirmDestructiveAction",
|
|
@@ -9240,7 +9413,7 @@ var HeadlessSession = class {
|
|
|
9240
9413
|
}
|
|
9241
9414
|
const line = JSON.stringify(payload) + "\n";
|
|
9242
9415
|
if (event === "history") {
|
|
9243
|
-
|
|
9416
|
+
log17.info("Wrote history event to stdout", {
|
|
9244
9417
|
requestId,
|
|
9245
9418
|
bytes: line.length
|
|
9246
9419
|
});
|
|
@@ -9326,7 +9499,7 @@ var HeadlessSession = class {
|
|
|
9326
9499
|
if (this.sessionStats.lastContextSize <= FORCED_COMPACTION_THRESHOLD_TOKENS) {
|
|
9327
9500
|
return;
|
|
9328
9501
|
}
|
|
9329
|
-
|
|
9502
|
+
log17.info("Forced compaction gate triggered", {
|
|
9330
9503
|
contextSize: this.sessionStats.lastContextSize,
|
|
9331
9504
|
threshold: FORCED_COMPACTION_THRESHOLD_TOKENS,
|
|
9332
9505
|
requestId
|
|
@@ -9345,7 +9518,7 @@ var HeadlessSession = class {
|
|
|
9345
9518
|
onBackgroundComplete = (toolCallId, name, result, subAgentMessages) => {
|
|
9346
9519
|
const notify = getToolByName(name)?.backgroundNotify ?? "wake";
|
|
9347
9520
|
this.pendingBlockUpdates.push({ toolCallId, result, subAgentMessages });
|
|
9348
|
-
|
|
9521
|
+
log17.info("Background complete", {
|
|
9349
9522
|
toolCallId,
|
|
9350
9523
|
name,
|
|
9351
9524
|
notify,
|
|
@@ -9397,13 +9570,14 @@ var HeadlessSession = class {
|
|
|
9397
9570
|
return Promise.resolve(early);
|
|
9398
9571
|
}
|
|
9399
9572
|
const shouldTimeout = !USER_FACING_TOOLS.has(name);
|
|
9573
|
+
const timeoutMs = LONG_RUNNING_TOOLS.has(name) ? LONG_RUNNING_TOOL_TIMEOUT_MS : EXTERNAL_TOOL_TIMEOUT_MS;
|
|
9400
9574
|
return new Promise((resolve4) => {
|
|
9401
9575
|
const timeout = shouldTimeout ? setTimeout(() => {
|
|
9402
9576
|
this.pendingTools.delete(id);
|
|
9403
9577
|
resolve4(
|
|
9404
|
-
|
|
9578
|
+
`Error: Tool timed out \u2014 no response from the app environment after ${Math.round(timeoutMs / 6e4)} minutes.`
|
|
9405
9579
|
);
|
|
9406
|
-
},
|
|
9580
|
+
}, timeoutMs) : void 0;
|
|
9407
9581
|
this.pendingTools.set(id, {
|
|
9408
9582
|
resolve: (result) => {
|
|
9409
9583
|
clearTimeout(timeout);
|
|
@@ -9607,7 +9781,7 @@ var HeadlessSession = class {
|
|
|
9607
9781
|
const { documents, images } = await persistAttachments(attachments);
|
|
9608
9782
|
return buildUploadHeader(documents, images) || void 0;
|
|
9609
9783
|
} catch (err) {
|
|
9610
|
-
|
|
9784
|
+
log17.warn("Attachment persistence failed", { error: err.message });
|
|
9611
9785
|
return void 0;
|
|
9612
9786
|
}
|
|
9613
9787
|
}
|
|
@@ -9621,7 +9795,7 @@ var HeadlessSession = class {
|
|
|
9621
9795
|
async runSingleTurn(parsed, requestId, fromChain = false, queued = false) {
|
|
9622
9796
|
const attachments = parsed.attachments;
|
|
9623
9797
|
if (attachments?.length) {
|
|
9624
|
-
|
|
9798
|
+
log17.info("Message has attachments", {
|
|
9625
9799
|
count: attachments.length,
|
|
9626
9800
|
urls: attachments.map((a) => a.url)
|
|
9627
9801
|
});
|
|
@@ -9809,7 +9983,7 @@ var HeadlessSession = class {
|
|
|
9809
9983
|
error: "Turn ended unexpectedly"
|
|
9810
9984
|
});
|
|
9811
9985
|
}
|
|
9812
|
-
|
|
9986
|
+
log17.info("Turn complete", {
|
|
9813
9987
|
requestId,
|
|
9814
9988
|
durationMs: Date.now() - this.turnStart
|
|
9815
9989
|
});
|
|
@@ -9821,7 +9995,7 @@ var HeadlessSession = class {
|
|
|
9821
9995
|
error: err.message
|
|
9822
9996
|
});
|
|
9823
9997
|
}
|
|
9824
|
-
|
|
9998
|
+
log17.warn("Command failed", {
|
|
9825
9999
|
action: "message",
|
|
9826
10000
|
requestId,
|
|
9827
10001
|
error: err.message
|
|
@@ -10031,7 +10205,7 @@ var HeadlessSession = class {
|
|
|
10031
10205
|
try {
|
|
10032
10206
|
parsed = JSON.parse(line);
|
|
10033
10207
|
} catch (err) {
|
|
10034
|
-
|
|
10208
|
+
log17.warn("Invalid JSON on stdin", {
|
|
10035
10209
|
error: err.message,
|
|
10036
10210
|
lineLength: line.length,
|
|
10037
10211
|
preview: line.slice(0, 200)
|
|
@@ -10040,7 +10214,7 @@ var HeadlessSession = class {
|
|
|
10040
10214
|
return;
|
|
10041
10215
|
}
|
|
10042
10216
|
const { action, requestId } = parsed;
|
|
10043
|
-
|
|
10217
|
+
log17.info("Command received", { action, requestId });
|
|
10044
10218
|
if (action === "tool_result" && parsed.id) {
|
|
10045
10219
|
const id = parsed.id;
|
|
10046
10220
|
const result = parsed.result ?? "";
|
|
@@ -10049,7 +10223,7 @@ var HeadlessSession = class {
|
|
|
10049
10223
|
this.pendingTools.delete(id);
|
|
10050
10224
|
pending2.resolve(result);
|
|
10051
10225
|
} else if (!this.running) {
|
|
10052
|
-
|
|
10226
|
+
log17.info("Late tool_result while idle, dismissing", { id });
|
|
10053
10227
|
this.emit("completed", { success: true }, requestId);
|
|
10054
10228
|
} else {
|
|
10055
10229
|
this.earlyResults.set(id, result);
|
|
@@ -10062,7 +10236,7 @@ var HeadlessSession = class {
|
|
|
10062
10236
|
...typeof parsed.before === "number" ? { before: parsed.before } : {},
|
|
10063
10237
|
...typeof parsed.limit === "number" ? { limit: parsed.limit } : {}
|
|
10064
10238
|
});
|
|
10065
|
-
|
|
10239
|
+
log17.info("History response", {
|
|
10066
10240
|
requestId,
|
|
10067
10241
|
startIndex: page.startIndex,
|
|
10068
10242
|
endIndex: page.endIndex,
|