tiger-agent 0.2.2 → 0.2.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.
package/README.md CHANGED
@@ -10,13 +10,20 @@ Made by **AI Research Group, Department of Civil Engineering, KMUTT**
10
10
 
11
11
  ---
12
12
 
13
- ## 🆕 What's New — v0.2.0
13
+ ## 🆕 What's New — v0.2.4
14
+
15
+ - **ClawHub skill install fixed** — `clawhub_install` and `clawhub_search` now work correctly when installed via `npm install -g`
16
+ - **No required API keys** — `tiger onboard` skips providers with no key; any single provider is enough to start
17
+ - **`/limit` Telegram command** — set per-provider daily token limits from chat without restarting
18
+ - **Soul & ownskill refresh fixed** — 24-hour regeneration timer now uses DB timestamps, not file mtime, so reflection appends no longer block the update cycle
19
+
20
+ ### v0.2.0
14
21
 
15
22
  - **npm global install** — `npm install -g tiger-agent`, no git clone needed
16
23
  - **Multi-provider LLM** — 5 providers (Kimi, Z.ai, MiniMax, Claude, Moonshot) with auto-fallback
17
24
  - **Daily token limits** — per-provider limits with automatic switching at UTC midnight
18
25
  - **`tiger` CLI** — unified command: `tiger onboard`, `tiger start`, `tiger telegram`, `tiger stop`
19
- - **Telegram `/api` & `/tokens`** — switch providers and monitor usage from chat
26
+ - **Telegram `/api`, `/tokens`, `/limit`** — manage providers and usage from chat
20
27
  - **Encrypted secrets** — optional at-rest encryption for API keys
21
28
 
22
29
  ---
@@ -33,68 +40,94 @@ Made by **AI Research Group, Department of Civil Engineering, KMUTT**
33
40
 
34
41
  ---
35
42
 
43
+ ## 📋 Requirements
44
+
45
+ - Node.js 18+ (20+ recommended)
46
+ - npm
47
+ - Python 3 (for SQLite memory helper)
48
+
49
+ ---
50
+
36
51
  ## 📦 Installation
37
52
 
38
53
  ```bash
39
54
  npm install -g tiger-agent
40
55
  ```
41
56
 
57
+ All config and runtime data is stored in `~/.tiger/` — nothing written to the npm global directory.
58
+
42
59
  ---
43
60
 
44
61
  ## 🚀 Quick Start
45
62
 
63
+ ### 1. Run the setup wizard
64
+
46
65
  ```bash
47
- tiger onboard # First-time setup wizard (run once)
48
- tiger start # Start CLI chat
66
+ tiger onboard
49
67
  ```
50
68
 
