@polka-codes/cli 0.10.25 → 0.10.26

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.js CHANGED
@@ -28,11 +28,13 @@ function createProviderErrorFromStatus(provider, model, statusCode, cause) {
28
28
  return new InvalidRequestError(provider, model, `HTTP ${statusCode}`, cause);
29
29
  }
30
30
  }
31
- var UserCancelledError, ProviderError, ProviderUnavailableError, RateLimitError, ProviderTimeoutError, AuthenticationError, ModelAccessError, InvalidRequestError, QuotaExceededError, MaxRetriesExceededError;
31
+ var UserCancelledError, ConfigurationError, MissingDependencyError, ProviderError, ProviderUnavailableError, RateLimitError, ProviderTimeoutError, AuthenticationError, ModelAccessError, InvalidRequestError, MalformedResponseError, QuotaExceededError, MaxRetriesExceededError;
32
32
  var init_errors = __esm({
33
33
  "src/errors.ts"() {
34
34
  "use strict";
35
35
  UserCancelledError = createErrorClass("UserCancelledError", (args) => args[0] ?? "User cancelled");
36
+ ConfigurationError = createErrorClass("ConfigurationError", (args) => args[0]);
37
+ MissingDependencyError = createErrorClass("MissingDependencyError", (args) => args[1]);
36
38
  ProviderError = class extends Error {
37
39
  provider;
38
40
  model;
@@ -112,6 +114,17 @@ var init_errors = __esm({
112
114
  );
113
115
  }
114
116
  };
117
+ MalformedResponseError = class extends ProviderError {
118
+ constructor(provider, model, cause) {
119
+ super(
120
+ provider,
121
+ model,
122
+ `${provider} returned an invalid response for model '${model}'. This could indicate a provider issue or incompatible API version. Please try again or contact support.`,
123
+ true,
124
+ cause
125
+ );
126
+ }
127
+ };
115
128
  QuotaExceededError = class extends ProviderError {
116
129
  currentCost;
117
130
  maxCost;
@@ -208,6 +221,7 @@ var init_getModel = __esm({
208
221
  "src/getModel.ts"() {
209
222
  "use strict";
210
223
  init_env();
224
+ init_errors();
211
225
  AiProvider = /* @__PURE__ */ ((AiProvider2) => {
212
226
  AiProvider2["Anthropic"] = "anthropic";
213
227
  AiProvider2["DeepSeek"] = "deepseek";
@@ -393,7 +407,7 @@ var init_getModel = __esm({
393
407
  }
394
408
  case "openai-compatible" /* OpenAICompatible */: {
395
409
  if (!config.baseUrl) {
396
- throw new Error("OpenAI-compatible providers require a baseUrl");
410
+ throw new ConfigurationError("OpenAI-compatible providers require a baseUrl");
397
411
  }
398
412
  const openaiCompatible = createOpenAICompatible({
399
413
  apiKey: config.apiKey,
@@ -427,7 +441,7 @@ var init_getModel = __esm({
427
441
  });
428
442
 
429
443
  // src/mcp/errors.ts
430
- var McpError, McpConnectionError, McpToolError, McpServerError;
444
+ var McpError, McpConnectionError, McpTimeoutError, McpProtocolError, McpToolError, McpServerError;
431
445
  var init_errors2 = __esm({
432
446
  "src/mcp/errors.ts"() {
433
447
  "use strict";
@@ -451,6 +465,17 @@ var init_errors2 = __esm({
451
465
  this.cause = cause;
452
466
  }
453
467
  };
468
+ McpTimeoutError = class extends McpError {
469
+ constructor(serverName, timeoutSeconds) {
470
+ super(serverName, `MCP server '${serverName}' timed out after ${timeoutSeconds} seconds. The server may be slow or unresponsive.`, true);
471
+ this.timeoutSeconds = timeoutSeconds;
472
+ }
473
+ };
474
+ McpProtocolError = class extends McpError {
475
+ constructor(serverName, message) {
476
+ super(serverName, `MCP protocol error with server '${serverName}': ${message}`, false);
477
+ }
478
+ };
454
479
  McpToolError = class extends McpError {
455
480
  constructor(serverName, toolName, message, cause) {
456
481
  super(serverName, `Tool '${toolName}' on server '${serverName}' failed: ${message}`, false);
@@ -1390,6 +1415,7 @@ var init_workflow_utils = __esm({
1390
1415
  "src/workflows/workflow.utils.ts"() {
1391
1416
  "use strict";
1392
1417
  init_ApiProviderConfig();
1418
+ init_errors();
1393
1419
  unquotePath = (path12) => {
1394
1420
  if (path12.startsWith('"') && path12.endsWith('"')) {
1395
1421
  try {
@@ -1412,7 +1438,7 @@ var init_workflow_utils = __esm({
1412
1438
  checkGhInstalled = async (executeCommand5) => {
1413
1439
  const result = await executeCommand5({ command: "gh", args: ["--version"] });
1414
1440
  if (result.exitCode !== 0) {
1415
- throw new Error("GitHub CLI (gh) is not installed. Please install it from https://cli.github.com/");
1441
+ throw new MissingDependencyError("gh", "GitHub CLI (gh) is not installed. Please install it from https://cli.github.com/");
1416
1442
  }
1417
1443
  };
1418
1444
  getDefaultBranch = async (executeCommand5) => {
@@ -3317,6 +3343,7 @@ var reviewWorkflow;
3317
3343
  var init_review_workflow = __esm({
3318
3344
  "src/workflows/review.workflow.ts"() {
3319
3345
  "use strict";
3346
+ init_errors();
3320
3347
  init_tools();
3321
3348
  init_git_file_tools();
3322
3349
  init_prompts();
@@ -3360,7 +3387,7 @@ var init_review_workflow = __esm({
3360
3387
  if (pr) {
3361
3388
  const ghCheckResult = await tools.executeCommand({ command: "gh", args: ["--version"] });
3362
3389
  if (ghCheckResult.exitCode !== 0) {
3363
- throw new Error("Error: GitHub CLI (gh) is not installed. Please install it from https://cli.github.com/");
3390
+ throw new MissingDependencyError("gh", "GitHub CLI (gh) is not installed. Please install it from https://cli.github.com/");
3364
3391
  }
3365
3392
  await step(`Checking out PR #${pr}...`, async () => {
3366
3393
  const checkoutResult = await tools.executeCommand({
@@ -4057,6 +4084,7 @@ var McpManager = class {
4057
4084
  // src/options.ts
4058
4085
  init_ApiProviderConfig();
4059
4086
  init_env();
4087
+ init_errors();
4060
4088
  init_getModel();
4061
4089
  import os from "os";
4062
4090
  import { loadConfig } from "@polka-codes/cli-shared";
@@ -4082,7 +4110,7 @@ async function parseOptions(options, { cwdArg, commandName } = {}, home = os.hom
4082
4110
  const apiKey = options.apiKey || env.POLKA_API_KEY;
4083
4111
  if (apiKey) {
4084
4112
  if (!defaultProvider) {
4085
- throw new Error("Must specify a provider if providing an API key");
4113
+ throw new ConfigurationError("Must specify a provider if providing an API key");
4086
4114
  }
4087
4115
  set(config, ["providers", defaultProvider, "apiKey"], apiKey);
4088
4116
  }
@@ -4298,7 +4326,7 @@ async function confirm2(input5, context) {
4298
4326
  if (context.yes) {
4299
4327
  return true;
4300
4328
  }
4301
- await new Promise((resolve5) => setTimeout(resolve5, 50));
4329
+ await new Promise((resolve6) => setTimeout(resolve6, 50));
4302
4330
  process.stderr.write("\x07");
4303
4331
  return await inquirerConfirm({ message: input5.message });
4304
4332
  }
@@ -4306,7 +4334,7 @@ async function input2(input5, context) {
4306
4334
  if (context.yes) {
4307
4335
  return input5.default ?? "";
4308
4336
  }
4309
- await new Promise((resolve5) => setTimeout(resolve5, 50));
4337
+ await new Promise((resolve6) => setTimeout(resolve6, 50));
4310
4338
  process.stderr.write("\x07");
4311
4339
  const result = await getUserInput(input5.message, {
4312
4340
  default: input5.default
@@ -4320,12 +4348,12 @@ async function select(input5, context) {
4320
4348
  if (context.yes) {
4321
4349
  return input5.choices[0].value;
4322
4350
  }
4323
- await new Promise((resolve5) => setTimeout(resolve5, 50));
4351
+ await new Promise((resolve6) => setTimeout(resolve6, 50));
4324
4352
  process.stderr.write("\x07");
4325
4353
  return await inquirerSelect({ message: input5.message, choices: input5.choices });
4326
4354
  }
4327
4355
  async function executeCommand(input5) {
4328
- return new Promise((resolve5, reject) => {
4356
+ return new Promise((resolve6, reject) => {
4329
4357
  const child = input5.shell === true ? input5.args && input5.args.length > 0 ? (
4330
4358
  // Use shell: true with command and args as separate parameters for safety
4331
4359
  spawn(input5.command, input5.args, { shell: true, stdio: "pipe" })
@@ -4347,7 +4375,7 @@ async function executeCommand(input5) {
4347
4375
  let exitCode = null;
4348
4376
  const checkAndResolve = () => {
4349
4377
  if (stdoutEnded && stderrEnded && closeEventFired) {
4350
- resolve5({ exitCode: exitCode ?? -1, stdout, stderr });
4378
+ resolve6({ exitCode: exitCode ?? -1, stdout, stderr });
4351
4379
  }
4352
4380
  };
4353
4381
  if (child.stdout) {
@@ -4488,7 +4516,7 @@ async function generateText(input5, context) {
4488
4516
  lastError = providerError;
4489
4517
  const backoff = computeRateLimitBackoffSeconds(i);
4490
4518
  context.workflowContext.logger.debug(`Waiting ${backoff}s before retry...`);
4491
- await new Promise((resolve5) => setTimeout(resolve5, backoff * 1e3));
4519
+ await new Promise((resolve6) => setTimeout(resolve6, backoff * 1e3));
4492
4520
  continue;
4493
4521
  }
4494
4522
  throw providerError;
@@ -4761,7 +4789,9 @@ async function runWorkflow(workflow, workflowInput, options) {
4761
4789
  }
4762
4790
  }
4763
4791
  if (!commandConfig?.provider || !commandConfig.model) {
4764
- const error = new Error(`No provider configured for command: ${commandName}. Please run "polka init" to configure your AI provider.`);
4792
+ const error = new ConfigurationError(
4793
+ `No provider configured for command: ${commandName}. Please run "polka init" to configure your AI provider.`
4794
+ );
4765
4795
  logger.error(`Error: ${error.message}`);
4766
4796
  throw error;
4767
4797
  }
@@ -5373,12 +5403,112 @@ async function plan(options = {}) {
5373
5403
  });
5374
5404
  }
5375
5405
 
5406
+ // src/config-validation.ts
5407
+ import { existsSync } from "fs";
5408
+ import { homedir } from "os";
5409
+ import { join, resolve } from "path";
5410
+ import { getGlobalConfigPath as getGlobalConfigPath2, localConfigFileName, mergeConfigs, readConfig } from "@polka-codes/cli-shared";
5411
+ import { ZodError } from "zod";
5412
+ function addConfigSource(sources, path12, required) {
5413
+ const existingSource = sources.find((source) => source.path === path12);
5414
+ if (existingSource) {
5415
+ existingSource.required = existingSource.required || required;
5416
+ return;
5417
+ }
5418
+ sources.push({ path: path12, required });
5419
+ }
5420
+ function formatIssuePath(path12) {
5421
+ if (path12.length === 0) {
5422
+ return void 0;
5423
+ }
5424
+ return path12.map(String).join(".");
5425
+ }
5426
+ function normalizeValidationError(source, error) {
5427
+ if (error instanceof ZodError) {
5428
+ return error.issues.map((issue) => ({
5429
+ source,
5430
+ path: formatIssuePath(issue.path),
5431
+ message: issue.message,
5432
+ code: "invalid_schema"
5433
+ }));
5434
+ }
5435
+ if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
5436
+ return [
5437
+ {
5438
+ source,
5439
+ message: `Config file not found: ${source}`,
5440
+ code: "file_not_found"
5441
+ }
5442
+ ];
5443
+ }
5444
+ return [
5445
+ {
5446
+ source,
5447
+ message: error instanceof Error ? error.message : String(error),
5448
+ code: "invalid_yaml"
5449
+ }
5450
+ ];
5451
+ }
5452
+ function getConfigSources(paths, cwd, home, includeGlobal) {
5453
+ const sources = [];
5454
+ if (includeGlobal) {
5455
+ const globalConfigPath = getGlobalConfigPath2(home);
5456
+ if (existsSync(globalConfigPath)) {
5457
+ addConfigSource(sources, globalConfigPath, false);
5458
+ }
5459
+ }
5460
+ if (paths) {
5461
+ const explicitPaths = Array.isArray(paths) ? paths : [paths];
5462
+ for (const path12 of explicitPaths) {
5463
+ addConfigSource(sources, resolve(cwd, path12), true);
5464
+ }
5465
+ return sources;
5466
+ }
5467
+ const defaultLocalConfigPath = join(cwd, localConfigFileName);
5468
+ if (existsSync(defaultLocalConfigPath)) {
5469
+ addConfigSource(sources, defaultLocalConfigPath, false);
5470
+ }
5471
+ return sources;
5472
+ }
5473
+ async function validateConfig(paths, options = {}) {
5474
+ const cwd = options.cwd ?? process.cwd();
5475
+ const home = options.home ?? homedir();
5476
+ const includeGlobal = options.includeGlobal ?? true;
5477
+ const configSources = getConfigSources(paths, cwd, home, includeGlobal);
5478
+ if (configSources.length === 0) {
5479
+ return { valid: true, config: {} };
5480
+ }
5481
+ const configs = [];
5482
+ const errors = [];
5483
+ for (const source of configSources) {
5484
+ if (!source.required && !existsSync(source.path)) {
5485
+ continue;
5486
+ }
5487
+ try {
5488
+ configs.push(readConfig(source.path));
5489
+ } catch (error) {
5490
+ errors.push(...normalizeValidationError(source.path, error));
5491
+ }
5492
+ }
5493
+ if (errors.length > 0) {
5494
+ return { valid: false, errors };
5495
+ }
5496
+ return {
5497
+ valid: true,
5498
+ config: mergeConfigs(configs)
5499
+ };
5500
+ }
5501
+
5502
+ // src/index.ts
5503
+ init_errors();
5504
+ init_errors2();
5505
+
5376
5506
  // src/program.ts
5377
5507
  import "dotenv/config";
5378
5508
  import { Command as Command14 } from "commander";
5379
5509
 
5380
5510
  // package.json
5381
- var version = "0.10.25";
5511
+ var version = "0.10.26";
5382
5512
 
5383
5513
  // src/commands/agent.ts
5384
5514
  import { exec as exec2 } from "child_process";
@@ -5787,7 +5917,7 @@ var AgentConfigSchema = z17.object({
5787
5917
  interval: z17.number().int().positive().default(6e4)
5788
5918
  }).optional()
5789
5919
  });
5790
- function validateConfig(config) {
5920
+ function validateConfig2(config) {
5791
5921
  try {
5792
5922
  return AgentConfigSchema.parse(config);
5793
5923
  } catch (error) {
@@ -5809,7 +5939,7 @@ async function loadConfig2(cliOptions, configPath) {
5809
5939
  config = mergeConfig(config, fileConfig);
5810
5940
  }
5811
5941
  config = mergeConfig(config, cliOptions);
5812
- return validateConfig(config);
5942
+ return validateConfig2(config);
5813
5943
  }
5814
5944
  function mergeConfig(base, override) {
5815
5945
  return deepMerge(base, override, [
@@ -7919,7 +8049,7 @@ function createContinuousImprovementLoop(context, stateManager, _sessionId) {
7919
8049
  context.logger.info("[Continuous] Wait interrupted");
7920
8050
  return;
7921
8051
  }
7922
- await new Promise((resolve5) => setTimeout(resolve5, 1e3));
8052
+ await new Promise((resolve6) => setTimeout(resolve6, 1e3));
7923
8053
  }
7924
8054
  }
7925
8055
  return {
@@ -8279,10 +8409,10 @@ ${"\u2550".repeat(60)}`);
8279
8409
  input: process.stdin,
8280
8410
  output: process.stdout
8281
8411
  });
8282
- return new Promise((resolve5) => {
8412
+ return new Promise((resolve6) => {
8283
8413
  rl.question(query, (answer) => {
8284
8414
  rl.close();
8285
- resolve5(answer.trim());
8415
+ resolve6(answer.trim());
8286
8416
  });
8287
8417
  });
8288
8418
  }
@@ -9898,16 +10028,13 @@ var COMMAND_CONSTANTS = {
9898
10028
  };
9899
10029
 
9900
10030
  // src/utils/command.ts
9901
- function getGlobalOptions(command) {
9902
- return (command.parent ?? command).opts();
9903
- }
9904
10031
  function getBaseWorkflowOptions(command) {
9905
- const globalOpts = getGlobalOptions(command);
10032
+ const globalOpts = (command.parent ?? command).opts();
9906
10033
  const verbose = globalOpts.silent ? -1 : globalOpts.verbose ?? 0;
9907
10034
  const logger = createLogger({ verbose });
9908
10035
  return {
9909
- interactive: !globalOpts.yes,
9910
10036
  ...globalOpts,
10037
+ interactive: !globalOpts.yes,
9911
10038
  logger
9912
10039
  };
9913
10040
  }
@@ -9917,7 +10044,7 @@ var readStdin = async (timeoutMs = COMMAND_CONSTANTS.DEFAULT_STDIN_TIMEOUT_MS) =
9917
10044
  if (process.stdin.isTTY) {
9918
10045
  return "";
9919
10046
  }
9920
- return new Promise((resolve5, reject) => {
10047
+ return new Promise((resolve6, reject) => {
9921
10048
  let input5 = "";
9922
10049
  const cleanup = () => {
9923
10050
  if (timeoutId) clearTimeout(timeoutId);
@@ -9925,14 +10052,14 @@ var readStdin = async (timeoutMs = COMMAND_CONSTANTS.DEFAULT_STDIN_TIMEOUT_MS) =
9925
10052
  };
9926
10053
  const timeoutId = setTimeout(() => {
9927
10054
  cleanup();
9928
- resolve5(input5);
10055
+ resolve6(input5);
9929
10056
  }, timeoutMs);
9930
10057
  process.stdin.on("data", (chunk) => {
9931
10058
  input5 += chunk.toString();
9932
10059
  });
9933
10060
  process.stdin.on("end", () => {
9934
10061
  cleanup();
9935
- resolve5(input5);
10062
+ resolve6(input5);
9936
10063
  });
9937
10064
  process.stdin.on("error", (err) => {
9938
10065
  cleanup();
@@ -10022,10 +10149,10 @@ var fixCommand = new Command4("fix").description("Fix issues by running a comman
10022
10149
  });
10023
10150
 
10024
10151
  // src/commands/init.ts
10025
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
10026
- import { join as join10 } from "path";
10152
+ import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync } from "fs";
10153
+ import { join as join11 } from "path";
10027
10154
  import { confirm as confirm3, input as input4, select as select3 } from "@inquirer/prompts";
10028
- import { getGlobalConfigPath as getGlobalConfigPath2, loadConfigAtPath as loadConfigAtPath4, localConfigFileName, readConfig } from "@polka-codes/cli-shared";
10155
+ import { getGlobalConfigPath as getGlobalConfigPath3, localConfigFileName as localConfigFileName2 } from "@polka-codes/cli-shared";
10029
10156
  import { Command as Command5 } from "commander";
10030
10157
  import { set as set2 } from "lodash-es";
10031
10158
  import { parseDocument, stringify as stringify3 } from "yaml";
@@ -10085,7 +10212,7 @@ async function configPrompt(existingConfig) {
10085
10212
 
10086
10213
  // src/workflows/init-interactive.workflow.ts
10087
10214
  init_prompts();
10088
- import { join as join9 } from "path";
10215
+ import { join as join10 } from "path";
10089
10216
  import { loadConfigAtPath as loadConfigAtPath3 } from "@polka-codes/cli-shared";
10090
10217
  import { agentWorkflow as agentWorkflow12, askFollowupQuestion as askFollowupQuestion5, listFiles as listFiles10, readFile as readFile17, searchFiles as searchFiles10 } from "@polka-codes/core";
10091
10218
  import { parse as parse2, stringify as stringify2 } from "yaml";
@@ -10255,7 +10382,7 @@ Please:
10255
10382
  }
10256
10383
  const scriptDir = ".polka-scripts";
10257
10384
  const scriptFileName = `${scriptName}.ts`;
10258
- const scriptFilePath = join9(scriptDir, scriptFileName);
10385
+ const scriptFilePath = join10(scriptDir, scriptFileName);
10259
10386
  await step("save-script", async () => {
10260
10387
  await tools.writeToFile({ path: scriptFilePath, content: script });
10261
10388
  logger.info(`
@@ -10292,8 +10419,8 @@ async function createSkill(name, logger, interactive) {
10292
10419
  `Skill name '${name}' conflicts with a built-in command. Please choose a different name (e.g., '${name}-skill' or 'my-${name}')`
10293
10420
  );
10294
10421
  }
10295
- const skillDir = join10(".claude", "skills", name);
10296
- if (existsSync(skillDir)) {
10422
+ const skillDir = join11(".claude", "skills", name);
10423
+ if (existsSync2(skillDir)) {
10297
10424
  if (interactive) {
10298
10425
  const proceed = await confirm3({
10299
10426
  message: `Skill '${name}' already exists. Overwrite?`,
@@ -10310,7 +10437,7 @@ async function createSkill(name, logger, interactive) {
10310
10437
  mkdirSync(skillDir, { recursive: true });
10311
10438
  logger.info(`Created skill directory: ${skillDir}`);
10312
10439
  const template = generateSkillTemplate(name);
10313
- writeFileSync(join10(skillDir, "SKILL.md"), template);
10440
+ writeFileSync(join11(skillDir, "SKILL.md"), template);
10314
10441
  logger.info(`Created SKILL.md`);
10315
10442
  logger.info("");
10316
10443
  logger.info(`Skill '${name}' created successfully!`);
@@ -10381,8 +10508,8 @@ Add additional files like:
10381
10508
  async function createScript(name, logger, interactive, isGlobal = false) {
10382
10509
  const scriptDir = ".polka-scripts";
10383
10510
  const scriptPathConfig = `${scriptDir}/${name}.ts`;
10384
- const scriptPathActual = join10(scriptDir, `${name}.ts`);
10385
- if (existsSync(scriptPathActual)) {
10511
+ const scriptPathActual = join11(scriptDir, `${name}.ts`);
10512
+ if (existsSync2(scriptPathActual)) {
10386
10513
  if (interactive) {
10387
10514
  const proceed = await confirm3({
10388
10515
  message: `Script '${scriptPathActual}' already exists. Overwrite?`,
@@ -10396,7 +10523,7 @@ async function createScript(name, logger, interactive, isGlobal = false) {
10396
10523
  throw new Error(`Script already exists: ${scriptPathActual}`);
10397
10524
  }
10398
10525
  }
10399
- if (!existsSync(scriptDir)) {
10526
+ if (!existsSync2(scriptDir)) {
10400
10527
  mkdirSync(scriptDir, { recursive: true });
10401
10528
  logger.info(`Created directory: ${scriptDir}`);
10402
10529
  }
@@ -10422,63 +10549,65 @@ if (import.meta.main) {
10422
10549
  `;
10423
10550
  writeFileSync(scriptPathActual, template);
10424
10551
  logger.info(`Created script: ${scriptPathActual}`);
10425
- const configPath = isGlobal ? getGlobalConfigPath2() : localConfigFileName;
10426
- if (existsSync(configPath)) {
10427
- try {
10428
- const config = readConfig(configPath);
10429
- if (!config.scripts) {
10430
- config.scripts = {};
10431
- }
10432
- config.scripts[name] = {
10433
- script: scriptPathConfig,
10434
- description: `Custom script: ${name}`
10435
- };
10436
- const configContent = readFileSync(configPath, "utf-8");
10437
- let newContent = configContent;
10438
- if (!configContent.includes("scripts:")) {
10439
- newContent = `${configContent.trimEnd()}
10552
+ const configPath = isGlobal ? getGlobalConfigPath3() : localConfigFileName2;
10553
+ if (existsSync2(configPath)) {
10554
+ const validation = await validateConfig(configPath, { includeGlobal: false });
10555
+ if (!validation.valid) {
10556
+ logger.warn("Could not update config file due to validation errors:");
10557
+ for (const error of validation.errors) {
10558
+ logger.warn(` ${error.message}`);
10559
+ }
10560
+ logger.info("Add the script manually to your config:");
10561
+ logger.info(` scripts:`);
10562
+ logger.info(` ${name}:`);
10563
+ logger.info(` script: ${scriptPathConfig}`);
10564
+ logger.info(` description: Custom script: ${name}`);
10565
+ return;
10566
+ }
10567
+ const config = validation.config;
10568
+ if (!config.scripts) {
10569
+ config.scripts = {};
10570
+ }
10571
+ config.scripts[name] = {
10572
+ script: scriptPathConfig,
10573
+ description: `Custom script: ${name}`
10574
+ };
10575
+ const configContent = readFileSync(configPath, "utf-8");
10576
+ let newContent = configContent;
10577
+ if (!configContent.includes("scripts:")) {
10578
+ newContent = `${configContent.trimEnd()}
10440
10579
 
10441
10580
  scripts:
10442
10581
  ${name}:
10443
10582
  script: ${scriptPathConfig}
10444
10583
  description: Custom script: ${name}
10445
10584
  `;
10446
- } else {
10447
- try {
10448
- const doc = parseDocument(configContent);
10449
- if (!doc.has("scripts")) {
10450
- doc.set("scripts", {});
10451
- }
10452
- doc.setIn(["scripts", name], {
10453
- script: scriptPathConfig,
10454
- description: `Custom script: ${name}`
10455
- });
10456
- newContent = doc.toString();
10457
- } catch (parseError) {
10458
- logger.warn("Could not parse config file safely. Please add the script manually:");
10459
- logger.info(` scripts:`);
10460
- logger.info(` ${name}:`);
10461
- logger.info(` script: ${scriptPathConfig}`);
10462
- logger.info(` description: Custom script: ${name}`);
10463
- if (parseError instanceof Error) {
10464
- logger.debug(`Error: ${parseError.message}`);
10465
- }
10466
- return;
10585
+ } else {
10586
+ try {
10587
+ const doc = parseDocument(configContent);
10588
+ if (!doc.has("scripts")) {
10589
+ doc.set("scripts", {});
10467
10590
  }
10468
- }
10469
- writeFileSync(configPath, newContent);
10470
- logger.info(`Added script to config: ${configPath}`);
10471
- logger.info(`Run with: polka run ${name}`);
10472
- } catch (error) {
10473
- logger.warn("Could not update config file. Add the script manually:");
10474
- logger.info(` scripts:`);
10475
- logger.info(` ${name}:`);
10476
- logger.info(` script: ${scriptPathConfig}`);
10477
- logger.info(` description: Custom script: ${name}`);
10478
- if (error instanceof Error) {
10479
- logger.debug(`Error: ${error.message}`);
10591
+ doc.setIn(["scripts", name], {
10592
+ script: scriptPathConfig,
10593
+ description: `Custom script: ${name}`
10594
+ });
10595
+ newContent = doc.toString();
10596
+ } catch (parseError) {
10597
+ logger.warn("Could not parse config file safely. Please add the script manually:");
10598
+ logger.info(` scripts:`);
10599
+ logger.info(` ${name}:`);
10600
+ logger.info(` script: ${scriptPathConfig}`);
10601
+ logger.info(` description: Custom script: ${name}`);
10602
+ if (parseError instanceof Error) {
10603
+ logger.debug(`Error: ${parseError.message}`);
10604
+ }
10605
+ return;
10480
10606
  }
10481
10607
  }
10608
+ writeFileSync(configPath, newContent);
10609
+ logger.info(`Added script to config: ${configPath}`);
10610
+ logger.info(`Run with: polka run ${name}`);
10482
10611
  } else {
10483
10612
  logger.info(`Tip: Add this script to your .polkacodes.yml:`);
10484
10613
  logger.info(` scripts:`);
@@ -10547,8 +10676,8 @@ var initCommand = new Command5("init").description("Initialize polkacodes config
10547
10676
  process.exit(1);
10548
10677
  }
10549
10678
  const scriptDir = ".polka-scripts";
10550
- const scriptPath = join10(scriptDir, `${name}.ts`);
10551
- if (existsSync(scriptPath)) {
10679
+ const scriptPath = join11(scriptDir, `${name}.ts`);
10680
+ if (existsSync2(scriptPath)) {
10552
10681
  if (interactive) {
10553
10682
  const proceed = await confirm3({
10554
10683
  message: `Script '${scriptPath}' already exists. Overwrite?`,
@@ -10562,9 +10691,9 @@ var initCommand = new Command5("init").description("Initialize polkacodes config
10562
10691
  throw new Error(`Script already exists: ${scriptPath}`);
10563
10692
  }
10564
10693
  }
10565
- const globalConfigPath2 = getGlobalConfigPath2();
10694
+ const globalConfigPath2 = getGlobalConfigPath3();
10566
10695
  const isGlobal2 = options.global ?? false;
10567
- const configPath2 = isGlobal2 ? globalConfigPath2 : localConfigFileName;
10696
+ const configPath2 = isGlobal2 ? globalConfigPath2 : localConfigFileName2;
10568
10697
  await runWorkflow(
10569
10698
  initInteractiveWorkflow,
10570
10699
  {
@@ -10603,10 +10732,10 @@ var initCommand = new Command5("init").description("Initialize polkacodes config
10603
10732
  logger.info("Valid types: config, script, skill");
10604
10733
  process.exit(1);
10605
10734
  }
10606
- const globalConfigPath = getGlobalConfigPath2();
10735
+ const globalConfigPath = getGlobalConfigPath3();
10607
10736
  let isGlobal = options.global ?? false;
10608
- let configPath = isGlobal ? globalConfigPath : localConfigFileName;
10609
- const exists = existsSync(configPath);
10737
+ let configPath = isGlobal ? globalConfigPath : localConfigFileName2;
10738
+ const exists = existsSync2(configPath);
10610
10739
  if (exists) {
10611
10740
  if (interactive) {
10612
10741
  const proceed = await confirm3({
@@ -10635,11 +10764,16 @@ var initCommand = new Command5("init").description("Initialize polkacodes config
10635
10764
  }
10636
10765
  logger.info(`Config file path: ${configPath}`);
10637
10766
  let existingConfig = {};
10638
- try {
10639
- existingConfig = readConfig(configPath);
10640
- } catch (error) {
10641
- logger.error(`Unable to parse config file: ${configPath}`, error);
10642
- throw error;
10767
+ if (existsSync2(configPath)) {
10768
+ const validation = await validateConfig(configPath, { includeGlobal: false });
10769
+ if (!validation.valid) {
10770
+ logger.error(`Config validation failed for ${configPath}:`);
10771
+ for (const error of validation.errors) {
10772
+ logger.error(` ${error.code}: ${error.message}`);
10773
+ }
10774
+ throw new Error(`Invalid config file: ${configPath}`);
10775
+ }
10776
+ existingConfig = validation.config;
10643
10777
  }
10644
10778
  const providerConfig = await configPrompt({});
10645
10779
  const { provider, model, apiKey } = providerConfig;
@@ -10659,7 +10793,8 @@ var initCommand = new Command5("init").description("Initialize polkacodes config
10659
10793
  case "local":
10660
10794
  break;
10661
10795
  case "global": {
10662
- const globalConfig = loadConfigAtPath4(globalConfigPath) ?? {};
10796
+ const globalValidation = await validateConfig(globalConfigPath, { includeGlobal: false });
10797
+ const globalConfig = globalValidation.valid ? globalValidation.config : {};
10663
10798
  set2(globalConfig, ["providers", provider, "apiKey"], apiKey);
10664
10799
  writeFileSync(globalConfigPath, stringify3(globalConfig));
10665
10800
  logger.info(`API key saved to global config file: ${globalConfigPath}`);
@@ -10668,7 +10803,7 @@ var initCommand = new Command5("init").description("Initialize polkacodes config
10668
10803
  }
10669
10804
  case "env": {
10670
10805
  let envFileContent = "";
10671
- const envExists = existsSync(".env");
10806
+ const envExists = existsSync2(".env");
10672
10807
  if (envExists) {
10673
10808
  envFileContent = readFileSync(".env", "utf-8");
10674
10809
  if (!envFileContent.endsWith("\n")) envFileContent += "\n";
@@ -10808,7 +10943,7 @@ async function startStdioServer(server, logger) {
10808
10943
 
10809
10944
  // src/mcp-server/tools.ts
10810
10945
  import * as path11 from "path";
10811
- import { getGlobalConfigPath as getGlobalConfigPath3, loadConfigAtPath as loadConfigAtPath5, MemoryManager as MemoryManager2, SQLiteMemoryStore as SQLiteMemoryStore2 } from "@polka-codes/cli-shared";
10946
+ import { getGlobalConfigPath as getGlobalConfigPath4, loadConfigAtPath as loadConfigAtPath4, MemoryManager as MemoryManager2, SQLiteMemoryStore as SQLiteMemoryStore2 } from "@polka-codes/cli-shared";
10812
10947
  import { DEFAULT_MEMORY_CONFIG as DEFAULT_MEMORY_CONFIG2, resolveHomePath as resolveHomePath2 } from "@polka-codes/core";
10813
10948
  import { z as z20 } from "zod";
10814
10949
  init_code_workflow();
@@ -10823,8 +10958,8 @@ async function getMemoryStore(logger, projectPath) {
10823
10958
  return cached;
10824
10959
  }
10825
10960
  try {
10826
- const globalConfigPath = getGlobalConfigPath3();
10827
- const config = await loadConfigAtPath5(globalConfigPath);
10961
+ const globalConfigPath = getGlobalConfigPath4();
10962
+ const config = await loadConfigAtPath4(globalConfigPath);
10828
10963
  const memoryConfig = config?.memory || DEFAULT_MEMORY_CONFIG2;
10829
10964
  if (!memoryConfig.enabled || memoryConfig.type === "memory") {
10830
10965
  return null;
@@ -11607,18 +11742,18 @@ var mcpServerCommand = new Command6("mcp-server").description("Start polka-codes
11607
11742
 
11608
11743
  // src/commands/memory.ts
11609
11744
  import { mkdir as mkdir7, readFile as readFile18, writeFile as writeFile6 } from "fs/promises";
11610
- import { dirname as dirname5, resolve as resolve3 } from "path";
11745
+ import { dirname as dirname5, resolve as resolve4 } from "path";
11611
11746
  import {
11612
11747
  detectProjectScope as detectProjectScope2,
11613
- getGlobalConfigPath as getGlobalConfigPath4,
11614
- loadConfigAtPath as loadConfigAtPath6,
11748
+ getGlobalConfigPath as getGlobalConfigPath5,
11749
+ loadConfigAtPath as loadConfigAtPath5,
11615
11750
  MemoryManager as MemoryManager3,
11616
11751
  SQLiteMemoryStore as SQLiteMemoryStore3
11617
11752
  } from "@polka-codes/cli-shared";
11618
11753
  import { DEFAULT_MEMORY_CONFIG as DEFAULT_MEMORY_CONFIG3, resolveHomePath as resolveHomePath3 } from "@polka-codes/core";
11619
11754
  async function getMemoryStore2() {
11620
- const globalConfigPath = getGlobalConfigPath4();
11621
- const config = await loadConfigAtPath6(globalConfigPath);
11755
+ const globalConfigPath = getGlobalConfigPath5();
11756
+ const config = await loadConfigAtPath5(globalConfigPath);
11622
11757
  const memoryConfig = config?.memory || DEFAULT_MEMORY_CONFIG3;
11623
11758
  if (!memoryConfig.enabled || memoryConfig.type === "memory") {
11624
11759
  console.error("Memory store is not enabled. Enable it in config with memory.enabled: true");
@@ -11766,7 +11901,7 @@ async function memoryExport(options) {
11766
11901
  console.error("Failed to export: query did not return entries");
11767
11902
  return;
11768
11903
  }
11769
- const outputPath = options.output ? resolve3(process.cwd(), options.output) : resolve3(process.cwd(), `memory-export-${Date.now()}.json`);
11904
+ const outputPath = options.output ? resolve4(process.cwd(), options.output) : resolve4(process.cwd(), `memory-export-${Date.now()}.json`);
11770
11905
  await mkdir7(dirname5(outputPath), { recursive: true });
11771
11906
  await writeFile6(outputPath, JSON.stringify(entries, null, 2));
11772
11907
  console.log(`Exported ${entries.length} entries to ${outputPath}`);
@@ -11777,7 +11912,7 @@ async function memoryExport(options) {
11777
11912
  async function memoryImport(inputFile, options) {
11778
11913
  const store = await getMemoryStore2();
11779
11914
  try {
11780
- const inputPath = resolve3(process.cwd(), inputFile);
11915
+ const inputPath = resolve4(process.cwd(), inputFile);
11781
11916
  const data = await readFile18(inputPath, "utf-8");
11782
11917
  let entries;
11783
11918
  try {
@@ -11873,8 +12008,8 @@ async function memoryStatus() {
11873
12008
  const store = await getMemoryStore2();
11874
12009
  try {
11875
12010
  const stats = await store.getStats();
11876
- const globalConfigPath = getGlobalConfigPath4();
11877
- const config = await loadConfigAtPath6(globalConfigPath);
12011
+ const globalConfigPath = getGlobalConfigPath5();
12012
+ const config = await loadConfigAtPath5(globalConfigPath);
11878
12013
  const memoryConfig = config?.memory || { path: "~/.config/polkacodes/memory/memory.sqlite" };
11879
12014
  const dbPath = resolveHomePath3(memoryConfig.path || "~/.config/polkacodes/memory/memory.sqlite");
11880
12015
  console.log("\nMemory Store Status:");
@@ -11925,8 +12060,8 @@ import { spawnSync as spawnSync2 } from "child_process";
11925
12060
  import { createErrorClass as createErrorClass4 } from "@polka-codes/core";
11926
12061
 
11927
12062
  // src/script/runner.ts
11928
- import { existsSync as existsSync2 } from "fs";
11929
- import { relative as relative2, resolve as resolve4 } from "path";
12063
+ import { existsSync as existsSync3 } from "fs";
12064
+ import { relative as relative2, resolve as resolve5 } from "path";
11930
12065
  import { pathToFileURL } from "url";
11931
12066
  import { createErrorClass as createErrorClass3 } from "@polka-codes/core";
11932
12067
  var ScriptValidationError = createErrorClass3(
@@ -11939,13 +12074,13 @@ var ScriptTimeoutError = createErrorClass3(
11939
12074
  );
11940
12075
  var ScriptExecutionError = createErrorClass3("ScriptExecutionError", (args) => `Script execution failed: ${args[0]}`);
11941
12076
  function validateScriptPath(scriptPath, projectRoot = process.cwd()) {
11942
- const normalizedRoot = resolve4(projectRoot);
11943
- const normalizedScript = resolve4(projectRoot, scriptPath);
12077
+ const normalizedRoot = resolve5(projectRoot);
12078
+ const normalizedScript = resolve5(projectRoot, scriptPath);
11944
12079
  const relativePath = relative2(normalizedRoot, normalizedScript);
11945
12080
  if (relativePath.startsWith("..")) {
11946
12081
  throw new ScriptValidationError(`Script path '${scriptPath}' is outside project directory`);
11947
12082
  }
11948
- if (!existsSync2(normalizedScript)) {
12083
+ if (!existsSync3(normalizedScript)) {
11949
12084
  throw new ScriptValidationError(`Script file not found: ${scriptPath}`);
11950
12085
  }
11951
12086
  const validExtensions = [".ts", ".js", ".mjs", ".cjs"];
@@ -11991,7 +12126,7 @@ var ScriptRunner = class {
11991
12126
  try {
11992
12127
  const returnValue = await this.withTimeout(timeout, async () => {
11993
12128
  const projectRoot = context.projectRoot || process.cwd();
11994
- const absolutePath = resolve4(projectRoot, scriptPath);
12129
+ const absolutePath = resolve5(projectRoot, scriptPath);
11995
12130
  const cacheBustUrl = `${pathToFileURL(absolutePath).href}?t=${Date.now()}`;
11996
12131
  const scriptModule = await import(cacheBustUrl);
11997
12132
  if (typeof scriptModule.main !== "function") {
@@ -12306,7 +12441,7 @@ var prCommand = new Command8("pr").description("Create a GitHub pull request").a
12306
12441
  });
12307
12442
 
12308
12443
  // src/commands/review.ts
12309
- import { existsSync as existsSync3 } from "fs";
12444
+ import { existsSync as existsSync4 } from "fs";
12310
12445
  import { checkbox, select as select4 } from "@inquirer/prompts";
12311
12446
  import { Command as Command9, InvalidOptionArgumentError } from "commander";
12312
12447
  init_workflow_utils();
@@ -12345,7 +12480,7 @@ var reviewCommand = new Command9("review").description("Review a GitHub pull req
12345
12480
  });
12346
12481
  let context = contextOption;
12347
12482
  let filesToReview = files;
12348
- if (files.length === 1 && !existsSync3(files[0]) && files[0].includes(" ") && !context) {
12483
+ if (files.length === 1 && !existsSync4(files[0]) && files[0].includes(" ") && !context) {
12349
12484
  logger.warn(
12350
12485
  "Warning: The argument looks like context but was passed as a file. Treating it as context. Please use --context for review instructions in the future."
12351
12486
  );
@@ -12376,7 +12511,7 @@ var reviewCommand = new Command9("review").description("Review a GitHub pull req
12376
12511
  if (yes) {
12377
12512
  shouldRunTask = true;
12378
12513
  } else if (process.stdin.isTTY && !json) {
12379
- await new Promise((resolve5) => setTimeout(resolve5, 50));
12514
+ await new Promise((resolve6) => setTimeout(resolve6, 50));
12380
12515
  try {
12381
12516
  const answer = await select4({
12382
12517
  message: "Do you wish polka-codes to address the review results?",
@@ -12822,12 +12957,33 @@ if (import.meta.main) {
12822
12957
  main();
12823
12958
  }
12824
12959
  export {
12960
+ AuthenticationError,
12961
+ ConfigurationError,
12962
+ InvalidRequestError,
12963
+ MalformedResponseError,
12964
+ MaxRetriesExceededError,
12965
+ McpConnectionError,
12966
+ McpError,
12967
+ McpProtocolError,
12968
+ McpServerError,
12969
+ McpTimeoutError,
12970
+ McpToolError,
12971
+ MissingDependencyError,
12972
+ ModelAccessError,
12973
+ ProviderError,
12974
+ ProviderTimeoutError,
12975
+ ProviderUnavailableError,
12976
+ QuotaExceededError,
12977
+ RateLimitError,
12978
+ UserCancelledError,
12825
12979
  code,
12826
12980
  commit,
12827
12981
  createPr,
12982
+ createProviderErrorFromStatus,
12828
12983
  fix,
12829
12984
  main,
12830
12985
  plan,
12831
12986
  reviewCode,
12832
- task
12987
+ task,
12988
+ validateConfig
12833
12989
  };