mirror of
https://github.com/lukaszraczylo/claude-adam.git
synced 2026-07-06 03:37:48 +00:00
chore(v0.3.3): analyst observability, A/B measurement, journal hygiene
Storage/window/exclusion split (#7): ISO-week journal rotation with safety fuse replaces size-based rotation (fixes silent under-counting when clusters straddle boundaries). Per-signal sliding windows via adam-window.mjs guard against stale signal accumulation. Legacy YYYY-MM-DD-<ts>.jsonl files remain readable. Error fingerprint normalization (#3): adam-observe.mjs extracts canonical error codes (ENOENT, ECONNREFUSED, etc.) and normalizes paths/timestamps/hex before hashing. 'Connection refused' and 'ECONNREFUSED' now cluster identically. Correction corpus expansion (#1): strong tokens (stop, wrong, undo, try again, different approach, etc.) fire on any occurrence. Weak tokens (no, actually, wait) require negation/contrast co-occurrence within 8 tokens. Kills the 'actually, I think...' false positive. Analyst observability (#6): mandatory clustering trace block; adam-explain.mjs parses to summary/full/json. Cluster decisions now surface rejection reasons (threshold, contradiction, window). Persisted to ~/.claude/adam/last-trace.txt. Dead_end nudge proposal type (#2): single-session auto-apply gate (>=3 dead_end events). Action appends to active-nudges.json, surfaced via adam-nudge.mjs at next SessionStart. Lower blast than skill_edit. Per-(skill, fingerprint) cooldown (#4): adam-cooldown.mjs replaces coarse per-skill check. proposal_fingerprint = djb2(skill_slug + cluster_id + normalized_diff_body). Legacy applied/rejected records gate via 'legacy' fingerprint fallback through resolveSkill helper (handles target_skill, skill, or target: <path>). task_completed scoring integration (#8): adam-score.mjs computes per-session urgency dampener (3 task_completed -> 0.5) and reinforcement candidates (skills cited in >=3 clean completions). New 'reinforcement' proposal type appends to reinforcements.jsonl on apply (no code/memory mutation). A/B effectiveness measurement (#5): every auto-applied edit appends to ab-tracking.jsonl. adam-ab-measure.mjs computes 7d pre/post signal-count delta per entry (improved / neutral / regressed / no_baseline / pending). Analyst surfaces regressions at top of /reflect output. Upgrade UX overhaul (#9): adam-upgrade.mjs implements --list/--diff/--accept /--accept-all. SessionStart nudge prints pending-merge warning when .adam-new files exist (latency ~20ms via fixed shortlist). install.sh emits unmissable final-message hint after creating any .adam-new file. Simplify pass: adam-utils.mjs deduplicates readJsonlSafe / listJsonlFiles / parseFrontmatter across 8 scripts. Net -46 LOC. Test coverage: 30 -> 87 tests. Every new feature has feature-validating assertions (false-case coverage included). T77 statically verifies install.sh references every adam-*.mjs source script (would have caught the missing adam-utils inclusion that review #2 surfaced).
This commit is contained in:
@@ -8,49 +8,12 @@
|
||||
import { readFileSync, writeFileSync, appendFileSync, mkdirSync, existsSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { homedir } from "node:os";
|
||||
import { parseFrontmatter } from "./adam-utils.mjs";
|
||||
|
||||
const ROOT = join(homedir(), ".claude", "adam");
|
||||
const JOURNAL = join(ROOT, "journal.jsonl");
|
||||
const JOURNAL_DIR = join(ROOT, "journal");
|
||||
|
||||
function parseFrontmatter(content) {
|
||||
const m = content.match(/^---\n([\s\S]*?)\n---/);
|
||||
if (!m) return {};
|
||||
const fm = {};
|
||||
const lines = m[1].split("\n");
|
||||
let i = 0;
|
||||
while (i < lines.length) {
|
||||
const line = lines[i];
|
||||
const idx = line.indexOf(":");
|
||||
if (idx === -1) { i++; continue; }
|
||||
const key = line.slice(0, idx).trim();
|
||||
const value = line.slice(idx + 1).trim();
|
||||
if (key === "source_entries") {
|
||||
const arr = [];
|
||||
if (value.startsWith("[") && value.endsWith("]")) {
|
||||
const inner = value.slice(1, -1)
|
||||
.split(",")
|
||||
.map(s => s.trim().replace(/^['"]|['"]$/g, ""));
|
||||
arr.push(...inner.filter(Boolean));
|
||||
fm[key] = arr;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
while (i < lines.length && /^\s*-\s+/.test(lines[i])) {
|
||||
const item = lines[i].replace(/^\s*-\s+/, "").trim().replace(/^['"]|['"]$/g, "");
|
||||
if (item) arr.push(item);
|
||||
i++;
|
||||
}
|
||||
fm[key] = arr;
|
||||
continue;
|
||||
}
|
||||
fm[key] = value;
|
||||
i++;
|
||||
}
|
||||
return fm;
|
||||
}
|
||||
|
||||
function main() {
|
||||
const proposalPath = process.argv[2];
|
||||
if (!proposalPath) {
|
||||
|
||||
Reference in New Issue
Block a user