@pushary/agent-hooks 0.87.0 → 0.87.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.
- package/CHANGELOG.md +9 -0
- package/data/SKILL.md +31 -11
- package/data/cursor-plugin/.cursor-plugin/plugin.json +1 -1
- package/data/cursor-plugin/rules/pushary.mdc +2 -2
- package/data/cursor-plugin/skills/pushary/SKILL.md +30 -10
- package/data/vscode-plugin/.claude-plugin/plugin.json +1 -1
- package/data/vscode-plugin/skills/pushary/SKILL.md +30 -10
- package/dist/bin/pushary-clean.js +1 -1
- package/dist/bin/pushary-doctor.js +1 -1
- package/dist/bin/pushary-setup.js +1 -1
- package/dist/{chunk-IWL5LWIE.js → chunk-LT2VLPUK.js} +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.87.1
|
|
4
|
+
|
|
5
|
+
### Unanswered approvals hand off once and fail closed
|
|
6
|
+
|
|
7
|
+
The installed agent instructions now distinguish a live timeout from cancelled,
|
|
8
|
+
missing and unavailable questions. They poll once, cancel before moving the
|
|
9
|
+
decision into the current client, reconcile the cancellation race once, and stop
|
|
10
|
+
when Pushary cannot safely fence the question state.
|
|
11
|
+
|
|
3
12
|
## 0.86.0
|
|
4
13
|
|
|
5
14
|
### Approving a plan from your phone
|
package/data/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pushary
|
|
3
|
-
version: 0.9.
|
|
3
|
+
version: 0.9.3
|
|
4
4
|
description: Push notifications and human-in-the-loop for AI agents. Use this whenever a running agent needs a human and nobody is at the terminal, such as before an irreversible or destructive action, before spending money, deploying, force-pushing or deleting, when blocked on a decision outside your authority, when running unattended and you hit a genuine ambiguity, when another skill's workflow says to confirm with the user, and when a long task finishes or fails with nobody watching. Also use it when the user says things like keep going and ping me on my phone if you need anything, notify me when my agent needs me, approve from my phone, ask me questions while I am away from the terminal, run this overnight, keep working while I am in a meeting, I am stepping away, do not wait for me, or wants a long task to run unattended. Send alerts when tasks finish or fail, ask questions (yes/no, multiple choice, or free text) via push, and get answers from the user's lock screen. Use these tools proactively - do not wait for the user to ask for notifications. Every question and answer is recorded, so an unattended run stays reviewable afterwards. Works with Claude Code, Codex, Cursor, VS Code, Windsurf, Hermes, Lovable, or any MCP client; no Claude Max subscription required. Pushary is a hosted service, $9.99/mo after a 3-day card-first trial.
|
|
5
5
|
metadata:
|
|
6
6
|
hermes:
|
|
@@ -202,9 +202,20 @@ Send a question to the user via push notification and wait for their answer. By
|
|
|
202
202
|
|
|
203
203
|
Always read `answered` rather than assuming the call blocked. It comes back false
|
|
204
204
|
in three different situations that mean different things: the wait timed out and
|
|
205
|
-
the question is still live (`timedOut`), the site policy is notify_only so
|
|
206
|
-
|
|
207
|
-
(`status: "pending"`).
|
|
205
|
+
the question is still live (`timedOut`), the site policy is notify_only so the
|
|
206
|
+
decision belongs in the current client (`status: "notified"`), or you passed
|
|
207
|
+
`wait: false` yourself (`status: "pending"`). Follow `handoffAction` when present,
|
|
208
|
+
otherwise `nextAction`.
|
|
209
|
+
|
|
210
|
+
For backward compatibility, `nextAction` keeps its original two values. A live timeout from `ask_user` says
|
|
211
|
+
`wait_for_answer`; poll once with `timeoutMs: 55000`. An unanswered poll says
|
|
212
|
+
`handoffAction: cancel_then_ask_in_current_client`: cancel the phone question before asking in
|
|
213
|
+
the current chat or client. If cancellation returns `handoffAction: "stop"`, stop.
|
|
214
|
+
Otherwise, if cancellation returns false, poll once for 1 second
|
|
215
|
+
and honor any answer that won the race. A cancelled question says `handoffAction:
|
|
216
|
+
stop` and must not be resurrected. An unavailable state also stops the handoff,
|
|
217
|
+
because the question cannot be safely fenced. Expired and missing questions are
|
|
218
|
+
not live timeouts.
|
|
208
219
|
|
|
209
220
|
Pass `toolName` and `toolTarget` whenever the question is an approval for a tool
|
|
210
221
|
call. They are what let the user turn a repeated approval into an always-allow
|
|
@@ -249,10 +260,12 @@ rule, so an approval you label once is an approval they never see again.
|
|
|
249
260
|
|
|
250
261
|
Poll for the user's response to a question sent via `ask_user` with `wait: false`, or to one that timed out. Not needed when using the default blocking mode.
|
|
251
262
|
|
|
252
|
-
A single call waits at most 55 seconds
|
|
253
|
-
|
|
254
|
-
`
|
|
255
|
-
|
|
263
|
+
A single call waits at most 55 seconds. Use it once after a live `ask_user`
|
|
264
|
+
timeout. If it returns `answered: false`, follow `handoffAction` when present,
|
|
265
|
+
otherwise `nextAction`: ask in the current chat or client only after cancelling a still-pending phone question. If the
|
|
266
|
+
cancellation loses a race, poll once for 1 second and honor the phone answer
|
|
267
|
+
instead. Only `status: "pending"` means the question is still live; cancelled,
|
|
268
|
+
expired, missing, and unavailable are different outcomes.
|
|
256
269
|
|
|
257
270
|
### cancel_question
|
|
258
271
|
|
|
@@ -273,6 +286,13 @@ Use glob syntax (`src/**`, `**/*.test.ts`). Shell commands are **not** scoped he
|
|
|
273
286
|
the user declined: ask what scope they want, and do **not** proceed as if they had
|
|
274
287
|
agreed. Not answered means the scope is simply not in force.
|
|
275
288
|
|
|
289
|
+
An unanswered proposal returns its `correlationId`. Poll it once; a late phone
|
|
290
|
+
yes ratifies the exact stored proposal. If that poll is still pending, cancel it
|
|
291
|
+
before asking in the current chat whether to continue without an enforced scope.
|
|
292
|
+
If cancellation returns `handoffAction: "stop"`, stop. Otherwise, if cancellation
|
|
293
|
+
returns false, poll once for 1 second and honor the phone answer
|
|
294
|
+
that won the race. A yes in chat is not a server-ratified scope.
|
|
295
|
+
|
|
276
296
|
Omitting `allowedPaths` proposes no path restriction, and the user is told that
|
|
277
297
|
plainly as "this agent is asking to touch anything", so omit it only when you mean
|
|
278
298
|
it.
|
|
@@ -303,7 +323,7 @@ Before executing any of the following, you MUST call `ask_user` with type "confi
|
|
|
303
323
|
- Network configuration changes (firewall, DNS, proxy)
|
|
304
324
|
- Any command the user has flagged as dangerous
|
|
305
325
|
|
|
306
|
-
If `ask_user` returns `answered: false`, do
|
|
326
|
+
If `ask_user` returns `answered: false`, do not execute yet and do not call the task blocked. Follow `handoffAction` when present, otherwise `nextAction`: poll once, then cancel a live phone question before asking in the current client. Execute only after an explicit "yes" from the winning surface.
|
|
307
327
|
|
|
308
328
|
This is not optional. Treat it as a hard constraint, not a suggestion.
|
|
309
329
|
|
|
@@ -323,10 +343,10 @@ result = ask_user({
|
|
|
323
343
|
if result.answered:
|
|
324
344
|
// result.value = "JWT tokens" - proceed with the chosen approach
|
|
325
345
|
else:
|
|
326
|
-
//
|
|
346
|
+
// follow result.handoffAction when present, otherwise result.nextAction
|
|
327
347
|
```
|
|
328
348
|
|
|
329
|
-
If the user answers in chat before the push response arrives,
|
|
349
|
+
If the user answers in chat before the push response arrives, call `cancel_question` before acting. If it returns `handoffAction: "stop"`, stop. Otherwise, if it returns false, poll once for 1 second and honor any phone answer that won the race.
|
|
330
350
|
|
|
331
351
|
**A note on how long ask_user blocks:** the wait time and whether it blocks at all are governed by the site's delivery mode, which the user configures (you do not set it). In the default smart mode and push-only mode, ask_user blocks for the policy timeout; in notify-only mode it returns immediately with `answered: false` after sending the push. Always check `answered` rather than assuming the call blocked, and pass `timeoutMs` only when you need a shorter wait than the site policy.
|
|
332
352
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "pushary",
|
|
3
3
|
"displayName": "Pushary — Control Panel for AI Agents",
|
|
4
4
|
"description": "Push notifications, human-in-the-loop questions, and permission gating for your AI coding agent. Get a push when a task finishes, answer the agent from your phone, and approve risky commands before they run.",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.2.0",
|
|
6
6
|
"author": { "name": "Pushary", "email": "business@pushary.com" },
|
|
7
7
|
"homepage": "https://pushary.com",
|
|
8
8
|
"repository": "https://github.com/Pushary/cursor-plugin",
|
|
@@ -16,9 +16,9 @@ When Pushary is connected, it is your channel for reaching the user. Any time yo
|
|
|
16
16
|
- A name, a path, a value, or other free text. Use type "input".
|
|
17
17
|
- Approval of a plan or an approach before you start. Use type "select" with the options the user is choosing between, or "confirm" to approve a single plan.
|
|
18
18
|
|
|
19
|
-
`ask_user` blocks and returns `{ answered, value }`. Always set `context` to one line on what you are doing, and set `agentName` to "Cursor - {project}". If `answered` is false,
|
|
19
|
+
`ask_user` blocks and returns `{ answered, value, nextAction, handoffAction }`. Always set `context` to one line on what you are doing, and set `agentName` to "Cursor - {project}". If `answered` is false, follow `handoffAction` when present, otherwise `nextAction`: poll once when instructed, then cancel a live phone question before asking in the current chat. Never assume approval.
|
|
20
20
|
|
|
21
|
-
If the user answers in the chat before the push comes back,
|
|
21
|
+
If the user answers in the chat before the push comes back, call `cancel_question` with the correlationId before acting. If cancellation returns `handoffAction: "stop"`, stop. Otherwise, if cancellation returns false, poll once for 1 second and honor any phone answer that won the race.
|
|
22
22
|
|
|
23
23
|
## Notify the user
|
|
24
24
|
|
|
@@ -195,9 +195,20 @@ Send a question to the user via push notification and wait for their answer. By
|
|
|
195
195
|
|
|
196
196
|
Always read `answered` rather than assuming the call blocked. It comes back false
|
|
197
197
|
in three different situations that mean different things: the wait timed out and
|
|
198
|
-
the question is still live (`timedOut`), the site policy is notify_only so
|
|
199
|
-
|
|
200
|
-
(`status: "pending"`).
|
|
198
|
+
the question is still live (`timedOut`), the site policy is notify_only so the
|
|
199
|
+
decision belongs in the current client (`status: "notified"`), or you passed
|
|
200
|
+
`wait: false` yourself (`status: "pending"`). Follow `handoffAction` when present,
|
|
201
|
+
otherwise `nextAction`.
|
|
202
|
+
|
|
203
|
+
For backward compatibility, `nextAction` keeps its original two values. A live timeout from `ask_user` says
|
|
204
|
+
`wait_for_answer`; poll once with `timeoutMs: 55000`. An unanswered poll says
|
|
205
|
+
`handoffAction: cancel_then_ask_in_current_client`: cancel the phone question before asking in
|
|
206
|
+
the current chat or client. If cancellation returns `handoffAction: "stop"`, stop.
|
|
207
|
+
Otherwise, if cancellation returns false, poll once for 1 second
|
|
208
|
+
and honor any answer that won the race. A cancelled question says `handoffAction:
|
|
209
|
+
stop` and must not be resurrected. An unavailable state also stops the handoff,
|
|
210
|
+
because the question cannot be safely fenced. Expired and missing questions are
|
|
211
|
+
not live timeouts.
|
|
201
212
|
|
|
202
213
|
Pass `toolName` and `toolTarget` whenever the question is an approval for a tool
|
|
203
214
|
call. They are what let the user turn a repeated approval into an always-allow
|
|
@@ -242,10 +253,12 @@ rule, so an approval you label once is an approval they never see again.
|
|
|
242
253
|
|
|
243
254
|
Poll for the user's response to a question sent via `ask_user` with `wait: false`, or to one that timed out. Not needed when using the default blocking mode.
|
|
244
255
|
|
|
245
|
-
A single call waits at most 55 seconds
|
|
246
|
-
|
|
247
|
-
`
|
|
248
|
-
|
|
256
|
+
A single call waits at most 55 seconds. Use it once after a live `ask_user`
|
|
257
|
+
timeout. If it returns `answered: false`, follow `handoffAction` when present,
|
|
258
|
+
otherwise `nextAction`: ask in the current chat or client only after cancelling a still-pending phone question. If the
|
|
259
|
+
cancellation loses a race, poll once for 1 second and honor the phone answer
|
|
260
|
+
instead. Only `status: "pending"` means the question is still live; cancelled,
|
|
261
|
+
expired, missing, and unavailable are different outcomes.
|
|
249
262
|
|
|
250
263
|
### cancel_question
|
|
251
264
|
|
|
@@ -266,6 +279,13 @@ Use glob syntax (`src/**`, `**/*.test.ts`). Shell commands are **not** scoped he
|
|
|
266
279
|
the user declined: ask what scope they want, and do **not** proceed as if they had
|
|
267
280
|
agreed. Not answered means the scope is simply not in force.
|
|
268
281
|
|
|
282
|
+
An unanswered proposal returns its `correlationId`. Poll it once; a late phone
|
|
283
|
+
yes ratifies the exact stored proposal. If that poll is still pending, cancel it
|
|
284
|
+
before asking in the current chat whether to continue without an enforced scope.
|
|
285
|
+
If cancellation returns `handoffAction: "stop"`, stop. Otherwise, if cancellation
|
|
286
|
+
returns false, poll once for 1 second and honor the phone answer
|
|
287
|
+
that won the race. A yes in chat is not a server-ratified scope.
|
|
288
|
+
|
|
269
289
|
Omitting `allowedPaths` proposes no path restriction, and the user is told that
|
|
270
290
|
plainly as "this agent is asking to touch anything", so omit it only when you mean
|
|
271
291
|
it.
|
|
@@ -296,7 +316,7 @@ Before executing any of the following, you MUST call `ask_user` with type "confi
|
|
|
296
316
|
- Network configuration changes (firewall, DNS, proxy)
|
|
297
317
|
- Any command the user has flagged as dangerous
|
|
298
318
|
|
|
299
|
-
If `ask_user` returns `answered: false`, do
|
|
319
|
+
If `ask_user` returns `answered: false`, do not execute yet and do not call the task blocked. Follow `handoffAction` when present, otherwise `nextAction`: poll once, then cancel a live phone question before asking in the current client. Execute only after an explicit "yes" from the winning surface.
|
|
300
320
|
|
|
301
321
|
This is not optional. Treat it as a hard constraint, not a suggestion.
|
|
302
322
|
|
|
@@ -316,10 +336,10 @@ result = ask_user({
|
|
|
316
336
|
if result.answered:
|
|
317
337
|
// result.value = "JWT tokens" - proceed with the chosen approach
|
|
318
338
|
else:
|
|
319
|
-
//
|
|
339
|
+
// follow result.handoffAction when present, otherwise result.nextAction
|
|
320
340
|
```
|
|
321
341
|
|
|
322
|
-
If the user answers in chat before the push response arrives,
|
|
342
|
+
If the user answers in chat before the push response arrives, call `cancel_question` before acting. If it returns `handoffAction: "stop"`, stop. Otherwise, if it returns false, poll once for 1 second and honor any phone answer that won the race.
|
|
323
343
|
|
|
324
344
|
**A note on how long ask_user blocks:** the wait time and whether it blocks at all are governed by the site's delivery mode, which the user configures (you do not set it). In the default smart mode and push-only mode, ask_user blocks for the policy timeout; in notify-only mode it returns immediately with `answered: false` after sending the push. Always check `answered` rather than assuming the call blocked, and pass `timeoutMs` only when you need a shorter wait than the site policy.
|
|
325
345
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pushary",
|
|
3
3
|
"description": "Push notifications, human-in-the-loop questions, and permission gating for your AI agent. Get a push when a task finishes, answer the agent from your phone, and approve risky commands before they run.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Pushary",
|
|
7
7
|
"email": "business@pushary.com",
|
|
@@ -195,9 +195,20 @@ Send a question to the user via push notification and wait for their answer. By
|
|
|
195
195
|
|
|
196
196
|
Always read `answered` rather than assuming the call blocked. It comes back false
|
|
197
197
|
in three different situations that mean different things: the wait timed out and
|
|
198
|
-
the question is still live (`timedOut`), the site policy is notify_only so
|
|
199
|
-
|
|
200
|
-
(`status: "pending"`).
|
|
198
|
+
the question is still live (`timedOut`), the site policy is notify_only so the
|
|
199
|
+
decision belongs in the current client (`status: "notified"`), or you passed
|
|
200
|
+
`wait: false` yourself (`status: "pending"`). Follow `handoffAction` when present,
|
|
201
|
+
otherwise `nextAction`.
|
|
202
|
+
|
|
203
|
+
For backward compatibility, `nextAction` keeps its original two values. A live timeout from `ask_user` says
|
|
204
|
+
`wait_for_answer`; poll once with `timeoutMs: 55000`. An unanswered poll says
|
|
205
|
+
`handoffAction: cancel_then_ask_in_current_client`: cancel the phone question before asking in
|
|
206
|
+
the current chat or client. If cancellation returns `handoffAction: "stop"`, stop.
|
|
207
|
+
Otherwise, if cancellation returns false, poll once for 1 second
|
|
208
|
+
and honor any answer that won the race. A cancelled question says `handoffAction:
|
|
209
|
+
stop` and must not be resurrected. An unavailable state also stops the handoff,
|
|
210
|
+
because the question cannot be safely fenced. Expired and missing questions are
|
|
211
|
+
not live timeouts.
|
|
201
212
|
|
|
202
213
|
Pass `toolName` and `toolTarget` whenever the question is an approval for a tool
|
|
203
214
|
call. They are what let the user turn a repeated approval into an always-allow
|
|
@@ -242,10 +253,12 @@ rule, so an approval you label once is an approval they never see again.
|
|
|
242
253
|
|
|
243
254
|
Poll for the user's response to a question sent via `ask_user` with `wait: false`, or to one that timed out. Not needed when using the default blocking mode.
|
|
244
255
|
|
|
245
|
-
A single call waits at most 55 seconds
|
|
246
|
-
|
|
247
|
-
`
|
|
248
|
-
|
|
256
|
+
A single call waits at most 55 seconds. Use it once after a live `ask_user`
|
|
257
|
+
timeout. If it returns `answered: false`, follow `handoffAction` when present,
|
|
258
|
+
otherwise `nextAction`: ask in the current chat or client only after cancelling a still-pending phone question. If the
|
|
259
|
+
cancellation loses a race, poll once for 1 second and honor the phone answer
|
|
260
|
+
instead. Only `status: "pending"` means the question is still live; cancelled,
|
|
261
|
+
expired, missing, and unavailable are different outcomes.
|
|
249
262
|
|
|
250
263
|
### cancel_question
|
|
251
264
|
|
|
@@ -266,6 +279,13 @@ Use glob syntax (`src/**`, `**/*.test.ts`). Shell commands are **not** scoped he
|
|
|
266
279
|
the user declined: ask what scope they want, and do **not** proceed as if they had
|
|
267
280
|
agreed. Not answered means the scope is simply not in force.
|
|
268
281
|
|
|
282
|
+
An unanswered proposal returns its `correlationId`. Poll it once; a late phone
|
|
283
|
+
yes ratifies the exact stored proposal. If that poll is still pending, cancel it
|
|
284
|
+
before asking in the current chat whether to continue without an enforced scope.
|
|
285
|
+
If cancellation returns `handoffAction: "stop"`, stop. Otherwise, if cancellation
|
|
286
|
+
returns false, poll once for 1 second and honor the phone answer
|
|
287
|
+
that won the race. A yes in chat is not a server-ratified scope.
|
|
288
|
+
|
|
269
289
|
Omitting `allowedPaths` proposes no path restriction, and the user is told that
|
|
270
290
|
plainly as "this agent is asking to touch anything", so omit it only when you mean
|
|
271
291
|
it.
|
|
@@ -296,7 +316,7 @@ Before executing any of the following, you MUST call `ask_user` with type "confi
|
|
|
296
316
|
- Network configuration changes (firewall, DNS, proxy)
|
|
297
317
|
- Any command the user has flagged as dangerous
|
|
298
318
|
|
|
299
|
-
If `ask_user` returns `answered: false`, do
|
|
319
|
+
If `ask_user` returns `answered: false`, do not execute yet and do not call the task blocked. Follow `handoffAction` when present, otherwise `nextAction`: poll once, then cancel a live phone question before asking in the current client. Execute only after an explicit "yes" from the winning surface.
|
|
300
320
|
|
|
301
321
|
This is not optional. Treat it as a hard constraint, not a suggestion.
|
|
302
322
|
|
|
@@ -316,10 +336,10 @@ result = ask_user({
|
|
|
316
336
|
if result.answered:
|
|
317
337
|
// result.value = "JWT tokens" - proceed with the chosen approach
|
|
318
338
|
else:
|
|
319
|
-
//
|
|
339
|
+
// follow result.handoffAction when present, otherwise result.nextAction
|
|
320
340
|
```
|
|
321
341
|
|
|
322
|
-
If the user answers in chat before the push response arrives,
|
|
342
|
+
If the user answers in chat before the push response arrives, call `cancel_question` before acting. If it returns `handoffAction: "stop"`, stop. Otherwise, if it returns false, poll once for 1 second and honor any phone answer that won the race.
|
|
323
343
|
|
|
324
344
|
**A note on how long ask_user blocks:** the wait time and whether it blocks at all are governed by the site's delivery mode, which the user configures (you do not set it). In the default smart mode and push-only mode, ask_user blocks for the policy timeout; in notify-only mode it returns immediately with `answered: false` after sending the push. Always check `answered` rather than assuming the call blocked, and pass `timeoutMs` only when you need a shorter wait than the site policy.
|
|
325
345
|
|
|
@@ -259,7 +259,7 @@ You have Pushary MCP tools that reach the user on their phone. Use them proactiv
|
|
|
259
259
|
- Use \`cancel_question\` to retract a pending question once it is no longer needed.
|
|
260
260
|
- Respect the user's Pushary delivery mode: it decides where an approval is surfaced (phone, terminal, or awareness only), not whether it is required. In Terminal mode do not expect a phone answer; the approval waits in the terminal. If the Pushary hook already gated an action, a single approval is enough, do not ask again.
|
|
261
261
|
|
|
262
|
-
Pass \`agentName\` as "${label} - <project folder name>" so the user knows which session is asking. If a question times out
|
|
262
|
+
Pass \`agentName\` as "${label} - <project folder name>" so the user knows which session is asking. If a question times out, follow \`handoffAction\` when present, otherwise \`nextAction\`: poll once, then cancel a live phone question before asking in the current client. If cancellation returns \`handoffAction: "stop"\`, stop. Otherwise, if cancellation returns false, poll once for 1 second and honor the answer that won the race.`;
|
|
263
263
|
var renderAgentInstructions = (label) => instructionBody(label);
|
|
264
264
|
var KEYLESS_FALLBACK_LINE = "This repo uses Pushary phone approvals. Your teammates get agent questions on their lock screens; you do not have a key yet, so questions will fall back to the terminal. Get your own key (3-day trial): https://pushary.com/sign-up?utm_source=agents-md&utm_medium=teammate";
|
|
265
265
|
var renderProjectAgentInstructions = (label) => `${instructionBody(label)}
|