@clearlydev/nx-archweave 0.2.1 → 0.2.2

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.
@@ -320,13 +320,14 @@ function renderConcurrencyBlock() {
320
320
  " cancel-in-progress: false"
321
321
  ].join("\n");
322
322
  }
323
- function renderPermissionsBlock() {
324
- return ["permissions:", " contents: read", " pull-requests: write", " id-token: write"].join("\n");
323
+ var REVIEW_GATE_CONDITION = "steps.secret-gate.outputs.enabled == 'true' && steps.round-gate.outputs.allowed == 'true'";
324
+ function renderReviewPermissions(idToken) {
325
+ return ["permissions:", " contents: read", " pull-requests: write", ...idToken ? [" id-token: write"] : []].join("\n");
325
326
  }
326
327
  function renderCheckoutStep(gateCondition, extraWith = []) {
327
328
  return [
328
329
  "- name: Checkout repository",
329
- ` if: ${gateCondition}`,
330
+ ...gateCondition === void 0 ? [] : [` if: ${gateCondition}`],
330
331
  ` uses: ${pinnedUses("actions/checkout")}`,
331
332
  " with:",
332
333
  ...extraWith.map((line) => ` ${line}`),
@@ -368,10 +369,46 @@ function renderRoundGateStep(maxRounds) {
368
369
  " fi"
369
370
  ].join("\n");
370
371
  }
372
+ var JUDGE_CONDITION = "steps.ai-review-result.outputs.run == 'true'";
373
+ function renderAiReviewResultStep() {
374
+ return [
375
+ "- name: Check the AI review result",
376
+ " id: ai-review-result",
377
+ " env:",
378
+ " AI_REVIEW_RESULT: ${{ needs.ai-review.result }}",
379
+ " REVIEW_ENABLED: ${{ needs.ai-review.outputs.enabled }}",
380
+ " REVIEW_ALLOWED: ${{ needs.ai-review.outputs.allowed }}",
381
+ " LAST_COMMENT_ID: ${{ needs.ai-review.outputs.last-comment-id }}",
382
+ " run: |",
383
+ ' if [ "$AI_REVIEW_RESULT" != success ]; then',
384
+ ` echo "::error title=AI review did not succeed::The AI review job ended with '$AI_REVIEW_RESULT'."`,
385
+ " exit 1",
386
+ " fi",
387
+ ' case "$REVIEW_ENABLED/$REVIEW_ALLOWED" in',
388
+ " false/* | true/false)",
389
+ ' echo "The AI review did not run (no secret, or the round limit) - nothing to judge."',
390
+ ' echo "run=false" >> "$GITHUB_OUTPUT"',
391
+ " exit 0",
392
+ " ;;",
393
+ " true/true)",
394
+ ' case "$LAST_COMMENT_ID" in',
395
+ " '' | *[!0-9]*) ;;",
396
+ " *)",
397
+ ' echo "run=true" >> "$GITHUB_OUTPUT"',
398
+ " exit 0",
399
+ " ;;",
400
+ " esac",
401
+ " ;;",
402
+ " esac",
403
+ ` echo "::error title=Review verdict not computed::The AI review job's results did not reach this job, so no verdict can be computed. Re-run all jobs."`,
404
+ " exit 1"
405
+ ].join("\n");
406
+ }
371
407
  function renderVerdictGateStep(maxRounds, locale) {
372
408
  return [
373
409
  "- name: Compute review verdict",
374
- " if: steps.secret-gate.outputs.enabled == 'true' && steps.round-gate.outputs.allowed == 'true'",
410
+ " id: verdict",
411
+ ` if: ${JUDGE_CONDITION}`,
375
412
  " env:",
376
413
  " GH_TOKEN: ${{ github.token }}",
377
414
  " GITHUB_REPOSITORY: ${{ github.repository }}",
@@ -379,7 +416,8 @@ function renderVerdictGateStep(maxRounds, locale) {
379
416
  ` ARCHWEAVE_MAX_ROUNDS: '${maxRounds}'`,
380
417
  ` ARCHWEAVE_LOCALE: '${locale}'`,
381
418
  " ARCHWEAVE_HEAD_SHA: ${{ github.event.pull_request.head.sha }}",
382
- " ARCHWEAVE_ROUND_AFTER_ID: ${{ steps.round-gate.outputs.last-comment-id }}",
419
+ " ARCHWEAVE_ROUND_AFTER_ID: ${{ needs.ai-review.outputs.last-comment-id }}",
420
+ " ARCHWEAVE_VERDICT_OUTPUT: 'github-output'",
383
421
  " run: |",
384
422
  " if [ -x node_modules/.bin/archweave-review-verdict ]; then",
385
423
  " node_modules/.bin/archweave-review-verdict",
@@ -388,16 +426,46 @@ function renderVerdictGateStep(maxRounds, locale) {
388
426
  " fi"
389
427
  ].join("\n");
390
428
  }
429
+ function renderBlockStep() {
430
+ return [
431
+ "- name: Fail on a blocking verdict",
432
+ " if: steps.verdict.outputs.blocked == 'true'",
433
+ " run: |",
434
+ ' echo "The review verdict is BLOCK - see the verdict comment on this pull request."',
435
+ " exit 1"
436
+ ].join("\n");
437
+ }
438
+ function renderVerdictCommentStep() {
439
+ return [
440
+ "- name: Post review verdict",
441
+ " env:",
442
+ " GH_TOKEN: ${{ github.token }}",
443
+ " REPOSITORY: ${{ github.repository }}",
444
+ " PR_NUMBER: ${{ github.event.pull_request.number }}",
445
+ " VERDICT_BODY: ${{ needs.review.outputs.comment-body }}",
446
+ " PREVIOUS_ID: ${{ needs.review.outputs.previous-comment-id }}",
447
+ " run: |",
448
+ ` payload=$(jq -n --arg body "$VERDICT_BODY" '{body: $body}')`,
449
+ ' case "$PREVIOUS_ID" in',
450
+ " ''|*[!0-9]*) PREVIOUS_ID= ;;",
451
+ " esac",
452
+ ` if [ -n "$PREVIOUS_ID" ] && printf '%s' "$payload" | gh api -X PATCH "repos/$REPOSITORY/issues/comments/$PREVIOUS_ID" --input - > /dev/null; then`,
453
+ " exit 0",
454
+ " fi",
455
+ ` printf '%s' "$payload" | gh api -X POST "repos/$REPOSITORY/issues/$PR_NUMBER/comments" --input - > /dev/null \\`,
456
+ ' || echo "Could not post the verdict comment (continuing)."'
457
+ ].join("\n");
458
+ }
391
459
  var SETUP_NODE_VERSION = "22";
392
460
  var FALLBACK_PNPM_VERSION = "10";
393
461
  var INSTALL_LINES = {
394
- pnpm: [" pnpm install --frozen-lockfile"],
395
- npm: [" npm ci"],
462
+ pnpm: [" pnpm install --frozen-lockfile --ignore-scripts"],
463
+ npm: [" npm ci --ignore-scripts"],
396
464
  yarn: [
397
465
  " corepack enable yarn",
398
- ' if [ "$(yarn --version | cut -d. -f1)" -ge 2 ]; then yarn install --immutable; else yarn install --frozen-lockfile; fi'
466
+ ' if [ "$(yarn --version | cut -d. -f1)" -ge 2 ]; then YARN_ENABLE_SCRIPTS=false yarn install --immutable --mode=skip-build; else yarn install --frozen-lockfile --ignore-scripts; fi'
399
467
  ],
400
- bun: [" bun install --frozen-lockfile"]
468
+ bun: [" bun install --frozen-lockfile --ignore-scripts"]
401
469
  };
402
470
  function renderPnpmVersionStep(gate) {
403
471
  return [
@@ -413,7 +481,7 @@ function renderPnpmVersionStep(gate) {
413
481
  ].join("\n");
414
482
  }
415
483
  function renderWorkspaceSetupSteps(packageManager) {
416
- const gate = " if: steps.secret-gate.outputs.enabled == 'true' && steps.round-gate.outputs.allowed == 'true'";
484
+ const gate = ` if: ${JUDGE_CONDITION}`;
417
485
  const steps = [];
418
486
  if (packageManager === "pnpm") {
419
487
  steps.push(renderPnpmVersionStep(gate));
@@ -448,6 +516,60 @@ function renderWorkspaceSetupSteps(packageManager) {
448
516
  ].join("\n"));
449
517
  return steps.join("\n\n");
450
518
  }
519
+ function renderReviewWorkflow(input, parts) {
520
+ const aiReviewSteps = [renderSecretGateStep(parts.secretName), renderRoundGateStep(input.maxRounds), ...parts.reviewSteps];
521
+ const reviewSteps = [
522
+ renderAiReviewResultStep(),
523
+ renderCheckoutStep(JUDGE_CONDITION),
524
+ renderWorkspaceSetupSteps(input.packageManager),
525
+ renderVerdictGateStep(input.maxRounds, input.locale),
526
+ renderBlockStep()
527
+ ];
528
+ return [
529
+ `name: ${parts.name}`,
530
+ "",
531
+ renderTriggerBlock(),
532
+ "",
533
+ renderConcurrencyBlock(),
534
+ "",
535
+ "permissions: {}",
536
+ "",
537
+ "jobs:",
538
+ " ai-review:",
539
+ " runs-on: ubuntu-latest",
540
+ indentBlock(renderReviewPermissions(parts.idToken), 4),
541
+ " outputs:",
542
+ " enabled: ${{ steps.secret-gate.outputs.enabled }}",
543
+ " allowed: ${{ steps.round-gate.outputs.allowed }}",
544
+ " last-comment-id: ${{ steps.round-gate.outputs.last-comment-id }}",
545
+ " steps:",
546
+ indentBlock(aiReviewSteps.join("\n\n"), 6),
547
+ "",
548
+ " review:",
549
+ " needs: ai-review",
550
+ " if: always()",
551
+ " runs-on: ubuntu-latest",
552
+ " permissions:",
553
+ " contents: read",
554
+ " pull-requests: read",
555
+ " outputs:",
556
+ " comment-body: ${{ steps.verdict.outputs.comment-body }}",
557
+ " previous-comment-id: ${{ steps.verdict.outputs.previous-comment-id }}",
558
+ " steps:",
559
+ indentBlock(reviewSteps.join("\n\n"), 6),
560
+ "",
561
+ " review-comment:",
562
+ " needs: review",
563
+ // Runs after a BLOCK failed the review job, too: the comment explains the red check.
564
+ " if: ${{ !cancelled() && needs.review.outputs.comment-body != '' }}",
565
+ " runs-on: ubuntu-latest",
566
+ " permissions:",
567
+ " pull-requests: write",
568
+ " steps:",
569
+ indentBlock(renderVerdictCommentStep(), 6),
570
+ ""
571
+ ].join("\n");
572
+ }
451
573
 
452
574
  // ../template-engine/dist/review/claude/claude-provider.js
453
575
  var SECRET_NAME = "CLAUDE_CODE_OAUTH_TOKEN";
@@ -480,40 +602,26 @@ function composePrompt(input) {
480
602
  return sections.join("\n\n---\n\n");
481
603
  }
482
604
  function buildWorkflowYaml(input) {
483
- const steps = [
484
- renderSecretGateStep(SECRET_NAME),
485
- renderRoundGateStep(input.maxRounds),
486
- renderCheckoutStep("steps.secret-gate.outputs.enabled == 'true' && steps.round-gate.outputs.allowed == 'true'"),
487
- [
488
- "- name: Run Claude review",
489
- " if: steps.secret-gate.outputs.enabled == 'true' && steps.round-gate.outputs.allowed == 'true'",
490
- ` uses: ${pinnedUses("anthropics/claude-code-action")}`,
491
- " with:",
492
- ` claude_code_oauth_token: \${{ secrets.${SECRET_NAME} }}`,
493
- " prompt: |",
494
- indentBlock(composePrompt(input), 6),
495
- " claude_args: |",
496
- ` --allowedTools "${ALLOWED_TOOLS}"`
497
- ].join("\n"),
498
- renderWorkspaceSetupSteps(input.packageManager),
499
- renderVerdictGateStep(input.maxRounds, input.locale)
500
- ];
501
- return [
502
- "name: Claude Code Review",
503
- "",
504
- renderTriggerBlock(),
505
- "",
506
- renderConcurrencyBlock(),
507
- "",
508
- renderPermissionsBlock(),
509
- "",
510
- "jobs:",
511
- " review:",
512
- " runs-on: ubuntu-latest",
513
- " steps:",
514
- indentBlock(steps.join("\n\n"), 6),
515
- ""
516
- ].join("\n");
605
+ return renderReviewWorkflow(input, {
606
+ name: "Claude Code Review",
607
+ secretName: SECRET_NAME,
608
+ // The Claude GitHub App signs in with the workflow's OIDC token (claude-code-action's FAQ).
609
+ idToken: true,
610
+ reviewSteps: [
611
+ renderCheckoutStep(REVIEW_GATE_CONDITION),
612
+ [
613
+ "- name: Run Claude review",
614
+ ` if: ${REVIEW_GATE_CONDITION}`,
615
+ ` uses: ${pinnedUses("anthropics/claude-code-action")}`,
616
+ " with:",
617
+ ` claude_code_oauth_token: \${{ secrets.${SECRET_NAME} }}`,
618
+ " prompt: |",
619
+ indentBlock(composePrompt(input), 6),
620
+ " claude_args: |",
621
+ ` --allowedTools "${ALLOWED_TOOLS}"`
622
+ ].join("\n")
623
+ ]
624
+ });
517
625
  }
518
626
  var claudeProvider = {
519
627
  id: "claude",
@@ -553,49 +661,39 @@ function composePrompt2(input) {
553
661
  return sections.join("\n\n---\n\n");
554
662
  }
555
663
  function buildWorkflowYaml2(input) {
556
- const gateCondition = "steps.secret-gate.outputs.enabled == 'true' && steps.round-gate.outputs.allowed == 'true'";
557
- const steps = [
558
- renderSecretGateStep(SECRET_NAME2),
559
- renderRoundGateStep(input.maxRounds),
560
- renderCheckoutStep(gateCondition),
561
- [
562
- "- name: Install cursor-agent CLI",
563
- ` if: ${gateCondition}`,
564
- " run: |",
565
- " curl https://cursor.com/install -fsS | bash",
566
- ' echo "$HOME/.cursor/bin" >> "$GITHUB_PATH"'
567
- ].join("\n"),
568
- [
569
- "- name: Run Cursor review",
570
- ` if: ${gateCondition}`,
571
- " env:",
572
- ` CURSOR_API_KEY: \${{ secrets.${SECRET_NAME2} }}`,
573
- " GH_TOKEN: ${{ github.token }}",
574
- " run: |",
575
- ` agent -p "$(cat <<'${PROMPT_HEREDOC_DELIMITER}'`,
576
- indentBlock(composePrompt2(input), 4),
577
- ` ${PROMPT_HEREDOC_DELIMITER}`,
578
- ' )"'
579
- ].join("\n"),
580
- renderWorkspaceSetupSteps(input.packageManager),
581
- renderVerdictGateStep(input.maxRounds, input.locale)
582
- ];
583
- return [
584
- "name: Cursor Code Review",
585
- "",
586
- renderTriggerBlock(),
587
- "",
588
- renderConcurrencyBlock(),
589
- "",
590
- renderPermissionsBlock(),
591
- "",
592
- "jobs:",
593
- " review:",
594
- " runs-on: ubuntu-latest",
595
- " steps:",
596
- indentBlock(steps.join("\n\n"), 6),
597
- ""
598
- ].join("\n");
664
+ return renderReviewWorkflow(input, {
665
+ name: "Cursor Code Review",
666
+ secretName: SECRET_NAME2,
667
+ // An API key: the Cursor CLI needs no OIDC token.
668
+ idToken: false,
669
+ reviewSteps: [
670
+ renderCheckoutStep(REVIEW_GATE_CONDITION),
671
+ [
672
+ "- name: Install cursor-agent CLI",
673
+ ` if: ${REVIEW_GATE_CONDITION}`,
674
+ " run: |",
675
+ // HTTPS only, TLS 1.2 or newer. Cursor publishes no pinned version or checksum for
676
+ // this installer; docs/pr-review.md states what that leaves open.
677
+ " curl --proto '=https' --tlsv1.2 -fsS https://cursor.com/install | bash",
678
+ // The docs name ~/.cursor/bin; the installer currently links `agent` into ~/.local/bin.
679
+ // Both go on the PATH, so the next step finds it wherever the installer puts it.
680
+ ' echo "$HOME/.local/bin" >> "$GITHUB_PATH"',
681
+ ' echo "$HOME/.cursor/bin" >> "$GITHUB_PATH"'
682
+ ].join("\n"),
683
+ [
684
+ "- name: Run Cursor review",
685
+ ` if: ${REVIEW_GATE_CONDITION}`,
686
+ " env:",
687
+ ` CURSOR_API_KEY: \${{ secrets.${SECRET_NAME2} }}`,
688
+ " GH_TOKEN: ${{ github.token }}",
689
+ " run: |",
690
+ ` agent -p "$(cat <<'${PROMPT_HEREDOC_DELIMITER}'`,
691
+ indentBlock(composePrompt2(input), 4),
692
+ ` ${PROMPT_HEREDOC_DELIMITER}`,
693
+ ' )"'
694
+ ].join("\n")
695
+ ]
696
+ });
599
697
  }
600
698
  var cursorProvider = {
601
699
  id: "cursor",
@@ -634,40 +732,26 @@ function composePrompt3(input) {
634
732
  return sections.join("\n\n---\n\n");
635
733
  }
636
734
  function buildWorkflowYaml3(input) {
637
- const steps = [
638
- renderSecretGateStep(SECRET_NAME3),
639
- renderRoundGateStep(input.maxRounds),
640
- renderCheckoutStep("steps.secret-gate.outputs.enabled == 'true' && steps.round-gate.outputs.allowed == 'true'"),
641
- [
642
- "- name: Run Gemini review",
643
- " if: steps.secret-gate.outputs.enabled == 'true' && steps.round-gate.outputs.allowed == 'true'",
644
- ` uses: ${pinnedUses("google-github-actions/run-gemini-cli")}`,
645
- " env:",
646
- " GITHUB_TOKEN: ${{ github.token }}",
647
- " with:",
648
- ` gemini_api_key: \${{ secrets.${SECRET_NAME3} }}`,
649
- " prompt: |",
650
- indentBlock(composePrompt3(input), 6)
651
- ].join("\n"),
652
- renderWorkspaceSetupSteps(input.packageManager),
653
- renderVerdictGateStep(input.maxRounds, input.locale)
654
- ];
655
- return [
656
- "name: Gemini Code Review",
657
- "",
658
- renderTriggerBlock(),
659
- "",
660
- renderConcurrencyBlock(),
661
- "",
662
- renderPermissionsBlock(),
663
- "",
664
- "jobs:",
665
- " review:",
666
- " runs-on: ubuntu-latest",
667
- " steps:",
668
- indentBlock(steps.join("\n\n"), 6),
669
- ""
670
- ].join("\n");
735
+ return renderReviewWorkflow(input, {
736
+ name: "Gemini Code Review",
737
+ secretName: SECRET_NAME3,
738
+ // An API key: run-gemini-cli uses OIDC only for Google Cloud workload identity federation.
739
+ idToken: false,
740
+ reviewSteps: [
741
+ renderCheckoutStep(REVIEW_GATE_CONDITION),
742
+ [
743
+ "- name: Run Gemini review",
744
+ ` if: ${REVIEW_GATE_CONDITION}`,
745
+ ` uses: ${pinnedUses("google-github-actions/run-gemini-cli")}`,
746
+ " env:",
747
+ " GITHUB_TOKEN: ${{ github.token }}",
748
+ " with:",
749
+ ` gemini_api_key: \${{ secrets.${SECRET_NAME3} }}`,
750
+ " prompt: |",
751
+ indentBlock(composePrompt3(input), 6)
752
+ ].join("\n")
753
+ ]
754
+ });
671
755
  }
672
756
  var geminiProvider = {
673
757
  id: "gemini",
@@ -706,64 +790,49 @@ function composePrompt4(input) {
706
790
  return sections.join("\n\n---\n\n");
707
791
  }
708
792
  function buildWorkflowYaml4(input) {
709
- const gateCondition = "steps.secret-gate.outputs.enabled == 'true' && steps.round-gate.outputs.allowed == 'true'";
710
- const steps = [
711
- renderSecretGateStep(SECRET_NAME4),
712
- renderRoundGateStep(input.maxRounds),
713
- renderCheckoutStep(gateCondition, ["ref: refs/pull/${{ github.event.pull_request.number }}/merge"]),
714
- [
715
- "- name: Fetch base and head refs for the PR",
716
- ` if: ${gateCondition}`,
717
- " env:",
718
- " PR_BASE_REF: ${{ github.event.pull_request.base.ref }}",
719
- " PR_NUMBER: ${{ github.event.pull_request.number }}",
720
- " run: |",
721
- " # Explicit destinations: the sandboxed review step has no network, so both sides",
722
- " # of the diff must survive as stable local refs (FETCH_HEAD alone is ambiguous).",
723
- " git fetch --no-tags origin \\",
724
- ' "+refs/heads/$PR_BASE_REF:refs/remotes/origin/pr-base" \\',
725
- ' "+refs/pull/$PR_NUMBER/head:refs/remotes/origin/pr-head"'
726
- ].join("\n"),
727
- [
728
- "- name: Run Codex review",
729
- " id: codex-review",
730
- ` if: ${gateCondition}`,
731
- ` uses: ${pinnedUses("openai/codex-action")}`,
732
- " with:",
733
- ` openai-api-key: \${{ secrets.${SECRET_NAME4} }}`,
734
- ' permission-profile: ":read-only"',
735
- " prompt: |",
736
- indentBlock(composePrompt4(input), 6)
737
- ].join("\n"),
738
- [
739
- "- name: Post review comment",
740
- ` if: ${gateCondition}`,
741
- " env:",
742
- " GH_TOKEN: ${{ github.token }}",
743
- " PR_NUMBER: ${{ github.event.pull_request.number }}",
744
- " REVIEW_BODY: ${{ steps.codex-review.outputs.final-message }}",
745
- " run: |",
746
- ' printf %s "$REVIEW_BODY" | gh pr comment "$PR_NUMBER" --body-file -'
747
- ].join("\n"),
748
- renderWorkspaceSetupSteps(input.packageManager),
749
- renderVerdictGateStep(input.maxRounds, input.locale)
750
- ];
751
- return [
752
- "name: GPT Code Review",
753
- "",
754
- renderTriggerBlock(),
755
- "",
756
- renderConcurrencyBlock(),
757
- "",
758
- renderPermissionsBlock(),
759
- "",
760
- "jobs:",
761
- " review:",
762
- " runs-on: ubuntu-latest",
763
- " steps:",
764
- indentBlock(steps.join("\n\n"), 6),
765
- ""
766
- ].join("\n");
793
+ return renderReviewWorkflow(input, {
794
+ name: "GPT Code Review",
795
+ secretName: SECRET_NAME4,
796
+ // An API key: codex-action needs no OIDC token.
797
+ idToken: false,
798
+ reviewSteps: [
799
+ renderCheckoutStep(REVIEW_GATE_CONDITION, ["ref: refs/pull/${{ github.event.pull_request.number }}/merge"]),
800
+ [
801
+ "- name: Fetch base and head refs for the PR",
802
+ ` if: ${REVIEW_GATE_CONDITION}`,
803
+ " env:",
804
+ " PR_BASE_REF: ${{ github.event.pull_request.base.ref }}",
805
+ " PR_NUMBER: ${{ github.event.pull_request.number }}",
806
+ " run: |",
807
+ " # Explicit destinations: the sandboxed review step has no network, so both sides",
808
+ " # of the diff must survive as stable local refs (FETCH_HEAD alone is ambiguous).",
809
+ " git fetch --no-tags origin \\",
810
+ ' "+refs/heads/$PR_BASE_REF:refs/remotes/origin/pr-base" \\',
811
+ ' "+refs/pull/$PR_NUMBER/head:refs/remotes/origin/pr-head"'
812
+ ].join("\n"),
813
+ [
814
+ "- name: Run Codex review",
815
+ " id: codex-review",
816
+ ` if: ${REVIEW_GATE_CONDITION}`,
817
+ ` uses: ${pinnedUses("openai/codex-action")}`,
818
+ " with:",
819
+ ` openai-api-key: \${{ secrets.${SECRET_NAME4} }}`,
820
+ ' permission-profile: ":read-only"',
821
+ " prompt: |",
822
+ indentBlock(composePrompt4(input), 6)
823
+ ].join("\n"),
824
+ [
825
+ "- name: Post review comment",
826
+ ` if: ${REVIEW_GATE_CONDITION}`,
827
+ " env:",
828
+ " GH_TOKEN: ${{ github.token }}",
829
+ " PR_NUMBER: ${{ github.event.pull_request.number }}",
830
+ " REVIEW_BODY: ${{ steps.codex-review.outputs.final-message }}",
831
+ " run: |",
832
+ ' printf %s "$REVIEW_BODY" | gh pr comment "$PR_NUMBER" --body-file -'
833
+ ].join("\n")
834
+ ]
835
+ });
767
836
  }
768
837
  var gptProvider = {
769
838
  id: "gpt",
@@ -1038,13 +1107,14 @@ function buildReviewConfigConsistencyCheck(root, mainWorkflowPath, mainExists, c
1038
1107
  evidence: [mainWorkflowPath, CONFIG_PATH]
1039
1108
  });
1040
1109
  }
1110
+ const earlierVersion = !/^ {2}review-comment:$/m.test(workflowContent);
1041
1111
  return createDoctorCheck({
1042
1112
  id: "review-config-consistency",
1043
1113
  label: "Review config/workflow consistency",
1044
1114
  status: "warning",
1045
- message: `${mainWorkflowPath} differs from what ${CONFIG_PATH}'s review options would generate`,
1115
+ message: earlierVersion ? `${mainWorkflowPath} was generated by an earlier nx-archweave version: it installs dependencies in the job that holds the provider secret` : `${mainWorkflowPath} differs from what ${CONFIG_PATH}'s review options would generate`,
1046
1116
  evidence: [mainWorkflowPath, CONFIG_PATH],
1047
- suggestedAction: `Re-run the add-review generator with --onConflict=overwrite to re-sync ${mainWorkflowPath} with ${CONFIG_PATH}, or update ${CONFIG_PATH} to match the installed file.`
1117
+ suggestedAction: earlierVersion ? `Re-run add-review --onConflict=overwrite to regenerate ${mainWorkflowPath}: the verdict then runs in a job without the secret, an OIDC token or install scripts. Edits you made to the file are replaced; the report shows the difference first.` : `Re-run the add-review generator with --onConflict=overwrite to re-sync ${mainWorkflowPath} with ${CONFIG_PATH}, or update ${CONFIG_PATH} to match the installed file.`
1048
1118
  });
1049
1119
  }
1050
1120