@pourkit/cli 0.0.0-next-20260703025114 → 0.0.0-next-20260703225916

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/cli.js CHANGED
@@ -355,8 +355,234 @@ import { Command, Option, CommanderError } from "commander";
355
355
  // shared/config.ts
356
356
  import { existsSync, readFileSync } from "fs";
357
357
  import { fileURLToPath } from "url";
358
- import { dirname, isAbsolute, join, normalize, sep, resolve } from "path";
358
+ import { dirname, join, resolve } from "path";
359
359
  import Ajv from "ajv";
360
+
361
+ // shared/config-normalization.ts
362
+ import { isAbsolute, normalize, sep } from "path";
363
+ var DEFAULT_MISSING_OR_EMPTY_OUTPUT_RETRIES = 3;
364
+ var DEFAULT_BRANCH_TEMPLATE = "pourkit/{{issue.number}}/{{issue.slug}}";
365
+ function applyOutputRetriesDefaults(retries) {
366
+ if (retries === void 0) return void 0;
367
+ return {
368
+ missingOrEmpty: retries.missingOrEmpty ?? DEFAULT_MISSING_OR_EMPTY_OUTPUT_RETRIES
369
+ };
370
+ }
371
+ function applyStageAgentDefaults(agent) {
372
+ return {
373
+ ...agent,
374
+ outputRetries: applyOutputRetriesDefaults(agent.outputRetries)
375
+ };
376
+ }
377
+ function assertRepoRelativePath(value, location) {
378
+ const normalized = normalize(value);
379
+ if (isAbsolute(value) || isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${sep}`)) {
380
+ throw new Error(
381
+ `${location} must stay within the repository and be repo-relative; got "${value}"`
382
+ );
383
+ }
384
+ }
385
+ function assertBaseBranch(value, location) {
386
+ if (value.includes("/")) {
387
+ throw new Error(
388
+ `${location} must be a local branch name, not a remote-qualified, tag, ref, or path-like name; got "${value}"`
389
+ );
390
+ }
391
+ if (/^[0-9a-f]{7,40}$/i.test(value)) {
392
+ throw new Error(
393
+ `${location} must be a branch name, not a commit SHA; got "${value}"`
394
+ );
395
+ }
396
+ }
397
+ function assertStageAgentPath(agent, location) {
398
+ if (!agent) return;
399
+ assertRepoRelativePath(agent.promptTemplate, `${location}.promptTemplate`);
400
+ }
401
+ function validateConfigSemantics(input) {
402
+ const sandbox = input.sandbox;
403
+ sandbox.copyToWorktree?.forEach((entry, index) => {
404
+ assertRepoRelativePath(entry, `sandbox.copyToWorktree[${index}]`);
405
+ });
406
+ const targetNames = /* @__PURE__ */ new Set();
407
+ for (const [targetIndex, target] of input.targets.entries()) {
408
+ if (targetNames.has(target.name)) {
409
+ throw new Error(
410
+ `Duplicate target name "${target.name}"; target names must be unique`
411
+ );
412
+ }
413
+ targetNames.add(target.name);
414
+ assertBaseBranch(target.baseBranch, `targets[${targetIndex}].baseBranch`);
415
+ assertStageAgentPath(
416
+ target.strategy.implement.builder,
417
+ `targets[${targetIndex}].strategy.implement.builder`
418
+ );
419
+ assertStageAgentPath(
420
+ target.strategy.failureResolution,
421
+ `targets[${targetIndex}].strategy.failureResolution`
422
+ );
423
+ assertStageAgentPath(
424
+ target.strategy.review.reviewer,
425
+ `targets[${targetIndex}].strategy.review.reviewer`
426
+ );
427
+ assertStageAgentPath(
428
+ target.strategy.review.refactor,
429
+ `targets[${targetIndex}].strategy.review.refactor`
430
+ );
431
+ assertStageAgentPath(
432
+ target.strategy.issueFinalReview,
433
+ `targets[${targetIndex}].strategy.issueFinalReview`
434
+ );
435
+ assertStageAgentPath(
436
+ target.strategy.finalize.prDescriptionAgent,
437
+ `targets[${targetIndex}].strategy.finalize.prDescriptionAgent`
438
+ );
439
+ }
440
+ }
441
+ function normalizePourkitConfig(input) {
442
+ const targets = input.targets.map((t) => {
443
+ const setupCommands = t.setupCommands?.map((cmd, i) => ({
444
+ command: cmd.command,
445
+ label: cmd.label ?? `check-${i}`
446
+ }));
447
+ const verifyLabeled = t.strategy.verify?.commands.map((cmd, i) => ({
448
+ command: cmd.command,
449
+ label: cmd.label ?? `check-${i}`
450
+ }));
451
+ return {
452
+ name: t.name,
453
+ baseBranch: t.baseBranch,
454
+ branchTemplate: t.branchTemplate ?? DEFAULT_BRANCH_TEMPLATE,
455
+ prdRun: t.prdRun,
456
+ setupCommands,
457
+ autoMerge: t.autoMerge ?? true,
458
+ queue: t.queue,
459
+ serena: t.serena,
460
+ strategy: {
461
+ type: "review-refactor-loop",
462
+ implement: {
463
+ builder: applyStageAgentDefaults(
464
+ t.strategy.implement.builder
465
+ )
466
+ },
467
+ failureResolution: {
468
+ agent: t.strategy.failureResolution.agent,
469
+ model: t.strategy.failureResolution.model,
470
+ variant: t.strategy.failureResolution.variant,
471
+ env: t.strategy.failureResolution.env,
472
+ promptTemplate: t.strategy.failureResolution.promptTemplate,
473
+ outputRetries: applyOutputRetriesDefaults(
474
+ t.strategy.failureResolution.outputRetries
475
+ ),
476
+ maxAttemptsPerFailure: t.strategy.failureResolution.maxAttemptsPerFailure,
477
+ failureLimits: t.strategy.failureResolution.failureLimits
478
+ },
479
+ review: {
480
+ reviewer: {
481
+ agent: t.strategy.review.reviewer.agent,
482
+ model: t.strategy.review.reviewer.model,
483
+ variant: t.strategy.review.reviewer.variant,
484
+ env: t.strategy.review.reviewer.env,
485
+ promptTemplate: t.strategy.review.reviewer.promptTemplate,
486
+ outputRetries: applyOutputRetriesDefaults(
487
+ t.strategy.review.reviewer.outputRetries
488
+ ),
489
+ criteria: t.strategy.review.reviewer.criteria,
490
+ includeReviewHistory: t.strategy.review.reviewer.includeReviewHistory
491
+ },
492
+ refactor: applyStageAgentDefaults(
493
+ t.strategy.review.refactor
494
+ ),
495
+ maxIterations: t.strategy.review.maxIterations
496
+ },
497
+ ...verifyLabeled ? { verify: { commands: verifyLabeled } } : {},
498
+ issueFinalReview: {
499
+ agent: t.strategy.issueFinalReview.agent,
500
+ model: t.strategy.issueFinalReview.model,
501
+ variant: t.strategy.issueFinalReview.variant,
502
+ env: t.strategy.issueFinalReview.env,
503
+ promptTemplate: t.strategy.issueFinalReview.promptTemplate,
504
+ outputRetries: applyOutputRetriesDefaults(
505
+ t.strategy.issueFinalReview.outputRetries
506
+ ),
507
+ maxAttempts: t.strategy.issueFinalReview.maxAttempts
508
+ },
509
+ finalize: {
510
+ prDescriptionAgent: applyStageAgentDefaults(
511
+ t.strategy.finalize.prDescriptionAgent
512
+ ),
513
+ maxAttempts: t.strategy.finalize.maxAttempts
514
+ }
515
+ }
516
+ };
517
+ });
518
+ const serenaConfig = input.serena;
519
+ const serenaDefaults = {
520
+ mcpUrl: serenaConfig?.mcpUrl ?? "http://localhost:9121/mcp",
521
+ sandboxMcpUrl: serenaConfig?.sandboxMcpUrl ?? "http://localhost:9121/mcp",
522
+ dataDir: serenaConfig?.dataDir ?? ".pourkit/serena/"
523
+ };
524
+ const serena = {
525
+ enabled: serenaConfig?.enabled ?? false,
526
+ required: serenaConfig?.required ?? false,
527
+ mcpUrl: process.env.POURKIT_SERENA_MCP_URL ?? serenaDefaults.mcpUrl,
528
+ sandboxMcpUrl: process.env.POURKIT_SERENA_SANDBOX_MCP_URL ?? serenaDefaults.sandboxMcpUrl,
529
+ dataDir: serenaDefaults.dataDir,
530
+ autoStart: serenaConfig?.autoStart ?? false
531
+ };
532
+ if (serena.mcpUrl.trim() === "") {
533
+ throw new Error("POURKIT_SERENA_MCP_URL must be a non-empty string");
534
+ }
535
+ if (serena.sandboxMcpUrl.trim() === "") {
536
+ throw new Error(
537
+ "POURKIT_SERENA_SANDBOX_MCP_URL must be a non-empty string"
538
+ );
539
+ }
540
+ const labels = input.labels;
541
+ const cleanupConfig = input.cleanup;
542
+ const sandboxInput = input.sandbox;
543
+ const checksInput = input.checks;
544
+ const memoryInput = input.memory;
545
+ return {
546
+ targets,
547
+ labels: {
548
+ readyForAgent: labels?.readyForAgent ?? "ready-for-agent",
549
+ agentInProgress: labels?.agentInProgress ?? "agent-in-progress",
550
+ blocked: labels?.blocked ?? "blocked",
551
+ prOpenAwaitingMerge: labels?.prOpenAwaitingMerge ?? "pr-open-awaiting-merge",
552
+ readyForHuman: labels?.readyForHuman ?? "ready-for-human",
553
+ needsTriage: labels?.needsTriage ?? "needs-triage"
554
+ },
555
+ sandbox: {
556
+ provider: sandboxInput.provider,
557
+ copyToWorktree: sandboxInput.copyToWorktree,
558
+ mounts: sandboxInput.mounts ? sandboxInput.mounts.map((m) => ({
559
+ hostPath: m.hostPath,
560
+ sandboxPath: m.sandboxPath,
561
+ readonly: m.readonly ?? false
562
+ })) : void 0,
563
+ env: sandboxInput.env,
564
+ idleTimeoutSeconds: sandboxInput.idleTimeoutSeconds,
565
+ forceRebuild: sandboxInput.forceRebuild
566
+ },
567
+ checks: {
568
+ requiredLabels: checksInput.requiredLabels,
569
+ allowedAuthors: checksInput.allowedAuthors,
570
+ checksFoundTimeoutSeconds: checksInput.checksFoundTimeoutSeconds ?? 60,
571
+ checksCompletionTimeoutSeconds: checksInput.checksCompletionTimeoutSeconds ?? 30 * 60,
572
+ pollIntervalSeconds: checksInput.pollIntervalSeconds ?? 15,
573
+ issueListLimit: checksInput.issueListLimit ?? 50
574
+ },
575
+ serena,
576
+ cleanup: {
577
+ enabled: cleanupConfig?.enabled ?? true,
578
+ worktreeRetentionDays: cleanupConfig?.worktreeRetentionDays ?? 14,
579
+ logRetentionDays: cleanupConfig?.logRetentionDays ?? 30
580
+ },
581
+ memory: memoryInput
582
+ };
583
+ }
584
+
585
+ // shared/config.ts
360
586
  var __filename = fileURLToPath(import.meta.url);
361
587
  var __dirname = dirname(__filename);
362
588
  function resolvePackagedAssetPath(fileName) {
@@ -386,8 +612,6 @@ function getValidator() {
386
612
  }
387
613
  return _validate;
388
614
  }
389
- var DEFAULT_MISSING_OR_EMPTY_OUTPUT_RETRIES = 3;
390
- var DEFAULT_BRANCH_TEMPLATE = "pourkit/{{issue.number}}/{{issue.slug}}";
391
615
  function resolveMissingOrEmptyOutputRetries(config) {
392
616
  return config?.outputRetries?.missingOrEmpty ?? DEFAULT_MISSING_OR_EMPTY_OUTPUT_RETRIES;
393
617
  }
@@ -555,98 +779,6 @@ function formatFirstAjvError(errors) {
555
779
  }
556
780
  return `${path9 || "Config"} ${error.message || "is invalid"}`;
557
781
  }
558
- function applyOutputRetriesDefaults(retries) {
559
- if (retries === void 0) return void 0;
560
- return {
561
- missingOrEmpty: retries.missingOrEmpty ?? DEFAULT_MISSING_OR_EMPTY_OUTPUT_RETRIES
562
- };
563
- }
564
- function applyStageAgentDefaults(agent) {
565
- return {
566
- ...agent,
567
- outputRetries: applyOutputRetriesDefaults(agent.outputRetries)
568
- };
569
- }
570
- function assertRepoRelativePath(value, location) {
571
- const normalized = normalize(value);
572
- if (isAbsolute(value) || isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${sep}`)) {
573
- throw new Error(
574
- `${location} must stay within the repository and be repo-relative; got "${value}"`
575
- );
576
- }
577
- }
578
- function assertBaseBranch(value, location) {
579
- if (value.includes("/")) {
580
- throw new Error(
581
- `${location} must be a local branch name, not a remote-qualified, tag, ref, or path-like name; got "${value}"`
582
- );
583
- }
584
- if (/^[0-9a-f]{7,40}$/i.test(value)) {
585
- throw new Error(
586
- `${location} must be a branch name, not a commit SHA; got "${value}"`
587
- );
588
- }
589
- }
590
- function assertStageAgentPath(agent, location) {
591
- if (!agent) return;
592
- const promptTemplate = agent.promptTemplate;
593
- if (typeof promptTemplate === "string") {
594
- assertRepoRelativePath(promptTemplate, `${location}.promptTemplate`);
595
- }
596
- }
597
- function validateConfigSemantics(data) {
598
- const sandbox = data.sandbox;
599
- const copyToWorktree = sandbox?.copyToWorktree;
600
- copyToWorktree?.forEach((entry, index) => {
601
- assertRepoRelativePath(entry, `sandbox.copyToWorktree[${index}]`);
602
- });
603
- const targetNames = /* @__PURE__ */ new Set();
604
- data.targets.forEach((target, targetIndex) => {
605
- const name = target.name;
606
- if (targetNames.has(name)) {
607
- throw new Error(
608
- `Duplicate target name "${name}"; target names must be unique`
609
- );
610
- }
611
- targetNames.add(name);
612
- assertBaseBranch(
613
- target.baseBranch,
614
- `targets[${targetIndex}].baseBranch`
615
- );
616
- const strategy = target.strategy;
617
- const implement = strategy.implement;
618
- const review = strategy.review;
619
- const finalize = strategy.finalize;
620
- assertStageAgentPath(
621
- implement.builder,
622
- `targets[${targetIndex}].strategy.implement.builder`
623
- );
624
- assertStageAgentPath(
625
- strategy.conflictResolution,
626
- `targets[${targetIndex}].strategy.conflictResolution`
627
- );
628
- assertStageAgentPath(
629
- strategy.failureResolution,
630
- `targets[${targetIndex}].strategy.failureResolution`
631
- );
632
- assertStageAgentPath(
633
- review.reviewer,
634
- `targets[${targetIndex}].strategy.review.reviewer`
635
- );
636
- assertStageAgentPath(
637
- review.refactor,
638
- `targets[${targetIndex}].strategy.review.refactor`
639
- );
640
- assertStageAgentPath(
641
- strategy.issueFinalReview,
642
- `targets[${targetIndex}].strategy.issueFinalReview`
643
- );
644
- assertStageAgentPath(
645
- finalize.prDescriptionAgent,
646
- `targets[${targetIndex}].strategy.finalize.prDescriptionAgent`
647
- );
648
- });
649
- }
650
782
  function assertKnownKeys(value, path9, knownKeys) {
651
783
  for (const key of Object.keys(value)) {
652
784
  if (!knownKeys.includes(key)) {
@@ -731,157 +863,9 @@ function parseConfig(raw) {
731
863
  )
732
864
  );
733
865
  }
734
- const data = config;
735
- validateConfigSemantics(data);
736
- const targets = data.targets.map(
737
- (t) => {
738
- const input = t;
739
- const strategy = input.strategy;
740
- const implement = strategy.implement;
741
- const failureResolution = strategy.failureResolution;
742
- const review = strategy.review;
743
- const reviewReviewer = review.reviewer;
744
- const reviewRefactor = review.refactor;
745
- const finalize = strategy.finalize;
746
- const issueFinalReview = strategy.issueFinalReview;
747
- const setupCommands = input.setupCommands?.map((cmd, i) => ({
748
- command: cmd.command,
749
- label: cmd.label ?? `check-${i}`
750
- }));
751
- const verifyCommands = strategy.verify?.commands ? strategy.verify.commands : void 0;
752
- const verifyLabeled = verifyCommands?.map((cmd, i) => ({
753
- command: cmd.command,
754
- label: cmd.label ?? `check-${i}`
755
- }));
756
- return {
757
- name: input.name,
758
- baseBranch: input.baseBranch,
759
- branchTemplate: input.branchTemplate ?? DEFAULT_BRANCH_TEMPLATE,
760
- prdRun: input.prdRun,
761
- setupCommands,
762
- autoMerge: input.autoMerge !== void 0 ? input.autoMerge : true,
763
- queue: input.queue,
764
- serena: input.serena,
765
- strategy: {
766
- type: "review-refactor-loop",
767
- implement: {
768
- builder: applyStageAgentDefaults(
769
- implement.builder
770
- )
771
- },
772
- failureResolution: {
773
- agent: failureResolution.agent,
774
- model: failureResolution.model,
775
- variant: failureResolution.variant,
776
- env: failureResolution.env,
777
- promptTemplate: failureResolution.promptTemplate,
778
- outputRetries: applyOutputRetriesDefaults(
779
- failureResolution.outputRetries
780
- ),
781
- maxAttemptsPerFailure: failureResolution.maxAttemptsPerFailure,
782
- failureLimits: failureResolution.failureLimits
783
- },
784
- review: {
785
- reviewer: {
786
- agent: reviewReviewer.agent,
787
- model: reviewReviewer.model,
788
- variant: reviewReviewer.variant,
789
- env: reviewReviewer.env,
790
- promptTemplate: reviewReviewer.promptTemplate,
791
- outputRetries: applyOutputRetriesDefaults(
792
- reviewReviewer.outputRetries
793
- ),
794
- criteria: reviewReviewer.criteria,
795
- includeReviewHistory: reviewReviewer.includeReviewHistory
796
- },
797
- refactor: applyStageAgentDefaults(
798
- reviewRefactor
799
- ),
800
- maxIterations: review.maxIterations
801
- },
802
- ...verifyLabeled ? { verify: { commands: verifyLabeled } } : {},
803
- issueFinalReview: {
804
- ...issueFinalReview,
805
- maxAttempts: issueFinalReview.maxAttempts,
806
- outputRetries: applyOutputRetriesDefaults(
807
- issueFinalReview.outputRetries
808
- )
809
- },
810
- finalize: {
811
- prDescriptionAgent: applyStageAgentDefaults(
812
- finalize.prDescriptionAgent
813
- ),
814
- maxAttempts: finalize.maxAttempts
815
- }
816
- }
817
- };
818
- }
819
- );
820
- const serenaRaw = data.serena;
821
- const serenaDefaults = {
822
- mcpUrl: serenaRaw?.mcpUrl ?? "http://localhost:9121/mcp",
823
- sandboxMcpUrl: serenaRaw?.sandboxMcpUrl ?? "http://localhost:9121/mcp",
824
- dataDir: serenaRaw?.dataDir ?? ".pourkit/serena/"
825
- };
826
- const serena = {
827
- enabled: serenaRaw?.enabled ?? false,
828
- required: serenaRaw?.required ?? false,
829
- mcpUrl: process.env.POURKIT_SERENA_MCP_URL ?? serenaDefaults.mcpUrl,
830
- sandboxMcpUrl: process.env.POURKIT_SERENA_SANDBOX_MCP_URL ?? serenaDefaults.sandboxMcpUrl,
831
- dataDir: serenaDefaults.dataDir,
832
- autoStart: serenaRaw?.autoStart ?? false
833
- };
834
- if (serena.mcpUrl.trim() === "") {
835
- throw new Error("POURKIT_SERENA_MCP_URL must be a non-empty string");
836
- }
837
- if (serena.sandboxMcpUrl.trim() === "") {
838
- throw new Error(
839
- "POURKIT_SERENA_SANDBOX_MCP_URL must be a non-empty string"
840
- );
841
- }
842
- const checksRaw = data.checks;
843
- const labelsRaw = data.labels;
844
- const cleanupRaw = data.cleanup;
845
- const sandboxRaw = data.sandbox;
846
- const memoryRaw = data.memory;
847
- return {
848
- targets,
849
- labels: {
850
- readyForAgent: labelsRaw?.readyForAgent ?? "ready-for-agent",
851
- agentInProgress: labelsRaw?.agentInProgress ?? "agent-in-progress",
852
- blocked: labelsRaw?.blocked ?? "blocked",
853
- prOpenAwaitingMerge: labelsRaw?.prOpenAwaitingMerge ?? "pr-open-awaiting-merge",
854
- readyForHuman: labelsRaw?.readyForHuman ?? "ready-for-human",
855
- needsTriage: labelsRaw?.needsTriage ?? "needs-triage"
856
- },
857
- sandbox: {
858
- provider: sandboxRaw?.provider ?? "docker",
859
- copyToWorktree: sandboxRaw?.copyToWorktree,
860
- mounts: sandboxRaw?.mounts ? sandboxRaw.mounts.map((m) => ({
861
- hostPath: m.hostPath,
862
- sandboxPath: m.sandboxPath,
863
- readonly: m.readonly ?? false
864
- })) : void 0,
865
- env: sandboxRaw?.env,
866
- idleTimeoutSeconds: sandboxRaw?.idleTimeoutSeconds,
867
- forceRebuild: sandboxRaw?.forceRebuild
868
- },
869
- checks: {
870
- requiredLabels: checksRaw?.requiredLabels ?? [],
871
- allowedAuthors: checksRaw?.allowedAuthors ?? [],
872
- checksFoundTimeoutSeconds: checksRaw?.checksFoundTimeoutSeconds ?? 60,
873
- checksCompletionTimeoutSeconds: checksRaw?.checksCompletionTimeoutSeconds ?? 30 * 60,
874
- pollIntervalSeconds: checksRaw?.pollIntervalSeconds ?? 15,
875
- issueListLimit: checksRaw?.issueListLimit ?? 50
876
- },
877
- serena,
878
- cleanup: {
879
- enabled: cleanupRaw?.enabled ?? true,
880
- worktreeRetentionDays: cleanupRaw?.worktreeRetentionDays ?? 14,
881
- logRetentionDays: cleanupRaw?.logRetentionDays ?? 30
882
- },
883
- memory: memoryRaw
884
- };
866
+ const input = raw;
867
+ validateConfigSemantics(input);
868
+ return normalizePourkitConfig(input);
885
869
  }
886
870
  function getVerificationCommands(target) {
887
871
  return target.strategy.verify?.commands ?? [];
@@ -19343,11 +19327,11 @@ function createCliProgram(version) {
19343
19327
  return program;
19344
19328
  }
19345
19329
  async function resolveCliVersion() {
19346
- if (isPackageVersion("0.0.0-next-20260703025114")) {
19347
- return "0.0.0-next-20260703025114";
19330
+ if (isPackageVersion("0.0.0-next-20260703225916")) {
19331
+ return "0.0.0-next-20260703225916";
19348
19332
  }
19349
- if (isReleaseVersion("0.0.0-next-20260703025114")) {
19350
- return "0.0.0-next-20260703025114";
19333
+ if (isReleaseVersion("0.0.0-next-20260703225916")) {
19334
+ return "0.0.0-next-20260703225916";
19351
19335
  }
19352
19336
  try {
19353
19337
  const root = repoRoot();