@corbat-tech/coco 2.0.0 → 2.1.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/dist/index.d.ts CHANGED
@@ -379,7 +379,7 @@ interface Orchestrator {
379
379
  interface OrchestratorConfig {
380
380
  projectPath: string;
381
381
  provider: {
382
- type: "anthropic" | "openai" | "gemini" | "kimi" | "lmstudio";
382
+ type: "anthropic" | "openai" | "gemini" | "kimi" | "kimi-code" | "lmstudio";
383
383
  apiKey?: string;
384
384
  model: string;
385
385
  maxTokens?: number;
@@ -500,6 +500,7 @@ declare const CocoConfigSchema: z.ZodObject<{
500
500
  openai: "openai";
501
501
  gemini: "gemini";
502
502
  kimi: "kimi";
503
+ "kimi-code": "kimi-code";
503
504
  lmstudio: "lmstudio";
504
505
  deepseek: "deepseek";
505
506
  mistral: "mistral";
@@ -2958,6 +2959,15 @@ declare class AnthropicProvider implements LLMProvider {
2958
2959
  * Ensure client is initialized
2959
2960
  */
2960
2961
  private ensureInitialized;
2962
+ /**
2963
+ * Extract system prompt from messages array or options.
2964
+ *
2965
+ * The agent-loop passes the system message as the first element of the
2966
+ * messages array (role: "system"). convertMessages() strips it out because
2967
+ * Anthropic requires it as a top-level parameter — but all callers forgot
2968
+ * to also pass it via options.system. This helper bridges that gap.
2969
+ */
2970
+ private extractSystem;
2961
2971
  /**
2962
2972
  * Convert messages to Anthropic format
2963
2973
  */
@@ -3071,7 +3081,7 @@ declare class TaskError extends CocoError {
3071
3081
  /**
3072
3082
  * Supported provider types
3073
3083
  */
3074
- type ProviderType = "anthropic" | "openai" | "codex" | "gemini" | "kimi" | "lmstudio" | "ollama" | "groq" | "openrouter" | "mistral" | "deepseek" | "together" | "huggingface";
3084
+ type ProviderType = "anthropic" | "openai" | "codex" | "gemini" | "kimi" | "kimi-code" | "lmstudio" | "ollama" | "groq" | "openrouter" | "mistral" | "deepseek" | "together" | "huggingface";
3075
3085
  /**
3076
3086
  * Create a provider by type
3077
3087
  */
package/dist/index.js CHANGED
@@ -118,6 +118,8 @@ function getApiKey(provider) {
118
118
  return process.env["GEMINI_API_KEY"] ?? process.env["GOOGLE_API_KEY"];
119
119
  case "kimi":
120
120
  return process.env["KIMI_API_KEY"] ?? process.env["MOONSHOT_API_KEY"];
121
+ case "kimi-code":
122
+ return process.env["KIMI_CODE_API_KEY"];
121
123
  case "lmstudio":
122
124
  return process.env["LMSTUDIO_API_KEY"] ?? "lm-studio";
123
125
  case "ollama":
@@ -148,6 +150,8 @@ function getBaseUrl(provider) {
148
150
  return process.env["OPENAI_BASE_URL"];
149
151
  case "kimi":
150
152
  return process.env["KIMI_BASE_URL"] ?? "https://api.moonshot.ai/v1";
153
+ case "kimi-code":
154
+ return process.env["KIMI_CODE_BASE_URL"] ?? "https://api.kimi.com/coding/v1";
151
155
  case "lmstudio":
152
156
  return process.env["LMSTUDIO_BASE_URL"] ?? "http://localhost:1234/v1";
153
157
  case "ollama":
@@ -180,6 +184,8 @@ function getDefaultModel(provider) {
180
184
  return process.env["GEMINI_MODEL"] ?? "gemini-3-flash-preview";
181
185
  case "kimi":
182
186
  return process.env["KIMI_MODEL"] ?? "kimi-k2.5";
187
+ case "kimi-code":
188
+ return process.env["KIMI_CODE_MODEL"] ?? "kimi-for-coding";
183
189
  case "lmstudio":
184
190
  return process.env["LMSTUDIO_MODEL"] ?? "local-model";
185
191
  case "ollama":
@@ -220,6 +226,7 @@ var init_env = __esm({
220
226
  "codex",
221
227
  "gemini",
222
228
  "kimi",
229
+ "kimi-code",
223
230
  "lmstudio",
224
231
  "ollama",
225
232
  "groq",
@@ -4687,7 +4694,14 @@ var BuildVerifier = class {
4687
4694
  if (!SAFE_BUILD_PATTERN.test(buildCommand.trim())) {
4688
4695
  return {
4689
4696
  success: false,
4690
- errors: [{ file: "", line: 0, column: 0, message: `Unsafe build command rejected: ${buildCommand}` }],
4697
+ errors: [
4698
+ {
4699
+ file: "",
4700
+ line: 0,
4701
+ column: 0,
4702
+ message: `Unsafe build command rejected: ${buildCommand}`
4703
+ }
4704
+ ],
4691
4705
  warnings: [],
4692
4706
  duration: Date.now() - startTime,
4693
4707
  stdout: "",
@@ -6242,9 +6256,7 @@ async function loadProjectConfig(projectPath) {
6242
6256
  const parsed = JSON.parse(raw);
6243
6257
  const result = ProjectConfigSchema.safeParse(parsed);
6244
6258
  if (!result.success) {
6245
- throw new Error(
6246
- `Invalid ${PROJECT_CONFIG_FILENAME} at ${configPath}: ${result.error.message}`
6247
- );
6259
+ throw new Error(`Invalid ${PROJECT_CONFIG_FILENAME} at ${configPath}: ${result.error.message}`);
6248
6260
  }
6249
6261
  let config = result.data;
6250
6262
  if (config.extend) {
@@ -6330,10 +6342,7 @@ function mergeThresholds(base, overrides) {
6330
6342
  }
6331
6343
  function resolvedThresholds(projectConfig) {
6332
6344
  if (!projectConfig) return DEFAULT_QUALITY_THRESHOLDS;
6333
- return mergeThresholds(
6334
- DEFAULT_QUALITY_THRESHOLDS,
6335
- thresholdsFromProjectConfig(projectConfig)
6336
- );
6345
+ return mergeThresholds(DEFAULT_QUALITY_THRESHOLDS, thresholdsFromProjectConfig(projectConfig));
6337
6346
  }
6338
6347
  function weightsFromProjectConfig(config) {
6339
6348
  const overrides = config.quality?.weights;
@@ -6416,9 +6425,7 @@ function getFileExtension(filePath) {
6416
6425
  function buildEvidence(dominant, counts, totalSourceFiles, files) {
6417
6426
  const evidence = [];
6418
6427
  const dominantCount = counts.get(dominant) ?? 0;
6419
- evidence.push(
6420
- `${dominantCount} of ${totalSourceFiles} source files are ${dominant}`
6421
- );
6428
+ evidence.push(`${dominantCount} of ${totalSourceFiles} source files are ${dominant}`);
6422
6429
  const configFiles = ["tsconfig.json", "pom.xml", "build.gradle", "Cargo.toml", "go.mod"];
6423
6430
  for (const cfg of configFiles) {
6424
6431
  if (files.some((f) => path15.basename(f) === cfg)) {
@@ -6665,10 +6672,7 @@ var JavaStyleAnalyzer = class {
6665
6672
  for (const { path: filePath, content } of files) {
6666
6673
  violations.push(...this.checkFile(filePath, content));
6667
6674
  }
6668
- const deduction = violations.reduce(
6669
- (sum, v) => sum + (v.severity === "error" ? 10 : 5),
6670
- 0
6671
- );
6675
+ const deduction = violations.reduce((sum, v) => sum + (v.severity === "error" ? 10 : 5), 0);
6672
6676
  const score = Math.max(0, 100 - deduction);
6673
6677
  return { score, violations };
6674
6678
  }
@@ -6697,7 +6701,9 @@ var JavaStyleAnalyzer = class {
6697
6701
  severity: "error"
6698
6702
  });
6699
6703
  }
6700
- const methodMatch = /\b(?:public|private|protected|static)\s+(?!class|interface|enum|record|new\b)(?:void|[\w<>[\]]+)\s+([A-Z]\w*)\s*\(/.exec(line);
6704
+ const methodMatch = /\b(?:public|private|protected|static)\s+(?!class|interface|enum|record|new\b)(?:void|[\w<>[\]]+)\s+([A-Z]\w*)\s*\(/.exec(
6705
+ line
6706
+ );
6701
6707
  if (methodMatch && !line.trim().startsWith("class") && !line.includes("class ")) {
6702
6708
  violations.push({
6703
6709
  rule: "MethodName",
@@ -6750,7 +6756,13 @@ var JavaDocumentationAnalyzer = class {
6750
6756
  async analyze(files) {
6751
6757
  const javaFiles = files ?? await findJavaFiles(this.projectPath, { srcPattern: "src/main/**/*.java" });
6752
6758
  if (!javaFiles.length) {
6753
- return { score: 100, javadocCoverage: 1, totalMethods: 0, documentedMethods: 0, undocumentedPublicMethods: [] };
6759
+ return {
6760
+ score: 100,
6761
+ javadocCoverage: 1,
6762
+ totalMethods: 0,
6763
+ documentedMethods: 0,
6764
+ undocumentedPublicMethods: []
6765
+ };
6754
6766
  }
6755
6767
  const fileContents = await Promise.all(
6756
6768
  javaFiles.map(async (f) => ({
@@ -6762,7 +6774,13 @@ var JavaDocumentationAnalyzer = class {
6762
6774
  }
6763
6775
  analyzeContent(files) {
6764
6776
  if (!files.length) {
6765
- return { score: 100, javadocCoverage: 1, totalMethods: 0, documentedMethods: 0, undocumentedPublicMethods: [] };
6777
+ return {
6778
+ score: 100,
6779
+ javadocCoverage: 1,
6780
+ totalMethods: 0,
6781
+ documentedMethods: 0,
6782
+ undocumentedPublicMethods: []
6783
+ };
6766
6784
  }
6767
6785
  let totalMethods = 0;
6768
6786
  let documentedMethods = 0;
@@ -6825,7 +6843,13 @@ var JavaCoverageAnalyzer = class {
6825
6843
  }
6826
6844
  parseJacocoXml(xml2) {
6827
6845
  if (!xml2.trim()) {
6828
- return { score: 0, lineCoverage: 0, branchCoverage: 0, methodCoverage: 0, reportFound: false };
6846
+ return {
6847
+ score: 0,
6848
+ lineCoverage: 0,
6849
+ branchCoverage: 0,
6850
+ methodCoverage: 0,
6851
+ reportFound: false
6852
+ };
6829
6853
  }
6830
6854
  const lineCoverage = this.extractCoverage(xml2, "LINE");
6831
6855
  const branchCoverage = this.extractCoverage(xml2, "BRANCH");
@@ -6834,9 +6858,7 @@ var JavaCoverageAnalyzer = class {
6834
6858
  return { score, lineCoverage, branchCoverage, methodCoverage, reportFound: true };
6835
6859
  }
6836
6860
  extractCoverage(xml2, type) {
6837
- const regex = new RegExp(
6838
- `<counter\\s+type="${type}"\\s+missed="(\\d+)"\\s+covered="(\\d+)"`
6839
- );
6861
+ const regex = new RegExp(`<counter\\s+type="${type}"\\s+missed="(\\d+)"\\s+covered="(\\d+)"`);
6840
6862
  const match = regex.exec(xml2);
6841
6863
  if (!match) return 0;
6842
6864
  const missed = parseInt(match[1] ?? "0", 10);
@@ -11498,7 +11520,7 @@ var AnthropicProvider = class {
11498
11520
  model: options?.model ?? this.config.model ?? DEFAULT_MODEL,
11499
11521
  max_tokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
11500
11522
  temperature: options?.temperature ?? this.config.temperature ?? 0,
11501
- system: options?.system,
11523
+ system: this.extractSystem(messages, options?.system),
11502
11524
  messages: this.convertMessages(messages),
11503
11525
  stop_sequences: options?.stopSequences
11504
11526
  });
@@ -11528,7 +11550,7 @@ var AnthropicProvider = class {
11528
11550
  model: options?.model ?? this.config.model ?? DEFAULT_MODEL,
11529
11551
  max_tokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
11530
11552
  temperature: options?.temperature ?? this.config.temperature ?? 0,
11531
- system: options?.system,
11553
+ system: this.extractSystem(messages, options?.system),
11532
11554
  messages: this.convertMessages(messages),
11533
11555
  tools: this.convertTools(options.tools),
11534
11556
  tool_choice: options.toolChoice ? this.convertToolChoice(options.toolChoice) : void 0
@@ -11560,7 +11582,7 @@ var AnthropicProvider = class {
11560
11582
  model: options?.model ?? this.config.model ?? DEFAULT_MODEL,
11561
11583
  max_tokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
11562
11584
  temperature: options?.temperature ?? this.config.temperature ?? 0,
11563
- system: options?.system,
11585
+ system: this.extractSystem(messages, options?.system),
11564
11586
  messages: this.convertMessages(messages)
11565
11587
  });
11566
11588
  for await (const event of stream) {
@@ -11586,7 +11608,7 @@ var AnthropicProvider = class {
11586
11608
  model: options?.model ?? this.config.model ?? DEFAULT_MODEL,
11587
11609
  max_tokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
11588
11610
  temperature: options?.temperature ?? this.config.temperature ?? 0,
11589
- system: options?.system,
11611
+ system: this.extractSystem(messages, options?.system),
11590
11612
  messages: this.convertMessages(messages),
11591
11613
  tools: this.convertTools(options.tools),
11592
11614
  tool_choice: options.toolChoice ? this.convertToolChoice(options.toolChoice) : void 0
@@ -11709,6 +11731,22 @@ var AnthropicProvider = class {
11709
11731
  });
11710
11732
  }
11711
11733
  }
11734
+ /**
11735
+ * Extract system prompt from messages array or options.
11736
+ *
11737
+ * The agent-loop passes the system message as the first element of the
11738
+ * messages array (role: "system"). convertMessages() strips it out because
11739
+ * Anthropic requires it as a top-level parameter — but all callers forgot
11740
+ * to also pass it via options.system. This helper bridges that gap.
11741
+ */
11742
+ extractSystem(messages, optionsSystem) {
11743
+ if (optionsSystem !== void 0) return optionsSystem;
11744
+ const systemMsg = messages.find((m) => m.role === "system");
11745
+ if (!systemMsg) return void 0;
11746
+ if (typeof systemMsg.content === "string") return systemMsg.content;
11747
+ const text = systemMsg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
11748
+ return text || void 0;
11749
+ }
11712
11750
  /**
11713
11751
  * Convert messages to Anthropic format
11714
11752
  */
@@ -11869,6 +11907,7 @@ var CONTEXT_WINDOWS2 = {
11869
11907
  "kimi-k2.5": 262144,
11870
11908
  "kimi-k2-0324": 131072,
11871
11909
  "kimi-latest": 131072,
11910
+ "kimi-for-coding": 131072,
11872
11911
  "moonshot-v1-8k": 8e3,
11873
11912
  "moonshot-v1-32k": 32e3,
11874
11913
  "moonshot-v1-128k": 128e3,
@@ -11945,7 +11984,12 @@ var LOCAL_MODEL_PATTERNS = [
11945
11984
  "gemma",
11946
11985
  "starcoder"
11947
11986
  ];
11948
- var MODELS_WITH_THINKING_MODE = ["kimi-k2.5", "kimi-k2-0324", "kimi-latest"];
11987
+ var MODELS_WITH_THINKING_MODE = [
11988
+ "kimi-k2.5",
11989
+ "kimi-k2-0324",
11990
+ "kimi-latest",
11991
+ "kimi-for-coding"
11992
+ ];
11949
11993
  var OpenAIProvider = class {
11950
11994
  id;
11951
11995
  name;
@@ -12564,6 +12608,20 @@ function createKimiProvider(config) {
12564
12608
  }
12565
12609
  return provider;
12566
12610
  }
12611
+ function createKimiCodeProvider(config) {
12612
+ const provider = new OpenAIProvider("kimi-code", "Kimi Code");
12613
+ const kimiCodeConfig = {
12614
+ ...config,
12615
+ baseUrl: config?.baseUrl ?? process.env["KIMI_CODE_BASE_URL"] ?? "https://api.kimi.com/coding/v1",
12616
+ apiKey: config?.apiKey ?? process.env["KIMI_CODE_API_KEY"],
12617
+ model: config?.model ?? "kimi-for-coding"
12618
+ };
12619
+ if (kimiCodeConfig.apiKey) {
12620
+ provider.initialize(kimiCodeConfig).catch(() => {
12621
+ });
12622
+ }
12623
+ return provider;
12624
+ }
12567
12625
  var OAUTH_CONFIGS = {
12568
12626
  /**
12569
12627
  * OpenAI OAuth (ChatGPT Plus/Pro subscriptions)
@@ -13067,7 +13125,7 @@ var GeminiProvider = class {
13067
13125
  temperature: options?.temperature ?? this.config.temperature ?? 0,
13068
13126
  stopSequences: options?.stopSequences
13069
13127
  },
13070
- systemInstruction: options?.system
13128
+ systemInstruction: this.extractSystem(messages, options?.system)
13071
13129
  });
13072
13130
  const { history, lastMessage } = this.convertMessages(messages);
13073
13131
  const chat = model.startChat({ history });
@@ -13095,7 +13153,7 @@ var GeminiProvider = class {
13095
13153
  maxOutputTokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
13096
13154
  temperature: options?.temperature ?? this.config.temperature ?? 0
13097
13155
  },
13098
- systemInstruction: options?.system,
13156
+ systemInstruction: this.extractSystem(messages, options?.system),
13099
13157
  tools,
13100
13158
  toolConfig: {
13101
13159
  functionCallingConfig: {
@@ -13124,7 +13182,7 @@ var GeminiProvider = class {
13124
13182
  maxOutputTokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
13125
13183
  temperature: options?.temperature ?? this.config.temperature ?? 0
13126
13184
  },
13127
- systemInstruction: options?.system
13185
+ systemInstruction: this.extractSystem(messages, options?.system)
13128
13186
  });
13129
13187
  const { history, lastMessage } = this.convertMessages(messages);
13130
13188
  const chat = model.startChat({ history });
@@ -13158,7 +13216,7 @@ var GeminiProvider = class {
13158
13216
  maxOutputTokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
13159
13217
  temperature: options?.temperature ?? this.config.temperature ?? 0
13160
13218
  },
13161
- systemInstruction: options?.system,
13219
+ systemInstruction: this.extractSystem(messages, options?.system),
13162
13220
  tools,
13163
13221
  toolConfig: {
13164
13222
  functionCallingConfig: {
@@ -13259,6 +13317,21 @@ var GeminiProvider = class {
13259
13317
  });
13260
13318
  }
13261
13319
  }
13320
+ /**
13321
+ * Extract system prompt from messages array or options.
13322
+ *
13323
+ * convertMessages() skips system-role messages ("handled via systemInstruction"),
13324
+ * but all callers forgot to also pass it via options.system. This helper bridges
13325
+ * that gap — mirrors the same fix applied to AnthropicProvider.
13326
+ */
13327
+ extractSystem(messages, optionsSystem) {
13328
+ if (optionsSystem !== void 0) return optionsSystem;
13329
+ const systemMsg = messages.find((m) => m.role === "system");
13330
+ if (!systemMsg) return void 0;
13331
+ if (typeof systemMsg.content === "string") return systemMsg.content;
13332
+ const text = systemMsg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
13333
+ return text || void 0;
13334
+ }
13262
13335
  /**
13263
13336
  * Convert messages to Gemini format
13264
13337
  */
@@ -13457,6 +13530,10 @@ async function createProvider(type, config = {}) {
13457
13530
  provider = createKimiProvider(mergedConfig);
13458
13531
  await provider.initialize(mergedConfig);
13459
13532
  return provider;
13533
+ case "kimi-code":
13534
+ provider = createKimiCodeProvider(mergedConfig);
13535
+ await provider.initialize(mergedConfig);
13536
+ return provider;
13460
13537
  case "lmstudio":
13461
13538
  provider = new OpenAIProvider("lmstudio", "LM Studio");
13462
13539
  mergedConfig.baseUrl = mergedConfig.baseUrl ?? "http://localhost:1234/v1";
@@ -13988,6 +14065,7 @@ var ProviderConfigSchema = z.object({
13988
14065
  "codex",
13989
14066
  "gemini",
13990
14067
  "kimi",
14068
+ "kimi-code",
13991
14069
  "lmstudio",
13992
14070
  "ollama",
13993
14071
  "groq",