@webpieces/rules-config 0.3.358 → 0.3.359
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/package.json +3 -3
- package/src/branch-mutation-log.d.ts +13 -5
- package/src/branch-mutation-log.js +86 -76
- package/src/branch-mutation-log.js.map +1 -1
- package/src/index.d.ts +2 -2
- package/src/index.js +3 -1
- package/src/index.js.map +1 -1
- package/src/review-json.d.ts +13 -5
- package/src/review-json.js +106 -87
- package/src/review-json.js.map +1 -1
- package/src/rules-config-design.d.ts +5 -1
- package/src/rules-config-design.js +10 -2
- package/src/rules-config-design.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webpieces/rules-config",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.359",
|
|
4
4
|
"description": "Shared webpieces.config.json loader. Single source of truth for validation rule configuration consumed by @webpieces/ai-hook-rules, @webpieces/code-rules, and @webpieces/nx-webpieces-rules.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
"README.md"
|
|
15
15
|
],
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@webpieces/core-context": "0.3.
|
|
18
|
-
"@webpieces/core-util": "0.3.
|
|
17
|
+
"@webpieces/core-context": "0.3.359",
|
|
18
|
+
"@webpieces/core-util": "0.3.359",
|
|
19
19
|
"@inversifyjs/binding-decorators": "1.1.5",
|
|
20
20
|
"inversify": "7.10.4",
|
|
21
21
|
"reflect-metadata": "0.2.2",
|
|
@@ -13,10 +13,18 @@ export declare class BranchMutationEvent {
|
|
|
13
13
|
artifacts: string[];
|
|
14
14
|
constructor(verb: MutationVerb, phase: MutationPhase);
|
|
15
15
|
}
|
|
16
|
+
/** Appends branch-mutation audit lines. `@provideSingleton` so it's injectable + drawn in the design. */
|
|
17
|
+
export declare class BranchMutationLog {
|
|
18
|
+
branchMutationLogPath(root: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Append one tab-separated line per branch-mutation event to
|
|
21
|
+
* `.webpieces/hooks/branch-mutations.log`. Swallows all errors — logging must NEVER block or fail
|
|
22
|
+
* the workflow it is observing.
|
|
23
|
+
*/
|
|
24
|
+
logBranchMutation(root: string, event: BranchMutationEvent): void;
|
|
25
|
+
private formatDetail;
|
|
26
|
+
private oneLine;
|
|
27
|
+
private rotateLogFile;
|
|
28
|
+
}
|
|
16
29
|
export declare function branchMutationLogPath(root: string): string;
|
|
17
|
-
/**
|
|
18
|
-
* Append one tab-separated line per branch-mutation event to `.webpieces/hooks/branch-mutations.log`.
|
|
19
|
-
* `root` is the workspace root holding `.webpieces`. Swallows all errors — logging must NEVER block or
|
|
20
|
-
* fail the workflow it is observing (mirrors logSyncEvent's contract).
|
|
21
|
-
*/
|
|
22
30
|
export declare function logBranchMutation(root: string, event: BranchMutationEvent): void;
|
|
@@ -1,32 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.BranchMutationEvent = void 0;
|
|
3
|
+
exports.BranchMutationLog = exports.BranchMutationEvent = void 0;
|
|
4
4
|
exports.branchMutationLogPath = branchMutationLogPath;
|
|
5
5
|
exports.logBranchMutation = logBranchMutation;
|
|
6
6
|
const tslib_1 = require("tslib");
|
|
7
7
|
const fs = tslib_1.__importStar(require("fs"));
|
|
8
8
|
const path = tslib_1.__importStar(require("path"));
|
|
9
|
+
const core_context_1 = require("@webpieces/core-context");
|
|
10
|
+
const inversify_1 = require("inversify");
|
|
9
11
|
const constants_1 = require("./constants");
|
|
10
12
|
const to_error_1 = require("./to-error");
|
|
11
|
-
// The BRANCH-MUTATION log — an audit trail for every workflow verb that RENAMES or MOVES branches
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// the agent (backup, checkout main, pull, squash-merge, rename) with ONLY `git reflog` as evidence —
|
|
15
|
-
// nothing in `.webpieces/`. This log records START / each phase boundary / END-with-outcome so the
|
|
16
|
-
// next agent (or a human) can reconstruct what the tooling did to the branches and where the merge/PR
|
|
17
|
-
// artifacts landed. Kept SEPARATE from the read-only refresher log (guard-async-work.log) so that log
|
|
18
|
-
// stays purely about the async cache. Writes to `.webpieces/hooks/branch-mutations.log`.
|
|
19
|
-
//
|
|
13
|
+
// The BRANCH-MUTATION log — an audit trail for every workflow verb that RENAMES or MOVES branches.
|
|
14
|
+
// Records START / each phase boundary / END-with-outcome so the next agent (or a human) can
|
|
15
|
+
// reconstruct what the tooling did to the branches. Writes to `.webpieces/hooks/branch-mutations.log`.
|
|
20
16
|
// Lives in rules-config (the shared dep of pr-gate) so the pr-gate scripts can call it directly.
|
|
21
17
|
const HOOKS_DIR = 'hooks';
|
|
22
18
|
const LOG_FILE = 'branch-mutations.log';
|
|
23
19
|
const LOG_FILE_PREV = 'branch-mutations.1.log';
|
|
24
20
|
const MAX_LOG_BYTES = 512 * 1024; // 512 KB — rotate when exceeded (mirrors the other webpieces logs)
|
|
25
21
|
const MAX_DETAIL_LEN = 400;
|
|
26
|
-
// Data-only record of one branch-mutation event (per CLAUDE.md: classes for data, explicit
|
|
27
|
-
// construction). `verb` + `phase` are always set; the rest describe the transition and default to
|
|
28
|
-
// empty so a call site fills only what that phase knows (e.g. RENAME sets from/to, PULL sets
|
|
29
|
-
// oldMain/newMain, CONFLICT sets conflictFiles + artifacts, END sets outcome).
|
|
22
|
+
// Data-only record of one branch-mutation event (per CLAUDE.md: classes for data, explicit construction).
|
|
30
23
|
class BranchMutationEvent {
|
|
31
24
|
verb;
|
|
32
25
|
phase;
|
|
@@ -44,71 +37,88 @@ class BranchMutationEvent {
|
|
|
44
37
|
}
|
|
45
38
|
}
|
|
46
39
|
exports.BranchMutationEvent = BranchMutationEvent;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
* Append one tab-separated line per branch-mutation event to `.webpieces/hooks/branch-mutations.log`.
|
|
52
|
-
* `root` is the workspace root holding `.webpieces`. Swallows all errors — logging must NEVER block or
|
|
53
|
-
* fail the workflow it is observing (mirrors logSyncEvent's contract).
|
|
54
|
-
*/
|
|
55
|
-
function logBranchMutation(root, event) {
|
|
56
|
-
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
57
|
-
try {
|
|
58
|
-
const timestamp = new Date().toISOString();
|
|
59
|
-
const hooksDir = path.join(root, constants_1.WEBPIECES_TMP_DIR, HOOKS_DIR);
|
|
60
|
-
fs.mkdirSync(hooksDir, { recursive: true });
|
|
61
|
-
const logPath = path.join(hooksDir, LOG_FILE);
|
|
62
|
-
rotateLogFile(logPath, path.join(hooksDir, LOG_FILE_PREV));
|
|
63
|
-
const line = [
|
|
64
|
-
`[${timestamp}]`,
|
|
65
|
-
event.verb,
|
|
66
|
-
event.phase,
|
|
67
|
-
oneLine(formatDetail(event)),
|
|
68
|
-
].join('\t') + '\n';
|
|
69
|
-
fs.appendFileSync(logPath, line);
|
|
70
|
-
}
|
|
71
|
-
catch (err) {
|
|
72
|
-
const error = (0, to_error_1.toError)(err);
|
|
73
|
-
void error;
|
|
40
|
+
/** Appends branch-mutation audit lines. `@provideSingleton` so it's injectable + drawn in the design. */
|
|
41
|
+
let BranchMutationLog = class BranchMutationLog {
|
|
42
|
+
branchMutationLogPath(root) {
|
|
43
|
+
return path.join(root, constants_1.WEBPIECES_TMP_DIR, HOOKS_DIR, LOG_FILE);
|
|
74
44
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
function rotateLogFile(logPath, prevPath) {
|
|
100
|
-
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
101
|
-
try {
|
|
102
|
-
const stat = fs.statSync(logPath);
|
|
103
|
-
if (stat.size > MAX_LOG_BYTES) {
|
|
104
|
-
if (fs.existsSync(prevPath))
|
|
105
|
-
fs.unlinkSync(prevPath);
|
|
106
|
-
fs.renameSync(logPath, prevPath);
|
|
45
|
+
/**
|
|
46
|
+
* Append one tab-separated line per branch-mutation event to
|
|
47
|
+
* `.webpieces/hooks/branch-mutations.log`. Swallows all errors — logging must NEVER block or fail
|
|
48
|
+
* the workflow it is observing.
|
|
49
|
+
*/
|
|
50
|
+
logBranchMutation(root, event) {
|
|
51
|
+
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
52
|
+
try {
|
|
53
|
+
const timestamp = new Date().toISOString();
|
|
54
|
+
const hooksDir = path.join(root, constants_1.WEBPIECES_TMP_DIR, HOOKS_DIR);
|
|
55
|
+
fs.mkdirSync(hooksDir, { recursive: true });
|
|
56
|
+
const logPath = path.join(hooksDir, LOG_FILE);
|
|
57
|
+
this.rotateLogFile(logPath, path.join(hooksDir, LOG_FILE_PREV));
|
|
58
|
+
const line = [
|
|
59
|
+
`[${timestamp}]`,
|
|
60
|
+
event.verb,
|
|
61
|
+
event.phase,
|
|
62
|
+
this.oneLine(this.formatDetail(event)),
|
|
63
|
+
].join('\t') + '\n';
|
|
64
|
+
fs.appendFileSync(logPath, line);
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
const error = (0, to_error_1.toError)(err);
|
|
68
|
+
void error;
|
|
107
69
|
}
|
|
108
70
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
71
|
+
// Render only the fields this event actually set, as `key=value` tokens — greppable on one line.
|
|
72
|
+
formatDetail(event) {
|
|
73
|
+
const parts = [];
|
|
74
|
+
if (event.fromBranch !== '' || event.toBranch !== '')
|
|
75
|
+
parts.push(`from=${event.fromBranch || '?'} to=${event.toBranch || '?'}`);
|
|
76
|
+
if (event.oldMain !== '' || event.newMain !== '')
|
|
77
|
+
parts.push(`oldMain=${event.oldMain || '?'} newMain=${event.newMain || '?'}`);
|
|
78
|
+
if (event.conflict)
|
|
79
|
+
parts.push('conflict=true');
|
|
80
|
+
if (event.conflictFiles.length > 0)
|
|
81
|
+
parts.push(`conflictFiles=${event.conflictFiles.length}(${event.conflictFiles.join(',')})`);
|
|
82
|
+
if (event.outcome !== '')
|
|
83
|
+
parts.push(`outcome=${event.outcome}`);
|
|
84
|
+
for (const artifact of event.artifacts)
|
|
85
|
+
parts.push(`artifact=${artifact}`);
|
|
86
|
+
return parts.join(' ');
|
|
112
87
|
}
|
|
88
|
+
// Collapse newlines/tabs and cap length so one event is always exactly one log line.
|
|
89
|
+
oneLine(value) {
|
|
90
|
+
const flat = value.replace(/[\t\r\n]+/g, ' ').trim();
|
|
91
|
+
return flat.length <= MAX_DETAIL_LEN ? flat : flat.slice(0, MAX_DETAIL_LEN) + '…';
|
|
92
|
+
}
|
|
93
|
+
rotateLogFile(logPath, prevPath) {
|
|
94
|
+
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
95
|
+
try {
|
|
96
|
+
const stat = fs.statSync(logPath);
|
|
97
|
+
if (stat.size > MAX_LOG_BYTES) {
|
|
98
|
+
if (fs.existsSync(prevPath))
|
|
99
|
+
fs.unlinkSync(prevPath);
|
|
100
|
+
fs.renameSync(logPath, prevPath);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
const error = (0, to_error_1.toError)(err);
|
|
105
|
+
void error;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
exports.BranchMutationLog = BranchMutationLog;
|
|
110
|
+
exports.BranchMutationLog = BranchMutationLog = tslib_1.__decorate([
|
|
111
|
+
(0, core_context_1.provideSingleton)(),
|
|
112
|
+
(0, inversify_1.injectable)()
|
|
113
|
+
], BranchMutationLog);
|
|
114
|
+
// Temporary migration delegators to BranchMutationLog — removed once consumers inject it.
|
|
115
|
+
const branchMutationLogSvc = new BranchMutationLog();
|
|
116
|
+
// webpieces-disable no-function-outside-class -- temporary back-compat delegator to BranchMutationLog; removed once consumers inject it
|
|
117
|
+
function branchMutationLogPath(root) {
|
|
118
|
+
return branchMutationLogSvc.branchMutationLogPath(root);
|
|
119
|
+
}
|
|
120
|
+
// webpieces-disable no-function-outside-class -- temporary back-compat delegator to BranchMutationLog; removed once consumers inject it
|
|
121
|
+
function logBranchMutation(root, event) {
|
|
122
|
+
branchMutationLogSvc.logBranchMutation(root, event);
|
|
113
123
|
}
|
|
114
124
|
//# sourceMappingURL=branch-mutation-log.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branch-mutation-log.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/branch-mutation-log.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"branch-mutation-log.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/branch-mutation-log.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport { provideSingleton } from '@webpieces/core-context';\nimport { injectable } from 'inversify';\n\nimport { WEBPIECES_TMP_DIR } from './constants';\nimport { toError } from './to-error';\n\n// The BRANCH-MUTATION log — an audit trail for every workflow verb that RENAMES or MOVES branches.\n// Records START / each phase boundary / END-with-outcome so the next agent (or a human) can\n// reconstruct what the tooling did to the branches. Writes to `.webpieces/hooks/branch-mutations.log`.\n// Lives in rules-config (the shared dep of pr-gate) so the pr-gate scripts can call it directly.\n\nconst HOOKS_DIR = 'hooks';\nconst LOG_FILE = 'branch-mutations.log';\nconst LOG_FILE_PREV = 'branch-mutations.1.log';\nconst MAX_LOG_BYTES = 512 * 1024; // 512 KB — rotate when exceeded (mirrors the other webpieces logs)\nconst MAX_DETAIL_LEN = 400;\n\n// The workflow verb whose branch mutation is being logged (the bin the AI/human invoked).\nexport type MutationVerb = 'wp-start-update' | 'wp-finish-update' | 'wp-start-upsert-pr' | 'wp-finish-upsert-pr';\n\n// A boundary within a verb's execution. START/END bracket the whole run; the middle phases mark each\n// irreversible git step so an interrupt leaves a breadcrumb at the last phase reached.\nexport type MutationPhase =\n | 'START' | 'BACKUP' | 'CHECKOUT_MAIN' | 'PULL' | 'SQUASH' | 'RENAME'\n | 'FINALIZE' | 'CONFLICT' | 'INTERRUPTED' | 'END';\n\n// Data-only record of one branch-mutation event (per CLAUDE.md: classes for data, explicit construction).\nexport class BranchMutationEvent {\n verb: MutationVerb;\n phase: MutationPhase;\n fromBranch: string = '';\n toBranch: string = '';\n oldMain: string = '';\n newMain: string = '';\n conflict: boolean = false;\n conflictFiles: string[] = [];\n outcome: string = '';\n artifacts: string[] = [];\n\n constructor(verb: MutationVerb, phase: MutationPhase) {\n this.verb = verb;\n this.phase = phase;\n }\n}\n\n/** Appends branch-mutation audit lines. `@provideSingleton` so it's injectable + drawn in the design. */\n@provideSingleton()\n@injectable()\nexport class BranchMutationLog {\n branchMutationLogPath(root: string): string {\n return path.join(root, WEBPIECES_TMP_DIR, HOOKS_DIR, LOG_FILE);\n }\n\n /**\n * Append one tab-separated line per branch-mutation event to\n * `.webpieces/hooks/branch-mutations.log`. Swallows all errors — logging must NEVER block or fail\n * the workflow it is observing.\n */\n logBranchMutation(root: string, event: BranchMutationEvent): void {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const timestamp = new Date().toISOString();\n const hooksDir = path.join(root, WEBPIECES_TMP_DIR, HOOKS_DIR);\n fs.mkdirSync(hooksDir, { recursive: true });\n\n const logPath = path.join(hooksDir, LOG_FILE);\n this.rotateLogFile(logPath, path.join(hooksDir, LOG_FILE_PREV));\n\n const line = [\n `[${timestamp}]`,\n event.verb,\n event.phase,\n this.oneLine(this.formatDetail(event)),\n ].join('\\t') + '\\n';\n fs.appendFileSync(logPath, line);\n } catch (err: unknown) {\n const error = toError(err);\n void error;\n }\n }\n\n // Render only the fields this event actually set, as `key=value` tokens — greppable on one line.\n private formatDetail(event: BranchMutationEvent): string {\n const parts: string[] = [];\n if (event.fromBranch !== '' || event.toBranch !== '') parts.push(`from=${event.fromBranch || '?'} to=${event.toBranch || '?'}`);\n if (event.oldMain !== '' || event.newMain !== '') parts.push(`oldMain=${event.oldMain || '?'} newMain=${event.newMain || '?'}`);\n if (event.conflict) parts.push('conflict=true');\n if (event.conflictFiles.length > 0) parts.push(`conflictFiles=${event.conflictFiles.length}(${event.conflictFiles.join(',')})`);\n if (event.outcome !== '') parts.push(`outcome=${event.outcome}`);\n for (const artifact of event.artifacts) parts.push(`artifact=${artifact}`);\n return parts.join(' ');\n }\n\n // Collapse newlines/tabs and cap length so one event is always exactly one log line.\n private oneLine(value: string): string {\n const flat = value.replace(/[\\t\\r\\n]+/g, ' ').trim();\n return flat.length <= MAX_DETAIL_LEN ? flat : flat.slice(0, MAX_DETAIL_LEN) + '…';\n }\n\n private rotateLogFile(logPath: string, prevPath: string): void {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const stat = fs.statSync(logPath);\n if (stat.size > MAX_LOG_BYTES) {\n if (fs.existsSync(prevPath)) fs.unlinkSync(prevPath);\n fs.renameSync(logPath, prevPath);\n }\n } catch (err: unknown) {\n const error = toError(err);\n void error;\n }\n }\n}\n\n// Temporary migration delegators to BranchMutationLog — removed once consumers inject it.\nconst branchMutationLogSvc = new BranchMutationLog();\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to BranchMutationLog; removed once consumers inject it\nexport function branchMutationLogPath(root: string): string {\n return branchMutationLogSvc.branchMutationLogPath(root);\n}\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to BranchMutationLog; removed once consumers inject it\nexport function logBranchMutation(root: string, event: BranchMutationEvent): void {\n branchMutationLogSvc.logBranchMutation(root, event);\n}\n"]}
|
package/src/index.d.ts
CHANGED
|
@@ -28,8 +28,8 @@ export { MaxMethodLinesConfig, MaxFileLinesConfig, RequireReturnTypeConfig, NoIn
|
|
|
28
28
|
export { METHOD_LIMIT_MODES, FILE_LIMIT_MODES, RETURN_TYPE_MODES, INLINE_TYPE_MODES, MODIFIED_CODE_MODES, PROJECT_MODES, PRISMA_DTOS_MODES, PRISMA_CONVERTER_MODES, DIRECT_API_RESOLVER_MODES, THROW_CAUSE_MODES, ON_OFF_MODES, STRUCTURAL_MODES, VALIDATE_TS_MODES, } from './rule-configs';
|
|
29
29
|
export type { MethodLimitMode, FileLimitMode, ReturnTypeMode, InlineTypeMode, ModifiedCodeMode, ProjectMode, PrismaValidateDtosMode, PrismaConverterMode, DirectApiResolverMode, ThrowCauseMode, OnOffMode, StructuralMode, ValidateTsMode, } from './rule-configs';
|
|
30
30
|
export { GateDefinition, PrGateConfig, defaultGates, defaultPrGateConfig, buildPrGateConfig, } from './pr-gate-config';
|
|
31
|
-
export { ReviewJson, loadReviewJson, prDirFor, reviewJsonPath, reviewJsonSchemaHint, } from './review-json';
|
|
31
|
+
export { ReviewJson, ReviewJsonService, loadReviewJson, prDirFor, reviewJsonPath, reviewJsonSchemaHint, } from './review-json';
|
|
32
32
|
export { MainSyncStatus, MainSyncLock, DEFAULT_HANG_TIMEOUT_MINUTES, mainSyncStatusPath, mainSyncLockPath, readMainSyncStatus, writeMainSyncStatus, readMainSyncLock, writeMainSyncLock, isLockStale, isRefreshInProgress, inProcessLock, finishedLock, computeMainSyncStatus, stampCleanMainSyncStatus, squashRecoverySteps, } from './main-sync-status';
|
|
33
33
|
export type { MutationVerb, MutationPhase } from './branch-mutation-log';
|
|
34
|
-
export { BranchMutationEvent, branchMutationLogPath, logBranchMutation, } from './branch-mutation-log';
|
|
34
|
+
export { BranchMutationEvent, BranchMutationLog, branchMutationLogPath, logBranchMutation, } from './branch-mutation-log';
|
|
35
35
|
export { CommandsConfig, buildCommandsConfig, DEFAULT_UPSERT_PR_COMMAND, DEFAULT_MERGE_COMPLETE_COMMAND, } from './commands-config';
|
package/src/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.findNewMethodSignaturesInDiff = exports.getChangedLineNumbers = exports.getFileDiff = exports.getChangedFiles = exports.resolveBase = exports.detectBase = exports.getCurrentBranch = exports.shouldSkipRule = exports.FieldDef = exports.sectionForRule = exports.isHookGuard = exports.HOOK_GUARD_NAMES = exports.DEFAULT_MATCH_RULES = exports.renderMatchRuleMessage = exports.compileMatchRulePatterns = exports.isMatchRuleAllowedPath = exports.findMatchRuleViolations = exports.MatchRuleViolation = exports.MatchRuleConfig = exports.allRuleNames = exports.validateMatchRulesSection = exports.validateExcludePaths = exports.validateCommandsSection = exports.validateSectionPlacement = exports.validatePrGateSection = exports.validateWebpiecesConfig = exports.TemplateWriter = exports.writeTemplate = exports.writeTemplateIfMissing = exports.loadTemplate = exports.defaultRulesDir = exports.defaultRules = exports.isPathExcluded = exports.ExcludePaths = exports.RulesConfigDesign = exports.INSTRUCT_AI_DIR = exports.RepoRootFinder = exports.ConfigFile = exports.CONFIG_FILENAME = exports.findConfigFile = exports.ConfigLoader = exports.LoadedConfig = exports.loadAndValidate = exports.toError = exports.runMain = exports.CliExitError = exports.RuleFailError = exports.InformAiError = exports.ResolvedRuleConfig = exports.ResolvedConfig = void 0;
|
|
4
4
|
exports.RETURN_TYPE_MODES = exports.FILE_LIMIT_MODES = exports.METHOD_LIMIT_MODES = exports.BaseRuleConfig = exports.ValidateTsInSrcConfig = exports.NoJsFilesConfig = exports.DiGraphConfig = exports.NxWiringConfig = exports.RuntimeArchitectureConfig = exports.NoFileImportCyclesConfig = exports.FeatureBranchGuardConfig = exports.RedirectHowToMergeMainConfig = exports.PrMergeGuardConfig = exports.MergeInProgressGuardConfig = exports.PrCreationOrPushGuardConfig = exports.BranchCreationGuardConfig = exports.RoleTagConfig = exports.FrameworkTagConfig = exports.InjectAnnotationNotNeededForConcreteClassConfig = exports.NoFunctionOutsideClassConfig = exports.NoProcessExitOutsideMainConfig = exports.NoSymbolDiTokensConfig = exports.AngularNoDirectApiInResolverConfig = exports.ThrowCauseRequiredConfig = exports.CatchErrorPatternConfig = exports.NoUnmanagedExceptionsConfig = exports.NoDestructureConfig = exports.PrismaConverterConfig = exports.PrismaValidateDtosConfig = exports.NoImplicitAnyConfig = exports.NoAnyUnknownConfig = exports.NoInlineTypeLiteralsConfig = exports.RequireReturnTypeConfig = exports.MaxFileLinesConfig = exports.MaxMethodLinesConfig = exports.WebpiecesRulesConfig = exports.MERGE_EXPLANATION_FILE = exports.MERGE_IN_PROGRESS_FILE = exports.PR_REVIEW_DIR = exports.MERGE_INFO_DIR = exports.WEBPIECES_TMP_DIR = exports.hasDisable = exports.RULE_NAMES = exports.WEBPIECES_DISABLE = exports.AbstractRule = exports.ChangedFilesOptions = exports.DiffRange = exports.DiffScope = exports.isNewOrModified = exports.hasChangesInRange = void 0;
|
|
5
|
-
exports.DEFAULT_MERGE_COMPLETE_COMMAND = exports.DEFAULT_UPSERT_PR_COMMAND = exports.buildCommandsConfig = exports.CommandsConfig = exports.logBranchMutation = exports.branchMutationLogPath = exports.BranchMutationEvent = exports.squashRecoverySteps = exports.stampCleanMainSyncStatus = exports.computeMainSyncStatus = exports.finishedLock = exports.inProcessLock = exports.isRefreshInProgress = exports.isLockStale = exports.writeMainSyncLock = exports.readMainSyncLock = exports.writeMainSyncStatus = exports.readMainSyncStatus = exports.mainSyncLockPath = exports.mainSyncStatusPath = exports.DEFAULT_HANG_TIMEOUT_MINUTES = exports.MainSyncLock = exports.MainSyncStatus = exports.reviewJsonSchemaHint = exports.reviewJsonPath = exports.prDirFor = exports.loadReviewJson = exports.ReviewJson = exports.buildPrGateConfig = exports.defaultPrGateConfig = exports.defaultGates = exports.PrGateConfig = exports.GateDefinition = exports.VALIDATE_TS_MODES = exports.STRUCTURAL_MODES = exports.ON_OFF_MODES = exports.THROW_CAUSE_MODES = exports.DIRECT_API_RESOLVER_MODES = exports.PRISMA_CONVERTER_MODES = exports.PRISMA_DTOS_MODES = exports.PROJECT_MODES = exports.MODIFIED_CODE_MODES = exports.INLINE_TYPE_MODES = void 0;
|
|
5
|
+
exports.DEFAULT_MERGE_COMPLETE_COMMAND = exports.DEFAULT_UPSERT_PR_COMMAND = exports.buildCommandsConfig = exports.CommandsConfig = exports.logBranchMutation = exports.branchMutationLogPath = exports.BranchMutationLog = exports.BranchMutationEvent = exports.squashRecoverySteps = exports.stampCleanMainSyncStatus = exports.computeMainSyncStatus = exports.finishedLock = exports.inProcessLock = exports.isRefreshInProgress = exports.isLockStale = exports.writeMainSyncLock = exports.readMainSyncLock = exports.writeMainSyncStatus = exports.readMainSyncStatus = exports.mainSyncLockPath = exports.mainSyncStatusPath = exports.DEFAULT_HANG_TIMEOUT_MINUTES = exports.MainSyncLock = exports.MainSyncStatus = exports.reviewJsonSchemaHint = exports.reviewJsonPath = exports.prDirFor = exports.loadReviewJson = exports.ReviewJsonService = exports.ReviewJson = exports.buildPrGateConfig = exports.defaultPrGateConfig = exports.defaultGates = exports.PrGateConfig = exports.GateDefinition = exports.VALIDATE_TS_MODES = exports.STRUCTURAL_MODES = exports.ON_OFF_MODES = exports.THROW_CAUSE_MODES = exports.DIRECT_API_RESOLVER_MODES = exports.PRISMA_CONVERTER_MODES = exports.PRISMA_DTOS_MODES = exports.PROJECT_MODES = exports.MODIFIED_CODE_MODES = exports.INLINE_TYPE_MODES = void 0;
|
|
6
6
|
var types_1 = require("./types");
|
|
7
7
|
Object.defineProperty(exports, "ResolvedConfig", { enumerable: true, get: function () { return types_1.ResolvedConfig; } });
|
|
8
8
|
Object.defineProperty(exports, "ResolvedRuleConfig", { enumerable: true, get: function () { return types_1.ResolvedRuleConfig; } });
|
|
@@ -147,6 +147,7 @@ Object.defineProperty(exports, "defaultPrGateConfig", { enumerable: true, get: f
|
|
|
147
147
|
Object.defineProperty(exports, "buildPrGateConfig", { enumerable: true, get: function () { return pr_gate_config_1.buildPrGateConfig; } });
|
|
148
148
|
var review_json_1 = require("./review-json");
|
|
149
149
|
Object.defineProperty(exports, "ReviewJson", { enumerable: true, get: function () { return review_json_1.ReviewJson; } });
|
|
150
|
+
Object.defineProperty(exports, "ReviewJsonService", { enumerable: true, get: function () { return review_json_1.ReviewJsonService; } });
|
|
150
151
|
Object.defineProperty(exports, "loadReviewJson", { enumerable: true, get: function () { return review_json_1.loadReviewJson; } });
|
|
151
152
|
Object.defineProperty(exports, "prDirFor", { enumerable: true, get: function () { return review_json_1.prDirFor; } });
|
|
152
153
|
Object.defineProperty(exports, "reviewJsonPath", { enumerable: true, get: function () { return review_json_1.reviewJsonPath; } });
|
|
@@ -170,6 +171,7 @@ Object.defineProperty(exports, "stampCleanMainSyncStatus", { enumerable: true, g
|
|
|
170
171
|
Object.defineProperty(exports, "squashRecoverySteps", { enumerable: true, get: function () { return main_sync_status_1.squashRecoverySteps; } });
|
|
171
172
|
var branch_mutation_log_1 = require("./branch-mutation-log");
|
|
172
173
|
Object.defineProperty(exports, "BranchMutationEvent", { enumerable: true, get: function () { return branch_mutation_log_1.BranchMutationEvent; } });
|
|
174
|
+
Object.defineProperty(exports, "BranchMutationLog", { enumerable: true, get: function () { return branch_mutation_log_1.BranchMutationLog; } });
|
|
173
175
|
Object.defineProperty(exports, "branchMutationLogPath", { enumerable: true, get: function () { return branch_mutation_log_1.branchMutationLogPath; } });
|
|
174
176
|
Object.defineProperty(exports, "logBranchMutation", { enumerable: true, get: function () { return branch_mutation_log_1.logBranchMutation; } });
|
|
175
177
|
var commands_config_1 = require("./commands-config");
|
package/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/index.ts"],"names":[],"mappings":"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","sourcesContent":["export { ResolvedConfig, ResolvedRuleConfig, RuleOptions } from './types';\nexport { InformAiError } from './inform-ai-error';\nexport { RuleFailError } from './rule-fail-error';\nexport { CliExitError } from './cli-exit-error';\nexport { runMain } from './run-main';\nexport { toError } from './to-error';\nexport { loadAndValidate, LoadedConfig, ConfigLoader } from './load-config';\nexport { findConfigFile, CONFIG_FILENAME, ConfigFile } from './config-file';\nexport { RepoRootFinder, INSTRUCT_AI_DIR } from './repo-root';\nexport { RulesConfigDesign } from './rules-config-design';\nexport { ExcludePaths } from './exclude-hook-paths';\nexport { isPathExcluded } from './exclude-paths';\nexport { defaultRules, defaultRulesDir } from './default-rules';\nexport { loadTemplate, writeTemplateIfMissing, writeTemplate, TemplateWriter } from './load-template';\nexport { validateWebpiecesConfig, validatePrGateSection, validateSectionPlacement, validateCommandsSection, validateExcludePaths, validateMatchRulesSection, allRuleNames } from './validate-config';\nexport {\n MatchRuleConfig,\n MatchRuleViolation,\n findMatchRuleViolations,\n isMatchRuleAllowedPath,\n compileMatchRulePatterns,\n renderMatchRuleMessage,\n DEFAULT_MATCH_RULES,\n} from './match-rules-config';\nexport type { ConfigSection } from './sections';\nexport { HOOK_GUARD_NAMES, isHookGuard, sectionForRule } from './sections';\nexport { FieldDef } from './field-def';\nexport type { SchemaShape } from './field-def';\nexport { shouldSkipRule, getCurrentBranch } from './skip-rule';\nexport type { SkipRuleResult } from './skip-rule';\nexport {\n detectBase,\n resolveBase,\n getChangedFiles,\n getFileDiff,\n getChangedLineNumbers,\n findNewMethodSignaturesInDiff,\n hasChangesInRange,\n isNewOrModified,\n DiffScope,\n DiffRange,\n ChangedFilesOptions,\n} from './diff-scope';\nexport { AbstractRule } from './abstract-rule';\nexport {\n WEBPIECES_DISABLE,\n RULE_NAMES,\n hasDisable,\n WEBPIECES_TMP_DIR,\n MERGE_INFO_DIR,\n PR_REVIEW_DIR,\n MERGE_IN_PROGRESS_FILE,\n MERGE_EXPLANATION_FILE,\n} from './constants';\nexport { WebpiecesRulesConfig } from './WebpiecesRulesConfig';\nexport {\n MaxMethodLinesConfig,\n MaxFileLinesConfig,\n RequireReturnTypeConfig,\n NoInlineTypeLiteralsConfig,\n NoAnyUnknownConfig,\n NoImplicitAnyConfig,\n PrismaValidateDtosConfig,\n PrismaConverterConfig,\n NoDestructureConfig,\n NoUnmanagedExceptionsConfig,\n CatchErrorPatternConfig,\n ThrowCauseRequiredConfig,\n AngularNoDirectApiInResolverConfig,\n NoSymbolDiTokensConfig,\n NoProcessExitOutsideMainConfig,\n NoFunctionOutsideClassConfig,\n InjectAnnotationNotNeededForConcreteClassConfig,\n FrameworkTagConfig,\n RoleTagConfig,\n BranchCreationGuardConfig,\n PrCreationOrPushGuardConfig,\n MergeInProgressGuardConfig,\n PrMergeGuardConfig,\n RedirectHowToMergeMainConfig,\n FeatureBranchGuardConfig,\n NoFileImportCyclesConfig,\n RuntimeArchitectureConfig,\n NxWiringConfig,\n DiGraphConfig,\n NoJsFilesConfig,\n ValidateTsInSrcConfig,\n BaseRuleConfig,\n} from './rule-configs';\n// Mode unions + their value arrays — the single source of truth shared with code-rules.\nexport {\n METHOD_LIMIT_MODES,\n FILE_LIMIT_MODES,\n RETURN_TYPE_MODES,\n INLINE_TYPE_MODES,\n MODIFIED_CODE_MODES,\n PROJECT_MODES,\n PRISMA_DTOS_MODES,\n PRISMA_CONVERTER_MODES,\n DIRECT_API_RESOLVER_MODES,\n THROW_CAUSE_MODES,\n ON_OFF_MODES,\n STRUCTURAL_MODES,\n VALIDATE_TS_MODES,\n} from './rule-configs';\nexport type {\n MethodLimitMode,\n FileLimitMode,\n ReturnTypeMode,\n InlineTypeMode,\n ModifiedCodeMode,\n ProjectMode,\n PrismaValidateDtosMode,\n PrismaConverterMode,\n DirectApiResolverMode,\n ThrowCauseMode,\n OnOffMode,\n StructuralMode,\n ValidateTsMode,\n} from './rule-configs';\nexport {\n GateDefinition,\n PrGateConfig,\n defaultGates,\n defaultPrGateConfig,\n buildPrGateConfig,\n} from './pr-gate-config';\nexport {\n ReviewJson,\n ReviewJsonService,\n loadReviewJson,\n prDirFor,\n reviewJsonPath,\n reviewJsonSchemaHint,\n} from './review-json';\nexport {\n MainSyncStatus,\n MainSyncLock,\n DEFAULT_HANG_TIMEOUT_MINUTES,\n mainSyncStatusPath,\n mainSyncLockPath,\n readMainSyncStatus,\n writeMainSyncStatus,\n readMainSyncLock,\n writeMainSyncLock,\n isLockStale,\n isRefreshInProgress,\n inProcessLock,\n finishedLock,\n computeMainSyncStatus,\n stampCleanMainSyncStatus,\n squashRecoverySteps,\n} from './main-sync-status';\nexport type { MutationVerb, MutationPhase } from './branch-mutation-log';\nexport {\n BranchMutationEvent,\n BranchMutationLog,\n branchMutationLogPath,\n logBranchMutation,\n} from './branch-mutation-log';\nexport {\n CommandsConfig,\n buildCommandsConfig,\n DEFAULT_UPSERT_PR_COMMAND,\n DEFAULT_MERGE_COMPLETE_COMMAND,\n} from './commands-config';\n"]}
|
package/src/review-json.d.ts
CHANGED
|
@@ -9,12 +9,20 @@ export declare class ReviewJson {
|
|
|
9
9
|
filesToReview: string[];
|
|
10
10
|
constructor(title: string, riskScore: number, riskLevel: string, riskEmoji: string, summary: string, violations: string[], risks: string[], filesToReview: string[]);
|
|
11
11
|
}
|
|
12
|
+
/** Locates + loads/validates the AI-authored review.json. `@provideSingleton` so it's drawn in the design. */
|
|
13
|
+
export declare class ReviewJsonService {
|
|
14
|
+
prDirFor(repoRoot: string, featureName: string): string;
|
|
15
|
+
reviewJsonPath(repoRoot: string, featureName: string): string;
|
|
16
|
+
reviewJsonSchemaHint(filePath: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Load + validate the AI-authored review.json. Throws InformAiError (with the schema) when missing,
|
|
19
|
+
* unparseable, or structurally wrong. Returns a fully-populated ReviewJson on success.
|
|
20
|
+
*/
|
|
21
|
+
loadReviewJson(filePath: string): ReviewJson;
|
|
22
|
+
private asStringArray;
|
|
23
|
+
private parseReviewJson;
|
|
24
|
+
}
|
|
12
25
|
export declare function prDirFor(repoRoot: string, featureName: string): string;
|
|
13
26
|
export declare function reviewJsonPath(repoRoot: string, featureName: string): string;
|
|
14
27
|
export declare function reviewJsonSchemaHint(filePath: string): string;
|
|
15
|
-
/**
|
|
16
|
-
* Load + validate the AI-authored review.json. Throws InformAiError (with the schema) when the file
|
|
17
|
-
* is missing, unparseable, or structurally wrong — the message is written straight back to the AI so
|
|
18
|
-
* it can fix the file and re-run. Returns a fully-populated ReviewJson on success.
|
|
19
|
-
*/
|
|
20
28
|
export declare function loadReviewJson(filePath: string): ReviewJson;
|
package/src/review-json.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ReviewJson = void 0;
|
|
3
|
+
exports.ReviewJsonService = exports.ReviewJson = void 0;
|
|
4
4
|
exports.prDirFor = prDirFor;
|
|
5
5
|
exports.reviewJsonPath = reviewJsonPath;
|
|
6
6
|
exports.reviewJsonSchemaHint = reviewJsonSchemaHint;
|
|
@@ -8,13 +8,13 @@ exports.loadReviewJson = loadReviewJson;
|
|
|
8
8
|
const tslib_1 = require("tslib");
|
|
9
9
|
const fs = tslib_1.__importStar(require("fs"));
|
|
10
10
|
const path = tslib_1.__importStar(require("path"));
|
|
11
|
+
const core_context_1 = require("@webpieces/core-context");
|
|
12
|
+
const inversify_1 = require("inversify");
|
|
11
13
|
const constants_1 = require("./constants");
|
|
12
14
|
const inform_ai_error_1 = require("./inform-ai-error");
|
|
13
15
|
const to_error_1 = require("./to-error");
|
|
14
|
-
// The AI-authored review for a PR.
|
|
15
|
-
//
|
|
16
|
-
// schema + instructions) and `wp-finish-upsert-pr` (which reads it to render the RISK section and
|
|
17
|
-
// post the PR). Data-only (per CLAUDE.md, classes for data).
|
|
16
|
+
// The AI-authored review for a PR. The AI writes this file itself between `wp-start-upsert-pr` (which
|
|
17
|
+
// prints the schema) and `wp-finish-upsert-pr` (which reads it). Data-only (per CLAUDE.md).
|
|
18
18
|
class ReviewJson {
|
|
19
19
|
title; // human PR title describing the change; used as the `gh pr` title (empty → caller falls back)
|
|
20
20
|
riskScore; // 0–100, drives the risk bar
|
|
@@ -38,94 +38,113 @@ class ReviewJson {
|
|
|
38
38
|
exports.ReviewJson = ReviewJson;
|
|
39
39
|
const RISK_LEVELS = ['green', 'yellow', 'red'];
|
|
40
40
|
const EMOJI_FOR_LEVEL = { green: '🟢', yellow: '🟡', red: '🔴' };
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
//
|
|
41
|
+
/** Locates + loads/validates the AI-authored review.json. `@provideSingleton` so it's drawn in the design. */
|
|
42
|
+
let ReviewJsonService = class ReviewJsonService {
|
|
43
|
+
// The per-feature PR working dir: `.webpieces/pr-review/<feature>`.
|
|
44
|
+
prDirFor(repoRoot, featureName) {
|
|
45
|
+
return path.join(repoRoot, constants_1.WEBPIECES_TMP_DIR, constants_1.PR_REVIEW_DIR, featureName);
|
|
46
|
+
}
|
|
47
|
+
// Absolute path of the review.json for a feature — beside pr-body.md, keyed by branch name.
|
|
48
|
+
reviewJsonPath(repoRoot, featureName) {
|
|
49
|
+
return path.join(this.prDirFor(repoRoot, featureName), 'review.json');
|
|
50
|
+
}
|
|
51
|
+
// Copy-paste schema both commands print (write it / fix it).
|
|
52
|
+
reviewJsonSchemaHint(filePath) {
|
|
53
|
+
return (`Write your PR review to:\n ${filePath}\n\n` +
|
|
54
|
+
`with this exact JSON shape (riskEmoji optional — derived from riskLevel):\n\n` +
|
|
55
|
+
`{\n` +
|
|
56
|
+
` "title": "concise PR title describing the change (imperative, no branch names)",\n` +
|
|
57
|
+
` "riskScore": 0, // integer 0–100 (higher = riskier)\n` +
|
|
58
|
+
` "riskLevel": "green | yellow | red",\n` +
|
|
59
|
+
` "summary": "5–10 sentence review summary",\n` +
|
|
60
|
+
` "violations": ["pattern/architecture violations you found (empty array if none)"],\n` +
|
|
61
|
+
` "risks": ["notable risks (empty array if none)"],\n` +
|
|
62
|
+
` "filesToReview": ["paths a human should look at (empty array if none)"]\n` +
|
|
63
|
+
`}`);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Load + validate the AI-authored review.json. Throws InformAiError (with the schema) when missing,
|
|
67
|
+
* unparseable, or structurally wrong. Returns a fully-populated ReviewJson on success.
|
|
68
|
+
*/
|
|
69
|
+
// webpieces-disable max-lines-new-methods -- one cohesive load+validate pass over the review fields
|
|
70
|
+
loadReviewJson(filePath) {
|
|
71
|
+
if (!fs.existsSync(filePath)) {
|
|
72
|
+
throw new inform_ai_error_1.InformAiError(`Required review.json not found.\n\n${this.reviewJsonSchemaHint(filePath)}\n\n` +
|
|
73
|
+
`Then re-run: pnpm wp-finish-upsert-pr`);
|
|
74
|
+
}
|
|
75
|
+
const raw = this.parseReviewJson(fs.readFileSync(filePath, 'utf8'), filePath);
|
|
76
|
+
if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {
|
|
77
|
+
throw new inform_ai_error_1.InformAiError(`review.json must be a JSON object.\n\n${this.reviewJsonSchemaHint(filePath)}`);
|
|
78
|
+
}
|
|
79
|
+
const errors = [];
|
|
80
|
+
const riskScore = raw['riskScore'];
|
|
81
|
+
if (typeof riskScore !== 'number' || !Number.isFinite(riskScore) || riskScore < 0 || riskScore > 100) {
|
|
82
|
+
errors.push(`"riskScore" must be a number 0–100, got ${JSON.stringify(riskScore)}.`);
|
|
83
|
+
}
|
|
84
|
+
const riskLevel = raw['riskLevel'];
|
|
85
|
+
if (typeof riskLevel !== 'string' || !RISK_LEVELS.includes(riskLevel)) {
|
|
86
|
+
errors.push(`"riskLevel" must be one of: ${RISK_LEVELS.join(', ')}.`);
|
|
87
|
+
}
|
|
88
|
+
const title = typeof raw['title'] === 'string' ? raw['title'].trim() : '';
|
|
89
|
+
if (title === '') {
|
|
90
|
+
errors.push('"title" must be a non-empty, imperative PR title describing the change (no branch names).');
|
|
91
|
+
}
|
|
92
|
+
if (errors.length > 0) {
|
|
93
|
+
throw new inform_ai_error_1.InformAiError(`review.json has ${errors.length} error(s) — fix ALL, then re-run pnpm wp-finish-upsert-pr:\n\n` +
|
|
94
|
+
errors.map((e) => ` • ${e}`).join('\n') +
|
|
95
|
+
`\n\n${this.reviewJsonSchemaHint(filePath)}`);
|
|
96
|
+
}
|
|
97
|
+
const level = riskLevel;
|
|
98
|
+
const emoji = typeof raw['riskEmoji'] === 'string' && raw['riskEmoji'] !== ''
|
|
99
|
+
? raw['riskEmoji']
|
|
100
|
+
: (EMOJI_FOR_LEVEL[level] ?? '🟡');
|
|
101
|
+
const summary = typeof raw['summary'] === 'string' ? raw['summary'] : '';
|
|
102
|
+
return new ReviewJson(title, riskScore, level, emoji, summary, this.asStringArray(raw['violations']), this.asStringArray(raw['risks']), this.asStringArray(raw['filesToReview']));
|
|
103
|
+
}
|
|
104
|
+
// webpieces-disable no-any-unknown -- opaque parsed JSON value, narrowed to string[] here
|
|
105
|
+
asStringArray(value) {
|
|
106
|
+
if (!Array.isArray(value))
|
|
107
|
+
return [];
|
|
108
|
+
// webpieces-disable no-any-unknown -- element of an opaque JSON array, narrowed by the type guard
|
|
109
|
+
return value.filter((v) => typeof v === 'string');
|
|
110
|
+
}
|
|
111
|
+
// Parse opaque AI-authored JSON, converting a SyntaxError into a readable InformAiError.
|
|
112
|
+
// webpieces-disable no-any-unknown -- returns the opaque parsed object; loadReviewJson narrows each field
|
|
113
|
+
parseReviewJson(raw, filePath) {
|
|
114
|
+
// webpieces-disable no-unmanaged-exceptions -- chokepoint: convert JSON.parse SyntaxError to an InformAiError for the AI
|
|
115
|
+
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
116
|
+
try {
|
|
117
|
+
// webpieces-disable no-any-unknown -- parsed JSON is opaque until narrowed by the caller
|
|
118
|
+
return JSON.parse(raw);
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
const error = (0, to_error_1.toError)(err);
|
|
122
|
+
throw new inform_ai_error_1.InformAiError(`review.json is not valid JSON (${error.message}).\n\n${this.reviewJsonSchemaHint(filePath)}\n\n` +
|
|
123
|
+
`Then re-run: pnpm wp-finish-upsert-pr`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
exports.ReviewJsonService = ReviewJsonService;
|
|
128
|
+
exports.ReviewJsonService = ReviewJsonService = tslib_1.__decorate([
|
|
129
|
+
(0, core_context_1.provideSingleton)(),
|
|
130
|
+
(0, inversify_1.injectable)()
|
|
131
|
+
], ReviewJsonService);
|
|
132
|
+
// Temporary migration delegators to ReviewJsonService — removed once consumers inject it.
|
|
133
|
+
const reviewJsonSvc = new ReviewJsonService();
|
|
134
|
+
// webpieces-disable no-function-outside-class -- temporary back-compat delegator to ReviewJsonService; removed once consumers inject it
|
|
44
135
|
function prDirFor(repoRoot, featureName) {
|
|
45
|
-
return
|
|
136
|
+
return reviewJsonSvc.prDirFor(repoRoot, featureName);
|
|
46
137
|
}
|
|
47
|
-
//
|
|
48
|
-
// AI and the finish command agree on the location without passing it around.
|
|
138
|
+
// webpieces-disable no-function-outside-class -- temporary back-compat delegator to ReviewJsonService; removed once consumers inject it
|
|
49
139
|
function reviewJsonPath(repoRoot, featureName) {
|
|
50
|
-
return
|
|
140
|
+
return reviewJsonSvc.reviewJsonPath(repoRoot, featureName);
|
|
51
141
|
}
|
|
52
|
-
//
|
|
53
|
-
// wp-finish-upsert-pr to instruct the AI to FIX it when missing/invalid.
|
|
142
|
+
// webpieces-disable no-function-outside-class -- temporary back-compat delegator to ReviewJsonService; removed once consumers inject it
|
|
54
143
|
function reviewJsonSchemaHint(filePath) {
|
|
55
|
-
return (
|
|
56
|
-
`with this exact JSON shape (riskEmoji optional — derived from riskLevel):\n\n` +
|
|
57
|
-
`{\n` +
|
|
58
|
-
` "title": "concise PR title describing the change (imperative, no branch names)",\n` +
|
|
59
|
-
` "riskScore": 0, // integer 0–100 (higher = riskier)\n` +
|
|
60
|
-
` "riskLevel": "green | yellow | red",\n` +
|
|
61
|
-
` "summary": "5–10 sentence review summary",\n` +
|
|
62
|
-
` "violations": ["pattern/architecture violations you found (empty array if none)"],\n` +
|
|
63
|
-
` "risks": ["notable risks (empty array if none)"],\n` +
|
|
64
|
-
` "filesToReview": ["paths a human should look at (empty array if none)"]\n` +
|
|
65
|
-
`}`);
|
|
66
|
-
}
|
|
67
|
-
// webpieces-disable no-any-unknown -- opaque parsed JSON value, narrowed to string[] here
|
|
68
|
-
function asStringArray(value) {
|
|
69
|
-
if (!Array.isArray(value))
|
|
70
|
-
return [];
|
|
71
|
-
// webpieces-disable no-any-unknown -- element of an opaque JSON array, narrowed by the type guard
|
|
72
|
-
return value.filter((v) => typeof v === 'string');
|
|
73
|
-
}
|
|
74
|
-
// Parse opaque AI-authored JSON, converting a SyntaxError into a readable InformAiError the AI can
|
|
75
|
-
// act on (mirrors readRawConfig in config-file.ts — the established JSON-parse chokepoint).
|
|
76
|
-
// webpieces-disable no-any-unknown -- returns the opaque parsed object; the caller narrows each field
|
|
77
|
-
function parseReviewJson(raw, filePath) {
|
|
78
|
-
// webpieces-disable no-unmanaged-exceptions -- chokepoint: convert JSON.parse SyntaxError to an InformAiError for the AI
|
|
79
|
-
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
80
|
-
try {
|
|
81
|
-
// webpieces-disable no-any-unknown -- parsed JSON is opaque until narrowed by the caller
|
|
82
|
-
return JSON.parse(raw);
|
|
83
|
-
}
|
|
84
|
-
catch (err) {
|
|
85
|
-
const error = (0, to_error_1.toError)(err);
|
|
86
|
-
throw new inform_ai_error_1.InformAiError(`review.json is not valid JSON (${error.message}).\n\n${reviewJsonSchemaHint(filePath)}\n\n` +
|
|
87
|
-
`Then re-run: pnpm wp-finish-upsert-pr`);
|
|
88
|
-
}
|
|
144
|
+
return reviewJsonSvc.reviewJsonSchemaHint(filePath);
|
|
89
145
|
}
|
|
90
|
-
|
|
91
|
-
* Load + validate the AI-authored review.json. Throws InformAiError (with the schema) when the file
|
|
92
|
-
* is missing, unparseable, or structurally wrong — the message is written straight back to the AI so
|
|
93
|
-
* it can fix the file and re-run. Returns a fully-populated ReviewJson on success.
|
|
94
|
-
*/
|
|
146
|
+
// webpieces-disable no-function-outside-class -- temporary back-compat delegator to ReviewJsonService; removed once consumers inject it
|
|
95
147
|
function loadReviewJson(filePath) {
|
|
96
|
-
|
|
97
|
-
throw new inform_ai_error_1.InformAiError(`Required review.json not found.\n\n${reviewJsonSchemaHint(filePath)}\n\n` +
|
|
98
|
-
`Then re-run: pnpm wp-finish-upsert-pr`);
|
|
99
|
-
}
|
|
100
|
-
const raw = parseReviewJson(fs.readFileSync(filePath, 'utf8'), filePath);
|
|
101
|
-
if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {
|
|
102
|
-
throw new inform_ai_error_1.InformAiError(`review.json must be a JSON object.\n\n${reviewJsonSchemaHint(filePath)}`);
|
|
103
|
-
}
|
|
104
|
-
const errors = [];
|
|
105
|
-
const riskScore = raw['riskScore'];
|
|
106
|
-
if (typeof riskScore !== 'number' || !Number.isFinite(riskScore) || riskScore < 0 || riskScore > 100) {
|
|
107
|
-
errors.push(`"riskScore" must be a number 0–100, got ${JSON.stringify(riskScore)}.`);
|
|
108
|
-
}
|
|
109
|
-
const riskLevel = raw['riskLevel'];
|
|
110
|
-
if (typeof riskLevel !== 'string' || !RISK_LEVELS.includes(riskLevel)) {
|
|
111
|
-
errors.push(`"riskLevel" must be one of: ${RISK_LEVELS.join(', ')}.`);
|
|
112
|
-
}
|
|
113
|
-
// Title is REQUIRED (hard-reject): the AI must author a real PR title. We no longer silently fall
|
|
114
|
-
// back to the feature name — an empty title means the AI skipped the field, which is a review gap.
|
|
115
|
-
const title = typeof raw['title'] === 'string' ? raw['title'].trim() : '';
|
|
116
|
-
if (title === '') {
|
|
117
|
-
errors.push('"title" must be a non-empty, imperative PR title describing the change (no branch names).');
|
|
118
|
-
}
|
|
119
|
-
if (errors.length > 0) {
|
|
120
|
-
throw new inform_ai_error_1.InformAiError(`review.json has ${errors.length} error(s) — fix ALL, then re-run pnpm wp-finish-upsert-pr:\n\n` +
|
|
121
|
-
errors.map((e) => ` • ${e}`).join('\n') +
|
|
122
|
-
`\n\n${reviewJsonSchemaHint(filePath)}`);
|
|
123
|
-
}
|
|
124
|
-
const level = riskLevel;
|
|
125
|
-
const emoji = typeof raw['riskEmoji'] === 'string' && raw['riskEmoji'] !== ''
|
|
126
|
-
? raw['riskEmoji']
|
|
127
|
-
: (EMOJI_FOR_LEVEL[level] ?? '🟡');
|
|
128
|
-
const summary = typeof raw['summary'] === 'string' ? raw['summary'] : '';
|
|
129
|
-
return new ReviewJson(title, riskScore, level, emoji, summary, asStringArray(raw['violations']), asStringArray(raw['risks']), asStringArray(raw['filesToReview']));
|
|
148
|
+
return reviewJsonSvc.loadReviewJson(filePath);
|
|
130
149
|
}
|
|
131
150
|
//# sourceMappingURL=review-json.js.map
|
package/src/review-json.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review-json.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/review-json.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport { WEBPIECES_TMP_DIR, PR_REVIEW_DIR } from './constants';\nimport { InformAiError } from './inform-ai-error';\nimport { toError } from './to-error';\n\n// The AI-authored review for a PR. webpieces is AI-first, so unlike trytami (where a human command\n// calls Claude), the AI writes this file itself between `wp-start-upsert-pr` (which prints the\n// schema + instructions) and `wp-finish-upsert-pr` (which reads it to render the RISK section and\n// post the PR). Data-only (per CLAUDE.md, classes for data).\nexport class ReviewJson {\n title: string; // human PR title describing the change; used as the `gh pr` title (empty → caller falls back)\n riskScore: number; // 0–100, drives the risk bar\n riskLevel: string; // 'green' | 'yellow' | 'red'\n riskEmoji: string; // '🟢' | '🟡' | '🔴' — derived from riskLevel when omitted\n summary: string; // rendered in the dashboard Summary section\n violations: string[]; // pattern/architecture violations; length = the Pattern Violations count\n risks: string[];\n filesToReview: string[];\n\n constructor(\n title: string,\n riskScore: number,\n riskLevel: string,\n riskEmoji: string,\n summary: string,\n violations: string[],\n risks: string[],\n filesToReview: string[],\n ) {\n this.title = title;\n this.riskScore = riskScore;\n this.riskLevel = riskLevel;\n this.riskEmoji = riskEmoji;\n this.summary = summary;\n this.violations = violations;\n this.risks = risks;\n this.filesToReview = filesToReview;\n }\n}\n\nconst RISK_LEVELS = ['green', 'yellow', 'red'] as const;\nconst EMOJI_FOR_LEVEL: Record<string, string> = { green: '🟢', yellow: '🟡', red: '🔴' };\n\n// The per-feature PR working dir: `.webpieces/pr-review/<feature>`. Holds pr-body.md (rendered\n// dashboard) and review.json (AI-authored review). Nested under pr-review/ to keep `.webpieces/`\n// top level quiet. Shared so the start/finish commands and the AI agree on one location.\nexport function prDirFor(repoRoot: string, featureName: string): string {\n return path.join(repoRoot, WEBPIECES_TMP_DIR, PR_REVIEW_DIR, featureName);\n}\n\n// Absolute path of the review.json for a feature — beside pr-body.md, keyed by branch name so the\n// AI and the finish command agree on the location without passing it around.\nexport function reviewJsonPath(repoRoot: string, featureName: string): string {\n return path.join(prDirFor(repoRoot, featureName), 'review.json');\n}\n\n// Copy-paste schema both commands print: wp-start-upsert-pr to instruct the AI to WRITE it,\n// wp-finish-upsert-pr to instruct the AI to FIX it when missing/invalid.\nexport function reviewJsonSchemaHint(filePath: string): string {\n return (\n `Write your PR review to:\\n ${filePath}\\n\\n` +\n `with this exact JSON shape (riskEmoji optional — derived from riskLevel):\\n\\n` +\n `{\\n` +\n ` \"title\": \"concise PR title describing the change (imperative, no branch names)\",\\n` +\n ` \"riskScore\": 0, // integer 0–100 (higher = riskier)\\n` +\n ` \"riskLevel\": \"green | yellow | red\",\\n` +\n ` \"summary\": \"5–10 sentence review summary\",\\n` +\n ` \"violations\": [\"pattern/architecture violations you found (empty array if none)\"],\\n` +\n ` \"risks\": [\"notable risks (empty array if none)\"],\\n` +\n ` \"filesToReview\": [\"paths a human should look at (empty array if none)\"]\\n` +\n `}`\n );\n}\n\n// webpieces-disable no-any-unknown -- opaque parsed JSON value, narrowed to string[] here\nfunction asStringArray(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n // webpieces-disable no-any-unknown -- element of an opaque JSON array, narrowed by the type guard\n return value.filter((v: unknown): v is string => typeof v === 'string');\n}\n\n// Parse opaque AI-authored JSON, converting a SyntaxError into a readable InformAiError the AI can\n// act on (mirrors readRawConfig in config-file.ts — the established JSON-parse chokepoint).\n// webpieces-disable no-any-unknown -- returns the opaque parsed object; the caller narrows each field\nfunction parseReviewJson(raw: string, filePath: string): Record<string, unknown> {\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: convert JSON.parse SyntaxError to an InformAiError for the AI\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // webpieces-disable no-any-unknown -- parsed JSON is opaque until narrowed by the caller\n return JSON.parse(raw) as Record<string, unknown>;\n } catch (err: unknown) {\n const error = toError(err);\n throw new InformAiError(\n `review.json is not valid JSON (${error.message}).\\n\\n${reviewJsonSchemaHint(filePath)}\\n\\n` +\n `Then re-run: pnpm wp-finish-upsert-pr`,\n );\n }\n}\n\n/**\n * Load + validate the AI-authored review.json. Throws InformAiError (with the schema) when the file\n * is missing, unparseable, or structurally wrong — the message is written straight back to the AI so\n * it can fix the file and re-run. Returns a fully-populated ReviewJson on success.\n */\nexport function loadReviewJson(filePath: string): ReviewJson {\n if (!fs.existsSync(filePath)) {\n throw new InformAiError(\n `Required review.json not found.\\n\\n${reviewJsonSchemaHint(filePath)}\\n\\n` +\n `Then re-run: pnpm wp-finish-upsert-pr`,\n );\n }\n\n const raw = parseReviewJson(fs.readFileSync(filePath, 'utf8'), filePath);\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n throw new InformAiError(`review.json must be a JSON object.\\n\\n${reviewJsonSchemaHint(filePath)}`);\n }\n\n const errors: string[] = [];\n\n const riskScore = raw['riskScore'];\n if (typeof riskScore !== 'number' || !Number.isFinite(riskScore) || riskScore < 0 || riskScore > 100) {\n errors.push(`\"riskScore\" must be a number 0–100, got ${JSON.stringify(riskScore)}.`);\n }\n\n const riskLevel = raw['riskLevel'];\n if (typeof riskLevel !== 'string' || !RISK_LEVELS.includes(riskLevel as typeof RISK_LEVELS[number])) {\n errors.push(`\"riskLevel\" must be one of: ${RISK_LEVELS.join(', ')}.`);\n }\n\n // Title is REQUIRED (hard-reject): the AI must author a real PR title. We no longer silently fall\n // back to the feature name — an empty title means the AI skipped the field, which is a review gap.\n const title = typeof raw['title'] === 'string' ? (raw['title'] as string).trim() : '';\n if (title === '') {\n errors.push('\"title\" must be a non-empty, imperative PR title describing the change (no branch names).');\n }\n\n if (errors.length > 0) {\n throw new InformAiError(\n `review.json has ${errors.length} error(s) — fix ALL, then re-run pnpm wp-finish-upsert-pr:\\n\\n` +\n errors.map((e: string): string => ` • ${e}`).join('\\n') +\n `\\n\\n${reviewJsonSchemaHint(filePath)}`,\n );\n }\n\n const level = riskLevel as string;\n const emoji = typeof raw['riskEmoji'] === 'string' && raw['riskEmoji'] !== ''\n ? (raw['riskEmoji'] as string)\n : (EMOJI_FOR_LEVEL[level] ?? '🟡');\n const summary = typeof raw['summary'] === 'string' ? (raw['summary'] as string) : '';\n\n return new ReviewJson(\n title,\n riskScore as number,\n level,\n emoji,\n summary,\n asStringArray(raw['violations']),\n asStringArray(raw['risks']),\n asStringArray(raw['filesToReview']),\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"review-json.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/review-json.ts"],"names":[],"mappings":";;;AAqKA,4BAEC;AAGD,wCAEC;AAGD,oDAEC;AAGD,wCAEC;;AAtLD,+CAAyB;AACzB,mDAA6B;AAC7B,0DAA2D;AAC3D,yCAAuC;AACvC,2CAA+D;AAC/D,uDAAkD;AAClD,yCAAqC;AAErC,sGAAsG;AACtG,4FAA4F;AAC5F,MAAa,UAAU;IACnB,KAAK,CAAS,CAAC,8FAA8F;IAC7G,SAAS,CAAS,CAAC,6BAA6B;IAChD,SAAS,CAAS,CAAC,6BAA6B;IAChD,SAAS,CAAS,CAAC,2DAA2D;IAC9E,OAAO,CAAS,CAAC,4CAA4C;IAC7D,UAAU,CAAW,CAAC,yEAAyE;IAC/F,KAAK,CAAW;IAChB,aAAa,CAAW;IAExB,YACI,KAAa,EACb,SAAiB,EACjB,SAAiB,EACjB,SAAiB,EACjB,OAAe,EACf,UAAoB,EACpB,KAAe,EACf,aAAuB;QAEvB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;IACvC,CAAC;CACJ;AA7BD,gCA6BC;AAED,MAAM,WAAW,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAU,CAAC;AACxD,MAAM,eAAe,GAA2B,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;AAEzF,8GAA8G;AAGvG,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IAC1B,oEAAoE;IACpE,QAAQ,CAAC,QAAgB,EAAE,WAAmB;QAC1C,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,6BAAiB,EAAE,yBAAa,EAAE,WAAW,CAAC,CAAC;IAC9E,CAAC;IAED,4FAA4F;IAC5F,cAAc,CAAC,QAAgB,EAAE,WAAmB;QAChD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,EAAE,aAAa,CAAC,CAAC;IAC1E,CAAC;IAED,6DAA6D;IAC7D,oBAAoB,CAAC,QAAgB;QACjC,OAAO,CACH,+BAA+B,QAAQ,MAAM;YAC7C,+EAA+E;YAC/E,KAAK;YACL,sFAAsF;YACtF,+EAA+E;YAC/E,0CAA0C;YAC1C,gDAAgD;YAChD,wFAAwF;YACxF,uDAAuD;YACvD,6EAA6E;YAC7E,GAAG,CACN,CAAC;IACN,CAAC;IAED;;;OAGG;IACH,oGAAoG;IACpG,cAAc,CAAC,QAAgB;QAC3B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,+BAAa,CACnB,sCAAsC,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC,MAAM;gBAC/E,uCAAuC,CAC1C,CAAC;QACN,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC;QAC9E,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAChE,MAAM,IAAI,+BAAa,CAAC,yCAAyC,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC5G,CAAC;QAED,MAAM,MAAM,GAAa,EAAE,CAAC;QAE5B,MAAM,SAAS,GAAG,GAAG,CAAC,WAAW,CAAC,CAAC;QACnC,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,GAAG,CAAC,IAAI,SAAS,GAAG,GAAG,EAAE,CAAC;YACnG,MAAM,CAAC,IAAI,CAAC,2CAA2C,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACzF,CAAC;QAED,MAAM,SAAS,GAAG,GAAG,CAAC,WAAW,CAAC,CAAC;QACnC,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,SAAuC,CAAC,EAAE,CAAC;YAClG,MAAM,CAAC,IAAI,CAAC,+BAA+B,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1E,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,GAAG,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,GAAG,CAAC,OAAO,CAAY,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtF,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YACf,MAAM,CAAC,IAAI,CAAC,2FAA2F,CAAC,CAAC;QAC7G,CAAC;QAED,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpB,MAAM,IAAI,+BAAa,CACnB,mBAAmB,MAAM,CAAC,MAAM,gEAAgE;gBAChG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAS,EAAU,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;gBACxD,OAAO,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC,EAAE,CAC/C,CAAC;QACN,CAAC;QAED,MAAM,KAAK,GAAG,SAAmB,CAAC;QAClC,MAAM,KAAK,GAAG,OAAO,GAAG,CAAC,WAAW,CAAC,KAAK,QAAQ,IAAI,GAAG,CAAC,WAAW,CAAC,KAAK,EAAE;YACzE,CAAC,CAAE,GAAG,CAAC,WAAW,CAAY;YAC9B,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC;QACvC,MAAM,OAAO,GAAG,OAAO,GAAG,CAAC,SAAS,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,GAAG,CAAC,SAAS,CAAY,CAAC,CAAC,CAAC,EAAE,CAAC;QAErF,OAAO,IAAI,UAAU,CACjB,KAAK,EACL,SAAmB,EACnB,KAAK,EACL,KAAK,EACL,OAAO,EACP,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,EACrC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAChC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAC3C,CAAC;IACN,CAAC;IAED,0FAA0F;IAClF,aAAa,CAAC,KAAc;QAChC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QACrC,kGAAkG;QAClG,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAU,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC;IAC5E,CAAC;IAED,yFAAyF;IACzF,0GAA0G;IAClG,eAAe,CAAC,GAAW,EAAE,QAAgB;QACjD,yHAAyH;QACzH,8DAA8D;QAC9D,IAAI,CAAC;YACD,yFAAyF;YACzF,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAA4B,CAAC;QACtD,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACpB,MAAM,KAAK,GAAG,IAAA,kBAAO,EAAC,GAAG,CAAC,CAAC;YAC3B,MAAM,IAAI,+BAAa,CACnB,kCAAkC,KAAK,CAAC,OAAO,SAAS,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC,MAAM;gBACjG,uCAAuC,CAC1C,CAAC;QACN,CAAC;IACL,CAAC;CACJ,CAAA;AAhHY,8CAAiB;4BAAjB,iBAAiB;IAF7B,IAAA,+BAAgB,GAAE;IAClB,IAAA,sBAAU,GAAE;GACA,iBAAiB,CAgH7B;AAED,0FAA0F;AAC1F,MAAM,aAAa,GAAG,IAAI,iBAAiB,EAAE,CAAC;AAE9C,wIAAwI;AACxI,SAAgB,QAAQ,CAAC,QAAgB,EAAE,WAAmB;IAC1D,OAAO,aAAa,CAAC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;AACzD,CAAC;AAED,wIAAwI;AACxI,SAAgB,cAAc,CAAC,QAAgB,EAAE,WAAmB;IAChE,OAAO,aAAa,CAAC,cAAc,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;AAC/D,CAAC;AAED,wIAAwI;AACxI,SAAgB,oBAAoB,CAAC,QAAgB;IACjD,OAAO,aAAa,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC;AACxD,CAAC;AAED,wIAAwI;AACxI,SAAgB,cAAc,CAAC,QAAgB;IAC3C,OAAO,aAAa,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;AAClD,CAAC","sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport { provideSingleton } from '@webpieces/core-context';\nimport { injectable } from 'inversify';\nimport { WEBPIECES_TMP_DIR, PR_REVIEW_DIR } from './constants';\nimport { InformAiError } from './inform-ai-error';\nimport { toError } from './to-error';\n\n// The AI-authored review for a PR. The AI writes this file itself between `wp-start-upsert-pr` (which\n// prints the schema) and `wp-finish-upsert-pr` (which reads it). Data-only (per CLAUDE.md).\nexport class ReviewJson {\n title: string; // human PR title describing the change; used as the `gh pr` title (empty → caller falls back)\n riskScore: number; // 0–100, drives the risk bar\n riskLevel: string; // 'green' | 'yellow' | 'red'\n riskEmoji: string; // '🟢' | '🟡' | '🔴' — derived from riskLevel when omitted\n summary: string; // rendered in the dashboard Summary section\n violations: string[]; // pattern/architecture violations; length = the Pattern Violations count\n risks: string[];\n filesToReview: string[];\n\n constructor(\n title: string,\n riskScore: number,\n riskLevel: string,\n riskEmoji: string,\n summary: string,\n violations: string[],\n risks: string[],\n filesToReview: string[],\n ) {\n this.title = title;\n this.riskScore = riskScore;\n this.riskLevel = riskLevel;\n this.riskEmoji = riskEmoji;\n this.summary = summary;\n this.violations = violations;\n this.risks = risks;\n this.filesToReview = filesToReview;\n }\n}\n\nconst RISK_LEVELS = ['green', 'yellow', 'red'] as const;\nconst EMOJI_FOR_LEVEL: Record<string, string> = { green: '🟢', yellow: '🟡', red: '🔴' };\n\n/** Locates + loads/validates the AI-authored review.json. `@provideSingleton` so it's drawn in the design. */\n@provideSingleton()\n@injectable()\nexport class ReviewJsonService {\n // The per-feature PR working dir: `.webpieces/pr-review/<feature>`.\n prDirFor(repoRoot: string, featureName: string): string {\n return path.join(repoRoot, WEBPIECES_TMP_DIR, PR_REVIEW_DIR, featureName);\n }\n\n // Absolute path of the review.json for a feature — beside pr-body.md, keyed by branch name.\n reviewJsonPath(repoRoot: string, featureName: string): string {\n return path.join(this.prDirFor(repoRoot, featureName), 'review.json');\n }\n\n // Copy-paste schema both commands print (write it / fix it).\n reviewJsonSchemaHint(filePath: string): string {\n return (\n `Write your PR review to:\\n ${filePath}\\n\\n` +\n `with this exact JSON shape (riskEmoji optional — derived from riskLevel):\\n\\n` +\n `{\\n` +\n ` \"title\": \"concise PR title describing the change (imperative, no branch names)\",\\n` +\n ` \"riskScore\": 0, // integer 0–100 (higher = riskier)\\n` +\n ` \"riskLevel\": \"green | yellow | red\",\\n` +\n ` \"summary\": \"5–10 sentence review summary\",\\n` +\n ` \"violations\": [\"pattern/architecture violations you found (empty array if none)\"],\\n` +\n ` \"risks\": [\"notable risks (empty array if none)\"],\\n` +\n ` \"filesToReview\": [\"paths a human should look at (empty array if none)\"]\\n` +\n `}`\n );\n }\n\n /**\n * Load + validate the AI-authored review.json. Throws InformAiError (with the schema) when missing,\n * unparseable, or structurally wrong. Returns a fully-populated ReviewJson on success.\n */\n // webpieces-disable max-lines-new-methods -- one cohesive load+validate pass over the review fields\n loadReviewJson(filePath: string): ReviewJson {\n if (!fs.existsSync(filePath)) {\n throw new InformAiError(\n `Required review.json not found.\\n\\n${this.reviewJsonSchemaHint(filePath)}\\n\\n` +\n `Then re-run: pnpm wp-finish-upsert-pr`,\n );\n }\n\n const raw = this.parseReviewJson(fs.readFileSync(filePath, 'utf8'), filePath);\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n throw new InformAiError(`review.json must be a JSON object.\\n\\n${this.reviewJsonSchemaHint(filePath)}`);\n }\n\n const errors: string[] = [];\n\n const riskScore = raw['riskScore'];\n if (typeof riskScore !== 'number' || !Number.isFinite(riskScore) || riskScore < 0 || riskScore > 100) {\n errors.push(`\"riskScore\" must be a number 0–100, got ${JSON.stringify(riskScore)}.`);\n }\n\n const riskLevel = raw['riskLevel'];\n if (typeof riskLevel !== 'string' || !RISK_LEVELS.includes(riskLevel as typeof RISK_LEVELS[number])) {\n errors.push(`\"riskLevel\" must be one of: ${RISK_LEVELS.join(', ')}.`);\n }\n\n const title = typeof raw['title'] === 'string' ? (raw['title'] as string).trim() : '';\n if (title === '') {\n errors.push('\"title\" must be a non-empty, imperative PR title describing the change (no branch names).');\n }\n\n if (errors.length > 0) {\n throw new InformAiError(\n `review.json has ${errors.length} error(s) — fix ALL, then re-run pnpm wp-finish-upsert-pr:\\n\\n` +\n errors.map((e: string): string => ` • ${e}`).join('\\n') +\n `\\n\\n${this.reviewJsonSchemaHint(filePath)}`,\n );\n }\n\n const level = riskLevel as string;\n const emoji = typeof raw['riskEmoji'] === 'string' && raw['riskEmoji'] !== ''\n ? (raw['riskEmoji'] as string)\n : (EMOJI_FOR_LEVEL[level] ?? '🟡');\n const summary = typeof raw['summary'] === 'string' ? (raw['summary'] as string) : '';\n\n return new ReviewJson(\n title,\n riskScore as number,\n level,\n emoji,\n summary,\n this.asStringArray(raw['violations']),\n this.asStringArray(raw['risks']),\n this.asStringArray(raw['filesToReview']),\n );\n }\n\n // webpieces-disable no-any-unknown -- opaque parsed JSON value, narrowed to string[] here\n private asStringArray(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n // webpieces-disable no-any-unknown -- element of an opaque JSON array, narrowed by the type guard\n return value.filter((v: unknown): v is string => typeof v === 'string');\n }\n\n // Parse opaque AI-authored JSON, converting a SyntaxError into a readable InformAiError.\n // webpieces-disable no-any-unknown -- returns the opaque parsed object; loadReviewJson narrows each field\n private parseReviewJson(raw: string, filePath: string): Record<string, unknown> {\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: convert JSON.parse SyntaxError to an InformAiError for the AI\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // webpieces-disable no-any-unknown -- parsed JSON is opaque until narrowed by the caller\n return JSON.parse(raw) as Record<string, unknown>;\n } catch (err: unknown) {\n const error = toError(err);\n throw new InformAiError(\n `review.json is not valid JSON (${error.message}).\\n\\n${this.reviewJsonSchemaHint(filePath)}\\n\\n` +\n `Then re-run: pnpm wp-finish-upsert-pr`,\n );\n }\n }\n}\n\n// Temporary migration delegators to ReviewJsonService — removed once consumers inject it.\nconst reviewJsonSvc = new ReviewJsonService();\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to ReviewJsonService; removed once consumers inject it\nexport function prDirFor(repoRoot: string, featureName: string): string {\n return reviewJsonSvc.prDirFor(repoRoot, featureName);\n}\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to ReviewJsonService; removed once consumers inject it\nexport function reviewJsonPath(repoRoot: string, featureName: string): string {\n return reviewJsonSvc.reviewJsonPath(repoRoot, featureName);\n}\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to ReviewJsonService; removed once consumers inject it\nexport function reviewJsonSchemaHint(filePath: string): string {\n return reviewJsonSvc.reviewJsonSchemaHint(filePath);\n}\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to ReviewJsonService; removed once consumers inject it\nexport function loadReviewJson(filePath: string): ReviewJson {\n return reviewJsonSvc.loadReviewJson(filePath);\n}\n"]}
|
|
@@ -2,6 +2,8 @@ import { RepoRootFinder } from './repo-root';
|
|
|
2
2
|
import { ConfigLoader } from './load-config';
|
|
3
3
|
import { TemplateWriter } from './load-template';
|
|
4
4
|
import { DiffScope } from './diff-scope';
|
|
5
|
+
import { BranchMutationLog } from './branch-mutation-log';
|
|
6
|
+
import { ReviewJsonService } from './review-json';
|
|
5
7
|
/**
|
|
6
8
|
* DI-design root for @webpieces/rules-config (role:designed-lib).
|
|
7
9
|
*
|
|
@@ -16,5 +18,7 @@ export declare class RulesConfigDesign {
|
|
|
16
18
|
private readonly configLoader;
|
|
17
19
|
private readonly templateWriter;
|
|
18
20
|
private readonly diffScope;
|
|
19
|
-
|
|
21
|
+
private readonly branchMutationLog;
|
|
22
|
+
private readonly reviewJson;
|
|
23
|
+
constructor(repoRootFinder: RepoRootFinder, configLoader: ConfigLoader, templateWriter: TemplateWriter, diffScope: DiffScope, branchMutationLog: BranchMutationLog, reviewJson: ReviewJsonService);
|
|
20
24
|
}
|
|
@@ -9,6 +9,8 @@ const repo_root_1 = require("./repo-root");
|
|
|
9
9
|
const load_config_1 = require("./load-config");
|
|
10
10
|
const load_template_1 = require("./load-template");
|
|
11
11
|
const diff_scope_1 = require("./diff-scope");
|
|
12
|
+
const branch_mutation_log_1 = require("./branch-mutation-log");
|
|
13
|
+
const review_json_1 = require("./review-json");
|
|
12
14
|
/**
|
|
13
15
|
* DI-design root for @webpieces/rules-config (role:designed-lib).
|
|
14
16
|
*
|
|
@@ -23,11 +25,15 @@ let RulesConfigDesign = class RulesConfigDesign {
|
|
|
23
25
|
configLoader;
|
|
24
26
|
templateWriter;
|
|
25
27
|
diffScope;
|
|
26
|
-
|
|
28
|
+
branchMutationLog;
|
|
29
|
+
reviewJson;
|
|
30
|
+
constructor(repoRootFinder, configLoader, templateWriter, diffScope, branchMutationLog, reviewJson) {
|
|
27
31
|
this.repoRootFinder = repoRootFinder;
|
|
28
32
|
this.configLoader = configLoader;
|
|
29
33
|
this.templateWriter = templateWriter;
|
|
30
34
|
this.diffScope = diffScope;
|
|
35
|
+
this.branchMutationLog = branchMutationLog;
|
|
36
|
+
this.reviewJson = reviewJson;
|
|
31
37
|
}
|
|
32
38
|
};
|
|
33
39
|
exports.RulesConfigDesign = RulesConfigDesign;
|
|
@@ -38,6 +44,8 @@ exports.RulesConfigDesign = RulesConfigDesign = tslib_1.__decorate([
|
|
|
38
44
|
tslib_1.__metadata("design:paramtypes", [repo_root_1.RepoRootFinder,
|
|
39
45
|
load_config_1.ConfigLoader,
|
|
40
46
|
load_template_1.TemplateWriter,
|
|
41
|
-
diff_scope_1.DiffScope
|
|
47
|
+
diff_scope_1.DiffScope,
|
|
48
|
+
branch_mutation_log_1.BranchMutationLog,
|
|
49
|
+
review_json_1.ReviewJsonService])
|
|
42
50
|
], RulesConfigDesign);
|
|
43
51
|
//# sourceMappingURL=rules-config-design.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules-config-design.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/rules-config-design.ts"],"names":[],"mappings":";;;;AAAA,oDAAsD;AACtD,0DAA2D;AAC3D,yCAAuC;AAEvC,2CAA6C;AAC7C,+CAA6C;AAC7C,mDAAiD;AACjD,6CAAyC;
|
|
1
|
+
{"version":3,"file":"rules-config-design.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/rules-config-design.ts"],"names":[],"mappings":";;;;AAAA,oDAAsD;AACtD,0DAA2D;AAC3D,yCAAuC;AAEvC,2CAA6C;AAC7C,+CAA6C;AAC7C,mDAAiD;AACjD,6CAAyC;AACzC,+DAA0D;AAC1D,+CAAkD;AAElD;;;;;;;;GAQG;AAII,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IAEL;IACA;IACA;IACA;IACA;IACA;IANrB,YACqB,cAA8B,EAC9B,YAA0B,EAC1B,cAA8B,EAC9B,SAAoB,EACpB,iBAAoC,EACpC,UAA6B;QAL7B,mBAAc,GAAd,cAAc,CAAgB;QAC9B,iBAAY,GAAZ,YAAY,CAAc;QAC1B,mBAAc,GAAd,cAAc,CAAgB;QAC9B,cAAS,GAAT,SAAS,CAAW;QACpB,sBAAiB,GAAjB,iBAAiB,CAAmB;QACpC,eAAU,GAAV,UAAU,CAAmB;IAC/C,CAAC;CACP,CAAA;AATY,8CAAiB;4BAAjB,iBAAiB;IAH7B,IAAA,0BAAc,GAAE;IAChB,IAAA,+BAAgB,GAAE;IAClB,IAAA,sBAAU,GAAE;6CAG4B,0BAAc;QAChB,0BAAY;QACV,8BAAc;QACnB,sBAAS;QACD,uCAAiB;QACxB,+BAAiB;GAPzC,iBAAiB,CAS7B","sourcesContent":["import { DocumentDesign } from '@webpieces/core-util';\nimport { provideSingleton } from '@webpieces/core-context';\nimport { injectable } from 'inversify';\n\nimport { RepoRootFinder } from './repo-root';\nimport { ConfigLoader } from './load-config';\nimport { TemplateWriter } from './load-template';\nimport { DiffScope } from './diff-scope';\nimport { BranchMutationLog } from './branch-mutation-log';\nimport { ReviewJsonService } from './review-json';\n\n/**\n * DI-design root for @webpieces/rules-config (role:designed-lib).\n *\n * `@DocumentDesign` marks the top of the DAG the DI-design analyzer roots on, so the library's design\n * (design.json / design.md / design.html) is generated. rules-config is the shared foundation whose\n * utilities are being migrated from free functions to injected `@provideSingleton` service classes; as\n * each service class lands (config loader, template writer, diff/git services, …) it is injected HERE\n * so it appears in the drawn design.\n */\n@DocumentDesign()\n@provideSingleton()\n@injectable()\nexport class RulesConfigDesign {\n constructor(\n private readonly repoRootFinder: RepoRootFinder,\n private readonly configLoader: ConfigLoader,\n private readonly templateWriter: TemplateWriter,\n private readonly diffScope: DiffScope,\n private readonly branchMutationLog: BranchMutationLog,\n private readonly reviewJson: ReviewJsonService,\n ) {}\n}\n"]}
|