ai-spec-dev 0.42.0 → 0.55.0
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/README.md +86 -40
- package/cli/commands/config.ts +129 -1
- package/cli/commands/create.ts +246 -11
- package/cli/commands/fix-history.ts +176 -0
- package/cli/commands/init.ts +344 -106
- package/cli/index.ts +3 -7
- package/cli/pipeline/helpers.ts +6 -0
- package/cli/pipeline/multi-repo.ts +291 -26
- package/cli/pipeline/single-repo.ts +103 -2
- package/cli/utils.ts +95 -4
- package/core/code-generator.ts +63 -14
- package/core/config-defaults.ts +44 -0
- package/core/constitution-generator.ts +2 -1
- package/core/cross-stack-verifier.ts +395 -0
- package/core/dsl-extractor.ts +2 -1
- package/core/error-feedback.ts +3 -2
- package/core/fix-history.ts +333 -0
- package/core/import-fixer.ts +827 -0
- package/core/import-verifier.ts +569 -0
- package/core/knowledge-memory.ts +55 -6
- package/core/openapi-exporter.ts +3 -2
- package/core/repo-store.ts +95 -0
- package/core/reviewer.ts +14 -13
- package/core/run-logger.ts +3 -4
- package/core/run-snapshot.ts +2 -3
- package/core/run-trend.ts +3 -4
- package/core/self-evaluator.ts +44 -7
- package/core/spec-generator.ts +30 -45
- package/core/token-budget.ts +3 -8
- package/core/types-generator.ts +2 -2
- package/core/vcr.ts +3 -1
- package/dist/cli/index.js +3889 -1937
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +3888 -1936
- package/dist/cli/index.mjs.map +1 -1
- package/dist/index.d.mts +17 -2
- package/dist/index.d.ts +17 -2
- package/dist/index.js +292 -181
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +292 -181
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/tests/cross-stack-verifier.test.ts +301 -0
- package/tests/fix-history.test.ts +335 -0
- package/tests/import-fixer.test.ts +944 -0
- package/tests/import-verifier.test.ts +420 -0
- package/tests/knowledge-memory.test.ts +40 -0
- package/tests/self-evaluator.test.ts +97 -0
- package/cli/commands/model.ts +0 -156
- package/cli/commands/scan.ts +0 -99
- package/cli/commands/workspace.ts +0 -219
- package/demo-backend/.ai-spec-constitution.md +0 -65
- package/demo-backend/package.json +0 -21
- package/demo-backend/prisma/schema.prisma +0 -22
- package/demo-backend/specs/feature-1-bookmark-id-uuid-title-string-required-url-str-v1.dsl.json +0 -186
- package/demo-backend/specs/feature-1-bookmark-id-uuid-title-string-required-url-str-v1.md +0 -211
- package/demo-backend/src/controllers/bookmark.controller.test.ts +0 -255
- package/demo-backend/src/controllers/bookmark.controller.ts +0 -187
- package/demo-backend/src/index.ts +0 -17
- package/demo-backend/src/routes/bookmark.routes.test.ts +0 -264
- package/demo-backend/src/routes/bookmark.routes.ts +0 -11
- package/demo-backend/src/routes/index.ts +0 -8
- package/demo-backend/src/services/bookmark.service.test.ts +0 -433
- package/demo-backend/src/services/bookmark.service.ts +0 -261
- package/demo-backend/tsconfig.json +0 -12
- package/demo-frontend/.ai-spec-constitution.md +0 -95
- package/demo-frontend/package.json +0 -23
- package/demo-frontend/src/App.tsx +0 -12
- package/demo-frontend/src/main.tsx +0 -9
- package/demo-frontend/tsconfig.json +0 -13
package/cli/utils.ts
CHANGED
|
@@ -1,37 +1,120 @@
|
|
|
1
1
|
import * as path from "path";
|
|
2
2
|
import * as fs from "fs-extra";
|
|
3
|
+
import * as os from "os";
|
|
3
4
|
import chalk from "chalk";
|
|
4
5
|
import { input, select } from "@inquirer/prompts";
|
|
5
6
|
import { CodeGenMode } from "../core/code-generator";
|
|
6
|
-
import { ENV_KEY_MAP } from "../core/spec-generator";
|
|
7
|
+
import { ENV_KEY_MAP, PROVIDER_CATALOG } from "../core/spec-generator";
|
|
7
8
|
import { getSavedKey, saveKey, KEY_STORE_FILE } from "../core/key-store";
|
|
8
9
|
|
|
9
10
|
// ─── Config ───────────────────────────────────────────────────────────────────
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
/** User-level preferences (stored in ~/.ai-spec-config.json) */
|
|
13
|
+
export interface AiSpecGlobalConfig {
|
|
12
14
|
provider?: string;
|
|
13
15
|
model?: string;
|
|
14
16
|
codegen?: CodeGenMode;
|
|
15
17
|
codegenProvider?: string;
|
|
16
18
|
codegenModel?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Full merged config (global + project-level overrides) */
|
|
22
|
+
export interface AiSpecConfig extends AiSpecGlobalConfig {
|
|
17
23
|
/** Minimum overall spec score (1-10) required to pass Approval Gate. 0 = disabled (default). */
|
|
18
24
|
minSpecScore?: number;
|
|
19
25
|
/** Minimum harness score (1-10) required for pipeline success. 0 = disabled (default). */
|
|
20
26
|
minHarnessScore?: number;
|
|
21
27
|
/** Maximum error-feedback cycles before giving up (default: 2, TDD default: 3). */
|
|
22
28
|
maxErrorCycles?: number;
|
|
29
|
+
/**
|
|
30
|
+
* Maximum number of tasks that can run concurrently within a codegen batch
|
|
31
|
+
* (api mode only). Prevents rate-limit errors when a layer has many independent
|
|
32
|
+
* tasks. Default: 3.
|
|
33
|
+
*/
|
|
34
|
+
maxCodegenConcurrency?: number;
|
|
35
|
+
/**
|
|
36
|
+
* When true (default), past hallucination patterns from
|
|
37
|
+
* `.ai-spec-fix-history.json` are injected into codegen prompts.
|
|
38
|
+
* Set to false to disable automatic learning from fix history.
|
|
39
|
+
*/
|
|
40
|
+
injectFixHistory?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Number of times a hallucination pattern must repeat in fix-history before
|
|
43
|
+
* `ai-spec fix-history --promote` offers it as a constitution §9 lesson.
|
|
44
|
+
* Default: 5.
|
|
45
|
+
*/
|
|
46
|
+
fixHistoryPromotionThreshold?: number;
|
|
47
|
+
/**
|
|
48
|
+
* Maximum number of past hallucination patterns injected into a single
|
|
49
|
+
* codegen prompt. Prevents prompt bloat. Default: 10.
|
|
50
|
+
*/
|
|
51
|
+
fixHistoryInjectMax?: number;
|
|
23
52
|
/** §9 lesson count threshold for auto-consolidation (default: 12). */
|
|
24
53
|
autoConsolidateThreshold?: number;
|
|
54
|
+
|
|
55
|
+
// ── Directory & file overrides ─────────────────────────────────────────────
|
|
56
|
+
/** Run log directory (default: ".ai-spec-logs") */
|
|
57
|
+
logDir?: string;
|
|
58
|
+
/** VCR recording directory (default: ".ai-spec-vcr") */
|
|
59
|
+
vcrDir?: string;
|
|
60
|
+
/** File backup directory (default: ".ai-spec-backup") */
|
|
61
|
+
backupDir?: string;
|
|
62
|
+
/** Review history file (default: ".ai-spec-reviews.json") */
|
|
63
|
+
reviewHistoryFile?: string;
|
|
64
|
+
|
|
65
|
+
// ── URL overrides ──────────────────────────────────────────────────────────
|
|
66
|
+
/** Default server URL for OpenAPI export (default: "http://localhost:3000") */
|
|
67
|
+
openApiServerUrl?: string;
|
|
68
|
+
|
|
69
|
+
// ── Numeric limits ─────────────────────────────────────────────────────────
|
|
70
|
+
/** Max chars captured from build/test/lint command output (default: 30000) */
|
|
71
|
+
maxCommandOutputChars?: number;
|
|
72
|
+
/** Max chars of source file sent to AI for auto-fix (default: 60000) */
|
|
73
|
+
maxFixFileChars?: number;
|
|
74
|
+
/** Max DSL extraction retries (default: 2) */
|
|
75
|
+
dslMaxRetries?: number;
|
|
76
|
+
/** Max constitution chars in codegen prompt (default: 4000) */
|
|
77
|
+
maxConstitutionChars?: number;
|
|
78
|
+
/** Per-provider token budget overrides (e.g. { "gemini": 900000, "claude": 180000 }) */
|
|
79
|
+
providerTokenBudgets?: Record<string, number>;
|
|
25
80
|
}
|
|
26
81
|
|
|
27
82
|
export const CONFIG_FILE = ".ai-spec.json";
|
|
83
|
+
export const GLOBAL_CONFIG_FILE = path.join(os.homedir(), ".ai-spec-config.json");
|
|
84
|
+
|
|
85
|
+
/** Load global user-level config from ~/.ai-spec-config.json */
|
|
86
|
+
export async function loadGlobalConfig(): Promise<AiSpecGlobalConfig> {
|
|
87
|
+
try {
|
|
88
|
+
if (await fs.pathExists(GLOBAL_CONFIG_FILE)) {
|
|
89
|
+
return await fs.readJson(GLOBAL_CONFIG_FILE);
|
|
90
|
+
}
|
|
91
|
+
} catch { /* ignore */ }
|
|
92
|
+
return {};
|
|
93
|
+
}
|
|
28
94
|
|
|
95
|
+
/** Save global user-level config to ~/.ai-spec-config.json */
|
|
96
|
+
export async function saveGlobalConfig(config: AiSpecGlobalConfig): Promise<void> {
|
|
97
|
+
await fs.ensureFile(GLOBAL_CONFIG_FILE);
|
|
98
|
+
await fs.writeJson(GLOBAL_CONFIG_FILE, config, { spaces: 2 });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Load merged config: global (baseline) + project-level (override).
|
|
103
|
+
* Provider/model from global, project-specific settings from local .ai-spec.json.
|
|
104
|
+
*/
|
|
29
105
|
export async function loadConfig(dir: string): Promise<AiSpecConfig> {
|
|
106
|
+
const globalConfig = await loadGlobalConfig();
|
|
107
|
+
|
|
108
|
+
let localConfig: AiSpecConfig = {};
|
|
30
109
|
const p = path.join(dir, CONFIG_FILE);
|
|
31
110
|
if (await fs.pathExists(p)) {
|
|
32
|
-
|
|
111
|
+
try {
|
|
112
|
+
localConfig = await fs.readJson(p);
|
|
113
|
+
} catch { /* ignore */ }
|
|
33
114
|
}
|
|
34
|
-
|
|
115
|
+
|
|
116
|
+
// Local overrides global
|
|
117
|
+
return { ...globalConfig, ...localConfig };
|
|
35
118
|
}
|
|
36
119
|
|
|
37
120
|
// ─── API Key Resolution ───────────────────────────────────────────────────────
|
|
@@ -45,6 +128,14 @@ export async function resolveApiKey(
|
|
|
45
128
|
const envVar = ENV_KEY_MAP[providerName];
|
|
46
129
|
if (envVar && process.env[envVar]) return process.env[envVar]!;
|
|
47
130
|
|
|
131
|
+
// Check fallback env vars (e.g. MiMo reads ANTHROPIC_AUTH_TOKEN from token-plan)
|
|
132
|
+
const meta = PROVIDER_CATALOG[providerName];
|
|
133
|
+
if (meta?.fallbackEnvKeys) {
|
|
134
|
+
for (const key of meta.fallbackEnvKeys) {
|
|
135
|
+
if (process.env[key]) return process.env[key]!;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
48
139
|
const savedKey = await getSavedKey(providerName);
|
|
49
140
|
if (savedKey) {
|
|
50
141
|
const masked = savedKey.slice(0, 6) + "..." + savedKey.slice(-4);
|
package/core/code-generator.ts
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
import { topoSortLayerTasks, printTaskProgress, LAYER_ICONS } from "./codegen/topo-sort";
|
|
24
24
|
import { estimateTokens, getDefaultBudget } from "./token-budget";
|
|
25
25
|
import { startSpinner } from "./cli-ui";
|
|
26
|
+
import { loadFixHistory, buildHallucinationAvoidanceSection } from "./fix-history";
|
|
26
27
|
|
|
27
28
|
// Re-export public symbols for backward compatibility
|
|
28
29
|
export { extractBehavioralContract } from "./codegen/helpers";
|
|
@@ -41,6 +42,20 @@ export interface CodeGenOptions {
|
|
|
41
42
|
dslFilePath?: string;
|
|
42
43
|
/** Repo language type — selects the appropriate codegen system prompt */
|
|
43
44
|
repoType?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Maximum number of tasks that can run concurrently within a single batch
|
|
47
|
+
* (api mode only). A batch larger than this value is split into sequential
|
|
48
|
+
* sub-chunks, each running maxConcurrency tasks in parallel. Default: 3.
|
|
49
|
+
*/
|
|
50
|
+
maxConcurrency?: number;
|
|
51
|
+
/**
|
|
52
|
+
* When true, prior hallucination patterns from `.ai-spec-fix-history.json`
|
|
53
|
+
* are injected into the codegen prompt as a "DO NOT REPEAT" section.
|
|
54
|
+
* Default: true when the ledger exists.
|
|
55
|
+
*/
|
|
56
|
+
injectFixHistory?: boolean;
|
|
57
|
+
/** Max number of past hallucination patterns to inject. Default: 10 */
|
|
58
|
+
fixHistoryInjectMax?: number;
|
|
44
59
|
}
|
|
45
60
|
|
|
46
61
|
export class CodeGenerator {
|
|
@@ -268,8 +283,27 @@ export class CodeGenerator {
|
|
|
268
283
|
console.log(chalk.gray(` Frontend context: ${fctx.framework} / ${fctx.httpClient} | hooks:${fctx.hookFiles.length} stores:${fctx.storeFiles.length}`));
|
|
269
284
|
}
|
|
270
285
|
|
|
286
|
+
// Inject past hallucination patterns so the AI learns from this project's fix history.
|
|
287
|
+
// Opt out via CodeGenOptions.injectFixHistory = false.
|
|
288
|
+
let fixHistorySection = "";
|
|
289
|
+
if (options.injectFixHistory !== false) {
|
|
290
|
+
try {
|
|
291
|
+
const history = await loadFixHistory(workingDir);
|
|
292
|
+
const section = buildHallucinationAvoidanceSection(history, {
|
|
293
|
+
maxItems: options.fixHistoryInjectMax ?? 10,
|
|
294
|
+
});
|
|
295
|
+
if (section) {
|
|
296
|
+
fixHistorySection = `\n${section}\n`;
|
|
297
|
+
const patternCount = (section.match(/❌ Do NOT/g) ?? []).length;
|
|
298
|
+
console.log(chalk.cyan(` ✓ Injected ${patternCount} prior hallucination pattern(s) from fix-history`));
|
|
299
|
+
}
|
|
300
|
+
} catch {
|
|
301
|
+
// Non-fatal: if the ledger is broken, just skip injection
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
271
305
|
// Token budget check — warn if context sections are large
|
|
272
|
-
const allContextText = spec + constitutionSection + dslSection + frontendSection + installedPackagesSection + sharedConfigSection;
|
|
306
|
+
const allContextText = spec + constitutionSection + dslSection + frontendSection + installedPackagesSection + sharedConfigSection + fixHistorySection;
|
|
273
307
|
const estimatedTokenCount = estimateTokens(allContextText);
|
|
274
308
|
const budget = getDefaultBudget(this.provider.providerName);
|
|
275
309
|
if (estimatedTokenCount > budget * 0.7) {
|
|
@@ -292,7 +326,7 @@ export class CodeGenerator {
|
|
|
292
326
|
// Use tasks if available for finer-grained generation with resume support
|
|
293
327
|
const tasks = await loadTasksForSpec(specFilePath);
|
|
294
328
|
if (tasks && tasks.length > 0) {
|
|
295
|
-
return this.runApiModeWithTasks(spec, tasks, specFilePath, workingDir, constitutionSection + dslSection + installedPackagesSection, frontendSection, sharedConfigSection, options, systemPrompt, context);
|
|
329
|
+
return this.runApiModeWithTasks(spec, tasks, specFilePath, workingDir, constitutionSection + dslSection + installedPackagesSection + fixHistorySection, frontendSection, sharedConfigSection, options, systemPrompt, context);
|
|
296
330
|
}
|
|
297
331
|
|
|
298
332
|
// Fallback: plan-then-generate
|
|
@@ -306,7 +340,7 @@ IMPORTANT: Check the "Frontend Project Context" section below. Extend existing h
|
|
|
306
340
|
|
|
307
341
|
=== Feature Spec ===
|
|
308
342
|
${spec}
|
|
309
|
-
${constitutionSection}${dslSection}${frontendSection}${installedPackagesSection}${sharedConfigSection}
|
|
343
|
+
${constitutionSection}${dslSection}${frontendSection}${installedPackagesSection}${sharedConfigSection}${fixHistorySection}
|
|
310
344
|
=== Project Context ===
|
|
311
345
|
${contextSummary}
|
|
312
346
|
|
|
@@ -336,7 +370,7 @@ Output ONLY a valid JSON array:
|
|
|
336
370
|
console.log(` ${icon} ${item.file}: ${chalk.gray(item.description)}`);
|
|
337
371
|
});
|
|
338
372
|
|
|
339
|
-
const { files } = await this.generateFiles(filePlan, spec, workingDir, constitutionSection + dslSection + frontendSection + installedPackagesSection, systemPrompt);
|
|
373
|
+
const { files } = await this.generateFiles(filePlan, spec, workingDir, constitutionSection + dslSection + frontendSection + installedPackagesSection + fixHistorySection, systemPrompt);
|
|
340
374
|
return files;
|
|
341
375
|
}
|
|
342
376
|
|
|
@@ -524,24 +558,39 @@ Output ONLY a valid JSON array:
|
|
|
524
558
|
|
|
525
559
|
// Partition tasks into topological batches (respects dependencies field).
|
|
526
560
|
// Each batch runs in parallel; batches run sequentially.
|
|
561
|
+
// Additionally, each batch is chunked by maxConcurrency to prevent
|
|
562
|
+
// rate-limit errors when a batch contains many independent tasks.
|
|
527
563
|
const taskBatches = topoSortLayerTasks(layerTasks);
|
|
528
564
|
const layerResults: TaskResult[] = [];
|
|
565
|
+
const maxConcurrency = Math.max(1, options.maxConcurrency ?? 3);
|
|
529
566
|
|
|
530
567
|
for (const batch of taskBatches) {
|
|
531
568
|
const batchIsParallel = batch.length > 1;
|
|
532
|
-
const batchResultPromises = batch.map((task) => executeTask(task, batchIsParallel));
|
|
533
|
-
const settled = await Promise.allSettled(batchResultPromises);
|
|
534
569
|
const batchResults: TaskResult[] = [];
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
570
|
+
|
|
571
|
+
// Split batch into chunks of at most `maxConcurrency` tasks.
|
|
572
|
+
// Each chunk runs in parallel; chunks run sequentially within the batch.
|
|
573
|
+
for (let chunkStart = 0; chunkStart < batch.length; chunkStart += maxConcurrency) {
|
|
574
|
+
const chunk = batch.slice(chunkStart, chunkStart + maxConcurrency);
|
|
575
|
+
if (batchIsParallel && batch.length > maxConcurrency) {
|
|
576
|
+
const chunkIdx = Math.floor(chunkStart / maxConcurrency) + 1;
|
|
577
|
+
const totalChunks = Math.ceil(batch.length / maxConcurrency);
|
|
578
|
+
console.log(chalk.gray(` ↳ chunk ${chunkIdx}/${totalChunks} (${chunk.length} tasks, concurrency cap: ${maxConcurrency})`));
|
|
579
|
+
}
|
|
580
|
+
const chunkResultPromises = chunk.map((task) => executeTask(task, batchIsParallel));
|
|
581
|
+
const settled = await Promise.allSettled(chunkResultPromises);
|
|
582
|
+
for (let i = 0; i < settled.length; i++) {
|
|
583
|
+
const outcome = settled[i];
|
|
584
|
+
if (outcome.status === "fulfilled") {
|
|
585
|
+
batchResults.push(outcome.value);
|
|
586
|
+
} else {
|
|
587
|
+
const task = chunk[i];
|
|
588
|
+
console.log(chalk.yellow(` ⚠ ${task.id} threw unexpectedly: ${outcome.reason?.message ?? outcome.reason}`));
|
|
589
|
+
batchResults.push({ task, files: [], createdFiles: [], success: 0, total: 0, impliesRegistration: false });
|
|
590
|
+
}
|
|
543
591
|
}
|
|
544
592
|
}
|
|
593
|
+
|
|
545
594
|
layerResults.push(...batchResults);
|
|
546
595
|
// Update cache after each batch so the next batch sees the exports.
|
|
547
596
|
await updateCacheFromBatch(batchResults);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* config-defaults.ts — Centralized default values for all configurable constants.
|
|
3
|
+
*
|
|
4
|
+
* Modules import their defaults from here instead of defining local magic numbers.
|
|
5
|
+
* The pipeline can override any value via AiSpecConfig at runtime.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// ─── Directory & File Names ─────────────────────────────────────────────────
|
|
9
|
+
|
|
10
|
+
export const DEFAULT_LOG_DIR = ".ai-spec-logs";
|
|
11
|
+
export const DEFAULT_VCR_DIR = ".ai-spec-vcr";
|
|
12
|
+
export const DEFAULT_BACKUP_DIR = ".ai-spec-backup";
|
|
13
|
+
export const DEFAULT_REVIEW_HISTORY_FILE = ".ai-spec-reviews.json";
|
|
14
|
+
|
|
15
|
+
// ─── URLs ───────────────────────────────────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
export const DEFAULT_OPENAPI_SERVER_URL = "http://localhost:3000";
|
|
18
|
+
|
|
19
|
+
// ─── Numeric Limits ─────────────────────────────────────────────────────────
|
|
20
|
+
|
|
21
|
+
/** Max chars captured from build/test/lint command output before parsing. */
|
|
22
|
+
export const DEFAULT_MAX_COMMAND_OUTPUT_CHARS = 30_000;
|
|
23
|
+
|
|
24
|
+
/** Max chars of an existing file sent to the AI for auto-fix. */
|
|
25
|
+
export const DEFAULT_MAX_FIX_FILE_CHARS = 60_000;
|
|
26
|
+
|
|
27
|
+
/** Max DSL extraction retries on parse failure. */
|
|
28
|
+
export const DEFAULT_DSL_MAX_RETRIES = 2;
|
|
29
|
+
|
|
30
|
+
/** Max constitution chars in codegen prompts (trimmed if exceeded). */
|
|
31
|
+
export const DEFAULT_MAX_CONSTITUTION_CHARS = 4_000;
|
|
32
|
+
|
|
33
|
+
/** Max chars of file content sent per file in review (reviewFiles mode). */
|
|
34
|
+
export const DEFAULT_MAX_REVIEW_FILE_CHARS = 3_000;
|
|
35
|
+
|
|
36
|
+
// ─── Token Budgets ──────────────────────────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
export const DEFAULT_TOKEN_BUDGETS: Record<string, number> = {
|
|
39
|
+
gemini: 900_000,
|
|
40
|
+
claude: 180_000,
|
|
41
|
+
openai: 120_000,
|
|
42
|
+
deepseek: 60_000,
|
|
43
|
+
default: 100_000,
|
|
44
|
+
};
|
|
@@ -4,6 +4,7 @@ import * as path from "path";
|
|
|
4
4
|
import { AIProvider } from "./spec-generator";
|
|
5
5
|
import { ContextLoader, ProjectContext } from "./context-loader";
|
|
6
6
|
import { constitutionSystemPrompt } from "../prompts/constitution.prompt";
|
|
7
|
+
import { DEFAULT_MAX_CONSTITUTION_CHARS } from "./config-defaults";
|
|
7
8
|
|
|
8
9
|
export const CONSTITUTION_FILE = ".ai-spec-constitution.md";
|
|
9
10
|
|
|
@@ -41,7 +42,7 @@ function buildConstitutionPrompt(context: ProjectContext, projectRoot: string):
|
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
if (context.schema) {
|
|
44
|
-
parts.push(`=== Prisma Schema ===\n${context.schema.slice(0,
|
|
45
|
+
parts.push(`=== Prisma Schema ===\n${context.schema.slice(0, DEFAULT_MAX_CONSTITUTION_CHARS)}\n`);
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
if (context.errorPatterns) {
|