paperclip-plugin-google-chat 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -0
- package/dist/constants.d.ts +9 -5
- package/dist/constants.js +9 -5
- package/dist/events.js +10 -4
- package/dist/manifest.d.ts +5 -162
- package/dist/manifest.js +4 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -73,6 +73,23 @@ src/
|
|
|
73
73
|
|
|
74
74
|
Pure logic (formatting, parsing, routing, validation) is separated from the SDK-facing worker so it is unit-tested without a running Paperclip (`tests/`).
|
|
75
75
|
|
|
76
|
+
## Adapter compatibility (important)
|
|
77
|
+
|
|
78
|
+
The plugin's **worker-side** features work with **any** adapter, because they run in the
|
|
79
|
+
plugin worker, not the agent:
|
|
80
|
+
|
|
81
|
+
- ✅ **Event notifications** (`events.subscribe` → Chat)
|
|
82
|
+
- ✅ **Inbound slash commands** (`webhooks.receive`)
|
|
83
|
+
- ✅ **Daily digest job** (`jobs.schedule`)
|
|
84
|
+
|
|
85
|
+
The **agent tools** (`post_to_google_chat`, `escalate_to_human`, `send_briefing`) are only
|
|
86
|
+
callable by adapters whose tool calls are routed **through Paperclip's tool dispatcher**. They
|
|
87
|
+
are **not available to `claude_local` / `codex_local` "process" adapters**, which run the CLI
|
|
88
|
+
(e.g. `claude -p`) as a black-box subprocess — Paperclip captures stdout but never sees the
|
|
89
|
+
agent's individual tool calls, so plugin tools can't be surfaced to them. For a CLI-based
|
|
90
|
+
fleet, drive Chat via the event/webhook features above, or give the agent its own posting
|
|
91
|
+
mechanism (an MCP server, or a direct webhook `curl`).
|
|
92
|
+
|
|
76
93
|
## Develop
|
|
77
94
|
|
|
78
95
|
```bash
|
package/dist/constants.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* the same convention).
|
|
5
5
|
*/
|
|
6
6
|
export declare const PLUGIN_ID = "google-chat";
|
|
7
|
-
export declare const PLUGIN_VERSION = "0.1.
|
|
7
|
+
export declare const PLUGIN_VERSION = "0.1.2";
|
|
8
8
|
/** Webhook endpoint keys declared in the manifest and matched in `onWebhook`. */
|
|
9
9
|
export declare const WEBHOOK_KEYS: {
|
|
10
10
|
/** Google Chat app events (MESSAGE, ADDED_TO_SPACE, CARD_CLICKED, …) POST here. */
|
|
@@ -21,13 +21,17 @@ export declare const JOB_KEYS: {
|
|
|
21
21
|
readonly dailyDigest: "daily-digest";
|
|
22
22
|
};
|
|
23
23
|
/**
|
|
24
|
-
* Domain events we translate into Google Chat notifications.
|
|
25
|
-
*
|
|
24
|
+
* Domain events we translate into Google Chat notifications. These are exact
|
|
25
|
+
* members of the host's `PLUGIN_EVENT_TYPES` catalog (@paperclipai/shared),
|
|
26
|
+
* verified against the deployed release. The host has NO `issue.completed` or
|
|
27
|
+
* `approval.requested`: completion is an `issue.updated` to a terminal status,
|
|
28
|
+
* and an approval request is `approval.created`.
|
|
26
29
|
*/
|
|
27
30
|
export declare const DOMAIN_EVENTS: {
|
|
28
31
|
readonly issueCreated: "issue.created";
|
|
29
32
|
readonly issueUpdated: "issue.updated";
|
|
30
|
-
readonly
|
|
31
|
-
readonly approvalRequested: "approval.requested";
|
|
33
|
+
readonly approvalCreated: "approval.created";
|
|
32
34
|
readonly agentRunFailed: "agent.run.failed";
|
|
33
35
|
};
|
|
36
|
+
/** Issue statuses treated as "completed" for notification purposes. */
|
|
37
|
+
export declare const TERMINAL_ISSUE_STATUSES: Set<string>;
|
package/dist/constants.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* the same convention).
|
|
5
5
|
*/
|
|
6
6
|
export const PLUGIN_ID = "google-chat";
|
|
7
|
-
export const PLUGIN_VERSION = "0.1.
|
|
7
|
+
export const PLUGIN_VERSION = "0.1.2";
|
|
8
8
|
/** Webhook endpoint keys declared in the manifest and matched in `onWebhook`. */
|
|
9
9
|
export const WEBHOOK_KEYS = {
|
|
10
10
|
/** Google Chat app events (MESSAGE, ADDED_TO_SPACE, CARD_CLICKED, …) POST here. */
|
|
@@ -21,13 +21,17 @@ export const JOB_KEYS = {
|
|
|
21
21
|
dailyDigest: "daily-digest",
|
|
22
22
|
};
|
|
23
23
|
/**
|
|
24
|
-
* Domain events we translate into Google Chat notifications.
|
|
25
|
-
*
|
|
24
|
+
* Domain events we translate into Google Chat notifications. These are exact
|
|
25
|
+
* members of the host's `PLUGIN_EVENT_TYPES` catalog (@paperclipai/shared),
|
|
26
|
+
* verified against the deployed release. The host has NO `issue.completed` or
|
|
27
|
+
* `approval.requested`: completion is an `issue.updated` to a terminal status,
|
|
28
|
+
* and an approval request is `approval.created`.
|
|
26
29
|
*/
|
|
27
30
|
export const DOMAIN_EVENTS = {
|
|
28
31
|
issueCreated: "issue.created",
|
|
29
32
|
issueUpdated: "issue.updated",
|
|
30
|
-
|
|
31
|
-
approvalRequested: "approval.requested",
|
|
33
|
+
approvalCreated: "approval.created",
|
|
32
34
|
agentRunFailed: "agent.run.failed",
|
|
33
35
|
};
|
|
36
|
+
/** Issue statuses treated as "completed" for notification purposes. */
|
|
37
|
+
export const TERMINAL_ISSUE_STATUSES = new Set(["done", "completed", "closed"]);
|
package/dist/events.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* gated by the per-event config toggles. The mapping is pure so it can be tested
|
|
7
7
|
* without the SDK; the worker performs the actual `postToWebhook`.
|
|
8
8
|
*/
|
|
9
|
-
import { DOMAIN_EVENTS } from "./constants.js";
|
|
9
|
+
import { DOMAIN_EVENTS, TERMINAL_ISSUE_STATUSES } from "./constants.js";
|
|
10
10
|
import { formatAgentRunFailed, formatApprovalRequested, formatIssueCompleted, formatIssueCreated, } from "./google-chat.js";
|
|
11
11
|
function asIssue(data) {
|
|
12
12
|
const d = data ?? {};
|
|
@@ -27,11 +27,17 @@ export function mapEventToNotification(event, config) {
|
|
|
27
27
|
if (!config.notifyOnIssueCreated)
|
|
28
28
|
return null;
|
|
29
29
|
return { routeKey: "default", text: formatIssueCreated(asIssue(event.data)) };
|
|
30
|
-
case DOMAIN_EVENTS.
|
|
30
|
+
case DOMAIN_EVENTS.issueUpdated: {
|
|
31
|
+
// The host has no `issue.completed`; completion surfaces as an update to a
|
|
32
|
+
// terminal status. Only notify on that transition, not every edit.
|
|
31
33
|
if (!config.notifyOnIssueCompleted)
|
|
32
34
|
return null;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
const issue = asIssue(event.data);
|
|
36
|
+
if (!issue.status || !TERMINAL_ISSUE_STATUSES.has(issue.status.toLowerCase()))
|
|
37
|
+
return null;
|
|
38
|
+
return { routeKey: "default", text: formatIssueCompleted(issue) };
|
|
39
|
+
}
|
|
40
|
+
case DOMAIN_EVENTS.approvalCreated:
|
|
35
41
|
if (!config.notifyOnApprovalRequested)
|
|
36
42
|
return null;
|
|
37
43
|
return { routeKey: "approvals", text: formatApprovalRequested(asIssue(event.data)) };
|
package/dist/manifest.d.ts
CHANGED
|
@@ -1,167 +1,10 @@
|
|
|
1
|
+
import type { PaperclipPluginManifestV1 } from "@paperclipai/plugin-sdk";
|
|
1
2
|
/**
|
|
2
3
|
* Paperclip plugin manifest (apiVersion 1). Declares the capability grants the
|
|
3
4
|
* host enforces and the surfaces the worker registers. Keep capabilities minimal —
|
|
4
|
-
* the host blocks any API call whose capability is not declared here.
|
|
5
|
+
* the host blocks any API call whose capability is not declared here. The
|
|
6
|
+
* PaperclipPluginManifestV1 annotation makes tsc validate field names against the
|
|
7
|
+
* host schema (e.g. jobs[].jobKey), so manifest drift fails the build, not install.
|
|
5
8
|
*/
|
|
6
|
-
declare const manifest:
|
|
7
|
-
readonly id: "google-chat";
|
|
8
|
-
readonly apiVersion: 1;
|
|
9
|
-
readonly version: "0.1.0";
|
|
10
|
-
readonly displayName: "Google Chat";
|
|
11
|
-
readonly description: "Bidirectional Google Chat bridge: posts issue/agent/approval notifications to spaces and drives Paperclip from Chat slash commands.";
|
|
12
|
-
readonly author: "Measured Assets";
|
|
13
|
-
readonly categories: readonly ["connector", "automation"];
|
|
14
|
-
readonly capabilities: readonly ["companies.read", "projects.read", "issues.read", "issues.create", "issues.update", "issue.comments.read", "issue.comments.create", "agents.read", "agents.invoke", "agent.sessions.create", "agent.sessions.send", "goals.read", "events.subscribe", "jobs.schedule", "http.outbound", "secrets.read-ref", "webhooks.receive", "agent.tools.register", "activity.log.write", "plugin.state.read", "plugin.state.write", "instance.settings.register"];
|
|
15
|
-
readonly entrypoints: {
|
|
16
|
-
readonly worker: "./dist/worker.js";
|
|
17
|
-
};
|
|
18
|
-
readonly instanceConfigSchema: {
|
|
19
|
-
readonly type: "object";
|
|
20
|
-
readonly properties: {
|
|
21
|
-
readonly defaultWebhookUrlRef: {
|
|
22
|
-
readonly type: "string";
|
|
23
|
-
readonly title: "Default space webhook (secret ref)";
|
|
24
|
-
readonly description: "Secret reference to a Google Chat incoming-webhook URL. Create the secret in Paperclip, paste the returned UUID here.";
|
|
25
|
-
};
|
|
26
|
-
readonly approvalsWebhookUrlRef: {
|
|
27
|
-
readonly type: "string";
|
|
28
|
-
readonly title: "Approvals space webhook (secret ref)";
|
|
29
|
-
};
|
|
30
|
-
readonly errorsWebhookUrlRef: {
|
|
31
|
-
readonly type: "string";
|
|
32
|
-
readonly title: "Errors space webhook (secret ref)";
|
|
33
|
-
};
|
|
34
|
-
readonly digestWebhookUrlRef: {
|
|
35
|
-
readonly type: "string";
|
|
36
|
-
readonly title: "Digest space webhook (secret ref)";
|
|
37
|
-
};
|
|
38
|
-
readonly serviceAccountKeyRef: {
|
|
39
|
-
readonly type: "string";
|
|
40
|
-
readonly title: "Service-account key (secret ref, optional)";
|
|
41
|
-
readonly description: "Only required for the Chat REST API (threaded replies). Webhook-only mode leaves this blank.";
|
|
42
|
-
};
|
|
43
|
-
readonly notifyOnIssueCreated: {
|
|
44
|
-
readonly type: "boolean";
|
|
45
|
-
readonly title: "Notify on issue created";
|
|
46
|
-
readonly default: false;
|
|
47
|
-
};
|
|
48
|
-
readonly notifyOnIssueCompleted: {
|
|
49
|
-
readonly type: "boolean";
|
|
50
|
-
readonly title: "Notify on issue completed";
|
|
51
|
-
readonly default: true;
|
|
52
|
-
};
|
|
53
|
-
readonly notifyOnApprovalRequested: {
|
|
54
|
-
readonly type: "boolean";
|
|
55
|
-
readonly title: "Notify on approval requested";
|
|
56
|
-
readonly default: true;
|
|
57
|
-
};
|
|
58
|
-
readonly notifyOnAgentRunFailed: {
|
|
59
|
-
readonly type: "boolean";
|
|
60
|
-
readonly title: "Notify on agent run failed";
|
|
61
|
-
readonly default: true;
|
|
62
|
-
};
|
|
63
|
-
readonly useCards: {
|
|
64
|
-
readonly type: "boolean";
|
|
65
|
-
readonly title: "Use Cards v2 formatting";
|
|
66
|
-
readonly default: false;
|
|
67
|
-
};
|
|
68
|
-
readonly enableCommands: {
|
|
69
|
-
readonly type: "boolean";
|
|
70
|
-
readonly title: "Enable inbound slash commands";
|
|
71
|
-
readonly default: true;
|
|
72
|
-
};
|
|
73
|
-
readonly verificationTokenRef: {
|
|
74
|
-
readonly type: "string";
|
|
75
|
-
readonly title: "Verification token (secret ref)";
|
|
76
|
-
};
|
|
77
|
-
readonly allowedSpaceIds: {
|
|
78
|
-
readonly type: "array";
|
|
79
|
-
readonly title: "Allowed space IDs";
|
|
80
|
-
readonly items: {
|
|
81
|
-
readonly type: "string";
|
|
82
|
-
};
|
|
83
|
-
};
|
|
84
|
-
readonly allowedUserEmails: {
|
|
85
|
-
readonly type: "array";
|
|
86
|
-
readonly title: "Allowed user emails";
|
|
87
|
-
readonly items: {
|
|
88
|
-
readonly type: "string";
|
|
89
|
-
};
|
|
90
|
-
};
|
|
91
|
-
readonly digestMode: {
|
|
92
|
-
readonly type: "boolean";
|
|
93
|
-
readonly title: "Enable daily digest";
|
|
94
|
-
readonly default: false;
|
|
95
|
-
};
|
|
96
|
-
readonly dailyDigestTime: {
|
|
97
|
-
readonly type: "string";
|
|
98
|
-
readonly title: "Daily digest time (HH:MM)";
|
|
99
|
-
readonly default: "08:00";
|
|
100
|
-
};
|
|
101
|
-
};
|
|
102
|
-
};
|
|
103
|
-
readonly webhooks: readonly [{
|
|
104
|
-
readonly endpointKey: "chat-events";
|
|
105
|
-
readonly displayName: "Google Chat events";
|
|
106
|
-
readonly description: "Configure your Google Chat app's HTTP endpoint to POST events here (MESSAGE, ADDED_TO_SPACE, CARD_CLICKED).";
|
|
107
|
-
}];
|
|
108
|
-
readonly jobs: readonly [{
|
|
109
|
-
readonly key: "daily-digest";
|
|
110
|
-
readonly displayName: "Daily digest";
|
|
111
|
-
readonly description: "Posts a once-daily summary to the digest space when digestMode is enabled.";
|
|
112
|
-
readonly schedule: "0 * * * *";
|
|
113
|
-
}];
|
|
114
|
-
readonly tools: readonly [{
|
|
115
|
-
readonly name: "post_to_google_chat";
|
|
116
|
-
readonly displayName: "Post to Google Chat";
|
|
117
|
-
readonly description: "Post a plain-text or Markdown message to a configured Google Chat space.";
|
|
118
|
-
readonly parametersSchema: {
|
|
119
|
-
readonly type: "object";
|
|
120
|
-
readonly properties: {
|
|
121
|
-
readonly text: {
|
|
122
|
-
readonly type: "string";
|
|
123
|
-
readonly description: "Message body (Google Chat Markdown supported).";
|
|
124
|
-
};
|
|
125
|
-
readonly space: {
|
|
126
|
-
readonly type: "string";
|
|
127
|
-
readonly description: "Optional routing key: default | approvals | errors | digest. Defaults to 'default'.";
|
|
128
|
-
};
|
|
129
|
-
};
|
|
130
|
-
readonly required: readonly ["text"];
|
|
131
|
-
};
|
|
132
|
-
}, {
|
|
133
|
-
readonly name: "escalate_to_human";
|
|
134
|
-
readonly displayName: "Escalate to human (Google Chat)";
|
|
135
|
-
readonly description: "Post an escalation message to the approvals space and ask a human to respond.";
|
|
136
|
-
readonly parametersSchema: {
|
|
137
|
-
readonly type: "object";
|
|
138
|
-
readonly properties: {
|
|
139
|
-
readonly message: {
|
|
140
|
-
readonly type: "string";
|
|
141
|
-
};
|
|
142
|
-
readonly issueId: {
|
|
143
|
-
readonly type: "string";
|
|
144
|
-
readonly description: "Optional Paperclip issue id for context.";
|
|
145
|
-
};
|
|
146
|
-
};
|
|
147
|
-
readonly required: readonly ["message"];
|
|
148
|
-
};
|
|
149
|
-
}, {
|
|
150
|
-
readonly name: "send_briefing";
|
|
151
|
-
readonly displayName: "Send briefing (Google Chat)";
|
|
152
|
-
readonly description: "Post a formatted briefing/report to the digest space (used by scheduled briefing routines).";
|
|
153
|
-
readonly parametersSchema: {
|
|
154
|
-
readonly type: "object";
|
|
155
|
-
readonly properties: {
|
|
156
|
-
readonly title: {
|
|
157
|
-
readonly type: "string";
|
|
158
|
-
};
|
|
159
|
-
readonly body: {
|
|
160
|
-
readonly type: "string";
|
|
161
|
-
};
|
|
162
|
-
};
|
|
163
|
-
readonly required: readonly ["body"];
|
|
164
|
-
};
|
|
165
|
-
}];
|
|
166
|
-
};
|
|
9
|
+
declare const manifest: PaperclipPluginManifestV1;
|
|
167
10
|
export default manifest;
|
package/dist/manifest.js
CHANGED
|
@@ -3,7 +3,9 @@ import { JOB_KEYS, PLUGIN_ID, PLUGIN_VERSION, TOOL_NAMES, WEBHOOK_KEYS } from ".
|
|
|
3
3
|
/**
|
|
4
4
|
* Paperclip plugin manifest (apiVersion 1). Declares the capability grants the
|
|
5
5
|
* host enforces and the surfaces the worker registers. Keep capabilities minimal —
|
|
6
|
-
* the host blocks any API call whose capability is not declared here.
|
|
6
|
+
* the host blocks any API call whose capability is not declared here. The
|
|
7
|
+
* PaperclipPluginManifestV1 annotation makes tsc validate field names against the
|
|
8
|
+
* host schema (e.g. jobs[].jobKey), so manifest drift fails the build, not install.
|
|
7
9
|
*/
|
|
8
10
|
const manifest = {
|
|
9
11
|
id: PLUGIN_ID,
|
|
@@ -55,7 +57,7 @@ const manifest = {
|
|
|
55
57
|
],
|
|
56
58
|
jobs: [
|
|
57
59
|
{
|
|
58
|
-
|
|
60
|
+
jobKey: JOB_KEYS.dailyDigest,
|
|
59
61
|
displayName: "Daily digest",
|
|
60
62
|
description: "Posts a once-daily summary to the digest space when digestMode is enabled.",
|
|
61
63
|
// Hourly tick; the handler self-gates to the configured HH:MM.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "paperclip-plugin-google-chat",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Bidirectional Google Chat integration for Paperclip — post agent/issue notifications to spaces and drive Paperclip from Chat slash commands.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|