@threadbase-sh/streamer 1.24.7 → 1.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,15 @@
1
+ -- Persist enough scanner output to reuse unchanged files on the next startup
2
+ -- scan. The scanner stat cache needs both file stats and the corresponding
3
+ -- ConversationMeta; mtime_ms/file_size alone are not sufficient.
4
+ ALTER TABLE conversation_meta ADD COLUMN scanner_meta_json TEXT;
5
+
6
+ -- File-level metadata is separate from conversation_meta so agent files that
7
+ -- are intentionally filtered out can still keep their classification cached.
8
+ CREATE TABLE IF NOT EXISTS conversation_file_metadata (
9
+ file_path TEXT PRIMARY KEY,
10
+ mtime_ms REAL NOT NULL,
11
+ file_size INTEGER NOT NULL,
12
+ is_agent INTEGER NOT NULL,
13
+ agent_entrypoints_key TEXT NOT NULL,
14
+ updated_at INTEGER NOT NULL
15
+ );
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/docker/seed-claude-config.ts"],"sourcesContent":["// Seed $HOME/.claude.json so spawned interactive Claude sessions reach a usable\n// prompt instead of a blocking first-run dialog (the mobile app shows an empty\n// screen otherwise). On a fresh /data volume the CLI would show, in order:\n// onboarding/theme picker, workspace-trust dialog, and the \"custom API key\n// detected\" approval. Seeding these flags clears all three. (The fourth gate,\n// the Bypass Permissions warning, is avoided by launching with\n// `--permission-mode dontAsk` rather than `--dangerously-skip-permissions` —\n// see src/pty-manager.ts.)\n//\n// Compiled by tsup to dist/seed-claude-config.cjs; docker/entrypoint.sh runs it\n// with the plain `node` in the runtime image, before the streamer starts.\n// __tests__/seed-claude-config.test.ts exercises seedClaudeConfig() directly.\nimport { readFileSync, writeFileSync } from \"node:fs\";\n\n// Trust this workspace dir without the per-project trust dialog. Matches the\n// --browse-root the streamer serves in the Fly container.\nexport const TRUSTED_DIR = \"/data/.claude/projects\";\n\ninterface ProjectEntry {\n allowedTools: string[];\n hasTrustDialogAccepted: boolean;\n hasCompletedProjectOnboarding: boolean;\n}\n\ninterface ClaudeConfig {\n hasCompletedOnboarding?: boolean;\n theme?: string;\n hasTrustDialogAccepted?: boolean;\n projects?: Record<string, Partial<ProjectEntry>>;\n customApiKeyResponses?: { approved?: string[]; rejected?: string[] };\n [key: string]: unknown;\n}\n\n// Read-modify-write merge into any existing config. Idempotent: re-runs (the\n// Fly volume persists .claude.json across restarts) preserve existing keys and\n// never duplicate an approved key suffix.\n//\n// Error handling is deliberate: a fresh volume (ENOENT) starts from empty, but\n// any OTHER read/parse error means the file EXISTS but is unreadable. The file\n// is the system of record (userID, approved keys, feature flags) — overwriting\n// it would silently truncate that state, so we throw rather than clobber.\nexport function seedClaudeConfig(configPath: string, apiKey: string): void {\n let config: ClaudeConfig = {};\n try {\n config = JSON.parse(readFileSync(configPath, \"utf8\"));\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw new Error(`refusing to overwrite ${configPath}: ${(err as Error).message}`);\n }\n // ENOENT — expected first boot. Fall through with an empty config.\n }\n\n config.hasCompletedOnboarding = true;\n config.theme = config.theme || \"dark\";\n config.hasTrustDialogAccepted = true;\n\n config.projects = config.projects || {};\n config.projects[TRUSTED_DIR] = Object.assign(\n { allowedTools: [], hasTrustDialogAccepted: true, hasCompletedProjectOnboarding: true },\n config.projects[TRUSTED_DIR] || {},\n );\n\n // The custom-API-key approval is keyed by the last 20 chars of the API key,\n // matching how the CLI records an accepted key. The streamer maps\n // CLAUDE_API_KEY → ANTHROPIC_API_KEY at spawn, so the CLI reads the same key.\n if (apiKey) {\n const suffix = apiKey.slice(-20);\n config.customApiKeyResponses = config.customApiKeyResponses || { approved: [], rejected: [] };\n config.customApiKeyResponses.approved = config.customApiKeyResponses.approved || [];\n if (!config.customApiKeyResponses.approved.includes(suffix)) {\n config.customApiKeyResponses.approved.push(suffix);\n }\n }\n\n writeFileSync(configPath, JSON.stringify(config, null, 2));\n}\n\n// CLI entry: `node dist/seed-claude-config.cjs`. Reads CLAUDE_CONFIG (path) and\n// CLAUDE_API_KEY from the environment. Any failure is logged with an\n// [entrypoint] prefix and exits non-zero so `set -euo pipefail` aborts boot\n// rather than letting the streamer start with unseeded config.\nfunction main(): void {\n const configPath = process.env.CLAUDE_CONFIG;\n if (!configPath) {\n console.error(\"[entrypoint] seed-claude-config: CLAUDE_CONFIG is not set\");\n process.exit(1);\n }\n try {\n seedClaudeConfig(configPath, process.env.CLAUDE_API_KEY || \"\");\n } catch (err) {\n console.error(`[entrypoint] ${(err as Error).message}`);\n process.exit(1);\n }\n}\n\n// tsup bundles this as CJS, so require.main === module is the right guard.\nif (require.main === module) {\n main();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA,qBAA4C;AAIrC,IAAM,cAAc;AAyBpB,SAAS,iBAAiB,YAAoB,QAAsB;AACzE,MAAI,SAAuB,CAAC;AAC5B,MAAI;AACF,aAAS,KAAK,UAAM,6BAAa,YAAY,MAAM,CAAC;AAAA,EACtD,SAAS,KAAK;AACZ,QAAK,IAA8B,SAAS,UAAU;AACpD,YAAM,IAAI,MAAM,yBAAyB,UAAU,KAAM,IAAc,OAAO,EAAE;AAAA,IAClF;AAAA,EAEF;AAEA,SAAO,yBAAyB;AAChC,SAAO,QAAQ,OAAO,SAAS;AAC/B,SAAO,yBAAyB;AAEhC,SAAO,WAAW,OAAO,YAAY,CAAC;AACtC,SAAO,SAAS,WAAW,IAAI,OAAO;AAAA,IACpC,EAAE,cAAc,CAAC,GAAG,wBAAwB,MAAM,+BAA+B,KAAK;AAAA,IACtF,OAAO,SAAS,WAAW,KAAK,CAAC;AAAA,EACnC;AAKA,MAAI,QAAQ;AACV,UAAM,SAAS,OAAO,MAAM,GAAG;AAC/B,WAAO,wBAAwB,OAAO,yBAAyB,EAAE,UAAU,CAAC,GAAG,UAAU,CAAC,EAAE;AAC5F,WAAO,sBAAsB,WAAW,OAAO,sBAAsB,YAAY,CAAC;AAClF,QAAI,CAAC,OAAO,sBAAsB,SAAS,SAAS,MAAM,GAAG;AAC3D,aAAO,sBAAsB,SAAS,KAAK,MAAM;AAAA,IACnD;AAAA,EACF;AAEA,oCAAc,YAAY,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAC3D;AAMA,SAAS,OAAa;AACpB,QAAM,aAAa,QAAQ,IAAI;AAC/B,MAAI,CAAC,YAAY;AACf,YAAQ,MAAM,2DAA2D;AACzE,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,MAAI;AACF,qBAAiB,YAAY,QAAQ,IAAI,kBAAkB,EAAE;AAAA,EAC/D,SAAS,KAAK;AACZ,YAAQ,MAAM,gBAAiB,IAAc,OAAO,EAAE;AACtD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAGA,IAAI,QAAQ,SAAS,QAAQ;AAC3B,OAAK;AACP;","names":[]}
1
+ {"version":3,"sources":["../src/docker/seed-claude-config.ts"],"sourcesContent":["// Seed $HOME/.claude.json so spawned interactive Claude sessions reach a usable\n// prompt instead of a blocking first-run dialog (the mobile app shows an empty\n// screen otherwise). On a fresh /data volume the CLI would show, in order:\n// onboarding/theme picker, workspace-trust dialog, and the \"custom API key\n// detected\" approval. Seeding these flags clears all three. (The fourth gate,\n// the Bypass Permissions warning, is avoided by launching with\n// `--permission-mode acceptEdits` rather than `--dangerously-skip-permissions` —\n// see src/pty-manager.ts.)\n//\n// Compiled by tsup to dist/seed-claude-config.cjs; docker/entrypoint.sh runs it\n// with the plain `node` in the runtime image, before the streamer starts.\n// __tests__/seed-claude-config.test.ts exercises seedClaudeConfig() directly.\nimport { readFileSync, writeFileSync } from \"node:fs\";\n\n// Trust this workspace dir without the per-project trust dialog. Matches the\n// --browse-root the streamer serves in the Fly container.\nexport const TRUSTED_DIR = \"/data/.claude/projects\";\n\ninterface ProjectEntry {\n allowedTools: string[];\n hasTrustDialogAccepted: boolean;\n hasCompletedProjectOnboarding: boolean;\n}\n\ninterface ClaudeConfig {\n hasCompletedOnboarding?: boolean;\n theme?: string;\n hasTrustDialogAccepted?: boolean;\n projects?: Record<string, Partial<ProjectEntry>>;\n customApiKeyResponses?: { approved?: string[]; rejected?: string[] };\n [key: string]: unknown;\n}\n\n// Read-modify-write merge into any existing config. Idempotent: re-runs (the\n// Fly volume persists .claude.json across restarts) preserve existing keys and\n// never duplicate an approved key suffix.\n//\n// Error handling is deliberate: a fresh volume (ENOENT) starts from empty, but\n// any OTHER read/parse error means the file EXISTS but is unreadable. The file\n// is the system of record (userID, approved keys, feature flags) — overwriting\n// it would silently truncate that state, so we throw rather than clobber.\nexport function seedClaudeConfig(configPath: string, apiKey: string): void {\n let config: ClaudeConfig = {};\n try {\n config = JSON.parse(readFileSync(configPath, \"utf8\"));\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw new Error(`refusing to overwrite ${configPath}: ${(err as Error).message}`);\n }\n // ENOENT — expected first boot. Fall through with an empty config.\n }\n\n config.hasCompletedOnboarding = true;\n config.theme = config.theme || \"dark\";\n config.hasTrustDialogAccepted = true;\n\n config.projects = config.projects || {};\n config.projects[TRUSTED_DIR] = Object.assign(\n { allowedTools: [], hasTrustDialogAccepted: true, hasCompletedProjectOnboarding: true },\n config.projects[TRUSTED_DIR] || {},\n );\n\n // The custom-API-key approval is keyed by the last 20 chars of the API key,\n // matching how the CLI records an accepted key. The streamer maps\n // CLAUDE_API_KEY → ANTHROPIC_API_KEY at spawn, so the CLI reads the same key.\n if (apiKey) {\n const suffix = apiKey.slice(-20);\n config.customApiKeyResponses = config.customApiKeyResponses || { approved: [], rejected: [] };\n config.customApiKeyResponses.approved = config.customApiKeyResponses.approved || [];\n if (!config.customApiKeyResponses.approved.includes(suffix)) {\n config.customApiKeyResponses.approved.push(suffix);\n }\n }\n\n writeFileSync(configPath, JSON.stringify(config, null, 2));\n}\n\n// CLI entry: `node dist/seed-claude-config.cjs`. Reads CLAUDE_CONFIG (path) and\n// CLAUDE_API_KEY from the environment. Any failure is logged with an\n// [entrypoint] prefix and exits non-zero so `set -euo pipefail` aborts boot\n// rather than letting the streamer start with unseeded config.\nfunction main(): void {\n const configPath = process.env.CLAUDE_CONFIG;\n if (!configPath) {\n console.error(\"[entrypoint] seed-claude-config: CLAUDE_CONFIG is not set\");\n process.exit(1);\n }\n try {\n seedClaudeConfig(configPath, process.env.CLAUDE_API_KEY || \"\");\n } catch (err) {\n console.error(`[entrypoint] ${(err as Error).message}`);\n process.exit(1);\n }\n}\n\n// tsup bundles this as CJS, so require.main === module is the right guard.\nif (require.main === module) {\n main();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA,qBAA4C;AAIrC,IAAM,cAAc;AAyBpB,SAAS,iBAAiB,YAAoB,QAAsB;AACzE,MAAI,SAAuB,CAAC;AAC5B,MAAI;AACF,aAAS,KAAK,UAAM,6BAAa,YAAY,MAAM,CAAC;AAAA,EACtD,SAAS,KAAK;AACZ,QAAK,IAA8B,SAAS,UAAU;AACpD,YAAM,IAAI,MAAM,yBAAyB,UAAU,KAAM,IAAc,OAAO,EAAE;AAAA,IAClF;AAAA,EAEF;AAEA,SAAO,yBAAyB;AAChC,SAAO,QAAQ,OAAO,SAAS;AAC/B,SAAO,yBAAyB;AAEhC,SAAO,WAAW,OAAO,YAAY,CAAC;AACtC,SAAO,SAAS,WAAW,IAAI,OAAO;AAAA,IACpC,EAAE,cAAc,CAAC,GAAG,wBAAwB,MAAM,+BAA+B,KAAK;AAAA,IACtF,OAAO,SAAS,WAAW,KAAK,CAAC;AAAA,EACnC;AAKA,MAAI,QAAQ;AACV,UAAM,SAAS,OAAO,MAAM,GAAG;AAC/B,WAAO,wBAAwB,OAAO,yBAAyB,EAAE,UAAU,CAAC,GAAG,UAAU,CAAC,EAAE;AAC5F,WAAO,sBAAsB,WAAW,OAAO,sBAAsB,YAAY,CAAC;AAClF,QAAI,CAAC,OAAO,sBAAsB,SAAS,SAAS,MAAM,GAAG;AAC3D,aAAO,sBAAsB,SAAS,KAAK,MAAM;AAAA,IACnD;AAAA,EACF;AAEA,oCAAc,YAAY,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAC3D;AAMA,SAAS,OAAa;AACpB,QAAM,aAAa,QAAQ,IAAI;AAC/B,MAAI,CAAC,YAAY;AACf,YAAQ,MAAM,2DAA2D;AACzE,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,MAAI;AACF,qBAAiB,YAAY,QAAQ,IAAI,kBAAkB,EAAE;AAAA,EAC/D,SAAS,KAAK;AACZ,YAAQ,MAAM,gBAAiB,IAAc,OAAO,EAAE;AACtD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAGA,IAAI,QAAQ,SAAS,QAAQ;AAC3B,OAAK;AACP;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@threadbase-sh/streamer",
3
- "version": "1.24.7",
3
+ "version": "1.25.0",
4
4
  "description": "PTY session management, WebSocket streaming, and REST API server for Claude Code conversations",
5
5
  "license": "MIT",
6
6
  "author": "Ronen Mars",