@open-everywhere/provider-google-chat 0.0.0-stage → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +51 -0
  3. package/README.md +40 -2
  4. package/agent/channels/google-chat-auth.ts +145 -0
  5. package/agent/channels/google-chat-front.ts +338 -0
  6. package/agent/channels/google-chat-identity.ts +97 -0
  7. package/agent/channels/google-chat-message-ops.ts +30 -0
  8. package/agent/channels/google-chat-origin-codec.ts +32 -0
  9. package/agent/channels/google-chat-post-arm.ts +36 -0
  10. package/agent/channels/google-chat-rest.ts +87 -0
  11. package/agent/channels/google-chat.ts +194 -0
  12. package/agent/contributions.ts +16 -0
  13. package/agent/docs-generated.ts +120 -0
  14. package/agent/policy.ts +101 -0
  15. package/agent/provider-events.ts +18 -0
  16. package/agent/register.ts +48 -0
  17. package/agent/surface-parity.ts +64 -0
  18. package/dist/agent/channels/google-chat-auth.d.ts +39 -0
  19. package/dist/agent/channels/google-chat-auth.d.ts.map +1 -0
  20. package/dist/agent/channels/google-chat-auth.js +118 -0
  21. package/dist/agent/channels/google-chat-auth.js.map +1 -0
  22. package/dist/agent/channels/google-chat-front.d.ts +102 -0
  23. package/dist/agent/channels/google-chat-front.d.ts.map +1 -0
  24. package/dist/agent/channels/google-chat-front.js +258 -0
  25. package/dist/agent/channels/google-chat-front.js.map +1 -0
  26. package/dist/agent/channels/google-chat-identity.d.ts +28 -0
  27. package/dist/agent/channels/google-chat-identity.d.ts.map +1 -0
  28. package/dist/agent/channels/google-chat-identity.js +70 -0
  29. package/dist/agent/channels/google-chat-identity.js.map +1 -0
  30. package/dist/agent/channels/google-chat-message-ops.d.ts +10 -0
  31. package/dist/agent/channels/google-chat-message-ops.d.ts.map +1 -0
  32. package/dist/agent/channels/google-chat-message-ops.js +25 -0
  33. package/dist/agent/channels/google-chat-message-ops.js.map +1 -0
  34. package/dist/agent/channels/google-chat-origin-codec.d.ts +6 -0
  35. package/dist/agent/channels/google-chat-origin-codec.d.ts.map +1 -0
  36. package/dist/agent/channels/google-chat-origin-codec.js +31 -0
  37. package/dist/agent/channels/google-chat-origin-codec.js.map +1 -0
  38. package/dist/agent/channels/google-chat-post-arm.d.ts +11 -0
  39. package/dist/agent/channels/google-chat-post-arm.d.ts.map +1 -0
  40. package/dist/agent/channels/google-chat-post-arm.js +31 -0
  41. package/dist/agent/channels/google-chat-post-arm.js.map +1 -0
  42. package/dist/agent/channels/google-chat-rest.d.ts +21 -0
  43. package/dist/agent/channels/google-chat-rest.d.ts.map +1 -0
  44. package/dist/agent/channels/google-chat-rest.js +81 -0
  45. package/dist/agent/channels/google-chat-rest.js.map +1 -0
  46. package/dist/agent/channels/google-chat.d.ts +3 -0
  47. package/dist/agent/channels/google-chat.d.ts.map +1 -0
  48. package/dist/agent/channels/google-chat.js +157 -0
  49. package/dist/agent/channels/google-chat.js.map +1 -0
  50. package/dist/agent/contributions.d.ts +12 -0
  51. package/dist/agent/contributions.d.ts.map +1 -0
  52. package/dist/agent/contributions.js +16 -0
  53. package/dist/agent/contributions.js.map +1 -0
  54. package/dist/agent/docs-generated.d.ts +3 -0
  55. package/dist/agent/docs-generated.d.ts.map +1 -0
  56. package/dist/agent/docs-generated.js +118 -0
  57. package/dist/agent/docs-generated.js.map +1 -0
  58. package/dist/agent/policy.d.ts +38 -0
  59. package/dist/agent/policy.d.ts.map +1 -0
  60. package/dist/agent/policy.js +78 -0
  61. package/dist/agent/policy.js.map +1 -0
  62. package/dist/agent/provider-events.d.ts +3 -0
  63. package/dist/agent/provider-events.d.ts.map +1 -0
  64. package/dist/agent/provider-events.js +16 -0
  65. package/dist/agent/provider-events.js.map +1 -0
  66. package/dist/agent/register.d.ts +3 -0
  67. package/dist/agent/register.d.ts.map +1 -0
  68. package/dist/agent/register.js +37 -0
  69. package/dist/agent/register.js.map +1 -0
  70. package/dist/agent/surface-parity.d.ts +3 -0
  71. package/dist/agent/surface-parity.d.ts.map +1 -0
  72. package/dist/agent/surface-parity.js +60 -0
  73. package/dist/agent/surface-parity.js.map +1 -0
  74. package/package.json +116 -4
  75. package/tsconfig.build.json +22 -0
  76. package/tsconfig.json +15 -0
