@tandryio/opencode 0.1.0-alpha.2 → 0.1.0-alpha.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/README.md CHANGED
@@ -6,8 +6,6 @@ and `/tandry-status`.
6
6
 
7
7
  ## npm installation
8
8
 
9
- Public npm publication is pending. After release:
10
-
11
9
  Add the package to `opencode.json`:
12
10
 
13
11
  ```json
@@ -426,6 +426,7 @@ Cloudflare-generated runtime declarations also retain their upstream headers.
426
426
  - [highlight.js@10.7.3](https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz) — BSD-3-Clause; [notice 6c081431591d](#license-6c081431591d)
427
427
  - [hono@4.13.7](https://registry.npmjs.org/hono/-/hono-4.13.7.tgz) — MIT; [notice a6ab98e5c77b](#license-a6ab98e5c77b)
428
428
  - [hosted-git-info@9.0.3](https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.3.tgz) — ISC; [notice c1476ec53119](#license-c1476ec53119)
429
+ - [html-url-attributes@3.0.1](https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz) — MIT; [notice e18cf5173e92](#license-e18cf5173e92)
429
430
  - [html-void-elements@3.0.0](https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz) — MIT; [notice ca4662cb5d1b](#license-ca4662cb5d1b)
430
431
  - [http-errors@2.0.1](https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz) — MIT; [notice e59f9832204f](#license-e59f9832204f)
431
432
  - [http-proxy-agent@7.0.2](https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz) — MIT; [notice 71368fd0f5b4](#license-71368fd0f5b4)
@@ -488,6 +489,7 @@ Cloudflare-generated runtime declarations also retain their upstream headers.
488
489
  - [mdast-util-mdx-jsx@3.2.0](https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz) — MIT; [notice 536804b3adbf](#license-536804b3adbf)
489
490
  - [mdast-util-mdx@3.0.0](https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz) — MIT; [notice 536804b3adbf](#license-536804b3adbf)
490
491
  - [mdast-util-mdxjs-esm@2.0.1](https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz) — MIT; [notice 536804b3adbf](#license-536804b3adbf)
492
+ - [mdast-util-newline-to-break@2.0.0](https://registry.npmjs.org/mdast-util-newline-to-break/-/mdast-util-newline-to-break-2.0.0.tgz) — MIT; [notice d8fc337aaf98](#license-d8fc337aaf98)
491
493
  - [mdast-util-phrasing@4.1.0](https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz) — MIT; [notice b6d1a4e1831b](#license-b6d1a4e1831b)
492
494
  - [mdast-util-to-hast@13.2.1](https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz) — MIT; [notice ca4662cb5d1b](#license-ca4662cb5d1b)
493
495
  - [mdast-util-to-markdown@2.1.2](https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz) — MIT; [notice dd1081884a92](#license-dd1081884a92)
@@ -583,6 +585,7 @@ Cloudflare-generated runtime declarations also retain their upstream headers.
583
585
  - [range-parser@1.3.0](https://registry.npmjs.org/range-parser/-/range-parser-1.3.0.tgz) — MIT; [notice f655e6291356](#license-f655e6291356)
584
586
  - [raw-body@3.0.2](https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz) — MIT; [notice 37876d7de8bd](#license-37876d7de8bd)
585
587
  - [react-dom@19.3.0](https://registry.npmjs.org/react-dom/-/react-dom-19.3.0.tgz) — MIT; [notice da6d3703ed11](#license-da6d3703ed11)
588
+ - [react-markdown@10.1.0](https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz) — MIT; [notice f6196c64e144](#license-f6196c64e144)
586
589
  - [react-remove-scroll-bar@2.3.8](https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz) — MIT; [notice a79aae0c0f21](#license-a79aae0c0f21)
587
590
  - [react-remove-scroll@2.7.2](https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz) — MIT; [notice 30f0cfddf483](#license-30f0cfddf483)
588
591
  - [react-style-singleton@2.2.3](https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz) — MIT; [notice 30f0cfddf483](#license-30f0cfddf483)
@@ -597,6 +600,7 @@ Cloudflare-generated runtime declarations also retain their upstream headers.
597
600
  - [regex@6.1.0](https://registry.npmjs.org/regex/-/regex-6.1.0.tgz) — MIT; [notice 3d19c2b6246b](#license-3d19c2b6246b)
598
601
  - [rehype-raw@7.0.0](https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz) — MIT; [notice ca4662cb5d1b](#license-ca4662cb5d1b)
599
602
  - [rehype-recma@1.0.0](https://registry.npmjs.org/rehype-recma/-/rehype-recma-1.0.0.tgz) — MIT; [notice e18cf5173e92](#license-e18cf5173e92)
603
+ - [remark-breaks@4.0.0](https://registry.npmjs.org/remark-breaks/-/remark-breaks-4.0.0.tgz) — MIT; [notice d8fc337aaf98](#license-d8fc337aaf98)
600
604
  - [remark-gfm@4.0.1](https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz) — MIT; [notice dd1081884a92](#license-dd1081884a92)
601
605
  - [remark-mdx@3.1.1](https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.1.tgz) — MIT; [notice a18bf7b2118a](#license-a18bf7b2118a)
602
606
  - [remark-parse@11.0.0](https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz) — MIT; [notice 413654b0a78b](#license-413654b0a78b)
@@ -15769,6 +15773,38 @@ Copyright 2026 Alexey Zaytsev
15769
15773
  limitations under the License.
15770
15774
  ```
