@dobbyai/mcp-external 1.0.4 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -14
- package/dist/__tests__/agent-mail-tools.test.d.ts +8 -0
- package/dist/__tests__/agent-mail-tools.test.d.ts.map +1 -0
- package/dist/__tests__/agent-mail-tools.test.js +255 -0
- package/dist/__tests__/agent-mail-tools.test.js.map +1 -0
- package/dist/__tests__/annotations.test.d.ts +8 -0
- package/dist/__tests__/annotations.test.d.ts.map +1 -0
- package/dist/__tests__/annotations.test.js +108 -0
- package/dist/__tests__/annotations.test.js.map +1 -0
- package/dist/__tests__/auth.test.d.ts +7 -0
- package/dist/__tests__/auth.test.d.ts.map +1 -0
- package/dist/__tests__/auth.test.js +161 -0
- package/dist/__tests__/auth.test.js.map +1 -0
- package/dist/__tests__/doctor.test.d.ts +16 -0
- package/dist/__tests__/doctor.test.d.ts.map +1 -0
- package/dist/__tests__/doctor.test.js +258 -0
- package/dist/__tests__/doctor.test.js.map +1 -0
- package/dist/__tests__/external-agents-tools.test.d.ts +11 -0
- package/dist/__tests__/external-agents-tools.test.d.ts.map +1 -0
- package/dist/__tests__/external-agents-tools.test.js +619 -0
- package/dist/__tests__/external-agents-tools.test.js.map +1 -0
- package/dist/__tests__/gateway-bearer.test.d.ts +12 -0
- package/dist/__tests__/gateway-bearer.test.d.ts.map +1 -0
- package/dist/__tests__/gateway-bearer.test.js +112 -0
- package/dist/__tests__/gateway-bearer.test.js.map +1 -0
- package/dist/__tests__/gateway-key-resolver.test.d.ts +10 -0
- package/dist/__tests__/gateway-key-resolver.test.d.ts.map +1 -0
- package/dist/__tests__/gateway-key-resolver.test.js +125 -0
- package/dist/__tests__/gateway-key-resolver.test.js.map +1 -0
- package/dist/__tests__/http-concurrency.test.d.ts +20 -0
- package/dist/__tests__/http-concurrency.test.d.ts.map +1 -0
- package/dist/__tests__/http-concurrency.test.js +254 -0
- package/dist/__tests__/http-concurrency.test.js.map +1 -0
- package/dist/__tests__/integration/protocol.test.d.ts +8 -0
- package/dist/__tests__/integration/protocol.test.d.ts.map +1 -0
- package/dist/__tests__/integration/protocol.test.js +110 -0
- package/dist/__tests__/integration/protocol.test.js.map +1 -0
- package/dist/__tests__/mcp-integrations.test.d.ts +8 -0
- package/dist/__tests__/mcp-integrations.test.d.ts.map +1 -0
- package/dist/__tests__/mcp-integrations.test.js +365 -0
- package/dist/__tests__/mcp-integrations.test.js.map +1 -0
- package/dist/__tests__/memory-graph-tools.test.d.ts +8 -0
- package/dist/__tests__/memory-graph-tools.test.d.ts.map +1 -0
- package/dist/__tests__/memory-graph-tools.test.js +254 -0
- package/dist/__tests__/memory-graph-tools.test.js.map +1 -0
- package/dist/__tests__/registry-dispatch.test.d.ts +11 -0
- package/dist/__tests__/registry-dispatch.test.d.ts.map +1 -0
- package/dist/__tests__/registry-dispatch.test.js +30 -0
- package/dist/__tests__/registry-dispatch.test.js.map +1 -0
- package/dist/__tests__/registry-listing-parity.test.d.ts +2 -0
- package/dist/__tests__/registry-listing-parity.test.d.ts.map +1 -0
- package/dist/__tests__/registry-listing-parity.test.js +89 -0
- package/dist/__tests__/registry-listing-parity.test.js.map +1 -0
- package/dist/__tests__/role-cap.test.d.ts +2 -0
- package/dist/__tests__/role-cap.test.d.ts.map +1 -0
- package/dist/__tests__/role-cap.test.js +113 -0
- package/dist/__tests__/role-cap.test.js.map +1 -0
- package/dist/__tests__/schedule-tools.test.d.ts +8 -0
- package/dist/__tests__/schedule-tools.test.d.ts.map +1 -0
- package/dist/__tests__/schedule-tools.test.js +285 -0
- package/dist/__tests__/schedule-tools.test.js.map +1 -0
- package/dist/__tests__/server-gateway-key.test.d.ts +18 -0
- package/dist/__tests__/server-gateway-key.test.d.ts.map +1 -0
- package/dist/__tests__/server-gateway-key.test.js +148 -0
- package/dist/__tests__/server-gateway-key.test.js.map +1 -0
- package/dist/__tests__/server-user-scoped.test.d.ts +34 -0
- package/dist/__tests__/server-user-scoped.test.d.ts.map +1 -0
- package/dist/__tests__/server-user-scoped.test.js +577 -0
- package/dist/__tests__/server-user-scoped.test.js.map +1 -0
- package/dist/__tests__/task-id-pattern.test.d.ts +12 -0
- package/dist/__tests__/task-id-pattern.test.d.ts.map +1 -0
- package/dist/__tests__/task-id-pattern.test.js +43 -0
- package/dist/__tests__/task-id-pattern.test.js.map +1 -0
- package/dist/__tests__/tiers.test.d.ts +7 -0
- package/dist/__tests__/tiers.test.d.ts.map +1 -0
- package/dist/__tests__/tiers.test.js +199 -0
- package/dist/__tests__/tiers.test.js.map +1 -0
- package/dist/__tests__/tools/hosted-agents.test.d.ts +9 -0
- package/dist/__tests__/tools/hosted-agents.test.d.ts.map +1 -0
- package/dist/__tests__/tools/hosted-agents.test.js +301 -0
- package/dist/__tests__/tools/hosted-agents.test.js.map +1 -0
- package/dist/__tests__/tools/llm-providers.test.d.ts +10 -0
- package/dist/__tests__/tools/llm-providers.test.d.ts.map +1 -0
- package/dist/__tests__/tools/llm-providers.test.js +105 -0
- package/dist/__tests__/tools/llm-providers.test.js.map +1 -0
- package/dist/__tests__/tools/services.test.js +139 -98
- package/dist/__tests__/tools/services.test.js.map +1 -1
- package/dist/__tests__/tools.test.d.ts +7 -0
- package/dist/__tests__/tools.test.d.ts.map +1 -0
- package/dist/__tests__/tools.test.js +152 -0
- package/dist/__tests__/tools.test.js.map +1 -0
- package/dist/__tests__/transport.test.d.ts +7 -0
- package/dist/__tests__/transport.test.d.ts.map +1 -0
- package/dist/__tests__/transport.test.js +397 -0
- package/dist/__tests__/transport.test.js.map +1 -0
- package/dist/__tests__/validate-credentials.test.d.ts +9 -0
- package/dist/__tests__/validate-credentials.test.d.ts.map +1 -0
- package/dist/__tests__/validate-credentials.test.js +172 -0
- package/dist/__tests__/validate-credentials.test.js.map +1 -0
- package/dist/__tests__/web-eval-tools.test.d.ts +8 -0
- package/dist/__tests__/web-eval-tools.test.d.ts.map +1 -0
- package/dist/__tests__/web-eval-tools.test.js +241 -0
- package/dist/__tests__/web-eval-tools.test.js.map +1 -0
- package/dist/__tests__/whoami.test.d.ts +11 -0
- package/dist/__tests__/whoami.test.d.ts.map +1 -0
- package/dist/__tests__/whoami.test.js +194 -0
- package/dist/__tests__/whoami.test.js.map +1 -0
- package/dist/__tests__/workflow-tools.test.d.ts +8 -0
- package/dist/__tests__/workflow-tools.test.d.ts.map +1 -0
- package/dist/__tests__/workflow-tools.test.js +261 -0
- package/dist/__tests__/workflow-tools.test.js.map +1 -0
- package/dist/__tests__/workloads.test.d.ts +9 -0
- package/dist/__tests__/workloads.test.d.ts.map +1 -0
- package/dist/__tests__/workloads.test.js +169 -0
- package/dist/__tests__/workloads.test.js.map +1 -0
- package/dist/auth/oauth-provider.d.ts +34 -0
- package/dist/auth/oauth-provider.d.ts.map +1 -0
- package/dist/auth/oauth-provider.js +75 -0
- package/dist/auth/oauth-provider.js.map +1 -0
- package/dist/auth/token-verifier.d.ts +45 -0
- package/dist/auth/token-verifier.d.ts.map +1 -0
- package/dist/auth/token-verifier.js +160 -0
- package/dist/auth/token-verifier.js.map +1 -0
- package/dist/connectors/claude-desktop.d.ts.map +1 -1
- package/dist/connectors/claude-desktop.js +3 -2
- package/dist/connectors/claude-desktop.js.map +1 -1
- package/dist/connectors/cursor.d.ts.map +1 -1
- package/dist/connectors/cursor.js +3 -2
- package/dist/connectors/cursor.js.map +1 -1
- package/dist/connectors/setup.d.ts.map +1 -1
- package/dist/connectors/setup.js +2 -1
- package/dist/connectors/setup.js.map +1 -1
- package/dist/connectors/vscode.d.ts.map +1 -1
- package/dist/connectors/vscode.js +3 -2
- package/dist/connectors/vscode.js.map +1 -1
- package/dist/connectors/windsurf.d.ts.map +1 -1
- package/dist/connectors/windsurf.js +3 -2
- package/dist/connectors/windsurf.js.map +1 -1
- package/dist/doctor.d.ts +34 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +134 -0
- package/dist/doctor.js.map +1 -0
- package/dist/http-server.d.ts +56 -0
- package/dist/http-server.d.ts.map +1 -0
- package/dist/http-server.js +455 -0
- package/dist/http-server.js.map +1 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +96 -171
- package/dist/index.js.map +1 -1
- package/dist/lib/consts.d.ts +21 -0
- package/dist/lib/consts.d.ts.map +1 -0
- package/dist/lib/consts.js +30 -0
- package/dist/lib/consts.js.map +1 -0
- package/dist/lib/dobby-client.d.ts +60 -3
- package/dist/lib/dobby-client.d.ts.map +1 -1
- package/dist/lib/dobby-client.js +145 -44
- package/dist/lib/dobby-client.js.map +1 -1
- package/dist/lib/gateway-key-resolver.d.ts +38 -0
- package/dist/lib/gateway-key-resolver.d.ts.map +1 -0
- package/dist/lib/gateway-key-resolver.js +59 -0
- package/dist/lib/gateway-key-resolver.js.map +1 -0
- package/dist/lib/log.d.ts +25 -0
- package/dist/lib/log.d.ts.map +1 -0
- package/dist/lib/log.js +36 -0
- package/dist/lib/log.js.map +1 -0
- package/dist/server.d.ts +175 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +1017 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/agent-mail.d.ts +112 -0
- package/dist/tools/agent-mail.d.ts.map +1 -0
- package/dist/tools/agent-mail.js +118 -0
- package/dist/tools/agent-mail.js.map +1 -0
- package/dist/tools/agent-versions.d.ts +93 -0
- package/dist/tools/agent-versions.d.ts.map +1 -0
- package/dist/tools/agent-versions.js +99 -0
- package/dist/tools/agent-versions.js.map +1 -0
- package/dist/tools/approvals.d.ts +24 -34
- package/dist/tools/approvals.d.ts.map +1 -1
- package/dist/tools/approvals.js +24 -81
- package/dist/tools/approvals.js.map +1 -1
- package/dist/tools/claude-code-sync.d.ts +40 -0
- package/dist/tools/claude-code-sync.d.ts.map +1 -0
- package/dist/tools/claude-code-sync.js +52 -0
- package/dist/tools/claude-code-sync.js.map +1 -0
- package/dist/tools/control-plane.d.ts +118 -0
- package/dist/tools/control-plane.d.ts.map +1 -0
- package/dist/tools/control-plane.js +135 -0
- package/dist/tools/control-plane.js.map +1 -0
- package/dist/tools/crew-builder.d.ts +24 -66
- package/dist/tools/crew-builder.d.ts.map +1 -1
- package/dist/tools/crew-builder.js +24 -185
- package/dist/tools/crew-builder.js.map +1 -1
- package/dist/tools/crewai.d.ts +24 -63
- package/dist/tools/crewai.d.ts.map +1 -1
- package/dist/tools/crewai.js +24 -145
- package/dist/tools/crewai.js.map +1 -1
- package/dist/tools/exa.d.ts +126 -0
- package/dist/tools/exa.d.ts.map +1 -0
- package/dist/tools/exa.js +125 -0
- package/dist/tools/exa.js.map +1 -0
- package/dist/tools/external-agents.d.ts +440 -0
- package/dist/tools/external-agents.d.ts.map +1 -0
- package/dist/tools/external-agents.js +386 -0
- package/dist/tools/external-agents.js.map +1 -0
- package/dist/tools/github-mcp.d.ts +228 -0
- package/dist/tools/github-mcp.d.ts.map +1 -0
- package/dist/tools/github-mcp.js +235 -0
- package/dist/tools/github-mcp.js.map +1 -0
- package/dist/tools/governance.d.ts +273 -0
- package/dist/tools/governance.d.ts.map +1 -0
- package/dist/tools/governance.js +286 -0
- package/dist/tools/governance.js.map +1 -0
- package/dist/tools/hosted-agents.d.ts +216 -0
- package/dist/tools/hosted-agents.d.ts.map +1 -0
- package/dist/tools/hosted-agents.js +214 -0
- package/dist/tools/hosted-agents.js.map +1 -0
- package/dist/tools/index.d.ts +6335 -191
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +441 -172
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/jira.d.ts +60 -176
- package/dist/tools/jira.d.ts.map +1 -1
- package/dist/tools/jira.js +60 -365
- package/dist/tools/jira.js.map +1 -1
- package/dist/tools/llm-providers.d.ts +50 -0
- package/dist/tools/llm-providers.d.ts.map +1 -0
- package/dist/tools/llm-providers.js +41 -0
- package/dist/tools/llm-providers.js.map +1 -0
- package/dist/tools/mcp-metrics.d.ts +47 -0
- package/dist/tools/mcp-metrics.d.ts.map +1 -0
- package/dist/tools/mcp-metrics.js +53 -0
- package/dist/tools/mcp-metrics.js.map +1 -0
- package/dist/tools/mcp-tools.d.ts +12 -29
- package/dist/tools/mcp-tools.d.ts.map +1 -1
- package/dist/tools/mcp-tools.js +12 -131
- package/dist/tools/mcp-tools.js.map +1 -1
- package/dist/tools/mem0.d.ts +127 -0
- package/dist/tools/mem0.d.ts.map +1 -0
- package/dist/tools/mem0.js +155 -0
- package/dist/tools/mem0.js.map +1 -0
- package/dist/tools/memory-graph.d.ts +151 -0
- package/dist/tools/memory-graph.d.ts.map +1 -0
- package/dist/tools/memory-graph.js +159 -0
- package/dist/tools/memory-graph.js.map +1 -0
- package/dist/tools/memory-stores.d.ts +141 -0
- package/dist/tools/memory-stores.d.ts.map +1 -0
- package/dist/tools/memory-stores.js +147 -0
- package/dist/tools/memory-stores.js.map +1 -0
- package/dist/tools/messages.d.ts +12 -20
- package/dist/tools/messages.d.ts.map +1 -1
- package/dist/tools/messages.js +12 -49
- package/dist/tools/messages.js.map +1 -1
- package/dist/tools/moltbook.d.ts +328 -0
- package/dist/tools/moltbook.d.ts.map +1 -0
- package/dist/tools/moltbook.js +334 -0
- package/dist/tools/moltbook.js.map +1 -0
- package/dist/tools/monitoring-attribution.d.ts +71 -0
- package/dist/tools/monitoring-attribution.d.ts.map +1 -0
- package/dist/tools/monitoring-attribution.js +74 -0
- package/dist/tools/monitoring-attribution.js.map +1 -0
- package/dist/tools/ops.d.ts +139 -0
- package/dist/tools/ops.d.ts.map +1 -0
- package/dist/tools/ops.js +151 -0
- package/dist/tools/ops.js.map +1 -0
- package/dist/tools/orchestrations.d.ts +109 -0
- package/dist/tools/orchestrations.d.ts.map +1 -0
- package/dist/tools/orchestrations.js +115 -0
- package/dist/tools/orchestrations.js.map +1 -0
- package/dist/tools/outcomes.d.ts +138 -0
- package/dist/tools/outcomes.d.ts.map +1 -0
- package/dist/tools/outcomes.js +136 -0
- package/dist/tools/outcomes.js.map +1 -0
- package/dist/tools/schedules.d.ts +149 -0
- package/dist/tools/schedules.d.ts.map +1 -0
- package/dist/tools/schedules.js +155 -0
- package/dist/tools/schedules.js.map +1 -0
- package/dist/tools/services.d.ts +6 -16
- package/dist/tools/services.d.ts.map +1 -1
- package/dist/tools/services.js +6 -135
- package/dist/tools/services.js.map +1 -1
- package/dist/tools/sessions.d.ts +124 -0
- package/dist/tools/sessions.d.ts.map +1 -0
- package/dist/tools/sessions.js +130 -0
- package/dist/tools/sessions.js.map +1 -0
- package/dist/tools/setup-status.d.ts +29 -0
- package/dist/tools/setup-status.d.ts.map +1 -0
- package/dist/tools/setup-status.js +35 -0
- package/dist/tools/setup-status.js.map +1 -0
- package/dist/tools/tasks.d.ts +44 -56
- package/dist/tools/tasks.d.ts.map +1 -1
- package/dist/tools/tasks.js +48 -212
- package/dist/tools/tasks.js.map +1 -1
- package/dist/tools/tiers.d.ts +55 -0
- package/dist/tools/tiers.d.ts.map +1 -0
- package/dist/tools/tiers.js +239 -0
- package/dist/tools/tiers.js.map +1 -0
- package/dist/tools/unified-agents.d.ts +43 -0
- package/dist/tools/unified-agents.d.ts.map +1 -0
- package/dist/tools/unified-agents.js +46 -0
- package/dist/tools/unified-agents.js.map +1 -0
- package/dist/tools/web-eval.d.ts +129 -0
- package/dist/tools/web-eval.d.ts.map +1 -0
- package/dist/tools/web-eval.js +136 -0
- package/dist/tools/web-eval.js.map +1 -0
- package/dist/tools/workflow.d.ts +105 -0
- package/dist/tools/workflow.d.ts.map +1 -0
- package/dist/tools/workflow.js +111 -0
- package/dist/tools/workflow.js.map +1 -0
- package/dist/tools/workloads.d.ts +81 -0
- package/dist/tools/workloads.d.ts.map +1 -0
- package/dist/tools/workloads.js +81 -0
- package/dist/tools/workloads.js.map +1 -0
- package/package.json +13 -7
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Graph MCP Tools Tests — Phase 4
|
|
3
|
+
*
|
|
4
|
+
* Tests for graph-based memory storage, semantic query,
|
|
5
|
+
* timeline, and context aggregation.
|
|
6
|
+
*/
|
|
7
|
+
import { describe, it, expect, vi, beforeEach, afterAll } from 'vitest';
|
|
8
|
+
import { createRegistry, toMcpResult } from '@dobbyai/capability-core';
|
|
9
|
+
// Mock global fetch
|
|
10
|
+
const mockFetch = vi.fn();
|
|
11
|
+
vi.stubGlobal('fetch', mockFetch);
|
|
12
|
+
// Clear env to force local-only mode
|
|
13
|
+
const originalEnv = { ...process.env };
|
|
14
|
+
// ADR-019: the legacy handle* functions are gone — dispatch goes through the
|
|
15
|
+
// capability registry (handlers are verbatim copies; MCP output byte-identical).
|
|
16
|
+
const registry = createRegistry();
|
|
17
|
+
const callCap = async (id, client, args) => toMcpResult(await registry.get(id).handler({ client: client }, args));
|
|
18
|
+
// ============================================
|
|
19
|
+
// Store Memory
|
|
20
|
+
// ============================================
|
|
21
|
+
describe('MemoryGraph: Store', () => {
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
vi.resetAllMocks();
|
|
24
|
+
// Ensure no MEM0_API_KEY for local-only tests
|
|
25
|
+
delete process.env.MEM0_API_KEY;
|
|
26
|
+
});
|
|
27
|
+
afterAll(() => {
|
|
28
|
+
process.env = originalEnv;
|
|
29
|
+
});
|
|
30
|
+
it('stores memory locally when Mem0 is not configured', async () => {
|
|
31
|
+
const result = await callCap('memory_graph_store', {}, {
|
|
32
|
+
content: 'Decided to use BigQuery append-only pattern for all tables',
|
|
33
|
+
category: 'project_decisions',
|
|
34
|
+
project: 'dobby',
|
|
35
|
+
tags: ['database', 'architecture'],
|
|
36
|
+
});
|
|
37
|
+
const data = JSON.parse(result.content[0].text);
|
|
38
|
+
expect(data.status).toBe('stored');
|
|
39
|
+
expect(data.memory_id).toMatch(/^mem_/);
|
|
40
|
+
expect(data.category).toBe('project_decisions');
|
|
41
|
+
expect(data.mem0_synced).toBe(false);
|
|
42
|
+
expect(data.graph_size).toBeGreaterThanOrEqual(1);
|
|
43
|
+
});
|
|
44
|
+
it('stores memory with relationships', async () => {
|
|
45
|
+
const result = await callCap('memory_graph_store', {}, {
|
|
46
|
+
content: 'Switched from PostgreSQL to BigQuery',
|
|
47
|
+
category: 'project_decisions',
|
|
48
|
+
related_to: ['mem_previous_123'],
|
|
49
|
+
relationship_type: 'supersedes',
|
|
50
|
+
});
|
|
51
|
+
const data = JSON.parse(result.content[0].text);
|
|
52
|
+
expect(data.status).toBe('stored');
|
|
53
|
+
expect(data.relationships).toHaveLength(1);
|
|
54
|
+
expect(data.relationships[0].type).toBe('supersedes');
|
|
55
|
+
expect(data.relationships[0].target_id).toBe('mem_previous_123');
|
|
56
|
+
});
|
|
57
|
+
it('defaults category to project_decisions', async () => {
|
|
58
|
+
const result = await callCap('memory_graph_store', {}, {
|
|
59
|
+
content: 'Some important decision',
|
|
60
|
+
});
|
|
61
|
+
const data = JSON.parse(result.content[0].text);
|
|
62
|
+
expect(data.category).toBe('project_decisions');
|
|
63
|
+
});
|
|
64
|
+
it('defaults relationship type to related', async () => {
|
|
65
|
+
const result = await callCap('memory_graph_store', {}, {
|
|
66
|
+
content: 'Related context',
|
|
67
|
+
related_to: ['other_mem'],
|
|
68
|
+
});
|
|
69
|
+
const data = JSON.parse(result.content[0].text);
|
|
70
|
+
expect(data.relationships[0].type).toBe('related');
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
// ============================================
|
|
74
|
+
// Query Memory
|
|
75
|
+
// ============================================
|
|
76
|
+
describe('MemoryGraph: Query', () => {
|
|
77
|
+
beforeEach(() => {
|
|
78
|
+
vi.resetAllMocks();
|
|
79
|
+
delete process.env.MEM0_API_KEY;
|
|
80
|
+
});
|
|
81
|
+
it('returns empty results when graph is empty', async () => {
|
|
82
|
+
// Previous tests may have populated the shared graph
|
|
83
|
+
const result = await callCap('memory_graph_query', {}, {
|
|
84
|
+
query: 'something that definitely does not exist xyz123',
|
|
85
|
+
});
|
|
86
|
+
const data = JSON.parse(result.content[0].text);
|
|
87
|
+
// Either empty results or non-matching
|
|
88
|
+
expect(data.query).toBe('something that definitely does not exist xyz123');
|
|
89
|
+
});
|
|
90
|
+
it('searches local graph cache by keyword', async () => {
|
|
91
|
+
// Store a memory first
|
|
92
|
+
await callCap('memory_graph_store', {}, {
|
|
93
|
+
content: 'Authentication uses JWT tokens with 30-day expiry',
|
|
94
|
+
category: 'conventions',
|
|
95
|
+
project: 'dobby',
|
|
96
|
+
tags: ['auth', 'jwt'],
|
|
97
|
+
});
|
|
98
|
+
// Query for it
|
|
99
|
+
const result = await callCap('memory_graph_query', {}, {
|
|
100
|
+
query: 'authentication JWT',
|
|
101
|
+
project: 'dobby',
|
|
102
|
+
});
|
|
103
|
+
const data = JSON.parse(result.content[0].text);
|
|
104
|
+
expect(data.results.length).toBeGreaterThanOrEqual(1);
|
|
105
|
+
expect(data.results[0].memory).toContain('JWT');
|
|
106
|
+
expect(data.results[0].source).toBe('local_graph');
|
|
107
|
+
});
|
|
108
|
+
it('respects depth and limit parameters', async () => {
|
|
109
|
+
const result = await callCap('memory_graph_query', {}, {
|
|
110
|
+
query: 'authentication',
|
|
111
|
+
depth: 2,
|
|
112
|
+
limit: 3,
|
|
113
|
+
});
|
|
114
|
+
const data = JSON.parse(result.content[0].text);
|
|
115
|
+
expect(data.depth).toBe(2);
|
|
116
|
+
// Results should not exceed limit
|
|
117
|
+
expect(data.results?.length || 0).toBeLessThanOrEqual(3);
|
|
118
|
+
});
|
|
119
|
+
it('caps depth at 3', async () => {
|
|
120
|
+
// Store a memory with "depth" keyword so we get results (which include depth field)
|
|
121
|
+
await callCap('memory_graph_store', {}, {
|
|
122
|
+
content: 'Testing depth cap behavior in graph traversal',
|
|
123
|
+
category: 'conventions',
|
|
124
|
+
});
|
|
125
|
+
const result = await callCap('memory_graph_query', {}, {
|
|
126
|
+
query: 'depth traversal',
|
|
127
|
+
depth: 10,
|
|
128
|
+
});
|
|
129
|
+
const data = JSON.parse(result.content[0].text);
|
|
130
|
+
expect(data.depth).toBe(3);
|
|
131
|
+
});
|
|
132
|
+
it('filters by category', async () => {
|
|
133
|
+
await callCap('memory_graph_store', {}, {
|
|
134
|
+
content: 'Always use vitest for frontend testing',
|
|
135
|
+
category: 'conventions',
|
|
136
|
+
});
|
|
137
|
+
await callCap('memory_graph_store', {}, {
|
|
138
|
+
content: 'Bug in vitest mock setup',
|
|
139
|
+
category: 'bug_history',
|
|
140
|
+
});
|
|
141
|
+
const result = await callCap('memory_graph_query', {}, {
|
|
142
|
+
query: 'vitest',
|
|
143
|
+
category: 'conventions',
|
|
144
|
+
});
|
|
145
|
+
const data = JSON.parse(result.content[0].text);
|
|
146
|
+
const localResults = (data.results || []).filter((r) => r.source === 'local_graph');
|
|
147
|
+
for (const r of localResults) {
|
|
148
|
+
expect(r.category).toBe('conventions');
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
// ============================================
|
|
153
|
+
// Timeline
|
|
154
|
+
// ============================================
|
|
155
|
+
describe('MemoryGraph: Timeline', () => {
|
|
156
|
+
beforeEach(() => {
|
|
157
|
+
vi.resetAllMocks();
|
|
158
|
+
delete process.env.MEM0_API_KEY;
|
|
159
|
+
});
|
|
160
|
+
it('returns timeline for a topic', async () => {
|
|
161
|
+
// Store some timeline entries
|
|
162
|
+
await callCap('memory_graph_store', {}, {
|
|
163
|
+
content: 'Initial database schema design for authentication',
|
|
164
|
+
category: 'architecture',
|
|
165
|
+
tags: ['database'],
|
|
166
|
+
});
|
|
167
|
+
const result = await callCap('memory_graph_timeline', {}, {
|
|
168
|
+
topic: 'database',
|
|
169
|
+
});
|
|
170
|
+
const data = JSON.parse(result.content[0].text);
|
|
171
|
+
expect(data.topic).toBe('database');
|
|
172
|
+
expect(data.timeline).toBeDefined();
|
|
173
|
+
expect(Array.isArray(data.timeline)).toBe(true);
|
|
174
|
+
});
|
|
175
|
+
it('returns empty timeline with helpful note', async () => {
|
|
176
|
+
const result = await callCap('memory_graph_timeline', {}, {
|
|
177
|
+
topic: 'nonexistent_unique_topic_abc',
|
|
178
|
+
});
|
|
179
|
+
const data = JSON.parse(result.content[0].text);
|
|
180
|
+
expect(data.total_entries).toBe(0);
|
|
181
|
+
expect(data.note).toContain('No timeline entries');
|
|
182
|
+
});
|
|
183
|
+
it('respects limit parameter', async () => {
|
|
184
|
+
const result = await callCap('memory_graph_timeline', {}, {
|
|
185
|
+
topic: 'test',
|
|
186
|
+
limit: 5,
|
|
187
|
+
});
|
|
188
|
+
const data = JSON.parse(result.content[0].text);
|
|
189
|
+
expect(data.timeline.length).toBeLessThanOrEqual(5);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
// ============================================
|
|
193
|
+
// Context Aggregation
|
|
194
|
+
// ============================================
|
|
195
|
+
describe('MemoryGraph: Context', () => {
|
|
196
|
+
beforeEach(() => {
|
|
197
|
+
vi.resetAllMocks();
|
|
198
|
+
delete process.env.MEM0_API_KEY;
|
|
199
|
+
});
|
|
200
|
+
it('returns context package with local memories', async () => {
|
|
201
|
+
await callCap('memory_graph_store', {}, {
|
|
202
|
+
content: 'API routes follow RESTful conventions with /api/v1/ prefix',
|
|
203
|
+
category: 'conventions',
|
|
204
|
+
tags: ['api'],
|
|
205
|
+
});
|
|
206
|
+
const result = await callCap('memory_graph_context', {}, {
|
|
207
|
+
task_title: 'Add new API endpoint for user management',
|
|
208
|
+
});
|
|
209
|
+
const data = JSON.parse(result.content[0].text);
|
|
210
|
+
expect(data.task).toBe('Add new API endpoint for user management');
|
|
211
|
+
expect(data.gathered_at).toBeTruthy();
|
|
212
|
+
expect(data.summary).toBeDefined();
|
|
213
|
+
expect(data.summary.total_memories_found).toBeGreaterThanOrEqual(0);
|
|
214
|
+
expect(data.summary.categories_searched).toContain('project_decisions');
|
|
215
|
+
});
|
|
216
|
+
it('includes mem0 not configured note', async () => {
|
|
217
|
+
const result = await callCap('memory_graph_context', {}, {
|
|
218
|
+
task_title: 'Some task',
|
|
219
|
+
});
|
|
220
|
+
const data = JSON.parse(result.content[0].text);
|
|
221
|
+
expect(data.mem0_configured).toBe(false);
|
|
222
|
+
expect(data.note).toContain('MEM0_API_KEY');
|
|
223
|
+
});
|
|
224
|
+
it('includes project filter', async () => {
|
|
225
|
+
const result = await callCap('memory_graph_context', {}, {
|
|
226
|
+
task_title: 'Fix auth bug',
|
|
227
|
+
project: 'dobby',
|
|
228
|
+
});
|
|
229
|
+
const data = JSON.parse(result.content[0].text);
|
|
230
|
+
expect(data.project).toBe('dobby');
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
// ============================================
|
|
234
|
+
// Tool Registration
|
|
235
|
+
// ============================================
|
|
236
|
+
describe('MemoryGraph: Tool Registration', () => {
|
|
237
|
+
it('all memory graph tools are in allTools', async () => {
|
|
238
|
+
const { allTools } = await import('../tools/index.js');
|
|
239
|
+
expect(allTools.memory_graph_store).toBeDefined();
|
|
240
|
+
expect(allTools.memory_graph_query).toBeDefined();
|
|
241
|
+
expect(allTools.memory_graph_timeline).toBeDefined();
|
|
242
|
+
expect(allTools.memory_graph_context).toBeDefined();
|
|
243
|
+
});
|
|
244
|
+
it('memory graph tools have correct schemas', async () => {
|
|
245
|
+
const { memoryGraphTools } = await import('../tools/memory-graph.js');
|
|
246
|
+
for (const [name, tool] of Object.entries(memoryGraphTools)) {
|
|
247
|
+
expect(tool.name).toBe(name);
|
|
248
|
+
expect(tool.description).toBeTruthy();
|
|
249
|
+
expect(tool.inputSchema.type).toBe('object');
|
|
250
|
+
expect(tool.inputSchema.properties).toBeDefined();
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
//# sourceMappingURL=memory-graph-tools.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-graph-tools.test.js","sourceRoot":"","sources":["../../src/__tests__/memory-graph-tools.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADR-019 Phase 1 — registry dispatch alignment.
|
|
3
|
+
*
|
|
4
|
+
* CallTool now dispatches through the @dobbyai/capability-core registry instead
|
|
5
|
+
* of a switch. This guards the load-bearing invariant: EVERY tool the server
|
|
6
|
+
* lists (allTools / getToolDefinitions) must be a registered capability, or the
|
|
7
|
+
* dispatch returns "Unknown tool" for a tool the client can see. A miss here is
|
|
8
|
+
* exactly the class of bug a silent migration would introduce.
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=registry-dispatch.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry-dispatch.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/registry-dispatch.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADR-019 Phase 1 — registry dispatch alignment.
|
|
3
|
+
*
|
|
4
|
+
* CallTool now dispatches through the @dobbyai/capability-core registry instead
|
|
5
|
+
* of a switch. This guards the load-bearing invariant: EVERY tool the server
|
|
6
|
+
* lists (allTools / getToolDefinitions) must be a registered capability, or the
|
|
7
|
+
* dispatch returns "Unknown tool" for a tool the client can see. A miss here is
|
|
8
|
+
* exactly the class of bug a silent migration would introduce.
|
|
9
|
+
*/
|
|
10
|
+
import { describe, it, expect } from "vitest";
|
|
11
|
+
import { createRegistry } from "@dobbyai/capability-core";
|
|
12
|
+
import { allTools } from "../tools/index.js";
|
|
13
|
+
describe("registry ↔ allTools alignment", () => {
|
|
14
|
+
const registry = createRegistry();
|
|
15
|
+
it("every allTools tool is a registered, dispatchable capability", () => {
|
|
16
|
+
const toolNames = Object.keys(allTools).sort();
|
|
17
|
+
const capabilityIds = registry.ids().sort();
|
|
18
|
+
expect(capabilityIds).toEqual(toolNames);
|
|
19
|
+
});
|
|
20
|
+
it("registers the full 148-tool catalog", () => {
|
|
21
|
+
expect(registry.size).toBe(Object.keys(allTools).length);
|
|
22
|
+
expect(registry.size).toBe(148);
|
|
23
|
+
});
|
|
24
|
+
it("no tool name maps to a missing capability", () => {
|
|
25
|
+
for (const name of Object.keys(allTools)) {
|
|
26
|
+
expect(registry.has(name)).toBe(true);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
//# sourceMappingURL=registry-dispatch.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry-dispatch.test.js","sourceRoot":"","sources":["../../src/__tests__/registry-dispatch.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7C,QAAQ,CAAC,+BAA+B,EAAE,GAAG,EAAE;IAC7C,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAC;IAElC,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACtE,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QAC/C,MAAM,aAAa,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC;QAC5C,MAAM,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;QACzD,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxC,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry-listing-parity.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/registry-listing-parity.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Byte-identical parity guard for routing ListTools/CallTool gating through the
|
|
3
|
+
* capability registry (ADR-019 P1 tail). Proves that
|
|
4
|
+
* `capabilityRegistry.visibleTo()` produces the EXACT same visible tool set as
|
|
5
|
+
* the legacy `filterToolsByTier` + read-only + `passesRoleCap` path — so the
|
|
6
|
+
* reroute of `getToolDefinitions` cannot change what mcp.dobby-ai.com serves.
|
|
7
|
+
*
|
|
8
|
+
* The equivalence rests on three field consistencies between each capability and
|
|
9
|
+
* its mcp/external metadata; if any drifts, this test fails loudly.
|
|
10
|
+
*/
|
|
11
|
+
import { describe, it, expect } from "vitest";
|
|
12
|
+
import { createRegistry } from "@dobbyai/capability-core";
|
|
13
|
+
import { allTools, minRoleForTool, getToolDefinitions, } from "../tools/index.js";
|
|
14
|
+
import { MVP_TOOLS, PRO_TOOLS } from "../tools/tiers.js";
|
|
15
|
+
const reg = createRegistry();
|
|
16
|
+
const toolNames = Object.keys(allTools);
|
|
17
|
+
function expectedTier(name) {
|
|
18
|
+
if (MVP_TOOLS.includes(name))
|
|
19
|
+
return "mvp";
|
|
20
|
+
if (PRO_TOOLS.includes(name))
|
|
21
|
+
return "pro";
|
|
22
|
+
return "enterprise";
|
|
23
|
+
}
|
|
24
|
+
describe("registry ↔ mcp/external field consistency (the reroute's foundation)", () => {
|
|
25
|
+
it("every allTools name is a registered capability", () => {
|
|
26
|
+
const missing = toolNames.filter((n) => !reg.get(n));
|
|
27
|
+
expect(missing).toEqual([]);
|
|
28
|
+
});
|
|
29
|
+
it("every registered capability id exists as a key in allTools (reverse of the check above — catches a capability added to capability-core's registry but never wired into an mcp/external tool group, which would otherwise bypass getToolAccessDenial's tier/read-only/role-cap gates entirely)", () => {
|
|
30
|
+
const toolNameSet = new Set(toolNames);
|
|
31
|
+
const missing = reg.ids().filter((id) => !toolNameSet.has(id));
|
|
32
|
+
expect(missing).toEqual([]);
|
|
33
|
+
});
|
|
34
|
+
it("cap.tier === the tiers.ts allowlist bucket for every tool", () => {
|
|
35
|
+
const drift = toolNames.filter((n) => reg.get(n).tier !== expectedTier(n));
|
|
36
|
+
expect(drift).toEqual([]);
|
|
37
|
+
});
|
|
38
|
+
it("cap.minRole === minRoleForTool(name) for every tool", () => {
|
|
39
|
+
const drift = toolNames.filter((n) => reg.get(n).minRole !== minRoleForTool(n));
|
|
40
|
+
expect(drift).toEqual([]);
|
|
41
|
+
});
|
|
42
|
+
it("cap.readOnly === annotations.readOnlyHint for every tool", () => {
|
|
43
|
+
const drift = toolNames.filter((n) => {
|
|
44
|
+
const hint = allTools[n]?.annotations?.readOnlyHint === true;
|
|
45
|
+
return reg.get(n).readOnly !== hint;
|
|
46
|
+
});
|
|
47
|
+
expect(drift).toEqual([]);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
describe("visibleTo() set === legacy getToolDefinitions() set (concrete roles + superadmin)", () => {
|
|
51
|
+
const tiers = ["mvp", "pro", "enterprise"];
|
|
52
|
+
const roles = [
|
|
53
|
+
"viewer",
|
|
54
|
+
"member",
|
|
55
|
+
"operator",
|
|
56
|
+
"developer",
|
|
57
|
+
"tenant_admin",
|
|
58
|
+
"tenant_owner",
|
|
59
|
+
];
|
|
60
|
+
function visibleViaRegistry(opts) {
|
|
61
|
+
const allowed = new Set(toolNames);
|
|
62
|
+
return reg
|
|
63
|
+
.visibleTo(opts)
|
|
64
|
+
.map((c) => c.id)
|
|
65
|
+
.filter((id) => allowed.has(id))
|
|
66
|
+
.sort();
|
|
67
|
+
}
|
|
68
|
+
function legacyList(opts) {
|
|
69
|
+
return getToolDefinitions(opts.tier, opts)
|
|
70
|
+
.map((t) => t.name)
|
|
71
|
+
.sort();
|
|
72
|
+
}
|
|
73
|
+
for (const tier of tiers) {
|
|
74
|
+
for (const readOnly of [false, true]) {
|
|
75
|
+
it(`tier=${tier} readOnly=${readOnly} superadmin → identical set`, () => {
|
|
76
|
+
expect(visibleViaRegistry({ tier, isSuperAdmin: true, readOnly })).toEqual(legacyList({ tier, isSuperAdmin: true, readOnly }));
|
|
77
|
+
});
|
|
78
|
+
it(`tier=${tier} readOnly=${readOnly} null role → identical set (graceful, tier-only)`, () => {
|
|
79
|
+
expect(visibleViaRegistry({ tier, role: null, readOnly })).toEqual(legacyList({ tier, role: null, readOnly }));
|
|
80
|
+
});
|
|
81
|
+
for (const role of roles) {
|
|
82
|
+
it(`tier=${tier} role=${role} readOnly=${readOnly} → identical set`, () => {
|
|
83
|
+
expect(visibleViaRegistry({ tier, role, readOnly })).toEqual(legacyList({ tier, role, readOnly }));
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
//# sourceMappingURL=registry-listing-parity.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry-listing-parity.test.js","sourceRoot":"","sources":["../../src/__tests__/registry-listing-parity.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"role-cap.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/role-cap.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { allTools, passesRoleCap, getToolDefinitions, getToolAccessDenial, } from "../tools/index.js";
|
|
3
|
+
// Representative tools:
|
|
4
|
+
// get_setup_status — readOnlyHint → minRole viewer
|
|
5
|
+
// create_task — write → minRole member
|
|
6
|
+
// approve_task — admin-class → minRole tenant_admin
|
|
7
|
+
const ENTERPRISE_SCOPES = ["mcp:*", "mcp:execute"];
|
|
8
|
+
describe("RBAC role-cap (ADR-019 Phase 2)", () => {
|
|
9
|
+
describe("passesRoleCap", () => {
|
|
10
|
+
it("superadmin bypasses every role-cap", () => {
|
|
11
|
+
expect(passesRoleCap("approve_task", "viewer", true)).toBe(true);
|
|
12
|
+
});
|
|
13
|
+
it("a nullish role skips the cap (tier-only, non-breaking rollout)", () => {
|
|
14
|
+
expect(passesRoleCap("create_task", undefined)).toBe(true);
|
|
15
|
+
expect(passesRoleCap("create_task", null)).toBe(true);
|
|
16
|
+
});
|
|
17
|
+
it("a viewer may call read-only tools but not writes", () => {
|
|
18
|
+
expect(passesRoleCap("get_setup_status", "viewer")).toBe(true);
|
|
19
|
+
expect(passesRoleCap("create_task", "viewer")).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
it("a member may call standard writes but not admin-class tools", () => {
|
|
22
|
+
expect(passesRoleCap("create_task", "member")).toBe(true);
|
|
23
|
+
expect(passesRoleCap("approve_task", "member")).toBe(false);
|
|
24
|
+
});
|
|
25
|
+
it("tenant_admin/tenant_owner may call admin-class tools", () => {
|
|
26
|
+
expect(passesRoleCap("approve_task", "tenant_admin")).toBe(true);
|
|
27
|
+
expect(passesRoleCap("approve_task", "tenant_owner")).toBe(true);
|
|
28
|
+
});
|
|
29
|
+
it("an unknown role fails closed for a write tool", () => {
|
|
30
|
+
expect(passesRoleCap("create_task", "bogus_role")).toBe(false);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
describe("getToolDefinitions role filtering (ListTools)", () => {
|
|
34
|
+
it("a viewer sees read-only tools, not writes", () => {
|
|
35
|
+
const names = getToolDefinitions("enterprise", { role: "viewer" }).map((t) => t.name);
|
|
36
|
+
expect(names).toContain("get_setup_status");
|
|
37
|
+
expect(names).not.toContain("create_task");
|
|
38
|
+
});
|
|
39
|
+
it("a member sees writes but not admin-class", () => {
|
|
40
|
+
const names = getToolDefinitions("enterprise", { role: "member" }).map((t) => t.name);
|
|
41
|
+
expect(names).toContain("create_task");
|
|
42
|
+
expect(names).not.toContain("approve_task");
|
|
43
|
+
});
|
|
44
|
+
it("superadmin sees the full enterprise set — a strict superset of a non-superadmin's", () => {
|
|
45
|
+
// capability-core 0.1.2 hides the 5 superAdminOnly ops tools from every
|
|
46
|
+
// non-superadmin, so a superadmin now sees STRICTLY MORE than a normal
|
|
47
|
+
// enterprise principal. The superadmin set = the FULL registry (all tools);
|
|
48
|
+
// the non-superadmin set is the full set minus the 5 ops tools.
|
|
49
|
+
//
|
|
50
|
+
// Both sides use a nullish role (tier-only, no role floor) so the ONLY
|
|
51
|
+
// difference between them is the superAdminOnly gating — isolating exactly
|
|
52
|
+
// the 5 ops tools as the delta.
|
|
53
|
+
const nonSu = new Set(getToolDefinitions("enterprise").map((t) => t.name));
|
|
54
|
+
const su = getToolDefinitions("enterprise", {
|
|
55
|
+
isSuperAdmin: true,
|
|
56
|
+
}).map((t) => t.name);
|
|
57
|
+
const suSet = new Set(su);
|
|
58
|
+
// Superadmin reaches the entire catalog (byte-identical to allTools).
|
|
59
|
+
expect(su.length).toBe(Object.keys(allTools).length);
|
|
60
|
+
// ...and it is a STRICT superset of the non-superadmin set.
|
|
61
|
+
expect(su.length).toBeGreaterThan(nonSu.size);
|
|
62
|
+
for (const name of nonSu) {
|
|
63
|
+
expect(suSet.has(name), `superadmin missing "${name}"`).toBe(true);
|
|
64
|
+
}
|
|
65
|
+
// The exclusive tools are exactly the 5 superAdminOnly ops caps.
|
|
66
|
+
const exclusive = su.filter((n) => !nonSu.has(n));
|
|
67
|
+
expect(exclusive.sort()).toEqual([
|
|
68
|
+
"acknowledge_ops_issue",
|
|
69
|
+
"get_active_issues",
|
|
70
|
+
"get_ops_audit_log",
|
|
71
|
+
"get_ops_health_summary",
|
|
72
|
+
"get_service_status",
|
|
73
|
+
].sort());
|
|
74
|
+
});
|
|
75
|
+
it("a nullish role does not reduce the set (tier-only)", () => {
|
|
76
|
+
const all = getToolDefinitions("enterprise").length;
|
|
77
|
+
expect(getToolDefinitions("enterprise", {}).length).toBe(all);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
describe("getToolAccessDenial role denial (CallTool)", () => {
|
|
81
|
+
it("denies a viewer on a write tool", () => {
|
|
82
|
+
const d = getToolAccessDenial("create_task", {
|
|
83
|
+
scopes: ENTERPRISE_SCOPES,
|
|
84
|
+
role: "viewer",
|
|
85
|
+
});
|
|
86
|
+
expect(d).toMatch(/tenant role/);
|
|
87
|
+
});
|
|
88
|
+
it("allows a member on a write tool", () => {
|
|
89
|
+
expect(getToolAccessDenial("create_task", {
|
|
90
|
+
scopes: ENTERPRISE_SCOPES,
|
|
91
|
+
role: "member",
|
|
92
|
+
})).toBeNull();
|
|
93
|
+
});
|
|
94
|
+
it("denies a member on an admin-class tool (names the required role)", () => {
|
|
95
|
+
const d = getToolAccessDenial("approve_task", {
|
|
96
|
+
scopes: ENTERPRISE_SCOPES,
|
|
97
|
+
role: "member",
|
|
98
|
+
});
|
|
99
|
+
expect(d).toMatch(/tenant_admin/);
|
|
100
|
+
});
|
|
101
|
+
it("superadmin bypasses the role denial", () => {
|
|
102
|
+
expect(getToolAccessDenial("approve_task", {
|
|
103
|
+
scopes: ENTERPRISE_SCOPES,
|
|
104
|
+
role: "viewer",
|
|
105
|
+
isSuperAdmin: true,
|
|
106
|
+
})).toBeNull();
|
|
107
|
+
});
|
|
108
|
+
it("a nullish role does not deny (tier-only)", () => {
|
|
109
|
+
expect(getToolAccessDenial("create_task", { scopes: ENTERPRISE_SCOPES })).toBeNull();
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
//# sourceMappingURL=role-cap.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"role-cap.test.js","sourceRoot":"","sources":["../../src/__tests__/role-cap.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schedule-tools.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/schedule-tools.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|