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.
Files changed (88) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/CLAUDE.md +3 -0
  3. package/README.md +8 -6
  4. package/README.zh-CN.md +5 -3
  5. package/assets/star-history-dark.svg +5 -5
  6. package/assets/star-history-light.svg +5 -5
  7. package/assets/star-history.json +35 -5
  8. package/dist/cli/index.js +1848 -754
  9. package/dist/dashboard/static/app.js +29 -885
  10. package/dist/dashboard/static/index.html +1 -5
  11. package/dist/dashboard/static/style.css +36 -503
  12. package/dist/index.d.ts +4 -4
  13. package/dist/index.js +286 -79
  14. package/dist/memcode/index.js +28035 -169
  15. package/dist/memcode-runtime/CHANGELOG.md +52 -0
  16. package/dist/sdk.js +103 -21
  17. package/dist/types.d.ts +1 -1
  18. package/docs/1.8.0-RELEASE-CANDIDATE-SPEC.md +22 -16
  19. package/docs/AGENT_OPERATOR_PLAYBOOK.md +2 -2
  20. package/docs/API_REFERENCE.md +10 -8
  21. package/docs/DASHBOARD.md +23 -0
  22. package/docs/DEVELOPMENT.md +2 -2
  23. package/docs/DOCKER.md +6 -3
  24. package/docs/INTEGRATIONS.md +2 -1
  25. package/docs/MODULES.md +46 -20
  26. package/docs/PERFORMANCE.md +1 -1
  27. package/docs/README.md +8 -7
  28. package/docs/SETUP.md +4 -3
  29. package/package.json +11 -11
  30. package/plugins/antigravity/memorix/plugin.json +1 -1
  31. package/plugins/antigravity/memorix/rules/memorix.md +5 -0
  32. package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
  33. package/plugins/claude/memorix/skills/memorix-memory/SKILL.md +3 -0
  34. package/plugins/claude/memorix/skills/memorix-mini-skills/SKILL.md +2 -0
  35. package/plugins/claude/memorix/skills/memorix-orchestrate/SKILL.md +2 -0
  36. package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
  37. package/plugins/codebuddy/memorix/skills/memorix-memory/SKILL.md +3 -0
  38. package/plugins/codebuddy/memorix/skills/memorix-mini-skills/SKILL.md +2 -0
  39. package/plugins/codebuddy/memorix/skills/memorix-orchestrate/SKILL.md +2 -0
  40. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  41. package/plugins/codex/memorix/skills/memorix-memory/SKILL.md +3 -0
  42. package/plugins/codex/memorix/skills/memorix-mini-skills/SKILL.md +2 -0
  43. package/plugins/codex/memorix/skills/memorix-orchestrate/SKILL.md +2 -0
  44. package/plugins/copilot/memorix/plugin.json +1 -1
  45. package/plugins/copilot/memorix/skills/memorix-memory/SKILL.md +3 -0
  46. package/plugins/copilot/memorix/skills/memorix-mini-skills/SKILL.md +2 -0
  47. package/plugins/copilot/memorix/skills/memorix-orchestrate/SKILL.md +2 -0
  48. package/plugins/cursor/memorix/skills/memorix-memory/SKILL.md +3 -0
  49. package/plugins/cursor/memorix/skills/memorix-mini-skills/SKILL.md +2 -0
  50. package/plugins/cursor/memorix/skills/memorix-orchestrate/SKILL.md +2 -0
  51. package/plugins/gemini/memorix/GEMINI.md +5 -0
  52. package/plugins/gemini/memorix/gemini-extension.json +1 -1
  53. package/plugins/hermes/memorix/plugin.yaml +7 -1
  54. package/plugins/omp/memorix/package.json +1 -1
  55. package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
  56. package/plugins/pi/memorix/package.json +1 -1
  57. package/plugins/pi/memorix/skills/memorix-memory/SKILL.md +3 -0
  58. package/plugins/pi/memorix/skills/memorix-mini-skills/SKILL.md +2 -0
  59. package/plugins/pi/memorix/skills/memorix-orchestrate/SKILL.md +2 -0
  60. package/server.json +2 -2
  61. package/src/cli/command-guide.ts +52 -1
  62. package/src/cli/commands/agent-integrations.ts +1 -0
  63. package/src/cli/commands/background.ts +166 -6
  64. package/src/cli/commands/hooks-install.ts +9 -2
  65. package/src/cli/commands/hooks-preview.ts +5 -0
  66. package/src/cli/commands/integrate.ts +2 -0
  67. package/src/cli/commands/serve-http.ts +73 -80
  68. package/src/cli/commands/serve.ts +95 -93
  69. package/src/cli/commands/setup.ts +11 -1
  70. package/src/cli/commands/uninstall.ts +24 -2
  71. package/src/cli/index.ts +1 -1
  72. package/src/codegraph/task-lens.ts +72 -7
  73. package/src/dashboard/static/index.html +1 -5
  74. package/src/dashboard/static/style.css +36 -503
  75. package/src/hooks/installers/index.ts +58 -0
  76. package/src/hooks/official-skills.ts +13 -6
  77. package/src/hooks/types.ts +2 -0
  78. package/src/integrations/registry.ts +9 -0
  79. package/src/memory/graph.ts +2 -2
  80. package/src/server/mcp-diagnostics.ts +9 -7
  81. package/src/server/modern-mcp-bridge.ts +108 -0
  82. package/src/server/stdio-startup-gate.ts +41 -2
  83. package/src/server/tool-profile.ts +7 -6
  84. package/src/server.ts +1 -1
  85. package/src/store/orama-store.ts +2 -2
  86. package/src/types.ts +1 -1
  87. package/src/wiki/types.ts +2 -2
  88. 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.',
@@ -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',
@@ -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 per-project JSONL files (official uses single file)
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: 'discovery-only';
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
- /** The pinned SDK is stateful; do not present a fake durable task loop. */
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: 'discovery-only',
38
- statelessRequests: 'compatibility-only',
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: 'unsupported',
45
- listCache: 'unsupported',
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
- this.input.write(chunk);
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
- return params === undefined || (typeof params === 'object' && params !== null && !Array.isArray(params));
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 — 18 tools.
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 — 26 tools.
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 'micro (agent-ready context + bounded recovery/media, ~9 tools)';
147
- case 'lite': return 'lite (core memory + sessions, ~18 tools)';
148
- case 'team': return 'team (lite + coordination tools + dashboard + knowledge workspace, ~26 tools)';
149
- case 'full': return 'full (all tools including advanced / KG-compat)';
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 will be added in P2
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
 
@@ -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 store Observations with all searchable fields.
8
- * Vector search (embeddings) will be added in P1 phase.
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. This is intentionally not
25
- * called a maintained wiki until the 1.2 Knowledge Workspace exists.
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
+ }