@novastorm-ai/cli 0.1.3 → 0.1.6
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/dist/bin/nova.js +3 -3
- package/dist/{chunk-7K55GHF5.js → chunk-3FVS3SB3.js} +80 -36
- package/dist/{chunk-DQXTUNZA.js → chunk-53K63TXF.js} +1 -1
- package/dist/{chunk-HVDG2MLB.js → chunk-7ZE7J73C.js} +200 -59
- package/dist/{dist-NNJKY4T4.js → dist-NVKTAKZX.js} +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.js +3 -3
- package/dist/{package-BSAVJZ7S.js → package-4UBQQT6Y.js} +1 -1
- package/dist/{setup-VJMYSGJI.js → setup-33G3DXAH.js} +2 -2
- package/package.json +3 -3
package/dist/bin/nova.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
run
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-7ZE7J73C.js";
|
|
5
5
|
import "../chunk-KE7XWO5N.js";
|
|
6
|
-
import "../chunk-
|
|
7
|
-
import "../chunk-
|
|
6
|
+
import "../chunk-53K63TXF.js";
|
|
7
|
+
import "../chunk-3FVS3SB3.js";
|
|
8
8
|
import "../chunk-3RG5ZIWI.js";
|
|
9
9
|
|
|
10
10
|
// bin/nova.ts
|
|
@@ -2007,7 +2007,12 @@ var FRAMEWORK_DEPS = [
|
|
|
2007
2007
|
{ dep: "@sveltejs/kit", framework: "sveltekit" },
|
|
2008
2008
|
{ dep: "astro", framework: "astro" },
|
|
2009
2009
|
{ dep: "vite", framework: "vite" },
|
|
2010
|
-
{ dep: "react-scripts", framework: "cra" }
|
|
2010
|
+
{ dep: "react-scripts", framework: "cra" },
|
|
2011
|
+
{ dep: "express", framework: "express" },
|
|
2012
|
+
{ dep: "@nestjs/core", framework: "nest" },
|
|
2013
|
+
{ dep: "fastify", framework: "fastify" },
|
|
2014
|
+
{ dep: "koa", framework: "koa" },
|
|
2015
|
+
{ dep: "@hapi/hapi", framework: "hapi" }
|
|
2011
2016
|
];
|
|
2012
2017
|
var PYTHON_FRAMEWORKS = [
|
|
2013
2018
|
{ dep: "django", framework: "django" },
|
|
@@ -2021,6 +2026,12 @@ var DEFAULT_PORTS = {
|
|
|
2021
2026
|
"sveltekit": 5173,
|
|
2022
2027
|
"astro": 4321,
|
|
2023
2028
|
"vite": 5173,
|
|
2029
|
+
"express": 3e3,
|
|
2030
|
+
"nest": 3e3,
|
|
2031
|
+
"fastify": 3e3,
|
|
2032
|
+
"koa": 3e3,
|
|
2033
|
+
"hapi": 3e3,
|
|
2034
|
+
"node": 3e3,
|
|
2024
2035
|
"dotnet": 5e3,
|
|
2025
2036
|
"django": 8e3,
|
|
2026
2037
|
"fastapi": 8e3,
|
|
@@ -2036,37 +2047,70 @@ var DEFAULT_PORTS = {
|
|
|
2036
2047
|
};
|
|
2037
2048
|
var StackDetector = class {
|
|
2038
2049
|
async detectStack(projectPath) {
|
|
2039
|
-
const
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2050
|
+
const detected = [];
|
|
2051
|
+
const [pkgResult, hasDotnet, pythonFw, rubyFw, phpFw, javaFw, hasGo, hasRust] = await Promise.all([
|
|
2052
|
+
this.detectFromPackageJson(projectPath),
|
|
2053
|
+
this.hasDotnet(projectPath),
|
|
2054
|
+
this.detectPython(projectPath),
|
|
2055
|
+
this.detectRuby(projectPath),
|
|
2056
|
+
this.detectPhp(projectPath),
|
|
2057
|
+
this.detectJava(projectPath),
|
|
2058
|
+
this.fileExists(join9(projectPath, "go.mod")),
|
|
2059
|
+
this.fileExists(join9(projectPath, "Cargo.toml"))
|
|
2060
|
+
]);
|
|
2061
|
+
if (pkgResult) detected.push(pkgResult);
|
|
2062
|
+
if (hasDotnet) {
|
|
2044
2063
|
const typescript = await this.hasTypescript(projectPath);
|
|
2045
|
-
|
|
2046
|
-
}
|
|
2047
|
-
|
|
2048
|
-
if (
|
|
2049
|
-
|
|
2050
|
-
}
|
|
2051
|
-
|
|
2052
|
-
if (
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2064
|
+
detected.push({ framework: "dotnet", language: "csharp", typescript });
|
|
2065
|
+
}
|
|
2066
|
+
if (pythonFw) detected.push({ framework: pythonFw, language: "python", typescript: false });
|
|
2067
|
+
if (rubyFw) detected.push({ framework: rubyFw, language: "ruby", typescript: false });
|
|
2068
|
+
if (phpFw) detected.push({ framework: phpFw, language: "php", typescript: false });
|
|
2069
|
+
if (javaFw) detected.push({ framework: javaFw, language: "java", typescript: false });
|
|
2070
|
+
if (hasGo) detected.push({ framework: "go", language: "go", typescript: false });
|
|
2071
|
+
if (hasRust) detected.push({ framework: "rust", language: "rust", typescript: false });
|
|
2072
|
+
if (detected.length === 0) {
|
|
2073
|
+
return { framework: "unknown", language: "unknown", typescript: false };
|
|
2074
|
+
}
|
|
2075
|
+
const PRIORITY = [
|
|
2076
|
+
"next.js",
|
|
2077
|
+
"nuxt",
|
|
2078
|
+
"sveltekit",
|
|
2079
|
+
"astro",
|
|
2080
|
+
"vite",
|
|
2081
|
+
"cra",
|
|
2082
|
+
"dotnet",
|
|
2083
|
+
"django",
|
|
2084
|
+
"fastapi",
|
|
2085
|
+
"flask",
|
|
2086
|
+
"rails",
|
|
2087
|
+
"sinatra",
|
|
2088
|
+
"laravel",
|
|
2089
|
+
"symfony",
|
|
2090
|
+
"spring-boot",
|
|
2091
|
+
"express",
|
|
2092
|
+
"nest",
|
|
2093
|
+
"fastify",
|
|
2094
|
+
"koa",
|
|
2095
|
+
"hapi",
|
|
2096
|
+
"node",
|
|
2097
|
+
"python",
|
|
2098
|
+
"ruby",
|
|
2099
|
+
"php",
|
|
2100
|
+
"java",
|
|
2101
|
+
"go",
|
|
2102
|
+
"rust"
|
|
2103
|
+
];
|
|
2104
|
+
detected.sort((a, b) => {
|
|
2105
|
+
const ai = PRIORITY.indexOf(a.framework);
|
|
2106
|
+
const bi = PRIORITY.indexOf(b.framework);
|
|
2107
|
+
return (ai === -1 ? 999 : ai) - (bi === -1 ? 999 : bi);
|
|
2108
|
+
});
|
|
2109
|
+
const primary = detected[0];
|
|
2110
|
+
if (detected.length > 1) {
|
|
2111
|
+
primary.additionalStacks = detected.slice(1).map((s) => s.framework);
|
|
2068
2112
|
}
|
|
2069
|
-
return
|
|
2113
|
+
return primary;
|
|
2070
2114
|
}
|
|
2071
2115
|
async detectDevCommand(stack, projectPath) {
|
|
2072
2116
|
const { framework, language, packageManager } = stack;
|
|
@@ -2113,20 +2157,19 @@ var StackDetector = class {
|
|
|
2113
2157
|
...pkg.devDependencies
|
|
2114
2158
|
};
|
|
2115
2159
|
const framework = FRAMEWORK_DEPS.find((f) => f.dep in allDeps);
|
|
2116
|
-
if (!framework) return null;
|
|
2117
2160
|
const typescript = await this.hasTypescript(projectPath);
|
|
2118
2161
|
const packageManager = await this.detectPackageManager(projectPath);
|
|
2119
2162
|
return {
|
|
2120
|
-
framework: framework
|
|
2163
|
+
framework: framework?.framework ?? "node",
|
|
2121
2164
|
language: typescript ? "typescript" : "javascript",
|
|
2122
2165
|
packageManager,
|
|
2123
2166
|
typescript
|
|
2124
2167
|
};
|
|
2125
2168
|
}
|
|
2126
|
-
async
|
|
2169
|
+
async hasDotnet(projectPath) {
|
|
2127
2170
|
try {
|
|
2128
2171
|
const entries = await readdir3(projectPath);
|
|
2129
|
-
return entries.some((e) => e.endsWith(".csproj"));
|
|
2172
|
+
return entries.some((e) => e.endsWith(".csproj") || e.endsWith(".sln"));
|
|
2130
2173
|
} catch {
|
|
2131
2174
|
return false;
|
|
2132
2175
|
}
|
|
@@ -6201,7 +6244,7 @@ Available packages: ${deps}`);
|
|
|
6201
6244
|
return parts.join("\n");
|
|
6202
6245
|
}
|
|
6203
6246
|
var Lane3Executor = class {
|
|
6204
|
-
constructor(projectPath, llmClient, gitManager, eventBus, maxFixIterations = 3, modelName, agentPromptLoader, pathGuard, commitQueue) {
|
|
6247
|
+
constructor(projectPath, llmClient, gitManager, eventBus, maxFixIterations = 3, modelName, agentPromptLoader, pathGuard, commitQueue, forceSkipValidation = false) {
|
|
6205
6248
|
this.projectPath = projectPath;
|
|
6206
6249
|
this.llmClient = llmClient;
|
|
6207
6250
|
this.gitManager = gitManager;
|
|
@@ -6210,6 +6253,7 @@ var Lane3Executor = class {
|
|
|
6210
6253
|
this.modelName = modelName;
|
|
6211
6254
|
this.agentPromptLoader = agentPromptLoader;
|
|
6212
6255
|
this.pathGuard = pathGuard;
|
|
6256
|
+
this.forceSkipValidation = forceSkipValidation;
|
|
6213
6257
|
this.diffApplier = new DiffApplier();
|
|
6214
6258
|
this.commitQueue = commitQueue ?? new CommitQueue(this.gitManager);
|
|
6215
6259
|
}
|
|
@@ -6317,7 +6361,7 @@ Remember: Output ONLY === FILE === or === DIFF === blocks. No text, no explanati
|
|
|
6317
6361
|
if (missingVars.length > 0 && this.eventBus) {
|
|
6318
6362
|
this.eventBus.emit({ type: "secrets_required", data: { envVars: missingVars, taskId: task.id } });
|
|
6319
6363
|
}
|
|
6320
|
-
const skipValidation = fileBlocks.length === 1 && fileBlocks[0].content.length < 3e3;
|
|
6364
|
+
const skipValidation = this.forceSkipValidation || fileBlocks.length === 1 && fileBlocks[0].content.length < 3e3;
|
|
6321
6365
|
const tscSkip = this.shouldSkipTsc(fileBlocks);
|
|
6322
6366
|
const validator = new CodeValidator(this.projectPath);
|
|
6323
6367
|
const fixer = new CodeFixer(this.llmClient, this.eventBus);
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
import {
|
|
7
7
|
ConfigReader,
|
|
8
8
|
runSetup
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-53K63TXF.js";
|
|
10
10
|
import {
|
|
11
11
|
AgentPromptLoader,
|
|
12
12
|
Brain,
|
|
@@ -25,8 +25,9 @@ import {
|
|
|
25
25
|
ProjectIndexer,
|
|
26
26
|
ProjectScaffolder,
|
|
27
27
|
ProviderFactory,
|
|
28
|
-
SCAFFOLD_PRESETS
|
|
29
|
-
|
|
28
|
+
SCAFFOLD_PRESETS,
|
|
29
|
+
StackDetector
|
|
30
|
+
} from "./chunk-3FVS3SB3.js";
|
|
30
31
|
import {
|
|
31
32
|
__require
|
|
32
33
|
} from "./chunk-3RG5ZIWI.js";
|
|
@@ -39,11 +40,15 @@ import { Command } from "commander";
|
|
|
39
40
|
|
|
40
41
|
// src/commands/start.ts
|
|
41
42
|
import { exec } from "child_process";
|
|
43
|
+
import { existsSync, readdirSync } from "fs";
|
|
44
|
+
import { writeFile as writeFile2 } from "fs/promises";
|
|
42
45
|
import * as net from "net";
|
|
43
46
|
import * as path from "path";
|
|
44
47
|
import chalk6 from "chalk";
|
|
45
48
|
import ora2 from "ora";
|
|
46
|
-
import { resolve as resolve2 } from "path";
|
|
49
|
+
import { resolve as resolve2, join as join2 } from "path";
|
|
50
|
+
import { input as input2 } from "@inquirer/prompts";
|
|
51
|
+
import TOML from "@iarna/toml";
|
|
47
52
|
|
|
48
53
|
// ../licensing/dist/index.js
|
|
49
54
|
import { createHash } from "crypto";
|
|
@@ -507,6 +512,10 @@ var ErrorAutoFixer = class {
|
|
|
507
512
|
MAX_FIX_ATTEMPTS = 3;
|
|
508
513
|
lastErrorSignature = "";
|
|
509
514
|
cooldownUntil = 0;
|
|
515
|
+
autofixTaskIds = /* @__PURE__ */ new Set();
|
|
516
|
+
isAutofixTask(taskId) {
|
|
517
|
+
return this.autofixTaskIds.has(taskId);
|
|
518
|
+
}
|
|
510
519
|
/**
|
|
511
520
|
* Process dev server output. Call this for every stdout/stderr chunk.
|
|
512
521
|
*/
|
|
@@ -603,6 +612,7 @@ Error: ${errorOutput.slice(0, 300)}`;
|
|
|
603
612
|
lane: 3,
|
|
604
613
|
status: "pending"
|
|
605
614
|
};
|
|
615
|
+
this.autofixTaskIds.add(task.id);
|
|
606
616
|
const executor = new Lane3Executor(
|
|
607
617
|
this.projectPath,
|
|
608
618
|
this.llmClient,
|
|
@@ -616,13 +626,16 @@ Error: ${errorOutput.slice(0, 300)}`;
|
|
|
616
626
|
// agentPromptLoader
|
|
617
627
|
void 0,
|
|
618
628
|
// pathGuard
|
|
619
|
-
this.commitQueue
|
|
629
|
+
this.commitQueue,
|
|
630
|
+
true
|
|
631
|
+
// skipValidation — auto-fix tasks skip tsc
|
|
620
632
|
);
|
|
621
633
|
console.log(chalk3.cyan("[Nova] Auto-fixing image errors..."));
|
|
622
634
|
this.wsServer.sendEvent({ type: "status", data: { message: "autofix_start" } });
|
|
623
635
|
this.eventBus.emit({ type: "task_started", data: { taskId: task.id } });
|
|
624
636
|
this.wsServer.sendEvent({ type: "task_created", data: task });
|
|
625
637
|
const result = await executor.execute(task, this.projectMap);
|
|
638
|
+
this.autofixTaskIds.delete(task.id);
|
|
626
639
|
if (result.success) {
|
|
627
640
|
console.log(chalk3.green("[Nova] Image errors fixed automatically"));
|
|
628
641
|
this.eventBus.emit({
|
|
@@ -639,7 +652,6 @@ Error: ${errorOutput.slice(0, 300)}`;
|
|
|
639
652
|
}
|
|
640
653
|
}
|
|
641
654
|
async fixCompilationError(errorOutput) {
|
|
642
|
-
const truncatedError = errorOutput.slice(0, 500);
|
|
643
655
|
console.log(
|
|
644
656
|
chalk3.yellow("[Nova] Detected compilation error \u2014 attempting auto-fix")
|
|
645
657
|
);
|
|
@@ -647,6 +659,56 @@ Error: ${errorOutput.slice(0, 300)}`;
|
|
|
647
659
|
type: "status",
|
|
648
660
|
data: { message: "Compilation error detected. Auto-fixing..." }
|
|
649
661
|
});
|
|
662
|
+
const targetFile = this.extractFilePath(errorOutput);
|
|
663
|
+
if (targetFile && this.projectMap.fileContexts.has(targetFile)) {
|
|
664
|
+
await this.fixWithLane2(targetFile, errorOutput);
|
|
665
|
+
} else {
|
|
666
|
+
await this.fixWithLane3(errorOutput);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
async fixWithLane2(targetFile, errorOutput) {
|
|
670
|
+
const truncatedError = errorOutput.slice(0, 500);
|
|
671
|
+
const task = {
|
|
672
|
+
id: crypto.randomUUID(),
|
|
673
|
+
description: `Fix the following compilation/build error in the project. Read the error carefully and fix the root cause:
|
|
674
|
+
${truncatedError}`,
|
|
675
|
+
files: [targetFile],
|
|
676
|
+
type: "single_file",
|
|
677
|
+
lane: 2,
|
|
678
|
+
status: "pending"
|
|
679
|
+
};
|
|
680
|
+
this.autofixTaskIds.add(task.id);
|
|
681
|
+
const executor = new Lane2Executor(
|
|
682
|
+
this.projectPath,
|
|
683
|
+
this.llmClient,
|
|
684
|
+
this.gitManager,
|
|
685
|
+
void 0,
|
|
686
|
+
// pathGuard
|
|
687
|
+
this.commitQueue
|
|
688
|
+
);
|
|
689
|
+
console.log(chalk3.cyan(`[Nova] Auto-fixing compilation error via Lane 2 (${targetFile})...`));
|
|
690
|
+
this.wsServer.sendEvent({ type: "status", data: { message: "autofix_start" } });
|
|
691
|
+
this.eventBus.emit({ type: "task_started", data: { taskId: task.id } });
|
|
692
|
+
this.wsServer.sendEvent({ type: "task_created", data: task });
|
|
693
|
+
const result = await executor.execute(task, this.projectMap);
|
|
694
|
+
this.autofixTaskIds.delete(task.id);
|
|
695
|
+
if (result.success) {
|
|
696
|
+
console.log(chalk3.green("[Nova] Compilation error fixed automatically (Lane 2)"));
|
|
697
|
+
this.eventBus.emit({
|
|
698
|
+
type: "task_completed",
|
|
699
|
+
data: { taskId: task.id, diff: result.diff ?? "", commitHash: result.commitHash ?? "" }
|
|
700
|
+
});
|
|
701
|
+
this.wsServer.sendEvent({ type: "status", data: { message: "autofix_end" } });
|
|
702
|
+
} else {
|
|
703
|
+
console.log(chalk3.red(`[Nova] Auto-fix failed: ${result.error}`));
|
|
704
|
+
const failEvent = { type: "task_failed", data: { taskId: task.id, error: result.error ?? "Auto-fix failed" } };
|
|
705
|
+
this.eventBus.emit(failEvent);
|
|
706
|
+
this.wsServer.sendEvent(failEvent);
|
|
707
|
+
this.wsServer.sendEvent({ type: "status", data: { message: "autofix_failed" } });
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
async fixWithLane3(errorOutput) {
|
|
711
|
+
const truncatedError = errorOutput.slice(0, 500);
|
|
650
712
|
const task = {
|
|
651
713
|
id: crypto.randomUUID(),
|
|
652
714
|
description: `Fix the following compilation/build error in the project. Read the error carefully and fix the root cause:
|
|
@@ -656,6 +718,7 @@ ${truncatedError}`,
|
|
|
656
718
|
lane: 3,
|
|
657
719
|
status: "pending"
|
|
658
720
|
};
|
|
721
|
+
this.autofixTaskIds.add(task.id);
|
|
659
722
|
const executor = new Lane3Executor(
|
|
660
723
|
this.projectPath,
|
|
661
724
|
this.llmClient,
|
|
@@ -669,13 +732,16 @@ ${truncatedError}`,
|
|
|
669
732
|
// agentPromptLoader
|
|
670
733
|
void 0,
|
|
671
734
|
// pathGuard
|
|
672
|
-
this.commitQueue
|
|
735
|
+
this.commitQueue,
|
|
736
|
+
true
|
|
737
|
+
// skipValidation — auto-fix tasks skip tsc
|
|
673
738
|
);
|
|
674
739
|
console.log(chalk3.cyan("[Nova] Auto-fixing compilation error..."));
|
|
675
740
|
this.wsServer.sendEvent({ type: "status", data: { message: "autofix_start" } });
|
|
676
741
|
this.eventBus.emit({ type: "task_started", data: { taskId: task.id } });
|
|
677
742
|
this.wsServer.sendEvent({ type: "task_created", data: task });
|
|
678
743
|
const result = await executor.execute(task, this.projectMap);
|
|
744
|
+
this.autofixTaskIds.delete(task.id);
|
|
679
745
|
if (result.success) {
|
|
680
746
|
console.log(chalk3.green("[Nova] Compilation error fixed automatically"));
|
|
681
747
|
this.eventBus.emit({
|
|
@@ -691,6 +757,21 @@ ${truncatedError}`,
|
|
|
691
757
|
this.wsServer.sendEvent({ type: "status", data: { message: "autofix_failed" } });
|
|
692
758
|
}
|
|
693
759
|
}
|
|
760
|
+
extractFilePath(errorOutput) {
|
|
761
|
+
const patterns = [
|
|
762
|
+
/\.\/([^\s:]+\.[tj]sx?)/,
|
|
763
|
+
// ./path/to/file.tsx
|
|
764
|
+
/(?:in|at|from)\s+([^\s:]+\.[tj]sx?)/i,
|
|
765
|
+
// in path/to/file.tsx
|
|
766
|
+
/([^\s:]+\.[tj]sx?)[\s:]/
|
|
767
|
+
// path/to/file.tsx:line
|
|
768
|
+
];
|
|
769
|
+
for (const p of patterns) {
|
|
770
|
+
const match = errorOutput.match(p);
|
|
771
|
+
if (match) return match[1];
|
|
772
|
+
}
|
|
773
|
+
return null;
|
|
774
|
+
}
|
|
694
775
|
};
|
|
695
776
|
|
|
696
777
|
// src/chat.ts
|
|
@@ -753,11 +834,11 @@ var NovaChat = class {
|
|
|
753
834
|
this.rl?.close();
|
|
754
835
|
this.rl = null;
|
|
755
836
|
}
|
|
756
|
-
parse(
|
|
757
|
-
const lower =
|
|
837
|
+
parse(input3) {
|
|
838
|
+
const lower = input3.toLowerCase();
|
|
758
839
|
for (const [prefix, type] of Object.entries(SLASH_COMMANDS)) {
|
|
759
840
|
if (lower === prefix || lower.startsWith(prefix + " ")) {
|
|
760
|
-
const args =
|
|
841
|
+
const args = input3.slice(prefix.length).trim();
|
|
761
842
|
return { type, args };
|
|
762
843
|
}
|
|
763
844
|
}
|
|
@@ -767,7 +848,7 @@ var NovaChat = class {
|
|
|
767
848
|
if (lower === "n" || lower === "no" || lower === "cancel") {
|
|
768
849
|
return { type: "cancel", args: "" };
|
|
769
850
|
}
|
|
770
|
-
return { type: "text", args:
|
|
851
|
+
return { type: "text", args: input3 };
|
|
771
852
|
}
|
|
772
853
|
};
|
|
773
854
|
|
|
@@ -1002,7 +1083,7 @@ async function startCommand() {
|
|
|
1002
1083
|
projectHash = createHash2("sha256").update(cwd).digest("hex");
|
|
1003
1084
|
}
|
|
1004
1085
|
const telemetry = new Telemetry();
|
|
1005
|
-
const cliPkg = await import("./package-
|
|
1086
|
+
const cliPkg = await import("./package-4UBQQT6Y.js").catch(
|
|
1006
1087
|
() => ({ default: { version: "0.0.1" } })
|
|
1007
1088
|
);
|
|
1008
1089
|
telemetry.send({
|
|
@@ -1031,39 +1112,100 @@ ${nudgeMessage}
|
|
|
1031
1112
|
}).catch(() => {
|
|
1032
1113
|
});
|
|
1033
1114
|
}
|
|
1115
|
+
if (!config.apiKeys.key && config.apiKeys.provider !== "ollama" && config.apiKeys.provider !== "claude-cli") {
|
|
1116
|
+
console.log(chalk6.yellow("\nNo API key configured. Running setup...\n"));
|
|
1117
|
+
const { runSetup: runSetup2 } = await import("./setup-33G3DXAH.js");
|
|
1118
|
+
await runSetup2(cwd);
|
|
1119
|
+
const updatedConfig = await configReader.read(cwd);
|
|
1120
|
+
config.apiKeys = updatedConfig.apiKeys;
|
|
1121
|
+
}
|
|
1122
|
+
const providerFactory = new ProviderFactory();
|
|
1123
|
+
let llmClient;
|
|
1124
|
+
try {
|
|
1125
|
+
llmClient = providerFactory.create(config.apiKeys.provider, config.apiKeys.key);
|
|
1126
|
+
} catch (err) {
|
|
1127
|
+
console.log(chalk6.yellow("\nAI provider not configured. Nova is running without AI analysis."));
|
|
1128
|
+
console.log(chalk6.dim('Run "nova setup" to configure your API key.\n'));
|
|
1129
|
+
llmClient = null;
|
|
1130
|
+
}
|
|
1131
|
+
const brain = llmClient ? new Brain(llmClient, eventBus) : null;
|
|
1034
1132
|
spinner.start("Detecting project...");
|
|
1035
|
-
const { StackDetector } = await import("./dist-NNJKY4T4.js");
|
|
1036
1133
|
const stackDetector = new StackDetector();
|
|
1037
1134
|
let stack = await stackDetector.detectStack(cwd);
|
|
1038
1135
|
let detectedDevCommand = await stackDetector.detectDevCommand(stack, cwd);
|
|
1039
1136
|
let detectedPort = await stackDetector.detectPort(stack, cwd);
|
|
1040
|
-
|
|
1137
|
+
const allStacks = [stack.framework, ...stack.additionalStacks ?? []];
|
|
1138
|
+
const stackLabel = allStacks.filter((s) => s !== "unknown").join(" + ") || "unknown";
|
|
1139
|
+
const langLabel = stack.typescript ? "TypeScript" : stack.language || "unknown";
|
|
1140
|
+
spinner.succeed(`Detecting project... ${chalk6.cyan(stackLabel)} (${chalk6.dim(langLabel)})`);
|
|
1141
|
+
if (stack.framework !== "unknown") {
|
|
1142
|
+
console.log(chalk6.green(` Detected: ${stackLabel}`));
|
|
1143
|
+
} else {
|
|
1144
|
+
const dirFiles = readdirSync(cwd).slice(0, 10).join(", ");
|
|
1145
|
+
console.log(chalk6.yellow(` Could not detect framework. Files in directory: ${dirFiles}`));
|
|
1146
|
+
}
|
|
1041
1147
|
let devCommand = config.project.devCommand || detectedDevCommand;
|
|
1042
1148
|
let devPort = config.project.port || detectedPort;
|
|
1043
1149
|
if (!devCommand) {
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1150
|
+
const projectMarkers = ["package.json", "requirements.txt", "go.mod", "Cargo.toml", "pom.xml", "build.gradle", "composer.json", "Gemfile"];
|
|
1151
|
+
const hasProjectFiles = projectMarkers.some((f) => existsSync(join2(cwd, f))) || readdirSync(cwd).some((f) => f.endsWith(".sln") || f.endsWith(".csproj"));
|
|
1152
|
+
if (hasProjectFiles) {
|
|
1153
|
+
const defaultCmd = stack.framework === "dotnet" ? "dotnet run" : stack.framework === "django" ? "python manage.py runserver" : stack.framework === "fastapi" ? "uvicorn main:app --reload" : stack.framework === "flask" ? "flask run" : stack.framework === "rails" ? "bin/rails server" : stack.framework === "laravel" ? "php artisan serve" : stack.framework === "spring-boot" ? "./mvnw spring-boot:run" : existsSync(join2(cwd, "package.json")) ? "npm run dev" : "";
|
|
1154
|
+
const stackLabel2 = stack.framework !== "unknown" ? ` (${chalk6.cyan(stack.framework)} detected)` : "";
|
|
1155
|
+
let devCmd;
|
|
1156
|
+
try {
|
|
1157
|
+
devCmd = await input2({
|
|
1158
|
+
message: `Dev command not found${stackLabel2}. Enter your dev command:`,
|
|
1159
|
+
default: defaultCmd || void 0
|
|
1160
|
+
});
|
|
1161
|
+
} catch {
|
|
1162
|
+
console.log("\nCancelled.");
|
|
1163
|
+
process.exit(0);
|
|
1164
|
+
}
|
|
1165
|
+
if (devCmd && devCmd.trim()) {
|
|
1166
|
+
devCommand = devCmd.trim();
|
|
1167
|
+
try {
|
|
1168
|
+
const novaTomlPath = join2(cwd, "nova.toml");
|
|
1169
|
+
let tomlContent = {};
|
|
1170
|
+
if (existsSync(novaTomlPath)) {
|
|
1171
|
+
const { readFileSync: readFileSync2 } = await import("fs");
|
|
1172
|
+
tomlContent = TOML.parse(readFileSync2(novaTomlPath, "utf-8"));
|
|
1173
|
+
}
|
|
1174
|
+
const project = tomlContent["project"] ?? {};
|
|
1175
|
+
project["devCommand"] = devCommand;
|
|
1176
|
+
tomlContent["project"] = project;
|
|
1177
|
+
await writeFile2(novaTomlPath, TOML.stringify(tomlContent), "utf-8");
|
|
1178
|
+
console.log(chalk6.dim(`Saved devCommand to nova.toml`));
|
|
1179
|
+
} catch {
|
|
1180
|
+
}
|
|
1181
|
+
} else {
|
|
1182
|
+
console.error(chalk6.red('Dev command is required. Add [project] devCommand = "..." to nova.toml'));
|
|
1183
|
+
process.exit(1);
|
|
1184
|
+
}
|
|
1185
|
+
} else {
|
|
1186
|
+
if (novaDir.exists(cwd)) {
|
|
1187
|
+
await novaDir.clean(cwd);
|
|
1188
|
+
}
|
|
1189
|
+
const scaffoldInfo = await promptAndScaffold(cwd);
|
|
1190
|
+
if (!scaffoldInfo.scaffolded) {
|
|
1191
|
+
process.exit(0);
|
|
1192
|
+
}
|
|
1193
|
+
if (scaffoldInfo.frontend) config.project.frontend = scaffoldInfo.frontend;
|
|
1194
|
+
if (scaffoldInfo.backends) config.project.backends = scaffoldInfo.backends;
|
|
1195
|
+
spinner.start("Re-detecting project...");
|
|
1196
|
+
stack = await stackDetector.detectStack(cwd);
|
|
1197
|
+
detectedDevCommand = await stackDetector.detectDevCommand(stack, cwd);
|
|
1198
|
+
detectedPort = await stackDetector.detectPort(stack, cwd);
|
|
1199
|
+
const reStacks = [stack.framework, ...stack.additionalStacks ?? []].filter((s) => s !== "unknown").join(" + ") || "unknown";
|
|
1200
|
+
spinner.succeed(`Detecting project... ${chalk6.cyan(reStacks)} (${chalk6.dim(stack.typescript ? "TypeScript" : stack.language || "unknown")})`);
|
|
1201
|
+
devCommand = config.project.devCommand || detectedDevCommand;
|
|
1202
|
+
devPort = config.project.port || detectedPort;
|
|
1203
|
+
if (!devCommand) {
|
|
1204
|
+
console.error(
|
|
1205
|
+
chalk6.red('No dev command found after scaffolding. Set project.devCommand in nova.toml or ensure package.json has a "dev" script.')
|
|
1206
|
+
);
|
|
1207
|
+
process.exit(1);
|
|
1208
|
+
}
|
|
1067
1209
|
}
|
|
1068
1210
|
}
|
|
1069
1211
|
spinner.start("Initializing .nova/ directory...");
|
|
@@ -1078,7 +1220,7 @@ ${nudgeMessage}
|
|
|
1078
1220
|
throw err;
|
|
1079
1221
|
}
|
|
1080
1222
|
spinner.succeed("Project indexed.");
|
|
1081
|
-
const { ProjectAnalyzer, RagIndexer, createEmbeddingService } = await import("./dist-
|
|
1223
|
+
const { ProjectAnalyzer, RagIndexer, createEmbeddingService } = await import("./dist-NVKTAKZX.js");
|
|
1082
1224
|
const { ProjectMapApi } = await import("./dist-5FLNK6MH.js");
|
|
1083
1225
|
const projectAnalyzer = new ProjectAnalyzer();
|
|
1084
1226
|
spinner.start("Analyzing project structure...");
|
|
@@ -1086,7 +1228,7 @@ ${nudgeMessage}
|
|
|
1086
1228
|
spinner.succeed(`Project analyzed: ${analysis.fileCount} files, ${analysis.methods.length} methods.`);
|
|
1087
1229
|
let ragIndexer = null;
|
|
1088
1230
|
try {
|
|
1089
|
-
const { VectorStore } = await import("./dist-
|
|
1231
|
+
const { VectorStore } = await import("./dist-NVKTAKZX.js");
|
|
1090
1232
|
let embeddingProvider = "tfidf";
|
|
1091
1233
|
let embeddingApiKey;
|
|
1092
1234
|
let embeddingBaseUrl;
|
|
@@ -1142,6 +1284,21 @@ ${nudgeMessage}
|
|
|
1142
1284
|
process.exit(1);
|
|
1143
1285
|
}
|
|
1144
1286
|
spinner.succeed("Ports available");
|
|
1287
|
+
const NODE_FRAMEWORKS = ["node", "express", "nest", "fastify", "koa", "hapi", "next.js", "nuxt", "sveltekit", "astro", "vite", "cra"];
|
|
1288
|
+
if (NODE_FRAMEWORKS.includes(stack.framework) && !existsSync(join2(cwd, "node_modules"))) {
|
|
1289
|
+
const pm = stack.packageManager ?? "npm";
|
|
1290
|
+
const installCmd = pm === "yarn" ? "yarn" : `${pm} install`;
|
|
1291
|
+
spinner.stop();
|
|
1292
|
+
console.log(chalk6.dim(` Installing dependencies (${installCmd})...`));
|
|
1293
|
+
try {
|
|
1294
|
+
const { execSync } = await import("child_process");
|
|
1295
|
+
execSync(installCmd, { cwd, stdio: "inherit" });
|
|
1296
|
+
console.log(chalk6.green(" Dependencies installed."));
|
|
1297
|
+
} catch {
|
|
1298
|
+
console.log(chalk6.red(` Failed to install dependencies. Run "${installCmd}" manually.`));
|
|
1299
|
+
process.exit(1);
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1145
1302
|
spinner.start(`Starting dev server (${chalk6.dim(devCommand)})...`);
|
|
1146
1303
|
try {
|
|
1147
1304
|
await devServer.spawn(devCommand, cwd, devPort);
|
|
@@ -1178,7 +1335,7 @@ Tips:`));
|
|
|
1178
1335
|
wsServer.start(httpServer);
|
|
1179
1336
|
}
|
|
1180
1337
|
proxyServer.setProjectMapApi(projectMapApi);
|
|
1181
|
-
const { GraphStore: GS, SearchRouter: SR } = await import("./dist-
|
|
1338
|
+
const { GraphStore: GS, SearchRouter: SR } = await import("./dist-NVKTAKZX.js");
|
|
1182
1339
|
const novaPath = novaDir.getPath(cwd);
|
|
1183
1340
|
const graphStoreForApi = new GS(novaPath);
|
|
1184
1341
|
const searchRouterForApi = new SR(graphStoreForApi);
|
|
@@ -1200,23 +1357,6 @@ Tips:`));
|
|
|
1200
1357
|
} else {
|
|
1201
1358
|
exec(`google-chrome "${openUrl}" 2>/dev/null || chromium "${openUrl}" 2>/dev/null || xdg-open "${openUrl}"`);
|
|
1202
1359
|
}
|
|
1203
|
-
if (!config.apiKeys.key && config.apiKeys.provider !== "ollama" && config.apiKeys.provider !== "claude-cli") {
|
|
1204
|
-
console.log(chalk6.yellow("\nNo API key configured. Running setup...\n"));
|
|
1205
|
-
const { runSetup: runSetup2 } = await import("./setup-VJMYSGJI.js");
|
|
1206
|
-
await runSetup2(cwd);
|
|
1207
|
-
const updatedConfig = await configReader.read(cwd);
|
|
1208
|
-
config.apiKeys = updatedConfig.apiKeys;
|
|
1209
|
-
}
|
|
1210
|
-
const providerFactory = new ProviderFactory();
|
|
1211
|
-
let llmClient;
|
|
1212
|
-
try {
|
|
1213
|
-
llmClient = providerFactory.create(config.apiKeys.provider, config.apiKeys.key);
|
|
1214
|
-
} catch (err) {
|
|
1215
|
-
console.log(chalk6.yellow("\nAI provider not configured. Nova is running without AI analysis."));
|
|
1216
|
-
console.log(chalk6.dim('Run "nova setup" to configure your API key.\n'));
|
|
1217
|
-
llmClient = null;
|
|
1218
|
-
}
|
|
1219
|
-
const brain = llmClient ? new Brain(llmClient, eventBus) : null;
|
|
1220
1360
|
try {
|
|
1221
1361
|
const { execSync } = await import("child_process");
|
|
1222
1362
|
execSync("git rev-parse --git-dir", { cwd, stdio: "ignore" });
|
|
@@ -1407,6 +1547,7 @@ ${pendingMessage}
|
|
|
1407
1547
|
}
|
|
1408
1548
|
wsServer.sendEvent(event);
|
|
1409
1549
|
setTimeout(async () => {
|
|
1550
|
+
if (autoFixer?.isAutofixTask(event.data.taskId)) return;
|
|
1410
1551
|
const logs = devServer.getLogs();
|
|
1411
1552
|
const recentLogs = logs.slice(-2e3);
|
|
1412
1553
|
const hasLogError = /error|Error|failed|Failed|Module not found|SyntaxError|TypeError/i.test(recentLogs) && !/Successfully compiled|Compiled/.test(recentLogs.slice(-500));
|
|
@@ -2278,14 +2419,14 @@ function createCli() {
|
|
|
2278
2419
|
if (opts.provider && (opts.key || opts.provider === "ollama" || opts.provider === "claude-cli")) {
|
|
2279
2420
|
const fs2 = await import("fs/promises");
|
|
2280
2421
|
const path4 = await import("path");
|
|
2281
|
-
const
|
|
2422
|
+
const TOML2 = (await import("@iarna/toml")).default;
|
|
2282
2423
|
const cwd = process.cwd();
|
|
2283
2424
|
const novaDir = path4.join(cwd, ".nova");
|
|
2284
2425
|
await fs2.mkdir(novaDir, { recursive: true });
|
|
2285
2426
|
const config = { apiKeys: { provider: opts.provider, key: opts.key } };
|
|
2286
2427
|
await fs2.writeFile(
|
|
2287
2428
|
path4.join(novaDir, "config.toml"),
|
|
2288
|
-
|
|
2429
|
+
TOML2.stringify(config),
|
|
2289
2430
|
"utf-8"
|
|
2290
2431
|
);
|
|
2291
2432
|
console.log(`Saved ${opts.provider} config to .nova/config.toml`);
|
package/dist/index.d.ts
CHANGED
|
@@ -53,7 +53,9 @@ declare class ErrorAutoFixer {
|
|
|
53
53
|
private readonly MAX_FIX_ATTEMPTS;
|
|
54
54
|
private lastErrorSignature;
|
|
55
55
|
private cooldownUntil;
|
|
56
|
+
readonly autofixTaskIds: Set<string>;
|
|
56
57
|
constructor(projectPath: string, llmClient: LlmClient, gitManager: IGitManager, eventBus: EventBus, wsServer: WebSocketServer, projectMap: ProjectMap, commitQueue?: CommitQueue | undefined);
|
|
58
|
+
isAutofixTask(taskId: string): boolean;
|
|
57
59
|
/**
|
|
58
60
|
* Process dev server output. Call this for every stdout/stderr chunk.
|
|
59
61
|
*/
|
|
@@ -63,6 +65,9 @@ declare class ErrorAutoFixer {
|
|
|
63
65
|
private attemptAutoFix;
|
|
64
66
|
private fixImageError;
|
|
65
67
|
private fixCompilationError;
|
|
68
|
+
private fixWithLane2;
|
|
69
|
+
private fixWithLane3;
|
|
70
|
+
private extractFilePath;
|
|
66
71
|
}
|
|
67
72
|
|
|
68
73
|
declare function createCli(): Command;
|
package/dist/index.js
CHANGED
|
@@ -4,13 +4,13 @@ import {
|
|
|
4
4
|
createCli,
|
|
5
5
|
promptAndScaffold,
|
|
6
6
|
run
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-7ZE7J73C.js";
|
|
8
8
|
import "./chunk-KE7XWO5N.js";
|
|
9
9
|
import {
|
|
10
10
|
ConfigReader,
|
|
11
11
|
runSetup
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-
|
|
12
|
+
} from "./chunk-53K63TXF.js";
|
|
13
|
+
import "./chunk-3FVS3SB3.js";
|
|
14
14
|
import "./chunk-3RG5ZIWI.js";
|
|
15
15
|
export {
|
|
16
16
|
ConfigReader,
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.1.
|
|
6
|
+
"version": "0.1.6",
|
|
7
7
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"main": "dist/index.js",
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"tsup": "^8.4.0",
|
|
37
37
|
"typescript": "^5.7.0",
|
|
38
|
-
"@novastorm-ai/
|
|
38
|
+
"@novastorm-ai/core": "0.0.1",
|
|
39
39
|
"@novastorm-ai/proxy": "0.0.1",
|
|
40
|
-
"@novastorm-ai/
|
|
40
|
+
"@novastorm-ai/licensing": "0.0.1"
|
|
41
41
|
},
|
|
42
42
|
"scripts": {
|
|
43
43
|
"build": "tsup",
|