@masslessai/push-todo 3.7.9 → 3.8.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.
@@ -0,0 +1,4 @@
1
+ #!/bin/bash
2
+ # Shell wrapper for session-end hook.
3
+ # Called by Claude Code's SessionEnd hook to report session_finished to Supabase.
4
+ exec node "$(dirname "$0")/session-end.js"
package/lib/cli.js CHANGED
@@ -85,7 +85,7 @@ ${bold('EXAMPLES:')}
85
85
 
86
86
  ${bold('CONNECT OPTIONS:')}
87
87
  --reauth Force re-authentication
88
- --client <type> Client type (claude-code, openai-codex, clawdbot)
88
+ --client <type> Client type (claude-code, openai-codex, openclaw)
89
89
  --check-version Check for updates (JSON output)
90
90
  --update Update to latest version
91
91
  --validate-key Validate API key (JSON output)
package/lib/connect.js CHANGED
@@ -55,7 +55,7 @@ const VERSION = getVersion();
55
55
  const CLIENT_NAMES = {
56
56
  'claude-code': 'Claude Code',
57
57
  'openai-codex': 'OpenAI Codex',
58
- 'clawdbot': 'Clawdbot'
58
+ 'openclaw': 'OpenClaw'
59
59
  };
60
60
 
61
61
  // ============================================================================
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@masslessai/push-todo",
3
- "version": "3.7.9",
3
+ "version": "3.8.1",
4
4
  "description": "Voice tasks from Push iOS app for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {
@@ -5,7 +5,7 @@
5
5
  * Sets up integrations for ALL detected AI coding clients:
6
6
  * 1. Claude Code - symlink to ~/.claude/skills/ (gives clean /push-todo command)
7
7
  * 2. OpenAI Codex - AGENTS.md in ~/.codex/
8
- * 3. Clawdbot - SKILL.md in ~/.clawdbot/skills/
8
+ * 3. OpenClaw - SKILL.md in ~/.openclaw/skills/ (legacy: ~/.clawdbot/)
9
9
  * 4. Downloads native keychain helper binary (macOS)
10
10
  */
11
11
 
@@ -35,10 +35,10 @@ const CODEX_SKILL_DIR = join(CODEX_DIR, 'skills', 'push-todo');
35
35
  const CODEX_SKILL_FILE = join(CODEX_SKILL_DIR, 'SKILL.md');
36
36
  const CODEX_AGENTS_FILE = join(CODEX_DIR, 'AGENTS.md');
37
37
 
38
- // Clawdbot locations
39
- const CLAWDBOT_DIR = join(homedir(), '.clawdbot');
40
- const CLAWDBOT_SKILL_DIR = join(CLAWDBOT_DIR, 'skills', 'push-todo');
41
- const CLAWDBOT_SKILL_FILE = join(CLAWDBOT_SKILL_DIR, 'SKILL.md');
38
+ // OpenClaw locations (formerly Clawdbot)
39
+ const OPENCLAW_DIR = join(homedir(), '.openclaw');
40
+ const OPENCLAW_LEGACY_DIR = join(homedir(), '.clawdbot');
41
+ const OPENCLAW_SKILL_DIR = join(OPENCLAW_DIR, 'skills', 'push-todo');
42
42
 
43
43
  const BINARY_NAME = 'push-keychain-helper';
44
44
  const BINARY_DIR = join(__dirname, '../bin');
@@ -234,50 +234,69 @@ At the start of each session, check for pending tasks from the Push iOS app:
234
234
  }
235
235
 
236
236
  /**
237
- * Set up Clawdbot integration.
238
- * Creates symlink ~/.clawdbot/skills/push-todo -> npm package
237
+ * Set up OpenClaw integration (formerly Clawdbot).
238
+ * Creates symlink ~/.openclaw/skills/push-todo -> npm package
239
+ * Also cleans up legacy ~/.clawdbot/skills/push-todo if present.
239
240
  *
240
- * @returns {boolean} True if Clawdbot was detected and set up
241
+ * @returns {boolean} True if OpenClaw was detected and set up
241
242
  */
