@link-assistant/agent 0.0.8 → 0.0.11

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 (104) hide show
  1. package/EXAMPLES.md +80 -1
  2. package/MODELS.md +72 -24
  3. package/README.md +95 -2
  4. package/TOOLS.md +20 -0
  5. package/package.json +36 -2
  6. package/src/agent/agent.ts +68 -54
  7. package/src/auth/claude-oauth.ts +426 -0
  8. package/src/auth/index.ts +28 -26
  9. package/src/auth/plugins.ts +876 -0
  10. package/src/bun/index.ts +53 -43
  11. package/src/bus/global.ts +5 -5
  12. package/src/bus/index.ts +59 -53
  13. package/src/cli/bootstrap.js +12 -12
  14. package/src/cli/bootstrap.ts +6 -6
  15. package/src/cli/cmd/agent.ts +97 -92
  16. package/src/cli/cmd/auth.ts +468 -0
  17. package/src/cli/cmd/cmd.ts +2 -2
  18. package/src/cli/cmd/export.ts +41 -41
  19. package/src/cli/cmd/mcp.ts +210 -53
  20. package/src/cli/cmd/models.ts +30 -29
  21. package/src/cli/cmd/run.ts +269 -213
  22. package/src/cli/cmd/stats.ts +185 -146
  23. package/src/cli/error.ts +17 -13
  24. package/src/cli/ui.ts +78 -0
  25. package/src/command/index.ts +26 -26
  26. package/src/config/config.ts +528 -288
  27. package/src/config/markdown.ts +15 -15
  28. package/src/file/ripgrep.ts +201 -169
  29. package/src/file/time.ts +21 -18
  30. package/src/file/watcher.ts +51 -42
  31. package/src/file.ts +1 -1
  32. package/src/flag/flag.ts +26 -11
  33. package/src/format/formatter.ts +206 -162
  34. package/src/format/index.ts +61 -61
  35. package/src/global/index.ts +21 -21
  36. package/src/id/id.ts +47 -33
  37. package/src/index.js +554 -332
  38. package/src/json-standard/index.ts +173 -0
  39. package/src/mcp/index.ts +135 -128
  40. package/src/patch/index.ts +336 -267
  41. package/src/project/bootstrap.ts +15 -15
  42. package/src/project/instance.ts +43 -36
  43. package/src/project/project.ts +47 -47
  44. package/src/project/state.ts +37 -33
  45. package/src/provider/models-macro.ts +5 -5
  46. package/src/provider/models.ts +32 -32
  47. package/src/provider/opencode.js +19 -19
  48. package/src/provider/provider.ts +518 -277
  49. package/src/provider/transform.ts +143 -102
  50. package/src/server/project.ts +21 -21
  51. package/src/server/server.ts +111 -105
  52. package/src/session/agent.js +66 -60
  53. package/src/session/compaction.ts +136 -111
  54. package/src/session/index.ts +189 -156
  55. package/src/session/message-v2.ts +312 -268
  56. package/src/session/message.ts +73 -57
  57. package/src/session/processor.ts +180 -166
  58. package/src/session/prompt.ts +678 -533
  59. package/src/session/retry.ts +26 -23
  60. package/src/session/revert.ts +76 -62
  61. package/src/session/status.ts +26 -26
  62. package/src/session/summary.ts +97 -76
  63. package/src/session/system.ts +77 -63
  64. package/src/session/todo.ts +22 -16
  65. package/src/snapshot/index.ts +92 -76
  66. package/src/storage/storage.ts +157 -120
  67. package/src/tool/bash.ts +116 -106
  68. package/src/tool/batch.ts +73 -59
  69. package/src/tool/codesearch.ts +60 -53
  70. package/src/tool/edit.ts +319 -263
  71. package/src/tool/glob.ts +32 -28
  72. package/src/tool/grep.ts +72 -53
  73. package/src/tool/invalid.ts +7 -7
  74. package/src/tool/ls.ts +77 -64
  75. package/src/tool/multiedit.ts +30 -21
  76. package/src/tool/patch.ts +121 -94
  77. package/src/tool/read.ts +140 -122
  78. package/src/tool/registry.ts +38 -38
  79. package/src/tool/task.ts +93 -60
  80. package/src/tool/todo.ts +16 -16
  81. package/src/tool/tool.ts +45 -36
  82. package/src/tool/webfetch.ts +97 -74
  83. package/src/tool/websearch.ts +78 -64
  84. package/src/tool/write.ts +21 -15
  85. package/src/util/binary.ts +27 -19
  86. package/src/util/context.ts +8 -8
  87. package/src/util/defer.ts +7 -5
  88. package/src/util/error.ts +24 -19
  89. package/src/util/eventloop.ts +16 -10
  90. package/src/util/filesystem.ts +37 -33
  91. package/src/util/fn.ts +11 -8
  92. package/src/util/iife.ts +1 -1
  93. package/src/util/keybind.ts +44 -44
  94. package/src/util/lazy.ts +7 -7
  95. package/src/util/locale.ts +20 -16
  96. package/src/util/lock.ts +43 -38
  97. package/src/util/log.ts +95 -85
  98. package/src/util/queue.ts +8 -8
  99. package/src/util/rpc.ts +35 -23
  100. package/src/util/scrap.ts +4 -4
  101. package/src/util/signal.ts +5 -5
  102. package/src/util/timeout.ts +6 -6
  103. package/src/util/token.ts +2 -2
  104. package/src/util/wildcard.ts +38 -27
