mnemos-capture 1.1.0 → 1.2.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/dist/cli/index.js CHANGED
@@ -17,10 +17,10 @@ async function main() {
17
17
  const keyIdx = args.indexOf("--key");
18
18
  const apiKey = keyIdx !== -1 ? args[keyIdx + 1] : undefined;
19
19
  if (!apiKey) {
20
- console.error("Usage: npx mnemos-capture setup-hooks --key YOUR_API_KEY [--briefing]");
20
+ console.error("Usage: npx mnemos-capture setup-hooks --key YOUR_API_KEY [--briefing] [--vault]");
21
21
  process.exit(1);
22
22
  }
23
- setupHooks(apiKey, { briefing: args.includes("--briefing") });
23
+ setupHooks(apiKey, { briefing: args.includes("--briefing"), vault: args.includes("--vault") });
24
24
  return;
25
25
  }
26
26
  if (command === "inbox-check") {
@@ -32,6 +32,34 @@ async function main() {
32
32
  await inboxCheck(apiKey, { briefing: args.includes("--briefing") });
33
33
  return;
34
34
  }
35
+ if (command === "vault-check") {
36
+ const { vaultCheck } = await import("./hooks.js");
37
+ const keyIdx = args.indexOf("--key");
38
+ const apiKey = keyIdx !== -1 ? args[keyIdx + 1] : undefined;
39
+ if (!apiKey)
40
+ process.exit(0); // silent fail in hook context
41
+ await vaultCheck(apiKey);
42
+ return;
43
+ }
44
+ if (command === "config") {
45
+ const { runConfigCommand } = await import("./config.js");
46
+ runConfigCommand(args.slice(1));
47
+ return;
48
+ }
49
+ if (command === "kos") {
50
+ const { kos } = await import("./kos.js");
51
+ const { readConfig } = await import("./config.js");
52
+ const keyIdx = args.indexOf("--key");
53
+ const apiKey = keyIdx !== -1 ? args[keyIdx + 1] : readConfig().key;
54
+ if (!apiKey) {
55
+ console.error("No API key. Pass --key YOUR_KEY or store it: mnemos config set key YOUR_KEY");
56
+ process.exit(1);
57
+ }
58
+ const planIdx = args.indexOf("--plan");
59
+ const plan = planIdx !== -1 ? args[planIdx + 1] : undefined;
60
+ await kos(apiKey, { plan });
61
+ return;
62
+ }
35
63
  // Default: open the hosted app
36
64
  console.log("");
37
65
  console.log(" Mnemos — Knowledge capture for agentic workflows\n");
@@ -52,11 +80,30 @@ function printHelp() {
52
80
  Mnemos — Knowledge capture for agentic workflows
53
81
 
54
82
  Usage:
55
- npx mnemos-capture Open Mnemos in your browser
56
- npx mnemos-capture serve-mcp --key KEY Start the MCP server for Claude Code
57
- npx mnemos-capture setup-hooks --key KEY Install inbox count hook (fast)
58
- npx mnemos-capture setup-hooks --key KEY --briefing Install full briefing hook (uses LLM)
59
- npx mnemos-capture help Show this help
83
+ npx mnemos-capture Open Mnemos in your browser
84
+ npx mnemos-capture serve-mcp --key KEY Start the MCP server for Claude Code
85
+ npx mnemos-capture setup-hooks --key KEY Install inbox count hook (fast)
86
+ npx mnemos-capture setup-hooks --key KEY --briefing Install full briefing hook (uses LLM)
87
+ npx mnemos-capture setup-hooks --key KEY --vault Install vault hook (PreToolCall)
88
+ npx mnemos-capture setup-hooks --key KEY --briefing --vault Install both hooks
89
+ npx mnemos-capture config set agent "claude -p" Set which AI assistant kos drives
90
+ npx mnemos-capture kos --key KEY [--plan FILE] Implement a plan in an isolated worktree
91
+ npx mnemos-capture help Show this help
92
+
93
+ MCP tools (via your AI assistant):
94
+ briefing — Session-start briefing with ranked insights to apply
95
+ generate_plan — Turn selected captures into a full implementation plan
96
+ list_plans — List or read saved implementation plans
97
+ vault_scan — Scan all captures for relevance to current activity
98
+ curate — Validate URLs and flag stale captures
99
+
100
+ kos — implement plans with your own AI assistant (model-agnostic):
101
+ 1. Tell Mnemos which assistant to drive (once):
102
+ mnemos config set agent "claude -p" # or "codex exec", "aider --yes --message"
103
+ 2. Generate a plan via the generate_plan MCP tool.
104
+ 3. Run: mnemos kos --key YOUR_KEY
105
+ kos creates an isolated git worktree, hands the plan to your assistant,
106
+ and reports the branch + the plan's Verification Checklist when done.
60
107
 
61
108
  Get started:
62
109
  1. Run: npx mnemos-capture
@@ -74,6 +121,9 @@ function printHelp() {
74
121
  The hook is installed automatically when you start the MCP server.
75
122
  To upgrade to a full project briefing at session start:
76
123
  npx mnemos-capture setup-hooks --key YOUR_API_KEY --briefing
124
+
125
+ To enable the vault (surfaces captures as you edit files — opt-in):
126
+ npx mnemos-capture setup-hooks --key YOUR_API_KEY --vault
77
127
  `);
78
128
  }
79
129
  main().catch((err) => {
@@ -0,0 +1,123 @@
1
+ /**
2
+ * kos — Mnemos' Knowledge Operations orchestrator.
3
+ *
4
+ * Drives whatever AI assistant the user configured (`mnemos config set agent ...`)
5
+ * to implement a generated plan in an isolated git worktree. Mnemos owns the
6
+ * harness-independent parts: fetching the plan, the worktree, and reporting the
7
+ * Verification Checklist. The assistant is a black box — model-agnostic by design.
8
+ */
9
+ import { tmpdir } from "os";
10
+ import { join } from "path";
11
+ import { writeFileSync, existsSync, appendFileSync, readFileSync } from "fs";
12
+ import { execSync } from "child_process";
13
+ import { callMcp } from "./hooks.js";
14
+ import { readConfig } from "./config.js";
15
+ // ── Pure helpers (exported for testing) ──
16
+ /** Extract `**filename.md**` plan names from a list_plans response. */
17
+ export function parsePlanFilenames(listText) {
18
+ const matches = listText.match(/\*\*([^*]+\.md)\*\*/g) ?? [];
19
+ return matches.map((m) => m.replace(/\*\*/g, ""));
20
+ }
21
+ /** Pick the newest plan. Filenames are date-prefixed (YYYY-MM-DD-...), so lexical desc = newest. */
22
+ export function latestPlanFilename(listText) {
23
+ const names = parsePlanFilenames(listText);
24
+ if (names.length === 0)
25
+ return null;
26
+ return [...names].sort((a, b) => b.localeCompare(a))[0] ?? null;
27
+ }
28
+ /** Pull the Verification Checklist items out of a plan's Markdown. */
29
+ export function parseChecklist(planText) {
30
+ const section = planText.match(/##\s*Verification Checklist\s*\n([\s\S]*?)(?=\n##\s|$)/i);
31
+ if (!section?.[1])
32
+ return [];
33
+ return section[1]
34
+ .split("\n")
35
+ .map((l) => l.trim())
36
+ .filter((l) => /^- \[[ x]\]/i.test(l))
37
+ .map((l) => l.replace(/^- \[[ x]\]\s*/i, ""));
38
+ }
39
+ /** Build a unique, sortable branch name for a kos run. */
40
+ export function buildKosBranch(now = new Date()) {
41
+ const stamp = now.toISOString().replace(/[:.]/g, "-").replace("T", "-").slice(0, 19);
42
+ return `mnemos/kos-${stamp}`;
43
+ }
44
+ /** The instruction handed to the assistant. The plan file is the real contract. */
45
+ export const KOS_PROMPT = "Implement the plan in MNEMOS_PLAN.md in this repository. " +
46
+ "Follow the Codebase Mapping table exactly — change only the files it lists. " +
47
+ "For each step apply the thinking effort named in its Effort column " +
48
+ "(low = quick/mechanical, medium = careful, high = deep reasoning). " +
49
+ "When finished, make sure every item in the Verification Checklist is satisfied.";
50
+ // ── Orchestrator ──
51
+ function run(cmd, cwd) {
52
+ return execSync(cmd, { cwd, stdio: ["pipe", "pipe", "pipe"] }).toString().trim();
53
+ }
54
+ export async function kos(apiKey, opts = {}) {
55
+ const cfg = readConfig();
56
+ if (!cfg.agent) {
57
+ console.error("No agent configured. Tell Mnemos which AI assistant to drive:\n");
58
+ console.error(' mnemos config set agent "claude -p" # Claude Code');
59
+ console.error(' mnemos config set agent "codex exec" # Codex');
60
+ console.error(' mnemos config set agent "aider --yes --message" # Aider');
61
+ process.exit(1);
62
+ }
63
+ // 1. Resolve the plan — explicit filename, or the newest saved plan
64
+ const planFile = opts.plan ?? latestPlanFilename((await callMcp(apiKey, "list_plans", {}, 15000)) ?? "");
65
+ if (!planFile) {
66
+ console.error("No plans found. Generate one first with the generate_plan MCP tool.");
67
+ process.exit(1);
68
+ }
69
+ const planText = await callMcp(apiKey, "list_plans", { filename: planFile }, 15000);
70
+ if (!planText || !planText.trim()) {
71
+ console.error(`Could not read plan: ${planFile}`);
72
+ process.exit(1);
73
+ }
74
+ // 2. Must be inside a git repo
75
+ let repoRoot;
76
+ try {
77
+ repoRoot = run("git rev-parse --show-toplevel");
78
+ }
79
+ catch {
80
+ console.error("mnemos kos must be run inside a git repository.");
81
+ process.exit(1);
82
+ return;
83
+ }
84
+ // 3. Isolated worktree on a fresh branch
85
+ const branch = buildKosBranch();
86
+ const worktreePath = join(tmpdir(), branch.replace(/\//g, "-"));
87
+ console.log(`Creating isolated worktree on branch ${branch}...`);
88
+ run(`git worktree add -b ${branch} "${worktreePath}"`, repoRoot);
89
+ // 4. Drop the plan in and keep git from tracking it (local exclude, not committed)
90
+ writeFileSync(join(worktreePath, "MNEMOS_PLAN.md"), planText);
91
+ try {
92
+ const excludePath = join(repoRoot, ".git", "info", "exclude");
93
+ if (existsSync(excludePath)) {
94
+ const current = readFileSync(excludePath, "utf-8");
95
+ if (!current.includes("MNEMOS_PLAN.md"))
96
+ appendFileSync(excludePath, "\nMNEMOS_PLAN.md\n");
97
+ }
98
+ }
99
+ catch {
100
+ // best-effort
101
+ }
102
+ // 5. Hand off to the user's assistant, running inside the worktree
103
+ console.log(`Launching: ${cfg.agent}\n`);
104
+ try {
105
+ execSync(`${cfg.agent} ${JSON.stringify(KOS_PROMPT)}`, { cwd: worktreePath, stdio: "inherit" });
106
+ }
107
+ catch {
108
+ console.error("\nThe agent exited with an error. The worktree is preserved for inspection.");
109
+ }
110
+ // 6. Report — branch + the plan's own checklist as the review gate
111
+ const checklist = parseChecklist(planText);
112
+ console.log(`\n${"─".repeat(60)}`);
113
+ console.log(`kos finished. Plan: ${planFile}`);
114
+ console.log(`Branch: ${branch}`);
115
+ console.log(`Worktree: ${worktreePath}`);
116
+ if (checklist.length > 0) {
117
+ console.log(`\nVerify before merging:`);
118
+ for (const item of checklist)
119
+ console.log(` [ ] ${item}`);
120
+ }
121
+ console.log(`\nReview the branch, then merge. Clean up the worktree with:`);
122
+ console.log(` git worktree remove "${worktreePath}"`);
123
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mnemos-capture",
3
- "version": "1.1.0",
4
- "description": "Zero-friction knowledge capture for agentic workflows. Paste anything → Claude extracts insights → auto-commits to your knowledge repo → your Claude Code workflow picks it up.",
3
+ "version": "1.2.0",
4
+ "description": "Capture anything. Your agents apply it. A knowledge pipeline that ingests the outside world and makes it directly actionable by any AI agent over MCP.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "mnemos-capture": "./dist/cli/index.js"
@@ -11,7 +11,9 @@
11
11
  "build": "next build",
12
12
  "start": "next start",
13
13
  "build:cli": "tsc -p cli/tsconfig.json",
14
- "prepublishOnly": "npm run build:cli"
14
+ "prepublishOnly": "npm run build:cli",
15
+ "test": "vitest run",
16
+ "test:watch": "vitest"
15
17
  },
16
18
  "keywords": [
17
19
  "ai",
@@ -51,7 +53,8 @@
51
53
  "autoprefixer": "^10.4.21",
52
54
  "postcss": "^8.5.3",
53
55
  "tailwindcss": "^3.4.17",
54
- "typescript": "^5"
56
+ "typescript": "^5",
57
+ "vitest": "^4.1.8"
55
58
  },
56
59
  "engines": {
57
60
  "node": ">=18"