@noesis-brain/mcp-server 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +93 -5
  2. package/dist/agent/runner.d.ts +25 -0
  3. package/dist/agent/runner.d.ts.map +1 -0
  4. package/dist/agent/runner.js +218 -0
  5. package/dist/agent/runner.js.map +1 -0
  6. package/dist/api/NoesisClient.d.ts +119 -0
  7. package/dist/api/NoesisClient.d.ts.map +1 -1
  8. package/dist/api/NoesisClient.js +130 -6
  9. package/dist/api/NoesisClient.js.map +1 -1
  10. package/dist/cli/setup.d.ts.map +1 -1
  11. package/dist/cli/setup.js +409 -35
  12. package/dist/cli/setup.js.map +1 -1
  13. package/dist/database/PostgresAdapter.js +216 -216
  14. package/dist/index.js +31 -1
  15. package/dist/index.js.map +1 -1
  16. package/dist/resolve/noteRef.d.ts +101 -0
  17. package/dist/resolve/noteRef.d.ts.map +1 -0
  18. package/dist/resolve/noteRef.js +186 -0
  19. package/dist/resolve/noteRef.js.map +1 -0
  20. package/dist/resolve/rootsFormat.d.ts +12 -0
  21. package/dist/resolve/rootsFormat.d.ts.map +1 -0
  22. package/dist/resolve/rootsFormat.js +63 -0
  23. package/dist/resolve/rootsFormat.js.map +1 -0
  24. package/dist/services/embedding.js +19 -19
  25. package/dist/tools/backlog.d.ts +4 -0
  26. package/dist/tools/backlog.d.ts.map +1 -0
  27. package/dist/tools/backlog.js +157 -0
  28. package/dist/tools/backlog.js.map +1 -0
  29. package/dist/tools/index.d.ts +52 -1
  30. package/dist/tools/index.d.ts.map +1 -1
  31. package/dist/tools/index.js +438 -142
  32. package/dist/tools/index.js.map +1 -1
  33. package/dist/tools/navis.d.ts.map +1 -1
  34. package/dist/tools/navis.js +4 -0
  35. package/dist/tools/navis.js.map +1 -1
  36. package/package.json +9 -4
  37. package/scripts/agent-e2e.mjs +69 -0
  38. package/scripts/noesis-capture-session-end.mjs +94 -0
  39. package/scripts/noesis-capture-watcher.mjs +907 -0
  40. package/scripts/noesis-sync.mjs +469 -469
  41. package/skill-templates/noesis-capture.md +166 -0
  42. package/skill-templates/noesis-create-study-note.md +149 -0
  43. package/skill-templates/noesis-find-related.md +89 -0
  44. package/skill-templates/noesis-investigate.md +90 -0
  45. package/skill-templates/noesis-manage-news.md +80 -0
  46. package/skill-templates/noesis-refine-note.md +92 -92
  47. package/skill-templates/noesis-skim-read.md +72 -0
  48. package/skill-templates/noesis-sync.md +110 -110
  49. package/templates/claude-md-block.md +26 -22
  50. package/templates/claude-md-restructure-on-sync.md +10 -0
