ai-spec-dev 0.42.0 → 0.46.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 +33 -17
- package/cli/commands/create.ts +232 -11
- package/cli/commands/init.ts +310 -107
- package/cli/commands/model.ts +7 -11
- package/cli/index.ts +1 -1
- package/cli/utils.ts +72 -4
- package/core/config-defaults.ts +44 -0
- package/core/constitution-generator.ts +2 -1
- package/core/dsl-extractor.ts +2 -1
- package/core/error-feedback.ts +3 -2
- 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/spec-generator.ts +27 -42
- package/core/token-budget.ts +3 -8
- package/core/vcr.ts +3 -1
- package/dist/cli/index.js +919 -519
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +912 -512
- package/dist/cli/index.mjs.map +1 -1
- package/dist/index.d.mts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +43 -53
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +43 -53
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- 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/dist/index.d.mts
CHANGED
|
@@ -81,6 +81,8 @@ interface ProviderMeta {
|
|
|
81
81
|
models: string[];
|
|
82
82
|
/** Environment variable name for the API key */
|
|
83
83
|
envKey: string;
|
|
84
|
+
/** Fallback env var names checked if envKey is not set */
|
|
85
|
+
fallbackEnvKeys?: string[];
|
|
84
86
|
/**
|
|
85
87
|
* Base URL for OpenAI-compatible providers.
|
|
86
88
|
* Undefined means the provider has its own SDK (Gemini / Claude).
|
|
@@ -126,10 +128,9 @@ declare class OpenAICompatibleProvider implements AIProvider {
|
|
|
126
128
|
generate(prompt: string, systemInstruction?: string): Promise<string>;
|
|
127
129
|
}
|
|
128
130
|
declare class MiMoProvider implements AIProvider {
|
|
131
|
+
private client;
|
|
129
132
|
readonly providerName = "mimo";
|
|
130
133
|
readonly modelName: string;
|
|
131
|
-
private apiKey;
|
|
132
|
-
private readonly baseUrl;
|
|
133
134
|
constructor(apiKey: string, modelName?: string);
|
|
134
135
|
generate(prompt: string, systemInstruction?: string): Promise<string>;
|
|
135
136
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -81,6 +81,8 @@ interface ProviderMeta {
|
|
|
81
81
|
models: string[];
|
|
82
82
|
/** Environment variable name for the API key */
|
|
83
83
|
envKey: string;
|
|
84
|
+
/** Fallback env var names checked if envKey is not set */
|
|
85
|
+
fallbackEnvKeys?: string[];
|
|
84
86
|
/**
|
|
85
87
|
* Base URL for OpenAI-compatible providers.
|
|
86
88
|
* Undefined means the provider has its own SDK (Gemini / Claude).
|
|
@@ -126,10 +128,9 @@ declare class OpenAICompatibleProvider implements AIProvider {
|
|
|
126
128
|
generate(prompt: string, systemInstruction?: string): Promise<string>;
|
|
127
129
|
}
|
|
128
130
|
declare class MiMoProvider implements AIProvider {
|
|
131
|
+
private client;
|
|
129
132
|
readonly providerName = "mimo";
|
|
130
133
|
readonly modelName: string;
|
|
131
|
-
private apiKey;
|
|
132
|
-
private readonly baseUrl;
|
|
133
134
|
constructor(apiKey: string, modelName?: string);
|
|
134
135
|
generate(prompt: string, systemInstruction?: string): Promise<string>;
|
|
135
136
|
}
|
package/dist/index.js
CHANGED
|
@@ -68,7 +68,6 @@ module.exports = __toCommonJS(index_exports);
|
|
|
68
68
|
var import_generative_ai = require("@google/generative-ai");
|
|
69
69
|
var import_sdk = __toESM(require("@anthropic-ai/sdk"));
|
|
70
70
|
var import_openai = __toESM(require("openai"));
|
|
71
|
-
var import_axios = __toESM(require("axios"));
|
|
72
71
|
var import_undici = require("undici");
|
|
73
72
|
|
|
74
73
|
// prompts/spec.prompt.ts
|
|
@@ -361,7 +360,9 @@ var PROVIDER_CATALOG = {
|
|
|
361
360
|
displayName: "MiMo (Xiaomi)",
|
|
362
361
|
description: "\u5C0F\u7C73 MiMo \u2014 mimo-v2-pro (Anthropic-compatible API)",
|
|
363
362
|
models: ["mimo-v2-pro"],
|
|
364
|
-
envKey: "MIMO_API_KEY"
|
|
363
|
+
envKey: "MIMO_API_KEY",
|
|
364
|
+
// Fallback env var — MiMo's token plan uses ANTHROPIC_AUTH_TOKEN
|
|
365
|
+
fallbackEnvKeys: ["ANTHROPIC_AUTH_TOKEN"]
|
|
365
366
|
// baseURL not used — MiMo has a dedicated provider class
|
|
366
367
|
},
|
|
367
368
|
gemini: {
|
|
@@ -530,8 +531,8 @@ var ClaudeProvider = class {
|
|
|
530
531
|
...systemInstruction ? { system: systemInstruction } : {},
|
|
531
532
|
messages: [{ role: "user", content: prompt }]
|
|
532
533
|
});
|
|
533
|
-
const
|
|
534
|
-
if (
|
|
534
|
+
const textBlock = message.content.find((b) => b.type === "text");
|
|
535
|
+
if (textBlock) return textBlock.text;
|
|
535
536
|
throw new Error("Unexpected response type from Claude API");
|
|
536
537
|
},
|
|
537
538
|
{ label: `${this.providerName}/${this.modelName}` }
|
|
@@ -576,43 +577,29 @@ var OpenAICompatibleProvider = class {
|
|
|
576
577
|
}
|
|
577
578
|
};
|
|
578
579
|
var MiMoProvider = class {
|
|
580
|
+
client;
|
|
579
581
|
providerName = "mimo";
|
|
580
582
|
modelName;
|
|
581
|
-
apiKey;
|
|
582
|
-
baseUrl = "https://api.xiaomimimo.com/anthropic/v1/messages";
|
|
583
583
|
constructor(apiKey, modelName = PROVIDER_CATALOG.mimo.models[0]) {
|
|
584
|
-
|
|
584
|
+
const baseURL = process.env["MIMO_BASE_URL"] || process.env["ANTHROPIC_BASE_URL"] || "https://token-plan-cn.xiaomimimo.com/anthropic";
|
|
585
|
+
this.client = new import_sdk.default({ apiKey, baseURL });
|
|
585
586
|
this.modelName = modelName;
|
|
586
587
|
}
|
|
587
588
|
async generate(prompt, systemInstruction) {
|
|
588
589
|
return withReliability(
|
|
589
590
|
async () => {
|
|
590
|
-
const
|
|
591
|
+
const stream = this.client.messages.stream({
|
|
591
592
|
model: this.modelName,
|
|
592
|
-
max_tokens:
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
stream: false,
|
|
596
|
-
temperature: 1,
|
|
597
|
-
stop_sequences: null
|
|
598
|
-
};
|
|
599
|
-
if (systemInstruction) {
|
|
600
|
-
body.system = systemInstruction;
|
|
601
|
-
}
|
|
602
|
-
const response = await import_axios.default.post(this.baseUrl, body, {
|
|
603
|
-
headers: {
|
|
604
|
-
"api-key": this.apiKey,
|
|
605
|
-
"Content-Type": "application/json"
|
|
606
|
-
}
|
|
593
|
+
max_tokens: 65536,
|
|
594
|
+
...systemInstruction ? { system: systemInstruction } : {},
|
|
595
|
+
messages: [{ role: "user", content: prompt }]
|
|
607
596
|
});
|
|
608
|
-
const
|
|
609
|
-
const
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
if (
|
|
613
|
-
|
|
614
|
-
}
|
|
615
|
-
throw new Error(`Unexpected MiMo response: ${JSON.stringify(response.data).slice(0, 200)}`);
|
|
597
|
+
const message = await stream.finalMessage();
|
|
598
|
+
const textBlock = message.content.find((b) => b.type === "text");
|
|
599
|
+
if (textBlock) return textBlock.text;
|
|
600
|
+
const thinkBlock = message.content.find((b) => b.type === "thinking");
|
|
601
|
+
if (thinkBlock) return thinkBlock.thinking;
|
|
602
|
+
return message.content.map((b) => b.text ?? "").join("");
|
|
616
603
|
},
|
|
617
604
|
{ label: `${this.providerName}/${this.modelName}` }
|
|
618
605
|
);
|
|
@@ -5217,13 +5204,11 @@ function typeLabel(v2) {
|
|
|
5217
5204
|
|
|
5218
5205
|
// core/token-budget.ts
|
|
5219
5206
|
var import_chalk6 = __toESM(require("chalk"));
|
|
5220
|
-
|
|
5221
|
-
|
|
5222
|
-
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
return Math.ceil(cjkCount + nonCjkLength / 4);
|
|
5226
|
-
}
|
|
5207
|
+
|
|
5208
|
+
// core/config-defaults.ts
|
|
5209
|
+
var DEFAULT_REVIEW_HISTORY_FILE = ".ai-spec-reviews.json";
|
|
5210
|
+
var DEFAULT_MAX_CONSTITUTION_CHARS = 4e3;
|
|
5211
|
+
var DEFAULT_MAX_REVIEW_FILE_CHARS = 3e3;
|
|
5227
5212
|
var DEFAULT_TOKEN_BUDGETS = {
|
|
5228
5213
|
gemini: 9e5,
|
|
5229
5214
|
claude: 18e4,
|
|
@@ -5231,8 +5216,18 @@ var DEFAULT_TOKEN_BUDGETS = {
|
|
|
5231
5216
|
deepseek: 6e4,
|
|
5232
5217
|
default: 1e5
|
|
5233
5218
|
};
|
|
5219
|
+
|
|
5220
|
+
// core/token-budget.ts
|
|
5221
|
+
var CJK_RANGE = /[\u4e00-\u9fff\u3400-\u4dbf\u3000-\u303f\uff00-\uffef]/g;
|
|
5222
|
+
function estimateTokens(text) {
|
|
5223
|
+
if (!text) return 0;
|
|
5224
|
+
const cjkCount = (text.match(CJK_RANGE) ?? []).length;
|
|
5225
|
+
const nonCjkLength = text.length - cjkCount;
|
|
5226
|
+
return Math.ceil(cjkCount + nonCjkLength / 4);
|
|
5227
|
+
}
|
|
5228
|
+
var DEFAULT_TOKEN_BUDGETS2 = DEFAULT_TOKEN_BUDGETS;
|
|
5234
5229
|
function getDefaultBudget(providerName) {
|
|
5235
|
-
return
|
|
5230
|
+
return DEFAULT_TOKEN_BUDGETS2[providerName] ?? DEFAULT_TOKEN_BUDGETS2.default;
|
|
5236
5231
|
}
|
|
5237
5232
|
|
|
5238
5233
|
// core/dsl-extractor.ts
|
|
@@ -6693,7 +6688,7 @@ ${context.routeSummary}
|
|
|
6693
6688
|
}
|
|
6694
6689
|
if (context.schema) {
|
|
6695
6690
|
parts.push(`=== Prisma Schema ===
|
|
6696
|
-
${context.schema.slice(0,
|
|
6691
|
+
${context.schema.slice(0, DEFAULT_MAX_CONSTITUTION_CHARS)}
|
|
6697
6692
|
`);
|
|
6698
6693
|
}
|
|
6699
6694
|
if (context.errorPatterns) {
|
|
@@ -6757,7 +6752,7 @@ async function loadAccumulatedLessons(projectRoot) {
|
|
|
6757
6752
|
const nextSection = section.slice(marker.length).match(/\n## \d/);
|
|
6758
6753
|
return nextSection ? section.slice(0, marker.length + nextSection.index) : section;
|
|
6759
6754
|
}
|
|
6760
|
-
var REVIEW_HISTORY_FILE =
|
|
6755
|
+
var REVIEW_HISTORY_FILE = DEFAULT_REVIEW_HISTORY_FILE;
|
|
6761
6756
|
async function loadReviewHistory(projectRoot) {
|
|
6762
6757
|
const historyPath = path8.join(projectRoot, REVIEW_HISTORY_FILE);
|
|
6763
6758
|
try {
|
|
@@ -6888,15 +6883,13 @@ ${specContent || "(No spec \u2014 review for general code quality)"}
|
|
|
6888
6883
|
${codeContext}`;
|
|
6889
6884
|
const archReview = await this.provider.generate(archPrompt, reviewArchitectureSystemPrompt);
|
|
6890
6885
|
console.log(import_chalk12.default.gray(" Pass 2/3: Implementation review..."));
|
|
6886
|
+
const specDigest = specContent && specContent.length > 600 ? specContent.slice(0, 600) + "\n... [spec truncated \u2014 see Pass 0/1 for full text]" : specContent || "(No spec)";
|
|
6891
6887
|
const history = await loadReviewHistory(this.projectRoot);
|
|
6892
6888
|
const historyContext = buildHistoryContext(history);
|
|
6893
6889
|
const implPrompt = `Review the implementation details of this change.
|
|
6894
6890
|
|
|
6895
|
-
=== Feature Spec ===
|
|
6896
|
-
${
|
|
6897
|
-
|
|
6898
|
-
=== Code ===
|
|
6899
|
-
${codeContext}
|
|
6891
|
+
=== Feature Spec (digest \u2014 full spec was provided in Pass 0/1) ===
|
|
6892
|
+
${specDigest}
|
|
6900
6893
|
|
|
6901
6894
|
=== Architecture Review (Pass 1 \u2014 do NOT repeat these findings) ===
|
|
6902
6895
|
${archReview}
|
|
@@ -6905,11 +6898,8 @@ ${historyContext}`;
|
|
|
6905
6898
|
console.log(import_chalk12.default.gray(" Pass 3/3: Impact & complexity assessment..."));
|
|
6906
6899
|
const impactPrompt = `Assess the impact and complexity of this change.
|
|
6907
6900
|
|
|
6908
|
-
=== Feature Spec ===
|
|
6909
|
-
${
|
|
6910
|
-
|
|
6911
|
-
=== Code ===
|
|
6912
|
-
${codeContext}
|
|
6901
|
+
=== Feature Spec (digest) ===
|
|
6902
|
+
${specDigest}
|
|
6913
6903
|
|
|
6914
6904
|
=== Architecture Review (Pass 1 \u2014 do NOT repeat) ===
|
|
6915
6905
|
${archReview}
|
|
@@ -6983,8 +6973,8 @@ ${sep}
|
|
|
6983
6973
|
filesSection += `
|
|
6984
6974
|
|
|
6985
6975
|
=== ${filePath} ===
|
|
6986
|
-
${content.slice(0,
|
|
6987
|
-
if (content.length >
|
|
6976
|
+
${content.slice(0, DEFAULT_MAX_REVIEW_FILE_CHARS)}`;
|
|
6977
|
+
if (content.length > DEFAULT_MAX_REVIEW_FILE_CHARS) filesSection += `
|
|
6988
6978
|
... (truncated, ${content.length} chars total)`;
|
|
6989
6979
|
} catch {
|
|
6990
6980
|
filesSection += `
|