@pushary/agent-hooks 0.95.2 → 0.95.5
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 +19 -0
- package/README.md +1 -1
- package/data/cursor-plugin/.cursor-plugin/plugin.json +1 -1
- package/data/cursor-plugin/CHANGELOG.md +5 -0
- package/data/cursor-plugin/README.md +6 -8
- package/data/cursor-plugin/hooks/hooks.json +56 -1
- package/data/cursor-plugin/scripts/pushary-gate.mjs +120 -71
- package/data/vscode-plugin/.claude-plugin/plugin.json +1 -1
- package/data/vscode-plugin/CHANGELOG.md +5 -0
- package/data/vscode-plugin/README.md +7 -15
- package/data/vscode-plugin/hooks/hooks.json +49 -0
- package/data/vscode-plugin/scripts/pushary-gate.mjs +208 -88
- package/dist/bin/pushary-bell-hook.js +20 -22
- package/dist/bin/pushary-bell.js +9 -11
- package/dist/bin/pushary-claude.js +58 -46
- package/dist/bin/pushary-clean.js +21 -20
- package/dist/bin/pushary-codex-bridge.js +120 -25
- package/dist/bin/pushary-codex-hook.js +43 -63
- package/dist/bin/pushary-codex.js +11 -10
- package/dist/bin/pushary-connect.js +8 -10
- package/dist/bin/pushary-cowork.js +5 -5
- package/dist/bin/pushary-daemon.js +26 -28
- package/dist/bin/pushary-disconnect.js +11 -10
- package/dist/bin/pushary-doctor.js +25 -25
- package/dist/bin/pushary-elicitation-hook.js +30 -31
- package/dist/bin/pushary-gemini-bridge.js +9 -11
- package/dist/bin/pushary-gemini-hook.js +45 -79
- package/dist/bin/pushary-hook.js +27 -29
- package/dist/bin/pushary-login.js +57 -31
- package/dist/bin/pushary-logout.js +6 -8
- package/dist/bin/pushary-mode.js +5 -5
- package/dist/bin/pushary-notification-hook.js +22 -24
- package/dist/bin/pushary-opencode-hook.js +38 -74
- package/dist/bin/pushary-permission-denied-hook.js +25 -27
- package/dist/bin/pushary-permission-hook.js +25 -27
- package/dist/bin/pushary-post-hook.js +22 -24
- package/dist/bin/pushary-prompt-hook.js +22 -24
- package/dist/bin/pushary-session-end-hook.js +22 -24
- package/dist/bin/pushary-session-start-hook.js +25 -27
- package/dist/bin/pushary-setup.js +78 -55
- package/dist/bin/pushary-stats.js +4 -4
- package/dist/bin/pushary-status.js +10 -12
- package/dist/bin/pushary-stop-hook.js +22 -24
- package/dist/bin/pushary-stopfailure-hook.js +22 -24
- package/dist/bin/pushary-suggestions.js +2 -2
- package/dist/bin/pushary-transcript-register.js +18 -20
- package/dist/bin/pushary-transcripts.js +7 -9
- package/dist/bin/pushary-upgrade.js +17 -19
- package/dist/bin/pushary-wait.js +5 -5
- package/dist/bin/pushary.js +1 -1
- package/dist/{chunk-7LUFYRH4.js → chunk-2D7BAOMY.js} +7 -7
- package/dist/{chunk-3ZUTNTZA.js → chunk-2ZTL3PGN.js} +1 -1
- package/dist/{chunk-EPFDN2ZT.js → chunk-32RMQO5Z.js} +1 -1
- package/dist/{chunk-EZIEXHYM.js → chunk-3AJIK5AO.js} +5 -2
- package/dist/{chunk-IPHOUBTU.js → chunk-4PX4QK2Z.js} +1 -1
- package/dist/{chunk-UW4LWAWY.js → chunk-4RF52LSU.js} +8 -8
- package/dist/{chunk-UOTSWS5N.js → chunk-67YNQ3QA.js} +43 -98
- package/dist/{chunk-G4TL4YWH.js → chunk-6AEM5RCS.js} +1 -1
- package/dist/{chunk-G24SEVCI.js → chunk-6VANQN5Q.js} +3 -7
- package/dist/{chunk-CKOLDI47.js → chunk-BDI2MXTT.js} +2 -2
- package/dist/{chunk-YKLCWWEI.js → chunk-BMANRGJQ.js} +1 -1
- package/dist/{chunk-2XUPP4WM.js → chunk-CUEZMPLJ.js} +1 -1
- package/dist/{chunk-A4R6BZCK.js → chunk-D62EONG3.js} +1 -1
- package/dist/{chunk-ZDAT5KMU.js → chunk-D6PRC3YQ.js} +1 -1
- package/dist/{chunk-MOY5X6HJ.js → chunk-DLLAWCQB.js} +1 -1
- package/dist/{chunk-DSTLA2TC.js → chunk-GOPIMNVC.js} +1 -1
- package/dist/{chunk-CH6DTGQR.js → chunk-HBHEX3JQ.js} +3 -3
- package/dist/{chunk-DNVDKHQD.js → chunk-HCMM3BOW.js} +226 -58
- package/dist/{chunk-76XICHYT.js → chunk-HGUZOUB2.js} +4 -4
- package/dist/{chunk-E3NF5CL2.js → chunk-HQIVR7MM.js} +6 -3
- package/dist/{chunk-JDFB3YKG.js → chunk-I6GZX3FT.js} +3 -3
- package/dist/{chunk-3OXHYPZG.js → chunk-IM2A5H33.js} +4 -1
- package/dist/{chunk-V27AHID3.js → chunk-IVQMNLSA.js} +3 -14
- package/dist/{chunk-4LL6LG5X.js → chunk-KAVDAZ7A.js} +43 -1
- package/dist/chunk-KBITFQST.js +6 -0
- package/dist/{chunk-AMZJ3CKW.js → chunk-KI4PA7MQ.js} +1 -1
- package/dist/{chunk-IAEXPTXA.js → chunk-N4VNLISN.js} +2 -2
- package/dist/{chunk-VX3BWMC5.js → chunk-OEKFD5BC.js} +1 -1
- package/dist/{chunk-QF4RI5CD.js → chunk-OI3DJA7N.js} +1 -1
- package/dist/{chunk-WB2C7VPF.js → chunk-OW6AZDY2.js} +3 -3
- package/dist/{chunk-4XXUHWIK.js → chunk-QHWXUNMN.js} +1 -1
- package/dist/{chunk-M7WWEFG6.js → chunk-QQGNFHIK.js} +2 -2
- package/dist/{chunk-YJAQRKH5.js → chunk-RLXVW4AM.js} +1 -1
- package/dist/{chunk-GUVCYYDK.js → chunk-S5CMLR35.js} +94 -15
- package/dist/{chunk-EUAQ4YAN.js → chunk-UCS65VVR.js} +1 -1
- package/dist/{chunk-WM5XMCID.js → chunk-VOSGZ6PH.js} +4 -4
- package/dist/{chunk-QUE76J4H.js → chunk-VTO3TNIB.js} +1 -1
- package/dist/{chunk-6FAHPGCZ.js → chunk-WDKHZRAS.js} +183 -25
- package/dist/{chunk-5GLPYGKS.js → chunk-WRDLHR2F.js} +2 -2
- package/dist/{chunk-RVSEGFPD.js → chunk-XLOELLAS.js} +9 -4
- package/dist/chunk-XS33QBJA.js +112 -0
- package/dist/{chunk-FQUV5KTM.js → chunk-Z2UWFEJW.js} +8 -8
- package/dist/src/index.d.ts +8 -1
- package/dist/src/index.js +11 -12
- package/package.json +1 -1
- package/dist/chunk-BC3VCZ3E.js +0 -86
- package/dist/chunk-RER3FRTD.js +0 -265
- package/dist/chunk-X7YWD6IS.js +0 -44
|
@@ -1,19 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
|
-
DEFAULT_SESSION,
|
|
3
2
|
cancelQuestion,
|
|
4
|
-
isDefaultSession,
|
|
5
3
|
isPolicyConfig,
|
|
6
|
-
listPendingQuestions,
|
|
7
|
-
listPendingQuestionsForToolUse,
|
|
8
|
-
markPendingCommandDelivered,
|
|
9
|
-
readPendingCommand,
|
|
10
|
-
removePendingCommand,
|
|
11
|
-
removePendingQuestion,
|
|
12
|
-
removePendingSession,
|
|
13
|
-
savePendingCommand,
|
|
14
4
|
sendNotification,
|
|
15
5
|
waitForAnswer
|
|
16
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-XS33QBJA.js";
|
|
17
7
|
import {
|
|
18
8
|
AGENT_IDENTITIES,
|
|
19
9
|
TEAMMATE_IDLE_ACTION,
|
|
@@ -34,20 +24,20 @@ import {
|
|
|
34
24
|
summarizeStop,
|
|
35
25
|
taskTitleFrom,
|
|
36
26
|
toolResultErrorText
|
|
37
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-BDI2MXTT.js";
|
|
38
28
|
import {
|
|
39
29
|
NOTIFICATION_PUSH_TYPES,
|
|
40
30
|
POSTTOOLUSE_MIRROR_ONLY_TOOLS
|
|
41
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-IVQMNLSA.js";
|
|
42
32
|
import {
|
|
43
33
|
getMachineId
|
|
44
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-N4VNLISN.js";
|
|
45
35
|
import {
|
|
46
36
|
withRetry
|
|
47
37
|
} from "./chunk-EYRGBYZG.js";
|
|
48
38
|
import {
|
|
49
39
|
reportedInstallSource
|
|
50
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-KAVDAZ7A.js";
|
|
51
41
|
import {
|
|
52
42
|
getApiKey,
|
|
53
43
|
getBaseUrl
|
|
@@ -55,6 +45,7 @@ import {
|
|
|
55
45
|
import {
|
|
56
46
|
HOOK_SOURCES,
|
|
57
47
|
PENDING_COMMAND_PREFIX,
|
|
48
|
+
REPO_AWARE_AGENTS,
|
|
58
49
|
gateOutputFor,
|
|
59
50
|
isAutoApprove,
|
|
60
51
|
localRepoKey,
|
|
@@ -63,7 +54,7 @@ import {
|
|
|
63
54
|
pendingCommandEvents,
|
|
64
55
|
resolveAutoResolveOrigin,
|
|
65
56
|
resolvePolicy
|
|
66
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-WDKHZRAS.js";
|
|
67
58
|
|
|
68
59
|
// src/policy.ts
|
|
69
60
|
import { createHash } from "crypto";
|
|
@@ -72,7 +63,6 @@ import { join } from "path";
|
|
|
72
63
|
import { tmpdir } from "os";
|
|
73
64
|
var CACHE_TTL_MS = 60 * 1e3;
|
|
74
65
|
var STALE_CACHE_MAX_MS = 12 * 60 * 60 * 1e3;
|
|
75
|
-
var REPO_AWARE_AGENTS = ["claude_code", "codex", "gemini_cli", "opencode"];
|
|
76
66
|
var policyRequestFor = (agentType) => ({
|
|
77
67
|
agent: agentType,
|
|
78
68
|
repoAware: REPO_AWARE_AGENTS.includes(agentType)
|
|
@@ -206,19 +196,190 @@ var fetchModeState = async (apiKey, sessionId, reuseWithinMs = 0, signal) => {
|
|
|
206
196
|
};
|
|
207
197
|
var fetchModeOverride = async (apiKey) => (await fetchModeState(apiKey)).mode;
|
|
208
198
|
|
|
199
|
+
// src/pending.ts
|
|
200
|
+
import { join as join2 } from "path";
|
|
201
|
+
import { homedir, tmpdir as tmpdir2 } from "os";
|
|
202
|
+
import { createHash as createHash2 } from "crypto";
|
|
203
|
+
import { existsSync as existsSync2, mkdirSync, writeFileSync as writeFileSync2, readFileSync as readFileSync2, readdirSync, renameSync, unlinkSync, rmSync, statSync } from "fs";
|
|
204
|
+
var PENDING_DIR = join2(tmpdir2(), "pushary-pending");
|
|
205
|
+
var commandRoot = () => process.env.PUSHARY_COMMAND_DIR?.trim() || join2(homedir(), ".pushary", "run", "commands");
|
|
206
|
+
var DEFAULT_SESSION = "_no_session";
|
|
207
|
+
var GRACE_MS = 10 * 60 * 1e3;
|
|
208
|
+
var sanitize = (sessionId) => sessionId.replace(/[^A-Za-z0-9_-]/g, "_").slice(0, 128) || DEFAULT_SESSION;
|
|
209
|
+
var dirFor = (sessionId) => join2(PENDING_DIR, sanitize(sessionId));
|
|
210
|
+
var commandDirFor = (sessionId, namespace = "") => join2(
|
|
211
|
+
commandRoot(),
|
|
212
|
+
createHash2("sha256").update(namespace).digest("hex").slice(0, 16),
|
|
213
|
+
sanitize(sessionId)
|
|
214
|
+
);
|
|
215
|
+
var legacyCommandFile = (sessionId, namespace = "") => join2(commandDirFor(sessionId, namespace), "command.json");
|
|
216
|
+
var commandFile = (sessionId, id, namespace = "") => join2(commandDirFor(sessionId, namespace), `${createHash2("sha256").update(id).digest("hex")}.json`);
|
|
217
|
+
var readCommandFile = (file) => {
|
|
218
|
+
try {
|
|
219
|
+
const value = JSON.parse(readFileSync2(file, "utf-8"));
|
|
220
|
+
if (typeof value.id !== "string" || typeof value.text !== "string" || typeof value.expiresAtMs !== "number") return null;
|
|
221
|
+
if (value.expiresAtMs <= Date.now()) {
|
|
222
|
+
unlinkSync(file);
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
...value,
|
|
227
|
+
delivered: value.delivered === true,
|
|
228
|
+
...value.failed === true ? { failed: true } : {}
|
|
229
|
+
};
|
|
230
|
+
} catch {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
var readPendingCommandById = (sessionId, id, namespace = "") => {
|
|
235
|
+
const current = readCommandFile(commandFile(sessionId, id, namespace));
|
|
236
|
+
if (current?.id === id) return current;
|
|
237
|
+
const legacy = readCommandFile(legacyCommandFile(sessionId, namespace));
|
|
238
|
+
return legacy?.id === id ? legacy : null;
|
|
239
|
+
};
|
|
240
|
+
var pruneExpiredCommands = (dir) => {
|
|
241
|
+
let files;
|
|
242
|
+
try {
|
|
243
|
+
files = readdirSync(dir).filter((file) => file.endsWith(".json"));
|
|
244
|
+
} catch {
|
|
245
|
+
return [];
|
|
246
|
+
}
|
|
247
|
+
return files.flatMap((file) => {
|
|
248
|
+
const command = readCommandFile(join2(dir, file));
|
|
249
|
+
return command ? [command] : [];
|
|
250
|
+
});
|
|
251
|
+
};
|
|
252
|
+
var pruneExpiredCommandStore = () => {
|
|
253
|
+
let namespaces;
|
|
254
|
+
try {
|
|
255
|
+
namespaces = readdirSync(commandRoot(), { withFileTypes: true });
|
|
256
|
+
} catch {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
for (const namespace of namespaces.filter((entry) => entry.isDirectory())) {
|
|
260
|
+
const namespaceDir = join2(commandRoot(), namespace.name);
|
|
261
|
+
let sessions;
|
|
262
|
+
try {
|
|
263
|
+
sessions = readdirSync(namespaceDir, { withFileTypes: true });
|
|
264
|
+
} catch {
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
for (const session of sessions.filter((entry) => entry.isDirectory())) {
|
|
268
|
+
pruneExpiredCommands(join2(namespaceDir, session.name));
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
var readPendingCommand = (sessionId, namespace = "") => {
|
|
273
|
+
const commands = pruneExpiredCommands(commandDirFor(sessionId, namespace));
|
|
274
|
+
return commands.find((command) => !command.delivered && !command.failed) ?? commands[0] ?? null;
|
|
275
|
+
};
|
|
276
|
+
var savePendingCommand = (sessionId, command, namespace = "") => {
|
|
277
|
+
const dir = commandDirFor(sessionId, namespace);
|
|
278
|
+
try {
|
|
279
|
+
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
280
|
+
pruneExpiredCommandStore();
|
|
281
|
+
if (readPendingCommandById(sessionId, command.id, namespace)) return false;
|
|
282
|
+
writeFileSync2(commandFile(sessionId, command.id, namespace), JSON.stringify(command), { encoding: "utf-8", mode: 384, flag: "wx" });
|
|
283
|
+
return true;
|
|
284
|
+
} catch {
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
var updatePendingCommand = (sessionId, id, update, namespace = "") => {
|
|
289
|
+
const command = readPendingCommandById(sessionId, id, namespace);
|
|
290
|
+
if (!command) return false;
|
|
291
|
+
const currentFile = commandFile(sessionId, id, namespace);
|
|
292
|
+
const file = existsSync2(currentFile) ? currentFile : legacyCommandFile(sessionId, namespace);
|
|
293
|
+
const temporary = `${file}.${process.pid}.tmp`;
|
|
294
|
+
try {
|
|
295
|
+
writeFileSync2(temporary, JSON.stringify({ ...command, ...update, text: "" }), { encoding: "utf-8", mode: 384 });
|
|
296
|
+
renameSync(temporary, file);
|
|
297
|
+
return true;
|
|
298
|
+
} catch {
|
|
299
|
+
try {
|
|
300
|
+
unlinkSync(temporary);
|
|
301
|
+
} catch {
|
|
302
|
+
}
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
var markPendingCommandDelivered = (sessionId, id, namespace = "") => updatePendingCommand(sessionId, id, { delivered: true, failed: void 0 }, namespace);
|
|
307
|
+
var markPendingCommandFailed = (sessionId, id, namespace = "") => updatePendingCommand(sessionId, id, { delivered: false, failed: true }, namespace);
|
|
308
|
+
var removePendingCommand = (sessionId, id, namespace = "") => {
|
|
309
|
+
if (!readPendingCommandById(sessionId, id, namespace)) return;
|
|
310
|
+
try {
|
|
311
|
+
unlinkSync(commandFile(sessionId, id, namespace));
|
|
312
|
+
} catch {
|
|
313
|
+
}
|
|
314
|
+
try {
|
|
315
|
+
if (readCommandFile(legacyCommandFile(sessionId, namespace))?.id === id) {
|
|
316
|
+
unlinkSync(legacyCommandFile(sessionId, namespace));
|
|
317
|
+
}
|
|
318
|
+
} catch {
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
var isDefaultSession = (sessionId) => sanitize(sessionId) === DEFAULT_SESSION;
|
|
322
|
+
var listPendingQuestionsForToolUse = (sessionId, toolUseId) => {
|
|
323
|
+
if (!toolUseId) return [];
|
|
324
|
+
const dir = dirFor(sessionId);
|
|
325
|
+
let files;
|
|
326
|
+
try {
|
|
327
|
+
files = readdirSync(dir);
|
|
328
|
+
} catch {
|
|
329
|
+
return [];
|
|
330
|
+
}
|
|
331
|
+
return files.filter((name) => {
|
|
332
|
+
try {
|
|
333
|
+
return readFileSync2(join2(dir, name), "utf-8") === toolUseId;
|
|
334
|
+
} catch {
|
|
335
|
+
return false;
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
};
|
|
339
|
+
var listPendingQuestions = (sessionId) => {
|
|
340
|
+
const dir = dirFor(sessionId);
|
|
341
|
+
let files;
|
|
342
|
+
try {
|
|
343
|
+
files = readdirSync(dir);
|
|
344
|
+
} catch {
|
|
345
|
+
return [];
|
|
346
|
+
}
|
|
347
|
+
if (!isDefaultSession(sessionId)) return files;
|
|
348
|
+
const cutoff = Date.now() - GRACE_MS;
|
|
349
|
+
return files.filter((name) => {
|
|
350
|
+
try {
|
|
351
|
+
return statSync(join2(dir, name)).mtimeMs < cutoff;
|
|
352
|
+
} catch {
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
};
|
|
357
|
+
var removePendingQuestion = (sessionId, correlationId) => {
|
|
358
|
+
try {
|
|
359
|
+
unlinkSync(join2(dirFor(sessionId), correlationId));
|
|
360
|
+
} catch {
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
var removePendingSession = (sessionId) => {
|
|
364
|
+
try {
|
|
365
|
+
rmSync(dirFor(sessionId), { recursive: true, force: true });
|
|
366
|
+
} catch {
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
|
|
209
370
|
// src/repo.ts
|
|
210
|
-
import { existsSync as
|
|
211
|
-
import { basename, dirname, isAbsolute, join as
|
|
371
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3, statSync as statSync2 } from "fs";
|
|
372
|
+
import { basename, dirname, isAbsolute, join as join3, resolve } from "path";
|
|
212
373
|
var MAX_PARENT_WALK = 64;
|
|
213
374
|
var GIT_FILE_PREFIX = "gitdir:";
|
|
214
375
|
var findGitDir = (startDir) => {
|
|
215
376
|
let current = resolve(startDir);
|
|
216
377
|
for (let depth = 0; depth < MAX_PARENT_WALK; depth += 1) {
|
|
217
|
-
const candidate =
|
|
378
|
+
const candidate = join3(current, ".git");
|
|
218
379
|
try {
|
|
219
|
-
if (
|
|
220
|
-
if (
|
|
221
|
-
const pointer =
|
|
380
|
+
if (existsSync3(candidate)) {
|
|
381
|
+
if (statSync2(candidate).isDirectory()) return candidate;
|
|
382
|
+
const pointer = readFileSync3(candidate, "utf-8").trim();
|
|
222
383
|
if (pointer.startsWith(GIT_FILE_PREFIX)) {
|
|
223
384
|
const target = pointer.slice(GIT_FILE_PREFIX.length).trim();
|
|
224
385
|
return isAbsolute(target) ? target : resolve(current, target);
|
|
@@ -234,7 +395,7 @@ var findGitDir = (startDir) => {
|
|
|
234
395
|
};
|
|
235
396
|
var configPathFor = (gitDir) => {
|
|
236
397
|
const index = gitDir.replace(/\\/g, "/").indexOf("/worktrees/");
|
|
237
|
-
return index === -1 ?
|
|
398
|
+
return index === -1 ? join3(gitDir, "config") : join3(gitDir.slice(0, index), "config");
|
|
238
399
|
};
|
|
239
400
|
var ORIGIN_SECTION = /^\[remote "origin"\]/;
|
|
240
401
|
var SECTION_HEADER = /^\[/;
|
|
@@ -242,9 +403,9 @@ var URL_LINE = /^url\s*=\s*(.+)$/;
|
|
|
242
403
|
var readOriginRemote = (gitDir) => {
|
|
243
404
|
try {
|
|
244
405
|
const configPath = configPathFor(gitDir);
|
|
245
|
-
if (!
|
|
406
|
+
if (!existsSync3(configPath)) return void 0;
|
|
246
407
|
let inOrigin = false;
|
|
247
|
-
for (const rawLine of
|
|
408
|
+
for (const rawLine of readFileSync3(configPath, "utf-8").split("\n")) {
|
|
248
409
|
const line = rawLine.trim();
|
|
249
410
|
if (SECTION_HEADER.test(line)) {
|
|
250
411
|
inOrigin = ORIGIN_SECTION.test(line);
|
|
@@ -291,10 +452,10 @@ var repoKeyFor = (cwd) => {
|
|
|
291
452
|
};
|
|
292
453
|
|
|
293
454
|
// src/usage.ts
|
|
294
|
-
import { closeSync, mkdirSync, openSync, readFileSync as
|
|
295
|
-
import { createHash as
|
|
296
|
-
import { join as
|
|
297
|
-
import { tmpdir as
|
|
455
|
+
import { closeSync, mkdirSync as mkdirSync2, openSync, readFileSync as readFileSync4, readSync, statSync as statSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
456
|
+
import { createHash as createHash3 } from "crypto";
|
|
457
|
+
import { join as join4 } from "path";
|
|
458
|
+
import { tmpdir as tmpdir3 } from "os";
|
|
298
459
|
var DEFAULT_PRICES = [
|
|
299
460
|
{ match: "opus-4-1", in: 15, out: 75 },
|
|
300
461
|
{ match: "opus-4-0", in: 15, out: 75 },
|
|
@@ -329,12 +490,12 @@ var estimateCostUsd = (usage, model) => {
|
|
|
329
490
|
const perTokenOut = price.out / 1e6;
|
|
330
491
|
return usage.inputTokens * perTokenIn + usage.outputTokens * perTokenOut + usage.cacheCreationTokens * perTokenIn * CACHE_WRITE_MULTIPLIER + usage.cacheReadTokens * perTokenIn * CACHE_READ_MULTIPLIER;
|
|
331
492
|
};
|
|
332
|
-
var stateDir = () => process.env.PUSHARY_USAGE_DIR?.trim() ||
|
|
333
|
-
var stateFile = (sessionId) =>
|
|
493
|
+
var stateDir = () => process.env.PUSHARY_USAGE_DIR?.trim() || join4(tmpdir3(), "pushary-usage");
|
|
494
|
+
var stateFile = (sessionId) => join4(stateDir(), sessionId.replace(/[^a-zA-Z0-9_-]/g, "_"));
|
|
334
495
|
var emptyState = () => ({ offset: 0, tokensIn: 0, tokensOut: 0, costUsd: 0, recentIds: [] });
|
|
335
496
|
var readState = (path) => {
|
|
336
497
|
try {
|
|
337
|
-
const parsed = JSON.parse(
|
|
498
|
+
const parsed = JSON.parse(readFileSync4(path, "utf-8"));
|
|
338
499
|
if (typeof parsed.offset === "number" && parsed.offset >= 0 && typeof parsed.tokensIn === "number" && typeof parsed.tokensOut === "number" && typeof parsed.costUsd === "number" && Array.isArray(parsed.recentIds)) {
|
|
339
500
|
return {
|
|
340
501
|
offset: parsed.offset,
|
|
@@ -409,7 +570,7 @@ var extractUserText = (content) => {
|
|
|
409
570
|
};
|
|
410
571
|
var readLastUserPrompt = (transcriptPath) => {
|
|
411
572
|
try {
|
|
412
|
-
const size =
|
|
573
|
+
const size = statSync3(transcriptPath).size;
|
|
413
574
|
const start = Math.max(0, size - USER_PROMPT_TAIL_BYTES);
|
|
414
575
|
const lines = readRange(transcriptPath, start, size).toString("utf-8").split("\n");
|
|
415
576
|
for (let i = lines.length - 1; i >= 0; i -= 1) {
|
|
@@ -432,7 +593,7 @@ var readLastUserPrompt = (transcriptPath) => {
|
|
|
432
593
|
};
|
|
433
594
|
var readNewUsage = (transcriptPath, sessionId) => {
|
|
434
595
|
try {
|
|
435
|
-
const file =
|
|
596
|
+
const file = statSync3(transcriptPath);
|
|
436
597
|
const size = file.size;
|
|
437
598
|
const path = stateFile(sessionId);
|
|
438
599
|
let state = readState(path);
|
|
@@ -450,14 +611,14 @@ var readNewUsage = (transcriptPath, sessionId) => {
|
|
|
450
611
|
state.offset += lastNewline + 1;
|
|
451
612
|
}
|
|
452
613
|
}
|
|
453
|
-
|
|
454
|
-
|
|
614
|
+
mkdirSync2(stateDir(), { recursive: true });
|
|
615
|
+
writeFileSync3(path, JSON.stringify(state), "utf-8");
|
|
455
616
|
if (state.tokensIn === 0 && state.tokensOut === 0) return null;
|
|
456
617
|
return {
|
|
457
618
|
// Identical cursor-range reports share an identity across transport retries.
|
|
458
619
|
// Native message identity distinguishes an in-place rotation of the range.
|
|
459
620
|
// This does not serialize readers of different, potentially overlapping ranges.
|
|
460
|
-
eventId:
|
|
621
|
+
eventId: createHash3("sha256").update(JSON.stringify([
|
|
461
622
|
sessionId,
|
|
462
623
|
file.dev,
|
|
463
624
|
file.ino,
|
|
@@ -542,18 +703,18 @@ var phoneDrivenEnv = (base) => ({
|
|
|
542
703
|
});
|
|
543
704
|
|
|
544
705
|
// src/throttle.ts
|
|
545
|
-
import { join as
|
|
546
|
-
import { tmpdir as
|
|
547
|
-
import { createHash as
|
|
548
|
-
import { existsSync as
|
|
549
|
-
var THROTTLE_DIR =
|
|
550
|
-
var markerPath = (key) =>
|
|
706
|
+
import { join as join5 } from "path";
|
|
707
|
+
import { tmpdir as tmpdir4 } from "os";
|
|
708
|
+
import { createHash as createHash4 } from "crypto";
|
|
709
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync3, statSync as statSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
710
|
+
var THROTTLE_DIR = join5(tmpdir4(), "pushary-throttle");
|
|
711
|
+
var markerPath = (key) => join5(THROTTLE_DIR, createHash4("sha256").update(key).digest("hex").slice(0, 16));
|
|
551
712
|
var throttlePass = (key, windowMs) => {
|
|
552
713
|
try {
|
|
553
714
|
const path = markerPath(key);
|
|
554
|
-
if (
|
|
555
|
-
|
|
556
|
-
|
|
715
|
+
if (existsSync4(path) && Date.now() - statSync4(path).mtimeMs < windowMs) return false;
|
|
716
|
+
mkdirSync3(THROTTLE_DIR, { recursive: true });
|
|
717
|
+
writeFileSync4(path, "", "utf-8");
|
|
557
718
|
return true;
|
|
558
719
|
} catch {
|
|
559
720
|
return false;
|
|
@@ -561,28 +722,28 @@ var throttlePass = (key, windowMs) => {
|
|
|
561
722
|
};
|
|
562
723
|
|
|
563
724
|
// src/events.ts
|
|
564
|
-
import { basename as basename2, join as
|
|
565
|
-
import { existsSync as
|
|
566
|
-
import { tmpdir as
|
|
567
|
-
var INTENT_DIR =
|
|
725
|
+
import { basename as basename2, join as join6 } from "path";
|
|
726
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync5, statSync as statSync5, writeFileSync as writeFileSync5 } from "fs";
|
|
727
|
+
import { tmpdir as tmpdir5 } from "os";
|
|
728
|
+
var INTENT_DIR = join6(tmpdir5(), "pushary-intent");
|
|
568
729
|
var INTENT_MAX_BYTES = 2048;
|
|
569
730
|
var INTENT_GRACE_MS = 10 * 60 * 1e3;
|
|
570
731
|
var sanitizeSession = (sessionId) => sessionId.replace(/[^A-Za-z0-9_-]/g, "_").slice(0, 128) || DEFAULT_SESSION;
|
|
571
|
-
var intentFile = (sessionId) =>
|
|
732
|
+
var intentFile = (sessionId) => join6(INTENT_DIR, sanitizeSession(sessionId));
|
|
572
733
|
var saveLastPrompt = (sessionId, prompt) => {
|
|
573
734
|
try {
|
|
574
735
|
const trimmed = prompt.replace(/\s+/g, " ").trim().slice(0, INTENT_MAX_BYTES);
|
|
575
736
|
if (!trimmed) return;
|
|
576
|
-
|
|
577
|
-
|
|
737
|
+
mkdirSync4(INTENT_DIR, { recursive: true });
|
|
738
|
+
writeFileSync5(intentFile(sessionId), trimmed, "utf-8");
|
|
578
739
|
} catch {
|
|
579
740
|
}
|
|
580
741
|
};
|
|
581
742
|
var readLastPrompt = (sessionId) => {
|
|
582
743
|
try {
|
|
583
744
|
const path = intentFile(sessionId);
|
|
584
|
-
if (isDefaultSession(sessionId) &&
|
|
585
|
-
const value =
|
|
745
|
+
if (isDefaultSession(sessionId) && statSync5(path).mtimeMs < Date.now() - INTENT_GRACE_MS) return void 0;
|
|
746
|
+
const value = readFileSync5(path, "utf-8").trim();
|
|
586
747
|
return value.length > 0 ? value : void 0;
|
|
587
748
|
} catch {
|
|
588
749
|
return void 0;
|
|
@@ -645,8 +806,8 @@ var POLICY_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
|
645
806
|
var readFreshCachedPolicy = (apiKey, agentType, sessionId) => {
|
|
646
807
|
const request = policyRequestFor(agentType);
|
|
647
808
|
const path = policyCacheFile(apiKey, request.agent, request.repoAware);
|
|
648
|
-
if (!
|
|
649
|
-
const cached = JSON.parse(
|
|
809
|
+
if (!existsSync5(path)) return null;
|
|
810
|
+
const cached = JSON.parse(readFileSync5(path, "utf-8"));
|
|
650
811
|
if (!isPolicyConfig(cached)) return null;
|
|
651
812
|
if ((cached._sessionId ?? null) !== (sessionId ?? null)) return null;
|
|
652
813
|
if (!cached._cachedAt || Date.now() - cached._cachedAt >= POLICY_CACHE_TTL_MS) return null;
|
|
@@ -1139,6 +1300,13 @@ export {
|
|
|
1139
1300
|
fetchModeState,
|
|
1140
1301
|
fetchModeOverride,
|
|
1141
1302
|
phoneDrivenEnv,
|
|
1303
|
+
DEFAULT_SESSION,
|
|
1304
|
+
readPendingCommandById,
|
|
1305
|
+
readPendingCommand,
|
|
1306
|
+
savePendingCommand,
|
|
1307
|
+
markPendingCommandDelivered,
|
|
1308
|
+
markPendingCommandFailed,
|
|
1309
|
+
removePendingCommand,
|
|
1142
1310
|
repoKeyFor,
|
|
1143
1311
|
throttlePass,
|
|
1144
1312
|
readLastUserPrompt,
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CLAUDE_HOOK_EVENTS,
|
|
3
3
|
supportedClaudeEvents
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-2D7BAOMY.js";
|
|
5
5
|
import {
|
|
6
6
|
guardBinary
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-3AJIK5AO.js";
|
|
8
8
|
import {
|
|
9
9
|
isProtectedByScope
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-OW6AZDY2.js";
|
|
11
11
|
import {
|
|
12
12
|
HOOK_LOCATOR_BINARY
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-WDKHZRAS.js";
|
|
14
14
|
|
|
15
15
|
// src/claude-config.ts
|
|
16
16
|
import { join } from "path";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
HOOK_BUDGETS,
|
|
3
3
|
OPENCODE_APPROVAL_EVENT
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-WDKHZRAS.js";
|
|
5
5
|
|
|
6
6
|
// src/opencode-plugin.ts
|
|
7
7
|
var OPENCODE_PLUGIN_MARKER = "pushary-opencode-plugin w1";
|
|
@@ -174,15 +174,18 @@ export const PusharyPlugin = async ({ client, directory, worktree }) => {
|
|
|
174
174
|
: null
|
|
175
175
|
const current = client && client.permission && typeof client.permission.reply === "function"
|
|
176
176
|
? () => client.permission.reply({
|
|
177
|
+
// Current v2 uses flat parameters; older generated clients read path/body.
|
|
178
|
+
requestID: asked.id, reply: allow ? "once" : "reject",
|
|
177
179
|
path: { requestID: asked.id },
|
|
178
180
|
body: { reply: allow ? "once" : "reject" },
|
|
179
|
-
})
|
|
181
|
+
}, { throwOnError: true })
|
|
180
182
|
: null
|
|
181
183
|
|
|
182
184
|
for (const attempt of [legacy, current]) {
|
|
183
185
|
if (!attempt) continue
|
|
184
186
|
try {
|
|
185
|
-
await attempt()
|
|
187
|
+
const result = await attempt()
|
|
188
|
+
if (result && result.error) continue
|
|
186
189
|
return
|
|
187
190
|
} catch {
|
|
188
191
|
// The person answered first, or this client does not serve that route.
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import {
|
|
14
14
|
isValidApiKey,
|
|
15
15
|
normalizeKeyScope
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-WDKHZRAS.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;
|
|
@@ -148,7 +148,7 @@ var describeKeyCheck = (check, baseUrl = getBaseUrl()) => {
|
|
|
148
148
|
return {
|
|
149
149
|
message: "Your Pushary plan is not active, so approvals will not deliver yet.",
|
|
150
150
|
next: [
|
|
151
|
-
"Your
|
|
151
|
+
"Your key is valid; activating the plan does not require replacing it.",
|
|
152
152
|
`Activate the plan: ${check.upgradeUrl}`,
|
|
153
153
|
"Then run: pushary doctor"
|
|
154
154
|
],
|
|
@@ -158,7 +158,7 @@ var describeKeyCheck = (check, baseUrl = getBaseUrl()) => {
|
|
|
158
158
|
case "unreachable":
|
|
159
159
|
return {
|
|
160
160
|
message: `Could not reach pushary.com to verify the key (${check.detail}).`,
|
|
161
|
-
next: ["
|
|
161
|
+
next: ["Account readiness is unverified. Re-run `pushary setup` once you are online."],
|
|
162
162
|
exitCode: EXIT.UNREACHABLE,
|
|
163
163
|
fatal: false
|
|
164
164
|
};
|
|
@@ -3,6 +3,9 @@ import {
|
|
|
3
3
|
resolveGlobalPackageVersion,
|
|
4
4
|
resolvePackageVersionFromBinary
|
|
5
5
|
} from "./chunk-L4ZCFMWW.js";
|
|
6
|
+
import {
|
|
7
|
+
MANAGED_PROVIDERS
|
|
8
|
+
} from "./chunk-WDKHZRAS.js";
|
|
6
9
|
|
|
7
10
|
// src/live-capabilities.ts
|
|
8
11
|
var CLAUDE_BRIDGE_CAPABILITY = "claude-bridge";
|
|
@@ -39,7 +42,7 @@ var resolveControlPolicy = (input) => {
|
|
|
39
42
|
if (input.providerAvailable && input.managerAvailable) return "enabled";
|
|
40
43
|
return input.servicePresent ? "legacy" : "unsupported";
|
|
41
44
|
};
|
|
42
|
-
var detectProviderLiveCapabilities = (providers =
|
|
45
|
+
var detectProviderLiveCapabilities = (providers = MANAGED_PROVIDERS) => {
|
|
43
46
|
const enabled = new Set(providers);
|
|
44
47
|
const geminiBin = enabled.has("gemini") ? resolveBinary("gemini") : void 0;
|
|
45
48
|
return providerLiveCapabilities({
|
|
@@ -1,21 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
|
-
ASKED_IN_EVERY_MODE_TOOLS
|
|
3
|
-
|
|
2
|
+
ASKED_IN_EVERY_MODE_TOOLS,
|
|
3
|
+
PRETOOLUSE_GATED_TOOLS
|
|
4
|
+
} from "./chunk-WDKHZRAS.js";
|
|
4
5
|
|
|
5
6
|
// src/claude-tools.ts
|
|
6
|
-
var PRETOOLUSE_GATED_TOOLS = [
|
|
7
|
-
"Bash",
|
|
8
|
-
"Write",
|
|
9
|
-
"Edit",
|
|
10
|
-
"MultiEdit",
|
|
11
|
-
"NotebookEdit",
|
|
12
|
-
"PowerShell",
|
|
13
|
-
"Monitor"
|
|
14
|
-
];
|
|
15
7
|
var PRETOOLUSE_PHONE_ANSWERED_TOOLS = ASKED_IN_EVERY_MODE_TOOLS;
|
|
16
8
|
var POSTTOOLUSE_MIRROR_ONLY_TOOLS = ["TodoWrite", "Task", "WebFetch", "WebSearch"];
|
|
17
9
|
var POSTTOOLUSE_MIRRORED_TOOLS = [...PRETOOLUSE_GATED_TOOLS, ...POSTTOOLUSE_MIRROR_ONLY_TOOLS];
|
|
18
|
-
var PRETOOLUSE_HANDLED_TOOLS = /* @__PURE__ */ new Set([...PRETOOLUSE_GATED_TOOLS, ...PRETOOLUSE_PHONE_ANSWERED_TOOLS]);
|
|
19
10
|
|
|
20
11
|
// src/claude-notifications.ts
|
|
21
12
|
var NOTIFICATION_MATCHED_TYPES = [
|
|
@@ -43,11 +34,9 @@ var NOTIFICATION_PUSH_TYPES = /* @__PURE__ */ new Set([
|
|
|
43
34
|
]);
|
|
44
35
|
|
|
45
36
|
export {
|
|
46
|
-
PRETOOLUSE_GATED_TOOLS,
|
|
47
37
|
PRETOOLUSE_PHONE_ANSWERED_TOOLS,
|
|
48
38
|
POSTTOOLUSE_MIRROR_ONLY_TOOLS,
|
|
49
39
|
POSTTOOLUSE_MIRRORED_TOOLS,
|
|
50
|
-
PRETOOLUSE_HANDLED_TOOLS,
|
|
51
40
|
NOTIFICATION_MATCHED_TYPES,
|
|
52
41
|
NOTIFICATION_PUSH_TYPES
|
|
53
42
|
};
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
configFilePath
|
|
3
|
+
} from "./chunk-2UMNXADU.js";
|
|
4
|
+
import {
|
|
5
|
+
normalizeInstallSource
|
|
6
|
+
} from "./chunk-WDKHZRAS.js";
|
|
7
|
+
|
|
1
8
|
// src/cli/fsx.ts
|
|
2
9
|
import { copyFileSync, existsSync, fsyncSync, mkdirSync, openSync, closeSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "fs";
|
|
3
10
|
import { dirname, join } from "path";
|
|
@@ -57,10 +64,45 @@ var writeJsonAtomicDurable = (filePath, data, mode) => {
|
|
|
57
64
|
}
|
|
58
65
|
};
|
|
59
66
|
|
|
67
|
+
// src/install-source.ts
|
|
68
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
69
|
+
var ENV_OVERRIDE = "PUSHARY_INSTALL_SOURCE";
|
|
70
|
+
var PLUGIN_ROOT = "CLAUDE_PLUGIN_ROOT";
|
|
71
|
+
var EDITOR_PLUGIN_MARKERS = ["cursor-plugin", "vscode-plugin"];
|
|
72
|
+
var detectInstallSource = (env = process.env, argv = process.argv) => {
|
|
73
|
+
const declared = env[ENV_OVERRIDE]?.trim();
|
|
74
|
+
if (declared) return normalizeInstallSource(declared);
|
|
75
|
+
const pluginRoot = env[PLUGIN_ROOT]?.trim();
|
|
76
|
+
if (pluginRoot) {
|
|
77
|
+
return EDITOR_PLUGIN_MARKERS.some((marker) => pluginRoot.includes(marker)) ? "editor_plugin" : "claude_plugin";
|
|
78
|
+
}
|
|
79
|
+
const entry = argv[1] ?? "";
|
|
80
|
+
if (entry.includes("_npx")) return "npx";
|
|
81
|
+
if (entry) return "npm";
|
|
82
|
+
return "unknown";
|
|
83
|
+
};
|
|
84
|
+
var storedInstallSource = () => {
|
|
85
|
+
try {
|
|
86
|
+
const parsed = JSON.parse(readFileSync2(configFilePath(), "utf-8"));
|
|
87
|
+
const stored = parsed.installSource;
|
|
88
|
+
return typeof stored === "string" && stored ? normalizeInstallSource(stored) : void 0;
|
|
89
|
+
} catch {
|
|
90
|
+
return void 0;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
var resolveInstallSourceFor = (config) => {
|
|
94
|
+
const stored = config.installSource;
|
|
95
|
+
if (typeof stored === "string" && stored) return normalizeInstallSource(stored);
|
|
96
|
+
return detectInstallSource();
|
|
97
|
+
};
|
|
98
|
+
var reportedInstallSource = () => storedInstallSource() ?? detectInstallSource();
|
|
99
|
+
|
|
60
100
|
export {
|
|
61
101
|
readJsonSafe,
|
|
62
102
|
backupFile,
|
|
63
103
|
writeFileAtomic,
|
|
64
104
|
writeJsonAtomic,
|
|
65
|
-
writeJsonAtomicDurable
|
|
105
|
+
writeJsonAtomicDurable,
|
|
106
|
+
resolveInstallSourceFor,
|
|
107
|
+
reportedInstallSource
|
|
66
108
|
};
|