iosm-cli 0.2.6 → 0.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +54 -1
- package/README.md +7 -7
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +9 -2
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-profiles.d.ts.map +1 -1
- package/dist/core/agent-profiles.js +12 -1
- package/dist/core/agent-profiles.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +40 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/sdk.d.ts +2 -2
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +3 -3
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager.d.ts +39 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +168 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/shadow-guard.js +1 -1
- package/dist/core/shadow-guard.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +91 -2
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/fetch.d.ts +56 -0
- package/dist/core/tools/fetch.d.ts.map +1 -0
- package/dist/core/tools/fetch.js +272 -0
- package/dist/core/tools/fetch.js.map +1 -0
- package/dist/core/tools/fs-ops.d.ts +54 -0
- package/dist/core/tools/fs-ops.d.ts.map +1 -0
- package/dist/core/tools/fs-ops.js +206 -0
- package/dist/core/tools/fs-ops.js.map +1 -0
- package/dist/core/tools/git-common.d.ts +45 -0
- package/dist/core/tools/git-common.d.ts.map +1 -0
- package/dist/core/tools/git-common.js +185 -0
- package/dist/core/tools/git-common.js.map +1 -0
- package/dist/core/tools/git-read.d.ts +62 -0
- package/dist/core/tools/git-read.d.ts.map +1 -0
- package/dist/core/tools/git-read.js +215 -0
- package/dist/core/tools/git-read.js.map +1 -0
- package/dist/core/tools/git-write.d.ts +75 -0
- package/dist/core/tools/git-write.d.ts.map +1 -0
- package/dist/core/tools/git-write.js +298 -0
- package/dist/core/tools/git-write.js.map +1 -0
- package/dist/core/tools/index.d.ts +90 -0
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +32 -0
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/task.js +1 -1
- package/dist/core/tools/task.js.map +1 -1
- package/dist/core/tools/web-search.d.ts +72 -0
- package/dist/core/tools/web-search.d.ts.map +1 -0
- package/dist/core/tools/web-search.js +702 -0
- package/dist/core/tools/web-search.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +7 -2
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/mcp-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/mcp-selector.js +3 -1
- package/dist/modes/interactive/components/mcp-selector.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +12 -2
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +11 -0
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +16 -5
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +4 -2
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +25 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +182 -2
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.js +7 -2
- package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
- package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/theme-selector.js +7 -2
- package/dist/modes/interactive/components/theme-selector.js.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +7 -2
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +18 -3
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.js +8 -0
- package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +4 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +184 -24
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/cli-reference.md +19 -1
- package/docs/configuration.md +11 -2
- package/docs/development-and-testing.md +1 -1
- package/docs/interactive-mode.md +2 -2
- package/docs/rpc-json-sdk.md +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { cp as fsCopy, mkdir as fsMkdir, rename as fsRename, rm as fsRm, stat as fsStat } from "node:fs/promises";
|
|
2
|
+
import { Type } from "@sinclair/typebox";
|
|
3
|
+
import { resolveToCwd } from "./path-utils.js";
|
|
4
|
+
const fsOpsSchema = Type.Object({
|
|
5
|
+
action: Type.Union([Type.Literal("mkdir"), Type.Literal("move"), Type.Literal("copy"), Type.Literal("delete")], {
|
|
6
|
+
description: "Filesystem operation: mkdir | move | copy | delete.",
|
|
7
|
+
}),
|
|
8
|
+
path: Type.Optional(Type.String({ description: "Target path for mkdir/delete actions." })),
|
|
9
|
+
from: Type.Optional(Type.String({ description: "Source path for move/copy actions." })),
|
|
10
|
+
to: Type.Optional(Type.String({ description: "Destination path for move/copy actions." })),
|
|
11
|
+
recursive: Type.Optional(Type.Boolean({
|
|
12
|
+
description: "Enable recursive behavior (required for deleting/copying directories). mkdir defaults to recursive=true.",
|
|
13
|
+
})),
|
|
14
|
+
force: Type.Optional(Type.Boolean({
|
|
15
|
+
description: "Allow replacement/no-op safety escapes. Required to overwrite destinations or ignore missing delete target.",
|
|
16
|
+
})),
|
|
17
|
+
});
|
|
18
|
+
const defaultOps = {
|
|
19
|
+
mkdir: (path, options) => fsMkdir(path, options).then(() => { }),
|
|
20
|
+
rename: (from, to) => fsRename(from, to),
|
|
21
|
+
copy: (from, to, options) => fsCopy(from, to, options).then(() => { }),
|
|
22
|
+
remove: (path, options) => fsRm(path, options).then(() => { }),
|
|
23
|
+
stat: (path) => fsStat(path),
|
|
24
|
+
};
|
|
25
|
+
function ensureNotAborted(signal) {
|
|
26
|
+
if (signal?.aborted) {
|
|
27
|
+
throw new Error("Operation aborted");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async function pathExists(ops, path) {
|
|
31
|
+
try {
|
|
32
|
+
await ops.stat(path);
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
if (error?.code === "ENOENT") {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export function createFsOpsTool(cwd, options) {
|
|
43
|
+
const ops = options?.operations ?? defaultOps;
|
|
44
|
+
const permissionGuard = options?.permissionGuard;
|
|
45
|
+
return {
|
|
46
|
+
name: "fs_ops",
|
|
47
|
+
label: "fs_ops",
|
|
48
|
+
description: "Structured filesystem mutations: mkdir, move, copy, delete. Uses explicit recursive/force safety flags for destructive operations.",
|
|
49
|
+
parameters: fsOpsSchema,
|
|
50
|
+
execute: async (_toolCallId, input, signal) => {
|
|
51
|
+
ensureNotAborted(signal);
|
|
52
|
+
const action = input.action;
|
|
53
|
+
const recursive = input.recursive ?? (action === "mkdir");
|
|
54
|
+
const force = input.force ?? false;
|
|
55
|
+
const summary = action === "move" || action === "copy"
|
|
56
|
+
? `${action} ${input.from ?? "(missing from)"} -> ${input.to ?? "(missing to)"}`
|
|
57
|
+
: `${action} ${input.path ?? "(missing path)"}`;
|
|
58
|
+
if (permissionGuard) {
|
|
59
|
+
const allowed = await permissionGuard({
|
|
60
|
+
toolName: "fs_ops",
|
|
61
|
+
cwd,
|
|
62
|
+
input: {
|
|
63
|
+
action,
|
|
64
|
+
path: input.path,
|
|
65
|
+
from: input.from,
|
|
66
|
+
to: input.to,
|
|
67
|
+
recursive,
|
|
68
|
+
force,
|
|
69
|
+
},
|
|
70
|
+
summary,
|
|
71
|
+
});
|
|
72
|
+
if (!allowed) {
|
|
73
|
+
throw new Error("Permission denied for fs_ops operation.");
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (action === "mkdir") {
|
|
77
|
+
if (!input.path) {
|
|
78
|
+
throw new Error("fs_ops mkdir requires path.");
|
|
79
|
+
}
|
|
80
|
+
const resolvedPath = resolveToCwd(input.path, cwd);
|
|
81
|
+
await ops.mkdir(resolvedPath, { recursive });
|
|
82
|
+
return {
|
|
83
|
+
content: [{ type: "text", text: `Created directory: ${input.path}` }],
|
|
84
|
+
details: {
|
|
85
|
+
action,
|
|
86
|
+
resolvedPath,
|
|
87
|
+
recursive,
|
|
88
|
+
force,
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
if (action === "delete") {
|
|
93
|
+
if (!input.path) {
|
|
94
|
+
throw new Error("fs_ops delete requires path.");
|
|
95
|
+
}
|
|
96
|
+
const resolvedPath = resolveToCwd(input.path, cwd);
|
|
97
|
+
const exists = await pathExists(ops, resolvedPath);
|
|
98
|
+
if (!exists) {
|
|
99
|
+
if (!force) {
|
|
100
|
+
throw new Error(`Path not found: ${input.path}`);
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
content: [{ type: "text", text: `Skipped delete (path missing): ${input.path}` }],
|
|
104
|
+
details: {
|
|
105
|
+
action,
|
|
106
|
+
resolvedPath,
|
|
107
|
+
recursive,
|
|
108
|
+
force,
|
|
109
|
+
noop: true,
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
const sourceStat = await ops.stat(resolvedPath);
|
|
114
|
+
if (sourceStat.isDirectory() && !recursive) {
|
|
115
|
+
throw new Error("Deleting a directory requires recursive=true.");
|
|
116
|
+
}
|
|
117
|
+
ensureNotAborted(signal);
|
|
118
|
+
await ops.remove(resolvedPath, {
|
|
119
|
+
recursive: sourceStat.isDirectory(),
|
|
120
|
+
force: false,
|
|
121
|
+
});
|
|
122
|
+
return {
|
|
123
|
+
content: [{ type: "text", text: `Deleted: ${input.path}` }],
|
|
124
|
+
details: {
|
|
125
|
+
action,
|
|
126
|
+
resolvedPath,
|
|
127
|
+
recursive,
|
|
128
|
+
force,
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
if (!input.from || !input.to) {
|
|
133
|
+
throw new Error(`fs_ops ${action} requires both from and to.`);
|
|
134
|
+
}
|
|
135
|
+
const resolvedFrom = resolveToCwd(input.from, cwd);
|
|
136
|
+
const resolvedTo = resolveToCwd(input.to, cwd);
|
|
137
|
+
const sourceExists = await pathExists(ops, resolvedFrom);
|
|
138
|
+
if (!sourceExists) {
|
|
139
|
+
throw new Error(`Source path not found: ${input.from}`);
|
|
140
|
+
}
|
|
141
|
+
const destinationExists = await pathExists(ops, resolvedTo);
|
|
142
|
+
if (destinationExists && !force) {
|
|
143
|
+
throw new Error(`Destination already exists: ${input.to}. Pass force=true to replace.`);
|
|
144
|
+
}
|
|
145
|
+
if (destinationExists && force) {
|
|
146
|
+
ensureNotAborted(signal);
|
|
147
|
+
await ops.remove(resolvedTo, { recursive: true, force: true });
|
|
148
|
+
}
|
|
149
|
+
const sourceStat = await ops.stat(resolvedFrom);
|
|
150
|
+
const sourceIsDirectory = sourceStat.isDirectory();
|
|
151
|
+
if (action === "copy" && sourceIsDirectory && !recursive) {
|
|
152
|
+
throw new Error("Copying a directory requires recursive=true.");
|
|
153
|
+
}
|
|
154
|
+
if (action === "copy") {
|
|
155
|
+
ensureNotAborted(signal);
|
|
156
|
+
await ops.copy(resolvedFrom, resolvedTo, {
|
|
157
|
+
recursive: sourceIsDirectory,
|
|
158
|
+
force,
|
|
159
|
+
});
|
|
160
|
+
return {
|
|
161
|
+
content: [{ type: "text", text: `Copied: ${input.from} -> ${input.to}` }],
|
|
162
|
+
details: {
|
|
163
|
+
action,
|
|
164
|
+
resolvedFrom,
|
|
165
|
+
resolvedTo,
|
|
166
|
+
recursive,
|
|
167
|
+
force,
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
let exdevFallback = false;
|
|
172
|
+
try {
|
|
173
|
+
ensureNotAborted(signal);
|
|
174
|
+
await ops.rename(resolvedFrom, resolvedTo);
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
if (error?.code !== "EXDEV") {
|
|
178
|
+
throw error;
|
|
179
|
+
}
|
|
180
|
+
exdevFallback = true;
|
|
181
|
+
ensureNotAborted(signal);
|
|
182
|
+
await ops.copy(resolvedFrom, resolvedTo, {
|
|
183
|
+
recursive: sourceIsDirectory,
|
|
184
|
+
force: true,
|
|
185
|
+
});
|
|
186
|
+
await ops.remove(resolvedFrom, {
|
|
187
|
+
recursive: sourceIsDirectory,
|
|
188
|
+
force: false,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
content: [{ type: "text", text: `Moved: ${input.from} -> ${input.to}` }],
|
|
193
|
+
details: {
|
|
194
|
+
action,
|
|
195
|
+
resolvedFrom,
|
|
196
|
+
resolvedTo,
|
|
197
|
+
recursive,
|
|
198
|
+
force,
|
|
199
|
+
exdevFallback: exdevFallback || undefined,
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
export const fsOpsTool = createFsOpsTool(process.cwd());
|
|
206
|
+
//# sourceMappingURL=fs-ops.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs-ops.js","sourceRoot":"","sources":["../../../src/core/tools/fs-ops.ts"],"names":[],"mappings":"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","sourcesContent":["import { cp as fsCopy, mkdir as fsMkdir, rename as fsRename, rm as fsRm, stat as fsStat } from \"node:fs/promises\";\nimport type { AgentTool } from \"@mariozechner/pi-agent-core\";\nimport { type Static, Type } from \"@sinclair/typebox\";\nimport { resolveToCwd } from \"./path-utils.js\";\nimport type { ToolPermissionGuard } from \"./permissions.js\";\n\nconst fsOpsSchema = Type.Object({\n\taction: Type.Union([Type.Literal(\"mkdir\"), Type.Literal(\"move\"), Type.Literal(\"copy\"), Type.Literal(\"delete\")], {\n\t\tdescription: \"Filesystem operation: mkdir | move | copy | delete.\",\n\t}),\n\tpath: Type.Optional(Type.String({ description: \"Target path for mkdir/delete actions.\" })),\n\tfrom: Type.Optional(Type.String({ description: \"Source path for move/copy actions.\" })),\n\tto: Type.Optional(Type.String({ description: \"Destination path for move/copy actions.\" })),\n\trecursive: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"Enable recursive behavior (required for deleting/copying directories). mkdir defaults to recursive=true.\",\n\t\t}),\n\t),\n\tforce: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"Allow replacement/no-op safety escapes. Required to overwrite destinations or ignore missing delete target.\",\n\t\t}),\n\t),\n});\n\nexport type FsOpsToolInput = Static<typeof fsOpsSchema>;\n\nexport interface FsOpsToolDetails {\n\taction: \"mkdir\" | \"move\" | \"copy\" | \"delete\";\n\tresolvedPath?: string;\n\tresolvedFrom?: string;\n\tresolvedTo?: string;\n\trecursive?: boolean;\n\tforce?: boolean;\n\texdevFallback?: boolean;\n\tnoop?: boolean;\n}\n\ninterface FsOpsOperations {\n\tmkdir(path: string, options: { recursive: boolean }): Promise<void>;\n\trename(from: string, to: string): Promise<void>;\n\tcopy(from: string, to: string, options: { recursive: boolean; force: boolean }): Promise<void>;\n\tremove(path: string, options: { recursive: boolean; force: boolean }): Promise<void>;\n\tstat(path: string): Promise<{ isDirectory: () => boolean }>;\n}\n\nconst defaultOps: FsOpsOperations = {\n\tmkdir: (path, options) => fsMkdir(path, options).then(() => {}),\n\trename: (from, to) => fsRename(from, to),\n\tcopy: (from, to, options) => fsCopy(from, to, options).then(() => {}),\n\tremove: (path, options) => fsRm(path, options).then(() => {}),\n\tstat: (path) => fsStat(path),\n};\n\nexport interface FsOpsToolOptions {\n\toperations?: FsOpsOperations;\n\tpermissionGuard?: ToolPermissionGuard;\n}\n\nfunction ensureNotAborted(signal?: AbortSignal): void {\n\tif (signal?.aborted) {\n\t\tthrow new Error(\"Operation aborted\");\n\t}\n}\n\nasync function pathExists(ops: FsOpsOperations, path: string): Promise<boolean> {\n\ttry {\n\t\tawait ops.stat(path);\n\t\treturn true;\n\t} catch (error: any) {\n\t\tif (error?.code === \"ENOENT\") {\n\t\t\treturn false;\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nexport function createFsOpsTool(cwd: string, options?: FsOpsToolOptions): AgentTool<typeof fsOpsSchema> {\n\tconst ops = options?.operations ?? defaultOps;\n\tconst permissionGuard = options?.permissionGuard;\n\n\treturn {\n\t\tname: \"fs_ops\",\n\t\tlabel: \"fs_ops\",\n\t\tdescription:\n\t\t\t\"Structured filesystem mutations: mkdir, move, copy, delete. Uses explicit recursive/force safety flags for destructive operations.\",\n\t\tparameters: fsOpsSchema,\n\t\texecute: async (_toolCallId: string, input: FsOpsToolInput, signal?: AbortSignal) => {\n\t\t\tensureNotAborted(signal);\n\t\t\tconst action = input.action;\n\t\t\tconst recursive = input.recursive ?? (action === \"mkdir\");\n\t\t\tconst force = input.force ?? false;\n\n\t\t\tconst summary =\n\t\t\t\taction === \"move\" || action === \"copy\"\n\t\t\t\t\t? `${action} ${input.from ?? \"(missing from)\"} -> ${input.to ?? \"(missing to)\"}`\n\t\t\t\t\t: `${action} ${input.path ?? \"(missing path)\"}`;\n\n\t\t\tif (permissionGuard) {\n\t\t\t\tconst allowed = await permissionGuard({\n\t\t\t\t\ttoolName: \"fs_ops\",\n\t\t\t\t\tcwd,\n\t\t\t\t\tinput: {\n\t\t\t\t\t\taction,\n\t\t\t\t\t\tpath: input.path,\n\t\t\t\t\t\tfrom: input.from,\n\t\t\t\t\t\tto: input.to,\n\t\t\t\t\t\trecursive,\n\t\t\t\t\t\tforce,\n\t\t\t\t\t},\n\t\t\t\t\tsummary,\n\t\t\t\t});\n\t\t\t\tif (!allowed) {\n\t\t\t\t\tthrow new Error(\"Permission denied for fs_ops operation.\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (action === \"mkdir\") {\n\t\t\t\tif (!input.path) {\n\t\t\t\t\tthrow new Error(\"fs_ops mkdir requires path.\");\n\t\t\t\t}\n\t\t\t\tconst resolvedPath = resolveToCwd(input.path, cwd);\n\t\t\t\tawait ops.mkdir(resolvedPath, { recursive });\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `Created directory: ${input.path}` }],\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\taction,\n\t\t\t\t\t\tresolvedPath,\n\t\t\t\t\t\trecursive,\n\t\t\t\t\t\tforce,\n\t\t\t\t\t} as FsOpsToolDetails,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (action === \"delete\") {\n\t\t\t\tif (!input.path) {\n\t\t\t\t\tthrow new Error(\"fs_ops delete requires path.\");\n\t\t\t\t}\n\t\t\t\tconst resolvedPath = resolveToCwd(input.path, cwd);\n\t\t\t\tconst exists = await pathExists(ops, resolvedPath);\n\t\t\t\tif (!exists) {\n\t\t\t\t\tif (!force) {\n\t\t\t\t\t\tthrow new Error(`Path not found: ${input.path}`);\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: `Skipped delete (path missing): ${input.path}` }],\n\t\t\t\t\t\tdetails: {\n\t\t\t\t\t\t\taction,\n\t\t\t\t\t\t\tresolvedPath,\n\t\t\t\t\t\t\trecursive,\n\t\t\t\t\t\t\tforce,\n\t\t\t\t\t\t\tnoop: true,\n\t\t\t\t\t\t} as FsOpsToolDetails,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconst sourceStat = await ops.stat(resolvedPath);\n\t\t\t\tif (sourceStat.isDirectory() && !recursive) {\n\t\t\t\t\tthrow new Error(\"Deleting a directory requires recursive=true.\");\n\t\t\t\t}\n\n\t\t\t\tensureNotAborted(signal);\n\t\t\t\tawait ops.remove(resolvedPath, {\n\t\t\t\t\trecursive: sourceStat.isDirectory(),\n\t\t\t\t\tforce: false,\n\t\t\t\t});\n\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `Deleted: ${input.path}` }],\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\taction,\n\t\t\t\t\t\tresolvedPath,\n\t\t\t\t\t\trecursive,\n\t\t\t\t\t\tforce,\n\t\t\t\t\t} as FsOpsToolDetails,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (!input.from || !input.to) {\n\t\t\t\tthrow new Error(`fs_ops ${action} requires both from and to.`);\n\t\t\t}\n\n\t\t\tconst resolvedFrom = resolveToCwd(input.from, cwd);\n\t\t\tconst resolvedTo = resolveToCwd(input.to, cwd);\n\t\t\tconst sourceExists = await pathExists(ops, resolvedFrom);\n\t\t\tif (!sourceExists) {\n\t\t\t\tthrow new Error(`Source path not found: ${input.from}`);\n\t\t\t}\n\t\t\tconst destinationExists = await pathExists(ops, resolvedTo);\n\t\t\tif (destinationExists && !force) {\n\t\t\t\tthrow new Error(`Destination already exists: ${input.to}. Pass force=true to replace.`);\n\t\t\t}\n\t\t\tif (destinationExists && force) {\n\t\t\t\tensureNotAborted(signal);\n\t\t\t\tawait ops.remove(resolvedTo, { recursive: true, force: true });\n\t\t\t}\n\n\t\t\tconst sourceStat = await ops.stat(resolvedFrom);\n\t\t\tconst sourceIsDirectory = sourceStat.isDirectory();\n\t\t\tif (action === \"copy\" && sourceIsDirectory && !recursive) {\n\t\t\t\tthrow new Error(\"Copying a directory requires recursive=true.\");\n\t\t\t}\n\n\t\t\tif (action === \"copy\") {\n\t\t\t\tensureNotAborted(signal);\n\t\t\t\tawait ops.copy(resolvedFrom, resolvedTo, {\n\t\t\t\t\trecursive: sourceIsDirectory,\n\t\t\t\t\tforce,\n\t\t\t\t});\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `Copied: ${input.from} -> ${input.to}` }],\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\taction,\n\t\t\t\t\t\tresolvedFrom,\n\t\t\t\t\t\tresolvedTo,\n\t\t\t\t\t\trecursive,\n\t\t\t\t\t\tforce,\n\t\t\t\t\t} as FsOpsToolDetails,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tlet exdevFallback = false;\n\t\t\ttry {\n\t\t\t\tensureNotAborted(signal);\n\t\t\t\tawait ops.rename(resolvedFrom, resolvedTo);\n\t\t\t} catch (error: any) {\n\t\t\t\tif (error?.code !== \"EXDEV\") {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\texdevFallback = true;\n\t\t\t\tensureNotAborted(signal);\n\t\t\t\tawait ops.copy(resolvedFrom, resolvedTo, {\n\t\t\t\t\trecursive: sourceIsDirectory,\n\t\t\t\t\tforce: true,\n\t\t\t\t});\n\t\t\t\tawait ops.remove(resolvedFrom, {\n\t\t\t\t\trecursive: sourceIsDirectory,\n\t\t\t\t\tforce: false,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: `Moved: ${input.from} -> ${input.to}` }],\n\t\t\t\tdetails: {\n\t\t\t\t\taction,\n\t\t\t\t\tresolvedFrom,\n\t\t\t\t\tresolvedTo,\n\t\t\t\t\trecursive,\n\t\t\t\t\tforce,\n\t\t\t\t\texdevFallback: exdevFallback || undefined,\n\t\t\t\t} as FsOpsToolDetails,\n\t\t\t};\n\t\t},\n\t};\n}\n\nexport const fsOpsTool = createFsOpsTool(process.cwd());\n"]}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type TruncationResult } from "./truncate.js";
|
|
2
|
+
export declare const DEFAULT_GIT_TIMEOUT_SECONDS = 30;
|
|
3
|
+
export declare const MAX_GIT_CAPTURE_BYTES: number;
|
|
4
|
+
export interface RunGitCommandResult {
|
|
5
|
+
stdout: string;
|
|
6
|
+
stderr: string;
|
|
7
|
+
exitCode: number;
|
|
8
|
+
captureTruncated: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface GitCommandExecutionOptions {
|
|
11
|
+
env?: NodeJS.ProcessEnv;
|
|
12
|
+
}
|
|
13
|
+
export type GitCommandExists = (command: string) => boolean;
|
|
14
|
+
export type RunGitCommand = (args: string[], cwd: string, timeoutMs: number, signal?: AbortSignal, executionOptions?: GitCommandExecutionOptions) => Promise<RunGitCommandResult>;
|
|
15
|
+
export interface GitCommandOptions {
|
|
16
|
+
commandExists?: GitCommandExists;
|
|
17
|
+
runCommand?: RunGitCommand;
|
|
18
|
+
}
|
|
19
|
+
export interface GitRunSummary {
|
|
20
|
+
output: string;
|
|
21
|
+
captureTruncated: boolean;
|
|
22
|
+
truncation?: TruncationResult;
|
|
23
|
+
exitCode: number;
|
|
24
|
+
}
|
|
25
|
+
export interface GitRunParams {
|
|
26
|
+
toolName: string;
|
|
27
|
+
action: string;
|
|
28
|
+
args: string[];
|
|
29
|
+
cwd: string;
|
|
30
|
+
timeoutSeconds: number;
|
|
31
|
+
runCommand: RunGitCommand;
|
|
32
|
+
signal?: AbortSignal;
|
|
33
|
+
env?: NodeJS.ProcessEnv;
|
|
34
|
+
}
|
|
35
|
+
export declare function resolveGitCommandOptions(options?: GitCommandOptions): {
|
|
36
|
+
hasCommand: GitCommandExists;
|
|
37
|
+
runCommand: RunGitCommand;
|
|
38
|
+
};
|
|
39
|
+
export declare function normalizePositiveInt(raw: number | undefined, fallback: number, field: string): number;
|
|
40
|
+
export declare function normalizeRefLike(raw: string | undefined, field: string): string | undefined;
|
|
41
|
+
export declare function requireRefLike(raw: string | undefined, field: string): string;
|
|
42
|
+
export declare function normalizeRequiredString(raw: string | undefined, field: string): string;
|
|
43
|
+
export declare function normalizeFiles(files: string[] | undefined, field: string): string[];
|
|
44
|
+
export declare function runGitAndFormatOutput(params: GitRunParams): Promise<GitRunSummary>;
|
|
45
|
+
//# sourceMappingURL=git-common.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-common.d.ts","sourceRoot":"","sources":["../../../src/core/tools/git-common.ts"],"names":[],"mappings":"AACA,OAAO,EAIN,KAAK,gBAAgB,EAErB,MAAM,eAAe,CAAC;AAEvB,eAAO,MAAM,2BAA2B,KAAK,CAAC;AAC9C,eAAO,MAAM,qBAAqB,QAAa,CAAC;AAEhD,MAAM,WAAW,mBAAmB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,0BAA0B;IAC1C,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACxB;AAED,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;AAE5D,MAAM,MAAM,aAAa,GAAG,CAC3B,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,WAAW,EACpB,gBAAgB,CAAC,EAAE,0BAA0B,KACzC,OAAO,CAAC,mBAAmB,CAAC,CAAC;AAElC,MAAM,WAAW,iBAAiB;IACjC,aAAa,CAAC,EAAE,gBAAgB,CAAC;IACjC,UAAU,CAAC,EAAE,aAAa,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,OAAO,CAAC;IAC1B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,aAAa,CAAC;IAC1B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACxB;AAuHD,wBAAgB,wBAAwB,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG;IACtE,UAAU,EAAE,gBAAgB,CAAC;IAC7B,UAAU,EAAE,aAAa,CAAC;CAC1B,CAKA;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAOrG;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAU3F;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAM7E;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAMtF;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAWnF;AAED,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAsCxF"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
2
|
+
import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, truncateHead, } from "./truncate.js";
|
|
3
|
+
export const DEFAULT_GIT_TIMEOUT_SECONDS = 30;
|
|
4
|
+
export const MAX_GIT_CAPTURE_BYTES = 512 * 1024;
|
|
5
|
+
function commandExists(command) {
|
|
6
|
+
try {
|
|
7
|
+
const result = spawnSync(command, ["--version"], { stdio: "pipe" });
|
|
8
|
+
const err = result.error;
|
|
9
|
+
return !err || err.code !== "ENOENT";
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function runGitCommand(args, cwd, timeoutMs, signal, executionOptions) {
|
|
16
|
+
return new Promise((resolve, reject) => {
|
|
17
|
+
if (signal?.aborted) {
|
|
18
|
+
reject(new Error("Operation aborted"));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const child = spawn("git", args, {
|
|
22
|
+
cwd,
|
|
23
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
24
|
+
env: executionOptions?.env ? { ...process.env, ...executionOptions.env } : process.env,
|
|
25
|
+
});
|
|
26
|
+
const stdoutChunks = [];
|
|
27
|
+
const stderrChunks = [];
|
|
28
|
+
let stdoutBytes = 0;
|
|
29
|
+
let stderrBytes = 0;
|
|
30
|
+
let captureTruncated = false;
|
|
31
|
+
let timedOut = false;
|
|
32
|
+
let aborted = false;
|
|
33
|
+
let settled = false;
|
|
34
|
+
const settle = (fn) => {
|
|
35
|
+
if (!settled) {
|
|
36
|
+
settled = true;
|
|
37
|
+
fn();
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const captureChunk = (chunk, chunks, currentBytes) => {
|
|
41
|
+
if (currentBytes >= MAX_GIT_CAPTURE_BYTES) {
|
|
42
|
+
return { nextBytes: currentBytes, truncated: true };
|
|
43
|
+
}
|
|
44
|
+
const remaining = MAX_GIT_CAPTURE_BYTES - currentBytes;
|
|
45
|
+
if (chunk.length <= remaining) {
|
|
46
|
+
chunks.push(chunk);
|
|
47
|
+
return { nextBytes: currentBytes + chunk.length, truncated: false };
|
|
48
|
+
}
|
|
49
|
+
chunks.push(chunk.subarray(0, remaining));
|
|
50
|
+
return { nextBytes: MAX_GIT_CAPTURE_BYTES, truncated: true };
|
|
51
|
+
};
|
|
52
|
+
const timeoutHandle = setTimeout(() => {
|
|
53
|
+
timedOut = true;
|
|
54
|
+
child.kill("SIGTERM");
|
|
55
|
+
}, Math.max(1000, timeoutMs));
|
|
56
|
+
const onAbort = () => {
|
|
57
|
+
aborted = true;
|
|
58
|
+
child.kill("SIGTERM");
|
|
59
|
+
};
|
|
60
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
61
|
+
const cleanup = () => {
|
|
62
|
+
clearTimeout(timeoutHandle);
|
|
63
|
+
signal?.removeEventListener("abort", onAbort);
|
|
64
|
+
};
|
|
65
|
+
child.stdout.on("data", (chunk) => {
|
|
66
|
+
const captured = captureChunk(chunk, stdoutChunks, stdoutBytes);
|
|
67
|
+
stdoutBytes = captured.nextBytes;
|
|
68
|
+
captureTruncated = captureTruncated || captured.truncated;
|
|
69
|
+
});
|
|
70
|
+
child.stderr.on("data", (chunk) => {
|
|
71
|
+
const captured = captureChunk(chunk, stderrChunks, stderrBytes);
|
|
72
|
+
stderrBytes = captured.nextBytes;
|
|
73
|
+
captureTruncated = captureTruncated || captured.truncated;
|
|
74
|
+
});
|
|
75
|
+
child.on("error", (error) => {
|
|
76
|
+
cleanup();
|
|
77
|
+
settle(() => reject(new Error(`Failed to run git: ${error.message}`)));
|
|
78
|
+
});
|
|
79
|
+
child.on("close", (code) => {
|
|
80
|
+
cleanup();
|
|
81
|
+
if (aborted) {
|
|
82
|
+
settle(() => reject(new Error("Operation aborted")));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (timedOut) {
|
|
86
|
+
settle(() => reject(new Error(`Command timed out after ${Math.round(timeoutMs / 1000)}s`)));
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
settle(() => resolve({
|
|
90
|
+
stdout: Buffer.concat(stdoutChunks).toString("utf-8"),
|
|
91
|
+
stderr: Buffer.concat(stderrChunks).toString("utf-8"),
|
|
92
|
+
exitCode: code ?? -1,
|
|
93
|
+
captureTruncated,
|
|
94
|
+
}));
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
export function resolveGitCommandOptions(options) {
|
|
99
|
+
return {
|
|
100
|
+
hasCommand: options?.commandExists ?? commandExists,
|
|
101
|
+
runCommand: options?.runCommand ?? runGitCommand,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
export function normalizePositiveInt(raw, fallback, field) {
|
|
105
|
+
if (raw === undefined)
|
|
106
|
+
return fallback;
|
|
107
|
+
const value = Math.floor(raw);
|
|
108
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
109
|
+
throw new Error(`${field} must be a positive number.`);
|
|
110
|
+
}
|
|
111
|
+
return value;
|
|
112
|
+
}
|
|
113
|
+
export function normalizeRefLike(raw, field) {
|
|
114
|
+
if (raw === undefined)
|
|
115
|
+
return undefined;
|
|
116
|
+
const normalized = raw.trim();
|
|
117
|
+
if (normalized.length === 0) {
|
|
118
|
+
throw new Error(`${field} must not be empty.`);
|
|
119
|
+
}
|
|
120
|
+
if (normalized.startsWith("-")) {
|
|
121
|
+
throw new Error(`${field} must not start with '-'.`);
|
|
122
|
+
}
|
|
123
|
+
return normalized;
|
|
124
|
+
}
|
|
125
|
+
export function requireRefLike(raw, field) {
|
|
126
|
+
const normalized = normalizeRefLike(raw, field);
|
|
127
|
+
if (!normalized) {
|
|
128
|
+
throw new Error(`${field} is required.`);
|
|
129
|
+
}
|
|
130
|
+
return normalized;
|
|
131
|
+
}
|
|
132
|
+
export function normalizeRequiredString(raw, field) {
|
|
133
|
+
const value = raw?.trim();
|
|
134
|
+
if (!value) {
|
|
135
|
+
throw new Error(`${field} is required.`);
|
|
136
|
+
}
|
|
137
|
+
return value;
|
|
138
|
+
}
|
|
139
|
+
export function normalizeFiles(files, field) {
|
|
140
|
+
if (!files || files.length === 0) {
|
|
141
|
+
throw new Error(`${field} is required.`);
|
|
142
|
+
}
|
|
143
|
+
const normalized = files
|
|
144
|
+
.map((file) => file.trim())
|
|
145
|
+
.filter((file) => file.length > 0);
|
|
146
|
+
if (normalized.length === 0) {
|
|
147
|
+
throw new Error(`${field} must include at least one non-empty path.`);
|
|
148
|
+
}
|
|
149
|
+
return normalized;
|
|
150
|
+
}
|
|
151
|
+
export async function runGitAndFormatOutput(params) {
|
|
152
|
+
const result = await params.runCommand(params.args, params.cwd, params.timeoutSeconds * 1000, params.signal, {
|
|
153
|
+
env: params.env,
|
|
154
|
+
});
|
|
155
|
+
if (result.exitCode !== 0) {
|
|
156
|
+
const errorText = result.stderr.trim() || result.stdout.trim() || `${params.toolName} ${params.action} failed with exit code ${result.exitCode}`;
|
|
157
|
+
throw new Error(errorText);
|
|
158
|
+
}
|
|
159
|
+
let output = result.stdout.trimEnd();
|
|
160
|
+
if (!output && result.stderr.trim().length > 0) {
|
|
161
|
+
output = result.stderr.trimEnd();
|
|
162
|
+
}
|
|
163
|
+
if (!output) {
|
|
164
|
+
output = "No output";
|
|
165
|
+
}
|
|
166
|
+
const truncation = truncateHead(output);
|
|
167
|
+
let finalOutput = truncation.content;
|
|
168
|
+
const notices = [];
|
|
169
|
+
if (truncation.truncated) {
|
|
170
|
+
notices.push(`${formatSize(DEFAULT_MAX_BYTES)} output limit reached`);
|
|
171
|
+
}
|
|
172
|
+
if (result.captureTruncated) {
|
|
173
|
+
notices.push(`capture limit reached (${formatSize(MAX_GIT_CAPTURE_BYTES)})`);
|
|
174
|
+
}
|
|
175
|
+
if (notices.length > 0) {
|
|
176
|
+
finalOutput += `\n\n[${notices.join(". ")} · showing up to ${DEFAULT_MAX_LINES} lines]`;
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
output: finalOutput,
|
|
180
|
+
captureTruncated: result.captureTruncated,
|
|
181
|
+
truncation: truncation.truncated ? truncation : undefined,
|
|
182
|
+
exitCode: result.exitCode,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=git-common.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-common.js","sourceRoot":"","sources":["../../../src/core/tools/git-common.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn, spawnSync } from \"node:child_process\";\nimport {\n\tDEFAULT_MAX_BYTES,\n\tDEFAULT_MAX_LINES,\n\tformatSize,\n\ttype TruncationResult,\n\ttruncateHead,\n} from \"./truncate.js\";\n\nexport const DEFAULT_GIT_TIMEOUT_SECONDS = 30;\nexport const MAX_GIT_CAPTURE_BYTES = 512 * 1024;\n\nexport interface RunGitCommandResult {\n\tstdout: string;\n\tstderr: string;\n\texitCode: number;\n\tcaptureTruncated: boolean;\n}\n\nexport interface GitCommandExecutionOptions {\n\tenv?: NodeJS.ProcessEnv;\n}\n\nexport type GitCommandExists = (command: string) => boolean;\n\nexport type RunGitCommand = (\n\targs: string[],\n\tcwd: string,\n\ttimeoutMs: number,\n\tsignal?: AbortSignal,\n\texecutionOptions?: GitCommandExecutionOptions,\n) => Promise<RunGitCommandResult>;\n\nexport interface GitCommandOptions {\n\tcommandExists?: GitCommandExists;\n\trunCommand?: RunGitCommand;\n}\n\nexport interface GitRunSummary {\n\toutput: string;\n\tcaptureTruncated: boolean;\n\ttruncation?: TruncationResult;\n\texitCode: number;\n}\n\nexport interface GitRunParams {\n\ttoolName: string;\n\taction: string;\n\targs: string[];\n\tcwd: string;\n\ttimeoutSeconds: number;\n\trunCommand: RunGitCommand;\n\tsignal?: AbortSignal;\n\tenv?: NodeJS.ProcessEnv;\n}\n\nfunction commandExists(command: string): boolean {\n\ttry {\n\t\tconst result = spawnSync(command, [\"--version\"], { stdio: \"pipe\" });\n\t\tconst err = result.error as NodeJS.ErrnoException | undefined;\n\t\treturn !err || err.code !== \"ENOENT\";\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction runGitCommand(\n\targs: string[],\n\tcwd: string,\n\ttimeoutMs: number,\n\tsignal?: AbortSignal,\n\texecutionOptions?: GitCommandExecutionOptions,\n): Promise<RunGitCommandResult> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (signal?.aborted) {\n\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\treturn;\n\t\t}\n\n\t\tconst child = spawn(\"git\", args, {\n\t\t\tcwd,\n\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\tenv: executionOptions?.env ? { ...process.env, ...executionOptions.env } : process.env,\n\t\t});\n\n\t\tconst stdoutChunks: Buffer[] = [];\n\t\tconst stderrChunks: Buffer[] = [];\n\t\tlet stdoutBytes = 0;\n\t\tlet stderrBytes = 0;\n\t\tlet captureTruncated = false;\n\t\tlet timedOut = false;\n\t\tlet aborted = false;\n\t\tlet settled = false;\n\n\t\tconst settle = (fn: () => void) => {\n\t\t\tif (!settled) {\n\t\t\t\tsettled = true;\n\t\t\t\tfn();\n\t\t\t}\n\t\t};\n\n\t\tconst captureChunk = (\n\t\t\tchunk: Buffer,\n\t\t\tchunks: Buffer[],\n\t\t\tcurrentBytes: number,\n\t\t): { nextBytes: number; truncated: boolean } => {\n\t\t\tif (currentBytes >= MAX_GIT_CAPTURE_BYTES) {\n\t\t\t\treturn { nextBytes: currentBytes, truncated: true };\n\t\t\t}\n\t\t\tconst remaining = MAX_GIT_CAPTURE_BYTES - currentBytes;\n\t\t\tif (chunk.length <= remaining) {\n\t\t\t\tchunks.push(chunk);\n\t\t\t\treturn { nextBytes: currentBytes + chunk.length, truncated: false };\n\t\t\t}\n\t\t\tchunks.push(chunk.subarray(0, remaining));\n\t\t\treturn { nextBytes: MAX_GIT_CAPTURE_BYTES, truncated: true };\n\t\t};\n\n\t\tconst timeoutHandle = setTimeout(() => {\n\t\t\ttimedOut = true;\n\t\t\tchild.kill(\"SIGTERM\");\n\t\t}, Math.max(1000, timeoutMs));\n\n\t\tconst onAbort = () => {\n\t\t\taborted = true;\n\t\t\tchild.kill(\"SIGTERM\");\n\t\t};\n\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n\t\tconst cleanup = () => {\n\t\t\tclearTimeout(timeoutHandle);\n\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t};\n\n\t\tchild.stdout.on(\"data\", (chunk: Buffer) => {\n\t\t\tconst captured = captureChunk(chunk, stdoutChunks, stdoutBytes);\n\t\t\tstdoutBytes = captured.nextBytes;\n\t\t\tcaptureTruncated = captureTruncated || captured.truncated;\n\t\t});\n\n\t\tchild.stderr.on(\"data\", (chunk: Buffer) => {\n\t\t\tconst captured = captureChunk(chunk, stderrChunks, stderrBytes);\n\t\t\tstderrBytes = captured.nextBytes;\n\t\t\tcaptureTruncated = captureTruncated || captured.truncated;\n\t\t});\n\n\t\tchild.on(\"error\", (error) => {\n\t\t\tcleanup();\n\t\t\tsettle(() => reject(new Error(`Failed to run git: ${error.message}`)));\n\t\t});\n\n\t\tchild.on(\"close\", (code) => {\n\t\t\tcleanup();\n\t\t\tif (aborted) {\n\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (timedOut) {\n\t\t\t\tsettle(() => reject(new Error(`Command timed out after ${Math.round(timeoutMs / 1000)}s`)));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettle(() =>\n\t\t\t\tresolve({\n\t\t\t\t\tstdout: Buffer.concat(stdoutChunks).toString(\"utf-8\"),\n\t\t\t\t\tstderr: Buffer.concat(stderrChunks).toString(\"utf-8\"),\n\t\t\t\t\texitCode: code ?? -1,\n\t\t\t\t\tcaptureTruncated,\n\t\t\t\t}),\n\t\t\t);\n\t\t});\n\t});\n}\n\nexport function resolveGitCommandOptions(options?: GitCommandOptions): {\n\thasCommand: GitCommandExists;\n\trunCommand: RunGitCommand;\n} {\n\treturn {\n\t\thasCommand: options?.commandExists ?? commandExists,\n\t\trunCommand: options?.runCommand ?? runGitCommand,\n\t};\n}\n\nexport function normalizePositiveInt(raw: number | undefined, fallback: number, field: string): number {\n\tif (raw === undefined) return fallback;\n\tconst value = Math.floor(raw);\n\tif (!Number.isFinite(value) || value <= 0) {\n\t\tthrow new Error(`${field} must be a positive number.`);\n\t}\n\treturn value;\n}\n\nexport function normalizeRefLike(raw: string | undefined, field: string): string | undefined {\n\tif (raw === undefined) return undefined;\n\tconst normalized = raw.trim();\n\tif (normalized.length === 0) {\n\t\tthrow new Error(`${field} must not be empty.`);\n\t}\n\tif (normalized.startsWith(\"-\")) {\n\t\tthrow new Error(`${field} must not start with '-'.`);\n\t}\n\treturn normalized;\n}\n\nexport function requireRefLike(raw: string | undefined, field: string): string {\n\tconst normalized = normalizeRefLike(raw, field);\n\tif (!normalized) {\n\t\tthrow new Error(`${field} is required.`);\n\t}\n\treturn normalized;\n}\n\nexport function normalizeRequiredString(raw: string | undefined, field: string): string {\n\tconst value = raw?.trim();\n\tif (!value) {\n\t\tthrow new Error(`${field} is required.`);\n\t}\n\treturn value;\n}\n\nexport function normalizeFiles(files: string[] | undefined, field: string): string[] {\n\tif (!files || files.length === 0) {\n\t\tthrow new Error(`${field} is required.`);\n\t}\n\tconst normalized = files\n\t\t.map((file) => file.trim())\n\t\t.filter((file) => file.length > 0);\n\tif (normalized.length === 0) {\n\t\tthrow new Error(`${field} must include at least one non-empty path.`);\n\t}\n\treturn normalized;\n}\n\nexport async function runGitAndFormatOutput(params: GitRunParams): Promise<GitRunSummary> {\n\tconst result = await params.runCommand(params.args, params.cwd, params.timeoutSeconds * 1000, params.signal, {\n\t\tenv: params.env,\n\t});\n\n\tif (result.exitCode !== 0) {\n\t\tconst errorText = result.stderr.trim() || result.stdout.trim() || `${params.toolName} ${params.action} failed with exit code ${result.exitCode}`;\n\t\tthrow new Error(errorText);\n\t}\n\n\tlet output = result.stdout.trimEnd();\n\tif (!output && result.stderr.trim().length > 0) {\n\t\toutput = result.stderr.trimEnd();\n\t}\n\tif (!output) {\n\t\toutput = \"No output\";\n\t}\n\n\tconst truncation = truncateHead(output);\n\tlet finalOutput = truncation.content;\n\tconst notices: string[] = [];\n\n\tif (truncation.truncated) {\n\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} output limit reached`);\n\t}\n\tif (result.captureTruncated) {\n\t\tnotices.push(`capture limit reached (${formatSize(MAX_GIT_CAPTURE_BYTES)})`);\n\t}\n\tif (notices.length > 0) {\n\t\tfinalOutput += `\\n\\n[${notices.join(\". \")} · showing up to ${DEFAULT_MAX_LINES} lines]`;\n\t}\n\n\treturn {\n\t\toutput: finalOutput,\n\t\tcaptureTruncated: result.captureTruncated,\n\t\ttruncation: truncation.truncated ? truncation : undefined,\n\t\texitCode: result.exitCode,\n\t};\n}\n"]}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { AgentTool } from "@mariozechner/pi-agent-core";
|
|
2
|
+
import { type Static } from "@sinclair/typebox";
|
|
3
|
+
import { type GitCommandOptions } from "./git-common.js";
|
|
4
|
+
import type { TruncationResult } from "./truncate.js";
|
|
5
|
+
declare const gitReadSchema: import("@sinclair/typebox").TObject<{
|
|
6
|
+
action: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"status">, import("@sinclair/typebox").TLiteral<"diff">, import("@sinclair/typebox").TLiteral<"log">, import("@sinclair/typebox").TLiteral<"blame">, import("@sinclair/typebox").TLiteral<"show">, import("@sinclair/typebox").TLiteral<"branch_list">, import("@sinclair/typebox").TLiteral<"remote_list">, import("@sinclair/typebox").TLiteral<"rev_parse">]>;
|
|
7
|
+
path: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
8
|
+
file: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
9
|
+
base: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
10
|
+
head: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
11
|
+
staged: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
12
|
+
context: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
13
|
+
porcelain: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
14
|
+
untracked: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
15
|
+
limit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
16
|
+
since: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
17
|
+
ref: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
18
|
+
line_start: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
19
|
+
line_end: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
20
|
+
all: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
21
|
+
verbose: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
22
|
+
target: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
23
|
+
short: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
24
|
+
timeout: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
25
|
+
}>;
|
|
26
|
+
export type GitReadToolInput = Static<typeof gitReadSchema>;
|
|
27
|
+
type GitReadAction = GitReadToolInput["action"];
|
|
28
|
+
export interface GitReadToolDetails {
|
|
29
|
+
action: GitReadAction;
|
|
30
|
+
command: string;
|
|
31
|
+
args: string[];
|
|
32
|
+
cwd: string;
|
|
33
|
+
exitCode: number;
|
|
34
|
+
captureTruncated?: boolean;
|
|
35
|
+
truncation?: TruncationResult;
|
|
36
|
+
}
|
|
37
|
+
export interface GitReadToolOptions extends GitCommandOptions {
|
|
38
|
+
}
|
|
39
|
+
export declare function createGitReadTool(cwd: string, options?: GitReadToolOptions): AgentTool<typeof gitReadSchema>;
|
|
40
|
+
export declare const gitReadTool: AgentTool<import("@sinclair/typebox").TObject<{
|
|
41
|
+
action: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"status">, import("@sinclair/typebox").TLiteral<"diff">, import("@sinclair/typebox").TLiteral<"log">, import("@sinclair/typebox").TLiteral<"blame">, import("@sinclair/typebox").TLiteral<"show">, import("@sinclair/typebox").TLiteral<"branch_list">, import("@sinclair/typebox").TLiteral<"remote_list">, import("@sinclair/typebox").TLiteral<"rev_parse">]>;
|
|
42
|
+
path: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
43
|
+
file: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
44
|
+
base: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
45
|
+
head: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
46
|
+
staged: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
47
|
+
context: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
48
|
+
porcelain: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
49
|
+
untracked: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
50
|
+
limit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
51
|
+
since: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
52
|
+
ref: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
53
|
+
line_start: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
54
|
+
line_end: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
55
|
+
all: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
56
|
+
verbose: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
57
|
+
target: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
58
|
+
short: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
59
|
+
timeout: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
60
|
+
}>, any>;
|
|
61
|
+
export {};
|
|
62
|
+
//# sourceMappingURL=git-read.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-read.d.ts","sourceRoot":"","sources":["../../../src/core/tools/git-read.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,KAAK,MAAM,EAAQ,MAAM,mBAAmB,CAAC;AAEtD,OAAO,EAON,KAAK,iBAAiB,EACtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,QAAA,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;EAwCjB,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,aAAa,CAAC,CAAC;AAK5D,KAAK,aAAa,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;AAEhD,MAAM,WAAW,kBAAkB;IAClC,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC9B;AAED,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;CAAG;AAiJhE,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC,OAAO,aAAa,CAAC,CA2C5G;AAED,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;QAAmC,CAAC"}
|