skimpyclaw 0.3.0 → 0.3.2

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/dist/cli.js CHANGED
@@ -6,7 +6,7 @@ import { spawn, spawnSync } from 'child_process';
6
6
  import { fileURLToPath } from 'url';
7
7
  import { loadConfig, loadRawConfig, getConfigPath, saveConfig } from './config.js';
8
8
  import { startRuntime } from './service.js';
9
- import { runSetup } from './setup.js';
9
+ import { runSetup, renderGatewayPlist } from './setup.js';
10
10
  import { runDoctor as runDoctorCommand } from './doctor/index.js';
11
11
  import { executeTool, getToolDefinitions, BUILTIN_TOOL_DEFINITIONS, BROWSER_TOOL_DEFINITION } from './tools.js';
12
12
  import { formatModelSelectionError, getModelSelectionUsage, resolveModelSelection } from './model-selection.js';
@@ -129,10 +129,22 @@ function startDaemon() {
129
129
  console.error('Daemon control is only supported on macOS with launchctl.');
130
130
  return 1;
131
131
  }
132
- if (!existsSync(LAUNCHD_PLIST)) {
133
- console.error(`Launchd plist not found: ${LAUNCHD_PLIST}`);
134
- console.error('Run `skimpyclaw onboard` first.');
135
- return 1;
132
+ // Regenerate plist to point at the current binary (pnpm changes path on upgrade)
133
+ try {
134
+ const plistContent = renderGatewayPlist();
135
+ const plistDir = join(homedir(), 'Library', 'LaunchAgents');
136
+ if (!existsSync(plistDir))
137
+ mkdirSync(plistDir, { recursive: true });
138
+ writeFileSync(LAUNCHD_PLIST, plistContent);
139
+ }
140
+ catch (err) {
141
+ // If template is missing (e.g. corrupted install), fall back to existing plist
142
+ if (!existsSync(LAUNCHD_PLIST)) {
143
+ console.error(`Launchd plist not found: ${LAUNCHD_PLIST}`);
144
+ console.error('Run `skimpyclaw onboard` first.');
145
+ return 1;
146
+ }
147
+ console.warn(`Warning: could not regenerate plist (${err instanceof Error ? err.message : err}), using existing`);
136
148
  }
137
149
  const result = runLaunchctl(['load', LAUNCHD_PLIST]);
138
150
  if (!result.ok && !result.output.includes('already loaded')) {
package/dist/setup.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  interface SetupOptions {
2
2
  dryRun?: boolean;
3
3
  }
4
+ export declare function renderGatewayPlist(): string;
4
5
  type ProviderChoice = 'anthropic-api' | 'anthropic-oauth' | 'openai-api' | 'codex-oauth' | 'minimax-api' | 'kimi-api';
5
6
  interface ProviderSecrets {
6
7
  anthropicKey?: string;
package/dist/setup.js CHANGED
@@ -128,7 +128,7 @@ function maskInput(input) {
128
128
  return '****';
129
129
  return input.slice(0, 4) + '****' + input.slice(-4);
130
130
  }
131
- function renderGatewayPlist() {
131
+ export function renderGatewayPlist() {
132
132
  if (!existsSync(GATEWAY_PLIST_TEMPLATE)) {
133
133
  throw new Error(`Gateway launchd template not found: ${GATEWAY_PLIST_TEMPLATE}`);
134
134
  }
@@ -235,7 +235,14 @@ function buildStarterCronJobs(starters) {
235
235
  },
236
236
  payload: {
237
237
  kind: 'agentTurn',
238
- message: 'Use WebSearch to fetch today\'s top 10 Hacker News stories. Reply with title, URL, and 1-line summary for each item.',
238
+ message: 'Fetch today\'s top 10 Hacker News stories. Reply with title, URL, and 1-line summary for each item.',
239
+ tools: {
240
+ enabled: true,
241
+ allowedPaths: [`${homedir()}/.skimpyclaw`],
242
+ maxIterations: 30,
243
+ bashTimeout: 30000,
244
+ browser: { enabled: true, headless: true },
245
+ },
239
246
  },
240
247
  });
241
248
  }
@@ -251,6 +258,13 @@ function buildStarterCronJobs(starters) {
251
258
  payload: {
252
259
  kind: 'agentTurn',
253
260
  message: `Check current weather and today forecast for ${starters.weatherLocation}. Keep it concise: current temp/conditions, highs/lows, precipitation chance, and 1 recommendation.`,
261
+ tools: {
262
+ enabled: true,
263
+ allowedPaths: [`${homedir()}/.skimpyclaw`],
264
+ maxIterations: 30,
265
+ bashTimeout: 30000,
266
+ browser: { enabled: true, headless: true },
267
+ },
254
268
  },
255
269
  });
256
270
  }
@@ -488,6 +502,13 @@ export function buildSetupConfig(input) {
488
502
  allowFrom: [parseInt(input.telegramId, 10) || input.telegramId],
489
503
  dailyNotesDir: '${HOME}/.skimpyclaw/Daily Notes',
490
504
  defaultAllowedPaths: allPaths,
505
+ tools: {
506
+ enabled: true,
507
+ allowedPaths: allPaths,
508
+ maxIterations: 100,
509
+ bashTimeout: 15000,
510
+ ...(features.browser ? { browser: { type: 'chromium', enabled: true, headless: true } } : {}),
511
+ },
491
512
  },
492
513
  discord: {
493
514
  enabled: useDiscord,
@@ -495,6 +516,13 @@ export function buildSetupConfig(input) {
495
516
  allowFrom: useDiscord ? [input.discordUserId || ''] : [],
496
517
  defaultAllowedPaths: allPaths,
497
518
  ...(input.discordDefaultChannelId ? { defaultChannelId: input.discordDefaultChannelId } : {}),
519
+ tools: {
520
+ enabled: true,
521
+ allowedPaths: allPaths,
522
+ maxIterations: 100,
523
+ bashTimeout: 15000,
524
+ ...(features.browser ? { browser: { type: 'chromium', enabled: true, headless: false } } : {}),
525
+ },
498
526
  },
499
527
  },
500
528
  cron: {
@@ -517,6 +545,13 @@ export function buildSetupConfig(input) {
517
545
  defaultProvider: 'macos',
518
546
  providers: {
519
547
  macos: { tts: { voice: 'Samantha' } },
548
+ ...(input.selectedProviders.has('openai-api') ? {
549
+ openai: {
550
+ apiKey: '${OPENAI_API_KEY}',
551
+ baseURL: 'https://api.openai.com/v1',
552
+ stt: { model: 'whisper-1' },
553
+ },
554
+ } : {}),
520
555
  },
521
556
  channels: {
522
557
  telegram: { enabled: true, acceptVoice: true, sendVoice: true },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skimpyclaw",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Lightweight personal AI assistant with Telegram and Discord integration",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",