@nocoo/pew 0.6.0 → 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 (84) 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/session-upload.d.ts +6 -22
  13. package/dist/commands/session-upload.d.ts.map +1 -1
  14. package/dist/commands/session-upload.js +12 -144
  15. package/dist/commands/session-upload.js.map +1 -1
  16. package/dist/commands/status.d.ts +4 -0
  17. package/dist/commands/status.d.ts.map +1 -1
  18. package/dist/commands/status.js +1 -0
  19. package/dist/commands/status.js.map +1 -1
  20. package/dist/commands/uninstall.d.ts +39 -0
  21. package/dist/commands/uninstall.d.ts.map +1 -0
  22. package/dist/commands/uninstall.js +107 -0
  23. package/dist/commands/uninstall.js.map +1 -0
  24. package/dist/commands/upload-engine.d.ts +63 -0
  25. package/dist/commands/upload-engine.d.ts.map +1 -0
  26. package/dist/commands/upload-engine.js +164 -0
  27. package/dist/commands/upload-engine.js.map +1 -0
  28. package/dist/commands/upload.d.ts +5 -21
  29. package/dist/commands/upload.d.ts.map +1 -1
  30. package/dist/commands/upload.js +11 -144
  31. package/dist/commands/upload.js.map +1 -1
  32. package/dist/notifier/claude-hook.d.ts +18 -0
  33. package/dist/notifier/claude-hook.d.ts.map +1 -0
  34. package/dist/notifier/claude-hook.js +226 -0
  35. package/dist/notifier/claude-hook.js.map +1 -0
  36. package/dist/notifier/codex-notifier.d.ts +19 -0
  37. package/dist/notifier/codex-notifier.d.ts.map +1 -0
  38. package/dist/notifier/codex-notifier.js +258 -0
  39. package/dist/notifier/codex-notifier.js.map +1 -0
  40. package/dist/notifier/coordinator.d.ts +29 -0
  41. package/dist/notifier/coordinator.d.ts.map +1 -0
  42. package/dist/notifier/coordinator.js +176 -0
  43. package/dist/notifier/coordinator.js.map +1 -0
  44. package/dist/notifier/gemini-hook.d.ts +18 -0
  45. package/dist/notifier/gemini-hook.d.ts.map +1 -0
  46. package/dist/notifier/gemini-hook.js +243 -0
  47. package/dist/notifier/gemini-hook.js.map +1 -0
  48. package/dist/notifier/notify-handler.d.ts +41 -0
  49. package/dist/notifier/notify-handler.d.ts.map +1 -0
  50. package/dist/notifier/notify-handler.js +172 -0
  51. package/dist/notifier/notify-handler.js.map +1 -0
  52. package/dist/notifier/openclaw-hook.d.ts +28 -0
  53. package/dist/notifier/openclaw-hook.d.ts.map +1 -0
  54. package/dist/notifier/openclaw-hook.js +272 -0
  55. package/dist/notifier/openclaw-hook.js.map +1 -0
  56. package/dist/notifier/opencode-plugin.d.ts +20 -0
  57. package/dist/notifier/opencode-plugin.d.ts.map +1 -0
  58. package/dist/notifier/opencode-plugin.js +106 -0
  59. package/dist/notifier/opencode-plugin.js.map +1 -0
  60. package/dist/notifier/paths.d.ts +21 -0
  61. package/dist/notifier/paths.d.ts.map +1 -0
  62. package/dist/notifier/paths.js +36 -0
  63. package/dist/notifier/paths.js.map +1 -0
  64. package/dist/notifier/registry.d.ts +21 -0
  65. package/dist/notifier/registry.d.ts.map +1 -0
  66. package/dist/notifier/registry.js +145 -0
  67. package/dist/notifier/registry.js.map +1 -0
  68. package/dist/storage/base-queue.d.ts +40 -0
  69. package/dist/storage/base-queue.d.ts.map +1 -0
  70. package/dist/storage/base-queue.js +89 -0
  71. package/dist/storage/base-queue.js.map +1 -0
  72. package/dist/storage/local-queue.d.ts +4 -24
  73. package/dist/storage/local-queue.d.ts.map +1 -1
  74. package/dist/storage/local-queue.js +5 -64
  75. package/dist/storage/local-queue.js.map +1 -1
  76. package/dist/storage/session-queue.d.ts +3 -21
  77. package/dist/storage/session-queue.d.ts.map +1 -1
  78. package/dist/storage/session-queue.js +4 -58
  79. package/dist/storage/session-queue.js.map +1 -1
  80. package/dist/utils/paths.d.ts +4 -0
  81. package/dist/utils/paths.d.ts.map +1 -1
  82. package/dist/utils/paths.js +4 -0
  83. package/dist/utils/paths.js.map +1 -1
  84. package/package.json +1 -1
