@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/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 path11;
2965
+ let path12;
2966
2966
  if (typeof promptOrOptions === "object" && promptOrOptions !== null) {
2967
2967
  prompt = promptOrOptions.prompt;
2968
2968
  existingUrl = promptOrOptions.imageUrl;
2969
- path11 = promptOrOptions.path;
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
- path11 ? { path: path11 } : void 0,
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 inflight = false;
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 || inflight || pauseCount > 0) {
3041
+ if (stopped || signal?.aborted || inflight2 || pauseCount > 0) {
3042
3042
  return;
3043
3043
  }
3044
- inflight = true;
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
- inflight = false;
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 dirty = false;
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
- dirty = true;
4944
+ dirty2 = true;
4945
4945
  }
4946
4946
  }
4947
- if (dirty) {
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
- log8.info("Turn started", {
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
- let thinkingStartedAt = 0;
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 (!thinkingStartedAt) {
6281
- thinkingStartedAt = event.ts;
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: thinkingStartedAt,
6583
+ startedAt: thinkingBlockStartTimes[thinkingCompleteCount] ?? event.ts,
6291
6584
  completedAt: event.ts
6292
6585
  });
6293
- thinkingStartedAt = 0;
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
- log8.info("Tool received", {
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
- log8.info("Tools executing", {
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
- log8.info("Waiting for external tool result", {
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
- log8.info("Tool completed", {
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 log8, EXTERNAL_TOOLS, USER_BLOCKING_EXTERNAL_TOOLS;
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
- log8 = createLogger("agent");
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 fs19 from "fs";
6619
- import path9 from "path";
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 = fs19.readFileSync(CONFIG_PATH, "utf-8");
6624
- log9.debug("Loaded config file", { path: CONFIG_PATH });
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
- log9.debug("No config file found", {
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
- log9.error("No API key found");
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
- log9.info("Config resolved", {
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 log9, CONFIG_PATH, DEFAULT_BASE_URL;
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
- log9 = createLogger("config");
6660
- CONFIG_PATH = path9.join(
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 log10, ToolRegistry;
6968
+ var log12, ToolRegistry;
6671
6969
  var init_toolRegistry = __esm({
6672
6970
  "src/toolRegistry.ts"() {
6673
6971
  "use strict";
6674
6972
  init_logger();
6675
- log10 = createLogger("tool-registry");
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
- log10.info("Tool stopped", { toolCallId: id, name: entry.name, mode });
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
- log10.info("Tool restarted", { toolCallId: id, name: entry.name });
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
- log11.info("Attachment saved", {
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
- log11.info("Extracted text saved", { path: extractedTextPath });
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 log11, UPLOADS_DIR, IMAGE_EXTENSIONS;
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
- log11 = createLogger("headless:attachments");
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 log12, EXTERNAL_TOOL_TIMEOUT_MS, USER_FACING_TOOLS, HeadlessSession;
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
- log12 = createLogger("headless");
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
- log12.info("Background complete", {
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
- log12.info("Message has attachments", {
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
- log12.warn("Attachment persistence failed", { error: err.message });
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
- log12.info("Turn complete", {
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
- log12.warn("Command failed", {
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
- log12.info("Command received", { action, requestId });
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
- log12.info("Late tool_result while idle, dismissing", { id });
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 fs20 from "fs";
7814
- import path10 from "path";
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
- fs20.readFileSync(
8133
- path10.join(import.meta.dirname, "..", "package.json"),
8432
+ fs21.readFileSync(
8433
+ path11.join(import.meta.dirname, "..", "package.json"),
8134
8434
  "utf-8"
8135
8435
  )
8136
8436
  );