@mindstudio-ai/remy 0.1.199 → 0.1.201

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
@@ -5461,9 +5461,9 @@ ${parts.join("\n\n")}
5461
5461
  }
5462
5462
  function loadPlatformBrief() {
5463
5463
  return `<platform_brief>
5464
- ## What is a MindStudio app?
5464
+ ## What is a Remy app?
5465
5465
 
5466
- A MindStudio app is a managed full-stack TypeScript project with three layers: a spec (natural language in src/), a backend contract (methods, tables, roles in dist/), and one or more interfaces (web, API, bots, cron, etc.). The spec is the source of truth; code is derived from it.
5466
+ A Remy app is a managed full-stack TypeScript project with three layers: a spec (natural language in src/), a backend contract (methods, tables, roles in dist/), and one or more interfaces (web, API, bots, cron, etc.). The spec is the source of truth; code is derived from it.
5467
5467
 
5468
5468
  This is a capable, stable platform used in production by 100k+ users. Build with confidence \u2014 you're building production-grade apps, not fragile prototypes.
5469
5469
 
@@ -5508,7 +5508,7 @@ TypeScript running in a sandboxed environment. Any npm package can be installed.
5508
5508
 
5509
5509
  The first-party SDK (@mindstudio-ai/agent) provides access to 200+ AI models (OpenAI, Anthropic, Google, Meta, Mistral, and more) and 1000+ integrations (email, SMS, Slack, HubSpot, Google Workspace, web scraping, image/video generation, media processing, and much more) with zero configuration \u2014 credentials are handled automatically in the execution environment. No API keys needed. This SDK is robust and battle-tested in production.
5510
5510
 
5511
- ## What MindStudio apps are NOT good for
5511
+ ## What Remy apps are NOT good for
5512
5512
 
5513
5513
  - Native mobile apps (iOS/Android). Mobile-responsive web apps are fine.
5514
5514
  - Real-time multiplayer with persistent connections (no WebSocket support). Turn-based or async patterns work.
@@ -6303,6 +6303,101 @@ var init_scrapeWebUrl2 = __esm({
6303
6303
  }
6304
6304
  });
6305
6305
 
6306
+ // src/tools/spec/writeBuildOverview.ts
6307
+ import fs19 from "fs";
6308
+ var OVERVIEW_FILE, DESIGN_BRIEF, OVERVIEW_SHELL, buildOverviewTool;
6309
+ var init_writeBuildOverview = __esm({
6310
+ "src/tools/spec/writeBuildOverview.ts"() {
6311
+ "use strict";
6312
+ init_designExpert();
6313
+ OVERVIEW_FILE = "src/overview.html";
6314
+ DESIGN_BRIEF = `We are building the Build Overview for this app \u2014 the home page of its Spec tab. It is a calm, dense, one-page reference of everything the app actually contains, including the parts the user can't see. It renders flush inside the Spec tab's content panel (the IDE supplies the surrounding nav).
6315
+
6316
+ Take the plain-language copy in <overview_copy> and lay it out and skin it into a single, beautiful, self-contained HTML document in the app's own brand. If <current_overview> is non-empty, use it as your starting point and preserve its established skin, updating only what the copy changed.
6317
+
6318
+ ### The single hard rule
6319
+ Preserve every fact in <overview_copy> exactly \u2014 every number, name, label, and claim. Do not add, drop, soften, reword, or invent any fact. You own layout, typography, and visual design only; the substance and the words are fixed. A single wrong number breaks this document's entire purpose.
6320
+
6321
+ ### What it is (and is not)
6322
+ - A typeset reference dossier: composed, dense, a little cool \u2014 substantial at a glance, then readable. Density communicates substance; sparse and airy reads as "not much here."
6323
+ - Brand-skinned: pull the palette, type system, and a single accent from the app's spec. The accent leads labels and figures; it is a mark, not a fill.
6324
+ - NOT a slide deck \u2014 no theatrics, no building to a climax, no persuasion.
6325
+ - NOT a docs site \u2014 no raised or shadowed cards, no hover-lift, no clickable-feeling surfaces, no sticky table of contents.
6326
+ - NOT a sparse memo \u2014 a restrained single-column page under-sells the work.
6327
+ - No header chrome and no footer: open straight on the app's logo and name so it sits flush with the IDE.
6328
+
6329
+ ### Constraints
6330
+ - A single self-contained HTML file. Fonts may load from a CDN; everything else (CSS, the logo SVG) is inline.
6331
+ - Responsive: fills the embedded panel width and collapses gracefully at narrow widths.
6332
+
6333
+ Respond only with the complete HTML file and absolutely no other text. Your response will be written directly to src/overview.html.`;
6334
+ OVERVIEW_SHELL = `<!DOCTYPE html>
6335
+ <html lang="en">
6336
+ <head>
6337
+ <meta charset="utf-8">
6338
+ <!-- This renders inside an iframe in the IDE. Keep it a simple, self-contained
6339
+ static document \u2014 no scroll/zoom/accessibility scaffolding beyond this head.
6340
+ The user-scalable=no viewport is intentional; leave it. -->
6341
+ <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
6342
+ <title>Build Overview</title>
6343
+ <!-- SKIN: link the app's fonts here (CDN \u2014 e.g. Fontshare / Google Fonts). -->
6344
+ <style>
6345
+ *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
6346
+ </style>
6347
+ </head>
6348
+ <body>
6349
+ <!-- Compose the Build Overview here. Layout, sections, type, and styling are
6350
+ yours \u2014 keep everything inline and self-contained, brand-skinned from the
6351
+ app's spec. -->
6352
+ </body>
6353
+ </html>`;
6354
+ buildOverviewTool = {
6355
+ clearable: false,
6356
+ definition: {
6357
+ name: "writeBuildOverview",
6358
+ description: "Generate or refresh the Build Overview \u2014 the project's home page in the Spec tab: a single-page, plain-language reference of everything the app actually contains, including the parts the user can't see (data stores, backend operations, access and roles, background jobs, seeded scenarios, the design system). You author the full copy: read the manifest and spec and state, plainly and exactly, what genuinely exists \u2014 real names and accurate counts \u2014 in calm, declarative, present-tense outcome language, with no persuasion or hype. Describe only what exists. Pass the complete copy as `content`; the design expert lays it out and skins it to the app's brand without altering any of your facts. Generate it at the end of a build and refresh it after meaningful work.",
6359
+ inputSchema: {
6360
+ type: "object",
6361
+ properties: {
6362
+ content: {
6363
+ type: "string",
6364
+ description: "The full Build Overview copy you authored: everything the app contains, in plain present-tense outcome language, with real names and exact counts. The design expert lays this out and skins it to the brand without changing any fact."
6365
+ }
6366
+ },
6367
+ required: ["content"]
6368
+ }
6369
+ },
6370
+ async execute(input, context) {
6371
+ if (!context) {
6372
+ return "Error: writeBuildOverview requires execution context for design expert delegation";
6373
+ }
6374
+ const content = (input.content ?? "").trim();
6375
+ if (!content) {
6376
+ return "Error: writeBuildOverview requires non-empty `content` (the overview copy).";
6377
+ }
6378
+ try {
6379
+ const existing = fs19.existsSync(OVERVIEW_FILE) ? fs19.readFileSync(OVERVIEW_FILE, "utf-8").trim() : "";
6380
+ const currentOverview = existing || OVERVIEW_SHELL;
6381
+ const task = `<overview_copy>${content}</overview_copy>
6382
+
6383
+ <current_overview>${currentOverview}</current_overview>
6384
+
6385
+ ${DESIGN_BRIEF}`;
6386
+ const result = await designExpertTool.execute({ task }, context);
6387
+ const htmlMatch = result.match(
6388
+ /```(?:html|wireframe)\n([\s\S]*?)```/
6389
+ );
6390
+ const html = htmlMatch ? htmlMatch[1].trim() : result;
6391
+ fs19.writeFileSync(OVERVIEW_FILE, html, "utf-8");
6392
+ return "Build overview written successfully to src/overview.html.";
6393
+ } catch (err) {
6394
+ return `Error generating build overview: ${err.message}`;
6395
+ }
6396
+ }
6397
+ };
6398
+ }
6399
+ });
6400
+
6306
6401
  // src/tools/index.ts
6307
6402
  function deriveContext(parent, toolCallId) {
6308
6403
  return { ...parent, toolCallId };
@@ -6357,6 +6452,7 @@ var init_tools6 = __esm({
6357
6452
  init_productVision();
6358
6453
  init_codeSanityCheck();
6359
6454
  init_scrapeWebUrl2();
6455
+ init_writeBuildOverview();
6360
6456
  ALL_TOOLS = [
6361
6457
  // Common
6362
6458
  setProjectOnboardingStateTool,
@@ -6369,6 +6465,7 @@ var init_tools6 = __esm({
6369
6465
  designExpertTool,
6370
6466
  productVisionTool,
6371
6467
  codeSanityCheckTool,
6468
+ buildOverviewTool,
6372
6469
  compactConversationTool,
6373
6470
  // Post-onboarding
6374
6471
  presentPublishPlanTool,
@@ -6411,11 +6508,11 @@ var init_tools6 = __esm({
6411
6508
  });
6412
6509
 
6413
6510
  // src/session.ts
6414
- import fs19 from "fs";
6511
+ import fs20 from "fs";
6415
6512
  import path9 from "path";
6416
6513
  function loadSession(state) {
6417
6514
  try {
6418
- const raw = fs19.readFileSync(SESSION_FILE, "utf-8");
6515
+ const raw = fs20.readFileSync(SESSION_FILE, "utf-8");
6419
6516
  const data = JSON.parse(raw);
6420
6517
  if (data.models && typeof data.models === "object") {
6421
6518
  state.models = data.models;
@@ -6474,7 +6571,7 @@ function saveSession(state) {
6474
6571
  if (state.models && Object.keys(state.models).length > 0) {
6475
6572
  payload.models = state.models;
6476
6573
  }
6477
- fs19.writeFileSync(SESSION_FILE, JSON.stringify(payload, null, 2), "utf-8");
6574
+ fs20.writeFileSync(SESSION_FILE, JSON.stringify(payload, null, 2), "utf-8");
6478
6575
  log8.info("Session saved", { messageCount: state.messages.length });
6479
6576
  } catch (err) {
6480
6577
  log8.warn("Session save failed", { error: err.message });
@@ -6483,11 +6580,11 @@ function saveSession(state) {
6483
6580
  function clearSession(state) {
6484
6581
  state.messages = [];
6485
6582
  try {
6486
- if (fs19.existsSync(SESSION_FILE)) {
6487
- fs19.mkdirSync(ARCHIVE_DIR, { recursive: true });
6583
+ if (fs20.existsSync(SESSION_FILE)) {
6584
+ fs20.mkdirSync(ARCHIVE_DIR, { recursive: true });
6488
6585
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
6489
6586
  const dest = path9.join(ARCHIVE_DIR, `cleared-${ts}.json`);
6490
- fs19.renameSync(SESSION_FILE, dest);
6587
+ fs20.renameSync(SESSION_FILE, dest);
6491
6588
  log8.info("Session archived on clear", { dest });
6492
6589
  }
6493
6590
  } catch (err) {
@@ -6495,7 +6592,7 @@ function clearSession(state) {
6495
6592
  error: err.message
6496
6593
  });
6497
6594
  try {
6498
- fs19.unlinkSync(SESSION_FILE);
6595
+ fs20.unlinkSync(SESSION_FILE);
6499
6596
  } catch {
6500
6597
  }
6501
6598
  }
@@ -6717,7 +6814,7 @@ var init_errors = __esm({
6717
6814
  });
6718
6815
 
6719
6816
  // src/brandExtraction/index.ts
6720
- import fs20 from "fs";
6817
+ import fs21 from "fs";
6721
6818
  import path10 from "path";
6722
6819
  import { createHash } from "crypto";
6723
6820
  async function runExtraction(apiConfig, model) {
@@ -6762,7 +6859,7 @@ function sha256(input) {
6762
6859
  }
6763
6860
  function readSafe(filePath) {
6764
6861
  try {
6765
- return fs20.readFileSync(filePath, "utf-8");
6862
+ return fs21.readFileSync(filePath, "utf-8");
6766
6863
  } catch {
6767
6864
  return "";
6768
6865
  }
@@ -6770,7 +6867,7 @@ function readSafe(filePath) {
6770
6867
  function walkMdFiles3(dir) {
6771
6868
  const results = [];
6772
6869
  try {
6773
- const entries = fs20.readdirSync(dir, { withFileTypes: true });
6870
+ const entries = fs21.readdirSync(dir, { withFileTypes: true });
6774
6871
  for (const entry of entries) {
6775
6872
  const full = path10.join(dir, entry.name);
6776
6873
  if (entry.isDirectory()) {
@@ -6785,7 +6882,7 @@ function walkMdFiles3(dir) {
6785
6882
  }
6786
6883
  function parseFrontmatter3(filePath) {
6787
6884
  try {
6788
- const content = fs20.readFileSync(filePath, "utf-8");
6885
+ const content = fs21.readFileSync(filePath, "utf-8");
6789
6886
  const match = content.match(/^---\n([\s\S]*?)\n---/);
6790
6887
  if (!match) {
6791
6888
  return { type: "" };
@@ -6964,14 +7061,14 @@ function pickFont(raw) {
6964
7061
  }
6965
7062
  function persistBrand(brand, inputHash) {
6966
7063
  const tmp = `${BRAND_FILE}.tmp`;
6967
- fs20.writeFileSync(tmp, JSON.stringify(brand, null, 2), "utf-8");
6968
- fs20.renameSync(tmp, BRAND_FILE);
7064
+ fs21.writeFileSync(tmp, JSON.stringify(brand, null, 2), "utf-8");
7065
+ fs21.renameSync(tmp, BRAND_FILE);
6969
7066
  const cache = { inputHash, generatedAt: Date.now() };
6970
- fs20.writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2), "utf-8");
7067
+ fs21.writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2), "utf-8");
6971
7068
  }
6972
7069
  function readCache() {
6973
7070
  try {
6974
- const raw = fs20.readFileSync(CACHE_FILE, "utf-8");
7071
+ const raw = fs21.readFileSync(CACHE_FILE, "utf-8");
6975
7072
  const parsed = JSON.parse(raw);
6976
7073
  if (parsed && typeof parsed.inputHash === "string" && typeof parsed.generatedAt === "number") {
6977
7074
  return parsed;
@@ -7638,12 +7735,12 @@ var init_agent = __esm({
7638
7735
  });
7639
7736
 
7640
7737
  // src/config.ts
7641
- import fs21 from "fs";
7738
+ import fs22 from "fs";
7642
7739
  import path11 from "path";
7643
7740
  import os from "os";
7644
7741
  function loadConfigFile() {
7645
7742
  try {
7646
- const raw = fs21.readFileSync(CONFIG_PATH, "utf-8");
7743
+ const raw = fs22.readFileSync(CONFIG_PATH, "utf-8");
7647
7744
  log12.debug("Loaded config file", { path: CONFIG_PATH });
7648
7745
  return JSON.parse(raw);
7649
7746
  } catch (err) {
@@ -7916,6 +8013,24 @@ var init_messageQueue = __esm({
7916
8013
  this.onChange?.();
7917
8014
  return all;
7918
8015
  }
8016
+ /**
8017
+ * Remove all items matching `predicate`. Fires onChange only if something
8018
+ * was removed. Returns the removed items.
8019
+ */
8020
+ removeWhere(predicate) {
8021
+ const removed = [];
8022
+ this.items = this.items.filter((item) => {
8023
+ if (predicate(item)) {
8024
+ removed.push(item);
8025
+ return false;
8026
+ }
8027
+ return true;
8028
+ });
8029
+ if (removed.length > 0) {
8030
+ this.onChange?.();
8031
+ }
8032
+ return removed;
8033
+ }
7919
8034
  /** Copy of current queue contents (for surfacing on events). */
7920
8035
  snapshot() {
7921
8036
  return [...this.items];
@@ -7967,6 +8082,24 @@ function resolveAction(text) {
7967
8082
  next
7968
8083
  };
7969
8084
  }
8085
+ function getActionChain(startName) {
8086
+ const chain = [];
8087
+ const seen = /* @__PURE__ */ new Set();
8088
+ let name = startName;
8089
+ while (name && !seen.has(name)) {
8090
+ seen.add(name);
8091
+ chain.push(name);
8092
+ let body;
8093
+ try {
8094
+ body = readAsset("automatedActions", `${name}.md`);
8095
+ } catch {
8096
+ break;
8097
+ }
8098
+ const fm = body.match(/^---\s*\n([\s\S]*?)\n---/);
8099
+ name = fm?.[1].match(/^\s*next:\s*(\w+)\s*$/m)?.[1];
8100
+ }
8101
+ return chain;
8102
+ }
7970
8103
  var NON_ACTION_SENTINELS;
7971
8104
  var init_resolve = __esm({
7972
8105
  "src/automatedActions/resolve.ts"() {
@@ -8071,14 +8204,16 @@ var init_headless = __esm({
8071
8204
  baseUrl: this.opts.baseUrl
8072
8205
  });
8073
8206
  const resumed = loadSession(this.state);
8074
- this.queue = new MessageQueue(loadQueue(), () => this.persistStats());
8207
+ this.queue = new MessageQueue(loadQueue(), () => {
8208
+ this.persistStats();
8209
+ this.emit("queue_changed", { queuedMessages: this.queue.snapshot() });
8210
+ });
8075
8211
  if (resumed) {
8076
8212
  this.emit("session_restored", {
8077
8213
  messageCount: this.state.messages.length,
8078
8214
  ...this.state.models && { models: this.state.models },
8079
8215
  modelSurfaces: MODEL_SURFACES,
8080
- allowedModelsByType: ALLOWED_MODELS_BY_TYPE,
8081
- ...this.queueFields()
8216
+ allowedModelsByType: ALLOWED_MODELS_BY_TYPE
8082
8217
  });
8083
8218
  }
8084
8219
  triggerBrandExtraction(
@@ -8128,7 +8263,7 @@ var init_headless = __esm({
8128
8263
  });
8129
8264
  process.on("SIGTERM", this.shutdown);
8130
8265
  process.on("SIGINT", this.shutdown);
8131
- this.emit("ready", this.queueFields());
8266
+ this.emit("ready");
8132
8267
  }
8133
8268
  shutdown = () => {
8134
8269
  this.emit("stopping");
@@ -8152,19 +8287,12 @@ var init_headless = __esm({
8152
8287
  }
8153
8288
  process.stdout.write(line);
8154
8289
  }
8155
- /**
8156
- * Emit a `completed` event and mark completedEmitted. Includes
8157
- * `queuedMessages` if the queue has items (sandbox uses this to know the
8158
- * agent is still busy with pipeline work).
8159
- */
8290
+ /** Emit a `completed` event and mark completedEmitted. Queue state is
8291
+ * surfaced separately via the `queue_changed` event, not on `completed`. */
8160
8292
  emitCompleted(rid, data) {
8161
- this.emit("completed", { ...data, ...this.queueFields() }, rid);
8293
+ this.emit("completed", { ...data }, rid);
8162
8294
  this.completedEmitted = true;
8163
8295
  }
8164
- /** Returns `{ queuedMessages }` when the queue is non-empty, else empty object. */
8165
- queueFields() {
8166
- return this.queue.length > 0 ? { queuedMessages: this.queue.snapshot() } : {};
8167
- }
8168
8296
  /** Dispatch a simple (non-streaming) command: call handler, emit response + completed. */
8169
8297
  dispatchSimple(requestId, eventName, handler) {
8170
8298
  try {
@@ -8342,11 +8470,7 @@ var init_headless = __esm({
8342
8470
  });
8343
8471
  return;
8344
8472
  case "turn_cancelled": {
8345
- this.emit(
8346
- "completed",
8347
- { success: false, error: "cancelled", ...this.queueFields() },
8348
- rid
8349
- );
8473
+ this.emit("completed", { success: false, error: "cancelled" }, rid);
8350
8474
  this.completedEmitted = true;
8351
8475
  return;
8352
8476
  }
@@ -8470,7 +8594,7 @@ var init_headless = __esm({
8470
8594
  * message — `running` stays held across the queue drain so no user
8471
8595
  * message can slip in mid-pipeline.
8472
8596
  */
8473
- async runSingleTurn(parsed, requestId) {
8597
+ async runSingleTurn(parsed, requestId, fromChain = false) {
8474
8598
  this.currentRequestId = requestId;
8475
8599
  this.currentAbort = new AbortController();
8476
8600
  this.completedEmitted = false;
@@ -8518,16 +8642,18 @@ var init_headless = __esm({
8518
8642
  onboardingState,
8519
8643
  parsed.viewContext
8520
8644
  );
8521
- if (resolved?.next) {
8522
- this.queue.push({
8523
- command: {
8524
- action: "message",
8525
- text: sentinel(resolved.next),
8526
- onboardingState
8527
- },
8528
- source: "chain",
8529
- enqueuedAt: Date.now()
8530
- });
8645
+ if (resolved?.next && !fromChain) {
8646
+ for (const step of getActionChain(resolved.next)) {
8647
+ this.queue.push({
8648
+ command: {
8649
+ action: "message",
8650
+ text: sentinel(step),
8651
+ onboardingState
8652
+ },
8653
+ source: "chain",
8654
+ enqueuedAt: Date.now()
8655
+ });
8656
+ }
8531
8657
  }
8532
8658
  try {
8533
8659
  await runTurn({
@@ -8585,11 +8711,6 @@ var init_headless = __esm({
8585
8711
  source: "user",
8586
8712
  enqueuedAt: Date.now()
8587
8713
  });
8588
- this.emit(
8589
- "queued",
8590
- { position: this.queue.length, ...this.queueFields() },
8591
- requestId
8592
- );
8593
8714
  return;
8594
8715
  }
8595
8716
  this.running = true;
@@ -8637,7 +8758,7 @@ var init_headless = __esm({
8637
8758
  continue;
8638
8759
  }
8639
8760
  const nextRid = next.command.requestId ?? `${next.source}-${Date.now()}`;
8640
- await this.runSingleTurn(next.command, nextRid);
8761
+ await this.runSingleTurn(next.command, nextRid, next.source === "chain");
8641
8762
  }
8642
8763
  }
8643
8764
  /**
@@ -8701,6 +8822,17 @@ var init_headless = __esm({
8701
8822
  }
8702
8823
  return this.queue.drain();
8703
8824
  }
8825
+ /**
8826
+ * Remove pending queued messages — all user messages, or one by id.
8827
+ * Only `source: 'user'` items are removable; chained and background
8828
+ * messages are part of a system chain and are never cancellable. Does
8829
+ * not affect the in-flight turn (use `cancel` for that).
8830
+ */
8831
+ handleCancelQueued(id) {
8832
+ return this.queue.removeWhere(
8833
+ (item) => item.source === "user" && (id === void 0 || item.command.requestId === id)
8834
+ );
8835
+ }
8704
8836
  //////////////////////////////////////////////////////////////////////////////
8705
8837
  // Stdin router
8706
8838
  //////////////////////////////////////////////////////////////////////////////
@@ -8765,7 +8897,11 @@ var init_headless = __esm({
8765
8897
  ...this.state.models && { models: this.state.models },
8766
8898
  modelSurfaces: MODEL_SURFACES,
8767
8899
  allowedModelsByType: ALLOWED_MODELS_BY_TYPE,
8768
- ...this.queueFields()
8900
+ // Current queue snapshot for connect/reconnect — get_history is the
8901
+ // on-demand "current state" query. Always an array (possibly empty),
8902
+ // matching the queue_changed convention so the client reconciles the
8903
+ // same way from both; live mutations are pushed via queue_changed.
8904
+ queuedMessages: this.queue.snapshot()
8769
8905
  }));
8770
8906
  return;
8771
8907
  }
@@ -8809,6 +8945,16 @@ var init_headless = __esm({
8809
8945
  );
8810
8946
  return;
8811
8947
  }
8948
+ if (action === "cancelQueued") {
8949
+ const id = parsed.id;
8950
+ const removed = this.handleCancelQueued(id);
8951
+ this.emit(
8952
+ "completed",
8953
+ { success: true, cancelledQueued: removed },
8954
+ requestId
8955
+ );
8956
+ return;
8957
+ }
8812
8958
  if (action === "stop_tool") {
8813
8959
  const id = parsed.id;
8814
8960
  const mode = parsed.mode ?? "hard";
@@ -8891,7 +9037,7 @@ var init_headless = __esm({
8891
9037
  // src/index.tsx
8892
9038
  import { render } from "ink";
8893
9039
  import os2 from "os";
8894
- import fs22 from "fs";
9040
+ import fs23 from "fs";
8895
9041
  import path12 from "path";
8896
9042
 
8897
9043
  // src/tui/App.tsx
@@ -9173,7 +9319,7 @@ Error: ${err.message}`,
9173
9319
  return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", gap: 1, children: [
9174
9320
  /* @__PURE__ */ jsxs4(Text5, { bold: true, color: "magenta", children: [
9175
9321
  "Remy ",
9176
- /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "v0.1.0 \u2014 MindStudio coding agent" })
9322
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "v0.1.0 \u2014 AI coding agent" })
9177
9323
  ] }),
