@pushary/agent-hooks 1.9.0 → 1.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/data/cursor-plugin/.cursor-plugin/plugin.json +1 -1
  3. package/data/cursor-plugin/CHANGELOG.md +4 -0
  4. package/data/cursor-plugin/scripts/pushary-gate.mjs +1 -1
  5. package/data/vscode-plugin/.claude-plugin/plugin.json +1 -1
  6. package/data/vscode-plugin/CHANGELOG.md +4 -0
  7. package/data/vscode-plugin/scripts/pushary-gate.mjs +1 -1
  8. package/dist/bin/pushary-bell-hook.js +23 -23
  9. package/dist/bin/pushary-bell.js +9 -9
  10. package/dist/bin/pushary-claude.js +26 -26
  11. package/dist/bin/pushary-clean.js +28 -28
  12. package/dist/bin/pushary-codex-bridge.js +18 -18
  13. package/dist/bin/pushary-codex-hook.js +31 -31
  14. package/dist/bin/pushary-codex.js +13 -13
  15. package/dist/bin/pushary-connect.js +13 -13
  16. package/dist/bin/pushary-cowork.js +5 -5
  17. package/dist/bin/pushary-daemon.js +26 -26
  18. package/dist/bin/pushary-disconnect.js +18 -18
  19. package/dist/bin/pushary-doctor.js +99 -48
  20. package/dist/bin/pushary-elicitation-hook.js +25 -25
  21. package/dist/bin/pushary-gemini-bridge.js +13 -13
  22. package/dist/bin/pushary-gemini-hook.js +28 -28
  23. package/dist/bin/pushary-hook.js +32 -32
  24. package/dist/bin/pushary-login.js +26 -23
  25. package/dist/bin/pushary-logout.js +7 -7
  26. package/dist/bin/pushary-mcp.js +9 -9
  27. package/dist/bin/pushary-mode.js +9 -9
  28. package/dist/bin/pushary-notification-hook.js +28 -28
  29. package/dist/bin/pushary-opencode-hook.js +27 -27
  30. package/dist/bin/pushary-permission-denied-hook.js +32 -32
  31. package/dist/bin/pushary-permission-hook.js +31 -31
  32. package/dist/bin/pushary-post-hook.js +28 -28
  33. package/dist/bin/pushary-prompt-hook.js +28 -28
  34. package/dist/bin/pushary-session-end-hook.js +28 -28
  35. package/dist/bin/pushary-session-start-hook.js +31 -31
  36. package/dist/bin/pushary-setup.js +69 -52
  37. package/dist/bin/pushary-stats.js +5 -5
  38. package/dist/bin/pushary-status.js +15 -15
  39. package/dist/bin/pushary-stop-hook.js +28 -28
  40. package/dist/bin/pushary-stopfailure-hook.js +28 -28
  41. package/dist/bin/pushary-suggestions.js +4 -4
  42. package/dist/bin/pushary-transcript-register.js +19 -19
  43. package/dist/bin/pushary-transcripts.js +7 -7
  44. package/dist/bin/pushary-upgrade.js +42 -394
  45. package/dist/bin/pushary-wait.js +9 -9
  46. package/dist/bin/pushary.js +6 -6
  47. package/dist/{chunk-7TQQSQZ7.js → chunk-2E4SRGYD.js} +17 -12
  48. package/dist/{chunk-TUZ7WKOF.js → chunk-2XK6D4WL.js} +1 -1
  49. package/dist/{chunk-42E4DE6C.js → chunk-35N53QLA.js} +10 -9
  50. package/dist/{chunk-VV4SBPCQ.js → chunk-3O4EBTR3.js} +1 -1
  51. package/dist/{chunk-XGS2DHGF.js → chunk-4KMTRXNL.js} +2 -2
  52. package/dist/chunk-6S727YUV.js +242 -0
  53. package/dist/{chunk-K75TP4JY.js → chunk-73BH4SZY.js} +2 -2
  54. package/dist/{chunk-SDSKTRIV.js → chunk-ABIW72ST.js} +1 -1
  55. package/dist/{chunk-HHNFGWR5.js → chunk-AL4NHBZ6.js} +1 -1
  56. package/dist/{chunk-YFS4HYCI.js → chunk-B6BLCHJW.js} +3 -3
  57. package/dist/{chunk-JOQEPWDH.js → chunk-BFVE3WPB.js} +2 -2
  58. package/dist/{chunk-IQUBCAEK.js → chunk-BK3R5NRE.js} +1 -1
  59. package/dist/{chunk-ET6QSY3H.js → chunk-CEHDCHXK.js} +1 -1
  60. package/dist/{chunk-P25O4K3J.js → chunk-COVPHB56.js} +7 -5
  61. package/dist/{chunk-MBVV3RX3.js → chunk-CTYCABBH.js} +1 -1
  62. package/dist/{chunk-RZXQFAWR.js → chunk-DKDZXJHZ.js} +1 -1
  63. package/dist/chunk-EO23EUOK.js +14 -0
  64. package/dist/{chunk-CKPDSFY3.js → chunk-ESME4HN2.js} +5 -5
  65. package/dist/{chunk-NAJ3UV4E.js → chunk-EUNYNLDU.js} +3 -3
  66. package/dist/{chunk-MQJWO3AA.js → chunk-FHLRRCUZ.js} +3 -3
  67. package/dist/{chunk-7LLNRCOK.js → chunk-FWQM6V7Z.js} +1 -1
  68. package/dist/{chunk-CFAD2LTH.js → chunk-HLNSTJND.js} +2 -2
  69. package/dist/{chunk-R76C43H7.js → chunk-HZ57E6LS.js} +84 -50
  70. package/dist/{chunk-ZMVLKPT7.js → chunk-HZYUDXIH.js} +5 -5
  71. package/dist/{chunk-OXQKXZJ3.js → chunk-IH5NZMN4.js} +2 -2
  72. package/dist/{chunk-2V64X5RE.js → chunk-IVPVCCFT.js} +1 -1
  73. package/dist/chunk-JXLANQLV.js +175 -0
  74. package/dist/{chunk-OLG6FJV2.js → chunk-KP45FGHD.js} +4 -4
  75. package/dist/{chunk-EG46RJRF.js → chunk-L52OIZXV.js} +1 -1
  76. package/dist/{chunk-IJJ3HHFT.js → chunk-MZXXLIF6.js} +1 -1
  77. package/dist/{chunk-YJZDIFON.js → chunk-N2ATGXI4.js} +2 -2
  78. package/dist/{chunk-WFVNXGZ6.js → chunk-PN3F7LOB.js} +8 -8
  79. package/dist/{chunk-4ZXYWEEH.js → chunk-Q36G3P7I.js} +1 -1
  80. package/dist/{chunk-XXVMUMKT.js → chunk-QDCEEQUS.js} +5 -5
  81. package/dist/{chunk-VYNTRHB6.js → chunk-RTKPR4UA.js} +1 -1
  82. package/dist/{chunk-MBNMO5IR.js → chunk-SFKU5DXZ.js} +2 -2
  83. package/dist/{chunk-JW7DKTT6.js → chunk-SI327OZF.js} +44 -16
  84. package/dist/{chunk-MGXXQHCM.js → chunk-U4DLXAGD.js} +1 -1
  85. package/dist/{chunk-US3RDXK7.js → chunk-UBCTOE5X.js} +2 -2
  86. package/dist/{chunk-4GMZOGH4.js → chunk-UBNJYMTG.js} +7 -6
  87. package/dist/{chunk-HSM5FIA3.js → chunk-UX2YSFKS.js} +1 -1
  88. package/dist/{chunk-P6VDRQF3.js → chunk-V3P2VSX7.js} +3 -3
  89. package/dist/{chunk-HNMMKFYN.js → chunk-VMGLXL74.js} +10 -10
  90. package/dist/{chunk-LQESQPIT.js → chunk-WCHFDVCC.js} +5 -5
  91. package/dist/{chunk-3OFHFVPX.js → chunk-WM2MEFCA.js} +1 -1
  92. package/dist/{chunk-CPBRXBLG.js → chunk-XOXW4D6P.js} +3 -3
  93. package/dist/{chunk-BG4QCOHQ.js → chunk-XXSAGQAV.js} +4 -4
  94. package/dist/{chunk-HQWPMVR4.js → chunk-Y4AUVOR7.js} +3 -3
  95. package/dist/{chunk-75CEJ4WP.js → chunk-Y6DSV2OS.js} +3 -3
  96. package/dist/{chunk-KETBIX7I.js → chunk-Y73RBCQD.js} +1 -1
  97. package/dist/{chunk-4PCF34AB.js → chunk-ZFDGCEKO.js} +89 -24
  98. package/dist/{chunk-ZRHA4PGN.js → chunk-ZNUNWWCN.js} +4 -2
  99. package/dist/{chunk-K7DY2DQN.js → chunk-ZSOFZDLY.js} +6 -6
  100. package/dist/global-upgrade-N24WINE7.js +24 -0
  101. package/dist/paths-53PCHAOJ.js +71 -0
  102. package/dist/{reapply-FYCVOWCW.js → reapply-2SU2ZHEK.js} +8 -8
  103. package/dist/src/index.js +20 -20
  104. package/dist/upgrade-lock-F6SM6IEZ.js +17 -0
  105. package/package.json +1 -1
