hivecode-mcp 0.14.0 → 0.14.2

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 (72) hide show
  1. package/HIVE_RULES.md +98 -98
  2. package/LICENSE +21 -21
  3. package/README.md +421 -421
  4. package/core.js +91 -91
  5. package/docs/ALWAYS_ON.md +310 -310
  6. package/docs/GITHUB_WORKFLOW.md +394 -394
  7. package/docs/HIVE_RULES.md +41 -41
  8. package/docs/MCP.md +157 -157
  9. package/docs/QUICKSTART.md +266 -266
  10. package/docs/SELF_HOSTING.md +256 -256
  11. package/docs/SLACK_SETUP.md +474 -450
  12. package/docs/TROUBLESHOOTING.md +105 -105
  13. package/hive-activity.js +336 -336
  14. package/hive-authors.js +46 -44
  15. package/hive-await.js +230 -230
  16. package/hive-branch.js +608 -607
  17. package/hive-busy.js +88 -88
  18. package/hive-coord.js +110 -110
  19. package/hive-gate.js +135 -135
  20. package/hive-github.js +2004 -1944
  21. package/hive-hook-install.js +179 -179
  22. package/hive-instructions.js +74 -74
  23. package/hive-land.js +695 -691
  24. package/hive-listen.js +81 -81
  25. package/hive-mailbox.js +520 -520
  26. package/hive-mcp-http.js +591 -580
  27. package/hive-mcp.js +2156 -2093
  28. package/hive-mux-proto.js +58 -58
  29. package/hive-mux.js +351 -350
  30. package/hive-notify.js +234 -233
  31. package/hive-obligations.js +247 -247
  32. package/hive-poll-proto.js +50 -50
  33. package/hive-pr-staleness.js +189 -189
  34. package/hive-pr.js +600 -512
  35. package/hive-privacy.js +327 -327
  36. package/hive-receipts.js +233 -233
  37. package/hive-relay-health.js +234 -230
  38. package/hive-repos.js +430 -430
  39. package/hive-room-key.js +210 -209
  40. package/hive-room-mode.js +1668 -1668
  41. package/hive-room-watcher.js +562 -561
  42. package/hive-secrets.js +89 -89
  43. package/hive-session.js +114 -114
  44. package/hive-setup.js +560 -558
  45. package/hive-slack-agent.js +408 -396
  46. package/hive-slack.js +2384 -1809
  47. package/hive-stdio.js +172 -172
  48. package/hive-stop-hook.js +293 -293
  49. package/hive-throttle.js +118 -118
  50. package/hive-time.js +71 -71
  51. package/hive-transport.js +578 -353
  52. package/hive-update.js +58 -58
  53. package/hive-version.js +110 -110
  54. package/hive-webhook.js +55 -54
  55. package/icr-merge.js +58 -58
  56. package/icr.js +851 -851
  57. package/lang-brace.js +305 -305
  58. package/lang-js.js +651 -651
  59. package/lang-json.js +211 -211
  60. package/lang-python.js +588 -588
  61. package/lang-ruby.js +230 -230
  62. package/lang-toml.js +136 -136
  63. package/lang-yaml.js +183 -183
  64. package/limits.js +413 -413
  65. package/package.json +192 -192
  66. package/reconcile.cjs +621 -614
  67. package/slack-app-manifest-agent.json +61 -61
  68. package/slack-app-manifest-inbound.json +36 -36
  69. package/slack-app-manifest.json +27 -27
  70. package/substrate.js +252 -252
  71. package/sync.js +5189 -4994
  72. package/token.js +201 -201
