@openclaw/google-meet 2026.7.1-beta.6 → 2026.7.2-beta.1

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 (193) hide show
  1. package/dist/{chrome-create-BhgM0jQO.js → chrome-create-DM1XJCOH.js} +87 -61
  2. package/dist/{cli-D364Yrym.js → cli-SodPSOFX.js} +47 -90
  3. package/dist/{config-DDYRr7-P.js → config-BeoHH_z5.js} +49 -13
  4. package/dist/{create-CkkaRlbI.js → create-CWcFI0ub.js} +2 -2
  5. package/dist/index.js +1235 -359
  6. package/dist/{oauth-75iPDzIn.js → oauth-DOfMKlGp.js} +3 -1
  7. package/node_modules/core-util-is/LICENSE +19 -0
  8. package/node_modules/core-util-is/README.md +3 -0
  9. package/node_modules/core-util-is/lib/util.js +107 -0
  10. package/node_modules/core-util-is/package.json +38 -0
  11. package/node_modules/immediate/LICENSE.txt +20 -0
  12. package/node_modules/immediate/README.md +93 -0
  13. package/node_modules/immediate/dist/immediate.js +75 -0
  14. package/node_modules/immediate/dist/immediate.min.js +1 -0
  15. package/node_modules/immediate/lib/browser.js +69 -0
  16. package/node_modules/immediate/lib/index.js +73 -0
  17. package/node_modules/immediate/package.json +42 -0
  18. package/node_modules/inherits/LICENSE +16 -0
  19. package/node_modules/inherits/README.md +42 -0
  20. package/node_modules/inherits/inherits.js +9 -0
  21. package/node_modules/inherits/inherits_browser.js +27 -0
  22. package/node_modules/inherits/package.json +29 -0
  23. package/node_modules/isarray/.npmignore +1 -0
  24. package/node_modules/isarray/.travis.yml +4 -0
  25. package/node_modules/isarray/Makefile +6 -0
  26. package/node_modules/isarray/README.md +60 -0
  27. package/node_modules/isarray/component.json +19 -0
  28. package/node_modules/isarray/index.js +5 -0
  29. package/node_modules/isarray/package.json +45 -0
  30. package/node_modules/isarray/test.js +20 -0
  31. package/node_modules/jszip/.codeclimate.yml +16 -0
  32. package/node_modules/jszip/.editorconfig +8 -0
  33. package/node_modules/jszip/.eslintrc.js +43 -0
  34. package/node_modules/jszip/.github/workflows/pr.yaml +58 -0
  35. package/node_modules/jszip/.jekyll-metadata +0 -0
  36. package/node_modules/jszip/.travis.yml +17 -0
  37. package/node_modules/jszip/CHANGES.md +204 -0
  38. package/node_modules/jszip/LICENSE.markdown +651 -0
  39. package/node_modules/jszip/README.markdown +33 -0
  40. package/node_modules/jszip/deps.js +37 -0
  41. package/node_modules/jszip/dist/jszip.js +11577 -0
  42. package/node_modules/jszip/dist/jszip.min.js +13 -0
  43. package/node_modules/jszip/graph.svg +601 -0
  44. package/node_modules/jszip/index.d.ts +330 -0
  45. package/node_modules/jszip/lib/base64.js +106 -0
  46. package/node_modules/jszip/lib/compressedObject.js +74 -0
  47. package/node_modules/jszip/lib/compressions.js +14 -0
  48. package/node_modules/jszip/lib/crc32.js +77 -0
  49. package/node_modules/jszip/lib/defaults.js +11 -0
  50. package/node_modules/jszip/lib/external.js +18 -0
  51. package/node_modules/jszip/lib/flate.js +85 -0
  52. package/node_modules/jszip/lib/generate/ZipFileWorker.js +539 -0
  53. package/node_modules/jszip/lib/generate/index.js +57 -0
  54. package/node_modules/jszip/lib/index.js +55 -0
  55. package/node_modules/jszip/lib/license_header.js +11 -0
  56. package/node_modules/jszip/lib/load.js +88 -0
  57. package/node_modules/jszip/lib/nodejs/NodejsStreamInputAdapter.js +74 -0
  58. package/node_modules/jszip/lib/nodejs/NodejsStreamOutputAdapter.js +42 -0
  59. package/node_modules/jszip/lib/nodejsUtils.js +57 -0
  60. package/node_modules/jszip/lib/object.js +384 -0
  61. package/node_modules/jszip/lib/readable-stream-browser.js +10 -0
  62. package/node_modules/jszip/lib/reader/ArrayReader.js +57 -0
  63. package/node_modules/jszip/lib/reader/DataReader.js +116 -0
  64. package/node_modules/jszip/lib/reader/NodeBufferReader.js +19 -0
  65. package/node_modules/jszip/lib/reader/StringReader.js +38 -0
  66. package/node_modules/jszip/lib/reader/Uint8ArrayReader.js +22 -0
  67. package/node_modules/jszip/lib/reader/readerFor.js +28 -0
  68. package/node_modules/jszip/lib/signature.js +7 -0
  69. package/node_modules/jszip/lib/stream/ConvertWorker.js +26 -0
  70. package/node_modules/jszip/lib/stream/Crc32Probe.js +24 -0
  71. package/node_modules/jszip/lib/stream/DataLengthProbe.js +29 -0
  72. package/node_modules/jszip/lib/stream/DataWorker.js +116 -0
  73. package/node_modules/jszip/lib/stream/GenericWorker.js +263 -0
  74. package/node_modules/jszip/lib/stream/StreamHelper.js +214 -0
  75. package/node_modules/jszip/lib/support.js +38 -0
  76. package/node_modules/jszip/lib/utf8.js +275 -0
  77. package/node_modules/jszip/lib/utils.js +501 -0
  78. package/node_modules/jszip/lib/zipEntries.js +261 -0
  79. package/node_modules/jszip/lib/zipEntry.js +293 -0
  80. package/node_modules/jszip/lib/zipObject.js +133 -0
  81. package/node_modules/jszip/package.json +67 -0
  82. package/node_modules/jszip/sponsors.md +21 -0
  83. package/node_modules/jszip/tsconfig.json +101 -0
  84. package/node_modules/jszip/vendor/FileSaver.js +247 -0
  85. package/node_modules/lie/README.md +62 -0
  86. package/node_modules/lie/dist/lie.js +350 -0
  87. package/node_modules/lie/dist/lie.min.js +1 -0
  88. package/node_modules/lie/dist/lie.polyfill.js +358 -0
  89. package/node_modules/lie/dist/lie.polyfill.min.js +1 -0
  90. package/node_modules/lie/lib/browser.js +273 -0
  91. package/node_modules/lie/lib/index.js +298 -0
  92. package/node_modules/lie/license.md +7 -0
  93. package/node_modules/lie/lie.d.ts +244 -0
  94. package/node_modules/lie/package.json +69 -0
  95. package/node_modules/lie/polyfill.js +4 -0
  96. package/node_modules/pako/CHANGELOG.md +164 -0
  97. package/node_modules/pako/LICENSE +21 -0
  98. package/node_modules/pako/README.md +191 -0
  99. package/node_modules/pako/dist/pako.js +6818 -0
  100. package/node_modules/pako/dist/pako.min.js +1 -0
  101. package/node_modules/pako/dist/pako_deflate.js +3997 -0
  102. package/node_modules/pako/dist/pako_deflate.min.js +1 -0
  103. package/node_modules/pako/dist/pako_inflate.js +3300 -0
  104. package/node_modules/pako/dist/pako_inflate.min.js +1 -0
  105. package/node_modules/pako/index.js +14 -0
  106. package/node_modules/pako/lib/deflate.js +400 -0
  107. package/node_modules/pako/lib/inflate.js +423 -0
  108. package/node_modules/pako/lib/utils/common.js +105 -0
  109. package/node_modules/pako/lib/utils/strings.js +187 -0
  110. package/node_modules/pako/lib/zlib/README +59 -0
  111. package/node_modules/pako/lib/zlib/adler32.js +51 -0
  112. package/node_modules/pako/lib/zlib/constants.js +68 -0
  113. package/node_modules/pako/lib/zlib/crc32.js +59 -0
  114. package/node_modules/pako/lib/zlib/deflate.js +1874 -0
  115. package/node_modules/pako/lib/zlib/gzheader.js +58 -0
  116. package/node_modules/pako/lib/zlib/inffast.js +345 -0
  117. package/node_modules/pako/lib/zlib/inflate.js +1556 -0
  118. package/node_modules/pako/lib/zlib/inftrees.js +343 -0
  119. package/node_modules/pako/lib/zlib/messages.js +32 -0
  120. package/node_modules/pako/lib/zlib/trees.js +1222 -0
  121. package/node_modules/pako/lib/zlib/zstream.js +47 -0
  122. package/node_modules/pako/package.json +44 -0
  123. package/node_modules/parse-ms/index.d.ts +30 -0
  124. package/node_modules/parse-ms/index.js +45 -0
  125. package/node_modules/parse-ms/license +9 -0
  126. package/node_modules/parse-ms/package.json +47 -0
  127. package/node_modules/parse-ms/readme.md +46 -0
  128. package/node_modules/pretty-ms/index.d.ts +157 -0
  129. package/node_modules/pretty-ms/index.js +149 -0
  130. package/node_modules/pretty-ms/license +9 -0
  131. package/node_modules/pretty-ms/package.json +55 -0
  132. package/node_modules/pretty-ms/readme.md +179 -0
  133. package/node_modules/process-nextick-args/index.js +45 -0
  134. package/node_modules/process-nextick-args/license.md +19 -0
  135. package/node_modules/process-nextick-args/package.json +25 -0
  136. package/node_modules/process-nextick-args/readme.md +18 -0
  137. package/node_modules/readable-stream/.travis.yml +34 -0
  138. package/node_modules/readable-stream/CONTRIBUTING.md +38 -0
  139. package/node_modules/readable-stream/GOVERNANCE.md +136 -0
  140. package/node_modules/readable-stream/LICENSE +47 -0
  141. package/node_modules/readable-stream/README.md +58 -0
  142. package/node_modules/readable-stream/doc/wg-meetings/2015-01-30.md +60 -0
  143. package/node_modules/readable-stream/duplex-browser.js +1 -0
  144. package/node_modules/readable-stream/duplex.js +1 -0
  145. package/node_modules/readable-stream/lib/_stream_duplex.js +131 -0
  146. package/node_modules/readable-stream/lib/_stream_passthrough.js +47 -0
  147. package/node_modules/readable-stream/lib/_stream_readable.js +1019 -0
  148. package/node_modules/readable-stream/lib/_stream_transform.js +214 -0
  149. package/node_modules/readable-stream/lib/_stream_writable.js +685 -0
  150. package/node_modules/readable-stream/lib/internal/streams/BufferList.js +78 -0
  151. package/node_modules/readable-stream/lib/internal/streams/destroy.js +84 -0
  152. package/node_modules/readable-stream/lib/internal/streams/stream-browser.js +1 -0
  153. package/node_modules/readable-stream/lib/internal/streams/stream.js +1 -0
  154. package/node_modules/readable-stream/package.json +52 -0
  155. package/node_modules/readable-stream/passthrough.js +1 -0
  156. package/node_modules/readable-stream/readable-browser.js +7 -0
  157. package/node_modules/readable-stream/readable.js +19 -0
  158. package/node_modules/readable-stream/transform.js +1 -0
  159. package/node_modules/readable-stream/writable-browser.js +1 -0
  160. package/node_modules/readable-stream/writable.js +8 -0
  161. package/node_modules/safe-buffer/LICENSE +21 -0
  162. package/node_modules/safe-buffer/README.md +584 -0
  163. package/node_modules/safe-buffer/index.d.ts +187 -0
  164. package/node_modules/safe-buffer/index.js +62 -0
  165. package/node_modules/safe-buffer/package.json +37 -0
  166. package/node_modules/{commander/LICENSE → setimmediate/LICENSE.txt} +8 -10
  167. package/node_modules/setimmediate/package.json +30 -0
  168. package/node_modules/setimmediate/setImmediate.js +186 -0
  169. package/node_modules/string_decoder/.travis.yml +50 -0
  170. package/node_modules/string_decoder/LICENSE +48 -0
  171. package/node_modules/string_decoder/README.md +47 -0
  172. package/node_modules/string_decoder/lib/string_decoder.js +296 -0
  173. package/node_modules/string_decoder/package.json +31 -0
  174. package/node_modules/util-deprecate/History.md +16 -0
  175. package/node_modules/util-deprecate/LICENSE +24 -0
  176. package/node_modules/util-deprecate/README.md +53 -0
  177. package/node_modules/util-deprecate/browser.js +67 -0
  178. package/node_modules/util-deprecate/node.js +6 -0
  179. package/node_modules/util-deprecate/package.json +27 -0
  180. package/npm-shrinkwrap.json +127 -9
  181. package/openclaw.plugin.json +1 -1
  182. package/package.json +8 -6
  183. package/node_modules/commander/Readme.md +0 -1172
  184. package/node_modules/commander/index.js +0 -21
  185. package/node_modules/commander/lib/argument.js +0 -147
  186. package/node_modules/commander/lib/command.js +0 -2790
  187. package/node_modules/commander/lib/error.js +0 -36
  188. package/node_modules/commander/lib/help.js +0 -731
  189. package/node_modules/commander/lib/option.js +0 -377
  190. package/node_modules/commander/lib/suggestSimilar.js +0 -99
  191. package/node_modules/commander/package-support.json +0 -19
  192. package/node_modules/commander/package.json +0 -64
  193. package/node_modules/commander/typings/index.d.ts +0 -1113