@@ -2,14 +2,16 @@ import {
2
2
  spawnClaude
3
3
  } from "./chunk-XHKBHWLX.js";
4
4
  import {
5
+ CODEX_HOOK_EVENTS,
6
+ CODEX_REQUIRED_APPROVAL_EVENTS,
5
7
  codexHome,
6
8
  codexHooksJsonIn,
7
9
  isPusharyCodexCommand,
8
10
  resolvePathBinary
9
- } from "./chunk-R76C43H7.js";
11
+ } from "./chunk-HZ57E6LS.js";
10
12
  import {
11
13
  getPackageVersion
12
- } from "./chunk-4PCF34AB.js";
14
+ } from "./chunk-ZFDGCEKO.js";
13
15
 
14
16
  // src/codex-app-server.ts
15
17
  import { existsSync, realpathSync } from "fs";
@@ -20,6 +22,7 @@ var CODEX_HOOK_STATUS = {
20
22
  modified: "modified",
21
23
  managed: "managed",
22
24
  disabled: "disabled",
25
+ asynchronous: "asynchronous",
23
26
  notListed: "not listed"
24
27
  };
25
28
  var CODEX_APP_SERVER_ARGS = ["app-server"];
@@ -42,11 +45,19 @@ var CODEX_NOT_ASKED = {
42
45
  };
43
46
  var UNRECOGNISED_LISTING = "Codex answered hooks/list in a shape Pushary does not recognise";
44
47
  var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
