@open-cr-agent/core 0.4.0 → 0.6.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.
Files changed (131) hide show
  1. package/dist/agent/json.d.ts +2 -0
  2. package/dist/agent/json.js +12 -0
  3. package/dist/{pipeline → agent}/pool.js +2 -1
  4. package/dist/{pipeline/agents.d.ts → agent/settings.d.ts} +21 -7
  5. package/dist/agent/settings.js +86 -0
  6. package/dist/anchor/match.js +5 -4
  7. package/dist/anchor/relocate.d.ts +3 -3
  8. package/dist/anchor/relocate.js +4 -4
  9. package/dist/at.d.ts +2 -0
  10. package/dist/at.js +12 -0
  11. package/dist/bundle/bundle.d.ts +2 -1
  12. package/dist/bundle/bundle.js +3 -2
  13. package/dist/bundle/grouping.d.ts +0 -1
  14. package/dist/bundle/runtime-grouper.d.ts +5 -0
  15. package/dist/{pipeline/helpers.js → bundle/runtime-grouper.js} +7 -16
  16. package/dist/contracts.d.ts +8 -14
  17. package/dist/contracts.js +2 -1
  18. package/dist/diff/hunks.js +3 -2
  19. package/dist/diff/parse.js +5 -4
  20. package/dist/diff/quoted-path.js +16 -15
  21. package/dist/domain.d.ts +10 -2
  22. package/dist/domain.js +2 -2
  23. package/dist/errors.d.ts +3 -1
  24. package/dist/errors.js +12 -0
  25. package/dist/hash.d.ts +2 -0
  26. package/dist/hash.js +7 -0
  27. package/dist/index.d.ts +28 -14
  28. package/dist/index.js +16 -5
  29. package/dist/internal.d.ts +10 -13
  30. package/dist/internal.js +10 -13
  31. package/dist/judge/judge.d.ts +3 -3
  32. package/dist/judge/judge.js +10 -9
  33. package/dist/judge/verdict.d.ts +0 -1
  34. package/dist/judge/verdict.js +1 -1
  35. package/dist/memory/memory.d.ts +7 -2
  36. package/dist/memory/memory.js +14 -2
  37. package/dist/net/proxied-fetch.js +2 -1
  38. package/dist/pipeline/assemble-report.d.ts +22 -0
  39. package/dist/pipeline/assemble-report.js +99 -0
  40. package/dist/pipeline/check-stage.d.ts +13 -0
  41. package/dist/pipeline/check-stage.js +70 -0
  42. package/dist/pipeline/context.d.ts +2 -1
  43. package/dist/pipeline/coverage.d.ts +1 -1
  44. package/dist/pipeline/coverage.js +2 -1
  45. package/dist/pipeline/execute-stage.d.ts +26 -0
  46. package/dist/pipeline/execute-stage.js +104 -0
  47. package/dist/pipeline/execute.d.ts +2 -4
  48. package/dist/pipeline/execute.js +65 -58
  49. package/dist/pipeline/filter-stage.d.ts +16 -0
  50. package/dist/pipeline/filter-stage.js +46 -0
  51. package/dist/pipeline/findings.js +3 -2
  52. package/dist/pipeline/imports.d.ts +1 -1
  53. package/dist/pipeline/imports.js +1 -1
  54. package/dist/pipeline/matrix.d.ts +1 -7
  55. package/dist/pipeline/options.d.ts +65 -0
  56. package/dist/pipeline/options.js +9 -0
  57. package/dist/pipeline/plan-output.d.ts +90 -0
  58. package/dist/pipeline/plan-output.js +109 -0
  59. package/dist/pipeline/plan.d.ts +7 -8
  60. package/dist/pipeline/plan.js +12 -9
  61. package/dist/pipeline/preview.d.ts +24 -7
  62. package/dist/pipeline/preview.js +31 -7
  63. package/dist/pipeline/provenance.d.ts +8 -17
  64. package/dist/pipeline/provenance.js +20 -8
  65. package/dist/pipeline/run.d.ts +2 -44
  66. package/dist/pipeline/run.js +18 -273
  67. package/dist/pipeline/task.d.ts +1 -3
  68. package/dist/pipeline/task.js +4 -4
  69. package/dist/plugin/registry.d.ts +5 -4
  70. package/dist/plugin/registry.js +3 -3
  71. package/dist/plugin/types.d.ts +4 -5
  72. package/dist/{pipeline → report}/output-schema.d.ts +70 -58
  73. package/dist/{pipeline → report}/output-schema.js +60 -36
  74. package/dist/report/output.d.ts +8 -0
  75. package/dist/report/output.js +211 -0
  76. package/dist/report/provenance.d.ts +26 -0
  77. package/dist/report/provenance.js +2 -0
  78. package/dist/report/read.d.ts +3 -0
  79. package/dist/report/read.js +34 -0
  80. package/dist/{pipeline → report}/report.d.ts +3 -3
  81. package/dist/report/serialize.d.ts +3 -0
  82. package/dist/report/serialize.js +27 -0
  83. package/dist/rereview/presence.js +1 -1
  84. package/dist/rereview/quote.js +2 -2
  85. package/dist/rereview/reconcile.d.ts +1 -1
  86. package/dist/review/impact.d.ts +0 -2
  87. package/dist/review/impact.js +2 -2
  88. package/dist/review/plan-phase.d.ts +3 -3
  89. package/dist/review/plan-phase.js +4 -4
  90. package/dist/review/prompt-text.d.ts +1 -1
  91. package/dist/review/prompt-text.js +1 -1
  92. package/dist/review/prompt.d.ts +0 -3
  93. package/dist/review/prompt.js +3 -3
  94. package/dist/rules/builtin/index.d.ts +0 -4
  95. package/dist/rules/builtin/index.js +1 -2
  96. package/dist/rules/repo-rules.d.ts +4 -6
  97. package/dist/rules/repo-rules.js +3 -3
  98. package/dist/runtime/chain-runner.d.ts +19 -0
  99. package/dist/runtime/chain-runner.js +63 -0
  100. package/dist/runtime/effort-capability.d.ts +14 -0
  101. package/dist/runtime/effort-capability.js +70 -0
  102. package/dist/runtime/failback.d.ts +2 -9
  103. package/dist/runtime/failback.js +23 -8
  104. package/dist/runtime/models.d.ts +2 -0
  105. package/dist/runtime/models.js +6 -0
  106. package/dist/runtime/tools.d.ts +0 -16
  107. package/dist/runtime/tools.js +3 -3
  108. package/dist/sarif/candidates.d.ts +2 -1
  109. package/dist/sarif/schema.d.ts +2 -2
  110. package/dist/sarif/schema.js +4 -4
  111. package/dist/session/jsonl.d.ts +2 -2
  112. package/dist/session/jsonl.js +5 -4
  113. package/dist/triage.d.ts +2 -2
  114. package/dist/triage.js +1 -1
  115. package/dist/vcs.d.ts +15 -0
  116. package/dist/vcs.js +2 -0
  117. package/dist/verify/prompt.d.ts +0 -6
  118. package/dist/verify/prompt.js +1 -1
  119. package/dist/verify/verify.d.ts +4 -4
  120. package/dist/verify/verify.js +5 -5
  121. package/package.json +1 -1
  122. package/dist/pipeline/agents.js +0 -55
  123. package/dist/pipeline/helpers.d.ts +0 -6
  124. package/dist/pipeline/output.d.ts +0 -77
  125. package/dist/pipeline/output.js +0 -132
  126. /package/dist/{pipeline → agent}/budget.d.ts +0 -0
  127. /package/dist/{pipeline → agent}/budget.js +0 -0
  128. /package/dist/{pipeline → agent}/pool.d.ts +0 -0
  129. /package/dist/{pipeline → agent}/usage.d.ts +0 -0
  130. /package/dist/{pipeline → agent}/usage.js +0 -0
  131. /package/dist/{pipeline → report}/report.js +0 -0
