@zephyrdeng/pi-review 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -473
- package/README.zh-CN.md +108 -256
- package/dist/args.d.ts.map +1 -1
- package/dist/args.js +6 -0
- package/dist/args.js.map +1 -1
- package/dist/cli.js +4 -1
- package/dist/cli.js.map +1 -1
- package/dist/extensions/review.d.ts +2 -0
- package/dist/extensions/review.js +22 -0
- package/dist/extensions/rv-prompts.d.ts +19 -0
- package/dist/extensions/rv-prompts.js +132 -0
- package/dist/screen-memory.d.ts +111 -0
- package/dist/screen-memory.d.ts.map +1 -0
- package/dist/screen-memory.js +320 -0
- package/dist/screen-memory.js.map +1 -0
- package/dist/screen-memory.test.d.ts +2 -0
- package/dist/screen-memory.test.d.ts.map +1 -0
- package/dist/screen-memory.test.js +145 -0
- package/dist/screen-memory.test.js.map +1 -0
- package/dist/screen.d.ts +17 -0
- package/dist/screen.d.ts.map +1 -1
- package/dist/screen.js +183 -11
- package/dist/screen.js.map +1 -1
- package/dist/screen.test.js +69 -1
- package/dist/screen.test.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/skills/pi-review/SKILL.md +38 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* English orchestration prompts for /rv — parent Pi agent runs pi-review per skill.
|
|
3
|
+
* Child review sessions use presets in resources/review-presets.json (also English).
|
|
4
|
+
*/
|
|
5
|
+
export type RvParsed = {
|
|
6
|
+
mode: "code" | "plan" | "challenge";
|
|
7
|
+
model?: string;
|
|
8
|
+
keepSession: boolean;
|
|
9
|
+
continueHandle?: string;
|
|
10
|
+
modelsOnly: boolean;
|
|
11
|
+
target: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function parseRvArgs(raw: string): RvParsed;
|
|
14
|
+
export declare function buildRvOrchestrationPrompt(parsed: RvParsed): string;
|
|
15
|
+
/** Short labels for TUI completions (English). */
|
|
16
|
+
export declare const RV_COMPLETIONS: {
|
|
17
|
+
value: string;
|
|
18
|
+
hint: string;
|
|
19
|
+
}[];
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* English orchestration prompts for /rv — parent Pi agent runs pi-review per skill.
|
|
3
|
+
* Child review sessions use presets in resources/review-presets.json (also English).
|
|
4
|
+
*/
|
|
5
|
+
export function parseRvArgs(raw) {
|
|
6
|
+
const tokens = raw.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g) ?? [];
|
|
7
|
+
const cleaned = tokens.map((t) => t.replace(/^['"]|['"]$/g, ""));
|
|
8
|
+
let mode = "code";
|
|
9
|
+
let model;
|
|
10
|
+
let keepSession = false;
|
|
11
|
+
let continueHandle;
|
|
12
|
+
let modelsOnly = false;
|
|
13
|
+
const rest = [];
|
|
14
|
+
for (let i = 0; i < cleaned.length; i++) {
|
|
15
|
+
const t = cleaned[i];
|
|
16
|
+
if (t === "models" && rest.length === 0 && i === cleaned.length - 1) {
|
|
17
|
+
modelsOnly = true;
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (t === "--keep-session") {
|
|
21
|
+
keepSession = true;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (t === "--mode" && cleaned[i + 1]) {
|
|
25
|
+
const m = cleaned[++i];
|
|
26
|
+
if (m === "plan" || m === "challenge" || m === "code")
|
|
27
|
+
mode = m;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (t === "--model" && cleaned[i + 1]) {
|
|
31
|
+
model = cleaned[++i];
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (t === "--continue" && cleaned[i + 1]) {
|
|
35
|
+
continueHandle = cleaned[++i];
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
rest.push(t);
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
mode,
|
|
42
|
+
model,
|
|
43
|
+
keepSession,
|
|
44
|
+
continueHandle,
|
|
45
|
+
modelsOnly,
|
|
46
|
+
target: rest.join(" ").trim(),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function baseRules() {
|
|
50
|
+
return [
|
|
51
|
+
"Follow the pi-review skill.",
|
|
52
|
+
"Run pi-review in an isolated child session; return only the review conclusion.",
|
|
53
|
+
"Do not edit, patch, commit, or implement findings unless the user asks separately.",
|
|
54
|
+
"Preserve the final PI_REVIEW_META line from pi-review output.",
|
|
55
|
+
].join(" ");
|
|
56
|
+
}
|
|
57
|
+
export function buildRvOrchestrationPrompt(parsed) {
|
|
58
|
+
if (parsed.modelsOnly) {
|
|
59
|
+
return [
|
|
60
|
+
"Run the pi-review model catalog step.",
|
|
61
|
+
baseRules(),
|
|
62
|
+
"Execute: pi-review models",
|
|
63
|
+
"Present a short English summary: how many providers, suggest 2–3 IDs suited for code review vs plan/challenge.",
|
|
64
|
+
"Do not start a review until the user supplies a target (@path or text).",
|
|
65
|
+
].join("\n\n");
|
|
66
|
+
}
|
|
67
|
+
if (parsed.continueHandle) {
|
|
68
|
+
return [
|
|
69
|
+
"Continue a prior pi-review session.",
|
|
70
|
+
baseRules(),
|
|
71
|
+
`Execute: pi-review --continue ${parsed.continueHandle} -- ${parsed.target || "follow up on the previous review"}`,
|
|
72
|
+
"Answer the follow-up in English; keep the same review-only scope.",
|
|
73
|
+
].join("\n\n");
|
|
74
|
+
}
|
|
75
|
+
if (!parsed.target) {
|
|
76
|
+
return [
|
|
77
|
+
"The /rv command needs a review target.",
|
|
78
|
+
"Tell the user (in English): usage is /rv [--mode code|plan|challenge] [--model provider/model] [--keep-session] -- @files-or-brief",
|
|
79
|
+
"Examples: /rv @src/foo.ts | /rv --mode challenge @docs/design.md | /rv models",
|
|
80
|
+
].join("\n\n");
|
|
81
|
+
}
|
|
82
|
+
const modeBlock = {
|
|
83
|
+
code: [
|
|
84
|
+
"Mode: code (default).",
|
|
85
|
+
"Focus: correctness, regressions, security, concurrency, API contracts, edge cases, tests.",
|
|
86
|
+
"Use read-only inspection via pi-review; no file mutations.",
|
|
87
|
+
].join(" "),
|
|
88
|
+
plan: [
|
|
89
|
+
"Mode: plan.",
|
|
90
|
+
"Review architecture, design, or strategy through engineering, product, security, QA, ops, and DX lenses.",
|
|
91
|
+
"Identify fatal flaws, trade-offs, sequencing risks, and minimal changes to de-risk the plan.",
|
|
92
|
+
].join(" "),
|
|
93
|
+
challenge: [
|
|
94
|
+
"Mode: challenge (adversarial).",
|
|
95
|
+
"Pressure-test assumptions, boundaries, dependencies, failure modes, migration, and missing evidence.",
|
|
96
|
+
"One-shot conclusion; do not run a live Q&A interview.",
|
|
97
|
+
].join(" "),
|
|
98
|
+
};
|
|
99
|
+
const cliParts = ["pi-review"];
|
|
100
|
+
if (parsed.mode !== "code")
|
|
101
|
+
cliParts.push(`--mode ${parsed.mode}`);
|
|
102
|
+
if (parsed.model)
|
|
103
|
+
cliParts.push(`--model ${parsed.model}`);
|
|
104
|
+
if (parsed.keepSession)
|
|
105
|
+
cliParts.push("--keep-session");
|
|
106
|
+
cliParts.push("--", parsed.target);
|
|
107
|
+
const modelStep = parsed.model
|
|
108
|
+
? `Use model exactly as given: ${parsed.model} (must appear in pi-review models output).`
|
|
109
|
+
: "Run pi-review models first if needed; pick a suitable listed ID or omit --model for Pi default.";
|
|
110
|
+
return [
|
|
111
|
+
"Run pi-review for the target below.",
|
|
112
|
+
baseRules(),
|
|
113
|
+
modeBlock[parsed.mode],
|
|
114
|
+
modelStep,
|
|
115
|
+
parsed.keepSession
|
|
116
|
+
? "Use --keep-session so the user can follow up with /rv --continue <handle>."
|
|
117
|
+
: "",
|
|
118
|
+
`Execute:\n${cliParts.join(" ")}`,
|
|
119
|
+
]
|
|
120
|
+
.filter(Boolean)
|
|
121
|
+
.join("\n\n");
|
|
122
|
+
}
|
|
123
|
+
/** Short labels for TUI completions (English). */
|
|
124
|
+
export const RV_COMPLETIONS = [
|
|
125
|
+
{ value: "@", hint: "file path after @ (e.g. @src/foo.ts)" },
|
|
126
|
+
{ value: "models", hint: "list pi-review models only" },
|
|
127
|
+
{ value: "--mode code", hint: "code / diff / MR review" },
|
|
128
|
+
{ value: "--mode plan", hint: "architecture or plan review" },
|
|
129
|
+
{ value: "--mode challenge", hint: "adversarial plan review" },
|
|
130
|
+
{ value: "--model ", hint: "provider/model from pi-review models" },
|
|
131
|
+
{ value: "--keep-session", hint: "persist session for follow-up" },
|
|
132
|
+
];
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { ScreenPattern } from "./screen.js";
|
|
2
|
+
/** A hunk flagged by screening (pattern hit or catch-all at/over threshold). */
|
|
3
|
+
export interface FlaggedScreenHunk {
|
|
4
|
+
path: string;
|
|
5
|
+
hunk: string;
|
|
6
|
+
startLine: number;
|
|
7
|
+
endLine: number;
|
|
8
|
+
catchAll?: number;
|
|
9
|
+
patterns: string[];
|
|
10
|
+
code: string;
|
|
11
|
+
}
|
|
12
|
+
/** One JSONL row in screen-memory.jsonl. */
|
|
13
|
+
export interface ScreenMemoryEntry {
|
|
14
|
+
ts: string;
|
|
15
|
+
path: string;
|
|
16
|
+
hunk: string;
|
|
17
|
+
lines: [number, number];
|
|
18
|
+
catchAll?: number;
|
|
19
|
+
/** Pattern ids that fired; empty means the catch-all alone flagged it. */
|
|
20
|
+
patterns: string[];
|
|
21
|
+
/** Catch-all fired with no catalog hit — a promotion candidate. */
|
|
22
|
+
unmatched: boolean;
|
|
23
|
+
/** sha256 of the hunk code — dedupe key across runs. */
|
|
24
|
+
hash: string;
|
|
25
|
+
/** Truncated hunk source for later inspection; absent past SNIPPET_LIMIT. */
|
|
26
|
+
code?: string;
|
|
27
|
+
/** How many runs flagged this same (path, hunk, hash). Absent = 1. */
|
|
28
|
+
seen?: number;
|
|
29
|
+
}
|
|
30
|
+
/** Hard cap keeps the log self-bounding; on overflow the newest entries stay. */
|
|
31
|
+
export declare const MEMORY_ENTRY_LIMIT = 500;
|
|
32
|
+
export declare const MEMORY_ENTRY_KEEP = 400;
|
|
33
|
+
/** Stored code snippets never exceed this many characters. */
|
|
34
|
+
export declare const SNIPPET_LIMIT = 1600;
|
|
35
|
+
/** Machine-level user catalog, sibling of config.json. */
|
|
36
|
+
export declare function screenPatternsFilePath(env?: NodeJS.ProcessEnv): string;
|
|
37
|
+
export declare function screenMemoryFilePath(env?: NodeJS.ProcessEnv): string;
|
|
38
|
+
export declare function screenMemoryEnabled(env?: NodeJS.ProcessEnv): boolean;
|
|
39
|
+
export interface ScreenPatternsFileLoad {
|
|
40
|
+
patterns: Record<string, ScreenPattern>;
|
|
41
|
+
disabled: string[];
|
|
42
|
+
warnings: string[];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Parse one patterns file, lenient like pi-config: bad entries warn and are
|
|
46
|
+
* skipped, unknown keys are ignored, invalid JSON yields an empty file.
|
|
47
|
+
* Shape: { "patterns": {id: {title, severity, category, recommendation}},
|
|
48
|
+
* "disabled": [id, ...] }
|
|
49
|
+
*/
|
|
50
|
+
export declare function parseScreenPatternsFile(text: string, source: string): ScreenPatternsFileLoad;
|
|
51
|
+
export interface UserPatternsLoad extends ScreenPatternsFileLoad {
|
|
52
|
+
/** Files that were read, in merge order (later files win id conflicts). */
|
|
53
|
+
files: string[];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Load user-declared patterns: the machine file first, then the extra file
|
|
57
|
+
* named by PI_REVIEW_SCREEN_PATTERNS (typically a project catalog checked
|
|
58
|
+
* into the repo). Later files override earlier ones on id conflicts, so a
|
|
59
|
+
* project can re-tune or replace a builtin entry. Missing files are skipped
|
|
60
|
+
* silently; unreadable ones warn.
|
|
61
|
+
*/
|
|
62
|
+
export declare function loadUserPatterns(env?: NodeJS.ProcessEnv): UserPatternsLoad;
|
|
63
|
+
/** Lenient JSONL read: malformed lines are skipped, a missing file is empty. */
|
|
64
|
+
export declare function readScreenMemory(file: string): ScreenMemoryEntry[];
|
|
65
|
+
/**
|
|
66
|
+
* Record flagged hunks in the memory log. No-ops when recording is disabled
|
|
67
|
+
* or nothing was flagged. A repeated (path, hunk, code hash) refreshes the
|
|
68
|
+
* stored verdict in place and bumps `seen` — so promoting a pattern visibly
|
|
69
|
+
* flips its entry from unmatched to a hit — while new hashes append. The file
|
|
70
|
+
* is rewritten capped at MEMORY_ENTRY_LIMIT entries (newest MEMORY_ENTRY_KEEP
|
|
71
|
+
* survive) via tmp+rename with 0600 permissions: hunk code can embed the very
|
|
72
|
+
* secrets the catalog flags. Best-effort: any failure warns on stderr and
|
|
73
|
+
* never fails the gate.
|
|
74
|
+
*/
|
|
75
|
+
export declare function recordScreenMemory(flagged: FlaggedScreenHunk[], env?: NodeJS.ProcessEnv): void;
|
|
76
|
+
export interface UnmatchedSignalGroup {
|
|
77
|
+
path: string;
|
|
78
|
+
hunk: string;
|
|
79
|
+
count: number;
|
|
80
|
+
lastCatchAll?: number;
|
|
81
|
+
lastLines: [number, number];
|
|
82
|
+
/** First non-empty line of the newest hunk code, truncated. */
|
|
83
|
+
sample: string;
|
|
84
|
+
}
|
|
85
|
+
export interface ScreenMemoryStats {
|
|
86
|
+
entries: number;
|
|
87
|
+
files: number;
|
|
88
|
+
unmatchedEntries: number;
|
|
89
|
+
/** Pattern id → times it fired, sorted desc. */
|
|
90
|
+
patternHits: Array<{
|
|
91
|
+
id: string;
|
|
92
|
+
count: number;
|
|
93
|
+
}>;
|
|
94
|
+
/** Unmatched signals grouped by path+hunk, sorted by count desc. */
|
|
95
|
+
unmatched: UnmatchedSignalGroup[];
|
|
96
|
+
}
|
|
97
|
+
export declare function aggregateScreenMemory(entries: ScreenMemoryEntry[]): ScreenMemoryStats;
|
|
98
|
+
export interface ScreenMemoryMeta {
|
|
99
|
+
file: string;
|
|
100
|
+
/** Where new patterns go (the machine-level patterns file). */
|
|
101
|
+
patternsFile: string;
|
|
102
|
+
catalog: {
|
|
103
|
+
builtin: number;
|
|
104
|
+
custom: number;
|
|
105
|
+
overrides: number;
|
|
106
|
+
disabled: number;
|
|
107
|
+
recording: boolean;
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
export declare function formatScreenMemoryAscii(stats: ScreenMemoryStats, meta: ScreenMemoryMeta): string;
|
|
111
|
+
//# sourceMappingURL=screen-memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screen-memory.d.ts","sourceRoot":"","sources":["../src/screen-memory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
// pi-review screen memory: the screening catalog learns from use.
|
|
2
|
+
//
|
|
3
|
+
// Two mechanisms share the pi-review state dir (siblings of config.json):
|
|
4
|
+
//
|
|
5
|
+
// - screen-patterns.json — a user-declared pattern catalog merged over the
|
|
6
|
+
// builtin SCREEN_PATTERNS, plus a `disabled` list to retire entries that
|
|
7
|
+
// misfire on this codebase. PI_REVIEW_SCREEN_PATTERNS names one extra file
|
|
8
|
+
// (e.g. a project catalog committed to the repo) which loads last and wins
|
|
9
|
+
// id conflicts — that is how a team shares its own defect patterns.
|
|
10
|
+
//
|
|
11
|
+
// - screen-memory.jsonl — every flagged hunk appends one JSONL entry with a
|
|
12
|
+
// code hash and its verdict. `pi-review screen-memory` aggregates the log:
|
|
13
|
+
// recurring unmatched signals are the evidence for new patterns, and hit
|
|
14
|
+
// frequencies show which entries earn their place. Promotion is always a
|
|
15
|
+
// human/agent edit of screen-patterns.json — screen never rewrites its own
|
|
16
|
+
// catalog. PI_REVIEW_SCREEN_MEMORY=0 disables recording; the file path moves
|
|
17
|
+
// with PI_REVIEW_SCREEN_MEMORY_FILE.
|
|
18
|
+
//
|
|
19
|
+
// Both files are advisory: malformed lines and invalid JSON warn on stderr and
|
|
20
|
+
// degrade to "nothing loaded" — memory must never break the gate.
|
|
21
|
+
import crypto from "node:crypto";
|
|
22
|
+
import fs from "node:fs";
|
|
23
|
+
import path from "node:path";
|
|
24
|
+
import { configFilePath } from "./pi-config.js";
|
|
25
|
+
import { expandMaybeHome } from "./utils.js";
|
|
26
|
+
/** Hard cap keeps the log self-bounding; on overflow the newest entries stay. */
|
|
27
|
+
export const MEMORY_ENTRY_LIMIT = 500;
|
|
28
|
+
export const MEMORY_ENTRY_KEEP = 400;
|
|
29
|
+
/** Stored code snippets never exceed this many characters. */
|
|
30
|
+
export const SNIPPET_LIMIT = 1600;
|
|
31
|
+
const VALID_SEVERITIES = new Set(["critical", "major", "minor"]);
|
|
32
|
+
const VALID_CATEGORIES = new Set(["correctness", "security", "data-loss", "performance"]);
|
|
33
|
+
const PATTERN_ID_RE = /^[a-z][a-z0-9_]{0,63}$/;
|
|
34
|
+
/** pi-review state dir: the directory containing the effective config file. */
|
|
35
|
+
function stateDir(env) {
|
|
36
|
+
return path.dirname(configFilePath(env));
|
|
37
|
+
}
|
|
38
|
+
/** Machine-level user catalog, sibling of config.json. */
|
|
39
|
+
export function screenPatternsFilePath(env = process.env) {
|
|
40
|
+
return path.join(stateDir(env), "screen-patterns.json");
|
|
41
|
+
}
|
|
42
|
+
export function screenMemoryFilePath(env = process.env) {
|
|
43
|
+
const override = env.PI_REVIEW_SCREEN_MEMORY_FILE?.trim();
|
|
44
|
+
if (override)
|
|
45
|
+
return expandMaybeHome(override);
|
|
46
|
+
return path.join(stateDir(env), "screen-memory.jsonl");
|
|
47
|
+
}
|
|
48
|
+
export function screenMemoryEnabled(env = process.env) {
|
|
49
|
+
const raw = env.PI_REVIEW_SCREEN_MEMORY?.trim().toLowerCase();
|
|
50
|
+
return raw !== "0" && raw !== "false" && raw !== "off";
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Parse one patterns file, lenient like pi-config: bad entries warn and are
|
|
54
|
+
* skipped, unknown keys are ignored, invalid JSON yields an empty file.
|
|
55
|
+
* Shape: { "patterns": {id: {title, severity, category, recommendation}},
|
|
56
|
+
* "disabled": [id, ...] }
|
|
57
|
+
*/
|
|
58
|
+
export function parseScreenPatternsFile(text, source) {
|
|
59
|
+
const warnings = [];
|
|
60
|
+
let raw;
|
|
61
|
+
try {
|
|
62
|
+
raw = JSON.parse(text);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
return {
|
|
66
|
+
patterns: {},
|
|
67
|
+
disabled: [],
|
|
68
|
+
warnings: [`${source} is not valid JSON (${error.message}); treating it as empty`],
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
72
|
+
return { patterns: {}, disabled: [], warnings: [`${source} must contain a JSON object; treating it as empty`] };
|
|
73
|
+
}
|
|
74
|
+
const record = raw;
|
|
75
|
+
const patterns = {};
|
|
76
|
+
if (record.patterns !== undefined && record.patterns !== null) {
|
|
77
|
+
if (typeof record.patterns !== "object" || Array.isArray(record.patterns)) {
|
|
78
|
+
warnings.push(`${source}: "patterns" must be an object; ignoring it`);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
for (const [id, value] of Object.entries(record.patterns)) {
|
|
82
|
+
if (!PATTERN_ID_RE.test(id)) {
|
|
83
|
+
warnings.push(`${source}: pattern id "${id}" must match ${PATTERN_ID_RE}; skipping it`);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const entry = value;
|
|
87
|
+
const problems = [];
|
|
88
|
+
if (entry === null || typeof entry !== "object" || Array.isArray(entry))
|
|
89
|
+
problems.push("entry must be an object");
|
|
90
|
+
else {
|
|
91
|
+
if (typeof entry.title !== "string" || !entry.title.trim())
|
|
92
|
+
problems.push("title must be a non-empty string");
|
|
93
|
+
if (typeof entry.severity !== "string" || !VALID_SEVERITIES.has(entry.severity))
|
|
94
|
+
problems.push(`severity must be one of ${[...VALID_SEVERITIES].join("/")}`);
|
|
95
|
+
if (typeof entry.category !== "string" || !VALID_CATEGORIES.has(entry.category))
|
|
96
|
+
problems.push(`category must be one of ${[...VALID_CATEGORIES].join("/")}`);
|
|
97
|
+
if (typeof entry.recommendation !== "string" || !entry.recommendation.trim())
|
|
98
|
+
problems.push("recommendation must be a non-empty string");
|
|
99
|
+
}
|
|
100
|
+
if (problems.length > 0) {
|
|
101
|
+
warnings.push(`${source}: pattern "${id}" invalid (${problems.join("; ")}); skipping it`);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
patterns[id] = {
|
|
105
|
+
title: entry.title.trim(),
|
|
106
|
+
severity: entry.severity,
|
|
107
|
+
category: entry.category,
|
|
108
|
+
recommendation: entry.recommendation.trim(),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const disabled = [];
|
|
114
|
+
if (record.disabled !== undefined && record.disabled !== null) {
|
|
115
|
+
if (!Array.isArray(record.disabled)) {
|
|
116
|
+
warnings.push(`${source}: "disabled" must be an array of pattern ids; ignoring it`);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
for (const value of record.disabled) {
|
|
120
|
+
if (typeof value === "string" && value.trim())
|
|
121
|
+
disabled.push(value.trim());
|
|
122
|
+
else
|
|
123
|
+
warnings.push(`${source}: "disabled" entries must be pattern id strings; skipping one`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return { patterns, disabled, warnings };
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Load user-declared patterns: the machine file first, then the extra file
|
|
131
|
+
* named by PI_REVIEW_SCREEN_PATTERNS (typically a project catalog checked
|
|
132
|
+
* into the repo). Later files override earlier ones on id conflicts, so a
|
|
133
|
+
* project can re-tune or replace a builtin entry. Missing files are skipped
|
|
134
|
+
* silently; unreadable ones warn.
|
|
135
|
+
*/
|
|
136
|
+
export function loadUserPatterns(env = process.env) {
|
|
137
|
+
const files = [screenPatternsFilePath(env)];
|
|
138
|
+
const extra = env.PI_REVIEW_SCREEN_PATTERNS?.trim();
|
|
139
|
+
if (extra)
|
|
140
|
+
files.push(expandMaybeHome(extra));
|
|
141
|
+
const merged = { patterns: {}, disabled: [], warnings: [], files: [] };
|
|
142
|
+
for (const file of files) {
|
|
143
|
+
if (!fs.existsSync(file))
|
|
144
|
+
continue;
|
|
145
|
+
let load;
|
|
146
|
+
try {
|
|
147
|
+
load = parseScreenPatternsFile(fs.readFileSync(file, "utf8"), file);
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
merged.warnings.push(`cannot read ${file}: ${error.message}`);
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
merged.files.push(file);
|
|
154
|
+
Object.assign(merged.patterns, load.patterns);
|
|
155
|
+
merged.disabled.push(...load.disabled);
|
|
156
|
+
merged.warnings.push(...load.warnings);
|
|
157
|
+
}
|
|
158
|
+
merged.disabled = [...new Set(merged.disabled)];
|
|
159
|
+
return merged;
|
|
160
|
+
}
|
|
161
|
+
/** Lenient JSONL read: malformed lines are skipped, a missing file is empty. */
|
|
162
|
+
export function readScreenMemory(file) {
|
|
163
|
+
let text;
|
|
164
|
+
try {
|
|
165
|
+
text = fs.readFileSync(file, "utf8");
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
return [];
|
|
169
|
+
}
|
|
170
|
+
const entries = [];
|
|
171
|
+
for (const line of text.split("\n")) {
|
|
172
|
+
if (!line.trim())
|
|
173
|
+
continue;
|
|
174
|
+
try {
|
|
175
|
+
const entry = JSON.parse(line);
|
|
176
|
+
if (entry && typeof entry === "object" && typeof entry.path === "string" && typeof entry.hunk === "string") {
|
|
177
|
+
entries.push(entry);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
// malformed line: drop it — the log is advisory telemetry
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return entries;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Record flagged hunks in the memory log. No-ops when recording is disabled
|
|
188
|
+
* or nothing was flagged. A repeated (path, hunk, code hash) refreshes the
|
|
189
|
+
* stored verdict in place and bumps `seen` — so promoting a pattern visibly
|
|
190
|
+
* flips its entry from unmatched to a hit — while new hashes append. The file
|
|
191
|
+
* is rewritten capped at MEMORY_ENTRY_LIMIT entries (newest MEMORY_ENTRY_KEEP
|
|
192
|
+
* survive) via tmp+rename with 0600 permissions: hunk code can embed the very
|
|
193
|
+
* secrets the catalog flags. Best-effort: any failure warns on stderr and
|
|
194
|
+
* never fails the gate.
|
|
195
|
+
*/
|
|
196
|
+
export function recordScreenMemory(flagged, env = process.env) {
|
|
197
|
+
if (flagged.length === 0 || !screenMemoryEnabled(env))
|
|
198
|
+
return;
|
|
199
|
+
try {
|
|
200
|
+
const file = screenMemoryFilePath(env);
|
|
201
|
+
const existing = readScreenMemory(file);
|
|
202
|
+
const byKey = new Map(existing.map((e) => [`${e.path}\u0000${e.hunk}\u0000${e.hash}`, e]));
|
|
203
|
+
const ts = new Date().toISOString();
|
|
204
|
+
let touched = 0;
|
|
205
|
+
for (const item of flagged) {
|
|
206
|
+
const hash = crypto.createHash("sha256").update(item.code).digest("hex");
|
|
207
|
+
const key = `${item.path}\u0000${item.hunk}\u0000${hash}`;
|
|
208
|
+
const snippet = item.code.length <= SNIPPET_LIMIT ? item.code : `${item.code.slice(0, SNIPPET_LIMIT)}…`;
|
|
209
|
+
const prev = byKey.get(key);
|
|
210
|
+
if (prev) {
|
|
211
|
+
prev.ts = ts;
|
|
212
|
+
prev.lines = [item.startLine, item.endLine];
|
|
213
|
+
prev.patterns = item.patterns;
|
|
214
|
+
prev.unmatched = item.patterns.length === 0;
|
|
215
|
+
if (item.catchAll !== undefined)
|
|
216
|
+
prev.catchAll = item.catchAll;
|
|
217
|
+
prev.seen = (prev.seen ?? 1) + 1;
|
|
218
|
+
touched += 1;
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
byKey.set(key, {
|
|
222
|
+
ts,
|
|
223
|
+
path: item.path,
|
|
224
|
+
hunk: item.hunk,
|
|
225
|
+
lines: [item.startLine, item.endLine],
|
|
226
|
+
...(item.catchAll !== undefined ? { catchAll: item.catchAll } : {}),
|
|
227
|
+
patterns: item.patterns,
|
|
228
|
+
unmatched: item.patterns.length === 0,
|
|
229
|
+
hash,
|
|
230
|
+
code: snippet,
|
|
231
|
+
seen: 1,
|
|
232
|
+
});
|
|
233
|
+
touched += 1;
|
|
234
|
+
}
|
|
235
|
+
if (touched === 0)
|
|
236
|
+
return;
|
|
237
|
+
const all = [...byKey.values()];
|
|
238
|
+
const kept = all.length > MEMORY_ENTRY_LIMIT ? all.slice(all.length - MEMORY_ENTRY_KEEP) : all;
|
|
239
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
240
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
241
|
+
fs.writeFileSync(tmp, `${kept.map((entry) => JSON.stringify(entry)).join("\n")}\n`, { encoding: "utf8", mode: 0o600 });
|
|
242
|
+
fs.renameSync(tmp, file);
|
|
243
|
+
try {
|
|
244
|
+
fs.chmodSync(file, 0o600); // a file created before this hardening keeps its old mode otherwise
|
|
245
|
+
}
|
|
246
|
+
catch {
|
|
247
|
+
// best-effort tightening; the tmp+rename above is the real guard
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
catch (error) {
|
|
251
|
+
process.stderr.write(`pi-review: screen memory write failed (${error.message}); continuing\n`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
export function aggregateScreenMemory(entries) {
|
|
255
|
+
const files = new Set();
|
|
256
|
+
const hits = new Map();
|
|
257
|
+
const groups = new Map();
|
|
258
|
+
let unmatchedEntries = 0;
|
|
259
|
+
for (const entry of entries) {
|
|
260
|
+
files.add(entry.path);
|
|
261
|
+
for (const id of entry.patterns ?? []) {
|
|
262
|
+
hits.set(id, (hits.get(id) ?? 0) + 1);
|
|
263
|
+
}
|
|
264
|
+
if (!entry.unmatched)
|
|
265
|
+
continue;
|
|
266
|
+
unmatchedEntries += entry.seen ?? 1;
|
|
267
|
+
const key = `${entry.path}\u0000${entry.hunk}`;
|
|
268
|
+
const group = groups.get(key) ?? {
|
|
269
|
+
path: entry.path,
|
|
270
|
+
hunk: entry.hunk,
|
|
271
|
+
count: 0,
|
|
272
|
+
lastLines: [0, 0],
|
|
273
|
+
sample: "",
|
|
274
|
+
};
|
|
275
|
+
group.count += entry.seen ?? 1;
|
|
276
|
+
group.lastLines = entry.lines ?? [0, 0];
|
|
277
|
+
group.lastCatchAll = entry.catchAll;
|
|
278
|
+
group.sample = (entry.code ?? "").split("\n").map((l) => l.trim()).find((l) => l.length > 0)?.slice(0, 100) ?? "";
|
|
279
|
+
groups.set(key, group);
|
|
280
|
+
}
|
|
281
|
+
return {
|
|
282
|
+
entries: entries.length,
|
|
283
|
+
files: files.size,
|
|
284
|
+
unmatchedEntries,
|
|
285
|
+
patternHits: [...hits.entries()].map(([id, count]) => ({ id, count })).sort((a, b) => b.count - a.count),
|
|
286
|
+
unmatched: [...groups.values()].sort((a, b) => b.count - a.count),
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
export function formatScreenMemoryAscii(stats, meta) {
|
|
290
|
+
const lines = ["── pi-review screen memory " + "─".repeat(14)];
|
|
291
|
+
lines.push(` Log ${meta.file} · ${stats.entries} entr${stats.entries === 1 ? "y" : "ies"} across ${stats.files} file${stats.files === 1 ? "" : "s"}` +
|
|
292
|
+
(meta.catalog.recording ? "" : " (recording off: PI_REVIEW_SCREEN_MEMORY=0)"));
|
|
293
|
+
lines.push(` Catalog ${meta.catalog.builtin} builtin · ${meta.catalog.custom} custom` +
|
|
294
|
+
(meta.catalog.overrides > 0 ? ` (${meta.catalog.overrides} override${meta.catalog.overrides === 1 ? "s" : ""} builtin)` : "") +
|
|
295
|
+
` · ${meta.catalog.disabled} disabled`);
|
|
296
|
+
if (stats.patternHits.length > 0) {
|
|
297
|
+
lines.push(` Hits ${stats.patternHits.map((h) => `${h.id} ×${h.count}`).join(" ")}`);
|
|
298
|
+
}
|
|
299
|
+
if (stats.unmatched.length > 0) {
|
|
300
|
+
lines.push(` Unmatched ${stats.unmatchedEntries} signal${stats.unmatchedEntries === 1 ? "" : "s"} in ${stats.unmatched.length} hunk${stats.unmatched.length === 1 ? "" : "s"} — promotion candidates:`);
|
|
301
|
+
for (const group of stats.unmatched.slice(0, 10)) {
|
|
302
|
+
const p = group.lastCatchAll !== undefined ? ` p=${group.lastCatchAll.toFixed(2)}` : "";
|
|
303
|
+
lines.push(` ${group.path} ${group.hunk} lines ${group.lastLines[0]}-${group.lastLines[1]}${p} ×${group.count}`);
|
|
304
|
+
if (group.sample)
|
|
305
|
+
lines.push(` ${group.sample}`);
|
|
306
|
+
}
|
|
307
|
+
if (stats.unmatched.length > 10)
|
|
308
|
+
lines.push(` … ${stats.unmatched.length - 10} more`);
|
|
309
|
+
}
|
|
310
|
+
else if (stats.entries === 0) {
|
|
311
|
+
lines.push(" Unmatched none yet — run `pi-review screen` to accumulate signals");
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
lines.push(" Unmatched none — every flagged hunk matched the catalog");
|
|
315
|
+
}
|
|
316
|
+
lines.push(` Promote ${meta.patternsFile} (or PI_REVIEW_SCREEN_PATTERNS)`);
|
|
317
|
+
lines.push("─".repeat(39));
|
|
318
|
+
return lines.join("\n");
|
|
319
|
+
}
|
|
320
|
+
//# sourceMappingURL=screen-memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screen-memory.js","sourceRoot":"","sources":["../src/screen-memory.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,EAAE;AACF,0EAA0E;AAC1E,EAAE;AACF,2EAA2E;AAC3E,2EAA2E;AAC3E,6EAA6E;AAC7E,6EAA6E;AAC7E,sEAAsE;AACtE,EAAE;AACF,4EAA4E;AAC5E,6EAA6E;AAC7E,2EAA2E;AAC3E,2EAA2E;AAC3E,6EAA6E;AAC7E,+EAA+E;AAC/E,uCAAuC;AACvC,EAAE;AACF,+EAA+E;AAC/E,kEAAkE;AAElE,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAiC7C,iFAAiF;AACjF,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AACtC,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,CAAC;AACrC,8DAA8D;AAC9D,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC;AAElC,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;AACjE,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC,CAAC;AAC1F,MAAM,aAAa,GAAG,wBAAwB,CAAC;AAE/C,+EAA+E;AAC/E,SAAS,QAAQ,CAAC,GAAsB;IACtC,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,sBAAsB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACzE,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,sBAAsB,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACvE,MAAM,QAAQ,GAAG,GAAG,CAAC,4BAA4B,EAAE,IAAI,EAAE,CAAC;IAC1D,IAAI,QAAQ;QAAE,OAAO,eAAe,CAAC,QAAQ,CAAE,CAAC;IAChD,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,qBAAqB,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACtE,MAAM,GAAG,GAAG,GAAG,CAAC,uBAAuB,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC9D,OAAO,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,KAAK,CAAC;AACzD,CAAC;AAQD;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAY,EAAE,MAAc;IAClE,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,QAAQ,EAAE,EAAE;YACZ,QAAQ,EAAE,EAAE;YACZ,QAAQ,EAAE,CAAC,GAAG,MAAM,uBAAwB,KAAe,CAAC,OAAO,yBAAyB,CAAC;SAC9F,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAClE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,GAAG,MAAM,mDAAmD,CAAC,EAAE,CAAC;IAClH,CAAC;IACD,MAAM,MAAM,GAAG,GAA8B,CAAC;IAC9C,MAAM,QAAQ,GAAkC,EAAE,CAAC;IACnD,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;QAC9D,IAAI,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1E,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,6CAA6C,CAAC,CAAC;QACxE,CAAC;aAAM,CAAC;YACN,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,QAAmC,CAAC,EAAE,CAAC;gBACrF,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;oBAC5B,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,iBAAiB,EAAE,gBAAgB,aAAa,eAAe,CAAC,CAAC;oBACxF,SAAS;gBACX,CAAC;gBACD,MAAM,KAAK,GAAG,KAAgC,CAAC;gBAC/C,MAAM,QAAQ,GAAa,EAAE,CAAC;gBAC9B,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;oBAAE,QAAQ,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;qBAC7G,CAAC;oBACJ,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE;wBAAE,QAAQ,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;oBAC9G,IAAI,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC;wBAC7E,QAAQ,CAAC,IAAI,CAAC,2BAA2B,CAAC,GAAG,gBAAgB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;oBAC9E,IAAI,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC;wBAC7E,QAAQ,CAAC,IAAI,CAAC,2BAA2B,CAAC,GAAG,gBAAgB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;oBAC9E,IAAI,OAAO,KAAK,CAAC,cAAc,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,EAAE;wBAC1E,QAAQ,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;gBAC/D,CAAC;gBACD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACxB,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,cAAc,EAAE,cAAc,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;oBAC1F,SAAS;gBACX,CAAC;gBACD,QAAQ,CAAC,EAAE,CAAC,GAAG;oBACb,KAAK,EAAG,KAAK,CAAC,KAAgB,CAAC,IAAI,EAAE;oBACrC,QAAQ,EAAE,KAAK,CAAC,QAAkB;oBAClC,QAAQ,EAAE,KAAK,CAAC,QAAqC;oBACrD,cAAc,EAAG,KAAK,CAAC,cAAyB,CAAC,IAAI,EAAE;iBACxD,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IACD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;QAC9D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YACpC,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,2DAA2D,CAAC,CAAC;QACtF,CAAC;aAAM,CAAC;YACN,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;gBACpC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE;oBAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;;oBACtE,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,+DAA+D,CAAC,CAAC;YAC/F,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AAC1C,CAAC;AAOD;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACnE,MAAM,KAAK,GAAG,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,GAAG,CAAC,yBAAyB,EAAE,IAAI,EAAE,CAAC;IACpD,IAAI,KAAK;QAAE,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,KAAK,CAAE,CAAC,CAAC;IAE/C,MAAM,MAAM,GAAqB,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IACzF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAS;QACnC,IAAI,IAA4B,CAAC;QACjC,IAAI,CAAC;YACH,IAAI,GAAG,uBAAuB,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC;QACtE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,eAAe,IAAI,KAAM,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;YACzE,SAAS;QACX,CAAC;QACD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC9C,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;IACzC,CAAC;IACD,MAAM,CAAC,QAAQ,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;IAChD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,OAAO,GAAwB,EAAE,CAAC;IACxC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE,SAAS;QAC3B,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAsB,CAAC;YACpD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC3G,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,0DAA0D;QAC5D,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAA4B,EAAE,MAAyB,OAAO,CAAC,GAAG;IACnG,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC;QAAE,OAAO;IAC9D,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;QACvC,MAAM,QAAQ,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACxC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3F,MAAM,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACpC,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACzE,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,IAAI,SAAS,IAAI,CAAC,IAAI,SAAS,IAAI,EAAE,CAAC;YAC1D,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,aAAa,CAAC,GAAG,CAAC;YACxG,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC5B,IAAI,IAAI,EAAE,CAAC;gBACT,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;gBACb,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;gBAC5C,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;gBAC9B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC;gBAC5C,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS;oBAAE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;gBAC/D,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;gBACjC,OAAO,IAAI,CAAC,CAAC;gBACb,SAAS;YACX,CAAC;YACD,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;gBACb,EAAE;gBACF,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,KAAK,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC;gBACrC,GAAG,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnE,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC;gBACrC,IAAI;gBACJ,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,CAAC;aACR,CAAC,CAAC;YACH,OAAO,IAAI,CAAC,CAAC;QACf,CAAC;QACD,IAAI,OAAO,KAAK,CAAC;YAAE,OAAO;QAC1B,MAAM,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QAChC,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,GAAG,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QAC/F,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,MAAM,GAAG,GAAG,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC;QACzC,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACvH,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACzB,IAAI,CAAC;YACH,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,oEAAoE;QACjG,CAAC;QAAC,MAAM,CAAC;YACP,iEAAiE;QACnE,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0CAA2C,KAAe,CAAC,OAAO,iBAAiB,CAAC,CAAC;IAC5G,CAAC;AACH,CAAC;AAuBD,MAAM,UAAU,qBAAqB,CAAC,OAA4B;IAChE,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IACvC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAgC,CAAC;IACvD,IAAI,gBAAgB,GAAG,CAAC,CAAC;IACzB,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACtB,KAAK,MAAM,EAAE,IAAI,KAAK,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;YACtC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACxC,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,SAAS;YAAE,SAAS;QAC/B,gBAAgB,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC;QACpC,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC,IAAI,SAAS,KAAK,CAAC,IAAI,EAAE,CAAC;QAC/C,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI;YAC/B,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,KAAK,EAAE,CAAC;YACR,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;YACjB,MAAM,EAAE,EAAE;SACX,CAAC;QACF,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC;QAC/B,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACxC,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC,QAAQ,CAAC;QACpC,KAAK,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;QAClH,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACzB,CAAC;IACD,OAAO;QACL,OAAO,EAAE,OAAO,CAAC,MAAM;QACvB,KAAK,EAAE,KAAK,CAAC,IAAI;QACjB,gBAAgB;QAChB,WAAW,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;QACxG,SAAS,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;KAClE,CAAC;AACJ,CAAC;AASD,MAAM,UAAU,uBAAuB,CAAC,KAAwB,EAAE,IAAsB;IACtF,MAAM,KAAK,GAAG,CAAC,6BAA6B,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/D,KAAK,CAAC,IAAI,CACR,gBAAgB,IAAI,CAAC,IAAI,MAAM,KAAK,CAAC,OAAO,QAAQ,KAAK,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,WAAW,KAAK,CAAC,KAAK,QAAQ,KAAK,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE;QAC/I,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,6CAA6C,CAAC,CAChF,CAAC;IACF,KAAK,CAAC,IAAI,CACR,gBAAgB,IAAI,CAAC,OAAO,CAAC,OAAO,cAAc,IAAI,CAAC,OAAO,CAAC,MAAM,SAAS;QAC5E,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,SAAS,YAAY,IAAI,CAAC,OAAO,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7H,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,WAAW,CACzC,CAAC;IACF,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,gBAAgB,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/F,CAAC;IACD,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,KAAK,CAAC,IAAI,CAAC,gBAAgB,KAAK,CAAC,gBAAgB,UAAU,KAAK,CAAC,gBAAgB,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,OAAO,KAAK,CAAC,SAAS,CAAC,MAAM,QAAQ,KAAK,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,0BAA0B,CAAC,CAAC;QAC1M,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;YACjD,MAAM,CAAC,GAAG,KAAK,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzF,KAAK,CAAC,IAAI,CAAC,OAAO,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,WAAW,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;YACvH,IAAI,KAAK,CAAC,MAAM;gBAAE,KAAK,CAAC,IAAI,CAAC,SAAS,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QACxD,CAAC;QACD,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,EAAE;YAAE,KAAK,CAAC,IAAI,CAAC,SAAS,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,EAAE,OAAO,CAAC,CAAC;IAC3F,CAAC;SAAM,IAAI,KAAK,CAAC,OAAO,KAAK,CAAC,EAAE,CAAC;QAC/B,KAAK,CAAC,IAAI,CAAC,sEAAsE,CAAC,CAAC;IACrF,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,4DAA4D,CAAC,CAAC;IAC3E,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,gBAAgB,IAAI,CAAC,YAAY,iCAAiC,CAAC,CAAC;IAC/E,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3B,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screen-memory.test.d.ts","sourceRoot":"","sources":["../src/screen-memory.test.ts"],"names":[],"mappings":""}
|