@happyvertical/utils 0.74.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/AGENT.md +33 -0
- package/LICENSE +7 -0
- package/README.md +143 -0
- package/dist/browser.d.ts +20 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +59 -0
- package/dist/browser.js.map +1 -0
- package/dist/chunks/universal-BeseWxvS.js +934 -0
- package/dist/chunks/universal-BeseWxvS.js.map +1 -0
- package/dist/cli/claude-context.d.ts +3 -0
- package/dist/cli/claude-context.d.ts.map +1 -0
- package/dist/cli/claude-context.js +21 -0
- package/dist/cli/claude-context.js.map +1 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/parse-args.d.ts +61 -0
- package/dist/cli/parse-args.d.ts.map +1 -0
- package/dist/cli/parse-flags.d.ts +22 -0
- package/dist/cli/parse-flags.d.ts.map +1 -0
- package/dist/config/env-config.d.ts +119 -0
- package/dist/config/env-config.d.ts.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +394 -0
- package/dist/index.js.map +1 -0
- package/dist/shared/code/extraction.d.ts +90 -0
- package/dist/shared/code/extraction.d.ts.map +1 -0
- package/dist/shared/code/index.d.ts +14 -0
- package/dist/shared/code/index.d.ts.map +1 -0
- package/dist/shared/code/sandbox.d.ts +165 -0
- package/dist/shared/code/sandbox.d.ts.map +1 -0
- package/dist/shared/code/validation.d.ts +113 -0
- package/dist/shared/code/validation.d.ts.map +1 -0
- package/dist/shared/index.d.ts +5 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/logger.d.ts +43 -0
- package/dist/shared/logger.d.ts.map +1 -0
- package/dist/shared/types.d.ts +195 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/universal.d.ts +400 -0
- package/dist/shared/universal.d.ts.map +1 -0
- package/dist/web.d.ts +35 -0
- package/dist/web.d.ts.map +1 -0
- package/metadata.json +54 -0
- package/package.json +70 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
import { basename } from "node:path";
|
|
2
|
+
import { parseArgs } from "node:util";
|
|
3
|
+
import { A, B, D, E, F, N, P, T, V, a, c, b, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, C, G, H, I, J, K, L, M, O, Q, R, S, U, W, X, Y } from "./chunks/universal-BeseWxvS.js";
|
|
4
|
+
import * as vm from "node:vm";
|
|
5
|
+
import { createHash } from "node:crypto";
|
|
6
|
+
import { isCuid } from "@paralleldrive/cuid2";
|
|
7
|
+
function parseCliArgs(argv, commands, builtInCommands = {}) {
|
|
8
|
+
let args = argv;
|
|
9
|
+
if (args.length > 0 && basename(args[0]) === "node") {
|
|
10
|
+
args = args.slice(1);
|
|
11
|
+
}
|
|
12
|
+
if (args.length > 0 && args[0].endsWith(".js")) {
|
|
13
|
+
args = args.slice(1);
|
|
14
|
+
}
|
|
15
|
+
if (args.length === 0) {
|
|
16
|
+
return { args: [], options: {} };
|
|
17
|
+
}
|
|
18
|
+
if (args.includes("--help")) {
|
|
19
|
+
return { command: "help", args: [], options: {} };
|
|
20
|
+
}
|
|
21
|
+
if (args.includes("--version")) {
|
|
22
|
+
return { command: "version", args: [], options: {} };
|
|
23
|
+
}
|
|
24
|
+
let matchedCommand;
|
|
25
|
+
let commandName;
|
|
26
|
+
let commandWordCount = 0;
|
|
27
|
+
for (let i2 = Math.min(3, args.length); i2 > 0; i2--) {
|
|
28
|
+
const possibleCommand = args.slice(0, i2).join(" ");
|
|
29
|
+
const found = builtInCommands[possibleCommand] || commands.find(
|
|
30
|
+
(cmd) => cmd.name === possibleCommand || cmd.aliases?.includes(possibleCommand)
|
|
31
|
+
);
|
|
32
|
+
if (found) {
|
|
33
|
+
matchedCommand = found;
|
|
34
|
+
commandName = possibleCommand;
|
|
35
|
+
commandWordCount = i2;
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (!commandName && args.length > 0) {
|
|
40
|
+
commandName = args[0];
|
|
41
|
+
commandWordCount = 1;
|
|
42
|
+
matchedCommand = commands.find(
|
|
43
|
+
(cmd) => cmd.name === commandName || cmd.aliases?.includes(commandName)
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
if (!matchedCommand) {
|
|
47
|
+
if (args.includes("-h")) {
|
|
48
|
+
return { command: "help", args: [], options: {} };
|
|
49
|
+
}
|
|
50
|
+
if (args.includes("-v")) {
|
|
51
|
+
return { command: "version", args: [], options: {} };
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
command: commandName,
|
|
55
|
+
args: args.slice(1).filter((arg) => !arg.startsWith("-")),
|
|
56
|
+
options: {}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const parseConfig = {
|
|
60
|
+
args: args.slice(commandWordCount),
|
|
61
|
+
options: {},
|
|
62
|
+
strict: false,
|
|
63
|
+
// Allow unknown options
|
|
64
|
+
allowPositionals: true
|
|
65
|
+
// Required for mixing positional args and options
|
|
66
|
+
};
|
|
67
|
+
const numberOptions = /* @__PURE__ */ new Set();
|
|
68
|
+
if (matchedCommand.options) {
|
|
69
|
+
for (const [name, option] of Object.entries(matchedCommand.options)) {
|
|
70
|
+
const nodeType = option.type === "boolean" ? "boolean" : "string";
|
|
71
|
+
if (option.type === "number") {
|
|
72
|
+
numberOptions.add(name);
|
|
73
|
+
}
|
|
74
|
+
parseConfig.options[name] = {
|
|
75
|
+
type: nodeType
|
|
76
|
+
};
|
|
77
|
+
if (option.default !== void 0) {
|
|
78
|
+
parseConfig.options[name].default = option.type === "number" ? String(option.default) : option.default;
|
|
79
|
+
}
|
|
80
|
+
if (option.short) {
|
|
81
|
+
parseConfig.options[name].short = option.short;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
const parsed = parseArgs(parseConfig);
|
|
87
|
+
const options = parsed.values || {};
|
|
88
|
+
for (const name of numberOptions) {
|
|
89
|
+
if (name in options && options[name] !== void 0) {
|
|
90
|
+
const rawValue = options[name];
|
|
91
|
+
if (rawValue === "") {
|
|
92
|
+
throw new Error(`Invalid number for --${name}: "${rawValue}"`);
|
|
93
|
+
}
|
|
94
|
+
const value = Number(rawValue);
|
|
95
|
+
if (Number.isNaN(value)) {
|
|
96
|
+
throw new Error(`Invalid number for --${name}: "${rawValue}"`);
|
|
97
|
+
}
|
|
98
|
+
options[name] = value;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
command: commandName,
|
|
103
|
+
args: parsed.positionals || [],
|
|
104
|
+
options
|
|
105
|
+
};
|
|
106
|
+
} catch (error) {
|
|
107
|
+
if (error instanceof Error && error.message.startsWith("Invalid number")) {
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
command: commandName,
|
|
112
|
+
args: args.slice(commandWordCount).filter((arg) => !arg.startsWith("-")),
|
|
113
|
+
options: {}
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function parseFlagArgs(args) {
|
|
118
|
+
const flags = {};
|
|
119
|
+
const positionals = [];
|
|
120
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
121
|
+
const arg = args[index];
|
|
122
|
+
if (arg === "--") {
|
|
123
|
+
positionals.push(...args.slice(index + 1));
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
if (!arg.startsWith("--")) {
|
|
127
|
+
positionals.push(arg);
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
const [rawKey, inlineValue] = arg.slice(2).split(/=(.*)/su, 2);
|
|
131
|
+
if (rawKey === "") {
|
|
132
|
+
throw new Error(
|
|
133
|
+
`Invalid flag token "${arg}": flag name is empty. Use --key=value or --key value.`
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
const key = rawKey.replace(
|
|
137
|
+
/-([a-z])/gu,
|
|
138
|
+
(_match, letter) => letter.toUpperCase()
|
|
139
|
+
);
|
|
140
|
+
if (inlineValue !== void 0) {
|
|
141
|
+
flags[key] = inlineValue;
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
const next = args[index + 1];
|
|
145
|
+
if (next !== void 0 && !next.startsWith("--")) {
|
|
146
|
+
flags[key] = next;
|
|
147
|
+
index += 1;
|
|
148
|
+
} else {
|
|
149
|
+
flags[key] = true;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return { flags, positionals };
|
|
153
|
+
}
|
|
154
|
+
const DEFAULT_BUILTINS = [
|
|
155
|
+
"Array",
|
|
156
|
+
"Object",
|
|
157
|
+
"JSON",
|
|
158
|
+
"Math",
|
|
159
|
+
"Date",
|
|
160
|
+
"String",
|
|
161
|
+
"Number",
|
|
162
|
+
"Boolean",
|
|
163
|
+
"RegExp",
|
|
164
|
+
"Set",
|
|
165
|
+
"Map",
|
|
166
|
+
"WeakSet",
|
|
167
|
+
"WeakMap",
|
|
168
|
+
"Symbol",
|
|
169
|
+
"Promise"
|
|
170
|
+
];
|
|
171
|
+
function createSandbox(options = {}) {
|
|
172
|
+
const {
|
|
173
|
+
globals = {},
|
|
174
|
+
allowedBuiltins = DEFAULT_BUILTINS,
|
|
175
|
+
allowConsole = false
|
|
176
|
+
} = options;
|
|
177
|
+
const sandbox = /* @__PURE__ */ Object.create(null);
|
|
178
|
+
for (const builtin of allowedBuiltins) {
|
|
179
|
+
if (builtin in globalThis) {
|
|
180
|
+
sandbox[builtin] = globalThis[builtin];
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (allowConsole) {
|
|
184
|
+
sandbox.console = console;
|
|
185
|
+
}
|
|
186
|
+
Object.assign(sandbox, globals);
|
|
187
|
+
return vm.createContext(sandbox);
|
|
188
|
+
}
|
|
189
|
+
function executeCode(code, sandbox, options = {}) {
|
|
190
|
+
const {
|
|
191
|
+
timeout = 5e3,
|
|
192
|
+
filename = "generated-code.js",
|
|
193
|
+
captureResult = true
|
|
194
|
+
} = options;
|
|
195
|
+
try {
|
|
196
|
+
let wrappedCode;
|
|
197
|
+
if (captureResult) {
|
|
198
|
+
const hasMultipleStatements = code.includes(";") || code.includes("\n") && code.trim().split("\n").length > 1;
|
|
199
|
+
const hasFunctionDef = /function\s+\w+|const\s+\w+\s*=\s*function|const\s+\w+\s*=\s*\(/i.test(
|
|
200
|
+
code
|
|
201
|
+
);
|
|
202
|
+
if (hasMultipleStatements || hasFunctionDef) {
|
|
203
|
+
wrappedCode = code;
|
|
204
|
+
} else {
|
|
205
|
+
wrappedCode = `(function() { return (${code}); })();`;
|
|
206
|
+
}
|
|
207
|
+
} else {
|
|
208
|
+
wrappedCode = code;
|
|
209
|
+
}
|
|
210
|
+
const result = vm.runInContext(wrappedCode, sandbox, {
|
|
211
|
+
timeout,
|
|
212
|
+
filename,
|
|
213
|
+
displayErrors: true
|
|
214
|
+
});
|
|
215
|
+
return result;
|
|
216
|
+
} catch (error) {
|
|
217
|
+
if (error instanceof Error) {
|
|
218
|
+
const message = `Code execution failed: ${error.message}`;
|
|
219
|
+
const enhancedError = new Error(message);
|
|
220
|
+
enhancedError.stack = error.stack;
|
|
221
|
+
throw enhancedError;
|
|
222
|
+
}
|
|
223
|
+
throw error;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
async function executeCodeAsync(code, sandbox, options = {}) {
|
|
227
|
+
const {
|
|
228
|
+
timeout = 5e3,
|
|
229
|
+
filename = "generated-code.js",
|
|
230
|
+
captureResult = true
|
|
231
|
+
} = options;
|
|
232
|
+
try {
|
|
233
|
+
let wrappedCode;
|
|
234
|
+
if (captureResult) {
|
|
235
|
+
const trimmedCode = code.trim();
|
|
236
|
+
const lines = trimmedCode.split("\n");
|
|
237
|
+
if (lines.length > 1 || trimmedCode.includes(";")) {
|
|
238
|
+
const statements = trimmedCode.split("\n").filter((line) => line.trim());
|
|
239
|
+
const lastLine = statements[statements.length - 1];
|
|
240
|
+
const otherLines = statements.slice(0, -1);
|
|
241
|
+
if (lastLine.trim().startsWith("return ")) {
|
|
242
|
+
wrappedCode = `(async function() {
|
|
243
|
+
${trimmedCode}
|
|
244
|
+
})();`;
|
|
245
|
+
} else {
|
|
246
|
+
const lastExpression = lastLine.trim().replace(/;$/, "");
|
|
247
|
+
wrappedCode = `(async function() {
|
|
248
|
+
${otherLines.join("\n")}
|
|
249
|
+
return ${lastExpression};
|
|
250
|
+
})();`;
|
|
251
|
+
}
|
|
252
|
+
} else {
|
|
253
|
+
wrappedCode = `(async function() {
|
|
254
|
+
return (${trimmedCode});
|
|
255
|
+
})();`;
|
|
256
|
+
}
|
|
257
|
+
} else {
|
|
258
|
+
wrappedCode = `(async function() {
|
|
259
|
+
${code}
|
|
260
|
+
})();`;
|
|
261
|
+
}
|
|
262
|
+
const result = await vm.runInContext(wrappedCode, sandbox, {
|
|
263
|
+
timeout,
|
|
264
|
+
filename,
|
|
265
|
+
displayErrors: true
|
|
266
|
+
});
|
|
267
|
+
return result;
|
|
268
|
+
} catch (error) {
|
|
269
|
+
if (error instanceof Error) {
|
|
270
|
+
const message = `Async code execution failed: ${error.message}`;
|
|
271
|
+
const enhancedError = new Error(message);
|
|
272
|
+
enhancedError.stack = error.stack;
|
|
273
|
+
throw enhancedError;
|
|
274
|
+
}
|
|
275
|
+
throw error;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
function executeInSandbox(code, options = {}) {
|
|
279
|
+
const sandbox = createSandbox(options);
|
|
280
|
+
return executeCode(code, sandbox, options);
|
|
281
|
+
}
|
|
282
|
+
async function executeInSandboxAsync(code, options = {}) {
|
|
283
|
+
const sandbox = createSandbox(options);
|
|
284
|
+
return executeCodeAsync(code, sandbox, options);
|
|
285
|
+
}
|
|
286
|
+
function normalizeUrl(url) {
|
|
287
|
+
const parsed = new URL(url);
|
|
288
|
+
parsed.protocol = parsed.protocol.toLowerCase();
|
|
289
|
+
parsed.hostname = parsed.hostname.toLowerCase();
|
|
290
|
+
parsed.hostname = parsed.hostname.replace(/^www\./, "");
|
|
291
|
+
if (parsed.protocol === "http:" && parsed.port === "80" || parsed.protocol === "https:" && parsed.port === "443") {
|
|
292
|
+
parsed.port = "";
|
|
293
|
+
}
|
|
294
|
+
parsed.hash = "";
|
|
295
|
+
const params = new URLSearchParams(parsed.search);
|
|
296
|
+
const filtered = new URLSearchParams();
|
|
297
|
+
const trackingParams = [
|
|
298
|
+
"utm_source",
|
|
299
|
+
"utm_medium",
|
|
300
|
+
"utm_campaign",
|
|
301
|
+
"utm_content",
|
|
302
|
+
"utm_term",
|
|
303
|
+
"fbclid",
|
|
304
|
+
"gclid",
|
|
305
|
+
"msclkid",
|
|
306
|
+
"_ga",
|
|
307
|
+
"mc_cid",
|
|
308
|
+
"mc_eid"
|
|
309
|
+
];
|
|
310
|
+
Array.from(params.keys()).sort().forEach((key) => {
|
|
311
|
+
if (!trackingParams.includes(key)) {
|
|
312
|
+
filtered.set(key, params.get(key));
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
parsed.search = filtered.toString();
|
|
316
|
+
return parsed.toString();
|
|
317
|
+
}
|
|
318
|
+
function generateScopeFromUrl(url, baseScope = "discovery/parser") {
|
|
319
|
+
const parsed = new URL(normalizeUrl(url));
|
|
320
|
+
const domain = parsed.hostname;
|
|
321
|
+
const pathParts = parsed.pathname.split("/").filter((p2) => p2);
|
|
322
|
+
const pageType = pathParts[0] || "index";
|
|
323
|
+
return `${baseScope}/${domain}/${pageType}`;
|
|
324
|
+
}
|
|
325
|
+
function hashPageContent(html) {
|
|
326
|
+
return createHash("sha256").update(html).digest("hex");
|
|
327
|
+
}
|
|
328
|
+
const PACKAGE_VERSION_INITIALIZED = true;
|
|
329
|
+
export {
|
|
330
|
+
A as ApiError,
|
|
331
|
+
B as BaseError,
|
|
332
|
+
D as DatabaseError,
|
|
333
|
+
E as ErrorCode,
|
|
334
|
+
F as FileError,
|
|
335
|
+
N as NetworkError,
|
|
336
|
+
PACKAGE_VERSION_INITIALIZED,
|
|
337
|
+
P as ParsingError,
|
|
338
|
+
T as TimeoutError,
|
|
339
|
+
V as ValidationError,
|
|
340
|
+
a as addInterval,
|
|
341
|
+
c as camelCase,
|
|
342
|
+
b as convertType,
|
|
343
|
+
d as createId,
|
|
344
|
+
createSandbox,
|
|
345
|
+
e as dateInString,
|
|
346
|
+
f as disableLogging,
|
|
347
|
+
g as domainToCamel,
|
|
348
|
+
h as enableLogging,
|
|
349
|
+
executeCode,
|
|
350
|
+
executeCodeAsync,
|
|
351
|
+
executeInSandbox,
|
|
352
|
+
executeInSandboxAsync,
|
|
353
|
+
i as extractAllCodeBlocks,
|
|
354
|
+
j as extractCodeBlock,
|
|
355
|
+
k as extractFunctionDefinition,
|
|
356
|
+
l as extractJSON,
|
|
357
|
+
m as formatDate,
|
|
358
|
+
generateScopeFromUrl,
|
|
359
|
+
n as getLogger,
|
|
360
|
+
o as getTempDirectory,
|
|
361
|
+
hashPageContent,
|
|
362
|
+
p as isArray,
|
|
363
|
+
isCuid,
|
|
364
|
+
q as isPlainObject,
|
|
365
|
+
r as isPlural,
|
|
366
|
+
s as isSafeCode,
|
|
367
|
+
t as isSingular,
|
|
368
|
+
u as isUrl,
|
|
369
|
+
v as isValidDate,
|
|
370
|
+
w as keysToCamel,
|
|
371
|
+
x as keysToSnake,
|
|
372
|
+
y as loadEnvConfig,
|
|
373
|
+
z as logTicker,
|
|
374
|
+
C as makeId,
|
|
375
|
+
G as makeSlug,
|
|
376
|
+
normalizeUrl,
|
|
377
|
+
H as parseAmazonDateString,
|
|
378
|
+
parseCliArgs,
|
|
379
|
+
I as parseDate,
|
|
380
|
+
parseFlagArgs,
|
|
381
|
+
J as pluralizeWord,
|
|
382
|
+
K as prettyDate,
|
|
383
|
+
L as setLogger,
|
|
384
|
+
M as singularize,
|
|
385
|
+
O as sleep,
|
|
386
|
+
Q as snakeCase,
|
|
387
|
+
R as toCamelCase,
|
|
388
|
+
S as toScreamingSnakeCase,
|
|
389
|
+
U as urlFilename,
|
|
390
|
+
W as urlPath,
|
|
391
|
+
X as validateCode,
|
|
392
|
+
Y as waitFor
|
|
393
|
+
};
|
|
394
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/cli/parse-args.ts","../src/cli/parse-flags.ts","../src/shared/code/sandbox.ts","../src/web.ts","../src/index.ts"],"sourcesContent":["/**\n * CLI Argument Parsing Utility\n *\n * Provides robust parsing for multi-word commands, options, and arguments.\n * Supports Node.js util.parseArgs for option parsing with fallback.\n */\n\nimport { basename } from 'node:path';\nimport { parseArgs as nodeParseArgs } from 'node:util';\n\n/**\n * Command option configuration\n */\nexport interface OptionConfig {\n type: 'string' | 'boolean' | 'number';\n description: string;\n default?: any;\n short?: string;\n}\n\n/**\n * Command definition\n */\nexport interface Command {\n name: string;\n description: string;\n aliases?: string[];\n options?: Record<string, OptionConfig>;\n args?: string[];\n handler?: (args: any, options: any) => Promise<void>;\n}\n\n/**\n * Parsed command line arguments\n */\nexport interface ParsedArgs {\n command?: string;\n args: string[];\n options: Record<string, any>;\n}\n\n/**\n * Parse command line arguments with support for multi-word commands\n *\n * Handles:\n * - Multi-word commands (up to 3 words: \"gnode create\", \"foo bar baz\")\n * - Command aliases\n * - Positional arguments\n * - Options using Node.js util.parseArgs\n * - Global flags (--help, --version)\n * - Automatic removal of node/script paths\n *\n * @param argv - Process argv or custom argument array\n * @param commands - Array of command definitions to match against\n * @param builtInCommands - Optional map of additional built-in commands\n * @returns Parsed arguments with command, args, and options\n *\n * @example\n * ```typescript\n * const parsed = parseCliArgs(\n * ['node', 'cli.js', 'gnode', 'create', 'my-site', '--template=town'],\n * commands\n * );\n * // { command: 'gnode create', args: ['my-site'], options: { template: 'town' } }\n * ```\n */\nexport function parseCliArgs(\n argv: string[],\n commands: Command[],\n builtInCommands: Record<string, Command> = {},\n): ParsedArgs {\n // Remove node and script name if present\n // Be precise: only remove if it's actually the node executable or a .js file\n // Use basename to avoid matching commands like \"gnode\" which end with \"node\"\n let args = argv;\n\n // Check if first arg is node executable (check basename to avoid false matches)\n if (args.length > 0 && basename(args[0]) === 'node') {\n args = args.slice(1);\n }\n\n // Check if first arg is a .js file (script name)\n if (args.length > 0 && args[0].endsWith('.js')) {\n args = args.slice(1);\n }\n\n if (args.length === 0) {\n return { args: [], options: {} };\n }\n\n // Handle global --help flag (check for -h later to avoid conflict with command options)\n if (args.includes('--help')) {\n return { command: 'help', args: [], options: {} };\n }\n\n if (args.includes('--version')) {\n return { command: 'version', args: [], options: {} };\n }\n\n // Try to match multi-word commands (longest match wins)\n let matchedCommand: Command | undefined;\n let commandName: string | undefined;\n let commandWordCount = 0;\n\n // Try up to 3 words for command name (e.g., \"foo bar baz\")\n for (let i = Math.min(3, args.length); i > 0; i--) {\n const possibleCommand = args.slice(0, i).join(' ');\n const found =\n builtInCommands[possibleCommand] ||\n commands.find(\n (cmd) =>\n cmd.name === possibleCommand ||\n cmd.aliases?.includes(possibleCommand),\n );\n\n if (found) {\n matchedCommand = found;\n commandName = possibleCommand;\n commandWordCount = i;\n break;\n }\n }\n\n // If no multi-word match, try single word\n if (!commandName && args.length > 0) {\n commandName = args[0];\n commandWordCount = 1;\n matchedCommand = commands.find(\n (cmd) =>\n cmd.name === commandName ||\n cmd.aliases?.includes(commandName as string),\n );\n }\n\n // If no command matched, check for global short flags\n if (!matchedCommand) {\n if (args.includes('-h')) {\n return { command: 'help', args: [], options: {} };\n }\n if (args.includes('-v')) {\n return { command: 'version', args: [], options: {} };\n }\n // Return unknown command with args filtered\n return {\n command: commandName,\n args: args.slice(1).filter((arg) => !arg.startsWith('-')),\n options: {},\n };\n }\n\n // Build parseArgs config from command definition\n const parseConfig: any = {\n args: args.slice(commandWordCount),\n options: {},\n strict: false, // Allow unknown options\n allowPositionals: true, // Required for mixing positional args and options\n };\n\n // Track which options are numbers for post-processing\n const numberOptions: Set<string> = new Set();\n\n if (matchedCommand.options) {\n for (const [name, option] of Object.entries(matchedCommand.options)) {\n // Node.js parseArgs only supports 'string' and 'boolean'\n // Treat 'number' as 'string' and convert after parsing\n const nodeType = option.type === 'boolean' ? 'boolean' : 'string';\n\n if (option.type === 'number') {\n numberOptions.add(name);\n }\n\n parseConfig.options[name] = {\n type: nodeType,\n };\n\n // Handle default value - convert number defaults to string for parseArgs\n if (option.default !== undefined) {\n parseConfig.options[name].default =\n option.type === 'number' ? String(option.default) : option.default;\n }\n\n if (option.short) {\n parseConfig.options[name].short = option.short;\n }\n }\n }\n\n try {\n const parsed = nodeParseArgs(parseConfig);\n // Cast to Record<string, unknown> since we'll be adding number values\n // during post-processing of 'number' type options\n const options: Record<string, unknown> = parsed.values || {};\n\n // Post-process number options: convert strings to numbers\n for (const name of numberOptions) {\n if (name in options && options[name] !== undefined) {\n const rawValue = options[name];\n // Empty string should be treated as invalid, not as 0\n if (rawValue === '') {\n throw new Error(`Invalid number for --${name}: \"${rawValue}\"`);\n }\n const value = Number(rawValue);\n if (Number.isNaN(value)) {\n throw new Error(`Invalid number for --${name}: \"${rawValue}\"`);\n }\n options[name] = value;\n }\n }\n\n return {\n command: commandName,\n args: parsed.positionals || [],\n options,\n };\n } catch (error) {\n // Re-throw validation errors (invalid number conversion)\n if (error instanceof Error && error.message.startsWith('Invalid number')) {\n throw error;\n }\n // Fallback for parse errors - extract positional args manually\n return {\n command: commandName,\n args: args.slice(commandWordCount).filter((arg) => !arg.startsWith('-')),\n options: {},\n };\n }\n}\n","/**\n * Lightweight flag/positional splitter for one-shot scripts.\n *\n * Distinct from `parseCliArgs`, which models multi-word commands and typed\n * options. `parseFlagArgs` is the bare-bones alternative for scripts that\n * just need `{ flags, positionals }` from `process.argv.slice(2)`.\n *\n * Flag forms supported:\n * --foo -> flags.foo = true\n * --foo bar -> flags.foo = 'bar'\n * --foo=bar -> flags.foo = 'bar'\n * --foo-bar baz -> flags.fooBar = 'baz' (kebab -> camel)\n * -- -> stop parsing flags; rest are positionals\n *\n * Anything not starting with `--` becomes a positional.\n */\nexport interface ParsedFlagArgs {\n flags: Record<string, string | true>;\n positionals: string[];\n}\n\nexport function parseFlagArgs(args: string[]): ParsedFlagArgs {\n const flags: Record<string, string | true> = {};\n const positionals: string[] = [];\n\n for (let index = 0; index < args.length; index += 1) {\n const arg = args[index];\n if (arg === '--') {\n positionals.push(...args.slice(index + 1));\n break;\n }\n if (!arg.startsWith('--')) {\n positionals.push(arg);\n continue;\n }\n\n const [rawKey, inlineValue] = arg.slice(2).split(/=(.*)/su, 2);\n if (rawKey === '') {\n // `--=value` or just `--` followed by garbage — the empty key\n // would be unreachable to any sensible caller. Throw rather than\n // silently producing `flags[''] = value`.\n throw new Error(\n `Invalid flag token \"${arg}\": flag name is empty. Use --key=value or --key value.`,\n );\n }\n const key = rawKey.replace(/-([a-z])/gu, (_match, letter: string) =>\n letter.toUpperCase(),\n );\n if (inlineValue !== undefined) {\n flags[key] = inlineValue;\n continue;\n }\n\n const next = args[index + 1];\n if (next !== undefined && !next.startsWith('--')) {\n flags[key] = next;\n index += 1;\n } else {\n flags[key] = true;\n }\n }\n\n return { flags, positionals };\n}\n","/**\n * Sandbox creation and safe code execution utilities\n *\n * Provides secure execution of generated code in isolated VM contexts with\n * controlled globals, timeouts, and resource constraints.\n */\n\nimport * as vm from 'node:vm';\n\n/**\n * Options for creating a sandbox execution context\n */\nexport interface SandboxOptions {\n /**\n * Global variables to make available in the sandbox\n * These will be accessible as global variables in the executed code\n */\n globals?: Record<string, any>;\n\n /**\n * Maximum execution time in milliseconds\n * Default: 5000ms (5 seconds)\n */\n timeout?: number;\n\n /**\n * Allowed built-in JavaScript objects\n * Default: ['Array', 'Object', 'JSON', 'Math', 'Date', 'String', 'Number', 'Boolean', 'RegExp']\n */\n allowedBuiltins?: string[];\n\n /**\n * Whether to allow console access (useful for debugging)\n * Default: false (console will be undefined unless provided in globals)\n */\n allowConsole?: boolean;\n}\n\n/**\n * Options for executing code in a sandbox\n */\nexport interface ExecuteOptions {\n /**\n * Maximum execution time in milliseconds\n * Overrides the sandbox-level timeout if provided\n */\n timeout?: number;\n\n /**\n * Filename to use in error messages and stack traces\n * Default: 'generated-code.js'\n */\n filename?: string;\n\n /**\n * Whether to capture and return the last expression value\n * Default: true\n */\n captureResult?: boolean;\n}\n\n/**\n * Default safe built-in objects available in the sandbox\n */\nconst DEFAULT_BUILTINS = [\n 'Array',\n 'Object',\n 'JSON',\n 'Math',\n 'Date',\n 'String',\n 'Number',\n 'Boolean',\n 'RegExp',\n 'Set',\n 'Map',\n 'WeakSet',\n 'WeakMap',\n 'Symbol',\n 'Promise',\n];\n\n/**\n * Creates a secure sandbox execution context with controlled globals\n *\n * @param options - Configuration for the sandbox\n * @returns A VM context that can be used with executeCode()\n *\n * @example\n * ```typescript\n * const sandbox = createSandbox({\n * globals: {\n * cheerio: require('cheerio'),\n * data: { foo: 'bar' }\n * },\n * timeout: 5000,\n * allowedBuiltins: ['Array', 'Object', 'JSON']\n * });\n *\n * const result = executeCode('data.foo', sandbox);\n * // Returns: \"bar\"\n * ```\n */\nexport function createSandbox(options: SandboxOptions = {}): vm.Context {\n const {\n globals = {},\n allowedBuiltins = DEFAULT_BUILTINS,\n allowConsole = false,\n } = options;\n\n // Start with an empty object with null prototype to avoid inheriting anything\n const sandbox: Record<string, any> = Object.create(null);\n\n // Add allowed built-ins\n for (const builtin of allowedBuiltins) {\n if (builtin in globalThis) {\n sandbox[builtin] = (globalThis as any)[builtin];\n }\n }\n\n // Add console if allowed (otherwise it remains undefined)\n if (allowConsole) {\n sandbox.console = console;\n }\n\n // Add user-provided globals\n Object.assign(sandbox, globals);\n\n // Create and return the context\n return vm.createContext(sandbox);\n}\n\n/**\n * Executes code in a sandbox with timeout and error handling\n *\n * @param code - The JavaScript code to execute\n * @param sandbox - The VM context created by createSandbox()\n * @param options - Execution options\n * @returns The result of the code execution\n * @throws {Error} If code execution fails or times out\n *\n * @example\n * ```typescript\n * const sandbox = createSandbox({\n * globals: { x: 10, y: 20 }\n * });\n *\n * const result = executeCode('x + y', sandbox);\n * // Returns: 30\n *\n * // With a function\n * const funcResult = executeCode(`\n * function add(a, b) {\n * return a + b;\n * }\n * add(x, y);\n * `, sandbox);\n * // Returns: 30\n * ```\n */\nexport function executeCode<T = any>(\n code: string,\n sandbox: vm.Context,\n options: ExecuteOptions = {},\n): T {\n const {\n timeout = 5000,\n filename = 'generated-code.js',\n captureResult = true,\n } = options;\n\n try {\n // For simple expressions, wrap in return. For complex code, execute directly\n let wrappedCode: string;\n\n if (captureResult) {\n // Check if code has multiple statements or function definitions\n const hasMultipleStatements =\n code.includes(';') ||\n (code.includes('\\n') && code.trim().split('\\n').length > 1);\n const hasFunctionDef =\n /function\\s+\\w+|const\\s+\\w+\\s*=\\s*function|const\\s+\\w+\\s*=\\s*\\(/i.test(\n code,\n );\n\n if (hasMultipleStatements || hasFunctionDef) {\n // Execute code as-is (will return last expression)\n wrappedCode = code;\n } else {\n // Simple expression - wrap in return\n wrappedCode = `(function() { return (${code}); })();`;\n }\n } else {\n wrappedCode = code;\n }\n\n const result = vm.runInContext(wrappedCode, sandbox, {\n timeout,\n filename,\n displayErrors: true,\n });\n\n return result as T;\n } catch (error) {\n // Enhanced error message with context\n if (error instanceof Error) {\n const message = `Code execution failed: ${error.message}`;\n const enhancedError = new Error(message);\n enhancedError.stack = error.stack;\n throw enhancedError;\n }\n throw error;\n }\n}\n\n/**\n * Executes async code in a sandbox with timeout and error handling\n *\n * @param code - The JavaScript code to execute (can contain async/await)\n * @param sandbox - The VM context created by createSandbox()\n * @param options - Execution options\n * @returns Promise resolving to the result of the code execution\n * @throws {Error} If code execution fails or times out\n *\n * @example\n * ```typescript\n * const sandbox = createSandbox({\n * globals: {\n * fetch: require('node-fetch')\n * }\n * });\n *\n * const result = await executeCodeAsync(`\n * const response = await fetch('https://api.example.com/data');\n * const data = await response.json();\n * data;\n * `, sandbox);\n * ```\n */\nexport async function executeCodeAsync<T = any>(\n code: string,\n sandbox: vm.Context,\n options: ExecuteOptions = {},\n): Promise<T> {\n const {\n timeout = 5000,\n filename = 'generated-code.js',\n captureResult = true,\n } = options;\n\n try {\n // For async code, wrap in async function with smart return handling\n let wrappedCode: string;\n\n if (captureResult) {\n // For multi-line code, wrap in async IIFE and return last expression\n // Split into statements and make last one a return\n const trimmedCode = code.trim();\n const lines = trimmedCode.split('\\n');\n\n if (lines.length > 1 || trimmedCode.includes(';')) {\n // Multi-line or multiple statements - find last expression\n const statements = trimmedCode\n .split('\\n')\n .filter((line) => line.trim());\n const lastLine = statements[statements.length - 1];\n const otherLines = statements.slice(0, -1);\n\n // If last line is already a return statement, keep code as-is\n if (lastLine.trim().startsWith('return ')) {\n wrappedCode = `(async function() {\n ${trimmedCode}\n })();`;\n } else {\n // Make last line a return (remove trailing semicolon if present)\n const lastExpression = lastLine.trim().replace(/;$/, '');\n wrappedCode = `(async function() {\n ${otherLines.join('\\n')}\n return ${lastExpression};\n })();`;\n }\n } else {\n // Single expression - wrap in return\n wrappedCode = `(async function() {\n return (${trimmedCode});\n })();`;\n }\n } else {\n wrappedCode = `(async function() {\n ${code}\n })();`;\n }\n\n const result = await vm.runInContext(wrappedCode, sandbox, {\n timeout,\n filename,\n displayErrors: true,\n });\n\n return result as T;\n } catch (error) {\n // Enhanced error message with context\n if (error instanceof Error) {\n const message = `Async code execution failed: ${error.message}`;\n const enhancedError = new Error(message);\n enhancedError.stack = error.stack;\n throw enhancedError;\n }\n throw error;\n }\n}\n\n/**\n * Convenience function to create a sandbox and execute code in one step\n *\n * @param code - The JavaScript code to execute\n * @param options - Combined sandbox and execution options\n * @returns The result of the code execution\n *\n * @example\n * ```typescript\n * const result = executeInSandbox('Math.sqrt(16)', {\n * globals: { x: 10 },\n * timeout: 1000\n * });\n * // Returns: 4\n * ```\n */\nexport function executeInSandbox<T = any>(\n code: string,\n options: SandboxOptions & ExecuteOptions = {},\n): T {\n const sandbox = createSandbox(options);\n return executeCode<T>(code, sandbox, options);\n}\n\n/**\n * Convenience function to create a sandbox and execute async code in one step\n *\n * @param code - The JavaScript code to execute (can contain async/await)\n * @param options - Combined sandbox and execution options\n * @returns Promise resolving to the result of the code execution\n *\n * @example\n * ```typescript\n * const result = await executeInSandboxAsync(`\n * const data = await Promise.resolve({ value: 42 });\n * data.value;\n * `, {\n * timeout: 2000\n * });\n * // Returns: 42\n * ```\n */\nexport async function executeInSandboxAsync<T = any>(\n code: string,\n options: SandboxOptions & ExecuteOptions = {},\n): Promise<T> {\n const sandbox = createSandbox(options);\n return executeCodeAsync<T>(code, sandbox, options);\n}\n","/**\n * Web and URL utility functions\n *\n * General-purpose utilities for working with URLs and web content.\n * Used by scrapers, note systems, and content processors.\n */\n\nimport { createHash } from 'node:crypto';\n\n/**\n * Normalize URL for consistent key storage\n * Removes tracking params, sorts query string, lowercases, etc.\n *\n * @param url - The URL to normalize\n * @returns Normalized URL string\n */\nexport function normalizeUrl(url: string): string {\n const parsed = new URL(url);\n\n // Lowercase scheme and host\n parsed.protocol = parsed.protocol.toLowerCase();\n parsed.hostname = parsed.hostname.toLowerCase();\n\n // Remove www prefix\n parsed.hostname = parsed.hostname.replace(/^www\\./, '');\n\n // Remove default ports\n if (\n (parsed.protocol === 'http:' && parsed.port === '80') ||\n (parsed.protocol === 'https:' && parsed.port === '443')\n ) {\n parsed.port = '';\n }\n\n // Remove fragment\n parsed.hash = '';\n\n // Sort and filter query params\n const params = new URLSearchParams(parsed.search);\n const filtered = new URLSearchParams();\n const trackingParams = [\n 'utm_source',\n 'utm_medium',\n 'utm_campaign',\n 'utm_content',\n 'utm_term',\n 'fbclid',\n 'gclid',\n 'msclkid',\n '_ga',\n 'mc_cid',\n 'mc_eid',\n ];\n\n Array.from(params.keys())\n .sort()\n .forEach((key) => {\n if (!trackingParams.includes(key)) {\n filtered.set(key, params.get(key)!);\n }\n });\n\n parsed.search = filtered.toString();\n\n return parsed.toString();\n}\n\n/**\n * Generate hierarchical scope from URL for organized note storage\n *\n * @param url - The URL to generate scope from\n * @param baseScope - Base scope prefix (default: 'discovery/parser')\n * @returns Hierarchical scope string\n *\n * @example\n * generateScopeFromUrl('https://cityofboston.gov/meetings/minutes')\n * // Returns: 'discovery/parser/cityofboston.gov/meetings'\n */\nexport function generateScopeFromUrl(\n url: string,\n baseScope = 'discovery/parser',\n): string {\n const parsed = new URL(normalizeUrl(url));\n const domain = parsed.hostname;\n const pathParts = parsed.pathname.split('/').filter((p) => p);\n\n // Use first path segment as page type (e.g., 'meetings', 'documents')\n const pageType = pathParts[0] || 'index';\n\n return `${baseScope}/${domain}/${pageType}`;\n}\n\n/**\n * Hash page content for change detection\n * Uses SHA-256 to create a unique fingerprint of the HTML\n *\n * @param html - Page HTML content\n * @returns SHA-256 hash as hex string\n */\nexport function hashPageContent(html: string): string {\n return createHash('sha256').update(html).digest('hex');\n}\n","export * from './cli/index';\nexport * from './config/env-config';\nexport * from './shared/index';\nexport * from './web';\n\n/** @internal */\nexport const PACKAGE_VERSION_INITIALIZED = true;\n"],"names":["i","nodeParseArgs","p"],"mappings":"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"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code extraction utilities for parsing code from text (e.g., AI responses)
|
|
3
|
+
*
|
|
4
|
+
* Provides functions to extract code blocks, JSON data, and function definitions
|
|
5
|
+
* from markdown-formatted text or AI-generated responses.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Extracts a code block from markdown-formatted text
|
|
9
|
+
*
|
|
10
|
+
* @param text - The text containing markdown code blocks
|
|
11
|
+
* @param language - Optional language specifier to match (e.g., 'javascript', 'typescript', 'json')
|
|
12
|
+
* @returns The extracted code without markdown delimiters, or empty string if not found
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const code = extractCodeBlock(`
|
|
17
|
+
* Here's the function:
|
|
18
|
+
* \`\`\`javascript
|
|
19
|
+
* function hello() {
|
|
20
|
+
* return 'world';
|
|
21
|
+
* }
|
|
22
|
+
* \`\`\`
|
|
23
|
+
* `, 'javascript');
|
|
24
|
+
* // Returns: "function hello() {\n return 'world';\n}"
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function extractCodeBlock(text: string, language?: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Extracts and parses JSON from text, handling markdown code blocks
|
|
30
|
+
*
|
|
31
|
+
* @param text - The text containing JSON data
|
|
32
|
+
* @returns The parsed JSON object
|
|
33
|
+
* @throws {SyntaxError} If the JSON is invalid
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* const data = extractJSON<{ name: string }>(`
|
|
38
|
+
* The result is:
|
|
39
|
+
* \`\`\`json
|
|
40
|
+
* {
|
|
41
|
+
* "name": "example"
|
|
42
|
+
* }
|
|
43
|
+
* \`\`\`
|
|
44
|
+
* `);
|
|
45
|
+
* // Returns: { name: "example" }
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare function extractJSON<T = any>(text: string): T;
|
|
49
|
+
/**
|
|
50
|
+
* Extracts all code blocks from markdown-formatted text
|
|
51
|
+
*
|
|
52
|
+
* @param text - The text containing markdown code blocks
|
|
53
|
+
* @param language - Optional language specifier to filter by
|
|
54
|
+
* @returns Array of extracted code blocks
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* const blocks = extractAllCodeBlocks(`
|
|
59
|
+
* \`\`\`javascript
|
|
60
|
+
* const a = 1;
|
|
61
|
+
* \`\`\`
|
|
62
|
+
*
|
|
63
|
+
* \`\`\`typescript
|
|
64
|
+
* const b: number = 2;
|
|
65
|
+
* \`\`\`
|
|
66
|
+
* `);
|
|
67
|
+
* // Returns: ["const a = 1;", "const b: number = 2;"]
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export declare function extractAllCodeBlocks(text: string, language?: string): string[];
|
|
71
|
+
/**
|
|
72
|
+
* Extracts a specific function definition from code
|
|
73
|
+
*
|
|
74
|
+
* @param code - The code containing function definitions
|
|
75
|
+
* @param functionName - The name of the function to extract
|
|
76
|
+
* @returns The function definition, or empty string if not found
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```typescript
|
|
80
|
+
* const code = `
|
|
81
|
+
* function foo() { return 1; }
|
|
82
|
+
* function bar() { return 2; }
|
|
83
|
+
* `;
|
|
84
|
+
*
|
|
85
|
+
* const fooFunc = extractFunctionDefinition(code, 'foo');
|
|
86
|
+
* // Returns: "function foo() { return 1; }"
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
export declare function extractFunctionDefinition(code: string, functionName: string): string;
|
|
90
|
+
//# sourceMappingURL=extraction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extraction.d.ts","sourceRoot":"","sources":["../../../src/shared/code/extraction.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAyBxE;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,WAAW,CAAC,CAAC,GAAG,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,CAoCpD;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,GAChB,MAAM,EAAE,CAqBV;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,GACnB,MAAM,CAoFR"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code utilities for extraction, validation, and safe execution
|
|
3
|
+
*
|
|
4
|
+
* Provides tools for working with generated code (e.g., from AI responses):
|
|
5
|
+
* - Extract code blocks from markdown and text
|
|
6
|
+
* - Validate code for security and syntax
|
|
7
|
+
* - Execute code safely in isolated sandboxes
|
|
8
|
+
*
|
|
9
|
+
* @module code
|
|
10
|
+
*/
|
|
11
|
+
export { extractAllCodeBlocks, extractCodeBlock, extractFunctionDefinition, extractJSON, } from './extraction';
|
|
12
|
+
export { createSandbox, type ExecuteOptions, executeCode, executeCodeAsync, executeInSandbox, executeInSandboxAsync, type SandboxOptions, } from './sandbox';
|
|
13
|
+
export { isSafeCode, type ValidationOptions, type ValidationResult, validateCode, } from './validation';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/code/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,yBAAyB,EACzB,WAAW,GACZ,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,aAAa,EACb,KAAK,cAAc,EACnB,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAChB,qBAAqB,EACrB,KAAK,cAAc,GACpB,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,UAAU,EACV,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,YAAY,GACb,MAAM,cAAc,CAAC"}
|