mirror of
https://github.com/sdwolf4103/opencode-working-memory.git
synced 2026-07-17 12:56:42 +02:00
fix: unify workspace memory quality gate
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
import type { LongTermMemoryEntry, LongTermSource } from "./types.ts";
|
||||
|
||||
export type MemoryQualityInput = Pick<LongTermMemoryEntry, "type" | "text"> & {
|
||||
source?: LongTermSource;
|
||||
};
|
||||
|
||||
export type MemoryQualityResult = {
|
||||
accepted: boolean;
|
||||
reasons: string[];
|
||||
};
|
||||
|
||||
export function assessMemoryQuality(entry: MemoryQualityInput): MemoryQualityResult {
|
||||
const reasons: string[] = [];
|
||||
const text = entry.text.trim();
|
||||
|
||||
if (text.length === 0) reasons.push("empty");
|
||||
if (isProgressSnapshotViolation(text)) reasons.push("progress_snapshot");
|
||||
if (isRawErrorViolation(text)) reasons.push("raw_error");
|
||||
if (isCommitOrCiViolation(text)) reasons.push("commit_or_ci_snapshot");
|
||||
if (isPathHeavyViolation(text)) reasons.push("path_heavy");
|
||||
if (isTemporaryStatusViolation(text)) reasons.push("temporary_status");
|
||||
if (entry.type === "feedback" && isFeedbackQualityViolation(text)) reasons.push("bad_feedback");
|
||||
if (entry.type === "decision" && isDecisionQualityViolation(text)) reasons.push("bad_decision");
|
||||
|
||||
return { accepted: reasons.length === 0, reasons };
|
||||
}
|
||||
|
||||
export function isProgressSnapshotViolation(text: string): boolean {
|
||||
if (/\d+\s+tests?\s+pass(?:ed)?/i.test(text)) return true;
|
||||
if (/\d+\s+suites?\s+(?:pass|fail)/i.test(text)) return true;
|
||||
|
||||
if (/\d+\s*(?:個|个)?\s*(?:files?|文件)/i.test(text)) {
|
||||
const hasSnapshotContext = /同步|synced|uploaded|downloaded|completed|generated|created|modified|processed|完成/i.test(text);
|
||||
const hasLimitContext = /limit|max|maximum|min|minimum|supports?|allowed|per\s+(?:batch|request|upload)/i.test(text);
|
||||
if (hasSnapshotContext && !hasLimitContext) return true;
|
||||
}
|
||||
|
||||
if (/\b(?:completed|done|finished|implemented|added|updated|fixed|reviewed|passed|modified)\b/i.test(text)) {
|
||||
if (/\b(?:wave|phase|task|plan|pr|commit|ci|test|suite|implementation|session|change|fix|review|file)\b/i.test(text)) return true;
|
||||
}
|
||||
if (/(?:已完成|完成|修復|实现|實作).{0,40}(?:wave|phase|task|plan|PR|測試|测试|實作|实现|修復)/iu.test(text)) return true;
|
||||
if (/(?:phases?|waves?|sprints?|milestones?|tasks?)\s*\d+(?:\s*[-–]\s*\d+)?/i.test(text)) {
|
||||
if (/completed|done|finished|完成|已完成/i.test(text)) return true;
|
||||
}
|
||||
if (/(?:已完成|完成).{0,30}(?:phases?|waves?|sprints?|milestones?|tasks?)/i.test(text)) return true;
|
||||
if (/\b(?:currently|right now|latest change|previous session|last wave|next step)\b/i.test(text)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isFeedbackQualityViolation(text: string): boolean {
|
||||
const stablePreference = /\b(?:user|the user)\s+(?:prefers|wants|asked|expects|requires|likes|dislikes)\b/i.test(text)
|
||||
|| /\b(?:prefer|preference|going forward|from now on|always|never)\b/i.test(text)
|
||||
|| /(?:使用者|用戶|用户).{0,12}(?:偏好|希望|要求|想要)/u.test(text)
|
||||
|| /(?:以後|以后|請|请).{0,20}(?:使用|回答|保持|避免)/u.test(text);
|
||||
|
||||
if (stablePreference) return false;
|
||||
|
||||
const internalNote = /\b(?:implemented|updated|fixed|reviewed|added|changed|modified|created|writes|wrote)\b/i.test(text);
|
||||
if (internalNote) return true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function isDecisionQualityViolation(text: string): boolean {
|
||||
const futureRule = /\b(?:use|keep|prefer|avoid|do not|don't|must|should|never|always|require|choose|reject)\b/i.test(text)
|
||||
|| /(?:使用|保持|避免|不要|必須|必须|應該|应该|選擇|选择)/u.test(text);
|
||||
if (!futureRule) return true;
|
||||
if (/\b(?:implemented|added|updated|fixed|completed|reviewed)\b/i.test(text)) return true;
|
||||
if (/\b(?:was|were|has been|had been)\b/i.test(text) && /\b(?:previous|last|latest|this session|this wave|already)\b/i.test(text)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function isRawErrorViolation(text: string): boolean {
|
||||
if (/^\s*(Error|TypeError|ReferenceError|SyntaxError|Exception):/i.test(text)) return true;
|
||||
if (/at \S+ \([^)]+:\d+:\d+\)/.test(text)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function isCommitOrCiViolation(text: string): boolean {
|
||||
if (/\b[0-9a-f]{7,40}\b/.test(text)) return true;
|
||||
if (/\bCI\b.*\b(?:passed|failed|run|compatibility|flaky)\b/i.test(text)) return true;
|
||||
if (/\b(?:passed|failed|run|compatibility|flaky)\b.*\bCI\b/i.test(text)) return true;
|
||||
if (/\bcompatibility\s+run\s+\d+/i.test(text)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function isPathHeavyViolation(text: string): boolean {
|
||||
const pathCount = (text.match(/\/[\w.-]+(?:\/[\w.-]+)+/g) || []).length;
|
||||
return pathCount > 2;
|
||||
}
|
||||
|
||||
function isTemporaryStatusViolation(text: string): boolean {
|
||||
if (/^(currently|now|pending|in progress|todo|wip)\b/i.test(text)) return true;
|
||||
if (/\b(?:run npm test|tests? are running|next reply|before continuing)\b/i.test(text)) return true;
|
||||
return false;
|
||||
}
|
||||
Reference in New Issue
Block a user