@farmslot/protocol 0.64.1 → 0.66.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 (42) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +7 -0
  3. package/dist/contracts/family.d.ts +2 -0
  4. package/dist/contracts/family.d.ts.map +1 -1
  5. package/dist/contracts/family.js.map +1 -1
  6. package/dist/contracts/runs.d.ts +4 -0
  7. package/dist/contracts/runs.d.ts.map +1 -1
  8. package/dist/contracts/runs.js.map +1 -1
  9. package/dist/contracts/template-placeholders.js +1 -1
  10. package/dist/contracts/template-placeholders.js.map +1 -1
  11. package/dist/index.d.ts +1 -0
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +1 -0
  14. package/dist/index.js.map +1 -1
  15. package/dist/recipes/step-io.d.ts +1 -0
  16. package/dist/recipes/step-io.d.ts.map +1 -1
  17. package/dist/recipes/step-io.js.map +1 -1
  18. package/dist/rpc/registry.d.ts +1 -0
  19. package/dist/rpc/registry.d.ts.map +1 -1
  20. package/dist/rpc/registry.js +1 -0
  21. package/dist/rpc/registry.js.map +1 -1
  22. package/dist/rpc/run.d.ts +8 -0
  23. package/dist/rpc/run.d.ts.map +1 -1
  24. package/dist/rpc/run.js +1 -0
  25. package/dist/rpc/run.js.map +1 -1
  26. package/dist/runs/linked-tickets.d.ts +29 -0
  27. package/dist/runs/linked-tickets.d.ts.map +1 -0
  28. package/dist/runs/linked-tickets.js +67 -0
  29. package/dist/runs/linked-tickets.js.map +1 -0
  30. package/dist/runs/recovery-hints.d.ts +3 -1
  31. package/dist/runs/recovery-hints.d.ts.map +1 -1
  32. package/dist/runs/recovery-hints.js +19 -0
  33. package/dist/runs/recovery-hints.js.map +1 -1
  34. package/dist/runs/review-findings.d.ts.map +1 -1
  35. package/dist/runs/review-findings.js +3 -0
  36. package/dist/runs/review-findings.js.map +1 -1
  37. package/dist/runs/run-list-view.d.ts.map +1 -1
  38. package/dist/runs/run-list-view.js +2 -0
  39. package/dist/runs/run-list-view.js.map +1 -1
  40. package/package.json +8 -2
  41. package/scripts/review-approval-policy.cjs +122 -0
  42. package/scripts/review-approval-policy.d.cts +31 -0