45
- var isCodexListedHook = (value) => isRecord(value) && typeof value.key === "string" && typeof value.eventName === "string" && typeof value.command === "string" && typeof value.sourcePath === "string" && typeof value.enabled === "boolean" && typeof value.isManaged === "boolean" && typeof value.currentHash === "string" && typeof value.trustStatus === "string";
48
+ var hasCodexHookIdentity = (value) => isRecord(value) && typeof value.key === "string" && value.key.length > 0 && typeof value.eventName === "string" && value.eventName.length > 0 && typeof value.sourcePath === "string" && value.sourcePath.length > 0 && typeof value.enabled === "boolean" && typeof value.isManaged === "boolean" && typeof value.currentHash === "string" && value.currentHash.length > 0 && typeof value.trustStatus === "string" && value.trustStatus.length > 0;
49
+ var isCodexListedHook = (value) => hasCodexHookIdentity(value) && (value.handlerType === void 0 || value.handlerType === "command") && typeof value.command === "string" && value.command.length > 0 && (value.async === void 0 || typeof value.async === "boolean");
50
+ var isCodexHookMetadata = (value) => {
51
+ if (isCodexListedHook(value)) return true;
52
+ if (!hasCodexHookIdentity(value)) return false;
53
+ if (value.handlerType === "prompt" || value.handlerType === "agent") return true;
54
+ return value.handlerType === "mcpTool" && typeof value.server === "string" && value.server.length > 0 && typeof value.tool === "string" && value.tool.length > 0;
55
+ };
46
56
  var listedHookFields = (hook) => ({
47
57
  key: hook.key,
48
58
  eventName: hook.eventName,
49
59
  command: hook.command,
60
+ async: hook.async ?? false,
50
61
  sourcePath: hook.sourcePath,
51
62
  enabled: hook.enabled,
52
63
  isManaged: hook.isManaged,
@@ -67,20 +78,17 @@ var hooksListingOf = (result) => {
67
78
  const warnings = [];
68
79
  for (const layer of result.data) {
69
80
  if (!isRecord(layer) || !Array.isArray(layer.hooks)) return null;
81
+ if (!layer.hooks.every(isCodexHookMetadata)) return null;
70
82
  hooks.push(...layer.hooks.filter(isCodexListedHook).map(listedHookFields));
71
83
  warnings.push(...diagnosticMessages(layer.warnings), ...diagnosticMessages(layer.errors));
72
84
  }
73
85
  return { hooks, warnings };
74
86
  };
75
87
  var isPusharyHookIn = (hooksJsonPath, hook) => hook.sourcePath === hooksJsonPath && isPusharyCodexCommand(hook.command);
76
- var isTrustableByPushary = (hook) => hook.enabled && !hook.isManaged && hook.trustStatus !== CODEX_HOOK_STATUS.managed;
88
+ var isTrustableByPushary = (hook) => hook.enabled && !hook.isManaged && hook.trustStatus !== CODEX_HOOK_STATUS.managed && !(CODEX_REQUIRED_APPROVAL_EVENTS.includes(hookEventOf(hook.eventName)) && hook.async === true);
77
89
  var pusharyHooksIn = (hooks, hooksJsonPath) => hooks.filter((hook) => isPusharyHookIn(hooksJsonPath, hook));
78
90
  var selectPusharyCodexHooks = (hooks, hooksJsonPath) => pusharyHooksIn(hooks, hooksJsonPath).filter(isTrustableByPushary);
79
- var codexTrustVerdict = (hooks, hooksJsonPath) => {
80
- if (pusharyHooksIn(hooks, hooksJsonPath).length === 0) return { kind: "unlisted" };
81
- const untrusted = selectPusharyCodexHooks(hooks, hooksJsonPath).filter((hook) => hook.trustStatus !== CODEX_HOOK_STATUS.trusted);
82
- return untrusted.length === 0 ? { kind: "trusted" } : { kind: "untrusted", hooks: untrusted };
83
- };
91
+ var codexTrustVerdict = (hooks, hooksJsonPath) => assessCodexHookTrust(CODEX_HOOK_EVENTS.map((event) => event.event), pusharyHooksIn(hooks, hooksJsonPath));
84
92
  var codexTrustEdit = (hooks) => ({
85
93
  edits: [{
86
94
  keyPath: HOOKS_STATE_KEY_PATH,
@@ -94,16 +102,34 @@ var initializeParams = (clientVersion) => ({
94
102
  });
95
103
  var hooksListParams = (cwd) => ({ cwds: [cwd] });
96
104
  var hookEventOf = (eventName) => eventName.charAt(0).toUpperCase() + eventName.slice(1);
105
+ var trustStatusOf = (hook) => {
106
+ if (!hook.enabled) return CODEX_HOOK_STATUS.disabled;
107
+ if (CODEX_REQUIRED_APPROVAL_EVENTS.includes(hookEventOf(hook.eventName)) && hook.async === true) return CODEX_HOOK_STATUS.asynchronous;
108
+ return hook.trustStatus;
109
+ };
97
110
  var readingOf = (hook) => ({
98
111
  event: hookEventOf(hook.eventName),
99
- status: hook.enabled ? hook.trustStatus : CODEX_HOOK_STATUS.disabled
112
+ status: trustStatusOf(hook)
100
113
  });
101
- var codexHookTrustByEvent = (events, hooks) => events.map((event) => hooks.map(readingOf).find((reading) => reading.event === event) ?? { event, status: CODEX_HOOK_STATUS.notListed });
102
- var CODEX_TRUST_FAILURES = /* @__PURE__ */ new Set([CODEX_HOOK_STATUS.untrusted, CODEX_HOOK_STATUS.modified]);
103
- var isCodexTrustFailure = (reading) => CODEX_TRUST_FAILURES.has(reading.status);
114
+ var codexHookTrustByEvent = (events, hooks) => {
115
+ const readings = hooks.map(readingOf);
116
+ const result = [];
117
+ for (const event of events) {
118
+ const matching = readings.filter((reading) => reading.event === event);
119
+ result.push(...matching.length > 0 ? matching : [{ event, status: CODEX_HOOK_STATUS.notListed }]);
120
+ }
121
+ return result;
122
+ };
123
+ var isCodexTrustFailure = (reading) => {
124
+ if (reading.status === CODEX_HOOK_STATUS.trusted || reading.status === CODEX_HOOK_STATUS.managed) return false;
125
+ if (reading.status === CODEX_HOOK_STATUS.disabled || reading.status === CODEX_HOOK_STATUS.notListed) {
126
+ return CODEX_REQUIRED_APPROVAL_EVENTS.includes(reading.event);
127
+ }
128
+ return true;
129
+ };
104
130
  var eventsWithStatus = (readings, status) => readings.filter((reading) => reading.status === status).map((reading) => reading.event);
105
131
  var assessCodexHookTrust = (events, hooks) => {
106
- const readings = codexHookTrustByEvent(events, hooks);
132
+ const readings = codexHookTrustByEvent([.../* @__PURE__ */ new Set([...events, ...CODEX_REQUIRED_APPROVAL_EVENTS])], hooks);
107
133
  const notListed = eventsWithStatus(readings, CODEX_HOOK_STATUS.notListed);
108
134
  if (readings.length > 0 && notListed.length === readings.length) return { kind: "unlisted" };
109
135
  const disabled = eventsWithStatus(readings, CODEX_HOOK_STATUS.disabled);
@@ -265,7 +291,7 @@ var confirmationAfterWrite = (listing, hooksJsonPath, writeError) => {
265
291
  const verdict = codexTrustVerdict(listing.hooks, hooksJsonPath);
266
292
  if (verdict.kind === "trusted") return { kind: "verified", wrote: true };
267
293
  if (verdict.kind === "unlisted") return { kind: "unlisted", warnings: listing.warnings };
268
- return { kind: "refused", hooks: verdict.hooks.map(readingOf), writeError };
294
+ return { kind: "refused", hooks: verdict.failures, writeError };
269
295
  };
270
296
  var trustConversation = (launch, hooksJsonPath) => async (session) => {
271
297
  const unavailable = await openSession(session);
@@ -275,7 +301,9 @@ var trustConversation = (launch, hooksJsonPath) => async (session) => {
275
301
  const verdict = codexTrustVerdict(before.hooks, hooksJsonPath);
276
302
  if (verdict.kind === "trusted") return { kind: "verified", wrote: false };
277
303
  if (verdict.kind === "unlisted") return { kind: "unlisted", warnings: before.warnings };
278
- const written = await session.request(METHOD_CONFIG_BATCH_WRITE, codexTrustEdit(verdict.hooks));
304
+ const trustable = selectPusharyCodexHooks(before.hooks, hooksJsonPath).filter((hook) => hook.trustStatus === CODEX_HOOK_STATUS.untrusted || hook.trustStatus === CODEX_HOOK_STATUS.modified);
305
+ if (trustable.length === 0) return { kind: "refused", hooks: verdict.failures, writeError: null };
306
+ const written = await session.request(METHOD_CONFIG_BATCH_WRITE, codexTrustEdit(trustable));
279
307
  const after = await listHooks(session, launch);
280
308
  if (!isListing(after)) return after;
281
309
  return confirmationAfterWrite(after, hooksJsonPath, written.kind === "error" ? written.message : null);
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  redactSecretsFromContent
3
- } from "./chunk-4PCF34AB.js";
3
+ } from "./chunk-ZFDGCEKO.js";
4
4
 
5
5
  // src/crypto.ts
6
6
  import nacl from "tweetnacl";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  configFilePath
3
- } from "./chunk-EG46RJRF.js";
3
+ } from "./chunk-L52OIZXV.js";
4
4
  import {
5
5
  normalizeInstallSource
6
- } from "./chunk-4PCF34AB.js";
6
+ } from "./chunk-ZFDGCEKO.js";
7
7
 
8
8
  // src/install-source.ts
9
9
  import { readFileSync } from "fs";
@@ -14,18 +14,19 @@ import {
14
14
  } from "./chunk-U4TMAANR.js";
15
15
  import {
16
16
  callMcpTool
17
- } from "./chunk-CPBRXBLG.js";
17
+ } from "./chunk-XOXW4D6P.js";
18
18
  import {
19
19
  reportedInstallSource
20
- } from "./chunk-US3RDXK7.js";
20
+ } from "./chunk-UBCTOE5X.js";
21
21
  import {
22
22
  NPX_LATEST_COMMAND
23
- } from "./chunk-SDSKTRIV.js";
23
+ } from "./chunk-ABIW72ST.js";
24
24
  import {
25
25
  NO_PAIRING_COMPUTER,
26
26
  PAIR_TTL_SECONDS,
27
+ classifyConfirmResponse,
27
28
  isAnswerSource
28
- } from "./chunk-4PCF34AB.js";
29
+ } from "./chunk-ZFDGCEKO.js";
29
30
 
