@amrishkhan05/frankly 0.1.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 (123) hide show
  1. package/.claude-plugin/marketplace.json +27 -0
  2. package/.claude-plugin/plugin.json +11 -0
  3. package/.github/ISSUE_TEMPLATE/bug_report.md +20 -0
  4. package/.github/ISSUE_TEMPLATE/documentation.md +15 -0
  5. package/.github/ISSUE_TEMPLATE/feature_request.md +15 -0
  6. package/.github/PULL_REQUEST_TEMPLATE.md +20 -0
  7. package/.github/copilot-instructions.md +12 -0
  8. package/.github/plugin/marketplace.json +20 -0
  9. package/.github/plugin/plugin.json +16 -0
  10. package/.mcp.json +10 -0
  11. package/LICENSE +21 -0
  12. package/README.md +394 -0
  13. package/commands/frankly-help.toml +2 -0
  14. package/commands/frankly-plan.toml +2 -0
  15. package/commands/frankly-review.toml +2 -0
  16. package/commands/frankly-verify.toml +2 -0
  17. package/commands/frankly.toml +2 -0
  18. package/dist/analysis/change-classifier.d.ts +65 -0
  19. package/dist/analysis/change-classifier.d.ts.map +1 -0
  20. package/dist/analysis/change-classifier.js +241 -0
  21. package/dist/analysis/change-classifier.js.map +1 -0
  22. package/dist/analysis/repository-intelligence.d.ts +15 -0
  23. package/dist/analysis/repository-intelligence.d.ts.map +1 -0
  24. package/dist/analysis/repository-intelligence.js +179 -0
  25. package/dist/analysis/repository-intelligence.js.map +1 -0
  26. package/dist/core/config.d.ts +393 -0
  27. package/dist/core/config.d.ts.map +1 -0
  28. package/dist/core/config.js +130 -0
  29. package/dist/core/config.js.map +1 -0
  30. package/dist/core/engine.d.ts +20 -0
  31. package/dist/core/engine.d.ts.map +1 -0
  32. package/dist/core/engine.js +117 -0
  33. package/dist/core/engine.js.map +1 -0
  34. package/dist/core/errors.d.ts +27 -0
  35. package/dist/core/errors.d.ts.map +1 -0
  36. package/dist/core/errors.js +48 -0
  37. package/dist/core/errors.js.map +1 -0
  38. package/dist/core/index.d.ts +8 -0
  39. package/dist/core/index.d.ts.map +1 -0
  40. package/dist/core/index.js +8 -0
  41. package/dist/core/index.js.map +1 -0
  42. package/dist/core/models.d.ts +155 -0
  43. package/dist/core/models.d.ts.map +1 -0
  44. package/dist/core/models.js +6 -0
  45. package/dist/core/models.js.map +1 -0
  46. package/dist/git/index.d.ts +7 -0
  47. package/dist/git/index.d.ts.map +1 -0
  48. package/dist/git/index.js +6 -0
  49. package/dist/git/index.js.map +1 -0
  50. package/dist/git/repository.d.ts +44 -0
  51. package/dist/git/repository.d.ts.map +1 -0
  52. package/dist/git/repository.js +198 -0
  53. package/dist/git/repository.js.map +1 -0
  54. package/dist/graph/symbols.d.ts +45 -0
  55. package/dist/graph/symbols.d.ts.map +1 -0
  56. package/dist/graph/symbols.js +204 -0
  57. package/dist/graph/symbols.js.map +1 -0
  58. package/dist/integrations/claude/checkpoint.d.ts +2 -0
  59. package/dist/integrations/claude/checkpoint.d.ts.map +1 -0
  60. package/dist/integrations/claude/checkpoint.js +33 -0
  61. package/dist/integrations/claude/checkpoint.js.map +1 -0
  62. package/dist/integrations/cli/demo.d.ts +3 -0
  63. package/dist/integrations/cli/demo.d.ts.map +1 -0
  64. package/dist/integrations/cli/demo.js +31 -0
  65. package/dist/integrations/cli/demo.js.map +1 -0
  66. package/dist/integrations/cli/index.d.ts +7 -0
  67. package/dist/integrations/cli/index.d.ts.map +1 -0
  68. package/dist/integrations/cli/index.js +181 -0
  69. package/dist/integrations/cli/index.js.map +1 -0
  70. package/dist/integrations/mcp/index.d.ts +3 -0
  71. package/dist/integrations/mcp/index.d.ts.map +1 -0
  72. package/dist/integrations/mcp/index.js +7 -0
  73. package/dist/integrations/mcp/index.js.map +1 -0
  74. package/dist/integrations/mcp/server.d.ts +14 -0
  75. package/dist/integrations/mcp/server.d.ts.map +1 -0
  76. package/dist/integrations/mcp/server.js +232 -0
  77. package/dist/integrations/mcp/server.js.map +1 -0
  78. package/dist/project/detector.d.ts +70 -0
  79. package/dist/project/detector.d.ts.map +1 -0
  80. package/dist/project/detector.js +214 -0
  81. package/dist/project/detector.js.map +1 -0
  82. package/dist/report/json.d.ts +26 -0
  83. package/dist/report/json.d.ts.map +1 -0
  84. package/dist/report/json.js +148 -0
  85. package/dist/report/json.js.map +1 -0
  86. package/dist/review/red-ink-review.d.ts +26 -0
  87. package/dist/review/red-ink-review.d.ts.map +1 -0
  88. package/dist/review/red-ink-review.js +103 -0
  89. package/dist/review/red-ink-review.js.map +1 -0
  90. package/fixtures/retry-429/README.md +8 -0
  91. package/fixtures/retry-429/baseline/package.json +4 -0
  92. package/fixtures/retry-429/baseline/src/client.test.ts +8 -0
  93. package/fixtures/retry-429/baseline/src/client.ts +3 -0
  94. package/fixtures/retry-429/baseline/src/retry-policy.ts +1 -0
  95. package/fixtures/retry-429/baseline/tsconfig.json +7 -0
  96. package/fixtures/retry-429/candidate/src/client.ts +5 -0
  97. package/fixtures/retry-429/candidate/src/retry-strategy.ts +9 -0
  98. package/fixtures/retry-429/candidate/src/unrelated-format.ts +1 -0
  99. package/hooks/copilot-activate.js +9 -0
  100. package/hooks/copilot-hooks.json +13 -0
  101. package/hooks/hooks.json +13 -0
  102. package/package.json +70 -0
  103. package/scripts/run.cjs +32 -0
  104. package/skills/frankly/SKILL.md +12 -0
  105. package/src/analysis/change-classifier.ts +285 -0
  106. package/src/analysis/repository-intelligence.ts +236 -0
  107. package/src/core/config.ts +149 -0
  108. package/src/core/engine.ts +143 -0
  109. package/src/core/errors.ts +56 -0
  110. package/src/core/index.ts +8 -0
  111. package/src/core/models.ts +280 -0
  112. package/src/git/index.ts +7 -0
  113. package/src/git/repository.ts +207 -0
  114. package/src/graph/symbols.ts +254 -0
  115. package/src/integrations/claude/checkpoint.ts +40 -0
  116. package/src/integrations/cli/demo.ts +34 -0
  117. package/src/integrations/cli/index.ts +211 -0
  118. package/src/integrations/mcp/index.ts +7 -0
  119. package/src/integrations/mcp/server.ts +257 -0
  120. package/src/project/detector.ts +242 -0
  121. package/src/report/json.ts +175 -0
  122. package/src/review/red-ink-review.ts +125 -0
  123. package/src/tests/phase1.test.ts +57 -0
