@pushary/agent-hooks 0.89.13 → 0.90.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +73 -0
- package/data/SKILL.md +1 -1
- package/data/cursor-plugin/skills/pushary/SKILL.md +1 -1
- package/data/vscode-plugin/skills/pushary/SKILL.md +1 -1
- package/dist/bin/pushary-bell-hook.js +4 -4
- package/dist/bin/pushary-bell.js +8 -8
- package/dist/bin/pushary-claude.js +72 -21
- package/dist/bin/pushary-clean.js +16 -42
- package/dist/bin/pushary-codex-bridge.js +37 -12
- package/dist/bin/pushary-codex-hook.js +45 -12
- package/dist/bin/pushary-codex.js +7 -7
- package/dist/bin/pushary-connect.js +11 -10
- package/dist/bin/pushary-daemon.js +187 -63
- package/dist/bin/pushary-disconnect.js +8 -8
- package/dist/bin/pushary-doctor.js +108 -25
- package/dist/bin/pushary-elicitation-hook.js +4 -4
- package/dist/bin/pushary-gemini-bridge.js +33 -11
- package/dist/bin/pushary-gemini-hook.js +21 -10
- package/dist/bin/pushary-hook.js +13 -13
- package/dist/bin/pushary-login.js +18 -7
- package/dist/bin/pushary-logout.js +6 -6
- package/dist/bin/pushary-mode.js +28 -21
- package/dist/bin/pushary-notification-hook.js +7 -7
- package/dist/bin/pushary-opencode-hook.js +8 -8
- package/dist/bin/pushary-permission-denied-hook.js +11 -11
- package/dist/bin/pushary-permission-hook.js +11 -11
- package/dist/bin/pushary-post-hook.js +14 -8
- package/dist/bin/pushary-prompt-hook.js +7 -7
- package/dist/bin/pushary-session-end-hook.js +7 -7
- package/dist/bin/pushary-session-start-hook.js +7 -7
- package/dist/bin/pushary-setup.js +168 -45
- package/dist/bin/pushary-stats.js +4 -4
- package/dist/bin/pushary-status.js +11 -10
- package/dist/bin/pushary-stop-hook.js +14 -8
- package/dist/bin/pushary-stopfailure-hook.js +7 -7
- package/dist/bin/pushary-suggestions.js +2 -2
- package/dist/bin/pushary-transcripts.js +6 -6
- package/dist/bin/pushary-upgrade.js +15 -15
- package/dist/bin/pushary-wait.js +5 -5
- package/dist/bin/pushary.js +1 -1
- package/dist/{chunk-B2HND22S.js → chunk-2LAHXHBR.js} +1 -1
- package/dist/{chunk-GMJDQDXU.js → chunk-43GMYSS4.js} +1 -0
- package/dist/{chunk-OX35BSPV.js → chunk-4LOPSGLP.js} +70 -11
- package/dist/{chunk-JTBDBKHU.js → chunk-54ELC7D7.js} +1 -1
- package/dist/{chunk-C56VHSXU.js → chunk-5NAZ7SFS.js} +1 -1
- package/dist/{chunk-4IPSMEGT.js → chunk-7FE2KABY.js} +12 -2
- package/dist/{chunk-RAEPAUNJ.js → chunk-7TPQEWUZ.js} +1 -1
- package/dist/{chunk-ZO43JTT3.js → chunk-AJYV3VGU.js} +1 -1
- package/dist/{chunk-QFJZHVVL.js → chunk-AZPIQG4G.js} +35 -1
- package/dist/{chunk-5MNTWAAJ.js → chunk-B6H2KAQC.js} +29 -22
- package/dist/{chunk-MNTZKFZI.js → chunk-BQBEH6TV.js} +5 -5
- package/dist/{chunk-WHDSJ6PD.js → chunk-BVBEURWJ.js} +1 -1
- package/dist/{chunk-ZWEKONU6.js → chunk-CELX75MW.js} +1 -1
- package/dist/{chunk-ZP3SNUP7.js → chunk-CNPAT3HL.js} +3 -2
- package/dist/{chunk-YXT55PYF.js → chunk-DYP6SMOR.js} +1 -1
- package/dist/chunk-DZDI62LY.js +145 -0
- package/dist/{chunk-VF3RTVWY.js → chunk-EZIEXHYM.js} +15 -7
- package/dist/{chunk-7JZCADBR.js → chunk-F2ICEWZL.js} +101 -19
- package/dist/{chunk-JHJHCMAF.js → chunk-F7OURW3C.js} +24 -6
- package/dist/{chunk-VASZ6TWW.js → chunk-FQL5E6NG.js} +2 -2
- package/dist/{chunk-JVLB5CAJ.js → chunk-GL3FFM7A.js} +7 -4
- package/dist/{chunk-5YEF55AX.js → chunk-H2QZRQR2.js} +1 -1
- package/dist/{chunk-S4BLNILH.js → chunk-I463AEG3.js} +1 -1
- package/dist/{chunk-ANMHIZZY.js → chunk-JW4KO5AF.js} +1 -1
- package/dist/{chunk-3YGGEDJK.js → chunk-KUZWXPUS.js} +3 -2
- package/dist/{chunk-N4QJ3CLX.js → chunk-L4E2BIJ2.js} +80 -7
- package/dist/{chunk-NBDU3R3G.js → chunk-OSALSIUF.js} +1 -1
- package/dist/{chunk-KNLKHJZR.js → chunk-PYA4FLKI.js} +32 -21
- package/dist/chunk-QCGNGEGE.js +15 -0
- package/dist/chunk-S6LYP7QA.js +127 -0
- package/dist/{chunk-M3UABYRT.js → chunk-UZNKVRLE.js} +1 -1
- package/dist/{chunk-FOGW6O2Y.js → chunk-VHWCVD42.js} +1 -1
- package/dist/{chunk-QINYXLA5.js → chunk-VNMKIJZB.js} +15 -2
- package/dist/{chunk-CBGGUEKE.js → chunk-Y6BWPERV.js} +90 -7
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +11 -11
- package/package.json +1 -1
- package/dist/chunk-MSTHT2M7.js +0 -72
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
FILE_TARGET_TOOLS,
|
|
6
6
|
redactSecrets,
|
|
7
7
|
redactSecretsDeep
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-VNMKIJZB.js";
|
|
9
9
|
|
|
10
10
|
// ../hook-mapping/src/describe.ts
|
|
11
11
|
import { isAbsolute, relative, resolve } from "path";
|
|
@@ -44,6 +44,48 @@ var eventPrefixes = {
|
|
|
44
44
|
Read: (input) => `read: ${input.file_path ?? "unknown"}`,
|
|
45
45
|
TodoWrite: (input) => describeTodoProgress(input.todos)
|
|
46
46
|
};
|
|
47
|
+
var MCP_TOOL_PREFIX = "mcp__";
|
|
48
|
+
var parseMcpToolName = (toolName) => {
|
|
49
|
+
if (!toolName.startsWith(MCP_TOOL_PREFIX)) return void 0;
|
|
50
|
+
const rest = toolName.slice(MCP_TOOL_PREFIX.length);
|
|
51
|
+
const split = rest.indexOf("__");
|
|
52
|
+
if (split <= 0 || split + 2 >= rest.length) return void 0;
|
|
53
|
+
return { server: rest.slice(0, split), tool: rest.slice(split + 2) };
|
|
54
|
+
};
|
|
55
|
+
var NETWORK_TARGET_KEYS = ["url", "urls", "href", "host", "hosts", "hostname", "domain", "domains"];
|
|
56
|
+
var ABSOLUTE_HTTP_URL = /^https?:\/\//i;
|
|
57
|
+
var HOSTNAME = /^(?=.{1,253}$)[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+(?::\d{1,5})?$/i;
|
|
58
|
+
var hostOfUrl = (value) => {
|
|
59
|
+
try {
|
|
60
|
+
return new URL(value).host || void 0;
|
|
61
|
+
} catch {
|
|
62
|
+
return void 0;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
var hostOf = (value, bareHostnames) => {
|
|
66
|
+
if (typeof value !== "string") return void 0;
|
|
67
|
+
const trimmed = value.trim();
|
|
68
|
+
if (ABSOLUTE_HTTP_URL.test(trimmed)) return hostOfUrl(trimmed);
|
|
69
|
+
return bareHostnames && HOSTNAME.test(trimmed) ? trimmed : void 0;
|
|
70
|
+
};
|
|
71
|
+
var firstHost = (value, bareHostnames) => Array.isArray(value) ? value.map((entry) => hostOf(entry, bareHostnames)).find((host) => host !== void 0) : hostOf(value, bareHostnames);
|
|
72
|
+
var deriveNetworkTarget = (toolInput) => {
|
|
73
|
+
for (const key of NETWORK_TARGET_KEYS) {
|
|
74
|
+
const host = firstHost(toolInput[key], true);
|
|
75
|
+
if (host) return host;
|
|
76
|
+
}
|
|
77
|
+
return Object.values(toolInput).map((value) => firstHost(value, false)).find((host) => host !== void 0);
|
|
78
|
+
};
|
|
79
|
+
var describeUnbuiltCall = (toolName, toolInput, format) => {
|
|
80
|
+
const mcp = parseMcpToolName(toolName);
|
|
81
|
+
const host = deriveNetworkTarget(toolInput);
|
|
82
|
+
if (mcp) {
|
|
83
|
+
if (format === "event") return `called ${mcp.tool} on ${mcp.server}`;
|
|
84
|
+
return host ? `call ${mcp.tool} on ${mcp.server} to reach ${host}` : `call ${mcp.tool} on ${mcp.server}`;
|
|
85
|
+
}
|
|
86
|
+
if (host) return format === "event" ? `accessed ${host}` : `network access to ${host}`;
|
|
87
|
+
return void 0;
|
|
88
|
+
};
|
|
47
89
|
var EVENT_ACTION_MAX = 120;
|
|
48
90
|
var HOOK_FALLBACK_MAX = 200;
|
|
49
91
|
var UNNAMED_ACTION = "this request";
|
|
@@ -51,11 +93,12 @@ var describeToolCall = (toolName, toolInput, format = "hook") => {
|
|
|
51
93
|
if (!toolName) return "";
|
|
52
94
|
const prefixes = format === "hook" ? hookPrefixes : eventPrefixes;
|
|
53
95
|
const builder = prefixes[toolName];
|
|
96
|
+
const unbuilt = builder ? void 0 : describeUnbuiltCall(toolName, toolInput ?? {}, format);
|
|
54
97
|
const detail = JSON.stringify(toolInput ?? {});
|
|
55
|
-
const raw = builder ? builder(toolInput) : format === "hook" ? detail === "{}" || detail === void 0 ? toolName : `${toolName}: ${detail}` : `${toolName}: done
|
|
98
|
+
const raw = builder ? builder(toolInput) : unbuilt ?? (format === "hook" ? detail === "{}" || detail === void 0 ? toolName : `${toolName}: ${detail}` : `${toolName}: done`);
|
|
56
99
|
const redacted = redactSecrets(raw);
|
|
57
100
|
if (format === "event") return redacted.slice(0, EVENT_ACTION_MAX);
|
|
58
|
-
return builder ? redacted : redacted.slice(0, HOOK_FALLBACK_MAX);
|
|
101
|
+
return builder || unbuilt ? redacted : redacted.slice(0, HOOK_FALLBACK_MAX);
|
|
59
102
|
};
|
|
60
103
|
var TOOL_TARGET_MAX_LENGTH = 80;
|
|
61
104
|
var deriveCommandHead = (command) => {
|
|
@@ -76,7 +119,9 @@ var deriveToolTarget = (toolName, toolInput) => {
|
|
|
76
119
|
if (dot <= 0) return void 0;
|
|
77
120
|
return base.slice(dot).slice(0, TOOL_TARGET_MAX_LENGTH);
|
|
78
121
|
}
|
|
79
|
-
|
|
122
|
+
const mcp = parseMcpToolName(toolName);
|
|
123
|
+
if (mcp) return mcp.server.slice(0, TOOL_TARGET_MAX_LENGTH);
|
|
124
|
+
return deriveNetworkTarget(toolInput)?.slice(0, TOOL_TARGET_MAX_LENGTH);
|
|
80
125
|
};
|
|
81
126
|
var SCRIPT_RUNNERS = /* @__PURE__ */ new Set(["npm", "pnpm", "yarn", "bun", "npx", "deno", "rake", "make", "just", "task", "turbo"]);
|
|
82
127
|
var RUN_SUBCOMMANDS = /* @__PURE__ */ new Set(["run", "run-script", "exec", "task"]);
|
|
@@ -210,7 +255,7 @@ var rawActionBody = (toolName, toolInput) => {
|
|
|
210
255
|
if (toolName === "Bash" || toolName === "PowerShell" || toolName === "Monitor" || toolName === "run_shell_command" || toolName === "shell" || toolName === "apply_patch") {
|
|
211
256
|
return firstString(toolInput.command);
|
|
212
257
|
}
|
|
213
|
-
return
|
|
258
|
+
return firstString(toolInput.url, toolInput.href);
|
|
214
259
|
};
|
|
215
260
|
var deriveActionBody = (toolName, toolInput) => {
|
|
216
261
|
try {
|
|
@@ -264,11 +309,36 @@ var summarizeStop = (input) => {
|
|
|
264
309
|
if (running > 0) return `Paused with ${running} background task${running === 1 ? "" : "s"} still running`;
|
|
265
310
|
const crons = countArray(input.session_crons);
|
|
266
311
|
if (crons > 0) return `Idle until a scheduled task wakes it (${crons} pending)`;
|
|
267
|
-
return summarizeFinalMessage(input.last_assistant_message);
|
|
312
|
+
return summarizeFinalMessage(input.last_assistant_message ?? input.prompt_response);
|
|
313
|
+
};
|
|
314
|
+
var subagentStopAction = (agentType) => {
|
|
315
|
+
const name = typeof agentType === "string" ? agentType.replace(/\s+/g, " ").trim() : "";
|
|
316
|
+
return name ? `${name} subagent finished` : "Subagent finished";
|
|
317
|
+
};
|
|
318
|
+
var subagentStopSummary = (input) => {
|
|
319
|
+
const message = input.last_assistant_message ?? input.prompt_response;
|
|
320
|
+
if (typeof message === "string" && message.trim()) return summarizeStop(input);
|
|
321
|
+
return subagentStopAction(input.agent_type);
|
|
322
|
+
};
|
|
323
|
+
var COMPACTION_TRIGGERS = {
|
|
324
|
+
manual: "on request",
|
|
325
|
+
auto: "automatically"
|
|
326
|
+
};
|
|
327
|
+
var compactionAction = (hookEvent, trigger) => {
|
|
328
|
+
const how = typeof trigger === "string" ? COMPACTION_TRIGGERS[trigger] : void 0;
|
|
329
|
+
const base = hookEvent === "PostCompact" ? "Compacted context" : "Compacting context";
|
|
330
|
+
return how ? `${base} ${how}` : base;
|
|
268
331
|
};
|
|
269
332
|
var sessionStartAction = (source) => source === "resume" ? "Session resumed" : "Session started";
|
|
270
333
|
var sessionEndAction = (reason) => typeof reason === "string" && SESSION_END_ACTIONS[reason] || "Session ended";
|
|
271
334
|
var taskTitleFrom = (prompt) => typeof prompt === "string" ? prompt.replace(/\s+/g, " ").trim().slice(0, TASK_TITLE_MAX_LENGTH) || void 0 : void 0;
|
|
335
|
+
var asString = (value) => typeof value === "string" && value.length > 0 ? value : void 0;
|
|
336
|
+
var sessionIdentityOf = (payload) => {
|
|
337
|
+
const sessionId = asString(payload.session_id);
|
|
338
|
+
const agentId = asString(payload.agent_id);
|
|
339
|
+
if (!agentId) return { sessionId };
|
|
340
|
+
return { sessionId: agentId, parentSessionId: sessionId };
|
|
341
|
+
};
|
|
272
342
|
|
|
273
343
|
export {
|
|
274
344
|
HOOK_FALLBACK_MAX,
|
|
@@ -287,7 +357,10 @@ export {
|
|
|
287
357
|
deriveBlocker,
|
|
288
358
|
AGENT_IDENTITIES,
|
|
289
359
|
summarizeStop,
|
|
360
|
+
subagentStopSummary,
|
|
361
|
+
compactionAction,
|
|
290
362
|
sessionStartAction,
|
|
291
363
|
sessionEndAction,
|
|
292
|
-
taskTitleFrom
|
|
364
|
+
taskTitleFrom,
|
|
365
|
+
sessionIdentityOf
|
|
293
366
|
};
|
|
@@ -3,6 +3,10 @@ import {
|
|
|
3
3
|
openSealedKey,
|
|
4
4
|
publicKeyFingerprint
|
|
5
5
|
} from "./chunk-3EGEA4KH.js";
|
|
6
|
+
import {
|
|
7
|
+
humanIsTty,
|
|
8
|
+
writeHuman
|
|
9
|
+
} from "./chunk-QCGNGEGE.js";
|
|
6
10
|
import {
|
|
7
11
|
useColor
|
|
8
12
|
} from "./chunk-5RUIFDTP.js";
|
|
@@ -11,7 +15,7 @@ import {
|
|
|
11
15
|
} from "./chunk-BSZYIAZL.js";
|
|
12
16
|
import {
|
|
13
17
|
reportedInstallSource
|
|
14
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-JW4KO5AF.js";
|
|
15
19
|
|
|
16
20
|
// src/reach.ts
|
|
17
21
|
var reachVerdict = (channels) => {
|
|
@@ -263,16 +267,6 @@ var describeRoundTrip = (outcome) => {
|
|
|
263
267
|
}
|
|
264
268
|
};
|
|
265
269
|
|
|
266
|
-
// src/cli/human.ts
|
|
267
|
-
var stream = process.stdout;
|
|
268
|
-
var setHumanStream = (target) => {
|
|
269
|
-
stream = target;
|
|
270
|
-
};
|
|
271
|
-
var writeHuman = (text) => {
|
|
272
|
-
stream.write(text);
|
|
273
|
-
};
|
|
274
|
-
var humanIsTty = () => stream === process.stdout && process.stdout.isTTY === true;
|
|
275
|
-
|
|
276
270
|
// src/onboarding.ts
|
|
277
271
|
import qrcodeTerminal from "qrcode-terminal";
|
|
278
272
|
var paint = (open) => (s) => useColor() ? `${open}${s}\x1B[0m` : s;
|
|
@@ -650,6 +644,20 @@ var confirmAppConnection = async (apiKey) => {
|
|
|
650
644
|
}
|
|
651
645
|
return sendAndConfirm(apiKey, channels);
|
|
652
646
|
};
|
|
647
|
+
var planAppConnect = (channels) => channels.precise && ownedApp(channels) === 0 ? { kind: "unpaired", repair: describeAppRepair(reachVerdict(channels)) ?? [] } : { kind: "send" };
|
|
648
|
+
var connectExistingApp = async (apiKey) => {
|
|
649
|
+
const probe = await fetchChannels(apiKey);
|
|
650
|
+
if (probe.kind !== "ok") return describeProbeFailure(probe);
|
|
651
|
+
const plan = planAppConnect(probe.status);
|
|
652
|
+
if (plan.kind === "send") {
|
|
653
|
+
console.log(` ${check} ${describeExistingConnection(probe.status)}`);
|
|
654
|
+
return sendAndConfirm(apiKey, probe.status);
|
|
655
|
+
}
|
|
656
|
+
console.log(` ${yellow("!")} No Pushary app of yours is connected to this site, and nothing was paired just now.`);
|
|
657
|
+
for (const line of plan.repair) console.log(` ${dim(line)}`);
|
|
658
|
+
console.log(` ${dim("No app yet? Get it at")} ${cyan("https://pushary.com/download")}`);
|
|
659
|
+
return phoneFailure("app_not_paired", plan.repair);
|
|
660
|
+
};
|
|
653
661
|
var printConnectInstructions = async (apiKey) => {
|
|
654
662
|
const probe = await fetchChannels(apiKey);
|
|
655
663
|
if (probe.kind !== "ok") return describeProbeFailure(probe);
|
|
@@ -737,6 +745,8 @@ var ackPairing = async (pairId) => {
|
|
|
737
745
|
} catch {
|
|
738
746
|
}
|
|
739
747
|
};
|
|
748
|
+
var pairFailed = (reason) => ({ kind: "failed", reason });
|
|
749
|
+
var pairingEscapeApplies = (outcome) => outcome.reason === "timeout" || outcome.reason === "expired" || outcome.reason === "cancelled";
|
|
740
750
|
var buildPairLinks = (pairId, publicKeyB64, baseUrl = apiBase(), code = null) => {
|
|
741
751
|
const id = encodeURIComponent(pairId);
|
|
742
752
|
const pk = encodeURIComponent(publicKeyB64);
|
|
@@ -760,7 +770,7 @@ var connectViaAppPairing = async (options = {}) => {
|
|
|
760
770
|
const started = await startPairing(keypair.publicKeyB64);
|
|
761
771
|
if (!started) {
|
|
762
772
|
console.log(` ${yellow("!")} Couldn't start pairing. Check your connection and try again.`);
|
|
763
|
-
return
|
|
773
|
+
return pairFailed("unreachable");
|
|
764
774
|
}
|
|
765
775
|
const { pairId, code } = started;
|
|
766
776
|
const { qrLink, universalLink, deepLink } = buildPairLinks(pairId, keypair.publicKeyB64, apiBase(), code);
|
|
@@ -800,14 +810,14 @@ var connectViaAppPairing = async (options = {}) => {
|
|
|
800
810
|
let consecutiveFailures = 0;
|
|
801
811
|
try {
|
|
802
812
|
while (Date.now() < deadline) {
|
|
803
|
-
if (cancelled) return
|
|
813
|
+
if (cancelled) return pairFailed("cancelled");
|
|
804
814
|
const claim = await claimPairing(pairId);
|
|
805
815
|
if (claim === null) {
|
|
806
816
|
consecutiveFailures += 1;
|
|
807
817
|
if (consecutiveFailures >= PAIR_MAX_CONSECUTIVE_FAILURES) {
|
|
808
818
|
stop(yellow("!"), "Can't reach pushary.com to finish pairing. Check your connection, then re-run setup.");
|
|
809
819
|
await cancelPairing(pairId);
|
|
810
|
-
return
|
|
820
|
+
return pairFailed("unreachable");
|
|
811
821
|
}
|
|
812
822
|
await sleep(PAIR_POLL_INTERVAL_MS);
|
|
813
823
|
continue;
|
|
@@ -820,29 +830,29 @@ var connectViaAppPairing = async (options = {}) => {
|
|
|
820
830
|
} catch {
|
|
821
831
|
stop(yellow("!"), "Pairing failed to decrypt \u2014 re-run setup to try again");
|
|
822
832
|
await cancelPairing(pairId);
|
|
823
|
-
return
|
|
833
|
+
return pairFailed("decrypt");
|
|
824
834
|
}
|
|
825
835
|
await ackPairing(pairId);
|
|
826
836
|
stop(check, "App connected");
|
|
827
|
-
return { apiKey, handle: claim.siteSlug };
|
|
837
|
+
return { kind: "paired", apiKey, handle: claim.siteSlug };
|
|
828
838
|
}
|
|
829
839
|
if (claim?.status === "expired") {
|
|
830
840
|
stop(yellow("!"), "Pairing expired \u2014 re-run setup to try again");
|
|
831
|
-
return
|
|
841
|
+
return pairFailed("expired");
|
|
832
842
|
}
|
|
833
843
|
if (claim?.status === "failed") {
|
|
834
844
|
stop(yellow("!"), describePairFailure(claim.reason));
|
|
835
|
-
return
|
|
845
|
+
return pairFailed("rejected");
|
|
836
846
|
}
|
|
837
847
|
await sleep(PAIR_POLL_INTERVAL_MS);
|
|
838
848
|
}
|
|
839
849
|
stop(yellow("!"), "Timed out waiting for the app");
|
|
840
850
|
await cancelPairing(pairId);
|
|
841
|
-
return
|
|
851
|
+
return pairFailed("timeout");
|
|
842
852
|
} catch (err) {
|
|
843
853
|
stop(yellow("!"), `Pairing error ${dim(`(${err instanceof Error ? err.message : "network"})`)}`);
|
|
844
854
|
await cancelPairing(pairId);
|
|
845
|
-
return
|
|
855
|
+
return pairFailed("unreachable");
|
|
846
856
|
} finally {
|
|
847
857
|
process.off("SIGINT", onInterrupt);
|
|
848
858
|
}
|
|
@@ -853,10 +863,11 @@ export {
|
|
|
853
863
|
describeReach,
|
|
854
864
|
verifyRoundTrip,
|
|
855
865
|
describeRoundTrip,
|
|
856
|
-
setHumanStream,
|
|
857
866
|
fetchChannels,
|
|
858
867
|
connectDevice,
|
|
859
868
|
confirmAppConnection,
|
|
869
|
+
connectExistingApp,
|
|
860
870
|
printConnectInstructions,
|
|
871
|
+
pairingEscapeApplies,
|
|
861
872
|
connectViaAppPairing
|
|
862
873
|
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// src/cli/human.ts
|
|
2
|
+
var stream = process.stdout;
|
|
3
|
+
var setHumanStream = (target) => {
|
|
4
|
+
stream = target;
|
|
5
|
+
};
|
|
6
|
+
var writeHuman = (text) => {
|
|
7
|
+
stream.write(text);
|
|
8
|
+
};
|
|
9
|
+
var humanIsTty = () => stream === process.stdout && process.stdout.isTTY === true;
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
setHumanStream,
|
|
13
|
+
writeHuman,
|
|
14
|
+
humanIsTty
|
|
15
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import {
|
|
2
|
+
HOOK_LOCATOR_BINARY
|
|
3
|
+
} from "./chunk-VNMKIJZB.js";
|
|
4
|
+
|
|
5
|
+
// src/diagnostics/bridge.ts
|
|
6
|
+
import { execFileSync } from "child_process";
|
|
7
|
+
import { existsSync, readFileSync } from "fs";
|
|
8
|
+
import { homedir } from "os";
|
|
9
|
+
import { dirname, join } from "path";
|
|
10
|
+
var BRIDGE_BUNDLE_IDENTIFIER = "com.pushary.app";
|
|
11
|
+
var BRIDGE_HELPER_SUFFIX = "/Contents/Helpers/pushary-bridge";
|
|
12
|
+
var BRIDGE_BUNDLE_ROOTS = ["/Applications/Pushary.app", "$HOME/Applications/Pushary.app"];
|
|
13
|
+
var expandHome = (path, home) => path.replaceAll("$HOME", home);
|
|
14
|
+
var parseBridgeStub = (contents, stubPath) => {
|
|
15
|
+
const helperSuffix = contents.match(/^H=(\S+)$/m)?.[1] ?? BRIDGE_HELPER_SUFFIX;
|
|
16
|
+
const cachePath = contents.match(/^C="([^"\n]+)"$/m)?.[1] ?? join(dirname(stubPath), ".bridge-cache");
|
|
17
|
+
const rootsLine = contents.match(/^for P in ((?:"[^"\n]*"\s*)+); do$/m)?.[1];
|
|
18
|
+
const bundleRoots = rootsLine ? [...rootsLine.matchAll(/"([^"]*)"/g)].map((match) => match[1]) : BRIDGE_BUNDLE_ROOTS;
|
|
19
|
+
const bundleIdentifier = contents.match(/kMDItemCFBundleIdentifier == "([^"]+)"/)?.[1] ?? BRIDGE_BUNDLE_IDENTIFIER;
|
|
20
|
+
return { helperSuffix, cachePath, bundleRoots, bundleIdentifier };
|
|
21
|
+
};
|
|
22
|
+
var resolveBridgeStub = (stubPath, probe) => {
|
|
23
|
+
const contents = probe.readFile(stubPath);
|
|
24
|
+
if (contents === null) return { kind: "no-stub", stub: stubPath };
|
|
25
|
+
const shape = parseBridgeStub(contents, stubPath);
|
|
26
|
+
const helperIn = (bundle) => `${bundle}${shape.helperSuffix}`;
|
|
27
|
+
const looked = [];
|
|
28
|
+
for (const root of shape.bundleRoots.map((root2) => expandHome(root2, probe.home))) {
|
|
29
|
+
looked.push(root);
|
|
30
|
+
if (probe.exists(helperIn(root))) return { kind: "bundle", helper: helperIn(root), via: "root" };
|
|
31
|
+
}
|
|
32
|
+
const cached = shape.cachePath ? probe.readFile(shape.cachePath)?.split("\n")[0]?.trim() : void 0;
|
|
33
|
+
if (cached) {
|
|
34
|
+
looked.push(cached);
|
|
35
|
+
if (probe.exists(helperIn(cached))) return { kind: "bundle", helper: helperIn(cached), via: "cache" };
|
|
36
|
+
}
|
|
37
|
+
for (const found of probe.mdfind(shape.bundleIdentifier)) {
|
|
38
|
+
looked.push(found);
|
|
39
|
+
if (probe.exists(helperIn(found))) return { kind: "bundle", helper: helperIn(found), via: "spotlight" };
|
|
40
|
+
}
|
|
41
|
+
return { kind: "missing", stub: stubPath, looked };
|
|
42
|
+
};
|
|
43
|
+
var BRIDGE_GONE_MESSAGE = "the Mac app is gone but its hooks remain; run pushary setup or reinstall the app";
|
|
44
|
+
var describeBridgeResolution = (resolution) => {
|
|
45
|
+
switch (resolution.kind) {
|
|
46
|
+
case "bundle":
|
|
47
|
+
return `${resolution.helper} (${resolution.via === "root" ? "installed" : resolution.via === "cache" ? "cached path" : "found by Spotlight"})`;
|
|
48
|
+
case "missing":
|
|
49
|
+
return BRIDGE_GONE_MESSAGE;
|
|
50
|
+
case "no-stub":
|
|
51
|
+
return `${resolution.stub} is not there; ${BRIDGE_GONE_MESSAGE}`;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
var isBridgeLocator = (executable) => executable !== null && executable.split(/[/\\]/).pop() === HOOK_LOCATOR_BINARY;
|
|
55
|
+
var spotlight = (bundleIdentifier) => {
|
|
56
|
+
if (process.platform !== "darwin") return [];
|
|
57
|
+
try {
|
|
58
|
+
return execFileSync("/usr/bin/mdfind", [`kMDItemCFBundleIdentifier == "${bundleIdentifier}"`], {
|
|
59
|
+
encoding: "utf-8",
|
|
60
|
+
timeout: 5e3,
|
|
61
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
62
|
+
}).split("\n").map((line) => line.trim()).filter((line) => line !== "");
|
|
63
|
+
} catch {
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
var readOrNull = (path) => {
|
|
68
|
+
try {
|
|
69
|
+
return readFileSync(path, "utf-8");
|
|
70
|
+
} catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
var liveBridgeProbe = () => ({
|
|
75
|
+
exists: existsSync,
|
|
76
|
+
readFile: readOrNull,
|
|
77
|
+
mdfind: spotlight,
|
|
78
|
+
home: homedir()
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// src/diagnostics/service-runtime.ts
|
|
82
|
+
var unescapeXml = (value) => value.replaceAll(""", '"').replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">").replaceAll("&", "&");
|
|
83
|
+
var unquoteSystemd = (value) => value.replaceAll('\\"', '"').replaceAll("\\\\", "\\").replaceAll("%%", "%");
|
|
84
|
+
var readServiceExecPath = (contents, platform) => {
|
|
85
|
+
if (platform === "darwin") {
|
|
86
|
+
const program = contents.match(/<key>ProgramArguments<\/key>\s*<array>\s*<string>([^<]*)<\/string>/)?.[1];
|
|
87
|
+
return program ? unescapeXml(program) : null;
|
|
88
|
+
}
|
|
89
|
+
if (platform === "linux") {
|
|
90
|
+
const exec = contents.match(/^ExecStart="((?:[^"\\]|\\.)*)"/m)?.[1];
|
|
91
|
+
return exec ? unquoteSystemd(exec) : null;
|
|
92
|
+
}
|
|
93
|
+
if (platform === "win32") {
|
|
94
|
+
const command = contents.match(/<Command>([^<]*)<\/Command>/)?.[1];
|
|
95
|
+
return command ? unescapeXml(command) : null;
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
};
|
|
99
|
+
var MANAGER_SEGMENTS = [
|
|
100
|
+
[".nvm", "nvm"],
|
|
101
|
+
["nvm", "nvm"],
|
|
102
|
+
["fnm", "fnm"],
|
|
103
|
+
[".fnm", "fnm"],
|
|
104
|
+
[".volta", "volta"],
|
|
105
|
+
["volta", "volta"],
|
|
106
|
+
[".asdf", "asdf"],
|
|
107
|
+
["asdf", "asdf"]
|
|
108
|
+
];
|
|
109
|
+
var versionManagerOf = (execPath) => {
|
|
110
|
+
const segments = execPath.split(/[/\\]/);
|
|
111
|
+
for (const segment of segments) {
|
|
112
|
+
const hit = MANAGER_SEGMENTS.find(([name]) => name === segment);
|
|
113
|
+
if (hit) return hit[1];
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
};
|
|
117
|
+
var describeVersionManagerPin = (execPath, manager) => `The background service is pinned to ${execPath}, which ${manager} manages. Switching Node versions strands it; run pushary daemon install afterwards.`;
|
|
118
|
+
|
|
119
|
+
export {
|
|
120
|
+
resolveBridgeStub,
|
|
121
|
+
describeBridgeResolution,
|
|
122
|
+
isBridgeLocator,
|
|
123
|
+
liveBridgeProbe,
|
|
124
|
+
readServiceExecPath,
|
|
125
|
+
versionManagerOf,
|
|
126
|
+
describeVersionManagerPin
|
|
127
|
+
};
|
|
@@ -91,7 +91,7 @@ var INSTALL_SOURCES = [
|
|
|
91
91
|
var isInstallSource = (value) => typeof value === "string" && INSTALL_SOURCES.includes(value);
|
|
92
92
|
var normalizeInstallSource = (value) => isInstallSource(value) ? value : "unknown";
|
|
93
93
|
var HOOK_BUDGETS = {
|
|
94
|
-
claude: { budgetSeconds:
|
|
94
|
+
claude: { budgetSeconds: 600, guardSeconds: 10 },
|
|
95
95
|
codex: { budgetSeconds: 180, guardSeconds: 10 },
|
|
96
96
|
gemini: { budgetSeconds: 180, guardSeconds: 10 },
|
|
97
97
|
// The Cursor gate is a dependency-free .mjs that cannot import this module; it
|
|
@@ -1054,6 +1054,8 @@ var resolvePolicyAcross = (config, toolName, modeOverride, toolInputs, cwd, repo
|
|
|
1054
1054
|
};
|
|
1055
1055
|
var isModeStateDegraded = (state) => state?.degraded === true;
|
|
1056
1056
|
var KILL_REASON = "Stopped by user, this agent was halted from Pushary";
|
|
1057
|
+
var PUSHARY_TOOL_PREFIX = "mcp__pushary__";
|
|
1058
|
+
var isPusharyOwnTool = (toolName) => toolName.startsWith(PUSHARY_TOOL_PREFIX);
|
|
1057
1059
|
var strictestScopeVerdict = (scope, paths) => {
|
|
1058
1060
|
if (paths.length === 0) return evaluateScope(scope, void 0);
|
|
1059
1061
|
let worst = { outcome: "in_scope" };
|
|
@@ -1085,6 +1087,13 @@ var ASKED_IN_EVERY_MODE = new Set(ASKED_IN_EVERY_MODE_TOOLS);
|
|
|
1085
1087
|
var isAskedInEveryMode = (toolName) => ASKED_IN_EVERY_MODE.has(toolName);
|
|
1086
1088
|
var resolveGate = (input) => {
|
|
1087
1089
|
const { modeState, config, toolName, toolInputs, cwd, repoKey, sessionId } = input;
|
|
1090
|
+
if (isPusharyOwnTool(toolName)) {
|
|
1091
|
+
return {
|
|
1092
|
+
kind: "defer",
|
|
1093
|
+
policy: resolvePolicyAcross(config, toolName, modeState.mode, toolInputs, cwd, repoKey, sessionId),
|
|
1094
|
+
reason: "own_tool"
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1088
1097
|
if (modeState.kill) return { kind: "kill", reason: KILL_REASON };
|
|
1089
1098
|
const policy = resolvePolicyAcross(config, toolName, modeState.mode, toolInputs, cwd, repoKey, sessionId);
|
|
1090
1099
|
const verdict = verdictForPolicy(policy);
|
|
@@ -1128,9 +1137,11 @@ var modeStateFromResponse = (data) => {
|
|
|
1128
1137
|
// Validated rather than cast: a malformed contract must read as no contract,
|
|
1129
1138
|
// never as one that silently matches nothing.
|
|
1130
1139
|
scope: isScopeContract(data.scope) ? data.scope : null,
|
|
1131
|
-
degraded: false
|
|
1140
|
+
degraded: false,
|
|
1141
|
+
askHandoff: data.askHandoff === true
|
|
1132
1142
|
};
|
|
1133
1143
|
};
|
|
1144
|
+
var stoppedOutput = (output, stopReason) => ({ ...output, continue: false, stopReason });
|
|
1134
1145
|
var claudePreToolUseOutput = (decision, reason, updatedInput) => ({
|
|
1135
1146
|
hookSpecificOutput: {
|
|
1136
1147
|
hookEventName: "PreToolUse",
|
|
@@ -1362,10 +1373,12 @@ export {
|
|
|
1362
1373
|
resolveAutoResolveOrigin,
|
|
1363
1374
|
resolvePolicy,
|
|
1364
1375
|
KILL_REASON,
|
|
1376
|
+
isPusharyOwnTool,
|
|
1365
1377
|
shouldDeferToNativeMode,
|
|
1366
1378
|
ASKED_IN_EVERY_MODE_TOOLS,
|
|
1367
1379
|
resolveGate,
|
|
1368
1380
|
modeStateFromResponse,
|
|
1381
|
+
stoppedOutput,
|
|
1369
1382
|
claudePreToolUseOutput,
|
|
1370
1383
|
PENDING_COMMAND_PREFIX,
|
|
1371
1384
|
pendingCommandEvents,
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
import {
|
|
2
2
|
pusharyDir
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-KUZWXPUS.js";
|
|
4
4
|
import {
|
|
5
5
|
readJsonSafe
|
|
6
6
|
} from "./chunk-4LL6LG5X.js";
|
|
7
7
|
|
|
8
8
|
// src/process-ownership.ts
|
|
9
9
|
import { createHash, randomUUID } from "crypto";
|
|
10
|
-
import { mkdirSync, readdirSync, unlinkSync, writeFileSync } from "fs";
|
|
10
|
+
import { mkdirSync, readdirSync, statSync, unlinkSync, writeFileSync } from "fs";
|
|
11
11
|
import { createConnection, createServer } from "net";
|
|
12
12
|
import { join } from "path";
|
|
13
13
|
var MAX_PROOF_BYTES = 1024;
|
|
14
14
|
var ownershipDir = (options) => options.dir ?? join(pusharyDir(), "processes");
|
|
15
15
|
var proofPath = (dir, sessionId) => join(dir, `${createHash("sha256").update(sessionId).digest("hex")}.json`);
|
|
16
|
+
var isOptionalTimestamp = (value) => value === void 0 || typeof value === "string" && Number.isFinite(Date.parse(value));
|
|
16
17
|
var isProof = (value) => {
|
|
17
18
|
if (!value || typeof value !== "object") return false;
|
|
18
19
|
const proof = value;
|
|
19
|
-
return typeof proof.sessionId === "string" && Number.isInteger(proof.pid) && proof.pid > 1 && Number.isInteger(proof.port) && proof.port > 0 && proof.port <= 65535 && typeof proof.token === "string" && proof.token.length > 0 && (proof.spawnId === void 0 || typeof proof.spawnId === "string");
|
|
20
|
+
return typeof proof.sessionId === "string" && Number.isInteger(proof.pid) && proof.pid > 1 && Number.isInteger(proof.port) && proof.port > 0 && proof.port <= 65535 && typeof proof.token === "string" && proof.token.length > 0 && (proof.spawnId === void 0 || typeof proof.spawnId === "string") && isOptionalTimestamp(proof.startedAt) && isOptionalTimestamp(proof.heartbeatAt);
|
|
20
21
|
};
|
|
21
22
|
var removeProof = (path, token) => {
|
|
22
23
|
const current = readJsonSafe(path);
|
|
@@ -34,16 +35,74 @@ var processIsAlive = (pid) => {
|
|
|
34
35
|
return error.code === "EPERM";
|
|
35
36
|
}
|
|
36
37
|
};
|
|
37
|
-
var
|
|
38
|
+
var fileTimes = (path) => {
|
|
39
|
+
try {
|
|
40
|
+
const stat = statSync(path);
|
|
41
|
+
return { createdAt: stat.birthtimeMs || stat.mtimeMs, modifiedAt: stat.mtimeMs };
|
|
42
|
+
} catch {
|
|
43
|
+
return { createdAt: 0, modifiedAt: 0 };
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
var parseTimestamp = (value) => {
|
|
47
|
+
if (value === void 0) return null;
|
|
48
|
+
const parsed = Date.parse(value);
|
|
49
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
50
|
+
};
|
|
51
|
+
var proofEntry = (proof, path) => {
|
|
52
|
+
const times = fileTimes(path);
|
|
53
|
+
const recordedStart = parseTimestamp(proof.startedAt);
|
|
54
|
+
const startedAt = recordedStart ?? times.createdAt;
|
|
55
|
+
return {
|
|
56
|
+
sessionId: proof.sessionId,
|
|
57
|
+
pid: proof.pid,
|
|
58
|
+
spawnId: proof.spawnId ?? null,
|
|
59
|
+
startedAt,
|
|
60
|
+
lastSeenAt: parseTimestamp(proof.heartbeatAt) ?? recordedStart ?? times.modifiedAt,
|
|
61
|
+
alive: processIsAlive(proof.pid)
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
var safeUnlink = (path) => {
|
|
65
|
+
try {
|
|
66
|
+
unlinkSync(path);
|
|
67
|
+
} catch {
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
var listProcessProofs = (options = {}) => {
|
|
71
|
+
const dir = ownershipDir(options);
|
|
72
|
+
const entries = [];
|
|
38
73
|
try {
|
|
39
74
|
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
40
75
|
if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
|
|
41
76
|
const path = join(dir, entry.name);
|
|
42
77
|
const stored = readJsonSafe(path);
|
|
43
|
-
if (stored.kind !== "ok" || !isProof(stored.value)
|
|
78
|
+
if (stored.kind !== "ok" || !isProof(stored.value)) {
|
|
79
|
+
if (options.reapDead) safeUnlink(path);
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const listed = proofEntry(stored.value, path);
|
|
83
|
+
if (!listed.alive && options.reapDead) safeUnlink(path);
|
|
84
|
+
entries.push(listed);
|
|
44
85
|
}
|
|
45
86
|
} catch {
|
|
46
87
|
}
|
|
88
|
+
return entries;
|
|
89
|
+
};
|
|
90
|
+
var pruneProofs = (dir) => {
|
|
91
|
+
listProcessProofs({ dir, reapDead: true });
|
|
92
|
+
};
|
|
93
|
+
var wasSpawned = (entry) => entry.spawnId !== null;
|
|
94
|
+
var silentSpawnedProofs = (entries, now, silenceMs) => {
|
|
95
|
+
const freshestByPid = /* @__PURE__ */ new Map();
|
|
96
|
+
for (const entry of entries) {
|
|
97
|
+
freshestByPid.set(entry.pid, Math.max(freshestByPid.get(entry.pid) ?? 0, entry.lastSeenAt));
|
|
98
|
+
}
|
|
99
|
+
const reported = /* @__PURE__ */ new Set();
|
|
100
|
+
return entries.filter((entry) => {
|
|
101
|
+
if (!entry.alive || !wasSpawned(entry) || reported.has(entry.pid)) return false;
|
|
102
|
+
if (now - (freshestByPid.get(entry.pid) ?? 0) < silenceMs) return false;
|
|
103
|
+
reported.add(entry.pid);
|
|
104
|
+
return true;
|
|
105
|
+
});
|
|
47
106
|
};
|
|
48
107
|
var startProcessOwnership = (identity, options = {}) => {
|
|
49
108
|
const dir = ownershipDir(options);
|
|
@@ -88,7 +147,7 @@ var startProcessOwnership = (identity, options = {}) => {
|
|
|
88
147
|
return;
|
|
89
148
|
}
|
|
90
149
|
try {
|
|
91
|
-
proof = { ...identity, port: address.port, token };
|
|
150
|
+
proof = { ...identity, port: address.port, token, startedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
92
151
|
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
93
152
|
pruneProofs(dir);
|
|
94
153
|
writeFileSync(path, JSON.stringify(proof), {
|
|
@@ -107,6 +166,14 @@ var startProcessOwnership = (identity, options = {}) => {
|
|
|
107
166
|
process.once("exit", cleanup);
|
|
108
167
|
return {
|
|
109
168
|
ready,
|
|
169
|
+
touch(at = Date.now()) {
|
|
170
|
+
if (stopped || !proof) return;
|
|
171
|
+
proof = { ...proof, heartbeatAt: new Date(at).toISOString() };
|
|
172
|
+
try {
|
|
173
|
+
writeFileSync(path, JSON.stringify(proof), { encoding: "utf8", mode: 384 });
|
|
174
|
+
} catch {
|
|
175
|
+
}
|
|
176
|
+
},
|
|
110
177
|
stop() {
|
|
111
178
|
if (stopped) return;
|
|
112
179
|
stopped = true;
|
|
@@ -184,9 +251,25 @@ var verifyProof = (proof, options) => new Promise((resolve) => {
|
|
|
184
251
|
});
|
|
185
252
|
});
|
|
186
253
|
|
|
254
|
+
// src/session-idle.ts
|
|
255
|
+
var SESSION_IDLE_TIMEOUT_MS = 10 * 6e4;
|
|
256
|
+
var SESSION_REAP_GRACE_MS = 5 * 6e4;
|
|
257
|
+
var SESSION_REAP_SILENCE_MS = SESSION_IDLE_TIMEOUT_MS + SESSION_REAP_GRACE_MS;
|
|
258
|
+
var idleDeadlinePassed = (idleSince, now, timeoutMs = SESSION_IDLE_TIMEOUT_MS) => idleSince !== null && now - idleSince >= timeoutMs;
|
|
259
|
+
var describeIdleWindow = (timeoutMs) => {
|
|
260
|
+
const minutes = Math.round(timeoutMs / 6e4);
|
|
261
|
+
return minutes >= 1 ? `${minutes} minute${minutes === 1 ? "" : "s"}` : `${Math.round(timeoutMs / 1e3)}s`;
|
|
262
|
+
};
|
|
263
|
+
|
|
187
264
|
export {
|
|
265
|
+
listProcessProofs,
|
|
266
|
+
silentSpawnedProofs,
|
|
188
267
|
startProcessOwnership,
|
|
189
268
|
withSpawnProcessOwnership,
|
|
190
269
|
ownsLiveProcess,
|
|
191
|
-
findLiveProcessBySpawnId
|
|
270
|
+
findLiveProcessBySpawnId,
|
|
271
|
+
SESSION_IDLE_TIMEOUT_MS,
|
|
272
|
+
SESSION_REAP_SILENCE_MS,
|
|
273
|
+
idleDeadlinePassed,
|
|
274
|
+
describeIdleWindow
|
|
192
275
|
};
|