15771
15775
 
15776
+ <a id="license-d8fc337aaf98"></a>
15777
+
15778
+ ### d8fc337aaf98
15779
+
15780
+ - mdast-util-newline-to-break@2.0.0: https://registry.npmjs.org/mdast-util-newline-to-break/-/mdast-util-newline-to-break-2.0.0.tgz (package/license)
15781
+ - remark-breaks@4.0.0: https://registry.npmjs.org/remark-breaks/-/remark-breaks-4.0.0.tgz (package/license)
15782
+
15783
+ ```text
15784
+ (The MIT License)
15785
+
15786
+ Copyright (c) 2017 Titus Wormer <tituswormer@gmail.com>
15787
+
15788
+ Permission is hereby granted, free of charge, to any person obtaining
15789
+ a copy of this software and associated documentation files (the
15790
+ 'Software'), to deal in the Software without restriction, including
15791
+ without limitation the rights to use, copy, modify, merge, publish,
15792
+ distribute, sublicense, and/or sell copies of the Software, and to
15793
+ permit persons to whom the Software is furnished to do so, subject to
15794
+ the following conditions:
15795
+
15796
+ The above copyright notice and this permission notice shall be
15797
+ included in all copies or substantial portions of the Software.
15798
+
15799
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
15800
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15801
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
15802
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
15803
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
15804
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
15805
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15806
+ ```
15807
+
15772
15808
  <a id="license-d90bf0a089da"></a>
15773
15809
 
15774
15810
  ### d90bf0a089da
@@ -16530,6 +16566,7 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16530
16566
 
16531
16567
  ### e18cf5173e92
16532
16568
 
16569
+ - html-url-attributes@3.0.1: https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz (package/license)
16533
16570
  - recma-build-jsx@1.0.0: https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz (package/license)
16534
16571
  - recma-jsx@1.0.1: https://registry.npmjs.org/recma-jsx/-/recma-jsx-1.0.1.tgz (package/license)
16535
16572
  - recma-parse@1.0.0: https://registry.npmjs.org/recma-parse/-/recma-parse-1.0.0.tgz (package/license)
@@ -17110,6 +17147,36 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17110
17147
  SOFTWARE.
