@rho-workspace/rho 0.5.4 → 0.5.6

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.
Files changed (161) hide show
  1. package/dist/agent-connect.d.ts +8 -0
  2. package/dist/agent-connect.js +15 -0
  3. package/dist/browser-access.js +3 -2
  4. package/dist/capabilities.d.ts +2 -2
  5. package/dist/capabilities.js +6 -1
  6. package/dist/cli.js +219 -176
  7. package/dist/contract.generated.d.ts +472 -4
  8. package/dist/contract.generated.js +1 -1
  9. package/dist/contracts/owners.generated.js +455 -6
  10. package/dist/conversations.d.ts +157 -4
  11. package/dist/conversations.js +69 -6
  12. package/dist/discovery.d.ts +1 -0
  13. package/dist/discovery.js +3 -3
  14. package/dist/extension-contract.d.ts +99 -0
  15. package/dist/extension-contract.js +52 -0
  16. package/dist/extension-directory.d.ts +9 -0
  17. package/dist/extension-directory.js +11 -0
  18. package/dist/extension-worker.d.ts +1 -0
  19. package/dist/extension-worker.js +36 -0
  20. package/dist/extensions.d.ts +157 -0
  21. package/dist/extensions.js +349 -0
  22. package/dist/plugin-cli.d.ts +1 -0
  23. package/dist/plugin-cli.js +139 -0
  24. package/dist/plugin-inventory.json +18 -0
  25. package/dist/plugins.d.ts +3 -3
  26. package/dist/project-work.d.ts +3 -1
  27. package/dist/project-work.js +15 -2
  28. package/dist/protocol.d.ts +8 -0
  29. package/dist/protocol.js +16 -7
  30. package/dist/server.d.ts +5 -10
  31. package/dist/server.js +122 -12
  32. package/dist/web/.vite/manifest.json +67 -67
  33. package/dist/web/assets/{canvas-BXhC8RDZ.js → canvas-D8rDdfDz.js} +1 -1
  34. package/dist/web/assets/choices-D-YfnFP6.js +1 -0
  35. package/dist/web/assets/{console-Dbdo-5oO.js → console-Trqc0swD.js} +1 -1
  36. package/dist/web/assets/{dist-B2V0VDO0.js → dist-DZmszrjG.js} +2 -2
  37. package/dist/web/assets/dist-DpIHRk3B.js +1 -0
  38. package/dist/web/assets/{dist-D25Vn17i.js → dist-eMx6b8N1.js} +1 -1
  39. package/dist/web/assets/dist-pF902jHA.js +3 -0
  40. package/dist/web/assets/explore-in-BCHqjJ7B.js +1 -0
  41. package/dist/web/assets/graph-lENgfQNH.js +2 -0
  42. package/dist/web/assets/index-B3_OVy91.css +1 -0
  43. package/dist/web/assets/{index-BHQIaDsx.js → index-BpL_Kl_s.js} +87 -86
  44. package/dist/web/assets/{notes-meaning-DdPbtNzJ.js → notes-meaning-DcVGUBBY.js} +1 -1
  45. package/dist/web/assets/overview-CDnVKlOt.js +6 -0
  46. package/dist/web/assets/preview-BEC1E9MK.js +1 -0
  47. package/dist/web/assets/{review-CmWou4Iv.js → review-DYP0aCXb.js} +1 -1
  48. package/dist/web/assets/{skills-Dy7n3L9d.js → skills-1ec0Z-jx.js} +1 -1
  49. package/dist/web/assets/{skills-work-Cj0W6b-I.js → skills-work-DNexV4OJ.js} +1 -1
  50. package/dist/web/assets/{studio-process-QOY_n2_8.js → studio-process-EYQgikxq.js} +2 -2
  51. package/dist/web/assets/{timeline-events-DmX1BCh3.js → timeline-events-Chj2Gbx7.js} +1 -1
  52. package/dist/web/assets/{work-turns-Co0C71rJ.js → work-turns-CT9RVcWY.js} +1 -1
  53. package/dist/web/assets/workspace-COmCbGV3.js +5 -0
  54. package/dist/web/composition.json +65 -65
  55. package/dist/web/index.html +3 -3
  56. package/dist/web/renderer.json +1 -1
  57. package/dist/web-assets.d.ts +2 -1
  58. package/dist/web-assets.js +3 -2
  59. package/dist/work-contract.js +2 -2
  60. package/docs/FRONTEND.md +26 -18
  61. package/docs/HEADLESS.md +38 -28
  62. package/docs/PLUGIN-AUTHORING.md +4 -0
  63. package/docs/THIRD-PARTY-PLUGINS.md +190 -0
  64. package/node_modules/@rho-workspace/plugin-agent/README.md +68 -0
  65. package/node_modules/@rho-workspace/plugin-agent/dist/acp-command.d.ts +1 -0
  66. package/node_modules/@rho-workspace/plugin-agent/dist/acp-command.js +9 -1
  67. package/node_modules/@rho-workspace/plugin-agent/dist/acp-conversation.d.ts +1 -0
  68. package/node_modules/@rho-workspace/plugin-agent/dist/acp-conversation.js +10 -0
  69. package/node_modules/@rho-workspace/plugin-agent/dist/activity-normalize.d.ts +1 -0
  70. package/node_modules/@rho-workspace/plugin-agent/dist/activity-normalize.js +2 -2
  71. package/node_modules/@rho-workspace/plugin-agent/dist/dsh-session.d.ts +6 -0
  72. package/node_modules/@rho-workspace/plugin-agent/dist/dsh-session.js +174 -0
  73. package/node_modules/@rho-workspace/plugin-agent/dist/external-session-contract.d.ts +82 -0
  74. package/node_modules/@rho-workspace/plugin-agent/dist/external-session-contract.js +20 -0
  75. package/node_modules/@rho-workspace/plugin-agent/dist/external-session.d.ts +84 -0
  76. package/node_modules/@rho-workspace/plugin-agent/dist/external-session.js +190 -0
  77. package/node_modules/@rho-workspace/plugin-agent/dist/index.d.ts +373 -0
  78. package/node_modules/@rho-workspace/plugin-agent/dist/index.js +1 -0
  79. package/node_modules/@rho-workspace/plugin-agent/dist/native-sessions.d.ts +70 -0
  80. package/node_modules/@rho-workspace/plugin-agent/dist/native-sessions.js +538 -0
  81. package/node_modules/@rho-workspace/plugin-agent/dist/operations.d.ts +33 -0
  82. package/node_modules/@rho-workspace/plugin-agent/dist/operations.js +3 -0
  83. package/node_modules/@rho-workspace/plugin-agent/dist/presentation.d.ts +14 -0
  84. package/node_modules/@rho-workspace/plugin-agent/dist/presentation.js +2 -0
  85. package/node_modules/@rho-workspace/plugin-agent/dist/ui-external-session.d.ts +15 -0
  86. package/node_modules/@rho-workspace/plugin-agent/dist/ui-external-session.js +37 -0
  87. package/node_modules/@rho-workspace/plugin-agent/package.json +6 -1
  88. package/node_modules/hono/dist/adapter/aws-lambda/handler.js +1 -1
  89. package/node_modules/hono/dist/cjs/adapter/aws-lambda/handler.js +1 -1
  90. package/node_modules/hono/dist/cjs/adapter/bun/serve-static.js +1 -1
  91. package/node_modules/hono/dist/cjs/adapter/bun/websocket.js +1 -1
  92. package/node_modules/hono/dist/cjs/client/fetch-result-please.js +1 -1
  93. package/node_modules/hono/dist/cjs/helper/accepts/accepts.js +2 -1
  94. package/node_modules/hono/dist/cjs/helper/ssg/ssg.js +5 -3
  95. package/node_modules/hono/dist/cjs/jsx/base.js +49 -30
  96. package/node_modules/hono/dist/cjs/jsx/components.js +2 -2
  97. package/node_modules/hono/dist/cjs/jsx/constants.js +2 -0
  98. package/node_modules/hono/dist/cjs/jsx/jsx-runtime.js +13 -17
  99. package/node_modules/hono/dist/cjs/middleware/etag/index.js +3 -1
  100. package/node_modules/hono/dist/cjs/middleware/pretty-json/index.js +1 -0
  101. package/node_modules/hono/dist/cjs/middleware/timing/timing.js +4 -3
  102. package/node_modules/hono/dist/cjs/utils/cookie.js +2 -2
  103. package/node_modules/hono/dist/cjs/utils/mime.js +1 -1
  104. package/node_modules/hono/dist/cjs/utils/url.js +1 -1
  105. package/node_modules/hono/dist/client/fetch-result-please.js +1 -1
  106. package/node_modules/hono/dist/helper/accepts/accepts.js +2 -1
  107. package/node_modules/hono/dist/helper/ssg/ssg.js +5 -3
  108. package/node_modules/hono/dist/jsx/base.js +49 -32
  109. package/node_modules/hono/dist/jsx/components.js +2 -2
  110. package/node_modules/hono/dist/jsx/constants.js +2 -1
  111. package/node_modules/hono/dist/jsx/jsx-runtime.js +15 -19
  112. package/node_modules/hono/dist/middleware/etag/index.js +3 -1
  113. package/node_modules/hono/dist/middleware/language/language.js +1 -1
  114. package/node_modules/hono/dist/middleware/pretty-json/index.js +1 -0
  115. package/node_modules/hono/dist/middleware/timing/timing.js +4 -3
  116. package/node_modules/hono/dist/utils/cookie.js +2 -2
  117. package/node_modules/hono/dist/utils/mime.js +1 -1
  118. package/node_modules/hono/dist/utils/url.js +1 -1
  119. package/node_modules/hono/package.json +1 -1
  120. package/package.json +5 -3
  121. package/protocol/index.json +93 -33
  122. package/protocol/operations/agent.sessions.list.json +146 -0
  123. package/protocol/operations/agent.sessions.read.json +315 -0
  124. package/protocol/operations/conversation.configure.json +29 -0
  125. package/protocol/operations/conversation.decide.json +29 -0
  126. package/protocol/operations/conversation.list.json +29 -0
  127. package/protocol/operations/conversation.permission.json +29 -0
  128. package/protocol/operations/conversation.read.json +29 -0
  129. package/protocol/operations/conversation.restore.json +29 -0
  130. package/protocol/operations/conversation.send.json +29 -0
  131. package/protocol/operations/conversation.settings.check.json +92 -0
  132. package/protocol/operations/conversation.settings.read.json +92 -0
  133. package/protocol/operations/conversation.settings.update.json +92 -0
  134. package/protocol/operations/conversation.start.json +46 -1
  135. package/protocol/operations/conversation.stop.json +29 -0
  136. package/protocol/operations/conversation.trash.json +29 -0
  137. package/protocol/operations/extension.call.json +132 -0
  138. package/protocol/operations/extension.content.json +78 -0
  139. package/protocol/operations/extension.describe.json +195 -0
  140. package/protocol/operations/extension.install.json +198 -0
  141. package/protocol/operations/extension.list.json +123 -0
  142. package/protocol/operations/extension.manage.json +55 -0
  143. package/protocol/operations/extension.read.json +112 -0
  144. package/protocol/operations/observation.snapshot.json +29 -0
  145. package/protocol/operations/project.work.read.json +3 -2
  146. package/protocol/operations/session.grant.json +9 -0
  147. package/protocol/operations/session.instructions.json +43 -0
  148. package/scripts/third-party-acceptance.mjs +77 -0
  149. package/vendor/composition.json +83 -83
  150. package/vendor/rho-workspace-plugin-agent-0.4.30.tgz +0 -0
  151. package/web/theme.css +12 -0
  152. package/dist/web/assets/choices-DU9kHlyQ.js +0 -1
  153. package/dist/web/assets/dist-BV3hWfn_.js +0 -3
  154. package/dist/web/assets/dist-CLNF2g-E.js +0 -1
  155. package/dist/web/assets/explore-in-8Q5ftt-E.js +0 -1
  156. package/dist/web/assets/graph-hS2kvHTI.js +0 -2
  157. package/dist/web/assets/index-Cj1_iqyK.css +0 -1
  158. package/dist/web/assets/overview-BV6ZO5TO.js +0 -6
  159. package/dist/web/assets/preview-n5lOOdjN.js +0 -1
  160. package/dist/web/assets/workspace-BKFefRfJ.js +0 -5
  161. package/vendor/rho-workspace-plugin-agent-0.4.28.tgz +0 -0