package/dist/index.d.ts CHANGED
@@ -1,26 +1,40 @@
1
- export type { AgentEvent, AgentRuntime, AgentTaskSpec, AppliedSampling, AppliedSettings, CodeMatch, CompletionRequest, CompletionResult, Effort, ModelTier, ReviewContext, Sampling, Usage, VcsAdapter, } from "./contracts.js";
2
- export type { AnchorMethod, ChangeRequest, DiffLine, FileChangeKind, FileDiff, Finding, FindingProvenance, FindingStatus, Hunk, LineRange, PriorFinding, PriorReview, QuoteSignature, ReportedFinding, RiskTier, Severity, Verdict, Verification, } from "./domain.js";
3
- export { CompletionError, isOcraError, OCRA_ERROR_CODES, OcraError, type OcraErrorCode, } from "./errors.js";
1
+ export { SpendLimitReached } from "./agent/budget.js";
2
+ export type { ReviewerOverride, ReviewerOverrides } from "./agent/settings.js";
3
+ export { type AgentRole, EFFORT_LEVELS, type RoleSetting, type RoleSettings, type TierEfforts, } from "./agent/settings.js";
4
+ export { addUsage, emptyUsage } from "./agent/usage.js";
5
+ export type { AgentEvent, AgentRuntime, AgentTaskSpec, AppliedSampling, AppliedSettings, CodeMatch, CompletionRequest, CompletionResult, Effort, ModelChains, ModelTier, ReviewContext, Sampling, Usage, } from "./contracts.js";
6
+ export { MODEL_TIERS } from "./contracts.js";
7
+ export type { AnchorMethod, ChangeRequest, DiffLine, FileChangeKind, FileDiff, Finding, FindingFix, FindingProvenance, FindingStatus, Hunk, LineRange, PriorFinding, PriorReview, QuoteSignature, ReportedFinding, RiskTier, Severity, Verdict, Verification, } from "./domain.js";
8
+ export { CompletionError, errorMessage, isOcraError, OCRA_ERROR_CODES, OcraError, type OcraErrorCode, } from "./errors.js";
4
9
  export type { JudgeDecisions } from "./judge/judge.js";
5
- export type { MemoryEntry } from "./memory/memory.js";
6
- export type { AgentRole, RoleSetting, RoleSettings, TierEfforts, } from "./pipeline/agents.js";
7
- export { SpendLimitReached } from "./pipeline/budget.js";
10
+ export type { MemoryEntry, MemorySource, RememberedEntry } from "./memory/memory.js";
11
+ export { type ProxyEnv, proxiedFetch } from "./net/proxied-fetch.js";
8
12
  export { AccessDeniedError } from "./pipeline/context.js";
