skimpyclaw 0.1.2 → 0.1.4

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.
@@ -43,6 +43,11 @@ describe('provider utils', () => {
43
43
  expect(resolveModel('anthropic/claude-3-5-haiku-20241022', cfg)).toBe('anthropic/claude-haiku-4-5');
44
44
  expect(resolveModel('claude-3.5-haiku', cfg)).toBe('claude-haiku-4-5');
45
45
  });
46
+ it('migrates deprecated claude opus 4 model ids', () => {
47
+ const cfg = { models: { aliases: {} } };
48
+ expect(resolveModel('claude-opus-4', cfg)).toBe('claude-opus-4-6');
49
+ expect(resolveModel('anthropic/claude-opus-4', cfg)).toBe('anthropic/claude-opus-4-6');
50
+ });
46
51
  it('normalizes provider route fields after deprecated model migration', () => {
47
52
  const cfg = { models: { aliases: {} } };
48
53
  const route = resolveProviderRoute('anthropic/claude-3-5-sonnet-20241022', cfg);
@@ -11,12 +11,13 @@ describe('setup config generation', () => {
11
11
  selectedProviders,
12
12
  providerSecrets: { anthropicKey: 'sk-ant-test' },
13
13
  });
14
- expect(config.agents.list.main.model).toBe('anthropic/claude-opus-4');
14
+ expect(config.agents.list.main.model).toBe('claude-opus');
15
15
  expect(config.models.providers.anthropic.apiKey).toBe('${ANTHROPIC_API_KEY}');
16
16
  expect(config.models.providers.codex.authPath).toBe('${HOME}/.codex/auth.json');
17
17
  expect(config.channels.telegram.allowFrom).toEqual([12345]);
18
18
  expect(config.channels.telegram.defaultAllowedPaths).toContain('/tmp/workspace');
19
- expect(config.models.aliases['claude-think']).toBe('anthropic/claude-sonnet-4-5');
19
+ expect(config.models.aliases['claude-think']).toBe('anthropic/claude-sonnet-4-6');
20
+ expect(config.models.aliases['claude-opus']).toBe('anthropic/claude-opus-4-6');
20
21
  expect(config.models.aliases.codex).toBe('codex/gpt-5.3-codex');
21
22
  expect(config.models.aliases['codex5.1']).toBe('codex/gpt-5.1-codex');
22
23
  expect(config.models.aliases['codex5.2']).toBe('codex/gpt-5.2-codex');
@@ -37,7 +37,7 @@ function createMockConfig() {
37
37
  providers: {},
38
38
  aliases: {
39
39
  'claude-think': 'anthropic/claude-sonnet-4-5',
40
- 'claude-opus': 'anthropic/claude-opus-4',
40
+ 'claude-opus': 'anthropic/claude-opus-4-6',
41
41
  },
42
42
  },
43
43
  channels: {
@@ -84,7 +84,7 @@ describe('subagent', () => {
84
84
  expect(task.type).toBe('coding');
85
85
  expect(task.prompt).toBe('list TODOs');
86
86
  expect(task.chatId).toBe(123);
87
- expect(task.model).toBe('anthropic/claude-opus-4');
87
+ expect(task.model).toBe('anthropic/claude-opus-4-6');
88
88
  expect(task.createdAt).toBeInstanceOf(Date);
89
89
  });
90
90
  it('increments task IDs', () => {
@@ -95,7 +95,7 @@ describe('subagent', () => {
95
95
  });
96
96
  it('uses model override when provided', () => {
97
97
  const task = dispatchSubagent('coding', 'test', 123, mockConfig, 'anthropic/claude-opus-4');
98
- expect(task.model).toBe('anthropic/claude-opus-4');
98
+ expect(task.model).toBe('anthropic/claude-opus-4-6');
99
99
  });
100
100
  it('resolves model override aliases to canonical model ids', () => {
101
101
  const task = dispatchSubagent('coding', 'test', 123, mockConfig, 'claude-think');
@@ -14,7 +14,7 @@ export declare function handleSkill(ctx: Context, cfg: Config): Promise<void>;
14
14
  export declare function handleApprovals(ctx: Context, cfg: Config): Promise<void>;
15
15
  export declare function handleApprove(ctx: Context, cfg: Config): Promise<void>;
16
16
  export declare function handleDeny(ctx: Context, cfg: Config): Promise<void>;
17
- export declare function handleNew(ctx: Context, cfg: Config): Promise<void>;
17
+ export declare function handleClear(ctx: Context, cfg: Config): Promise<void>;
18
18
  export declare function handleCompact(ctx: Context, cfg: Config): Promise<void>;
19
19
  export declare function handleSilence(ctx: Context, cfg: Config): Promise<void>;
20
20
  export declare function handleMemory(ctx: Context, cfg: Config): Promise<void>;
@@ -33,7 +33,7 @@ export declare const commandHandlers: {
33
33
  approvals: typeof handleApprovals;
34
34
  approve: typeof handleApprove;
35
35
  deny: typeof handleDeny;
36
- new: typeof handleNew;
36
+ clear: typeof handleClear;
37
37
  compact: typeof handleCompact;
38
38
  silence: typeof handleSilence;
39
39
  memory: typeof handleMemory;
@@ -369,7 +369,7 @@ export async function handleDeny(ctx, cfg) {
369
369
  }
370
370
  }
371
371
  }
372
- export async function handleNew(ctx, cfg) {
372
+ export async function handleClear(ctx, cfg) {
373
373
  const chatId = ctx.chat?.id;
374
374
  if (chatId)
375
375
  await clearHistory(chatId);
@@ -458,7 +458,7 @@ export const commandHandlers = {
458
458
  approvals: handleApprovals,
459
459
  approve: handleApprove,
460
460
  deny: handleDeny,
461
- new: handleNew,
461
+ clear: handleClear,
462
462
  compact: handleCompact,
463
463
  silence: handleSilence,
464
464
  memory: handleMemory,
@@ -132,7 +132,7 @@ export async function initTelegram(cfg) {
132
132
  bot.command('approvals', (ctx) => commandHandlers.approvals(ctx, cfg));
133
133
  bot.command('approve', (ctx) => commandHandlers.approve(ctx, cfg));
134
134
  bot.command('deny', (ctx) => commandHandlers.deny(ctx, cfg));
135
- bot.command('new', (ctx) => commandHandlers.new(ctx, cfg));
135
+ bot.command('clear', (ctx) => commandHandlers.clear(ctx, cfg));
136
136
  bot.command('compact', (ctx) => commandHandlers.compact(ctx, cfg));
137
137
  bot.command('silence', (ctx) => commandHandlers.silence(ctx, cfg));
138
138
  bot.command('memory', (ctx) => commandHandlers.memory(ctx, cfg));
@@ -5,7 +5,7 @@ export const BOT_COMMANDS = [
5
5
  { command: 'model', description: 'Switch model (fast/smart/opus)' },
6
6
  { command: 'status', description: 'Show bot status' },
7
7
  { command: 'memory', description: 'View recent memory entries' },
8
- { command: 'new', description: 'Clear conversation history' },
8
+ { command: 'clear', description: 'Clear conversation history' },
9
9
  { command: 'compact', description: 'Compress conversation history' },
10
10
  { command: 'silence', description: 'Pause proactive messages' },
11
11
  { command: 'cron', description: 'List or run scheduled jobs' },
package/dist/discord.js CHANGED
@@ -29,7 +29,7 @@ const BOT_COMMANDS = [
29
29
  { command: 'help', description: 'Show available commands' },
30
30
  { command: 'model', description: 'Switch model (fast/smart/opus)' },
31
31
  { command: 'status', description: 'Show bot status' },
32
- { command: 'new', description: 'Clear conversation history' },
32
+ { command: 'clear', description: 'Clear conversation history' },
33
33
  { command: 'compact', description: 'Compress conversation history' },
34
34
  { command: 'silence', description: 'Pause proactive messages' },
35
35
  { command: 'cron', description: 'List or run scheduled jobs' },
@@ -422,7 +422,7 @@ async function handleCommand(message, command, args) {
422
422
  }
423
423
  return;
424
424
  }
425
- if (command === 'new') {
425
+ if (command === 'clear') {
426
426
  await clearHistory(conversationKey(message));
427
427
  await message.reply('Conversation cleared. Starting fresh.');
428
428
  return;
package/dist/gateway.js CHANGED
@@ -1,11 +1,21 @@
1
1
  // Gateway HTTP server for health checks and control
2
2
  import Fastify from 'fastify';
3
+ import { existsSync } from 'fs';
4
+ import { fileURLToPath } from 'url';
3
5
  import { join } from 'path';
4
6
  import { runAgentTurn } from './agent.js';
5
7
  import { getCronJobs, runCronJob } from './cron.js';
6
8
  import { registerDashboardAPI } from './api.js';
7
9
  import { registerDashboard } from './dashboard-frontend.js';
8
10
  import { ensureDashboardToken } from './config.js';
11
+ const __dirname = fileURLToPath(new URL('.', import.meta.url));
12
+ function resolveDashboardDistDir() {
13
+ const packageDistDashboard = join(__dirname, 'dashboard');
14
+ if (existsSync(join(packageDistDashboard, 'index.html'))) {
15
+ return packageDistDashboard;
16
+ }
17
+ return join(process.cwd(), 'dist', 'dashboard');
18
+ }
9
19
  let config;
10
20
  let startTime;
11
21
  let lastMessage;
@@ -94,7 +104,7 @@ export async function createGateway(cfg) {
94
104
  registerDashboardAPI(fastify, config);
95
105
  // Register dashboard frontend (framework app)
96
106
  registerDashboard(fastify, {
97
- frameworkDistDir: join(process.cwd(), 'dist', 'dashboard'),
107
+ frameworkDistDir: resolveDashboardDistDir(),
98
108
  botName: config.agents.list[config.agents.default]?.identity?.name || 'SkimpyClaw',
99
109
  botEmoji: config.agents.list[config.agents.default]?.identity?.emoji || 'šŸ‘™šŸ¦ž',
100
110
  });
@@ -107,6 +107,9 @@ function migrateDeprecatedModelSpec(modelSpec) {
107
107
  else if (/^claude[-.]3[-.]5[-.]haiku(?:[-_.].*)?$/i.test(bare)) {
108
108
  migratedBare = 'claude-haiku-4-5';
109
109
  }
110
+ else if (/^claude[-.]opus[-.]4(?:[-_.].*)?$/i.test(bare)) {
111
+ migratedBare = 'claude-opus-4-6';
112
+ }
110
113
  if (migratedBare === bare)
111
114
  return modelSpec;
112
115
  return hasProvider ? `${provider}/${migratedBare}` : migratedBare;
@@ -30,6 +30,6 @@ export declare function saveProactiveMessage(platform: string, chatId: string |
30
30
  */
31
31
  export declare function replaceWithSummary(platform: string, chatId: string | number, summary: string): Promise<void>;
32
32
  /**
33
- * Delete the session file. Used by /new.
33
+ * Delete the session file. Used by /clear.
34
34
  */
35
35
  export declare function clearHistory(platform: string, chatId: string | number): Promise<void>;
package/dist/sessions.js CHANGED
@@ -127,7 +127,7 @@ export async function replaceWithSummary(platform, chatId, summary) {
127
127
  }
128
128
  }
129
129
  /**
130
- * Delete the session file. Used by /new.
130
+ * Delete the session file. Used by /clear.
131
131
  */
132
132
  export async function clearHistory(platform, chatId) {
133
133
  try {
package/dist/setup.js CHANGED
@@ -278,7 +278,7 @@ function buildProviders(providers) {
278
278
  function buildDefaultModel(providers) {
279
279
  const hasAnthropic = providers.has('anthropic-api') || providers.has('anthropic-oauth');
280
280
  if (hasAnthropic)
281
- return 'anthropic/claude-opus-4';
281
+ return 'claude-opus';
282
282
  if (providers.has('codex-oauth'))
283
283
  return 'codex/gpt-5.3-codex';
284
284
  if (providers.has('kimi-api'))
@@ -291,8 +291,8 @@ function buildAliases(providers) {
291
291
  // Always include well-known aliases so users can switch models easily
292
292
  const aliases = {
293
293
  'claude-fast': 'anthropic/claude-haiku-4-5',
294
- 'claude-think': 'anthropic/claude-sonnet-4-5',
295
- 'claude-opus': 'anthropic/claude-opus-4',
294
+ 'claude-think': 'anthropic/claude-sonnet-4-6',
295
+ 'claude-opus': 'anthropic/claude-opus-4-6',
296
296
  'codex5.1': 'codex/gpt-5.1-codex',
297
297
  'codex5.2': 'codex/gpt-5.2-codex',
298
298
  'codex5.3': 'codex/gpt-5.3-codex',
@@ -803,10 +803,11 @@ export async function runSetup(options = {}) {
803
803
  console.log('\nNext steps:');
804
804
  console.log('1. Review templates in ~/.skimpyclaw/agents/main/');
805
805
  console.log('2. Start the daemon:');
806
- console.log(` launchctl load ~/Library/LaunchAgents/${GATEWAY_PLIST_LABEL}.plist`);
806
+ console.log(' skimpyclaw start --daemon');
807
807
  console.log('3. Check health:');
808
- console.log(' curl http://localhost:18790/health');
809
- console.log(`4. Send /help in your ${useDiscord ? 'Discord bot DM/server' : 'Telegram bot'}`);
808
+ console.log(' skimpyclaw status');
809
+ console.log(`4. Optional daemon controls: skimpyclaw stop | skimpyclaw restart`);
810
+ console.log(`5. Send /help in your ${useDiscord ? 'Discord bot DM/server' : 'Telegram bot'}`);
810
811
  console.log('\nšŸ‘™šŸ¦ž Enjoy!');
811
812
  }
812
813
  finally {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skimpyclaw",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Lightweight personal AI assistant with Telegram and Discord integration",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",