openalmanac 0.4.3 → 0.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/tool-tracking.d.ts +22 -0
- package/dist/tool-tracking.js +40 -24
- package/dist/tools/pages/index.js +35 -1
- package/package.json +1 -1
package/dist/tool-tracking.d.ts
CHANGED
|
@@ -1,14 +1,34 @@
|
|
|
1
1
|
import type { FastMCP } from "fastmcp";
|
|
2
2
|
type ToolGroup = "read" | "write" | "research" | "wiki_admin" | "account";
|
|
3
|
+
type EntityType = "account" | "image" | "page" | "topic" | "web" | "wiki";
|
|
4
|
+
type MutationScope = "none" | "local" | "backend" | "backend_dry_run";
|
|
3
5
|
type IntentDomain = "auth" | "page_read" | "page_write" | "search" | "topic_management" | "web_research" | "wiki_management";
|
|
4
6
|
export interface McpToolCallEvent {
|
|
5
7
|
tool_name: string;
|
|
6
8
|
tool_group: ToolGroup;
|
|
7
9
|
intent_domain: IntentDomain;
|
|
10
|
+
operation: string;
|
|
11
|
+
entity_type: EntityType;
|
|
12
|
+
mutation_scope: MutationScope;
|
|
8
13
|
success: boolean;
|
|
9
14
|
duration_ms: number;
|
|
10
15
|
mcp_version: string;
|
|
11
16
|
error_type?: string;
|
|
17
|
+
wiki_slug?: string;
|
|
18
|
+
dry_run?: boolean;
|
|
19
|
+
requested_count?: number;
|
|
20
|
+
result_count?: number;
|
|
21
|
+
result_created_count?: number;
|
|
22
|
+
result_updated_count?: number;
|
|
23
|
+
result_renamed_count?: number;
|
|
24
|
+
result_unchanged_count?: number;
|
|
25
|
+
result_error_count?: number;
|
|
26
|
+
result_skipped_count?: number;
|
|
27
|
+
result_stub_created_count?: number;
|
|
28
|
+
planned_created_count?: number;
|
|
29
|
+
planned_updated_count?: number;
|
|
30
|
+
planned_renamed_count?: number;
|
|
31
|
+
planned_error_count?: number;
|
|
12
32
|
}
|
|
13
33
|
interface McpToolDefinition {
|
|
14
34
|
name: string;
|
|
@@ -21,6 +41,8 @@ interface ToolTrackingDeps {
|
|
|
21
41
|
trackToolCall?: (event: McpToolCallEvent) => Promise<void>;
|
|
22
42
|
now?: () => number;
|
|
23
43
|
}
|
|
44
|
+
export type McpTrackingDetails = Partial<Omit<McpToolCallEvent, "tool_name" | "tool_group" | "intent_domain" | "success" | "duration_ms" | "mcp_version" | "error_type">>;
|
|
45
|
+
export declare function setMcpTrackingDetails(details: McpTrackingDetails): void;
|
|
24
46
|
export declare function postMcpToolCall(event: McpToolCallEvent): Promise<void>;
|
|
25
47
|
export declare function wrapMcpToolDefinition<T extends McpToolDefinition>(definition: T, deps: ToolTrackingDeps): T;
|
|
26
48
|
export declare function installMcpToolTracking(server: FastMCP, mcpVersion: string): FastMCP;
|
package/dist/tool-tracking.js
CHANGED
|
@@ -1,31 +1,45 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
1
2
|
import { request, requireValidApiKey } from "./auth.js";
|
|
2
3
|
const AUTH_EXEMPT_TOOLS = new Set(["login", "logout"]);
|
|
4
|
+
const trackingDetailsStorage = new AsyncLocalStorage();
|
|
5
|
+
export function setMcpTrackingDetails(details) {
|
|
6
|
+
const store = trackingDetailsStorage.getStore();
|
|
7
|
+
if (store) {
|
|
8
|
+
store.details = { ...store.details, ...details };
|
|
9
|
+
}
|
|
10
|
+
}
|
|
3
11
|
const TOOL_METADATA = {
|
|
4
|
-
search_pages: { tool_group: "read", intent_domain: "search" },
|
|
5
|
-
search_topics: { tool_group: "read", intent_domain: "search" },
|
|
6
|
-
list_pages: { tool_group: "read", intent_domain: "page_read" },
|
|
7
|
-
list_topics: { tool_group: "read", intent_domain: "page_read" },
|
|
8
|
-
list_wikis: { tool_group: "read", intent_domain: "wiki_management" },
|
|
9
|
-
download: { tool_group: "read", intent_domain: "page_read" },
|
|
10
|
-
read_page: { tool_group: "read", intent_domain: "page_read" },
|
|
11
|
-
search_web: { tool_group: "research", intent_domain: "web_research" },
|
|
12
|
-
read_webpage: { tool_group: "research", intent_domain: "web_research" },
|
|
13
|
-
search_images: { tool_group: "research", intent_domain: "web_research" },
|
|
14
|
-
view_images: { tool_group: "research", intent_domain: "web_research" },
|
|
15
|
-
new: { tool_group: "write", intent_domain: "page_write" },
|
|
16
|
-
publish: { tool_group: "write", intent_domain: "page_write" },
|
|
17
|
-
delete_pages: { tool_group: "write", intent_domain: "page_write" },
|
|
18
|
-
create_topics: { tool_group: "write", intent_domain: "topic_management" },
|
|
19
|
-
update_topic: { tool_group: "write", intent_domain: "topic_management" },
|
|
20
|
-
create_wiki: { tool_group: "wiki_admin", intent_domain: "wiki_management" },
|
|
21
|
-
get_wiki_settings: { tool_group: "wiki_admin", intent_domain: "wiki_management" },
|
|
22
|
-
update_wiki_settings: { tool_group: "wiki_admin", intent_domain: "wiki_management" },
|
|
23
|
-
join_wiki: { tool_group: "wiki_admin", intent_domain: "wiki_management" },
|
|
24
|
-
get_wiki_membership: { tool_group: "wiki_admin", intent_domain: "wiki_management" },
|
|
25
|
-
whoami: { tool_group: "account", intent_domain: "auth" },
|
|
12
|
+
search_pages: { tool_group: "read", intent_domain: "search", operation: "page_search", entity_type: "page", mutation_scope: "none" },
|
|
13
|
+
search_topics: { tool_group: "read", intent_domain: "search", operation: "topic_search", entity_type: "topic", mutation_scope: "none" },
|
|
14
|
+
list_pages: { tool_group: "read", intent_domain: "page_read", operation: "page_list", entity_type: "page", mutation_scope: "none" },
|
|
15
|
+
list_topics: { tool_group: "read", intent_domain: "page_read", operation: "topic_list", entity_type: "topic", mutation_scope: "none" },
|
|
16
|
+
list_wikis: { tool_group: "read", intent_domain: "wiki_management", operation: "wiki_list", entity_type: "wiki", mutation_scope: "none" },
|
|
17
|
+
download: { tool_group: "read", intent_domain: "page_read", operation: "page_download", entity_type: "page", mutation_scope: "local" },
|
|
18
|
+
read_page: { tool_group: "read", intent_domain: "page_read", operation: "page_read", entity_type: "page", mutation_scope: "none" },
|
|
19
|
+
search_web: { tool_group: "research", intent_domain: "web_research", operation: "web_search", entity_type: "web", mutation_scope: "none" },
|
|
20
|
+
read_webpage: { tool_group: "research", intent_domain: "web_research", operation: "webpage_read", entity_type: "web", mutation_scope: "none" },
|
|
21
|
+
search_images: { tool_group: "research", intent_domain: "web_research", operation: "image_search", entity_type: "image", mutation_scope: "none" },
|
|
22
|
+
view_images: { tool_group: "research", intent_domain: "web_research", operation: "image_view", entity_type: "image", mutation_scope: "none" },
|
|
23
|
+
new: { tool_group: "write", intent_domain: "page_write", operation: "page_scaffold", entity_type: "page", mutation_scope: "local" },
|
|
24
|
+
publish: { tool_group: "write", intent_domain: "page_write", operation: "page_publish", entity_type: "page", mutation_scope: "backend" },
|
|
25
|
+
delete_pages: { tool_group: "write", intent_domain: "page_write", operation: "page_delete", entity_type: "page", mutation_scope: "backend" },
|
|
26
|
+
create_topics: { tool_group: "write", intent_domain: "topic_management", operation: "topic_create", entity_type: "topic", mutation_scope: "backend" },
|
|
27
|
+
update_topic: { tool_group: "write", intent_domain: "topic_management", operation: "topic_update", entity_type: "topic", mutation_scope: "backend" },
|
|
28
|
+
create_wiki: { tool_group: "wiki_admin", intent_domain: "wiki_management", operation: "wiki_create", entity_type: "wiki", mutation_scope: "backend" },
|
|
29
|
+
get_wiki_settings: { tool_group: "wiki_admin", intent_domain: "wiki_management", operation: "wiki_settings_read", entity_type: "wiki", mutation_scope: "none" },
|
|
30
|
+
update_wiki_settings: { tool_group: "wiki_admin", intent_domain: "wiki_management", operation: "wiki_settings_update", entity_type: "wiki", mutation_scope: "backend" },
|
|
31
|
+
join_wiki: { tool_group: "wiki_admin", intent_domain: "wiki_management", operation: "wiki_join", entity_type: "wiki", mutation_scope: "backend" },
|
|
32
|
+
get_wiki_membership: { tool_group: "wiki_admin", intent_domain: "wiki_management", operation: "wiki_membership_read", entity_type: "wiki", mutation_scope: "none" },
|
|
33
|
+
whoami: { tool_group: "account", intent_domain: "auth", operation: "account_read", entity_type: "account", mutation_scope: "none" },
|
|
26
34
|
};
|
|
27
35
|
function metadataForTool(toolName) {
|
|
28
|
-
return TOOL_METADATA[toolName] ?? {
|
|
36
|
+
return TOOL_METADATA[toolName] ?? {
|
|
37
|
+
tool_group: "account",
|
|
38
|
+
intent_domain: "auth",
|
|
39
|
+
operation: "unknown",
|
|
40
|
+
entity_type: "account",
|
|
41
|
+
mutation_scope: "none",
|
|
42
|
+
};
|
|
29
43
|
}
|
|
30
44
|
function errorType(error) {
|
|
31
45
|
if (error instanceof Error && error.name)
|
|
@@ -52,10 +66,11 @@ export function wrapMcpToolDefinition(definition, deps) {
|
|
|
52
66
|
async execute(...args) {
|
|
53
67
|
await validateAuth();
|
|
54
68
|
const startedAt = now();
|
|
69
|
+
const trackingState = { details: {} };
|
|
55
70
|
let success = false;
|
|
56
71
|
let caught;
|
|
57
72
|
try {
|
|
58
|
-
const result = await execute(...args);
|
|
73
|
+
const result = await trackingDetailsStorage.run(trackingState, async () => execute(...args));
|
|
59
74
|
success = true;
|
|
60
75
|
return result;
|
|
61
76
|
}
|
|
@@ -67,6 +82,7 @@ export function wrapMcpToolDefinition(definition, deps) {
|
|
|
67
82
|
const event = {
|
|
68
83
|
tool_name: definition.name,
|
|
69
84
|
...metadata,
|
|
85
|
+
...trackingState.details,
|
|
70
86
|
success,
|
|
71
87
|
duration_ms: Math.max(0, Math.round(now() - startedAt)),
|
|
72
88
|
mcp_version: deps.mcpVersion,
|
|
@@ -3,10 +3,34 @@ import { readFileSync, writeFileSync, mkdirSync, readdirSync, existsSync } from
|
|
|
3
3
|
import { stringify as yamlStringify } from "yaml";
|
|
4
4
|
import { request } from "../../auth.js";
|
|
5
5
|
import { openBrowser } from "../../browser.js";
|
|
6
|
+
import { setMcpTrackingDetails } from "../../tool-tracking.js";
|
|
6
7
|
import { coerceJson } from "../../utils.js";
|
|
7
8
|
import { formatPublishResults } from "./publish-format.js";
|
|
8
9
|
import { resolvePageDir, resolvePagePaths, SLUG_RE } from "./workspace.js";
|
|
9
10
|
import { WRITING_GUIDE } from "./writing-guide.js";
|
|
11
|
+
function summarizePublishTracking(results, requestedCount, wiki_slug, dryRun) {
|
|
12
|
+
const details = {
|
|
13
|
+
wiki_slug,
|
|
14
|
+
dry_run: dryRun,
|
|
15
|
+
mutation_scope: dryRun ? "backend_dry_run" : "backend",
|
|
16
|
+
requested_count: requestedCount,
|
|
17
|
+
result_count: results.length,
|
|
18
|
+
result_error_count: results.filter(result => result.status === "error").length,
|
|
19
|
+
result_stub_created_count: results.reduce((count, result) => count + (result.stubs_created?.length ?? 0), 0),
|
|
20
|
+
};
|
|
21
|
+
if (dryRun) {
|
|
22
|
+
details.planned_created_count = results.filter(result => result.plan?.action === "create").length;
|
|
23
|
+
details.planned_updated_count = results.filter(result => result.plan?.action === "update").length;
|
|
24
|
+
details.planned_renamed_count = results.filter(result => result.plan?.action === "rename").length;
|
|
25
|
+
details.planned_error_count = results.filter(result => result.plan?.action === "error").length;
|
|
26
|
+
return details;
|
|
27
|
+
}
|
|
28
|
+
details.result_created_count = results.filter(result => result.status === "created").length;
|
|
29
|
+
details.result_updated_count = results.filter(result => result.status === "updated").length;
|
|
30
|
+
details.result_renamed_count = results.filter(result => result.status === "renamed").length;
|
|
31
|
+
details.result_unchanged_count = results.filter(result => result.status === "unchanged").length;
|
|
32
|
+
return details;
|
|
33
|
+
}
|
|
10
34
|
export function registerPageTools(server) {
|
|
11
35
|
server.addTool({
|
|
12
36
|
name: "search_pages",
|
|
@@ -198,6 +222,13 @@ export function registerPageTools(server) {
|
|
|
198
222
|
nudges.length > 0 ? nudges.join("\n") : "",
|
|
199
223
|
WRITING_GUIDE,
|
|
200
224
|
];
|
|
225
|
+
setMcpTrackingDetails({
|
|
226
|
+
wiki_slug,
|
|
227
|
+
requested_count: pages.length,
|
|
228
|
+
result_count: created.length + skipped.length,
|
|
229
|
+
result_created_count: created.length,
|
|
230
|
+
result_skipped_count: skipped.length,
|
|
231
|
+
});
|
|
201
232
|
return parts.filter(Boolean).join("\n\n");
|
|
202
233
|
},
|
|
203
234
|
});
|
|
@@ -253,8 +284,11 @@ export function registerPageTools(server) {
|
|
|
253
284
|
});
|
|
254
285
|
const results = (await resp.json());
|
|
255
286
|
const summary = formatPublishResults(results, targetSlugs, wiki_slug, dry_run ?? false);
|
|
287
|
+
const dryRun = dry_run ?? false;
|
|
288
|
+
const details = summarizePublishTracking(results, targetSlugs.length, wiki_slug, dryRun);
|
|
289
|
+
setMcpTrackingDetails(details);
|
|
256
290
|
// Open browser on single-page publish success (non-GUI, non-dry-run).
|
|
257
|
-
if (!
|
|
291
|
+
if (!dryRun && targetSlugs.length === 1 && process.env.OPENALMANAC_GUI !== "1") {
|
|
258
292
|
const r = results[0];
|
|
259
293
|
if (r && r.status !== "error") {
|
|
260
294
|
const resultSlug = r.slug;
|