30
31
  // src/reach.ts
31
32
  var reachVerdict = (channels) => {
@@ -206,8 +207,8 @@ var defaultCancel = async (apiKey, correlationId) => {
206
207
  });
207
208
  };
208
209
  var answeredRoundTrip = (answer, correlationId, latencyMs) => {
209
- if (answer.value !== "yes" && answer.value !== "no") {
210
- return { kind: "error", detail: "the server reported an answer without a valid Yes or No value" };
210
+ if (answer.value === void 0 || classifyConfirmResponse(answer.value) === null) {
211
+ return { kind: "error", detail: "the server reported an answer without a valid Yes, No or defer value" };
211
212
  }
212
213
  return {
213
214
  kind: "answered",
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getBaseUrl
3
- } from "./chunk-EG46RJRF.js";
3
+ } from "./chunk-L52OIZXV.js";
4
4
 
5
5
  // src/transcript-api.ts
6
6
  var fetchTranscriptRecipients = async (apiKey, baseUrl = getBaseUrl()) => {
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  readExistingMachineId
3
- } from "./chunk-VV4SBPCQ.js";
3
+ } from "./chunk-3O4EBTR3.js";
4
4
  import {
5
5
  NetworkError
6
6
  } from "./chunk-7QLSKOSU.js";
7
7
  import {
8
8
  getBaseUrl
9
- } from "./chunk-EG46RJRF.js";
9
+ } from "./chunk-L52OIZXV.js";
10
10
  import {
11
11
  clientContextHeaders,
12
12
  getPackageVersion
13
- } from "./chunk-4PCF34AB.js";
13
+ } from "./chunk-ZFDGCEKO.js";
14
14
 
