memorix 1.8.4 → 1.8.6
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/CHANGELOG.md +52 -0
- package/CLAUDE.md +3 -0
- package/README.md +8 -6
- package/README.zh-CN.md +5 -3
- package/assets/star-history-dark.svg +5 -5
- package/assets/star-history-light.svg +5 -5
- package/assets/star-history.json +35 -5
- package/dist/cli/index.js +1848 -754
- package/dist/dashboard/static/app.js +29 -885
- package/dist/dashboard/static/index.html +1 -5
- package/dist/dashboard/static/style.css +36 -503
- package/dist/index.d.ts +4 -4
- package/dist/index.js +286 -79
- package/dist/memcode/index.js +28035 -169
- package/dist/memcode-runtime/CHANGELOG.md +52 -0
- package/dist/sdk.js +103 -21
- package/dist/types.d.ts +1 -1
- package/docs/1.8.0-RELEASE-CANDIDATE-SPEC.md +22 -16
- package/docs/AGENT_OPERATOR_PLAYBOOK.md +2 -2
- package/docs/API_REFERENCE.md +10 -8
- package/docs/DASHBOARD.md +23 -0
- package/docs/DEVELOPMENT.md +2 -2
- package/docs/DOCKER.md +6 -3
- package/docs/INTEGRATIONS.md +2 -1
- package/docs/MODULES.md +46 -20
- package/docs/PERFORMANCE.md +1 -1
- package/docs/README.md +8 -7
- package/docs/SETUP.md +4 -3
- package/package.json +11 -11
- package/plugins/antigravity/memorix/plugin.json +1 -1
- package/plugins/antigravity/memorix/rules/memorix.md +5 -0
- package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
- package/plugins/claude/memorix/skills/memorix-memory/SKILL.md +3 -0
- package/plugins/claude/memorix/skills/memorix-mini-skills/SKILL.md +2 -0
- package/plugins/claude/memorix/skills/memorix-orchestrate/SKILL.md +2 -0
- package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
- package/plugins/codebuddy/memorix/skills/memorix-memory/SKILL.md +3 -0
- package/plugins/codebuddy/memorix/skills/memorix-mini-skills/SKILL.md +2 -0
- package/plugins/codebuddy/memorix/skills/memorix-orchestrate/SKILL.md +2 -0
- package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/codex/memorix/skills/memorix-memory/SKILL.md +3 -0
- package/plugins/codex/memorix/skills/memorix-mini-skills/SKILL.md +2 -0
- package/plugins/codex/memorix/skills/memorix-orchestrate/SKILL.md +2 -0
- package/plugins/copilot/memorix/plugin.json +1 -1
- package/plugins/copilot/memorix/skills/memorix-memory/SKILL.md +3 -0
- package/plugins/copilot/memorix/skills/memorix-mini-skills/SKILL.md +2 -0
- package/plugins/copilot/memorix/skills/memorix-orchestrate/SKILL.md +2 -0
- package/plugins/cursor/memorix/skills/memorix-memory/SKILL.md +3 -0
- package/plugins/cursor/memorix/skills/memorix-mini-skills/SKILL.md +2 -0
- package/plugins/cursor/memorix/skills/memorix-orchestrate/SKILL.md +2 -0
- package/plugins/gemini/memorix/GEMINI.md +5 -0
- package/plugins/gemini/memorix/gemini-extension.json +1 -1
- package/plugins/hermes/memorix/plugin.yaml +7 -1
- package/plugins/omp/memorix/package.json +1 -1
- package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/pi/memorix/package.json +1 -1
- package/plugins/pi/memorix/skills/memorix-memory/SKILL.md +3 -0
- package/plugins/pi/memorix/skills/memorix-mini-skills/SKILL.md +2 -0
- package/plugins/pi/memorix/skills/memorix-orchestrate/SKILL.md +2 -0
- package/server.json +2 -2
- package/src/cli/command-guide.ts +52 -1
- package/src/cli/commands/agent-integrations.ts +1 -0
- package/src/cli/commands/background.ts +166 -6
- package/src/cli/commands/hooks-install.ts +9 -2
- package/src/cli/commands/hooks-preview.ts +5 -0
- package/src/cli/commands/integrate.ts +2 -0
- package/src/cli/commands/serve-http.ts +73 -80
- package/src/cli/commands/serve.ts +95 -93
- package/src/cli/commands/setup.ts +11 -1
- package/src/cli/commands/uninstall.ts +24 -2
- package/src/cli/index.ts +1 -1
- package/src/codegraph/task-lens.ts +72 -7
- package/src/dashboard/static/index.html +1 -5
- package/src/dashboard/static/style.css +36 -503
- package/src/hooks/installers/index.ts +58 -0
- package/src/hooks/official-skills.ts +13 -6
- package/src/hooks/types.ts +2 -0
- package/src/integrations/registry.ts +9 -0
- package/src/memory/graph.ts +2 -2
- package/src/server/mcp-diagnostics.ts +9 -7
- package/src/server/modern-mcp-bridge.ts +108 -0
- package/src/server/stdio-startup-gate.ts +41 -2
- package/src/server/tool-profile.ts +7 -6
- package/src/server.ts +1 -1
- package/src/store/orama-store.ts +2 -2
- package/src/types.ts +1 -1
- package/src/wiki/types.ts +2 -2
- package/src/workspace/mcp-adapters/workbuddy.ts +71 -0
|
@@ -38,6 +38,9 @@ export const OFFICIAL_MEMORIX_SKILLS: OfficialMemorixSkill[] = [
|
|
|
38
38
|
'| Specific past decision, bug, file, or change | `memorix_search` | `memorix memory search --query "<topic>"` |',
|
|
39
39
|
'| Need the full source for a search hit | `memorix_detail` | `memorix memory detail --id <id>` |',
|
|
40
40
|
'| Need the sequence around one memory | `memorix_timeline` | `memorix memory timeline --id <id>` |',
|
|
41
|
+
'| Check source and freshness for a memory | `memorix_evidence` | `memorix evidence list|get|events` |',
|
|
42
|
+
'| Record whether a memory helped, conflicted, or was corrected | `memorix_feedback` | `memorix feedback record|show|audit` |',
|
|
43
|
+
'| Inspect or import controlled media | `memorix_media` | `memorix media import|attach|list|show|status` |',
|
|
41
44
|
'| Learned reusable project knowledge | `memorix_store` | `memorix memory store --type <type> --entity <name> --title "<title>" "<text>"` |',
|
|
42
45
|
'| Task or bug is complete/outdated | `memorix_resolve` | `memorix memory resolve --ids <ids>` |',
|
|
43
46
|
'',
|
|
@@ -168,6 +171,8 @@ export const OFFICIAL_MEMORIX_SKILLS: OfficialMemorixSkill[] = [
|
|
|
168
171
|
'',
|
|
169
172
|
'Promote memories into mini-skills only when they are reusable instructions, not just historical notes.',
|
|
170
173
|
'',
|
|
174
|
+
'The standard setup uses the `lite` MCP profile. `memorix_skills` and `memorix_promote` are full-profile tools, so use the CLI fallback unless the current server was explicitly started with `MEMORIX_MODE=full` or `--mode full`. Do not probe hidden MCP tools repeatedly.',
|
|
175
|
+
'',
|
|
171
176
|
'## Tool Router',
|
|
172
177
|
'',
|
|
173
178
|
'| Situation | Prefer | CLI fallback |',
|
|
@@ -203,15 +208,17 @@ export const OFFICIAL_MEMORIX_SKILLS: OfficialMemorixSkill[] = [
|
|
|
203
208
|
'| Situation | Prefer | CLI fallback |',
|
|
204
209
|
'|---|---|---|',
|
|
205
210
|
'| Run managed subagent execution | CLI | `memorix orchestrate --goal "<goal>" --agents claude:1,codex:1` |',
|
|
206
|
-
'| Register coordination identity | `team_manage` action `join` | `memorix team join --agentType <agent>` |',
|
|
207
|
-
'| Create or inspect tasks | `team_task` | `memorix task create|list|claim|complete` |',
|
|
208
|
-
'| Send or read coordination messages | `team_message` | `memorix message send|broadcast|inbox` |',
|
|
209
|
-
'| Share structured handoff | `memorix_handoff` | `memorix handoff send` |',
|
|
210
|
-
'| Avoid file conflicts | `team_file_lock` | `memorix lock lock|unlock|status` |',
|
|
211
|
-
'| Poll joined coordination state | `memorix_poll` | `memorix poll` |',
|
|
211
|
+
'| Register coordination identity when team MCP tools are available | `team_manage` action `join` | `memorix team join --agentType <agent>` |',
|
|
212
|
+
'| Create or inspect tasks when team MCP tools are available | `team_task` | `memorix task create|list|claim|complete` |',
|
|
213
|
+
'| Send or read coordination messages when team MCP tools are available | `team_message` | `memorix message send|broadcast|inbox` |',
|
|
214
|
+
'| Share structured handoff when team MCP tools are available | `memorix_handoff` | `memorix handoff send` |',
|
|
215
|
+
'| Avoid file conflicts when team MCP tools are available | `team_file_lock` | `memorix lock lock|unlock|status` |',
|
|
216
|
+
'| Poll joined coordination state when team MCP tools are available | `memorix_poll` | `memorix poll` |',
|
|
212
217
|
'',
|
|
213
218
|
'## Boundaries',
|
|
214
219
|
'',
|
|
220
|
+
'The standard setup uses the `lite` MCP profile. Coordination MCP tools are exposed only by `team` or `full`; use the CLI fallback for ordinary installations, or explicitly start the server with `--mode team`. Do not probe unavailable team tools in a loop.',
|
|
221
|
+
'',
|
|
215
222
|
'- For ordinary memory, do not join coordination state.',
|
|
216
223
|
'- For production multi-agent execution, prefer `memorix orchestrate` so the main process owns planning, dispatch, retries, and verification gates.',
|
|
217
224
|
'- `memorix orchestrate` uses the current checkout for single-worker runs and task worktrees for parallel runs. Use `--isolated` to force worktree isolation, `--no-worktree` to disable it, `--allow-dirty` to run with uncommitted changes, and `--no-auto-merge` to preserve task worktrees for manual review.',
|
package/src/hooks/types.ts
CHANGED
|
@@ -42,6 +42,7 @@ export type AgentName =
|
|
|
42
42
|
| 'opencode'
|
|
43
43
|
| 'trae'
|
|
44
44
|
| 'dsh'
|
|
45
|
+
| 'workbuddy'
|
|
45
46
|
| 'pi'
|
|
46
47
|
| 'omp';
|
|
47
48
|
|
|
@@ -63,6 +64,7 @@ export const AGENT_SUPPORT_TIER: Record<AgentName, SupportTier> = {
|
|
|
63
64
|
opencode: 'community',
|
|
64
65
|
trae: 'community',
|
|
65
66
|
dsh: 'community',
|
|
67
|
+
workbuddy: 'community',
|
|
66
68
|
pi: 'community',
|
|
67
69
|
omp: 'community',
|
|
68
70
|
antigravity: 'community',
|
|
@@ -159,6 +159,15 @@ export const MEMORIX_INTEGRATIONS: MemorixIntegration[] = [
|
|
|
159
159
|
surfaces: ['MCP', 'AGENTS.md', 'skills'],
|
|
160
160
|
note: 'DeepSeek Harness support writes a @deepseek-ai/dsh-mcp-client row into $DSH_HOME/cordis.patch.yml (default ~/.dsh/cordis.patch.yml), guidance into the harness AGENTS.md, and skills under $DSH_HOME/skills.',
|
|
161
161
|
},
|
|
162
|
+
{
|
|
163
|
+
agent: 'workbuddy',
|
|
164
|
+
name: 'WorkBuddy',
|
|
165
|
+
entry: 'official-config',
|
|
166
|
+
status: 'ready',
|
|
167
|
+
install: 'memorix setup --agent workbuddy',
|
|
168
|
+
surfaces: ['MCP', 'AGENTS.md'],
|
|
169
|
+
note: 'WorkBuddy support writes a memorix MCP server row into ~/.workbuddy/mcp.json (or <project>/.workbuddy/mcp.json for project installs) and guidance into AGENTS.md.',
|
|
170
|
+
},
|
|
162
171
|
{
|
|
163
172
|
agent: 'memcode',
|
|
164
173
|
name: 'memcode',
|
package/src/memory/graph.ts
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* Source: MCP Official Memory Server v0.6.3 (complete rewrite with same API).
|
|
6
6
|
*
|
|
7
7
|
* Key differences from official implementation:
|
|
8
|
-
* - Uses
|
|
9
|
-
* - Async initialization with persistence layer
|
|
8
|
+
* - Uses the project-scoped SQLite graph store; legacy JSONL is migration-only
|
|
9
|
+
* - Async initialization with the shared persistence layer
|
|
10
10
|
* - Project-scoped operations
|
|
11
11
|
*/
|
|
12
12
|
|
|
@@ -12,7 +12,7 @@ export interface McpDiagnostics {
|
|
|
12
12
|
legacy: string;
|
|
13
13
|
discovery: 'supported';
|
|
14
14
|
versionlessRequests: 'legacy-compatible';
|
|
15
|
-
modernResultMetadata: '
|
|
15
|
+
modernResultMetadata: 'supported';
|
|
16
16
|
statelessRequests: 'supported' | 'compatibility-only' | 'unsupported';
|
|
17
17
|
statefulStreamableHttp: 'supported';
|
|
18
18
|
};
|
|
@@ -20,12 +20,12 @@ export interface McpDiagnostics {
|
|
|
20
20
|
tasks: 'supported' | 'unsupported';
|
|
21
21
|
polling: 'supported' | 'unsupported';
|
|
22
22
|
subscriptions: 'supported' | 'unsupported';
|
|
23
|
-
listCache: 'supported' | 'unsupported';
|
|
23
|
+
listCache: 'supported' | 'protocol-hints-only' | 'unsupported';
|
|
24
24
|
explicitProjectHandle: 'supported';
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
/**
|
|
28
|
+
/** Do not present a fake durable task loop or a cache that does not exist. */
|
|
29
29
|
export function getMcpDiagnostics(): McpDiagnostics {
|
|
30
30
|
return {
|
|
31
31
|
serverName: MCP_SERVER_NAME,
|
|
@@ -34,15 +34,17 @@ export function getMcpDiagnostics(): McpDiagnostics {
|
|
|
34
34
|
legacy: LEGACY_MCP_PROTOCOL_VERSION,
|
|
35
35
|
discovery: 'supported',
|
|
36
36
|
versionlessRequests: 'legacy-compatible',
|
|
37
|
-
modernResultMetadata: '
|
|
38
|
-
statelessRequests: '
|
|
37
|
+
modernResultMetadata: 'supported',
|
|
38
|
+
statelessRequests: 'supported',
|
|
39
39
|
statefulStreamableHttp: 'supported',
|
|
40
40
|
},
|
|
41
41
|
capabilities: {
|
|
42
42
|
tasks: 'unsupported',
|
|
43
43
|
polling: 'unsupported',
|
|
44
|
-
subscriptions: '
|
|
45
|
-
|
|
44
|
+
subscriptions: 'supported',
|
|
45
|
+
// The protocol envelope is emitted, but TTL is intentionally zero until
|
|
46
|
+
// Memorix can invalidate a durable per-project list cache correctly.
|
|
47
|
+
listCache: 'protocol-hints-only',
|
|
46
48
|
explicitProjectHandle: 'supported',
|
|
47
49
|
},
|
|
48
50
|
};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Modern MCP protocol bridge.
|
|
3
|
+
*
|
|
4
|
+
* Memorix's product handlers still use the mature v1 SDK internally. The
|
|
5
|
+
* public modern transport is served by the official v2 SDK; this bridge keeps
|
|
6
|
+
* one source of truth for the tool implementation by forwarding v2 tool calls
|
|
7
|
+
* through an in-process v1 client/server pair.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
fromJsonSchema,
|
|
12
|
+
McpServer as ModernMcpServer,
|
|
13
|
+
} from '@modelcontextprotocol/server';
|
|
14
|
+
import { Client as LegacyClient } from '@modelcontextprotocol/sdk/client/index.js';
|
|
15
|
+
import { InMemoryTransport as LegacyInMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js';
|
|
16
|
+
import { getMcpServerInfo } from './mcp-discovery.js';
|
|
17
|
+
import type { CreateMemorixServerOptions } from '../server.js';
|
|
18
|
+
import type { ProjectBindingSource } from './request-context.js';
|
|
19
|
+
|
|
20
|
+
export interface ModernMcpBridgeOptions extends CreateMemorixServerOptions {
|
|
21
|
+
projectRoot: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Lifecycle hooks kept beside the v2 facade so transport adapters do not lose
|
|
26
|
+
* Memorix-specific project binding and deferred maintenance behavior.
|
|
27
|
+
*/
|
|
28
|
+
export interface ModernMcpBridgeLifecycle {
|
|
29
|
+
projectId: string;
|
|
30
|
+
deferredInit: () => Promise<void>;
|
|
31
|
+
switchProject: (newCwd: string, source?: ProjectBindingSource) => Promise<boolean>;
|
|
32
|
+
isExplicitlyBound: () => boolean;
|
|
33
|
+
handleTransportClose: () => void;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type ModernMcpBridge = ModernMcpServer & {
|
|
37
|
+
memorix: ModernMcpBridgeLifecycle;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Build an official v2 server whose tools delegate to the existing Memorix
|
|
42
|
+
* implementation. The v1 side is process-local and never becomes a second
|
|
43
|
+
* network endpoint, so project isolation and business behavior stay shared.
|
|
44
|
+
*/
|
|
45
|
+
export async function createModernMcpBridge(
|
|
46
|
+
options: ModernMcpBridgeOptions,
|
|
47
|
+
): Promise<ModernMcpBridge> {
|
|
48
|
+
const { createMemorixServer } = await import('../server.js');
|
|
49
|
+
const legacy = await createMemorixServer(
|
|
50
|
+
options.projectRoot,
|
|
51
|
+
undefined,
|
|
52
|
+
undefined,
|
|
53
|
+
{
|
|
54
|
+
...options,
|
|
55
|
+
allowUntrackedFallback: options.allowUntrackedFallback ?? false,
|
|
56
|
+
deferProjectInitUntilBound: options.deferProjectInitUntilBound ?? true,
|
|
57
|
+
deferProjectRuntimeInit: options.deferProjectRuntimeInit ?? true,
|
|
58
|
+
},
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
const [clientTransport, serverTransport] = LegacyInMemoryTransport.createLinkedPair();
|
|
62
|
+
const legacyClient = new LegacyClient({
|
|
63
|
+
name: 'memorix-modern-bridge',
|
|
64
|
+
version: getMcpServerInfo().version,
|
|
65
|
+
});
|
|
66
|
+
await legacy.server.connect(serverTransport);
|
|
67
|
+
await legacyClient.connect(clientTransport);
|
|
68
|
+
|
|
69
|
+
const listed = await legacyClient.listTools();
|
|
70
|
+
const modern = new ModernMcpServer(getMcpServerInfo());
|
|
71
|
+
|
|
72
|
+
for (const tool of listed.tools) {
|
|
73
|
+
modern.registerTool(
|
|
74
|
+
tool.name,
|
|
75
|
+
{
|
|
76
|
+
...(tool.title ? { title: tool.title } : {}),
|
|
77
|
+
...(tool.description ? { description: tool.description } : {}),
|
|
78
|
+
inputSchema: fromJsonSchema(tool.inputSchema as Record<string, unknown>),
|
|
79
|
+
},
|
|
80
|
+
async (args) => await legacyClient.callTool({
|
|
81
|
+
name: tool.name,
|
|
82
|
+
arguments: args as Record<string, unknown>,
|
|
83
|
+
}) as never,
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const bridge = modern as ModernMcpBridge;
|
|
88
|
+
bridge.memorix = {
|
|
89
|
+
projectId: legacy.projectId,
|
|
90
|
+
deferredInit: legacy.deferredInit,
|
|
91
|
+
switchProject: legacy.switchProject,
|
|
92
|
+
isExplicitlyBound: legacy.isExplicitlyBound,
|
|
93
|
+
handleTransportClose: legacy.handleTransportClose,
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
let closed = false;
|
|
97
|
+
const modernClose = modern.close.bind(modern);
|
|
98
|
+
modern.close = async () => {
|
|
99
|
+
if (closed) return;
|
|
100
|
+
closed = true;
|
|
101
|
+
await modernClose();
|
|
102
|
+
await legacyClient.close().catch(() => undefined);
|
|
103
|
+
await legacy.server.close().catch(() => undefined);
|
|
104
|
+
legacy.handleTransportClose();
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
return bridge;
|
|
108
|
+
}
|
|
@@ -54,7 +54,21 @@ export class StdioStartupGate {
|
|
|
54
54
|
this.fail(new Error(`stdio input chunk exceeded ${this.maxBufferSize} bytes`));
|
|
55
55
|
return;
|
|
56
56
|
}
|
|
57
|
-
|
|
57
|
+
// Keep the old claim-less discovery probe compatible even after the
|
|
58
|
+
// official v2 transport is ready. Other complete lines are forwarded
|
|
59
|
+
// unchanged so the v2 transport remains responsible for parsing and
|
|
60
|
+
// protocol errors.
|
|
61
|
+
this.pendingInput += typeof chunk === 'string' ? chunk : chunk.toString('utf8');
|
|
62
|
+
let newline = this.pendingInput.indexOf('\n');
|
|
63
|
+
while (newline >= 0 && !this.stopped) {
|
|
64
|
+
const line = this.pendingInput.slice(0, newline + 1);
|
|
65
|
+
this.pendingInput = this.pendingInput.slice(newline + 1);
|
|
66
|
+
this.handleReadyLine(line);
|
|
67
|
+
newline = this.pendingInput.indexOf('\n');
|
|
68
|
+
}
|
|
69
|
+
if (!this.stopped && Buffer.byteLength(this.pendingInput, 'utf8') > this.maxBufferSize) {
|
|
70
|
+
this.fail(new Error(`stdio input exceeded ${this.maxBufferSize} bytes`));
|
|
71
|
+
}
|
|
58
72
|
return;
|
|
59
73
|
}
|
|
60
74
|
|
|
@@ -171,6 +185,24 @@ export class StdioStartupGate {
|
|
|
171
185
|
this.queuedBytes += bytes;
|
|
172
186
|
}
|
|
173
187
|
|
|
188
|
+
private handleReadyLine(line: string): void {
|
|
189
|
+
const parsed = this.parseLine(line);
|
|
190
|
+
if (parsed && !('error' in parsed) && this.isDiscoveryRequest(parsed.message)) {
|
|
191
|
+
const response = {
|
|
192
|
+
jsonrpc: '2.0',
|
|
193
|
+
id: parsed.message.id,
|
|
194
|
+
result: createMcpStartupDiscoverResult(this.serverInfo),
|
|
195
|
+
};
|
|
196
|
+
try {
|
|
197
|
+
this.stdout.write(`${JSON.stringify(response)}\n`);
|
|
198
|
+
} catch (error) {
|
|
199
|
+
this.fail(error instanceof Error ? error : new Error(String(error)));
|
|
200
|
+
}
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
this.input.write(line);
|
|
204
|
+
}
|
|
205
|
+
|
|
174
206
|
private parseLine(line: string): ParsedLine {
|
|
175
207
|
const trimmed = line.endsWith('\n') ? line.slice(0, -1).replace(/\r$/, '') : line;
|
|
176
208
|
if (!trimmed.trim()) return null;
|
|
@@ -213,7 +245,14 @@ export class StdioStartupGate {
|
|
|
213
245
|
if (message.method !== MCP_SERVER_DISCOVER_METHOD) return false;
|
|
214
246
|
if (!Object.prototype.hasOwnProperty.call(message, 'id')) return false;
|
|
215
247
|
const params = message.params;
|
|
216
|
-
|
|
248
|
+
// A claim-less discover is the compatibility probe supported by Memorix
|
|
249
|
+
// 1.8.x. A modern 2026 request carries `_meta` and must flow into the
|
|
250
|
+
// official v2 stdio classifier after the startup queue is ready.
|
|
251
|
+
if (params === undefined) return true;
|
|
252
|
+
return typeof params === 'object'
|
|
253
|
+
&& params !== null
|
|
254
|
+
&& !Array.isArray(params)
|
|
255
|
+
&& !Object.prototype.hasOwnProperty.call(params, '_meta');
|
|
217
256
|
}
|
|
218
257
|
|
|
219
258
|
private isValidRequestId(id: unknown): id is string | number | null {
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
* We provide four profiles:
|
|
9
9
|
* - "micro" (stdio default): Agent-ready project context + bounded recovery/media controls — 9 tools.
|
|
10
10
|
* Suitable for normal MCP clients where every tool schema costs context tokens.
|
|
11
|
-
* - "lite": Core memory CRUD, sessions, reasoning, retention, backup —
|
|
11
|
+
* - "lite": Core memory CRUD, sessions, reasoning, retention, backup — 20 tools.
|
|
12
12
|
* Suitable for solo users who want the full memory surface without team tools.
|
|
13
|
-
* - "team" (HTTP default): lite + orchestration coordination tools, dashboard, and Knowledge Workspace —
|
|
13
|
+
* - "team" (HTTP default): lite + orchestration coordination tools, dashboard, and Knowledge Workspace — 28 tools.
|
|
14
14
|
* Suitable when an operator explicitly wants task/message/lock surfaces.
|
|
15
15
|
* - "full": Everything, including niche / advanced tools (consolidate, dedup,
|
|
16
16
|
* formation metrics, skills, rules/workspace sync, KG-official, image ingest).
|
|
@@ -142,11 +142,12 @@ export function resolveToolProfile(opts: ResolveToolProfileOpts): ToolProfile {
|
|
|
142
142
|
* Human-readable description for logs / diagnostics.
|
|
143
143
|
*/
|
|
144
144
|
export function describeProfile(profile: ToolProfile): string {
|
|
145
|
+
const count = countToolsInProfile(profile);
|
|
145
146
|
switch (profile) {
|
|
146
|
-
case 'micro': return
|
|
147
|
-
case 'lite': return
|
|
148
|
-
case 'team': return
|
|
149
|
-
case 'full': return
|
|
147
|
+
case 'micro': return `micro (agent-ready context + bounded recovery/media, ${count} tools)`;
|
|
148
|
+
case 'lite': return `lite (core memory + sessions, ${count} tools)`;
|
|
149
|
+
case 'team': return `team (lite + coordination tools + dashboard + knowledge workspace, ${count} tools)`;
|
|
150
|
+
case 'full': return `full (all tools including advanced / KG-compat, ${count} tools)`;
|
|
150
151
|
}
|
|
151
152
|
}
|
|
152
153
|
|
package/src/server.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*
|
|
13
13
|
* Extensibility:
|
|
14
14
|
* - New tools can be registered via server.registerTool()
|
|
15
|
-
* - Rules sync tools
|
|
15
|
+
* - Rules and workspace sync tools are available only in the explicit full profile
|
|
16
16
|
* - New agent format adapters plug in without changing this file
|
|
17
17
|
*/
|
|
18
18
|
|
package/src/store/orama-store.ts
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Full-text + vector + hybrid search engine backed by Orama.
|
|
5
5
|
* Source: @orama/orama (10.1K stars, <2KB, pure JS, zero deps)
|
|
6
6
|
*
|
|
7
|
-
* Schema designed to
|
|
8
|
-
*
|
|
7
|
+
* Schema designed to index Observations with all searchable fields.
|
|
8
|
+
* SQLite remains the durable source of truth; this index is rebuilt as needed.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { create, insert, insertMultiple, search, remove, update, count, getByID, type AnyOrama } from '@orama/orama';
|
package/src/types.ts
CHANGED
|
@@ -670,7 +670,7 @@ export interface MemoryRef {
|
|
|
670
670
|
/** MCP config format adapter interface */
|
|
671
671
|
export interface MCPConfigAdapter {
|
|
672
672
|
/** Setup-only adapters may support a host that does not participate in workspace sync. */
|
|
673
|
-
readonly source: AgentTarget | 'codebuddy' | 'dsh';
|
|
673
|
+
readonly source: AgentTarget | 'codebuddy' | 'dsh' | 'workbuddy';
|
|
674
674
|
/** Parse MCP server entries from a config file */
|
|
675
675
|
parse(content: string): MCPServerEntry[];
|
|
676
676
|
/** Generate config file content from MCP server entries */
|
package/src/wiki/types.ts
CHANGED
|
@@ -21,8 +21,8 @@ export interface KnowledgeSection {
|
|
|
21
21
|
|
|
22
22
|
export interface ProjectKnowledgeOverview {
|
|
23
23
|
/**
|
|
24
|
-
* A read-only projection of durable memories.
|
|
25
|
-
*
|
|
24
|
+
* A read-only projection of durable memories. The maintained, review-gated
|
|
25
|
+
* Knowledge Workspace is a separate surface backed by source claims.
|
|
26
26
|
*/
|
|
27
27
|
title: 'Memory Overview';
|
|
28
28
|
subtitle: 'Generated from durable project memory';
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { MCPConfigAdapter, MCPServerEntry } from '../../types.js';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* WorkBuddy MCP config adapter.
|
|
7
|
+
*
|
|
8
|
+
* WorkBuddy stores its MCP server list in a JSON file following the standard
|
|
9
|
+
* MCP client convention:
|
|
10
|
+
*
|
|
11
|
+
* { "mcpServers": { [name]: { command, args, env?, url?, headers? } } }
|
|
12
|
+
*
|
|
13
|
+
* Per the official WorkBuddy MCP guide, two scopes are supported:
|
|
14
|
+
* - user-level: ~/.workbuddy/mcp.json
|
|
15
|
+
* - project-level: <project>/.workbuddy/mcp.json
|
|
16
|
+
*
|
|
17
|
+
* getConfigPath returns the project-level path when a projectRoot is supplied,
|
|
18
|
+
* otherwise the user-level path — matching the existing adapter convention.
|
|
19
|
+
*/
|
|
20
|
+
export class WorkbuddyMCPAdapter implements MCPConfigAdapter {
|
|
21
|
+
readonly source = 'workbuddy' as const;
|
|
22
|
+
|
|
23
|
+
parse(content: string): MCPServerEntry[] {
|
|
24
|
+
try {
|
|
25
|
+
const config = JSON.parse(content);
|
|
26
|
+
const servers = config.mcpServers ?? {};
|
|
27
|
+
return Object.entries(servers).map(([name, entry]: [string, any]) => ({
|
|
28
|
+
name,
|
|
29
|
+
command: entry.command ?? '',
|
|
30
|
+
args: entry.args ?? [],
|
|
31
|
+
...(entry.env && Object.keys(entry.env).length > 0 ? { env: entry.env } : {}),
|
|
32
|
+
...(entry.url ? { url: entry.url } : {}),
|
|
33
|
+
...(entry.headers && Object.keys(entry.headers).length > 0 ? { headers: entry.headers } : {}),
|
|
34
|
+
...(entry.disabled === true ? { disabled: true } : {}),
|
|
35
|
+
}));
|
|
36
|
+
} catch {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
generate(servers: MCPServerEntry[]): string {
|
|
42
|
+
const mcpServers: Record<string, any> = {};
|
|
43
|
+
for (const s of servers) {
|
|
44
|
+
const entry: Record<string, any> = {};
|
|
45
|
+
if (s.url) {
|
|
46
|
+
entry.url = s.url;
|
|
47
|
+
if (s.headers && Object.keys(s.headers).length > 0) {
|
|
48
|
+
entry.headers = s.headers;
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
entry.command = s.command;
|
|
52
|
+
entry.args = s.args;
|
|
53
|
+
}
|
|
54
|
+
if (s.env && Object.keys(s.env).length > 0) {
|
|
55
|
+
entry.env = s.env;
|
|
56
|
+
}
|
|
57
|
+
if (s.disabled === true) {
|
|
58
|
+
entry.disabled = true;
|
|
59
|
+
}
|
|
60
|
+
mcpServers[s.name] = entry;
|
|
61
|
+
}
|
|
62
|
+
return JSON.stringify({ mcpServers }, null, 2) + '\n';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
getConfigPath(projectRoot?: string): string {
|
|
66
|
+
if (projectRoot) {
|
|
67
|
+
return join(projectRoot, '.workbuddy', 'mcp.json');
|
|
68
|
+
}
|
|
69
|
+
return join(homedir(), '.workbuddy', 'mcp.json');
|
|
70
|
+
}
|
|
71
|
+
}
|