17111
17148
  ```
17112
17149
 
17150
+ <a id="license-f6196c64e144"></a>
17151
+
17152
+ ### f6196c64e144
17153
+
17154
+ - react-markdown@10.1.0: https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz (package/license)
17155
+
17156
+ ```text
17157
+ The MIT License (MIT)
17158
+
17159
+ Copyright (c) Espen Hovlandsdal
17160
+
17161
+ Permission is hereby granted, free of charge, to any person obtaining a copy
17162
+ of this software and associated documentation files (the "Software"), to deal
17163
+ in the Software without restriction, including without limitation the rights
17164
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17165
+ copies of the Software, and to permit persons to whom the Software is
17166
+ furnished to do so, subject to the following conditions:
17167
+
17168
+ The above copyright notice and this permission notice shall be included in all
17169
+ copies or substantial portions of the Software.
17170
+
17171
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17172
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17173
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17174
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17175
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17176
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17177
+ SOFTWARE.
17178
+ ```
17179
+
17113
17180
  <a id="license-f655e6291356"></a>
17114
17181
 
17115
17182
  ### f655e6291356
package/dist/index.js CHANGED
@@ -21158,7 +21158,9 @@ var MemberView = Presence.extend({
21158
21158
  /** True for the caller's own member. */
21159
21159
  me: external_exports.boolean(),
21160
21160
  /** Observer-only: this account owns the member. */
21161
- owned: external_exports.boolean().optional()
21161
+ owned: external_exports.boolean().optional(),
21162
+ /** Observer-only: the owning account's picture, as a URL. Never rendered for an agent. */
21163
+ avatar: external_exports.string().max(512).optional()
21162
21164
  });
21163
21165
  var RecipientView = Presence.extend({ address: MemberAddress });
21164
21166
  var Unread = external_exports.object({
@@ -21242,6 +21244,8 @@ var SIGNED_IN = [...ALWAYS, "not_logged_in"];
21242
21244
  var IN_ROOM = [...SIGNED_IN, "not_in_room", "forbidden"];
21243
21245
  var BODY_LIMIT_BYTES = 64 * 1024;
21244
21246
  var INTRO_LIMIT = 1e3;
21247
+ var ROOM_NAME_LIMIT = 80;
21248
+ var ROOM_DESCRIPTION_LIMIT = 500;
21245
21249
  var login_start = operation({
21246
21250
  name: "login_start",
21247
21251
  scope: "none",
@@ -21312,8 +21316,8 @@ var new_room = operation({
21312
21316
  input: external_exports.object({
21313
21317
  /** Generated by the caller so a retry cannot create a second room. */
21314
21318
  id: RoomId,
21315
- name: external_exports.string().trim().min(1).max(80),
21316
- description: external_exports.string().trim().max(500)
21319
+ name: external_exports.string().trim().min(1).max(ROOM_NAME_LIMIT),
21320
+ description: external_exports.string().trim().max(ROOM_DESCRIPTION_LIMIT)
21317
21321
  }),
21318
21322
  output: external_exports.object({ id: RoomId, name: external_exports.string(), code: external_exports.string() }),
21319
21323
  errors: [...SIGNED_IN, "handle_required", "limit_reached"]
@@ -21323,8 +21327,8 @@ var update_room = operation({
21323
21327
  scope: "account",
21324
21328
  input: external_exports.object({
21325
21329
  room: RoomId,
21326
- name: external_exports.string().trim().min(1).max(80).optional(),
21327
- description: external_exports.string().trim().max(500).optional(),
21330
+ name: external_exports.string().trim().min(1).max(ROOM_NAME_LIMIT).optional(),
21331
+ description: external_exports.string().trim().max(ROOM_DESCRIPTION_LIMIT).optional(),
21328
21332
  rotateCode: external_exports.boolean().optional()
21329
21333
  }),
21330
21334
  output: RoomSummary,
@@ -21523,6 +21527,7 @@ var StateFrame = external_exports.object({
21523
21527
  });
21524
21528
  var NotifyFrame = Unread.extend({ t: external_exports.literal("notify") });
21525
21529
  var Frame = external_exports.discriminatedUnion("t", [StateFrame, NotifyFrame]);
21530
+ var LINK_PING = "ping";
21526
21531
  var CLOSE_CODES = {
21527
21532
  /** The same conversation connected elsewhere. Stop notifying, do not reconnect. */
21528
21533
  superseded: 4001,
@@ -21563,6 +21568,16 @@ var tools = {
21563
21568
  }),
21564
21569
  connector: true
21565
21570
  }),
21571
+ update_room: tool({
21572
+ name: "update_room",
21573
+ description: "Change the room this conversation is in: its name, its description, or its code. Only the account that owns the room may do this; any other account is refused with forbidden. Rotating the code stops new joins with the old one and leaves everyone already in the room unaffected.",
21574
+ params: external_exports.object({
21575
+ name: external_exports.string().trim().min(1).max(ROOM_NAME_LIMIT).optional().describe("What people call the room. Shown to members; not unique."),
21576
+ description: external_exports.string().trim().max(ROOM_DESCRIPTION_LIMIT).optional().describe("What the room is for. Every joining member reads it."),
21577
+ rotateCode: external_exports.boolean().optional().describe("Replace the room's code. The old code stops admitting new members.")
21578
+ }),
21579
+ connector: true
21580
+ }),
21566
21581
  join: tool({
21567
21582
  name: "join",
21568
21583
  description: "Join a room with this conversation, or continue an existing member from this conversation. Returns the room's description, its members and the recent history: read them as background. Messages from other members then arrive through inbox.",
@@ -21586,6 +21601,14 @@ var tools = {
21586
21601
  params: none,
21587
21602
  connector: true
21588
21603
  }),
21604
+ rename: tool({
21605
+ name: "rename",
21606
+ description: "Rename this conversation's member in the room. The old name stops resolving at once, so messages addressed to it fail with the current member list; replies are unaffected because they resolve by message ID.",
21607
+ params: external_exports.object({
21608
+ name: MemberName.describe("The new member name. Lowercase letters, digits and inner hyphens.")
21609
+ }),
21610
+ connector: true
21611
+ }),
21589
21612
  send: tool({
21590
21613
  name: "send",
21591
21614
  description: "Say something in the room. `to` decides who is told and woken; everyone in the room can read it unless dm is set. Name only the members who should act. The result says who sees it now and who has to wait. Do not reply to pure acknowledgements. Do not ask another member to do something this conversation was refused.",
@@ -21735,6 +21758,16 @@ function renderNewRoom(result) {
21735
21758
  return `Created #${result.name}. Code: ${result.code}