9
- export type { ReviewerOverride, ReviewerOverrides, SkippedCell, SkipReason, } from "./pipeline/matrix.js";
10
- export { type OutputFinding, type OutputPriorFinding, REPORT_VERSION, type ReportOutput, toReportOutput, } from "./pipeline/output.js";
11
- export { reportJsonSchema, reportOutputSchema } from "./pipeline/output-schema.js";
12
- export type { AgentProvenance, ProvenanceInput, RunProvenance, } from "./pipeline/provenance.js";
13
- export { type AnchoringSummary, type CoverageEntry, coverageGaps, type ReviewEvent, type ReviewReport, type TaskOutcome, type TaskStatus, } from "./pipeline/report.js";
14
- export { type ReviewOptions, review } from "./pipeline/run.js";
13
+ export type { SkippedCell, SkipReason } from "./pipeline/matrix.js";
14
+ export type { ReviewLimits, ReviewMode, ReviewOptions, ReviewStages, RunIdentity, } from "./pipeline/options.js";
15
+ export type { ProvenanceInput } from "./pipeline/provenance.js";
16
+ export { review } from "./pipeline/run.js";
15
17
  export { agentsMdReviewerPlugin, correctnessReviewerPlugin, docsReviewerPlugin, performanceReviewerPlugin, securityReviewerPlugin, sessionJsonlPlugin, } from "./plugin/builtin.js";
16
18
  export { type PluginHostOptions, startPlugins } from "./plugin/host.js";
17
19
  export { PluginError, PluginRegistry } from "./plugin/registry.js";
18
- export type { BootstrapContext, ConfigureContext, CustomProvider, Env, ModelChains, ModelPrice, OcraPlugin, PluginSummary, PostConfigureContext, RuntimeFactory, RuntimeOptions, ToolDefinition, VcsFactory, } from "./plugin/types.js";
20
+ export type { BootstrapContext, ConfigureContext, CustomProvider, Env, ModelPrice, OcraPlugin, PluginSummary, PostConfigureContext, RuntimeFactory, RuntimeOptions, ToolDefinition, VcsFactory, } from "./plugin/types.js";
21
+ export { type OutputFinding, type OutputPriorFinding, type ReportOutput, toReportOutput, } from "./report/output.js";
22
+ export { REPORT_VERSION, reportJsonSchema, reportOutputSchema } from "./report/output-schema.js";
23
+ export type { AgentProvenance, RuleProvenance, RunProvenance } from "./report/provenance.js";
24
+ export { type AnchoringSummary, type CoverageEntry, coverageGaps, type ReviewEvent, type ReviewReport, type TaskOutcome, type TaskStatus, } from "./report/report.js";
19
25
  export type { ReviewerDefinition, ReviewerScope } from "./review/reviewer.js";
26
+ export { REVIEW_TOOLS, type ReviewToolName } from "./review/tools.js";
20
27
  export type { Language } from "./rules/languages.js";
21
- export type { RepoRule } from "./rules/repo-rules.js";
28
+ export type { RepoRule, RuleSource, SourcedRule } from "./rules/repo-rules.js";
22
29
  export type { RuleSet } from "./rules/rule-set.js";
30
+ export { type AttemptError, type AttemptOutcome, MAX_AGENT_STEPS, RESUME_MESSAGE, withoutSecrets, } from "./runtime/attempt.js";
31
+ export { ChainRunner, type ModelAttempts } from "./runtime/chain-runner.js";
32
+ export { type EffortCapability, type EffortParameter, effortCapability, thinkingBudget, } from "./runtime/effort-capability.js";
33
+ export { type ModelRef, parseModel } from "./runtime/models.js";
34
+ export { parseQuotaError, type QuotaError } from "./runtime/quota.js";
35
+ export { reviewTools } from "./runtime/tools.js";
23
36
  export { parseSarifLog, SarifError, type SarifLog } from "./sarif/schema.js";
24
37
  export type { ExclusionReason, SelectionPolicy } from "./select/select.js";
38
+ export type { VcsAdapter } from "./vcs.js";
25
39
  export type { RefutedFinding } from "./verify/verify.js";
26
40
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -3,15 +3,26 @@
3
3
  // etc/core.api.md records it; a change here updates that report
4
4
  // (`npm run api`). What the other workspace packages need beyond this comes
5
5
  // from "@open-cr-agent/core/internal", which is not a contract.
6
- export { CompletionError, isOcraError, OCRA_ERROR_CODES, OcraError, } from "./errors.js";
7
- export { SpendLimitReached } from "./pipeline/budget.js";
6
+ export { SpendLimitReached } from "./agent/budget.js";
7
+ export { EFFORT_LEVELS, } from "./agent/settings.js";
8
+ export { addUsage, emptyUsage } from "./agent/usage.js";
9
+ export { MODEL_TIERS } from "./contracts.js";
10
+ export { CompletionError, errorMessage, isOcraError, OCRA_ERROR_CODES, OcraError, } from "./errors.js";
11
+ export { proxiedFetch } from "./net/proxied-fetch.js";
8
12
  export { AccessDeniedError } from "./pipeline/context.js";
9
- export { REPORT_VERSION, toReportOutput, } from "./pipeline/output.js";
10
- export { reportJsonSchema, reportOutputSchema } from "./pipeline/output-schema.js";
11
- export { coverageGaps, } from "./pipeline/report.js";
12
13
  export { review } from "./pipeline/run.js";
13
14
  export { agentsMdReviewerPlugin, correctnessReviewerPlugin, docsReviewerPlugin, performanceReviewerPlugin, securityReviewerPlugin, sessionJsonlPlugin, } from "./plugin/builtin.js";
14
15
  export { startPlugins } from "./plugin/host.js";
15
16
  export { PluginError, PluginRegistry } from "./plugin/registry.js";