package/hive-stdio.js CHANGED
@@ -1,172 +1,172 @@
1
- // hive-stdio.js -- the MCP stdio server Hivecode actually needs, without the SDK's web stack.
2
- //
3
- // WHY THIS EXISTS. @modelcontextprotocol/sdk is a client AND a server AND three HTTP transports,
4
- // so installing it installs express, hono, cors, jose, zod, ajv and ~85 other packages -- 25 MB,
5
- // most of a stranger's first `npx hivecode-mcp` download (36.7s measured cold, 25 Sep 2026). A
6
- // load trace of a full session (join, claim, write, release, say, wait) showed the client uses
7
- // exactly one slice of it: newline-delimited JSON-RPC over stdin/stdout, `initialize`, `ping`,
8
- // `tools/list`, `tools/call`, and two outgoing notifications. That slice is this file.
9
- //
10
- // IT MUST BEHAVE EXACTLY LIKE THE SDK WHERE A CLIENT CAN TELL. The SDK is still a devDependency,
11
- // and tests/mcp-conformance-test.mjs drives this server with the SDK's own CLIENT -- the one
12
- // Claude Code and the Gemini CLI are built on. Specifically, as in the SDK (1.30):
13
- // - protocol version: echo the client's if supported, else answer with the newest we know;
14
- // - `ping` -> {}; an unknown method -> error -32601; a handler that throws -> its own numeric
15
- // `code` if it has one, else -32603, with the error's message;
16
- // - a request the client CANCELLED gets no response (the spec: "SHOULD NOT send a response");
17
- // - a line that is not JSON is logged to stderr and otherwise ignored, never answered.
18
- // And one thing the SDK does not do: when stdin closes, the server says so (onclose), so the
19
- // process can EXIT. The spec asks exactly that of a stdio server; the SDK left it running, and a
20
- // Hivecode server that outlives its agent app keeps a seat in the room for a member who is gone.
21
-
22
- export const LATEST_PROTOCOL_VERSION = '2025-11-25'
23
- export const SUPPORTED_PROTOCOL_VERSIONS = [LATEST_PROTOCOL_VERSION, '2025-06-18', '2025-03-26', '2024-11-05', '2024-10-07']
24
-
25
- // Same shape hive-mcp.js used to import from '@modelcontextprotocol/sdk/types.js': something
26
- // setRequestHandler can take the method name from.
27
- export const ListToolsRequestSchema = Object.freeze({ method: 'tools/list' })
28
- export const CallToolRequestSchema = Object.freeze({ method: 'tools/call' })
29
-
30
- const METHOD_NOT_FOUND = -32601
31
- const INVALID_PARAMS = -32602
32
- const INTERNAL_ERROR = -32603
33
-
34
- export class Server {
35
- constructor(serverInfo, { capabilities = {}, instructions } = {}) {
36
- this._serverInfo = serverInfo
37
- this._capabilities = capabilities
38
- this._instructions = instructions
39
- // Keyed by method, called as handler(request, extra) -- the SDK's own internal shape, which
40
- // the test seam in hive-mcp.js reaches into on purpose.
41
- this._requestHandlers = new Map()
42
- this._transport = null
43
- this._inflight = new Map() // request id -> AbortController, so a cancel can find it
44
- this.onclose = null
45
- this.oninitialized = null
46
- this._clientInfo = null // who connected: the app's name and version, from initialize
47
- this._requestHandlers.set('initialize', (req) => {
48
- const requested = req.params && req.params.protocolVersion
49
- this._clientInfo = (req.params && req.params.clientInfo) || null
50
- return {
51
- protocolVersion: SUPPORTED_PROTOCOL_VERSIONS.includes(requested) ? requested : LATEST_PROTOCOL_VERSION,
52
- capabilities: this._capabilities,
53
- serverInfo: this._serverInfo,
54
- ...(this._instructions ? { instructions: this._instructions } : {}),
55
- }
56
- })
57
- this._requestHandlers.set('ping', () => ({}))
58
- }
59
- /** The connecting app's clientInfo ({ name, version }), as the SDK's Server exposes it. */
60
- getClientVersion() { return this._clientInfo || undefined }
61
-
62
- setRequestHandler(schema, handler) {
63
- const method = typeof schema === 'string' ? schema : schema && schema.method
64
- if (!method) throw new Error('setRequestHandler needs a method')
65
- this._requestHandlers.set(method, handler)
66
- }
67
-
68
- async connect(transport) {
69
- this._transport = transport
70
- transport.onmessage = (msg) => this._onmessage(msg)
71
- transport.onclose = () => { this._transport = null; if (this.onclose) this.onclose() }
72
- await transport.start()
73
- }
74
-
75
- /** Send a notification to the client. Rejects when there is nobody to send it to. */
76
- notification({ method, params }) {
77
- if (!this._transport) return Promise.reject(new Error('Not connected'))
78
- return this._transport.send({ jsonrpc: '2.0', method, ...(params !== undefined ? { params } : {}) })
79
- }
80
-
81
- _onmessage(msg) {
82
- if (Array.isArray(msg)) {
83
- // JSON-RPC batches: the 2025-03-26 revision allowed them. Answer each request in the batch;
84
- // the replies go back one per line, which every client matches by id.
85
- for (const m of msg) this._onmessage(m)
86
- return
87
- }
88
- if (!msg || typeof msg !== 'object' || msg.jsonrpc !== '2.0') return
89
- if (msg.method === undefined) return // a response to a request we never send
90
- if (msg.id === undefined || msg.id === null) return this._onnotification(msg)
91
- this._onrequest(msg)
92
- }
93
-
94
- _onnotification(msg) {
95
- if (msg.method === 'notifications/initialized') { if (this.oninitialized) this.oninitialized(); return }
96
- if (msg.method === 'notifications/cancelled') {
97
- const id = msg.params && msg.params.requestId
98
- const ac = this._inflight.get(id)
99
- if (ac) ac.abort()
100
- }
101
- // every other notification is ignorable by spec
102
- }
103
-
104
- async _onrequest(msg) {
105
- const { id, method } = msg
106
- const handler = this._requestHandlers.get(method)
107
- if (!handler) return this._reply({ jsonrpc: '2.0', id, error: { code: METHOD_NOT_FOUND, message: 'Method not found' } })
108
- if (method === 'tools/call' && (!msg.params || typeof msg.params !== 'object' || typeof msg.params.name !== 'string')) {
109
- return this._reply({ jsonrpc: '2.0', id, error: { code: INVALID_PARAMS, message: 'tools/call needs params.name' } })
110
- }
111
- const ac = new AbortController()
112
- this._inflight.set(id, ac)
113
- let reply
114
- try {
115
- const result = await handler({ method, params: msg.params }, { signal: ac.signal, requestId: id })
116
- reply = { jsonrpc: '2.0', id, result: result === undefined ? {} : result }
117
- } catch (e) {
118
- const code = e && Number.isSafeInteger(e.code) ? e.code : INTERNAL_ERROR
119
- reply = { jsonrpc: '2.0', id, error: { code, message: (e && e.message) || 'Internal error' } }
120
- } finally {
121
- this._inflight.delete(id)
122
- }
123
- if (ac.signal.aborted) return // cancelled by the client: it is no longer waiting for this
124
- this._reply(reply)
125
- }
126
-
127
- _reply(message) {
128
- if (!this._transport) return
129
- Promise.resolve(this._transport.send(message)).catch((e) => process.stderr.write(`[hive-stdio] could not reply: ${e && e.message}\n`))
130
- }
131
- }
132
-
133
- export class StdioServerTransport {
134
- constructor(stdin = process.stdin, stdout = process.stdout) {
135
- this._stdin = stdin
136
- this._stdout = stdout
137
- this._buf = ''
138
- this._closed = false
139
- this.onmessage = null
140
- this.onclose = null
141
- }
142
-
143
- async start() {
144
- this._stdin.setEncoding('utf8') // a multi-byte character split across two chunks stays whole
145
- this._stdin.on('data', (chunk) => {
146
- this._buf += chunk
147
- let i
148
- while ((i = this._buf.indexOf('\n')) >= 0) {
149
- const line = this._buf.slice(0, i).replace(/\r$/, '')
150
- this._buf = this._buf.slice(i + 1)
151
- if (!line.trim()) continue
152
- let msg
153
- try { msg = JSON.parse(line) } catch {
154
- process.stderr.write(`[hive-stdio] ignored a line that is not JSON (${line.length} chars)\n`)
155
- continue
156
- }
157
- try { if (this.onmessage) this.onmessage(msg) } catch (e) { process.stderr.write(`[hive-stdio] ${e && e.stack}\n`) }
158
- }
159
- })
160
- const close = () => { if (this._closed) return; this._closed = true; if (this.onclose) this.onclose() }
161
- this._stdin.on('end', close)
162
- this._stdin.on('close', close)
163
- this._stdin.on('error', close)
164
- }
165
-
166
- send(message) {
167
- return new Promise((resolve, reject) => {
168
- if (this._closed && !this._stdout.writable) return reject(new Error('stdout is closed'))
169
- this._stdout.write(JSON.stringify(message) + '\n', (err) => (err ? reject(err) : resolve()))
170
- })
171
- }
172
- }
1
+ // hive-stdio.js -- the MCP stdio server Hivecode actually needs, without the SDK's web stack.
2
+ //
3
+ // WHY THIS EXISTS. @modelcontextprotocol/sdk is a client AND a server AND three HTTP transports,
4
+ // so installing it installs express, hono, cors, jose, zod, ajv and ~85 other packages -- 25 MB,
5
+ // most of a stranger's first `npx hivecode-mcp` download (36.7s measured cold, 25 Sep 2026). A
6
+ // load trace of a full session (join, claim, write, release, say, wait) showed the client uses
7
+ // exactly one slice of it: newline-delimited JSON-RPC over stdin/stdout, `initialize`, `ping`,
8
+ // `tools/list`, `tools/call`, and two outgoing notifications. That slice is this file.
9
+ //
10
+ // IT MUST BEHAVE EXACTLY LIKE THE SDK WHERE A CLIENT CAN TELL. The SDK is still a devDependency,
11
+ // and tests/mcp-conformance-test.mjs drives this server with the SDK's own CLIENT -- the one
12
+ // Claude Code and the Gemini CLI are built on. Specifically, as in the SDK (1.30):
13
+ // - protocol version: echo the client's if supported, else answer with the newest we know;
14
+ // - `ping` -> {}; an unknown method -> error -32601; a handler that throws -> its own numeric
15
+ // `code` if it has one, else -32603, with the error's message;
16
+ // - a request the client CANCELLED gets no response (the spec: "SHOULD NOT send a response");
17
+ // - a line that is not JSON is logged to stderr and otherwise ignored, never answered.
18
+ // And one thing the SDK does not do: when stdin closes, the server says so (onclose), so the
19
+ // process can EXIT. The spec asks exactly that of a stdio server; the SDK left it running, and a
20
+ // Hivecode server that outlives its agent app keeps a seat in the room for a member who is gone.
21
+
22
+ export const LATEST_PROTOCOL_VERSION = '2025-11-25'
23
+ export const SUPPORTED_PROTOCOL_VERSIONS = [LATEST_PROTOCOL_VERSION, '2025-06-18', '2025-03-26', '2024-11-05', '2024-10-07']
24
+
25
+ // Same shape hive-mcp.js used to import from '@modelcontextprotocol/sdk/types.js': something
26
+ // setRequestHandler can take the method name from.
27
+ export const ListToolsRequestSchema = Object.freeze({ method: 'tools/list' })
28
+ export const CallToolRequestSchema = Object.freeze({ method: 'tools/call' })
29
+
30
+ const METHOD_NOT_FOUND = -32601
31
+ const INVALID_PARAMS = -32602
32
+ const INTERNAL_ERROR = -32603
33
+
34
+ export class Server {
35
+ constructor(serverInfo, { capabilities = {}, instructions } = {}) {
36
+ this._serverInfo = serverInfo
37
+ this._capabilities = capabilities
38
+ this._instructions = instructions
39
+ // Keyed by method, called as handler(request, extra) -- the SDK's own internal shape, which
40
+ // the test seam in hive-mcp.js reaches into on purpose.
41
+ this._requestHandlers = new Map()
42
+ this._transport = null
43
+ this._inflight = new Map() // request id -> AbortController, so a cancel can find it
44
+ this.onclose = null
45
+ this.oninitialized = null
46
+ this._clientInfo = null // who connected: the app's name and version, from initialize
47
+ this._requestHandlers.set('initialize', (req) => {
48
+ const requested = req.params && req.params.protocolVersion
49
+ this._clientInfo = (req.params && req.params.clientInfo) || null
50
+ return {
51
+ protocolVersion: SUPPORTED_PROTOCOL_VERSIONS.includes(requested) ? requested : LATEST_PROTOCOL_VERSION,
52
+ capabilities: this._capabilities,
53
+ serverInfo: this._serverInfo,
54
+ ...(this._instructions ? { instructions: this._instructions } : {}),
55
+ }
56
+ })
57
+ this._requestHandlers.set('ping', () => ({}))
58
+ }
59
+ /** The connecting app's clientInfo ({ name, version }), as the SDK's Server exposes it. */
60
+ getClientVersion() { return this._clientInfo || undefined }
61
+
62
+ setRequestHandler(schema, handler) {
63
+ const method = typeof schema === 'string' ? schema : schema && schema.method
64
+ if (!method) throw new Error('setRequestHandler needs a method')
65
+ this._requestHandlers.set(method, handler)
66
+ }
67
+
68
+ async connect(transport) {
69
+ this._transport = transport
70
+ transport.onmessage = (msg) => this._onmessage(msg)
71
+ transport.onclose = () => { this._transport = null; if (this.onclose) this.onclose() }
72
+ await transport.start()
73
+ }
74
+
75
+ /** Send a notification to the client. Rejects when there is nobody to send it to. */
76
+ notification({ method, params }) {
77
+ if (!this._transport) return Promise.reject(new Error('Not connected'))
78
+ return this._transport.send({ jsonrpc: '2.0', method, ...(params !== undefined ? { params } : {}) })
79
+ }
80
+
81
+ _onmessage(msg) {
82
+ if (Array.isArray(msg)) {
83
+ // JSON-RPC batches: the 2025-03-26 revision allowed them. Answer each request in the batch;
84
+ // the replies go back one per line, which every client matches by id.
85
+ for (const m of msg) this._onmessage(m)
86
+ return
87
+ }
88
+ if (!msg || typeof msg !== 'object' || msg.jsonrpc !== '2.0') return
89
+ if (msg.method === undefined) return // a response to a request we never send
90
+ if (msg.id === undefined || msg.id === null) return this._onnotification(msg)
91
+ this._onrequest(msg)
92
+ }
93
+
94
+ _onnotification(msg) {
95
+ if (msg.method === 'notifications/initialized') { if (this.oninitialized) this.oninitialized(); return }
96
+ if (msg.method === 'notifications/cancelled') {
97
+ const id = msg.params && msg.params.requestId
98
+ const ac = this._inflight.get(id)
99
+ if (ac) ac.abort()
100
+ }
101
+ // every other notification is ignorable by spec
102
+ }
103
+
104
+ async _onrequest(msg) {
105
+ const { id, method } = msg
106
+ const handler = this._requestHandlers.get(method)
107
+ if (!handler) return this._reply({ jsonrpc: '2.0', id, error: { code: METHOD_NOT_FOUND, message: 'Method not found' } })
108
+ if (method === 'tools/call' && (!msg.params || typeof msg.params !== 'object' || typeof msg.params.name !== 'string')) {
109
+ return this._reply({ jsonrpc: '2.0', id, error: { code: INVALID_PARAMS, message: 'tools/call needs params.name' } })
110
+ }
111
+ const ac = new AbortController()
112
+ this._inflight.set(id, ac)
113
+ let reply
114
+ try {
115
+ const result = await handler({ method, params: msg.params }, { signal: ac.signal, requestId: id })
116
+ reply = { jsonrpc: '2.0', id, result: result === undefined ? {} : result }
117
+ } catch (e) {
118
+ const code = e && Number.isSafeInteger(e.code) ? e.code : INTERNAL_ERROR
119
+ reply = { jsonrpc: '2.0', id, error: { code, message: (e && e.message) || 'Internal error' } }
120
+ } finally {
121
+ this._inflight.delete(id)
122
+ }
123
+ if (ac.signal.aborted) return // cancelled by the client: it is no longer waiting for this
124
+ this._reply(reply)
125
+ }
126
+
127
+ _reply(message) {
128
+ if (!this._transport) return
129
+ Promise.resolve(this._transport.send(message)).catch((e) => process.stderr.write(`[hive-stdio] could not reply: ${e && e.message}\n`))
130
+ }
131
+ }
132
+
133
+ export class StdioServerTransport {
134
+ constructor(stdin = process.stdin, stdout = process.stdout) {
135
+ this._stdin = stdin
136
+ this._stdout = stdout
137
+ this._buf = ''
138
+ this._closed = false
139
+ this.onmessage = null
140
+ this.onclose = null
141
+ }
142
+
143
+ async start() {
144
+ this._stdin.setEncoding('utf8') // a multi-byte character split across two chunks stays whole
145
+ this._stdin.on('data', (chunk) => {
146
+ this._buf += chunk
147
+ let i
148
+ while ((i = this._buf.indexOf('\n')) >= 0) {
149
+ const line = this._buf.slice(0, i).replace(/\r$/, '')
150
+ this._buf = this._buf.slice(i + 1)
151
+ if (!line.trim()) continue
152
+ let msg
153
+ try { msg = JSON.parse(line) } catch {
154
+ process.stderr.write(`[hive-stdio] ignored a line that is not JSON (${line.length} chars)\n`)
155
+ continue
156
+ }
157
+ try { if (this.onmessage) this.onmessage(msg) } catch (e) { process.stderr.write(`[hive-stdio] ${e && e.stack}\n`) }
158
+ }
159
+ })
160
+ const close = () => { if (this._closed) return; this._closed = true; if (this.onclose) this.onclose() }
161
+ this._stdin.on('end', close)
162
+ this._stdin.on('close', close)
163
+ this._stdin.on('error', close)
164
+ }
165
+
166
+ send(message) {
167
+ return new Promise((resolve, reject) => {
168
+ if (this._closed && !this._stdout.writable) return reject(new Error('stdout is closed'))
169
+ this._stdout.write(JSON.stringify(message) + '\n', (err) => (err ? reject(err) : resolve()))
170
+ })
171
+ }
172
+ }