terramend 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +145 -0
- package/dist/agents/claude.d.ts +73 -0
- package/dist/agents/claudePretoolGate.d.ts +99 -0
- package/dist/agents/gateServer.d.ts +7 -0
- package/dist/agents/index.d.ts +6 -0
- package/dist/agents/nativeFsDenies.d.ts +28 -0
- package/dist/agents/opencode.d.ts +231 -0
- package/dist/agents/opencodePlugin.d.ts +85 -0
- package/dist/agents/opencodeShared.d.ts +40 -0
- package/dist/agents/postRun.d.ts +132 -0
- package/dist/agents/reviewer.d.ts +38 -0
- package/dist/agents/sessionLabeler.d.ts +97 -0
- package/dist/agents/shared.d.ts +189 -0
- package/dist/agents/subagentModels.d.ts +19 -0
- package/dist/agents/subagentToolGates.d.ts +55 -0
- package/dist/cli.mjs +197426 -0
- package/dist/external.d.ts +227 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +196783 -0
- package/dist/internal/index.d.ts +18 -0
- package/dist/internal.js +1714 -0
- package/dist/lifecycle.d.ts +2 -0
- package/dist/main.d.ts +8 -0
- package/dist/mcp/arkConfig.d.ts +1 -0
- package/dist/mcp/checkSuite.d.ts +25 -0
- package/dist/mcp/checkout.d.ts +77 -0
- package/dist/mcp/comment.d.ts +119 -0
- package/dist/mcp/commitInfo.d.ts +9 -0
- package/dist/mcp/crosswalk.d.ts +105 -0
- package/dist/mcp/dependencies.d.ts +8 -0
- package/dist/mcp/geminiSanitizer.d.ts +28 -0
- package/dist/mcp/git.d.ts +46 -0
- package/dist/mcp/guardrails.d.ts +104 -0
- package/dist/mcp/issue.d.ts +18 -0
- package/dist/mcp/issueComments.d.ts +9 -0
- package/dist/mcp/issueEvents.d.ts +9 -0
- package/dist/mcp/issueInfo.d.ts +9 -0
- package/dist/mcp/labels.d.ts +12 -0
- package/dist/mcp/localContext.d.ts +19 -0
- package/dist/mcp/moduleExtraction.d.ts +71 -0
- package/dist/mcp/moduleTests.d.ts +104 -0
- package/dist/mcp/modules.d.ts +179 -0
- package/dist/mcp/output.d.ts +12 -0
- package/dist/mcp/pathSafety.d.ts +14 -0
- package/dist/mcp/policy.d.ts +48 -0
- package/dist/mcp/pr.d.ts +49 -0
- package/dist/mcp/prInfo.d.ts +9 -0
- package/dist/mcp/providerSchema.d.ts +50 -0
- package/dist/mcp/review.d.ts +199 -0
- package/dist/mcp/reviewComments.d.ts +178 -0
- package/dist/mcp/roots.d.ts +58 -0
- package/dist/mcp/scope.d.ts +15 -0
- package/dist/mcp/selectMode.d.ts +18 -0
- package/dist/mcp/server.d.ts +48 -0
- package/dist/mcp/shared.d.ts +47 -0
- package/dist/mcp/shell.d.ts +37 -0
- package/dist/mcp/staleFix.d.ts +51 -0
- package/dist/mcp/terraform/cost.d.ts +55 -0
- package/dist/mcp/terraform/currency.d.ts +94 -0
- package/dist/mcp/terraform/decisions.d.ts +178 -0
- package/dist/mcp/terraform/findings.d.ts +75 -0
- package/dist/mcp/terraform/plan.d.ts +157 -0
- package/dist/mcp/terraform/scanners.d.ts +131 -0
- package/dist/mcp/terraform/tools.d.ts +63 -0
- package/dist/mcp/terraform/types.d.ts +172 -0
- package/dist/mcp/terraform.d.ts +22 -0
- package/dist/mcp/terratest.d.ts +83 -0
- package/dist/mcp/upload.d.ts +6 -0
- package/dist/models.d.ts +171 -0
- package/dist/modes.d.ts +26 -0
- package/dist/prep/index.d.ts +7 -0
- package/dist/prep/installNodeDependencies.d.ts +2 -0
- package/dist/prep/installPythonDependencies.d.ts +2 -0
- package/dist/prep/types.d.ts +31 -0
- package/dist/reviewQuality.d.ts +64 -0
- package/dist/skills/terraform-best-practices/SKILL.md +369 -0
- package/dist/toolState.d.ts +135 -0
- package/dist/utils/activity.d.ts +40 -0
- package/dist/utils/agent.d.ts +20 -0
- package/dist/utils/agentHangReport.d.ts +38 -0
- package/dist/utils/apiFetch.d.ts +19 -0
- package/dist/utils/apiKeys.d.ts +41 -0
- package/dist/utils/apiUrl.d.ts +20 -0
- package/dist/utils/assets.d.ts +8 -0
- package/dist/utils/billingErrors.d.ts +85 -0
- package/dist/utils/body.d.ts +34 -0
- package/dist/utils/buildTerramendFooter.d.ts +25 -0
- package/dist/utils/byokFallback.d.ts +85 -0
- package/dist/utils/claudeSubscription.d.ts +30 -0
- package/dist/utils/cli.d.ts +10 -0
- package/dist/utils/codexHome.d.ts +29 -0
- package/dist/utils/codexOAuth.d.ts +60 -0
- package/dist/utils/diffCoverage.d.ts +63 -0
- package/dist/utils/errorReport.d.ts +17 -0
- package/dist/utils/exitHandler.d.ts +8 -0
- package/dist/utils/fixDoubleEscapedString.d.ts +1 -0
- package/dist/utils/gitAuth.d.ts +84 -0
- package/dist/utils/gitAuthServer.d.ts +24 -0
- package/dist/utils/github.d.ts +78 -0
- package/dist/utils/globals.d.ts +3 -0
- package/dist/utils/install.d.ts +60 -0
- package/dist/utils/instructions.d.ts +48 -0
- package/dist/utils/leapingComment.d.ts +11 -0
- package/dist/utils/learnings.d.ts +62 -0
- package/dist/utils/learningsTruncate.d.ts +25 -0
- package/dist/utils/lifecycle.d.ts +57 -0
- package/dist/utils/log.d.ts +111 -0
- package/dist/utils/normalizeEnv.d.ts +30 -0
- package/dist/utils/openCodeModels.d.ts +11 -0
- package/dist/utils/overrides.d.ts +40 -0
- package/dist/utils/packageManager.d.ts +49 -0
- package/dist/utils/patchWorkflowRunFields.d.ts +29 -0
- package/dist/utils/payload.d.ts +105 -0
- package/dist/utils/prSummary.d.ts +61 -0
- package/dist/utils/progressComment.d.ts +146 -0
- package/dist/utils/providerErrors.d.ts +31 -0
- package/dist/utils/rangeDiff.d.ts +51 -0
- package/dist/utils/remediationCommand.d.ts +55 -0
- package/dist/utils/retry.d.ts +13 -0
- package/dist/utils/reviewCleanup.d.ts +14 -0
- package/dist/utils/run.d.ts +9 -0
- package/dist/utils/runContext.d.ts +60 -0
- package/dist/utils/runContextData.d.ts +23 -0
- package/dist/utils/runErrorRenderer.d.ts +64 -0
- package/dist/utils/runLifecycle.d.ts +86 -0
- package/dist/utils/runStartupLog.d.ts +15 -0
- package/dist/utils/secrets.d.ts +22 -0
- package/dist/utils/setup.d.ts +90 -0
- package/dist/utils/shell.d.ts +32 -0
- package/dist/utils/skills.d.ts +10 -0
- package/dist/utils/subprocess.d.ts +80 -0
- package/dist/utils/terraformMcp.d.ts +42 -0
- package/dist/utils/time.d.ts +15 -0
- package/dist/utils/timer.d.ts +23 -0
- package/dist/utils/todoTracking.d.ts +16 -0
- package/dist/utils/token.d.ts +39 -0
- package/dist/utils/version.d.ts +2 -0
- package/dist/utils/versioning.d.ts +7 -0
- package/dist/utils/vertex.d.ts +16 -0
- package/dist/utils/workflow.d.ts +13 -0
- package/package.json +119 -0
- package/src/agents/claude.test.ts +1016 -0
- package/src/agents/claude.ts +1246 -0
- package/src/agents/claudePretoolGate.test.ts +28 -0
- package/src/agents/claudePretoolGate.ts +173 -0
- package/src/agents/gateServer.test.ts +204 -0
- package/src/agents/gateServer.ts +124 -0
- package/src/agents/index.ts +10 -0
- package/src/agents/nativeFsDenies.ts +82 -0
- package/src/agents/opencode.test.ts +1440 -0
- package/src/agents/opencode.ts +1312 -0
- package/src/agents/opencodePlugin.ts +222 -0
- package/src/agents/opencodeShared.test.ts +34 -0
- package/src/agents/opencodeShared.ts +121 -0
- package/src/agents/postRun.test.ts +549 -0
- package/src/agents/postRun.ts +535 -0
- package/src/agents/reviewer.ts +104 -0
- package/src/agents/sessionLabeler.test.ts +247 -0
- package/src/agents/sessionLabeler.ts +178 -0
- package/src/agents/shared.test.ts +76 -0
- package/src/agents/shared.ts +292 -0
- package/src/agents/subagentModels.test.ts +113 -0
- package/src/agents/subagentModels.ts +40 -0
- package/src/agents/subagentRegistration.test.ts +41 -0
- package/src/agents/subagentToolGates.ts +114 -0
- package/src/cli.test.ts +129 -0
- package/src/cli.ts +105 -0
- package/src/commands/gha.test.ts +192 -0
- package/src/commands/gha.ts +188 -0
- package/src/commands/mcp.ts +122 -0
- package/src/config.ts +1 -0
- package/src/entry.ts +7 -0
- package/src/entryPost.stdlibOnly.test.ts +109 -0
- package/src/entryPost.ts +99 -0
- package/src/external.test.ts +16 -0
- package/src/external.ts +302 -0
- package/src/index.ts +11 -0
- package/src/internal/index.ts +71 -0
- package/src/lifecycle.ts +2 -0
- package/src/main.test.ts +873 -0
- package/src/main.ts +712 -0
- package/src/mcp/__fixtures__/terramend-scratch-pr-49-review-3485940013.json +110 -0
- package/src/mcp/__fixtures__/terramend-scratch-pr-64-review-3531000326.json +14 -0
- package/src/mcp/__fixtures__/terramend-test-repo-pr-1.diff.json +67 -0
- package/src/mcp/__snapshots__/checkout.test.ts.snap +109 -0
- package/src/mcp/__snapshots__/reviewComments.test.ts.snap +71 -0
- package/src/mcp/arkConfig.ts +7 -0
- package/src/mcp/checkSuite.test.ts +245 -0
- package/src/mcp/checkSuite.ts +255 -0
- package/src/mcp/checkout.test.ts +752 -0
- package/src/mcp/checkout.ts +886 -0
- package/src/mcp/comment.test.ts +772 -0
- package/src/mcp/comment.ts +582 -0
- package/src/mcp/commitInfo.test.ts +127 -0
- package/src/mcp/commitInfo.ts +61 -0
- package/src/mcp/crosswalk.test.ts +106 -0
- package/src/mcp/crosswalk.ts +339 -0
- package/src/mcp/dependencies.test.ts +309 -0
- package/src/mcp/dependencies.ts +189 -0
- package/src/mcp/geminiSanitizer.test.ts +287 -0
- package/src/mcp/geminiSanitizer.ts +207 -0
- package/src/mcp/git.test.ts +1083 -0
- package/src/mcp/git.ts +890 -0
- package/src/mcp/guardrails.test.ts +705 -0
- package/src/mcp/guardrails.ts +465 -0
- package/src/mcp/issue.test.ts +113 -0
- package/src/mcp/issue.ts +73 -0
- package/src/mcp/issueComments.test.ts +69 -0
- package/src/mcp/issueComments.ts +48 -0
- package/src/mcp/issueEvents.test.ts +134 -0
- package/src/mcp/issueEvents.ts +100 -0
- package/src/mcp/issueInfo.test.ts +104 -0
- package/src/mcp/issueInfo.ts +72 -0
- package/src/mcp/labels.test.ts +52 -0
- package/src/mcp/labels.ts +34 -0
- package/src/mcp/localContext.ts +28 -0
- package/src/mcp/localServer.test.ts +75 -0
- package/src/mcp/localServer.ts +131 -0
- package/src/mcp/moduleExtraction.test.ts +261 -0
- package/src/mcp/moduleExtraction.ts +313 -0
- package/src/mcp/moduleTests.test.ts +269 -0
- package/src/mcp/moduleTests.ts +421 -0
- package/src/mcp/modules.test.ts +640 -0
- package/src/mcp/modules.ts +696 -0
- package/src/mcp/output.test.ts +96 -0
- package/src/mcp/output.ts +70 -0
- package/src/mcp/pathSafety.test.ts +44 -0
- package/src/mcp/pathSafety.ts +28 -0
- package/src/mcp/policy.test.ts +282 -0
- package/src/mcp/policy.ts +199 -0
- package/src/mcp/pr.test.ts +387 -0
- package/src/mcp/pr.ts +194 -0
- package/src/mcp/prInfo.test.ts +96 -0
- package/src/mcp/prInfo.ts +91 -0
- package/src/mcp/providerSchema.test.ts +85 -0
- package/src/mcp/providerSchema.ts +175 -0
- package/src/mcp/review.test.ts +936 -0
- package/src/mcp/review.ts +923 -0
- package/src/mcp/reviewComments.test.ts +549 -0
- package/src/mcp/reviewComments.ts +896 -0
- package/src/mcp/roots.test.ts +175 -0
- package/src/mcp/roots.ts +217 -0
- package/src/mcp/scope.test.ts +59 -0
- package/src/mcp/scope.ts +65 -0
- package/src/mcp/security.test.ts +720 -0
- package/src/mcp/selectMode.test.ts +210 -0
- package/src/mcp/selectMode.ts +181 -0
- package/src/mcp/server.test.ts +292 -0
- package/src/mcp/server.ts +403 -0
- package/src/mcp/shared.ts +100 -0
- package/src/mcp/shell.test.ts +520 -0
- package/src/mcp/shell.ts +505 -0
- package/src/mcp/staleFix.test.ts +237 -0
- package/src/mcp/staleFix.ts +277 -0
- package/src/mcp/terraform/cost.ts +163 -0
- package/src/mcp/terraform/currency.test.ts +338 -0
- package/src/mcp/terraform/currency.ts +336 -0
- package/src/mcp/terraform/decisions.ts +527 -0
- package/src/mcp/terraform/findings.ts +333 -0
- package/src/mcp/terraform/plan.ts +348 -0
- package/src/mcp/terraform/scanners.ts +809 -0
- package/src/mcp/terraform/tools.test.ts +1071 -0
- package/src/mcp/terraform/tools.ts +908 -0
- package/src/mcp/terraform/types.ts +305 -0
- package/src/mcp/terraform.test.ts +1957 -0
- package/src/mcp/terraform.ts +23 -0
- package/src/mcp/terratest.test.ts +105 -0
- package/src/mcp/terratest.ts +196 -0
- package/src/mcp/toolFiltering.test.ts +85 -0
- package/src/mcp/upload.test.ts +180 -0
- package/src/mcp/upload.ts +112 -0
- package/src/models.test.ts +300 -0
- package/src/models.ts +708 -0
- package/src/modes.test.ts +107 -0
- package/src/modes.ts +880 -0
- package/src/prep/index.ts +43 -0
- package/src/prep/installNodeDependencies.test.ts +298 -0
- package/src/prep/installNodeDependencies.ts +196 -0
- package/src/prep/installPythonDependencies.test.ts +268 -0
- package/src/prep/installPythonDependencies.ts +199 -0
- package/src/prep/types.ts +38 -0
- package/src/reviewQuality.test.ts +63 -0
- package/src/reviewQuality.ts +134 -0
- package/src/runCli.test.ts +214 -0
- package/src/runCli.ts +282 -0
- package/src/skills/terraform-best-practices/SKILL.md +369 -0
- package/src/toolState.test.ts +45 -0
- package/src/toolState.ts +252 -0
- package/src/utils/activity.test.ts +188 -0
- package/src/utils/activity.ts +210 -0
- package/src/utils/agent.test.ts +251 -0
- package/src/utils/agent.ts +139 -0
- package/src/utils/agentHangReport.test.ts +203 -0
- package/src/utils/agentHangReport.ts +170 -0
- package/src/utils/apiFetch.test.ts +115 -0
- package/src/utils/apiFetch.ts +62 -0
- package/src/utils/apiKeys.test.ts +344 -0
- package/src/utils/apiKeys.ts +206 -0
- package/src/utils/apiUrl.test.ts +30 -0
- package/src/utils/apiUrl.ts +59 -0
- package/src/utils/assets.test.ts +153 -0
- package/src/utils/assets.ts +107 -0
- package/src/utils/billingErrors.test.ts +121 -0
- package/src/utils/billingErrors.ts +189 -0
- package/src/utils/body.test.ts +217 -0
- package/src/utils/body.ts +168 -0
- package/src/utils/buildTerramendFooter.test.ts +38 -0
- package/src/utils/buildTerramendFooter.ts +82 -0
- package/src/utils/byokFallback.test.ts +205 -0
- package/src/utils/byokFallback.ts +128 -0
- package/src/utils/claudeSubscription.test.ts +179 -0
- package/src/utils/claudeSubscription.ts +93 -0
- package/src/utils/cli.ts +31 -0
- package/src/utils/codexHome.test.ts +190 -0
- package/src/utils/codexHome.ts +191 -0
- package/src/utils/codexOAuth.ts +147 -0
- package/src/utils/codexRefreshDetect.test.ts +85 -0
- package/src/utils/codexRefreshDetect.ts +35 -0
- package/src/utils/diffCoverage.test.ts +468 -0
- package/src/utils/diffCoverage.ts +404 -0
- package/src/utils/errorReport.test.ts +135 -0
- package/src/utils/errorReport.ts +83 -0
- package/src/utils/exitHandler.ts +35 -0
- package/src/utils/fixDoubleEscapedString.ts +9 -0
- package/src/utils/ghaCore.ts +13 -0
- package/src/utils/gitAuth.test.ts +322 -0
- package/src/utils/gitAuth.ts +263 -0
- package/src/utils/gitAuthServer.test.ts +260 -0
- package/src/utils/gitAuthServer.ts +182 -0
- package/src/utils/github.test.ts +615 -0
- package/src/utils/github.ts +538 -0
- package/src/utils/globals.ts +9 -0
- package/src/utils/humanEditCapture.test.ts +100 -0
- package/src/utils/humanEditCapture.ts +193 -0
- package/src/utils/install.test.ts +768 -0
- package/src/utils/install.ts +492 -0
- package/src/utils/instructions.test.ts +240 -0
- package/src/utils/instructions.ts +543 -0
- package/src/utils/leapingComment.test.ts +51 -0
- package/src/utils/leapingComment.ts +18 -0
- package/src/utils/learnings.test.ts +87 -0
- package/src/utils/learnings.ts +138 -0
- package/src/utils/learningsTocRender.test.ts +116 -0
- package/src/utils/learningsTruncate.test.ts +39 -0
- package/src/utils/learningsTruncate.ts +42 -0
- package/src/utils/lifecycle.test.ts +195 -0
- package/src/utils/lifecycle.ts +198 -0
- package/src/utils/log.test.ts +402 -0
- package/src/utils/log.ts +432 -0
- package/src/utils/normalizeEnv.test.ts +91 -0
- package/src/utils/normalizeEnv.ts +106 -0
- package/src/utils/openCodeModels.ts +82 -0
- package/src/utils/overrides.test.ts +89 -0
- package/src/utils/overrides.ts +98 -0
- package/src/utils/packageManager.test.ts +321 -0
- package/src/utils/packageManager.ts +257 -0
- package/src/utils/patchWorkflowRunFields.test.ts +92 -0
- package/src/utils/patchWorkflowRunFields.ts +150 -0
- package/src/utils/payload.test.ts +497 -0
- package/src/utils/payload.ts +371 -0
- package/src/utils/postApiFetch.ts +51 -0
- package/src/utils/prSummary.test.ts +224 -0
- package/src/utils/prSummary.ts +147 -0
- package/src/utils/progressComment.ts +261 -0
- package/src/utils/providerErrors.test.ts +315 -0
- package/src/utils/providerErrors.ts +172 -0
- package/src/utils/rangeDiff.test.ts +236 -0
- package/src/utils/rangeDiff.ts +182 -0
- package/src/utils/remediationCommand.test.ts +163 -0
- package/src/utils/remediationCommand.ts +119 -0
- package/src/utils/retry.test.ts +153 -0
- package/src/utils/retry.ts +58 -0
- package/src/utils/reviewCleanup.ts +106 -0
- package/src/utils/run.ts +99 -0
- package/src/utils/runContext.ts +145 -0
- package/src/utils/runContextData.ts +58 -0
- package/src/utils/runErrorRenderer.test.ts +95 -0
- package/src/utils/runErrorRenderer.ts +259 -0
- package/src/utils/runFixture.ts +76 -0
- package/src/utils/runLifecycle.ts +237 -0
- package/src/utils/runStartupLog.ts +60 -0
- package/src/utils/secrets.test.ts +103 -0
- package/src/utils/secrets.ts +177 -0
- package/src/utils/setup.test.ts +509 -0
- package/src/utils/setup.ts +352 -0
- package/src/utils/shell.ts +103 -0
- package/src/utils/skills.test.ts +46 -0
- package/src/utils/skills.ts +67 -0
- package/src/utils/subprocess.test.ts +170 -0
- package/src/utils/subprocess.ts +438 -0
- package/src/utils/terraformMcp.test.ts +63 -0
- package/src/utils/terraformMcp.ts +83 -0
- package/src/utils/time.test.ts +105 -0
- package/src/utils/time.ts +59 -0
- package/src/utils/timer.test.ts +91 -0
- package/src/utils/timer.ts +72 -0
- package/src/utils/todoTracking.test.ts +223 -0
- package/src/utils/todoTracking.ts +167 -0
- package/src/utils/token.test.ts +239 -0
- package/src/utils/token.ts +186 -0
- package/src/utils/version.ts +10 -0
- package/src/utils/versioning.test.ts +34 -0
- package/src/utils/versioning.ts +44 -0
- package/src/utils/vertex.ts +85 -0
- package/src/utils/workflow.ts +25 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import type { ToolContext } from "#app/mcp/server";
|
|
4
|
+
import { apiFetch } from "#app/utils/apiFetch";
|
|
5
|
+
import { log } from "#app/utils/cli";
|
|
6
|
+
import { patchWorkflowRunFields } from "#app/utils/patchWorkflowRunFields";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The PR-level summary snapshot is a markdown file the agent edits in place
|
|
10
|
+
* during a Review / IncrementalReview run. The server seeds the file with
|
|
11
|
+
* either the previous run's snapshot (incremental) or a stub scaffold (first
|
|
12
|
+
* run), lets the agent edit it with its native file-editing tools, then
|
|
13
|
+
* reads it back at end-of-run and persists it to `WorkflowRun.summarySnapshot`.
|
|
14
|
+
*
|
|
15
|
+
* The snapshot is an internal artifact — it is consumed by future agent runs
|
|
16
|
+
* as durable cross-run context, not surfaced to humans. User-visible summary
|
|
17
|
+
* content lives in the Review / IncrementalReview review bodies, governed by
|
|
18
|
+
* `action/modes.ts`.
|
|
19
|
+
*
|
|
20
|
+
* Edit-in-place avoids the output-token tax of a tool call that regurgitates
|
|
21
|
+
* the full snapshot, and gives incremental runs a clean surface that
|
|
22
|
+
* range-diffs cleanly across runs because the section headings are stable.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
export const SUMMARY_FILE_NAME = "terramend-summary.md";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* minimal seed for first-run PRs. just a header + a one-line note about
|
|
29
|
+
* what this file is for. structure is intentionally NOT prescribed —
|
|
30
|
+
* different PRs warrant different organization, and the agent should pick
|
|
31
|
+
* a shape that fits this PR. the agent's prompt (see selectMode.ts
|
|
32
|
+
* `buildSummaryAddendum`) carries the actual instructions for what to
|
|
33
|
+
* capture and how.
|
|
34
|
+
*
|
|
35
|
+
* keeping the seed short also makes the unchanged-from-seed gate more
|
|
36
|
+
* sensitive — any meaningful edit moves the file off the seed, so
|
|
37
|
+
* `persistSummary` can reliably skip the DB write when the agent didn't
|
|
38
|
+
* touch the file.
|
|
39
|
+
*/
|
|
40
|
+
export const SUMMARY_SCAFFOLD = `# PR summary
|
|
41
|
+
|
|
42
|
+
<!-- durable cross-run context. edit in place; the next agent run reads this
|
|
43
|
+
before reviewing new commits. structure however serves the PR best. -->
|
|
44
|
+
`;
|
|
45
|
+
|
|
46
|
+
const MIN_SNAPSHOT_LENGTH = 60;
|
|
47
|
+
/** PG TEXT can hold ~1GB but a sane cap protects the DB / API payloads. */
|
|
48
|
+
const MAX_SNAPSHOT_LENGTH = 32_768;
|
|
49
|
+
|
|
50
|
+
export function summaryFilePath(tmpdir: string): string {
|
|
51
|
+
return join(tmpdir, SUMMARY_FILE_NAME);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** seed the summary file with previous snapshot (incremental) or scaffold (first run). */
|
|
55
|
+
export async function seedSummaryFile(params: {
|
|
56
|
+
tmpdir: string;
|
|
57
|
+
previousSnapshot: string | null;
|
|
58
|
+
}): Promise<string> {
|
|
59
|
+
const path = summaryFilePath(params.tmpdir);
|
|
60
|
+
await mkdir(dirname(path), { recursive: true });
|
|
61
|
+
const seed =
|
|
62
|
+
params.previousSnapshot && params.previousSnapshot.trim().length >= MIN_SNAPSHOT_LENGTH
|
|
63
|
+
? params.previousSnapshot
|
|
64
|
+
: SUMMARY_SCAFFOLD;
|
|
65
|
+
await writeFile(path, seed, "utf8");
|
|
66
|
+
return path;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** read + validate the summary file written by the agent.
|
|
70
|
+
* returns null when the file is missing or fails sanity checks. */
|
|
71
|
+
export async function readSummaryFile(path: string): Promise<string | null> {
|
|
72
|
+
let raw: string;
|
|
73
|
+
try {
|
|
74
|
+
raw = await readFile(path, "utf8");
|
|
75
|
+
} catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
const trimmed = raw.trim();
|
|
79
|
+
if (trimmed.length < MIN_SNAPSHOT_LENGTH) return null;
|
|
80
|
+
if (trimmed.length > MAX_SNAPSHOT_LENGTH) return trimmed.slice(0, MAX_SNAPSHOT_LENGTH);
|
|
81
|
+
return trimmed;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Fetch the most recent persisted PR summary snapshot for this PR.
|
|
86
|
+
* Returns null on first-time PRs, when summary is disabled, or on any error.
|
|
87
|
+
* Best-effort: a transient API failure should not block the run.
|
|
88
|
+
*/
|
|
89
|
+
export async function fetchPreviousSnapshot(
|
|
90
|
+
ctx: ToolContext,
|
|
91
|
+
prNumber: number,
|
|
92
|
+
): Promise<string | null> {
|
|
93
|
+
if (!ctx.githubInstallationToken) return null;
|
|
94
|
+
try {
|
|
95
|
+
const response = await apiFetch({
|
|
96
|
+
path: `/api/repo/${ctx.repo.owner}/${ctx.repo.name}/pr/${prNumber}/summary-comment`,
|
|
97
|
+
method: "GET",
|
|
98
|
+
headers: { authorization: `Bearer ${ctx.githubInstallationToken}` },
|
|
99
|
+
signal: AbortSignal.timeout(10_000),
|
|
100
|
+
});
|
|
101
|
+
if (!response.ok) return null;
|
|
102
|
+
const data = (await response.json()) as { snapshot?: string | null };
|
|
103
|
+
return typeof data.snapshot === "string" && data.snapshot.length > 0 ? data.snapshot : null;
|
|
104
|
+
} catch {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Read the agent-edited PR summary tmpfile and persist to
|
|
111
|
+
* `WorkflowRun.summarySnapshot`.
|
|
112
|
+
*
|
|
113
|
+
* Best-effort: any failure is logged and does not affect the run's success
|
|
114
|
+
* status. Skips the PATCH when the file is byte-identical to its seed —
|
|
115
|
+
* persisting the seed verbatim would either re-write what the DB already has
|
|
116
|
+
* (on incremental runs) or serialize the placeholder scaffold (on first
|
|
117
|
+
* runs), neither of which is useful.
|
|
118
|
+
*
|
|
119
|
+
* Funnels through both the success path and the SIGINT/SIGTERM handler;
|
|
120
|
+
* `summaryPersistAttempted` guards against double-execution.
|
|
121
|
+
*/
|
|
122
|
+
export async function persistSummary(ctx: ToolContext): Promise<void> {
|
|
123
|
+
const filePath = ctx.toolState.summaryFilePath;
|
|
124
|
+
if (!filePath) return;
|
|
125
|
+
if (ctx.toolState.summaryPersistAttempted) return;
|
|
126
|
+
ctx.toolState.summaryPersistAttempted = true;
|
|
127
|
+
const snapshot = await readSummaryFile(filePath);
|
|
128
|
+
if (!snapshot) {
|
|
129
|
+
log.debug(`pr summary tmpfile missing or invalid at ${filePath} — skipping persist`);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
// soft gate: agent never touched the seeded file. saving the seed back
|
|
133
|
+
// is a no-op at best (incremental run — DB already has it) and a bug at
|
|
134
|
+
// worst (first run — serializes the placeholder italics). log a warning
|
|
135
|
+
// so the failure mode is visible in CI without flipping the run to
|
|
136
|
+
// failed.
|
|
137
|
+
const seed = ctx.toolState.summarySeed?.trim();
|
|
138
|
+
if (seed !== undefined && snapshot === seed) {
|
|
139
|
+
log.warning(
|
|
140
|
+
"» pr summary tmpfile unchanged from seed — skipping persist (agent did not edit it)",
|
|
141
|
+
);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
await patchWorkflowRunFields(ctx, { summarySnapshot: snapshot }).catch((err) => {
|
|
145
|
+
log.debug(`pr summary persist failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
146
|
+
});
|
|
147
|
+
}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single source of truth for reading, updating, deleting, and creating "progress comments" —
|
|
3
|
+
* the GitHub comments Terramend uses to surface a run's status.
|
|
4
|
+
*
|
|
5
|
+
* A progress comment can be one of two distinct GitHub entities with non-overlapping IDs and
|
|
6
|
+
* distinct REST endpoints:
|
|
7
|
+
* - "issue": a top-level issue/PR timeline comment (octokit.rest.issues.*Comment)
|
|
8
|
+
* - "review": an inline PR review-thread comment (octokit.rest.pulls.*ReviewComment)
|
|
9
|
+
*
|
|
10
|
+
* Callers carry a `ProgressComment` (id + type) value end-to-end so the right endpoint is always
|
|
11
|
+
* picked. Adding a third comment type later means one new branch in this file, not six.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export type ProgressCommentType = "issue" | "review";
|
|
15
|
+
|
|
16
|
+
export type ProgressComment = {
|
|
17
|
+
id: number;
|
|
18
|
+
type: ProgressCommentType;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Parse the on-the-wire `{ id: string; type }` shape (the form carried in `JsonPayload`)
|
|
23
|
+
* into the in-memory `ProgressComment` shape. Returns undefined when the id isn't a
|
|
24
|
+
* positive integer so callers can short-circuit cleanly. Callers handle logging.
|
|
25
|
+
*/
|
|
26
|
+
export function parseProgressComment(
|
|
27
|
+
raw: { id: string; type: ProgressCommentType } | null | undefined,
|
|
28
|
+
): ProgressComment | undefined {
|
|
29
|
+
if (!raw?.id) return undefined;
|
|
30
|
+
const id = parseInt(raw.id, 10);
|
|
31
|
+
if (Number.isNaN(id) || id <= 0) return undefined;
|
|
32
|
+
return { id, type: raw.type };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// minimal Octokit shape needed by the progress-comment helpers. structural so the helper
|
|
36
|
+
// can be called from both the action package (@octokit/rest v22) and the root project
|
|
37
|
+
// (@octokit/rest v21) without a nominal type clash. only the methods used here are listed.
|
|
38
|
+
interface CommentResponse {
|
|
39
|
+
data: { id: number; body?: string | null | undefined; html_url: string; node_id?: string };
|
|
40
|
+
}
|
|
41
|
+
export interface ProgressCommentOctokit {
|
|
42
|
+
rest: {
|
|
43
|
+
issues: {
|
|
44
|
+
createComment: (params: {
|
|
45
|
+
owner: string;
|
|
46
|
+
repo: string;
|
|
47
|
+
issue_number: number;
|
|
48
|
+
body: string;
|
|
49
|
+
}) => Promise<CommentResponse>;
|
|
50
|
+
getComment: (params: {
|
|
51
|
+
owner: string;
|
|
52
|
+
repo: string;
|
|
53
|
+
comment_id: number;
|
|
54
|
+
}) => Promise<CommentResponse>;
|
|
55
|
+
updateComment: (params: {
|
|
56
|
+
owner: string;
|
|
57
|
+
repo: string;
|
|
58
|
+
comment_id: number;
|
|
59
|
+
body: string;
|
|
60
|
+
}) => Promise<CommentResponse>;
|
|
61
|
+
deleteComment: (params: {
|
|
62
|
+
owner: string;
|
|
63
|
+
repo: string;
|
|
64
|
+
comment_id: number;
|
|
65
|
+
}) => Promise<unknown>;
|
|
66
|
+
};
|
|
67
|
+
pulls: {
|
|
68
|
+
createReplyForReviewComment: (params: {
|
|
69
|
+
owner: string;
|
|
70
|
+
repo: string;
|
|
71
|
+
pull_number: number;
|
|
72
|
+
comment_id: number;
|
|
73
|
+
body: string;
|
|
74
|
+
}) => Promise<CommentResponse>;
|
|
75
|
+
getReviewComment: (params: {
|
|
76
|
+
owner: string;
|
|
77
|
+
repo: string;
|
|
78
|
+
comment_id: number;
|
|
79
|
+
}) => Promise<CommentResponse>;
|
|
80
|
+
updateReviewComment: (params: {
|
|
81
|
+
owner: string;
|
|
82
|
+
repo: string;
|
|
83
|
+
comment_id: number;
|
|
84
|
+
body: string;
|
|
85
|
+
}) => Promise<CommentResponse>;
|
|
86
|
+
deleteReviewComment: (params: {
|
|
87
|
+
owner: string;
|
|
88
|
+
repo: string;
|
|
89
|
+
comment_id: number;
|
|
90
|
+
}) => Promise<unknown>;
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
interface ApiCtx {
|
|
96
|
+
octokit: ProgressCommentOctokit;
|
|
97
|
+
owner: string;
|
|
98
|
+
repo: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Fetch a progress comment via the appropriate REST endpoint for its type.
|
|
103
|
+
* Returns the common subset of fields callers actually use.
|
|
104
|
+
*/
|
|
105
|
+
export async function getProgressComment(
|
|
106
|
+
ctx: ApiCtx,
|
|
107
|
+
comment: ProgressComment,
|
|
108
|
+
): Promise<{ id: number; body: string | undefined; html_url: string }> {
|
|
109
|
+
const result = await (comment.type === "review"
|
|
110
|
+
? ctx.octokit.rest.pulls.getReviewComment({
|
|
111
|
+
owner: ctx.owner,
|
|
112
|
+
repo: ctx.repo,
|
|
113
|
+
comment_id: comment.id,
|
|
114
|
+
})
|
|
115
|
+
: ctx.octokit.rest.issues.getComment({
|
|
116
|
+
owner: ctx.owner,
|
|
117
|
+
repo: ctx.repo,
|
|
118
|
+
comment_id: comment.id,
|
|
119
|
+
}));
|
|
120
|
+
return {
|
|
121
|
+
id: result.data.id,
|
|
122
|
+
body: result.data.body ?? undefined,
|
|
123
|
+
html_url: result.data.html_url,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Update a progress comment in place via the appropriate REST endpoint.
|
|
129
|
+
* Returns the common subset of fields callers actually use.
|
|
130
|
+
*/
|
|
131
|
+
export async function updateProgressComment(
|
|
132
|
+
ctx: ApiCtx,
|
|
133
|
+
comment: ProgressComment,
|
|
134
|
+
body: string,
|
|
135
|
+
): Promise<{
|
|
136
|
+
id: number;
|
|
137
|
+
body: string | undefined;
|
|
138
|
+
html_url: string;
|
|
139
|
+
node_id: string | undefined;
|
|
140
|
+
}> {
|
|
141
|
+
const result = await (comment.type === "review"
|
|
142
|
+
? ctx.octokit.rest.pulls.updateReviewComment({
|
|
143
|
+
owner: ctx.owner,
|
|
144
|
+
repo: ctx.repo,
|
|
145
|
+
comment_id: comment.id,
|
|
146
|
+
body,
|
|
147
|
+
})
|
|
148
|
+
: ctx.octokit.rest.issues.updateComment({
|
|
149
|
+
owner: ctx.owner,
|
|
150
|
+
repo: ctx.repo,
|
|
151
|
+
comment_id: comment.id,
|
|
152
|
+
body,
|
|
153
|
+
}));
|
|
154
|
+
return {
|
|
155
|
+
id: result.data.id,
|
|
156
|
+
body: result.data.body ?? undefined,
|
|
157
|
+
html_url: result.data.html_url,
|
|
158
|
+
node_id: result.data.node_id,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Delete a progress comment via the appropriate REST endpoint.
|
|
164
|
+
* Lower-level than `deleteProgressComment` in mcp/comment.ts — that one also clears
|
|
165
|
+
* tool state. Callers that don't have a ToolContext (post cleanup, error handlers)
|
|
166
|
+
* should use this directly; the higher-level wrapper delegates here.
|
|
167
|
+
*/
|
|
168
|
+
export async function deleteProgressCommentApi(
|
|
169
|
+
ctx: ApiCtx,
|
|
170
|
+
comment: ProgressComment,
|
|
171
|
+
): Promise<void> {
|
|
172
|
+
if (comment.type === "review") {
|
|
173
|
+
await ctx.octokit.rest.pulls.deleteReviewComment({
|
|
174
|
+
owner: ctx.owner,
|
|
175
|
+
repo: ctx.repo,
|
|
176
|
+
comment_id: comment.id,
|
|
177
|
+
});
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
await ctx.octokit.rest.issues.deleteComment({
|
|
181
|
+
owner: ctx.owner,
|
|
182
|
+
repo: ctx.repo,
|
|
183
|
+
comment_id: comment.id,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Discriminated target for `createLeapingProgressComment`. The two variants map to the two
|
|
189
|
+
* distinct GitHub create endpoints; review-reply additionally needs the parent comment ID.
|
|
190
|
+
*/
|
|
191
|
+
export type CreateProgressCommentTarget =
|
|
192
|
+
| { kind: "issue"; issueNumber: number }
|
|
193
|
+
| { kind: "reviewReply"; pullNumber: number; replyToCommentId: number };
|
|
194
|
+
|
|
195
|
+
export interface CreatedProgressComment {
|
|
196
|
+
comment: ProgressComment;
|
|
197
|
+
body: string | undefined;
|
|
198
|
+
html_url: string;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Create the initial "Leaping into action..." progress comment.
|
|
203
|
+
*
|
|
204
|
+
* Reliability: when `kind: "reviewReply"` fails (e.g. the parent comment was deleted or the
|
|
205
|
+
* thread is otherwise unreachable), falls back to a top-level issue comment on the same PR
|
|
206
|
+
* rather than leaving the run with no progress surface. The fallback is logged.
|
|
207
|
+
*
|
|
208
|
+
* (PR # === issue # in GitHub's number space, so `pullNumber` doubles as the fallback target.)
|
|
209
|
+
*/
|
|
210
|
+
export async function createLeapingProgressComment(
|
|
211
|
+
ctx: ApiCtx,
|
|
212
|
+
target: CreateProgressCommentTarget,
|
|
213
|
+
body: string,
|
|
214
|
+
): Promise<CreatedProgressComment> {
|
|
215
|
+
if (target.kind === "reviewReply") {
|
|
216
|
+
try {
|
|
217
|
+
const result = await ctx.octokit.rest.pulls.createReplyForReviewComment({
|
|
218
|
+
owner: ctx.owner,
|
|
219
|
+
repo: ctx.repo,
|
|
220
|
+
pull_number: target.pullNumber,
|
|
221
|
+
comment_id: target.replyToCommentId,
|
|
222
|
+
body,
|
|
223
|
+
});
|
|
224
|
+
return {
|
|
225
|
+
comment: { id: result.data.id, type: "review" },
|
|
226
|
+
body: result.data.body ?? undefined,
|
|
227
|
+
html_url: result.data.html_url,
|
|
228
|
+
};
|
|
229
|
+
} catch (error) {
|
|
230
|
+
// console.warn (not the action-flavored log.warning) because this helper runs in
|
|
231
|
+
// both the action runtime and the Next.js webhook context, and we don't want a
|
|
232
|
+
// ::warning:: GitHub Actions annotation leaking into Vercel logs.
|
|
233
|
+
console.warn(
|
|
234
|
+
`[progressComment] review reply failed (parent ${target.replyToCommentId} on PR #${target.pullNumber}), falling back to issue comment:`,
|
|
235
|
+
error,
|
|
236
|
+
);
|
|
237
|
+
const fallback = await ctx.octokit.rest.issues.createComment({
|
|
238
|
+
owner: ctx.owner,
|
|
239
|
+
repo: ctx.repo,
|
|
240
|
+
issue_number: target.pullNumber,
|
|
241
|
+
body,
|
|
242
|
+
});
|
|
243
|
+
return {
|
|
244
|
+
comment: { id: fallback.data.id, type: "issue" },
|
|
245
|
+
body: fallback.data.body ?? undefined,
|
|
246
|
+
html_url: fallback.data.html_url,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
const result = await ctx.octokit.rest.issues.createComment({
|
|
251
|
+
owner: ctx.owner,
|
|
252
|
+
repo: ctx.repo,
|
|
253
|
+
issue_number: target.issueNumber,
|
|
254
|
+
body,
|
|
255
|
+
});
|
|
256
|
+
return {
|
|
257
|
+
comment: { id: result.data.id, type: "issue" },
|
|
258
|
+
body: result.data.body ?? undefined,
|
|
259
|
+
html_url: result.data.html_url,
|
|
260
|
+
};
|
|
261
|
+
}
|