@creator-notes/cnotes 0.33.0 → 0.35.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 +1 -1
- package/dist/commands/canvas.d.ts.map +1 -1
- package/dist/commands/canvas.js +194 -24
- package/dist/commands/canvas.js.map +1 -1
- package/dist/commands/notes.d.ts.map +1 -1
- package/dist/commands/notes.js +74 -36
- package/dist/commands/notes.js.map +1 -1
- package/dist/commands/operations.d.ts.map +1 -1
- package/dist/commands/operations.js +20 -1
- package/dist/commands/operations.js.map +1 -1
- package/dist/commands/versions.d.ts.map +1 -1
- package/dist/commands/versions.js +27 -5
- package/dist/commands/versions.js.map +1 -1
- package/dist/lib/api-client.d.ts.map +1 -1
- package/dist/lib/api-client.js +6 -1
- package/dist/lib/api-client.js.map +1 -1
- package/dist/lib/build-schema.d.ts +3 -3
- package/dist/lib/build-schema.d.ts.map +1 -1
- package/dist/lib/build-schema.js +4 -3
- package/dist/lib/build-schema.js.map +1 -1
- package/dist/lib/mention-lint.d.ts +42 -0
- package/dist/lib/mention-lint.d.ts.map +1 -1
- package/dist/lib/mention-lint.js +175 -0
- package/dist/lib/mention-lint.js.map +1 -1
- package/dist/lib/rubrics.d.ts +60 -0
- package/dist/lib/rubrics.d.ts.map +1 -0
- package/dist/lib/rubrics.js +66 -0
- package/dist/lib/rubrics.js.map +1 -0
- package/dist/mcp-server.js +41 -28
- package/dist/mcp-server.js.map +1 -1
- package/package.json +1 -1
- package/skills/cnotes/SKILL.md +52 -13
- package/skills/cnotes/references/humanizer.md +7 -1
package/dist/lib/mention-lint.js
CHANGED
|
@@ -83,6 +83,181 @@ export function lintMentionMarkdown(markdown, allowAtKey) {
|
|
|
83
83
|
}
|
|
84
84
|
return issues;
|
|
85
85
|
}
|
|
86
|
+
/** Parse a wiki-link body (`[[inner]]`): target + optional type, either order
|
|
87
|
+
* (`[[blocks::DEC-3]]` and `[[DEC-3::blocks]]` both bind — mirror of
|
|
88
|
+
* lib/tiptap/markdown-extensions.ts). Returns null for ordinary wiki prose. */
|
|
89
|
+
function parseWikiInner(inner) {
|
|
90
|
+
const noAlias = inner.split("|")[0].trim();
|
|
91
|
+
const parts = noAlias.split("::").map((s) => s.trim());
|
|
92
|
+
const isTarget = (s) => DISPLAY_ID_RE.test(s) || AT_KEY_RE.test(s);
|
|
93
|
+
if (parts.length === 1) {
|
|
94
|
+
return isTarget(parts[0]) ? { target: parts[0], type: null } : null;
|
|
95
|
+
}
|
|
96
|
+
if (parts.length === 2) {
|
|
97
|
+
if (isTarget(parts[1]))
|
|
98
|
+
return { target: parts[1], type: parts[0].toLowerCase() || null };
|
|
99
|
+
if (isTarget(parts[0]))
|
|
100
|
+
return { target: parts[0], type: parts[1].toLowerCase() || null };
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
const WIKI_RE = /\[\[([^\]]+)\]\]/g;
|
|
105
|
+
/** Collect every mention on one line, both `[T](relationship:t)` and `[[T]]`. */
|
|
106
|
+
function findMentions(line) {
|
|
107
|
+
const found = [];
|
|
108
|
+
for (const m of line.matchAll(MENTION_RE)) {
|
|
109
|
+
const linkText = m[1];
|
|
110
|
+
found.push({
|
|
111
|
+
raw: m[0],
|
|
112
|
+
index: m.index ?? 0,
|
|
113
|
+
effectiveType: m[2].trim().toLowerCase(),
|
|
114
|
+
retype: (t) => `[${linkText}](relationship:${t})`,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
for (const m of line.matchAll(WIKI_RE)) {
|
|
118
|
+
const parsed = parseWikiInner(m[1]);
|
|
119
|
+
if (!parsed)
|
|
120
|
+
continue;
|
|
121
|
+
found.push({
|
|
122
|
+
raw: m[0],
|
|
123
|
+
index: m.index ?? 0,
|
|
124
|
+
effectiveType: parsed.type ?? "references",
|
|
125
|
+
retype: (t) => `[[${t}::${parsed.target}]]`,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
return found.sort((a, b) => a.index - b.index);
|
|
129
|
+
}
|
|
130
|
+
/** Prose forms for each type: the label and the de-hyphenated slug. The
|
|
131
|
+
* `references` type is excluded — it's what generic mentions already are. */
|
|
132
|
+
function buildTypePhrases(types) {
|
|
133
|
+
const phrases = [];
|
|
134
|
+
const seen = new Set();
|
|
135
|
+
for (const t of types) {
|
|
136
|
+
const value = t.value.trim().toLowerCase();
|
|
137
|
+
if (!value || value === "references")
|
|
138
|
+
continue;
|
|
139
|
+
for (const phrase of new Set([
|
|
140
|
+
t.label.trim().toLowerCase(),
|
|
141
|
+
value.replace(/-/g, " "),
|
|
142
|
+
])) {
|
|
143
|
+
if (!phrase || seen.has(phrase))
|
|
144
|
+
continue;
|
|
145
|
+
seen.add(phrase);
|
|
146
|
+
phrases.push({ phrase, value, label: t.label });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// Longest first so "depends on" wins over a hypothetical "depends".
|
|
150
|
+
return phrases.sort((a, b) => b.phrase.length - a.phrase.length);
|
|
151
|
+
}
|
|
152
|
+
/** Strip list/quote/heading markers and opening emphasis from a line start. */
|
|
153
|
+
function stripLineDecoration(line) {
|
|
154
|
+
return line
|
|
155
|
+
.replace(/^[\s>]*/, "")
|
|
156
|
+
.replace(/^(?:[-*+]\s+|\d+[.)]\s+|#{1,6}\s+)/, "")
|
|
157
|
+
.replace(/^[*_]{1,3}/, "");
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Lint one markdown body for relationship verbs narrated in prose next to a
|
|
161
|
+
* GENERIC mention (`relationship:references` or untyped `[[NOTE-12]]`).
|
|
162
|
+
* Fires when a line STARTS with a type's verb, or when the verb sits
|
|
163
|
+
* immediately before the mention. Mentions that already carry a specific type
|
|
164
|
+
* are never flagged, even if the prose disagrees — that's a judgment call, not
|
|
165
|
+
* a lint. Fenced code blocks are skipped.
|
|
166
|
+
*
|
|
167
|
+
* @param types workspace relationship types (fetch via
|
|
168
|
+
* `fetchRelationshipTypeOptions`); pass [] to disable.
|
|
169
|
+
*/
|
|
170
|
+
export function lintNarratedVerbMentions(markdown, types) {
|
|
171
|
+
const typePhrases = buildTypePhrases(types);
|
|
172
|
+
if (typePhrases.length === 0)
|
|
173
|
+
return [];
|
|
174
|
+
const warnings = [];
|
|
175
|
+
let inFence = false;
|
|
176
|
+
markdown.split(/\r?\n/).forEach((line, i) => {
|
|
177
|
+
if (/^\s*(```|~~~)/.test(line)) {
|
|
178
|
+
inFence = !inFence;
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (inFence)
|
|
182
|
+
return;
|
|
183
|
+
const generics = findMentions(line).filter((m) => m.effectiveType === "references");
|
|
184
|
+
if (generics.length === 0)
|
|
185
|
+
return;
|
|
186
|
+
// Rule B: verb immediately before a generic mention ("this blocks [[X]]").
|
|
187
|
+
const claimed = new Set();
|
|
188
|
+
for (const mention of generics) {
|
|
189
|
+
const before = line.slice(0, mention.index).trimEnd().toLowerCase();
|
|
190
|
+
for (const p of typePhrases) {
|
|
191
|
+
if (!before.endsWith(p.phrase))
|
|
192
|
+
continue;
|
|
193
|
+
const pre = before.slice(0, before.length - p.phrase.length);
|
|
194
|
+
if (pre !== "" && !/[^a-z0-9]$/.test(pre))
|
|
195
|
+
continue;
|
|
196
|
+
const start = line.toLowerCase().lastIndexOf(p.phrase, mention.index);
|
|
197
|
+
warnings.push(makeWarning(i + 1, line.slice(start, start + p.phrase.length), p, mention));
|
|
198
|
+
claimed.add(mention);
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
// Rule A: line leads with a verb, generic mention anywhere after it
|
|
203
|
+
// ("Blocks clean filmstrip of [[X]]."). First unclaimed mention gets it.
|
|
204
|
+
const stripped = stripLineDecoration(line);
|
|
205
|
+
const strippedLower = stripped.toLowerCase();
|
|
206
|
+
const target = generics.find((m) => !claimed.has(m));
|
|
207
|
+
if (!target)
|
|
208
|
+
return;
|
|
209
|
+
for (const p of typePhrases) {
|
|
210
|
+
if (!strippedLower.startsWith(p.phrase))
|
|
211
|
+
continue;
|
|
212
|
+
if (!/^[\s:,.!*_—-]/.test(strippedLower.slice(p.phrase.length)))
|
|
213
|
+
continue;
|
|
214
|
+
warnings.push(makeWarning(i + 1, stripped.slice(0, p.phrase.length), p, target));
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
return warnings;
|
|
219
|
+
}
|
|
220
|
+
function makeWarning(line, verb, p, mention) {
|
|
221
|
+
const rewrite = mention.retype(p.value);
|
|
222
|
+
return {
|
|
223
|
+
line,
|
|
224
|
+
verb,
|
|
225
|
+
suggestedType: p.value,
|
|
226
|
+
mention: mention.raw,
|
|
227
|
+
rewrite,
|
|
228
|
+
message: `prose "${verb}" narrates a relationship the graph can't see — ` +
|
|
229
|
+
`${mention.raw} files a plain reference. If the claim is real, retype ` +
|
|
230
|
+
`the mention: ${rewrite} (workspace type "${p.label}") and drop the ` +
|
|
231
|
+
`now-redundant verb. If "${verb}" isn't asserting a relationship here, ` +
|
|
232
|
+
`ignore this warning.`,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
/** Cheap gate: does this body contain any generic mention at all? Used to
|
|
236
|
+
* skip the relationship-types fetch when no warning could possibly fire. */
|
|
237
|
+
export function hasGenericMention(markdown) {
|
|
238
|
+
for (const m of markdown.matchAll(MENTION_RE)) {
|
|
239
|
+
if (m[2].trim().toLowerCase() === "references")
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
for (const m of markdown.matchAll(WIKI_RE)) {
|
|
243
|
+
const parsed = parseWikiInner(m[1]);
|
|
244
|
+
if (parsed && parsed.type === null)
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
/** Fetch the workspace's relationship types for the narrated-verb lint.
|
|
250
|
+
* Best-effort: returns null on any failure — the lint is advisory and must
|
|
251
|
+
* never fail (or slow-fail) a write. */
|
|
252
|
+
export async function fetchRelationshipTypeOptions(api, workspaceId) {
|
|
253
|
+
try {
|
|
254
|
+
const data = await api.get("/api/relationship-types", { workspaceId });
|
|
255
|
+
return data.relationshipTypes ?? [];
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
86
261
|
/**
|
|
87
262
|
* Format the server's `unresolvedMentions` into an actionable block. Returns
|
|
88
263
|
* null when there's nothing to report.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mention-lint.js","sourceRoot":"","sources":["../../src/lib/mention-lint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH;;4EAE4E;AAC5E,MAAM,aAAa,GAAG,uCAAuC,CAAC;AAC9D,sEAAsE;AACtE,MAAM,SAAS,GAAG,mBAAmB,CAAC;AACtC,6DAA6D;AAC7D,MAAM,UAAU,GAAG,uCAAuC,CAAC;AAa3D,sFAAsF;AACtF,SAAS,QAAQ,CAAC,QAAgB;IAChC,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACpC,OAAO,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AACrE,CAAC;AAED,SAAS,aAAa,CAAC,MAAc,EAAE,UAAmB;IACxD,IAAI,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5C,IAAI,UAAU,IAAI,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IACtD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CACjC,QAAgB,EAChB,UAAmB;IAEnB,MAAM,MAAM,GAAuB,EAAE,CAAC;IACtC,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9C,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACjB,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACtB,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAClC,IAAI,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC;YAAE,SAAS;QAEhD,IAAI,OAAe,CAAC;QACpB,IAAI,MAAM,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YAChD,6DAA6D;YAC7D,OAAO;gBACL,cAAc,MAAM,iDAAiD;oBACrE,oDAAoD;oBACpD,sEAAsE;oBACtE,SAAS,IAAI,uCAAuC,IAAI,KAAK,CAAC;QAClE,CAAC;aAAM,IAAI,UAAU,IAAI,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1E,OAAO;gBACL,cAAc,MAAM,sDAAsD;oBAC1E,qEAAqE,IAAI,IAAI;oBAC7E,qCAAqC,IAAI,IAAI,CAAC;QAClD,CAAC;aAAM,CAAC;YACN,OAAO;gBACL,cAAc,MAAM,4CAA4C;oBAChE,qBAAqB,UAAU,CAAC,CAAC,CAAC,wCAAwC,CAAC,CAAC,CAAC,EAAE,KAAK;oBACpF,+DAA+D,IAAI,IAAI,CAAC;QAC5E,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAQD;;;GAGG;AACH,MAAM,UAAU,0BAA0B,CACxC,UAAmB;IAEnB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACvE,MAAM,KAAK,GAAI,UAAkC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAC1D,MAAM,MAAM,GAAG,CAAC,CAAC,SAAS,IAAI,WAAW,CAAC;QAC1C,MAAM,IAAI,GAAG,CAAC,CAAC,gBAAgB,IAAI,YAAY,CAAC;QAChD,MAAM,aAAa,GACjB,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ;YAC/B,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;QACnD,MAAM,GAAG,GAAG,aAAa;YACvB,CAAC,CAAC,qCAAqC,IAAI,kEAAkE;YAC7G,CAAC,CAAC,YAAY,MAAM,oEAAoE,CAAC;QAC3F,OAAO,QAAQ,MAAM,kBAAkB,IAAI,MAAM,GAAG,EAAE,CAAC;IACzD,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
|
1
|
+
{"version":3,"file":"mention-lint.js","sourceRoot":"","sources":["../../src/lib/mention-lint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type-rubric helpers for the authoring loop.
|
|
3
|
+
*
|
|
4
|
+
* Rubrics (`validationPrompt` on each supertag) are the quality standard for
|
|
5
|
+
* a note type. Agents habitually filter create responses down to
|
|
6
|
+
* `.results[].displayId`, so a sibling top-level `rubrics` array is invisible
|
|
7
|
+
* unless the agent already knows to look. These helpers:
|
|
8
|
+
*
|
|
9
|
+
* 1. Load the workspace's type → rubric map (non-fatal on failure).
|
|
10
|
+
* 2. Attach `type` + `rubric` onto each create result item so a `.results[]`
|
|
11
|
+
* extraction carries the standard along with the displayId.
|
|
12
|
+
* 3. Build a compact `{ type, rubric }[]` list for pre-write surfaces
|
|
13
|
+
* (`operations begin`), so the text is in context before authoring starts.
|
|
14
|
+
*/
|
|
15
|
+
import type { ApiClient } from "./api-client.js";
|
|
16
|
+
export type TypeRubric = {
|
|
17
|
+
type: string;
|
|
18
|
+
/** Null when the type exists but has no validationPrompt. */
|
|
19
|
+
rubric: string | null;
|
|
20
|
+
};
|
|
21
|
+
/** Case-insensitive map of type display name → validationPrompt text. */
|
|
22
|
+
export type RubricMap = Map<string, string>;
|
|
23
|
+
/**
|
|
24
|
+
* Fetch every workspace type that has a validationPrompt.
|
|
25
|
+
* Returns an empty map (never throws) when the request fails — rubric echo
|
|
26
|
+
* must never fail a successful create / begin.
|
|
27
|
+
*/
|
|
28
|
+
export declare function loadRubricMap(api: ApiClient, workspaceId: string): Promise<RubricMap>;
|
|
29
|
+
/**
|
|
30
|
+
* Compact list of `{ type, rubric }` for the distinct types in `typeNames`
|
|
31
|
+
* that have a validationPrompt. Preserves first-seen casing from `typeNames`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function rubricsForTypes(typeNames: string[], map: RubricMap): Array<{
|
|
34
|
+
type: string;
|
|
35
|
+
rubric: string;
|
|
36
|
+
}>;
|
|
37
|
+
/**
|
|
38
|
+
* Every type in the workspace that has a validationPrompt, for pre-write
|
|
39
|
+
* surfaces (`operations begin`). Sorted by type name for stable output.
|
|
40
|
+
*/
|
|
41
|
+
export declare function allWorkspaceRubrics(map: RubricMap): Array<{
|
|
42
|
+
type: string;
|
|
43
|
+
rubric: string;
|
|
44
|
+
}>;
|
|
45
|
+
type CreateResult = Record<string, unknown> & {
|
|
46
|
+
key?: string;
|
|
47
|
+
displayId?: string;
|
|
48
|
+
noteId?: string;
|
|
49
|
+
title?: string;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Attach `type` + `rubric` onto each create result.
|
|
53
|
+
*
|
|
54
|
+
* `typeByKey` maps the batch item key → type string from the create request.
|
|
55
|
+
* Types without a validationPrompt get `rubric: null` so the gap is visible
|
|
56
|
+
* (several default types ship without one).
|
|
57
|
+
*/
|
|
58
|
+
export declare function attachRubricsToResults<T extends CreateResult>(results: T[], typeByKey: Map<string, string>, map: RubricMap): Array<T & TypeRubric>;
|
|
59
|
+
export {};
|
|
60
|
+
//# sourceMappingURL=rubrics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rubrics.d.ts","sourceRoot":"","sources":["../../src/lib/rubrics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF,yEAAyE;AACzE,MAAM,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE5C;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,SAAS,EACd,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,SAAS,CAAC,CAiBpB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EAAE,EACnB,GAAG,EAAE,SAAS,GACb,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAWzC;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,SAAS,GAAG,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAI3F;AAED,KAAK,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAC5C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,YAAY,EAC3D,OAAO,EAAE,CAAC,EAAE,EACZ,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,GAAG,EAAE,SAAS,GACb,KAAK,CAAC,CAAC,GAAG,UAAU,CAAC,CAMvB"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetch every workspace type that has a validationPrompt.
|
|
3
|
+
* Returns an empty map (never throws) when the request fails — rubric echo
|
|
4
|
+
* must never fail a successful create / begin.
|
|
5
|
+
*/
|
|
6
|
+
export async function loadRubricMap(api, workspaceId) {
|
|
7
|
+
try {
|
|
8
|
+
const supertags = await api.get("/api/supertags", {
|
|
9
|
+
workspaceId,
|
|
10
|
+
});
|
|
11
|
+
const byName = new Map();
|
|
12
|
+
for (const s of Array.isArray(supertags) ? supertags : []) {
|
|
13
|
+
const nm = String(s.name || "").toLowerCase();
|
|
14
|
+
const prompt = s.validationPrompt;
|
|
15
|
+
if (nm && typeof prompt === "string" && prompt.trim()) {
|
|
16
|
+
byName.set(nm, prompt);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return byName;
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return new Map();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Compact list of `{ type, rubric }` for the distinct types in `typeNames`
|
|
27
|
+
* that have a validationPrompt. Preserves first-seen casing from `typeNames`.
|
|
28
|
+
*/
|
|
29
|
+
export function rubricsForTypes(typeNames, map) {
|
|
30
|
+
const seen = new Set();
|
|
31
|
+
const out = [];
|
|
32
|
+
for (const raw of typeNames) {
|
|
33
|
+
const key = raw.toLowerCase();
|
|
34
|
+
if (seen.has(key))
|
|
35
|
+
continue;
|
|
36
|
+
seen.add(key);
|
|
37
|
+
const rubric = map.get(key);
|
|
38
|
+
if (rubric)
|
|
39
|
+
out.push({ type: raw, rubric });
|
|
40
|
+
}
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Every type in the workspace that has a validationPrompt, for pre-write
|
|
45
|
+
* surfaces (`operations begin`). Sorted by type name for stable output.
|
|
46
|
+
*/
|
|
47
|
+
export function allWorkspaceRubrics(map) {
|
|
48
|
+
return Array.from(map.entries())
|
|
49
|
+
.map(([type, rubric]) => ({ type, rubric }))
|
|
50
|
+
.sort((a, b) => a.type.localeCompare(b.type));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Attach `type` + `rubric` onto each create result.
|
|
54
|
+
*
|
|
55
|
+
* `typeByKey` maps the batch item key → type string from the create request.
|
|
56
|
+
* Types without a validationPrompt get `rubric: null` so the gap is visible
|
|
57
|
+
* (several default types ship without one).
|
|
58
|
+
*/
|
|
59
|
+
export function attachRubricsToResults(results, typeByKey, map) {
|
|
60
|
+
return results.map((r) => {
|
|
61
|
+
const type = (r.key ? typeByKey.get(String(r.key)) : undefined) ?? String(r.type ?? "");
|
|
62
|
+
const rubric = type ? map.get(type.toLowerCase()) ?? null : null;
|
|
63
|
+
return { ...r, type, rubric };
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=rubrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rubrics.js","sourceRoot":"","sources":["../../src/lib/rubrics.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp-server.js
CHANGED
|
@@ -29,6 +29,8 @@ import { resolveNoteId } from "./lib/resolve-note.js";
|
|
|
29
29
|
import { readCanvasMarkdown } from "./lib/canvas-read.js";
|
|
30
30
|
import { buildSchema } from "./lib/build-schema.js";
|
|
31
31
|
import { assertMcpLocalFileReadable, getMcpLocalFileRoots, } from "./lib/mcp-local-file.js";
|
|
32
|
+
import { attachRubricsToResults, loadRubricMap, rubricsForTypes, } from "./lib/rubrics.js";
|
|
33
|
+
import { lintNarratedVerbMentions, hasGenericMention, fetchRelationshipTypeOptions, } from "./lib/mention-lint.js";
|
|
32
34
|
// ---------------------------------------------------------------------------
|
|
33
35
|
// Environment
|
|
34
36
|
// ---------------------------------------------------------------------------
|
|
@@ -233,41 +235,40 @@ const NoteCreateItem = z.object({
|
|
|
233
235
|
markdown: z.string().describe("Note content as markdown (the first # h1 heading becomes the title)"),
|
|
234
236
|
tags: z.array(z.string()).optional().describe("Tags for this note"),
|
|
235
237
|
});
|
|
236
|
-
server.tool("cnotes_notes_create", "Create one or more interlinked notes in a single atomic transaction. FIRST
|
|
238
|
+
server.tool("cnotes_notes_create", "Create one or more interlinked notes in a single atomic transaction. FIRST call cnotes_types_show for each target type and author to that rubric — do not skip this. Pass `notes` as one item object or an array; each note's title is its first # h1 heading. Cross-reference in markdown with [@key: Title](relationship:type) (same-batch — @key resolves to the new display ID) or [NOTE-12: Title](relationship:type) (existing note); ALWAYS include the ': Title' part. Pick the relationship type from the verb your own prose uses ('blocks', 'depends-on', …; free-form — unknown types auto-create); reserve 'references' for pure citations — a verb narrated in prose around a 'references' chip is invisible to backlinks. A `mentionWarnings` array in the result flags narrated verbs it detects; treat each as a retype instruction unless the prose genuinely isn't asserting a relationship. Each result item carries `type` + `rubric` (null when the type has no validationPrompt); a top-level `rubrics` array is also present. On validation failure, `details.items` pinpoints the bad item by index + key.", {
|
|
237
239
|
notes: z
|
|
238
240
|
.union([NoteCreateItem, z.array(NoteCreateItem).min(1)])
|
|
239
241
|
.describe("Either a single item object or a non-empty array of items."),
|
|
240
242
|
}, async ({ notes }) => withErrorHandling(async () => {
|
|
241
243
|
const items = Array.isArray(notes) ? notes : [notes];
|
|
244
|
+
// Narrated-verb lint (warn-only, pre-send): MCP has no stderr channel,
|
|
245
|
+
// so `mentionWarnings` in the result is the only way the model sees it.
|
|
246
|
+
let mentionWarnings = [];
|
|
247
|
+
if (items.some((n) => hasGenericMention(String(n.markdown ?? "")))) {
|
|
248
|
+
const relTypes = await fetchRelationshipTypeOptions(api, workspaceId);
|
|
249
|
+
if (relTypes) {
|
|
250
|
+
mentionWarnings = items.flatMap((n) => lintNarratedVerbMentions(String(n.markdown ?? ""), relTypes).map((w) => ({ item: n.key, ...w })));
|
|
251
|
+
}
|
|
252
|
+
}
|
|
242
253
|
const result = await api.post("/api/notes/bulk", {
|
|
243
254
|
action: "bulkCreate",
|
|
244
255
|
workspaceId,
|
|
245
256
|
notes: items,
|
|
246
257
|
});
|
|
247
|
-
//
|
|
248
|
-
//
|
|
249
|
-
// create already succeeded if we got here.
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
.map((t) => ({ type: t, rubric: byName.get(t.toLowerCase()) || "" }))
|
|
262
|
-
.filter((r) => r.rubric);
|
|
263
|
-
if (rubrics.length > 0 && result && typeof result === "object") {
|
|
264
|
-
result.rubrics = rubrics;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
catch {
|
|
268
|
-
// Skip the rubric echo if supertags can't be fetched.
|
|
269
|
-
}
|
|
270
|
-
return result;
|
|
258
|
+
// Attach rubrics ON EACH result so filtering to results[] still carries
|
|
259
|
+
// the standard. Top-level rubrics kept for backward compatibility.
|
|
260
|
+
// Non-fatal: create already succeeded if we got here.
|
|
261
|
+
const rubricMap = await loadRubricMap(api, workspaceId);
|
|
262
|
+
const typeByKey = new Map(items.map((n) => [n.key, n.type]));
|
|
263
|
+
const rawResults = (result.results || []);
|
|
264
|
+
const enriched = attachRubricsToResults(rawResults, typeByKey, rubricMap);
|
|
265
|
+
const rubrics = rubricsForTypes(items.map((n) => String(n.type)), rubricMap);
|
|
266
|
+
return {
|
|
267
|
+
...result,
|
|
268
|
+
results: enriched,
|
|
269
|
+
...(rubrics.length > 0 ? { rubrics } : {}),
|
|
270
|
+
...(mentionWarnings.length > 0 ? { mentionWarnings } : {}),
|
|
271
|
+
};
|
|
271
272
|
}));
|
|
272
273
|
server.tool("cnotes_notes_retype", "Change a single note's type. Atomic operation: creates a new note with the target type, archives the old one, and cross-links both.", {
|
|
273
274
|
noteId: z.string().describe("Display ID of the note to retype (e.g. NOTE-1)"),
|
|
@@ -590,7 +591,7 @@ server.tool("cnotes_canvas_bulk_remove", "Remove multiple nodes from a canvas in
|
|
|
590
591
|
action: "bulkRemoveNodes",
|
|
591
592
|
nodeIds,
|
|
592
593
|
})));
|
|
593
|
-
server.tool("cnotes_canvas_add_edge", "Connect two nodes on a canvas with an edge. Defaults to an arrow at the target end and a solid line.", {
|
|
594
|
+
server.tool("cnotes_canvas_add_edge", "Connect two nodes on a canvas with an edge (any node type, including section frames). Defaults to an arrow at the target end and a solid line.", {
|
|
594
595
|
canvasId: z.string().describe("Canvas ID"),
|
|
595
596
|
sourceNodeId: z.string().describe("Source node ID"),
|
|
596
597
|
targetNodeId: z.string().describe("Target node ID"),
|
|
@@ -852,16 +853,28 @@ server.tool("cnotes_versions_list", "List versions of a note.", {
|
|
|
852
853
|
throw new Error(`Note not found: ${noteId}`);
|
|
853
854
|
return note.versions || [];
|
|
854
855
|
}));
|
|
855
|
-
server.tool("cnotes_versions_create", "Create a new version of a note. Content is markdown. To link to other notes, use [NOTE-123: Title](relationship:
|
|
856
|
+
server.tool("cnotes_versions_create", "Create a new version of a note. Content is markdown. To link to other notes, use [NOTE-123: Title](relationship:type) inside the markdown — always include the title (the part after the colon) or the chip renders as 'Untitled'. Pick the relationship type from the verb your own prose uses ('blocks', 'depends-on', 'caused-by', …; free-form — unknown types auto-create); reserve 'references' for pure citations — a verb narrated in prose around a 'references' chip is invisible to backlinks. A `mentionWarnings` array in the result flags narrated verbs it detects; treat each as a retype instruction unless the prose genuinely isn't asserting a relationship.", {
|
|
856
857
|
noteId: z.string().describe("Note display ID or Convex ID"),
|
|
857
858
|
markdown: z.string().describe("New content as markdown"),
|
|
858
859
|
description: z.string().describe("Change description (required)"),
|
|
859
860
|
}, async ({ noteId, markdown, description }) => withErrorHandling(async () => {
|
|
861
|
+
// Narrated-verb lint (warn-only): same contract as cnotes_notes_create.
|
|
862
|
+
let mentionWarnings = [];
|
|
863
|
+
if (hasGenericMention(markdown)) {
|
|
864
|
+
const relTypes = await fetchRelationshipTypeOptions(api, workspaceId);
|
|
865
|
+
if (relTypes) {
|
|
866
|
+
mentionWarnings = lintNarratedVerbMentions(markdown, relTypes).map((w) => ({ ...w }));
|
|
867
|
+
}
|
|
868
|
+
}
|
|
860
869
|
const resolvedId = await resolveNoteId(api, workspaceId, noteId);
|
|
861
|
-
|
|
870
|
+
const data = await api.post(`/api/notes/${resolvedId}/versions`, {
|
|
862
871
|
content: markdown,
|
|
863
872
|
description,
|
|
864
873
|
});
|
|
874
|
+
return {
|
|
875
|
+
...data,
|
|
876
|
+
...(mentionWarnings.length > 0 ? { mentionWarnings } : {}),
|
|
877
|
+
};
|
|
865
878
|
}));
|
|
866
879
|
// ---------------------------------------------------------------------------
|
|
867
880
|
// Workspace
|