@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/index.js
CHANGED
|
@@ -994,25 +994,18 @@ var init_updatePlanStatus = __esm({
|
|
|
994
994
|
}
|
|
995
995
|
});
|
|
996
996
|
|
|
997
|
-
// src/tools/common/
|
|
998
|
-
var
|
|
999
|
-
var
|
|
1000
|
-
"src/tools/common/
|
|
997
|
+
// src/tools/common/markBuildComplete.ts
|
|
998
|
+
var markBuildCompleteTool;
|
|
999
|
+
var init_markBuildComplete = __esm({
|
|
1000
|
+
"src/tools/common/markBuildComplete.ts"() {
|
|
1001
1001
|
"use strict";
|
|
1002
|
-
|
|
1002
|
+
markBuildCompleteTool = {
|
|
1003
1003
|
definition: {
|
|
1004
|
-
name: "
|
|
1005
|
-
description:
|
|
1004
|
+
name: "markBuildComplete",
|
|
1005
|
+
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.',
|
|
1006
1006
|
inputSchema: {
|
|
1007
1007
|
type: "object",
|
|
1008
|
-
properties: {
|
|
1009
|
-
state: {
|
|
1010
|
-
type: "string",
|
|
1011
|
-
enum: ["building", "buildComplete", "onboardingFinished"],
|
|
1012
|
-
description: "The onboarding state to advance to."
|
|
1013
|
-
}
|
|
1014
|
-
},
|
|
1015
|
-
required: ["state"]
|
|
1008
|
+
properties: {}
|
|
1016
1009
|
}
|
|
1017
1010
|
},
|
|
1018
1011
|
async execute() {
|
|
@@ -4146,6 +4139,41 @@ var init_runMethod = __esm({
|
|
|
4146
4139
|
}
|
|
4147
4140
|
});
|
|
4148
4141
|
|
|
4142
|
+
// src/tools/code/testJewel.ts
|
|
4143
|
+
var testJewelTool;
|
|
4144
|
+
var init_testJewel = __esm({
|
|
4145
|
+
"src/tools/code/testJewel.ts"() {
|
|
4146
|
+
"use strict";
|
|
4147
|
+
testJewelTool = {
|
|
4148
|
+
definition: {
|
|
4149
|
+
name: "testJewel",
|
|
4150
|
+
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.",
|
|
4151
|
+
inputSchema: {
|
|
4152
|
+
type: "object",
|
|
4153
|
+
properties: {
|
|
4154
|
+
method: {
|
|
4155
|
+
type: "string",
|
|
4156
|
+
description: 'The shadowed method\'s export name (camelCase, e.g. "updateIssue"). Its manifest entry must have a `jewel` pointer.'
|
|
4157
|
+
},
|
|
4158
|
+
humanInput: {
|
|
4159
|
+
type: "object",
|
|
4160
|
+
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."
|
|
4161
|
+
},
|
|
4162
|
+
subject: {
|
|
4163
|
+
type: "object",
|
|
4164
|
+
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."
|
|
4165
|
+
}
|
|
4166
|
+
},
|
|
4167
|
+
required: ["method"]
|
|
4168
|
+
}
|
|
4169
|
+
},
|
|
4170
|
+
async execute() {
|
|
4171
|
+
return "ok";
|
|
4172
|
+
}
|
|
4173
|
+
};
|
|
4174
|
+
}
|
|
4175
|
+
});
|
|
4176
|
+
|
|
4149
4177
|
// src/tools/code/queryDatabase.ts
|
|
4150
4178
|
var queryDatabaseTool;
|
|
4151
4179
|
var init_queryDatabase = __esm({
|
|
@@ -6704,6 +6732,155 @@ var init_loadSkill2 = __esm({
|
|
|
6704
6732
|
}
|
|
6705
6733
|
});
|
|
6706
6734
|
|
|
6735
|
+
// src/subagents/designExpert/tools/createWireframe.ts
|
|
6736
|
+
var createWireframe_exports = {};
|
|
6737
|
+
__export(createWireframe_exports, {
|
|
6738
|
+
WIREFRAMES_DIR: () => WIREFRAMES_DIR,
|
|
6739
|
+
definition: () => definition10,
|
|
6740
|
+
execute: () => execute10
|
|
6741
|
+
});
|
|
6742
|
+
import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
|
|
6743
|
+
import { join as join2 } from "path";
|
|
6744
|
+
function slugify(name) {
|
|
6745
|
+
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40).replace(/-+$/, "") || "wireframe";
|
|
6746
|
+
}
|
|
6747
|
+
function singleLine(value) {
|
|
6748
|
+
return value.replace(/\s+/g, " ").trim();
|
|
6749
|
+
}
|
|
6750
|
+
function validate(name, html) {
|
|
6751
|
+
const warnings = [];
|
|
6752
|
+
if (!name.trim()) {
|
|
6753
|
+
return { error: "Error: name is required.", warnings };
|
|
6754
|
+
}
|
|
6755
|
+
if (!html.trim()) {
|
|
6756
|
+
return { error: "Error: html is required.", warnings };
|
|
6757
|
+
}
|
|
6758
|
+
if (/^\s*---/.test(html)) {
|
|
6759
|
+
return {
|
|
6760
|
+
error: "Error: html must not include frontmatter \u2014 pass name and description as parameters and the frontmatter is added for you.",
|
|
6761
|
+
warnings
|
|
6762
|
+
};
|
|
6763
|
+
}
|
|
6764
|
+
if (/<img[\s>]/i.test(html)) {
|
|
6765
|
+
return {
|
|
6766
|
+
error: "Error: wireframes must not contain <img> tags. Use skeleton placeholders (grey boxes, gradients) instead of images.",
|
|
6767
|
+
warnings
|
|
6768
|
+
};
|
|
6769
|
+
}
|
|
6770
|
+
if (!/<style[\s>]/i.test(html) && !/style=/i.test(html)) {
|
|
6771
|
+
return {
|
|
6772
|
+
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.",
|
|
6773
|
+
warnings
|
|
6774
|
+
};
|
|
6775
|
+
}
|
|
6776
|
+
const lines = html.split("\n").length;
|
|
6777
|
+
if (lines > 120) {
|
|
6778
|
+
warnings.push(
|
|
6779
|
+
`The wireframe is ${lines} lines \u2014 past the ~100-line budget. Wireframes isolate one small piece; consider whether this is building too much.`
|
|
6780
|
+
);
|
|
6781
|
+
}
|
|
6782
|
+
return { warnings };
|
|
6783
|
+
}
|
|
6784
|
+
async function uploadMirror(context, slug, content) {
|
|
6785
|
+
const { apiConfig } = context;
|
|
6786
|
+
if (!apiConfig?.appId) {
|
|
6787
|
+
return { ok: false, note: "no app id in this session" };
|
|
6788
|
+
}
|
|
6789
|
+
try {
|
|
6790
|
+
const url = `${apiConfig.baseUrl}/_internal/v2/apps/${apiConfig.appId}/dev/wireframes`;
|
|
6791
|
+
const res = await fetch(url, {
|
|
6792
|
+
method: "POST",
|
|
6793
|
+
headers: {
|
|
6794
|
+
"Content-Type": "application/json",
|
|
6795
|
+
Authorization: `Bearer ${apiConfig.apiKey}`
|
|
6796
|
+
},
|
|
6797
|
+
body: JSON.stringify({ slug, content }),
|
|
6798
|
+
signal: AbortSignal.timeout(UPLOAD_TIMEOUT_MS2)
|
|
6799
|
+
});
|
|
6800
|
+
if (!res.ok) {
|
|
6801
|
+
return { ok: false, note: `HTTP ${res.status}` };
|
|
6802
|
+
}
|
|
6803
|
+
return { ok: true };
|
|
6804
|
+
} catch (err) {
|
|
6805
|
+
return { ok: false, note: err.message };
|
|
6806
|
+
}
|
|
6807
|
+
}
|
|
6808
|
+
async function execute10(input, onLog, context) {
|
|
6809
|
+
if (!context) {
|
|
6810
|
+
return "Error: createWireframe requires execution context";
|
|
6811
|
+
}
|
|
6812
|
+
const name = String(input.name ?? "");
|
|
6813
|
+
const description = String(input.description ?? "");
|
|
6814
|
+
const html = String(input.html ?? "");
|
|
6815
|
+
const { error, warnings } = validate(name, html);
|
|
6816
|
+
if (error) {
|
|
6817
|
+
return error;
|
|
6818
|
+
}
|
|
6819
|
+
const slug = `${slugify(name)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
6820
|
+
const relPath = `${WIREFRAMES_DIR}/${slug}.html`;
|
|
6821
|
+
const content = [
|
|
6822
|
+
"---",
|
|
6823
|
+
`name: ${singleLine(name)}`,
|
|
6824
|
+
`description: ${singleLine(description)}`,
|
|
6825
|
+
"---",
|
|
6826
|
+
html.trim(),
|
|
6827
|
+
""
|
|
6828
|
+
].join("\n");
|
|
6829
|
+
await mkdir2(join2(PROJECT_ROOT, WIREFRAMES_DIR), { recursive: true });
|
|
6830
|
+
await writeFile2(join2(PROJECT_ROOT, relPath), content, "utf8");
|
|
6831
|
+
onLog?.(`Wrote ${relPath}, mirroring for preview...`);
|
|
6832
|
+
const mirror = await uploadMirror(context, slug, content);
|
|
6833
|
+
if (!mirror.ok) {
|
|
6834
|
+
log10.warn("Wireframe mirror upload failed", { slug, note: mirror.note });
|
|
6835
|
+
}
|
|
6836
|
+
const lines = [
|
|
6837
|
+
`Created wireframe "${singleLine(name)}" at ${relPath}.`,
|
|
6838
|
+
`Reference it in your response and in specs with exactly: `
|
|
6839
|
+
];
|
|
6840
|
+
if (!mirror.ok) {
|
|
6841
|
+
lines.push(
|
|
6842
|
+
`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.`
|
|
6843
|
+
);
|
|
6844
|
+
}
|
|
6845
|
+
if (warnings.length > 0) {
|
|
6846
|
+
lines.push(...warnings.map((w) => `Note: ${w}`));
|
|
6847
|
+
}
|
|
6848
|
+
return lines.join("\n");
|
|
6849
|
+
}
|
|
6850
|
+
var log10, WIREFRAMES_DIR, UPLOAD_TIMEOUT_MS2, definition10;
|
|
6851
|
+
var init_createWireframe = __esm({
|
|
6852
|
+
"src/subagents/designExpert/tools/createWireframe.ts"() {
|
|
6853
|
+
"use strict";
|
|
6854
|
+
init_projectRoot();
|
|
6855
|
+
init_logger();
|
|
6856
|
+
log10 = createLogger("createWireframe");
|
|
6857
|
+
WIREFRAMES_DIR = "src/.wireframes";
|
|
6858
|
+
UPLOAD_TIMEOUT_MS2 = 3e4;
|
|
6859
|
+
definition10 = {
|
|
6860
|
+
name: "createWireframe",
|
|
6861
|
+
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).",
|
|
6862
|
+
inputSchema: {
|
|
6863
|
+
type: "object",
|
|
6864
|
+
properties: {
|
|
6865
|
+
name: {
|
|
6866
|
+
type: "string",
|
|
6867
|
+
description: 'Short display name, e.g. "Feed Post Card". Becomes the caption and the filename slug.'
|
|
6868
|
+
},
|
|
6869
|
+
description: {
|
|
6870
|
+
type: "string",
|
|
6871
|
+
description: "One line on what the wireframe shows \u2014 layout, states, motion."
|
|
6872
|
+
},
|
|
6873
|
+
html: {
|
|
6874
|
+
type: "string",
|
|
6875
|
+
description: "The complete HTML document (<html>\u2026</html>), self-contained vanilla HTML/CSS/JS. No frontmatter \u2014 it is added for you."
|
|
6876
|
+
}
|
|
6877
|
+
},
|
|
6878
|
+
required: ["name", "description", "html"]
|
|
6879
|
+
}
|
|
6880
|
+
};
|
|
6881
|
+
}
|
|
6882
|
+
});
|
|
6883
|
+
|
|
6707
6884
|
// src/subagents/designExpert/tools/index.ts
|
|
6708
6885
|
async function executeDesignExpertTool(name, input, context, toolCallId, onLog) {
|
|
6709
6886
|
const tool = tools[name];
|
|
@@ -6728,6 +6905,7 @@ var init_tools4 = __esm({
|
|
|
6728
6905
|
init_renderImage();
|
|
6729
6906
|
init_polishCopy();
|
|
6730
6907
|
init_loadSkill2();
|
|
6908
|
+
init_createWireframe();
|
|
6731
6909
|
init_screenshot2();
|
|
6732
6910
|
tools = {
|
|
6733
6911
|
searchGoogle: searchGoogle_exports,
|
|
@@ -6742,7 +6920,9 @@ var init_tools4 = __esm({
|
|
|
6742
6920
|
editImages: editImages_exports,
|
|
6743
6921
|
renderImage: renderImage_exports,
|
|
6744
6922
|
polishCopy: polishCopy_exports,
|
|
6745
|
-
loadSkill: loadSkill_exports
|
|
6923
|
+
loadSkill: loadSkill_exports,
|
|
6924
|
+
// Appended last: tool order is part of the subagent's prompt-cache prefix.
|
|
6925
|
+
createWireframe: createWireframe_exports
|
|
6746
6926
|
};
|
|
6747
6927
|
DESIGN_EXPERT_TOOLS = [
|
|
6748
6928
|
...COMMON_READ_TOOLS,
|
|
@@ -6757,7 +6937,7 @@ async function initOrgContext(config) {
|
|
|
6757
6937
|
cached = await fetchRemyContext(config);
|
|
6758
6938
|
const orgDefaultModels2 = filterModelPicks(cached?.defaultModels);
|
|
6759
6939
|
setOrgDefaultModels(orgDefaultModels2);
|
|
6760
|
-
|
|
6940
|
+
log11.debug("org context loaded", {
|
|
6761
6941
|
delegatedAvailable: cached?.auth?.delegatedAvailable ?? false,
|
|
6762
6942
|
requireDelegatedOnly: cached?.auth?.requireDelegatedOnly ?? false,
|
|
6763
6943
|
hasOrgName: !!cached?.org?.name,
|
|
@@ -6766,7 +6946,7 @@ async function initOrgContext(config) {
|
|
|
6766
6946
|
} catch (err) {
|
|
6767
6947
|
cached = null;
|
|
6768
6948
|
setOrgDefaultModels({});
|
|
6769
|
-
|
|
6949
|
+
log11.debug("org context init failed", { error: err.message });
|
|
6770
6950
|
}
|
|
6771
6951
|
}
|
|
6772
6952
|
function getOrgContext() {
|
|
@@ -6802,14 +6982,14 @@ function renderOrgContextBlock() {
|
|
|
6802
6982
|
lines.push("</org_context>");
|
|
6803
6983
|
return lines.join("\n");
|
|
6804
6984
|
}
|
|
6805
|
-
var
|
|
6985
|
+
var log11, cached;
|
|
6806
6986
|
var init_orgContext = __esm({
|
|
6807
6987
|
"src/orgContext.ts"() {
|
|
6808
6988
|
"use strict";
|
|
6809
6989
|
init_api();
|
|
6810
6990
|
init_surfaces();
|
|
6811
6991
|
init_logger();
|
|
6812
|
-
|
|
6992
|
+
log11 = createLogger("orgContext");
|
|
6813
6993
|
cached = null;
|
|
6814
6994
|
}
|
|
6815
6995
|
});
|
|
@@ -7966,7 +8146,7 @@ var init_tools8 = __esm({
|
|
|
7966
8146
|
init_presentPublishPlan();
|
|
7967
8147
|
init_writePlan();
|
|
7968
8148
|
init_updatePlanStatus();
|
|
7969
|
-
|
|
8149
|
+
init_markBuildComplete();
|
|
7970
8150
|
init_promptUser();
|
|
7971
8151
|
init_confirmDestructiveAction();
|
|
7972
8152
|
init_sdkConsultant();
|
|
@@ -7986,6 +8166,7 @@ var init_tools8 = __esm({
|
|
|
7986
8166
|
init_restartProcess();
|
|
7987
8167
|
init_runScenario();
|
|
7988
8168
|
init_runMethod();
|
|
8169
|
+
init_testJewel();
|
|
7989
8170
|
init_queryDatabase();
|
|
7990
8171
|
init_screenshot2();
|
|
7991
8172
|
init_browserAutomation();
|
|
@@ -7998,7 +8179,7 @@ var init_tools8 = __esm({
|
|
|
7998
8179
|
init_writeBuildOverview();
|
|
7999
8180
|
ALL_TOOLS = [
|
|
8000
8181
|
// Common
|
|
8001
|
-
|
|
8182
|
+
markBuildCompleteTool,
|
|
8002
8183
|
promptUserTool,
|
|
8003
8184
|
confirmDestructiveActionTool,
|
|
8004
8185
|
askMindStudioSdkTool,
|
|
@@ -8041,7 +8222,8 @@ var init_tools8 = __esm({
|
|
|
8041
8222
|
restartProcessTool,
|
|
8042
8223
|
// Appended rather than grouped: position is part of the cache prefix, so a
|
|
8043
8224
|
// new tool goes at the end to leave every existing session's prefix intact.
|
|
8044
|
-
loadSkillTool
|
|
8225
|
+
loadSkillTool,
|
|
8226
|
+
testJewelTool
|
|
8045
8227
|
];
|
|
8046
8228
|
SUBAGENT_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
8047
8229
|
"visualDesignExpert",
|
|
@@ -8336,17 +8518,17 @@ async function runExtraction(apiConfig, model) {
|
|
|
8336
8518
|
const inputHash = computeInputHash();
|
|
8337
8519
|
const cached3 = readCache();
|
|
8338
8520
|
if (cached3 && cached3.inputHash === inputHash) {
|
|
8339
|
-
|
|
8521
|
+
log12.debug("Brand inputs unchanged \u2014 skipping extraction", { inputHash });
|
|
8340
8522
|
return null;
|
|
8341
8523
|
}
|
|
8342
|
-
|
|
8524
|
+
log12.info("Extracting brand", { inputHash });
|
|
8343
8525
|
const brand = await extractBrand(apiConfig, model);
|
|
8344
8526
|
if (!brand) {
|
|
8345
|
-
|
|
8527
|
+
log12.warn("Brand extraction failed \u2014 leaving cache untouched");
|
|
8346
8528
|
return null;
|
|
8347
8529
|
}
|
|
8348
8530
|
persistBrand(brand, inputHash);
|
|
8349
|
-
|
|
8531
|
+
log12.info("Brand persisted", { inputHash });
|
|
8350
8532
|
return brand;
|
|
8351
8533
|
}
|
|
8352
8534
|
function isDedicatedBrandFile(filePath) {
|
|
@@ -8432,7 +8614,7 @@ function parseFrontmatter3(filePath) {
|
|
|
8432
8614
|
async function extractBrand(apiConfig, model) {
|
|
8433
8615
|
const corpus = buildCorpus();
|
|
8434
8616
|
if (!corpus.trim()) {
|
|
8435
|
-
|
|
8617
|
+
log12.debug("No spec corpus \u2014 emitting empty brand");
|
|
8436
8618
|
return { version: 1 };
|
|
8437
8619
|
}
|
|
8438
8620
|
let responseText = "";
|
|
@@ -8466,17 +8648,17 @@ async function extractBrand(apiConfig, model) {
|
|
|
8466
8648
|
toolNames: []
|
|
8467
8649
|
});
|
|
8468
8650
|
} else if (event.type === "error") {
|
|
8469
|
-
|
|
8651
|
+
log12.error("Brand extraction stream error", { error: event.error });
|
|
8470
8652
|
return null;
|
|
8471
8653
|
}
|
|
8472
8654
|
}
|
|
8473
8655
|
} catch (err) {
|
|
8474
|
-
|
|
8656
|
+
log12.error("Brand extraction threw", { error: err?.message });
|
|
8475
8657
|
return null;
|
|
8476
8658
|
}
|
|
8477
8659
|
const parsed = parseJsonResponse(responseText);
|
|
8478
8660
|
if (!parsed) {
|
|
8479
|
-
|
|
8661
|
+
log12.warn("Brand extraction returned unparseable JSON", {
|
|
8480
8662
|
preview: responseText.slice(0, 200)
|
|
8481
8663
|
});
|
|
8482
8664
|
return null;
|
|
@@ -8643,7 +8825,7 @@ function readCache() {
|
|
|
8643
8825
|
return null;
|
|
8644
8826
|
}
|
|
8645
8827
|
}
|
|
8646
|
-
var
|
|
8828
|
+
var log12, EXTRACT_PROMPT, BRAND_FILE, CACHE_FILE, HEAD_SLICE_CHARS, BRAND_CORPUS_CHAR_LIMIT;
|
|
8647
8829
|
var init_brandExtraction = __esm({
|
|
8648
8830
|
"src/brandExtraction/index.ts"() {
|
|
8649
8831
|
"use strict";
|
|
@@ -8652,7 +8834,7 @@ var init_brandExtraction = __esm({
|
|
|
8652
8834
|
init_atomicWrite();
|
|
8653
8835
|
init_logger();
|
|
8654
8836
|
init_usageLedger();
|
|
8655
|
-
|
|
8837
|
+
log12 = createLogger("brandExtraction");
|
|
8656
8838
|
EXTRACT_PROMPT = readAsset("brandExtraction", "extract.md");
|
|
8657
8839
|
BRAND_FILE = ".remy-brand.json";
|
|
8658
8840
|
CACHE_FILE = ".remy-brand.cache.json";
|
|
@@ -8669,7 +8851,7 @@ function triggerBrandExtraction(apiConfig, model) {
|
|
|
8669
8851
|
}
|
|
8670
8852
|
inflight = true;
|
|
8671
8853
|
void runExtraction(apiConfig, model).catch((err) => {
|
|
8672
|
-
|
|
8854
|
+
log13.error("Brand extraction failed", { error: err?.message });
|
|
8673
8855
|
}).finally(() => {
|
|
8674
8856
|
inflight = false;
|
|
8675
8857
|
if (dirty) {
|
|
@@ -8678,13 +8860,13 @@ function triggerBrandExtraction(apiConfig, model) {
|
|
|
8678
8860
|
}
|
|
8679
8861
|
});
|
|
8680
8862
|
}
|
|
8681
|
-
var
|
|
8863
|
+
var log13, inflight, dirty;
|
|
8682
8864
|
var init_trigger2 = __esm({
|
|
8683
8865
|
"src/brandExtraction/trigger.ts"() {
|
|
8684
8866
|
"use strict";
|
|
8685
8867
|
init_brandExtraction();
|
|
8686
8868
|
init_logger();
|
|
8687
|
-
|
|
8869
|
+
log13 = createLogger("brandExtraction:trigger");
|
|
8688
8870
|
inflight = false;
|
|
8689
8871
|
dirty = false;
|
|
8690
8872
|
}
|
|
@@ -8733,7 +8915,7 @@ async function runTurn(params) {
|
|
|
8733
8915
|
(n, e) => n + (e.attachments?.length ?? 0),
|
|
8734
8916
|
0
|
|
8735
8917
|
);
|
|
8736
|
-
|
|
8918
|
+
log14.info("Turn started", {
|
|
8737
8919
|
requestId,
|
|
8738
8920
|
model,
|
|
8739
8921
|
buildModel: buildModelOverride,
|
|
@@ -8782,7 +8964,7 @@ async function runTurn(params) {
|
|
|
8782
8964
|
}
|
|
8783
8965
|
const isFirstMessage = state.messages.filter((m) => m.role === "user").length === 1;
|
|
8784
8966
|
const STATUS_EXCLUDED_TOOLS = /* @__PURE__ */ new Set([
|
|
8785
|
-
"
|
|
8967
|
+
"markBuildComplete",
|
|
8786
8968
|
"setProjectMetadata",
|
|
8787
8969
|
"editsFinished"
|
|
8788
8970
|
]);
|
|
@@ -9028,7 +9210,7 @@ async function runTurn(params) {
|
|
|
9028
9210
|
const acc = toolInputAccumulators.get(event.id);
|
|
9029
9211
|
const wasStreamed = acc?.started ?? false;
|
|
9030
9212
|
const isInputStreaming = !!tool?.streaming?.partialInput;
|
|
9031
|
-
|
|
9213
|
+
log14.info("Tool received", {
|
|
9032
9214
|
requestId,
|
|
9033
9215
|
toolCallId: event.id,
|
|
9034
9216
|
name: event.name
|
|
@@ -9147,7 +9329,7 @@ async function runTurn(params) {
|
|
|
9147
9329
|
const toolCalls = getToolCalls(contentBlocks);
|
|
9148
9330
|
if (toolCalls.length === 0 && (stopReason === "repetition" || stopReason === "max_tokens") && abnormalStopRecoveries < MAX_ABNORMAL_STOP_RECOVERIES && !signal?.aborted) {
|
|
9149
9331
|
abnormalStopRecoveries++;
|
|
9150
|
-
|
|
9332
|
+
log14.warn("Abnormal stop \u2014 nudging model to continue", {
|
|
9151
9333
|
requestId,
|
|
9152
9334
|
stopReason,
|
|
9153
9335
|
attempt: abnormalStopRecoveries
|
|
@@ -9175,7 +9357,7 @@ async function runTurn(params) {
|
|
|
9175
9357
|
});
|
|
9176
9358
|
return;
|
|
9177
9359
|
}
|
|
9178
|
-
|
|
9360
|
+
log14.info("Tools executing", {
|
|
9179
9361
|
requestId,
|
|
9180
9362
|
count: toolCalls.length,
|
|
9181
9363
|
tools: toolCalls.map((tc) => tc.name)
|
|
@@ -9222,7 +9404,7 @@ async function runTurn(params) {
|
|
|
9222
9404
|
let result;
|
|
9223
9405
|
if (EXTERNAL_TOOLS.has(tc.name) && resolveExternalTool) {
|
|
9224
9406
|
saveSession(state);
|
|
9225
|
-
|
|
9407
|
+
log14.info("Waiting for external tool result", {
|
|
9226
9408
|
requestId,
|
|
9227
9409
|
toolCallId: tc.id,
|
|
9228
9410
|
name: tc.name
|
|
@@ -9290,7 +9472,7 @@ async function runTurn(params) {
|
|
|
9290
9472
|
if (!isBackgroundCall(tc)) {
|
|
9291
9473
|
toolRegistry?.unregister(tc.id);
|
|
9292
9474
|
}
|
|
9293
|
-
|
|
9475
|
+
log14.info("Tool completed", {
|
|
9294
9476
|
requestId,
|
|
9295
9477
|
toolCallId: tc.id,
|
|
9296
9478
|
name: tc.name,
|
|
@@ -9364,7 +9546,7 @@ async function runTurn(params) {
|
|
|
9364
9546
|
statusWatcher.stop();
|
|
9365
9547
|
}
|
|
9366
9548
|
}
|
|
9367
|
-
var
|
|
9549
|
+
var log14, BRAND_TRIGGERING_TOOLS, EXTERNAL_TOOLS, USER_BLOCKING_EXTERNAL_TOOLS;
|
|
9368
9550
|
var init_agent = __esm({
|
|
9369
9551
|
"src/agent.ts"() {
|
|
9370
9552
|
"use strict";
|
|
@@ -9383,7 +9565,7 @@ var init_agent = __esm({
|
|
|
9383
9565
|
init_surfaces();
|
|
9384
9566
|
init_toolRegistry();
|
|
9385
9567
|
init_historyLimits();
|
|
9386
|
-
|
|
9568
|
+
log14 = createLogger("agent");
|
|
9387
9569
|
BRAND_TRIGGERING_TOOLS = /* @__PURE__ */ new Set([
|
|
9388
9570
|
"writeSpec",
|
|
9389
9571
|
"editSpec",
|
|
@@ -9391,11 +9573,12 @@ var init_agent = __esm({
|
|
|
9391
9573
|
]);
|
|
9392
9574
|
EXTERNAL_TOOLS = /* @__PURE__ */ new Set([
|
|
9393
9575
|
"promptUser",
|
|
9394
|
-
"
|
|
9576
|
+
"markBuildComplete",
|
|
9395
9577
|
"presentPublishPlan",
|
|
9396
9578
|
"confirmDestructiveAction",
|
|
9397
9579
|
"runScenario",
|
|
9398
9580
|
"runMethod",
|
|
9581
|
+
"testJewel",
|
|
9399
9582
|
"queryDatabase",
|
|
9400
9583
|
"browserCommand",
|
|
9401
9584
|
"setProjectMetadata"
|
|
@@ -9507,6 +9690,10 @@ function buildSystemPrompt(onboardingState) {
|
|
|
9507
9690
|
{{compiled/auth.md}}
|
|
9508
9691
|
</auth>
|
|
9509
9692
|
|
|
9693
|
+
<jewels>
|
|
9694
|
+
{{compiled/jewels.md}}
|
|
9695
|
+
</jewels>
|
|
9696
|
+
|
|
9510
9697
|
<dev_and_deploy>
|
|
9511
9698
|
{{compiled/dev-and-deploy.md}}
|
|
9512
9699
|
</dev_and_deploy>
|
|
@@ -9561,7 +9748,7 @@ New projects progress through four onboarding states. The user might skip this e
|
|
|
9561
9748
|
|
|
9562
9749
|
- **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.
|
|
9563
9750
|
- **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).
|
|
9564
|
-
- **buildComplete**: The build is done.
|
|
9751
|
+
- **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.
|
|
9565
9752
|
- **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.
|
|
9566
9753
|
</project_onboarding>
|
|
9567
9754
|
|
|
@@ -9602,10 +9789,10 @@ import os from "os";
|
|
|
9602
9789
|
function loadConfigFile() {
|
|
9603
9790
|
try {
|
|
9604
9791
|
const raw = fs22.readFileSync(CONFIG_PATH, "utf-8");
|
|
9605
|
-
|
|
9792
|
+
log15.debug("Loaded config file", { path: CONFIG_PATH });
|
|
9606
9793
|
return JSON.parse(raw);
|
|
9607
9794
|
} catch (err) {
|
|
9608
|
-
|
|
9795
|
+
log15.debug("No config file found", {
|
|
9609
9796
|
path: CONFIG_PATH,
|
|
9610
9797
|
error: err.message
|
|
9611
9798
|
});
|
|
@@ -9620,13 +9807,13 @@ function resolveConfig(flags2) {
|
|
|
9620
9807
|
const baseUrl2 = flags2?.baseUrl || process.env.MINDSTUDIO_BASE_URL || env?.apiBaseUrl || DEFAULT_BASE_URL;
|
|
9621
9808
|
const appId = process.env.MINDSTUDIO_APP_ID || void 0;
|
|
9622
9809
|
if (!apiKey) {
|
|
9623
|
-
|
|
9810
|
+
log15.error("No API key found");
|
|
9624
9811
|
throw new Error(
|
|
9625
9812
|
"No API key found. Set MINDSTUDIO_API_KEY or configure ~/.mindstudio-local-tunnel/config.json."
|
|
9626
9813
|
);
|
|
9627
9814
|
}
|
|
9628
9815
|
const keySource = flags2?.apiKey ? "cli flag" : process.env.MINDSTUDIO_API_KEY ? "env var" : "config file";
|
|
9629
|
-
|
|
9816
|
+
log15.info("Config resolved", {
|
|
9630
9817
|
baseUrl: baseUrl2,
|
|
9631
9818
|
keySource,
|
|
9632
9819
|
environment: activeEnv,
|
|
@@ -9634,12 +9821,12 @@ function resolveConfig(flags2) {
|
|
|
9634
9821
|
});
|
|
9635
9822
|
return { apiKey, baseUrl: baseUrl2, appId };
|
|
9636
9823
|
}
|
|
9637
|
-
var
|
|
9824
|
+
var log15, CONFIG_PATH, DEFAULT_BASE_URL;
|
|
9638
9825
|
var init_config = __esm({
|
|
9639
9826
|
"src/config.ts"() {
|
|
9640
9827
|
"use strict";
|
|
9641
9828
|
init_logger();
|
|
9642
|
-
|
|
9829
|
+
log15 = createLogger("config");
|
|
9643
9830
|
CONFIG_PATH = path12.join(
|
|
9644
9831
|
os.homedir(),
|
|
9645
9832
|
".mindstudio-local-tunnel",
|
|
@@ -9651,8 +9838,8 @@ var init_config = __esm({
|
|
|
9651
9838
|
|
|
9652
9839
|
// src/headless/attachments.ts
|
|
9653
9840
|
import { mkdirSync, existsSync } from "fs";
|
|
9654
|
-
import { writeFile as
|
|
9655
|
-
import { basename as basename2, join as
|
|
9841
|
+
import { writeFile as writeFile3 } from "fs/promises";
|
|
9842
|
+
import { basename as basename2, join as join3, extname as extname2 } from "path";
|
|
9656
9843
|
function filenameFromUrl(url) {
|
|
9657
9844
|
try {
|
|
9658
9845
|
const pathname = new URL(url).pathname;
|
|
@@ -9663,7 +9850,7 @@ function filenameFromUrl(url) {
|
|
|
9663
9850
|
}
|
|
9664
9851
|
}
|
|
9665
9852
|
function resolveUniqueFilename(name, claimed) {
|
|
9666
|
-
const isFree = (candidate) => !claimed.has(candidate) && !existsSync(
|
|
9853
|
+
const isFree = (candidate) => !claimed.has(candidate) && !existsSync(join3(UPLOADS_DIR, candidate));
|
|
9667
9854
|
if (isFree(name)) {
|
|
9668
9855
|
return name;
|
|
9669
9856
|
}
|
|
@@ -9697,7 +9884,7 @@ async function persistAttachments(attachments) {
|
|
|
9697
9884
|
const results = await Promise.allSettled(
|
|
9698
9885
|
nonVoice.map(async (att, i) => {
|
|
9699
9886
|
const name = names[i];
|
|
9700
|
-
const localPath =
|
|
9887
|
+
const localPath = join3(UPLOADS_DIR, name);
|
|
9701
9888
|
const res = await fetch(att.url, {
|
|
9702
9889
|
signal: AbortSignal.timeout(3e4)
|
|
9703
9890
|
});
|
|
@@ -9705,8 +9892,8 @@ async function persistAttachments(attachments) {
|
|
|
9705
9892
|
throw new Error(`HTTP ${res.status} downloading ${att.url}`);
|
|
9706
9893
|
}
|
|
9707
9894
|
const buffer = Buffer.from(await res.arrayBuffer());
|
|
9708
|
-
await
|
|
9709
|
-
|
|
9895
|
+
await writeFile3(localPath, buffer);
|
|
9896
|
+
log16.info("Attachment saved", {
|
|
9710
9897
|
filename: name,
|
|
9711
9898
|
path: localPath,
|
|
9712
9899
|
bytes: buffer.length
|
|
@@ -9719,8 +9906,8 @@ async function persistAttachments(attachments) {
|
|
|
9719
9906
|
});
|
|
9720
9907
|
if (textRes.ok) {
|
|
9721
9908
|
extractedTextPath = `${localPath}.txt`;
|
|
9722
|
-
await
|
|
9723
|
-
|
|
9909
|
+
await writeFile3(extractedTextPath, await textRes.text(), "utf-8");
|
|
9910
|
+
log16.info("Extracted text saved", { path: extractedTextPath });
|
|
9724
9911
|
}
|
|
9725
9912
|
} catch {
|
|
9726
9913
|
}
|
|
@@ -9764,12 +9951,12 @@ function buildUploadHeader(documents, images) {
|
|
|
9764
9951
|
return `[Uploaded files]
|
|
9765
9952
|
${lines.join("\n")}`;
|
|
9766
9953
|
}
|
|
9767
|
-
var
|
|
9954
|
+
var log16, UPLOADS_DIR, IMAGE_EXTENSIONS;
|
|
9768
9955
|
var init_attachments = __esm({
|
|
9769
9956
|
"src/headless/attachments.ts"() {
|
|
9770
9957
|
"use strict";
|
|
9771
9958
|
init_logger();
|
|
9772
|
-
|
|
9959
|
+
log16 = createLogger("headless:attachments");
|
|
9773
9960
|
UPLOADS_DIR = "src/.user-uploads";
|
|
9774
9961
|
IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp"]);
|
|
9775
9962
|
}
|
|
@@ -9961,7 +10148,7 @@ var headless_exports = {};
|
|
|
9961
10148
|
__export(headless_exports, {
|
|
9962
10149
|
HeadlessSession: () => HeadlessSession
|
|
9963
10150
|
});
|
|
9964
|
-
var
|
|
10151
|
+
var log17, EXTERNAL_TOOL_TIMEOUT_MS, LONG_RUNNING_TOOLS, LONG_RUNNING_TOOL_TIMEOUT_MS, USER_FACING_TOOLS, FORCED_COMPACTION_THRESHOLD_TOKENS, HeadlessSession;
|
|
9965
10152
|
var init_headless = __esm({
|
|
9966
10153
|
"src/headless/index.ts"() {
|
|
9967
10154
|
"use strict";
|
|
@@ -9983,8 +10170,10 @@ var init_headless = __esm({
|
|
|
9983
10170
|
init_messageQueue();
|
|
9984
10171
|
init_resolve();
|
|
9985
10172
|
init_sentinel();
|
|
9986
|
-
|
|
10173
|
+
log17 = createLogger("headless");
|
|
9987
10174
|
EXTERNAL_TOOL_TIMEOUT_MS = 3e5;
|
|
10175
|
+
LONG_RUNNING_TOOLS = /* @__PURE__ */ new Set(["runMethod", "testJewel"]);
|
|
10176
|
+
LONG_RUNNING_TOOL_TIMEOUT_MS = 18e5;
|
|
9988
10177
|
USER_FACING_TOOLS = /* @__PURE__ */ new Set([
|
|
9989
10178
|
"promptUser",
|
|
9990
10179
|
"confirmDestructiveAction",
|
|
@@ -10206,7 +10395,7 @@ var init_headless = __esm({
|
|
|
10206
10395
|
}
|
|
10207
10396
|
const line = JSON.stringify(payload) + "\n";
|
|
10208
10397
|
if (event === "history") {
|
|
10209
|
-
|
|
10398
|
+
log17.info("Wrote history event to stdout", {
|
|
10210
10399
|
requestId,
|
|
10211
10400
|
bytes: line.length
|
|
10212
10401
|
});
|
|
@@ -10292,7 +10481,7 @@ var init_headless = __esm({
|
|
|
10292
10481
|
if (this.sessionStats.lastContextSize <= FORCED_COMPACTION_THRESHOLD_TOKENS) {
|
|
10293
10482
|
return;
|
|
10294
10483
|
}
|
|
10295
|
-
|
|
10484
|
+
log17.info("Forced compaction gate triggered", {
|
|
10296
10485
|
contextSize: this.sessionStats.lastContextSize,
|
|
10297
10486
|
threshold: FORCED_COMPACTION_THRESHOLD_TOKENS,
|
|
10298
10487
|
requestId
|
|
@@ -10311,7 +10500,7 @@ var init_headless = __esm({
|
|
|
10311
10500
|
onBackgroundComplete = (toolCallId, name, result, subAgentMessages) => {
|
|
10312
10501
|
const notify = getToolByName(name)?.backgroundNotify ?? "wake";
|
|
10313
10502
|
this.pendingBlockUpdates.push({ toolCallId, result, subAgentMessages });
|
|
10314
|
-
|
|
10503
|
+
log17.info("Background complete", {
|
|
10315
10504
|
toolCallId,
|
|
10316
10505
|
name,
|
|
10317
10506
|
notify,
|
|
@@ -10363,13 +10552,14 @@ var init_headless = __esm({
|
|
|
10363
10552
|
return Promise.resolve(early);
|
|
10364
10553
|
}
|
|
10365
10554
|
const shouldTimeout = !USER_FACING_TOOLS.has(name);
|
|
10555
|
+
const timeoutMs = LONG_RUNNING_TOOLS.has(name) ? LONG_RUNNING_TOOL_TIMEOUT_MS : EXTERNAL_TOOL_TIMEOUT_MS;
|
|
10366
10556
|
return new Promise((resolve4) => {
|
|
10367
10557
|
const timeout = shouldTimeout ? setTimeout(() => {
|
|
10368
10558
|
this.pendingTools.delete(id);
|
|
10369
10559
|
resolve4(
|
|
10370
|
-
|
|
10560
|
+
`Error: Tool timed out \u2014 no response from the app environment after ${Math.round(timeoutMs / 6e4)} minutes.`
|
|
10371
10561
|
);
|
|
10372
|
-
},
|
|
10562
|
+
}, timeoutMs) : void 0;
|
|
10373
10563
|
this.pendingTools.set(id, {
|
|
10374
10564
|
resolve: (result) => {
|
|
10375
10565
|
clearTimeout(timeout);
|
|
@@ -10573,7 +10763,7 @@ var init_headless = __esm({
|
|
|
10573
10763
|
const { documents, images } = await persistAttachments(attachments);
|
|
10574
10764
|
return buildUploadHeader(documents, images) || void 0;
|
|
10575
10765
|
} catch (err) {
|
|
10576
|
-
|
|
10766
|
+
log17.warn("Attachment persistence failed", { error: err.message });
|
|
10577
10767
|
return void 0;
|
|
10578
10768
|
}
|
|
10579
10769
|
}
|
|
@@ -10587,7 +10777,7 @@ var init_headless = __esm({
|
|
|
10587
10777
|
async runSingleTurn(parsed, requestId, fromChain = false, queued = false) {
|
|
10588
10778
|
const attachments = parsed.attachments;
|
|
10589
10779
|
if (attachments?.length) {
|
|
10590
|
-
|
|
10780
|
+
log17.info("Message has attachments", {
|
|
10591
10781
|
count: attachments.length,
|
|
10592
10782
|
urls: attachments.map((a) => a.url)
|
|
10593
10783
|
});
|
|
@@ -10775,7 +10965,7 @@ var init_headless = __esm({
|
|
|
10775
10965
|
error: "Turn ended unexpectedly"
|
|
10776
10966
|
});
|
|
10777
10967
|
}
|
|
10778
|
-
|
|
10968
|
+
log17.info("Turn complete", {
|
|
10779
10969
|
requestId,
|
|
10780
10970
|
durationMs: Date.now() - this.turnStart
|
|
10781
10971
|
});
|
|
@@ -10787,7 +10977,7 @@ var init_headless = __esm({
|
|
|
10787
10977
|
error: err.message
|
|
10788
10978
|
});
|
|
10789
10979
|
}
|
|
10790
|
-
|
|
10980
|
+
log17.warn("Command failed", {
|
|
10791
10981
|
action: "message",
|
|
10792
10982
|
requestId,
|
|
10793
10983
|
error: err.message
|
|
@@ -10997,7 +11187,7 @@ var init_headless = __esm({
|
|
|
10997
11187
|
try {
|
|
10998
11188
|
parsed = JSON.parse(line);
|
|
10999
11189
|
} catch (err) {
|
|
11000
|
-
|
|
11190
|
+
log17.warn("Invalid JSON on stdin", {
|
|
11001
11191
|
error: err.message,
|
|
11002
11192
|
lineLength: line.length,
|
|
11003
11193
|
preview: line.slice(0, 200)
|
|
@@ -11006,7 +11196,7 @@ var init_headless = __esm({
|
|
|
11006
11196
|
return;
|
|
11007
11197
|
}
|
|
11008
11198
|
const { action, requestId } = parsed;
|
|
11009
|
-
|
|
11199
|
+
log17.info("Command received", { action, requestId });
|
|
11010
11200
|
if (action === "tool_result" && parsed.id) {
|
|
11011
11201
|
const id = parsed.id;
|
|
11012
11202
|
const result = parsed.result ?? "";
|
|
@@ -11015,7 +11205,7 @@ var init_headless = __esm({
|
|
|
11015
11205
|
this.pendingTools.delete(id);
|
|
11016
11206
|
pending2.resolve(result);
|
|
11017
11207
|
} else if (!this.running) {
|
|
11018
|
-
|
|
11208
|
+
log17.info("Late tool_result while idle, dismissing", { id });
|
|
11019
11209
|
this.emit("completed", { success: true }, requestId);
|
|
11020
11210
|
} else {
|
|
11021
11211
|
this.earlyResults.set(id, result);
|
|
@@ -11028,7 +11218,7 @@ var init_headless = __esm({
|
|
|
11028
11218
|
...typeof parsed.before === "number" ? { before: parsed.before } : {},
|
|
11029
11219
|
...typeof parsed.limit === "number" ? { limit: parsed.limit } : {}
|
|
11030
11220
|
});
|
|
11031
|
-
|
|
11221
|
+
log17.info("History response", {
|
|
11032
11222
|
requestId,
|
|
11033
11223
|
startIndex: page.startIndex,
|
|
11034
11224
|
endIndex: page.endIndex,
|