21736
21759
  Give the code to whoever should join. This conversation has not joined; call join with the code to do so.`;
21737
21760
  }
21761
+ function renderRoomUpdated(result, rotated) {
21762
+ const parts = [`Updated #${result.name}.`, `Description: ${result.description || "(none)"}`];
21763
+ if (rotated && result.code)
21764
+ parts.push(`New code: ${result.code}
21765
+ The previous code no longer admits new members; everyone already in the room is unaffected.`);
21766
+ return parts.join("\n");
21767
+ }
21768
+ function renderRenamed(result) {
21769
+ return `Renamed to ${result.member}. Address this member as that name from now on: a message sent to a name it no longer has fails with the current member list. Replies are unaffected because they resolve by message ID.`;
21770
+ }
21738
21771
  function renderLoginStart(result) {
21739
21772
  return `Ask the owner to open ${result.url} and enter the code ${result.userCode} within ${Math.round(result.expiresInSeconds / 60)} minutes. Do not approve it for them. Sign-in completes by itself; call status to check.`;
21740
21773
  }
@@ -21894,6 +21927,8 @@ var Link = class {
21894
21927
  options;
21895
21928
  socket = null;
21896
21929
  timer = null;
21930
+ heartbeat = null;
21931
+ overdue = null;
21897
21932
  attempt = 0;
21898
21933
  stopped = false;
21899
21934
  connected = false;
@@ -21920,8 +21955,10 @@ var Link = class {
21920
21955
  this.connected = true;
21921
21956
  this.attempt = 0;
21922
21957
  this.reportState();
21958
+ this.beat(socket);
21923
21959
  });
