From 0d153824629c0dec2476fc6ef0645d58f48b1e3c Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Wed, 18 Feb 2026 23:38:13 +0800 Subject: [PATCH 01/37] =?UTF-8?q?=F0=9F=93=A6=20new:=20add=20update=20chec?= =?UTF-8?q?ker=20functionality=20and=20context=20injection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/src/index.ts | 9 +++++++++ packages/core/src/loop.ts | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index b63cf5b..3d20616 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -49,3 +49,12 @@ export { BACKUP_CODE_LENGTH, RECOVERY_TOKEN_LENGTH, } from './owner-auth.js'; + +// Update checker — npm registry polling + system prompt context +export { + checkForUpdate, + buildUpdateContext, + detectRuntime, + isNewerVersion, +} from './update-checker.js'; +export type { UpdateInfo, UpdateRuntime } from './update-checker.js'; diff --git a/packages/core/src/loop.ts b/packages/core/src/loop.ts index 841387c..c02ee98 100644 --- a/packages/core/src/loop.ts +++ b/packages/core/src/loop.ts @@ -760,6 +760,11 @@ export async function agentLoop( } } + // Inject software update context (if an update is available) + if (context.updateContext) { + basePrompt += context.updateContext; + } + const systemPrompt = learning.injectIntoPrompt(basePrompt, learnedContext); // Sanitize user message for prompt injection defense (friends only) From ec863b1fcf0c0a01001fff8fdca898aa3efb3914 Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Wed, 18 Feb 2026 23:38:22 +0800 Subject: [PATCH 02/37] =?UTF-8?q?=F0=9F=93=A6=20new:=20implement=20update?= =?UTF-8?q?=20checker=20with=20caching=20and=20runtime=20detection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/src/update-checker.ts | 255 ++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 packages/core/src/update-checker.ts diff --git a/packages/core/src/update-checker.ts b/packages/core/src/update-checker.ts new file mode 100644 index 0000000..b87a046 --- /dev/null +++ b/packages/core/src/update-checker.ts @@ -0,0 +1,255 @@ +/** + * Update Checker + * + * Lightweight, non-blocking module that checks the npm registry for newer + * versions of tinyclaw. Results are cached locally (24-hour TTL) to avoid + * repeated network calls. + * + * The update info is injected into the agent's system prompt context so the + * AI can conversationally inform the user about available upgrades. + * + * Runtime detection differentiates npm installs (self-upgradable via shell + * tool) from Docker containers (manual pull required). + */ + +import { join } from 'node:path'; +import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs'; +import { logger } from '@tinyclaw/logger'; + +// --------------------------------------------------------------------------- +// Types +// --------------------------------------------------------------------------- + +export type UpdateRuntime = 'npm' | 'docker' | 'source'; + +export interface UpdateInfo { + /** Currently running version (e.g. "1.0.0"). */ + current: string; + /** Latest version published on npm (e.g. "1.1.0"). */ + latest: string; + /** Whether a newer version is available. */ + updateAvailable: boolean; + /** Detected runtime environment. */ + runtime: UpdateRuntime; + /** Timestamp (ms) of the last check. */ + checkedAt: number; + /** GitHub release URL for the latest version. */ + releaseUrl: string; +} + +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +/** Time-to-live for the cache file (24 hours). */ +const CACHE_TTL_MS = 24 * 60 * 60 * 1000; + +/** npm registry endpoint for the tinyclaw package. */ +const NPM_REGISTRY_URL = 'https://registry.npmjs.org/tinyclaw/latest'; + +/** Maximum time to wait for the registry response (ms). */ +const FETCH_TIMEOUT_MS = 5_000; + +/** Cache file name within the data directory. */ +const CACHE_FILENAME = 'update-check.json'; + +/** GitHub releases base URL. */ +const GITHUB_RELEASES_URL = 'https://github.com/warengonzaga/tinyclaw/releases/tag'; + +// --------------------------------------------------------------------------- +// Runtime detection +// --------------------------------------------------------------------------- + +/** + * Detect the runtime environment. + * + * - Docker: `/.dockerenv` exists or `TINYCLAW_RUNTIME` env is set to "docker" + * - Source: `TINYCLAW_RUNTIME` env is set to "source" + * - npm: everything else (global install via npm/bun/pnpm) + */ +export function detectRuntime(): UpdateRuntime { + const envRuntime = process.env.TINYCLAW_RUNTIME?.toLowerCase(); + if (envRuntime === 'docker') return 'docker'; + if (envRuntime === 'source') return 'source'; + + // Docker container detection + try { + if (existsSync('/.dockerenv')) return 'docker'; + } catch { + // Permission errors on exotic platforms — assume npm + } + + return 'npm'; +} + +// --------------------------------------------------------------------------- +// Semver comparison (minimal — avoids pulling a full semver library) +// --------------------------------------------------------------------------- + +/** + * Compare two semver strings. Returns true when `latest` is strictly newer + * than `current`. Only handles `MAJOR.MINOR.PATCH`; pre-release suffixes + * are ignored. + */ +export function isNewerVersion(current: string, latest: string): boolean { + const parse = (v: string): number[] => + v.replace(/^v/, '').split('.').map(Number).slice(0, 3); + const [cMaj = 0, cMin = 0, cPat = 0] = parse(current); + const [lMaj = 0, lMin = 0, lPat = 0] = parse(latest); + if (lMaj !== cMaj) return lMaj > cMaj; + if (lMin !== cMin) return lMin > cMin; + return lPat > cPat; +} + +// --------------------------------------------------------------------------- +// Cache I/O +// --------------------------------------------------------------------------- + +function getCachePath(dataDir: string): string { + return join(dataDir, 'data', CACHE_FILENAME); +} + +function readCache(dataDir: string): UpdateInfo | null { + try { + const raw = readFileSync(getCachePath(dataDir), 'utf-8'); + const cached = JSON.parse(raw) as UpdateInfo; + if (cached && typeof cached.checkedAt === 'number') return cached; + } catch { + // Missing or corrupt — will re-check + } + return null; +} + +function writeCache(dataDir: string, info: UpdateInfo): void { + try { + const dir = join(dataDir, 'data'); + if (!existsSync(dir)) mkdirSync(dir, { recursive: true }); + writeFileSync(getCachePath(dataDir), JSON.stringify(info, null, 2), 'utf-8'); + } catch (err) { + logger.debug('Failed to write update cache', err); + } +} + +// --------------------------------------------------------------------------- +// Registry fetch +// --------------------------------------------------------------------------- + +async function fetchLatestVersion(): Promise { + try { + const controller = new AbortController(); + const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS); + + const res = await fetch(NPM_REGISTRY_URL, { + signal: controller.signal, + headers: { Accept: 'application/json' }, + }); + clearTimeout(timeout); + + if (!res.ok) return null; + const data = (await res.json()) as { version?: string }; + return data.version ?? null; + } catch { + // Network error, timeout, or offline — silently return null + return null; + } +} + +// --------------------------------------------------------------------------- +// Public API +// --------------------------------------------------------------------------- + +/** + * Check for available updates. + * + * - Returns cached result if the cache is still fresh (< 24 hours old). + * - Otherwise fetches the npm registry in the background. + * - Never throws — returns null on any failure so startup is never delayed. + * + * @param currentVersion - The currently running version string. + * @param dataDir - The tinyclaw data directory (e.g. `~/.tinyclaw`). + */ +export async function checkForUpdate( + currentVersion: string, + dataDir: string, +): Promise { + try { + // Return cached result if still fresh + const cached = readCache(dataDir); + if (cached && Date.now() - cached.checkedAt < CACHE_TTL_MS) { + // Re-evaluate against the current binary version (in case user + // upgraded manually since the last check) + return { + ...cached, + current: currentVersion, + updateAvailable: isNewerVersion(currentVersion, cached.latest), + }; + } + + // Fetch latest version from npm + const latest = await fetchLatestVersion(); + if (!latest) return cached ?? null; // Network failure — use stale cache if available + + const runtime = detectRuntime(); + const info: UpdateInfo = { + current: currentVersion, + latest, + updateAvailable: isNewerVersion(currentVersion, latest), + runtime, + checkedAt: Date.now(), + releaseUrl: `${GITHUB_RELEASES_URL}/v${latest}`, + }; + + writeCache(dataDir, info); + + if (info.updateAvailable) { + logger.info('Update available', { current: currentVersion, latest, runtime }, { emoji: '🆕' }); + } + + return info; + } catch (err) { + logger.debug('Update check failed', err); + return null; + } +} + +// --------------------------------------------------------------------------- +// System prompt context builder +// --------------------------------------------------------------------------- + +/** + * Build a system prompt section that informs the agent about an available + * update. Returns an empty string if no update is available or info is null. + */ +export function buildUpdateContext(info: UpdateInfo | null): string { + if (!info?.updateAvailable) return ''; + + const upgradeInstructions = + info.runtime === 'npm' + ? `Since you are running as an npm global install, you can upgrade yourself using the shell tool: +\`bun install -g tinyclaw@latest\` or \`npm install -g tinyclaw@latest\` +After the upgrade completes, request a restart using the tinyclaw_restart tool so the supervisor can reload with the new version.` + : info.runtime === 'docker' + ? `Since you are running inside a Docker container, you cannot upgrade yourself directly. +Instruct the owner to run the following commands externally: +\`docker pull ghcr.io/warengonzaga/tinyclaw:latest\` +Then restart the container (e.g. \`docker restart tinyclaw\` or \`docker compose up -d\`).` + : `Since you are running from source, instruct the owner to pull the latest changes and rebuild: +\`git pull && bun install && bun run build:packages\` +Then restart using the tinyclaw_restart tool.`; + + return ` + +## Software Update Available +- **Current version:** ${info.current} +- **Latest version:** ${info.latest} +- **Runtime:** ${info.runtime} +- **Release notes:** ${info.releaseUrl} + +${upgradeInstructions} + +**Behavior guidelines:** +- Mention the update naturally early in the conversation, but do not interrupt an ongoing task. +- Do not repeat the update reminder if the owner has already acknowledged or dismissed it. +- If the owner agrees to update, proceed with the appropriate upgrade path above. +- After a successful upgrade and restart, confirm the new version is running.`; +} From 054b7c85d73a684b1cdf00f98dd942593e1e9d6d Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Wed, 18 Feb 2026 23:38:27 +0800 Subject: [PATCH 03/37] =?UTF-8?q?=F0=9F=A7=AA=20test:=20add=20comprehensiv?= =?UTF-8?q?e=20tests=20for=20update=20checker=20module?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/tests/update-checker.test.ts | 246 +++++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 packages/core/tests/update-checker.test.ts diff --git a/packages/core/tests/update-checker.test.ts b/packages/core/tests/update-checker.test.ts new file mode 100644 index 0000000..ab49c03 --- /dev/null +++ b/packages/core/tests/update-checker.test.ts @@ -0,0 +1,246 @@ +/** + * Tests for the update checker module. + * + * Validates version comparison, runtime detection, system prompt context + * building, cache I/O, and the main checkForUpdate flow. + */ + +import { describe, expect, test, beforeEach, afterEach } from 'bun:test'; +import { mkdirSync, rmSync, existsSync, readFileSync, writeFileSync } from 'fs'; +import { join } from 'path'; +import { tmpdir } from 'os'; +import { + isNewerVersion, + detectRuntime, + buildUpdateContext, + checkForUpdate, + type UpdateInfo, +} from '../src/update-checker.js'; + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +function createTempDir(suffix: string): string { + const dir = join(tmpdir(), `tinyclaw-update-test-${suffix}-${Date.now()}`); + mkdirSync(join(dir, 'data'), { recursive: true }); + return dir; +} + +function makeMockInfo(overrides: Partial = {}): UpdateInfo { + return { + current: '1.0.0', + latest: '1.1.0', + updateAvailable: true, + runtime: 'npm', + checkedAt: Date.now(), + releaseUrl: 'https://github.com/warengonzaga/tinyclaw/releases/tag/v1.1.0', + ...overrides, + }; +} + +// --------------------------------------------------------------------------- +// isNewerVersion +// --------------------------------------------------------------------------- + +describe('isNewerVersion', () => { + test('detects major bump', () => { + expect(isNewerVersion('1.0.0', '2.0.0')).toBe(true); + }); + + test('detects minor bump', () => { + expect(isNewerVersion('1.0.0', '1.1.0')).toBe(true); + }); + + test('detects patch bump', () => { + expect(isNewerVersion('1.0.0', '1.0.1')).toBe(true); + }); + + test('returns false for same version', () => { + expect(isNewerVersion('1.0.0', '1.0.0')).toBe(false); + }); + + test('returns false for older version', () => { + expect(isNewerVersion('2.0.0', '1.9.9')).toBe(false); + }); + + test('handles v-prefix', () => { + expect(isNewerVersion('v1.0.0', 'v1.0.1')).toBe(true); + }); + + test('handles mixed v-prefix', () => { + expect(isNewerVersion('1.0.0', 'v2.0.0')).toBe(true); + }); + + test('handles double-digit versions', () => { + expect(isNewerVersion('1.9.0', '1.10.0')).toBe(true); + }); +}); + +// --------------------------------------------------------------------------- +// detectRuntime +// --------------------------------------------------------------------------- + +describe('detectRuntime', () => { + const originalEnv = process.env.TINYCLAW_RUNTIME; + + afterEach(() => { + if (originalEnv === undefined) { + delete process.env.TINYCLAW_RUNTIME; + } else { + process.env.TINYCLAW_RUNTIME = originalEnv; + } + }); + + test('returns docker when TINYCLAW_RUNTIME=docker', () => { + process.env.TINYCLAW_RUNTIME = 'docker'; + expect(detectRuntime()).toBe('docker'); + }); + + test('returns source when TINYCLAW_RUNTIME=source', () => { + process.env.TINYCLAW_RUNTIME = 'source'; + expect(detectRuntime()).toBe('source'); + }); + + test('returns npm by default', () => { + delete process.env.TINYCLAW_RUNTIME; + // On a normal dev machine without /.dockerenv, should return npm + const result = detectRuntime(); + expect(result === 'npm' || result === 'docker').toBe(true); + }); + + test('is case-insensitive for env var', () => { + process.env.TINYCLAW_RUNTIME = 'Docker'; + expect(detectRuntime()).toBe('docker'); + }); +}); + +// --------------------------------------------------------------------------- +// buildUpdateContext +// --------------------------------------------------------------------------- + +describe('buildUpdateContext', () => { + test('returns empty string when no update available', () => { + const info = makeMockInfo({ updateAvailable: false }); + expect(buildUpdateContext(info)).toBe(''); + }); + + test('returns empty string for null info', () => { + expect(buildUpdateContext(null)).toBe(''); + }); + + test('includes version info for npm runtime', () => { + const info = makeMockInfo({ runtime: 'npm' }); + const ctx = buildUpdateContext(info); + expect(ctx).toContain('1.0.0'); + expect(ctx).toContain('1.1.0'); + expect(ctx).toContain('bun install -g tinyclaw@latest'); + expect(ctx).toContain('tinyclaw_restart'); + }); + + test('includes docker pull instructions for docker runtime', () => { + const info = makeMockInfo({ runtime: 'docker' }); + const ctx = buildUpdateContext(info); + expect(ctx).toContain('docker pull'); + expect(ctx).toContain('ghcr.io/warengonzaga/tinyclaw'); + expect(ctx).toContain('cannot upgrade yourself directly'); + }); + + test('includes git pull instructions for source runtime', () => { + const info = makeMockInfo({ runtime: 'source' }); + const ctx = buildUpdateContext(info); + expect(ctx).toContain('git pull'); + expect(ctx).toContain('bun run build:packages'); + }); + + test('includes release URL', () => { + const info = makeMockInfo(); + const ctx = buildUpdateContext(info); + expect(ctx).toContain('releases/tag/v1.1.0'); + }); + + test('includes behavior guidelines', () => { + const info = makeMockInfo(); + const ctx = buildUpdateContext(info); + expect(ctx).toContain('do not interrupt'); + expect(ctx).toContain('Do not repeat'); + }); +}); + +// --------------------------------------------------------------------------- +// checkForUpdate — cache behavior +// --------------------------------------------------------------------------- + +describe('checkForUpdate', () => { + let tempDir: string; + + beforeEach(() => { + tempDir = createTempDir('check'); + }); + + afterEach(() => { + try { + rmSync(tempDir, { recursive: true, force: true }); + } catch { + // cleanup best-effort + } + }); + + test('returns cached result if cache is fresh', async () => { + const cached = makeMockInfo({ checkedAt: Date.now() }); + writeFileSync( + join(tempDir, 'data', 'update-check.json'), + JSON.stringify(cached), + ); + + const result = await checkForUpdate('1.0.0', tempDir); + expect(result).not.toBeNull(); + expect(result!.latest).toBe('1.1.0'); + expect(result!.updateAvailable).toBe(true); + }); + + test('re-evaluates updateAvailable against current version', async () => { + // Cache says latest=1.1.0, but we're now running 1.1.0 + const cached = makeMockInfo({ checkedAt: Date.now(), latest: '1.1.0' }); + writeFileSync( + join(tempDir, 'data', 'update-check.json'), + JSON.stringify(cached), + ); + + const result = await checkForUpdate('1.1.0', tempDir); + expect(result).not.toBeNull(); + expect(result!.updateAvailable).toBe(false); + expect(result!.current).toBe('1.1.0'); + }); + + test('returns null on network failure with no cache', async () => { + // No cache file, and registry will naturally fail or return data + // This tests the graceful fallback — should never throw + const result = await checkForUpdate('1.0.0', tempDir); + // Result depends on network availability — just ensure no throw + expect(result === null || typeof result === 'object').toBe(true); + }); + + test('handles corrupt cache file gracefully', async () => { + writeFileSync(join(tempDir, 'data', 'update-check.json'), 'not json!!!'); + + // Should not throw, will attempt fresh fetch + const result = await checkForUpdate('1.0.0', tempDir); + expect(result === null || typeof result === 'object').toBe(true); + }); + + test('creates data dir if missing', async () => { + const freshDir = join(tmpdir(), `tinyclaw-update-nodatadir-${Date.now()}`); + mkdirSync(freshDir, { recursive: true }); + + try { + const result = await checkForUpdate('1.0.0', freshDir); + // If fetch succeeded, cache file should have been written + if (result) { + expect(existsSync(join(freshDir, 'data', 'update-check.json'))).toBe(true); + } + } finally { + rmSync(freshDir, { recursive: true, force: true }); + } + }); +}); From 59c79d9cc2a84ccaf44c56c2e41491da1a4d14f2 Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Wed, 18 Feb 2026 23:38:33 +0800 Subject: [PATCH 04/37] =?UTF-8?q?=F0=9F=93=A6=20new:=20add=20updateContext?= =?UTF-8?q?=20to=20AgentContext=20for=20software=20updates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/types/src/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 757af42..1c804fd 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -191,6 +191,8 @@ export interface AgentContext { getLatestSummary(userId: string): string | null; estimateTokens(text: string): number; }; + /** Pre-built system prompt section about available software updates. */ + updateContext?: string; } // --------------------------------------------------------------------------- From c0a98830a3c8ffb2870139cb7099682ba158388f Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Wed, 18 Feb 2026 23:38:37 +0800 Subject: [PATCH 05/37] =?UTF-8?q?=F0=9F=93=A6=20new:=20add=20software=20up?= =?UTF-8?q?date=20check=20and=20context=20to=20start=20command?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cli/src/commands/start.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/cli/src/commands/start.ts b/src/cli/src/commands/start.ts index 2512958..c2a635c 100644 --- a/src/cli/src/commands/start.ts +++ b/src/cli/src/commands/start.ts @@ -19,6 +19,8 @@ import { DEFAULT_MODEL, DEFAULT_BASE_URL, BUILTIN_MODEL_TAGS, + checkForUpdate, + buildUpdateContext, } from '@tinyclaw/core'; import { loadPlugins } from '@tinyclaw/plugins'; import { createPulseScheduler } from '@tinyclaw/pulse'; @@ -823,6 +825,19 @@ export async function startCommand(): Promise { // Load persisted owner ID (if already claimed) const persistedOwnerId = configManager.get('owner.ownerId'); + // --- Check for software updates (non-blocking) ------------------------- + + let updateContext: string | undefined; + try { + const { getVersion } = await import('../ui/banner.js'); + const currentVersion = getVersion(); + const updateInfo = await checkForUpdate(currentVersion, dataDir); + const ctx = buildUpdateContext(updateInfo); + if (ctx) updateContext = ctx; + } catch (err) { + logger.debug('Update check skipped', err); + } + const context = { db, provider: routerDefaultProvider, @@ -842,6 +857,7 @@ export async function startCommand(): Promise { shield, compactor, ownerId: persistedOwnerId || undefined, + updateContext, }; // --- Initialize pulse scheduler ----------------------------------------- From 9398d214e6be14000aa9ecb94d74bf36ca237978 Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Wed, 18 Feb 2026 23:47:42 +0800 Subject: [PATCH 06/37] =?UTF-8?q?=F0=9F=93=A6=20new:=20update=20package=20?= =?UTF-8?q?versions=20to=201.0.1=20across=20all=20packages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- packages/compactor/package.json | 3 ++- packages/config/package.json | 3 ++- packages/core/package.json | 3 ++- packages/delegation/package.json | 3 ++- packages/heartware/package.json | 3 ++- packages/intercom/package.json | 3 ++- packages/learning/package.json | 3 ++- packages/logger/package.json | 3 ++- packages/matcher/package.json | 3 ++- packages/memory/package.json | 3 ++- packages/plugins/package.json | 2 +- packages/pulse/package.json | 3 ++- packages/queue/package.json | 3 ++- packages/router/package.json | 3 ++- packages/sandbox/package.json | 3 ++- packages/secrets/package.json | 3 ++- packages/shell/package.json | 3 ++- packages/shield/package.json | 3 ++- packages/types/package.json | 2 +- plugins/channel/plugin-channel-discord/package.json | 2 +- plugins/channel/plugin-channel-friends/package.json | 2 +- plugins/provider/plugin-provider-openai/package.json | 2 +- src/cli/package.json | 2 +- src/web/package.json | 2 +- 25 files changed, 42 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index 5a15840..606dbdb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tinyclaw-monorepo", - "version": "1.0.0", + "version": "1.0.1", "description": "Your autonomous AI companion", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/compactor/package.json b/packages/compactor/package.json index cc81485..906bf26 100644 --- a/packages/compactor/package.json +++ b/packages/compactor/package.json @@ -1,6 +1,7 @@ { "name": "@tinyclaw/compactor", - "version": "1.0.0", + "private": true, + "version": "1.0.1", "description": "Layered conversation compaction and token optimization for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/config/package.json b/packages/config/package.json index e2ea3b3..74e7be4 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -1,6 +1,7 @@ { "name": "@tinyclaw/config", - "version": "1.0.0", + "private": true, + "version": "1.0.1", "description": "SQLite-backed persistent configuration for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/core/package.json b/packages/core/package.json index ddc8287..d0f73f9 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,7 @@ { "name": "@tinyclaw/core", - "version": "1.0.0", + "private": true, + "version": "1.0.1", "description": "Core agent runtime for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/delegation/package.json b/packages/delegation/package.json index 49d0f2e..e17bd2a 100644 --- a/packages/delegation/package.json +++ b/packages/delegation/package.json @@ -1,6 +1,7 @@ { "name": "@tinyclaw/delegation", - "version": "1.0.0", + "private": true, + "version": "1.0.1", "description": "Sub-agent delegation and lifecycle management for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/heartware/package.json b/packages/heartware/package.json index b10b7ec..eb0b529 100644 --- a/packages/heartware/package.json +++ b/packages/heartware/package.json @@ -1,6 +1,7 @@ { "name": "@tinyclaw/heartware", - "version": "1.0.0", + "private": true, + "version": "1.0.1", "description": "Personality and self-configuration system for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/intercom/package.json b/packages/intercom/package.json index fc8173f..d0d5a50 100644 --- a/packages/intercom/package.json +++ b/packages/intercom/package.json @@ -1,6 +1,7 @@ { "name": "@tinyclaw/intercom", - "version": "1.0.0", + "private": true, + "version": "1.0.1", "description": "Lightweight pub/sub event bus for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/learning/package.json b/packages/learning/package.json index a35e9a8..af309d4 100644 --- a/packages/learning/package.json +++ b/packages/learning/package.json @@ -1,6 +1,7 @@ { "name": "@tinyclaw/learning", - "version": "1.0.0", + "private": true, + "version": "1.0.1", "description": "Pattern detection and adaptive learning engine for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/logger/package.json b/packages/logger/package.json index 2f37b4d..5d50133 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -1,6 +1,7 @@ { "name": "@tinyclaw/logger", - "version": "1.0.0", + "private": true, + "version": "1.0.1", "description": "Context-aware structured logging for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/matcher/package.json b/packages/matcher/package.json index 401cb9a..eab4fad 100644 --- a/packages/matcher/package.json +++ b/packages/matcher/package.json @@ -1,6 +1,7 @@ { "name": "@tinyclaw/matcher", - "version": "1.0.0", + "private": true, + "version": "1.0.1", "description": "Hybrid semantic text matching engine for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/memory/package.json b/packages/memory/package.json index f84e079..69b1f06 100644 --- a/packages/memory/package.json +++ b/packages/memory/package.json @@ -1,6 +1,7 @@ { "name": "@tinyclaw/memory", - "version": "1.0.0", + "private": true, + "version": "1.0.1", "description": "3-layer adaptive memory with temporal decay for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/plugins/package.json b/packages/plugins/package.json index 1b586ae..cbdae12 100644 --- a/packages/plugins/package.json +++ b/packages/plugins/package.json @@ -1,6 +1,6 @@ { "name": "@tinyclaw/plugins", - "version": "1.0.0", + "version": "1.0.1", "description": "Config-driven plugin loader and validator for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/pulse/package.json b/packages/pulse/package.json index 7a7db1a..4987db0 100644 --- a/packages/pulse/package.json +++ b/packages/pulse/package.json @@ -1,6 +1,7 @@ { "name": "@tinyclaw/pulse", - "version": "1.0.0", + "private": true, + "version": "1.0.1", "description": "Cron-like recurring task scheduler for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/queue/package.json b/packages/queue/package.json index 231660c..7610ae3 100644 --- a/packages/queue/package.json +++ b/packages/queue/package.json @@ -1,6 +1,7 @@ { "name": "@tinyclaw/queue", - "version": "1.0.0", + "private": true, + "version": "1.0.1", "description": "Per-session promise-chain task serialization for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/router/package.json b/packages/router/package.json index 3988a3d..ff9cf13 100644 --- a/packages/router/package.json +++ b/packages/router/package.json @@ -1,6 +1,7 @@ { "name": "@tinyclaw/router", - "version": "1.0.0", + "private": true, + "version": "1.0.1", "description": "Multi-provider LLM routing and query classification for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/sandbox/package.json b/packages/sandbox/package.json index 0dac5e6..9ea4fcd 100644 --- a/packages/sandbox/package.json +++ b/packages/sandbox/package.json @@ -1,6 +1,7 @@ { "name": "@tinyclaw/sandbox", - "version": "1.0.0", + "private": true, + "version": "1.0.1", "description": "Lightweight sandboxed code execution for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/secrets/package.json b/packages/secrets/package.json index d527cb4..e2b4813 100644 --- a/packages/secrets/package.json +++ b/packages/secrets/package.json @@ -1,6 +1,7 @@ { "name": "@tinyclaw/secrets", - "version": "1.0.0", + "private": true, + "version": "1.0.1", "description": "Machine-bound encrypted secrets management for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/shell/package.json b/packages/shell/package.json index bb0e96a..62dfc75 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,7 @@ { "name": "@tinyclaw/shell", - "version": "1.0.0", + "private": true, + "version": "1.0.1", "description": "Controlled shell execution with permission engine for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/shield/package.json b/packages/shield/package.json index 100241f..4dfda5f 100644 --- a/packages/shield/package.json +++ b/packages/shield/package.json @@ -1,6 +1,7 @@ { "name": "@tinyclaw/shield", - "version": "1.0.0", + "private": true, + "version": "1.0.1", "description": "Runtime SHIELD.md threat evaluation and enforcement for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/types/package.json b/packages/types/package.json index 63577c0..fa8e8d4 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@tinyclaw/types", - "version": "1.0.0", + "version": "1.0.1", "description": "Shared TypeScript type definitions for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/plugins/channel/plugin-channel-discord/package.json b/plugins/channel/plugin-channel-discord/package.json index ce7d302..14fb18f 100644 --- a/plugins/channel/plugin-channel-discord/package.json +++ b/plugins/channel/plugin-channel-discord/package.json @@ -1,6 +1,6 @@ { "name": "@tinyclaw/plugin-channel-discord", - "version": "1.0.0", + "version": "1.0.1", "description": "Discord channel plugin for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/plugins/channel/plugin-channel-friends/package.json b/plugins/channel/plugin-channel-friends/package.json index 3c384e8..173a2df 100644 --- a/plugins/channel/plugin-channel-friends/package.json +++ b/plugins/channel/plugin-channel-friends/package.json @@ -1,6 +1,6 @@ { "name": "@tinyclaw/plugin-channel-friends", - "version": "1.0.0", + "version": "1.0.1", "description": "Friends web chat channel plugin for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/plugins/provider/plugin-provider-openai/package.json b/plugins/provider/plugin-provider-openai/package.json index 7530f72..0067ec6 100644 --- a/plugins/provider/plugin-provider-openai/package.json +++ b/plugins/provider/plugin-provider-openai/package.json @@ -1,6 +1,6 @@ { "name": "@tinyclaw/plugin-provider-openai", - "version": "1.0.0", + "version": "1.0.1", "description": "OpenAI provider plugin for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/src/cli/package.json b/src/cli/package.json index 6350d57..f2b6184 100644 --- a/src/cli/package.json +++ b/src/cli/package.json @@ -1,6 +1,6 @@ { "name": "tinyclaw", - "version": "1.0.0", + "version": "1.0.1", "description": "Command-line interface for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/src/web/package.json b/src/web/package.json index a483cd6..5d178ac 100644 --- a/src/web/package.json +++ b/src/web/package.json @@ -1,7 +1,7 @@ { "name": "@tinyclaw/web", "private": true, - "version": "1.0.0", + "version": "1.0.1", "description": "Web user interface for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", From 4e31c8aeba7c9a4e3374c7edefc893c1b1ecac7c Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Thu, 19 Feb 2026 00:06:12 +0800 Subject: [PATCH 07/37] =?UTF-8?q?=E2=9A=99=EF=B8=8F=20setup:=20update=20CI?= =?UTF-8?q?=20workflows=20for=20release=20process=20and=20permissions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 13 +++++++++++++ .github/workflows/container.yml | 2 ++ .github/workflows/package.yml | 2 ++ .github/workflows/release.yml | 14 +------------- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ccc9a39..f95561c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,6 +9,9 @@ on: permissions: contents: read + packages: write + security-events: write + pull-requests: write jobs: build: @@ -50,3 +53,13 @@ jobs: max_attempts: 3 timeout_minutes: 10 command: bun test + + package: + needs: test + uses: ./.github/workflows/package.yml + secrets: inherit + + container: + needs: test + uses: ./.github/workflows/container.yml + secrets: inherit diff --git a/.github/workflows/container.yml b/.github/workflows/container.yml index d999b53..9183ef2 100644 --- a/.github/workflows/container.yml +++ b/.github/workflows/container.yml @@ -3,6 +3,8 @@ name: Container Build on: workflow_call: workflow_dispatch: + release: + types: [published] permissions: contents: read diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index bb337f2..bb93dcf 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -8,6 +8,8 @@ on: description: 'Perform dry run without publishing' type: boolean default: true + release: + types: [published] permissions: contents: read diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2dbd038..1ccb171 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -42,20 +42,8 @@ jobs: echo "changed=false" >> $GITHUB_OUTPUT fi - package: - needs: check-version - if: needs.check-version.outputs.changed == 'true' - uses: ./.github/workflows/package.yml - secrets: inherit - - container: - needs: check-version - if: needs.check-version.outputs.changed == 'true' - uses: ./.github/workflows/container.yml - secrets: inherit - release: - needs: [check-version, package, container] + needs: check-version if: needs.check-version.outputs.changed == 'true' runs-on: ubuntu-latest steps: From 1cd2fcac45abc23d11415506fbb7d57fe5379234 Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Thu, 19 Feb 2026 00:07:12 +0800 Subject: [PATCH 08/37] =?UTF-8?q?=F0=9F=94=A7=20update:=20enhance=20versio?= =?UTF-8?q?n=20parsing=20in=20isNewerVersion=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/src/update-checker.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/core/src/update-checker.ts b/packages/core/src/update-checker.ts index b87a046..851f510 100644 --- a/packages/core/src/update-checker.ts +++ b/packages/core/src/update-checker.ts @@ -93,7 +93,12 @@ export function detectRuntime(): UpdateRuntime { */ export function isNewerVersion(current: string, latest: string): boolean { const parse = (v: string): number[] => - v.replace(/^v/, '').split('.').map(Number).slice(0, 3); + v + .replace(/^v/, '') + .replace(/[-+].*$/, '') + .split('.') + .map((s) => { const n = Number(s); return isNaN(n) ? 0 : n; }) + .slice(0, 3); const [cMaj = 0, cMin = 0, cPat = 0] = parse(current); const [lMaj = 0, lMin = 0, lPat = 0] = parse(latest); if (lMaj !== cMaj) return lMaj > cMaj; From 3f91a71a6959b908d870abc11c647fd522bf0836 Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Thu, 19 Feb 2026 00:15:08 +0800 Subject: [PATCH 09/37] =?UTF-8?q?=F0=9F=93=A6=20new:=20add=20build=20step?= =?UTF-8?q?=20for=20all=20packages=20in=20CI=20workflow?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/package.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index bb93dcf..7411945 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -33,6 +33,9 @@ jobs: - name: Install dependencies run: bun install --frozen-lockfile + - name: Build all packages + run: bun run build + - name: Build & Publish Packages uses: wgtechlabs/package-build-flow-action@v2.0.0 with: From 080224edda299f5a281633f60c93c5b6b8941dfb Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Thu, 19 Feb 2026 14:14:19 +0800 Subject: [PATCH 10/37] =?UTF-8?q?=E2=9A=99=EF=B8=8F=20setup=20(ci):=20upda?= =?UTF-8?q?te=20package-build-flow-action=20to=20v2.0.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index 7411945..cf74eff 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -37,7 +37,7 @@ jobs: run: bun run build - name: Build & Publish Packages - uses: wgtechlabs/package-build-flow-action@v2.0.0 + uses: wgtechlabs/package-build-flow-action@v2.0.1 with: monorepo: 'true' workspace-detection: 'true' From 6e46e613394529dc2aed43d8976b4a79cf5b62d8 Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Thu, 19 Feb 2026 14:20:18 +0800 Subject: [PATCH 11/37] =?UTF-8?q?=E2=9A=99=EF=B8=8F=20setup:=20enforce=20c?= =?UTF-8?q?lean=20commit=20convention=20with=20husky=20and=20ci?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/commit-lint.yml | 54 +++++++++++++++++++++++++++++++ .husky/commit-msg | 43 ++++++++++++++++++++++++ .husky/pre-commit | 1 + bun.lock | 51 +++++++++++++++-------------- package.json | 5 ++- 5 files changed, 129 insertions(+), 25 deletions(-) create mode 100644 .github/workflows/commit-lint.yml create mode 100644 .husky/commit-msg create mode 100644 .husky/pre-commit diff --git a/.github/workflows/commit-lint.yml b/.github/workflows/commit-lint.yml new file mode 100644 index 0000000..3676bb1 --- /dev/null +++ b/.github/workflows/commit-lint.yml @@ -0,0 +1,54 @@ +name: Commit Lint + +on: + pull_request: + branches: [main, dev] + push: + branches: [main, dev] + +permissions: + contents: read + pull-requests: write + +jobs: + lint-commits: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Validate commit messages + run: | + # Clean Commit convention pattern + # Format: [()]: + PATTERN='^(📦|🔧|🗑️|🔒|⚙️|☕|🧪|📖|🚀) (new|update|remove|security|setup|chore|test|docs|release)(\([a-z0-9][a-z0-9-]*\))?: .{1,72}$' + + if [ "${{ github.event_name }}" = "pull_request" ]; then + COMMITS=$(git log --format="%s" ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}) + else + COMMITS=$(git log --format="%s" -1) + fi + + FAILED=0 + while IFS= read -r msg; do + [ -z "$msg" ] && continue + # Allow merge commits + if echo "$msg" | grep -qE "^Merge "; then + continue + fi + if ! echo "$msg" | grep -qP "$PATTERN"; then + echo "✖ Invalid commit message: $msg" + FAILED=1 + else + echo "✔ Valid commit message: $msg" + fi + done <<< "$COMMITS" + + if [ "$FAILED" -eq 1 ]; then + echo "" + echo "One or more commit messages do not follow the Clean Commit convention." + echo "Format: [()]: " + echo "Reference: https://github.com/wgtechlabs/clean-commit" + exit 1 + fi diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100644 index 0000000..ac2676b --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1,43 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +commit_msg=$(cat "$1") + +# Clean Commit convention pattern +# Format: [()]: +# Emojis: 📦 new | 🔧 update | 🗑️ remove | 🔒 security | ⚙️ setup | ☕ chore | 🧪 test | 📖 docs | 🚀 release +pattern='^(📦|🔧|🗑️|🔒|⚙️|☕|🧪|📖|🚀) (new|update|remove|security|setup|chore|test|docs|release)(\([a-z0-9][a-z0-9-]*\))?: .{1,72}$' + +# Allow merge commits +if echo "$commit_msg" | grep -qE "^Merge "; then + exit 0 +fi + +# Validate against Clean Commit pattern (first line only) +first_line=$(echo "$commit_msg" | head -n 1) +if ! echo "$first_line" | grep -qP "$pattern"; then + echo "" + echo "✖ Invalid commit message format." + echo "" + echo " Expected: [()]: " + echo "" + echo " Types and emojis:" + echo " 📦 new – new features, files, or capabilities" + echo " 🔧 update – changes, refactoring, improvements" + echo " 🗑️ remove – removing code, files, or dependencies" + echo " 🔒 security – security fixes or patches" + echo " ⚙️ setup – configs, CI/CD, tooling, build systems" + echo " ☕ chore – maintenance, dependency updates" + echo " 🧪 test – adding or updating tests" + echo " 📖 docs – documentation changes" + echo " 🚀 release – version releases" + echo "" + echo " Examples:" + echo " 📦 new: user authentication system" + echo " 🔧 update (api): improve error handling" + echo " ⚙️ setup (ci): configure github actions workflow" + echo "" + echo " Reference: https://github.com/wgtechlabs/clean-commit" + echo "" + exit 1 +fi diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..4dfead0 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +bun test diff --git a/bun.lock b/bun.lock index ec7912a..79db941 100644 --- a/bun.lock +++ b/bun.lock @@ -10,12 +10,13 @@ "devDependencies": { "@types/bun": "latest", "@types/node": "^22.10.0", + "husky": "^9.1.7", "typescript": "^5.7.0", }, }, "packages/compactor": { "name": "@tinyclaw/compactor", - "version": "1.0.0", + "version": "1.0.1", "dependencies": { "@tinyclaw/logger": "workspace:*", "@tinyclaw/types": "workspace:*", @@ -27,7 +28,7 @@ }, "packages/config": { "name": "@tinyclaw/config", - "version": "1.0.0", + "version": "1.0.1", "dependencies": { "@tinyclaw/core": "workspace:*", "@tinyclaw/logger": "workspace:*", @@ -38,7 +39,7 @@ }, "packages/core": { "name": "@tinyclaw/core", - "version": "1.0.0", + "version": "1.0.1", "dependencies": { "@tinyclaw/delegation": "workspace:*", "@tinyclaw/logger": "workspace:*", @@ -50,7 +51,7 @@ }, "packages/delegation": { "name": "@tinyclaw/delegation", - "version": "1.0.0", + "version": "1.0.1", "dependencies": { "@tinyclaw/logger": "workspace:*", "@tinyclaw/router": "workspace:*", @@ -64,7 +65,7 @@ }, "packages/heartware": { "name": "@tinyclaw/heartware", - "version": "1.0.0", + "version": "1.0.1", "dependencies": { "@tinyclaw/logger": "workspace:*", "@tinyclaw/types": "workspace:*", @@ -72,29 +73,29 @@ }, "packages/intercom": { "name": "@tinyclaw/intercom", - "version": "1.0.0", + "version": "1.0.1", }, "packages/learning": { "name": "@tinyclaw/learning", - "version": "1.0.0", + "version": "1.0.1", "dependencies": { "@tinyclaw/types": "workspace:*", }, }, "packages/logger": { "name": "@tinyclaw/logger", - "version": "1.0.0", + "version": "1.0.1", "dependencies": { "@wgtechlabs/log-engine": "^2.3.0", }, }, "packages/matcher": { "name": "@tinyclaw/matcher", - "version": "1.0.0", + "version": "1.0.1", }, "packages/memory": { "name": "@tinyclaw/memory", - "version": "1.0.0", + "version": "1.0.1", "dependencies": { "@tinyclaw/types": "workspace:*", }, @@ -104,7 +105,7 @@ }, "packages/plugins": { "name": "@tinyclaw/plugins", - "version": "1.0.0", + "version": "1.0.1", "dependencies": { "@tinyclaw/logger": "workspace:*", "@tinyclaw/types": "workspace:*", @@ -112,7 +113,7 @@ }, "packages/pulse": { "name": "@tinyclaw/pulse", - "version": "1.0.0", + "version": "1.0.1", "dependencies": { "@tinyclaw/logger": "workspace:*", "@tinyclaw/types": "workspace:*", @@ -120,11 +121,11 @@ }, "packages/queue": { "name": "@tinyclaw/queue", - "version": "1.0.0", + "version": "1.0.1", }, "packages/router": { "name": "@tinyclaw/router", - "version": "1.0.0", + "version": "1.0.1", "dependencies": { "@tinyclaw/logger": "workspace:*", "@tinyclaw/types": "workspace:*", @@ -132,11 +133,11 @@ }, "packages/sandbox": { "name": "@tinyclaw/sandbox", - "version": "1.0.0", + "version": "1.0.1", }, "packages/secrets": { "name": "@tinyclaw/secrets", - "version": "1.0.0", + "version": "1.0.1", "dependencies": { "@tinyclaw/logger": "workspace:*", "@tinyclaw/types": "workspace:*", @@ -145,7 +146,7 @@ }, "packages/shell": { "name": "@tinyclaw/shell", - "version": "1.0.0", + "version": "1.0.1", "dependencies": { "@tinyclaw/logger": "workspace:*", "@tinyclaw/types": "workspace:*", @@ -153,7 +154,7 @@ }, "packages/shield": { "name": "@tinyclaw/shield", - "version": "1.0.0", + "version": "1.0.1", "dependencies": { "@tinyclaw/logger": "workspace:*", "@tinyclaw/types": "workspace:*", @@ -161,11 +162,11 @@ }, "packages/types": { "name": "@tinyclaw/types", - "version": "1.0.0", + "version": "1.0.1", }, "plugins/channel/plugin-channel-discord": { "name": "@tinyclaw/plugin-channel-discord", - "version": "1.0.0", + "version": "1.0.1", "dependencies": { "@tinyclaw/logger": "workspace:*", "@tinyclaw/types": "workspace:*", @@ -174,7 +175,7 @@ }, "plugins/channel/plugin-channel-friends": { "name": "@tinyclaw/plugin-channel-friends", - "version": "1.0.0", + "version": "1.0.1", "dependencies": { "@tinyclaw/logger": "workspace:*", "@tinyclaw/types": "workspace:*", @@ -182,7 +183,7 @@ }, "plugins/provider/plugin-provider-openai": { "name": "@tinyclaw/plugin-provider-openai", - "version": "1.0.0", + "version": "1.0.1", "dependencies": { "@tinyclaw/logger": "workspace:*", "@tinyclaw/types": "workspace:*", @@ -190,7 +191,7 @@ }, "src/cli": { "name": "tinyclaw", - "version": "1.0.0", + "version": "1.0.1", "bin": { "tinyclaw": "./dist/index.js", }, @@ -228,7 +229,7 @@ }, "src/web": { "name": "@tinyclaw/web", - "version": "1.0.0", + "version": "1.0.1", "dependencies": { "@tinyclaw/core": "workspace:*", "@tinyclaw/heartware": "workspace:*", @@ -553,6 +554,8 @@ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + "husky": ["husky@9.1.7", "", { "bin": { "husky": "bin.js" } }, "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA=="], + "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], "is-reference": ["is-reference@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.6" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="], diff --git a/package.json b/package.json index 606dbdb..531c3d2 100644 --- a/package.json +++ b/package.json @@ -23,11 +23,14 @@ "start": "bun run --cwd src/cli start", "test": "bun test", "cli": "bun run src/cli/src/index.ts", - "dev:purge": "bun run cli purge --force" + "dev:purge": "bun run cli purge --force", + "prepare": "husky", + "prepare": "husky" }, "devDependencies": { "@types/bun": "latest", "@types/node": "^22.10.0", + "husky": "^9.1.7", "typescript": "^5.7.0" }, "dependencies": { From 57d3d0f7a529983615a84169ab173bfd1d96d6d5 Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Thu, 19 Feb 2026 14:25:27 +0800 Subject: [PATCH 12/37] =?UTF-8?q?=E2=9A=99=EF=B8=8F=20setup=20(husky):=20a?= =?UTF-8?q?dd=20clean=20commit=20validation=20hook?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/commit-lint.yml | 2 +- .husky/commit-msg | 42 +------------------------------ .husky/validate-commit-msg.mjs | 40 +++++++++++++++++++++++++++++ package.json | 1 - 4 files changed, 42 insertions(+), 43 deletions(-) create mode 100644 .husky/validate-commit-msg.mjs diff --git a/.github/workflows/commit-lint.yml b/.github/workflows/commit-lint.yml index 3676bb1..bd0587e 100644 --- a/.github/workflows/commit-lint.yml +++ b/.github/workflows/commit-lint.yml @@ -22,7 +22,7 @@ jobs: run: | # Clean Commit convention pattern # Format: [()]: - PATTERN='^(📦|🔧|🗑️|🔒|⚙️|☕|🧪|📖|🚀) (new|update|remove|security|setup|chore|test|docs|release)(\([a-z0-9][a-z0-9-]*\))?: .{1,72}$' + PATTERN='^(📦|🔧|🗑️|🔒|⚙️|☕|🧪|📖|🚀) (new|update|remove|security|setup|chore|test|docs|release)( \([a-z0-9][a-z0-9-]*\))?: .{1,72}$' if [ "${{ github.event_name }}" = "pull_request" ]; then COMMITS=$(git log --format="%s" ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}) diff --git a/.husky/commit-msg b/.husky/commit-msg index ac2676b..d03b211 100644 --- a/.husky/commit-msg +++ b/.husky/commit-msg @@ -1,43 +1,3 @@ #!/bin/sh -. "$(dirname "$0")/_/husky.sh" -commit_msg=$(cat "$1") - -# Clean Commit convention pattern -# Format: [()]: -# Emojis: 📦 new | 🔧 update | 🗑️ remove | 🔒 security | ⚙️ setup | ☕ chore | 🧪 test | 📖 docs | 🚀 release -pattern='^(📦|🔧|🗑️|🔒|⚙️|☕|🧪|📖|🚀) (new|update|remove|security|setup|chore|test|docs|release)(\([a-z0-9][a-z0-9-]*\))?: .{1,72}$' - -# Allow merge commits -if echo "$commit_msg" | grep -qE "^Merge "; then - exit 0 -fi - -# Validate against Clean Commit pattern (first line only) -first_line=$(echo "$commit_msg" | head -n 1) -if ! echo "$first_line" | grep -qP "$pattern"; then - echo "" - echo "✖ Invalid commit message format." - echo "" - echo " Expected: [()]: " - echo "" - echo " Types and emojis:" - echo " 📦 new – new features, files, or capabilities" - echo " 🔧 update – changes, refactoring, improvements" - echo " 🗑️ remove – removing code, files, or dependencies" - echo " 🔒 security – security fixes or patches" - echo " ⚙️ setup – configs, CI/CD, tooling, build systems" - echo " ☕ chore – maintenance, dependency updates" - echo " 🧪 test – adding or updating tests" - echo " 📖 docs – documentation changes" - echo " 🚀 release – version releases" - echo "" - echo " Examples:" - echo " 📦 new: user authentication system" - echo " 🔧 update (api): improve error handling" - echo " ⚙️ setup (ci): configure github actions workflow" - echo "" - echo " Reference: https://github.com/wgtechlabs/clean-commit" - echo "" - exit 1 -fi +bun "$(dirname "$0")/validate-commit-msg.mjs" "$1" diff --git a/.husky/validate-commit-msg.mjs b/.husky/validate-commit-msg.mjs new file mode 100644 index 0000000..791f667 --- /dev/null +++ b/.husky/validate-commit-msg.mjs @@ -0,0 +1,40 @@ +import { readFileSync } from "fs"; + +const msgFile = process.argv[2]; +const raw = readFileSync(msgFile, "utf8"); +const firstLine = raw.replace(/\r/g, "").split("\n")[0].trim(); + +// Allow merge commits +if (/^Merge /.test(firstLine)) process.exit(0); + +// Clean Commit convention pattern +// Format: [()]: +const pattern = + /^(📦|🔧|🗑️|🔒|⚙️|☕|🧪|📖|🚀) (new|update|remove|security|setup|chore|test|docs|release)( \([a-z0-9][a-z0-9-]*\))?: .{1,72}$/u; + +if (!pattern.test(firstLine)) { + console.error(""); + console.error("✖ Invalid commit message format."); + console.error(""); + console.error(" Expected: [()]: "); + console.error(""); + console.error(" Types and emojis:"); + console.error(" 📦 new – new features, files, or capabilities"); + console.error(" 🔧 update – changes, refactoring, improvements"); + console.error(" 🗑️ remove – removing code, files, or dependencies"); + console.error(" 🔒 security – security fixes or patches"); + console.error(" ⚙️ setup – configs, CI/CD, tooling, build systems"); + console.error(" ☕ chore – maintenance, dependency updates"); + console.error(" 🧪 test – adding or updating tests"); + console.error(" 📖 docs – documentation changes"); + console.error(" 🚀 release – version releases"); + console.error(""); + console.error(" Examples:"); + console.error(" 📦 new: user authentication system"); + console.error(" 🔧 update (api): improve error handling"); + console.error(" ⚙️ setup (ci): configure github actions workflow"); + console.error(""); + console.error(" Reference: https://github.com/wgtechlabs/clean-commit"); + console.error(""); + process.exit(1); +} diff --git a/package.json b/package.json index 531c3d2..b298748 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,6 @@ "test": "bun test", "cli": "bun run src/cli/src/index.ts", "dev:purge": "bun run cli purge --force", - "prepare": "husky", "prepare": "husky" }, "devDependencies": { From d71d8659d4e9cbed9581f9ec44ecd26bc682ee75 Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Thu, 19 Feb 2026 15:12:40 +0800 Subject: [PATCH 13/37] =?UTF-8?q?=E2=9A=99=EF=B8=8F=20setup=20(ci):=20fix?= =?UTF-8?q?=20security,=20guards,=20and=20validation=20issues?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - add if-guard to package/container jobs (main push only) - narrow ci.yml top-level permissions to contents: read - add per-job permissions for package and container jobs - remove unused packages/security-events write from release.yml - fix commit-lint push range to validate all commits (before..after) - quote SHA interpolations in commit-lint PR log command - remove duplicate bun run build step from package.yml - add --bail flag to pre-commit bun test hook - add msgFile undefined guard in validate-commit-msg.mjs - make variation selector optional for trash and gear emojis - strengthen readCache to validate latest and runtime field types Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/ci.yml | 12 +++++++++--- .github/workflows/commit-lint.yml | 10 ++++++++-- .github/workflows/package.yml | 3 --- .github/workflows/release.yml | 2 -- .husky/pre-commit | 2 +- .husky/validate-commit-msg.mjs | 6 +++++- packages/core/src/update-checker.ts | 2 +- 7 files changed, 24 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f95561c..5117223 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,9 +9,6 @@ on: permissions: contents: read - packages: write - security-events: write - pull-requests: write jobs: build: @@ -56,10 +53,19 @@ jobs: package: needs: test + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + permissions: + packages: write + pull-requests: write uses: ./.github/workflows/package.yml secrets: inherit container: needs: test + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + permissions: + packages: write + security-events: write + pull-requests: write uses: ./.github/workflows/container.yml secrets: inherit diff --git a/.github/workflows/commit-lint.yml b/.github/workflows/commit-lint.yml index bd0587e..e5ecf1f 100644 --- a/.github/workflows/commit-lint.yml +++ b/.github/workflows/commit-lint.yml @@ -25,9 +25,15 @@ jobs: PATTERN='^(📦|🔧|🗑️|🔒|⚙️|☕|🧪|📖|🚀) (new|update|remove|security|setup|chore|test|docs|release)( \([a-z0-9][a-z0-9-]*\))?: .{1,72}$' if [ "${{ github.event_name }}" = "pull_request" ]; then - COMMITS=$(git log --format="%s" ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}) + COMMITS=$(git log --format="%s" "${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}") else - COMMITS=$(git log --format="%s" -1) + GITHUB_EVENT_BEFORE="${{ github.event.before }}" + GITHUB_EVENT_AFTER="${{ github.event.after }}" + if [ "$GITHUB_EVENT_BEFORE" = "0000000000000000000000000000000000000000" ]; then + COMMITS=$(git log --format="%s" "$GITHUB_EVENT_AFTER" -1) + else + COMMITS=$(git log --format="%s" "${GITHUB_EVENT_BEFORE}..${GITHUB_EVENT_AFTER}") + fi fi FAILED=0 diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index cf74eff..f8bc8d0 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -33,9 +33,6 @@ jobs: - name: Install dependencies run: bun install --frozen-lockfile - - name: Build all packages - run: bun run build - - name: Build & Publish Packages uses: wgtechlabs/package-build-flow-action@v2.0.1 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1ccb171..8d3f8da 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,8 +8,6 @@ on: permissions: contents: write - packages: write - security-events: write pull-requests: write jobs: diff --git a/.husky/pre-commit b/.husky/pre-commit index 4dfead0..b7f861e 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1 +1 @@ -bun test +bun test --bail diff --git a/.husky/validate-commit-msg.mjs b/.husky/validate-commit-msg.mjs index 791f667..6e1811b 100644 --- a/.husky/validate-commit-msg.mjs +++ b/.husky/validate-commit-msg.mjs @@ -1,6 +1,10 @@ import { readFileSync } from "fs"; const msgFile = process.argv[2]; +if (!msgFile) { + console.error("Error: No commit message file path provided."); + process.exit(1); +} const raw = readFileSync(msgFile, "utf8"); const firstLine = raw.replace(/\r/g, "").split("\n")[0].trim(); @@ -10,7 +14,7 @@ if (/^Merge /.test(firstLine)) process.exit(0); // Clean Commit convention pattern // Format: [()]: const pattern = - /^(📦|🔧|🗑️|🔒|⚙️|☕|🧪|📖|🚀) (new|update|remove|security|setup|chore|test|docs|release)( \([a-z0-9][a-z0-9-]*\))?: .{1,72}$/u; + /^(📦|🔧|🗑\uFE0F?|🔒|⚙\uFE0F?|☕|🧪|📖|🚀) (new|update|remove|security|setup|chore|test|docs|release)( \([a-z0-9][a-z0-9-]*\))?: .{1,72}$/u; if (!pattern.test(firstLine)) { console.error(""); diff --git a/packages/core/src/update-checker.ts b/packages/core/src/update-checker.ts index 851f510..8143d4a 100644 --- a/packages/core/src/update-checker.ts +++ b/packages/core/src/update-checker.ts @@ -118,7 +118,7 @@ function readCache(dataDir: string): UpdateInfo | null { try { const raw = readFileSync(getCachePath(dataDir), 'utf-8'); const cached = JSON.parse(raw) as UpdateInfo; - if (cached && typeof cached.checkedAt === 'number') return cached; + if (cached && typeof cached.checkedAt === 'number' && typeof cached.latest === 'string' && typeof cached.runtime === 'string') return cached; } catch { // Missing or corrupt — will re-check } From 0407858ab5b712db7a9bd1ebd911a897fba19502 Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Thu, 19 Feb 2026 15:20:29 +0800 Subject: [PATCH 14/37] =?UTF-8?q?=E2=9A=99=EF=B8=8F=20setup=20(ci):=20remo?= =?UTF-8?q?ve=20redundant=20permissions=20from=20reusable=20workflow=20cal?= =?UTF-8?q?ls?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit permissions are already defined in the called workflows (package.yml, container.yml) - specifying them in the caller causes startup_failure on duplicate runs triggered by open PRs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/ci.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5117223..1915eaf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,18 +54,11 @@ jobs: package: needs: test if: github.event_name == 'push' && github.ref == 'refs/heads/main' - permissions: - packages: write - pull-requests: write uses: ./.github/workflows/package.yml secrets: inherit container: needs: test if: github.event_name == 'push' && github.ref == 'refs/heads/main' - permissions: - packages: write - security-events: write - pull-requests: write uses: ./.github/workflows/container.yml secrets: inherit From a240bb672c872d0330a7ad1781cd9f65bcfac26e Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Thu, 19 Feb 2026 19:44:58 +0800 Subject: [PATCH 15/37] =?UTF-8?q?=F0=9F=94=A7=20update=20(ci):=20handle=20?= =?UTF-8?q?initial=20push=20and=20improve=20update-checker=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - update commit-lint workflow to capture all reachable commits on initial push - improve update-checker test to assert cache file absence when fetch fails Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/commit-lint.yml | 3 ++- packages/core/tests/update-checker.test.ts | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/commit-lint.yml b/.github/workflows/commit-lint.yml index e5ecf1f..f288543 100644 --- a/.github/workflows/commit-lint.yml +++ b/.github/workflows/commit-lint.yml @@ -30,7 +30,8 @@ jobs: GITHUB_EVENT_BEFORE="${{ github.event.before }}" GITHUB_EVENT_AFTER="${{ github.event.after }}" if [ "$GITHUB_EVENT_BEFORE" = "0000000000000000000000000000000000000000" ]; then - COMMITS=$(git log --format="%s" "$GITHUB_EVENT_AFTER" -1) + # Initial push has no valid "before" SHA, so capture all reachable commits + COMMITS=$(git log --format="%s" "$GITHUB_EVENT_AFTER") else COMMITS=$(git log --format="%s" "${GITHUB_EVENT_BEFORE}..${GITHUB_EVENT_AFTER}") fi diff --git a/packages/core/tests/update-checker.test.ts b/packages/core/tests/update-checker.test.ts index ab49c03..92cee78 100644 --- a/packages/core/tests/update-checker.test.ts +++ b/packages/core/tests/update-checker.test.ts @@ -235,9 +235,12 @@ describe('checkForUpdate', () => { try { const result = await checkForUpdate('1.0.0', freshDir); - // If fetch succeeded, cache file should have been written + // If fetch succeeded, cache file should have been written; + // otherwise, the cache file should not exist. if (result) { expect(existsSync(join(freshDir, 'data', 'update-check.json'))).toBe(true); + } else { + expect(existsSync(join(freshDir, 'data', 'update-check.json'))).toBe(false); } } finally { rmSync(freshDir, { recursive: true, force: true }); From 283a0693cd1631bce9485960fc7500d4b549bef1 Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Thu, 19 Feb 2026 22:37:24 +0800 Subject: [PATCH 16/37] =?UTF-8?q?=F0=9F=93=A6=20new=20(landing):=20add=20l?= =?UTF-8?q?anding=20page=20with=20svelte=20and=20tailwindcss?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/landing/README.md | 9 ++ src/landing/index.html | 16 ++++ src/landing/package.json | 23 +++++ src/landing/public/CNAME | 1 + src/landing/src/App.svelte | 48 +++++++++++ src/landing/src/app.css | 68 +++++++++++++++ src/landing/src/components/ComingSoon.svelte | 47 +++++++++++ src/landing/src/components/Features.svelte | 89 ++++++++++++++++++++ src/landing/src/components/Footer.svelte | 80 ++++++++++++++++++ src/landing/src/components/Hero.svelte | 70 +++++++++++++++ src/landing/src/components/QuickStart.svelte | 74 ++++++++++++++++ src/landing/src/main.js | 11 +++ src/landing/tsconfig.json | 10 +++ src/landing/vite.config.ts | 18 ++++ 14 files changed, 564 insertions(+) create mode 100644 src/landing/README.md create mode 100644 src/landing/index.html create mode 100644 src/landing/package.json create mode 100644 src/landing/public/CNAME create mode 100644 src/landing/src/App.svelte create mode 100644 src/landing/src/app.css create mode 100644 src/landing/src/components/ComingSoon.svelte create mode 100644 src/landing/src/components/Features.svelte create mode 100644 src/landing/src/components/Footer.svelte create mode 100644 src/landing/src/components/Hero.svelte create mode 100644 src/landing/src/components/QuickStart.svelte create mode 100644 src/landing/src/main.js create mode 100644 src/landing/tsconfig.json create mode 100644 src/landing/vite.config.ts diff --git a/src/landing/README.md b/src/landing/README.md new file mode 100644 index 0000000..7690a4e --- /dev/null +++ b/src/landing/README.md @@ -0,0 +1,9 @@ +# Tiny Claw Landing Page + +Official landing page for the Tiny Claw project, built with Svelte 5 + Vite + Tailwind CSS. + +## Scripts + +- `bun run dev` — Start development server on port 5174 +- `bun run build` — Build for production +- `bun run preview` — Preview production build diff --git a/src/landing/index.html b/src/landing/index.html new file mode 100644 index 0000000..b4d1899 --- /dev/null +++ b/src/landing/index.html @@ -0,0 +1,16 @@ + + + + + + Tiny Claw — Your Autonomous AI Companion + + + + + + +
+ + + diff --git a/src/landing/package.json b/src/landing/package.json new file mode 100644 index 0000000..7ee2179 --- /dev/null +++ b/src/landing/package.json @@ -0,0 +1,23 @@ +{ + "name": "@tinyclaw/landing", + "private": true, + "version": "1.0.1", + "description": "Official landing page for Tiny Claw", + "license": "GPL-3.0", + "author": "Waren Gonzaga", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "svelte": "^5.20.1" + }, + "devDependencies": { + "@sveltejs/vite-plugin-svelte": "^6.1.4", + "@tailwindcss/vite": "^4.1.18", + "tailwindcss": "^4.1.18", + "vite": "^7.2.4" + } +} diff --git a/src/landing/public/CNAME b/src/landing/public/CNAME new file mode 100644 index 0000000..e87adda --- /dev/null +++ b/src/landing/public/CNAME @@ -0,0 +1 @@ +tinyclaw.ai diff --git a/src/landing/src/App.svelte b/src/landing/src/App.svelte new file mode 100644 index 0000000..660b8d5 --- /dev/null +++ b/src/landing/src/App.svelte @@ -0,0 +1,48 @@ + + +
+ + +
+ + + +
+ +
+
diff --git a/src/landing/src/app.css b/src/landing/src/app.css new file mode 100644 index 0000000..37899cd --- /dev/null +++ b/src/landing/src/app.css @@ -0,0 +1,68 @@ +@import "tailwindcss"; + +@theme { + /* Ant Colony theme — dark, earthy tones */ + --color-bg-primary: #0a0a0a; + --color-bg-secondary: #111111; + --color-bg-tertiary: #171717; + --color-bg-card: #141414; + --color-bg-card-hover: #1a1a1a; + --color-bg-code: #1e1e1e; + + --color-text-normal: #e0e0e0; + --color-text-muted: #8a8a8a; + --color-text-link: #c98540; + + --color-brand: #8b5a2b; + --color-brand-hover: #a06830; + --color-brand-light: #c98540; + --color-accent-green: #7ab648; + --color-accent-yellow: #c49530; + + --color-border: #222222; + --color-border-hover: #333333; + + --color-gradient-start: #8b5a2b; + --color-gradient-end: #c98540; +} + +* { + box-sizing: border-box; +} + +html { + scroll-behavior: smooth; +} + +html, body { + margin: 0; + padding: 0; + background-color: var(--color-bg-primary); + color: var(--color-text-normal); + font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; + font-size: 16px; + line-height: 1.6; + -webkit-font-smoothing: antialiased; +} + +#app { + min-height: 100vh; +} + +/* Custom scrollbar */ +::-webkit-scrollbar { + width: 8px; +} + +::-webkit-scrollbar-track { + background: transparent; +} + +::-webkit-scrollbar-thumb { + background: #262626; + border-radius: 4px; +} + +::-webkit-scrollbar-thumb:hover { + background: #444; +} diff --git a/src/landing/src/components/ComingSoon.svelte b/src/landing/src/components/ComingSoon.svelte new file mode 100644 index 0000000..0d3d2ea --- /dev/null +++ b/src/landing/src/components/ComingSoon.svelte @@ -0,0 +1,47 @@ +
+
+ +

+ Coming Soon +

+

+ Tiny Claw is under heavy development. We're building something special and want to get it right before the first official release. +

+ + +
+ +

Under Active Development

+

+ Running it now may spoil the experience we're building for you. Follow us for launch updates and be the first to know when Tiny Claw is ready. +

+ + + +
+ + +

+ Want to get involved? Check out the contributing guide or sponsor the project. +

+
+
diff --git a/src/landing/src/components/Features.svelte b/src/landing/src/components/Features.svelte new file mode 100644 index 0000000..0eee0b5 --- /dev/null +++ b/src/landing/src/components/Features.svelte @@ -0,0 +1,89 @@ + + +
+
+ +
+

+ Packed with Power +

+

+ A single ant is tiny, but it's autonomous, it learns, it adapts, and it builds something greater over time. +

+
+ + +
+ {#each features as feature} +
+
{feature.emoji}
+

{feature.title}

+

{feature.description}

+
+ {/each} +
+
+
diff --git a/src/landing/src/components/Footer.svelte b/src/landing/src/components/Footer.svelte new file mode 100644 index 0000000..bbd1cba --- /dev/null +++ b/src/landing/src/components/Footer.svelte @@ -0,0 +1,80 @@ + diff --git a/src/landing/src/components/Hero.svelte b/src/landing/src/components/Hero.svelte new file mode 100644 index 0000000..f163adc --- /dev/null +++ b/src/landing/src/components/Hero.svelte @@ -0,0 +1,70 @@ +
+ + + +
+ +
+ + Under Active Development +
+ + + + + +

+ Tiny Claw +
+ Your Autonomous AI Companion +

+ + +

+ A personal, self-improving, self-learning AI companion built from scratch. + Small by design, mighty by nature. +

+ + + + + +
+
+
Native
+
Built from scratch
+
+
+
Tiny
+
Core stays minimal
+
+
+
Smart
+
Self-improving AI
+
+
+
Free
+
Open source
+
+
+
+
diff --git a/src/landing/src/components/QuickStart.svelte b/src/landing/src/components/QuickStart.svelte new file mode 100644 index 0000000..196e70f --- /dev/null +++ b/src/landing/src/components/QuickStart.svelte @@ -0,0 +1,74 @@ +
+
+ +
+

+ Quick Start +

+

+ Up and running in under a minute. No config files needed — Tiny Claw walks you through the rest. +

+
+ + +
+ +
+
+
1
+
+
+

Install

+
+ $ bun install +
+
+
+ + +
+
+
2
+
+
+

Run

+
+ $ bun start +
+
+
+ + +
+
+
3
+
+
+

Open

+

+ Visit http://localhost:3000 and Tiny Claw will walk you through setup. No config files needed. +

+
+
+
+ + +
+

Development

+
+
+
bun dev
+ Development mode with hot reload +
+
+
bun build
+ Build all packages +
+
+
bun test
+ Run the test suite +
+
+
+
+
diff --git a/src/landing/src/main.js b/src/landing/src/main.js new file mode 100644 index 0000000..8a8e537 --- /dev/null +++ b/src/landing/src/main.js @@ -0,0 +1,11 @@ +import './app.css' +import { mount } from 'svelte' +import App from './App.svelte' + +const target = document.getElementById('app') + +if (!target) { + throw new Error('Landing page failed to find #app root element.') +} + +mount(App, { target }) diff --git a/src/landing/tsconfig.json b/src/landing/tsconfig.json new file mode 100644 index 0000000..7d32988 --- /dev/null +++ b/src/landing/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "bundler", + "verbatimModuleSyntax": true + }, + "include": ["src/**/*.ts", "src/**/*.svelte"] +} diff --git a/src/landing/vite.config.ts b/src/landing/vite.config.ts new file mode 100644 index 0000000..2db8baf --- /dev/null +++ b/src/landing/vite.config.ts @@ -0,0 +1,18 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' +import { resolve } from 'path' + +export default defineConfig({ + plugins: [svelte(), tailwindcss()], + build: { + rollupOptions: { + input: { + main: resolve(__dirname, 'index.html'), + }, + }, + }, + server: { + port: 5174, + }, +}) From cbe57e2f0debfb118cfac3f2f83e4d5da4bb5787 Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Thu, 19 Feb 2026 22:37:37 +0800 Subject: [PATCH 17/37] =?UTF-8?q?=E2=9A=99=EF=B8=8F=20setup=20(ci):=20add?= =?UTF-8?q?=20deploy=20workflow=20for=20landing=20page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/landing.yml | 49 +++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 .github/workflows/landing.yml diff --git a/.github/workflows/landing.yml b/.github/workflows/landing.yml new file mode 100644 index 0000000..f72d924 --- /dev/null +++ b/.github/workflows/landing.yml @@ -0,0 +1,49 @@ +name: Deploy Landing Page + +on: + push: + branches: [main] + paths: + - 'src/landing/**' + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - name: Install dependencies + run: bun install + + - name: Build landing page + run: bun run --cwd src/landing build + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: src/landing/dist + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 From 01135d604202e466345840d437d485f50c9e80ee Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Thu, 19 Feb 2026 22:37:47 +0800 Subject: [PATCH 18/37] =?UTF-8?q?=E2=9A=99=EF=B8=8F=20setup=20(landing):?= =?UTF-8?q?=20add=20build:landing=20script=20and=20update=20lockfile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- bun.lock | 15 +++++++++++++++ package.json | 1 + 2 files changed, 16 insertions(+) diff --git a/bun.lock b/bun.lock index 79db941..6219459 100644 --- a/bun.lock +++ b/bun.lock @@ -227,6 +227,19 @@ "@types/qrcode": "^1.5.6", }, }, + "src/landing": { + "name": "@tinyclaw/landing", + "version": "1.0.1", + "dependencies": { + "svelte": "^5.20.1", + }, + "devDependencies": { + "@sveltejs/vite-plugin-svelte": "^6.1.4", + "@tailwindcss/vite": "^4.1.18", + "tailwindcss": "^4.1.18", + "vite": "^7.2.4", + }, + }, "src/web": { "name": "@tinyclaw/web", "version": "1.0.1", @@ -434,6 +447,8 @@ "@tinyclaw/intercom": ["@tinyclaw/intercom@workspace:packages/intercom"], + "@tinyclaw/landing": ["@tinyclaw/landing@workspace:src/landing"], + "@tinyclaw/learning": ["@tinyclaw/learning@workspace:packages/learning"], "@tinyclaw/logger": ["@tinyclaw/logger@workspace:packages/logger"], diff --git a/package.json b/package.json index b298748..029ea2a 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "build:plugins": "bun run --filter './plugins/**/*' build", "build:apps": "bun run --cwd src/web build && bun run --cwd src/cli build", "build:ui": "bun run --cwd src/web build", + "build:landing": "bun run --cwd src/landing build", "build:all": "bun run build:packages && bun run build:plugins && bun run build:apps", "start": "bun run --cwd src/cli start", "test": "bun test", From af268be1d1c891864c1e24ad52d927c970fddc2d Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Thu, 19 Feb 2026 23:01:54 +0800 Subject: [PATCH 19/37] =?UTF-8?q?=E2=9A=99=EF=B8=8F=20setup=20(husky):=20a?= =?UTF-8?q?dd=20error=20handling=20and=20allow=20revert=20commits?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .husky/validate-commit-msg.mjs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/.husky/validate-commit-msg.mjs b/.husky/validate-commit-msg.mjs index 6e1811b..ba81a53 100644 --- a/.husky/validate-commit-msg.mjs +++ b/.husky/validate-commit-msg.mjs @@ -5,11 +5,19 @@ if (!msgFile) { console.error("Error: No commit message file path provided."); process.exit(1); } -const raw = readFileSync(msgFile, "utf8"); +let raw; +try { + raw = readFileSync(msgFile, "utf8"); +} catch (err) { + console.error( + `Error: Could not read commit message file "${msgFile}": ${err.message}`, + ); + process.exit(1); +} const firstLine = raw.replace(/\r/g, "").split("\n")[0].trim(); -// Allow merge commits -if (/^Merge /.test(firstLine)) process.exit(0); +// Allow merge and revert commits +if (/^Merge /.test(firstLine) || /^Revert /.test(firstLine)) process.exit(0); // Clean Commit convention pattern // Format: [()]: From cf70b8573161f865f17b851514c52bc8677316d7 Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Thu, 19 Feb 2026 23:30:12 +0800 Subject: [PATCH 20/37] =?UTF-8?q?=F0=9F=94=92=20security=20(update-checker?= =?UTF-8?q?):=20sanitize=20version=20and=20url=20for=20prompt=20injection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- packages/core/src/update-checker.ts | 47 +++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/packages/core/src/update-checker.ts b/packages/core/src/update-checker.ts index 8143d4a..6810497 100644 --- a/packages/core/src/update-checker.ts +++ b/packages/core/src/update-checker.ts @@ -86,6 +86,33 @@ export function detectRuntime(): UpdateRuntime { // Semver comparison (minimal — avoids pulling a full semver library) // --------------------------------------------------------------------------- +/** Matches a semver-like version string (with optional v-prefix). */ +const SEMVER_RE = /^v?\d+\.\d+\.\d+/; + +/** Matches a safe HTTPS URL. */ +const SAFE_URL_RE = /^https?:\/\/[^\s]+$/; + +/** + * Sanitize a string for safe interpolation into a system prompt. + * Validates against an expected pattern and strips characters that could + * be used for prompt injection (newlines, backticks, markdown markers). + */ +export function sanitizeForPrompt( + value: string, + kind: 'version' | 'url', +): string { + const trimmed = value.trim(); + if (kind === 'version') { + if (!SEMVER_RE.test(trimmed)) return 'unknown'; + // Strip everything after the patch number to remove injected text + return trimmed.replace(/^(v?\d+\.\d+\.\d+)[\s\S]*$/, '$1'); + } + // kind === 'url' + if (!SAFE_URL_RE.test(trimmed)) return '(unavailable)'; + // Remove characters that could break prompt formatting + return trimmed.replace(/[`\n\r\[\](){}#*_~>|]/g, ''); +} + /** * Compare two semver strings. Returns true when `latest` is strictly newer * than `current`. Only handles `MAJOR.MINOR.PATCH`; pre-release suffixes @@ -192,7 +219,18 @@ export async function checkForUpdate( // Fetch latest version from npm const latest = await fetchLatestVersion(); - if (!latest) return cached ?? null; // Network failure — use stale cache if available + if (!latest) { + // Network failure — use stale cache if available, but recompute + // against the caller-supplied currentVersion + if (cached) { + return { + ...cached, + current: currentVersion, + updateAvailable: isNewerVersion(currentVersion, cached.latest), + }; + } + return null; + } const runtime = detectRuntime(); const info: UpdateInfo = { @@ -228,6 +266,9 @@ export async function checkForUpdate( export function buildUpdateContext(info: UpdateInfo | null): string { if (!info?.updateAvailable) return ''; + const safeLatest = sanitizeForPrompt(info.latest, 'version'); + const safeReleaseUrl = sanitizeForPrompt(info.releaseUrl, 'url'); + const upgradeInstructions = info.runtime === 'npm' ? `Since you are running as an npm global install, you can upgrade yourself using the shell tool: @@ -246,9 +287,9 @@ Then restart using the tinyclaw_restart tool.`; ## Software Update Available - **Current version:** ${info.current} -- **Latest version:** ${info.latest} +- **Latest version:** ${safeLatest} - **Runtime:** ${info.runtime} -- **Release notes:** ${info.releaseUrl} +- **Release notes:** ${safeReleaseUrl} ${upgradeInstructions} From 7094636284fbe1207139c48de184357d8ad7e3a1 Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Thu, 19 Feb 2026 23:31:59 +0800 Subject: [PATCH 21/37] =?UTF-8?q?=F0=9F=A7=AA=20test=20(update-checker):?= =?UTF-8?q?=20add=20sanitizeForPrompt=20tests=20and=20improve=20mocking?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- packages/core/tests/update-checker.test.ts | 72 ++++++++++++++++++---- 1 file changed, 59 insertions(+), 13 deletions(-) diff --git a/packages/core/tests/update-checker.test.ts b/packages/core/tests/update-checker.test.ts index 92cee78..1b4a909 100644 --- a/packages/core/tests/update-checker.test.ts +++ b/packages/core/tests/update-checker.test.ts @@ -14,6 +14,7 @@ import { detectRuntime, buildUpdateContext, checkForUpdate, + sanitizeForPrompt, type UpdateInfo, } from '../src/update-checker.js'; @@ -173,12 +174,16 @@ describe('buildUpdateContext', () => { describe('checkForUpdate', () => { let tempDir: string; + const originalFetch = globalThis.fetch; beforeEach(() => { tempDir = createTempDir('check'); + // Default mock: simulate network failure so tests are deterministic + globalThis.fetch = (() => Promise.reject(new Error('mock network failure'))) as typeof fetch; }); afterEach(() => { + globalThis.fetch = originalFetch; try { rmSync(tempDir, { recursive: true, force: true }); } catch { @@ -214,36 +219,77 @@ describe('checkForUpdate', () => { }); test('returns null on network failure with no cache', async () => { - // No cache file, and registry will naturally fail or return data - // This tests the graceful fallback — should never throw + // No cache file, fetch mock rejects — should return null const result = await checkForUpdate('1.0.0', tempDir); - // Result depends on network availability — just ensure no throw - expect(result === null || typeof result === 'object').toBe(true); + expect(result).toBeNull(); }); test('handles corrupt cache file gracefully', async () => { writeFileSync(join(tempDir, 'data', 'update-check.json'), 'not json!!!'); - // Should not throw, will attempt fresh fetch + // Corrupt cache is unreadable and fetch mock rejects — should return null const result = await checkForUpdate('1.0.0', tempDir); - expect(result === null || typeof result === 'object').toBe(true); + expect(result).toBeNull(); }); test('creates data dir if missing', async () => { const freshDir = join(tmpdir(), `tinyclaw-update-nodatadir-${Date.now()}`); mkdirSync(freshDir, { recursive: true }); + // Mock a successful fetch so cache gets written + globalThis.fetch = (() => + Promise.resolve( + new Response(JSON.stringify({ version: '1.1.0' }), { + status: 200, + headers: { 'Content-Type': 'application/json' }, + }), + )) as typeof fetch; + try { const result = await checkForUpdate('1.0.0', freshDir); - // If fetch succeeded, cache file should have been written; - // otherwise, the cache file should not exist. - if (result) { - expect(existsSync(join(freshDir, 'data', 'update-check.json'))).toBe(true); - } else { - expect(existsSync(join(freshDir, 'data', 'update-check.json'))).toBe(false); - } + expect(result).not.toBeNull(); + expect(existsSync(join(freshDir, 'data', 'update-check.json'))).toBe(true); } finally { rmSync(freshDir, { recursive: true, force: true }); } }); }); + +// --------------------------------------------------------------------------- +// sanitizeForPrompt +// --------------------------------------------------------------------------- + +describe('sanitizeForPrompt', () => { + test('accepts valid semver version', () => { + expect(sanitizeForPrompt('1.2.3', 'version')).toBe('1.2.3'); + }); + + test('accepts v-prefixed version', () => { + expect(sanitizeForPrompt('v1.2.3', 'version')).toBe('v1.2.3'); + }); + + test('strips trailing garbage from version', () => { + expect(sanitizeForPrompt('1.2.3-evil\nprompt', 'version')).toBe('1.2.3'); + }); + + test('returns unknown for non-semver version', () => { + expect(sanitizeForPrompt('not-a-version', 'version')).toBe('unknown'); + }); + + test('accepts valid https URL', () => { + const url = 'https://github.com/warengonzaga/tinyclaw/releases/tag/v1.0.0'; + expect(sanitizeForPrompt(url, 'url')).toBe( + 'https://github.com/warengonzaga/tinyclaw/releases/tag/v1.0.0', + ); + }); + + test('returns unavailable for non-http URL', () => { + expect(sanitizeForPrompt('javascript:alert(1)', 'url')).toBe('(unavailable)'); + }); + + test('strips markdown/injection characters from URL', () => { + const url = 'https://example.com/path`injection`'; + const result = sanitizeForPrompt(url, 'url'); + expect(result).not.toContain('`'); + }); +}); From 858ff22968c04a191da6158e1e9a16da64b32266 Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Thu, 19 Feb 2026 23:53:23 +0800 Subject: [PATCH 22/37] =?UTF-8?q?=E2=9A=99=EF=B8=8F=20setup=20(ci):=20pin?= =?UTF-8?q?=20action=20shas=20and=20scope=20deploy=20permissions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - pin all GitHub Actions to full commit SHAs for supply chain security - move pages/id-token permissions to deploy job only - pin bun version to 1.2.x and use --frozen-lockfile - use dynamic concurrency group name with workflow prefix Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/landing.yml | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/.github/workflows/landing.yml b/.github/workflows/landing.yml index f72d924..d3fe727 100644 --- a/.github/workflows/landing.yml +++ b/.github/workflows/landing.yml @@ -9,41 +9,42 @@ on: permissions: contents: read - pages: write - id-token: write concurrency: - group: pages + group: ${{ github.workflow }}-pages cancel-in-progress: true jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - - uses: oven-sh/setup-bun@v2 + - uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2 with: - bun-version: latest + bun-version: 1.2.x - name: Install dependencies - run: bun install + run: bun install --frozen-lockfile - name: Build landing page run: bun run --cwd src/landing build - name: Upload artifact - uses: actions/upload-pages-artifact@v3 + uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3 with: path: src/landing/dist deploy: needs: build runs-on: ubuntu-latest + permissions: + pages: write + id-token: write environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4 + uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4 From a5c13059b612d4ac05a6cf1518e0e75d517138a5 Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Thu, 19 Feb 2026 23:54:07 +0800 Subject: [PATCH 23/37] =?UTF-8?q?=F0=9F=94=92=20security=20(core):=20harde?= =?UTF-8?q?n=20update=20checker=20cache=20and=20fetch=20logic?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - validate runtime value against allowed list when reading cache - sanitize current version before embedding in prompt context - move AbortController setup outside try block and use finally to clear timeout Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- packages/core/src/update-checker.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/core/src/update-checker.ts b/packages/core/src/update-checker.ts index 6810497..6ecc7ce 100644 --- a/packages/core/src/update-checker.ts +++ b/packages/core/src/update-checker.ts @@ -145,7 +145,8 @@ function readCache(dataDir: string): UpdateInfo | null { try { const raw = readFileSync(getCachePath(dataDir), 'utf-8'); const cached = JSON.parse(raw) as UpdateInfo; - if (cached && typeof cached.checkedAt === 'number' && typeof cached.latest === 'string' && typeof cached.runtime === 'string') return cached; + const validRuntimes: UpdateRuntime[] = ['npm', 'docker', 'source']; + if (cached && typeof cached.checkedAt === 'number' && typeof cached.latest === 'string' && validRuntimes.includes(cached.runtime as UpdateRuntime)) return cached; } catch { // Missing or corrupt — will re-check } @@ -155,7 +156,7 @@ function readCache(dataDir: string): UpdateInfo | null { function writeCache(dataDir: string, info: UpdateInfo): void { try { const dir = join(dataDir, 'data'); - if (!existsSync(dir)) mkdirSync(dir, { recursive: true }); + mkdirSync(dir, { recursive: true }); writeFileSync(getCachePath(dataDir), JSON.stringify(info, null, 2), 'utf-8'); } catch (err) { logger.debug('Failed to write update cache', err); @@ -167,15 +168,13 @@ function writeCache(dataDir: string, info: UpdateInfo): void { // --------------------------------------------------------------------------- async function fetchLatestVersion(): Promise { + const controller = new AbortController(); + const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS); try { - const controller = new AbortController(); - const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS); - const res = await fetch(NPM_REGISTRY_URL, { signal: controller.signal, headers: { Accept: 'application/json' }, }); - clearTimeout(timeout); if (!res.ok) return null; const data = (await res.json()) as { version?: string }; @@ -183,6 +182,8 @@ async function fetchLatestVersion(): Promise { } catch { // Network error, timeout, or offline — silently return null return null; + } finally { + clearTimeout(timeout); } } @@ -266,6 +267,7 @@ export async function checkForUpdate( export function buildUpdateContext(info: UpdateInfo | null): string { if (!info?.updateAvailable) return ''; + const safeCurrent = sanitizeForPrompt(info.current, 'version'); const safeLatest = sanitizeForPrompt(info.latest, 'version'); const safeReleaseUrl = sanitizeForPrompt(info.releaseUrl, 'url'); @@ -286,7 +288,7 @@ Then restart using the tinyclaw_restart tool.`; return ` ## Software Update Available -- **Current version:** ${info.current} +- **Current version:** ${safeCurrent} - **Latest version:** ${safeLatest} - **Runtime:** ${info.runtime} - **Release notes:** ${safeReleaseUrl} From ea45a35033319e1c9f1823a0f26df076bde7405e Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Thu, 19 Feb 2026 23:54:54 +0800 Subject: [PATCH 24/37] =?UTF-8?q?=F0=9F=93=A6=20new=20(landing):=20extract?= =?UTF-8?q?=20GitHubIcon=20component=20and=20improve=20accessibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - add reusable GitHubIcon Svelte component to replace inline SVG duplication - add skip-to-main-content link for keyboard navigation - add aria-label to primary nav element - add aria-hidden to decorative SVG icons Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/landing/src/App.svelte | 10 ++++++---- src/landing/src/components/Hero.svelte | 4 ++-- src/landing/src/components/icons/GitHubIcon.svelte | 6 ++++++ 3 files changed, 14 insertions(+), 6 deletions(-) create mode 100644 src/landing/src/components/icons/GitHubIcon.svelte diff --git a/src/landing/src/App.svelte b/src/landing/src/App.svelte index 660b8d5..ed287af 100644 --- a/src/landing/src/App.svelte +++ b/src/landing/src/App.svelte @@ -3,10 +3,12 @@ import Features from './components/Features.svelte' import ComingSoon from './components/ComingSoon.svelte' import Footer from './components/Footer.svelte' + import GitHubIcon from './components/icons/GitHubIcon.svelte'
-
-
+
diff --git a/src/landing/src/components/Hero.svelte b/src/landing/src/components/Hero.svelte index f163adc..3c2eb4e 100644 --- a/src/landing/src/components/Hero.svelte +++ b/src/landing/src/components/Hero.svelte @@ -34,7 +34,7 @@ class="inline-flex items-center gap-2 rounded-xl bg-brand px-7 py-3 text-base font-semibold text-white no-underline shadow-lg shadow-brand/20 transition-all hover:bg-brand-hover hover:shadow-brand/30 hover:-translate-y-0.5" > Stay Updated - + - + View on GitHub diff --git a/src/landing/src/components/icons/GitHubIcon.svelte b/src/landing/src/components/icons/GitHubIcon.svelte new file mode 100644 index 0000000..dcddd4d --- /dev/null +++ b/src/landing/src/components/icons/GitHubIcon.svelte @@ -0,0 +1,6 @@ + + + From c142513612cce8de8db227c06a48e90feaf30293 Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Thu, 19 Feb 2026 23:55:43 +0800 Subject: [PATCH 25/37] =?UTF-8?q?=F0=9F=94=A7=20update=20(landing):=20impr?= =?UTF-8?q?ove=20scrollbar=20styling=20and=20Firefox=20support?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - add scrollbar-width and scrollbar-color for Firefox compatibility - use CSS variable for scrollbar thumb hover color - remove quoted font family name for Inter Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/landing/src/app.css | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/landing/src/app.css b/src/landing/src/app.css index 37899cd..23147d4 100644 --- a/src/landing/src/app.css +++ b/src/landing/src/app.css @@ -39,7 +39,7 @@ html, body { padding: 0; background-color: var(--color-bg-primary); color: var(--color-text-normal); - font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; + font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; font-size: 16px; line-height: 1.6; -webkit-font-smoothing: antialiased; @@ -50,6 +50,11 @@ html, body { } /* Custom scrollbar */ +* { + scrollbar-width: thin; + scrollbar-color: #262626 transparent; +} + ::-webkit-scrollbar { width: 8px; } @@ -64,5 +69,5 @@ html, body { } ::-webkit-scrollbar-thumb:hover { - background: #444; + background: var(--color-border-hover); } From 302f44b0e0735f964040f57db51125de90dad8ed Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Thu, 19 Feb 2026 23:56:27 +0800 Subject: [PATCH 26/37] =?UTF-8?q?=F0=9F=94=A7=20update=20(landing):=20clar?= =?UTF-8?q?ify=20QuickStart=20step=203=20description?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/landing/src/components/QuickStart.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/landing/src/components/QuickStart.svelte b/src/landing/src/components/QuickStart.svelte index 196e70f..9d4ac55 100644 --- a/src/landing/src/components/QuickStart.svelte +++ b/src/landing/src/components/QuickStart.svelte @@ -46,7 +46,7 @@

Open

- Visit http://localhost:3000 and Tiny Claw will walk you through setup. No config files needed. + Visit http://localhost:3000 and Tiny Claw will guide you through the initial setup interactively.

From 99c228aaae2090149713a3d8543f480d7cc044fe Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Fri, 20 Feb 2026 00:17:21 +0800 Subject: [PATCH 27/37] =?UTF-8?q?=E2=9A=99=EF=B8=8F=20setup=20(ci):=20stre?= =?UTF-8?q?amline=20CI=20workflows=20by=20removing=20unused=20jobs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 12 ------------ .github/workflows/container.yml | 4 ++++ .github/workflows/package.yml | 4 ++++ 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1915eaf..ccc9a39 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,15 +50,3 @@ jobs: max_attempts: 3 timeout_minutes: 10 command: bun test - - package: - needs: test - if: github.event_name == 'push' && github.ref == 'refs/heads/main' - uses: ./.github/workflows/package.yml - secrets: inherit - - container: - needs: test - if: github.event_name == 'push' && github.ref == 'refs/heads/main' - uses: ./.github/workflows/container.yml - secrets: inherit diff --git a/.github/workflows/container.yml b/.github/workflows/container.yml index 9183ef2..90e74ed 100644 --- a/.github/workflows/container.yml +++ b/.github/workflows/container.yml @@ -1,6 +1,10 @@ name: Container Build on: + pull_request: + branches: [main, dev] + push: + branches: [main, dev] workflow_call: workflow_dispatch: release: diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index f8bc8d0..2e8037f 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -1,6 +1,10 @@ name: Package Build on: + pull_request: + branches: [main, dev] + push: + branches: [main, dev] workflow_call: workflow_dispatch: inputs: From bab10e0b8931f0c3065a2bd8c1e5aedb8d5ece42 Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Fri, 20 Feb 2026 00:17:39 +0800 Subject: [PATCH 28/37] =?UTF-8?q?=F0=9F=97=91=EF=B8=8F=20remove:=20delete?= =?UTF-8?q?=20pre-commit=20script=20for=20bun=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .husky/pre-commit | 1 - 1 file changed, 1 deletion(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index b7f861e..e69de29 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1 +0,0 @@ -bun test --bail From 3004a38efef29f2b31ff23e5421ef600127225ac Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Fri, 20 Feb 2026 00:20:34 +0800 Subject: [PATCH 29/37] =?UTF-8?q?=F0=9F=94=A7=20update=20(ci):=20add=20bui?= =?UTF-8?q?ld=20step=20for=20workspace=20packages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/package.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index 2e8037f..01fbe1d 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -37,6 +37,9 @@ jobs: - name: Install dependencies run: bun install --frozen-lockfile + - name: Build workspace packages + run: bun run build:packages + - name: Build & Publish Packages uses: wgtechlabs/package-build-flow-action@v2.0.1 with: From 67f0a767f839d95dc502b00b0b06b70f39ef86ae Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Fri, 20 Feb 2026 00:25:01 +0800 Subject: [PATCH 30/37] =?UTF-8?q?=F0=9F=94=A7=20update=20(dockerfile):=20u?= =?UTF-8?q?pgrade=20bun=20version=20for=20builder=20and=20production=20sta?= =?UTF-8?q?ges?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 84f9869..501aaaa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # ── Stage 1: Install + Build ──────────────────────────────────────── -FROM oven/bun:1 AS builder +FROM oven/bun:1.3.9 AS builder WORKDIR /app @@ -40,7 +40,7 @@ COPY . . RUN bun run build # ── Stage 2: Production ───────────────────────────────────────────── -FROM oven/bun:1-slim AS production +FROM oven/bun:1.3.9-slim AS production WORKDIR /app From 8dc6789a763b41d6defb3e8dc7a1618599e445bc Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Fri, 20 Feb 2026 00:26:52 +0800 Subject: [PATCH 31/37] =?UTF-8?q?=F0=9F=9A=80=20release:=20bump=20version?= =?UTF-8?q?=20to=201.1.0=20for=20all=20packages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- packages/compactor/package.json | 2 +- packages/config/package.json | 2 +- packages/core/package.json | 2 +- packages/delegation/package.json | 2 +- packages/heartware/package.json | 2 +- packages/intercom/package.json | 2 +- packages/learning/package.json | 2 +- packages/logger/package.json | 2 +- packages/matcher/package.json | 2 +- packages/memory/package.json | 2 +- packages/plugins/package.json | 2 +- packages/pulse/package.json | 2 +- packages/queue/package.json | 2 +- packages/router/package.json | 2 +- packages/sandbox/package.json | 2 +- packages/secrets/package.json | 2 +- packages/shell/package.json | 2 +- packages/shield/package.json | 2 +- packages/types/package.json | 2 +- plugins/channel/plugin-channel-discord/package.json | 2 +- plugins/channel/plugin-channel-friends/package.json | 2 +- plugins/provider/plugin-provider-openai/package.json | 2 +- src/cli/package.json | 2 +- src/landing/package.json | 2 +- src/web/package.json | 2 +- 26 files changed, 26 insertions(+), 26 deletions(-) diff --git a/package.json b/package.json index 029ea2a..c4c8666 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tinyclaw-monorepo", - "version": "1.0.1", + "version": "1.1.0", "description": "Your autonomous AI companion", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/compactor/package.json b/packages/compactor/package.json index 906bf26..229f50e 100644 --- a/packages/compactor/package.json +++ b/packages/compactor/package.json @@ -1,7 +1,7 @@ { "name": "@tinyclaw/compactor", "private": true, - "version": "1.0.1", + "version": "1.1.0", "description": "Layered conversation compaction and token optimization for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/config/package.json b/packages/config/package.json index 74e7be4..8696a3a 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -1,7 +1,7 @@ { "name": "@tinyclaw/config", "private": true, - "version": "1.0.1", + "version": "1.1.0", "description": "SQLite-backed persistent configuration for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/core/package.json b/packages/core/package.json index d0f73f9..b630362 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,7 +1,7 @@ { "name": "@tinyclaw/core", "private": true, - "version": "1.0.1", + "version": "1.1.0", "description": "Core agent runtime for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/delegation/package.json b/packages/delegation/package.json index e17bd2a..bfcafaf 100644 --- a/packages/delegation/package.json +++ b/packages/delegation/package.json @@ -1,7 +1,7 @@ { "name": "@tinyclaw/delegation", "private": true, - "version": "1.0.1", + "version": "1.1.0", "description": "Sub-agent delegation and lifecycle management for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/heartware/package.json b/packages/heartware/package.json index eb0b529..a51ac8f 100644 --- a/packages/heartware/package.json +++ b/packages/heartware/package.json @@ -1,7 +1,7 @@ { "name": "@tinyclaw/heartware", "private": true, - "version": "1.0.1", + "version": "1.1.0", "description": "Personality and self-configuration system for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/intercom/package.json b/packages/intercom/package.json index d0d5a50..a670da3 100644 --- a/packages/intercom/package.json +++ b/packages/intercom/package.json @@ -1,7 +1,7 @@ { "name": "@tinyclaw/intercom", "private": true, - "version": "1.0.1", + "version": "1.1.0", "description": "Lightweight pub/sub event bus for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/learning/package.json b/packages/learning/package.json index af309d4..80c247f 100644 --- a/packages/learning/package.json +++ b/packages/learning/package.json @@ -1,7 +1,7 @@ { "name": "@tinyclaw/learning", "private": true, - "version": "1.0.1", + "version": "1.1.0", "description": "Pattern detection and adaptive learning engine for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/logger/package.json b/packages/logger/package.json index 5d50133..37ffc26 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -1,7 +1,7 @@ { "name": "@tinyclaw/logger", "private": true, - "version": "1.0.1", + "version": "1.1.0", "description": "Context-aware structured logging for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/matcher/package.json b/packages/matcher/package.json index eab4fad..8b16a69 100644 --- a/packages/matcher/package.json +++ b/packages/matcher/package.json @@ -1,7 +1,7 @@ { "name": "@tinyclaw/matcher", "private": true, - "version": "1.0.1", + "version": "1.1.0", "description": "Hybrid semantic text matching engine for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/memory/package.json b/packages/memory/package.json index 69b1f06..9419bf8 100644 --- a/packages/memory/package.json +++ b/packages/memory/package.json @@ -1,7 +1,7 @@ { "name": "@tinyclaw/memory", "private": true, - "version": "1.0.1", + "version": "1.1.0", "description": "3-layer adaptive memory with temporal decay for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/plugins/package.json b/packages/plugins/package.json index cbdae12..eb92615 100644 --- a/packages/plugins/package.json +++ b/packages/plugins/package.json @@ -1,6 +1,6 @@ { "name": "@tinyclaw/plugins", - "version": "1.0.1", + "version": "1.1.0", "description": "Config-driven plugin loader and validator for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/pulse/package.json b/packages/pulse/package.json index 4987db0..3b91ec4 100644 --- a/packages/pulse/package.json +++ b/packages/pulse/package.json @@ -1,7 +1,7 @@ { "name": "@tinyclaw/pulse", "private": true, - "version": "1.0.1", + "version": "1.1.0", "description": "Cron-like recurring task scheduler for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/queue/package.json b/packages/queue/package.json index 7610ae3..81c3ca6 100644 --- a/packages/queue/package.json +++ b/packages/queue/package.json @@ -1,7 +1,7 @@ { "name": "@tinyclaw/queue", "private": true, - "version": "1.0.1", + "version": "1.1.0", "description": "Per-session promise-chain task serialization for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/router/package.json b/packages/router/package.json index ff9cf13..f6db4a7 100644 --- a/packages/router/package.json +++ b/packages/router/package.json @@ -1,7 +1,7 @@ { "name": "@tinyclaw/router", "private": true, - "version": "1.0.1", + "version": "1.1.0", "description": "Multi-provider LLM routing and query classification for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/sandbox/package.json b/packages/sandbox/package.json index 9ea4fcd..6c569a9 100644 --- a/packages/sandbox/package.json +++ b/packages/sandbox/package.json @@ -1,7 +1,7 @@ { "name": "@tinyclaw/sandbox", "private": true, - "version": "1.0.1", + "version": "1.1.0", "description": "Lightweight sandboxed code execution for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/secrets/package.json b/packages/secrets/package.json index e2b4813..e8fc37e 100644 --- a/packages/secrets/package.json +++ b/packages/secrets/package.json @@ -1,7 +1,7 @@ { "name": "@tinyclaw/secrets", "private": true, - "version": "1.0.1", + "version": "1.1.0", "description": "Machine-bound encrypted secrets management for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/shell/package.json b/packages/shell/package.json index 62dfc75..0563848 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,7 +1,7 @@ { "name": "@tinyclaw/shell", "private": true, - "version": "1.0.1", + "version": "1.1.0", "description": "Controlled shell execution with permission engine for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/shield/package.json b/packages/shield/package.json index 4dfda5f..f93891d 100644 --- a/packages/shield/package.json +++ b/packages/shield/package.json @@ -1,7 +1,7 @@ { "name": "@tinyclaw/shield", "private": true, - "version": "1.0.1", + "version": "1.1.0", "description": "Runtime SHIELD.md threat evaluation and enforcement for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/packages/types/package.json b/packages/types/package.json index fa8e8d4..43db388 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@tinyclaw/types", - "version": "1.0.1", + "version": "1.1.0", "description": "Shared TypeScript type definitions for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/plugins/channel/plugin-channel-discord/package.json b/plugins/channel/plugin-channel-discord/package.json index 14fb18f..f9f426a 100644 --- a/plugins/channel/plugin-channel-discord/package.json +++ b/plugins/channel/plugin-channel-discord/package.json @@ -1,6 +1,6 @@ { "name": "@tinyclaw/plugin-channel-discord", - "version": "1.0.1", + "version": "1.1.0", "description": "Discord channel plugin for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/plugins/channel/plugin-channel-friends/package.json b/plugins/channel/plugin-channel-friends/package.json index 173a2df..091d510 100644 --- a/plugins/channel/plugin-channel-friends/package.json +++ b/plugins/channel/plugin-channel-friends/package.json @@ -1,6 +1,6 @@ { "name": "@tinyclaw/plugin-channel-friends", - "version": "1.0.1", + "version": "1.1.0", "description": "Friends web chat channel plugin for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/plugins/provider/plugin-provider-openai/package.json b/plugins/provider/plugin-provider-openai/package.json index 0067ec6..5b93e05 100644 --- a/plugins/provider/plugin-provider-openai/package.json +++ b/plugins/provider/plugin-provider-openai/package.json @@ -1,6 +1,6 @@ { "name": "@tinyclaw/plugin-provider-openai", - "version": "1.0.1", + "version": "1.1.0", "description": "OpenAI provider plugin for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/src/cli/package.json b/src/cli/package.json index f2b6184..52f1123 100644 --- a/src/cli/package.json +++ b/src/cli/package.json @@ -1,6 +1,6 @@ { "name": "tinyclaw", - "version": "1.0.1", + "version": "1.1.0", "description": "Command-line interface for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/src/landing/package.json b/src/landing/package.json index 7ee2179..32e44e1 100644 --- a/src/landing/package.json +++ b/src/landing/package.json @@ -1,7 +1,7 @@ { "name": "@tinyclaw/landing", "private": true, - "version": "1.0.1", + "version": "1.1.0", "description": "Official landing page for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", diff --git a/src/web/package.json b/src/web/package.json index 5d178ac..79d8533 100644 --- a/src/web/package.json +++ b/src/web/package.json @@ -1,7 +1,7 @@ { "name": "@tinyclaw/web", "private": true, - "version": "1.0.1", + "version": "1.1.0", "description": "Web user interface for Tiny Claw", "license": "GPL-3.0", "author": "Waren Gonzaga", From 4422bf382b1f343be0745c89bbe51204a0fa8d43 Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Fri, 20 Feb 2026 00:33:46 +0800 Subject: [PATCH 32/37] =?UTF-8?q?=F0=9F=94=A7=20update=20(dockerfile):=20r?= =?UTF-8?q?emove=20frozen-lockfile=20option=20from=20bun=20install?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 501aaaa..8acfc2f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -31,7 +31,7 @@ COPY plugins/channel/plugin-channel-friends/package.json ./plugins/channel/plugi COPY plugins/provider/plugin-provider-openai/package.json ./plugins/provider/plugin-provider-openai/ # Install all deps (dev included — needed to build) -RUN bun install --frozen-lockfile +RUN bun install # Copy source COPY . . From 958e520459ffc5d8ab7485b2ec1e69fe47cdc095 Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Fri, 20 Feb 2026 00:42:10 +0800 Subject: [PATCH 33/37] =?UTF-8?q?=F0=9F=93=A6=20new:=20add=20dev:landing?= =?UTF-8?q?=20script=20for=20development=20of=20landing=20page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index c4c8666..a945800 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "test": "bun test", "cli": "bun run src/cli/src/index.ts", "dev:purge": "bun run cli purge --force", + "dev:landing": "bun run --cwd src/landing dev", "prepare": "husky" }, "devDependencies": { From 61699d8ba37806890d0029951fd0cc36d01a2179 Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Fri, 20 Feb 2026 00:42:17 +0800 Subject: [PATCH 34/37] =?UTF-8?q?=F0=9F=93=96=20docs:=20update=20README=20?= =?UTF-8?q?with=20model=20names=20and=20licensing=20information?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b1b2708..b8ab0e0 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ Tiny Claw is inspired by personal AI companions from science fiction like **Cods - **Self-configuring.** No manual config files. The agent configures itself through conversation. - **Own personality.** Ships with a personality (Heartware system) that's uniquely its own. - **Native, not wrapped.** Every component is built from scratch with zero dependency on external AI frameworks. -- **Easy to start.** Uses Ollama Cloud with two built-in models — kimi-k2.5 (default) and gpt-oss:120b. Choose your model during setup and switch anytime via conversation. +- **Easy to start.** Uses Ollama Cloud with two built-in models — kimi-k2.5:cloud (default) and gpt-oss:120b-cloud. Choose your model during setup and switch anytime via conversation. - **Cost-conscious.** Smart routing tiers queries across your installed providers. Cheap models handle simple stuff, powerful models only fire when needed. ## ✨ Features @@ -120,6 +120,7 @@ tinyclaw/ router/ Smart provider routing (8-dim classifier) learning/ Behavioral pattern detection sandbox/ Bun Worker code execution + shell/ Controlled shell execution with permission engine shield/ Runtime SHIELD.md enforcement + anti-malware pulse/ Cron-like proactive scheduler queue/ Per-session message locking queue @@ -129,11 +130,11 @@ tinyclaw/ secrets/ Encrypted secrets management (AES-256-GCM) plugins/ Plugin discovery and loading plugins/ Plugin packages (keep the core tiny) - channel/ Messaging integrations (Discord, etc.) + channel/ Messaging integrations (Discord, Friends, etc.) provider/ LLM providers (OpenAI, etc.) - tool/ Additional agent tools src/ cli/ CLI entry point + landing/ Official landing page (Svelte + Vite) web/ Web UI (Svelte 5, Discord-like experience) ``` @@ -157,7 +158,7 @@ Read the project's [code of conduct](https://github.com/warengonzaga/tinyclaw/bl ## 📃 License -This project is licensed under [MIT License](https://opensource.org/license/MIT). +This project is licensed under [GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.html). ## 🙏 Credits From 6e3e0bd59bab7214c1f441f4cab2cb05294b2e0a Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Fri, 20 Feb 2026 17:48:21 +0800 Subject: [PATCH 35/37] =?UTF-8?q?=E2=9A=99=EF=B8=8F=20setup:=20update=20re?= =?UTF-8?q?lease=20action=20to=20v1.2.1=20and=20change=20token=20secret?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8d3f8da..670c1ba 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -50,9 +50,9 @@ jobs: fetch-depth: 0 - name: Create Release - uses: wgtechlabs/release-build-flow-action@032b32cb5f6933e5912768c5b2e42c29389c2c95 # v1.0.0 + uses: wgtechlabs/release-build-flow-action@799974c8dec094fbe94a92b2764365d3a8f9ce5f # v1.2.1 with: - github-token: ${{ secrets.GITHUB_TOKEN }} + github-token: ${{ secrets.GH_PAT }} monorepo: 'true' workspace-detection: 'true' package-manager: 'bun' From 8bb83824cbd3661d900b5a6eb185ee8d125c5c30 Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Fri, 20 Feb 2026 17:48:28 +0800 Subject: [PATCH 36/37] =?UTF-8?q?=F0=9F=93=96=20docs:=20update=20commit=20?= =?UTF-8?q?message=20guidelines=20for=20breaking=20changes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/instructions/copilot.instructions.md | 5 +++++ AGENTS.md | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/.github/instructions/copilot.instructions.md b/.github/instructions/copilot.instructions.md index 0d440e5..21e3339 100644 --- a/.github/instructions/copilot.instructions.md +++ b/.github/instructions/copilot.instructions.md @@ -13,6 +13,8 @@ Reference: https://github.com/wgtechlabs/clean-commit ```text : (): + !: + ! (): ``` ## The 9 Types @@ -32,6 +34,7 @@ Reference: https://github.com/wgtechlabs/clean-commit ## Rules - Use lowercase for type +- Use `!` immediately after type (no space) to signal a breaking change — only for `new`, `update`, `remove`, `security` - Use present tense ("add" not "added") - No period at the end - Keep description under 72 characters @@ -47,3 +50,5 @@ Reference: https://github.com/wgtechlabs/clean-commit - `🧪 test: add unit tests for auth service` - `📖 docs: update installation instructions` - `🚀 release: version 1.0.0` +- `📦 new!: completely redesign authentication system` +- `🔧 update! (api): change response format for all endpoints` diff --git a/AGENTS.md b/AGENTS.md index 4206fe8..717a06d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,6 +9,8 @@ Reference: https://github.com/wgtechlabs/clean-commit ```text : (): + !: + ! (): ``` ## The 9 Types @@ -28,6 +30,7 @@ Reference: https://github.com/wgtechlabs/clean-commit ## Rules - Use lowercase for type +- Use `!` immediately after type (no space) to signal a breaking change — only for `new`, `update`, `remove`, `security` - Use present tense ("add" not "added") - No period at the end - Keep description under 72 characters @@ -43,3 +46,5 @@ Reference: https://github.com/wgtechlabs/clean-commit - `🧪 test: add unit tests for auth service` - `📖 docs: update installation instructions` - `🚀 release: version 1.0.0` +- `📦 new!: completely redesign authentication system` +- `🔧 update! (api): change response format for all endpoints` From 7c8f470144288537ec65256d2914d045393c9c4e Mon Sep 17 00:00:00 2001 From: Waren Gonzaga Date: Fri, 20 Feb 2026 17:48:37 +0800 Subject: [PATCH 37/37] =?UTF-8?q?=F0=9F=94=A7=20update:=20enhance=20commit?= =?UTF-8?q?=20message=20validation=20for=20breaking=20changes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .husky/validate-commit-msg.mjs | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/.husky/validate-commit-msg.mjs b/.husky/validate-commit-msg.mjs index ba81a53..71ad87b 100644 --- a/.husky/validate-commit-msg.mjs +++ b/.husky/validate-commit-msg.mjs @@ -20,15 +20,30 @@ const firstLine = raw.replace(/\r/g, "").split("\n")[0].trim(); if (/^Merge /.test(firstLine) || /^Revert /.test(firstLine)) process.exit(0); // Clean Commit convention pattern -// Format: [()]: +// Format: [!][()]: const pattern = - /^(📦|🔧|🗑\uFE0F?|🔒|⚙\uFE0F?|☕|🧪|📖|🚀) (new|update|remove|security|setup|chore|test|docs|release)( \([a-z0-9][a-z0-9-]*\))?: .{1,72}$/u; + /^(📦|🔧|🗑\uFE0F?|🔒|⚙\uFE0F?|☕|🧪|📖|🚀) (new|update|remove|security|setup|chore|test|docs|release)(!?)( \([a-z0-9][a-z0-9-]*\))?: .{1,72}$/u; + +// Only new, update, remove, security may use the breaking change marker +const breakingMatch = firstLine.match(pattern); +if (breakingMatch) { + const type = breakingMatch[2]; + const bang = breakingMatch[3]; + if (bang === '!' && !['new', 'update', 'remove', 'security'].includes(type)) { + console.error(''); + console.error('✖ Breaking change marker (!) is only allowed for: new, update, remove, security'); + console.error(''); + process.exit(1); + } +} if (!pattern.test(firstLine)) { console.error(""); console.error("✖ Invalid commit message format."); console.error(""); - console.error(" Expected: [()]: "); + console.error(" Expected: [!][()]: "); + console.error(""); + console.error(" Use ! after type for breaking changes (new, update, remove, security only)"); console.error(""); console.error(" Types and emojis:"); console.error(" 📦 new – new features, files, or capabilities"); @@ -45,6 +60,8 @@ if (!pattern.test(firstLine)) { console.error(" 📦 new: user authentication system"); console.error(" 🔧 update (api): improve error handling"); console.error(" ⚙️ setup (ci): configure github actions workflow"); + console.error(" 📦 new!: completely redesign authentication system"); + console.error(" 🔧 update! (api): change response format for all endpoints"); console.error(""); console.error(" Reference: https://github.com/wgtechlabs/clean-commit"); console.error("");