@farazirfan/costar-server-executor 1.7.54 → 1.7.55

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.
Files changed (41) hide show
  1. package/dist/cron/local-run-log.d.ts +35 -0
  2. package/dist/cron/local-run-log.d.ts.map +1 -0
  3. package/dist/cron/local-run-log.js +153 -0
  4. package/dist/cron/local-run-log.js.map +1 -0
  5. package/dist/cron/local-store.d.ts +86 -0
  6. package/dist/cron/local-store.d.ts.map +1 -0
  7. package/dist/cron/local-store.js +199 -0
  8. package/dist/cron/local-store.js.map +1 -0
  9. package/dist/db/local-database.d.ts +134 -0
  10. package/dist/db/local-database.d.ts.map +1 -0
  11. package/dist/db/local-database.js +419 -0
  12. package/dist/db/local-database.js.map +1 -0
  13. package/dist/middleware/auth.d.ts +13 -0
  14. package/dist/middleware/auth.d.ts.map +1 -0
  15. package/dist/middleware/auth.js +67 -0
  16. package/dist/middleware/auth.js.map +1 -0
  17. package/dist/routes/db-ops.d.ts +11 -0
  18. package/dist/routes/db-ops.d.ts.map +1 -0
  19. package/dist/routes/db-ops.js +266 -0
  20. package/dist/routes/db-ops.js.map +1 -0
  21. package/dist/routes/sandbox-ops.d.ts +15 -0
  22. package/dist/routes/sandbox-ops.d.ts.map +1 -0
  23. package/dist/routes/sandbox-ops.js +306 -0
  24. package/dist/routes/sandbox-ops.js.map +1 -0
  25. package/dist/server.d.ts +2 -0
  26. package/dist/server.d.ts.map +1 -1
  27. package/dist/server.js +57 -1
  28. package/dist/server.js.map +1 -1
  29. package/dist/services/backup-service.d.ts +49 -0
  30. package/dist/services/backup-service.d.ts.map +1 -0
  31. package/dist/services/backup-service.js +113 -0
  32. package/dist/services/backup-service.js.map +1 -0
  33. package/dist/services/s3-file-watcher.d.ts +79 -0
  34. package/dist/services/s3-file-watcher.d.ts.map +1 -0
  35. package/dist/services/s3-file-watcher.js +191 -0
  36. package/dist/services/s3-file-watcher.js.map +1 -0
  37. package/dist/web-server.d.ts +7 -0
  38. package/dist/web-server.d.ts.map +1 -1
  39. package/dist/web-server.js +59 -18
  40. package/dist/web-server.js.map +1 -1
  41. package/package.json +2 -1
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Local Cron Run Log — JSONL execution history (OpenClaw pattern)
3
+ * One file per job: ~/.costar/cron/runs/{jobId}.jsonl
4
+ * Part of Phase 5: Direct Client → Sandbox Architecture.
5
+ *
6
+ * Features:
7
+ * - One JSON line per execution
8
+ * - Pruned at 2MB / 2000 lines (configurable)
9
+ * - Sequential write queue to prevent corruption
10
+ */
11
+ export type CronRunLogEntry = {
12
+ ts: string;
13
+ jobId: string;
14
+ jobName: string;
15
+ status: "ok" | "error" | "skipped";
16
+ error?: string;
17
+ summary?: string;
18
+ durationMs?: number;
19
+ nextRunAt?: string;
20
+ };
21
+ /**
22
+ * Append a run log entry (sequential queue per job).
23
+ */
24
+ export declare function appendRunLog(entry: CronRunLogEntry): Promise<void>;
25
+ /**
26
+ * Read recent run log entries for a job.
27
+ * Returns newest first.
28
+ */
29
+ export declare function readRunLog(jobId: string, limit?: number): CronRunLogEntry[];
30
+ /**
31
+ * Read run logs across all jobs (for dashboard).
32
+ * Returns newest first.
33
+ */
34
+ export declare function readAllRunLogs(limit?: number): CronRunLogEntry[];
35
+ //# sourceMappingURL=local-run-log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-run-log.d.ts","sourceRoot":"","sources":["../../src/cron/local-run-log.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAUH,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,IAAI,GAAG,OAAO,GAAG,SAAS,CAAC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAuBF;;GAEG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CASxE;AAuBD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,GAAE,MAAY,GAAG,eAAe,EAAE,CA0BhF;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,GAAE,MAAY,GAAG,eAAe,EAAE,CAoCrE"}
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Local Cron Run Log — JSONL execution history (OpenClaw pattern)
3
+ * One file per job: ~/.costar/cron/runs/{jobId}.jsonl
4
+ * Part of Phase 5: Direct Client → Sandbox Architecture.
5
+ *
6
+ * Features:
7
+ * - One JSON line per execution
8
+ * - Pruned at 2MB / 2000 lines (configurable)
9
+ * - Sequential write queue to prevent corruption
10
+ */
11
+ import fs from "node:fs";
12
+ import path from "node:path";
13
+ import { resolveCoStarDir } from "../cli/paths.js";
14
+ // ═══════════════════════════════════════════════════════
15
+ // PATHS
16
+ // ═══════════════════════════════════════════════════════
17
+ function getRunsDir() {
18
+ return path.join(resolveCoStarDir(), "cron", "runs");
19
+ }
20
+ function getRunLogPath(jobId) {
21
+ // Sanitize jobId to prevent path traversal
22
+ const safe = jobId.replace(/[^a-zA-Z0-9_-]/g, "_");
23
+ return path.join(getRunsDir(), `${safe}.jsonl`);
24
+ }
25
+ // ═══════════════════════════════════════════════════════
26
+ // WRITE OPERATIONS
27
+ // ═══════════════════════════════════════════════════════
28
+ /** Write queue to prevent concurrent writes */
29
+ const writeQueue = new Map();
30
+ /**
31
+ * Append a run log entry (sequential queue per job).
32
+ */
33
+ export async function appendRunLog(entry) {
34
+ const logPath = getRunLogPath(entry.jobId);
35
+ // Chain writes sequentially per job
36
+ const existing = writeQueue.get(entry.jobId) ?? Promise.resolve();
37
+ const next = existing.then(() => doAppend(logPath, entry));
38
+ writeQueue.set(entry.jobId, next);
39
+ await next;
40
+ }
41
+ async function doAppend(logPath, entry) {
42
+ try {
43
+ const dir = path.dirname(logPath);
44
+ if (!fs.existsSync(dir)) {
45
+ fs.mkdirSync(dir, { recursive: true });
46
+ }
47
+ const line = JSON.stringify(entry) + "\n";
48
+ fs.appendFileSync(logPath, line, "utf-8");
49
+ // Check if pruning needed
50
+ await pruneIfNeeded(logPath);
51
+ }
52
+ catch (error) {
53
+ console.error(`[CRON-LOG] Error appending to ${logPath}:`, error);
54
+ }
55
+ }
56
+ // ═══════════════════════════════════════════════════════
57
+ // READ OPERATIONS
58
+ // ═══════════════════════════════════════════════════════
59
+ /**
60
+ * Read recent run log entries for a job.
61
+ * Returns newest first.
62
+ */
63
+ export function readRunLog(jobId, limit = 200) {
64
+ const logPath = getRunLogPath(jobId);
65
+ if (!fs.existsSync(logPath)) {
66
+ return [];
67
+ }
68
+ try {
69
+ const content = fs.readFileSync(logPath, "utf-8");
70
+ const lines = content.split("\n").filter((l) => l.trim());
71
+ const entries = [];
72
+ for (const line of lines) {
73
+ try {
74
+ entries.push(JSON.parse(line));
75
+ }
76
+ catch {
77
+ // Skip malformed lines
78
+ }
79
+ }
80
+ // Return newest first, limited
81
+ return entries.reverse().slice(0, limit);
82
+ }
83
+ catch (error) {
84
+ console.error(`[CRON-LOG] Error reading ${logPath}:`, error);
85
+ return [];
86
+ }
87
+ }
88
+ /**
89
+ * Read run logs across all jobs (for dashboard).
90
+ * Returns newest first.
91
+ */
92
+ export function readAllRunLogs(limit = 100) {
93
+ const runsDir = getRunsDir();
94
+ if (!fs.existsSync(runsDir)) {
95
+ return [];
96
+ }
97
+ const allEntries = [];
98
+ try {
99
+ const files = fs.readdirSync(runsDir).filter((f) => f.endsWith(".jsonl"));
100
+ for (const file of files) {
101
+ const filePath = path.join(runsDir, file);
102
+ try {
103
+ const content = fs.readFileSync(filePath, "utf-8");
104
+ const lines = content.split("\n").filter((l) => l.trim());
105
+ for (const line of lines) {
106
+ try {
107
+ allEntries.push(JSON.parse(line));
108
+ }
109
+ catch {
110
+ // Skip malformed
111
+ }
112
+ }
113
+ }
114
+ catch {
115
+ // Skip unreadable files
116
+ }
117
+ }
118
+ }
119
+ catch (error) {
120
+ console.error("[CRON-LOG] Error reading all run logs:", error);
121
+ }
122
+ // Sort newest first, limit
123
+ allEntries.sort((a, b) => (b.ts || "").localeCompare(a.ts || ""));
124
+ return allEntries.slice(0, limit);
125
+ }
126
+ // ═══════════════════════════════════════════════════════
127
+ // PRUNING (OpenClaw pattern)
128
+ // ═══════════════════════════════════════════════════════
129
+ const MAX_BYTES = 2 * 1024 * 1024; // 2MB
130
+ const KEEP_LINES = 2000;
131
+ async function pruneIfNeeded(logPath) {
132
+ try {
133
+ const stat = fs.statSync(logPath);
134
+ if (stat.size <= MAX_BYTES)
135
+ return;
136
+ const content = fs.readFileSync(logPath, "utf-8");
137
+ const lines = content.split("\n").filter((l) => l.trim());
138
+ if (lines.length <= KEEP_LINES)
139
+ return;
140
+ // Keep only the most recent KEEP_LINES
141
+ const kept = lines.slice(-KEEP_LINES);
142
+ const newContent = kept.join("\n") + "\n";
143
+ // Atomic write
144
+ const tmpPath = logPath + `.tmp.${process.pid}`;
145
+ fs.writeFileSync(tmpPath, newContent, "utf-8");
146
+ fs.renameSync(tmpPath, logPath);
147
+ console.log(`[CRON-LOG] Pruned ${logPath}: ${lines.length} → ${kept.length} entries`);
148
+ }
149
+ catch {
150
+ // Ignore pruning errors
151
+ }
152
+ }
153
+ //# sourceMappingURL=local-run-log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-run-log.js","sourceRoot":"","sources":["../../src/cron/local-run-log.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Local Cron Store — File-based JSON cron job storage (OpenClaw pattern)
3
+ * Replaces Supabase cron_jobs table. Jobs stored in ~/.costar/cron/jobs.json.
4
+ * Part of Phase 5: Direct Client → Sandbox Architecture.
5
+ *
6
+ * Features:
7
+ * - Atomic writes (temp file → rename)
8
+ * - Auto .bak on every save
9
+ * - OpenClaw-compatible job format
10
+ */
11
+ export type CronJobLocal = {
12
+ id: string;
13
+ user_id: string;
14
+ name: string;
15
+ instruction: string;
16
+ enabled: boolean;
17
+ schedule_type: "cron" | "every" | "at";
18
+ /** Cron expression (for schedule_type=cron) */
19
+ cron_expression?: string;
20
+ /** Interval in ms (for schedule_type=every) */
21
+ schedule_value?: number;
22
+ /** ISO datetime (for schedule_type=at) */
23
+ schedule_at?: string;
24
+ /** IANA timezone */
25
+ timezone?: string;
26
+ /** Delete job after successful run (for one-shot 'at' jobs) */
27
+ delete_after_run?: boolean;
28
+ /** Current status */
29
+ status: "active" | "paused" | "completed" | "error";
30
+ /** Next scheduled run time */
31
+ next_run_at?: string;
32
+ /** Retry tracking */
33
+ retry_count: number;
34
+ max_retries: number;
35
+ /** Metadata */
36
+ created_at: string;
37
+ updated_at: string;
38
+ };
39
+ export type CronStoreFile = {
40
+ version: 1;
41
+ jobs: CronJobLocal[];
42
+ };
43
+ /**
44
+ * Load jobs from disk. Returns empty store if file doesn't exist.
45
+ */
46
+ export declare function loadJobs(): CronStoreFile;
47
+ /**
48
+ * Save jobs to disk with atomic write + backup.
49
+ */
50
+ export declare function saveJobs(store: CronStoreFile): void;
51
+ /**
52
+ * Get all jobs for a user.
53
+ */
54
+ export declare function getAllJobs(userId: string, enabledOnly?: boolean): CronJobLocal[];
55
+ /**
56
+ * Get a job by ID.
57
+ */
58
+ export declare function getJobById(jobId: string): CronJobLocal | null;
59
+ /**
60
+ * Get jobs that are due to run (next_run_at <= now).
61
+ */
62
+ export declare function getDueJobs(userId: string): CronJobLocal[];
63
+ /**
64
+ * Create a new cron job.
65
+ */
66
+ export declare function addJob(params: {
67
+ userId: string;
68
+ name: string;
69
+ instruction: string;
70
+ scheduleType: "cron" | "every" | "at";
71
+ cronExpression?: string;
72
+ scheduleValue?: number;
73
+ scheduleAt?: string;
74
+ timezone?: string;
75
+ deleteAfterRun?: boolean;
76
+ maxRetries?: number;
77
+ }): CronJobLocal;
78
+ /**
79
+ * Update an existing job.
80
+ */
81
+ export declare function updateJob(jobId: string, updates: Partial<CronJobLocal>): CronJobLocal | null;
82
+ /**
83
+ * Remove a job.
84
+ */
85
+ export declare function removeJob(jobId: string): boolean;
86
+ //# sourceMappingURL=local-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-store.d.ts","sourceRoot":"","sources":["../../src/cron/local-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAUH,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IACvC,+CAA+C;IAC/C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+CAA+C;IAC/C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,0CAA0C;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,qBAAqB;IACrB,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,WAAW,GAAG,OAAO,CAAC;IACpD,8BAA8B;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qBAAqB;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,CAAC,CAAC;IACX,IAAI,EAAE,YAAY,EAAE,CAAC;CACtB,CAAC;AAkBF;;GAEG;AACH,wBAAgB,QAAQ,IAAI,aAAa,CAoCxC;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAwBnD;AAiBD;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,GAAE,OAAe,GAAG,YAAY,EAAE,CAOvF;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAG7D;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,EAAE,CAWzD;AAED;;GAEG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IACtC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,YAAY,CA4Bf;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,GAAG,IAAI,CAmB5F;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAYhD"}
@@ -0,0 +1,199 @@
1
+ /**
2
+ * Local Cron Store — File-based JSON cron job storage (OpenClaw pattern)
3
+ * Replaces Supabase cron_jobs table. Jobs stored in ~/.costar/cron/jobs.json.
4
+ * Part of Phase 5: Direct Client → Sandbox Architecture.
5
+ *
6
+ * Features:
7
+ * - Atomic writes (temp file → rename)
8
+ * - Auto .bak on every save
9
+ * - OpenClaw-compatible job format
10
+ */
11
+ import fs from "node:fs";
12
+ import path from "node:path";
13
+ import { resolveCoStarDir } from "../cli/paths.js";
14
+ // ═══════════════════════════════════════════════════════
15
+ // PATHS
16
+ // ═══════════════════════════════════════════════════════
17
+ function getCronDir() {
18
+ return path.join(resolveCoStarDir(), "cron");
19
+ }
20
+ function getStorePath() {
21
+ return path.join(getCronDir(), "jobs.json");
22
+ }
23
+ // ═══════════════════════════════════════════════════════
24
+ // FILE I/O (OpenClaw atomic write pattern)
25
+ // ═══════════════════════════════════════════════════════
26
+ /**
27
+ * Load jobs from disk. Returns empty store if file doesn't exist.
28
+ */
29
+ export function loadJobs() {
30
+ const storePath = getStorePath();
31
+ try {
32
+ if (!fs.existsSync(storePath)) {
33
+ return { version: 1, jobs: [] };
34
+ }
35
+ const raw = fs.readFileSync(storePath, "utf-8");
36
+ const parsed = JSON.parse(raw);
37
+ // Validate
38
+ if (!parsed.version || !Array.isArray(parsed.jobs)) {
39
+ console.warn("[CRON-STORE] Invalid store file format, returning empty");
40
+ return { version: 1, jobs: [] };
41
+ }
42
+ return parsed;
43
+ }
44
+ catch (error) {
45
+ console.error("[CRON-STORE] Error loading store:", error);
46
+ // Try .bak file
47
+ const bakPath = storePath + ".bak";
48
+ if (fs.existsSync(bakPath)) {
49
+ try {
50
+ const raw = fs.readFileSync(bakPath, "utf-8");
51
+ const parsed = JSON.parse(raw);
52
+ console.log("[CRON-STORE] Recovered from backup file");
53
+ return parsed;
54
+ }
55
+ catch {
56
+ console.error("[CRON-STORE] Backup file also corrupted");
57
+ }
58
+ }
59
+ return { version: 1, jobs: [] };
60
+ }
61
+ }
62
+ /**
63
+ * Save jobs to disk with atomic write + backup.
64
+ */
65
+ export function saveJobs(store) {
66
+ const storePath = getStorePath();
67
+ const dir = getCronDir();
68
+ // Ensure directory exists
69
+ if (!fs.existsSync(dir)) {
70
+ fs.mkdirSync(dir, { recursive: true });
71
+ }
72
+ const json = JSON.stringify(store, null, 2);
73
+ // Create .bak of current file
74
+ if (fs.existsSync(storePath)) {
75
+ try {
76
+ fs.copyFileSync(storePath, storePath + ".bak");
77
+ }
78
+ catch {
79
+ // Ignore backup errors
80
+ }
81
+ }
82
+ // Atomic write: temp file → rename
83
+ const tmpPath = storePath + `.tmp.${process.pid}`;
84
+ fs.writeFileSync(tmpPath, json, "utf-8");
85
+ fs.renameSync(tmpPath, storePath);
86
+ }
87
+ // ═══════════════════════════════════════════════════════
88
+ // CRUD OPERATIONS
89
+ // ═══════════════════════════════════════════════════════
90
+ /**
91
+ * Generate a random ID.
92
+ */
93
+ function generateId() {
94
+ const bytes = new Uint8Array(16);
95
+ crypto.getRandomValues(bytes);
96
+ return Array.from(bytes)
97
+ .map((b) => b.toString(16).padStart(2, "0"))
98
+ .join("");
99
+ }
100
+ /**
101
+ * Get all jobs for a user.
102
+ */
103
+ export function getAllJobs(userId, enabledOnly = false) {
104
+ const store = loadJobs();
105
+ let jobs = store.jobs.filter((j) => j.user_id === userId);
106
+ if (enabledOnly) {
107
+ jobs = jobs.filter((j) => j.enabled);
108
+ }
109
+ return jobs;
110
+ }
111
+ /**
112
+ * Get a job by ID.
113
+ */
114
+ export function getJobById(jobId) {
115
+ const store = loadJobs();
116
+ return store.jobs.find((j) => j.id === jobId) ?? null;
117
+ }
118
+ /**
119
+ * Get jobs that are due to run (next_run_at <= now).
120
+ */
121
+ export function getDueJobs(userId) {
122
+ const store = loadJobs();
123
+ const now = new Date().toISOString();
124
+ return store.jobs.filter((j) => {
125
+ if (j.user_id !== userId)
126
+ return false;
127
+ if (!j.enabled)
128
+ return false;
129
+ if (j.status !== "active")
130
+ return false;
131
+ if (!j.next_run_at)
132
+ return false;
133
+ return j.next_run_at <= now;
134
+ });
135
+ }
136
+ /**
137
+ * Create a new cron job.
138
+ */
139
+ export function addJob(params) {
140
+ const store = loadJobs();
141
+ const now = new Date().toISOString();
142
+ const job = {
143
+ id: generateId(),
144
+ user_id: params.userId,
145
+ name: params.name,
146
+ instruction: params.instruction,
147
+ enabled: true,
148
+ schedule_type: params.scheduleType,
149
+ cron_expression: params.cronExpression,
150
+ schedule_value: params.scheduleValue,
151
+ schedule_at: params.scheduleAt,
152
+ timezone: params.timezone,
153
+ delete_after_run: params.deleteAfterRun,
154
+ status: "active",
155
+ retry_count: 0,
156
+ max_retries: params.maxRetries ?? 3,
157
+ created_at: now,
158
+ updated_at: now,
159
+ };
160
+ store.jobs.push(job);
161
+ saveJobs(store);
162
+ console.log(`[CRON-STORE] Created job: ${job.name} (${job.id})`);
163
+ return job;
164
+ }
165
+ /**
166
+ * Update an existing job.
167
+ */
168
+ export function updateJob(jobId, updates) {
169
+ const store = loadJobs();
170
+ const idx = store.jobs.findIndex((j) => j.id === jobId);
171
+ if (idx === -1)
172
+ return null;
173
+ const job = store.jobs[idx];
174
+ const updated = {
175
+ ...job,
176
+ ...updates,
177
+ id: job.id, // Never overwrite ID
178
+ user_id: job.user_id, // Never overwrite user
179
+ updated_at: new Date().toISOString(),
180
+ };
181
+ store.jobs[idx] = updated;
182
+ saveJobs(store);
183
+ return updated;
184
+ }
185
+ /**
186
+ * Remove a job.
187
+ */
188
+ export function removeJob(jobId) {
189
+ const store = loadJobs();
190
+ const before = store.jobs.length;
191
+ store.jobs = store.jobs.filter((j) => j.id !== jobId);
192
+ if (store.jobs.length < before) {
193
+ saveJobs(store);
194
+ console.log(`[CRON-STORE] Removed job: ${jobId}`);
195
+ return true;
196
+ }
197
+ return false;
198
+ }
199
+ //# sourceMappingURL=local-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-store.js","sourceRoot":"","sources":["../../src/cron/local-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Local SQLite Database — Activity, Assets, Projects
3
+ * Replaces Supabase for structured data. Runs on each sandbox.
4
+ * Part of Phase 4: Direct Client → Sandbox Architecture.
5
+ *
6
+ * Uses better-sqlite3 for synchronous, fast queries.
7
+ * Vector search via sqlite-vec for embeddings.
8
+ */
9
+ /**
10
+ * Initialize the database. Creates tables if they don't exist.
11
+ */
12
+ export declare function initDatabase(): Promise<void>;
13
+ /**
14
+ * Close the database connection.
15
+ */
16
+ export declare function closeDatabase(): void;
17
+ export type ActivityRow = {
18
+ id: string;
19
+ user_id: string;
20
+ request: string | null;
21
+ response: string | null;
22
+ status: string;
23
+ executor: string;
24
+ source: string | null;
25
+ tool_calls: number;
26
+ duration: number | null;
27
+ error: string | null;
28
+ keywords: string | null;
29
+ categories: string | null;
30
+ sandbox_id: string | null;
31
+ created_at: string;
32
+ updated_at: string;
33
+ };
34
+ export declare function createActivity(params: {
35
+ userId: string;
36
+ request: string;
37
+ executor: "client" | "server";
38
+ source?: string;
39
+ sandboxId?: string;
40
+ embedding?: number[];
41
+ }): ActivityRow;
42
+ export declare function completeActivity(params: {
43
+ activityId: string;
44
+ response: string;
45
+ request?: string;
46
+ toolCalls?: number;
47
+ duration?: number;
48
+ keywords?: string;
49
+ categories?: string[];
50
+ embedding?: number[];
51
+ }): ActivityRow;
52
+ export declare function failActivity(params: {
53
+ activityId: string;
54
+ error: string;
55
+ duration?: number;
56
+ }): ActivityRow;
57
+ export declare function getActivityById(activityId: string): ActivityRow | null;
58
+ export declare function getRecentActivity(userId: string, limit?: number): ActivityRow[];
59
+ export declare function getActivityByStatus(userId: string, status: string, limit?: number): ActivityRow[];
60
+ export declare function getNewClientActivitySince(userId: string, afterTimestamp?: string | null, limit?: number): ActivityRow[];
61
+ export declare function searchActivityByKeywords(userId: string, query: string, limit?: number): ActivityRow[];
62
+ /**
63
+ * Semantic vector search via sqlite-vec.
64
+ * Falls back to empty results if sqlite-vec not loaded.
65
+ */
66
+ export declare function searchActivityByEmbedding(embedding: number[], userId: string, limit?: number, threshold?: number): Array<ActivityRow & {
67
+ similarity: number;
68
+ }>;
69
+ export declare function getActivityStats(userId: string): {
70
+ total: number;
71
+ pending: number;
72
+ completed: number;
73
+ failed: number;
74
+ avgDuration?: number;
75
+ avgToolCalls?: number;
76
+ };
77
+ export type AssetRow = {
78
+ id: string;
79
+ user_id: string;
80
+ name: string | null;
81
+ type: string | null;
82
+ local_file_path: string | null;
83
+ remote_url: string | null;
84
+ description: string | null;
85
+ sandbox_id: string | null;
86
+ created_at: string;
87
+ updated_at: string;
88
+ };
89
+ export declare function upsertAsset(params: {
90
+ userId: string;
91
+ name?: string;
92
+ type?: string;
93
+ localFilePath?: string;
94
+ remoteUrl?: string;
95
+ description?: string;
96
+ sandboxId?: string;
97
+ }): AssetRow;
98
+ export declare function getAssets(userId: string, limit?: number): AssetRow[];
99
+ export declare function getAssetById(assetId: string): AssetRow | null;
100
+ export declare function linkAssetToActivity(params: {
101
+ requestId: string;
102
+ assetId: string;
103
+ action?: string;
104
+ }): void;
105
+ export type ProjectRow = {
106
+ id: string;
107
+ user_id: string;
108
+ name: string | null;
109
+ description: string | null;
110
+ sandbox_id: string | null;
111
+ project_path: string | null;
112
+ convo_summary: string | null;
113
+ is_active: number;
114
+ created_at: string;
115
+ updated_at: string;
116
+ };
117
+ export declare function upsertProject(params: {
118
+ userId: string;
119
+ name?: string;
120
+ description?: string;
121
+ sandboxId?: string;
122
+ projectPath?: string;
123
+ convoSummary?: string;
124
+ isActive?: boolean;
125
+ id?: string;
126
+ }): ProjectRow;
127
+ export declare function getProjects(userId: string, limit?: number): ProjectRow[];
128
+ export declare function getProjectById(projectId: string): ProjectRow | null;
129
+ export declare function linkProjectToActivity(params: {
130
+ requestId: string;
131
+ projectId: string;
132
+ action?: string;
133
+ }): void;
134
+ //# sourceMappingURL=local-database.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-database.d.ts","sourceRoot":"","sources":["../../src/db/local-database.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AA8BH;;GAEG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAsHlD;AAUD;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAMpC;AAMD,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,cAAc,CAAC,MAAM,EAAE;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB,GAAG,WAAW,CAuBd;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB,GAAG,WAAW,CA6Cd;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,WAAW,CASd;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAGtE;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,WAAW,EAAE,CAKnF;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,WAAW,EAAE,CAKrG;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,GAAE,MAAW,GAAG,WAAW,EAAE,CAc3H;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,WAAW,EAAE,CASzG;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EAAE,EACnB,MAAM,EAAE,MAAM,EACd,KAAK,GAAE,MAAW,EAClB,SAAS,GAAE,MAAY,GACtB,KAAK,CAAC,WAAW,GAAG;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAiC7C;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CA2BA;AAMD,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,WAAW,CAAC,MAAM,EAAE;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,QAAQ,CAuBX;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,GAAE,MAAY,GAAG,QAAQ,EAAE,CAKzE;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAG7D;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,IAAI,CAOP;AAMD,MAAM,MAAM,UAAU,GAAG;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,aAAa,CAAC,MAAM,EAAE;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,GAAG,UAAU,CA+Bb;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,GAAE,MAAY,GAAG,UAAU,EAAE,CAK7E;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAGnE;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,IAAI,CAOP"}