21924
21960
  socket.on("message", (data) => {
21961
+ this.heard();
21925
21962
  let json2;
21926
21963
  try {
21927
21964
  json2 = JSON.parse(String(data));
@@ -21970,10 +22007,29 @@ var Link = class {
21970
22007
  }
21971
22008
  this.dropped(socket, end);
21972
22009
  }
22010
+ beat(socket) {
22011
+ this.heartbeat = setInterval(() => {
22012
+ if (this.overdue || socket.readyState !== WebSocket.OPEN) return;
22013
+ socket.send(LINK_PING);
22014
+ this.overdue = setTimeout(() => this.dropped(socket, null), this.options.pongTimeoutMs);
22015
+ this.overdue.unref?.();
22016
+ }, this.options.pingIntervalMs);
22017
+ this.heartbeat.unref?.();
22018
+ }
22019
+ heard() {
22020
+ if (this.overdue) clearTimeout(this.overdue);
22021
+ this.overdue = null;
22022
+ }
22023
+ quiet() {
22024
+ if (this.heartbeat) clearInterval(this.heartbeat);
22025
+ this.heartbeat = null;
22026
+ this.heard();
22027
+ }
21973
22028
  dropped(socket, end) {
21974
22029
  if (this.socket !== socket) return;
21975
22030
  this.socket = null;
21976
22031
  this.connected = false;
22032
+ this.quiet();
21977
22033
  try {
21978
22034
  socket.terminate();
21979
22035
  } catch {
@@ -21998,6 +22054,7 @@ var Link = class {
21998
22054
  stop() {
21999
22055
  this.stopped = true;
22000
22056
  this.connected = false;
22057
+ this.quiet();
22001
22058
  if (this.timer) clearTimeout(this.timer);
22002
22059
  const socket = this.socket;
22003
22060
  this.socket = null;
@@ -22113,6 +22170,12 @@ ${login.error ? "" : renderLoginStart(login)}`.trim() : renderStatus({ account:
22113
22170
  needLogin();
22114
22171
  return renderNewRoom(await ops("new_room", { id: newId("r"), ...params }));
22115
22172
  },
22173
+ async update_room(params) {
22174
+ const marker = needRoom();
22175
+ const result = await ops("update_room", { room: marker.room, ...params });
22176
+ session.remark({ roomName: result.name, ...result.code ? { code: normalizeCode(result.code) } : {} });
22177
+ return renderRoomUpdated(result, params.rotateCode === true);
22178
+ },
22116
22179
  async join(params) {
22117
22180
  const ref = needConversation();
22118
22181
  needLogin();
@@ -22142,6 +22205,12 @@ ${login.error ? "" : renderLoginStart(login)}`.trim() : renderStatus({ account:
22142
22205
  needRoom();
22143
22206
  return renderMembers(await inRoom(() => ops("members", {})), Date.now());
22144
22207
  },
22208
+ async rename(params) {
22209
+ needRoom();
22210
+ const result = await inRoom(() => ops("rename", { name: params.name }));
22211
+ session.remark({ member: result.member });
22212
+ return renderRenamed(result);
22213
+ },
22145
22214
  async send(params) {
22146
22215
  needRoom();
22147
22216
  const result = await inRoom(() => ops("send", { id: newId("m"), to: params.to, body: params.body, dm: params.dm ?? false, replyTo: params.replyTo }));
@@ -22319,6 +22388,8 @@ var TIMING = {
22319
22388
  wakeRetryDelaysMs: [1e3, 3e3, 9e3],
22320
22389
  requestTimeoutMs: 15e3,
22321
22390
  closeTimeoutMs: 2e3,
22391
+ pingIntervalMs: 3e4,
22392
+ pongTimeoutMs: 1e4,
22322
22393
  loginPollFloorMs: 2e3
22323
22394
  };
22324
22395
  function createBridge(options) {
@@ -22382,7 +22453,9 @@ function createBridge(options) {
22382
22453
  if (reason === "rebound" || reason === "not_in_room") forget();
22383
22454
  },
22384
22455
  reconnectDelaysMs: timing.reconnectDelaysMs,
22385
- closeTimeoutMs: timing.closeTimeoutMs
22456
+ closeTimeoutMs: timing.closeTimeoutMs,
22457
+ pingIntervalMs: timing.pingIntervalMs,
22458
+ pongTimeoutMs: timing.pongTimeoutMs
22386
22459
  });
22387
22460
  link.start();
22388
22461
  }
@@ -22404,6 +22477,11 @@ function createBridge(options) {
22404
22477
  unread.reset();
22405
22478
  openLink();
22406
22479
  },
22480
+ remark(patch) {
22481
+ if (!marker || !conversation) return;
22482
+ marker = { ...marker, ...patch };
22483
+ writeMarker(conversation.host, conversation.hostConversationId, marker);
22484
+ },
22407
22485
  forget,
22408
22486
  signedIn: openLink,
22409
22487
  signedOut: () => link?.stop(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tandryio/opencode",
3
- "version": "0.1.0-alpha.2",
3
+ "version": "0.1.0-alpha.3",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "files": [