@@ -0,0 +1,10 @@
1
+ import { type SurfaceMessageOps } from "@open-everywhere/core/agent/adapter-api.js";
2
+ import { type GoogleChatPolicy } from "../policy.js";
3
+ import { type GoogleChatPostDeps } from "./google-chat-rest.js";
4
+ export interface GoogleChatNoticeDeps extends GoogleChatPostDeps {
5
+ readonly policy?: () => GoogleChatPolicy;
6
+ }
7
+ /** Post one host notice into a space. Throws a token-free error when it cannot. */
8
+ export declare function postGoogleChatNotice(channelId: string, text: string, deps?: GoogleChatNoticeDeps): Promise<string>;
9
+ export declare const googleChatMessageOps: SurfaceMessageOps;
10
+ //# sourceMappingURL=google-chat-message-ops.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-chat-message-ops.d.ts","sourceRoot":"","sources":["../../../agent/channels/google-chat-message-ops.ts"],"names":[],"mappings":"AAQA,OAAO,EAAkB,KAAK,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AACpG,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EAA2B,KAAK,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEzF,MAAM,WAAW,oBAAqB,SAAQ,kBAAkB;IAC9D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,gBAAgB,CAAC;CAC1C;AAED,mFAAmF;AACnF,wBAAsB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,oBAAyB,GAAG,OAAO,CAAC,MAAM,CAAC,CAI5H;AAED,eAAO,MAAM,oBAAoB,EAAE,iBAMlC,CAAC"}
@@ -0,0 +1,25 @@
1
+ // google-chat-message-ops — the Google Chat surface's host-notice transport (SurfaceMessageOps). Core's shared
2
+ // room-notice paths — an approval outcome note, the judge-lift notice, a stop or cancel note — post through
3
+ // `SurfaceMessageOps.postText(channelId, text)`. On Google Chat the `channelId` is the space name the identity
4
+ // mapper put in the binding's target. A `replyToMessageId` anchor is not followed: Google Chat threads a reply by
5
+ // thread name, not by message, so the notice lands in the space as a new message.
6
+ //
7
+ // 🔴 TEXT ONLY. `editMessage` refuses: no card posts on this surface yet, so there is no card to close.
8
+ import { markNotApplied } from "@open-everywhere/core/agent/adapter-api.js";
9
+ import { googleChatPolicy } from "../policy.js";
10
+ import { createGoogleChatMessage } from "./google-chat-rest.js";
11
+ /** Post one host notice into a space. Throws a token-free error when it cannot. */
12
+ export async function postGoogleChatNotice(channelId, text, deps = {}) {
13
+ const policy = (deps.policy ?? googleChatPolicy)();
14
+ if (!policy.enabled)
15
+ throw markNotApplied(new Error("the Google Chat surface is turned off."));
16
+ return createGoogleChatMessage({ space: channelId, text }, deps);
17
+ }
18
+ export const googleChatMessageOps = {
19
+ platform: "google-chat",
20
+ postText: (channelId, text) => postGoogleChatNotice(channelId, text),
21
+ async editMessage() {
22
+ throw markNotApplied(new Error("editing a Google Chat message is not built yet."));
23
+ },
24
+ };
25
+ //# sourceMappingURL=google-chat-message-ops.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-chat-message-ops.js","sourceRoot":"","sources":["../../../agent/channels/google-chat-message-ops.ts"],"names":[],"mappings":"AAAA,+GAA+G;AAC/G,4GAA4G;AAC5G,+GAA+G;AAC/G,kHAAkH;AAClH,kFAAkF;AAClF,EAAE;AACF,wGAAwG;AAExG,OAAO,EAAE,cAAc,EAA0B,MAAM,4CAA4C,CAAC;AACpG,OAAO,EAAE,gBAAgB,EAAyB,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,uBAAuB,EAA2B,MAAM,uBAAuB,CAAC;AAMzF,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,SAAiB,EAAE,IAAY,EAAE,IAAI,GAAyB,EAAE;IACzG,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,gBAAgB,CAAC,EAAE,CAAC;IACnD,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,MAAM,cAAc,CAAC,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC,CAAC;IAC/F,OAAO,uBAAuB,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,CAAC;AACnE,CAAC;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAsB;IACrD,QAAQ,EAAE,aAAa;IACvB,QAAQ,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC,oBAAoB,CAAC,SAAS,EAAE,IAAI,CAAC;IACpE,KAAK,CAAC,WAAW;QACf,MAAM,cAAc,CAAC,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC,CAAC;IACrF,CAAC;CACF,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { UnifiedWakeOrigin, WakeOriginCodec } from "@open-everywhere/core/agent/adapter-api.js";
2
+ export type GoogleChatOrigin = Extract<UnifiedWakeOrigin, {
3
+ platform: "google-chat";
4
+ }>;
5
+ export declare const googleChatWakeOriginCodec: WakeOriginCodec<GoogleChatOrigin>;
6
+ //# sourceMappingURL=google-chat-origin-codec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-chat-origin-codec.d.ts","sourceRoot":"","sources":["../../../agent/channels/google-chat-origin-codec.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,4CAA4C,CAAC;AAGrG,MAAM,MAAM,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,EAAE;IAAE,QAAQ,EAAE,aAAa,CAAA;CAAE,CAAC,CAAC;AAOvF,eAAO,MAAM,yBAAyB,EAAE,eAAe,CAAC,gBAAgB,CAavE,CAAC"}
@@ -0,0 +1,31 @@
1
+ // The Google Chat UnifiedWakeOrigin codec. An origin is STORED DATA (the durable wake map), so this validator is a
2
+ // compatibility contract with rows already on disk: it tolerates unknown extra fields, and it refuses any row whose
3
+ // space, thread or message name is not Google's grammar, because the post arm builds its URL from them.
4
+ //
5
+ // THE CONVERSATION: `threadRef` keys on (space, thread). Every message in a Google Chat space carries a thread
6
+ // name, even a top-level one, so the thread is part of the identity and placement lives inside it (no
7
+ // `placementRef`). Only a positive `threadReply: true` makes an origin thread-scoped.
8
+ import { isMessageNameIn, isSpaceName, isThreadNameIn } from "./google-chat-rest.js";
9
+ const WORKSPACE_SEGMENT = /^[a-z0-9][a-z0-9-]{0,62}$/u;
10
+ /** A task windowId is `[^:]+` (core channels/window-key.ts); Google names hold no colon, but fold one anyway. */
11
+ const noColon = (s) => s.replace(/:/g, "_");
12
+ export const googleChatWakeOriginCodec = {
13
+ validate: (o) => {
14
+ if (typeof o.workspace !== "string" || !WORKSPACE_SEGMENT.test(o.workspace))
15
+ return false;
16
+ if (!isSpaceName(o.space))
17
+ return false;
18
+ if (o.thread !== undefined && !isThreadNameIn(o.thread, o.space))
19
+ return false;
20
+ if (o.messageName !== undefined && !isMessageNameIn(o.messageName, o.space))
21
+ return false;
22
+ // A thread reply with no thread is not a shape the front mints.
23
+ if (o.threadReply !== undefined && (o.threadReply !== true || o.thread === undefined))
24
+ return false;
25
+ return true;
26
+ },
27
+ threadRef: (o) => ({ channelKey: noColon(`google-chat/${o.space}`), threadKey: noColon(o.thread ?? o.space) }),
28
+ isThreadScoped: (o) => o.threadReply === true,
29
+ containerId: (o) => o.space,
30
+ };
31
+ //# sourceMappingURL=google-chat-origin-codec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-chat-origin-codec.js","sourceRoot":"","sources":["../../../agent/channels/google-chat-origin-codec.ts"],"names":[],"mappings":"AAAA,mHAAmH;AACnH,oHAAoH;AACpH,wGAAwG;AACxG,EAAE;AACF,+GAA+G;AAC/G,sGAAsG;AACtG,sFAAsF;AAGtF,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAIrF,MAAM,iBAAiB,GAAG,4BAA4B,CAAC;AAEvD,iHAAiH;AACjH,MAAM,OAAO,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AAE5D,MAAM,CAAC,MAAM,yBAAyB,GAAsC;IAC1E,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE;QACd,IAAI,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;YAAE,OAAO,KAAK,CAAC;QAC1F,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QACxC,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QAC/E,IAAI,CAAC,CAAC,WAAW,KAAK,SAAS,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QAC1F,gEAAgE;QAChE,IAAI,CAAC,CAAC,WAAW,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,WAAW,KAAK,IAAI,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC;YAAE,OAAO,KAAK,CAAC;QACpG,OAAO,IAAI,CAAC;IACd,CAAC;IACD,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;IAC9G,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,KAAK,IAAI;IAC7C,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK;CAC5B,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { type PostArm } from "@open-everywhere/core/agent/adapter-api.js";
2
+ import { type GoogleChatPolicy } from "../policy.js";
3
+ import { type GoogleChatPostDeps } from "./google-chat-rest.js";
4
+ import { type GoogleChatOrigin } from "./google-chat-origin-codec.js";
5
+ export interface GoogleChatReplyDeps extends GoogleChatPostDeps {
6
+ readonly policy?: () => GoogleChatPolicy;
7
+ }
8
+ /** Send one reply for a stored origin. Throws a token-free error when the reply did not go out. */
9
+ export declare function sendGoogleChatReply(origin: GoogleChatOrigin, text: string, deps?: GoogleChatReplyDeps): Promise<string>;
10
+ export declare const googleChatPostArm: PostArm;
11
+ //# sourceMappingURL=google-chat-post-arm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-chat-post-arm.d.ts","sourceRoot":"","sources":["../../../agent/channels/google-chat-post-arm.ts"],"names":[],"mappings":"AAQA,OAAO,EAAkB,KAAK,OAAO,EAAiD,MAAM,4CAA4C,CAAC;AACzI,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EAA2B,KAAK,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AACzF,OAAO,EAA6B,KAAK,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAEjG,MAAM,WAAW,mBAAoB,SAAQ,kBAAkB;IAC7D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,gBAAgB,CAAC;CAC1C;AAED,mGAAmG;AACnG,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,mBAAwB,GAAG,OAAO,CAAC,MAAM,CAAC,CAUjI;AAED,eAAO,MAAM,iBAAiB,EAAE,OAK/B,CAAC"}
@@ -0,0 +1,31 @@
1
+ // google-chat-post-arm — the Google Chat surface's arm of the post-arms registry. One verb: answer the event that
2
+ // woke the seat, in the same space and thread, as the app (google-chat-rest.ts). The space and thread come from
3
+ // the stored origin, which the front froze from the token-verified event; the model never names one.
4
+ //
5
+ // 🔴 THE POLICY IS RE-READ AT SEND TIME. A surface turned off between the wake and the reply sends nothing, and
6
+ // an origin minted under another workspace segment is refused.
7
+ // NO EDIT, NO REACTION yet: the arm registers neither, and the capability manifest says so.
8
+ import { markNotApplied } from "@open-everywhere/core/agent/adapter-api.js";
9
+ import { googleChatPolicy } from "../policy.js";
10
+ import { createGoogleChatMessage } from "./google-chat-rest.js";
11
+ import { googleChatWakeOriginCodec } from "./google-chat-origin-codec.js";
12
+ /** Send one reply for a stored origin. Throws a token-free error when the reply did not go out. */
13
+ export async function sendGoogleChatReply(origin, text, deps = {}) {
14
+ if (!googleChatWakeOriginCodec.validate(origin)) {
15
+ throw markNotApplied(new Error("reply couldn't post to Google Chat — the stored reply target is not a valid Google Chat origin."));
16
+ }
17
+ const policy = (deps.policy ?? googleChatPolicy)();
18
+ if (!policy.enabled)
19
+ throw markNotApplied(new Error("reply couldn't post to Google Chat — the surface is turned off in agent/google-chat/policy.ts."));
20
+ if (origin.workspace !== policy.workspace) {
21
+ throw markNotApplied(new Error("reply couldn't post to Google Chat — the stored reply target belongs to another workspace."));
22
+ }
23
+ return createGoogleChatMessage({ space: origin.space, ...(origin.thread !== undefined ? { thread: origin.thread } : {}), text }, deps);
24
+ }
25
+ export const googleChatPostArm = {
26
+ platform: "google-chat",
27
+ dispatchUnified: (origin, text, _deps) => sendGoogleChatReply(origin, text),
28
+ describeRedriveTarget: (origin) => `Google Chat ${origin.space}`,
29
+ redriveContainerId: (origin) => origin.space,
30
+ };
31
+ //# sourceMappingURL=google-chat-post-arm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-chat-post-arm.js","sourceRoot":"","sources":["../../../agent/channels/google-chat-post-arm.ts"],"names":[],"mappings":"AAAA,kHAAkH;AAClH,gHAAgH;AAChH,qGAAqG;AACrG,EAAE;AACF,gHAAgH;AAChH,+DAA+D;AAC/D,4FAA4F;AAE5F,OAAO,EAAE,cAAc,EAA+D,MAAM,4CAA4C,CAAC;AACzI,OAAO,EAAE,gBAAgB,EAAyB,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,uBAAuB,EAA2B,MAAM,uBAAuB,CAAC;AACzF,OAAO,EAAE,yBAAyB,EAAyB,MAAM,+BAA+B,CAAC;AAMjG,mGAAmG;AACnG,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,MAAwB,EAAE,IAAY,EAAE,IAAI,GAAwB,EAAE;IAC9G,IAAI,CAAC,yBAAyB,CAAC,QAAQ,CAAC,MAA4C,CAAC,EAAE,CAAC;QACtF,MAAM,cAAc,CAAC,IAAI,KAAK,CAAC,iGAAiG,CAAC,CAAC,CAAC;IACrI,CAAC;IACD,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,gBAAgB,CAAC,EAAE,CAAC;IACnD,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,MAAM,cAAc,CAAC,IAAI,KAAK,CAAC,gGAAgG,CAAC,CAAC,CAAC;IACvJ,IAAI,MAAM,CAAC,SAAS,KAAK,MAAM,CAAC,SAAS,EAAE,CAAC;QAC1C,MAAM,cAAc,CAAC,IAAI,KAAK,CAAC,4FAA4F,CAAC,CAAC,CAAC;IAChI,CAAC;IACD,OAAO,uBAAuB,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,CAAC;AACzI,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAY;IACxC,QAAQ,EAAE,aAAa;IACvB,eAAe,EAAE,CAAC,MAAyB,EAAE,IAAY,EAAE,KAAuB,EAAE,EAAE,CAAC,mBAAmB,CAAC,MAA0B,EAAE,IAAI,CAAC;IAC5I,qBAAqB,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,eAAgB,MAA2B,CAAC,KAAK,EAAE;IACtF,kBAAkB,EAAE,CAAC,MAAM,EAAE,EAAE,CAAE,MAA2B,CAAC,KAAK;CACnE,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { type GoogleChatTokenDeps } from "./google-chat-auth.js";
2
+ /** One Chat message's text limit is 4,096 characters; leave room for nothing else. */
3
+ export declare const GOOGLE_CHAT_MAX_TEXT = 4000;
4
+ export declare function isSpaceName(v: unknown): v is string;
5
+ /** A thread name that belongs to `space` (a thread of another space is not a thread of this one). */
6
+ export declare function isThreadNameIn(v: unknown, space: string): v is string;
7
+ export declare function isMessageNameIn(v: unknown, space: string): v is string;
8
+ /** Split `text` into Chat-sized pieces, preferring a newline near the limit, never inside a surrogate pair. */
9
+ export declare function splitGoogleChatText(text: string, max?: number): readonly string[];
10
+ export interface GoogleChatPostDeps extends GoogleChatTokenDeps {
11
+ }
12
+ /**
13
+ * Post `text` into `space`, threaded under `thread` when given (a thread Google no longer knows falls back to
14
+ * a new thread). Returns the LAST created message name. A pre-flight refusal is definitive (`markNotApplied`).
15
+ */
16
+ export declare function createGoogleChatMessage(input: {
17
+ readonly space: string;
18
+ readonly thread?: string;
19
+ readonly text: string;
20
+ }, deps?: GoogleChatPostDeps): Promise<string>;
21
+ //# sourceMappingURL=google-chat-rest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-chat-rest.d.ts","sourceRoot":"","sources":["../../../agent/channels/google-chat-rest.ts"],"names":[],"mappings":"AAQA,OAAO,EAAyB,KAAK,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAGxF,sFAAsF;AACtF,eAAO,MAAM,oBAAoB,OAAO,CAAC;AAMzC,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,MAAM,CAEnD;AAED,qGAAqG;AACrG,wBAAgB,cAAc,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,IAAI,MAAM,CAErE;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,IAAI,MAAM,CAEtE;AAED,+GAA+G;AAC/G,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAuB,GAAG,SAAS,MAAM,EAAE,CAc/F;AAED,MAAM,WAAW,kBAAmB,SAAQ,mBAAmB;CAAG;AAElE;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAClF,IAAI,GAAE,kBAAuB,GAC5B,OAAO,CAAC,MAAM,CAAC,CA6BjB"}
@@ -0,0 +1,81 @@
1
+ // google-chat-rest — the ONE outbound call of the Google Chat surface: create a message in a space, as the app,
2
+ // optionally inside a thread. The host is pinned (`chat.googleapis.com`), the space and thread names are
3
+ // validated against Google's resource grammar before they reach a URL, and errors carry the HTTP status only.
4
+ //
5
+ // The app can post only into a space it is a member of, so this call cannot reach a space nobody added the app
6
+ // to. A text longer than one Chat message is sent as consecutive messages in the same thread.
7
+ import { friendlyOutboundText, markNotApplied } from "@open-everywhere/core/agent/adapter-api.js";
8
+ import { googleChatAccessToken } from "./google-chat-auth.js";
9
+ const CHAT_API = "https://chat.googleapis.com/v1";
10
+ /** One Chat message's text limit is 4,096 characters; leave room for nothing else. */
11
+ export const GOOGLE_CHAT_MAX_TEXT = 4000;
12
+ const SPACE_NAME = /^spaces\/[A-Za-z0-9_-]{1,128}$/u;
13
+ const THREAD_NAME = /^spaces\/[A-Za-z0-9_-]{1,128}\/threads\/[A-Za-z0-9_.-]{1,128}$/u;
14
+ const MESSAGE_NAME = /^spaces\/[A-Za-z0-9_-]{1,128}\/messages\/[A-Za-z0-9_.-]{1,128}$/u;
15
+ export function isSpaceName(v) {
16
+ return typeof v === "string" && SPACE_NAME.test(v);
17
+ }
18
+ /** A thread name that belongs to `space` (a thread of another space is not a thread of this one). */
19
+ export function isThreadNameIn(v, space) {
20
+ return typeof v === "string" && THREAD_NAME.test(v) && v.startsWith(`${space}/threads/`);
21
+ }
22
+ export function isMessageNameIn(v, space) {
23
+ return typeof v === "string" && MESSAGE_NAME.test(v) && v.startsWith(`${space}/messages/`);
24
+ }
25
+ /** Split `text` into Chat-sized pieces, preferring a newline near the limit, never inside a surrogate pair. */
26
+ export function splitGoogleChatText(text, max = GOOGLE_CHAT_MAX_TEXT) {
27
+ const out = [];
28
+ let rest = text;
29
+ while (rest.length > max) {
30
+ const nl = rest.lastIndexOf("\n", max);
31
+ let cut = nl > max / 2 ? nl : max;
32
+ // Never cut through a surrogate pair: a lone half is not valid text, and Google may refuse the message.
33
+ const before = rest.charCodeAt(cut - 1);
34
+ if (before >= 0xd800 && before <= 0xdbff)
35
+ cut -= 1;
36
+ out.push(rest.slice(0, cut));
37
+ rest = rest.slice(cut).replace(/^\n/u, "");
38
+ }
39
+ out.push(rest);
40
+ return out;
41
+ }
42
+ /**
43
+ * Post `text` into `space`, threaded under `thread` when given (a thread Google no longer knows falls back to
44
+ * a new thread). Returns the LAST created message name. A pre-flight refusal is definitive (`markNotApplied`).
45
+ */
46
+ export async function createGoogleChatMessage(input, deps = {}) {
47
+ if (!isSpaceName(input.space))
48
+ throw markNotApplied(new Error("the Google Chat space name is not valid."));
49
+ if (input.thread !== undefined && !isThreadNameIn(input.thread, input.space)) {
50
+ throw markNotApplied(new Error("the Google Chat thread does not belong to the space."));
51
+ }
52
+ if (input.text.trim() === "")
53
+ throw markNotApplied(new Error("a Google Chat message needs text."));
54
+ // THE FRIENDLY-NAMES GUARD (OPE-2482), on the one Google Chat write: every raw id renders as a name or
55
+ // plain words before the text is split and sent, so a post outside the registered arms is covered too.
56
+ const text = await friendlyOutboundText(input.text, "google-chat");
57
+ const token = await googleChatAccessToken(deps);
58
+ const doFetch = deps.fetch ?? fetch;
59
+ let thread = input.thread;
60
+ let last = "";
61
+ for (const piece of splitGoogleChatText(text)) {
62
+ const url = `${CHAT_API}/${input.space}/messages${thread !== undefined ? "?messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD" : ""}`;
63
+ const res = await doFetch(url, {
64
+ method: "POST",
65
+ headers: { authorization: `Bearer ${token}`, "content-type": "application/json; charset=utf-8" },
66
+ body: JSON.stringify({ text: piece, ...(thread !== undefined ? { thread: { name: thread } } : {}) }),
67
+ });
68
+ if (!res.ok)
69
+ throw new Error(`Google Chat refused the message (HTTP ${res.status}).`);
70
+ const body = (await res.json().catch(() => ({})));
71
+ if (typeof body.name !== "string")
72
+ throw new Error("Google Chat returned no message name.");
73
+ last = body.name;
74
+ // The pieces after the first follow the first one's thread, so a long answer stays together.
75
+ const created = body.thread?.name;
76
+ if (thread === undefined && isThreadNameIn(created, input.space))
77
+ thread = created;
78
+ }
79
+ return last;
80
+ }
81
+ //# sourceMappingURL=google-chat-rest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-chat-rest.js","sourceRoot":"","sources":["../../../agent/channels/google-chat-rest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ declare const _default: import("eve/channels").Channel<undefined, Record<string, unknown>, Record<string, unknown>>;
2
+ export default _default;
3
+ //# sourceMappingURL=google-chat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-chat.d.ts","sourceRoot":"","sources":["../../../agent/channels/google-chat.ts"],"names":[],"mappings":""}
@@ -0,0 +1,157 @@
1
+ // The GOOGLE CHAT surface — the agent as a Google Chat app (OPE-2442). A custom `defineChannel` HTTP transport
2
+ // (eve ships no Google Chat channel): `POST /eve/v1/google-chat` is the app's HTTP endpoint. The eve-free
3
+ // orchestration is google-chat-front.ts; this file is the live wiring — the store, the config, and the two seat
4
+ // dispatches.
5
+ //
6
+ // THE LOOP:
7
+ // POST /eve/v1/google-chat
8
+ // → handleGoogleChatRequest (google-chat-front.ts) holds the route's order, and a test pins it:
9
+ // → the surface SHIPS OFF: a disabled policy (or one with no audience) answers 503 before the body is read
10
+ // → the bearer token is verified against Google's keys and the policy's audience (fail closed: 401)
11
+ // → the body is read ONCE, capped (413), and the route acknowledges `{}` (no synchronous message) so a slow seat
12
+ // never makes Google time the event out; the rest runs in the background
13
+ // → parse, dedupe on the message name, route: a mention in a space diverts into the standing seat of the
14
+ // domain whose `reach` lists `google-chat/<workspace>/<space id>` — the same
15
+ // `divertInboundToUnifiedWindow` every chat surface's front door uses; the person's own DM with the app
16
+ // diverts into their DM seat (channels/dm-seat.ts)
17
+ // → the seat answers with `reply`, which the post arm (google-chat-post-arm.ts) sends into the same space
18
+ // and thread, as the app.
19
+ //
20
+ // Spend, the wake ingress row, provider-selection admission, rate-limit retry and the audit of the wake all ride
21
+ // the shared divert. Nothing here re-implements them.
22
+ import { auditErrorDetail } from "@open-everywhere/core/agent/adapter-api.js";
23
+ import { defineChannel, POST } from "eve/channels";
24
+ import { appendAudit, claimRuntimeRotation, carryTailForward, deploymentOrg, divertInboundToUnifiedWindow, divertToUnifiedWindow, dmWindowRegistryKey, getConfig, getOperationalStore, getOrCreateDmSeat, grainUsesUnifiedWindow, mintRotationToken, mintWakeId, receiptEventTime, recordWakeTail, resolveWakeTrustFromContext, shouldRotate, spreadVendorTs, stampMintedRuntime, supervisorGrainFor, tailAuthorGrain, touchDmSeat, withEndsTurnFinalChannel, } from "@open-everywhere/core/agent/adapter-api.js";
25
+ import { googleChatPolicy } from "../policy.js";
26
+ import { handleGoogleChatRequest, renderGoogleChatWake } from "./google-chat-front.js";
27
+ const ROUTE = "/eve/v1/google-chat";
28
+ /** How long a message name stays claimed — longer than Google's retry window. */
29
+ const DEDUPE_TTL_MS = 24 * 60 * 60 * 1000;
30
+ function log(msg) {
31
+ console.log(`[open-everywhere:google-chat] ${msg}`);
32
+ }
33
+ function authContext(auth) {
34
+ return { channel: { kind: "google-chat" }, session: { auth: { current: auth } } };
35
+ }
36
+ /** The tail row both seats file after the wake landed: the trigger only. */
37
+ function tailRow(plan, atIso) {
38
+ return {
39
+ kind: "wake",
40
+ at: atIso,
41
+ from: "human",
42
+ trust: plan.trigger.trust,
43
+ ...tailAuthorGrain(plan.ingested[0] ?? { trust: plan.trigger.trust }),
44
+ author: plan.trigger.author,
45
+ authorId: plan.trigger.authorId ?? "",
46
+ id: plan.trigger.id,
47
+ platform: "google-chat",
48
+ container: plan.surfaceKey,
49
+ ...(plan.origin.thread !== undefined ? { threadRoot: plan.origin.thread } : {}),
50
+ text: plan.trigger.body,
51
+ };
52
+ }
53
+ /** The ROOM dispatch: the domain's standing seat, through the shared inbound divert. */
54
+ async function liveDispatchRoom(plan, to) {
55
+ const org = deploymentOrg();
56
+ const store = getOperationalStore();
57
+ const grain = supervisorGrainFor(plan.surfaceKey, getConfig().loadDomains());
58
+ const atIso = new Date().toISOString();
59
+ const perContainer = (gen) => `google-chat:${plan.surfaceKey}:oe-sup:g${gen}`;
60
+ // OPE-599: claim the runtime-change rotation BEFORE the row read, and unconditionally.
61
+ const runtimeChanged = await claimRuntimeRotation({ org, registryKey: grain.registryKey, surfaceKey: plan.surfaceKey, domainName: grain.domainName, atIso });
62
+ const existing = await store.getChannelSession(org, grain.registryKey);
63
+ let token;
64
+ let tail = [];
65
+ if (!existing) {
66
+ const row = await store.rotateChannelSession(org, grain.registryKey, mintRotationToken(grain, 1, () => perContainer(1)), atIso);
67
+ await stampMintedRuntime({ org, registryKey: grain.registryKey, surfaceKey: plan.surfaceKey, domainName: grain.domainName, atIso });
68
+ token = row.token;
69
+ }
70
+ else if (shouldRotate(existing, atIso, { runtimeChanged })) {
71
+ const gen = existing.generation + 1;
72
+ tail = await carryTailForward(org, grain.registryKey, existing.token);
73
+ token = (await store.rotateChannelSession(org, grain.registryKey, mintRotationToken(grain, gen, () => perContainer(gen)), atIso)).token;
74
+ }
75
+ else {
76
+ token = existing.token;
77
+ }
78
+ const wakeId = mintWakeId();
79
+ const rendered = renderGoogleChatWake(plan, wakeId, tail);
80
+ const window = { wakeId, origin: plan.origin, addressing: "direct-mention", ...spreadVendorTs(receiptEventTime(Date.now())) };
81
+ await divertInboundToUnifiedWindow(to, {
82
+ message: rendered.message,
83
+ ...(rendered.context.length > 0 ? { context: rendered.context } : {}),
84
+ token,
85
+ window,
86
+ surfaceKey: plan.surfaceKey,
87
+ auth: plan.auth,
88
+ });
89
+ await store.touchChannelSession(org, grain.registryKey, atIso).catch(() => undefined);
90
+ await recordWakeTail(org, grain.registryKey, token, tailRow(plan, atIso)).catch(() => undefined);
91
+ }
92
+ /** The DM dispatch: the person's own DM seat. */
93
+ async function liveDispatchDm(plan, to) {
94
+ const org = deploymentOrg();
95
+ const atIso = new Date().toISOString();
96
+ const seat = await getOrCreateDmSeat(org, { surfaceKey: plan.surfaceKey }, atIso);
97
+ const wakeId = mintWakeId();
98
+ const rendered = renderGoogleChatWake(plan, wakeId, seat.freshGeneration ? seat.tail : undefined);
99
+ await divertToUnifiedWindow(to, {
100
+ message: rendered.message,
101
+ ...(rendered.context.length > 0 ? { context: rendered.context } : {}),
102
+ token: seat.token,
103
+ window: { wakeId, origin: plan.origin, addressing: "direct-mention", ...spreadVendorTs(receiptEventTime(Date.now())) },
104
+ // Byte-exactly the surface named inside the DM token — the privacy fence both admission gates match on.
105
+ surfaceKey: plan.surfaceKey,
106
+ auth: plan.auth,
107
+ });
108
+ await touchDmSeat(org, plan.surfaceKey, atIso).catch(() => undefined);
109
+ await recordWakeTail(org, dmWindowRegistryKey(plan.surfaceKey), seat.token, tailRow(plan, atIso)).catch(() => undefined);
110
+ }
111
+ /** The live front deps over this request's `to`. */
112
+ function liveGoogleChatFrontDeps(to) {
113
+ return {
114
+ policy: googleChatPolicy,
115
+ markSeen: (key) => getOperationalStore().markEventSeen(deploymentOrg(), key, new Date().toISOString(), DEDUPE_TTL_MS),
116
+ roomHasSeat: (surfaceKey) => {
117
+ try {
118
+ return grainUsesUnifiedWindow(supervisorGrainFor(surfaceKey, getConfig().loadDomains()));
119
+ }
120
+ catch {
121
+ return false;
122
+ }
123
+ },
124
+ wakeTrust: (auth, sender) => resolveWakeTrustFromContext(authContext(auth), { id: sender, isBot: false }, { principalFallback: true }),
125
+ dispatchRoom: (plan) => liveDispatchRoom(plan, to),
126
+ dispatchDm: (plan) => liveDispatchDm(plan, to),
127
+ audit: (row) => appendAudit({
128
+ org: deploymentOrg(),
129
+ platform: "google-chat",
130
+ workspace: row.workspace,
131
+ ...(row.surface ? { surface: row.surface } : {}),
132
+ ...(row.principalId ? { principalId: row.principalId } : {}),
133
+ action: row.action,
134
+ detail: row.detail,
135
+ }).catch(() => undefined),
136
+ };
137
+ }
138
+ const channel = defineChannel({
139
+ routes: [
140
+ POST(ROUTE, (req, { to, waitUntil }) => handleGoogleChatRequest(req, waitUntil, liveGoogleChatFrontDeps(to), {
141
+ log,
142
+ // The event was acknowledged and its name claimed, so a retry is a duplicate: this row is the only trace
143
+ // of the lost message. The error class only: an error message can carry message content.
144
+ onFailure: (err, policy) => appendAudit({
145
+ org: deploymentOrg(),
146
+ platform: "google-chat",
147
+ workspace: policy.workspace,
148
+ action: "google-chat.wake_failed",
149
+ detail: { error: auditErrorDetail(err instanceof Error ? err.name : "error").error },
150
+ })
151
+ .then(() => undefined)
152
+ .catch(() => undefined),
153
+ })),
154
+ ],
155
+ });
156
+ export default withEndsTurnFinalChannel(channel);
157
+ //# sourceMappingURL=google-chat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-chat.js","sourceRoot":"","sources":["../../../agent/channels/google-chat.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export declare const CONTRIBUTIONS: {
2
+ readonly schemaVersion: 1;
3
+ readonly package: "@open-everywhere/provider-google-chat";
4
+ readonly register: "agent/register.js#registerGoogleChatProvider";
5
+ readonly contributions: readonly [{
6
+ readonly kind: "channel";
7
+ readonly name: "google-chat";
8
+ readonly module: "agent/channels/google-chat.js";
9
+ readonly summary: "Google Chat — the agent as a Chat app: @mentions in spaces and direct messages in, threaded replies out.";
10
+ }];
11
+ };
12
+ //# sourceMappingURL=contributions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contributions.d.ts","sourceRoot":"","sources":["../../agent/contributions.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,aAAa;aACxB,aAAa,EAAE,CAAC;aAChB,OAAO,EAAE,uCAAuC;aAChD,QAAQ,EAAE,8CAA8C;aACxD,aAAa;iBAET,IAAI,EAAE,SAAS;iBAAE,IAAI,EAAE,aAAa;iBAAE,MAAM,EAAE,+BAA+B;iBAAE,OAAO,EAAE,0GAA0G;;CAE9L,CAAC"}
@@ -0,0 +1,16 @@
1
+ // THE CONTRIBUTION MANIFEST for `@open-everywhere/provider-google-chat` (OPE-2442) — the curated catalogue of
2
+ // everything this package OFFERS an app's eve slot tree. `oe build` reads it; the app's `roster.config.ts` decides
3
+ // about it, and `roster.lock.json` records the review. See packages/providers/github/agent/contributions.ts for why
4
+ // the manifest is curated, import-free data.
5
+ //
6
+ // ERASABLE SYNTAX ONLY (no `enum`, no `namespace`) — `oe build` loads this with a bare import.
7
+ export const CONTRIBUTIONS = {
8
+ schemaVersion: 1,
9
+ package: "@open-everywhere/provider-google-chat",
10
+ register: "agent/register.js#registerGoogleChatProvider",
11
+ contributions: [
12
+ // ── channels ─────────────────────────────────────────────────────────────────────────────────
13
+ { kind: "channel", name: "google-chat", module: "agent/channels/google-chat.js", summary: "Google Chat — the agent as a Chat app: @mentions in spaces and direct messages in, threaded replies out." },
14
+ ],
15
+ };
16
+ //# sourceMappingURL=contributions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contributions.js","sourceRoot":"","sources":["../../agent/contributions.ts"],"names":[],"mappings":"AAAA,8GAA8G;AAC9G,mHAAmH;AACnH,oHAAoH;AACpH,6CAA6C;AAC7C,EAAE;AACF,+FAA+F;AAE/F,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,aAAa,EAAE,CAAC;IAChB,OAAO,EAAE,uCAAuC;IAChD,QAAQ,EAAE,8CAA8C;IACxD,aAAa,EAAE;QACb,gGAAgG;QAChG,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,+BAA+B,EAAE,OAAO,EAAE,0GAA0G,EAAE;KACvM;CACO,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { DocEntry } from "@open-everywhere/core/agent/adapter-api.js";
2
+ export declare const PROVIDER_DOCS: readonly DocEntry[];
3
+ //# sourceMappingURL=docs-generated.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs-generated.d.ts","sourceRoot":"","sources":["../../agent/docs-generated.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4CAA4C,CAAC;AAE3E,eAAO,MAAM,aAAa,EAAE,SAAS,QAAQ,EAgH5C,CAAC"}