15
15
  // src/cli/net.ts
16
16
  import { createRequire } from "module";
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  activeHookSource,
3
3
  activeIdentity
4
- } from "./chunk-CKPDSFY3.js";
4
+ } from "./chunk-ESME4HN2.js";
5
5
  import {
6
6
  defersToNativeMode,
7
7
  reportMachineDenial
8
- } from "./chunk-YJZDIFON.js";
8
+ } from "./chunk-N2ATGXI4.js";
9
9
  import {
10
10
  isGatingMoment,
11
11
  recordKeylessMoment
12
- } from "./chunk-IJJ3HHFT.js";
12
+ } from "./chunk-MZXXLIF6.js";
13
13
  import {
14
14
  announceSubscriptionRequired,
15
15
  denyReasonFrom,
@@ -39,7 +39,7 @@ import {
39
39
  reportEvent,
40
40
  scopePathFor,
41
41
  settleQuestionsForToolUse
42
- } from "./chunk-42E4DE6C.js";
42
+ } from "./chunk-35N53QLA.js";
43
43
  import {
44
44
  DEFAULT_SESSION
45
45
  } from "./chunk-N6IOSZOE.js";
@@ -55,20 +55,20 @@ import {
55
55
  requestGate,
56
56
  sendNotification,
57
57
  waitForQuestion
58
- } from "./chunk-ZMVLKPT7.js";
58
+ } from "./chunk-HZYUDXIH.js";
59
59
  import {
60
60
  SubscriptionRequiredError
61
- } from "./chunk-CPBRXBLG.js";
61
+ } from "./chunk-XOXW4D6P.js";
62
62
  import {
63
63
  getMachineId
64
- } from "./chunk-VV4SBPCQ.js";
64
+ } from "./chunk-3O4EBTR3.js";
65
65
  import {
66
66
  getApiKey,
67
67
  getBaseUrl
68
- } from "./chunk-EG46RJRF.js";
68
+ } from "./chunk-L52OIZXV.js";
69
69
  import {
70
70
  NPX_LATEST_COMMAND
71
- } from "./chunk-SDSKTRIV.js";
71
+ } from "./chunk-ABIW72ST.js";
72
72
  import {
73
73
  AGENT_QUESTION_STRATEGY,
74
74
  GATE_BLOCK_REASON_MAX_LENGTH,
@@ -96,7 +96,7 @@ import {
96
96
  parseAgentQuestions,
97
97
  resolveGate,
98
98
  stoppedOutput
99
- } from "./chunk-4PCF34AB.js";
99
+ } from "./chunk-ZFDGCEKO.js";
100
100
 
101
101
  // src/claude-permission-rules.ts
102
102
  import { readFileSync, statSync } from "fs";
@@ -4,14 +4,14 @@ import {
4
4
  } from "./chunk-XHKBHWLX.js";
5
5
  import {
6
6
  readControlMode
7
- } from "./chunk-ZRHA4PGN.js";
7
+ } from "./chunk-ZNUNWWCN.js";
8
8
  import {
9
9
  getMachineId
10
- } from "./chunk-VV4SBPCQ.js";
10
+ } from "./chunk-3O4EBTR3.js";
11
11
  import {
12
12
  pusharyDir,
13
13
  resolveGlobalBinary
14
- } from "./chunk-R76C43H7.js";
14
+ } from "./chunk-HZ57E6LS.js";
15
15
  import {
16
16
  readJsonSafe,
17
17
  writeFileAtomic,
@@ -20,14 +20,14 @@ import {
20
20
  } from "./chunk-T7E75EKA.js";
21
21
  import {
22
22
  getApiKey
23
- } from "./chunk-EG46RJRF.js";
23
+ } from "./chunk-L52OIZXV.js";
24
24
  import {
25
25
  CLI_PACKAGE_NAMES,
26
26
  cmdShimTarget,
27
27
  getPackageVersion,
28
28
  globalPackageFolder,
29
29
  globalRootFor
30
- } from "./chunk-4PCF34AB.js";
30
+ } from "./chunk-ZFDGCEKO.js";
31
31
 
32
32
  // src/daemon-lifecycle.ts
33
33
  import { dirname, join, win32 as win32Path } from "path";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  pusharyDir
3
- } from "./chunk-R76C43H7.js";
3
+ } from "./chunk-HZ57E6LS.js";
4
4
  import {
5
5
  readJsonSafe
6
6
  } from "./chunk-T7E75EKA.js";
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  keyCheckFromResponse
3
- } from "./chunk-75CEJ4WP.js";
3
+ } from "./chunk-Y6DSV2OS.js";
4
4
  import {
5
5
  installNetworkDefaults
6
- } from "./chunk-P6VDRQF3.js";
6
+ } from "./chunk-V3P2VSX7.js";
7
7
  import {
8
8
  getBaseUrl
9
- } from "./chunk-EG46RJRF.js";
9
+ } from "./chunk-L52OIZXV.js";
10
10
 
11
11
  // src/retry.ts
12
12
  var isRetryable = (err) => {
@@ -4,18 +4,18 @@ import {
4
4
  } from "./chunk-POFBE6ZY.js";
5
5
  import {
6
6
  isNetworkFailure
7
- } from "./chunk-P6VDRQF3.js";
7
+ } from "./chunk-V3P2VSX7.js";
8
8
  import {
9
9
  clientReportClaims
10
- } from "./chunk-R76C43H7.js";
10
+ } from "./chunk-HZ57E6LS.js";
11
11
  import {
12
12
  getApiKey,
13
13
  getBaseUrl
14
- } from "./chunk-EG46RJRF.js";
14
+ } from "./chunk-L52OIZXV.js";
15
15
  import {
16
16
  CLIENT_REPORT_PATH,
17
17
  degradedLine
18
- } from "./chunk-4PCF34AB.js";
18
+ } from "./chunk-ZFDGCEKO.js";
19
19
 
