@mindstudio-ai/remy 0.1.157 → 0.1.159
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/automatedActions/buildFromInitialSpec.md +2 -2
- package/dist/brandExtraction/extract.md +51 -0
- package/dist/headless.js +324 -43
- package/dist/index.js +353 -53
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2962,11 +2962,11 @@ async function captureAndAnalyzeScreenshot(promptOrOptions) {
|
|
|
2962
2962
|
let prompt;
|
|
2963
2963
|
let existingUrl;
|
|
2964
2964
|
let onLog;
|
|
2965
|
-
let
|
|
2965
|
+
let path12;
|
|
2966
2966
|
if (typeof promptOrOptions === "object" && promptOrOptions !== null) {
|
|
2967
2967
|
prompt = promptOrOptions.prompt;
|
|
2968
2968
|
existingUrl = promptOrOptions.imageUrl;
|
|
2969
|
-
|
|
2969
|
+
path12 = promptOrOptions.path;
|
|
2970
2970
|
onLog = promptOrOptions.onLog;
|
|
2971
2971
|
} else {
|
|
2972
2972
|
prompt = promptOrOptions;
|
|
@@ -2978,7 +2978,7 @@ async function captureAndAnalyzeScreenshot(promptOrOptions) {
|
|
|
2978
2978
|
} else {
|
|
2979
2979
|
const ssResult = await sidecarRequest(
|
|
2980
2980
|
"/screenshot-full-page",
|
|
2981
|
-
|
|
2981
|
+
path12 ? { path: path12 } : void 0,
|
|
2982
2982
|
{ timeout: 12e4 }
|
|
2983
2983
|
);
|
|
2984
2984
|
url = ssResult?.url || ssResult?.screenshotUrl;
|
|
@@ -3033,15 +3033,15 @@ var init_browserLock = __esm({
|
|
|
3033
3033
|
// src/statusWatcher.ts
|
|
3034
3034
|
function startStatusWatcher(config) {
|
|
3035
3035
|
const { apiConfig, getContext, onStatus, interval = 5e3, signal } = config;
|
|
3036
|
-
let
|
|
3036
|
+
let inflight2 = false;
|
|
3037
3037
|
let stopped = false;
|
|
3038
3038
|
let pauseCount = 0;
|
|
3039
3039
|
const url = `${apiConfig.baseUrl}/_internal/v2/agent/remy/generate-status`;
|
|
3040
3040
|
async function tick() {
|
|
3041
|
-
if (stopped || signal?.aborted ||
|
|
3041
|
+
if (stopped || signal?.aborted || inflight2 || pauseCount > 0) {
|
|
3042
3042
|
return;
|
|
3043
3043
|
}
|
|
3044
|
-
|
|
3044
|
+
inflight2 = true;
|
|
3045
3045
|
try {
|
|
3046
3046
|
const context = getContext();
|
|
3047
3047
|
if (!context) {
|
|
@@ -3069,7 +3069,7 @@ function startStatusWatcher(config) {
|
|
|
3069
3069
|
onStatus(data.label);
|
|
3070
3070
|
} catch {
|
|
3071
3071
|
} finally {
|
|
3072
|
-
|
|
3072
|
+
inflight2 = false;
|
|
3073
3073
|
}
|
|
3074
3074
|
}
|
|
3075
3075
|
const timer = setInterval(tick, interval);
|
|
@@ -4936,15 +4936,15 @@ function getSampleIndices(pools, sizes) {
|
|
|
4936
4936
|
}
|
|
4937
4937
|
const loaded = load();
|
|
4938
4938
|
if (loaded) {
|
|
4939
|
-
let
|
|
4939
|
+
let dirty2 = false;
|
|
4940
4940
|
for (const key of ["uiInspiration", "designReferences", "fonts"]) {
|
|
4941
4941
|
const before = loaded[key].length;
|
|
4942
4942
|
loaded[key] = loaded[key].filter((i) => i < pools[key]);
|
|
4943
4943
|
if (loaded[key].length < before) {
|
|
4944
|
-
|
|
4944
|
+
dirty2 = true;
|
|
4945
4945
|
}
|
|
4946
4946
|
}
|
|
4947
|
-
if (
|
|
4947
|
+
if (dirty2) {
|
|
4948
4948
|
save(loaded);
|
|
4949
4949
|
}
|
|
4950
4950
|
cached = loaded;
|
|
@@ -6061,6 +6061,298 @@ var init_errors = __esm({
|
|
|
6061
6061
|
}
|
|
6062
6062
|
});
|
|
6063
6063
|
|
|
6064
|
+
// src/brandExtraction/index.ts
|
|
6065
|
+
import fs19 from "fs";
|
|
6066
|
+
import path9 from "path";
|
|
6067
|
+
import { createHash } from "crypto";
|
|
6068
|
+
async function runExtraction(apiConfig) {
|
|
6069
|
+
const inputHash = computeInputHash();
|
|
6070
|
+
const cached2 = readCache();
|
|
6071
|
+
if (cached2 && cached2.inputHash === inputHash) {
|
|
6072
|
+
log8.debug("Brand inputs unchanged \u2014 skipping extraction", { inputHash });
|
|
6073
|
+
return null;
|
|
6074
|
+
}
|
|
6075
|
+
log8.info("Extracting brand", { inputHash });
|
|
6076
|
+
const brand = await extractBrand(apiConfig);
|
|
6077
|
+
if (!brand) {
|
|
6078
|
+
log8.warn("Brand extraction failed \u2014 leaving cache untouched");
|
|
6079
|
+
return null;
|
|
6080
|
+
}
|
|
6081
|
+
persistBrand(brand, inputHash);
|
|
6082
|
+
log8.info("Brand persisted", { inputHash });
|
|
6083
|
+
return brand;
|
|
6084
|
+
}
|
|
6085
|
+
function computeInputHash() {
|
|
6086
|
+
const entries = [];
|
|
6087
|
+
for (const filePath of walkMdFiles3("src")) {
|
|
6088
|
+
if (filePath === path9.join("src", "app.md")) {
|
|
6089
|
+
entries.push({ path: filePath, content: readSafe(filePath) });
|
|
6090
|
+
continue;
|
|
6091
|
+
}
|
|
6092
|
+
const fm = parseFrontmatter3(filePath);
|
|
6093
|
+
if (fm.type.startsWith("design/color") || fm.type.startsWith("design/typography")) {
|
|
6094
|
+
entries.push({ path: filePath, content: readSafe(filePath) });
|
|
6095
|
+
}
|
|
6096
|
+
}
|
|
6097
|
+
const manifest = readSafe("mindstudio.json");
|
|
6098
|
+
if (manifest) {
|
|
6099
|
+
entries.push({ path: "mindstudio.json", content: manifest });
|
|
6100
|
+
}
|
|
6101
|
+
entries.sort((a, b) => a.path.localeCompare(b.path));
|
|
6102
|
+
const fingerprint = entries.map((e) => `${e.path}:${sha256(e.content)}`).join("\n");
|
|
6103
|
+
return sha256(fingerprint);
|
|
6104
|
+
}
|
|
6105
|
+
function sha256(input) {
|
|
6106
|
+
return createHash("sha256").update(input).digest("hex");
|
|
6107
|
+
}
|
|
6108
|
+
function readSafe(filePath) {
|
|
6109
|
+
try {
|
|
6110
|
+
return fs19.readFileSync(filePath, "utf-8");
|
|
6111
|
+
} catch {
|
|
6112
|
+
return "";
|
|
6113
|
+
}
|
|
6114
|
+
}
|
|
6115
|
+
function walkMdFiles3(dir) {
|
|
6116
|
+
const results = [];
|
|
6117
|
+
try {
|
|
6118
|
+
const entries = fs19.readdirSync(dir, { withFileTypes: true });
|
|
6119
|
+
for (const entry of entries) {
|
|
6120
|
+
const full = path9.join(dir, entry.name);
|
|
6121
|
+
if (entry.isDirectory()) {
|
|
6122
|
+
results.push(...walkMdFiles3(full));
|
|
6123
|
+
} else if (entry.name.endsWith(".md")) {
|
|
6124
|
+
results.push(full);
|
|
6125
|
+
}
|
|
6126
|
+
}
|
|
6127
|
+
} catch {
|
|
6128
|
+
}
|
|
6129
|
+
return results.sort();
|
|
6130
|
+
}
|
|
6131
|
+
function parseFrontmatter3(filePath) {
|
|
6132
|
+
try {
|
|
6133
|
+
const content = fs19.readFileSync(filePath, "utf-8");
|
|
6134
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
6135
|
+
if (!match) {
|
|
6136
|
+
return { type: "" };
|
|
6137
|
+
}
|
|
6138
|
+
const fm = match[1];
|
|
6139
|
+
const type = fm.match(/^type:\s*(.+)$/m)?.[1]?.trim() ?? "";
|
|
6140
|
+
return { type };
|
|
6141
|
+
} catch {
|
|
6142
|
+
return { type: "" };
|
|
6143
|
+
}
|
|
6144
|
+
}
|
|
6145
|
+
async function extractBrand(apiConfig) {
|
|
6146
|
+
const corpus = buildCorpus();
|
|
6147
|
+
if (!corpus.trim()) {
|
|
6148
|
+
log8.debug("No spec corpus \u2014 emitting empty brand");
|
|
6149
|
+
return { version: 1 };
|
|
6150
|
+
}
|
|
6151
|
+
let responseText = "";
|
|
6152
|
+
try {
|
|
6153
|
+
for await (const event of streamChat({
|
|
6154
|
+
...apiConfig,
|
|
6155
|
+
subAgentId: "brandExtractor",
|
|
6156
|
+
system: EXTRACT_PROMPT,
|
|
6157
|
+
messages: [{ role: "user", content: corpus }],
|
|
6158
|
+
tools: []
|
|
6159
|
+
})) {
|
|
6160
|
+
if (event.type === "text") {
|
|
6161
|
+
responseText += event.text;
|
|
6162
|
+
} else if (event.type === "error") {
|
|
6163
|
+
log8.error("Brand extraction stream error", { error: event.error });
|
|
6164
|
+
return null;
|
|
6165
|
+
}
|
|
6166
|
+
}
|
|
6167
|
+
} catch (err) {
|
|
6168
|
+
log8.error("Brand extraction threw", { error: err?.message });
|
|
6169
|
+
return null;
|
|
6170
|
+
}
|
|
6171
|
+
const parsed = parseJsonResponse(responseText);
|
|
6172
|
+
if (!parsed) {
|
|
6173
|
+
log8.warn("Brand extraction returned unparseable JSON", {
|
|
6174
|
+
preview: responseText.slice(0, 200)
|
|
6175
|
+
});
|
|
6176
|
+
return null;
|
|
6177
|
+
}
|
|
6178
|
+
return validateBrand(parsed);
|
|
6179
|
+
}
|
|
6180
|
+
function buildCorpus() {
|
|
6181
|
+
const sections = [];
|
|
6182
|
+
const manifest = readSafe("mindstudio.json");
|
|
6183
|
+
if (manifest) {
|
|
6184
|
+
sections.push(`## File: mindstudio.json
|
|
6185
|
+
|
|
6186
|
+
${manifest}`);
|
|
6187
|
+
}
|
|
6188
|
+
for (const filePath of walkMdFiles3("src")) {
|
|
6189
|
+
const content = readSafe(filePath);
|
|
6190
|
+
if (content) {
|
|
6191
|
+
sections.push(`## File: ${filePath}
|
|
6192
|
+
|
|
6193
|
+
${content}`);
|
|
6194
|
+
}
|
|
6195
|
+
}
|
|
6196
|
+
return sections.join("\n\n---\n\n");
|
|
6197
|
+
}
|
|
6198
|
+
function parseJsonResponse(text) {
|
|
6199
|
+
const trimmed = text.trim();
|
|
6200
|
+
const fenceMatch = trimmed.match(/^```(?:json)?\s*\n([\s\S]*?)\n```\s*$/);
|
|
6201
|
+
const candidate = fenceMatch ? fenceMatch[1] : trimmed;
|
|
6202
|
+
try {
|
|
6203
|
+
return JSON.parse(candidate);
|
|
6204
|
+
} catch {
|
|
6205
|
+
const braceMatch = candidate.match(/\{[\s\S]*\}/);
|
|
6206
|
+
if (braceMatch) {
|
|
6207
|
+
try {
|
|
6208
|
+
return JSON.parse(braceMatch[0]);
|
|
6209
|
+
} catch {
|
|
6210
|
+
return null;
|
|
6211
|
+
}
|
|
6212
|
+
}
|
|
6213
|
+
return null;
|
|
6214
|
+
}
|
|
6215
|
+
}
|
|
6216
|
+
function validateBrand(raw) {
|
|
6217
|
+
if (!raw || typeof raw !== "object") {
|
|
6218
|
+
return null;
|
|
6219
|
+
}
|
|
6220
|
+
const obj = raw;
|
|
6221
|
+
const out = { version: 1 };
|
|
6222
|
+
if (typeof obj.name === "string" && obj.name.trim()) {
|
|
6223
|
+
out.name = obj.name.trim();
|
|
6224
|
+
}
|
|
6225
|
+
if (typeof obj.tagline === "string" && obj.tagline.trim()) {
|
|
6226
|
+
out.tagline = obj.tagline.trim();
|
|
6227
|
+
}
|
|
6228
|
+
if (typeof obj.logoUrl === "string" && obj.logoUrl.trim()) {
|
|
6229
|
+
out.logoUrl = obj.logoUrl.trim();
|
|
6230
|
+
}
|
|
6231
|
+
const colors = pickColors(obj.colors);
|
|
6232
|
+
if (colors) {
|
|
6233
|
+
out.colors = colors;
|
|
6234
|
+
}
|
|
6235
|
+
const typography = pickTypography(obj.typography);
|
|
6236
|
+
if (typography) {
|
|
6237
|
+
out.typography = typography;
|
|
6238
|
+
}
|
|
6239
|
+
return out;
|
|
6240
|
+
}
|
|
6241
|
+
function pickColors(raw) {
|
|
6242
|
+
if (!raw || typeof raw !== "object") {
|
|
6243
|
+
return void 0;
|
|
6244
|
+
}
|
|
6245
|
+
const c = raw;
|
|
6246
|
+
const out = {};
|
|
6247
|
+
for (const key of [
|
|
6248
|
+
"background",
|
|
6249
|
+
"text",
|
|
6250
|
+
"heading",
|
|
6251
|
+
"accent",
|
|
6252
|
+
"muted"
|
|
6253
|
+
]) {
|
|
6254
|
+
const v = c[key];
|
|
6255
|
+
if (typeof v === "string" && v.trim()) {
|
|
6256
|
+
out[key] = v.trim();
|
|
6257
|
+
}
|
|
6258
|
+
}
|
|
6259
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
6260
|
+
}
|
|
6261
|
+
function pickTypography(raw) {
|
|
6262
|
+
if (!raw || typeof raw !== "object") {
|
|
6263
|
+
return void 0;
|
|
6264
|
+
}
|
|
6265
|
+
const t = raw;
|
|
6266
|
+
const out = {};
|
|
6267
|
+
const body = pickFont(t.body);
|
|
6268
|
+
if (body) {
|
|
6269
|
+
out.body = body;
|
|
6270
|
+
}
|
|
6271
|
+
const heading = pickFont(t.heading);
|
|
6272
|
+
if (heading) {
|
|
6273
|
+
out.heading = heading;
|
|
6274
|
+
}
|
|
6275
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
6276
|
+
}
|
|
6277
|
+
function pickFont(raw) {
|
|
6278
|
+
if (!raw || typeof raw !== "object") {
|
|
6279
|
+
return void 0;
|
|
6280
|
+
}
|
|
6281
|
+
const f = raw;
|
|
6282
|
+
if (typeof f.family !== "string" || !f.family.trim()) {
|
|
6283
|
+
return void 0;
|
|
6284
|
+
}
|
|
6285
|
+
const out = { family: f.family.trim() };
|
|
6286
|
+
if (typeof f.stylesheet === "string" && f.stylesheet.trim()) {
|
|
6287
|
+
out.stylesheet = f.stylesheet.trim();
|
|
6288
|
+
}
|
|
6289
|
+
if (typeof f.fileUrl === "string" && f.fileUrl.trim()) {
|
|
6290
|
+
out.fileUrl = f.fileUrl.trim();
|
|
6291
|
+
}
|
|
6292
|
+
return out;
|
|
6293
|
+
}
|
|
6294
|
+
function persistBrand(brand, inputHash) {
|
|
6295
|
+
const tmp = `${BRAND_FILE}.tmp`;
|
|
6296
|
+
fs19.writeFileSync(tmp, JSON.stringify(brand, null, 2), "utf-8");
|
|
6297
|
+
fs19.renameSync(tmp, BRAND_FILE);
|
|
6298
|
+
const cache = { inputHash, generatedAt: Date.now() };
|
|
6299
|
+
fs19.writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2), "utf-8");
|
|
6300
|
+
}
|
|
6301
|
+
function readCache() {
|
|
6302
|
+
try {
|
|
6303
|
+
const raw = fs19.readFileSync(CACHE_FILE, "utf-8");
|
|
6304
|
+
const parsed = JSON.parse(raw);
|
|
6305
|
+
if (parsed && typeof parsed.inputHash === "string" && typeof parsed.generatedAt === "number") {
|
|
6306
|
+
return parsed;
|
|
6307
|
+
}
|
|
6308
|
+
return null;
|
|
6309
|
+
} catch {
|
|
6310
|
+
return null;
|
|
6311
|
+
}
|
|
6312
|
+
}
|
|
6313
|
+
var log8, EXTRACT_PROMPT, BRAND_FILE, CACHE_FILE;
|
|
6314
|
+
var init_brandExtraction = __esm({
|
|
6315
|
+
"src/brandExtraction/index.ts"() {
|
|
6316
|
+
"use strict";
|
|
6317
|
+
init_api();
|
|
6318
|
+
init_assets();
|
|
6319
|
+
init_logger();
|
|
6320
|
+
log8 = createLogger("brandExtraction");
|
|
6321
|
+
EXTRACT_PROMPT = readAsset("brandExtraction", "extract.md");
|
|
6322
|
+
BRAND_FILE = ".remy-brand.json";
|
|
6323
|
+
CACHE_FILE = ".remy-brand.cache.json";
|
|
6324
|
+
}
|
|
6325
|
+
});
|
|
6326
|
+
|
|
6327
|
+
// src/brandExtraction/trigger.ts
|
|
6328
|
+
function triggerBrandExtraction(apiConfig) {
|
|
6329
|
+
if (inflight) {
|
|
6330
|
+
dirty = true;
|
|
6331
|
+
return;
|
|
6332
|
+
}
|
|
6333
|
+
inflight = true;
|
|
6334
|
+
void runExtraction(apiConfig).catch((err) => {
|
|
6335
|
+
log9.error("Brand extraction failed", { error: err?.message });
|
|
6336
|
+
}).finally(() => {
|
|
6337
|
+
inflight = false;
|
|
6338
|
+
if (dirty) {
|
|
6339
|
+
dirty = false;
|
|
6340
|
+
triggerBrandExtraction(apiConfig);
|
|
6341
|
+
}
|
|
6342
|
+
});
|
|
6343
|
+
}
|
|
6344
|
+
var log9, inflight, dirty;
|
|
6345
|
+
var init_trigger2 = __esm({
|
|
6346
|
+
"src/brandExtraction/trigger.ts"() {
|
|
6347
|
+
"use strict";
|
|
6348
|
+
init_brandExtraction();
|
|
6349
|
+
init_logger();
|
|
6350
|
+
log9 = createLogger("brandExtraction:trigger");
|
|
6351
|
+
inflight = false;
|
|
6352
|
+
dirty = false;
|
|
6353
|
+
}
|
|
6354
|
+
});
|
|
6355
|
+
|
|
6064
6356
|
// src/agent.ts
|
|
6065
6357
|
function getTextContent(blocks) {
|
|
6066
6358
|
return blocks.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
@@ -6092,7 +6384,7 @@ async function runTurn(params) {
|
|
|
6092
6384
|
} = params;
|
|
6093
6385
|
const tools2 = getToolDefinitions(onboardingState);
|
|
6094
6386
|
const excludeToolsFromClearing = tools2.filter((t) => !CLEARABLE_TOOLS.has(t.name)).map((t) => t.name);
|
|
6095
|
-
|
|
6387
|
+
log10.info("Turn started", {
|
|
6096
6388
|
requestId,
|
|
6097
6389
|
model,
|
|
6098
6390
|
toolCount: tools2.length,
|
|
@@ -6153,7 +6445,8 @@ async function runTurn(params) {
|
|
|
6153
6445
|
return;
|
|
6154
6446
|
}
|
|
6155
6447
|
const contentBlocks = [];
|
|
6156
|
-
|
|
6448
|
+
const thinkingBlockStartTimes = [];
|
|
6449
|
+
let thinkingCompleteCount = 0;
|
|
6157
6450
|
const toolInputAccumulators = /* @__PURE__ */ new Map();
|
|
6158
6451
|
let stopReason = "end_turn";
|
|
6159
6452
|
let subAgentText = "";
|
|
@@ -6277,8 +6570,8 @@ async function runTurn(params) {
|
|
|
6277
6570
|
break;
|
|
6278
6571
|
}
|
|
6279
6572
|
case "thinking":
|
|
6280
|
-
if (
|
|
6281
|
-
|
|
6573
|
+
if (event.text === "") {
|
|
6574
|
+
thinkingBlockStartTimes.push(event.ts);
|
|
6282
6575
|
}
|
|
6283
6576
|
onEvent({ type: "thinking", text: event.text });
|
|
6284
6577
|
break;
|
|
@@ -6287,10 +6580,10 @@ async function runTurn(params) {
|
|
|
6287
6580
|
type: "thinking",
|
|
6288
6581
|
thinking: event.thinking,
|
|
6289
6582
|
signature: event.signature,
|
|
6290
|
-
startedAt:
|
|
6583
|
+
startedAt: thinkingBlockStartTimes[thinkingCompleteCount] ?? event.ts,
|
|
6291
6584
|
completedAt: event.ts
|
|
6292
6585
|
});
|
|
6293
|
-
|
|
6586
|
+
thinkingCompleteCount++;
|
|
6294
6587
|
break;
|
|
6295
6588
|
case "tool_input_delta": {
|
|
6296
6589
|
const acc = getOrCreateAccumulator2(event.id, event.name);
|
|
@@ -6320,7 +6613,7 @@ async function runTurn(params) {
|
|
|
6320
6613
|
const tool = getToolByName(event.name);
|
|
6321
6614
|
const wasStreamed = acc?.started ?? false;
|
|
6322
6615
|
const isInputStreaming = !!tool?.streaming?.partialInput;
|
|
6323
|
-
|
|
6616
|
+
log10.info("Tool received", {
|
|
6324
6617
|
requestId,
|
|
6325
6618
|
toolCallId: event.id,
|
|
6326
6619
|
name: event.name
|
|
@@ -6413,7 +6706,7 @@ async function runTurn(params) {
|
|
|
6413
6706
|
});
|
|
6414
6707
|
return;
|
|
6415
6708
|
}
|
|
6416
|
-
|
|
6709
|
+
log10.info("Tools executing", {
|
|
6417
6710
|
requestId,
|
|
6418
6711
|
count: toolCalls.length,
|
|
6419
6712
|
tools: toolCalls.map((tc) => tc.name)
|
|
@@ -6460,7 +6753,7 @@ async function runTurn(params) {
|
|
|
6460
6753
|
let result;
|
|
6461
6754
|
if (EXTERNAL_TOOLS.has(tc.name) && resolveExternalTool) {
|
|
6462
6755
|
saveSession(state);
|
|
6463
|
-
|
|
6756
|
+
log10.info("Waiting for external tool result", {
|
|
6464
6757
|
requestId,
|
|
6465
6758
|
toolCallId: tc.id,
|
|
6466
6759
|
name: tc.name
|
|
@@ -6527,7 +6820,7 @@ async function runTurn(params) {
|
|
|
6527
6820
|
if (!tc.input.background) {
|
|
6528
6821
|
toolRegistry?.unregister(tc.id);
|
|
6529
6822
|
}
|
|
6530
|
-
|
|
6823
|
+
log10.info("Tool completed", {
|
|
6531
6824
|
requestId,
|
|
6532
6825
|
toolCallId: tc.id,
|
|
6533
6826
|
name: tc.name,
|
|
@@ -6541,6 +6834,9 @@ async function runTurn(params) {
|
|
|
6541
6834
|
result: r.result,
|
|
6542
6835
|
isError: r.isError
|
|
6543
6836
|
});
|
|
6837
|
+
if (!r.isError && BRAND_TRIGGERING_TOOLS.has(tc.name)) {
|
|
6838
|
+
triggerBrandExtraction(apiConfig);
|
|
6839
|
+
}
|
|
6544
6840
|
return r;
|
|
6545
6841
|
})
|
|
6546
6842
|
);
|
|
@@ -6580,7 +6876,7 @@ async function runTurn(params) {
|
|
|
6580
6876
|
}
|
|
6581
6877
|
}
|
|
6582
6878
|
}
|
|
6583
|
-
var
|
|
6879
|
+
var log10, BRAND_TRIGGERING_TOOLS, EXTERNAL_TOOLS, USER_BLOCKING_EXTERNAL_TOOLS;
|
|
6584
6880
|
var init_agent = __esm({
|
|
6585
6881
|
"src/agent.ts"() {
|
|
6586
6882
|
"use strict";
|
|
@@ -6594,7 +6890,9 @@ var init_agent = __esm({
|
|
|
6594
6890
|
init_cleanMessages();
|
|
6595
6891
|
init_tools6();
|
|
6596
6892
|
init_sentinel();
|
|
6597
|
-
|
|
6893
|
+
init_trigger2();
|
|
6894
|
+
log10 = createLogger("agent");
|
|
6895
|
+
BRAND_TRIGGERING_TOOLS = /* @__PURE__ */ new Set(["writeSpec", "editSpec"]);
|
|
6598
6896
|
EXTERNAL_TOOLS = /* @__PURE__ */ new Set([
|
|
6599
6897
|
"promptUser",
|
|
6600
6898
|
"setProjectOnboardingState",
|
|
@@ -6615,16 +6913,16 @@ var init_agent = __esm({
|
|
|
6615
6913
|
});
|
|
6616
6914
|
|
|
6617
6915
|
// src/config.ts
|
|
6618
|
-
import
|
|
6619
|
-
import
|
|
6916
|
+
import fs20 from "fs";
|
|
6917
|
+
import path10 from "path";
|
|
6620
6918
|
import os from "os";
|
|
6621
6919
|
function loadConfigFile() {
|
|
6622
6920
|
try {
|
|
6623
|
-
const raw =
|
|
6624
|
-
|
|
6921
|
+
const raw = fs20.readFileSync(CONFIG_PATH, "utf-8");
|
|
6922
|
+
log11.debug("Loaded config file", { path: CONFIG_PATH });
|
|
6625
6923
|
return JSON.parse(raw);
|
|
6626
6924
|
} catch (err) {
|
|
6627
|
-
|
|
6925
|
+
log11.debug("No config file found", {
|
|
6628
6926
|
path: CONFIG_PATH,
|
|
6629
6927
|
error: err.message
|
|
6630
6928
|
});
|
|
@@ -6638,26 +6936,26 @@ function resolveConfig(flags2) {
|
|
|
6638
6936
|
const apiKey = flags2?.apiKey || process.env.MINDSTUDIO_API_KEY || env?.apiKey || "";
|
|
6639
6937
|
const baseUrl2 = flags2?.baseUrl || process.env.MINDSTUDIO_BASE_URL || env?.apiBaseUrl || DEFAULT_BASE_URL;
|
|
6640
6938
|
if (!apiKey) {
|
|
6641
|
-
|
|
6939
|
+
log11.error("No API key found");
|
|
6642
6940
|
throw new Error(
|
|
6643
6941
|
"No API key found. Set MINDSTUDIO_API_KEY or configure ~/.mindstudio-local-tunnel/config.json."
|
|
6644
6942
|
);
|
|
6645
6943
|
}
|
|
6646
6944
|
const keySource = flags2?.apiKey ? "cli flag" : process.env.MINDSTUDIO_API_KEY ? "env var" : "config file";
|
|
6647
|
-
|
|
6945
|
+
log11.info("Config resolved", {
|
|
6648
6946
|
baseUrl: baseUrl2,
|
|
6649
6947
|
keySource,
|
|
6650
6948
|
environment: activeEnv
|
|
6651
6949
|
});
|
|
6652
6950
|
return { apiKey, baseUrl: baseUrl2 };
|
|
6653
6951
|
}
|
|
6654
|
-
var
|
|
6952
|
+
var log11, CONFIG_PATH, DEFAULT_BASE_URL;
|
|
6655
6953
|
var init_config = __esm({
|
|
6656
6954
|
"src/config.ts"() {
|
|
6657
6955
|
"use strict";
|
|
6658
6956
|
init_logger();
|
|
6659
|
-
|
|
6660
|
-
CONFIG_PATH =
|
|
6957
|
+
log11 = createLogger("config");
|
|
6958
|
+
CONFIG_PATH = path10.join(
|
|
6661
6959
|
os.homedir(),
|
|
6662
6960
|
".mindstudio-local-tunnel",
|
|
6663
6961
|
"config.json"
|
|
@@ -6667,12 +6965,12 @@ var init_config = __esm({
|
|
|
6667
6965
|
});
|
|
6668
6966
|
|
|
6669
6967
|
// src/toolRegistry.ts
|
|
6670
|
-
var
|
|
6968
|
+
var log12, ToolRegistry;
|
|
6671
6969
|
var init_toolRegistry = __esm({
|
|
6672
6970
|
"src/toolRegistry.ts"() {
|
|
6673
6971
|
"use strict";
|
|
6674
6972
|
init_logger();
|
|
6675
|
-
|
|
6973
|
+
log12 = createLogger("tool-registry");
|
|
6676
6974
|
ToolRegistry = class {
|
|
6677
6975
|
entries = /* @__PURE__ */ new Map();
|
|
6678
6976
|
onEvent;
|
|
@@ -6698,7 +6996,7 @@ var init_toolRegistry = __esm({
|
|
|
6698
6996
|
if (!entry) {
|
|
6699
6997
|
return false;
|
|
6700
6998
|
}
|
|
6701
|
-
|
|
6999
|
+
log12.info("Tool stopped", { toolCallId: id, name: entry.name, mode });
|
|
6702
7000
|
entry.abortController.abort(mode);
|
|
6703
7001
|
if (mode === "graceful") {
|
|
6704
7002
|
const partial = entry.getPartialResult?.() ?? "";
|
|
@@ -6731,7 +7029,7 @@ ${partial}` : "[INTERRUPTED] Tool execution was stopped.";
|
|
|
6731
7029
|
if (!entry) {
|
|
6732
7030
|
return false;
|
|
6733
7031
|
}
|
|
6734
|
-
|
|
7032
|
+
log12.info("Tool restarted", { toolCallId: id, name: entry.name });
|
|
6735
7033
|
entry.abortController.abort("restart");
|
|
6736
7034
|
const newInput = patchedInput ? { ...entry.input, ...patchedInput } : entry.input;
|
|
6737
7035
|
this.onEvent?.({
|
|
@@ -6797,7 +7095,7 @@ async function persistAttachments(attachments) {
|
|
|
6797
7095
|
}
|
|
6798
7096
|
const buffer = Buffer.from(await res.arrayBuffer());
|
|
6799
7097
|
await writeFile(localPath, buffer);
|
|
6800
|
-
|
|
7098
|
+
log13.info("Attachment saved", {
|
|
6801
7099
|
filename: name,
|
|
6802
7100
|
path: localPath,
|
|
6803
7101
|
bytes: buffer.length
|
|
@@ -6811,7 +7109,7 @@ async function persistAttachments(attachments) {
|
|
|
6811
7109
|
if (textRes.ok) {
|
|
6812
7110
|
extractedTextPath = `${localPath}.txt`;
|
|
6813
7111
|
await writeFile(extractedTextPath, await textRes.text(), "utf-8");
|
|
6814
|
-
|
|
7112
|
+
log13.info("Extracted text saved", { path: extractedTextPath });
|
|
6815
7113
|
}
|
|
6816
7114
|
} catch {
|
|
6817
7115
|
}
|
|
@@ -6856,12 +7154,12 @@ function buildUploadHeader(results) {
|
|
|
6856
7154
|
return `[Uploaded files]
|
|
6857
7155
|
${lines.join("\n")}`;
|
|
6858
7156
|
}
|
|
6859
|
-
var
|
|
7157
|
+
var log13, UPLOADS_DIR, IMAGE_EXTENSIONS;
|
|
6860
7158
|
var init_attachments = __esm({
|
|
6861
7159
|
"src/headless/attachments.ts"() {
|
|
6862
7160
|
"use strict";
|
|
6863
7161
|
init_logger();
|
|
6864
|
-
|
|
7162
|
+
log13 = createLogger("headless:attachments");
|
|
6865
7163
|
UPLOADS_DIR = "src/.user-uploads";
|
|
6866
7164
|
IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp"]);
|
|
6867
7165
|
}
|
|
@@ -7040,7 +7338,7 @@ __export(headless_exports, {
|
|
|
7040
7338
|
HeadlessSession: () => HeadlessSession
|
|
7041
7339
|
});
|
|
7042
7340
|
import { createInterface } from "readline";
|
|
7043
|
-
var
|
|
7341
|
+
var log14, EXTERNAL_TOOL_TIMEOUT_MS, USER_FACING_TOOLS, HeadlessSession;
|
|
7044
7342
|
var init_headless = __esm({
|
|
7045
7343
|
"src/headless/index.ts"() {
|
|
7046
7344
|
"use strict";
|
|
@@ -7049,6 +7347,7 @@ var init_headless = __esm({
|
|
|
7049
7347
|
init_prompt();
|
|
7050
7348
|
init_trigger();
|
|
7051
7349
|
init_compaction();
|
|
7350
|
+
init_trigger2();
|
|
7052
7351
|
init_lsp();
|
|
7053
7352
|
init_agent();
|
|
7054
7353
|
init_session();
|
|
@@ -7059,7 +7358,7 @@ var init_headless = __esm({
|
|
|
7059
7358
|
init_messageQueue();
|
|
7060
7359
|
init_resolve();
|
|
7061
7360
|
init_sentinel();
|
|
7062
|
-
|
|
7361
|
+
log14 = createLogger("headless");
|
|
7063
7362
|
EXTERNAL_TOOL_TIMEOUT_MS = 3e5;
|
|
7064
7363
|
USER_FACING_TOOLS = /* @__PURE__ */ new Set([
|
|
7065
7364
|
"promptUser",
|
|
@@ -7131,6 +7430,7 @@ var init_headless = __esm({
|
|
|
7131
7430
|
...this.queueFields()
|
|
7132
7431
|
});
|
|
7133
7432
|
}
|
|
7433
|
+
triggerBrandExtraction(this.config);
|
|
7134
7434
|
this.toolRegistry.onEvent = this.onEvent;
|
|
7135
7435
|
this.readline = createInterface({ input: process.stdin });
|
|
7136
7436
|
this.readline.on("line", this.handleStdinLine);
|
|
@@ -7230,7 +7530,7 @@ var init_headless = __esm({
|
|
|
7230
7530
|
}
|
|
7231
7531
|
onBackgroundComplete = (toolCallId, name, result, subAgentMessages) => {
|
|
7232
7532
|
this.pendingBlockUpdates.push({ toolCallId, result, subAgentMessages });
|
|
7233
|
-
|
|
7533
|
+
log14.info("Background complete", {
|
|
7234
7534
|
toolCallId,
|
|
7235
7535
|
name,
|
|
7236
7536
|
requestId: this.currentRequestId
|
|
@@ -7451,7 +7751,7 @@ var init_headless = __esm({
|
|
|
7451
7751
|
this.turnStart = Date.now();
|
|
7452
7752
|
const attachments = parsed.attachments;
|
|
7453
7753
|
if (attachments?.length) {
|
|
7454
|
-
|
|
7754
|
+
log14.info("Message has attachments", {
|
|
7455
7755
|
count: attachments.length,
|
|
7456
7756
|
urls: attachments.map((a) => a.url)
|
|
7457
7757
|
});
|
|
@@ -7468,7 +7768,7 @@ var init_headless = __esm({
|
|
|
7468
7768
|
${userMessage}` : header;
|
|
7469
7769
|
}
|
|
7470
7770
|
} catch (err) {
|
|
7471
|
-
|
|
7771
|
+
log14.warn("Attachment persistence failed", { error: err.message });
|
|
7472
7772
|
}
|
|
7473
7773
|
}
|
|
7474
7774
|
let resolved = null;
|
|
@@ -7526,7 +7826,7 @@ ${userMessage}` : header;
|
|
|
7526
7826
|
error: "Turn ended unexpectedly"
|
|
7527
7827
|
});
|
|
7528
7828
|
}
|
|
7529
|
-
|
|
7829
|
+
log14.info("Turn complete", {
|
|
7530
7830
|
requestId,
|
|
7531
7831
|
durationMs: Date.now() - this.turnStart
|
|
7532
7832
|
});
|
|
@@ -7538,7 +7838,7 @@ ${userMessage}` : header;
|
|
|
7538
7838
|
error: err.message
|
|
7539
7839
|
});
|
|
7540
7840
|
}
|
|
7541
|
-
|
|
7841
|
+
log14.warn("Command failed", {
|
|
7542
7842
|
action: "message",
|
|
7543
7843
|
requestId,
|
|
7544
7844
|
error: err.message
|
|
@@ -7673,7 +7973,7 @@ ${userMessage}` : header;
|
|
|
7673
7973
|
return;
|
|
7674
7974
|
}
|
|
7675
7975
|
const { action, requestId } = parsed;
|
|
7676
|
-
|
|
7976
|
+
log14.info("Command received", { action, requestId });
|
|
7677
7977
|
if (action === "tool_result" && parsed.id) {
|
|
7678
7978
|
const id = parsed.id;
|
|
7679
7979
|
const result = parsed.result ?? "";
|
|
@@ -7682,7 +7982,7 @@ ${userMessage}` : header;
|
|
|
7682
7982
|
this.pendingTools.delete(id);
|
|
7683
7983
|
pending.resolve(result);
|
|
7684
7984
|
} else if (!this.running) {
|
|
7685
|
-
|
|
7985
|
+
log14.info("Late tool_result while idle, dismissing", { id });
|
|
7686
7986
|
this.emit("completed", { success: true }, requestId);
|
|
7687
7987
|
} else {
|
|
7688
7988
|
this.earlyResults.set(id, result);
|
|
@@ -7810,8 +8110,8 @@ ${userMessage}` : header;
|
|
|
7810
8110
|
// src/index.tsx
|
|
7811
8111
|
import { render } from "ink";
|
|
7812
8112
|
import os2 from "os";
|
|
7813
|
-
import
|
|
7814
|
-
import
|
|
8113
|
+
import fs21 from "fs";
|
|
8114
|
+
import path11 from "path";
|
|
7815
8115
|
|
|
7816
8116
|
// src/tui/App.tsx
|
|
7817
8117
|
import { useState as useState2, useCallback, useRef } from "react";
|
|
@@ -8129,8 +8429,8 @@ for (let i = 0; i < args.length; i++) {
|
|
|
8129
8429
|
var startupLog = createLogger("startup");
|
|
8130
8430
|
function printDebugInfo(config) {
|
|
8131
8431
|
const pkg = JSON.parse(
|
|
8132
|
-
|
|
8133
|
-
|
|
8432
|
+
fs21.readFileSync(
|
|
8433
|
+
path11.join(import.meta.dirname, "..", "package.json"),
|
|
8134
8434
|
"utf-8"
|
|
8135
8435
|
)
|
|
8136
8436
|
);
|