mnotes-cli 1.7.1 → 1.9.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/client.d.ts CHANGED
@@ -72,6 +72,31 @@ export declare function createClient(baseUrl: string, apiKey: string): {
72
72
  isDefault: boolean;
73
73
  }>;
74
74
  }>;
75
+ queryGraph(opts?: {
76
+ workspaceId?: string;
77
+ query?: string;
78
+ nodeType?: string;
79
+ neighbors?: string;
80
+ depth?: number;
81
+ limit?: number;
82
+ }): Promise<{
83
+ data: {
84
+ nodes: Array<{
85
+ id: string;
86
+ noteId: string | null;
87
+ label: string;
88
+ nodeType: string;
89
+ depth?: number;
90
+ }>;
91
+ edges: Array<{
92
+ id: string;
93
+ sourceId: string;
94
+ targetId: string;
95
+ edgeType: string;
96
+ weight: number;
97
+ }>;
98
+ };
99
+ }>;
75
100
  createWorkspace(name: string): Promise<{
76
101
  data: {
77
102
  id: string;
package/dist/client.js CHANGED
@@ -51,6 +51,23 @@ function createClient(baseUrl, apiKey) {
51
51
  async listWorkspaces() {
52
52
  return request("GET", "/api/v1/workspaces");
53
53
  },
54
+ async queryGraph(opts) {
55
+ const params = new URLSearchParams();
56
+ if (opts?.workspaceId)
57
+ params.set("workspaceId", opts.workspaceId);
58
+ if (opts?.query)
59
+ params.set("query", opts.query);
60
+ if (opts?.nodeType)
61
+ params.set("nodeType", opts.nodeType);
62
+ if (opts?.neighbors)
63
+ params.set("neighbors", opts.neighbors);
64
+ if (opts?.depth)
65
+ params.set("depth", String(opts.depth));
66
+ if (opts?.limit)
67
+ params.set("limit", String(opts.limit));
68
+ const qs = params.toString();
69
+ return request("GET", `/api/v1/graph${qs ? `?${qs}` : ""}`);
70
+ },
54
71
  async createWorkspace(name) {
55
72
  return request("POST", "/api/v1/workspaces", { name });
56
73
  },
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function registerRecallKnowledgeCommand(program: Command): void;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerRecallKnowledgeCommand = registerRecallKnowledgeCommand;
4
+ const config_1 = require("../config");
5
+ const client_1 = require("../client");
6
+ const output_1 = require("../output");
7
+ function registerRecallKnowledgeCommand(program) {
8
+ program
9
+ .command("recall_knowledge")
10
+ .description("Query the knowledge graph (read-only)")
11
+ .option("--query <text>", "Filter nodes by label (case-insensitive)")
12
+ .option("--type <type>", "Filter by node type: note, tag, concept")
13
+ .option("--neighbors <nodeId>", "Show neighbors of a specific node")
14
+ .option("--depth <n>", "Neighbor traversal depth (1-3, default 1)", "1")
15
+ .option("--limit <n>", "Max nodes to return (default 50)", "50")
16
+ .option("--workspace-id <id>", "Workspace ID")
17
+ .action(async (opts) => {
18
+ const globalOpts = program.opts();
19
+ const config = (0, config_1.resolveConfig)(globalOpts);
20
+ const client = (0, client_1.createClient)(config.baseUrl, config.apiKey);
21
+ const result = await client.queryGraph({
22
+ workspaceId: opts.workspaceId || config.workspaceId,
23
+ query: opts.query,
24
+ nodeType: opts.type,
25
+ neighbors: opts.neighbors,
26
+ depth: opts.depth ? parseInt(opts.depth, 10) : undefined,
27
+ limit: opts.limit ? parseInt(opts.limit, 10) : undefined,
28
+ });
29
+ if (globalOpts.json) {
30
+ (0, output_1.printJson)(result.data);
31
+ }
32
+ else {
33
+ (0, output_1.printGraph)(result.data.nodes, result.data.edges);
34
+ }
35
+ });
36
+ }
package/dist/index.js CHANGED
@@ -11,6 +11,7 @@ const delete_1 = require("./commands/delete");
11
11
  const connect_1 = require("./commands/connect");
12
12
  const login_1 = require("./commands/login");
13
13
  const workspace_1 = require("./commands/workspace");
14
+ const recall_knowledge_1 = require("./commands/recall-knowledge");
14
15
  const program = new commander_1.Command();
15
16
  program
16
17
  .name("mnotes")
@@ -28,6 +29,7 @@ program
28
29
  (0, connect_1.registerConnectCommand)(program);
29
30
  (0, login_1.registerLoginCommand)(program);
30
31
  (0, workspace_1.registerWorkspaceCommand)(program);
32
+ (0, recall_knowledge_1.registerRecallKnowledgeCommand)(program);
31
33
  program.parseAsync(process.argv).catch((err) => {
32
34
  process.stderr.write(`Error: ${err.message}\n`);
33
35
  process.exit(1);
package/dist/output.d.ts CHANGED
@@ -14,4 +14,17 @@ export declare function printSearchResults(results: Array<{
14
14
  title: string;
15
15
  snippet?: string;
16
16
  }>): void;
17
+ export declare function printGraph(nodes: Array<{
18
+ id: string;
19
+ noteId: string | null;
20
+ label: string;
21
+ nodeType: string;
22
+ depth?: number;
23
+ }>, edges: Array<{
24
+ id: string;
25
+ sourceId: string;
26
+ targetId: string;
27
+ edgeType: string;
28
+ weight: number;
29
+ }>): void;
17
30
  export declare function printSuccess(msg: string): void;
package/dist/output.js CHANGED
@@ -4,6 +4,7 @@ exports.printJson = printJson;
4
4
  exports.printNoteList = printNoteList;
5
5
  exports.printNote = printNote;
6
6
  exports.printSearchResults = printSearchResults;
7
+ exports.printGraph = printGraph;
7
8
  exports.printSuccess = printSuccess;
8
9
  function printJson(data) {
9
10
  console.log(JSON.stringify(data, null, 2));
@@ -42,6 +43,34 @@ function printSearchResults(results) {
42
43
  }
43
44
  }
44
45
  }
46
+ function printGraph(nodes, edges) {
47
+ if (nodes.length === 0) {
48
+ process.stderr.write("Knowledge graph is empty.\n");
49
+ return;
50
+ }
51
+ const idWidth = Math.max(4, ...nodes.map((n) => n.id.length));
52
+ const typeWidth = Math.max(4, ...nodes.map((n) => n.nodeType.length));
53
+ const labelWidth = Math.min(50, Math.max(5, ...nodes.map((n) => n.label.length)));
54
+ console.log(`${"ID".padEnd(idWidth)} ${"TYPE".padEnd(typeWidth)} LABEL`);
55
+ for (const node of nodes) {
56
+ const label = node.label.length > labelWidth
57
+ ? node.label.substring(0, labelWidth - 1) + "…"
58
+ : node.label;
59
+ const depthSuffix = node.depth !== undefined && node.depth > 0 ? ` (depth ${node.depth})` : "";
60
+ console.log(`${node.id.padEnd(idWidth)} ${node.nodeType.padEnd(typeWidth)} ${label}${depthSuffix}`);
61
+ }
62
+ if (edges.length > 0) {
63
+ console.log("");
64
+ console.log(`Edges (${edges.length}):`);
65
+ for (const edge of edges) {
66
+ const srcLabel = nodes.find((n) => n.id === edge.sourceId)?.label ?? edge.sourceId;
67
+ const tgtLabel = nodes.find((n) => n.id === edge.targetId)?.label ?? edge.targetId;
68
+ console.log(` ${srcLabel} --[${edge.edgeType}]--> ${tgtLabel}`);
69
+ }
70
+ }
71
+ console.log("");
72
+ console.log(`${nodes.length} node(s), ${edges.length} edge(s)`);
73
+ }
45
74
  function printSuccess(msg) {
46
75
  process.stderr.write(`${msg}\n`);
47
76
  }
@@ -65,6 +65,46 @@ m-notes is not just a knowledge base — it's a full note-taking system. **Use n
65
65
 
66
66
  **When in doubt, create a note.** Notes are searchable, linkable, and visible in the UI.
67
67
 
68
+ ## Knowledge Graph — Build Structured Memory
69
+
70
+ Beyond flat knowledge entries, you have a **knowledge graph** for structured relationships between concepts. Use it to map how things connect — architecture components, dependencies, decisions, and patterns.
71
+
72
+ ### When to Build the Graph
73
+ - **Session start**: If the graph is empty, call \`populate_graph\` to initialize from existing notes and wikilinks.
74
+ - **Architecture decisions**: Create concept nodes for components, link them with "related" or "parent" edges.
75
+ - **Dependency discovery**: Create nodes for packages, link to the components that use them.
76
+ - **Bug investigations**: Link bug nodes to the components and patterns involved.
77
+ - **Any time you see a relationship**: If A relates to B, create an edge. The graph gets more valuable over time.
78
+
79
+ ### Graph Tools
80
+ | Tool | When to use |
81
+ |------|------------|
82
+ | \`populate_graph\` | Initialize graph from existing notes (idempotent, safe to re-run) |
83
+ | \`create_node\` | Create a concept, tag, or note-linked node |
84
+ | \`create_edge\` | Link two nodes (types: wikilink, related, parent, tagged, custom) |
85
+ | \`query_graph\` | Search the graph by node type, label, or connectivity |
86
+ | \`get_neighbors\` | Explore nodes connected to a specific node |
87
+ | \`query_note_graph\` | Get the connection subgraph around a note |
88
+
89
+ ### Node Types
90
+ - **note** — linked to an existing note (set \`noteId\`)
91
+ - **tag** — represents a tag or category
92
+ - **concept** — free-form concept (architecture component, pattern, decision)
93
+
94
+ ### Edge Types
95
+ - **wikilink** — note links to another note
96
+ - **related** — general relationship
97
+ - **parent** — hierarchical (component contains sub-component)
98
+ - **tagged** — node is tagged with a category
99
+ - **custom** — any other relationship (describe in metadata)
100
+
101
+ ### Example: Mapping Architecture
102
+ \`\`\`
103
+ create_node({ label: "Auth Module", nodeType: "concept", workspaceId: "..." })
104
+ create_node({ label: "PostgreSQL", nodeType: "concept", workspaceId: "..." })
105
+ create_edge({ sourceId: authNodeId, targetId: pgNodeId, edgeType: "related", workspaceId: "..." })
106
+ \`\`\`
107
+
68
108
  ## MCP Tools Reference
69
109
 
70
110
  ### Session & Context
@@ -104,5 +144,15 @@ m-notes is not just a knowledge base — it's a full note-taking system. **Use n
104
144
  | \`move_note\` | Move note to a different folder |
105
145
  | \`context_fetch\` | Search notes by query |
106
146
 
147
+ ### Knowledge Graph
148
+ | Tool | When to use |
149
+ |------|------------|
150
+ | \`populate_graph\` | Initialize graph from notes (run once at start) |
151
+ | \`create_node\` | Add a concept, tag, or note-linked node |
152
+ | \`create_edge\` | Link two nodes with a typed relationship |
153
+ | \`query_graph\` | Search graph by type, label, or connectivity |
154
+ | \`get_neighbors\` | Explore connections from a node |
155
+ | \`query_note_graph\` | Get subgraph around a specific note |
156
+
107
157
  All tools require \`workspaceId: "${opts.workspaceId}"\`.`;
108
158
  }
@@ -31,6 +31,22 @@ Store discoveries, decisions, and patterns via \`knowledge_store\`:
31
31
  ### Session End
32
32
  Call \`session_log\` with workspaceId "${opts.workspaceId}", a summary, decisions, and actions.
33
33
 
34
+ ## Knowledge Graph
35
+
36
+ Build structured relationships between concepts as you work. The graph maps how architecture components, dependencies, decisions, and patterns connect.
37
+
38
+ ### When to Build
39
+ - Session start: call \`populate_graph\` if graph is empty (idempotent)
40
+ - When you discover relationships between components, patterns, or decisions: create nodes and edges
41
+ - Architecture decisions: create concept nodes, link with "related" or "parent" edges
42
+
43
+ ### Node types: note, tag, concept
44
+ ### Edge types: wikilink, related, parent, tagged, custom
45
+
46
+ Example:
47
+ create_node({ label: "Auth Module", nodeType: "concept", workspaceId: "${opts.workspaceId}" })
48
+ create_edge({ sourceId: "...", targetId: "...", edgeType: "related", workspaceId: "${opts.workspaceId}" })
49
+
34
50
  ## Available MCP Tools
35
51
  - project_context_load -- load project context at session start
36
52
  - session_context_resume -- resume from previous session
@@ -39,5 +55,10 @@ Call \`session_log\` with workspaceId "${opts.workspaceId}", a summary, decision
39
55
  - bulk_knowledge_recall -- recall by tag patterns
40
56
  - knowledge_snapshot -- export all knowledge
41
57
  - session_log -- log session summary
42
- - context_fetch -- search notes by query`;
58
+ - context_fetch -- search notes by query
59
+ - populate_graph -- initialize knowledge graph from notes
60
+ - create_node -- add a concept/tag/note node to the graph
61
+ - create_edge -- link two nodes with a typed relationship
62
+ - query_graph -- search graph by type, label, or connectivity
63
+ - get_neighbors -- explore connections from a node`;
43
64
  }
@@ -31,10 +31,35 @@ Call recall_knowledge with:
31
31
  - \`bug/{id}\` -- bug investigations
32
32
  - \`pattern/{name}\` -- code patterns
33
33
 
34
+ ## Knowledge Graph
35
+
36
+ Build structured relationships as you work:
37
+ \`\`\`
38
+ Call populate_graph with:
39
+ - workspaceId: "${opts.workspaceId}"
40
+ (initializes graph from existing notes — run once)
41
+
42
+ Call create_node with:
43
+ - label: "<concept name>"
44
+ - nodeType: "concept" (or "note", "tag")
45
+ - workspaceId: "${opts.workspaceId}"
46
+
47
+ Call create_edge with:
48
+ - sourceId: "<node id>"
49
+ - targetId: "<node id>"
50
+ - edgeType: "related" (or "parent", "tagged", "custom")
51
+ - workspaceId: "${opts.workspaceId}"
52
+ \`\`\`
53
+
34
54
  ## Available MCP Tools
35
55
  - \`knowledge_store\` -- Store knowledge entries
36
56
  - \`recall_knowledge\` -- Semantic search for knowledge
37
57
  - \`bulk_knowledge_recall\` -- Recall by tag patterns
38
58
  - \`knowledge_snapshot\` -- Export all knowledge
39
- - \`context_fetch\` -- Search notes by query`;
59
+ - \`context_fetch\` -- Search notes by query
60
+ - \`populate_graph\` -- Initialize knowledge graph from notes
61
+ - \`create_node\` -- Add concept/tag/note node to the graph
62
+ - \`create_edge\` -- Link two nodes with a typed relationship
63
+ - \`query_graph\` -- Search graph by type, label, or connectivity
64
+ - \`get_neighbors\` -- Explore connections from a node`;
40
65
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mnotes-cli",
3
- "version": "1.7.1",
3
+ "version": "1.9.0",
4
4
  "description": "CLI for m-notes AI knowledge base — manage notes, search, and CRUD from the terminal",
5
5
  "bin": {
6
6
  "mnotes": "./dist/index.js"