aemeathcli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/README.md +607 -0
  2. package/dist/App-P4MYD4QY.js +2719 -0
  3. package/dist/App-P4MYD4QY.js.map +1 -0
  4. package/dist/api-key-fallback-YQQBOQIL.js +11 -0
  5. package/dist/api-key-fallback-YQQBOQIL.js.map +1 -0
  6. package/dist/chunk-4IJD72YB.js +184 -0
  7. package/dist/chunk-4IJD72YB.js.map +1 -0
  8. package/dist/chunk-6PDJ45T4.js +325 -0
  9. package/dist/chunk-6PDJ45T4.js.map +1 -0
  10. package/dist/chunk-CARHU3DO.js +562 -0
  11. package/dist/chunk-CARHU3DO.js.map +1 -0
  12. package/dist/chunk-CGEV3ARR.js +80 -0
  13. package/dist/chunk-CGEV3ARR.js.map +1 -0
  14. package/dist/chunk-CS5X3BWX.js +27 -0
  15. package/dist/chunk-CS5X3BWX.js.map +1 -0
  16. package/dist/chunk-CYQNBB25.js +44 -0
  17. package/dist/chunk-CYQNBB25.js.map +1 -0
  18. package/dist/chunk-DAHGLHNR.js +657 -0
  19. package/dist/chunk-DAHGLHNR.js.map +1 -0
  20. package/dist/chunk-H66O5Z2V.js +305 -0
  21. package/dist/chunk-H66O5Z2V.js.map +1 -0
  22. package/dist/chunk-HCIHOHLX.js +322 -0
  23. package/dist/chunk-HCIHOHLX.js.map +1 -0
  24. package/dist/chunk-HMJRPNPZ.js +1031 -0
  25. package/dist/chunk-HMJRPNPZ.js.map +1 -0
  26. package/dist/chunk-I5PZ4JTS.js +119 -0
  27. package/dist/chunk-I5PZ4JTS.js.map +1 -0
  28. package/dist/chunk-IYW62KKR.js +255 -0
  29. package/dist/chunk-IYW62KKR.js.map +1 -0
  30. package/dist/chunk-JAXXTYID.js +51 -0
  31. package/dist/chunk-JAXXTYID.js.map +1 -0
  32. package/dist/chunk-LSOYPSAT.js +183 -0
  33. package/dist/chunk-LSOYPSAT.js.map +1 -0
  34. package/dist/chunk-MFBHNWGV.js +416 -0
  35. package/dist/chunk-MFBHNWGV.js.map +1 -0
  36. package/dist/chunk-MXZSI3AY.js +311 -0
  37. package/dist/chunk-MXZSI3AY.js.map +1 -0
  38. package/dist/chunk-NBR3GHMT.js +72 -0
  39. package/dist/chunk-NBR3GHMT.js.map +1 -0
  40. package/dist/chunk-O3ZF22SW.js +246 -0
  41. package/dist/chunk-O3ZF22SW.js.map +1 -0
  42. package/dist/chunk-SUSJPZU2.js +181 -0
  43. package/dist/chunk-SUSJPZU2.js.map +1 -0
  44. package/dist/chunk-TEVZS4FA.js +310 -0
  45. package/dist/chunk-TEVZS4FA.js.map +1 -0
  46. package/dist/chunk-UY2SYSEZ.js +211 -0
  47. package/dist/chunk-UY2SYSEZ.js.map +1 -0
  48. package/dist/chunk-WAHVZH7V.js +260 -0
  49. package/dist/chunk-WAHVZH7V.js.map +1 -0
  50. package/dist/chunk-WPP3PEDE.js +234 -0
  51. package/dist/chunk-WPP3PEDE.js.map +1 -0
  52. package/dist/chunk-Y5XVD2CD.js +1610 -0
  53. package/dist/chunk-Y5XVD2CD.js.map +1 -0
  54. package/dist/chunk-YL5XFHR3.js +56 -0
  55. package/dist/chunk-YL5XFHR3.js.map +1 -0
  56. package/dist/chunk-ZGOHARPV.js +122 -0
  57. package/dist/chunk-ZGOHARPV.js.map +1 -0
  58. package/dist/claude-adapter-QMLFMSP3.js +6 -0
  59. package/dist/claude-adapter-QMLFMSP3.js.map +1 -0
  60. package/dist/claude-login-5WELXPKT.js +324 -0
  61. package/dist/claude-login-5WELXPKT.js.map +1 -0
  62. package/dist/cli.d.ts +1 -0
  63. package/dist/cli.js +703 -0
  64. package/dist/cli.js.map +1 -0
  65. package/dist/codex-login-7HHLJHBF.js +164 -0
  66. package/dist/codex-login-7HHLJHBF.js.map +1 -0
  67. package/dist/config-store-W6FBCQAQ.js +6 -0
  68. package/dist/config-store-W6FBCQAQ.js.map +1 -0
  69. package/dist/executor-6RIKIGXK.js +4 -0
  70. package/dist/executor-6RIKIGXK.js.map +1 -0
  71. package/dist/gemini-adapter-6JIHZ7WI.js +6 -0
  72. package/dist/gemini-adapter-6JIHZ7WI.js.map +1 -0
  73. package/dist/gemini-login-ZZLYC3J6.js +346 -0
  74. package/dist/gemini-login-ZZLYC3J6.js.map +1 -0
  75. package/dist/index.d.ts +2210 -0
  76. package/dist/index.js +1419 -0
  77. package/dist/index.js.map +1 -0
  78. package/dist/kimi-adapter-JN4HFFHU.js +6 -0
  79. package/dist/kimi-adapter-JN4HFFHU.js.map +1 -0
  80. package/dist/kimi-login-CZPS63NK.js +149 -0
  81. package/dist/kimi-login-CZPS63NK.js.map +1 -0
  82. package/dist/native-cli-adapters-OLW3XX57.js +6 -0
  83. package/dist/native-cli-adapters-OLW3XX57.js.map +1 -0
  84. package/dist/ollama-adapter-OJQ3FKWK.js +6 -0
  85. package/dist/ollama-adapter-OJQ3FKWK.js.map +1 -0
  86. package/dist/openai-adapter-XU46EN7B.js +6 -0
  87. package/dist/openai-adapter-XU46EN7B.js.map +1 -0
  88. package/dist/registry-4KD24ZC3.js +6 -0
  89. package/dist/registry-4KD24ZC3.js.map +1 -0
  90. package/dist/registry-H7B3AHPQ.js +5 -0
  91. package/dist/registry-H7B3AHPQ.js.map +1 -0
  92. package/dist/server-manager-PTGBHCLS.js +5 -0
  93. package/dist/server-manager-PTGBHCLS.js.map +1 -0
  94. package/dist/session-manager-ECEEACGY.js +12 -0
  95. package/dist/session-manager-ECEEACGY.js.map +1 -0
  96. package/dist/team-manager-HC4XGCFY.js +11 -0
  97. package/dist/team-manager-HC4XGCFY.js.map +1 -0
  98. package/dist/tmux-manager-GPYZ3WQH.js +6 -0
  99. package/dist/tmux-manager-GPYZ3WQH.js.map +1 -0
  100. package/dist/tools-TSMXMHIF.js +6 -0
  101. package/dist/tools-TSMXMHIF.js.map +1 -0
  102. package/package.json +89 -0
