@effect-agent/pr-review 0.1.0-beta.8 → 0.1.0-beta.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -122,6 +122,16 @@ context; a materially changed base lineage falls back to full. Re-running the
122
122
  same covered head skips model execution by default while preserving its
123
123
  stored blocking/success conclusion.
124
124
 
125
+ After a new state-bearing Action review posts, prior marker-bearing bot reviews
126
+ are retired by default: their bodies become collapsed, superseded history,
127
+ resolved findings are struck through, and matching inline comments are
128
+ minimized as outdated. Only strictly older reviews from the same GitHub actor
129
+ are eligible, so copied markers and newer concurrent reviews are untouched.
130
+ The machine-state comments remain byte-identical and terminal, so an edited
131
+ body still participates in incremental state recovery.
132
+ This cosmetic pass is fail-open and can be disabled with the Action input
133
+ `retire-stale-reviews: "false"`.
134
+
125
135
  Authentication is an explicit Effect service supplied by the Action host;
126
136
  WebCrypto import/sign/verify failures stay typed. The terminal marker is
127
137
  schema-branded and capped at 24,000 characters. If signing fails or state
package/dist/action.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { W as GitHubApiFailure, Y as ReviewPublisher, hn as PullRequestSourceFailure, lt as ReviewMode, mn as PullRequestSource, mt as ReviewStateAuthenticator, pn as PullRequestMetadata, q as PriorReviews, vn as ChangedFile } from "./fan-out-BBEATQwc.mjs";
1
+ import { An as ChangedFile, Dn as PullRequestSourceFailure, En as PullRequestSource, Et as ReviewStateAuthenticator, Tn as PullRequestMetadata, W as GitHubApiFailure, Y as ReviewPublisher, ot as ReviewRetirementHost, q as PriorReviews, xt as ReviewMode } from "./fan-out-C6gq3CFg.mjs";
2
2
  import { EffortPosition, InvalidEffortInput, ReviewProvider, ReviewRunOutcome, ReviewTargetUnresolved, RunReviewOptions } from "./index.mjs";
3
3
  import { Config, Effect, FileSystem, Schema } from "effect";
4
4
  import { BudgetExceeded } from "effect-agent";
@@ -40,6 +40,7 @@ interface ResolvedActionInputs {
40
40
  /** Deprecated compatibility input; conclusions are always conservative. */
41
41
  readonly failOn: FailOnPolicy;
42
42
  readonly skipUnchanged: boolean;
43
+ readonly retireStaleReviews: boolean;
43
44
  }
44
45
  /** Read the PR_REVIEW_* input surface (all optional, all defaulted). */
45
46
  declare const resolveActionInputs: () => Effect.Effect<{
@@ -57,6 +58,7 @@ declare const resolveActionInputs: () => Effect.Effect<{
57
58
  reviewMode: "final" | "incremental";
58
59
  failOn: "never" | "request-changes";
59
60
  skipUnchanged: boolean;
61
+ retireStaleReviews: boolean;
60
62
  }, Config.ConfigError | InvalidEffortInput | InvalidMaxDurationInput, never>;
61
63
  /** A guidance file larger than this is refused, never silently truncated. */
62
64
  declare const MAX_GUIDANCE_FILE_CHARS = 20000;
@@ -128,6 +130,8 @@ declare const runReviewAction: <E, R, FingerprintE = never, FingerprintR = never
128
130
  readonly modelLabel?: string | undefined;
129
131
  /** Explicit test/custom-host history override; GitHub owns the default adapter. */
130
132
  readonly priorReviews?: PriorReviews["Service"] | undefined;
133
+ /** Retire marker-bearing prior reviews after a successful post (default true). */
134
+ readonly retireStaleReviews?: boolean | undefined;
131
135
  }) => Effect.Effect<{
132
136
  _tag: "Skipped";
133
137
  reason: string;
@@ -135,7 +139,7 @@ declare const runReviewAction: <E, R, FingerprintE = never, FingerprintR = never
135
139
  reason?: undefined;
136
140
  _tag: "Completed";
137
141
  outcome: ReviewRunOutcome;
138
- }, E | FingerprintE | Config.ConfigError | import("effect/PlatformError").PlatformError | PullRequestSourceFailure | ReviewGateFailed | ReviewTargetUnresolved, FileSystem.FileSystem | ReviewStateAuthenticator | Exclude<FingerprintR, PriorReviews | PullRequestSource | ReviewPublisher> | Exclude<R, PriorReviews | PullRequestSource | ReviewPublisher>>;
142
+ }, E | FingerprintE | Config.ConfigError | import("effect/PlatformError").PlatformError | PullRequestSourceFailure | ReviewGateFailed | ReviewTargetUnresolved, FileSystem.FileSystem | import("effect/unstable/http/HttpClient").HttpClient | ReviewStateAuthenticator | Exclude<FingerprintR, PriorReviews | PullRequestSource | ReviewPublisher | ReviewRetirementHost> | Exclude<R, PriorReviews | PullRequestSource | ReviewPublisher | ReviewRetirementHost>>;
139
143
  /**
140
144
  * The packaged, environment-driven action program: inputs from PR_REVIEW_*,
141
145
  * reviewer built from the packaged factory, provider client from the
@@ -148,7 +152,7 @@ declare const reviewActionProgram: Effect.Effect<{
148
152
  reason?: undefined;
149
153
  _tag: "Completed";
150
154
  outcome: ReviewRunOutcome;
151
- }, import("effect-agent").AgentApprovalDenied | import("effect-agent").AgentApprovalPending | import("effect-agent").AgentChildPending | import("effect-agent").AgentInputError | import("effect-agent").AgentOutputError | import("effect-agent").AgentPolicyError | import("effect/unstable/ai/AiError").AiError | import("effect-agent").BudgetAdapterError | BudgetExceeded | Config.ConfigError | import("effect-agent").ContextOverflowError | GitHubApiFailure | GuidanceFileUnreadable | InvalidEffortInput | InvalidMaxDurationInput | import("effect-agent").ModelProtocolError | import("effect/PlatformError").PlatformError | PullRequestSourceFailure | ReviewGateFailed | ReviewTargetUnresolved | Schema.SchemaError, FileSystem.FileSystem>;
155
+ }, import("effect-agent").AgentApprovalDenied | import("effect-agent").AgentApprovalPending | import("effect-agent").AgentChildPending | import("effect-agent").AgentInputError | import("effect-agent").AgentOutputError | import("effect-agent").AgentPolicyError | import("effect/unstable/ai/AiError").AiError | import("effect-agent").BudgetAdapterError | BudgetExceeded | Config.ConfigError | import("effect-agent").ContextOverflowError | GitHubApiFailure | GuidanceFileUnreadable | InvalidEffortInput | InvalidMaxDurationInput | import("effect-agent").ModelProtocolError | import("effect/PlatformError").PlatformError | PullRequestSourceFailure | ReviewGateFailed | ReviewTargetUnresolved | Schema.SchemaError, FileSystem.FileSystem | import("effect/unstable/http/HttpClient").HttpClient>;
152
156
  /** Run the packaged action program on Node; the bundled action entrypoint. */
153
157
  declare const main: () => void;
154
158
  /** The packaged GitHub Actions surface. */
@@ -168,6 +172,7 @@ declare const PrReviewAction: {
168
172
  reviewMode: "final" | "incremental";
169
173
  failOn: "never" | "request-changes";
170
174
  skipUnchanged: boolean;
175
+ retireStaleReviews: boolean;
171
176
  }, Config.ConfigError | InvalidEffortInput | InvalidMaxDurationInput, never>;
172
177
  readonly run: typeof runReviewAction;
173
178
  readonly program: Effect.Effect<{
@@ -177,7 +182,7 @@ declare const PrReviewAction: {
177
182
  reason?: undefined;
178
183
  _tag: "Completed";
179
184
  outcome: ReviewRunOutcome;
180
- }, import("effect-agent").AgentApprovalDenied | import("effect-agent").AgentApprovalPending | import("effect-agent").AgentChildPending | import("effect-agent").AgentInputError | import("effect-agent").AgentOutputError | import("effect-agent").AgentPolicyError | import("effect/unstable/ai/AiError").AiError | import("effect-agent").BudgetAdapterError | BudgetExceeded | Config.ConfigError | import("effect-agent").ContextOverflowError | GitHubApiFailure | GuidanceFileUnreadable | InvalidEffortInput | InvalidMaxDurationInput | import("effect-agent").ModelProtocolError | import("effect/PlatformError").PlatformError | PullRequestSourceFailure | ReviewGateFailed | ReviewTargetUnresolved | Schema.SchemaError, FileSystem.FileSystem>;
185
+ }, import("effect-agent").AgentApprovalDenied | import("effect-agent").AgentApprovalPending | import("effect-agent").AgentChildPending | import("effect-agent").AgentInputError | import("effect-agent").AgentOutputError | import("effect-agent").AgentPolicyError | import("effect/unstable/ai/AiError").AiError | import("effect-agent").BudgetAdapterError | BudgetExceeded | Config.ConfigError | import("effect-agent").ContextOverflowError | GitHubApiFailure | GuidanceFileUnreadable | InvalidEffortInput | InvalidMaxDurationInput | import("effect-agent").ModelProtocolError | import("effect/PlatformError").PlatformError | PullRequestSourceFailure | ReviewGateFailed | ReviewTargetUnresolved | Schema.SchemaError, FileSystem.FileSystem | import("effect/unstable/http/HttpClient").HttpClient>;
181
186
  readonly main: typeof main;
182
187
  };
183
188
  //#endregion
package/dist/action.mjs CHANGED
@@ -1,7 +1,8 @@
1
- import { M as unavailableReviewStateAuthenticatorLayer, O as selectReviewRange, P as webCryptoReviewStateAuthenticatorLayer, i as PriorReviews, k as selectedPullRequestSourceLayer, m as ReviewHeadComparison, on as normalizeRepoRelativePath, p as ReviewExecutionContext, rn as PullRequestSource, y as ReviewStateAuthenticator } from "./github-BZNzmxao.mjs";
2
- import { A as InvalidEffortInput, M as parseEffortPosition, a as anthropicClientLayer, b as fanOutReviewBudgetLimits, c as makeOpenAiReviewModel, f as gitHubReviewLayers, h as PrReview, l as openAiClientLayer, m as resolveReviewTarget, n as DEFAULT_PROVIDER, o as describeReviewModel, p as readGitHubEvent, s as makeAnthropicReviewModel, x as reviewBudgetLimits } from "./providers-J6BKHyHe.mjs";
1
+ import { C as ReviewExecutionContext, H as unavailableReviewStateAuthenticatorLayer, R as selectReviewRange, W as webCryptoReviewStateAuthenticatorLayer, b as retireStaleReviews, gn as normalizeRepoRelativePath, i as PriorReviews, k as ReviewStateAuthenticator, pn as PullRequestSource, w as ReviewHeadComparison, z as selectedPullRequestSourceLayer } from "./github-Lfa_ox-u.mjs";
2
+ import { A as InvalidEffortInput, M as parseEffortPosition, a as anthropicClientLayer, b as fanOutReviewBudgetLimits, c as makeOpenAiReviewModel, f as gitHubReviewLayers, h as PrReview, l as openAiClientLayer, m as resolveReviewTarget, n as DEFAULT_PROVIDER, o as describeReviewModel, p as readGitHubEvent, s as makeAnthropicReviewModel, x as reviewBudgetLimits } from "./providers-CaOnz7mK.mjs";
3
3
  import { Config, Console, Effect, FileSystem, Layer, Option, Redacted, Schema } from "effect";
4
4
  import { BudgetExceeded, UsageBudgetLimits } from "effect-agent";
5
+ import { FetchHttpClient } from "effect/unstable/http";
5
6
  import { NodeRuntime, NodeServices } from "@effect/platform-node";
6
7
  //#region src/action.ts
7
8
  /** Deprecated compatibility input; host-derived conclusions are unconditional. */
