crewx 0.8.1 → 0.8.2-rc.1

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 (106) hide show
  1. package/README.md +268 -268
  2. package/bin/cli-commands.js +34 -0
  3. package/bin/crewx-lib.js +213 -108
  4. package/bin/crewx-ui.js +83 -83
  5. package/bin/crewx.js +219 -147
  6. package/bin/launcher-flags.js +29 -0
  7. package/bin/package.json +1 -1
  8. package/dist/assets/{MarketPage-Dwsg6K-B.js → MarketPage-njRHlSSN.js} +1 -1
  9. package/dist/assets/{PromptTab-DVKc7hJY.js → PromptTab-CNyClpEe.js} +1 -1
  10. package/dist/assets/{_baseUniq-wjlVo2E6.js → _baseUniq-CGNNUfN7.js} +1 -1
  11. package/dist/assets/{arc-BfPgRtzW.js → arc-BEN-1A69.js} +1 -1
  12. package/dist/assets/{architectureDiagram-Q4EWVU46-ewcueFAG.js → architectureDiagram-Q4EWVU46-fAPvGzXk.js} +1 -1
  13. package/dist/assets/{blockDiagram-DXYQGD6D-TxlbbvKn.js → blockDiagram-DXYQGD6D-BWrb7uua.js} +1 -1
  14. package/dist/assets/{c4Diagram-AHTNJAMY-C1lT_bl_.js → c4Diagram-AHTNJAMY-CbnLz81q.js} +1 -1
  15. package/dist/assets/channel-uEnl63Ym.js +1 -0
  16. package/dist/assets/chatgpt-logo-dark.svg +15 -15
  17. package/dist/assets/chatgpt-logo.svg +15 -15
  18. package/dist/assets/{chunk-4BX2VUAB-C41j2mCL.js → chunk-4BX2VUAB-BopMVv1Q.js} +1 -1
  19. package/dist/assets/{chunk-4TB4RGXK-HNNsUbz0.js → chunk-4TB4RGXK-Axjc-DMR.js} +1 -1
  20. package/dist/assets/{chunk-55IACEB6-qtCgO0r2.js → chunk-55IACEB6-BVzu25a2.js} +1 -1
  21. package/dist/assets/{chunk-EDXVE4YY-BSnDYtsd.js → chunk-EDXVE4YY-Csh0IKkY.js} +1 -1
  22. package/dist/assets/{chunk-FMBD7UC4-DyHRLQqX.js → chunk-FMBD7UC4-D3yW6Ykv.js} +1 -1
  23. package/dist/assets/{chunk-OYMX7WX6-CCjfi6WS.js → chunk-OYMX7WX6-CDzLbKmY.js} +1 -1
  24. package/dist/assets/{chunk-QZHKN3VN-COLty8kd.js → chunk-QZHKN3VN-CqYP7txP.js} +1 -1
  25. package/dist/assets/{chunk-YZCP3GAM-CHUUnGeN.js → chunk-YZCP3GAM-CIz2ApJG.js} +1 -1
  26. package/dist/assets/classDiagram-6PBFFD2Q-CU98S3yn.js +1 -0
  27. package/dist/assets/classDiagram-v2-HSJHXN6E-CU98S3yn.js +1 -0
  28. package/dist/assets/clone-D3Eqsbb8.js +1 -0
  29. package/dist/assets/{cose-bilkent-S5V4N54A-CSip-V2g.js → cose-bilkent-S5V4N54A-DgVG9_nb.js} +1 -1
  30. package/dist/assets/{dagre-KV5264BT-DkdpnWhv.js → dagre-KV5264BT-DnNIMI1A.js} +1 -1
  31. package/dist/assets/{diagram-5BDNPKRD-PH4qc6PV.js → diagram-5BDNPKRD-asGr2q6a.js} +1 -1
  32. package/dist/assets/{diagram-G4DWMVQ6-Cg5xZcjx.js → diagram-G4DWMVQ6-hwyZkwNx.js} +1 -1
  33. package/dist/assets/{diagram-MMDJMWI5-soKmeTCW.js → diagram-MMDJMWI5-BJbIxezj.js} +1 -1
  34. package/dist/assets/{diagram-TYMM5635-Daq5Mihu.js → diagram-TYMM5635-JB2YJBVu.js} +1 -1
  35. package/dist/assets/{erDiagram-SMLLAGMA-kr2OtY0Y.js → erDiagram-SMLLAGMA-i1KkUgG6.js} +1 -1
  36. package/dist/assets/{flowDiagram-DWJPFMVM-DQZCb8gm.js → flowDiagram-DWJPFMVM-62cwXjLB.js} +1 -1
  37. package/dist/assets/{ganttDiagram-T4ZO3ILL-BHkn485T.js → ganttDiagram-T4ZO3ILL-BDhku_zz.js} +1 -1
  38. package/dist/assets/{gitGraphDiagram-UUTBAWPF-FaCyYFmC.js → gitGraphDiagram-UUTBAWPF-DkHe0Kwk.js} +1 -1
  39. package/dist/assets/{graph-BVJlrP6V.js → graph-BnMMHCuQ.js} +1 -1
  40. package/dist/assets/{infoDiagram-42DDH7IO-DJOWkKdM.js → infoDiagram-42DDH7IO-V7zg8GAV.js} +1 -1
  41. package/dist/assets/{ishikawaDiagram-UXIWVN3A-VfpvNaIf.js → ishikawaDiagram-UXIWVN3A-CTtEO2wl.js} +1 -1
  42. package/dist/assets/{journeyDiagram-VCZTEJTY-CPzsak-v.js → journeyDiagram-VCZTEJTY-NxQMTN2m.js} +1 -1
  43. package/dist/assets/{kanban-definition-6JOO6SKY-DFqLDBU0.js → kanban-definition-6JOO6SKY-BHBrmGg3.js} +1 -1
  44. package/dist/assets/{layout-CCSbNPHm.js → layout-DutU1eng.js} +1 -1
  45. package/dist/assets/{linear-C4T7PCKE.js → linear-Czvrvocq.js} +1 -1
  46. package/dist/assets/{main-CELBpK6r.js → main-D0PuDE6-.js} +230 -226
  47. package/dist/assets/{min-CGQNEYGh.js → min-CI38XtLs.js} +1 -1
  48. package/dist/assets/{mindmap-definition-QFDTVHPH-AuU1EqwS.js → mindmap-definition-QFDTVHPH-CbFeHoxp.js} +1 -1
  49. package/dist/assets/{pieDiagram-DEJITSTG-CopkCZwp.js → pieDiagram-DEJITSTG-MV4uB5yA.js} +1 -1
  50. package/dist/assets/{quadrantDiagram-34T5L4WZ-lMKrSv_t.js → quadrantDiagram-34T5L4WZ-D0a8e2mx.js} +1 -1
  51. package/dist/assets/{requirementDiagram-MS252O5E-dWUpHOFb.js → requirementDiagram-MS252O5E-CeTlv4na.js} +1 -1
  52. package/dist/assets/{sankeyDiagram-XADWPNL6-C8UQx9Bb.js → sankeyDiagram-XADWPNL6-D1E3xq9q.js} +1 -1
  53. package/dist/assets/{sequenceDiagram-FGHM5R23-CUVNIItJ.js → sequenceDiagram-FGHM5R23-BO1RXtYs.js} +1 -1
  54. package/dist/assets/{stateDiagram-FHFEXIEX-Ct0GamGl.js → stateDiagram-FHFEXIEX-AhFKkuPE.js} +1 -1
  55. package/dist/assets/stateDiagram-v2-QKLJ7IA2-gv2g1MYi.js +1 -0
  56. package/dist/assets/{timeline-definition-GMOUNBTQ-ul8Po7f7.js → timeline-definition-GMOUNBTQ-BMVxUhID.js} +1 -1
  57. package/dist/assets/{vennDiagram-DHZGUBPP-B4AOWQnP.js → vennDiagram-DHZGUBPP-YFiJZns6.js} +1 -1
  58. package/dist/assets/{wardley-RL74JXVD-Dr7Wp3AJ.js → wardley-RL74JXVD-JlCdJekg.js} +1 -1
  59. package/dist/assets/{wardleyDiagram-NUSXRM2D-Ck70faXX.js → wardleyDiagram-NUSXRM2D-BLn2PZq9.js} +1 -1
  60. package/dist/assets/{xychartDiagram-5P7HB3ND-Bsy5-cNt.js → xychartDiagram-5P7HB3ND-DNOUK9or.js} +1 -1
  61. package/dist/index.html +12 -12
  62. package/dist-electron/main.js +153 -116
  63. package/dist-electron/overlay.js +102 -65
  64. package/dist-electron/package.json +1 -0
  65. package/dist-electron/preload.js +8 -8
  66. package/dist-server/bootstrap/crewx-server.js +19 -10
  67. package/dist-server/repository/box.repository.js +20 -20
  68. package/dist-server/repository/project.repository.js +13 -13
  69. package/dist-server/repository/request-log.repository.js +10 -10
  70. package/dist-server/repository/task.repository.js +72 -72
  71. package/dist-server/repository/thread.repository.js +57 -57
  72. package/package.json +6 -6
  73. package/packages/cli/dist/bootstrap/crewx-cli.js +12 -0
  74. package/packages/cli/dist/commands/agent.js +23 -23
  75. package/packages/cli/dist/commands/init.js +19 -19
  76. package/packages/cli/dist/commands/parse-common-flags.d.ts +19 -3
  77. package/packages/cli/dist/commands/parse-common-flags.js +46 -6
  78. package/packages/cli/dist/commands/registry.d.ts +13 -0
  79. package/packages/cli/dist/commands/registry.js +29 -0
  80. package/packages/cli/dist/commands/task-db.js +7 -7
  81. package/packages/cli/dist/examples/deny-secrets-plugin.d.ts +22 -0
  82. package/packages/cli/dist/examples/deny-secrets-plugin.js +40 -0
  83. package/packages/cli/dist/main.js +134 -68
  84. package/packages/cli/dist/plugins/examples/echo-hook.d.ts +24 -0
  85. package/packages/cli/dist/plugins/examples/echo-hook.js +60 -0
  86. package/packages/cli/dist/plugins/examples/verify-echo-hook.d.ts +8 -0
  87. package/packages/cli/dist/plugins/examples/verify-echo-hook.js +47 -0
  88. package/packages/cli/dist/plugins/sqlite-tracing.d.ts +11 -0
  89. package/packages/cli/dist/plugins/sqlite-tracing.js +19 -0
  90. package/packages/cli/dist/schema/tasks.d.ts +7 -0
  91. package/packages/cli/dist/schema/tasks.js +48 -0
  92. package/packages/cli/package.json +52 -52
  93. package/scripts/build-manual.mjs +266 -266
  94. package/scripts/emit-dist-server-package-json.mjs +7 -7
  95. package/scripts/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  96. package/scripts/postinstall.mjs +44 -44
  97. package/scripts/smoke-tarball.mjs +285 -285
  98. package/scripts/snapshot-msg-list.sh +52 -52
  99. package/server.js +167 -164
  100. package/dist/assets/channel-BP4PNMmz.js +0 -1
  101. package/dist/assets/classDiagram-6PBFFD2Q-Upr3UAcM.js +0 -1
  102. package/dist/assets/classDiagram-v2-HSJHXN6E-Upr3UAcM.js +0 -1
  103. package/dist/assets/clone-B8BP7ReZ.js +0 -1
  104. package/dist/assets/stateDiagram-v2-QKLJ7IA2-CFBLQDEx.js +0 -1
  105. package/dist-server/domain/task/dto/project-usage.dto.js +0 -38
  106. package/dist-server/domain/thread/dto/send-message.dto.js +0 -10
