tiger-agent 0.2.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/.env.example ADDED
@@ -0,0 +1,22 @@
1
+ # ============================================
2
+ # Tiger Bot Environment Configuration
3
+ # Copy this file to .env and fill in real values
4
+ # NEVER commit .env to git!
5
+ # ============================================
6
+
7
+ # Google Gemini (for image generation)
8
+ GEMINI_API_KEY=your_gemini_api_key_here
9
+
10
+ # Telegram Bot
11
+ TELEGRAM_BOT_TOKEN=your_telegram_bot_token_here
12
+ TELEGRAM_CHAT_ID=8172556270
13
+
14
+ # X/Twitter (optional - paid API)
15
+ X_BEARER_TOKEN=your_x_bearer_token_here
16
+
17
+ # Pinecone (optional - if using cloud vector DB)
18
+ PINECONE_API_KEY=your_pinecone_key_here
19
+ PINECONE_ENVIRONMENT=your_pinecone_env
20
+
21
+ # SQLite Configuration
22
+ TIGER_DB_PATH=/root/.tiger/memory/tiger_memory.db
@@ -0,0 +1,14 @@
1
+ # Secrets only. Keep this file local as .env.secrets (gitignored),
2
+ # or encrypt it to .env.secrets.enc and delete the plaintext.
3
+
4
+ # Moonshot/Open Platform key (used when KIMI_PROVIDER=moonshot)
5
+ MOONSHOT_API_KEY=
6
+
7
+ # Kimi Code API key (used when KIMI_PROVIDER=code)
8
+ KIMI_CODE_API_KEY=
9
+
10
+ # Backward-compatible alias (optional)
11
+ KIMI_API_KEY=
12
+
13
+ # Telegram bot token
14
+ TELEGRAM_BOT_TOKEN=
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 AI Research Group, Department of Civil Engineering,
4
+ King Mongkut's University of Technology Thonburi (KMUTT)
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,284 @@
1
+ # ๐Ÿฏ Tiger Agent
2
+
3
+ **Made by AI Research Group, Department of Civil Engineering, King Mongkut's University of Technology Thonburi (KMUTT)**
4
+
5
+ Tiger is a **Cognitive AI Agent** with persistent long-term memory, multi-provider LLM support, self-learning, and Telegram bot integration โ€” designed for 24/7 autonomous operation on Linux.
6
+
7
+ ---
8
+
9
+ ## ๐ŸŽฏ Why Tiger?
10
+
11
+ | Feature | Tiger Bot | Generic AI Assistants |
12
+ |---------|-----------|----------------------|
13
+ | **Memory** | Persistent lifetime memory (Vector DB) | Forgets when session ends |
14
+ | **Learning** | Self-training every 12 hours | Static, never improves |
15
+ | **Security** | Audit logs + Encryption + Hardened perms | No audit trail |
16
+ | **Channels** | CLI + Telegram simultaneously | Single channel only |
17
+ | **Execution** | Chains multiple skills autonomously | Single command only |
18
+
19
+ ---
20
+
21
+ ## ๐Ÿ“ฆ Installation
22
+
23
+ ```bash
24
+ npm install -g tiger-agent
25
+ ```
26
+
27
+ No git clone needed.
28
+
29
+ ---
30
+
31
+ ## ๐Ÿš€ Quick Start
32
+
33
+ ```bash
34
+ tiger onboard # First-time setup wizard
35
+ tiger start # Start CLI chat
36
+ ```
37
+
38
+ CLI exit: `/exit` or `/quit`
39
+
40
+ For Telegram:
41
+
42
+ ```bash
43
+ tiger telegram # Foreground
44
+ tiger telegram --background # Background daemon
45
+ tiger stop # Stop daemon
46
+ tiger status # Check daemon status
47
+ ```
48
+
49
+ ---
50
+
51
+ ## ๐Ÿ“‹ Requirements
52
+
53
+ - Node.js 18+ (20+ recommended)
54
+ - npm
55
+ - Python 3 (for SQLite memory helper)
56
+
57
+ ---
58
+
59
+ ## ๐ŸŽฎ Run Modes
60
+
61
+ | Mode | Global install | From source | Use Case |
62
+ |------|---------------|-------------|----------|
63
+ | **CLI** | `tiger start` | `npm run cli` | Interactive terminal |
64
+ | **Telegram** | `tiger telegram` | `npm run telegram` | Bot foreground |
65
+ | **Background** | `tiger telegram --background` | `npm run telegram:bg` | 24/7 daemon |
66
+ | **Stop** | `tiger stop` | `npm run telegram:stop` | Kill daemon |
67
+ | **Status** | `tiger status` | โ€” | Check daemon |
68
+
69
+ Background logs: `~/.tiger/logs/telegram-supervisor.log`
70
+
71
+ ---
72
+
73
+ ## ๐Ÿ”ง Setup Wizard
74
+
75
+ `tiger onboard` (global) or `npm run setup` (from source) configures:
76
+
77
+ - `~/.tiger/.env` โ€” non-secret settings
78
+ - `~/.tiger/.env.secrets` โ€” API keys and tokens (mode 600)
79
+
80
+ Options during setup:
81
+ - Persistent vs temporary vector DB
82
+ - Optional `sqlite-vec` acceleration
83
+ - Optional encrypted secrets file
84
+
85
+ ---
86
+
87
+ ## ๐Ÿ”‘ Environment Variables
88
+
89
+ | Variable | Default | Description |
90
+ |----------|---------|-------------|
91
+ | `ACTIVE_PROVIDER` | โ€” | Active LLM provider (`kimi`, `zai`, `minimax`, `claude`, `moonshot`) |
92
+ | `PROVIDER_ORDER` | โ€” | Fallback order, comma-separated |
93
+ | `TELEGRAM_BOT_TOKEN` | โ€” | Telegram bot token |
94
+ | `ALLOW_SHELL` | `false` | Enable shell tool |
95
+ | `ALLOW_SKILL_INSTALL` | `false` | Enable ClawHub skill install |
96
+ | `VECTOR_DB_PATH` | `~/.tiger/db/memory.sqlite` | SQLite vector DB path |
97
+ | `DATA_DIR` | `~/.tiger/data` | Context files directory |
98
+
99
+ ---
100
+
101
+ ## ๐ŸŒ Multi-Provider LLM
102
+
103
+ Tiger supports **5 providers** with automatic fallback and daily token limits.
104
+
105
+ ### Supported Providers
106
+
107
+ | Provider | ID | Default Model | API Key |
108
+ |----------|----|--------------|---------|
109
+ | Kimi Code | `kimi` | `k2p5` | `KIMI_CODE_API_KEY` |
110
+ | Kimi Moonshot | `moonshot` | `kimi-k1` | `MOONSHOT_API_KEY` |
111
+ | Z.ai (Zhipu) | `zai` | `glm-5` | `ZAI_API_KEY` (format: `id.secret`) |
112
+ | MiniMax | `minimax` | `abab6.5s-chat` | `MINIMAX_API_KEY` |
113
+ | Claude (Anthropic) | `claude` | `claude-sonnet-4-6` | `CLAUDE_API_KEY` |
114
+
115
+ ### `.env` Configuration
116
+
117
+ ```env
118
+ ACTIVE_PROVIDER=zai
119
+ PROVIDER_ORDER=zai,claude,kimi,minimax,moonshot
120
+
121
+ KIMI_CODE_API_KEY=<key>
122
+ ZAI_API_KEY=<key>
123
+ MINIMAX_API_KEY=<key>
124
+ CLAUDE_API_KEY=<key>
125
+ MOONSHOT_API_KEY=<key>
126
+
127
+ # Daily token limits per provider (0 = unlimited)
128
+ KIMI_TOKEN_LIMIT=100000
129
+ ZAI_TOKEN_LIMIT=100000
130
+ MINIMAX_TOKEN_LIMIT=100000
131
+ CLAUDE_TOKEN_LIMIT=500000
132
+ MOONSHOT_TOKEN_LIMIT=100000
133
+ ```
134
+
135
+ ### Auto-Switch Behaviour
136
+
137
+ 1. Uses `ACTIVE_PROVIDER` for all requests
138
+ 2. On **429** (rate limit) or **403** (quota exceeded) โ€” switches to next in `PROVIDER_ORDER`
139
+ 3. When a provider's daily token limit is reached โ€” skipped for the rest of the day
140
+ 4. Providers with no API key are silently skipped
141
+ 5. Token usage tracked in `~/.tiger/db/token_usage.json`, resets at UTC midnight
142
+
143
+ ---
144
+
145
+ ## ๐Ÿ’ฌ Telegram Commands
146
+
147
+ | Command | Description |
148
+ |---------|-------------|
149
+ | `/api` | Show all providers with token usage |
150
+ | `/api <id>` | Switch provider (e.g. `/api claude`) |
151
+ | `/tokens` | Show today's token usage per provider |
152
+ | `/help` | Show all commands |
153
+
154
+ ---
155
+
156
+ ## ๐Ÿง  Memory & Context
157
+
158
+ Context files loaded every turn (from `~/.tiger/data/`):
159
+
160
+ - `soul.md` โ€” Agent personality
161
+ - `human.md` / `human2.md` โ€” User profile
162
+ - `ownskill.md` โ€” Known skills (auto-refreshed every 24h)
163
+
164
+ Auto-refresh cycles (configurable via `.env`):
165
+
166
+ | Cycle | Variable | Default |
167
+ |-------|----------|---------|
168
+ | Skill summary | `OWN_SKILL_UPDATE_HOURS` | 24h |
169
+ | Soul refresh | `SOUL_UPDATE_HOURS` | 24h |
170
+ | Reflection | `REFLECTION_UPDATE_HOURS` | 12h |
171
+ | Memory ingest | `MEMORY_INGEST_EVERY_TURNS` | every N turns |
172
+
173
+ Vector memory DB: `~/.tiger/db/memory.sqlite`
174
+
175
+ Optional `sqlite-vec` acceleration:
176
+ ```env
177
+ SQLITE_VEC_EXTENSION=/path/to/sqlite_vec
178
+ ```
179
+
180
+ Memory commands (from source):
181
+ ```bash
182
+ npm run memory:init # Initialize DB
183
+ npm run memory:stats # Show stats
184
+ npm run memory:migrate # Migrate from /tmp/
185
+ npm run memory:vec:check # Check sqlite-vec
186
+ ```
187
+
188
+ ---
189
+
190
+ ## ๐Ÿ› ๏ธ Built-in Tools
191
+
192
+ | Category | Tools |
193
+ |----------|-------|
194
+ | **Files** | `list_files`, `read_file`, `write_file` |
195
+ | **Shell** | `run_shell` (requires `ALLOW_SHELL=true`) |
196
+ | **Skills** | `list_skills`, `load_skill`, `clawhub_search`, `clawhub_install` |
197
+ | **Orchestration** | `run_sub_agents` |
198
+
199
+ ---
200
+
201
+ ## ๐Ÿ”’ Security
202
+
203
+ | Feature | Detail |
204
+ |---------|--------|
205
+ | **Credential Storage** | Externalized to `~/.tiger/.env.secrets` (mode 600) |
206
+ | **Database Security** | `~/.tiger/db/` with hardened permissions |
207
+ | **Audit Logging** | Sanitized skill logs at `~/.tiger/logs/audit.log` |
208
+ | **Auto Backup** | Daily SQLite backups, 30-day retention |
209
+ | **Secret Rotation** | Built-in 90-day rotation reminders |
210
+
211
+ ### Encrypted Secrets (optional)
212
+
213
+ ```bash
214
+ export SECRETS_PASSPHRASE='your-long-passphrase'
215
+ node scripts/encrypt-env.js --in .env.secrets --out .env.secrets.enc
216
+ rm .env.secrets
217
+ ```
218
+
219
+ ---
220
+
221
+ ## ๐Ÿ†š Tiger vs OpenClaw
222
+
223
+ | Feature | **Tiger** ๐Ÿฏ | **OpenClaw** ๐Ÿ”ง |
224
+ |---------|-------------|-----------------|
225
+ | **Identity** | Persistent AI persona | Skill marketplace |
226
+ | **Memory** | Text files + SQLite vector | Skill-based only |
227
+ | **Self-Training** | โœ… 12h auto-reflection | โŒ Manual only |
228
+ | **Skill Orchestration** | Multi-skill pipelines | Single execution |
229
+ | **Context Retention** | โœ… Cross-session | Session-only |
230
+ | **Security** | โœ… Encryption + audit logs | Basic |
231
+ | **Installation** | `npm install -g tiger-agent` | `clawhub install` |
232
+
233
+ ---
234
+
235
+ ## ๐Ÿ› Troubleshooting
236
+
237
+ | Issue | Solution |
238
+ |-------|----------|
239
+ | Bot stuck on one provider | `/api <name>` in Telegram to switch manually |
240
+ | Provider silently skipped | No API key set, or daily limit reached โ€” check `/tokens` |
241
+ | `401` auth error | Wrong or missing API key |
242
+ | `403` quota error | Daily quota exhausted โ€” auto-switches; top up billing or raise `*_TOKEN_LIMIT` |
243
+ | `429` rate limit | Auto-switches to next provider in `PROVIDER_ORDER` |
244
+ | Z.ai auth fails | Key must be `id.secret` format (from Zhipu/BigModel console) |
245
+ | Shell tool disabled | Set `ALLOW_SHELL=true` in `.env` |
246
+ | Stuck processes | `pkill -f "node src/cli.js"` then restart |
247
+ | Reset token counters | Delete `~/.tiger/db/token_usage.json` and restart |
248
+
249
+ ---
250
+
251
+ ## ๐Ÿ“ Data Directory
252
+
253
+ After global install, all runtime data lives in `~/.tiger/`:
254
+
255
+ ```
256
+ ~/.tiger/
257
+ โ”œโ”€โ”€ .env # Settings
258
+ โ”œโ”€โ”€ .env.secrets # API keys (mode 600)
259
+ โ”œโ”€โ”€ data/ # Context files (soul.md, human.md, ...)
260
+ โ”œโ”€โ”€ db/
261
+ โ”‚ โ”œโ”€โ”€ agent.json # Conversation state
262
+ โ”‚ โ”œโ”€โ”€ memory.sqlite # Vector memory
263
+ โ”‚ โ””โ”€โ”€ token_usage.json # Daily token counters
264
+ โ””โ”€โ”€ logs/
265
+ โ”œโ”€โ”€ audit.log
266
+ โ””โ”€โ”€ telegram-supervisor.log
267
+ ```
268
+
269
+ ---
270
+
271
+ ## ๐Ÿ‘ฅ Authors
272
+
273
+ **AI Research Group**
274
+ Department of Civil Engineering
275
+ King Mongkut's University of Technology Thonburi (KMUTT)
276
+ Bangkok, Thailand
277
+
278
+ ---
279
+
280
+ ## ๐Ÿ“œ License
281
+
282
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
283
+
284
+ *[่™Ž - Hว” - The Tiger: Powerful, agile, and relentless in pursuit of goals]*
package/bin/tiger.js ADDED
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const path = require('path');
5
+ const fs = require('fs');
6
+ const os = require('os');
7
+
8
+ const PKG_ROOT = path.resolve(__dirname, '..');
9
+ const TIGER_HOME = process.env.TIGER_HOME || path.join(os.homedir(), '.tiger');
10
+
11
+ // Ensure runtime dirs exist
12
+ ['', 'data', 'db', 'logs'].forEach((d) => fs.mkdirSync(path.join(TIGER_HOME, d), { recursive: true }));
13
+
14
+ // Expose to child modules and the supervisor worker
15
+ process.env.TIGER_HOME = TIGER_HOME;
16
+
17
+ // chdir so all relative env paths (./data, ./db, .env) resolve inside ~/.tiger
18
+ process.chdir(TIGER_HOME);
19
+
20
+ const argv = process.argv.slice(2);
21
+ const cmd = argv[0] || '';
22
+
23
+ // โ”€โ”€โ”€ Help โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
24
+ function showHelp() {
25
+ console.log(`
26
+ Tiger Agent ๐Ÿฏ โ€” AI assistant with persistent memory
27
+
28
+ Usage:
29
+ tiger onboard Interactive setup wizard
30
+ tiger onboard --install-daemon Setup + install system daemon (auto-start on boot)
31
+ tiger start Start CLI chat
32
+ tiger telegram Start Telegram bot (foreground)
33
+ tiger telegram --background Start Telegram bot as background process
34
+ tiger stop Stop background Telegram bot
35
+ tiger status Show daemon / process status
36
+ tiger version Print version
37
+
38
+ Config & data: ${TIGER_HOME}
39
+ `.trim());
40
+ }
41
+
42
+ // โ”€โ”€โ”€ Route commands โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
43
+ switch (cmd) {
44
+ case 'onboard':
45
+ require(path.join(PKG_ROOT, 'scripts', 'onboard.js'));
46
+ break;
47
+
48
+ case 'version':
49
+ case '-v':
50
+ case '--version': {
51
+ const pkg = require(path.join(PKG_ROOT, 'package.json'));
52
+ console.log(pkg.version);
53
+ break;
54
+ }
55
+
56
+ case 'status': {
57
+ const pidFile = path.join(TIGER_HOME, 'tiger-telegram.pid');
58
+ if (!fs.existsSync(pidFile)) { console.log('Tiger daemon: not running'); break; }
59
+ const pid = Number(fs.readFileSync(pidFile, 'utf8').trim());
60
+ try { process.kill(pid, 0); console.log(`Tiger daemon: running (PID ${pid})`); }
61
+ catch (_) { console.log('Tiger daemon: not running (stale pid file)'); }
62
+ break;
63
+ }
64
+
65
+ case 'stop':
66
+ process.argv = [process.argv[0], process.argv[1], '--telegram-stop'];
67
+ require(path.join(PKG_ROOT, 'src', 'cli.js'));
68
+ break;
69
+
70
+ case 'telegram':
71
+ if (argv.includes('--background') || argv.includes('-b')) {
72
+ process.argv = [process.argv[0], process.argv[1], '--telegram', '--background'];
73
+ } else {
74
+ process.argv = [process.argv[0], process.argv[1], '--telegram'];
75
+ }
76
+ require(path.join(PKG_ROOT, 'src', 'cli.js'));
77
+ break;
78
+
79
+ case 'start':
80
+ case 'cli':
81
+ case '':
82
+ process.argv = [process.argv[0], process.argv[1]];
83
+ require(path.join(PKG_ROOT, 'src', 'cli.js'));
84
+ break;
85
+
86
+ case 'help':
87
+ case '--help':
88
+ case '-h':
89
+ showHelp();
90
+ break;
91
+
92
+ default:
93
+ console.error(`Unknown command: ${cmd}`);
94
+ showHelp();
95
+ process.exit(1);
96
+ }
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "tiger-agent",
3
+ "version": "0.2.0",
4
+ "description": "Cognitive AI agent with persistent memory, multi-provider LLM, and Telegram bot",
5
+ "type": "commonjs",
6
+ "main": "src/cli.js",
7
+ "bin": {
8
+ "tiger": "bin/tiger.js"
9
+ },
10
+ "files": [
11
+ "bin/",
12
+ "src/",
13
+ "scripts/",
14
+ ".env.example",
15
+ ".env.secrets.example"
16
+ ],
17
+ "scripts": {
18
+ "postinstall": "node -e \"if(process.env.npm_config_global==='true'){console.log('\\n๐Ÿฏ Tiger Agent installed!\\n\\nRun to get started:\\n tiger onboard\\n')}\"",
19
+ "setup": "node scripts/setup.js",
20
+ "onboard": "node scripts/onboard.js",
21
+ "start": "node src/cli.js",
22
+ "telegram": "node src/cli.js --telegram",
23
+ "telegram:bg": "node src/cli.js --telegram --background",
24
+ "telegram:stop": "node src/cli.js --telegram-stop",
25
+ "cli": "node src/cli.js",
26
+ "memory:init": "python3 scripts/sqlite_memory.py init --db ./db/memory.sqlite",
27
+ "memory:stats": "python3 scripts/sqlite_memory.py stats --db ./db/memory.sqlite",
28
+ "memory:migrate": "node scripts/migrate-vector-db.js --from /tmp/tiger_memory.db --to ./db/memory.sqlite",
29
+ "memory:vec:check": "python3 scripts/sqlite_vec_setup.py",
30
+ "memory:vec:install": "python3 scripts/sqlite_vec_setup.py --install --write-env"
31
+ },
32
+ "engines": {
33
+ "node": ">=18"
34
+ },
35
+ "keywords": [
36
+ "ai",
37
+ "agent",
38
+ "llm",
39
+ "telegram",
40
+ "chatbot",
41
+ "memory",
42
+ "claude",
43
+ "zhipu",
44
+ "glm",
45
+ "kimi",
46
+ "minimax"
47
+ ],
48
+ "author": "AI Research Group, Dept. of Civil Engineering, KMUTT",
49
+ "license": "MIT",
50
+ "publishConfig": {
51
+ "access": "public"
52
+ },
53
+ "dependencies": {
54
+ "clawhub": "^0.5.0",
55
+ "dotenv": "^16.4.5",
56
+ "node-telegram-bot-api": "^0.66.0"
57
+ }
58
+ }
@@ -0,0 +1,54 @@
1
+ #!/bin/bash
2
+ # Tiger Audit Logger
3
+ # Logs skill usage with sanitization (no secrets)
4
+ # Format: TIMESTAMP | SKILL | ACTION | STATUS | USER_HASH
5
+
6
+ TIGER_HOME="${TIGER_HOME:-$HOME/.tiger}"
7
+ AUDIT_LOG="$TIGER_HOME/logs/audit.log"
8
+ MAX_LOG_SIZE=10485760 # 10MB
9
+ MAX_LOG_FILES=5
10
+
11
+ # Create log directory
12
+ mkdir -p "$(dirname "$AUDIT_LOG")"
13
+ chmod 700 "$(dirname "$AUDIT_LOG")"
14
+
15
+ # Rotate logs if too large
16
+ rotate_logs() {
17
+ if [ -f "$AUDIT_LOG" ] && [ $(stat -f%z "$AUDIT_LOG" 2>/dev/null || stat -c%s "$AUDIT_LOG" 2>/dev/null || echo 0) -gt $MAX_LOG_SIZE ]; then
18
+ for i in $(seq $MAX_LOG_FILES -1 1); do
19
+ [ -f "$AUDIT_LOG.$i" ] && mv "$AUDIT_LOG.$i" "$AUDIT_LOG.$((i+1))"
20
+ done
21
+ [ -f "$AUDIT_LOG" ] && mv "$AUDIT_LOG" "$AUDIT_LOG.1"
22
+ touch "$AUDIT_LOG"
23
+ chmod 600 "$AUDIT_LOG"
24
+ fi
25
+ }
26
+
27
+ # Log function
28
+ log_audit() {
29
+ rotate_logs
30
+
31
+ local skill="$1"
32
+ local action="$2"
33
+ local status="$3"
34
+ local timestamp=$(date -Iseconds)
35
+ local user_hash=$(echo "$USER@$(hostname)" | sha256sum | cut -d' ' -f1 | head -c16)
36
+
37
+ # Sanitize: remove potential secrets from action
38
+ local sanitized_action=$(echo "$action" | sed -E 's/(api[_-]?key|token|password|secret)[=:][^ ]+/\1=***/gi')
39
+
40
+ echo "[$timestamp] | $skill | $sanitized_action | $status | $user_hash" >> "$AUDIT_LOG"
41
+ chmod 600 "$AUDIT_LOG"
42
+ }
43
+
44
+ # Example usage:
45
+ # log_audit "nano-banana-pro-2" "generate_image --prompt '...'" "success"
46
+
47
+ # If called directly, show usage
48
+ if [ "${BASH_SOURCE[0]}" == "${0}" ]; then
49
+ echo "Tiger Audit Logger"
50
+ echo "Usage: source $0 && log_audit <skill> <action> <status>"
51
+ echo ""
52
+ echo "Recent audit entries:"
53
+ [ -f "$AUDIT_LOG" ] && tail -20 "$AUDIT_LOG" || echo "(no entries yet)"
54
+ fi
@@ -0,0 +1,42 @@
1
+ #!/bin/bash
2
+ # Tiger Database Backup Script
3
+ # Runs: Daily via cron or manual
4
+ # Backs up: SQLite memory DB, config files
5
+
6
+ set -e
7
+
8
+ TIGER_HOME="${TIGER_HOME:-$HOME/.tiger}"
9
+ BACKUP_DIR="$TIGER_HOME/backup"
10
+ DB_PATH="$TIGER_HOME/memory/tiger_memory.db"
11
+ DATE=$(date +%Y%m%d_%H%M%S)
12
+ RETENTION_DAYS=30
13
+
14
+ echo "๐Ÿฏ Tiger Backup Started: $DATE"
15
+
16
+ # Create backup directory
17
+ mkdir -p "$BACKUP_DIR"
18
+
19
+ # Backup SQLite database (with WAL if exists)
20
+ if [ -f "$DB_PATH" ]; then
21
+ BACKUP_FILE="$BACKUP_DIR/tiger_memory_$DATE.db"
22
+ sqlite3 "$DB_PATH" ".backup '$BACKUP_FILE'"
23
+ gzip "$BACKUP_FILE"
24
+ echo "โœ… Database backed up: ${BACKUP_FILE}.gz"
25
+ else
26
+ echo "โš ๏ธ Database not found at $DB_PATH"
27
+ fi
28
+
29
+ # Backup config (excluding secrets)
30
+ if [ -d "$TIGER_HOME/config" ]; then
31
+ CONFIG_BACKUP="$BACKUP_DIR/config_$DATE.tar.gz"
32
+ tar -czf "$CONFIG_BACKUP" -C "$TIGER_HOME" config/ 2>/dev/null || true
33
+ echo "โœ… Config backed up: $CONFIG_BACKUP"
34
+ fi
35
+
36
+ # Cleanup old backups (keep last 30 days)
37
+ find "$BACKUP_DIR" -name "*.gz" -type f -mtime +$RETENTION_DAYS -delete
38
+ echo "๐Ÿงน Cleaned backups older than $RETENTION_DAYS days"
39
+
40
+ # Log backup event
41
+ logger -t tiger-backup "Backup completed: $DATE"
42
+ echo "โœ… Backup completed successfully"
@@ -0,0 +1,57 @@
1
+ const crypto = require('crypto');
2
+
3
+ const DEFAULT_ITERATIONS = 310000;
4
+
5
+ function deriveKey(passphrase, salt, iterations = DEFAULT_ITERATIONS) {
6
+ return crypto.pbkdf2Sync(
7
+ Buffer.from(String(passphrase), 'utf8'),
8
+ salt,
9
+ iterations,
10
+ 32,
11
+ 'sha256'
12
+ );
13
+ }
14
+
15
+ function encryptString(plaintext, passphrase, { iterations = DEFAULT_ITERATIONS } = {}) {
16
+ if (!passphrase) throw new Error('Missing passphrase');
17
+ const salt = crypto.randomBytes(16);
18
+ const iv = crypto.randomBytes(12);
19
+ const key = deriveKey(passphrase, salt, iterations);
20
+
21
+ const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
22
+ const ciphertext = Buffer.concat([cipher.update(Buffer.from(String(plaintext), 'utf8')), cipher.final()]);
23
+ const tag = cipher.getAuthTag();
24
+
25
+ return {
26
+ v: 1,
27
+ alg: 'aes-256-gcm',
28
+ kdf: 'pbkdf2-sha256',
29
+ iterations,
30
+ salt_b64: salt.toString('base64'),
31
+ iv_b64: iv.toString('base64'),
32
+ tag_b64: tag.toString('base64'),
33
+ ciphertext_b64: ciphertext.toString('base64')
34
+ };
35
+ }
36
+
37
+ function decryptToString(payload, passphrase) {
38
+ if (!passphrase) throw new Error('Missing passphrase');
39
+ if (!payload || payload.v !== 1) throw new Error('Unsupported payload');
40
+
41
+ const salt = Buffer.from(payload.salt_b64, 'base64');
42
+ const iv = Buffer.from(payload.iv_b64, 'base64');
43
+ const tag = Buffer.from(payload.tag_b64, 'base64');
44
+ const ciphertext = Buffer.from(payload.ciphertext_b64, 'base64');
45
+
46
+ const key = deriveKey(passphrase, salt, Number(payload.iterations) || DEFAULT_ITERATIONS);
47
+ const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
48
+ decipher.setAuthTag(tag);
49
+
50
+ const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
51
+ return plaintext.toString('utf8');
52
+ }
53
+
54
+ module.exports = {
55
+ encryptString,
56
+ decryptToString
57
+ };
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { decryptToString } = require('./cryptoEnv');
6
+
7
+ function arg(name, def = '') {
8
+ const idx = process.argv.indexOf(name);
9
+ if (idx === -1) return def;
10
+ return process.argv[idx + 1] || def;
11
+ }
12
+
13
+ const inPath = arg('--in', '.env.secrets.enc');
14
+ const outPath = arg('--out', '.env.secrets');
15
+ const passphrase = process.env.SECRETS_PASSPHRASE || '';
16
+
17
+ if (!passphrase) {
18
+ console.error('Missing SECRETS_PASSPHRASE env var');
19
+ process.exit(2);
20
+ }
21
+
22
+ const absIn = path.resolve(process.cwd(), inPath);
23
+ const absOut = path.resolve(process.cwd(), outPath);
24
+
25
+ if (!fs.existsSync(absIn)) {
26
+ console.error(`Encrypted file not found: ${absIn}`);
27
+ process.exit(2);
28
+ }
29
+
30
+ const payload = JSON.parse(fs.readFileSync(absIn, 'utf8'));
31
+ const plaintext = decryptToString(payload, passphrase);
32
+ fs.writeFileSync(absOut, plaintext, { mode: 0o600 });
33
+
34
+ console.log(`Wrote decrypted secrets to ${outPath}`);