@@ -1,5 +1,5 @@
1
1
  import { escapeToBuffer, raw, resolveCallbackSync, stringBufferToString } from "../utils/html.js";
2
- import { DOM_MEMO, DOM_RENDERER } from "./constants.js";
2
+ import { DOM_MEMO, DOM_RENDERER, RENDERED_JSX } from "./constants.js";
3
3
  import { captureRenderContext, createContext, globalContexts, runWithRenderContext, useContext } from "./context.js";
4
4
  import { domRenderers } from "./intrinsic-element/common.js";
5
5
  import { components_exports } from "./intrinsic-element/components.js";
@@ -25,7 +25,7 @@ const emptyTags = [
25
25
  "track",
26
26
  "wbr"
27
27
  ];
28
- const booleanAttributes = [
28
+ const booleanAttributes = /* @__PURE__ */ new Set([
29
29
  "allowfullscreen",
30
30
  "async",
31
31
  "autofocus",
@@ -51,8 +51,11 @@ const booleanAttributes = [
51
51
  "readonly",
52
52
  "required",
53
53
  "reversed",
54
- "selected"
55
- ];
54
+ "selected",
55
+ "shadowrootclonable",
56
+ "shadowrootdelegatesfocus",
57
+ "shadowrootserializable"
58
+ ]);
56
59
  const resolveFunctionComponentResult = (result, suspendedContext) => result.then((resolved) => {
57
60
  if (typeof resolved !== "string" && !Array.isArray(resolved) && !(resolved instanceof JSXNode)) return resolved;
58
61
  const children = Array.isArray(resolved) ? resolved : [resolved];
@@ -63,6 +66,44 @@ const resolveFunctionComponentResult = (result, suspendedContext) => result.then
63
66
  };
64
67
  return suspendedContext ? suspendedContext(render) : runWithRenderContext(render);
65
68
  });
