crewx 0.8.9-rc.2 → 0.8.9-rc.21

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 (82) hide show
  1. package/dist/assets/{MarketPage-BpajB_Ex.js → MarketPage-Cl9KvLAo.js} +1 -1
  2. package/dist/assets/PromptTab-gj_BvClc.js +27 -0
  3. package/dist/assets/{arc-B0fFLEOc.js → arc-DDzVSXZh.js} +1 -1
  4. package/dist/assets/{architectureDiagram-UYN6MBPD-CrC7MKTM.js → architectureDiagram-UYN6MBPD-p8OOXe5w.js} +1 -1
  5. package/dist/assets/{blockDiagram-ZHA2E4KO-DJsG-9x2.js → blockDiagram-ZHA2E4KO-BTlfXGnf.js} +7 -7
  6. package/dist/assets/{c4Diagram-6F5ED5ID-DlkyjvkS.js → c4Diagram-6F5ED5ID-CKbrDPWE.js} +1 -1
  7. package/dist/assets/channel-Hzz-cXd0.js +1 -0
  8. package/dist/assets/{chunk-5HRBRIJM-B_Csqjvw.js → chunk-5HRBRIJM-otR_A_1G.js} +1 -1
  9. package/dist/assets/{chunk-7U56Z5CX-BlNdzxbh.js → chunk-7U56Z5CX-BliJIH4-.js} +1 -1
  10. package/dist/assets/{chunk-ASOPGD6M-BiFWfa3w.js → chunk-ASOPGD6M-CmzypD4Z.js} +1 -1
  11. package/dist/assets/{chunk-KFBOBJHC-ocugjY-9.js → chunk-KFBOBJHC-BW4u3lPL.js} +1 -1
  12. package/dist/assets/{chunk-T2TOU4HS-kUreJ-bv.js → chunk-T2TOU4HS-BAp6Xscz.js} +1 -1
  13. package/dist/assets/{chunk-TMUBEWPD-Du19Q8X-.js → chunk-TMUBEWPD-Bv_RKIlz.js} +1 -1
  14. package/dist/assets/classDiagram-LNE6IOMH-CXR-DJKP.js +1 -0
  15. package/dist/assets/classDiagram-v2-MQ7JQ4JX-CXR-DJKP.js +1 -0
  16. package/dist/assets/{dagre-4EVJKHTY-8N5qxubq.js → dagre-4EVJKHTY-sYyP6lkA.js} +1 -1
  17. package/dist/assets/{diagram-QW4FP2JN-CjLH9uYk.js → diagram-QW4FP2JN-XWldv7Gz.js} +1 -1
  18. package/dist/assets/{erDiagram-6RL3IURR-CXgt8NtN.js → erDiagram-6RL3IURR-Cd8OVAQ0.js} +1 -1
  19. package/dist/assets/{flowDiagram-7ASYPVHJ-CdFlmdmT.js → flowDiagram-7ASYPVHJ-Cc3onSB6.js} +1 -1
  20. package/dist/assets/{ganttDiagram-NTVNEXSI-DDjK4yxy.js → ganttDiagram-NTVNEXSI-Q6HxMUkA.js} +1 -1
  21. package/dist/assets/{gitGraph-YCYPL57B-Bd9jYZ-C.js → gitGraph-YCYPL57B-BUh0zUco.js} +1 -1
  22. package/dist/assets/{gitGraphDiagram-NRZ2UAAF-pmwetPkN.js → gitGraphDiagram-NRZ2UAAF-CvPqw-ya.js} +1 -1
  23. package/dist/assets/{infoDiagram-A4XQUW5V-BoDEaOyd.js → infoDiagram-A4XQUW5V-CbKGdGqb.js} +1 -1
  24. package/dist/assets/{journeyDiagram-G5WM74LC-D1LRuhB3.js → journeyDiagram-G5WM74LC-BXyAvuxS.js} +1 -1
  25. package/dist/assets/{kanban-definition-QRCXZQQD-B66SGjA2.js → kanban-definition-QRCXZQQD-CxBFX9if.js} +1 -1
  26. package/dist/assets/{linear-VMCGabuP.js → linear-Bu0P9vdO.js} +1 -1
  27. package/dist/assets/main-AYmbxFu4.css +10 -0
  28. package/dist/assets/main-CcrxU2Tf.js +1454 -0
  29. package/dist/assets/{mindmap-definition-GWI6TPTV--NljwHD9.js → mindmap-definition-GWI6TPTV-BbXI83yG.js} +1 -1
  30. package/dist/assets/{pieDiagram-YF2LJOPJ-CP4IPp3Q.js → pieDiagram-YF2LJOPJ-DuXspLPW.js} +1 -1
  31. package/dist/assets/{quadrantDiagram-OS5C2QUG-baFc-DtQ.js → quadrantDiagram-OS5C2QUG-DnngSA8p.js} +1 -1
  32. package/dist/assets/{requirementDiagram-MIRIMTAZ-BTWwNcnt.js → requirementDiagram-MIRIMTAZ-ChJE8XYc.js} +1 -1
  33. package/dist/assets/{sankeyDiagram-Y46BX6SQ-CnrACC1i.js → sankeyDiagram-Y46BX6SQ-BlkQKMk0.js} +1 -1
  34. package/dist/assets/{sequenceDiagram-G6AWOVSC-Ct5WkHJl.js → sequenceDiagram-G6AWOVSC-BvYCRnWL.js} +1 -1
  35. package/dist/assets/{stateDiagram-MAYHULR4-DeZHZmIy.js → stateDiagram-MAYHULR4-Cb6BiEq_.js} +1 -1
  36. package/dist/assets/stateDiagram-v2-4JROLMXI-31Hvt1M0.js +1 -0
  37. package/dist/assets/{timeline-definition-U7ZMHBDA-BZfUE50X.js → timeline-definition-U7ZMHBDA-w1-dGiEP.js} +1 -1
  38. package/dist/assets/{xychartDiagram-6QU3TZC5-DV6BFyHM.js → xychartDiagram-6QU3TZC5-B85iIKzT.js} +1 -1
  39. package/dist/index.html +2 -2
  40. package/dist-server/__stubs__/ccusage-codex.js +8 -0
  41. package/dist-server/app.module.js +2 -0
  42. package/dist-server/common/limits/defaults.js +3 -3
  43. package/dist-server/domain/agent/agent.service.js +11 -0
  44. package/dist-server/domain/cli/cli.service.js +3 -3
  45. package/dist-server/domain/cron/cron.service.js +5 -1
  46. package/dist-server/domain/doc/doc.controller.js +22 -0
  47. package/dist-server/domain/doc/doc.service.js +42 -10
  48. package/dist-server/domain/git/git.controller.js +180 -0
  49. package/dist-server/domain/git/git.module.js +2 -0
  50. package/dist-server/domain/git/git.service.js +327 -34
  51. package/dist-server/domain/message/message.service.js +18 -8
  52. package/dist-server/domain/onboarding/onboarding.service.js +1 -1
  53. package/dist-server/domain/onboarding/presets/custom.js +2 -2
  54. package/dist-server/domain/onboarding/presets/dev-team.js +7 -7
  55. package/dist-server/domain/onboarding/presets/marketing-team.js +5 -5
  56. package/dist-server/domain/onboarding/presets/planning-team.js +5 -5
  57. package/dist-server/domain/onboarding/presets/solo.js +3 -3
  58. package/dist-server/domain/settings/settings.module.js +2 -0
  59. package/dist-server/domain/settings/settings.service.js +75 -8
  60. package/dist-server/domain/task/task.service.js +7 -7
  61. package/dist-server/domain/thread/thread.service.js +2 -1
  62. package/dist-server/domain/usage/usage.controller.js +30 -0
  63. package/dist-server/domain/usage/usage.service.js +212 -0
  64. package/dist-server/domain/wi/wi.controller.js +43 -0
  65. package/dist-server/domain/wi/wi.module.js +22 -0
  66. package/dist-server/domain/wi/wi.service.js +110 -0
  67. package/dist-server/domain/wi/wi.types.js +2 -0
  68. package/dist-server/domain/workspace/workspace.service.js +4 -1
  69. package/dist-server/modules/crewx-pool.service.js +194 -53
  70. package/dist-server/repository/task.repository.js +5 -1
  71. package/package.json +16 -14
  72. package/packages/cli/dist/commands/agent.js +1 -1
  73. package/packages/cli/dist/commands/init.d.ts +2 -0
  74. package/packages/cli/dist/commands/init.js +198 -6
  75. package/packages/cli/package.json +3 -2
  76. package/dist/assets/PromptTab-HhD4MQcW.js +0 -37
  77. package/dist/assets/channel-ClmdPiZd.js +0 -1
  78. package/dist/assets/classDiagram-LNE6IOMH-Q0hRWLPF.js +0 -1
  79. package/dist/assets/classDiagram-v2-MQ7JQ4JX-Q0hRWLPF.js +0 -1
  80. package/dist/assets/main-AqROOc4i.css +0 -10
  81. package/dist/assets/main-DWCTap27.js +0 -1289
  82. package/dist/assets/stateDiagram-v2-4JROLMXI-DVsMMyDB.js +0 -1
