Skip to content

Conversation

@phodal
Copy link
Owner

@phodal phodal commented Dec 25, 2025

Overview

This PR introduces a comprehensive artifact execution framework that enables AutoDev to create, package, and execute interactive artifacts across multiple platforms.

Key Features

1. Artifact Bundle System

  • ArtifactBundle: Core data structure for packaging artifacts with metadata
  • ArtifactBundlePacker: Platform-specific implementations for creating .unit files (ZIP-based)
  • Support for Node.js, Python, and Web artifact types

2. Artifact Executors

  • NodeJsArtifactExecutor: Execute Node.js artifacts with npm dependency management
  • PythonArtifactExecutor: Execute Python artifacts with pip dependency management
  • WebArtifactExecutor: Execute web artifacts with live preview
  • ProcessManager: Manage long-running artifact processes with start/stop controls

3. UI Components

  • ArtifactPage: Main UI for artifact creation and execution
  • ArtifactPreviewPanel: Platform-specific preview panels (Desktop, Android, iOS, Web)
  • ArtifactAgentViewModel: State management for artifact workflows
  • Streaming optimization with throttled content updates

4. File Association

  • .unit file type registration with ZIP MIME type
  • Desktop file handler for opening .unit files
  • CLI support for artifact execution

Technical Improvements

  • Platform-specific implementations using Kotlin Multiplatform expect/actual
  • Proper dependency management to avoid conflicts with IntelliJ libraries
  • Comprehensive test coverage for bundle packing and execution
  • Integration with existing agent framework

Testing

  • Added unit tests for ArtifactBundlePacker
  • Added integration tests for artifact executors
  • Added tests for Node.js artifact bundle creation

Related Issues

Fixes #526

Checklist

  • Code follows project conventions
  • Tests added/updated
  • All platforms considered (JS, WASM, Desktop JVM, Android, iOS)
  • Build and tests passing
  • Documentation updated (if needed)

Pull Request opened by Augment Code with guidance from the PR author

Summary by CodeRabbit

Release Notes

  • New Features

    • Added Node.js artifact support with automatic dependency detection from code.
    • Introduced ability to fix and regenerate failed artifacts with error context.
    • Added local execution for Node.js artifacts with server URL detection and process management.
    • New "Open Unit Bundle" menu option to load pre-built artifacts.
    • Auto-detection and management of long-running server processes.
  • Improvements

    • Enhanced artifact selection to prefer code artifacts over metadata files.
    • Optimized rendering performance during content streaming.
    • .unit files now properly recognized as ZIP archives.

✏️ Tip: You can customize this high-level summary in your review settings.

- Add ArtifactExecutor for running Node.js applications from .unit files
- Support npm install and node index.js execution with real-time output
- Add NodeJsExecutionView UI component for terminal-like output display
- Update ArtifactBundle to handle NODEJS artifact type
- Extend GenerateTestUnit to create Express.js demo applications
- Add execution button to ArtifactPreviewPanel for Node.js artifacts
…rt/stop controls

- Add ProcessManager to manage long-running processes like Express.js servers
- Update Node.js execution to support server processes with start/stop UI controls
- Add auto-dependency detection for Node.js artifacts from require/import statements
- Improve artifact selection logic to avoid package.json as main content
- Add server URL display and stop button in NodeJsExecutionView
- Extend ArtifactPreviewPanel with onFixRequest callback for auto-f
Copilot AI review requested due to automatic review settings December 25, 2025 12:11
@coderabbitai
Copy link

coderabbitai bot commented Dec 25, 2025

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

This PR adds Node.js artifact support to AutoDev Unit, enabling generation and execution of Node.js/React applications. It introduces artifact fixing capabilities, process management for long-running servers, and platform-specific execution handlers for Node.js, Python, and web artifacts.

Changes

