@pinet/slack-bridge 0.1.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.
- package/LICENSE +21 -0
- package/README.md +570 -0
- package/dist/activity-log.d.ts +62 -0
- package/dist/activity-log.js +293 -0
- package/dist/agent-completion-runtime.d.ts +17 -0
- package/dist/agent-completion-runtime.js +26 -0
- package/dist/agent-event-runtime.d.ts +13 -0
- package/dist/agent-event-runtime.js +27 -0
- package/dist/agent-prompt-guidance.d.ts +22 -0
- package/dist/agent-prompt-guidance.js +46 -0
- package/dist/broker/adapters/slack.d.ts +74 -0
- package/dist/broker/adapters/slack.js +563 -0
- package/dist/broker/adapters/types.d.ts +1 -0
- package/dist/broker/adapters/types.js +1 -0
- package/dist/broker/agent-messaging.d.ts +1 -0
- package/dist/broker/agent-messaging.js +1 -0
- package/dist/broker/auth.d.ts +1 -0
- package/dist/broker/auth.js +1 -0
- package/dist/broker/client.d.ts +167 -0
- package/dist/broker/client.js +624 -0
- package/dist/broker/control-plane-dashboard.d.ts +98 -0
- package/dist/broker/control-plane-dashboard.js +213 -0
- package/dist/broker/ghost-reaper.d.ts +49 -0
- package/dist/broker/ghost-reaper.js +209 -0
- package/dist/broker/index.d.ts +36 -0
- package/dist/broker/index.js +90 -0
- package/dist/broker/leader.d.ts +1 -0
- package/dist/broker/leader.js +1 -0
- package/dist/broker/maintenance.d.ts +1 -0
- package/dist/broker/maintenance.js +1 -0
- package/dist/broker/message-send.d.ts +1 -0
- package/dist/broker/message-send.js +1 -0
- package/dist/broker/paths.d.ts +1 -0
- package/dist/broker/paths.js +1 -0
- package/dist/broker/raw-tcp-loopback.d.ts +1 -0
- package/dist/broker/raw-tcp-loopback.js +1 -0
- package/dist/broker/router.d.ts +1 -0
- package/dist/broker/router.js +1 -0
- package/dist/broker/schema.d.ts +9 -0
- package/dist/broker/schema.js +63 -0
- package/dist/broker/socket-server.d.ts +120 -0
- package/dist/broker/socket-server.js +1087 -0
- package/dist/broker/types.d.ts +1 -0
- package/dist/broker/types.js +1 -0
- package/dist/broker-delivery.d.ts +10 -0
- package/dist/broker-delivery.js +26 -0
- package/dist/broker-inbound-persistence.d.ts +11 -0
- package/dist/broker-inbound-persistence.js +22 -0
- package/dist/broker-prompt-loader.d.ts +34 -0
- package/dist/broker-prompt-loader.js +185 -0
- package/dist/broker-runtime-access.d.ts +14 -0
- package/dist/broker-runtime-access.js +20 -0
- package/dist/broker-runtime.d.ts +100 -0
- package/dist/broker-runtime.js +533 -0
- package/dist/broker-thread-owner-hints.d.ts +10 -0
- package/dist/broker-thread-owner-hints.js +14 -0
- package/dist/canvases.d.ts +80 -0
- package/dist/canvases.js +221 -0
- package/dist/command-registration-runtime.d.ts +9 -0
- package/dist/command-registration-runtime.js +9 -0
- package/dist/core-tool-guardrails.d.ts +24 -0
- package/dist/core-tool-guardrails.js +66 -0
- package/dist/deploy-manifest.d.ts +27 -0
- package/dist/deploy-manifest.js +197 -0
- package/dist/follower-delivery.d.ts +16 -0
- package/dist/follower-delivery.js +70 -0
- package/dist/follower-runtime.d.ts +61 -0
- package/dist/follower-runtime.js +350 -0
- package/dist/git-metadata.d.ts +35 -0
- package/dist/git-metadata.js +88 -0
- package/dist/guardrails.d.ts +69 -0
- package/dist/guardrails.js +283 -0
- package/dist/helpers.d.ts +550 -0
- package/dist/helpers.js +2711 -0
- package/dist/home-tab.d.ts +27 -0
- package/dist/home-tab.js +242 -0
- package/dist/imessage-tools.d.ts +33 -0
- package/dist/imessage-tools.js +96 -0
- package/dist/inbox-drain-runtime.d.ts +30 -0
- package/dist/inbox-drain-runtime.js +71 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1330 -0
- package/dist/persisted-runtime-state.d.ts +52 -0
- package/dist/persisted-runtime-state.js +98 -0
- package/dist/pinet-activity-formatting.d.ts +20 -0
- package/dist/pinet-activity-formatting.js +43 -0
- package/dist/pinet-agent-status.d.ts +36 -0
- package/dist/pinet-agent-status.js +48 -0
- package/dist/pinet-commands.d.ts +70 -0
- package/dist/pinet-commands.js +402 -0
- package/dist/pinet-confirmation-replies.d.ts +7 -0
- package/dist/pinet-confirmation-replies.js +30 -0
- package/dist/pinet-control-plane-dashboard.d.ts +34 -0
- package/dist/pinet-control-plane-dashboard.js +86 -0
- package/dist/pinet-home-tabs.d.ts +36 -0
- package/dist/pinet-home-tabs.js +101 -0
- package/dist/pinet-maintenance-delivery.d.ts +22 -0
- package/dist/pinet-maintenance-delivery.js +45 -0
- package/dist/pinet-mesh-ops.d.ts +97 -0
- package/dist/pinet-mesh-ops.js +266 -0
- package/dist/pinet-registration-gate.d.ts +14 -0
- package/dist/pinet-registration-gate.js +42 -0
- package/dist/pinet-remote-control-acks.d.ts +16 -0
- package/dist/pinet-remote-control-acks.js +46 -0
- package/dist/pinet-remote-control.d.ts +17 -0
- package/dist/pinet-remote-control.js +74 -0
- package/dist/pinet-runtime-composition.d.ts +27 -0
- package/dist/pinet-runtime-composition.js +20 -0
- package/dist/pinet-tools.d.ts +67 -0
- package/dist/pinet-tools.js +1211 -0
- package/dist/prompts/broker/default.md +41 -0
- package/dist/prompts/broker/tmux.md +49 -0
- package/dist/ralph-loop.d.ts +76 -0
- package/dist/ralph-loop.js +524 -0
- package/dist/reaction-triggers.d.ts +25 -0
- package/dist/reaction-triggers.js +171 -0
- package/dist/repo-tool-guardrails.d.ts +20 -0
- package/dist/repo-tool-guardrails.js +81 -0
- package/dist/runtime-agent-context.d.ts +93 -0
- package/dist/runtime-agent-context.js +302 -0
- package/dist/runtime-mode.d.ts +10 -0
- package/dist/runtime-mode.js +39 -0
- package/dist/scheduled-wakeups.d.ts +1 -0
- package/dist/scheduled-wakeups.js +1 -0
- package/dist/session-ui-runtime.d.ts +20 -0
- package/dist/session-ui-runtime.js +163 -0
- package/dist/single-player-runtime.d.ts +71 -0
- package/dist/single-player-runtime.js +436 -0
- package/dist/skins/cosmere.json +1571 -0
- package/dist/skins/foundation.json +1304 -0
- package/dist/slack-access.d.ts +186 -0
- package/dist/slack-access.js +462 -0
- package/dist/slack-api.d.ts +2 -0
- package/dist/slack-api.js +1 -0
- package/dist/slack-block-kit.d.ts +36 -0
- package/dist/slack-block-kit.js +242 -0
- package/dist/slack-export.d.ts +31 -0
- package/dist/slack-export.js +206 -0
- package/dist/slack-message-context.d.ts +15 -0
- package/dist/slack-message-context.js +207 -0
- package/dist/slack-modals.d.ts +13 -0
- package/dist/slack-modals.js +79 -0
- package/dist/slack-pinet-runtime-adapter.d.ts +16 -0
- package/dist/slack-pinet-runtime-adapter.js +72 -0
- package/dist/slack-presence.d.ts +36 -0
- package/dist/slack-presence.js +89 -0
- package/dist/slack-request-runtime.d.ts +8 -0
- package/dist/slack-request-runtime.js +19 -0
- package/dist/slack-runtime-access.d.ts +28 -0
- package/dist/slack-runtime-access.js +107 -0
- package/dist/slack-scope-diagnostics.d.ts +31 -0
- package/dist/slack-scope-diagnostics.js +235 -0
- package/dist/slack-socket-dedup.d.ts +7 -0
- package/dist/slack-socket-dedup.js +135 -0
- package/dist/slack-thread-status.d.ts +41 -0
- package/dist/slack-thread-status.js +156 -0
- package/dist/slack-tool-policy-runtime.d.ts +36 -0
- package/dist/slack-tool-policy-runtime.js +96 -0
- package/dist/slack-tools.d.ts +52 -0
- package/dist/slack-tools.js +2688 -0
- package/dist/slack-turn-guardrails.d.ts +19 -0
- package/dist/slack-turn-guardrails.js +36 -0
- package/dist/slack-upload.d.ts +49 -0
- package/dist/slack-upload.js +224 -0
- package/dist/task-assignments.d.ts +45 -0
- package/dist/task-assignments.js +527 -0
- package/dist/thread-confirmations.d.ts +22 -0
- package/dist/thread-confirmations.js +139 -0
- package/dist/tool-registration-runtime.d.ts +13 -0
- package/dist/tool-registration-runtime.js +13 -0
- package/dist/ttl-cache.d.ts +47 -0
- package/dist/ttl-cache.js +105 -0
- package/manifest.yaml +57 -0
- package/package.json +60 -0
- package/skills/pinet-skin-creator/SKILL.md +109 -0
- package/skills/pinet-skin-creator/references/descriptor-format.md +99 -0
- package/skills/pinet-skin-creator/references/safety-checklist.md +56 -0
- package/skills/pinet-skin-creator/templates/pinet-skin-descriptor.json +77 -0
- package/skills/slack-bridge/SKILL.md +360 -0
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
// ─── Security Guardrails ─────────────────────────────────
|
|
2
|
+
/** Well-known read-only tools that are always safe */
|
|
3
|
+
export const READ_ONLY_TOOLS = new Set([
|
|
4
|
+
"read",
|
|
5
|
+
"rg",
|
|
6
|
+
"slack",
|
|
7
|
+
"slack_inbox",
|
|
8
|
+
"slack_send",
|
|
9
|
+
"slack:help",
|
|
10
|
+
"slack:read",
|
|
11
|
+
"slack:read_channel",
|
|
12
|
+
"slack:export",
|
|
13
|
+
"slack:presence",
|
|
14
|
+
"slack:canvas_comments_read",
|
|
15
|
+
"slack:confirm_action",
|
|
16
|
+
"pinet:agents",
|
|
17
|
+
"pinet:read",
|
|
18
|
+
"memory_read",
|
|
19
|
+
"memory_search",
|
|
20
|
+
"memory_list",
|
|
21
|
+
"memory_check",
|
|
22
|
+
]);
|
|
23
|
+
/** Well-known write tools (used when readOnly mode is active) */
|
|
24
|
+
export const WRITE_TOOLS = new Set([
|
|
25
|
+
"bash",
|
|
26
|
+
"edit",
|
|
27
|
+
"write",
|
|
28
|
+
"comment_add",
|
|
29
|
+
"comment_wipe_all",
|
|
30
|
+
"memory_write",
|
|
31
|
+
"memory_sync",
|
|
32
|
+
"memory_init",
|
|
33
|
+
"slack:create_channel",
|
|
34
|
+
"slack:project_create",
|
|
35
|
+
"slack:post_channel",
|
|
36
|
+
"slack:delete",
|
|
37
|
+
"slack:upload",
|
|
38
|
+
"slack:schedule",
|
|
39
|
+
"slack:pin",
|
|
40
|
+
"slack:bookmark",
|
|
41
|
+
"slack:react",
|
|
42
|
+
"slack:canvas_create",
|
|
43
|
+
"slack:canvas_update",
|
|
44
|
+
"slack:modal_open",
|
|
45
|
+
"slack:modal_push",
|
|
46
|
+
"slack:modal_update",
|
|
47
|
+
"pinet:schedule",
|
|
48
|
+
"pinet:send",
|
|
49
|
+
"pinet:snooze",
|
|
50
|
+
"pinet:free",
|
|
51
|
+
"pinet:ports",
|
|
52
|
+
"pinet:reload",
|
|
53
|
+
"pinet:exit",
|
|
54
|
+
]);
|
|
55
|
+
/**
|
|
56
|
+
* Match a tool name against glob patterns (supports `*` wildcard).
|
|
57
|
+
* Slack and Pinet dispatcher actions use `<namespace>:<action>` names; legacy
|
|
58
|
+
* `<namespace>_<action>` guardrail patterns still match during migration. Pinet
|
|
59
|
+
* direct tools are no longer registered, but keeping alias matching prevents old
|
|
60
|
+
* security configs from silently failing open.
|
|
61
|
+
* Returns true if the tool name matches any of the patterns.
|
|
62
|
+
*/
|
|
63
|
+
export function matchesToolPattern(toolName, patterns) {
|
|
64
|
+
const candidates = new Set([toolName]);
|
|
65
|
+
if (toolName.startsWith("slack:")) {
|
|
66
|
+
candidates.add(`slack_${toolName.slice("slack:".length)}`);
|
|
67
|
+
}
|
|
68
|
+
else if (toolName.startsWith("slack_")) {
|
|
69
|
+
candidates.add(`slack:${toolName.slice("slack_".length)}`);
|
|
70
|
+
}
|
|
71
|
+
if (toolName.startsWith("pinet:")) {
|
|
72
|
+
candidates.add(`pinet_${toolName.slice("pinet:".length)}`);
|
|
73
|
+
}
|
|
74
|
+
else if (toolName.startsWith("pinet_")) {
|
|
75
|
+
candidates.add(`pinet:${toolName.slice("pinet_".length)}`);
|
|
76
|
+
}
|
|
77
|
+
if (toolName === "pinet_message" || toolName === "pinet:send" || toolName === "pinet_send") {
|
|
78
|
+
candidates.add("pinet_message");
|
|
79
|
+
candidates.add("pinet:send");
|
|
80
|
+
candidates.add("pinet_send");
|
|
81
|
+
}
|
|
82
|
+
for (const pattern of patterns) {
|
|
83
|
+
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
|
84
|
+
const re = new RegExp(`^${escaped}$`);
|
|
85
|
+
for (const candidate of candidates) {
|
|
86
|
+
if (re.test(candidate))
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Check if a tool is blocked by the guardrails.
|
|
94
|
+
* Returns true if:
|
|
95
|
+
* - tool matches any blockedTools pattern
|
|
96
|
+
* - guardrails.readOnly is true AND tool is in WRITE_TOOLS
|
|
97
|
+
*/
|
|
98
|
+
export function isToolBlocked(toolName, guardrails) {
|
|
99
|
+
if (guardrails.blockedTools?.length && matchesToolPattern(toolName, guardrails.blockedTools)) {
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
if (!guardrails.readOnly) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
const readOnlyCandidates = new Set([toolName]);
|
|
106
|
+
if (toolName.startsWith("slack:")) {
|
|
107
|
+
readOnlyCandidates.add(`slack_${toolName.slice("slack:".length)}`);
|
|
108
|
+
}
|
|
109
|
+
else if (toolName.startsWith("slack_")) {
|
|
110
|
+
readOnlyCandidates.add(`slack:${toolName.slice("slack_".length)}`);
|
|
111
|
+
}
|
|
112
|
+
if (toolName.startsWith("pinet:")) {
|
|
113
|
+
readOnlyCandidates.add(`pinet_${toolName.slice("pinet:".length)}`);
|
|
114
|
+
}
|
|
115
|
+
else if (toolName.startsWith("pinet_")) {
|
|
116
|
+
readOnlyCandidates.add(`pinet:${toolName.slice("pinet_".length)}`);
|
|
117
|
+
}
|
|
118
|
+
if (toolName === "pinet_message" || toolName === "pinet:send" || toolName === "pinet_send") {
|
|
119
|
+
readOnlyCandidates.add("pinet_message");
|
|
120
|
+
readOnlyCandidates.add("pinet:send");
|
|
121
|
+
readOnlyCandidates.add("pinet_send");
|
|
122
|
+
}
|
|
123
|
+
for (const candidate of readOnlyCandidates) {
|
|
124
|
+
if (WRITE_TOOLS.has(candidate)) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Check if a tool needs confirmation.
|
|
132
|
+
* Returns true if tool matches any requireConfirmation pattern.
|
|
133
|
+
* Returns false if tool is already blocked (blocked takes priority).
|
|
134
|
+
*/
|
|
135
|
+
export function toolNeedsConfirmation(toolName, guardrails) {
|
|
136
|
+
if (isToolBlocked(toolName, guardrails))
|
|
137
|
+
return false;
|
|
138
|
+
if (guardrails.requireConfirmation?.length &&
|
|
139
|
+
matchesToolPattern(toolName, guardrails.requireConfirmation)) {
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Build security instructions to prepend to Slack-triggered messages.
|
|
146
|
+
* Returns a clear, structured prompt with active guardrails.
|
|
147
|
+
* Returns empty string if no guardrails are active.
|
|
148
|
+
*/
|
|
149
|
+
export function hasEffectivelyEmptyRuntimeGuardrails(guardrails) {
|
|
150
|
+
return (guardrails?.readOnly !== true &&
|
|
151
|
+
(guardrails?.blockedTools?.length ?? 0) === 0 &&
|
|
152
|
+
(guardrails?.requireConfirmation?.length ?? 0) === 0);
|
|
153
|
+
}
|
|
154
|
+
export function formatRuntimeGuardrailsPosture(guardrails) {
|
|
155
|
+
if (hasEffectivelyEmptyRuntimeGuardrails(guardrails)) {
|
|
156
|
+
return "empty (warn-first posture; behavior unchanged)";
|
|
157
|
+
}
|
|
158
|
+
const sections = [];
|
|
159
|
+
if (guardrails?.readOnly === true) {
|
|
160
|
+
sections.push("readOnly");
|
|
161
|
+
}
|
|
162
|
+
const blockedCount = guardrails?.blockedTools?.length ?? 0;
|
|
163
|
+
if (blockedCount > 0) {
|
|
164
|
+
sections.push(`blockedTools:${blockedCount}`);
|
|
165
|
+
}
|
|
166
|
+
const confirmationCount = guardrails?.requireConfirmation?.length ?? 0;
|
|
167
|
+
if (confirmationCount > 0) {
|
|
168
|
+
sections.push(`requireConfirmation:${confirmationCount}`);
|
|
169
|
+
}
|
|
170
|
+
return sections.length > 0 ? `configured (${sections.join(", ")})` : "configured";
|
|
171
|
+
}
|
|
172
|
+
export function getEmptyRuntimeGuardrailsWarning(guardrails) {
|
|
173
|
+
if (!hasEffectivelyEmptyRuntimeGuardrails(guardrails)) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
return [
|
|
177
|
+
"Slack/Pinet access is enabled for admitted users, but runtime guardrails are effectively empty.",
|
|
178
|
+
"Configure slack-bridge.security.readOnly, security.blockedTools, or security.requireConfirmation if you want runtime restrictions for Slack-triggered turns.",
|
|
179
|
+
"This warning is visibility-only; current runtime behavior is unchanged.",
|
|
180
|
+
].join(" ");
|
|
181
|
+
}
|
|
182
|
+
export function buildSecurityPrompt(guardrails) {
|
|
183
|
+
const sections = [];
|
|
184
|
+
const hasReadOnly = guardrails.readOnly === true;
|
|
185
|
+
const hasBlocked = (guardrails.blockedTools?.length ?? 0) > 0;
|
|
186
|
+
const hasConfirmation = (guardrails.requireConfirmation?.length ?? 0) > 0;
|
|
187
|
+
if (hasEffectivelyEmptyRuntimeGuardrails(guardrails))
|
|
188
|
+
return "";
|
|
189
|
+
sections.push("⚠️ SECURITY GUARDRAILS — Slack-triggered action restrictions:");
|
|
190
|
+
if (hasReadOnly) {
|
|
191
|
+
const allowed = [...READ_ONLY_TOOLS].join(", ");
|
|
192
|
+
sections.push([
|
|
193
|
+
"🔒 READ-ONLY MODE is active.",
|
|
194
|
+
`You MUST NOT use any write tools (${[...WRITE_TOOLS].join(", ")}).`,
|
|
195
|
+
`Only these tools are allowed: ${allowed}.`,
|
|
196
|
+
"If a request requires writing files or modifying state, explain that read-only mode is active and the action cannot be performed via Slack.",
|
|
197
|
+
].join("\n"));
|
|
198
|
+
}
|
|
199
|
+
if (hasBlocked) {
|
|
200
|
+
sections.push([
|
|
201
|
+
"🚫 BLOCKED TOOLS:",
|
|
202
|
+
`The following tool patterns are completely blocked: ${guardrails.blockedTools.join(", ")}.`,
|
|
203
|
+
"Do NOT use any tool matching these patterns. If a request requires a blocked tool, inform the user it is not available via Slack.",
|
|
204
|
+
].join("\n"));
|
|
205
|
+
}
|
|
206
|
+
if (hasConfirmation) {
|
|
207
|
+
sections.push([
|
|
208
|
+
"✋ CONFIRMATION REQUIRED:",
|
|
209
|
+
`Before using tools matching these patterns: [${guardrails.requireConfirmation.join(", ")}], you MUST first call slack with action "confirm_action" and args containing thread_ts, the exact action string required by the guarded tool, and the tool name (for dispatcher actions, use slack:<action> or pinet:<action>).`,
|
|
210
|
+
"Wait for the user's response via slack_inbox. Only proceed if the user approves. If denied, inform the user and skip the action.",
|
|
211
|
+
].join("\n"));
|
|
212
|
+
}
|
|
213
|
+
return sections.join("\n\n");
|
|
214
|
+
}
|
|
215
|
+
// ─── Broker Role Guardrails ──────────────────────────────
|
|
216
|
+
/**
|
|
217
|
+
* Tools that the broker agent must NEVER use.
|
|
218
|
+
* The broker is infrastructure — it coordinates, not codes.
|
|
219
|
+
* Spawning local subagents (Agent) is forbidden because they
|
|
220
|
+
* have no Slack/Pinet connectivity and can't be monitored.
|
|
221
|
+
* Direct file mutation tools are also blocked so the runtime
|
|
222
|
+
* enforces the coordination-only role even if prompt guidance drifts.
|
|
223
|
+
*/
|
|
224
|
+
export const BROKER_FORBIDDEN_TOOLS = new Set(["Agent", "edit", "write"]);
|
|
225
|
+
/**
|
|
226
|
+
* Check if a tool is forbidden for the broker role.
|
|
227
|
+
* Returns true if the broker must not use this tool.
|
|
228
|
+
*/
|
|
229
|
+
export function isBrokerForbiddenTool(toolName) {
|
|
230
|
+
return BROKER_FORBIDDEN_TOOLS.has(toolName);
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Build a prompt snippet describing broker tool restrictions.
|
|
234
|
+
* Injected into the system prompt when the broker role is active.
|
|
235
|
+
*/
|
|
236
|
+
export function buildBrokerToolGuardrailsPrompt() {
|
|
237
|
+
const forbidden = [...BROKER_FORBIDDEN_TOOLS].join(", ");
|
|
238
|
+
return [
|
|
239
|
+
"🚫 BROKER TOOL RESTRICTION:",
|
|
240
|
+
`The following tools are BLOCKED for the broker role: ${forbidden}.`,
|
|
241
|
+
"The Agent tool (including code-reviewer and other local subagents) spawns local workers with no Slack/Pinet connectivity — they can't be monitored, can't own threads, and can't coordinate with humans.",
|
|
242
|
+
"The edit and write tools are blocked because the broker is coordination infrastructure, not an implementation worker.",
|
|
243
|
+
"Use pinet action=send to delegate coding or review work to connected Pinet agents instead.",
|
|
244
|
+
].join("\n");
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Parse whether a user message is approving a confirmation request.
|
|
248
|
+
* Case-insensitive, trimmed.
|
|
249
|
+
*/
|
|
250
|
+
export function isConfirmationApproval(text) {
|
|
251
|
+
const APPROVALS = new Set([
|
|
252
|
+
"yes",
|
|
253
|
+
"approve",
|
|
254
|
+
"approved",
|
|
255
|
+
"confirm",
|
|
256
|
+
"confirmed",
|
|
257
|
+
"go ahead",
|
|
258
|
+
"proceed",
|
|
259
|
+
"y",
|
|
260
|
+
"ok",
|
|
261
|
+
"\u{1F44D}",
|
|
262
|
+
]);
|
|
263
|
+
return APPROVALS.has(text.trim().toLowerCase());
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Parse whether a user message is rejecting a confirmation request.
|
|
267
|
+
* Case-insensitive, trimmed.
|
|
268
|
+
*/
|
|
269
|
+
export function isConfirmationRejection(text) {
|
|
270
|
+
const REJECTIONS = new Set([
|
|
271
|
+
"no",
|
|
272
|
+
"deny",
|
|
273
|
+
"denied",
|
|
274
|
+
"reject",
|
|
275
|
+
"rejected",
|
|
276
|
+
"cancel",
|
|
277
|
+
"abort",
|
|
278
|
+
"stop",
|
|
279
|
+
"n",
|
|
280
|
+
"\u{1F44E}",
|
|
281
|
+
]);
|
|
282
|
+
return REJECTIONS.has(text.trim().toLowerCase());
|
|
283
|
+
}
|