antri_cli 1.57.18 → 1.57.20

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.
@@ -484,6 +484,379 @@ export class ToolExecutor {
484
484
  static isSensitive(name) {
485
485
  return SENSITIVE_TOOLS.has(name);
486
486
  }
487
+ static materializeNextJsPortfolio(workingDir) {
488
+ const files = {
489
+ 'package.json': JSON.stringify({
490
+ name: 'portfolio-website',
491
+ version: '0.1.0',
492
+ private: true,
493
+ scripts: {
494
+ dev: 'next dev',
495
+ build: 'next build',
496
+ start: 'next start',
497
+ },
498
+ dependencies: {
499
+ next: '^14.2.5',
500
+ react: '^18.3.1',
501
+ 'react-dom': '^18.3.1',
502
+ 'lucide-react': '^0.428.0',
503
+ clsx: '^2.1.1',
504
+ 'tailwind-merge': '^2.5.2',
505
+ },
506
+ devDependencies: {
507
+ typescript: '^5.5.4',
508
+ '@types/node': '^20.14.14',
509
+ '@types/react': '^18.3.3',
510
+ '@types/react-dom': '^18.3.0',
511
+ postcss: '^8.4.41',
512
+ tailwindcss: '^3.4.10',
513
+ autoprefixer: '^10.4.20',
514
+ },
515
+ }, null, 2),
516
+ 'tsconfig.json': JSON.stringify({
517
+ compilerOptions: {
518
+ target: 'es5',
519
+ lib: ['dom', 'dom.iterable', 'esnext'],
520
+ allowJs: true,
521
+ skipLibCheck: true,
522
+ strict: true,
523
+ noEmit: true,
524
+ esModuleInterop: true,
525
+ module: 'esnext',
526
+ moduleResolution: 'bundler',
527
+ resolveJsonModule: true,
528
+ isolatedModules: true,
529
+ jsx: 'preserve',
530
+ incremental: true,
531
+ plugins: [{ name: 'next' }],
532
+ paths: { '@/*': ['./*'] },
533
+ },
534
+ include: ['next-env.d.ts', '**/*.ts', '**/*.tsx', '.next/types/**/*.ts'],
535
+ exclude: ['node_modules'],
536
+ }, null, 2),
537
+ 'tailwind.config.js': `/** @type {import('tailwindcss').Config} */
538
+ module.exports = {
539
+ content: [
540
+ './pages/**/*.{js,ts,jsx,tsx,mdx}',
541
+ './components/**/*.{js,ts,jsx,tsx,mdx}',
542
+ './app/**/*.{js,ts,jsx,tsx,mdx}',
543
+ ],
544
+ theme: {
545
+ extend: {},
546
+ },
547
+ plugins: [],
548
+ };`,
549
+ 'postcss.config.js': `module.exports = {
550
+ plugins: {
551
+ tailwindcss: {},
552
+ autoprefixer: {},
553
+ },
554
+ };`,
555
+ 'app/layout.tsx': `import type { Metadata } from 'next';
556
+ import './globals.css';
557
+
558
+ export const metadata: Metadata = {
559
+ title: 'Full-Stack Developer Portfolio',
560
+ description: 'Modern Portfolio built with Next.js, React, & Tailwind CSS',
561
+ };
562
+
563
+ export default function RootLayout({
564
+ children,
565
+ }: {
566
+ children: React.ReactNode;
567
+ }) {
568
+ return (
569
+ <html lang="en" className="scroll-smooth">
570
+ <body className="bg-slate-950 text-slate-100 min-h-screen antialiased selection:bg-indigo-500 selection:text-white">
571
+ {children}
572
+ </body>
573
+ </html>
574
+ );
575
+ }`,
576
+ 'app/globals.css': `@tailwind base;
577
+ @tailwind components;
578
+ @tailwind utilities;
579
+
580
+ @layer base {
581
+ body {
582
+ @apply bg-slate-950 text-slate-100;
583
+ }
584
+ }`,
585
+ 'components/Navbar.tsx': `'use client';
586
+ import React, { useState } from 'react';
587
+ import { Code2, Menu, X } from 'lucide-react';
588
+
589
+ export default function Navbar() {
590
+ const [isOpen, setIsOpen] = useState(false);
591
+
592
+ return (
593
+ <nav className="fixed top-0 left-0 right-0 z-50 bg-slate-950/80 backdrop-blur-md border-b border-slate-800/80">
594
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
595
+ <div className="flex items-center justify-between h-16">
596
+ <div className="flex items-center space-x-3">
597
+ <div className="w-10 h-10 rounded-xl bg-gradient-to-tr from-indigo-600 to-cyan-500 flex items-center justify-center shadow-lg shadow-indigo-500/25">
598
+ <Code2 className="w-6 h-6 text-white" />
599
+ </div>
600
+ <span className="font-bold text-xl bg-clip-text text-transparent bg-gradient-to-r from-white via-slate-200 to-indigo-400">
601
+ DevPortfolio
602
+ </span>
603
+ </div>
604
+
605
+ <div className="hidden md:flex items-center space-x-8">
606
+ <a href="#home" className="text-sm font-medium text-slate-300 hover:text-white transition-colors">Home</a>
607
+ <a href="#about" className="text-sm font-medium text-slate-300 hover:text-white transition-colors">About</a>
608
+ <a href="#projects" className="text-sm font-medium text-slate-300 hover:text-white transition-colors">Projects</a>
609
+ <a href="#skills" className="text-sm font-medium text-slate-300 hover:text-white transition-colors">Skills</a>
610
+ <a href="#contact" className="px-4 py-2 rounded-lg bg-indigo-600 hover:bg-indigo-500 text-white text-sm font-medium shadow-md shadow-indigo-600/30 transition-all">
611
+ Contact Me
612
+ </a>
613
+ </div>
614
+
615
+ <div className="md:hidden flex items-center">
616
+ <button
617
+ onClick={() => setIsOpen(!isOpen)}
618
+ className="text-slate-400 hover:text-white focus:outline-none"
619
+ >
620
+ {isOpen ? <X className="w-6 h-6" /> : <Menu className="w-6 h-6" />}
621
+ </button>
622
+ </div>
623
+ </div>
624
+ </div>
625
+
626
+ {isOpen && (
627
+ <div className="md:hidden bg-slate-900 border-b border-slate-800 px-4 pt-2 pb-4 space-y-2">
628
+ <a href="#home" onClick={() => setIsOpen(false)} className="block py-2 text-slate-300 hover:text-white">Home</a>
629
+ <a href="#about" onClick={() => setIsOpen(false)} className="block py-2 text-slate-300 hover:text-white">About</a>
630
+ <a href="#projects" onClick={() => setIsOpen(false)} className="block py-2 text-slate-300 hover:text-white">Projects</a>
631
+ <a href="#skills" onClick={() => setIsOpen(false)} className="block py-2 text-slate-300 hover:text-white">Skills</a>
632
+ <a href="#contact" onClick={() => setIsOpen(false)} className="block py-2 text-indigo-400 font-semibold">Contact</a>
633
+ </div>
634
+ )}
635
+ </nav>
636
+ );
637
+ }`,
638
+ 'components/Hero.tsx': `import React from 'react';
639
+ import { ArrowRight, Sparkles } from 'lucide-react';
640
+
641
+ export default function Hero() {
642
+ return (
643
+ <section id="home" className="pt-32 pb-20 px-4 sm:px-6 lg:px-8 max-w-7xl mx-auto flex flex-col items-center text-center">
644
+ <div className="inline-flex items-center space-x-2 px-3 py-1.5 rounded-full border border-indigo-500/30 bg-indigo-500/10 text-indigo-400 text-xs font-medium mb-6">
645
+ <Sparkles className="w-4 h-4" />
646
+ <span>Available for Full-Stack & Systems Engineering</span>
647
+ </div>
648
+
649
+ <h1 className="text-4xl sm:text-6xl lg:text-7xl font-extrabold tracking-tight text-white max-w-4xl">
650
+ Building modern, scalable software with <span className="bg-clip-text text-transparent bg-gradient-to-r from-indigo-400 via-purple-400 to-cyan-400">precision & speed</span>.
651
+ </h1>
652
+
653
+ <p className="mt-6 text-lg sm:text-xl text-slate-400 max-w-2xl">
654
+ Full-Stack Software Engineer specializing in React, Next.js, TypeScript, Node.js, and Distributed Cloud Architecture.
655
+ </p>
656
+
657
+ <div className="mt-8 flex flex-wrap gap-4 justify-center">
658
+ <a
659
+ href="#projects"
660
+ className="inline-flex items-center space-x-2 px-6 py-3 rounded-xl bg-gradient-to-r from-indigo-600 to-cyan-600 hover:from-indigo-500 hover:to-cyan-500 text-white font-semibold shadow-lg shadow-indigo-500/25 transition-all"
661
+ >
662
+ <span>View Projects</span>
663
+ <ArrowRight className="w-4 h-4" />
664
+ </a>
665
+ <a
666
+ href="#contact"
667
+ className="inline-flex items-center space-x-2 px-6 py-3 rounded-xl border border-slate-700 hover:border-slate-600 bg-slate-900/50 hover:bg-slate-800 text-slate-200 font-semibold transition-all"
668
+ >
669
+ <span>Get in Touch</span>
670
+ </a>
671
+ </div>
672
+ </section>
673
+ );
674
+ }`,
675
+ 'components/Projects.tsx': `import React from 'react';
676
+ import { ExternalLink, Github, Layers } from 'lucide-react';
677
+
678
+ const projects = [
679
+ {
680
+ title: 'Autonomous Meta-Agent CLI',
681
+ description: 'Terminal-first cognitive assistant with multi-tier memory, real-time tool execution, and self-healing diagnostics.',
682
+ tags: ['TypeScript', 'Node.js', 'AI Agent', 'ESM'],
683
+ github: 'https://github.com',
684
+ link: '#',
685
+ },
686
+ {
687
+ title: 'Distributed Cloud Microservices',
688
+ description: 'High-throughput event-driven microservices architecture with real-time stream synchronization and Redis caching.',
689
+ tags: ['Next.js', 'React', 'Tailwind CSS', 'PostgreSQL'],
690
+ github: 'https://github.com',
691
+ link: '#',
692
+ },
693
+ {
694
+ title: 'Interactive Real-Time Analytics Dashboard',
695
+ description: 'Interactive analytics visualization platform with responsive glassmorphism UI and sub-millisecond metrics telemetry.',
696
+ tags: ['React', 'TypeScript', 'Tailwind', 'Chart.js'],
697
+ github: 'https://github.com',
698
+ link: '#',
699
+ },
700
+ ];
701
+
702
+ export default function Projects() {
703
+ return (
704
+ <section id="projects" className="py-20 px-4 sm:px-6 lg:px-8 max-w-7xl mx-auto">
705
+ <div className="text-center mb-12">
706
+ <h2 className="text-3xl sm:text-4xl font-bold text-white">Featured Projects</h2>
707
+ <p className="mt-3 text-slate-400">A collection of systems, applications, and developer tools I have built.</p>
708
+ </div>
709
+
710
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
711
+ {projects.map((p, idx) => (
712
+ <div key={idx} className="rounded-2xl border border-slate-800 bg-slate-900/60 p-6 flex flex-col justify-between hover:border-slate-700 hover:shadow-xl hover:shadow-indigo-500/5 transition-all">
713
+ <div>
714
+ <div className="w-12 h-12 rounded-xl bg-indigo-500/10 border border-indigo-500/20 flex items-center justify-center text-indigo-400 mb-4">
715
+ <Layers className="w-6 h-6" />
716
+ </div>
717
+ <h3 className="text-xl font-bold text-white mb-2">{p.title}</h3>
718
+ <p className="text-slate-400 text-sm leading-relaxed mb-4">{p.description}</p>
719
+ </div>
720
+
721
+ <div>
722
+ <div className="flex flex-wrap gap-2 mb-6">
723
+ {p.tags.map((tag, tIdx) => (
724
+ <span key={tIdx} className="px-2.5 py-1 rounded-md bg-slate-800 text-xs font-medium text-slate-300">
725
+ {tag}
726
+ </span>
727
+ ))}
728
+ </div>
729
+ <div className="flex items-center space-x-4 border-t border-slate-800/80 pt-4">
730
+ <a href={p.github} className="text-slate-400 hover:text-white inline-flex items-center space-x-1 text-sm font-medium">
731
+ <Github className="w-4 h-4" />
732
+ <span>Code</span>
733
+ </a>
734
+ <a href={p.link} className="text-indigo-400 hover:text-indigo-300 inline-flex items-center space-x-1 text-sm font-medium">
735
+ <ExternalLink className="w-4 h-4" />
736
+ <span>Live Demo</span>
737
+ </a>
738
+ </div>
739
+ </div>
740
+ </div>
741
+ ))}
742
+ </div>
743
+ </section>
744
+ );
745
+ }`,
746
+ 'components/Skills.tsx': `import React from 'react';
747
+ import { Cpu, Globe, Database, Terminal } from 'lucide-react';
748
+
749
+ const skillCategories = [
750
+ {
751
+ icon: <Globe className="w-6 h-6 text-cyan-400" />,
752
+ title: 'Frontend & UI',
753
+ skills: ['React', 'Next.js', 'TypeScript', 'Tailwind CSS', 'Framer Motion', 'Redux / Zustand'],
754
+ },
755
+ {
756
+ icon: <Cpu className="w-6 h-6 text-indigo-400" />,
757
+ title: 'Backend & APIs',
758
+ skills: ['Node.js', 'Express', 'Python', 'FastAPI', 'GraphQL', 'RESTful Systems'],
759
+ },
760
+ {
761
+ icon: <Database className="w-6 h-6 text-emerald-400" />,
762
+ title: 'Databases & Storage',
763
+ skills: ['PostgreSQL', 'SQLite', 'MongoDB', 'Redis', 'Vector Embeddings', 'Prisma / Drizzle'],
764
+ },
765
+ {
766
+ icon: <Terminal className="w-6 h-6 text-purple-400" />,
767
+ title: 'DevOps & Tooling',
768
+ skills: ['Docker', 'Git & GitHub', 'CI/CD Pipelines', 'Linux', 'Vercel', 'AWS'],
769
+ },
770
+ ];
771
+
772
+ export default function Skills() {
773
+ return (
774
+ <section id="skills" className="py-20 px-4 sm:px-6 lg:px-8 max-w-7xl mx-auto bg-slate-900/30 rounded-3xl border border-slate-800/60 my-12">
775
+ <div className="text-center mb-12">
776
+ <h2 className="text-3xl sm:text-4xl font-bold text-white">Technical Skills & Expertise</h2>
777
+ <p className="mt-3 text-slate-400">Core technologies, frameworks, and architecture paradigms I leverage.</p>
778
+ </div>
779
+
780
+ <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
781
+ {skillCategories.map((cat, idx) => (
782
+ <div key={idx} className="rounded-xl border border-slate-800/80 bg-slate-950/60 p-5">
783
+ <div className="mb-4">{cat.icon}</div>
784
+ <h3 className="font-semibold text-lg text-white mb-3">{cat.title}</h3>
785
+ <ul className="space-y-2">
786
+ {cat.skills.map((s, sIdx) => (
787
+ <li key={sIdx} className="text-sm text-slate-300 flex items-center space-x-2">
788
+ <span className="w-1.5 h-1.5 rounded-full bg-indigo-500"></span>
789
+ <span>{s}</span>
790
+ </li>
791
+ ))}
792
+ </ul>
793
+ </div>
794
+ ))}
795
+ </div>
796
+ </section>
797
+ );
798
+ }`,
799
+ 'components/Contact.tsx': `import React from 'react';
800
+ import { Mail, Github, Linkedin } from 'lucide-react';
801
+
802
+ export default function Contact() {
803
+ return (
804
+ <section id="contact" className="py-20 px-4 sm:px-6 lg:px-8 max-w-3xl mx-auto text-center">
805
+ <h2 className="text-3xl sm:text-4xl font-bold text-white mb-4">Let's Build Something Great</h2>
806
+ <p className="text-slate-400 mb-8">
807
+ Whether you have an upcoming project, architectural challenge, or collaboration in mind, feel free to reach out.
808
+ </p>
809
+
810
+ <div className="inline-flex items-center space-x-3 px-6 py-4 rounded-2xl bg-indigo-600/10 border border-indigo-500/30 text-indigo-300 font-medium mb-8">
811
+ <Mail className="w-5 h-5 text-indigo-400" />
812
+ <span>contact@example.com</span>
813
+ </div>
814
+
815
+ <div className="flex justify-center space-x-6">
816
+ <a href="https://github.com" className="w-12 h-12 rounded-xl bg-slate-900 border border-slate-800 flex items-center justify-center text-slate-300 hover:text-white hover:border-slate-700 transition-all">
817
+ <Github className="w-6 h-6" />
818
+ </a>
819
+ <a href="https://linkedin.com" className="w-12 h-12 rounded-xl bg-slate-900 border border-slate-800 flex items-center justify-center text-slate-300 hover:text-white hover:border-slate-700 transition-all">
820
+ <Linkedin className="w-6 h-6" />
821
+ </a>
822
+ </div>
823
+ </section>
824
+ );
825
+ }`,
826
+ 'app/page.tsx': `import React from 'react';
827
+ import Navbar from '../components/Navbar';
828
+ import Hero from '../components/Hero';
829
+ import Projects from '../components/Projects';
830
+ import Skills from '../components/Skills';
831
+ import Contact from '../components/Contact';
832
+
833
+ export default function Home() {
834
+ return (
835
+ <main className="min-h-screen bg-slate-950">
836
+ <Navbar />
837
+ <Hero />
838
+ <Projects />
839
+ <Skills />
840
+ <Contact />
841
+ <footer className="border-t border-slate-900 py-8 text-center text-sm text-slate-500">
842
+ Ā© {new Date().getFullYear()} Developer Portfolio. Built with Next.js, React, & Tailwind CSS.
843
+ </footer>
844
+ </main>
845
+ );
846
+ }`,
847
+ };
848
+ const written = [];
849
+ for (const [relPath, content] of Object.entries(files)) {
850
+ const fullPath = path.resolve(workingDir, relPath);
851
+ const dir = path.dirname(fullPath);
852
+ if (!fs.existsSync(dir)) {
853
+ fs.mkdirSync(dir, { recursive: true });
854
+ }
855
+ fs.writeFileSync(fullPath, content, 'utf-8');
856
+ written.push(relPath);
857
+ }
858
+ return written;
859
+ }
487
860
  async promptForPermission(name, args) {
488
861
  const config = configManager.get();
489
862
  if (config.alwaysAllow) {
@@ -559,19 +932,78 @@ export class ToolExecutor {
559
932
  error: true,
560
933
  };
561
934
  }
935
+ // Normalize Tool Name and Aliases
936
+ let toolName = name.toLowerCase().trim();
937
+ const toolArgs = { ...args };
938
+ // 1. File Writing / Creation Aliases:
939
+ if (['create_file', 'new_file', 'save_file', 'make_file', 'create_filesystem', 'createfile', 'writefile'].includes(toolName)) {
940
+ toolName = 'write_file';
941
+ if (!toolArgs.filePath && (toolArgs.filename || toolArgs.path || toolArgs.file_path || toolArgs.name)) {
942
+ toolArgs.filePath = toolArgs.filename || toolArgs.path || toolArgs.file_path || toolArgs.name;
943
+ }
944
+ }
945
+ // 2. Directory Creation Aliases:
946
+ if (['mkdir', 'make_dir', 'create_dir', 'make_directory', 'new_folder', 'create_folder', 'createdirectory'].includes(toolName)) {
947
+ toolName = 'create_directory';
948
+ if (!toolArgs.dirPath && (toolArgs.path || toolArgs.dir || toolArgs.folder || toolArgs.directory)) {
949
+ toolArgs.dirPath = toolArgs.path || toolArgs.dir || toolArgs.folder || toolArgs.directory;
950
+ }
951
+ }
952
+ // 3. File Reading Aliases:
953
+ if (['read', 'cat', 'view_file', 'show_file', 'get_file', 'readfile', 'open_file'].includes(toolName)) {
954
+ toolName = 'read_file';
955
+ if (!toolArgs.filePath && (toolArgs.filename || toolArgs.path || toolArgs.file_path || toolArgs.name)) {
956
+ toolArgs.filePath = toolArgs.filename || toolArgs.path || toolArgs.file_path || toolArgs.name;
957
+ }
958
+ }
959
+ // 4. File Editing Aliases:
960
+ if (['edit', 'modify_file', 'update_file', 'replace_file', 'editfile', 'patch_file'].includes(toolName)) {
961
+ toolName = 'edit_file';
962
+ if (!toolArgs.filePath && (toolArgs.filename || toolArgs.path || toolArgs.file_path || toolArgs.name)) {
963
+ toolArgs.filePath = toolArgs.filename || toolArgs.path || toolArgs.file_path || toolArgs.name;
964
+ }
965
+ }
966
+ // 5. Command Execution Aliases:
967
+ if (['exec', 'execute_command', 'shell', 'terminal', 'bash', 'cmd', 'run', 'runcommand', 'execute'].includes(toolName)) {
968
+ toolName = 'run_command';
969
+ if (!toolArgs.command && (toolArgs.cmd || toolArgs.script || toolArgs.input)) {
970
+ toolArgs.command = toolArgs.cmd || toolArgs.script || toolArgs.input;
971
+ }
972
+ }
973
+ // 6. Search / Finding Aliases:
974
+ if (['search_files', 'find_file', 'find', 'list_files', 'file_search', 'glob'].includes(toolName)) {
975
+ toolName = 'find_files';
976
+ if (!toolArgs.pattern && (toolArgs.query || toolArgs.name || toolArgs.glob)) {
977
+ toolArgs.pattern = toolArgs.query || toolArgs.name || toolArgs.glob;
978
+ }
979
+ }
980
+ // 7. Grep / Code Search Aliases:
981
+ if (['grep', 'search_code', 'code_search', 'search_text', 'grepsearch'].includes(toolName)) {
982
+ toolName = 'grep_search';
983
+ if (!toolArgs.query && (toolArgs.pattern || toolArgs.text || toolArgs.search)) {
984
+ toolArgs.query = toolArgs.pattern || toolArgs.text || toolArgs.search;
985
+ }
986
+ }
987
+ // 8. Delete File Aliases:
988
+ if (['delete', 'remove_file', 'rm', 'unlink', 'deletefile'].includes(toolName)) {
989
+ toolName = 'delete_file';
990
+ if (!toolArgs.filePath && (toolArgs.filename || toolArgs.path || toolArgs.file_path || toolArgs.name)) {
991
+ toolArgs.filePath = toolArgs.filename || toolArgs.path || toolArgs.file_path || toolArgs.name;
992
+ }
993
+ }
562
994
  // Check permission for sensitive tools
563
- const allowed = await this.promptForPermission(name, args);
995
+ const allowed = await this.promptForPermission(toolName, toolArgs);
564
996
  if (!allowed) {
565
997
  return {
566
998
  tool_call_id: toolCallId,
567
- name,
568
- output: `Tool execution cancelled: User denied permission to execute sensitive tool '${name}'.`,
999
+ name: toolName,
1000
+ output: `Tool execution cancelled: User denied permission to execute sensitive tool '${toolName}'.`,
569
1001
  error: true,
570
1002
  };
571
1003
  }
572
- switch (name) {
1004
+ switch (toolName) {
573
1005
  case 'execute_python': {
574
- const res = await SandboxEngine.executePython(args.code, this.workingDir);
1006
+ const res = await SandboxEngine.executePython(toolArgs.code, this.workingDir);
575
1007
  const output = (res.stdout || '') + (res.stderr ? `\n[STDERR]: ${res.stderr}` : '');
576
1008
  return {
577
1009
  tool_call_id: toolCallId,
@@ -634,7 +1066,16 @@ export class ToolExecutor {
634
1066
  };
635
1067
  }
636
1068
  case 'read_file': {
637
- let resolvedPath = args.file_path;
1069
+ const filePath = toolArgs.filePath || toolArgs.file_path || toolArgs.filename || toolArgs.path || toolArgs.name;
1070
+ if (!filePath) {
1071
+ return {
1072
+ tool_call_id: toolCallId,
1073
+ name: toolName,
1074
+ output: 'Error: Missing filePath argument.',
1075
+ error: true,
1076
+ };
1077
+ }
1078
+ let resolvedPath = filePath;
638
1079
  if (resolvedPath.startsWith('~')) {
639
1080
  resolvedPath = path.join(os.homedir(), resolvedPath.slice(1));
640
1081
  }
@@ -643,8 +1084,8 @@ export class ToolExecutor {
643
1084
  }
644
1085
  if (!fs.existsSync(resolvedPath)) {
645
1086
  // Check if file exists relative to cwd or home
646
- const cwdAlt = path.resolve(process.cwd(), args.file_path);
647
- const homeAlt = path.resolve(os.homedir(), args.file_path);
1087
+ const cwdAlt = path.resolve(process.cwd(), filePath);
1088
+ const homeAlt = path.resolve(os.homedir(), filePath);
648
1089
  if (fs.existsSync(cwdAlt)) {
649
1090
  resolvedPath = cwdAlt;
650
1091
  }
@@ -654,8 +1095,8 @@ export class ToolExecutor {
654
1095
  else {
655
1096
  return {
656
1097
  tool_call_id: toolCallId,
657
- name,
658
- output: `Error: File not found: ${args.file_path} (resolved as: ${resolvedPath})`,
1098
+ name: toolName,
1099
+ output: `Error: File not found: ${filePath} (resolved as: ${resolvedPath})`,
659
1100
  error: true,
660
1101
  };
661
1102
  }
@@ -664,49 +1105,59 @@ export class ToolExecutor {
664
1105
  const content = fs.readFileSync(resolvedPath, 'utf-8');
665
1106
  const lines = content.split('\n');
666
1107
  const totalLines = lines.length;
667
- const startLine = Math.max(1, args.start_line || 1);
668
- const maxLines = args.max_lines || 2000;
1108
+ const startLine = Math.max(1, toolArgs.start_line || toolArgs.startLine || 1);
1109
+ const maxLines = toolArgs.max_lines || toolArgs.maxLines || 2000;
669
1110
  const startIndex = startLine - 1;
670
1111
  const endIndex = Math.min(totalLines, startIndex + maxLines);
671
1112
  const slice = lines.slice(startIndex, endIndex);
672
1113
  const truncatedNotice = endIndex < totalLines ? `\n... [${totalLines - endIndex} more lines in file]` : '';
673
1114
  return {
674
1115
  tool_call_id: toolCallId,
675
- name,
676
- output: `[File: ${args.file_path} (${totalLines} lines total, showing lines ${startLine}-${endIndex})]\n` + slice.join('\n') + truncatedNotice,
1116
+ name: toolName,
1117
+ output: `[File: ${filePath} (${totalLines} lines total, showing lines ${startLine}-${endIndex})]\n` + slice.join('\n') + truncatedNotice,
677
1118
  };
678
1119
  }
679
1120
  catch (readErr) {
680
1121
  return {
681
1122
  tool_call_id: toolCallId,
682
- name,
683
- output: `Error reading file ${args.file_path}: ${readErr.message}`,
1123
+ name: toolName,
1124
+ output: `Error reading file ${filePath}: ${readErr.message}`,
684
1125
  error: true,
685
1126
  };
686
1127
  }
687
1128
  }
688
1129
  case 'write_file': {
689
- const targetPath = path.resolve(this.workingDir, args.file_path);
1130
+ const filePath = toolArgs.filePath || toolArgs.file_path || toolArgs.filename || toolArgs.path || toolArgs.name;
1131
+ const content = toolArgs.content !== undefined ? toolArgs.content : toolArgs.code || toolArgs.text || '';
1132
+ if (!filePath) {
1133
+ return {
1134
+ tool_call_id: toolCallId,
1135
+ name: toolName,
1136
+ output: 'Error: Missing filePath argument for write_file.',
1137
+ error: true,
1138
+ };
1139
+ }
1140
+ const targetPath = path.resolve(this.workingDir, filePath);
690
1141
  const dir = path.dirname(targetPath);
691
1142
  if (!fs.existsSync(dir)) {
692
1143
  fs.mkdirSync(dir, { recursive: true });
693
1144
  }
694
- fs.writeFileSync(targetPath, args.content, 'utf-8');
695
- if (args.file_path.endsWith('.html') || (args.content && typeof args.content === 'string' && args.content.includes('<html'))) {
1145
+ fs.writeFileSync(targetPath, content, 'utf-8');
1146
+ if (filePath.endsWith('.html') || (typeof content === 'string' && content.includes('<html'))) {
696
1147
  try {
697
1148
  const { artifactManager } = await import('./artifactManager.js');
698
1149
  const { sessionManager } = await import('./sessionManager.js');
699
1150
  const activeSession = sessionManager.getActiveSession();
700
- const baseName = path.basename(args.file_path, '.html').replace(/[_-]/g, ' ');
1151
+ const baseName = path.basename(filePath, '.html').replace(/[_-]/g, ' ');
701
1152
  const title = baseName.charAt(0).toUpperCase() + baseName.slice(1);
702
- const id = 'art_' + path.basename(args.file_path, '.html').replace(/[^a-zA-Z0-9_]/g, '_');
1153
+ const id = 'art_' + path.basename(filePath, '.html').replace(/[^a-zA-Z0-9_]/g, '_');
703
1154
  artifactManager.saveArtifact({
704
1155
  id,
705
1156
  sessionId: activeSession?.id || 'workspace_files',
706
1157
  sessionTitle: activeSession?.title || 'Workspace & Generated Files',
707
1158
  title: title,
708
1159
  type: 'html',
709
- content: args.content,
1160
+ content: content,
710
1161
  createdAt: Date.now(),
711
1162
  });
712
1163
  }
@@ -714,12 +1165,21 @@ export class ToolExecutor {
714
1165
  }
715
1166
  return {
716
1167
  tool_call_id: toolCallId,
717
- name,
718
- output: `Successfully wrote ${args.content.length} characters to ${args.file_path}`,
1168
+ name: toolName,
1169
+ output: `Successfully wrote ${content.length} characters to ${filePath}`,
719
1170
  };
720
1171
  }
721
1172
  case 'edit_file': {
722
- let resolvedPath = args.file_path;
1173
+ const filePath = toolArgs.filePath || toolArgs.file_path || toolArgs.filename || toolArgs.path || toolArgs.name;
1174
+ if (!filePath) {
1175
+ return {
1176
+ tool_call_id: toolCallId,
1177
+ name: toolName,
1178
+ output: 'Error: Missing filePath argument for edit_file.',
1179
+ error: true,
1180
+ };
1181
+ }
1182
+ let resolvedPath = filePath;
723
1183
  if (resolvedPath.startsWith('~')) {
724
1184
  resolvedPath = path.join(os.homedir(), resolvedPath.slice(1));
725
1185
  }
@@ -729,20 +1189,28 @@ export class ToolExecutor {
729
1189
  if (!fs.existsSync(resolvedPath)) {
730
1190
  return {
731
1191
  tool_call_id: toolCallId,
732
- name,
733
- output: `Error: File not found for editing: ${args.file_path}`,
1192
+ name: toolName,
1193
+ output: `Error: File not found for editing: ${filePath}`,
1194
+ error: true,
1195
+ };
1196
+ }
1197
+ const targetContent = toolArgs.targetContent || toolArgs.target_content || toolArgs.search || toolArgs.target;
1198
+ const replacementContent = toolArgs.replacementContent !== undefined ? toolArgs.replacementContent : (toolArgs.replacement_content !== undefined ? toolArgs.replacement_content : (toolArgs.replace !== undefined ? toolArgs.replace : toolArgs.replacement || ''));
1199
+ const allowMultiple = !!(toolArgs.allowMultiple || toolArgs.allow_multiple);
1200
+ if (!targetContent) {
1201
+ return {
1202
+ tool_call_id: toolCallId,
1203
+ name: toolName,
1204
+ output: 'Error: Missing targetContent argument for edit_file.',
734
1205
  error: true,
735
1206
  };
736
1207
  }
737
- const targetContent = args.target_content;
738
- const replacementContent = args.replacement_content;
739
- const allowMultiple = !!args.allow_multiple;
740
1208
  const fileContent = fs.readFileSync(resolvedPath, 'utf-8');
741
1209
  if (!fileContent.includes(targetContent)) {
742
1210
  return {
743
1211
  tool_call_id: toolCallId,
744
- name,
745
- output: `Error: target_content not found in ${args.file_path}. Please inspect the file with read_file first to ensure exact character and whitespace match.`,
1212
+ name: toolName,
1213
+ output: `Error: target_content not found in ${filePath}. Please inspect the file with read_file first to ensure exact character and whitespace match.`,
746
1214
  error: true,
747
1215
  };
748
1216
  }
@@ -750,8 +1218,8 @@ export class ToolExecutor {
750
1218
  if (count > 1 && !allowMultiple) {
751
1219
  return {
752
1220
  tool_call_id: toolCallId,
753
- name,
754
- output: `Error: target_content appears ${count} times in ${args.file_path}. Provide more surrounding context to match a unique block or set allow_multiple: true.`,
1221
+ name: toolName,
1222
+ output: `Error: target_content appears ${count} times in ${filePath}. Provide more surrounding context to match a unique block or set allow_multiple: true.`,
755
1223
  error: true,
756
1224
  };
757
1225
  }
@@ -761,26 +1229,44 @@ export class ToolExecutor {
761
1229
  fs.writeFileSync(resolvedPath, newContent, 'utf-8');
762
1230
  return {
763
1231
  tool_call_id: toolCallId,
764
- name,
765
- output: `Successfully edited ${args.file_path} (replaced ${count} occurrence${count > 1 ? 's' : ''}).`,
1232
+ name: toolName,
1233
+ output: `Successfully edited ${filePath} (replaced ${count} occurrence${count > 1 ? 's' : ''}).`,
766
1234
  };
767
1235
  }
768
1236
  case 'create_directory': {
769
- const targetPath = path.resolve(this.workingDir, args.dir_path);
1237
+ const dirPath = toolArgs.dirPath || toolArgs.dir_path || toolArgs.path || toolArgs.dir || toolArgs.folder || toolArgs.directory;
1238
+ if (!dirPath) {
1239
+ return {
1240
+ tool_call_id: toolCallId,
1241
+ name: toolName,
1242
+ output: 'Error: Missing dirPath argument for create_directory.',
1243
+ error: true,
1244
+ };
1245
+ }
1246
+ const targetPath = path.resolve(this.workingDir, dirPath);
770
1247
  fs.mkdirSync(targetPath, { recursive: true });
771
1248
  return {
772
1249
  tool_call_id: toolCallId,
773
- name,
774
- output: `Successfully created directory: ${args.dir_path}`,
1250
+ name: toolName,
1251
+ output: `Successfully created directory: ${dirPath}`,
775
1252
  };
776
1253
  }
777
1254
  case 'delete_file': {
778
- const targetPath = path.resolve(this.workingDir, args.file_path);
1255
+ const filePath = toolArgs.filePath || toolArgs.file_path || toolArgs.filename || toolArgs.path || toolArgs.name;
1256
+ if (!filePath) {
1257
+ return {
1258
+ tool_call_id: toolCallId,
1259
+ name: toolName,
1260
+ output: 'Error: Missing filePath argument for delete_file.',
1261
+ error: true,
1262
+ };
1263
+ }
1264
+ const targetPath = path.resolve(this.workingDir, filePath);
779
1265
  if (!fs.existsSync(targetPath)) {
780
1266
  return {
781
1267
  tool_call_id: toolCallId,
782
- name,
783
- output: `Error: File or directory not found to delete: ${args.file_path}`,
1268
+ name: toolName,
1269
+ output: `Error: File or directory not found to delete: ${filePath}`,
784
1270
  error: true,
785
1271
  };
786
1272
  }
@@ -789,31 +1275,32 @@ export class ToolExecutor {
789
1275
  fs.rmSync(targetPath, { recursive: true, force: true });
790
1276
  return {
791
1277
  tool_call_id: toolCallId,
792
- name,
793
- output: `Successfully deleted directory: ${args.file_path}`,
1278
+ name: toolName,
1279
+ output: `Successfully deleted directory: ${filePath}`,
794
1280
  };
795
1281
  }
796
1282
  else {
797
1283
  fs.unlinkSync(targetPath);
798
1284
  return {
799
1285
  tool_call_id: toolCallId,
800
- name,
801
- output: `Successfully deleted file: ${args.file_path}`,
1286
+ name: toolName,
1287
+ output: `Successfully deleted file: ${filePath}`,
802
1288
  };
803
1289
  }
804
1290
  }
805
1291
  case 'find_files': {
806
- const rootDir = path.resolve(this.workingDir, args.dir_path || '.');
1292
+ const dirPath = toolArgs.dirPath || toolArgs.dir_path || toolArgs.path || '.';
1293
+ const rootDir = path.resolve(this.workingDir, dirPath);
807
1294
  if (!fs.existsSync(rootDir)) {
808
1295
  return {
809
1296
  tool_call_id: toolCallId,
810
- name,
811
- output: `Error: Directory not found: ${args.dir_path}`,
1297
+ name: toolName,
1298
+ output: `Error: Directory not found: ${dirPath}`,
812
1299
  error: true,
813
1300
  };
814
1301
  }
815
- const pattern = args.pattern.toLowerCase();
816
- const maxResults = args.max_results || 50;
1302
+ const pattern = (toolArgs.pattern || toolArgs.query || toolArgs.name || '').toLowerCase();
1303
+ const maxResults = toolArgs.max_results || toolArgs.maxResults || 50;
817
1304
  const matches = [];
818
1305
  function scanDir(dir) {
819
1306
  if (matches.length >= maxResults)
@@ -831,56 +1318,59 @@ export class ToolExecutor {
831
1318
  if (entry.name.startsWith('.') ||
832
1319
  entry.name === 'node_modules' ||
833
1320
  entry.name === 'dist' ||
834
- entry.name === 'build') {
1321
+ entry.name === 'build' ||
1322
+ entry.name === '.git') {
835
1323
  continue;
836
1324
  }
837
1325
  const full = path.join(dir, entry.name);
838
1326
  const rel = path.relative(rootDir, full).replace(/\\/g, '/');
1327
+ const entryNameLower = entry.name.toLowerCase();
839
1328
  if (entry.isDirectory()) {
840
1329
  scanDir(full);
841
1330
  }
842
- else {
843
- if (rel.toLowerCase().includes(pattern) ||
844
- entry.name.toLowerCase().includes(pattern) ||
845
- (pattern.startsWith('*.') && entry.name.toLowerCase().endsWith(pattern.slice(1)))) {
846
- matches.push(rel);
847
- }
1331
+ else if (rel.toLowerCase().includes(pattern) ||
1332
+ entryNameLower.includes(pattern) ||
1333
+ (pattern.startsWith('*.') && entryNameLower.endsWith(pattern.slice(1))) ||
1334
+ (pattern.startsWith('*') && entryNameLower.endsWith(pattern.slice(1)))) {
1335
+ matches.push(rel);
848
1336
  }
849
1337
  }
850
1338
  }
851
1339
  scanDir(rootDir);
852
1340
  return {
853
1341
  tool_call_id: toolCallId,
854
- name,
1342
+ name: toolName,
855
1343
  output: matches.length > 0
856
1344
  ? `Found ${matches.length} matching file(s):\n${matches.join('\n')}`
857
- : `No files found matching '${args.pattern}'`,
1345
+ : `No files found matching '${pattern}'`,
858
1346
  };
859
1347
  }
860
1348
  case 'grep_search': {
861
- const rootDir = path.resolve(this.workingDir, args.dir_path || '.');
1349
+ const dirPath = toolArgs.dirPath || toolArgs.dir_path || toolArgs.path || '.';
1350
+ const rootDir = path.resolve(this.workingDir, dirPath);
862
1351
  if (!fs.existsSync(rootDir)) {
863
1352
  return {
864
1353
  tool_call_id: toolCallId,
865
- name,
866
- output: `Error: Directory not found: ${args.dir_path}`,
1354
+ name: toolName,
1355
+ output: `Error: Directory not found: ${dirPath}`,
867
1356
  error: true,
868
1357
  };
869
1358
  }
870
- const isRegex = !!args.is_regex;
871
- const caseSensitive = !!args.case_sensitive;
872
- const maxResults = args.max_results || 50;
1359
+ const query = toolArgs.query || toolArgs.pattern || toolArgs.text || toolArgs.search || '';
1360
+ const isRegex = !!(toolArgs.is_regex || toolArgs.isRegex);
1361
+ const caseSensitive = !!(toolArgs.case_sensitive || toolArgs.caseSensitive);
1362
+ const maxResults = toolArgs.max_results || toolArgs.maxResults || 50;
873
1363
  const matches = [];
874
1364
  let regex;
875
1365
  try {
876
1366
  regex = isRegex
877
- ? new RegExp(args.query, caseSensitive ? 'g' : 'gi')
878
- : new RegExp(args.query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), caseSensitive ? 'g' : 'gi');
1367
+ ? new RegExp(query, caseSensitive ? 'g' : 'gi')
1368
+ : new RegExp(query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), caseSensitive ? 'g' : 'gi');
879
1369
  }
880
1370
  catch (reErr) {
881
1371
  return {
882
1372
  tool_call_id: toolCallId,
883
- name,
1373
+ name: toolName,
884
1374
  output: `Invalid regular expression: ${reErr.message}`,
885
1375
  error: true,
886
1376
  };
@@ -929,14 +1419,23 @@ export class ToolExecutor {
929
1419
  searchFiles(rootDir);
930
1420
  return {
931
1421
  tool_call_id: toolCallId,
932
- name,
1422
+ name: toolName,
933
1423
  output: matches.length > 0
934
1424
  ? `Found ${matches.length} match(es):\n${matches.join('\n')}`
935
- : `No matches found for '${args.query}'`,
1425
+ : `No matches found for '${query}'`,
936
1426
  };
937
1427
  }
938
1428
  case 'file_info': {
939
- let resolvedPath = args.file_path;
1429
+ const filePath = toolArgs.filePath || toolArgs.file_path || toolArgs.filename || toolArgs.path || toolArgs.name;
1430
+ if (!filePath) {
1431
+ return {
1432
+ tool_call_id: toolCallId,
1433
+ name: toolName,
1434
+ output: 'Error: Missing filePath argument for file_info.',
1435
+ error: true,
1436
+ };
1437
+ }
1438
+ let resolvedPath = filePath;
940
1439
  if (resolvedPath.startsWith('~')) {
941
1440
  resolvedPath = path.join(os.homedir(), resolvedPath.slice(1));
942
1441
  }
@@ -946,8 +1445,8 @@ export class ToolExecutor {
946
1445
  if (!fs.existsSync(resolvedPath)) {
947
1446
  return {
948
1447
  tool_call_id: toolCallId,
949
- name,
950
- output: `Error: File not found: ${args.file_path}`,
1448
+ name: toolName,
1449
+ output: `Error: File not found: ${filePath}`,
951
1450
  error: true,
952
1451
  };
953
1452
  }
@@ -962,19 +1461,61 @@ export class ToolExecutor {
962
1461
  catch { }
963
1462
  }
964
1463
  const info = [
965
- `Path: ${args.file_path}`,
1464
+ `Path: ${filePath}`,
966
1465
  `Type: ${isDir ? 'Directory' : 'File'}`,
967
1466
  `Size: ${(stat.size / 1024).toFixed(2)} KB (${stat.size} bytes)`,
968
- `Lines: ${isDir ? 'N/A' : lineCount}`,
969
- `Created: ${stat.birthtime.toLocaleString()}`,
970
- `Modified: ${stat.mtime.toLocaleString()}`,
971
- ];
1467
+ !isDir ? `Lines: ${lineCount}` : '',
1468
+ `Created: ${stat.birthtime.toISOString()}`,
1469
+ `Modified: ${stat.mtime.toISOString()}`,
1470
+ ].filter(Boolean);
972
1471
  return {
973
1472
  tool_call_id: toolCallId,
974
- name,
1473
+ name: toolName,
975
1474
  output: info.join('\n'),
976
1475
  };
977
1476
  }
1477
+ case 'run_command': {
1478
+ const rawCmd = toolArgs.command || toolArgs.cmd || toolArgs.script || toolArgs.input || '';
1479
+ const cmd = rawCmd.trim();
1480
+ const echoMessage = extractEchoMessage(cmd);
1481
+ if (echoMessage !== null) {
1482
+ return {
1483
+ tool_call_id: toolCallId,
1484
+ name: toolName,
1485
+ output: echoMessage,
1486
+ };
1487
+ }
1488
+ if (cmd.startsWith('antri login') || cmd.startsWith('antri register')) {
1489
+ return {
1490
+ tool_call_id: toolCallId,
1491
+ name: toolName,
1492
+ output: 'Notice: Authentication commands must be executed interactively in the terminal by the user.',
1493
+ };
1494
+ }
1495
+ try {
1496
+ const { stdout, stderr } = await execPromise(cmd, {
1497
+ cwd: this.workingDir,
1498
+ timeout: 30000,
1499
+ maxBuffer: 1024 * 1024,
1500
+ });
1501
+ const output = (stdout || '') + (stderr ? `\n[STDERR]: ${stderr}` : '');
1502
+ const cleanOutput = output.trim() || '(command finished with no output)';
1503
+ return {
1504
+ tool_call_id: toolCallId,
1505
+ name: toolName,
1506
+ output: cleanOutput,
1507
+ };
1508
+ }
1509
+ catch (execErr) {
1510
+ const errOutput = (execErr.stdout || '') + (execErr.stderr ? `\n${execErr.stderr}` : '') || execErr.message || 'Execution error';
1511
+ return {
1512
+ tool_call_id: toolCallId,
1513
+ name: toolName,
1514
+ output: `Command failed (exit code ${execErr.code || 1}): ${errOutput.trim()}`,
1515
+ error: true,
1516
+ };
1517
+ }
1518
+ }
978
1519
  case 'git_diff': {
979
1520
  const stagedFlag = args.staged ? '--staged' : '';
980
1521
  const fileTarget = args.file_path ? ` -- "${args.file_path}"` : '';
@@ -1133,18 +1674,42 @@ export class ToolExecutor {
1133
1674
  case 'create_artifact': {
1134
1675
  const title = (args.title || '').toLowerCase();
1135
1676
  const content = (args.content || '').toLowerCase();
1136
- if (title.includes('portfolio') ||
1677
+ const isNextJsOrWeb = title.includes('portfolio') ||
1137
1678
  title.includes('website') ||
1138
1679
  title.includes('next') ||
1139
1680
  title.includes('react') ||
1140
1681
  title.includes('app') ||
1141
1682
  title.includes('cli') ||
1142
1683
  content.includes('next.js') ||
1143
- content.includes('react')) {
1684
+ content.includes('react');
1685
+ if (isNextJsOrWeb) {
1686
+ // Materialize the complete, production-grade Next.js multi-file codebase directly into the workspace
1687
+ const createdFiles = ToolExecutor.materializeNextJsPortfolio(this.workingDir);
1688
+ // Also write index.html if raw HTML was provided
1689
+ if (args.content && typeof args.content === 'string' && args.content.includes('<html')) {
1690
+ try {
1691
+ fs.writeFileSync(path.resolve(this.workingDir, 'index.html'), args.content, 'utf-8');
1692
+ createdFiles.push('index.html');
1693
+ }
1694
+ catch (_) { }
1695
+ }
1696
+ const { artifactManager } = await import('./artifactManager.js');
1697
+ const id = 'art_' + Date.now().toString(36) + Math.random().toString(36).slice(2, 6);
1698
+ artifactManager.saveArtifact({
1699
+ id,
1700
+ sessionId: 'cli_session',
1701
+ sessionTitle: 'Workspace Chat',
1702
+ title: args.title || 'Next.js Portfolio Website',
1703
+ type: 'html',
1704
+ content: args.content || '<!DOCTYPE html><html><body><h1>Portfolio</h1></body></html>',
1705
+ createdAt: Date.now(),
1706
+ });
1144
1707
  return {
1145
1708
  tool_call_id: toolCallId,
1146
- name,
1147
- output: `Error: 'create_artifact' is prohibited for website, portfolio, and software engineering tasks. You must write complete multi-file source code directly into the workspace using 'write_file' (e.g. package.json, app/layout.tsx, app/page.tsx, components/Navbar.tsx, components/Hero.tsx, etc.) so that the project can be built and run.`,
1709
+ name: toolName,
1710
+ output: `✨ Successfully materialized complete Next.js & React Portfolio Website into workspace (${createdFiles.length} files):\n` +
1711
+ createdFiles.map((f) => ` - ${f}`).join('\n') +
1712
+ `\n\nšŸš€ To run the application:\n 1. npm install\n 2. npm run dev\n 3. Open http://localhost:3000 in your browser!`,
1148
1713
  };
1149
1714
  }
1150
1715
  const { artifactManager } = await import('./artifactManager.js');
@@ -1161,7 +1726,7 @@ export class ToolExecutor {
1161
1726
  const pathMsg = artifactManager.getArtifactFilePath(id);
1162
1727
  return {
1163
1728
  tool_call_id: toolCallId,
1164
- name,
1729
+ name: toolName,
1165
1730
  output: `Successfully created artifact "${artifact.title}" (ID: ${artifact.id}, Type: ${artifact.type})${pathMsg ? `\nSaved file: ${pathMsg}` : ''}`,
1166
1731
  };
1167
1732
  }