@@ -27,6 +27,7 @@ const workspace_event_bus_js_1 = require("../domain/events/workspace-event.bus.j
27
27
  * 2. CREWX_CONFIG env var (fallback when no workspace yaml found)
28
28
  *
29
29
  * Same workspace path → same Crewx instance (Map cache).
30
+ * Instances are lazily evicted when crewx.yaml mtime+size changes.
30
31
  * All instances are closed on application shutdown.
31
32
  *
32
33
  * Lifecycle: NestJS calls onApplicationShutdown() automatically.
@@ -36,6 +37,8 @@ let CrewxPoolService = class CrewxPoolService {
36
37
  eventBus;
37
38
  pool = new Map();
38
39
  poolMeta = new Map();
40
+ /** Orphaned metas: evicted while tasks were in-flight. Keyed by unique stamp. */
41
+ orphanedMetas = new Set();
39
42
  constructor(eventBus) {
40
43
  this.eventBus = eventBus;
41
44
  }
@@ -50,6 +53,23 @@ let CrewxPoolService = class CrewxPoolService {
50
53
  }
51
54
  return this.getForPath((0, workspace_context_store_js_1.getWorkspacePath)());
52
55
  }
56
+ /**
57
+ * Resolve the crewx.yaml config path for a workspace WITHOUT creating or
58
+ * caching a Crewx instance. Resolution policy (mirrors getForPath):
59
+ * 1. CREWX_CONFIG env → single shared file (pin)
60
+ * 2. <ws>/crewx.yaml → <ws>/crewx.yml (first existing)
61
+ * 3. CREWX_CONFIG fallback (undefined when neither yaml exists)
62
+ */
63
+ resolveConfigPath(workspacePath) {
64
+ const configPath = process.env.CREWX_CONFIG;
65
+ if (configPath)
66
+ return configPath;
67
+ const candidates = [
68
+ (0, path_1.join)(workspacePath, 'crewx.yaml'),
69
+ (0, path_1.join)(workspacePath, 'crewx.yml'),
70
+ ];
71
+ return candidates.find((p) => (0, fs_1.existsSync)(p)) ?? process.env.CREWX_CONFIG;
72
+ }
53
73
  /**
54
74
  * Return the Crewx instance for an explicit workspace path.
55
75
  * When CREWX_CONFIG is set, all paths resolve to a single shared instance
@@ -60,18 +80,71 @@ let CrewxPoolService = class CrewxPoolService {
60
80
  if (configPath) {
61
81
  return this.getOrCreate('__crewx_config__', configPath);
62
82
  }
63
- const candidates = [
64
- (0, path_1.join)(workspacePath, 'crewx.yaml'),
65
- (0, path_1.join)(workspacePath, 'crewx.yml'),
66
- ];
67
- const yamlPath = candidates.find((p) => (0, fs_1.existsSync)(p))
68
- ?? process.env.CREWX_CONFIG;
69
- return this.getOrCreate(workspacePath, yamlPath);
83
+ return this.getOrCreate(workspacePath, this.resolveConfigPath(workspacePath));
84
+ }
85
+ /**
86
+ * Check whether the cached instance for the given key is stale relative
87
+ * to the config file on disk. Returns false when statSync fails (treat as
88
+ * unchanged) or when no entry exists in the pool.
89
+ *
90
+ * Public so that AGT.LIST can share the staleness judgement without
91
+ * triggering expensive instance creation.
92
+ */
93
+ isStale(key, configPath) {
94
+ if (!configPath)
95
+ return false;
96
+ const meta = this.poolMeta.get(key);
97
+ if (!meta)
98
+ return false;
99
+ const current = this.readFileStat(configPath);
100
+ if (!current)
101
+ return false; // statSync failed → treat as unchanged
102
+ return current.mtimeMs !== meta.fileStat.mtimeMs || current.size !== meta.fileStat.size;
70
103
  }
71
104
  invalidate(workspacePath) {
72
105
  const key = process.env.CREWX_CONFIG ? '__crewx_config__' : workspacePath;
73
106
  this.evict(key);
74
107
  }
108
+ readFileStat(filePath) {
109
+ try {
110
+ const s = (0, fs_1.statSync)(filePath);
111
+ return { mtimeMs: s.mtimeMs, size: s.size };
112
+ }
113
+ catch {
114
+ // File temporarily unavailable (editor rename, atomic write). Treat as unchanged.
115
+ return null;
116
+ }
117
+ }
118
+ /**
119
+ * Lazy evict: remove from pool Map immediately so the next request starts
120
+ * fresh, but defer unsub + close() on the old instance until all in-flight
121
+ * tasks complete (refcount reaches 0).
122
+ *
123
+ * We intentionally keep event listeners alive on the orphaned instance so
124
+ * that task:end can decrement refcount and trigger close when it hits 0.
125
+ */
126
+ lazyEvict(key) {
127
+ const meta = this.poolMeta.get(key);
128
+ const existing = this.pool.get(key);
129
+ // Remove from active maps so next getOrCreate starts fresh.
130
+ this.pool.delete(key);
131
+ this.poolMeta.delete(key);
132
+ if (!existing)
133
+ return;
134
+ if (!meta || meta.refcount <= 0) {
135
+ // No in-flight tasks — unsub and close immediately.
136
+ meta?.unsub();
137
+ existing.then((c) => c.close()).catch(() => { });
138
+ }
139
+ else {
140
+ // In-flight tasks: keep event listeners alive so task:end can fire.
141
+ // Mark meta as orphaned so task:end can find it.
142
+ meta.orphanedInstance = existing;
143
+ this.orphanedMetas.add(meta);
144
+ // checkOrphanedClose is called from task:end handler via orphanedMetas.
145
+ }
146
+ }
147
+ /** Explicit (immediate) evict — used by invalidate() triggered by UI writes. */
75
148
  evict(key) {
76
149
  const meta = this.poolMeta.get(key);
77
150
  if (meta) {
@@ -85,14 +158,54 @@ let CrewxPoolService = class CrewxPoolService {
85
158
  }
86
159
  }
87
160
  getOrCreate(key, configPath) {
161
+ // Check staleness for existing entry — evict lazily if config changed.
162
+ if (this.pool.has(key) && configPath) {
163
+ if (this.isStale(key, configPath)) {
164
+ this.lazyEvict(key);
165
+ }
166
+ }
88
167
  if (!this.pool.has(key)) {
168
+ // Capture mtime BEFORE createServerCrewx to prevent TOCTOU self-perpetuation.
169
+ const capturedStat = configPath
170
+ ? (this.readFileStat(configPath) ?? { mtimeMs: 0, size: 0 })
171
+ : { mtimeMs: 0, size: 0 };
89
172
  const instancePromise = (0, crewx_server_js_1.createServerCrewx)(configPath, this.eventBus);
90
173
  this.pool.set(key, instancePromise);
91
174
  // Wire up SDK event subscriptions after the instance resolves.
92
- instancePromise.then((crewx) => this.wireEvents(key, crewx)).catch(() => { });
175
+ instancePromise
176
+ .then((crewx) => {
177
+ try {
178
+ this.wireEvents(key, crewx, capturedStat);
179
+ }
180
+ catch {
181
+ // wireEvents failed (e.g. crewx.on not available in tests/stubs).
182
+ // Ensure poolMeta is at least set so shutdown cleanup works.
183
+ if (!this.poolMeta.has(key)) {
184
+ this.poolMeta.set(key, {
185
+ unsub: () => { },
186
+ poolKey: key,
187
+ fileStat: capturedStat,
188
+ refcount: 0,
189
+ });
190
+ }
191
+ }
192
+ })
193
+ .catch(() => {
194
+ // If creation failed, remove from pool so a subsequent request retries.
195
+ this.pool.delete(key);
196
+ this.poolMeta.delete(key);
197
+ });
93
198
  }
94
199
  return this.pool.get(key);
95
200
  }
201
+ checkOrphanedClose(meta) {
202
+ if (meta.refcount <= 0 && meta.orphanedInstance) {
203
+ // All in-flight tasks have finished — safe to unsub listeners and close.
204
+ meta.unsub();
205
+ meta.orphanedInstance.then((c) => c.close()).catch(() => { });
206
+ this.orphanedMetas.delete(meta);
207
+ }
208
+ }
96
209
  /**
97
210
  * Subscribe to task:start / task:end / task:output on a newly created Crewx instance and
98
211
  * fan-out task.created / task.updated / task.logged events to WorkspaceEventBus.
@@ -100,9 +213,7 @@ let CrewxPoolService = class CrewxPoolService {
100
213
  * threadId for task.updated is read from task:end metadata (propagated by SDK from task:start).
101
214
  * threadId for task.logged is enriched from threadIdByTask (task:output has no threadId).
102
215
  */
103
- wireEvents(key, crewx) {
104
- if (!this.eventBus)
105
- return;
216
+ wireEvents(key, crewx, capturedStat) {
106
217
  const bus = this.eventBus;
107
218
  const wsId = crewx.workspaceId;
108
219
  // task.logged: taskId → threadId (populated on task:start, cleared on task:end)
@@ -112,25 +223,39 @@ let CrewxPoolService = class CrewxPoolService {
112
223
  const THROTTLE_MS = 200;
113
224
  // Hard cap: evict oldest entry when exceeded (guards against missed task:end on crash)
114
225
  const MAX_TASK_ENTRIES = 500;
226
+ // Create meta object first so event handlers can reference it directly
227
+ // (avoids stale poolMeta.get(key) after a lazy evict replaces the entry).
228
+ const meta = {
229
+ unsub: () => { }, // filled in below after handlers are registered
230
+ poolKey: key,
231
+ fileStat: capturedStat,
232
+ refcount: 0,
233
+ };
115
234
  const unsubStart = crewx.on('task:start', (e) => {
235
+ // Increment refcount directly on the captured meta (not via Map lookup).
236
+ meta.refcount++;
116
237
  threadIdByTask.set(e.traceId, e.threadId ?? '');
117
238
  if (threadIdByTask.size > MAX_TASK_ENTRIES) {
118
239
  const oldest = threadIdByTask.keys().next().value;
119
240
  if (oldest !== undefined)
120
241
  threadIdByTask.delete(oldest);
121
242
  }
122
- bus.emit(wsId, {
123
- type: 'task.created',
124
- data: {
125
- taskId: e.traceId,
126
- threadId: e.threadId ?? '',
127
- agent: e.agentRef,
128
- status: 'running',
129
- updatedAt: e.timestamp.toISOString(),
130
- },
131
- });
243
+ if (bus) {
244
+ bus.emit(wsId, {
245
+ type: 'task.created',
246
+ data: {
247
+ taskId: e.traceId,
248
+ threadId: e.threadId ?? '',
249
+ agent: e.agentRef,
250
+ status: 'running',
251
+ updatedAt: e.timestamp.toISOString(),
252
+ },
253
+ });
254
+ }
132
255
  });
133
256
  const unsubOutput = crewx.on('task:output', (e) => {
257
+ if (!bus)
258
+ return;
134
259
  const taskId = e.traceId;
135
260
  if (throttleByTask.has(taskId))
136
261
  return; // absorb within 200ms window
@@ -145,42 +270,50 @@ let CrewxPoolService = class CrewxPoolService {
145
270
  });
146
271
  const unsubEnd = crewx.on('task:end', (e) => {
147
272
  const taskId = e.traceId;
148
- // flush pending task.logged before emitting task.updated
149
- const timer = throttleByTask.get(taskId);
150
- if (timer !== undefined) {
151
- clearTimeout(timer);
152
- throttleByTask.delete(taskId);
273
+ if (bus) {
274
+ // flush pending task.logged before emitting task.updated
275
+ const timer = throttleByTask.get(taskId);
276
+ if (timer !== undefined) {
277
+ clearTimeout(timer);
278
+ throttleByTask.delete(taskId);
279
+ bus.emit(wsId, {
280
+ type: 'task.logged',
281
+ data: { taskId, threadId: threadIdByTask.get(taskId) ?? '' },
282
+ });
283
+ }
284
+ threadIdByTask.delete(taskId);
285
+ const threadId = e.metadata?.threadId ?? '';
153
286
  bus.emit(wsId, {
154
- type: 'task.logged',
155
- data: { taskId, threadId: threadIdByTask.get(taskId) ?? '' },
287
+ type: 'task.updated',
288
+ data: {
289
+ taskId: e.traceId,
290
+ threadId,
291
+ agent: e.agentRef,
292
+ status: e.error ? 'failed' : 'success',
293
+ ...(e.error ? { error: e.error.message } : {}),
294
+ ...(e.costUsd != null ? { costUsd: e.costUsd } : {}),
295
+ updatedAt: e.timestamp.toISOString(),
296
+ },
156
297
  });
157
298
  }
158
- threadIdByTask.delete(taskId);
159
- const threadId = e.metadata?.threadId ?? '';
160
- bus.emit(wsId, {
161
- type: 'task.updated',
162
- data: {
163
- taskId: e.traceId,
164
- threadId,
165
- agent: e.agentRef,
166
- status: e.error ? 'failed' : 'success',
167
- ...(e.error ? { error: e.error.message } : {}),
168
- ...(e.costUsd != null ? { costUsd: e.costUsd } : {}),
169
- updatedAt: e.timestamp.toISOString(),
170
- },
171
- });
172
- });
173
- this.poolMeta.set(key, {
174
- unsub: () => {
175
- unsubStart();
176
- unsubOutput();
177
- unsubEnd();
178
- for (const t of throttleByTask.values())
179
- clearTimeout(t);
180
- throttleByTask.clear();
181
- threadIdByTask.clear();
182
- },
299
+ // Decrement refcount on the captured meta directly.
300
+ meta.refcount = Math.max(0, meta.refcount - 1);
301
+ // If this meta has been orphaned (lazy evict), trigger deferred close.
302
+ if (meta.orphanedInstance) {
303
+ this.checkOrphanedClose(meta);
304
+ }
183
305
  });
306
+ // Wire unsub into the meta object now that handlers are registered.
307
+ meta.unsub = () => {
308
+ unsubStart();
309
+ unsubOutput();
310
+ unsubEnd();
311
+ for (const t of throttleByTask.values())
312
+ clearTimeout(t);
313
+ throttleByTask.clear();
314
+ threadIdByTask.clear();
315
+ };
316
+ this.poolMeta.set(key, meta);
184
317
  }
185
318
  async onApplicationShutdown() {
186
319
  // Unsubscribe all SDK listeners before closing instances.
@@ -188,6 +321,14 @@ let CrewxPoolService = class CrewxPoolService {
188
321
  meta.unsub();
189
322
  }
190
323
  this.poolMeta.clear();
324
+ // Unsub and close any orphaned instances (deferred close from lazy evict).
325
+ for (const orphan of this.orphanedMetas) {
326
+ orphan.unsub();
327
+ if (orphan.orphanedInstance) {
328
+ orphan.orphanedInstance.then((c) => c.close()).catch(() => { });
329
+ }
330
+ }
331
+ this.orphanedMetas.clear();
191
332
  await Promise.all([...this.pool.values()].map((p) => p.then((c) => c.close()).catch(() => { })));
192
333
  }
193
334
  };
@@ -135,7 +135,7 @@ let TaskRepository = class TaskRepository extends base_sqlite_repository_js_1.Ba
135
135
  provider: 'cli',
136
136
  input_tokens: r.inputTokens,
137
137
  output_tokens: r.outputTokens,
138
- total_tokens: r.inputTokens + r.outputTokens,
138
+ total_tokens: r.totalTokens,
139
139
  total_cost: r.costUsd,
140
140
  task_count: r.totalTasks,
141
141
  active_duration_ms: 0,
@@ -153,6 +153,10 @@ let TaskRepository = class TaskRepository extends base_sqlite_repository_js_1.Ba
153
153
  output_tokens: r.outputTokens,
154
154
  }));
155
155
  }
156
+ /** USG.PROVIDER: Aggregate per-provider usage within a date range. */
157
+ getProviderUsage(from, to, workspace) {
158
+ return this.sdk.getProviderUsage(from, to, workspace);
159
+ }
156
160
  /** Find a task by id with workspace isolation for stop operation. */
157
161
  findTaskForStop(taskId, workspaceId) {
158
162
  const row = this.sdk.findTaskForStop(taskId, workspaceId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "crewx",
3
- "version": "0.8.9-rc.2",
3
+ "version": "0.8.9-rc.21",
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": {
@@ -50,6 +50,8 @@
50
50
  "class-validator": "0.15.1",
51
51
  "cookie-parser": "1.4.7",
52
52
  "date-fns": "^4.3.0",
53
+ "dom-anchor-text-position": "^5.0.0",
54
+ "dom-anchor-text-quote": "^4.0.2",
53
55
  "dotenv": "17.2.3",
54
56
  "elkjs": "^0.11.1",
55
57
  "execa": "8.0.1",
@@ -78,20 +80,20 @@
78
80
  "wink-nlp-utils": "2.1.0",
79
81
  "yargs": "17.7.0",
80
82
  "zod": "3.25.76",
81
- "@crewx/cli": "0.8.9-rc.2",
82
- "@crewx/chromex": "0.1.0",
83
- "@crewx/doc": "0.1.8",
84
- "@crewx/dreaming": "0.1.0",
85
- "@crewx/cron": "0.1.10",
86
- "@crewx/memory": "0.1.23",
87
- "@crewx/knowledge-core": "0.1.17",
88
- "@crewx/shared": "0.0.5",
89
- "@crewx/sdk": "0.8.9-rc.2",
90
- "@crewx/wi": "0.1.10",
91
- "@crewx/search": "0.1.10",
92
- "@crewx/workflow": "0.3.22",
83
+ "@crewx/cli": "0.8.9-rc.21",
84
+ "@crewx/cron": "0.1.10-rc.55",
85
+ "@crewx/chromex": "0.1.0-rc.57",
86
+ "@crewx/dreaming": "0.1.0-rc.39",
87
+ "@crewx/doc": "0.1.9-rc.19",
88
+ "@crewx/knowledge-core": "0.1.17-rc.16",
89
+ "@crewx/sdk": "0.8.9-rc.21",
90
+ "@crewx/memory": "0.1.23-rc.37",
91
+ "@crewx/search": "0.1.10-rc.20",
92
+ "@crewx/shared": "0.0.6-rc.8",
93
+ "@crewx/wbs": "0.1.10-rc.50",
93
94
  "@crewx/skill": "0.1.20",
94
- "@crewx/wbs": "0.1.10"
95
+ "@crewx/workflow": "0.3.22-rc.37",
96
+ "@crewx/wi": "0.1.10-rc.21"
95
97
  },
96
98
  "devDependencies": {
97
99
  "@ccusage/codex": "0.0.1",
@@ -237,7 +237,7 @@ Examples:
237
237
  crewx agent
238
238
  crewx agent ls
239
239
  crewx agent ls --role=PM
240
- crewx agent ls --team="CrewX Core 개발팀"
240
+ crewx agent ls --team="CrewX Core Team"
241
241
  crewx agent ls --provider=claude
242
242
  crewx agent ls --role=PM --provider=claude
243
243
  crewx agent ls --role=PM,general
@@ -13,6 +13,8 @@ export interface InitResult {
13
13
  skippedReason?: 'yaml-exists';
14
14
  workspaceId?: string;
15
15
  slug?: string;
16
+ statusLineConfigured?: boolean;
17
+ statusLineSkipped?: boolean;
16
18
  }
17
19
  /**
18
20
  * Programmatic init — creates crewx.yaml, support dirs, and optionally installs hooks.