17
+ export { toReportOutput, } from "./report/output.js";
18
+ export { REPORT_VERSION, reportJsonSchema, reportOutputSchema } from "./report/output-schema.js";
19
+ export { coverageGaps, } from "./report/report.js";
20
+ export { REVIEW_TOOLS } from "./review/tools.js";
21
+ export { MAX_AGENT_STEPS, RESUME_MESSAGE, withoutSecrets, } from "./runtime/attempt.js";
22
+ export { ChainRunner } from "./runtime/chain-runner.js";
23
+ export { effortCapability, thinkingBudget, } from "./runtime/effort-capability.js";
24
+ export { parseModel } from "./runtime/models.js";
25
+ export { parseQuotaError } from "./runtime/quota.js";
26
+ export { reviewTools } from "./runtime/tools.js";
16
27
  export { parseSarifLog, SarifError } from "./sarif/schema.js";
17
28
  //# sourceMappingURL=index.js.map
@@ -1,22 +1,19 @@
1
+ export { AGENT_ROLES } from "./agent/settings.js";
2
+ export { at } from "./at.js";
1
3
  export { parseUnifiedDiff } from "./diff/parse.js";
2
4
  export { severitySchema, verificationSchema } from "./domain.js";
3
- export { errorMessage, usageSpent } from "./errors.js";
4
- export { MEMORY_PATH, parseMemory, serializeMemory } from "./memory/memory.js";
5
- export { proxiedFetch } from "./net/proxied-fetch.js";
6
- export { AGENT_ROLES, EFFORT_LEVELS } from "./pipeline/agents.js";
5
+ export { errnoCode, isNotFound, usageSpent } from "./errors.js";
6
+ export { shortHash } from "./hash.js";
7
+ export { MEMORY_PATH, memoryEntrySchema, parseMemory, serializeMemory, } from "./memory/memory.js";
7
8
  export { reviewContext } from "./pipeline/context.js";
8
9
  export { RISK_TIERS } from "./pipeline/matrix.js";
9
- export { isUnsafeCodePoint, type PlanOutput, serializeOutput, toPlanOutput, } from "./pipeline/output.js";
10
+ export { MAX_TIMER_MS, REVIEW_DEFAULTS } from "./pipeline/options.js";
11
+ export { PLAN_VERSION, type PlanOutput, planOutputSchema, toPlanOutput, } from "./pipeline/plan-output.js";
10
12
  export { previewReview, type ReviewPreview } from "./pipeline/preview.js";
11
13
  export { stableHash } from "./pipeline/provenance.js";
12
14
  export { newRunId } from "./pipeline/run-id.js";
13
- export { addUsage, emptyUsage } from "./pipeline/usage.js";
14
- export { REVIEW_TOOLS } from "./review/tools.js";
15
+ export { readReport } from "./report/read.js";
16
+ export { isUnsafeCodePoint, serializeOutput } from "./report/serialize.js";
15
17
  export { repoRuleSchema } from "./rules/repo-rules.js";
16
- export { type AttemptOutcome, MAX_AGENT_STEPS, RESUME_MESSAGE, withoutSecrets, } from "./runtime/attempt.js";
17
- export { completeWithFailback, withFailback } from "./runtime/failback.js";
18
- export { ModelHealth, parseModel } from "./runtime/models.js";
19
- export { parseQuotaError, type QuotaError, sleep } from "./runtime/quota.js";
20
- export { MAX_READ_LINES, reviewTools } from "./runtime/tools.js";
21
- export { defaultSelectionPolicy } from "./select/select.js";
18
+ export { REPORT_FILE } from "./session/jsonl.js";
22
19
  //# sourceMappingURL=internal.d.ts.map
package/dist/internal.js CHANGED
@@ -1,25 +1,22 @@
1
1
  // "@open-cr-agent/core/internal": what ocra's own packages share beyond the
2
2
  // public API (index.ts). Not a contract: any release may change or remove
3
3
  // any of it, and nothing outside this repository should import it.
4
+ export { AGENT_ROLES } from "./agent/settings.js";
5
+ export { at } from "./at.js";
4
6
  export { parseUnifiedDiff } from "./diff/parse.js";
5
7
  export { severitySchema, verificationSchema } from "./domain.js";
6
- export { errorMessage, usageSpent } from "./errors.js";
7
- export { MEMORY_PATH, parseMemory, serializeMemory } from "./memory/memory.js";
8
- export { proxiedFetch } from "./net/proxied-fetch.js";
9
- export { AGENT_ROLES, EFFORT_LEVELS } from "./pipeline/agents.js";
8
+ export { errnoCode, isNotFound, usageSpent } from "./errors.js";
9
+ export { shortHash } from "./hash.js";
10
+ export { MEMORY_PATH, memoryEntrySchema, parseMemory, serializeMemory, } from "./memory/memory.js";
10
11
  export { reviewContext } from "./pipeline/context.js";
11
12
  export { RISK_TIERS } from "./pipeline/matrix.js";
12
- export { isUnsafeCodePoint, serializeOutput, toPlanOutput, } from "./pipeline/output.js";
13
+ export { MAX_TIMER_MS, REVIEW_DEFAULTS } from "./pipeline/options.js";
14
+ export { PLAN_VERSION, planOutputSchema, toPlanOutput, } from "./pipeline/plan-output.js";
13
15
  export { previewReview } from "./pipeline/preview.js";
14
16
  export { stableHash } from "./pipeline/provenance.js";
15
17
  export { newRunId } from "./pipeline/run-id.js";
16
- export { addUsage, emptyUsage } from "./pipeline/usage.js";
17
- export { REVIEW_TOOLS } from "./review/tools.js";
18
+ export { readReport } from "./report/read.js";
19
+ export { isUnsafeCodePoint, serializeOutput } from "./report/serialize.js";
18
20
  export { repoRuleSchema } from "./rules/repo-rules.js";
