sam-coder-cli 1.0.67 → 1.0.69
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/bin/agi-cli.js +88 -10
- package/package.json +1 -1
package/bin/agi-cli.js
CHANGED
|
@@ -430,9 +430,10 @@ const agentUtils = {
|
|
|
430
430
|
},
|
|
431
431
|
|
|
432
432
|
async writeFile(input, maybeContent) {
|
|
433
|
+
let filePath;
|
|
433
434
|
try {
|
|
434
|
-
|
|
435
|
-
const content = typeof input === 'string' ? maybeContent : input?.content;
|
|
435
|
+
filePath = typeof input === 'string' ? input : input?.path;
|
|
436
|
+
const content = typeof input === 'string' ? maybeContent : (input?.content ?? input?.contents ?? input?.data);
|
|
436
437
|
if (!filePath) throw new Error('writeFile: missing path');
|
|
437
438
|
if (typeof content !== 'string') throw new Error('writeFile: missing content');
|
|
438
439
|
const dir = path.dirname(filePath);
|
|
@@ -440,7 +441,8 @@ const agentUtils = {
|
|
|
440
441
|
await fs.writeFile(filePath, content, 'utf-8');
|
|
441
442
|
return `Successfully wrote to ${filePath}`;
|
|
442
443
|
} catch (error) {
|
|
443
|
-
|
|
444
|
+
const ctx = filePath || (typeof input === 'object' ? input?.path : undefined) || 'unknown path';
|
|
445
|
+
throw new Error(`Failed to write to file ${ctx}: ${error.message}`);
|
|
444
446
|
}
|
|
445
447
|
},
|
|
446
448
|
|
|
@@ -514,9 +516,54 @@ const agentUtils = {
|
|
|
514
516
|
|
|
515
517
|
async runCommand(input) {
|
|
516
518
|
try {
|
|
517
|
-
const
|
|
518
|
-
|
|
519
|
-
const
|
|
519
|
+
const isObj = typeof input === 'object' && input !== null;
|
|
520
|
+
let command = !isObj ? input : (input.command ?? null);
|
|
521
|
+
const cmd = isObj ? (input.cmd ?? input.program ?? null) : null;
|
|
522
|
+
const args = isObj ? (input.args ?? input.params ?? null) : null;
|
|
523
|
+
const script = isObj ? (input.script ?? null) : null;
|
|
524
|
+
const shell = isObj ? (input.shell ?? (input.powershell ? 'powershell.exe' : (input.bash ? 'bash' : undefined))) : undefined;
|
|
525
|
+
const cwdRaw = isObj ? input.cwd : undefined;
|
|
526
|
+
const envRaw = isObj ? input.env : undefined;
|
|
527
|
+
const timeout = isObj && typeof input.timeout === 'number' ? input.timeout : undefined;
|
|
528
|
+
|
|
529
|
+
const quoteArg = (a) => {
|
|
530
|
+
if (a == null) return '';
|
|
531
|
+
const s = String(a);
|
|
532
|
+
return /\s|["']/g.test(s) ? '"' + s.replace(/"/g, '\\"') + '"' : s;
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
// Build command from arrays or fields if not provided directly
|
|
536
|
+
if (!command && cmd) {
|
|
537
|
+
if (Array.isArray(cmd)) {
|
|
538
|
+
command = cmd.map(quoteArg).join(' ');
|
|
539
|
+
} else if (typeof cmd === 'string') {
|
|
540
|
+
command = cmd;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
if (Array.isArray(command)) {
|
|
544
|
+
command = command.map(quoteArg).join(' ');
|
|
545
|
+
}
|
|
546
|
+
if (command && Array.isArray(args) && args.length) {
|
|
547
|
+
command = `${command} ${args.map(quoteArg).join(' ')}`;
|
|
548
|
+
}
|
|
549
|
+
if (script && !command) {
|
|
550
|
+
// If only a script is provided, run it directly under the selected shell
|
|
551
|
+
command = String(script);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
if (!command || typeof command !== 'string' || command.trim().length === 0) {
|
|
555
|
+
throw new Error('runCommand: missing command');
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// Resolve cwd
|
|
559
|
+
let cwd = process.cwd();
|
|
560
|
+
if (typeof cwdRaw === 'string' && cwdRaw.trim().length > 0) {
|
|
561
|
+
cwd = path.isAbsolute(cwdRaw) ? cwdRaw : path.join(process.cwd(), cwdRaw);
|
|
562
|
+
}
|
|
563
|
+
// Merge env
|
|
564
|
+
const env = envRaw && typeof envRaw === 'object' ? { ...process.env, ...envRaw } : undefined;
|
|
565
|
+
|
|
566
|
+
const { stdout, stderr } = await execAsync(command, { cwd, env, timeout, shell });
|
|
520
567
|
if (stderr) {
|
|
521
568
|
console.error('Command stderr:', stderr);
|
|
522
569
|
}
|
|
@@ -529,10 +576,17 @@ const agentUtils = {
|
|
|
529
576
|
async searchFiles(input) {
|
|
530
577
|
try {
|
|
531
578
|
const isString = typeof input === 'string';
|
|
532
|
-
|
|
533
|
-
|
|
579
|
+
let pattern = isString ? input : input?.pattern;
|
|
580
|
+
let basePathRaw = isString ? null : (input?.path || null);
|
|
534
581
|
const recursive = isString ? true : (input?.recursive !== false);
|
|
535
582
|
|
|
583
|
+
// Handle wildcards embedded in the path (e.g., C:\\foo\\bar\\*)
|
|
584
|
+
const hasWildcard = (p) => typeof p === 'string' && /[\*\?]/.test(p);
|
|
585
|
+
if (!pattern && hasWildcard(basePathRaw)) {
|
|
586
|
+
pattern = path.basename(basePathRaw);
|
|
587
|
+
basePathRaw = path.dirname(basePathRaw);
|
|
588
|
+
}
|
|
589
|
+
|
|
536
590
|
const basePath = basePathRaw
|
|
537
591
|
? (path.isAbsolute(basePathRaw) ? basePathRaw : path.join(process.cwd(), basePathRaw))
|
|
538
592
|
: process.cwd();
|
|
@@ -542,12 +596,36 @@ const agentUtils = {
|
|
|
542
596
|
const matchByPattern = (name) => {
|
|
543
597
|
if (!pattern) return true; // if no pattern, match all
|
|
544
598
|
const escaped = pattern.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
545
|
-
const regex = new RegExp('^' + escaped.replace(/\*/g, '.*') + '$');
|
|
599
|
+
const regex = new RegExp('^' + escaped.replace(/\*/g, '.*').replace(/\?/g, '.') + '$');
|
|
546
600
|
return regex.test(name);
|
|
547
601
|
};
|
|
548
602
|
|
|
603
|
+
// If base path is a file, test it directly
|
|
604
|
+
try {
|
|
605
|
+
const stat = await fs.stat(basePath);
|
|
606
|
+
if (stat.isFile()) {
|
|
607
|
+
if (matchByPattern(path.basename(basePath))) {
|
|
608
|
+
results.push(basePath);
|
|
609
|
+
}
|
|
610
|
+
return results.length > 0
|
|
611
|
+
? `Found ${results.length} files:\n${results.join('\n')}`
|
|
612
|
+
: 'No files found';
|
|
613
|
+
}
|
|
614
|
+
} catch (e) {
|
|
615
|
+
if (e && e.code === 'ENOENT') {
|
|
616
|
+
return 'No files found';
|
|
617
|
+
}
|
|
618
|
+
// Non-ENOENT errors are handled by traversal below
|
|
619
|
+
}
|
|
620
|
+
|
|
549
621
|
const search = async (dir) => {
|
|
550
|
-
|
|
622
|
+
let entries;
|
|
623
|
+
try {
|
|
624
|
+
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
625
|
+
} catch (e) {
|
|
626
|
+
if (e && e.code === 'ENOENT') return; // directory missing
|
|
627
|
+
throw e;
|
|
628
|
+
}
|
|
551
629
|
for (const entry of entries) {
|
|
552
630
|
const fullPath = path.join(dir, entry.name);
|
|
553
631
|
try {
|