@crewx/sdk 0.9.0-rc.10 → 0.9.0-rc.12
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/dist/config/pricing.d.ts +2 -2
- package/dist/config/pricing.types.d.ts +0 -10
- package/dist/esm/index.js +110 -76
- package/dist/esm/plugins/index.js +97 -61
- package/dist/esm/repository/index.js +84 -48
- package/dist/esm/testing/index.js +1 -1
- package/dist/facade/Crewx.d.ts +3 -0
- package/dist/index.js +111 -77
- package/dist/plugins/index.js +97 -61
- package/dist/provider/bridge.d.ts +1 -0
- package/dist/repository/index.d.ts +1 -1
- package/dist/repository/index.js +84 -48
- package/dist/repository/task.repository.d.ts +15 -0
- package/dist/testing/index.js +1 -1
- package/package.json +1 -1
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import*as $ from'path';import $__default,{join,dirname}from'path';import {fileURLToPath}from'url';import {existsSync,mkdirSync,writeFileSync,appendFileSync,readFileSync}from'fs';import
|
|
1
|
+
import*as $ from'path';import $__default,{join,dirname}from'path';import {fileURLToPath}from'url';import {existsSync,mkdirSync,writeFileSync,appendFileSync,readFileSync}from'fs';import Yt,{homedir}from'os';import {createHash}from'crypto';import {sql,eq,desc,and,or,isNull,like,asc,inArray,gte,lt as lt$1}from'drizzle-orm';import {sqliteTable,text,integer,real,index,unique,uniqueIndex}from'drizzle-orm/sqlite-core';var tt=(d=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(d,{get:(t,e)=>(typeof require<"u"?require:t)[e]}):d)(function(d){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+d+'" is not supported')});var Bt=()=>fileURLToPath(import.meta.url),Ft=()=>$__default.dirname(Bt()),k=Ft();var U=class{detach(t){}};function St(d){let t=e=>String(e).padStart(2,"0");return `${d.getFullYear()}${t(d.getMonth()+1)}${t(d.getDate())}T${t(d.getHours())}${t(d.getMinutes())}${t(d.getSeconds())}`}var ut=class extends U{name="file-logger";unsubs=[];logFiles=new Map;logsDir;version;constructor(t){super(),this.logsDir=join(t?.workspaceRoot??process.cwd(),".crewx","logs"),this.version=t?.version??"unknown";}attach(t){this.unsubs.push(t.on("task:start",e=>{try{existsSync(this.logsDir)||mkdirSync(this.logsDir,{recursive:!0});let n=St(e.timestamp),s=join(this.logsDir,`${n}_${e.traceId}.log`);this.logFiles.set(e.traceId,s);let o=`=== TASK LOG: ${e.traceId} ===
|
|
2
2
|
CrewX Version: ${this.version}
|
|
3
3
|
Mode: ${e.mode}
|
|
4
4
|
Agent: ${e.agentRef}
|
|
5
5
|
Started: ${e.timestamp.toLocaleString()}
|
|
6
6
|
Message: ${e.message}
|
|
7
7
|
|
|
8
|
-
`;writeFileSync(
|
|
9
|
-
`,"utf8");}catch{}}),t.on("task:end",e=>{try{let
|
|
10
|
-
[${
|
|
11
|
-
`;appendFileSync(
|
|
12
|
-
${
|
|
13
|
-
`)}`);let
|
|
8
|
+
`;writeFileSync(s,o,{encoding:"utf8",mode:384});}catch{}}),t.on("task:output",e=>{try{let n=this.logFiles.get(e.traceId);if(!n)return;let s=new Date().toISOString();appendFileSync(n,`[${s}] STDOUT: ${e.output}
|
|
9
|
+
`,"utf8");}catch{}}),t.on("task:end",e=>{try{let n=this.logFiles.get(e.traceId);if(!n)return;let s=new Date().toLocaleString(),o=e.error?`failed: ${e.error.message}`:"completed successfully",i=`[${s}] INFO: Task ${o} in ${e.durationMs}ms
|
|
10
|
+
[${s}] INFO: Process closed with exit code: ${e.error?1:0}
|
|
11
|
+
`;appendFileSync(n,i,"utf8"),this.logFiles.delete(e.traceId);}catch{}}));}detach(t){this.unsubs.forEach(e=>e()),this.unsubs=[],this.logFiles.clear();}};function Kt(d){let t=$.resolve(d);return process.platform==="win32"&&(t=t.replace(/\\/g,"/"),t=t.replace(/^([A-Z]):/,(e,n)=>`${n.toLowerCase()}:`)),t.length>1&&!/^[a-zA-Z]:\/$/.test(t)&&(t=t.replace(/\/+$/,"")),t}function yt(d){let t=Kt(d);return createHash("sha256").update(t).digest("hex")}var X=class{resolveDbPath(){return process.env.CREWX_DB?process.env.CREWX_DB:process.env.CREWX_TRACES_DB?process.env.CREWX_TRACES_DB:join(Yt.homedir(),".crewx","crewx.db")}resolveDbPaths(){return [this.resolveDbPath()]}isMissingTableError(t){return t instanceof Error&&/no such table:/i.test(t.message)}dbExists(t){return existsSync(t??this.resolveDbPath())}};function R(d){let t=tt("better-sqlite3"),{drizzle:e}=tt("drizzle-orm/better-sqlite3"),n=new t(d);return n.exec("PRAGMA journal_mode = WAL"),n.exec("PRAGMA busy_timeout = 5000"),n.exec("PRAGMA foreign_keys = ON"),{db:e(n),runRaw:(s,o=[])=>n.prepare(s).run(...o),close:()=>n.close()}}var At=new Set,Jt={agent_id:"TEXT",status:"TEXT DEFAULT 'running'",started_at:"TEXT",trace_id:"TEXT",parent_task_id:"TEXT",crewx_version:"TEXT",pid:"INTEGER",thread_id:"TEXT",workspace_id:"TEXT",workspace_ref:"TEXT",workspace_name:"TEXT",project_id:"TEXT",project_name:"TEXT"};function pt(d,t){return (d.get(`SELECT count(*) as cnt FROM sqlite_master WHERE type='table' AND name='${t}'`)?.cnt??0)>0}function Vt(d,t){if(t>0||!pt(d,"tasks"))return;let e=d.all("PRAGMA table_info(tasks)"),n=new Set(e.map(s=>s.name));for(let[s,o]of Object.entries(Jt))n.has(s)||d.run(`ALTER TABLE tasks ADD COLUMN ${s} ${o}`);}var Qt={"0002_normalize_task_names":{workspace_name:"TEXT",project_name:"TEXT"}};function Zt(d,t,e){if(!pt(d,"__drizzle_migrations")||!pt(d,"tasks"))return;let n=d.all(e`SELECT hash FROM __drizzle_migrations`),s=new Set(n.map(i=>i.hash)),o=JSON.parse(readFileSync($__default.join(t,"meta/_journal.json"),"utf-8"));for(let i of o.entries){let a=Qt[i.tag];if(!a)continue;let c=$__default.join(t,`${i.tag}.sql`);if(!existsSync(c))continue;let l=readFileSync(c,"utf-8"),u=createHash("sha256").update(l).digest("hex");if(s.has(u))continue;let f=d.all("PRAGMA table_info(tasks)"),m=new Set(f.map(T=>T.name));for(let[T,G]of Object.entries(a))m.has(T)||(d.run(`ALTER TABLE tasks ADD COLUMN ${T} ${G}`),m.add(T));}}function te(d,t,e){let n=d.all(e`SELECT hash FROM __drizzle_migrations`),s=new Set(n.map(i=>i.hash)),o=JSON.parse(readFileSync($__default.join(t,"meta/_journal.json"),"utf-8"));for(let i of o.entries){let a=$__default.join(t,`${i.tag}.sql`);if(!existsSync(a))continue;let c=readFileSync(a,"utf-8"),l=createHash("sha256").update(c).digest("hex");if(s.has(l))continue;let u=/ALTER\s+TABLE\s+[`"]?(\w+)[`"]?\s+ADD\s+[`"]?(\w+)[`"]?/gi,f=[],m;for(;(m=u.exec(c))!==null;)f.push({table:m[1],column:m[2]});if(f.length===0||!c.split(/-->\s*statement-breakpoint/).map(M=>M.trim()).filter(Boolean).every(M=>/^ALTER\s+TABLE\s+.+\s+ADD\s+/i.test(M)))continue;f.every(({table:M,column:O})=>d.all(`PRAGMA table_info("${M}")`).some(L=>L.name===O))&&d.run(e`INSERT INTO __drizzle_migrations (hash, created_at) VALUES (${l}, ${i.when})`);}}function ee(d){let{migrate:t}=tt("drizzle-orm/better-sqlite3/migrator"),{sql:e}=tt("drizzle-orm"),n=[$__default.join(k,"../migrations"),$__default.join(k,"migrations"),$__default.join(k,"../../../../drizzle/migrations"),$__default.join(process.cwd(),"drizzle/migrations")],s=n.find(l=>existsSync($__default.join(l,"meta/_journal.json")));if(!s)throw new Error(`migrations folder not found. Searched:
|
|
12
|
+
${n.join(`
|
|
13
|
+
`)}`);let o=d.get(e`SELECT count(*) as cnt FROM sqlite_master WHERE type='table' AND name='__drizzle_migrations'`),i=0;o?.cnt&&(i=d.get(e`SELECT count(*) as cnt FROM __drizzle_migrations`)?.cnt??0),Vt(d,i),o?.cnt&&(te(d,s,e),Zt(d,s,e)),t(d,{migrationsFolder:s});let c=(d.get(e`SELECT count(*) as cnt FROM __drizzle_migrations`)?.cnt??0)-i;if(c>0){let l=o?.cnt?"Database migrated":"Database initialized";console.error(`[crewx] ${l} (${c} migration${c>1?"s":""} applied).`);}}function nt(d,t){At.has(t)||(ee(d),At.add(t));}var _=class extends Error{code;cause;constructor(t,e,n){super(e),this.name="RepositoryError",this.code=t,this.cause=n,Object.setPrototypeOf(this,new.target.prototype);}};var Y=sqliteTable("workspaces",{id:text("id").primaryKey(),slug:text("slug").notNull().unique(),name:text("name").notNull(),workspace_path:text("workspace_path"),description:text("description"),is_active:integer("is_active").notNull().default(1),created_at:text("created_at").notNull(),updated_at:text("updated_at").notNull()});var r=sqliteTable("tasks",{id:text("id").primaryKey(),agent_id:text("agent_id").notNull(),user_id:text("user_id"),prompt:text("prompt").notNull(),mode:text("mode").notNull().default("execute"),status:text("status").notNull().default("running"),result:text("result"),error:text("error"),started_at:text("started_at").notNull(),completed_at:text("completed_at"),duration_ms:integer("duration_ms"),metadata:text("metadata"),workspace_id:text("workspace_id"),trace_id:text("trace_id"),parent_task_id:text("parent_task_id"),caller_agent_id:text("caller_agent_id"),model:text("model"),platform:text("platform").default("cli"),crewx_version:text("crewx_version"),input_tokens:integer("input_tokens").default(0),output_tokens:integer("output_tokens").default(0),cost_usd:real("cost_usd").default(0),pid:integer("pid"),rendered_prompt:text("rendered_prompt"),command:text("command"),coding_agent_command:text("coding_agent_command"),exit_code:integer("exit_code"),logs:text("logs"),thread_id:text("thread_id"),workspace_ref:text("workspace_ref"),project_id:text("project_id"),project_ref:text("project_ref"),cached_input_tokens:integer("cached_input_tokens").default(0),run_epoch:integer("run_epoch").default(0)},d=>({idx_tasks_agent_id:index("idx_tasks_agent_id").on(d.agent_id),idx_tasks_status:index("idx_tasks_status").on(d.status),idx_tasks_started_at:index("idx_tasks_started_at").on(d.started_at),idx_tasks_trace_id:index("idx_tasks_trace_id").on(d.trace_id),idx_tasks_parent_task_id:index("idx_tasks_parent_task_id").on(d.parent_task_id),idx_tasks_crewx_version:index("idx_tasks_crewx_version").on(d.crewx_version),idx_tasks_pid:index("idx_tasks_pid").on(d.pid),idx_tasks_thread_id:index("idx_tasks_thread_id").on(d.thread_id),idx_tasks_workspace_id:index("idx_tasks_workspace_id").on(d.workspace_id),idx_tasks_workspace_ref:index("idx_tasks_workspace_ref").on(d.workspace_ref),idx_tasks_project_id:index("idx_tasks_project_id").on(d.project_id),idx_tasks_ws_started:index("idx_tasks_ws_started").on(d.workspace_id,d.started_at)}));var p=sqliteTable("threads",{id:text("id").primaryKey(),workspace_id:text("workspace_id").references(()=>Y.id,{onDelete:"set null"}),platform:text("platform").notNull().default("cli"),title:text("title"),first_message:text("first_message"),last_message:text("last_message"),message_count:integer("message_count").notNull().default(0),created_at:text("created_at").notNull(),updated_at:text("updated_at").notNull(),metadata:text("metadata"),title_locked:integer("title_locked").notNull().default(0),pinned:integer("pinned").notNull().default(0),starred:integer("starred").notNull().default(0)},d=>({idx_threads_updated_at:index("idx_threads_updated_at").on(d.updated_at),idx_threads_workspace_id:index("idx_threads_workspace_id").on(d.workspace_id)}));var ce=sqliteTable("spans",{id:text("id").primaryKey(),task_id:text("task_id").references(()=>r.id,{onDelete:"set null"}),parent_span_id:text("parent_span_id").references(()=>ce.id,{onDelete:"set null"}),name:text("name").notNull(),kind:text("kind").notNull().default("internal"),status:text("status").notNull().default("ok"),started_at:text("started_at").notNull(),completed_at:text("completed_at"),duration_ms:integer("duration_ms"),input:text("input"),output:text("output"),error:text("error"),attributes:text("attributes")},d=>({idx_spans_task_id:index("idx_spans_task_id").on(d.task_id),idx_spans_parent_span_id:index("idx_spans_parent_span_id").on(d.parent_span_id)}));sqliteTable("tool_calls",{id:text("id").primaryKey(),task_id:text("task_id").references(()=>r.id,{onDelete:"cascade"}),session_id:text("session_id"),tool_name:text("tool_name").notNull(),files:text("files"),input:text("input"),output:text("output"),duration_ms:integer("duration_ms"),timestamp:text("timestamp").notNull()},d=>({idx_tool_calls_task_id:index("idx_tool_calls_task_id").on(d.task_id),idx_tool_calls_tool_name:index("idx_tool_calls_tool_name").on(d.tool_name),idx_tool_calls_timestamp:index("idx_tool_calls_timestamp").on(d.timestamp)}));sqliteTable("thread_boxes",{id:text("id").primaryKey(),thread_id:text("thread_id").notNull().references(()=>p.id,{onDelete:"cascade"}),seq:integer("seq").notNull(),first_task_id:text("first_task_id").notNull(),mid_task_id:text("mid_task_id").notNull(),last_task_id:text("last_task_id").notNull(),task_count:integer("task_count").notNull(),summary:text("summary"),source_tokens:integer("source_tokens").notNull(),summary_tokens:integer("summary_tokens"),created_at:text("created_at").notNull()},d=>({idx_thread_boxes_thread_id:index("idx_thread_boxes_thread_id").on(d.thread_id),idx_thread_boxes_seq:index("idx_thread_boxes_seq").on(d.thread_id,d.seq),uniq_thread_boxes_thread_seq:unique().on(d.thread_id,d.seq)}));sqliteTable("request_logs",{id:text("id").primaryKey(),path:text("path").notNull(),method:text("method").notNull(),status_code:integer("status_code").notNull(),duration_ms:integer("duration_ms").notNull(),ip:text("ip"),request_headers:text("request_headers"),response_headers:text("response_headers"),request_body:text("request_body"),response_body:text("response_body"),query:text("query"),user_id:text("user_id"),project_id:text("project_id"),partition_key:text("partition_key").notNull(),timestamp:text("timestamp").notNull().default(sql`(datetime('now'))`),metadata:text("metadata")},d=>({idx_request_logs_timestamp:index("idx_request_logs_timestamp").on(d.timestamp),idx_request_logs_path:index("idx_request_logs_path").on(d.path),idx_request_logs_status_code:index("idx_request_logs_status_code").on(d.status_code),idx_request_logs_partition_key:index("idx_request_logs_partition_key").on(d.partition_key)}));sqliteTable("usage_limit_snapshots",{id:text("id").primaryKey(),provider:text("provider").notNull(),account_ref:text("account_ref").notNull().default("default"),limit_window:text("limit_window").notNull(),bucket_start:text("bucket_start").notNull(),captured_at:text("captured_at").notNull(),used_percent:integer("used_percent").notNull(),remaining_percent:integer("remaining_percent").notNull(),resets_at:text("resets_at"),source:text("source").notNull(),metadata:text("metadata")},d=>({uniq_usage_limit_snapshots_bucket:uniqueIndex("uniq_usage_limit_snapshots_bucket").on(d.provider,d.account_ref,d.limit_window,d.bucket_start),idx_usage_limit_snapshots_window_bucket:index("idx_usage_limit_snapshots_window_bucket").on(d.limit_window,d.bucket_start),idx_usage_limit_snapshots_provider_window_bucket:index("idx_usage_limit_snapshots_provider_window_bucket").on(d.provider,d.limit_window,d.bucket_start)}));function $t(d){let t=d.toLowerCase().trim();t=t.replace(/\[[^\]]*\]$/g,"");let e=t.lastIndexOf("/");return e>=0&&(t=t.slice(e+1)),t=t.replace(/-\d{8}$/,""),t}var B="2026-05-09",Re="0.8.9-rc.13",F=10,z=parseInt(Re.split("rc.")[1]),ye=new Set(["workflow","mcp"]),Ae=600*1e3,dt=class extends X{dbPath;pidNullObservedSince=new Map;constructor(t={}){super(),t.dbPath?this.dbPath=t.dbPath:t.dbRoot&&(this.dbPath=join(t.dbRoot,".crewx","crewx.db"));}resolveDbPath(){return this.dbPath?this.dbPath:super.resolveDbPath()}openHandle(t){let e=this.resolveDbPath();if(t){let s=dirname(e);existsSync(s)||mkdirSync(s,{recursive:true});}else if(!existsSync(e))throw new _("NOT_FOUND","Database not found");let n=R(e);if(t)try{nt(n.db,e);}catch(s){throw n.close(),s}return n}startTask(t){let e=this.openHandle(true);try{e.db.insert(r).values({id:t.id,agent_id:t.agentId,prompt:t.prompt,mode:t.mode,status:t.status,started_at:t.startedAt,pid:t.pid??null,parent_task_id:t.parentTaskId??null,caller_agent_id:t.callerAgentId??null,trace_id:t.traceId??null,command:t.command??null,metadata:t.metadata??null,workspace_id:t.workspaceId??null,platform:t.platform??"cli",crewx_version:t.crewxVersion??null,thread_id:t.threadId??null,model:t.model??null,rendered_prompt:t.renderedPrompt??null,coding_agent_command:t.codingAgentCommand??null}).onConflictDoUpdate({target:r.id,set:{pid:sql`COALESCE(excluded.pid, ${r.pid})`},setWhere:eq(r.status,"running")}).run();}catch(n){throw n instanceof _?n:new _("DB_ERROR","Failed to start task",n)}finally{e.close();}}finishTask(t){let e=this.openHandle(true);try{let n=t.runEpoch??null;e.runRaw(`UPDATE tasks SET status=?, result=?, error=?, completed_at=?, duration_ms=?,
|
|
14
14
|
exit_code=?, input_tokens=?, output_tokens=?, cached_input_tokens=?, cost_usd=?,
|
|
15
15
|
model=COALESCE(?, model)
|
|
16
|
-
WHERE id=? AND status='running' AND COALESCE(run_epoch, 0) = COALESCE(?, 0)`,[t.status,t.result??null,t.error??null,t.completedAt,t.durationMs??null,t.exitCode??null,t.inputTokens??0,t.outputTokens??0,t.cachedInputTokens??0,t.costUsd??0,t.model??null,t.id,
|
|
16
|
+
WHERE id=? AND status='running' AND COALESCE(run_epoch, 0) = COALESCE(?, 0)`,[t.status,t.result??null,t.error??null,t.completedAt,t.durationMs??null,t.exitCode??null,t.inputTokens??0,t.outputTokens??0,t.cachedInputTokens??0,t.costUsd??0,t.model??null,t.id,n]);}catch(n){throw n instanceof _?n:new _("DB_ERROR","Failed to finish task",n)}finally{e.close();}}appendLog(t,e){let n=this.openHandle(true);try{n.db.transaction(s=>{let o=s.select({logs:r.logs}).from(r).where(eq(r.id,t)).limit(1).get(),i=o?.logs?JSON.parse(o.logs):[];i.push(e),s.update(r).set({logs:JSON.stringify(i)}).where(eq(r.id,t)).run();},{behavior:"immediate"});}catch(s){throw s instanceof _?s:new _("DB_ERROR","Failed to append log",s)}finally{n.close();}}getRunningTasks(){if(!this.dbExists())return [];let t=this.openHandle(false);try{return t.db.select().from(r).where(eq(r.status,"running")).orderBy(desc(r.started_at)).all()}catch(e){throw new _("DB_ERROR","Failed to get running tasks",e)}finally{t.close();}}getAllTasks(){if(!this.dbExists())return [];let t=this.openHandle(false);try{return t.db.select().from(r).orderBy(desc(r.started_at)).limit(100).all()}catch(e){throw new _("DB_ERROR","Failed to get all tasks",e)}finally{t.close();}}getTask(t){if(!this.dbExists())return;let e=this.openHandle(false);try{return e.db.select().from(r).where(eq(r.id,t)).limit(1).get()??void 0}catch(n){throw new _("DB_ERROR","Failed to get task",n)}finally{e.close();}}killTask(t){if(!this.dbExists())return {killed:false};let e=this.openHandle(true);try{let n=e.db.select({id:r.id,status:r.status,pid:r.pid}).from(r).where(eq(r.id,t)).limit(1).get();if(!n||n.status!=="running")return {killed:!1};if(n.pid)try{process.kill(n.pid,"SIGTERM");}catch{}return e.db.update(r).set({status:"failed",error:"Killed by user",completed_at:new Date().toISOString()}).where(and(eq(r.id,t),eq(r.status,"running"))).run(),{killed:!0,pid:n.pid??void 0}}catch(n){throw n instanceof _?n:new _("DB_ERROR","Failed to kill task",n)}finally{e.close();}}reapOrphanedTasks(){if(!this.dbExists())return 0;let t=this.openHandle(true);try{let e=t.db.select({id:r.id,pid:r.pid,platform:r.platform,run_epoch:r.run_epoch}).from(r).where(eq(r.status,"running")).all(),n=Date.now(),s=new Set,o=0;for(let i of e){if(i.pid){let l=!1;try{process.kill(i.pid,0),l=!0;}catch{}l||(t.db.update(r).set({status:"failed",error:"Reaped: process not found (orphaned task)",completed_at:new Date().toISOString()}).where(and(eq(r.id,i.id),eq(r.status,"running"))).run(),o++);continue}if(ye.has(i.platform??"cli"))continue;let a=`${i.id}:${i.run_epoch??0}`;s.add(a);let c=this.pidNullObservedSince.get(a);if(c===void 0){this.pidNullObservedSince.set(a,n);continue}n-c>=Ae&&(t.db.update(r).set({status:"failed",error:"Reaped: pid never recorded after resume (stale running_instruction)",completed_at:new Date().toISOString()}).where(and(eq(r.id,i.id),eq(r.status,"running"))).run(),o++,this.pidNullObservedSince.delete(a));}for(let i of Array.from(this.pidNullObservedSince.keys()))s.has(i)||this.pidNullObservedSince.delete(i);return o}finally{t.close();}}findTaskStatus(t,e){let n=this.resolveDbPaths();for(let s of n){if(!existsSync(s))continue;let o=R(s);try{let i=e?eq(r.workspace_id,e):void 0,a=i?and(eq(r.id,t),i):eq(r.id,t),c=o.db.select().from(r).where(a).limit(1).get()??void 0;if(!c){let l=or(eq(r.thread_id,t),and(isNull(r.thread_id),like(r.command,`%--thread=${t}%`))),u=i?and(l,i):l;c=o.db.select().from(r).where(u).orderBy(desc(r.started_at)).limit(1).get()??void 0;}if(c)return c}catch(i){throw new _("DB_ERROR","Failed to find task status",i)}finally{o.close();}}}findChildTasks(t,e){let n=this.resolveDbPaths(),s=new Set,o=[];for(let i of n){if(!existsSync(i))continue;let a=R(i);try{let c=e?and(eq(r.parent_task_id,t),eq(r.workspace_id,e)):eq(r.parent_task_id,t),l=a.db.select().from(r).where(c).orderBy(asc(r.started_at)).all();for(let u of l)s.has(u.id)||(s.add(u.id),o.push(u));}catch(c){throw new _("DB_ERROR","Failed to find child tasks",c)}finally{a.close();}}return o}getWorkspaceUsageSummary(t){if(!this.dbExists())return [];let e=this.openHandle(false);try{return e.db.all(t?sql`
|
|
17
17
|
SELECT
|
|
18
18
|
COALESCE(workspace_id, 'unknown') AS workspace_id,
|
|
19
19
|
COALESCE(SUM(input_tokens), 0) AS input_tokens,
|
|
@@ -34,7 +34,7 @@ ${s.join(`
|
|
|
34
34
|
FROM tasks
|
|
35
35
|
GROUP BY workspace_id
|
|
36
36
|
ORDER BY (COALESCE(SUM(input_tokens), 0) + COALESCE(SUM(output_tokens), 0)) DESC
|
|
37
|
-
`)}catch(
|
|
37
|
+
`)}catch(n){throw new _("DB_ERROR","Failed to get workspace usage summary",n)}finally{e.close();}}getThreadTokenUsage(t,e){let n=this.resolveDbPaths(),s=new Set,o=0,i=0,a=0;for(let c of n){if(!existsSync(c))continue;let l=R(c);try{let u=or(eq(r.thread_id,t),and(isNull(r.thread_id),like(r.command,`%--thread=${t}%`))),f=e?and(u,eq(r.workspace_id,e)):u,m=l.db.select({id:r.id,input_tokens:r.input_tokens,output_tokens:r.output_tokens,cost_usd:r.cost_usd}).from(r).where(f).all();for(let T of m)s.has(T.id)||(s.add(T.id),o+=T.input_tokens??0,i+=T.output_tokens??0,a+=T.cost_usd??0);}catch(u){throw new _("DB_ERROR","Failed to get thread token usage",u)}finally{l.close();}}return {inputTokens:o,outputTokens:i,costUsd:a}}findTasksByThread(t,e){let n=this.resolveDbPaths(),s=new Set,o=[];for(let i of n){if(!existsSync(i))continue;let a=R(i);try{let c=or(eq(r.thread_id,t),and(isNull(r.thread_id),like(r.command,`%--thread=${t}%`))),l=e?and(c,eq(r.workspace_id,e)):c,u=a.db.select().from(r).where(l).orderBy(asc(r.started_at)).all();for(let f of u)s.has(f.id)||(s.add(f.id),o.push(f));}catch(c){throw new _("DB_ERROR","Failed to find tasks by thread",c)}finally{a.close();}}return o}findAllTasks(t){if(!this.dbExists())return {rows:[],total:0};let e=this.openHandle(false);try{let n=[];t.workspaceId&&n.push(eq(r.workspace_id,t.workspaceId));let s=t.agents&&t.agents.length>0?t.agents:t.agentId?[t.agentId]:null;s&&n.push(inArray(r.agent_id,s));let o=t.statuses&&t.statuses.length>0?t.statuses:t.status?[t.status]:null;o&&n.push(inArray(r.status,o));let i=t.q??t.search;i&&n.push(like(r.prompt,`%${i}%`)),t.from&&n.push(gte(r.started_at,t.from)),t.to&&n.push(lt$1(r.started_at,t.to));let a=n.length>0?and(...n):void 0,c=e.db.select({count:sql`count(*)`}).from(r).where(a).get(),l=(t.sortDir??"DESC")==="ASC"?asc(r.started_at):desc(r.started_at);return {rows:e.db.select().from(r).where(a).orderBy(l).limit(t.limit).offset(t.offset).all(),total:c?.count??0}}catch(n){throw new _("DB_ERROR","Failed to find all tasks",n)}finally{e.close();}}getAgentUsage(t,e,n){if(!this.dbExists())return [];let s=this.openHandle(false);try{return s.db.all(n?sql`
|
|
38
38
|
SELECT
|
|
39
39
|
t.agent_id,
|
|
40
40
|
t.workspace_id,
|
|
@@ -42,11 +42,11 @@ ${s.join(`
|
|
|
42
42
|
COALESCE(SUM(
|
|
43
43
|
COALESCE(t.input_tokens, 0)
|
|
44
44
|
+ CASE
|
|
45
|
-
WHEN t.started_at >= ${
|
|
45
|
+
WHEN t.started_at >= ${B}
|
|
46
46
|
AND (
|
|
47
47
|
t.crewx_version IS NULL
|
|
48
48
|
OR (t.crewx_version LIKE '0.8.%' AND t.crewx_version NOT LIKE '0.8.9%')
|
|
49
|
-
OR (t.crewx_version LIKE '0.8.9-rc.%' AND CAST(SUBSTR(t.crewx_version, ${
|
|
49
|
+
OR (t.crewx_version LIKE '0.8.9-rc.%' AND CAST(SUBSTR(t.crewx_version, ${F}) AS INTEGER) < ${z})
|
|
50
50
|
)
|
|
51
51
|
THEN COALESCE(t.cached_input_tokens, 0)
|
|
52
52
|
ELSE 0
|
|
@@ -59,17 +59,17 @@ ${s.join(`
|
|
|
59
59
|
WHERE t.status IN ('completed', 'success')
|
|
60
60
|
AND t.started_at >= ${t}
|
|
61
61
|
AND t.started_at < ${e}
|
|
62
|
-
AND t.workspace_id = ${
|
|
62
|
+
AND t.workspace_id = ${n}
|
|
63
63
|
GROUP BY t.agent_id, t.workspace_id
|
|
64
64
|
ORDER BY (
|
|
65
65
|
COALESCE(SUM(
|
|
66
66
|
COALESCE(t.input_tokens, 0)
|
|
67
67
|
+ CASE
|
|
68
|
-
WHEN t.started_at >= ${
|
|
68
|
+
WHEN t.started_at >= ${B}
|
|
69
69
|
AND (
|
|
70
70
|
t.crewx_version IS NULL
|
|
71
71
|
OR (t.crewx_version LIKE '0.8.%' AND t.crewx_version NOT LIKE '0.8.9%')
|
|
72
|
-
OR (t.crewx_version LIKE '0.8.9-rc.%' AND CAST(SUBSTR(t.crewx_version, ${
|
|
72
|
+
OR (t.crewx_version LIKE '0.8.9-rc.%' AND CAST(SUBSTR(t.crewx_version, ${F}) AS INTEGER) < ${z})
|
|
73
73
|
)
|
|
74
74
|
THEN COALESCE(t.cached_input_tokens, 0)
|
|
75
75
|
ELSE 0
|
|
@@ -85,11 +85,11 @@ ${s.join(`
|
|
|
85
85
|
COALESCE(SUM(
|
|
86
86
|
COALESCE(t.input_tokens, 0)
|
|
87
87
|
+ CASE
|
|
88
|
-
WHEN t.started_at >= ${
|
|
88
|
+
WHEN t.started_at >= ${B}
|
|
89
89
|
AND (
|
|
90
90
|
t.crewx_version IS NULL
|
|
91
91
|
OR (t.crewx_version LIKE '0.8.%' AND t.crewx_version NOT LIKE '0.8.9%')
|
|
92
|
-
OR (t.crewx_version LIKE '0.8.9-rc.%' AND CAST(SUBSTR(t.crewx_version, ${
|
|
92
|
+
OR (t.crewx_version LIKE '0.8.9-rc.%' AND CAST(SUBSTR(t.crewx_version, ${F}) AS INTEGER) < ${z})
|
|
93
93
|
)
|
|
94
94
|
THEN COALESCE(t.cached_input_tokens, 0)
|
|
95
95
|
ELSE 0
|
|
@@ -107,11 +107,11 @@ ${s.join(`
|
|
|
107
107
|
COALESCE(SUM(
|
|
108
108
|
COALESCE(t.input_tokens, 0)
|
|
109
109
|
+ CASE
|
|
110
|
-
WHEN t.started_at >= ${
|
|
110
|
+
WHEN t.started_at >= ${B}
|
|
111
111
|
AND (
|
|
112
112
|
t.crewx_version IS NULL
|
|
113
113
|
OR (t.crewx_version LIKE '0.8.%' AND t.crewx_version NOT LIKE '0.8.9%')
|
|
114
|
-
OR (t.crewx_version LIKE '0.8.9-rc.%' AND CAST(SUBSTR(t.crewx_version, ${
|
|
114
|
+
OR (t.crewx_version LIKE '0.8.9-rc.%' AND CAST(SUBSTR(t.crewx_version, ${F}) AS INTEGER) < ${z})
|
|
115
115
|
)
|
|
116
116
|
THEN COALESCE(t.cached_input_tokens, 0)
|
|
117
117
|
ELSE 0
|
|
@@ -119,18 +119,18 @@ ${s.join(`
|
|
|
119
119
|
), 0)
|
|
120
120
|
+ COALESCE(SUM(t.output_tokens), 0)
|
|
121
121
|
) DESC
|
|
122
|
-
`).map(i=>({agentId:i.agent_id,workspaceId:i.workspace_id??null,totalTasks:i.total_tasks,inputTokens:i.input_tokens,outputTokens:i.output_tokens,cachedInputTokens:i.cached_input_tokens,costUsd:i.cost_usd,totalTokens:i.input_tokens+i.output_tokens}))}catch(
|
|
122
|
+
`).map(i=>({agentId:i.agent_id,workspaceId:i.workspace_id??null,totalTasks:i.total_tasks,inputTokens:i.input_tokens,outputTokens:i.output_tokens,cachedInputTokens:i.cached_input_tokens,costUsd:i.cost_usd,totalTokens:i.input_tokens+i.output_tokens}))}catch(o){throw new _("DB_ERROR","Failed to get agent usage",o)}finally{s.close();}}getAgentUsageTrendRaw(t,e,n){if(!this.dbExists())return [];let s=this.openHandle(false);try{return s.db.all(n?sql`
|
|
123
123
|
SELECT
|
|
124
124
|
date(t.started_at) AS date,
|
|
125
125
|
t.agent_id,
|
|
126
126
|
COALESCE(SUM(
|
|
127
127
|
COALESCE(t.input_tokens, 0)
|
|
128
128
|
+ CASE
|
|
129
|
-
WHEN t.started_at >= ${
|
|
129
|
+
WHEN t.started_at >= ${B}
|
|
130
130
|
AND (
|
|
131
131
|
t.crewx_version IS NULL
|
|
132
132
|
OR (t.crewx_version LIKE '0.8.%' AND t.crewx_version NOT LIKE '0.8.9%')
|
|
133
|
-
OR (t.crewx_version LIKE '0.8.9-rc.%' AND CAST(SUBSTR(t.crewx_version, ${
|
|
133
|
+
OR (t.crewx_version LIKE '0.8.9-rc.%' AND CAST(SUBSTR(t.crewx_version, ${F}) AS INTEGER) < ${z})
|
|
134
134
|
)
|
|
135
135
|
THEN COALESCE(t.cached_input_tokens, 0)
|
|
136
136
|
ELSE 0
|
|
@@ -143,7 +143,7 @@ ${s.join(`
|
|
|
143
143
|
WHERE t.status IN ('completed', 'success')
|
|
144
144
|
AND t.started_at >= ${t}
|
|
145
145
|
AND t.started_at < ${e}
|
|
146
|
-
AND t.workspace_id = ${
|
|
146
|
+
AND t.workspace_id = ${n}
|
|
147
147
|
GROUP BY date(t.started_at), t.agent_id
|
|
148
148
|
ORDER BY date(t.started_at) ASC
|
|
149
149
|
`:sql`
|
|
@@ -153,11 +153,11 @@ ${s.join(`
|
|
|
153
153
|
COALESCE(SUM(
|
|
154
154
|
COALESCE(t.input_tokens, 0)
|
|
155
155
|
+ CASE
|
|
156
|
-
WHEN t.started_at >= ${
|
|
156
|
+
WHEN t.started_at >= ${B}
|
|
157
157
|
AND (
|
|
158
158
|
t.crewx_version IS NULL
|
|
159
159
|
OR (t.crewx_version LIKE '0.8.%' AND t.crewx_version NOT LIKE '0.8.9%')
|
|
160
|
-
OR (t.crewx_version LIKE '0.8.9-rc.%' AND CAST(SUBSTR(t.crewx_version, ${
|
|
160
|
+
OR (t.crewx_version LIKE '0.8.9-rc.%' AND CAST(SUBSTR(t.crewx_version, ${F}) AS INTEGER) < ${z})
|
|
161
161
|
)
|
|
162
162
|
THEN COALESCE(t.cached_input_tokens, 0)
|
|
163
163
|
ELSE 0
|
|
@@ -172,43 +172,79 @@ ${s.join(`
|
|
|
172
172
|
AND t.started_at < ${e}
|
|
173
173
|
GROUP BY date(t.started_at), t.agent_id
|
|
174
174
|
ORDER BY date(t.started_at) ASC
|
|
175
|
-
`).map(i=>({date:i.date,agentId:i.agent_id,inputTokens:i.input_tokens,outputTokens:i.output_tokens,cachedInputTokens:i.cached_input_tokens,costUsd:i.cost_usd,totalTokens:i.input_tokens+i.output_tokens}))}catch(
|
|
175
|
+
`).map(i=>({date:i.date,agentId:i.agent_id,inputTokens:i.input_tokens,outputTokens:i.output_tokens,cachedInputTokens:i.cached_input_tokens,costUsd:i.cost_usd,totalTokens:i.input_tokens+i.output_tokens}))}catch(o){throw new _("DB_ERROR","Failed to get agent usage trend",o)}finally{s.close();}}findTaskForStop(t,e){if(!this.dbExists())return;let n=this.openHandle(false);try{return n.db.select().from(r).where(and(eq(r.id,t),eq(r.workspace_id,e))).limit(1).get()??void 0}catch(s){throw new _("DB_ERROR","Failed to find task for stop",s)}finally{n.close();}}markTaskFailed(t,e,n){if(!this.dbExists())return;let s=this.openHandle(true);try{let o=new Date().toISOString(),i=n?and(eq(r.id,t),eq(r.status,"running"),eq(r.workspace_id,n)):and(eq(r.id,t),eq(r.status,"running"));s.db.update(r).set({status:"failed",error:e,completed_at:o}).where(i).run();}catch(o){throw o instanceof _?o:new _("DB_ERROR","Failed to mark task failed",o)}finally{s.close();}}findTasksByPromptHint(t,e){let n=this.resolveDbPaths(),s=new Set,o=[];for(let i of n){if(!existsSync(i))continue;let a=R(i);try{let c=e?and(like(r.prompt,`%${t}%`),eq(r.workspace_id,e)):like(r.prompt,`%${t}%`),l=a.db.select().from(r).where(c).orderBy(asc(r.started_at)).all();for(let u of l)s.has(u.id)||(s.add(u.id),o.push(u));}catch(c){throw new _("DB_ERROR","Failed to find tasks by prompt hint",c)}finally{a.close();}}return o}getProviderUsage(t,e,n){if(!this.dbExists())return [];let s=this.openHandle(false);try{let o=sql`
|
|
176
176
|
CASE
|
|
177
|
-
WHEN ${
|
|
178
|
-
WHEN ${
|
|
179
|
-
WHEN ${
|
|
180
|
-
WHEN ${
|
|
181
|
-
WHEN ${
|
|
182
|
-
WHEN ${
|
|
177
|
+
WHEN ${r.model} LIKE 'claude-%' OR ${r.model} IN ('opus', 'sonnet', 'haiku', 'opus[1m]', 'sonnet[1m]') THEN 'claude'
|
|
178
|
+
WHEN ${r.model} LIKE 'gpt-%' OR ${r.model} LIKE 'codex-%' THEN 'codex'
|
|
179
|
+
WHEN ${r.model} LIKE 'gemini-%' THEN 'gemini'
|
|
180
|
+
WHEN ${r.model} LIKE 'zai-%' OR ${r.model} LIKE 'openrouter/z-ai/%' THEN 'opencode'
|
|
181
|
+
WHEN ${r.model} LIKE 'minimax/%' THEN 'minimax'
|
|
182
|
+
WHEN ${r.model} LIKE 'qwen%' THEN 'qwen'
|
|
183
183
|
ELSE 'unknown'
|
|
184
184
|
END
|
|
185
185
|
`,i=sql`
|
|
186
|
-
COALESCE(${
|
|
186
|
+
COALESCE(${r.input_tokens}, 0)
|
|
187
187
|
+ CASE
|
|
188
|
-
WHEN ${
|
|
188
|
+
WHEN ${r.started_at} >= ${B}
|
|
189
189
|
AND (
|
|
190
|
-
${
|
|
191
|
-
OR (${
|
|
192
|
-
OR (${
|
|
190
|
+
${r.crewx_version} IS NULL
|
|
191
|
+
OR (${r.crewx_version} LIKE '0.8.%' AND ${r.crewx_version} NOT LIKE '0.8.9%')
|
|
192
|
+
OR (${r.crewx_version} LIKE '0.8.9-rc.%' AND CAST(SUBSTR(${r.crewx_version}, ${F}) AS INTEGER) < ${z})
|
|
193
193
|
)
|
|
194
|
-
THEN COALESCE(${
|
|
194
|
+
THEN COALESCE(${r.cached_input_tokens}, 0)
|
|
195
195
|
ELSE 0
|
|
196
196
|
END
|
|
197
|
-
`,a=
|
|
197
|
+
`,a=n?sql`WHERE ${r.status} IN ('completed', 'success') AND ${r.started_at} >= ${t} AND ${r.started_at} < ${e} AND ${r.workspace_id} = ${n}`:sql`WHERE ${r.status} IN ('completed', 'success') AND ${r.started_at} >= ${t} AND ${r.started_at} < ${e}`;return s.db.all(sql`
|
|
198
198
|
SELECT
|
|
199
|
-
${
|
|
199
|
+
${o} AS provider,
|
|
200
200
|
COUNT(*) AS total_tasks,
|
|
201
201
|
COALESCE(SUM(${i}), 0) AS input_tokens,
|
|
202
|
-
COALESCE(SUM(${
|
|
203
|
-
COALESCE(SUM(${
|
|
204
|
-
COALESCE(SUM(${
|
|
205
|
-
COALESCE(SUM(${
|
|
206
|
-
MAX(${
|
|
207
|
-
FROM ${
|
|
202
|
+
COALESCE(SUM(${r.output_tokens}), 0) AS output_tokens,
|
|
203
|
+
COALESCE(SUM(${r.cached_input_tokens}), 0) AS cached_input_tokens,
|
|
204
|
+
COALESCE(SUM(${r.cost_usd}), 0) AS cost_usd,
|
|
205
|
+
COALESCE(SUM(${r.duration_ms}), 0) AS active_duration_ms,
|
|
206
|
+
MAX(${r.completed_at}) AS last_active_at
|
|
207
|
+
FROM ${r}
|
|
208
208
|
${a}
|
|
209
209
|
GROUP BY provider
|
|
210
|
-
ORDER BY (COALESCE(SUM(${i}), 0) + COALESCE(SUM(${
|
|
211
|
-
`).map(
|
|
210
|
+
ORDER BY (COALESCE(SUM(${i}), 0) + COALESCE(SUM(${r.output_tokens}), 0)) DESC
|
|
211
|
+
`).map(l=>({provider:l.provider,totalTasks:l.total_tasks,inputTokens:l.input_tokens,outputTokens:l.output_tokens,cachedInputTokens:l.cached_input_tokens,costUsd:l.cost_usd,totalTokens:l.input_tokens+l.output_tokens,activeDurationMs:l.active_duration_ms??0,lastActiveAt:l.last_active_at??null}))}catch(o){throw new _("DB_ERROR","Failed to get provider usage",o)}finally{s.close();}}getModelUsage(t,e,n){if(!this.dbExists())return [];let s=this.openHandle(false);try{let o=sql`
|
|
212
|
+
CASE
|
|
213
|
+
WHEN ${r.model} LIKE 'claude-%' OR ${r.model} IN ('opus', 'sonnet', 'haiku', 'opus[1m]', 'sonnet[1m]') THEN 'claude'
|
|
214
|
+
WHEN ${r.model} LIKE 'gpt-%' OR ${r.model} LIKE 'codex-%' THEN 'codex'
|
|
215
|
+
WHEN ${r.model} LIKE 'gemini-%' THEN 'gemini'
|
|
216
|
+
WHEN ${r.model} LIKE 'zai-%' OR ${r.model} LIKE 'openrouter/z-ai/%' THEN 'opencode'
|
|
217
|
+
WHEN ${r.model} LIKE 'minimax/%' THEN 'minimax'
|
|
218
|
+
WHEN ${r.model} LIKE 'qwen%' THEN 'qwen'
|
|
219
|
+
ELSE 'unknown'
|
|
220
|
+
END
|
|
221
|
+
`,i=sql`
|
|
222
|
+
COALESCE(${r.input_tokens}, 0)
|
|
223
|
+
+ CASE
|
|
224
|
+
WHEN ${r.started_at} >= ${B}
|
|
225
|
+
AND (
|
|
226
|
+
${r.crewx_version} IS NULL
|
|
227
|
+
OR (${r.crewx_version} LIKE '0.8.%' AND ${r.crewx_version} NOT LIKE '0.8.9%')
|
|
228
|
+
OR (${r.crewx_version} LIKE '0.8.9-rc.%' AND CAST(SUBSTR(${r.crewx_version}, ${F}) AS INTEGER) < ${z})
|
|
229
|
+
)
|
|
230
|
+
THEN COALESCE(${r.cached_input_tokens}, 0)
|
|
231
|
+
ELSE 0
|
|
232
|
+
END
|
|
233
|
+
`,a=n?sql`WHERE ${r.status} IN ('completed', 'success') AND ${r.started_at} >= ${t} AND ${r.started_at} < ${e} AND ${r.workspace_id} = ${n}`:sql`WHERE ${r.status} IN ('completed', 'success') AND ${r.started_at} >= ${t} AND ${r.started_at} < ${e}`,c=s.db.all(sql`
|
|
234
|
+
SELECT
|
|
235
|
+
${r.model} AS model,
|
|
236
|
+
${o} AS provider,
|
|
237
|
+
COUNT(*) AS total_tasks,
|
|
238
|
+
COALESCE(SUM(${i}), 0) AS input_tokens,
|
|
239
|
+
COALESCE(SUM(${r.output_tokens}), 0) AS output_tokens,
|
|
240
|
+
COALESCE(SUM(${r.cached_input_tokens}), 0) AS cached_input_tokens,
|
|
241
|
+
COALESCE(SUM(${r.cost_usd}), 0) AS cost_usd,
|
|
242
|
+
COALESCE(SUM(${r.duration_ms}), 0) AS active_duration_ms,
|
|
243
|
+
MAX(${r.completed_at}) AS last_active_at
|
|
244
|
+
FROM ${r}
|
|
245
|
+
${a}
|
|
246
|
+
GROUP BY ${r.model}
|
|
247
|
+
`),l=new Map;for(let u of c){let f=$t(u.model??""),m=l.get(f);m?(m.totalTasks+=u.total_tasks,m.inputTokens+=u.input_tokens,m.outputTokens+=u.output_tokens,m.cachedInputTokens+=u.cached_input_tokens,m.costUsd+=u.cost_usd,m.totalTokens+=u.input_tokens+u.output_tokens,m.activeDurationMs+=u.active_duration_ms??0,u.last_active_at&&(!m.lastActiveAt||u.last_active_at>m.lastActiveAt)&&(m.lastActiveAt=u.last_active_at)):l.set(f,{model:f,provider:u.provider,totalTasks:u.total_tasks,inputTokens:u.input_tokens,outputTokens:u.output_tokens,cachedInputTokens:u.cached_input_tokens,costUsd:u.cost_usd,totalTokens:u.input_tokens+u.output_tokens,activeDurationMs:u.active_duration_ms??0,lastActiveAt:u.last_active_at??null});}return Array.from(l.values()).sort((u,f)=>f.costUsd-u.costUsd)}catch(o){throw new _("DB_ERROR","Failed to get model usage",o)}finally{s.close();}}};var kt=class extends U{name="sqlite-tracing";unsubs=[];dbPath;version;constructor(t){super(),this.dbPath=join(t?.dbRoot??homedir(),".crewx","crewx.db"),this.version=t?.version??"unknown";}attach(t){let e=new dt({dbPath:this.dbPath}),n=process.cwd(),o=existsSync(join(n,"crewx.yaml"))||existsSync(join(n,"crewx.yml"))?yt(n):null,i=process.argv.join(" ");this.unsubs.push(t.on("task:start",a=>{try{let c=a.callerAgentId??null,l=a.parentTaskId??null,u=a.rootTraceId??a.traceId,f=a.metadata?JSON.stringify(a.metadata):JSON.stringify({provider:a.provider??"cli/claude"});e.startTask({id:a.traceId,agentId:a.agentRef.replace(/^@/,""),prompt:a.message,mode:a.mode,status:"running",pid:a.pid??null,startedAt:a.timestamp.toISOString(),crewxVersion:this.version,platform:a.platform??"cli",model:a.model??null,renderedPrompt:a.renderedPrompt??null,command:i,codingAgentCommand:a.codingAgentCommand??null,workspaceId:a.workspaceId??o,callerAgentId:c,parentTaskId:l,traceId:u,metadata:f,threadId:a.threadId??null});}catch{}}),t.on("task:output",a=>{try{e.appendLog(a.traceId,{timestamp:a.timestamp.toISOString(),level:a.level??"stdout",message:a.output});}catch{}}),t.on("task:end",a=>{try{let c=typeof a.metadata?.runEpoch=="number"?a.metadata.runEpoch:null;e.finishTask({id:a.traceId,status:a.error?"failed":"success",result:a.result??null,error:a.error?JSON.stringify(a.error):null,completedAt:a.timestamp.toISOString(),durationMs:a.durationMs,exitCode:a.exitCode??null,inputTokens:a.inputTokens??0,outputTokens:a.outputTokens??0,cachedInputTokens:a.cachedInputTokens??0,costUsd:a.costUsd??0,model:a.model??null,runEpoch:c});}catch{}}));}detach(t){this.unsubs.forEach(e=>e()),this.unsubs=[];}};var ct=class extends X{dbPath;constructor(t={}){super(),t.dbPath?this.dbPath=t.dbPath:t.dbRoot&&(this.dbPath=join(t.dbRoot,".crewx","crewx.db"));}resolveDbPath(){return this.dbPath?this.dbPath:super.resolveDbPath()}openHandle(t){let e=this.resolveDbPath();if(t){let s=dirname(e);existsSync(s)||mkdirSync(s,{recursive:true});}else if(!existsSync(e))throw new _("NOT_FOUND","Database not found");let n=R(e);if(t)try{nt(n.db,e);}catch(s){throw n.close(),s}return n}validateWorkspaceId(t,e){return t.db.select({id:Y.id}).from(Y).where(eq(Y.id,e)).limit(1).get()?e:null}topLevelTaskPredicateSql(t="child"){return sql.raw(`(
|
|
212
248
|
${t}.parent_task_id IS NULL
|
|
213
249
|
OR ${t}.parent_task_id = ''
|
|
214
250
|
OR NOT EXISTS (
|
|
@@ -216,7 +252,7 @@ ${s.join(`
|
|
|
216
252
|
WHERE parent.id = ${t}.parent_task_id
|
|
217
253
|
AND parent.thread_id = ${t}.thread_id
|
|
218
254
|
)
|
|
219
|
-
)`)}findAllThreads(t){let e=this.resolveDbPaths(),
|
|
255
|
+
)`)}findAllThreads(t){let e=this.resolveDbPaths(),n=new Set,s=[];for(let o of e){if(!existsSync(o))continue;let i=R(o);try{let a=t?eq(p.workspace_id,t):void 0,c=i.db.select().from(p).where(a).orderBy(desc(p.updated_at)).all();for(let l of c)n.has(l.id)||(n.add(l.id),s.push(l));}catch(a){throw new _("DB_ERROR","Failed to find all threads",a)}finally{i.close();}}return s}findThreadById(t,e){let n=this.resolveDbPaths();for(let s of n){if(!existsSync(s))continue;let o=R(s);try{let i=eq(p.id,t),a=e?and(i,eq(p.workspace_id,e)):i,c=o.db.select().from(p).where(a).limit(1).get()??void 0;if(c)return c}catch(i){throw new _("DB_ERROR","Failed to find thread by id",i)}finally{o.close();}}}threadExists(t,e){let n=this.resolveDbPaths();for(let s of n){if(!existsSync(s))continue;let o=R(s);try{let i=eq(p.id,t),a=e?and(i,eq(p.workspace_id,e)):i;if(o.db.select({id:p.id}).from(p).where(a).limit(1).get())return !0}catch(i){throw new _("DB_ERROR","Failed to check thread existence",i)}finally{o.close();}}return false}aggregateTaskStats(t,e){let n=this.resolveDbPaths(),s=0,o=0,i=0,a=0,c=0,l=new Set;for(let u of n){if(!existsSync(u))continue;let f=R(u);try{let m=f.db.get(sql`
|
|
220
256
|
SELECT
|
|
221
257
|
count(*) AS cnt,
|
|
222
258
|
COALESCE(SUM(child.input_tokens), 0) AS total_input,
|
|
@@ -227,13 +263,13 @@ ${s.join(`
|
|
|
227
263
|
WHERE child.thread_id = ${t}
|
|
228
264
|
AND ${this.topLevelTaskPredicateSql()}
|
|
229
265
|
${e?sql`AND child.workspace_id = ${e}`:sql``}
|
|
230
|
-
`);
|
|
266
|
+
`);m&&(s+=m.cnt,o+=m.total_input,i+=m.total_output,a+=m.total_cached,c+=m.total_cost);let T=f.db.all(sql`
|
|
231
267
|
SELECT DISTINCT child.agent_id FROM tasks child
|
|
232
268
|
WHERE child.thread_id = ${t}
|
|
233
269
|
AND child.agent_id IS NOT NULL AND child.agent_id != ''
|
|
234
270
|
AND ${this.topLevelTaskPredicateSql()}
|
|
235
271
|
${e?sql`AND child.workspace_id = ${e}`:sql``}
|
|
236
|
-
`);for(let G of
|
|
272
|
+
`);for(let G of T)l.add(G.agent_id);}catch(m){throw new _("DB_ERROR","Failed to aggregate task stats",m)}finally{f.close();}}return {taskCount:s,inputTokens:o,outputTokens:i,cachedInputTokens:a,costUsd:c,agentIds:Array.from(l)}}findTopLevelTasks(t,e,n){let s=this.resolveDbPaths(),o=new Set,i=[];for(let a of s){if(!existsSync(a))continue;let c=R(a);try{let l;n!==void 0?l=c.db.all(sql`
|
|
237
273
|
SELECT * FROM (
|
|
238
274
|
SELECT child.*,
|
|
239
275
|
ROW_NUMBER() OVER (PARTITION BY child.agent_id ORDER BY child.started_at DESC) AS rn
|
|
@@ -242,30 +278,30 @@ ${s.join(`
|
|
|
242
278
|
AND ${this.topLevelTaskPredicateSql()}
|
|
243
279
|
${e?sql`AND child.workspace_id = ${e}`:sql``}
|
|
244
280
|
) ranked
|
|
245
|
-
WHERE rn <= ${
|
|
281
|
+
WHERE rn <= ${n}
|
|
246
282
|
ORDER BY started_at ASC
|
|
247
|
-
`):c
|
|
283
|
+
`):l=c.db.all(sql`
|
|
248
284
|
SELECT child.* FROM tasks child
|
|
249
285
|
WHERE child.thread_id = ${t}
|
|
250
286
|
AND ${this.topLevelTaskPredicateSql()}
|
|
251
287
|
${e?sql`AND child.workspace_id = ${e}`:sql``}
|
|
252
288
|
ORDER BY child.started_at ASC
|
|
253
|
-
`);for(let
|
|
289
|
+
`);for(let u of l)o.has(u.id)||(o.add(u.id),i.push(u));}catch(l){throw new _("DB_ERROR","Failed to find top-level tasks",l)}finally{c.close();}}if(n!==void 0&&s.length>1){let a=new Map;for(let c of i){let l=c.agent_id??"";a.has(l)||a.set(l,[]),a.get(l).push(c);}i=[];for(let c of a.values())c.sort((l,u)=>(u.started_at??"").localeCompare(l.started_at??"")),i.push(...c.slice(0,n));i.sort((c,l)=>(c.started_at??"").localeCompare(l.started_at??""));}return i}findAllTasks(t,e){let n=this.resolveDbPaths(),s=new Set,o=[];for(let i of n){if(!existsSync(i))continue;let a=R(i);try{let c=eq(r.thread_id,t),l=e?and(c,eq(r.workspace_id,e)):c,u=a.db.select().from(r).where(l).orderBy(asc(r.started_at)).all();for(let f of u)s.has(f.id)||(s.add(f.id),o.push(f));}catch(c){throw new _("DB_ERROR","Failed to find all tasks for thread",c)}finally{a.close();}}return o}findTaskById(t,e,n){let s=this.resolveDbPaths();for(let o of s){if(!existsSync(o))continue;let i=R(o);try{let a=and(eq(r.id,e),eq(r.thread_id,t)),c=n?and(a,eq(r.workspace_id,n)):a,l=i.db.select().from(r).where(c).limit(1).get();if(!l)continue;let u=i.db.select().from(r).where(eq(r.parent_task_id,l.id)).orderBy(asc(r.started_at)).all();return {task:l,children:u}}catch(a){throw new _("DB_ERROR","Failed to find task by id",a)}finally{i.close();}}}batchFetchTasks(t,e){let n=new Map;if(t.length===0)return n;let s=this.resolveDbPaths();for(let o of s){if(!existsSync(o))continue;let i=R(o);try{let a=i.db.all(sql`
|
|
254
290
|
SELECT child.* FROM tasks child
|
|
255
|
-
WHERE child.thread_id IN (${sql.join(t.map(
|
|
291
|
+
WHERE child.thread_id IN (${sql.join(t.map(c=>sql`${c}`),sql`, `)})
|
|
256
292
|
AND ${this.topLevelTaskPredicateSql()}
|
|
257
293
|
${e?sql`AND child.workspace_id = ${e}`:sql``}
|
|
258
294
|
ORDER BY child.started_at ASC
|
|
259
|
-
`);for(let
|
|
295
|
+
`);for(let c of a){let l=c.thread_id;n.has(l)||n.set(l,[]),n.get(l).push(c);}}catch(a){throw new _("DB_ERROR","Failed to batch fetch tasks",a)}finally{i.close();}}return n}updateThreadTitle(t,e,n){if(!this.dbExists())return;let s=this.openHandle(true);try{let o=eq(p.id,t),i=n?and(o,eq(p.workspace_id,n)):o;if(!s.db.select({id:p.id}).from(p).where(i).limit(1).get())return;s.db.update(p).set({title:e,title_locked:1,updated_at:new Date().toISOString()}).where(eq(p.id,t)).run();}catch(o){throw o instanceof _?o:new _("DB_ERROR","Failed to update thread title",o)}finally{s.close();}}upsertThread(t,e){let n=this.openHandle(true);try{let s=e.workspaceId?this.validateWorkspaceId(n,e.workspaceId):null,o=new Date().toISOString();if(n.db.select({id:p.id,message_count:p.message_count}).from(p).where(eq(p.id,t)).limit(1).get()){let a={updated_at:o};e.title!==void 0&&(a.title=e.title),e.titleLocked!==void 0&&(a.title_locked=e.titleLocked?1:0),n.db.update(p).set(a).where(eq(p.id,t)).run();}else n.db.insert(p).values({id:t,platform:e.platform,workspace_id:s,title:e.title??null,title_locked:e.titleLocked?1:0,message_count:0,created_at:o,updated_at:o}).run();}catch(s){throw s instanceof _?s:new _("DB_ERROR","Failed to upsert thread",s)}finally{n.close();}}ensureThread(t,e,n){let s=this.openHandle(true);try{let o=n?this.validateWorkspaceId(s,n):null,i=s.db.select({id:p.id,platform:p.platform,workspace_id:p.workspace_id}).from(p).where(eq(p.id,t)).limit(1).get();if(i){o&&!i.workspace_id&&s.db.update(p).set({workspace_id:o}).where(eq(p.id,t)).run();return}let a=new Date().toISOString();s.db.insert(p).values({id:t,platform:e,workspace_id:o,message_count:0,created_at:a,updated_at:a}).run();}catch(o){throw o instanceof _?o:new _("DB_ERROR","Failed to ensure thread",o)}finally{s.close();}}saveUserMessage(t,e,n){if(!this.dbExists())return {firstMessage:false};let s=this.openHandle(true);try{let o=new Date().toISOString();return {firstMessage:s.db.transaction(a=>{let l=a.select({message_count:p.message_count}).from(p).where(eq(p.id,t)).limit(1).get()?.message_count===0;return a.run(sql`
|
|
260
296
|
UPDATE threads
|
|
261
297
|
SET first_message = COALESCE(first_message, ${e}),
|
|
262
298
|
title = CASE WHEN title_locked = 0 AND title IS NULL THEN substr(${e}, 1, 60) ELSE title END,
|
|
263
299
|
last_message = ${e},
|
|
264
300
|
message_count = message_count + 1,
|
|
265
|
-
updated_at = ${
|
|
301
|
+
updated_at = ${o}
|
|
266
302
|
WHERE id = ${t}
|
|
267
|
-
`),
|
|
268
|
-
`).filter(
|
|
269
|
-
`).trim()}function
|
|
270
|
-
`):e&&typeof e=="object"&&e.result!==void 0&&(t=e.result||"");}catch{t
|
|
271
|
-
`)[0].slice(0,200)),e.push({id:`${
|
|
303
|
+
`),l},{behavior:"immediate"})}}catch(o){throw o instanceof _?o:new _("DB_ERROR","Failed to save user message",o)}finally{s.close();}}saveAssistantMessage(t,e,n){if(!this.dbExists())return;let s=this.openHandle(true);try{let o=new Date().toISOString();s.db.update(p).set({last_message:e,updated_at:o}).where(eq(p.id,t)).run();}catch(o){throw o instanceof _?o:new _("DB_ERROR","Failed to save assistant message",o)}finally{s.close();}}updateThread(t,e){if(!this.dbExists())return;let n=this.openHandle(true);try{let s={updated_at:new Date().toISOString()};e.title!==void 0&&(s.title=e.title,s.title_locked=1),e.titleLocked!==void 0&&(s.title_locked=e.titleLocked?1:0),n.db.update(p).set(s).where(eq(p.id,t)).run();}catch(s){throw s instanceof _?s:new _("DB_ERROR","Failed to update thread",s)}finally{n.close();}}togglePin(t,e){let n=this.openHandle(true);try{let s=e?and(eq(p.id,t),eq(p.workspace_id,e)):eq(p.id,t),o=n.db.select({pinned:p.pinned,metadata:p.metadata}).from(p).where(s).get();if(!o)return null;let i=o.pinned?0:1,a=o.metadata?JSON.parse(o.metadata):{};if(i){let c=e?and(eq(p.pinned,1),eq(p.workspace_id,e)):eq(p.pinned,1),l=n.db.select({metadata:p.metadata}).from(p).where(c).all(),u=0;for(let f of l){let m=f.metadata?JSON.parse(f.metadata):{};typeof m.pinOrder=="number"&&m.pinOrder>u&&(u=m.pinOrder);}a.pinOrder=u+1;}else delete a.pinOrder;return n.db.update(p).set({pinned:i,metadata:Object.keys(a).length>0?JSON.stringify(a):null}).where(s).run(),{pinned:!!i}}catch(s){throw s instanceof _?s:new _("DB_ERROR","Failed to toggle pin",s)}finally{n.close();}}reorderPins(t,e){let n=this.openHandle(true);try{for(let s=0;s<t.length;s++){let o=e?and(eq(p.id,t[s]),eq(p.workspace_id,e)):eq(p.id,t[s]),i=n.db.select({metadata:p.metadata}).from(p).where(o).get();if(!i)continue;let a=i.metadata?JSON.parse(i.metadata):{};a.pinOrder=s+1,n.db.update(p).set({metadata:JSON.stringify(a)}).where(o).run();}}catch(s){throw s instanceof _?s:new _("DB_ERROR","Failed to reorder pins",s)}finally{n.close();}}toggleStar(t,e){let n=this.openHandle(true);try{let s=e?and(eq(p.id,t),eq(p.workspace_id,e)):eq(p.id,t),o=n.db.select({starred:p.starred}).from(p).where(s).get();if(!o)return null;let i=o.starred?0:1;return n.db.update(p).set({starred:i}).where(s).run(),{starred:!!i}}catch(s){throw s instanceof _?s:new _("DB_ERROR","Failed to toggle star",s)}finally{n.close();}}resolveOverdriveForRequest(t,e,n,s){let i=this.openHandle(true);try{let a=e?and(eq(p.id,t),eq(p.workspace_id,e)):eq(p.id,t);return i.db.transaction(l=>{let u=l.select({metadata:p.metadata}).from(p).where(a).get();if(!u)return null;let f=u.metadata?JSON.parse(u.metadata):{},m=f.overdrive??{},T=s?.defaultTurns??m.defaultTurns??3,G=s?.updatedBy??"ui",M=new Date().toISOString(),O,v,L,V;switch(n){case "enable-count":{let Q=s?.turns??T,Z=s?.consumeCurrent?Math.max(Q-1,0):Q;O=Z>0?"count":"off",v=Z,L=!0,V="count";break}case "enable-latch":{O="latch",v=0,L=!0,V="latch";break}case "disable":{O="off",v=0,L=!1;break}default:{let Q=m.state??"off",Z=typeof m.remaining=="number"?m.remaining:0;if(Q==="count"&&Z>0){let Et=Z-1;Et<=0?(O="off",v=0):(O="count",v=Et),L=!0,V="count";}else Q==="latch"?(O="latch",v=0,L=!0,V="latch"):(O="off",v=0,L=!1);break}}return f.overdrive={state:O,remaining:v,defaultTurns:T,updatedAt:M,updatedBy:G},l.update(p).set({metadata:JSON.stringify(f),updated_at:M}).where(a).run(),{applied:L,appliedMode:V,state:O,remaining:v}},{behavior:"immediate"})}catch(a){throw a instanceof _?a:new _("DB_ERROR","Failed to resolve overdrive",a)}finally{i.close();}}};function $e(d){return d.replace(/<conversation_history[^>]*>[\s\S]*?<\/conversation_history>/g,"").split(`
|
|
304
|
+
`).filter(s=>!(s.startsWith("Loaded ")&&s.includes("layouts from")||s.includes("[dotenv@")||s.includes("[Nest]")&&s.includes("DEBUG")||s.startsWith("Registered custom layout:")||s.startsWith("Updated custom layout:"))).join(`
|
|
305
|
+
`).trim()}function Ie(d){if(!d)return "";let t=d;try{let e=JSON.parse(t);Array.isArray(e)?t=e.filter(n=>n?.type==="text"&&n?.text).map(n=>n.text).join(`
|
|
306
|
+
`):e&&typeof e=="object"&&e.result!==void 0&&(t=e.result||"");}catch{t=$e(t);}return t}var lt=class{dbPath;constructor(t){this.dbPath=t??join(homedir(),".crewx","crewx.db");}getThreadRepo(){return new ct({dbPath:this.dbPath})}updateThread(t,e){this.getThreadRepo().updateThread(t,{title:e.title});}async ensureThread(t,e,n){let s=this.getThreadRepo(),o=s.findThreadById(t);if(o){if(o.platform!==e)throw new Error(`Thread '${t}' already exists with platform '${o.platform}' \u2014 cannot change to '${e}' (platform is immutable)`);return {created:false}}return s.ensureThread(t,e,n),{created:true}}async fetchHistory(t,e){let n=e?.limit??100,s=this.getThreadRepo(),o=s.findThreadById(t),i=s.findTopLevelTasks(t,void 0,n),a=new Set(["queued","cancelled"]);i=i.filter(u=>(!u.status||!a.has(u.status))&&(!e?.currentTraceId||u.trace_id!==e.currentTraceId));let c=o?.platform??"cli",l=this.rowsToMessages(i);return {threadId:t,platform:c,messages:l,metadata:{title:o?.title??void 0,firstMessage:o?.first_message??void 0,lastMessage:o?.last_message??void 0,messageCount:o?.message_count??0,updatedAt:o?.updated_at?new Date(o.updated_at).getTime():void 0}}}async saveUserMessage(t,e,n,s){let{firstMessage:o}=this.getThreadRepo().saveUserMessage(t,e);return {id:t,firstMessage:o}}async saveAssistantMessage(t,e,n,s){return this.getThreadRepo().saveAssistantMessage(t,e),{id:t}}close(){}normalizeStatus(t){if(t&&!["success","completed","done"].includes(t)){if(["failed","error"].includes(t))return "failed";if(t==="running")return "running"}}rowsToMessages(t){let e=[];for(let n of t){n.prompt&&e.push({id:`${n.id}-user`,text:n.prompt,isAssistant:false,timestamp:new Date(n.started_at).getTime(),metadata:{caller_agent_id:n.caller_agent_id}});let s=Ie(n.result),o=this.normalizeStatus(n.status);if(s||o==="running"||o==="failed"){let i={agent_id:n.agent_id,task_id:n.id};o&&(i.status=o),o==="failed"&&n.error&&(i.reason=n.error.split(`
|
|
307
|
+
`)[0].slice(0,200)),e.push({id:`${n.id}-assistant`,text:s,isAssistant:true,timestamp:new Date(n.started_at).getTime(),metadata:i});}}return e}};var wt=class extends U{name="conversation";_provider;unsubStart=null;unsubEnd=null;constructor(t){super(),this._provider=new lt(t?.dbPath);}get conversationProvider(){return this._provider}async afterUserMessage(t,e,n,s){}async afterAssistantMessage(t,e,n){}attach(t){this.unsubStart=t.on("task:start",async e=>{if(!e.threadId)return;let n=e.platform??"cli";try{let s=await this._provider.ensureThread(e.threadId,n,e.workspaceId),o=await this._provider.saveUserMessage(e.threadId,e.message??"");await this.afterUserMessage(e.threadId,o.id,s.created||o.firstMessage,e);}catch{}}),this.unsubEnd=t.on("task:end",async e=>{if(!e.result)return;let n=e.metadata?.threadId;if(!n)return;let s=e.agentRef?.replace(/^@/,"")??"";try{let{id:o}=await this._provider.saveAssistantMessage(n,e.result,s);await this.afterAssistantMessage(n,o,e);}catch{}});}detach(t){this.unsubStart?.(),this.unsubStart=null,this.unsubEnd?.(),this.unsubEnd=null,this._provider.close?.();}};export{wt as ConversationPlugin,ut as FileLoggerPlugin,kt as SqliteTracingPlugin};
|