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.
Files changed (104) hide show
  1. package/.claude-plugin/plugin.json +38 -0
  2. package/CHANGELOG.md +52 -0
  3. package/LICENSE +21 -0
  4. package/README.md +790 -0
  5. package/dist/chunker.js +33 -0
  6. package/dist/chunker.js.map +1 -0
  7. package/dist/config.js +23 -0
  8. package/dist/config.js.map +1 -0
  9. package/dist/curriculum/daemon.js +190 -0
  10. package/dist/curriculum/daemon.js.map +1 -0
  11. package/dist/curriculum/scanner.js +237 -0
  12. package/dist/curriculum/scanner.js.map +1 -0
  13. package/dist/index.js +429 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/lib/migrations.js +128 -0
  16. package/dist/lib/migrations.js.map +1 -0
  17. package/dist/ollama.js +59 -0
  18. package/dist/ollama.js.map +1 -0
  19. package/dist/project-detect.js +102 -0
  20. package/dist/project-detect.js.map +1 -0
  21. package/dist/project.js +26 -0
  22. package/dist/project.js.map +1 -0
  23. package/dist/sleep/daemon.js +215 -0
  24. package/dist/sleep/daemon.js.map +1 -0
  25. package/dist/sleep/miner.js +285 -0
  26. package/dist/sleep/miner.js.map +1 -0
  27. package/dist/supabase.js +405 -0
  28. package/dist/supabase.js.map +1 -0
  29. package/dist/telemetry/emit.js +19 -0
  30. package/dist/telemetry/emit.js.map +1 -0
  31. package/dist/telemetry/pruner.js +141 -0
  32. package/dist/telemetry/pruner.js.map +1 -0
  33. package/dist/telemetry/types.js +2 -0
  34. package/dist/telemetry/types.js.map +1 -0
  35. package/dist/tools/backlog.js +599 -0
  36. package/dist/tools/backlog.js.map +1 -0
  37. package/dist/tools/batch-freeze-patterns.js +243 -0
  38. package/dist/tools/batch-freeze-patterns.js.map +1 -0
  39. package/dist/tools/bloat-audit.js +101 -0
  40. package/dist/tools/bloat-audit.js.map +1 -0
  41. package/dist/tools/checkpoint.js +259 -0
  42. package/dist/tools/checkpoint.js.map +1 -0
  43. package/dist/tools/compact.js +60 -0
  44. package/dist/tools/compact.js.map +1 -0
  45. package/dist/tools/conflict.js +102 -0
  46. package/dist/tools/conflict.js.map +1 -0
  47. package/dist/tools/curriculum.js +225 -0
  48. package/dist/tools/curriculum.js.map +1 -0
  49. package/dist/tools/frozen-cache.js +106 -0
  50. package/dist/tools/frozen-cache.js.map +1 -0
  51. package/dist/tools/health.js +368 -0
  52. package/dist/tools/health.js.map +1 -0
  53. package/dist/tools/hygiene.js +309 -0
  54. package/dist/tools/hygiene.js.map +1 -0
  55. package/dist/tools/image.js +107 -0
  56. package/dist/tools/image.js.map +1 -0
  57. package/dist/tools/list-global-patterns.js +101 -0
  58. package/dist/tools/list-global-patterns.js.map +1 -0
  59. package/dist/tools/orchestrator.js +113 -0
  60. package/dist/tools/orchestrator.js.map +1 -0
  61. package/dist/tools/policy.js +90 -0
  62. package/dist/tools/policy.js.map +1 -0
  63. package/dist/tools/refactor.js +220 -0
  64. package/dist/tools/refactor.js.map +1 -0
  65. package/dist/tools/save.js +42 -0
  66. package/dist/tools/save.js.map +1 -0
  67. package/dist/tools/search.js +189 -0
  68. package/dist/tools/search.js.map +1 -0
  69. package/dist/tools/setup.js +868 -0
  70. package/dist/tools/setup.js.map +1 -0
  71. package/dist/tools/shared-schemas.js +24 -0
  72. package/dist/tools/shared-schemas.js.map +1 -0
  73. package/dist/tools/skills.js +174 -0
  74. package/dist/tools/skills.js.map +1 -0
  75. package/dist/tools/sleep.js +239 -0
  76. package/dist/tools/sleep.js.map +1 -0
  77. package/dist/tools/sovereign-constitution.js +319 -0
  78. package/dist/tools/sovereign-constitution.js.map +1 -0
  79. package/dist/tools/summarize.js +55 -0
  80. package/dist/tools/summarize.js.map +1 -0
  81. package/dist/tools/sync.js +255 -0
  82. package/dist/tools/sync.js.map +1 -0
  83. package/dist/tools/system_dashboard.js +181 -0
  84. package/dist/tools/system_dashboard.js.map +1 -0
  85. package/dist/tools/update-rule.js +15 -0
  86. package/dist/tools/update-rule.js.map +1 -0
  87. package/dist/tools/verification.js +333 -0
  88. package/dist/tools/verification.js.map +1 -0
  89. package/dist/trajectory/daemon.js +270 -0
  90. package/dist/trajectory/daemon.js.map +1 -0
  91. package/dist/trajectory/stripper.js +124 -0
  92. package/dist/trajectory/stripper.js.map +1 -0
  93. package/dist/trajectory/summarizer.js +77 -0
  94. package/dist/trajectory/summarizer.js.map +1 -0
  95. package/dist/transactions/checkpoint.js +272 -0
  96. package/dist/transactions/checkpoint.js.map +1 -0
  97. package/dist/verification-gate.js +43 -0
  98. package/dist/verification-gate.js.map +1 -0
  99. package/dist/version.js +16 -0
  100. package/dist/version.js.map +1 -0
  101. package/hooks/README.md +54 -0
  102. package/hooks/md-policy.py +497 -0
  103. package/marketplace.json +13 -0
  104. package/package.json +66 -0
