@frontman-ai/astro 0.4.1 → 0.5.0

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.
Files changed (3) hide show
  1. package/dist/index.js +1313 -512
  2. package/dist/integration.js +1313 -512
  3. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
- import * as Fs from 'fs';
1
+ import * as Fs7 from 'fs';
2
2
  import { existsSync, readFileSync } from 'fs';
3
- import * as Nodepath from 'path';
3
+ import * as Nodepath5 from 'path';
4
4
  import { dirname, join } from 'path';
5
5
  import * as Nodebuffer from 'buffer';
6
6
  import * as Nodechild_process from 'child_process';
@@ -25,8 +25,6 @@ var require_lib = __commonJS({
25
25
  module.exports.rgPath = path.join(__dirname, `../bin/rg${process.platform === "win32" ? ".exe" : ""}`);
26
26
  }
27
27
  });
28
-
29
- // ../../node_modules/@rescript/runtime/lib/es6/Stdlib_JsError.js
30
28
  function panic(msg) {
31
29
  throw new Error(`Panic! ` + msg);
32
30
  }
@@ -72,7 +70,7 @@ function forEach(opt, f) {
72
70
  return f(valFromOption(opt));
73
71
  }
74
72
  }
75
- function getOrThrow(x, message3) {
73
+ function getOrThrow(x, message4) {
76
74
  if (x !== void 0) {
77
75
  return valFromOption(x);
78
76
  } else {
@@ -124,6 +122,7 @@ var clientCss = "https://app.frontman.sh/frontman.css";
124
122
  var devClientJs = "http://localhost:5173/src/Main.res.mjs";
125
123
 
126
124
  // src/FrontmanAstro__Config.res.mjs
125
+ var packageVersion = "0.5.0" ;
127
126
  var host = process.env["FRONTMAN_HOST"];
128
127
  var defaultHost = host !== void 0 ? host : apiHost;
129
128
  var ensureConfig = (function(c2) {
@@ -138,7 +137,7 @@ function makeFromObject(rawConfig) {
138
137
  let raw = getOr(config.basePath, "frontman").replace(/^\/+|\/+$/g, "");
139
138
  let basePath = raw === "" ? "frontman" : raw;
140
139
  let serverName = getOr(config.serverName, "frontman-astro");
141
- let serverVersion = getOr(config.serverVersion, "1.0.0");
140
+ let serverVersion = getOr(config.serverVersion, packageVersion);
142
141
  let isLightTheme = getOr(config.isLightTheme, false);
143
142
  let baseUrl = getOr(config.clientUrl, getOr(process.env["FRONTMAN_CLIENT_URL"], isDev ? devClientJs : clientJs));
144
143
  let url2 = new URL(baseUrl);
@@ -462,22 +461,22 @@ function create(str) {
462
461
  // ../../node_modules/sury/src/Sury.res.mjs
463
462
  var immutableEmpty = {};
464
463
  var immutableEmpty$1 = [];
465
- function capitalize(string3) {
466
- return string3.slice(0, 1).toUpperCase() + string3.slice(1);
464
+ function capitalize(string4) {
465
+ return string4.slice(0, 1).toUpperCase() + string4.slice(1);
467
466
  }
468
467
  var copy = ((d2) => ({ ...d2 }));
469
- function fromString(string3) {
468
+ function fromString(string4) {
470
469
  let _idx = 0;
471
470
  while (true) {
472
471
  let idx = _idx;
473
- let match = string3[idx];
472
+ let match = string4[idx];
474
473
  if (match === void 0) {
475
- return `"` + string3 + `"`;
474
+ return `"` + string4 + `"`;
476
475
  }
477
476
  switch (match) {
478
477
  case '"':
479
478
  case "\n":
480
- return JSON.stringify(string3);
479
+ return JSON.stringify(string4);
481
480
  default:
482
481
  _idx = idx + 1 | 0;
483
482
  continue;
@@ -545,14 +544,14 @@ function stringify(unknown2) {
545
544
  return "null";
546
545
  }
547
546
  if (Array.isArray(unknown2)) {
548
- let string3 = "[";
547
+ let string4 = "[";
549
548
  for (let i = 0, i_finish = unknown2.length; i < i_finish; ++i) {
550
549
  if (i !== 0) {
551
- string3 = string3 + ", ";
550
+ string4 = string4 + ", ";
552
551
  }
553
- string3 = string3 + stringify(unknown2[i]);
552
+ string4 = string4 + stringify(unknown2[i]);
554
553
  }
555
- return string3 + "]";
554
+ return string4 + "]";
556
555
  }
557
556
  if (unknown2.constructor !== Object) {
558
557
  return Object.prototype.toString.call(unknown2);
@@ -569,9 +568,9 @@ function stringify(unknown2) {
569
568
  function toExpression(schema3) {
570
569
  let tag = schema3.type;
571
570
  let $$const = schema3.const;
572
- let name14 = schema3.name;
573
- if (name14 !== void 0) {
574
- return name14;
571
+ let name15 = schema3.name;
572
+ if (name15 !== void 0) {
573
+ return name15;
575
574
  }
576
575
  if ($$const !== void 0) {
577
576
  return stringify($$const);
@@ -732,8 +731,8 @@ var shakenTraps = {
732
731
  return target[prop];
733
732
  }
734
733
  let l$1 = valFromOption(l);
735
- let message3 = `Schema S.` + l$1 + ` is not enabled. To start using it, add S.enable` + capitalize(l$1) + `() at the project root.`;
736
- throw new Error(`[Sury] ` + message3);
734
+ let message4 = `Schema S.` + l$1 + ` is not enabled. To start using it, add S.enable` + capitalize(l$1) + `() at the project root.`;
735
+ throw new Error(`[Sury] ` + message4);
737
736
  }
738
737
  };
739
738
  function shaken(apiName) {
@@ -1691,10 +1690,10 @@ function isPriority(tagFlag, byKey) {
1691
1690
  }
1692
1691
  }
1693
1692
  function isWiderUnionSchema(schemaAnyOf, inputAnyOf) {
1694
- return inputAnyOf.every((inputSchema13, idx) => {
1693
+ return inputAnyOf.every((inputSchema14, idx) => {
1695
1694
  let schema3 = schemaAnyOf[idx];
1696
- if (schema3 !== void 0 && !(flags[inputSchema13.type] & 9152) && inputSchema13.type === schema3.type) {
1697
- return inputSchema13.const === schema3.const;
1695
+ if (schema3 !== void 0 && !(flags[inputSchema14.type] & 9152) && inputSchema14.type === schema3.type) {
1696
+ return inputSchema14.const === schema3.const;
1698
1697
  } else {
1699
1698
  return false;
1700
1699
  }
@@ -2740,8 +2739,8 @@ function argsToString(args) {
2740
2739
  function stripAnsi(str) {
2741
2740
  return str.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "");
2742
2741
  }
2743
- function addLog(state, level, message3, attributes, consoleMethod) {
2744
- let cleanMessage = stripAnsi(message3).trim();
2742
+ function addLog(state, level, message4, attributes, consoleMethod) {
2743
+ let cleanMessage = stripAnsi(message4).trim();
2745
2744
  if (cleanMessage === "") {
2746
2745
  return;
2747
2746
  }
@@ -2818,11 +2817,11 @@ var interceptConsole = (function(state) {
2818
2817
  originalDebug(...args);
2819
2818
  };
2820
2819
  });
2821
- function handleStdoutWrite(state, message3) {
2820
+ function handleStdoutWrite(state, message4) {
2822
2821
  try {
2823
- let matchesPattern2 = state.config.stdoutPatterns.some((pattern2) => message3.includes(pattern2));
2822
+ let matchesPattern2 = state.config.stdoutPatterns.some((pattern2) => message4.includes(pattern2));
2824
2823
  if (matchesPattern2) {
2825
- return addLog(state, "build", message3, void 0, void 0);
2824
+ return addLog(state, "build", message4, void 0, void 0);
2826
2825
  } else {
2827
2826
  return;
2828
2827
  }
@@ -2834,8 +2833,8 @@ function interceptStdout(_state) {
2834
2833
  (function(_state2) {
2835
2834
  const originalWrite = process.stdout.write.bind(process.stdout);
2836
2835
  process.stdout.write = (chunk, ...args) => {
2837
- const message3 = typeof chunk === "string" ? chunk : chunk.toString();
2838
- handleStdoutWrite(_state2, message3);
2836
+ const message4 = typeof chunk === "string" ? chunk : chunk.toString();
2837
+ handleStdoutWrite(_state2, message4);
2839
2838
  return originalWrite(chunk, ...args);
2840
2839
  };
2841
2840
  })(_state);
@@ -2990,12 +2989,65 @@ Parameters:
2990
2989
 
2991
2990
  Returns logs in chronological order (oldest first within buffer).`;
2992
2991
 
2993
- // ../frontman-core/src/FrontmanCore__FileTracker.res.mjs
2992
+ // ../frontman-core/src/FrontmanCore__ExnUtils.res.mjs
2993
+ function message3(exn) {
2994
+ return getOr(flatMap(fromException(exn), message2), "Unknown error");
2995
+ }
2994
2996
  var readFiles = {
2995
- contents: /* @__PURE__ */ new Set()
2997
+ contents: /* @__PURE__ */ new Map()
2996
2998
  };
2997
- function recordRead(resolvedPath) {
2998
- readFiles.contents.add(resolvedPath);
2999
+ function mergeRanges(ranges) {
3000
+ let match = ranges.length;
3001
+ if (match === 0) {
3002
+ return [];
3003
+ }
3004
+ let sorted = ranges.toSorted((a, b) => a.start - b.start | 0);
3005
+ let first = sorted[0];
3006
+ let merged = [{
3007
+ start: first.start,
3008
+ end_: first.end_
3009
+ }];
3010
+ for (let i = 1, i_finish = sorted.length; i < i_finish; ++i) {
3011
+ let current = sorted[i];
3012
+ let last = merged[merged.length - 1 | 0];
3013
+ if (current.start <= last.end_) {
3014
+ last.end_ = max(last.end_, current.end_);
3015
+ } else {
3016
+ merged.push({
3017
+ start: current.start,
3018
+ end_: current.end_
3019
+ });
3020
+ }
3021
+ }
3022
+ return merged;
3023
+ }
3024
+ function recordRead(resolvedPath, offset, limit, totalLines) {
3025
+ let now = Date.now();
3026
+ let newRange = {
3027
+ start: offset,
3028
+ end_: min(offset + limit | 0, totalLines)
3029
+ };
3030
+ let record = readFiles.contents.get(resolvedPath);
3031
+ if (record !== void 0) {
3032
+ record.readAt = now;
3033
+ record.totalLines = totalLines;
3034
+ record.ranges = mergeRanges(record.ranges.concat([newRange]));
3035
+ } else {
3036
+ readFiles.contents.set(resolvedPath, {
3037
+ readAt: now,
3038
+ ranges: [newRange],
3039
+ totalLines
3040
+ });
3041
+ }
3042
+ }
3043
+ function isLineCovered(ranges, line) {
3044
+ return ranges.some((r) => {
3045
+ if (line >= r.start) {
3046
+ return line < r.end_;
3047
+ } else {
3048
+ return false;
3049
+ }
3050
+ });
2999
3051
  }
3000
3052
  function assertReadBefore(resolvedPath) {
3001
3053
  if (readFiles.contents.has(resolvedPath)) {
@@ -3010,6 +3062,90 @@ function assertReadBefore(resolvedPath) {
3010
3062
  };
3011
3063
  }
3012
3064
  }
3065
+ async function assertNotStale(resolvedPath) {
3066
+ let record = readFiles.contents.get(resolvedPath);
3067
+ if (record === void 0) {
3068
+ return {
3069
+ TAG: "Ok",
3070
+ _0: void 0
3071
+ };
3072
+ }
3073
+ try {
3074
+ let stats = await Fs7.promises.stat(resolvedPath);
3075
+ let mtimeMs = stats.mtimeMs;
3076
+ if (mtimeMs > record.readAt + 100) {
3077
+ return {
3078
+ TAG: "Error",
3079
+ _0: `File "` + resolvedPath + `" has been modified since it was last read. Please read the file again before editing.`
3080
+ };
3081
+ } else {
3082
+ return {
3083
+ TAG: "Ok",
3084
+ _0: void 0
3085
+ };
3086
+ }
3087
+ } catch (exn) {
3088
+ return {
3089
+ TAG: "Ok",
3090
+ _0: void 0
3091
+ };
3092
+ }
3093
+ }
3094
+ function checkCoverage(resolvedPath, content, oldText) {
3095
+ let record = readFiles.contents.get(resolvedPath);
3096
+ if (record === void 0) {
3097
+ return;
3098
+ }
3099
+ let ranges = record.ranges;
3100
+ if (ranges.length === 1) {
3101
+ let match = ranges[0];
3102
+ if (match.start === 0) {
3103
+ let end_ = match.end_;
3104
+ if (end_ >= record.totalLines) {
3105
+ return;
3106
+ }
3107
+ }
3108
+ }
3109
+ let lines = content.split("\n");
3110
+ let oldLines = oldText.trim().split("\n");
3111
+ let firstOldLine = getOr(oldLines[0], "").trim();
3112
+ let targetLine = {
3113
+ contents: void 0
3114
+ };
3115
+ lines.forEach((line2, idx) => {
3116
+ let match = targetLine.contents;
3117
+ if (match !== void 0 || line2.trim() !== firstOldLine) {
3118
+ return;
3119
+ } else {
3120
+ targetLine.contents = idx;
3121
+ return;
3122
+ }
3123
+ });
3124
+ let line = targetLine.contents;
3125
+ if (line === void 0) {
3126
+ return;
3127
+ }
3128
+ if (isLineCovered(ranges, line)) {
3129
+ return;
3130
+ }
3131
+ let rangeStr = ranges.map((r) => r.start.toString() + `-` + r.end_.toString()).join(", ");
3132
+ return `Warning: You are editing around line ` + line.toString() + ` but only read lines [` + rangeStr + `] of this ` + record.totalLines.toString() + `-line file. Consider reading the target section first with read_file and an appropriate offset.`;
3133
+ }
3134
+ async function assertEditSafe(resolvedPath) {
3135
+ let e = assertReadBefore(resolvedPath);
3136
+ if (e.TAG === "Ok") {
3137
+ return await assertNotStale(resolvedPath);
3138
+ } else {
3139
+ return e;
3140
+ }
3141
+ }
3142
+ function recordWrite(resolvedPath) {
3143
+ let record = readFiles.contents.get(resolvedPath);
3144
+ if (record !== void 0) {
3145
+ record.readAt = Date.now();
3146
+ return;
3147
+ }
3148
+ }
3013
3149
  function endsWithSep(path) {
3014
3150
  if (path.endsWith("/")) {
3015
3151
  return true;
@@ -3018,10 +3154,10 @@ function endsWithSep(path) {
3018
3154
  }
3019
3155
  }
3020
3156
  function resolve(sourceRoot, inputPath) {
3021
- let normalizedRoot = Nodepath.normalize(sourceRoot);
3022
- let rootWithSep = endsWithSep(normalizedRoot) ? normalizedRoot : normalizedRoot + Nodepath.sep;
3023
- if (Nodepath.isAbsolute(inputPath)) {
3024
- let normalizedPath = Nodepath.normalize(inputPath);
3157
+ let normalizedRoot = Nodepath5.normalize(sourceRoot);
3158
+ let rootWithSep = endsWithSep(normalizedRoot) ? normalizedRoot : normalizedRoot + Nodepath5.sep;
3159
+ if (Nodepath5.isAbsolute(inputPath)) {
3160
+ let normalizedPath = Nodepath5.normalize(inputPath);
3025
3161
  if (normalizedPath === normalizedRoot || normalizedPath.startsWith(rootWithSep)) {
3026
3162
  return {
3027
3163
  TAG: "Ok",
@@ -3036,7 +3172,7 @@ function resolve(sourceRoot, inputPath) {
3036
3172
  };
3037
3173
  }
3038
3174
  }
3039
- let fullPath = Nodepath.normalize(Nodepath.join(sourceRoot, inputPath));
3175
+ let fullPath = Nodepath5.normalize(Nodepath5.join(sourceRoot, inputPath));
3040
3176
  if (fullPath === normalizedRoot || fullPath.startsWith(rootWithSep)) {
3041
3177
  return {
3042
3178
  TAG: "Ok",
@@ -3055,7 +3191,7 @@ function toString(safePath) {
3055
3191
  return safePath.path;
3056
3192
  }
3057
3193
  function dirname2(safePath) {
3058
- return Nodepath.dirname(safePath.path);
3194
+ return Nodepath5.dirname(safePath.path);
3059
3195
  }
3060
3196
 
3061
3197
  // ../frontman-core/src/FrontmanCore__PathContext.res.mjs
@@ -3067,7 +3203,7 @@ function endsWithSep2(path) {
3067
3203
  }
3068
3204
  }
3069
3205
  function toRelativePath(sourceRoot, absolutePath) {
3070
- let normalizedRoot = endsWithSep2(sourceRoot) ? sourceRoot : sourceRoot + Nodepath.sep;
3206
+ let normalizedRoot = endsWithSep2(sourceRoot) ? sourceRoot : sourceRoot + Nodepath5.sep;
3071
3207
  if (absolutePath.startsWith(normalizedRoot)) {
3072
3208
  return absolutePath.slice(normalizedRoot.length, absolutePath.length);
3073
3209
  } else if (absolutePath.startsWith(sourceRoot)) {
@@ -3080,17 +3216,30 @@ function resolveSearchPath(sourceRoot, inputPath) {
3080
3216
  if (inputPath === void 0) {
3081
3217
  return sourceRoot;
3082
3218
  }
3083
- if (!Nodepath.isAbsolute(inputPath)) {
3084
- return Nodepath.join(sourceRoot, inputPath);
3219
+ if (!Nodepath5.isAbsolute(inputPath)) {
3220
+ return Nodepath5.join(sourceRoot, inputPath);
3085
3221
  }
3086
- let normalizedPath = Nodepath.normalize(inputPath);
3087
- let normalizedRoot = Nodepath.normalize(sourceRoot);
3222
+ let normalizedPath = Nodepath5.normalize(inputPath);
3223
+ let normalizedRoot = Nodepath5.normalize(sourceRoot);
3088
3224
  if (normalizedPath.startsWith(normalizedRoot)) {
3089
3225
  return normalizedPath;
3090
3226
  } else {
3091
3227
  return sourceRoot;
3092
3228
  }
3093
3229
  }
3230
+ async function resolveSearchDir(sourceRoot, inputPath) {
3231
+ let resolved = resolveSearchPath(sourceRoot, inputPath);
3232
+ try {
3233
+ let stats = await Fs7.promises.stat(resolved);
3234
+ if (stats.isFile()) {
3235
+ return Nodepath5.dirname(resolved);
3236
+ } else {
3237
+ return resolved;
3238
+ }
3239
+ } catch (exn) {
3240
+ return resolved;
3241
+ }
3242
+ }
3094
3243
  function detectPathConfusion(sourceRoot, requestedPath) {
3095
3244
  let normalizedPath = requestedPath.replaceAll("\\", "/").replace(/^\.\//, "").replace(/^\//, "");
3096
3245
  let firstSegment = getOr(normalizedPath.split("/")[0], "");
@@ -3099,7 +3248,7 @@ function detectPathConfusion(sourceRoot, requestedPath) {
3099
3248
  return `Path '` + requestedPath + `' not found. The sourceRoot is '` + sourceRoot + `' which already includes '` + firstSegment + `/'. Try using '.' or a path relative to sourceRoot instead.`;
3100
3249
  }
3101
3250
  }
3102
- function dirname3(result) {
3251
+ function dirname4(result) {
3103
3252
  return dirname2(result.safePath);
3104
3253
  }
3105
3254
  function resolve2(sourceRoot, inputPath) {
@@ -3617,8 +3766,74 @@ var outputSchema2 = schema2((s2) => ({
3617
3766
  message: s2.m(string2),
3618
3767
  _context: s2.m(option2(pathContextSchema))
3619
3768
  }));
3769
+ function toPathCtx(r) {
3770
+ return {
3771
+ sourceRoot: r.sourceRoot,
3772
+ resolvedPath: r.resolvedPath,
3773
+ relativePath: r.relativePath
3774
+ };
3775
+ }
3776
+ async function createFile(resolved, content, displayPath) {
3777
+ try {
3778
+ await Fs7.promises.mkdir(dirname4(resolved), {
3779
+ recursive: true
3780
+ });
3781
+ await Fs7.promises.writeFile(resolved.resolvedPath, content, "utf8");
3782
+ recordWrite(resolved.resolvedPath);
3783
+ return {
3784
+ TAG: "Ok",
3785
+ _0: {
3786
+ message: "File created successfully.",
3787
+ _context: toPathCtx(resolved)
3788
+ }
3789
+ };
3790
+ } catch (raw_exn) {
3791
+ let exn = internalToException(raw_exn);
3792
+ return {
3793
+ TAG: "Error",
3794
+ _0: `Failed to create file ` + displayPath + `: ` + message3(exn)
3795
+ };
3796
+ }
3797
+ }
3798
+ async function findAndReplace(resolved, oldText, newText, replaceAll, displayPath) {
3799
+ try {
3800
+ let content = await Fs7.promises.readFile(resolved.resolvedPath, "utf8");
3801
+ let coverageWarning = checkCoverage(resolved.resolvedPath, content, oldText);
3802
+ let newContent = applyEdit(content, oldText, newText, replaceAll);
3803
+ if (typeof newContent !== "object") {
3804
+ if (newContent === "NotFound") {
3805
+ return {
3806
+ TAG: "Error",
3807
+ _0: `oldText not found in file ` + displayPath + `. Make sure the text matches exactly, or read the file again to see its current content.`
3808
+ };
3809
+ } else {
3810
+ return {
3811
+ TAG: "Error",
3812
+ _0: `Found multiple matches for oldText in ` + displayPath + `. Provide more surrounding context to identify the correct match, or use replaceAll to replace all occurrences.`
3813
+ };
3814
+ }
3815
+ }
3816
+ await Fs7.promises.writeFile(resolved.resolvedPath, newContent._0, "utf8");
3817
+ recordWrite(resolved.resolvedPath);
3818
+ let message4 = coverageWarning !== void 0 ? `Edit applied successfully.
3819
+
3820
+ ` + coverageWarning : "Edit applied successfully.";
3821
+ return {
3822
+ TAG: "Ok",
3823
+ _0: {
3824
+ message: message4,
3825
+ _context: toPathCtx(resolved)
3826
+ }
3827
+ };
3828
+ } catch (raw_exn) {
3829
+ let exn = internalToException(raw_exn);
3830
+ return {
3831
+ TAG: "Error",
3832
+ _0: `Failed to edit file ` + displayPath + `: ` + message3(exn)
3833
+ };
3834
+ }
3835
+ }
3620
3836
  async function execute2(ctx2, input) {
3621
- let replaceAll = getOr(input.replaceAll, false);
3622
3837
  if (input.oldText === input.newText) {
3623
3838
  return {
3624
3839
  TAG: "Error",
@@ -3632,77 +3847,19 @@ async function execute2(ctx2, input) {
3632
3847
  _0: formatError(err._0)
3633
3848
  };
3634
3849
  }
3635
- let result = err._0;
3636
- let pathCtx_sourceRoot = result.sourceRoot;
3637
- let pathCtx_resolvedPath = result.resolvedPath;
3638
- let pathCtx_relativePath = result.relativePath;
3639
- let pathCtx = {
3640
- sourceRoot: pathCtx_sourceRoot,
3641
- resolvedPath: pathCtx_resolvedPath,
3642
- relativePath: pathCtx_relativePath
3643
- };
3644
- if (input.oldText === "") {
3645
- try {
3646
- let dirPath = dirname3(result);
3647
- await Fs.promises.mkdir(dirPath, {
3648
- recursive: true
3649
- });
3650
- await Fs.promises.writeFile(result.resolvedPath, input.newText, "utf8");
3651
- return {
3652
- TAG: "Ok",
3653
- _0: {
3654
- message: "File created successfully.",
3655
- _context: pathCtx
3656
- }
3657
- };
3658
- } catch (raw_exn) {
3659
- let exn = internalToException(raw_exn);
3660
- let msg = getOr(flatMap(fromException(exn), message2), "Unknown error");
3661
- return {
3662
- TAG: "Error",
3663
- _0: `Failed to create file ` + input.path + `: ` + msg
3664
- };
3665
- }
3850
+ let resolved = err._0;
3851
+ let oldText = input.oldText;
3852
+ if (oldText === "") {
3853
+ return await createFile(resolved, input.newText, input.path);
3854
+ }
3855
+ let msg = await assertEditSafe(resolved.resolvedPath);
3856
+ if (msg.TAG === "Ok") {
3857
+ return await findAndReplace(resolved, oldText, input.newText, getOr(input.replaceAll, false), input.path);
3666
3858
  } else {
3667
- let msg$1 = assertReadBefore(result.resolvedPath);
3668
- if (msg$1.TAG !== "Ok") {
3669
- return {
3670
- TAG: "Error",
3671
- _0: msg$1._0
3672
- };
3673
- }
3674
- try {
3675
- let content = await Fs.promises.readFile(result.resolvedPath, "utf8");
3676
- let newContent = applyEdit(content, input.oldText, input.newText, replaceAll);
3677
- if (typeof newContent !== "object") {
3678
- if (newContent === "NotFound") {
3679
- return {
3680
- TAG: "Error",
3681
- _0: `oldText not found in file ` + input.path + `. Make sure the text matches exactly, or read the file again to see its current content.`
3682
- };
3683
- } else {
3684
- return {
3685
- TAG: "Error",
3686
- _0: `Found multiple matches for oldText in ` + input.path + `. Provide more surrounding context to identify the correct match, or use replaceAll to replace all occurrences.`
3687
- };
3688
- }
3689
- }
3690
- await Fs.promises.writeFile(result.resolvedPath, newContent._0, "utf8");
3691
- return {
3692
- TAG: "Ok",
3693
- _0: {
3694
- message: "Edit applied successfully.",
3695
- _context: pathCtx
3696
- }
3697
- };
3698
- } catch (raw_exn$1) {
3699
- let exn$1 = internalToException(raw_exn$1);
3700
- let msg$2 = getOr(flatMap(fromException(exn$1), message2), "Unknown error");
3701
- return {
3702
- TAG: "Error",
3703
- _0: `Failed to edit file ` + input.path + `: ` + msg$2
3704
- };
3705
- }
3859
+ return {
3860
+ TAG: "Error",
3861
+ _0: msg._0
3862
+ };
3706
3863
  }
3707
3864
  }
3708
3865
  var name3 = "edit_file";
@@ -3828,12 +3985,12 @@ function getMostSignificantDynamicType(segments) {
3828
3985
  });
3829
3986
  }
3830
3987
  async function findPages(baseDir, currentPath, projectRoot, sourceRoot) {
3831
- let fullPath = Nodepath.join(projectRoot, baseDir, currentPath);
3988
+ let fullPath = Nodepath5.join(projectRoot, baseDir, currentPath);
3832
3989
  try {
3833
- let entries = await Fs.promises.readdir(fullPath);
3990
+ let entries = await Fs7.promises.readdir(fullPath);
3834
3991
  return (await Promise.all(entries.map(async (entry) => {
3835
- let entryPath = Nodepath.join(fullPath, entry);
3836
- let stats = await Fs.promises.lstat(entryPath);
3992
+ let entryPath = Nodepath5.join(fullPath, entry);
3993
+ let stats = await Fs7.promises.lstat(entryPath);
3837
3994
  if (stats.isSymbolicLink()) {
3838
3995
  return [];
3839
3996
  }
@@ -3841,13 +3998,13 @@ async function findPages(baseDir, currentPath, projectRoot, sourceRoot) {
3841
3998
  if (entry.startsWith("_") || entry === "api" || entry === "components") {
3842
3999
  return [];
3843
4000
  } else {
3844
- return await findPages(baseDir, Nodepath.join(currentPath, entry), projectRoot, sourceRoot);
4001
+ return await findPages(baseDir, Nodepath5.join(currentPath, entry), projectRoot, sourceRoot);
3845
4002
  }
3846
4003
  }
3847
4004
  if (!(entry.endsWith(".astro") || entry.endsWith(".md") || entry.endsWith(".mdx") || entry.endsWith(".html"))) {
3848
4005
  return [];
3849
4006
  }
3850
- let filePath = Nodepath.join(currentPath, entry);
4007
+ let filePath = Nodepath5.join(currentPath, entry);
3851
4008
  let routePath = fileToRoute(filePath);
3852
4009
  let filePathNoExt = filePath.replace(/\.(astro|md|mdx|html)$/, "");
3853
4010
  let segments = filePathNoExt.replaceAll("\\", "/").split("/");
@@ -3906,10 +4063,10 @@ function fromString2(x, radix) {
3906
4063
  }
3907
4064
  }
3908
4065
  function execPromise(command, options) {
4066
+ let maxBuffer = getOr(options.maxBuffer, 52428800);
3909
4067
  return new Promise((resolve3, _reject) => {
3910
4068
  let cwd = options.cwd;
3911
4069
  let env = options.env;
3912
- let maxBuffer = getOr(options.maxBuffer, 52428800);
3913
4070
  Nodechild_process.exec(command, {
3914
4071
  cwd,
3915
4072
  env,
@@ -3943,108 +4100,123 @@ function spawnPromise(command, args, options) {
3943
4100
  return new Promise((resolve3, _reject) => {
3944
4101
  let cwd = options.cwd;
3945
4102
  let env = options.env;
3946
- let proc = Nodechild_process.spawn(command, args, {
3947
- cwd,
3948
- env
3949
- });
3950
- let stdoutChunks = {
3951
- contents: []
3952
- };
3953
- let stderrChunks = {
3954
- contents: []
3955
- };
3956
- let stdoutLen = {
3957
- contents: 0
3958
- };
3959
- let stderrLen = {
3960
- contents: 0
3961
- };
3962
- let resolved = {
3963
- contents: false
3964
- };
3965
- let guardedResolve = (value) => {
3966
- if (resolved.contents) {
3967
- return;
3968
- } else {
3969
- resolved.contents = true;
3970
- return resolve3(value);
3971
- }
3972
- };
3973
- proc.stdout.on("data", (chunk) => {
3974
- if (resolved.contents) {
3975
- return;
3976
- } else {
3977
- stdoutChunks.contents.push(chunk);
3978
- stdoutLen.contents = stdoutLen.contents + chunk.byteLength | 0;
3979
- if (stdoutLen.contents > maxBuffer) {
3980
- proc.kill("SIGTERM");
3981
- return guardedResolve({
3982
- TAG: "Error",
3983
- _0: {
3984
- code: void 0,
3985
- stdout: Nodebuffer.Buffer.concat(stdoutChunks.contents).toString("utf8"),
3986
- stderr: Nodebuffer.Buffer.concat(stderrChunks.contents).toString("utf8"),
3987
- message: "stdout maxBuffer exceeded"
3988
- }
3989
- });
4103
+ try {
4104
+ let proc = Nodechild_process.spawn(command, args, {
4105
+ cwd,
4106
+ env
4107
+ });
4108
+ let stdoutChunks = {
4109
+ contents: []
4110
+ };
4111
+ let stderrChunks = {
4112
+ contents: []
4113
+ };
4114
+ let stdoutLen = {
4115
+ contents: 0
4116
+ };
4117
+ let stderrLen = {
4118
+ contents: 0
4119
+ };
4120
+ let resolved = {
4121
+ contents: false
4122
+ };
4123
+ let guardedResolve = (value) => {
4124
+ if (resolved.contents) {
4125
+ return;
3990
4126
  } else {
4127
+ resolved.contents = true;
4128
+ return resolve3(value);
4129
+ }
4130
+ };
4131
+ proc.stdout.on("data", (chunk) => {
4132
+ if (resolved.contents) {
3991
4133
  return;
4134
+ } else {
4135
+ stdoutChunks.contents.push(chunk);
4136
+ stdoutLen.contents = stdoutLen.contents + chunk.byteLength | 0;
4137
+ if (stdoutLen.contents > maxBuffer) {
4138
+ proc.kill("SIGTERM");
4139
+ return guardedResolve({
4140
+ TAG: "Error",
4141
+ _0: {
4142
+ code: void 0,
4143
+ stdout: Nodebuffer.Buffer.concat(stdoutChunks.contents).toString("utf8"),
4144
+ stderr: Nodebuffer.Buffer.concat(stderrChunks.contents).toString("utf8"),
4145
+ message: "stdout maxBuffer exceeded"
4146
+ }
4147
+ });
4148
+ } else {
4149
+ return;
4150
+ }
3992
4151
  }
3993
- }
3994
- });
3995
- proc.stderr.on("data", (chunk) => {
3996
- if (resolved.contents) {
3997
- return;
3998
- } else {
3999
- stderrChunks.contents.push(chunk);
4000
- stderrLen.contents = stderrLen.contents + chunk.byteLength | 0;
4001
- if (stderrLen.contents > maxBuffer) {
4002
- proc.kill("SIGTERM");
4152
+ });
4153
+ proc.stderr.on("data", (chunk) => {
4154
+ if (resolved.contents) {
4155
+ return;
4156
+ } else {
4157
+ stderrChunks.contents.push(chunk);
4158
+ stderrLen.contents = stderrLen.contents + chunk.byteLength | 0;
4159
+ if (stderrLen.contents > maxBuffer) {
4160
+ proc.kill("SIGTERM");
4161
+ return guardedResolve({
4162
+ TAG: "Error",
4163
+ _0: {
4164
+ code: void 0,
4165
+ stdout: Nodebuffer.Buffer.concat(stdoutChunks.contents).toString("utf8"),
4166
+ stderr: Nodebuffer.Buffer.concat(stderrChunks.contents).toString("utf8"),
4167
+ message: "stderr maxBuffer exceeded"
4168
+ }
4169
+ });
4170
+ } else {
4171
+ return;
4172
+ }
4173
+ }
4174
+ });
4175
+ proc.on("error", (err) => guardedResolve({
4176
+ TAG: "Error",
4177
+ _0: {
4178
+ code: void 0,
4179
+ stdout: Nodebuffer.Buffer.concat(stdoutChunks.contents).toString("utf8"),
4180
+ stderr: Nodebuffer.Buffer.concat(stderrChunks.contents).toString("utf8"),
4181
+ message: err.message
4182
+ }
4183
+ }));
4184
+ proc.on("close", (nullableCode) => {
4185
+ let code = nullableCode == null ? void 0 : some(nullableCode);
4186
+ if (!(nullableCode == null) && nullableCode === 0) {
4003
4187
  return guardedResolve({
4004
- TAG: "Error",
4188
+ TAG: "Ok",
4005
4189
  _0: {
4006
- code: void 0,
4007
4190
  stdout: Nodebuffer.Buffer.concat(stdoutChunks.contents).toString("utf8"),
4008
- stderr: Nodebuffer.Buffer.concat(stderrChunks.contents).toString("utf8"),
4009
- message: "stderr maxBuffer exceeded"
4191
+ stderr: Nodebuffer.Buffer.concat(stderrChunks.contents).toString("utf8")
4010
4192
  }
4011
4193
  });
4012
- } else {
4013
- return;
4014
4194
  }
4015
- }
4016
- });
4017
- proc.on("error", (err) => guardedResolve({
4018
- TAG: "Error",
4019
- _0: {
4020
- code: void 0,
4021
- stdout: Nodebuffer.Buffer.concat(stdoutChunks.contents).toString("utf8"),
4022
- stderr: Nodebuffer.Buffer.concat(stderrChunks.contents).toString("utf8"),
4023
- message: err.message
4024
- }
4025
- }));
4026
- proc.on("close", (nullableCode) => {
4027
- let code = nullableCode == null ? void 0 : some(nullableCode);
4028
- if (!(nullableCode == null) && nullableCode === 0) {
4029
- return guardedResolve({
4030
- TAG: "Ok",
4195
+ let codeStr = nullableCode == null ? "null" : nullableCode.toString();
4196
+ guardedResolve({
4197
+ TAG: "Error",
4031
4198
  _0: {
4199
+ code,
4032
4200
  stdout: Nodebuffer.Buffer.concat(stdoutChunks.contents).toString("utf8"),
4033
- stderr: Nodebuffer.Buffer.concat(stderrChunks.contents).toString("utf8")
4201
+ stderr: Nodebuffer.Buffer.concat(stderrChunks.contents).toString("utf8"),
4202
+ message: `Process exited with code ` + codeStr
4034
4203
  }
4035
4204
  });
4036
- }
4037
- let codeStr = nullableCode == null ? "null" : nullableCode.toString();
4038
- guardedResolve({
4205
+ });
4206
+ return;
4207
+ } catch (raw_exn) {
4208
+ let exn = internalToException(raw_exn);
4209
+ let msg = getOr(flatMap(fromException(exn), message2), "spawn failed");
4210
+ return resolve3({
4039
4211
  TAG: "Error",
4040
4212
  _0: {
4041
- code,
4042
- stdout: Nodebuffer.Buffer.concat(stdoutChunks.contents).toString("utf8"),
4043
- stderr: Nodebuffer.Buffer.concat(stderrChunks.contents).toString("utf8"),
4044
- message: `Process exited with code ` + codeStr
4213
+ code: void 0,
4214
+ stdout: "",
4215
+ stderr: "",
4216
+ message: msg
4045
4217
  }
4046
4218
  });
4047
- });
4219
+ }
4048
4220
  });
4049
4221
  }
4050
4222
  async function execWithOptions(command, options) {
@@ -4070,7 +4242,8 @@ var ToolNames = {
4070
4242
  grep: "grep",
4071
4243
  fileExists: "file_exists",
4072
4244
  loadAgentInstructions: "load_agent_instructions",
4073
- lighthouse: "lighthouse"};
4245
+ lighthouse: "lighthouse",
4246
+ listTree: "list_tree"};
4074
4247
 
4075
4248
  // ../frontman-core/src/tools/FrontmanCore__Tool__Grep.res.mjs
4076
4249
  var name6 = ToolNames.grep;
@@ -4229,15 +4402,40 @@ async function executeRipgrep(rgPath, pattern2, searchPath, type_, glob, caseIns
4229
4402
  }
4230
4403
  async function executeGitGrep(pattern2, searchPath, caseInsensitive, literal3, maxResults, glob, type_) {
4231
4404
  let args = buildGitGrepArgs(pattern2, caseInsensitive, literal3, maxResults, glob, type_);
4232
- let result = await spawnResult("git", args, searchPath);
4405
+ let match;
4406
+ try {
4407
+ let stats = await Fs7.promises.stat(searchPath);
4408
+ match = stats.isFile() ? [
4409
+ Nodepath5.dirname(searchPath),
4410
+ Nodepath5.basename(searchPath)
4411
+ ] : [
4412
+ searchPath,
4413
+ void 0
4414
+ ];
4415
+ } catch (exn) {
4416
+ match = [
4417
+ searchPath,
4418
+ void 0
4419
+ ];
4420
+ }
4421
+ let filePathspec = match[1];
4422
+ if (filePathspec !== void 0) {
4423
+ if (args.includes("--")) {
4424
+ args.push(filePathspec);
4425
+ } else {
4426
+ args.push("--");
4427
+ args.push(filePathspec);
4428
+ }
4429
+ }
4430
+ let result = await spawnResult("git", args, match[0]);
4233
4431
  if (result.TAG === "Ok") {
4234
4432
  return {
4235
4433
  TAG: "Ok",
4236
4434
  _0: parseGrepOutput(result._0.stdout, maxResults)
4237
4435
  };
4238
4436
  }
4239
- let match = result._0;
4240
- let code = match.code;
4437
+ let match$1 = result._0;
4438
+ let code = match$1.code;
4241
4439
  if (code === 1) {
4242
4440
  return {
4243
4441
  TAG: "Ok",
@@ -4248,9 +4446,9 @@ async function executeGitGrep(pattern2, searchPath, caseInsensitive, literal3, m
4248
4446
  }
4249
4447
  };
4250
4448
  }
4251
- let stderr = match.stderr;
4449
+ let stderr = match$1.stderr;
4252
4450
  let codeStr = getOr(map(code, (c2) => c2.toString()), "unknown");
4253
- let detail = stderr === "" ? match.message : stderr;
4451
+ let detail = stderr === "" ? match$1.message : stderr;
4254
4452
  return {
4255
4453
  TAG: "Error",
4256
4454
  _0: `Git grep failed (exit ` + codeStr + `): ` + detail
@@ -4335,56 +4533,465 @@ async function execute5(ctx2, input) {
4335
4533
  return await gitGrepWithFallback();
4336
4534
  }
4337
4535
  }
4338
- var description5 = `Fast content search tool that finds files containing specific text or patterns, returning matching lines sorted by file modification time.
4536
+ var description5 = `Searches **file contents** for text or regex patterns. Returns matching lines with file paths and line numbers.
4339
4537
 
4340
- WHEN TO USE THIS TOOL:
4341
- - Use when you need to find files containing specific text or patterns
4342
- - Great for searching code bases for function names, variable declarations, or error messages
4343
- - Useful for finding all files that use a particular API or pattern
4538
+ Use grep to find where code is *used* \u2014 function calls, variable references, imports, error messages, string literals. If you need to find a file by *name* instead, use search_files.
4344
4539
 
4345
4540
  PARAMETERS:
4346
- - pattern (required): The text or regex pattern to search for
4347
- - path (optional): Directory to search in (defaults to source root)
4348
- - type (optional): File type filter (e.g., "js", "ts", "py", "go")
4349
- - glob (optional): Glob pattern to filter files (e.g., "*.js", "*.{ts,tsx}")
4541
+ - pattern (required): Text or regex to search for inside files
4542
+ - path (optional): Directory or file to search in (defaults to source root). When a file path is given, only that file is searched.
4543
+ - type (optional): File type filter (e.g., "js", "ts", "py")
4544
+ - glob (optional): Glob pattern to filter files (e.g., "*.tsx", "*.{ts,tsx}")
4350
4545
  - case_insensitive (optional): Case insensitive search (default: false)
4351
4546
  - literal (optional): Treat pattern as literal text, not regex (default: false)
4352
4547
  - max_results (optional): Maximum number of results to return (default: 20)
4353
4548
 
4354
4549
  EXAMPLES:
4355
- - Find "function" in JavaScript files: pattern="function", type="js"
4356
- - Find imports: pattern="import.*from", glob="*.ts"
4357
- - Case-insensitive search: pattern="error", case_insensitive=true
4358
- - Literal search: pattern="log.error()", literal=true
4550
+ - Find where useState is called: pattern="useState"
4551
+ - Find API routes: pattern="app\\.(get|post|put)", glob="*.ts"
4552
+ - Search within one file: pattern="className", path="src/components/Button.tsx"
4553
+ - Literal dot search: pattern="console.log(", literal=true
4359
4554
 
4360
4555
  OUTPUT:
4361
- Returns matching lines grouped by file, with line numbers and content.
4362
- Results are sorted by file modification time (newest first).
4556
+ Matching lines grouped by file, with line numbers. Sorted by file modification time (newest first).
4363
4557
 
4364
4558
  LIMITATIONS:
4365
- - Results limited to max_results (default 20)
4366
- - Binary files are automatically skipped
4367
- - Hidden files (starting with '.') are skipped by default`;
4368
- var name7 = ToolNames.readFile;
4369
- var inputSchema6 = schema2((s2) => ({
4370
- path: s2.m(string2),
4371
- offset: s2.m(option2(int2)),
4372
- limit: s2.m(option2(int2))
4373
- }));
4374
- var pathContextSchema2 = schema2((s2) => ({
4375
- sourceRoot: s2.m(string2),
4376
- resolvedPath: s2.m(string2),
4377
- relativePath: s2.m(string2)
4378
- }));
4379
- var outputSchema6 = schema2((s2) => ({
4380
- content: s2.m(string2),
4381
- totalLines: s2.m(int2),
4382
- hasMore: s2.m(bool2),
4383
- _context: s2.m(option2(pathContextSchema2))
4384
- }));
4385
- async function execute6(ctx2, input) {
4386
- let offset = getOr(input.offset, 0);
4387
- let limit = getOr(input.limit, 500);
4559
+ - Results capped at max_results (default 20) files
4560
+ - Binary files and hidden files (dotfiles) are skipped`;
4561
+
4562
+ // ../../node_modules/@rescript/runtime/lib/es6/Stdlib_JSON.js
4563
+ function bool3(json3) {
4564
+ if (typeof json3 === "boolean") {
4565
+ return json3;
4566
+ }
4567
+ }
4568
+ function $$null2(json3) {
4569
+ if (json3 === null) {
4570
+ return null;
4571
+ }
4572
+ }
4573
+ function string3(json3) {
4574
+ if (typeof json3 === "string") {
4575
+ return json3;
4576
+ }
4577
+ }
4578
+ function float3(json3) {
4579
+ if (typeof json3 === "number") {
4580
+ return json3;
4581
+ }
4582
+ }
4583
+ function object2(json3) {
4584
+ if (typeof json3 === "object" && json3 !== null && !Array.isArray(json3)) {
4585
+ return json3;
4586
+ }
4587
+ }
4588
+ function array3(json3) {
4589
+ if (Array.isArray(json3)) {
4590
+ return json3;
4591
+ }
4592
+ }
4593
+ var Decode = {
4594
+ bool: bool3,
4595
+ $$null: $$null2,
4596
+ string: string3,
4597
+ float: float3,
4598
+ object: object2,
4599
+ array: array3
4600
+ };
4601
+
4602
+ // ../../node_modules/@rescript/runtime/lib/es6/Primitive_string.js
4603
+ function compare(s1, s2) {
4604
+ if (s1 === s2) {
4605
+ return 0;
4606
+ } else if (s1 < s2) {
4607
+ return -1;
4608
+ } else {
4609
+ return 1;
4610
+ }
4611
+ }
4612
+ async function pathExists(path) {
4613
+ try {
4614
+ await Fs7.promises.access(path);
4615
+ return true;
4616
+ } catch (exn) {
4617
+ return false;
4618
+ }
4619
+ }
4620
+
4621
+ // ../frontman-core/src/tools/FrontmanCore__Tool__ListTree.res.mjs
4622
+ var name7 = ToolNames.listTree;
4623
+ var inputSchema6 = schema2((s2) => ({
4624
+ path: s2.m(option2(string2)),
4625
+ depth: s2.m(option2(int2))
4626
+ }));
4627
+ var workspaceSchema = schema2((s2) => ({
4628
+ name: s2.m(string2),
4629
+ path: s2.m(string2)
4630
+ }));
4631
+ var outputSchema6 = schema2((s2) => ({
4632
+ tree: s2.m(string2),
4633
+ workspaces: s2.m(array2(workspaceSchema)),
4634
+ monorepoType: s2.m(option2(string2))
4635
+ }));
4636
+ var packageJsonNameSchema = schema2((s2) => ({
4637
+ name: s2.m(option2(string2))
4638
+ }));
4639
+ var packageJsonWorkspacesObjSchema = schema2((s2) => ({
4640
+ packages: s2.m(option2(array2(string2)))
4641
+ }));
4642
+ var noiseDirs = [
4643
+ "node_modules",
4644
+ ".git",
4645
+ "dist",
4646
+ "build",
4647
+ ".next",
4648
+ "_build",
4649
+ "deps",
4650
+ ".turbo",
4651
+ ".cache",
4652
+ "coverage",
4653
+ ".svelte-kit",
4654
+ ".output",
4655
+ ".nuxt",
4656
+ ".vercel",
4657
+ "__pycache__",
4658
+ "target"
4659
+ ];
4660
+ function makeTrieNode(name15) {
4661
+ return {
4662
+ name: name15,
4663
+ children: {
4664
+ contents: {}
4665
+ },
4666
+ isFile: {
4667
+ contents: false
4668
+ }
4669
+ };
4670
+ }
4671
+ function buildTrie(files) {
4672
+ let root_children = {
4673
+ contents: {}
4674
+ };
4675
+ let root_isFile = {
4676
+ contents: false
4677
+ };
4678
+ let root = {
4679
+ name: ".",
4680
+ children: root_children,
4681
+ isFile: root_isFile
4682
+ };
4683
+ files.forEach((filePath) => {
4684
+ let parts = filePath.split("/").filter((p2) => p2 !== "");
4685
+ let current = {
4686
+ contents: root
4687
+ };
4688
+ parts.forEach((part, idx) => {
4689
+ let isLast = idx === (parts.length - 1 | 0);
4690
+ let existing = current.contents.children.contents[part];
4691
+ if (existing !== void 0) {
4692
+ if (isLast) {
4693
+ existing.isFile.contents = true;
4694
+ }
4695
+ current.contents = existing;
4696
+ return;
4697
+ }
4698
+ let node = makeTrieNode(part);
4699
+ if (isLast) {
4700
+ node.isFile.contents = true;
4701
+ }
4702
+ current.contents.children.contents[part] = node;
4703
+ current.contents = node;
4704
+ });
4705
+ });
4706
+ return root;
4707
+ }
4708
+ function getSortedChildren(node) {
4709
+ let entries = Object.entries(node.children.contents).map((param) => {
4710
+ let child = param[1];
4711
+ let hasChildren = Object.keys(child.children.contents).length !== 0;
4712
+ let isDir = hasChildren || !child.isFile.contents;
4713
+ return {
4714
+ entryName: param[0],
4715
+ node: child,
4716
+ isDir
4717
+ };
4718
+ }).filter((e) => !noiseDirs.includes(e.entryName));
4719
+ return entries.toSorted((a, b) => {
4720
+ let match = a.isDir;
4721
+ let match$1 = b.isDir;
4722
+ if (match) {
4723
+ if (!match$1) {
4724
+ return -1;
4725
+ }
4726
+ } else if (match$1) {
4727
+ return 1;
4728
+ }
4729
+ let n = compare(a.entryName, b.entryName);
4730
+ if (n < 0) {
4731
+ return -1;
4732
+ } else if (n > 0) {
4733
+ return 1;
4734
+ } else {
4735
+ return 0;
4736
+ }
4737
+ });
4738
+ }
4739
+ function renderTree(root, maxDepth, workspacePaths) {
4740
+ let lines = [];
4741
+ let walk = (node, prefix, currentDepth, parentPath) => {
4742
+ if (currentDepth > maxDepth) {
4743
+ return;
4744
+ }
4745
+ let children = getSortedChildren(node);
4746
+ let totalCount = children.length;
4747
+ let truncated = totalCount > 15;
4748
+ let visibleChildren = truncated ? children.slice(0, 10) : children;
4749
+ let visibleCount = visibleChildren.length;
4750
+ visibleChildren.forEach((entry, idx) => {
4751
+ let isLastVisible = idx === (visibleCount - 1 | 0) && !truncated;
4752
+ let connector = isLastVisible ? `\u2514\u2500\u2500 ` : `\u251C\u2500\u2500 `;
4753
+ let childPrefix = isLastVisible ? prefix + " " : prefix + `\u2502 `;
4754
+ let suffix = entry.isDir ? "/" : "";
4755
+ let entryRelPath = parentPath !== void 0 ? parentPath + "/" + entry.entryName : entry.entryName;
4756
+ let workspaceAnnotation;
4757
+ if (entry.isDir) {
4758
+ let wsName = workspacePaths[entryRelPath];
4759
+ workspaceAnnotation = wsName !== void 0 ? ` [workspace: ` + wsName + `]` : "";
4760
+ } else {
4761
+ workspaceAnnotation = "";
4762
+ }
4763
+ lines.push(prefix + connector + entry.entryName + suffix + workspaceAnnotation);
4764
+ if (entry.isDir) {
4765
+ return walk(entry.node, childPrefix, currentDepth + 1 | 0, entryRelPath);
4766
+ }
4767
+ });
4768
+ if (!truncated) {
4769
+ return;
4770
+ }
4771
+ let remaining = totalCount - 10 | 0;
4772
+ lines.push(prefix + (`\u2514\u2500\u2500 ... and ` + remaining.toString() + ` more entries`));
4773
+ };
4774
+ lines.push(".");
4775
+ walk(root, "", 1, void 0);
4776
+ return lines.join("\n");
4777
+ }
4778
+ function buildWorkspacePathLookup(workspaces) {
4779
+ let lookup = {};
4780
+ workspaces.forEach((ws) => {
4781
+ lookup[ws.path] = ws.name;
4782
+ });
4783
+ return lookup;
4784
+ }
4785
+ async function readJsonFile(path) {
4786
+ try {
4787
+ let content = await Fs7.promises.readFile(path, "utf8");
4788
+ return {
4789
+ TAG: "Ok",
4790
+ _0: JSON.parse(content)
4791
+ };
4792
+ } catch (raw_exn) {
4793
+ let exn = internalToException(raw_exn);
4794
+ let msg = getOr(flatMap(fromException(exn), message2), "Unknown error");
4795
+ return {
4796
+ TAG: "Error",
4797
+ _0: `Failed to read/parse ` + path + `: ` + msg
4798
+ };
4799
+ }
4800
+ }
4801
+ async function readPackageName(dirPath) {
4802
+ let pkgPath = Nodepath5.join(dirPath, "package.json");
4803
+ let json3 = await readJsonFile(pkgPath);
4804
+ if (json3.TAG !== "Ok") {
4805
+ return;
4806
+ }
4807
+ try {
4808
+ return parseOrThrow2(json3._0, packageJsonNameSchema).name;
4809
+ } catch (exn) {
4810
+ return;
4811
+ }
4812
+ }
4813
+ function extractWorkspaceGlobs(json3) {
4814
+ let obj = Decode.object(json3);
4815
+ if (obj === void 0) {
4816
+ return;
4817
+ }
4818
+ let wsJson = obj["workspaces"];
4819
+ if (wsJson === void 0) {
4820
+ return;
4821
+ }
4822
+ try {
4823
+ return parseOrThrow2(wsJson, array2(string2));
4824
+ } catch (exn) {
4825
+ try {
4826
+ return parseOrThrow2(wsJson, packageJsonWorkspacesObjSchema).packages;
4827
+ } catch (exn$1) {
4828
+ return;
4829
+ }
4830
+ }
4831
+ }
4832
+ async function resolveWorkspaceGlobs(rootPath, globs) {
4833
+ let results = [];
4834
+ await Promise.all(globs.map(async (glob) => {
4835
+ if (glob.endsWith("/*")) {
4836
+ let parentDir = glob.slice(0, glob.length - 2 | 0);
4837
+ let fullParent = Nodepath5.join(rootPath, parentDir);
4838
+ try {
4839
+ let entries = await Fs7.promises.readdir(fullParent);
4840
+ await Promise.all(entries.map(async (entry) => {
4841
+ let entryPath = Nodepath5.join(fullParent, entry);
4842
+ let stats = await Fs7.promises.stat(entryPath);
4843
+ if (stats.isDirectory()) {
4844
+ results.push(parentDir + "/" + entry);
4845
+ return;
4846
+ }
4847
+ }));
4848
+ return;
4849
+ } catch (raw_exn) {
4850
+ let exn = internalToException(raw_exn);
4851
+ let msg = getOr(flatMap(fromException(exn), message2), "Unknown error");
4852
+ console.warn(`ListTree: failed to resolve workspace glob "` + glob + `": ` + msg);
4853
+ return;
4854
+ }
4855
+ } else {
4856
+ let fullPath = Nodepath5.join(rootPath, glob);
4857
+ if (await pathExists(fullPath)) {
4858
+ results.push(glob);
4859
+ return;
4860
+ } else {
4861
+ return;
4862
+ }
4863
+ }
4864
+ }));
4865
+ return results;
4866
+ }
4867
+ async function detectMonorepo(rootPath) {
4868
+ let pkgJsonResult = await readJsonFile(Nodepath5.join(rootPath, "package.json"));
4869
+ let workspaceGlobs;
4870
+ workspaceGlobs = pkgJsonResult.TAG === "Ok" ? extractWorkspaceGlobs(pkgJsonResult._0) : void 0;
4871
+ let hasTurbo = await pathExists(Nodepath5.join(rootPath, "turbo.json"));
4872
+ let hasNx = await pathExists(Nodepath5.join(rootPath, "nx.json"));
4873
+ let hasPnpmWorkspace = await pathExists(Nodepath5.join(rootPath, "pnpm-workspace.yaml"));
4874
+ let monorepoType = hasTurbo ? "turborepo" : hasNx ? "nx" : hasPnpmWorkspace ? "pnpm-workspaces" : workspaceGlobs !== void 0 ? "npm-workspaces" : void 0;
4875
+ let workspaces;
4876
+ if (workspaceGlobs !== void 0) {
4877
+ let resolvedPaths = await resolveWorkspaceGlobs(rootPath, workspaceGlobs);
4878
+ workspaces = await Promise.all(resolvedPaths.map(async (wsPath) => {
4879
+ let fullPath = Nodepath5.join(rootPath, wsPath);
4880
+ let n = await readPackageName(fullPath);
4881
+ let name15 = n !== void 0 ? n : wsPath;
4882
+ return {
4883
+ name: name15,
4884
+ path: wsPath
4885
+ };
4886
+ }));
4887
+ } else {
4888
+ workspaces = [];
4889
+ }
4890
+ return {
4891
+ monorepoType,
4892
+ workspaces
4893
+ };
4894
+ }
4895
+ async function getTrackedFiles(cwd) {
4896
+ let result = await spawnResult("git", ["ls-files"], cwd);
4897
+ if (result.TAG === "Ok") {
4898
+ let lines = result._0.stdout.trim().split("\n").filter((line) => line !== "");
4899
+ return {
4900
+ TAG: "Ok",
4901
+ _0: lines
4902
+ };
4903
+ }
4904
+ let match = result._0;
4905
+ let match$1 = match.code;
4906
+ if (match$1 === 128) {
4907
+ return {
4908
+ TAG: "Error",
4909
+ _0: `Not a git repository: ` + match.stderr
4910
+ };
4911
+ }
4912
+ return {
4913
+ TAG: "Error",
4914
+ _0: `git ls-files failed: ` + match.stderr
4915
+ };
4916
+ }
4917
+ async function execute6(ctx2, input) {
4918
+ let path = getOr(input.path, ".");
4919
+ let maxDepth = getOr(input.depth, 3);
4920
+ let err = resolve2(ctx2.sourceRoot, path);
4921
+ if (err.TAG !== "Ok") {
4922
+ return {
4923
+ TAG: "Error",
4924
+ _0: formatError(err._0)
4925
+ };
4926
+ }
4927
+ let result = err._0;
4928
+ try {
4929
+ let fullPath;
4930
+ try {
4931
+ let stats = await Fs7.promises.stat(result.resolvedPath);
4932
+ fullPath = stats.isFile() ? Nodepath5.dirname(result.resolvedPath) : result.resolvedPath;
4933
+ } catch (exn) {
4934
+ fullPath = result.resolvedPath;
4935
+ }
4936
+ let filesResult = await getTrackedFiles(fullPath);
4937
+ let files;
4938
+ if (filesResult.TAG === "Ok") {
4939
+ files = filesResult._0;
4940
+ } else {
4941
+ console.warn(`ListTree: ` + filesResult._0 + `, falling back to readdir`);
4942
+ files = await Fs7.promises.readdir(fullPath);
4943
+ }
4944
+ let trie = buildTrie(files);
4945
+ let monoInfo = await detectMonorepo(fullPath);
4946
+ let workspacePaths = buildWorkspacePathLookup(monoInfo.workspaces);
4947
+ let tree = renderTree(trie, maxDepth, workspacePaths);
4948
+ return {
4949
+ TAG: "Ok",
4950
+ _0: {
4951
+ tree,
4952
+ workspaces: monoInfo.workspaces,
4953
+ monorepoType: monoInfo.monorepoType
4954
+ }
4955
+ };
4956
+ } catch (raw_exn) {
4957
+ let exn$1 = internalToException(raw_exn);
4958
+ let msg = getOr(flatMap(fromException(exn$1), message2), "Unknown error");
4959
+ return {
4960
+ TAG: "Error",
4961
+ _0: `Failed to list tree for ` + path + `: ` + msg
4962
+ };
4963
+ }
4964
+ }
4965
+ var description6 = `Returns a **recursive directory tree** of the project structure, with monorepo workspace detection.
4966
+
4967
+ Use list_tree to get oriented in a codebase, understand the layout, or explore a subtree. Prefer this over chaining multiple list_files calls. For a flat listing of one directory, use list_files instead.
4968
+
4969
+ PARAMETERS:
4970
+ - path (optional): Subdirectory to root the tree at. Defaults to "." (project root). If a file path is given, shows the tree from its parent directory.
4971
+ - depth (optional): Maximum directory depth to display. Defaults to 3.
4972
+
4973
+ OUTPUT:
4974
+ Text tree with directories (ending in /) and files. Workspace roots are annotated with [workspace: name]. Respects .gitignore. Skips node_modules, .git, dist, build, etc.`;
4975
+ var name8 = ToolNames.readFile;
4976
+ var inputSchema7 = schema2((s2) => ({
4977
+ path: s2.m(string2),
4978
+ offset: s2.m(option2(int2)),
4979
+ limit: s2.m(option2(int2))
4980
+ }));
4981
+ var pathContextSchema2 = schema2((s2) => ({
4982
+ sourceRoot: s2.m(string2),
4983
+ resolvedPath: s2.m(string2),
4984
+ relativePath: s2.m(string2)
4985
+ }));
4986
+ var outputSchema7 = schema2((s2) => ({
4987
+ content: s2.m(string2),
4988
+ totalLines: s2.m(int2),
4989
+ hasMore: s2.m(bool2),
4990
+ _context: s2.m(option2(pathContextSchema2))
4991
+ }));
4992
+ async function execute7(ctx2, input) {
4993
+ let offset = getOr(input.offset, 0);
4994
+ let limit = getOr(input.limit, 500);
4388
4995
  let err = resolve2(ctx2.sourceRoot, input.path);
4389
4996
  if (err.TAG !== "Ok") {
4390
4997
  return {
@@ -4394,13 +5001,13 @@ async function execute6(ctx2, input) {
4394
5001
  }
4395
5002
  let result = err._0;
4396
5003
  try {
4397
- let content = await Fs.promises.readFile(result.resolvedPath, "utf8");
5004
+ let content = await Fs7.promises.readFile(result.resolvedPath, "utf8");
4398
5005
  let lines = content.split("\n");
4399
5006
  let totalLines = lines.length;
4400
5007
  let selectedLines = lines.slice(offset, offset + limit | 0);
4401
5008
  let selectedContent = selectedLines.join("\n");
4402
5009
  let hasMore = (offset + limit | 0) < totalLines;
4403
- recordRead(result.resolvedPath);
5010
+ recordRead(result.resolvedPath, offset, limit, totalLines);
4404
5011
  return {
4405
5012
  TAG: "Ok",
4406
5013
  _0: {
@@ -4423,7 +5030,7 @@ async function execute6(ctx2, input) {
4423
5030
  };
4424
5031
  }
4425
5032
  }
4426
- var description6 = `Reads a file from the filesystem.
5033
+ var description7 = `Reads a file from the filesystem.
4427
5034
 
4428
5035
  Parameters:
4429
5036
  - path (required): Path to file - either relative to source root or absolute (must be under source root)
@@ -4431,7 +5038,12 @@ Parameters:
4431
5038
  - limit (optional): Maximum lines to read (default: 500). Pass null or 500 for default.
4432
5039
 
4433
5040
  Returns file content with metadata about total lines and whether more content exists.
4434
- The _context field provides path resolution details for debugging.`;
5041
+ The _context field provides path resolution details for debugging.
5042
+
5043
+ When hasMore is true, the file has content beyond what was returned. For large files:
5044
+ - Use grep first to find the line numbers of relevant sections, then read_file with a targeted offset.
5045
+ - Don't read sequentially from the top \u2014 jump to the section you need.
5046
+ - For React/Vue/Astro components, locate the render/return block before editing.`;
4435
5047
 
4436
5048
  // ../../node_modules/@rescript/runtime/lib/es6/Stdlib_Result.js
4437
5049
  function map3(opt, f) {
@@ -4446,8 +5058,8 @@ function map3(opt, f) {
4446
5058
  }
4447
5059
 
4448
5060
  // ../frontman-core/src/tools/FrontmanCore__Tool__ListFiles.res.mjs
4449
- var name8 = ToolNames.listFiles;
4450
- var inputSchema7 = schema2((s2) => ({
5061
+ var name9 = ToolNames.listFiles;
5062
+ var inputSchema8 = schema2((s2) => ({
4451
5063
  path: s2.m(option2(string2))
4452
5064
  }));
4453
5065
  var fileEntrySchema = schema2((s2) => ({
@@ -4456,7 +5068,7 @@ var fileEntrySchema = schema2((s2) => ({
4456
5068
  isFile: s2.m(bool2),
4457
5069
  isDirectory: s2.m(bool2)
4458
5070
  }));
4459
- var outputSchema7 = array2(fileEntrySchema);
5071
+ var outputSchema8 = array2(fileEntrySchema);
4460
5072
  async function getIgnoredEntries(cwd, entries) {
4461
5073
  if (entries.length === 0) {
4462
5074
  return {
@@ -4511,7 +5123,7 @@ async function getIgnoredEntries(cwd, entries) {
4511
5123
  };
4512
5124
  }
4513
5125
  }
4514
- async function execute7(ctx2, input) {
5126
+ async function execute8(ctx2, input) {
4515
5127
  let path = getOr(input.path, ".");
4516
5128
  let err = resolve2(ctx2.sourceRoot, path);
4517
5129
  if (err.TAG !== "Ok") {
@@ -4520,22 +5132,40 @@ async function execute7(ctx2, input) {
4520
5132
  _0: formatError(err._0)
4521
5133
  };
4522
5134
  }
5135
+ let result = err._0;
4523
5136
  try {
4524
- let fullPath = err._0.resolvedPath;
4525
- let entries = await Fs.promises.readdir(fullPath);
4526
- let filteredEntriesResult = map3(await getIgnoredEntries(fullPath, entries), (ignored) => entries.filter((name14) => !ignored.includes(name14)));
5137
+ let match;
5138
+ try {
5139
+ let stats = await Fs7.promises.stat(result.resolvedPath);
5140
+ match = stats.isFile() ? [
5141
+ Nodepath5.dirname(result.resolvedPath),
5142
+ Nodepath5.dirname(path)
5143
+ ] : [
5144
+ result.resolvedPath,
5145
+ path
5146
+ ];
5147
+ } catch (exn) {
5148
+ match = [
5149
+ result.resolvedPath,
5150
+ path
5151
+ ];
5152
+ }
5153
+ let relativePath = match[1];
5154
+ let fullPath = match[0];
5155
+ let entries = await Fs7.promises.readdir(fullPath);
5156
+ let filteredEntriesResult = map3(await getIgnoredEntries(fullPath, entries), (ignored) => entries.filter((name15) => !ignored.includes(name15)));
4527
5157
  if (filteredEntriesResult.TAG !== "Ok") {
4528
5158
  return {
4529
5159
  TAG: "Error",
4530
5160
  _0: filteredEntriesResult._0
4531
5161
  };
4532
5162
  }
4533
- let entriesWithStats = await Promise.all(filteredEntriesResult._0.map(async (name14) => {
4534
- let entryPath = Nodepath.join(fullPath, name14);
4535
- let stats = await Fs.promises.stat(entryPath);
5163
+ let entriesWithStats = await Promise.all(filteredEntriesResult._0.map(async (name15) => {
5164
+ let entryPath = Nodepath5.join(fullPath, name15);
5165
+ let stats = await Fs7.promises.stat(entryPath);
4536
5166
  return {
4537
- name: name14,
4538
- path: Nodepath.join(path, name14),
5167
+ name: name15,
5168
+ path: Nodepath5.join(relativePath, name15),
4539
5169
  isFile: stats.isFile(),
4540
5170
  isDirectory: stats.isDirectory()
4541
5171
  };
@@ -4545,22 +5175,25 @@ async function execute7(ctx2, input) {
4545
5175
  _0: entriesWithStats
4546
5176
  };
4547
5177
  } catch (raw_exn) {
4548
- let exn = internalToException(raw_exn);
4549
- let msg = getOr(flatMap(fromException(exn), message2), "Unknown error");
5178
+ let exn$1 = internalToException(raw_exn);
5179
+ let msg = getOr(flatMap(fromException(exn$1), message2), "Unknown error");
4550
5180
  return {
4551
5181
  TAG: "Error",
4552
5182
  _0: `Failed to list files in ` + path + `: ` + msg
4553
5183
  };
4554
5184
  }
4555
5185
  }
4556
- var description7 = `Lists files and directories in a given path.
5186
+ var description8 = `Lists the **immediate contents** of a single directory \u2014 names, paths, and whether each entry is a file or directory.
4557
5187
 
4558
- Parameters:
4559
- - path (optional): Path to directory - either relative to source root or absolute (must be under source root). Defaults to "." (root directory).
5188
+ Use list_files to inspect one directory before reading or editing files. For a recursive multi-level tree, use list_tree instead. To find files by name across the project, use search_files.
4560
5189
 
4561
- Returns array of entries with name, path, and type information.`;
4562
- var name9 = ToolNames.writeFile;
4563
- var inputSchema8 = schema2((s2) => ({
5190
+ PARAMETERS:
5191
+ - path (optional): Directory to list (relative to source root or absolute). Defaults to "." (project root). If a file path is given, lists its parent directory.
5192
+
5193
+ OUTPUT:
5194
+ Array of entries, each with name, path, isFile, and isDirectory. Respects .gitignore \u2014 ignored entries are excluded.`;
5195
+ var name10 = ToolNames.writeFile;
5196
+ var inputSchema9 = schema2((s2) => ({
4564
5197
  path: s2.m(string2),
4565
5198
  content: s2.m(option2(string2)),
4566
5199
  image_ref: s2.m(option2(string2)),
@@ -4571,17 +5204,17 @@ var pathContextSchema3 = schema2((s2) => ({
4571
5204
  resolvedPath: s2.m(string2),
4572
5205
  relativePath: s2.m(string2)
4573
5206
  }));
4574
- var outputSchema8 = schema2((s2) => ({
5207
+ var outputSchema9 = schema2((s2) => ({
4575
5208
  _context: s2.m(option2(pathContextSchema3))
4576
5209
  }));
4577
5210
  function writeContent(resolvedPath, content, encoding) {
4578
5211
  if (encoding === void 0) {
4579
- return Fs.promises.writeFile(resolvedPath, content, "utf8");
5212
+ return Fs7.promises.writeFile(resolvedPath, content, "utf8");
4580
5213
  }
4581
5214
  let buffer = Nodebuffer.Buffer.from(content, "base64");
4582
- return Fs.promises.writeFile(resolvedPath, buffer);
5215
+ return Fs7.promises.writeFile(resolvedPath, buffer);
4583
5216
  }
4584
- async function execute8(ctx2, input) {
5217
+ async function execute9(ctx2, input) {
4585
5218
  let match = input.content;
4586
5219
  let match$1 = input.image_ref;
4587
5220
  if (match === void 0) {
@@ -4610,32 +5243,49 @@ async function execute8(ctx2, input) {
4610
5243
  _0: formatError(err._0)
4611
5244
  };
4612
5245
  }
4613
- let result = err._0;
5246
+ let resolved = err._0;
5247
+ let fileExists;
4614
5248
  try {
4615
- await Fs.promises.mkdir(dirname3(result), {
5249
+ await Fs7.promises.stat(resolved.resolvedPath);
5250
+ fileExists = true;
5251
+ } catch (exn) {
5252
+ fileExists = false;
5253
+ }
5254
+ let guardResult = fileExists ? await assertEditSafe(resolved.resolvedPath) : {
5255
+ TAG: "Ok",
5256
+ _0: void 0
5257
+ };
5258
+ if (guardResult.TAG !== "Ok") {
5259
+ return {
5260
+ TAG: "Error",
5261
+ _0: guardResult._0
5262
+ };
5263
+ }
5264
+ try {
5265
+ await Fs7.promises.mkdir(dirname4(resolved), {
4616
5266
  recursive: true
4617
5267
  });
4618
- await writeContent(result.resolvedPath, match, input.encoding);
5268
+ await writeContent(resolved.resolvedPath, match, input.encoding);
5269
+ recordWrite(resolved.resolvedPath);
4619
5270
  return {
4620
5271
  TAG: "Ok",
4621
5272
  _0: {
4622
5273
  _context: {
4623
- sourceRoot: result.sourceRoot,
4624
- resolvedPath: result.resolvedPath,
4625
- relativePath: result.relativePath
5274
+ sourceRoot: resolved.sourceRoot,
5275
+ resolvedPath: resolved.resolvedPath,
5276
+ relativePath: resolved.relativePath
4626
5277
  }
4627
5278
  }
4628
5279
  };
4629
5280
  } catch (raw_exn) {
4630
- let exn = internalToException(raw_exn);
4631
- let msg = getOr(flatMap(fromException(exn), message2), "Unknown error");
5281
+ let exn$1 = internalToException(raw_exn);
4632
5282
  return {
4633
5283
  TAG: "Error",
4634
- _0: `Failed to write file ` + input.path + `: ` + msg
5284
+ _0: `Failed to write file ` + input.path + `: ` + message3(exn$1)
4635
5285
  };
4636
5286
  }
4637
5287
  }
4638
- var description8 = `Writes content to a file.
5288
+ var description9 = `Writes content to a file.
4639
5289
 
4640
5290
  Parameters:
4641
5291
  - path (required): Path to file - either relative to source root or absolute (must be under source root)
@@ -4645,12 +5295,15 @@ Parameters:
4645
5295
 
4646
5296
  Provide either content OR image_ref, not both.
4647
5297
  Creates parent directories if they don't exist. Overwrites existing files.
4648
- The _context field provides path resolution details for debugging.`;
4649
- var name10 = ToolNames.fileExists;
4650
- var inputSchema9 = schema2((s2) => ({
5298
+
5299
+ IMPORTANT: If the file already exists, you MUST read it with read_file first. The tool will reject writes to existing files that haven't been read.`;
5300
+
5301
+ // ../frontman-core/src/tools/FrontmanCore__Tool__FileExists.res.mjs
5302
+ var name11 = ToolNames.fileExists;
5303
+ var inputSchema10 = schema2((s2) => ({
4651
5304
  path: s2.m(string2)
4652
5305
  }));
4653
- async function execute9(ctx2, input) {
5306
+ async function execute10(ctx2, input) {
4654
5307
  let msg = resolve(ctx2.sourceRoot, input.path);
4655
5308
  if (msg.TAG !== "Ok") {
4656
5309
  return {
@@ -4658,28 +5311,21 @@ async function execute9(ctx2, input) {
4658
5311
  _0: msg._0
4659
5312
  };
4660
5313
  }
4661
- try {
4662
- await Fs.promises.access(toString(msg._0));
4663
- return {
4664
- TAG: "Ok",
4665
- _0: true
4666
- };
4667
- } catch (exn) {
4668
- return {
4669
- TAG: "Ok",
4670
- _0: false
4671
- };
4672
- }
5314
+ let exists = await pathExists(toString(msg._0));
5315
+ return {
5316
+ TAG: "Ok",
5317
+ _0: exists
5318
+ };
4673
5319
  }
4674
- var description9 = `Checks if a file or directory exists.
5320
+ var description10 = `Checks if a file or directory exists.
4675
5321
 
4676
5322
  Parameters:
4677
5323
  - path (required): Path to check - either relative to source root or absolute (must be under source root)
4678
5324
 
4679
5325
  Returns true if the path exists, false otherwise.`;
4680
- var outputSchema9 = bool2;
5326
+ var outputSchema10 = bool2;
4681
5327
 
4682
- // ../bindings/src/Lighthouse.res.mjs
5328
+ // ../frontman-core/src/FrontmanCore__Lighthouse.res.mjs
4683
5329
  var run = ((url2, flags2) => import('module').then(({ createRequire }) => {
4684
5330
  const req = createRequire(import.meta.url);
4685
5331
  try {
@@ -4694,7 +5340,10 @@ var run = ((url2, flags2) => import('module').then(({ createRequire }) => {
4694
5340
  }
4695
5341
  }));
4696
5342
 
4697
- // ../bindings/src/ChromeLauncher.res.mjs
5343
+ // ../frontman-core/src/FrontmanCore__ChromeLauncher.res.mjs
5344
+ function getPort(prim) {
5345
+ return prim.port;
5346
+ }
4698
5347
  var launch = ((options) => import('module').then(({ createRequire }) => {
4699
5348
  const req = createRequire(import.meta.url);
4700
5349
  try {
@@ -4719,17 +5368,37 @@ async function killSafely(chrome) {
4719
5368
  }
4720
5369
 
4721
5370
  // ../frontman-core/src/tools/FrontmanCore__Tool__Lighthouse.res.mjs
4722
- var name11 = ToolNames.lighthouse;
4723
- var inputSchema10 = schema2((s2) => ({
5371
+ var name12 = ToolNames.lighthouse;
5372
+ var presetSchema = union2([
5373
+ literal2("desktop"),
5374
+ literal2("mobile")
5375
+ ]);
5376
+ function presetToString(preset) {
5377
+ if (preset === "desktop") {
5378
+ return "desktop";
5379
+ } else {
5380
+ return "mobile";
5381
+ }
5382
+ }
5383
+ var inputSchema11 = schema2((s2) => ({
4724
5384
  url: s2.m(string2),
4725
- preset: s2.m(option2(string2))
5385
+ preset: s2.m(option2(presetSchema))
5386
+ }));
5387
+ var elementDetailSchema = schema2((s2) => ({
5388
+ selector: s2.m(option2(string2)),
5389
+ snippet: s2.m(option2(string2)),
5390
+ nodeLabel: s2.m(option2(string2)),
5391
+ explanation: s2.m(option2(string2)),
5392
+ url: s2.m(option2(string2)),
5393
+ sourceLocation: s2.m(option2(string2))
4726
5394
  }));
4727
5395
  var auditIssueSchema = schema2((s2) => ({
4728
5396
  id: s2.m(string2),
4729
5397
  title: s2.m(string2),
4730
5398
  description: s2.m(string2),
4731
5399
  score: s2.m(float2),
4732
- displayValue: s2.m(option2(string2))
5400
+ displayValue: s2.m(option2(string2)),
5401
+ elements: s2.m(array2(elementDetailSchema))
4733
5402
  }));
4734
5403
  var categoryResultSchema = schema2((s2) => ({
4735
5404
  id: s2.m(string2),
@@ -4737,7 +5406,7 @@ var categoryResultSchema = schema2((s2) => ({
4737
5406
  score: s2.m(int2),
4738
5407
  topIssues: s2.m(array2(auditIssueSchema))
4739
5408
  }));
4740
- var outputSchema10 = schema2((s2) => ({
5409
+ var outputSchema11 = schema2((s2) => ({
4741
5410
  url: s2.m(string2),
4742
5411
  fetchTime: s2.m(string2),
4743
5412
  categories: s2.m(array2(categoryResultSchema)),
@@ -4750,30 +5419,126 @@ var categoryIds = [
4750
5419
  "best-practices",
4751
5420
  "seo"
4752
5421
  ];
5422
+ function getStr(dict3, key) {
5423
+ return flatMap(dict3[key], Decode.string);
5424
+ }
5425
+ function extractNodeDetail(itemDict) {
5426
+ let n = flatMap(itemDict["node"], Decode.object);
5427
+ let nodeDict;
5428
+ if (n !== void 0) {
5429
+ nodeDict = n;
5430
+ } else {
5431
+ let match = getStr(itemDict, "type");
5432
+ nodeDict = match === "node" ? itemDict : void 0;
5433
+ }
5434
+ if (nodeDict === void 0) {
5435
+ return;
5436
+ }
5437
+ let selector = getStr(nodeDict, "selector");
5438
+ let snippet = getStr(nodeDict, "snippet");
5439
+ let nodeLabel = getStr(nodeDict, "nodeLabel");
5440
+ let explanation = getStr(nodeDict, "explanation");
5441
+ if (selector === void 0 && snippet === void 0) {
5442
+ return;
5443
+ }
5444
+ return {
5445
+ selector,
5446
+ snippet,
5447
+ nodeLabel,
5448
+ explanation,
5449
+ url: void 0,
5450
+ sourceLocation: void 0
5451
+ };
5452
+ }
5453
+ function extractSourceLocation(itemDict) {
5454
+ let sourceDict = flatMap(itemDict["source"], Decode.object);
5455
+ if (sourceDict === void 0) {
5456
+ return;
5457
+ }
5458
+ let url2 = getStr(sourceDict, "url");
5459
+ if (url2 === void 0) {
5460
+ return;
5461
+ }
5462
+ let line = map(flatMap(sourceDict["line"], Decode.float), (prim) => prim | 0);
5463
+ let col = map(flatMap(sourceDict["column"], Decode.float), (prim) => prim | 0);
5464
+ if (line !== void 0) {
5465
+ if (col !== void 0) {
5466
+ return url2 + `:` + line.toString() + `:` + col.toString();
5467
+ } else {
5468
+ return url2 + `:` + line.toString();
5469
+ }
5470
+ } else {
5471
+ return url2;
5472
+ }
5473
+ }
5474
+ function extractResourceDetail(itemDict) {
5475
+ let url2 = getStr(itemDict, "url");
5476
+ let sourceLocation = extractSourceLocation(itemDict);
5477
+ if (url2 === void 0 && sourceLocation === void 0) {
5478
+ return;
5479
+ }
5480
+ return {
5481
+ selector: void 0,
5482
+ snippet: void 0,
5483
+ nodeLabel: void 0,
5484
+ explanation: void 0,
5485
+ url: url2,
5486
+ sourceLocation
5487
+ };
5488
+ }
5489
+ function extractElements(details) {
5490
+ let detailsDict = flatMap(details, Decode.object);
5491
+ if (detailsDict === void 0) {
5492
+ return [];
5493
+ }
5494
+ let arr = flatMap(detailsDict["items"], Decode.array);
5495
+ let items = arr !== void 0 ? arr : [];
5496
+ return filterMap(items, (item) => {
5497
+ let itemDict = Decode.object(item);
5498
+ if (itemDict === void 0) {
5499
+ return;
5500
+ }
5501
+ let result = extractNodeDetail(itemDict);
5502
+ if (result !== void 0) {
5503
+ return result;
5504
+ } else {
5505
+ return extractResourceDetail(itemDict);
5506
+ }
5507
+ }).slice(0, 3);
5508
+ }
4753
5509
  function getTopIssues(category, audits, maxIssues) {
4754
5510
  return filterMap(category.auditRefs, (ref) => audits[ref.id]).filter((audit) => {
4755
- let score = audit.score;
4756
- if (!(score == null) && (audit.scoreDisplayMode === "binary" || audit.scoreDisplayMode === "numeric" || audit.scoreDisplayMode === "metricSavings")) {
4757
- return score < 1;
4758
- } else {
5511
+ let match = audit.scoreDisplayMode;
5512
+ let match$1 = audit.score;
5513
+ switch (match) {
5514
+ case "numeric":
5515
+ case "binary":
5516
+ case "metricSavings":
5517
+ break;
5518
+ default:
5519
+ return false;
5520
+ }
5521
+ if (match$1 == null) {
4759
5522
  return false;
5523
+ } else {
5524
+ return match$1 < 1;
4760
5525
  }
4761
5526
  }).toSorted((a, b) => {
4762
- let scoreA = getOr(fromNullable(a.score), 0);
4763
- let scoreB = getOr(fromNullable(b.score), 0);
5527
+ let scoreA = getOrThrow(fromNullable(a.score));
5528
+ let scoreB = getOrThrow(fromNullable(b.score));
4764
5529
  return scoreA - scoreB;
4765
5530
  }).slice(0, maxIssues).map((audit) => ({
4766
5531
  id: audit.id,
4767
5532
  title: audit.title,
4768
5533
  description: audit.description,
4769
- score: getOr(fromNullable(audit.score), 0),
4770
- displayValue: audit.displayValue
5534
+ score: getOrThrow(fromNullable(audit.score)),
5535
+ displayValue: audit.displayValue,
5536
+ elements: extractElements(audit.details)
4771
5537
  }));
4772
5538
  }
4773
5539
  function processLhr(lhr) {
4774
5540
  let categories = filterMap(categoryIds, (id) => lhr.categories[id]).map((category) => {
4775
- let s2 = category.score;
4776
- let score = !(s2 == null) ? Math.round(s2 * 100) | 0 : 0;
5541
+ let score = Math.round(getOrThrow(fromNullable(category.score)) * 100) | 0;
4777
5542
  let topIssues = getTopIssues(category, lhr.audits, 3);
4778
5543
  return {
4779
5544
  id: category.id,
@@ -4794,14 +5559,17 @@ function processLhr(lhr) {
4794
5559
  };
4795
5560
  }
4796
5561
  async function runLighthouse(chrome, url2, preset) {
4797
- let port2 = chrome.port;
5562
+ let port2 = getPort(chrome);
5563
+ let formFactor = presetToString(preset);
5564
+ let tmp;
5565
+ tmp = preset === "desktop";
4798
5566
  let flags_port = port2;
4799
5567
  let flags_output = "json";
4800
5568
  let flags_logLevel = "error";
4801
5569
  let flags_onlyCategories = categoryIds;
4802
- let flags_formFactor = preset;
5570
+ let flags_formFactor = formFactor;
4803
5571
  let flags_screenEmulation = {
4804
- disabled: preset === "desktop"
5572
+ disabled: tmp
4805
5573
  };
4806
5574
  let flags_throttlingMethod = "simulate";
4807
5575
  let flags2 = {
@@ -4813,42 +5581,28 @@ async function runLighthouse(chrome, url2, preset) {
4813
5581
  screenEmulation: flags_screenEmulation,
4814
5582
  throttlingMethod: flags_throttlingMethod
4815
5583
  };
5584
+ let result;
4816
5585
  try {
4817
5586
  let runnerResult = await run(url2, flags2);
4818
- await killSafely(chrome);
4819
- if (runnerResult == null) {
4820
- return {
4821
- TAG: "Error",
4822
- _0: "Lighthouse returned no results. The URL may be unreachable."
4823
- };
4824
- } else {
4825
- return {
4826
- TAG: "Ok",
4827
- _0: processLhr(runnerResult.lhr)
4828
- };
4829
- }
5587
+ result = runnerResult == null ? {
5588
+ TAG: "Error",
5589
+ _0: "Lighthouse returned no results. The URL may be unreachable."
5590
+ } : {
5591
+ TAG: "Ok",
5592
+ _0: processLhr(runnerResult.lhr)
5593
+ };
4830
5594
  } catch (raw_exn) {
4831
5595
  let exn = internalToException(raw_exn);
4832
- await killSafely(chrome);
4833
- let msg = getOr(flatMap(fromException(exn), message2), "Unknown error");
4834
- return {
5596
+ result = {
4835
5597
  TAG: "Error",
4836
- _0: `Lighthouse audit failed: ` + msg
5598
+ _0: `Lighthouse audit failed: ` + message3(exn)
4837
5599
  };
4838
5600
  }
5601
+ await killSafely(chrome);
5602
+ return result;
4839
5603
  }
4840
- async function execute10(_ctx, input) {
5604
+ async function execute11(_ctx, input) {
4841
5605
  let preset = getOr(input.preset, "desktop");
4842
- switch (preset) {
4843
- case "desktop":
4844
- case "mobile":
4845
- break;
4846
- default:
4847
- return {
4848
- TAG: "Error",
4849
- _0: `Invalid preset "` + preset + `". Must be "desktop" or "mobile".`
4850
- };
4851
- }
4852
5606
  try {
4853
5607
  let chrome = await launch({
4854
5608
  chromeFlags: [
@@ -4861,14 +5615,13 @@ async function execute10(_ctx, input) {
4861
5615
  return await runLighthouse(chrome, input.url, preset);
4862
5616
  } catch (raw_exn) {
4863
5617
  let exn = internalToException(raw_exn);
4864
- let msg = getOr(flatMap(fromException(exn), message2), "Unknown error");
4865
5618
  return {
4866
5619
  TAG: "Error",
4867
- _0: `Failed to launch Chrome: ` + msg + `. Make sure Chrome is installed on the system.`
5620
+ _0: `Failed to launch Chrome: ` + message3(exn) + `. Make sure Chrome is installed on the system.`
4868
5621
  };
4869
5622
  }
4870
5623
  }
4871
- var description10 = `Runs a Lighthouse audit on a URL to analyze performance, accessibility, best practices, and SEO.
5624
+ var description11 = `Runs a Lighthouse audit on a URL to analyze performance, accessibility, best practices, and SEO.
4872
5625
 
4873
5626
  WHEN TO USE THIS TOOL:
4874
5627
  - After making changes that might affect page load performance
@@ -4882,21 +5635,27 @@ PARAMETERS:
4882
5635
  IMPORTANT: Check the current_page context for device_emulation - if a mobile device is being emulated (e.g., iPhone, Pixel), use preset: "mobile" to match the user's testing context.
4883
5636
 
4884
5637
  OUTPUT:
4885
- Returns scores (0-100) for each category plus the top 3 issues to fix in each category.
4886
- Higher scores are better. Issues include actionable descriptions.
5638
+ Returns scores (0-100) for each category plus the top 3 worst issues per category.
5639
+ Higher scores are better. Each issue includes:
5640
+ - A description of the problem
5641
+ - Specific offending elements with CSS selectors, HTML snippets, and source locations when available
5642
+ Use the selectors and snippets to locate the exact elements that need fixing.
5643
+
5644
+ IMPORTANT - ITERATIVE FIXING:
5645
+ Only the 3 worst-scoring issues per category are returned. Fixing these may reveal additional issues that were previously ranked lower. After making fixes, re-run the lighthouse audit to check for newly surfaced issues and verify improvements. Repeat until scores are satisfactory.
4887
5646
 
4888
5647
  LIMITATIONS:
4889
5648
  - Requires Chrome to be installed on the system
4890
5649
  - Takes 15-30 seconds to complete
4891
5650
  - Results can vary between runs (\xB15 points is normal)
4892
5651
  - URL must be accessible from the machine running the audit`;
4893
- var name12 = ToolNames.searchFiles;
4894
- var inputSchema11 = schema2((s2) => ({
5652
+ var name13 = ToolNames.searchFiles;
5653
+ var inputSchema12 = schema2((s2) => ({
4895
5654
  pattern: s2.m(string2),
4896
5655
  path: s2.m(option2(string2)),
4897
5656
  max_results: s2.m(option2(int2))
4898
5657
  }));
4899
- var outputSchema11 = schema2((s2) => ({
5658
+ var outputSchema12 = schema2((s2) => ({
4900
5659
  files: s2.m(array2(string2)),
4901
5660
  totalResults: s2.m(int2),
4902
5661
  truncated: s2.m(bool2)
@@ -4946,7 +5705,7 @@ function matchesPattern(fileName2, patternLower) {
4946
5705
  function filterAndPaginate(lines, pattern2, maxResults) {
4947
5706
  let patternLower = pattern2.toLowerCase();
4948
5707
  let matchedFiles = lines.filter((filePath) => {
4949
- let fileName2 = Nodepath.basename(filePath);
5708
+ let fileName2 = Nodepath5.basename(filePath);
4950
5709
  return matchesPattern(fileName2, patternLower);
4951
5710
  });
4952
5711
  let truncated = matchedFiles.length > maxResults;
@@ -5010,8 +5769,8 @@ async function executeGitLsFiles(pattern2, searchPath, maxResults) {
5010
5769
  _0: `Git ls-files failed: ` + match.stderr
5011
5770
  };
5012
5771
  }
5013
- async function execute11(ctx2, input) {
5014
- let searchPath = resolveSearchPath(ctx2.sourceRoot, input.path);
5772
+ async function execute12(ctx2, input) {
5773
+ let searchPath = await resolveSearchDir(ctx2.sourceRoot, input.path);
5015
5774
  let maxResults = getOr(input.max_results, 20);
5016
5775
  let rgPath = getRipgrepPath2();
5017
5776
  if (rgPath === void 0) {
@@ -5024,43 +5783,36 @@ async function execute11(ctx2, input) {
5024
5783
  return await executeGitLsFiles(input.pattern, searchPath, maxResults);
5025
5784
  }
5026
5785
  }
5027
- var description11 = `Fast file name search tool that finds files matching a pattern.
5786
+ var description12 = `Searches **file names** across the project. Returns file paths whose name matches a pattern.
5028
5787
 
5029
- WHEN TO USE THIS TOOL:
5030
- - Use when you need to find files by name pattern
5031
- - Great for locating specific files like "config.json" or "*.test.ts"
5032
- - Useful for finding all files with a specific extension or naming convention
5033
- - When you need to discover the file structure of a project
5034
- - Note: this tool only searches file names, not directory names. Use list_files to browse directories.
5788
+ Use search_files to locate files by name \u2014 "find the Button component", "where are the test files". This does NOT search file contents; use grep for that. Use list_tree for a structural overview of the project.
5035
5789
 
5036
5790
  PARAMETERS:
5037
- - pattern (required): The filename pattern to search for (supports glob-like patterns)
5038
- - path (optional): Directory to search in (defaults to source root)
5791
+ - pattern (required): Filename pattern to match (supports glob-like: "*.test.ts", "config", "Button*")
5792
+ - path (optional): Directory to search in (defaults to source root). If a file path is given, searches in its parent directory.
5039
5793
  - max_results (optional): Maximum number of results to return (default: 20)
5040
5794
 
5041
5795
  EXAMPLES:
5042
- - Find all config files: pattern="config"
5043
- - Find TypeScript test files: pattern="*.test.ts"
5044
- - Find files in specific directory: pattern="*.json", path="src/config"
5796
+ - Locate a component: pattern="Button"
5797
+ - Find test files: pattern="*.test.ts"
5798
+ - Find configs in a subdirectory: pattern="*.json", path="src/config"
5045
5799
 
5046
5800
  OUTPUT:
5047
- Returns list of matching file paths.
5048
- Results are sorted by modification time (newest first).
5801
+ List of matching file paths, sorted by modification time (newest first).
5049
5802
 
5050
5803
  LIMITATIONS:
5051
- - Results limited to max_results (default 20)
5052
- - Hidden files (starting with '.') are included
5053
- - Respects .gitignore when using git ls-files fallback
5054
- - Only finds files, not directories`;
5055
- var name13 = ToolNames.loadAgentInstructions;
5056
- var inputSchema12 = schema2((s2) => ({
5804
+ - Results capped at max_results (default 20)
5805
+ - Matches file names only, not directory names
5806
+ - Hidden files (dotfiles) are included`;
5807
+ var name14 = ToolNames.loadAgentInstructions;
5808
+ var inputSchema13 = schema2((s2) => ({
5057
5809
  startPath: s2.m(option2(string2))
5058
5810
  }));
5059
5811
  var instructionFileSchema = schema2((s2) => ({
5060
5812
  content: s2.m(string2),
5061
5813
  fullPath: s2.m(string2)
5062
5814
  }));
5063
- var outputSchema12 = array2(instructionFileSchema);
5815
+ var outputSchema13 = array2(instructionFileSchema);
5064
5816
  var agentsVariants = [
5065
5817
  "Agents.md",
5066
5818
  ".claude/Agents.md",
@@ -5073,11 +5825,11 @@ var claudeVariants = [
5073
5825
  ];
5074
5826
  async function findFileCaseInsensitive(dir, targetFileName) {
5075
5827
  try {
5076
- let files = await Fs.promises.readdir(dir);
5828
+ let files = await Fs7.promises.readdir(dir);
5077
5829
  let targetLower = targetFileName.toLowerCase();
5078
5830
  let found = files.find((file) => file.toLowerCase() === targetLower);
5079
5831
  if (found !== void 0) {
5080
- return Nodepath.join(dir, found);
5832
+ return Nodepath5.join(dir, found);
5081
5833
  } else {
5082
5834
  return;
5083
5835
  }
@@ -5086,14 +5838,14 @@ async function findFileCaseInsensitive(dir, targetFileName) {
5086
5838
  }
5087
5839
  }
5088
5840
  async function loadIfExists(path) {
5089
- let dir = Nodepath.dirname(path);
5090
- let fileName2 = Nodepath.basename(path);
5841
+ let dir = Nodepath5.dirname(path);
5842
+ let fileName2 = Nodepath5.basename(path);
5091
5843
  let actualPath = await findFileCaseInsensitive(dir, fileName2);
5092
5844
  if (actualPath === void 0) {
5093
5845
  return;
5094
5846
  }
5095
5847
  try {
5096
- let content = await Fs.promises.readFile(actualPath, "utf8");
5848
+ let content = await Fs7.promises.readFile(actualPath, "utf8");
5097
5849
  return {
5098
5850
  content,
5099
5851
  fullPath: actualPath
@@ -5106,7 +5858,7 @@ async function loadVariants(dir, variants) {
5106
5858
  let results = [];
5107
5859
  for (let i = 0, i_finish = variants.length; i < i_finish; ++i) {
5108
5860
  let variant = variants[i];
5109
- let path = Nodepath.join(dir, variant);
5861
+ let path = Nodepath5.join(dir, variant);
5110
5862
  let file = await loadIfExists(path);
5111
5863
  if (file !== void 0) {
5112
5864
  results.push(file);
@@ -5123,7 +5875,7 @@ async function findAtDirectory(dir) {
5123
5875
  }
5124
5876
  }
5125
5877
  async function walkUpDirectories(current, acc) {
5126
- let parent = Nodepath.dirname(current);
5878
+ let parent = Nodepath5.dirname(current);
5127
5879
  if (parent === current) {
5128
5880
  return acc;
5129
5881
  }
@@ -5131,7 +5883,7 @@ async function walkUpDirectories(current, acc) {
5131
5883
  let newAcc = acc.concat(filesAtLevel);
5132
5884
  return await walkUpDirectories(parent, newAcc);
5133
5885
  }
5134
- async function execute12(ctx2, input) {
5886
+ async function execute13(ctx2, input) {
5135
5887
  let inputPath = getOr(input.startPath, ".");
5136
5888
  let msg = resolve(ctx2.sourceRoot, inputPath);
5137
5889
  if (msg.TAG !== "Ok") {
@@ -5156,7 +5908,7 @@ async function execute12(ctx2, input) {
5156
5908
  };
5157
5909
  }
5158
5910
  }
5159
- var description12 = `Discovers and loads agent instruction files (Agents.md or CLAUDE.md) following Claude Code's discovery algorithm.
5911
+ var description13 = `Discovers and loads agent instruction files (Agents.md or CLAUDE.md) following Claude Code's discovery algorithm.
5160
5912
 
5161
5913
  Parameters:
5162
5914
  - startPath (optional): Starting directory for discovery - must be under source root. Defaults to "." (source root).
@@ -5173,22 +5925,6 @@ Discovery:
5173
5925
  function coreTools() {
5174
5926
  return {
5175
5927
  tools: [
5176
- {
5177
- name: name7,
5178
- description: description6,
5179
- inputSchema: inputSchema6,
5180
- outputSchema: outputSchema6,
5181
- execute: execute6,
5182
- visibleToAgent: true
5183
- },
5184
- {
5185
- name: name9,
5186
- description: description8,
5187
- inputSchema: inputSchema8,
5188
- outputSchema: outputSchema8,
5189
- execute: execute8,
5190
- visibleToAgent: true
5191
- },
5192
5928
  {
5193
5929
  name: name8,
5194
5930
  description: description7,
@@ -5206,11 +5942,27 @@ function coreTools() {
5206
5942
  visibleToAgent: true
5207
5943
  },
5208
5944
  {
5209
- name: name13,
5210
- description: description12,
5211
- inputSchema: inputSchema12,
5212
- outputSchema: outputSchema12,
5213
- execute: execute12,
5945
+ name: name9,
5946
+ description: description8,
5947
+ inputSchema: inputSchema8,
5948
+ outputSchema: outputSchema8,
5949
+ execute: execute8,
5950
+ visibleToAgent: true
5951
+ },
5952
+ {
5953
+ name: name11,
5954
+ description: description10,
5955
+ inputSchema: inputSchema10,
5956
+ outputSchema: outputSchema10,
5957
+ execute: execute10,
5958
+ visibleToAgent: true
5959
+ },
5960
+ {
5961
+ name: name14,
5962
+ description: description13,
5963
+ inputSchema: inputSchema13,
5964
+ outputSchema: outputSchema13,
5965
+ execute: execute13,
5214
5966
  visibleToAgent: false
5215
5967
  },
5216
5968
  {
@@ -5221,6 +5973,14 @@ function coreTools() {
5221
5973
  execute: execute5,
5222
5974
  visibleToAgent: true
5223
5975
  },
5976
+ {
5977
+ name: name13,
5978
+ description: description12,
5979
+ inputSchema: inputSchema12,
5980
+ outputSchema: outputSchema12,
5981
+ execute: execute12,
5982
+ visibleToAgent: true
5983
+ },
5224
5984
  {
5225
5985
  name: name12,
5226
5986
  description: description11,
@@ -5229,14 +5989,6 @@ function coreTools() {
5229
5989
  execute: execute11,
5230
5990
  visibleToAgent: true
5231
5991
  },
5232
- {
5233
- name: name11,
5234
- description: description10,
5235
- inputSchema: inputSchema10,
5236
- outputSchema: outputSchema10,
5237
- execute: execute10,
5238
- visibleToAgent: true
5239
- },
5240
5992
  {
5241
5993
  name: name3,
5242
5994
  description: description2,
@@ -5244,6 +5996,14 @@ function coreTools() {
5244
5996
  outputSchema: outputSchema2,
5245
5997
  execute: execute2,
5246
5998
  visibleToAgent: true
5999
+ },
6000
+ {
6001
+ name: name7,
6002
+ description: description6,
6003
+ inputSchema: inputSchema6,
6004
+ outputSchema: outputSchema6,
6005
+ execute: execute6,
6006
+ visibleToAgent: true
5247
6007
  }
5248
6008
  ]
5249
6009
  };
@@ -5264,8 +6024,8 @@ function replaceByName(registry, replacement) {
5264
6024
  })
5265
6025
  };
5266
6026
  }
5267
- function getToolByName(registry, name14) {
5268
- return registry.tools.find((m) => m.name === name14);
6027
+ function getToolByName(registry, name15) {
6028
+ return registry.tools.find((m) => m.name === name15);
5269
6029
  }
5270
6030
  function serializeTool(m) {
5271
6031
  return {
@@ -5345,6 +6105,18 @@ function handlePreflight() {
5345
6105
  });
5346
6106
  }
5347
6107
 
6108
+ // ../frontman-core/src/FrontmanCore__MiddlewareConfig.res.mjs
6109
+ function frameworkIdToString(id) {
6110
+ switch (id) {
6111
+ case "Nextjs":
6112
+ return "nextjs";
6113
+ case "Vite":
6114
+ return "vite";
6115
+ case "Astro":
6116
+ return "astro";
6117
+ }
6118
+ }
6119
+
5348
6120
  // ../frontman-core/src/FrontmanCore__UIShell.res.mjs
5349
6121
  function generateHTML(config) {
5350
6122
  let clientCssTag = mapOr(config.clientCssUrl, "", (url2) => `<link rel="stylesheet" href="` + url2 + `">`);
@@ -5358,11 +6130,19 @@ function generateHTML(config) {
5358
6130
  let configObj = Object.fromEntries([
5359
6131
  [
5360
6132
  "framework",
5361
- config.frameworkLabel
6133
+ frameworkIdToString(config.frameworkId)
5362
6134
  ],
5363
6135
  [
5364
6136
  "basePath",
5365
6137
  config.basePath
6138
+ ],
6139
+ [
6140
+ "projectRoot",
6141
+ config.projectRoot
6142
+ ],
6143
+ [
6144
+ "sourceRoot",
6145
+ config.sourceRoot
5366
6146
  ]
5367
6147
  ]);
5368
6148
  forEach(openrouterKey, (key) => {
@@ -5416,7 +6196,7 @@ function serveWithEntrypoint(config, entrypointUrl) {
5416
6196
  clientCssUrl: config.clientCssUrl,
5417
6197
  entrypointUrl,
5418
6198
  isLightTheme: config.isLightTheme,
5419
- frameworkLabel: config.frameworkLabel
6199
+ frameworkId: config.frameworkId
5420
6200
  } : config);
5421
6201
  }
5422
6202
 
@@ -5425,80 +6205,6 @@ function $$catch(promise, callback) {
5425
6205
  return promise.catch((err) => callback(internalToException(err)));
5426
6206
  }
5427
6207
 
5428
- // ../frontman-protocol/src/FrontmanProtocol__MCP.res.mjs
5429
- enableJson2();
5430
- var capabilitiesSchema = schema2((s2) => ({
5431
- tools: s2.m(option2(dict2(json2))),
5432
- resources: s2.m(option2(dict2(json2))),
5433
- prompts: s2.m(option2(dict2(json2)))
5434
- }));
5435
- var infoSchema = schema2((s2) => ({
5436
- name: s2.m(string2),
5437
- version: s2.m(string2)
5438
- }));
5439
- schema2((s2) => ({
5440
- protocolVersion: s2.m(string2),
5441
- capabilities: s2.m(capabilitiesSchema),
5442
- clientInfo: s2.m(infoSchema)
5443
- }));
5444
- schema2((s2) => ({
5445
- protocolVersion: s2.m(string2),
5446
- capabilities: s2.m(capabilitiesSchema),
5447
- serverInfo: s2.m(infoSchema)
5448
- }));
5449
- schema2((s2) => ({
5450
- callId: s2.m(string2),
5451
- name: s2.m(string2),
5452
- arguments: s2.m(option2(dict2(json2)))
5453
- }));
5454
- var toolResultContentSchema = schema2((s2) => ({
5455
- type: s2.m(string2),
5456
- text: s2.m(string2)
5457
- }));
5458
- schema2((s2) => ({
5459
- code: s2.m(int2),
5460
- message: s2.m(string2)
5461
- }));
5462
- var callToolResultSchema = schema2((s2) => ({
5463
- content: s2.m(array2(toolResultContentSchema)),
5464
- isError: s2.m(option2(bool2))
5465
- }));
5466
- schema2((s2) => ({
5467
- tools: s2.m(array2(json2))
5468
- }));
5469
-
5470
- // ../frontman-core/src/FrontmanCore__SSE.res.mjs
5471
- function formatEvent(eventType, data) {
5472
- return `event: ` + eventType + `
5473
- data: ` + data + `
5474
-
5475
- `;
5476
- }
5477
- function resultEvent(result) {
5478
- let data = JSON.stringify(reverseConvertToJsonOrThrow2(result, callToolResultSchema));
5479
- return formatEvent("result", data);
5480
- }
5481
- function errorEvent(result) {
5482
- let data = JSON.stringify(reverseConvertToJsonOrThrow2(result, callToolResultSchema));
5483
- return formatEvent("error", data);
5484
- }
5485
- function headers() {
5486
- return Object.fromEntries([
5487
- [
5488
- "Content-Type",
5489
- "text/event-stream"
5490
- ],
5491
- [
5492
- "Cache-Control",
5493
- "no-cache, no-transform"
5494
- ],
5495
- [
5496
- "Connection",
5497
- "keep-alive"
5498
- ]
5499
- ]);
5500
- }
5501
-
5502
6208
  // ../../node_modules/dom-element-to-component-source/dist/_commonjsHelpers-CqEciG1_.mjs
5503
6209
  function c(e) {
5504
6210
  if (Object.prototype.hasOwnProperty.call(e, "__esModule")) return e;
@@ -7108,6 +7814,80 @@ async function Te(o) {
7108
7814
  }
7109
7815
  }
7110
7816
 
7817
+ // ../frontman-protocol/src/FrontmanProtocol__MCP.res.mjs
7818
+ enableJson2();
7819
+ var capabilitiesSchema = schema2((s2) => ({
7820
+ tools: s2.m(option2(dict2(json2))),
7821
+ resources: s2.m(option2(dict2(json2))),
7822
+ prompts: s2.m(option2(dict2(json2)))
7823
+ }));
7824
+ var infoSchema = schema2((s2) => ({
7825
+ name: s2.m(string2),
7826
+ version: s2.m(string2)
7827
+ }));
7828
+ schema2((s2) => ({
7829
+ protocolVersion: s2.m(string2),
7830
+ capabilities: s2.m(capabilitiesSchema),
7831
+ clientInfo: s2.m(infoSchema)
7832
+ }));
7833
+ schema2((s2) => ({
7834
+ protocolVersion: s2.m(string2),
7835
+ capabilities: s2.m(capabilitiesSchema),
7836
+ serverInfo: s2.m(infoSchema)
7837
+ }));
7838
+ schema2((s2) => ({
7839
+ callId: s2.m(string2),
7840
+ name: s2.m(string2),
7841
+ arguments: s2.m(option2(dict2(json2)))
7842
+ }));
7843
+ var toolResultContentSchema = schema2((s2) => ({
7844
+ type: s2.m(string2),
7845
+ text: s2.m(string2)
7846
+ }));
7847
+ schema2((s2) => ({
7848
+ code: s2.m(int2),
7849
+ message: s2.m(string2)
7850
+ }));
7851
+ var callToolResultSchema = schema2((s2) => ({
7852
+ content: s2.m(array2(toolResultContentSchema)),
7853
+ isError: s2.m(option2(bool2))
7854
+ }));
7855
+ schema2((s2) => ({
7856
+ tools: s2.m(array2(json2))
7857
+ }));
7858
+
7859
+ // ../frontman-core/src/FrontmanCore__SSE.res.mjs
7860
+ function formatEvent(eventType, data) {
7861
+ return `event: ` + eventType + `
7862
+ data: ` + data + `
7863
+
7864
+ `;
7865
+ }
7866
+ function resultEvent(result) {
7867
+ let data = JSON.stringify(reverseConvertToJsonOrThrow2(result, callToolResultSchema));
7868
+ return formatEvent("result", data);
7869
+ }
7870
+ function errorEvent(result) {
7871
+ let data = JSON.stringify(reverseConvertToJsonOrThrow2(result, callToolResultSchema));
7872
+ return formatEvent("error", data);
7873
+ }
7874
+ function headers() {
7875
+ return Object.fromEntries([
7876
+ [
7877
+ "Content-Type",
7878
+ "text/event-stream"
7879
+ ],
7880
+ [
7881
+ "Cache-Control",
7882
+ "no-cache, no-transform"
7883
+ ],
7884
+ [
7885
+ "Connection",
7886
+ "keep-alive"
7887
+ ]
7888
+ ]);
7889
+ }
7890
+
7111
7891
  // ../frontman-protocol/src/FrontmanProtocol__Relay.res.mjs
7112
7892
  var remoteToolSchema = schema2((s2) => ({
7113
7893
  name: s2.m(string2),
@@ -7127,12 +7907,12 @@ var toolCallRequestSchema = schema2((s2) => ({
7127
7907
  var protocolVersion = "1.0";
7128
7908
 
7129
7909
  // ../frontman-core/src/FrontmanCore__Server.res.mjs
7130
- async function executeTool(registry, ctx2, name14, $$arguments) {
7131
- let toolModule = getToolByName(registry, name14);
7910
+ async function executeTool(registry, ctx2, name15, $$arguments) {
7911
+ let toolModule = getToolByName(registry, name15);
7132
7912
  if (toolModule === void 0) {
7133
7913
  return {
7134
7914
  TAG: "ToolNotFound",
7135
- _0: name14
7915
+ _0: name15
7136
7916
  };
7137
7917
  }
7138
7918
  let toolCtx_projectRoot = ctx2.projectRoot;
@@ -7536,7 +8316,7 @@ function toMiddlewareConfig(config) {
7536
8316
  clientCssUrl: config.clientCssUrl,
7537
8317
  entrypointUrl: config.entrypointUrl,
7538
8318
  isLightTheme: config.isLightTheme,
7539
- frameworkLabel: "Astro"
8319
+ frameworkId: "Astro"
7540
8320
  };
7541
8321
  }
7542
8322
  function createMiddleware2(config) {
@@ -7545,7 +8325,7 @@ function createMiddleware2(config) {
7545
8325
  return createMiddleware(middlewareConfig, registry);
7546
8326
  }
7547
8327
 
7548
- // ../bindings/src/NodeHttp.res.mjs
8328
+ // src/FrontmanAstro__ViteAdapter.res.mjs
7549
8329
  var collectRequestBody = (async function(req) {
7550
8330
  const chunks = [];
7551
8331
  for await (const chunk of req) {
@@ -7554,8 +8334,6 @@ var collectRequestBody = (async function(req) {
7554
8334
  const { Buffer: Buffer4 } = await import('buffer');
7555
8335
  return Buffer4.concat(chunks);
7556
8336
  });
7557
-
7558
- // src/FrontmanAstro__ViteAdapter.res.mjs
7559
8337
  var copyHeaders = (function(headers2, res) {
7560
8338
  headers2.forEach(function(value, key) {
7561
8339
  res.setHeader(key, value);
@@ -7695,6 +8473,29 @@ function make5(configInput) {
7695
8473
  },
7696
8474
  "astro:server:setup": (param) => {
7697
8475
  initialize();
8476
+ let prependTrailingSlashRewrite = (function(server, basePath) {
8477
+ var hs = server.httpServer;
8478
+ if (!hs) return;
8479
+ var prefix = "/" + basePath.toLowerCase();
8480
+ var prefixSlash = prefix + "/";
8481
+ var listeners = hs.listeners("request").slice();
8482
+ hs.removeAllListeners("request");
8483
+ hs.on("request", function(req) {
8484
+ var raw = req.url || "";
8485
+ var qIdx = raw.indexOf("?");
8486
+ var path = (qIdx !== -1 ? raw.slice(0, qIdx) : raw).toLowerCase();
8487
+ var needsSlash = false;
8488
+ if (path === prefix) needsSlash = true;
8489
+ else if (path.lastIndexOf("/") < path.length - 1 && (path.startsWith(prefixSlash) || path.endsWith(prefix))) needsSlash = true;
8490
+ if (needsSlash) {
8491
+ var qs = qIdx !== -1 ? raw.slice(qIdx) : "";
8492
+ var pathPart = qIdx !== -1 ? raw.slice(0, qIdx) : raw;
8493
+ req.url = pathPart + "/" + qs;
8494
+ }
8495
+ });
8496
+ for (var i = 0; i < listeners.length; i++) hs.on("request", listeners[i]);
8497
+ });
8498
+ prependTrailingSlashRewrite(param.server, config.basePath);
7698
8499
  param.toolbar.onAppInitialized("frontman:toolbar", () => {
7699
8500
  console.log("[Frontman] Dev toolbar app initialized");
7700
8501
  });