@@ -0,0 +1,657 @@
1
+ import { getEventBus } from './chunk-YL5XFHR3.js';
2
+ import { estimateTokenCount, createTokenUsage, formatCost } from './chunk-CGEV3ARR.js';
3
+ import { isCommandBlocked } from './chunk-CS5X3BWX.js';
4
+ import { SUPPORTED_MODELS } from './chunk-HCIHOHLX.js';
5
+ import { ModelNotFoundError } from './chunk-ZGOHARPV.js';
6
+ import { logger } from './chunk-JAXXTYID.js';
7
+
8
+ // src/core/model-router.ts
9
+ var ModelRouter = class {
10
+ config;
11
+ userOverride;
12
+ constructor(config) {
13
+ this.config = config;
14
+ }
15
+ /**
16
+ * Set a temporary user override that takes highest priority.
17
+ */
18
+ setUserOverride(modelId) {
19
+ if (modelId !== void 0) {
20
+ this.validateModel(modelId);
21
+ }
22
+ this.userOverride = modelId;
23
+ }
24
+ /**
25
+ * Resolve the best model for a given role through the priority pipeline.
26
+ */
27
+ resolve(role) {
28
+ if (this.userOverride) {
29
+ const info = this.getModelInfo(this.userOverride);
30
+ return {
31
+ modelId: this.userOverride,
32
+ provider: info.provider,
33
+ source: "user_override",
34
+ role
35
+ };
36
+ }
37
+ if (role) {
38
+ const roleConfig = this.config.roles[role];
39
+ if (roleConfig) {
40
+ if (this.isModelAvailable(roleConfig.primary)) {
41
+ const info = this.getModelInfo(roleConfig.primary);
42
+ return {
43
+ modelId: roleConfig.primary,
44
+ provider: info.provider,
45
+ source: "role_config",
46
+ role
47
+ };
48
+ }
49
+ for (const fallbackModel of roleConfig.fallback) {
50
+ if (this.isModelAvailable(fallbackModel)) {
51
+ const info = this.getModelInfo(fallbackModel);
52
+ logger.info(
53
+ { role, primary: roleConfig.primary, fallback: fallbackModel },
54
+ "Using fallback model for role"
55
+ );
56
+ return {
57
+ modelId: fallbackModel,
58
+ provider: info.provider,
59
+ source: "fallback_chain",
60
+ role
61
+ };
62
+ }
63
+ }
64
+ }
65
+ }
66
+ const defaultModel = this.config.defaultModel;
67
+ if (this.isModelAvailable(defaultModel)) {
68
+ const info = this.getModelInfo(defaultModel);
69
+ return {
70
+ modelId: defaultModel,
71
+ provider: info.provider,
72
+ source: "system_default",
73
+ role
74
+ };
75
+ }
76
+ const anyAvailable = this.getAvailableModels()[0];
77
+ if (anyAvailable) {
78
+ return {
79
+ modelId: anyAvailable.id,
80
+ provider: anyAvailable.provider,
81
+ source: "system_default",
82
+ role
83
+ };
84
+ }
85
+ throw new ModelNotFoundError(defaultModel);
86
+ }
87
+ /**
88
+ * Check if a model is available (provider is enabled and model is known).
89
+ */
90
+ isModelAvailable(modelId) {
91
+ const info = SUPPORTED_MODELS[modelId];
92
+ if (!info) {
93
+ return false;
94
+ }
95
+ return this.config.enabledProviders.includes(info.provider);
96
+ }
97
+ /**
98
+ * Get model info by ID. Throws if not found.
99
+ */
100
+ getModelInfo(modelId) {
101
+ const info = SUPPORTED_MODELS[modelId];
102
+ if (!info) {
103
+ throw new ModelNotFoundError(modelId);
104
+ }
105
+ return info;
106
+ }
107
+ /**
108
+ * Get all available models (from enabled providers).
109
+ */
110
+ getAvailableModels() {
111
+ return Object.values(SUPPORTED_MODELS).filter(
112
+ (model) => this.config.enabledProviders.includes(model.provider)
113
+ );
114
+ }
115
+ /**
116
+ * List models recommended for a specific role.
117
+ */
118
+ getModelsForRole(role) {
119
+ return this.getAvailableModels().filter(
120
+ (model) => model.supportedRoles.includes(role)
121
+ );
122
+ }
123
+ /**
124
+ * Validate that a model ID exists. Throws ModelNotFoundError if not.
125
+ */
126
+ validateModel(modelId) {
127
+ if (!SUPPORTED_MODELS[modelId]) {
128
+ throw new ModelNotFoundError(modelId);
129
+ }
130
+ }
131
+ };
132
+ function createModelRouter(config) {
133
+ const enabledProviders = Object.entries(config.providers).filter(([, providerConfig]) => providerConfig?.enabled).map(([name]) => name);
134
+ return new ModelRouter({
135
+ defaultModel: config.defaultModel,
136
+ roles: config.roles,
137
+ enabledProviders
138
+ });
139
+ }
140
+
141
+ // src/core/context-manager.ts
142
+ var CONTEXT_BUDGET_RATIO = 0.85;
143
+ var SYSTEM_PROMPT_RESERVE = 4e3;
144
+ var ContextManager = class {
145
+ maxTokens;
146
+ budgetTokens;
147
+ fileContext = /* @__PURE__ */ new Map();
148
+ currentTokenCount = 0;
149
+ constructor(modelInfo) {
150
+ this.maxTokens = modelInfo.contextWindow;
151
+ this.budgetTokens = Math.floor(this.maxTokens * CONTEXT_BUDGET_RATIO);
152
+ }
153
+ /**
154
+ * Get the available token budget for new content.
155
+ */
156
+ getAvailableBudget() {
157
+ return Math.max(0, this.budgetTokens - this.currentTokenCount - SYSTEM_PROMPT_RESERVE);
158
+ }
159
+ /**
160
+ * Get total context usage.
161
+ */
162
+ getUsage() {
163
+ return {
164
+ used: this.currentTokenCount,
165
+ budget: this.budgetTokens,
166
+ max: this.maxTokens,
167
+ percentage: Math.round(this.currentTokenCount / this.budgetTokens * 100)
168
+ };
169
+ }
170
+ /**
171
+ * Trim messages to fit within the context window.
172
+ * Preserves system prompt and most recent messages.
173
+ */
174
+ trimMessages(messages, systemPrompt) {
175
+ const systemTokens = systemPrompt ? estimateTokenCount(systemPrompt) : 0;
176
+ const availableTokens = this.budgetTokens - systemTokens - SYSTEM_PROMPT_RESERVE;
177
+ if (availableTokens <= 0) {
178
+ logger.warn("System prompt alone exceeds context budget");
179
+ return [];
180
+ }
181
+ const result = [];
182
+ let usedTokens = 0;
183
+ for (let i = messages.length - 1; i >= 0; i--) {
184
+ const msg = messages[i];
185
+ if (!msg) {
186
+ continue;
187
+ }
188
+ const msgTokens = estimateTokenCount(msg.content);
189
+ if (usedTokens + msgTokens > availableTokens) {
190
+ break;
191
+ }
192
+ result.unshift(msg);
193
+ usedTokens += msgTokens;
194
+ }
195
+ this.currentTokenCount = usedTokens + systemTokens;
196
+ if (result.length < messages.length) {
197
+ logger.info(
198
+ {
199
+ original: messages.length,
200
+ trimmed: result.length,
201
+ droppedMessages: messages.length - result.length
202
+ },
203
+ "Trimmed conversation to fit context window"
204
+ );
205
+ }
206
+ return result;
207
+ }
208
+ /**
209
+ * Track a file being added to context.
210
+ */
211
+ addFileContext(filePath, content) {
212
+ const tokenCount = estimateTokenCount(content);
213
+ this.fileContext.set(filePath, {
214
+ filePath,
215
+ tokenCount,
216
+ lastAccessedAt: Date.now()
217
+ });
218
+ this.currentTokenCount += tokenCount;
219
+ }
220
+ /**
221
+ * Touch a file (update last accessed time).
222
+ */
223
+ touchFile(filePath) {
224
+ const entry = this.fileContext.get(filePath);
225
+ if (entry) {
226
+ entry.lastAccessedAt = Date.now();
227
+ }
228
+ }
229
+ /**
230
+ * Remove a file from context.
231
+ */
232
+ removeFileContext(filePath) {
233
+ const entry = this.fileContext.get(filePath);
234
+ if (entry) {
235
+ this.currentTokenCount -= entry.tokenCount;
236
+ this.fileContext.delete(filePath);
237
+ }
238
+ }
239
+ /**
240
+ * Evict least-recently-used files to free space.
241
+ */
242
+ evictLRU(tokensNeeded) {
243
+ const evicted = [];
244
+ const sorted = [...this.fileContext.entries()].sort(
245
+ ([, a], [, b]) => a.lastAccessedAt - b.lastAccessedAt
246
+ );
247
+ let freedTokens = 0;
248
+ for (const [filePath, entry] of sorted) {
249
+ if (freedTokens >= tokensNeeded) {
250
+ break;
251
+ }
252
+ this.removeFileContext(filePath);
253
+ freedTokens += entry.tokenCount;
254
+ evicted.push(filePath);
255
+ }
256
+ if (evicted.length > 0) {
257
+ logger.info(
258
+ { evicted, freedTokens },
259
+ "Evicted files from context to free space"
260
+ );
261
+ }
262
+ return evicted;
263
+ }
264
+ /**
265
+ * Get all tracked files.
266
+ */
267
+ getTrackedFiles() {
268
+ return [...this.fileContext.values()];
269
+ }
270
+ /**
271
+ * Reset context tracking (for model switch).
272
+ */
273
+ reset() {
274
+ this.fileContext.clear();
275
+ this.currentTokenCount = 0;
276
+ }
277
+ };
278
+
279
+ // src/core/cost-tracker.ts
280
+ var CostTracker = class {
281
+ entries = [];
282
+ budgetConfig;
283
+ warningEmitted = false;
284
+ constructor(budgetConfig) {
285
+ this.budgetConfig = budgetConfig;
286
+ }
287
+ /**
288
+ * Record a cost entry from a model response.
289
+ */
290
+ record(provider, model, inputTokens, outputTokens, role) {
291
+ const usage = createTokenUsage(model, inputTokens, outputTokens);
292
+ const entry = {
293
+ provider,
294
+ model,
295
+ role,
296
+ usage,
297
+ timestamp: /* @__PURE__ */ new Date()
298
+ };
299
+ this.entries.push(entry);
300
+ const total = this.getSessionTotal();
301
+ const eventBus = getEventBus();
302
+ eventBus.emit("cost:updated", {
303
+ total,
304
+ provider,
305
+ delta: usage.costUsd
306
+ });
307
+ if (total >= this.budgetConfig.budgetWarning && !this.warningEmitted) {
308
+ this.warningEmitted = true;
309
+ eventBus.emit("cost:warning", {
310
+ current: total,
311
+ limit: this.budgetConfig.budgetWarning
312
+ });
313
+ logger.warn(
314
+ { current: formatCost(total), warning: formatCost(this.budgetConfig.budgetWarning) },
315
+ "Budget warning threshold reached"
316
+ );
317
+ }
318
+ if (total >= this.budgetConfig.budgetHardStop) {
319
+ eventBus.emit("cost:exceeded", {
320
+ current: total,
321
+ limit: this.budgetConfig.budgetHardStop
322
+ });
323
+ logger.error(
324
+ { current: formatCost(total), limit: formatCost(this.budgetConfig.budgetHardStop) },
325
+ "Budget hard stop reached"
326
+ );
327
+ }
328
+ return usage;
329
+ }
330
+ /**
331
+ * Get total session cost.
332
+ */
333
+ getSessionTotal() {
334
+ return this.entries.reduce((sum, entry) => sum + entry.usage.costUsd, 0);
335
+ }
336
+ /**
337
+ * Get total token counts.
338
+ */
339
+ getSessionTokens() {
340
+ const input = this.entries.reduce((sum, e) => sum + e.usage.inputTokens, 0);
341
+ const output = this.entries.reduce((sum, e) => sum + e.usage.outputTokens, 0);
342
+ return { input, output, total: input + output };
343
+ }
344
+ /**
345
+ * Get cost breakdown by provider, model, and role.
346
+ */
347
+ getBreakdown() {
348
+ const byProvider = {};
349
+ const byModel = {};
350
+ const byRole = {};
351
+ for (const entry of this.entries) {
352
+ byProvider[entry.provider] = (byProvider[entry.provider] ?? 0) + entry.usage.costUsd;
353
+ byModel[entry.model] = (byModel[entry.model] ?? 0) + entry.usage.costUsd;
354
+ if (entry.role) {
355
+ byRole[entry.role] = (byRole[entry.role] ?? 0) + entry.usage.costUsd;
356
+ }
357
+ }
358
+ return { byProvider, byModel, byRole };
359
+ }
360
+ /**
361
+ * Check if budget hard stop has been exceeded.
362
+ */
363
+ isBudgetExceeded() {
364
+ return this.getSessionTotal() >= this.budgetConfig.budgetHardStop;
365
+ }
366
+ /**
367
+ * Get formatted session summary.
368
+ */
369
+ getSummary() {
370
+ const total = this.getSessionTotal();
371
+ const tokens = this.getSessionTokens();
372
+ return `${formatCost(total)} (${tokens.total.toLocaleString()} tokens)`;
373
+ }
374
+ /**
375
+ * Get all cost entries (for export).
376
+ */
377
+ getEntries() {
378
+ return this.entries;
379
+ }
380
+ /**
381
+ * Reset cost tracking for a new session.
382
+ */
383
+ reset() {
384
+ this.entries.length = 0;
385
+ this.warningEmitted = false;
386
+ }
387
+ };
388
+
389
+ // src/core/permission-manager.ts
390
+ var DANGEROUS_COMMANDS = [
391
+ "rm -rf",
392
+ "git push --force",
393
+ "git reset --hard",
394
+ "git checkout .",
395
+ "git clean -f",
396
+ "git branch -D",
397
+ "drop table",
398
+ "drop database",
399
+ "truncate",
400
+ "format c:",
401
+ "del /f /s /q"
402
+ ];
403
+ var PermissionManager = class {
404
+ mode;
405
+ allowedPaths;
406
+ blockedCommands;
407
+ approvedOperations = /* @__PURE__ */ new Set();
408
+ constructor(mode, allowedPaths, blockedCommands) {
409
+ this.mode = mode;
410
+ this.allowedPaths = allowedPaths;
411
+ this.blockedCommands = blockedCommands;
412
+ }
413
+ /**
414
+ * Check if an operation is permitted.
415
+ */
416
+ check(request) {
417
+ if (request.command && this.isDangerousCommand(request.command)) {
418
+ return {
419
+ allowed: false,
420
+ reason: `Dangerous command detected: "${request.command}"`,
421
+ requiresUserApproval: true
422
+ };
423
+ }
424
+ if (request.command && isCommandBlocked(request.command, this.blockedCommands)) {
425
+ return {
426
+ allowed: false,
427
+ reason: `Command is on the blocked list`,
428
+ requiresUserApproval: true
429
+ };
430
+ }
431
+ const opKey = this.getOperationKey(request);
432
+ if (this.approvedOperations.has(opKey)) {
433
+ return { allowed: true, requiresUserApproval: false };
434
+ }
435
+ switch (this.mode) {
436
+ case "permissive":
437
+ return { allowed: true, requiresUserApproval: false };
438
+ case "standard":
439
+ return this.checkStandardMode(request);
440
+ case "strict":
441
+ return this.checkStrictMode(request);
442
+ }
443
+ }
444
+ /**
445
+ * Record that the user has approved an operation.
446
+ */
447
+ approve(request) {
448
+ const opKey = this.getOperationKey(request);
449
+ this.approvedOperations.add(opKey);
450
+ logger.info({ operation: opKey }, "Operation approved by user");
451
+ }
452
+ /**
453
+ * Update permission mode.
454
+ */
455
+ setMode(mode) {
456
+ this.mode = mode;
457
+ this.approvedOperations.clear();
458
+ logger.info({ mode }, "Permission mode changed");
459
+ }
460
+ /**
461
+ * Get current mode.
462
+ */
463
+ getMode() {
464
+ return this.mode;
465
+ }
466
+ checkStandardMode(request) {
467
+ if (this.isReadOperation(request)) {
468
+ return { allowed: true, requiresUserApproval: false };
469
+ }
470
+ return {
471
+ allowed: false,
472
+ reason: `${request.operation} requires approval in standard mode`,
473
+ requiresUserApproval: true
474
+ };
475
+ }
476
+ checkStrictMode(request) {
477
+ return {
478
+ allowed: false,
479
+ reason: `${request.operation} requires approval in strict mode`,
480
+ requiresUserApproval: true
481
+ };
482
+ }
483
+ isReadOperation(request) {
484
+ const readTools = ["read", "glob", "grep", "web-search", "web-fetch"];
485
+ return readTools.includes(request.toolName);
486
+ }
487
+ isDangerousCommand(command) {
488
+ const lower = command.toLowerCase().trim();
489
+ return DANGEROUS_COMMANDS.some((dangerous) => lower.includes(dangerous));
490
+ }
491
+ getOperationKey(request) {
492
+ return `${request.toolName}:${request.operation}:${request.resource ?? ""}`;
493
+ }
494
+ };
495
+
496
+ // src/core/task-orchestrator.ts
497
+ var nextTaskId = 1;
498
+ function generateTaskId() {
499
+ return String(nextTaskId++);
500
+ }
501
+ var TaskOrchestrator = class {
502
+ tasks = /* @__PURE__ */ new Map();
503
+ /**
504
+ * Create a new task.
505
+ */
506
+ createTask(subject, description, options) {
507
+ const id = generateTaskId();
508
+ const now = /* @__PURE__ */ new Date();
509
+ const task = {
510
+ id,
511
+ subject,
512
+ description,
513
+ status: "pending",
514
+ owner: options?.owner,
515
+ model: options?.model,
516
+ role: options?.role,
517
+ blocks: [],
518
+ blockedBy: options?.blockedBy ? [...options.blockedBy] : [],
519
+ createdAt: now,
520
+ updatedAt: now
521
+ };
522
+ this.tasks.set(id, task);
523
+ if (options?.blockedBy) {
524
+ for (const blockerId of options.blockedBy) {
525
+ const blocker = this.tasks.get(blockerId);
526
+ if (blocker && !blocker.blocks.includes(id)) {
527
+ blocker.blocks.push(id);
528
+ }
529
+ }
530
+ }
531
+ getEventBus().emit("task:created", { taskId: id, subject });
532
+ logger.info({ taskId: id, subject }, "Task created");
533
+ return task;
534
+ }
535
+ /**
536
+ * Update task status.
537
+ */
538
+ updateStatus(taskId, status) {
539
+ const task = this.getTask(taskId);
540
+ task.status = status;
541
+ task.updatedAt = /* @__PURE__ */ new Date();
542
+ getEventBus().emit("task:updated", { taskId, status });
543
+ if (status === "completed") {
544
+ getEventBus().emit("task:completed", { taskId });
545
+ this.resolveBlockedTasks(taskId);
546
+ }
547
+ logger.info({ taskId, status }, "Task status updated");
548
+ }
549
+ /**
550
+ * Assign a task to an agent.
551
+ */
552
+ assignTask(taskId, owner, model) {
553
+ const task = this.getTask(taskId);
554
+ task.owner = owner;
555
+ if (model) {
556
+ task.model = model;
557
+ }
558
+ task.updatedAt = /* @__PURE__ */ new Date();
559
+ logger.info({ taskId, owner, model }, "Task assigned");
560
+ }
561
+ /**
562
+ * Get a task by ID. Throws if not found.
563
+ */
564
+ getTask(taskId) {
565
+ const task = this.tasks.get(taskId);
566
+ if (!task) {
567
+ throw new Error(`Task not found: ${taskId}`);
568
+ }
569
+ return task;
570
+ }
571
+ /**
572
+ * Get all tasks.
573
+ */
574
+ getAllTasks() {
575
+ return [...this.tasks.values()];
576
+ }
577
+ /**
578
+ * Get tasks by status.
579
+ */
580
+ getTasksByStatus(status) {
581
+ return [...this.tasks.values()].filter((t) => t.status === status);
582
+ }
583
+ /**
584
+ * Get tasks assigned to an agent.
585
+ */
586
+ getTasksByOwner(owner) {
587
+ return [...this.tasks.values()].filter((t) => t.owner === owner);
588
+ }
589
+ /**
590
+ * Get tasks that are ready to be worked on (pending, not blocked).
591
+ */
592
+ getAvailableTasks() {
593
+ return [...this.tasks.values()].filter(
594
+ (t) => t.status === "pending" && !t.owner && t.blockedBy.every((blockerId) => {
595
+ const blocker = this.tasks.get(blockerId);
596
+ return blocker?.status === "completed";
597
+ })
598
+ );
599
+ }
600
+ /**
601
+ * Check if all tasks are completed.
602
+ */
603
+ isAllComplete() {
604
+ return [...this.tasks.values()].every((t) => t.status === "completed");
605
+ }
606
+ /**
607
+ * Get progress summary.
608
+ */
609
+ getProgress() {
610
+ const tasks = [...this.tasks.values()];
611
+ return {
612
+ total: tasks.length,
613
+ completed: tasks.filter((t) => t.status === "completed").length,
614
+ inProgress: tasks.filter((t) => t.status === "in_progress").length,
615
+ pending: tasks.filter((t) => t.status === "pending").length,
616
+ blocked: tasks.filter((t) => t.status === "blocked").length
617
+ };
618
+ }
619
+ /**
620
+ * Delete a task.
621
+ */
622
+ deleteTask(taskId) {
623
+ const task = this.tasks.get(taskId);
624
+ if (task) {
625
+ for (const [, otherTask] of this.tasks) {
626
+ otherTask.blockedBy = otherTask.blockedBy.filter((id) => id !== taskId);
627
+ otherTask.blocks = otherTask.blocks.filter((id) => id !== taskId);
628
+ }
629
+ this.tasks.delete(taskId);
630
+ }
631
+ }
632
+ /**
633
+ * When a task completes, check if any blocked tasks can now proceed.
634
+ */
635
+ resolveBlockedTasks(completedTaskId) {
636
+ for (const [, task] of this.tasks) {
637
+ if (task.status === "blocked" || task.status === "pending") {
638
+ const allDepsComplete = task.blockedBy.every((depId) => {
639
+ const dep = this.tasks.get(depId);
640
+ return dep?.status === "completed";
641
+ });
642
+ if (allDepsComplete && task.status === "blocked") {
643
+ task.status = "pending";
644
+ task.updatedAt = /* @__PURE__ */ new Date();
645
+ logger.info(
646
+ { taskId: task.id, unblockedBy: completedTaskId },
647
+ "Task unblocked"
648
+ );
649
+ }
650
+ }
651
+ }
652
+ }
653
+ };
654
+
655
+ export { ContextManager, CostTracker, ModelRouter, PermissionManager, TaskOrchestrator, createModelRouter };
656
+ //# sourceMappingURL=chunk-DAHGLHNR.js.map
657
+ //# sourceMappingURL=chunk-DAHGLHNR.js.map