@assistkick/create 1.25.0 → 1.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assistkick/create",
3
- "version": "1.25.0",
3
+ "version": "1.26.0",
4
4
  "description": "Scaffold assistkick-product-system into any project",
5
5
  "type": "module",
6
6
  "bin": {
@@ -5,6 +5,7 @@
5
5
 
6
6
  import { join, dirname } from 'node:path';
7
7
  import { fileURLToPath } from 'node:url';
8
+ import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync, statSync } from 'node:fs';
8
9
  import { createClaudeService } from '@assistkick/shared/lib/claude-service.js';
9
10
  import { GitWorkflow } from '@assistkick/shared/lib/git_workflow.js';
10
11
  import { getDb } from '@assistkick/shared/lib/db.js';
@@ -41,16 +42,53 @@ const DEBUGGER_SKILL_PATH = join(SKILLS_DIR, 'product-debugger', 'SKILL.md');
41
42
  const VIDEO_PACKAGE_DIR = join(SKILL_ROOT, 'video');
42
43
  const BUNDLE_OUTPUT_DIR = process.env.REMOTION_BUNDLE_DIR || join(PROJECT_ROOT, 'data', 'remotion-bundle');
43
44
 
45
+ /* ── Persistent file logger ──────────────────────────────────────────────
46
+ * Writes every log line to data/server.log so logs survive tsx watch restarts.
47
+ * Truncates the file when it exceeds MAX_LOG_LINES to prevent unbounded growth.
48
+ */
49
+ const LOG_DIR = join(SKILL_ROOT, 'data');
50
+ const LOG_FILE = join(LOG_DIR, 'server.log');
51
+ const MAX_LOG_LINES = 2000;
52
+ const TRUNCATE_TO = 1500; // keep last N lines after truncation
53
+
54
+ if (!existsSync(LOG_DIR)) mkdirSync(LOG_DIR, { recursive: true });
55
+
56
+ /** Append a line to the log file, truncating when it gets too large. */
57
+ const writeToLogFile = (line: string): void => {
58
+ try {
59
+ appendFileSync(LOG_FILE, line + '\n');
60
+ // Check file size periodically (cheap stat check — only truncate when > ~200KB)
61
+ const stats = statSync(LOG_FILE);
62
+ if (stats.size > 200_000) {
63
+ const content = readFileSync(LOG_FILE, 'utf-8');
64
+ const lines = content.split('\n');
65
+ if (lines.length > MAX_LOG_LINES) {
66
+ const trimmed = lines.slice(-TRUNCATE_TO).join('\n');
67
+ writeFileSync(LOG_FILE, trimmed + '\n');
68
+ }
69
+ }
70
+ } catch {
71
+ // Never let logging failures break the app
72
+ }
73
+ };
74
+
75
+ // Write startup marker so you can find restart boundaries in the log file
76
+ writeToLogFile(`\n${'='.repeat(80)}\n[${new Date().toISOString()}] SERVER STARTING (pid ${process.pid})\n${'='.repeat(80)}`);
77
+
44
78
  export const log = (tag: string, ...args: any[]) => {
45
79
  const ts = new Date().toISOString().slice(11, 23);
46
- console.log(`[${ts}] [${tag}]`, ...args);
80
+ const line = `[${ts}] [${tag}] ${args.map(a => typeof a === 'string' ? a : JSON.stringify(a)).join(' ')}`;
81
+ console.log(line);
82
+ writeToLogFile(line);
47
83
  };
48
84
 
49
85
  /** Log an error with its stack trace for debugging. */
50
86
  export const logError = (tag: string, msg: string, err: unknown) => {
51
87
  const ts = new Date().toISOString().slice(11, 23);
52
88
  const stack = err instanceof Error ? err.stack : String(err);
53
- console.error(`[${ts}] [${tag}] ERROR ${msg}`, stack);
89
+ const line = `[${ts}] [${tag}] ERROR ${msg} ${stack}`;
90
+ console.error(line);
91
+ writeToLogFile(line);
54
92
  };
55
93
 
56
94
  export let claudeService: any;
@@ -14,12 +14,30 @@ import { migrate } from 'drizzle-orm/libsql/migrator';
14
14
  import { drizzle } from 'drizzle-orm/libsql';
15
15
  import { createClient } from '@libsql/client';
