gnosys 5.7.0 → 5.8.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 +29 -2
- package/dist/cli.js +249 -117
- package/dist/cli.js.map +1 -1
- package/dist/index.js +167 -25
- package/dist/index.js.map +1 -1
- package/dist/lib/ask.d.ts.map +1 -1
- package/dist/lib/ask.js +20 -4
- package/dist/lib/ask.js.map +1 -1
- package/dist/lib/chat/SlashPalette.d.ts +34 -0
- package/dist/lib/chat/SlashPalette.d.ts.map +1 -0
- package/dist/lib/chat/SlashPalette.js +49 -0
- package/dist/lib/chat/SlashPalette.js.map +1 -0
- package/dist/lib/chat/index.d.ts.map +1 -1
- package/dist/lib/chat/index.js +6 -4
- package/dist/lib/chat/index.js.map +1 -1
- package/dist/lib/chat/llmTurn.d.ts.map +1 -1
- package/dist/lib/chat/llmTurn.js +4 -1
- package/dist/lib/chat/llmTurn.js.map +1 -1
- package/dist/lib/chat/render.d.ts.map +1 -1
- package/dist/lib/chat/render.js +91 -10
- package/dist/lib/chat/render.js.map +1 -1
- package/dist/lib/config.d.ts +25 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +30 -0
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/db.d.ts +21 -0
- package/dist/lib/db.d.ts.map +1 -1
- package/dist/lib/db.js +44 -17
- package/dist/lib/db.js.map +1 -1
- package/dist/lib/heartbeat.d.ts +31 -0
- package/dist/lib/heartbeat.d.ts.map +1 -0
- package/dist/lib/heartbeat.js +91 -0
- package/dist/lib/heartbeat.js.map +1 -0
- package/dist/lib/idFormat.d.ts +41 -0
- package/dist/lib/idFormat.d.ts.map +1 -0
- package/dist/lib/idFormat.js +66 -0
- package/dist/lib/idFormat.js.map +1 -0
- package/dist/lib/import.d.ts.map +1 -1
- package/dist/lib/import.js +2 -1
- package/dist/lib/import.js.map +1 -1
- package/dist/lib/ingest.d.ts +7 -1
- package/dist/lib/ingest.d.ts.map +1 -1
- package/dist/lib/ingest.js +23 -4
- package/dist/lib/ingest.js.map +1 -1
- package/dist/lib/llm.d.ts +1 -1
- package/dist/lib/llm.d.ts.map +1 -1
- package/dist/lib/llm.js.map +1 -1
- package/dist/lib/progress.d.ts +54 -0
- package/dist/lib/progress.d.ts.map +1 -0
- package/dist/lib/progress.js +92 -0
- package/dist/lib/progress.js.map +1 -0
- package/dist/lib/remote.d.ts +14 -1
- package/dist/lib/remote.d.ts.map +1 -1
- package/dist/lib/remote.js +75 -28
- package/dist/lib/remote.js.map +1 -1
- package/dist/lib/setup/sections/routing.d.ts.map +1 -1
- package/dist/lib/setup/sections/routing.js +4 -2
- package/dist/lib/setup/sections/routing.js.map +1 -1
- package/dist/lib/setup.d.ts +5 -0
- package/dist/lib/setup.d.ts.map +1 -1
- package/dist/lib/setup.js +127 -0
- package/dist/lib/setup.js.map +1 -1
- package/dist/lib/upgrade.d.ts +38 -0
- package/dist/lib/upgrade.d.ts.map +1 -0
- package/dist/lib/upgrade.js +61 -0
- package/dist/lib/upgrade.js.map +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import dotenv from "dotenv";
|
|
12
12
|
import path from "path";
|
|
13
13
|
import { readFileSync } from "fs";
|
|
14
|
+
import { fileURLToPath } from "url";
|
|
14
15
|
const home = process.env.HOME || process.env.USERPROFILE || "/tmp";
|
|
15
16
|
try {
|
|
16
17
|
const envFile = readFileSync(path.join(home, ".config", "gnosys", ".env"), "utf8");
|
|
@@ -23,6 +24,19 @@ try {
|
|
|
23
24
|
catch {
|
|
24
25
|
// .env file not found — that's fine, env vars may be set elsewhere
|
|
25
26
|
}
|
|
27
|
+
// v5.7.1 (#15): read our running version so the upgrade-marker watcher
|
|
28
|
+
// can detect when a newer global install lands and exit for client respawn.
|
|
29
|
+
const __filenameMcp = fileURLToPath(import.meta.url);
|
|
30
|
+
const __dirnameMcp = path.dirname(__filenameMcp);
|
|
31
|
+
const RUNNING_VERSION = (() => {
|
|
32
|
+
try {
|
|
33
|
+
const raw = readFileSync(path.resolve(__dirnameMcp, "..", "package.json"), "utf8");
|
|
34
|
+
return JSON.parse(raw).version || "0.0.0";
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return "0.0.0";
|
|
38
|
+
}
|
|
39
|
+
})();
|
|
26
40
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
27
41
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
28
42
|
import { z } from "zod";
|
|
@@ -51,7 +65,7 @@ import { GnosysDreamEngine, DreamScheduler, formatDreamReport } from "./lib/drea
|
|
|
51
65
|
import { GnosysExporter, formatExportReport } from "./lib/export.js";
|
|
52
66
|
import { createProjectIdentity, readProjectIdentity } from "./lib/projectIdentity.js";
|
|
53
67
|
import { setPreference, getPreference, getAllPreferences, deletePreference } from "./lib/preferences.js";
|
|
54
|
-
import { syncRules } from "./lib/rulesGen.js";
|
|
68
|
+
import { syncRules, generateRulesBlock } from "./lib/rulesGen.js";
|
|
55
69
|
import { federatedSearch, detectAmbiguity, generateBriefing, generateAllBriefings, getWorkingSet, formatWorkingSet, detectCurrentProject } from "./lib/federated.js";
|
|
56
70
|
import { generatePortfolio, formatPortfolioCompact, formatPortfolioMarkdown, generateStatusPrompt } from "./lib/portfolio.js";
|
|
57
71
|
// Initialize resolver (discovers all layered stores)
|
|
@@ -73,6 +87,38 @@ function formatMcpError(action, err) {
|
|
|
73
87
|
}
|
|
74
88
|
return `Error ${action}: ${err instanceof Error ? err.message : String(err)}`;
|
|
75
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* v5.7.1 (#15): poll `~/.gnosys/last-upgrade-at` and exit when a newer
|
|
92
|
+
* version has been installed. The MCP client (Claude Code, Cursor, etc.)
|
|
93
|
+
* sees the clean exit and respawns the process, which then runs the new
|
|
94
|
+
* global binary.
|
|
95
|
+
*
|
|
96
|
+
* The 10s cadence is a deliberate trade-off: latency is small, the FS
|
|
97
|
+
* check is one stat (~µs), and an upgrade that landed mid-session gets
|
|
98
|
+
* picked up before the next agent turn in almost every case.
|
|
99
|
+
*/
|
|
100
|
+
function startUpgradeMarkerWatcher() {
|
|
101
|
+
const check = async () => {
|
|
102
|
+
try {
|
|
103
|
+
const { shouldRestartMcp, readUpgradeMarker } = await import("./lib/upgrade.js");
|
|
104
|
+
if (shouldRestartMcp(RUNNING_VERSION)) {
|
|
105
|
+
const marker = readUpgradeMarker();
|
|
106
|
+
const newVersion = marker?.version || "newer";
|
|
107
|
+
console.error(`gnosys MCP: upgrading from v${RUNNING_VERSION} → v${newVersion} — restarting`);
|
|
108
|
+
// Clean exit so the MCP host respawns us against the upgraded binary.
|
|
109
|
+
process.exit(0);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
// Stat failed — non-critical. Try again on the next tick.
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
// Immediate boot-time check, then poll.
|
|
117
|
+
void check();
|
|
118
|
+
const timer = setInterval(() => void check(), 10_000);
|
|
119
|
+
// Don't block process exit on this timer.
|
|
120
|
+
timer.unref();
|
|
121
|
+
}
|
|
76
122
|
// These are initialized in main() after resolver runs
|
|
77
123
|
let search = null;
|
|
78
124
|
let tagRegistry = null;
|
|
@@ -150,6 +196,38 @@ async function resolveToolContext(projectRoot) {
|
|
|
150
196
|
projectId,
|
|
151
197
|
};
|
|
152
198
|
}
|
|
199
|
+
/**
|
|
200
|
+
* v5.7.1 (#13): Resolve scope + projectId for a memory write.
|
|
201
|
+
*
|
|
202
|
+
* Previously every write was hard-coded to scope="project" with whatever
|
|
203
|
+
* `ctx.projectId` happened to resolve to — including null. That produced
|
|
204
|
+
* "project-scope, no project" orphans visible cross-project.
|
|
205
|
+
*
|
|
206
|
+
* Now: derive scope from the explicit `store` argument and refuse to
|
|
207
|
+
* create a project-scoped memory when no project identity is reachable,
|
|
208
|
+
* telling the caller exactly how to fix it.
|
|
209
|
+
*/
|
|
210
|
+
function resolveWriteScope(ctx, targetStore) {
|
|
211
|
+
const scope = targetStore || "project";
|
|
212
|
+
if (scope === "global" || scope === "personal") {
|
|
213
|
+
return { ok: true, scope, projectId: null };
|
|
214
|
+
}
|
|
215
|
+
if (!ctx.projectId) {
|
|
216
|
+
return {
|
|
217
|
+
ok: false,
|
|
218
|
+
error: [
|
|
219
|
+
"Cannot write a project-scoped memory: no project identity is reachable.",
|
|
220
|
+
"",
|
|
221
|
+
"Pick one:",
|
|
222
|
+
" • Pass projectRoot=<path-to-project> to anchor this memory to that project",
|
|
223
|
+
" • Pass store='global' to write to shared org knowledge",
|
|
224
|
+
" • Pass store='personal' for cross-project personal notes",
|
|
225
|
+
" • Run gnosys_init in the target directory to register it as a project",
|
|
226
|
+
].join("\n"),
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
return { ok: true, scope: "project", projectId: ctx.projectId };
|
|
230
|
+
}
|
|
153
231
|
// ─── Tool: gnosys_discover ──────────────────────────────────────────────
|
|
154
232
|
server.tool("gnosys_discover", "Discover relevant memories by describing what you're working on. Searches relevance keyword clouds across all stores. Returns lightweight metadata (title, path, relevance keywords) — NO file contents. Use gnosys_read to load specific memories you need. Call this FIRST when starting a task to find what Gnosys knows.", {
|
|
155
233
|
query: z
|
|
@@ -435,14 +513,21 @@ server.tool("gnosys_add", "Add a new memory. Accepts raw text — an LLM structu
|
|
|
435
513
|
};
|
|
436
514
|
}
|
|
437
515
|
try {
|
|
438
|
-
|
|
516
|
+
// v5.8.0 (#8): pass per-call config so the LLM provider resolves against
|
|
517
|
+
// the merged project+global config, not the MCP's boot-time config.
|
|
518
|
+
const result = await ingestion.ingest(input, ctx.config);
|
|
439
519
|
if (!ctx.centralDb?.isAvailable()) {
|
|
440
520
|
return {
|
|
441
521
|
content: [{ type: "text", text: "Database not available. Cannot write memory." }],
|
|
442
522
|
isError: true,
|
|
443
523
|
};
|
|
444
524
|
}
|
|
445
|
-
|
|
525
|
+
// v5.7.1 (#13): determine scope/projectId before writing
|
|
526
|
+
const scopeResult = resolveWriteScope(ctx, targetStore);
|
|
527
|
+
if (!scopeResult.ok) {
|
|
528
|
+
return { content: [{ type: "text", text: scopeResult.error }], isError: true };
|
|
529
|
+
}
|
|
530
|
+
const id = ctx.centralDb.getNextId(result.category, scopeResult.projectId ?? undefined);
|
|
446
531
|
const today = new Date().toISOString().split("T")[0];
|
|
447
532
|
const frontmatter = {
|
|
448
533
|
id,
|
|
@@ -461,7 +546,7 @@ server.tool("gnosys_add", "Add a new memory. Accepts raw text — an LLM structu
|
|
|
461
546
|
};
|
|
462
547
|
const content = `# ${result.title}\n\n${result.content}`;
|
|
463
548
|
// Write to DB only (SQLite is sole source of truth)
|
|
464
|
-
syncMemoryToDb(ctx.centralDb, frontmatter, content, undefined,
|
|
549
|
+
syncMemoryToDb(ctx.centralDb, frontmatter, content, undefined, scopeResult.projectId, scopeResult.scope);
|
|
465
550
|
auditToDb(ctx.centralDb, "write", id, { tool: "gnosys_add", category: result.category });
|
|
466
551
|
// Rebuild search index across all stores
|
|
467
552
|
if (ctx.search) {
|
|
@@ -531,7 +616,12 @@ server.tool("gnosys_add_structured", "Add a memory with structured input (no LLM
|
|
|
531
616
|
isError: true,
|
|
532
617
|
};
|
|
533
618
|
}
|
|
534
|
-
|
|
619
|
+
// v5.7.1 (#13): determine scope/projectId before writing
|
|
620
|
+
const scopeResult = resolveWriteScope(ctx, targetStore);
|
|
621
|
+
if (!scopeResult.ok) {
|
|
622
|
+
return { content: [{ type: "text", text: scopeResult.error }], isError: true };
|
|
623
|
+
}
|
|
624
|
+
const id = ctx.centralDb.getNextId(category, scopeResult.projectId ?? undefined);
|
|
535
625
|
const today = new Date().toISOString().split("T")[0];
|
|
536
626
|
const frontmatter = {
|
|
537
627
|
id,
|
|
@@ -550,7 +640,7 @@ server.tool("gnosys_add_structured", "Add a memory with structured input (no LLM
|
|
|
550
640
|
};
|
|
551
641
|
const fullContent = `# ${title}\n\n${content}`;
|
|
552
642
|
// Write to DB only (SQLite is sole source of truth)
|
|
553
|
-
syncMemoryToDb(ctx.centralDb, frontmatter, fullContent, undefined,
|
|
643
|
+
syncMemoryToDb(ctx.centralDb, frontmatter, fullContent, undefined, scopeResult.projectId, scopeResult.scope);
|
|
554
644
|
auditToDb(ctx.centralDb, "write", id, { tool: "gnosys_add_structured", category });
|
|
555
645
|
if (ctx.search)
|
|
556
646
|
await reindexAllStores();
|
|
@@ -961,15 +1051,15 @@ server.tool("gnosys_commit_context", "Pre-compaction memory sweep. Call this bef
|
|
|
961
1051
|
projectRoot: projectRootParam,
|
|
962
1052
|
}, async ({ context, dry_run, projectRoot }) => {
|
|
963
1053
|
const ctx = await resolveToolContext(projectRoot);
|
|
964
|
-
//
|
|
965
|
-
|
|
1054
|
+
// v5.8.0 (#8): no early-gate on the module-level `ingestion` here.
|
|
1055
|
+
// It's bound to the MCP's boot-time config — which may not have an LLM
|
|
1056
|
+
// block on the directory we launched in. The real LLM resolution
|
|
1057
|
+
// happens against `ctx.config` (merged project+global) below; if that
|
|
1058
|
+
// can't find a provider, getLLMProvider() surfaces a provider-specific
|
|
1059
|
+
// error message.
|
|
1060
|
+
if (!ingestion) {
|
|
966
1061
|
return {
|
|
967
|
-
content: [
|
|
968
|
-
{
|
|
969
|
-
type: "text",
|
|
970
|
-
text: "Commit context requires an LLM. Configure a provider in gnosys.json or set ANTHROPIC_API_KEY.",
|
|
971
|
-
},
|
|
972
|
-
],
|
|
1062
|
+
content: [{ type: "text", text: "Ingestion module not initialized." }],
|
|
973
1063
|
isError: true,
|
|
974
1064
|
};
|
|
975
1065
|
}
|
|
@@ -1059,7 +1149,7 @@ Output ONLY the JSON array, no markdown fences.`,
|
|
|
1059
1149
|
results.push(`❌ FAILED: "${candidate.summary}": Database not available`);
|
|
1060
1150
|
continue;
|
|
1061
1151
|
}
|
|
1062
|
-
const result = await ingestion.ingest(candidate.summary);
|
|
1152
|
+
const result = await ingestion.ingest(candidate.summary, ctx.config);
|
|
1063
1153
|
const id = ctx.centralDb.getNextId(result.category, ctx.projectId ?? undefined);
|
|
1064
1154
|
const today = new Date().toISOString().split("T")[0];
|
|
1065
1155
|
const frontmatter = {
|
|
@@ -2050,7 +2140,11 @@ server.tool("gnosys_preference_set", "Set a user preference. Preferences are sto
|
|
|
2050
2140
|
return {
|
|
2051
2141
|
content: [{
|
|
2052
2142
|
type: "text",
|
|
2053
|
-
|
|
2143
|
+
// v5.8.0 (#9): no longer suggest running gnosys_sync. The
|
|
2144
|
+
// SessionStart hook (gnosys recall) already injects preferences
|
|
2145
|
+
// into the next session's context — no need to rewrite tracked
|
|
2146
|
+
// files like CLAUDE.md.
|
|
2147
|
+
text: `Preference set: **${pref.title}**\n Key: ${pref.key}\n Value: ${pref.value}`,
|
|
2054
2148
|
}],
|
|
2055
2149
|
};
|
|
2056
2150
|
}
|
|
@@ -2123,14 +2217,31 @@ server.tool("gnosys_preference_delete", "Delete a user preference by key.", {
|
|
|
2123
2217
|
return {
|
|
2124
2218
|
content: [{
|
|
2125
2219
|
type: "text",
|
|
2126
|
-
|
|
2220
|
+
// v5.8.0 (#9): drop the gnosys_sync suggestion — SessionStart
|
|
2221
|
+
// hook picks up the change next time without rewriting tracked files.
|
|
2222
|
+
text: `Preference "${key}" deleted.`,
|
|
2127
2223
|
}],
|
|
2128
2224
|
};
|
|
2129
2225
|
});
|
|
2130
2226
|
// ─── Tool: gnosys_sync ──────────────────────────────────────────────────
|
|
2131
|
-
|
|
2227
|
+
//
|
|
2228
|
+
// v5.8.0 (#9): inert-by-default. Previously this tool always wrote a
|
|
2229
|
+
// GNOSYS:START/GNOSYS:END block into the project's CLAUDE.md (a tracked
|
|
2230
|
+
// file in most repos), producing phantom git diffs every time an agent
|
|
2231
|
+
// helpfully called it after a preference change. Now the default is
|
|
2232
|
+
// "return the rules block as text" — the agent can use that as in-context
|
|
2233
|
+
// guidance without touching disk. To actually rewrite the rules file
|
|
2234
|
+
// (the v5.7.0 behaviour), pass `commit_to_disk: true` explicitly.
|
|
2235
|
+
//
|
|
2236
|
+
// Routine in-session context flows through the SessionStart hook
|
|
2237
|
+
// (`gnosys recall`), not through this tool.
|
|
2238
|
+
server.tool("gnosys_sync", "Get the current user preferences + project conventions formatted as a GNOSYS:START/GNOSYS:END block. By default returns the block as text only (no disk write). Pass commit_to_disk=true to write it into the detected agent rules file (CLAUDE.md, .cursor/rules/gnosys.mdc) — only do this if the user has explicitly asked to refresh the rules file. Routine session context is already injected via the SessionStart hook (`gnosys recall`); do NOT call this tool after every preference change.", {
|
|
2132
2239
|
projectRoot: projectRootParam,
|
|
2133
|
-
|
|
2240
|
+
commit_to_disk: z
|
|
2241
|
+
.boolean()
|
|
2242
|
+
.optional()
|
|
2243
|
+
.describe("If true, write the block into the detected agent rules file on disk. Default: false (text only). Note: rules files like CLAUDE.md and .cursor/rules/*.mdc are typically tracked in git, so writing creates a diff."),
|
|
2244
|
+
}, async ({ projectRoot, commit_to_disk }) => {
|
|
2134
2245
|
if (!centralDb?.isAvailable()) {
|
|
2135
2246
|
return {
|
|
2136
2247
|
content: [{ type: "text", text: "Central DB not available. Cannot sync rules." }],
|
|
@@ -2155,12 +2266,36 @@ server.tool("gnosys_sync", "Regenerate agent rules file from current user prefer
|
|
|
2155
2266
|
isError: true,
|
|
2156
2267
|
};
|
|
2157
2268
|
}
|
|
2269
|
+
const preferences = getAllPreferences(centralDb);
|
|
2270
|
+
let projectConventions = [];
|
|
2271
|
+
if (identity.projectId) {
|
|
2272
|
+
const projectMems = centralDb.getMemoriesByProject(identity.projectId);
|
|
2273
|
+
projectConventions = projectMems.filter((m) => (m.category === "decisions" || m.category === "conventions") && m.status === "active");
|
|
2274
|
+
}
|
|
2275
|
+
const block = generateRulesBlock(preferences, projectConventions);
|
|
2276
|
+
// Default path: return the block as text, no disk write.
|
|
2277
|
+
if (!commit_to_disk) {
|
|
2278
|
+
return {
|
|
2279
|
+
content: [
|
|
2280
|
+
{
|
|
2281
|
+
type: "text",
|
|
2282
|
+
text: `Rules block (preview, not written to disk):\n\n${block}\n\n` +
|
|
2283
|
+
`Summary: ${preferences.length} preference(s), ${projectConventions.length} project convention(s).\n` +
|
|
2284
|
+
`To write this into ${identity.agentRulesTarget || "the agent rules file"}, call gnosys_sync again with commit_to_disk=true.\n` +
|
|
2285
|
+
`(SessionStart hook 'gnosys recall' already provides routine session context — usually no disk write is needed.)`,
|
|
2286
|
+
},
|
|
2287
|
+
],
|
|
2288
|
+
};
|
|
2289
|
+
}
|
|
2290
|
+
// Opt-in disk write path.
|
|
2158
2291
|
if (!identity.agentRulesTarget) {
|
|
2159
2292
|
return {
|
|
2160
|
-
content: [
|
|
2293
|
+
content: [
|
|
2294
|
+
{
|
|
2161
2295
|
type: "text",
|
|
2162
|
-
text: "
|
|
2163
|
-
}
|
|
2296
|
+
text: "commit_to_disk=true requested, but no agent rules target detected (no .cursor/ or CLAUDE.md found). Create one first, then re-run gnosys_init to detect it.",
|
|
2297
|
+
},
|
|
2298
|
+
],
|
|
2164
2299
|
};
|
|
2165
2300
|
}
|
|
2166
2301
|
const result = await syncRules(centralDb, projectDir, identity.agentRulesTarget, identity.projectId);
|
|
@@ -2172,10 +2307,13 @@ server.tool("gnosys_sync", "Regenerate agent rules file from current user prefer
|
|
|
2172
2307
|
}
|
|
2173
2308
|
const action = result.created ? "Created" : "Updated";
|
|
2174
2309
|
return {
|
|
2175
|
-
content: [
|
|
2310
|
+
content: [
|
|
2311
|
+
{
|
|
2176
2312
|
type: "text",
|
|
2177
|
-
text: `${action} rules file: ${result.filePath}\n\n Preferences injected: ${result.prefCount}\n Project conventions: ${result.conventionCount}\n\
|
|
2178
|
-
|
|
2313
|
+
text: `${action} rules file: ${result.filePath}\n\n Preferences injected: ${result.prefCount}\n Project conventions: ${result.conventionCount}\n\n` +
|
|
2314
|
+
`⚠ This wrote to a file that may be tracked in git — expect a diff. Routine session context flows through the SessionStart hook; only call gnosys_sync with commit_to_disk=true when the user explicitly asks to refresh the rules file.`,
|
|
2315
|
+
},
|
|
2316
|
+
],
|
|
2179
2317
|
};
|
|
2180
2318
|
});
|
|
2181
2319
|
// ─── Tool: gnosys_federated_search ───────────────────────────────────────
|
|
@@ -2644,6 +2782,10 @@ This marks the conversation checkpoint so the next /gnosys-memorize only process
|
|
|
2644
2782
|
});
|
|
2645
2783
|
// ─── Start the server ────────────────────────────────────────────────────
|
|
2646
2784
|
async function main() {
|
|
2785
|
+
// v5.7.1 (#15): start the upgrade-marker watcher BEFORE anything else.
|
|
2786
|
+
// If `gnosys upgrade` was run on this machine while the MCP was idle,
|
|
2787
|
+
// pick that up immediately instead of serving stale tool handlers.
|
|
2788
|
+
startUpgradeMarkerWatcher();
|
|
2647
2789
|
// v3.0: Initialize central DB at ~/.gnosys/gnosys.db
|
|
2648
2790
|
try {
|
|
2649
2791
|
centralDb = GnosysDB.openCentral();
|