mnotes-cli 1.7.0 → 1.8.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
  },
@@ -40,6 +40,7 @@ const fs = __importStar(require("fs"));
40
40
  const path = __importStar(require("path"));
41
41
  const config_utils_1 = require("./config-utils");
42
42
  const workspace_prompt_1 = require("./workspace-prompt");
43
+ const config_1 = require("../../config");
43
44
  const claude_code_1 = require("../../templates/claude-code");
44
45
  const codex_1 = require("../../templates/codex");
45
46
  const openclaw_1 = require("../../templates/openclaw");
@@ -91,11 +92,11 @@ function printConnectionStatus() {
91
92
  * prompts interactively after validating the connection.
92
93
  */
93
94
  async function resolveWorkspace(opts) {
94
- // AC-5: --workspace flag works as before
95
- const fromFlag = opts.workspace || process.env.MNOTES_WORKSPACE_ID;
96
- if (fromFlag)
97
- return fromFlag;
98
- // AC-1/AC-2/AC-3/AC-4: Interactive workspace selection/creation
95
+ // Check flag, env, dir map, global config
96
+ const fromConfig = (0, config_1.resolveConfig)({ workspaceId: opts.workspace });
97
+ if (fromConfig.workspaceId)
98
+ return fromConfig.workspaceId;
99
+ // Nothing stored interactive selection/creation
99
100
  const resolved = await (0, workspace_prompt_1.resolveWorkspaceInteractively)(opts.url, opts.apiKey);
100
101
  return resolved.id;
101
102
  }
@@ -110,12 +111,9 @@ function normalizeBaseUrl(raw) {
110
111
  return raw.replace(/\/+$/, "").replace(/\/api\/mcp$/i, "");
111
112
  }
112
113
  async function handleClaudeCode(opts) {
113
- const url = normalizeBaseUrl(opts.url || process.env.MNOTES_URL || "https://mnotes.framework.by");
114
- const apiKey = opts.apiKey || process.env.MNOTES_API_KEY;
115
- if (!apiKey) {
116
- process.stderr.write("Error: API key required. Use --api-key or set MNOTES_API_KEY\n");
117
- process.exit(1);
118
- }
114
+ const config = (0, config_1.resolveConfig)(opts);
115
+ const url = normalizeBaseUrl(config.baseUrl);
116
+ const apiKey = config.apiKey;
119
117
  const validation = await (0, config_utils_1.validateConnection)(url, apiKey);
120
118
  if (!validation.ok) {
121
119
  process.stderr.write(`Error: Cannot connect to ${url}: ${validation.error}\n`);
@@ -179,12 +177,9 @@ function printScaffoldResults(results) {
179
177
  * Handles the `codex` integration target.
180
178
  */
181
179
  async function handleCodex(opts) {
182
- const url = normalizeBaseUrl(opts.url || process.env.MNOTES_URL || "https://mnotes.framework.by");
183
- const apiKey = opts.apiKey || process.env.MNOTES_API_KEY;
184
- if (!apiKey) {
185
- process.stderr.write("Error: API key required. Use --api-key or set MNOTES_API_KEY\n");
186
- process.exit(1);
187
- }
180
+ const config = (0, config_1.resolveConfig)(opts);
181
+ const url = normalizeBaseUrl(config.baseUrl);
182
+ const apiKey = config.apiKey;
188
183
  const validation = await (0, config_utils_1.validateConnection)(url, apiKey);
189
184
  if (!validation.ok) {
190
185
  process.stderr.write(`Error: Cannot connect to ${url}: ${validation.error}\n`);
@@ -216,13 +211,10 @@ async function handleCodex(opts) {
216
211
  * Handles the `openclaw` integration target.
217
212
  */
218
213
  async function handleOpenClaw(opts) {
219
- const url = normalizeBaseUrl(opts.url || process.env.MNOTES_URL || "https://mnotes.framework.by");
220
- const apiKey = opts.apiKey || process.env.MNOTES_API_KEY;
214
+ const config = (0, config_1.resolveConfig)(opts);
215
+ const url = normalizeBaseUrl(config.baseUrl);
216
+ const apiKey = config.apiKey;
221
217
  const configPath = opts.configPath || path.join(process.env.HOME || "~", ".openclaw", "mcp.json");
222
- if (!apiKey) {
223
- process.stderr.write("Error: API key required. Use --api-key or set MNOTES_API_KEY\n");
224
- process.exit(1);
225
- }
226
218
  const validation = await (0, config_utils_1.validateConnection)(url, apiKey);
227
219
  if (!validation.ok) {
228
220
  process.stderr.write(`Error: Cannot connect to ${url}: ${validation.error}\n`);
@@ -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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mnotes-cli",
3
- "version": "1.7.0",
3
+ "version": "1.8.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"