@frontman-ai/astro 0.4.2 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -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 Nodepath4 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
  }
@@ -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.1" ;
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);
@@ -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 = Nodepath4.normalize(sourceRoot);
3022
- let rootWithSep = endsWithSep(normalizedRoot) ? normalizedRoot : normalizedRoot + Nodepath4.sep;
3023
- if (Nodepath4.isAbsolute(inputPath)) {
3024
- let normalizedPath = Nodepath4.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 = Nodepath4.normalize(Nodepath4.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 Nodepath4.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 + Nodepath4.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 (!Nodepath4.isAbsolute(inputPath)) {
3084
- return Nodepath4.join(sourceRoot, inputPath);
3219
+ if (!Nodepath5.isAbsolute(inputPath)) {
3220
+ return Nodepath5.join(sourceRoot, inputPath);
3085
3221
  }
3086
- let normalizedPath = Nodepath4.normalize(inputPath);
3087
- let normalizedRoot = Nodepath4.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 = Nodepath4.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 = Nodepath4.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, Nodepath4.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 = Nodepath4.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) {
@@ -4230,15 +4402,40 @@ async function executeRipgrep(rgPath, pattern2, searchPath, type_, glob, caseIns
4230
4402
  }
4231
4403
  async function executeGitGrep(pattern2, searchPath, caseInsensitive, literal3, maxResults, glob, type_) {
4232
4404
  let args = buildGitGrepArgs(pattern2, caseInsensitive, literal3, maxResults, glob, type_);
4233
- 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]);
4234
4431
  if (result.TAG === "Ok") {
4235
4432
  return {
4236
4433
  TAG: "Ok",
4237
4434
  _0: parseGrepOutput(result._0.stdout, maxResults)
4238
4435
  };
4239
4436
  }
4240
- let match = result._0;
4241
- let code = match.code;
4437
+ let match$1 = result._0;
4438
+ let code = match$1.code;
4242
4439
  if (code === 1) {
4243
4440
  return {
4244
4441
  TAG: "Ok",
@@ -4249,9 +4446,9 @@ async function executeGitGrep(pattern2, searchPath, caseInsensitive, literal3, m
4249
4446
  }
4250
4447
  };
4251
4448
  }
4252
- let stderr = match.stderr;
4449
+ let stderr = match$1.stderr;
4253
4450
  let codeStr = getOr(map(code, (c2) => c2.toString()), "unknown");
4254
- let detail = stderr === "" ? match.message : stderr;
4451
+ let detail = stderr === "" ? match$1.message : stderr;
4255
4452
  return {
4256
4453
  TAG: "Error",
4257
4454
  _0: `Git grep failed (exit ` + codeStr + `): ` + detail
@@ -4336,36 +4533,31 @@ async function execute5(ctx2, input) {
4336
4533
  return await gitGrepWithFallback();
4337
4534
  }
4338
4535
  }
4339
- 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.
4340
4537
 
4341
- WHEN TO USE THIS TOOL:
4342
- - Use when you need to find files containing specific text or patterns
4343
- - Great for searching code bases for function names, variable declarations, or error messages
4344
- - 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.
4345
4539
 
4346
4540
  PARAMETERS:
4347
- - pattern (required): The text or regex pattern to search for
4348
- - path (optional): Directory to search in (defaults to source root)
4349
- - type (optional): File type filter (e.g., "js", "ts", "py", "go")
4350
- - 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}")
4351
4545
  - case_insensitive (optional): Case insensitive search (default: false)
4352
4546
  - literal (optional): Treat pattern as literal text, not regex (default: false)
4353
4547
  - max_results (optional): Maximum number of results to return (default: 20)
4354
4548
 
4355
4549
  EXAMPLES:
4356
- - Find "function" in JavaScript files: pattern="function", type="js"
4357
- - Find imports: pattern="import.*from", glob="*.ts"
4358
- - Case-insensitive search: pattern="error", case_insensitive=true
4359
- - 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
4360
4554
 
4361
4555
  OUTPUT:
4362
- Returns matching lines grouped by file, with line numbers and content.
4363
- 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).
4364
4557
 
4365
4558
  LIMITATIONS:
4366
- - Results limited to max_results (default 20)
4367
- - Binary files are automatically skipped
4368
- - Hidden files (starting with '.') are skipped by default`;
4559
+ - Results capped at max_results (default 20) files
4560
+ - Binary files and hidden files (dotfiles) are skipped`;
4369
4561
 
4370
4562
  // ../../node_modules/@rescript/runtime/lib/es6/Stdlib_JSON.js
