@humanlayer/agentlayer-justbash 0.0.7

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 (61) hide show
  1. package/dist/index.d.ts +3 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +630 -0
  4. package/dist/index.js.map +22 -0
  5. package/dist/prompts/index.d.ts +29 -0
  6. package/dist/prompts/index.d.ts.map +1 -0
  7. package/dist/prompts/index.js +123 -0
  8. package/dist/prompts/index.js.map +10 -0
  9. package/dist/tools/apply-patch.d.ts +9 -0
  10. package/dist/tools/apply-patch.d.ts.map +1 -0
  11. package/dist/tools/bash.d.ts +8 -0
  12. package/dist/tools/bash.d.ts.map +1 -0
  13. package/dist/tools/code-search.d.ts +12 -0
  14. package/dist/tools/code-search.d.ts.map +1 -0
  15. package/dist/tools/edit.d.ts +12 -0
  16. package/dist/tools/edit.d.ts.map +1 -0
  17. package/dist/tools/glob.d.ts +6 -0
  18. package/dist/tools/glob.d.ts.map +1 -0
  19. package/dist/tools/grep.d.ts +8 -0
  20. package/dist/tools/grep.d.ts.map +1 -0
  21. package/dist/tools/index.d.ts +13 -0
  22. package/dist/tools/index.d.ts.map +1 -0
  23. package/dist/tools/index.js +510 -0
  24. package/dist/tools/index.js.map +21 -0
  25. package/dist/tools/list.d.ts +7 -0
  26. package/dist/tools/list.d.ts.map +1 -0
  27. package/dist/tools/read.d.ts +7 -0
  28. package/dist/tools/read.d.ts.map +1 -0
  29. package/dist/tools/skill.d.ts +10 -0
  30. package/dist/tools/skill.d.ts.map +1 -0
  31. package/dist/tools/web-fetch.d.ts +7 -0
  32. package/dist/tools/web-fetch.d.ts.map +1 -0
  33. package/dist/tools/web-search.d.ts +16 -0
  34. package/dist/tools/web-search.d.ts.map +1 -0
  35. package/dist/tools/write.d.ts +6 -0
  36. package/dist/tools/write.d.ts.map +1 -0
  37. package/package.json +59 -0
  38. package/src/index.ts +2 -0
  39. package/src/prompts/index.ts +161 -0
  40. package/src/tools/apply-patch.ts +121 -0
  41. package/src/tools/apply-patch.txt +35 -0
  42. package/src/tools/bash.ts +20 -0
  43. package/src/tools/bash.txt +114 -0
  44. package/src/tools/code-search.ts +119 -0
  45. package/src/tools/edit.ts +58 -0
  46. package/src/tools/edit.txt +10 -0
  47. package/src/tools/glob.ts +33 -0
  48. package/src/tools/glob.txt +6 -0
  49. package/src/tools/grep.ts +53 -0
  50. package/src/tools/grep.txt +8 -0
  51. package/src/tools/index.ts +12 -0
  52. package/src/tools/list.ts +41 -0
  53. package/src/tools/list.txt +5 -0
  54. package/src/tools/read.ts +16 -0
  55. package/src/tools/read.txt +14 -0
  56. package/src/tools/skill.ts +49 -0
  57. package/src/tools/web-fetch.ts +97 -0
  58. package/src/tools/web-fetch.txt +10 -0
  59. package/src/tools/web-search.ts +59 -0
  60. package/src/tools/write.ts +26 -0
  61. package/src/tools/write.txt +8 -0
