@zeph-to/hook-sdk 1.8.0 → 1.9.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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @zeph-to/hook-sdk
2
2
 
3
- Push notification SDK + CLI for [Zeph](https://zeph.to). Zero dependencies uses native `fetch`.
3
+ Push notification SDK + CLI for [Zeph](https://zeph.to). The `ZephHook` SDK uses native `fetch` with no runtime dependencies; the `zeph` CLI adds `@inquirer/prompts` for its interactive installer.
4
4
 
5
5
  ## Installation
6
6
 
@@ -202,7 +202,8 @@ Push bodies are encrypted with AES-256-GCM. The wrapping key is derived via ECDH
202
202
  ## Requirements
203
203
 
204
204
  - Node.js >= 18 (uses native `fetch`)
205
- - Zero runtime dependencies
205
+ - The `ZephHook` SDK has no runtime dependencies. The CLI depends on
206
+ `@inquirer/prompts` for the interactive `zeph install` picker.
206
207
 
207
208
  ## License
208
209
 
package/dist/cli.js CHANGED
@@ -97,6 +97,9 @@ Install options:
97
97
  --key <api-key> API key (non-interactive)
98
98
  --hook <hook-id> Hook ID (non-interactive)
99
99
  --base-url <url> Base URL (non-interactive)
100
+ --only <agents> Comma-separated agent ids to install for
101
+ (claude,cursor,windsurf,gemini,codex,copilot,cline,aider).
102
+ Skips the interactive picker.
100
103
 
101
104
  Uninstall options:
102
105
  --dry-run Preview what would be removed, change nothing
@@ -1,2 +1,9 @@
1
+ import type { Agent } from './agents.js';
2
+ /**
3
+ * Resolve agents from a non-interactive `--only cursor,gemini` flag.
4
+ * Matches on agent id; unknown ids are silently dropped. Exported for
5
+ * unit testing.
6
+ */
7
+ export declare const filterAgentsByIds: (detected: Agent[], only: string) => Agent[];
1
8
  export declare const handleInstall: (args: Record<string, string | boolean>) => Promise<number>;
2
9
  //# sourceMappingURL=installer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../src/installer.ts"],"names":[],"mappings":"AA4RA,eAAO,MAAM,aAAa,GAAU,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,KAAG,OAAO,CAAC,MAAM,CAoH1F,CAAC"}
1
+ {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../src/installer.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAwSzC;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,UAAU,KAAK,EAAE,EAAE,MAAM,MAAM,KAAG,KAAK,EAKxE,CAAC;AAqBF,eAAO,MAAM,aAAa,GAAU,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,KAAG,OAAO,CAAC,MAAM,CA4H1F,CAAC"}
package/dist/installer.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.handleInstall = void 0;
3
+ exports.handleInstall = exports.filterAgentsByIds = void 0;
4
4
  const child_process_1 = require("child_process");
5
5
  const fs_1 = require("fs");
6
6
  const os_1 = require("os");
@@ -251,6 +251,52 @@ const AGENT_INSTALLERS = {
251
251
  cline: installCline,
252
252
  aider: installAider,
253
253
  };
254
+ // One-line summary of what each agent's installer does — shown in the
255
+ // interactive plan before anything is written.
256
+ const AGENT_PLAN_LABELS = {
257
+ claude: 'Claude Code — install plugin',
258
+ cursor: 'Cursor — MCP + hooks + rules',
259
+ windsurf: 'Windsurf — MCP + hooks + rules',
260
+ gemini: 'Gemini CLI — MCP + hooks + rules',
261
+ codex: 'Codex CLI — hooks + rules',
262
+ copilot: 'Copilot CLI — hooks + rules',
263
+ cline: 'Cline — rules',
264
+ aider: 'Aider — conventions',
265
+ };
266
+ // ── Agent selection ──────────────────────────────────────────────
267
+ /**
268
+ * Interactive agent picker — an @inquirer/prompts checkbox (arrow keys
269
+ * to move, space to toggle, enter to confirm). Every agent starts
270
+ * checked, so a bare Enter installs for all. Returns the chosen Agent[].
271
+ *
272
+ * Dynamic import keeps @inquirer/prompts (ESM) loadable from this
273
+ * CommonJS build, and means the dependency is only touched on the
274
+ * interactive path — `notify` / `list` / scripted `install --only`
275
+ * never load it.
276
+ */
277
+ const pickAgentsInteractive = async (detected) => {
278
+ const { checkbox } = await import('@inquirer/prompts');
279
+ const picked = await checkbox({
280
+ message: 'Install Zeph for which agents? (space to toggle, enter to confirm)',
281
+ choices: detected.map((agent) => ({
282
+ name: AGENT_PLAN_LABELS[agent.id] ?? agent.name,
283
+ value: agent.id,
284
+ checked: true,
285
+ })),
286
+ loop: false,
287
+ });
288
+ return detected.filter((a) => picked.includes(a.id));
289
+ };
290
+ /**
291
+ * Resolve agents from a non-interactive `--only cursor,gemini` flag.
292
+ * Matches on agent id; unknown ids are silently dropped. Exported for
293
+ * unit testing.
294
+ */
295
+ const filterAgentsByIds = (detected, only) => {
296
+ const ids = new Set(only.split(',').map((s) => s.trim().toLowerCase()).filter(Boolean));
297
+ return detected.filter((a) => ids.has(a.id));
298
+ };
299
+ exports.filterAgentsByIds = filterAgentsByIds;
254
300
  // ── Test Connection ──────────────────────────────────────────────
255
301
  const testConnection = async (apiKey, baseUrl) => {
256
302
  try {
@@ -291,7 +337,32 @@ const handleInstall = async (args) => {
291
337
  if (detected.length === 0) {
292
338
  console.log('\n No supported agents found. Config will still be saved.\n');
293
339
  }
294
- // 2. Collect credentials
340
+ // 2. Choose which agents to install for — asked up front so the user
341
+ // sees the choice before being walked through credential prompts.
342
+ let selected = detected;
343
+ const onlyArg = args.only?.trim();
344
+ if (detected.length > 0) {
345
+ if (onlyArg) {
346
+ // Non-interactive or scripted: --only cursor,gemini
347
+ selected = (0, exports.filterAgentsByIds)(detected, onlyArg);
348
+ console.log(`\n --only ${onlyArg} → ${selected.map((a) => a.name).join(', ') || '(no match)'}`);
349
+ }
350
+ else if (nonInteractive) {
351
+ // Scripted run with no --only: keep the all-detected default
352
+ selected = detected;
353
+ }
354
+ else {
355
+ try {
356
+ selected = await pickAgentsInteractive(detected);
357
+ }
358
+ catch {
359
+ // Ctrl-C in the picker (or no TTY) — treat as a clean cancel.
360
+ console.log('\n Cancelled.\n');
361
+ return 0;
362
+ }
363
+ }
364
+ }
365
+ // 3. Collect credentials
295
366
  const existing = (0, config_js_1.loadConfig)();
296
367
  let apiKey;
297
368
  let hookId;
@@ -321,33 +392,19 @@ const handleInstall = async (args) => {
321
392
  console.error('\n Error: API key is required.\n');
322
393
  return 1;
323
394
  }
324
- // 3. Confirmation (interactive only)
395
+ // 4. Show the resolved plan before touching anything (interactive only).
325
396
  if (!nonInteractive) {
326
397
  console.log('\n Will do:');
327
- console.log(' 1. Save config to ~/.zeph/config.json');
328
- let step = 2;
329
- for (const agent of detected) {
330
- const labels = {
331
- claude: 'Install Claude Code plugin',
332
- cursor: 'Setup Cursor (MCP + hooks + rules)',
333
- windsurf: 'Setup Windsurf (MCP + hooks + rules)',
334
- gemini: 'Setup Gemini CLI (MCP + hooks + rules)',
335
- codex: 'Setup Codex CLI (hooks + rules)',
336
- copilot: 'Setup Copilot CLI (hooks + rules)',
337
- cline: 'Setup Cline (rules)',
338
- aider: 'Setup Aider (conventions)',
339
- };
340
- console.log(` ${step}. ${labels[agent.id] ?? `Install for ${agent.name}`}`);
341
- step++;
398
+ console.log(` - Save config to ${config_js_1.CONFIG_FILE}`);
399
+ for (const agent of selected) {
400
+ console.log(` - ${AGENT_PLAN_LABELS[agent.id] ?? `Install for ${agent.name}`}`);
342
401
  }
343
- console.log(` ${step}. Test connection`);
344
- const confirm = await promptInput(' Continue? [Y/n] ');
345
- if (confirm.toLowerCase() === 'n') {
346
- console.log('\n Cancelled.\n');
347
- return 0;
402
+ if (selected.length === 0) {
403
+ console.log(' (no agents selected only the config file will be saved)');
348
404
  }
405
+ console.log(' - Test connection');
349
406
  }
350
- // 4. Save config
407
+ // 5. Save config
351
408
  console.log('');
352
409
  const config = {
353
410
  apiKey,
@@ -356,14 +413,14 @@ const handleInstall = async (args) => {
356
413
  };
357
414
  (0, config_js_1.saveConfig)(config);
358
415
  ok(`Config saved to ${config_js_1.CONFIG_FILE}`);
359
- // 5. Install per-agent
360
- for (const agent of detected) {
416
+ // 6. Install for the selected agents only
417
+ for (const agent of selected) {
361
418
  console.log(`\n Installing for ${agent.name}...`);
362
419
  const installer = AGENT_INSTALLERS[agent.id];
363
420
  if (installer)
364
421
  installer();
365
422
  }
366
- // 6. Test connection
423
+ // 7. Test connection
367
424
  console.log('\n Testing connection...');
368
425
  await testConnection(apiKey, baseUrl);
369
426
  console.log('\n Done! Restart your agents.\n');
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@zeph-to/hook-sdk",
3
- "version": "1.8.0",
4
- "description": "Zeph push notification SDK + CLI zero dependencies",
3
+ "version": "1.9.0",
4
+ "description": "Zeph push notification SDK + CLI for AI agents",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
7
7
  "exports": {
@@ -62,5 +62,8 @@
62
62
  "claude",
63
63
  "devtools"
64
64
  ],
65
- "license": "Apache-2.0"
65
+ "license": "Apache-2.0",
66
+ "dependencies": {
67
+ "@inquirer/prompts": "^8.4.3"
68
+ }
66
69
  }