@@ -1,171 +1,194 @@
1
- import z from "zod"
2
- import { Tool } from "./tool"
3
- import TurndownService from "turndown"
4
- import DESCRIPTION from "./webfetch.txt"
1
+ import z from 'zod';
2
+ import { Tool } from './tool';
3
+ import TurndownService from 'turndown';
4
+ import DESCRIPTION from './webfetch.txt';
5
5
 
6
- const MAX_RESPONSE_SIZE = 5 * 1024 * 1024 // 5MB
7
- const DEFAULT_TIMEOUT = 30 * 1000 // 30 seconds
8
- const MAX_TIMEOUT = 120 * 1000 // 2 minutes
6
+ const MAX_RESPONSE_SIZE = 5 * 1024 * 1024; // 5MB
7
+ const DEFAULT_TIMEOUT = 30 * 1000; // 30 seconds
8
+ const MAX_TIMEOUT = 120 * 1000; // 2 minutes
9
9
 
10
- export const WebFetchTool = Tool.define("webfetch", {
10
+ export const WebFetchTool = Tool.define('webfetch', {
11
11
  description: DESCRIPTION,
12
12
  parameters: z.object({
13
- url: z.string().describe("The URL to fetch content from"),
13
+ url: z.string().describe('The URL to fetch content from'),
14
14
  format: z
15
- .enum(["text", "markdown", "html"])
16
- .describe("The format to return the content in (text, markdown, or html)"),
17
- timeout: z.number().describe("Optional timeout in seconds (max 120)").optional(),
15
+ .enum(['text', 'markdown', 'html'])
16
+ .describe(
17
+ 'The format to return the content in (text, markdown, or html)'
18
+ ),
19
+ timeout: z
20
+ .number()
21
+ .describe('Optional timeout in seconds (max 120)')
22
+ .optional(),
18
23
  }),
19
24
  async execute(params, ctx) {
20
25
  // Validate URL
21
- if (!params.url.startsWith("http://") && !params.url.startsWith("https://")) {
22
- throw new Error("URL must start with http:// or https://")
26
+ if (
27
+ !params.url.startsWith('http://') &&
28
+ !params.url.startsWith('https://')
29
+ ) {
30
+ throw new Error('URL must start with http:// or https://');
23
31
  }
24
32
 
25
33
  // No restrictions - unrestricted web fetch
26
- const timeout = Math.min((params.timeout ?? DEFAULT_TIMEOUT / 1000) * 1000, MAX_TIMEOUT)
34
+ const timeout = Math.min(
35
+ (params.timeout ?? DEFAULT_TIMEOUT / 1000) * 1000,
36
+ MAX_TIMEOUT
37
+ );
27
38
 
28
- const controller = new AbortController()
29
- const timeoutId = setTimeout(() => controller.abort(), timeout)
39
+ const controller = new AbortController();
40
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
30
41
 
31
42
  // Build Accept header based on requested format with q parameters for fallbacks
32
- let acceptHeader = "*/*"
43
+ let acceptHeader = '*/*';
33
44
  switch (params.format) {
34
- case "markdown":
35
- acceptHeader = "text/markdown;q=1.0, text/x-markdown;q=0.9, text/plain;q=0.8, text/html;q=0.7, */*;q=0.1"
36
- break
37
- case "text":
38
- acceptHeader = "text/plain;q=1.0, text/markdown;q=0.9, text/html;q=0.8, */*;q=0.1"
39
- break
40
- case "html":
41
- acceptHeader = "text/html;q=1.0, application/xhtml+xml;q=0.9, text/plain;q=0.8, text/markdown;q=0.7, */*;q=0.1"
42
- break
45
+ case 'markdown':
46
+ acceptHeader =
47
+ 'text/markdown;q=1.0, text/x-markdown;q=0.9, text/plain;q=0.8, text/html;q=0.7, */*;q=0.1';
48
+ break;
49
+ case 'text':
50
+ acceptHeader =
51
+ 'text/plain;q=1.0, text/markdown;q=0.9, text/html;q=0.8, */*;q=0.1';
52
+ break;
53
+ case 'html':
54
+ acceptHeader =
55
+ 'text/html;q=1.0, application/xhtml+xml;q=0.9, text/plain;q=0.8, text/markdown;q=0.7, */*;q=0.1';
56
+ break;
43
57
  default:
44
58
  acceptHeader =
45
- "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8"
59
+ 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8';
46
60
  }
47
61
 
48
62
  const response = await fetch(params.url, {
49
63
  signal: AbortSignal.any([controller.signal, ctx.abort]),
50
64
  headers: {
51
- "User-Agent":
52
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
65
+ 'User-Agent':
66
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
53
67
  Accept: acceptHeader,
54
- "Accept-Language": "en-US,en;q=0.9",
68
+ 'Accept-Language': 'en-US,en;q=0.9',
55
69
  },
56
- })
70
+ });
57
71
 
58
- clearTimeout(timeoutId)
72
+ clearTimeout(timeoutId);
59
73
 
60
74
  if (!response.ok) {
61
- throw new Error(`Request failed with status code: ${response.status}`)
75
+ throw new Error(`Request failed with status code: ${response.status}`);
62
76
  }
63
77
 
64
78
  // Check content length
65
- const contentLength = response.headers.get("content-length")
79
+ const contentLength = response.headers.get('content-length');
66
80
  if (contentLength && parseInt(contentLength) > MAX_RESPONSE_SIZE) {
67
- throw new Error("Response too large (exceeds 5MB limit)")
81
+ throw new Error('Response too large (exceeds 5MB limit)');
68
82
  }
69
83
 
70
- const arrayBuffer = await response.arrayBuffer()
84
+ const arrayBuffer = await response.arrayBuffer();
71
85
  if (arrayBuffer.byteLength > MAX_RESPONSE_SIZE) {
72
- throw new Error("Response too large (exceeds 5MB limit)")
86
+ throw new Error('Response too large (exceeds 5MB limit)');
73
87
  }
74
88
 
75
- const content = new TextDecoder().decode(arrayBuffer)
76
- const contentType = response.headers.get("content-type") || ""
89
+ const content = new TextDecoder().decode(arrayBuffer);
90
+ const contentType = response.headers.get('content-type') || '';
77
91
 
78
- const title = `${params.url} (${contentType})`
92
+ const title = `${params.url} (${contentType})`;
79
93
 
80
94
  // Handle content based on requested format and actual content type
81
95
  switch (params.format) {
82
- case "markdown":
83
- if (contentType.includes("text/html")) {
84
- const markdown = convertHTMLToMarkdown(content)
96
+ case 'markdown':
97
+ if (contentType.includes('text/html')) {
98
+ const markdown = convertHTMLToMarkdown(content);
85
99
  return {
86
100
  output: markdown,
87
101
  title,
88
102
  metadata: {},
89
- }
103
+ };
90
104
  }
91
105
  return {
92
106
  output: content,
93
107
  title,
94
108
  metadata: {},
95
- }
109
+ };
96
110
 
97
- case "text":
98
- if (contentType.includes("text/html")) {
99
- const text = await extractTextFromHTML(content)
111
+ case 'text':
112
+ if (contentType.includes('text/html')) {
113
+ const text = await extractTextFromHTML(content);
100
114
  return {
101
115
  output: text,
102
116
  title,
103
117
  metadata: {},
104
- }
118
+ };
105
119
  }
106
120
  return {
107
121
  output: content,
108
122
  title,
109
123
  metadata: {},
110
- }
124
+ };
111
125
 
112
- case "html":
126
+ case 'html':
113
127
  return {
114
128
  output: content,
115
129
  title,
116
130
  metadata: {},
117
- }
131
+ };
118
132
 
119
133
  default:
120
134
  return {
121
135
  output: content,
122
136
  title,
123
137
  metadata: {},
124
- }
138
+ };
125
139
  }
126
140
  },
127
- })
141
+ });
128
142
 
129
143
  async function extractTextFromHTML(html: string) {
130
- let text = ""
131
- let skipContent = false
144
+ let text = '';
145
+ let skipContent = false;
132
146
 
133
147
  const rewriter = new HTMLRewriter()
134
- .on("script, style, noscript, iframe, object, embed", {
148
+ .on('script, style, noscript, iframe, object, embed', {
135
149
  element() {
136
- skipContent = true
150
+ skipContent = true;
137
151
  },
138
152
  text() {
139
153
  // Skip text content inside these elements
140
154
  },
141
155
  })
142
- .on("*", {
156
+ .on('*', {
143
157
  element(element) {
144
158
  // Reset skip flag when entering other elements
145
- if (!["script", "style", "noscript", "iframe", "object", "embed"].includes(element.tagName)) {
146
- skipContent = false
159
+ if (
160
+ ![
161
+ 'script',
162
+ 'style',
163
+ 'noscript',
164
+ 'iframe',
165
+ 'object',
166
+ 'embed',
167
+ ].includes(element.tagName)
168
+ ) {
169
+ skipContent = false;
147
170
  }
148
171
  },
149
172
  text(input) {
150
173
  if (!skipContent) {
151
- text += input.text
174
+ text += input.text;
152
175
  }
153
176
  },
154
177
  })
155
- .transform(new Response(html))
178
+ .transform(new Response(html));
156
179
 
157
- await rewriter.text()
158
- return text.trim()
180
+ await rewriter.text();
181
+ return text.trim();
159
182
  }
160
183
 
161
184
  function convertHTMLToMarkdown(html: string): string {
162
185
  const turndownService = new TurndownService({
163
- headingStyle: "atx",
164
- hr: "---",
165
- bulletListMarker: "-",
166
- codeBlockStyle: "fenced",
167
- emDelimiter: "*",
168
- })
169
- turndownService.remove(["script", "style", "meta", "link"])
170
- return turndownService.turndown(html)
186
+ headingStyle: 'atx',
187
+ hr: '---',
188
+ bulletListMarker: '-',
189
+ codeBlockStyle: 'fenced',
190
+ emDelimiter: '*',
191
+ });
192
+ turndownService.remove(['script', 'style', 'meta', 'link']);
193
+ return turndownService.turndown(html);
171
194
  }
@@ -1,133 +1,147 @@
1
- import z from "zod"
2
- import { Tool } from "./tool"
3
- import DESCRIPTION from "./websearch.txt"
4
- import { Config } from "../config/config"
1
+ import z from 'zod';
2
+ import { Tool } from './tool';
3
+ import DESCRIPTION from './websearch.txt';
4
+ import { Config } from '../config/config';
5
5
 
6
6
  const API_CONFIG = {
7
- BASE_URL: "https://mcp.exa.ai",
7
+ BASE_URL: 'https://mcp.exa.ai',
8
8
  ENDPOINTS: {
9
- SEARCH: "/mcp",
9
+ SEARCH: '/mcp',
10
10
  },
11
11
  DEFAULT_NUM_RESULTS: 8,
12
- } as const
12
+ } as const;
13
13
 
14
14
  interface McpSearchRequest {
15
- jsonrpc: string
16
- id: number
17
- method: string
15
+ jsonrpc: string;
16
+ id: number;
17
+ method: string;
18
18
  params: {
19
- name: string
19
+ name: string;
20
20
  arguments: {
21
- query: string
22
- numResults?: number
23
- livecrawl?: "fallback" | "preferred"
24
- type?: "auto" | "fast" | "deep"
25
- contextMaxCharacters?: number
26
- }
27
- }
21
+ query: string;
22
+ numResults?: number;
23
+ livecrawl?: 'fallback' | 'preferred';
24
+ type?: 'auto' | 'fast' | 'deep';
25
+ contextMaxCharacters?: number;
26
+ };
27
+ };
28
28
  }
29
29
 
30
30
  interface McpSearchResponse {
31
- jsonrpc: string
31
+ jsonrpc: string;
32
32
  result: {
33
33
  content: Array<{
34
- type: string
35
- text: string
36
- }>
37
- }
34
+ type: string;
35
+ text: string;
36
+ }>;
37
+ };
38
38
  }
39
39
 
40
- export const WebSearchTool = Tool.define("websearch", {
40
+ export const WebSearchTool = Tool.define('websearch', {
41
41
  description: DESCRIPTION,
42
42
  parameters: z.object({
43
- query: z.string().describe("Websearch query"),
44
- numResults: z.number().optional().describe("Number of search results to return (default: 8)"),
43
+ query: z.string().describe('Websearch query'),
44
+ numResults: z
45
+ .number()
46
+ .optional()
47
+ .describe('Number of search results to return (default: 8)'),
45
48
  livecrawl: z
46
- .enum(["fallback", "preferred"])
49
+ .enum(['fallback', 'preferred'])
47
50
  .optional()
48
51
  .describe(
49
- "Live crawl mode - 'fallback': use live crawling as backup if cached content unavailable, 'preferred': prioritize live crawling (default: 'fallback')",
52
+ "Live crawl mode - 'fallback': use live crawling as backup if cached content unavailable, 'preferred': prioritize live crawling (default: 'fallback')"
50
53
  ),
51
54
  type: z
52
- .enum(["auto", "fast", "deep"])
55
+ .enum(['auto', 'fast', 'deep'])
53
56
  .optional()
54
- .describe("Search type - 'auto': balanced search (default), 'fast': quick results, 'deep': comprehensive search"),
57
+ .describe(
58
+ "Search type - 'auto': balanced search (default), 'fast': quick results, 'deep': comprehensive search"
59
+ ),
55
60
  contextMaxCharacters: z
56
61
  .number()
57
62
  .optional()
58
- .describe("Maximum characters for context string optimized for LLMs (default: 10000)"),
63
+ .describe(
64
+ 'Maximum characters for context string optimized for LLMs (default: 10000)'
65
+ ),
59
66
  }),
60
67
  async execute(params, ctx) {
61
68
  // No restrictions - unrestricted web search
62
69
  const searchRequest: McpSearchRequest = {
63
- jsonrpc: "2.0",
70
+ jsonrpc: '2.0',
64
71
  id: 1,
65
- method: "tools/call",
72
+ method: 'tools/call',
66
73
  params: {
67
- name: "web_search_exa",
74
+ name: 'web_search_exa',
68
75
  arguments: {
69
76
  query: params.query,
70
- type: params.type || "auto",
77
+ type: params.type || 'auto',
71
78
  numResults: params.numResults || API_CONFIG.DEFAULT_NUM_RESULTS,
72
- livecrawl: params.livecrawl || "fallback",
79
+ livecrawl: params.livecrawl || 'fallback',
73
80
  contextMaxCharacters: params.contextMaxCharacters,
74
81
  },
75
82
  },
76
- }
83
+ };
77
84
 
78
- const controller = new AbortController()
79
- const timeoutId = setTimeout(() => controller.abort(), 25000)
85
+ const controller = new AbortController();
86
+ const timeoutId = setTimeout(() => controller.abort(), 25000);
80
87
 
81
88
  try {
82
89
  const headers: Record<string, string> = {
83
- accept: "application/json, text/event-stream",
84
- "content-type": "application/json",
85
- }
90
+ accept: 'application/json, text/event-stream',
91
+ 'content-type': 'application/json',
92
+ };
86
93
 
87
- const response = await fetch(`${API_CONFIG.BASE_URL}${API_CONFIG.ENDPOINTS.SEARCH}`, {
88
- method: "POST",
89
- headers,
90
- body: JSON.stringify(searchRequest),
91
- signal: AbortSignal.any([controller.signal, ctx.abort]),
92
- })
94
+ const response = await fetch(
95
+ `${API_CONFIG.BASE_URL}${API_CONFIG.ENDPOINTS.SEARCH}`,
96
+ {
97
+ method: 'POST',
98
+ headers,
99
+ body: JSON.stringify(searchRequest),
100
+ signal: AbortSignal.any([controller.signal, ctx.abort]),
101
+ }
102
+ );
93
103
 
94
- clearTimeout(timeoutId)
104
+ clearTimeout(timeoutId);
95
105
 
96
106
  if (!response.ok) {
97
- const errorText = await response.text()
98
- throw new Error(`Search error (${response.status}): ${errorText}`)
107
+ const errorText = await response.text();
108
+ throw new Error(`Search error (${response.status}): ${errorText}`);
99
109
  }
100
110
 
101
- const responseText = await response.text()
111
+ const responseText = await response.text();
102
112
 
103
113
  // Parse SSE response
104
- const lines = responseText.split("\n")
114
+ const lines = responseText.split('\n');
105
115
  for (const line of lines) {
106
- if (line.startsWith("data: ")) {
107
- const data: McpSearchResponse = JSON.parse(line.substring(6))
108
- if (data.result && data.result.content && data.result.content.length > 0) {
116
+ if (line.startsWith('data: ')) {
117
+ const data: McpSearchResponse = JSON.parse(line.substring(6));
118
+ if (
119
+ data.result &&
120
+ data.result.content &&
121
+ data.result.content.length > 0
122
+ ) {
109
123
  return {
110
124
  output: data.result.content[0].text,
111
125
  title: `Web search: ${params.query}`,
112
126
  metadata: {},
113
- }
127
+ };
114
128
  }
115
129
  }
116
130
  }
117
131
 
118
132
  return {
119
- output: "No search results found. Please try a different query.",
133
+ output: 'No search results found. Please try a different query.',
120
134
  title: `Web search: ${params.query}`,
121
135
  metadata: {},
122
- }
136
+ };
123
137
  } catch (error) {
124
- clearTimeout(timeoutId)
138
+ clearTimeout(timeoutId);
125
139
 
126
- if (error instanceof Error && error.name === "AbortError") {
127
- throw new Error("Search request timed out")
140
+ if (error instanceof Error && error.name === 'AbortError') {
141
+ throw new Error('Search request timed out');
128
142
  }
129
143
 
130
- throw error
144
+ throw error;
131
145
  }
132
146
  },
133
- })
147
+ });
package/src/tool/write.ts CHANGED
@@ -1,24 +1,30 @@
1
- import z from "zod"
2
- import * as path from "path"
3
- import { Tool } from "./tool"
4
- import DESCRIPTION from "./write.txt"
5
- import { Instance } from "../project/instance"
1
+ import z from 'zod';
2
+ import * as path from 'path';
3
+ import { Tool } from './tool';
4
+ import DESCRIPTION from './write.txt';
5
+ import { Instance } from '../project/instance';
6
6
 
7
- export const WriteTool = Tool.define("write", {
7
+ export const WriteTool = Tool.define('write', {
8
8
  description: DESCRIPTION,
9
9
  parameters: z.object({
10
- content: z.string().describe("The content to write to the file"),
11
- filePath: z.string().describe("The absolute path to the file to write (must be absolute, not relative)"),
10
+ content: z.string().describe('The content to write to the file'),
11
+ filePath: z
12
+ .string()
13
+ .describe(
14
+ 'The absolute path to the file to write (must be absolute, not relative)'
15
+ ),
12
16
  }),
13
17
  async execute(params, ctx) {
14
18
  // No restrictions - unrestricted file system access
15
- const filepath = path.isAbsolute(params.filePath) ? params.filePath : path.join(Instance.directory, params.filePath)
19
+ const filepath = path.isAbsolute(params.filePath)
20
+ ? params.filePath
21
+ : path.join(Instance.directory, params.filePath);
16
22
 
17
- const file = Bun.file(filepath)
18
- const exists = await file.exists()
23
+ const file = Bun.file(filepath);
24
+ const exists = await file.exists();
19
25
 
20
26
  // Write the file without permission checks
21
- await Bun.write(filepath, params.content)
27
+ await Bun.write(filepath, params.content);
22
28
 
23
29
  return {
24
30
  title: path.relative(Instance.worktree, filepath),
@@ -27,7 +33,7 @@ export const WriteTool = Tool.define("write", {
27
33
  filepath,
28
34
  exists: exists,
29
35
  },
30
- output: "",
31
- }
36
+ output: '',
37
+ };
32
38
  },
33
- })
39
+ });
@@ -1,41 +1,49 @@
1
1
  export namespace Binary {
2
- export function search<T>(array: T[], id: string, compare: (item: T) => string): { found: boolean; index: number } {
3
- let left = 0
4
- let right = array.length - 1
2
+ export function search<T>(
3
+ array: T[],
4
+ id: string,
5
+ compare: (item: T) => string
6
+ ): { found: boolean; index: number } {
7
+ let left = 0;
8
+ let right = array.length - 1;
5
9
 
6
10
  while (left <= right) {
7
- const mid = Math.floor((left + right) / 2)
8
- const midId = compare(array[mid])
11
+ const mid = Math.floor((left + right) / 2);
12
+ const midId = compare(array[mid]);
9
13
 
10
14
  if (midId === id) {
11
- return { found: true, index: mid }
15
+ return { found: true, index: mid };
12
16
  } else if (midId < id) {
13
- left = mid + 1
17
+ left = mid + 1;
14
18
  } else {
15
- right = mid - 1
19
+ right = mid - 1;
16
20
  }
17
21
  }
18
22
 
19
- return { found: false, index: left }
23
+ return { found: false, index: left };
20
24
  }
21
25
 
22
- export function insert<T>(array: T[], item: T, compare: (item: T) => string): T[] {
23
- const id = compare(item)
24
- let left = 0
25
- let right = array.length
26
+ export function insert<T>(
27
+ array: T[],
28
+ item: T,
29
+ compare: (item: T) => string
30
+ ): T[] {
31
+ const id = compare(item);
32
+ let left = 0;
33
+ let right = array.length;
26
34
 
27
35
  while (left < right) {
28
- const mid = Math.floor((left + right) / 2)
29
- const midId = compare(array[mid])
36
+ const mid = Math.floor((left + right) / 2);
37
+ const midId = compare(array[mid]);
30
38
 
31
39
  if (midId < id) {
32
- left = mid + 1
40
+ left = mid + 1;
33
41
  } else {
34
- right = mid
42
+ right = mid;
35
43
  }
36
44
  }
37
45
 
38
- array.splice(left, 0, item)
39
- return array
46
+ array.splice(left, 0, item);
47
+ return array;
40
48
  }
41
49
  }
@@ -1,25 +1,25 @@
1
- import { AsyncLocalStorage } from "async_hooks"
1
+ import { AsyncLocalStorage } from 'async_hooks';
2
2
 
3
3
  export namespace Context {
4
4
  export class NotFound extends Error {
5
5
  constructor(public override readonly name: string) {
6
- super(`No context found for ${name}`)
6
+ super(`No context found for ${name}`);
7
7
  }
8
8
  }
9
9
 
10
10
  export function create<T>(name: string) {
11
- const storage = new AsyncLocalStorage<T>()
11
+ const storage = new AsyncLocalStorage<T>();
12
12
  return {
13
13
  use() {
14
- const result = storage.getStore()
14
+ const result = storage.getStore();
15
15
  if (!result) {
16
- throw new NotFound(name)
16
+ throw new NotFound(name);
17
17
  }
18
- return result
18
+ return result;
19
19
  },
20
20
  provide<R>(value: T, fn: () => R) {
21
- return storage.run(value, fn)
21
+ return storage.run(value, fn);
22
22
  },
23
- }
23
+ };
24
24
  }
25
25
  }
package/src/util/defer.ts CHANGED
@@ -1,12 +1,14 @@
1
1
  export function defer<T extends () => void | Promise<void>>(
2
- fn: T,
3
- ): T extends () => Promise<void> ? { [Symbol.asyncDispose]: () => Promise<void> } : { [Symbol.dispose]: () => void } {
2
+ fn: T
3
+ ): T extends () => Promise<void>
4
+ ? { [Symbol.asyncDispose]: () => Promise<void> }
5
+ : { [Symbol.dispose]: () => void } {
4
6
  return {
5
7
  [Symbol.dispose]() {
6
- fn()
8
+ fn();
7
9
  },
8
10
  [Symbol.asyncDispose]() {
9
- return Promise.resolve(fn())
11
+ return Promise.resolve(fn());
10
12
  },
11
- } as any
13
+ } as any;
12
14
  }