@@ -0,0 +1,3 @@
1
+ export * from './prompts/index';
2
+ export * from './tools';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,SAAS,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,630 @@
1
+ // src/prompts/index.ts
2
+ import { resolve } from "node:path";
3
+ import {
4
+ createAgentSystemPrompt as createCoreAgentSystemPrompt,
5
+ environmentPrompt as createEnvironmentPrompt,
6
+ repoInstructionsPrompt as createRepoInstructionsPrompt
7
+ } from "@humanlayer/agentlayer-core/prompts";
8
+ import {
9
+ buildCodingProviderOptions,
10
+ detectModelFamily,
11
+ getSystemPromptForModel,
12
+ resolveCodingModelPrompt,
13
+ systemPrompts,
14
+ tarsPersona
15
+ } from "@humanlayer/agentlayer-core/prompts";
16
+ var DEFAULT_REPO_INSTRUCTION_CANDIDATES = ["CLAUDE.md", "AGENTS.md", "CONTEXT.md"];
17
+ async function getRepoRoot(bash, cwd) {
18
+ const result = await bash.exec(`git -C "${cwd}" rev-parse --show-toplevel 2>/dev/null`);
19
+ if (result.exitCode !== 0)
20
+ return;
21
+ const root = result.stdout.trim();
22
+ return root.length > 0 ? root : undefined;
23
+ }
24
+ async function readFileIfExists(bash, filePath) {
25
+ const result = await bash.exec(`cat "${filePath}" 2>/dev/null`);
26
+ if (result.exitCode !== 0)
27
+ return;
28
+ return result.stdout;
29
+ }
30
+ async function firstExistingCandidate(bash, cwd, candidates) {
31
+ for (const candidate of candidates) {
32
+ const filePath = `${cwd}/${candidate}`;
33
+ const contents = await readFileIfExists(bash, filePath);
34
+ if (contents !== undefined)
35
+ return filePath;
36
+ }
37
+ return;
38
+ }
39
+ async function findRepoInstructions(bash, startCwd, candidates, skipRepoRootFallback) {
40
+ const cwdPath = await firstExistingCandidate(bash, startCwd, candidates);
41
+ if (cwdPath) {
42
+ const contents = await readFileIfExists(bash, cwdPath);
43
+ if (contents?.trim()) {
44
+ return { path: cwdPath, contents };
45
+ }
46
+ }
47
+ if (!skipRepoRootFallback) {
48
+ const repoRoot = await getRepoRoot(bash, startCwd);
49
+ if (repoRoot && repoRoot !== startCwd) {
50
+ const rootPath = await firstExistingCandidate(bash, repoRoot, candidates);
51
+ if (rootPath) {
52
+ const contents = await readFileIfExists(bash, rootPath);
53
+ if (contents?.trim()) {
54
+ return { path: rootPath, contents };
55
+ }
56
+ }
57
+ }
58
+ }
59
+ return;
60
+ }
61
+ async function environmentPrompt(bash, opts) {
62
+ const isGitRepo = opts.isGitRepo ?? await getRepoRoot(bash, opts.cwd) !== undefined;
63
+ return createEnvironmentPrompt({
64
+ cwd: opts.cwd,
65
+ isGitRepo,
66
+ platform: opts.platform,
67
+ date: opts.date
68
+ });
69
+ }
70
+ async function repoInstructionsPrompt(bash, opts) {
71
+ if (opts.filePath) {
72
+ const filePath = opts.filePath.startsWith("/") ? opts.filePath : resolve(opts.cwd, opts.filePath);
73
+ const contents = await readFileIfExists(bash, filePath);
74
+ if (!contents?.trim()) {
75
+ if (opts.allowMissing)
76
+ return;
77
+ throw new Error(`Repo instructions file is empty: ${filePath}`);
78
+ }
79
+ return createRepoInstructionsPrompt({ path: filePath, contents });
80
+ }
81
+ const candidates = opts.candidates ?? DEFAULT_REPO_INSTRUCTION_CANDIDATES;
82
+ const found = await findRepoInstructions(bash, opts.cwd, candidates, opts._skipRepoRootFallback ?? false);
83
+ if (!found) {
84
+ if (opts.allowMissing)
85
+ return;
86
+ const repoRoot = await getRepoRoot(bash, opts.cwd);
87
+ const searched = repoRoot ? [`${opts.cwd} (cwd)`, `${repoRoot} (repo root)`] : [opts.cwd];
88
+ throw new Error(`No repo instructions found. Searched for ${candidates.join(", ")} in: ${searched.join(", ")}`);
89
+ }
90
+ return createRepoInstructionsPrompt(found);
91
+ }
92
+ async function createAgentSystemPrompt(opts) {
93
+ const repoInstructions = await repoInstructionsPrompt(opts.bash, {
94
+ cwd: opts.cwd,
95
+ filePath: opts.filePath,
96
+ candidates: opts.candidates,
97
+ allowMissing: opts.allowMissingRepoInstructions ?? true
98
+ });
99
+ const environment = opts.includeEnvironment === false ? undefined : await environmentPrompt(opts.bash, {
100
+ cwd: opts.cwd,
101
+ platform: opts.platform,
102
+ date: opts.date
103
+ });
104
+ return createCoreAgentSystemPrompt({
105
+ model: opts.model,
106
+ repoInstructions,
107
+ environment,
108
+ systemPromptAdditions: opts.systemPromptAdditions
109
+ });
110
+ }
111
+
112
+ // src/tools/apply-patch.ts
113
+ import { isAbsolute, resolve as resolve2 } from "node:path";
114
+ import { ApplyPatchTool } from "@humanlayer/agentlayer-core/interfaces";
115
+ import { APPLY_PATCH_DESCRIPTION } from "@humanlayer/agentlayer-core/prompts";
116
+ import { applyUpdateChunks, parsePatch, validateHunks } from "@humanlayer/agentlayer-core/utils";
117
+ function createApplyPatchTool(bash, opts = {}) {
118
+ const { cwd } = opts;
119
+ const _resolvePath = (filePath) => {
120
+ if (!cwd || isAbsolute(filePath)) {
121
+ return filePath;
122
+ }
123
+ return resolve2(cwd, filePath);
124
+ };
125
+ return ApplyPatchTool.define(async (input) => {
126
+ const { patch_text } = input;
127
+ if (!patch_text || !patch_text.trim()) {
128
+ throw new Error("patch_text is required");
129
+ }
130
+ let ops;
131
+ try {
132
+ ops = parsePatch(patch_text);
133
+ } catch (err) {
134
+ throw new Error(`apply_patch verification failed: ${err}`);
135
+ }
136
+ if (ops.length === 0) {
137
+ throw new Error("patch rejected: empty patch");
138
+ }
139
+ const hasHunks = ops.some((op) => op.type === "add" || op.chunks.length > 0 || op.type === "delete");
140
+ if (!hasHunks) {
141
+ throw new Error("apply_patch verification failed: no hunks found");
142
+ }
143
+ const readFile = async (filePath) => {
144
+ const result = await bash.exec(`cat "${filePath}"`);
145
+ if (result.exitCode !== 0) {
146
+ throw new Error(`File not found: ${filePath}`);
147
+ }
148
+ return result.stdout;
149
+ };
150
+ await validateHunks(ops, readFile);
151
+ const results = [];
152
+ for (const op of ops) {
153
+ if (op.type === "add") {
154
+ const filePath = op.filePath;
155
+ const mkdirResult = await bash.exec(`mkdir -p "$(dirname "${filePath}")"`);
156
+ if (mkdirResult.exitCode !== 0) {
157
+ throw new Error(`Failed to create parent directory for ${filePath}: ${mkdirResult.stderr}`);
158
+ }
159
+ const DELIM = "PATCHEOF_8f3a2b1c";
160
+ const content = op.addContent ?? "";
161
+ const writeResult = await bash.exec(`cat > "${filePath}" <<'${DELIM}'
162
+ ${content}
163
+ ${DELIM}`);
164
+ if (writeResult.exitCode !== 0) {
165
+ throw new Error(`Failed to write file ${filePath}: ${writeResult.stderr}`);
166
+ }
167
+ results.push(`Added ${filePath}`);
168
+ } else if (op.type === "update") {
169
+ const content = await readFile(op.filePath);
170
+ const updated = applyUpdateChunks(content, op.chunks);
171
+ const DELIM = "PATCHEOF_8f3a2b1c";
172
+ const writeResult = await bash.exec(`cat > "${op.filePath}" <<'${DELIM}'
173
+ ${updated}
174
+ ${DELIM}`);
175
+ if (writeResult.exitCode !== 0) {
176
+ throw new Error(`Failed to write file ${op.filePath}: ${writeResult.stderr}`);
177
+ }
178
+ results.push(`Updated ${op.filePath}`);
179
+ } else if (op.type === "move") {
180
+ const content = await readFile(op.filePath);
181
+ const updated = applyUpdateChunks(content, op.chunks);
182
+ const targetPath = op.targetPath;
183
+ const mkdirResult = await bash.exec(`mkdir -p "$(dirname "${targetPath}")"`);
184
+ if (mkdirResult.exitCode !== 0) {
185
+ throw new Error(`Failed to create parent directory for ${targetPath}: ${mkdirResult.stderr}`);
186
+ }
187
+ const DELIM = "PATCHEOF_8f3a2b1c";
188
+ const writeResult = await bash.exec(`cat > "${targetPath}" <<'${DELIM}'
189
+ ${updated}
190
+ ${DELIM}`);
191
+ if (writeResult.exitCode !== 0) {
192
+ throw new Error(`Failed to write file ${targetPath}: ${writeResult.stderr}`);
193
+ }
194
+ const rmResult = await bash.exec(`rm "${op.filePath}"`);
195
+ if (rmResult.exitCode !== 0) {
196
+ throw new Error(`Failed to remove original file ${op.filePath}: ${rmResult.stderr}`);
197
+ }
198
+ results.push(`Moved ${op.filePath} → ${targetPath}`);
199
+ } else if (op.type === "delete") {
200
+ const rmResult = await bash.exec(`rm "${op.filePath}"`);
201
+ if (rmResult.exitCode !== 0) {
202
+ throw new Error(`Failed to delete file ${op.filePath}: ${rmResult.stderr}`);
203
+ }
204
+ results.push(`Deleted ${op.filePath}`);
205
+ }
206
+ }
207
+ return results.join(`
208
+ `);
209
+ }, { description: APPLY_PATCH_DESCRIPTION });
210
+ }
211
+ // src/tools/bash.ts
212
+ import { BashTool } from "@humanlayer/agentlayer-core/interfaces";
213
+ import { BASH_DESCRIPTION } from "@humanlayer/agentlayer-core/prompts";
214
+ import { truncateOutput } from "@humanlayer/agentlayer-core/utils";
215
+ function createJustBashTool(bash) {
216
+ return BashTool.define(async (input) => {
217
+ const result = await bash.exec(input.command, {
218
+ ...input.workdir ? { cwd: input.workdir } : {}
219
+ });
220
+ let output = result.stdout;
221
+ if (result.stderr) {
222
+ output += `
223
+ STDERR: ${result.stderr}`;
224
+ }
225
+ return truncateOutput(`Exit code: ${result.exitCode}
226
+ ${output}`);
227
+ }, { description: BASH_DESCRIPTION });
228
+ }
229
+ // src/tools/code-search.ts
230
+ import { CodeSearchTool } from "@humanlayer/agentlayer-core/interfaces";
231
+ import { CODE_SEARCH_DESCRIPTION } from "@humanlayer/agentlayer-core/prompts";
232
+ var DEFAULT_TIMEOUT_SEC = 30;
233
+ var CONTEXT7_BASE_URL = "https://context7.com";
234
+ async function fetchExaViaBash(bash, input, apiKey, timeoutSec) {
235
+ try {
236
+ const query = `${input.query} -- for ${input.packageName} in ${input.language}`;
237
+ const payload = JSON.stringify({ query, tokensNum: 5000 });
238
+ const escapedPayload = payload.replace(/'/g, "'\\''");
239
+ const result = await bash.exec(`curl -s --max-time ${timeoutSec} ` + `-H "Content-Type: application/json" ` + `-H "x-api-key: ${apiKey}" ` + `-d '${escapedPayload}' ` + `https://api.exa.ai/context`);
240
+ if (result.exitCode !== 0)
241
+ return null;
242
+ const data = JSON.parse(result.stdout);
243
+ return data.response ?? null;
244
+ } catch {
245
+ return null;
246
+ }
247
+ }
248
+ async function fetchContext7ViaBash(bash, input, apiKey, timeoutSec) {
249
+ try {
250
+ const searchQuery = encodeURIComponent(input.query);
251
+ const libName = encodeURIComponent(input.packageName);
252
+ const searchResult = await bash.exec(`curl -s --max-time ${timeoutSec} ` + `-H "Authorization: Bearer ${apiKey}" ` + `"${CONTEXT7_BASE_URL}/api/v2/libs/search?query=${searchQuery}&libraryName=${libName}"`);
253
+ if (searchResult.exitCode !== 0)
254
+ return null;
255
+ const searchData = JSON.parse(searchResult.stdout);
256
+ const libraries = searchData.results ?? [];
257
+ if (libraries.length === 0)
258
+ return null;
259
+ const best = libraries.reduce((a, b) => (b.trustScore ?? 0) > (a.trustScore ?? 0) ? b : a);
260
+ const contextQuery = encodeURIComponent(input.query);
261
+ const libId = encodeURIComponent(best.id);
262
+ const contextResult = await bash.exec(`curl -s --max-time ${timeoutSec} ` + `-H "Authorization: Bearer ${apiKey}" ` + `"${CONTEXT7_BASE_URL}/api/v2/context?query=${contextQuery}&libraryId=${libId}"`);
263
+ if (contextResult.exitCode !== 0)
264
+ return null;
265
+ return contextResult.stdout;
266
+ } catch {
267
+ return null;
268
+ }
269
+ }
270
+ function createCodeSearchTool(bash, opts) {
271
+ if (!opts.exaApiKey && !opts.context7ApiKey) {
272
+ throw new Error("At least one API key (exaApiKey or context7ApiKey) is required");
273
+ }
274
+ const timeoutSec = opts.timeoutSec ?? DEFAULT_TIMEOUT_SEC;
275
+ return CodeSearchTool.define(async (input) => {
276
+ const [exaResult, c7Result] = await Promise.all([
277
+ opts.exaApiKey ? fetchExaViaBash(bash, input, opts.exaApiKey, timeoutSec) : Promise.resolve(null),
278
+ opts.context7ApiKey ? fetchContext7ViaBash(bash, input, opts.context7ApiKey, timeoutSec) : Promise.resolve(null)
279
+ ]);
280
+ const parts = [];
281
+ if (c7Result) {
282
+ parts.push(`## Context7 Documentation
283
+
284
+ ${c7Result}`);
285
+ }
286
+ if (exaResult) {
287
+ parts.push(`## Exa Search Results
288
+
289
+ ${exaResult}`);
290
+ }
291
+ if (parts.length === 0) {
292
+ return `No documentation found for "${input.packageName}" with query: ${input.query}`;
293
+ }
294
+ return parts.join(`
295
+
296
+ ---
297
+
298
+ `);
299
+ }, { description: CODE_SEARCH_DESCRIPTION });
300
+ }
301
+ // src/tools/edit.ts
302
+ import { EditTool } from "@humanlayer/agentlayer-core/interfaces";
303
+ import { EDIT_DESCRIPTION } from "@humanlayer/agentlayer-core/prompts";
304
+ function createEditTool(bash) {
305
+ return EditTool.define(async (input) => {
306
+ const catResult = await bash.exec(`cat "${input.file_path}"`);
307
+ if (catResult.exitCode !== 0) {
308
+ throw new Error(`File ${input.file_path} not found`);
309
+ }
310
+ const content = catResult.stdout;
311
+ if (!content.includes(input.old_string)) {
312
+ return { content, matchCount: 0 };
313
+ }
314
+ let updated;
315
+ let matchCount;
316
+ if (input.replace_all) {
317
+ let count = 0;
318
+ let pos = 0;
319
+ while (true) {
320
+ const idx = content.indexOf(input.old_string, pos);
321
+ if (idx === -1)
322
+ break;
323
+ count++;
324
+ pos = idx + input.old_string.length;
325
+ }
326
+ updated = content.split(input.old_string).join(input.new_string);
327
+ matchCount = count;
328
+ } else {
329
+ const firstIdx = content.indexOf(input.old_string);
330
+ const lastIdx = content.lastIndexOf(input.old_string);
331
+ if (firstIdx !== lastIdx) {
332
+ throw new Error("Found multiple matches for old_string. Provide more surrounding context to make the match unique.");
333
+ }
334
+ updated = content.replace(input.old_string, input.new_string);
335
+ matchCount = 1;
336
+ }
337
+ const DELIM = "EDITEOF_8f3a2b1c";
338
+ const writeResult = await bash.exec(`cat > "${input.file_path}" <<'${DELIM}'
339
+ ${updated}
340
+ ${DELIM}`);
341
+ if (writeResult.exitCode !== 0) {
342
+ throw new Error(`Failed to write file ${input.file_path}: ${writeResult.stderr}`);
343
+ }
344
+ return { content: updated, matchCount };
345
+ }, { description: EDIT_DESCRIPTION });
346
+ }
347
+ // src/tools/glob.ts
348
+ import { GlobTool } from "@humanlayer/agentlayer-core/interfaces";
349
+ import { GLOB_DESCRIPTION } from "@humanlayer/agentlayer-core/prompts";
350
+ function createGlobTool(bash) {
351
+ return GlobTool.define(async (input) => {
352
+ const searchPath = input.path ?? ".";
353
+ const result = await bash.exec(`rg --files -g "${input.pattern}" "${searchPath}" 2>/dev/null`);
354
+ if (result.exitCode !== 0 && result.exitCode !== 1) {
355
+ const findResult = await bash.exec(`find "${searchPath}" -type f -name "${input.pattern}" 2>/dev/null | head -100`);
356
+ if (findResult.exitCode !== 0) {
357
+ return [];
358
+ }
359
+ return findResult.stdout.split(`
360
+ `).map((l) => l.trim()).filter(Boolean);
361
+ }
362
+ return result.stdout.split(`
363
+ `).map((l) => l.trim()).filter(Boolean);
364
+ }, { description: GLOB_DESCRIPTION });
365
+ }
366
+ // src/tools/grep.ts
367
+ import { GrepTool } from "@humanlayer/agentlayer-core/interfaces";
368
+ import { GREP_DESCRIPTION } from "@humanlayer/agentlayer-core/prompts";
369
+ var MAX_MATCHES = 100;
370
+ function createGrepTool(bash) {
371
+ return GrepTool.define(async (input) => {
372
+ const searchPath = input.path ?? ".";
373
+ let cmd = `rg -nH --hidden --no-messages --regexp "${input.pattern}"`;
374
+ if (input.include) {
375
+ cmd += ` --glob "${input.include}"`;
376
+ }
377
+ cmd += ` "${searchPath}"`;
378
+ const result = await bash.exec(cmd);
379
+ if (result.exitCode === 1) {
380
+ return [];
381
+ }
382
+ if (result.exitCode !== 0) {
383
+ throw new Error(`grep failed with exit code ${result.exitCode}: ${result.stderr}`);
384
+ }
385
+ const matches = [];
386
+ for (const line of result.stdout.split(`
387
+ `)) {
388
+ if (!line)
389
+ continue;
390
+ const colonIdx = line.indexOf(":");
391
+ if (colonIdx === -1)
392
+ continue;
393
+ const afterFile = line.indexOf(":", colonIdx + 1);
394
+ if (afterFile === -1)
395
+ continue;
396
+ const file = line.slice(0, colonIdx);
397
+ const lineNum = Number.parseInt(line.slice(colonIdx + 1, afterFile), 10);
398
+ const content = line.slice(afterFile + 1);
399
+ if (!Number.isNaN(lineNum)) {
400
+ matches.push({ file, line: lineNum, content });
401
+ }
402
+ if (matches.length >= MAX_MATCHES)
403
+ break;
404
+ }
405
+ return matches;
406
+ }, { description: GREP_DESCRIPTION });
407
+ }
408
+ // src/tools/list.ts
409
+ import { ListTool } from "@humanlayer/agentlayer-core/interfaces";
410
+ import { LIST_DESCRIPTION } from "@humanlayer/agentlayer-core/prompts";
411
+ function createListTool(bash) {
412
+ return ListTool.define(async (input) => {
413
+ const dirPath = input.path ?? ".";
414
+ const result = await bash.exec(`ls -1F "${dirPath}" 2>/dev/null`);
415
+ if (result.exitCode !== 0) {
416
+ throw new Error(`Failed to list directory ${dirPath}: ${result.stderr}`);
417
+ }
418
+ const ignorePatterns = new Set(["node_modules", ".git", "dist", "build", ...input.ignore ?? []]);
419
+ const entries = [];
420
+ for (const raw of result.stdout.split(`
421
+ `)) {
422
+ const line = raw.trim();
423
+ if (!line)
424
+ continue;
425
+ if (line.endsWith("/")) {
426
+ const name = line.slice(0, -1);
427
+ if (ignorePatterns.has(name))
428
+ continue;
429
+ entries.push({ name, type: "directory" });
430
+ } else {
431
+ const name = line.replace(/[*@|=>]$/, "");
432
+ if (ignorePatterns.has(name))
433
+ continue;
434
+ entries.push({ name, type: "file" });
435
+ }
436
+ }
437
+ return entries;
438
+ }, { description: LIST_DESCRIPTION });
439
+ }
440
+ // src/tools/read.ts
441
+ import { ReadTool } from "@humanlayer/agentlayer-core/interfaces";
442
+ import { READ_DESCRIPTION } from "@humanlayer/agentlayer-core/prompts";
443
+ function createJustBashReadTool(bash) {
444
+ return ReadTool.define(async (input) => {
445
+ const result = await bash.exec(`cat "${input.file_path}"`);
446
+ if (result.exitCode !== 0) {
447
+ throw new Error(`File not found: ${input.file_path}`);
448
+ }
449
+ return result.stdout;
450
+ }, { description: READ_DESCRIPTION });
451
+ }
452
+ // src/tools/skill.ts
453
+ import { createSkillTool } from "@humanlayer/agentlayer-core";
454
+ function parseFrontmatterDescription(content) {
455
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
456
+ if (!match)
457
+ return null;
458
+ const fmMatch = match[1]?.match(/description:\s*(.+)/);
459
+ return fmMatch?.[1]?.trim() ?? null;
460
+ }
461
+ function parseFirstHeading(content) {
462
+ const match = content.match(/^#\s+(.+)/m);
463
+ return match?.[1]?.trim() ?? null;
464
+ }
465
+ async function createSkillToolFromVFS(bash, opts) {
466
+ const directories = Array.isArray(opts.dirs) ? opts.dirs : [opts.dirs];
467
+ const resolved = [];
468
+ for (const dir of directories) {
469
+ let lsResult;
470
+ try {
471
+ lsResult = await bash.exec(`ls "${dir}"/*.md 2>/dev/null`);
472
+ } catch {
473
+ continue;
474
+ }
475
+ if (lsResult.exitCode !== 0)
476
+ continue;
477
+ const files = lsResult.stdout.trim().split(`
478
+ `).filter(Boolean);
479
+ for (const filePath of files) {
480
+ const catResult = await bash.exec(`cat "${filePath}"`);
481
+ if (catResult.exitCode !== 0)
482
+ continue;
483
+ const content = catResult.stdout;
484
+ const name = filePath.split("/").pop()?.replace(".md", "") ?? filePath;
485
+ const description = parseFrontmatterDescription(content) ?? parseFirstHeading(content) ?? name;
486
+ resolved.push({ name, description, content });
487
+ }
488
+ }
489
+ const mergedMap = new Map(resolved.map((s) => [s.name, s]));
490
+ for (const skill of opts.skills ?? []) {
491
+ mergedMap.set(skill.name, skill);
492
+ }
493
+ return createSkillTool({ skills: [...mergedMap.values()] });
494
+ }
495
+ // src/tools/web-fetch.ts
496
+ import { WebFetchTool } from "@humanlayer/agentlayer-core";
497
+ import { WEB_FETCH_DESCRIPTION } from "@humanlayer/agentlayer-core/prompts";
498
+ import TurndownService from "turndown";
499
+ var MAX_RESPONSE_SIZE = 5 * 1024 * 1024;
500
+ var MAX_TIMEOUT_MS = 120000;
501
+ function stripHtmlTags(html) {
502
+ return html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "").replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, "").replace(/<[^>]+>/g, "").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&nbsp;/g, " ").replace(/\n{3,}/g, `
503
+
504
+ `).trim();
505
+ }
506
+ function createWebFetchTool(bash) {
507
+ const turndown = new TurndownService({
508
+ headingStyle: "atx",
509
+ codeBlockStyle: "fenced"
510
+ });
511
+ turndown.remove(["script", "style", "meta", "link", "noscript", "iframe"]);
512
+ return WebFetchTool.define(async (input) => {
513
+ if (!input.url.startsWith("http://") && !input.url.startsWith("https://")) {
514
+ throw new Error("URL must start with http:// or https://");
515
+ }
516
+ const timeoutSec = Math.min(input.timeout, MAX_TIMEOUT_MS) / 1000;
517
+ const maxSizeBytes = MAX_RESPONSE_SIZE;
518
+ const result = await bash.exec(`curl -sL --max-filesize ${maxSizeBytes} --max-time ${timeoutSec} ` + `-A "Mozilla/5.0 (compatible; agent/1.0)" ` + `-w '\\n%{http_code}' "${input.url}"`);
519
+ if (result.exitCode !== 0) {
520
+ if (result.exitCode === 28) {
521
+ throw new Error(`Request timed out after ${input.timeout}ms`);
522
+ }
523
+ if (result.exitCode === 63) {
524
+ throw new Error("Response too large (exceeds 5MB limit)");
525
+ }
526
+ throw new Error(`curl failed (exit ${result.exitCode}): ${result.stderr}`);
527
+ }
528
+ const lines = result.stdout.split(`
529
+ `);
530
+ const statusLine = lines[lines.length - 1]?.trim() ?? "";
531
+ const statusCode = Number.parseInt(statusLine, 10);
532
+ const body = lines.slice(0, -1).join(`
533
+ `);
534
+ if (!Number.isNaN(statusCode) && statusCode >= 400) {
535
+ throw new Error(`Request failed with status code: ${statusCode}`);
536
+ }
537
+ if (input.format === "html") {
538
+ return body;
539
+ }
540
+ const isHtml = body.trimStart().startsWith("<!") || body.trimStart().toLowerCase().startsWith("<html");
541
+ if (input.format === "text") {
542
+ if (isHtml) {
543
+ return stripHtmlTags(body);
544
+ }
545
+ return body;
546
+ }
547
+ if (isHtml) {
548
+ return turndown.turndown(body);
549
+ }
550
+ return body;
551
+ }, { description: WEB_FETCH_DESCRIPTION });
552
+ }
553
+ // src/tools/web-search.ts
554
+ import { WebSearchTool } from "@humanlayer/agentlayer-core";
555
+ import { WEB_SEARCH_DESCRIPTION } from "@humanlayer/agentlayer-core/prompts";
556
+ var DEFAULT_TIMEOUT_SEC2 = 25;
557
+ function createWebSearchTool(bash, opts) {
558
+ const timeoutSec = opts.timeoutSec ?? DEFAULT_TIMEOUT_SEC2;
559
+ return WebSearchTool.define(async (input) => {
560
+ const payload = JSON.stringify({
561
+ query: input.query,
562
+ numResults: input.numResults,
563
+ contents: { text: { maxCharacters: 500 } }
564
+ });
565
+ const escapedPayload = payload.replace(/'/g, "'\\''");
566
+ const result = await bash.exec(`curl -s --max-time ${timeoutSec} ` + `-H "Content-Type: application/json" ` + `-H "x-api-key: ${opts.exaApiKey}" ` + `-d '${escapedPayload}' ` + `https://api.exa.ai/search`);
567
+ if (result.exitCode !== 0) {
568
+ if (result.exitCode === 28) {
569
+ throw new Error("Search request timed out");
570
+ }
571
+ throw new Error(`curl failed (exit ${result.exitCode}): ${result.stderr}`);
572
+ }
573
+ let data;
574
+ try {
575
+ data = JSON.parse(result.stdout);
576
+ } catch {
577
+ throw new Error(`Failed to parse search response: ${result.stdout.slice(0, 200)}`);
578
+ }
579
+ const results = (data.results ?? []).map((r) => ({
580
+ title: r.title ?? "",
581
+ url: r.url ?? "",
582
+ snippet: r.text ?? r.snippet ?? ""
583
+ }));
584
+ return { results };
585
+ }, { description: WEB_SEARCH_DESCRIPTION });
586
+ }
587
+ // src/tools/write.ts
588
+ import { WriteTool } from "@humanlayer/agentlayer-core";
589
+ import { WRITE_DESCRIPTION } from "@humanlayer/agentlayer-core/prompts";
590
+ function createWriteTool(bash) {
591
+ return WriteTool.define(async (input) => {
592
+ const dirResult = await bash.exec(`mkdir -p "$(dirname "${input.file_path}")"`);
593
+ if (dirResult.exitCode !== 0) {
594
+ throw new Error(`Failed to create parent directory for ${input.file_path}: ${dirResult.stderr}`);
595
+ }
596
+ const DELIM = "WRITEOF_8f3a2b1c";
597
+ const writeResult = await bash.exec(`cat > "${input.file_path}" <<'${DELIM}'
598
+ ${input.content}
599
+ ${DELIM}`);
600
+ if (writeResult.exitCode !== 0) {
601
+ throw new Error(`Failed to write file ${input.file_path}: ${writeResult.stderr}`);
602
+ }
603
+ return `Successfully wrote to ${input.file_path}`;
604
+ }, { description: WRITE_DESCRIPTION });
605
+ }
606
+ export {
607
+ tarsPersona,
608
+ systemPrompts,
609
+ resolveCodingModelPrompt,
610
+ repoInstructionsPrompt,
611
+ getSystemPromptForModel,
612
+ environmentPrompt,
613
+ detectModelFamily,
614
+ createWriteTool,
615
+ createWebSearchTool,
616
+ createWebFetchTool,
617
+ createSkillToolFromVFS,
618
+ createListTool,
619
+ createJustBashTool,
620
+ createJustBashReadTool,
621
+ createGrepTool,
622
+ createGlobTool,
623
+ createEditTool,
624
+ createCodeSearchTool,
625
+ createApplyPatchTool,
626
+ createAgentSystemPrompt,
627
+ buildCodingProviderOptions
628
+ };
629
+
630
+ //# debugId=28E820D43B2BB25564756E2164756E21