@gwdn/nexus-mcp 0.8.6 → 0.8.8

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 (52) hide show
  1. package/README.md +3 -4
  2. package/dist/nexus-api.d.ts.map +1 -1
  3. package/dist/nexus-api.js +10 -1
  4. package/dist/nexus-api.js.map +1 -1
  5. package/dist/server.js +1 -1
  6. package/package.json +9 -2
  7. package/.github/workflows/ci.yml +0 -38
  8. package/.github/workflows/release.yml +0 -57
  9. package/src/__tests__/auth.test.ts +0 -162
  10. package/src/__tests__/decision-comments.test.ts +0 -173
  11. package/src/__tests__/e2e-integration.test.ts +0 -443
  12. package/src/__tests__/helpers.ts +0 -58
  13. package/src/__tests__/layer1-knowledge.test.ts +0 -302
  14. package/src/__tests__/layer2-coordination.test.ts +0 -918
  15. package/src/__tests__/layer3-governance.test.ts +0 -205
  16. package/src/__tests__/machine-id.test.ts +0 -136
  17. package/src/__tests__/nexus-api.test.ts +0 -127
  18. package/src/__tests__/project-list-and-skill-assign.test.ts +0 -282
  19. package/src/__tests__/reviews.test.ts +0 -420
  20. package/src/__tests__/server.test.ts +0 -251
  21. package/src/__tests__/setup.ts +0 -15
  22. package/src/__tests__/task-list-and-doc-list.test.ts +0 -226
  23. package/src/auth.ts +0 -81
  24. package/src/machine-id.ts +0 -60
  25. package/src/nexus-api.ts +0 -141
  26. package/src/server.ts +0 -629
  27. package/src/tools/add-task-note.ts +0 -50
  28. package/src/tools/append-session-entry.ts +0 -113
  29. package/src/tools/classify-document.ts +0 -55
  30. package/src/tools/create-task.ts +0 -66
  31. package/src/tools/decision-comments.ts +0 -103
  32. package/src/tools/delete-document.ts +0 -43
  33. package/src/tools/directives.ts +0 -303
  34. package/src/tools/get-document.ts +0 -80
  35. package/src/tools/get-project-memory.ts +0 -65
  36. package/src/tools/get-related-entities.ts +0 -73
  37. package/src/tools/governance.ts +0 -165
  38. package/src/tools/ingest-document.ts +0 -65
  39. package/src/tools/letter-inbox.ts +0 -157
  40. package/src/tools/letters.ts +0 -144
  41. package/src/tools/list-documents.ts +0 -58
  42. package/src/tools/list-tasks.ts +0 -57
  43. package/src/tools/project-list.ts +0 -52
  44. package/src/tools/reviews.ts +0 -281
  45. package/src/tools/search-knowledge.ts +0 -68
  46. package/src/tools/sessions.ts +0 -157
  47. package/src/tools/skill-assign.ts +0 -142
  48. package/src/tools/skills.ts +0 -255
  49. package/src/tools/update-document.ts +0 -66
  50. package/src/tools/update-task-status.ts +0 -64
  51. package/tsconfig.json +0 -20
  52. package/vitest.config.ts +0 -8
package/README.md CHANGED
@@ -89,12 +89,11 @@ terminals that were started before the update.
89
89
 
90
90
  **Symptoms:** MCP tools report an older version, or new tools/fixes are missing.
91
91
 
92
- **Fix:** Before starting OpenCode, clear stale npx caches:
92
+ **Fix:** Before starting OpenCode, clear all npx caches for this package:
93
93
 
94
94
  ```bash
95
- find ~/.npm/_npx -path "*/node_modules/@gwdn/nexus-mcp/package.json" \
96
- -exec node -e "if(require('{}').version!=='0.8.1') console.log(require('path').resolve('{}','../../..'))" \; \
97
- | xargs rm -rf
95
+ find ~/.npm/_npx -path "*/node_modules/@gwdn/nexus-mcp" -type d \
96
+ -exec rm -rf {} + 2>/dev/null
98
97
  ```
99
98
 
