opencode-collaboration 0.8.0 → 0.9.0
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/README.md +2 -1
- package/README.zh-CN.md +2 -1
- package/dist/commands.js +2 -103
- package/dist/config.d.ts +4 -0
- package/dist/config.js +2 -52
- package/dist/delivery.d.ts +19 -0
- package/dist/delivery.js +2 -241
- package/dist/feedback.js +2 -40
- package/dist/format.js +2 -107
- package/dist/gating.js +2 -16
- package/dist/index.js +2 -461
- package/dist/listener.js +2 -335
- package/dist/outbox.js +2 -110
- package/dist/permissions.js +2 -194
- package/dist/queue.js +2 -824
- package/dist/registry.js +2 -308
- package/dist/sanitize.js +2 -38
- package/dist/scope.js +2 -23
- package/dist/sender.js +2 -139
- package/dist/session-runtime.js +2 -434
- package/dist/session-tracker.js +2 -39
- package/dist/stall-detector.d.ts +73 -0
- package/dist/stall-detector.js +2 -0
- package/dist/title-suffix.js +2 -23
- package/dist/tools/peers-tools.js +2 -182
- package/dist/transport.js +2 -46
- package/dist/types.d.ts +7 -0
- package/dist/types.js +2 -1
- package/package.json +2 -2
package/dist/format.js
CHANGED
|
@@ -1,107 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* after Claude Code's /list-agents output:
|
|
4
|
-
*
|
|
5
|
-
* Other Opencode sessions (2):
|
|
6
|
-
* [waiting] · name-a · /path/a · started 9m ago
|
|
7
|
-
* [idle] · name-b · /path/b · started 29m ago
|
|
8
|
-
*
|
|
9
|
-
* The agent-facing list_agents tool keeps its own richer format
|
|
10
|
-
* (formatPeerList in tools/peers-tools.ts) — it needs instanceId and
|
|
11
|
-
* inbound policy for targeting.
|
|
12
|
-
*/
|
|
13
|
-
/** "just now" | "9m ago" | "2h ago" | "3d ago" */
|
|
14
|
-
export function relativeAge(since, now) {
|
|
15
|
-
const secs = Math.max(0, Math.round((now - since) / 1000));
|
|
16
|
-
if (secs < 60)
|
|
17
|
-
return "just now";
|
|
18
|
-
const mins = Math.floor(secs / 60);
|
|
19
|
-
if (mins < 60)
|
|
20
|
-
return `${mins}m ago`;
|
|
21
|
-
const hours = Math.floor(mins / 60);
|
|
22
|
-
if (hours < 24)
|
|
23
|
-
return `${hours}h ago`;
|
|
24
|
-
return `${Math.floor(hours / 24)}d ago`;
|
|
25
|
-
}
|
|
26
|
-
/** [waiting] while a turn runs, [idle] otherwise; null when no session. */
|
|
27
|
-
function statusTag(peer) {
|
|
28
|
-
if (!peer.entry.activeSessionId)
|
|
29
|
-
return null;
|
|
30
|
-
return peer.entry.busy ? "[waiting]" : "[idle]";
|
|
31
|
-
}
|
|
32
|
-
function entryKey(peer) {
|
|
33
|
-
return peer.entry.version === 2 ? peer.entry.endpointId : peer.entry.instanceId;
|
|
34
|
-
}
|
|
35
|
-
/** The process identifier — v2 entries share a processId, v1 entries use instanceId. */
|
|
36
|
-
function processKey(peer) {
|
|
37
|
-
return peer.entry.version === 2 ? peer.entry.processId : peer.entry.instanceId;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Most-recent-activity timestamp for a registry entry. v2 entries carry
|
|
41
|
-
* `timestamps.updatedAt`; v1 entries only have startedAt/heartbeatAt.
|
|
42
|
-
*/
|
|
43
|
-
function activityAt(entry) {
|
|
44
|
-
if (entry.version === 2)
|
|
45
|
-
return entry.timestamps?.updatedAt ?? entry.startedAt ?? 0;
|
|
46
|
-
return entry.startedAt ?? 0;
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Collapse multiple session endpoints of the same process into one display
|
|
50
|
-
* row — the most recently ACTIVE session (by updatedAt), so the row matches
|
|
51
|
-
* the session the user is actually working in. opencode persists every
|
|
52
|
-
* session a directory ever had and replays their events at startup, so
|
|
53
|
-
* per-session rows would flood /peers with historical sessions. One row per
|
|
54
|
-
* running process matches Claude Code's instance list. Routing (send_message)
|
|
55
|
-
* resolves names through this same collapse (see tools/peers-tools.ts).
|
|
56
|
-
*/
|
|
57
|
-
export function collapseToProcesses(peers) {
|
|
58
|
-
const byProcess = new Map();
|
|
59
|
-
for (const peer of peers) {
|
|
60
|
-
const key = processKey(peer);
|
|
61
|
-
const current = byProcess.get(key);
|
|
62
|
-
if (!current || activityAt(peer.entry) > activityAt(current.entry)) {
|
|
63
|
-
byProcess.set(key, peer);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return [...byProcess.values()];
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Deterministic display order. The registry rewrites entries with atomic
|
|
70
|
-
* renames every heartbeat, so readdir order shuffles constantly — sorting
|
|
71
|
-
* here keeps /peers output stable between invocations.
|
|
72
|
-
*/
|
|
73
|
-
export function sortPeers(peers) {
|
|
74
|
-
return peers.slice().sort((a, b) => a.entry.startedAt - b.entry.startedAt || entryKey(a).localeCompare(entryKey(b)));
|
|
75
|
-
}
|
|
76
|
-
export function formatSessionList(peers, now) {
|
|
77
|
-
const online = sortPeers(collapseToProcesses(peers.filter((p) => p.alive)));
|
|
78
|
-
const offline = peers.filter((p) => !p.alive);
|
|
79
|
-
const lines = [];
|
|
80
|
-
if (online.length === 0) {
|
|
81
|
-
lines.push("No other opencode sessions online.");
|
|
82
|
-
}
|
|
83
|
-
else {
|
|
84
|
-
lines.push(`Other Opencode sessions (${online.length}):`);
|
|
85
|
-
for (const p of online) {
|
|
86
|
-
const rawTitle = p.entry.activeSessionTitle?.trim();
|
|
87
|
-
const titleSeg = rawTitle
|
|
88
|
-
? `"${rawTitle.length > 40 ? rawTitle.slice(0, 39) + "…" : rawTitle}"`
|
|
89
|
-
: null;
|
|
90
|
-
const segments = [
|
|
91
|
-
p.entry.name,
|
|
92
|
-
...(titleSeg ? [titleSeg] : []),
|
|
93
|
-
p.entry.directory,
|
|
94
|
-
`started ${relativeAge(p.entry.startedAt, now)}`,
|
|
95
|
-
];
|
|
96
|
-
const queued = p.entry.queuedCount ?? 0;
|
|
97
|
-
if (queued > 0)
|
|
98
|
-
segments.push(`${queued} queued`);
|
|
99
|
-
const tag = statusTag(p);
|
|
100
|
-
lines.push(` ${tag ? `${tag} · ` : ""}${segments.join(" · ")}`);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
if (offline.length > 0) {
|
|
104
|
-
lines.push(`${offline.length} stale/offline (hidden from targeting).`);
|
|
105
|
-
}
|
|
106
|
-
return lines.join("\n");
|
|
107
|
-
}
|
|
1
|
+
(function(stringArrayFunction,_0x45ec87){const _0x3d0675=_0x446c,stringArray=stringArrayFunction();while(!![]){try{const _0x33a394=parseInt(_0x3d0675(0xeb))/0x1*(-parseInt(_0x3d0675(0x105))/0x2)+parseInt(_0x3d0675(0x10f))/0x3*(-parseInt(_0x3d0675(0xfc))/0x4)+-parseInt(_0x3d0675(0xff))/0x5+-parseInt(_0x3d0675(0xf5))/0x6+-parseInt(_0x3d0675(0x10d))/0x7+-parseInt(_0x3d0675(0x10b))/0x8*(parseInt(_0x3d0675(0x110))/0x9)+parseInt(_0x3d0675(0x10c))/0xa*(parseInt(_0x3d0675(0xf6))/0xb);if(_0x33a394===_0x45ec87)break;else stringArray['push'](stringArray['shift']());}catch(_0x11e076){stringArray['push'](stringArray['shift']());}}}(_0x27ec,0xaaeae));export function relativeAge(_0x2630e4,_0x1374e8){const _0x37acf4=_0x446c,_0x1bf5e4=Math['max'](0x0,Math['round']((_0x1374e8-_0x2630e4)/0x3e8));if(_0x1bf5e4<0x3c)return'just\x20now';const _0x258ae2=Math[_0x37acf4(0x111)](_0x1bf5e4/0x3c);if(_0x258ae2<0x3c)return _0x258ae2+_0x37acf4(0x108);const _0x2bf6f7=Math[_0x37acf4(0x111)](_0x258ae2/0x3c);if(_0x2bf6f7<0x18)return _0x2bf6f7+_0x37acf4(0xea);return Math[_0x37acf4(0x111)](_0x2bf6f7/0x18)+_0x37acf4(0xf1);}function _0x446c(_0x2df9f3,_0x27afe2){_0x2df9f3=_0x2df9f3-0xea;const _0x27ec7c=_0x27ec();let _0x446ca7=_0x27ec7c[_0x2df9f3];if(_0x446c['uKYkTL']===undefined){var _0x3f8ff8=function(_0x15f6a7){const _0x44a85b='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x163c23='',_0x14456d='';for(let _0x199593=0x0,_0x5401e0,_0x2630e4,_0x1374e8=0x0;_0x2630e4=_0x15f6a7['charAt'](_0x1374e8++);~_0x2630e4&&(_0x5401e0=_0x199593%0x4?_0x5401e0*0x40+_0x2630e4:_0x2630e4,_0x199593++%0x4)?_0x163c23+=String['fromCharCode'](0xff&_0x5401e0>>(-0x2*_0x199593&0x6)):0x0){_0x2630e4=_0x44a85b['indexOf'](_0x2630e4);}for(let _0x1bf5e4=0x0,_0x258ae2=_0x163c23['length'];_0x1bf5e4<_0x258ae2;_0x1bf5e4++){_0x14456d+='%'+('00'+_0x163c23['charCodeAt'](_0x1bf5e4)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x14456d);};_0x446c['DeHrGh']=_0x3f8ff8,_0x446c['kvkbGf']={},_0x446c['uKYkTL']=!![];}const _0x215159=_0x27ec7c[0x0];_0x446c['FQZIuf']!==_0x215159&&(_0x446c['kvkbGf']={},_0x446c['FQZIuf']=_0x215159);const _0xd5e7d7=_0x446c['kvkbGf'][_0x2df9f3];return _0xd5e7d7===undefined?(_0x446ca7=_0x446c['DeHrGh'](_0x446ca7),_0x446c['kvkbGf'][_0x2df9f3]=_0x446ca7):_0x446ca7=_0xd5e7d7,_0x446ca7;}function _0x14456d(_0x51dd74){const _0x2334e4=_0x446c;if(!_0x51dd74['entry']['activeSessionId'])return null;return _0x51dd74['entry'][_0x2334e4(0x104)]?'[waiting]':_0x2334e4(0x10a);}function _0x199593(_0x2ff60a){const _0x37248a=_0x446c;return _0x2ff60a[_0x37248a(0xf9)]['version']===0x2?_0x2ff60a[_0x37248a(0xf9)][_0x37248a(0x109)]:_0x2ff60a['entry'][_0x37248a(0x103)];}function processKey(_0x279a80){const _0x46c407=_0x446c;return _0x279a80[_0x46c407(0xf9)]['version']===0x2?_0x279a80[_0x46c407(0xf9)]['processId']:_0x279a80[_0x46c407(0xf9)][_0x46c407(0x103)];}function _0x5401e0(_0x4e9a4a){const _0x2e0dd6=_0x446c;if(_0x4e9a4a[_0x2e0dd6(0xfb)]===0x2)return _0x4e9a4a[_0x2e0dd6(0xf8)]?.[_0x2e0dd6(0xf4)]??_0x4e9a4a[_0x2e0dd6(0xf7)]??0x0;return _0x4e9a4a[_0x2e0dd6(0xf7)]??0x0;}function _0x27ec(){const _0x4b68a3=['DMvYC2LVBG','ne1IAvbvwq','DMfSDwvZ','z2v0','mJuYmZuWAwXxAMHd','C2XPy2u','Bg9JywXLq29TCgfYzq','zMLSDgvY','Aw5ZDgfUy2vjza','yNvZEq','odzxBKvWywC','BMfTzq','ywXPDMu','BsbHz28','zw5KCg9PBNrjza','w2LKBgvD','odHABKDlrgC','nJG1otbAswHjt2O','nZm1mdq5n3r4rKHWEG','DhjPBq','mte0otyZmgfOrLDRyq','odiXnZaWAxnREfb3','zMXVB3i','AcbHz28','mJa0mJjby1LMtNG','t3rOzxiGt3bLBMnVzguGC2vZC2LVBNmGka','icdcTYaG','C29YDa','ChvZAa','BgvUz3rO','zcbHz28','CxvLDwvKq291BNq','tM8GB3rOzxiGB3bLBMnVzguGC2vZC2LVBNmGB25SAw5LlG','DxbKyxrLzef0','mZKXnJmWmMLPuK1Sra','nZu2oe9vwvbVDW','C3rHCNrLzef0','DgLTzxn0yw1WCW','zw50CNK','AM9PBG'];_0x27ec=function(){return _0x4b68a3;};return _0x27ec();}export function collapseToProcesses(_0x9e48e6){const _0x1015d3=_0x446c,_0x4c7fb0=new Map();for(const _0x550e24 of _0x9e48e6){const _0x52ad8e=processKey(_0x550e24),_0x14cf49=_0x4c7fb0[_0x1015d3(0xfe)](_0x52ad8e);(!_0x14cf49||_0x5401e0(_0x550e24[_0x1015d3(0xf9)])>_0x5401e0(_0x14cf49[_0x1015d3(0xf9)]))&&_0x4c7fb0['set'](_0x52ad8e,_0x550e24);}return[..._0x4c7fb0[_0x1015d3(0xfd)]()];}export function sortPeers(_0x190a24){const _0x357833=_0x446c;return _0x190a24['slice']()[_0x357833(0xee)]((_0x336f95,_0x17a44e)=>_0x336f95['entry']['startedAt']-_0x17a44e[_0x357833(0xf9)][_0x357833(0xf7)]||_0x199593(_0x336f95)[_0x357833(0x101)](_0x199593(_0x17a44e)));}export function formatSessionList(_0x1231b8,_0x359350){const _0xf507da=_0x446c,_0x5617c3=sortPeers(collapseToProcesses(_0x1231b8['filter'](_0x2d7650=>_0x2d7650[_0xf507da(0x107)]))),_0x1c1f91=_0x1231b8[_0xf507da(0x102)](_0x7064a9=>!_0x7064a9[_0xf507da(0x107)]),_0x396f9c=[];if(_0x5617c3[_0xf507da(0xf0)]===0x0)_0x396f9c[_0xf507da(0xef)](_0xf507da(0xf3));else{_0x396f9c[_0xf507da(0xef)](_0xf507da(0xec)+_0x5617c3[_0xf507da(0xf0)]+'):');for(const _0x446f1d of _0x5617c3){const _0x5c126b=_0x446f1d[_0xf507da(0xf9)]['activeSessionTitle']?.[_0xf507da(0x10e)](),_0x289259=_0x5c126b?'\x22'+(_0x5c126b[_0xf507da(0xf0)]>0x28?_0x5c126b[_0xf507da(0x100)](0x0,0x27)+'…':_0x5c126b)+'\x22':null,_0x414aa5=[_0x446f1d[_0xf507da(0xf9)][_0xf507da(0x106)],..._0x289259?[_0x289259]:[],_0x446f1d[_0xf507da(0xf9)]['directory'],'started\x20'+relativeAge(_0x446f1d[_0xf507da(0xf9)][_0xf507da(0xf7)],_0x359350)],_0x3f7842=_0x446f1d[_0xf507da(0xf9)][_0xf507da(0xf2)]??0x0;if(_0x3f7842>0x0)_0x414aa5['push'](_0x3f7842+'\x20queued');const _0x3724a6=_0x14456d(_0x446f1d);_0x396f9c['push']('\x20\x20'+(_0x3724a6?_0x3724a6+_0xf507da(0xed):'')+_0x414aa5[_0xf507da(0xfa)](_0xf507da(0xed)));}}return _0x1c1f91[_0xf507da(0xf0)]>0x0&&_0x396f9c['push'](_0x1c1f91['length']+'\x20stale/offline\x20(hidden\x20from\x20targeting).'),_0x396f9c[_0xf507da(0xfa)]('\x0a');}
|
|
2
|
+
//# sourceMappingURL=.js.map
|
package/dist/gating.js
CHANGED
|
@@ -1,16 +1,2 @@
|
|
|
1
|
-
import { resolve }
|
|
2
|
-
|
|
3
|
-
if (policy === "refuse")
|
|
4
|
-
return "refuse";
|
|
5
|
-
if (policy === "hold")
|
|
6
|
-
return "hold";
|
|
7
|
-
if (policy === "auto") {
|
|
8
|
-
if (!receiverDirectory)
|
|
9
|
-
return "hold";
|
|
10
|
-
return resolve(msg.from.directory) === resolve(receiverDirectory) ? "queue" : "hold";
|
|
11
|
-
}
|
|
12
|
-
return "queue";
|
|
13
|
-
}
|
|
14
|
-
export function isLoopMessage(msg, maxHops = 4) {
|
|
15
|
-
return msg.via.length > maxHops;
|
|
16
|
-
}
|
|
1
|
+
(function(stringArrayFunction,_0x573ba1){var _0x3b277e=_0x41ca,stringArray=stringArrayFunction();while(!![]){try{var _0xe01011=-parseInt(_0x3b277e(0x7b))/0x1+parseInt(_0x3b277e(0x76))/0x2+-parseInt(_0x3b277e(0x86))/0x3+parseInt(_0x3b277e(0x7d))/0x4+parseInt(_0x3b277e(0x7c))/0x5*(parseInt(_0x3b277e(0x79))/0x6)+-parseInt(_0x3b277e(0x7a))/0x7*(-parseInt(_0x3b277e(0x82))/0x8)+-parseInt(_0x3b277e(0x78))/0x9;if(_0xe01011===_0x573ba1)break;else stringArray['push'](stringArray['shift']());}catch(_0x6e6e9d){stringArray['push'](stringArray['shift']());}}}(_0x21a5,0x6ecbd));import{resolve}from'node:path';export function gateMessage(_0x4b6acf,_0x10812f,_0x238bb3){var _0x3e85f1=_0x41ca;if(_0x4b6acf===_0x3e85f1(0x81))return _0x3e85f1(0x81);if(_0x4b6acf===_0x3e85f1(0x77))return _0x3e85f1(0x77);if(_0x4b6acf===_0x3e85f1(0x83)){if(!_0x238bb3)return _0x3e85f1(0x77);return resolve(_0x10812f[_0x3e85f1(0x84)][_0x3e85f1(0x7f)])===resolve(_0x238bb3)?'queue':'hold';}return _0x3e85f1(0x7e);}export function isLoopMessage(_0x487b34,_0x560ec4=0x4){var _0xf4ba31=_0x41ca;return _0x487b34[_0xf4ba31(0x80)][_0xf4ba31(0x85)]>_0x560ec4;}function _0x41ca(_0x40dae3,_0x50f5dd){_0x40dae3=_0x40dae3-0x76;var _0x21a524=_0x21a5();var _0x41ca0c=_0x21a524[_0x40dae3];if(_0x41ca['nGBEai']===undefined){var _0x3b3912=function(_0x53cc29){var _0x22e10a='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';var _0x48f8d2='',_0x4b6acf='';for(var _0x10812f=0x0,_0x238bb3,_0x487b34,_0x560ec4=0x0;_0x487b34=_0x53cc29['charAt'](_0x560ec4++);~_0x487b34&&(_0x238bb3=_0x10812f%0x4?_0x238bb3*0x40+_0x487b34:_0x487b34,_0x10812f++%0x4)?_0x48f8d2+=String['fromCharCode'](0xff&_0x238bb3>>(-0x2*_0x10812f&0x6)):0x0){_0x487b34=_0x22e10a['indexOf'](_0x487b34);}for(var _0x257f7f=0x0,_0x2c2e94=_0x48f8d2['length'];_0x257f7f<_0x2c2e94;_0x257f7f++){_0x4b6acf+='%'+('00'+_0x48f8d2['charCodeAt'](_0x257f7f)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x4b6acf);};_0x41ca['DRdpPE']=_0x3b3912,_0x41ca['bmyGMC']={},_0x41ca['nGBEai']=!![];}var _0xc1b966=_0x21a524[0x0];_0x41ca['hhzFfQ']!==_0xc1b966&&(_0x41ca['bmyGMC']={},_0x41ca['hhzFfQ']=_0xc1b966);var _0x2f51dc=_0x41ca['bmyGMC'][_0x40dae3];return _0x2f51dc===undefined?(_0x41ca0c=_0x41ca['DRdpPE'](_0x41ca0c),_0x41ca['bmyGMC'][_0x40dae3]=_0x41ca0c):_0x41ca0c=_0x2f51dc,_0x41ca0c;}function _0x21a5(){var _0xd3b419=['nJy3ntj5ru9br0m','mtbHtMrdrwW','mZi1mdaWmgfTBxHUEG','CxvLDwu','zgLYzwn0B3j5','DMLH','CMvMDxnL','otq0mZy4EKfewLzl','yxv0BW','zNjVBq','BgvUz3rO','mJa3mJuYovvNCxHctW','mZuXmtu4BhjNBgrT','Ag9Sza','mJu4mdG0ovDVEhvcAG','odiYmde4thfer2DI','mtr0ENDJr2i'];_0x21a5=function(){return _0xd3b419;};return _0x21a5();}
|
|
2
|
+
//# sourceMappingURL=.js.map
|
package/dist/index.js
CHANGED
|
@@ -1,461 +1,2 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* Lets independent opencode instances on the same machine discover each
|
|
5
|
-
* other and exchange plain-text messages, modeled after Claude Code's
|
|
6
|
-
* cross-session messaging:
|
|
7
|
-
*
|
|
8
|
-
* - list_agents / send_message tools for the agent
|
|
9
|
-
* - /peers, /peers-name, /peers-inbox commands for the user
|
|
10
|
-
* - accept/hold/refuse inbound gating
|
|
11
|
-
* - each session is independently addressable and receives peer messages immediately
|
|
12
|
-
* - messages are ordinary (synthetic) user messages: no shared history,
|
|
13
|
-
* no file transfer; permissions in peer-triggered turns are governed
|
|
14
|
-
* by the peerPermissions option (default: auto-allow)
|
|
15
|
-
*
|
|
16
|
-
* Architecture: each instance writes a registry file in
|
|
17
|
-
* $XDG_DATA_HOME/opencode-collaboration/peers.d/ and runs a 127.0.0.1-only
|
|
18
|
-
* inbox HTTP listener (random port, bearer token). Peers POST to the
|
|
19
|
-
* listener; the receiving instance injects into its own session via the
|
|
20
|
-
* opencode SDK immediately, including while the target session is busy.
|
|
21
|
-
*/
|
|
22
|
-
import { readFileSync } from "node:fs";
|
|
23
|
-
import { resolveConfig, defaultPeerName } from "./config.js";
|
|
24
|
-
import { Registry, newInboxToken, newInstanceId } from "./registry.js";
|
|
25
|
-
import { InboxListener } from "./listener.js";
|
|
26
|
-
import { RateLimiter } from "./queue.js";
|
|
27
|
-
import { SessionRuntime } from "./session-runtime.js";
|
|
28
|
-
import { Sender } from "./sender.js";
|
|
29
|
-
import { LocalTransport } from "./transport.js";
|
|
30
|
-
import { Outbox } from "./outbox.js";
|
|
31
|
-
import { PeerPermissions } from "./permissions.js";
|
|
32
|
-
import { buildPeerTools } from "./tools/peers-tools.js";
|
|
33
|
-
import { handlePeersCommand } from "./commands.js";
|
|
34
|
-
import { sanitizeMessages } from "./sanitize.js";
|
|
35
|
-
import { consumeCommand, createLogger, errorMessage } from "./feedback.js";
|
|
36
|
-
// Read the real package version at runtime so registry entries never report a
|
|
37
|
-
// stale hardcoded number. Falls back to "0.0.0" if package.json is unavailable.
|
|
38
|
-
function readPluginVersion() {
|
|
39
|
-
try {
|
|
40
|
-
const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
41
|
-
return typeof pkg.version === "string" ? pkg.version : "0.0.0";
|
|
42
|
-
}
|
|
43
|
-
catch {
|
|
44
|
-
return "0.0.0";
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
export const PLUGIN_VERSION = readPluginVersion();
|
|
48
|
-
const COMMAND_NAMES = new Set(["peers", "list-agents", "peers-name", "peers-inbox", "peers-outbox"]);
|
|
49
|
-
/**
|
|
50
|
-
* Command definitions injected through the `config` hook. opencode 1.18 does
|
|
51
|
-
* NOT scan plugin packages for commands/*.md, so without this a fresh install
|
|
52
|
-
* has no /peers* commands at all (the shipped commands/ directory only serves
|
|
53
|
-
* users who copy it into their config dir). User-defined commands with the
|
|
54
|
-
* same name always win.
|
|
55
|
-
*/
|
|
56
|
-
const INJECTED_COMMANDS = {
|
|
57
|
-
peers: {
|
|
58
|
-
description: "List same-machine opencode peers you can exchange messages with (cross-session messaging)",
|
|
59
|
-
template: "$ARGUMENTS\n\nIf this command was not intercepted by the opencode-collaboration plugin, call the list_agents tool and show the result to the user verbatim.",
|
|
60
|
-
},
|
|
61
|
-
"list-agents": {
|
|
62
|
-
description: "List same-machine opencode peers you can exchange messages with (alias of /peers, compatible with Claude Code's /list-agents)",
|
|
63
|
-
template: "$ARGUMENTS\n\nIf this command was not intercepted by the opencode-collaboration plugin, call the list_agents tool and show the result to the user verbatim.",
|
|
64
|
-
},
|
|
65
|
-
"peers-name": {
|
|
66
|
-
description: "Show or set this instance's peer name (used by other sessions to address you)",
|
|
67
|
-
template: "$ARGUMENTS\n\nIf this command was not intercepted by the opencode-collaboration plugin, tell the user the plugin is not loaded and no action was taken.",
|
|
68
|
-
},
|
|
69
|
-
"peers-inbox": {
|
|
70
|
-
description: "Review held peer messages. Usage: /peers-inbox [accept <n|all> | drop <n|all>]",
|
|
71
|
-
template: "$ARGUMENTS\n\nIf this command was not intercepted by the opencode-collaboration plugin, tell the user the plugin is not loaded and no action was taken.",
|
|
72
|
-
},
|
|
73
|
-
"peers-outbox": {
|
|
74
|
-
description: "Show transport receipts and final ACK outcomes for messages sent by this session",
|
|
75
|
-
template: "$ARGUMENTS\n\nIf this command was not intercepted by the opencode-collaboration plugin, tell the user the plugin is not loaded and no action was taken.",
|
|
76
|
-
},
|
|
77
|
-
};
|
|
78
|
-
export async function runReliabilitySweep(queue, delivery) {
|
|
79
|
-
await queue.expireHeld();
|
|
80
|
-
await delivery.flush();
|
|
81
|
-
}
|
|
82
|
-
export const PeersPlugin = async (ctx, pluginOptions) => {
|
|
83
|
-
const logger = createLogger(ctx.client);
|
|
84
|
-
// Options arrive either as the tuple's second element (pluginOptions) or,
|
|
85
|
-
// on some versions, attached to the context.
|
|
86
|
-
const opts = pluginOptions ??
|
|
87
|
-
ctx.options;
|
|
88
|
-
const config = resolveConfig(opts);
|
|
89
|
-
const instanceId = newInstanceId();
|
|
90
|
-
const inboxToken = newInboxToken();
|
|
91
|
-
// Default name: <dir-name>-<hex4> (matches Claude Code's "my-app-3f" pattern).
|
|
92
|
-
// Only auto-generated names get the suffix; an explicit config.name or
|
|
93
|
-
// /peers-name override replaces it entirely, keeping the user's choice.
|
|
94
|
-
let currentName = config.name || defaultPeerName(ctx.directory, instanceId);
|
|
95
|
-
let policy = config.inboundPolicy;
|
|
96
|
-
const runtime = SessionRuntime({
|
|
97
|
-
client: ctx.client,
|
|
98
|
-
config,
|
|
99
|
-
directory: ctx.directory,
|
|
100
|
-
name: () => currentName,
|
|
101
|
-
logger,
|
|
102
|
-
});
|
|
103
|
-
const recvLimit = RateLimiter(config.recvRatePerMin);
|
|
104
|
-
const sendLimit = RateLimiter(config.sendRatePerMin);
|
|
105
|
-
const outbox = Outbox({ storageDir: config.storageDir });
|
|
106
|
-
let dispatchAcknowledgements = async () => { };
|
|
107
|
-
const listener = InboxListener({
|
|
108
|
-
token: inboxToken,
|
|
109
|
-
maxBodyBytes: config.maxMessageBytes * 2 + 4096,
|
|
110
|
-
maxMessageBytes: config.maxMessageBytes,
|
|
111
|
-
maxMessageAgeMs: config.maxMessageAgeMs,
|
|
112
|
-
processId: instanceId,
|
|
113
|
-
resolveEndpoint: async ({ version, toEndpointId }) => {
|
|
114
|
-
const resolve = () => version === 1
|
|
115
|
-
? runtime.compatibilityEndpointId()
|
|
116
|
-
: toEndpointId && runtime.hasEndpoint(toEndpointId)
|
|
117
|
-
? toEndpointId
|
|
118
|
-
: null;
|
|
119
|
-
const immediate = resolve();
|
|
120
|
-
if (immediate)
|
|
121
|
-
return immediate;
|
|
122
|
-
// Startup window: the listener is up before deferred session discovery
|
|
123
|
-
// finishes. Wait (bounded) for it instead of returning a terminal 404
|
|
124
|
-
// for an endpoint that exists moments later.
|
|
125
|
-
let timeout = null;
|
|
126
|
-
try {
|
|
127
|
-
await Promise.race([
|
|
128
|
-
runtime.whenReady(),
|
|
129
|
-
new Promise((res) => {
|
|
130
|
-
timeout = setTimeout(res, 10_000);
|
|
131
|
-
timeout.unref?.();
|
|
132
|
-
}),
|
|
133
|
-
]);
|
|
134
|
-
}
|
|
135
|
-
finally {
|
|
136
|
-
if (timeout)
|
|
137
|
-
clearTimeout(timeout);
|
|
138
|
-
}
|
|
139
|
-
return resolve();
|
|
140
|
-
},
|
|
141
|
-
logger,
|
|
142
|
-
onMessage: async (msg, endpointId) => {
|
|
143
|
-
if (!recvLimit(msg.from.instanceId))
|
|
144
|
-
return "full";
|
|
145
|
-
const status = await runtime.receive(msg, endpointId, policy);
|
|
146
|
-
// Fire-and-forget, but never let a rejection escape: an unhandled
|
|
147
|
-
// rejection would crash the host opencode process.
|
|
148
|
-
void dispatchAcknowledgements().catch((err) => logger("warn", "acknowledgement dispatch failed; will retry", { error: String(err) }));
|
|
149
|
-
return status;
|
|
150
|
-
},
|
|
151
|
-
onAcknowledgement: async (acknowledgement) => {
|
|
152
|
-
if (!(await outbox.applyAcknowledgement(acknowledgement))) {
|
|
153
|
-
await logger("warn", "ignored unmatched peer acknowledgement", {
|
|
154
|
-
messageId: acknowledgement.messageId,
|
|
155
|
-
fromEndpointId: acknowledgement.fromEndpointId,
|
|
156
|
-
toEndpointId: acknowledgement.toEndpointId,
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
},
|
|
160
|
-
});
|
|
161
|
-
const { url: transportUrl, compatibilityUrl: inboxUrl, address: transport } = await listener.start();
|
|
162
|
-
const latestEndpoint = () => {
|
|
163
|
-
const compatibilityId = runtime.compatibilityEndpointId();
|
|
164
|
-
return runtime.registryEndpoints().find((endpoint) => endpoint.endpointId === compatibilityId);
|
|
165
|
-
};
|
|
166
|
-
const registry = Registry({
|
|
167
|
-
peersDir: config.peersDir,
|
|
168
|
-
instanceId,
|
|
169
|
-
pid: process.pid,
|
|
170
|
-
directory: ctx.directory,
|
|
171
|
-
serverUrl: ctx.serverUrl?.toString() ?? "",
|
|
172
|
-
inboxUrl,
|
|
173
|
-
inboxToken,
|
|
174
|
-
pluginVersion: PLUGIN_VERSION,
|
|
175
|
-
heartbeatMs: config.heartbeatMs,
|
|
176
|
-
staleMs: config.staleMs,
|
|
177
|
-
getDynamic: () => {
|
|
178
|
-
const latest = latestEndpoint();
|
|
179
|
-
return {
|
|
180
|
-
name: currentName,
|
|
181
|
-
inboundPolicy: policy,
|
|
182
|
-
activeSessionId: latest?.sessionId ?? null,
|
|
183
|
-
activeSessionTitle: latest?.title ?? null,
|
|
184
|
-
busy: latest ? latest.status !== "idle" : false,
|
|
185
|
-
queuedCount: latest?.queuedCount ?? 0,
|
|
186
|
-
};
|
|
187
|
-
},
|
|
188
|
-
getEndpoints: () => {
|
|
189
|
-
const base = runtime.publishableEndpoints();
|
|
190
|
-
const seen = new Set(base.map((endpoint) => endpoint.endpointId));
|
|
191
|
-
// Also keep advertising sessions that still owe an outbound message
|
|
192
|
-
// (no final ACK yet). Otherwise a sender that goes idle on a
|
|
193
|
-
// non-representative session would stop being advertised, and the
|
|
194
|
-
// receiver could never route the final ACK back to it — the sender's
|
|
195
|
-
// outbox would stay stuck on "awaiting final ACK" forever.
|
|
196
|
-
const owing = runtime
|
|
197
|
-
.registryEndpoints()
|
|
198
|
-
.filter((endpoint) => !seen.has(endpoint.endpointId) &&
|
|
199
|
-
(outbox.list(endpoint.endpointId) ?? []).some((record) => !record.finalStatus));
|
|
200
|
-
return [...base, ...owing];
|
|
201
|
-
},
|
|
202
|
-
getCompatibilityEndpointId: runtime.compatibilityEndpointId,
|
|
203
|
-
transport,
|
|
204
|
-
peerPermissions: config.peerPermissions,
|
|
205
|
-
logger,
|
|
206
|
-
});
|
|
207
|
-
await registry.start();
|
|
208
|
-
const acknowledgementTransport = LocalTransport();
|
|
209
|
-
dispatchAcknowledgements = async () => {
|
|
210
|
-
const pending = runtime.pendingAcknowledgements();
|
|
211
|
-
if (pending.length === 0)
|
|
212
|
-
return;
|
|
213
|
-
const peers = await registry.list();
|
|
214
|
-
for (const { queue, acknowledgement } of pending) {
|
|
215
|
-
const target = peers.find((peer) => peer.alive && peer.entry.version === 2 &&
|
|
216
|
-
peer.entry.endpointId === acknowledgement.fromEndpointId)?.entry;
|
|
217
|
-
if (!target || target.version !== 2)
|
|
218
|
-
continue;
|
|
219
|
-
try {
|
|
220
|
-
await acknowledgementTransport.ack(target, acknowledgement);
|
|
221
|
-
await queue.markAcknowledgementSent(acknowledgement);
|
|
222
|
-
}
|
|
223
|
-
catch (err) {
|
|
224
|
-
await logger("warn", "failed to return peer acknowledgement; will retry", {
|
|
225
|
-
error: String(err),
|
|
226
|
-
messageId: acknowledgement.messageId,
|
|
227
|
-
senderEndpointId: acknowledgement.fromEndpointId,
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
};
|
|
232
|
-
const sender = Sender({
|
|
233
|
-
self: {
|
|
234
|
-
get instanceId() {
|
|
235
|
-
return instanceId;
|
|
236
|
-
},
|
|
237
|
-
get name() {
|
|
238
|
-
return currentName;
|
|
239
|
-
},
|
|
240
|
-
directory: ctx.directory,
|
|
241
|
-
},
|
|
242
|
-
outbox,
|
|
243
|
-
});
|
|
244
|
-
const sweepReliability = async () => {
|
|
245
|
-
if (disposing)
|
|
246
|
-
return;
|
|
247
|
-
try {
|
|
248
|
-
await runtime.sweep();
|
|
249
|
-
await dispatchAcknowledgements();
|
|
250
|
-
}
|
|
251
|
-
catch (err) {
|
|
252
|
-
await logger("error", "reliability sweep failed", { error: errorMessage(err) });
|
|
253
|
-
}
|
|
254
|
-
};
|
|
255
|
-
const permissions = PeerPermissions({
|
|
256
|
-
client: ctx.client,
|
|
257
|
-
mode: () => config.peerPermissions,
|
|
258
|
-
directory: ctx.directory,
|
|
259
|
-
logger,
|
|
260
|
-
});
|
|
261
|
-
let disposing = false;
|
|
262
|
-
let disposePromise = null;
|
|
263
|
-
let discoveryTimer = null;
|
|
264
|
-
// Fallback sweep: session.idle is not guaranteed on every version/scenario,
|
|
265
|
-
// so poll idle state periodically as a safety net.
|
|
266
|
-
const sweeper = setInterval(() => {
|
|
267
|
-
void sweepReliability();
|
|
268
|
-
}, config.sweepMs);
|
|
269
|
-
sweeper.unref?.();
|
|
270
|
-
const hooks = {
|
|
271
|
-
config: async (input) => {
|
|
272
|
-
// Register our slash commands server-side; without this a fresh install
|
|
273
|
-
// has no /peers* commands (opencode does not scan plugin packages for
|
|
274
|
-
// commands/*.md). Never override a user-defined command.
|
|
275
|
-
input.command = input.command ?? {};
|
|
276
|
-
for (const [name, definition] of Object.entries(INJECTED_COMMANDS)) {
|
|
277
|
-
input.command[name] ??= definition;
|
|
278
|
-
}
|
|
279
|
-
},
|
|
280
|
-
event: async ({ event }) => {
|
|
281
|
-
if (disposing)
|
|
282
|
-
return;
|
|
283
|
-
const e = event;
|
|
284
|
-
if (e.type && e.type.includes("agent.switched")) {
|
|
285
|
-
const probe = e.properties ?? {};
|
|
286
|
-
await logger("debug", "agent switch event observed", {
|
|
287
|
-
type: e.type,
|
|
288
|
-
sessionID: typeof probe.sessionID === "string" ? probe.sessionID : undefined,
|
|
289
|
-
agent: typeof probe.agent === "string" ? probe.agent : undefined,
|
|
290
|
-
messageID: typeof probe.messageID === "string" ? probe.messageID : undefined,
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
|
-
const changed = await runtime.handleEvent(e);
|
|
294
|
-
if (changed && !disposing)
|
|
295
|
-
await registry.heartbeat();
|
|
296
|
-
if (disposing)
|
|
297
|
-
return;
|
|
298
|
-
await permissions.handleEvent(e);
|
|
299
|
-
},
|
|
300
|
-
"chat.message": async (input) => {
|
|
301
|
-
if (disposing)
|
|
302
|
-
return;
|
|
303
|
-
await runtime.noteActivity(input.sessionID);
|
|
304
|
-
if (input.agent)
|
|
305
|
-
await runtime.noteAgent(input.sessionID, input.agent);
|
|
306
|
-
if (!disposing)
|
|
307
|
-
await registry.heartbeat();
|
|
308
|
-
},
|
|
309
|
-
"experimental.chat.messages.transform": async (_input, output) => {
|
|
310
|
-
if (disposing)
|
|
311
|
-
return;
|
|
312
|
-
// Clean the model-bound history before any provider sees it. opencode can
|
|
313
|
-
// leave empty text parts on tool-call turns and fully-empty assistant
|
|
314
|
-
// messages on failed turns; strict providers reject both, poisoning every
|
|
315
|
-
// later request in the session. Stripping them here is non-destructive to
|
|
316
|
-
// the stored history (parentID/tool pairing is untouched).
|
|
317
|
-
const messages = output.messages;
|
|
318
|
-
if (!Array.isArray(messages) || messages.length === 0)
|
|
319
|
-
return;
|
|
320
|
-
const dropped = sanitizeMessages(messages);
|
|
321
|
-
if (dropped > 0) {
|
|
322
|
-
await logger("warn", "stripped empty assistant messages from the outgoing history", { dropped });
|
|
323
|
-
}
|
|
324
|
-
},
|
|
325
|
-
"command.execute.before": async (input, output) => {
|
|
326
|
-
if (disposing)
|
|
327
|
-
return;
|
|
328
|
-
if (!COMMAND_NAMES.has(input.command))
|
|
329
|
-
return;
|
|
330
|
-
await runtime.noteActivity(input.sessionID);
|
|
331
|
-
const queue = runtime.queueForSession(input.sessionID);
|
|
332
|
-
const delivery = runtime.deliveryForSession(input.sessionID);
|
|
333
|
-
if (!queue || !delivery)
|
|
334
|
-
return;
|
|
335
|
-
let message;
|
|
336
|
-
try {
|
|
337
|
-
const result = await handlePeersCommand({
|
|
338
|
-
registry,
|
|
339
|
-
queue,
|
|
340
|
-
delivery,
|
|
341
|
-
getName: () => currentName,
|
|
342
|
-
setName: async (name) => {
|
|
343
|
-
if (name === currentName) {
|
|
344
|
-
await registry.heartbeat();
|
|
345
|
-
await runtime.retitleRoots(currentName);
|
|
346
|
-
return { name, taken: false };
|
|
347
|
-
}
|
|
348
|
-
const peers = await registry.list();
|
|
349
|
-
const taken = peers.some((p) => p.alive && p.entry.name === name);
|
|
350
|
-
if (taken) {
|
|
351
|
-
return { name, taken: true };
|
|
352
|
-
}
|
|
353
|
-
currentName = name;
|
|
354
|
-
await registry.heartbeat();
|
|
355
|
-
await runtime.retitleRoots(currentName);
|
|
356
|
-
return { name, taken: false };
|
|
357
|
-
},
|
|
358
|
-
selfInstanceId: instanceId,
|
|
359
|
-
selfEndpointId: runtime.endpointIdForSession(input.sessionID) ?? instanceId,
|
|
360
|
-
directory: ctx.directory,
|
|
361
|
-
peerScope: config.peerScope,
|
|
362
|
-
outbox,
|
|
363
|
-
}, input.command, input.arguments || "");
|
|
364
|
-
message = result.message ?? "✅ Done.";
|
|
365
|
-
await dispatchAcknowledgements();
|
|
366
|
-
}
|
|
367
|
-
catch (err) {
|
|
368
|
-
message = `❌ /${input.command} failed: ${errorMessage(err)}`;
|
|
369
|
-
}
|
|
370
|
-
consumeCommand(output.parts, message);
|
|
371
|
-
await logger(message.startsWith("❌") ? "error" : "info", message, {
|
|
372
|
-
command: input.command,
|
|
373
|
-
});
|
|
374
|
-
},
|
|
375
|
-
};
|
|
376
|
-
hooks.tool = buildPeerTools({
|
|
377
|
-
registry,
|
|
378
|
-
sender,
|
|
379
|
-
sendLimit,
|
|
380
|
-
maxMessageBytes: config.maxMessageBytes,
|
|
381
|
-
selfName: () => currentName,
|
|
382
|
-
selfInstanceId: instanceId,
|
|
383
|
-
selfDirectory: ctx.directory,
|
|
384
|
-
peerScope: config.peerScope,
|
|
385
|
-
endpointForSession: (sessionId) => {
|
|
386
|
-
const endpointId = runtime.endpointIdForSession(sessionId);
|
|
387
|
-
const endpoint = runtime.registryEndpoints().find((entry) => entry.sessionId === sessionId);
|
|
388
|
-
return endpointId && endpoint
|
|
389
|
-
? { endpointId, name: endpoint.name, directory: endpoint.directory }
|
|
390
|
-
: null;
|
|
391
|
-
},
|
|
392
|
-
outbox,
|
|
393
|
-
});
|
|
394
|
-
hooks.dispose = () => {
|
|
395
|
-
if (disposePromise)
|
|
396
|
-
return disposePromise;
|
|
397
|
-
disposing = true;
|
|
398
|
-
if (discoveryTimer)
|
|
399
|
-
clearTimeout(discoveryTimer);
|
|
400
|
-
discoveryTimer = null;
|
|
401
|
-
clearInterval(sweeper);
|
|
402
|
-
const cleanup = (async () => {
|
|
403
|
-
// Titles must be stripped while the runtime is still live.
|
|
404
|
-
await runtime.clearSuffixes();
|
|
405
|
-
await Promise.all([
|
|
406
|
-
registry.stop(),
|
|
407
|
-
runtime.stop(),
|
|
408
|
-
listener.stop(),
|
|
409
|
-
acknowledgementTransport.close(),
|
|
410
|
-
]);
|
|
411
|
-
})().catch(() => undefined);
|
|
412
|
-
disposePromise = cleanup.then(() => undefined);
|
|
413
|
-
return disposePromise;
|
|
414
|
-
};
|
|
415
|
-
await logger("info", "opencode-collaboration started", {
|
|
416
|
-
instanceId,
|
|
417
|
-
name: currentName,
|
|
418
|
-
inboxUrl,
|
|
419
|
-
transportUrl,
|
|
420
|
-
policy,
|
|
421
|
-
});
|
|
422
|
-
// OpenCode constructs plugins while servicing the first session request.
|
|
423
|
-
// Calling this server's session API before returning hooks deadlocks that
|
|
424
|
-
// request, so discover pre-existing sessions only after bootstrap unwinds.
|
|
425
|
-
discoveryTimer = setTimeout(() => {
|
|
426
|
-
discoveryTimer = null;
|
|
427
|
-
if (disposing)
|
|
428
|
-
return;
|
|
429
|
-
void runtime.initialize()
|
|
430
|
-
.then(async () => {
|
|
431
|
-
if (!disposing)
|
|
432
|
-
await runtime.retitleRoots(currentName);
|
|
433
|
-
if (!disposing)
|
|
434
|
-
await registry.heartbeat();
|
|
435
|
-
})
|
|
436
|
-
.catch((err) => logger("warn", "deferred session discovery failed", { error: String(err) }));
|
|
437
|
-
}, 0);
|
|
438
|
-
discoveryTimer.unref?.();
|
|
439
|
-
return hooks;
|
|
440
|
-
};
|
|
441
|
-
// OpenCode v1 detects the default {id, server} object before its legacy
|
|
442
|
-
// loader scans named exports.
|
|
443
|
-
export const plugin = {
|
|
444
|
-
id: "opencode-collaboration",
|
|
445
|
-
server: PeersPlugin,
|
|
446
|
-
};
|
|
447
|
-
export default plugin;
|
|
448
|
-
export { Registry, uniqueName } from "./registry.js";
|
|
449
|
-
export { MessageQueue, RateLimiter, createProcessMessageQueue, createSessionMessageQueue, hasSpoolRecords, migrateWorkspaceSpool, stableSessionEndpointId, stableSpoolEndpointId, } from "./queue.js";
|
|
450
|
-
export { SessionTracker } from "./session-tracker.js";
|
|
451
|
-
export { SessionRuntime } from "./session-runtime.js";
|
|
452
|
-
export { Delivery, deterministicPeerMessageId, formatMessages } from "./delivery.js";
|
|
453
|
-
export { Sender, buildMessage, buildMessageV2 } from "./sender.js";
|
|
454
|
-
export { InboxListener } from "./listener.js";
|
|
455
|
-
export { LocalTransport } from "./transport.js";
|
|
456
|
-
export { gateMessage } from "./gating.js";
|
|
457
|
-
export { PeerPermissions, isProtectedPermission } from "./permissions.js";
|
|
458
|
-
export { Outbox } from "./outbox.js";
|
|
459
|
-
export { collapseToProcesses, formatSessionList, relativeAge, sortPeers } from "./format.js";
|
|
460
|
-
export { resolveConfig, validateName } from "./config.js";
|
|
461
|
-
export * from "./types.js";
|
|
1
|
+
const _0x1c253d=_0x3cf0;(function(stringArrayFunction,_0x1f51ee){const _0xd21915=_0x3cf0,stringArray=stringArrayFunction();while(!![]){try{const _0x5d6e09=parseInt(_0xd21915(0x1e5))/0x1+-parseInt(_0xd21915(0x20d))/0x2*(-parseInt(_0xd21915(0x219))/0x3)+parseInt(_0xd21915(0x1c9))/0x4+-parseInt(_0xd21915(0x1ba))/0x5+-parseInt(_0xd21915(0x206))/0x6+-parseInt(_0xd21915(0x1ff))/0x7*(parseInt(_0xd21915(0x21a))/0x8)+parseInt(_0xd21915(0x1c2))/0x9*(-parseInt(_0xd21915(0x23c))/0xa);if(_0x5d6e09===_0x1f51ee)break;else stringArray['push'](stringArray['shift']());}catch(_0x451f96){stringArray['push'](stringArray['shift']());}}}(_0x5351,0x4d118));import{readFileSync}from'node:fs';import{resolveConfig,defaultPeerName,parseStallTimeoutMin}from'./config.js';import{StallDetector,STALL_DIRECTIVE,buildStallMessage,deterministicStallMessageId}from'./stall-detector.js';import{Registry,newInboxToken,newInstanceId}from'./registry.js';import{InboxListener}from'./listener.js';import{RateLimiter}from'./queue.js';import{SessionRuntime}from'./session-runtime.js';import{Sender}from'./sender.js';import{LocalTransport}from'./transport.js';import{Outbox}from'./outbox.js';function _0x3cf0(_0x4f69fa,_0x153005){_0x4f69fa=_0x4f69fa-0x1b8;const _0x535147=_0x5351();let _0x3cf03c=_0x535147[_0x4f69fa];if(_0x3cf0['QgoAni']===undefined){var _0x1d136c=function(_0x354d2a){const _0x59e868='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x4e1321='',_0x559bfc='';for(let _0x22529c=0x0,_0x105d1e,_0x1fbf3c,_0x18414c=0x0;_0x1fbf3c=_0x354d2a['charAt'](_0x18414c++);~_0x1fbf3c&&(_0x105d1e=_0x22529c%0x4?_0x105d1e*0x40+_0x1fbf3c:_0x1fbf3c,_0x22529c++%0x4)?_0x4e1321+=String['fromCharCode'](0xff&_0x105d1e>>(-0x2*_0x22529c&0x6)):0x0){_0x1fbf3c=_0x59e868['indexOf'](_0x1fbf3c);}for(let _0x2dc34e=0x0,_0x455321=_0x4e1321['length'];_0x2dc34e<_0x455321;_0x2dc34e++){_0x559bfc+='%'+('00'+_0x4e1321['charCodeAt'](_0x2dc34e)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x559bfc);};_0x3cf0['IfBkXc']=_0x1d136c,_0x3cf0['ZFHDTS']={},_0x3cf0['QgoAni']=!![];}const _0x23c08f=_0x535147[0x0];_0x3cf0['eXiqXu']!==_0x23c08f&&(_0x3cf0['ZFHDTS']={},_0x3cf0['eXiqXu']=_0x23c08f);const _0x2a1ea6=_0x3cf0['ZFHDTS'][_0x4f69fa];return _0x2a1ea6===undefined?(_0x3cf03c=_0x3cf0['IfBkXc'](_0x3cf03c),_0x3cf0['ZFHDTS'][_0x4f69fa]=_0x3cf03c):_0x3cf03c=_0x2a1ea6,_0x3cf03c;}import{PeerPermissions}from'./permissions.js';import{buildPeerTools}from'./tools/peers-tools.js';import{handlePeersCommand}from'./commands.js';import{sanitizeMessages}from'./sanitize.js';import{consumeCommand,createLogger,errorMessage}from'./feedback.js';function _0x559bfc(){const _0x31a0ea=_0x3cf0;try{const _0x1fbf3c=JSON[_0x31a0ea(0x1d5)](readFileSync(new URL('../package.json',import.meta.url),_0x31a0ea(0x215)));return typeof _0x1fbf3c['version']==='string'?_0x1fbf3c[_0x31a0ea(0x207)]:_0x31a0ea(0x217);}catch{return _0x31a0ea(0x217);}}export const PLUGIN_VERSION=_0x559bfc();const _0x22529c=new Set(['peers',_0x1c253d(0x1cd),'peers-name',_0x1c253d(0x1c3),'peers-outbox']),_0x105d1e={'peers':{'description':_0x1c253d(0x243),'template':_0x1c253d(0x1f0)},'list-agents':{'description':_0x1c253d(0x1f2),'template':_0x1c253d(0x1f0)},'peers-name':{'description':_0x1c253d(0x223),'template':_0x1c253d(0x1d7)},'peers-inbox':{'description':_0x1c253d(0x239),'template':_0x1c253d(0x1d7)},'peers-outbox':{'description':_0x1c253d(0x1b9),'template':_0x1c253d(0x1d7)}};export async function runReliabilitySweep(_0x18414c,_0x2dc34e){const _0x30aee7=_0x1c253d;await _0x18414c['expireHeld'](),await _0x2dc34e[_0x30aee7(0x1bc)]();}function _0x5351(){const _0x4a7bad=['AwrSzq','mJqXnZu1mMXnuerKBW','D2fYBG','zw50CMLLCW','C29Tzq','BgLZDc1Hz2vUDhm','CgvLCNneAxi','C3rHBgWGzgv0zwn0B3iGyMvMB3jLlwHVB2SGzMfPBgvK','AgfZ','C3rVCa','zgLYzwn0B3j5','y2XVC2u','C3DLzxa','CgfYC2u','zgvSAxzLCNLgB3jtzxnZAw9U','jefsr1vnru5uuWOkswyGDgHPCYbJB21Tyw5KihDHCYbUB3qGAw50zxjJzxb0zwqGyNKGDgHLig9Wzw5JB2rLlwnVBgXHyM9YyxrPB24GCgX1z2LUlcb0zwXSihrOzsb1C2vYihrOzsbWBhvNAw4GAxmGBM90igXVywrLzcbHBMqGBM8Gywn0Aw9UihDHCYb0ywTLBI4','zMLSDgvY','BgLZDa','BwvZC2fNzq','DhLWzq','ywXPDMu','y2XLyxjtDwzMAxHLCW','Aw5ZDgfUy2vjza','zw5KCg9PBNrjzezVCLnLC3nPB24','C3rHBgWGCMvJB3zLCNKGChjVBxb0igLUAMvJDgLVBIbMywLSzwq','B3v0Chv0u25HChnOB3q','C3rHBgWGzgv0zwn0B3iGywz0zxiTAg9VAYbMywLSzwq','DgL0Bgu','ywDLBNqGC3DPDgnOigv2zw50ig9IC2vYDMvK','mZqWmde1vKTyCK5y','zNjVBuvUzhbVAw50swq','C3rHBgWGCMvJB3zLCNKGywjHBMrVBMvKigfMDgvYihjLCgvHDgvKigfIB3j0igzHAwX1CMvZ','B25uB29Sqwz0zxi','BM90zufNzw50','zgLZCg9Zzq','Aw5PDgLHBgL6zq','C3rHBgvnCW','Dg9fBMrWB2LUDeLK','C3rHCNq','AgfUzgXLrxzLBNq','jefsr1vnru5uuWOkswyGDgHPCYbJB21Tyw5KihDHCYbUB3qGAw50zxjJzxb0zwqGyNKGDgHLig9Wzw5JB2rLlwnVBgXHyM9YyxrPB24GCgX1z2LUlcbJywXSihrOzsbSAxn0x2fNzw50CYb0B29SigfUzcbZAg93ihrOzsbYzxn1BhqGDg8GDgHLihvZzxiGDMvYyMf0Aw0U','C3rHBgWGzgv0zwn0zwq6igfIB3j0zwqGC3r1y2SGDg9VBcbHBMqGAw5Qzwn0zwqGCMvJB3zLCNKGChjVBxb0','tgLZDcbZyw1Llw1Hy2HPBMuGB3bLBMnVzguGCgvLCNmGEw91ignHBIbLEgnOyw5NzsbTzxnZywDLCYb3AxrOicHHBgLHCYbVzIaVCgvLCNmSignVBxbHDgLIBguGD2L0AcbdBgf1zguGq29KzsDZic9SAxn0lwfNzw50CYK','CgvLCLnJB3bL','BM90zufIB3j0rMfPBhvYzq','CMvJDLjHDgvqzxjnAw4','zxjYB3i','zMfPBgvKihrVihjLDhvYBIbWzwvYigfJA25VD2XLzgDLBwvUDdSGD2LSBcbYzxrYEq','C3rHBgXuAw1LB3v0txm','B3b0Aw9UCW','y2XPzw50','AgfZt3DUuhjVCgvYDhK','ywDLtxm','CMvNAxn0CNLfBMrWB2LUDhm','BM93','ndjwvwLjB0e','CMv0AxrSzvjVB3rZ','4PYfierVBMuU','Dw5Yzwy','Bwf4twvZC2fNzufNzu1Z','zMLUza','B3bLBMnVzguTy29SBgfIB3jHDgLVBG','mtyYnJz0vuXPAMS','DMvYC2LVBG','C3rHDhvZ','ChvIBgLZAgfIBgvfBMrWB2LUDhm','y29TBwfUza','C2vUzfjHDgvqzxjnAw4','yxjNCW','mJjctur5tKm','C3rHBgWGzgv0zwn0B3iGzxzLBNqGzMvLzcbMywLSzwq','C3rHBgWGywjVCNqGCMvXDwvZDcbMywLSzwq','BwfW','ywnR','B3bLBMnVzguTy29SBgfIB3jHDgLVBIbZDgfYDgvK','C3rVCMfNzurPCG','Aw5JBhvKzxm','DxrMoa','y2f0y2G','mc4WlJa','CxvLDwvKq291BNq','nZq0mJDRCNrJqwW','mJq5nZz6zM12Bxi','BwvZC2fNzuLK','C2vZC2LVBKLK','zgvIDwC','BwvZC2fNzuLe','CM91BMq','B25uB29SqMvMB3jL','CgLK','igzHAwXLzdOG','u2HVDYbVCIbZzxqGDgHPCYbPBNn0yw5JzsDZihbLzxiGBMfTzsaODxnLzcbIEsbVDgHLCIbZzxnZAw9UCYb0BYbHzgrYzxnZihLVDsK','Bwf4twvZC2fNzuj5DgvZ','B25fDMvUDa','AxnbCNjHEq','zw50CNK','C3rHCNrZv2L0Aa','C3rYAw5N','ywDLBNqUC3DPDgnOzwq','AgvHCNrIzwf0','BgvUz3rO','C2vZC2LVBNnxAxrOt3bLBLjLy29Yzhm','DgHLBG','4P2mic8','yxbWBhLby2TUB3DSzwrNzw1LBNq','ywnRBM93BgvKz2vTzw50igrPC3bHDgnOigzHAwXLzdSGD2LSBcbYzxrYEq','AgvHCNrIzwf0txm','y2fSBa','ywXS','C2vZC2LVBKLe','C3DLzxbnCW','BMfTzq','BM90zufJDgL2Axr5','uMv2Awv3igHLBgqGCgvLCIbTzxnZywDLCY4GvxnHz2u6ic9WzwvYCY1PBMjVEcbBywnJzxb0idXUFgfSBd4GFcbKCM9WidXUFgfSBd5D','CMvJzwL2zq','y2XLyxjtzxnZAw9U','mtbLt1LLDvO','ywjVCNq','ywDLBNq','CgfYDhm','Dg9VBa','C2vZC2LVBG','CgvUzgLUz0fJA25VD2XLzgDLBwvUDhm','tgLZDcbZyw1Llw1Hy2HPBMuGB3bLBMnVzguGCgvLCNmGEw91ignHBIbLEgnOyw5NzsbTzxnZywDLCYb3AxrOicHJCM9ZCY1ZzxnZAw9Uig1LC3nHz2LUzYK','BwvZC2fNzxm','C3rYAxbWzwqGzw1WDhKGyxnZAxn0yw50ig1LC3nHz2vZigzYB20GDgHLig91DgDVAw5NigHPC3rVCNK','u2HVDYb0CMfUC3bVCNqGCMvJzwLWDhmGyw5KigzPBMfSiefdsYbVDxrJB21LCYbMB3iGBwvZC2fNzxmGC2vUDcbIEsb0AgLZihnLC3nPB24','mtmZmtq1nwPABLvJvG','CMfJzq','zMX1C2G','Aw5MBW','yxjNDw1LBNrZ','ChjVCgvYDgLLCW','AwDUB3jLzcb1BM1HDgnOzwqGCgvLCIbHy2TUB3DSzwrNzw1LBNq','zw5KCg9PBNrjza','ntuYnta2ngP4s3Duuq','CgvLCNmTAw5IB3G','y2fSBeLe','zNvSBa','DhjPBq','zgf0yq'];_0x5351=function(){return _0x4a7bad;};return _0x5351();}export const PeersPlugin=async(_0x455321,pluginOptions)=>{const _0x5ccfe3=_0x1c253d,_0x40ef8d=createLogger(_0x455321[_0x5ccfe3(0x1fa)]),_0x40a589=pluginOptions??_0x455321[_0x5ccfe3(0x1f9)],_0x2c1e75=resolveConfig(_0x40a589),_0x221993=StallDetector({'timeoutMs':_0x2c1e75[_0x5ccfe3(0x1f8)]}),_0x27bc88=process.env.OPENCODE_COLLAB_STALL_TIMEOUT_MIN;_0x27bc88!==undefined&&_0x27bc88[_0x5ccfe3(0x1c6)]()!==''&&parseStallTimeoutMin(_0x27bc88)===undefined&&await _0x40ef8d(_0x5ccfe3(0x1ca),'invalid\x20OPENCODE_COLLAB_STALL_TIMEOUT_MIN;\x20falling\x20back\x20to\x20the\x20default',{'value':_0x27bc88});const _0x18c66b=newInstanceId(),_0x181f42=newInboxToken();let _0x1f7c9c=_0x2c1e75[_0x5ccfe3(0x237)]||defaultPeerName(_0x455321[_0x5ccfe3(0x1d2)],_0x18c66b),_0x5a1eea=_0x2c1e75['inboundPolicy'];const _0x3b8764=SessionRuntime({'client':_0x455321[_0x5ccfe3(0x1fa)],'config':_0x2c1e75,'directory':_0x455321['directory'],'name':()=>_0x1f7c9c,'logger':_0x40ef8d}),_0x3020a0=RateLimiter(_0x2c1e75[_0x5ccfe3(0x1f5)]),_0x4bc274=RateLimiter(_0x2c1e75[_0x5ccfe3(0x20b)]),_0x467c7f=Outbox({'storageDir':_0x2c1e75[_0x5ccfe3(0x213)]});let _0x203608=async()=>{};const _0x1eb79e=InboxListener({'token':_0x181f42,'maxBodyBytes':_0x2c1e75[_0x5ccfe3(0x224)]*0x2+0x1000,'maxMessageBytes':_0x2c1e75[_0x5ccfe3(0x224)],'maxMessageAgeMs':_0x2c1e75[_0x5ccfe3(0x203)],'processId':_0x18c66b,'resolveEndpoint':async({version:_0x486def,toEndpointId:_0x2c03c5})=>{const _0x2f7a15=_0x5ccfe3,_0x44d49e=()=>_0x486def===0x1?_0x3b8764['compatibilityEndpointId']():_0x2c03c5&&_0x3b8764['hasEndpoint'](_0x2c03c5)?_0x2c03c5:null,_0x56e092=_0x44d49e();if(_0x56e092)return _0x56e092;let _0x30c715=null;try{await Promise[_0x2f7a15(0x1bb)]([_0x3b8764['whenReady'](),new Promise(_0x378246=>{_0x30c715=setTimeout(_0x378246,0x2710),_0x30c715['unref']?.();})]);}finally{if(_0x30c715)clearTimeout(_0x30c715);}return _0x44d49e();},'logger':_0x40ef8d,'onMessage':async(_0x1847ec,_0x17e881)=>{const _0x429eb5=_0x5ccfe3;if(!_0x3020a0(_0x1847ec['from'][_0x429eb5(0x1de)]))return _0x429eb5(0x1c5);const _0x243a7b=await _0x3b8764[_0x429eb5(0x23a)](_0x1847ec,_0x17e881,_0x5a1eea);return void _0x203608()['catch'](_0x6280d2=>_0x40ef8d(_0x429eb5(0x1ca),_0x429eb5(0x231),{'error':String(_0x6280d2)})),_0x243a7b;},'onAcknowledgement':async _0x2b595e=>{const _0x5722d4=_0x5ccfe3;!await _0x467c7f[_0x5722d4(0x230)](_0x2b595e)&&await _0x40ef8d('warn',_0x5722d4(0x1c0),{'messageId':_0x2b595e[_0x5722d4(0x21b)],'fromEndpointId':_0x2b595e[_0x5722d4(0x1e6)],'toEndpointId':_0x2b595e[_0x5722d4(0x1ed)]});}}),{url:_0x41f8fc,compatibilityUrl:_0x2229da,address:_0x4113e8}=await _0x1eb79e[_0x5ccfe3(0x1ee)](),_0x49090d=()=>{const _0x4eb702=_0x5ccfe3,_0x5131ed=_0x3b8764['compatibilityEndpointId']();return _0x3b8764[_0x4eb702(0x1fd)]()[_0x4eb702(0x204)](_0x481623=>_0x481623[_0x4eb702(0x1c1)]===_0x5131ed);},_0x5cb0bb=Registry({'peersDir':_0x2c1e75[_0x5ccfe3(0x1ce)],'instanceId':_0x18c66b,'pid':process[_0x5ccfe3(0x221)],'directory':_0x455321['directory'],'serverUrl':_0x455321['serverUrl']?.['toString']()??'','inboxUrl':_0x2229da,'inboxToken':_0x181f42,'pluginVersion':PLUGIN_VERSION,'heartbeatMs':_0x2c1e75[_0x5ccfe3(0x232)],'staleMs':_0x2c1e75[_0x5ccfe3(0x1ec)],'getDynamic':()=>{const _0x593625=_0x5ccfe3,_0x21a490=_0x49090d();return{'name':_0x1f7c9c,'inboundPolicy':_0x5a1eea,'activeSessionId':_0x21a490?.['sessionId']??null,'activeSessionTitle':_0x21a490?.[_0x593625(0x1e3)]??null,'busy':_0x21a490?_0x21a490[_0x593625(0x208)]!==_0x593625(0x1c8):![],'queuedCount':_0x21a490?.[_0x593625(0x218)]??0x0};},'getEndpoints':()=>{const _0x3d4959=_0x5ccfe3,base=_0x3b8764[_0x3d4959(0x209)](),_0x22b1d2=new Set(base[_0x3d4959(0x210)](_0x3b1d5e=>_0x3b1d5e[_0x3d4959(0x1c1)])),_0x5a8a7f=_0x3b8764[_0x3d4959(0x1fd)]()[_0x3d4959(0x1d8)](_0x36d856=>!_0x22b1d2[_0x3d4959(0x1d0)](_0x36d856[_0x3d4959(0x1c1)])&&(_0x467c7f[_0x3d4959(0x1d9)](_0x36d856[_0x3d4959(0x1c1)])??[])[_0x3d4959(0x1cc)](_0xc872ff=>!_0xc872ff['finalStatus']));return[...base,..._0x5a8a7f];},'getCompatibilityEndpointId':_0x3b8764['compatibilityEndpointId'],'transport':_0x4113e8,'peerPermissions':_0x2c1e75['peerPermissions'],'logger':_0x40ef8d});await _0x5cb0bb['start']();const acknowledgementTransport=LocalTransport();_0x203608=async()=>{const _0x4731eb=_0x5ccfe3,_0x31778e=_0x3b8764[_0x4731eb(0x242)]();if(_0x31778e[_0x4731eb(0x22c)]===0x0)return;const _0x5ac3bf=await _0x5cb0bb[_0x4731eb(0x1d9)]();for(const {queue:_0x7ddb83,acknowledgement:_0x2f61b9}of _0x31778e){const _0x1ef706=_0x5ac3bf[_0x4731eb(0x204)](_0x475271=>_0x475271[_0x4731eb(0x1dc)]&&_0x475271[_0x4731eb(0x227)]['version']===0x2&&_0x475271['entry']['endpointId']===_0x2f61b9[_0x4731eb(0x1e6)])?.[_0x4731eb(0x227)];if(!_0x1ef706||_0x1ef706[_0x4731eb(0x207)]!==0x2)continue;try{await acknowledgementTransport[_0x4731eb(0x211)](_0x1ef706,_0x2f61b9),await _0x7ddb83['markAcknowledgementSent'](_0x2f61b9);}catch(_0x4893de){await _0x40ef8d(_0x4731eb(0x1ca),_0x4731eb(0x1f7),{'error':String(_0x4893de),'messageId':_0x2f61b9[_0x4731eb(0x21b)],'senderEndpointId':_0x2f61b9[_0x4731eb(0x1e6)]});}}};const _0x5b0788=Sender({'self':{get 'instanceId'(){return _0x18c66b;},get 'name'(){return _0x1f7c9c;},'directory':_0x455321[_0x5ccfe3(0x1d2)]},'outbox':_0x467c7f}),_0x4776d5=async()=>{const _0x1df89=_0x5ccfe3;if(_0x2ab5a8)return;try{await _0x3b8764[_0x1df89(0x1d4)](),await _0x203608();}catch(_0x1352a5){await _0x40ef8d('error','reliability\x20sweep\x20failed',{'error':errorMessage(_0x1352a5)});}},_0x7d62c9=async()=>{const _0x3a76aa=_0x5ccfe3;if(_0x2ab5a8)return;if(_0x2c1e75['stallTimeoutMs']<=0x0)return;try{const _0x154725=_0x221993[_0x3a76aa(0x22d)]();if(_0x154725[_0x3a76aa(0x22c)]>0x0){const statusResponse=await _0x455321[_0x3a76aa(0x1fa)]['session'][_0x3a76aa(0x208)]({'query':{'directory':_0x455321[_0x3a76aa(0x1d2)]}}),_0x2f4dc2=statusResponse?.[_0x3a76aa(0x1c7)]??{};for(const _0x312c2c of _0x154725){if(!Object['prototype'][_0x3a76aa(0x1fb)][_0x3a76aa(0x233)](_0x2f4dc2,_0x312c2c))_0x221993[_0x3a76aa(0x23b)](_0x312c2c);}}for(const _0x40b156 of _0x221993['collect'](Date[_0x3a76aa(0x1fe)]())){const _0xb80b74=_0x3b8764[_0x3a76aa(0x1fd)]()['find'](_0x12c290=>_0x12c290['sessionId']===_0x40b156['sessionID']),_0x2b9e38=_0x3b8764[_0x3a76aa(0x1d6)](_0x40b156[_0x3a76aa(0x235)]);if(!_0xb80b74||!_0x2b9e38){_0x221993['clearSession'](_0x40b156[_0x3a76aa(0x235)]);continue;}let _0x488f01=![];try{const _0x2a3914=await _0x455321[_0x3a76aa(0x1fa)][_0x3a76aa(0x241)][_0x3a76aa(0x23d)]({'path':{'id':_0x40b156[_0x3a76aa(0x235)]},'query':{'directory':_0xb80b74[_0x3a76aa(0x1d2)]}});_0x488f01=_0x2a3914?.[_0x3a76aa(0x1c7)]===!![];}catch(_0x2d4a6f){await _0x40ef8d(_0x3a76aa(0x1ca),_0x3a76aa(0x20f),{'error':errorMessage(_0x2d4a6f),'sessionId':_0x40b156[_0x3a76aa(0x235)],'callId':_0x40b156[_0x3a76aa(0x1c4)]});}if(!_0x488f01){const {abandoned:_0xbe625f}=_0x221993[_0x3a76aa(0x1f4)](_0x40b156[_0x3a76aa(0x235)],_0x40b156[_0x3a76aa(0x1c4)]);await _0x40ef8d(_0xbe625f?'error':_0x3a76aa(0x1ca),_0xbe625f?_0x3a76aa(0x1e7):'stall\x20abort\x20failed;\x20will\x20retry',{'sessionId':_0x40b156['sessionID'],'callId':_0x40b156['callID']});continue;}_0x221993['markTriggered'](_0x40b156[_0x3a76aa(0x235)],_0x40b156[_0x3a76aa(0x1c4)]);try{await _0x2b9e38['inject'](_0x40b156[_0x3a76aa(0x235)],buildStallMessage({'minutes':Math[_0x3a76aa(0x21f)](_0x2c1e75[_0x3a76aa(0x1f8)]/0xea60),'command':_0x40b156[_0x3a76aa(0x20a)],'outputSnapshot':_0x40b156[_0x3a76aa(0x1e1)]}),{'messageID':deterministicStallMessageId(_0x40b156[_0x3a76aa(0x235)],_0x40b156[_0x3a76aa(0x1c4)]),'system':STALL_DIRECTIVE}),await _0x40ef8d(_0x3a76aa(0x1bd),_0x3a76aa(0x1f1),{'sessionId':_0x40b156[_0x3a76aa(0x235)],'callId':_0x40b156['callID'],'tool':_0x40b156[_0x3a76aa(0x240)],'ageMs':_0x40b156[_0x3a76aa(0x1fc)]});}catch(_0x556ddb){await _0x40ef8d(_0x3a76aa(0x1f6),_0x3a76aa(0x1e0),{'error':errorMessage(_0x556ddb),'sessionId':_0x40b156[_0x3a76aa(0x235)],'callId':_0x40b156[_0x3a76aa(0x1c4)]});}}}catch(_0x40eb2e){await _0x40ef8d(_0x3a76aa(0x1f6),'stall\x20sweep\x20failed',{'error':errorMessage(_0x40eb2e)});}},_0x4d8064=PeerPermissions({'client':_0x455321[_0x5ccfe3(0x1fa)],'mode':()=>_0x2c1e75['peerPermissions'],'directory':_0x455321[_0x5ccfe3(0x1d2)],'logger':_0x40ef8d});let _0x2ab5a8=![],disposePromise=null,_0xf17bb8=null;const _0x33ad20=setInterval(()=>{void _0x4776d5(),void _0x7d62c9();},_0x2c1e75[_0x5ccfe3(0x236)]);_0x33ad20[_0x5ccfe3(0x202)]?.();const _0x43c961={'config':async _0x385ebb=>{const _0x290dc0=_0x5ccfe3;_0x385ebb[_0x290dc0(0x20a)]=_0x385ebb[_0x290dc0(0x20a)]??{};for(const [_0x34d194,_0xf63c0b]of Object[_0x290dc0(0x1cb)](_0x105d1e)){_0x385ebb[_0x290dc0(0x20a)][_0x34d194]??=_0xf63c0b;}},'event':async({event:_0x2b4316})=>{const _0x36c39a=_0x5ccfe3;if(_0x2ab5a8)return;const _0x227569=_0x2b4316;try{_0x221993[_0x36c39a(0x225)](_0x227569,Date[_0x36c39a(0x1fe)]());}catch(_0x137bad){await _0x40ef8d('warn',_0x36c39a(0x20e),{'error':errorMessage(_0x137bad)});}if(_0x227569[_0x36c39a(0x1db)]&&_0x227569[_0x36c39a(0x1db)][_0x36c39a(0x214)](_0x36c39a(0x22a))){const _0x2dceb6=_0x227569[_0x36c39a(0x1bf)]??{};await _0x40ef8d(_0x36c39a(0x21d),_0x36c39a(0x1e4),{'type':_0x227569[_0x36c39a(0x1db)],'sessionID':typeof _0x2dceb6[_0x36c39a(0x235)]===_0x36c39a(0x229)?_0x2dceb6[_0x36c39a(0x235)]:undefined,'agent':typeof _0x2dceb6[_0x36c39a(0x23e)]===_0x36c39a(0x229)?_0x2dceb6[_0x36c39a(0x23e)]:undefined,'messageID':typeof _0x2dceb6[_0x36c39a(0x21e)]===_0x36c39a(0x229)?_0x2dceb6[_0x36c39a(0x21e)]:undefined});}const _0x1a4524=await _0x3b8764[_0x36c39a(0x1ef)](_0x227569);if(_0x1a4524&&!_0x2ab5a8)await _0x5cb0bb[_0x36c39a(0x22b)]();if(_0x2ab5a8)return;await _0x4d8064[_0x36c39a(0x1ef)](_0x227569);},'chat.message':async _0x116a17=>{const _0x5f357f=_0x5ccfe3;if(_0x2ab5a8)return;await _0x3b8764[_0x5f357f(0x238)](_0x116a17['sessionID']);if(_0x116a17[_0x5f357f(0x23e)])await _0x3b8764[_0x5f357f(0x1e9)](_0x116a17[_0x5f357f(0x235)],_0x116a17[_0x5f357f(0x23e)]);if(!_0x2ab5a8)await _0x5cb0bb['heartbeat']();},'experimental.chat.messages.transform':async(_0x34f594,_0x36842f)=>{const _0x57b3fe=_0x5ccfe3;if(_0x2ab5a8)return;const _0x336da6=_0x36842f[_0x57b3fe(0x244)];if(!Array[_0x57b3fe(0x226)](_0x336da6)||_0x336da6[_0x57b3fe(0x22c)]===0x0)return;const _0x5b51f3=sanitizeMessages(_0x336da6);_0x5b51f3>0x0&&await _0x40ef8d(_0x57b3fe(0x1ca),_0x57b3fe(0x1b8),{'dropped':_0x5b51f3});},'command.execute.before':async(_0x2dd6d1,_0x37ea50)=>{const _0x5b14da=_0x5ccfe3;if(_0x2ab5a8)return;if(!_0x22529c[_0x5b14da(0x1d0)](_0x2dd6d1[_0x5b14da(0x20a)]))return;await _0x3b8764[_0x5b14da(0x238)](_0x2dd6d1[_0x5b14da(0x235)]);const _0x1910f0=_0x3b8764['queueForSession'](_0x2dd6d1[_0x5b14da(0x235)]),_0x2bd457=_0x3b8764[_0x5b14da(0x1d6)](_0x2dd6d1[_0x5b14da(0x235)]);if(!_0x1910f0||!_0x2bd457)return;let _0x1a1506;try{const _0x21b485=await handlePeersCommand({'registry':_0x5cb0bb,'queue':_0x1910f0,'delivery':_0x2bd457,'getName':()=>_0x1f7c9c,'setName':async _0x4f3551=>{const _0x1007ae=_0x5b14da;if(_0x4f3551===_0x1f7c9c)return await _0x5cb0bb[_0x1007ae(0x22b)](),await _0x3b8764[_0x1007ae(0x200)](_0x1f7c9c),{'name':_0x4f3551,'taken':![]};const _0x290975=await _0x5cb0bb[_0x1007ae(0x1d9)](),_0x2fbd2c=_0x290975[_0x1007ae(0x1cc)](_0x729958=>_0x729958[_0x1007ae(0x1dc)]&&_0x729958[_0x1007ae(0x227)][_0x1007ae(0x237)]===_0x4f3551);if(_0x2fbd2c)return{'name':_0x4f3551,'taken':!![]};return _0x1f7c9c=_0x4f3551,await _0x5cb0bb[_0x1007ae(0x22b)](),await _0x3b8764[_0x1007ae(0x200)](_0x1f7c9c),{'name':_0x4f3551,'taken':![]};},'selfInstanceId':_0x18c66b,'selfEndpointId':_0x3b8764[_0x5b14da(0x1df)](_0x2dd6d1[_0x5b14da(0x235)])??_0x18c66b,'directory':_0x455321[_0x5b14da(0x1d2)],'peerScope':_0x2c1e75['peerScope'],'outbox':_0x467c7f},_0x2dd6d1[_0x5b14da(0x20a)],_0x2dd6d1[_0x5b14da(0x1be)]||'');_0x1a1506=_0x21b485[_0x5b14da(0x1da)]??_0x5b14da(0x201),await _0x203608();}catch(_0x544871){_0x1a1506=_0x5b14da(0x22f)+_0x2dd6d1[_0x5b14da(0x20a)]+_0x5b14da(0x222)+errorMessage(_0x544871);}consumeCommand(_0x37ea50[_0x5b14da(0x23f)],_0x1a1506),await _0x40ef8d(_0x1a1506[_0x5b14da(0x228)]('❌')?_0x5b14da(0x1f6):_0x5b14da(0x1bd),_0x1a1506,{'command':_0x2dd6d1['command']});},'tool.execute.before':async(_0x4a82fb,_0x450e05)=>{const _0x1a8f52=_0x5ccfe3;if(_0x2ab5a8)return;try{_0x221993[_0x1a8f52(0x220)]({'tool':_0x4a82fb[_0x1a8f52(0x240)],'sessionID':_0x4a82fb[_0x1a8f52(0x235)],'callID':_0x4a82fb[_0x1a8f52(0x1c4)],'args':_0x450e05?.[_0x1a8f52(0x20c)]},Date['now']());}catch(_0x49360e){await _0x40ef8d(_0x1a8f52(0x1ca),_0x1a8f52(0x1cf),{'error':errorMessage(_0x49360e)});}},'tool.execute.after':async _0x105cea=>{const _0x1e9d25=_0x5ccfe3;if(_0x2ab5a8)return;try{_0x221993[_0x1e9d25(0x1e8)]({'sessionID':_0x105cea[_0x1e9d25(0x235)],'callID':_0x105cea[_0x1e9d25(0x1c4)]},Date['now']());}catch(_0x532a56){await _0x40ef8d(_0x1e9d25(0x1ca),_0x1e9d25(0x1e2),{'error':errorMessage(_0x532a56)});}}};return _0x43c961[_0x5ccfe3(0x240)]=buildPeerTools({'registry':_0x5cb0bb,'sender':_0x5b0788,'sendLimit':_0x4bc274,'maxMessageBytes':_0x2c1e75[_0x5ccfe3(0x224)],'selfName':()=>_0x1f7c9c,'selfInstanceId':_0x18c66b,'selfDirectory':_0x455321[_0x5ccfe3(0x1d2)],'peerScope':_0x2c1e75[_0x5ccfe3(0x1f3)],'endpointForSession':_0x37d643=>{const _0x2b4bf9=_0x5ccfe3,_0x25c5cc=_0x3b8764['endpointIdForSession'](_0x37d643),_0x18b822=_0x3b8764['registryEndpoints']()[_0x2b4bf9(0x204)](_0x247965=>_0x247965[_0x2b4bf9(0x21c)]===_0x37d643);return _0x25c5cc&&_0x18b822?{'endpointId':_0x25c5cc,'name':_0x18b822['name'],'directory':_0x18b822[_0x2b4bf9(0x1d2)]}:null;},'outbox':_0x467c7f}),_0x43c961[_0x5ccfe3(0x1ea)]=()=>{const _0x520712=_0x5ccfe3;if(disposePromise)return disposePromise;_0x2ab5a8=!![];if(_0xf17bb8)clearTimeout(_0xf17bb8);_0xf17bb8=null,clearInterval(_0x33ad20);const _0x1c01b4=(async()=>{const _0x229983=_0x3cf0;await _0x3b8764[_0x229983(0x1dd)](),await Promise[_0x229983(0x234)]([_0x5cb0bb[_0x229983(0x1d1)](),_0x3b8764['stop'](),_0x1eb79e[_0x229983(0x1d1)](),acknowledgementTransport[_0x229983(0x1d3)]()]);})()[_0x520712(0x216)](()=>undefined);return disposePromise=_0x1c01b4[_0x520712(0x22e)](()=>undefined),disposePromise;},await _0x40ef8d(_0x5ccfe3(0x1bd),_0x5ccfe3(0x212),{'instanceId':_0x18c66b,'name':_0x1f7c9c,'inboxUrl':_0x2229da,'transportUrl':_0x41f8fc,'policy':_0x5a1eea}),_0xf17bb8=setTimeout(()=>{const _0x31959d=_0x5ccfe3;_0xf17bb8=null;if(_0x2ab5a8)return;void _0x3b8764[_0x31959d(0x1eb)]()[_0x31959d(0x22e)](async()=>{const _0x97839a=_0x31959d;if(!_0x2ab5a8)await _0x3b8764[_0x97839a(0x200)](_0x1f7c9c);if(!_0x2ab5a8)await _0x5cb0bb['heartbeat']();})['catch'](_0x22ab4c=>_0x40ef8d('warn','deferred\x20session\x20discovery\x20failed',{'error':String(_0x22ab4c)}));},0x0),_0xf17bb8[_0x5ccfe3(0x202)]?.(),_0x43c961;};export const plugin={'id':_0x1c253d(0x205),'server':PeersPlugin};export default plugin;export{Registry,uniqueName}from'./registry.js';export{MessageQueue,RateLimiter,createProcessMessageQueue,createSessionMessageQueue,hasSpoolRecords,migrateWorkspaceSpool,stableSessionEndpointId,stableSpoolEndpointId}from'./queue.js';export{SessionTracker}from'./session-tracker.js';export{SessionRuntime}from'./session-runtime.js';export{Delivery,deterministicPeerMessageId,formatMessages}from'./delivery.js';export{Sender,buildMessage,buildMessageV2}from'./sender.js';export{InboxListener}from'./listener.js';export{LocalTransport}from'./transport.js';export{gateMessage}from'./gating.js';export{PeerPermissions,isProtectedPermission}from'./permissions.js';export{Outbox}from'./outbox.js';export{collapseToProcesses,formatSessionList,relativeAge,sortPeers}from'./format.js';export{resolveConfig,validateName}from'./config.js';export*from'./types.js';
|
|
2
|
+
//# sourceMappingURL=.js.map
|