16
16
  import { getTableColumns, getTableName } from 'drizzle-orm';
17
+ import { existsSync, mkdirSync } from 'node:fs';
18
+ import { join } from 'node:path';
17
19
  import * as schema from './schema.js';
18
20
 
19
- const client = createClient({
20
- url: process.env.TURSO_DATABASE_URL!,
21
- authToken: process.env.TURSO_AUTH_TOKEN!,
22
- });
21
+ const tursoUrl = process.env.TURSO_DATABASE_URL;
22
+ const tursoAuthToken = process.env.TURSO_AUTH_TOKEN;
23
+
24
+ let connectionUrl: string;
25
+ let connectionAuthToken: string | undefined;
26
+
27
+ if (tursoUrl && tursoAuthToken) {
28
+ connectionUrl = tursoUrl;
29
+ connectionAuthToken = tursoAuthToken;
30
+ } else {
31
+ // Local SQLite fallback — same logic as lib/db.ts
32
+ const dataDir = join(import.meta.dirname, '..', '..', '..', 'data');
33
+ if (!existsSync(dataDir)) {
34
+ mkdirSync(dataDir, { recursive: true });
35
+ }
36
+ connectionUrl = `file:${join(dataDir, 'local.db')}`;
37
+ connectionAuthToken = undefined;
38
+ }
39
+
40
+ const client = createClient({ url: connectionUrl, authToken: connectionAuthToken });
23
41
 
24
42
  const db = drizzle(client);
25
43
 
@@ -1,14 +1,19 @@
1
1
  import { defineConfig } from 'drizzle-kit';
2
2
  import { config } from 'dotenv';
3
+ import { join } from 'node:path';
3
4
 
4
5
  config({ path: '../../.env' });
5
6
 
7
+ const tursoUrl = process.env.TURSO_DATABASE_URL;
8
+ const tursoAuthToken = process.env.TURSO_AUTH_TOKEN;
9
+
10
+ const dbCredentials = (tursoUrl && tursoAuthToken)
11
+ ? { url: tursoUrl, authToken: tursoAuthToken }
12
+ : { url: `file:${join(import.meta.dirname, '..', '..', 'data', 'local.db')}` };
13
+
6
14
  export default defineConfig({
7
15
  schema: './db/schema.ts',
8
16
  out: './db/migrations',
9
17
  dialect: 'turso',
10
- dbCredentials: {
11
- url: process.env.TURSO_DATABASE_URL,
12
- authToken: process.env.TURSO_AUTH_TOKEN,
13
- },
18
+ dbCredentials,
14
19
  });
@@ -7,6 +7,8 @@ import { config } from 'dotenv';
7
7
  config({ path: '../../.env' });
8
8
 
9
9
  import { createClient } from '@libsql/client';
10
+ import { existsSync, mkdirSync } from 'node:fs';
11
+ import { join } from 'node:path';
10
12
 
11
13
  const TABLES = [
12
14
  'nodes',
@@ -25,10 +27,25 @@ if (!projectId) {
25
27
  }
26
28
 
27
29
  async function main() {
28
- const client = createClient({
29
- url: process.env.TURSO_DATABASE_URL!,
30
- authToken: process.env.TURSO_AUTH_TOKEN!,
31
- });
30
+ const tursoUrl = process.env.TURSO_DATABASE_URL;
31
+ const tursoAuthToken = process.env.TURSO_AUTH_TOKEN;
32
+
33
+ let connectionUrl: string;
34
+ let connectionAuthToken: string | undefined;
35
+
36
+ if (tursoUrl && tursoAuthToken) {
37
+ connectionUrl = tursoUrl;
38
+ connectionAuthToken = tursoAuthToken;
39
+ } else {
40
+ const dataDir = join(import.meta.dirname, '..', '..', '..', 'data');
41
+ if (!existsSync(dataDir)) {
42
+ mkdirSync(dataDir, { recursive: true });
43
+ }
44
+ connectionUrl = `file:${join(dataDir, 'local.db')}`;
45
+ connectionAuthToken = undefined;
46
+ }
47
+
48
+ const client = createClient({ url: connectionUrl, authToken: connectionAuthToken });
32
49
 
33
50
  console.log(`Assigning unassigned rows to project: ${projectId}\n`);
34
51