@nocoo/pew 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/cli.d.ts.map +1 -1
  2. package/dist/cli.js +179 -1
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/init.d.ts +38 -0
  5. package/dist/commands/init.d.ts.map +1 -0
  6. package/dist/commands/init.js +73 -0
  7. package/dist/commands/init.js.map +1 -0
  8. package/dist/commands/notify.d.ts +11 -0
  9. package/dist/commands/notify.d.ts.map +1 -0
  10. package/dist/commands/notify.js +28 -0
  11. package/dist/commands/notify.js.map +1 -0
  12. package/dist/commands/status.d.ts +4 -0
  13. package/dist/commands/status.d.ts.map +1 -1
  14. package/dist/commands/status.js +1 -0
  15. package/dist/commands/status.js.map +1 -1
  16. package/dist/commands/uninstall.d.ts +39 -0
  17. package/dist/commands/uninstall.d.ts.map +1 -0
  18. package/dist/commands/uninstall.js +107 -0
  19. package/dist/commands/uninstall.js.map +1 -0
  20. package/dist/notifier/claude-hook.d.ts +18 -0
  21. package/dist/notifier/claude-hook.d.ts.map +1 -0
  22. package/dist/notifier/claude-hook.js +226 -0
  23. package/dist/notifier/claude-hook.js.map +1 -0
  24. package/dist/notifier/codex-notifier.d.ts +19 -0
  25. package/dist/notifier/codex-notifier.d.ts.map +1 -0
  26. package/dist/notifier/codex-notifier.js +258 -0
  27. package/dist/notifier/codex-notifier.js.map +1 -0
  28. package/dist/notifier/coordinator.d.ts +29 -0
  29. package/dist/notifier/coordinator.d.ts.map +1 -0
  30. package/dist/notifier/coordinator.js +176 -0
  31. package/dist/notifier/coordinator.js.map +1 -0
  32. package/dist/notifier/gemini-hook.d.ts +18 -0
  33. package/dist/notifier/gemini-hook.d.ts.map +1 -0
  34. package/dist/notifier/gemini-hook.js +243 -0
  35. package/dist/notifier/gemini-hook.js.map +1 -0
  36. package/dist/notifier/notify-handler.d.ts +41 -0
  37. package/dist/notifier/notify-handler.d.ts.map +1 -0
  38. package/dist/notifier/notify-handler.js +172 -0
  39. package/dist/notifier/notify-handler.js.map +1 -0
  40. package/dist/notifier/openclaw-hook.d.ts +28 -0
  41. package/dist/notifier/openclaw-hook.d.ts.map +1 -0
  42. package/dist/notifier/openclaw-hook.js +272 -0
  43. package/dist/notifier/openclaw-hook.js.map +1 -0
  44. package/dist/notifier/opencode-plugin.d.ts +20 -0
  45. package/dist/notifier/opencode-plugin.d.ts.map +1 -0
  46. package/dist/notifier/opencode-plugin.js +106 -0
  47. package/dist/notifier/opencode-plugin.js.map +1 -0
  48. package/dist/notifier/paths.d.ts +21 -0
  49. package/dist/notifier/paths.d.ts.map +1 -0
  50. package/dist/notifier/paths.js +36 -0
  51. package/dist/notifier/paths.js.map +1 -0
  52. package/dist/notifier/registry.d.ts +21 -0
  53. package/dist/notifier/registry.d.ts.map +1 -0
  54. package/dist/notifier/registry.js +145 -0
  55. package/dist/notifier/registry.js.map +1 -0
  56. package/dist/utils/paths.d.ts +4 -0
  57. package/dist/utils/paths.d.ts.map +1 -1
  58. package/dist/utils/paths.js +4 -0
  59. package/dist/utils/paths.js.map +1 -1
  60. package/package.json +1 -1