@@ -48,6 +49,7 @@ const resolveActionInputs = Effect.fn("resolveActionInputs")(function* () {
48
49
  const reviewMode = yield* Config.literals(["incremental", "final"], "PR_REVIEW_MODE").pipe(Config.withDefault("incremental"));
49
50
  const failOn = yield* Config.literals(["never", "request-changes"], "PR_REVIEW_FAIL_ON").pipe(Config.withDefault("never"));
50
51
  const skipUnchanged = yield* Config.boolean("PR_REVIEW_SKIP_UNCHANGED").pipe(Config.withDefault(true));
52
+ const retireStaleReviews = yield* Config.boolean("PR_REVIEW_RETIRE_STALE_REVIEWS").pipe(Config.withDefault(true));
51
53
  return {
52
54
  provider,
53
55
  model: Option.getOrUndefined(model),
@@ -62,7 +64,8 @@ const resolveActionInputs = Effect.fn("resolveActionInputs")(function* () {
62
64
  maxDurationMinutes,
63
65
  reviewMode,
64
66
  failOn,
65
- skipUnchanged
67
+ skipUnchanged,
68
+ retireStaleReviews
66
69
  };
67
70
  });
68
71
  /** A guidance file larger than this is refused, never silently truncated. */
@@ -322,7 +325,20 @@ const runReviewAction = (reviewer, options = {}) => Effect.gen(function* () {
322
325
  });
323
326
  const outcome = yield* selection === void 0 ? reviewEffect : reviewEffect.pipe(Effect.provide(selectedPullRequestSourceLayer(selection)), Effect.provideService(ReviewExecutionContext, selection));
324
327
  yield* Console.log(`Review finished in ${outcome.turns} turn(s): verdict ${outcome.review.verdict}, ${outcome.plan.comments.length} inline comment(s), ${outcome.plan.demoted.length} demoted finding(s).`);
325
- if (outcome.published !== void 0) yield* Console.log(`Posted ${outcome.published.event} review: ${outcome.published.url}`);
328
+ if (outcome.published !== void 0) {
329
+ yield* Console.log(`Posted ${outcome.published.event} review: ${outcome.published.url}`);
330
+ if (options.retireStaleReviews !== false && outcome.state !== void 0) if (outcome.published.authorNodeId === null || outcome.published.submittedAt === null) yield* Console.warn("Skipping stale-review retirement because GitHub did not return the posted review's actor and submission time.");
331
+ else {
332
+ const report = yield* retireStaleReviews({
333
+ currentReviewId: outcome.published.reviewId,
334
+ currentReviewUrl: outcome.published.url,
335
+ currentAuthorNodeId: outcome.published.authorNodeId,
336
+ currentSubmittedAt: outcome.published.submittedAt,
337
+ currentState: outcome.state
338
+ });
339
+ yield* Console.log(`Review retirement: ${report.reviewsRetired} prior review(s), ${report.findingsResolved} resolved finding(s), ${report.commentsMinimized} minimized inline comment(s), ${report.failures} failure(s).`);
340
+ }
341
+ }
326
342
  const check = concludeReviewOutcome(outcome);
327
343
  yield* writeActionOutputs(outcomeOutputs(outcome, check.conclusion));
328
344
  yield* writeStepSummary(outcomeSummary(outcome, options.modelLabel, check.conclusion));
@@ -368,6 +384,7 @@ const reviewActionProgram = Effect.gen(function* () {
368
384
  failOn: inputs.failOn,
369
385
  skipUnchanged: inputs.skipUnchanged,
370
386
  reviewMode: inputs.reviewMode,
387
+ retireStaleReviews: inputs.retireStaleReviews,
371
388
  modelLabel
372
389
  };
373
390
  if (inputs.provider === "anthropic") {
@@ -392,7 +409,7 @@ const reviewActionProgram = Effect.gen(function* () {
392
409
  return yield* runReviewAction(reviewer, harness).pipe(Effect.provide(Layer.merge(stateAuthenticatorLayer, openAiClientLayer)));
393
410
  });
394
411
  /** Run the packaged action program on Node; the bundled action entrypoint. */
395
- const main = () => NodeRuntime.runMain(reviewActionProgram.pipe(Effect.tapError((error) => Console.error(Schema.is(BudgetExceeded)(error) ? `Budget exceeded: ${error.limit} observed ${error.observedValue}, limit ${error.limitValue}.` : String(error))), Effect.scoped, Effect.provide(NodeServices.layer)), { disableErrorReporting: true });
412
+ const main = () => NodeRuntime.runMain(reviewActionProgram.pipe(Effect.tapError((error) => Console.error(Schema.is(BudgetExceeded)(error) ? `Budget exceeded: ${error.limit} observed ${error.observedValue}, limit ${error.limitValue}.` : String(error))), Effect.scoped, Effect.provide(Layer.merge(NodeServices.layer, FetchHttpClient.layer))), { disableErrorReporting: true });
396
413
  /** The packaged GitHub Actions surface. */
397
414
  const PrReviewAction = {
398
415
  inputs: resolveActionInputs,
@@ -1 +1 @@
1
- {"version":3,"file":"action.mjs","names":[],"sources":["../src/action.ts"],"sourcesContent":["import { NodeRuntime, NodeServices } from \"@effect/platform-node\";\nimport { Config, Console, Effect, FileSystem, Layer, Option, Redacted, Schema } from \"effect\";\nimport { BudgetExceeded, UsageBudgetLimits } from \"effect-agent\";\n\nimport { InvalidEffortInput, parseEffortPosition, type EffortPosition } from \"./internal/effort.ts\";\nimport { PrReview, type RunReviewOptions } from \"./internal/factory.ts\";\nimport { readGitHubEvent, resolveReviewTarget, gitHubReviewLayers } from \"./internal/github-env.ts\";\nimport { PriorReviews } from \"./internal/github.ts\";\nimport {\n anthropicClientLayer,\n DEFAULT_PROVIDER,\n describeReviewModel,\n makeAnthropicReviewModel,\n makeOpenAiReviewModel,\n openAiClientLayer,\n type ReviewProvider,\n} from \"./internal/providers.ts\";\nimport {\n ReviewExecutionContext,\n ReviewHeadComparison,\n ReviewStateAuthenticator,\n type ReviewMode,\n type ReviewState,\n selectReviewRange,\n selectedPullRequestSourceLayer,\n unavailableReviewStateAuthenticatorLayer,\n webCryptoReviewStateAuthenticatorLayer,\n} from \"./internal/review-state.ts\";\nimport { fanOutReviewBudgetLimits, reviewBudgetLimits } from \"./internal/run.ts\";\nimport type { ReviewRunOutcome } from \"./internal/run.ts\";\nimport { normalizeRepoRelativePath, PullRequestSource } from \"./internal/source.ts\";\n\n// ---------------------------------------------------------------------------\n// The GitHub Actions entrypoint (deployment class E: one bounded ephemeral\n// run, no exactly-once posting). Bounded continuity state travels in GitHub\n// review bodies and is validated before reuse. Inputs arrive as\n// PR_REVIEW_* environment variables set by the action manifest; the target\n// pull request comes from the standard Actions event environment. A non-PR\n// or draft event is a typed skip — green job, nothing posted. Publication\n// happens only after the run settles, so a failed or truncated run posts\n// nothing.\n// ---------------------------------------------------------------------------\n\n/** Deprecated compatibility input; host-derived conclusions are unconditional. */\nexport const FailOnPolicy = Schema.Literals([\"never\", \"request-changes\"]);\nexport type FailOnPolicy = typeof FailOnPolicy.Type;\n\nexport const ReviewCheckConclusion = Schema.Literals([\"success\", \"blocking\", \"incomplete\"]);\nexport type ReviewCheckConclusion = typeof ReviewCheckConclusion.Type;\n\n/** The host-derived blocking or incomplete conclusion failed the check. */\nexport class ReviewGateFailed extends Schema.TaggedError<ReviewGateFailed>()(\"ReviewGateFailed\", {\n conclusion: Schema.Literals([\"blocking\", \"incomplete\"]),\n reasons: Schema.Array(Schema.NonEmptyString.check(Schema.isMaxLength(1_000))).check(\n Schema.isMinLength(1),\n ),\n}) {\n override get message() {\n return `Review check concluded '${this.conclusion}': ${this.reasons.join(\"; \")}`;\n }\n}\n\n/** A configured max-duration that cannot bound a run; configuration faults fail loudly. */\nexport class InvalidMaxDurationInput extends Schema.TaggedError<InvalidMaxDurationInput>()(\n \"InvalidMaxDurationInput\",\n {\n minutes: Schema.Int,\n },\n) {\n override get message() {\n return `Invalid max-duration-minutes '${this.minutes}': expected a positive number of minutes.`;\n }\n}\n\n/** Everything the packaged action reads from its environment. */\nexport interface ResolvedActionInputs {\n readonly provider: ReviewProvider;\n readonly model: string | undefined;\n readonly effort: EffortPosition | undefined;\n readonly post: boolean;\n readonly applyVerdict: boolean;\n readonly fanOut: boolean;\n readonly guidance: string | undefined;\n readonly guidanceFile: string | undefined;\n readonly ignore: ReadonlyArray<string>;\n readonly maxFindings: number | undefined;\n readonly maxDurationMinutes: number | undefined;\n readonly reviewMode: ReviewMode;\n /** Deprecated compatibility input; conclusions are always conservative. */\n readonly failOn: FailOnPolicy;\n readonly skipUnchanged: boolean;\n}\n\n/** Read the PR_REVIEW_* input surface (all optional, all defaulted). */\nexport const resolveActionInputs = Effect.fn(\"resolveActionInputs\")(function* () {\n const provider = yield* Config.literals([\"openai\", \"anthropic\"], \"PR_REVIEW_PROVIDER\").pipe(\n Config.withDefault<ReviewProvider>(DEFAULT_PROVIDER),\n );\n const model = yield* Config.option(Config.nonEmptyString(\"PR_REVIEW_MODEL\"));\n const effortRaw = yield* Config.option(Config.nonEmptyString(\"PR_REVIEW_EFFORT\"));\n let effort: EffortPosition | undefined;\n if (Option.isSome(effortRaw)) {\n effort = parseEffortPosition(effortRaw.value);\n if (effort === undefined) {\n return yield* InvalidEffortInput.make({ input: effortRaw.value });\n }\n }\n const maxDurationMinutes = Option.getOrUndefined(\n yield* Config.option(Config.int(\"PR_REVIEW_MAX_DURATION_MINUTES\")),\n );\n if (maxDurationMinutes !== undefined && maxDurationMinutes <= 0) {\n return yield* InvalidMaxDurationInput.make({ minutes: maxDurationMinutes });\n }\n const post = yield* Config.boolean(\"PR_REVIEW_POST\").pipe(Config.withDefault(true));\n const applyVerdict = yield* Config.boolean(\"PR_REVIEW_APPLY_VERDICT\").pipe(\n Config.withDefault(false),\n );\n const fanOut = yield* Config.boolean(\"PR_REVIEW_FAN_OUT\").pipe(Config.withDefault(false));\n const guidance = yield* Config.option(Config.nonEmptyString(\"PR_REVIEW_GUIDANCE\"));\n const guidanceFile = yield* Config.option(Config.nonEmptyString(\"PR_REVIEW_GUIDANCE_FILE\"));\n const ignoreRaw = yield* Config.string(\"PR_REVIEW_IGNORE\").pipe(Config.withDefault(\"\"));\n const maxFindings = yield* Config.option(Config.int(\"PR_REVIEW_MAX_FINDINGS\"));\n const reviewMode = yield* Config.literals([\"incremental\", \"final\"], \"PR_REVIEW_MODE\").pipe(\n Config.withDefault<ReviewMode>(\"incremental\"),\n );\n const failOn = yield* Config.literals([\"never\", \"request-changes\"], \"PR_REVIEW_FAIL_ON\").pipe(\n Config.withDefault<FailOnPolicy>(\"never\"),\n );\n const skipUnchanged = yield* Config.boolean(\"PR_REVIEW_SKIP_UNCHANGED\").pipe(\n Config.withDefault(true),\n );\n return {\n provider,\n model: Option.getOrUndefined(model),\n effort,\n post,\n applyVerdict,\n fanOut,\n guidance: Option.getOrUndefined(guidance),\n guidanceFile: Option.getOrUndefined(guidanceFile),\n ignore: ignoreRaw\n .split(\",\")\n .map((pattern) => pattern.trim())\n .filter((pattern) => pattern.length > 0),\n maxFindings: Option.getOrUndefined(maxFindings),\n maxDurationMinutes,\n reviewMode,\n failOn,\n skipUnchanged,\n } satisfies ResolvedActionInputs;\n});\n\n/** A guidance file larger than this is refused, never silently truncated. */\nexport const MAX_GUIDANCE_FILE_CHARS = 20_000;\n\n/** A configured guidance file could not be used; configuration faults fail loudly. */\nexport class GuidanceFileUnreadable extends Schema.TaggedError<GuidanceFileUnreadable>()(\n \"GuidanceFileUnreadable\",\n {\n path: Schema.String,\n reason: Schema.String,\n },\n) {\n override get message() {\n return `Cannot use guidance file '${this.path}': ${this.reason}`;\n }\n}\n\n/**\n * Resolve the effective review guidance: the committed guidance file (a\n * repository-owned review profile) first, with any inline guidance appended.\n * A configured-but-unreadable file fails typed — a review silently running\n * without its profile would be worse than a red job.\n */\nexport const resolveGuidance = Effect.fn(\"resolveGuidance\")(function* (inputs: {\n readonly guidance: string | undefined;\n readonly guidanceFile: string | undefined;\n}) {\n const filePath = inputs.guidanceFile;\n if (filePath === undefined) return inputs.guidance;\n // The profile path is operator configuration, but it stays fail-closed\n // like every other path in this package: workspace-relative only, and the\n // size bound is checked before the file is read into memory.\n const relative = yield* normalizeRepoRelativePath(filePath).pipe(\n Effect.mapError((violation) =>\n GuidanceFileUnreadable.make({ path: filePath, reason: violation.reason }),\n ),\n );\n const fs = yield* FileSystem.FileSystem;\n const unreadable = (error: { readonly _tag: string; readonly message: string }) =>\n GuidanceFileUnreadable.make({\n path: relative,\n reason: `${error._tag}: ${error.message}`.slice(0, 2_048),\n });\n const stat = yield* fs.stat(relative).pipe(Effect.mapError(unreadable));\n const oversized = GuidanceFileUnreadable.make({\n path: relative,\n reason: `File is larger than the ${MAX_GUIDANCE_FILE_CHARS}-character guidance bound.`,\n });\n if (stat.size > BigInt(MAX_GUIDANCE_FILE_CHARS) * 4n) {\n return yield* oversized;\n }\n const content = yield* fs.readFileString(relative).pipe(Effect.mapError(unreadable));\n if (content.length > MAX_GUIDANCE_FILE_CHARS) {\n return yield* oversized;\n }\n const combined = [content.trim(), inputs.guidance ?? \"\"]\n .filter((part) => part.length > 0)\n .join(\"\\n\");\n return combined.length > 0 ? combined : undefined;\n});\n\n/** One step-output line; values must be single-line by construction. */\nconst outputLine = (name: string, value: string): string =>\n `${name}=${value.replaceAll(\"\\n\", \" \").slice(0, 1_000)}\\n`;\n\n/** Append step outputs to GITHUB_OUTPUT when present (no-op locally). */\nexport const writeActionOutputs = Effect.fn(\"writeActionOutputs\")(function* (\n entries: ReadonlyArray<readonly [name: string, value: string]>,\n) {\n const outputPath = yield* Config.string(\"GITHUB_OUTPUT\").pipe(Config.withDefault(\"\"));\n if (outputPath === \"\") return;\n const fs = yield* FileSystem.FileSystem;\n yield* fs.writeFileString(\n outputPath,\n entries.map(([name, value]) => outputLine(name, value)).join(\"\"),\n {\n flag: \"a\",\n },\n );\n});\n\n/** Append markdown to the GITHUB_STEP_SUMMARY report when present (no-op locally). */\nexport const writeStepSummary = Effect.fn(\"writeStepSummary\")(function* (\n lines: ReadonlyArray<string>,\n) {\n const summaryPath = yield* Config.string(\"GITHUB_STEP_SUMMARY\").pipe(Config.withDefault(\"\"));\n if (summaryPath === \"\") return;\n const fs = yield* FileSystem.FileSystem;\n yield* fs.writeFileString(summaryPath, `${lines.join(\"\\n\")}\\n`, { flag: \"a\" });\n});\n\nconst outcomeOutputs = (\n outcome: ReviewRunOutcome,\n conclusion: ReviewCheckConclusion,\n): ReadonlyArray<readonly [string, string]> => [\n [\"skipped\", \"false\"],\n [\"conclusion\", conclusion],\n [\"verdict\", outcome.review.verdict],\n [\"coverage\", outcome.coverage.status],\n [\"review-mode\", outcome.reviewMode ?? \"full\"],\n [\"review-reason\", outcome.reviewReason ?? \"direct full review\"],\n [\"inline-comments\", String(outcome.plan.comments.length)],\n [\"demoted-findings\", String(outcome.plan.demoted.length)],\n [\"concerns\", String(outcome.review.concerns?.length ?? 0)],\n ...(outcome.usage === undefined\n ? []\n : ([\n [\"input-tokens\", String(outcome.usage.inputTokens)],\n [\"output-tokens\", String(outcome.usage.outputTokens)],\n ] as const)),\n [\"review-url\", outcome.published?.url ?? \"\"],\n];\n\nconst outcomeSummary = (\n outcome: ReviewRunOutcome,\n modelLabel: string | undefined,\n conclusion: ReviewCheckConclusion,\n): ReadonlyArray<string> => [\n \"### Pull-request review\",\n `- Check conclusion: **${conclusion}**`,\n `- Verdict: **${outcome.review.verdict}**`,\n `- Coverage: **${outcome.coverage.status}** · scope: ${outcome.reviewMode ?? \"full\"}`,\n `- Inline comments: ${outcome.plan.comments.length} · demoted findings: ${outcome.plan.demoted.length} · concerns: ${outcome.review.concerns?.length ?? 0}`,\n ...(modelLabel === undefined ? [] : [`- Model: \\`${modelLabel}\\``]),\n ...(outcome.usage === undefined\n ? []\n : [\n `- Tokens: ${outcome.usage.inputTokens} in / ${outcome.usage.outputTokens} out${\n outcome.usageScope === \"coordinator\" ? \" (coordinator)\" : \"\"\n }`,\n ]),\n ...(outcome.published === undefined\n ? [\"- Dry run: nothing posted\"]\n : [`- Posted: ${outcome.published.url}`]),\n];\n\n/** The result of one action invocation: a typed skip or a settled review. */\nexport type ReviewActionResult =\n | { readonly _tag: \"Skipped\"; readonly reason: string }\n | { readonly _tag: \"Completed\"; readonly outcome: ReviewRunOutcome };\n\nconst skip = (reason: string) =>\n Effect.gen(function* () {\n yield* Console.log(`Skipping review: ${reason}`);\n yield* writeActionOutputs([\n [\"skipped\", \"true\"],\n [\"skip-reason\", reason],\n ]);\n yield* writeStepSummary([\"### Pull-request review skipped\", `- Reason: ${reason}`]);\n return { _tag: \"Skipped\", reason } satisfies ReviewActionResult;\n });\n\n/** The Actions run URL for the review footer, or undefined outside Actions. */\nconst resolveRunUrl = Effect.fn(\"resolveRunUrl\")(function* () {\n const runId = yield* Config.string(\"GITHUB_RUN_ID\").pipe(Config.withDefault(\"\"));\n const repository = yield* Config.string(\"GITHUB_REPOSITORY\").pipe(Config.withDefault(\"\"));\n if (runId === \"\" || repository === \"\") return undefined;\n const server = yield* Config.string(\"GITHUB_SERVER_URL\").pipe(\n Config.withDefault(\"https://github.com\"),\n );\n return `${server}/${repository}/actions/runs/${runId}`;\n});\n\n/** The reviewer surface the action harness drives. `PrReview.make` and\n * `PrReview.makeFanOut` provide the state-selection effects; the legacy\n * fingerprint field remains for source compatibility with custom harnesses. */\nexport interface HarnessedReviewer<E, R, FingerprintE, FingerprintR> {\n readonly run: (runOptions?: RunReviewOptions) => Effect.Effect<ReviewRunOutcome, E, R>;\n readonly fingerprint?: Effect.Effect<string, FingerprintE, FingerprintR> | undefined;\n readonly profileFingerprint?: Effect.Effect<string, FingerprintE, FingerprintR> | undefined;\n readonly snapshot?:\n | Effect.Effect<\n {\n readonly metadata: import(\"./internal/source.ts\").PullRequestMetadata;\n readonly files: ReadonlyArray<import(\"./internal/diff.ts\").ChangedFile>;\n },\n FingerprintE,\n FingerprintR\n >\n | undefined;\n readonly filterFiles?:\n | ((\n files: ReadonlyArray<import(\"./internal/diff.ts\").ChangedFile>,\n ) => ReadonlyArray<import(\"./internal/diff.ts\").ChangedFile>)\n | undefined;\n}\n\nconst blockingReasons = (input: {\n readonly findings: ReadonlyArray<{ readonly severity: string; readonly title: string }>;\n readonly concerns: ReadonlyArray<{ readonly severity: string; readonly title: string }>;\n}): ReadonlyArray<string> => [\n ...input.findings\n .filter((finding) => finding.severity === \"blocking\")\n .map((finding) => `blocking finding: ${finding.title}`),\n ...input.concerns\n .filter((concern) => concern.severity === \"blocking\")\n .map((concern) => `blocking concern: ${concern.title}`),\n];\n\n/** Host-derived check conclusion; model verdict prose cannot weaken it. */\nexport const concludeReviewOutcome = (\n outcome: ReviewRunOutcome,\n): {\n readonly conclusion: ReviewCheckConclusion;\n readonly reasons: ReadonlyArray<string>;\n} => {\n if (outcome.coverage.status === \"incomplete\") {\n return { conclusion: \"incomplete\", reasons: outcome.coverage.reasons };\n }\n const reasons = blockingReasons({\n findings: outcome.activeFindings,\n concerns: outcome.activeConcerns,\n });\n return reasons.length > 0\n ? { conclusion: \"blocking\", reasons }\n : { conclusion: \"success\", reasons };\n};\n\nconst concludeReviewState = (state: ReviewState) => {\n const reasons = blockingReasons({\n findings: state.unresolvedFindings,\n concerns: state.unresolvedConcerns,\n });\n return reasons.length > 0\n ? ({ conclusion: \"blocking\", reasons } as const)\n : ({ conclusion: \"success\", reasons: [] } as const);\n};\n\n/**\n * Harness one already-built reviewer inside the Actions environment: resolve\n * the target from the event, provide the GitHub source/publisher/prior\n * reviews, validate/select bounded continuity scope, write step outputs, and apply\n * the host-derived coverage/blocker gate. Draft and non-PR skips are values;\n * an unchanged reviewed head preserves and enforces its stored conclusion. The reviewer's\n * remaining requirements — its model client, any extra tool handlers — stay\n * visible in `R` for the caller.\n */\nexport const runReviewAction = <E, R, FingerprintE = never, FingerprintR = never>(\n reviewer: HarnessedReviewer<E, R, FingerprintE, FingerprintR>,\n options: {\n readonly post?: boolean | undefined;\n readonly failOn?: FailOnPolicy | undefined;\n /** Skip model execution when the current head already has complete stored coverage. */\n readonly skipUnchanged?: boolean | undefined;\n /** Incremental by default; `final` deliberately re-reviews the full PR diff. */\n readonly reviewMode?: ReviewMode | undefined;\n /** Model binding descriptor for the Actions step summary. */\n readonly modelLabel?: string | undefined;\n /** Explicit test/custom-host history override; GitHub owns the default adapter. */\n readonly priorReviews?: PriorReviews[\"Service\"] | undefined;\n } = {},\n) =>\n Effect.gen(function* () {\n const event = yield* readGitHubEvent();\n if (Option.isSome(event)) {\n if (event.value.pull_request === undefined) {\n return yield* skip(\"the triggering event carries no pull request\");\n }\n if (event.value.pull_request.draft === true) {\n return yield* skip(\"the pull request is a draft\");\n }\n }\n const target = yield* resolveReviewTarget({});\n // One layer build for state selection AND the run, so both observe\n // the same cached pull-request snapshot.\n return yield* Effect.gen(function* () {\n let selection: ReturnType<typeof selectReviewRange> | undefined;\n if (reviewer.profileFingerprint !== undefined) {\n const source = yield* PullRequestSource;\n const [snapshot, profileFingerprint] = yield* Effect.all([\n reviewer.snapshot ?? Effect.all({ metadata: source.metadata, files: source.anchorFiles }),\n reviewer.profileFingerprint,\n ]);\n const { metadata, files: fullFiles } = snapshot;\n const history = options.priorReviews ?? (yield* PriorReviews);\n const stateAuthenticator = yield* ReviewStateAuthenticator;\n const recovered =\n stateAuthenticator.status === \"unavailable\"\n ? {\n state: undefined,\n failure:\n stateAuthenticator.unavailableReason ??\n \"an authenticated review-state secret is not configured\",\n }\n : yield* history.latestState.pipe(\n Effect.match({\n onFailure: (failure) => ({ state: undefined, failure: failure.reason }),\n onSuccess: (state) => ({\n state: Option.getOrUndefined(state),\n failure: undefined,\n }),\n }),\n );\n let comparison: ReviewHeadComparison | undefined;\n let baseComparison: ReviewHeadComparison | undefined;\n if (\n (options.reviewMode ?? \"incremental\") === \"incremental\" &&\n recovered.state !== undefined\n ) {\n if (recovered.state.reviewedHeadSha === metadata.headSha) {\n comparison = ReviewHeadComparison.make({\n status: \"identical\",\n baseSha: metadata.headSha,\n headSha: metadata.headSha,\n mergeBaseSha: metadata.headSha,\n files: [],\n truncated: false,\n });\n } else {\n comparison = yield* history\n .compareHeads(recovered.state.reviewedHeadSha, metadata.headSha)\n .pipe(Effect.orElseSucceed(() => undefined));\n if (comparison !== undefined && reviewer.filterFiles !== undefined) {\n comparison = ReviewHeadComparison.make({\n ...comparison,\n files: reviewer.filterFiles(comparison.files),\n });\n }\n }\n if (metadata.baseSha !== undefined && recovered.state.baseSha !== metadata.baseSha) {\n baseComparison = yield* history\n .compareHeads(recovered.state.baseSha, metadata.baseSha)\n .pipe(Effect.orElseSucceed(() => undefined));\n if (baseComparison !== undefined && reviewer.filterFiles !== undefined) {\n baseComparison = ReviewHeadComparison.make({\n ...baseComparison,\n files: reviewer.filterFiles(baseComparison.files),\n });\n }\n }\n }\n selection = {\n ...selectReviewRange({\n requestedMode: options.reviewMode ?? \"incremental\",\n current: metadata,\n fullFiles,\n profileFingerprint,\n priorState: recovered.state,\n comparison,\n baseComparison,\n lookupFailure: recovered.failure,\n }),\n stateAuthenticator,\n };\n if (\n options.skipUnchanged !== false &&\n selection.mode === \"incremental\" &&\n selection.files.length === 0 &&\n selection.priorState !== undefined\n ) {\n const result = concludeReviewState(selection.priorState);\n const reason = \"no changed review scope since the last successfully reviewed head\";\n yield* Console.log(\n `Skipping review of ${target.repository}#${target.number}: ${reason}.`,\n );\n yield* writeActionOutputs([\n [\"skipped\", \"true\"],\n [\"skip-reason\", reason],\n [\"conclusion\", result.conclusion],\n [\"coverage\", \"complete\"],\n [\"review-mode\", \"incremental\"],\n ]);\n yield* writeStepSummary([\n \"### Pull-request review skipped\",\n `- Reason: ${reason}`,\n `- Preserved check conclusion: **${result.conclusion}**`,\n ]);\n if (result.conclusion === \"blocking\") {\n return yield* ReviewGateFailed.make({\n conclusion: \"blocking\",\n reasons: result.reasons,\n });\n }\n return { _tag: \"Skipped\", reason } satisfies ReviewActionResult;\n }\n } else if (options.skipUnchanged !== false && reviewer.fingerprint !== undefined) {\n // Preserve the pre-state custom harness contract explicitly. The\n // packaged reviewer always takes the authenticated state path above.\n const current = yield* reviewer.fingerprint;\n const history = options.priorReviews ?? (yield* PriorReviews);\n const latest = yield* history.latestFingerprint.pipe(\n Effect.orElseSucceed(() => Option.none<string>()),\n );\n if (Option.isSome(latest) && latest.value === current) {\n const reason = \"changeset unchanged since the last review\";\n yield* Console.log(\n `Skipping review of ${target.repository}#${target.number}: ${reason}.`,\n );\n yield* writeActionOutputs([\n [\"skipped\", \"true\"],\n [\"skip-reason\", reason],\n [\"fingerprint\", current],\n [\"conclusion\", \"success\"],\n [\"coverage\", \"complete\"],\n ]);\n yield* writeStepSummary([\"### Pull-request review skipped\", `- Reason: ${reason}`]);\n return { _tag: \"Skipped\", reason } satisfies ReviewActionResult;\n }\n }\n yield* Console.log(\n `Reviewing ${target.repository}#${target.number} (${options.post === false ? \"dry run\" : \"posting\"})...`,\n );\n const runUrl = yield* resolveRunUrl();\n const reviewEffect = reviewer.run({ post: options.post ?? true, runUrl });\n const outcome = yield* selection === undefined\n ? reviewEffect\n : reviewEffect.pipe(\n Effect.provide(selectedPullRequestSourceLayer(selection)),\n Effect.provideService(ReviewExecutionContext, selection),\n );\n yield* Console.log(\n `Review finished in ${outcome.turns} turn(s): verdict ${outcome.review.verdict}, ` +\n `${outcome.plan.comments.length} inline comment(s), ${outcome.plan.demoted.length} demoted finding(s).`,\n );\n if (outcome.published !== undefined) {\n yield* Console.log(`Posted ${outcome.published.event} review: ${outcome.published.url}`);\n }\n const check = concludeReviewOutcome(outcome);\n yield* writeActionOutputs(outcomeOutputs(outcome, check.conclusion));\n yield* writeStepSummary(outcomeSummary(outcome, options.modelLabel, check.conclusion));\n if (check.conclusion !== \"success\") {\n return yield* ReviewGateFailed.make({\n conclusion: check.conclusion,\n reasons: check.reasons,\n });\n }\n return { _tag: \"Completed\", outcome } satisfies ReviewActionResult;\n }).pipe(Effect.provide(gitHubReviewLayers(target)));\n });\n\n/**\n * The packaged, environment-driven action program: inputs from PR_REVIEW_*,\n * reviewer built from the packaged factory, provider client from the\n * matching credential environment variable.\n */\nexport const reviewActionProgram = Effect.gen(function* () {\n const inputs = yield* resolveActionInputs();\n const stateSecret = Option.map(\n yield* Config.option(Config.nonEmptyString(\"PR_REVIEW_STATE_SECRET\")),\n Redacted.make,\n );\n const stateAuthenticatorLayer = Option.match(stateSecret, {\n onNone: () =>\n unavailableReviewStateAuthenticatorLayer(\n \"an authenticated review-state secret is not configured\",\n ),\n onSome: webCryptoReviewStateAuthenticatorLayer,\n });\n const guidance = yield* resolveGuidance(inputs);\n const modelLabel = describeReviewModel(inputs.provider, inputs.model, inputs.effort);\n const defaults = inputs.fanOut ? fanOutReviewBudgetLimits : reviewBudgetLimits;\n const budget =\n inputs.maxDurationMinutes === undefined\n ? defaults\n : UsageBudgetLimits.make({\n ...defaults,\n maxDurationMillis: inputs.maxDurationMinutes * 60_000,\n });\n const shared = {\n guidance,\n ignore: inputs.ignore,\n maxFindings: inputs.maxFindings,\n applyVerdict: inputs.applyVerdict,\n modelLabel,\n budget,\n };\n const harness = {\n post: inputs.post,\n failOn: inputs.failOn,\n skipUnchanged: inputs.skipUnchanged,\n reviewMode: inputs.reviewMode,\n modelLabel,\n };\n if (inputs.provider === \"anthropic\") {\n const model = makeAnthropicReviewModel(inputs.model, inputs.effort);\n const reviewer = inputs.fanOut\n ? PrReview.makeFanOut({ ...shared, model })\n : PrReview.make({ ...shared, model });\n return yield* runReviewAction(reviewer, harness).pipe(\n Effect.provide(Layer.merge(stateAuthenticatorLayer, anthropicClientLayer)),\n );\n }\n const model = makeOpenAiReviewModel(inputs.model, inputs.effort);\n const reviewer = inputs.fanOut\n ? PrReview.makeFanOut({ ...shared, model })\n : PrReview.make({ ...shared, model });\n return yield* runReviewAction(reviewer, harness).pipe(\n Effect.provide(Layer.merge(stateAuthenticatorLayer, openAiClientLayer)),\n );\n});\n\n/** Run the packaged action program on Node; the bundled action entrypoint. */\nexport const main = (): void =>\n NodeRuntime.runMain(\n reviewActionProgram.pipe(\n Effect.tapError((error) =>\n Console.error(\n Schema.is(BudgetExceeded)(error)\n ? `Budget exceeded: ${error.limit} observed ${error.observedValue}, limit ${error.limitValue}.`\n : String(error),\n ),\n ),\n Effect.scoped,\n Effect.provide(NodeServices.layer),\n ),\n { disableErrorReporting: true },\n );\n\n/** The packaged GitHub Actions surface. */\nexport const PrReviewAction = {\n inputs: resolveActionInputs,\n run: runReviewAction,\n program: reviewActionProgram,\n main,\n} as const;\n"],"mappings":"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"}
1
+ {"version":3,"file":"action.mjs","names":[],"sources":["../src/action.ts"],"sourcesContent":["import { NodeRuntime, NodeServices } from \"@effect/platform-node\";\nimport { Config, Console, Effect, FileSystem, Layer, Option, Redacted, Schema } from \"effect\";\nimport { BudgetExceeded, UsageBudgetLimits } from \"effect-agent\";\nimport { FetchHttpClient } from \"effect/unstable/http\";\n\nimport { InvalidEffortInput, parseEffortPosition, type EffortPosition } from \"./internal/effort.ts\";\nimport { PrReview, type RunReviewOptions } from \"./internal/factory.ts\";\nimport { readGitHubEvent, resolveReviewTarget, gitHubReviewLayers } from \"./internal/github-env.ts\";\nimport { PriorReviews } from \"./internal/github.ts\";\nimport {\n anthropicClientLayer,\n DEFAULT_PROVIDER,\n describeReviewModel,\n makeAnthropicReviewModel,\n makeOpenAiReviewModel,\n openAiClientLayer,\n type ReviewProvider,\n} from \"./internal/providers.ts\";\nimport { retireStaleReviews } from \"./internal/retirement.ts\";\nimport {\n ReviewExecutionContext,\n ReviewHeadComparison,\n ReviewStateAuthenticator,\n type ReviewMode,\n type ReviewState,\n selectReviewRange,\n selectedPullRequestSourceLayer,\n unavailableReviewStateAuthenticatorLayer,\n webCryptoReviewStateAuthenticatorLayer,\n} from \"./internal/review-state.ts\";\nimport { fanOutReviewBudgetLimits, reviewBudgetLimits } from \"./internal/run.ts\";\nimport type { ReviewRunOutcome } from \"./internal/run.ts\";\nimport { normalizeRepoRelativePath, PullRequestSource } from \"./internal/source.ts\";\n\n// ---------------------------------------------------------------------------\n// The GitHub Actions entrypoint (deployment class E: one bounded ephemeral\n// run, no exactly-once posting). Bounded continuity state travels in GitHub\n// review bodies and is validated before reuse. Inputs arrive as\n// PR_REVIEW_* environment variables set by the action manifest; the target\n// pull request comes from the standard Actions event environment. A non-PR\n// or draft event is a typed skip — green job, nothing posted. Publication\n// happens only after the run settles, so a failed or truncated run posts\n// nothing.\n// ---------------------------------------------------------------------------\n\n/** Deprecated compatibility input; host-derived conclusions are unconditional. */\nexport const FailOnPolicy = Schema.Literals([\"never\", \"request-changes\"]);\nexport type FailOnPolicy = typeof FailOnPolicy.Type;\n\nexport const ReviewCheckConclusion = Schema.Literals([\"success\", \"blocking\", \"incomplete\"]);\nexport type ReviewCheckConclusion = typeof ReviewCheckConclusion.Type;\n\n/** The host-derived blocking or incomplete conclusion failed the check. */\nexport class ReviewGateFailed extends Schema.TaggedError<ReviewGateFailed>()(\"ReviewGateFailed\", {\n conclusion: Schema.Literals([\"blocking\", \"incomplete\"]),\n reasons: Schema.Array(Schema.NonEmptyString.check(Schema.isMaxLength(1_000))).check(\n Schema.isMinLength(1),\n ),\n}) {\n override get message() {\n return `Review check concluded '${this.conclusion}': ${this.reasons.join(\"; \")}`;\n }\n}\n\n/** A configured max-duration that cannot bound a run; configuration faults fail loudly. */\nexport class InvalidMaxDurationInput extends Schema.TaggedError<InvalidMaxDurationInput>()(\n \"InvalidMaxDurationInput\",\n {\n minutes: Schema.Int,\n },\n) {\n override get message() {\n return `Invalid max-duration-minutes '${this.minutes}': expected a positive number of minutes.`;\n }\n}\n\n/** Everything the packaged action reads from its environment. */\nexport interface ResolvedActionInputs {\n readonly provider: ReviewProvider;\n readonly model: string | undefined;\n readonly effort: EffortPosition | undefined;\n readonly post: boolean;\n readonly applyVerdict: boolean;\n readonly fanOut: boolean;\n readonly guidance: string | undefined;\n readonly guidanceFile: string | undefined;\n readonly ignore: ReadonlyArray<string>;\n readonly maxFindings: number | undefined;\n readonly maxDurationMinutes: number | undefined;\n readonly reviewMode: ReviewMode;\n /** Deprecated compatibility input; conclusions are always conservative. */\n readonly failOn: FailOnPolicy;\n readonly skipUnchanged: boolean;\n readonly retireStaleReviews: boolean;\n}\n\n/** Read the PR_REVIEW_* input surface (all optional, all defaulted). */\nexport const resolveActionInputs = Effect.fn(\"resolveActionInputs\")(function* () {\n const provider = yield* Config.literals([\"openai\", \"anthropic\"], \"PR_REVIEW_PROVIDER\").pipe(\n Config.withDefault<ReviewProvider>(DEFAULT_PROVIDER),\n );\n const model = yield* Config.option(Config.nonEmptyString(\"PR_REVIEW_MODEL\"));\n const effortRaw = yield* Config.option(Config.nonEmptyString(\"PR_REVIEW_EFFORT\"));\n let effort: EffortPosition | undefined;\n if (Option.isSome(effortRaw)) {\n effort = parseEffortPosition(effortRaw.value);\n if (effort === undefined) {\n return yield* InvalidEffortInput.make({ input: effortRaw.value });\n }\n }\n const maxDurationMinutes = Option.getOrUndefined(\n yield* Config.option(Config.int(\"PR_REVIEW_MAX_DURATION_MINUTES\")),\n );\n if (maxDurationMinutes !== undefined && maxDurationMinutes <= 0) {\n return yield* InvalidMaxDurationInput.make({ minutes: maxDurationMinutes });\n }\n const post = yield* Config.boolean(\"PR_REVIEW_POST\").pipe(Config.withDefault(true));\n const applyVerdict = yield* Config.boolean(\"PR_REVIEW_APPLY_VERDICT\").pipe(\n Config.withDefault(false),\n );\n const fanOut = yield* Config.boolean(\"PR_REVIEW_FAN_OUT\").pipe(Config.withDefault(false));\n const guidance = yield* Config.option(Config.nonEmptyString(\"PR_REVIEW_GUIDANCE\"));\n const guidanceFile = yield* Config.option(Config.nonEmptyString(\"PR_REVIEW_GUIDANCE_FILE\"));\n const ignoreRaw = yield* Config.string(\"PR_REVIEW_IGNORE\").pipe(Config.withDefault(\"\"));\n const maxFindings = yield* Config.option(Config.int(\"PR_REVIEW_MAX_FINDINGS\"));\n const reviewMode = yield* Config.literals([\"incremental\", \"final\"], \"PR_REVIEW_MODE\").pipe(\n Config.withDefault<ReviewMode>(\"incremental\"),\n );\n const failOn = yield* Config.literals([\"never\", \"request-changes\"], \"PR_REVIEW_FAIL_ON\").pipe(\n Config.withDefault<FailOnPolicy>(\"never\"),\n );\n const skipUnchanged = yield* Config.boolean(\"PR_REVIEW_SKIP_UNCHANGED\").pipe(\n Config.withDefault(true),\n );\n const retireStaleReviews = yield* Config.boolean(\"PR_REVIEW_RETIRE_STALE_REVIEWS\").pipe(\n Config.withDefault(true),\n );\n return {\n provider,\n model: Option.getOrUndefined(model),\n effort,\n post,\n applyVerdict,\n fanOut,\n guidance: Option.getOrUndefined(guidance),\n guidanceFile: Option.getOrUndefined(guidanceFile),\n ignore: ignoreRaw\n .split(\",\")\n .map((pattern) => pattern.trim())\n .filter((pattern) => pattern.length > 0),\n maxFindings: Option.getOrUndefined(maxFindings),\n maxDurationMinutes,\n reviewMode,\n failOn,\n skipUnchanged,\n retireStaleReviews,\n } satisfies ResolvedActionInputs;\n});\n\n/** A guidance file larger than this is refused, never silently truncated. */\nexport const MAX_GUIDANCE_FILE_CHARS = 20_000;\n\n/** A configured guidance file could not be used; configuration faults fail loudly. */\nexport class GuidanceFileUnreadable extends Schema.TaggedError<GuidanceFileUnreadable>()(\n \"GuidanceFileUnreadable\",\n {\n path: Schema.String,\n reason: Schema.String,\n },\n) {\n override get message() {\n return `Cannot use guidance file '${this.path}': ${this.reason}`;\n }\n}\n\n/**\n * Resolve the effective review guidance: the committed guidance file (a\n * repository-owned review profile) first, with any inline guidance appended.\n * A configured-but-unreadable file fails typed — a review silently running\n * without its profile would be worse than a red job.\n */\nexport const resolveGuidance = Effect.fn(\"resolveGuidance\")(function* (inputs: {\n readonly guidance: string | undefined;\n readonly guidanceFile: string | undefined;\n}) {\n const filePath = inputs.guidanceFile;\n if (filePath === undefined) return inputs.guidance;\n // The profile path is operator configuration, but it stays fail-closed\n // like every other path in this package: workspace-relative only, and the\n // size bound is checked before the file is read into memory.\n const relative = yield* normalizeRepoRelativePath(filePath).pipe(\n Effect.mapError((violation) =>\n GuidanceFileUnreadable.make({ path: filePath, reason: violation.reason }),\n ),\n );\n const fs = yield* FileSystem.FileSystem;\n const unreadable = (error: { readonly _tag: string; readonly message: string }) =>\n GuidanceFileUnreadable.make({\n path: relative,\n reason: `${error._tag}: ${error.message}`.slice(0, 2_048),\n });\n const stat = yield* fs.stat(relative).pipe(Effect.mapError(unreadable));\n const oversized = GuidanceFileUnreadable.make({\n path: relative,\n reason: `File is larger than the ${MAX_GUIDANCE_FILE_CHARS}-character guidance bound.`,\n });\n if (stat.size > BigInt(MAX_GUIDANCE_FILE_CHARS) * 4n) {\n return yield* oversized;\n }\n const content = yield* fs.readFileString(relative).pipe(Effect.mapError(unreadable));\n if (content.length > MAX_GUIDANCE_FILE_CHARS) {\n return yield* oversized;\n }\n const combined = [content.trim(), inputs.guidance ?? \"\"]\n .filter((part) => part.length > 0)\n .join(\"\\n\");\n return combined.length > 0 ? combined : undefined;\n});\n\n/** One step-output line; values must be single-line by construction. */\nconst outputLine = (name: string, value: string): string =>\n `${name}=${value.replaceAll(\"\\n\", \" \").slice(0, 1_000)}\\n`;\n\n/** Append step outputs to GITHUB_OUTPUT when present (no-op locally). */\nexport const writeActionOutputs = Effect.fn(\"writeActionOutputs\")(function* (\n entries: ReadonlyArray<readonly [name: string, value: string]>,\n) {\n const outputPath = yield* Config.string(\"GITHUB_OUTPUT\").pipe(Config.withDefault(\"\"));\n if (outputPath === \"\") return;\n const fs = yield* FileSystem.FileSystem;\n yield* fs.writeFileString(\n outputPath,\n entries.map(([name, value]) => outputLine(name, value)).join(\"\"),\n {\n flag: \"a\",\n },\n );\n});\n\n/** Append markdown to the GITHUB_STEP_SUMMARY report when present (no-op locally). */\nexport const writeStepSummary = Effect.fn(\"writeStepSummary\")(function* (\n lines: ReadonlyArray<string>,\n) {\n const summaryPath = yield* Config.string(\"GITHUB_STEP_SUMMARY\").pipe(Config.withDefault(\"\"));\n if (summaryPath === \"\") return;\n const fs = yield* FileSystem.FileSystem;\n yield* fs.writeFileString(summaryPath, `${lines.join(\"\\n\")}\\n`, { flag: \"a\" });\n});\n\nconst outcomeOutputs = (\n outcome: ReviewRunOutcome,\n conclusion: ReviewCheckConclusion,\n): ReadonlyArray<readonly [string, string]> => [\n [\"skipped\", \"false\"],\n [\"conclusion\", conclusion],\n [\"verdict\", outcome.review.verdict],\n [\"coverage\", outcome.coverage.status],\n [\"review-mode\", outcome.reviewMode ?? \"full\"],\n [\"review-reason\", outcome.reviewReason ?? \"direct full review\"],\n [\"inline-comments\", String(outcome.plan.comments.length)],\n [\"demoted-findings\", String(outcome.plan.demoted.length)],\n [\"concerns\", String(outcome.review.concerns?.length ?? 0)],\n ...(outcome.usage === undefined\n ? []\n : ([\n [\"input-tokens\", String(outcome.usage.inputTokens)],\n [\"output-tokens\", String(outcome.usage.outputTokens)],\n ] as const)),\n [\"review-url\", outcome.published?.url ?? \"\"],\n];\n\nconst outcomeSummary = (\n outcome: ReviewRunOutcome,\n modelLabel: string | undefined,\n conclusion: ReviewCheckConclusion,\n): ReadonlyArray<string> => [\n \"### Pull-request review\",\n `- Check conclusion: **${conclusion}**`,\n `- Verdict: **${outcome.review.verdict}**`,\n `- Coverage: **${outcome.coverage.status}** · scope: ${outcome.reviewMode ?? \"full\"}`,\n `- Inline comments: ${outcome.plan.comments.length} · demoted findings: ${outcome.plan.demoted.length} · concerns: ${outcome.review.concerns?.length ?? 0}`,\n ...(modelLabel === undefined ? [] : [`- Model: \\`${modelLabel}\\``]),\n ...(outcome.usage === undefined\n ? []\n : [\n `- Tokens: ${outcome.usage.inputTokens} in / ${outcome.usage.outputTokens} out${\n outcome.usageScope === \"coordinator\" ? \" (coordinator)\" : \"\"\n }`,\n ]),\n ...(outcome.published === undefined\n ? [\"- Dry run: nothing posted\"]\n : [`- Posted: ${outcome.published.url}`]),\n];\n\n/** The result of one action invocation: a typed skip or a settled review. */\nexport type ReviewActionResult =\n | { readonly _tag: \"Skipped\"; readonly reason: string }\n | { readonly _tag: \"Completed\"; readonly outcome: ReviewRunOutcome };\n\nconst skip = (reason: string) =>\n Effect.gen(function* () {\n yield* Console.log(`Skipping review: ${reason}`);\n yield* writeActionOutputs([\n [\"skipped\", \"true\"],\n [\"skip-reason\", reason],\n ]);\n yield* writeStepSummary([\"### Pull-request review skipped\", `- Reason: ${reason}`]);\n return { _tag: \"Skipped\", reason } satisfies ReviewActionResult;\n });\n\n/** The Actions run URL for the review footer, or undefined outside Actions. */\nconst resolveRunUrl = Effect.fn(\"resolveRunUrl\")(function* () {\n const runId = yield* Config.string(\"GITHUB_RUN_ID\").pipe(Config.withDefault(\"\"));\n const repository = yield* Config.string(\"GITHUB_REPOSITORY\").pipe(Config.withDefault(\"\"));\n if (runId === \"\" || repository === \"\") return undefined;\n const server = yield* Config.string(\"GITHUB_SERVER_URL\").pipe(\n Config.withDefault(\"https://github.com\"),\n );\n return `${server}/${repository}/actions/runs/${runId}`;\n});\n\n/** The reviewer surface the action harness drives. `PrReview.make` and\n * `PrReview.makeFanOut` provide the state-selection effects; the legacy\n * fingerprint field remains for source compatibility with custom harnesses. */\nexport interface HarnessedReviewer<E, R, FingerprintE, FingerprintR> {\n readonly run: (runOptions?: RunReviewOptions) => Effect.Effect<ReviewRunOutcome, E, R>;\n readonly fingerprint?: Effect.Effect<string, FingerprintE, FingerprintR> | undefined;\n readonly profileFingerprint?: Effect.Effect<string, FingerprintE, FingerprintR> | undefined;\n readonly snapshot?:\n | Effect.Effect<\n {\n readonly metadata: import(\"./internal/source.ts\").PullRequestMetadata;\n readonly files: ReadonlyArray<import(\"./internal/diff.ts\").ChangedFile>;\n },\n FingerprintE,\n FingerprintR\n >\n | undefined;\n readonly filterFiles?:\n | ((\n files: ReadonlyArray<import(\"./internal/diff.ts\").ChangedFile>,\n ) => ReadonlyArray<import(\"./internal/diff.ts\").ChangedFile>)\n | undefined;\n}\n\nconst blockingReasons = (input: {\n readonly findings: ReadonlyArray<{ readonly severity: string; readonly title: string }>;\n readonly concerns: ReadonlyArray<{ readonly severity: string; readonly title: string }>;\n}): ReadonlyArray<string> => [\n ...input.findings\n .filter((finding) => finding.severity === \"blocking\")\n .map((finding) => `blocking finding: ${finding.title}`),\n ...input.concerns\n .filter((concern) => concern.severity === \"blocking\")\n .map((concern) => `blocking concern: ${concern.title}`),\n];\n\n/** Host-derived check conclusion; model verdict prose cannot weaken it. */\nexport const concludeReviewOutcome = (\n outcome: ReviewRunOutcome,\n): {\n readonly conclusion: ReviewCheckConclusion;\n readonly reasons: ReadonlyArray<string>;\n} => {\n if (outcome.coverage.status === \"incomplete\") {\n return { conclusion: \"incomplete\", reasons: outcome.coverage.reasons };\n }\n const reasons = blockingReasons({\n findings: outcome.activeFindings,\n concerns: outcome.activeConcerns,\n });\n return reasons.length > 0\n ? { conclusion: \"blocking\", reasons }\n : { conclusion: \"success\", reasons };\n};\n\nconst concludeReviewState = (state: ReviewState) => {\n const reasons = blockingReasons({\n findings: state.unresolvedFindings,\n concerns: state.unresolvedConcerns,\n });\n return reasons.length > 0\n ? ({ conclusion: \"blocking\", reasons } as const)\n : ({ conclusion: \"success\", reasons: [] } as const);\n};\n\n/**\n * Harness one already-built reviewer inside the Actions environment: resolve\n * the target from the event, provide the GitHub source/publisher/prior\n * reviews, validate/select bounded continuity scope, write step outputs, and apply\n * the host-derived coverage/blocker gate. Draft and non-PR skips are values;\n * an unchanged reviewed head preserves and enforces its stored conclusion. The reviewer's\n * remaining requirements — its model client, any extra tool handlers — stay\n * visible in `R` for the caller.\n */\nexport const runReviewAction = <E, R, FingerprintE = never, FingerprintR = never>(\n reviewer: HarnessedReviewer<E, R, FingerprintE, FingerprintR>,\n options: {\n readonly post?: boolean | undefined;\n readonly failOn?: FailOnPolicy | undefined;\n /** Skip model execution when the current head already has complete stored coverage. */\n readonly skipUnchanged?: boolean | undefined;\n /** Incremental by default; `final` deliberately re-reviews the full PR diff. */\n readonly reviewMode?: ReviewMode | undefined;\n /** Model binding descriptor for the Actions step summary. */\n readonly modelLabel?: string | undefined;\n /** Explicit test/custom-host history override; GitHub owns the default adapter. */\n readonly priorReviews?: PriorReviews[\"Service\"] | undefined;\n /** Retire marker-bearing prior reviews after a successful post (default true). */\n readonly retireStaleReviews?: boolean | undefined;\n } = {},\n) =>\n Effect.gen(function* () {\n const event = yield* readGitHubEvent();\n if (Option.isSome(event)) {\n if (event.value.pull_request === undefined) {\n return yield* skip(\"the triggering event carries no pull request\");\n }\n if (event.value.pull_request.draft === true) {\n return yield* skip(\"the pull request is a draft\");\n }\n }\n const target = yield* resolveReviewTarget({});\n // One layer build for state selection AND the run, so both observe\n // the same cached pull-request snapshot.\n return yield* Effect.gen(function* () {\n let selection: ReturnType<typeof selectReviewRange> | undefined;\n if (reviewer.profileFingerprint !== undefined) {\n const source = yield* PullRequestSource;\n const [snapshot, profileFingerprint] = yield* Effect.all([\n reviewer.snapshot ?? Effect.all({ metadata: source.metadata, files: source.anchorFiles }),\n reviewer.profileFingerprint,\n ]);\n const { metadata, files: fullFiles } = snapshot;\n const history = options.priorReviews ?? (yield* PriorReviews);\n const stateAuthenticator = yield* ReviewStateAuthenticator;\n const recovered =\n stateAuthenticator.status === \"unavailable\"\n ? {\n state: undefined,\n failure:\n stateAuthenticator.unavailableReason ??\n \"an authenticated review-state secret is not configured\",\n }\n : yield* history.latestState.pipe(\n Effect.match({\n onFailure: (failure) => ({ state: undefined, failure: failure.reason }),\n onSuccess: (state) => ({\n state: Option.getOrUndefined(state),\n failure: undefined,\n }),\n }),\n );\n let comparison: ReviewHeadComparison | undefined;\n let baseComparison: ReviewHeadComparison | undefined;\n if (\n (options.reviewMode ?? \"incremental\") === \"incremental\" &&\n recovered.state !== undefined\n ) {\n if (recovered.state.reviewedHeadSha === metadata.headSha) {\n comparison = ReviewHeadComparison.make({\n status: \"identical\",\n baseSha: metadata.headSha,\n headSha: metadata.headSha,\n mergeBaseSha: metadata.headSha,\n files: [],\n truncated: false,\n });\n } else {\n comparison = yield* history\n .compareHeads(recovered.state.reviewedHeadSha, metadata.headSha)\n .pipe(Effect.orElseSucceed(() => undefined));\n if (comparison !== undefined && reviewer.filterFiles !== undefined) {\n comparison = ReviewHeadComparison.make({\n ...comparison,\n files: reviewer.filterFiles(comparison.files),\n });\n }\n }\n if (metadata.baseSha !== undefined && recovered.state.baseSha !== metadata.baseSha) {\n baseComparison = yield* history\n .compareHeads(recovered.state.baseSha, metadata.baseSha)\n .pipe(Effect.orElseSucceed(() => undefined));\n if (baseComparison !== undefined && reviewer.filterFiles !== undefined) {\n baseComparison = ReviewHeadComparison.make({\n ...baseComparison,\n files: reviewer.filterFiles(baseComparison.files),\n });\n }\n }\n }\n selection = {\n ...selectReviewRange({\n requestedMode: options.reviewMode ?? \"incremental\",\n current: metadata,\n fullFiles,\n profileFingerprint,\n priorState: recovered.state,\n comparison,\n baseComparison,\n lookupFailure: recovered.failure,\n }),\n stateAuthenticator,\n };\n if (\n options.skipUnchanged !== false &&\n selection.mode === \"incremental\" &&\n selection.files.length === 0 &&\n selection.priorState !== undefined\n ) {\n const result = concludeReviewState(selection.priorState);\n const reason = \"no changed review scope since the last successfully reviewed head\";\n yield* Console.log(\n `Skipping review of ${target.repository}#${target.number}: ${reason}.`,\n );\n yield* writeActionOutputs([\n [\"skipped\", \"true\"],\n [\"skip-reason\", reason],\n [\"conclusion\", result.conclusion],\n [\"coverage\", \"complete\"],\n [\"review-mode\", \"incremental\"],\n ]);\n yield* writeStepSummary([\n \"### Pull-request review skipped\",\n `- Reason: ${reason}`,\n `- Preserved check conclusion: **${result.conclusion}**`,\n ]);\n if (result.conclusion === \"blocking\") {\n return yield* ReviewGateFailed.make({\n conclusion: \"blocking\",\n reasons: result.reasons,\n });\n }\n return { _tag: \"Skipped\", reason } satisfies ReviewActionResult;\n }\n } else if (options.skipUnchanged !== false && reviewer.fingerprint !== undefined) {\n // Preserve the pre-state custom harness contract explicitly. The\n // packaged reviewer always takes the authenticated state path above.\n const current = yield* reviewer.fingerprint;\n const history = options.priorReviews ?? (yield* PriorReviews);\n const latest = yield* history.latestFingerprint.pipe(\n Effect.orElseSucceed(() => Option.none<string>()),\n );\n if (Option.isSome(latest) && latest.value === current) {\n const reason = \"changeset unchanged since the last review\";\n yield* Console.log(\n `Skipping review of ${target.repository}#${target.number}: ${reason}.`,\n );\n yield* writeActionOutputs([\n [\"skipped\", \"true\"],\n [\"skip-reason\", reason],\n [\"fingerprint\", current],\n [\"conclusion\", \"success\"],\n [\"coverage\", \"complete\"],\n ]);\n yield* writeStepSummary([\"### Pull-request review skipped\", `- Reason: ${reason}`]);\n return { _tag: \"Skipped\", reason } satisfies ReviewActionResult;\n }\n }\n yield* Console.log(\n `Reviewing ${target.repository}#${target.number} (${options.post === false ? \"dry run\" : \"posting\"})...`,\n );\n const runUrl = yield* resolveRunUrl();\n const reviewEffect = reviewer.run({ post: options.post ?? true, runUrl });\n const outcome = yield* selection === undefined\n ? reviewEffect\n : reviewEffect.pipe(\n Effect.provide(selectedPullRequestSourceLayer(selection)),\n Effect.provideService(ReviewExecutionContext, selection),\n );\n yield* Console.log(\n `Review finished in ${outcome.turns} turn(s): verdict ${outcome.review.verdict}, ` +\n `${outcome.plan.comments.length} inline comment(s), ${outcome.plan.demoted.length} demoted finding(s).`,\n );\n if (outcome.published !== undefined) {\n yield* Console.log(`Posted ${outcome.published.event} review: ${outcome.published.url}`);\n if (options.retireStaleReviews !== false && outcome.state !== undefined) {\n if (outcome.published.authorNodeId === null || outcome.published.submittedAt === null) {\n yield* Console.warn(\n \"Skipping stale-review retirement because GitHub did not return the posted review's actor and submission time.\",\n );\n } else {\n const report = yield* retireStaleReviews({\n currentReviewId: outcome.published.reviewId,\n currentReviewUrl: outcome.published.url,\n currentAuthorNodeId: outcome.published.authorNodeId,\n currentSubmittedAt: outcome.published.submittedAt,\n currentState: outcome.state,\n });\n yield* Console.log(\n `Review retirement: ${report.reviewsRetired} prior review(s), ` +\n `${report.findingsResolved} resolved finding(s), ` +\n `${report.commentsMinimized} minimized inline comment(s), ` +\n `${report.failures} failure(s).`,\n );\n }\n }\n }\n const check = concludeReviewOutcome(outcome);\n yield* writeActionOutputs(outcomeOutputs(outcome, check.conclusion));\n yield* writeStepSummary(outcomeSummary(outcome, options.modelLabel, check.conclusion));\n if (check.conclusion !== \"success\") {\n return yield* ReviewGateFailed.make({\n conclusion: check.conclusion,\n reasons: check.reasons,\n });\n }\n return { _tag: \"Completed\", outcome } satisfies ReviewActionResult;\n }).pipe(Effect.provide(gitHubReviewLayers(target)));\n });\n\n/**\n * The packaged, environment-driven action program: inputs from PR_REVIEW_*,\n * reviewer built from the packaged factory, provider client from the\n * matching credential environment variable.\n */\nexport const reviewActionProgram = Effect.gen(function* () {\n const inputs = yield* resolveActionInputs();\n const stateSecret = Option.map(\n yield* Config.option(Config.nonEmptyString(\"PR_REVIEW_STATE_SECRET\")),\n Redacted.make,\n );\n const stateAuthenticatorLayer = Option.match(stateSecret, {\n onNone: () =>\n unavailableReviewStateAuthenticatorLayer(\n \"an authenticated review-state secret is not configured\",\n ),\n onSome: webCryptoReviewStateAuthenticatorLayer,\n });\n const guidance = yield* resolveGuidance(inputs);\n const modelLabel = describeReviewModel(inputs.provider, inputs.model, inputs.effort);\n const defaults = inputs.fanOut ? fanOutReviewBudgetLimits : reviewBudgetLimits;\n const budget =\n inputs.maxDurationMinutes === undefined\n ? defaults\n : UsageBudgetLimits.make({\n ...defaults,\n maxDurationMillis: inputs.maxDurationMinutes * 60_000,\n });\n const shared = {\n guidance,\n ignore: inputs.ignore,\n maxFindings: inputs.maxFindings,\n applyVerdict: inputs.applyVerdict,\n modelLabel,\n budget,\n };\n const harness = {\n post: inputs.post,\n failOn: inputs.failOn,\n skipUnchanged: inputs.skipUnchanged,\n reviewMode: inputs.reviewMode,\n retireStaleReviews: inputs.retireStaleReviews,\n modelLabel,\n };\n if (inputs.provider === \"anthropic\") {\n const model = makeAnthropicReviewModel(inputs.model, inputs.effort);\n const reviewer = inputs.fanOut\n ? PrReview.makeFanOut({ ...shared, model })\n : PrReview.make({ ...shared, model });\n return yield* runReviewAction(reviewer, harness).pipe(\n Effect.provide(Layer.merge(stateAuthenticatorLayer, anthropicClientLayer)),\n );\n }\n const model = makeOpenAiReviewModel(inputs.model, inputs.effort);\n const reviewer = inputs.fanOut\n ? PrReview.makeFanOut({ ...shared, model })\n : PrReview.make({ ...shared, model });\n return yield* runReviewAction(reviewer, harness).pipe(\n Effect.provide(Layer.merge(stateAuthenticatorLayer, openAiClientLayer)),\n );\n});\n\n/** Run the packaged action program on Node; the bundled action entrypoint. */\nexport const main = (): void =>\n NodeRuntime.runMain(\n reviewActionProgram.pipe(\n Effect.tapError((error) =>\n Console.error(\n Schema.is(BudgetExceeded)(error)\n ? `Budget exceeded: ${error.limit} observed ${error.observedValue}, limit ${error.limitValue}.`\n : String(error),\n ),\n ),\n Effect.scoped,\n Effect.provide(Layer.merge(NodeServices.layer, FetchHttpClient.layer)),\n ),\n { disableErrorReporting: true },\n );\n\n/** The packaged GitHub Actions surface. */\nexport const PrReviewAction = {\n inputs: resolveActionInputs,\n run: runReviewAction,\n program: reviewActionProgram,\n main,\n} as const;\n"],"mappings":"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"}
package/dist/cli.mjs CHANGED
@@ -1,7 +1,8 @@
1
- import { s as fingerprintUnchanged } from "./github-BZNzmxao.mjs";
2
- import { A as InvalidEffortInput, M as parseEffortPosition, a as anthropicClientLayer, c as makeOpenAiReviewModel, f as gitHubReviewLayers, h as PrReview, l as openAiClientLayer, m as resolveReviewTarget, n as DEFAULT_PROVIDER, o as describeReviewModel, s as makeAnthropicReviewModel, t as DEFAULT_MODEL, w as ReviewPublicationPlan } from "./providers-J6BKHyHe.mjs";
1
+ import { s as fingerprintUnchanged } from "./github-Lfa_ox-u.mjs";
2
+ import { A as InvalidEffortInput, M as parseEffortPosition, a as anthropicClientLayer, c as makeOpenAiReviewModel, f as gitHubReviewLayers, h as PrReview, l as openAiClientLayer, m as resolveReviewTarget, n as DEFAULT_PROVIDER, o as describeReviewModel, s as makeAnthropicReviewModel, t as DEFAULT_MODEL, w as ReviewPublicationPlan } from "./providers-CaOnz7mK.mjs";
3
3
  import { Console, Effect, Layer, Option, Schema } from "effect";
4
4
  import { BudgetExceeded } from "effect-agent";
5
+ import { FetchHttpClient } from "effect/unstable/http";
5
6
  import { NodeRuntime, NodeServices } from "@effect/platform-node";
6
7
  import { Command, Flag } from "effect/unstable/cli";
7
8
  //#region src/cli.ts
@@ -94,7 +95,7 @@ const command = Command.make("pr-review", {
94
95
  yield* Console.log(JSON.stringify(encodedPlan, null, 2));
95
96
  }
96
97
  })).pipe(Command.withDescription("Review one GitHub pull request with an @effect-agent/pr-review reviewer and post the validated result as a pull-request review."));
97
- const program = Command.run(command, { version: "0.0.0" }).pipe(Effect.tapError((error) => Console.error(Schema.is(BudgetExceeded)(error) ? `Budget exceeded: ${error.limit} observed ${error.observedValue}, limit ${error.limitValue}.` : String(error))), Effect.scoped, Effect.provide(NodeServices.layer));
98
+ const program = Command.run(command, { version: "0.0.0" }).pipe(Effect.tapError((error) => Console.error(Schema.is(BudgetExceeded)(error) ? `Budget exceeded: ${error.limit} observed ${error.observedValue}, limit ${error.limitValue}.` : String(error))), Effect.scoped, Effect.provide(Layer.merge(NodeServices.layer, FetchHttpClient.layer)));
98
99
  NodeRuntime.runMain(program, { disableErrorReporting: true });
99
100
  //#endregion
100
101
  export {};
package/dist/cli.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.mjs","names":["CliCommand"],"sources":["../src/cli.ts"],"sourcesContent":["import { NodeRuntime, NodeServices } from \"@effect/platform-node\";\nimport { Console, Effect, Layer, Option, Schema } from \"effect\";\nimport { BudgetExceeded } from \"effect-agent\";\nimport { Command as CliCommand, Flag } from \"effect/unstable/cli\";\n\nimport { InvalidEffortInput, parseEffortPosition, type EffortPosition } from \"./internal/effort.ts\";\nimport { PrReview, type RunReviewOptions } from \"./internal/factory.ts\";\nimport { gitHubReviewLayers, resolveReviewTarget } from \"./internal/github-env.ts\";\nimport { fingerprintUnchanged } from \"./internal/github.ts\";\nimport {\n anthropicClientLayer,\n DEFAULT_MODEL,\n DEFAULT_PROVIDER,\n describeReviewModel,\n makeAnthropicReviewModel,\n makeOpenAiReviewModel,\n openAiClientLayer,\n type ReviewProvider,\n} from \"./internal/providers.ts\";\nimport { ReviewPublicationPlan } from \"./internal/render.ts\";\nimport type { ReviewRunOutcome } from \"./internal/run.ts\";\n\n// ---------------------------------------------------------------------------\n// The CLI entrypoint: resolve which pull request to review (flags first, then\n// the GitHub Actions event environment), run one bounded ephemeral review,\n// and either print the validated publication plan (default: dry run) or post\n// it as a pull-request review (--post).\n// ---------------------------------------------------------------------------\n\nconst repoFlag = Flag.string(\"repo\").pipe(\n Flag.optional,\n Flag.withDescription(\"Repository as owner/name; defaults to GITHUB_REPOSITORY.\"),\n);\nconst prFlag = Flag.integer(\"pr\").pipe(\n Flag.optional,\n Flag.withDescription(\"Pull request number; defaults to the GITHUB_EVENT_PATH payload.\"),\n);\nconst providerFlag = Flag.string(\"provider\").pipe(\n Flag.withDefault<string>(DEFAULT_PROVIDER),\n Flag.withDescription('Model provider: \"openai\" (default) or \"anthropic\".'),\n);\nconst modelFlag = Flag.string(\"model\").pipe(\n Flag.optional,\n Flag.withDescription(\n `Model id (defaults: openai ${DEFAULT_MODEL.openai}, anthropic ${DEFAULT_MODEL.anthropic}).`,\n ),\n);\nconst effortFlag = Flag.string(\"effort\").pipe(\n Flag.optional,\n Flag.withDescription(\n 'Reasoning effort: \"low\", \"medium\", \"high\", \"xhigh\", \"max\", or a number in [0, 1] resolved onto the provider\\'s own ladder.',\n ),\n);\nconst postFlag = Flag.boolean(\"post\").pipe(\n Flag.withDescription(\"Post the review to GitHub; without it the plan prints to stdout.\"),\n);\nconst applyVerdictFlag = Flag.boolean(\"apply-verdict\").pipe(\n Flag.withDescription(\n \"Map the model verdict onto APPROVE/REQUEST_CHANGES instead of always COMMENT.\",\n ),\n);\nconst fanOutFlag = Flag.boolean(\"fan-out\").pipe(\n Flag.withDescription(\n \"Fan the review out to bounded per-unit subagent reviewers (S1 attached delegation) instead of one flat reviewer.\",\n ),\n);\nconst ignoreFlag = Flag.string(\"ignore\").pipe(\n Flag.withDefault(\"\"),\n Flag.withDescription(\n 'Comma-separated glob patterns removed from the review surface, e.g. \"**/*.lock,dist/**\".',\n ),\n);\nconst maxFindingsFlag = Flag.integer(\"max-findings\").pipe(\n Flag.optional,\n Flag.withDescription(\"Findings bound (1-20); the schema cap of 20 applies regardless.\"),\n);\nconst skipUnchangedFlag = Flag.boolean(\"skip-unchanged\").pipe(\n Flag.withDescription(\n \"Skip when the changeset fingerprint matches the last posted review (explicit runs review unconditionally by default).\",\n ),\n);\n\n/** An unknown --provider value; the two supported providers are spelled out. */\nclass UnknownProvider extends Schema.TaggedError<UnknownProvider>()(\"UnknownProvider\", {\n provider: Schema.String,\n}) {\n override get message() {\n return `Unknown provider '${this.provider}': expected \"openai\" or \"anthropic\".`;\n }\n}\n\nconst decodeProvider = (raw: string): Effect.Effect<ReviewProvider, UnknownProvider> =>\n raw === \"openai\" || raw === \"anthropic\"\n ? Effect.succeed(raw)\n : Effect.fail(UnknownProvider.make({ provider: raw }));\n\nconst command = CliCommand.make(\n \"pr-review\",\n {\n repo: repoFlag,\n pr: prFlag,\n provider: providerFlag,\n model: modelFlag,\n effort: effortFlag,\n post: postFlag,\n applyVerdict: applyVerdictFlag,\n fanOut: fanOutFlag,\n ignore: ignoreFlag,\n maxFindings: maxFindingsFlag,\n skipUnchanged: skipUnchangedFlag,\n },\n (flags) =>\n Effect.gen(function* () {\n const provider = yield* decodeProvider(flags.provider);\n const target = yield* resolveReviewTarget({\n repository: Option.getOrUndefined(flags.repo),\n number: Option.getOrUndefined(flags.pr),\n });\n const model = Option.getOrUndefined(flags.model);\n const effortRaw = Option.getOrUndefined(flags.effort);\n let effort: EffortPosition | undefined;\n if (effortRaw !== undefined) {\n effort = parseEffortPosition(effortRaw);\n if (effort === undefined) {\n return yield* InvalidEffortInput.make({ input: effortRaw });\n }\n }\n const shared = {\n applyVerdict: flags.applyVerdict,\n ignore: flags.ignore\n .split(\",\")\n .map((pattern) => pattern.trim())\n .filter((pattern) => pattern.length > 0),\n maxFindings: Option.getOrUndefined(flags.maxFindings),\n modelLabel: describeReviewModel(provider, model, effort),\n };\n\n yield* Console.log(\n `Reviewing ${target.repository}#${target.number} with ${provider}:${model ?? DEFAULT_MODEL[provider]} (${flags.post ? \"posting\" : \"dry run\"}${flags.fanOut ? \", fan-out\" : \"\"})...`,\n );\n\n const githubLayers = gitHubReviewLayers(target);\n // Fingerprint check and run under ONE provide, sharing the cached\n // pull-request snapshot; None means \"unchanged, skipped\".\n const runOrSkip = <E, R, FingerprintE, FingerprintR>(reviewer: {\n readonly run: (runOptions?: RunReviewOptions) => Effect.Effect<ReviewRunOutcome, E, R>;\n readonly fingerprint: Effect.Effect<string, FingerprintE, FingerprintR>;\n }) =>\n Effect.gen(function* () {\n if (flags.skipUnchanged) {\n const current = yield* reviewer.fingerprint;\n if (yield* fingerprintUnchanged(current)) {\n return Option.none<ReviewRunOutcome>();\n }\n }\n return Option.some(yield* reviewer.run({ post: flags.post }));\n });\n\n let result: Option.Option<ReviewRunOutcome>;\n if (provider === \"anthropic\") {\n const boundModel = makeAnthropicReviewModel(model, effort);\n const reviewer = flags.fanOut\n ? PrReview.makeFanOut({ ...shared, model: boundModel })\n : PrReview.make({ ...shared, model: boundModel });\n result = yield* runOrSkip(reviewer).pipe(\n Effect.provide(Layer.merge(githubLayers, anthropicClientLayer)),\n );\n } else {\n const boundModel = makeOpenAiReviewModel(model, effort);\n const reviewer = flags.fanOut\n ? PrReview.makeFanOut({ ...shared, model: boundModel })\n : PrReview.make({ ...shared, model: boundModel });\n result = yield* runOrSkip(reviewer).pipe(\n Effect.provide(Layer.merge(githubLayers, openAiClientLayer)),\n );\n }\n\n if (Option.isNone(result)) {\n yield* Console.log(\"Skipped: changeset unchanged since the last posted review.\");\n return;\n }\n const outcome = result.value;\n\n yield* Console.log(\n `Review finished in ${outcome.turns} turn(s): verdict ${outcome.review.verdict}, ` +\n `${outcome.plan.comments.length} inline comment(s), ${outcome.plan.demoted.length} demoted finding(s).`,\n );\n if (outcome.published !== undefined) {\n yield* Console.log(`Posted ${outcome.published.event} review: ${outcome.published.url}`);\n } else {\n const encodedPlan = yield* Schema.encodeEffect(ReviewPublicationPlan)(outcome.plan);\n yield* Console.log(JSON.stringify(encodedPlan, null, 2));\n }\n }),\n).pipe(\n CliCommand.withDescription(\n \"Review one GitHub pull request with an @effect-agent/pr-review reviewer and post the validated result as a pull-request review.\",\n ),\n);\n\nconst program = CliCommand.run(command, { version: \"0.0.0\" }).pipe(\n Effect.tapError((error) =>\n Console.error(\n Schema.is(BudgetExceeded)(error)\n ? `Budget exceeded: ${error.limit} observed ${error.observedValue}, limit ${error.limitValue}.`\n : String(error),\n ),\n ),\n Effect.scoped,\n Effect.provide(NodeServices.layer),\n);\n\nNodeRuntime.runMain(program, { disableErrorReporting: true });\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.mjs","names":["CliCommand"],"sources":["../src/cli.ts"],"sourcesContent":["import { NodeRuntime, NodeServices } from \"@effect/platform-node\";\nimport { Console, Effect, Layer, Option, Schema } from \"effect\";\nimport { BudgetExceeded } from \"effect-agent\";\nimport { Command as CliCommand, Flag } from \"effect/unstable/cli\";\nimport { FetchHttpClient } from \"effect/unstable/http\";\n\nimport { InvalidEffortInput, parseEffortPosition, type EffortPosition } from \"./internal/effort.ts\";\nimport { PrReview, type RunReviewOptions } from \"./internal/factory.ts\";\nimport { gitHubReviewLayers, resolveReviewTarget } from \"./internal/github-env.ts\";\nimport { fingerprintUnchanged } from \"./internal/github.ts\";\nimport {\n anthropicClientLayer,\n DEFAULT_MODEL,\n DEFAULT_PROVIDER,\n describeReviewModel,\n makeAnthropicReviewModel,\n makeOpenAiReviewModel,\n openAiClientLayer,\n type ReviewProvider,\n} from \"./internal/providers.ts\";\nimport { ReviewPublicationPlan } from \"./internal/render.ts\";\nimport type { ReviewRunOutcome } from \"./internal/run.ts\";\n\n// ---------------------------------------------------------------------------\n// The CLI entrypoint: resolve which pull request to review (flags first, then\n// the GitHub Actions event environment), run one bounded ephemeral review,\n// and either print the validated publication plan (default: dry run) or post\n// it as a pull-request review (--post).\n// ---------------------------------------------------------------------------\n\nconst repoFlag = Flag.string(\"repo\").pipe(\n Flag.optional,\n Flag.withDescription(\"Repository as owner/name; defaults to GITHUB_REPOSITORY.\"),\n);\nconst prFlag = Flag.integer(\"pr\").pipe(\n Flag.optional,\n Flag.withDescription(\"Pull request number; defaults to the GITHUB_EVENT_PATH payload.\"),\n);\nconst providerFlag = Flag.string(\"provider\").pipe(\n Flag.withDefault<string>(DEFAULT_PROVIDER),\n Flag.withDescription('Model provider: \"openai\" (default) or \"anthropic\".'),\n);\nconst modelFlag = Flag.string(\"model\").pipe(\n Flag.optional,\n Flag.withDescription(\n `Model id (defaults: openai ${DEFAULT_MODEL.openai}, anthropic ${DEFAULT_MODEL.anthropic}).`,\n ),\n);\nconst effortFlag = Flag.string(\"effort\").pipe(\n Flag.optional,\n Flag.withDescription(\n 'Reasoning effort: \"low\", \"medium\", \"high\", \"xhigh\", \"max\", or a number in [0, 1] resolved onto the provider\\'s own ladder.',\n ),\n);\nconst postFlag = Flag.boolean(\"post\").pipe(\n Flag.withDescription(\"Post the review to GitHub; without it the plan prints to stdout.\"),\n);\nconst applyVerdictFlag = Flag.boolean(\"apply-verdict\").pipe(\n Flag.withDescription(\n \"Map the model verdict onto APPROVE/REQUEST_CHANGES instead of always COMMENT.\",\n ),\n);\nconst fanOutFlag = Flag.boolean(\"fan-out\").pipe(\n Flag.withDescription(\n \"Fan the review out to bounded per-unit subagent reviewers (S1 attached delegation) instead of one flat reviewer.\",\n ),\n);\nconst ignoreFlag = Flag.string(\"ignore\").pipe(\n Flag.withDefault(\"\"),\n Flag.withDescription(\n 'Comma-separated glob patterns removed from the review surface, e.g. \"**/*.lock,dist/**\".',\n ),\n);\nconst maxFindingsFlag = Flag.integer(\"max-findings\").pipe(\n Flag.optional,\n Flag.withDescription(\"Findings bound (1-20); the schema cap of 20 applies regardless.\"),\n);\nconst skipUnchangedFlag = Flag.boolean(\"skip-unchanged\").pipe(\n Flag.withDescription(\n \"Skip when the changeset fingerprint matches the last posted review (explicit runs review unconditionally by default).\",\n ),\n);\n\n/** An unknown --provider value; the two supported providers are spelled out. */\nclass UnknownProvider extends Schema.TaggedError<UnknownProvider>()(\"UnknownProvider\", {\n provider: Schema.String,\n}) {\n override get message() {\n return `Unknown provider '${this.provider}': expected \"openai\" or \"anthropic\".`;\n }\n}\n\nconst decodeProvider = (raw: string): Effect.Effect<ReviewProvider, UnknownProvider> =>\n raw === \"openai\" || raw === \"anthropic\"\n ? Effect.succeed(raw)\n : Effect.fail(UnknownProvider.make({ provider: raw }));\n\nconst command = CliCommand.make(\n \"pr-review\",\n {\n repo: repoFlag,\n pr: prFlag,\n provider: providerFlag,\n model: modelFlag,\n effort: effortFlag,\n post: postFlag,\n applyVerdict: applyVerdictFlag,\n fanOut: fanOutFlag,\n ignore: ignoreFlag,\n maxFindings: maxFindingsFlag,\n skipUnchanged: skipUnchangedFlag,\n },\n (flags) =>\n Effect.gen(function* () {\n const provider = yield* decodeProvider(flags.provider);\n const target = yield* resolveReviewTarget({\n repository: Option.getOrUndefined(flags.repo),\n number: Option.getOrUndefined(flags.pr),\n });\n const model = Option.getOrUndefined(flags.model);\n const effortRaw = Option.getOrUndefined(flags.effort);\n let effort: EffortPosition | undefined;\n if (effortRaw !== undefined) {\n effort = parseEffortPosition(effortRaw);\n if (effort === undefined) {\n return yield* InvalidEffortInput.make({ input: effortRaw });\n }\n }\n const shared = {\n applyVerdict: flags.applyVerdict,\n ignore: flags.ignore\n .split(\",\")\n .map((pattern) => pattern.trim())\n .filter((pattern) => pattern.length > 0),\n maxFindings: Option.getOrUndefined(flags.maxFindings),\n modelLabel: describeReviewModel(provider, model, effort),\n };\n\n yield* Console.log(\n `Reviewing ${target.repository}#${target.number} with ${provider}:${model ?? DEFAULT_MODEL[provider]} (${flags.post ? \"posting\" : \"dry run\"}${flags.fanOut ? \", fan-out\" : \"\"})...`,\n );\n\n const githubLayers = gitHubReviewLayers(target);\n // Fingerprint check and run under ONE provide, sharing the cached\n // pull-request snapshot; None means \"unchanged, skipped\".\n const runOrSkip = <E, R, FingerprintE, FingerprintR>(reviewer: {\n readonly run: (runOptions?: RunReviewOptions) => Effect.Effect<ReviewRunOutcome, E, R>;\n readonly fingerprint: Effect.Effect<string, FingerprintE, FingerprintR>;\n }) =>\n Effect.gen(function* () {\n if (flags.skipUnchanged) {\n const current = yield* reviewer.fingerprint;\n if (yield* fingerprintUnchanged(current)) {\n return Option.none<ReviewRunOutcome>();\n }\n }\n return Option.some(yield* reviewer.run({ post: flags.post }));\n });\n\n let result: Option.Option<ReviewRunOutcome>;\n if (provider === \"anthropic\") {\n const boundModel = makeAnthropicReviewModel(model, effort);\n const reviewer = flags.fanOut\n ? PrReview.makeFanOut({ ...shared, model: boundModel })\n : PrReview.make({ ...shared, model: boundModel });\n result = yield* runOrSkip(reviewer).pipe(\n Effect.provide(Layer.merge(githubLayers, anthropicClientLayer)),\n );\n } else {\n const boundModel = makeOpenAiReviewModel(model, effort);\n const reviewer = flags.fanOut\n ? PrReview.makeFanOut({ ...shared, model: boundModel })\n : PrReview.make({ ...shared, model: boundModel });\n result = yield* runOrSkip(reviewer).pipe(\n Effect.provide(Layer.merge(githubLayers, openAiClientLayer)),\n );\n }\n\n if (Option.isNone(result)) {\n yield* Console.log(\"Skipped: changeset unchanged since the last posted review.\");\n return;\n }\n const outcome = result.value;\n\n yield* Console.log(\n `Review finished in ${outcome.turns} turn(s): verdict ${outcome.review.verdict}, ` +\n `${outcome.plan.comments.length} inline comment(s), ${outcome.plan.demoted.length} demoted finding(s).`,\n );\n if (outcome.published !== undefined) {\n yield* Console.log(`Posted ${outcome.published.event} review: ${outcome.published.url}`);\n } else {\n const encodedPlan = yield* Schema.encodeEffect(ReviewPublicationPlan)(outcome.plan);\n yield* Console.log(JSON.stringify(encodedPlan, null, 2));\n }\n }),\n).pipe(\n CliCommand.withDescription(\n \"Review one GitHub pull request with an @effect-agent/pr-review reviewer and post the validated result as a pull-request review.\",\n ),\n);\n\nconst program = CliCommand.run(command, { version: \"0.0.0\" }).pipe(\n Effect.tapError((error) =>\n Console.error(\n Schema.is(BudgetExceeded)(error)\n ? `Budget exceeded: ${error.limit} observed ${error.observedValue}, limit ${error.limitValue}.`\n : String(error),\n ),\n ),\n Effect.scoped,\n Effect.provide(Layer.merge(NodeServices.layer, FetchHttpClient.layer)),\n);\n\nNodeRuntime.runMain(program, { disableErrorReporting: true });\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { Context, Effect, Layer, Option, Redacted, Schema } from "effect";
1
+ import { Context, DateTime, Effect, Layer, Option, Redacted, Schema } from "effect";
2
2
  import { AgentPolicy, RunEvent, RuntimeBinding, SubagentPolicy } from "effect-agent";
3
3
  import { Tool, Toolkit } from "effect/unstable/ai";
4
4
  import { HttpClient } from "effect/unstable/http";
@@ -551,10 +551,86 @@ declare const planPublication: (review: CodeReview, files: ReadonlyArray<Changed
551
551
  readonly stateNotice?: string | undefined;
552
552
  }) => ReviewPublicationPlan;
553
553
  //#endregion
554
+ //#region src/internal/retirement.d.ts
555
+ declare const RetirableReview_base: Schema.Class<RetirableReview, Schema.Struct<{
556
+ readonly reviewId: Schema.Int;
557
+ readonly body: Schema.String;
558
+ readonly commitSha: Schema.NonEmptyString;
559
+ readonly authorNodeId: Schema.NullOr<Schema.NonEmptyString>;
560
+ readonly submittedAt: Schema.NullOr<Schema.DateTimeUtc>;
561
+ }>, {}>;
562
+ /** One previously posted review as observed through the retirement host. */
563
+ declare class RetirableReview extends RetirableReview_base {}
564
+ declare const RetirableReviewComment_base: Schema.Class<RetirableReviewComment, Schema.Struct<{
565
+ readonly nodeId: Schema.NonEmptyString;
566
+ readonly path: Schema.NonEmptyString;
567
+ readonly startLine: Schema.NullOr<Schema.Int>;
568
+ readonly endLine: Schema.NullOr<Schema.Int>;
569
+ readonly body: Schema.String;
570
+ }>, {}>;
571
+ /** One inline comment attached to a previously posted review. */
572
+ declare class RetirableReviewComment extends RetirableReviewComment_base {}
573
+ declare const ReviewRetirementFailure_base: Schema.Class<ReviewRetirementFailure, Schema.TaggedStruct<"ReviewRetirementFailure", {
574
+ readonly operation: Schema.String;
575
+ readonly reason: Schema.String;
576
+ }>, import("effect/Cause").YieldableError>;
577
+ /** A GitHub retirement read or mutation failed. */
578
+ declare class ReviewRetirementFailure extends ReviewRetirementFailure_base {
579
+ get message(): string;
580
+ }
581
+ declare const ReviewRetirementHost_base: Context.ServiceClass<ReviewRetirementHost, "@effect-agent/pr-review/ReviewRetirementHost", {
582
+ readonly listReviews: Effect.Effect<ReadonlyArray<RetirableReview>, ReviewRetirementFailure>;
583
+ readonly listComments: (reviewId: number) => Effect.Effect<ReadonlyArray<RetirableReviewComment>, ReviewRetirementFailure>;
584
+ readonly updateBody: (reviewId: number, body: string) => Effect.Effect<void, ReviewRetirementFailure>;
585
+ readonly minimizeComment: (nodeId: string) => Effect.Effect<void, ReviewRetirementFailure>;
586
+ }>;
587
+ /**
588
+ * Host-side GitHub operations used by retirement. Domain code never reaches
589
+ * into REST or GraphQL directly, and deterministic tests substitute this port.
590
+ */
591
+ declare class ReviewRetirementHost extends ReviewRetirementHost_base {}
592
+ declare const ReviewRetirementReport_base: Schema.Class<ReviewRetirementReport, Schema.Struct<{
593
+ readonly reviewsRetired: Schema.Int;
594
+ readonly findingsResolved: Schema.Int;
595
+ readonly commentsMinimized: Schema.Int;
596
+ readonly failures: Schema.Int;
597
+ }>, {}>;
598
+ /** Observable cosmetic work completed by one fail-open retirement pass. */
599
+ declare class ReviewRetirementReport extends ReviewRetirementReport_base {}
600
+ interface ReviewRetirementInput {
601
+ readonly currentReviewId: number;
602
+ readonly currentReviewUrl: string;
603
+ readonly currentAuthorNodeId: string;
604
+ readonly currentSubmittedAt: DateTime.Utc;
605
+ readonly currentState: ReviewState;
606
+ }
607
+ interface ReviewRetirementDecision {
608
+ readonly body: string;
609
+ readonly resolvedFindings: ReadonlyArray<StoredReviewFinding>;
610
+ readonly priorFindingCount: number;
611
+ }
612
+ /** The host-authored metadata marker is the authority gate for any edit. */
613
+ declare const hasReviewMetadataMarker: (body: string) => boolean;
614
+ /** Compute one prior review's resolved subset and deterministic retired body. */
615
+ declare const decideReviewRetirement: (input: {
616
+ readonly priorBody: string;
617
+ readonly priorState: ReviewState;
618
+ readonly currentState: ReviewState;
619
+ readonly currentReviewUrl: string;
620
+ }) => ReviewRetirementDecision;
621
+ /**
622
+ * Retire every marker-bearing prior review against the newest posted state.
623
+ * Every lookup, edit, and minimization is isolated: retirement is cosmetic
624
+ * and can never change the run or check outcome.
625
+ */
626
+ declare const retireStaleReviews: (input: ReviewRetirementInput) => Effect.Effect<ReviewRetirementReport, never, ReviewRetirementHost | ReviewStateAuthenticator>;
627
+ //#endregion
554
628
  //#region src/internal/github.d.ts
555
629
  declare const GitHubReviewTarget_base: Context.ServiceClass<GitHubReviewTarget, "@effect-agent/pr-review/GitHubReviewTarget", {
556
630
  /** API root, e.g. `https://api.github.com` (no trailing slash). */
557
631
  readonly apiUrl: string;
632
+ /** GraphQL root, e.g. `https://api.github.com/graphql`. */
633
+ readonly graphqlUrl: string;
558
634
  /** `owner/name`. */
559
635
  readonly repository: string;
560
636
  readonly number: number;
@@ -565,6 +641,7 @@ declare const GitHubReviewTarget_base: Context.ServiceClass<GitHubReviewTarget,
565
641
  declare class GitHubReviewTarget extends GitHubReviewTarget_base {
566
642
  static layer(config: {
567
643
  readonly apiUrl: string;
644
+ readonly graphqlUrl?: string | undefined;
568
645
  readonly repository: string;
569
646
  readonly number: number;
570
647
  readonly token: Option.Option<Redacted.Redacted<string>>;
@@ -578,11 +655,16 @@ declare const GitHubApiFailure_base: Schema.Class<GitHubApiFailure, Schema.Tagge
578
655
  declare class GitHubApiFailure extends GitHubApiFailure_base {
579
656
  get message(): string;
580
657
  }
658
+ /** Decode GitHub's external timestamp before it participates in mutation ordering. */
659
+ declare const parseGitHubSubmittedAt: (value: string | null) => DateTime.Utc | null;
581
660
  declare const PublishedReview_base: Schema.Class<PublishedReview, Schema.Struct<{
582
661
  readonly reviewId: Schema.Int;
583
662
  readonly url: Schema.String;
584
663
  readonly event: Schema.String;
585
664
  readonly inlineComments: Schema.Int;
665
+ /** Actor and ordering boundary returned by the create-review response. */
666
+ readonly authorNodeId: Schema.NullOr<Schema.NonEmptyString>;
667
+ readonly submittedAt: Schema.NullOr<Schema.DateTimeUtc>;
586
668
  }>, {}>;
587
669
  /** The publication receipt callers report back to the operator. */
588
670
  declare class PublishedReview extends PublishedReview_base {}
@@ -599,6 +681,8 @@ declare class ReviewPublisher extends ReviewPublisher_base {}
599
681
  declare const gitHubPullRequestSourceLayer: Layer.Layer<PullRequestSource, never, GitHubReviewTarget | HttpClient.HttpClient>;
600
682
  /** GitHub-backed publisher: one POST to the pull-request reviews endpoint. */
601
683
  declare const gitHubReviewPublisherLayer: Layer.Layer<ReviewPublisher, never, GitHubReviewTarget | HttpClient.HttpClient>;
684
+ /** GitHub-backed host operations for cosmetic retirement after publication. */
685
+ declare const gitHubReviewRetirementHostLayer: Layer.Layer<ReviewRetirementHost, never, GitHubReviewTarget | HttpClient.HttpClient>;
602
686
  declare const PriorReviewLookupFailure_base: Schema.Class<PriorReviewLookupFailure, Schema.TaggedStruct<"PriorReviewLookupFailure", {
603
687
  readonly reason: Schema.String;
604
688
  }>, import("effect/Cause").YieldableError>;
@@ -993,5 +1077,5 @@ declare const fanOutHandlersLayer: <Provider, ModelProvides, ModelRequires>(chil
993
1077
  readonly message?: string;
994
1078
  }, never>>;
995
1079
  //#endregion
996
- export { gitHubReviewPublisherLayer as $, clampMaxFindings as $t, fileReviewerInstructions as A, ChangedFileSummary as At, ReviewUnitPlan as B, MAX_CONCERNS as Bt, defaultFanOutPolicy as C, commentableLines as Cn, selectReviewRange as Ct, fanOutReviewInstructions as D, unavailableReviewStateAuthenticatorLayer as Dt, fanOutHandlersLayerFor as E, toStoredFinding as Et, MAX_MERGED_FINDINGS as F, FileSlice as Ft, GitHubReviewTarget as G, ReviewConcern as Gt, planReviewUnits as H, PullRequestReviewer as Ht, MAX_REVIEW_UNITS as I, FileSliceQuery as It, PublishedReview as J, ReviewInstructionOptions as Jt, PriorReviewLookupFailure as K, ReviewFinding as Kt, MAX_UNIT_FILES as L, FindingSeverity as Lt, makeFanOutReviewSuite as M, CodeReview as Mt, makeFileReviewerInstructions as N, FileDiffQuery as Nt, fileReviewDelegation as O, validateReviewState as Ot, mapFileReviewChildFailure as P, FileDiffView as Pt, gitHubPullRequestSourceLayer as Q, ReviewVerdict as Qt, ReviewUnit as R, ListChangedFiles as Rt, MAX_FILE_REVIEW_TOOL_CALLS as S, annotatePatch as Sn, fromStoredFinding as St, fanOutHandlersLayer as T, toStoredConcern as Tt, rankAndDedupeFindings as U, ReadFile as Ut, UNIT_CHANGED_LINE_BUDGET as V, MAX_FINDINGS as Vt, GitHubApiFailure as W, ReadFileDiff as Wt, fingerprintUnchanged as X, ReviewToolkit as Xt, ReviewPublisher as Y, ReviewMission as Yt, gitHubPriorReviewsLayer as Z, ReviewToolkitLayer as Zt, FileReviewer as _, normalizeRepoRelativePath as _n, StoredReviewConcern as _t, FanOutReviewSuite as a, resolveGuidance as an, GitCommitSha as at, MAX_CHILD_CONCERNS as b, ChangedPath as bn, computeProfileFingerprint as bt, FanOutSuiteOptions as c, ReviewCoverage as cn, ReviewHeadComparison as ct, FileReviewReport as d, MAX_CHANGED_FILES as dn, ReviewSelection as dt, defaultReviewPolicy as en, ReviewCommentDraft as et, FileReviewRequest as f, MAX_FILE_CHARS as fn, ReviewState as ft, FileReviewUnitResult as g, ReviewInputViolation as gn, ReviewStateMarkerTooLarge as gt, FileReviewUnitFailed as h, PullRequestSourceFailure as hn, ReviewStateMarker as ht, FanOutInstructionOptions as i, readFileHandler as in, planPublication as it, makeFanOutReviewInstructions as j, ChangedFilesView as jt, fileReviewPolicy as k, webCryptoReviewStateAuthenticatorLayer as kt, FileReviewBrief as l, ReviewShape as ln, ReviewMode as lt, FileReviewToolkitLayer as m, PullRequestSource as mn, ReviewStateAuthenticator as mt, FanOutCoordinatorToolkit as n, makeReviewInstructions as nn, ReviewPublicationPlan as nt, FanOutReviewToolkit as o, reviewInstructions as on, MAX_REVIEW_STATE_MARKER_CHARS as ot, FileReviewToolkit as p, PullRequestMetadata as pn, ReviewStateAuthenticationFailure as pt, PriorReviews as q, ReviewGuidance as qt, FanOutCoordinatorToolkitLayer as r, readFileDiffHandler as rn, anchorViolation as rt, FanOutReviewer as s, FailedReviewUnit as sn, ReviewExecutionContext as st, DelegateFileReview as t, listChangedFilesHandler as tn, ReviewEvent as tt, FileReviewDelegationFailure as u, assessReviewCoverage as un, ReviewScopeMode as ut, ListReviewUnits as v, ChangedFile as vn, StoredReviewFinding as vt, defaultFileReviewerPolicy as w, parsePatch as wn, selectedPullRequestSourceLayer as wt, MAX_CHILD_FINDINGS as x, PatchLine as xn, fromStoredConcern as xt, ListReviewUnitsQuery as y, ChangedFileStatus as yn, buildProfileMission as yt, ReviewUnitId as z, ListChangedFilesQuery as zt };
997
- //# sourceMappingURL=fan-out-BBEATQwc.d.mts.map
1080
+ export { gitHubReviewPublisherLayer as $, MAX_FINDINGS as $t, fileReviewerInstructions as A, ChangedFile as An, StoredReviewFinding as At, ReviewUnitPlan as B, validateReviewState as Bt, defaultFanOutPolicy as C, MAX_CHANGED_FILES as Cn, ReviewSelection as Ct, fanOutReviewInstructions as D, PullRequestSourceFailure as Dn, ReviewStateMarker as Dt, fanOutHandlersLayerFor as E, PullRequestSource as En, ReviewStateAuthenticator as Et, MAX_MERGED_FINDINGS as F, commentableLines as Fn, selectReviewRange as Ft, GitHubReviewTarget as G, FileDiffQuery as Gt, planReviewUnits as H, ChangedFileSummary as Ht, MAX_REVIEW_UNITS as I, parsePatch as In, selectedPullRequestSourceLayer as It, PublishedReview as J, FileSliceQuery as Jt, PriorReviewLookupFailure as K, FileDiffView as Kt, MAX_UNIT_FILES as L, toStoredConcern as Lt, makeFanOutReviewSuite as M, ChangedPath as Mn, computeProfileFingerprint as Mt, makeFileReviewerInstructions as N, PatchLine as Nn, fromStoredConcern as Nt, fileReviewDelegation as O, ReviewInputViolation as On, ReviewStateMarkerTooLarge as Ot, mapFileReviewChildFailure as P, annotatePatch as Pn, fromStoredFinding as Pt, gitHubPullRequestSourceLayer as Q, MAX_CONCERNS as Qt, ReviewUnit as R, toStoredFinding as Rt, MAX_FILE_REVIEW_TOOL_CALLS as S, assessReviewCoverage as Sn, ReviewScopeMode as St, fanOutHandlersLayer as T, PullRequestMetadata as Tn, ReviewStateAuthenticationFailure as Tt, rankAndDedupeFindings as U, ChangedFilesView as Ut, UNIT_CHANGED_LINE_BUDGET as V, webCryptoReviewStateAuthenticatorLayer as Vt, GitHubApiFailure as W, CodeReview as Wt, fingerprintUnchanged as X, ListChangedFiles as Xt, ReviewPublisher as Y, FindingSeverity as Yt, gitHubPriorReviewsLayer as Z, ListChangedFilesQuery as Zt, FileReviewer as _, resolveGuidance as _n, GitCommitSha as _t, FanOutReviewSuite as a, ReviewGuidance as an, ReviewRetirementFailure as at, MAX_CHILD_CONCERNS as b, ReviewCoverage as bn, ReviewHeadComparison as bt, FanOutSuiteOptions as c, ReviewToolkit as cn, ReviewRetirementReport as ct, FileReviewReport as d, clampMaxFindings as dn, retireStaleReviews as dt, PullRequestReviewer as en, gitHubReviewRetirementHostLayer as et, FileReviewRequest as f, defaultReviewPolicy as fn, ReviewCommentDraft as ft, FileReviewUnitResult as g, readFileHandler as gn, planPublication as gt, FileReviewUnitFailed as h, readFileDiffHandler as hn, anchorViolation as ht, FanOutInstructionOptions as i, ReviewFinding as in, ReviewRetirementDecision as it, makeFanOutReviewInstructions as j, ChangedFileStatus as jn, buildProfileMission as jt, fileReviewPolicy as k, normalizeRepoRelativePath as kn, StoredReviewConcern as kt, FileReviewBrief as l, ReviewToolkitLayer as ln, decideReviewRetirement as lt, FileReviewToolkitLayer as m, makeReviewInstructions as mn, ReviewPublicationPlan as mt, FanOutCoordinatorToolkit as n, ReadFileDiff as nn, RetirableReview as nt, FanOutReviewToolkit as o, ReviewInstructionOptions as on, ReviewRetirementHost as ot, FileReviewToolkit as p, listChangedFilesHandler as pn, ReviewEvent as pt, PriorReviews as q, FileSlice as qt, FanOutCoordinatorToolkitLayer as r, ReviewConcern as rn, RetirableReviewComment as rt, FanOutReviewer as s, ReviewMission as sn, ReviewRetirementInput as st, DelegateFileReview as t, ReadFile as tn, parseGitHubSubmittedAt as tt, FileReviewDelegationFailure as u, ReviewVerdict as un, hasReviewMetadataMarker as ut, ListReviewUnits as v, reviewInstructions as vn, MAX_REVIEW_STATE_MARKER_CHARS as vt, defaultFileReviewerPolicy as w, MAX_FILE_CHARS as wn, ReviewState as wt, MAX_CHILD_FINDINGS as x, ReviewShape as xn, ReviewMode as xt, ListReviewUnitsQuery as y, FailedReviewUnit as yn, ReviewExecutionContext as yt, ReviewUnitId as z, unavailableReviewStateAuthenticatorLayer as zt };
1081
+ //# sourceMappingURL=fan-out-C6gq3CFg.d.mts.map