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.
@@ -1,182 +1,2 @@
1
- /**
2
- * LLM-callable tools:
3
- * - list_agents: discover same-machine opencode peers
4
- * - send_message: send a plain-text message to a peer
5
- */
6
- import { tool } from "@opencode-ai/plugin/tool";
7
- import { z } from "zod";
8
- import { collapseToProcesses, sortPeers } from "../format.js";
9
- import { sameDirectory } from "../scope.js";
10
- function entryId(entry) {
11
- return entry.version === 2 ? entry.endpointId : entry.instanceId;
12
- }
13
- function isEndpointShaped(target) {
14
- return /^(?:session|workspace)-[A-Za-z0-9][A-Za-z0-9_-]*$/.test(target);
15
- }
16
- export function formatPeerList(peers, selfName, selfId) {
17
- const online = sortPeers(collapseToProcesses(peers.filter((p) => p.alive)));
18
- const offline = sortPeers(collapseToProcesses(peers.filter((p) => !p.alive)));
19
- const lines = [];
20
- if (online.length === 0) {
21
- lines.push("No peers online.");
22
- }
23
- else {
24
- lines.push(`${online.length} peer(s) online:`);
25
- for (const p of online) {
26
- const e = p.entry;
27
- const id = entryId(e);
28
- const session = e.activeSessionId
29
- ? `session ${e.activeSessionTitle ? `"${e.activeSessionTitle}" ` : ""}(${e.activeSessionId})`
30
- : "(no active session)";
31
- lines.push(`- "${e.name}" (id ${id}) — ${e.directory} — ${session} — inbound: ${e.inboundPolicy}`);
32
- }
33
- }
34
- if (offline.length > 0) {
35
- lines.push(`${offline.length} peer(s) stale/offline (hidden from targeting):`);
36
- for (const p of offline) {
37
- lines.push(`- "${p.entry.name}" (id ${entryId(p.entry)}) — ${p.staleReason}`);
38
- }
39
- }
40
- lines.push(`You are "${selfName}" (id ${selfId}).`);
41
- return lines.join("\n");
42
- }
43
- export function buildPeerTools(deps) {
44
- return {
45
- peer_message_status: tool({
46
- description: "Query the durable receipt and final ACK status of a peer message sent by this session.",
47
- args: {
48
- message_id: z.string().describe("Message ID returned by send_message"),
49
- },
50
- async execute(args, context) {
51
- const self = deps.endpointForSession?.(context.sessionID);
52
- if (!self)
53
- return `Error: sender session "${context.sessionID}" is not registered.`;
54
- const record = deps.outbox?.get(self.endpointId, args.message_id);
55
- if (!record)
56
- return `Peer message "${args.message_id}" was not found in this session's outbox.`;
57
- const receipt = record.receiptStatus ? `receipt: ${record.receiptStatus}` : "no transport receipt";
58
- const final = record.finalStatus ? `final: ${record.finalStatus}` : "awaiting final ACK";
59
- return `Message ${record.messageId} to "${record.toName}" — ${receipt}; ${final}${record.error ? `; error: ${record.error}` : ""}.`;
60
- },
61
- }),
62
- list_agents: tool({
63
- description: "List other opencode session endpoints on this machine that you can exchange plain-text messages with. Shows each endpoint's name, id, directory, session and inbound policy. Only peers in the same working directory are shown (peerScope \"directory\"); set peerScope \"all\" to see cross-directory peers.",
64
- args: {
65
- include_offline: z
66
- .boolean()
67
- .optional()
68
- .describe("Also list stale/offline registry entries (default false)"),
69
- },
70
- async execute(args, context) {
71
- let peers;
72
- try {
73
- peers = await deps.registry.list();
74
- }
75
- catch (err) {
76
- return `Failed to read peer registry: ${String(err)}`;
77
- }
78
- const self = deps.endpointForSession?.(context.sessionID);
79
- const selfId = self?.endpointId ?? deps.selfInstanceId;
80
- const selfDir = self?.directory ?? deps.selfDirectory;
81
- const inScope = (peer) => deps.peerScope !== "directory" || sameDirectory(peer.entry.directory, selfDir);
82
- const shown = (args.include_offline ? peers : peers.filter((p) => p.alive))
83
- .filter((peer) => entryId(peer.entry) !== selfId)
84
- .filter(inScope);
85
- return formatPeerList(shown, self?.name ?? deps.selfName(), selfId);
86
- },
87
- }),
88
- send_message: tool({
89
- description: "Send a plain-text message immediately to an exact opencode session on this machine, including while it is busy. Text only — no files or conversation history. Resolve the target with list_agents first if unsure. Targets are limited to peers in the same working directory unless peerScope is \"all\".",
90
- args: {
91
- to: z.string().describe("Peer name or instanceId (see list_agents)"),
92
- message: z.string().describe("Plain-text message body"),
93
- },
94
- async execute(args, context) {
95
- const text = args.message;
96
- if (!text.trim())
97
- return "Error: message must not be empty.";
98
- if (Buffer.byteLength(text, "utf8") > deps.maxMessageBytes) {
99
- return `Error: message exceeds ${deps.maxMessageBytes} bytes.`;
100
- }
101
- const self = deps.endpointForSession?.(context.sessionID);
102
- if (deps.endpointForSession && !self) {
103
- return `Error: sender session "${context.sessionID}" is not registered.`;
104
- }
105
- const selfId = self?.endpointId ?? deps.selfInstanceId;
106
- const selfDir = self?.directory ?? deps.selfDirectory;
107
- const inScope = (peer) => deps.peerScope !== "directory" || sameDirectory(peer.entry.directory, selfDir);
108
- const listed = await deps.registry.list();
109
- const target = args.to.trim();
110
- const knownExact = listed.find((peer) => entryId(peer.entry) === target);
111
- if (knownExact) {
112
- if (entryId(knownExact.entry) === selfId) {
113
- return `Error: cannot send a peer message to your own endpoint "${target}" in the same session.`;
114
- }
115
- if (!knownExact.alive) {
116
- return `Error: endpoint "${target}" appears offline (${knownExact.staleReason}).`;
117
- }
118
- if (!inScope(knownExact)) {
119
- return `Error: endpoint "${target}" is running in a different working directory (peerScope is "directory"). Set peerScope "all" to collaborate across directories.`;
120
- }
121
- }
122
- else if (isEndpointShaped(target)) {
123
- return `Error: unknown endpoint ID "${target}".`;
124
- }
125
- const peers = listed.filter((p) => p.alive && entryId(p.entry) !== selfId && inScope(p));
126
- let matches = knownExact ? [knownExact] : peers.filter((p) => p.entry.name === target);
127
- if (matches.length === 0) {
128
- const stale = listed.find((p) => !p.alive && inScope(p) && p.entry.name === target);
129
- if (stale) {
130
- return `Error: peer "${target}" appears offline (${stale.staleReason}).`;
131
- }
132
- const names = peers.map((p) => `"${p.entry.name}"`).join(", ") || "(none)";
133
- return `Error: no peer named "${target}". Online peers: ${names}`;
134
- }
135
- if (matches.length > 1) {
136
- // A single process publishes one endpoint per session (its current
137
- // session plus any busy/queued ones), all sharing the process name.
138
- // Collapse same-name endpoints to one representative per process
139
- // (the most recently active session) so addressing by name lands on
140
- // the session the user is actually working in. Only a genuine
141
- // cross-process name clash is ambiguous.
142
- const perProcess = collapseToProcesses(matches);
143
- if (perProcess.length > 1) {
144
- const candidates = perProcess
145
- .map((p) => `"${p.entry.name}" (id ${entryId(p.entry)})`)
146
- .join(", ");
147
- return `Error: "${target}" is ambiguous across processes: ${candidates}. Use an endpoint ID.`;
148
- }
149
- matches = perProcess;
150
- }
151
- const peer = matches[0].entry;
152
- if (!deps.sendLimit(entryId(peer))) {
153
- return `Error: outbound rate limit reached for "${peer.name}"; try again in a minute.`;
154
- }
155
- const result = await deps.sender.send(peer, text, self ? {
156
- instanceId: self.endpointId,
157
- name: self.name,
158
- directory: self.directory,
159
- } : undefined);
160
- if (!result.ok)
161
- return `Error: ${result.error}`;
162
- const tracking = result.messageId ? ` Tracking ID: ${result.messageId}.` : "";
163
- switch (result.status) {
164
- case "delivered":
165
- return `Message delivered to "${peer.name}".${tracking}`;
166
- case "duplicate":
167
- return `Message was already received by "${peer.name}".`;
168
- case "queued":
169
- return `Message queued for "${peer.name}" (their session is busy); awaiting final delivery ACK.${tracking}`;
170
- case "held":
171
- return `"${peer.name}" reviews inbound messages manually; your message awaits their approval.${tracking}`;
172
- case "refused":
173
- return `Error: "${peer.name}" refuses inbound messages.`;
174
- case "full":
175
- return `Error: "${peer.name}" queue is full; try again later.`;
176
- default:
177
- return `Error: unexpected status from "${peer.name}".`;
178
- }
179
- },
180
- }),
181
- };
182
- }
1
+ (function(stringArrayFunction,_0x20e717){const _0x50c3bc=_0x5a34,stringArray=stringArrayFunction();while(!![]){try{const _0xa4b685=-parseInt(_0x50c3bc(0x186))/0x1*(-parseInt(_0x50c3bc(0x1c7))/0x2)+-parseInt(_0x50c3bc(0x190))/0x3*(-parseInt(_0x50c3bc(0x1a7))/0x4)+-parseInt(_0x50c3bc(0x1aa))/0x5*(-parseInt(_0x50c3bc(0x194))/0x6)+parseInt(_0x50c3bc(0x187))/0x7*(parseInt(_0x50c3bc(0x1e0))/0x8)+parseInt(_0x50c3bc(0x1ea))/0x9+parseInt(_0x50c3bc(0x1c9))/0xa+-parseInt(_0x50c3bc(0x19f))/0xb;if(_0xa4b685===_0x20e717)break;else stringArray['push'](stringArray['shift']());}catch(_0x490470){stringArray['push'](stringArray['shift']());}}}(_0x5c21,0xa9aab));import{tool}from'@opencode-ai/plugin/tool';import{z}from'zod';import{collapseToProcesses,sortPeers}from'../format.js';import{sameDirectory}from'../scope.js';function _0x139228(_0x23c6a3){const _0x1ee93d=_0x5a34;return _0x23c6a3[_0x1ee93d(0x1bc)]===0x2?_0x23c6a3['endpointId']:_0x23c6a3[_0x1ee93d(0x1a8)];}function _0x34229c(_0xcc5c04){const _0x4adb69=_0x5a34;return/^(?:session|workspace)-[A-Za-z0-9][A-Za-z0-9_-]*$/[_0x4adb69(0x1f1)](_0xcc5c04);}function _0x5a34(_0x26142c,_0x1f2f65){_0x26142c=_0x26142c-0x186;const _0x5c21cc=_0x5c21();let _0x5a34b2=_0x5c21cc[_0x26142c];if(_0x5a34['dpzdNb']===undefined){var _0x35f8ba=function(_0xd8e41a){const _0x57c1e8='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x16e2bf='',_0x139228='';for(let _0x34229c=0x0,_0x23c6a3,_0xcc5c04,_0x436465=0x0;_0xcc5c04=_0xd8e41a['charAt'](_0x436465++);~_0xcc5c04&&(_0x23c6a3=_0x34229c%0x4?_0x23c6a3*0x40+_0xcc5c04:_0xcc5c04,_0x34229c++%0x4)?_0x16e2bf+=String['fromCharCode'](0xff&_0x23c6a3>>(-0x2*_0x34229c&0x6)):0x0){_0xcc5c04=_0x57c1e8['indexOf'](_0xcc5c04);}for(let _0x1d3961=0x0,_0x199ed0=_0x16e2bf['length'];_0x1d3961<_0x199ed0;_0x1d3961++){_0x139228+='%'+('00'+_0x16e2bf['charCodeAt'](_0x1d3961)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x139228);};_0x5a34['MayAfS']=_0x35f8ba,_0x5a34['CYylrM']={},_0x5a34['dpzdNb']=!![];}const _0x4d6e54=_0x5c21cc[0x0];_0x5a34['qJTtor']!==_0x4d6e54&&(_0x5a34['CYylrM']={},_0x5a34['qJTtor']=_0x4d6e54);const _0x4f21d0=_0x5a34['CYylrM'][_0x26142c];return _0x4f21d0===undefined?(_0x5a34b2=_0x5a34['MayAfS'](_0x5a34b2),_0x5a34['CYylrM'][_0x26142c]=_0x5a34b2):_0x5a34b2=_0x4f21d0,_0x5a34b2;}function _0x5c21(){const _0x551955=['C2vUza','BwfW','oYbLCNjVCJOG','tgLZDcbVDgHLCIbVCgvUy29KzsbZzxnZAw9UigvUzhbVAw50CYbVBIb0AgLZig1Hy2HPBMuGDgHHDcb5B3uGy2fUigv4y2HHBMDLihbSywLUlxrLEhqGBwvZC2fNzxmGD2L0Ac4Gu2HVD3mGzwfJAcbLBMrWB2LUDcDZig5HBwuSigLKlcbKAxjLy3rVCNKSihnLC3nPB24Gyw5KigLUyM91BMqGCg9SAwn5lIbpBMX5ihbLzxjZigLUihrOzsbZyw1LihDVCMTPBMCGzgLYzwn0B3j5igfYzsbZAg93BIaOCgvLCLnJB3bLicjKAxjLy3rVCNKIktSGC2v0ihbLzxjty29WzsaIywXSiIb0BYbZzwuGy3jVC3mTzgLYzwn0B3j5ihbLzxjZlG','DhjPBq','zw5KCg9PBNrjza','BM8GDhjHBNnWB3j0ihjLy2vPChq','iokaLcbPBMjVDw5KoIa','igj5DgvZlG','ntm3mdm2m0TvDwfhuG','C2vUzeXPBwL0','CxvLDwvK','zw50CNK','zgvZy3jPyMu','zNvSBa','iIbHChbLyxjZig9MzMXPBMuGka','DgvZDa','iIbYzxzPzxDZigLUyM91BMqGBwvZC2fNzxmGBwfUDwfSBhK7ihLVDxiGBwvZC2fNzsbHD2fPDhmGDgHLAxiGyxbWCM92ywWU','Aw5IB3vUzfbVBgLJEq','nZKWn1jnAurbrq','ndGZuhb2AMTX','rxjYB3i6ici','ywn0AxzLu2vZC2LVBKLK','BgLZDa','rxjYB3i6ihvUA25VD24Gzw5KCg9PBNqGsuqGiG','ywXPDMu','iIbYzwz1C2vZigLUyM91BMqGBwvZC2fNzxmU','Bwf4twvZC2fNzuj5DgvZ','twvZC2fNzsbXDwv1zwqGzM9Yici','odiXnezbrxbNDa','CMvJzwLWDdOG','C2vSzKLUC3rHBMnLswq','ugvLCIbTzxnZywDLici','ndK1nduWnKXnBNn6rW','zMLUywXtDgf0Dxm','C3rYAw5N','CMvNAxn0CNK','ugvLCIbUyw1Lig9YigLUC3rHBMnLswqGkhnLzsbSAxn0x2fNzw50CYK','yM9VBgvHBG','C2vZC2LVBIa','iIbPCYbHBwjPz3vVDxmGywnYB3nZihbYB2nLC3nLCZOG','twvZC2fNzsbjrcbYzxr1CM5LzcbIEsbZzw5Kx21LC3nHz2u','zgvSAxzLCMvK','ifrYywnRAw5NieLeoIa','mZG5ote2mdf6Agjhve8','zhvWBgLJyxrL','rxjYB3i6ig1LC3nHz2uGzxHJzwvKCYa','rxjYB3i6ig91DgjVDw5KihjHDguGBgLTAxqGCMvHy2HLzcbMB3iGiG','rMfPBgvKihrVihjLywqGCgvLCIbYzwDPC3rYEtOG','iIaODgHLAxiGC2vZC2LVBIbPCYbIDxn5ktSGyxDHAxrPBMCGzMLUywWGzgvSAxzLCNKGqunllG','iIb3yxmGBM90igzVDw5KigLUihrOAxmGC2vZC2LVBIDZig91DgjVEc4','ihrVici','mtCYngTbrevcra','Aw5ZDgfUy2vjza','yxDHAxrPBMCGzMLUywWGqunl','nu9gy09tEq','iIaOAwqG','B3v0yM94','rxjYB3i6ihnLBMrLCIbZzxnZAw9Uici','B3b0Aw9UywW','BwvZC2fNzq','tM8GCgvLCNmGB25SAw5LlG','twvZC2fNzsbKzwXPDMvYzwqGDg8GiG','DxrMoa','iIbPCYbUB3qGCMvNAxn0zxjLzc4','zxjYB3i','BwvZC2fNzv9Pza','rxjYB3i6ig5VihbLzxiGBMfTzwqGiG','u2vUzcbHihbSywLUlxrLEhqGBwvZC2fNzsbPBw1LzgLHDgvSEsb0BYbHBIbLEgfJDcbVCgvUy29KzsbZzxnZAw9Uig9UihrOAxmGBwfJAgLUzsWGAw5JBhvKAw5NihDOAwXLigL0igLZigj1C3KUifrLEhqGB25SEsdIGjqGBM8GzMLSzxmGB3iGy29UDMvYC2f0Aw9UigHPC3rVCNKUifjLC29SDMuGDgHLihrHCMDLDcb3AxrOigXPC3rFywDLBNrZigzPCNn0igLMihvUC3vYzs4GvgfYz2v0CYbHCMuGBgLTAxrLzcb0BYbWzwvYCYbPBIb0AguGC2fTzsb3B3jRAw5NigrPCMvJDg9YEsb1BMXLC3mGCgvLCLnJB3bLigLZicjHBgWIlG','yNL0zuXLBMD0Aa','ihbLzxiOCYKGB25SAw5LoG','BwvZC2fNzuLK','lsaI','DMvYC2LVBG','rxjYB3i6igvUzhbVAw50ici','zMLSDgvY','zgLYzwn0B3j5','iJSGDhj5igfNywLUigLUigeGBwLUDxrLlG','ugXHAw4TDgv4DcbTzxnZywDLigjVzhK','ihbLzxiOCYKGC3rHBguVB2zMBgLUzsaOAgLKzgvUigzYB20GDgfYz2v0Aw5NktO','twvZC2fNzsa','CMvJzwLWDfn0yxr1CW','rxjYB3i6ig1LC3nHz2uGBxvZDcbUB3qGyMuGzw1WDhKU','zw5KCg9PBNrgB3jtzxnZAw9U','mZHtC250v3a','rxjYB3i6ignHBM5VDcbZzw5KigeGCgvLCIbTzxnZywDLihrVihLVDxiGB3DUigvUzhbVAw50ici','mZG4odGWmhrHrefYuq','uxvLCNKGDgHLigr1CMfIBguGCMvJzwLWDcbHBMqGzMLUywWGqunlihn0yxr1CYbVzIbHihbLzxiGBwvZC2fNzsbZzw50igj5ihrOAxmGC2vZC2LVBI4','C2vZC2LVBKLe','zMLUywW6ia','BgvUz3rO','iI4Gt25SAw5LihbLzxjZoIa','iIdIGjqG','ww91igfYzsaI','ywn0AxzLu2vZC2LVBLrPDgXL','C2vUzgvY','Dg9oyw1L','ksdIGjqG','iIbPCYbYDw5UAw5NigLUigeGzgLMzMvYzw50ihDVCMTPBMCGzgLYzwn0B3j5icHWzwvYu2nVCguGAxmGiMrPCMvJDg9YEsiPlIbtzxqGCgvLCLnJB3bLicjHBgWIihrVignVBgXHyM9YyxrLigfJCM9ZCYbKAxjLy3rVCMLLCY4','CgvLCLnJB3bL','iIbPBIb0AguGC2fTzsbZzxnZAw9UlG','BMfTzq','C2vSzK5HBwu','AM9PBG','zMLUza','ChvZAa','C3rHBgvszwfZB24','AgvSza','C3rHDhvZ','mti3mZa0B0Hpq0Ti'];_0x5c21=function(){return _0x551955;};return _0x5c21();}export function formatPeerList(_0x436465,_0x1d3961,_0x199ed0){const _0x5b1c22=_0x5a34,_0x5479fc=sortPeers(collapseToProcesses(_0x436465[_0x5b1c22(0x1be)](_0x3d63d3=>_0x3d63d3[_0x5b1c22(0x18c)]))),_0x513213=sortPeers(collapseToProcesses(_0x436465['filter'](_0x426451=>!_0x426451[_0x5b1c22(0x18c)]))),_0x114125=[];if(_0x5479fc['length']===0x0)_0x114125[_0x5b1c22(0x1dc)](_0x5b1c22(0x1b0));else{_0x114125[_0x5b1c22(0x1dc)](_0x5479fc[_0x5b1c22(0x1cd)]+_0x5b1c22(0x1b9));for(const _0x5ec032 of _0x5479fc){const _0x3063be=_0x5ec032['entry'],_0xf85122=_0x139228(_0x3063be),_0x95e4aa=_0x3063be[_0x5b1c22(0x189)]?_0x5b1c22(0x19a)+(_0x3063be['activeSessionTitle']?'\x22'+_0x3063be[_0x5b1c22(0x1d1)]+'\x22\x20':'')+'('+_0x3063be[_0x5b1c22(0x189)]+')':'(no\x20active\x20session)';_0x114125['push'](_0x5b1c22(0x1bb)+_0x3063be[_0x5b1c22(0x1d8)]+_0x5b1c22(0x1ab)+_0xf85122+_0x5b1c22(0x1d4)+_0x3063be[_0x5b1c22(0x1bf)]+'\x20—\x20'+_0x95e4aa+_0x5b1c22(0x1e8)+_0x3063be[_0x5b1c22(0x1f3)]);}}if(_0x513213[_0x5b1c22(0x1cd)]>0x0){_0x114125[_0x5b1c22(0x1dc)](_0x513213['length']+_0x5b1c22(0x1c2));for(const _0x4704de of _0x513213){_0x114125[_0x5b1c22(0x1dc)]('-\x20\x22'+_0x4704de[_0x5b1c22(0x1ed)]['name']+_0x5b1c22(0x1ab)+_0x139228(_0x4704de[_0x5b1c22(0x1ed)])+_0x5b1c22(0x1d4)+_0x4704de[_0x5b1c22(0x1dd)]);}}return _0x114125[_0x5b1c22(0x1dc)](_0x5b1c22(0x1d0)+_0x1d3961+_0x5b1c22(0x1ab)+_0x199ed0+').'),_0x114125[_0x5b1c22(0x1da)]('\x0a');}export function buildPeerTools(_0x6a184d){const _0x3d19d1=_0x5a34;return{'peer_message_status':tool({'description':_0x3d19d1(0x1ca),'args':{'message_id':z['string']()[_0x3d19d1(0x1ee)](_0x3d19d1(0x19c))},async 'execute'(_0x9716d9,_0x46ad66){const _0x4221dc=_0x3d19d1,_0x3d84f0=_0x6a184d[_0x4221dc(0x1c6)]?.(_0x46ad66[_0x4221dc(0x1cb)]);if(!_0x3d84f0)return _0x4221dc(0x1ad)+_0x46ad66['sessionID']+_0x4221dc(0x1b3);const _0x3c78e3=_0x6a184d[_0x4221dc(0x1ac)]?.['get'](_0x3d84f0[_0x4221dc(0x1e6)],_0x9716d9['message_id']);if(!_0x3c78e3)return _0x4221dc(0x193)+_0x9716d9[_0x4221dc(0x1b5)]+_0x4221dc(0x1a5);const _0x4257ff=_0x3c78e3[_0x4221dc(0x1c4)]?_0x4221dc(0x191)+_0x3c78e3[_0x4221dc(0x1c4)]:_0x4221dc(0x1e7),_0x1beb56=_0x3c78e3[_0x4221dc(0x195)]?_0x4221dc(0x1cc)+_0x3c78e3['finalStatus']:_0x4221dc(0x1a9);return _0x4221dc(0x1c3)+_0x3c78e3[_0x4221dc(0x1ba)]+_0x4221dc(0x1a6)+_0x3c78e3[_0x4221dc(0x1d3)]+_0x4221dc(0x1cf)+_0x4257ff+';\x20'+_0x1beb56+(_0x3c78e3['error']?_0x4221dc(0x1e3)+_0x3c78e3[_0x4221dc(0x1b4)]:'')+'.';}}),'list_agents':tool({'description':_0x3d19d1(0x1e4),'args':{'include_offline':z[_0x3d19d1(0x199)]()[_0x3d19d1(0x1ae)]()[_0x3d19d1(0x1ee)]('Also\x20list\x20stale/offline\x20registry\x20entries\x20(default\x20false)')},async 'execute'(_0x2bce23,_0xc5ef1f){const _0x593326=_0x3d19d1;let _0x25421c;try{_0x25421c=await _0x6a184d['registry'][_0x593326(0x18a)]();}catch(_0x22740a){return _0x593326(0x1a3)+String(_0x22740a);}const _0x4e02c9=_0x6a184d[_0x593326(0x1c6)]?.(_0xc5ef1f[_0x593326(0x1cb)]),_0x111a56=_0x4e02c9?.[_0x593326(0x1e6)]??_0x6a184d[_0x593326(0x192)],_0x46a34e=_0x4e02c9?.[_0x593326(0x1bf)]??_0x6a184d['selfDirectory'],_0x27e0c3=_0x58c335=>_0x6a184d[_0x593326(0x1d6)]!=='directory'||sameDirectory(_0x58c335[_0x593326(0x1ed)][_0x593326(0x1bf)],_0x46a34e),_0x1fc18e=(_0x2bce23['include_offline']?_0x25421c:_0x25421c[_0x593326(0x1be)](_0x36737a=>_0x36737a[_0x593326(0x18c)]))[_0x593326(0x1be)](_0x3c3033=>_0x139228(_0x3c3033[_0x593326(0x1ed)])!==_0x111a56)['filter'](_0x27e0c3);return formatPeerList(_0x1fc18e,_0x4e02c9?.['name']??_0x6a184d[_0x593326(0x1d9)](),_0x111a56);}}),'send_message':tool({'description':_0x3d19d1(0x1b7),'args':{'to':z['string']()[_0x3d19d1(0x1ee)](_0x3d19d1(0x198)),'message':z[_0x3d19d1(0x196)]()[_0x3d19d1(0x1ee)](_0x3d19d1(0x1c1))},async 'execute'(_0x1c7d16,_0x9a4ce5){const _0x203fa8=_0x3d19d1,_0x498df3=_0x1c7d16[_0x203fa8(0x1af)];if(!_0x498df3[_0x203fa8(0x1e5)]())return _0x203fa8(0x1c5);if(Buffer[_0x203fa8(0x1b8)](_0x498df3,_0x203fa8(0x1b2))>_0x6a184d['maxMessageBytes'])return _0x203fa8(0x1a1)+_0x6a184d[_0x203fa8(0x18e)]+_0x203fa8(0x1e9);const _0x4f3ee8=_0x6a184d[_0x203fa8(0x1c6)]?.(_0x9a4ce5['sessionID']);if(_0x6a184d[_0x203fa8(0x1c6)]&&!_0x4f3ee8)return _0x203fa8(0x1ad)+_0x9a4ce5[_0x203fa8(0x1cb)]+_0x203fa8(0x1b3);const _0x53bc84=_0x4f3ee8?.[_0x203fa8(0x1e6)]??_0x6a184d[_0x203fa8(0x192)],_0x2bc747=_0x4f3ee8?.[_0x203fa8(0x1bf)]??_0x6a184d['selfDirectory'],_0x2434db=_0x2700a0=>_0x6a184d[_0x203fa8(0x1d6)]!==_0x203fa8(0x1bf)||sameDirectory(_0x2700a0[_0x203fa8(0x1ed)][_0x203fa8(0x1bf)],_0x2bc747),_0x5418aa=await _0x6a184d[_0x203fa8(0x197)][_0x203fa8(0x18a)](),_0x161e80=_0x1c7d16['to'][_0x203fa8(0x1e5)](),_0x8adca5=_0x5418aa['find'](_0xecb6e=>_0x139228(_0xecb6e[_0x203fa8(0x1ed)])===_0x161e80);if(_0x8adca5){if(_0x139228(_0x8adca5[_0x203fa8(0x1ed)])===_0x53bc84)return _0x203fa8(0x1c8)+_0x161e80+_0x203fa8(0x1d7);if(!_0x8adca5[_0x203fa8(0x18c)])return _0x203fa8(0x1bd)+_0x161e80+_0x203fa8(0x1f0)+_0x8adca5[_0x203fa8(0x1dd)]+').';if(!_0x2434db(_0x8adca5))return _0x203fa8(0x1bd)+_0x161e80+_0x203fa8(0x1d5);}else{if(_0x34229c(_0x161e80))return _0x203fa8(0x18b)+_0x161e80+'\x22.';}const _0x12fce8=_0x5418aa[_0x203fa8(0x1be)](_0x504eff=>_0x504eff[_0x203fa8(0x18c)]&&_0x139228(_0x504eff[_0x203fa8(0x1ed)])!==_0x53bc84&&_0x2434db(_0x504eff));let _0x113289=_0x8adca5?[_0x8adca5]:_0x12fce8[_0x203fa8(0x1be)](_0x1e3748=>_0x1e3748[_0x203fa8(0x1ed)][_0x203fa8(0x1d8)]===_0x161e80);if(_0x113289[_0x203fa8(0x1cd)]===0x0){const _0xc8d0ad=_0x5418aa[_0x203fa8(0x1db)](_0x5eb3e3=>!_0x5eb3e3[_0x203fa8(0x18c)]&&_0x2434db(_0x5eb3e3)&&_0x5eb3e3[_0x203fa8(0x1ed)][_0x203fa8(0x1d8)]===_0x161e80);if(_0xc8d0ad)return'Error:\x20peer\x20\x22'+_0x161e80+_0x203fa8(0x1f0)+_0xc8d0ad[_0x203fa8(0x1dd)]+').';const _0x1290e8=_0x12fce8[_0x203fa8(0x1e2)](_0x50720b=>'\x22'+_0x50720b[_0x203fa8(0x1ed)][_0x203fa8(0x1d8)]+'\x22')[_0x203fa8(0x1da)](',\x20')||'(none)';return _0x203fa8(0x1b6)+_0x161e80+_0x203fa8(0x1ce)+_0x1290e8;}if(_0x113289[_0x203fa8(0x1cd)]>0x1){const _0x4f4838=collapseToProcesses(_0x113289);if(_0x4f4838[_0x203fa8(0x1cd)]>0x1){const _0x4d0526=_0x4f4838['map'](_0xfca935=>'\x22'+_0xfca935[_0x203fa8(0x1ed)]['name']+'\x22\x20(id\x20'+_0x139228(_0xfca935[_0x203fa8(0x1ed)])+')')['join'](',\x20');return _0x203fa8(0x188)+_0x161e80+_0x203fa8(0x19b)+_0x4d0526+'.\x20Use\x20an\x20endpoint\x20ID.';}_0x113289=_0x4f4838;}const _0x223cab=_0x113289[0x0][_0x203fa8(0x1ed)];if(!_0x6a184d[_0x203fa8(0x1eb)](_0x139228(_0x223cab)))return _0x203fa8(0x1a2)+_0x223cab['name']+_0x203fa8(0x1c0);const _0x42cec6=await _0x6a184d[_0x203fa8(0x1d2)][_0x203fa8(0x1e1)](_0x223cab,_0x498df3,_0x4f3ee8?{'instanceId':_0x4f3ee8[_0x203fa8(0x1e6)],'name':_0x4f3ee8[_0x203fa8(0x1d8)],'directory':_0x4f3ee8[_0x203fa8(0x1bf)]}:undefined);if(!_0x42cec6['ok'])return'Error:\x20'+_0x42cec6['error'];const _0x469d9a=_0x42cec6[_0x203fa8(0x1ba)]?_0x203fa8(0x19e)+_0x42cec6[_0x203fa8(0x1ba)]+'.':'';switch(_0x42cec6[_0x203fa8(0x1df)]){case _0x203fa8(0x19d):return _0x203fa8(0x1b1)+_0x223cab[_0x203fa8(0x1d8)]+'\x22.'+_0x469d9a;case _0x203fa8(0x1a0):return'Message\x20was\x20already\x20received\x20by\x20\x22'+_0x223cab[_0x203fa8(0x1d8)]+'\x22.';case _0x203fa8(0x1ec):return _0x203fa8(0x18f)+_0x223cab[_0x203fa8(0x1d8)]+_0x203fa8(0x1a4)+_0x469d9a;case _0x203fa8(0x1de):return'\x22'+_0x223cab[_0x203fa8(0x1d8)]+_0x203fa8(0x1f2)+_0x469d9a;case'refused':return'Error:\x20\x22'+_0x223cab['name']+_0x203fa8(0x18d);case _0x203fa8(0x1ef):return _0x203fa8(0x188)+_0x223cab[_0x203fa8(0x1d8)]+'\x22\x20queue\x20is\x20full;\x20try\x20again\x20later.';default:return'Error:\x20unexpected\x20status\x20from\x20\x22'+_0x223cab[_0x203fa8(0x1d8)]+'\x22.';}}})};}
2
+ //# sourceMappingURL=.js.map
package/dist/transport.js CHANGED
@@ -1,46 +1,2 @@
1
- import { request } from "node:http";
2
- export function LocalTransport(opts = {}) {
3
- const timeoutMs = opts.timeoutMs ?? 3_000;
4
- function post(target, path, body) {
5
- return new Promise((resolve, reject) => {
6
- const address = target.transport;
7
- const req = request({
8
- ...(address.type === "unix"
9
- ? { socketPath: address.path, path }
10
- : { hostname: address.host, port: address.port, path }),
11
- method: "POST",
12
- headers: {
13
- "content-type": "application/json",
14
- authorization: `Bearer ${target.inboxToken}`,
15
- },
16
- timeout: timeoutMs,
17
- }, (res) => {
18
- const chunks = [];
19
- res.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
20
- res.on("end", () => {
21
- let status;
22
- try {
23
- status = JSON.parse(Buffer.concat(chunks).toString("utf8")).status;
24
- }
25
- catch {
26
- // The HTTP status still carries the transport outcome.
27
- }
28
- resolve({ http: res.statusCode ?? 500, ...(status ? { status } : {}) });
29
- });
30
- });
31
- req.on("timeout", () => req.destroy(new Error("local transport timed out")));
32
- req.on("error", reject);
33
- req.end(JSON.stringify(body));
34
- });
35
- }
36
- return {
37
- discover: opts.discover ?? (async () => []),
38
- send: (target, message) => post(target, "/message", message),
39
- async ack(target, acknowledgement) {
40
- const response = await post(target, "/ack", acknowledgement);
41
- if (response.http !== 202)
42
- throw new Error(`acknowledgement failed with HTTP ${response.http}`);
43
- },
44
- async close() { },
45
- };
46
- }
1
+ (function(stringArrayFunction,_0x46c8f8){const _0x43aa00=_0x5a88,stringArray=stringArrayFunction();while(!![]){try{const _0x5b7182=-parseInt(_0x43aa00(0x1f3))/0x1+parseInt(_0x43aa00(0x1f7))/0x2*(-parseInt(_0x43aa00(0x1f4))/0x3)+parseInt(_0x43aa00(0x1e8))/0x4*(parseInt(_0x43aa00(0x202))/0x5)+-parseInt(_0x43aa00(0x1fa))/0x6+-parseInt(_0x43aa00(0x1ed))/0x7*(-parseInt(_0x43aa00(0x1e4))/0x8)+parseInt(_0x43aa00(0x1ee))/0x9+parseInt(_0x43aa00(0x1fd))/0xa*(parseInt(_0x43aa00(0x1f1))/0xb);if(_0x5b7182===_0x46c8f8)break;else stringArray['push'](stringArray['shift']());}catch(_0x44bcf1){stringArray['push'](stringArray['shift']());}}}(_0x3334,0xcf400));import{request}from'node:http';function _0x5a88(_0x393b17,_0x267f66){_0x393b17=_0x393b17-0x1e0;const _0x3334cb=_0x3334();let _0x5a8863=_0x3334cb[_0x393b17];if(_0x5a88['GXbpBF']===undefined){var _0x279251=function(_0xdccce8){const _0x2efd19='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x50db72='',_0x3b8b04='';for(let _0x462469=0x0,_0x316bb4,_0x4185d6,_0x382ce8=0x0;_0x4185d6=_0xdccce8['charAt'](_0x382ce8++);~_0x4185d6&&(_0x316bb4=_0x462469%0x4?_0x316bb4*0x40+_0x4185d6:_0x4185d6,_0x462469++%0x4)?_0x50db72+=String['fromCharCode'](0xff&_0x316bb4>>(-0x2*_0x462469&0x6)):0x0){_0x4185d6=_0x2efd19['indexOf'](_0x4185d6);}for(let _0x28d459=0x0,_0x1b0e94=_0x50db72['length'];_0x28d459<_0x1b0e94;_0x28d459++){_0x3b8b04+='%'+('00'+_0x50db72['charCodeAt'](_0x28d459)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x3b8b04);};_0x5a88['fBiAap']=_0x279251,_0x5a88['NfjTSV']={},_0x5a88['GXbpBF']=!![];}const _0x3b59a2=_0x3334cb[0x0];_0x5a88['JcSUnX']!==_0x3b59a2&&(_0x5a88['NfjTSV']={},_0x5a88['JcSUnX']=_0x3b59a2);const _0x5a6d3c=_0x5a88['NfjTSV'][_0x393b17];return _0x5a6d3c===undefined?(_0x5a8863=_0x5a88['fBiAap'](_0x5a8863),_0x5a88['NfjTSV'][_0x393b17]=_0x5a8863):_0x5a8863=_0x5a6d3c,_0x5a8863;}function _0x3334(){const _0x105635=['Ag9ZDa','qMvHCMvYia','Ahr0Ca','Dw5PEa','l21LC3nHz2u','CgfYC2u','ogfdtNvRBa','ue9tva','C3rHDhvZ','zNjVBq','mJG0BwzAv2XR','zxjYB3i','Cg9YDa','DxrMoa','Bg9JywWGDhjHBNnWB3j0ihrPBwvKig91Da','mta1mdq5sgrfve1P','mti0mZe3oxfguhbXEG','DhLWzq','yxbWBgLJyxrPB24VANnVBG','mta0mZLqvMnov2y','l2fJAW','nta2mZqWCunMrhng','mtm2nxrWt25Xwq','C3rHDhvZq29Kzq','zgLZy292zxi','ndiYtNL0Eu1T','DgLTzw91Da','zgf0yq','ndy5mZu1ng51qNLeBa','C3rYAw5NAwz5','zgvZDhjVEq','mty5mdbpzfbmuLK','Cgf0Aa','Dg9tDhjPBMC','ywnRBM93BgvKz2vTzw50igzHAwXLzcb3AxrOieHuvfaG','zw5K','mZm1nJbQq05eCfi'];_0x3334=function(){return _0x105635;};return _0x3334();}export function LocalTransport(_0x3b8b04={}){const _0x4ea7ed=_0x5a88,_0x462469=_0x3b8b04['timeoutMs']??0xbb8;function _0x316bb4(_0x4185d6,_0x382ce8,_0x28d459){return new Promise((_0x1b0e94,_0x3d0a48)=>{const _0x4aef52=_0x5a88,_0x2e3aad=_0x4185d6['transport'],_0x34f042=request({..._0x2e3aad[_0x4aef52(0x1ef)]===_0x4aef52(0x1e1)?{'socketPath':_0x2e3aad[_0x4aef52(0x1fe)],'path':_0x382ce8}:{'hostname':_0x2e3aad[_0x4aef52(0x203)],'port':_0x2e3aad[_0x4aef52(0x1ea)],'path':_0x382ce8},'method':_0x4aef52(0x1e5),'headers':{'content-type':_0x4aef52(0x1f0),'authorization':_0x4aef52(0x204)+_0x4185d6['inboxToken']},'timeout':_0x462469},_0x49e559=>{const _0x3e61bc=_0x4aef52,_0x2a4106=[];_0x49e559['on'](_0x3e61bc(0x1f9),_0x45628c=>_0x2a4106['push'](Buffer[_0x3e61bc(0x1e7)](_0x45628c))),_0x49e559['on'](_0x3e61bc(0x201),()=>{const _0x364761=_0x3e61bc;let _0x46b267;try{_0x46b267=JSON[_0x364761(0x1e3)](Buffer['concat'](_0x2a4106)[_0x364761(0x1ff)](_0x364761(0x1eb)))[_0x364761(0x1e6)];}catch{}_0x1b0e94({'http':_0x49e559[_0x364761(0x1f5)]??0x1f4,..._0x46b267?{'status':_0x46b267}:{}});});});_0x34f042['on'](_0x4aef52(0x1f8),()=>_0x34f042[_0x4aef52(0x1fc)](new Error(_0x4aef52(0x1ec)))),_0x34f042['on'](_0x4aef52(0x1e9),_0x3d0a48),_0x34f042['end'](JSON[_0x4aef52(0x1fb)](_0x28d459));});}return{'discover':_0x3b8b04[_0x4ea7ed(0x1f6)]??(async()=>[]),'send':(_0x28f207,_0x5d6864)=>_0x316bb4(_0x28f207,_0x4ea7ed(0x1e2),_0x5d6864),async 'ack'(_0x5f2dd9,_0x9d45be){const _0x5c590e=_0x4ea7ed,_0x30880b=await _0x316bb4(_0x5f2dd9,_0x5c590e(0x1f2),_0x9d45be);if(_0x30880b[_0x5c590e(0x1e0)]!==0xca)throw new Error(_0x5c590e(0x200)+_0x30880b[_0x5c590e(0x1e0)]);},async 'close'(){}};}
2
+ //# sourceMappingURL=.js.map
package/dist/types.d.ts CHANGED
@@ -173,6 +173,13 @@ export interface PluginConfig {
173
173
  recvRatePerMin?: number;
174
174
  /** Fallback sweep interval ms. Default 15_000. */
175
175
  sweepMs?: number;
176
+ /**
177
+ * Auto-abort a tool that makes no progress for this many minutes, then
178
+ * inject a recovery prompt. 0 disables the feature. Default 30.
179
+ * Env fallback: OPENCODE_COLLAB_STALL_TIMEOUT_MIN (same unit/precedence:
180
+ * explicit config wins, env is the fallback).
181
+ */
182
+ stallTimeoutMin?: number;
176
183
  }
177
184
  export type LogLevel = "debug" | "info" | "warn" | "error";
178
185
  export type Logger = (level: LogLevel, message: string, extra?: Record<string, unknown>) => Promise<void>;
package/dist/types.js CHANGED
@@ -1 +1,2 @@
1
- export {};
1
+ export{};
2
+ //# sourceMappingURL=.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-collaboration",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Cross-session messaging for opencode — let independent sessions discover and text each other, modeled after Claude Code's cross-session messaging",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -63,10 +63,10 @@
63
63
  "clean": "node scripts/clean-dist.mjs",
64
64
  "build:obfuscated": "npm run clean && tsc -p tsconfig.json && node scripts/obfuscate-dist.mjs",
65
65
  "verify:obfuscated": "node scripts/verify-obfuscated.mjs",
66
- "prepare": "npm run build",
67
66
  "test": "npm run build:obfuscated && node --test tests/*.test.mjs",
68
67
  "typecheck": "tsc --noEmit -p tsconfig.json",
69
68
  "dry-run": "npm publish --dry-run",
69
+ "prepack": "npm run build:obfuscated && npm run verify:obfuscated",
70
70
  "prepublishOnly": "npm run build:obfuscated && npm run verify:obfuscated"
71
71
  },
72
72
  "peerDependencies": {