Cohort / File(s) Summary
Core Artifact Types
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/ArtifactAgent.kt, mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/ArtifactAgentTemplate.kt
Added NODEJS artifact type enum entry with mime type application/autodev.artifacts.nodejs. Introduced fix() public API and buildFixPrompt() helper to enable artifact repair workflows. Updated templates with Node.js-specific guidelines and examples.
Bundle Management
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/artifact/ArtifactBundle.kt, mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/artifact/ArtifactBundlePacker.kt
Extended bundle handling with Node.js support: dependency auto-detection via detectNodeDependencies(), selectBestArtifact() selection logic, fingerprint calculation, and package.json generation. Updated main file naming for NODEJS to "index.js".
Artifact Execution Framework
mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/artifact/executor/ArtifactExecutor.kt, mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/artifact/executor/ArtifactExecutorFactory.kt
Introduced public ArtifactExecutor interface defining execution/validation contract with ExecutionResult and ValidationResult types. Added ArtifactExecutorFactory singleton to orchestrate executor selection and artifact execution with type determination.
Executor Implementations
mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/artifact/executor/NodeJsArtifactExecutor.kt, mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/artifact/executor/WebArtifactExecutor.kt, mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/artifact/executor/PythonArtifactExecutor.kt
Added platform-specific executors: NodeJsArtifactExecutor with recovery logic for package.json parsing and long-running server support; WebArtifactExecutor with Python/Node.js HTTP server fallback; PythonArtifactExecutor with PEP 723 dependency parsing.
Process Management
mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/artifact/executor/ProcessManager.kt
New singleton managing long-running external processes with graceful shutdown, concurrent tracking via ConcurrentHashMap, async output streaming, and startup validation. Supports process lifecycle (start/stop/check alive).
Legacy Compatibility
mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/artifact/ArtifactExecutor.kt
Added deprecated ArtifactExecutor object and ExecutionResult types, delegating to new ArtifactExecutorFactory for backward compatibility.
Test Utilities
mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/artifact/GenerateTestUnit.kt
Refactored main entry to support two modes via CLI arguments: HTML demo generation and Express.js unit creation with bundle packaging.
UI View Model
mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/agent/artifact/ArtifactAgentViewModel.kt
Added fixArtifact() public function for error recovery workflows. Integrated best-artifact selection post-generation. Added NODEJS type mapping in artifact type handling.
Compose UI Components
mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/agent/artifact/ArtifactPage.kt, mpp-ui/src/*/kotlin/cc/unitmesh/devins/ui/compose/agent/artifact/ArtifactPreviewPanel.*.kt
Added optional onFixRequest callback parameter to ArtifactPreviewPanel across all platforms (common, jvm, android, ios, js, wasmJs). Updated JVM implementation with Node.js execution UI (Execute/Stop buttons, server URL display, process management).
JVM UI & Menu Integration
mpp-ui/src/jvmMain/kotlin/cc/unitmesh/devins/ui/Main.kt, mpp-ui/src/jvmMain/kotlin/cc/unitmesh/devins/ui/desktop/AutoDevMenuBar.kt, mpp-ui/src/jvmMain/kotlin/cc/unitmesh/devins/ui/desktop/Keymap.kt
Added File menu item "Open Unit Bundle..." with Cmd/Ctrl+Shift+U shortcut. Implemented openUnitBundleFile() for async bundle loading and UI state switching.
Rendering Optimization
mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/sketch/SketchRenderer.kt
Added streaming throttling during content updates to optimize rendering with configurable thresholds (line/character deltas, time intervals). Caches parsed CodeFence blocks to prevent redundant parsing.
Build Configuration
mpp-ui/build.gradle.kts
Updated .unit file mime type from application/x-autodev-unit to application/zip with clarifying comments. Updated macOS UTI declarations to reflect ZIP archive semantics.
Test Files
mpp-core/src/jvmTest/kotlin/cc/unitmesh/agent/artifact/ArtifactExecutorTest.kt, mpp-core/src/jvmTest/kotlin/cc/unitmesh/agent/artifact/NodeJsArtifactBundleTest.kt
Added comprehensive test suites covering Node.js artifact generation, bundling, packing/unpacking, dependency detection, package.json structure, and artifact selection logic.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as UI/ViewModel
    participant Agent as ArtifactAgent
    participant Executor as ArtifactExecutor<br/>(Factory)
    participant NodeExec as NodeJsArtifact<br/>Executor
    participant ProcMgr as ProcessManager
    participant NodeRuntime as Node.js<br/>Runtime

    User->>UI: Click Execute for Node.js artifact
    activate UI
    UI->>Executor: executeArtifact(unitFilePath)
    activate Executor
    
    Executor->>Executor: Extract .unit bundle
    Executor->>Executor: Read ARTIFACT.md, determine type
    Executor->>Executor: Get executor for NODEJS type
    
    rect rgb(200, 220, 250)
        Note over Executor,NodeExec: Execution Phase
        Executor->>NodeExec: execute(extractDir, onOutput)
        activate NodeExec
        NodeExec->>NodeExec: Validate package.json exists
        NodeExec->>NodeExec: Detect main file (index.js)
        NodeExec->>ProcMgr: startProcess(npm install)
        activate ProcMgr
        ProcMgr->>NodeRuntime: npm install
        NodeRuntime-->>ProcMgr: Dependencies installed
        deactivate ProcMgr
        
        NodeExec->>ProcMgr: startProcess(node index.js)
        activate ProcMgr
        ProcMgr->>NodeRuntime: Launch Node.js process
        NodeRuntime-->>ProcMgr: Process running, serverUrl detected
        ProcMgr-->>NodeExec: (processId, output)
        deactivate ProcMgr
        
        NodeExec-->>Executor: ExecutionResult.Success(output, serverUrl, processId)
        deactivate NodeExec
    end
    
    Executor-->>UI: ExecutionResult
    deactivate Executor
    
    UI->>UI: Update state (serverUrl, processId, running)
    UI->>User: Display execution output & server link
    deactivate UI
    
    opt On Execution Error
        User->>UI: Click "Fix with AI"
        activate UI
        UI->>Agent: fix(originalArtifact, errorMessage)
        activate Agent
        Agent->>Agent: buildFixPrompt(artifact, error)
        Agent->>Agent: generate() with fix context
        Agent-->>UI: ArtifactResult with fixed code
        deactivate Agent
        
        UI->>UI: selectBestArtifact(result.artifacts)
        UI->>User: Show fixed artifact for retry
        deactivate UI
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Rationale: The PR introduces substantial, interconnected changes across multiple domains—artifact execution with platform-specific executors, long-running process management with concurrent tracking, LLM-driven artifact repair workflows, and cross-platform UI updates (6+ platform variants). The heterogeneous nature (new public APIs, process lifecycle logic, streaming optimizations, menu integration) and complexity of executor implementations (recovery logic, dependency parsing, server detection) require careful review despite coherent architectural patterns.

Possibly related PRs

Poem

🐰✨ A bunny hops through Node.js fields,
Where processes run and servers yield,\
Auto-fixing artifacts with flair,\
From HTML to Python—everywhere!\
Unit bundles dance in ZIP delight,\
Reversible creation, oh what a sight! 🎉

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/autodev-unit-artifact

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b8d985e and f1856fe.

📒 Files selected for processing (26)
  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/ArtifactAgent.kt
  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/ArtifactAgentTemplate.kt
  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/artifact/ArtifactBundle.kt
  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/artifact/ArtifactBundlePacker.kt
  • mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/artifact/ArtifactExecutor.kt
  • mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/artifact/GenerateTestUnit.kt
  • mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/artifact/executor/ArtifactExecutor.kt
  • mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/artifact/executor/ArtifactExecutorFactory.kt
  • mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/artifact/executor/NodeJsArtifactExecutor.kt
  • mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/artifact/executor/ProcessManager.kt
  • mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/artifact/executor/PythonArtifactExecutor.kt
  • mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/artifact/executor/WebArtifactExecutor.kt
  • mpp-core/src/jvmTest/kotlin/cc/unitmesh/agent/artifact/ArtifactExecutorTest.kt
  • mpp-core/src/jvmTest/kotlin/cc/unitmesh/agent/artifact/NodeJsArtifactBundleTest.kt
  • mpp-ui/build.gradle.kts
  • mpp-ui/src/androidMain/kotlin/cc/unitmesh/devins/ui/compose/agent/artifact/ArtifactPreviewPanel.android.kt
  • mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/agent/artifact/ArtifactAgentViewModel.kt
  • mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/agent/artifact/ArtifactPage.kt
  • mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/sketch/SketchRenderer.kt
  • mpp-ui/src/iosMain/kotlin/cc/unitmesh/devins/ui/compose/agent/artifact/ArtifactPreviewPanel.ios.kt
  • mpp-ui/src/jsMain/kotlin/cc/unitmesh/devins/ui/compose/agent/artifact/ArtifactPreviewPanel.js.kt
  • mpp-ui/src/jvmMain/kotlin/cc/unitmesh/devins/ui/Main.kt
  • mpp-ui/src/jvmMain/kotlin/cc/unitmesh/devins/ui/compose/agent/artifact/ArtifactPreviewPanel.jvm.kt
  • mpp-ui/src/jvmMain/kotlin/cc/unitmesh/devins/ui/desktop/AutoDevMenuBar.kt
  • mpp-ui/src/jvmMain/kotlin/cc/unitmesh/devins/ui/desktop/Keymap.kt
  • mpp-ui/src/wasmJsMain/kotlin/cc/unitmesh/devins/ui/compose/agent/artifact/ArtifactPreviewPanel.wasmJs.kt

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@phodal phodal merged commit e195a23 into master Dec 25, 2025
6 of 7 checks passed
@augmentcode
Copy link

augmentcode bot commented Dec 25, 2025

🤖 Augment PR Summary

Summary: Adds a cross-platform artifact “.unit” execution framework so AutoDev can package and run interactive outputs (Node.js, Python, and Web).

Changes:

  • Introduced a Node.js artifact type and expanded artifact-generation guidance (EN/ZH) for Node.js code-only artifacts.
  • Enhanced ArtifactBundle to support Node.js bundles (index.js), dependency auto-detection, and safer file merging.
  • Added JVM-side executor architecture (ArtifactExecutor interface + factory) with concrete Node.js/Python/Web executors.
  • Implemented long-running process support via ProcessManager (start/stop and process tracking).
  • Updated UI to support Node.js execution output, server start/stop controls, and an “auto-fix” flow on execution errors.
  • Adjusted desktop file association for .unit files to use ZIP MIME/UTI semantics and added “Open Unit Bundle…” menu action.
  • Added unit tests for Node.js bundling, packing/extraction, and dependency detection behavior.

Technical Notes: Uses Kotlin Multiplatform expect/actual for preview panels; introduces streaming throttling in Sketch rendering to reduce recompositions during LLM streaming.

🤖 Was this summary useful? React with 👍 or 👎

Copy link

@augmentcode augmentcode bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 5 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

.start()

// Read output in background
coroutineScope {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

coroutineScope { launch { … } } waits for the launched reader to complete, so startHttpServer() will suspend until the server process exits and execute() will effectively hang. Consider launching output reading in a scope that doesn’t block returning the Process.

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎

// Verify package.json content
val packageEntry = entries.find { it.name == "package.json" }!!
val packageContent = zip.getInputStream(packageEntry).bufferedReader().readText()
assertTrue(packageContent.contains("\"type\": \"module\""), "package.json should have module type")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test asserts "type": "module" in package.json, but ArtifactBundle.generatePackageJson() explicitly avoids setting type: module for NODEJS, so this will fail (also applies to the similar assertion later in this file).

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎

// Match require('package') or require("package")
val requirePattern = Regex("""require\s*\(\s*['"]([^'"./][^'"]*)['"]\s*\)""")
requirePattern.findAll(content).forEach { match ->
val packageName = match.groupValues[1].split("/").first()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dependency detection uses split("/").first(), which will mis-handle scoped packages like @scope/pkg by turning them into @scope (invalid). This seems likely to generate incorrect package.json dependencies for many modern npm packages.

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎

.redirectErrorStream(true)

val process = processBuilder.start()
val outputBuilder = StringBuilder()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

outputBuilder is appended from outputJob while also being read to produce the returned string, but StringBuilder isn’t thread-safe—this is a data race on Dispatchers.IO (Guideline: thread_safety).

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎

logger.info("ArtifactExecutorFactory") { "🚀 Executing artifact from: $unitFilePath" }

// Step 1: Extract .unit file
val tempDir = Files.createTempDirectory("autodev-artifact-${UUID.randomUUID()}")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

executeArtifact() creates a temp extraction directory but never cleans it up, so repeated executions can leak disk space unless something else removes it later (Guideline: no_memory_leaks).

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a comprehensive artifact execution framework that enables AutoDev to create, package, and execute interactive artifacts across multiple platforms (Node.js, Python, Web). The implementation includes sophisticated features like dependency detection, process management, and auto-fix capabilities.

Key Changes

  • Adds artifact executors for Node.js, Python, and Web artifacts with platform-specific execution logic
  • Implements automatic dependency detection from require/import statements for Node.js artifacts
  • Introduces ProcessManager for managing long-running processes (e.g., Express.js servers)
  • Adds AI-powered auto-fix functionality for failed artifact executions
  • Implements streaming optimization with throttled content updates to reduce UI flickering
  • Registers .unit file type with proper MIME type associations

Reviewed changes

Copilot reviewed 26 out of 26 changed files in this pull request and generated 19 comments.

Show a summary per file
File Description
ArtifactExecutor.kt Base interface defining contract for artifact executors with validation and execution methods
NodeJsArtifactExecutor.kt Executes Node.js artifacts with npm dependency management and server process handling
PythonArtifactExecutor.kt Executes Python artifacts with PEP 723 metadata parsing and pip dependency installation
WebArtifactExecutor.kt Executes web artifacts by starting local HTTP servers with Python or Node.js
ProcessManager.kt Manages long-running processes with start/stop controls and output streaming
ArtifactExecutorFactory.kt Factory pattern implementation for selecting appropriate executors based on artifact type
ArtifactBundle.kt Enhanced with auto-dependency detection, selectBestArtifact logic, and Node.js support
ArtifactBundlePacker.kt Updated to include index.js mapping for Node.js artifacts
ArtifactAgent.kt Added fix() method for AI-powered error correction of failed artifacts
ArtifactAgentTemplate.kt Extended with Node.js guidelines and templates for artifact generation
ArtifactPreviewPanel.jvm.kt Desktop implementation with Node.js execution UI, play/stop controls, and error handling
ArtifactPreviewPanel (other platforms) Updated signatures to support onFixRequest callback across all platforms
ArtifactPage.kt Integrated fix request functionality into artifact workflow
ArtifactAgentViewModel.kt Added fixArtifact method with streaming support and best artifact selection
SketchRenderer.kt Implemented throttled content rendering to reduce recomposition frequency during streaming
NodeJsArtifactBundleTest.kt Comprehensive tests for Node.js bundle creation, roundtrip, and validation
ArtifactExecutorTest.kt Tests for artifact execution, extraction, and dependency detection
GenerateTestUnit.kt Extended utility to generate test Express.js applications
build.gradle.kts Changed MIME type from custom to application/zip for better OS integration
Main.kt Added openUnitBundle functionality with file chooser integration
AutoDevMenuBar.kt Added "Open Unit Bundle" menu item
Keymap.kt Added keyboard shortcut (Cmd/Ctrl+Shift+U) for opening unit bundles

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +682 to +683
val tempUnitFile = File.createTempFile("artifact-${artifact.identifier}", ".unit")
// Note: Don't deleteOnExit for server processes - they need the files
Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The temp file created with File.createTempFile is not cleaned up. Since the comment explicitly says "Don't deleteOnExit for server processes - they need the files", this could lead to disk space issues over time as temp files accumulate. Consider implementing a cleanup strategy for stopped processes or exposing cleanup options to the user.

Copilot uses AI. Check for mistakes.
Comment on lines +139 to +143
val importPattern = Regex("""import\s+.*?\s+from\s+['"]([^'"./][^'"]*)['"]\s*;?""")
importPattern.findAll(content).forEach { match ->
val packageName = match.groupValues[1].split("/").first()
dependencies.add(packageName)
}
Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regular expression pattern for detecting imports doesn't handle all valid ES6 import syntaxes. For example, it won't match "import * as express from 'express'" or "import {createServer} from 'http'". Consider using a more comprehensive pattern or multiple patterns to cover all import variations.

Copilot uses AI. Check for mistakes.
Comment on lines +80 to +112
val expressAppCode = """
import express from 'express';
const app = express();
const PORT = process.env.PORT || 3000;
app.use(express.json());
app.get('/', (req, res) => {
res.json({
message: 'Hello from Express.js!',
timestamp: new Date().toISOString(),
version: '1.0.0'
});
});
app.get('/api/health', (req, res) => {
res.json({ status: 'ok', uptime: process.uptime() });
});
app.post('/api/echo', (req, res) => {
res.json({
received: req.body,
timestamp: new Date().toISOString()
});
});
app.listen(PORT, () => {
console.log(`🚀 Express.js server running on http://localhost:${'$'}{PORT}`);
console.log(`📡 Health check: http://localhost:${'$'}{PORT}/api/health`);
console.log(`📝 Echo endpoint: POST http://localhost:${'$'}{PORT}/api/echo`);
});
""".trimIndent()
Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Express.js demo code uses ES6 import syntax which requires "type": "module" in package.json or .mjs file extension to work in Node.js. Without this configuration, the code will fail with "SyntaxError: Cannot use import statement outside a module". Either add "type": "module" to the bundle generation or use CommonJS require() syntax.

Copilot uses AI. Check for mistakes.
Comment on lines +225 to +228
val codeArtifact = nodeJsArtifacts.find { artifact ->
val content = artifact.content.trim()
// Skip if it's clearly JSON (package.json)
!(content.startsWith("{") && content.contains("\"name\"") && content.contains("\"dependencies\""))
Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The detection of package.json content is too simplistic. The pattern checks if content starts with "{" and contains "name", which could incorrectly match legitimate JavaScript objects or JSON configurations. Consider using a more robust check, such as attempting to parse as JSON and checking for specific package.json fields like "dependencies" or "version" in addition to "name".

Copilot uses AI. Check for mistakes.
Comment on lines +259 to +274
private suspend fun openUnitBundleFile(uiState: DesktopUiState) {
try {
val fileChooser = createFileChooser()
val selectedPath = fileChooser.chooseFile(
title = "Open Unit Bundle",
fileExtensions = listOf("unit")
)

selectedPath?.let { path ->
AutoDevLogger.info("AutoDevMain") { "📦 Opening Unit Bundle: $path" }

// Switch to Artifact mode
uiState.updateAgentType(AgentType.ARTIFACT)

// Load the bundle
val success = withContext(Dispatchers.IO) {
Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The withContext(Dispatchers.IO) block calls File operations but doesn't handle the case where the context file doesn't exist or is malformed. The null return at the end silently swallows all exceptions. Consider logging warnings for specific failure cases (file not found, parse error, etc.) to aid debugging.

Copilot uses AI. Check for mistakes.
Comment on lines +30 to +74
content = """
import express from 'express';
const app = express();
app.get('/', (req, res) => res.json({ message: 'Hello' }));
app.listen(3000, () => console.log('Server running'));
""".trimIndent()
)

val bundle = ArtifactBundle.fromArtifact(
artifact = artifact,
conversationHistory = emptyList(),
modelInfo = null
).copy(
dependencies = mapOf("express" to "^4.18.2")
)

val outputFile = File(tempDir, "express-app.unit")
val packer = ArtifactBundlePacker()
val result = packer.pack(bundle, outputFile.absolutePath)

assertTrue(result is PackResult.Success, "Pack should succeed")

// Verify ZIP contents
ZipFile(outputFile).use { zip ->
val entries = zip.entries().toList()
val entryNames = entries.map { it.name }

// Should contain all required files
assertTrue(entryNames.contains("index.js"), "Should contain index.js")
assertTrue(entryNames.contains("package.json"), "Should contain package.json")
assertTrue(entryNames.contains("ARTIFACT.md"), "Should contain ARTIFACT.md")
assertTrue(entryNames.contains(".artifact/context.json"), "Should contain context.json")

// Verify index.js content
val indexEntry = entries.find { it.name == "index.js" }!!
val indexContent = zip.getInputStream(indexEntry).bufferedReader().readText()
assertTrue(indexContent.contains("express"), "index.js should contain express import")
assertTrue(indexContent.contains("app.listen"), "index.js should contain app.listen")

// Verify package.json content
val packageEntry = entries.find { it.name == "package.json" }!!
val packageContent = zip.getInputStream(packageEntry).bufferedReader().readText()
assertTrue(packageContent.contains("\"type\": \"module\""), "package.json should have module type")
assertTrue(packageContent.contains("\"express\""), "package.json should contain express dependency")
assertTrue(packageContent.contains("\"start\": \"node index.js\""), "package.json should have start script")
Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test uses ES6 import syntax but the package.json doesn't include "type": "module", which will cause the Node.js code to fail at runtime. Either add "type": "module" to the generated package.json or use CommonJS require() syntax in the test.

Copilot uses AI. Check for mistakes.
Comment on lines +77 to +90
val outputJob = CoroutineScope(Dispatchers.IO).launch {
try {
process.inputStream.bufferedReader().use { reader ->
reader.lineSequence().forEach { line ->
outputBuilder.appendLine(line)
onOutput?.invoke("$line\n")
}
}
} catch (e: Exception) {
if (e !is CancellationException) {
logger.warn("ProcessManager") { "Output reading error: ${e.message}" }
}
}
}
Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The process output job is launched in a new CoroutineScope without lifecycle management. If the parent coroutine is cancelled, this job will continue running and potentially leak resources. Consider using the parent scope or passing a scope parameter to ensure proper cancellation propagation.

Copilot uses AI. Check for mistakes.
Comment on lines +97 to +105
*/
private fun findAvailablePort(startPort: Int = 8000): Int {
for (port in startPort..9000) {
try {
ServerSocket(port).use { socket ->
return socket.localPort
}
} catch (e: Exception) {
// Port is in use, try next
Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ServerSocket is used only to find an available port but is closed immediately after creation. This creates a race condition where another process could grab the port before the HTTP server starts. Consider keeping the socket open and passing it to the HTTP server, or use a retry mechanism if port binding fails.

Suggested change
*/
private fun findAvailablePort(startPort: Int = 8000): Int {
for (port in startPort..9000) {
try {
ServerSocket(port).use { socket ->
return socket.localPort
}
} catch (e: Exception) {
// Port is in use, try next
*
* Uses an ephemeral port (0) and verifies that it falls within the desired range.
*/
private fun findAvailablePort(startPort: Int = 8000): Int {
ServerSocket(0).use { socket ->
val port = socket.localPort
if (port in startPort..9000) {
return port

Copilot uses AI. Check for mistakes.
Comment on lines +199 to +201
return dependencies
.filter { it !in builtInModules && !it.startsWith("node:") }
.associateWith { packageVersions[it] ?: "latest" }
Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dependency detection excludes packages starting with "node:" but doesn't filter them from the builtInModules set before checking. This means "node:fs" would be excluded but "fs" might not be if it somehow wasn't in the builtInModules set. Consider normalizing the package name by removing the "node:" prefix before filtering against builtInModules.

Copilot uses AI. Check for mistakes.
Comment on lines +425 to +427
files.filterKeys { key -> key !in coreFileNames }.forEach { (key, value) ->
put(key, value)
}
Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code filters core file names to prevent conflicts, but uses a simple set check. If additional files contain paths with subdirectories (e.g., ".artifact/context.json"), the filtering won't work correctly since CONTEXT_JSON is defined as ".artifact/context.json" but files map keys might not match exactly. Consider normalizing paths before comparison.

Suggested change
files.filterKeys { key -> key !in coreFileNames }.forEach { (key, value) ->
put(key, value)
}
// Normalize paths to improve conflict detection (e.g., "subdir/.artifact/context.json")
fun String.normalizePathForComparison(): String =
this.replace('\\', '/').removePrefix("./")
fun conflictsWithCore(key: String): Boolean {
val normalizedKey = key.normalizePathForComparison()
return coreFileNames.any { core ->
val normalizedCore = core.normalizePathForComparison()
normalizedKey == normalizedCore || normalizedKey.endsWith("/$normalizedCore")
}
}
files.forEach { (key, value) ->
if (!conflictsWithCore(key)) {
put(key, value)
}
}

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AutoDev Unit - the Artifact builder

2 participants