4371
4563
  function bool3(json3) {
@@ -4419,7 +4611,7 @@ function compare(s1, s2) {
4419
4611
  }
4420
4612
  async function pathExists(path) {
4421
4613
  try {
4422
- await Fs.promises.access(path);
4614
+ await Fs7.promises.access(path);
4423
4615
  return true;
4424
4616
  } catch (exn) {
4425
4617
  return false;
@@ -4592,7 +4784,7 @@ function buildWorkspacePathLookup(workspaces) {
4592
4784
  }
4593
4785
  async function readJsonFile(path) {
4594
4786
  try {
4595
- let content = await Fs.promises.readFile(path, "utf8");
4787
+ let content = await Fs7.promises.readFile(path, "utf8");
4596
4788
  return {
4597
4789
  TAG: "Ok",
4598
4790
  _0: JSON.parse(content)
@@ -4607,7 +4799,7 @@ async function readJsonFile(path) {
4607
4799
  }
4608
4800
  }
4609
4801
  async function readPackageName(dirPath) {
4610
- let pkgPath = Nodepath4.join(dirPath, "package.json");
4802
+ let pkgPath = Nodepath5.join(dirPath, "package.json");
4611
4803
  let json3 = await readJsonFile(pkgPath);
4612
4804
  if (json3.TAG !== "Ok") {
4613
4805
  return;
@@ -4642,12 +4834,12 @@ async function resolveWorkspaceGlobs(rootPath, globs) {
4642
4834
  await Promise.all(globs.map(async (glob) => {
4643
4835
  if (glob.endsWith("/*")) {
4644
4836
  let parentDir = glob.slice(0, glob.length - 2 | 0);
4645
- let fullParent = Nodepath4.join(rootPath, parentDir);
4837
+ let fullParent = Nodepath5.join(rootPath, parentDir);
4646
4838
  try {
4647
- let entries = await Fs.promises.readdir(fullParent);
4839
+ let entries = await Fs7.promises.readdir(fullParent);
4648
4840
  await Promise.all(entries.map(async (entry) => {
4649
- let entryPath = Nodepath4.join(fullParent, entry);
4650
- let stats = await Fs.promises.stat(entryPath);
4841
+ let entryPath = Nodepath5.join(fullParent, entry);
4842
+ let stats = await Fs7.promises.stat(entryPath);
4651
4843
  if (stats.isDirectory()) {
4652
4844
  results.push(parentDir + "/" + entry);
4653
4845
  return;
@@ -4661,7 +4853,7 @@ async function resolveWorkspaceGlobs(rootPath, globs) {
4661
4853
  return;
4662
4854
  }
4663
4855
  } else {
4664
- let fullPath = Nodepath4.join(rootPath, glob);
4856
+ let fullPath = Nodepath5.join(rootPath, glob);
4665
4857
  if (await pathExists(fullPath)) {
4666
4858
  results.push(glob);
4667
4859
  return;
@@ -4673,18 +4865,18 @@ async function resolveWorkspaceGlobs(rootPath, globs) {
4673
4865
  return results;
4674
4866
  }
4675
4867
  async function detectMonorepo(rootPath) {
4676
- let pkgJsonResult = await readJsonFile(Nodepath4.join(rootPath, "package.json"));
4868
+ let pkgJsonResult = await readJsonFile(Nodepath5.join(rootPath, "package.json"));
4677
4869
  let workspaceGlobs;
4678
4870
  workspaceGlobs = pkgJsonResult.TAG === "Ok" ? extractWorkspaceGlobs(pkgJsonResult._0) : void 0;
4679
- let hasTurbo = await pathExists(Nodepath4.join(rootPath, "turbo.json"));
4680
- let hasNx = await pathExists(Nodepath4.join(rootPath, "nx.json"));
4681
- let hasPnpmWorkspace = await pathExists(Nodepath4.join(rootPath, "pnpm-workspace.yaml"));
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"));
4682
4874
  let monorepoType = hasTurbo ? "turborepo" : hasNx ? "nx" : hasPnpmWorkspace ? "pnpm-workspaces" : workspaceGlobs !== void 0 ? "npm-workspaces" : void 0;
4683
4875
  let workspaces;
4684
4876
  if (workspaceGlobs !== void 0) {
4685
4877
  let resolvedPaths = await resolveWorkspaceGlobs(rootPath, workspaceGlobs);
4686
4878
  workspaces = await Promise.all(resolvedPaths.map(async (wsPath) => {
4687
- let fullPath = Nodepath4.join(rootPath, wsPath);
4879
+ let fullPath = Nodepath5.join(rootPath, wsPath);
4688
4880
  let n = await readPackageName(fullPath);
4689
4881
  let name15 = n !== void 0 ? n : wsPath;
4690
4882
  return {
@@ -4732,15 +4924,22 @@ async function execute6(ctx2, input) {
4732
4924
  _0: formatError(err._0)
4733
4925
  };
4734
4926
  }
4927
+ let result = err._0;
4735
4928
  try {
4736
- let fullPath = err._0.resolvedPath;
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
+ }
4737
4936
  let filesResult = await getTrackedFiles(fullPath);
4738
4937
  let files;
4739
4938
  if (filesResult.TAG === "Ok") {
4740
4939
  files = filesResult._0;
4741
4940
  } else {
4742
4941
  console.warn(`ListTree: ` + filesResult._0 + `, falling back to readdir`);
4743
- files = await Fs.promises.readdir(fullPath);
4942
+ files = await Fs7.promises.readdir(fullPath);
4744
4943
  }
4745
4944
  let trie = buildTrie(files);
4746
4945
  let monoInfo = await detectMonorepo(fullPath);
@@ -4755,30 +4954,24 @@ async function execute6(ctx2, input) {
4755
4954
  }
4756
4955
  };
4757
4956
  } catch (raw_exn) {
4758
- let exn = internalToException(raw_exn);
4759
- let msg = getOr(flatMap(fromException(exn), message2), "Unknown error");
4957
+ let exn$1 = internalToException(raw_exn);
4958
+ let msg = getOr(flatMap(fromException(exn$1), message2), "Unknown error");
4760
4959
  return {
4761
4960
  TAG: "Error",
4762
4961
  _0: `Failed to list tree for ` + path + `: ` + msg
4763
4962
  };
4764
4963
  }
4765
4964
  }
4766
- var description6 = `Returns a text tree view of the project directory structure with monorepo workspace detection.
4965
+ var description6 = `Returns a **recursive directory tree** of the project structure, with monorepo workspace detection.
4767
4966
 
4768
- WHEN TO USE THIS TOOL:
4769
- - Getting oriented in an unfamiliar codebase
4770
- - Understanding monorepo workspace layout and boundaries
4771
- - Exploring a specific subdirectory's structure in depth
4772
- - Prefer this over chaining multiple list_files calls for structure discovery
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.
4773
4968
 
4774
4969
  PARAMETERS:
4775
- - path (optional): Subdirectory to root the tree at. Defaults to "." (project root).
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.
4776
4971
  - depth (optional): Maximum directory depth to display. Defaults to 3.
4777
4972
 
4778
4973
  OUTPUT:
4779
- Returns a text tree with directories and files. Directories end with /.
4780
- Workspace roots are annotated with [workspace: name].
4781
- Respects .gitignore. Skips node_modules, .git, dist, build, etc.`;
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.`;
4782
4975
  var name8 = ToolNames.readFile;
4783
4976
  var inputSchema7 = schema2((s2) => ({
4784
4977
  path: s2.m(string2),
@@ -4808,13 +5001,13 @@ async function execute7(ctx2, input) {
4808
5001
  }
4809
5002
  let result = err._0;
4810
5003
  try {
4811
- let content = await Fs.promises.readFile(result.resolvedPath, "utf8");
5004
+ let content = await Fs7.promises.readFile(result.resolvedPath, "utf8");
4812
5005
  let lines = content.split("\n");
4813
5006
  let totalLines = lines.length;
4814
5007
  let selectedLines = lines.slice(offset, offset + limit | 0);
4815
5008
  let selectedContent = selectedLines.join("\n");
4816
5009
  let hasMore = (offset + limit | 0) < totalLines;
4817
- recordRead(result.resolvedPath);
5010
+ recordRead(result.resolvedPath, offset, limit, totalLines);
4818
5011
  return {
4819
5012
  TAG: "Ok",
4820
5013
  _0: {
@@ -4845,7 +5038,12 @@ Parameters:
4845
5038
  - limit (optional): Maximum lines to read (default: 500). Pass null or 500 for default.
4846
5039
 
4847
5040
  Returns file content with metadata about total lines and whether more content exists.
4848
- 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.`;
4849
5047
 
4850
5048
  // ../../node_modules/@rescript/runtime/lib/es6/Stdlib_Result.js
4851
5049
  function map3(opt, f) {
@@ -4934,9 +5132,27 @@ async function execute8(ctx2, input) {
4934
5132
  _0: formatError(err._0)
4935
5133
  };
4936
5134
  }
5135
+ let result = err._0;
4937
5136
  try {
4938
- let fullPath = err._0.resolvedPath;
4939
- let entries = await Fs.promises.readdir(fullPath);
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);
4940
5156
  let filteredEntriesResult = map3(await getIgnoredEntries(fullPath, entries), (ignored) => entries.filter((name15) => !ignored.includes(name15)));
4941
5157
  if (filteredEntriesResult.TAG !== "Ok") {
4942
5158
  return {
@@ -4945,11 +5161,11 @@ async function execute8(ctx2, input) {
4945
5161
  };
4946
5162
  }
4947
5163
  let entriesWithStats = await Promise.all(filteredEntriesResult._0.map(async (name15) => {
4948
- let entryPath = Nodepath4.join(fullPath, name15);
4949
- let stats = await Fs.promises.stat(entryPath);
5164
+ let entryPath = Nodepath5.join(fullPath, name15);
5165
+ let stats = await Fs7.promises.stat(entryPath);
4950
5166
  return {
4951
5167
  name: name15,
4952
- path: Nodepath4.join(path, name15),
5168
+ path: Nodepath5.join(relativePath, name15),
4953
5169
  isFile: stats.isFile(),
4954
5170
  isDirectory: stats.isDirectory()
4955
5171
  };
@@ -4959,29 +5175,23 @@ async function execute8(ctx2, input) {
4959
5175
  _0: entriesWithStats
4960
5176
  };
4961
5177
  } catch (raw_exn) {
4962
- let exn = internalToException(raw_exn);
4963
- 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");
4964
5180
  return {
4965
5181
  TAG: "Error",
4966
5182
  _0: `Failed to list files in ` + path + `: ` + msg
4967
5183
  };
4968
5184
  }
4969
5185
  }
4970
- var description8 = `Lists files and directories in a single directory.
5186
+ var description8 = `Lists the **immediate contents** of a single directory \u2014 names, paths, and whether each entry is a file or directory.
4971
5187
 
4972
- WHEN TO USE THIS TOOL:
4973
- - Browsing one directory's immediate contents in detail (names, types)
4974
- - Checking what files exist in a specific directory before reading or editing
4975
- - Verifying file organization after making changes
4976
- - Use list_tree instead when you need a multi-level project overview or monorepo layout
4977
- - Use search_files instead when you need to find files by name pattern across the project
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.
4978
5189
 
4979
5190
  PARAMETERS:
4980
- - path (optional): Path to directory - either relative to source root or absolute (must be under source root). Defaults to "." (root directory).
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.
4981
5192
 
4982
5193
  OUTPUT:
4983
- Returns array of entries with name, path, and type (file or directory) information.
4984
- Respects .gitignore \u2014 ignored files are excluded from results.`;
5194
+ Array of entries, each with name, path, isFile, and isDirectory. Respects .gitignore \u2014 ignored entries are excluded.`;
4985
5195
  var name10 = ToolNames.writeFile;
4986
5196
  var inputSchema9 = schema2((s2) => ({
4987
5197
  path: s2.m(string2),
@@ -4999,10 +5209,10 @@ var outputSchema9 = schema2((s2) => ({
4999
5209
  }));
5000
5210
  function writeContent(resolvedPath, content, encoding) {
5001
5211
  if (encoding === void 0) {
5002
- return Fs.promises.writeFile(resolvedPath, content, "utf8");
5212
+ return Fs7.promises.writeFile(resolvedPath, content, "utf8");
5003
5213
  }
5004
5214
  let buffer = Nodebuffer.Buffer.from(content, "base64");
5005
- return Fs.promises.writeFile(resolvedPath, buffer);
5215
+ return Fs7.promises.writeFile(resolvedPath, buffer);
5006
5216
  }
5007
5217
  async function execute9(ctx2, input) {
5008
5218
  let match = input.content;
@@ -5033,28 +5243,45 @@ async function execute9(ctx2, input) {
5033
5243
  _0: formatError(err._0)
5034
5244
  };
5035
5245
  }
5036
- let result = err._0;
5246
+ let resolved = err._0;
5247
+ let fileExists;
5248
+ try {
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
+ }
5037
5264
  try {
5038
- await Fs.promises.mkdir(dirname3(result), {
5265
+ await Fs7.promises.mkdir(dirname4(resolved), {
5039
5266
  recursive: true
5040
5267
  });
5041
- await writeContent(result.resolvedPath, match, input.encoding);
5268
+ await writeContent(resolved.resolvedPath, match, input.encoding);
5269
+ recordWrite(resolved.resolvedPath);
5042
5270
  return {
5043
5271
  TAG: "Ok",
5044
5272
  _0: {
5045
5273
  _context: {
5046
- sourceRoot: result.sourceRoot,
5047
- resolvedPath: result.resolvedPath,
5048
- relativePath: result.relativePath
5274
+ sourceRoot: resolved.sourceRoot,
5275
+ resolvedPath: resolved.resolvedPath,
5276
+ relativePath: resolved.relativePath
5049
5277
  }
5050
5278
  }
5051
5279
  };
5052
5280
  } catch (raw_exn) {
5053
- let exn = internalToException(raw_exn);
5054
- let msg = getOr(flatMap(fromException(exn), message2), "Unknown error");
5281
+ let exn$1 = internalToException(raw_exn);
5055
5282
  return {
5056
5283
  TAG: "Error",
5057
- _0: `Failed to write file ` + input.path + `: ` + msg
5284
+ _0: `Failed to write file ` + input.path + `: ` + message3(exn$1)
5058
5285
  };
5059
5286
  }
5060
5287
  }
@@ -5068,7 +5295,8 @@ Parameters:
5068
5295
 
5069
5296
  Provide either content OR image_ref, not both.
5070
5297
  Creates parent directories if they don't exist. Overwrites existing files.
5071
- The _context field provides path resolution details for debugging.`;
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.`;
5072
5300
 
5073
5301
  // ../frontman-core/src/tools/FrontmanCore__Tool__FileExists.res.mjs
5074
5302
  var name11 = ToolNames.fileExists;
@@ -5097,7 +5325,7 @@ Parameters:
5097
5325
  Returns true if the path exists, false otherwise.`;
5098
5326
  var outputSchema10 = bool2;
5099
5327
 
5100
- // ../bindings/src/Lighthouse.res.mjs
5328
+ // ../frontman-core/src/FrontmanCore__Lighthouse.res.mjs
5101
5329
  var run = ((url2, flags2) => import('module').then(({ createRequire }) => {
5102
5330
  const req = createRequire(import.meta.url);
5103
5331
  try {
@@ -5112,7 +5340,10 @@ var run = ((url2, flags2) => import('module').then(({ createRequire }) => {
5112
5340
  }
5113
5341
  }));
5114
5342
 
5115
- // ../bindings/src/ChromeLauncher.res.mjs
5343
+ // ../frontman-core/src/FrontmanCore__ChromeLauncher.res.mjs
5344
+ function getPort(prim) {
5345
+ return prim.port;
5346
+ }
5116
5347
  var launch = ((options) => import('module').then(({ createRequire }) => {
5117
5348
  const req = createRequire(import.meta.url);
5118
5349
  try {
@@ -5136,11 +5367,6 @@ async function killSafely(chrome) {
5136
5367
  }
5137
5368
  }
5138
5369
 
5139
- // ../frontman-core/src/FrontmanCore__ExnUtils.res.mjs
5140
- function message3(exn) {
5141
- return getOr(flatMap(fromException(exn), message2), "Unknown error");
5142
- }
5143
-
5144
5370
  // ../frontman-core/src/tools/FrontmanCore__Tool__Lighthouse.res.mjs
5145
5371
  var name12 = ToolNames.lighthouse;
5146
5372
  var presetSchema = union2([
@@ -5333,7 +5559,7 @@ function processLhr(lhr) {
5333
5559
  };
5334
5560
  }
5335
5561
  async function runLighthouse(chrome, url2, preset) {
5336
- let port2 = chrome.port;
5562
+ let port2 = getPort(chrome);
5337
5563
  let formFactor = presetToString(preset);
5338
5564
  let tmp;
5339
5565
  tmp = preset === "desktop";
@@ -5479,7 +5705,7 @@ function matchesPattern(fileName2, patternLower) {
5479
5705
  function filterAndPaginate(lines, pattern2, maxResults) {
5480
5706
  let patternLower = pattern2.toLowerCase();
5481
5707
  let matchedFiles = lines.filter((filePath) => {
5482
- let fileName2 = Nodepath4.basename(filePath);
5708
+ let fileName2 = Nodepath5.basename(filePath);
5483
5709
  return matchesPattern(fileName2, patternLower);
5484
5710
  });
5485
5711
  let truncated = matchedFiles.length > maxResults;
@@ -5544,7 +5770,7 @@ async function executeGitLsFiles(pattern2, searchPath, maxResults) {
5544
5770
  };
5545
5771
  }
5546
5772
  async function execute12(ctx2, input) {
5547
- let searchPath = resolveSearchPath(ctx2.sourceRoot, input.path);
5773
+ let searchPath = await resolveSearchDir(ctx2.sourceRoot, input.path);
5548
5774
  let maxResults = getOr(input.max_results, 20);
5549
5775
  let rgPath = getRipgrepPath2();
5550
5776
  if (rgPath === void 0) {
@@ -5557,34 +5783,27 @@ async function execute12(ctx2, input) {
5557
5783
  return await executeGitLsFiles(input.pattern, searchPath, maxResults);
5558
5784
  }
5559
5785
  }
5560
- var description12 = `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.
5561
5787
 
5562
- WHEN TO USE THIS TOOL:
5563
- - Use when you need to find files by name pattern
5564
- - Great for locating specific files like "config.json" or "*.test.ts"
5565
- - Useful for finding all files with a specific extension or naming convention
5566
- - When you need to discover the file structure of a project
5567
- - 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.
5568
5789
 
5569
5790
  PARAMETERS:
5570
- - pattern (required): The filename pattern to search for (supports glob-like patterns)
5571
- - 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.
5572
5793
  - max_results (optional): Maximum number of results to return (default: 20)
5573
5794
 
5574
5795
  EXAMPLES:
5575
- - Find all config files: pattern="config"
5576
- - Find TypeScript test files: pattern="*.test.ts"
5577
- - 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"
5578
5799
 
5579
5800
  OUTPUT:
5580
- Returns list of matching file paths.
5581
- Results are sorted by modification time (newest first).
5801
+ List of matching file paths, sorted by modification time (newest first).
5582
5802
 
5583
5803
  LIMITATIONS:
5584
- - Results limited to max_results (default 20)
5585
- - Hidden files (starting with '.') are included
5586
- - Respects .gitignore when using git ls-files fallback
5587
- - Only finds files, not directories`;
5804
+ - Results capped at max_results (default 20)
5805
+ - Matches file names only, not directory names
5806
+ - Hidden files (dotfiles) are included`;
5588
5807
  var name14 = ToolNames.loadAgentInstructions;
5589
5808
  var inputSchema13 = schema2((s2) => ({
5590
5809
  startPath: s2.m(option2(string2))
@@ -5606,11 +5825,11 @@ var claudeVariants = [
5606
5825
  ];
5607
5826
  async function findFileCaseInsensitive(dir, targetFileName) {
5608
5827
  try {
5609
- let files = await Fs.promises.readdir(dir);
5828
+ let files = await Fs7.promises.readdir(dir);
5610
5829
  let targetLower = targetFileName.toLowerCase();
5611
5830
  let found = files.find((file) => file.toLowerCase() === targetLower);
5612
5831
  if (found !== void 0) {
5613
- return Nodepath4.join(dir, found);
5832
+ return Nodepath5.join(dir, found);
5614
5833
  } else {
5615
5834
  return;
5616
5835
  }
@@ -5619,14 +5838,14 @@ async function findFileCaseInsensitive(dir, targetFileName) {
5619
5838
  }
5620
5839
  }
5621
5840
  async function loadIfExists(path) {
5622
- let dir = Nodepath4.dirname(path);
5623
- let fileName2 = Nodepath4.basename(path);
5841
+ let dir = Nodepath5.dirname(path);
5842
+ let fileName2 = Nodepath5.basename(path);
5624
5843
  let actualPath = await findFileCaseInsensitive(dir, fileName2);
5625
5844
  if (actualPath === void 0) {
5626
5845
  return;
5627
5846
  }
5628
5847
  try {
5629
- let content = await Fs.promises.readFile(actualPath, "utf8");
5848
+ let content = await Fs7.promises.readFile(actualPath, "utf8");
5630
5849
  return {
5631
5850
  content,
5632
5851
  fullPath: actualPath
@@ -5639,7 +5858,7 @@ async function loadVariants(dir, variants) {
5639
5858
  let results = [];
5640
5859
  for (let i = 0, i_finish = variants.length; i < i_finish; ++i) {
5641
5860
  let variant = variants[i];
5642
- let path = Nodepath4.join(dir, variant);
5861
+ let path = Nodepath5.join(dir, variant);
5643
5862
  let file = await loadIfExists(path);
5644
5863
  if (file !== void 0) {
5645
5864
  results.push(file);
@@ -5656,7 +5875,7 @@ async function findAtDirectory(dir) {
5656
5875
  }
5657
5876
  }
5658
5877
  async function walkUpDirectories(current, acc) {
5659
- let parent = Nodepath4.dirname(current);
5878
+ let parent = Nodepath5.dirname(current);
5660
5879
  if (parent === current) {
5661
5880
  return acc;
5662
5881
  }
@@ -5886,29 +6105,54 @@ function handlePreflight() {
5886
6105
  });
5887
6106
  }
5888
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
+
5889
6120
  // ../frontman-core/src/FrontmanCore__UIShell.res.mjs
5890
6121
  function generateHTML(config) {
5891
6122
  let clientCssTag = mapOr(config.clientCssUrl, "", (url2) => `<link rel="stylesheet" href="` + url2 + `">`);
5892
6123
  let entrypointTemplate = mapOr(config.entrypointUrl, "", (url2) => `<script type="template" id="frontman-entrypoint-url">` + url2 + `</script>`);
5893
6124
  let themeClass = config.isLightTheme ? "" : "dark";
5894
- let openrouterKey = flatMap(process.env["OPENROUTER_API_KEY"], (key) => {
6125
+ let getEnvKey = (varName) => flatMap(process.env[varName], (key) => {
5895
6126
  if (key !== "") {
5896
6127
  return key;
5897
6128
  }
5898
6129
  });
6130
+ let openrouterKey = getEnvKey("OPENROUTER_API_KEY");
6131
+ let anthropicKey = getEnvKey("ANTHROPIC_API_KEY");
5899
6132
  let configObj = Object.fromEntries([
5900
6133
  [
5901
6134
  "framework",
5902
- config.frameworkLabel
6135
+ frameworkIdToString(config.frameworkId)
5903
6136
  ],
5904
6137
  [
5905
6138
  "basePath",
5906
6139
  config.basePath
6140
+ ],
6141
+ [
6142
+ "projectRoot",
6143
+ config.projectRoot
6144
+ ],
6145
+ [
6146
+ "sourceRoot",
6147
+ config.sourceRoot
5907
6148
  ]
5908
6149
  ]);
5909
6150
  forEach(openrouterKey, (key) => {
5910
6151
  configObj["openrouterKeyValue"] = key;
5911
6152
  });
6153
+ forEach(anthropicKey, (key) => {
6154
+ configObj["anthropicKeyValue"] = key;
6155
+ });
5912
6156
  let payload = JSON.stringify(configObj);
5913
6157
  let runtimeConfigScript = `<script>window.__frontmanRuntime=` + payload + `</script>`;
5914
6158
  return `<!DOCTYPE html>
@@ -5957,7 +6201,7 @@ function serveWithEntrypoint(config, entrypointUrl) {
5957
6201
  clientCssUrl: config.clientCssUrl,
5958
6202
  entrypointUrl,
5959
6203
  isLightTheme: config.isLightTheme,
5960
- frameworkLabel: config.frameworkLabel
6204
+ frameworkId: config.frameworkId
5961
6205
  } : config);
5962
6206
  }
5963
6207
 
@@ -5966,80 +6210,6 @@ function $$catch(promise, callback) {
5966
6210
  return promise.catch((err) => callback(internalToException(err)));
5967
6211
  }
5968
6212
 
5969
- // ../frontman-protocol/src/FrontmanProtocol__MCP.res.mjs
5970
- enableJson2();
5971
- var capabilitiesSchema = schema2((s2) => ({
5972
- tools: s2.m(option2(dict2(json2))),
5973
- resources: s2.m(option2(dict2(json2))),
5974
- prompts: s2.m(option2(dict2(json2)))
5975
- }));
5976
- var infoSchema = schema2((s2) => ({
5977
- name: s2.m(string2),
5978
- version: s2.m(string2)
5979
- }));
5980
- schema2((s2) => ({
5981
- protocolVersion: s2.m(string2),
5982
- capabilities: s2.m(capabilitiesSchema),
5983
- clientInfo: s2.m(infoSchema)
5984
- }));
5985
- schema2((s2) => ({
5986
- protocolVersion: s2.m(string2),
5987
- capabilities: s2.m(capabilitiesSchema),
5988
- serverInfo: s2.m(infoSchema)
5989
- }));
5990
- schema2((s2) => ({
5991
- callId: s2.m(string2),
5992
- name: s2.m(string2),
5993
- arguments: s2.m(option2(dict2(json2)))
5994
- }));
5995
- var toolResultContentSchema = schema2((s2) => ({
5996
- type: s2.m(string2),
5997
- text: s2.m(string2)
5998
- }));
5999
- schema2((s2) => ({
6000
- code: s2.m(int2),
6001
- message: s2.m(string2)
6002
- }));
6003
- var callToolResultSchema = schema2((s2) => ({
6004
- content: s2.m(array2(toolResultContentSchema)),
6005
- isError: s2.m(option2(bool2))
6006
- }));
6007
- schema2((s2) => ({
6008
- tools: s2.m(array2(json2))
6009
- }));
6010
-
6011
- // ../frontman-core/src/FrontmanCore__SSE.res.mjs
6012
- function formatEvent(eventType, data) {
6013
- return `event: ` + eventType + `
6014
- data: ` + data + `
6015
-
6016
- `;
6017
- }
6018
- function resultEvent(result) {
6019
- let data = JSON.stringify(reverseConvertToJsonOrThrow2(result, callToolResultSchema));
6020
- return formatEvent("result", data);
6021
- }
6022
- function errorEvent(result) {
6023
- let data = JSON.stringify(reverseConvertToJsonOrThrow2(result, callToolResultSchema));
6024
- return formatEvent("error", data);
6025
- }
6026
- function headers() {
6027
- return Object.fromEntries([
6028
- [
6029
- "Content-Type",
6030
- "text/event-stream"
6031
- ],
6032
- [
6033
- "Cache-Control",
6034
- "no-cache, no-transform"
6035
- ],
6036
- [
6037
- "Connection",
6038
- "keep-alive"
6039
- ]
6040
- ]);
6041
- }
6042
-
6043
6213
  // ../../node_modules/dom-element-to-component-source/dist/_commonjsHelpers-CqEciG1_.mjs
6044
6214
  function c(e) {
6045
6215
  if (Object.prototype.hasOwnProperty.call(e, "__esModule")) return e;
@@ -7649,6 +7819,102 @@ async function Te(o) {
7649
7819
  }
7650
7820
  }
7651
7821
 
7822
+ // ../frontman-protocol/src/FrontmanProtocol__Types.res.mjs
7823
+ enableJson2();
7824
+ var modelSelectionSchema = schema2((s2) => ({
7825
+ provider: s2.m(string2),
7826
+ value: s2.m(string2)
7827
+ }));
7828
+
7829
+ // ../frontman-protocol/src/FrontmanProtocol__MCP.res.mjs
7830
+ enableJson2();
7831
+ var capabilitiesSchema = schema2((s2) => ({
7832
+ tools: s2.m(option2(dict2(json2))),
7833
+ resources: s2.m(option2(dict2(json2))),
7834
+ prompts: s2.m(option2(dict2(json2)))
7835
+ }));
7836
+ var infoSchema = schema2((s2) => ({
7837
+ name: s2.m(string2),
7838
+ version: s2.m(string2)
7839
+ }));
7840
+ schema2((s2) => ({
7841
+ protocolVersion: s2.m(string2),
7842
+ capabilities: s2.m(capabilitiesSchema),
7843
+ clientInfo: s2.m(infoSchema)
7844
+ }));
7845
+ schema2((s2) => ({
7846
+ protocolVersion: s2.m(string2),
7847
+ capabilities: s2.m(capabilitiesSchema),
7848
+ serverInfo: s2.m(infoSchema)
7849
+ }));
7850
+ schema2((s2) => ({
7851
+ callId: s2.m(string2),
7852
+ name: s2.m(string2),
7853
+ arguments: s2.m(option2(dict2(json2)))
7854
+ }));
7855
+ var toolResultContentTypeSchema = union2([
7856
+ literal2("text"),
7857
+ literal2("image"),
7858
+ literal2("resource")
7859
+ ]);
7860
+ var toolResultContentSchema = schema2((s2) => ({
7861
+ type: s2.m(toolResultContentTypeSchema),
7862
+ text: s2.m(string2)
7863
+ }));
7864
+ schema2((s2) => ({
7865
+ code: s2.m(int2),
7866
+ message: s2.m(string2)
7867
+ }));
7868
+ var callToolResultMetaSchema = schema2((s2) => ({
7869
+ model: s2.m(option2(modelSelectionSchema)),
7870
+ envApiKey: s2.m(dict2(string2))
7871
+ }));
7872
+ var emptyMeta_envApiKey = {};
7873
+ var emptyMeta = {
7874
+ model: void 0,
7875
+ envApiKey: emptyMeta_envApiKey
7876
+ };
7877
+ var callToolResultSchema = schema2((s2) => ({
7878
+ content: s2.m(array2(toolResultContentSchema)),
7879
+ isError: s2.m(option2(bool2)),
7880
+ _meta: s2.m(callToolResultMetaSchema)
7881
+ }));
7882
+ schema2((s2) => ({
7883
+ tools: s2.m(array2(json2))
7884
+ }));
7885
+
7886
+ // ../frontman-core/src/FrontmanCore__SSE.res.mjs
7887
+ function formatEvent(eventType, data) {
7888
+ return `event: ` + eventType + `
7889
+ data: ` + data + `
7890
+
7891
+ `;
7892
+ }
7893
+ function resultEvent(result) {
7894
+ let data = JSON.stringify(reverseConvertToJsonOrThrow2(result, callToolResultSchema));
7895
+ return formatEvent("result", data);
7896
+ }
7897
+ function errorEvent(result) {
7898
+ let data = JSON.stringify(reverseConvertToJsonOrThrow2(result, callToolResultSchema));
7899
+ return formatEvent("error", data);
7900
+ }
7901
+ function headers() {
7902
+ return Object.fromEntries([
7903
+ [
7904
+ "Content-Type",
7905
+ "text/event-stream"
7906
+ ],
7907
+ [
7908
+ "Cache-Control",
7909
+ "no-cache, no-transform"
7910
+ ],
7911
+ [
7912
+ "Connection",
7913
+ "keep-alive"
7914
+ ]
7915
+ ]);
7916
+ }
7917
+
7652
7918
  // ../frontman-protocol/src/FrontmanProtocol__Relay.res.mjs
7653
7919
  var remoteToolSchema = schema2((s2) => ({
7654
7920
  name: s2.m(string2),
@@ -7694,7 +7960,8 @@ async function executeTool(registry, ctx2, name15, $$arguments) {
7694
7960
  type: "text",
7695
7961
  text: result._0
7696
7962
  }],
7697
- isError: true
7963
+ isError: true,
7964
+ _meta: emptyMeta
7698
7965
  }
7699
7966
  };
7700
7967
  }
@@ -7706,7 +7973,8 @@ async function executeTool(registry, ctx2, name15, $$arguments) {
7706
7973
  type: "text",
7707
7974
  text: JSON.stringify(outputJson)
7708
7975
  }],
7709
- isError: void 0
7976
+ isError: void 0,
7977
+ _meta: emptyMeta
7710
7978
  }
7711
7979
  };
7712
7980
  } catch (raw_e) {
@@ -7734,7 +8002,8 @@ function resultToMCP(result) {
7734
8002
  type: "text",
7735
8003
  text: `Tool not found: ` + result._0
7736
8004
  }],
7737
- isError: true
8005
+ isError: true,
8006
+ _meta: emptyMeta
7738
8007
  };
7739
8008
  case "InvalidInput":
7740
8009
  return {
@@ -7742,7 +8011,8 @@ function resultToMCP(result) {
7742
8011
  type: "text",
7743
8012
  text: `Invalid input: ` + result._0
7744
8013
  }],
7745
- isError: true
8014
+ isError: true,
8015
+ _meta: emptyMeta
7746
8016
  };
7747
8017
  case "ExecutionError":
7748
8018
  return {
@@ -7750,7 +8020,8 @@ function resultToMCP(result) {
7750
8020
  type: "text",
7751
8021
  text: `Execution error: ` + result._0
7752
8022
  }],
7753
- isError: true
8023
+ isError: true,
8024
+ _meta: emptyMeta
7754
8025
  };
7755
8026
  }
7756
8027
  }
@@ -7839,7 +8110,8 @@ async function handleToolCall(registry, config, req) {
7839
8110
  let errorResult_isError2 = true;
7840
8111
  let errorResult2 = {
7841
8112
  content: errorResult_content2,
7842
- isError: errorResult_isError2
8113
+ isError: errorResult_isError2,
8114
+ _meta: emptyMeta
7843
8115
  };
7844
8116
  controller.enqueue(encoder.encode(errorEvent(errorResult2)));
7845
8117
  controller.close();
@@ -7858,7 +8130,8 @@ async function handleToolCall(registry, config, req) {
7858
8130
  let errorResult_isError = true;
7859
8131
  let errorResult = {
7860
8132
  content: errorResult_content,
7861
- isError: errorResult_isError
8133
+ isError: errorResult_isError,
8134
+ _meta: emptyMeta
7862
8135
  };
7863
8136
  let json3 = reverseConvertToJsonOrThrow2(errorResult, callToolResultSchema);
7864
8137
  return Response.json(json3, {
@@ -7966,19 +8239,19 @@ function isFrontmanRoute(pathname, basePath, method) {
7966
8239
  function getCanonicalRedirect(prefixPath, basePath) {
7967
8240
  let suffix = "/" + basePath;
7968
8241
  if (prefixPath === basePath) {
7969
- return "/" + basePath;
8242
+ return "/" + basePath + "/";
7970
8243
  }
7971
8244
  if (prefixPath.endsWith(suffix)) {
7972
8245
  let stripped = prefixPath.slice(0, prefixPath.length - suffix.length | 0);
7973
8246
  let cleanPrefix = stripped === "" ? "" : stripped;
7974
- let tmp = cleanPrefix === "" ? "/" + basePath : "/" + cleanPrefix + "/" + basePath;
8247
+ let tmp = cleanPrefix === "" ? "/" + basePath + "/" : "/" + cleanPrefix + "/" + basePath + "/";
7975
8248
  return tmp;
7976
8249
  }
7977
8250
  if (!prefixPath.startsWith(basePath + "/")) {
7978
8251
  return;
7979
8252
  }
7980
- let rest = prefixPath.slice(basePath.length + 1 | 0);
7981
- let tmp$1 = rest === "" ? "/" + basePath : "/" + rest + "/" + basePath;
8253
+ let rest = prefixPath.slice(basePath.length + 1 | 0, prefixPath.length);
8254
+ let tmp$1 = rest === "" ? "/" + basePath + "/" : "/" + rest + "/" + basePath + "/";
7982
8255
  return tmp$1;
7983
8256
  }
7984
8257
  function buildEntrypointUrl(config, requestUrl, prefixPath) {
@@ -7988,7 +8261,7 @@ function buildEntrypointUrl(config, requestUrl, prefixPath) {
7988
8261
  }
7989
8262
  let url2 = new URL(requestUrl);
7990
8263
  let origin = url2.origin;
7991
- let pagePath = prefixPath === "" ? "/" : "/" + prefixPath;
8264
+ let pagePath = prefixPath === "" ? "/" : "/" + prefixPath + "/";
7992
8265
  return origin + pagePath;
7993
8266
  }
7994
8267
  function createMiddleware(config, registry) {
@@ -8077,7 +8350,7 @@ function toMiddlewareConfig(config) {
8077
8350
  clientCssUrl: config.clientCssUrl,
8078
8351
  entrypointUrl: config.entrypointUrl,
8079
8352
  isLightTheme: config.isLightTheme,
8080
- frameworkLabel: "Astro"
8353
+ frameworkId: "Astro"
8081
8354
  };
8082
8355
  }
8083
8356
  function createMiddleware2(config) {
@@ -8086,7 +8359,7 @@ function createMiddleware2(config) {
8086
8359
  return createMiddleware(middlewareConfig, registry);
8087
8360
  }
8088
8361
 
8089
- // ../bindings/src/NodeHttp.res.mjs
8362
+ // src/FrontmanAstro__ViteAdapter.res.mjs
8090
8363
  var collectRequestBody = (async function(req) {
8091
8364
  const chunks = [];
8092
8365
  for await (const chunk of req) {
@@ -8095,8 +8368,6 @@ var collectRequestBody = (async function(req) {
8095
8368
  const { Buffer: Buffer4 } = await import('buffer');
8096
8369
  return Buffer4.concat(chunks);
8097
8370
  });
8098
-
8099
- // src/FrontmanAstro__ViteAdapter.res.mjs
8100
8371
  var copyHeaders = (function(headers2, res) {
8101
8372
  headers2.forEach(function(value, key) {
8102
8373
  res.setHeader(key, value);
@@ -8186,7 +8457,7 @@ function adaptToConnect(middleware, basePath) {
8186
8457
 
8187
8458
  // src/FrontmanAstro__Integration.res.mjs
8188
8459
  var annotationCaptureScript2 = annotationCaptureScript;
8189
- var icon = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="3"/></svg>`;
8460
+ var icon = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="90 70 230 270" fill="none"><path d="M145.925 316.925C136.175 316.925 129.242 315.517 125.125 312.7C121.008 309.667 118.517 305.875 117.65 301.325C116.783 296.558 116.35 291.792 116.35 287.025V119C116.35 107.733 118.517 100.042 122.85 95.925C127.4 91.5917 135.417 89.425 146.9 89.425H265.85C270.833 89.425 275.492 89.8583 279.825 90.725C284.375 91.5917 288.058 94.0833 290.875 98.2C293.692 102.317 295.1 109.358 295.1 119.325C295.1 129.075 293.583 136.008 290.55 140.125C287.733 144.242 284.05 146.733 279.5 147.6C274.95 148.467 270.183 148.9 265.2 148.9H175.825V177.825H235.625C240.608 177.825 245.05 178.258 248.95 179.125C253.067 179.775 256.208 181.942 258.375 185.625C260.758 189.092 261.95 195.158 261.95 203.825C261.95 212.058 260.758 217.908 258.375 221.375C255.992 224.842 252.742 226.9 248.625 227.55C244.725 228.2 240.283 228.525 235.3 228.525H175.825V287.35C175.825 292.117 175.392 296.775 174.525 301.325C173.658 305.875 171.167 309.667 167.05 312.7C162.933 315.517 155.892 316.925 145.925 316.925Z" fill="currentColor"/></svg>`;
8190
8461
  function getToolbarAppPath() {
8191
8462
  return new URL("./toolbar.js", import.meta.url).pathname;
8192
8463
  }
@@ -8236,6 +8507,29 @@ function make5(configInput) {
8236
8507
  },
8237
8508
  "astro:server:setup": (param) => {
8238
8509
  initialize();
8510
+ let prependTrailingSlashRewrite = (function(server, basePath) {
8511
+ var hs = server.httpServer;
8512
+ if (!hs) return;
8513
+ var prefix = "/" + basePath.toLowerCase();
8514
+ var prefixSlash = prefix + "/";
8515
+ var listeners = hs.listeners("request").slice();
8516
+ hs.removeAllListeners("request");
8517
+ hs.on("request", function(req) {
8518
+ var raw = req.url || "";
8519
+ var qIdx = raw.indexOf("?");
8520
+ var path = (qIdx !== -1 ? raw.slice(0, qIdx) : raw).toLowerCase();
8521
+ var needsSlash = false;
8522
+ if (path === prefix) needsSlash = true;
8523
+ else if (path.lastIndexOf("/") < path.length - 1 && (path.startsWith(prefixSlash) || path.endsWith(prefix))) needsSlash = true;
8524
+ if (needsSlash) {
8525
+ var qs = qIdx !== -1 ? raw.slice(qIdx) : "";
8526
+ var pathPart = qIdx !== -1 ? raw.slice(0, qIdx) : raw;
8527
+ req.url = pathPart + "/" + qs;
8528
+ }
8529
+ });
8530
+ for (var i = 0; i < listeners.length; i++) hs.on("request", listeners[i]);
8531
+ });
8532
+ prependTrailingSlashRewrite(param.server, config.basePath);
8239
8533
  param.toolbar.onAppInitialized("frontman:toolbar", () => {
8240
8534
  console.log("[Frontman] Dev toolbar app initialized");
8241
8535
  });