@pcircle/memesh 4.8.3 → 4.9.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +2 -1
- package/.codex-plugin/mcp.json +6 -4
- package/.codex-plugin/plugin.json +1 -1
- package/AGENTS.md +68 -17
- package/README.de.md +83 -555
- package/README.md +83 -581
- package/README.zh-TW.md +84 -572
- package/dashboard/dist/index.html +10 -10
- package/dist/cli/view-live.d.ts.map +1 -1
- package/dist/cli/view-live.js +154 -384
- package/dist/cli/view-live.js.map +1 -1
- package/dist/core/agent-message-inbox.d.ts +2 -1
- package/dist/core/agent-message-inbox.d.ts.map +1 -1
- package/dist/core/agent-message-inbox.js +23 -4
- package/dist/core/agent-message-inbox.js.map +1 -1
- package/dist/core/agent-messaging.d.ts.map +1 -1
- package/dist/core/agent-messaging.js +23 -15
- package/dist/core/agent-messaging.js.map +1 -1
- package/dist/core/agent-router.d.ts +11 -10
- package/dist/core/agent-router.d.ts.map +1 -1
- package/dist/core/agent-router.js +29 -14
- package/dist/core/agent-router.js.map +1 -1
- package/dist/core/agent-scope-id.d.ts +11 -0
- package/dist/core/agent-scope-id.d.ts.map +1 -0
- package/dist/core/agent-scope-id.js +40 -0
- package/dist/core/agent-scope-id.js.map +1 -0
- package/dist/core/analytics.d.ts.map +1 -1
- package/dist/core/analytics.js.map +1 -1
- package/dist/core/briefing.d.ts.map +1 -1
- package/dist/core/briefing.js +8 -2
- package/dist/core/briefing.js.map +1 -1
- package/dist/core/config.d.ts +4 -40
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +75 -141
- package/dist/core/config.js.map +1 -1
- package/dist/core/demo.d.ts.map +1 -1
- package/dist/core/demo.js +6 -6
- package/dist/core/demo.js.map +1 -1
- package/dist/core/doctor.d.ts +2 -6
- package/dist/core/doctor.d.ts.map +1 -1
- package/dist/core/doctor.js +120 -154
- package/dist/core/doctor.js.map +1 -1
- package/dist/core/dreamer.d.ts +32 -47
- package/dist/core/dreamer.d.ts.map +1 -1
- package/dist/core/dreamer.js +214 -704
- package/dist/core/dreamer.js.map +1 -1
- package/dist/core/install-channel.d.ts.map +1 -1
- package/dist/core/install-channel.js +4 -47
- package/dist/core/install-channel.js.map +1 -1
- package/dist/core/install-id.d.ts.map +1 -1
- package/dist/core/install-id.js.map +1 -1
- package/dist/core/kg-backfill.d.ts.map +1 -1
- package/dist/core/kg-backfill.js.map +1 -1
- package/dist/core/lesson-engine.d.ts +0 -5
- package/dist/core/lesson-engine.d.ts.map +1 -1
- package/dist/core/lesson-engine.js +0 -25
- package/dist/core/lesson-engine.js.map +1 -1
- package/dist/core/lifecycle.d.ts.map +1 -1
- package/dist/core/lifecycle.js +58 -49
- package/dist/core/lifecycle.js.map +1 -1
- package/dist/core/memory-tool.d.ts.map +1 -1
- package/dist/core/memory-tool.js +20 -18
- package/dist/core/memory-tool.js.map +1 -1
- package/dist/core/operations.d.ts +3 -27
- package/dist/core/operations.d.ts.map +1 -1
- package/dist/core/operations.js +10 -245
- package/dist/core/operations.js.map +1 -1
- package/dist/core/paths.d.ts +4 -1
- package/dist/core/paths.d.ts.map +1 -1
- package/dist/core/paths.js +88 -14
- package/dist/core/paths.js.map +1 -1
- package/dist/core/product-improvements.js +2 -2
- package/dist/core/product-improvements.js.map +1 -1
- package/dist/core/project-tags.d.ts +2 -0
- package/dist/core/project-tags.d.ts.map +1 -1
- package/dist/core/project-tags.js +29 -1
- package/dist/core/project-tags.js.map +1 -1
- package/dist/core/schema-export.d.ts.map +1 -1
- package/dist/core/schema-export.js +13 -3
- package/dist/core/schema-export.js.map +1 -1
- package/dist/core/semver.d.ts +7 -0
- package/dist/core/semver.d.ts.map +1 -0
- package/dist/core/semver.js +49 -0
- package/dist/core/semver.js.map +1 -0
- package/dist/core/serializer.d.ts.map +1 -1
- package/dist/core/serializer.js +69 -57
- package/dist/core/serializer.js.map +1 -1
- package/dist/core/signal-scorer.d.ts.map +1 -1
- package/dist/core/signal-scorer.js.map +1 -1
- package/dist/core/transcript-extractor.d.ts +1 -85
- package/dist/core/transcript-extractor.d.ts.map +1 -1
- package/dist/core/transcript-extractor.js +5 -364
- package/dist/core/transcript-extractor.js.map +1 -1
- package/dist/core/transcript-source.d.ts +22 -6
- package/dist/core/transcript-source.d.ts.map +1 -1
- package/dist/core/transcript-source.js +108 -69
- package/dist/core/transcript-source.js.map +1 -1
- package/dist/core/types.d.ts +1 -17
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/version-check.d.ts +1 -0
- package/dist/core/version-check.d.ts.map +1 -1
- package/dist/core/version-check.js +46 -1
- package/dist/core/version-check.js.map +1 -1
- package/dist/db.d.ts +0 -34
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +6 -287
- package/dist/db.js.map +1 -1
- package/dist/host-runtime/acp.d.ts.map +1 -1
- package/dist/host-runtime/acp.js +4 -3
- package/dist/host-runtime/acp.js.map +1 -1
- package/dist/host-runtime/claude.d.ts.map +1 -1
- package/dist/host-runtime/claude.js +11 -11
- package/dist/host-runtime/claude.js.map +1 -1
- package/dist/host-runtime/codex-session.d.ts +9 -1
- package/dist/host-runtime/codex-session.d.ts.map +1 -1
- package/dist/host-runtime/codex-session.js +474 -29
- package/dist/host-runtime/codex-session.js.map +1 -1
- package/dist/host-runtime/codex.d.ts.map +1 -1
- package/dist/host-runtime/codex.js +4 -3
- package/dist/host-runtime/codex.js.map +1 -1
- package/dist/host-runtime/config.d.ts +1 -0
- package/dist/host-runtime/config.d.ts.map +1 -1
- package/dist/host-runtime/config.js +4 -0
- package/dist/host-runtime/config.js.map +1 -1
- package/dist/host-runtime/entry.d.ts +5 -0
- package/dist/host-runtime/entry.d.ts.map +1 -0
- package/dist/host-runtime/entry.js +11 -0
- package/dist/host-runtime/entry.js.map +1 -0
- package/dist/host-runtime/router-client.d.ts.map +1 -1
- package/dist/host-runtime/router-client.js +62 -15
- package/dist/host-runtime/router-client.js.map +1 -1
- package/dist/host-runtime/router.js +2 -2
- package/dist/host-runtime/router.js.map +1 -1
- package/dist/knowledge-graph.d.ts +0 -1
- package/dist/knowledge-graph.d.ts.map +1 -1
- package/dist/knowledge-graph.js +77 -60
- package/dist/knowledge-graph.js.map +1 -1
- package/dist/mcp/THIRD_PARTY_NOTICES.txt +217 -0
- package/dist/mcp/server.js +30685 -38
- package/dist/mcp/server.js.map +6 -1
- package/dist/skills-manifest.json +39 -34
- package/dist/storage/entity-index.d.ts +3 -0
- package/dist/storage/entity-index.d.ts.map +1 -0
- package/dist/storage/entity-index.js +8 -0
- package/dist/storage/entity-index.js.map +1 -0
- package/dist/storage/fts-index.d.ts.map +1 -1
- package/dist/storage/fts-index.js +11 -7
- package/dist/storage/fts-index.js.map +1 -1
- package/dist/storage/graph-repairs.d.ts +7 -2
- package/dist/storage/graph-repairs.d.ts.map +1 -1
- package/dist/storage/graph-repairs.js +89 -13
- package/dist/storage/graph-repairs.js.map +1 -1
- package/dist/storage/schema.d.ts +1 -1
- package/dist/storage/schema.d.ts.map +1 -1
- package/dist/storage/schema.js +1 -2
- package/dist/storage/schema.js.map +1 -1
- package/dist/storage/sqlite.d.ts +0 -1
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/transports/agent-messaging.d.ts.map +1 -1
- package/dist/transports/agent-messaging.js +5 -7
- package/dist/transports/agent-messaging.js.map +1 -1
- package/dist/transports/cli/cli.d.ts.map +1 -1
- package/dist/transports/cli/cli.js +75 -686
- package/dist/transports/cli/cli.js.map +1 -1
- package/dist/transports/http/retired-routes.js +1 -1
- package/dist/transports/http/retired-routes.js.map +1 -1
- package/dist/transports/http/server.d.ts.map +1 -1
- package/dist/transports/http/server.js +13 -232
- package/dist/transports/http/server.js.map +1 -1
- package/dist/transports/mcp/handlers.d.ts +130 -4
- package/dist/transports/mcp/handlers.d.ts.map +1 -1
- package/dist/transports/mcp/handlers.js +56 -7
- package/dist/transports/mcp/handlers.js.map +1 -1
- package/dist/transports/schemas.d.ts +71 -19
- package/dist/transports/schemas.d.ts.map +1 -1
- package/dist/transports/schemas.js +57 -11
- package/dist/transports/schemas.js.map +1 -1
- package/docs/platforms/README.md +6 -5
- package/docs/platforms/agent-messaging.md +241 -20
- package/hooks/hooks.json +23 -2
- package/llms-install.md +62 -30
- package/package.json +12 -9
- package/scripts/hooks/_generated/agent-message-inbox.js +23 -4
- package/scripts/hooks/_generated/core-paths.js +88 -14
- package/scripts/hooks/_generated/fts-index.js +11 -7
- package/scripts/hooks/_generated/schema.js +1 -2
- package/scripts/hooks/_shared.js +65 -23
- package/scripts/hooks/decision-nudge.js +152 -0
- package/scripts/hooks/post-commit.js +11 -0
- package/scripts/hooks/pre-compact.js +12 -4
- package/scripts/hooks/session-start.js +32 -9
- package/scripts/hooks/session-summary.js +19 -374
- package/scripts/upgrade-plugin.sh +71 -2
- package/skills/memesh/SKILL.md +24 -15
- package/skills/memesh-review/SKILL.md +7 -6
- package/dist/core/auto-tagger.d.ts +0 -10
- package/dist/core/auto-tagger.d.ts.map +0 -1
- package/dist/core/auto-tagger.js +0 -63
- package/dist/core/auto-tagger.js.map +0 -1
- package/dist/core/conflict-candidates.d.ts +0 -20
- package/dist/core/conflict-candidates.d.ts.map +0 -1
- package/dist/core/conflict-candidates.js +0 -71
- package/dist/core/conflict-candidates.js.map +0 -1
- package/dist/core/conflict-judge.d.ts +0 -58
- package/dist/core/conflict-judge.d.ts.map +0 -1
- package/dist/core/conflict-judge.js +0 -189
- package/dist/core/conflict-judge.js.map +0 -1
- package/dist/core/digest-validator.d.ts +0 -18
- package/dist/core/digest-validator.d.ts.map +0 -1
- package/dist/core/digest-validator.js +0 -85
- package/dist/core/digest-validator.js.map +0 -1
- package/dist/core/embedder.d.ts +0 -20
- package/dist/core/embedder.d.ts.map +0 -1
- package/dist/core/embedder.js +0 -242
- package/dist/core/embedder.js.map +0 -1
- package/dist/core/failure-analyzer.d.ts +0 -19
- package/dist/core/failure-analyzer.d.ts.map +0 -1
- package/dist/core/failure-analyzer.js +0 -83
- package/dist/core/failure-analyzer.js.map +0 -1
- package/dist/core/json-utils.d.ts +0 -3
- package/dist/core/json-utils.d.ts.map +0 -1
- package/dist/core/json-utils.js +0 -46
- package/dist/core/json-utils.js.map +0 -1
- package/dist/core/llm-client.d.ts +0 -22
- package/dist/core/llm-client.d.ts.map +0 -1
- package/dist/core/llm-client.js +0 -203
- package/dist/core/llm-client.js.map +0 -1
- package/dist/core/llm-telemetry.d.ts +0 -47
- package/dist/core/llm-telemetry.d.ts.map +0 -1
- package/dist/core/llm-telemetry.js +0 -117
- package/dist/core/llm-telemetry.js.map +0 -1
- package/dist/core/llm-validator.d.ts +0 -20
- package/dist/core/llm-validator.d.ts.map +0 -1
- package/dist/core/llm-validator.js +0 -231
- package/dist/core/llm-validator.js.map +0 -1
- package/dist/core/ollama-host.d.ts +0 -6
- package/dist/core/ollama-host.d.ts.map +0 -1
- package/dist/core/ollama-host.js +0 -30
- package/dist/core/ollama-host.js.map +0 -1
- package/dist/core/output-language.d.ts +0 -6
- package/dist/core/output-language.d.ts.map +0 -1
- package/dist/core/output-language.js +0 -25
- package/dist/core/output-language.js.map +0 -1
- package/dist/core/prompt-safety.d.ts +0 -4
- package/dist/core/prompt-safety.d.ts.map +0 -1
- package/dist/core/prompt-safety.js +0 -20
- package/dist/core/prompt-safety.js.map +0 -1
- package/dist/storage/vector-index.d.ts +0 -3
- package/dist/storage/vector-index.d.ts.map +0 -1
- package/dist/storage/vector-index.js +0 -13
- package/dist/storage/vector-index.js.map +0 -1
- /package/{.mcp.json → .claude-plugin/mcp.json} +0 -0
package/dist/core/doctor.js
CHANGED
|
@@ -4,22 +4,16 @@ import path from 'path';
|
|
|
4
4
|
import net from 'node:net';
|
|
5
5
|
import { createHash } from 'crypto';
|
|
6
6
|
import { createRequire } from 'module';
|
|
7
|
-
import { pathToFileURL } from 'url';
|
|
8
7
|
import { execFileSync } from 'child_process';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { probeProvider } from './llm-validator.js';
|
|
12
|
-
import { openDatabase, closeDatabase, getPendingReindexInfo, isDatabaseOpen, readVectorGeneration, generationRowIds, } from '../db.js';
|
|
8
|
+
import { findRetiredConfigKeys, getConfigPath, readConfig } from './config.js';
|
|
9
|
+
import { openDatabase, closeDatabase, isDatabaseOpen, } from '../db.js';
|
|
13
10
|
import { getUpdateCheck } from './version-check.js';
|
|
14
11
|
import { classifyBump } from './updater.js';
|
|
15
12
|
import { getCurrentInstallChannel, getInstallChannelSupport, detectPluginHost, pluginHostConfigRoot, versionedPluginCacheRoots, PLUGIN_REFRESH_COMMANDS, } from './install-channel.js';
|
|
16
13
|
import { getInstallRecord } from './install-id.js';
|
|
17
14
|
import { citationRulePath, citationRuleState } from './citation-rule.js';
|
|
18
|
-
import { getDbPath, getMemeshDirFromDbPath, homeDir, memeshDir
|
|
15
|
+
import { getAgentRouterSocketPath, getDbPath, getMemeshDirFromDbPath, homeDir, memeshDir } from './paths.js';
|
|
19
16
|
import { detectPluginRuntime, readInstallMarker } from './install-hooks.js';
|
|
20
|
-
import { lastTranscriptMineAt } from './transcript-source.js';
|
|
21
|
-
import { countMissingVectors } from './operations.js';
|
|
22
|
-
import { hasVectorIndex } from '../storage/vector-index.js';
|
|
23
17
|
import { UNSPACED_SCRIPT_GLOB_RUN3 } from '../storage/fts-index.js';
|
|
24
18
|
import { MemeshDatabase } from '../storage/sqlite.js';
|
|
25
19
|
import { AUTO_CAPTURE_TAG } from './types.js';
|
|
@@ -28,7 +22,6 @@ import { autoCaptureDecision } from './capture-flag.js';
|
|
|
28
22
|
import { guardFromMetadata } from './guards.js';
|
|
29
23
|
import { getAgentMessageStorageReport } from './agent-message-storage.js';
|
|
30
24
|
import { readHostConfigFile } from '../host-runtime/config.js';
|
|
31
|
-
const EMBEDDING_PROBE_TIMEOUT_MS = 15000;
|
|
32
25
|
const EXPECTED_HOOK_TYPES = ['PreToolUse', 'SessionStart', 'PostToolUse', 'Stop', 'PreCompact'];
|
|
33
26
|
const AGENT_MESSAGE_STORAGE_QUOTA_ENV = 'MEMESH_AGENT_MESSAGE_STORAGE_QUOTA_BYTES';
|
|
34
27
|
const LOCALE_README_FILES = [
|
|
@@ -153,9 +146,9 @@ function inspectCodexSessionSetup(codexPluginCacheDetected, existsSyncImpl) {
|
|
|
153
146
|
return null;
|
|
154
147
|
const configPath = path.join(getMemeshDirFromDbPath(), 'hosts', 'codex-session.json');
|
|
155
148
|
if (existsSyncImpl(configPath)) {
|
|
156
|
-
return
|
|
149
|
+
return createInfo('codex-session-setup', 'Codex ordinary-session notifications', 'A Codex identity override file is present and will be validated at SessionStart. A valid override applies only in its configured workspace; other Codex plugin sessions use automatic thread-scoped identities. A cached plugin copy does not prove a live registration; use `memesh message discover --project <project>` to read current presence.');
|
|
157
150
|
}
|
|
158
|
-
return
|
|
151
|
+
return createInfo('codex-session-setup', 'Codex ordinary-session notifications', 'No explicit identity override is configured. When the Codex plugin is enabled, each startup or resumed thread registers automatically under a thread-scoped identity. A cached plugin copy does not prove a live registration; use `memesh message discover --project <project>` to read current presence.');
|
|
159
152
|
}
|
|
160
153
|
function configuredAgentMessageStoragePolicy(explicit) {
|
|
161
154
|
if (explicit !== undefined)
|
|
@@ -194,14 +187,10 @@ function parseJsonFile(filePath, readFileSyncImpl) {
|
|
|
194
187
|
};
|
|
195
188
|
}
|
|
196
189
|
}
|
|
197
|
-
function inspectConfigFile(existsSyncImpl, readFileSyncImpl, getConfigPathImpl
|
|
190
|
+
function inspectConfigFile(existsSyncImpl, readFileSyncImpl, getConfigPathImpl) {
|
|
198
191
|
const configPath = getConfigPathImpl();
|
|
199
192
|
if (!existsSyncImpl(configPath)) {
|
|
200
|
-
return createCheck('config', 'Config', 'pass',
|
|
201
|
-
? `No config file yet (${configPath}), but your environment names ${envLlm.provider}${envLlm.apiKey ? ' (via its API key)' : ' (via OLLAMA_HOST)'}, which enables Smart Mode. A file is only needed to pin a provider or change defaults.`
|
|
202
|
-
: `No config file yet (${configPath}). MeMesh will run in Core mode until you configure Smart Mode.`, envLlm
|
|
203
|
-
? `Optional: \`memesh config set llm.provider ${envLlm.provider}\` pins it so it does not depend on which shell you run from.`
|
|
204
|
-
: 'Optional: run `memesh config list` or set an LLM with `memesh config set llm.provider anthropic`.');
|
|
193
|
+
return createCheck('config', 'Config', 'pass', `No config file yet (${configPath}); default settings are in effect.`, 'Optional: run memesh config list to inspect settings.');
|
|
205
194
|
}
|
|
206
195
|
try {
|
|
207
196
|
const raw = readFileSyncImpl(configPath, 'utf8');
|
|
@@ -209,35 +198,66 @@ function inspectConfigFile(existsSyncImpl, readFileSyncImpl, getConfigPathImpl,
|
|
|
209
198
|
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
210
199
|
return createCheck('config', 'Config', 'fail', `${configPath} parsed but is not a JSON object — every setting is being ignored.`, `Fix or remove ${configPath}, then re-run memesh doctor.`, { code: 'config-parse.not-object', params: { path: configPath } });
|
|
211
200
|
}
|
|
201
|
+
const retiredKeys = findRetiredConfigKeys(parsed);
|
|
202
|
+
if (retiredKeys.length > 0) {
|
|
203
|
+
const keys = retiredKeys.join(', ');
|
|
204
|
+
return createCheck('config', 'Config', 'warn', `${configPath} is valid JSON but still contains ${retiredKeys.length} retired top-level setting(s) (${keys}). ` +
|
|
205
|
+
'This version ignores them, but legacy provider credentials or settings may remain on disk.', `Review ${configPath} locally and remove only those retired top-level keys. ` +
|
|
206
|
+
'Do not paste the file into an issue because it may contain credentials. Then run memesh doctor again.', {
|
|
207
|
+
code: 'config-parse.retired-settings',
|
|
208
|
+
params: { path: configPath, count: retiredKeys.length, keys },
|
|
209
|
+
});
|
|
210
|
+
}
|
|
212
211
|
return createCheck('config', 'Config', 'pass', `${configPath} is valid JSON and its settings are in effect.`);
|
|
213
212
|
}
|
|
214
213
|
catch (err) {
|
|
215
214
|
const msg = err instanceof Error ? err.message : String(err);
|
|
216
|
-
return createCheck('config', 'Config', 'fail', `${configPath} could not be read or parsed (${msg}).
|
|
215
|
+
return createCheck('config', 'Config', 'fail', `${configPath} could not be read or parsed (${msg}). Its settings are being ignored right now.`, `Fix the JSON or remove the file to fall back to defaults: mv ${configPath} ${configPath}.bak`, { code: 'config-parse.unreadable', params: { path: configPath, detail: msg } });
|
|
217
216
|
}
|
|
218
217
|
}
|
|
219
|
-
|
|
220
|
-
|
|
218
|
+
const MCP_PLACEHOLDER = '${CLAUDE_PLUGIN_ROOT}';
|
|
219
|
+
function declaredMcpManifest(packageRoot, readFileSyncImpl) {
|
|
220
|
+
const parsed = parseJsonFile(path.join(packageRoot, '.claude-plugin', 'plugin.json'), readFileSyncImpl);
|
|
221
|
+
if (!parsed.ok)
|
|
222
|
+
return null;
|
|
223
|
+
const declared = parsed.value.mcpServers;
|
|
224
|
+
if (typeof declared !== 'string' || !declared.startsWith('./'))
|
|
225
|
+
return null;
|
|
226
|
+
return declared.slice(2);
|
|
227
|
+
}
|
|
228
|
+
function inspectMcpConfig(packageRoot, installChannel, existsSyncImpl, readFileSyncImpl, env) {
|
|
229
|
+
const relativeManifest = declaredMcpManifest(packageRoot, readFileSyncImpl);
|
|
230
|
+
if (relativeManifest === null) {
|
|
231
|
+
return createCheck('mcp-config', 'MCP config', 'fail', '.claude-plugin/plugin.json declares no `mcpServers` path, so Claude Code has no MeMesh MCP server to start.', 'Reinstall MeMesh so the plugin manifest and the MCP manifest it names are both restored.', { code: 'mcp-config.missing' });
|
|
232
|
+
}
|
|
233
|
+
const label = relativeManifest;
|
|
234
|
+
const mcpPath = path.join(packageRoot, relativeManifest);
|
|
221
235
|
if (!existsSyncImpl(mcpPath)) {
|
|
222
|
-
return createCheck('mcp-config', 'MCP config', 'fail',
|
|
236
|
+
return createCheck('mcp-config', 'MCP config', 'fail', `${label} is missing.`, 'Reinstall MeMesh so the plugin manifest and the MCP manifest it names are both restored.', { code: 'mcp-config.missing' });
|
|
223
237
|
}
|
|
224
238
|
const parsed = parseJsonFile(mcpPath, readFileSyncImpl);
|
|
225
239
|
if (!parsed.ok) {
|
|
226
|
-
return createCheck('mcp-config', 'MCP config', 'fail',
|
|
240
|
+
return createCheck('mcp-config', 'MCP config', 'fail', `${label} is not valid JSON.`, `Fix ${mcpPath} so Claude Code can read the MCP server definition.`, { code: 'mcp-config.invalid-json', params: { path: mcpPath } });
|
|
227
241
|
}
|
|
228
242
|
const server = parsed.value.mcpServers?.memesh;
|
|
229
243
|
if (!server || typeof server.command !== 'string') {
|
|
230
|
-
return createCheck('mcp-config', 'MCP config', 'fail',
|
|
244
|
+
return createCheck('mcp-config', 'MCP config', 'fail', `${label} does not define a usable \`memesh\` MCP server entry.`, `Reinstall MeMesh or restore the \`mcpServers.memesh\` entry in \`${label}\`.`, { code: 'mcp-config.no-entry' });
|
|
231
245
|
}
|
|
232
246
|
const args = Array.isArray(server.args) ? server.args : [];
|
|
233
247
|
const entry = typeof args[0] === 'string' ? args[0] : null;
|
|
234
248
|
if (entry) {
|
|
235
|
-
const
|
|
249
|
+
const pluginRoot = installChannel === 'plugin-marketplace' ? packageRoot : (env.CLAUDE_PLUGIN_ROOT || null);
|
|
250
|
+
if (entry.includes(MCP_PLACEHOLDER) && pluginRoot === null) {
|
|
251
|
+
return createCheck('mcp-config', 'MCP config', 'warn', `${label} starts \`${entry}\`. NOT VERIFIED: \`${MCP_PLACEHOLDER}\` is substituted by the Claude Code plugin runtime, and this is a ${installChannel} install with CLAUDE_PLUGIN_ROOT unset — so the file it names was not checked.`, `Verify it the way the plugin runtime would: CLAUDE_PLUGIN_ROOT=${packageRoot} memesh doctor`, { code: 'mcp-config.placeholder-unresolved', params: { entry, channel: installChannel } });
|
|
252
|
+
}
|
|
253
|
+
const resolved = pluginRoot === null
|
|
254
|
+
? path.resolve(packageRoot, entry)
|
|
255
|
+
: path.resolve(entry.replaceAll(MCP_PLACEHOLDER, pluginRoot));
|
|
236
256
|
if (!existsSyncImpl(resolved)) {
|
|
237
|
-
return createCheck('mcp-config', 'MCP config', 'fail',
|
|
257
|
+
return createCheck('mcp-config', 'MCP config', 'fail', `${label} starts \`${entry}\`, and that file is not in this install — so every memesh MCP tool fails to start.`, `Reinstall MeMesh; if you edited \`${label}\` by hand, point it back at \`${MCP_PLACEHOLDER}/dist/mcp/server.js\`.`, { code: 'mcp-config.entry-missing', params: { entry, resolved } });
|
|
238
258
|
}
|
|
239
259
|
}
|
|
240
|
-
return createCheck('mcp-config', 'MCP config', 'pass',
|
|
260
|
+
return createCheck('mcp-config', 'MCP config', 'pass', `${label} is present, defines the memesh MCP server, and the script it starts exists.`);
|
|
241
261
|
}
|
|
242
262
|
function extractHookScriptPaths(hooksConfig, packageRoot) {
|
|
243
263
|
const hooks = hooksConfig.hooks;
|
|
@@ -530,19 +550,11 @@ function defaultResolveShellMemesh() {
|
|
|
530
550
|
return null;
|
|
531
551
|
}
|
|
532
552
|
}
|
|
533
|
-
|
|
534
|
-
function defaultNativeBindingProbe(packageRoot) {
|
|
553
|
+
function defaultNativeBindingProbe(_packageRoot) {
|
|
535
554
|
try {
|
|
536
|
-
const probe = new MemeshDatabase(':memory:'
|
|
555
|
+
const probe = new MemeshDatabase(':memory:');
|
|
537
556
|
try {
|
|
538
|
-
|
|
539
|
-
return { ok: false, message: `${RUNTIME_TOO_OLD}: node:sqlite in ${process.version} has no enableLoadExtension` };
|
|
540
|
-
}
|
|
541
|
-
probe.enableLoadExtension(true);
|
|
542
|
-
const localRequire = createRequire(pathToFileURL(path.join(packageRoot, 'package.json')).href);
|
|
543
|
-
const sqliteVec = localRequire('sqlite-vec');
|
|
544
|
-
sqliteVec.load(probe);
|
|
545
|
-
probe.prepare('SELECT vec_version()').get();
|
|
557
|
+
probe.prepare('SELECT 1').get();
|
|
546
558
|
}
|
|
547
559
|
finally {
|
|
548
560
|
probe.close();
|
|
@@ -607,19 +619,36 @@ export function hasBuiltInSqlite() {
|
|
|
607
619
|
}
|
|
608
620
|
function inspectNativeBinding(packageRoot, _existsSyncImpl, probeImpl = defaultNativeBindingProbe) {
|
|
609
621
|
const result = probeImpl(packageRoot);
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
622
|
+
return result.ok
|
|
623
|
+
? createCheck('native-binding', 'SQLite', 'pass', 'node:sqlite opened a database (probe succeeded).')
|
|
624
|
+
: createCheck('native-binding', 'SQLite', 'fail', `SQLite could not open a database: ${result.message}`, 'Check the Node runtime and reinstall if necessary.', { code: 'native-binding.load-failed', params: { detail: result.message, root: packageRoot } });
|
|
625
|
+
}
|
|
626
|
+
function readVersionFromInstalledBinary(binaryPath, existsSyncImpl, readFileSyncImpl, realpathSyncImpl = fs.realpathSync) {
|
|
627
|
+
let resolved;
|
|
628
|
+
try {
|
|
629
|
+
resolved = realpathSyncImpl(binaryPath);
|
|
615
630
|
}
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
return createCheck('native-binding', 'SQLite and vector search', 'warn', 'sqlite-vec is not installed, so memesh cannot search by meaning. Memories are still saved, and still found by keyword.', 'Run: npm install (in the directory that depends on @pcircle/memesh)', { code: 'native-binding.not-installed' });
|
|
631
|
+
catch {
|
|
632
|
+
resolved = binaryPath;
|
|
619
633
|
}
|
|
620
|
-
|
|
634
|
+
let dir = path.dirname(resolved);
|
|
635
|
+
for (let depth = 0; depth < 8; depth += 1) {
|
|
636
|
+
const pkgPath = path.join(dir, 'package.json');
|
|
637
|
+
if (existsSyncImpl(pkgPath)) {
|
|
638
|
+
const parsed = parseJsonFile(pkgPath, readFileSyncImpl);
|
|
639
|
+
if (!parsed.ok)
|
|
640
|
+
return null;
|
|
641
|
+
const { name, version } = parsed.value;
|
|
642
|
+
return name === '@pcircle/memesh' && typeof version === 'string' ? version : null;
|
|
643
|
+
}
|
|
644
|
+
const parent = path.dirname(dir);
|
|
645
|
+
if (parent === dir)
|
|
646
|
+
return null;
|
|
647
|
+
dir = parent;
|
|
648
|
+
}
|
|
649
|
+
return null;
|
|
621
650
|
}
|
|
622
|
-
function inspectShellCli(installChannel, packageRoot, resolveShellMemeshImpl) {
|
|
651
|
+
function inspectShellCli(installChannel, packageRoot, packageVersion, resolveShellMemeshImpl, existsSyncImpl, readFileSyncImpl) {
|
|
623
652
|
const shellPath = resolveShellMemeshImpl();
|
|
624
653
|
const isSameAsCurrent = shellPath ? path.resolve(shellPath).startsWith(path.resolve(packageRoot)) : false;
|
|
625
654
|
const hasDistinctShellCli = !!shellPath && !isSameAsCurrent;
|
|
@@ -629,12 +658,20 @@ function inspectShellCli(installChannel, packageRoot, resolveShellMemeshImpl) {
|
|
|
629
658
|
: 'Running from npm-global install — shell access available in this terminal.');
|
|
630
659
|
}
|
|
631
660
|
if (hasDistinctShellCli) {
|
|
632
|
-
|
|
661
|
+
const shellVersion = readVersionFromInstalledBinary(shellPath, existsSyncImpl, readFileSyncImpl);
|
|
662
|
+
if (shellVersion) {
|
|
663
|
+
return {
|
|
664
|
+
...createInfo('shell-cli', 'Shell CLI on PATH', `Installed versions: this interface ${packageVersion}; terminal ${shellVersion}.`),
|
|
665
|
+
code: 'shell-cli.versions',
|
|
666
|
+
params: { current: packageVersion, terminal: shellVersion, shellPath: shellPath, packageRoot },
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
return createCheck('shell-cli', 'Shell CLI on PATH', 'pass', `\`memesh\` resolves to ${shellPath} (separate from this install at ${packageRoot}) — could not read the shell copy's own version to compare.`);
|
|
633
670
|
}
|
|
634
671
|
if (installChannel === 'plugin-marketplace') {
|
|
635
672
|
const host = detectPluginHost(packageRoot) === 'codex' ? 'Codex CLI' : 'Claude Code';
|
|
636
673
|
return createCheck('shell-cli', 'Shell CLI on PATH', 'warn', 'Plugin is installed but `memesh` is not on the shell PATH. Typing `memesh` in a regular terminal will report `command not found`. '
|
|
637
|
-
+ `${host} MCP / hooks / \`/memesh\` skill still work — this only affects standalone shell usage and other MCP clients (Cursor, Cline, etc.).`, 'Run `npm install -g @pcircle/memesh`
|
|
674
|
+
+ `${host} MCP / hooks / \`/memesh\` skill still work — this only affects standalone shell usage and other MCP clients (Cursor, Cline, etc.).`, 'Run `npm install -g @pcircle/memesh` if you want the separate shell CLI. Its database path depends on its environment and configuration.', { code: 'shell-cli.not-on-path' });
|
|
638
675
|
}
|
|
639
676
|
return createCheck('shell-cli', 'Shell CLI on PATH', 'pass', shellPath
|
|
640
677
|
? `\`memesh\` resolves to ${shellPath}.`
|
|
@@ -827,6 +864,24 @@ function inspectPluginCacheCurrency(installChannel, pluginHost, packageRoot, ins
|
|
|
827
864
|
}
|
|
828
865
|
return createCheck('plugin-cache', `Plugin cache source record is current (${hostLabel})`, 'warn', `The plugin cache records commit ${installedSha.slice(0, 8)}, but the marketplace has moved to ${marketplaceSha.slice(0, 8)} under the same version — ${hostLabel} does not normally refresh a cache whose version did not change, so refresh the cache before relying on the newer marketplace code.`, `Run \`${command}\` to refresh the cache in place, then restart ${hostLabel}.`, { code: 'plugin-cache.stale', params: { installed: installedSha.slice(0, 8), marketplace: marketplaceSha.slice(0, 8), host: hostLabel, command } });
|
|
829
866
|
}
|
|
867
|
+
function isClaudeChannelCommand(command) {
|
|
868
|
+
if (command === 'memesh-host-claude')
|
|
869
|
+
return true;
|
|
870
|
+
if (typeof command !== 'string' || !path.isAbsolute(command) || path.basename(command) !== 'memesh-host-claude') {
|
|
871
|
+
return false;
|
|
872
|
+
}
|
|
873
|
+
try {
|
|
874
|
+
const target = fs.realpathSync(command);
|
|
875
|
+
const stat = fs.statSync(target);
|
|
876
|
+
if (!stat.isFile())
|
|
877
|
+
return false;
|
|
878
|
+
fs.accessSync(target, fs.constants.X_OK);
|
|
879
|
+
return true;
|
|
880
|
+
}
|
|
881
|
+
catch {
|
|
882
|
+
return false;
|
|
883
|
+
}
|
|
884
|
+
}
|
|
830
885
|
function inspectClaudeChannelRegistration(existsSyncImpl, readFileSyncImpl) {
|
|
831
886
|
const configPath = path.join(homeDir(), '.claude.json');
|
|
832
887
|
let parsed = null;
|
|
@@ -875,14 +930,15 @@ function inspectClaudeChannelRegistration(existsSyncImpl, readFileSyncImpl) {
|
|
|
875
930
|
targetConfigValid = false;
|
|
876
931
|
}
|
|
877
932
|
}
|
|
878
|
-
const
|
|
933
|
+
const commandValid = isClaudeChannelCommand(command);
|
|
934
|
+
const coherent = commandValid
|
|
879
935
|
&& args !== null
|
|
880
936
|
&& args.length === 2
|
|
881
937
|
&& configIndex === 0
|
|
882
938
|
&& target !== null
|
|
883
939
|
&& targetConfigValid;
|
|
884
940
|
if (!coherent) {
|
|
885
|
-
const reason =
|
|
941
|
+
const reason = !commandValid || args === null || configIndex !== 0 || target === null
|
|
886
942
|
? 'the command or --config declaration is malformed'
|
|
887
943
|
: 'the declared owner config target is missing, insecure, malformed, or incomplete';
|
|
888
944
|
return createCheck('claude-channel', 'Claude Channel registration', 'warn', `The user-scoped memesh-channel registration is present but ${reason}. Live Claude Channel notification is not established.`, 'Remove and re-register the owner-controlled memesh-channel entry with `memesh agent setup claude`; keep its generated config file owner-private.');
|
|
@@ -977,7 +1033,13 @@ async function inspectUpdateStatus(packageVersion, getUpdateCheckImpl, installSu
|
|
|
977
1033
|
return createCheck('update-status', 'Update status', 'pass', `Running pre-release version (${packageVersion}), npm latest is ${update.latestVersion}`);
|
|
978
1034
|
}
|
|
979
1035
|
}
|
|
980
|
-
|
|
1036
|
+
const checkedHoursAgo = update.lastSuccessfulCheckAt === null
|
|
1037
|
+
? null
|
|
1038
|
+
: (Date.now() - Date.parse(update.lastSuccessfulCheckAt)) / 3600_000;
|
|
1039
|
+
const checkedAgo = formatHoursAgo(checkedHoursAgo);
|
|
1040
|
+
return createCheck('update-status', 'Update status', update.freshness === 'stale' ? 'warn' : 'pass', update.freshness === 'stale'
|
|
1041
|
+
? `As of the last check (${checkedAgo}), ${packageVersion} was the latest version — that check is more than 24h old, so a newer release may exist since. Doctor never makes a live registry call itself.`
|
|
1042
|
+
: `As of the last check (${checkedAgo}), ${packageVersion} was the latest version.`, update.freshness === 'stale'
|
|
981
1043
|
? 'Run `memesh status` while online to refresh cached update metadata.'
|
|
982
1044
|
: undefined, update.freshness === 'stale'
|
|
983
1045
|
? { code: 'update-status.stale', params: { version: packageVersion } }
|
|
@@ -1099,8 +1161,7 @@ function inspectMessageCapability(packageRoot, enabled, probe) {
|
|
|
1099
1161
|
return createCheck('message-capability', 'Message adapter imports', 'fail', `Installed message capability probe failed: ${result.message}.`, 'Reinstall or rebuild this package, then retry with MEMESH_DOCTOR_PROBE_MESSAGE_CAPABILITY=1.', { code: 'message-capability.probe-failed', params: { detail: result.message } });
|
|
1100
1162
|
}
|
|
1101
1163
|
async function defaultMessageRouterStatusProbe() {
|
|
1102
|
-
const socketPath = process.env.MEMESH_ROUTER_SOCKET
|
|
1103
|
-
?? path.join(getMemeshDirFromDbPath(), 'agent-router.sock');
|
|
1164
|
+
const socketPath = process.env.MEMESH_ROUTER_SOCKET ?? getAgentRouterSocketPath();
|
|
1104
1165
|
let stat;
|
|
1105
1166
|
try {
|
|
1106
1167
|
stat = fs.lstatSync(socketPath);
|
|
@@ -1147,54 +1208,6 @@ async function inspectMessageRouterStatus(enabled, probe) {
|
|
|
1147
1208
|
return createCheck('message-router-status', 'Live message router / host registration', 'warn', `An owner-private router socket exists at ${result.socket_path}, but it did not accept a local connection. No host registration or native delivery is verified.`, 'Check the owner-configured `memesh-router` process, then run this opt-in probe again.', { code: 'message-router.socket-unreachable', params: { path: result.socket_path } });
|
|
1148
1209
|
}
|
|
1149
1210
|
}
|
|
1150
|
-
async function inspectEmbeddingProbe(capabilities, probeCapabilities, embedTextImpl) {
|
|
1151
|
-
if (capabilities.embeddings === 'tfidf') {
|
|
1152
|
-
return createInfo('embeddings_probe', 'Embeddings work', 'No neural embedder configured — recall runs on FTS5 keyword search alone. That is a supported mode, not a fault.');
|
|
1153
|
-
}
|
|
1154
|
-
if (!probeCapabilities) {
|
|
1155
|
-
return createInfo('embeddings_probe', 'Embeddings work', `NOT VERIFIED. Config names "${capabilities.embeddings}", but generating a test embedding is a network call (billed on hosted providers) so it was not made — a revoked key or an unreachable host would look identical to a healthy setup here.`, 'Run: memesh doctor --probe (generates one test embedding to confirm)');
|
|
1156
|
-
}
|
|
1157
|
-
let timer;
|
|
1158
|
-
try {
|
|
1159
|
-
const vector = await Promise.race([
|
|
1160
|
-
embedTextImpl('memesh doctor embedding probe'),
|
|
1161
|
-
new Promise((_, reject) => {
|
|
1162
|
-
timer = setTimeout(() => reject(new Error(`no response within ${EMBEDDING_PROBE_TIMEOUT_MS / 1000}s`)), EMBEDDING_PROBE_TIMEOUT_MS);
|
|
1163
|
-
}),
|
|
1164
|
-
]);
|
|
1165
|
-
if (!vector || vector.length === 0) {
|
|
1166
|
-
return createCheck('embeddings_probe', 'Embeddings work', 'warn', `Config selects "${capabilities.embeddings}" but generating a test embedding returned nothing. Semantic recall is degraded to FTS5-only; keyword search still works.`, 'Run: memesh doctor --probe for detail, or check network access to the embedding provider.', { code: 'embeddings.empty', params: { provider: String(capabilities.embeddings) } });
|
|
1167
|
-
}
|
|
1168
|
-
return createCheck('embeddings_probe', 'Embeddings work', 'pass', `Generated a ${vector.length}-dim test embedding via "${capabilities.embeddings}".`);
|
|
1169
|
-
}
|
|
1170
|
-
catch (err) {
|
|
1171
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1172
|
-
return createCheck('embeddings_probe', 'Embeddings work', 'warn', `Config selects "${capabilities.embeddings}" but the embedder threw (${msg}). Semantic recall is degraded to FTS5-only.`, 'Check the embedding provider is reachable (e.g. run `ollama serve`), or remove embedder config to use keyword-only search.', { code: 'embeddings.threw', params: { provider: String(capabilities.embeddings), detail: msg } });
|
|
1173
|
-
}
|
|
1174
|
-
finally {
|
|
1175
|
-
clearTimeout(timer);
|
|
1176
|
-
}
|
|
1177
|
-
}
|
|
1178
|
-
async function inspectLlmProbe(capabilities, probeCapabilities, probeProviderImpl) {
|
|
1179
|
-
const llm = capabilities.llm;
|
|
1180
|
-
if (!llm) {
|
|
1181
|
-
return createInfo('llm_probe', 'LLM reachable', 'No LLM configured — Core Mode. Write-side features (lessons, auto-tag, dream) are off by design.');
|
|
1182
|
-
}
|
|
1183
|
-
if (!probeCapabilities) {
|
|
1184
|
-
return createInfo('llm_probe', 'LLM reachable', `NOT VERIFIED. Config names ${llm.provider} (${llm.model ?? 'default'}), but no live call was made — an expired key or an unreachable host would look identical to a healthy setup here.`, 'Run: memesh doctor --probe (makes one small live call to confirm)');
|
|
1185
|
-
}
|
|
1186
|
-
try {
|
|
1187
|
-
const result = await probeProviderImpl(llm.provider, llm.apiKey);
|
|
1188
|
-
if (result.valid) {
|
|
1189
|
-
return createCheck('llm_probe', 'LLM reachable', 'pass', `${llm.provider} answered a live probe.`);
|
|
1190
|
-
}
|
|
1191
|
-
return createCheck('llm_probe', 'LLM reachable', 'fail', `${llm.provider} is configured but did not answer: ${result.error ?? 'unknown error'}. Every LLM-backed feature is silently doing nothing.`, 'Check the API key / host, then re-run: memesh doctor --probe', { code: 'llm.unreachable', params: { provider: llm.provider, detail: result.error ?? 'unknown error' } });
|
|
1192
|
-
}
|
|
1193
|
-
catch (err) {
|
|
1194
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1195
|
-
return createCheck('llm_probe', 'LLM reachable', 'fail', `${llm.provider} probe threw: ${msg}. Every LLM-backed feature is silently doing nothing.`, 'Check the API key / host, then re-run: memesh doctor --probe', { code: 'llm.threw', params: { provider: llm.provider, detail: msg } });
|
|
1196
|
-
}
|
|
1197
|
-
}
|
|
1198
1211
|
function summarizeOverallStatus(checks) {
|
|
1199
1212
|
const assertions = checks.filter((check) => !check.informational);
|
|
1200
1213
|
if (assertions.some((check) => check.status === 'fail'))
|
|
@@ -1204,7 +1217,7 @@ function summarizeOverallStatus(checks) {
|
|
|
1204
1217
|
return 'PASS';
|
|
1205
1218
|
}
|
|
1206
1219
|
export async function runDoctor(options) {
|
|
1207
|
-
const { packageRoot, packageVersion, probeHttp = false,
|
|
1220
|
+
const { packageRoot, packageVersion, probeHttp = false, httpBaseUrl = 'http://127.0.0.1:3737', platform = process.platform, envImpl = process.env, openDatabaseImpl = openDatabase, closeDatabaseImpl = closeDatabase, isDatabaseOpenImpl = isDatabaseOpen, getConfigPathImpl = getConfigPath, getUpdateCheckImpl = getUpdateCheck, getCurrentInstallChannelImpl = getCurrentInstallChannel, installedPluginsPathImpl, marketplaceHeadShaImpl = defaultMarketplaceHeadSha, pluginCacheDiscoveryImpl, getInstallChannelSupportImpl = getInstallChannelSupport, existsSyncImpl = fs.existsSync, readFileSyncImpl = fs.readFileSync, statSyncImpl = fs.statSync, fetchImpl = fetch, agentMessageStoragePolicy, nativeBindingProbeImpl, resolveShellMemeshImpl = defaultResolveShellMemesh, probeMessageCapability = process.env.MEMESH_DOCTOR_PROBE_MESSAGE_CAPABILITY === '1', messageCapabilityProbeImpl = probeInstalledMessageCapability, probeMessageRouterStatus = process.env.MEMESH_DOCTOR_PROBE_MESSAGE_ROUTER === '1', messageRouterStatusProbeImpl = defaultMessageRouterStatusProbe, } = options;
|
|
1208
1221
|
const wasDbOpenBeforeUs = isDatabaseOpenImpl();
|
|
1209
1222
|
const safeCloseDatabaseImpl = wasDbOpenBeforeUs
|
|
1210
1223
|
? () => undefined
|
|
@@ -1240,39 +1253,6 @@ export async function runDoctor(options) {
|
|
|
1240
1253
|
`automatic rebuild cannot notice. Re-run doctor after the rebuild: this count should be 0.`, `Run 'memesh reindex --fts' to rebuild the keyword index.`, { code: 'fts.unsegmented', params: { count: unsegmented.c } }, 'fts-rebuild'));
|
|
1241
1254
|
}
|
|
1242
1255
|
}
|
|
1243
|
-
const pendingReindex = getPendingReindexInfo();
|
|
1244
|
-
const vectorDb = db;
|
|
1245
|
-
let missingVectors;
|
|
1246
|
-
let vectorsPossible = true;
|
|
1247
|
-
try {
|
|
1248
|
-
vectorsPossible = hasVectorIndex(vectorDb);
|
|
1249
|
-
missingVectors = vectorsPossible ? countMissingVectors(vectorDb) : 0;
|
|
1250
|
-
}
|
|
1251
|
-
catch {
|
|
1252
|
-
missingVectors = null;
|
|
1253
|
-
}
|
|
1254
|
-
const payableDebt = pendingReindex && !(pendingReindex.reason === 'vectors-missing' && !vectorsPossible);
|
|
1255
|
-
if (payableDebt || missingVectors === null || missingVectors > 0) {
|
|
1256
|
-
const owed = pendingReindex && pendingReindex.reason !== 'vectors-missing'
|
|
1257
|
-
? 'Search index needs rebuilding (embedding configuration changed)'
|
|
1258
|
-
: missingVectors === null
|
|
1259
|
-
? 'The vector index could not be read, so how much of your memory semantic recall can see is unknown'
|
|
1260
|
-
: `${missingVectors} memor${missingVectors === 1 ? 'y has' : 'ies have'} no search vector, `
|
|
1261
|
-
+ 'so semantic recall cannot find them (keyword search still works)';
|
|
1262
|
-
dbChecks.push(createCheck('vector_index', 'Vector Index', 'warn', owed, `Run 'memesh reindex' to fix. This will restore full search functionality.`, { code: 'vector-index.stale', params: { missing: missingVectors ?? -1 } }));
|
|
1263
|
-
}
|
|
1264
|
-
const generation = readVectorGeneration();
|
|
1265
|
-
if (generation.state !== 'none') {
|
|
1266
|
-
const staged = generationRowIds().size;
|
|
1267
|
-
const detail = generation.state === 'open'
|
|
1268
|
-
? `${staged} vectors staged at ${generation.info.dimension} dimensions `
|
|
1269
|
-
+ `(provider ${generation.info.provider}, started ${generation.info.startedAt})`
|
|
1270
|
-
: `${staged} vectors staged, but the marker cannot be read (${generation.detail})`;
|
|
1271
|
-
dbChecks.push(createCheck('vector_generation', 'Half-built search index', 'warn', `An unfinished index rebuild is holding disk space: ${detail}.`, generation.state === 'open'
|
|
1272
|
-
? `Run 'memesh reindex' to finish it (the vectors already produced are reused), `
|
|
1273
|
-
+ `or 'memesh reindex --discard-generation' to reclaim the space.`
|
|
1274
|
-
: `Run 'memesh reindex --discard-generation' to clear it, then 'memesh reindex'.`, { code: 'vector-generation.open', params: { staged } }));
|
|
1275
|
-
}
|
|
1276
1256
|
try {
|
|
1277
1257
|
const guardRows = db
|
|
1278
1258
|
.prepare(`SELECT id, name, metadata FROM entities
|
|
@@ -1406,8 +1386,8 @@ export async function runDoctor(options) {
|
|
|
1406
1386
|
catch {
|
|
1407
1387
|
}
|
|
1408
1388
|
}
|
|
1409
|
-
checks.push(inspectConfigFile(existsSyncImpl, readFileSyncImpl, getConfigPathImpl
|
|
1410
|
-
checks.push(inspectMcpConfig(packageRoot, existsSyncImpl, readFileSyncImpl));
|
|
1389
|
+
checks.push(inspectConfigFile(existsSyncImpl, readFileSyncImpl, getConfigPathImpl));
|
|
1390
|
+
checks.push(inspectMcpConfig(packageRoot, install, existsSyncImpl, readFileSyncImpl, envImpl));
|
|
1411
1391
|
checks.push(...inspectHooksConfig(packageRoot, platform, existsSyncImpl, readFileSyncImpl, statSyncImpl));
|
|
1412
1392
|
const pluginHost = detectPluginHost(packageRoot);
|
|
1413
1393
|
let codexPluginCacheDetected = pluginHost === 'codex';
|
|
@@ -1450,24 +1430,10 @@ export async function runDoctor(options) {
|
|
|
1450
1430
|
checks.push(inspectDashboardArtifact(packageRoot, existsSyncImpl));
|
|
1451
1431
|
checks.push(inspectNodeRuntime(packageRoot, existsSyncImpl, readFileSyncImpl));
|
|
1452
1432
|
checks.push(inspectNativeBinding(packageRoot, existsSyncImpl, nativeBindingProbeImpl));
|
|
1453
|
-
checks.push(inspectShellCli(install, packageRoot, resolveShellMemeshImpl));
|
|
1433
|
+
checks.push(inspectShellCli(install, packageRoot, packageVersion, resolveShellMemeshImpl, existsSyncImpl, readFileSyncImpl));
|
|
1454
1434
|
checks.push(verifySkillsManifest(packageRoot, existsSyncImpl, readFileSyncImpl, installSupport));
|
|
1455
1435
|
checks.push(inspectMessageCapability(packageRoot, probeMessageCapability, messageCapabilityProbeImpl));
|
|
1456
1436
|
checks.push(await inspectMessageRouterStatus(probeMessageRouterStatus, messageRouterStatusProbeImpl));
|
|
1457
|
-
const capabilities = detectCapabilitiesImpl();
|
|
1458
|
-
checks.push(createInfo('capabilities', 'Capabilities (configured)', `Search level ${capabilities.searchLevel} (${capabilities.searchLevel === 1 ? 'Smart Mode' : 'Core'}); embeddings: ${capabilities.embeddings}; LLM: ${capabilities.llm ? `${capabilities.llm.provider} (${capabilities.llm.model ?? 'default'})` : 'not configured'}. Configured values only — see the probe rows below for what actually works.`));
|
|
1459
|
-
if (!isTranscriptMiningEnabled()) {
|
|
1460
|
-
checks.push(createInfo('transcript-mining', 'Scheduled transcript mining', 'Off (opt-in). memesh can mine this project\'s Claude Code session transcripts for decisions and lessons and STAGE them for your review. Turn it on with `memesh config set transcriptMining true`, then have a scheduler (cron/launchd) run `memesh dream run --from-transcripts --if-due` — it self-throttles and stages only, so nothing enters your graph without `dream accept`.'));
|
|
1461
|
-
}
|
|
1462
|
-
else {
|
|
1463
|
-
const last = lastTranscriptMineAt(getProjectName(process.cwd()));
|
|
1464
|
-
const when = last === null
|
|
1465
|
-
? 'not yet run for this project'
|
|
1466
|
-
: `last mined ${((Date.now() - last) / 3600_000).toFixed(1)}h ago`;
|
|
1467
|
-
checks.push(createInfo('transcript-mining', 'Scheduled transcript mining', `On for this project — ${when}. Have a scheduler run \`memesh dream run --from-transcripts --if-due\`; it mines when due (default every 24h) and stages proposals. Review the queue with \`memesh dream list\`.`));
|
|
1468
|
-
}
|
|
1469
|
-
checks.push(await inspectEmbeddingProbe(capabilities, probeCapabilities, embedTextImpl));
|
|
1470
|
-
checks.push(await inspectLlmProbe(capabilities, probeCapabilities, probeProviderImpl));
|
|
1471
1437
|
checks.push(await inspectUpdateStatus(packageVersion, getUpdateCheckImpl, installSupport));
|
|
1472
1438
|
try {
|
|
1473
1439
|
const record = getInstallRecord();
|