20
20
  // src/client-report-claim.ts
21
21
  import { createHash } from "crypto";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  SETUP_FLAGS
3
- } from "./chunk-ET6QSY3H.js";
3
+ } from "./chunk-CEHDCHXK.js";
4
4
  import {
5
5
  parseFlags
6
6
  } from "./chunk-GMXKITVA.js";
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-7QLSKOSU.js";
10
10
  import {
11
11
  NPX_LATEST_COMMAND
12
- } from "./chunk-SDSKTRIV.js";
12
+ } from "./chunk-ABIW72ST.js";
13
13
  import {
14
14
  CLAUDE_CONNECTOR_GUIDE,
15
15
  CLAUDE_CONNECTOR_STEPS,
@@ -17,7 +17,7 @@ import {
17
17
  CLAUDE_CONNECTOR_URL,
18
18
  COWORK_CONNECTOR_LIMIT,
19
19
  COWORK_STANDING_INSTRUCTIONS
20
- } from "./chunk-4PCF34AB.js";
20
+ } from "./chunk-ZFDGCEKO.js";
21
21
 
22
22
  // src/cli/cowork.ts
23
23
  import { readFileSync } from "fs";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  pusharyFetch
3
- } from "./chunk-P6VDRQF3.js";
3
+ } from "./chunk-V3P2VSX7.js";
4
4
  import {
5
5
  NetworkError
6
6
  } from "./chunk-7QLSKOSU.js";
@@ -9,11 +9,11 @@ import {
9
9
  } from "./chunk-KZERVKTD.js";
10
10
  import {
11
11
  getBaseUrl
12
- } from "./chunk-EG46RJRF.js";
12
+ } from "./chunk-L52OIZXV.js";
13
13
  import {
14
14
  isValidApiKey,
15
15
  normalizeKeyScope
16
- } from "./chunk-4PCF34AB.js";
16
+ } from "./chunk-ZFDGCEKO.js";
17
17
 
18
18
  // src/session.ts
19
19
  var samePusharyAccount = (left, right) => left.kind === "ok" && right.kind === "ok" && left.identity.workspaceId !== "" && left.identity.workspaceId === right.identity.workspaceId && left.identity.siteId === right.identity.siteId;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  readConfigFileKey
3
- } from "./chunk-ZRHA4PGN.js";
3
+ } from "./chunk-ZNUNWWCN.js";
4
4
 
5
5
  // src/bell/fleet.ts
6
6
  import { closeSync, constants, futimesSync, lstatSync, mkdirSync, openSync, readdirSync, unlinkSync } from "fs";
@@ -1186,6 +1186,7 @@ var isSafeSimpleCommand = (segment) => {
1186
1186
  if (/^[A-Za-z_][A-Za-z0-9_]*=/.test(first) || first.includes("$")) return false;
1187
1187
  if (!isTrustedExecutable(first)) return false;
1188
1188
  const exe = basenameOf(first);
1189
+ if (INSPECTED_ARGUMENT_COMMANDS.has(exe) && argumentsMayExpand(segment)) return false;
1189
1190
  if (exe === "git") {
1190
1191
  const sub = tokens[1];
1191
1192
  if (!sub || sub.startsWith("-")) return false;
@@ -1200,25 +1201,73 @@ var isSafeSimpleCommand = (segment) => {
1200
1201
  }
1201
1202
  return true;
1202
1203
  }
1204
+ if (exe === "sed") return isPrintOnlySed(tokens.slice(1));
1205
+ if (exe === "date") return isReadOnlyDate(tokens.slice(1));
1203
1206
  return SAFE_SHELL_COMMANDS.has(exe);
1204
1207
  };
