hivecode-mcp 0.14.1 → 0.14.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/HIVE_RULES.md +98 -98
- package/LICENSE +21 -21
- package/README.md +421 -421
- package/core.js +91 -91
- package/docs/ALWAYS_ON.md +310 -310
- package/docs/GITHUB_WORKFLOW.md +394 -394
- package/docs/HIVE_RULES.md +41 -41
- package/docs/MCP.md +157 -157
- package/docs/QUICKSTART.md +266 -266
- package/docs/SELF_HOSTING.md +256 -256
- package/docs/SLACK_SETUP.md +474 -474
- package/docs/TROUBLESHOOTING.md +106 -105
- package/hive-activity.js +336 -336
- package/hive-authors.js +46 -44
- package/hive-await.js +230 -230
- package/hive-branch.js +674 -607
- package/hive-busy.js +88 -88
- package/hive-coord.js +110 -110
- package/hive-gate.js +135 -135
- package/hive-github.js +3 -1
- package/hive-hook-install.js +179 -179
- package/hive-instructions.js +74 -74
- package/hive-land.js +709 -691
- package/hive-listen.js +81 -81
- package/hive-mailbox.js +520 -520
- package/hive-mcp-http.js +591 -591
- package/hive-mcp.js +92 -12
- package/hive-mux-proto.js +58 -58
- package/hive-mux.js +354 -351
- package/hive-notify.js +234 -233
- package/hive-obligations.js +247 -247
- package/hive-poll-proto.js +50 -50
- package/hive-pr-staleness.js +189 -189
- package/hive-pr.js +637 -512
- package/hive-privacy.js +327 -327
- package/hive-receipts.js +233 -233
- package/hive-relay-health.js +234 -234
- package/hive-repos.js +430 -430
- package/hive-room-key.js +210 -210
- package/hive-room-mode.js +1761 -1668
- package/hive-room-watcher.js +623 -561
- package/hive-secrets.js +89 -89
- package/hive-session.js +114 -114
- package/hive-setup.js +560 -560
- package/hive-slack-agent.js +408 -408
- package/hive-slack.js +2417 -2367
- package/hive-stdio.js +172 -172
- package/hive-stop-hook.js +293 -293
- package/hive-throttle.js +118 -118
- package/hive-time.js +71 -71
- package/hive-transport.js +617 -578
- package/hive-update.js +58 -58
- package/hive-version.js +110 -110
- package/hive-webhook.js +55 -54
- package/icr-merge.js +58 -58
- package/icr.js +856 -851
- package/lang-brace.js +305 -305
- package/lang-js.js +695 -651
- package/lang-json.js +211 -211
- package/lang-python.js +588 -588
- package/lang-ruby.js +230 -230
- package/lang-toml.js +136 -136
- package/lang-yaml.js +183 -183
- package/limits.js +413 -413
- package/package.json +11 -3
- package/reconcile.cjs +621 -621
- package/slack-app-manifest-agent.json +61 -61
- package/slack-app-manifest-inbound.json +36 -36
- package/slack-app-manifest.json +27 -27
- package/substrate.js +252 -252
- package/sync.js +434 -60
- package/token.js +201 -201
package/core.js
CHANGED
|
@@ -1,91 +1,91 @@
|
|
|
1
|
-
// Shared pure logic, used by the sync clients and the agents — and unit-tested
|
|
2
|
-
// in test.js. Keeping these here (instead of copy-pasted) means a fix in one
|
|
3
|
-
// place fixes everywhere, and the tests exercise the REAL code.
|
|
4
|
-
|
|
5
|
-
import reconcilePkg from './reconcile.cjs'
|
|
6
|
-
|
|
7
|
-
export const {
|
|
8
|
-
applyDiff,
|
|
9
|
-
hasConflictMarkers,
|
|
10
|
-
stripConflictMarkers,
|
|
11
|
-
merge3,
|
|
12
|
-
summarizeChange,
|
|
13
|
-
changedRange,
|
|
14
|
-
symbolsIn,
|
|
15
|
-
icrMerge3,
|
|
16
|
-
createReconciler,
|
|
17
|
-
reconcile
|
|
18
|
-
} = reconcilePkg
|
|
19
|
-
|
|
20
|
-
// Optimistic concurrency: is a write based on `expected` still safe to apply?
|
|
21
|
-
// Returns the new version on success, or { stale, current } if the region moved.
|
|
22
|
-
export function safeBump(versions, region, expected) {
|
|
23
|
-
const current = versions.get(region)
|
|
24
|
-
if (current !== expected) return { stale: true, current }
|
|
25
|
-
versions.set(region, (current ?? 0) + 1)
|
|
26
|
-
return { ok: true, version: (current ?? 0) + 1 }
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Lock helpers (pessimistic concurrency). A lock is "alive" only if unexpired.
|
|
30
|
-
export function lockHeldByOther(locks, file, me, now) {
|
|
31
|
-
const l = locks.get(file)
|
|
32
|
-
return l && l.owner !== me && l.exp > now ? l : null
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Deadlock-safe multi-file ordering: always acquire in a stable sorted order so
|
|
36
|
-
// two agents can never form a circular wait (A holds 1 wants 2, B holds 2 wants 1).
|
|
37
|
-
export function lockOrder(files) {
|
|
38
|
-
return [...files].sort()
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Richer negotiation: when a lock holder gets a request, decide how to respond.
|
|
42
|
-
// Returns one of:
|
|
43
|
-
// grant — no conflict, hand over (after finishing)
|
|
44
|
-
// counter — we both touch the same thing; propose taking turns
|
|
45
|
-
// deny — the request is destructive while I'm still mid-edit; refuse for now
|
|
46
|
-
// `holder` = { intent, done }, `request` = { from, summary }.
|
|
47
|
-
export function negotiate(holder, request) {
|
|
48
|
-
const h = (holder.intent || '').toLowerCase()
|
|
49
|
-
const r = (request.summary || '').toLowerCase()
|
|
50
|
-
if (/\b(delete|drop|remove|rewrite|overwrite)\b/.test(r) && !holder.done) {
|
|
51
|
-
return { decision: 'deny', reason: 'that change is destructive and I am still mid-edit' }
|
|
52
|
-
}
|
|
53
|
-
const overlap = sharedWord(h, r)
|
|
54
|
-
if (overlap && !holder.done) {
|
|
55
|
-
return { decision: 'counter', reason: `we both touch "${overlap}"`, counter: 'let me finish, then it is yours' }
|
|
56
|
-
}
|
|
57
|
-
return { decision: 'grant', reason: 'no conflict' }
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Smallest shared "significant" word (len > 3) between two intent strings.
|
|
61
|
-
function sharedWord(a, b) {
|
|
62
|
-
const words = (s) => new Set(s.split(/[^a-z0-9]+/i).filter((w) => w.length > 3))
|
|
63
|
-
const wb = words(b)
|
|
64
|
-
for (const w of words(a)) if (wb.has(w)) return w
|
|
65
|
-
return null
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// --- Patch-apply-or-rework (for two writers in the SAME file) ---
|
|
69
|
-
// 3-way line merge: given the `base` an agent read, the `mine` it produced, and
|
|
70
|
-
// the `current` on the board now, decide what to write.
|
|
71
|
-
// - current unchanged -> take mine
|
|
72
|
-
// - I changed nothing -> take current
|
|
73
|
-
// - changes on disjoint lines -> merge both (no rework)
|
|
74
|
-
// - changes overlap the same lines -> { conflict } -> agent must re-do on current
|
|
75
|
-
export function mergeEdit(base, mine, current) {
|
|
76
|
-
if (current === base) return { ok: true, text: mine }
|
|
77
|
-
if (mine === base) return { ok: true, text: current }
|
|
78
|
-
if (mine === current) return { ok: true, text: mine }
|
|
79
|
-
const b = base.split('\n')
|
|
80
|
-
const mr = changedRange(b, mine.split('\n'))
|
|
81
|
-
const tr = changedRange(b, current.split('\n'))
|
|
82
|
-
if (mr.endBase <= tr.startBase || tr.endBase <= mr.startBase) {
|
|
83
|
-
const out = b.slice()
|
|
84
|
-
for (const e of [mr, tr].sort((x, y) => y.startBase - x.startBase)) {
|
|
85
|
-
out.splice(e.startBase, e.endBase - e.startBase, ...e.newLines)
|
|
86
|
-
}
|
|
87
|
-
return { ok: true, text: out.join('\n') }
|
|
88
|
-
}
|
|
89
|
-
return { conflict: true } // same lines changed two ways -> re-reason on `current`
|
|
90
|
-
}
|
|
91
|
-
|
|
1
|
+
// Shared pure logic, used by the sync clients and the agents — and unit-tested
|
|
2
|
+
// in test.js. Keeping these here (instead of copy-pasted) means a fix in one
|
|
3
|
+
// place fixes everywhere, and the tests exercise the REAL code.
|
|
4
|
+
|
|
5
|
+
import reconcilePkg from './reconcile.cjs'
|
|
6
|
+
|
|
7
|
+
export const {
|
|
8
|
+
applyDiff,
|
|
9
|
+
hasConflictMarkers,
|
|
10
|
+
stripConflictMarkers,
|
|
11
|
+
merge3,
|
|
12
|
+
summarizeChange,
|
|
13
|
+
changedRange,
|
|
14
|
+
symbolsIn,
|
|
15
|
+
icrMerge3,
|
|
16
|
+
createReconciler,
|
|
17
|
+
reconcile
|
|
18
|
+
} = reconcilePkg
|
|
19
|
+
|
|
20
|
+
// Optimistic concurrency: is a write based on `expected` still safe to apply?
|
|
21
|
+
// Returns the new version on success, or { stale, current } if the region moved.
|
|
22
|
+
export function safeBump(versions, region, expected) {
|
|
23
|
+
const current = versions.get(region)
|
|
24
|
+
if (current !== expected) return { stale: true, current }
|
|
25
|
+
versions.set(region, (current ?? 0) + 1)
|
|
26
|
+
return { ok: true, version: (current ?? 0) + 1 }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Lock helpers (pessimistic concurrency). A lock is "alive" only if unexpired.
|
|
30
|
+
export function lockHeldByOther(locks, file, me, now) {
|
|
31
|
+
const l = locks.get(file)
|
|
32
|
+
return l && l.owner !== me && l.exp > now ? l : null
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Deadlock-safe multi-file ordering: always acquire in a stable sorted order so
|
|
36
|
+
// two agents can never form a circular wait (A holds 1 wants 2, B holds 2 wants 1).
|
|
37
|
+
export function lockOrder(files) {
|
|
38
|
+
return [...files].sort()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Richer negotiation: when a lock holder gets a request, decide how to respond.
|
|
42
|
+
// Returns one of:
|
|
43
|
+
// grant — no conflict, hand over (after finishing)
|
|
44
|
+
// counter — we both touch the same thing; propose taking turns
|
|
45
|
+
// deny — the request is destructive while I'm still mid-edit; refuse for now
|
|
46
|
+
// `holder` = { intent, done }, `request` = { from, summary }.
|
|
47
|
+
export function negotiate(holder, request) {
|
|
48
|
+
const h = (holder.intent || '').toLowerCase()
|
|
49
|
+
const r = (request.summary || '').toLowerCase()
|
|
50
|
+
if (/\b(delete|drop|remove|rewrite|overwrite)\b/.test(r) && !holder.done) {
|
|
51
|
+
return { decision: 'deny', reason: 'that change is destructive and I am still mid-edit' }
|
|
52
|
+
}
|
|
53
|
+
const overlap = sharedWord(h, r)
|
|
54
|
+
if (overlap && !holder.done) {
|
|
55
|
+
return { decision: 'counter', reason: `we both touch "${overlap}"`, counter: 'let me finish, then it is yours' }
|
|
56
|
+
}
|
|
57
|
+
return { decision: 'grant', reason: 'no conflict' }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Smallest shared "significant" word (len > 3) between two intent strings.
|
|
61
|
+
function sharedWord(a, b) {
|
|
62
|
+
const words = (s) => new Set(s.split(/[^a-z0-9]+/i).filter((w) => w.length > 3))
|
|
63
|
+
const wb = words(b)
|
|
64
|
+
for (const w of words(a)) if (wb.has(w)) return w
|
|
65
|
+
return null
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// --- Patch-apply-or-rework (for two writers in the SAME file) ---
|
|
69
|
+
// 3-way line merge: given the `base` an agent read, the `mine` it produced, and
|
|
70
|
+
// the `current` on the board now, decide what to write.
|
|
71
|
+
// - current unchanged -> take mine
|
|
72
|
+
// - I changed nothing -> take current
|
|
73
|
+
// - changes on disjoint lines -> merge both (no rework)
|
|
74
|
+
// - changes overlap the same lines -> { conflict } -> agent must re-do on current
|
|
75
|
+
export function mergeEdit(base, mine, current) {
|
|
76
|
+
if (current === base) return { ok: true, text: mine }
|
|
77
|
+
if (mine === base) return { ok: true, text: current }
|
|
78
|
+
if (mine === current) return { ok: true, text: mine }
|
|
79
|
+
const b = base.split('\n')
|
|
80
|
+
const mr = changedRange(b, mine.split('\n'))
|
|
81
|
+
const tr = changedRange(b, current.split('\n'))
|
|
82
|
+
if (mr.endBase <= tr.startBase || tr.endBase <= mr.startBase) {
|
|
83
|
+
const out = b.slice()
|
|
84
|
+
for (const e of [mr, tr].sort((x, y) => y.startBase - x.startBase)) {
|
|
85
|
+
out.splice(e.startBase, e.endBase - e.startBase, ...e.newLines)
|
|
86
|
+
}
|
|
87
|
+
return { ok: true, text: out.join('\n') }
|
|
88
|
+
}
|
|
89
|
+
return { conflict: true } // same lines changed two ways -> re-reason on `current`
|
|
90
|
+
}
|
|
91
|
+
|