100
99
  Then start OpenCode normally. npx will fetch the latest version into a fresh
@@ -1 +1 @@
1
- {"version":3,"file":"nexus-api.d.ts","sourceRoot":"","sources":["../src/nexus-api.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAeH;;;GAGG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAIrC;AA0BD,MAAM,WAAW,gBAAgB,CAAC,CAAC,GAAG,OAAO;IAC3C,EAAE,EAAE,OAAO,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,CAAC,GAAG,IAAI,CAAA;IACd,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB;AAKD;;GAEG;AACH,wBAAsB,QAAQ,CAAC,CAAC,GAAG,OAAO,EACxC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IACP,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAA;IAC5C,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,SAAS,CAAC,EAAE,MAAM,CAAA;CACd,GACL,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CA6C9B;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,CAAC,GAAG,OAAO,EACzC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,OAAO,GACZ,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAE9B;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAAC,CAAC,GAAG,OAAO,EACxC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAE9B"}
1
+ {"version":3,"file":"nexus-api.d.ts","sourceRoot":"","sources":["../src/nexus-api.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAsBH;;;GAGG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAIrC;AA0BD,MAAM,WAAW,gBAAgB,CAAC,CAAC,GAAG,OAAO;IAC3C,EAAE,EAAE,OAAO,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,CAAC,GAAG,IAAI,CAAA;IACd,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB;AAKD;;GAEG;AACH,wBAAsB,QAAQ,CAAC,CAAC,GAAG,OAAO,EACxC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IACP,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAA;IAC5C,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,SAAS,CAAC,EAAE,MAAM,CAAA;CACd,GACL,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CA8C9B;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,CAAC,GAAG,OAAO,EACzC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,OAAO,GACZ,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAE9B;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAAC,CAAC,GAAG,OAAO,EACxC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAE9B"}
package/dist/nexus-api.js CHANGED
@@ -5,17 +5,25 @@
5
5
  * All operations go through /api/mcp/* endpoints, authenticated
6
6
  * via the NEXUS_PRIVATE_TOKEN (nxs_pat_*) Bearer token.
7
7
  */
8
+ import { hostname } from 'node:os';
8
9
  import { getMachineId } from './machine-id.js';
9
10
  let _baseUrl = null;
10
11
  let _token = null;
11
12
  let _machineId = null;
12
- // Eagerly resolve machine ID (sync, cached after first call)
13
+ let _machineName = null;
14
+ // Eagerly resolve machine ID and hostname (sync, cached after first call)
13
15
  try {
14
16
  _machineId = getMachineId();
15
17
  }
16
18
  catch {
17
19
  // machine_id is optional enrichment — never block startup
18
20
  }
21
+ try {
22
+ _machineName = hostname();
23
+ }
24
+ catch {
25
+ // hostname is optional enrichment
26
+ }
19
27
  /**
20
28
  * Reset the cached API configuration. Used by E2E tests to switch
21
29
  * from mocked env vars to real credentials.
@@ -54,6 +62,7 @@ export async function nexusApi(path, options = {}) {
54
62
  Authorization: `Bearer ${token}`,
55
63
  'Content-Type': 'application/json',
56
64
  ...(_machineId ? { 'X-Nexus-Machine-Id': _machineId } : {}),
65
+ ...(_machineName ? { 'X-Nexus-Machine-Name': _machineName } : {}),
57
66
  ...(options.headers ?? {}),
58
67
  };
59
68
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"nexus-api.js","sourceRoot":"","sources":["../src/nexus-api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"nexus-api.js","sourceRoot":"","sources":["../src/nexus-api.ts"],"names":[],"mappings":"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"}
package/dist/server.js CHANGED
@@ -121,7 +121,7 @@ function withIdentity(handler) {
121
121
  // ---------------------------------------------------------------------------
122
122
  const server = new McpServer({
123
123
  name: 'nexus-mcp',
124
- version: '0.8.0',
124
+ version: '0.8.7',
125
125
  }, {
126
126
  capabilities: {
127
127
  tools: {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gwdn/nexus-mcp",
3
- "version": "0.8.6",
3
+ "version": "0.8.8",
4
4
  "description": "MCP server for the Nexus platform",
5
5
  "type": "module",
6
6
  "main": "dist/server.js",
@@ -8,7 +8,8 @@
8
8
  "nexus-mcp": "dist/server.js"
9
9
  },
10
10
  "scripts": {
11
- "build": "tsc",
11
+ "build": "tsc && chmod +x dist/server.js",
12
+ "prepublishOnly": "npm run build",
12
13
  "dev": "tsx src/server.ts",
13
14
  "start": "node dist/server.js",
14
15
  "test": "vitest run",
@@ -20,10 +21,16 @@
20
21
  "zod": "^4.3.6"
21
22
  },
22
23
  "devDependencies": {
24
+ "@types/node": "^25.9.1",
23
25
  "tsx": "^4.21.0",
24
26
  "typescript": "^5.8.3",
25
27
  "vitest": "^4.1.4"
26
28
  },
29
+ "files": [
30
+ "dist",
31
+ "README.md",
32
+ "LICENSE"
33
+ ],
27
34
  "engines": {
28
35
  "node": ">=20"
29
36
  }
@@ -1,38 +0,0 @@
1
- name: CI
2
-
3
- on:
4
- push:
5
- branches: [main]
6
- pull_request:
7
- branches: [main]
8
-
9
- jobs:
10
- test:
11
- name: Test (Node ${{ matrix.node-version }})
12
- runs-on: blacksmith-2vcpu-ubuntu-2204
13
- strategy:
14
- fail-fast: false
15
- matrix:
16
- node-version: [20, 22]
17
-
18
- steps:
19
- - name: Checkout
20
- uses: actions/checkout@v4
21
-
22
- - name: Setup Node.js ${{ matrix.node-version }}
23
- uses: actions/setup-node@v4
24
- with:
25
- node-version: ${{ matrix.node-version }}
26
- cache: npm
27
-
28
- - name: Install dependencies
29
- run: npm ci
30
-
31
- - name: Typecheck
32
- run: npm run typecheck
33
-
34
- - name: Test
35
- run: npm test
36
-
37
- - name: Build
38
- run: npm run build
@@ -1,57 +0,0 @@
1
- name: Release
2
-
3
- on:
4
- push:
5
- tags:
6
- - "v*"
7
-
8
- permissions:
9
- contents: write
10
-
11
- jobs:
12
- release:
13
- name: Publish to npm
14
- runs-on: blacksmith-2vcpu-ubuntu-2204
15
-
16
- steps:
17
- - name: Checkout
18
- uses: actions/checkout@v4
19
-
20
- - name: Setup Node.js
21
- uses: actions/setup-node@v4
22
- with:
23
- node-version: 22
24
- cache: npm
25
- registry-url: https://registry.npmjs.org
26
-
27
- - name: Install dependencies
28
- run: npm ci
29
-
30
- - name: Typecheck
31
- run: npm run typecheck
32
-
33
- - name: Test
34
- run: npm test
35
-
36
- - name: Build
37
- run: npm run build
38
-
39
- - name: Verify version matches tag
40
- run: |
41
- PKG_VERSION="v$(node -p "require('./package.json').version")"
42
- TAG_VERSION="${GITHUB_REF#refs/tags/}"
43
- if [ "$PKG_VERSION" != "$TAG_VERSION" ]; then
44
- echo "ERROR: package.json version ($PKG_VERSION) does not match tag ($TAG_VERSION)"
45
- exit 1
46
- fi
47
- echo "Version verified: $TAG_VERSION"
48
-
49
- - name: Publish to npm
50
- run: npm publish --access public
51
- env:
52
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
53
-
54
- - name: Create GitHub Release
55
- uses: softprops/action-gh-release@v2
56
- with:
57
- generate_release_notes: true
@@ -1,162 +0,0 @@
1
- /**
2
- * Tests for src/auth.ts
3
- *
4
- * Covers:
5
- * - initIdentity() with valid/invalid tokens
6
- * - getIdentity() before/after init
7
- */
8
-
9
- import { beforeEach, describe, expect, it, vi } from 'vitest'
10
-
11
- // Mock the nexus-api module before importing auth
12
- vi.mock('../nexus-api.js', () => ({
13
- nexusGet: vi.fn(),
14
- }))
15
-
16
- import { nexusGet } from '../nexus-api.js'
17
- import { TEST_IDS } from './helpers'
18
-
19
- describe('MCP Auth', () => {
20
- beforeEach(() => {
21
- vi.resetModules()
22
- vi.restoreAllMocks()
23
- // Suppress console.error
24
- vi.spyOn(console, 'error').mockImplementation(() => {})
25
- })
26
-
27
- describe('initIdentity', () => {
28
- it('should resolve identity from a valid token', async () => {
29
- vi.mocked(nexusGet).mockResolvedValue({
30
- ok: true,
31
- status: 200,
32
- data: {
33
- userId: TEST_IDS.userId,
34
- email: 'test@example.com',
35
- displayName: 'Test User',
36
- isPlatformAdmin: true,
37
- isPlatformOwner: false,
38
- tenantId: TEST_IDS.tenantId,
39
- memberships: [],
40
- agentAssignments: [],
41
- },
42
- error: null,
43
- })
44
-
45
- process.env.NEXUS_PRIVATE_TOKEN =
46
- 'nxs_pat_valid-test-token-1234567890abcde'
47
-
48
- const { initIdentity } = await import('../auth.js')
49
- const identity = await initIdentity()
50
-
51
- expect(identity).toBeDefined()
52
- expect(identity.userId).toBe(TEST_IDS.userId)
53
- expect(identity.displayName).toBe('Test User')
54
- expect(identity.email).toBe('test@example.com')
55
- expect(identity.isPlatformAdmin).toBe(true)
56
- expect(identity.isPlatformOwner).toBe(false)
57
- })
58
-
59
- it('should throw if NEXUS_PRIVATE_TOKEN is not set', async () => {
60
- delete process.env.NEXUS_PRIVATE_TOKEN
61
-
62
- const { initIdentity } = await import('../auth.js')
63
- await expect(initIdentity()).rejects.toThrow(
64
- 'NEXUS_PRIVATE_TOKEN is not set',
65
- )
66
- })
67
-
68
- it('should throw if API returns an error', async () => {
69
- vi.mocked(nexusGet).mockResolvedValue({
70
- ok: false,
71
- status: 401,
72
- data: null,
73
- error: 'Invalid token',
74
- })
75
-
76
- process.env.NEXUS_PRIVATE_TOKEN = 'nxs_pat_invalid-token-123456789012345'
77
-
78
- const { initIdentity } = await import('../auth.js')
79
- await expect(initIdentity()).rejects.toThrow(
80
- 'Identity resolution failed',
81
- )
82
- })
83
-
84
- it('should throw if API returns null data', async () => {
85
- vi.mocked(nexusGet).mockResolvedValue({
86
- ok: true,
87
- status: 200,
88
- data: null,
89
- error: null,
90
- })
91
-
92
- process.env.NEXUS_PRIVATE_TOKEN = 'nxs_pat_null-data-token-12345678901234'
93
-
94
- const { initIdentity } = await import('../auth.js')
95
- await expect(initIdentity()).rejects.toThrow(
96
- 'Identity resolution failed',
97
- )
98
- })
99
-
100
- it('should resolve platform_owner identity with both admin and owner flags', async () => {
101
- vi.mocked(nexusGet).mockResolvedValue({
102
- ok: true,
103
- status: 200,
104
- data: {
105
- userId: TEST_IDS.userId,
106
- email: 'owner@example.com',
107
- displayName: 'Platform Owner',
108
- isPlatformAdmin: true,
109
- isPlatformOwner: true,
110
- tenantId: TEST_IDS.tenantId,
111
- memberships: [],
112
- agentAssignments: [],
113
- },
114
- error: null,
115
- })
116
-
117
- process.env.NEXUS_PRIVATE_TOKEN = 'nxs_pat_owner-test-token-12345678901'
118
-
119
- const { initIdentity } = await import('../auth.js')
120
- const identity = await initIdentity()
121
-
122
- expect(identity.isPlatformAdmin).toBe(true)
123
- expect(identity.isPlatformOwner).toBe(true)
124
- expect(identity.displayName).toBe('Platform Owner')
125
- expect(identity.email).toBe('owner@example.com')
126
- })
127
- })
128
-
129
- describe('getIdentity', () => {
130
- it('should throw if called before initIdentity', async () => {
131
- const { getIdentity } = await import('../auth.js')
132
- expect(() => getIdentity()).toThrow('Identity not initialized')
133
- })
134
-
135
- it('should return cached identity after init', async () => {
136
- vi.mocked(nexusGet).mockResolvedValue({
137
- ok: true,
138
- status: 200,
139
- data: {
140
- userId: TEST_IDS.userId,
141
- email: 'cached@example.com',
142
- displayName: 'Cached User',
143
- isPlatformAdmin: false,
144
- isPlatformOwner: false,
145
- tenantId: TEST_IDS.tenantId,
146
- memberships: [],
147
- agentAssignments: [],
148
- },
149
- error: null,
150
- })
151
-
152
- process.env.NEXUS_PRIVATE_TOKEN = 'nxs_pat_cached-test-token-1234567890'
153
-
154
- const { initIdentity, getIdentity } = await import('../auth.js')
155
- await initIdentity()
156
-
157
- const identity = getIdentity()
158
- expect(identity.userId).toBe(TEST_IDS.userId)
159
- expect(identity.displayName).toBe('Cached User')
160
- })
161
- })
162
- })
@@ -1,173 +0,0 @@
1
- /**
2
- * Tests for decision comment tools.
3
- * All tools delegate to the Nexus API via nexusPost().
4
- */
5
-
6
- import { beforeEach, describe, expect, it, vi } from 'vitest'
7
- import { mockApiError, mockApiSuccess, parseToolResponse, TEST_IDS } from './helpers'
8
-
9
- vi.mock('../nexus-api.js', () => ({
10
- nexusPost: vi.fn(),
11
- }))
12
-
13
- import { nexusPost } from '../nexus-api.js'
14
-
15
- describe('Decision Comments tools', () => {
16
- beforeEach(() => {
17
- vi.restoreAllMocks()
18
- })
19
-
20
- describe('addDecisionComment', () => {
21
- it('should add a comment to an existing decision', async () => {
22
- vi.mocked(nexusPost).mockResolvedValue(
23
- mockApiSuccess({
24
- action: 'dc_add',
25
- comment_id: 'comment-id-1',
26
- decision_id: TEST_IDS.adrId,
27
- decision_title: 'Test ADR',
28
- project_id: TEST_IDS.projectId,
29
- }),
30
- )
31
-
32
- const { addDecisionComment } = await import('../tools/decision-comments.js')
33
- const result = await addDecisionComment({
34
- decision_id: TEST_IDS.adrId,
35
- body: 'This is a comment',
36
- user_id: TEST_IDS.userId,
37
- })
38
-
39
- expect(result.isError).toBeUndefined()
40
- const parsed = parseToolResponse(result)
41
- expect(parsed.action).toBe('dc_add')
42
- expect(parsed.comment_id).toBe('comment-id-1')
43
- expect(parsed.decision_id).toBe(TEST_IDS.adrId)
44
- expect(parsed.decision_title).toBe('Test ADR')
45
- })
46
-
47
- it('should support agent_id in comment', async () => {
48
- vi.mocked(nexusPost).mockResolvedValue(
49
- mockApiSuccess({
50
- action: 'dc_add',
51
- comment_id: 'comment-id-2',
52
- decision_id: TEST_IDS.adrId,
53
- decision_title: 'ADR',
54
- project_id: TEST_IDS.projectId,
55
- }),
56
- )
57
-
58
- const { addDecisionComment } = await import('../tools/decision-comments.js')
59
- const result = await addDecisionComment({
60
- decision_id: TEST_IDS.adrId,
61
- body: 'Agent comment',
62
- agent_id: TEST_IDS.agentId,
63
- user_id: TEST_IDS.userId,
64
- })
65
-
66
- expect(result.isError).toBeUndefined()
67
- // Verify agent_id was passed to the API
68
- expect(nexusPost).toHaveBeenCalledWith('/api/mcp/governance', {
69
- action: 'dc_add',
70
- decision_id: TEST_IDS.adrId,
71
- body: 'Agent comment',
72
- agent_id: TEST_IDS.agentId,
73
- })
74
- })
75
-
76
- it('should return error if decision not found', async () => {
77
- vi.mocked(nexusPost).mockResolvedValue(mockApiError('Decision not found', 404))
78
-
79
- const { addDecisionComment } = await import('../tools/decision-comments.js')
80
- const result = await addDecisionComment({
81
- decision_id: TEST_IDS.adrId,
82
- body: 'Comment',
83
- user_id: TEST_IDS.userId,
84
- })
85
-
86
- expect(result.isError).toBe(true)
87
- })
88
-
89
- it('should return error on API failure', async () => {
90
- vi.mocked(nexusPost).mockResolvedValue(mockApiError('Failed to add comment'))
91
-
92
- const { addDecisionComment } = await import('../tools/decision-comments.js')
93
- const result = await addDecisionComment({
94
- decision_id: TEST_IDS.adrId,
95
- body: 'Comment',
96
- user_id: TEST_IDS.userId,
97
- })
98
-
99
- expect(result.isError).toBe(true)
100
- })
101
- })
102
-
103
- describe('listDecisionComments', () => {
104
- it('should list comments for a decision', async () => {
105
- vi.mocked(nexusPost).mockResolvedValue(
106
- mockApiSuccess({
107
- decision_id: TEST_IDS.adrId,
108
- decision_title: 'Test ADR',
109
- total: 2,
110
- comments: [
111
- {
112
- id: 'c1',
113
- author_id: TEST_IDS.userId,
114
- agent_id: null,
115
- body: 'First comment',
116
- created_at: '2026-01-01T00:00:00Z',
117
- },
118
- {
119
- id: 'c2',
120
- author_id: TEST_IDS.userId,
121
- agent_id: TEST_IDS.agentId,
122
- body: 'Second comment',
123
- created_at: '2026-01-01T01:00:00Z',
124
- },
125
- ],
126
- }),
127
- )
128
-
129
- const { listDecisionComments } = await import('../tools/decision-comments.js')
130
- const result = await listDecisionComments({
131
- decision_id: TEST_IDS.adrId,
132
- })
133
-
134
- expect(result.isError).toBeUndefined()
135
- const parsed = parseToolResponse(result)
136
- expect(parsed.decision_title).toBe('Test ADR')
137
- expect(parsed.total).toBe(2)
138
- expect(parsed.comments).toHaveLength(2)
139
- expect(parsed.comments[0].body).toBe('First comment')
140
- })
141
-
142
- it('should return empty list for decision with no comments', async () => {
143
- vi.mocked(nexusPost).mockResolvedValue(
144
- mockApiSuccess({
145
- decision_id: TEST_IDS.adrId,
146
- decision_title: 'ADR',
147
- total: 0,
148
- comments: [],
149
- }),
150
- )
151
-
152
- const { listDecisionComments } = await import('../tools/decision-comments.js')
153
- const result = await listDecisionComments({
154
- decision_id: TEST_IDS.adrId,
155
- })
156
-
157
- const parsed = parseToolResponse(result)
158
- expect(parsed.total).toBe(0)
159
- expect(parsed.comments).toHaveLength(0)
160
- })
161
-
162
- it('should return error if decision not found', async () => {
163
- vi.mocked(nexusPost).mockResolvedValue(mockApiError('Decision not found', 404))
164
-
165
- const { listDecisionComments } = await import('../tools/decision-comments.js')
166
- const result = await listDecisionComments({
167
- decision_id: TEST_IDS.adrId,
168
- })
169
-
170
- expect(result.isError).toBe(true)
171
- })
172
- })
173
- })