@@ -0,0 +1,172 @@
1
+ import { access, mkdir, readFile, unlink, writeFile } from "node:fs/promises";
2
+ import { constants } from "node:fs";
3
+ import { execFile } from "node:child_process";
4
+ import { dirname, join } from "node:path";
5
+ import { promisify } from "node:util";
6
+ const execFileAsync = promisify(execFile);
7
+ export const NOTIFY_HANDLER_MARKER = "PEW_NOTIFY_HANDLER";
8
+ export function buildNotifyHandler(opts) {
9
+ const { stateDir, pewBin } = opts;
10
+ return `#!/usr/bin/env node
11
+ // ${NOTIFY_HANDLER_MARKER} — Auto-generated, do not edit
12
+ "use strict";
13
+
14
+ const { appendFileSync, readFileSync, mkdirSync, existsSync } = require("node:fs");
15
+ const { join, resolve } = require("node:path");
16
+ const { spawn } = require("node:child_process");
17
+ const { homedir } = require("node:os");
18
+
19
+ const STATE_DIR = ${JSON.stringify(stateDir)};
20
+ const PEW_BIN = ${JSON.stringify(pewBin)};
21
+ const SELF_PATH = resolve(__filename);
22
+ const HOME_DIR = homedir();
23
+
24
+ const rawArgs = process.argv.slice(2);
25
+ let source = "";
26
+ const payloadArgs = [];
27
+ for (let i = 0; i < rawArgs.length; i++) {
28
+ const arg = rawArgs[i];
29
+ if (arg === "--source") {
30
+ source = rawArgs[i + 1] || source;
31
+ i += 1;
32
+ continue;
33
+ }
34
+ if (arg.startsWith("--source=")) {
35
+ source = arg.slice("--source=".length) || source;
36
+ continue;
37
+ }
38
+ payloadArgs.push(arg);
39
+ }
40
+
41
+ try {
42
+ mkdirSync(STATE_DIR, { recursive: true });
43
+ appendFileSync(join(STATE_DIR, "notify.signal"), "\\n", "utf8");
44
+ } catch (_) {}
45
+
46
+ const bin = existsSync(PEW_BIN) ? PEW_BIN : "npx";
47
+ const args = bin === PEW_BIN
48
+ ? ["notify", "--source=" + source, ...payloadArgs]
49
+ : ["@nocoo/pew", "notify", "--source=" + source, ...payloadArgs];
50
+
51
+ try {
52
+ const child = spawn(bin, args, {
53
+ detached: true,
54
+ stdio: "ignore",
55
+ env: { ...process.env },
56
+ });
57
+ child.unref();
58
+ } catch (_) {}
59
+
60
+ if (source === "codex") {
61
+ try {
62
+ const original = JSON.parse(
63
+ readFileSync(join(STATE_DIR, "codex_notify_original.json"), "utf8"),
64
+ );
65
+ const cmd = Array.isArray(original && original.notify) ? original.notify : null;
66
+ if (cmd && cmd.length > 0 && !isSelfNotify(cmd)) {
67
+ const child = spawn(cmd[0], cmd.slice(1), {
68
+ detached: true,
69
+ stdio: "ignore",
70
+ env: { ...process.env },
71
+ });
72
+ child.unref();
73
+ }
74
+ } catch (_) {}
75
+ }
76
+
77
+ process.exit(0);
78
+
79
+ function isSelfNotify(cmd) {
80
+ return cmd.some((part) => {
81
+ if (typeof part !== "string") return false;
82
+ if (!part.includes("notify.cjs")) return false;
83
+ const resolved = part.startsWith("~/")
84
+ ? join(HOME_DIR, part.slice(2))
85
+ : resolve(part);
86
+ return resolved === SELF_PATH;
87
+ });
88
+ }
89
+ `;
90
+ }
91
+ export async function writeNotifyHandler(opts) {
92
+ const fs = opts.fs ?? { readFile, writeFile, mkdir };
93
+ const now = opts.now ?? (() => new Date().toISOString());
94
+ const notifyPath = join(opts.binDir, "notify.cjs");
95
+ await fs.mkdir(opts.binDir, { recursive: true });
96
+ let existing = null;
97
+ try {
98
+ existing = await fs.readFile(notifyPath, "utf8");
99
+ }
100
+ catch (err) {
101
+ if (err?.code !== "ENOENT")
102
+ throw err;
103
+ }
104
+ if (existing === opts.source) {
105
+ return { changed: false, path: notifyPath };
106
+ }
107
+ let backupPath;
108
+ if (existing !== null) {
109
+ backupPath = `${notifyPath}.bak.${now().replace(/[:.]/g, "-")}`;
110
+ await fs.writeFile(backupPath, existing, "utf8");
111
+ }
112
+ await fs.writeFile(notifyPath, opts.source, "utf8");
113
+ return { changed: true, path: notifyPath, backupPath };
114
+ }
115
+ export async function removeNotifyHandler(opts) {
116
+ const fs = opts.fs ?? { readFile, unlink };
117
+ let existing;
118
+ try {
119
+ existing = await fs.readFile(opts.notifyPath, "utf8");
120
+ }
121
+ catch (err) {
122
+ if (err?.code === "ENOENT") {
123
+ return {
124
+ changed: false,
125
+ path: opts.notifyPath,
126
+ detail: "notify.cjs not found",
127
+ };
128
+ }
129
+ throw err;
130
+ }
131
+ if (!existing.includes(NOTIFY_HANDLER_MARKER)) {
132
+ return {
133
+ changed: false,
134
+ path: opts.notifyPath,
135
+ detail: "notify.cjs did not match pew marker",
136
+ warnings: ["File does not contain pew marker"],
137
+ };
138
+ }
139
+ await fs.unlink(opts.notifyPath);
140
+ return {
141
+ changed: true,
142
+ path: opts.notifyPath,
143
+ detail: "notify.cjs removed",
144
+ };
145
+ }
146
+ export async function resolvePewBin() {
147
+ const fromArgv = typeof process.argv[1] === "string" ? join(dirname(process.argv[1]), "pew") : null;
148
+ if (fromArgv && (await isExecutable(fromArgv))) {
149
+ return fromArgv;
150
+ }
151
+ try {
152
+ const result = await execFileAsync("which", ["pew"]);
153
+ const candidate = result.stdout.trim();
154
+ if (candidate && (await isExecutable(candidate))) {
155
+ return candidate;
156
+ }
157
+ }
158
+ catch {
159
+ // Fall through to the final error.
160
+ }
161
+ throw new Error("Unable to resolve pew binary. Ensure `pew` is available in PATH.");
162
+ }
163
+ async function isExecutable(filePath) {
164
+ try {
165
+ await access(filePath, constants.X_OK);
166
+ return true;
167
+ }
168
+ catch {
169
+ return false;
170
+ }
171
+ }
172
+ //# sourceMappingURL=notify-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notify-handler.js","sourceRoot":"","sources":["../../src/notifier/notify-handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { type SpawnSyncOptions } from "node:child_process";
2
+ import type { NotifierOperationResult, NotifierStatus } from "@pew/core";
3
+ interface OpenClawHookFs {
4
+ readFile: (path: string, encoding: BufferEncoding) => Promise<string>;
5
+ writeFile: (path: string, data: string, encoding: BufferEncoding) => Promise<unknown>;
6
+ mkdir: (path: string, options: {
7
+ recursive: boolean;
8
+ }) => Promise<unknown>;
9
+ rm: (path: string, options: {
10
+ recursive: boolean;
11
+ force: boolean;
12
+ }) => Promise<unknown>;
13
+ }
14
+ interface SpawnResult {
15
+ status: number | null;
16
+ }
17
+ export interface OpenClawHookOptions {
18
+ pluginBaseDir: string;
19
+ notifyPath: string;
20
+ openclawConfigPath: string;
21
+ fs?: OpenClawHookFs;
22
+ spawn?: (cmd: string, args: string[], opts?: SpawnSyncOptions) => SpawnResult;
23
+ }
24
+ export declare function installOpenClawHook(opts: OpenClawHookOptions): Promise<NotifierOperationResult>;
25
+ export declare function uninstallOpenClawHook(opts: OpenClawHookOptions): Promise<NotifierOperationResult>;
26
+ export declare function getOpenClawHookStatus(opts: OpenClawHookOptions): Promise<NotifierStatus>;
27
+ export {};
28
+ //# sourceMappingURL=openclaw-hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openclaw-hook.d.ts","sourceRoot":"","sources":["../../src/notifier/openclaw-hook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGtE,OAAO,KAAK,EAAE,uBAAuB,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEzE,UAAU,cAAc;IACtB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACtE,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACtF,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3E,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,SAAS,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACzF;AAED,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,EAAE,CAAC,EAAE,cAAc,CAAC;IACpB,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,gBAAgB,KAAK,WAAW,CAAC;CAC/E;AAKD,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,uBAAuB,CAAC,CAoDlC;AAED,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,uBAAuB,CAAC,CAyElC;AAED,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,cAAc,CAAC,CAsBzB"}
@@ -0,0 +1,272 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
3
+ import { dirname, join, resolve } from "node:path";
4
+ const SOURCE = "openclaw";
5
+ const PLUGIN_ID = "pew-session-sync";
6
+ export async function installOpenClawHook(opts) {
7
+ const fs = opts.fs ?? { readFile, writeFile, mkdir, rm };
8
+ const spawn = opts.spawn ?? defaultSpawn;
9
+ const pluginDir = join(opts.pluginBaseDir, PLUGIN_ID);
10
+ await fs.mkdir(pluginDir, { recursive: true });
11
+ await fs.writeFile(join(pluginDir, "package.json"), buildPackageJson(), "utf8");
12
+ await fs.writeFile(join(pluginDir, "openclaw.plugin.json"), buildPluginMeta(), "utf8");
13
+ await fs.writeFile(join(pluginDir, "index.js"), buildPluginIndex(opts.notifyPath, dirname(opts.pluginBaseDir)), "utf8");
14
+ try {
15
+ const installResult = spawn("openclaw", ["plugins", "install", "--link", pluginDir], { cwd: pluginDir });
16
+ const enableResult = spawn("openclaw", ["plugins", "enable", PLUGIN_ID], { cwd: pluginDir });
17
+ const warnings = [];
18
+ if ((installResult.status ?? 1) !== 0)
19
+ warnings.push("openclaw plugin install failed");
20
+ if ((enableResult.status ?? 1) !== 0)
21
+ warnings.push("openclaw plugin enable failed");
22
+ return {
23
+ source: SOURCE,
24
+ action: warnings.length > 0 ? "skip" : "install",
25
+ changed: true,
26
+ detail: warnings.length > 0
27
+ ? "OpenClaw plugin installation needs attention"
28
+ : "OpenClaw plugin installed",
29
+ warnings: warnings.length > 0 ? warnings : undefined,
30
+ };
31
+ }
32
+ catch (err) {
33
+ if (err?.code === "ENOENT") {
34
+ return {
35
+ source: SOURCE,
36
+ action: "skip",
37
+ changed: false,
38
+ detail: "OpenClaw CLI not found",
39
+ warnings: ["openclaw CLI not found"],
40
+ };
41
+ }
42
+ throw err;
43
+ }
44
+ }
45
+ export async function uninstallOpenClawHook(opts) {
46
+ const fs = opts.fs ?? { readFile, writeFile, mkdir, rm };
47
+ const pluginDir = join(opts.pluginBaseDir, PLUGIN_ID);
48
+ const loaded = await loadConfig(opts.openclawConfigPath, fs);
49
+ if (loaded.status === "missing") {
50
+ await fs.rm(pluginDir, { recursive: true, force: true });
51
+ return {
52
+ source: SOURCE,
53
+ action: "skip",
54
+ changed: false,
55
+ detail: "OpenClaw config not found",
56
+ };
57
+ }
58
+ if (loaded.status === "invalid") {
59
+ return {
60
+ source: SOURCE,
61
+ action: "skip",
62
+ changed: false,
63
+ detail: "Invalid OpenClaw config",
64
+ };
65
+ }
66
+ const config = loaded.config;
67
+ let changed = false;
68
+ const plugins = normalizeObject(config.plugins);
69
+ const entries = normalizeObject(plugins.entries);
70
+ if (entries[PLUGIN_ID]) {
71
+ delete entries[PLUGIN_ID];
72
+ changed = true;
73
+ }
74
+ const load = normalizeObject(plugins.load);
75
+ const paths = Array.isArray(load.paths) ? load.paths : [];
76
+ const resolvedPluginDir = resolve(pluginDir);
77
+ const nextPaths = paths.filter((entry) => resolve(String(entry)) !== resolvedPluginDir);
78
+ if (nextPaths.length !== paths.length) {
79
+ load.paths = nextPaths;
80
+ changed = true;
81
+ }
82
+ const installs = normalizeObject(plugins.installs);
83
+ for (const [key, value] of Object.entries(installs)) {
84
+ const sourcePath = typeof value.sourcePath === "string"
85
+ ? resolve(String(value.sourcePath))
86
+ : null;
87
+ const installPath = typeof value.installPath === "string"
88
+ ? resolve(String(value.installPath))
89
+ : null;
90
+ if (key === PLUGIN_ID || sourcePath === resolvedPluginDir || installPath === resolvedPluginDir) {
91
+ delete installs[key];
92
+ changed = true;
93
+ }
94
+ }
95
+ const nextPlugins = {};
96
+ if (Object.keys(entries).length > 0)
97
+ nextPlugins.entries = entries;
98
+ if (Array.isArray(load.paths) && load.paths.length > 0)
99
+ nextPlugins.load = load;
100
+ if (Object.keys(installs).length > 0)
101
+ nextPlugins.installs = installs;
102
+ if (changed) {
103
+ const nextConfig = { ...config };
104
+ if (Object.keys(nextPlugins).length > 0)
105
+ nextConfig.plugins = nextPlugins;
106
+ else
107
+ delete nextConfig.plugins;
108
+ await fs.writeFile(opts.openclawConfigPath, `${JSON.stringify(nextConfig, null, 2)}\n`, "utf8");
109
+ }
110
+ await fs.rm(pluginDir, { recursive: true, force: true });
111
+ return {
112
+ source: SOURCE,
113
+ action: "uninstall",
114
+ changed,
115
+ detail: changed ? "OpenClaw plugin removed" : "OpenClaw plugin not installed",
116
+ };
117
+ }
118
+ export async function getOpenClawHookStatus(opts) {
119
+ const fs = opts.fs ?? { readFile, writeFile, mkdir, rm };
120
+ const pluginDir = join(opts.pluginBaseDir, PLUGIN_ID);
121
+ const loaded = await loadConfig(opts.openclawConfigPath, fs);
122
+ if (loaded.status === "missing")
123
+ return "not-installed";
124
+ if (loaded.status === "invalid")
125
+ return "error";
126
+ const config = loaded.config;
127
+ const plugins = normalizeObject(config.plugins);
128
+ const entries = normalizeObject(plugins.entries);
129
+ const load = normalizeObject(plugins.load);
130
+ const installs = normalizeObject(plugins.installs);
131
+ const paths = Array.isArray(load.paths) ? load.paths.map((entry) => resolve(String(entry))) : [];
132
+ const resolvedPluginDir = resolve(pluginDir);
133
+ const filesReady = await hasPluginFiles(pluginDir, fs);
134
+ return Boolean(entries[PLUGIN_ID]) &&
135
+ paths.includes(resolvedPluginDir) &&
136
+ Boolean(installs[PLUGIN_ID]) &&
137
+ filesReady
138
+ ? "installed"
139
+ : "not-installed";
140
+ }
141
+ async function loadConfig(configPath, fs) {
142
+ try {
143
+ const raw = await fs.readFile(configPath, "utf8");
144
+ try {
145
+ const parsed = JSON.parse(raw);
146
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed)
147
+ ? { status: "ok", config: parsed }
148
+ : { status: "invalid" };
149
+ }
150
+ catch {
151
+ return { status: "invalid" };
152
+ }
153
+ }
154
+ catch (err) {
155
+ if (err?.code === "ENOENT")
156
+ return { status: "missing" };
157
+ throw err;
158
+ }
159
+ }
160
+ async function hasPluginFiles(pluginDir, fs) {
161
+ const files = ["package.json", "openclaw.plugin.json", "index.js"];
162
+ for (const file of files) {
163
+ try {
164
+ await fs.readFile(join(pluginDir, file), "utf8");
165
+ }
166
+ catch {
167
+ return false;
168
+ }
169
+ }
170
+ return true;
171
+ }
172
+ function buildPackageJson() {
173
+ return `${JSON.stringify({
174
+ name: "@pew/openclaw-session-sync",
175
+ version: "0.0.0",
176
+ private: true,
177
+ type: "module",
178
+ openclaw: { extensions: ["./index.js"] },
179
+ }, null, 2)}\n`;
180
+ }
181
+ function buildPluginMeta() {
182
+ return `${JSON.stringify({
183
+ id: PLUGIN_ID,
184
+ name: "Pew OpenClaw Session Sync",
185
+ description: "Trigger pew sync on OpenClaw agent/session lifecycle events.",
186
+ configSchema: {
187
+ type: "object",
188
+ additionalProperties: false,
189
+ properties: {},
190
+ },
191
+ }, null, 2)}\n`;
192
+ }
193
+ function buildPluginIndex(notifyPath, stateDir) {
194
+ return `import { spawn } from "node:child_process";
195
+ import { readFile, writeFile } from "node:fs/promises";
196
+
197
+ const NOTIFY_PATH = ${JSON.stringify(notifyPath)};
198
+ const THROTTLE_STATE_PATH = ${JSON.stringify(join(stateDir, "openclaw.session-sync.trigger-state.json"))};
199
+ const SESSION_TRIGGER_THROTTLE_MS = 15_000;
200
+
201
+ export default function register(api) {
202
+ api.on("agent_end", async () => {
203
+ await triggerSync();
204
+ });
205
+
206
+ api.on("gateway_start", async () => {
207
+ await triggerSync();
208
+ });
209
+
210
+ api.on("gateway_stop", async () => {
211
+ await triggerSync();
212
+ });
213
+ }
214
+
215
+ async function triggerSync() {
216
+ try {
217
+ if (await isThrottled()) return;
218
+ const child = spawn("/usr/bin/env", ["node", NOTIFY_PATH, "--source=openclaw"], {
219
+ detached: true,
220
+ stdio: "ignore",
221
+ env: { ...process.env },
222
+ });
223
+ child.unref();
224
+ } catch (_) {}
225
+ }
226
+
227
+ async function isThrottled() {
228
+ const now = Date.now();
229
+ let lastTriggeredAt = 0;
230
+
231
+ try {
232
+ const raw = await readFile(THROTTLE_STATE_PATH, "utf8");
233
+ const parsed = JSON.parse(raw);
234
+ if (parsed && typeof parsed.lastTriggeredAt === "number") {
235
+ lastTriggeredAt = parsed.lastTriggeredAt;
236
+ }
237
+ } catch (error) {
238
+ if (error?.code !== "ENOENT") return false;
239
+ }
240
+
241
+ if (now - lastTriggeredAt < SESSION_TRIGGER_THROTTLE_MS) {
242
+ return true;
243
+ }
244
+
245
+ try {
246
+ await writeFile(
247
+ THROTTLE_STATE_PATH,
248
+ JSON.stringify({ lastTriggeredAt: now }) + "\\n",
249
+ "utf8",
250
+ );
251
+ } catch (_) {}
252
+
253
+ return false;
254
+ }
255
+ `;
256
+ }
257
+ function normalizeObject(value) {
258
+ return value && typeof value === "object" && !Array.isArray(value)
259
+ ? { ...value }
260
+ : {};
261
+ }
262
+ function defaultSpawn(cmd, args, opts) {
263
+ const result = spawnSync(cmd, args, {
264
+ timeout: 30_000,
265
+ stdio: "ignore",
266
+ ...opts,
267
+ });
268
+ if (result.error)
269
+ throw result.error;
270
+ return { status: result.status };
271
+ }
272
+ //# sourceMappingURL=openclaw-hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openclaw-hook.js","sourceRoot":"","sources":["../../src/notifier/openclaw-hook.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { NotifierOperationResult, NotifierStatus } from "@pew/core";
2
+ interface OpenCodePluginFs {
3
+ readFile: (path: string, encoding: BufferEncoding) => Promise<string>;
4
+ writeFile: (path: string, data: string, encoding: BufferEncoding) => Promise<unknown>;
5
+ mkdir: (path: string, options: {
6
+ recursive: boolean;
7
+ }) => Promise<unknown>;
8
+ unlink: (path: string) => Promise<unknown>;
9
+ }
10
+ export interface OpenCodePluginOptions {
11
+ pluginDir: string;
12
+ notifyPath: string;
13
+ pluginName?: string;
14
+ fs?: OpenCodePluginFs;
15
+ }
16
+ export declare function installOpenCodePlugin(opts: OpenCodePluginOptions): Promise<NotifierOperationResult>;
17
+ export declare function uninstallOpenCodePlugin(opts: OpenCodePluginOptions): Promise<NotifierOperationResult>;
18
+ export declare function getOpenCodePluginStatus(opts: OpenCodePluginOptions): Promise<NotifierStatus>;
19
+ export {};
20
+ //# sourceMappingURL=opencode-plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode-plugin.d.ts","sourceRoot":"","sources":["../../src/notifier/opencode-plugin.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,uBAAuB,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEzE,UAAU,gBAAgB;IACxB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACtE,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACtF,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3E,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,EAAE,CAAC,EAAE,gBAAgB,CAAC;CACvB;AAMD,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,uBAAuB,CAAC,CAgClC;AAED,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,uBAAuB,CAAC,CAgClC;AAED,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,cAAc,CAAC,CAYzB"}
@@ -0,0 +1,106 @@
1
+ import { mkdir, readFile, unlink, writeFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ const SOURCE = "opencode";
4
+ const DEFAULT_PLUGIN_NAME = "pew-tracker.js";
5
+ const PLUGIN_MARKER = "PEW_TRACKER_PLUGIN";
6
+ export async function installOpenCodePlugin(opts) {
7
+ const fs = opts.fs ?? { readFile, writeFile, mkdir, unlink };
8
+ const pluginName = opts.pluginName ?? DEFAULT_PLUGIN_NAME;
9
+ const pluginPath = join(opts.pluginDir, pluginName);
10
+ const nextSource = buildOpenCodePlugin({ notifyPath: opts.notifyPath });
11
+ const existing = await readOptional(pluginPath, fs);
12
+ if (existing === nextSource) {
13
+ return {
14
+ source: SOURCE,
15
+ action: "install",
16
+ changed: false,
17
+ detail: "OpenCode plugin already installed",
18
+ };
19
+ }
20
+ await fs.mkdir(opts.pluginDir, { recursive: true });
21
+ let backupPath;
22
+ if (existing !== null) {
23
+ backupPath = `${pluginPath}.bak.${new Date().toISOString().replace(/[:.]/g, "-")}`;
24
+ await fs.writeFile(backupPath, existing, "utf8");
25
+ }
26
+ await fs.writeFile(pluginPath, nextSource, "utf8");
27
+ return {
28
+ source: SOURCE,
29
+ action: "install",
30
+ changed: true,
31
+ detail: "OpenCode plugin installed",
32
+ backupPath,
33
+ };
34
+ }
35
+ export async function uninstallOpenCodePlugin(opts) {
36
+ const fs = opts.fs ?? { readFile, writeFile, mkdir, unlink };
37
+ const pluginName = opts.pluginName ?? DEFAULT_PLUGIN_NAME;
38
+ const pluginPath = join(opts.pluginDir, pluginName);
39
+ const existing = await readOptional(pluginPath, fs);
40
+ if (existing === null) {
41
+ return {
42
+ source: SOURCE,
43
+ action: "skip",
44
+ changed: false,
45
+ detail: "OpenCode plugin not found",
46
+ };
47
+ }
48
+ if (!existing.includes(PLUGIN_MARKER)) {
49
+ return {
50
+ source: SOURCE,
51
+ action: "skip",
52
+ changed: false,
53
+ detail: "OpenCode plugin file did not match pew marker",
54
+ warnings: ["File does not contain pew marker"],
55
+ };
56
+ }
57
+ await fs.unlink(pluginPath);
58
+ return {
59
+ source: SOURCE,
60
+ action: "uninstall",
61
+ changed: true,
62
+ detail: "OpenCode plugin removed",
63
+ };
64
+ }
65
+ export async function getOpenCodePluginStatus(opts) {
66
+ const fs = opts.fs ?? { readFile, writeFile, mkdir, unlink };
67
+ const pluginName = opts.pluginName ?? DEFAULT_PLUGIN_NAME;
68
+ let existing;
69
+ try {
70
+ existing = await readOptional(join(opts.pluginDir, pluginName), fs);
71
+ }
72
+ catch {
73
+ return "error";
74
+ }
75
+ if (existing === null)
76
+ return "not-installed";
77
+ return existing.includes(PLUGIN_MARKER) ? "installed" : "error";
78
+ }
79
+ function buildOpenCodePlugin({ notifyPath }) {
80
+ return `// ${PLUGIN_MARKER}
81
+ const notifyPath = ${JSON.stringify(notifyPath)};
82
+ export const PewTrackerPlugin = async ({ $ }) => {
83
+ return {
84
+ event: async ({ event }) => {
85
+ if (!event || event.type !== "session.updated") return;
86
+ try {
87
+ if (!notifyPath) return;
88
+ const proc = $\`/usr/bin/env node ${"${notifyPath}"} --source=opencode\`;
89
+ if (proc && typeof proc.catch === "function") proc.catch(() => {});
90
+ } catch (_) {}
91
+ }
92
+ };
93
+ };
94
+ `;
95
+ }
96
+ async function readOptional(filePath, fs) {
97
+ try {
98
+ return await fs.readFile(filePath, "utf8");
99
+ }
100
+ catch (err) {
101
+ if (err?.code === "ENOENT")
102
+ return null;
103
+ throw err;
104
+ }
105
+ }
106
+ //# sourceMappingURL=opencode-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode-plugin.js","sourceRoot":"","sources":["../../src/notifier/opencode-plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export interface NotifierPaths {
2
+ stateDir: string;
3
+ binDir: string;
4
+ notifyPath: string;
5
+ lockPath: string;
6
+ signalPath: string;
7
+ claudeDir: string;
8
+ claudeSettingsPath: string;
9
+ geminiDir: string;
10
+ geminiSettingsPath: string;
11
+ opencodeConfigDir: string;
12
+ opencodePluginDir: string;
13
+ openclawHome: string;
14
+ openclawConfigPath: string;
15
+ openclawPluginDir: string;
16
+ codexHome: string;
17
+ codexConfigPath: string;
18
+ codexNotifyOriginalPath: string;
19
+ }
20
+ export declare function resolveNotifierPaths(home: string, env?: Record<string, string | undefined>): NotifierPaths;
21
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/notifier/paths.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,uBAAuB,EAAE,MAAM,CAAC;CACjC;AAOD,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GACpD,aAAa,CAoCf"}