@@ -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":"AAAA,OAAO,EAAE,SAAS,EAAyB,MAAM,oBAAoB,CAAC;AACtE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsBnD,MAAM,MAAM,GAAG,UAAU,CAAC;AAC1B,MAAM,SAAS,GAAG,kBAAkB,CAAC;AAErC,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,IAAyB;IAEzB,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IACzD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,YAAY,CAAC;IACzC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;IAEtD,MAAM,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/C,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,EAAE,gBAAgB,EAAE,EAAE,MAAM,CAAC,CAAC;IAChF,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,sBAAsB,CAAC,EAAE,eAAe,EAAE,EAAE,MAAM,CAAC,CAAC;IACvF,MAAM,EAAE,CAAC,SAAS,CAChB,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,EAC3B,gBAAgB,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,EAC9D,MAAM,CACP,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,KAAK,CACzB,UAAU,EACV,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,CAAC,EAC3C,EAAE,GAAG,EAAE,SAAS,EAAE,CACnB,CAAC;QACF,MAAM,YAAY,GAAG,KAAK,CACxB,UAAU,EACV,CAAC,SAAS,EAAE,QAAQ,EAAE,SAAS,CAAC,EAChC,EAAE,GAAG,EAAE,SAAS,EAAE,CACnB,CAAC;QAEF,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,IAAI,CAAC,aAAa,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;QACvF,IAAI,CAAC,YAAY,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QAErF,OAAO;YACL,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;YAChD,OAAO,EAAE,IAAI;YACb,MAAM,EACJ,QAAQ,CAAC,MAAM,GAAG,CAAC;gBACjB,CAAC,CAAC,8CAA8C;gBAChD,CAAC,CAAC,2BAA2B;YACjC,QAAQ,EAAE,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;SACrD,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAAyC,EAAE,IAAI,KAAK,QAAQ,EAAE,CAAC;YAClE,OAAO;gBACL,MAAM,EAAE,MAAM;gBACd,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,KAAK;gBACd,MAAM,EAAE,wBAAwB;gBAChC,QAAQ,EAAE,CAAC,wBAAwB,CAAC;aACrC,CAAC;QACJ,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,IAAyB;IAEzB,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IACzD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC;IAC7D,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAChC,MAAM,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,OAAO;YACL,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,2BAA2B;SACpC,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO;YACL,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,yBAAyB;SAClC,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC7B,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,MAAM,OAAO,GAAG,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACjD,IAAI,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACvB,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC;QAC1B,OAAO,GAAG,IAAI,CAAC;IACjB,CAAC;IAED,MAAM,IAAI,GAAG,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1D,MAAM,iBAAiB,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAC7C,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,iBAAiB,CAAC,CAAC;IACxF,IAAI,SAAS,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC;QACtC,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;QACvB,OAAO,GAAG,IAAI,CAAC;IACjB,CAAC;IAED,MAAM,QAAQ,GAAG,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpD,MAAM,UAAU,GAAG,OAAQ,KAAiC,CAAC,UAAU,KAAK,QAAQ;YAClF,CAAC,CAAC,OAAO,CAAC,MAAM,CAAE,KAAiC,CAAC,UAAU,CAAC,CAAC;YAChE,CAAC,CAAC,IAAI,CAAC;QACT,MAAM,WAAW,GAAG,OAAQ,KAAiC,CAAC,WAAW,KAAK,QAAQ;YACpF,CAAC,CAAC,OAAO,CAAC,MAAM,CAAE,KAAiC,CAAC,WAAW,CAAC,CAAC;YACjE,CAAC,CAAC,IAAI,CAAC;QACT,IAAI,GAAG,KAAK,SAAS,IAAI,UAAU,KAAK,iBAAiB,IAAI,WAAW,KAAK,iBAAiB,EAAE,CAAC;YAC/F,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC;YACrB,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GAA4B,EAAE,CAAC;IAChD,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC;QAAE,WAAW,CAAC,OAAO,GAAG,OAAO,CAAC;IACnE,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,WAAW,CAAC,IAAI,GAAG,IAAI,CAAC;IAChF,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,GAAG,CAAC;QAAE,WAAW,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAEtE,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,UAAU,GAAG,EAAE,GAAG,MAAM,EAAE,CAAC;QACjC,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC;YAAE,UAAU,CAAC,OAAO,GAAG,WAAW,CAAC;;YACrE,OAAO,UAAU,CAAC,OAAO,CAAC;QAC/B,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,kBAAkB,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAClG,CAAC;IAED,MAAM,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,OAAO;QACL,MAAM,EAAE,MAAM;QACd,MAAM,EAAE,WAAW;QACnB,OAAO;QACP,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,+BAA+B;KAC9E,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,IAAyB;IAEzB,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IACzD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC;IAC7D,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,eAAe,CAAC;IACxD,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC;IAEhD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC7B,MAAM,OAAO,GAAG,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACjG,MAAM,iBAAiB,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAE7C,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACvD,OAAO,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAChC,KAAK,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAC5B,UAAU;QACV,CAAC,CAAC,WAAW;QACb,CAAC,CAAC,eAAe,CAAC;AACtB,CAAC;AAED,KAAK,UAAU,UAAU,CACvB,UAAkB,EAClB,EAAkB;IAMlB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAClD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC/B,OAAO,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;gBACnE,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAiC,EAAE;gBAC7D,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;QAC/B,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAAyC,EAAE,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;QAChG,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,SAAiB,EAAE,EAAkB;IACjE,MAAM,KAAK,GAAG,CAAC,cAAc,EAAE,sBAAsB,EAAE,UAAU,CAAC,CAAC;IACnE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;QACnD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,gBAAgB;IACvB,OAAO,GAAG,IAAI,CAAC,SAAS,CACtB;QACE,IAAI,EAAE,4BAA4B;QAClC,OAAO,EAAE,OAAO;QAChB,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,EAAE,UAAU,EAAE,CAAC,YAAY,CAAC,EAAE;KACzC,EACD,IAAI,EACJ,CAAC,CACF,IAAI,CAAC;AACR,CAAC;AAED,SAAS,eAAe;IACtB,OAAO,GAAG,IAAI,CAAC,SAAS,CACtB;QACE,EAAE,EAAE,SAAS;QACb,IAAI,EAAE,2BAA2B;QACjC,WAAW,EAAE,8DAA8D;QAC3E,YAAY,EAAE;YACZ,IAAI,EAAE,QAAQ;YACd,oBAAoB,EAAE,KAAK;YAC3B,UAAU,EAAE,EAAE;SACf;KACF,EACD,IAAI,EACJ,CAAC,CACF,IAAI,CAAC;AACR,CAAC;AAED,SAAS,gBAAgB,CAAC,UAAkB,EAAE,QAAgB;IAC5D,OAAO;;;sBAGa,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC;8BAClB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,0CAA0C,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyDvG,CAAC;AACF,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACrC,OAAO,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAChE,CAAC,CAAC,EAAE,GAAI,KAAiC,EAAE;QAC3C,CAAC,CAAC,EAAE,CAAC;AACT,CAAC;AAED,SAAS,YAAY,CAAC,GAAW,EAAE,IAAc,EAAE,IAAuB;IACxE,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE;QAClC,OAAO,EAAE,MAAM;QACf,KAAK,EAAE,QAAQ;QACf,GAAG,IAAI;KACR,CAAC,CAAC;IACH,IAAI,MAAM,CAAC,KAAK;QAAE,MAAM,MAAM,CAAC,KAAK,CAAC;IACrC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;AACnC,CAAC"}
@@ -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"}
@@ -0,0 +1,36 @@
1
+ import { join, resolve } from "node:path";
2
+ function normalizeEnvPath(value) {
3
+ const trimmed = typeof value === "string" ? value.trim() : "";
4
+ return trimmed ? resolve(trimmed) : null;
5
+ }
6
+ export function resolveNotifierPaths(home, env = process.env) {
7
+ const stateDir = join(home, ".config", "pew");
8
+ const binDir = join(stateDir, "bin");
9
+ const claudeDir = join(home, ".claude");
10
+ const geminiDir = normalizeEnvPath(env.GEMINI_HOME) ?? join(home, ".gemini");
11
+ const opencodeConfigDir = normalizeEnvPath(env.OPENCODE_CONFIG_DIR) ??
12
+ join(normalizeEnvPath(env.XDG_CONFIG_HOME) ?? join(home, ".config"), "opencode");
13
+ const openclawHome = normalizeEnvPath(env.OPENCLAW_STATE_DIR) ?? join(home, ".openclaw");
14
+ const codexHome = normalizeEnvPath(env.CODEX_HOME) ?? join(home, ".codex");
15
+ return {
16
+ stateDir,
17
+ binDir,
18
+ notifyPath: join(binDir, "notify.cjs"),
19
+ lockPath: join(stateDir, "sync.lock"),
20
+ signalPath: join(stateDir, "notify.signal"),
21
+ claudeDir,
22
+ claudeSettingsPath: join(claudeDir, "settings.json"),
23
+ geminiDir,
24
+ geminiSettingsPath: join(geminiDir, "settings.json"),
25
+ opencodeConfigDir,
26
+ opencodePluginDir: join(opencodeConfigDir, "plugin"),
27
+ openclawHome,
28
+ openclawConfigPath: normalizeEnvPath(env.OPENCLAW_CONFIG_PATH) ??
29
+ join(openclawHome, "openclaw.json"),
30
+ openclawPluginDir: join(stateDir, "openclaw-plugin"),
31
+ codexHome,
32
+ codexConfigPath: join(codexHome, "config.toml"),
33
+ codexNotifyOriginalPath: join(stateDir, "codex_notify_original.json"),
34
+ };
35
+ }
36
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/notifier/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsB1C,SAAS,gBAAgB,CAAC,KAAyB;IACjD,MAAM,OAAO,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9D,OAAO,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,IAAY,EACZ,MAA0C,OAAO,CAAC,GAAG;IAErD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IACrC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,gBAAgB,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAE7E,MAAM,iBAAiB,GACrB,gBAAgB,CAAC,GAAG,CAAC,mBAAmB,CAAC;QACzC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,UAAU,CAAC,CAAC;IAEnF,MAAM,YAAY,GAChB,gBAAgB,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAEtE,MAAM,SAAS,GAAG,gBAAgB,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAE3E,OAAO;QACL,QAAQ;QACR,MAAM;QACN,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC;QACtC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC;QACrC,UAAU,EAAE,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC;QAC3C,SAAS;QACT,kBAAkB,EAAE,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC;QACpD,SAAS;QACT,kBAAkB,EAAE,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC;QACpD,iBAAiB;QACjB,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,EAAE,QAAQ,CAAC;QACpD,YAAY;QACZ,kBAAkB,EAChB,gBAAgB,CAAC,GAAG,CAAC,oBAAoB,CAAC;YAC1C,IAAI,CAAC,YAAY,EAAE,eAAe,CAAC;QACrC,iBAAiB,EAAE,IAAI,CAAC,QAAQ,EAAE,iBAAiB,CAAC;QACpD,SAAS;QACT,eAAe,EAAE,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC;QAC/C,uBAAuB,EAAE,IAAI,CAAC,QAAQ,EAAE,4BAA4B,CAAC;KACtE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { NotifierOperationResult, NotifierStatus, Source } from "@pew/core";
2
+ import type { NotifierPaths } from "./paths.js";
3
+ interface RegistryDeps {
4
+ spawn?: (cmd: string, args: string[], opts?: object) => {
5
+ status: number | null;
6
+ };
7
+ }
8
+ export interface NotifierDriver {
9
+ source: Source;
10
+ displayName: string;
11
+ install(paths: NotifierPaths, deps?: RegistryDeps): Promise<NotifierOperationResult>;
12
+ uninstall(paths: NotifierPaths, deps?: RegistryDeps): Promise<NotifierOperationResult>;
13
+ status(paths: NotifierPaths): Promise<NotifierStatus>;
14
+ }
15
+ export declare function getAllDrivers(): NotifierDriver[];
16
+ export declare function getDriver(source: Source): NotifierDriver | undefined;
17
+ export declare function installAll(paths: NotifierPaths, deps?: RegistryDeps): Promise<NotifierOperationResult[]>;
18
+ export declare function uninstallAll(paths: NotifierPaths, deps?: RegistryDeps): Promise<NotifierOperationResult[]>;
19
+ export declare function statusAll(paths: NotifierPaths): Promise<Record<Source, NotifierStatus>>;
20
+ export {};
21
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/notifier/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACjF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAmBhD,UAAU,YAAY;IACpB,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK;QAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;CACnF;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAC;IACrF,SAAS,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAC;IACvF,MAAM,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CACvD;AA4GD,wBAAgB,aAAa,IAAI,cAAc,EAAE,CAEhD;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAEpE;AAED,wBAAsB,UAAU,CAC9B,KAAK,EAAE,aAAa,EACpB,IAAI,CAAC,EAAE,YAAY,GAClB,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAgBpC;AAED,wBAAsB,YAAY,CAChC,KAAK,EAAE,aAAa,EACpB,IAAI,CAAC,EAAE,YAAY,GAClB,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAgBpC;AAED,wBAAsB,SAAS,CAC7B,KAAK,EAAE,aAAa,GACnB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAYzC"}
@@ -0,0 +1,145 @@
1
+ import { installClaudeHook, uninstallClaudeHook, getClaudeHookStatus } from "./claude-hook.js";
2
+ import { installGeminiHook, uninstallGeminiHook, getGeminiHookStatus } from "./gemini-hook.js";
3
+ import { installOpenCodePlugin, uninstallOpenCodePlugin, getOpenCodePluginStatus, } from "./opencode-plugin.js";
4
+ import { installOpenClawHook, uninstallOpenClawHook, getOpenClawHookStatus, } from "./openclaw-hook.js";
5
+ import { installCodexNotifier, uninstallCodexNotifier, getCodexNotifierStatus, } from "./codex-notifier.js";
6
+ const DRIVERS = [
7
+ {
8
+ source: "claude-code",
9
+ displayName: "Claude Code",
10
+ install: (paths) => installClaudeHook({
11
+ settingsPath: paths.claudeSettingsPath,
12
+ notifyPath: paths.notifyPath,
13
+ }),
14
+ uninstall: (paths) => uninstallClaudeHook({
15
+ settingsPath: paths.claudeSettingsPath,
16
+ notifyPath: paths.notifyPath,
17
+ }),
18
+ status: (paths) => getClaudeHookStatus({
19
+ settingsPath: paths.claudeSettingsPath,
20
+ notifyPath: paths.notifyPath,
21
+ }),
22
+ },
23
+ {
24
+ source: "gemini-cli",
25
+ displayName: "Gemini CLI",
26
+ install: (paths) => installGeminiHook({
27
+ settingsPath: paths.geminiSettingsPath,
28
+ notifyPath: paths.notifyPath,
29
+ }),
30
+ uninstall: (paths) => uninstallGeminiHook({
31
+ settingsPath: paths.geminiSettingsPath,
32
+ notifyPath: paths.notifyPath,
33
+ }),
34
+ status: (paths) => getGeminiHookStatus({
35
+ settingsPath: paths.geminiSettingsPath,
36
+ notifyPath: paths.notifyPath,
37
+ }),
38
+ },
39
+ {
40
+ source: "opencode",
41
+ displayName: "OpenCode",
42
+ install: (paths) => installOpenCodePlugin({
43
+ pluginDir: paths.opencodePluginDir,
44
+ notifyPath: paths.notifyPath,
45
+ }),
46
+ uninstall: (paths) => uninstallOpenCodePlugin({
47
+ pluginDir: paths.opencodePluginDir,
48
+ notifyPath: paths.notifyPath,
49
+ }),
50
+ status: (paths) => getOpenCodePluginStatus({
51
+ pluginDir: paths.opencodePluginDir,
52
+ notifyPath: paths.notifyPath,
53
+ }),
54
+ },
55
+ {
56
+ source: "openclaw",
57
+ displayName: "OpenClaw",
58
+ install: (paths, deps) => installOpenClawHook({
59
+ pluginBaseDir: paths.openclawPluginDir,
60
+ notifyPath: paths.notifyPath,
61
+ openclawConfigPath: paths.openclawConfigPath,
62
+ spawn: deps?.spawn,
63
+ }),
64
+ uninstall: (paths, deps) => uninstallOpenClawHook({
65
+ pluginBaseDir: paths.openclawPluginDir,
66
+ notifyPath: paths.notifyPath,
67
+ openclawConfigPath: paths.openclawConfigPath,
68
+ spawn: deps?.spawn,
69
+ }),
70
+ status: (paths) => getOpenClawHookStatus({
71
+ pluginBaseDir: paths.openclawPluginDir,
72
+ notifyPath: paths.notifyPath,
73
+ openclawConfigPath: paths.openclawConfigPath,
74
+ }),
75
+ },
76
+ {
77
+ source: "codex",
78
+ displayName: "Codex",
79
+ install: (paths) => installCodexNotifier({
80
+ configPath: paths.codexConfigPath,
81
+ notifyPath: paths.notifyPath,
82
+ originalBackupPath: paths.codexNotifyOriginalPath,
83
+ }),
84
+ uninstall: (paths) => uninstallCodexNotifier({
85
+ configPath: paths.codexConfigPath,
86
+ notifyPath: paths.notifyPath,
87
+ originalBackupPath: paths.codexNotifyOriginalPath,
88
+ }),
89
+ status: (paths) => getCodexNotifierStatus({
90
+ configPath: paths.codexConfigPath,
91
+ notifyPath: paths.notifyPath,
92
+ originalBackupPath: paths.codexNotifyOriginalPath,
93
+ }),
94
+ },
95
+ ];
96
+ export function getAllDrivers() {
97
+ return DRIVERS.slice();
98
+ }
99
+ export function getDriver(source) {
100
+ return DRIVERS.find((driver) => driver.source === source);
101
+ }
102
+ export async function installAll(paths, deps) {
103
+ return Promise.all(DRIVERS.map(async (driver) => {
104
+ try {
105
+ return await driver.install(paths, deps);
106
+ }
107
+ catch (error) {
108
+ return {
109
+ source: driver.source,
110
+ action: "skip",
111
+ changed: false,
112
+ detail: error instanceof Error ? error.message : String(error),
113
+ warnings: ["Driver install failed"],
114
+ };
115
+ }
116
+ }));
117
+ }
118
+ export async function uninstallAll(paths, deps) {
119
+ return Promise.all(DRIVERS.map(async (driver) => {
120
+ try {
121
+ return await driver.uninstall(paths, deps);
122
+ }
123
+ catch (error) {
124
+ return {
125
+ source: driver.source,
126
+ action: "skip",
127
+ changed: false,
128
+ detail: error instanceof Error ? error.message : String(error),
129
+ warnings: ["Driver uninstall failed"],
130
+ };
131
+ }
132
+ }));
133
+ }
134
+ export async function statusAll(paths) {
135
+ const entries = await Promise.all(DRIVERS.map(async (driver) => {
136
+ try {
137
+ return [driver.source, await driver.status(paths)];
138
+ }
139
+ catch {
140
+ return [driver.source, "error"];
141
+ }
142
+ }));
143
+ return Object.fromEntries(entries);
144
+ }
145
+ //# sourceMappingURL=registry.js.map