9178
9324
  sessionRestored && /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
9179
9325
  "Session restored (",
@@ -9210,7 +9356,7 @@ for (let i = 0; i < args.length; i++) {
9210
9356
  var startupLog = createLogger("startup");
9211
9357
  function printDebugInfo(config) {
9212
9358
  const pkg = JSON.parse(
9213
- fs22.readFileSync(
9359
+ fs23.readFileSync(
9214
9360
  path12.join(import.meta.dirname, "..", "package.json"),
9215
9361
  "utf-8"
9216
9362
  )
@@ -69,7 +69,7 @@ From research into v0, Lovable, Bolt, and Anthropic's `<frontend_aesthetics>` co
69
69
 
70
70
  ## SDK Usage
71
71
 
72
- The canonical import pattern for MindStudio app methods is `import { mindstudio } from '@mindstudio-ai/agent'` with `mindstudio.generateText(...)`, `mindstudio.runTask(...)`, etc. The `mindstudio` singleton handles auth automatically. `new MindStudioAgent({ apiKey })` is only for external usage outside MindStudio apps.
72
+ The canonical import pattern for app methods is `import { mindstudio } from '@mindstudio-ai/agent'` with `mindstudio.generateText(...)`, `mindstudio.runTask(...)`, etc. The `mindstudio` singleton handles auth automatically. `new MindStudioAgent({ apiKey })` is only for external usage outside an app.
73
73
 
74
74
  The SDK ships `llms.txt` at the package root with full signatures for all 170+ actions. The compiled fragment references this path (`dist/methods/node_modules/@mindstudio-ai/agent/llms.txt`) so the agent knows where to look up specific action details.
75
75
 
@@ -18,7 +18,7 @@ instructions:
18
18
  ---
19
19
 
20
20
  **You will compile source docs into prompt fragments for Remy, a coding agent
21
- that builds MindStudio apps. The compiled fragments go in `src/prompt/compiled/`
21
+ that builds apps. The compiled fragments go in `src/prompt/compiled/`
22
22
  and are loaded into the agent's system prompt at runtime.**
23
23
 
24
24
  **Work through this one source file at a time, sequentially.** For each one:
@@ -39,7 +39,7 @@ Source files are in `docs/developer-guide/` at the project root.
39
39
 
40
40
  **Your audience is an LLM acting as a coding agent.** It needs to produce
41
41
  correct code, not learn concepts. Everything you write should be optimized
42
- for an agent that is actively building a MindStudio app and needs to get
42
+ for an agent that is actively building an app and needs to get
43
43
  the details right.
44
44
 
45
45
  ### What to keep
@@ -1,6 +1,6 @@
1
1
  # Auth
2
2
 
3
- MindStudio apps can have and manage their own users. Auth is opt-in: configure it in the manifest, define a user table, and build your own login UI. The platform handles verification codes, cookies, and session management. Apps without auth config use anonymous guest sessions (current default behavior).
3
+ Remy apps can have and manage their own users. Auth is opt-in: configure it in the manifest, define a user table, and build your own login UI. The platform handles verification codes, cookies, and session management. Apps without auth config use anonymous guest sessions (current default behavior).
4
4
 
5
5
  **Auth is optional.** Many apps don't need it. Only add auth when the app needs to identify users or restrict access.
6
6
 
@@ -338,7 +338,7 @@ Roles are declared in the manifest, stored as an array column on the user table,
338
338
  - Declare roles in `mindstudio.json` with `id` and `name`
339
339
  - The mapped `roles` column holds a JSON array of role ID strings: `["vendor", "admin"]`
340
340
  - Writable from code: `Users.update(userId, { roles: ['admin'] })` — platform syncs automatically
341
- - Writable from dashboard: MindStudio dashboard shows app users and their roles
341
+ - Writable from dashboard: Remy dashboard shows app users and their roles
342
342
  - Backend enforcement: `auth.requireRole('admin')` works as before
343
343
 
344
344
  ## Apps Without Auth
@@ -1,12 +1,12 @@
1
1
  # Frontend Design Notes
2
2
 
3
- Design standards for web interfaces in MindStudio apps.
3
+ Design standards for web interfaces in Remy apps.
4
4
 
5
5
  ## Quality Bar
6
6
 
7
7
  Every interface must feel like a polished, shipping product — not a prototype, not a starter template, not a homework assignment. If it wouldn't look good on Dribbble, Behance, or Mobbin, it's not done.
8
8
 
9
- MindStudio apps are end-user products. The interface is the product. Users judge the entire app by how it looks and feels in the first 3 seconds.
9
+ Remy apps are end-user products. The interface is the product. Users judge the entire app by how it looks and feels in the first 3 seconds.
10
10
 
11
11
  For questions about design, layout, UI, interfaces, components, and anything else, ask the design expert! They have access to countless resources and references and can provide great inspiration as you plan and work - the response to a quick "I'm making XYZ - wdyt?" can be such a powerful input to your thinking!
12
12
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Interfaces are projections of the backend contract into different modalities. The same methods power all of them. An interface can be as complex and polished as you want, but it's always safe — the backend contract is where anything real happens. The interface can't break business logic or corrupt data.
4
4
 
5
- All external service connections (Discord bot tokens, Telegram bot setup, webhook secrets, email addresses) are configured at the project level by the user through the MindStudio platform. The agent's job is to write the config files and the methods that handle the requests — not to manage API keys, OAuth flows, or service registration.
5
+ All external service connections (Discord bot tokens, Telegram bot setup, webhook secrets, email addresses) are configured at the project level by the user through the Remy platform. The agent's job is to write the config files and the methods that handle the requests — not to manage API keys, OAuth flows, or service registration.
6
6
 
7
7
  ## Web Interface
8
8
 
@@ -1,6 +1,6 @@
1
- # MindStudio Platform
1
+ # Remy Platform
2
2
 
3
- A MindStudio app has three layers: a **spec** (natural language in `src/`), a **backend contract** (methods, tables, roles in `dist/`), and **interfaces** (web, API, bots, cron, etc. — also in `dist/`). The spec is the source of truth; the code is a derivation.
3
+ A Remy app has three layers: a **spec** (natural language in `src/`), a **backend contract** (methods, tables, roles in `dist/`), and **interfaces** (web, API, bots, cron, etc. — also in `dist/`). The spec is the source of truth; the code is a derivation.
4
4
 
5
5
  `src/` is the authored source — natural language specs, brand guidelines, reference materials. No code. `dist/` is the compiled output — TypeScript methods, frontends, JSON configs. You can edit `dist/` directly, but `src/` is the reset point. Regenerate `dist/` from `src/` at any time.
6
6
 
@@ -6,7 +6,7 @@ There is a huge amount of capability here: hundreds of text generation models (O
6
6
 
7
7
  ## Usage in Methods
8
8
 
9
- Inside a MindStudio app method, use the `mindstudio` singleton — credentials come from the execution environment automatically:
9
+ Inside an app method, use the `mindstudio` singleton — credentials come from the execution environment automatically:
10
10
 
11
11
  ```typescript
12
12
  import { mindstudio } from '@mindstudio-ai/agent';
@@ -90,7 +90,7 @@ result.$billingCost; // cost in credits (if applicable)
90
90
 
91
91
  ### Third-Party Integrations (OAuth Connectors)
92
92
 
93
- 850+ additional actions from the MindStudio Connector Registry, covering services like HubSpot, Salesforce, Airtable, Google Workspace, Notion, Coda, and many more. These require OAuth connections set up by the user in MindStudio.
93
+ 850+ additional actions from the MindStudio Connector Registry, covering services like HubSpot, Salesforce, Airtable, Google Workspace, Notion, Coda, and many more. These require OAuth connections set up by the user in Remy.
94
94
 
95
95
  Built-in connector methods include: ActiveCampaign, Airtable, Apollo, Coda, Facebook, Gmail, Google Docs/Sheets/Calendar/Drive, HubSpot, Hunter.io, Instagram, LinkedIn, Notion, X (Twitter), YouTube.
96
96
 
@@ -76,7 +76,7 @@ Before installing a package you haven't used in this project, do a quick web sea
76
76
  You have access to the `mindstudio` CLI, which exposes every SDK action as a command-line tool. Use it via bash for one-off tasks: generating images, video, or audio, scraping URLs, sending emails, running AI completions, or anything else the SDK can do. Every JavaScript SDK method has a corresponding CLI command. Run `askMindStudioSdk` to discover commands for CLI usage.
77
77
 
78
78
  ### Production App Management
79
- You have access to `mindstudio-prod`, a CLI for managing the user's production MindStudio app. Use it via your bash tool. All output is JSON. Run `mindstudio-prod --help` or `mindstudio-prod <command> --help` to discover usage and available options.
79
+ You have access to `mindstudio-prod`, a CLI for managing the user's production app. Use it via your bash tool. All output is JSON. Run `mindstudio-prod --help` or `mindstudio-prod <command> --help` to discover usage and available options.
80
80
 
81
81
  Available commands: `requests` (server-side request logs, error rates, latency), `crashes` (frontend browser errors — grouped issues + drill-down to individual events), `analytics` (traffic, top pages/referrers/geo, AI-referral attribution, live counters), `releases` (deploy status, history), `domains` (custom subdomains and fully custom domains), `users` (list, set roles), `db` (query production sql db), `data` (live db operations like lift-from-dev), `methods` (list, invoke), `secrets` (list, get, set, delete).
82
82
 
@@ -1 +1 @@
1
- You are Remy, a coding and spec-building agent for MindStudio apps. You were created by MindStudio.
1
+ You are Remy, a coding and spec-building agent that builds apps.
@@ -7,6 +7,7 @@
7
7
  ## Principles
8
8
  - The spec in `src/` is the source of truth. When in doubt, consult the spec before making code changes. When behavior changes, update the spec first.
9
9
  - Always keep the spec up to date after making changes to the code, especially when adding features or building things from the roadmap.
10
+ - Keep `src/overview.html` (the Build Overview — the project's home page) current the same way you keep the spec in sync: after meaningful work such as new features, interfaces, data stores, or background jobs, re-author its copy and call `writeBuildOverview` so it still reflects everything the app actually contains.
10
11
  - Change only what the task requires. Match existing styles. Keep solutions simple.
11
12
  - Read files before editing them. Understand the context before making changes.
12
13
  - When the user asks you to make a change, execute it fully — all steps, no pausing for confirmation. Use `confirmDestructiveAction` to gate before destructive or irreversible actions (e.g., deleting data, resetting the database). For large changes that touch many files or involve significant design decisions, use `writePlan` to write an implementation plan for user approval — but only when the scope genuinely warrants it or the user asks to see a plan. The plan is saved to `.remy-plan.md` and the user can review, discuss, and refine it before approving. Do not begin implementation until the plan is approved. Most work should be done autonomously without a plan.
@@ -6,7 +6,7 @@ The goal of the intake session is to truly and deeply align with the user on a s
6
6
 
7
7
  ### What You're Working With
8
8
 
9
- MindStudio apps are full-stack TypeScript projects. You have a lot to work with:
9
+ Remy apps are full-stack TypeScript projects. You have a lot to work with:
10
10
 
11
11
  - **Backend (Methods):** TypeScript in a sandboxed runtime. Any npm package. Managed SQLite database with typed schemas and automatic migrations. Built-in app-managed auth with email/SMS verification, cookie sessions, and role enforcement. None of these are required — use what the app needs.
12
12
  - **Frontend (Web Interface):** Starts as Vite + React, but any TypeScript project with a build command works. Any framework, any library, or no framework at all.
@@ -18,12 +18,12 @@ Most things are fine. These are fast-moving products built by non-technical user
18
18
 
19
19
  These are things we already know about and have decided to accept:
20
20
 
21
- - **`dist/` is where code lives.** MindStudio apps use `dist/` for all code (methods, interfaces, tables) and `src/` for natural language specs. This is NOT the conventional "dist is build output" pattern. Never flag code being in `dist/` as wrong.
21
+ - **`dist/` is where code lives.** Remy apps use `dist/` for all code (methods, interfaces, tables) and `src/` for natural language specs. This is NOT the conventional "dist is build output" pattern. Never flag code being in `dist/` as wrong.
22
22
  - The raw request body for webhook signature verification (Stripe, GitHub, etc.) is available natively — under `input._request.rawBody` on API interface methods, and at top-level `input.rawBody` on Webhook interface methods. Do NOT suggest external proxies or workarounds.
23
23
 
24
24
  - Ignore limited browser support for `oklch` gradients using `in <colorspace>` syntax — we accept the compatibility tradeoff for better color quality
25
25
  -Ignore limited browser support for CSS scroll-driven animations (`animation-timeline: scroll()` / `view()`) - we accept this tradeoff
26
- - Trust your knowledge about Platform SDKs (these are the core of every MindStudio app) - for our purposes, assume they're always current and stable:
26
+ - Trust your knowledge about Platform SDKs (these are the core of every app) - for our purposes, assume they're always current and stable:
27
27
  - `@mindstudio-ai/interface` — frontend SDK. `createClient<T>()` gives typed RPC to backend methods (no raw fetch). `auth` handles auth state (`auth.currentUser`, `auth.onAuthStateChanged(cb)`, verification flows, logout). `platform.uploadFile()` handles signed S3 uploads and returns permanent CDN URLs with query-string resizing for images and auto-thumbnails for videos.
28
28
  - `@mindstudio-ai/agent` — backend SDK. `db.defineTable<T>()` gives a typed ORM with Query (chainable reads) and direct writes. `auth` gives `auth.userId`, `auth.roles`, `auth.requireRole()`, `auth.hasRole()`. Also provides 200+ managed actions for AI models, email/SMS, third-party APIs, media processing.
29
29
  - We know these libriares are actively maintained, don't waste time checking: