@mariozechner/pi-coding-agent 0.25.4 → 0.26.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.
Files changed (118) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +47 -5
  3. package/dist/cli/file-processor.d.ts.map +1 -1
  4. package/dist/cli/file-processor.js +1 -1
  5. package/dist/cli/file-processor.js.map +1 -1
  6. package/dist/cli/session-picker.d.ts +2 -2
  7. package/dist/cli/session-picker.d.ts.map +1 -1
  8. package/dist/cli/session-picker.js +2 -2
  9. package/dist/cli/session-picker.js.map +1 -1
  10. package/dist/core/agent-session.d.ts.map +1 -1
  11. package/dist/core/agent-session.js +1 -13
  12. package/dist/core/agent-session.js.map +1 -1
  13. package/dist/core/custom-tools/loader.d.ts +3 -2
  14. package/dist/core/custom-tools/loader.d.ts.map +1 -1
  15. package/dist/core/custom-tools/loader.js +5 -4
  16. package/dist/core/custom-tools/loader.js.map +1 -1
  17. package/dist/core/hooks/loader.d.ts +2 -5
  18. package/dist/core/hooks/loader.d.ts.map +1 -1
  19. package/dist/core/hooks/loader.js +4 -7
  20. package/dist/core/hooks/loader.js.map +1 -1
  21. package/dist/core/model-config.d.ts +5 -4
  22. package/dist/core/model-config.d.ts.map +1 -1
  23. package/dist/core/model-config.js +12 -19
  24. package/dist/core/model-config.js.map +1 -1
  25. package/dist/core/sdk.d.ts +211 -0
  26. package/dist/core/sdk.d.ts.map +1 -0
  27. package/dist/core/sdk.js +466 -0
  28. package/dist/core/sdk.js.map +1 -0
  29. package/dist/core/session-manager.d.ts +31 -91
  30. package/dist/core/session-manager.d.ts.map +1 -1
  31. package/dist/core/session-manager.js +187 -352
  32. package/dist/core/session-manager.js.map +1 -1
  33. package/dist/core/settings-manager.d.ts +12 -2
  34. package/dist/core/settings-manager.d.ts.map +1 -1
  35. package/dist/core/settings-manager.js +101 -37
  36. package/dist/core/settings-manager.js.map +1 -1
  37. package/dist/core/skills.d.ts +7 -1
  38. package/dist/core/skills.d.ts.map +1 -1
  39. package/dist/core/skills.js +7 -5
  40. package/dist/core/skills.js.map +1 -1
  41. package/dist/core/slash-commands.d.ts +9 -3
  42. package/dist/core/slash-commands.d.ts.map +1 -1
  43. package/dist/core/slash-commands.js +10 -7
  44. package/dist/core/slash-commands.js.map +1 -1
  45. package/dist/core/system-prompt.d.ts +24 -2
  46. package/dist/core/system-prompt.d.ts.map +1 -1
  47. package/dist/core/system-prompt.js +18 -16
  48. package/dist/core/system-prompt.js.map +1 -1
  49. package/dist/core/tools/bash.d.ts +6 -1
  50. package/dist/core/tools/bash.d.ts.map +1 -1
  51. package/dist/core/tools/bash.js +149 -144
  52. package/dist/core/tools/bash.js.map +1 -1
  53. package/dist/core/tools/edit.d.ts +7 -1
  54. package/dist/core/tools/edit.d.ts.map +1 -1
  55. package/dist/core/tools/edit.js +105 -102
  56. package/dist/core/tools/edit.js.map +1 -1
  57. package/dist/core/tools/find.d.ts +7 -1
  58. package/dist/core/tools/find.d.ts.map +1 -1
  59. package/dist/core/tools/find.js +128 -124
  60. package/dist/core/tools/find.js.map +1 -1
  61. package/dist/core/tools/grep.d.ts +11 -1
  62. package/dist/core/tools/grep.d.ts.map +1 -1
  63. package/dist/core/tools/grep.js +198 -194
  64. package/dist/core/tools/grep.js.map +1 -1
  65. package/dist/core/tools/index.d.ts +31 -29
  66. package/dist/core/tools/index.d.ts.map +1 -1
  67. package/dist/core/tools/index.js +44 -16
  68. package/dist/core/tools/index.js.map +1 -1
  69. package/dist/core/tools/ls.d.ts +6 -1
  70. package/dist/core/tools/ls.d.ts.map +1 -1
  71. package/dist/core/tools/ls.js +90 -86
  72. package/dist/core/tools/ls.js.map +1 -1
  73. package/dist/core/tools/path-utils.d.ts +6 -1
  74. package/dist/core/tools/path-utils.d.ts.map +1 -1
  75. package/dist/core/tools/path-utils.js +17 -5
  76. package/dist/core/tools/path-utils.js.map +1 -1
  77. package/dist/core/tools/read.d.ts +7 -1
  78. package/dist/core/tools/read.d.ts.map +1 -1
  79. package/dist/core/tools/read.js +118 -115
  80. package/dist/core/tools/read.js.map +1 -1
  81. package/dist/core/tools/write.d.ts +6 -1
  82. package/dist/core/tools/write.d.ts.map +1 -1
  83. package/dist/core/tools/write.js +63 -59
  84. package/dist/core/tools/write.js.map +1 -1
  85. package/dist/index.d.ts +2 -1
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.js +14 -0
  88. package/dist/index.js.map +1 -1
  89. package/dist/main.d.ts +4 -1
  90. package/dist/main.d.ts.map +1 -1
  91. package/dist/main.js +142 -312
  92. package/dist/main.js.map +1 -1
  93. package/dist/modes/interactive/components/session-selector.d.ts +3 -12
  94. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  95. package/dist/modes/interactive/components/session-selector.js +1 -3
  96. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  97. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  98. package/dist/modes/interactive/interactive-mode.js +3 -2
  99. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  100. package/dist/utils/shell.d.ts.map +1 -1
  101. package/dist/utils/shell.js +1 -1
  102. package/dist/utils/shell.js.map +1 -1
  103. package/docs/sdk.md +864 -0
  104. package/examples/README.md +29 -0
  105. package/examples/sdk/01-minimal.ts +22 -0
  106. package/examples/sdk/02-custom-model.ts +36 -0
  107. package/examples/sdk/03-custom-prompt.ts +44 -0
  108. package/examples/sdk/04-skills.ts +44 -0
  109. package/examples/sdk/05-tools.ts +93 -0
  110. package/examples/sdk/06-hooks.ts +61 -0
  111. package/examples/sdk/07-context-files.ts +36 -0
  112. package/examples/sdk/08-slash-commands.ts +37 -0
  113. package/examples/sdk/09-api-keys-and-oauth.ts +45 -0
  114. package/examples/sdk/10-settings.ts +38 -0
  115. package/examples/sdk/11-sessions.ts +46 -0
  116. package/examples/sdk/12-full-control.ts +99 -0
  117. package/examples/sdk/README.md +138 -0
  118. package/package.json +4 -4
@@ -1,7 +1,6 @@
1
1
  import { Type } from "@sinclair/typebox";
2
2
  import { constants } from "fs";
3
3
  import { access, readFile } from "fs/promises";
4
- import { resolve as resolvePath } from "path";
5
4
  import { detectSupportedImageMimeTypeFromFile } from "../../utils/mime.js";
6
5
  import { resolveReadPath } from "./path-utils.js";
7
6
  import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, truncateHead } from "./truncate.js";
@@ -10,129 +9,133 @@ const readSchema = Type.Object({
10
9
  offset: Type.Optional(Type.Number({ description: "Line number to start reading from (1-indexed)" })),
11
10
  limit: Type.Optional(Type.Number({ description: "Maximum number of lines to read" })),
12
11
  });
13
- export const readTool = {
14
- name: "read",
15
- label: "read",
16
- description: `Read the contents of a file. Supports text files and images (jpg, png, gif, webp). Images are sent as attachments. For text files, output is truncated to ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Use offset/limit for large files.`,
17
- parameters: readSchema,
18
- execute: async (_toolCallId, { path, offset, limit }, signal) => {
19
- const absolutePath = resolvePath(resolveReadPath(path));
20
- return new Promise((resolve, reject) => {
21
- // Check if already aborted
22
- if (signal?.aborted) {
23
- reject(new Error("Operation aborted"));
24
- return;
25
- }
26
- let aborted = false;
27
- // Set up abort handler
28
- const onAbort = () => {
29
- aborted = true;
30
- reject(new Error("Operation aborted"));
31
- };
32
- if (signal) {
33
- signal.addEventListener("abort", onAbort, { once: true });
34
- }
35
- // Perform the read operation
36
- (async () => {
37
- try {
38
- // Check if file exists
39
- await access(absolutePath, constants.R_OK);
40
- // Check if aborted before reading
41
- if (aborted) {
42
- return;
43
- }
44
- const mimeType = await detectSupportedImageMimeTypeFromFile(absolutePath);
45
- // Read the file based on type
46
- let content;
47
- let details;
48
- if (mimeType) {
49
- // Read as image (binary)
50
- const buffer = await readFile(absolutePath);
51
- const base64 = buffer.toString("base64");
52
- content = [
53
- { type: "text", text: `Read image file [${mimeType}]` },
54
- { type: "image", data: base64, mimeType },
55
- ];
56
- }
57
- else {
58
- // Read as text
59
- const textContent = await readFile(absolutePath, "utf-8");
60
- const allLines = textContent.split("\n");
61
- const totalFileLines = allLines.length;
62
- // Apply offset if specified (1-indexed to 0-indexed)
63
- const startLine = offset ? Math.max(0, offset - 1) : 0;
64
- const startLineDisplay = startLine + 1; // For display (1-indexed)
65
- // Check if offset is out of bounds
66
- if (startLine >= allLines.length) {
67
- throw new Error(`Offset ${offset} is beyond end of file (${allLines.length} lines total)`);
12
+ export function createReadTool(cwd) {
13
+ return {
14
+ name: "read",
15
+ label: "read",
16
+ description: `Read the contents of a file. Supports text files and images (jpg, png, gif, webp). Images are sent as attachments. For text files, output is truncated to ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Use offset/limit for large files.`,
17
+ parameters: readSchema,
18
+ execute: async (_toolCallId, { path, offset, limit }, signal) => {
19
+ const absolutePath = resolveReadPath(path, cwd);
20
+ return new Promise((resolve, reject) => {
21
+ // Check if already aborted
22
+ if (signal?.aborted) {
23
+ reject(new Error("Operation aborted"));
24
+ return;
25
+ }
26
+ let aborted = false;
27
+ // Set up abort handler
28
+ const onAbort = () => {
29
+ aborted = true;
30
+ reject(new Error("Operation aborted"));
31
+ };
32
+ if (signal) {
33
+ signal.addEventListener("abort", onAbort, { once: true });
34
+ }
35
+ // Perform the read operation
36
+ (async () => {
37
+ try {
38
+ // Check if file exists
39
+ await access(absolutePath, constants.R_OK);
40
+ // Check if aborted before reading
41
+ if (aborted) {
42
+ return;
68
43
  }
69
- // If limit is specified by user, use it; otherwise we'll let truncateHead decide
70
- let selectedContent;
71
- let userLimitedLines;
72
- if (limit !== undefined) {
73
- const endLine = Math.min(startLine + limit, allLines.length);
74
- selectedContent = allLines.slice(startLine, endLine).join("\n");
75
- userLimitedLines = endLine - startLine;
44
+ const mimeType = await detectSupportedImageMimeTypeFromFile(absolutePath);
45
+ // Read the file based on type
46
+ let content;
47
+ let details;
48
+ if (mimeType) {
49
+ // Read as image (binary)
50
+ const buffer = await readFile(absolutePath);
51
+ const base64 = buffer.toString("base64");
52
+ content = [
53
+ { type: "text", text: `Read image file [${mimeType}]` },
54
+ { type: "image", data: base64, mimeType },
55
+ ];
76
56
  }
77
57
  else {
78
- selectedContent = allLines.slice(startLine).join("\n");
79
- }
80
- // Apply truncation (respects both line and byte limits)
81
- const truncation = truncateHead(selectedContent);
82
- let outputText;
83
- if (truncation.firstLineExceedsLimit) {
84
- // First line at offset exceeds 30KB - tell model to use bash
85
- const firstLineSize = formatSize(Buffer.byteLength(allLines[startLine], "utf-8"));
86
- outputText = `[Line ${startLineDisplay} is ${firstLineSize}, exceeds ${formatSize(DEFAULT_MAX_BYTES)} limit. Use bash: sed -n '${startLineDisplay}p' ${path} | head -c ${DEFAULT_MAX_BYTES}]`;
87
- details = { truncation };
88
- }
89
- else if (truncation.truncated) {
90
- // Truncation occurred - build actionable notice
91
- const endLineDisplay = startLineDisplay + truncation.outputLines - 1;
92
- const nextOffset = endLineDisplay + 1;
93
- outputText = truncation.content;
94
- if (truncation.truncatedBy === "lines") {
95
- outputText += `\n\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines}. Use offset=${nextOffset} to continue]`;
58
+ // Read as text
59
+ const textContent = await readFile(absolutePath, "utf-8");
60
+ const allLines = textContent.split("\n");
61
+ const totalFileLines = allLines.length;
62
+ // Apply offset if specified (1-indexed to 0-indexed)
63
+ const startLine = offset ? Math.max(0, offset - 1) : 0;
64
+ const startLineDisplay = startLine + 1; // For display (1-indexed)
65
+ // Check if offset is out of bounds
66
+ if (startLine >= allLines.length) {
67
+ throw new Error(`Offset ${offset} is beyond end of file (${allLines.length} lines total)`);
68
+ }
69
+ // If limit is specified by user, use it; otherwise we'll let truncateHead decide
70
+ let selectedContent;
71
+ let userLimitedLines;
72
+ if (limit !== undefined) {
73
+ const endLine = Math.min(startLine + limit, allLines.length);
74
+ selectedContent = allLines.slice(startLine, endLine).join("\n");
75
+ userLimitedLines = endLine - startLine;
76
+ }
77
+ else {
78
+ selectedContent = allLines.slice(startLine).join("\n");
79
+ }
80
+ // Apply truncation (respects both line and byte limits)
81
+ const truncation = truncateHead(selectedContent);
82
+ let outputText;
83
+ if (truncation.firstLineExceedsLimit) {
84
+ // First line at offset exceeds 30KB - tell model to use bash
85
+ const firstLineSize = formatSize(Buffer.byteLength(allLines[startLine], "utf-8"));
86
+ outputText = `[Line ${startLineDisplay} is ${firstLineSize}, exceeds ${formatSize(DEFAULT_MAX_BYTES)} limit. Use bash: sed -n '${startLineDisplay}p' ${path} | head -c ${DEFAULT_MAX_BYTES}]`;
87
+ details = { truncation };
88
+ }
89
+ else if (truncation.truncated) {
90
+ // Truncation occurred - build actionable notice
91
+ const endLineDisplay = startLineDisplay + truncation.outputLines - 1;
92
+ const nextOffset = endLineDisplay + 1;
93
+ outputText = truncation.content;
94
+ if (truncation.truncatedBy === "lines") {
95
+ outputText += `\n\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines}. Use offset=${nextOffset} to continue]`;
96
+ }
97
+ else {
98
+ outputText += `\n\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Use offset=${nextOffset} to continue]`;
99
+ }
100
+ details = { truncation };
101
+ }
102
+ else if (userLimitedLines !== undefined && startLine + userLimitedLines < allLines.length) {
103
+ // User specified limit, there's more content, but no truncation
104
+ const remaining = allLines.length - (startLine + userLimitedLines);
105
+ const nextOffset = startLine + userLimitedLines + 1;
106
+ outputText = truncation.content;
107
+ outputText += `\n\n[${remaining} more lines in file. Use offset=${nextOffset} to continue]`;
96
108
  }
97
109
  else {
98
- outputText += `\n\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Use offset=${nextOffset} to continue]`;
110
+ // No truncation, no user limit exceeded
111
+ outputText = truncation.content;
99
112
  }
100
- details = { truncation };
113
+ content = [{ type: "text", text: outputText }];
101
114
  }
102
- else if (userLimitedLines !== undefined && startLine + userLimitedLines < allLines.length) {
103
- // User specified limit, there's more content, but no truncation
104
- const remaining = allLines.length - (startLine + userLimitedLines);
105
- const nextOffset = startLine + userLimitedLines + 1;
106
- outputText = truncation.content;
107
- outputText += `\n\n[${remaining} more lines in file. Use offset=${nextOffset} to continue]`;
115
+ // Check if aborted after reading
116
+ if (aborted) {
117
+ return;
108
118
  }
109
- else {
110
- // No truncation, no user limit exceeded
111
- outputText = truncation.content;
119
+ // Clean up abort handler
120
+ if (signal) {
121
+ signal.removeEventListener("abort", onAbort);
112
122
  }
113
- content = [{ type: "text", text: outputText }];
114
- }
115
- // Check if aborted after reading
116
- if (aborted) {
117
- return;
118
- }
119
- // Clean up abort handler
120
- if (signal) {
121
- signal.removeEventListener("abort", onAbort);
123
+ resolve({ content, details });
122
124
  }
123
- resolve({ content, details });
124
- }
125
- catch (error) {
126
- // Clean up abort handler
127
- if (signal) {
128
- signal.removeEventListener("abort", onAbort);
129
- }
130
- if (!aborted) {
131
- reject(error);
125
+ catch (error) {
126
+ // Clean up abort handler
127
+ if (signal) {
128
+ signal.removeEventListener("abort", onAbort);
129
+ }
130
+ if (!aborted) {
131
+ reject(error);
132
+ }
132
133
  }
133
- }
134
- })();
135
- });
136
- },
137
- };
134
+ })();
135
+ });
136
+ },
137
+ };
138
+ }
139
+ /** Default read tool using process.cwd() - for backwards compatibility */
140
+ export const readTool = createReadTool(process.cwd());
138
141
  //# sourceMappingURL=read.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"read.js","sourceRoot":"","sources":["../../../src/core/tools/read.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool, ImageContent, TextContent } from \"@mariozechner/pi-ai\";\nimport { Type } from \"@sinclair/typebox\";\nimport { constants } from \"fs\";\nimport { access, readFile } from \"fs/promises\";\nimport { resolve as resolvePath } from \"path\";\nimport { detectSupportedImageMimeTypeFromFile } from \"../../utils/mime.js\";\nimport { resolveReadPath } from \"./path-utils.js\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationResult, truncateHead } from \"./truncate.js\";\n\nconst readSchema = Type.Object({\n\tpath: Type.String({ description: \"Path to the file to read (relative or absolute)\" }),\n\toffset: Type.Optional(Type.Number({ description: \"Line number to start reading from (1-indexed)\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of lines to read\" })),\n});\n\nexport interface ReadToolDetails {\n\ttruncation?: TruncationResult;\n}\n\nexport const readTool: AgentTool<typeof readSchema> = {\n\tname: \"read\",\n\tlabel: \"read\",\n\tdescription: `Read the contents of a file. Supports text files and images (jpg, png, gif, webp). Images are sent as attachments. For text files, output is truncated to ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Use offset/limit for large files.`,\n\tparameters: readSchema,\n\texecute: async (\n\t\t_toolCallId: string,\n\t\t{ path, offset, limit }: { path: string; offset?: number; limit?: number },\n\t\tsignal?: AbortSignal,\n\t) => {\n\t\tconst absolutePath = resolvePath(resolveReadPath(path));\n\n\t\treturn new Promise<{ content: (TextContent | ImageContent)[]; details: ReadToolDetails | undefined }>(\n\t\t\t(resolve, reject) => {\n\t\t\t\t// Check if already aborted\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet aborted = false;\n\n\t\t\t\t// Set up abort handler\n\t\t\t\tconst onAbort = () => {\n\t\t\t\t\taborted = true;\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t};\n\n\t\t\t\tif (signal) {\n\t\t\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t}\n\n\t\t\t\t// Perform the read operation\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// Check if file exists\n\t\t\t\t\t\tawait access(absolutePath, constants.R_OK);\n\n\t\t\t\t\t\t// Check if aborted before reading\n\t\t\t\t\t\tif (aborted) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst mimeType = await detectSupportedImageMimeTypeFromFile(absolutePath);\n\n\t\t\t\t\t\t// Read the file based on type\n\t\t\t\t\t\tlet content: (TextContent | ImageContent)[];\n\t\t\t\t\t\tlet details: ReadToolDetails | undefined;\n\n\t\t\t\t\t\tif (mimeType) {\n\t\t\t\t\t\t\t// Read as image (binary)\n\t\t\t\t\t\t\tconst buffer = await readFile(absolutePath);\n\t\t\t\t\t\t\tconst base64 = buffer.toString(\"base64\");\n\n\t\t\t\t\t\t\tcontent = [\n\t\t\t\t\t\t\t\t{ type: \"text\", text: `Read image file [${mimeType}]` },\n\t\t\t\t\t\t\t\t{ type: \"image\", data: base64, mimeType },\n\t\t\t\t\t\t\t];\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Read as text\n\t\t\t\t\t\t\tconst textContent = await readFile(absolutePath, \"utf-8\");\n\t\t\t\t\t\t\tconst allLines = textContent.split(\"\\n\");\n\t\t\t\t\t\t\tconst totalFileLines = allLines.length;\n\n\t\t\t\t\t\t\t// Apply offset if specified (1-indexed to 0-indexed)\n\t\t\t\t\t\t\tconst startLine = offset ? Math.max(0, offset - 1) : 0;\n\t\t\t\t\t\t\tconst startLineDisplay = startLine + 1; // For display (1-indexed)\n\n\t\t\t\t\t\t\t// Check if offset is out of bounds\n\t\t\t\t\t\t\tif (startLine >= allLines.length) {\n\t\t\t\t\t\t\t\tthrow new Error(`Offset ${offset} is beyond end of file (${allLines.length} lines total)`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// If limit is specified by user, use it; otherwise we'll let truncateHead decide\n\t\t\t\t\t\t\tlet selectedContent: string;\n\t\t\t\t\t\t\tlet userLimitedLines: number | undefined;\n\t\t\t\t\t\t\tif (limit !== undefined) {\n\t\t\t\t\t\t\t\tconst endLine = Math.min(startLine + limit, allLines.length);\n\t\t\t\t\t\t\t\tselectedContent = allLines.slice(startLine, endLine).join(\"\\n\");\n\t\t\t\t\t\t\t\tuserLimitedLines = endLine - startLine;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tselectedContent = allLines.slice(startLine).join(\"\\n\");\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Apply truncation (respects both line and byte limits)\n\t\t\t\t\t\t\tconst truncation = truncateHead(selectedContent);\n\n\t\t\t\t\t\t\tlet outputText: string;\n\n\t\t\t\t\t\t\tif (truncation.firstLineExceedsLimit) {\n\t\t\t\t\t\t\t\t// First line at offset exceeds 30KB - tell model to use bash\n\t\t\t\t\t\t\t\tconst firstLineSize = formatSize(Buffer.byteLength(allLines[startLine], \"utf-8\"));\n\t\t\t\t\t\t\t\toutputText = `[Line ${startLineDisplay} is ${firstLineSize}, exceeds ${formatSize(DEFAULT_MAX_BYTES)} limit. Use bash: sed -n '${startLineDisplay}p' ${path} | head -c ${DEFAULT_MAX_BYTES}]`;\n\t\t\t\t\t\t\t\tdetails = { truncation };\n\t\t\t\t\t\t\t} else if (truncation.truncated) {\n\t\t\t\t\t\t\t\t// Truncation occurred - build actionable notice\n\t\t\t\t\t\t\t\tconst endLineDisplay = startLineDisplay + truncation.outputLines - 1;\n\t\t\t\t\t\t\t\tconst nextOffset = endLineDisplay + 1;\n\n\t\t\t\t\t\t\t\toutputText = truncation.content;\n\n\t\t\t\t\t\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\t\t\t\toutputText += `\\n\\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines}. Use offset=${nextOffset} to continue]`;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\toutputText += `\\n\\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Use offset=${nextOffset} to continue]`;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tdetails = { truncation };\n\t\t\t\t\t\t\t} else if (userLimitedLines !== undefined && startLine + userLimitedLines < allLines.length) {\n\t\t\t\t\t\t\t\t// User specified limit, there's more content, but no truncation\n\t\t\t\t\t\t\t\tconst remaining = allLines.length - (startLine + userLimitedLines);\n\t\t\t\t\t\t\t\tconst nextOffset = startLine + userLimitedLines + 1;\n\n\t\t\t\t\t\t\t\toutputText = truncation.content;\n\t\t\t\t\t\t\t\toutputText += `\\n\\n[${remaining} more lines in file. Use offset=${nextOffset} to continue]`;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t// No truncation, no user limit exceeded\n\t\t\t\t\t\t\t\toutputText = truncation.content;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tcontent = [{ type: \"text\", text: outputText }];\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Check if aborted after reading\n\t\t\t\t\t\tif (aborted) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Clean up abort handler\n\t\t\t\t\t\tif (signal) {\n\t\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tresolve({ content, details });\n\t\t\t\t\t} catch (error: any) {\n\t\t\t\t\t\t// Clean up abort handler\n\t\t\t\t\t\tif (signal) {\n\t\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!aborted) {\n\t\t\t\t\t\t\treject(error);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t},\n\t\t);\n\t},\n};\n"]}
1
+ {"version":3,"file":"read.js","sourceRoot":"","sources":["../../../src/core/tools/read.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool, ImageContent, TextContent } from \"@mariozechner/pi-ai\";\nimport { Type } from \"@sinclair/typebox\";\nimport { constants } from \"fs\";\nimport { access, readFile } from \"fs/promises\";\nimport { detectSupportedImageMimeTypeFromFile } from \"../../utils/mime.js\";\nimport { resolveReadPath } from \"./path-utils.js\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationResult, truncateHead } from \"./truncate.js\";\n\nconst readSchema = Type.Object({\n\tpath: Type.String({ description: \"Path to the file to read (relative or absolute)\" }),\n\toffset: Type.Optional(Type.Number({ description: \"Line number to start reading from (1-indexed)\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of lines to read\" })),\n});\n\nexport interface ReadToolDetails {\n\ttruncation?: TruncationResult;\n}\n\nexport function createReadTool(cwd: string): AgentTool<typeof readSchema> {\n\treturn {\n\t\tname: \"read\",\n\t\tlabel: \"read\",\n\t\tdescription: `Read the contents of a file. Supports text files and images (jpg, png, gif, webp). Images are sent as attachments. For text files, output is truncated to ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Use offset/limit for large files.`,\n\t\tparameters: readSchema,\n\t\texecute: async (\n\t\t\t_toolCallId: string,\n\t\t\t{ path, offset, limit }: { path: string; offset?: number; limit?: number },\n\t\t\tsignal?: AbortSignal,\n\t\t) => {\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\n\n\t\t\treturn new Promise<{ content: (TextContent | ImageContent)[]; details: ReadToolDetails | undefined }>(\n\t\t\t\t(resolve, reject) => {\n\t\t\t\t\t// Check if already aborted\n\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet aborted = false;\n\n\t\t\t\t\t// Set up abort handler\n\t\t\t\t\tconst onAbort = () => {\n\t\t\t\t\t\taborted = true;\n\t\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\t};\n\n\t\t\t\t\tif (signal) {\n\t\t\t\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t\t}\n\n\t\t\t\t\t// Perform the read operation\n\t\t\t\t\t(async () => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t// Check if file exists\n\t\t\t\t\t\t\tawait access(absolutePath, constants.R_OK);\n\n\t\t\t\t\t\t\t// Check if aborted before reading\n\t\t\t\t\t\t\tif (aborted) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst mimeType = await detectSupportedImageMimeTypeFromFile(absolutePath);\n\n\t\t\t\t\t\t\t// Read the file based on type\n\t\t\t\t\t\t\tlet content: (TextContent | ImageContent)[];\n\t\t\t\t\t\t\tlet details: ReadToolDetails | undefined;\n\n\t\t\t\t\t\t\tif (mimeType) {\n\t\t\t\t\t\t\t\t// Read as image (binary)\n\t\t\t\t\t\t\t\tconst buffer = await readFile(absolutePath);\n\t\t\t\t\t\t\t\tconst base64 = buffer.toString(\"base64\");\n\n\t\t\t\t\t\t\t\tcontent = [\n\t\t\t\t\t\t\t\t\t{ type: \"text\", text: `Read image file [${mimeType}]` },\n\t\t\t\t\t\t\t\t\t{ type: \"image\", data: base64, mimeType },\n\t\t\t\t\t\t\t\t];\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t// Read as text\n\t\t\t\t\t\t\t\tconst textContent = await readFile(absolutePath, \"utf-8\");\n\t\t\t\t\t\t\t\tconst allLines = textContent.split(\"\\n\");\n\t\t\t\t\t\t\t\tconst totalFileLines = allLines.length;\n\n\t\t\t\t\t\t\t\t// Apply offset if specified (1-indexed to 0-indexed)\n\t\t\t\t\t\t\t\tconst startLine = offset ? Math.max(0, offset - 1) : 0;\n\t\t\t\t\t\t\t\tconst startLineDisplay = startLine + 1; // For display (1-indexed)\n\n\t\t\t\t\t\t\t\t// Check if offset is out of bounds\n\t\t\t\t\t\t\t\tif (startLine >= allLines.length) {\n\t\t\t\t\t\t\t\t\tthrow new Error(`Offset ${offset} is beyond end of file (${allLines.length} lines total)`);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// If limit is specified by user, use it; otherwise we'll let truncateHead decide\n\t\t\t\t\t\t\t\tlet selectedContent: string;\n\t\t\t\t\t\t\t\tlet userLimitedLines: number | undefined;\n\t\t\t\t\t\t\t\tif (limit !== undefined) {\n\t\t\t\t\t\t\t\t\tconst endLine = Math.min(startLine + limit, allLines.length);\n\t\t\t\t\t\t\t\t\tselectedContent = allLines.slice(startLine, endLine).join(\"\\n\");\n\t\t\t\t\t\t\t\t\tuserLimitedLines = endLine - startLine;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tselectedContent = allLines.slice(startLine).join(\"\\n\");\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Apply truncation (respects both line and byte limits)\n\t\t\t\t\t\t\t\tconst truncation = truncateHead(selectedContent);\n\n\t\t\t\t\t\t\t\tlet outputText: string;\n\n\t\t\t\t\t\t\t\tif (truncation.firstLineExceedsLimit) {\n\t\t\t\t\t\t\t\t\t// First line at offset exceeds 30KB - tell model to use bash\n\t\t\t\t\t\t\t\t\tconst firstLineSize = formatSize(Buffer.byteLength(allLines[startLine], \"utf-8\"));\n\t\t\t\t\t\t\t\t\toutputText = `[Line ${startLineDisplay} is ${firstLineSize}, exceeds ${formatSize(DEFAULT_MAX_BYTES)} limit. Use bash: sed -n '${startLineDisplay}p' ${path} | head -c ${DEFAULT_MAX_BYTES}]`;\n\t\t\t\t\t\t\t\t\tdetails = { truncation };\n\t\t\t\t\t\t\t\t} else if (truncation.truncated) {\n\t\t\t\t\t\t\t\t\t// Truncation occurred - build actionable notice\n\t\t\t\t\t\t\t\t\tconst endLineDisplay = startLineDisplay + truncation.outputLines - 1;\n\t\t\t\t\t\t\t\t\tconst nextOffset = endLineDisplay + 1;\n\n\t\t\t\t\t\t\t\t\toutputText = truncation.content;\n\n\t\t\t\t\t\t\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\t\t\t\t\toutputText += `\\n\\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines}. Use offset=${nextOffset} to continue]`;\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\toutputText += `\\n\\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Use offset=${nextOffset} to continue]`;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tdetails = { truncation };\n\t\t\t\t\t\t\t\t} else if (userLimitedLines !== undefined && startLine + userLimitedLines < allLines.length) {\n\t\t\t\t\t\t\t\t\t// User specified limit, there's more content, but no truncation\n\t\t\t\t\t\t\t\t\tconst remaining = allLines.length - (startLine + userLimitedLines);\n\t\t\t\t\t\t\t\t\tconst nextOffset = startLine + userLimitedLines + 1;\n\n\t\t\t\t\t\t\t\t\toutputText = truncation.content;\n\t\t\t\t\t\t\t\t\toutputText += `\\n\\n[${remaining} more lines in file. Use offset=${nextOffset} to continue]`;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t// No truncation, no user limit exceeded\n\t\t\t\t\t\t\t\t\toutputText = truncation.content;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tcontent = [{ type: \"text\", text: outputText }];\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Check if aborted after reading\n\t\t\t\t\t\t\tif (aborted) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Clean up abort handler\n\t\t\t\t\t\t\tif (signal) {\n\t\t\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tresolve({ content, details });\n\t\t\t\t\t\t} catch (error: any) {\n\t\t\t\t\t\t\t// Clean up abort handler\n\t\t\t\t\t\t\tif (signal) {\n\t\t\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (!aborted) {\n\t\t\t\t\t\t\t\treject(error);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t})();\n\t\t\t\t},\n\t\t\t);\n\t\t},\n\t};\n}\n\n/** Default read tool using process.cwd() - for backwards compatibility */\nexport const readTool = createReadTool(process.cwd());\n"]}
@@ -3,6 +3,11 @@ declare const writeSchema: import("@sinclair/typebox").TObject<{
3
3
  path: import("@sinclair/typebox").TString;
4
4
  content: import("@sinclair/typebox").TString;
5
5
  }>;
6
- export declare const writeTool: AgentTool<typeof writeSchema>;
6
+ export declare function createWriteTool(cwd: string): AgentTool<typeof writeSchema>;
7
+ /** Default write tool using process.cwd() - for backwards compatibility */
8
+ export declare const writeTool: AgentTool<import("@sinclair/typebox").TObject<{
9
+ path: import("@sinclair/typebox").TString;
10
+ content: import("@sinclair/typebox").TString;
11
+ }>, any>;
7
12
  export {};
8
13
  //# sourceMappingURL=write.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../../src/core/tools/write.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAMrD,QAAA,MAAM,WAAW;;;EAGf,CAAC;AAEH,eAAO,MAAM,SAAS,EAAE,SAAS,CAAC,OAAO,WAAW,CAsEnD,CAAC","sourcesContent":["import type { AgentTool } from \"@mariozechner/pi-ai\";\nimport { Type } from \"@sinclair/typebox\";\nimport { mkdir, writeFile } from \"fs/promises\";\nimport { dirname, resolve as resolvePath } from \"path\";\nimport { expandPath } from \"./path-utils.js\";\n\nconst writeSchema = Type.Object({\n\tpath: Type.String({ description: \"Path to the file to write (relative or absolute)\" }),\n\tcontent: Type.String({ description: \"Content to write to the file\" }),\n});\n\nexport const writeTool: AgentTool<typeof writeSchema> = {\n\tname: \"write\",\n\tlabel: \"write\",\n\tdescription:\n\t\t\"Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.\",\n\tparameters: writeSchema,\n\texecute: async (_toolCallId: string, { path, content }: { path: string; content: string }, signal?: AbortSignal) => {\n\t\tconst absolutePath = resolvePath(expandPath(path));\n\t\tconst dir = dirname(absolutePath);\n\n\t\treturn new Promise<{ content: Array<{ type: \"text\"; text: string }>; details: undefined }>((resolve, reject) => {\n\t\t\t// Check if already aborted\n\t\t\tif (signal?.aborted) {\n\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet aborted = false;\n\n\t\t\t// Set up abort handler\n\t\t\tconst onAbort = () => {\n\t\t\t\taborted = true;\n\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t};\n\n\t\t\tif (signal) {\n\t\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t}\n\n\t\t\t// Perform the write operation\n\t\t\t(async () => {\n\t\t\t\ttry {\n\t\t\t\t\t// Create parent directories if needed\n\t\t\t\t\tawait mkdir(dir, { recursive: true });\n\n\t\t\t\t\t// Check if aborted before writing\n\t\t\t\t\tif (aborted) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Write the file\n\t\t\t\t\tawait writeFile(absolutePath, content, \"utf-8\");\n\n\t\t\t\t\t// Check if aborted after writing\n\t\t\t\t\tif (aborted) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Clean up abort handler\n\t\t\t\t\tif (signal) {\n\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t}\n\n\t\t\t\t\tresolve({\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: `Successfully wrote ${content.length} bytes to ${path}` }],\n\t\t\t\t\t\tdetails: undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (error: any) {\n\t\t\t\t\t// Clean up abort handler\n\t\t\t\t\tif (signal) {\n\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!aborted) {\n\t\t\t\t\t\treject(error);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})();\n\t\t});\n\t},\n};\n"]}
1
+ {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../../src/core/tools/write.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAMrD,QAAA,MAAM,WAAW;;;EAGf,CAAC;AAEH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC,OAAO,WAAW,CAAC,CA8E1E;AAED,2EAA2E;AAC3E,eAAO,MAAM,SAAS;;;QAAiC,CAAC","sourcesContent":["import type { AgentTool } from \"@mariozechner/pi-ai\";\nimport { Type } from \"@sinclair/typebox\";\nimport { mkdir, writeFile } from \"fs/promises\";\nimport { dirname } from \"path\";\nimport { resolveToCwd } from \"./path-utils.js\";\n\nconst writeSchema = Type.Object({\n\tpath: Type.String({ description: \"Path to the file to write (relative or absolute)\" }),\n\tcontent: Type.String({ description: \"Content to write to the file\" }),\n});\n\nexport function createWriteTool(cwd: string): AgentTool<typeof writeSchema> {\n\treturn {\n\t\tname: \"write\",\n\t\tlabel: \"write\",\n\t\tdescription:\n\t\t\t\"Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.\",\n\t\tparameters: writeSchema,\n\t\texecute: async (\n\t\t\t_toolCallId: string,\n\t\t\t{ path, content }: { path: string; content: string },\n\t\t\tsignal?: AbortSignal,\n\t\t) => {\n\t\t\tconst absolutePath = resolveToCwd(path, cwd);\n\t\t\tconst dir = dirname(absolutePath);\n\n\t\t\treturn new Promise<{ content: Array<{ type: \"text\"; text: string }>; details: undefined }>(\n\t\t\t\t(resolve, reject) => {\n\t\t\t\t\t// Check if already aborted\n\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet aborted = false;\n\n\t\t\t\t\t// Set up abort handler\n\t\t\t\t\tconst onAbort = () => {\n\t\t\t\t\t\taborted = true;\n\t\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\t};\n\n\t\t\t\t\tif (signal) {\n\t\t\t\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t\t}\n\n\t\t\t\t\t// Perform the write operation\n\t\t\t\t\t(async () => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t// Create parent directories if needed\n\t\t\t\t\t\t\tawait mkdir(dir, { recursive: true });\n\n\t\t\t\t\t\t\t// Check if aborted before writing\n\t\t\t\t\t\t\tif (aborted) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Write the file\n\t\t\t\t\t\t\tawait writeFile(absolutePath, content, \"utf-8\");\n\n\t\t\t\t\t\t\t// Check if aborted after writing\n\t\t\t\t\t\t\tif (aborted) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Clean up abort handler\n\t\t\t\t\t\t\tif (signal) {\n\t\t\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: `Successfully wrote ${content.length} bytes to ${path}` }],\n\t\t\t\t\t\t\t\tdetails: undefined,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} catch (error: any) {\n\t\t\t\t\t\t\t// Clean up abort handler\n\t\t\t\t\t\t\tif (signal) {\n\t\t\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (!aborted) {\n\t\t\t\t\t\t\t\treject(error);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t})();\n\t\t\t\t},\n\t\t\t);\n\t\t},\n\t};\n}\n\n/** Default write tool using process.cwd() - for backwards compatibility */\nexport const writeTool = createWriteTool(process.cwd());\n"]}
@@ -1,69 +1,73 @@
1
1
  import { Type } from "@sinclair/typebox";
2
2
  import { mkdir, writeFile } from "fs/promises";
3
- import { dirname, resolve as resolvePath } from "path";
4
- import { expandPath } from "./path-utils.js";
3
+ import { dirname } from "path";
4
+ import { resolveToCwd } from "./path-utils.js";
5
5
  const writeSchema = Type.Object({
6
6
  path: Type.String({ description: "Path to the file to write (relative or absolute)" }),
7
7
  content: Type.String({ description: "Content to write to the file" }),
8
8
  });
9
- export const writeTool = {
10
- name: "write",
11
- label: "write",
12
- description: "Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.",
13
- parameters: writeSchema,
14
- execute: async (_toolCallId, { path, content }, signal) => {
15
- const absolutePath = resolvePath(expandPath(path));
16
- const dir = dirname(absolutePath);
17
- return new Promise((resolve, reject) => {
18
- // Check if already aborted
19
- if (signal?.aborted) {
20
- reject(new Error("Operation aborted"));
21
- return;
22
- }
23
- let aborted = false;
24
- // Set up abort handler
25
- const onAbort = () => {
26
- aborted = true;
27
- reject(new Error("Operation aborted"));
28
- };
29
- if (signal) {
30
- signal.addEventListener("abort", onAbort, { once: true });
31
- }
32
- // Perform the write operation
33
- (async () => {
34
- try {
35
- // Create parent directories if needed
36
- await mkdir(dir, { recursive: true });
37
- // Check if aborted before writing
38
- if (aborted) {
39
- return;
40
- }
41
- // Write the file
42
- await writeFile(absolutePath, content, "utf-8");
43
- // Check if aborted after writing
44
- if (aborted) {
45
- return;
46
- }
47
- // Clean up abort handler
48
- if (signal) {
49
- signal.removeEventListener("abort", onAbort);
50
- }
51
- resolve({
52
- content: [{ type: "text", text: `Successfully wrote ${content.length} bytes to ${path}` }],
53
- details: undefined,
54
- });
9
+ export function createWriteTool(cwd) {
10
+ return {
11
+ name: "write",
12
+ label: "write",
13
+ description: "Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.",
14
+ parameters: writeSchema,
15
+ execute: async (_toolCallId, { path, content }, signal) => {
16
+ const absolutePath = resolveToCwd(path, cwd);
17
+ const dir = dirname(absolutePath);
18
+ return new Promise((resolve, reject) => {
19
+ // Check if already aborted
20
+ if (signal?.aborted) {
21
+ reject(new Error("Operation aborted"));
22
+ return;
55
23
  }
56
- catch (error) {
57
- // Clean up abort handler
58
- if (signal) {
59
- signal.removeEventListener("abort", onAbort);
24
+ let aborted = false;
25
+ // Set up abort handler
26
+ const onAbort = () => {
27
+ aborted = true;
28
+ reject(new Error("Operation aborted"));
29
+ };
30
+ if (signal) {
31
+ signal.addEventListener("abort", onAbort, { once: true });
32
+ }
33
+ // Perform the write operation
34
+ (async () => {
35
+ try {
36
+ // Create parent directories if needed
37
+ await mkdir(dir, { recursive: true });
38
+ // Check if aborted before writing
39
+ if (aborted) {
40
+ return;
41
+ }
42
+ // Write the file
43
+ await writeFile(absolutePath, content, "utf-8");
44
+ // Check if aborted after writing
45
+ if (aborted) {
46
+ return;
47
+ }
48
+ // Clean up abort handler
49
+ if (signal) {
50
+ signal.removeEventListener("abort", onAbort);
51
+ }
52
+ resolve({
53
+ content: [{ type: "text", text: `Successfully wrote ${content.length} bytes to ${path}` }],
54
+ details: undefined,
55
+ });
60
56
  }
61
- if (!aborted) {
62
- reject(error);
57
+ catch (error) {
58
+ // Clean up abort handler
59
+ if (signal) {
60
+ signal.removeEventListener("abort", onAbort);
61
+ }
62
+ if (!aborted) {
63
+ reject(error);
64
+ }
63
65
  }
64
- }
65
- })();
66
- });
67
- },
68
- };
66
+ })();
67
+ });
68
+ },
69
+ };
70
+ }
71
+ /** Default write tool using process.cwd() - for backwards compatibility */
72
+ export const writeTool = createWriteTool(process.cwd());
69
73
  //# sourceMappingURL=write.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"write.js","sourceRoot":"","sources":["../../../src/core/tools/write.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,MAAM,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC;IAC/B,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,kDAAkD,EAAE,CAAC;IACtF,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,8BAA8B,EAAE,CAAC;CACrE,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,SAAS,GAAkC;IACvD,IAAI,EAAE,OAAO;IACb,KAAK,EAAE,OAAO;IACd,WAAW,EACV,iIAAiI;IAClI,UAAU,EAAE,WAAW;IACvB,OAAO,EAAE,KAAK,EAAE,WAAmB,EAAE,EAAE,IAAI,EAAE,OAAO,EAAqC,EAAE,MAAoB,EAAE,EAAE,CAAC;QACnH,MAAM,YAAY,GAAG,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;QACnD,MAAM,GAAG,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;QAElC,OAAO,IAAI,OAAO,CAAyE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC;YAC/G,2BAA2B;YAC3B,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;gBACrB,MAAM,CAAC,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC;gBACvC,OAAO;YACR,CAAC;YAED,IAAI,OAAO,GAAG,KAAK,CAAC;YAEpB,uBAAuB;YACvB,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC;gBACrB,OAAO,GAAG,IAAI,CAAC;gBACf,MAAM,CAAC,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC;YAAA,CACvC,CAAC;YAEF,IAAI,MAAM,EAAE,CAAC;gBACZ,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAC3D,CAAC;YAED,8BAA8B;YAC9B,CAAC,KAAK,IAAI,EAAE,CAAC;gBACZ,IAAI,CAAC;oBACJ,sCAAsC;oBACtC,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;oBAEtC,kCAAkC;oBAClC,IAAI,OAAO,EAAE,CAAC;wBACb,OAAO;oBACR,CAAC;oBAED,iBAAiB;oBACjB,MAAM,SAAS,CAAC,YAAY,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;oBAEhD,iCAAiC;oBACjC,IAAI,OAAO,EAAE,CAAC;wBACb,OAAO;oBACR,CAAC;oBAED,yBAAyB;oBACzB,IAAI,MAAM,EAAE,CAAC;wBACZ,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;oBAC9C,CAAC;oBAED,OAAO,CAAC;wBACP,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,sBAAsB,OAAO,CAAC,MAAM,aAAa,IAAI,EAAE,EAAE,CAAC;wBAC1F,OAAO,EAAE,SAAS;qBAClB,CAAC,CAAC;gBACJ,CAAC;gBAAC,OAAO,KAAU,EAAE,CAAC;oBACrB,yBAAyB;oBACzB,IAAI,MAAM,EAAE,CAAC;wBACZ,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;oBAC9C,CAAC;oBAED,IAAI,CAAC,OAAO,EAAE,CAAC;wBACd,MAAM,CAAC,KAAK,CAAC,CAAC;oBACf,CAAC;gBACF,CAAC;YAAA,CACD,CAAC,EAAE,CAAC;QAAA,CACL,CAAC,CAAC;IAAA,CACH;CACD,CAAC","sourcesContent":["import type { AgentTool } from \"@mariozechner/pi-ai\";\nimport { Type } from \"@sinclair/typebox\";\nimport { mkdir, writeFile } from \"fs/promises\";\nimport { dirname, resolve as resolvePath } from \"path\";\nimport { expandPath } from \"./path-utils.js\";\n\nconst writeSchema = Type.Object({\n\tpath: Type.String({ description: \"Path to the file to write (relative or absolute)\" }),\n\tcontent: Type.String({ description: \"Content to write to the file\" }),\n});\n\nexport const writeTool: AgentTool<typeof writeSchema> = {\n\tname: \"write\",\n\tlabel: \"write\",\n\tdescription:\n\t\t\"Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.\",\n\tparameters: writeSchema,\n\texecute: async (_toolCallId: string, { path, content }: { path: string; content: string }, signal?: AbortSignal) => {\n\t\tconst absolutePath = resolvePath(expandPath(path));\n\t\tconst dir = dirname(absolutePath);\n\n\t\treturn new Promise<{ content: Array<{ type: \"text\"; text: string }>; details: undefined }>((resolve, reject) => {\n\t\t\t// Check if already aborted\n\t\t\tif (signal?.aborted) {\n\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet aborted = false;\n\n\t\t\t// Set up abort handler\n\t\t\tconst onAbort = () => {\n\t\t\t\taborted = true;\n\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t};\n\n\t\t\tif (signal) {\n\t\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t}\n\n\t\t\t// Perform the write operation\n\t\t\t(async () => {\n\t\t\t\ttry {\n\t\t\t\t\t// Create parent directories if needed\n\t\t\t\t\tawait mkdir(dir, { recursive: true });\n\n\t\t\t\t\t// Check if aborted before writing\n\t\t\t\t\tif (aborted) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Write the file\n\t\t\t\t\tawait writeFile(absolutePath, content, \"utf-8\");\n\n\t\t\t\t\t// Check if aborted after writing\n\t\t\t\t\tif (aborted) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Clean up abort handler\n\t\t\t\t\tif (signal) {\n\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t}\n\n\t\t\t\t\tresolve({\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: `Successfully wrote ${content.length} bytes to ${path}` }],\n\t\t\t\t\t\tdetails: undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (error: any) {\n\t\t\t\t\t// Clean up abort handler\n\t\t\t\t\tif (signal) {\n\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!aborted) {\n\t\t\t\t\t\treject(error);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})();\n\t\t});\n\t},\n};\n"]}
1
+ {"version":3,"file":"write.js","sourceRoot":"","sources":["../../../src/core/tools/write.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@mariozechner/pi-ai\";\nimport { Type } from \"@sinclair/typebox\";\nimport { mkdir, writeFile } from \"fs/promises\";\nimport { dirname } from \"path\";\nimport { resolveToCwd } from \"./path-utils.js\";\n\nconst writeSchema = Type.Object({\n\tpath: Type.String({ description: \"Path to the file to write (relative or absolute)\" }),\n\tcontent: Type.String({ description: \"Content to write to the file\" }),\n});\n\nexport function createWriteTool(cwd: string): AgentTool<typeof writeSchema> {\n\treturn {\n\t\tname: \"write\",\n\t\tlabel: \"write\",\n\t\tdescription:\n\t\t\t\"Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.\",\n\t\tparameters: writeSchema,\n\t\texecute: async (\n\t\t\t_toolCallId: string,\n\t\t\t{ path, content }: { path: string; content: string },\n\t\t\tsignal?: AbortSignal,\n\t\t) => {\n\t\t\tconst absolutePath = resolveToCwd(path, cwd);\n\t\t\tconst dir = dirname(absolutePath);\n\n\t\t\treturn new Promise<{ content: Array<{ type: \"text\"; text: string }>; details: undefined }>(\n\t\t\t\t(resolve, reject) => {\n\t\t\t\t\t// Check if already aborted\n\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet aborted = false;\n\n\t\t\t\t\t// Set up abort handler\n\t\t\t\t\tconst onAbort = () => {\n\t\t\t\t\t\taborted = true;\n\t\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\t};\n\n\t\t\t\t\tif (signal) {\n\t\t\t\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t\t}\n\n\t\t\t\t\t// Perform the write operation\n\t\t\t\t\t(async () => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t// Create parent directories if needed\n\t\t\t\t\t\t\tawait mkdir(dir, { recursive: true });\n\n\t\t\t\t\t\t\t// Check if aborted before writing\n\t\t\t\t\t\t\tif (aborted) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Write the file\n\t\t\t\t\t\t\tawait writeFile(absolutePath, content, \"utf-8\");\n\n\t\t\t\t\t\t\t// Check if aborted after writing\n\t\t\t\t\t\t\tif (aborted) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Clean up abort handler\n\t\t\t\t\t\t\tif (signal) {\n\t\t\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: `Successfully wrote ${content.length} bytes to ${path}` }],\n\t\t\t\t\t\t\t\tdetails: undefined,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} catch (error: any) {\n\t\t\t\t\t\t\t// Clean up abort handler\n\t\t\t\t\t\t\tif (signal) {\n\t\t\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (!aborted) {\n\t\t\t\t\t\t\t\treject(error);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t})();\n\t\t\t\t},\n\t\t\t);\n\t\t},\n\t};\n}\n\n/** Default write tool using process.cwd() - for backwards compatibility */\nexport const writeTool = createWriteTool(process.cwd());\n"]}
package/dist/index.d.ts CHANGED
@@ -7,7 +7,8 @@ export { isBashToolResult, isEditToolResult, isFindToolResult, isGrepToolResult,
7
7
  export { messageTransformer } from "./core/messages.js";
8
8
  export { findModel, getApiKeyForModel, getAvailableModels } from "./core/model-config.js";
9
9
  export { getOAuthProviders, login, logout, type OAuthAuthInfo, type OAuthPrompt, type OAuthProvider, } from "./core/oauth/index.js";
10
- export { type CompactionEntry, createSummaryMessage, getLatestCompactionEntry, type LoadedSession, loadSessionFromEntries, type ModelChangeEntry, parseSessionEntries, type SessionEntry, type SessionHeader, SessionManager, type SessionMessageEntry, SUMMARY_PREFIX, SUMMARY_SUFFIX, type ThinkingLevelChangeEntry, } from "./core/session-manager.js";
10
+ export { type BuildSystemPromptOptions, buildSystemPrompt, type CreateAgentSessionOptions, type CreateAgentSessionResult, configureOAuthStorage, createAgentSession, createBashTool, createCodingTools, createEditTool, createFindTool, createGrepTool, createLsTool, createReadOnlyTools, createReadTool, createWriteTool, defaultGetApiKey, discoverAvailableModels, discoverContextFiles, discoverCustomTools, discoverHooks, discoverModels, discoverSkills, discoverSlashCommands, type FileSlashCommand, findModel as findModelByProviderAndId, loadSettings, readOnlyTools, } from "./core/sdk.js";
11
+ export { type CompactionEntry, createSummaryMessage, getLatestCompactionEntry, type LoadedSession, loadSessionFromEntries, type ModelChangeEntry, parseSessionEntries, type SessionEntry, type SessionHeader, type SessionInfo, SessionManager, type SessionMessageEntry, SUMMARY_PREFIX, SUMMARY_SUFFIX, type ThinkingLevelChangeEntry, } from "./core/session-manager.js";
11
12
  export { type CompactionSettings, type RetrySettings, type Settings, SettingsManager, type SkillsSettings, } from "./core/settings-manager.js";
12
13
  export { formatSkillsForPrompt, type LoadSkillsFromDirOptions, type LoadSkillsResult, loadSkills, loadSkillsFromDir, type Skill, type SkillFrontmatter, type SkillWarning, } from "./core/skills.js";
13
14
  export { type BashToolDetails, bashTool, codingTools, editTool, type FindToolDetails, findTool, type GrepToolDetails, grepTool, type LsToolDetails, lsTool, type ReadToolDetails, readTool, type TruncationResult, writeTool, } from "./core/tools/index.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACN,YAAY,EACZ,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,yBAAyB,EAC9B,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,YAAY,GACjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACN,KAAK,cAAc,EACnB,sBAAsB,EACtB,OAAO,EACP,2BAA2B,EAC3B,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACrB,aAAa,GACb,MAAM,sBAAsB,CAAC;AAE9B,YAAY,EACX,uBAAuB,EACvB,eAAe,EACf,iBAAiB,EACjB,qBAAqB,EACrB,UAAU,EACV,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,IAAI,gBAAgB,EAChC,OAAO,EACP,aAAa,GACb,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,0BAA0B,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC3F,YAAY,EACX,aAAa,EACb,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,iBAAiB,EACjB,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,OAAO,EACP,SAAS,EACT,gBAAgB,EAChB,WAAW,EACX,aAAa,EACb,iBAAiB,EACjB,mBAAmB,EACnB,YAAY,EACZ,aAAa,EACb,mBAAmB,EACnB,eAAe,EACf,qBAAqB,EACrB,YAAY,EACZ,cAAc,EACd,oBAAoB,GACpB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACN,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,GACjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC1F,OAAO,EACN,iBAAiB,EACjB,KAAK,EACL,MAAM,EACN,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,aAAa,GAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACN,KAAK,eAAe,EACpB,oBAAoB,EACpB,wBAAwB,EACxB,KAAK,aAAa,EAClB,sBAAsB,EACtB,KAAK,gBAAgB,EACrB,mBAAmB,EACnB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,cAAc,EACd,KAAK,mBAAmB,EACxB,cAAc,EACd,cAAc,EACd,KAAK,wBAAwB,GAC7B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACN,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,QAAQ,EACb,eAAe,EACf,KAAK,cAAc,GACnB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EACN,qBAAqB,EACrB,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,EACrB,UAAU,EACV,iBAAiB,EACjB,KAAK,KAAK,EACV,KAAK,gBAAgB,EACrB,KAAK,YAAY,GACjB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACN,KAAK,eAAe,EACpB,QAAQ,EACR,WAAW,EACX,QAAQ,EACR,KAAK,eAAe,EACpB,QAAQ,EACR,KAAK,eAAe,EACpB,QAAQ,EACR,KAAK,aAAa,EAClB,MAAM,EACN,KAAK,eAAe,EACpB,QAAQ,EACR,KAAK,gBAAgB,EACrB,SAAS,GACT,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC","sourcesContent":["// Core session management\nexport {\n\tAgentSession,\n\ttype AgentSessionConfig,\n\ttype AgentSessionEvent,\n\ttype AgentSessionEventListener,\n\ttype CompactionResult,\n\ttype ModelCycleResult,\n\ttype PromptOptions,\n\ttype SessionStats,\n} from \"./core/agent-session.js\";\n// Compaction\nexport {\n\ttype CutPointResult,\n\tcalculateContextTokens,\n\tcompact,\n\tDEFAULT_COMPACTION_SETTINGS,\n\testimateTokens,\n\tfindCutPoint,\n\tfindTurnStartIndex,\n\tgenerateSummary,\n\tgetLastAssistantUsage,\n\tshouldCompact,\n} from \"./core/compaction.js\";\n// Custom tools\nexport type {\n\tAgentToolUpdateCallback,\n\tCustomAgentTool,\n\tCustomToolFactory,\n\tCustomToolsLoadResult,\n\tExecResult,\n\tLoadedCustomTool,\n\tRenderResultOptions,\n\tSessionEvent as ToolSessionEvent,\n\tToolAPI,\n\tToolUIContext,\n} from \"./core/custom-tools/index.js\";\nexport { discoverAndLoadCustomTools, loadCustomTools } from \"./core/custom-tools/index.js\";\nexport type {\n\tAgentEndEvent,\n\tAgentStartEvent,\n\tBashToolResultEvent,\n\tBranchEvent,\n\tBranchEventResult,\n\tCustomToolResultEvent,\n\tEditToolResultEvent,\n\tFindToolResultEvent,\n\tGrepToolResultEvent,\n\tHookAPI,\n\tHookEvent,\n\tHookEventContext,\n\tHookFactory,\n\tHookUIContext,\n\tLsToolResultEvent,\n\tReadToolResultEvent,\n\tSessionEvent,\n\tToolCallEvent,\n\tToolCallEventResult,\n\tToolResultEvent,\n\tToolResultEventResult,\n\tTurnEndEvent,\n\tTurnStartEvent,\n\tWriteToolResultEvent,\n} from \"./core/hooks/index.js\";\n// Hook system types and type guards\nexport {\n\tisBashToolResult,\n\tisEditToolResult,\n\tisFindToolResult,\n\tisGrepToolResult,\n\tisLsToolResult,\n\tisReadToolResult,\n\tisWriteToolResult,\n} from \"./core/hooks/index.js\";\nexport { messageTransformer } from \"./core/messages.js\";\n// Model configuration and OAuth\nexport { findModel, getApiKeyForModel, getAvailableModels } from \"./core/model-config.js\";\nexport {\n\tgetOAuthProviders,\n\tlogin,\n\tlogout,\n\ttype OAuthAuthInfo,\n\ttype OAuthPrompt,\n\ttype OAuthProvider,\n} from \"./core/oauth/index.js\";\nexport {\n\ttype CompactionEntry,\n\tcreateSummaryMessage,\n\tgetLatestCompactionEntry,\n\ttype LoadedSession,\n\tloadSessionFromEntries,\n\ttype ModelChangeEntry,\n\tparseSessionEntries,\n\ttype SessionEntry,\n\ttype SessionHeader,\n\tSessionManager,\n\ttype SessionMessageEntry,\n\tSUMMARY_PREFIX,\n\tSUMMARY_SUFFIX,\n\ttype ThinkingLevelChangeEntry,\n} from \"./core/session-manager.js\";\nexport {\n\ttype CompactionSettings,\n\ttype RetrySettings,\n\ttype Settings,\n\tSettingsManager,\n\ttype SkillsSettings,\n} from \"./core/settings-manager.js\";\n// Skills\nexport {\n\tformatSkillsForPrompt,\n\ttype LoadSkillsFromDirOptions,\n\ttype LoadSkillsResult,\n\tloadSkills,\n\tloadSkillsFromDir,\n\ttype Skill,\n\ttype SkillFrontmatter,\n\ttype SkillWarning,\n} from \"./core/skills.js\";\n// Tools\nexport {\n\ttype BashToolDetails,\n\tbashTool,\n\tcodingTools,\n\teditTool,\n\ttype FindToolDetails,\n\tfindTool,\n\ttype GrepToolDetails,\n\tgrepTool,\n\ttype LsToolDetails,\n\tlsTool,\n\ttype ReadToolDetails,\n\treadTool,\n\ttype TruncationResult,\n\twriteTool,\n} from \"./core/tools/index.js\";\n// Main entry point\nexport { main } from \"./main.js\";\n// Theme utilities for custom tools\nexport { getMarkdownTheme } from \"./modes/interactive/theme/theme.js\";\n"]}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["// Core session management\nexport {\n\tAgentSession,\n\ttype AgentSessionConfig,\n\ttype AgentSessionEvent,\n\ttype AgentSessionEventListener,\n\ttype CompactionResult,\n\ttype ModelCycleResult,\n\ttype PromptOptions,\n\ttype SessionStats,\n} from \"./core/agent-session.js\";\n// Compaction\nexport {\n\ttype CutPointResult,\n\tcalculateContextTokens,\n\tcompact,\n\tDEFAULT_COMPACTION_SETTINGS,\n\testimateTokens,\n\tfindCutPoint,\n\tfindTurnStartIndex,\n\tgenerateSummary,\n\tgetLastAssistantUsage,\n\tshouldCompact,\n} from \"./core/compaction.js\";\n// Custom tools\nexport type {\n\tAgentToolUpdateCallback,\n\tCustomAgentTool,\n\tCustomToolFactory,\n\tCustomToolsLoadResult,\n\tExecResult,\n\tLoadedCustomTool,\n\tRenderResultOptions,\n\tSessionEvent as ToolSessionEvent,\n\tToolAPI,\n\tToolUIContext,\n} from \"./core/custom-tools/index.js\";\nexport { discoverAndLoadCustomTools, loadCustomTools } from \"./core/custom-tools/index.js\";\nexport type {\n\tAgentEndEvent,\n\tAgentStartEvent,\n\tBashToolResultEvent,\n\tBranchEvent,\n\tBranchEventResult,\n\tCustomToolResultEvent,\n\tEditToolResultEvent,\n\tFindToolResultEvent,\n\tGrepToolResultEvent,\n\tHookAPI,\n\tHookEvent,\n\tHookEventContext,\n\tHookFactory,\n\tHookUIContext,\n\tLsToolResultEvent,\n\tReadToolResultEvent,\n\tSessionEvent,\n\tToolCallEvent,\n\tToolCallEventResult,\n\tToolResultEvent,\n\tToolResultEventResult,\n\tTurnEndEvent,\n\tTurnStartEvent,\n\tWriteToolResultEvent,\n} from \"./core/hooks/index.js\";\n// Hook system types and type guards\nexport {\n\tisBashToolResult,\n\tisEditToolResult,\n\tisFindToolResult,\n\tisGrepToolResult,\n\tisLsToolResult,\n\tisReadToolResult,\n\tisWriteToolResult,\n} from \"./core/hooks/index.js\";\nexport { messageTransformer } from \"./core/messages.js\";\n// Model configuration and OAuth\nexport { findModel, getApiKeyForModel, getAvailableModels } from \"./core/model-config.js\";\nexport {\n\tgetOAuthProviders,\n\tlogin,\n\tlogout,\n\ttype OAuthAuthInfo,\n\ttype OAuthPrompt,\n\ttype OAuthProvider,\n} from \"./core/oauth/index.js\";\n// SDK for programmatic usage\nexport {\n\ttype BuildSystemPromptOptions,\n\tbuildSystemPrompt,\n\ttype CreateAgentSessionOptions,\n\ttype CreateAgentSessionResult,\n\t// Configuration\n\tconfigureOAuthStorage,\n\t// Factory\n\tcreateAgentSession,\n\tcreateBashTool,\n\t// Tool factories (for custom cwd)\n\tcreateCodingTools,\n\tcreateEditTool,\n\tcreateFindTool,\n\tcreateGrepTool,\n\tcreateLsTool,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateWriteTool,\n\t// Helpers\n\tdefaultGetApiKey,\n\tdiscoverAvailableModels,\n\tdiscoverContextFiles,\n\tdiscoverCustomTools,\n\tdiscoverHooks,\n\t// Discovery\n\tdiscoverModels,\n\tdiscoverSkills,\n\tdiscoverSlashCommands,\n\ttype FileSlashCommand,\n\tfindModel as findModelByProviderAndId,\n\tloadSettings,\n\t// Pre-built tools (use process.cwd())\n\treadOnlyTools,\n} from \"./core/sdk.js\";\nexport {\n\ttype CompactionEntry,\n\tcreateSummaryMessage,\n\tgetLatestCompactionEntry,\n\ttype LoadedSession,\n\tloadSessionFromEntries,\n\ttype ModelChangeEntry,\n\tparseSessionEntries,\n\ttype SessionEntry,\n\ttype SessionHeader,\n\ttype SessionInfo,\n\tSessionManager,\n\ttype SessionMessageEntry,\n\tSUMMARY_PREFIX,\n\tSUMMARY_SUFFIX,\n\ttype ThinkingLevelChangeEntry,\n} from \"./core/session-manager.js\";\nexport {\n\ttype CompactionSettings,\n\ttype RetrySettings,\n\ttype Settings,\n\tSettingsManager,\n\ttype SkillsSettings,\n} from \"./core/settings-manager.js\";\n// Skills\nexport {\n\tformatSkillsForPrompt,\n\ttype LoadSkillsFromDirOptions,\n\ttype LoadSkillsResult,\n\tloadSkills,\n\tloadSkillsFromDir,\n\ttype Skill,\n\ttype SkillFrontmatter,\n\ttype SkillWarning,\n} from \"./core/skills.js\";\n// Tools\nexport {\n\ttype BashToolDetails,\n\tbashTool,\n\tcodingTools,\n\teditTool,\n\ttype FindToolDetails,\n\tfindTool,\n\ttype GrepToolDetails,\n\tgrepTool,\n\ttype LsToolDetails,\n\tlsTool,\n\ttype ReadToolDetails,\n\treadTool,\n\ttype TruncationResult,\n\twriteTool,\n} from \"./core/tools/index.js\";\n// Main entry point\nexport { main } from \"./main.js\";\n// Theme utilities for custom tools\nexport { getMarkdownTheme } from \"./modes/interactive/theme/theme.js\";\n"]}
package/dist/index.js CHANGED
@@ -9,6 +9,20 @@ export { messageTransformer } from "./core/messages.js";
9
9
  // Model configuration and OAuth
10
10
  export { findModel, getApiKeyForModel, getAvailableModels } from "./core/model-config.js";
11
11
  export { getOAuthProviders, login, logout, } from "./core/oauth/index.js";
12
+ // SDK for programmatic usage
13
+ export { buildSystemPrompt,
14
+ // Configuration
15
+ configureOAuthStorage,
16
+ // Factory
17
+ createAgentSession, createBashTool,
18
+ // Tool factories (for custom cwd)
19
+ createCodingTools, createEditTool, createFindTool, createGrepTool, createLsTool, createReadOnlyTools, createReadTool, createWriteTool,
20
+ // Helpers
21
+ defaultGetApiKey, discoverAvailableModels, discoverContextFiles, discoverCustomTools, discoverHooks,
22
+ // Discovery
23
+ discoverModels, discoverSkills, discoverSlashCommands, findModel as findModelByProviderAndId, loadSettings,
24
+ // Pre-built tools (use process.cwd())
25
+ readOnlyTools, } from "./core/sdk.js";
12
26
  export { createSummaryMessage, getLatestCompactionEntry, loadSessionFromEntries, parseSessionEntries, SessionManager, SUMMARY_PREFIX, SUMMARY_SUFFIX, } from "./core/session-manager.js";
13
27
  export { SettingsManager, } from "./core/settings-manager.js";
14
28
  // Skills