@@ -0,0 +1,243 @@
1
+ // batch_freeze_patterns — hydrate frozen-patterns.json from explicit globs
2
+ // AND/OR a markdown rule-file in a single MCP call. v1.1.3.
3
+ //
4
+ // Each on-disk entry is { pattern, source, added_at }. NO eager glob
5
+ // expansion: patterns are stored as-given. Dedup key is the trimmed,
6
+ // case-sensitive pattern string. First writer wins (an existing entry is
7
+ // skipped, not overwritten). Atomic write is delegated to writeFrozenCache
8
+ // (.tmp + rename).
9
+ import { readFile } from "node:fs/promises";
10
+ import { isAbsolute, relative, resolve } from "node:path";
11
+ import { addFrozenPattern } from "../supabase.js";
12
+ import { currentProjectId, slugify } from "../project.js";
13
+ import { loadFrozenCache, writeFrozenCache, } from "./frozen-cache.js";
14
+ const DEFAULT_SECTION = "## Frozen Patterns";
15
+ /**
16
+ * Pull pattern strings out of a markdown section. Strict, no NLP:
17
+ * - locate the first line that exactly matches `section` (after rstrip)
18
+ * - read until the next markdown heading (line starting with `#`) or EOF
19
+ * - strip leading list markers (`-`, `*`, `+`, or `1.`/`2.`/...) + space
20
+ * - strip surrounding backticks (single or triple)
21
+ * - reject empty results and lines containing an unescaped space
22
+ */
23
+ function extractFromMarkdown(body, section) {
24
+ const lines = body.split(/\r?\n/);
25
+ const target = section.trimEnd();
26
+ let i = 0;
27
+ let found = false;
28
+ for (; i < lines.length; i++) {
29
+ if (lines[i].replace(/\s+$/, "") === target) {
30
+ found = true;
31
+ i++;
32
+ break;
33
+ }
34
+ }
35
+ if (!found)
36
+ return { found: false, raw: [], skipped: 0 };
37
+ const raw = [];
38
+ let skipped = 0;
39
+ for (; i < lines.length; i++) {
40
+ const line = lines[i];
41
+ // Stop at the next markdown heading.
42
+ if (/^#/.test(line))
43
+ break;
44
+ const trimmed = line.trim();
45
+ if (!trimmed)
46
+ continue;
47
+ if (trimmed.startsWith("<!--"))
48
+ continue;
49
+ // Strip leading list markers: `-`, `*`, `+`, or numeric `1.` / `2.`.
50
+ let candidate = trimmed.replace(/^([-*+]|\d+\.)\s+/, "");
51
+ // Strip surrounding triple or single backticks.
52
+ candidate = candidate.replace(/^```+|```+$/g, "").replace(/^`+|`+$/g, "");
53
+ candidate = candidate.trim();
54
+ if (!candidate) {
55
+ skipped++;
56
+ continue;
57
+ }
58
+ // Reject obvious non-paths: contains an unescaped space (anything that
59
+ // looks like a sentence, not a glob/path).
60
+ if (/(?<!\\)\s/.test(candidate)) {
61
+ skipped++;
62
+ continue;
63
+ }
64
+ raw.push(candidate);
65
+ }
66
+ return { found: true, raw, skipped };
67
+ }
68
+ /**
69
+ * Validate one already-extracted pattern. Returns the cleaned string if it
70
+ * passes, or null if it should be skipped. (extractFromMarkdown already
71
+ * applies these checks; this is the same gate for `paths` array entries so
72
+ * inline callers can't bypass them.)
73
+ */
74
+ function validatePattern(p) {
75
+ const trimmed = p.replace(/^`+|`+$/g, "").trim();
76
+ if (!trimmed)
77
+ return null;
78
+ if (/(?<!\\)\s/.test(trimmed))
79
+ return null;
80
+ return trimmed;
81
+ }
82
+ /**
83
+ * Resolve a workspace-relative path for the `source` field of a rule-file
84
+ * provenance. Falls back to the as-given string if the relative form would
85
+ * escape the workspace (i.e. starts with `..`).
86
+ */
87
+ function workspaceRelative(filePath) {
88
+ try {
89
+ const abs = isAbsolute(filePath) ? filePath : resolve(filePath);
90
+ const rel = relative(process.cwd(), abs).replace(/\\/g, "/");
91
+ if (rel && !rel.startsWith(".."))
92
+ return rel;
93
+ return filePath.replace(/\\/g, "/");
94
+ }
95
+ catch {
96
+ return filePath;
97
+ }
98
+ }
99
+ export async function batchFreezePatterns(args) {
100
+ const projectId = args.project_id ?? currentProjectId;
101
+ const dryRun = args.dry_run ?? false;
102
+ const section = args.section ?? DEFAULT_SECTION;
103
+ if ((!args.paths || args.paths.length === 0) && !args.from_rule_file) {
104
+ return {
105
+ action: "batch_freeze_patterns",
106
+ project_id: projectId,
107
+ added: 0,
108
+ deduped: 0,
109
+ skipped: 0,
110
+ source: "none",
111
+ dry_run: dryRun,
112
+ error: "At least one of `paths` or `from_rule_file` must be provided.",
113
+ };
114
+ }
115
+ const candidates = [];
116
+ let skipped = 0;
117
+ let resolvedSource = "";
118
+ let sectionMissing = false;
119
+ if (args.paths && args.paths.length > 0) {
120
+ const inlineSource = args.source_tag ?? "inline";
121
+ for (const raw of args.paths) {
122
+ const ok = validatePattern(raw);
123
+ if (!ok) {
124
+ skipped++;
125
+ continue;
126
+ }
127
+ candidates.push({ pattern: ok, source: inlineSource });
128
+ }
129
+ resolvedSource = inlineSource;
130
+ }
131
+ if (args.from_rule_file) {
132
+ const rulePath = args.from_rule_file;
133
+ const ruleSource = args.source_tag ?? workspaceRelative(rulePath);
134
+ let body;
135
+ try {
136
+ body = await readFile(rulePath, "utf8");
137
+ }
138
+ catch (e) {
139
+ return {
140
+ action: "batch_freeze_patterns",
141
+ project_id: projectId,
142
+ added: 0,
143
+ deduped: 0,
144
+ skipped: 0,
145
+ source: ruleSource,
146
+ dry_run: dryRun,
147
+ error: `Failed to read rule file: ${e.message}`,
148
+ };
149
+ }
150
+ const ext = extractFromMarkdown(body, section);
151
+ if (!ext.found) {
152
+ sectionMissing = true;
153
+ resolvedSource = ruleSource;
154
+ }
155
+ else {
156
+ for (const pat of ext.raw) {
157
+ candidates.push({ pattern: pat, source: ruleSource });
158
+ }
159
+ skipped += ext.skipped;
160
+ // Rule file source label trumps inline if both supplied (more
161
+ // descriptive). Inline source is still attached per-candidate above.
162
+ resolvedSource = ruleSource;
163
+ }
164
+ }
165
+ if (sectionMissing && candidates.length === 0) {
166
+ return {
167
+ action: "batch_freeze_patterns",
168
+ project_id: projectId,
169
+ added: 0,
170
+ deduped: 0,
171
+ skipped: 0,
172
+ source: resolvedSource,
173
+ dry_run: dryRun,
174
+ error: "section not found",
175
+ };
176
+ }
177
+ // Compute the prospective new cache.
178
+ const cache = await loadFrozenCache();
179
+ const key = slugify(projectId);
180
+ const bucket = (cache.projects[key] ??= []);
181
+ const existingPatterns = new Set(bucket.map((e) => e.pattern));
182
+ let added = 0;
183
+ let deduped = 0;
184
+ const newPatterns = [];
185
+ const newEntries = [];
186
+ const now = Date.now();
187
+ // Track patterns staged in *this* batch so the second occurrence in the
188
+ // same call counts as a dedup, not a second add.
189
+ const batchSeen = new Set();
190
+ for (const c of candidates) {
191
+ if (existingPatterns.has(c.pattern) || batchSeen.has(c.pattern)) {
192
+ deduped++;
193
+ continue;
194
+ }
195
+ batchSeen.add(c.pattern);
196
+ const entry = {
197
+ pattern: c.pattern,
198
+ source: c.source,
199
+ added_at: now,
200
+ };
201
+ newEntries.push(entry);
202
+ newPatterns.push(c.pattern);
203
+ added++;
204
+ }
205
+ if (dryRun) {
206
+ return {
207
+ action: "batch_freeze_patterns",
208
+ project_id: projectId,
209
+ added,
210
+ deduped,
211
+ skipped,
212
+ source: resolvedSource || "none",
213
+ dry_run: true,
214
+ patterns: newPatterns,
215
+ };
216
+ }
217
+ // Persist: append new entries to the cache, atomic-write, and mirror to
218
+ // Supabase so the existing freeze_file/unfreeze_file flow stays consistent.
219
+ if (newEntries.length > 0) {
220
+ bucket.push(...newEntries);
221
+ await writeFrozenCache(cache);
222
+ for (const e of newEntries) {
223
+ try {
224
+ await addFrozenPattern(projectId, e.pattern, `batch_freeze_patterns: ${e.source}`);
225
+ }
226
+ catch {
227
+ // Supabase mirror is best-effort. Cache (read by the hook) is
228
+ // authoritative for blocking; if the network is down the freeze
229
+ // still takes effect on disk.
230
+ }
231
+ }
232
+ }
233
+ return {
234
+ action: "batch_freeze_patterns",
235
+ project_id: projectId,
236
+ added,
237
+ deduped,
238
+ skipped,
239
+ source: resolvedSource || "none",
240
+ dry_run: false,
241
+ };
242
+ }
243
+ //# sourceMappingURL=batch-freeze-patterns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-freeze-patterns.js","sourceRoot":"","sources":["../../src/tools/batch-freeze-patterns.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,101 @@
1
+ import { promises as fs } from "fs";
2
+ import * as path from "path";
3
+ import * as os from "os";
4
+ export const BLOAT_THRESHOLD = 10000;
5
+ export function estimateTokens(text) {
6
+ if (!text)
7
+ return 0;
8
+ return Math.ceil(text.length / 4);
9
+ }
10
+ async function fileExists(p) {
11
+ try {
12
+ await fs.access(p);
13
+ return true;
14
+ }
15
+ catch {
16
+ return false;
17
+ }
18
+ }
19
+ async function readSafe(p) {
20
+ try {
21
+ return await fs.readFile(p, "utf-8");
22
+ }
23
+ catch {
24
+ return "";
25
+ }
26
+ }
27
+ async function resolveHiddenMemory(workspaceAbs) {
28
+ try {
29
+ const home = os.homedir();
30
+ const isWin = process.platform === "win32";
31
+ let encoded = workspaceAbs.replace(/[:\\/ ]/g, "-");
32
+ if (isWin)
33
+ encoded = encoded.toLowerCase();
34
+ const primary = path.join(home, ".claude", "projects", encoded, "memory", "MEMORY.md");
35
+ if (await fileExists(primary))
36
+ return primary;
37
+ // Fallback scan
38
+ const projectsDir = path.join(home, ".claude", "projects");
39
+ const basename = path.basename(workspaceAbs).toLowerCase();
40
+ try {
41
+ const entries = await fs.readdir(projectsDir, { withFileTypes: true });
42
+ for (const e of entries) {
43
+ if (!e.isDirectory())
44
+ continue;
45
+ if (!e.name.toLowerCase().includes(basename))
46
+ continue;
47
+ const cand = path.join(projectsDir, e.name, "memory", "MEMORY.md");
48
+ if (await fileExists(cand))
49
+ return cand;
50
+ }
51
+ }
52
+ catch {
53
+ /* ignore */
54
+ }
55
+ return null;
56
+ }
57
+ catch {
58
+ return null;
59
+ }
60
+ }
61
+ export async function auditBloat(workspace) {
62
+ const claudeMdPath = path.join(workspace, "CLAUDE.md");
63
+ const claudeMd = await readSafe(claudeMdPath);
64
+ const claudeMdTokens = estimateTokens(claudeMd);
65
+ const claudeMdBloated = claudeMdTokens > BLOAT_THRESHOLD;
66
+ const hiddenMemoryPath = await resolveHiddenMemory(workspace);
67
+ const hiddenMemory = hiddenMemoryPath ? await readSafe(hiddenMemoryPath) : "";
68
+ const hiddenMemoryTokens = estimateTokens(hiddenMemory);
69
+ const hiddenMemoryBloated = hiddenMemoryTokens > BLOAT_THRESHOLD;
70
+ const bloat_audit = {
71
+ threshold: BLOAT_THRESHOLD,
72
+ claude_md: { path: claudeMdPath, tokens: claudeMdTokens, bloated: claudeMdBloated },
73
+ hidden_memory: {
74
+ path: hiddenMemoryPath,
75
+ tokens: hiddenMemoryTokens,
76
+ bloated: hiddenMemoryBloated,
77
+ found: hiddenMemoryPath !== null,
78
+ },
79
+ };
80
+ const anyBloated = claudeMdBloated || hiddenMemoryBloated;
81
+ if (!anyBloated)
82
+ return { bloat_audit, sovereign_purge_recommendation: null };
83
+ const recommendation = {
84
+ id: "sovereign_purge",
85
+ description: `Bloat detected (CLAUDE.md=${claudeMdTokens} tokens, hidden MEMORY.md=${hiddenMemoryTokens} tokens; threshold=${BLOAT_THRESHOLD}). Auto-purge will safely migrate legacy content to Supabase vectors and reset files to the clean DNA v2.1 baseline.`,
86
+ bloat_audit,
87
+ agent_protocol: "ASK_USER_THEN_EXECUTE",
88
+ steps: [
89
+ "Ask the user for explicit YES/NO permission before doing anything.",
90
+ "On YES: (a) mkdir -p docs/scm-memory/ (b) move CLAUDE.md -> docs/scm-memory/legacy_claude.md (c) if hidden MEMORY.md exists, copy it to docs/scm-memory/legacy_memory.md (d) call sync_local_memory({ force: true }) so the legacy files are vectorized into Supabase (e) call ensureSovereignConstitution({ force: true }) to regenerate a fresh v2.1 CLAUDE.md (f) report a 2-line synthesis to the user.",
91
+ "On NO: do nothing this session; the recommendation will resurface next init_project.",
92
+ ],
93
+ legacy_targets: {
94
+ claude_md: claudeMdPath,
95
+ hidden_memory: hiddenMemoryPath,
96
+ },
97
+ destination: path.join(workspace, "docs", "scm-memory"),
98
+ };
99
+ return { bloat_audit, sovereign_purge_recommendation: recommendation };
100
+ }
101
+ //# sourceMappingURL=bloat-audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bloat-audit.js","sourceRoot":"","sources":["../../src/tools/bloat-audit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,259 @@
1
+ // MCP tool wrappers for Transactional Workflow Checkpoints
2
+ // (Agentic OS 2026 / Mission 4 / Phase B).
3
+ //
4
+ // Four handlers that wrap the pure service layer in
5
+ // src/transactions/checkpoint.ts and add the MCP-shaped envelope:
6
+ //
7
+ // * checkpoint_create — openCheckpoint() + cloud_backlog.metadata stamp
8
+ // when this is a root checkpoint tied to a backlog
9
+ // task. The stamp populates
10
+ // cloud_backlog.metadata.checkpoint_root_id, which
11
+ // archive_done_backlog (014) joins on to populate
12
+ // archive_backlog.chunk_id at archive time.
13
+ // * checkpoint_commit — commitCheckpoint()
14
+ // * checkpoint_rollback — rollbackCheckpoint() + structured [M4] rollback
15
+ // signal log. No separate signals table — the
16
+ // miner's LEFT JOIN over workflow_checkpoints
17
+ // picks rolledback rows directly.
18
+ // * checkpoint_list — listCheckpoints() with safe limit bounds.
19
+ //
20
+ // Style mirrors src/tools/compact.ts (handler + input shape exports) and
21
+ // src/tools/sleep.ts (project_id resolution via currentProjectId default).
22
+ // Zero `any`, zero TODO, zero placeholders.
23
+ import { z } from "zod";
24
+ import { supabase } from "../supabase.js";
25
+ import { currentProjectId } from "../project.js";
26
+ import { openCheckpoint, commitCheckpoint, rollbackCheckpoint, listCheckpoints, } from "../transactions/checkpoint.js";
27
+ // ─── shared project_id helper ───────────────────────────────────────────────
28
+ function resolveProjectId(explicit) {
29
+ if (typeof explicit === "string" && explicit.trim().length > 0) {
30
+ return explicit;
31
+ }
32
+ return currentProjectId;
33
+ }
34
+ // ─── checkpoint_create ──────────────────────────────────────────────────────
35
+ export const checkpointCreateInputShape = {
36
+ project_id: z
37
+ .string()
38
+ .optional()
39
+ .describe(`Project namespace. Defaults to the slugified current working directory ('${currentProjectId}').`),
40
+ skill_id: z
41
+ .number()
42
+ .int()
43
+ .positive()
44
+ .nullable()
45
+ .optional()
46
+ .describe("agent_skills.id when this checkpoint is anchoring a step of a JIT-retrieved skill. NULL when the workflow is ad-hoc."),
47
+ step_index: z
48
+ .number()
49
+ .int()
50
+ .nonnegative()
51
+ .optional()
52
+ .default(0)
53
+ .describe("Zero-based ordinal of this step within the workflow. Default 0 (root step)."),
54
+ step_label: z
55
+ .string()
56
+ .min(1)
57
+ .describe("Short human-readable label for the step (e.g. 'edit-and-typecheck', 'run-migration'). Required."),
58
+ parent_id: z
59
+ .number()
60
+ .int()
61
+ .positive()
62
+ .nullable()
63
+ .optional()
64
+ .describe("workflow_checkpoints.id of the prior step in the chain. NULL = root step of the workflow."),
65
+ backlog_task_id: z
66
+ .number()
67
+ .int()
68
+ .positive()
69
+ .optional()
70
+ .describe("cloud_backlog.id this workflow services. When provided AND parent_id is null, this checkpoint becomes the root and its id is stamped into cloud_backlog.metadata.checkpoint_root_id so archive_done_backlog can populate archive_backlog.chunk_id at archive time."),
71
+ };
72
+ const checkpointCreateSchema = z.object(checkpointCreateInputShape);
73
+ /**
74
+ * Stamp metadata.checkpoint_root_id onto a cloud_backlog row via a
75
+ * read-modify-write. We avoid jsonb_set RPC plumbing (would require a new
76
+ * SECURITY DEFINER fn) — the row count is always 1 here, so the round-trip
77
+ * cost is negligible and the code stays portable.
78
+ *
79
+ * Returns true if the row was stamped, false if the row was not found or
80
+ * the project_id didn't match (defensive guard against cross-tenant
81
+ * stamping).
82
+ */
83
+ async function stampCheckpointRootIdOnBacklog(projectId, backlogTaskId, checkpointId) {
84
+ const { data: row, error: loadErr } = await supabase
85
+ .from("cloud_backlog")
86
+ .select("id, project_id, metadata")
87
+ .eq("id", backlogTaskId)
88
+ .eq("project_id", projectId)
89
+ .maybeSingle();
90
+ if (loadErr) {
91
+ throw new Error(`[M4] stampCheckpointRootIdOnBacklog: lookup failed: ${loadErr.message}`);
92
+ }
93
+ if (!row) {
94
+ // No matching row — log and report not-stamped; this is not a hard error
95
+ // (caller may have passed a stale id; we don't want to fail the
96
+ // checkpoint that was already inserted).
97
+ console.log(`[M4] stamp skipped: cloud_backlog id=${backlogTaskId} not found in project=${projectId}`);
98
+ return false;
99
+ }
100
+ const existing = row.metadata && typeof row.metadata === "object" && !Array.isArray(row.metadata)
101
+ ? row.metadata
102
+ : {};
103
+ const nextMetadata = {
104
+ ...existing,
105
+ checkpoint_root_id: checkpointId,
106
+ };
107
+ const { error: updateErr } = await supabase
108
+ .from("cloud_backlog")
109
+ .update({ metadata: nextMetadata })
110
+ .eq("id", backlogTaskId)
111
+ .eq("project_id", projectId);
112
+ if (updateErr) {
113
+ throw new Error(`[M4] stampCheckpointRootIdOnBacklog: update failed: ${updateErr.message}`);
114
+ }
115
+ console.log(`[M4] stamped checkpoint_root_id=${checkpointId} on cloud_backlog.id=${backlogTaskId}`);
116
+ return true;
117
+ }
118
+ export async function checkpointCreateHandler(args) {
119
+ const parsed = checkpointCreateSchema.parse(args);
120
+ const projectId = resolveProjectId(parsed.project_id);
121
+ const skillId = parsed.skill_id === undefined || parsed.skill_id === null ? null : parsed.skill_id;
122
+ const parentId = parsed.parent_id === undefined || parsed.parent_id === null ? null : parsed.parent_id;
123
+ const stepIndex = parsed.step_index ?? 0;
124
+ const opened = await openCheckpoint({
125
+ projectId,
126
+ skillId,
127
+ stepIndex,
128
+ stepLabel: parsed.step_label,
129
+ parentId,
130
+ });
131
+ let backlogStamped = false;
132
+ // Stamp only when this is a ROOT checkpoint (parentId is null) AND a
133
+ // backlog task id was supplied. Non-root checkpoints inherit their root
134
+ // via the parent_id chain; restamping a non-root would break the join.
135
+ if (parentId === null && parsed.backlog_task_id !== undefined) {
136
+ backlogStamped = await stampCheckpointRootIdOnBacklog(projectId, parsed.backlog_task_id, opened.id);
137
+ }
138
+ return {
139
+ checkpoint_id: opened.id,
140
+ status: "open",
141
+ backlog_stamped: backlogStamped,
142
+ };
143
+ }
144
+ // ─── checkpoint_commit ──────────────────────────────────────────────────────
145
+ export const checkpointCommitInputShape = {
146
+ project_id: z
147
+ .string()
148
+ .optional()
149
+ .describe(`Project namespace. Defaults to the slugified current working directory ('${currentProjectId}').`),
150
+ checkpoint_id: z
151
+ .number()
152
+ .int()
153
+ .positive()
154
+ .describe("workflow_checkpoints.id to mark committed."),
155
+ source_chunk_id: z
156
+ .number()
157
+ .int()
158
+ .positive()
159
+ .describe("memory_chunks.id whose trajectory_summaries entry is the replay anchor. Required — committed rows MUST pin a chunk."),
160
+ };
161
+ const checkpointCommitSchema = z.object(checkpointCommitInputShape);
162
+ export async function checkpointCommitHandler(args) {
163
+ const parsed = checkpointCommitSchema.parse(args);
164
+ const projectId = resolveProjectId(parsed.project_id);
165
+ const committed = await commitCheckpoint({
166
+ projectId,
167
+ checkpointId: parsed.checkpoint_id,
168
+ sourceChunkId: parsed.source_chunk_id,
169
+ });
170
+ return {
171
+ checkpoint_id: committed.id,
172
+ status: "committed",
173
+ source_chunk_id: committed.sourceChunkId,
174
+ };
175
+ }
176
+ // ─── checkpoint_rollback ────────────────────────────────────────────────────
177
+ export const checkpointRollbackInputShape = {
178
+ project_id: z
179
+ .string()
180
+ .optional()
181
+ .describe(`Project namespace. Defaults to the slugified current working directory ('${currentProjectId}').`),
182
+ checkpoint_id: z
183
+ .number()
184
+ .int()
185
+ .positive()
186
+ .describe("workflow_checkpoints.id to mark rolledback."),
187
+ reason: z
188
+ .string()
189
+ .min(1)
190
+ .describe("Non-empty human-readable reason persisted to workflow_checkpoints.rollback_reason and surfaced to the M3 miner as a negative signal."),
191
+ };
192
+ const checkpointRollbackSchema = z.object(checkpointRollbackInputShape);
193
+ export async function checkpointRollbackHandler(args) {
194
+ const parsed = checkpointRollbackSchema.parse(args);
195
+ const projectId = resolveProjectId(parsed.project_id);
196
+ const r = await rollbackCheckpoint({
197
+ projectId,
198
+ checkpointId: parsed.checkpoint_id,
199
+ reason: parsed.reason,
200
+ });
201
+ // M3 signal: emit a structured log line. The miner reads
202
+ // workflow_checkpoints directly (no separate signals table); this log is
203
+ // purely operational visibility so a human can grep rollback churn.
204
+ const anchor = r.restoredFrom
205
+ ? `parent=${r.restoredFrom.checkpointId} source_chunk_id=${r.restoredFrom.sourceChunkId}`
206
+ : "no_replay_anchor";
207
+ console.log(`[M4] rollback_signal: project=${projectId} id=${r.id} reason=${parsed.reason} ${anchor}`);
208
+ return {
209
+ checkpoint_id: r.id,
210
+ status: "rolledback",
211
+ restored_from: r.restoredFrom
212
+ ? {
213
+ checkpoint_id: r.restoredFrom.checkpointId,
214
+ source_chunk_id: r.restoredFrom.sourceChunkId,
215
+ }
216
+ : null,
217
+ };
218
+ }
219
+ // ─── checkpoint_list ────────────────────────────────────────────────────────
220
+ export const checkpointListInputShape = {
221
+ project_id: z
222
+ .string()
223
+ .optional()
224
+ .describe(`Project namespace. Defaults to the slugified current working directory ('${currentProjectId}').`),
225
+ status: z
226
+ .enum(["open", "committed", "rolledback"])
227
+ .optional()
228
+ .describe("Lifecycle filter. Omit to surface all states."),
229
+ skill_id: z
230
+ .number()
231
+ .int()
232
+ .positive()
233
+ .optional()
234
+ .describe("Filter by agent_skills.id. Omit to surface checkpoints regardless of skill linkage."),
235
+ limit: z
236
+ .number()
237
+ .int()
238
+ .positive()
239
+ .max(100)
240
+ .optional()
241
+ .default(20)
242
+ .describe("Hard cap on rows returned. Default 20, max 100."),
243
+ };
244
+ const checkpointListSchema = z.object(checkpointListInputShape);
245
+ export async function checkpointListHandler(args) {
246
+ const parsed = checkpointListSchema.parse(args);
247
+ const projectId = resolveProjectId(parsed.project_id);
248
+ const limit = parsed.limit ?? 20;
249
+ const status = parsed.status;
250
+ const skillId = parsed.skill_id === undefined || parsed.skill_id === null ? undefined : parsed.skill_id;
251
+ const rows = await listCheckpoints({
252
+ projectId,
253
+ status,
254
+ skillId,
255
+ limit,
256
+ });
257
+ return { count: rows.length, checkpoints: rows };
258
+ }
259
+ //# sourceMappingURL=checkpoint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkpoint.js","sourceRoot":"","sources":["../../src/tools/checkpoint.ts"],"names":[],"mappings":"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"}