51
- CLI exit: `/exit` or `/quit`
69
+ The wizard will ask for:
70
+ - **Active provider** — which LLM to use by default (e.g. `zai`, `claude`)
71
+ - **Fallback order** — comma-separated list tried when the active provider is rate-limited
72
+ - **API keys** — enter only the providers you have keys for; others are skipped automatically
73
+ - **Telegram bot token** — from [@BotFather](https://t.me/BotFather) on Telegram
74
+ - **Daily token limits** — per-provider caps (0 = unlimited); auto-switches on breach
75
+ - **Shell / skill-install** — optional tool permissions
52
76
 
53
- **Telegram bot:**
77
+ Config is saved to `~/.tiger/.env` (mode 600).
54
78
 
79
+ ### 2. Start
80
+
81
+ **CLI chat:**
55
82
  ```bash
56
- tiger telegram # Start in foreground
57
- tiger telegram --background # Start as background daemon
58
- tiger stop # Stop daemon
59
- tiger status # Check daemon status
83
+ tiger start
60
84
  ```
85
+ Exit with `/exit` or `/quit`.
61
86
 
62
- ---
87
+ **Telegram bot (foreground):**
88
+ ```bash
89
+ tiger telegram
90
+ ```
63
91
 
64
- ## 📋 Requirements
92
+ **Telegram bot (background daemon):**
93
+ ```bash
94
+ tiger telegram --background # start
95
+ tiger status # check if running
96
+ tiger stop # stop
97
+ ```
65
98
 
66
- - Node.js 18+ (20+ recommended)
67
- - npm
68
- - Python 3 (for SQLite memory helper)
99
+ Logs: `~/.tiger/logs/telegram.out.log`
69
100
 
70
101
  ---
71
102
 
72
103
  ## 🎮 Run Modes
73
104
 
74
- | Mode | Command | Use Case |
75
- |------|---------|----------|
105
+ | Mode | Command | Description |
106
+ |------|---------|-------------|
76
107
  | **CLI** | `tiger start` | Interactive terminal chat |
77
108
  | **Telegram** | `tiger telegram` | Telegram bot (foreground) |
78
- | **Background** | `tiger telegram --background` | 24/7 daemon |
79
- | **Stop** | `tiger stop` | Kill background daemon |
80
- | **Status** | `tiger status` | Check if daemon is running |
81
-
82
- Background logs: `~/.tiger/logs/telegram-supervisor.log`
109
+ | **Background** | `tiger telegram --background` | 24/7 daemon with auto-restart |
110
+ | **Stop** | `tiger stop` | Stop background daemon |
111
+ | **Status** | `tiger status` | Check daemon status |
112
+ | **Onboard** | `tiger onboard` | Re-run setup wizard |
83
113
 
84
114
  ---
85
115
 
86
- ## 🔧 Setup Wizard
116
+ ## 🔧 Setup Wizard Details
87
117
 
88
- `tiger onboard` creates and configures:
118
+ `tiger onboard` writes `~/.tiger/.env` with all settings. You can re-run it at any time to update config.
89
119
 
90
- - `~/.tiger/.env` settings and provider config
91
- - `~/.tiger/.env.secrets` — API keys (mode 600, gitignored)
120
+ | Wizard prompt | What it sets |
121
+ |---------------|-------------|
122
+ | Active provider | `ACTIVE_PROVIDER` |
123
+ | Fallback order | `PROVIDER_ORDER` |
124
+ | API keys | `ZAI_API_KEY`, `CLAUDE_API_KEY`, etc. |
125
+ | Telegram token | `TELEGRAM_BOT_TOKEN` |
126
+ | Token limits | `ZAI_TOKEN_LIMIT`, `CLAUDE_TOKEN_LIMIT`, etc. |
127
+ | Shell tool | `ALLOW_SHELL` |
128
+ | Skill install | `ALLOW_SKILL_INSTALL` |
92
129
 
93
- Setup options:
94
- - Choose LLM provider and API keys
95
- - Persistent vs temporary vector DB
96
- - Optional `sqlite-vec` acceleration
97
- - Optional encrypted secrets file
130
+ > **Tip:** You can also edit `~/.tiger/.env` directly and restart the bot to apply changes.
98
131
 
99
132
  ---
100
133
 
@@ -233,6 +266,27 @@ Without it, Tiger falls back to cosine similarity in Python — slower but fully
233
266
  | **Skills** | `list_skills`, `load_skill`, `clawhub_search`, `clawhub_install` |
234
267
  | **Orchestration** | `run_sub_agents` |
235
268
 
269
+ ### ClawHub Skills
270
+
271
+ Tiger can search and install skills from [ClawHub](https://clawhub.dev) — a community registry of reusable agent skills. The `clawhub` CLI is bundled with Tiger, no separate install needed.
272
+
273
+ Enable skill install in `~/.tiger/.env`:
274
+
275
+ ```env
276
+ ALLOW_SKILL_INSTALL=true
277
+ ```
278
+
279
+ Then just ask Tiger in chat:
280
+
281
+ ```
282
+ Search for a web search skill on clawhub
283
+ Install the web-search skill
284
+ ```
285
+
286
+ Skills are installed to `~/.tiger/skills/` and loaded automatically on demand.
287
+
288
+ > **Note:** `ALLOW_SKILL_INSTALL=true` must be set during `tiger onboard` or added manually to `~/.tiger/.env`.
289
+
236
290
  ---
237
291
 
238
292
  ## 🔒 Security
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tiger-agent",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "Cognitive AI agent with persistent memory, multi-provider LLM, and Telegram bot",
5
5
  "type": "commonjs",
6
6
  "main": "src/cli.js",
@@ -1,7 +1,7 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
  const { chatCompletion, embedText } = require('../llmClient');
4
- const { dataDir, embeddingsEnabled } = require('../config');
4
+ const { dataDir, embeddingsEnabled, reflectionUpdateHours } = require('../config');
5
5
  const { addMemory, getMeta, setMeta, getMessagesSince, getRecentMessagesAll } = require('./db');
6
6
 
7
7
  const REFLECTION_META_KEY = 'memory_reflection_last_run_ts';
@@ -80,7 +80,7 @@ function appendHuman2Update(filePath, payload, stampIso) {
80
80
  for (const w of payload.successfulWorkflows) lines.push(`- Workflow: ${w}`);
81
81
  if (!lines.length) return;
82
82
  const block = `\n## Update ${stampIso}\n${lines.join('\n')}\n`;
83
- fs.writeFileSync(full, `${existing.trimEnd()}\n${block}`, 'utf8');
83
+ fs.writeFileSync(full, `${existing.trimEnd()}${block}`, 'utf8');
84
84
  }
85
85
 
86
86
  async function generateReflection(rows, sinceIso, untilIso) {
@@ -123,9 +123,20 @@ async function generateReflection(rows, sinceIso, untilIso) {
123
123
  };
124
124
  }
125
125
 
126
+ function shouldRunReflectionCycle(lastRunTs) {
127
+ if (!lastRunTs) return true;
128
+ const hoursPassed = (nowTs() - lastRunTs) / (60 * 60 * 1000);
129
+ return hoursPassed >= reflectionUpdateHours;
130
+ }
131
+
126
132
  async function maybeRunReflectionCycle({ force = false } = {}) {
127
133
  const startedAt = nowTs();
128
134
  const lastRunTs = Number(getMeta(REFLECTION_META_KEY, 0) || 0);
135
+
136
+ if (!force && !shouldRunReflectionCycle(lastRunTs)) {
137
+ return { ok: true, skipped: true, reason: 'not_yet_due' };
138
+ }
139
+
129
140
  const rows = lastRunTs
130
141
  ? getMessagesSince(lastRunTs, MAX_MESSAGE_SCAN)
131
142
  : getRecentMessagesAll(Math.min(MAX_MESSAGE_SCAN, 240));
@@ -185,6 +196,7 @@ async function maybeRunReflectionCycle({ force = false } = {}) {
185
196
  }
186
197
 
187
198
  setMeta(REFLECTION_META_KEY, startedAt);
199
+ console.log(`[ReflectionCycle] Completed at ${stampIso} (${rows.length} messages processed)`);
188
200
  return { ok: true, skipped: false, at: stampIso };
189
201
  }
190
202
 
@@ -8,14 +8,30 @@ function startReflectionScheduler() {
8
8
 
9
9
  const everyMs = Math.max(1, Number(reflectionUpdateHours || 12)) * 60 * 60 * 1000;
10
10
 
11
+ console.log(`[ReflectionScheduler] Starting with interval: ${reflectionUpdateHours || 12} hours (${everyMs}ms)`);
12
+
11
13
  // Kick one asynchronous check on startup.
12
- maybeRunReflectionCycle().catch(() => {});
14
+ maybeRunReflectionCycle().catch((err) => {
15
+ console.error('[ReflectionScheduler] Startup check failed:', err.message);
16
+ });
13
17
 
14
18
  intervalHandle = setInterval(() => {
15
- maybeRunReflectionCycle().catch(() => {});
19
+ console.log('[ReflectionScheduler] Running scheduled reflection cycle...');
20
+ maybeRunReflectionCycle().catch((err) => {
21
+ console.error('[ReflectionScheduler] Scheduled cycle failed:', err.message);
22
+ });
16
23
  }, everyMs);
17
24
  }
18
25
 
26
+ function stopReflectionScheduler() {
27
+ if (intervalHandle) {
28
+ clearInterval(intervalHandle);
29
+ intervalHandle = null;
30
+ console.log('[ReflectionScheduler] Stopped');
31
+ }
32
+ }
33
+
19
34
  module.exports = {
20
- startReflectionScheduler
35
+ startReflectionScheduler,
36
+ stopReflectionScheduler
21
37
  };
@@ -4,7 +4,8 @@ const { execFile } = require('child_process');
4
4
  const { promisify } = require('util');
5
5
 
6
6
  const execFileAsync = promisify(execFile);
7
- const localClawhubBin = path.resolve(process.cwd(), 'node_modules', '.bin', 'clawhub');
7
+ // Resolve clawhub from the package's own node_modules (works for both global and local installs)
8
+ const localClawhubBin = path.resolve(__dirname, '..', '..', 'node_modules', '.bin', 'clawhub');
8
9
 
9
10
  function listSkills(baseDir) {
10
11
  if (!fs.existsSync(baseDir)) return [];
@@ -7,7 +7,8 @@ const { listSkills, loadSkill, clawhubSearch, clawhubInstall } = require('./skil
7
7
  const { runSubAgentBatch } = require('./subAgent');
8
8
 
9
9
  const execAsync = promisify(exec);
10
- const skillsDir = path.resolve('./skills');
10
+ const rootDir = process.env.TIGER_HOME || process.cwd();
11
+ const skillsDir = path.resolve(rootDir, 'skills');
11
12
 
12
13
  function toAbsolutePath(inputPath) {
13
14
  return path.resolve(String(inputPath || '.'));
@@ -113,7 +114,7 @@ async function clawhubSearchTool(args = {}) {
113
114
  return clawhubSearch({
114
115
  query: args.query,
115
116
  limit: args.limit,
116
- workdir: args.workdir || process.cwd(),
117
+ workdir: args.workdir || rootDir,
117
118
  dir: args.dir || 'skills',
118
119
  timeout_ms: args.timeout_ms
119
120
  });
@@ -124,7 +125,7 @@ async function clawhubInstallTool(args = {}) {
124
125
  slug: args.slug,
125
126
  version: args.version,
126
127
  force: args.force,
127
- workdir: args.workdir || process.cwd(),
128
+ workdir: args.workdir || rootDir,
128
129
  dir: args.dir || 'skills',
129
130
  timeout_ms: args.timeout_ms
130
131
  });