group-chat-mcp 0.1.1 → 0.1.3
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/.github/workflows/publish.yml +32 -0
- package/CHANGELOG.md +42 -0
- package/LICENSE +21 -0
- package/README.md +30 -5
- package/dist/__tests__/check-inbox.test.d.ts +2 -0
- package/dist/__tests__/check-inbox.test.d.ts.map +1 -0
- package/dist/__tests__/check-inbox.test.js +85 -0
- package/dist/__tests__/check-inbox.test.js.map +1 -0
- package/dist/__tests__/cli-session-commands.test.d.ts +2 -0
- package/dist/__tests__/cli-session-commands.test.d.ts.map +1 -0
- package/dist/__tests__/cli-session-commands.test.js +145 -0
- package/dist/__tests__/cli-session-commands.test.js.map +1 -0
- package/dist/__tests__/cursor-hook.test.d.ts +2 -0
- package/dist/__tests__/cursor-hook.test.d.ts.map +1 -0
- package/dist/__tests__/cursor-hook.test.js +79 -0
- package/dist/__tests__/cursor-hook.test.js.map +1 -0
- package/dist/__tests__/installer-hooks.test.d.ts +2 -0
- package/dist/__tests__/installer-hooks.test.d.ts.map +1 -0
- package/dist/__tests__/installer-hooks.test.js +110 -0
- package/dist/__tests__/installer-hooks.test.js.map +1 -0
- package/dist/__tests__/session-state-service.test.d.ts +2 -0
- package/dist/__tests__/session-state-service.test.d.ts.map +1 -0
- package/dist/__tests__/session-state-service.test.js +65 -0
- package/dist/__tests__/session-state-service.test.js.map +1 -0
- package/dist/constants/env.d.ts +1 -0
- package/dist/constants/env.d.ts.map +1 -1
- package/dist/constants/env.js +1 -0
- package/dist/constants/env.js.map +1 -1
- package/dist/constants/settings-paths.d.ts +2 -0
- package/dist/constants/settings-paths.d.ts.map +1 -1
- package/dist/constants/settings-paths.js +4 -0
- package/dist/constants/settings-paths.js.map +1 -1
- package/dist/constants/storage.d.ts +1 -0
- package/dist/constants/storage.d.ts.map +1 -1
- package/dist/constants/storage.js +1 -0
- package/dist/constants/storage.js.map +1 -1
- package/dist/gchat.d.ts +13 -0
- package/dist/gchat.d.ts.map +1 -1
- package/dist/gchat.js +93 -6
- package/dist/gchat.js.map +1 -1
- package/dist/hooks/cursor-hook.d.ts +3 -0
- package/dist/hooks/cursor-hook.d.ts.map +1 -0
- package/dist/hooks/cursor-hook.js +106 -0
- package/dist/hooks/cursor-hook.js.map +1 -0
- package/dist/index.js +30 -9
- package/dist/index.js.map +1 -1
- package/dist/schemas/tool-schemas.d.ts +19 -0
- package/dist/schemas/tool-schemas.d.ts.map +1 -1
- package/dist/schemas/tool-schemas.js +9 -0
- package/dist/schemas/tool-schemas.js.map +1 -1
- package/dist/services/inbox-poller.d.ts.map +1 -1
- package/dist/services/inbox-poller.js +1 -15
- package/dist/services/inbox-poller.js.map +1 -1
- package/dist/services/installer-service.d.ts +2 -0
- package/dist/services/installer-service.d.ts.map +1 -1
- package/dist/services/installer-service.js +79 -1
- package/dist/services/installer-service.js.map +1 -1
- package/dist/services/session-state-service.d.ts +16 -0
- package/dist/services/session-state-service.d.ts.map +1 -0
- package/dist/services/session-state-service.js +96 -0
- package/dist/services/session-state-service.js.map +1 -0
- package/dist/services/state-service.d.ts +2 -0
- package/dist/services/state-service.d.ts.map +1 -1
- package/dist/services/state-service.js +12 -0
- package/dist/services/state-service.js.map +1 -1
- package/dist/services/tool-handlers.d.ts +0 -2
- package/dist/services/tool-handlers.d.ts.map +1 -1
- package/dist/services/tool-handlers.js +11 -27
- package/dist/services/tool-handlers.js.map +1 -1
- package/dist/types/hook-input.d.ts +7 -0
- package/dist/types/hook-input.d.ts.map +1 -0
- package/dist/types/hook-input.js +2 -0
- package/dist/types/hook-input.js.map +1 -0
- package/dist/types/hook-response.d.ts +5 -0
- package/dist/types/hook-response.d.ts.map +1 -0
- package/dist/types/hook-response.js +2 -0
- package/dist/types/hook-response.js.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/parsed-command.d.ts +12 -3
- package/dist/types/parsed-command.d.ts.map +1 -1
- package/dist/types/parsed-error.d.ts +2 -1
- package/dist/types/parsed-error.d.ts.map +1 -1
- package/dist/types/session-state.d.ts +7 -0
- package/dist/types/session-state.d.ts.map +1 -0
- package/dist/types/session-state.js +2 -0
- package/dist/types/session-state.js.map +1 -0
- package/dist/{handlers/tool-handlers.d.ts → utils/notification-utils.d.ts} +3 -7
- package/dist/utils/notification-utils.d.ts.map +1 -0
- package/dist/utils/notification-utils.js +42 -0
- package/dist/utils/notification-utils.js.map +1 -0
- package/package.json +6 -1
- package/vitest.config.ts +7 -0
- package/dist/handlers/tool-handlers.d.ts.map +0 -1
- package/dist/handlers/tool-handlers.js +0 -198
- package/dist/handlers/tool-handlers.js.map +0 -1
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: Publish to npm
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
id-token: write
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
publish:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
environment: npm-publish
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- uses: actions/setup-node@v4
|
|
19
|
+
with:
|
|
20
|
+
node-version: 24
|
|
21
|
+
registry-url: https://registry.npmjs.org
|
|
22
|
+
|
|
23
|
+
- run: npm ci
|
|
24
|
+
- run: npm run build
|
|
25
|
+
- run: npm test
|
|
26
|
+
|
|
27
|
+
- name: Set version from tag
|
|
28
|
+
run: |
|
|
29
|
+
TAG="${GITHUB_REF_NAME#v}"
|
|
30
|
+
npm version "$TAG" --no-git-tag-version --allow-same-version
|
|
31
|
+
|
|
32
|
+
- run: npm publish --provenance --access public
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,48 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.1.3] - 2026-03-21
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `read_notifications` MCP tool for pull-based notification retrieval (replaces push-based inbox poller for Cursor)
|
|
13
|
+
- Cursor session lifecycle hooks: `sessionStart`, `sessionEnd`, `beforeMCPExecution` via `hooks.json`
|
|
14
|
+
- `SessionStateService` for per-PID session state management with in-memory cache and stale session reaping
|
|
15
|
+
- `cursor-join` and `cursor-leave` CLI commands for hook-driven agent registration
|
|
16
|
+
- `GC_CLIENT_TYPE` environment variable to disable push-based inbox poller when set to `cursor`
|
|
17
|
+
- `writeNotificationToParticipants` and `formatNotificationContent` extracted to `src/utils/notification-utils.ts`
|
|
18
|
+
- `readAndClearInbox` method on `StateService` for atomic inbox read-and-clear
|
|
19
|
+
- Cursor installer writes `hooks.json` with idempotent merge logic preserving existing non-group-chat-mcp hooks
|
|
20
|
+
- Cursor `mcp.json` entry now includes `GC_CLIENT_TYPE` and `GC_POLL_INTERVAL_MS` in env block
|
|
21
|
+
- 28 new tests across 5 test files covering session state, CLI commands, cursor hook, installer hooks, and read_notifications
|
|
22
|
+
- Vitest configuration (`vitest.config.ts`)
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- `ParsedCommand` changed from interface to discriminated union type with `cursor-join` and `cursor-leave` variants
|
|
27
|
+
- `ParsedError` extended with `missing-required-arg` variant and optional `message` field
|
|
28
|
+
- MCP server dynamically resolves agent ID from session state on each tool call (falls back to startup-registered ID)
|
|
29
|
+
- Inbox poller conditionally skipped when `GC_CLIENT_TYPE === 'cursor'`
|
|
30
|
+
- Vitest include updated to cover both `src/__tests__/` and `tests/` directories
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- `readStdin()` in cursor hook no longer leaks the timeout handle (added cleanup + `.unref()`)
|
|
35
|
+
- `--server-pid` validation rejects zero, negative, and non-integer values in both `cursor-join` and `cursor-leave`
|
|
36
|
+
- Existing installer tests updated to match new Cursor mcp.json format with `env` block
|
|
37
|
+
|
|
38
|
+
## [0.1.2] - 2026-03-21
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- npm auto-publish workflow on GitHub release
|
|
43
|
+
- `repository` URL in `package.json` for npm provenance verification
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
|
|
47
|
+
- CI pipeline: switched to Node 24 for npm OIDC Trusted Publishing support
|
|
48
|
+
- CI pipeline: resolved `NODE_AUTH_TOKEN` / OIDC auth conflicts for `npm publish`
|
|
49
|
+
|
|
8
50
|
## [0.1.1] - 2026-03-21
|
|
9
51
|
|
|
10
52
|
### Changed
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 appboypov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Group Chat MCP
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/group-chat-mcp)
|
|
4
|
+
[](https://github.com/appboypov/group-chat-mcp/blob/main/LICENSE)
|
|
5
|
+
[](https://www.typescriptlang.org/)
|
|
6
|
+
|
|
3
7
|
Multi-agent communication server using the Model Context Protocol. Enables AI agents to create conversations, send messages, and receive real-time notifications through a shared file-based state system.
|
|
4
8
|
|
|
5
9
|
## Features
|
|
@@ -7,6 +11,8 @@ Multi-agent communication server using the Model Context Protocol. Enables AI ag
|
|
|
7
11
|
- Real-time multi-agent messaging via MCP channel notifications
|
|
8
12
|
- Project-scoped and direct message conversations
|
|
9
13
|
- Automatic agent registration and cleanup per session
|
|
14
|
+
- Per-session agent lifecycle for Cursor via hooks (`sessionStart`, `sessionEnd`, `beforeMCPExecution`)
|
|
15
|
+
- Pull-based inbox for clients without push notification support (`read_notifications`)
|
|
10
16
|
- File-based shared state with atomic locking
|
|
11
17
|
- Zero-config setup via `gchat install`
|
|
12
18
|
|
|
@@ -40,7 +46,7 @@ The installer prompts for:
|
|
|
40
46
|
- **IDE**: Claude Code, Cursor, or Both
|
|
41
47
|
- **Scope**: Global (all projects) or Local (current project only)
|
|
42
48
|
|
|
43
|
-
For Claude Code, the installer registers the MCP server via `claude mcp add` (requires the Claude Code CLI on PATH). For Cursor, it writes the
|
|
49
|
+
For Claude Code, the installer registers the MCP server via `claude mcp add` (requires the Claude Code CLI on PATH). For Cursor, it writes `mcp.json` with the server entry and `hooks.json` with session lifecycle hooks that register and unregister agents per chat session.
|
|
44
50
|
|
|
45
51
|
To remove the configuration:
|
|
46
52
|
|
|
@@ -48,9 +54,9 @@ To remove the configuration:
|
|
|
48
54
|
gchat uninstall
|
|
49
55
|
```
|
|
50
56
|
|
|
51
|
-
###
|
|
57
|
+
### Claude Code: enable channel notifications
|
|
52
58
|
|
|
53
|
-
Channel notifications allow agents to receive messages in real-time as they arrive.
|
|
59
|
+
Channel notifications allow agents to receive messages in real-time as they arrive. Start your session with:
|
|
54
60
|
|
|
55
61
|
```bash
|
|
56
62
|
claude --dangerously-load-development-channels server:group-chat-mcp
|
|
@@ -58,6 +64,16 @@ claude --dangerously-load-development-channels server:group-chat-mcp
|
|
|
58
64
|
|
|
59
65
|
Without this flag, agents can still read messages by calling `get_conversation`, but incoming messages will not be injected into the conversation automatically.
|
|
60
66
|
|
|
67
|
+
### Cursor: session lifecycle
|
|
68
|
+
|
|
69
|
+
Cursor keeps MCP server processes alive across chat sessions. The installed hooks handle agent lifecycle automatically:
|
|
70
|
+
|
|
71
|
+
- **`sessionStart`** registers a new agent and joins the project conversation.
|
|
72
|
+
- **`sessionEnd`** leaves all conversations and unregisters the agent.
|
|
73
|
+
- **`beforeMCPExecution`** auto-approves group-chat-mcp tools and prompts for all other MCP servers.
|
|
74
|
+
|
|
75
|
+
Since Cursor does not support push notifications, agents use the `read_notifications` tool to poll for new messages.
|
|
76
|
+
|
|
61
77
|
## Usage
|
|
62
78
|
|
|
63
79
|
After setup, the MCP server starts automatically when your IDE launches a session. Each session:
|
|
@@ -65,7 +81,7 @@ After setup, the MCP server starts automatically when your IDE launches a sessio
|
|
|
65
81
|
1. Generates a unique agent ID
|
|
66
82
|
2. Registers the agent in the shared state
|
|
67
83
|
3. Joins the project conversation (one per project directory)
|
|
68
|
-
4. Polls for incoming notifications
|
|
84
|
+
4. Polls for incoming notifications (Claude Code) or exposes `read_notifications` (Cursor)
|
|
69
85
|
5. Cleans up on disconnect (leaves conversations, unregisters)
|
|
70
86
|
|
|
71
87
|
Multiple agents in the same project directory share a single project conversation.
|
|
@@ -158,12 +174,21 @@ Leave a conversation.
|
|
|
158
174
|
|
|
159
175
|
Returns confirmation. Notifies remaining participants.
|
|
160
176
|
|
|
177
|
+
### read_notifications
|
|
178
|
+
|
|
179
|
+
Check for new messages and notifications from other agents. Returns all pending notifications and clears the inbox. Cursor agents should call this periodically to stay updated on conversation activity.
|
|
180
|
+
|
|
181
|
+
No input parameters.
|
|
182
|
+
|
|
183
|
+
Returns pending notifications or `"No new notifications."` if the inbox is empty.
|
|
184
|
+
|
|
161
185
|
## Configuration
|
|
162
186
|
|
|
163
187
|
| Variable | Required | Default | Description |
|
|
164
188
|
|----------|----------|---------|-------------|
|
|
165
189
|
| GC_PROJECT_PATH | No | `process.cwd()` | Override the project directory path (must be an absolute path) |
|
|
166
|
-
| GC_POLL_INTERVAL_MS | No | `2000` | Inbox polling interval in milliseconds |
|
|
190
|
+
| GC_POLL_INTERVAL_MS | No | `2000` (`5000` for Cursor) | Inbox polling interval in milliseconds. The Cursor installer sets this to `5000` via the mcp.json env block. |
|
|
191
|
+
| GC_CLIENT_TYPE | No | — | Set to `"cursor"` to disable the push-based inbox poller (set automatically by the Cursor installer) |
|
|
167
192
|
|
|
168
193
|
## License
|
|
169
194
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-inbox.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/check-inbox.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import { StateService } from '../services/state-service.js';
|
|
6
|
+
import { handleToolCall } from '../services/tool-handlers.js';
|
|
7
|
+
import { NotificationType } from '../enums/notification-type.js';
|
|
8
|
+
import { writeJsonFile } from '../utils/file-utils.js';
|
|
9
|
+
import { formatNotificationContent } from '../utils/notification-utils.js';
|
|
10
|
+
let tmpDir;
|
|
11
|
+
let stateService;
|
|
12
|
+
beforeEach(async () => {
|
|
13
|
+
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'gchat-inbox-test-'));
|
|
14
|
+
stateService = new StateService(tmpDir);
|
|
15
|
+
await stateService.init();
|
|
16
|
+
});
|
|
17
|
+
afterEach(async () => {
|
|
18
|
+
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
19
|
+
});
|
|
20
|
+
describe('read_notifications', () => {
|
|
21
|
+
describe('Given 3 notifications in agent inbox', () => {
|
|
22
|
+
it('When read_notifications tool is called Then all 3 are returned', async () => {
|
|
23
|
+
const agent = await stateService.registerAgent('/test-project');
|
|
24
|
+
const inboxPath = path.join(tmpDir, 'inboxes', `${agent.id}.json`);
|
|
25
|
+
const notifications = [
|
|
26
|
+
{ id: 'n1', type: NotificationType.Message, conversationId: 'conv-1', agentId: 'sender-1', content: 'Hello', timestamp: Date.now() },
|
|
27
|
+
{ id: 'n2', type: NotificationType.Join, conversationId: 'conv-1', agentId: 'sender-2', content: 'sender-2 joined', timestamp: Date.now() },
|
|
28
|
+
{ id: 'n3', type: NotificationType.Leave, conversationId: 'conv-1', agentId: 'sender-3', content: 'sender-3 left', timestamp: Date.now() },
|
|
29
|
+
];
|
|
30
|
+
await writeJsonFile(inboxPath, notifications);
|
|
31
|
+
const result = await handleToolCall(stateService, 'read_notifications', agent.id, undefined);
|
|
32
|
+
const outputText = result.content[0].text;
|
|
33
|
+
const outputLines = outputText.split('\n');
|
|
34
|
+
const headerLine = outputLines[0];
|
|
35
|
+
const notificationLines = outputLines.slice(1).filter((line) => line.trim().length > 0);
|
|
36
|
+
expect(headerLine).toMatch(/^3 notification/);
|
|
37
|
+
expect(notificationLines.length).toBe(3);
|
|
38
|
+
});
|
|
39
|
+
it('When read_notifications tool is called Then inbox is empty after the call', async () => {
|
|
40
|
+
const agent = await stateService.registerAgent('/test-project');
|
|
41
|
+
const inboxPath = path.join(tmpDir, 'inboxes', `${agent.id}.json`);
|
|
42
|
+
const notifications = [
|
|
43
|
+
{ id: 'n1', type: NotificationType.Message, conversationId: 'conv-1', agentId: 'sender-1', content: 'Hello', timestamp: Date.now() },
|
|
44
|
+
{ id: 'n2', type: NotificationType.Join, conversationId: 'conv-1', agentId: 'sender-2', content: 'sender-2 joined', timestamp: Date.now() },
|
|
45
|
+
{ id: 'n3', type: NotificationType.Leave, conversationId: 'conv-1', agentId: 'sender-3', content: 'sender-3 left', timestamp: Date.now() },
|
|
46
|
+
];
|
|
47
|
+
await writeJsonFile(inboxPath, notifications);
|
|
48
|
+
await handleToolCall(stateService, 'read_notifications', agent.id, undefined);
|
|
49
|
+
const raw = await fs.readFile(inboxPath, 'utf-8');
|
|
50
|
+
const remaining = JSON.parse(raw);
|
|
51
|
+
expect(remaining).toEqual([]);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
describe('Given empty inbox', () => {
|
|
55
|
+
it('When read_notifications tool is called Then result indicates no notifications and inbox remains empty', async () => {
|
|
56
|
+
const agent = await stateService.registerAgent('/test-project');
|
|
57
|
+
const result = await handleToolCall(stateService, 'read_notifications', agent.id, undefined);
|
|
58
|
+
expect(result.content).toBeDefined();
|
|
59
|
+
expect(result.content.length).toBeGreaterThan(0);
|
|
60
|
+
expect('isError' in result).toBe(false);
|
|
61
|
+
const inbox = await stateService.getInbox(agent.id);
|
|
62
|
+
expect(inbox).toEqual([]);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
describe('Given agent has notifications', () => {
|
|
66
|
+
it('When read_notifications is called Then notifications are formatted using the same format as the inbox poller', async () => {
|
|
67
|
+
const agent = await stateService.registerAgent('/test-project');
|
|
68
|
+
const inboxPath = path.join(tmpDir, 'inboxes', `${agent.id}.json`);
|
|
69
|
+
const notifications = [
|
|
70
|
+
{ id: 'n1', type: NotificationType.Message, conversationId: 'conv-1', agentId: 'sender-1', content: 'Hello', timestamp: Date.now() },
|
|
71
|
+
{ id: 'n2', type: NotificationType.Join, conversationId: 'conv-1', agentId: 'sender-2', content: 'sender-2 joined', timestamp: Date.now() },
|
|
72
|
+
{ id: 'n3', type: NotificationType.Leave, conversationId: 'conv-1', agentId: 'sender-3', content: 'sender-3 left', timestamp: Date.now() },
|
|
73
|
+
];
|
|
74
|
+
await writeJsonFile(inboxPath, notifications);
|
|
75
|
+
const result = await handleToolCall(stateService, 'read_notifications', agent.id, undefined);
|
|
76
|
+
const outputText = result.content[0].text;
|
|
77
|
+
const outputLines = outputText.split('\n').slice(1);
|
|
78
|
+
for (let i = 0; i < notifications.length; i++) {
|
|
79
|
+
const expected = formatNotificationContent(notifications[i]);
|
|
80
|
+
expect(outputLines[i]).toBe(expected);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
//# sourceMappingURL=check-inbox.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-inbox.test.js","sourceRoot":"","sources":["../../src/__tests__/check-inbox.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-session-commands.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/cli-session-commands.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import { StateService } from '../services/state-service.js';
|
|
6
|
+
import { SessionStateService } from '../services/session-state-service.js';
|
|
7
|
+
import { handleCursorJoin, handleCursorLeave } from '../gchat.js';
|
|
8
|
+
import { ConversationType } from '../enums/conversation-type.js';
|
|
9
|
+
import { NotificationType } from '../enums/notification-type.js';
|
|
10
|
+
import { INBOXES_DIR } from '../constants/storage.js';
|
|
11
|
+
const UUID_V4_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
12
|
+
let tmpDir;
|
|
13
|
+
let stateService;
|
|
14
|
+
let sessionStateService;
|
|
15
|
+
beforeEach(async () => {
|
|
16
|
+
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'gchat-cli-test-'));
|
|
17
|
+
stateService = new StateService(tmpDir);
|
|
18
|
+
await stateService.init();
|
|
19
|
+
sessionStateService = new SessionStateService(tmpDir);
|
|
20
|
+
});
|
|
21
|
+
afterEach(async () => {
|
|
22
|
+
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
23
|
+
});
|
|
24
|
+
describe('cursor-join', () => {
|
|
25
|
+
describe('Given project path and server PID', () => {
|
|
26
|
+
it('When cursor-join is called Then an agent UUID and conversation UUID are returned', async () => {
|
|
27
|
+
const projectPath = '/test-project';
|
|
28
|
+
const serverPid = 12345;
|
|
29
|
+
const result = await handleCursorJoin(projectPath, serverPid, { stateService, sessionStateService });
|
|
30
|
+
expect(result.agentId).toMatch(UUID_V4_REGEX);
|
|
31
|
+
expect(result.conversationId).toMatch(UUID_V4_REGEX);
|
|
32
|
+
});
|
|
33
|
+
it('When cursor-join is called Then the agent is registered and session state is written', async () => {
|
|
34
|
+
const projectPath = '/test-project';
|
|
35
|
+
const serverPid = 12345;
|
|
36
|
+
const result = await handleCursorJoin(projectPath, serverPid, { stateService, sessionStateService });
|
|
37
|
+
const registeredAgent = await stateService.getAgent(result.agentId);
|
|
38
|
+
expect(registeredAgent).not.toBeNull();
|
|
39
|
+
expect(registeredAgent.projectPath).toBe(projectPath);
|
|
40
|
+
const sessionResult = await sessionStateService.readSessionAgent(serverPid);
|
|
41
|
+
expect(sessionResult).toEqual({ agentId: result.agentId, projectPath });
|
|
42
|
+
});
|
|
43
|
+
it('When cursor-join is called Then the agent is a participant in the project conversation', async () => {
|
|
44
|
+
const projectPath = '/test-project';
|
|
45
|
+
const serverPid = 12345;
|
|
46
|
+
const result = await handleCursorJoin(projectPath, serverPid, { stateService, sessionStateService });
|
|
47
|
+
const conversation = await stateService.getConversation(result.conversationId);
|
|
48
|
+
expect(conversation).not.toBeNull();
|
|
49
|
+
expect(conversation.participants).toContain(result.agentId);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
describe('Given project path with existing conversation and 1 participant', () => {
|
|
53
|
+
it('When cursor-join is called Then a join notification is written to the existing participant inbox', async () => {
|
|
54
|
+
const projectPath = '/test-project';
|
|
55
|
+
const agentA = await stateService.registerAgent(projectPath);
|
|
56
|
+
const conversation = await stateService.getOrCreateProjectConversation(projectPath);
|
|
57
|
+
await stateService.joinConversation(agentA.id, conversation.id);
|
|
58
|
+
const serverPidB = 54321;
|
|
59
|
+
const result = await handleCursorJoin(projectPath, serverPidB, { stateService, sessionStateService });
|
|
60
|
+
const inboxPath = path.join(tmpDir, INBOXES_DIR, `${agentA.id}.json`);
|
|
61
|
+
let notifications = [];
|
|
62
|
+
try {
|
|
63
|
+
const raw = await fs.readFile(inboxPath, 'utf-8');
|
|
64
|
+
notifications = JSON.parse(raw);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
notifications = [];
|
|
68
|
+
}
|
|
69
|
+
const joinNotification = notifications.find((n) => n.type === NotificationType.Join && n.agentId === result.agentId);
|
|
70
|
+
expect(joinNotification).toBeDefined();
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
describe('cursor-leave', () => {
|
|
75
|
+
describe('Given agent X registered with PID 1234', () => {
|
|
76
|
+
it('When cursor-leave is called Then X is unregistered and session state is cleared', async () => {
|
|
77
|
+
const projectPath = '/test-project';
|
|
78
|
+
const serverPid = 1234;
|
|
79
|
+
const joinResult = await handleCursorJoin(projectPath, serverPid, { stateService, sessionStateService });
|
|
80
|
+
await handleCursorLeave(serverPid, { stateService, sessionStateService });
|
|
81
|
+
const registeredAgent = await stateService.getAgent(joinResult.agentId);
|
|
82
|
+
expect(registeredAgent).toBeNull();
|
|
83
|
+
const sessionResult = await sessionStateService.readSessionAgent(serverPid);
|
|
84
|
+
expect(sessionResult).toBeNull();
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
describe('Given no session state for PID 9999', () => {
|
|
88
|
+
it('When cursor-leave is called Then no error is thrown', async () => {
|
|
89
|
+
await expect(handleCursorLeave(9999, { stateService, sessionStateService })).resolves.toBeUndefined();
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
describe('Given agent X in conversation with agent Y', () => {
|
|
93
|
+
it('When cursor-leave is called for X Then Y has a leave notification in its inbox', async () => {
|
|
94
|
+
const projectPath = '/test-project';
|
|
95
|
+
const serverPidX = 1234;
|
|
96
|
+
const serverPidY = 5678;
|
|
97
|
+
const resultY = await handleCursorJoin(projectPath, serverPidY, { stateService, sessionStateService });
|
|
98
|
+
const resultX = await handleCursorJoin(projectPath, serverPidX, { stateService, sessionStateService });
|
|
99
|
+
await handleCursorLeave(serverPidX, { stateService, sessionStateService });
|
|
100
|
+
const inboxPath = path.join(tmpDir, INBOXES_DIR, `${resultY.agentId}.json`);
|
|
101
|
+
let notifications = [];
|
|
102
|
+
try {
|
|
103
|
+
const raw = await fs.readFile(inboxPath, 'utf-8');
|
|
104
|
+
notifications = JSON.parse(raw);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
notifications = [];
|
|
108
|
+
}
|
|
109
|
+
const leaveNotification = notifications.find((n) => n.type === NotificationType.Leave && n.agentId === resultX.agentId);
|
|
110
|
+
expect(leaveNotification).toBeDefined();
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
describe('Given agent X in 2 conversations with server PID', () => {
|
|
114
|
+
it('When cursor-leave is called Then X is removed from both conversations and unregistered', async () => {
|
|
115
|
+
const projectPath = '/test-project';
|
|
116
|
+
const serverPid = 1234;
|
|
117
|
+
const joinResult = await handleCursorJoin(projectPath, serverPid, { stateService, sessionStateService });
|
|
118
|
+
const secondConversation = await stateService.createConversation({
|
|
119
|
+
type: ConversationType.Group,
|
|
120
|
+
name: 'Second conversation',
|
|
121
|
+
participants: [joinResult.agentId],
|
|
122
|
+
});
|
|
123
|
+
await handleCursorLeave(serverPid, { stateService, sessionStateService });
|
|
124
|
+
const agent = await stateService.getAgent(joinResult.agentId);
|
|
125
|
+
expect(agent).toBeNull();
|
|
126
|
+
const conv1 = await stateService.getConversation(joinResult.conversationId);
|
|
127
|
+
expect(conv1.participants).not.toContain(joinResult.agentId);
|
|
128
|
+
const conv2 = await stateService.getConversation(secondConversation.id);
|
|
129
|
+
expect(conv2.participants).not.toContain(joinResult.agentId);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
describe('Given agent X as sole participant in conversation C', () => {
|
|
133
|
+
it('When cursor-leave is called Then conversation C is archived', async () => {
|
|
134
|
+
const projectPath = '/test-project';
|
|
135
|
+
const serverPid = 1234;
|
|
136
|
+
const joinResult = await handleCursorJoin(projectPath, serverPid, { stateService, sessionStateService });
|
|
137
|
+
await handleCursorLeave(serverPid, { stateService, sessionStateService });
|
|
138
|
+
const conversation = await stateService.getConversation(joinResult.conversationId);
|
|
139
|
+
expect(conversation).not.toBeNull();
|
|
140
|
+
expect(conversation.archivedAt).toBeDefined();
|
|
141
|
+
expect(typeof conversation.archivedAt).toBe('number');
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
//# sourceMappingURL=cli-session-commands.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-session-commands.test.js","sourceRoot":"","sources":["../../src/__tests__/cli-session-commands.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAGtD,MAAM,aAAa,GAAG,iEAAiE,CAAC;AAExF,IAAI,MAAc,CAAC;AACnB,IAAI,YAA0B,CAAC;AAC/B,IAAI,mBAAwC,CAAC;AAE7C,UAAU,CAAC,KAAK,IAAI,EAAE;IACpB,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC;IACrE,YAAY,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,YAAY,CAAC,IAAI,EAAE,CAAC;IAC1B,mBAAmB,GAAG,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAC;AACxD,CAAC,CAAC,CAAC;AAEH,SAAS,CAAC,KAAK,IAAI,EAAE;IACnB,MAAM,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AACxD,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,QAAQ,CAAC,mCAAmC,EAAE,GAAG,EAAE;QACjD,EAAE,CAAC,kFAAkF,EAAE,KAAK,IAAI,EAAE;YAChG,MAAM,WAAW,GAAG,eAAe,CAAC;YACpC,MAAM,SAAS,GAAG,KAAK,CAAC;YAExB,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,WAAW,EAAE,SAAS,EAAE,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAC,CAAC;YAErG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;YAC9C,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sFAAsF,EAAE,KAAK,IAAI,EAAE;YACpG,MAAM,WAAW,GAAG,eAAe,CAAC;YACpC,MAAM,SAAS,GAAG,KAAK,CAAC;YAExB,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,WAAW,EAAE,SAAS,EAAE,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAC,CAAC;YAErG,MAAM,eAAe,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACpE,MAAM,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;YACvC,MAAM,CAAC,eAAgB,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAEvD,MAAM,aAAa,GAAG,MAAM,mBAAmB,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;YAC5E,MAAM,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;QAC1E,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wFAAwF,EAAE,KAAK,IAAI,EAAE;YACtG,MAAM,WAAW,GAAG,eAAe,CAAC;YACpC,MAAM,SAAS,GAAG,KAAK,CAAC;YAExB,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,WAAW,EAAE,SAAS,EAAE,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAC,CAAC;YAErG,MAAM,YAAY,GAAG,MAAM,YAAY,CAAC,eAAe,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;YAC/E,MAAM,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;YACpC,MAAM,CAAC,YAAa,CAAC,YAAY,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,iEAAiE,EAAE,GAAG,EAAE;QAC/E,EAAE,CAAC,kGAAkG,EAAE,KAAK,IAAI,EAAE;YAChH,MAAM,WAAW,GAAG,eAAe,CAAC;YAEpC,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;YAC7D,MAAM,YAAY,GAAG,MAAM,YAAY,CAAC,8BAA8B,CAAC,WAAW,CAAC,CAAC;YACpF,MAAM,YAAY,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,EAAE,YAAY,CAAC,EAAE,CAAC,CAAC;YAEhE,MAAM,UAAU,GAAG,KAAK,CAAC;YACzB,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,WAAW,EAAE,UAAU,EAAE,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAC,CAAC;YAEtG,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;YACtE,IAAI,aAAa,GAAmB,EAAE,CAAC;YACvC,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;gBAClD,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAmB,CAAC;YACpD,CAAC;YAAC,MAAM,CAAC;gBACP,aAAa,GAAG,EAAE,CAAC;YACrB,CAAC;YAED,MAAM,gBAAgB,GAAG,aAAa,CAAC,IAAI,CACzC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,gBAAgB,CAAC,IAAI,IAAI,CAAC,CAAC,OAAO,KAAK,MAAM,CAAC,OAAO,CACxE,CAAC;YACF,MAAM,CAAC,gBAAgB,CAAC,CAAC,WAAW,EAAE,CAAC;QACzC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,QAAQ,CAAC,wCAAwC,EAAE,GAAG,EAAE;QACtD,EAAE,CAAC,iFAAiF,EAAE,KAAK,IAAI,EAAE;YAC/F,MAAM,WAAW,GAAG,eAAe,CAAC;YACpC,MAAM,SAAS,GAAG,IAAI,CAAC;YAEvB,MAAM,UAAU,GAAG,MAAM,gBAAgB,CAAC,WAAW,EAAE,SAAS,EAAE,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAC,CAAC;YAEzG,MAAM,iBAAiB,CAAC,SAAS,EAAE,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAC,CAAC;YAE1E,MAAM,eAAe,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YACxE,MAAM,CAAC,eAAe,CAAC,CAAC,QAAQ,EAAE,CAAC;YAEnC,MAAM,aAAa,GAAG,MAAM,mBAAmB,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;YAC5E,MAAM,CAAC,aAAa,CAAC,CAAC,QAAQ,EAAE,CAAC;QACnC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,qCAAqC,EAAE,GAAG,EAAE;QACnD,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;YACnE,MAAM,MAAM,CACV,iBAAiB,CAAC,IAAI,EAAE,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAC,CAC/D,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;QAC7B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,4CAA4C,EAAE,GAAG,EAAE;QAC1D,EAAE,CAAC,gFAAgF,EAAE,KAAK,IAAI,EAAE;YAC9F,MAAM,WAAW,GAAG,eAAe,CAAC;YACpC,MAAM,UAAU,GAAG,IAAI,CAAC;YACxB,MAAM,UAAU,GAAG,IAAI,CAAC;YAExB,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,WAAW,EAAE,UAAU,EAAE,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAC,CAAC;YACvG,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,WAAW,EAAE,UAAU,EAAE,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAC,CAAC;YAEvG,MAAM,iBAAiB,CAAC,UAAU,EAAE,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAC,CAAC;YAE3E,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,OAAO,OAAO,CAAC,CAAC;YAC5E,IAAI,aAAa,GAAmB,EAAE,CAAC;YACvC,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;gBAClD,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAmB,CAAC;YACpD,CAAC;YAAC,MAAM,CAAC;gBACP,aAAa,GAAG,EAAE,CAAC;YACrB,CAAC;YAED,MAAM,iBAAiB,GAAG,aAAa,CAAC,IAAI,CAC1C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,gBAAgB,CAAC,KAAK,IAAI,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,CAC1E,CAAC;YACF,MAAM,CAAC,iBAAiB,CAAC,CAAC,WAAW,EAAE,CAAC;QAC1C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAChE,EAAE,CAAC,wFAAwF,EAAE,KAAK,IAAI,EAAE;YACtG,MAAM,WAAW,GAAG,eAAe,CAAC;YACpC,MAAM,SAAS,GAAG,IAAI,CAAC;YAEvB,MAAM,UAAU,GAAG,MAAM,gBAAgB,CAAC,WAAW,EAAE,SAAS,EAAE,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAC,CAAC;YAEzG,MAAM,kBAAkB,GAAG,MAAM,YAAY,CAAC,kBAAkB,CAAC;gBAC/D,IAAI,EAAE,gBAAgB,CAAC,KAAK;gBAC5B,IAAI,EAAE,qBAAqB;gBAC3B,YAAY,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC;aACnC,CAAC,CAAC;YAEH,MAAM,iBAAiB,CAAC,SAAS,EAAE,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAC,CAAC;YAE1E,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YAC9D,MAAM,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC;YAEzB,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,eAAe,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;YAC5E,MAAM,CAAC,KAAM,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YAE9D,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,eAAe,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;YACxE,MAAM,CAAC,KAAM,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,qDAAqD,EAAE,GAAG,EAAE;QACnE,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;YAC3E,MAAM,WAAW,GAAG,eAAe,CAAC;YACpC,MAAM,SAAS,GAAG,IAAI,CAAC;YAEvB,MAAM,UAAU,GAAG,MAAM,gBAAgB,CAAC,WAAW,EAAE,SAAS,EAAE,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAC,CAAC;YAEzG,MAAM,iBAAiB,CAAC,SAAS,EAAE,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAC,CAAC;YAE1E,MAAM,YAAY,GAAG,MAAM,YAAY,CAAC,eAAe,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;YACnF,MAAM,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;YACpC,MAAM,CAAC,YAAa,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,CAAC;YAC/C,MAAM,CAAC,OAAO,YAAa,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor-hook.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/cursor-hook.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll } from 'vitest';
|
|
2
|
+
import { spawnSync, execFileSync } from 'node:child_process';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const HOOK_PATH = path.resolve(__dirname, '../../dist/hooks/cursor-hook.js');
|
|
7
|
+
const TEST_TIMEOUT = 15000;
|
|
8
|
+
beforeAll(() => {
|
|
9
|
+
execFileSync('npm', ['run', 'build'], {
|
|
10
|
+
cwd: path.resolve(__dirname, '../..'),
|
|
11
|
+
encoding: 'utf-8',
|
|
12
|
+
timeout: 30000,
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
function runHook(input) {
|
|
16
|
+
const result = spawnSync('node', [HOOK_PATH], {
|
|
17
|
+
input,
|
|
18
|
+
encoding: 'utf-8',
|
|
19
|
+
timeout: 10000,
|
|
20
|
+
});
|
|
21
|
+
if (result.error) {
|
|
22
|
+
throw result.error;
|
|
23
|
+
}
|
|
24
|
+
return JSON.parse(result.stdout.trim());
|
|
25
|
+
}
|
|
26
|
+
describe('cursor-hook', () => {
|
|
27
|
+
describe('Given stdin JSON with hook_event_name beforeMCPExecution and server group-chat-mcp', () => {
|
|
28
|
+
it('Then stdout contains permission allow', () => {
|
|
29
|
+
const response = runHook(JSON.stringify({
|
|
30
|
+
hook_event_name: 'beforeMCPExecution',
|
|
31
|
+
server: 'group-chat-mcp',
|
|
32
|
+
}));
|
|
33
|
+
expect(response.permission).toBe('allow');
|
|
34
|
+
}, TEST_TIMEOUT);
|
|
35
|
+
});
|
|
36
|
+
describe('Given stdin JSON with hook_event_name beforeMCPExecution and server some-other-mcp', () => {
|
|
37
|
+
it('Then stdout contains permission ask', () => {
|
|
38
|
+
const response = runHook(JSON.stringify({
|
|
39
|
+
hook_event_name: 'beforeMCPExecution',
|
|
40
|
+
server: 'some-other-mcp',
|
|
41
|
+
}));
|
|
42
|
+
expect(response.permission).toBe('ask');
|
|
43
|
+
}, TEST_TIMEOUT);
|
|
44
|
+
});
|
|
45
|
+
describe('Given invalid JSON on stdin', () => {
|
|
46
|
+
it('When the hook script runs Then it outputs permission allow', () => {
|
|
47
|
+
const response = runHook('not-valid-json{{{');
|
|
48
|
+
expect(response.permission).toBe('allow');
|
|
49
|
+
}, TEST_TIMEOUT);
|
|
50
|
+
});
|
|
51
|
+
describe('Given unknown hook_event_name', () => {
|
|
52
|
+
it('When the hook script runs Then it outputs permission allow', () => {
|
|
53
|
+
const response = runHook(JSON.stringify({
|
|
54
|
+
hook_event_name: 'unknownEvent',
|
|
55
|
+
}));
|
|
56
|
+
expect(response.permission).toBe('allow');
|
|
57
|
+
}, TEST_TIMEOUT);
|
|
58
|
+
});
|
|
59
|
+
describe('Given stdin JSON with hook_event_name sessionEnd', () => {
|
|
60
|
+
it('Then stdout contains permission allow', () => {
|
|
61
|
+
const response = runHook(JSON.stringify({
|
|
62
|
+
hook_event_name: 'sessionEnd',
|
|
63
|
+
}));
|
|
64
|
+
expect(response.permission).toBe('allow');
|
|
65
|
+
}, TEST_TIMEOUT);
|
|
66
|
+
});
|
|
67
|
+
describe('Given stdin JSON with hook_event_name sessionStart and workspace_roots', () => {
|
|
68
|
+
it('Then it registers an agent and stdout contains permission allow with agent_message', () => {
|
|
69
|
+
const response = runHook(JSON.stringify({
|
|
70
|
+
hook_event_name: 'sessionStart',
|
|
71
|
+
workspace_roots: ['/tmp/test-project-hook'],
|
|
72
|
+
}));
|
|
73
|
+
expect(response.permission).toBe('allow');
|
|
74
|
+
expect(response.agent_message).toBeDefined();
|
|
75
|
+
expect(response.agent_message.length).toBeGreaterThan(0);
|
|
76
|
+
}, TEST_TIMEOUT);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
//# sourceMappingURL=cursor-hook.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor-hook.test.js","sourceRoot":"","sources":["../../src/__tests__/cursor-hook.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installer-hooks.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/installer-hooks.test.ts"],"names":[],"mappings":""}
|