@@ -8,6 +8,7 @@ import { sleep } from "openclaw/plugin-sdk/runtime-env";
8
8
  const GOOGLE_DRIVE_API_BASE_URL = "https://www.googleapis.com/drive/v3";
9
9
  const GOOGLE_DRIVE_API_HOST = "www.googleapis.com";
10
10
  const GOOGLE_DRIVE_MEET_SCOPE = "https://www.googleapis.com/auth/drive.meet.readonly";
11
+ const GOOGLE_DRIVE_REQUEST_TIMEOUT_MS = 3e4;
11
12
  const TEXT_PLAIN_MIME = "text/plain";
12
13
  function appendQuery$1(url, query) {
13
14
  const parsed = new URL(url);
@@ -33,7 +34,8 @@ async function exportGoogleDriveDocumentText(params) {
33
34
  Accept: TEXT_PLAIN_MIME
34
35
  } },
35
36
  policy: { allowedHostnames: [GOOGLE_DRIVE_API_HOST] },
36
- auditContext: "google-meet.drive.files.export"
37
+ auditContext: "google-meet.drive.files.export",
38
+ timeoutMs: GOOGLE_DRIVE_REQUEST_TIMEOUT_MS
37
39
  });
38
40
  try {
39
41
  if (!response.ok) throw await googleApiError({
@@ -51,6 +53,7 @@ async function exportGoogleDriveDocumentText(params) {
51
53
  const GOOGLE_MEET_API_BASE_URL = `https://meet.googleapis.com/v2`;
52
54
  const GOOGLE_MEET_URL_HOST = "meet.google.com";
53
55
  const GOOGLE_MEET_API_HOST = "meet.googleapis.com";
56
+ const GOOGLE_MEET_REQUEST_TIMEOUT_MS = 3e4;
54
57
  const GOOGLE_MEET_MEDIA_SCOPE = "https://www.googleapis.com/auth/meetings.conference.media.readonly";
55
58
  const GOOGLE_MEET_SPACE_SCOPE = "https://www.googleapis.com/auth/meetings.space.readonly";
56
59
  const GOOGLE_MEET_SPACE_CREATED_SCOPE = "https://www.googleapis.com/auth/meetings.space.created";
@@ -101,14 +104,28 @@ function assertResourceArray(value, key, context) {
101
104
  function getErrorMessage(error) {
102
105
  return error instanceof Error ? error.message : String(error);
103
106
  }
104
- async function fetchGoogleMeetJson(params) {
105
- const { response, release } = await fetchWithSsrFGuard({
107
+ async function requestGoogleMeetApi(params) {
108
+ return await fetchWithSsrFGuard({
106
109
  url: appendQuery(`${GOOGLE_MEET_API_BASE_URL}/${params.path}`, params.query),
107
- init: { headers: {
108
- Authorization: `Bearer ${params.accessToken}`,
109
- Accept: "application/json"
110
- } },
110
+ init: {
111
+ method: params.method,
112
+ headers: {
113
+ Authorization: `Bearer ${params.accessToken}`,
114
+ Accept: "application/json",
115
+ ...params.body === void 0 ? {} : { "Content-Type": "application/json" }
116
+ },
117
+ body: params.body
118
+ },
111
119
  policy: { allowedHostnames: [GOOGLE_MEET_API_HOST] },
120
+ auditContext: params.auditContext,
121
+ timeoutMs: GOOGLE_MEET_REQUEST_TIMEOUT_MS
122
+ });
123
+ }
124
+ async function fetchGoogleMeetJson(params) {
125
+ const { response, release } = await requestGoogleMeetApi({
126
+ accessToken: params.accessToken,
127
+ path: params.path,
128
+ query: params.query,
112
129
  auditContext: params.auditContext
113
130
  });
114
131
  try {
@@ -146,13 +163,9 @@ async function listGoogleMeetCollection(params) {
146
163
  }
147
164
  async function fetchGoogleMeetSpace(params) {
148
165
  const name = normalizeGoogleMeetSpaceName(params.meeting);
149
- const { response, release } = await fetchWithSsrFGuard({
150
- url: `${GOOGLE_MEET_API_BASE_URL}/${encodeSpaceNameForPath(name)}`,
151
- init: { headers: {
152
- Authorization: `Bearer ${params.accessToken}`,
153
- Accept: "application/json"
154
- } },
155
- policy: { allowedHostnames: [GOOGLE_MEET_API_HOST] },
166
+ const { response, release } = await requestGoogleMeetApi({
167
+ accessToken: params.accessToken,
168
+ path: encodeSpaceNameForPath(name),
156
169
  auditContext: "google-meet.spaces.get"
157
170
  });
158
171
  try {
@@ -170,18 +183,11 @@ async function fetchGoogleMeetSpace(params) {
170
183
  }
171
184
  async function createGoogleMeetSpace(params) {
172
185
  const body = params.config && Object.keys(params.config).length > 0 ? JSON.stringify({ config: params.config }) : "{}";
173
- const { response, release } = await fetchWithSsrFGuard({
174
- url: `${GOOGLE_MEET_API_BASE_URL}/spaces`,
175
- init: {
176
- method: "POST",
177
- headers: {
178
- Authorization: `Bearer ${params.accessToken}`,
179
- Accept: "application/json",
180
- "Content-Type": "application/json"
181
- },
182
- body
183
- },
184
- policy: { allowedHostnames: [GOOGLE_MEET_API_HOST] },
186
+ const { response, release } = await requestGoogleMeetApi({
187
+ accessToken: params.accessToken,
188
+ path: "spaces",
189
+ method: "POST",
190
+ body,
185
191
  auditContext: "google-meet.spaces.create"
186
192
  });
187
193
  try {
@@ -207,18 +213,11 @@ async function endGoogleMeetActiveConference(params) {
207
213
  accessToken: params.accessToken,
208
214
  meeting: params.meeting
209
215
  })).name;
210
- const { response, release } = await fetchWithSsrFGuard({
211
- url: `${GOOGLE_MEET_API_BASE_URL}/${encodeSpaceNameForPath(space)}:endActiveConference`,
212
- init: {
213
- method: "POST",
214
- headers: {
215
- Authorization: `Bearer ${params.accessToken}`,
216
- Accept: "application/json",
217
- "Content-Type": "application/json"
218
- },
219
- body: "{}"
220
- },
221
- policy: { allowedHostnames: [GOOGLE_MEET_API_HOST] },
216
+ const { response, release } = await requestGoogleMeetApi({
217
+ accessToken: params.accessToken,
218
+ path: `${encodeSpaceNameForPath(space)}:endActiveConference`,
219
+ method: "POST",
220
+ body: "{}",
222
221
  auditContext: "google-meet.spaces.endActiveConference"
223
222
  });
224
223
  try {
@@ -625,6 +624,15 @@ function isSameMeetUrlForReuse(a, b) {
625
624
  const normalizedB = normalizeMeetUrlForReuse(b);
626
625
  return Boolean(normalizedA && normalizedB && normalizedA === normalizedB);
627
626
  }
627
+ function isEnglishMeetTab(url) {
628
+ if (!url) return false;
629
+ try {
630
+ const parsed = new URL(url);
631
+ return parsed.protocol === "https:" && parsed.hostname.toLowerCase() === "meet.google.com" && parsed.searchParams.get("hl")?.toLowerCase() === "en";
632
+ } catch {
633
+ return false;
634
+ }
635
+ }
628
636
  function isGoogleMeetNode(node) {
629
637
  const commands = Array.isArray(node.commands) ? node.commands : [];
630
638
  const caps = Array.isArray(node.caps) ? node.caps : [];
@@ -665,17 +673,16 @@ async function resolveChromeNodeInfo(params) {
665
673
  const requested = params.requestedNode?.trim();
666
674
  if (requested) {
667
675
  const matches = (await listGoogleMeetNodes(params.runtime)).nodes.filter((node) => matchesRequestedNode(node, requested));
668
- if (matches.length === 1) {
669
- const [node] = matches;
670
- if (isGoogleMeetNode(node)) return node;
671
- throw new Error(`Configured Google Meet node ${requested} is not usable (${formatNodeLabel(node)}): ${describeNodeUsabilityIssues(node).join("; ")}. Start or reinstall \`openclaw node run\` on that Chrome host, approve pairing, and allow googlemeet.chrome plus browser.proxy.`);
672
- }
673
676
  if (matches.length > 1) throw new Error(`Configured Google Meet node ${requested} is ambiguous (${matches.length} matches). Pin chromeNode.node to a unique node id, display name, or remote IP.`);
674
- throw new Error(`Configured Google Meet node ${requested} was not found. Run \`openclaw nodes status\` and start or approve the Chrome node.`);
677
+ const [node] = matches;
678
+ if (!node) throw new Error(`Configured Google Meet node ${requested} was not found. Run \`openclaw nodes status\` and start or approve the Chrome node.`);
679
+ if (isGoogleMeetNode(node)) return node;
680
+ throw new Error(`Configured Google Meet node ${requested} is not usable (${formatNodeLabel(node)}): ${describeNodeUsabilityIssues(node).join("; ")}. Start or reinstall \`openclaw node run\` on that Chrome host, approve pairing, and allow googlemeet.chrome plus browser.proxy.`);
675
681
  }
676
682
  const nodes = (await listGoogleMeetNodes(params.runtime, { connected: true })).nodes.filter(isGoogleMeetNode);
677
- if (nodes.length === 0) throw new Error("No connected Google Meet-capable node with browser proxy. Run `openclaw node run` on the Chrome host with browser proxy enabled, approve pairing, and allow googlemeet.chrome plus browser.proxy.");
678
- if (nodes.length === 1) return nodes[0];
683
+ const [node] = nodes;
684
+ if (!node) throw new Error("No connected Google Meet-capable node with browser proxy. Run `openclaw node run` on the Chrome host with browser proxy enabled, approve pairing, and allow googlemeet.chrome plus browser.proxy.");
685
+ if (nodes.length === 1) return node;
679
686
  throw new Error("Multiple Google Meet-capable nodes connected. Set plugins.entries.google-meet.config.chromeNode.node.");
680
687
  }
681
688
  async function resolveChromeNode(params) {
@@ -894,25 +901,43 @@ async function createMeetWithBrowserProxyOnNode(params) {
894
901
  });
895
902
  const timeoutMs = Math.max(GOOGLE_MEET_BROWSER_CREATE_TIMEOUT_MS, params.config.chrome.joinTimeoutMs);
896
903
  const stepTimeoutMs = Math.min(timeoutMs, GOOGLE_MEET_BROWSER_STEP_TIMEOUT_MS);
904
+ let openedByPlugin = false;
897
905
  let tab = await findGoogleMeetCreateTab({
898
906
  runtime: params.runtime,
899
907
  nodeId,
900
908
  timeoutMs: stepTimeoutMs
901
909
  });
902
- if (tab?.targetId) await focusBrowserTab({
903
- runtime: params.runtime,
904
- nodeId,
905
- targetId: tab.targetId,
906
- timeoutMs: stepTimeoutMs
907
- });
908
- else tab = readBrowserTab(await callBrowserProxyOnNode({
909
- runtime: params.runtime,
910
- nodeId,
911
- method: "POST",
912
- path: "/tabs/open",
913
- body: { url: forceMeetEnglishUi(GOOGLE_MEET_NEW_URL) },
914
- timeoutMs: stepTimeoutMs
915
- }));
910
+ if (tab?.targetId) {
911
+ await focusBrowserTab({
912
+ runtime: params.runtime,
913
+ nodeId,
914
+ targetId: tab.targetId,
915
+ timeoutMs: stepTimeoutMs
916
+ });
917
+ const reusedUrl = tab.url ?? "";
918
+ const englishUrl = (/^https:\/\/meet\.google\.com\/new(?:$|[/?#])/i.test(reusedUrl) || reusedUrl.startsWith("https://accounts.google.com/")) && reusedUrl ? forceMeetEnglishUi(reusedUrl) : void 0;
919
+ if (englishUrl && englishUrl !== reusedUrl) tab = readBrowserTab(await callBrowserProxyOnNode({
920
+ runtime: params.runtime,
921
+ nodeId,
922
+ method: "POST",
923
+ path: "/navigate",
924
+ body: {
925
+ targetId: tab.targetId,
926
+ url: englishUrl
927
+ },
928
+ timeoutMs: stepTimeoutMs
929
+ })) ?? tab;
930
+ } else {
931
+ tab = readBrowserTab(await callBrowserProxyOnNode({
932
+ runtime: params.runtime,
933
+ nodeId,
934
+ method: "POST",
935
+ path: "/tabs/open",
936
+ body: { url: forceMeetEnglishUi(GOOGLE_MEET_NEW_URL) },
937
+ timeoutMs: stepTimeoutMs
938
+ }));
939
+ openedByPlugin = Boolean(tab?.targetId);
940
+ }
916
941
  const targetId = tab?.targetId;
917
942
  if (!targetId) throw new Error("Browser fallback opened Google Meet but did not return a targetId.");
918
943
  const notes = /* @__PURE__ */ new Set();
@@ -938,6 +963,7 @@ async function createMeetWithBrowserProxyOnNode(params) {
938
963
  source: "browser",
939
964
  nodeId,
940
965
  targetId,
966
+ openedByPlugin,
941
967
  meetingUri: result.meetingUri,
942
968
  browserUrl: result.browserUrl,
943
969
  browserTitle: result.browserTitle,
@@ -964,4 +990,4 @@ async function createMeetWithBrowserProxyOnNode(params) {
964
990
  throw new Error(lastResult?.manualAction ?? `Google Meet did not return a meeting URL from the browser create flow before timeout.${lastError ? ` Last browser automation error: ${formatBrowserAutomationError(lastError)}` : ""}`);
965
991
  }
966
992
  //#endregion
967
- export { fetchLatestGoogleMeetConferenceRecord as _, forceMeetEnglishUi as a, readBrowserTab as c, buildGoogleMeetPreflightReport as d, createGoogleMeetSpace as f, fetchGoogleMeetSpace as g, fetchGoogleMeetAttendance as h, callBrowserProxyOnNode as i, resolveChromeNode as l, fetchGoogleMeetArtifacts as m, isGoogleMeetBrowserManualActionError as n, isSameMeetUrlForReuse as o, endGoogleMeetActiveConference as p, asBrowserTabs as r, normalizeMeetUrlForReuse as s, createMeetWithBrowserProxyOnNode as t, resolveChromeNodeInfo as u };
993
+ export { fetchGoogleMeetSpace as _, forceMeetEnglishUi as a, normalizeMeetUrlForReuse as c, resolveChromeNodeInfo as d, buildGoogleMeetPreflightReport as f, fetchGoogleMeetAttendance as g, fetchGoogleMeetArtifacts as h, callBrowserProxyOnNode as i, readBrowserTab as l, endGoogleMeetActiveConference as m, isGoogleMeetBrowserManualActionError as n, isEnglishMeetTab as o, createGoogleMeetSpace as p, asBrowserTabs as r, isSameMeetUrlForReuse as s, createMeetWithBrowserProxyOnNode as t, resolveChromeNode as u, fetchLatestGoogleMeetConferenceRecord as v };
@@ -1,14 +1,16 @@
1
- import { a as buildGoogleMeetCalendarDayWindow, i as resolveGoogleMeetGatewayOperationTimeoutMs, o as findGoogleMeetCalendarEvent, s as listGoogleMeetCalendarEvents } from "./config-DDYRr7-P.js";
2
- import { _ as fetchLatestGoogleMeetConferenceRecord, d as buildGoogleMeetPreflightReport, f as createGoogleMeetSpace, g as fetchGoogleMeetSpace, h as fetchGoogleMeetAttendance, m as fetchGoogleMeetArtifacts, p as endGoogleMeetActiveConference } from "./chrome-create-BhgM0jQO.js";
3
- import { buildGoogleMeetAuthUrl, createGoogleMeetOAuthState, createGoogleMeetPkce, exchangeGoogleMeetAuthCode, resolveGoogleMeetAccessToken, waitForGoogleMeetAuthCode } from "./oauth-75iPDzIn.js";
4
- import { hasCreateSpaceConfigInput, resolveCreateSpaceConfig } from "./create-CkkaRlbI.js";
1
+ import { a as buildGoogleMeetCalendarDayWindow, i as resolveGoogleMeetGatewayOperationTimeoutMs, o as findGoogleMeetCalendarEvent, s as listGoogleMeetCalendarEvents } from "./config-BeoHH_z5.js";
2
+ import { _ as fetchGoogleMeetSpace, f as buildGoogleMeetPreflightReport, g as fetchGoogleMeetAttendance, h as fetchGoogleMeetArtifacts, m as endGoogleMeetActiveConference, p as createGoogleMeetSpace, v as fetchLatestGoogleMeetConferenceRecord } from "./chrome-create-DM1XJCOH.js";
3
+ import { buildGoogleMeetAuthUrl, createGoogleMeetOAuthState, createGoogleMeetPkce, exchangeGoogleMeetAuthCode, resolveGoogleMeetAccessToken, waitForGoogleMeetAuthCode } from "./oauth-DOfMKlGp.js";
4
+ import { hasCreateSpaceConfigInput, resolveCreateSpaceConfig } from "./create-CWcFI0ub.js";
5
5
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
6
6
  import { callGatewayFromCli } from "openclaw/plugin-sdk/gateway-runtime";
7
- import { clampTimerTimeoutMs, parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
7
+ import { clampTimerTimeoutMs, parseStrictNonNegativeInteger, parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
8
8
  import path from "node:path";
9
9
  import { mkdir, writeFile } from "node:fs/promises";
10
10
  import { createInterface } from "node:readline/promises";
11
11
  import { format } from "node:util";
12
+ import JSZip from "jszip";
13
+ import prettyMilliseconds from "pretty-ms";
12
14
  //#region extensions/google-meet/src/cli.ts
13
15
  const testing = {
14
16
  parsePositiveNumber,
@@ -103,11 +105,7 @@ async function callGoogleMeetGateway(params) {
103
105
  }
104
106
  function formatDuration(value) {
105
107
  if (value === void 0) return "n/a";
106
- const totalSeconds = Math.round(value / 1e3);
107
- const hours = Math.floor(totalSeconds / 3600);
108
- const minutes = Math.floor(totalSeconds % 3600 / 60);
109
- const seconds = totalSeconds % 60;
110
- return hours > 0 ? `${hours}h ${minutes.toString().padStart(2, "0")}m` : `${minutes}m ${seconds.toString().padStart(2, "0")}s`;
108
+ return prettyMilliseconds(Math.max(0, Math.round(value / 1e3) * 1e3), { unitCount: 2 });
111
109
  }
112
110
  function writeDoctorStatus(status) {
113
111
  if (!status.found) {
@@ -297,6 +295,7 @@ function writeRecoverCurrentTabResult(result) {
297
295
  url: result.browser.browserUrl ?? result.tab?.url ?? "unknown",
298
296
  transport: result.transport,
299
297
  mode: "transcribe",
298
+ agentId: "main",
300
299
  state: "active",
301
300
  createdAt: "",
302
301
  updatedAt: "",
@@ -315,6 +314,13 @@ function writeRecoverCurrentTabResult(result) {
315
314
  }
316
315
  });
317
316
  }
317
+ function writeLeaveResult(sessionId, result) {
318
+ if (result.browserLeft === false) {
319
+ writeStdoutLine("left %s, but the browser participant may still be in the call; check session notes", sessionId);
320
+ return;
321
+ }
322
+ writeStdoutLine("left %s", sessionId);
323
+ }
318
324
  function resolveMeetingInput(config, value) {
319
325
  const meeting = value?.trim() || config.defaults.meeting;
320
326
  if (!meeting) throw new Error("Meeting input is required. Pass a URL/meeting code or configure defaults.meeting.");
@@ -720,81 +726,6 @@ function googleMeetExportFileNames() {
720
726
  function defaultExportDirectory() {
721
727
  return `google-meet-export-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
722
728
  }
723
- const CRC32_TABLE = new Uint32Array(Array.from({ length: 256 }, (_, index) => {
724
- let value = index;
725
- for (let bit = 0; bit < 8; bit += 1) value = value & 1 ? 3988292384 ^ value >>> 1 : value >>> 1;
726
- return value >>> 0;
727
- }));
728
- function crc32(buffer) {
729
- let value = 4294967295;
730
- for (const byte of buffer) value = CRC32_TABLE[(value ^ byte) & 255] ^ value >>> 8;
731
- return (value ^ 4294967295) >>> 0;
732
- }
733
- function dosDateTime(date = /* @__PURE__ */ new Date()) {
734
- return {
735
- time: date.getHours() << 11 | date.getMinutes() << 5 | Math.floor(date.getSeconds() / 2),
736
- date: date.getFullYear() - 1980 << 9 | date.getMonth() + 1 << 5 | date.getDate()
737
- };
738
- }
739
- function buildZipArchive(files) {
740
- const localParts = [];
741
- const centralParts = [];
742
- let offset = 0;
743
- const stamp = dosDateTime();
744
- for (const file of files) {
745
- const name = Buffer.from(file.name, "utf8");
746
- const content = Buffer.from(file.content, "utf8");
747
- const checksum = crc32(content);
748
- const local = Buffer.alloc(30);
749
- local.writeUInt32LE(67324752, 0);
750
- local.writeUInt16LE(20, 4);
751
- local.writeUInt16LE(0, 6);
752
- local.writeUInt16LE(0, 8);
753
- local.writeUInt16LE(stamp.time, 10);
754
- local.writeUInt16LE(stamp.date, 12);
755
- local.writeUInt32LE(checksum, 14);
756
- local.writeUInt32LE(content.length, 18);
757
- local.writeUInt32LE(content.length, 22);
758
- local.writeUInt16LE(name.length, 26);
759
- local.writeUInt16LE(0, 28);
760
- localParts.push(local, name, content);
761
- const central = Buffer.alloc(46);
762
- central.writeUInt32LE(33639248, 0);
763
- central.writeUInt16LE(20, 4);
764
- central.writeUInt16LE(20, 6);
765
- central.writeUInt16LE(0, 8);
766
- central.writeUInt16LE(0, 10);
767
- central.writeUInt16LE(stamp.time, 12);
768
- central.writeUInt16LE(stamp.date, 14);
769
- central.writeUInt32LE(checksum, 16);
770
- central.writeUInt32LE(content.length, 20);
771
- central.writeUInt32LE(content.length, 24);
772
- central.writeUInt16LE(name.length, 28);
773
- central.writeUInt16LE(0, 30);
774
- central.writeUInt16LE(0, 32);
775
- central.writeUInt16LE(0, 34);
776
- central.writeUInt16LE(0, 36);
777
- central.writeUInt32LE(0, 38);
778
- central.writeUInt32LE(offset, 42);
779
- centralParts.push(central, name);
780
- offset += local.length + name.length + content.length;
781
- }
782
- const centralDirectory = Buffer.concat(centralParts);
783
- const end = Buffer.alloc(22);
784
- end.writeUInt32LE(101010256, 0);
785
- end.writeUInt16LE(0, 4);
786
- end.writeUInt16LE(0, 6);
787
- end.writeUInt16LE(files.length, 8);
788
- end.writeUInt16LE(files.length, 10);
789
- end.writeUInt32LE(centralDirectory.length, 12);
790
- end.writeUInt32LE(offset, 16);
791
- end.writeUInt16LE(0, 20);
792
- return Buffer.concat([
793
- ...localParts,
794
- centralDirectory,
795
- end
796
- ]);
797
- }
798
729
  async function writeMeetExportBundle(params) {
799
730
  const outputDir = params.outputDir?.trim() || defaultExportDirectory();
800
731
  await mkdir(outputDir, { recursive: true });
@@ -840,7 +771,9 @@ async function writeMeetExportBundle(params) {
840
771
  files: files.map((file) => path.join(outputDir, file.name))
841
772
  };
842
773
  if (zipFile) {
843
- await writeFile(zipFile, buildZipArchive(files));
774
+ const zip = new JSZip();
775
+ for (const file of files) zip.file(file.name, file.content);
776
+ await writeFile(zipFile, await zip.generateAsync({ type: "nodebuffer" }));
844
777
  result.zipFile = zipFile;
845
778
  }
846
779
  return result;
@@ -1316,6 +1249,28 @@ function registerGoogleMeetCli(params) {
1316
1249
  }
1317
1250
  writeStdoutJson(await (await params.ensureRuntime()).status(sessionId));
1318
1251
  });
1252
+ root.command("transcript").description("Print the bounded caption transcript for a Meet session").argument("<session-id>", "Meet session ID").option("--since <index>", "Resume from the previous response's nextIndex").option("--json", "Print JSON output", false).action(async (sessionId, options) => {
1253
+ const sinceIndex = parseStrictNonNegativeInteger(options.since);
1254
+ if (options.since !== void 0 && sinceIndex === void 0) throw new Error("--since must be a non-negative safe integer");
1255
+ const delegated = await callGoogleMeetGateway({
1256
+ callGateway,
1257
+ method: "googlemeet.transcript",
1258
+ payload: {
1259
+ sessionId,
1260
+ ...sinceIndex === void 0 ? {} : { sinceIndex }
1261
+ }
1262
+ });
1263
+ const result = delegated.ok ? delegated.payload : await (await params.ensureRuntime()).transcript(sessionId, sinceIndex === void 0 ? {} : { sinceIndex });
1264
+ if (!result.found) throw new Error("session not found");
1265
+ if (options.json) {
1266
+ writeStdoutJson(result);
1267
+ return;
1268
+ }
1269
+ if (result.evicted) writeStdoutLine("# transcript evicted from runtime memory");
1270
+ else if (result.droppedLines) writeStdoutLine("# %d earlier lines dropped by the transcript cap", result.droppedLines);
1271
+ for (const line of result.lines ?? []) writeStdoutLine("%s%s%s", line.at ? `[${line.at}] ` : "", line.speaker ? `${line.speaker}: ` : "", line.text);
1272
+ writeStdoutLine("# nextIndex: %d", result.nextIndex ?? 0);
1273
+ });
1319
1274
  root.command("doctor").description("Show human-readable Meet session/browser/realtime health").argument("[session-id]", "Meet session ID").option("--oauth", "Verify Google Meet OAuth token refresh without printing secrets", false).option("--meeting <value>", "Also verify spaces.get for a Meet URL, code, or spaces/{id}").option("--create-space", "Also verify spaces.create by creating a throwaway Meet space", false).option("--access-token <token>", "Access token override").option("--refresh-token <token>", "Refresh token override").option("--client-id <id>", "OAuth client id override").option("--client-secret <secret>", "OAuth client secret override").option("--expires-at <ms>", "Cached access token expiry as unix epoch milliseconds").option("--json", "Print JSON output", false).action(async (sessionId, options) => {
1320
1275
  if (options.oauth) {
1321
1276
  const report = await buildOAuthDoctorReport(params.config, options);
@@ -1376,12 +1331,14 @@ function registerGoogleMeetCli(params) {
1376
1331
  payload: { sessionId }
1377
1332
  });
1378
1333
  if (delegated.ok) {
1379
- if (!delegated.payload.found) throw new Error("session not found");
1380
- writeStdoutLine("left %s", sessionId);
1334
+ const result = delegated.payload;
1335
+ if (!result.found) throw new Error("session not found");
1336
+ writeLeaveResult(sessionId, result);
1381
1337
  return;
1382
1338
  }
1383
- if (!(await (await params.ensureRuntime()).leave(sessionId)).found) throw new Error("session not found");
1384
- writeStdoutLine("left %s", sessionId);
1339
+ const result = await (await params.ensureRuntime()).leave(sessionId);
1340
+ if (!result.found) throw new Error("session not found");
1341
+ writeLeaveResult(sessionId, result);
1385
1342
  });
1386
1343
  root.command("speak").argument("<session-id>", "Meet session ID").argument("[message]", "Realtime instructions to speak now").action(async (sessionId, message) => {
1387
1344
  const delegated = await callGoogleMeetGateway({
@@ -4,34 +4,69 @@ import { readProviderJsonResponse } from "openclaw/plugin-sdk/provider-http";
4
4
  import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
5
5
  import { addTimerTimeoutGraceMs, resolvePositiveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
6
6
  import { REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME, resolveRealtimeVoiceAgentConsultToolPolicy } from "openclaw/plugin-sdk/realtime-voice";
7
+ //#region extensions/google-meet/src/meet-url.ts
8
+ function normalizeOptionalString$1(value) {
9
+ if (typeof value !== "string") return;
10
+ return value.trim() || void 0;
11
+ }
12
+ function normalizeMeetUrl(input) {
13
+ const raw = normalizeOptionalString$1(input);
14
+ if (!raw) throw new Error("url required");
15
+ let url;
16
+ try {
17
+ url = new URL(raw);
18
+ } catch {
19
+ throw new Error("url must be a valid Google Meet URL");
20
+ }
21
+ if (url.protocol !== "https:" || url.hostname.toLowerCase() !== "meet.google.com" || url.port || url.username || url.password) throw new Error("url must be an explicit https://meet.google.com/... URL");
22
+ if (!/^\/[a-z]{3}-[a-z]{4}-[a-z]{3}(?:$|[/?#])/i.test(url.pathname)) throw new Error("url must include a Google Meet meeting code");
23
+ return url.toString();
24
+ }
25
+ //#endregion
7
26
  //#region extensions/google-meet/src/calendar.ts
8
27
  const GOOGLE_CALENDAR_API_BASE_URL = "https://www.googleapis.com/calendar/v3";
9
28
  const GOOGLE_CALENDAR_API_HOST = "www.googleapis.com";
10
- const GOOGLE_MEET_URL_HOST = "meet.google.com";
11
29
  const GOOGLE_CALENDAR_EVENTS_SCOPE = "https://www.googleapis.com/auth/calendar.events.readonly";
30
+ const GOOGLE_CALENDAR_REQUEST_TIMEOUT_MS = 3e4;
12
31
  function appendQuery(url, query) {
13
32
  const parsed = new URL(url);
14
33
  for (const [key, value] of Object.entries(query)) if (value !== void 0) parsed.searchParams.set(key, String(value));
15
34
  return parsed.toString();
16
35
  }
17
- function isGoogleMeetUri(value) {
18
- if (!value?.trim()) return false;
36
+ function normalizeGoogleMeetCalendarUri(value) {
37
+ if (!value?.trim()) return;
19
38
  try {
20
- return new URL(value).hostname === GOOGLE_MEET_URL_HOST;
39
+ const url = new URL(value);
40
+ if (url.protocol !== "http:" && url.protocol !== "https:") return;
41
+ if (url.hostname.toLowerCase() !== "meet.google.com" || url.port || url.username || url.password) return;
42
+ url.protocol = "https:";
43
+ return normalizeMeetUrl(url.toString());
21
44
  } catch {
22
- return false;
45
+ return;
23
46
  }
24
47
  }
25
48
  function extractGoogleMeetUriFromText(value) {
26
- return (value?.match(/https:\/\/meet\.google\.com\/[a-z0-9-]+/i))?.[0];
49
+ const matches = value?.matchAll(/https:\/\/meet\.google\.com\/[a-z0-9-]+/gi);
50
+ for (const match of matches ?? []) {
51
+ const uri = normalizeGoogleMeetCalendarUri(match[0]);
52
+ if (uri) return uri;
53
+ }
54
+ }
55
+ function findFirstGoogleMeetCalendarUri(entryPoints, predicate = () => true) {
56
+ for (const entry of entryPoints) {
57
+ if (!predicate(entry)) continue;
58
+ const uri = normalizeGoogleMeetCalendarUri(entry.uri);
59
+ if (uri) return uri;
60
+ }
27
61
  }
28
62
  function extractGoogleMeetUriFromCalendarEvent(event) {
29
- if (isGoogleMeetUri(event.hangoutLink)) return event.hangoutLink;
63
+ const hangoutLink = normalizeGoogleMeetCalendarUri(event.hangoutLink);
64
+ if (hangoutLink) return hangoutLink;
30
65
  const entryPoints = event.conferenceData?.entryPoints ?? [];
31
- const videoEntry = entryPoints.find((entry) => entry.entryPointType === "video" && isGoogleMeetUri(entry.uri));
32
- if (videoEntry?.uri) return videoEntry.uri;
33
- const meetEntry = entryPoints.find((entry) => isGoogleMeetUri(entry.uri));
34
- if (meetEntry?.uri) return meetEntry.uri;
66
+ const videoEntryUri = findFirstGoogleMeetCalendarUri(entryPoints, (entry) => entry.entryPointType === "video");
67
+ if (videoEntryUri) return videoEntryUri;
68
+ const meetEntryUri = findFirstGoogleMeetCalendarUri(entryPoints);
69
+ if (meetEntryUri) return meetEntryUri;
35
70
  return extractGoogleMeetUriFromText(event.location) ?? extractGoogleMeetUriFromText(event.description);
36
71
  }
37
72
  function buildGoogleMeetCalendarDayWindow(now = /* @__PURE__ */ new Date()) {
@@ -91,7 +126,8 @@ async function fetchGoogleCalendarEvents(params) {
91
126
  Accept: "application/json"
92
127
  } },
93
128
  policy: { allowedHostnames: [GOOGLE_CALENDAR_API_HOST] },
94
- auditContext: "google-meet.calendar.events.list"
129
+ auditContext: "google-meet.calendar.events.list",
130
+ timeoutMs: GOOGLE_CALENDAR_REQUEST_TIMEOUT_MS
95
131
  });
96
132
  try {
97
133
  if (!response.ok) throw await googleApiError({
@@ -464,4 +500,4 @@ function resolveGoogleMeetConfigWithEnv(input, env = process.env) {
464
500
  };
465
501
  }
466
502
  //#endregion
467
- export { buildGoogleMeetCalendarDayWindow as a, resolveGoogleMeetGatewayOperationTimeoutMs as i, DEFAULT_GOOGLE_MEET_AUDIO_OUTPUT_COMMAND as n, findGoogleMeetCalendarEvent as o, resolveGoogleMeetConfig as r, listGoogleMeetCalendarEvents as s, DEFAULT_GOOGLE_MEET_AUDIO_INPUT_COMMAND as t };
503
+ export { buildGoogleMeetCalendarDayWindow as a, normalizeMeetUrl as c, resolveGoogleMeetGatewayOperationTimeoutMs as i, DEFAULT_GOOGLE_MEET_AUDIO_OUTPUT_COMMAND as n, findGoogleMeetCalendarEvent as o, resolveGoogleMeetConfig as r, listGoogleMeetCalendarEvents as s, DEFAULT_GOOGLE_MEET_AUDIO_INPUT_COMMAND as t };
@@ -1,5 +1,5 @@
1
- import { f as createGoogleMeetSpace, t as createMeetWithBrowserProxyOnNode } from "./chrome-create-BhgM0jQO.js";
2
- import { resolveGoogleMeetAccessToken } from "./oauth-75iPDzIn.js";
1
+ import { p as createGoogleMeetSpace, t as createMeetWithBrowserProxyOnNode } from "./chrome-create-DM1XJCOH.js";
2
+ import { resolveGoogleMeetAccessToken } from "./oauth-DOfMKlGp.js";
3
3
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
4
4
  //#region extensions/google-meet/src/create.ts
5
5
  function normalizeTransport(value) {