@@ -1,92 +1,92 @@
1
- ---
2
- description: Polish a Noesis note's metadata and structure. Use a scope (today/session/catalog/cascade) or pass a specific note to iterate over multiple notes.
3
- ---
4
-
5
- Refine Noesis notes: fill missing metadata (title, description, keywords, aliases), tighten structure (heading hierarchy, frontmatter completeness), refresh AI-rated quality and importance scores. Works on a single note or a batch discovered by scope.
6
-
7
- ## Arguments
8
-
9
- $ARGUMENTS
10
-
11
- Accepted forms:
12
-
13
- - (no args) — ask the user to pick a scope via `AskUserQuestion`.
14
- - `<path-or-filename>.md` — refine this specific note.
15
- - `<topic-or-query>` — search for matching notes and offer them to the user.
16
- - `today` — discover and refine notes referenced in today's conversation logs.
17
- - `session [id]` — discover and refine notes referenced in a specific session (or the latest).
18
- - `catalog <name>` — refine all notes in a named Noesis catalog.
19
- - `cascade <anchor>` — refine the anchor note plus its semantically-similar neighbors.
20
- - `--limit <N>` — cap how many notes a batch mode processes (default: 15).
21
- - `--dry-run` — show what would change without writing.
22
-
23
- ## Workflow
24
-
25
- ### Step 1 — Parse mode
26
-
27
- From `$ARGUMENTS`, determine `MODE` using the first matching rule:
28
-
29
- | Priority | Pattern | Mode |
30
- |---|---|---|
31
- | 1 | `cascade <anchor>` | CASCADE |
32
- | 2 | `today` (anywhere) | TODAY |
33
- | 3 | `catalog <name>` | CATALOG |
34
- | 4 | `session [<id>]` | SESSION |
35
- | 5 | Ends in `.md` (path or filename) | SINGLE |
36
- | 6 | Non-empty string (treated as search query) | SEARCH |
37
- | 7 | Empty | ASK |
38
-
39
- For `ASK`, prompt the user via `AskUserQuestion` with options for each mode and proceed once they pick.
40
-
41
- ### Step 2 — Discover candidate notes
42
-
43
- Cap the candidate list per mode:
44
-
45
- - **SINGLE**: just the one note. Resolve filename to a path via `mcp__noesis__search_notes` if needed.
46
- - **SEARCH**: call `mcp__noesis__search_notes(query)` with the user's query; show the top 10, ask the user to pick one or more.
47
- - **TODAY**: read `~/.claude/logs/console_*.clog` files dated today, extract note paths and search terms mentioned, deduplicate, cap at `--limit` (default 15).
48
- - **SESSION**: same as TODAY but scoped to the chosen session UUID (or the latest if unspecified).
49
- - **CATALOG**: call `mcp__noesis__list_notes(catalog: <name>)`, cap at `--limit` (default 25).
50
- - **CASCADE**: resolve the anchor note's ID via `mcp__noesis__get_note(path)`, then call `mcp__noesis__find_similar_notes(note_id, limit: --limit ?? 10)`. Include the anchor itself.
51
-
52
- Show the discovered list to the user and ask them to confirm or trim before refining. Sort by ascending `quality_score` (worst first) so the most-needed refinement happens first.
53
-
54
- ### Step 3 — Refine each note sequentially
55
-
56
- For each candidate note:
57
-
58
- 1. **Read current state:** `mcp__noesis__get_note(path|id)` to get the full metadata + content.
59
- 2. **Fill missing metadata:** call `mcp__noesis__enhance_note_metadata(note_id)` with the relevant fields requested (`title`, `description`, `keywords`, `aliases`). The MCP tool uses AI to derive values from the note content. Apply with user approval if the change looks substantial; auto-apply if filling pure gaps (e.g., empty `keywords`).
60
- 3. **Structural suggestions** (light touch — skip if `--dry-run`):
61
- - Frontmatter completeness: title / description / keywords / aliases / date / updated / status / importance_score / quality_score.
62
- - Heading hierarchy: surface any H3+ without parent H2, or duplicate H1s.
63
- - Suggest and apply with `Edit` after user approval per file.
64
- 4. **Refresh scores:** call `mcp__noesis__rate_quality(note_id)` and `mcp__noesis__rate_importance(note_id)` — these run an AI rating pass; track the delta vs the prior values.
65
- 5. **Push:** if anything changed locally, call `mcp__noesis__sync_notes(files: [<absolute path>])` to push.
66
-
67
- ### Step 4 — Report
68
-
69
- Per-note line:
70
-
71
- - `refined <path>: metadata filled (Δ desc / kw / aliases), quality <old> → <new>, importance <old> → <new>`
72
- - `refined <path>: no changes needed`
73
- - `skipped <path> (<reason>)`
74
-
75
- Final tally:
76
-
77
- - `Total: T. Refined: R. Score delta: avg +X quality / +Y importance. Skipped: S. Errors: E.`
78
-
79
- ## Constraints
80
-
81
- - Never overwrite a user-authored description with an AI-generated one without confirmation. The MCP tool returns suggestions; you apply them only after the user OKs substantial replacements.
82
- - Never touch note `content` body text in refinement — only frontmatter and structural markers (headings, list normalization). Body rewrites are out of scope; that's an editing task, not a refinement.
83
- - One note at a time — sequential, not parallel. Each push uses `sync_notes(files:[...])` so conflicts surface per-note.
84
- - If a sync push returns conflict, hand off to `/noesis-sync` (which has the conflict-resolution flow embedded) or stop the batch and report.
85
-
86
- ## Examples
87
-
88
- - `/noesis-refine-note c:/path/to/note.md` — refine a single note.
89
- - `/noesis-refine-note today` — refine notes touched today.
90
- - `/noesis-refine-note catalog Work` — refine the Work catalog.
91
- - `/noesis-refine-note cascade c:/path/to/anchor.md` — refine the anchor and its semantic neighbors.
92
- - `/noesis-refine-note today --dry-run` — preview only.
1
+ ---
2
+ description: Polish a Noesis note's metadata and structure. Use a scope (today/session/catalog/cascade) or pass a specific note to iterate over multiple notes.
3
+ ---
4
+
5
+ Refine Noesis notes: fill missing metadata (title, description, keywords, aliases), tighten structure (heading hierarchy, frontmatter completeness), refresh AI-rated quality and importance scores. Works on a single note or a batch discovered by scope.
6
+
7
+ ## Arguments
8
+
9
+ $ARGUMENTS
10
+
11
+ Accepted forms:
12
+
13
+ - (no args) — ask the user to pick a scope via `AskUserQuestion`.
14
+ - `<path-or-filename>.md` — refine this specific note.
15
+ - `<topic-or-query>` — search for matching notes and offer them to the user.
16
+ - `today` — discover and refine notes referenced in today's conversation logs.
17
+ - `session [id]` — discover and refine notes referenced in a specific session (or the latest).
18
+ - `catalog <name>` — refine all notes in a named Noesis catalog.
19
+ - `cascade <anchor>` — refine the anchor note plus its semantically-similar neighbors.
20
+ - `--limit <N>` — cap how many notes a batch mode processes (default: 15).
21
+ - `--dry-run` — show what would change without writing.
22
+
23
+ ## Workflow
24
+
25
+ ### Step 1 — Parse mode
26
+
27
+ From `$ARGUMENTS`, determine `MODE` using the first matching rule:
28
+
29
+ | Priority | Pattern | Mode |
30
+ |---|---|---|
31
+ | 1 | `cascade <anchor>` | CASCADE |
32
+ | 2 | `today` (anywhere) | TODAY |
33
+ | 3 | `catalog <name>` | CATALOG |
34
+ | 4 | `session [<id>]` | SESSION |
35
+ | 5 | Ends in `.md` (path or filename) | SINGLE |
36
+ | 6 | Non-empty string (treated as search query) | SEARCH |
37
+ | 7 | Empty | ASK |
38
+
39
+ For `ASK`, prompt the user via `AskUserQuestion` with options for each mode and proceed once they pick.
40
+
41
+ ### Step 2 — Discover candidate notes
42
+
43
+ Cap the candidate list per mode:
44
+
45
+ - **SINGLE**: just the one note. Resolve filename to a path via `mcp__noesis__search_notes` if needed.
46
+ - **SEARCH**: call `mcp__noesis__search_notes(query)` with the user's query; show the top 10, ask the user to pick one or more.
47
+ - **TODAY**: read `~/.claude/logs/console_*.clog` files dated today, extract note paths and search terms mentioned, deduplicate, cap at `--limit` (default 15).
48
+ - **SESSION**: same as TODAY but scoped to the chosen session UUID (or the latest if unspecified).
49
+ - **CATALOG**: call `mcp__noesis__list_notes(catalog: <name>)`, cap at `--limit` (default 25).
50
+ - **CASCADE**: resolve the anchor note's ID via `mcp__noesis__get_note(path)`, then call `mcp__noesis__find_similar_notes(note_id, limit: --limit ?? 10)`. Include the anchor itself.
51
+
52
+ Show the discovered list to the user and ask them to confirm or trim before refining. Sort by ascending `quality_score` (worst first) so the most-needed refinement happens first.
53
+
54
+ ### Step 3 — Refine each note sequentially
55
+
56
+ For each candidate note:
57
+
58
+ 1. **Read current state:** `mcp__noesis__get_note(path|id)` to get the full metadata + content.
59
+ 2. **Fill missing metadata:** call `mcp__noesis__enhance_note_metadata(note_id)` with the relevant fields requested (`title`, `description`, `keywords`, `aliases`). The MCP tool uses AI to derive values from the note content. Apply with user approval if the change looks substantial; auto-apply if filling pure gaps (e.g., empty `keywords`).
60
+ 3. **Structural suggestions** (light touch — skip if `--dry-run`):
61
+ - Frontmatter completeness: title / description / keywords / aliases / date / updated / status / importance_score / quality_score.
62
+ - Heading hierarchy: surface any H3+ without parent H2, or duplicate H1s.
63
+ - Suggest and apply with `Edit` after user approval per file.
64
+ 4. **Refresh scores:** call `mcp__noesis__rate_quality(note_id)` and `mcp__noesis__rate_importance(note_id)` — these run an AI rating pass; track the delta vs the prior values.
65
+ 5. **Push:** if anything changed locally, call `mcp__noesis__sync_notes(files: [<absolute path>])` to push.
66
+
67
+ ### Step 4 — Report
68
+
69
+ Per-note line:
70
+
71
+ - `refined <path>: metadata filled (Δ desc / kw / aliases), quality <old> → <new>, importance <old> → <new>`
72
+ - `refined <path>: no changes needed`
73
+ - `skipped <path> (<reason>)`
74
+
75
+ Final tally:
76
+
77
+ - `Total: T. Refined: R. Score delta: avg +X quality / +Y importance. Skipped: S. Errors: E.`
78
+
79
+ ## Constraints
80
+
81
+ - Never overwrite a user-authored description with an AI-generated one without confirmation. The MCP tool returns suggestions; you apply them only after the user OKs substantial replacements.
82
+ - Never touch note `content` body text in refinement — only frontmatter and structural markers (headings, list normalization). Body rewrites are out of scope; that's an editing task, not a refinement.
83
+ - One note at a time — sequential, not parallel. Each push uses `sync_notes(files:[...])` so conflicts surface per-note.
84
+ - If a sync push returns conflict, hand off to `/noesis-sync` (which has the conflict-resolution flow embedded) or stop the batch and report.
85
+
86
+ ## Examples
87
+
88
+ - `/noesis-refine-note c:/path/to/note.md` — refine a single note.
89
+ - `/noesis-refine-note today` — refine notes touched today.
90
+ - `/noesis-refine-note catalog Work` — refine the Work catalog.
91
+ - `/noesis-refine-note cascade c:/path/to/anchor.md` — refine the anchor and its semantic neighbors.
92
+ - `/noesis-refine-note today --dry-run` — preview only.
@@ -0,0 +1,72 @@
1
+ ---
2
+ description: Generate Skim-Read key parts for a Noesis note YOURSELF (no in-app AI) and persist them as suggested marks — the Gemini-free fallback for the Skim-Read panel. Accepts a note ID or file path.
3
+ argument-hint: <note path or ID> [--style gist|balanced|thorough|structure|keyword] [--intensity light|normal|heavy]
4
+ ---
5
+
6
+ Generate the KEY PARTS a reader should focus on in a Noesis note and persist them, so the note's Skim-Read panel surfaces them. YOU do the extraction (using your own model) and the server only anchors + saves — no in-app Gemini call. This is the fallback to use when the app's built-in Skim-Read is rate-limited / 503, or any time you want to drive it from Claude Code.
7
+
8
+ ## Arguments
9
+
10
+ $ARGUMENTS
11
+
12
+ Accepted forms:
13
+
14
+ - `<path>.md` — a file path (e.g. from the Noesis web UI "Copy File Path" button). Quote paths with spaces.
15
+ - `<id>` — a numeric Note ID.
16
+ - Natural language — e.g. `Create skim-read for the note "/path/to/note.md"`; extract the path/ID from the request.
17
+ - `--style <s>` — reading strategy: `gist` | `balanced` (default) | `thorough` | `structure` | `keyword`.
18
+ - `--intensity <i>` — how many parts: `light` | `normal` (default) | `heavy`.
19
+
20
+ ## Workflow
21
+
22
+ ### Step 1 — Resolve the note
23
+
24
+ From `$ARGUMENTS`, extract the target: an all-digits token is a Note ID; anything else (a path, possibly quoted) is a file path. Capture optional `--style` / `--intensity`. If neither an ID nor a path is present, ask the user which note via `AskUserQuestion`.
25
+
26
+ ### Step 2 — Read the note content
27
+
28
+ Call `mcp__noesis__get_note(id: <id>)` or `mcp__noesis__get_note(path: <path>)`. Use the returned `content` as the source of truth. Do NOT call `mcp__noesis__get_note_skim_read` — that uses the in-app AI, which this skill deliberately bypasses.
29
+
30
+ ### Step 3 — Generate the key parts
31
+
32
+ Pick the spans a reader should focus on to get the gist efficiently — spread across the note's sections, each a DISTINCT idea (don't spend several parts on the same point). For each part produce `{ granularity, quote, headingPath?, importance, reason }`:
33
+
34
+ - **quote** — copied CHARACTER-FOR-CHARACTER (verbatim) from `content`. Do NOT paraphrase, translate, fix typos, summarize, or add ellipses. Make each quote long enough to occur exactly once (add surrounding words if a short phrase repeats).
35
+ - `section` → the heading line text · `sentence` → the full sentence · `paragraph` → its first ~12 words · `keyword` → the exact token(s).
36
+ - **granularity** — `section` | `paragraph` | `sentence` | `keyword`.
37
+ - **importance** — 0..1; reserve > 0.8 for the few genuinely load-bearing parts.
38
+ - **reason** — ≤ 12 words, plainly what the span says (no hype words).
39
+ - Only quote VISIBLE prose. Skip code fences (```), YAML frontmatter, HTML tags, and any COLLAPSED `<details>` block (one without the `open` attribute).
40
+ - `headingPath` — ancestor heading texts (top-most first) to disambiguate a repeated quote; omit or `[]` if unknown.
41
+
42
+ Prefer fewer high-confidence parts over filling a quota; it is correct to return few parts for a short or list-like note.
43
+
44
+ ### Step 4 — Apply
45
+
46
+ Call `mcp__noesis__apply_note_skim_read` with `{ id | path, keyParts: [...], style?, intensity? }`. The server anchors each verbatim quote and persists matches as `suggested` marks (replacing prior un-accepted suggestions; accepted/dismissed marks are preserved).
47
+
48
+ ### Step 5 — Fix unmatched quotes (loop)
49
+
50
+ The result includes `unmatchedQuotes` — quotes that did not occur verbatim in the note. If non-empty:
51
+
52
+ 1. Re-read those spans in `content` and correct each quote to the note's EXACT text.
53
+ 2. Call `mcp__noesis__apply_note_skim_read` again with the corrected full set.
54
+ 3. Repeat until `unmatchedQuotes` is empty (or you've corrected every quote you reasonably can — typically ≤ 3 rounds).
55
+
56
+ ### Step 6 — Report
57
+
58
+ State how many key parts were applied (`keyPartCount`), list any quotes that still didn't anchor, and tell the user to open the note's **Skim-Read** panel to see them.
59
+
60
+ ## Constraints
61
+
62
+ - Quotes MUST be verbatim slices of the note content — never invented or edited. A verbatim quote is what lets the server anchor the mark.
63
+ - This skill never calls the in-app Skim-Read AI; generating the parts yourself is the entire point (it works when Gemini is down).
64
+ - The path must sit under one of the user's registered Noesis roots, and the note must exist in the database the MCP server targets. If the lookup 404s, confirm the path/ID and that the MCP server points at the right backend.
65
+ - Do not edit the note's body — Skim-Read only adds non-destructive `suggested` marks.
66
+
67
+ ## Examples
68
+
69
+ - `/noesis-skim-read "/path/to/note.md"` — skim-read by file path.
70
+ - `/noesis-skim-read 2302 --style gist` — terse gist of note 2302.
71
+ - `/noesis-skim-read 2302 --intensity heavy` — more key parts.
72
+ - `Create skim-read for the note "/path/to/note.md"` — natural-language invocation.
@@ -1,110 +1,110 @@
1
- ---
2
- description: Sync local Noesis notes with the cloud — pulls web-UI edits, pushes local changes, resolves conflicts inline.
3
- ---
4
-
5
- The one-stop sync command for Noesis notes. Discovers notes edited via the Noesis web UI (Quick Fix), pulls them locally first, pushes your local changes, and resolves any conflicts inline with your input.
6
-
7
- ## Arguments
8
-
9
- $ARGUMENTS
10
-
11
- Accepted forms:
12
- - (no args) — auto-scope: sync files edited in this conversation, else the current project root.
13
- - `--files <absolute-paths>` — push these specific files (still pulls web-UI edits first for the matching root).
14
- - `<root-name>` — bulk sync the named root (full scan).
15
- - `--dry-run` — preview all actions without writing anything.
16
- - `--skip-online-edits` — skip the web-UI-edit pull step (advanced; rarely needed).
17
-
18
- ## Workflow
19
-
20
- CRITICAL: never start backend servers, write temporary scripts, or improvise HTTP calls. The cloud API at noesis-notes.vercel.app is always available through the MCP tool or the bundled script.
21
-
22
- ### Step 1 — Discover web-UI edits (unless `--skip-online-edits`)
23
-
24
- Call `mcp__noesis__list_edited_online_notes` (filter by `root_id` if `$ARGUMENTS` names a root). For each returned note inspect the `localStatus`:
25
-
26
- - `unchanged` — local file matches the last sync baseline; pull is safe and silent.
27
- - `not_on_disk` — file does not exist locally; pull creates it (auto-pull, no conflict possible).
28
- - `also_modified` — local file has diverged from the baseline. Tell the user the conflict cascade will run for those entries and ask `AskUserQuestion` to confirm before proceeding. If they decline, skip Step 2 for the `also_modified` entries and continue to Step 3 for the rest.
29
-
30
- If `list_edited_online_notes` returns an empty list, skip to Step 3.
31
-
32
- ### Step 2 — Pull web-UI edits
33
-
34
- For each pending note from Step 1 (excluding any the user declined), call:
35
-
36
- ```
37
- mcp__noesis__sync_notes(files: ["<absolute path = root_path + '/' + relative_path>"])
38
- ```
39
-
40
- Process one file at a time so per-file conflicts surface immediately. Track each result for the Step 5 summary.
41
-
42
- ### Step 3 — Push local changes
43
-
44
- Apply scoping:
45
-
46
- 1. **Specific files just edited in this conversation** → pass `files: [<paths>]` (do NOT sync everything else).
47
- 2. **User passed `--files <paths>`** → use those paths.
48
- 3. **User passed a root name** → pass `root: "<name>"` (slow full scan).
49
- 4. **No context, no args** → pass `root` matching the current project directory if it maps to a registered root; otherwise fall back to `files` of the files edited in this conversation.
50
-
51
- Choose the tier:
52
-
53
- - **Tier 1 (preferred):** call `mcp__noesis__sync_notes` with the resolved scope (and `dryRun: true` if `--dry-run`).
54
- - **Tier 2 (MCP unavailable):** run `node "{{NOESIS_MCP_SCRIPT_PATH}}" [args]` — the bundled script reads its token from `~/.claude.json` → `mcpServers.noesis.env.NOESIS_API_TOKEN` and talks to the cloud API directly. Pass the same CLI args (`--files`, `--root`, `--dry-run`).
55
- - **Tier 3 (no Node.js):** call the cloud HTTPS endpoints directly via `curl`. Read the token from `~/.claude.json` as above.
56
- ```bash
57
- curl -H "Authorization: Bearer $TOKEN" https://noesis-notes.vercel.app/api/mcp/roots?forSync=true
58
- curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
59
- https://noesis-notes.vercel.app/api/mcp/notes/upsert \
60
- -d '{"file":{"path":"...","relativePath":"...","content":"...","hash":"...","rootId":N,"rootName":"...","project":"..."},"metadata":{}}'
61
- ```
62
-
63
- ### Step 4 — Resolve conflicts inline (if any)
64
-
65
- If Step 2 or Step 3 reported `conflicts.length > 0` (Tier C of the bidirectional sync — overlapping hunks that anchor reapply and `node-diff3` could not auto-merge), do this PER conflicting file rather than reporting "run another skill":
66
-
67
- 1. **Gather three sides:**
68
- - **CLOUD** — `mcp__noesis__get_note(id)` (id is in the conflict payload, or resolve via `mcp__noesis__list_notes` filtered to the relative path).
69
- - **LOCAL** — `Read` the local file at the resolved absolute path.
70
- - **BASE** — read `.noesis/baseline/<relative_path>` under the root. If the baseline file is missing (legacy sync state), tell the user and ask whether to treat as a two-way merge or skip the file.
71
-
72
- 2. **Classify each pair of overlapping hunks:**
73
- - **Trivial overlap** (one side adds, other doesn't touch; or one side is a strict superset) → auto-merge silently with the inclusive result.
74
- - **Mixed overlap** → resolve the trivial parts automatically; STOP and ask only about the irreconcilable parts.
75
- - **Semantic overlap** (opposing edits, contradictory rewrites) → present the diff and ask via `AskUserQuestion`: `keep-local` / `keep-cloud` / paste merged text. NEVER silently overwrite.
76
-
77
- 3. **Apply the merge:**
78
- - `Write` the merged content to the local file.
79
- - Call `mcp__noesis__sync_notes(files: [<absolute path>])` to push the resolved version.
80
- - If the push returns 409 (cloud changed since this step started), the cloud was updated concurrently — repeat Step 4 for that file from the top.
81
- - After a clean push, call `POST /api/mcp/notes/:id/clear-conflict` (via `Bash` + `curl` with the API token) to clear the cloud `conflict_marker`.
82
-
83
- Process one file at a time. Do NOT batch a chosen-text response across multiple files.
84
-
85
- ### Step 5 — Report
86
-
87
- Print one line per file processed:
88
-
89
- - `pulled (web-UI edit applied locally)` — Step 2 succeeded with no conflict.
90
- - `pushed (local change applied to cloud)` — Step 3 succeeded with no conflict.
91
- - `merged auto for <path>` — Step 4 resolved trivial overlap without user input.
92
- - `merged by user for <path>` — Step 4 resolved with explicit user choice.
93
- - `skipped <path> (<reason>)` — user declined, baseline missing, or other.
94
-
95
- End with a final tally: `Pulled: N. Pushed: M. Merged: K (auto X / by-user Y). Skipped: Z. Errors: E.`
96
-
97
- ## Constraints
98
-
99
- - Never silently overwrite opposing edits — always present the diff and ask.
100
- - Never modify cloud-side content directly via `PUT /api/notes/:id` — go through `sync_notes` so the optimistic-concurrency 409 catches concurrent changes.
101
- - Never strip frontmatter or H1 from either side during merge — preserve verbatim from whichever side wrote them.
102
- - One file at a time for conflict resolution.
103
-
104
- ## Examples
105
-
106
- - `/noesis-sync` — auto-scope to recent conversation edits or current project root.
107
- - `/noesis-sync --dry-run` — preview the full flow without writing.
108
- - `/noesis-sync --files <absolute-path>` — push a specific file (still pulls web-UI edits first).
109
- - `/noesis-sync <root-name>` — bulk sync a named root.
110
- - `/noesis-sync --skip-online-edits` — push only, skip the web-UI pull step.
1
+ ---
2
+ description: Sync local Noesis notes with the cloud — pulls web-UI edits, pushes local changes, resolves conflicts inline.
3
+ ---
4
+
5
+ The one-stop sync command for Noesis notes. Discovers notes edited via the Noesis web UI (Quick Fix), pulls them locally first, pushes your local changes, and resolves any conflicts inline with your input.
6
+
7
+ ## Arguments
8
+
9
+ $ARGUMENTS
10
+
11
+ Accepted forms:
12
+ - (no args) — auto-scope: sync files edited in this conversation, else the current project root.
13
+ - `--files <absolute-paths>` — push these specific files (still pulls web-UI edits first for the matching root).
14
+ - `<root-name>` — bulk sync the named root (full scan).
15
+ - `--dry-run` — preview all actions without writing anything.
16
+ - `--skip-online-edits` — skip the web-UI-edit pull step (advanced; rarely needed).
17
+
18
+ ## Workflow
19
+
20
+ CRITICAL: never start backend servers, write temporary scripts, or improvise HTTP calls. The cloud API at noesis-notes.vercel.app is always available through the MCP tool or the bundled script.
21
+
22
+ ### Step 1 — Discover web-UI edits (unless `--skip-online-edits`)
23
+
24
+ Call `mcp__noesis__list_edited_online_notes` (filter by `root_id` if `$ARGUMENTS` names a root). For each returned note inspect the `localStatus`:
25
+
26
+ - `unchanged` — local file matches the last sync baseline; pull is safe and silent.
27
+ - `not_on_disk` — file does not exist locally; pull creates it (auto-pull, no conflict possible).
28
+ - `also_modified` — local file has diverged from the baseline. Tell the user the conflict cascade will run for those entries and ask `AskUserQuestion` to confirm before proceeding. If they decline, skip Step 2 for the `also_modified` entries and continue to Step 3 for the rest.
29
+
30
+ If `list_edited_online_notes` returns an empty list, skip to Step 3.
31
+
32
+ ### Step 2 — Pull web-UI edits
33
+
34
+ For each pending note from Step 1 (excluding any the user declined), call:
35
+
36
+ ```
37
+ mcp__noesis__sync_notes(files: ["<absolute path = root_path + '/' + relative_path>"])
38
+ ```
39
+
40
+ Process one file at a time so per-file conflicts surface immediately. Track each result for the Step 5 summary.
41
+
42
+ ### Step 3 — Push local changes
43
+
44
+ Apply scoping:
45
+
46
+ 1. **Specific files just edited in this conversation** → pass `files: [<paths>]` (do NOT sync everything else).
47
+ 2. **User passed `--files <paths>`** → use those paths.
48
+ 3. **User passed a root name** → pass `root: "<name>"` (slow full scan).
49
+ 4. **No context, no args** → pass `root` matching the current project directory if it maps to a registered root; otherwise fall back to `files` of the files edited in this conversation.
50
+
51
+ Choose the tier:
52
+
53
+ - **Tier 1 (preferred):** call `mcp__noesis__sync_notes` with the resolved scope (and `dryRun: true` if `--dry-run`).
54
+ - **Tier 2 (MCP unavailable):** run `node "{{NOESIS_MCP_SCRIPT_PATH}}" [args]` — the bundled script reads its token from `~/.claude.json` → `mcpServers.noesis.env.NOESIS_API_TOKEN` and talks to the cloud API directly. Pass the same CLI args (`--files`, `--root`, `--dry-run`).
55
+ - **Tier 3 (no Node.js):** call the cloud HTTPS endpoints directly via `curl`. Read the token from `~/.claude.json` as above.
56
+ ```bash
57
+ curl -H "Authorization: Bearer $TOKEN" https://noesis-notes.vercel.app/api/mcp/roots?forSync=true
58
+ curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
59
+ https://noesis-notes.vercel.app/api/mcp/notes/upsert \
60
+ -d '{"file":{"path":"...","relativePath":"...","content":"...","hash":"...","rootId":N,"rootName":"...","project":"..."},"metadata":{}}'
61
+ ```
62
+
63
+ ### Step 4 — Resolve conflicts inline (if any)
64
+
65
+ If Step 2 or Step 3 reported `conflicts.length > 0` (Tier C of the bidirectional sync — overlapping hunks that anchor reapply and `node-diff3` could not auto-merge), do this PER conflicting file rather than reporting "run another skill":
66
+
67
+ 1. **Gather three sides:**
68
+ - **CLOUD** — `mcp__noesis__get_note(id)` (id is in the conflict payload, or resolve via `mcp__noesis__list_notes` filtered to the relative path).
69
+ - **LOCAL** — `Read` the local file at the resolved absolute path.
70
+ - **BASE** — read `.noesis/baseline/<relative_path>` under the root. If the baseline file is missing (legacy sync state), tell the user and ask whether to treat as a two-way merge or skip the file.
71
+
72
+ 2. **Classify each pair of overlapping hunks:**
73
+ - **Trivial overlap** (one side adds, other doesn't touch; or one side is a strict superset) → auto-merge silently with the inclusive result.
74
+ - **Mixed overlap** → resolve the trivial parts automatically; STOP and ask only about the irreconcilable parts.
75
+ - **Semantic overlap** (opposing edits, contradictory rewrites) → present the diff and ask via `AskUserQuestion`: `keep-local` / `keep-cloud` / paste merged text. NEVER silently overwrite.
76
+
77
+ 3. **Apply the merge:**
78
+ - `Write` the merged content to the local file.
79
+ - Call `mcp__noesis__sync_notes(files: [<absolute path>])` to push the resolved version.
80
+ - If the push returns 409 (cloud changed since this step started), the cloud was updated concurrently — repeat Step 4 for that file from the top.
81
+ - After a clean push, call `POST /api/mcp/notes/:id/clear-conflict` (via `Bash` + `curl` with the API token) to clear the cloud `conflict_marker`.
82
+
83
+ Process one file at a time. Do NOT batch a chosen-text response across multiple files.
84
+
85
+ ### Step 5 — Report
86
+
87
+ Print one line per file processed:
88
+
89
+ - `pulled (web-UI edit applied locally)` — Step 2 succeeded with no conflict.
90
+ - `pushed (local change applied to cloud)` — Step 3 succeeded with no conflict.
91
+ - `merged auto for <path>` — Step 4 resolved trivial overlap without user input.
92
+ - `merged by user for <path>` — Step 4 resolved with explicit user choice.
93
+ - `skipped <path> (<reason>)` — user declined, baseline missing, or other.
94
+
95
+ End with a final tally: `Pulled: N. Pushed: M. Merged: K (auto X / by-user Y). Skipped: Z. Errors: E.`
96
+
97
+ ## Constraints
98
+
99
+ - Never silently overwrite opposing edits — always present the diff and ask.
100
+ - Never modify cloud-side content directly via `PUT /api/notes/:id` — go through `sync_notes` so the optimistic-concurrency 409 catches concurrent changes.
101
+ - Never strip frontmatter or H1 from either side during merge — preserve verbatim from whichever side wrote them.
102
+ - One file at a time for conflict resolution.
103
+
104
+ ## Examples
105
+
106
+ - `/noesis-sync` — auto-scope to recent conversation edits or current project root.
107
+ - `/noesis-sync --dry-run` — preview the full flow without writing.
108
+ - `/noesis-sync --files <absolute-path>` — push a specific file (still pulls web-UI edits first).
109
+ - `/noesis-sync <root-name>` — bulk sync a named root.
110
+ - `/noesis-sync --skip-online-edits` — push only, skip the web-UI pull step.
@@ -1,22 +1,26 @@
1
- ## Noesis MCP — conventions
2
-
3
- ### Writing notes
4
- - Use plain `##` headings for primary sections — Noesis builds its sidebar outline from them. Reserve collapsible `<details>` blocks for appendix-style noise (logs, references, changelogs).
5
-
6
- ### Pushing notes to the cloud
7
- - "Sync to Noesis" means push to the Noesis cloud database, not `cp` to a folder.
8
- - Use `mcp__noesis__sync_notes` with `files: [<absolute paths>]`.
9
- - Files must be within a registered root — check via `mcp__noesis__list_roots`.
10
-
11
- ### Reading and discovering notes
12
- - Note relations and codebase links live in the Noesis **database**, not in `.md` frontmatter — don't grep `.md` files for them.
13
- - Use `mcp__noesis__get_note` (read by ID or path), `mcp__noesis__find_similar_notes` (semantic similarity), `mcp__noesis__search_semantic` / `mcp__noesis__search_notes` (meaning / keyword search), `mcp__noesis__update_relations` (read-only when called without the `relations` param).
14
-
15
- ### Path-as-identifier (cross-machine)
16
- For any path inside a Noesis-watched root (paths containing `/.noesis/`, or any path under a directory listed by `mcp__noesis__list_roots`), the path is a Noesis identifier — the cloud copy is always authoritative, and the local copy on this machine may be **missing** (other machine) or **stale** (the user edited the note via the Noesis web UI's Quick Fix; the web UI surfaces that state with the badge 「在线编辑 · 等待本地同步」). Either way, the local copy is not a trustworthy source of truth — reading it directly silently feeds outdated content into the rest of the turn.
17
-
18
- Trigger: when the user references such a path and you are about to read, edit, or otherwise consume it, sync first — once per path per turn, before the first tool call that touches it. Not before subsequent re-reads of the same path in the same turn.
19
-
20
- - **NORMAL mode (writes allowed):** call `mcp__noesis__sync_notes(files: [<that path>])`. The three-way merge handles every case: in-sync → cheap no-op (`'skip'`); cloud-newer → auto-pulls to local disk; local-newer → pushes to cloud; both diverged → conflict cascade (3-way merge); missing locally → auto-creates from cloud. In all five cases the next `Read`/`Edit`/`Write` sees the right bytes.
21
- - **PLAN mode (writes forbidden):** call `mcp__noesis__get_note(path=<that path>)` for a read-only cloud lookup. Compare its `content_hash` / `updated_at` against the local file's hash / mtime; if drift exists, surface it in the plan and propose `sync_notes` as Step 1 of the implementation.
22
- - In either mode, do NOT fall back to Glob/Grep to hunt for similar filenames; do NOT ask the user to disambiguate the path. The cloud is authoritative for Noesis-watched paths.
1
+ ## Noesis MCP — conventions
2
+
3
+ ### Writing notes
4
+ - Use plain `##` headings for primary sections — Noesis builds its sidebar outline from them. Reserve collapsible `<details>` blocks for appendix-style noise (logs, references, changelogs).
5
+
6
+ ### Pushing notes to the cloud
7
+ - "Sync to Noesis" means push to the Noesis cloud database, not `cp` to a folder.
8
+ - Use `mcp__noesis__sync_notes` with `files: [<absolute paths>]`.
9
+ - Files must be within a registered root — check via `mcp__noesis__list_roots`.
10
+
11
+ ### Reading and discovering notes
12
+ - Note relations and codebase links live in the Noesis **database**, not in `.md` frontmatter — don't grep `.md` files for them.
13
+ - Use `mcp__noesis__get_note` (read by ID or path), `mcp__noesis__find_similar_notes` (semantic similarity), `mcp__noesis__search_semantic` / `mcp__noesis__search_notes` (meaning / keyword search), `mcp__noesis__update_relations` (read-only when called without the `relations` param).
14
+
15
+ ### Path-as-identifier (cross-machine)
16
+ For any path inside a Noesis-watched root, the path is a Noesis identifier — the cloud copy is always authoritative, and the local copy on this machine may be **missing** (other machine) or **stale** (the user edited the note via the Noesis web UI's Quick Fix; the web UI surfaces that state with the badge 「在线编辑 · 等待本地同步」). Either way, the local copy is not a trustworthy source of truth — reading it directly silently feeds outdated content into the rest of the turn.
17
+
18
+ A path is Noesis-watched if it contains `/.noesis/` **OR sits under a folder named `Noesis`** (the cloud root — e.g. `~/Noesis/…`, `%USERPROFILE%\Noesis\…`, or `C:\Users\<you>\Noesis\…`), **OR** is under any directory listed by `mcp__noesis__list_roots`. The `Noesis`/`.noesis` folder name is the cheap signal; when in doubt, treat a `.md` path that looks like a note as watched and let the MCP tool decide.
19
+
20
+ Trigger: when the user references such a path and you are about to read, edit, or otherwise consume it, sync first — once per path per turn, before the first tool call that touches it. Not before subsequent re-reads of the same path in the same turn.
21
+
22
+ **RECOVERY RULE:** if `Read` returns "file does not exist" for a `.md` path that looks like a note — especially one under a `.noesis`/`Noesis` folder — your immediate next action is the MCP tool below with the **same path**. Do NOT conclude the note is missing, on another machine, or that the path was mistyped until the MCP lookup also fails.
23
+
24
+ - **NORMAL mode (writes allowed):** call `mcp__noesis__sync_notes(files: [<that path>])`. The three-way merge handles every case: in-sync → cheap no-op (`'skip'`); cloud-newer → auto-pulls to local disk; local-newer → pushes to cloud; both diverged → conflict cascade (3-way merge); missing locally → auto-creates from cloud. In all five cases the next `Read`/`Edit`/`Write` sees the right bytes.
25
+ - **PLAN mode (writes forbidden):** call `mcp__noesis__get_note(path=<that path>)` for a read-only cloud lookup. Compare its `content_hash` / `updated_at` against the local file's hash / mtime; if drift exists, surface it in the plan and propose `sync_notes` as Step 1 of the implementation.
26
+ - In either mode, do NOT fall back to Glob/Grep to hunt for similar filenames; do NOT ask the user to disambiguate the path. The cloud is authoritative for Noesis-watched paths.
@@ -0,0 +1,10 @@
1
+ ### Restructuring notes that grew by accretion (optional)
2
+ Before syncing a note that shows the **accretion smell** — bolt-on sections (e.g. "a later round of testing exposed a case sections 1–7 didn't cover"), duplicated passages re-explaining the same point under different headings, or a chronological log of patches — do NOT push the sprawl as-is, and do NOT just append another section. Notes that grow by accretion become hard to study.
3
+
4
+ Restructure first:
5
+ 1. Read the FULL current note (`mcp__noesis__get_note` or the local file) so you preserve the substance — diagrams, inventories, code snippets, instrumentation, repro tables.
6
+ 2. Reorganize into ONE coherent narrative led by the **root cause / main finding**, not by chronology: Context & Symptom → Root Cause → supporting detail → inventory/appendix.
7
+ 3. Merge the duplicated sections; fold each bolted-on "later round" addition into the section it belongs to. Revise the existing section rather than adding a new one.
8
+ 4. Then sync, and briefly say which notes you restructured — never rewrite a note body silently.
9
+
10
+ This deliberately permits **body rewrites** on sync — broader than `/noesis-refine-note`, which only touches metadata and headings. You are reorganizing for clarity, not deleting content: preserve every fact, diagram, and snippet.