@@ -0,0 +1,122 @@
1
+ 'use strict';
2
+
3
+ const DEFAULT_APPROVAL_POLICY = Object.freeze({
4
+ maxNits: 3,
5
+ minorVerdict: 'COMMENT',
6
+ majorVerdict: 'REQUEST_CHANGES',
7
+ });
8
+ const verdicts = ['APPROVE', 'COMMENT', 'REQUEST_CHANGES'];
9
+ const severities = ['blocker', 'major', 'minor', 'nit'];
10
+
11
+ function isReviewSeverity(value) {
12
+ return severities.includes(value);
13
+ }
14
+
15
+ function resolveApprovalPolicy(value) {
16
+ if (value === undefined) return { ...DEFAULT_APPROVAL_POLICY };
17
+ if (
18
+ !value ||
19
+ typeof value !== 'object' ||
20
+ Array.isArray(value) ||
21
+ Object.keys(value).some((key) => !Object.hasOwn(DEFAULT_APPROVAL_POLICY, key))
22
+ )
23
+ throw new Error('approvalPolicy accepts only maxNits, minorVerdict and majorVerdict');
24
+ const policy = { ...DEFAULT_APPROVAL_POLICY, ...value };
25
+ if (
26
+ !Number.isSafeInteger(policy.maxNits) ||
27
+ policy.maxNits < 0 ||
28
+ !verdicts.includes(policy.minorVerdict) ||
29
+ !verdicts.includes(policy.majorVerdict)
30
+ )
31
+ throw new Error(
32
+ 'Invalid approvalPolicy: maxNits must be nonnegative and verdicts must be APPROVE, COMMENT or REQUEST_CHANGES',
33
+ );
34
+ return policy;
35
+ }
36
+
37
+ function normalizeReviewSeverity(value) {
38
+ const legacy = { must_fix: 'major', suggestion: 'minor', nitpick: 'nit', comment: 'nit' };
39
+ const severity = legacy[value] ?? value ?? 'major';
40
+ if (!isReviewSeverity(severity))
41
+ throw new Error('Review severity must be blocker, major, minor or nit');
42
+ return severity;
43
+ }
44
+
45
+ function reviewRecommendation(findings, value) {
46
+ const policy = resolveApprovalPolicy(value);
47
+ const counts = { blocker: 0, major: 0, minor: 0, nit: 0 };
48
+ for (const finding of findings) {
49
+ // Older results omitted severity; they cannot grant an approval.
50
+ const severity = normalizeReviewSeverity(finding.severity);
51
+ counts[severity]++;
52
+ }
53
+ const required = ['APPROVE'];
54
+ if (counts.blocker) required.push('REQUEST_CHANGES');
55
+ if (counts.major) required.push(policy.majorVerdict);
56
+ if (counts.minor) required.push(policy.minorVerdict);
57
+ if (counts.nit > policy.maxNits) required.push('COMMENT');
58
+ return verdicts[Math.max(...required.map((verdict) => verdicts.indexOf(verdict)))];
59
+ }
60
+
61
+ class ReviewApprovalPolicyError extends Error {
62
+ constructor(recommendation) {
63
+ super(
64
+ `Review recommendation conflicts with approvalPolicy; findings require ${recommendation}`,
65
+ );
66
+ this.code = 'REVIEW_POLICY_CONFLICT';
67
+ this.recommendation = recommendation;
68
+ }
69
+ }
70
+
71
+ function assertReviewRecommendation(findings, recommendation, policy) {
72
+ const required = reviewRecommendation(findings, policy);
73
+ if (recommendation !== required && !(required === 'APPROVE' && recommendation === 'COMMENT'))
74
+ throw new ReviewApprovalPolicyError(required);
75
+ return recommendation;
76
+ }
77
+
78
+ function renderApprovalPolicy(value) {
79
+ const policy = resolveApprovalPolicy(value);
80
+ return [
81
+ '## Review approval policy',
82
+ '',
83
+ `Blocker requires REQUEST_CHANGES; major requires ${policy.majorVerdict}; minor requires ${policy.minorVerdict}; more than ${policy.maxNits} nits requires COMMENT. Use the strictest applicable verdict, otherwise APPROVE. COMMENT includes concrete asks.`,
84
+ 'Minor means a real defect or gap: wrong value, changed behavior without a test, false PR-description claim or duplication of an existing helper. Nit means style or wording with no behavior impact. Size alone is never a finding. Unrelated concerns mixed in one PR are a minor asking to split.',
85
+ 'Record every finding with severity blocker, major, minor or nit. Put out-of-diff notes in the review body; every inline comment must resolve to a RIGHT-side added or context line in the PR diff at the reviewed head.',
86
+ ].join('\n');
87
+ }
88
+
89
+ function renderReviewResultInstructions(resultRelPath) {
90
+ return `
91
+
92
+ ## Machine-readable review result
93
+
94
+ Write \`${resultRelPath}\` as JSON before completing:
95
+
96
+ \`\`\`json
97
+ {
98
+ "schemaVersion": 1,
99
+ "verdict": "pass",
100
+ "recommendation": "APPROVE",
101
+ "issues": []
102
+ }
103
+ \`\`\`
104
+
105
+ For an issues verdict, set \`verdict\` to \`"issues"\` and include at least one
106
+ \`{ "file": "path", "line": 1, "description": "specific finding", "severity": "minor" }\` entry.
107
+ Use verdict pass when the shared approval policy permits APPROVE, otherwise issues. The recommendation must match that policy. Retain permitted nits in issues even with verdict pass.
108
+ Omit line for body-only findings without a source location.
109
+ The JSON verdict and issues are authoritative; the Markdown file is the human-readable report.`;
110
+ }
111
+
112
+ module.exports = {
113
+ normalizeReviewSeverity,
114
+ renderReviewResultInstructions,
115
+ isReviewSeverity,
116
+ DEFAULT_APPROVAL_POLICY,
117
+ resolveApprovalPolicy,
118
+ reviewRecommendation,
119
+ assertReviewRecommendation,
120
+ renderApprovalPolicy,
121
+ ReviewApprovalPolicyError,
122
+ };
@@ -0,0 +1,31 @@
1
+ export type ReviewRecommendation = 'APPROVE' | 'COMMENT' | 'REQUEST_CHANGES';
2
+ export type ReviewSeverity = 'blocker' | 'major' | 'minor' | 'nit';
3
+ export interface ReviewApprovalPolicy {
4
+ maxNits: number;
5
+ minorVerdict: ReviewRecommendation;
6
+ majorVerdict: ReviewRecommendation;
7
+ }
8
+ export interface ReviewSeverityFinding {
9
+ severity?: string;
10
+ }
11
+ export function isReviewSeverity(value: unknown): value is ReviewSeverity;
12
+ export const DEFAULT_APPROVAL_POLICY: Readonly<ReviewApprovalPolicy>;
13
+ export function resolveApprovalPolicy(value?: unknown): ReviewApprovalPolicy;
14
+ export function reviewRecommendation(
15
+ findings: readonly ReviewSeverityFinding[],
16
+ policy?: Partial<ReviewApprovalPolicy>,
17
+ ): ReviewRecommendation;
18
+ export function assertReviewRecommendation(
19
+ findings: readonly ReviewSeverityFinding[],
20
+ recommendation: unknown,
21
+ policy?: Partial<ReviewApprovalPolicy>,
22
+ ): ReviewRecommendation;
23
+ export function renderApprovalPolicy(policy?: Partial<ReviewApprovalPolicy>): string;
24
+ export class ReviewApprovalPolicyError extends Error {
25
+ code: 'REVIEW_POLICY_CONFLICT';
26
+ recommendation: ReviewRecommendation;
27
+ constructor(recommendation: ReviewRecommendation);
28
+ }
29
+
30
+ export function normalizeReviewSeverity(value: unknown): ReviewSeverity;
31
+ export function renderReviewResultInstructions(resultPath: string): string;