242
- function setupClawdbot() {
243
- // Only set up if Clawdbot directory exists (user has Clawdbot installed)
244
- if (!existsSync(CLAWDBOT_DIR)) {
243
+ function setupOpenClaw() {
244
+ // Detect OpenClaw (new) or Clawdbot (legacy)
245
+ const detected = existsSync(OPENCLAW_DIR) || existsSync(OPENCLAW_LEGACY_DIR);
246
+ if (!detected) {
245
247
  return false;
246
248
  }
247
249
 
248
- console.log('[push-todo] Detected Clawdbot installation');
250
+ // Prefer ~/.openclaw/ (new); fall back to ~/.clawdbot/ (legacy)
251
+ const targetDir = existsSync(OPENCLAW_DIR) ? OPENCLAW_DIR : OPENCLAW_LEGACY_DIR;
252
+ const skillDir = join(targetDir, 'skills', 'push-todo');
253
+ const label = existsSync(OPENCLAW_DIR) ? 'OpenClaw' : 'OpenClaw (legacy ~/.clawdbot)';
254
+
255
+ console.log(`[push-todo] Detected ${label} installation`);
249
256
 
250
257
  try {
251
258
  // Ensure skills directory exists
252
- const skillsDir = join(CLAWDBOT_DIR, 'skills');
253
- mkdirSync(skillsDir, { recursive: true });
259
+ mkdirSync(join(targetDir, 'skills'), { recursive: true });
254
260
 
255
261
  // Create symlink (same as Claude Code approach)
256
- if (existsSync(CLAWDBOT_SKILL_DIR)) {
257
- const stats = lstatSync(CLAWDBOT_SKILL_DIR);
262
+ if (existsSync(skillDir)) {
263
+ const stats = lstatSync(skillDir);
258
264
  if (stats.isSymbolicLink()) {
259
- const target = readlinkSync(CLAWDBOT_SKILL_DIR);
265
+ const target = readlinkSync(skillDir);
260
266
  if (target === PACKAGE_ROOT) {
261
- console.log('[push-todo] Clawdbot: Symlink already configured');
267
+ console.log('[push-todo] OpenClaw: Symlink already configured');
262
268
  } else {
263
- unlinkSync(CLAWDBOT_SKILL_DIR);
264
- symlinkSync(PACKAGE_ROOT, CLAWDBOT_SKILL_DIR);
265
- console.log('[push-todo] Clawdbot: Updated symlink');
269
+ unlinkSync(skillDir);
270
+ symlinkSync(PACKAGE_ROOT, skillDir);
271
+ console.log('[push-todo] OpenClaw: Updated symlink');
266
272
  }
267
273
  } else {
268
- // It's a directory (old copy) - remove and replace with symlink
269
- rmSync(CLAWDBOT_SKILL_DIR, { recursive: true });
270
- symlinkSync(PACKAGE_ROOT, CLAWDBOT_SKILL_DIR);
271
- console.log('[push-todo] Clawdbot: Replaced copy with symlink');
274
+ rmSync(skillDir, { recursive: true });
275
+ symlinkSync(PACKAGE_ROOT, skillDir);
276
+ console.log('[push-todo] OpenClaw: Replaced copy with symlink');
272
277
  }
273
278
  } else {
274
- symlinkSync(PACKAGE_ROOT, CLAWDBOT_SKILL_DIR);
275
- console.log('[push-todo] Clawdbot: Created symlink');
279
+ symlinkSync(PACKAGE_ROOT, skillDir);
280
+ console.log('[push-todo] OpenClaw: Created symlink');
281
+ }
282
+
283
+ // Clean up legacy Clawdbot symlink if we installed to the new location
284
+ if (existsSync(OPENCLAW_DIR) && existsSync(OPENCLAW_LEGACY_DIR)) {
285
+ const legacySkill = join(OPENCLAW_LEGACY_DIR, 'skills', 'push-todo');
286
+ if (existsSync(legacySkill)) {
287
+ try {
288
+ const stats = lstatSync(legacySkill);
289
+ if (stats.isSymbolicLink()) {
290
+ unlinkSync(legacySkill);
291
+ console.log('[push-todo] OpenClaw: Cleaned up legacy ~/.clawdbot symlink');
292
+ }
293
+ } catch { /* best-effort */ }
294
+ }
276
295
  }
277
296
 
278
297
  return true;
279
298
  } catch (error) {
280
- console.log(`[push-todo] Clawdbot: Setup failed: ${error.message}`);
299
+ console.log(`[push-todo] OpenClaw: Setup failed: ${error.message}`);
281
300
  return false;
282
301
  }
283
302
  }
@@ -343,15 +362,15 @@ async function main() {
343
362
  const codexSuccess = setupCodex();
344
363
  if (codexSuccess) console.log('');
345
364
 
346
- // Step 5: Set up Clawdbot (if installed)
347
- const clawdbotSuccess = setupClawdbot();
348
- if (clawdbotSuccess) console.log('');
365
+ // Step 5: Set up OpenClaw (if installed — formerly Clawdbot)
366
+ const openclawSuccess = setupOpenClaw();
367
+ if (openclawSuccess) console.log('');
349
368
 
350
369
  // Track which clients were set up
351
370
  const clients = [];
352
371
  if (claudeSuccess) clients.push('Claude Code');
353
372
  if (codexSuccess) clients.push('OpenAI Codex');
354
- if (clawdbotSuccess) clients.push('Clawdbot');
373
+ if (openclawSuccess) clients.push('OpenClaw');
355
374
 
356
375
  // Step 6: Download native binary (macOS only)
357
376
  if (platform() !== 'darwin') {
@@ -392,7 +411,7 @@ async function main() {
392
411
  console.log('[push-todo] push-todo List your tasks');
393
412
  if (claudeSuccess) console.log('[push-todo] /push-todo Use in Claude Code');
394
413
  if (codexSuccess) console.log('[push-todo] $push-todo Use in OpenAI Codex');
395
- if (clawdbotSuccess) console.log('[push-todo] /push-todo Use in Clawdbot');
414
+ if (openclawSuccess) console.log('[push-todo] /push-todo Use in OpenClaw');
396
415
  return;
397
416
  }
398
417
 
@@ -429,8 +448,8 @@ async function main() {
429
448
  if (codexSuccess) {
430
449
  console.log('[push-todo] $push-todo Use in OpenAI Codex');
431
450
  }
432
- if (clawdbotSuccess) {
433
- console.log('[push-todo] /push-todo Use in Clawdbot');
451
+ if (openclawSuccess) {
452
+ console.log('[push-todo] /push-todo Use in OpenClaw');
434
453
  }
435
454
  }
436
455
 
@@ -2,7 +2,11 @@
2
2
  /**
3
3
  * Pre-uninstall script for Push CLI.
4
4
  *
5
- * Removes the Claude Code plugin symlink.
5
+ * Removes skill symlinks for all detected AI coding clients:
6
+ * 1. Claude Code - ~/.claude/skills/push-todo
7
+ * 2. OpenAI Codex - ~/.codex/skills/push-todo
8
+ * 3. OpenClaw - ~/.openclaw/skills/push-todo (and legacy ~/.clawdbot/)
9
+ * 4. Legacy plugin - ~/.claude/plugins/push-todo
6
10
  */
7
11
 
8
12
  import { existsSync, unlinkSync, lstatSync, readlinkSync } from 'fs';
@@ -16,37 +20,37 @@ const __dirname = dirname(__filename);
16
20
  // Package root (one level up from scripts/)
17
21
  const PACKAGE_ROOT = join(__dirname, '..');
18
22
 
19
- // Claude Code plugin location
20
- const PLUGIN_LINK = join(homedir(), '.claude', 'plugins', 'push-todo');
23
+ // All symlink locations to clean up
24
+ const SYMLINKS = [
25
+ { path: join(homedir(), '.claude', 'skills', 'push-todo'), label: 'Claude Code skill' },
26
+ { path: join(homedir(), '.claude', 'plugins', 'push-todo'), label: 'Claude Code plugin (legacy)' },
27
+ { path: join(homedir(), '.codex', 'skills', 'push-todo'), label: 'OpenAI Codex skill' },
28
+ { path: join(homedir(), '.openclaw', 'skills', 'push-todo'), label: 'OpenClaw skill' },
29
+ { path: join(homedir(), '.clawdbot', 'skills', 'push-todo'), label: 'OpenClaw skill (legacy ~/.clawdbot)' },
30
+ ];
21
31
 
22
32
  /**
23
- * Remove Claude Code plugin symlink if it points to this package.
33
+ * Remove a symlink if it points to this package.
24
34
  */
25
- function removePluginSymlink() {
26
- if (!existsSync(PLUGIN_LINK)) {
27
- console.log('[push-todo] No plugin symlink found, nothing to remove.');
28
- return;
29
- }
35
+ function removeSymlink({ path, label }) {
36
+ if (!existsSync(path)) return;
30
37
 
31
38
  try {
32
- const stats = lstatSync(PLUGIN_LINK);
33
-
39
+ const stats = lstatSync(path);
34
40
  if (!stats.isSymbolicLink()) {
35
- console.log('[push-todo] Plugin is not a symlink, leaving it alone.');
41
+ console.log(`[push-todo] ${label} is not a symlink, leaving it alone.`);
36
42
  return;
37
43
  }
38
44
 
39
- const target = readlinkSync(PLUGIN_LINK);
40
-
41
- // Only remove if it points to this package
45
+ const target = readlinkSync(path);
42
46
  if (target === PACKAGE_ROOT || target.includes('node_modules/@masslessai/push-todo')) {
43
- unlinkSync(PLUGIN_LINK);
44
- console.log('[push-todo] Removed Claude Code plugin symlink.');
47
+ unlinkSync(path);
48
+ console.log(`[push-todo] Removed ${label} symlink.`);
45
49
  } else {
46
- console.log('[push-todo] Plugin symlink points elsewhere, leaving it alone.');
50
+ console.log(`[push-todo] ${label} symlink points elsewhere, leaving it alone.`);
47
51
  }
48
52
  } catch (error) {
49
- console.error(`[push-todo] Warning: Could not remove symlink: ${error.message}`);
53
+ console.error(`[push-todo] Warning: Could not remove ${label}: ${error.message}`);
50
54
  }
51
55
  }
52
56
 
@@ -56,7 +60,9 @@ function removePluginSymlink() {
56
60
  function main() {
57
61
  console.log('[push-todo] Running pre-uninstall...');
58
62
 
59
- removePluginSymlink();
63
+ for (const link of SYMLINKS) {
64
+ removeSymlink(link);
65
+ }
60
66
 
61
67
  console.log('[push-todo] Uninstall cleanup complete.');
62
68
  console.log('[push-todo] Your configuration at ~/.config/push/ has been preserved.');