hivecode-mcp 0.14.2 → 0.14.4
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/HIVE_RULES.md +41 -98
- package/docs/TROUBLESHOOTING.md +4 -0
- package/hive-await.js +57 -21
- package/hive-branch.js +68 -2
- package/hive-gate.js +116 -2
- package/hive-instructions.js +110 -61
- package/hive-land.js +15 -1
- package/hive-mailbox.js +74 -7
- package/hive-mcp.js +258 -47
- package/hive-mux.js +4 -1
- package/hive-notify.js +21 -5
- package/hive-pr.js +42 -5
- package/hive-receipts.js +56 -5
- package/hive-room-mode.js +143 -37
- package/hive-room-watcher.js +95 -16
- package/hive-seen.js +135 -0
- package/hive-slack.js +62 -4
- package/hive-stop-hook.js +33 -18
- package/hive-transport.js +85 -11
- package/icr.js +7 -2
- package/lang-js.js +54 -10
- package/package.json +13 -4
- package/sync.js +419 -225
- package/docs/HIVE_RULES.md +0 -41
package/hive-transport.js
CHANGED
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
// set when node started, so the WebSocket died with ENOTFOUND, the long-poll probe died the same
|
|
25
25
|
// way, and hive_join said "the relay refused the connection" about a relay it never reached. Now:
|
|
26
26
|
// - proxyFor(url) picks the proxy: HIVE_PROXY (a URL, or off), else HTTPS_PROXY for wss:/https:
|
|
27
|
-
// and HTTP_PROXY for ws:/http:. NO_PROXY is honoured; loopback never goes through a proxy
|
|
27
|
+
// and HTTP_PROXY for ws:/http:. NO_PROXY is honoured; loopback never goes through a proxy,
|
|
28
|
+
// including where node's env-proxy mode would send it there (directFetch).
|
|
28
29
|
// - Both pipes ride an HTTP CONNECT tunnel through it: the WebSocket (an agent for `ws`) and the
|
|
29
30
|
// long-poll requests (fetchFor). Through a tunnel to a wss:// relay the proxy sees only
|
|
30
31
|
// "CONNECT host:443"; the path and query -- where the room token rides -- stay inside TLS.
|
|
@@ -184,13 +185,46 @@ function tunnelAgent(proxy, secure, kind = 'fetch') {
|
|
|
184
185
|
|
|
185
186
|
/** A fetch-shaped call carried over the tunnel agent: just what offersPoll and PollSocket use. */
|
|
186
187
|
function proxyFetch(proxy, url, init = {}) {
|
|
188
|
+
return agentFetch(url, init, (secure) => tunnelAgent(proxy, secure))
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// DIRECT MEANS DIRECT, EVEN WHERE NODE APPLIES THE ENV PROXY ITSELF. With env-proxy mode on
|
|
192
|
+
// (NODE_USE_ENV_PROXY=1 or --use-env-proxy, what Antigravity's VMs run), the built-in fetch AND http's
|
|
193
|
+
// global agent send every request through http(s)_proxy unless node's own NO_PROXY exempts it. So a
|
|
194
|
+
// call proxyFor() had decided was direct -- loopback, a NO_PROXY match, HIVE_PROXY=off -- went to the
|
|
195
|
+
// proxy anyway: a self-hosted relay on localhost was "unreachable" for an invite revoke or the /health
|
|
196
|
+
// probe while its WebSockets worked (antigravity-VM, 9 Nov 2026; tests/loopback-direct-fetch-test.mjs).
|
|
197
|
+
// Measured on node 22.23 and 24.22: an agent of our own is never proxied. Used only in env-proxy mode,
|
|
198
|
+
// so everywhere else a direct call is still the built-in fetch, exactly as before.
|
|
199
|
+
// Node fixes the mode ONCE, AT STARTUP: clearing NODE_USE_ENV_PROXY later does not turn it off (a
|
|
200
|
+
// first version read it per call, and proxy-fetch-test, which clears it mid-run, still went to the
|
|
201
|
+
// proxy). So the mode is read when this module loads -- the nearest point to node's own decision --
|
|
202
|
+
// and a per-call env can only add it, never take it away.
|
|
203
|
+
const envProxyIn = (env) => {
|
|
204
|
+
if (/^(1|true|yes|on)$/i.test(String((env && env.NODE_USE_ENV_PROXY) || '').trim())) return true
|
|
205
|
+
return /(^|\s)--use-env-proxy(\s|=|$)/.test(String((env && env.NODE_OPTIONS) || ''))
|
|
206
|
+
}
|
|
207
|
+
const ENV_PROXY_AT_START = envProxyIn(process.env) || process.execArgv.includes('--use-env-proxy')
|
|
208
|
+
const envProxyMode = (env = process.env) => ENV_PROXY_AT_START || envProxyIn(env)
|
|
209
|
+
const directAgents = new Map()
|
|
210
|
+
function directAgent(secure) {
|
|
211
|
+
let a = directAgents.get(secure)
|
|
212
|
+
if (!a) { a = new (secure ? https.Agent : http.Agent)({ keepAlive: true, maxFreeSockets: 4 }); directAgents.set(secure, a) }
|
|
213
|
+
return a
|
|
214
|
+
}
|
|
215
|
+
function directFetch(url, init = {}) {
|
|
216
|
+
return agentFetch(url, init, directAgent)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/** The request behind proxyFetch and directFetch: `agentFor(secure)` picks the agent that carries it. */
|
|
220
|
+
function agentFetch(url, init, agentFor) {
|
|
187
221
|
return new Promise((resolve, reject) => {
|
|
188
222
|
const u = new URL(url)
|
|
189
223
|
const secure = u.protocol === 'https:'
|
|
190
224
|
const body = init.body == null ? null : Buffer.from(init.body)
|
|
191
225
|
const headers = { ...(init.headers || {}) }
|
|
192
226
|
if (body) headers['content-length'] = String(body.length)
|
|
193
|
-
const req = (secure ? https : http).request(u, { method: init.method || 'GET', headers, agent:
|
|
227
|
+
const req = (secure ? https : http).request(u, { method: init.method || 'GET', headers, agent: agentFor(secure) }, (res) => {
|
|
194
228
|
const chunks = []
|
|
195
229
|
res.on('data', (c) => chunks.push(c))
|
|
196
230
|
res.on('error', reject)
|
|
@@ -218,10 +252,11 @@ function proxyFetch(proxy, url, init = {}) {
|
|
|
218
252
|
})
|
|
219
253
|
}
|
|
220
254
|
|
|
221
|
-
/** The fetch to reach `url` with: through the proxy tunnel when one applies, else
|
|
255
|
+
/** The fetch to reach `url` with: through the proxy tunnel when one applies, else direct (see directFetch). */
|
|
222
256
|
export function fetchFor(url, env = process.env) {
|
|
223
257
|
const p = proxyFor(url, env)
|
|
224
|
-
|
|
258
|
+
if (p) return (u, init) => proxyFetch(p, u, init)
|
|
259
|
+
return envProxyMode(env) ? directFetch : globalThis.fetch
|
|
225
260
|
}
|
|
226
261
|
|
|
227
262
|
/**
|
|
@@ -373,6 +408,7 @@ export class PollSocket extends SocketShape {
|
|
|
373
408
|
_lost(reason, code = 1006) {
|
|
374
409
|
if (this.readyState === CLOSED) return
|
|
375
410
|
this.readyState = CLOSED
|
|
411
|
+
clearTimeout(this._closeTimer)
|
|
376
412
|
if (this._sid) this._req('close', undefined, {}, 5000).catch(() => { })
|
|
377
413
|
fire(this, 'close', { type: 'close', code, reason, wasClean: false, target: this })
|
|
378
414
|
}
|
|
@@ -392,7 +428,7 @@ export class PollSocket extends SocketShape {
|
|
|
392
428
|
// A proxy that cuts long requests shows up as a failure after a long wait: hold shorter.
|
|
393
429
|
if (startedAt && now - startedAt > 5000 && this._hold > 4000) this._hold = Math.max(4000, Math.floor(this._hold / 2))
|
|
394
430
|
await sleep(Math.min(2000, 250 * 2 ** Math.min(3, Math.floor((now - this._troubleSince) / 5000))))
|
|
395
|
-
return this.readyState === OPEN
|
|
431
|
+
return this.readyState === OPEN || this.readyState === CLOSING
|
|
396
432
|
}
|
|
397
433
|
_ok() { this._troubleSince = 0 }
|
|
398
434
|
async _recvLoop() {
|
|
@@ -429,17 +465,18 @@ export class PollSocket extends SocketShape {
|
|
|
429
465
|
if (!this._flushQueued) { this._flushQueued = true; setImmediate(() => { this._flushQueued = false; this._flush() }) }
|
|
430
466
|
}
|
|
431
467
|
async _flush() {
|
|
432
|
-
|
|
468
|
+
const live = () => this.readyState === OPEN || this.readyState === CLOSING
|
|
469
|
+
if (this._sending || !this._outbox.length || !live()) { this._closeIfDrained(); return }
|
|
433
470
|
this._sending = true
|
|
434
471
|
try {
|
|
435
|
-
while (this._outbox.length &&
|
|
472
|
+
while (this._outbox.length && live()) {
|
|
436
473
|
let n = 0, bytes = 0
|
|
437
474
|
while (n < this._outbox.length && n < 512 && (n === 0 || bytes + this._outbox[n].length <= 4 * 1048576)) { bytes += this._outbox[n].length; n++ }
|
|
438
475
|
const batch = this._outbox.slice(0, n)
|
|
439
476
|
const first = this._outSeq
|
|
440
477
|
const body = packFrames(batch)
|
|
441
478
|
for (;;) {
|
|
442
|
-
if (
|
|
479
|
+
if (!live()) return
|
|
443
480
|
const started = Date.now()
|
|
444
481
|
let r
|
|
445
482
|
try { r = await this._req('send', body, { 'content-type': 'application/octet-stream', 'x-hive-seq': String(first) }, 60000) }
|
|
@@ -455,17 +492,54 @@ export class PollSocket extends SocketShape {
|
|
|
455
492
|
this._outbox.splice(0, n)
|
|
456
493
|
this._outSeq = first + n
|
|
457
494
|
}
|
|
458
|
-
} finally { this._sending = false }
|
|
495
|
+
} finally { this._sending = false; this._closeIfDrained() }
|
|
459
496
|
}
|
|
497
|
+
// CLOSE DELIVERS WHAT WAS SENT FIRST, as a WebSocket's does (0.14.3 P0-1). A WebSocket hands its
|
|
498
|
+
// bytes to the OS on send(), so ws.close() still delivers them; this socket keeps them in _outbox
|
|
499
|
+
// until the relay accepts them, and close() used to drop that array: an edit made just before the
|
|
500
|
+
// agent left never reached the room while hive_edit had already said it was syncing (8-9 Nov mock
|
|
501
|
+
// run, both Antigravity VM agents). Now close() keeps sending for up to CLOSE_DRAIN_MS, then ends
|
|
502
|
+
// the session. The pending request keeps the process alive meanwhile, so an exit waits for it.
|
|
460
503
|
close(code = 1000, reason = '') {
|
|
461
504
|
if (this.readyState === CLOSING || this.readyState === CLOSED) return
|
|
505
|
+
if (this.readyState === OPEN && (this._outbox.length || this._sending)) {
|
|
506
|
+
this.readyState = CLOSING
|
|
507
|
+
this._closeWith = { code, reason }
|
|
508
|
+
this._closeTimer = setTimeout(() => this._endClose(false), PollSocket.CLOSE_DRAIN_MS)
|
|
509
|
+
this._flush()
|
|
510
|
+
return
|
|
511
|
+
}
|
|
512
|
+
this._closeWith = { code, reason }
|
|
513
|
+
this._endClose(true)
|
|
514
|
+
}
|
|
515
|
+
_closeIfDrained() {
|
|
516
|
+
if (this.readyState === CLOSING && !this._sending && !this._outbox.length) this._endClose(true)
|
|
517
|
+
}
|
|
518
|
+
_endClose(drained) {
|
|
519
|
+
if (this.readyState === CLOSED) return
|
|
520
|
+
clearTimeout(this._closeTimer)
|
|
462
521
|
const had = !!this._sid
|
|
522
|
+
const { code, reason } = this._closeWith || { code: 1000, reason: '' }
|
|
463
523
|
this.readyState = CLOSED
|
|
464
524
|
if (had) this._req('close', undefined, {}, 5000).catch(() => { })
|
|
465
|
-
setImmediate(() => fire(this, 'close', { type: 'close', code, reason, wasClean:
|
|
525
|
+
setImmediate(() => fire(this, 'close', { type: 'close', code, reason, wasClean: drained, target: this }))
|
|
526
|
+
}
|
|
527
|
+
/** Resolves once nothing is waiting to reach the relay (or the socket is gone): the drain, observable. */
|
|
528
|
+
drained(timeoutMs = PollSocket.CLOSE_DRAIN_MS) {
|
|
529
|
+
const end = Date.now() + timeoutMs
|
|
530
|
+
return new Promise((resolve) => {
|
|
531
|
+
const tick = () => {
|
|
532
|
+
if (this.readyState === CLOSED || (!this._outbox.length && !this._sending)) return resolve(!this._outbox.length)
|
|
533
|
+
if (Date.now() >= end) return resolve(false)
|
|
534
|
+
setTimeout(tick, 25)
|
|
535
|
+
}
|
|
536
|
+
tick()
|
|
537
|
+
})
|
|
466
538
|
}
|
|
467
|
-
terminate()
|
|
539
|
+
// terminate is for a dead link (the liveness check): nothing can be delivered on it, so no drain.
|
|
540
|
+
terminate() { this._closeWith = { code: 1006, reason: 'terminated' }; this._endClose(false) }
|
|
468
541
|
}
|
|
542
|
+
PollSocket.CLOSE_DRAIN_MS = 10000
|
|
469
543
|
|
|
470
544
|
/**
|
|
471
545
|
* The socket every provider gets: a WebSocket, or long-poll where WebSockets are refused (above).
|
package/icr.js
CHANGED
|
@@ -802,12 +802,17 @@ export function structuralMerge(base, a, b, opts = {}) {
|
|
|
802
802
|
// ASYNC/AWAIT SYNCHRONIZATION (intent):
|
|
803
803
|
// When a declaration was synchronous in base and became ASYNC in the merged result,
|
|
804
804
|
// upgrade call sites inside async callers with `await` so the contract holds.
|
|
805
|
+
// ONLY a function that EXISTED in the base as sync (0.14.3 P0-5). A function new in this merge was
|
|
806
|
+
// written async by its author, together with its callers: nothing was "made async" under anyone.
|
|
807
|
+
// Counting it rewrote authored lines (`return f()` -> `return await f()`, credited to the author,
|
|
808
|
+
// silently), and two peers making the same insert at once stacked in the shared text: the room's
|
|
809
|
+
// own server.js read `return await await await admitMux(req, q)` (9 Nov).
|
|
805
810
|
const asyncUpgrades = []
|
|
806
811
|
if (lang.isAsyncDecl && lang.upgradeCallSitesToAwait) {
|
|
807
812
|
for (const name of mergedNames) {
|
|
808
|
-
const
|
|
813
|
+
const wasSyncInBase = baseNames.has(name) && !lang.isAsyncDecl(base, name)
|
|
809
814
|
const isAsyncInMerged = lang.isAsyncDecl(merged, name)
|
|
810
|
-
if (
|
|
815
|
+
if (wasSyncInBase && isAsyncInMerged) {
|
|
811
816
|
const upgraded = lang.upgradeCallSitesToAwait(merged, name)
|
|
812
817
|
if (upgraded !== merged && lang.parses(upgraded)) {
|
|
813
818
|
merged = upgraded
|
package/lang-js.js
CHANGED
|
@@ -230,45 +230,63 @@ function isAsyncDecl(src, name) {
|
|
|
230
230
|
|
|
231
231
|
// Upgrade free call sites of `fnName` to `await fnName(...)` if they are inside an async parent
|
|
232
232
|
// and not already awaited.
|
|
233
|
+
//
|
|
234
|
+
// Left alone (0.14.3 P0-5): a call that is already awaited (`await f()`, `await (f())`); a call that
|
|
235
|
+
// IS the value an async function returns (`return f()`, `async () => f()`) -- OUTSIDE a try, where
|
|
236
|
+
// returning the promise resolves to the same value. Inside a try (its block or its catch) `return f()`
|
|
237
|
+
// is NOT the same once f is async: a rejection escapes the catch and a finally runs before f settles,
|
|
238
|
+
// so there it is upgraded, which is what the feature is for (Claude-cloud's review). A call that is an
|
|
239
|
+
// argument of an awaited call (`await g(f())`) is NOT awaited by that await and is upgraded too.
|
|
240
|
+
// Each position is inserted at most once.
|
|
233
241
|
function upgradeCallSitesToAwait(src, fnName) {
|
|
234
242
|
try {
|
|
235
243
|
const ast = parse(src)
|
|
236
|
-
const spots =
|
|
244
|
+
const spots = new Set()
|
|
237
245
|
|
|
238
|
-
|
|
246
|
+
// awaited: this node IS the operand of an await (through parentheses or an optional chain only).
|
|
247
|
+
// inTry: this node sits in a try block or catch clause of the current function.
|
|
248
|
+
function walkAST(node, parent, isAsyncScope = false, awaited = false, inTry = false) {
|
|
239
249
|
if (!node || typeof node.type !== 'string') return
|
|
240
250
|
|
|
241
251
|
let childAsyncScope = isAsyncScope
|
|
252
|
+
let childInTry = inTry
|
|
242
253
|
if (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') {
|
|
243
254
|
childAsyncScope = !!node.async
|
|
255
|
+
childInTry = false // a nested function has its own try scopes
|
|
244
256
|
}
|
|
257
|
+
const passAwait = node.type === 'AwaitExpression' ? true
|
|
258
|
+
: (node.type === 'ParenthesizedExpression' || node.type === 'ChainExpression') ? awaited : false
|
|
245
259
|
|
|
246
260
|
if (node.type === 'CallExpression') {
|
|
247
261
|
let isTarget = false
|
|
248
262
|
if (node.callee.type === 'Identifier' && node.callee.name === fnName) isTarget = true
|
|
249
263
|
if (isTarget && childAsyncScope) {
|
|
250
|
-
const alreadyAwaited = parent && parent.type === 'AwaitExpression'
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
264
|
+
const alreadyAwaited = awaited || (parent && parent.type === 'AwaitExpression')
|
|
265
|
+
const returnedAsIs = !inTry && parent && (parent.type === 'ReturnStatement' ||
|
|
266
|
+
(parent.type === 'ArrowFunctionExpression' && parent.body === node))
|
|
267
|
+
if (!alreadyAwaited && !returnedAsIs) spots.add(node.start)
|
|
254
268
|
}
|
|
255
269
|
}
|
|
256
270
|
|
|
257
271
|
for (const k of Object.keys(node)) {
|
|
258
272
|
if (k === 'type' || k === 'start' || k === 'end' || k === 'loc' || k === 'range') continue
|
|
259
273
|
const v = node[k]
|
|
274
|
+
// A try's block and its catch clause are "in try"; its finally is not (a return there is final).
|
|
275
|
+
const kInTry = node.type === 'TryStatement' ? (k === 'block' || k === 'handler') || childInTry : childInTry
|
|
260
276
|
if (Array.isArray(v)) {
|
|
261
|
-
for (const c of v) walkAST(c, node, childAsyncScope)
|
|
277
|
+
for (const c of v) walkAST(c, node, childAsyncScope, passAwait, kInTry)
|
|
262
278
|
} else if (v && typeof v.type === 'string') {
|
|
263
|
-
walkAST(v, node, childAsyncScope)
|
|
279
|
+
walkAST(v, node, childAsyncScope, passAwait, kInTry)
|
|
264
280
|
}
|
|
265
281
|
}
|
|
266
282
|
}
|
|
267
283
|
|
|
268
284
|
walkAST(ast, null, false)
|
|
269
|
-
if (!spots.
|
|
285
|
+
if (!spots.size) return src
|
|
270
286
|
|
|
271
|
-
spots.sort((a, b) => b - a)
|
|
287
|
+
const order = [...spots].sort((a, b) => b - a)
|
|
288
|
+
spots.clear()
|
|
289
|
+
for (const p of order) spots.add(p)
|
|
272
290
|
let out = src
|
|
273
291
|
for (const pos of spots) {
|
|
274
292
|
out = out.slice(0, pos) + 'await ' + out.slice(pos)
|
|
@@ -279,6 +297,31 @@ function upgradeCallSitesToAwait(src, fnName) {
|
|
|
279
297
|
}
|
|
280
298
|
}
|
|
281
299
|
|
|
300
|
+
// STACKED AWAITS LEFT BY A CRDT UNION (0.14.3 P0-5-3). Two peers making the same sync -> async
|
|
301
|
+
// change at once each insert `await ` before the same call; the shared text keeps BOTH inserts, so
|
|
302
|
+
// the room reads `await await f()`. No merge can prevent that (each peer's merge is right on its own),
|
|
303
|
+
// so the engine removes it afterwards. Returns the [start, end) spans to delete: for every
|
|
304
|
+
// `await await x`, the OUTER `await` and the whitespace after it, and only when nothing but whitespace
|
|
305
|
+
// separates the two (so `await (await x)`, a comment, or a string is never touched). On the same
|
|
306
|
+
// converged text every peer computes the same spans, so their deletes are of the same characters.
|
|
307
|
+
function stackedAwaits(src) {
|
|
308
|
+
let ast
|
|
309
|
+
try { ast = parse(src) } catch { return [] }
|
|
310
|
+
const spans = []
|
|
311
|
+
const walk = (node) => {
|
|
312
|
+
if (!node || typeof node.type !== 'string') return
|
|
313
|
+
if (node.type === 'AwaitExpression' && node.argument && node.argument.type === 'AwaitExpression' &&
|
|
314
|
+
/^await\s+$/.test(src.slice(node.start, node.argument.start))) spans.push([node.start, node.argument.start])
|
|
315
|
+
for (const k of Object.keys(node)) {
|
|
316
|
+
if (k === 'type' || k === 'start' || k === 'end' || k === 'loc' || k === 'range') continue
|
|
317
|
+
const v = node[k]
|
|
318
|
+
if (Array.isArray(v)) { for (const c of v) walk(c) } else if (v && typeof v.type === 'string') walk(v)
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
walk(ast)
|
|
322
|
+
return spans.sort((a, b) => a[0] - b[0])
|
|
323
|
+
}
|
|
324
|
+
|
|
282
325
|
// Find callers of `fnName` that are synchronous (cannot be auto-awaited without changing the caller's signature)
|
|
283
326
|
function syncCallSitesOf(src, fnName) {
|
|
284
327
|
const syncCallers = []
|
|
@@ -641,6 +684,7 @@ export const javascript = {
|
|
|
641
684
|
declBody,
|
|
642
685
|
isAsyncDecl,
|
|
643
686
|
upgradeCallSitesToAwait,
|
|
687
|
+
stackedAwaits, // spans of `await await` a CRDT union left (P0-5-3)
|
|
644
688
|
syncCallSitesOf,
|
|
645
689
|
renameRefs, // rewrites every matching identifier (kept for reference)
|
|
646
690
|
renameFreeRefs, // scope-aware — only rewrites references that resolve to the binding
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hivecode-mcp",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.4",
|
|
4
4
|
"description": "MCP server that lets any AI coding agent join a Hivecode room — humans and multiple AI agents edit one live codebase with folder-scoped permissions and approval gates.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -36,8 +36,13 @@
|
|
|
36
36
|
"hive-version.js",
|
|
37
37
|
"hive-pr-staleness.js",
|
|
38
38
|
"hive-pr.js",
|
|
39
|
-
"hive-branch.js",
|
|
39
|
+
"hive-branch.js",
|
|
40
|
+
"hive-land.js",
|
|
41
|
+
"hive-repos.js",
|
|
42
|
+
"hive-room-mode.js",
|
|
43
|
+
"hive-room-watcher.js",
|
|
40
44
|
"hive-mailbox.js",
|
|
45
|
+
"hive-seen.js",
|
|
41
46
|
"hive-obligations.js",
|
|
42
47
|
"hive-receipts.js",
|
|
43
48
|
"hive-throttle.js",
|
|
@@ -134,7 +139,7 @@
|
|
|
134
139
|
"test:substrate:authority": "node substrate-authority-test.js",
|
|
135
140
|
"test:substrate:all": "node substrate-test.js && node substrate-live-test.js && node substrate-enforce-test.js && node substrate-authority-test.js",
|
|
136
141
|
"test:recover": "node tests/recover-test.mjs",
|
|
137
|
-
"test:mailbox": "node tests/mailbox-test.mjs && node tests/mcp-wait-test.mjs && node tests/mailbox-noise-test.mjs",
|
|
142
|
+
"test:mailbox": "node tests/mailbox-test.mjs && node tests/mcp-wait-test.mjs && node tests/mailbox-noise-test.mjs && node tests/mail-identity-test.mjs",
|
|
138
143
|
"test:stophook": "node tests/stop-hook-test.mjs",
|
|
139
144
|
"test:limits": "node tests/limits-test.mjs && node tests/rate-hold-test.mjs && node tests/persist-batch-test.mjs",
|
|
140
145
|
"test:merge": "node tests/diff3-test.mjs && node tests/merge-balloon-test.mjs && node tests/icr-merge-test.js && node tests/icr-gap-comments-test.mjs && node tests/icr-comment-fuzz-test.mjs",
|
|
@@ -188,5 +193,9 @@
|
|
|
188
193
|
"doc": "docs",
|
|
189
194
|
"test": "tests"
|
|
190
195
|
},
|
|
191
|
-
"author": "Ganesh Shivlal Kute <support@getgrm.tech>"
|
|
196
|
+
"author": "Ganesh Shivlal Kute <support@getgrm.tech>",
|
|
197
|
+
"repository": {
|
|
198
|
+
"type": "git",
|
|
199
|
+
"url": "git+https://github.com/Ganesh-Kute/HiveCode.git"
|
|
200
|
+
}
|
|
192
201
|
}
|