@@ -31,9 +31,9 @@ let ProjectRepository = class ProjectRepository extends base_sqlite_repository_j
31
31
  }
32
32
  // Backfill workspace_path for rows that still have it in the old repo_path column
33
33
  try {
34
- db.run(`
35
- UPDATE workspaces SET workspace_path = repo_path
36
- WHERE (workspace_path IS NULL OR workspace_path = '') AND repo_path IS NOT NULL AND repo_path != ''
34
+ db.run(`
35
+ UPDATE workspaces SET workspace_path = repo_path
36
+ WHERE (workspace_path IS NULL OR workspace_path = '') AND repo_path IS NOT NULL AND repo_path != ''
37
37
  `);
38
38
  }
39
39
  catch {
@@ -86,13 +86,13 @@ let ProjectRepository = class ProjectRepository extends base_sqlite_repository_j
86
86
  const db = this.openProjectDb();
87
87
  try {
88
88
  const countRow = db.get('SELECT COUNT(*) as count FROM threads WHERE workspace_id = ?', [id]);
89
- const rows = db.all(`
90
- SELECT t.*,
91
- (SELECT agent_id FROM tasks tk WHERE tk.thread_id = t.id AND tk.agent_id IS NOT NULL ORDER BY tk.started_at ASC LIMIT 1) AS agent_id
92
- FROM threads t
93
- WHERE t.workspace_id = ?
94
- ORDER BY t.updated_at DESC
95
- LIMIT ? OFFSET ?
89
+ const rows = db.all(`
90
+ SELECT t.*,
91
+ (SELECT agent_id FROM tasks tk WHERE tk.thread_id = t.id AND tk.agent_id IS NOT NULL ORDER BY tk.started_at ASC LIMIT 1) AS agent_id
92
+ FROM threads t
93
+ WHERE t.workspace_id = ?
94
+ ORDER BY t.updated_at DESC
95
+ LIMIT ? OFFSET ?
96
96
  `, [id, params.limit, params.offset]);
97
97
  return { rows, total: countRow.count };
98
98
  }
@@ -128,9 +128,9 @@ let ProjectRepository = class ProjectRepository extends base_sqlite_repository_j
128
128
  const db = this.openProjectDb(false);
129
129
  try {
130
130
  const now = new Date().toISOString();
131
- db.run(`
132
- INSERT INTO workspaces (id, slug, name, workspace_path, is_active, created_at, updated_at)
133
- VALUES (?, ?, ?, ?, 1, ?, ?)
131
+ db.run(`
132
+ INSERT INTO workspaces (id, slug, name, workspace_path, is_active, created_at, updated_at)
133
+ VALUES (?, ?, ?, ?, 1, ?, ?)
134
134
  `, [id, slug, name, repoPath, now, now]);
135
135
  return db.get('SELECT * FROM workspaces WHERE id = ?', [id]);
136
136
  }
@@ -15,16 +15,16 @@ const common_1 = require("@nestjs/common");
15
15
  const base_sqlite_repository_js_1 = require("./base-sqlite.repository.js");
16
16
  let RequestLogRepository = class RequestLogRepository extends base_sqlite_repository_js_1.BaseSqliteRepository {
17
17
  static { RequestLogRepository_1 = this; }
18
- static INSERT_SQL = `
19
- INSERT INTO request_logs (
20
- id, path, method, status_code, duration_ms,
21
- ip, request_headers, response_headers, request_body, response_body,
22
- query, user_id, project_id, partition_key, timestamp, metadata
23
- ) VALUES (
24
- ?, ?, ?, ?, ?,
25
- ?, ?, ?, ?, ?,
26
- ?, ?, ?, ?, ?, ?
27
- )
18
+ static INSERT_SQL = `
19
+ INSERT INTO request_logs (
20
+ id, path, method, status_code, duration_ms,
21
+ ip, request_headers, response_headers, request_body, response_body,
22
+ query, user_id, project_id, partition_key, timestamp, metadata
23
+ ) VALUES (
24
+ ?, ?, ?, ?, ?,
25
+ ?, ?, ?, ?, ?,
26
+ ?, ?, ?, ?, ?, ?
27
+ )
28
28
  `;
29
29
  logger = new common_1.Logger(RequestLogRepository_1.name);
30
30
  db = null;
@@ -23,16 +23,16 @@ let TaskRepository = class TaskRepository extends base_sqlite_repository_js_1.Ba
23
23
  const db = this.openReadonly(dbPath);
24
24
  try {
25
25
  // Primary lookup: by internal task UUID
26
- let row = db.get(`SELECT id, agent_id, status, started_at, completed_at, duration_ms,
27
- error, caller_agent_id, parent_task_id, logs,
28
- prompt, result, model, thread_id, input_tokens, output_tokens, cost_usd, metadata
26
+ let row = db.get(`SELECT id, agent_id, status, started_at, completed_at, duration_ms,
27
+ error, caller_agent_id, parent_task_id, logs,
28
+ prompt, result, model, thread_id, input_tokens, output_tokens, cost_usd, metadata
29
29
  FROM tasks WHERE id = ?${wsFilter}`, [taskId, ...wsParams]);
30
30
  // Fallback: treat taskId as thread/conversation name
31
31
  if (!row) {
32
- row = db.get(`SELECT id, agent_id, status, started_at, completed_at, duration_ms,
33
- error, caller_agent_id, parent_task_id, logs,
34
- prompt, result, model, thread_id, input_tokens, output_tokens, cost_usd, metadata
35
- FROM tasks WHERE (thread_id = ? OR (thread_id IS NULL AND command LIKE ?))${wsFilter}
32
+ row = db.get(`SELECT id, agent_id, status, started_at, completed_at, duration_ms,
33
+ error, caller_agent_id, parent_task_id, logs,
34
+ prompt, result, model, thread_id, input_tokens, output_tokens, cost_usd, metadata
35
+ FROM tasks WHERE (thread_id = ? OR (thread_id IS NULL AND command LIKE ?))${wsFilter}
36
36
  ORDER BY started_at DESC LIMIT 1`, [taskId, `%--thread=${taskId}%`, ...wsParams]);
37
37
  }
38
38
  if (row)
@@ -51,7 +51,7 @@ let TaskRepository = class TaskRepository extends base_sqlite_repository_js_1.Ba
51
51
  }
52
52
  /** Get child tasks for a parent task. */
53
53
  findChildTasks(db, parentTaskId) {
54
- return db.all(`SELECT id, agent_id, status, started_at, completed_at, duration_ms, error, logs
54
+ return db.all(`SELECT id, agent_id, status, started_at, completed_at, duration_ms, error, logs
55
55
  FROM tasks WHERE parent_task_id = ? ORDER BY started_at ASC`, [parentTaskId]);
56
56
  }
57
57
  /** Get workspace usage summary, optionally filtered by workspaceId. */
@@ -63,18 +63,18 @@ let TaskRepository = class TaskRepository extends base_sqlite_repository_js_1.Ba
63
63
  try {
64
64
  const whereClause = workspaceId ? `WHERE workspace_id = ?` : '';
65
65
  const queryParams = workspaceId ? [workspaceId] : [];
66
- return db.all(`
67
- SELECT
68
- COALESCE(workspace_id, 'unknown') AS workspace_id,
69
- COALESCE(workspace_name, 'Unknown Workspace') AS workspace_name,
70
- SUM(input_tokens) AS input_tokens,
71
- SUM(output_tokens) AS output_tokens,
72
- SUM(cost_usd) AS cost_usd,
73
- COUNT(*) AS task_count
74
- FROM tasks
75
- ${whereClause}
76
- GROUP BY workspace_id, workspace_name
77
- ORDER BY (SUM(input_tokens) + SUM(output_tokens)) DESC
66
+ return db.all(`
67
+ SELECT
68
+ COALESCE(workspace_id, 'unknown') AS workspace_id,
69
+ COALESCE(workspace_name, 'Unknown Workspace') AS workspace_name,
70
+ SUM(input_tokens) AS input_tokens,
71
+ SUM(output_tokens) AS output_tokens,
72
+ SUM(cost_usd) AS cost_usd,
73
+ COUNT(*) AS task_count
74
+ FROM tasks
75
+ ${whereClause}
76
+ GROUP BY workspace_id, workspace_name
77
+ ORDER BY (SUM(input_tokens) + SUM(output_tokens)) DESC
78
78
  `, queryParams);
79
79
  }
80
80
  catch (error) {
@@ -98,7 +98,7 @@ let TaskRepository = class TaskRepository extends base_sqlite_repository_js_1.Ba
98
98
  continue;
99
99
  const db = this.openReadonly(dbPath);
100
100
  try {
101
- const rows = db.all(`SELECT id, input_tokens, output_tokens, cost_usd
101
+ const rows = db.all(`SELECT id, input_tokens, output_tokens, cost_usd
102
102
  FROM tasks WHERE thread_id = ? OR (thread_id IS NULL AND command LIKE ?)`, [threadId, `%--thread=${threadId}%`]);
103
103
  for (const row of rows) {
104
104
  if (seenIds.has(row.id))
@@ -134,9 +134,9 @@ let TaskRepository = class TaskRepository extends base_sqlite_repository_js_1.Ba
134
134
  const baseParams = [threadId, `%--thread=${threadId}%`];
135
135
  if (workspaceId)
136
136
  baseParams.push(workspaceId);
137
- const rows = db.all(`SELECT id, agent_id, started_at, completed_at, logs
138
- FROM tasks
139
- WHERE (thread_id = ? OR (thread_id IS NULL AND command LIKE ?))${wsFilter}
137
+ const rows = db.all(`SELECT id, agent_id, started_at, completed_at, logs
138
+ FROM tasks
139
+ WHERE (thread_id = ? OR (thread_id IS NULL AND command LIKE ?))${wsFilter}
140
140
  ORDER BY started_at ASC`, baseParams);
141
141
  for (const row of rows) {
142
142
  if (!seenIds.has(row.id)) {
@@ -187,10 +187,10 @@ let TaskRepository = class TaskRepository extends base_sqlite_repository_js_1.Ba
187
187
  const countRow = db.get(`SELECT COUNT(*) AS cnt FROM tasks ${whereClause}`, queryParams);
188
188
  const total = countRow?.cnt ?? 0;
189
189
  const sortDir = params.sortDir === 'ASC' ? 'ASC' : 'DESC';
190
- const tasks = db.all(`SELECT id, agent_id, status, prompt, model, started_at, completed_at, duration_ms,
191
- input_tokens, output_tokens, cost_usd, thread_id
192
- FROM tasks ${whereClause}
193
- ORDER BY started_at ${sortDir}
190
+ const tasks = db.all(`SELECT id, agent_id, status, prompt, model, started_at, completed_at, duration_ms,
191
+ input_tokens, output_tokens, cost_usd, thread_id
192
+ FROM tasks ${whereClause}
193
+ ORDER BY started_at ${sortDir}
194
194
  LIMIT ? OFFSET ?`, [...queryParams, params.limit, params.offset]);
195
195
  return { tasks, total };
196
196
  }
@@ -215,34 +215,34 @@ let TaskRepository = class TaskRepository extends base_sqlite_repository_js_1.Ba
215
215
  ? (params.push(workspace), `AND t.workspace_name = ?`)
216
216
  : '';
217
217
  // Provider derived from coding_agent_command first word (no agents table)
218
- return db.all(`
219
- SELECT
220
- t.agent_id,
221
- t.workspace_id,
222
- t.workspace_name,
223
- COALESCE(
224
- 'cli/' || SUBSTR(t.coding_agent_command, 1,
225
- CASE WHEN INSTR(t.coding_agent_command, ' ') > 0
226
- THEN INSTR(t.coding_agent_command, ' ') - 1
227
- ELSE LENGTH(t.coding_agent_command)
228
- END
229
- ),
230
- 'unknown'
231
- ) AS provider,
232
- COALESCE(SUM(t.input_tokens), 0) AS input_tokens,
233
- COALESCE(SUM(t.output_tokens), 0) AS output_tokens,
234
- COALESCE(SUM(t.input_tokens), 0) + COALESCE(SUM(t.output_tokens), 0) AS total_tokens,
235
- COALESCE(SUM(t.cost_usd), 0) AS total_cost,
236
- COUNT(*) AS task_count,
237
- COALESCE(SUM(t.duration_ms), 0) AS active_duration_ms,
238
- MAX(t.completed_at) AS last_active_at
239
- FROM tasks t
240
- WHERE t.status IN ('completed', 'success')
241
- AND t.started_at >= ?
242
- AND t.started_at < ?
243
- ${workspaceCondition}
244
- GROUP BY t.agent_id, t.workspace_id, t.workspace_name, provider
245
- ORDER BY total_tokens DESC
218
+ return db.all(`
219
+ SELECT
220
+ t.agent_id,
221
+ t.workspace_id,
222
+ t.workspace_name,
223
+ COALESCE(
224
+ 'cli/' || SUBSTR(t.coding_agent_command, 1,
225
+ CASE WHEN INSTR(t.coding_agent_command, ' ') > 0
226
+ THEN INSTR(t.coding_agent_command, ' ') - 1
227
+ ELSE LENGTH(t.coding_agent_command)
228
+ END
229
+ ),
230
+ 'unknown'
231
+ ) AS provider,
232
+ COALESCE(SUM(t.input_tokens), 0) AS input_tokens,
233
+ COALESCE(SUM(t.output_tokens), 0) AS output_tokens,
234
+ COALESCE(SUM(t.input_tokens), 0) + COALESCE(SUM(t.output_tokens), 0) AS total_tokens,
235
+ COALESCE(SUM(t.cost_usd), 0) AS total_cost,
236
+ COUNT(*) AS task_count,
237
+ COALESCE(SUM(t.duration_ms), 0) AS active_duration_ms,
238
+ MAX(t.completed_at) AS last_active_at
239
+ FROM tasks t
240
+ WHERE t.status IN ('completed', 'success')
241
+ AND t.started_at >= ?
242
+ AND t.started_at < ?
243
+ ${workspaceCondition}
244
+ GROUP BY t.agent_id, t.workspace_id, t.workspace_name, provider
245
+ ORDER BY total_tokens DESC
246
246
  `, params);
247
247
  }
248
248
  catch (error) {
@@ -263,18 +263,18 @@ let TaskRepository = class TaskRepository extends base_sqlite_repository_js_1.Ba
263
263
  const workspaceCondition = workspace
264
264
  ? (params.push(workspace), `AND t.workspace_name = ?`)
265
265
  : '';
266
- return db.all(`
267
- SELECT
268
- t.started_at,
269
- t.agent_id,
270
- COALESCE(t.input_tokens, 0) AS input_tokens,
271
- COALESCE(t.output_tokens, 0) AS output_tokens
272
- FROM tasks t
273
- WHERE t.status IN ('completed', 'success')
274
- AND t.started_at >= ?
275
- AND t.started_at < ?
276
- ${workspaceCondition}
277
- ORDER BY t.started_at ASC
266
+ return db.all(`
267
+ SELECT
268
+ t.started_at,
269
+ t.agent_id,
270
+ COALESCE(t.input_tokens, 0) AS input_tokens,
271
+ COALESCE(t.output_tokens, 0) AS output_tokens
272
+ FROM tasks t
273
+ WHERE t.status IN ('completed', 'success')
274
+ AND t.started_at >= ?
275
+ AND t.started_at < ?
276
+ ${workspaceCondition}
277
+ ORDER BY t.started_at ASC
278
278
  `, params);
279
279
  }
280
280
  catch (error) {
@@ -315,7 +315,7 @@ let TaskRepository = class TaskRepository extends base_sqlite_repository_js_1.Ba
315
315
  const params = workspaceId
316
316
  ? [error, now, taskId, workspaceId]
317
317
  : [error, now, taskId];
318
- db.run(`UPDATE tasks SET status = 'failed', error = ?, completed_at = ?
318
+ db.run(`UPDATE tasks SET status = 'failed', error = ?, completed_at = ?
319
319
  WHERE id = ? AND status = 'running'${wsFilter}`, params);
320
320
  const changes = db.get(`SELECT changes() AS cnt`);
321
321
  return (changes?.cnt ?? 0) > 0;
@@ -336,9 +336,9 @@ let TaskRepository = class TaskRepository extends base_sqlite_repository_js_1.Ba
336
336
  try {
337
337
  const wsFilter = workspaceId ? ` AND workspace_id = ?` : '';
338
338
  const params = workspaceId ? [`%${hint}%`, workspaceId] : [`%${hint}%`];
339
- const rows = db.all(`SELECT id, agent_id, started_at, completed_at, logs
340
- FROM tasks
341
- WHERE prompt LIKE ?${wsFilter}
339
+ const rows = db.all(`SELECT id, agent_id, started_at, completed_at, logs
340
+ FROM tasks
341
+ WHERE prompt LIKE ?${wsFilter}
342
342
  ORDER BY started_at ASC`, params);
343
343
  for (const row of rows) {
344
344
  if (!seenIds.has(row.id)) {
@@ -29,12 +29,12 @@ let ThreadRepository = class ThreadRepository extends base_sqlite_repository_js_
29
29
  ? `WHERE (workspace_id = ? OR workspace_id IS NULL)`
30
30
  : '';
31
31
  const queryParams = workspaceId ? [workspaceId] : [];
32
- const fetched = db.all(`
33
- SELECT id, workspace_id, platform, title, first_message, last_message,
34
- message_count, created_at, updated_at, metadata
35
- FROM threads
36
- ${whereClause}
37
- ORDER BY updated_at DESC
32
+ const fetched = db.all(`
33
+ SELECT id, workspace_id, platform, title, first_message, last_message,
34
+ message_count, created_at, updated_at, metadata
35
+ FROM threads
36
+ ${whereClause}
37
+ ORDER BY updated_at DESC
38
38
  `, queryParams);
39
39
  for (const row of fetched) {
40
40
  if (!seenIds.has(row.id)) {
@@ -66,10 +66,10 @@ let ThreadRepository = class ThreadRepository extends base_sqlite_repository_js_
66
66
  continue;
67
67
  const wsFilter = workspaceId ? ` AND (workspace_id = ? OR workspace_id IS NULL)` : '';
68
68
  const params = workspaceId ? [threadId, workspaceId] : [threadId];
69
- const row = db.get(`
70
- SELECT id, workspace_id, platform, title, first_message, last_message,
71
- message_count, created_at, updated_at, metadata
72
- FROM threads WHERE id = ?${wsFilter}
69
+ const row = db.get(`
70
+ SELECT id, workspace_id, platform, title, first_message, last_message,
71
+ message_count, created_at, updated_at, metadata
72
+ FROM threads WHERE id = ?${wsFilter}
73
73
  `, params);
74
74
  if (row)
75
75
  return row;
@@ -129,22 +129,22 @@ let ThreadRepository = class ThreadRepository extends base_sqlite_repository_js_
129
129
  continue;
130
130
  const wsFilter = workspaceId ? ` AND workspace_id = ?` : '';
131
131
  const statsParams = workspaceId ? [threadId, workspaceId] : [threadId];
132
- const stats = db.get(`
133
- SELECT COUNT(*) as cnt,
134
- COALESCE(SUM(input_tokens), 0) as total_input,
135
- COALESCE(SUM(output_tokens), 0) as total_output,
136
- COALESCE(SUM(cost_usd), 0) as total_cost
137
- FROM tasks
138
- WHERE thread_id = ? AND (parent_task_id IS NULL OR parent_task_id = '')${wsFilter}
132
+ const stats = db.get(`
133
+ SELECT COUNT(*) as cnt,
134
+ COALESCE(SUM(input_tokens), 0) as total_input,
135
+ COALESCE(SUM(output_tokens), 0) as total_output,
136
+ COALESCE(SUM(cost_usd), 0) as total_cost
137
+ FROM tasks
138
+ WHERE thread_id = ? AND (parent_task_id IS NULL OR parent_task_id = '')${wsFilter}
139
139
  `, statsParams);
140
140
  taskCount += stats.cnt;
141
141
  inputTokens += stats.total_input;
142
142
  outputTokens += stats.total_output;
143
143
  costUsd += stats.total_cost;
144
- const agentRows = db.all(`
145
- SELECT DISTINCT agent_id FROM tasks
146
- WHERE thread_id = ? AND agent_id IS NOT NULL AND agent_id != ''
147
- AND (parent_task_id IS NULL OR parent_task_id = '')${wsFilter}
144
+ const agentRows = db.all(`
145
+ SELECT DISTINCT agent_id FROM tasks
146
+ WHERE thread_id = ? AND agent_id IS NOT NULL AND agent_id != ''
147
+ AND (parent_task_id IS NULL OR parent_task_id = '')${wsFilter}
148
148
  `, statsParams);
149
149
  for (const row of agentRows) {
150
150
  agents.add(row.agent_id);
@@ -175,13 +175,13 @@ let ThreadRepository = class ThreadRepository extends base_sqlite_repository_js_
175
175
  continue;
176
176
  const wsFilter = workspaceId ? ` AND workspace_id = ?` : '';
177
177
  const taskParams = workspaceId ? [threadId, workspaceId] : [threadId];
178
- const tasks = db.all(`
179
- SELECT id, agent_id, prompt, result, status, started_at, completed_at,
180
- duration_ms, thread_id, logs, input_tokens, output_tokens, cost_usd,
181
- error, parent_task_id, caller_agent_id
182
- FROM tasks
183
- WHERE thread_id = ? AND (parent_task_id IS NULL OR parent_task_id = '')${wsFilter}
184
- ORDER BY started_at ASC
178
+ const tasks = db.all(`
179
+ SELECT id, agent_id, prompt, result, status, started_at, completed_at,
180
+ duration_ms, thread_id, logs, input_tokens, output_tokens, cost_usd,
181
+ error, parent_task_id, caller_agent_id
182
+ FROM tasks
183
+ WHERE thread_id = ? AND (parent_task_id IS NULL OR parent_task_id = '')${wsFilter}
184
+ ORDER BY started_at ASC
185
185
  `, taskParams);
186
186
  for (const t of tasks) {
187
187
  if (!seenIds.has(t.id)) {
@@ -215,12 +215,12 @@ let ThreadRepository = class ThreadRepository extends base_sqlite_repository_js_
215
215
  continue;
216
216
  const wsFilter = workspaceId ? ` AND workspace_id = ?` : '';
217
217
  const taskParams = workspaceId ? [threadId, workspaceId] : [threadId];
218
- const tasks = db.all(`
219
- SELECT id, agent_id, prompt, result, status, started_at, completed_at,
220
- duration_ms, thread_id, logs, input_tokens, output_tokens, cost_usd,
221
- error, parent_task_id, caller_agent_id
222
- FROM tasks WHERE thread_id = ?${wsFilter}
223
- ORDER BY started_at ASC
218
+ const tasks = db.all(`
219
+ SELECT id, agent_id, prompt, result, status, started_at, completed_at,
220
+ duration_ms, thread_id, logs, input_tokens, output_tokens, cost_usd,
221
+ error, parent_task_id, caller_agent_id
222
+ FROM tasks WHERE thread_id = ?${wsFilter}
223
+ ORDER BY started_at ASC
224
224
  `, taskParams);
225
225
  for (const t of tasks) {
226
226
  if (!seenIds.has(t.id)) {
@@ -250,17 +250,17 @@ let ThreadRepository = class ThreadRepository extends base_sqlite_repository_js_
250
250
  try {
251
251
  const wsFilter = workspaceId ? ` AND workspace_id = ?` : '';
252
252
  const findParams = workspaceId ? [taskId, threadId, workspaceId] : [taskId, threadId];
253
- const row = db.get(`
254
- SELECT id, agent_id, prompt, result, status, started_at, completed_at,
255
- duration_ms, thread_id, logs, input_tokens, output_tokens, cost_usd,
256
- error, parent_task_id, caller_agent_id
257
- FROM tasks WHERE id = ? AND thread_id = ?${wsFilter}
253
+ const row = db.get(`
254
+ SELECT id, agent_id, prompt, result, status, started_at, completed_at,
255
+ duration_ms, thread_id, logs, input_tokens, output_tokens, cost_usd,
256
+ error, parent_task_id, caller_agent_id
257
+ FROM tasks WHERE id = ? AND thread_id = ?${wsFilter}
258
258
  `, findParams);
259
259
  if (!row)
260
260
  continue;
261
- const children = db.all(`SELECT id, agent_id, prompt, result, status, started_at, completed_at,
262
- duration_ms, thread_id, logs, input_tokens, output_tokens, cost_usd,
263
- error, parent_task_id, caller_agent_id
261
+ const children = db.all(`SELECT id, agent_id, prompt, result, status, started_at, completed_at,
262
+ duration_ms, thread_id, logs, input_tokens, output_tokens, cost_usd,
263
+ error, parent_task_id, caller_agent_id
264
264
  FROM tasks WHERE parent_task_id = ? ORDER BY started_at ASC`, [row.id]);
265
265
  return { task: row, children };
266
266
  }
@@ -287,13 +287,13 @@ let ThreadRepository = class ThreadRepository extends base_sqlite_repository_js_
287
287
  continue;
288
288
  const db = this.openReadonly(dbPath);
289
289
  try {
290
- const rows = db.all(`
291
- SELECT id, agent_id, status, started_at, completed_at,
292
- duration_ms, thread_id, input_tokens, output_tokens, cost_usd, error
293
- FROM tasks
294
- WHERE thread_id IN (${placeholders})
295
- AND (parent_task_id IS NULL OR parent_task_id = '')
296
- ORDER BY started_at ASC
290
+ const rows = db.all(`
291
+ SELECT id, agent_id, status, started_at, completed_at,
292
+ duration_ms, thread_id, input_tokens, output_tokens, cost_usd, error
293
+ FROM tasks
294
+ WHERE thread_id IN (${placeholders})
295
+ AND (parent_task_id IS NULL OR parent_task_id = '')
296
+ ORDER BY started_at ASC
297
297
  `, threadIds);
298
298
  for (const row of rows) {
299
299
  const tid = row.thread_id;
@@ -323,17 +323,17 @@ let ThreadRepository = class ThreadRepository extends base_sqlite_repository_js_
323
323
  try {
324
324
  const existing = db.get('SELECT id, message_count FROM threads WHERE id = ?', [threadId]);
325
325
  if (existing) {
326
- db.run(`
327
- UPDATE threads
328
- SET updated_at = datetime('now'), message_count = message_count + 1
329
- WHERE id = ?
326
+ db.run(`
327
+ UPDATE threads
328
+ SET updated_at = datetime('now'), message_count = message_count + 1
329
+ WHERE id = ?
330
330
  `, [threadId]);
331
331
  }
332
332
  else {
333
- db.run(`
334
- INSERT OR REPLACE INTO threads
335
- (id, workspace_id, platform, title, first_message, message_count, created_at, updated_at)
336
- VALUES (?, ?, 'cli', ?, ?, 1, datetime('now'), datetime('now'))
333
+ db.run(`
334
+ INSERT OR REPLACE INTO threads
335
+ (id, workspace_id, platform, title, first_message, message_count, created_at, updated_at)
336
+ VALUES (?, ?, 'cli', ?, ?, 1, datetime('now'), datetime('now'))
337
337
  `, [threadId, opts.workspaceId ?? null, opts.title, opts.firstMessage]);
338
338
  }
339
339
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "crewx",
3
- "version": "0.8.1",
3
+ "version": "0.8.2-rc.1",
4
4
  "description": "CrewX — AI agent team dashboard with Electron UI and CLI (Web + Electron + Global CLI)",
5
5
  "main": "server.js",
6
6
  "bin": {
@@ -97,17 +97,17 @@
97
97
  "yargs": "^17.7.0",
98
98
  "zod": "^3.22.0",
99
99
  "zustand": "^4.5.0",
100
+ "@crewx/cli": "0.8.2-rc.1",
100
101
  "@crewx/cron": "0.1.7",
101
- "@crewx/cli": "0.8.1",
102
102
  "@crewx/doc": "0.1.7",
103
103
  "@crewx/knowledge-core": "0.1.5",
104
104
  "@crewx/memory": "0.1.9",
105
105
  "@crewx/search": "0.1.8",
106
+ "@crewx/wbs": "0.1.8",
106
107
  "@crewx/shared": "0.0.4",
107
108
  "@crewx/workflow": "0.3.8",
108
- "@crewx/sdk": "0.8.1",
109
- "@crewx/wbs": "0.1.8",
110
- "@crewx/skill": "0.1.7"
109
+ "@crewx/skill": "0.1.7",
110
+ "@crewx/sdk": "0.8.2-rc.1"
111
111
  },
112
112
  "devDependencies": {
113
113
  "@nestjs/cli": "^11.0.16",
@@ -145,7 +145,7 @@
145
145
  "typescript": "^5.3.3",
146
146
  "vite": "^5.0.10",
147
147
  "vite-plugin-electron": "^0.29.0",
148
- "vitest": "^4.0.18"
148
+ "vitest": "^3.2.4"
149
149
  },
150
150
  "optionalDependencies": {
151
151
  "electron": "^39.2.7"
@@ -1,12 +1,18 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.createCliCrewx = createCliCrewx;
4
7
  const fs_1 = require("fs");
5
8
  const path_1 = require("path");
9
+ const os_1 = require("os");
10
+ const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
6
11
  const sdk_1 = require("@crewx/sdk");
7
12
  const plugins_1 = require("@crewx/sdk/plugins");
8
13
  const register_builtin_tools_1 = require("../register-builtin-tools");
9
14
  const version_1 = require("../utils/version");
15
+ const tasks_1 = require("../schema/tasks");
10
16
  /**
11
17
  * Build a Crewx instance with CLI-standard plugins (FileLogger + SqliteTracing)
12
18
  * and built-in tools registered. Use this from any CLI command that needs a
@@ -39,6 +45,12 @@ async function createCliCrewx(configPath = process.env.CREWX_CONFIG ?? 'crewx.ya
39
45
  // No explicit config and file doesn't exist — built-in-only mode
40
46
  yamlPath = undefined;
41
47
  }
48
+ // Ensure ~/.crewx/crewx.db schema exists before SqliteTracingPlugin opens it.
49
+ const dbDir = (0, path_1.join)((0, os_1.homedir)(), '.crewx');
50
+ (0, fs_1.mkdirSync)(dbDir, { recursive: true });
51
+ const schemaDb = new better_sqlite3_1.default((0, path_1.join)(dbDir, 'crewx.db'));
52
+ (0, tasks_1.ensureTasksSchema)(schemaDb);
53
+ schemaDb.close();
42
54
  // Pass ourselves back to the SDK: when this Crewx encounters a file:// remote
43
55
  // agent, the SDK uses this factory to bootstrap the target Crewx instance
44
56
  // with the same plugin set (FileLogger + SqliteTracing + built-in tools).
@@ -219,28 +219,28 @@ function loadAgentSkills() {
219
219
  }
220
220
  }
221
221
  function printAgentHelp() {
222
- console.log(`
223
- CrewX Agent Management
224
-
225
- Usage:
226
- crewx agent # List configured agents (default)
227
- crewx agent ls # List configured agents
228
- crewx agent list # Alias for ls
229
- crewx agent prompt <id> # Inspect rendered agent prompt
230
-
231
- Filter Options (for agent ls):
232
- --role <value> Filter by agent role (comma-separated for multiple: PM,Dev)
233
- --team <value> Filter by agent team (comma-separated for multiple)
234
- --provider <value> Filter by provider (comma-separated, partial match: claude)
235
-
236
- Examples:
237
- crewx agent
238
- crewx agent ls
239
- crewx agent ls --role=PM
240
- crewx agent ls --team="CrewX Core 개발팀"
241
- crewx agent ls --provider=claude
242
- crewx agent ls --role=PM --provider=claude
243
- crewx agent ls --role=PM,general
244
- CREWX_CONFIG=./crewx.yaml crewx agent list
222
+ console.log(`
223
+ CrewX Agent Management
224
+
225
+ Usage:
226
+ crewx agent # List configured agents (default)
227
+ crewx agent ls # List configured agents
228
+ crewx agent list # Alias for ls
229
+ crewx agent prompt <id> # Inspect rendered agent prompt
230
+
231
+ Filter Options (for agent ls):
232
+ --role <value> Filter by agent role (comma-separated for multiple: PM,Dev)
233
+ --team <value> Filter by agent team (comma-separated for multiple)
234
+ --provider <value> Filter by provider (comma-separated, partial match: claude)
235
+
236
+ Examples:
237
+ crewx agent
238
+ crewx agent ls
239
+ crewx agent ls --role=PM
240
+ crewx agent ls --team="CrewX Core 개발팀"
241
+ crewx agent ls --provider=claude
242
+ crewx agent ls --role=PM --provider=claude
243
+ crewx agent ls --role=PM,general
244
+ CREWX_CONFIG=./crewx.yaml crewx agent list
245
245
  `.trim());
246
246
  }
@@ -56,27 +56,27 @@ function escapeYamlBlock(text) {
56
56
  }
57
57
  function generateDefaultYaml(agents) {
58
58
  const agentBlocks = agents
59
- .map((a) => ` - id: "${a.id}"
60
- name: "${a.name}"
61
- role: "${a.role}"
62
- team: "${a.team}"
63
- provider: "${a.provider}"
64
- default_model: "${a.default_model}"
65
- working_directory: "${a.working_directory}"
66
- description: "${a.description}"
67
- system_prompt: |
59
+ .map((a) => ` - id: "${a.id}"
60
+ name: "${a.name}"
61
+ role: "${a.role}"
62
+ team: "${a.team}"
63
+ provider: "${a.provider}"
64
+ default_model: "${a.default_model}"
65
+ working_directory: "${a.working_directory}"
66
+ description: "${a.description}"
67
+ system_prompt: |
68
68
  ${escapeYamlBlock(a.system_prompt)}`)
69
69
  .join('\n\n');
70
- return `# CrewX Agents Configuration
71
- # Generated by 'crewx init'
72
-
73
- agents:
74
- ${agentBlocks}
75
-
76
- # Usage examples:
77
- # crewx query "@planner analyze this codebase"
78
- # crewx execute "@developer implement the feature described above"
79
- # crewx agent ls
70
+ return `# CrewX Agents Configuration
71
+ # Generated by 'crewx init'
72
+
73
+ agents:
74
+ ${agentBlocks}
75
+
76
+ # Usage examples:
77
+ # crewx query "@planner analyze this codebase"
78
+ # crewx execute "@developer implement the feature described above"
79
+ # crewx agent ls
80
80
  `;
81
81
  }
82
82
  /**