@travisennis/acai 0.0.12 → 0.0.14
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/README.md +5 -2
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +91 -5
- package/dist/commands/history/types.d.ts +3 -2
- package/dist/commands/history/types.d.ts.map +1 -1
- package/dist/commands/init-project/utils.d.ts +0 -1
- package/dist/commands/init-project/utils.d.ts.map +1 -1
- package/dist/commands/init-project/utils.js +1 -1
- package/dist/commands/manager.d.ts.map +1 -1
- package/dist/commands/manager.js +0 -18
- package/dist/commands/share/html-renderer.d.ts.map +1 -1
- package/dist/commands/share/html-renderer.js +54 -48
- package/dist/commands/tools/index.js +39 -38
- package/dist/config/index.d.ts +0 -2
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +3 -7
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +94 -76
- package/dist/models/manager.d.ts +1 -10
- package/dist/models/manager.d.ts.map +1 -1
- package/dist/models/manager.js +2 -2
- package/dist/models/opencode-go-provider.d.ts +6 -4
- package/dist/models/opencode-go-provider.d.ts.map +1 -1
- package/dist/models/opencode-go-provider.js +55 -35
- package/dist/models/providers.d.ts +1 -1
- package/dist/models/providers.d.ts.map +1 -1
- package/dist/prompts/system-prompt.d.ts +0 -2
- package/dist/prompts/system-prompt.d.ts.map +1 -1
- package/dist/prompts/system-prompt.js +6 -10
- package/dist/repl/index.d.ts +27 -11
- package/dist/repl/index.d.ts.map +1 -1
- package/dist/repl/index.js +238 -254
- package/dist/sessions/manager.d.ts +41 -0
- package/dist/sessions/manager.d.ts.map +1 -1
- package/dist/sessions/manager.js +53 -0
- package/dist/sessions/summary.d.ts.map +1 -1
- package/dist/sessions/summary.js +18 -0
- package/dist/skills/index.d.ts +12 -2
- package/dist/skills/index.d.ts.map +1 -1
- package/dist/skills/index.js +123 -73
- package/dist/terminal/control.d.ts +1 -21
- package/dist/terminal/control.d.ts.map +1 -1
- package/dist/terminal/control.js +1 -32
- package/dist/terminal/formatting.d.ts +0 -33
- package/dist/terminal/formatting.d.ts.map +1 -1
- package/dist/terminal/formatting.js +0 -91
- package/dist/terminal/highlight/theme.d.ts +0 -37
- package/dist/terminal/highlight/theme.d.ts.map +1 -1
- package/dist/terminal/highlight/theme.js +1 -79
- package/dist/terminal/keys.d.ts +0 -97
- package/dist/terminal/keys.d.ts.map +1 -1
- package/dist/terminal/keys.js +0 -194
- package/dist/terminal/select-prompt.d.ts.map +1 -1
- package/dist/terminal/select-prompt.js +65 -51
- package/dist/terminal/style.d.ts +1 -1
- package/dist/terminal/style.d.ts.map +1 -1
- package/dist/terminal/supports-color.d.ts.map +1 -1
- package/dist/terminal/supports-color.js +38 -20
- package/dist/terminal/supports-hyperlinks.d.ts +3 -0
- package/dist/terminal/supports-hyperlinks.d.ts.map +1 -1
- package/dist/terminal/supports-hyperlinks.js +72 -31
- package/dist/terminal/table/layout-manager.d.ts +0 -20
- package/dist/terminal/table/layout-manager.d.ts.map +1 -1
- package/dist/terminal/table/layout-manager.js +68 -44
- package/dist/terminal/table/utils.d.ts +0 -1
- package/dist/terminal/table/utils.d.ts.map +1 -1
- package/dist/terminal/table/utils.js +2 -4
- package/dist/tools/apply-patch.d.ts +5 -3
- package/dist/tools/apply-patch.d.ts.map +1 -1
- package/dist/tools/apply-patch.js +154 -123
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +11 -8
- package/dist/tools/dynamic-tool-loader.d.ts +6 -1
- package/dist/tools/dynamic-tool-loader.d.ts.map +1 -1
- package/dist/tools/dynamic-tool-loader.js +154 -135
- package/dist/tools/index.d.ts +3 -133
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +0 -20
- package/dist/tools/read-file.d.ts.map +1 -1
- package/dist/tools/read-file.js +32 -13
- package/dist/tools/skill.d.ts.map +1 -1
- package/dist/tools/skill.js +20 -13
- package/dist/tools/web-fetch.d.ts +2 -6
- package/dist/tools/web-fetch.d.ts.map +1 -1
- package/dist/tools/web-fetch.js +59 -36
- package/dist/tools/web-search.d.ts +0 -4
- package/dist/tools/web-search.d.ts.map +1 -1
- package/dist/tools/web-search.js +40 -32
- package/dist/tui/autocomplete/utils.d.ts +0 -15
- package/dist/tui/autocomplete/utils.d.ts.map +1 -1
- package/dist/tui/autocomplete/utils.js +0 -85
- package/dist/tui/autocomplete.d.ts +1 -1
- package/dist/tui/autocomplete.d.ts.map +1 -1
- package/dist/tui/autocomplete.js +1 -1
- package/dist/tui/components/editor.d.ts +12 -0
- package/dist/tui/components/editor.d.ts.map +1 -1
- package/dist/tui/components/editor.js +181 -195
- package/dist/tui/components/input.d.ts +4 -0
- package/dist/tui/components/input.d.ts.map +1 -1
- package/dist/tui/components/input.js +33 -31
- package/dist/tui/components/markdown.d.ts +30 -0
- package/dist/tui/components/markdown.d.ts.map +1 -1
- package/dist/tui/components/markdown.js +274 -242
- package/dist/tui/components/modal.d.ts.map +1 -1
- package/dist/tui/components/modal.js +11 -11
- package/dist/tui/components/select-list.d.ts +5 -0
- package/dist/tui/components/select-list.d.ts.map +1 -1
- package/dist/tui/components/select-list.js +69 -98
- package/dist/tui/components/table.d.ts +6 -0
- package/dist/tui/components/table.d.ts.map +1 -1
- package/dist/tui/components/table.js +61 -52
- package/dist/tui/index.d.ts +1 -8
- package/dist/tui/index.d.ts.map +1 -1
- package/dist/tui/index.js +0 -8
- package/dist/tui/tui.d.ts +9 -0
- package/dist/tui/tui.d.ts.map +1 -1
- package/dist/tui/tui.js +78 -48
- package/dist/tui/utils.d.ts +7 -0
- package/dist/tui/utils.d.ts.map +1 -1
- package/dist/tui/utils.js +117 -53
- package/dist/utils/bash.d.ts.map +1 -1
- package/dist/utils/bash.js +156 -104
- package/dist/utils/command-protection.d.ts +3 -6
- package/dist/utils/command-protection.d.ts.map +1 -1
- package/dist/utils/command-protection.js +213 -100
- package/dist/utils/filesystem/operations.d.ts +0 -15
- package/dist/utils/filesystem/operations.d.ts.map +1 -1
- package/dist/utils/filesystem/operations.js +1 -38
- package/dist/utils/filesystem/security.d.ts.map +1 -1
- package/dist/utils/filesystem/security.js +22 -15
- package/dist/utils/filetype-detection.d.ts +0 -1
- package/dist/utils/filetype-detection.d.ts.map +1 -1
- package/dist/utils/filetype-detection.js +0 -12
- package/dist/utils/formatting.d.ts +0 -30
- package/dist/utils/formatting.d.ts.map +1 -1
- package/dist/utils/formatting.js +0 -44
- package/dist/utils/git.d.ts +4 -6
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +36 -46
- package/dist/utils/ignore.d.ts +1 -1
- package/dist/utils/ignore.d.ts.map +1 -1
- package/dist/utils/ignore.js +1 -1
- package/dist/utils/process.d.ts.map +1 -1
- package/dist/utils/process.js +77 -79
- package/dist/utils/yaml.d.ts +0 -1
- package/dist/utils/yaml.d.ts.map +1 -1
- package/dist/utils/yaml.js +80 -89
- package/dist/utils/zod.d.ts +0 -3
- package/dist/utils/zod.d.ts.map +1 -1
- package/dist/utils/zod.js +0 -7
- package/package.json +25 -24
- package/dist/agent/sub-agent.d.ts +0 -23
- package/dist/agent/sub-agent.d.ts.map +0 -1
- package/dist/agent/sub-agent.js +0 -109
- package/dist/commands/add-directory/index.d.ts +0 -3
- package/dist/commands/add-directory/index.d.ts.map +0 -1
- package/dist/commands/add-directory/index.js +0 -50
- package/dist/commands/add-directory/utils.d.ts +0 -3
- package/dist/commands/add-directory/utils.d.ts.map +0 -1
- package/dist/commands/add-directory/utils.js +0 -15
- package/dist/commands/clear/index.d.ts +0 -3
- package/dist/commands/clear/index.d.ts.map +0 -1
- package/dist/commands/clear/index.js +0 -13
- package/dist/commands/generate-rules/index.d.ts +0 -3
- package/dist/commands/generate-rules/index.d.ts.map +0 -1
- package/dist/commands/generate-rules/index.js +0 -206
- package/dist/commands/generate-rules/service.d.ts +0 -22
- package/dist/commands/generate-rules/service.d.ts.map +0 -1
- package/dist/commands/generate-rules/service.js +0 -103
- package/dist/commands/generate-rules/utils.d.ts +0 -5
- package/dist/commands/generate-rules/utils.d.ts.map +0 -1
- package/dist/commands/generate-rules/utils.js +0 -25
- package/dist/commands/handoff/index.d.ts +0 -3
- package/dist/commands/handoff/index.d.ts.map +0 -1
- package/dist/commands/handoff/index.js +0 -97
- package/dist/commands/handoff/utils.d.ts +0 -4
- package/dist/commands/handoff/utils.d.ts.map +0 -1
- package/dist/commands/handoff/utils.js +0 -123
- package/dist/commands/list-directories/index.d.ts +0 -3
- package/dist/commands/list-directories/index.d.ts.map +0 -1
- package/dist/commands/list-directories/index.js +0 -35
- package/dist/commands/pickup/index.d.ts +0 -3
- package/dist/commands/pickup/index.d.ts.map +0 -1
- package/dist/commands/pickup/index.js +0 -141
- package/dist/commands/pickup/types.d.ts +0 -6
- package/dist/commands/pickup/types.d.ts.map +0 -1
- package/dist/commands/pickup/types.js +0 -1
- package/dist/commands/pickup/utils.d.ts +0 -7
- package/dist/commands/pickup/utils.d.ts.map +0 -1
- package/dist/commands/pickup/utils.js +0 -56
- package/dist/commands/remove-directory/index.d.ts +0 -3
- package/dist/commands/remove-directory/index.d.ts.map +0 -1
- package/dist/commands/remove-directory/index.js +0 -55
- package/dist/commands/review/index.d.ts +0 -3
- package/dist/commands/review/index.d.ts.map +0 -1
- package/dist/commands/review/index.js +0 -12
- package/dist/commands/review/review-panel.d.ts +0 -3
- package/dist/commands/review/review-panel.d.ts.map +0 -1
- package/dist/commands/review/review-panel.js +0 -186
- package/dist/commands/review/utils.d.ts +0 -18
- package/dist/commands/review/utils.d.ts.map +0 -1
- package/dist/commands/review/utils.js +0 -146
- package/dist/commands/shell/index.d.ts +0 -3
- package/dist/commands/shell/index.d.ts.map +0 -1
- package/dist/commands/shell/index.js +0 -96
- package/dist/subagents/index.d.ts +0 -16
- package/dist/subagents/index.d.ts.map +0 -1
- package/dist/subagents/index.js +0 -231
- package/dist/terminal/index.d.ts +0 -9
- package/dist/terminal/index.d.ts.map +0 -1
- package/dist/terminal/index.js +0 -8
- package/dist/tools/agent.d.ts +0 -27
- package/dist/tools/agent.d.ts.map +0 -1
- package/dist/tools/agent.js +0 -81
- package/dist/tools/directory-tree.d.ts +0 -28
- package/dist/tools/directory-tree.d.ts.map +0 -1
- package/dist/tools/directory-tree.js +0 -154
- package/dist/tools/glob.d.ts +0 -35
- package/dist/tools/glob.d.ts.map +0 -1
- package/dist/tools/glob.js +0 -167
- package/dist/tools/grep.d.ts +0 -100
- package/dist/tools/grep.d.ts.map +0 -1
- package/dist/tools/grep.js +0 -608
- package/dist/tools/ls.d.ts +0 -26
- package/dist/tools/ls.d.ts.map +0 -1
- package/dist/tools/ls.js +0 -83
- package/dist/tui/components/header.d.ts +0 -21
- package/dist/tui/components/header.d.ts.map +0 -1
- package/dist/tui/components/header.js +0 -63
- package/dist/utils/bash/parse.d.ts +0 -19
- package/dist/utils/bash/parse.d.ts.map +0 -1
- package/dist/utils/bash/parse.js +0 -223
- package/dist/utils/bash/quote.d.ts +0 -6
- package/dist/utils/bash/quote.d.ts.map +0 -1
- package/dist/utils/bash/quote.js +0 -23
- package/dist/utils/generators.d.ts +0 -3
- package/dist/utils/generators.d.ts.map +0 -1
- package/dist/utils/generators.js +0 -25
- package/dist/utils/glob.d.ts +0 -52
- package/dist/utils/glob.d.ts.map +0 -1
- package/dist/utils/glob.js +0 -376
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Command Protection Module
|
|
3
3
|
* Detects and blocks destructive commands that could cause data loss
|
|
4
4
|
*/
|
|
5
|
+
import path from "node:path";
|
|
5
6
|
/**
|
|
6
7
|
* Check if a git subcommand appears as an actual command (not inside quoted strings).
|
|
7
8
|
* This helps avoid false positives when destructive command text appears in
|
|
@@ -91,6 +92,34 @@ export function detectDestructiveCommand(command) {
|
|
|
91
92
|
}
|
|
92
93
|
return { blocked: false };
|
|
93
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Check if a git restore command will discard uncommitted changes
|
|
97
|
+
* (restore without --staged and not creating a branch with -b)
|
|
98
|
+
*/
|
|
99
|
+
function isDestructiveGitRestore(lowerCommand) {
|
|
100
|
+
if (!lowerCommand.startsWith("git restore"))
|
|
101
|
+
return false;
|
|
102
|
+
if (lowerCommand.includes(" --staged"))
|
|
103
|
+
return false;
|
|
104
|
+
const afterRestore = lowerCommand.substring("git restore".length).trim();
|
|
105
|
+
return !!afterRestore && !afterRestore.startsWith("-b");
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Check if a git branch command uses -D (force delete without merge check)
|
|
109
|
+
*/
|
|
110
|
+
function isDestructiveGitBranchD(command, lowerCommand) {
|
|
111
|
+
const branchMatch = lowerCommand.match(/git\s+branch\s+-([a-z])/);
|
|
112
|
+
if (!branchMatch)
|
|
113
|
+
return false;
|
|
114
|
+
// Check if the flag in the original command is uppercase
|
|
115
|
+
const flagInOriginal = command.match(/git\s+branch\s+-([A-Za-z])/i);
|
|
116
|
+
if (!flagInOriginal)
|
|
117
|
+
return false;
|
|
118
|
+
if (flagInOriginal[1] !== flagInOriginal[1].toUpperCase())
|
|
119
|
+
return false;
|
|
120
|
+
// Verify this is an actual git branch command, not text inside quotes
|
|
121
|
+
return isActualGitCommand(command, "branch");
|
|
122
|
+
}
|
|
94
123
|
/**
|
|
95
124
|
* Detect destructive git commands
|
|
96
125
|
*/
|
|
@@ -116,18 +145,13 @@ function detectDestructiveGitCommands(command) {
|
|
|
116
145
|
};
|
|
117
146
|
}
|
|
118
147
|
// Block git restore without --staged (discards uncommitted changes)
|
|
119
|
-
if (lowerCommand
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
reason: "git restore <file> (without --staged) discards uncommitted changes",
|
|
127
|
-
command,
|
|
128
|
-
tip: "Use 'git restore --staged <file>' to only unstage, or 'git stash' to save changes.",
|
|
129
|
-
};
|
|
130
|
-
}
|
|
148
|
+
if (isDestructiveGitRestore(lowerCommand)) {
|
|
149
|
+
return {
|
|
150
|
+
blocked: true,
|
|
151
|
+
reason: "git restore <file> (without --staged) discards uncommitted changes",
|
|
152
|
+
command,
|
|
153
|
+
tip: "Use 'git restore --staged <file>' to only unstage, or 'git stash' to save changes.",
|
|
154
|
+
};
|
|
131
155
|
}
|
|
132
156
|
// Block git clean -f (force deletes untracked files)
|
|
133
157
|
if (lowerCommand.includes("git clean -f") ||
|
|
@@ -151,27 +175,13 @@ function detectDestructiveGitCommands(command) {
|
|
|
151
175
|
};
|
|
152
176
|
}
|
|
153
177
|
// Block git branch -D (force delete without merge check)
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
if (flagInOriginal &&
|
|
162
|
-
flagInOriginal[1] === flagInOriginal[1].toUpperCase()) {
|
|
163
|
-
// Verify this is an actual git branch command, not text inside quotes
|
|
164
|
-
// Check if git branch appears at start or after command separators
|
|
165
|
-
const isActualCommand = isActualGitCommand(command, "branch");
|
|
166
|
-
if (isActualCommand) {
|
|
167
|
-
return {
|
|
168
|
-
blocked: true,
|
|
169
|
-
reason: "git branch -D force-deletes branches without checking if they're merged",
|
|
170
|
-
command,
|
|
171
|
-
tip: "Use 'git branch -d' (lowercase) to safely delete branches that are merged.",
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
}
|
|
178
|
+
if (isDestructiveGitBranchD(command, lowerCommand)) {
|
|
179
|
+
return {
|
|
180
|
+
blocked: true,
|
|
181
|
+
reason: "git branch -D force-deletes branches without checking if they're merged",
|
|
182
|
+
command,
|
|
183
|
+
tip: "Use 'git branch -d' (lowercase) to safely delete branches that are merged.",
|
|
184
|
+
};
|
|
175
185
|
}
|
|
176
186
|
// Block git stash drop and git stash clear
|
|
177
187
|
if (lowerCommand.includes("git stash drop") ||
|
|
@@ -189,49 +199,168 @@ function detectDestructiveGitCommands(command) {
|
|
|
189
199
|
* Detect dangerous rm -rf commands outside of temporary directories
|
|
190
200
|
*/
|
|
191
201
|
function detectDangerousRmRf(command) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
202
|
+
const tokens = tokenizeShellCommand(command);
|
|
203
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
204
|
+
const token = tokens[i];
|
|
205
|
+
if (!token || token.separator || token.value !== "rm")
|
|
206
|
+
continue;
|
|
207
|
+
const rmArgs = collectCommandArguments(tokens, i + 1);
|
|
208
|
+
if (!isRecursiveForceRm(rmArgs))
|
|
209
|
+
continue;
|
|
210
|
+
const paths = getRmPathArguments(rmArgs);
|
|
211
|
+
if (paths.length === 0)
|
|
212
|
+
continue;
|
|
213
|
+
if (paths.every(isTempDirectoryOnly))
|
|
214
|
+
continue;
|
|
215
|
+
return {
|
|
216
|
+
blocked: true,
|
|
217
|
+
reason: "rm -rf outside of temporary directories can cause permanent data loss",
|
|
218
|
+
command,
|
|
219
|
+
tip: "Only rm -rf is allowed for /tmp/*, /var/tmp/*, or $TMPDIR/* to clean temporary files.",
|
|
220
|
+
};
|
|
196
221
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
222
|
+
return { blocked: false };
|
|
223
|
+
}
|
|
224
|
+
function tokenizeShellCommand(command) {
|
|
225
|
+
const state = {
|
|
226
|
+
tokens: [],
|
|
227
|
+
current: "",
|
|
228
|
+
inSingleQuote: false,
|
|
229
|
+
inDoubleQuote: false,
|
|
230
|
+
escaped: false,
|
|
231
|
+
};
|
|
232
|
+
for (let i = 0; i < command.length; i++) {
|
|
233
|
+
consumeShellChar(state, command[i] ?? "");
|
|
234
|
+
}
|
|
235
|
+
pushShellToken(state);
|
|
236
|
+
return state.tokens;
|
|
237
|
+
}
|
|
238
|
+
function consumeShellChar(state, char) {
|
|
239
|
+
if (state.escaped) {
|
|
240
|
+
state.current += char;
|
|
241
|
+
state.escaped = false;
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
if (char === "\\" && !state.inSingleQuote) {
|
|
245
|
+
state.escaped = true;
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
if (char === "'" && !state.inDoubleQuote) {
|
|
249
|
+
state.inSingleQuote = !state.inSingleQuote;
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (char === '"' && !state.inSingleQuote) {
|
|
253
|
+
state.inDoubleQuote = !state.inDoubleQuote;
|
|
254
|
+
return;
|
|
203
255
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
const isTempDirectoryOnly = tempDirs.some((tempDir) => {
|
|
209
|
-
// Check if path starts with temp directory (e.g., /tmp/foo, /tmp/*)
|
|
210
|
-
if (afterRmRf === tempDir || afterRmRf.startsWith(`${tempDir}/`)) {
|
|
211
|
-
return true;
|
|
256
|
+
if (isTokenBoundary(state, char)) {
|
|
257
|
+
pushShellToken(state);
|
|
258
|
+
if (char === "\n" || isShellSeparator(char)) {
|
|
259
|
+
state.tokens.push({ value: char, separator: true });
|
|
212
260
|
}
|
|
213
|
-
return
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
state.current += char;
|
|
264
|
+
}
|
|
265
|
+
function isTokenBoundary(state, char) {
|
|
266
|
+
return (!state.inSingleQuote &&
|
|
267
|
+
!state.inDoubleQuote &&
|
|
268
|
+
(/\s/.test(char) || isShellSeparator(char)));
|
|
269
|
+
}
|
|
270
|
+
function pushShellToken(state) {
|
|
271
|
+
if (!state.current)
|
|
272
|
+
return;
|
|
273
|
+
state.tokens.push({ value: state.current, separator: false });
|
|
274
|
+
state.current = "";
|
|
275
|
+
}
|
|
276
|
+
function isShellSeparator(char) {
|
|
277
|
+
return char === ";" || char === "|" || char === "&";
|
|
278
|
+
}
|
|
279
|
+
function collectCommandArguments(tokens, startIndex) {
|
|
280
|
+
const args = [];
|
|
281
|
+
for (let i = startIndex; i < tokens.length; i++) {
|
|
282
|
+
const token = tokens[i];
|
|
283
|
+
if (!token || token.separator)
|
|
284
|
+
break;
|
|
285
|
+
args.push(token.value);
|
|
286
|
+
}
|
|
287
|
+
return args;
|
|
288
|
+
}
|
|
289
|
+
function isRecursiveForceRm(args) {
|
|
290
|
+
const flags = { recursive: false, force: false };
|
|
291
|
+
for (const arg of args) {
|
|
292
|
+
if (arg === "--")
|
|
293
|
+
break;
|
|
294
|
+
updateRmFlagState(flags, arg);
|
|
295
|
+
}
|
|
296
|
+
return flags.recursive && flags.force;
|
|
297
|
+
}
|
|
298
|
+
function updateRmFlagState(flags, arg) {
|
|
299
|
+
if (arg === "--recursive") {
|
|
300
|
+
flags.recursive = true;
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
if (arg === "--force") {
|
|
304
|
+
flags.force = true;
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
if (!/^-[^-]+$/.test(arg))
|
|
308
|
+
return;
|
|
309
|
+
if (arg.includes("r") || arg.includes("R"))
|
|
310
|
+
flags.recursive = true;
|
|
311
|
+
if (arg.includes("f"))
|
|
312
|
+
flags.force = true;
|
|
313
|
+
}
|
|
314
|
+
function getRmPathArguments(args) {
|
|
315
|
+
const paths = [];
|
|
316
|
+
let parsingOptions = true;
|
|
317
|
+
for (const arg of args) {
|
|
318
|
+
if (parsingOptions && arg === "--") {
|
|
319
|
+
parsingOptions = false;
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
if (parsingOptions && isRmOption(arg))
|
|
323
|
+
continue;
|
|
324
|
+
paths.push(arg);
|
|
325
|
+
}
|
|
326
|
+
return paths;
|
|
327
|
+
}
|
|
328
|
+
function isRmOption(arg) {
|
|
329
|
+
return arg.startsWith("-") && arg !== "-";
|
|
330
|
+
}
|
|
331
|
+
function isTempDirectoryOnly(inputPath) {
|
|
217
332
|
const tmpDirVar = "$" + "TMPDIR";
|
|
218
333
|
const tmpDirVarBraces = "$" + "{TMPDIR}";
|
|
219
|
-
if (
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
afterRmRf.startsWith(`${tmpDirVarBraces}/`)) {
|
|
223
|
-
return { blocked: false };
|
|
334
|
+
if (isTempVariablePath(inputPath, tmpDirVar) ||
|
|
335
|
+
isTempVariablePath(inputPath, tmpDirVarBraces)) {
|
|
336
|
+
return true;
|
|
224
337
|
}
|
|
225
|
-
if (
|
|
226
|
-
return
|
|
338
|
+
if (!inputPath.startsWith("/"))
|
|
339
|
+
return false;
|
|
340
|
+
const normalizedPath = normalizeAbsolutePath(inputPath);
|
|
341
|
+
const tempDirs = ["/tmp", "/var/tmp", process.env["TMPDIR"] || "/tmp"].map(normalizeAbsolutePath);
|
|
342
|
+
return tempDirs.some((tempDir) => normalizedPath === tempDir || normalizedPath.startsWith(`${tempDir}/`));
|
|
343
|
+
}
|
|
344
|
+
function isTempVariablePath(inputPath, variable) {
|
|
345
|
+
if (inputPath !== variable && !inputPath.startsWith(`${variable}/`)) {
|
|
346
|
+
return false;
|
|
227
347
|
}
|
|
228
|
-
|
|
229
|
-
return
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
348
|
+
const suffix = inputPath.slice(variable.length);
|
|
349
|
+
return !suffix.split("/").includes("..");
|
|
350
|
+
}
|
|
351
|
+
function normalizeAbsolutePath(inputPath) {
|
|
352
|
+
return path.posix.normalize(inputPath.replace(/\/+$/, "") || "/");
|
|
353
|
+
}
|
|
354
|
+
function detectDangerousRmRfInText(content) {
|
|
355
|
+
const rmCommandPattern = /\brm\b[^\n;&|)]*/gi;
|
|
356
|
+
let match = rmCommandPattern.exec(content);
|
|
357
|
+
while (match !== null) {
|
|
358
|
+
const rmResult = detectDangerousRmRf(match[0]);
|
|
359
|
+
if (rmResult.blocked)
|
|
360
|
+
return rmResult;
|
|
361
|
+
match = rmCommandPattern.exec(content);
|
|
362
|
+
}
|
|
363
|
+
return { blocked: false };
|
|
235
364
|
}
|
|
236
365
|
/**
|
|
237
366
|
* Detect dangerous patterns in inline scripts (-c flags)
|
|
@@ -259,9 +388,6 @@ function detectDangerousInlineScripts(command) {
|
|
|
259
388
|
/git\s+push\s+(-f|--force)/i,
|
|
260
389
|
/git\s+branch\s+-[A-Z]/i,
|
|
261
390
|
/git\s+stash\s+(drop|clear)/i,
|
|
262
|
-
/rm\s+-rf\s+\/home/i,
|
|
263
|
-
/rm\s+-rf\s+\/usr/i,
|
|
264
|
-
/rm\s+-rf\s+~/i,
|
|
265
391
|
];
|
|
266
392
|
// Check if any destructive pattern is present in the command
|
|
267
393
|
for (const destructivePattern of destructivePatterns) {
|
|
@@ -274,6 +400,15 @@ function detectDangerousInlineScripts(command) {
|
|
|
274
400
|
};
|
|
275
401
|
}
|
|
276
402
|
}
|
|
403
|
+
const rmResult = detectDangerousRmRfInText(command);
|
|
404
|
+
if (rmResult.blocked) {
|
|
405
|
+
return {
|
|
406
|
+
blocked: true,
|
|
407
|
+
reason: `Inline ${language} script contains destructive operation`,
|
|
408
|
+
command,
|
|
409
|
+
tip: "Review the script content for destructive commands.",
|
|
410
|
+
};
|
|
411
|
+
}
|
|
277
412
|
}
|
|
278
413
|
}
|
|
279
414
|
return { blocked: false };
|
|
@@ -362,34 +497,12 @@ function detectDangerousScriptContent(content) {
|
|
|
362
497
|
};
|
|
363
498
|
}
|
|
364
499
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
/\brm\s+-rf\s+\/var\s*$/i, // Block /var alone but allow /var/tmp
|
|
372
|
-
/\brm\s+-rf\s+~(?!\/)/i, // rm -rf ~ but allow ~/tmp
|
|
373
|
-
];
|
|
374
|
-
for (const pattern of dangerousRmPatterns) {
|
|
375
|
-
if (pattern.test(content)) {
|
|
376
|
-
return {
|
|
377
|
-
blocked: true,
|
|
378
|
-
tip: "The script contains a dangerous rm -rf command.",
|
|
379
|
-
};
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
// Check for format string attacks and other dangerous patterns
|
|
383
|
-
const dangerousPatterns = [
|
|
384
|
-
/\brm\s+-rf\s+\$\w+/i, // rm -rf $VAR (variable expansion could be dangerous)
|
|
385
|
-
];
|
|
386
|
-
for (const pattern of dangerousPatterns) {
|
|
387
|
-
if (pattern.test(content)) {
|
|
388
|
-
return {
|
|
389
|
-
blocked: true,
|
|
390
|
-
tip: "The script contains a potentially dangerous rm command with variable expansion.",
|
|
391
|
-
};
|
|
392
|
-
}
|
|
500
|
+
const rmResult = detectDangerousRmRfInText(content);
|
|
501
|
+
if (rmResult.blocked) {
|
|
502
|
+
return {
|
|
503
|
+
blocked: true,
|
|
504
|
+
tip: "The script contains a dangerous rm -rf command.",
|
|
505
|
+
};
|
|
393
506
|
}
|
|
394
507
|
return { blocked: false };
|
|
395
508
|
}
|
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
export declare function toPath(urlOrPath: URL | string): string;
|
|
2
|
-
/**
|
|
3
|
-
* Converts Windows backslashes to POSIX forward slashes.
|
|
4
|
-
* Preserves UNC paths and extended-length paths.
|
|
5
|
-
* @param inputPath - Path to convert
|
|
6
|
-
* @returns Path with forward slashes
|
|
7
|
-
*/
|
|
8
|
-
export declare function slash(inputPath: string): string;
|
|
9
|
-
/**
|
|
10
|
-
* Checks if a path exists and is a directory.
|
|
11
|
-
* @param filePath - Path to check (URL or string)
|
|
12
|
-
* @returns Promise resolving to true if path is a directory
|
|
13
|
-
* @throws TypeError if input is invalid
|
|
14
|
-
*/
|
|
15
|
-
export declare function isDirectory(filePath: URL | string): Promise<boolean>;
|
|
16
1
|
/**
|
|
17
2
|
* Safely clears all contents of a directory.
|
|
18
3
|
* @param directoryPath - Path to the directory to clear (URL or string)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operations.d.ts","sourceRoot":"","sources":["../../../source/utils/filesystem/operations.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"operations.d.ts","sourceRoot":"","sources":["../../../source/utils/filesystem/operations.ts"],"names":[],"mappings":"AAQA;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,aAAa,EAAE,GAAG,GAAG,MAAM,GAC1B,OAAO,CAAC,IAAI,CAAC,CAuGf"}
|
|
@@ -1,46 +1,9 @@
|
|
|
1
1
|
import * as fsPromises from "node:fs/promises";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
-
|
|
4
|
+
function toPath(urlOrPath) {
|
|
5
5
|
return urlOrPath instanceof URL ? fileURLToPath(urlOrPath) : urlOrPath;
|
|
6
6
|
}
|
|
7
|
-
/**
|
|
8
|
-
* Converts Windows backslashes to POSIX forward slashes.
|
|
9
|
-
* Preserves UNC paths and extended-length paths.
|
|
10
|
-
* @param inputPath - Path to convert
|
|
11
|
-
* @returns Path with forward slashes
|
|
12
|
-
*/
|
|
13
|
-
export function slash(inputPath) {
|
|
14
|
-
const isExtendedLengthPath = inputPath.startsWith("\\\\?\\");
|
|
15
|
-
const isUncPath = inputPath.startsWith("\\\\");
|
|
16
|
-
if (isExtendedLengthPath || isUncPath) {
|
|
17
|
-
return inputPath;
|
|
18
|
-
}
|
|
19
|
-
return inputPath.replace(/\\/g, "/");
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Checks if a path exists and is a directory.
|
|
23
|
-
* @param filePath - Path to check (URL or string)
|
|
24
|
-
* @returns Promise resolving to true if path is a directory
|
|
25
|
-
* @throws TypeError if input is invalid
|
|
26
|
-
*/
|
|
27
|
-
export async function isDirectory(filePath) {
|
|
28
|
-
const resolvedPath = path.resolve(toPath(filePath));
|
|
29
|
-
if (typeof resolvedPath !== "string" || !resolvedPath.trim()) {
|
|
30
|
-
throw new TypeError(`Expected a non-empty string or URL, got ${typeof filePath}`);
|
|
31
|
-
}
|
|
32
|
-
try {
|
|
33
|
-
const stats = await fsPromises.stat(resolvedPath);
|
|
34
|
-
return stats.isDirectory();
|
|
35
|
-
}
|
|
36
|
-
catch (error) {
|
|
37
|
-
const err = error;
|
|
38
|
-
if (err.code === "ENOENT") {
|
|
39
|
-
return false;
|
|
40
|
-
}
|
|
41
|
-
throw error;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
7
|
/**
|
|
45
8
|
* Safely clears all contents of a directory.
|
|
46
9
|
* @param directoryPath - Path to the directory to clear (URL or string)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../../source/utils/filesystem/security.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAsCpD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAK3E;AAoCD,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,EAAE,GACpB,OAAO,
|
|
1
|
+
{"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../../source/utils/filesystem/security.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAsCpD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAK3E;AAoCD,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,EAAE,GACpB,OAAO,CAKT;AA2DD,wBAAsB,YAAY,CAChC,aAAa,EAAE,MAAM,EACrB,gBAAgB,EAAE,MAAM,GAAG,MAAM,EAAE,EACnC,OAAO,GAAE;IAAE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,WAAW,CAAA;CAAO,GACtE,OAAO,CAAC,MAAM,CAAC,CAuFjB;AA8BD,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,GACjB,IAAI,CAIN"}
|
|
@@ -75,7 +75,10 @@ function isPathWithinBaseDir(requestedPath, baseDir) {
|
|
|
75
75
|
}
|
|
76
76
|
// Check if path is within any of the allowed directories
|
|
77
77
|
export function isPathWithinAllowedDirs(requestedPath, allowedDirs) {
|
|
78
|
-
return allowedDirs.some((allowedDir) =>
|
|
78
|
+
return allowedDirs.some((allowedDir) => {
|
|
79
|
+
const expandedDir = expandHome(allowedDir);
|
|
80
|
+
return isPathWithinBaseDir(requestedPath, expandedDir);
|
|
81
|
+
});
|
|
79
82
|
}
|
|
80
83
|
async function resolveValidAncestor(startDir, isWithinAllowed) {
|
|
81
84
|
let current = startDir;
|
|
@@ -104,6 +107,21 @@ async function resolveValidAncestor(startDir, isWithinAllowed) {
|
|
|
104
107
|
}
|
|
105
108
|
}
|
|
106
109
|
}
|
|
110
|
+
async function ensurePathExists(validatedPath, requestedPath, abortSignal) {
|
|
111
|
+
if (abortSignal?.aborted) {
|
|
112
|
+
throw new Error("Path validation aborted during existence check");
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
await fs.stat(validatedPath);
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
const error = err;
|
|
119
|
+
if (error.code === "ENOENT") {
|
|
120
|
+
throw new Error(`The specified path does not exist: ${requestedPath} (${validatedPath})`);
|
|
121
|
+
}
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
107
125
|
// Security utilities
|
|
108
126
|
export async function validatePath(requestedPath, allowedDirectory, options = {}) {
|
|
109
127
|
const { requireExistence = true, abortSignal } = options;
|
|
@@ -121,7 +139,8 @@ export async function validatePath(requestedPath, allowedDirectory, options = {}
|
|
|
121
139
|
: [allowedDirectory];
|
|
122
140
|
// Resolve and normalize all allowed directories
|
|
123
141
|
const normalizedAllowedDirs = await Promise.all(allowedDirectories.map(async (dir) => {
|
|
124
|
-
|
|
142
|
+
const expandedDir = expandHome(dir);
|
|
143
|
+
let normalizedDir = normalizePath(path.resolve(expandedDir));
|
|
125
144
|
// Try to resolve real path for allowedDirectory when it exists to handle symlinked roots
|
|
126
145
|
try {
|
|
127
146
|
const stats = await fs.stat(normalizedDir);
|
|
@@ -171,19 +190,7 @@ export async function validatePath(requestedPath, allowedDirectory, options = {}
|
|
|
171
190
|
}
|
|
172
191
|
// Now, if requireExistence, check if the path exists
|
|
173
192
|
if (requireExistence) {
|
|
174
|
-
|
|
175
|
-
throw new Error("Path validation aborted during existence check");
|
|
176
|
-
}
|
|
177
|
-
try {
|
|
178
|
-
await fs.stat(validatedPath);
|
|
179
|
-
}
|
|
180
|
-
catch (err) {
|
|
181
|
-
const error = err;
|
|
182
|
-
if (error.code === "ENOENT") {
|
|
183
|
-
throw new Error(`The specified path does not exist: ${requestedPath} (${validatedPath})`);
|
|
184
|
-
}
|
|
185
|
-
throw error;
|
|
186
|
-
}
|
|
193
|
+
await ensurePathExists(validatedPath, requestedPath, abortSignal);
|
|
187
194
|
}
|
|
188
195
|
return validatedPath;
|
|
189
196
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filetype-detection.d.ts","sourceRoot":"","sources":["../../source/utils/filetype-detection.ts"],"names":[],"mappings":"AA+FA,wBAAgB,
|
|
1
|
+
{"version":3,"file":"filetype-detection.d.ts","sourceRoot":"","sources":["../../source/utils/filetype-detection.ts"],"names":[],"mappings":"AA+FA,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAW7E"}
|
|
@@ -86,18 +86,6 @@ const extensionToLanguageMap = {
|
|
|
86
86
|
".proto": { name: "Protocol Buffers", codeblock: "protobuf" },
|
|
87
87
|
".txt": { name: "Text", codeblock: "text" },
|
|
88
88
|
};
|
|
89
|
-
export function getLanguageFromFilePath(filePath) {
|
|
90
|
-
const extension = extname(filePath).toLowerCase();
|
|
91
|
-
const languageInfo = extension
|
|
92
|
-
? extensionToLanguageMap[extension]
|
|
93
|
-
: undefined;
|
|
94
|
-
if (languageInfo) {
|
|
95
|
-
return languageInfo.name;
|
|
96
|
-
}
|
|
97
|
-
const filename = basename(filePath).toLowerCase();
|
|
98
|
-
const filenameLanguageInfo = extensionToLanguageMap[`.${filename}`];
|
|
99
|
-
return filenameLanguageInfo?.name;
|
|
100
|
-
}
|
|
101
89
|
export function getCodeblockFromFilePath(filePath) {
|
|
102
90
|
const extension = extname(filePath).toLowerCase();
|
|
103
91
|
const languageInfo = extension
|
|
@@ -24,36 +24,6 @@ export type FormatType = "xml" | "markdown" | "bracket";
|
|
|
24
24
|
* ```
|
|
25
25
|
*/
|
|
26
26
|
export declare function formatFile(file: string, content: string, format: FormatType): string;
|
|
27
|
-
/**
|
|
28
|
-
* Formats URL content with metadata in the specified format.
|
|
29
|
-
*
|
|
30
|
-
* @param siteUrl - The URL to format
|
|
31
|
-
* @param content - The URL content to format
|
|
32
|
-
* @param format - The output format type
|
|
33
|
-
* @returns Formatted URL content with metadata
|
|
34
|
-
* @throws {Error} When an unsupported format is provided
|
|
35
|
-
*
|
|
36
|
-
* @example
|
|
37
|
-
* ```typescript
|
|
38
|
-
* formatUrl("https://example.com", "<html>...</html>", "xml")
|
|
39
|
-
* // Returns: "<webpage>\n<url>https://example.com</url>\n<content>\n<html>...</html>\n</content>\n</webpage>"
|
|
40
|
-
* ```
|
|
41
|
-
*/
|
|
42
|
-
export declare function formatUrl(siteUrl: string, content: string, format: FormatType): string;
|
|
43
|
-
/**
|
|
44
|
-
* Formats content as a code block with appropriate language identifier.
|
|
45
|
-
*
|
|
46
|
-
* @param file - The file path used to determine the code block language
|
|
47
|
-
* @param content - The code content to format
|
|
48
|
-
* @returns Formatted code block with language identifier
|
|
49
|
-
*
|
|
50
|
-
* @example
|
|
51
|
-
* ```typescript
|
|
52
|
-
* formatCodeBlock("example.js", "console.log('hello');")
|
|
53
|
-
* // Returns: "``` javascript\nconsole.log('hello');\n```"
|
|
54
|
-
* ```
|
|
55
|
-
*/
|
|
56
|
-
export declare function formatCodeBlock(file: string, content: string): string;
|
|
57
27
|
/**
|
|
58
28
|
* Formats generic content blocks with a name in the specified format.
|
|
59
29
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formatting.d.ts","sourceRoot":"","sources":["../../source/utils/formatting.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,UAAU,GAAG,SAAS,CAAC;AAExD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,UAAU,GACjB,MAAM,CAaR;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,
|
|
1
|
+
{"version":3,"file":"formatting.d.ts","sourceRoot":"","sources":["../../source/utils/formatting.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,UAAU,GAAG,SAAS,CAAC;AAExD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,UAAU,GACjB,MAAM,CAaR;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,UAAU,GACjB,MAAM,CAWR;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,UAAU,GAAI,KAAK,MAAM,KAAG,MACG,CAAC;AAE7C;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,iBAAiB,GAAI,OAAO,MAAM,KAAG,MASjD,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,cAAc,GAAI,cAAc,MAAM,KAAG,MAuCrD,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,KAAG,MAwC1C,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,UAAU,GAAI,MAAM,IAAI,KAAG,MASvC,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,gBAAgB,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,MAGvD,CAAC"}
|
package/dist/utils/formatting.js
CHANGED
|
@@ -35,50 +35,6 @@ export function formatFile(file, content, format) {
|
|
|
35
35
|
throw new Error(`Unsupported format: ${format}`);
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
-
/**
|
|
39
|
-
* Formats URL content with metadata in the specified format.
|
|
40
|
-
*
|
|
41
|
-
* @param siteUrl - The URL to format
|
|
42
|
-
* @param content - The URL content to format
|
|
43
|
-
* @param format - The output format type
|
|
44
|
-
* @returns Formatted URL content with metadata
|
|
45
|
-
* @throws {Error} When an unsupported format is provided
|
|
46
|
-
*
|
|
47
|
-
* @example
|
|
48
|
-
* ```typescript
|
|
49
|
-
* formatUrl("https://example.com", "<html>...</html>", "xml")
|
|
50
|
-
* // Returns: "<webpage>\n<url>https://example.com</url>\n<content>\n<html>...</html>\n</content>\n</webpage>"
|
|
51
|
-
* ```
|
|
52
|
-
*/
|
|
53
|
-
export function formatUrl(siteUrl, content, format) {
|
|
54
|
-
switch (format) {
|
|
55
|
-
case "xml":
|
|
56
|
-
return `<webpage>\n<url>${siteUrl}</url>\n<content>\n${content}\n</content>\n</webpage>`;
|
|
57
|
-
case "markdown":
|
|
58
|
-
return `## URL: ${siteUrl}\n${MD_TRIPLE_QUOTE}\n${content}\n${MD_TRIPLE_QUOTE}`;
|
|
59
|
-
case "bracket":
|
|
60
|
-
return `[url]: ${siteUrl}\n[url content begin]\n${content}\n[url content end]`;
|
|
61
|
-
default:
|
|
62
|
-
throw new Error(`Unsupported format: ${format}`);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Formats content as a code block with appropriate language identifier.
|
|
67
|
-
*
|
|
68
|
-
* @param file - The file path used to determine the code block language
|
|
69
|
-
* @param content - The code content to format
|
|
70
|
-
* @returns Formatted code block with language identifier
|
|
71
|
-
*
|
|
72
|
-
* @example
|
|
73
|
-
* ```typescript
|
|
74
|
-
* formatCodeBlock("example.js", "console.log('hello');")
|
|
75
|
-
* // Returns: "``` javascript\nconsole.log('hello');\n```"
|
|
76
|
-
* ```
|
|
77
|
-
*/
|
|
78
|
-
export function formatCodeBlock(file, content) {
|
|
79
|
-
const codeBlockName = getCodeblockFromFilePath(file) || path.extname(file).slice(1);
|
|
80
|
-
return `${MD_TRIPLE_QUOTE} ${codeBlockName}\n${content}\n${MD_TRIPLE_QUOTE}`;
|
|
81
|
-
}
|
|
82
38
|
/**
|
|
83
39
|
* Formats generic content blocks with a name in the specified format.
|
|
84
40
|
*
|