smart-claude-memory-mcp 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +38 -0
- package/CHANGELOG.md +52 -0
- package/LICENSE +21 -0
- package/README.md +790 -0
- package/dist/chunker.js +33 -0
- package/dist/chunker.js.map +1 -0
- package/dist/config.js +23 -0
- package/dist/config.js.map +1 -0
- package/dist/curriculum/daemon.js +190 -0
- package/dist/curriculum/daemon.js.map +1 -0
- package/dist/curriculum/scanner.js +237 -0
- package/dist/curriculum/scanner.js.map +1 -0
- package/dist/index.js +429 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/migrations.js +128 -0
- package/dist/lib/migrations.js.map +1 -0
- package/dist/ollama.js +59 -0
- package/dist/ollama.js.map +1 -0
- package/dist/project-detect.js +102 -0
- package/dist/project-detect.js.map +1 -0
- package/dist/project.js +26 -0
- package/dist/project.js.map +1 -0
- package/dist/sleep/daemon.js +215 -0
- package/dist/sleep/daemon.js.map +1 -0
- package/dist/sleep/miner.js +285 -0
- package/dist/sleep/miner.js.map +1 -0
- package/dist/supabase.js +405 -0
- package/dist/supabase.js.map +1 -0
- package/dist/telemetry/emit.js +19 -0
- package/dist/telemetry/emit.js.map +1 -0
- package/dist/telemetry/pruner.js +141 -0
- package/dist/telemetry/pruner.js.map +1 -0
- package/dist/telemetry/types.js +2 -0
- package/dist/telemetry/types.js.map +1 -0
- package/dist/tools/backlog.js +599 -0
- package/dist/tools/backlog.js.map +1 -0
- package/dist/tools/batch-freeze-patterns.js +243 -0
- package/dist/tools/batch-freeze-patterns.js.map +1 -0
- package/dist/tools/bloat-audit.js +101 -0
- package/dist/tools/bloat-audit.js.map +1 -0
- package/dist/tools/checkpoint.js +259 -0
- package/dist/tools/checkpoint.js.map +1 -0
- package/dist/tools/compact.js +60 -0
- package/dist/tools/compact.js.map +1 -0
- package/dist/tools/conflict.js +102 -0
- package/dist/tools/conflict.js.map +1 -0
- package/dist/tools/curriculum.js +225 -0
- package/dist/tools/curriculum.js.map +1 -0
- package/dist/tools/frozen-cache.js +106 -0
- package/dist/tools/frozen-cache.js.map +1 -0
- package/dist/tools/health.js +368 -0
- package/dist/tools/health.js.map +1 -0
- package/dist/tools/hygiene.js +309 -0
- package/dist/tools/hygiene.js.map +1 -0
- package/dist/tools/image.js +107 -0
- package/dist/tools/image.js.map +1 -0
- package/dist/tools/list-global-patterns.js +101 -0
- package/dist/tools/list-global-patterns.js.map +1 -0
- package/dist/tools/orchestrator.js +113 -0
- package/dist/tools/orchestrator.js.map +1 -0
- package/dist/tools/policy.js +90 -0
- package/dist/tools/policy.js.map +1 -0
- package/dist/tools/refactor.js +220 -0
- package/dist/tools/refactor.js.map +1 -0
- package/dist/tools/save.js +42 -0
- package/dist/tools/save.js.map +1 -0
- package/dist/tools/search.js +189 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/setup.js +868 -0
- package/dist/tools/setup.js.map +1 -0
- package/dist/tools/shared-schemas.js +24 -0
- package/dist/tools/shared-schemas.js.map +1 -0
- package/dist/tools/skills.js +174 -0
- package/dist/tools/skills.js.map +1 -0
- package/dist/tools/sleep.js +239 -0
- package/dist/tools/sleep.js.map +1 -0
- package/dist/tools/sovereign-constitution.js +319 -0
- package/dist/tools/sovereign-constitution.js.map +1 -0
- package/dist/tools/summarize.js +55 -0
- package/dist/tools/summarize.js.map +1 -0
- package/dist/tools/sync.js +255 -0
- package/dist/tools/sync.js.map +1 -0
- package/dist/tools/system_dashboard.js +181 -0
- package/dist/tools/system_dashboard.js.map +1 -0
- package/dist/tools/update-rule.js +15 -0
- package/dist/tools/update-rule.js.map +1 -0
- package/dist/tools/verification.js +333 -0
- package/dist/tools/verification.js.map +1 -0
- package/dist/trajectory/daemon.js +270 -0
- package/dist/trajectory/daemon.js.map +1 -0
- package/dist/trajectory/stripper.js +124 -0
- package/dist/trajectory/stripper.js.map +1 -0
- package/dist/trajectory/summarizer.js +77 -0
- package/dist/trajectory/summarizer.js.map +1 -0
- package/dist/transactions/checkpoint.js +272 -0
- package/dist/transactions/checkpoint.js.map +1 -0
- package/dist/verification-gate.js +43 -0
- package/dist/verification-gate.js.map +1 -0
- package/dist/version.js +16 -0
- package/dist/version.js.map +1 -0
- package/hooks/README.md +54 -0
- package/hooks/md-policy.py +497 -0
- package/marketplace.json +13 -0
- package/package.json +66 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { currentProjectId } from "../project.js";
|
|
3
|
+
import { updateLocalReadme, updateProjectArchitecture } from "./backlog.js";
|
|
4
|
+
import { VERSION } from "../version.js";
|
|
5
|
+
function buildWorkerPrompt(args) {
|
|
6
|
+
const runGate = args.run_gate !== false; // default true
|
|
7
|
+
const allowRollback = args.allow_rollback !== false;
|
|
8
|
+
const selfHeal = args.self_heal !== false; // default true in v1.1.0
|
|
9
|
+
const maxAttempts = Math.max(1, Math.min(args.max_healing_attempts ?? 3, 5));
|
|
10
|
+
const synthLimit = args.synthesis_word_limit ?? 220;
|
|
11
|
+
const workspace = args.workspace ? resolve(args.workspace) : process.cwd();
|
|
12
|
+
const workspaceForPrompt = workspace.replace(/\\/g, "/");
|
|
13
|
+
const targetFiles = args.target_files ?? [];
|
|
14
|
+
const steps = [
|
|
15
|
+
"## Mandate",
|
|
16
|
+
`You are a worker sub-agent spawned by the Orchestrator (main Claude session). Your context is yours alone — the main session has asked you to handle this task end-to-end so its context stays clean. Resolve compile failures locally; do NOT bounce red gates back to the Orchestrator.`,
|
|
17
|
+
"",
|
|
18
|
+
"## Task",
|
|
19
|
+
args.title.trim(),
|
|
20
|
+
"",
|
|
21
|
+
"## Instructions",
|
|
22
|
+
args.instructions.trim(),
|
|
23
|
+
"",
|
|
24
|
+
];
|
|
25
|
+
if (targetFiles.length > 0) {
|
|
26
|
+
steps.push("## Target files");
|
|
27
|
+
for (const f of targetFiles)
|
|
28
|
+
steps.push(`- ${f}`);
|
|
29
|
+
steps.push("");
|
|
30
|
+
}
|
|
31
|
+
steps.push("## Required workflow");
|
|
32
|
+
steps.push("1. Perform the edits/research/commands as instructed. Track the absolute path of every file you touched — you will need this list for steps 3 and 4.");
|
|
33
|
+
if (runGate) {
|
|
34
|
+
steps.push(`2. Immediately after the work is done, call \`refactor_guard({ action: "gate", workspace: "${workspaceForPrompt}" })\` to run the compiler/analyzer for this stack.`);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
steps.push("2. (Gate skipped — Orchestrator requested no compile check.)");
|
|
38
|
+
}
|
|
39
|
+
if (runGate && selfHeal) {
|
|
40
|
+
steps.push("");
|
|
41
|
+
steps.push(`### 3. Autonomous Self-Healing Loop (max ${maxAttempts} attempt${maxAttempts === 1 ? "" : "s"})`);
|
|
42
|
+
steps.push("If the gate in step 2 **fails**, you MUST NOT report failure yet. Execute the healing loop below. The goal is to diagnose the regression against the last known-good snapshot and fix it locally before escalating.");
|
|
43
|
+
steps.push("");
|
|
44
|
+
steps.push("For each attempt (up to the cap above):");
|
|
45
|
+
steps.push(" a. For EACH file you edited in step 1, call `analyze_regression({ file: <abs-path>, backups_to_compare: 3 })`. The response contains `comparisons[]` (diff vs each recent backup) and `closest_prior` (the backup with the smallest edit distance — the most likely stable baseline).");
|
|
46
|
+
steps.push(" b. Read the broken file and the `closest_prior` backup side-by-side. Use the `diff.sample_changes` entries (+ added / - removed lines) plus the compiler error from step 2 to localize the defect. Typical causes: dropped import, renamed symbol, mismatched signature, stale type, missing null-check that the prior version had.");
|
|
47
|
+
steps.push(" c. Apply a **minimal local fix** — re-add the missing piece, reconcile the signature, etc. Do NOT wholesale-restore from the backup (that would erase the feature work). Preserve the intent of the original edit.");
|
|
48
|
+
steps.push(` d. Re-run \`refactor_guard({ action: "gate", workspace: "${workspaceForPrompt}" })\`. If it passes, exit the loop and proceed to step 5.`);
|
|
49
|
+
steps.push(" e. If it still fails, record the attempt (error signature + what you tried) and loop back to (a) with the new compiler output. Do not repeat a fix that already failed — change hypothesis.");
|
|
50
|
+
steps.push("");
|
|
51
|
+
steps.push(`If all ${maxAttempts} healing attempt${maxAttempts === 1 ? "" : "s"} fail, proceed to step 4 (rollback). The fact that healing was attempted — and which hypotheses you tested — MUST appear in paragraph 2 of the synthesis.`);
|
|
52
|
+
}
|
|
53
|
+
else if (runGate) {
|
|
54
|
+
steps.push("3. (Self-healing disabled for this delegation — proceed straight to rollback on gate failure.)");
|
|
55
|
+
}
|
|
56
|
+
if (allowRollback) {
|
|
57
|
+
const prefix = runGate && selfHeal ? "4." : "3.";
|
|
58
|
+
steps.push("");
|
|
59
|
+
steps.push(`${prefix} **Rollback (last resort).** Only if the gate is still red after the self-healing loop: for every file you edited, call \`refactor_guard({ action: "rollback", file: <abs-path> })\` to restore the pre-edit backup. Record the rollback in the synthesis together with the specific compiler error healing could not resolve.`);
|
|
60
|
+
}
|
|
61
|
+
const synthStep = runGate && selfHeal ? "5." : allowRollback ? "4." : "3.";
|
|
62
|
+
steps.push("");
|
|
63
|
+
steps.push(`${synthStep} Return ONLY a 2-paragraph synthesis (≤ ${synthLimit} words total). Paragraph 1: what changed, why, and which files. Paragraph 2: gate result (pass on first try / passed after N healing attempts / rolled back), key healing hypotheses you tested, remaining risks or follow-ups.`);
|
|
64
|
+
steps.push("");
|
|
65
|
+
steps.push("## Hard constraints");
|
|
66
|
+
steps.push("- DO NOT paste raw file contents, long log excerpts, or full stack traces into the synthesis. Summarize each compiler error as ≤ 1 sentence (error code + what symbol/line it points at).");
|
|
67
|
+
steps.push("- Keep the synthesis under the word limit. The Orchestrator will reject output that leaks raw context back into the main session.");
|
|
68
|
+
steps.push("- Self-healing is strictly LOCAL. Never ask the Orchestrator for more context to fix a compile error while healing attempts remain — the backups and compiler output are sufficient.");
|
|
69
|
+
steps.push("- If the task is ambiguous or the gate failure reflects a genuinely missing requirement (not a regression you introduced), say so in the synthesis with a specific next question for the Orchestrator — do not invent requirements.");
|
|
70
|
+
return steps.join("\n");
|
|
71
|
+
}
|
|
72
|
+
export async function delegateTask(args) {
|
|
73
|
+
if (!args.title || !args.title.trim()) {
|
|
74
|
+
throw new Error("delegate_task requires a non-empty 'title'.");
|
|
75
|
+
}
|
|
76
|
+
if (!args.instructions || !args.instructions.trim()) {
|
|
77
|
+
throw new Error("delegate_task requires non-empty 'instructions'.");
|
|
78
|
+
}
|
|
79
|
+
const prompt = buildWorkerPrompt(args);
|
|
80
|
+
const description = args.title.length <= 40 ? args.title : args.title.slice(0, 37) + "...";
|
|
81
|
+
const runGate = args.run_gate !== false;
|
|
82
|
+
const selfHeal = args.self_heal !== false;
|
|
83
|
+
const maxHealingAttempts = Math.max(1, Math.min(args.max_healing_attempts ?? 3, 5));
|
|
84
|
+
return {
|
|
85
|
+
action: "delegate_task",
|
|
86
|
+
version: VERSION,
|
|
87
|
+
title: args.title,
|
|
88
|
+
description_for_agent_tool: description,
|
|
89
|
+
workspace: args.workspace ? resolve(args.workspace) : process.cwd(),
|
|
90
|
+
run_gate: runGate,
|
|
91
|
+
self_heal: runGate && selfHeal,
|
|
92
|
+
max_healing_attempts: runGate && selfHeal ? maxHealingAttempts : 0,
|
|
93
|
+
allow_rollback: args.allow_rollback !== false,
|
|
94
|
+
synthesis_word_limit: args.synthesis_word_limit ?? 220,
|
|
95
|
+
prompt,
|
|
96
|
+
usage_hint: "Copy the 'prompt' field into the Agent tool call as the 'prompt' parameter. Use subagent_type: 'general-purpose' unless a specialized agent fits better. The worker will self-heal compile failures locally (analyze_regression → minimal fix → re-gate, up to max_healing_attempts) before falling back to rollback. After the sub-agent returns its synthesis, call sync_artefacts to refresh README + project_file_architecture.md.",
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
export async function syncArtefacts(args = {}) {
|
|
100
|
+
const projectId = args.project_id ?? currentProjectId;
|
|
101
|
+
const [readmeSync, architectureSync] = await Promise.all([
|
|
102
|
+
updateLocalReadme(projectId),
|
|
103
|
+
updateProjectArchitecture(projectId),
|
|
104
|
+
]);
|
|
105
|
+
return {
|
|
106
|
+
action: "sync_artefacts",
|
|
107
|
+
project_id: projectId,
|
|
108
|
+
readme_sync: readmeSync,
|
|
109
|
+
architecture_sync: architectureSync,
|
|
110
|
+
note: "Orchestrator doc-only sync (subset of session_end). Call this after a worker sub-agent reports success; call manage_backlog({action:'session_end'}) at the actual end of the session to also archive done tasks and emit the resume prompt.",
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=orchestrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/tools/orchestrator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { addFrozenPattern, removeFrozenPattern, writeFrozenPatternsCache, } from "../supabase.js";
|
|
2
|
+
import { currentProjectId, slugify } from "../project.js";
|
|
3
|
+
import { loadFrozenCache, writeFrozenCache, } from "./frozen-cache.js";
|
|
4
|
+
/**
|
|
5
|
+
* v1.1.3: read frozen patterns from the on-disk cache so the response shape
|
|
6
|
+
* matches the persisted schema ({ pattern, source, added_at }). The cache is
|
|
7
|
+
* the source of truth for provenance — Supabase only stores `pattern` and
|
|
8
|
+
* `reason`. The hook keys cache lookups by slugified workspace basename, so
|
|
9
|
+
* we mirror that here.
|
|
10
|
+
*/
|
|
11
|
+
export async function listFrozen(args = {}) {
|
|
12
|
+
const projectId = args.project_id ?? currentProjectId;
|
|
13
|
+
const cache = await loadFrozenCache();
|
|
14
|
+
const key = slugify(projectId);
|
|
15
|
+
const patterns = cache.projects[key] ?? [];
|
|
16
|
+
return {
|
|
17
|
+
action: "list_frozen",
|
|
18
|
+
project_id: projectId,
|
|
19
|
+
count: patterns.length,
|
|
20
|
+
patterns,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Stage a `{ pattern, source, added_at }` entry into the cache *before* we
|
|
25
|
+
* call writeFrozenPatternsCache, so the cache merger keeps our provenance
|
|
26
|
+
* instead of defaulting to source="supabase". Returns the freshly written
|
|
27
|
+
* entry. First-writer-wins: existing entries with the same pattern are kept.
|
|
28
|
+
*/
|
|
29
|
+
async function stageEntry(projectId, pattern, source) {
|
|
30
|
+
const key = slugify(projectId);
|
|
31
|
+
const cache = await loadFrozenCache();
|
|
32
|
+
const bucket = (cache.projects[key] ??= []);
|
|
33
|
+
const existing = bucket.find((e) => e.pattern === pattern);
|
|
34
|
+
if (existing)
|
|
35
|
+
return existing;
|
|
36
|
+
const entry = { pattern, source, added_at: Date.now() };
|
|
37
|
+
bucket.push(entry);
|
|
38
|
+
await writeFrozenCache(cache);
|
|
39
|
+
return entry;
|
|
40
|
+
}
|
|
41
|
+
export async function freezeFile(args) {
|
|
42
|
+
const projectId = args.project_id ?? currentProjectId;
|
|
43
|
+
await addFrozenPattern(projectId, args.pattern, args.reason);
|
|
44
|
+
// Stage provenance first, then resync from Supabase. The merger preserves
|
|
45
|
+
// our staged source/added_at because the entry is now "already on disk".
|
|
46
|
+
const entry = await stageEntry(projectId, args.pattern, "freeze_file");
|
|
47
|
+
const cache = await writeFrozenPatternsCache();
|
|
48
|
+
return {
|
|
49
|
+
action: "freeze_file",
|
|
50
|
+
project_id: projectId,
|
|
51
|
+
pattern: args.pattern,
|
|
52
|
+
reason: args.reason ?? null,
|
|
53
|
+
entry,
|
|
54
|
+
cache,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export async function unfreezeFile(args) {
|
|
58
|
+
const projectId = args.project_id ?? currentProjectId;
|
|
59
|
+
// Require an explicit justification so an agent can't silently disarm the
|
|
60
|
+
// policy. The user's original spec: "allow Claude (or the user) to manually
|
|
61
|
+
// remove a pattern from frozen_features after getting permission."
|
|
62
|
+
if (!args.justification || args.justification.trim().length < 4) {
|
|
63
|
+
return {
|
|
64
|
+
action: "unfreeze_file",
|
|
65
|
+
project_id: projectId,
|
|
66
|
+
pattern: args.pattern,
|
|
67
|
+
removed: 0,
|
|
68
|
+
warning: "Refused: unfreeze requires a 'justification' string (≥ 4 chars) explaining why the full-rewrite guardrail can be lifted for this file. Ask the user for permission first.",
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const removed = await removeFrozenPattern(projectId, args.pattern);
|
|
72
|
+
// Drop the entry from the on-disk cache too — match by entry.pattern.
|
|
73
|
+
const key = slugify(projectId);
|
|
74
|
+
const cache = await loadFrozenCache();
|
|
75
|
+
const bucket = cache.projects[key];
|
|
76
|
+
if (bucket) {
|
|
77
|
+
cache.projects[key] = bucket.filter((e) => e.pattern !== args.pattern);
|
|
78
|
+
await writeFrozenCache(cache);
|
|
79
|
+
}
|
|
80
|
+
const cacheRefresh = await writeFrozenPatternsCache();
|
|
81
|
+
return {
|
|
82
|
+
action: "unfreeze_file",
|
|
83
|
+
project_id: projectId,
|
|
84
|
+
pattern: args.pattern,
|
|
85
|
+
justification: args.justification,
|
|
86
|
+
removed,
|
|
87
|
+
cache: cacheRefresh,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/tools/policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { readFile, copyFile, stat } from "node:fs/promises";
|
|
2
|
+
import { resolve, join } from "node:path";
|
|
3
|
+
import { spawn } from "node:child_process";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { detectProjectType } from "../project-detect.js";
|
|
6
|
+
// TODO(v1.2.0): drop the legacy CLAUDE_MEMORY_GATE_DIR fallback after the Smart Claude Memory rebrand has settled.
|
|
7
|
+
// The on-disk dir `~/.claude-memory` is intentionally preserved to keep existing backups discoverable.
|
|
8
|
+
const GATE_DIR = process.env.SMART_CLAUDE_MEMORY_GATE_DIR ??
|
|
9
|
+
process.env.CLAUDE_MEMORY_GATE_DIR ??
|
|
10
|
+
join(homedir(), ".claude-memory");
|
|
11
|
+
const BACKUP_INDEX_PATH = join(GATE_DIR, "backup-index.json");
|
|
12
|
+
// ─── Import scanner (regex-based, heuristic) ─────────────────────────────
|
|
13
|
+
const IMPORT_PATTERNS = {
|
|
14
|
+
ts: [
|
|
15
|
+
/^\s*import\s+(?:[^'"]+?\s+from\s+)?['"]([^'"]+)['"]/gm,
|
|
16
|
+
/\bimport\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
17
|
+
/\brequire\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
18
|
+
/^\s*export\s+(?:\*\s+)?from\s+['"]([^'"]+)['"]/gm,
|
|
19
|
+
],
|
|
20
|
+
js: [
|
|
21
|
+
/^\s*import\s+(?:[^'"]+?\s+from\s+)?['"]([^'"]+)['"]/gm,
|
|
22
|
+
/\bimport\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
23
|
+
/\brequire\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
24
|
+
/^\s*export\s+(?:\*\s+)?from\s+['"]([^'"]+)['"]/gm,
|
|
25
|
+
],
|
|
26
|
+
dart: [
|
|
27
|
+
/^\s*import\s+['"]([^'"]+)['"]/gm,
|
|
28
|
+
/^\s*export\s+['"]([^'"]+)['"]/gm,
|
|
29
|
+
/^\s*part\s+['"]([^'"]+)['"]/gm,
|
|
30
|
+
/^\s*part\s+of\s+['"]([^'"]+)['"]/gm,
|
|
31
|
+
],
|
|
32
|
+
py: [
|
|
33
|
+
/^\s*from\s+(\S+)\s+import\b/gm,
|
|
34
|
+
/^\s*import\s+([\w.,\s]+)$/gm,
|
|
35
|
+
],
|
|
36
|
+
};
|
|
37
|
+
function extForPatterns(p) {
|
|
38
|
+
const e = p.toLowerCase();
|
|
39
|
+
if (e.endsWith(".ts") || e.endsWith(".tsx"))
|
|
40
|
+
return "ts";
|
|
41
|
+
if (e.endsWith(".js") || e.endsWith(".jsx") || e.endsWith(".mjs") || e.endsWith(".cjs"))
|
|
42
|
+
return "js";
|
|
43
|
+
if (e.endsWith(".dart"))
|
|
44
|
+
return "dart";
|
|
45
|
+
if (e.endsWith(".py"))
|
|
46
|
+
return "py";
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
export async function scanImports(filePath) {
|
|
50
|
+
const lang = extForPatterns(filePath);
|
|
51
|
+
if (!lang)
|
|
52
|
+
return [];
|
|
53
|
+
let text;
|
|
54
|
+
try {
|
|
55
|
+
text = await readFile(filePath, "utf8");
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
const found = new Set();
|
|
61
|
+
for (const re of IMPORT_PATTERNS[lang]) {
|
|
62
|
+
let m;
|
|
63
|
+
const src = new RegExp(re.source, re.flags);
|
|
64
|
+
while ((m = src.exec(text)) !== null) {
|
|
65
|
+
const raw = m[1]?.trim();
|
|
66
|
+
if (!raw)
|
|
67
|
+
continue;
|
|
68
|
+
if (lang === "py" && raw.includes(",")) {
|
|
69
|
+
for (const name of raw.split(",")) {
|
|
70
|
+
const t = name.trim();
|
|
71
|
+
if (t)
|
|
72
|
+
found.add(t);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
found.add(raw);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return [...found].sort();
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Run a native binary via spawn WITHOUT shell:true. All inputs come from the
|
|
84
|
+
* compile-time project-type lookup, not from user input — but we still avoid
|
|
85
|
+
* the shell path so no interpolation can ever reach /bin/sh or cmd.exe.
|
|
86
|
+
* On Windows, .cmd shims (npm, npx) need an explicit extension.
|
|
87
|
+
*/
|
|
88
|
+
function runBin(bin, args, cwd, timeoutMs = 120_000) {
|
|
89
|
+
return new Promise((resolveResult) => {
|
|
90
|
+
const winBin = process.platform === "win32" && /^(npm|npx|yarn|pnpm)$/i.test(bin) ? `${bin}.cmd` : bin;
|
|
91
|
+
// Windows: shell:true is required to launch .cmd/.bat shims; args are internal (no user input).
|
|
92
|
+
const child = process.platform === "win32"
|
|
93
|
+
? spawn(winBin, args, { cwd, shell: true })
|
|
94
|
+
: spawn(winBin, args, { cwd });
|
|
95
|
+
let stdout = "";
|
|
96
|
+
let stderr = "";
|
|
97
|
+
const timer = setTimeout(() => child.kill(), timeoutMs);
|
|
98
|
+
child.stdout?.on("data", (d) => { stdout += d.toString(); });
|
|
99
|
+
child.stderr?.on("data", (d) => { stderr += d.toString(); });
|
|
100
|
+
child.on("error", (e) => {
|
|
101
|
+
clearTimeout(timer);
|
|
102
|
+
resolveResult({ code: null, stdout, stderr: stderr + String(e) });
|
|
103
|
+
});
|
|
104
|
+
child.on("close", (code) => {
|
|
105
|
+
clearTimeout(timer);
|
|
106
|
+
resolveResult({ code, stdout, stderr });
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
export async function compilerGate(workspace) {
|
|
111
|
+
const ws = resolve(workspace ?? process.cwd());
|
|
112
|
+
const det = await detectProjectType(ws);
|
|
113
|
+
const t0 = Date.now();
|
|
114
|
+
if (!det.compiler_gate_command) {
|
|
115
|
+
return {
|
|
116
|
+
workspace: ws,
|
|
117
|
+
project_type: det.type,
|
|
118
|
+
command: null,
|
|
119
|
+
ran: false,
|
|
120
|
+
exit_code: null,
|
|
121
|
+
ok: false,
|
|
122
|
+
duration_ms: 0,
|
|
123
|
+
stdout_tail: "",
|
|
124
|
+
stderr_tail: "",
|
|
125
|
+
note: `No compiler-gate command for project type '${det.type}'. Configure one manually or skip.`,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
const { bin, args } = det.compiler_gate_command;
|
|
129
|
+
const { code, stdout, stderr } = await runBin(bin, args, ws);
|
|
130
|
+
const duration = Date.now() - t0;
|
|
131
|
+
const ok = code === 0;
|
|
132
|
+
return {
|
|
133
|
+
workspace: ws,
|
|
134
|
+
project_type: det.type,
|
|
135
|
+
command: `${bin} ${args.join(" ")}`,
|
|
136
|
+
ran: true,
|
|
137
|
+
exit_code: code,
|
|
138
|
+
ok,
|
|
139
|
+
duration_ms: duration,
|
|
140
|
+
stdout_tail: stdout.slice(-2000),
|
|
141
|
+
stderr_tail: stderr.slice(-2000),
|
|
142
|
+
note: ok
|
|
143
|
+
? `Compiler check passed (${duration} ms).`
|
|
144
|
+
: `Compiler check FAILED (exit ${code}). If this follows a recent refactor, call refactor_guard with action:"rollback" to restore the pre-edit backup.`,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
async function readBackupIndex() {
|
|
148
|
+
try {
|
|
149
|
+
const raw = await readFile(BACKUP_INDEX_PATH, "utf8");
|
|
150
|
+
const data = JSON.parse(raw);
|
|
151
|
+
return data.entries ?? {};
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
return {};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
export async function rollbackFile(file) {
|
|
158
|
+
const abs = resolve(file);
|
|
159
|
+
const entries = await readBackupIndex();
|
|
160
|
+
const record = entries[abs] ??
|
|
161
|
+
entries[file] ??
|
|
162
|
+
entries[abs.replace(/\\/g, "/")];
|
|
163
|
+
if (!record) {
|
|
164
|
+
return {
|
|
165
|
+
file: abs,
|
|
166
|
+
restored: false,
|
|
167
|
+
warning: `No hook-managed backup found for ${abs}. Check backup-index.json or restore manually.`,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
try {
|
|
171
|
+
await stat(record.backup);
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
return {
|
|
175
|
+
file: abs,
|
|
176
|
+
restored: false,
|
|
177
|
+
from: record.backup,
|
|
178
|
+
warning: `Backup file referenced in the index no longer exists at ${record.backup}.`,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
await copyFile(record.backup, abs);
|
|
183
|
+
}
|
|
184
|
+
catch (e) {
|
|
185
|
+
return {
|
|
186
|
+
file: abs,
|
|
187
|
+
restored: false,
|
|
188
|
+
from: record.backup,
|
|
189
|
+
warning: `Restore failed: ${e.message}`,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
file: abs,
|
|
194
|
+
restored: true,
|
|
195
|
+
from: record.backup,
|
|
196
|
+
tool: record.tool,
|
|
197
|
+
timestamp: record.timestamp,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
export async function refactorGuard(args) {
|
|
201
|
+
switch (args.action) {
|
|
202
|
+
case "plan": {
|
|
203
|
+
const out = [];
|
|
204
|
+
for (const p of args.paths) {
|
|
205
|
+
const abs = resolve(p);
|
|
206
|
+
out.push({ file: abs, imports: await scanImports(abs) });
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
action: "plan",
|
|
210
|
+
files: out,
|
|
211
|
+
note: "Imports are extracted with language-specific regexes, not a full parser. Use these as a coupling signal; verify cross-file dependencies manually before splitting.",
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
case "gate":
|
|
215
|
+
return { action: "gate", ...(await compilerGate(args.workspace)) };
|
|
216
|
+
case "rollback":
|
|
217
|
+
return { action: "rollback", ...(await rollbackFile(args.file)) };
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=refactor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refactor.js","sourceRoot":"","sources":["../../src/tools/refactor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { embed } from "../ollama.js";
|
|
3
|
+
import { upsertRule } from "../supabase.js";
|
|
4
|
+
import { currentProjectId } from "../project.js";
|
|
5
|
+
/** Reserved project_id for the GLOBAL Knowledge Vault. */
|
|
6
|
+
export const GLOBAL_PROJECT_ID = "GLOBAL";
|
|
7
|
+
/** Minimum characters for a valid global_rationale. Trim-based; whitespace doesn't count. */
|
|
8
|
+
const SOVEREIGN_RATIONALE_MIN_CHARS = 10;
|
|
9
|
+
const SOVEREIGN_VETTING_ERROR = 'SOVEREIGN VETTING FAILED: Saving to GLOBAL requires a "global_rationale" field in metadata. Apply the Cross-Project Test: Why is this memory a universal truth? Provide a rationale and retry.';
|
|
10
|
+
export async function saveMemory(args) {
|
|
11
|
+
const metadata = { ...(args.metadata ?? {}) };
|
|
12
|
+
const isGlobal = metadata.is_global === true;
|
|
13
|
+
// ── Sovereign Vetting Gate (Rule 10) ────────────────────────────────────
|
|
14
|
+
// Hard runtime check: is_global=true MUST be paired with a non-trivial
|
|
15
|
+
// global_rationale. The schema-level describe() is advisory; this gate is
|
|
16
|
+
// the physical rejection that prevents pollution of the GLOBAL Vault.
|
|
17
|
+
if (isGlobal) {
|
|
18
|
+
const rationale = metadata.global_rationale;
|
|
19
|
+
const trimmed = typeof rationale === "string" ? rationale.trim() : "";
|
|
20
|
+
if (trimmed.length < SOVEREIGN_RATIONALE_MIN_CHARS) {
|
|
21
|
+
throw new Error(SOVEREIGN_VETTING_ERROR);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// GLOBAL routing: if the caller flagged the memory as universal, override
|
|
25
|
+
// the row's project_id to the reserved 'GLOBAL' bucket regardless of the
|
|
26
|
+
// explicit project_id argument. The is_global flag is KEPT inside the
|
|
27
|
+
// persisted metadata jsonb for audit/traceability.
|
|
28
|
+
const projectId = isGlobal
|
|
29
|
+
? GLOBAL_PROJECT_ID
|
|
30
|
+
: (args.project_id ?? currentProjectId);
|
|
31
|
+
const chunkIndex = args.chunk_index ?? 0;
|
|
32
|
+
// Default file_origin keys inline-saved memories by content hash so callers
|
|
33
|
+
// who skip the field don't accidentally collide on the (project_id,
|
|
34
|
+
// file_origin, chunk_index) unique key.
|
|
35
|
+
const fileOrigin = args.file_origin ??
|
|
36
|
+
`inline:${createHash("sha256").update(args.content).digest("hex").slice(0, 12)}`;
|
|
37
|
+
const type = metadata.type ?? null;
|
|
38
|
+
const [vec] = await embed([args.content]);
|
|
39
|
+
const id = await upsertRule(projectId, fileOrigin, chunkIndex, args.content, vec, metadata);
|
|
40
|
+
return { id, project_id: projectId, type, is_global: isGlobal };
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=save.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"save.js","sourceRoot":"","sources":["../../src/tools/save.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAqBjD,0DAA0D;AAC1D,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAC;AAc1C,6FAA6F;AAC7F,MAAM,6BAA6B,GAAG,EAAE,CAAC;AAEzC,MAAM,uBAAuB,GAC3B,gMAAgM,CAAC;AAEnM,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAMhC;IAMC,MAAM,QAAQ,GAAuB,EAAE,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,CAAC;IAClE,MAAM,QAAQ,GAAG,QAAQ,CAAC,SAAS,KAAK,IAAI,CAAC;IAE7C,2EAA2E;IAC3E,uEAAuE;IACvE,0EAA0E;IAC1E,sEAAsE;IACtE,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,SAAS,GAAG,QAAQ,CAAC,gBAAgB,CAAC;QAC5C,MAAM,OAAO,GACX,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxD,IAAI,OAAO,CAAC,MAAM,GAAG,6BAA6B,EAAE,CAAC;YACnD,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,yEAAyE;IACzE,sEAAsE;IACtE,mDAAmD;IACnD,MAAM,SAAS,GAAG,QAAQ;QACxB,CAAC,CAAC,iBAAiB;QACnB,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,IAAI,gBAAgB,CAAC,CAAC;IAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,IAAI,CAAC,CAAC;IAEzC,4EAA4E;IAC5E,oEAAoE;IACpE,wCAAwC;IACxC,MAAM,UAAU,GACd,IAAI,CAAC,WAAW;QAChB,UAAU,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;IAEnF,MAAM,IAAI,GAAI,QAAQ,CAAC,IAA+B,IAAI,IAAI,CAAC;IAE/D,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IAC1C,MAAM,EAAE,GAAG,MAAM,UAAU,CACzB,SAAS,EACT,UAAU,EACV,UAAU,EACV,IAAI,CAAC,OAAO,EACZ,GAAG,EACH,QAAmC,CACpC,CAAC;IAEF,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;AAClE,CAAC"}
|