19
- export { MAX_AGENT_STEPS, RESUME_MESSAGE, withoutSecrets, } from "./runtime/attempt.js";
20
- export { completeWithFailback, withFailback } from "./runtime/failback.js";
21
- export { ModelHealth, parseModel } from "./runtime/models.js";
22
- export { parseQuotaError, sleep } from "./runtime/quota.js";
23
- export { MAX_READ_LINES, reviewTools } from "./runtime/tools.js";
24
- export { defaultSelectionPolicy } from "./select/select.js";
21
+ export { REPORT_FILE } from "./session/jsonl.js";
25
22
  //# sourceMappingURL=internal.js.map
@@ -1,7 +1,7 @@
1
- import type { AgentRuntime, Effort, Usage } from "../contracts.js";
1
+ import { type AgentCallSettings } from "../agent/settings.js";
2
+ import type { AgentRuntime, Usage } from "../contracts.js";
2
3
  import type { ChangeRequest, Finding, PriorFinding, RiskTier, Severity, Verdict } from "../domain.js";
3
4
  import { type JudgeResponse } from "./prompt.js";
4
- export declare const JUDGE_TIMEOUT_MS = 180000;
5
5
  export interface JudgeDecisions {
6
6
  merged: {
7
7
  kept: string;
@@ -34,7 +34,7 @@ export interface JudgeOptions {
34
34
  tier: RiskTier;
35
35
  signal: AbortSignal;
36
36
  enabled: boolean;
37
- effort?: Effort | undefined;
37
+ call?: AgentCallSettings | undefined;
38
38
  keepDropped?: boolean;
39
39
  carried?: readonly PriorFinding[];
40
40
  }
@@ -1,9 +1,10 @@
1
+ import { parseJsonAnswer } from "../agent/json.js";
2
+ import { agentCall } from "../agent/settings.js";
3
+ import { at } from "../at.js";
1
4
  import { errorMessage, OcraError, usageSpent } from "../errors.js";
2
- import { agentCall } from "../pipeline/agents.js";
3
- import { parseJsonAnswer } from "../pipeline/helpers.js";
4
5
  import { buildJudgePrompt, judgeResponseSchema } from "./prompt.js";
5
6
  import { decideVerdict, defaultSummary } from "./verdict.js";
6
- export const JUDGE_TIMEOUT_MS = 180_000;
7
+ const JUDGE_TIMEOUT_MS = 180_000;
7
8
  export async function judgeFindings(findings, options) {
8
9
  const carried = options.carried ?? [];
9
10
  const fallback = (warnings = [], usage = []) => ({
@@ -22,7 +23,7 @@ export async function judgeFindings(findings, options) {
22
23
  try {
23
24
  const answer = await complete({
24
25
  tier: "top",
25
- ...agentCall("judge", options.effort),
26
+ ...agentCall("judge", options.call),
26
27
  system: prompt.system,
27
28
  user: prompt.user,
28
29
  timeoutMs: JUDGE_TIMEOUT_MS,
@@ -69,7 +70,7 @@ export function applyDecisions(findings, response) {
69
70
  const decisions = { merged: [], dropped: [], recalibrated: [] };
70
71
  const warnings = [];
71
72
  const removed = new Set();
72
- const isProtected = (i) => protectedFinding(findings[i]);
73
+ const isProtected = (i) => protectedFinding(at(findings, i));
73
74
  for (const group of response.duplicates) {
74
75
  const members = [...new Set(group.filter(valid))].filter((i) => !removed.has(i));
75
76
  // Merging keeps one member; keep a protected one so it is not merged away.
@@ -82,19 +83,19 @@ export function applyDecisions(findings, response) {
82
83
  for (const i of rest)
83
84
  removed.add(i);
84
85
  decisions.merged.push({
85
- kept: findings[keep].fingerprint,
86
- merged: rest.map((i) => findings[i].fingerprint),
86
+ kept: at(findings, keep).fingerprint,
87
+ merged: rest.map((i) => at(findings, i).fingerprint),
87
88
  });
88
89
  }
89
90
  for (const { index, reason } of response.drop) {
90
91
  if (!valid(index) || removed.has(index))
91
92
  continue;
92
93
  if (isProtected(index)) {
93
- warnings.push(`judge tried to drop the confirmed critical finding ${findings[index].fingerprint.slice(0, 8)}; kept it`);
94
+ warnings.push(`judge tried to drop the confirmed critical finding ${at(findings, index).fingerprint.slice(0, 8)}; kept it`);
94
95
  continue;
95
96
  }
96
97
  removed.add(index);
97
- const f = findings[index];
98
+ const f = at(findings, index);
98
99
  decisions.dropped.push({ fingerprint: f.fingerprint, file: f.file, title: f.title, reason });
99
100
  }
100
101
  const severities = new Map();
@@ -1,5 +1,4 @@
1
1
  import type { Finding, Severity, Verdict, Verification } from "../domain.js";
2
- export declare const PATTERN_WARNINGS = 3;
3
2
  export interface VerdictInput {
4
3
  severity: Severity;
5
4
  verification?: Verification;
@@ -1,4 +1,4 @@
1
- export const PATTERN_WARNINGS = 3;
1
+ const PATTERN_WARNINGS = 3;
2
2
  // The rubric is code, so the same findings always give the same verdict and
3
3
  // a failed judge call cannot change it; it leans towards approval. Only a
4
4
  // critical finding the verifier confirmed blocks: one model's unchecked claim
@@ -11,9 +11,14 @@ export declare const memoryEntrySchema: z.ZodObject<{
11
11
  export type MemoryEntry = z.infer<typeof memoryEntrySchema>;
12
12
  export declare function parseMemory(json: string): MemoryEntry[];
13
13
  export declare function serializeMemory(entries: readonly MemoryEntry[]): string;
14
- export declare function applyMemory(findings: readonly Finding[], memory: readonly MemoryEntry[]): {
14
+ export type MemorySource = "repository" | "account";
15
+ export type RememberedEntry = MemoryEntry & {
16
+ source: MemorySource;
17
+ };
18
+ export declare function mergeMemory(repository: readonly MemoryEntry[], account: readonly MemoryEntry[]): RememberedEntry[];
19
+ export declare function applyMemory<E extends MemoryEntry>(findings: readonly Finding[], memory: readonly E[]): {
15
20
  kept: Finding[];
16
- remembered: MemoryEntry[];
21
+ remembered: E[];
17
22
  };
18
23
  export declare function memoryFor(files: readonly string[], memory: readonly MemoryEntry[]): MemoryEntry[];
19
24
  //# sourceMappingURL=memory.d.ts.map
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { OcraError } from "../errors.js";
2
+ import { errorMessage, OcraError } from "../errors.js";
3
3
  export const MEMORY_PATH = ".ocra/memory.json";
4
4
  const MAX_ENTRIES = 1_000;
5
5
  export const memoryEntrySchema = z.object({
@@ -19,7 +19,7 @@ export function parseMemory(json) {
19
19
  data = JSON.parse(json);
20
20
  }
21
21
  catch (error) {
22
- throw new OcraError("CONFIG_INVALID", `${MEMORY_PATH} is not valid JSON: ${error.message}`, { cause: error });
22
+ throw new OcraError("CONFIG_INVALID", `${MEMORY_PATH} is not valid JSON: ${errorMessage(error)}`, { cause: error });
23
23
  }
24
24
  const parsed = memoryFileSchema.safeParse(data);
25
25
  if (!parsed.success)
@@ -29,6 +29,18 @@ export function parseMemory(json) {
29
29
  export function serializeMemory(entries) {
30
30
  return `${JSON.stringify({ accepted: entries }, null, 2)}\n`;
31
31
  }
32
+ // The union of both sources; a fingerprint both list is the repository's.
33
+ export function mergeMemory(repository, account) {
34
+ const merged = repository.map((e) => ({ ...e, source: "repository" }));
35
+ const seen = new Set(repository.map((e) => e.fingerprint));
36
+ for (const e of account) {
37
+ if (seen.has(e.fingerprint))
38
+ continue;
39
+ seen.add(e.fingerprint);
40
+ merged.push({ ...e, source: "account" });
41
+ }
42
+ return merged;
43
+ }
32
44
  export function applyMemory(findings, memory) {
33
45
  const accepted = new Map(memory.map((e) => [e.fingerprint, e]));
34
46
  const kept = [];
@@ -5,7 +5,8 @@ import { EnvHttpProxyAgent, fetch as undiciFetch } from "undici";
5
5
  // EnvHttpProxyAgent, reading the given environment rather than the
6
6
  // process's; without one, Node's fetch is used as it is. undici's fetch and
7
7
  // agent are used together so that no object crosses between it and Node's
8
- // bundled copy (as runtime-opencode's transport does).
8
+ // bundled copy (runtime-opencode's transport keeps its own copy of the
9
+ // adapter on purpose; see there).
9
10
  export function proxiedFetch(env) {
10
11
  const httpProxy = env.HTTP_PROXY ?? env.http_proxy;
11
12
  const httpsProxy = env.HTTPS_PROXY ?? env.https_proxy;
@@ -0,0 +1,22 @@
1
+ import type { PriorReview } from "../domain.js";
2
+ import { type ReviewReport } from "../report/report.js";
3
+ import type { ReviewerDefinition } from "../review/reviewer.js";
4
+ import type { CheckStage } from "./check-stage.js";
5
+ import type { ExecuteStage, StageContext } from "./execute-stage.js";
6
+ import type { FilterStage } from "./filter-stage.js";
7
+ export interface RunFacts {
8
+ runId: string;
9
+ reviewers: readonly ReviewerDefinition[];
10
+ prior: {
11
+ review?: PriorReview;
12
+ warning?: string;
13
+ };
14
+ scopeNote?: NonNullable<ReviewReport["scope"]> | undefined;
15
+ }
16
+ export interface Stages {
17
+ executed: ExecuteStage;
18
+ filtered: FilterStage;
19
+ checked: CheckStage;
20
+ }
21
+ export declare function assembleReport(run: RunFacts, stages: Stages, context: StageContext): ReviewReport;
22
+ //# sourceMappingURL=assemble-report.d.ts.map
@@ -0,0 +1,99 @@
1
+ import { effortWarnings, resolveAgents } from "../agent/settings.js";
2
+ import { addUsage, emptyUsage, unpricedCalls } from "../agent/usage.js";
3
+ import { summarizeAnchoring } from "../report/report.js";
4
+ import { runProvenance } from "./provenance.js";
5
+ export function assembleReport(run, stages, context) {
6
+ const report = reportBody(run, stages, context);
7
+ const { options, plan, budget } = context;
8
+ const { executed, filtered, checked } = stages;
9
+ if (checked.judged.decisions)
10
+ report.judgement = checked.judged.decisions;
11
+ if (options.limits?.maxCostUsd !== undefined) {
12
+ const reached = budget.exhausted()
13
+ ? "total"
14
+ : executed.reviewLimitReached()
15
+ ? "review"
16
+ : undefined;
17
+ report.spendLimit = { usd: options.limits?.maxCostUsd, ...(reached ? { reached } : {}) };
18
+ }
19
+ report.anchoring = summarizeAnchoring(report.findings, executed.relocations.length);
20
+ const agents = resolveAgents(run.reviewers, options);
21
+ report.warnings.push(...effortWarnings(agents, options.runtime));
22
+ if (options.identity?.provenance) {
23
+ const { runtime, reviewerOverrides } = options;
24
+ report.provenance = runProvenance(options.identity?.provenance, runtime, run.reviewers, agents, reviewerOverrides, plan.repoRules);
25
+ }
26
+ if (run.prior.review) {
27
+ const { fixed, notReproduced, notRechecked, unchanged, dismissed } = filtered.reconciled;
28
+ report.rereview = { fixed, notReproduced, notRechecked, unchanged, dismissed };
29
+ }
30
+ if (plan.widened) {
31
+ report.scope = {
32
+ mode: "full",
33
+ reason: `the risk tier rose from ${plan.widened.from} to ${plan.widened.to}, which adds reviewers`,
34
+ };
35
+ }
36
+ else if (run.scopeNote)
37
+ report.scope = run.scopeNote;
38
+ if (run.prior.warning)
39
+ report.warnings.push(run.prior.warning);
40
+ return report;
41
+ }
42
+ function reportBody(run, { executed, filtered, checked }, { plan }) {
43
+ const { verification, judged } = checked;
44
+ const calls = [...plan.usage, ...executed.usage(), ...checked.usage];
45
+ return {
46
+ runId: run.runId,
47
+ changeRequest: plan.changeRequest,
48
+ tier: plan.tier,
49
+ verdict: judged.verdict,
50
+ summary: filtered.nothingReviewed
51
+ ? "Nothing was reviewed: no reviewer covered or finished any selected file."
52
+ : judged.summary,
53
+ coverage: filtered.coverage,
54
+ bundles: plan.bundles.map((b) => ({ label: b.label, files: b.files.map((f) => f.newPath) })),
55
+ tasks: [...executed.results.map((r) => r.outcome), ...filtered.imported.outcomes],
56
+ skipped: executed.matrix.skipped,
57
+ findings: sortFindings(judged.findings),
58
+ // Counted before the judge: dropping or downgrading a critical nobody
59
+ // could check must not turn an incomplete run into a clean one.
60
+ unverifiedCriticals: countMissedCriticals(verification.kept, verification.missed),
61
+ refuted: verification.refuted,
62
+ remembered: filtered.remembered,
63
+ usage: sumUsage(calls),
64
+ warnings: [
65
+ ...unpricedWarning(calls),
66
+ ...plan.warnings,
67
+ ...executed.warnings,
68
+ ...filtered.warnings,
69
+ ...checked.warnings,
70
+ ],
71
+ };
72
+ }
73
+ const SEVERITY_ORDER = { critical: 0, warning: 1, suggestion: 2 };
74
+ function sortFindings(findings) {
75
+ return findings.sort((a, b) => SEVERITY_ORDER[a.severity] - SEVERITY_ORDER[b.severity] ||
76
+ a.file.localeCompare(b.file) ||
77
+ (a.lineRange?.start ?? 0) - (b.lineRange?.start ?? 0));
78
+ }
79
+ function unpricedWarning(calls) {
80
+ const unpriced = unpricedCalls(calls);
81
+ return unpriced > 0
82
+ ? [
83
+ `${unpriced} model call(s) used tokens but reported no cost: their model has no price, so the reported cost and the spend limit do not count them`,
84
+ ]
85
+ : [];
86
+ }
87
+ function sumUsage(usages) {
88
+ return usages.reduce(addUsage, emptyUsage());
89
+ }
90
+ // Low-confidence findings do not count toward the verdict, so their missed
91
+ // verification does not make the run incomplete either.
92
+ function countMissedCriticals(findings, missed) {
93
+ const set = new Set(missed);
94
+ return findings.filter((f) => f.severity === "critical" &&
95
+ !f.lowConfidence &&
96
+ f.verification === "unchecked" &&
97
+ set.has(f.fingerprint)).length;
98
+ }
99
+ //# sourceMappingURL=assemble-report.js.map
@@ -0,0 +1,13 @@
1
+ import type { Usage } from "../contracts.js";
2
+ import { type JudgeResult } from "../judge/judge.js";
3
+ import { type VerificationResult } from "../verify/verify.js";
4
+ import type { StageContext } from "./execute-stage.js";
5
+ import type { FilterStage } from "./filter-stage.js";
6
+ export interface CheckStage {
7
+ verification: VerificationResult;
8
+ judged: JudgeResult;
9
+ usage: Usage[];
10
+ warnings: string[];
11
+ }
12
+ export declare function checkStage(filtered: FilterStage, context: StageContext): Promise<CheckStage>;
13
+ //# sourceMappingURL=check-stage.d.ts.map
@@ -0,0 +1,70 @@
1
+ import { roleCall } from "../agent/settings.js";
2
+ import { judgeFindings } from "../judge/judge.js";
3
+ import { stillOpen } from "../rereview/reconcile.js";
4
+ import { markUnchecked, verifyFindings } from "../verify/verify.js";
5
+ import { REVIEW_DEFAULTS } from "./options.js";
6
+ // Verify fact-checks the findings, then the judge merges, filters and
7
+ // recalibrates them and gives the verdict.
8
+ export async function checkStage(filtered, context) {
9
+ const verification = await verify(filtered, context);
10
+ const judged = await judge(verification, filtered, context);
11
+ return {
12
+ verification,
13
+ judged,
14
+ usage: [...verification.usage, ...judged.usage],
15
+ warnings: [...verification.warnings, ...judged.warnings],
16
+ };
17
+ }
18
+ async function verify({ reconciled }, { options, plan, budget, signal, emit }) {
19
+ if (options.stages?.verify === false) {
20
+ return {
21
+ checked: 0,
22
+ kept: markUnchecked(reconciled.findings),
23
+ refuted: [],
24
+ missed: [],
25
+ usage: [],
26
+ warnings: [],
27
+ };
28
+ }
29
+ const verification = await verifyFindings(reconciled.findings, {
30
+ runtime: options.runtime,
31
+ diffs: plan.selected,
32
+ context: plan.context,
33
+ signal,
34
+ concurrency: options.limits?.concurrency ?? REVIEW_DEFAULTS.concurrency,
35
+ budget,
36
+ call: roleCall("verifier", options),
37
+ });
38
+ if (verification.checked > 0) {
39
+ emit({
40
+ type: "verification_finished",
41
+ checked: verification.checked,
42
+ refuted: verification.refuted,
43
+ });
44
+ }
45
+ return verification;
46
+ }
47
+ async function judge(verification, { reconciled, nothingReviewed }, { options, plan, budget, signal, emit }) {
48
+ const wanted = options.stages?.judge !== false && verification.kept.length > 0;
49
+ const affordable = !budget.exhausted();
50
+ const judged = await judgeFindings(verification.kept, {
51
+ runtime: options.runtime,
52
+ changeRequest: plan.changeRequest,
53
+ tier: plan.tier,
54
+ signal,
55
+ call: roleCall("judge", options),
56
+ enabled: wanted && affordable,
57
+ keepDropped: options.mode?.ultra === true,
58
+ carried: stillOpen(reconciled),
59
+ });
60
+ if (wanted && !affordable) {
61
+ judged.warnings.push(`spend limit of $${options.limits?.maxCostUsd} reached: findings were not judged`);
62
+ }
63
+ if (!nothingReviewed) {
64
+ emit(judged.decisions
65
+ ? { type: "judge_finished", verdict: judged.verdict, judgement: judged.decisions }
66
+ : { type: "judge_finished", verdict: judged.verdict });
67
+ }
68
+ return judged;
69
+ }
70
+ //# sourceMappingURL=check-stage.js.map
@@ -1,6 +1,7 @@
1
- import type { ReviewContext, VcsAdapter } from "../contracts.js";
1
+ import type { ReviewContext } from "../contracts.js";
2
2
  import type { FileDiff } from "../domain.js";
3
3
  import { OcraError } from "../errors.js";
4
+ import type { VcsAdapter } from "../vcs.js";
4
5
  export declare class AccessDeniedError extends OcraError {
5
6
  constructor(message: string);
6
7
  }
@@ -1,6 +1,6 @@
1
+ import type { CoverageEntry } from "../report/report.js";
1
2
  import type { FileDecision } from "../select/select.js";
2
3
  import type { JobResult } from "./execute.js";
3
4
  import type { MatrixCell } from "./matrix.js";
4
- import type { CoverageEntry } from "./report.js";
5
5
  export declare function coverageOf(decisions: readonly FileDecision[], results: readonly JobResult[], unchanged: ReadonlySet<string>, limited: readonly MatrixCell[], notStarted: ReadonlySet<string>): CoverageEntry[];
6
6
  //# sourceMappingURL=coverage.d.ts.map
@@ -1,3 +1,4 @@
1
+ import { at } from "../at.js";
1
2
  export function coverageOf(decisions, results, unchanged, limited, notStarted) {
2
3
  // A file is reviewed when every reviewer assigned to it finished at least
3
4
  // one of its tasks: under --ultra one completed sample is enough. A
@@ -24,7 +25,7 @@ export function coverageOf(decisions, results, unchanged, limited, notStarted) {
24
25
  }
25
26
  const status = new Map();
26
27
  for (const [k, completed] of done) {
27
- const file = k.split("\0")[1];
28
+ const file = at(k.split("\0"), 1);
28
29
  const now = completed ? "reviewed" : ran.has(k) ? "failed" : "unreviewed";
29
30
  const before = status.get(file);
30
31
  // failed outranks unreviewed, which outranks reviewed.
@@ -0,0 +1,26 @@
1
+ import { type SpendTracker } from "../agent/budget.js";
2
+ import type { Usage } from "../contracts.js";
3
+ import type { ReviewEvent } from "../report/report.js";
4
+ import type { ReviewerDefinition } from "../review/reviewer.js";
5
+ import { type JobResult } from "./execute.js";
6
+ import { type ReviewMatrix } from "./matrix.js";
7
+ import { type ReviewHooks, type ReviewOptions } from "./options.js";
8
+ import type { ReviewPlan } from "./plan.js";
9
+ export interface StageContext {
10
+ options: ReviewOptions & ReviewHooks;
11
+ plan: ReviewPlan;
12
+ budget: SpendTracker;
13
+ signal: AbortSignal;
14
+ emit: (event: ReviewEvent) => void;
15
+ }
16
+ export interface ExecuteStage {
17
+ matrix: ReviewMatrix;
18
+ results: JobResult[];
19
+ notStarted: ReadonlySet<string>;
20
+ relocations: readonly Usage[];
21
+ usage(): Usage[];
22
+ warnings: string[];
23
+ reviewLimitReached(): boolean;
24
+ }
25
+ export declare function executeStage(reviewers: readonly ReviewerDefinition[], context: StageContext): Promise<ExecuteStage>;
26
+ //# sourceMappingURL=execute-stage.d.ts.map