@nodex-studio/mcp 0.0.1
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/README.md +96 -0
- package/bin/nodex-mcp.js +2 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +7 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +12 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +30 -0
- package/dist/config.js.map +1 -0
- package/dist/find-wpn.d.ts +66 -0
- package/dist/find-wpn.d.ts.map +1 -0
- package/dist/find-wpn.js +188 -0
- package/dist/find-wpn.js.map +1 -0
- package/dist/find-wpn.test.d.ts +2 -0
- package/dist/find-wpn.test.d.ts.map +1 -0
- package/dist/find-wpn.test.js +59 -0
- package/dist/find-wpn.test.js.map +1 -0
- package/dist/resolve-note.d.ts +34 -0
- package/dist/resolve-note.d.ts.map +1 -0
- package/dist/resolve-note.js +42 -0
- package/dist/resolve-note.js.map +1 -0
- package/dist/resolve-note.test.d.ts +2 -0
- package/dist/resolve-note.test.d.ts.map +1 -0
- package/dist/resolve-note.test.js +72 -0
- package/dist/resolve-note.test.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +257 -0
- package/dist/server.js.map +1 -0
- package/dist/text-result.d.ts +11 -0
- package/dist/text-result.d.ts.map +1 -0
- package/dist/text-result.js +17 -0
- package/dist/text-result.js.map +1 -0
- package/dist/wpn-client.d.ts +51 -0
- package/dist/wpn-client.d.ts.map +1 -0
- package/dist/wpn-client.js +140 -0
- package/dist/wpn-client.js.map +1 -0
- package/package.json +31 -0
package/README.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# @nodex-studio/mcp
|
|
2
|
+
|
|
3
|
+
stdio [Model Context Protocol](https://modelcontextprotocol.io) server for **Nodex** workspace/project/note (WPN) data. It calls the same HTTP JSON API as the web client:
|
|
4
|
+
|
|
5
|
+
- **Cloud:** `nodex-sync-api` or Next colocated `/api/v1` (Mongo WPN + JWT).
|
|
6
|
+
- **Local:** Electron **loopback** bridge on `127.0.0.1` (file vault), enabled with `NODEX_WPN_LOCAL_HTTP=1`.
|
|
7
|
+
|
|
8
|
+
## Tools
|
|
9
|
+
|
|
10
|
+
| Tool | Purpose |
|
|
11
|
+
|------|---------|
|
|
12
|
+
| `nodex_find_projects` | Find by project **name or UUID**; optional `workspaceQuery`. Returns `status` + `matches` with `path` `Workspace / Project`; `ambiguous` / `workspace_ambiguous` list all candidates. |
|
|
13
|
+
| `nodex_find_notes` | Find by note **title or UUID**; optional `workspaceQuery` / `projectQuery`. Returns `path` `Workspace / Project / Title`; `ambiguous`, `workspace_ambiguous`, `project_ambiguous` as needed. |
|
|
14
|
+
| `nodex_list_wpn` | `scope`: `workspaces` \| `projects`+`workspaceId` \| `notes`+`projectId` \| `full_tree` — same data as GET `/wpn/workspaces`, `/wpn/workspaces/…/projects`, `/wpn/projects/…/notes`. |
|
|
15
|
+
| `nodex_resolve_note` | Match `workspaceName` + `projectName` + `noteTitle` (trim, case-insensitive) → canonical `noteId`. Errors with `candidates` if ambiguous. |
|
|
16
|
+
| `nodex_get_note` | `GET /wpn/notes/:id` — full note including `content`. |
|
|
17
|
+
| `nodex_write_note` | Discriminated `mode`: `patch_existing`, `create_root`, `create_child`, `create_sibling` (maps to `PATCH` / `POST` WPN routes). |
|
|
18
|
+
|
|
19
|
+
**Binary / cloud assets:** sync-api `/me/assets` may return 501 until implemented; embed text in markdown or use URLs the host can fetch. Local assets stay on disk under the project folder (Electron).
|
|
20
|
+
|
|
21
|
+
## Environment
|
|
22
|
+
|
|
23
|
+
### Cloud (Cursor / Claude Desktop / Windsurf / CI)
|
|
24
|
+
|
|
25
|
+
- `NODEX_SYNC_API_BASE` — must include `/api/v1` (e.g. `http://127.0.0.1:4010/api/v1` or `https://your-host/api/v1`).
|
|
26
|
+
- `NODEX_ACCESS_TOKEN` **or** `NODEX_JWT` — raw JWT string (no `Bearer ` prefix).
|
|
27
|
+
|
|
28
|
+
### Local (Electron file vault + MCP)
|
|
29
|
+
|
|
30
|
+
1. Start Electron with a folder vault open.
|
|
31
|
+
2. Set in the **main** process env: `NODEX_WPN_LOCAL_HTTP=1` (see [`.env.example`](../../.env.example)). Optional: `NODEX_WPN_LOCAL_HTTP_PORT`, `NODEX_LOCAL_WPN_TOKEN`.
|
|
32
|
+
3. Read `baseUrl` and `token` from Electron userData file `nodex-local-wpn-mcp.json` (written when the bridge starts), **or** set the same token in both Electron and MCP.
|
|
33
|
+
4. MCP env:
|
|
34
|
+
|
|
35
|
+
- `NODEX_LOCAL_WPN_URL` — e.g. `http://127.0.0.1:41234` (no `/api/v1` suffix for the bridge).
|
|
36
|
+
- `NODEX_LOCAL_WPN_TOKEN` — Bearer secret matching the bridge.
|
|
37
|
+
|
|
38
|
+
**Security:** Any local process can reach `127.0.0.1`; the bearer token is the gate. Disable the bridge when not needed (`NODEX_WPN_LOCAL_HTTP` unset).
|
|
39
|
+
|
|
40
|
+
## Run
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# from repo root (after npm install)
|
|
44
|
+
npm run build -w @nodex-studio/mcp
|
|
45
|
+
node packages/nodex-mcp/dist/cli.js
|
|
46
|
+
# or
|
|
47
|
+
npm run dev -w @nodex-studio/mcp
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Example: Cursor MCP (`mcp.json`)
|
|
51
|
+
|
|
52
|
+
Cloud:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"mcpServers": {
|
|
57
|
+
"nodex": {
|
|
58
|
+
"command": "node",
|
|
59
|
+
"args": ["/absolute/path/to/nodex/packages/nodex-mcp/dist/cli.js"],
|
|
60
|
+
"env": {
|
|
61
|
+
"NODEX_SYNC_API_BASE": "http://127.0.0.1:4010/api/v1",
|
|
62
|
+
"NODEX_ACCESS_TOKEN": "<jwt-from-login>"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Local (after Electron wrote `nodex-local-wpn-mcp.json` or you set a fixed token):
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"mcpServers": {
|
|
74
|
+
"nodex-local": {
|
|
75
|
+
"command": "node",
|
|
76
|
+
"args": ["/absolute/path/to/nodex/packages/nodex-mcp/dist/cli.js"],
|
|
77
|
+
"env": {
|
|
78
|
+
"NODEX_LOCAL_WPN_URL": "http://127.0.0.1:41234",
|
|
79
|
+
"NODEX_LOCAL_WPN_TOKEN": "<same-as-electron>"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## CI
|
|
87
|
+
|
|
88
|
+
Use a machine-safe JWT (service account or long-lived test user) with `NODEX_SYNC_API_BASE` + `NODEX_ACCESS_TOKEN`. Do not commit secrets; inject via CI secrets.
|
|
89
|
+
|
|
90
|
+
## Tests
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npm test -w @nodex-studio/mcp
|
|
94
|
+
# from repo root:
|
|
95
|
+
npm run test:mcp
|
|
96
|
+
```
|
package/bin/nodex-mcp.js
ADDED
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,KAAK,iBAAiB,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACrC,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;IAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve HTTP base + bearer for WPN calls.
|
|
3
|
+
*
|
|
4
|
+
* Cloud: NODEX_SYNC_API_BASE (must include `/api/v1`) + NODEX_ACCESS_TOKEN or NODEX_JWT.
|
|
5
|
+
* Local: NODEX_LOCAL_WPN_URL (e.g. http://127.0.0.1:41234) + NODEX_LOCAL_WPN_TOKEN.
|
|
6
|
+
*/
|
|
7
|
+
export type WpnHttpConfig = {
|
|
8
|
+
baseUrl: string;
|
|
9
|
+
bearerToken: string;
|
|
10
|
+
};
|
|
11
|
+
export declare function loadWpnHttpConfig(): WpnHttpConfig;
|
|
12
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAcF,wBAAgB,iBAAiB,IAAI,aAAa,CAwBjD"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
function trimSlash(s) {
|
|
2
|
+
return s.replace(/\/+$/, "");
|
|
3
|
+
}
|
|
4
|
+
function normalizeSyncBase(raw) {
|
|
5
|
+
const t = trimSlash(raw.trim());
|
|
6
|
+
if (t.endsWith("/api/v1")) {
|
|
7
|
+
return t;
|
|
8
|
+
}
|
|
9
|
+
return `${t}/api/v1`;
|
|
10
|
+
}
|
|
11
|
+
export function loadWpnHttpConfig() {
|
|
12
|
+
const localUrl = process.env.NODEX_LOCAL_WPN_URL?.trim();
|
|
13
|
+
const localToken = process.env.NODEX_LOCAL_WPN_TOKEN?.trim();
|
|
14
|
+
if (localUrl && localToken) {
|
|
15
|
+
return { baseUrl: trimSlash(localUrl), bearerToken: localToken };
|
|
16
|
+
}
|
|
17
|
+
const syncRaw = process.env.NODEX_SYNC_API_BASE?.trim();
|
|
18
|
+
if (!syncRaw) {
|
|
19
|
+
throw new Error("Set either (NODEX_LOCAL_WPN_URL + NODEX_LOCAL_WPN_TOKEN) for Electron loopback, or " +
|
|
20
|
+
"NODEX_SYNC_API_BASE (+ NODEX_ACCESS_TOKEN or NODEX_JWT) for cloud sync-api.");
|
|
21
|
+
}
|
|
22
|
+
const token = process.env.NODEX_ACCESS_TOKEN?.trim() ||
|
|
23
|
+
process.env.NODEX_JWT?.trim() ||
|
|
24
|
+
"";
|
|
25
|
+
if (!token) {
|
|
26
|
+
throw new Error("Cloud mode requires NODEX_ACCESS_TOKEN or NODEX_JWT (Bearer value, no 'Bearer ' prefix).");
|
|
27
|
+
}
|
|
28
|
+
return { baseUrl: normalizeSyncBase(syncRaw), bearerToken: token };
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAWA,SAAS,SAAS,CAAC,CAAS;IAC1B,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAC/B,CAAC;AAED,SAAS,iBAAiB,CAAC,GAAW;IACpC,MAAM,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IAChC,IAAI,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,CAAC;IACX,CAAC;IACD,OAAO,GAAG,CAAC,SAAS,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,IAAI,EAAE,CAAC;IACzD,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,IAAI,EAAE,CAAC;IAC7D,IAAI,QAAQ,IAAI,UAAU,EAAE,CAAC;QAC3B,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,QAAQ,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC;IACnE,CAAC;IAED,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,IAAI,EAAE,CAAC;IACxD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,qFAAqF;YACnF,6EAA6E,CAChF,CAAC;IACJ,CAAC;IACD,MAAM,KAAK,GACT,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,IAAI,EAAE;QACtC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,EAAE;QAC7B,EAAE,CAAC;IACL,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACb,0FAA0F,CAC3F,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,iBAAiB,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;AACrE,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { WpnHttpClient } from "./wpn-client.js";
|
|
2
|
+
import type { WpnNoteWithContextRow } from "./wpn-client.js";
|
|
3
|
+
/** RFC-style UUID v1–v5 (loose check for id vs name disambiguation). */
|
|
4
|
+
export declare function isLikelyUuid(s: string): boolean;
|
|
5
|
+
export type ProjectPathRow = {
|
|
6
|
+
projectId: string;
|
|
7
|
+
projectName: string;
|
|
8
|
+
workspaceId: string;
|
|
9
|
+
workspaceName: string;
|
|
10
|
+
path: string;
|
|
11
|
+
};
|
|
12
|
+
export type WorkspaceRef = {
|
|
13
|
+
workspaceId: string;
|
|
14
|
+
workspaceName: string;
|
|
15
|
+
};
|
|
16
|
+
export type NotePathRow = {
|
|
17
|
+
noteId: string;
|
|
18
|
+
title: string;
|
|
19
|
+
type: string;
|
|
20
|
+
projectId: string;
|
|
21
|
+
projectName: string;
|
|
22
|
+
workspaceId: string;
|
|
23
|
+
workspaceName: string;
|
|
24
|
+
path: string;
|
|
25
|
+
};
|
|
26
|
+
export declare function findProjectsByQuery(client: WpnHttpClient, query: string, workspaceQuery?: string): Promise<{
|
|
27
|
+
status: "none";
|
|
28
|
+
message: string;
|
|
29
|
+
} | {
|
|
30
|
+
status: "workspace_ambiguous";
|
|
31
|
+
message: string;
|
|
32
|
+
workspaces: WorkspaceRef[];
|
|
33
|
+
} | {
|
|
34
|
+
status: "ambiguous";
|
|
35
|
+
message: string;
|
|
36
|
+
matches: ProjectPathRow[];
|
|
37
|
+
} | {
|
|
38
|
+
status: "unique";
|
|
39
|
+
matches: ProjectPathRow[];
|
|
40
|
+
}>;
|
|
41
|
+
export declare function findNotesByQuery(rows: WpnNoteWithContextRow[], query: string, workspaceQuery?: string, projectQuery?: string): {
|
|
42
|
+
status: "none";
|
|
43
|
+
message: string;
|
|
44
|
+
} | {
|
|
45
|
+
status: "workspace_ambiguous";
|
|
46
|
+
message: string;
|
|
47
|
+
workspaces: WorkspaceRef[];
|
|
48
|
+
} | {
|
|
49
|
+
status: "project_ambiguous";
|
|
50
|
+
message: string;
|
|
51
|
+
projects: {
|
|
52
|
+
projectId: string;
|
|
53
|
+
projectName: string;
|
|
54
|
+
workspaceId: string;
|
|
55
|
+
workspaceName: string;
|
|
56
|
+
path: string;
|
|
57
|
+
}[];
|
|
58
|
+
} | {
|
|
59
|
+
status: "ambiguous";
|
|
60
|
+
message: string;
|
|
61
|
+
matches: NotePathRow[];
|
|
62
|
+
} | {
|
|
63
|
+
status: "unique";
|
|
64
|
+
matches: NotePathRow[];
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=find-wpn.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-wpn.d.ts","sourceRoot":"","sources":["../src/find-wpn.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAG7D,wEAAwE;AACxE,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAG/C;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAKF,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,aAAa,EACrB,KAAK,EAAE,MAAM,EACb,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CACN;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,MAAM,EAAE,qBAAqB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,YAAY,EAAE,CAAA;CAAE,GAC9E;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,cAAc,EAAE,CAAA;CAAE,GACnE;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,cAAc,EAAE,CAAA;CAAE,CAClD,CA2EA;AAED,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,qBAAqB,EAAE,EAC7B,KAAK,EAAE,MAAM,EACb,cAAc,CAAC,EAAE,MAAM,EACvB,YAAY,CAAC,EAAE,MAAM,GAEnB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,MAAM,EAAE,qBAAqB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,YAAY,EAAE,CAAA;CAAE,GAC9E;IAAE,MAAM,EAAE,mBAAmB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,GAClK;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,WAAW,EAAE,CAAA;CAAE,GAChE;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,WAAW,EAAE,CAAA;CAAE,CAsH/C"}
|
package/dist/find-wpn.js
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { norm } from "./resolve-note.js";
|
|
2
|
+
/** RFC-style UUID v1–v5 (loose check for id vs name disambiguation). */
|
|
3
|
+
export function isLikelyUuid(s) {
|
|
4
|
+
const t = s.trim();
|
|
5
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(t);
|
|
6
|
+
}
|
|
7
|
+
export async function findProjectsByQuery(client, query, workspaceQuery) {
|
|
8
|
+
const q = query.trim();
|
|
9
|
+
if (!q) {
|
|
10
|
+
return { status: "none", message: "Empty query." };
|
|
11
|
+
}
|
|
12
|
+
const workspaces = (await client.getWorkspaces());
|
|
13
|
+
let scopedWs = workspaces;
|
|
14
|
+
if (workspaceQuery !== undefined && workspaceQuery.trim() !== "") {
|
|
15
|
+
const wq = workspaceQuery.trim();
|
|
16
|
+
if (isLikelyUuid(wq)) {
|
|
17
|
+
scopedWs = workspaces.filter((w) => w.id === wq);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
scopedWs = workspaces.filter((w) => norm(w.name ?? "") === norm(wq));
|
|
21
|
+
}
|
|
22
|
+
if (scopedWs.length === 0) {
|
|
23
|
+
return {
|
|
24
|
+
status: "none",
|
|
25
|
+
message: `No workspace matched "${workspaceQuery}".`,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
if (scopedWs.length > 1) {
|
|
29
|
+
return {
|
|
30
|
+
status: "workspace_ambiguous",
|
|
31
|
+
message: "Multiple workspaces match that name; pass workspace id or a more specific workspaceQuery.",
|
|
32
|
+
workspaces: scopedWs.map((w) => ({
|
|
33
|
+
workspaceId: w.id,
|
|
34
|
+
workspaceName: w.name ?? "",
|
|
35
|
+
})),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const flat = [];
|
|
40
|
+
for (const w of scopedWs) {
|
|
41
|
+
const projects = (await client.getProjects(w.id));
|
|
42
|
+
const wname = w.name ?? "";
|
|
43
|
+
for (const p of projects) {
|
|
44
|
+
const pname = p.name ?? "";
|
|
45
|
+
flat.push({
|
|
46
|
+
projectId: p.id,
|
|
47
|
+
projectName: pname,
|
|
48
|
+
workspaceId: w.id,
|
|
49
|
+
workspaceName: wname,
|
|
50
|
+
path: `${wname} / ${pname}`,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
let matches;
|
|
55
|
+
if (isLikelyUuid(q)) {
|
|
56
|
+
matches = flat.filter((r) => r.projectId === q);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
matches = flat.filter((r) => norm(r.projectName) === norm(q));
|
|
60
|
+
}
|
|
61
|
+
if (matches.length === 0) {
|
|
62
|
+
return {
|
|
63
|
+
status: "none",
|
|
64
|
+
message: isLikelyUuid(q)
|
|
65
|
+
? `No project with id "${q}".`
|
|
66
|
+
: `No project named "${query}" in the selected scope.`,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (matches.length === 1) {
|
|
70
|
+
return { status: "unique", matches };
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
status: "ambiguous",
|
|
74
|
+
message: "Multiple projects match; each row includes projectId and path (Workspace / Project). Pick one id or narrow workspaceQuery.",
|
|
75
|
+
matches,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
export function findNotesByQuery(rows, query, workspaceQuery, projectQuery) {
|
|
79
|
+
const q = query.trim();
|
|
80
|
+
if (!q) {
|
|
81
|
+
return { status: "none", message: "Empty query." };
|
|
82
|
+
}
|
|
83
|
+
let filtered = rows;
|
|
84
|
+
if (workspaceQuery !== undefined && workspaceQuery.trim() !== "") {
|
|
85
|
+
const wq = workspaceQuery.trim();
|
|
86
|
+
if (isLikelyUuid(wq)) {
|
|
87
|
+
filtered = filtered.filter((r) => r.workspace_id === wq);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
const wsMatches = new Map();
|
|
91
|
+
for (const r of filtered) {
|
|
92
|
+
if (norm(r.workspace_name) === norm(wq)) {
|
|
93
|
+
wsMatches.set(r.workspace_id, r.workspace_name);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (wsMatches.size > 1) {
|
|
97
|
+
return {
|
|
98
|
+
status: "workspace_ambiguous",
|
|
99
|
+
message: "Multiple workspaces share that name; pass workspace id as workspaceQuery or disambiguate.",
|
|
100
|
+
workspaces: [...wsMatches.entries()].map(([workspaceId, workspaceName]) => ({
|
|
101
|
+
workspaceId,
|
|
102
|
+
workspaceName,
|
|
103
|
+
})),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
filtered = filtered.filter((r) => norm(r.workspace_name) === norm(wq));
|
|
107
|
+
}
|
|
108
|
+
if (filtered.length === 0) {
|
|
109
|
+
return {
|
|
110
|
+
status: "none",
|
|
111
|
+
message: `No notes in a workspace matching "${workspaceQuery}".`,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (projectQuery !== undefined && projectQuery.trim() !== "") {
|
|
116
|
+
const pq = projectQuery.trim();
|
|
117
|
+
if (isLikelyUuid(pq)) {
|
|
118
|
+
filtered = filtered.filter((r) => r.project_id === pq);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
const projBuckets = new Map();
|
|
122
|
+
for (const r of filtered) {
|
|
123
|
+
if (norm(r.project_name) !== norm(pq)) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const k = `${r.workspace_id}\0${r.project_id}`;
|
|
127
|
+
if (!projBuckets.has(k)) {
|
|
128
|
+
const path = `${r.workspace_name} / ${r.project_name}`;
|
|
129
|
+
projBuckets.set(k, {
|
|
130
|
+
projectId: r.project_id,
|
|
131
|
+
projectName: r.project_name,
|
|
132
|
+
workspaceId: r.workspace_id,
|
|
133
|
+
workspaceName: r.workspace_name,
|
|
134
|
+
path,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (projBuckets.size > 1) {
|
|
139
|
+
return {
|
|
140
|
+
status: "project_ambiguous",
|
|
141
|
+
message: "Multiple projects match that name in scope; pass project id as projectQuery or narrow workspace.",
|
|
142
|
+
projects: [...projBuckets.values()],
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
filtered = filtered.filter((r) => norm(r.project_name) === norm(pq));
|
|
146
|
+
}
|
|
147
|
+
if (filtered.length === 0) {
|
|
148
|
+
return {
|
|
149
|
+
status: "none",
|
|
150
|
+
message: `No notes in a project matching "${projectQuery}" in the current scope.`,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
let matches;
|
|
155
|
+
if (isLikelyUuid(q)) {
|
|
156
|
+
matches = filtered.filter((r) => r.id === q);
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
matches = filtered.filter((r) => norm(r.title) === norm(q));
|
|
160
|
+
}
|
|
161
|
+
const out = matches.map((r) => ({
|
|
162
|
+
noteId: r.id,
|
|
163
|
+
title: r.title,
|
|
164
|
+
type: r.type,
|
|
165
|
+
projectId: r.project_id,
|
|
166
|
+
projectName: r.project_name,
|
|
167
|
+
workspaceId: r.workspace_id,
|
|
168
|
+
workspaceName: r.workspace_name,
|
|
169
|
+
path: `${r.workspace_name} / ${r.project_name} / ${r.title}`,
|
|
170
|
+
}));
|
|
171
|
+
if (out.length === 0) {
|
|
172
|
+
return {
|
|
173
|
+
status: "none",
|
|
174
|
+
message: isLikelyUuid(q)
|
|
175
|
+
? `No note with id "${q}" in the selected scope.`
|
|
176
|
+
: `No note titled "${query}" in the selected scope.`,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
if (out.length === 1) {
|
|
180
|
+
return { status: "unique", matches: out };
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
status: "ambiguous",
|
|
184
|
+
message: "Multiple notes match; each row includes noteId and path (Workspace / Project / Title). Pick one id or narrow filters.",
|
|
185
|
+
matches: out,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=find-wpn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-wpn.js","sourceRoot":"","sources":["../src/find-wpn.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-wpn.test.d.ts","sourceRoot":"","sources":["../src/find-wpn.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { describe, it } from "node:test";
|
|
3
|
+
import { findNotesByQuery, isLikelyUuid } from "./find-wpn.js";
|
|
4
|
+
describe("isLikelyUuid", () => {
|
|
5
|
+
it("accepts lowercase uuid", () => {
|
|
6
|
+
assert.equal(isLikelyUuid("550e8400-e29b-41d4-a716-446655440000"), true);
|
|
7
|
+
});
|
|
8
|
+
it("rejects plain title", () => {
|
|
9
|
+
assert.equal(isLikelyUuid("My Note"), false);
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
describe("findNotesByQuery", () => {
|
|
13
|
+
const idA = "550e8400-e29b-41d4-a716-446655440001";
|
|
14
|
+
const idB = "550e8400-e29b-41d4-a716-446655440002";
|
|
15
|
+
const rows = [
|
|
16
|
+
{
|
|
17
|
+
id: idA,
|
|
18
|
+
title: "Todo",
|
|
19
|
+
type: "markdown",
|
|
20
|
+
project_id: "p1",
|
|
21
|
+
project_name: "Core",
|
|
22
|
+
workspace_id: "w1",
|
|
23
|
+
workspace_name: "Main",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
id: idB,
|
|
27
|
+
title: "Todo",
|
|
28
|
+
type: "markdown",
|
|
29
|
+
project_id: "p2",
|
|
30
|
+
project_name: "App",
|
|
31
|
+
workspace_id: "w1",
|
|
32
|
+
workspace_name: "Main",
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
it("returns unique by title", () => {
|
|
36
|
+
const r = findNotesByQuery(rows, "todo", "main", "core");
|
|
37
|
+
assert.equal(r.status, "unique");
|
|
38
|
+
if (r.status === "unique") {
|
|
39
|
+
assert.equal(r.matches.length, 1);
|
|
40
|
+
assert.equal(r.matches[0].noteId, idA);
|
|
41
|
+
assert.equal(r.matches[0].path, "Main / Core / Todo");
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
it("returns ambiguous when same title in scope", () => {
|
|
45
|
+
const r = findNotesByQuery(rows, "todo");
|
|
46
|
+
assert.equal(r.status, "ambiguous");
|
|
47
|
+
if (r.status === "ambiguous") {
|
|
48
|
+
assert.equal(r.matches.length, 2);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
it("returns unique by note id", () => {
|
|
52
|
+
const r = findNotesByQuery(rows, idB);
|
|
53
|
+
assert.equal(r.status, "unique");
|
|
54
|
+
if (r.status === "unique") {
|
|
55
|
+
assert.equal(r.matches[0].noteId, idB);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
//# sourceMappingURL=find-wpn.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-wpn.test.js","sourceRoot":"","sources":["../src/find-wpn.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { WpnNoteWithContextRow } from "./wpn-client.js";
|
|
2
|
+
export declare function norm(s: string): string;
|
|
3
|
+
export type ResolveNoteInput = {
|
|
4
|
+
workspaceName: string;
|
|
5
|
+
projectName: string;
|
|
6
|
+
noteTitle: string;
|
|
7
|
+
};
|
|
8
|
+
export type ResolveNoteOk = {
|
|
9
|
+
ok: true;
|
|
10
|
+
noteId: string;
|
|
11
|
+
workspaceId: string;
|
|
12
|
+
workspaceName: string;
|
|
13
|
+
projectId: string;
|
|
14
|
+
projectName: string;
|
|
15
|
+
title: string;
|
|
16
|
+
type: string;
|
|
17
|
+
};
|
|
18
|
+
export type ResolveNoteAmbiguous = {
|
|
19
|
+
ok: false;
|
|
20
|
+
reason: "none" | "ambiguous";
|
|
21
|
+
candidates: {
|
|
22
|
+
noteId: string;
|
|
23
|
+
workspaceName: string;
|
|
24
|
+
projectName: string;
|
|
25
|
+
title: string;
|
|
26
|
+
}[];
|
|
27
|
+
};
|
|
28
|
+
export type ResolveNoteResult = ResolveNoteOk | ResolveNoteAmbiguous;
|
|
29
|
+
/**
|
|
30
|
+
* Match workspace, project, and note title using trim + case-insensitive comparison
|
|
31
|
+
* (Unicode case-folding via `toLowerCase()`).
|
|
32
|
+
*/
|
|
33
|
+
export declare function resolveNoteFromCatalog(rows: WpnNoteWithContextRow[], input: ResolveNoteInput): ResolveNoteResult;
|
|
34
|
+
//# sourceMappingURL=resolve-note.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-note.d.ts","sourceRoot":"","sources":["../src/resolve-note.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAE7D,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEtC;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,EAAE,IAAI,CAAC;IACT,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,MAAM,GAAG,WAAW,CAAC;IAC7B,UAAU,EAAE;QACV,MAAM,EAAE,MAAM,CAAC;QACf,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;KACf,EAAE,CAAC;CACL,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,aAAa,GAAG,oBAAoB,CAAC;AAErE;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,qBAAqB,EAAE,EAC7B,KAAK,EAAE,gBAAgB,GACtB,iBAAiB,CAoCnB"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export function norm(s) {
|
|
2
|
+
return s.trim().replace(/\s+/g, " ").toLowerCase();
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Match workspace, project, and note title using trim + case-insensitive comparison
|
|
6
|
+
* (Unicode case-folding via `toLowerCase()`).
|
|
7
|
+
*/
|
|
8
|
+
export function resolveNoteFromCatalog(rows, input) {
|
|
9
|
+
const wn = norm(input.workspaceName);
|
|
10
|
+
const pn = norm(input.projectName);
|
|
11
|
+
const tn = norm(input.noteTitle);
|
|
12
|
+
const matches = rows.filter((r) => norm(r.workspace_name) === wn &&
|
|
13
|
+
norm(r.project_name) === pn &&
|
|
14
|
+
norm(r.title) === tn);
|
|
15
|
+
if (matches.length === 0) {
|
|
16
|
+
return { ok: false, reason: "none", candidates: [] };
|
|
17
|
+
}
|
|
18
|
+
if (matches.length > 1) {
|
|
19
|
+
return {
|
|
20
|
+
ok: false,
|
|
21
|
+
reason: "ambiguous",
|
|
22
|
+
candidates: matches.map((r) => ({
|
|
23
|
+
noteId: r.id,
|
|
24
|
+
workspaceName: r.workspace_name,
|
|
25
|
+
projectName: r.project_name,
|
|
26
|
+
title: r.title,
|
|
27
|
+
})),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const r = matches[0];
|
|
31
|
+
return {
|
|
32
|
+
ok: true,
|
|
33
|
+
noteId: r.id,
|
|
34
|
+
workspaceId: r.workspace_id,
|
|
35
|
+
workspaceName: r.workspace_name,
|
|
36
|
+
projectId: r.project_id,
|
|
37
|
+
projectName: r.project_name,
|
|
38
|
+
title: r.title,
|
|
39
|
+
type: r.type,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=resolve-note.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-note.js","sourceRoot":"","sources":["../src/resolve-note.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,IAAI,CAAC,CAAS;IAC5B,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;AACrD,CAAC;AAgCD;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,IAA6B,EAC7B,KAAuB;IAEvB,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IACrC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACnC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACjC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CACzB,CAAC,CAAC,EAAE,EAAE,CACJ,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,EAAE;QAC7B,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,EAAE;QAC3B,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,CACvB,CAAC;IACF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;IACvD,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,WAAW;YACnB,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC9B,MAAM,EAAE,CAAC,CAAC,EAAE;gBACZ,aAAa,EAAE,CAAC,CAAC,cAAc;gBAC/B,WAAW,EAAE,CAAC,CAAC,YAAY;gBAC3B,KAAK,EAAE,CAAC,CAAC,KAAK;aACf,CAAC,CAAC;SACJ,CAAC;IACJ,CAAC;IACD,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAE,CAAC;IACtB,OAAO;QACL,EAAE,EAAE,IAAI;QACR,MAAM,EAAE,CAAC,CAAC,EAAE;QACZ,WAAW,EAAE,CAAC,CAAC,YAAY;QAC3B,aAAa,EAAE,CAAC,CAAC,cAAc;QAC/B,SAAS,EAAE,CAAC,CAAC,UAAU;QACvB,WAAW,EAAE,CAAC,CAAC,YAAY;QAC3B,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,IAAI,EAAE,CAAC,CAAC,IAAI;KACb,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-note.test.d.ts","sourceRoot":"","sources":["../src/resolve-note.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { describe, it } from "node:test";
|
|
3
|
+
import { resolveNoteFromCatalog } from "./resolve-note.js";
|
|
4
|
+
const rows = [
|
|
5
|
+
{
|
|
6
|
+
id: "a1",
|
|
7
|
+
title: "Spec",
|
|
8
|
+
type: "markdown",
|
|
9
|
+
project_id: "p1",
|
|
10
|
+
project_name: "Core",
|
|
11
|
+
workspace_id: "w1",
|
|
12
|
+
workspace_name: "Main",
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
id: "a2",
|
|
16
|
+
title: "Spec",
|
|
17
|
+
type: "markdown",
|
|
18
|
+
project_id: "p2",
|
|
19
|
+
project_name: "Core",
|
|
20
|
+
workspace_id: "w2",
|
|
21
|
+
workspace_name: "Other",
|
|
22
|
+
},
|
|
23
|
+
];
|
|
24
|
+
describe("resolveNoteFromCatalog", () => {
|
|
25
|
+
it("returns single match with case-insensitive names", () => {
|
|
26
|
+
const r = resolveNoteFromCatalog(rows, {
|
|
27
|
+
workspaceName: "main",
|
|
28
|
+
projectName: " core ",
|
|
29
|
+
noteTitle: "SPEC",
|
|
30
|
+
});
|
|
31
|
+
assert.equal(r.ok, true);
|
|
32
|
+
if (r.ok) {
|
|
33
|
+
assert.equal(r.noteId, "a1");
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
it("returns none when title missing", () => {
|
|
37
|
+
const r = resolveNoteFromCatalog(rows, {
|
|
38
|
+
workspaceName: "Main",
|
|
39
|
+
projectName: "Core",
|
|
40
|
+
noteTitle: "Missing",
|
|
41
|
+
});
|
|
42
|
+
assert.equal(r.ok, false);
|
|
43
|
+
if (!r.ok) {
|
|
44
|
+
assert.equal(r.reason, "none");
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
it("returns ambiguous when same triple exists twice", () => {
|
|
48
|
+
const dup = [
|
|
49
|
+
...rows,
|
|
50
|
+
{
|
|
51
|
+
id: "a3",
|
|
52
|
+
title: "Spec",
|
|
53
|
+
type: "markdown",
|
|
54
|
+
project_id: "p9",
|
|
55
|
+
project_name: "Core",
|
|
56
|
+
workspace_id: "w1",
|
|
57
|
+
workspace_name: "Main",
|
|
58
|
+
},
|
|
59
|
+
];
|
|
60
|
+
const r = resolveNoteFromCatalog(dup, {
|
|
61
|
+
workspaceName: "Main",
|
|
62
|
+
projectName: "Core",
|
|
63
|
+
noteTitle: "Spec",
|
|
64
|
+
});
|
|
65
|
+
assert.equal(r.ok, false);
|
|
66
|
+
if (!r.ok) {
|
|
67
|
+
assert.equal(r.reason, "ambiguous");
|
|
68
|
+
assert.equal(r.candidates.length, 2);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
//# sourceMappingURL=resolve-note.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-note.test.js","sourceRoot":"","sources":["../src/resolve-note.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,MAAM,IAAI,GAA4B;IACpC;QACE,EAAE,EAAE,IAAI;QACR,KAAK,EAAE,MAAM;QACb,IAAI,EAAE,UAAU;QAChB,UAAU,EAAE,IAAI;QAChB,YAAY,EAAE,MAAM;QACpB,YAAY,EAAE,IAAI;QAClB,cAAc,EAAE,MAAM;KACvB;IACD;QACE,EAAE,EAAE,IAAI;QACR,KAAK,EAAE,MAAM;QACb,IAAI,EAAE,UAAU;QAChB,UAAU,EAAE,IAAI;QAChB,YAAY,EAAE,MAAM;QACpB,YAAY,EAAE,IAAI;QAClB,cAAc,EAAE,OAAO;KACxB;CACF,CAAC;AAEF,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,CAAC,GAAG,sBAAsB,CAAC,IAAI,EAAE;YACrC,aAAa,EAAE,MAAM;YACrB,WAAW,EAAE,SAAS;YACtB,SAAS,EAAE,MAAM;SAClB,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QACzB,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC;YACT,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,CAAC,GAAG,sBAAsB,CAAC,IAAI,EAAE;YACrC,aAAa,EAAE,MAAM;YACrB,WAAW,EAAE,MAAM;YACnB,SAAS,EAAE,SAAS;SACrB,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAC1B,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YACV,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,GAAG,GAA4B;YACnC,GAAG,IAAI;YACP;gBACE,EAAE,EAAE,IAAI;gBACR,KAAK,EAAE,MAAM;gBACb,IAAI,EAAE,UAAU;gBAChB,UAAU,EAAE,IAAI;gBAChB,YAAY,EAAE,MAAM;gBACpB,YAAY,EAAE,IAAI;gBAClB,cAAc,EAAE,MAAM;aACvB;SACF,CAAC;QACF,MAAM,CAAC,GAAG,sBAAsB,CAAC,GAAG,EAAE;YACpC,aAAa,EAAE,MAAM;YACrB,WAAW,EAAE,MAAM;YACnB,SAAS,EAAE,MAAM;SAClB,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAC1B,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YACV,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;YACpC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACvC,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAyFA,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAuOvD"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { loadWpnHttpConfig } from "./config.js";
|
|
5
|
+
import { findNotesByQuery, findProjectsByQuery } from "./find-wpn.js";
|
|
6
|
+
import { resolveNoteFromCatalog } from "./resolve-note.js";
|
|
7
|
+
import { errorResult, jsonResult } from "./text-result.js";
|
|
8
|
+
import { WpnHttpClient } from "./wpn-client.js";
|
|
9
|
+
const resolveInput = z.object({
|
|
10
|
+
workspaceName: z.string().describe("Workspace name (trimmed, case-insensitive match)"),
|
|
11
|
+
projectName: z.string().describe("Project name (trimmed, case-insensitive match)"),
|
|
12
|
+
noteTitle: z.string().describe("Note title (trimmed, case-insensitive match)"),
|
|
13
|
+
});
|
|
14
|
+
const getNoteInput = z.object({
|
|
15
|
+
noteId: z.string().describe("Canonical note UUID"),
|
|
16
|
+
});
|
|
17
|
+
const findProjectsInput = z.object({
|
|
18
|
+
query: z.string().describe("Project name or project UUID"),
|
|
19
|
+
workspaceQuery: z
|
|
20
|
+
.string()
|
|
21
|
+
.optional()
|
|
22
|
+
.describe("Optional workspace name or UUID to limit search (required if project name clashes across workspaces)."),
|
|
23
|
+
});
|
|
24
|
+
const findNotesInput = z.object({
|
|
25
|
+
query: z.string().describe("Note title or note UUID"),
|
|
26
|
+
workspaceQuery: z
|
|
27
|
+
.string()
|
|
28
|
+
.optional()
|
|
29
|
+
.describe("Optional workspace name or UUID to narrow results"),
|
|
30
|
+
projectQuery: z
|
|
31
|
+
.string()
|
|
32
|
+
.optional()
|
|
33
|
+
.describe("Optional project name or UUID to narrow results"),
|
|
34
|
+
});
|
|
35
|
+
const listWpnInput = z.discriminatedUnion("scope", [
|
|
36
|
+
z.object({ scope: z.literal("workspaces") }),
|
|
37
|
+
z.object({
|
|
38
|
+
scope: z.literal("projects"),
|
|
39
|
+
workspaceId: z.string().describe("Workspace id from scope=workspaces"),
|
|
40
|
+
}),
|
|
41
|
+
z.object({
|
|
42
|
+
scope: z.literal("notes"),
|
|
43
|
+
projectId: z.string().describe("Project id from scope=projects"),
|
|
44
|
+
}),
|
|
45
|
+
z.object({ scope: z.literal("full_tree") }),
|
|
46
|
+
]);
|
|
47
|
+
const writeNoteInput = z.discriminatedUnion("mode", [
|
|
48
|
+
z.object({
|
|
49
|
+
mode: z.literal("patch_existing"),
|
|
50
|
+
noteId: z.string(),
|
|
51
|
+
title: z.string().optional(),
|
|
52
|
+
content: z.string().optional(),
|
|
53
|
+
type: z.string().optional(),
|
|
54
|
+
metadata: z.record(z.string(), z.unknown()).nullable().optional(),
|
|
55
|
+
}),
|
|
56
|
+
z.object({
|
|
57
|
+
mode: z.literal("create_root"),
|
|
58
|
+
projectId: z.string(),
|
|
59
|
+
type: z.string(),
|
|
60
|
+
title: z.string().optional(),
|
|
61
|
+
content: z.string().optional(),
|
|
62
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
63
|
+
}),
|
|
64
|
+
z.object({
|
|
65
|
+
mode: z.literal("create_child"),
|
|
66
|
+
projectId: z.string(),
|
|
67
|
+
anchorId: z.string(),
|
|
68
|
+
type: z.string(),
|
|
69
|
+
title: z.string().optional(),
|
|
70
|
+
content: z.string().optional(),
|
|
71
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
72
|
+
}),
|
|
73
|
+
z.object({
|
|
74
|
+
mode: z.literal("create_sibling"),
|
|
75
|
+
projectId: z.string(),
|
|
76
|
+
anchorId: z.string(),
|
|
77
|
+
type: z.string(),
|
|
78
|
+
title: z.string().optional(),
|
|
79
|
+
content: z.string().optional(),
|
|
80
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
81
|
+
}),
|
|
82
|
+
]);
|
|
83
|
+
export async function runMcpStdioServer() {
|
|
84
|
+
const cfg = loadWpnHttpConfig();
|
|
85
|
+
const client = new WpnHttpClient(cfg);
|
|
86
|
+
const mcp = new McpServer({ name: "nodex-mcp", version: "0.0.0" }, {
|
|
87
|
+
capabilities: {
|
|
88
|
+
tools: {},
|
|
89
|
+
},
|
|
90
|
+
instructions: "Nodex WPN tools: nodex_list_wpn lists workspaces / projects / notes or a full_tree; " +
|
|
91
|
+
"nodex_find_projects / nodex_find_notes resolve by name or UUID with path (Workspace / Project / Title) and ambiguity hints; " +
|
|
92
|
+
"nodex_resolve_note finds a noteId from workspace+project+title; nodex_get_note reads a note; " +
|
|
93
|
+
"nodex_write_note patches or creates notes. " +
|
|
94
|
+
"Configure NODEX_SYNC_API_BASE + NODEX_ACCESS_TOKEN (cloud) or NODEX_LOCAL_WPN_URL + NODEX_LOCAL_WPN_TOKEN (Electron loopback).",
|
|
95
|
+
});
|
|
96
|
+
mcp.registerTool("nodex_find_projects", {
|
|
97
|
+
description: "Find project(s) by name or id. Returns status unique | ambiguous | none | workspace_ambiguous; " +
|
|
98
|
+
"each match includes projectId, names, and path \"Workspace / Project\". On clash, all candidates are listed.",
|
|
99
|
+
inputSchema: findProjectsInput,
|
|
100
|
+
}, async (args) => {
|
|
101
|
+
try {
|
|
102
|
+
const result = await findProjectsByQuery(client, args.query, args.workspaceQuery);
|
|
103
|
+
return jsonResult(result);
|
|
104
|
+
}
|
|
105
|
+
catch (e) {
|
|
106
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
107
|
+
return errorResult(msg);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
mcp.registerTool("nodex_find_notes", {
|
|
111
|
+
description: "Find note(s) by title or id using GET /wpn/notes-with-context. Optional workspaceQuery / projectQuery narrow scope. " +
|
|
112
|
+
"Returns status unique | ambiguous | none | workspace_ambiguous | project_ambiguous; " +
|
|
113
|
+
"each match includes noteId, title, and path \"Workspace / Project / Title\".",
|
|
114
|
+
inputSchema: findNotesInput,
|
|
115
|
+
}, async (args) => {
|
|
116
|
+
try {
|
|
117
|
+
const rows = await client.getNotesWithContext();
|
|
118
|
+
const result = findNotesByQuery(rows, args.query, args.workspaceQuery, args.projectQuery);
|
|
119
|
+
return jsonResult(result);
|
|
120
|
+
}
|
|
121
|
+
catch (e) {
|
|
122
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
123
|
+
return errorResult(msg);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
mcp.registerTool("nodex_list_wpn", {
|
|
127
|
+
description: "List WPN data: workspaces (GET /wpn/workspaces), projects in a workspace, flat note tree for a project, or full_tree (all nested).",
|
|
128
|
+
inputSchema: listWpnInput,
|
|
129
|
+
}, async (args) => {
|
|
130
|
+
try {
|
|
131
|
+
if (args.scope === "workspaces") {
|
|
132
|
+
const workspaces = await client.getWorkspaces();
|
|
133
|
+
return jsonResult({ scope: "workspaces", workspaces });
|
|
134
|
+
}
|
|
135
|
+
if (args.scope === "projects") {
|
|
136
|
+
const projects = await client.getProjects(args.workspaceId);
|
|
137
|
+
return jsonResult({
|
|
138
|
+
scope: "projects",
|
|
139
|
+
workspaceId: args.workspaceId,
|
|
140
|
+
projects,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
if (args.scope === "notes") {
|
|
144
|
+
const notes = await client.getNotesFlat(args.projectId);
|
|
145
|
+
return jsonResult({ scope: "notes", projectId: args.projectId, notes });
|
|
146
|
+
}
|
|
147
|
+
const workspaces = await client.getWorkspaces();
|
|
148
|
+
const wsRows = workspaces;
|
|
149
|
+
const tree = [];
|
|
150
|
+
for (const w of wsRows) {
|
|
151
|
+
const projectsRaw = await client.getProjects(w.id);
|
|
152
|
+
const projects = projectsRaw;
|
|
153
|
+
const projectBlocks = [];
|
|
154
|
+
for (const p of projects) {
|
|
155
|
+
const notes = await client.getNotesFlat(p.id);
|
|
156
|
+
projectBlocks.push({ project: p, notes });
|
|
157
|
+
}
|
|
158
|
+
tree.push({ workspace: w, projects: projectBlocks });
|
|
159
|
+
}
|
|
160
|
+
return jsonResult({ scope: "full_tree", tree });
|
|
161
|
+
}
|
|
162
|
+
catch (e) {
|
|
163
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
164
|
+
return errorResult(msg);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
mcp.tool("nodex_resolve_note", "Resolve a note to its canonical UUID using workspace name, project name, and note title. " +
|
|
168
|
+
"Matching is trim + case-insensitive. Returns an error if zero or multiple notes match.", resolveInput.shape, async (args) => {
|
|
169
|
+
try {
|
|
170
|
+
const rows = await client.getNotesWithContext();
|
|
171
|
+
const r = resolveNoteFromCatalog(rows, {
|
|
172
|
+
workspaceName: args.workspaceName,
|
|
173
|
+
projectName: args.projectName,
|
|
174
|
+
noteTitle: args.noteTitle,
|
|
175
|
+
});
|
|
176
|
+
if (!r.ok) {
|
|
177
|
+
return errorResult(JSON.stringify({
|
|
178
|
+
error: r.reason === "none"
|
|
179
|
+
? "No note matched workspace/project/title."
|
|
180
|
+
: "Multiple notes matched; disambiguate titles or use noteId from candidates.",
|
|
181
|
+
reason: r.reason,
|
|
182
|
+
candidates: r.candidates,
|
|
183
|
+
}, null, 2));
|
|
184
|
+
}
|
|
185
|
+
return jsonResult({
|
|
186
|
+
noteId: r.noteId,
|
|
187
|
+
workspaceId: r.workspaceId,
|
|
188
|
+
workspaceName: r.workspaceName,
|
|
189
|
+
projectId: r.projectId,
|
|
190
|
+
projectName: r.projectName,
|
|
191
|
+
title: r.title,
|
|
192
|
+
type: r.type,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
catch (e) {
|
|
196
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
197
|
+
return errorResult(msg);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
mcp.tool("nodex_get_note", "Fetch a single note by id (includes content and metadata).", getNoteInput.shape, async (args) => {
|
|
201
|
+
try {
|
|
202
|
+
const note = await client.getNote(args.noteId);
|
|
203
|
+
return jsonResult({ note });
|
|
204
|
+
}
|
|
205
|
+
catch (e) {
|
|
206
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
207
|
+
return errorResult(msg);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
mcp.registerTool("nodex_write_note", {
|
|
211
|
+
description: "Create or patch a note. Modes: patch_existing (PATCH), create_root | create_child | create_sibling (POST with relation).",
|
|
212
|
+
inputSchema: writeNoteInput,
|
|
213
|
+
}, async (args) => {
|
|
214
|
+
try {
|
|
215
|
+
if (args.mode === "patch_existing") {
|
|
216
|
+
const patch = {};
|
|
217
|
+
if (args.title !== undefined) {
|
|
218
|
+
patch.title = args.title;
|
|
219
|
+
}
|
|
220
|
+
if (args.content !== undefined) {
|
|
221
|
+
patch.content = args.content;
|
|
222
|
+
}
|
|
223
|
+
if (args.type !== undefined) {
|
|
224
|
+
patch.type = args.type;
|
|
225
|
+
}
|
|
226
|
+
if (args.metadata !== undefined) {
|
|
227
|
+
patch.metadata = args.metadata;
|
|
228
|
+
}
|
|
229
|
+
const note = await client.patchNote(args.noteId, patch);
|
|
230
|
+
return jsonResult({ ok: true, note });
|
|
231
|
+
}
|
|
232
|
+
const relation = args.mode === "create_root"
|
|
233
|
+
? "root"
|
|
234
|
+
: args.mode === "create_child"
|
|
235
|
+
? "child"
|
|
236
|
+
: "sibling";
|
|
237
|
+
const anchorId = args.mode === "create_root" ? undefined : args.anchorId;
|
|
238
|
+
const body = {
|
|
239
|
+
type: args.type,
|
|
240
|
+
relation,
|
|
241
|
+
anchorId,
|
|
242
|
+
title: args.title,
|
|
243
|
+
content: args.content,
|
|
244
|
+
metadata: args.metadata,
|
|
245
|
+
};
|
|
246
|
+
const created = await client.createNote(args.projectId, body);
|
|
247
|
+
return jsonResult({ ok: true, created });
|
|
248
|
+
}
|
|
249
|
+
catch (e) {
|
|
250
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
251
|
+
return errorResult(msg);
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
const transport = new StdioServerTransport();
|
|
255
|
+
await mcp.connect(transport);
|
|
256
|
+
}
|
|
257
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** MCP tool handler return shape (subset of CallToolResult). */
|
|
2
|
+
export type ToolReturn = {
|
|
3
|
+
content: {
|
|
4
|
+
type: "text";
|
|
5
|
+
text: string;
|
|
6
|
+
}[];
|
|
7
|
+
isError?: boolean;
|
|
8
|
+
};
|
|
9
|
+
export declare function jsonResult(obj: unknown): ToolReturn;
|
|
10
|
+
export declare function errorResult(message: string): ToolReturn;
|
|
11
|
+
//# sourceMappingURL=text-result.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-result.d.ts","sourceRoot":"","sources":["../src/text-result.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC1C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,UAAU,CASnD;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAKvD"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function jsonResult(obj) {
|
|
2
|
+
return {
|
|
3
|
+
content: [
|
|
4
|
+
{
|
|
5
|
+
type: "text",
|
|
6
|
+
text: JSON.stringify(obj, null, 2),
|
|
7
|
+
},
|
|
8
|
+
],
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export function errorResult(message) {
|
|
12
|
+
return {
|
|
13
|
+
isError: true,
|
|
14
|
+
content: [{ type: "text", text: message }],
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=text-result.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-result.js","sourceRoot":"","sources":["../src/text-result.ts"],"names":[],"mappings":"AAMA,MAAM,UAAU,UAAU,CAAC,GAAY;IACrC,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;aACnC;SACF;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,OAAO;QACL,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;KAC3C,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { WpnHttpConfig } from "./config.js";
|
|
2
|
+
export type WpnNoteWithContextRow = {
|
|
3
|
+
id: string;
|
|
4
|
+
title: string;
|
|
5
|
+
type: string;
|
|
6
|
+
project_id: string;
|
|
7
|
+
project_name: string;
|
|
8
|
+
workspace_id: string;
|
|
9
|
+
workspace_name: string;
|
|
10
|
+
};
|
|
11
|
+
export type WpnNoteDetail = {
|
|
12
|
+
id: string;
|
|
13
|
+
project_id: string;
|
|
14
|
+
parent_id: string | null;
|
|
15
|
+
type: string;
|
|
16
|
+
title: string;
|
|
17
|
+
content: string;
|
|
18
|
+
metadata?: Record<string, unknown>;
|
|
19
|
+
sibling_index: number;
|
|
20
|
+
created_at_ms: number;
|
|
21
|
+
updated_at_ms: number;
|
|
22
|
+
};
|
|
23
|
+
export declare class WpnHttpClient {
|
|
24
|
+
private readonly cfg;
|
|
25
|
+
constructor(cfg: WpnHttpConfig);
|
|
26
|
+
private url;
|
|
27
|
+
private headers;
|
|
28
|
+
private getJson;
|
|
29
|
+
getWorkspaces(): Promise<unknown[]>;
|
|
30
|
+
getProjects(workspaceId: string): Promise<unknown[]>;
|
|
31
|
+
getNotesFlat(projectId: string): Promise<unknown[]>;
|
|
32
|
+
getNotesWithContext(): Promise<WpnNoteWithContextRow[]>;
|
|
33
|
+
getNote(noteId: string): Promise<WpnNoteDetail>;
|
|
34
|
+
patchNote(noteId: string, patch: {
|
|
35
|
+
title?: string;
|
|
36
|
+
content?: string;
|
|
37
|
+
type?: string;
|
|
38
|
+
metadata?: Record<string, unknown> | null;
|
|
39
|
+
}): Promise<WpnNoteDetail>;
|
|
40
|
+
createNote(projectId: string, body: {
|
|
41
|
+
type: string;
|
|
42
|
+
relation: "root" | "child" | "sibling";
|
|
43
|
+
anchorId?: string;
|
|
44
|
+
title?: string;
|
|
45
|
+
content?: string;
|
|
46
|
+
metadata?: Record<string, unknown>;
|
|
47
|
+
}): Promise<{
|
|
48
|
+
id: string;
|
|
49
|
+
}>;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=wpn-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wpn-client.d.ts","sourceRoot":"","sources":["../src/wpn-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,MAAM,qBAAqB,GAAG;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,qBAAa,aAAa;IACZ,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAAH,GAAG,EAAE,aAAa;IAE/C,OAAO,CAAC,GAAG;IAKX,OAAO,CAAC,OAAO;YAQD,OAAO;IAmBf,aAAa,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAYnC,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAYpD,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAYnD,mBAAmB,IAAI,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAYvD,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAuB/C,SAAS,CACb,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;QACL,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;KAC3C,GACA,OAAO,CAAC,aAAa,CAAC;IAwBnB,UAAU,CACd,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;QACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACpC,GACA,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;CA0B3B"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
export class WpnHttpClient {
|
|
2
|
+
cfg;
|
|
3
|
+
constructor(cfg) {
|
|
4
|
+
this.cfg = cfg;
|
|
5
|
+
}
|
|
6
|
+
url(path) {
|
|
7
|
+
const p = path.startsWith("/") ? path : `/${path}`;
|
|
8
|
+
return `${this.cfg.baseUrl}${p}`;
|
|
9
|
+
}
|
|
10
|
+
headers() {
|
|
11
|
+
return {
|
|
12
|
+
Accept: "application/json",
|
|
13
|
+
"Content-Type": "application/json",
|
|
14
|
+
Authorization: `Bearer ${this.cfg.bearerToken}`,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
async getJson(path, errLabel) {
|
|
18
|
+
const res = await fetch(this.url(path), {
|
|
19
|
+
method: "GET",
|
|
20
|
+
headers: this.headers(),
|
|
21
|
+
});
|
|
22
|
+
const text = await res.text();
|
|
23
|
+
let body;
|
|
24
|
+
try {
|
|
25
|
+
body = text ? JSON.parse(text) : {};
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
throw new Error(`${errLabel}: invalid JSON (${res.status})`);
|
|
29
|
+
}
|
|
30
|
+
if (!res.ok) {
|
|
31
|
+
const err = body?.error ?? text.slice(0, 200);
|
|
32
|
+
throw new Error(`${errLabel} failed (${res.status}): ${err}`);
|
|
33
|
+
}
|
|
34
|
+
return body;
|
|
35
|
+
}
|
|
36
|
+
async getWorkspaces() {
|
|
37
|
+
const body = await this.getJson("/wpn/workspaces", "WPN GET workspaces");
|
|
38
|
+
const ws = body.workspaces;
|
|
39
|
+
if (!Array.isArray(ws)) {
|
|
40
|
+
throw new Error("WPN GET workspaces: missing workspaces array");
|
|
41
|
+
}
|
|
42
|
+
return ws;
|
|
43
|
+
}
|
|
44
|
+
async getProjects(workspaceId) {
|
|
45
|
+
const body = await this.getJson(`/wpn/workspaces/${encodeURIComponent(workspaceId)}/projects`, "WPN GET projects");
|
|
46
|
+
const p = body.projects;
|
|
47
|
+
if (!Array.isArray(p)) {
|
|
48
|
+
throw new Error("WPN GET projects: missing projects array");
|
|
49
|
+
}
|
|
50
|
+
return p;
|
|
51
|
+
}
|
|
52
|
+
async getNotesFlat(projectId) {
|
|
53
|
+
const body = await this.getJson(`/wpn/projects/${encodeURIComponent(projectId)}/notes`, "WPN GET notes");
|
|
54
|
+
const n = body.notes;
|
|
55
|
+
if (!Array.isArray(n)) {
|
|
56
|
+
throw new Error("WPN GET notes: missing notes array");
|
|
57
|
+
}
|
|
58
|
+
return n;
|
|
59
|
+
}
|
|
60
|
+
async getNotesWithContext() {
|
|
61
|
+
const body = await this.getJson("/wpn/notes-with-context", "WPN GET notes-with-context");
|
|
62
|
+
const notes = body.notes;
|
|
63
|
+
if (!Array.isArray(notes)) {
|
|
64
|
+
throw new Error("WPN GET notes-with-context: missing notes array");
|
|
65
|
+
}
|
|
66
|
+
return notes;
|
|
67
|
+
}
|
|
68
|
+
async getNote(noteId) {
|
|
69
|
+
const res = await fetch(this.url(`/wpn/notes/${encodeURIComponent(noteId)}`), {
|
|
70
|
+
method: "GET",
|
|
71
|
+
headers: this.headers(),
|
|
72
|
+
});
|
|
73
|
+
const text = await res.text();
|
|
74
|
+
let body;
|
|
75
|
+
try {
|
|
76
|
+
body = text ? JSON.parse(text) : {};
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
throw new Error(`WPN get note: invalid JSON (${res.status})`);
|
|
80
|
+
}
|
|
81
|
+
if (!res.ok) {
|
|
82
|
+
const err = body?.error ?? text.slice(0, 200);
|
|
83
|
+
throw new Error(`WPN GET note failed (${res.status}): ${err}`);
|
|
84
|
+
}
|
|
85
|
+
const note = body.note;
|
|
86
|
+
if (!note || typeof note !== "object") {
|
|
87
|
+
throw new Error("WPN GET note: missing note object");
|
|
88
|
+
}
|
|
89
|
+
return note;
|
|
90
|
+
}
|
|
91
|
+
async patchNote(noteId, patch) {
|
|
92
|
+
const res = await fetch(this.url(`/wpn/notes/${encodeURIComponent(noteId)}`), {
|
|
93
|
+
method: "PATCH",
|
|
94
|
+
headers: this.headers(),
|
|
95
|
+
body: JSON.stringify(patch),
|
|
96
|
+
});
|
|
97
|
+
const text = await res.text();
|
|
98
|
+
let body;
|
|
99
|
+
try {
|
|
100
|
+
body = text ? JSON.parse(text) : {};
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
throw new Error(`WPN patch note: invalid JSON (${res.status})`);
|
|
104
|
+
}
|
|
105
|
+
if (!res.ok) {
|
|
106
|
+
const err = body?.error ?? text.slice(0, 200);
|
|
107
|
+
throw new Error(`WPN PATCH note failed (${res.status}): ${err}`);
|
|
108
|
+
}
|
|
109
|
+
const note = body.note;
|
|
110
|
+
if (!note) {
|
|
111
|
+
throw new Error("WPN PATCH note: missing note in response");
|
|
112
|
+
}
|
|
113
|
+
return note;
|
|
114
|
+
}
|
|
115
|
+
async createNote(projectId, body) {
|
|
116
|
+
const res = await fetch(this.url(`/wpn/projects/${encodeURIComponent(projectId)}/notes`), {
|
|
117
|
+
method: "POST",
|
|
118
|
+
headers: this.headers(),
|
|
119
|
+
body: JSON.stringify(body),
|
|
120
|
+
});
|
|
121
|
+
const text = await res.text();
|
|
122
|
+
let parsed;
|
|
123
|
+
try {
|
|
124
|
+
parsed = text ? JSON.parse(text) : {};
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
throw new Error(`WPN create note: invalid JSON (${res.status})`);
|
|
128
|
+
}
|
|
129
|
+
if (!res.ok) {
|
|
130
|
+
const err = parsed?.error ?? text.slice(0, 200);
|
|
131
|
+
throw new Error(`WPN POST note failed (${res.status}): ${err}`);
|
|
132
|
+
}
|
|
133
|
+
const id = parsed.id;
|
|
134
|
+
if (typeof id !== "string" || !id) {
|
|
135
|
+
throw new Error("WPN POST note: missing id in response");
|
|
136
|
+
}
|
|
137
|
+
return { id };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=wpn-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wpn-client.js","sourceRoot":"","sources":["../src/wpn-client.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nodex-studio/mcp",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "MCP server (stdio) for Nodex WPN over HTTP — cloud sync-api or Electron loopback",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist",
|
|
8
|
+
"bin"
|
|
9
|
+
],
|
|
10
|
+
"bin": {
|
|
11
|
+
"nodex-mcp": "bin/nodex-mcp.js"
|
|
12
|
+
},
|
|
13
|
+
"publishConfig": {
|
|
14
|
+
"access": "public"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc -p tsconfig.json",
|
|
18
|
+
"start": "node dist/cli.js",
|
|
19
|
+
"dev": "tsx src/cli.ts",
|
|
20
|
+
"typecheck": "tsc --noEmit",
|
|
21
|
+
"test": "tsx --test src/resolve-note.test.ts src/find-wpn.test.ts"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
25
|
+
"zod": "^3.24.1"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"tsx": "^4.21.0",
|
|
29
|
+
"typescript": "^5.9.3"
|
|
30
|
+
}
|
|
31
|
+
}
|