@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.
- package/README.md +93 -5
- package/dist/agent/runner.d.ts +25 -0
- package/dist/agent/runner.d.ts.map +1 -0
- package/dist/agent/runner.js +218 -0
- package/dist/agent/runner.js.map +1 -0
- package/dist/api/NoesisClient.d.ts +119 -0
- package/dist/api/NoesisClient.d.ts.map +1 -1
- package/dist/api/NoesisClient.js +130 -6
- package/dist/api/NoesisClient.js.map +1 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +409 -35
- package/dist/cli/setup.js.map +1 -1
- package/dist/database/PostgresAdapter.js +216 -216
- package/dist/index.js +31 -1
- package/dist/index.js.map +1 -1
- package/dist/resolve/noteRef.d.ts +101 -0
- package/dist/resolve/noteRef.d.ts.map +1 -0
- package/dist/resolve/noteRef.js +186 -0
- package/dist/resolve/noteRef.js.map +1 -0
- package/dist/resolve/rootsFormat.d.ts +12 -0
- package/dist/resolve/rootsFormat.d.ts.map +1 -0
- package/dist/resolve/rootsFormat.js +63 -0
- package/dist/resolve/rootsFormat.js.map +1 -0
- package/dist/services/embedding.js +19 -19
- package/dist/tools/backlog.d.ts +4 -0
- package/dist/tools/backlog.d.ts.map +1 -0
- package/dist/tools/backlog.js +157 -0
- package/dist/tools/backlog.js.map +1 -0
- package/dist/tools/index.d.ts +52 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +438 -142
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/navis.d.ts.map +1 -1
- package/dist/tools/navis.js +4 -0
- package/dist/tools/navis.js.map +1 -1
- package/package.json +9 -4
- package/scripts/agent-e2e.mjs +69 -0
- package/scripts/noesis-capture-session-end.mjs +94 -0
- package/scripts/noesis-capture-watcher.mjs +907 -0
- package/scripts/noesis-sync.mjs +469 -469
- package/skill-templates/noesis-capture.md +166 -0
- package/skill-templates/noesis-create-study-note.md +149 -0
- package/skill-templates/noesis-find-related.md +89 -0
- package/skill-templates/noesis-investigate.md +90 -0
- package/skill-templates/noesis-manage-news.md +80 -0
- package/skill-templates/noesis-refine-note.md +92 -92
- package/skill-templates/noesis-skim-read.md +72 -0
- package/skill-templates/noesis-sync.md +110 -110
- package/templates/claude-md-block.md +26 -22
- package/templates/claude-md-restructure-on-sync.md +10 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified note-reference resolution (single-vault refactor, M1).
|
|
3
|
+
*
|
|
4
|
+
* Pure logic — no network, no filesystem, no process state. Everything the
|
|
5
|
+
* resolver needs arrives in a ResolverContext built by the caller (M2 wires
|
|
6
|
+
* this to `GET /api/mcp/roots?includeArchived=1`, which since V3 returns the
|
|
7
|
+
* archived translation entries plus `{vault_root_id, device_home_dirs}`).
|
|
8
|
+
*
|
|
9
|
+
* Accepted reference forms (the plan's reference grammar):
|
|
10
|
+
* - note URLs on any host: https://noesisbrain.com/notes/2761[#bm=...]
|
|
11
|
+
* - noesis://note/2761[/optional-slug]
|
|
12
|
+
* - bare numeric ids: "2761"
|
|
13
|
+
* - absolute paths of ANY OS shape: /Users/me/Noesis/x.md,
|
|
14
|
+
* c:/Users/me/Noesis/x.md, C:\temp_cGit\.noesis\x.md
|
|
15
|
+
* - tilde / %USERPROFILE% forms: ~/Noesis/x.md, %USERPROFILE%\Noesis\x.md
|
|
16
|
+
* - LEGACY pre-migration absolute paths, translated through archived roots
|
|
17
|
+
* (vault_subfolder + '.noesis/'-collapse candidates, collapsed first)
|
|
18
|
+
*
|
|
19
|
+
* Fixes the pre-M1 footgun where a root with an empty current-OS path
|
|
20
|
+
* resolved to process.cwd(): empty/missing slots never produce a comparable
|
|
21
|
+
* form here, and local paths are composed (never path.resolve'd) from a
|
|
22
|
+
* verified non-empty base.
|
|
23
|
+
*/
|
|
24
|
+
export type OsKey = 'win32' | 'darwin' | 'linux';
|
|
25
|
+
export interface ResolverRoot {
|
|
26
|
+
id: number;
|
|
27
|
+
name: string;
|
|
28
|
+
local_paths: Record<string, string>;
|
|
29
|
+
archived_at?: string | null;
|
|
30
|
+
vault_subfolder?: string | null;
|
|
31
|
+
}
|
|
32
|
+
export interface ResolverContext {
|
|
33
|
+
/** This machine's OS family (CLIENT_OS). */
|
|
34
|
+
clientOs: OsKey;
|
|
35
|
+
/** This machine's home directory (os.homedir()). */
|
|
36
|
+
homeDir: string;
|
|
37
|
+
/** The user's designated vault root id (V3 roots meta), if known. */
|
|
38
|
+
vaultRootId: number | null;
|
|
39
|
+
/** Per-OS home dirs of the user's machines (V3 roots meta), if known. */
|
|
40
|
+
deviceHomeDirs: Record<string, string> | null;
|
|
41
|
+
/** Active + archived roots (GET /roots?includeArchived=1). */
|
|
42
|
+
roots: ResolverRoot[];
|
|
43
|
+
}
|
|
44
|
+
export type NoteRef = {
|
|
45
|
+
kind: 'id';
|
|
46
|
+
id: number;
|
|
47
|
+
} | {
|
|
48
|
+
kind: 'path';
|
|
49
|
+
path: string;
|
|
50
|
+
};
|
|
51
|
+
export interface ResolvedPathRef {
|
|
52
|
+
/** Root to look candidates up under (the matched root, or the vault). */
|
|
53
|
+
rootId: number;
|
|
54
|
+
/** relative_path candidates, in lookup priority order. */
|
|
55
|
+
candidates: string[];
|
|
56
|
+
via: 'active-root' | 'legacy-translation';
|
|
57
|
+
/** Set when the input matched an archived root. */
|
|
58
|
+
archivedRootId?: number;
|
|
59
|
+
}
|
|
60
|
+
/** Forward slashes + lowercase drive letter (win32 canonical compare form). */
|
|
61
|
+
export declare function normalizePath(p: string): string;
|
|
62
|
+
/** Shape-sniff which OS family a path belongs to (mirrors the backend). */
|
|
63
|
+
export declare function detectPathOsKey(p: string): OsKey;
|
|
64
|
+
/**
|
|
65
|
+
* Parse an input string into a note reference. URLs and ids resolve by note
|
|
66
|
+
* id (the caller fetches the note to learn its relative_path); everything
|
|
67
|
+
* else is treated as a path.
|
|
68
|
+
*/
|
|
69
|
+
export declare function parseNoteReference(input: string): NoteRef;
|
|
70
|
+
interface ComparableForm {
|
|
71
|
+
cmp: string;
|
|
72
|
+
orig: string;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Comparable spellings of one path under an OS family: the normalized raw
|
|
76
|
+
* form plus one home-expanded form per known home dir for that family (this
|
|
77
|
+
* machine's home when the family is the client OS, and the cloud-cached
|
|
78
|
+
* device home). Empty inputs produce NO forms (the cwd-footgun fix).
|
|
79
|
+
*/
|
|
80
|
+
export declare function comparableForms(p: string | null | undefined, osKey: OsKey, homes: string[]): ComparableForm[];
|
|
81
|
+
/**
|
|
82
|
+
* Resolve a path-form reference against the context's roots: longest-prefix
|
|
83
|
+
* across active + archived roots on the sniffed OS family, tilde/home
|
|
84
|
+
* expansion on both sides, legacy translation into the vault for archived
|
|
85
|
+
* matches. Null when nothing matches (or an archived match has no
|
|
86
|
+
* translation target).
|
|
87
|
+
*/
|
|
88
|
+
export declare function resolvePathReference(ctx: ResolverContext, inputPath: string): ResolvedPathRef | null;
|
|
89
|
+
/**
|
|
90
|
+
* The local base directory (this machine, CLIENT_OS) of a root — tilde-form
|
|
91
|
+
* expanded against THIS machine's home dir — or null when the root has no
|
|
92
|
+
* usable path on this OS (never a cwd-relative guess).
|
|
93
|
+
*/
|
|
94
|
+
export declare function rootLocalBase(ctx: ResolverContext, rootId: number): string | null;
|
|
95
|
+
/**
|
|
96
|
+
* The local absolute path (this machine, CLIENT_OS) for a note of `rootId` at
|
|
97
|
+
* `relativePath` — or null when that root has no usable path on this OS.
|
|
98
|
+
*/
|
|
99
|
+
export declare function localAbsFor(ctx: ResolverContext, rootId: number, relativePath: string): string | null;
|
|
100
|
+
export {};
|
|
101
|
+
//# sourceMappingURL=noteRef.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noteRef.d.ts","sourceRoot":"","sources":["../../src/resolve/noteRef.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,MAAM,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEjD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC9B,4CAA4C;IAC5C,QAAQ,EAAE,KAAK,CAAC;IAChB,oDAAoD;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,yEAAyE;IACzE,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IAC9C,8DAA8D;IAC9D,KAAK,EAAE,YAAY,EAAE,CAAC;CACvB;AAED,MAAM,MAAM,OAAO,GAAG;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAElF,MAAM,WAAW,eAAe;IAC9B,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,GAAG,EAAE,aAAa,GAAG,oBAAoB,CAAC;IAC1C,mDAAmD;IACnD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,+EAA+E;AAC/E,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAM/C;AAED,2EAA2E;AAC3E,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,KAAK,CAKhD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAgBzD;AAED,UAAU,cAAc;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAQD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE,CAiB7G;AAYD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAwCpG;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAejF;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKrG"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified note-reference resolution (single-vault refactor, M1).
|
|
3
|
+
*
|
|
4
|
+
* Pure logic — no network, no filesystem, no process state. Everything the
|
|
5
|
+
* resolver needs arrives in a ResolverContext built by the caller (M2 wires
|
|
6
|
+
* this to `GET /api/mcp/roots?includeArchived=1`, which since V3 returns the
|
|
7
|
+
* archived translation entries plus `{vault_root_id, device_home_dirs}`).
|
|
8
|
+
*
|
|
9
|
+
* Accepted reference forms (the plan's reference grammar):
|
|
10
|
+
* - note URLs on any host: https://noesisbrain.com/notes/2761[#bm=...]
|
|
11
|
+
* - noesis://note/2761[/optional-slug]
|
|
12
|
+
* - bare numeric ids: "2761"
|
|
13
|
+
* - absolute paths of ANY OS shape: /Users/me/Noesis/x.md,
|
|
14
|
+
* c:/Users/me/Noesis/x.md, C:\temp_cGit\.noesis\x.md
|
|
15
|
+
* - tilde / %USERPROFILE% forms: ~/Noesis/x.md, %USERPROFILE%\Noesis\x.md
|
|
16
|
+
* - LEGACY pre-migration absolute paths, translated through archived roots
|
|
17
|
+
* (vault_subfolder + '.noesis/'-collapse candidates, collapsed first)
|
|
18
|
+
*
|
|
19
|
+
* Fixes the pre-M1 footgun where a root with an empty current-OS path
|
|
20
|
+
* resolved to process.cwd(): empty/missing slots never produce a comparable
|
|
21
|
+
* form here, and local paths are composed (never path.resolve'd) from a
|
|
22
|
+
* verified non-empty base.
|
|
23
|
+
*/
|
|
24
|
+
/** Forward slashes + lowercase drive letter (win32 canonical compare form). */
|
|
25
|
+
export function normalizePath(p) {
|
|
26
|
+
let normalized = p.replace(/\\/g, '/');
|
|
27
|
+
if (normalized.length >= 2 && normalized[1] === ':') {
|
|
28
|
+
normalized = normalized[0].toLowerCase() + normalized.slice(1);
|
|
29
|
+
}
|
|
30
|
+
return normalized;
|
|
31
|
+
}
|
|
32
|
+
/** Shape-sniff which OS family a path belongs to (mirrors the backend). */
|
|
33
|
+
export function detectPathOsKey(p) {
|
|
34
|
+
if (/^[A-Za-z]:[\\/]/.test(p))
|
|
35
|
+
return 'win32';
|
|
36
|
+
if (p.startsWith('/Users/') || p.startsWith('~/'))
|
|
37
|
+
return 'darwin';
|
|
38
|
+
if (p.startsWith('/'))
|
|
39
|
+
return 'linux';
|
|
40
|
+
return 'win32';
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Parse an input string into a note reference. URLs and ids resolve by note
|
|
44
|
+
* id (the caller fetches the note to learn its relative_path); everything
|
|
45
|
+
* else is treated as a path.
|
|
46
|
+
*/
|
|
47
|
+
export function parseNoteReference(input) {
|
|
48
|
+
const s = input.trim();
|
|
49
|
+
if (/^\d+$/.test(s))
|
|
50
|
+
return { kind: 'id', id: parseInt(s, 10) };
|
|
51
|
+
const noesisScheme = s.match(/^noesis:\/\/note\/(\d+)(?:[/#?].*)?$/i);
|
|
52
|
+
if (noesisScheme)
|
|
53
|
+
return { kind: 'id', id: parseInt(noesisScheme[1], 10) };
|
|
54
|
+
if (/^https?:\/\//i.test(s)) {
|
|
55
|
+
// Anchored: the /notes/{id} segment must end the path (fragment/query
|
|
56
|
+
// tolerated) — '/a/notes/12.png' is NOT a note reference.
|
|
57
|
+
const urlNote = s.match(/\/notes\/(\d+)(?:[/#?].*)?$/i);
|
|
58
|
+
if (urlNote)
|
|
59
|
+
return { kind: 'id', id: parseInt(urlNote[1], 10) };
|
|
60
|
+
}
|
|
61
|
+
return { kind: 'path', path: s };
|
|
62
|
+
}
|
|
63
|
+
function expandHomePrefix(p, home) {
|
|
64
|
+
if (p === '~' || p.startsWith('~/'))
|
|
65
|
+
return home + p.slice(1);
|
|
66
|
+
if (/^%USERPROFILE%/i.test(p))
|
|
67
|
+
return home + p.slice('%USERPROFILE%'.length);
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Comparable spellings of one path under an OS family: the normalized raw
|
|
72
|
+
* form plus one home-expanded form per known home dir for that family (this
|
|
73
|
+
* machine's home when the family is the client OS, and the cloud-cached
|
|
74
|
+
* device home). Empty inputs produce NO forms (the cwd-footgun fix).
|
|
75
|
+
*/
|
|
76
|
+
export function comparableForms(p, osKey, homes) {
|
|
77
|
+
const raw = (p ?? '').trim();
|
|
78
|
+
if (!raw)
|
|
79
|
+
return [];
|
|
80
|
+
const base = normalizePath(raw);
|
|
81
|
+
const variants = new Set([base]);
|
|
82
|
+
for (const home of homes) {
|
|
83
|
+
const h = normalizePath(home).replace(/\/+$/, '');
|
|
84
|
+
if (!h)
|
|
85
|
+
continue;
|
|
86
|
+
const expanded = expandHomePrefix(base, h);
|
|
87
|
+
if (expanded)
|
|
88
|
+
variants.add(expanded);
|
|
89
|
+
}
|
|
90
|
+
return [...variants].map((v) => {
|
|
91
|
+
const trimmed = v.length > 1 ? v.replace(/\/+$/, '') : v;
|
|
92
|
+
return { orig: trimmed, cmp: osKey === 'win32' ? trimmed.toLowerCase() : trimmed };
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
function homesFor(ctx, osKey) {
|
|
96
|
+
const homes = [];
|
|
97
|
+
if (osKey === ctx.clientOs && ctx.homeDir)
|
|
98
|
+
homes.push(ctx.homeDir);
|
|
99
|
+
const cloudHome = ctx.deviceHomeDirs?.[osKey];
|
|
100
|
+
if (typeof cloudHome === 'string' && cloudHome.trim())
|
|
101
|
+
homes.push(cloudHome);
|
|
102
|
+
return homes;
|
|
103
|
+
}
|
|
104
|
+
const NOESIS_SEG = '.noesis/';
|
|
105
|
+
/**
|
|
106
|
+
* Resolve a path-form reference against the context's roots: longest-prefix
|
|
107
|
+
* across active + archived roots on the sniffed OS family, tilde/home
|
|
108
|
+
* expansion on both sides, legacy translation into the vault for archived
|
|
109
|
+
* matches. Null when nothing matches (or an archived match has no
|
|
110
|
+
* translation target).
|
|
111
|
+
*/
|
|
112
|
+
export function resolvePathReference(ctx, inputPath) {
|
|
113
|
+
const osKey = detectPathOsKey(inputPath);
|
|
114
|
+
const homes = homesFor(ctx, osKey);
|
|
115
|
+
const inputForms = comparableForms(inputPath, osKey, homes);
|
|
116
|
+
if (inputForms.length === 0)
|
|
117
|
+
return null;
|
|
118
|
+
let best = null;
|
|
119
|
+
for (const root of ctx.roots) {
|
|
120
|
+
for (const rootForm of comparableForms(root.local_paths?.[osKey], osKey, homes)) {
|
|
121
|
+
for (const input of inputForms) {
|
|
122
|
+
const isMatch = input.cmp === rootForm.cmp || input.cmp.startsWith(rootForm.cmp + '/');
|
|
123
|
+
if (!isMatch)
|
|
124
|
+
continue;
|
|
125
|
+
if (!best || rootForm.cmp.length > best.rootLen) {
|
|
126
|
+
const rel = input.orig.slice(rootForm.orig.length).replace(/^\//, '');
|
|
127
|
+
best = { root, rootLen: rootForm.cmp.length, rel };
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (!best)
|
|
133
|
+
return null;
|
|
134
|
+
const rel = best.rel;
|
|
135
|
+
if (!best.root.archived_at) {
|
|
136
|
+
return { rootId: best.root.id, candidates: [rel], via: 'active-root' };
|
|
137
|
+
}
|
|
138
|
+
const subfolder = best.root.vault_subfolder?.replace(/^\/+|\/+$/g, '');
|
|
139
|
+
if (!subfolder || ctx.vaultRootId == null)
|
|
140
|
+
return null;
|
|
141
|
+
// F8: when the input EXPLICITLY names a `.noesis/` dot path, try the
|
|
142
|
+
// UNCOLLAPSED candidate first. In a collapse-fallback pair (a different file
|
|
143
|
+
// won the collapsed slot at migration, so this note kept its `.noesis/`
|
|
144
|
+
// prefix), collapsed-first would wrongly return the native sibling; the
|
|
145
|
+
// dot-path the caller typed is the one they mean. Harmless in the common
|
|
146
|
+
// case: the uncollapsed candidate simply misses and falls to the collapsed.
|
|
147
|
+
const candidates = rel.startsWith(NOESIS_SEG)
|
|
148
|
+
? [`${subfolder}/${rel}`, `${subfolder}/${rel.slice(NOESIS_SEG.length)}`]
|
|
149
|
+
: [`${subfolder}/${rel}`];
|
|
150
|
+
return { rootId: ctx.vaultRootId, candidates, via: 'legacy-translation', archivedRootId: best.root.id };
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* The local base directory (this machine, CLIENT_OS) of a root — tilde-form
|
|
154
|
+
* expanded against THIS machine's home dir — or null when the root has no
|
|
155
|
+
* usable path on this OS (never a cwd-relative guess).
|
|
156
|
+
*/
|
|
157
|
+
export function rootLocalBase(ctx, rootId) {
|
|
158
|
+
const root = ctx.roots.find((r) => r.id === rootId);
|
|
159
|
+
const rawBase = root?.local_paths?.[ctx.clientOs]?.trim();
|
|
160
|
+
if (!rawBase)
|
|
161
|
+
return null;
|
|
162
|
+
let base = normalizePath(rawBase);
|
|
163
|
+
const home = normalizePath(ctx.homeDir ?? '').replace(/\/+$/, '');
|
|
164
|
+
const expanded = home ? expandHomePrefix(base, home) : null;
|
|
165
|
+
if (expanded)
|
|
166
|
+
base = expanded;
|
|
167
|
+
if (base.startsWith('~'))
|
|
168
|
+
return null; // home unknown — refuse to guess
|
|
169
|
+
// Any unexpanded %TOKEN% (e.g. a stored literal %USERNAME% template) would
|
|
170
|
+
// otherwise mkdir a literal '%USERNAME%' directory on materialize.
|
|
171
|
+
if (/%[^%/\\]+%/.test(base))
|
|
172
|
+
return null;
|
|
173
|
+
return base.length > 1 ? base.replace(/\/+$/, '') : base;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* The local absolute path (this machine, CLIENT_OS) for a note of `rootId` at
|
|
177
|
+
* `relativePath` — or null when that root has no usable path on this OS.
|
|
178
|
+
*/
|
|
179
|
+
export function localAbsFor(ctx, rootId, relativePath) {
|
|
180
|
+
const base = rootLocalBase(ctx, rootId);
|
|
181
|
+
if (!base)
|
|
182
|
+
return null;
|
|
183
|
+
const rel = relativePath.replace(/^\/+/, '');
|
|
184
|
+
return `${base}/${rel}`;
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=noteRef.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noteRef.js","sourceRoot":"","sources":["../../src/resolve/noteRef.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type ResolverContext } from './noteRef.js';
|
|
2
|
+
/**
|
|
3
|
+
* Pure renderer for the `list_roots` tool output (single-vault, M3).
|
|
4
|
+
*
|
|
5
|
+
* Shows the vault (with its per-OS tilde paths AND this machine's resolved
|
|
6
|
+
* absolute base), any other still-active roots, and the archived roots as the
|
|
7
|
+
* legacy-path translation table — old absolute paths under an archived root
|
|
8
|
+
* keep resolving via get_note/sync_notes, translated into the vault subfolder
|
|
9
|
+
* shown here.
|
|
10
|
+
*/
|
|
11
|
+
export declare function formatRootsList(ctx: ResolverContext): string;
|
|
12
|
+
//# sourceMappingURL=rootsFormat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rootsFormat.d.ts","sourceRoot":"","sources":["../../src/resolve/rootsFormat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,eAAe,EAAc,MAAM,cAAc,CAAC;AAE/E;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,CA0D5D"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { rootLocalBase } from './noteRef.js';
|
|
2
|
+
/**
|
|
3
|
+
* Pure renderer for the `list_roots` tool output (single-vault, M3).
|
|
4
|
+
*
|
|
5
|
+
* Shows the vault (with its per-OS tilde paths AND this machine's resolved
|
|
6
|
+
* absolute base), any other still-active roots, and the archived roots as the
|
|
7
|
+
* legacy-path translation table — old absolute paths under an archived root
|
|
8
|
+
* keep resolving via get_note/sync_notes, translated into the vault subfolder
|
|
9
|
+
* shown here.
|
|
10
|
+
*/
|
|
11
|
+
export function formatRootsList(ctx) {
|
|
12
|
+
if (ctx.roots.length === 0) {
|
|
13
|
+
return 'No root directories configured. A vault (~/Noesis) is designated automatically on first use.';
|
|
14
|
+
}
|
|
15
|
+
const OS_LABELS = [
|
|
16
|
+
['win32', 'Windows'],
|
|
17
|
+
['darwin', 'macOS '],
|
|
18
|
+
['linux', 'Linux '],
|
|
19
|
+
];
|
|
20
|
+
const active = ctx.roots.filter((r) => !r.archived_at);
|
|
21
|
+
const archived = ctx.roots.filter((r) => r.archived_at);
|
|
22
|
+
const lines = [];
|
|
23
|
+
let anyMissing = false;
|
|
24
|
+
active.forEach((root, index) => {
|
|
25
|
+
const isVault = ctx.vaultRootId != null && root.id === ctx.vaultRootId;
|
|
26
|
+
lines.push(`${index + 1}. **${root.name}**${isVault ? ' ← YOUR VAULT' : ''}`);
|
|
27
|
+
for (const [key, label] of OS_LABELS) {
|
|
28
|
+
const v = root.local_paths?.[key];
|
|
29
|
+
const marker = key === ctx.clientOs ? ' [active]' : '';
|
|
30
|
+
if (v) {
|
|
31
|
+
lines.push(` ${label}: ${v}${marker}`);
|
|
32
|
+
}
|
|
33
|
+
else if (key === ctx.clientOs) {
|
|
34
|
+
lines.push(` ${label}: (not configured for this OS)${marker}`);
|
|
35
|
+
anyMissing = true;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const resolved = rootLocalBase(ctx, root.id);
|
|
39
|
+
if (resolved) {
|
|
40
|
+
lines.push(` On this machine: ${resolved}`);
|
|
41
|
+
}
|
|
42
|
+
lines.push('');
|
|
43
|
+
});
|
|
44
|
+
let text = `Watched directories (${active.length}):\n\n${lines.join('\n').trimEnd()}`;
|
|
45
|
+
if (archived.length > 0) {
|
|
46
|
+
const rows = archived.map((r) => {
|
|
47
|
+
const oldPaths = OS_LABELS.map(([key]) => r.local_paths?.[key])
|
|
48
|
+
.filter((v) => !!v)
|
|
49
|
+
.join(' | ');
|
|
50
|
+
const target = r.vault_subfolder ? `→ vault: ${r.vault_subfolder}/` : '→ (notes trashed at migration)';
|
|
51
|
+
return `- ${r.name}: ${oldPaths} ${target}`;
|
|
52
|
+
});
|
|
53
|
+
text +=
|
|
54
|
+
`\n\nArchived roots — legacy path translation (${archived.length}):\n` +
|
|
55
|
+
rows.join('\n') +
|
|
56
|
+
`\n\nOld paths under these roots still work: get_note/sync_notes translate them into the vault automatically.`;
|
|
57
|
+
}
|
|
58
|
+
if (anyMissing) {
|
|
59
|
+
text += `\n\nTip: an ACTIVE root missing a path for this OS (${ctx.clientOs}) can't sync on this machine — add the path in the Noesis Dashboard.`;
|
|
60
|
+
}
|
|
61
|
+
return text;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=rootsFormat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rootsFormat.js","sourceRoot":"","sources":["../../src/resolve/rootsFormat.ts"],"names":[],"mappings":"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"}
|
|
@@ -77,25 +77,25 @@ export async function generateMetadata(content) {
|
|
|
77
77
|
if (contentToAnalyze.length > maxChars) {
|
|
78
78
|
contentToAnalyze = contentToAnalyze.substring(0, maxChars) + '...';
|
|
79
79
|
}
|
|
80
|
-
const prompt = `Analyze this markdown document and generate metadata for it.
|
|
81
|
-
|
|
82
|
-
Document content:
|
|
83
|
-
---
|
|
84
|
-
${contentToAnalyze}
|
|
85
|
-
---
|
|
86
|
-
|
|
87
|
-
Generate the following metadata in JSON format:
|
|
88
|
-
1. title: A concise, descriptive title (max 80 chars). IMPORTANT: If the document starts with a # heading on the first line, use that FIRST heading as the title (clean it up if needed). Only generate a new title if there's no H1 heading at the start.
|
|
89
|
-
2. description: A brief summary of what this document is about (1-2 sentences, max 200 chars)
|
|
90
|
-
3. keywords: An array of 5-15 relevant keywords/tags including:
|
|
91
|
-
- Main topics and concepts
|
|
92
|
-
- Technical terms and technologies (Redis, SignalR, MongoDB, etc.)
|
|
93
|
-
- Component/service/class names found in code (e.g., PrintController, BtXmlExecutor, DevicesInternalController)
|
|
94
|
-
- Include BOTH CamelCase (PrintController) AND space-separated (Print Controller) versions of component names
|
|
95
|
-
- API endpoint patterns or route names if mentioned
|
|
96
|
-
Avoid generic words like "document", "file", "note", "example", "sample".
|
|
97
|
-
|
|
98
|
-
Respond with ONLY valid JSON in this exact format, no markdown code blocks:
|
|
80
|
+
const prompt = `Analyze this markdown document and generate metadata for it.
|
|
81
|
+
|
|
82
|
+
Document content:
|
|
83
|
+
---
|
|
84
|
+
${contentToAnalyze}
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
Generate the following metadata in JSON format:
|
|
88
|
+
1. title: A concise, descriptive title (max 80 chars). IMPORTANT: If the document starts with a # heading on the first line, use that FIRST heading as the title (clean it up if needed). Only generate a new title if there's no H1 heading at the start.
|
|
89
|
+
2. description: A brief summary of what this document is about (1-2 sentences, max 200 chars)
|
|
90
|
+
3. keywords: An array of 5-15 relevant keywords/tags including:
|
|
91
|
+
- Main topics and concepts
|
|
92
|
+
- Technical terms and technologies (Redis, SignalR, MongoDB, etc.)
|
|
93
|
+
- Component/service/class names found in code (e.g., PrintController, BtXmlExecutor, DevicesInternalController)
|
|
94
|
+
- Include BOTH CamelCase (PrintController) AND space-separated (Print Controller) versions of component names
|
|
95
|
+
- API endpoint patterns or route names if mentioned
|
|
96
|
+
Avoid generic words like "document", "file", "note", "example", "sample".
|
|
97
|
+
|
|
98
|
+
Respond with ONLY valid JSON in this exact format, no markdown code blocks:
|
|
99
99
|
{"title": "...", "description": "...", "keywords": ["...", "..."]}`;
|
|
100
100
|
try {
|
|
101
101
|
const result = await genAI.models.generateContent({
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backlog.d.ts","sourceRoot":"","sources":["../../src/tools/backlog.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAe3D,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAiLlF"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backlog v2 MCP tools — the loop's view of /api/mcp/backlog. Thin wrappers:
|
|
3
|
+
* every rule (stage legality, OWNER_GATE, freeze, park guards) is enforced
|
|
4
|
+
* server-side; these tools shape requests and return compact JSON text that a
|
|
5
|
+
* driving loop can parse. The owner-only acts (approve / reject / cancel) have
|
|
6
|
+
* NO tool here by design — they exist only on the owner's page.
|
|
7
|
+
*/
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
const STAGE_ENUM = z.enum(['jot', 'refined', 'materialized', 'approved', 'running', 'implemented', 'shipped']);
|
|
10
|
+
const KIND_ENUM = z.enum(['feature', 'bug', 'design', 'process', 'research']);
|
|
11
|
+
const SIZE_ENUM = z.enum(['S', 'M', 'L']);
|
|
12
|
+
function jsonText(data) {
|
|
13
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
14
|
+
}
|
|
15
|
+
function errText(e) {
|
|
16
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
17
|
+
return { content: [{ type: 'text', text: `Backlog tool failed: ${msg}` }], isError: true };
|
|
18
|
+
}
|
|
19
|
+
export function registerBacklogTools(server, client) {
|
|
20
|
+
server.tool('backlog_get', 'Read the Backlog: without a key, list issues (+ per-stage counts, optionally filtered by stage or a text query); with a key (TCK-<n>), the full issue including increments and open owner questions.', {
|
|
21
|
+
key: z.string().optional().describe('Issue key like TCK-7 (omit to list)'),
|
|
22
|
+
stage: STAGE_ENUM.optional().describe('List filter: only this stage'),
|
|
23
|
+
query: z.string().optional().describe('List filter: title/body text search'),
|
|
24
|
+
}, async (args) => {
|
|
25
|
+
try {
|
|
26
|
+
const data = args.key
|
|
27
|
+
? await client.backlogGet(args.key)
|
|
28
|
+
: await client.backlogList({ stage: args.stage, q: args.query });
|
|
29
|
+
return jsonText(data);
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
return errText(e);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
server.tool('backlog_upsert_issue', 'Create a Backlog issue (no key; groom may create in jot/refined/materialized) or update an existing one (with key; content fields only before approval, bookkeeping fields until terminal).', {
|
|
36
|
+
key: z.string().optional().describe('Existing issue key to update; omit to create'),
|
|
37
|
+
title: z.string().optional(),
|
|
38
|
+
kind: KIND_ENUM.optional(),
|
|
39
|
+
size: SIZE_ENUM.optional(),
|
|
40
|
+
origin_jot: z.string().optional().describe('Verbatim original memo text'),
|
|
41
|
+
body_md: z.string().optional().describe('Requirement markdown (Problem / Current / Proposed / Acceptance criteria / NOT-do)'),
|
|
42
|
+
stage: z.enum(['jot', 'refined', 'materialized']).optional().describe('Create-only: initial stage'),
|
|
43
|
+
branch: z.string().optional(),
|
|
44
|
+
worktree: z.string().optional(),
|
|
45
|
+
pr_number: z.number().int().optional(),
|
|
46
|
+
}, async (args) => {
|
|
47
|
+
try {
|
|
48
|
+
if (args.key) {
|
|
49
|
+
const { key, stage: _ignored, ...patch } = args;
|
|
50
|
+
const body = Object.fromEntries(Object.entries(patch).filter(([, v]) => v !== undefined));
|
|
51
|
+
return jsonText(await client.backlogPatch(key, body));
|
|
52
|
+
}
|
|
53
|
+
if (!args.title)
|
|
54
|
+
return errText(new Error('title is required to create an issue'));
|
|
55
|
+
const body = Object.fromEntries(Object.entries(args).filter(([, v]) => v !== undefined));
|
|
56
|
+
return jsonText(await client.backlogCreate(body));
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
return errText(e);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
server.tool('backlog_set_stage', "Move an issue through its lifecycle on the loop surface: jot->refined, refined->materialized (send-back too), approved->running, running->approved (STOP-acknowledge), running->implemented, implemented->shipped. Cannot approve/reject/cancel — those are the owner's page buttons (OWNER_GATE).", {
|
|
63
|
+
key: z.string().describe('Issue key like TCK-7'),
|
|
64
|
+
to: STAGE_ENUM.describe('Target stage (approve only as the running->approved stop-ack)'),
|
|
65
|
+
reason: z.string().optional().describe('Reason for send-backs'),
|
|
66
|
+
}, async (args) => {
|
|
67
|
+
try {
|
|
68
|
+
return jsonText(await client.backlogSetStage(args.key, args.to, args.reason));
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
return errText(e);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
server.tool('backlog_plan_increments', 'Register or refresh the planned increment list for an issue (upsert by sequence; rows that already started are never rewritten).', {
|
|
75
|
+
key: z.string(),
|
|
76
|
+
increments: z
|
|
77
|
+
.array(z.object({
|
|
78
|
+
sequence: z.number().int().positive(),
|
|
79
|
+
name: z.string(),
|
|
80
|
+
type: z.enum(['spike', 'implementation', 'verification', 'refactor']).optional(),
|
|
81
|
+
}))
|
|
82
|
+
.min(1),
|
|
83
|
+
}, async (args) => {
|
|
84
|
+
try {
|
|
85
|
+
return jsonText(await client.backlogPlanIncrements(args.key, args.increments));
|
|
86
|
+
}
|
|
87
|
+
catch (e) {
|
|
88
|
+
return errText(e);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
server.tool('backlog_report_increment', "Report an increment lifecycle edge. phase 'start': marks it running, bumps attempts, stamps model/effort. phase 'finish': status passed|failed|parked|skipped + telemetry (verifier_verdict, gate_results, commits, evidence_md, obstacles_md); duration lands in the trace automatically.", {
|
|
92
|
+
key: z.string(),
|
|
93
|
+
sequence: z.number().int().positive(),
|
|
94
|
+
phase: z.enum(['start', 'finish']),
|
|
95
|
+
model: z.string().optional(),
|
|
96
|
+
effort: z.string().optional(),
|
|
97
|
+
status: z.enum(['passed', 'failed', 'parked', 'skipped']).optional(),
|
|
98
|
+
verifier_verdict: z.enum(['pass', 'fail']).optional(),
|
|
99
|
+
gate_results: z.record(z.string(), z.unknown()).optional(),
|
|
100
|
+
commits: z.array(z.object({ sha: z.string(), message: z.string() })).optional(),
|
|
101
|
+
evidence_md: z.string().optional(),
|
|
102
|
+
obstacles_md: z.string().optional(),
|
|
103
|
+
}, async (args) => {
|
|
104
|
+
try {
|
|
105
|
+
const { key, sequence, ...body } = args;
|
|
106
|
+
const clean = Object.fromEntries(Object.entries(body).filter(([, v]) => v !== undefined));
|
|
107
|
+
return jsonText(await client.backlogReportIncrement(key, sequence, clean));
|
|
108
|
+
}
|
|
109
|
+
catch (e) {
|
|
110
|
+
return errText(e);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
server.tool('backlog_control', 'The iteration-boundary poll: requested control state (run/pause/stop/cancel), stage, frozen vs CURRENT spec hash (both server-computed — compare the two strings; a mismatch means the requirement changed), unanswered owner questions, and discussion since a message cursor.', {
|
|
114
|
+
key: z.string(),
|
|
115
|
+
after_message_id: z.number().int().optional().describe('Return thread messages newer than this id'),
|
|
116
|
+
}, async (args) => {
|
|
117
|
+
try {
|
|
118
|
+
return jsonText(await client.backlogControl(args.key, args.after_message_id));
|
|
119
|
+
}
|
|
120
|
+
catch (e) {
|
|
121
|
+
return errText(e);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
server.tool('backlog_post_message', "The loop's voice on an issue: kind 'answer' + answer_to replies to an owner question WITHOUT stopping work; kind 'question' (+ parks_sequence) asks the owner and parks that increment ([Q] park); kind 'comment' leaves a note.", {
|
|
125
|
+
key: z.string(),
|
|
126
|
+
body_md: z.string(),
|
|
127
|
+
kind: z.enum(['answer', 'question', 'comment']),
|
|
128
|
+
answer_to: z.number().int().optional().describe('Message id of the owner question being answered'),
|
|
129
|
+
parks_sequence: z.number().int().optional().describe("With kind 'question': increment sequence to park"),
|
|
130
|
+
}, async (args) => {
|
|
131
|
+
try {
|
|
132
|
+
const { key, ...body } = args;
|
|
133
|
+
const clean = Object.fromEntries(Object.entries(body).filter(([, v]) => v !== undefined));
|
|
134
|
+
return jsonText(await client.backlogPostMessage(key, clean));
|
|
135
|
+
}
|
|
136
|
+
catch (e) {
|
|
137
|
+
return errText(e);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
server.tool('backlog_append_event', "Append a free-form trace event to an issue (dot-namespaced type like 'gate.result' or 'loop.note'; optional payload, actor claude|verifier|system, and increment sequence linkage).", {
|
|
141
|
+
key: z.string(),
|
|
142
|
+
type: z.string().describe('Dot-namespaced lowercase type, e.g. loop.note'),
|
|
143
|
+
payload: z.record(z.string(), z.unknown()).optional(),
|
|
144
|
+
actor: z.enum(['claude', 'verifier', 'system']).optional(),
|
|
145
|
+
increment_seq: z.number().int().optional(),
|
|
146
|
+
}, async (args) => {
|
|
147
|
+
try {
|
|
148
|
+
const { key, ...body } = args;
|
|
149
|
+
const clean = Object.fromEntries(Object.entries(body).filter(([, v]) => v !== undefined));
|
|
150
|
+
return jsonText(await client.backlogAppendEvent(key, clean));
|
|
151
|
+
}
|
|
152
|
+
catch (e) {
|
|
153
|
+
return errText(e);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=backlog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backlog.js","sourceRoot":"","sources":["../../src/tools/backlog.ts"],"names":[],"mappings":"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"}
|