69
+ const markRenderedJSX = (value) => {
70
+ value[RENDERED_JSX] = true;
71
+ return value;
72
+ };
73
+ const isEscapedAttribute = (value) => value instanceof String && value.isEscaped && !(RENDERED_JSX in value);
74
+ const objectToAttributeString = (v) => {
75
+ const s = v.toString();
76
+ return s instanceof Promise ? s.then(String) : String(s);
77
+ };
78
+ const attributeToBuffer = (buffer, prefix, key, v, tag) => {
79
+ if (key === "ref" || v === null || v === void 0) return;
80
+ if (typeof v === "boolean" && booleanAttributes.has(key)) {
81
+ if (v) buffer[0] += `${prefix}${key}=""`;
82
+ return;
83
+ }
84
+ if (typeof v === "function") {
85
+ if (!key.startsWith("on")) throw new Error(`Invalid prop '${key}' of type 'function' supplied to ${tag ? `'${tag}'` : "a JSX element"}.`);
86
+ return;
87
+ }
88
+ buffer[0] += `${prefix}${key}="`;
89
+ if (key === "style" && typeof v === "object") {
90
+ let styleStr = "";
91
+ styleObjectForEach(v, (property, value) => {
92
+ if (value != null) styleStr += `${styleStr ? ";" : ""}${property}:${value}`;
93
+ });
94
+ escapeToBuffer(styleStr, buffer);
95
+ } else if (typeof v === "string") escapeToBuffer(v, buffer);
96
+ else if (typeof v === "number" || isEscapedAttribute(v)) buffer[0] += `${v}`;
97
+ else {
98
+ const s = v instanceof Promise ? v.then((r) => typeof r === "object" && r !== null && !isEscapedAttribute(r) ? objectToAttributeString(r) : r) : objectToAttributeString(v);
99
+ if (s instanceof Promise) {
100
+ buffer.unshift("\"", s);
101
+ return;
102
+ }
103
+ escapeToBuffer(s, buffer);
104
+ }
105
+ buffer[0] += "\"";
106
+ };
66
107
  const childrenToStringToBuffer = (children, buffer) => {
67
108
  for (let i = 0, len = children.length; i < len; i++) {
68
109
  const child = children[i];
@@ -114,7 +155,7 @@ var JSXNode = class {
114
155
  const render = () => {
115
156
  const buffer = [""];
116
157
  this.toStringToBuffer(buffer);
117
- return buffer.length === 1 ? "callbacks" in buffer ? resolveCallbackSync(raw(buffer[0], buffer.callbacks)).toString() : buffer[0] : stringBufferToString(buffer, buffer.callbacks);
158
+ return buffer.length === 1 ? "callbacks" in buffer ? resolveCallbackSync(raw(buffer[0], buffer.callbacks)).toString() : buffer[0] : stringBufferToString(buffer, buffer.callbacks).then(markRenderedJSX);
118
159
  };
119
160
  return runWithRenderContext(render);
120
161
  }
@@ -127,34 +168,10 @@ var JSXNode = class {
127
168
  for (let [key, v] of Object.entries(props)) {
128
169
  key = normalizeKey(key);
129
170
  if (!isValidAttributeName(key)) continue;
130
- if (key === "children") {} else if (key === "style" && typeof v === "object") {
131
- let styleStr = "";
132
- styleObjectForEach(v, (property, value) => {
133
- if (value != null) styleStr += `${styleStr ? ";" : ""}${property}:${value}`;
134
- });
135
- buffer[0] += " style=\"";
136
- escapeToBuffer(styleStr, buffer);
137
- buffer[0] += "\"";
138
- } else if (typeof v === "string") {
139
- buffer[0] += ` ${key}="`;
140
- escapeToBuffer(v, buffer);
141
- buffer[0] += "\"";
142
- } else if (v === null || v === void 0) {} else if (typeof v === "number" || v.isEscaped) buffer[0] += ` ${key}="${v}"`;
143
- else if (typeof v === "boolean" && booleanAttributes.includes(key)) {
144
- if (v) buffer[0] += ` ${key}=""`;
145
- } else if (key === "dangerouslySetInnerHTML") {
171
+ if (key === "children") {} else if (key === "dangerouslySetInnerHTML" && typeof v === "object" && v !== null && "__html" in v) {
146
172
  if (children.length > 0) throw new Error("Can only set one of `children` or `props.dangerouslySetInnerHTML`.");
147
173
  children = [raw(v.__html)];
148
- } else if (v instanceof Promise) {
149
- buffer[0] += ` ${key}="`;
150
- buffer.unshift("\"", v);
151
- } else if (typeof v === "function") {
152
- if (!key.startsWith("on") && key !== "ref") throw new Error(`Invalid prop '${key}' of type 'function' supplied to '${tag}'.`);
153
- } else {
154
- buffer[0] += ` ${key}="`;
155
- escapeToBuffer(v.toString(), buffer);
156
- buffer[0] += "\"";
157
- }
174
+ } else attributeToBuffer(buffer, " ", key, v, tag);
158
175
  }
159
176
  if (emptyTags.includes(tag) && children.length === 0) {
160
177
  buffer[0] += "/>";
@@ -248,4 +265,4 @@ const cloneElement = (element, props, ...children) => {
248
265
  };
249
266
  const reactAPICompatVersion = "19.0.0-hono-jsx";
250
267
  //#endregion
251
- export { Fragment, JSXFragmentNode, JSXNode, booleanAttributes, cloneElement, getNameSpaceContext, isUntrustedObject, isValidElement, jsx, jsxFn, memo, reactAPICompatVersion, renderChildren, renderUntrustedObject, shallowEqual };
268
+ export { Fragment, JSXFragmentNode, JSXNode, attributeToBuffer, booleanAttributes, cloneElement, getNameSpaceContext, isUntrustedObject, isValidElement, jsx, jsxFn, markRenderedJSX, memo, reactAPICompatVersion, renderChildren, renderUntrustedObject, shallowEqual };
@@ -77,7 +77,7 @@ const ErrorBoundary = async ({ children, fallback, fallbackRender, onError }) =>
77
77
  buffer[0] = buffer[0].replace(replaceRe, () => fallbackResString);
78
78
  return fallbackCallbacks?.length ? raw("", fallbackCallbacks) : "";
79
79
  }
80
- return raw(`<template data-hono-target="E:${index}">${fallbackResString}</template><script>
80
+ return raw(`<template data-hono-target="E:${index}">${fallbackResString}</template><script${nonce ? ` nonce="${nonce}"` : ""}>
81
81
  ((d,c,n) => {
82
82
  c=d.currentScript.previousSibling
83
83
  d=d.getElementById('E:${index}')
@@ -118,7 +118,7 @@ d.parentElement.insertBefore(c.content,d.nextSibling)
118
118
  buffer[0] += content;
119
119
  return raw("", content.callbacks);
120
120
  }
121
- return raw(content + (resolvedCount !== callbacks.length ? "" : `<script>
121
+ return raw(content + (resolvedCount !== callbacks.length ? "" : `<script${nonce ? ` nonce="${nonce}"` : ""}>
122
122
  ((d,c,n) => {
123
123
  d=d.getElementById('E:${index}')
124
124
  if(!d)return
@@ -5,5 +5,6 @@ const DOM_STASH = Symbol("STASH");
5
5
  const DOM_INTERNAL_TAG = Symbol("INTERNAL");
6
6
  const DOM_MEMO = Symbol("MEMO");
7
7
  const PERMALINK = Symbol("PERMALINK");
8
+ const RENDERED_JSX = Symbol("RENDERED_JSX");
8
9
  //#endregion
9
- export { DOM_ERROR_HANDLER, DOM_INTERNAL_TAG, DOM_MEMO, DOM_RENDERER, DOM_STASH, PERMALINK };
10
+ export { DOM_ERROR_HANDLER, DOM_INTERNAL_TAG, DOM_MEMO, DOM_RENDERER, DOM_STASH, PERMALINK, RENDERED_JSX };
@@ -1,31 +1,27 @@
1
1
  import { escapeToBuffer, raw, stringBufferToString } from "../utils/html.js";
2
2
  import { html } from "../helper/html/index.js";
3
- import { isValidAttributeName, styleObjectForEach } from "./utils.js";
4
- import { Fragment } from "./base.js";
3
+ import { PERMALINK } from "./constants.js";
4
+ import { isValidAttributeName } from "./utils.js";
5
+ import { Fragment, attributeToBuffer, markRenderedJSX } from "./base.js";
5
6
  import { jsxDEV } from "./jsx-dev-runtime.js";
6
7
  //#region src/jsx/jsx-runtime.ts
8
+ const jsxTemplate = (strings, ...values) => {
9
+ const result = html(strings, ...values);
10
+ return result instanceof Promise ? result.then(markRenderedJSX) : markRenderedJSX(result);
11
+ };
7
12
  const jsxAttr = (key, v) => {
8
13
  if (!isValidAttributeName(key)) return raw("");
9
- const buffer = [`${key}="`];
10
- if (key === "style" && typeof v === "object") {
11
- let styleStr = "";
12
- styleObjectForEach(v, (property, value) => {
13
- if (value != null) styleStr += `${styleStr ? ";" : ""}${property}:${value}`;
14
- });
15
- escapeToBuffer(styleStr, buffer);
16
- buffer[0] += "\"";
17
- } else if (typeof v === "string") {
14
+ if (typeof v === "string") {
15
+ const buffer = [`${key}="`];
18
16
  escapeToBuffer(v, buffer);
19
- buffer[0] += "\"";
20
- } else if (v === null || v === void 0) return raw("");
21
- else if (typeof v === "number" || v.isEscaped) buffer[0] += `${v}"`;
22
- else if (v instanceof Promise) buffer.unshift("\"", v);
23
- else {
24
- escapeToBuffer(v.toString(), buffer);
25
- buffer[0] += "\"";
17
+ return raw(buffer[0] + "\"");
26
18
  }
19
+ let value = v;
20
+ if (typeof value === "function" && (key === "action" || key === "formaction")) value = PERMALINK in value ? value[PERMALINK] : void 0;
21
+ const buffer = [""];
22
+ attributeToBuffer(buffer, "", key, value);
27
23
  return buffer.length === 1 ? raw(buffer[0]) : stringBufferToString(buffer, void 0);
28
24
  };
29
25
  const jsxEscape = (value) => value;
30
26
  //#endregion
31
- export { Fragment, jsxDEV as jsx, jsxAttr, jsxEscape, html as jsxTemplate, jsxDEV as jsxs };
27
+ export { Fragment, jsxDEV as jsx, jsxAttr, jsxEscape, jsxTemplate, jsxDEV as jsxs };
@@ -16,7 +16,8 @@ const RETAINED_304_HEADERS = [
16
16
  ];
17
17
  const stripWeak = (tag) => tag.replace(/^W\//, "");
18
18
  function etagMatches(etag, ifNoneMatch) {
19
- return ifNoneMatch != null && ifNoneMatch.split(",").some((t) => stripWeak(t.trim()) === stripWeak(etag));
19
+ const expected = stripWeak(etag);
20
+ return ifNoneMatch?.match(/"[^"]*"/g)?.some((tag) => tag === expected) ?? false;
20
21
  }
21
22
  function initializeGenerator(generator) {
22
23
  if (!generator) {
@@ -64,6 +65,7 @@ const etag = (options) => {
64
65
  etag = weak ? `W/"${hash}"` : `"${hash}"`;
65
66
  }
66
67
  if (ifNoneMatch === "*" || etagMatches(etag, ifNoneMatch)) {
68
+ await res.body?.cancel();
67
69
  c.res = new Response(null, {
68
70
  status: 304,
69
71
  statusText: "Not Modified",
@@ -1,5 +1,5 @@
1
- import { parseAccept } from "../../utils/accept.js";
2
1
  import { getCookie, setCookie } from "../../helper/cookie/index.js";
2
+ import { parseAccept } from "../../utils/accept.js";
3
3
  //#region src/middleware/language/language.ts
4
4
  const DEFAULT_OPTIONS = {
5
5
  order: [
@@ -31,6 +31,7 @@ const prettyJSON = (options) => {
31
31
  } catch {
32
32
  return;
33
33
  }
34
+ await c.res.body?.cancel();
34
35
  c.res = new Response(JSON.stringify(obj, null, options?.space ?? 2), c.res);
35
36
  c.res.headers.delete("Content-Length");
36
37
  }
@@ -74,6 +74,7 @@ const timing = (config) => {
74
74
  }
75
75
  };
76
76
  };
77
+ const quote = (s) => `"${s.replace(/[\\"]/g, "\\$&")}"`;
77
78
  /**
78
79
  * Set a metric for the timing middleware.
79
80
  *
@@ -96,11 +97,11 @@ const setMetric = (c, name, valueDescription, description, precision) => {
96
97
  return;
97
98
  }
98
99
  if (typeof valueDescription === "number") {
99
- const dur = valueDescription.toFixed(precision || 1);
100
- const metric = description ? `${name};dur=${dur};desc="${description}"` : `${name};dur=${dur}`;
100
+ const dur = valueDescription.toFixed(precision ?? 1);
101
+ const metric = description ? `${name};dur=${dur};desc=${quote(description)}` : `${name};dur=${dur}`;
101
102
  metrics.headers.push(metric);
102
103
  } else {
103
- const metric = valueDescription ? `${name};desc="${valueDescription}"` : `${name}`;
104
+ const metric = valueDescription ? `${name};desc=${quote(valueDescription)}` : `${name}`;
104
105
  metrics.headers.push(metric);
105
106
  }
106
107
  };
@@ -79,8 +79,8 @@ const parseSigned = async (cookie, secret, name) => {
79
79
  const _serialize = (name, value, opt = {}) => {
80
80
  if (!validCookieNameRegEx.test(name)) throw new Error("Invalid cookie name");
81
81
  let cookie = `${name}=${value}`;
82
- if (name.startsWith("__Secure-") && !opt.secure) throw new Error("__Secure- Cookie must have Secure attributes");
83
- if (name.startsWith("__Host-")) {
82
+ if (/^__secure-/i.test(name) && !opt.secure) throw new Error("__Secure- Cookie must have Secure attributes");
83
+ if (/^__host-/i.test(name)) {
84
84
  if (!opt.secure) throw new Error("__Host- Cookie must have Secure attributes");
85
85
  if (opt.path !== "/") throw new Error("__Host- Cookie must have Path attributes with \"/\"");
86
86
  if (opt.domain) throw new Error("__Host- Cookie must not have Domain attributes");
@@ -9,7 +9,7 @@ const getMimeType = (filename, mimes = baseMimes) => {
9
9
  return mimes[match[1].toLowerCase()];
10
10
  };
11
11
  const getExtension = (mimeType) => {
12
- const baseType = mimeType.split(";", 1)[0].trim();
12
+ const baseType = mimeType.split(";", 1)[0].trim().toLowerCase();
13
13
  for (const ext in baseMimes) {
14
14
  const stored = baseMimes[ext];
15
15
  if (stored === mimeType || stored.split(";", 1)[0].trim() === baseType) return ext;
@@ -161,7 +161,7 @@ const _getQueryParam = (url, key, multiple) => {
161
161
  const hashIndex = url.indexOf("#", 8);
162
162
  if (hashIndex !== -1) url = url.slice(0, hashIndex);
163
163
  let encoded;
164
- if (!multiple && key && key.indexOf("%") === -1 && key.indexOf("+") === -1) {
164
+ if (!multiple && key && !/[%+&=]/.test(key)) {
165
165
  const queryIndex = url.indexOf("?", 8);
166
166
  let keyIndex = queryIndex;
167
167
  if (keyIndex === -1) return;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hono",
3
- "version": "4.13.16",
3
+ "version": "4.13.17",
4
4
  "description": "Web framework built on Web Standards",
5
5
  "main": "dist/cjs/index.js",
6
6
  "type": "module",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rho-workspace/rho",
3
- "version": "0.5.4",
3
+ "version": "0.5.6",
4
4
  "type": "module",
5
5
  "description": "Rho local workspace service, scoped browser shell and headless client",
6
6
  "license": "AGPL-3.0-only",
@@ -56,7 +56,9 @@
56
56
  "scripts/ui-toolchain.json",
57
57
  "scripts/ui-preview",
58
58
  "web/theme.css",
59
- "docs/PLUGIN-AUTHORING.md"
59
+ "docs/PLUGIN-AUTHORING.md",
60
+ "docs/THIRD-PARTY-PLUGINS.md",
61
+ "scripts/third-party-acceptance.mjs"
60
62
  ],
61
63
  "scripts": {
62
64
  "acceptance:collaboration": "node scripts/collaboration-acceptance.mjs",
@@ -77,7 +79,7 @@
77
79
  "@rho-workspace/plugin-tables": "file:vendor/rho-workspace-plugin-tables-0.5.0.tgz",
78
80
  "@rho-workspace/plugin-media": "file:vendor/rho-workspace-plugin-media-0.4.0.tgz",
79
81
  "@rho-workspace/plugin-charts": "file:vendor/rho-workspace-plugin-charts-0.4.0.tgz",
80
- "@rho-workspace/plugin-agent": "file:vendor/rho-workspace-plugin-agent-0.4.28.tgz",
82
+ "@rho-workspace/plugin-agent": "file:vendor/rho-workspace-plugin-agent-0.4.30.tgz",
81
83
  "@rho-workspace/plugin-annotations": "file:vendor/rho-workspace-plugin-annotations-0.5.2.tgz",
82
84
  "@rho-workspace/plugin-console": "file:vendor/rho-workspace-plugin-console-0.3.1.tgz",
83
85
  "@rho-workspace/plugin-kernel": "file:vendor/rho-workspace-plugin-kernel-0.5.5.tgz",
@@ -74,6 +74,18 @@
74
74
  "bytes": 3705,
75
75
  "sha256": "64d31b4cefd29c0132bc82223775ada64f974df17216a06e8be5e7ff98461d1e"
76
76
  },
77
+ "agent.sessions.list": {
78
+ "summary": "agent.sessions.list",
79
+ "path": "operations/agent.sessions.list.json",
80
+ "bytes": 3397,
81
+ "sha256": "853106dcca93104995c3afff078975904788c3ee1f4bba3e5f99c0d27f189ca6"
82
+ },
83
+ "agent.sessions.read": {
84
+ "summary": "agent.sessions.read",
85
+ "path": "operations/agent.sessions.read.json",
86
+ "bytes": 7526,
87
+ "sha256": "48a53f06a7a1d33e11bbe3efc7d5a5d47c8130bc344b557c49ff5edfc226dbe6"
88
+ },
77
89
  "annotation.create": {
78
90
  "summary": "annotation.create",
79
91
  "path": "operations/annotation.create.json",
@@ -233,14 +245,14 @@
233
245
  "conversation.configure": {
234
246
  "summary": "Person at this machine only: change one setting the Agent offers (model, effort, mode…) for the next messages of a conversation started in Rho. An open session changes now; otherwise the choice is applied when the session next opens. Refused while a message is being answered.",
235
247
  "path": "operations/conversation.configure.json",
236
- "bytes": 20110,
237
- "sha256": "a92723b3e054d81050be0edb5531b2f4621d30c4d3b8712c91959355d3a33cf7"
248
+ "bytes": 20885,
249
+ "sha256": "8a745fb3600d7ac64fad3812d856f7b135a2d2c3ea2eca65d922cd6d48c1eba7"
238
250
  },
239
251
  "conversation.decide": {
240
252
  "summary": "Person at this machine only: say to use an answer, or that it needs changes and why. The decision holds for the file versions that message kept when it was given and says nothing of later versions. A new decision supersedes the one before; none is removed. Refused while the Agent is still answering.",
241
253
  "path": "operations/conversation.decide.json",
242
- "bytes": 33825,
243
- "sha256": "366b88fc2102cd7ea25aa753c5e8f17780a2d78269a4e152786a97b0a0c22dc6"
254
+ "bytes": 34600,
255
+ "sha256": "518369b3d052cea7f78f9722577d47ff54490ff8ba39769b0d768bf8529b8af4"
244
256
  },
245
257
  "conversation.delete": {
246
258
  "summary": "Person at this machine only: delete Rho's record of a conversation in the trash. The Agent's own session files are not touched. Repeating the request that started it is then refused.",
@@ -251,68 +263,68 @@
251
263
  "conversation.list": {
252
264
  "summary": "Person at this machine only: list the conversations started in Rho in this project, or those in its trash, with each one's Agent, last model, choices and reported usage. Reading starts nothing.",
253
265
  "path": "operations/conversation.list.json",
254
- "bytes": 6767,
255
- "sha256": "44c0fcaaf3b0775db9d3f969218a0b9516ea4d55f79d6d9737c34be368bda7a1"
266
+ "bytes": 7600,
267
+ "sha256": "2e291ce118cab1c43436e1e5ed22a916923f0089696f32dfa5ead04c99be5ec0"
256
268
  },
257
269
  "conversation.permission": {
258
270
  "summary": "Person at this machine only: record an offered choice for a pending Agent permission request. The original request identity is retained; repeated identical choices do not respond twice.",
259
271
  "path": "operations/conversation.permission.json",
260
- "bytes": 33644,
261
- "sha256": "85bc65c9209d43a75b49542d10f5d82c2998307ef2f8b3727a94ec6ae1bffc56"
272
+ "bytes": 34419,
273
+ "sha256": "3ca68aad6568a7fe3426671d84725656d1ff19815521090dadcac7c543dcce88"
262
274
  },
263
275
  "conversation.read": {
264
276
  "summary": "Read a conversation started in Rho: the person's messages, the Agent's visible text and tool steps, and how each message ended. Reading starts and resumes nothing.",
265
277
  "path": "operations/conversation.read.json",
266
- "bytes": 48752,
267
- "sha256": "0ae9de68afa2da8419f5d723eca3f2ea8db9d1e0936a8dd1e92284d8bcc27805"
278
+ "bytes": 49527,
279
+ "sha256": "cc68d9b16b03f5a39debba41c4b41422f843d18a67b1cb26f7e8eb58d3c5bcb9"
268
280
  },
269
281
  "conversation.restore": {
270
282
  "summary": "Person at this machine only: return a conversation from the trash to the project's conversations, within the project's conversation limit.",
271
283
  "path": "operations/conversation.restore.json",
272
- "bytes": 6261,
273
- "sha256": "282449bc3f84125f2e6d37ec391596aa03e666b1fac06774454cd830aa9d69e4"
284
+ "bytes": 7036,
285
+ "sha256": "184780ef30bc8d0a835c94b7617bac9abc1da220e8fc4e1fbaae6a72188e4238"
274
286
  },
275
287
  "conversation.send": {
276
288
  "summary": "Person at this machine only: send the next message to a conversation started in Rho. A continuationOf links a new message to the latest confirmed Agent turn-limit stop; the original request is not resent. Refused while the previous message is being answered. A repeated changeId with the same input returns the original message.",
277
289
  "path": "operations/conversation.send.json",
278
- "bytes": 33931,
279
- "sha256": "031bbfe0e76b4e932969743953f7664a283b85b75dc3fe55fca6af45ac4d1e4c"
290
+ "bytes": 34706,
291
+ "sha256": "8dd79b04112b14500817c596a8551921675d3a062babe62aee1837d30305a124"
280
292
  },
281
293
  "conversation.settings.check": {
282
294
  "summary": "Person at this machine only: start the chosen Agent in this project to read the settings it offers, then remove that session and end the process. No message is sent; one check per Agent runs at a time.",
283
295
  "path": "operations/conversation.settings.check.json",
284
- "bytes": 14555,
285
- "sha256": "0aba6e7c8dc96f20aa20db2bea94238d370774450c70a19cabdec344a2eda88e"
296
+ "bytes": 16792,
297
+ "sha256": "07b682197ffd780dbb462f0f55d9d0db29c6fea4b2b630556a462e041d4ced56"
286
298
  },
287
299
  "conversation.settings.read": {
288
300
  "summary": "Person at this machine only: read the Agent and settings chosen for new conversations and what each Agent last offered. Reading starts nothing.",
289
301
  "path": "operations/conversation.settings.read.json",
290
- "bytes": 14360,
291
- "sha256": "04d5f1cf71ee88946dc0bbe7bef7d3864e6cc6e705304b98e19ad2351c999ca7"
302
+ "bytes": 16597,
303
+ "sha256": "f200650e9a3a816bd3e919adbacad7c4ffb1ab0fd07e7d59f8c25fd8184b71b7"
292
304
  },
293
305
  "conversation.settings.update": {
294
306
  "summary": "Person at this machine only: choose the Agent and its settings for new conversations, among the values that Agent last offered, and whether a model describes the files a message writes. A stale expectedVersion is refused.",
295
307
  "path": "operations/conversation.settings.update.json",
296
- "bytes": 16639,
297
- "sha256": "20612281dff10b3a2f121be5a060f5e996dd7e2ccf5f2b06406bae87a85bc1ed"
308
+ "bytes": 18876,
309
+ "sha256": "9d2b489c49a3731c9081fa2c142e1785b53bf8e4bca09349bb82faf7f792f7b2"
298
310
  },
299
311
  "conversation.start": {
300
- "summary": "Person at this machine only: start a conversation with the selected Claude Code or Codex Agent in this project. Rho selects the Agent plugin backend, attaches this project's MCP grant and records the message before sending it. Without backend or config, the person's saved Agent and settings are used and recorded with the conversation. A repeated changeId with the same text returns the original conversation and starts nothing.",
312
+ "summary": "Person at this machine only: start a conversation with the selected Claude Code or Codex Agent in this project. Rho selects the Agent plugin backend, attaches this project's MCP grant and records the message before sending it. Without backend or config, the person's saved Agent and settings are used and recorded with the conversation. A repeated changeId with the same text returns the original conversation and starts nothing. With continue, the message continues an Agent session listed by agent.sessions.list (one started in a terminal, an editor or the Agent's own app) through that same session, or through a copy of it with copy; a session another live window holds open is refused unless copied.",
301
313
  "path": "operations/conversation.start.json",
302
- "bytes": 34318,
303
- "sha256": "b691ed1d000206bbaa65289e7e255d53fc5552ace1ad180b4f4d8cf2020bbb96"
314
+ "bytes": 35719,
315
+ "sha256": "3cf1320d24698b12d2629d167b1ddd3516d7793725f52499b309437bd1d83fac"
304
316
  },
305
317
  "conversation.stop": {
306
318
  "summary": "Person at this machine only: ask the original Agent to stop answering one message. ACP cancellation is confirmed by the original prompt response; a lost connection keeps the outcome unknown. Legacy CLI conversations confirm process exit. Steps already taken stay done.",
307
319
  "path": "operations/conversation.stop.json",
308
- "bytes": 33471,
309
- "sha256": "0755e7ba9a7c1a516d0158f0f53656f1635970ab767b0455fe786fdb1535c441"
320
+ "bytes": 34246,
321
+ "sha256": "f4bf1a4b8108837fe29f7d71a549c4ecf51c7edfa13777c033460cadebd048e5"
310
322
  },
311
323
  "conversation.trash": {
312
324
  "summary": "Person at this machine only: move a conversation that is not being answered to the trash. It is kept whole and not continued until restored; an idle connection to its Agent ends.",
313
325
  "path": "operations/conversation.trash.json",
314
- "bytes": 6299,
315
- "sha256": "8ecc3aaf8da2cc307b65e7015a17ae1ec096451859a06721d884e1d519cb4540"
326
+ "bytes": 7074,
327
+ "sha256": "643d239b90f97bc69d5f0884b69f51c547f1393ae0cff4a9b9fcf2d9e9763051"
316
328
  },
317
329
  "data.compare": {
318
330
  "summary": "Join two explicit table versions using declared keys, namespaces, fields and join policy. Scientific comparability remains the project responsibility.",
@@ -404,6 +416,48 @@
404
416
  "bytes": 1004,
405
417
  "sha256": "4fbf03970c525ad073153aad9846ce960da2369b8cb45b4b6aaeef95cd8f19fd"
406
418
  },
419
+ "extension.call": {
420
+ "summary": "Call an enabled third-party operation at the described package digest, under the caller and project. The package runs trusted native code. Non-read calls retain the original changeId: repeat observes that invocation, including unknown outcomes, without re-execution. Completion is not scientific validity.",
421
+ "path": "operations/extension.call.json",
422
+ "bytes": 3054,
423
+ "sha256": "fef35859de95442313afcf2fb517ab7ec2e30781344e0b77174b904f70e5df3b"
424
+ },
425
+ "extension.content": {
426
+ "summary": "Read one installed plugin Skill or standalone HTML view at its selected package digest. Reading starts no plugin or runtime.",
427
+ "path": "operations/extension.content.json",
428
+ "bytes": 1627,
429
+ "sha256": "fe3542d6f35267766ef5227d9d6cb98009895ac9ec9cdc1355fbed97e07c77d9"
430
+ },
431
+ "extension.describe": {
432
+ "summary": "Read an installed third-party package manifest, operation input schemas, required Rho methods, Skills and views. Read its Skill with extension.content before use. Disabled packages cannot run.",
433
+ "path": "operations/extension.describe.json",
434
+ "bytes": 4684,
435
+ "sha256": "441616d6e634daa1ce2d058f6d0b0bd7ccd494de33f01a3dae3d6c344dc6f1a9"
436
+ },
437
+ "extension.install": {
438
+ "summary": "Local person/operator: install a trusted prebuilt npm package, local folder, tarball, or Git source. Lifecycle scripts are disabled. Replacement stages and checks the new package before switching; use replace and expectedDigest for updates.",
439
+ "path": "operations/extension.install.json",
440
+ "bytes": 4803,
441
+ "sha256": "862db9660b7c6d0ddfe53aa2c3e1254c0d4a4a717f23c6b820c3248d916b7ce9"
442
+ },
443
+ "extension.list": {
444
+ "summary": "List independently installed third-party packages and their enabled state, source and immutable digest. Reads start no plugin or runtime. Use extension.describe to discover operation schemas and Skills.",
445
+ "path": "operations/extension.list.json",
446
+ "bytes": 2933,
447
+ "sha256": "4af06a8a7c11dbed53a9d9804d215708d7e6b6c0edacdf1bf2817a3daf24f86f"
448
+ },
449
+ "extension.manage": {
450
+ "summary": "Local person/operator: enable, disable or remove an installed third-party package at the expected digest. Existing native tasks, R sessions, project files and retained receipts are preserved.",
451
+ "path": "operations/extension.manage.json",
452
+ "bytes": 1207,
453
+ "sha256": "90a83550840d2d33d3d0c7e5db0dcd09de4752b0b829f65a0cac2f39dbdf5a07"
454
+ },
455
+ "extension.read": {
456
+ "summary": "Observe an original plugin invocation, including pending or unknown outcomes. Never reruns code. Only its original caller can read it.",
457
+ "path": "operations/extension.read.json",
458
+ "bytes": 2409,
459
+ "sha256": "81f219ef1ce3aa15a3d7bd5865a97e141ff5db3ab4629a1eef7928dcf9681d40"
460
+ },
407
461
  "feedback.read": {
408
462
  "summary": "Original business binding only: fetch one complete frozen feedback object using its original delivery/context and a stable fetchId. relatedDocumentId is a pointer: read its CURRENT version before conditional edit/save and preserve human changes. This owner-served receipt does not prove client return or understanding.",
409
463
  "path": "operations/feedback.read.json",
@@ -533,8 +587,8 @@
533
587
  "observation.snapshot": {
534
588
  "summary": "observation.snapshot",
535
589
  "path": "operations/observation.snapshot.json",
536
- "bytes": 165030,
537
- "sha256": "ee71c0bf7b912ad38bbbfc3ad5a797f1306f1eb821cdc30819d24b5d86e0867d"
590
+ "bytes": 165863,
591
+ "sha256": "3ac0beddb297dbd7ee9448f30655e5d9b4e8dd8cbe46a64ed815d133dddfa436"
538
592
  },
539
593
  "project.create": {
540
594
  "summary": "project.create",
@@ -605,8 +659,8 @@
605
659
  "project.work.read": {
606
660
  "summary": "Person at this machine only: read linked Agent sessions, retained native activity identities, current referenced files and the shared notes document. Source cursors and resource versions remain independent. Does not start an Agent, collector or Host.",
607
661
  "path": "operations/project.work.read.json",
608
- "bytes": 22226,
609
- "sha256": "fb1426f26fa7bbb5c01671832b58cac79aa708bc056d8a3cc8e6f0cfc249d9ab"
662
+ "bytes": 22262,
663
+ "sha256": "51d070968ec8b567765acecb7c8ddc83411fe222c469641b2679cc00a5cb1008"
610
664
  },
611
665
  "protocol.describe": {
612
666
  "summary": "protocol.describe",
@@ -683,8 +737,14 @@
683
737
  "session.grant": {
684
738
  "summary": "session.grant",
685
739
  "path": "operations/session.grant.json",
686
- "bytes": 4767,
687
- "sha256": "95564602b9006b5fe960bad93460916c1461f9578766d2fd95a1bccfd866b7a4"
740
+ "bytes": 5059,
741
+ "sha256": "d5d0e15b50349fbec4affa99ceb1b98c79a6dbdce048e1305f8cd8ad31a3fdd2"
742
+ },
743
+ "session.instructions": {
744
+ "summary": "Person at this machine or operator only: read a prompt for the person's own MCP client to connect itself to this existing project. Returns local launcher paths, never credential contents. Reading or copying grants no access, edits no client configuration and starts no runtime.",
745
+ "path": "operations/session.instructions.json",
746
+ "bytes": 1057,
747
+ "sha256": "acc5dba3651bdd6db317d7a3062fd0d7f3dff3e1514d6d51c00a017c3d050181"
688
748
  },
689
749
  "skill.list": {
690
750
  "summary": "List the application and enabled provider Skills shipped in the selected package. Skills guide discovery but do not grant authorization.",