@@ -0,0 +1,214 @@
1
+ /**
2
+ * Project detection and analysis
3
+ * Identifies TypeScript/JavaScript projects, workspaces, and configuration
4
+ */
5
+ import * as fs from "fs";
6
+ import * as path from "path";
7
+ import { ProjectError } from "../core/errors.js";
8
+ export class ProjectDetector {
9
+ constructor(rootPath) {
10
+ this.cache = new Map();
11
+ this.rootPath = rootPath;
12
+ }
13
+ /**
14
+ * Detect project configuration
15
+ */
16
+ async detectProject() {
17
+ const cacheKey = "project";
18
+ if (this.cache.has(cacheKey)) {
19
+ return this.cache.get(cacheKey);
20
+ }
21
+ const packageJson = this.readPackageJson(this.rootPath);
22
+ if (!packageJson) {
23
+ throw new ProjectError("No package.json found", { path: this.rootPath });
24
+ }
25
+ const project = {
26
+ root: this.rootPath,
27
+ type: this.detectLanguageType(),
28
+ packageManager: this.detectPackageManager(),
29
+ isWorkspace: this.isWorkspace(packageJson),
30
+ hasTsConfig: this.hasTsConfig(this.rootPath),
31
+ testRunner: this.detectTestRunner(packageJson),
32
+ };
33
+ if (project.isWorkspace) {
34
+ project.workspaceRoot = this.rootPath;
35
+ project.packages = this.detectWorkspacePackages(packageJson);
36
+ }
37
+ this.cache.set(cacheKey, project);
38
+ return project;
39
+ }
40
+ /**
41
+ * Detect language type from tsconfig or file extensions
42
+ */
43
+ detectLanguageType() {
44
+ if (this.hasTsConfig(this.rootPath)) {
45
+ return "typescript";
46
+ }
47
+ // Check for .ts files
48
+ return this.hasTypeScriptFiles(this.rootPath) ? "typescript" : "javascript";
49
+ }
50
+ /**
51
+ * Check if tsconfig.json exists
52
+ */
53
+ hasTsConfig(dir) {
54
+ return fs.existsSync(path.join(dir, "tsconfig.json"));
55
+ }
56
+ /**
57
+ * Check for TypeScript files
58
+ */
59
+ hasTypeScriptFiles(dir, depth = 2) {
60
+ if (depth <= 0)
61
+ return false;
62
+ try {
63
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
64
+ for (const entry of entries) {
65
+ if (entry.name.startsWith(".") || entry.name === "node_modules")
66
+ continue;
67
+ if (entry.isFile() && entry.name.endsWith(".ts"))
68
+ return true;
69
+ if (entry.isDirectory() && this.hasTypeScriptFiles(path.join(dir, entry.name), depth - 1)) {
70
+ return true;
71
+ }
72
+ }
73
+ }
74
+ catch {
75
+ // Ignore errors
76
+ }
77
+ return false;
78
+ }
79
+ /**
80
+ * Detect package manager from lock files
81
+ */
82
+ detectPackageManager() {
83
+ if (fs.existsSync(path.join(this.rootPath, "pnpm-lock.yaml")))
84
+ return "pnpm";
85
+ if (fs.existsSync(path.join(this.rootPath, "yarn.lock")))
86
+ return "yarn";
87
+ return "npm";
88
+ }
89
+ /**
90
+ * Check if project is a workspace
91
+ */
92
+ isWorkspace(packageJson) {
93
+ return (Array.isArray(packageJson.workspaces) || typeof packageJson.workspaces === "object");
94
+ }
95
+ /**
96
+ * Detect workspace packages
97
+ */
98
+ detectWorkspacePackages(packageJson) {
99
+ const workspaces = packageJson.workspaces;
100
+ if (!workspaces)
101
+ return [];
102
+ let patterns = [];
103
+ if (Array.isArray(workspaces)) {
104
+ patterns = workspaces;
105
+ }
106
+ else if (typeof workspaces === "object" && workspaces !== null) {
107
+ const w = workspaces;
108
+ if (Array.isArray(w.packages)) {
109
+ patterns = w.packages;
110
+ }
111
+ }
112
+ // Resolve glob patterns to actual packages
113
+ const packages = [];
114
+ for (const pattern of patterns) {
115
+ const resolved = this.resolveGlobPattern(pattern);
116
+ packages.push(...resolved);
117
+ }
118
+ return packages;
119
+ }
120
+ /**
121
+ * Resolve glob pattern to actual directories
122
+ */
123
+ resolveGlobPattern(pattern) {
124
+ const result = [];
125
+ if (!pattern.includes("*")) {
126
+ const fullPath = path.join(this.rootPath, pattern);
127
+ if (fs.existsSync(fullPath)) {
128
+ result.push(pattern);
129
+ }
130
+ return result;
131
+ }
132
+ // Simple glob resolution
133
+ const parts = pattern.split("/");
134
+ const basePart = parts[0];
135
+ if (basePart.includes("*")) {
136
+ const basePattern = basePart.replace("*", "");
137
+ try {
138
+ const entries = fs.readdirSync(this.rootPath);
139
+ for (const entry of entries) {
140
+ if (entry.startsWith(basePattern)) {
141
+ const fullPath = path.join(this.rootPath, entry);
142
+ if (fs.statSync(fullPath).isDirectory()) {
143
+ result.push(entry);
144
+ }
145
+ }
146
+ }
147
+ }
148
+ catch {
149
+ // Ignore errors
150
+ }
151
+ }
152
+ return result;
153
+ }
154
+ /**
155
+ * Detect test runner from package.json
156
+ */
157
+ detectTestRunner(packageJson) {
158
+ const deps = {
159
+ ...(packageJson.dependencies || {}),
160
+ ...(packageJson.devDependencies || {}),
161
+ };
162
+ if ("nx" in deps)
163
+ return "nx";
164
+ if ("vitest" in deps)
165
+ return "vitest";
166
+ if ("jest" in deps)
167
+ return "jest";
168
+ return undefined;
169
+ }
170
+ /**
171
+ * Read package.json from directory
172
+ */
173
+ readPackageJson(dir) {
174
+ const packageJsonPath = path.join(dir, "package.json");
175
+ try {
176
+ const content = fs.readFileSync(packageJsonPath, "utf-8");
177
+ return JSON.parse(content);
178
+ }
179
+ catch {
180
+ return null;
181
+ }
182
+ }
183
+ /**
184
+ * Find package.json for a given file path
185
+ */
186
+ findPackageJsonForFile(filePath) {
187
+ let dir = path.dirname(filePath);
188
+ while (dir !== path.dirname(dir)) {
189
+ const packageJsonPath = path.join(dir, "package.json");
190
+ if (fs.existsSync(packageJsonPath)) {
191
+ return packageJsonPath;
192
+ }
193
+ dir = path.dirname(dir);
194
+ }
195
+ return null;
196
+ }
197
+ /**
198
+ * Read tsconfig.json
199
+ */
200
+ readTsConfig(dir = this.rootPath) {
201
+ const tsConfigPath = path.join(dir, "tsconfig.json");
202
+ try {
203
+ const content = fs.readFileSync(tsConfigPath, "utf-8");
204
+ return JSON.parse(content);
205
+ }
206
+ catch {
207
+ return null;
208
+ }
209
+ }
210
+ }
211
+ export async function createProjectDetector(rootPath) {
212
+ return new ProjectDetector(rootPath);
213
+ }
214
+ //# sourceMappingURL=detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detector.js","sourceRoot":"","sources":["../../src/project/detector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Report formatting
3
+ * Outputs analysis results in various formats
4
+ */
5
+ import type { AnalysisResult } from "../core/models.js";
6
+ export declare class ReportFormatter {
7
+ /**
8
+ * Format as JSON
9
+ */
10
+ formatAsJson(result: AnalysisResult): string;
11
+ /**
12
+ * Format as compact terminal output
13
+ */
14
+ formatAsTerminal(result: AnalysisResult): string;
15
+ /**
16
+ * Format as markdown
17
+ */
18
+ formatAsMarkdown(result: AnalysisResult): string;
19
+ /**
20
+ * Format as summary
21
+ */
22
+ formatAsSummary(result: AnalysisResult): string;
23
+ formatAsCi(result: AnalysisResult): string;
24
+ }
25
+ export declare function createReportFormatter(): ReportFormatter;
26
+ //# sourceMappingURL=json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../src/report/json.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAyB,MAAM,mBAAmB,CAAC;AAE/E,qBAAa,eAAe;IACxB;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM;IAI5C;;OAEG;IACH,gBAAgB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM;IAiEhD;;OAEG;IACH,gBAAgB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM;IAqDhD;;OAEG;IACL,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM;IAgB/C,UAAU,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM;CAY3C;AAED,wBAAgB,qBAAqB,IAAI,eAAe,CAEvD"}
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Report formatting
3
+ * Outputs analysis results in various formats
4
+ */
5
+ export class ReportFormatter {
6
+ /**
7
+ * Format as JSON
8
+ */
9
+ formatAsJson(result) {
10
+ return JSON.stringify(result, null, 2);
11
+ }
12
+ /**
13
+ * Format as compact terminal output
14
+ */
15
+ formatAsTerminal(result) {
16
+ const lines = [];
17
+ lines.push("FRANKLY · RED INK REVIEW\n");
18
+ // Task
19
+ lines.push(`Task\n${result.task}\n`);
20
+ // Verdict
21
+ const review = result.review;
22
+ lines.push(`CHANGE VERDICT\n${review.verdict}\n`);
23
+ // Metrics
24
+ lines.push(`TASK ALIGNMENT\n${review.taskAlignment}\n`);
25
+ lines.push(`CHANGE NECESSITY\n${review.changeNecessity}/100\n`);
26
+ lines.push(`CHANGE SURFACE\n${review.changeSurface}\n`);
27
+ lines.push(`SCOPE DRIFT\n${Math.round(review.scopeDrift * 100)}%\n`);
28
+ lines.push(`MINIMUM PATCH\n${result.files.length} file(s), ${result.symbols.length} changed symbol(s)\n`);
29
+ // Red marks
30
+ if (review.findings.length > 0) {
31
+ lines.push("RED MARKS\n");
32
+ for (const finding of review.findings) {
33
+ const icon = finding.severity === "error" ? "✗" : "⚠";
34
+ lines.push(`${icon} ${finding.title}`);
35
+ }
36
+ lines.push("");
37
+ }
38
+ // Blast radius
39
+ lines.push("BLAST RADIUS\n");
40
+ lines.push(`Direct callers ${review.blastRadius.directCallers}`);
41
+ lines.push(`Transitive callers ${review.blastRadius.transitiveCallers}`);
42
+ lines.push(`Packages ${review.blastRadius.affectedPackages}\n`);
43
+ // Test impact
44
+ lines.push("TEST IMPACT\n");
45
+ lines.push(`Likely affected ${review.testImpact.likelyAffected}`);
46
+ lines.push(`Possibly affected ${review.testImpact.possiblyAffected}`);
47
+ lines.push(`Executed ${review.testImpact.executed}`);
48
+ lines.push(`Passed ${review.testImpact.passed}\n`);
49
+ for (const test of review.testImpact.predicted.slice(0, 10)) {
50
+ lines.push(` ${test.status.padEnd(19)} ${test.path}`);
51
+ }
52
+ if (review.testImpact.predicted.length)
53
+ lines.push("");
54
+ if (review.contractChanges.length) {
55
+ lines.push("CONTRACT CHANGES\n");
56
+ for (const contract of review.contractChanges.slice(0, 10))
57
+ lines.push(`⚠ ${contract.type} ${contract.location}`);
58
+ lines.push("");
59
+ }
60
+ // Recommendation
61
+ lines.push("RECOMMENDATION\n");
62
+ lines.push(review.recommendation);
63
+ if (review.correction)
64
+ lines.push(`\nCORRECTION PASS (1/1)\n${review.correction.instruction}`);
65
+ if (review.personality) {
66
+ lines.push(`\nFrank: "${review.personality}"`);
67
+ }
68
+ return lines.join("\n");
69
+ }
70
+ /**
71
+ * Format as markdown
72
+ */
73
+ formatAsMarkdown(result) {
74
+ const lines = [];
75
+ lines.push("# Frankly · Red Ink Review\n");
76
+ // Task
77
+ lines.push(`## Task\n${result.task}\n`);
78
+ // Verdict
79
+ const review = result.review;
80
+ lines.push(`## Change Verdict\n**${review.verdict}**\n`);
81
+ // Metrics
82
+ lines.push("## Analysis\n");
83
+ lines.push(`- **Task Alignment**: ${review.taskAlignment}`);
84
+ lines.push(`- **Change Necessity**: ${review.changeNecessity}/100`);
85
+ lines.push(`- **Change Surface**: ${review.changeSurface}`);
86
+ lines.push(`- **Scope Drift**: ${Math.round(review.scopeDrift * 100)}%\n`);
87
+ lines.push(`- **Behavioral Changes**: ${review.behavioralChanges.join(", ") || "none detected"}`);
88
+ // Findings
89
+ if (review.findings.length > 0) {
90
+ lines.push("## Findings\n");
91
+ for (const finding of review.findings) {
92
+ lines.push(`- **${finding.title}** (${finding.severity})\n ${finding.description}`);
93
+ }
94
+ lines.push("");
95
+ }
96
+ // Impact
97
+ lines.push("## Impact\n");
98
+ lines.push("### Blast Radius");
99
+ lines.push(`- Direct callers: ${review.blastRadius.directCallers}`);
100
+ lines.push(`- Transitive callers: ${review.blastRadius.transitiveCallers}`);
101
+ lines.push(`- Affected packages: ${review.blastRadius.affectedPackages}\n`);
102
+ lines.push("### Test Impact");
103
+ lines.push(`- Likely affected: ${review.testImpact.likelyAffected}`);
104
+ lines.push(`- Possibly affected: ${review.testImpact.possiblyAffected}`);
105
+ lines.push(`- Executed: ${review.testImpact.executed}`);
106
+ lines.push(`- Passed: ${review.testImpact.passed}\n`);
107
+ // Recommendation
108
+ lines.push("## Recommendation\n");
109
+ lines.push(review.recommendation);
110
+ if (review.correction)
111
+ lines.push(`\n## Correction Pass\n\n${review.correction.instruction}`);
112
+ return lines.join("\n");
113
+ }
114
+ /**
115
+ * Format as summary
116
+ */
117
+ formatAsSummary(result) {
118
+ const review = result.review;
119
+ return `
120
+ FRANKLY ANALYSIS
121
+
122
+ Verdict: ${review.verdict}
123
+ Files changed: ${result.files.length}
124
+ Symbols changed: ${result.symbols.length}
125
+ Findings: ${review.findings.length}
126
+ Task alignment: ${review.taskAlignment}
127
+ Change necessity: ${review.changeNecessity}/100
128
+
129
+ ${review.recommendation}
130
+ `.trim();
131
+ }
132
+ formatAsCi(result) {
133
+ return JSON.stringify({
134
+ schemaVersion: result.schemaVersion,
135
+ verdict: result.review.verdict,
136
+ necessityScore: result.review.changeNecessity,
137
+ scopeDrift: result.review.scopeDrift,
138
+ findings: result.review.findings.map(({ id, severity, confidence, title, affectedSymbols }) => ({ id, severity, confidence, title, affectedSymbols })),
139
+ predictedTests: result.review.testImpact.predicted,
140
+ executedTests: result.review.testImpact.executedResults,
141
+ contracts: result.review.contractChanges,
142
+ });
143
+ }
144
+ }
145
+ export function createReportFormatter() {
146
+ return new ReportFormatter();
147
+ }
148
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/report/json.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { ChangedFile, ExecutedTest, RedInkReview } from "../core/models.js";
2
+ import type { ClassifiedChange } from "../analysis/change-classifier.js";
3
+ import type { RepositoryIntelligence } from "../analysis/repository-intelligence.js";
4
+ import type { FranklyAction, FranklyIntensity, FranklyPersonality } from "../core/config.js";
5
+ export interface ReviewInput {
6
+ task: string;
7
+ files: ChangedFile[];
8
+ classifications: ClassifiedChange[];
9
+ scopeDrift: number;
10
+ fileCount: number;
11
+ symbolCount: number;
12
+ intelligence: RepositoryIntelligence;
13
+ executedTests: ExecutedTest[];
14
+ personality: FranklyPersonality;
15
+ action: FranklyAction;
16
+ intensity: FranklyIntensity;
17
+ disabled: boolean;
18
+ maxCorrectionPasses: number;
19
+ }
20
+ export declare class RedInkReviewBuilder {
21
+ build(input: ReviewInput): RedInkReview;
22
+ private classificationFindings;
23
+ private verdict;
24
+ }
25
+ export declare function createRedInkReviewBuilder(): RedInkReviewBuilder;
26
+ //# sourceMappingURL=red-ink-review.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"red-ink-review.d.ts","sourceRoot":"","sources":["../../src/review/red-ink-review.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,YAAY,EAEZ,YAAY,EAEb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AACrF,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE7F,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,eAAe,EAAE,gBAAgB,EAAE,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,sBAAsB,CAAC;IACrC,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,WAAW,EAAE,kBAAkB,CAAC;IAChC,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE,gBAAgB,CAAC;IAC5B,QAAQ,EAAE,OAAO,CAAC;IAClB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,qBAAa,mBAAmB;IAC9B,KAAK,CAAC,KAAK,EAAE,WAAW,GAAG,YAAY;IA6CvC,OAAO,CAAC,sBAAsB;IAkB9B,OAAO,CAAC,OAAO;CAOhB;AAwBD,wBAAgB,yBAAyB,IAAI,mBAAmB,CAE/D"}
@@ -0,0 +1,103 @@
1
+ export class RedInkReviewBuilder {
2
+ build(input) {
3
+ const confidence = input.intensity === "lite" ? ["high"] : input.intensity === "ultra" ? ["high", "medium", "low"] : ["high", "medium"];
4
+ const findings = input.disabled ? [] : [...this.classificationFindings(input.classifications), ...input.intelligence.findings].filter((item) => confidence.includes(item.confidence));
5
+ const hasUntestedImpact = !input.disabled && input.intelligence.predictedTests.length > 0 && input.executedTests.length === 0;
6
+ const baseVerdict = this.verdict(findings, input.disabled ? 0 : input.scopeDrift, hasUntestedImpact);
7
+ const verdict = input.action === "enforce" && baseVerdict !== "CLEAN" ? "BLOCK" : baseVerdict;
8
+ const justified = input.classifications.filter((item) => ["REQUIRED", "SUPPORTING", "TEST", "GENERATED"].includes(item.classification)).length;
9
+ const necessity = input.disabled ? 100 : input.classifications.length
10
+ ? Math.max(0, Math.round((justified / input.classifications.length) * 100 - findings.filter((item) => item.confidence !== "low").length * 5))
11
+ : 100;
12
+ const passed = input.executedTests.filter((test) => test.status === "PASSED").length;
13
+ const correction = input.action === "correct" && input.maxCorrectionPasses > 0 && verdict !== "CLEAN" ? input.intelligence.correction : undefined;
14
+ return {
15
+ task: input.task,
16
+ verdict,
17
+ taskAlignment: necessity >= 80 ? "high" : necessity >= 50 ? "medium" : "low",
18
+ changeNecessity: necessity,
19
+ changeSurface: surface(input.files, input.symbolCount, input.intelligence),
20
+ scopeDrift: input.disabled ? 0 : input.scopeDrift,
21
+ findings,
22
+ blastRadius: {
23
+ directCallers: input.intelligence.directCallers.length,
24
+ transitiveCallers: input.intelligence.transitiveCallers.length,
25
+ affectedPackages: input.intelligence.packages.length,
26
+ callers: [...input.intelligence.directCallers, ...input.intelligence.transitiveCallers],
27
+ packages: input.intelligence.packages,
28
+ },
29
+ testImpact: {
30
+ likelyAffected: input.intelligence.predictedTests.filter((test) => test.status === "LIKELY_AFFECTED").length,
31
+ possiblyAffected: input.intelligence.predictedTests.filter((test) => test.status === "POSSIBLY_AFFECTED").length,
32
+ executed: input.executedTests.length,
33
+ passed,
34
+ predicted: input.intelligence.predictedTests,
35
+ executedResults: input.executedTests,
36
+ },
37
+ contractChanges: input.intelligence.contracts,
38
+ behavioralChanges: input.intelligence.behavioralChanges,
39
+ reuseCandidates: input.intelligence.reuseCandidates,
40
+ correction,
41
+ recommendation: recommendation(verdict, findings, Boolean(correction)),
42
+ personality: personalityLine(input.personality, verdict),
43
+ };
44
+ }
45
+ classificationFindings(classifications) {
46
+ return classifications.flatMap((item, index) => {
47
+ if (!["SUSPICIOUS", "UNEXPLAINED", "REFACTOR", "INCIDENTAL"].includes(item.classification))
48
+ return [];
49
+ const target = "path" in item.symbol ? item.symbol.path : item.symbol.id;
50
+ return [{
51
+ id: `classification-${index + 1}`,
52
+ severity: item.classification === "UNEXPLAINED" ? "error" : "warning",
53
+ confidence: item.confidence,
54
+ title: item.classification === "REFACTOR" ? "Refactor contamination" : `${item.classification[0]}${item.classification.slice(1).toLowerCase()} change`,
55
+ description: item.justification,
56
+ affectedSymbols: [target],
57
+ evidence: item.evidence,
58
+ recommendation: "Remove the change or provide repository evidence that the task requires it.",
59
+ autoCorrectible: true,
60
+ }];
61
+ });
62
+ }
63
+ verdict(findings, drift, untested) {
64
+ if (findings.some((item) => item.title === "Refactor contamination"))
65
+ return "SPLIT";
66
+ if (findings.some((item) => item.severity === "error") || drift > 0.3 || findings.length > 3)
67
+ return "SIMPLIFY";
68
+ if (untested || findings.some((item) => item.title === "Missing regression coverage"))
69
+ return "VERIFY";
70
+ if (findings.length)
71
+ return "REVIEW";
72
+ return "CLEAN";
73
+ }
74
+ }
75
+ function surface(files, symbols, intelligence) {
76
+ const score = files.filter((file) => !/(?:-lock\.json|pnpm-lock\.yaml|yarn\.lock)$/.test(file.path)).length
77
+ + Math.ceil(symbols / 3)
78
+ + intelligence.contracts.length * 2
79
+ + Math.max(0, intelligence.packages.length - 1) * 3;
80
+ return score <= 4 ? "LOW" : score <= 12 ? "MEDIUM" : "HIGH";
81
+ }
82
+ function recommendation(verdict, findings, correction) {
83
+ if (verdict === "CLEAN")
84
+ return "Patch appears appropriately scoped; no red marks found.";
85
+ if (correction)
86
+ return "Give the coding agent the single correction pass below, then run verify_change.";
87
+ if (verdict === "VERIFY")
88
+ return "Run the predicted related tests and record their actual results.";
89
+ if (verdict === "SPLIT")
90
+ return "Move unrelated refactoring into a separate patch.";
91
+ return `Review ${findings.length} evidence-backed finding(s) before approval.`;
92
+ }
93
+ function personalityLine(personality, verdict) {
94
+ if (personality === "conservative")
95
+ return verdict === "CLEAN" ? "The patch appears proportionate." : "These changes may be broader than required.";
96
+ if (personality === "witty")
97
+ return verdict === "CLEAN" ? "Nothing to circle in red." : "The diff brought guests the task did not invite.";
98
+ return verdict === "CLEAN" ? "Every changed line has a plausible reason." : "This task does not yet justify this patch.";
99
+ }
100
+ export function createRedInkReviewBuilder() {
101
+ return new RedInkReviewBuilder();
102
+ }
103
+ //# sourceMappingURL=red-ink-review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"red-ink-review.js","sourceRoot":"","sources":["../../src/review/red-ink-review.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ # Retry HTTP 429 fixture
2
+
3
+ This fixture represents an overly broad AI-generated candidate patch for the task
4
+ "Retry HTTP 429 responses." The baseline already has a retry policy; the candidate
5
+ replaces it with a single-use abstraction and adds an unrelated file.
6
+
7
+ `npm run demo` copies `baseline/` into a temporary Git repository, commits it, then
8
+ overlays `candidate/` before running Frankly's analysis.
@@ -0,0 +1,4 @@
1
+ {
2
+ "name": "retry-demo",
3
+ "type": "module"
4
+ }
@@ -0,0 +1,8 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { request } from "./client.js";
3
+
4
+ describe("request", () => {
5
+ it("retries server errors", () => {
6
+ expect(request(500)).toBe(true);
7
+ });
8
+ });
@@ -0,0 +1,3 @@
1
+ import { shouldRetry } from "./retry-policy.js";
2
+
3
+ export const request = (status: number) => shouldRetry(status);
@@ -0,0 +1 @@
1
+ export const shouldRetry = (status: number) => status >= 500;
@@ -0,0 +1,7 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ESNext"
5
+ },
6
+ "include": ["src"]
7
+ }
@@ -0,0 +1,5 @@
1
+ import { DefaultRetryStrategy } from "./retry-strategy.js";
2
+
3
+ const retry = new DefaultRetryStrategy();
4
+
5
+ export const request = (status: number) => retry.retry(status);
@@ -0,0 +1,9 @@
1
+ export interface RetryStrategy {
2
+ retry(status: number): boolean;
3
+ }
4
+
5
+ export class DefaultRetryStrategy implements RetryStrategy {
6
+ retry(status: number): boolean {
7
+ return status === 429 || status >= 500;
8
+ }
9
+ }
@@ -0,0 +1 @@
1
+ export const unchangedBehavior = true;
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ /** @format */
3
+
4
+ process.stdout.write(
5
+ JSON.stringify({
6
+ additionalContext:
7
+ "Frankly is active. Use plan_change before uncertain work; use analyze_change at completion; apply at most one minimize_change correction; then use verify_change with actual test results.",
8
+ }),
9
+ );
@@ -0,0 +1,13 @@
1
+ {
2
+ "version": 1,
3
+ "hooks": {
4
+ "sessionStart": [
5
+ {
6
+ "type": "command",
7
+ "bash": "node \"${PLUGIN_ROOT}/hooks/copilot-activate.js\"",
8
+ "powershell": "node \"${PLUGIN_ROOT}\\hooks\\copilot-activate.js\"",
9
+ "timeoutSec": 5
10
+ }
11
+ ]
12
+ }
13
+ }