@pushary/agent-hooks 1.7.3 → 1.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.
- package/CHANGELOG.md +10 -0
- package/README.md +13 -1
- package/data/cursor-plugin/scripts/pushary-gate.mjs +2 -21
- package/data/cursor-plugin/scripts/redaction.mjs +51 -0
- package/data/vscode-plugin/scripts/pushary-gate.mjs +1 -21
- package/data/vscode-plugin/scripts/redaction.mjs +51 -0
- package/dist/bin/pushary-bell-hook.js +23 -23
- package/dist/bin/pushary-bell.js +9 -9
- package/dist/bin/pushary-claude.js +26 -26
- package/dist/bin/pushary-clean.js +91 -107
- package/dist/bin/pushary-codex-bridge.js +18 -18
- package/dist/bin/pushary-codex-hook.js +42 -43
- package/dist/bin/pushary-codex.js +13 -13
- package/dist/bin/pushary-connect.js +13 -13
- package/dist/bin/pushary-cowork.js +5 -5
- package/dist/bin/pushary-daemon.js +27 -27
- package/dist/bin/pushary-disconnect.js +18 -18
- package/dist/bin/pushary-doctor.js +85 -79
- package/dist/bin/pushary-elicitation-hook.js +25 -25
- package/dist/bin/pushary-gemini-bridge.js +12 -12
- package/dist/bin/pushary-gemini-hook.js +29 -30
- package/dist/bin/pushary-hook.js +32 -32
- package/dist/bin/pushary-login.js +12 -12
- package/dist/bin/pushary-logout.js +7 -7
- package/dist/bin/pushary-mcp.js +85 -28
- package/dist/bin/pushary-mode.js +9 -9
- package/dist/bin/pushary-notification-hook.js +28 -28
- package/dist/bin/pushary-opencode-hook.js +28 -29
- package/dist/bin/pushary-permission-denied-hook.js +32 -32
- package/dist/bin/pushary-permission-hook.js +31 -31
- package/dist/bin/pushary-post-hook.js +28 -28
- package/dist/bin/pushary-prompt-hook.js +28 -28
- package/dist/bin/pushary-session-end-hook.js +28 -28
- package/dist/bin/pushary-session-start-hook.js +32 -32
- package/dist/bin/pushary-setup.js +60 -127
- package/dist/bin/pushary-stats.js +5 -5
- package/dist/bin/pushary-status.js +15 -15
- package/dist/bin/pushary-stop-hook.js +28 -28
- package/dist/bin/pushary-stopfailure-hook.js +28 -28
- package/dist/bin/pushary-suggestions.js +4 -4
- package/dist/bin/pushary-transcript-register.js +19 -19
- package/dist/bin/pushary-transcripts.js +7 -7
- package/dist/bin/pushary-upgrade.js +231 -105
- package/dist/bin/pushary-wait.js +9 -9
- package/dist/bin/pushary.js +6 -6
- package/dist/{chunk-EEEJ2JIL.js → chunk-2ABTSGFT.js} +3 -3
- package/dist/{chunk-DUQO4C4I.js → chunk-2OY3ZZ5N.js} +3 -3
- package/dist/{chunk-MIXWMA73.js → chunk-3EVPNIBE.js} +3 -3
- package/dist/{chunk-WTJM7PSL.js → chunk-6J2JC2RT.js} +3 -3
- package/dist/{chunk-EADXTSHE.js → chunk-7Z7Q4GGS.js} +2 -2
- package/dist/{chunk-MZBRL5H5.js → chunk-A2A2YTMG.js} +108 -25
- package/dist/{chunk-KEL5MXRL.js → chunk-AHV4LNB5.js} +1 -1
- package/dist/{chunk-G3OMOTJ4.js → chunk-AXPCESYO.js} +3 -3
- package/dist/{chunk-3EUBQARL.js → chunk-C2WCPBF7.js} +1 -1
- package/dist/chunk-CJVVKOSR.js +73 -0
- package/dist/{chunk-U6RVDUJ5.js → chunk-CULUZTWQ.js} +283 -41
- package/dist/{chunk-N5MZH5A6.js → chunk-CVQYGMSR.js} +4 -4
- package/dist/{chunk-VKVSRCBO.js → chunk-D2FX3EPW.js} +1 -1
- package/dist/{chunk-62CVUUNU.js → chunk-DB3ONZB4.js} +2 -2
- package/dist/{chunk-WGMW7OXW.js → chunk-DE4Y6TCC.js} +6 -6
- package/dist/{chunk-YYCTF4Q5.js → chunk-E4FJTUH4.js} +1 -1
- package/dist/{chunk-EUGNVLMG.js → chunk-EPCXUP3P.js} +3 -1
- package/dist/{chunk-PRNFSORD.js → chunk-EX3GAPA4.js} +1 -1
- package/dist/{chunk-TCVMK6GI.js → chunk-EYK3GSRH.js} +4 -4
- package/dist/{chunk-R6OYCUNK.js → chunk-GPEGOGRJ.js} +1 -1
- package/dist/chunk-GU3EJCVV.js +43 -0
- package/dist/{chunk-Y4ZH64UK.js → chunk-HQ6G3B5R.js} +2 -2
- package/dist/{chunk-5S2VBSJI.js → chunk-HZVVNGEW.js} +2 -2
- package/dist/{chunk-IWJKSIB4.js → chunk-IPVKH2ST.js} +1 -1
- package/dist/{chunk-UOQRM7JQ.js → chunk-J5TIV3J6.js} +5 -5
- package/dist/{chunk-IRZG3HEU.js → chunk-JU6W3XAU.js} +1 -1
- package/dist/{chunk-G62JL2NT.js → chunk-JYG4B33G.js} +1 -1
- package/dist/{chunk-OTNOANMX.js → chunk-JZTHGAPA.js} +8 -8
- package/dist/{chunk-7RUJKCR4.js → chunk-KGDWDSNL.js} +2 -2
- package/dist/{chunk-6JQFIHZC.js → chunk-KVQBWI5T.js} +3 -3
- package/dist/{chunk-OVC5QXN5.js → chunk-LXQ5FBBD.js} +1 -1
- package/dist/{chunk-VE7TXLR4.js → chunk-M5ICYGHT.js} +3 -3
- package/dist/{chunk-YPUBA2FL.js → chunk-M5JDZ45W.js} +4 -4
- package/dist/{chunk-O3JDWNLU.js → chunk-MDEPU45E.js} +183 -28
- package/dist/{chunk-P2VIBGXA.js → chunk-MPWXGONV.js} +1 -1
- package/dist/{chunk-YC27PROF.js → chunk-NGDD6TXY.js} +20 -5
- package/dist/{chunk-G4GLCLKK.js → chunk-NQTHFF4W.js} +138 -17
- package/dist/{chunk-NOI3XTCY.js → chunk-OKXS7WDZ.js} +1 -1
- package/dist/{chunk-LPNJLKBQ.js → chunk-OLQRRFBX.js} +1 -1
- package/dist/{chunk-D6OODZCM.js → chunk-P7WQEVWA.js} +2 -2
- package/dist/{chunk-62VT3BPH.js → chunk-Q7E4I6UA.js} +28 -16
- package/dist/{chunk-BIH2Y2HP.js → chunk-R7437YI3.js} +2 -2
- package/dist/{chunk-RLW3JWDY.js → chunk-RHR6NARM.js} +2 -2
- package/dist/{chunk-WPX67AKT.js → chunk-SAXBC4AZ.js} +1 -1
- package/dist/{chunk-IPSRMLCJ.js → chunk-SIFVFP6T.js} +1 -1
- package/dist/{chunk-7OA34PNW.js → chunk-SLFABHW3.js} +40 -10
- package/dist/{chunk-AWVNAYGD.js → chunk-TY4JT7W3.js} +1 -1
- package/dist/{chunk-KJXUIPS4.js → chunk-UI36QSBI.js} +28 -16
- package/dist/{chunk-G6RRVJOG.js → chunk-VQKRG3AC.js} +6 -6
- package/dist/{chunk-ZKJ34T2F.js → chunk-WE2J62NC.js} +31 -17
- package/dist/{chunk-LHC45YUC.js → chunk-ZSZSSJCV.js} +1 -1
- package/dist/{chunk-BGBLLHZ4.js → chunk-ZVSKMPBZ.js} +1 -1
- package/dist/{reapply-PH5T4BGR.js → reapply-CW3MA66V.js} +9 -9
- package/dist/src/index.js +20 -20
- package/package.json +1 -1
- package/dist/chunk-5GB22QYL.js +0 -255
- package/dist/chunk-VYPJHGG6.js +0 -92
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.8.0
|
|
4
|
+
|
|
5
|
+
- **An approval you give after auto mode blocks a call is no longer lost when the agent rewords the call.** Your approval covers only the exact call that was blocked. Claude Code tells the agent only that it may retry, and an agent that sent a changed command was blocked again, so the approval you gave from your phone or the Mac notch did nothing. Pushary now refuses the first changed call and tells the agent to send the blocked call again unchanged. If the agent ends its turn without sending it, Pushary tells it to send it.
|
|
6
|
+
- Claude Code no longer tells your phone and the Mac notch that it is waiting for you while its background tasks are still running. Claude Code reports itself idle after a minute at the prompt even when it will continue by itself once those tasks finish. A question from the agent still reaches you as before.
|
|
7
|
+
- A prompt longer than 500 characters, or a shell command longer than about 490, no longer stops your agent at its next phone approval. The hook sent the whole text and the server refused it, so Claude Code halted with "Pushary could not create a verifiable approval" and Codex and OpenCode denied the call. The question, intent, action, blocker and agent name are now cut to what the card can show, and a cut line ends in "…". The server now does the same for every older CLI, so this fix does not wait for you to update. (#1604)
|
|
8
|
+
- A line cut to fit, including a long diff, never ends on half an emoji. The server stores these lines as JSON, and Postgres refuses a half character, so the approval failed to save.
|
|
9
|
+
- `pushary doctor`, `pushary upgrade`, `pushary clean` and automatic updates recognise a global install under either package name, `@pushary/agent-hooks` or `pushary`. A machine keeps the name it already has, and setup on a new machine installs the name it was run from. Nothing changes for an existing install.
|
|
10
|
+
- `pushary doctor` flags a machine with both names installed globally, because uninstalling either one removes every Pushary command.
|
|
11
|
+
- `pushary upgrade` no longer installs over an automatic update that is still running. It says another upgrade is running, with its process id, and stops.
|
|
12
|
+
|
|
3
13
|
## 1.7.3
|
|
4
14
|
|
|
5
15
|
- **Approval text never hides part of a command.** The value after a credential name is now hidden only up to the first space, quote or piece of shell syntax. 1.7.2 could still hide a command: `eval TOKEN="x; rm -rf ~"` read `eval TOKEN="[redacted]"`, `password= reboot` read `password= [redacted]`, and `rm -rf {password=x,/}` hid the `,/` that also deletes `/`. A private key block is hidden only when it holds nothing but the key. Tokens, keys and quoted values without spaces are hidden as before. A quoted value with spaces now shows what follows its first word, as in `--password='[redacted] pass'`. Logs and error reports still hide the whole value.
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Pushary
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@pushary/agent-hooks)
|
|
4
4
|
[](https://www.npmjs.com/package/@pushary/agent-hooks)
|
|
@@ -100,6 +100,18 @@ Verify it worked:
|
|
|
100
100
|
npx @pushary/agent-hooks@latest doctor
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
+
Setup installs this package globally with npm, at the version you ran, because the
|
|
104
|
+
hooks run from that install. You never install it by hand.
|
|
105
|
+
|
|
106
|
+
## Remove it
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
npx @pushary/agent-hooks@latest clean
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
It removes the hooks, the MCP entries, the stored key and the background service.
|
|
113
|
+
Add `--dry-run` to see what it would remove first.
|
|
114
|
+
|
|
103
115
|
## Supported agents
|
|
104
116
|
|
|
105
117
|
| Agent | Notify | Ask | Gate |
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
// Pushary Cursor hooks: server policy, fenced phone approvals, and lifecycle telemetry.
|
|
3
3
|
// Dependency-free for marketplace installs. Regenerate agent-hooks/data after edits.
|
|
4
4
|
|
|
5
|
+
import { redactSecrets, redactSecretsDeep } from './redaction.mjs'
|
|
6
|
+
export { redactSecrets } from './redaction.mjs'
|
|
5
7
|
import { createHash, randomUUID } from 'node:crypto'
|
|
6
8
|
import { hostname } from 'node:os'
|
|
7
9
|
import { existsSync, readFileSync } from 'node:fs'
|
|
@@ -294,27 +296,6 @@ export const describeNetworkFailure = (error, env = process.env) => {
|
|
|
294
296
|
// line reached the lock screen verbatim.
|
|
295
297
|
const ACTION_BODY_MAX = 4000
|
|
296
298
|
const ACTION_BODY_TRUNCATION_MARKER = '\n… [truncated]'
|
|
297
|
-
const REDACTION_RULES = [
|
|
298
|
-
[/-----BEGIN[A-Z0-9 ]*PRIVATE KEY-----(?:\r?\n|(?:\\r)?\\n)?(?:(?:Proc-Type|DEK-Info): [A-Za-z0-9,-]+(?:\r?\n|(?:\\r)?\\n))*(?:[A-Za-z0-9+/=\r\n]|\\[rn])*?-----END[A-Z0-9 ]*PRIVATE KEY-----/g, '[redacted key]'],
|
|
299
|
-
[/\bsk-[A-Za-z0-9_-]{16,}\b/g, '[redacted]'],
|
|
300
|
-
[/\b[spr]k_(?:live|test)_[A-Za-z0-9]{8,}\b/g, '[redacted]'],
|
|
301
|
-
[/\bwhsec_[A-Za-z0-9]{16,}\b/g, '[redacted]'],
|
|
302
|
-
[/\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36,}\b/g, '[redacted]'],
|
|
303
|
-
[/\bgithub_pat_[A-Za-z0-9_]{22,}\b/g, '[redacted]'],
|
|
304
|
-
[/\bglpat-[A-Za-z0-9_-]{20,}\b/g, '[redacted]'],
|
|
305
|
-
[/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g, '[redacted]'],
|
|
306
|
-
[/\bAIza[A-Za-z0-9_-]{35}\b/g, '[redacted]'],
|
|
307
|
-
[/\bAKIA[0-9A-Z]{16}\b/g, '[redacted]'],
|
|
308
|
-
[/\bnpm_[A-Za-z0-9]{36}\b/g, '[redacted]'],
|
|
309
|
-
[/\bxai-[A-Za-z0-9]{16,}\b/g, '[redacted]'],
|
|
310
|
-
[/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g, '[redacted]'],
|
|
311
|
-
[/\bbearer\s+[A-Za-z0-9._~+/=-]+/gi, 'bearer [redacted]'],
|
|
312
|
-
[/\bauthorization:\s*(?:[A-Za-z0-9_\-./+=:@%^!#]|\\[^\s'"])+/gi, 'authorization: [redacted]'],
|
|
313
|
-
[/((?:secret|token|password|passwd|api[_-]?key|access[_-]?key|client[_-]?secret|private[_-]?key)["']?(?:[ \t]*:[ \t]*|[ \t]+=[ \t]*|=))(?:(")(?:[A-Za-z0-9_\-./+=:@%^!#]|\\[^\s'"])*"|(')[A-Za-z0-9_\-./+=:@%^!#\\]*'|(["']?)(?:[A-Za-z0-9_\-./+=:@%^!#]|\\[^\s'"])+)/gi, '$1$2$3$4[redacted]$2$3'],
|
|
314
|
-
]
|
|
315
|
-
const HIGH_ENTROPY_RULE = [/[A-Za-z0-9+/]{40,}={0,2}/g, '[redacted]']
|
|
316
|
-
export const redactSecrets = (text) => REDACTION_RULES.reduce((acc, [pattern, replacement]) => acc.replace(pattern, replacement), text)
|
|
317
|
-
const redactSecretsDeep = (text) => redactSecrets(text).replace(HIGH_ENTROPY_RULE[0], HIGH_ENTROPY_RULE[1])
|
|
318
299
|
const capActionBody = (text) =>
|
|
319
300
|
text.length <= ACTION_BODY_MAX ? text : `${text.slice(0, ACTION_BODY_MAX - ACTION_BODY_TRUNCATION_MARKER.length)}${ACTION_BODY_TRUNCATION_MARKER}`
|
|
320
301
|
const deriveActionBody = (command) => capActionBody(redactSecretsDeep(command))
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// Generated by scripts/generate-editor-redaction.mjs.
|
|
2
|
+
const CREDENTIAL_NAME = String.raw `(?:authorization|secret|token|password|passwd|api[_-]?key|access[_-]?key|client[_-]?secret|private[_-]?key)["']?`;
|
|
3
|
+
const CREDENTIAL_KEY = String.raw `${CREDENTIAL_NAME}\s*[=:]\s*`;
|
|
4
|
+
const DISPLAYED_CREDENTIAL_KEY = String.raw `${CREDENTIAL_NAME}(?:[ \t]*:[ \t]*|[ \t]+=[ \t]*|=)`;
|
|
5
|
+
const SHELL_INERT_UNIT = String.raw `(?:[A-Za-z0-9_\-./+=:@%^!#]|\\[^\s'"])`;
|
|
6
|
+
const SHELL_INERT_SINGLE_QUOTED_UNIT = String.raw `[A-Za-z0-9_\-./+=:@%^!#\\]`;
|
|
7
|
+
const SHELL_INERT_URL_PASSWORD_UNIT = String.raw `(?:[A-Za-z0-9_\-.+=:%^!#]|\\[^\s'"@/])`;
|
|
8
|
+
const PEM_LINE_BREAK = String.raw `(?:\r?\n|(?:\\r)?\\n)`;
|
|
9
|
+
const credentialAssignmentRule = (key, doubleQuoted, singleQuoted, bare) => ({
|
|
10
|
+
pattern: new RegExp(String.raw `(${key})(?:(")${doubleQuoted}|(')${singleQuoted}|(["']?)${bare})`, 'gi'),
|
|
11
|
+
replacement: '$1$2$3$4[redacted]$2$3',
|
|
12
|
+
});
|
|
13
|
+
const DISPLAYED_SECRET_SHAPES = {
|
|
14
|
+
privateKeyBody: String.raw `${PEM_LINE_BREAK}?(?:(?:Proc-Type|DEK-Info): [A-Za-z0-9,-]+${PEM_LINE_BREAK})*(?:[A-Za-z0-9+/=\r\n]|\\[rn])*?`,
|
|
15
|
+
urlPassword: `${SHELL_INERT_URL_PASSWORD_UNIT}+`,
|
|
16
|
+
authorizationValue: `${SHELL_INERT_UNIT}+`,
|
|
17
|
+
credentialAssignment: credentialAssignmentRule(DISPLAYED_CREDENTIAL_KEY, `${SHELL_INERT_UNIT}*"`, `${SHELL_INERT_SINGLE_QUOTED_UNIT}*'`, `${SHELL_INERT_UNIT}+`),
|
|
18
|
+
};
|
|
19
|
+
const CUT_OFF_SECRET_SHAPES = {
|
|
20
|
+
privateKeyBody: String.raw `[\s\S]*?`,
|
|
21
|
+
urlPassword: String.raw `[^\s@/]+`,
|
|
22
|
+
authorizationValue: String.raw `\S+`,
|
|
23
|
+
credentialAssignment: credentialAssignmentRule(CREDENTIAL_KEY, String.raw `(?:\\[\s\S]|[^"\\])*(?:"|\\?$)`, "[^']*(?:'|$)", String.raw `\S+`),
|
|
24
|
+
};
|
|
25
|
+
const secretRedactionRules = (shapes) => [
|
|
26
|
+
{ pattern: /\bpk_[A-Za-z0-9_]+\.[A-Za-z0-9_]+/g, replacement: '[redacted]' },
|
|
27
|
+
{ pattern: new RegExp(String.raw `-----BEGIN[A-Z0-9 ]*PRIVATE KEY-----${shapes.privateKeyBody}-----END[A-Z0-9 ]*PRIVATE KEY-----`, 'g'), replacement: '[redacted key]' },
|
|
28
|
+
{ pattern: /\bsk-[A-Za-z0-9_-]{16,}\b/g, replacement: '[redacted]' },
|
|
29
|
+
{ pattern: /\b[spr]k_(?:live|test)_[A-Za-z0-9]{8,}\b/g, replacement: '[redacted]' },
|
|
30
|
+
{ pattern: /\bwhsec_[A-Za-z0-9]{16,}\b/g, replacement: '[redacted]' },
|
|
31
|
+
{ pattern: /\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36,}\b/g, replacement: '[redacted]' },
|
|
32
|
+
{ pattern: /\bgithub_pat_[A-Za-z0-9_]{22,}\b/g, replacement: '[redacted]' },
|
|
33
|
+
{ pattern: /\bglpat-[A-Za-z0-9_-]{20,}\b/g, replacement: '[redacted]' },
|
|
34
|
+
{ pattern: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g, replacement: '[redacted]' },
|
|
35
|
+
{ pattern: /\bAIza[A-Za-z0-9_-]{35}\b/g, replacement: '[redacted]' },
|
|
36
|
+
{ pattern: /\bAKIA[0-9A-Z]{16}\b/g, replacement: '[redacted]' },
|
|
37
|
+
{ pattern: /\bnpm_[A-Za-z0-9]{36}\b/g, replacement: '[redacted]' },
|
|
38
|
+
{ pattern: /\bxai-[A-Za-z0-9]{16,}\b/g, replacement: '[redacted]' },
|
|
39
|
+
{ pattern: /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g, replacement: '[redacted]' },
|
|
40
|
+
{ pattern: new RegExp(String.raw `\b([a-z][a-z0-9+.-]*:\/\/[^\s:/@]+:)${shapes.urlPassword}@`, 'gi'), replacement: '$1[redacted]@' },
|
|
41
|
+
{ pattern: /\bbearer\s+[A-Za-z0-9._~+/=-]+/gi, replacement: 'bearer [redacted]' },
|
|
42
|
+
{ pattern: new RegExp(String.raw `\bauthorization:\s*${shapes.authorizationValue}`, 'gi'), replacement: 'authorization: [redacted]' },
|
|
43
|
+
shapes.credentialAssignment,
|
|
44
|
+
];
|
|
45
|
+
export const SECRET_REDACTION_RULES = secretRedactionRules(DISPLAYED_SECRET_SHAPES);
|
|
46
|
+
const CUT_OFF_TEXT_REDACTION_RULES = secretRedactionRules(CUT_OFF_SECRET_SHAPES);
|
|
47
|
+
const HIGH_ENTROPY_RULE = { pattern: /[A-Za-z0-9+/]{40,}={0,2}/g, replacement: '[redacted]' };
|
|
48
|
+
const applyRedactionRules = (rules, text) => rules.reduce((acc, rule) => acc.replace(rule.pattern, rule.replacement), text);
|
|
49
|
+
export const redactSecrets = (text) => applyRedactionRules(SECRET_REDACTION_RULES, text);
|
|
50
|
+
export const redactSecretsFromContent = (text) => applyRedactionRules(CUT_OFF_TEXT_REDACTION_RULES, text);
|
|
51
|
+
export const redactSecretsDeep = (text) => redactSecrets(text).replace(HIGH_ENTROPY_RULE.pattern, HIGH_ENTROPY_RULE.replacement);
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// Pushary VS Code hooks: server policy, fenced phone approvals, and lifecycle telemetry.
|
|
3
3
|
// Dependency-free for marketplace installs. Regenerate agent-hooks/data after edits.
|
|
4
4
|
|
|
5
|
+
import { redactSecrets, redactSecretsDeep } from './redaction.mjs'
|
|
5
6
|
import { createHash, randomUUID } from 'node:crypto'
|
|
6
7
|
import { homedir, hostname } from 'node:os'
|
|
7
8
|
import { existsSync, readFileSync } from 'node:fs'
|
|
@@ -337,27 +338,6 @@ const ACTION_BODY_TRUNCATION_MARKER = '\n… [truncated]'
|
|
|
337
338
|
// One combined list used to serve both, which meant the only text this gate
|
|
338
339
|
// scrubbed was the action body. The question and the notification body carried
|
|
339
340
|
// the raw command.
|
|
340
|
-
const REDACTION_RULES = [
|
|
341
|
-
[/-----BEGIN[A-Z0-9 ]*PRIVATE KEY-----(?:\r?\n|(?:\\r)?\\n)?(?:(?:Proc-Type|DEK-Info): [A-Za-z0-9,-]+(?:\r?\n|(?:\\r)?\\n))*(?:[A-Za-z0-9+/=\r\n]|\\[rn])*?-----END[A-Z0-9 ]*PRIVATE KEY-----/g, '[redacted key]'],
|
|
342
|
-
[/\bsk-[A-Za-z0-9_-]{16,}\b/g, '[redacted]'],
|
|
343
|
-
[/\b[spr]k_(?:live|test)_[A-Za-z0-9]{8,}\b/g, '[redacted]'],
|
|
344
|
-
[/\bwhsec_[A-Za-z0-9]{16,}\b/g, '[redacted]'],
|
|
345
|
-
[/\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36,}\b/g, '[redacted]'],
|
|
346
|
-
[/\bgithub_pat_[A-Za-z0-9_]{22,}\b/g, '[redacted]'],
|
|
347
|
-
[/\bglpat-[A-Za-z0-9_-]{20,}\b/g, '[redacted]'],
|
|
348
|
-
[/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g, '[redacted]'],
|
|
349
|
-
[/\bAIza[A-Za-z0-9_-]{35}\b/g, '[redacted]'],
|
|
350
|
-
[/\bAKIA[0-9A-Z]{16}\b/g, '[redacted]'],
|
|
351
|
-
[/\bnpm_[A-Za-z0-9]{36}\b/g, '[redacted]'],
|
|
352
|
-
[/\bxai-[A-Za-z0-9]{16,}\b/g, '[redacted]'],
|
|
353
|
-
[/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g, '[redacted]'],
|
|
354
|
-
[/\bbearer\s+[A-Za-z0-9._~+/=-]+/gi, 'bearer [redacted]'],
|
|
355
|
-
[/\bauthorization:\s*(?:[A-Za-z0-9_\-./+=:@%^!#]|\\[^\s'"])+/gi, 'authorization: [redacted]'],
|
|
356
|
-
[/((?:secret|token|password|passwd|api[_-]?key|access[_-]?key|client[_-]?secret|private[_-]?key)["']?(?:[ \t]*:[ \t]*|[ \t]+=[ \t]*|=))(?:(")(?:[A-Za-z0-9_\-./+=:@%^!#]|\\[^\s'"])*"|(')[A-Za-z0-9_\-./+=:@%^!#\\]*'|(["']?)(?:[A-Za-z0-9_\-./+=:@%^!#]|\\[^\s'"])+)/gi, '$1$2$3$4[redacted]$2$3'],
|
|
357
|
-
]
|
|
358
|
-
const HIGH_ENTROPY_RULE = [/[A-Za-z0-9+/]{40,}={0,2}/g, '[redacted]']
|
|
359
|
-
const redactSecrets = (text) => REDACTION_RULES.reduce((acc, [pattern, replacement]) => acc.replace(pattern, replacement), text)
|
|
360
|
-
const redactSecretsDeep = (text) => redactSecrets(text).replace(HIGH_ENTROPY_RULE[0], HIGH_ENTROPY_RULE[1])
|
|
361
341
|
const capActionBody = (text) =>
|
|
362
342
|
text.length <= ACTION_BODY_MAX ? text : `${text.slice(0, ACTION_BODY_MAX - ACTION_BODY_TRUNCATION_MARKER.length)}${ACTION_BODY_TRUNCATION_MARKER}`
|
|
363
343
|
const deriveActionBody = (command) => capActionBody(redactSecretsDeep(command))
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// Generated by scripts/generate-editor-redaction.mjs.
|
|
2
|
+
const CREDENTIAL_NAME = String.raw `(?:authorization|secret|token|password|passwd|api[_-]?key|access[_-]?key|client[_-]?secret|private[_-]?key)["']?`;
|
|
3
|
+
const CREDENTIAL_KEY = String.raw `${CREDENTIAL_NAME}\s*[=:]\s*`;
|
|
4
|
+
const DISPLAYED_CREDENTIAL_KEY = String.raw `${CREDENTIAL_NAME}(?:[ \t]*:[ \t]*|[ \t]+=[ \t]*|=)`;
|
|
5
|
+
const SHELL_INERT_UNIT = String.raw `(?:[A-Za-z0-9_\-./+=:@%^!#]|\\[^\s'"])`;
|
|
6
|
+
const SHELL_INERT_SINGLE_QUOTED_UNIT = String.raw `[A-Za-z0-9_\-./+=:@%^!#\\]`;
|
|
7
|
+
const SHELL_INERT_URL_PASSWORD_UNIT = String.raw `(?:[A-Za-z0-9_\-.+=:%^!#]|\\[^\s'"@/])`;
|
|
8
|
+
const PEM_LINE_BREAK = String.raw `(?:\r?\n|(?:\\r)?\\n)`;
|
|
9
|
+
const credentialAssignmentRule = (key, doubleQuoted, singleQuoted, bare) => ({
|
|
10
|
+
pattern: new RegExp(String.raw `(${key})(?:(")${doubleQuoted}|(')${singleQuoted}|(["']?)${bare})`, 'gi'),
|
|
11
|
+
replacement: '$1$2$3$4[redacted]$2$3',
|
|
12
|
+
});
|
|
13
|
+
const DISPLAYED_SECRET_SHAPES = {
|
|
14
|
+
privateKeyBody: String.raw `${PEM_LINE_BREAK}?(?:(?:Proc-Type|DEK-Info): [A-Za-z0-9,-]+${PEM_LINE_BREAK})*(?:[A-Za-z0-9+/=\r\n]|\\[rn])*?`,
|
|
15
|
+
urlPassword: `${SHELL_INERT_URL_PASSWORD_UNIT}+`,
|
|
16
|
+
authorizationValue: `${SHELL_INERT_UNIT}+`,
|
|
17
|
+
credentialAssignment: credentialAssignmentRule(DISPLAYED_CREDENTIAL_KEY, `${SHELL_INERT_UNIT}*"`, `${SHELL_INERT_SINGLE_QUOTED_UNIT}*'`, `${SHELL_INERT_UNIT}+`),
|
|
18
|
+
};
|
|
19
|
+
const CUT_OFF_SECRET_SHAPES = {
|
|
20
|
+
privateKeyBody: String.raw `[\s\S]*?`,
|
|
21
|
+
urlPassword: String.raw `[^\s@/]+`,
|
|
22
|
+
authorizationValue: String.raw `\S+`,
|
|
23
|
+
credentialAssignment: credentialAssignmentRule(CREDENTIAL_KEY, String.raw `(?:\\[\s\S]|[^"\\])*(?:"|\\?$)`, "[^']*(?:'|$)", String.raw `\S+`),
|
|
24
|
+
};
|
|
25
|
+
const secretRedactionRules = (shapes) => [
|
|
26
|
+
{ pattern: /\bpk_[A-Za-z0-9_]+\.[A-Za-z0-9_]+/g, replacement: '[redacted]' },
|
|
27
|
+
{ pattern: new RegExp(String.raw `-----BEGIN[A-Z0-9 ]*PRIVATE KEY-----${shapes.privateKeyBody}-----END[A-Z0-9 ]*PRIVATE KEY-----`, 'g'), replacement: '[redacted key]' },
|
|
28
|
+
{ pattern: /\bsk-[A-Za-z0-9_-]{16,}\b/g, replacement: '[redacted]' },
|
|
29
|
+
{ pattern: /\b[spr]k_(?:live|test)_[A-Za-z0-9]{8,}\b/g, replacement: '[redacted]' },
|
|
30
|
+
{ pattern: /\bwhsec_[A-Za-z0-9]{16,}\b/g, replacement: '[redacted]' },
|
|
31
|
+
{ pattern: /\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36,}\b/g, replacement: '[redacted]' },
|
|
32
|
+
{ pattern: /\bgithub_pat_[A-Za-z0-9_]{22,}\b/g, replacement: '[redacted]' },
|
|
33
|
+
{ pattern: /\bglpat-[A-Za-z0-9_-]{20,}\b/g, replacement: '[redacted]' },
|
|
34
|
+
{ pattern: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g, replacement: '[redacted]' },
|
|
35
|
+
{ pattern: /\bAIza[A-Za-z0-9_-]{35}\b/g, replacement: '[redacted]' },
|
|
36
|
+
{ pattern: /\bAKIA[0-9A-Z]{16}\b/g, replacement: '[redacted]' },
|
|
37
|
+
{ pattern: /\bnpm_[A-Za-z0-9]{36}\b/g, replacement: '[redacted]' },
|
|
38
|
+
{ pattern: /\bxai-[A-Za-z0-9]{16,}\b/g, replacement: '[redacted]' },
|
|
39
|
+
{ pattern: /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g, replacement: '[redacted]' },
|
|
40
|
+
{ pattern: new RegExp(String.raw `\b([a-z][a-z0-9+.-]*:\/\/[^\s:/@]+:)${shapes.urlPassword}@`, 'gi'), replacement: '$1[redacted]@' },
|
|
41
|
+
{ pattern: /\bbearer\s+[A-Za-z0-9._~+/=-]+/gi, replacement: 'bearer [redacted]' },
|
|
42
|
+
{ pattern: new RegExp(String.raw `\bauthorization:\s*${shapes.authorizationValue}`, 'gi'), replacement: 'authorization: [redacted]' },
|
|
43
|
+
shapes.credentialAssignment,
|
|
44
|
+
];
|
|
45
|
+
export const SECRET_REDACTION_RULES = secretRedactionRules(DISPLAYED_SECRET_SHAPES);
|
|
46
|
+
const CUT_OFF_TEXT_REDACTION_RULES = secretRedactionRules(CUT_OFF_SECRET_SHAPES);
|
|
47
|
+
const HIGH_ENTROPY_RULE = { pattern: /[A-Za-z0-9+/]{40,}={0,2}/g, replacement: '[redacted]' };
|
|
48
|
+
const applyRedactionRules = (rules, text) => rules.reduce((acc, rule) => acc.replace(rule.pattern, rule.replacement), text);
|
|
49
|
+
export const redactSecrets = (text) => applyRedactionRules(SECRET_REDACTION_RULES, text);
|
|
50
|
+
export const redactSecretsFromContent = (text) => applyRedactionRules(CUT_OFF_TEXT_REDACTION_RULES, text);
|
|
51
|
+
export const redactSecretsDeep = (text) => redactSecrets(text).replace(HIGH_ENTROPY_RULE.pattern, HIGH_ENTROPY_RULE.replacement);
|
|
@@ -1,38 +1,38 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
handleBell
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-IPVKH2ST.js";
|
|
5
5
|
import {
|
|
6
6
|
readHookInput
|
|
7
|
-
} from "../chunk-
|
|
8
|
-
import "../chunk-
|
|
7
|
+
} from "../chunk-KGDWDSNL.js";
|
|
8
|
+
import "../chunk-JZTHGAPA.js";
|
|
9
9
|
import "../chunk-SGZJ5LYH.js";
|
|
10
|
-
import "../chunk-
|
|
11
|
-
import "../chunk-
|
|
12
|
-
import "../chunk-
|
|
13
|
-
import "../chunk-
|
|
14
|
-
import "../chunk-
|
|
15
|
-
import "../chunk-
|
|
16
|
-
import "../chunk-
|
|
17
|
-
import "../chunk-
|
|
18
|
-
import "../chunk-
|
|
19
|
-
import "../chunk-
|
|
10
|
+
import "../chunk-EYK3GSRH.js";
|
|
11
|
+
import "../chunk-ZVSKMPBZ.js";
|
|
12
|
+
import "../chunk-C2WCPBF7.js";
|
|
13
|
+
import "../chunk-6J2JC2RT.js";
|
|
14
|
+
import "../chunk-WE2J62NC.js";
|
|
15
|
+
import "../chunk-3EVPNIBE.js";
|
|
16
|
+
import "../chunk-OKXS7WDZ.js";
|
|
17
|
+
import "../chunk-MPWXGONV.js";
|
|
18
|
+
import "../chunk-SAXBC4AZ.js";
|
|
19
|
+
import "../chunk-OLQRRFBX.js";
|
|
20
20
|
import "../chunk-XHKBHWLX.js";
|
|
21
|
-
import "../chunk-
|
|
22
|
-
import "../chunk-
|
|
21
|
+
import "../chunk-EPCXUP3P.js";
|
|
22
|
+
import "../chunk-CVQYGMSR.js";
|
|
23
23
|
import "../chunk-POFBE6ZY.js";
|
|
24
24
|
import "../chunk-GMXKITVA.js";
|
|
25
|
-
import "../chunk-
|
|
26
|
-
import "../chunk-
|
|
27
|
-
import "../chunk-
|
|
25
|
+
import "../chunk-P7WQEVWA.js";
|
|
26
|
+
import "../chunk-2OY3ZZ5N.js";
|
|
27
|
+
import "../chunk-LXQ5FBBD.js";
|
|
28
28
|
import "../chunk-7QLSKOSU.js";
|
|
29
29
|
import "../chunk-KZERVKTD.js";
|
|
30
|
-
import "../chunk-
|
|
31
|
-
import "../chunk-
|
|
30
|
+
import "../chunk-DB3ONZB4.js";
|
|
31
|
+
import "../chunk-A2A2YTMG.js";
|
|
32
32
|
import "../chunk-T7E75EKA.js";
|
|
33
|
-
import "../chunk-
|
|
34
|
-
import "../chunk-
|
|
35
|
-
import "../chunk-
|
|
33
|
+
import "../chunk-GPEGOGRJ.js";
|
|
34
|
+
import "../chunk-E4FJTUH4.js";
|
|
35
|
+
import "../chunk-NQTHFF4W.js";
|
|
36
36
|
|
|
37
37
|
// bin/pushary-bell-hook.ts
|
|
38
38
|
var main = async () => {
|
package/dist/bin/pushary-bell.js
CHANGED
|
@@ -5,37 +5,37 @@ import {
|
|
|
5
5
|
liveAgentCount,
|
|
6
6
|
ring,
|
|
7
7
|
upgradeThreshold
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-IPVKH2ST.js";
|
|
9
9
|
import {
|
|
10
10
|
addBellHooks,
|
|
11
11
|
bellInstalled,
|
|
12
12
|
removeBellHooks
|
|
13
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-OKXS7WDZ.js";
|
|
14
14
|
import {
|
|
15
15
|
createIo
|
|
16
16
|
} from "../chunk-U4TMAANR.js";
|
|
17
17
|
import {
|
|
18
18
|
exitOnHelpFlag
|
|
19
|
-
} from "../chunk-
|
|
19
|
+
} from "../chunk-HZVVNGEW.js";
|
|
20
20
|
import {
|
|
21
21
|
parseFlags
|
|
22
22
|
} from "../chunk-GMXKITVA.js";
|
|
23
|
-
import "../chunk-
|
|
23
|
+
import "../chunk-P7WQEVWA.js";
|
|
24
24
|
import "../chunk-7QLSKOSU.js";
|
|
25
25
|
import {
|
|
26
26
|
EXIT
|
|
27
27
|
} from "../chunk-KZERVKTD.js";
|
|
28
|
-
import "../chunk-
|
|
28
|
+
import "../chunk-DB3ONZB4.js";
|
|
29
29
|
import {
|
|
30
30
|
claudeSettings
|
|
31
|
-
} from "../chunk-
|
|
31
|
+
} from "../chunk-A2A2YTMG.js";
|
|
32
32
|
import {
|
|
33
33
|
readJsonSafe,
|
|
34
34
|
writeJsonAtomic
|
|
35
35
|
} from "../chunk-T7E75EKA.js";
|
|
36
|
-
import "../chunk-
|
|
37
|
-
import "../chunk-
|
|
38
|
-
import "../chunk-
|
|
36
|
+
import "../chunk-GPEGOGRJ.js";
|
|
37
|
+
import "../chunk-E4FJTUH4.js";
|
|
38
|
+
import "../chunk-NQTHFF4W.js";
|
|
39
39
|
|
|
40
40
|
// bin/pushary-bell.ts
|
|
41
41
|
exitOnHelpFlag("bell");
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
describeIdleWindow,
|
|
9
9
|
startProcessOwnership,
|
|
10
10
|
withSpawnProcessOwnership
|
|
11
|
-
} from "../chunk-
|
|
11
|
+
} from "../chunk-ZSZSSJCV.js";
|
|
12
12
|
import {
|
|
13
13
|
announceSubscriptionRequired,
|
|
14
14
|
isDeferAnswer
|
|
@@ -18,24 +18,24 @@ import {
|
|
|
18
18
|
loadSessionKey,
|
|
19
19
|
registerTranscript,
|
|
20
20
|
registeredTranscriptEnabled
|
|
21
|
-
} from "../chunk-
|
|
21
|
+
} from "../chunk-JZTHGAPA.js";
|
|
22
22
|
import "../chunk-SGZJ5LYH.js";
|
|
23
|
-
import "../chunk-
|
|
24
|
-
import "../chunk-
|
|
25
|
-
import "../chunk-
|
|
26
|
-
import "../chunk-
|
|
23
|
+
import "../chunk-EYK3GSRH.js";
|
|
24
|
+
import "../chunk-ZVSKMPBZ.js";
|
|
25
|
+
import "../chunk-C2WCPBF7.js";
|
|
26
|
+
import "../chunk-6J2JC2RT.js";
|
|
27
27
|
import {
|
|
28
28
|
ensureDaemonRunning
|
|
29
|
-
} from "../chunk-
|
|
30
|
-
import "../chunk-
|
|
31
|
-
import "../chunk-
|
|
29
|
+
} from "../chunk-WE2J62NC.js";
|
|
30
|
+
import "../chunk-3EVPNIBE.js";
|
|
31
|
+
import "../chunk-OKXS7WDZ.js";
|
|
32
32
|
import {
|
|
33
33
|
encryptRecord
|
|
34
|
-
} from "../chunk-
|
|
35
|
-
import "../chunk-
|
|
34
|
+
} from "../chunk-MPWXGONV.js";
|
|
35
|
+
import "../chunk-SAXBC4AZ.js";
|
|
36
36
|
import {
|
|
37
37
|
transcriptsEnabled
|
|
38
|
-
} from "../chunk-
|
|
38
|
+
} from "../chunk-OLQRRFBX.js";
|
|
39
39
|
import {
|
|
40
40
|
needsShell,
|
|
41
41
|
spawnClaude
|
|
@@ -50,7 +50,7 @@ import {
|
|
|
50
50
|
repoKeyFor,
|
|
51
51
|
reportEvent,
|
|
52
52
|
scopePathFor
|
|
53
|
-
} from "../chunk-
|
|
53
|
+
} from "../chunk-CULUZTWQ.js";
|
|
54
54
|
import {
|
|
55
55
|
DEFAULT_SESSION,
|
|
56
56
|
markPendingCommandDelivered,
|
|
@@ -60,7 +60,7 @@ import {
|
|
|
60
60
|
removePendingCommand,
|
|
61
61
|
savePendingCommand
|
|
62
62
|
} from "../chunk-N6IOSZOE.js";
|
|
63
|
-
import "../chunk-
|
|
63
|
+
import "../chunk-EPCXUP3P.js";
|
|
64
64
|
import {
|
|
65
65
|
DECISION_STOP_REASON,
|
|
66
66
|
UNVERIFIABLE_APPROVAL_REASON,
|
|
@@ -71,36 +71,36 @@ import {
|
|
|
71
71
|
nextLongPollMs,
|
|
72
72
|
waitForAnswer,
|
|
73
73
|
withdrawQuestion
|
|
74
|
-
} from "../chunk-
|
|
75
|
-
import "../chunk-
|
|
74
|
+
} from "../chunk-NGDD6TXY.js";
|
|
75
|
+
import "../chunk-CVQYGMSR.js";
|
|
76
76
|
import "../chunk-POFBE6ZY.js";
|
|
77
77
|
import "../chunk-GMXKITVA.js";
|
|
78
|
-
import "../chunk-
|
|
78
|
+
import "../chunk-P7WQEVWA.js";
|
|
79
79
|
import {
|
|
80
80
|
SubscriptionRequiredError
|
|
81
|
-
} from "../chunk-
|
|
82
|
-
import "../chunk-
|
|
83
|
-
import "../chunk-
|
|
81
|
+
} from "../chunk-M5ICYGHT.js";
|
|
82
|
+
import "../chunk-2ABTSGFT.js";
|
|
83
|
+
import "../chunk-2OY3ZZ5N.js";
|
|
84
84
|
import {
|
|
85
85
|
getMachineId
|
|
86
|
-
} from "../chunk-
|
|
86
|
+
} from "../chunk-LXQ5FBBD.js";
|
|
87
87
|
import "../chunk-7QLSKOSU.js";
|
|
88
88
|
import "../chunk-KZERVKTD.js";
|
|
89
|
-
import "../chunk-
|
|
90
|
-
import "../chunk-
|
|
89
|
+
import "../chunk-DB3ONZB4.js";
|
|
90
|
+
import "../chunk-A2A2YTMG.js";
|
|
91
91
|
import "../chunk-T7E75EKA.js";
|
|
92
92
|
import {
|
|
93
93
|
getApiKey,
|
|
94
94
|
getBaseUrl
|
|
95
|
-
} from "../chunk-
|
|
95
|
+
} from "../chunk-GPEGOGRJ.js";
|
|
96
96
|
import {
|
|
97
97
|
NPX_LATEST_COMMAND
|
|
98
|
-
} from "../chunk-
|
|
98
|
+
} from "../chunk-E4FJTUH4.js";
|
|
99
99
|
import {
|
|
100
100
|
KILL_REASON,
|
|
101
101
|
redactSecretsFromContent,
|
|
102
102
|
resolveGate
|
|
103
|
-
} from "../chunk-
|
|
103
|
+
} from "../chunk-NQTHFF4W.js";
|
|
104
104
|
|
|
105
105
|
// src/wrapper/localPassthrough.ts
|
|
106
106
|
var SIGNAL_NUMBERS = {
|