@pushary/agent-hooks 0.95.4 → 0.95.6
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 +14 -0
- package/data/cursor-plugin/.cursor-plugin/plugin.json +1 -1
- package/data/cursor-plugin/CHANGELOG.md +5 -0
- package/data/cursor-plugin/README.md +1 -1
- package/data/cursor-plugin/scripts/pushary-gate.mjs +5 -2
- package/data/vscode-plugin/.claude-plugin/plugin.json +1 -1
- package/data/vscode-plugin/CHANGELOG.md +5 -0
- package/data/vscode-plugin/README.md +1 -1
- package/data/vscode-plugin/scripts/pushary-gate.mjs +14 -3
- package/dist/bin/pushary-bell-hook.js +20 -20
- package/dist/bin/pushary-bell.js +9 -9
- package/dist/bin/pushary-claude.js +29 -24
- package/dist/bin/pushary-clean.js +20 -20
- package/dist/bin/pushary-codex-bridge.js +10 -10
- package/dist/bin/pushary-codex-hook.js +24 -24
- package/dist/bin/pushary-codex.js +8 -8
- package/dist/bin/pushary-connect.js +8 -8
- package/dist/bin/pushary-cowork.js +5 -5
- package/dist/bin/pushary-daemon.js +26 -26
- package/dist/bin/pushary-disconnect.js +11 -10
- package/dist/bin/pushary-doctor.js +89 -35
- package/dist/bin/pushary-elicitation-hook.js +20 -20
- package/dist/bin/pushary-gemini-bridge.js +9 -9
- package/dist/bin/pushary-gemini-hook.js +23 -23
- package/dist/bin/pushary-hook.js +27 -27
- package/dist/bin/pushary-login.js +9 -9
- package/dist/bin/pushary-logout.js +6 -6
- package/dist/bin/pushary-mode.js +5 -5
- package/dist/bin/pushary-notification-hook.js +22 -22
- package/dist/bin/pushary-opencode-hook.js +23 -23
- package/dist/bin/pushary-permission-denied-hook.js +25 -25
- package/dist/bin/pushary-permission-hook.js +25 -25
- package/dist/bin/pushary-post-hook.js +22 -22
- package/dist/bin/pushary-prompt-hook.js +22 -22
- package/dist/bin/pushary-session-end-hook.js +22 -22
- package/dist/bin/pushary-session-start-hook.js +25 -25
- package/dist/bin/pushary-setup.js +62 -42
- package/dist/bin/pushary-stats.js +4 -4
- package/dist/bin/pushary-status.js +14 -10
- package/dist/bin/pushary-stop-hook.js +22 -22
- package/dist/bin/pushary-stopfailure-hook.js +22 -22
- package/dist/bin/pushary-suggestions.js +2 -2
- package/dist/bin/pushary-transcript-register.js +18 -18
- package/dist/bin/pushary-transcripts.js +7 -7
- package/dist/bin/pushary-upgrade.js +17 -17
- package/dist/bin/pushary-wait.js +5 -5
- package/dist/bin/pushary.js +1 -1
- package/dist/{chunk-EEJ6EQMI.js → chunk-32WFHA77.js} +1 -1
- package/dist/{chunk-YE37HYN3.js → chunk-32WWVRXN.js} +3 -14
- package/dist/{chunk-GGX5QTBG.js → chunk-3AJIK5AO.js} +4 -1
- package/dist/{chunk-PFRLYYF6.js → chunk-43TFQOAT.js} +1 -1
- package/dist/{chunk-MDDKA4QM.js → chunk-4XFBO3GW.js} +1 -1
- package/dist/{chunk-KT2CGUOE.js → chunk-6II5RBAS.js} +1 -1
- package/dist/{chunk-3N4FT4WQ.js → chunk-6MRPTYYH.js} +1 -1
- package/dist/{chunk-ND52YE7L.js → chunk-7N3D4GN7.js} +4 -4
- package/dist/{chunk-TMOCSYJK.js → chunk-A2M6FGUF.js} +3 -3
- package/dist/{chunk-HPM47TEO.js → chunk-AXECWTTZ.js} +2 -2
- package/dist/{chunk-MZOTKCNZ.js → chunk-BS5XR4J7.js} +4 -4
- package/dist/{chunk-O7ODXFII.js → chunk-C7BFOC35.js} +2 -2
- package/dist/{chunk-TKA2L2BU.js → chunk-CDBTCEKE.js} +5 -5
- package/dist/{chunk-JDNW6FTV.js → chunk-DH4INZW3.js} +1 -1
- package/dist/{chunk-6BNBW3M2.js → chunk-DSCGKZO5.js} +2 -2
- package/dist/{chunk-W5GH5GTX.js → chunk-FBO5WS3D.js} +1 -1
- package/dist/{chunk-U24ERDPE.js → chunk-FHIVWF4B.js} +13 -15
- package/dist/{chunk-HTWQH3VI.js → chunk-FVTFSYKB.js} +1 -1
- package/dist/{chunk-HJYGC7IR.js → chunk-GOPIMNVC.js} +1 -1
- package/dist/{chunk-DLLAWCQB.js → chunk-GOQHN2UH.js} +1 -1
- package/dist/{chunk-LVU3Q43J.js → chunk-HBBQO77U.js} +1 -1
- package/dist/{chunk-CVZP67ST.js → chunk-HHODMHTH.js} +4 -4
- package/dist/{chunk-3OXHYPZG.js → chunk-HKQ6CD32.js} +4 -1
- package/dist/{chunk-TGORRMOU.js → chunk-JZSWA3VT.js} +1 -1
- package/dist/{chunk-MNWDOXX6.js → chunk-KAWLZTRJ.js} +1 -1
- package/dist/{chunk-7W6E3C3I.js → chunk-KNIVXEW4.js} +1 -1
- package/dist/{chunk-D6PRC3YQ.js → chunk-LZQVAEWP.js} +2 -1
- package/dist/{chunk-JAKWHALW.js → chunk-O5RQ7RYJ.js} +90 -18
- package/dist/{chunk-TR6DBXO3.js → chunk-OIZVYUED.js} +1 -1
- package/dist/{chunk-V4G7BQZ6.js → chunk-R4MBUCPQ.js} +1 -1
- package/dist/{chunk-XDHJ4KZJ.js → chunk-RPHXG4HI.js} +2 -2
- package/dist/{chunk-J5KTLGO5.js → chunk-SLVXQOYU.js} +1 -1
- package/dist/{chunk-AGQA72IH.js → chunk-SRFA5BOO.js} +1 -1
- package/dist/{chunk-7VVX6HQG.js → chunk-VZADMT7R.js} +219 -17
- package/dist/{chunk-J6NAWJTQ.js → chunk-WRK6RAA5.js} +47 -4
- package/dist/{chunk-ZKDQ3QRP.js → chunk-WZ63WTAZ.js} +1 -1
- package/dist/{chunk-57NOPUBK.js → chunk-XJ6CXTSB.js} +8 -8
- package/dist/{chunk-4NJURLRP.js → chunk-XKIB2FQY.js} +8 -8
- package/dist/{chunk-2BE7ZVWP.js → chunk-XS33QBJA.js} +15 -3
- package/dist/{chunk-MQO7J2OJ.js → chunk-ZJ6QXXBC.js} +10 -7
- package/dist/{chunk-XIVPHGV4.js → chunk-ZQREURP6.js} +1 -1
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +11 -11
- package/package.json +1 -1
|
@@ -21,6 +21,168 @@ var COWORK_STANDING_INSTRUCTIONS = `Pushary is connected as a custom connector.
|
|
|
21
21
|
- Cancel a question when it is no longer needed. Once this turn ends, reopen Cowork for follow-up work; this connector cannot restart it.
|
|
22
22
|
- If Pushary tools are missing or disabled, report that once and continue within my authorization. Do not claim a notification or approval was delivered.`;
|
|
23
23
|
|
|
24
|
+
// ../contracts/src/agent-manifest.ts
|
|
25
|
+
var defaults = {
|
|
26
|
+
hasStoredIdentity: true,
|
|
27
|
+
hookSource: null,
|
|
28
|
+
policyAgent: null,
|
|
29
|
+
repoAware: false,
|
|
30
|
+
disconnectable: false,
|
|
31
|
+
managedProvider: false,
|
|
32
|
+
enforcement: "cooperative",
|
|
33
|
+
connectVia: "Plain MCP",
|
|
34
|
+
setupCommand: null,
|
|
35
|
+
setupChoice: null,
|
|
36
|
+
setupGuide: "",
|
|
37
|
+
activationGuide: null,
|
|
38
|
+
enforcementDetail: "Cooperative. The agent chooses when to ask; no native permission interception.",
|
|
39
|
+
capabilityNote: "",
|
|
40
|
+
documented: true
|
|
41
|
+
};
|
|
42
|
+
var AGENTS = {
|
|
43
|
+
claude_code: {
|
|
44
|
+
...defaults,
|
|
45
|
+
label: "Claude Code",
|
|
46
|
+
activationGuide: "/docs/agents/guides/claude-code#verify-a-real-approval",
|
|
47
|
+
hookSource: "claude",
|
|
48
|
+
policyAgent: "claude_code",
|
|
49
|
+
repoAware: true,
|
|
50
|
+
disconnectable: true,
|
|
51
|
+
managedProvider: true,
|
|
52
|
+
enforcement: "enforced",
|
|
53
|
+
connectVia: "Native hooks + MCP",
|
|
54
|
+
setupCommand: "npx @pushary/agent-hooks setup",
|
|
55
|
+
enforcementDetail: "Shell, writes and edits, subject to Claude Code permission mode and explicit policy."
|
|
56
|
+
},
|
|
57
|
+
claude_chat: {
|
|
58
|
+
...defaults,
|
|
59
|
+
label: "Claude Chat",
|
|
60
|
+
connectVia: "Custom MCP connector",
|
|
61
|
+
setupGuide: "[Claude.ai and Claude Desktop setup](/docs/agents/guides/claude-desktop)"
|
|
62
|
+
},
|
|
63
|
+
claude_cowork: {
|
|
64
|
+
...defaults,
|
|
65
|
+
label: "Claude Cowork",
|
|
66
|
+
connectVia: "Custom MCP connector + optional Cowork skill",
|
|
67
|
+
setupGuide: "[Cowork setup](/docs/agents/guides/claude-desktop#use-it-in-cowork)",
|
|
68
|
+
enforcementDetail: COWORK_CONNECTOR_LIMIT
|
|
69
|
+
},
|
|
70
|
+
codex: {
|
|
71
|
+
...defaults,
|
|
72
|
+
label: "Codex",
|
|
73
|
+
hookSource: "codex",
|
|
74
|
+
policyAgent: "codex",
|
|
75
|
+
repoAware: true,
|
|
76
|
+
disconnectable: true,
|
|
77
|
+
managedProvider: true,
|
|
78
|
+
enforcement: "enforced",
|
|
79
|
+
connectVia: "Native hooks + MCP",
|
|
80
|
+
setupCommand: "npx @pushary/agent-hooks setup",
|
|
81
|
+
enforcementDetail: "Shell and apply_patch edits through native permission hooks; requires a compatible Codex runtime."
|
|
82
|
+
},
|
|
83
|
+
chatgpt: {
|
|
84
|
+
...defaults,
|
|
85
|
+
label: "ChatGPT",
|
|
86
|
+
connectVia: "Custom MCP connector",
|
|
87
|
+
setupGuide: "[ChatGPT setup](/docs/agents/guides/chatgpt)"
|
|
88
|
+
},
|
|
89
|
+
gemini_cli: {
|
|
90
|
+
...defaults,
|
|
91
|
+
label: "Gemini CLI",
|
|
92
|
+
hookSource: "gemini",
|
|
93
|
+
policyAgent: "gemini_cli",
|
|
94
|
+
repoAware: true,
|
|
95
|
+
disconnectable: true,
|
|
96
|
+
managedProvider: true,
|
|
97
|
+
enforcement: "enforced",
|
|
98
|
+
connectVia: "Native hooks + MCP",
|
|
99
|
+
setupCommand: "npx @pushary/agent-hooks setup",
|
|
100
|
+
enforcementDetail: "Shell, writes and edits through native BeforeTool hooks."
|
|
101
|
+
},
|
|
102
|
+
hermes: {
|
|
103
|
+
...defaults,
|
|
104
|
+
label: "Hermes",
|
|
105
|
+
policyAgent: "hermes",
|
|
106
|
+
enforcement: "enforced",
|
|
107
|
+
connectVia: "Native Python plugin + approval transport",
|
|
108
|
+
setupCommand: "npx @pushary/agent-hooks setup",
|
|
109
|
+
enforcementDetail: "Hermes dangerous-command approvals when the Pushary transport is selected; optional PUSHARY_GATE_TOOLS gates named tools.",
|
|
110
|
+
capabilityNote: "Uses the Python plugin, not a macOS bridge HookSource. CLI disconnect and managed-provider controls are not implemented for Hermes."
|
|
111
|
+
},
|
|
112
|
+
cursor: {
|
|
113
|
+
...defaults,
|
|
114
|
+
label: "Cursor",
|
|
115
|
+
hookSource: "cursor",
|
|
116
|
+
policyAgent: "cursor",
|
|
117
|
+
disconnectable: true,
|
|
118
|
+
enforcement: "enforced",
|
|
119
|
+
connectVia: "Editor plugin hooks + MCP",
|
|
120
|
+
setupCommand: "npx @pushary/agent-hooks setup",
|
|
121
|
+
enforcementDetail: "With installed hooks: shell, MCP execution and Write/Delete/Edit tool calls. Plain MCP remains cooperative."
|
|
122
|
+
},
|
|
123
|
+
vscode: {
|
|
124
|
+
...defaults,
|
|
125
|
+
label: "VS Code",
|
|
126
|
+
hookSource: "vscode",
|
|
127
|
+
policyAgent: "vscode",
|
|
128
|
+
enforcement: "enforced",
|
|
129
|
+
connectVia: "Agent plugin hooks + MCP",
|
|
130
|
+
setupCommand: "npx @pushary/agent-hooks setup",
|
|
131
|
+
enforcementDetail: "PreToolUse approval hooks from the installed agent plugin; the host decides which events it exposes.",
|
|
132
|
+
capabilityNote: "Has both a bridge HookSource and a per-agent policy profile. CLI disconnect and managed-provider controls are not implemented for VS Code."
|
|
133
|
+
},
|
|
134
|
+
opencode: {
|
|
135
|
+
...defaults,
|
|
136
|
+
label: "OpenCode",
|
|
137
|
+
hookSource: "opencode",
|
|
138
|
+
policyAgent: "opencode",
|
|
139
|
+
repoAware: true,
|
|
140
|
+
disconnectable: true,
|
|
141
|
+
enforcement: "enforced",
|
|
142
|
+
connectVia: "Generated plugin + MCP",
|
|
143
|
+
setupCommand: "npx @pushary/agent-hooks setup",
|
|
144
|
+
enforcementDetail: "Shell, writes, edits and web fetches when OpenCode itself asks for permission."
|
|
145
|
+
},
|
|
146
|
+
windsurf: {
|
|
147
|
+
...defaults,
|
|
148
|
+
label: "Windsurf",
|
|
149
|
+
setupCommand: "npx @pushary/agent-hooks setup",
|
|
150
|
+
setupChoice: "Other"
|
|
151
|
+
},
|
|
152
|
+
unknown: {
|
|
153
|
+
...defaults,
|
|
154
|
+
label: "Agent",
|
|
155
|
+
documented: false
|
|
156
|
+
},
|
|
157
|
+
lovable: {
|
|
158
|
+
...defaults,
|
|
159
|
+
label: "Lovable",
|
|
160
|
+
setupGuide: "[Lovable setup](/docs/agents/guides/lovable)"
|
|
161
|
+
},
|
|
162
|
+
mcp: {
|
|
163
|
+
...defaults,
|
|
164
|
+
hasStoredIdentity: false,
|
|
165
|
+
label: "Any MCP client",
|
|
166
|
+
setupCommand: "npx @pushary/agent-hooks setup",
|
|
167
|
+
setupChoice: "Other"
|
|
168
|
+
},
|
|
169
|
+
http: {
|
|
170
|
+
...defaults,
|
|
171
|
+
hasStoredIdentity: false,
|
|
172
|
+
label: "No-code and HTTP",
|
|
173
|
+
connectVia: "REST with a Bearer token",
|
|
174
|
+
setupGuide: "[Connect any agent](/docs/agents/connect-any-agent)"
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
var HOOK_SOURCES = Object.freeze(Object.values(AGENTS).flatMap((agent) => agent.hookSource === null ? [] : [agent.hookSource]));
|
|
178
|
+
var POLICY_AGENTS = [...Object.values(AGENTS).flatMap((agent) => agent.policyAgent === null ? [] : [agent.policyAgent]), "*"];
|
|
179
|
+
var AGENT_LABELS_BY_TYPE = Object.fromEntries(
|
|
180
|
+
Object.entries(AGENTS).flatMap(([id, agent]) => agent.hasStoredIdentity ? [[id, agent.label]] : [])
|
|
181
|
+
);
|
|
182
|
+
var DISCONNECTABLE_AGENTS = Object.freeze(Object.values(AGENTS).flatMap((agent) => agent.disconnectable ? [agent.hookSource] : []));
|
|
183
|
+
var REPO_AWARE_AGENTS = Object.freeze(Object.values(AGENTS).flatMap((agent) => agent.repoAware ? [agent.policyAgent] : []));
|
|
184
|
+
var MANAGED_PROVIDERS = Object.freeze(Object.values(AGENTS).flatMap((agent) => agent.managedProvider ? [agent.hookSource] : []));
|
|
185
|
+
|
|
24
186
|
// ../contracts/src/index.ts
|
|
25
187
|
var KEY_SCOPES = ["full_access", "agent", "connector", "bound"];
|
|
26
188
|
var normalizeKeyScope = (value) => typeof value === "string" && KEY_SCOPES.includes(value) ? value : null;
|
|
@@ -140,21 +302,6 @@ var hookWaitDeadline = (startMs, policyWaitSeconds, agent, nowMs) => {
|
|
|
140
302
|
};
|
|
141
303
|
var hookWaitClamped = (startMs, policyWaitSeconds, agent, nowMs) => startMs + hookMaxWaitSeconds(agent) * 1e3 < nowMs + Math.max(policyWaitSeconds, 0) * 1e3;
|
|
142
304
|
var effectiveWaitSeconds = (timeoutAction, policySeconds, agent) => timeoutAction === "wait" ? hookMaxWaitSeconds(agent) : policySeconds;
|
|
143
|
-
var HOOK_SOURCES = ["claude", "codex", "gemini", "cursor", "vscode", "opencode"];
|
|
144
|
-
var AGENT_LABELS_BY_TYPE = {
|
|
145
|
-
claude_code: "Claude Code",
|
|
146
|
-
claude_chat: "Claude Chat",
|
|
147
|
-
claude_cowork: "Claude Cowork",
|
|
148
|
-
codex: "Codex",
|
|
149
|
-
chatgpt: "ChatGPT",
|
|
150
|
-
gemini_cli: "Gemini CLI",
|
|
151
|
-
hermes: "Hermes",
|
|
152
|
-
cursor: "Cursor",
|
|
153
|
-
vscode: "VS Code",
|
|
154
|
-
opencode: "OpenCode",
|
|
155
|
-
windsurf: "Windsurf",
|
|
156
|
-
unknown: "Agent"
|
|
157
|
-
};
|
|
158
305
|
var OPENCODE_APPROVAL_EVENT = "permission.ask";
|
|
159
306
|
var CURSOR_GATE_EVENTS = ["beforeShellExecution", "beforeMCPExecution", "preToolUse"];
|
|
160
307
|
var HOOK_LOCATOR_BINARY = "pushary-bridge";
|
|
@@ -813,6 +960,23 @@ p:12:small=n:1e-7`
|
|
|
813
960
|
}
|
|
814
961
|
];
|
|
815
962
|
var AUTHORIZATION_PERMIT_TTL_SECONDS = 60 * 60;
|
|
963
|
+
var ANSWER_SOURCES = [
|
|
964
|
+
"dashboard",
|
|
965
|
+
"mobile_app",
|
|
966
|
+
"mobile_background",
|
|
967
|
+
"decide_page",
|
|
968
|
+
"live_page",
|
|
969
|
+
"answer_link",
|
|
970
|
+
"inbox",
|
|
971
|
+
"slack",
|
|
972
|
+
"mac_app",
|
|
973
|
+
// Nobody. A decision opened on a workspace's sandbox site is settled by the
|
|
974
|
+
// simulator instead of being delivered, and the ledger has to say so: a
|
|
975
|
+
// sandbox row that looked like a human answer would be indistinguishable
|
|
976
|
+
// evidence of a person who was never asked.
|
|
977
|
+
"sandbox"
|
|
978
|
+
];
|
|
979
|
+
var isAnswerSource = (value) => typeof value === "string" && ANSWER_SOURCES.includes(value);
|
|
816
980
|
var classifyDecisionRisk = (toolName, toolTarget) => {
|
|
817
981
|
const parts = [toolName, toolTarget ?? ""];
|
|
818
982
|
const matchesAny = (patterns) => parts.some((part) => patterns.some((re) => re.test(part)));
|
|
@@ -1111,6 +1275,17 @@ var shouldDeferToNativeMode = (permissionMode, toolName, options = {}) => {
|
|
|
1111
1275
|
var ASKED_IN_EVERY_MODE_TOOLS = ["AskUserQuestion", "ExitPlanMode"];
|
|
1112
1276
|
var ASKED_IN_EVERY_MODE = new Set(ASKED_IN_EVERY_MODE_TOOLS);
|
|
1113
1277
|
var isAskedInEveryMode = (toolName) => ASKED_IN_EVERY_MODE.has(toolName);
|
|
1278
|
+
var PRETOOLUSE_GATED_TOOLS = [
|
|
1279
|
+
"Bash",
|
|
1280
|
+
"Write",
|
|
1281
|
+
"Edit",
|
|
1282
|
+
"MultiEdit",
|
|
1283
|
+
"NotebookEdit",
|
|
1284
|
+
"PowerShell",
|
|
1285
|
+
"Monitor"
|
|
1286
|
+
];
|
|
1287
|
+
var PRETOOLUSE_HANDLED_TOOLS = /* @__PURE__ */ new Set([...PRETOOLUSE_GATED_TOOLS, ...ASKED_IN_EVERY_MODE_TOOLS]);
|
|
1288
|
+
var isPermissionRequestOwnedByPreToolUse = (toolName, permissionMode, defers = shouldDeferToNativeMode) => PRETOOLUSE_HANDLED_TOOLS.has(toolName) && (isAskedInEveryMode(toolName) || !defers(permissionMode, toolName));
|
|
1114
1289
|
var resolveGate = (input) => {
|
|
1115
1290
|
const { modeState, config, toolName, toolInputs, cwd, repoKey, sessionId } = input;
|
|
1116
1291
|
if (isPusharyOwnTool(toolName)) {
|
|
@@ -1368,6 +1543,23 @@ var elicitationContentFromAnswers = (ask, answers) => {
|
|
|
1368
1543
|
return content;
|
|
1369
1544
|
};
|
|
1370
1545
|
|
|
1546
|
+
// ../contracts/src/hook-activation.ts
|
|
1547
|
+
var hookWritePath = (toolName, input) => toolName === "Write" && typeof input.file_path === "string" && input.file_path.startsWith("/") && input.file_path.length <= 4096 ? input.file_path : void 0;
|
|
1548
|
+
var HOOK_ACTIVATION_RESULTS = ["unverified", "approved_executed", "denied_observed", "unexpected_execution", "tool_failed"];
|
|
1549
|
+
var isHookActivationReport = (value) => {
|
|
1550
|
+
if (!value || typeof value !== "object") return false;
|
|
1551
|
+
const report = value;
|
|
1552
|
+
return typeof report.agentType === "string" && typeof report.machineId === "string" && typeof report.target === "string" && report.target.length > 0 && report.target.length <= 4096 && typeof report.truncated === "boolean" && Array.isArray(report.evidence) && report.evidence.length <= 20 && (!report.truncated || report.evidence.length === 0) && report.evidence.every((item) => {
|
|
1553
|
+
if (!item || typeof item !== "object") return false;
|
|
1554
|
+
const row = item;
|
|
1555
|
+
return ["correlationId", "sessionId", "toolUseId", "toolName", "createdAt"].every((key) => typeof row[key] === "string" && row[key].length > 0 && row[key].length <= 256) && (row.answerSource === null || isAnswerSource(row.answerSource)) && HOOK_ACTIVATION_RESULTS.includes(row.result) && Number.isFinite(Date.parse(row.createdAt)) && (row.occurredAt === null || typeof row.occurredAt === "string" && Number.isFinite(Date.parse(row.occurredAt))) && (row.observedAt === null || typeof row.observedAt === "string" && Number.isFinite(Date.parse(row.observedAt))) && (row.result === "unverified" || row.occurredAt !== null && row.observedAt !== null && row.producer !== null && isAnswerSource(row.answerSource) && row.answerSource !== "sandbox") && (row.producer === null || row.producer === "hook" || row.producer === "uplink");
|
|
1556
|
+
});
|
|
1557
|
+
};
|
|
1558
|
+
var hookActivationResult = (report) => {
|
|
1559
|
+
if (report?.evidence.some((row) => row.result === "unexpected_execution")) return "unexpected_execution";
|
|
1560
|
+
return report && !report.truncated && report.evidence.length === 1 ? report.evidence[0].result : "unverified";
|
|
1561
|
+
};
|
|
1562
|
+
|
|
1371
1563
|
export {
|
|
1372
1564
|
CLAUDE_CONNECTOR_URL,
|
|
1373
1565
|
CLAUDE_CONNECTOR_GUIDE,
|
|
@@ -1375,6 +1567,15 @@ export {
|
|
|
1375
1567
|
CLAUDE_CONNECTOR_STEPS,
|
|
1376
1568
|
CLAUDE_CONNECTOR_TEST,
|
|
1377
1569
|
COWORK_STANDING_INSTRUCTIONS,
|
|
1570
|
+
AGENTS,
|
|
1571
|
+
HOOK_SOURCES,
|
|
1572
|
+
AGENT_LABELS_BY_TYPE,
|
|
1573
|
+
DISCONNECTABLE_AGENTS,
|
|
1574
|
+
REPO_AWARE_AGENTS,
|
|
1575
|
+
MANAGED_PROVIDERS,
|
|
1576
|
+
hookWritePath,
|
|
1577
|
+
isHookActivationReport,
|
|
1578
|
+
hookActivationResult,
|
|
1378
1579
|
normalizeKeyScope,
|
|
1379
1580
|
parseAgentQuestion,
|
|
1380
1581
|
parseAgentQuestions,
|
|
@@ -1384,8 +1585,6 @@ export {
|
|
|
1384
1585
|
hookWaitDeadline,
|
|
1385
1586
|
hookWaitClamped,
|
|
1386
1587
|
effectiveWaitSeconds,
|
|
1387
|
-
HOOK_SOURCES,
|
|
1388
|
-
AGENT_LABELS_BY_TYPE,
|
|
1389
1588
|
OPENCODE_APPROVAL_EVENT,
|
|
1390
1589
|
CURSOR_GATE_EVENTS,
|
|
1391
1590
|
HOOK_LOCATOR_BINARY,
|
|
@@ -1399,6 +1598,7 @@ export {
|
|
|
1399
1598
|
DECISION_LINE_MAX,
|
|
1400
1599
|
redactSecrets,
|
|
1401
1600
|
redactSecretsDeep,
|
|
1601
|
+
isAnswerSource,
|
|
1402
1602
|
buildDecisionEpisodeFeatures,
|
|
1403
1603
|
resolveAutoResolveOrigin,
|
|
1404
1604
|
resolvePolicy,
|
|
@@ -1406,6 +1606,8 @@ export {
|
|
|
1406
1606
|
isPusharyOwnTool,
|
|
1407
1607
|
shouldDeferToNativeMode,
|
|
1408
1608
|
ASKED_IN_EVERY_MODE_TOOLS,
|
|
1609
|
+
PRETOOLUSE_GATED_TOOLS,
|
|
1610
|
+
isPermissionRequestOwnedByPreToolUse,
|
|
1409
1611
|
resolveGate,
|
|
1410
1612
|
modeStateFromResponse,
|
|
1411
1613
|
stoppedOutput,
|
|
@@ -1,9 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
detectProviderLiveCapabilities,
|
|
3
|
+
hasSpawnProvider,
|
|
4
|
+
resolveControlPolicy
|
|
5
|
+
} from "./chunk-HKQ6CD32.js";
|
|
6
|
+
import {
|
|
7
|
+
daemonHasRemoteProof,
|
|
8
|
+
daemonServiceManagerAvailable,
|
|
9
|
+
hasDaemonServiceDefinition,
|
|
10
|
+
readDaemonNeedsLogin,
|
|
11
|
+
readDaemonStatus
|
|
12
|
+
} from "./chunk-7N3D4GN7.js";
|
|
1
13
|
import {
|
|
2
14
|
getMachineId
|
|
3
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-C7BFOC35.js";
|
|
4
16
|
import {
|
|
5
17
|
getPackageVersion
|
|
6
18
|
} from "./chunk-DINDL2CF.js";
|
|
19
|
+
import {
|
|
20
|
+
readControlMode,
|
|
21
|
+
readKeySource
|
|
22
|
+
} from "./chunk-6MRPTYYH.js";
|
|
7
23
|
import {
|
|
8
24
|
getBaseUrl
|
|
9
25
|
} from "./chunk-2UMNXADU.js";
|
|
@@ -50,7 +66,7 @@ var parseMachine = (value) => {
|
|
|
50
66
|
online: raw.online === true
|
|
51
67
|
};
|
|
52
68
|
};
|
|
53
|
-
var machineReadiness = (machines, machineId, expectedCapabilities) => {
|
|
69
|
+
var machineReadiness = (machines, machineId, expectedCapabilities, now = Date.now()) => {
|
|
54
70
|
const machine = machines.find((item) => item.machineId === machineId);
|
|
55
71
|
if (!machine) return { kind: "not-ready", detail: "this machine has not heartbeated to the server" };
|
|
56
72
|
if (!machine.online) return { kind: "not-ready", detail: "the server reports this machine offline" };
|
|
@@ -60,12 +76,15 @@ var machineReadiness = (machines, machineId, expectedCapabilities) => {
|
|
|
60
76
|
if (machine.lastControlAt === null || !Number.isFinite(Date.parse(machine.lastControlAt))) {
|
|
61
77
|
return { kind: "not-ready", detail: "the server has not observed this machine polling the control queue" };
|
|
62
78
|
}
|
|
79
|
+
if (!daemonHasRemoteProof({ kind: "running", lastSuccessfulHeartbeatAt: machine.lastSeenAt, lastSuccessfulControlAt: machine.lastControlAt }, now)) {
|
|
80
|
+
return { kind: "not-ready", detail: "the heartbeat or control-queue proof is stale; wake this machine and retry pushary doctor" };
|
|
81
|
+
}
|
|
63
82
|
const missing = expectedCapabilities.filter((capability) => !machine.capabilities.includes(capability));
|
|
64
83
|
return missing.length === 0 ? { kind: "ready", machine } : { kind: "not-ready", detail: `the server is missing capabilities: ${missing.join(", ")}` };
|
|
65
84
|
};
|
|
66
85
|
var readMachineReadiness = async (apiKey, expectedCapabilities, deps = {}) => {
|
|
67
86
|
const listed = await listMachines(apiKey, deps);
|
|
68
|
-
return listed.kind === "ok" ? machineReadiness(listed.machines, deps.machineId ?? getMachineId(), expectedCapabilities) : listed.kind === "unsupported" ? { kind: "unsupported", detail: "the server does not report machine readiness yet" } : listed;
|
|
87
|
+
return listed.kind === "ok" ? machineReadiness(listed.machines, deps.machineId ?? getMachineId(), expectedCapabilities, deps.now?.()) : listed.kind === "unsupported" ? { kind: "unsupported", detail: "the server does not report machine readiness yet" } : listed;
|
|
69
88
|
};
|
|
70
89
|
var waitForMachineReadiness = async (apiKey, expectedCapabilities, deps = {}) => {
|
|
71
90
|
const attempts = deps.attempts ?? 21;
|
|
@@ -106,6 +125,29 @@ var describeLastSeen = (iso, now = Date.now()) => {
|
|
|
106
125
|
if (hours < 48) return `${hours}h ago`;
|
|
107
126
|
return `${Math.round(hours / 24)}d ago`;
|
|
108
127
|
};
|
|
128
|
+
var readManagedControlEvidence = (apiKey, providers, serverProof) => {
|
|
129
|
+
const now = Date.now();
|
|
130
|
+
const daemon = readDaemonStatus();
|
|
131
|
+
const capabilities = detectProviderLiveCapabilities(providers);
|
|
132
|
+
const providerAvailable = hasSpawnProvider(capabilities);
|
|
133
|
+
const managerAvailable = daemonServiceManagerAvailable();
|
|
134
|
+
const serviceInstalled = hasDaemonServiceDefinition();
|
|
135
|
+
const keyCurrent = Boolean(apiKey) && readKeySource().key === apiKey && readDaemonNeedsLogin().kind !== "blocked";
|
|
136
|
+
const policy = resolveControlPolicy({ mode: readControlMode(), providerAvailable, managerAvailable, servicePresent: serviceInstalled || daemon.kind !== "absent" });
|
|
137
|
+
const localProof = daemonHasRemoteProof(daemon, now);
|
|
138
|
+
const remote = serverProof?.kind === "ready" ? machineReadiness([serverProof.machine], daemon.machineId ?? "", ["spawn", ...capabilities], now) : serverProof;
|
|
139
|
+
return {
|
|
140
|
+
ready: keyCurrent && policy === "enabled" && providerAvailable && managerAvailable && serviceInstalled && localProof && remote?.kind === "ready",
|
|
141
|
+
keyCurrent,
|
|
142
|
+
providerAvailable,
|
|
143
|
+
managerAvailable,
|
|
144
|
+
serviceInstalled,
|
|
145
|
+
policy,
|
|
146
|
+
localProof,
|
|
147
|
+
serverProof: remote?.kind ?? "unchecked",
|
|
148
|
+
checkedAt: new Date(now).toISOString()
|
|
149
|
+
};
|
|
150
|
+
};
|
|
109
151
|
|
|
110
152
|
export {
|
|
111
153
|
HEARTBEAT_INTERVAL_MS,
|
|
@@ -113,5 +155,6 @@ export {
|
|
|
113
155
|
readMachineReadiness,
|
|
114
156
|
waitForMachineReadiness,
|
|
115
157
|
listMachines,
|
|
116
|
-
describeLastSeen
|
|
158
|
+
describeLastSeen,
|
|
159
|
+
readManagedControlEvidence
|
|
117
160
|
};
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
detectClaudeVersion
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-OIZVYUED.js";
|
|
4
4
|
import {
|
|
5
5
|
addClaudeMcpServer,
|
|
6
6
|
addPusharyHooks,
|
|
7
7
|
addPusharyToolPermissions
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-HHODMHTH.js";
|
|
9
9
|
import {
|
|
10
10
|
claudeWired,
|
|
11
11
|
codexWired,
|
|
12
12
|
geminiWired
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-A2M6FGUF.js";
|
|
14
14
|
import {
|
|
15
15
|
CLAUDE_HOOK_EVENTS,
|
|
16
16
|
GEMINI_HOOK_BINARY,
|
|
@@ -21,10 +21,10 @@ import {
|
|
|
21
21
|
needsReregistration,
|
|
22
22
|
registrationSignatures,
|
|
23
23
|
supportedClaudeEvents
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-CDBTCEKE.js";
|
|
25
25
|
import {
|
|
26
26
|
guardBinary
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-3AJIK5AO.js";
|
|
28
28
|
import {
|
|
29
29
|
resolveGlobalBinDir,
|
|
30
30
|
resolveGlobalBinary
|
|
@@ -40,14 +40,14 @@ import {
|
|
|
40
40
|
codexHooksJson,
|
|
41
41
|
hasCodexHooks,
|
|
42
42
|
vscodePluginMcp
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-FBO5WS3D.js";
|
|
44
44
|
import {
|
|
45
45
|
readJsonSafe,
|
|
46
46
|
writeJsonAtomic
|
|
47
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-KAWLZTRJ.js";
|
|
48
48
|
import {
|
|
49
49
|
HOOK_LOCATOR_BINARY
|
|
50
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-VZADMT7R.js";
|
|
51
51
|
|
|
52
52
|
// src/reapply.ts
|
|
53
53
|
import { join } from "path";
|
|
@@ -3,19 +3,19 @@ import {
|
|
|
3
3
|
loadPin,
|
|
4
4
|
savePin,
|
|
5
5
|
verifyRecipients
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-WZ63WTAZ.js";
|
|
7
7
|
import {
|
|
8
8
|
hookOwnerOf
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-BS5XR4J7.js";
|
|
10
10
|
import {
|
|
11
11
|
ensureDaemonRunning
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-7N3D4GN7.js";
|
|
13
13
|
import {
|
|
14
14
|
buildTranscriptRecords,
|
|
15
15
|
decodePublicKey,
|
|
16
16
|
generateSessionKey,
|
|
17
17
|
wrapSessionKey
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-DH4INZW3.js";
|
|
19
19
|
import {
|
|
20
20
|
fetchTranscriptRecipients,
|
|
21
21
|
uploadTranscriptRecords
|
|
@@ -23,17 +23,17 @@ import {
|
|
|
23
23
|
import {
|
|
24
24
|
transcriptEnvironmentPreference,
|
|
25
25
|
transcriptsEnabled
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-JZSWA3VT.js";
|
|
27
27
|
import {
|
|
28
28
|
codexHome,
|
|
29
29
|
pusharyDir
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-FBO5WS3D.js";
|
|
31
31
|
import {
|
|
32
32
|
readTranscriptPreference
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-6MRPTYYH.js";
|
|
34
34
|
import {
|
|
35
35
|
writeJsonAtomic
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-KAWLZTRJ.js";
|
|
37
37
|
import {
|
|
38
38
|
getApiKey,
|
|
39
39
|
getBaseUrl
|
|
@@ -12,7 +12,7 @@ import { randomUUID } from "crypto";
|
|
|
12
12
|
var isPolicyConfig = (data) => {
|
|
13
13
|
if (!data || typeof data !== "object") return false;
|
|
14
14
|
const d = data;
|
|
15
|
-
return Array.isArray(d.policies) && typeof d.defaultTimeoutSeconds === "number" && typeof d.defaultTimeoutAction === "string";
|
|
15
|
+
return (d.resolvedAgent === void 0 || typeof d.resolvedAgent === "string") && Array.isArray(d.policies) && typeof d.defaultTimeoutSeconds === "number" && typeof d.defaultTimeoutAction === "string";
|
|
16
16
|
};
|
|
17
17
|
var isAskUserResponse = (data) => {
|
|
18
18
|
if (!data || typeof data !== "object") return false;
|
|
@@ -45,13 +45,24 @@ var waitForAnswer = async (apiKey, correlationId, timeoutMs = 3e4, signal) => {
|
|
|
45
45
|
if (!isWaitForAnswerResponse(result)) throw new Error("Invalid wait_for_answer response");
|
|
46
46
|
return result;
|
|
47
47
|
};
|
|
48
|
+
var WAIT_RESPONSE_GRACE_MS = 2e3;
|
|
49
|
+
var MIN_LONG_POLL_MS = 1e3;
|
|
50
|
+
var MAX_LONG_POLL_MS = 3e4;
|
|
51
|
+
var nextLongPollMs = (deadlineMs, nowMs) => {
|
|
52
|
+
const hold = Math.min(deadlineMs - nowMs - WAIT_RESPONSE_GRACE_MS, MAX_LONG_POLL_MS);
|
|
53
|
+
return hold >= MIN_LONG_POLL_MS ? hold : null;
|
|
54
|
+
};
|
|
48
55
|
var pollForAnswer = async (apiKey, correlationId, deadlineMs, pollInterval = 2e3) => {
|
|
49
56
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
50
57
|
while (Date.now() < deadlineMs) {
|
|
51
|
-
const
|
|
58
|
+
const hold = nextLongPollMs(deadlineMs, Date.now());
|
|
59
|
+
if (hold === null) {
|
|
60
|
+
await sleep(Math.max(0, deadlineMs - Date.now()));
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
52
63
|
let answer;
|
|
53
64
|
try {
|
|
54
|
-
answer = await waitForAnswer(apiKey, correlationId,
|
|
65
|
+
answer = await waitForAnswer(apiKey, correlationId, hold, AbortSignal.timeout(Math.max(1, deadlineMs - Date.now())));
|
|
55
66
|
} catch {
|
|
56
67
|
const late = await withdrawQuestion(apiKey, correlationId);
|
|
57
68
|
return late.answered ? late : STOPPED;
|
|
@@ -93,6 +104,7 @@ export {
|
|
|
93
104
|
isLocalQuestionHandoff,
|
|
94
105
|
askUser,
|
|
95
106
|
waitForAnswer,
|
|
107
|
+
nextLongPollMs,
|
|
96
108
|
cancelQuestion,
|
|
97
109
|
withdrawQuestion,
|
|
98
110
|
waitForQuestion,
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
isPolicyConfig,
|
|
4
4
|
sendNotification,
|
|
5
5
|
waitForAnswer
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-XS33QBJA.js";
|
|
7
7
|
import {
|
|
8
8
|
AGENT_IDENTITIES,
|
|
9
9
|
TEAMMATE_IDLE_ACTION,
|
|
@@ -24,20 +24,20 @@ import {
|
|
|
24
24
|
summarizeStop,
|
|
25
25
|
taskTitleFrom,
|
|
26
26
|
toolResultErrorText
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-HBBQO77U.js";
|
|
28
28
|
import {
|
|
29
29
|
NOTIFICATION_PUSH_TYPES,
|
|
30
30
|
POSTTOOLUSE_MIRROR_ONLY_TOOLS
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-32WWVRXN.js";
|
|
32
32
|
import {
|
|
33
33
|
getMachineId
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-C7BFOC35.js";
|
|
35
35
|
import {
|
|
36
36
|
withRetry
|
|
37
37
|
} from "./chunk-EYRGBYZG.js";
|
|
38
38
|
import {
|
|
39
39
|
reportedInstallSource
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-KAWLZTRJ.js";
|
|
41
41
|
import {
|
|
42
42
|
getApiKey,
|
|
43
43
|
getBaseUrl
|
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
import {
|
|
46
46
|
HOOK_SOURCES,
|
|
47
47
|
PENDING_COMMAND_PREFIX,
|
|
48
|
+
REPO_AWARE_AGENTS,
|
|
48
49
|
gateOutputFor,
|
|
49
50
|
isAutoApprove,
|
|
50
51
|
localRepoKey,
|
|
@@ -53,7 +54,7 @@ import {
|
|
|
53
54
|
pendingCommandEvents,
|
|
54
55
|
resolveAutoResolveOrigin,
|
|
55
56
|
resolvePolicy
|
|
56
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-VZADMT7R.js";
|
|
57
58
|
|
|
58
59
|
// src/policy.ts
|
|
59
60
|
import { createHash } from "crypto";
|
|
@@ -62,7 +63,6 @@ import { join } from "path";
|
|
|
62
63
|
import { tmpdir } from "os";
|
|
63
64
|
var CACHE_TTL_MS = 60 * 1e3;
|
|
64
65
|
var STALE_CACHE_MAX_MS = 12 * 60 * 60 * 1e3;
|
|
65
|
-
var REPO_AWARE_AGENTS = ["claude_code", "codex", "gemini_cli", "opencode"];
|
|
66
66
|
var policyRequestFor = (agentType) => ({
|
|
67
67
|
agent: agentType,
|
|
68
68
|
repoAware: REPO_AWARE_AGENTS.includes(agentType)
|
|
@@ -1004,6 +1004,7 @@ var settleQuestionsForToolUse = async (sessionId, toolUseId) => {
|
|
|
1004
1004
|
for (const answer of late) removePendingQuestion(sessionId, answer.correlationId);
|
|
1005
1005
|
};
|
|
1006
1006
|
var handlePostToolUse = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
1007
|
+
const occurredAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1007
1008
|
const deadline = Date.now() + HOOK_BUDGET_MS;
|
|
1008
1009
|
const signal = AbortSignal.timeout(HOOK_BUDGET_MS);
|
|
1009
1010
|
try {
|
|
@@ -1028,6 +1029,8 @@ var handlePostToolUse = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
|
1028
1029
|
const beacon = !isMirrorOnly && decisionSource === "policy_auto" && throttlePass(`autodecision:${sessionKey}:${lookup.tool}`, AUTO_DECISION_WINDOW_MS) ? deriveAutoDecisionBeacon(lookup.tool, lookup.input, liveMode, agent.type, input.cwd, input.session_id) : void 0;
|
|
1029
1030
|
const toolReport = reportEvent({
|
|
1030
1031
|
event: isError ? "tool_error" : "tool_complete",
|
|
1032
|
+
occurredAt,
|
|
1033
|
+
toolUseId: input.tool_use_id,
|
|
1031
1034
|
agentType: agent.type,
|
|
1032
1035
|
agentName: `${agent.label} - ${projectName}`,
|
|
1033
1036
|
action,
|
package/dist/src/index.d.ts
CHANGED
|
@@ -34,6 +34,8 @@ interface AgentIdentity {
|
|
|
34
34
|
readonly label: string;
|
|
35
35
|
}
|
|
36
36
|
interface AgentEvent {
|
|
37
|
+
occurredAt?: string;
|
|
38
|
+
toolUseId?: string;
|
|
37
39
|
event: string;
|
|
38
40
|
agentType: string;
|
|
39
41
|
agentName?: string;
|
|
@@ -147,6 +149,7 @@ interface AskUserParams {
|
|
|
147
149
|
machineId?: string;
|
|
148
150
|
toolName?: string;
|
|
149
151
|
toolTarget?: string;
|
|
152
|
+
toolPath?: string;
|
|
150
153
|
repoKey?: string;
|
|
151
154
|
intent?: string;
|
|
152
155
|
action?: string;
|