1208
+ var SED_PRINT_ONLY_SCRIPT = /^(?:\d+|\$)(?:,(?:\d+|\$))?p$/;
1209
+ var SED_QUIET_FLAG = "-n";
1210
+ var DATE_FORMAT_PREFIX = "+";
1211
+ var DATE_UTC_FLAG = "-u";
1212
+ var isFlagToken = (token) => token.startsWith("-");
1213
+ var isPrintOnlySed = (args) => args[0] === SED_QUIET_FLAG && SED_PRINT_ONLY_SCRIPT.test(args[1] ?? "") && !args.slice(2).some(isFlagToken);
1214
+ var isReadOnlyDate = (args) => args.every((arg) => arg.startsWith(DATE_FORMAT_PREFIX) || arg === DATE_UTC_FLAG);
1215
+ var SINGLE_QUOTE = "'";
1216
+ var QUOTED_LITERAL = "_";
1217
+ var LITERAL_IN_DOUBLE_QUOTES = /* @__PURE__ */ new Set([";", "|", "&", "<", ">", "*", "?", "[", SHELL_ESCAPE]);
1218
+ var READ_ONLY_SEGMENT_SEPARATOR = /&&|\|\||[;|]/g;
1219
+ var PIPELINE_CHAIN_SEPARATOR = /&&|\|\||;/g;
1220
+ var shellVisibleText = (command) => {
1221
+ let visible = "";
1222
+ let quote = null;
1223
+ for (let index = 0; index < command.length; index += 1) {
1224
+ const char = command[index];
1225
+ if (quote === SINGLE_QUOTE) {
1226
+ quote = char === SINGLE_QUOTE ? null : quote;
1227
+ visible += quote === null ? char : QUOTED_LITERAL;
1228
+ continue;
1229
+ }
1230
+ if (quote === SHELL_DOUBLE_QUOTE) {
1231
+ if (char === SHELL_ESCAPE && DOUBLE_QUOTE_ESCAPABLE.has(command[index + 1] ?? "")) return null;
1232
+ quote = char === SHELL_DOUBLE_QUOTE ? null : quote;
1233
+ visible += quote !== null && LITERAL_IN_DOUBLE_QUOTES.has(char) ? QUOTED_LITERAL : char;
1234
+ continue;
1235
+ }
1236
+ if (SHELL_QUOTES.has(char)) quote = char;
1237
+ visible += char;
1238
+ }
1239
+ return quote === null ? visible : null;
1240
+ };
1241
+ var EXPANSION_THAT_CAN_BECOME_A_FLAG = /\$|(?:^|\s)[*?[]/;
1242
+ var SHELL_QUOTE_CHARACTERS = /['"]/g;
1243
+ var INSPECTED_ARGUMENT_COMMANDS = /* @__PURE__ */ new Set(["git", "find", "sed", "date"]);
1244
+ var argumentsMayExpand = (segment) => {
1245
+ const visible = shellVisibleText(segment);
1246
+ return visible === null || EXPANSION_THAT_CAN_BECOME_A_FLAG.test(visible.replace(SHELL_QUOTE_CHARACTERS, ""));
1247
+ };
1248
+ var blankedSafeRedirections = (text) => text.replace(SAFE_REDIRECTION, (redirection) => " ".repeat(redirection.length));
1249
+ var segmentsSplitWhereVisible = (command, visible, separators) => {
1250
+ const segments = [];
1251
+ let start = 0;
1252
+ for (const separator of visible.matchAll(separators)) {
1253
+ segments.push(command.slice(start, separator.index));
1254
+ start = separator.index + separator[0].length;
1255
+ }
1256
+ segments.push(command.slice(start));
1257
+ return segments;
1258
+ };
1205
1259
  var isSafeReadOnlyCommand = (command) => {
1206
1260
  const trimmed = command.trim();
1207
1261
  if (!trimmed || trimmed.length > 2e3) return false;
1208
- if (/[`\n\r{}]/.test(trimmed)) return false;
1209
- if (/;|\|\|/.test(trimmed)) return false;
1210
- if (/\\(?![()!])/.test(trimmed)) return false;
1211
- if (/(?<!\\)[()]/.test(trimmed)) return false;
1212
- const noRedir = trimmed.replace(SAFE_REDIRECTION, " ");
1213
- if (/[<>]/.test(noRedir)) return false;
1214
- if (noRedir.replace(/&&/g, " ").includes("&")) return false;
1215
- for (const andPart of noRedir.split("&&")) {
1216
- if (!andPart.trim()) return false;
1217
- for (const segment of andPart.split("|")) {
1218
- if (!isSafeSimpleCommand(segment)) return false;
1219
- }
1220
- }
1221
- return true;
1262
+ if (/[\n\r]/.test(trimmed)) return false;
1263
+ const visible = shellVisibleText(trimmed);
1264
+ if (visible === null || /[`{}]|\$'/.test(visible)) return false;
1265
+ if (/\\(?![()!])/.test(visible)) return false;
1266
+ if (/(?<!\\)[()]/.test(visible)) return false;
1267
+ const visibleWithoutRedirection = blankedSafeRedirections(visible);
1268
+ if (/[<>]/.test(visibleWithoutRedirection)) return false;
1269
+ if (visibleWithoutRedirection.replace(/&&/g, " ").includes("&")) return false;
1270
+ return segmentsSplitWhereVisible(blankedSafeRedirections(trimmed), visibleWithoutRedirection, READ_ONLY_SEGMENT_SEPARATOR).every((segment) => segment.trim().length > 0 && isSafeSimpleCommand(segment));
1222
1271
  };
1223
1272
  var isAutoApprove = (policy) => policy.timeoutSeconds === 0 && policy.timeoutAction === "approve";
1224
1273
  var isAutoDeny = (policy) => policy.timeoutSeconds === 0 && policy.timeoutAction === "deny";
@@ -1542,6 +1591,7 @@ var segmentNeedsAPerson = (toolName, segment) => {
1542
1591
  return invocationHidesItsEffect(invocation) || subcommandDestroys(invocation) || classifyDecisionRisk(toolName, normalized) !== "standard" || isCoveredByPolicy(CAPABILITY_PATTERNS.destructive, toolName, normalized) || isCoveredByPolicy(CAPABILITY_PATTERNS.network, toolName, normalized) || isCoveredByPolicy(DATA_LOSS_COMMAND_PATTERNS, toolName, normalized);
1543
1592
  };
1544
1593
  var commandNeedsAPerson = (toolName, command) => {
1594
+ if (toolName === "Bash" && isSafeReadOnlyCommand(command)) return false;
1545
1595
  const segments = readableCommandSegments(command);
1546
1596
  return segments === null || classifyDecisionRisk(toolName, command) !== "standard" || segments.some((segment) => segmentNeedsAPerson(toolName, segment));
1547
1597
  };
@@ -1619,11 +1669,7 @@ ${body}`;
1619
1669
  const highConsequence = HIGH_CONSEQUENCE_PATTERNS.some((re) => re.test(scanText));
1620
1670
  return { isCommand: command, commandText, path, highConsequence };
1621
1671
  };
1622
- var isDestructive = (toolName, commandText) => {
1623
- const haystack = `${toolName ?? ""}
1624
- ${commandText}`;
1625
- return APPROVAL_FATIGUE_FLAG_PATTERNS.some((re) => re.test(haystack));
1626
- };
1672
+ var isDestructive = (toolName, commandText) => namesADestructiveAction(toolName ?? "", commandText);
1627
1673
  var addAlnumTokens = (source, set) => {
1628
1674
  for (const raw of source.toLowerCase().split(/[^a-z0-9]+/)) {
1629
1675
  if (raw) set.add(raw);
@@ -1776,11 +1822,27 @@ var SETTLED_OUTCOME = {
1776
1822
  deny: "deny"
1777
1823
  };
1778
1824
  var isSettledOutcome = (value) => typeof value === "string" && SETTLED_OUTCOMES.includes(value);
1825
+ var APPROVE_RESPONSES = /* @__PURE__ */ new Set(["yes", "approve", "approved"]);
1826
+ var DENY_RESPONSES = /* @__PURE__ */ new Set(["no", "deny", "denied", "reject", "rejected"]);
1827
+ var DEFER_RESPONSES = /* @__PURE__ */ new Set(["defer"]);
1828
+ var classifyConfirmResponse = (response) => {
1829
+ const normalized = (response ?? "").trim().toLowerCase();
1830
+ if (APPROVE_RESPONSES.has(normalized)) return "approve";
1831
+ if (DENY_RESPONSES.has(normalized)) return "deny";
1832
+ if (DEFER_RESPONSES.has(normalized)) return "defer";
1833
+ return null;
1834
+ };
1835
+ var commandTextThatCanAct = (command) => {
1836
+ const visible = shellVisibleText(command);
1837
+ return visible === null ? command : segmentsSplitWhereVisible(command, visible, PIPELINE_CHAIN_SEPARATOR).filter((pipeline) => !isSafeReadOnlyCommand(pipeline)).join("\n");
1838
+ };
1839
+ var destructiveKeywordTarget = (toolName, toolTarget) => toolName === "Bash" ? commandTextThatCanAct(toolTarget) : toolTarget;
1840
+ var matchesAnyPattern = (patterns, parts) => parts.some((part) => patterns.some((re) => re.test(part)));
1841
+ var namesADestructiveAction = (toolName, toolTarget) => matchesAnyPattern(APPROVAL_FATIGUE_FLAG_PATTERNS, [toolName, destructiveKeywordTarget(toolName, toolTarget)]);
1779
1842
  var classifyDecisionRisk = (toolName, toolTarget) => {
1780
- const parts = [toolName, toolTarget ?? ""];
1781
- const matchesAny = (patterns) => parts.some((part) => patterns.some((re) => re.test(part)));
1782
- if (matchesAny(APPROVAL_FATIGUE_FLAG_PATTERNS)) return "destructive";
1783
- if (matchesAny(HIGH_CONSEQUENCE_PATTERNS)) return "elevated";
1843
+ const target = toolTarget ?? "";
1844
+ if (namesADestructiveAction(toolName, target)) return "destructive";
1845
+ if (matchesAnyPattern(HIGH_CONSEQUENCE_PATTERNS, [toolName, target])) return "elevated";
1784
1846
  return "standard";
1785
1847
  };
1786
1848
  var POLICY_CAPABILITIES = ["read", "edit", "shell", "network", "destructive"];
@@ -2555,10 +2617,11 @@ var elicitationContentFromAnswers = (ask, answers) => {
2555
2617
  // ../contracts/src/hook-activation.ts
2556
2618
  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;
2557
2619
  var HOOK_ACTIVATION_RESULTS = ["unverified", "approved_executed", "denied_observed", "unexpected_execution", "tool_failed"];
2620
+ var MAX_HOOK_ACTIVATION_EVIDENCE_ROWS = 20;
2558
2621
  var isHookActivationReport = (value) => {
2559
2622
  if (!value || typeof value !== "object") return false;
2560
2623
  const report = value;
2561
- 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) => {
2624
+ 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 <= MAX_HOOK_ACTIVATION_EVIDENCE_ROWS && (!report.truncated || report.evidence.length === 0) && report.evidence.every((item) => {
2562
2625
  if (!item || typeof item !== "object") return false;
2563
2626
  const row = item;
2564
2627
  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");
@@ -2738,6 +2801,7 @@ export {
2738
2801
  redactSecretsDeep,
2739
2802
  degradedLine,
2740
2803
  hookWritePath,
2804
+ MAX_HOOK_ACTIVATION_EVIDENCE_ROWS,
2741
2805
  isHookActivationReport,
2742
2806
  hookActivationResult,
2743
2807
  PAIR_TTL_SECONDS,
@@ -2780,6 +2844,7 @@ export {
2780
2844
  ASK_AGENT_NAME_MAX,
2781
2845
  truncateLine,
2782
2846
  isAnswerSource,
2847
+ classifyConfirmResponse,
2783
2848
  buildDecisionEpisodeFeatures,
2784
2849
  resolveAutoResolveOrigin,
2785
2850
  resolvePolicy,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolveInstallSourceFor
3
- } from "./chunk-US3RDXK7.js";
3
+ } from "./chunk-UBCTOE5X.js";
4
4
  import {
5
5
  backupFile,
6
6
  readJsonSafe,
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-T7E75EKA.js";
10
10
  import {
11
11
  configFilePath
12
- } from "./chunk-EG46RJRF.js";
12
+ } from "./chunk-L52OIZXV.js";
13
13
 
14
14
  // src/shell-alias.ts
15
15
  import { homedir } from "os";
@@ -110,6 +110,7 @@ var isDisabledExport = (line) => {
110
110
  return OUR_EXPORT.test(trimmed.slice(1, -LOGOUT_MARK.length).trim());
111
111
  };
112
112
  var keyPrefix = (key) => key.split(".")[0] ?? key;
113
+ var manualKeyStepFor = (kind, platform) => kind === "no-rc" || platform === "win32" ? "config-only" : "paste-export";
113
114
  var rcResult = (kind, over = {}) => ({
114
115
  kind,
115
116
  path: null,
@@ -298,6 +299,7 @@ export {
298
299
  exportLine,
299
300
  isDisabledExport,
300
301
  keyPrefix,
302
+ manualKeyStepFor,
301
303
  writeKey,
302
304
  clearKey,
303
305
  readConfigFileKey,