@aman_asmuei/aman-agent 0.40.0 → 0.41.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.
package/dist/index.js CHANGED
@@ -731,17 +731,17 @@ var init_types = __esm({
731
731
  // src/orchestrator/dag.ts
732
732
  function validateDAG(dag) {
733
733
  const nodeIds = /* @__PURE__ */ new Set();
734
- for (const node of dag.nodes) {
735
- if (nodeIds.has(node.id)) {
736
- throw new DAGValidationError(`Duplicate node id: "${node.id}"`);
734
+ for (const node2 of dag.nodes) {
735
+ if (nodeIds.has(node2.id)) {
736
+ throw new DAGValidationError(`Duplicate node id: "${node2.id}"`);
737
737
  }
738
- nodeIds.add(node.id);
738
+ nodeIds.add(node2.id);
739
739
  }
740
- for (const node of dag.nodes) {
741
- for (const dep of node.dependencies) {
740
+ for (const node2 of dag.nodes) {
741
+ for (const dep of node2.dependencies) {
742
742
  if (!nodeIds.has(dep)) {
743
743
  throw new DAGValidationError(
744
- `Node "${node.id}" depends on nonexistent node "${dep}"`
744
+ `Node "${node2.id}" depends on nonexistent node "${dep}"`
745
745
  );
746
746
  }
747
747
  }
@@ -764,14 +764,14 @@ function validateDAG(dag) {
764
764
  }
765
765
  const inDegree = /* @__PURE__ */ new Map();
766
766
  const adj = /* @__PURE__ */ new Map();
767
- for (const node of dag.nodes) {
768
- inDegree.set(node.id, 0);
769
- adj.set(node.id, []);
767
+ for (const node2 of dag.nodes) {
768
+ inDegree.set(node2.id, 0);
769
+ adj.set(node2.id, []);
770
770
  }
771
- for (const node of dag.nodes) {
772
- for (const dep of node.dependencies) {
773
- adj.get(dep).push(node.id);
774
- inDegree.set(node.id, inDegree.get(node.id) + 1);
771
+ for (const node2 of dag.nodes) {
772
+ for (const dep of node2.dependencies) {
773
+ adj.get(dep).push(node2.id);
774
+ inDegree.set(node2.id, inDegree.get(node2.id) + 1);
775
775
  }
776
776
  }
777
777
  const queue = [];
@@ -794,6 +794,32 @@ function validateDAG(dag) {
794
794
  );
795
795
  }
796
796
  }
797
+ function getReadyNodes(dag, taskStatuses, resolvedGates) {
798
+ const gateBlocked = /* @__PURE__ */ new Set();
799
+ for (const gate of dag.gates) {
800
+ if (resolvedGates?.has(gate.id)) continue;
801
+ const allAfterDone = gate.afterNodes.every(
802
+ (id) => taskStatuses.get(id) === "completed"
803
+ );
804
+ if (allAfterDone) {
805
+ for (const id of gate.beforeNodes) {
806
+ gateBlocked.add(id);
807
+ }
808
+ }
809
+ }
810
+ const ready = [];
811
+ for (const node2 of dag.nodes) {
812
+ if (taskStatuses.get(node2.id) !== "pending") continue;
813
+ if (gateBlocked.has(node2.id)) continue;
814
+ const allDepsCompleted = node2.dependencies.every(
815
+ (dep) => taskStatuses.get(dep) === "completed"
816
+ );
817
+ if (allDepsCompleted) {
818
+ ready.push(node2.id);
819
+ }
820
+ }
821
+ return ready;
822
+ }
797
823
  var DAGValidationError;
798
824
  var init_dag = __esm({
799
825
  "src/orchestrator/dag.ts"() {
@@ -3756,6 +3782,9 @@ var ORCHESTRATOR_PROFILES = [
3756
3782
  testerProfile,
3757
3783
  reviewerProfile
3758
3784
  ];
3785
+ function getOrchestratorProfile(name) {
3786
+ return ORCHESTRATOR_PROFILES.find((p5) => p5.name === name);
3787
+ }
3759
3788
 
3760
3789
  // src/profile-templates.ts
3761
3790
  var BUILT_IN_PROFILES = [
@@ -6074,21 +6103,950 @@ async function delegatePipeline(steps, initialInput, client, mcpManager, options
6074
6103
 
6075
6104
  // src/orchestrator/index.ts
6076
6105
  init_types();
6106
+
6107
+ // src/orchestrator/state-machine.ts
6108
+ var ORCHESTRATION_TRANSITIONS = {
6109
+ pending: ["running", "cancelled"],
6110
+ running: ["awaiting_approval", "paused", "completed", "failed", "cancelled"],
6111
+ awaiting_approval: ["approved", "cancelled", "failed"],
6112
+ approved: ["running", "cancelled"],
6113
+ paused: ["running", "cancelled", "failed"],
6114
+ completed: [],
6115
+ failed: [],
6116
+ cancelled: []
6117
+ };
6118
+ var TASK_TRANSITIONS = {
6119
+ pending: ["ready", "skipped", "blocked"],
6120
+ ready: ["running", "skipped", "blocked"],
6121
+ running: ["completed", "failed"],
6122
+ completed: [],
6123
+ failed: ["ready"],
6124
+ skipped: [],
6125
+ blocked: ["ready", "skipped"]
6126
+ };
6127
+ var TERMINAL_ORCHESTRATION = /* @__PURE__ */ new Set([
6128
+ "completed",
6129
+ "failed",
6130
+ "cancelled"
6131
+ ]);
6132
+ var InvalidTransitionError = class extends Error {
6133
+ constructor(from, to, entity = "orchestration") {
6134
+ super(
6135
+ `Invalid ${entity} transition: ${from} \u2192 ${to}`
6136
+ );
6137
+ this.from = from;
6138
+ this.to = to;
6139
+ this.entity = entity;
6140
+ this.name = "InvalidTransitionError";
6141
+ }
6142
+ from;
6143
+ to;
6144
+ entity;
6145
+ };
6146
+ function createOrchestrationState(dag) {
6147
+ const now = Date.now();
6148
+ const taskStatuses = /* @__PURE__ */ new Map();
6149
+ for (const node2 of dag.nodes) {
6150
+ taskStatuses.set(node2.id, "pending");
6151
+ }
6152
+ return {
6153
+ dag,
6154
+ status: "pending",
6155
+ taskStatuses,
6156
+ taskResults: /* @__PURE__ */ new Map(),
6157
+ activeGate: null,
6158
+ startedAt: now,
6159
+ updatedAt: now
6160
+ };
6161
+ }
6162
+ function canTransition(state, to) {
6163
+ return ORCHESTRATION_TRANSITIONS[state.status].includes(to);
6164
+ }
6165
+ function cloneState(state) {
6166
+ return {
6167
+ ...state,
6168
+ taskStatuses: new Map(state.taskStatuses),
6169
+ taskResults: new Map(state.taskResults),
6170
+ updatedAt: Date.now()
6171
+ };
6172
+ }
6173
+ function transition(state, to, error) {
6174
+ if (!canTransition(state, to)) {
6175
+ throw new InvalidTransitionError(state.status, to);
6176
+ }
6177
+ const next = cloneState(state);
6178
+ next.status = to;
6179
+ if (TERMINAL_ORCHESTRATION.has(to)) {
6180
+ next.completedAt = next.updatedAt;
6181
+ }
6182
+ if (error !== void 0) {
6183
+ next.error = error;
6184
+ }
6185
+ return next;
6186
+ }
6187
+ function transitionTask(state, taskId, to) {
6188
+ const current = state.taskStatuses.get(taskId);
6189
+ if (current === void 0) {
6190
+ throw new Error(`Unknown task id: ${taskId}`);
6191
+ }
6192
+ if (!TASK_TRANSITIONS[current].includes(to)) {
6193
+ throw new InvalidTransitionError(current, to, "task");
6194
+ }
6195
+ const next = cloneState(state);
6196
+ next.taskStatuses.set(taskId, to);
6197
+ return next;
6198
+ }
6199
+
6200
+ // src/orchestrator/index.ts
6077
6201
  init_dag();
6202
+
6203
+ // src/orchestrator/model-router.ts
6204
+ function createModelRouter(clients) {
6205
+ return {
6206
+ getClient(tier) {
6207
+ if (tier === "fast") return clients.fast ?? clients.standard;
6208
+ if (tier === "advanced") return clients.advanced ?? clients.standard;
6209
+ return clients.standard;
6210
+ }
6211
+ };
6212
+ }
6213
+
6214
+ // src/orchestrator/audit.ts
6215
+ function createAuditLog(orchestrationId) {
6216
+ return { orchestrationId, events: [] };
6217
+ }
6218
+ function recordAuditEvent(log5, event) {
6219
+ log5.events.push({ ...event, timestamp: Date.now() });
6220
+ }
6221
+
6222
+ // src/orchestrator/index.ts
6078
6223
  init_decompose();
6079
6224
 
6080
6225
  // src/orchestrator/scheduler.ts
6081
6226
  init_dag();
6227
+ async function runScheduler(dag, router, options, callbacks) {
6228
+ const startTime = Date.now();
6229
+ const maxParallel = options?.maxParallelTasks ?? 4;
6230
+ const mcpManager = options?.mcpManager ?? null;
6231
+ validateDAG(dag);
6232
+ let state = createOrchestrationState(dag);
6233
+ const auditLog = createAuditLog(dag.id);
6234
+ state = transition(state, "running");
6235
+ recordAuditEvent(auditLog, {
6236
+ type: "orchestration_started",
6237
+ message: `Orchestration "${dag.name}" started`
6238
+ });
6239
+ const resolvedGates = /* @__PURE__ */ new Set();
6240
+ const running = /* @__PURE__ */ new Map();
6241
+ async function transitionOrch(to, error) {
6242
+ const from = state.status;
6243
+ state = transition(state, to, error);
6244
+ if (callbacks?.onPhaseTransition) {
6245
+ await callbacks.onPhaseTransition(from, to);
6246
+ }
6247
+ }
6248
+ function dispatchTask(nodeId) {
6249
+ const node2 = dag.nodes.find((n) => n.id === nodeId);
6250
+ state = transitionTask(state, nodeId, "ready");
6251
+ state = transitionTask(state, nodeId, "running");
6252
+ const taskPromise = (async () => {
6253
+ if (callbacks?.onTaskStarted) {
6254
+ await callbacks.onTaskStarted(nodeId, node2.name);
6255
+ }
6256
+ recordAuditEvent(auditLog, {
6257
+ type: "task_started",
6258
+ message: `Task "${node2.name}" started`,
6259
+ taskId: nodeId
6260
+ });
6261
+ const startedAt = Date.now();
6262
+ const client = router.getClient(node2.tier);
6263
+ const taskDesc = [node2.name, node2.description, node2.context].filter(Boolean).join(": ");
6264
+ try {
6265
+ const delegationResult = await delegateTask(
6266
+ taskDesc,
6267
+ node2.profile,
6268
+ client,
6269
+ mcpManager,
6270
+ { silent: true }
6271
+ );
6272
+ const completedAt = Date.now();
6273
+ if (delegationResult.success) {
6274
+ const taskResult = {
6275
+ nodeId,
6276
+ status: "completed",
6277
+ output: delegationResult.response,
6278
+ toolsUsed: delegationResult.toolsUsed,
6279
+ turns: delegationResult.turns,
6280
+ startedAt,
6281
+ completedAt,
6282
+ tier: node2.tier
6283
+ };
6284
+ state = transitionTask(state, nodeId, "completed");
6285
+ state.taskResults.set(nodeId, taskResult);
6286
+ recordAuditEvent(auditLog, {
6287
+ type: "task_completed",
6288
+ message: `Task "${node2.name}" completed`,
6289
+ taskId: nodeId
6290
+ });
6291
+ if (callbacks?.onTaskCompleted) {
6292
+ await callbacks.onTaskCompleted(nodeId, node2.name, taskResult);
6293
+ }
6294
+ } else {
6295
+ const taskResult = {
6296
+ nodeId,
6297
+ status: "failed",
6298
+ error: delegationResult.error ?? "Task failed",
6299
+ toolsUsed: delegationResult.toolsUsed,
6300
+ turns: delegationResult.turns,
6301
+ startedAt,
6302
+ completedAt,
6303
+ tier: node2.tier
6304
+ };
6305
+ state = transitionTask(state, nodeId, "failed");
6306
+ state.taskResults.set(nodeId, taskResult);
6307
+ recordAuditEvent(auditLog, {
6308
+ type: "task_failed",
6309
+ message: `Task "${node2.name}" failed: ${delegationResult.error}`,
6310
+ taskId: nodeId
6311
+ });
6312
+ if (callbacks?.onTaskFailed) {
6313
+ await callbacks.onTaskFailed(nodeId, node2.name, delegationResult.error ?? "Task failed");
6314
+ }
6315
+ }
6316
+ } catch (err) {
6317
+ const completedAt = Date.now();
6318
+ const errorMsg = err instanceof Error ? err.message : String(err);
6319
+ const taskResult = {
6320
+ nodeId,
6321
+ status: "failed",
6322
+ error: errorMsg,
6323
+ toolsUsed: [],
6324
+ turns: 0,
6325
+ startedAt,
6326
+ completedAt,
6327
+ tier: node2.tier
6328
+ };
6329
+ state = transitionTask(state, nodeId, "failed");
6330
+ state.taskResults.set(nodeId, taskResult);
6331
+ recordAuditEvent(auditLog, {
6332
+ type: "task_failed",
6333
+ message: `Task "${node2.name}" threw: ${errorMsg}`,
6334
+ taskId: nodeId
6335
+ });
6336
+ if (callbacks?.onTaskFailed) {
6337
+ await callbacks.onTaskFailed(nodeId, node2.name, errorMsg);
6338
+ }
6339
+ }
6340
+ })();
6341
+ running.set(nodeId, taskPromise);
6342
+ taskPromise.then(() => running.delete(nodeId));
6343
+ }
6344
+ try {
6345
+ while (true) {
6346
+ if (["completed", "failed", "cancelled"].includes(state.status)) {
6347
+ break;
6348
+ }
6349
+ const hasFailed = [...state.taskStatuses.values()].some((s) => s === "failed");
6350
+ if (hasFailed) {
6351
+ await transitionOrch("failed", "A task failed");
6352
+ recordAuditEvent(auditLog, {
6353
+ type: "orchestration_failed",
6354
+ message: "Orchestration failed due to task failure"
6355
+ });
6356
+ break;
6357
+ }
6358
+ let gateHandled = false;
6359
+ for (const gate of dag.gates) {
6360
+ if (resolvedGates.has(gate.id)) continue;
6361
+ const allAfterDone = gate.afterNodes.every(
6362
+ (id) => state.taskStatuses.get(id) === "completed"
6363
+ );
6364
+ if (!allAfterDone) continue;
6365
+ gateHandled = true;
6366
+ await transitionOrch("awaiting_approval");
6367
+ recordAuditEvent(auditLog, {
6368
+ type: "approval_requested",
6369
+ message: `Gate "${gate.name}" requires approval`,
6370
+ gateId: gate.id
6371
+ });
6372
+ let approved = false;
6373
+ if (callbacks?.onApprovalRequired) {
6374
+ approved = await callbacks.onApprovalRequired(gate.id, gate.name);
6375
+ }
6376
+ if (approved) {
6377
+ resolvedGates.add(gate.id);
6378
+ await transitionOrch("approved");
6379
+ recordAuditEvent(auditLog, {
6380
+ type: "approval_granted",
6381
+ message: `Gate "${gate.name}" approved`,
6382
+ gateId: gate.id
6383
+ });
6384
+ await transitionOrch("running");
6385
+ recordAuditEvent(auditLog, {
6386
+ type: "gate_resolved",
6387
+ message: `Gate "${gate.name}" resolved, resuming`,
6388
+ gateId: gate.id
6389
+ });
6390
+ } else {
6391
+ await transitionOrch("cancelled");
6392
+ recordAuditEvent(auditLog, {
6393
+ type: "approval_denied",
6394
+ message: `Gate "${gate.name}" denied, cancelling`,
6395
+ gateId: gate.id
6396
+ });
6397
+ break;
6398
+ }
6399
+ }
6400
+ if (["completed", "failed", "cancelled"].includes(state.status)) {
6401
+ break;
6402
+ }
6403
+ const readyNodes = getReadyNodes(dag, state.taskStatuses, resolvedGates);
6404
+ if (readyNodes.length === 0 && running.size === 0) {
6405
+ const allCompleted = [...state.taskStatuses.values()].every(
6406
+ (s) => s === "completed" || s === "skipped"
6407
+ );
6408
+ if (allCompleted) {
6409
+ await transitionOrch("completed");
6410
+ recordAuditEvent(auditLog, {
6411
+ type: "orchestration_completed",
6412
+ message: `Orchestration "${dag.name}" completed successfully`
6413
+ });
6414
+ break;
6415
+ } else {
6416
+ await transitionOrch("failed", "Scheduler stuck: no ready or running tasks");
6417
+ recordAuditEvent(auditLog, {
6418
+ type: "orchestration_failed",
6419
+ message: "Orchestration stuck with no progress possible"
6420
+ });
6421
+ break;
6422
+ }
6423
+ }
6424
+ const availableSlots = maxParallel - running.size;
6425
+ const toDispatch = readyNodes.slice(0, availableSlots);
6426
+ for (const nodeId of toDispatch) {
6427
+ dispatchTask(nodeId);
6428
+ }
6429
+ if (running.size > 0) {
6430
+ await Promise.race(running.values());
6431
+ }
6432
+ }
6433
+ } catch (err) {
6434
+ const errorMsg = err instanceof Error ? err.message : String(err);
6435
+ if (!["completed", "failed", "cancelled"].includes(state.status)) {
6436
+ try {
6437
+ state = transition(state, "failed", errorMsg);
6438
+ } catch {
6439
+ }
6440
+ }
6441
+ recordAuditEvent(auditLog, {
6442
+ type: "orchestration_failed",
6443
+ message: `Orchestration error: ${errorMsg}`
6444
+ });
6445
+ }
6446
+ return {
6447
+ status: state.status,
6448
+ taskResults: state.taskResults,
6449
+ auditLog,
6450
+ error: state.error,
6451
+ durationMs: Date.now() - startTime
6452
+ };
6453
+ }
6454
+
6455
+ // src/orchestrator/review-loop.ts
6456
+ function buildReviewDAG(originalDAG, taskResults) {
6457
+ let context = "Review the following completed work:\n\n";
6458
+ for (const node2 of originalDAG.nodes) {
6459
+ const result = taskResults.get(node2.id);
6460
+ context += `## Task: ${node2.name}
6461
+ `;
6462
+ context += `Profile: ${node2.profile}
6463
+ `;
6464
+ context += `Output: ${result?.output ?? "(no output)"}
6465
+
6466
+ `;
6467
+ }
6468
+ return {
6469
+ id: `review-${originalDAG.id}`,
6470
+ name: `Review: ${originalDAG.name}`,
6471
+ goal: `Review the completed work from "${originalDAG.name}"`,
6472
+ nodes: [
6473
+ {
6474
+ id: "code-review",
6475
+ name: "Code Review",
6476
+ profile: "reviewer",
6477
+ tier: "standard",
6478
+ dependencies: [],
6479
+ context
6480
+ },
6481
+ {
6482
+ id: "test-review",
6483
+ name: "Test Review",
6484
+ profile: "tester",
6485
+ tier: "standard",
6486
+ dependencies: [],
6487
+ context
6488
+ }
6489
+ ],
6490
+ gates: []
6491
+ };
6492
+ }
6493
+ async function runReviewLoop(originalDAG, taskResults, options) {
6494
+ const reviewDAG = buildReviewDAG(originalDAG, taskResults);
6495
+ const schedulerResult = await runScheduler(
6496
+ reviewDAG,
6497
+ options.router,
6498
+ {},
6499
+ options.callbacks
6500
+ );
6501
+ if (schedulerResult.status === "completed") {
6502
+ return {
6503
+ passed: true,
6504
+ iterations: 1,
6505
+ reviewResult: schedulerResult
6506
+ };
6507
+ }
6508
+ return {
6509
+ passed: false,
6510
+ iterations: 1,
6511
+ reason: schedulerResult.error,
6512
+ reviewResult: schedulerResult
6513
+ };
6514
+ }
6515
+
6516
+ // src/orchestrator/circuit-breaker.ts
6517
+ var DEFAULTS = {
6518
+ failureThreshold: 3,
6519
+ resetTimeoutMs: 6e4,
6520
+ halfOpenMaxAttempts: 1
6521
+ };
6522
+ function createCircuitBreaker(name, options) {
6523
+ const opts = { ...DEFAULTS, ...options };
6524
+ let state = "closed";
6525
+ let failures = 0;
6526
+ let lastFailureAt = null;
6527
+ let openedAt = null;
6528
+ let halfOpenAttempts = 0;
6529
+ function checkHalfOpen() {
6530
+ if (state === "open" && openedAt !== null && Date.now() - openedAt >= opts.resetTimeoutMs) {
6531
+ state = "half-open";
6532
+ halfOpenAttempts = 0;
6533
+ }
6534
+ }
6535
+ return {
6536
+ get name() {
6537
+ return name;
6538
+ },
6539
+ get state() {
6540
+ checkHalfOpen();
6541
+ return state;
6542
+ },
6543
+ get failures() {
6544
+ return failures;
6545
+ },
6546
+ get lastFailureAt() {
6547
+ return lastFailureAt;
6548
+ },
6549
+ canExecute() {
6550
+ checkHalfOpen();
6551
+ if (state === "closed") return true;
6552
+ if (state === "open") return false;
6553
+ if (halfOpenAttempts >= opts.halfOpenMaxAttempts) return false;
6554
+ halfOpenAttempts++;
6555
+ return true;
6556
+ },
6557
+ recordSuccess() {
6558
+ if (state === "half-open") {
6559
+ state = "closed";
6560
+ failures = 0;
6561
+ lastFailureAt = null;
6562
+ openedAt = null;
6563
+ halfOpenAttempts = 0;
6564
+ }
6565
+ },
6566
+ recordFailure() {
6567
+ failures++;
6568
+ lastFailureAt = Date.now();
6569
+ if (state === "half-open") {
6570
+ state = "open";
6571
+ openedAt = Date.now();
6572
+ halfOpenAttempts = 0;
6573
+ } else if (failures >= opts.failureThreshold) {
6574
+ state = "open";
6575
+ openedAt = Date.now();
6576
+ }
6577
+ },
6578
+ reset() {
6579
+ state = "closed";
6580
+ failures = 0;
6581
+ lastFailureAt = null;
6582
+ openedAt = null;
6583
+ halfOpenAttempts = 0;
6584
+ }
6585
+ };
6586
+ }
6587
+ function createCircuitBreakerRegistry(options) {
6588
+ const breakers = /* @__PURE__ */ new Map();
6589
+ return {
6590
+ get(name) {
6591
+ let cb = breakers.get(name);
6592
+ if (!cb) {
6593
+ cb = createCircuitBreaker(name, options);
6594
+ breakers.set(name, cb);
6595
+ }
6596
+ return cb;
6597
+ },
6598
+ getAll() {
6599
+ return [...breakers.values()];
6600
+ },
6601
+ resetAll() {
6602
+ for (const cb of breakers.values()) {
6603
+ cb.reset();
6604
+ }
6605
+ },
6606
+ formatStatus() {
6607
+ if (breakers.size === 0) {
6608
+ return "No circuit breakers registered.";
6609
+ }
6610
+ const lines = [...breakers.values()].map(
6611
+ (cb) => ` ${cb.name}: state=${cb.state} failures=${cb.failures}`
6612
+ );
6613
+ return `Circuit breakers (${breakers.size}):
6614
+ ${lines.join("\n")}`;
6615
+ }
6616
+ };
6617
+ }
6082
6618
 
6083
6619
  // src/orchestrator/checkpoint.ts
6084
6620
  import { readFile as readFile2, writeFile, mkdir } from "fs/promises";
6085
6621
  import { join } from "path";
6086
6622
 
6623
+ // src/orchestrator/cost-tracker.ts
6624
+ var DEFAULT_TIER_COSTS = {
6625
+ fast: {
6626
+ inputTokensPerDollar: 5e6,
6627
+ outputTokensPerDollar: 125e4
6628
+ },
6629
+ // ~$0.20/$0.80 per 1M
6630
+ standard: {
6631
+ inputTokensPerDollar: 333333,
6632
+ outputTokensPerDollar: 66667
6633
+ },
6634
+ // ~$3/$15 per 1M
6635
+ advanced: {
6636
+ inputTokensPerDollar: 66667,
6637
+ outputTokensPerDollar: 13333
6638
+ }
6639
+ // ~$15/$75 per 1M
6640
+ };
6641
+ function createCostTracker(options) {
6642
+ const budgetLimit = options?.budgetLimit ?? null;
6643
+ const tierCosts = {
6644
+ ...DEFAULT_TIER_COSTS,
6645
+ ...options?.tierCosts
6646
+ };
6647
+ const _entries = [];
6648
+ function estimateCost(tier, inputTokens, outputTokens) {
6649
+ const rates = tierCosts[tier];
6650
+ return inputTokens / rates.inputTokensPerDollar + outputTokens / rates.outputTokensPerDollar;
6651
+ }
6652
+ function record(taskId, tier, inputTokens, outputTokens) {
6653
+ _entries.push({
6654
+ tier,
6655
+ taskId,
6656
+ inputTokens,
6657
+ outputTokens,
6658
+ estimatedCost: estimateCost(tier, inputTokens, outputTokens),
6659
+ timestamp: Date.now()
6660
+ });
6661
+ }
6662
+ function totalCost() {
6663
+ return _entries.reduce((sum, e) => sum + e.estimatedCost, 0);
6664
+ }
6665
+ function costByTier() {
6666
+ const result = {
6667
+ fast: 0,
6668
+ standard: 0,
6669
+ advanced: 0
6670
+ };
6671
+ for (const entry of _entries) {
6672
+ result[entry.tier] += entry.estimatedCost;
6673
+ }
6674
+ return result;
6675
+ }
6676
+ function entries() {
6677
+ return [..._entries];
6678
+ }
6679
+ function isOverBudget() {
6680
+ if (budgetLimit === null) return false;
6681
+ return totalCost() > budgetLimit;
6682
+ }
6683
+ function remainingBudget() {
6684
+ if (budgetLimit === null) return null;
6685
+ return budgetLimit - totalCost();
6686
+ }
6687
+ function formatSummary() {
6688
+ const total = totalCost();
6689
+ const byTier = costByTier();
6690
+ const lines = [];
6691
+ lines.push(`Total: $${total.toFixed(4)}`);
6692
+ for (const tier of ["fast", "standard", "advanced"]) {
6693
+ if (byTier[tier] > 0) {
6694
+ lines.push(` ${tier}: $${byTier[tier].toFixed(4)}`);
6695
+ }
6696
+ }
6697
+ if (budgetLimit !== null) {
6698
+ const remaining = remainingBudget();
6699
+ lines.push(
6700
+ `Budget: $${budgetLimit.toFixed(2)} | Remaining: $${remaining.toFixed(4)}`
6701
+ );
6702
+ }
6703
+ lines.push(`Entries: ${_entries.length}`);
6704
+ return lines.join("\n");
6705
+ }
6706
+ return {
6707
+ record,
6708
+ totalCost,
6709
+ costByTier,
6710
+ entries,
6711
+ isOverBudget,
6712
+ remainingBudget,
6713
+ formatSummary
6714
+ };
6715
+ }
6716
+
6717
+ // src/orchestrator/policy.ts
6718
+ var maxTaskCount = {
6719
+ name: "max-task-count",
6720
+ description: "DAG has more than 20 tasks",
6721
+ severity: "warning",
6722
+ check: (dag) => {
6723
+ if (dag.nodes.length > 20) {
6724
+ return [
6725
+ {
6726
+ rule: "max-task-count",
6727
+ severity: "warning",
6728
+ message: `DAG has ${dag.nodes.length} tasks (limit: 20)`
6729
+ }
6730
+ ];
6731
+ }
6732
+ return [];
6733
+ }
6734
+ };
6735
+ var requiresReview = {
6736
+ name: "requires-review",
6737
+ description: 'No node with profile "reviewer" exists',
6738
+ severity: "warning",
6739
+ check: (dag) => {
6740
+ const hasReviewer = dag.nodes.some((n) => n.profile === "reviewer");
6741
+ if (!hasReviewer) {
6742
+ return [
6743
+ {
6744
+ rule: "requires-review",
6745
+ severity: "warning",
6746
+ message: "DAG has no reviewer node \u2014 consider adding a code review step"
6747
+ }
6748
+ ];
6749
+ }
6750
+ return [];
6751
+ }
6752
+ };
6753
+ var requiresTesting = {
6754
+ name: "requires-testing",
6755
+ description: 'No node with profile "tester" exists',
6756
+ severity: "warning",
6757
+ check: (dag) => {
6758
+ const hasTester = dag.nodes.some((n) => n.profile === "tester");
6759
+ if (!hasTester) {
6760
+ return [
6761
+ {
6762
+ rule: "requires-testing",
6763
+ severity: "warning",
6764
+ message: "DAG has no tester node \u2014 consider adding a testing step"
6765
+ }
6766
+ ];
6767
+ }
6768
+ return [];
6769
+ }
6770
+ };
6771
+ var noOrphanNodes = {
6772
+ name: "no-orphan-nodes",
6773
+ description: "Every node is either a root or has valid dependencies",
6774
+ severity: "error",
6775
+ check: (dag) => {
6776
+ const nodeIds = new Set(dag.nodes.map((n) => n.id));
6777
+ const violations = [];
6778
+ for (const node2 of dag.nodes) {
6779
+ for (const dep of node2.dependencies) {
6780
+ if (!nodeIds.has(dep)) {
6781
+ violations.push({
6782
+ rule: "no-orphan-nodes",
6783
+ severity: "error",
6784
+ message: `Node "${node2.id}" depends on "${dep}" which does not exist`,
6785
+ nodeId: node2.id
6786
+ });
6787
+ }
6788
+ }
6789
+ }
6790
+ return violations;
6791
+ }
6792
+ };
6793
+ var approvalBeforeDeploy = {
6794
+ name: "approval-before-deploy",
6795
+ description: "If any node name contains 'deploy' or 'release', an approval gate should exist",
6796
+ severity: "warning",
6797
+ check: (dag) => {
6798
+ const deployNodes = dag.nodes.filter((n) => {
6799
+ const lower = n.name.toLowerCase();
6800
+ return lower.includes("deploy") || lower.includes("release");
6801
+ });
6802
+ if (deployNodes.length === 0) return [];
6803
+ const hasApprovalGate = dag.gates.some((g) => g.type === "approval");
6804
+ if (hasApprovalGate) return [];
6805
+ return deployNodes.map((n) => ({
6806
+ rule: "approval-before-deploy",
6807
+ severity: "warning",
6808
+ message: `Node "${n.name}" looks like a deploy/release step but no approval gate exists`,
6809
+ nodeId: n.id
6810
+ }));
6811
+ }
6812
+ };
6813
+ var noAdvancedWithoutJustification = {
6814
+ name: "no-advanced-without-justification",
6815
+ description: 'Nodes with tier "advanced" flagged for cost awareness',
6816
+ severity: "info",
6817
+ check: (dag) => dag.nodes.filter((n) => n.tier === "advanced").map((n) => ({
6818
+ rule: "no-advanced-without-justification",
6819
+ severity: "info",
6820
+ message: `Node "${n.id}" uses advanced tier \u2014 ensure this is justified for cost`,
6821
+ nodeId: n.id
6822
+ }))
6823
+ };
6824
+ var maxParallelDepth = {
6825
+ name: "max-parallel-depth",
6826
+ description: "DAG has more than 5 levels of depth",
6827
+ severity: "warning",
6828
+ check: (dag) => {
6829
+ const nodeIds = new Set(dag.nodes.map((n) => n.id));
6830
+ const depthMap = /* @__PURE__ */ new Map();
6831
+ function getDepth(node2, visited) {
6832
+ if (depthMap.has(node2.id)) return depthMap.get(node2.id);
6833
+ if (visited.has(node2.id)) return 0;
6834
+ visited.add(node2.id);
6835
+ let maxDep = 0;
6836
+ for (const depId of node2.dependencies) {
6837
+ const depNode = dag.nodes.find((n) => n.id === depId);
6838
+ if (depNode) {
6839
+ maxDep = Math.max(maxDep, getDepth(depNode, visited) + 1);
6840
+ }
6841
+ }
6842
+ depthMap.set(node2.id, maxDep);
6843
+ return maxDep;
6844
+ }
6845
+ for (const node2 of dag.nodes) {
6846
+ getDepth(node2, /* @__PURE__ */ new Set());
6847
+ }
6848
+ const maxDepth = Math.max(0, ...depthMap.values());
6849
+ if (maxDepth > 5) {
6850
+ return [
6851
+ {
6852
+ rule: "max-parallel-depth",
6853
+ severity: "warning",
6854
+ message: `DAG depth is ${maxDepth} (limit: 5)`
6855
+ }
6856
+ ];
6857
+ }
6858
+ return [];
6859
+ }
6860
+ };
6861
+ function getDefaultPolicies() {
6862
+ return [
6863
+ maxTaskCount,
6864
+ requiresReview,
6865
+ requiresTesting,
6866
+ noOrphanNodes,
6867
+ approvalBeforeDeploy,
6868
+ noAdvancedWithoutJustification,
6869
+ maxParallelDepth
6870
+ ];
6871
+ }
6872
+ function evaluatePolicy(dag, rules) {
6873
+ const effectiveRules = rules ?? getDefaultPolicies();
6874
+ const violations = [];
6875
+ for (const rule of effectiveRules) {
6876
+ violations.push(...rule.check(dag));
6877
+ }
6878
+ const hasErrors = violations.some((v) => v.severity === "error");
6879
+ return {
6880
+ passed: !hasErrors,
6881
+ violations
6882
+ };
6883
+ }
6884
+
6885
+ // src/orchestrator/runner.ts
6886
+ async function runOrchestrationFull(dag, options) {
6887
+ const startTime = Date.now();
6888
+ let policyResult;
6889
+ if (options.enablePolicyCheck) {
6890
+ policyResult = evaluatePolicy(dag);
6891
+ if (!policyResult.passed) {
6892
+ const errorMessages = policyResult.violations.filter((v) => v.severity === "error").map((v) => v.message).join("; ");
6893
+ return {
6894
+ scheduler: {
6895
+ status: "failed",
6896
+ taskResults: /* @__PURE__ */ new Map(),
6897
+ auditLog: createAuditLog(dag.id),
6898
+ error: `Policy check failed: ${errorMessages}`,
6899
+ durationMs: Date.now() - startTime
6900
+ },
6901
+ policy: policyResult,
6902
+ success: false,
6903
+ durationMs: Date.now() - startTime
6904
+ };
6905
+ }
6906
+ }
6907
+ const circuitBreakers = options.enableCircuitBreaker ? createCircuitBreakerRegistry() : void 0;
6908
+ const costTracker = options.enableCostTracking ? createCostTracker({ budgetLimit: options.budgetLimit }) : void 0;
6909
+ const wrappedCallbacks = {
6910
+ ...options.callbacks,
6911
+ onTaskStarted: async (nodeId, nodeName) => {
6912
+ const node2 = dag.nodes.find((n) => n.id === nodeId);
6913
+ if (circuitBreakers && node2) {
6914
+ circuitBreakers.get(node2.profile).canExecute();
6915
+ }
6916
+ await options.callbacks?.onTaskStarted?.(nodeId, nodeName);
6917
+ },
6918
+ onTaskCompleted: async (nodeId, nodeName, result) => {
6919
+ const node2 = dag.nodes.find((n) => n.id === nodeId);
6920
+ if (node2) {
6921
+ circuitBreakers?.get(node2.profile).recordSuccess();
6922
+ costTracker?.record(nodeId, node2.tier, result.turns * 500, result.turns * 200);
6923
+ }
6924
+ await options.callbacks?.onTaskCompleted?.(nodeId, nodeName, result);
6925
+ },
6926
+ onTaskFailed: async (nodeId, nodeName, error) => {
6927
+ const node2 = dag.nodes.find((n) => n.id === nodeId);
6928
+ if (node2) {
6929
+ circuitBreakers?.get(node2.profile).recordFailure();
6930
+ }
6931
+ await options.callbacks?.onTaskFailed?.(nodeId, nodeName, error);
6932
+ }
6933
+ };
6934
+ const schedulerResult = await runScheduler(dag, options.router, {
6935
+ maxParallelTasks: options.maxParallelTasks
6936
+ }, wrappedCallbacks);
6937
+ let reviewResult;
6938
+ if (options.enableSelfReview && schedulerResult.status === "completed") {
6939
+ reviewResult = await runReviewLoop(dag, schedulerResult.taskResults, {
6940
+ router: options.router
6941
+ });
6942
+ }
6943
+ const success = schedulerResult.status === "completed" && (reviewResult ? reviewResult.passed : true) && (costTracker ? !costTracker.isOverBudget() : true);
6944
+ return {
6945
+ scheduler: schedulerResult,
6946
+ policy: policyResult,
6947
+ review: reviewResult,
6948
+ costSummary: costTracker?.formatSummary(),
6949
+ circuitBreakerStatus: circuitBreakers?.formatStatus(),
6950
+ success,
6951
+ durationMs: Date.now() - startTime
6952
+ };
6953
+ }
6954
+
6087
6955
  // src/orchestrator/smart-orchestrate.ts
6088
6956
  init_decompose();
6089
6957
 
6090
6958
  // src/orchestrator/templates/index.ts
6091
6959
  init_dag();
6960
+ function node(id, profile, tier, deps = []) {
6961
+ return {
6962
+ id,
6963
+ name: id.charAt(0).toUpperCase() + id.slice(1),
6964
+ profile,
6965
+ tier,
6966
+ dependencies: deps
6967
+ };
6968
+ }
6969
+ function approvalGate(id, afterNodes, beforeNodes) {
6970
+ return {
6971
+ id,
6972
+ name: `Approval: ${id}`,
6973
+ type: "approval",
6974
+ afterNodes,
6975
+ beforeNodes
6976
+ };
6977
+ }
6978
+ function fullFeatureTemplate(options) {
6979
+ const gates = [];
6980
+ if (options.requireApproval) {
6981
+ gates.push(approvalGate("approval", ["review", "test"], ["finalize"]));
6982
+ }
6983
+ const dag = {
6984
+ id: `full-feature-${options.name}`,
6985
+ name: `Full Feature: ${options.name}`,
6986
+ goal: options.goal,
6987
+ nodes: [
6988
+ node("design", "architect", "advanced"),
6989
+ node("implement", "coder", "standard", ["design"]),
6990
+ node("review", "reviewer", "standard", ["implement"]),
6991
+ node("test", "tester", "standard", ["implement"]),
6992
+ node("finalize", "coder", "standard", ["review", "test"])
6993
+ ],
6994
+ gates
6995
+ };
6996
+ validateDAG(dag);
6997
+ return dag;
6998
+ }
6999
+ function bugFixTemplate(options) {
7000
+ const nodes = [
7001
+ node("reproduce", "tester", "standard"),
7002
+ node("fix", "coder", "standard", ["reproduce"]),
7003
+ node("test", "tester", "standard", ["fix"]),
7004
+ node("review", "reviewer", "standard", ["test"])
7005
+ ];
7006
+ const gates = [];
7007
+ if (options.requireApproval) {
7008
+ nodes.push(node("verify", "tester", "standard", ["review"]));
7009
+ gates.push(approvalGate("approval", ["review"], ["verify"]));
7010
+ }
7011
+ const dag = {
7012
+ id: `bug-fix-${options.name}`,
7013
+ name: `Bug Fix: ${options.name}`,
7014
+ goal: options.goal,
7015
+ nodes,
7016
+ gates
7017
+ };
7018
+ validateDAG(dag);
7019
+ return dag;
7020
+ }
7021
+ function securityAuditTemplate(options) {
7022
+ const gates = [];
7023
+ if (options.requireApproval) {
7024
+ gates.push(approvalGate("approval", ["triage"], ["fix"]));
7025
+ }
7026
+ const dag = {
7027
+ id: `security-audit-${options.name}`,
7028
+ name: `Security Audit: ${options.name}`,
7029
+ goal: options.goal,
7030
+ nodes: [
7031
+ node("scan", "security", "standard"),
7032
+ node("triage", "security", "standard", ["scan"]),
7033
+ node("fix", "coder", "standard", ["triage"]),
7034
+ node("rescan", "security", "standard", ["fix"]),
7035
+ node("review", "reviewer", "standard", ["rescan"])
7036
+ ],
7037
+ gates
7038
+ };
7039
+ validateDAG(dag);
7040
+ return dag;
7041
+ }
7042
+ var TEMPLATES = {
7043
+ "full-feature": fullFeatureTemplate,
7044
+ "bug-fix": bugFixTemplate,
7045
+ "security-audit": securityAuditTemplate
7046
+ };
7047
+ function getTemplate(name) {
7048
+ return TEMPLATES[name];
7049
+ }
6092
7050
 
6093
7051
  // src/project/detector.ts
6094
7052
  var FRONTEND_FRAMEWORKS = /* @__PURE__ */ new Set(["react", "vue", "svelte"]);
@@ -6106,11 +7064,92 @@ var BACKEND_FRAMEWORKS = /* @__PURE__ */ new Set([
6106
7064
  "django",
6107
7065
  "flask"
6108
7066
  ]);
7067
+ var ML_FRAMEWORKS = /* @__PURE__ */ new Set(["torch", "tensorflow", "sklearn", "pytorch", "pandas", "numpy"]);
6109
7068
  var WEB_FRAMEWORKS = /* @__PURE__ */ new Set([
6110
7069
  ...FRONTEND_FRAMEWORKS,
6111
7070
  ...FULLSTACK_FRAMEWORKS,
6112
7071
  ...BACKEND_FRAMEWORKS
6113
7072
  ]);
7073
+ var TEMPLATE_MAP = {
7074
+ "web-frontend": "full-feature",
7075
+ "web-fullstack": "full-feature",
7076
+ "api-backend": "full-feature",
7077
+ mobile: "full-feature",
7078
+ "cli-tool": "bug-fix",
7079
+ library: "full-feature",
7080
+ "ml-data": "full-feature",
7081
+ monorepo: "full-feature",
7082
+ unknown: "full-feature"
7083
+ };
7084
+ var PROFILE_MAP = {
7085
+ "web-frontend": ["architect", "coder", "tester", "reviewer"],
7086
+ "web-fullstack": ["architect", "coder", "security", "tester", "reviewer"],
7087
+ "api-backend": ["architect", "coder", "security", "tester", "reviewer"],
7088
+ mobile: ["architect", "coder", "tester", "reviewer"],
7089
+ "cli-tool": ["coder", "tester", "reviewer"],
7090
+ library: ["architect", "coder", "tester", "reviewer"],
7091
+ "ml-data": ["architect", "coder", "tester"],
7092
+ monorepo: ["architect", "coder", "security", "tester", "reviewer"],
7093
+ unknown: ["coder", "tester", "reviewer"]
7094
+ };
7095
+ var DESCRIPTION_MAP = {
7096
+ "web-frontend": "Frontend web application",
7097
+ "web-fullstack": "Full-stack web application with database",
7098
+ "api-backend": "API/backend service",
7099
+ mobile: "Mobile application",
7100
+ "cli-tool": "Command-line tool",
7101
+ library: "Reusable library/package",
7102
+ "ml-data": "Machine learning / data science project",
7103
+ monorepo: "Monorepo with multiple packages",
7104
+ unknown: "Unknown project type"
7105
+ };
7106
+ function hasAny(items, set) {
7107
+ return items.some((i) => set.has(i));
7108
+ }
7109
+ function classifyProject(stack) {
7110
+ let type;
7111
+ let confidence;
7112
+ if (stack.isMonorepo) {
7113
+ type = "monorepo";
7114
+ confidence = 0.9;
7115
+ } else if (hasAny(stack.frameworks, /* @__PURE__ */ new Set(["flutter"])) || stack.languages.includes("dart")) {
7116
+ type = "mobile";
7117
+ confidence = 0.9;
7118
+ } else if (hasAny(stack.frameworks, FULLSTACK_FRAMEWORKS) && stack.databases.length > 0) {
7119
+ type = "web-fullstack";
7120
+ confidence = 0.9;
7121
+ } else if (hasAny(stack.frameworks, BACKEND_FRAMEWORKS)) {
7122
+ type = "api-backend";
7123
+ confidence = 0.9;
7124
+ } else if (hasAny(stack.frameworks, FRONTEND_FRAMEWORKS)) {
7125
+ type = "web-frontend";
7126
+ confidence = 0.85;
7127
+ } else if (stack.languages.includes("python") && !hasAny(stack.frameworks, WEB_FRAMEWORKS)) {
7128
+ if (hasAny(stack.frameworks, ML_FRAMEWORKS)) {
7129
+ type = "ml-data";
7130
+ confidence = 0.8;
7131
+ } else {
7132
+ type = "cli-tool";
7133
+ confidence = 0.6;
7134
+ }
7135
+ } else if (stack.languages.length > 0 && stack.frameworks.length === 0) {
7136
+ type = "library";
7137
+ confidence = 0.6;
7138
+ } else if (stack.languages.length === 0 && stack.frameworks.length === 0) {
7139
+ type = "unknown";
7140
+ confidence = 0.3;
7141
+ } else {
7142
+ type = "unknown";
7143
+ confidence = 0.3;
7144
+ }
7145
+ return {
7146
+ type,
7147
+ confidence,
7148
+ suggestedTemplate: TEMPLATE_MAP[type],
7149
+ suggestedProfiles: PROFILE_MAP[type],
7150
+ description: DESCRIPTION_MAP[type]
7151
+ };
7152
+ }
6114
7153
 
6115
7154
  // src/orchestrator/smart-orchestrate.ts
6116
7155
  init_stack_detector();
@@ -6119,24 +7158,130 @@ init_stack_detector();
6119
7158
  import fs18 from "fs";
6120
7159
  import path18 from "path";
6121
7160
  import os15 from "os";
7161
+ function isProfileInstalled(profileName, profilesDir) {
7162
+ return fs18.existsSync(path18.join(profilesDir, profileName, "core.md"));
7163
+ }
7164
+ function installProfile(profileName, profilesDir) {
7165
+ const profile = getOrchestratorProfile(profileName);
7166
+ if (!profile) return false;
7167
+ const profileDir = path18.join(profilesDir, profileName);
7168
+ fs18.mkdirSync(profileDir, { recursive: true });
7169
+ fs18.writeFileSync(path18.join(profileDir, "core.md"), profile.core, "utf-8");
7170
+ if (profile.rules) {
7171
+ fs18.writeFileSync(path18.join(profileDir, "rules.md"), profile.rules, "utf-8");
7172
+ }
7173
+ return true;
7174
+ }
7175
+ function ensureAllProfilesInstalled(profilesDir) {
7176
+ const installed = [];
7177
+ const skipped = [];
7178
+ for (const profile of ORCHESTRATOR_PROFILES) {
7179
+ if (isProfileInstalled(profile.name, profilesDir)) {
7180
+ skipped.push(profile.name);
7181
+ } else {
7182
+ installProfile(profile.name, profilesDir);
7183
+ installed.push(profile.name);
7184
+ }
7185
+ }
7186
+ return { installed, skipped };
7187
+ }
7188
+ function getProfilesDir() {
7189
+ const acoreHome = process.env.ACORE_HOME;
7190
+ if (acoreHome) {
7191
+ return path18.join(acoreHome, "profiles");
7192
+ }
7193
+ return path18.join(os15.homedir(), ".acore", "profiles");
7194
+ }
6122
7195
 
6123
- // src/orchestrator/index.ts
6124
- init_dag();
7196
+ // src/orchestrator/smart-orchestrate.ts
6125
7197
  function formatDAGForDisplay(dag) {
6126
7198
  const lines = [];
6127
7199
  lines.push(`## ${dag.name}`);
6128
7200
  lines.push(`**Goal:** ${dag.goal}`);
6129
7201
  lines.push(`**Tasks:** ${dag.nodes.length} | **Gates:** ${dag.gates.length}`);
6130
7202
  lines.push("");
6131
- for (const node of dag.nodes) {
6132
- const depLabel = node.dependencies.length === 0 ? "(root)" : `(after: ${node.dependencies.join(", ")})`;
6133
- lines.push(`- **${node.name}** \u2192 ${node.profile} [${node.tier}] ${depLabel}`);
7203
+ for (const node2 of dag.nodes) {
7204
+ const depLabel = node2.dependencies.length === 0 ? "(root)" : `(after: ${node2.dependencies.join(", ")})`;
7205
+ lines.push(`- **${node2.name}** \u2192 ${node2.profile} [${node2.tier}] ${depLabel}`);
6134
7206
  }
6135
7207
  for (const gate of dag.gates) {
6136
7208
  lines.push(`- \u{1F512} **${gate.name}** [${gate.type}]`);
6137
7209
  }
6138
7210
  return lines.join("\n");
6139
7211
  }
7212
+ async function smartOrchestrate(options) {
7213
+ ensureAllProfilesInstalled(getProfilesDir());
7214
+ let projectType;
7215
+ let templateName = options.templateName;
7216
+ if (options.projectPath && !templateName) {
7217
+ const stack = scanStack(options.projectPath);
7218
+ const classification = classifyProject(stack);
7219
+ projectType = classification.type;
7220
+ templateName = classification.suggestedTemplate;
7221
+ }
7222
+ let dag;
7223
+ if (templateName) {
7224
+ const templateFn = getTemplate(templateName);
7225
+ if (templateFn) {
7226
+ dag = templateFn({ name: "Orchestration", goal: options.requirement });
7227
+ } else {
7228
+ dag = await decomposeRequirement(options.requirement, options.client);
7229
+ templateName = void 0;
7230
+ }
7231
+ } else {
7232
+ dag = await decomposeRequirement(options.requirement, options.client);
7233
+ }
7234
+ const orchestration = await runOrchestrationFull(dag, {
7235
+ router: options.router,
7236
+ enablePolicyCheck: options.enablePolicyCheck,
7237
+ enableSelfReview: options.enableSelfReview,
7238
+ enableCostTracking: options.enableCostTracking,
7239
+ budgetLimit: options.budgetLimit,
7240
+ callbacks: options.callbacks
7241
+ });
7242
+ const summary = formatSmartResult({
7243
+ dag,
7244
+ projectType,
7245
+ templateUsed: templateName,
7246
+ orchestration,
7247
+ summary: ""
7248
+ });
7249
+ return { dag, projectType, templateUsed: templateName, orchestration, summary };
7250
+ }
7251
+ function formatSmartResult(result) {
7252
+ const lines = [];
7253
+ if (result.projectType) {
7254
+ lines.push(`Project type: ${result.projectType}`);
7255
+ }
7256
+ if (result.templateUsed) {
7257
+ lines.push(`Template: ${result.templateUsed}`);
7258
+ }
7259
+ lines.push("");
7260
+ lines.push(formatDAGForDisplay(result.dag));
7261
+ lines.push("");
7262
+ const orch = result.orchestration;
7263
+ lines.push(
7264
+ `Status: ${orch.success ? "completed" : "failed"} (${orch.durationMs}ms)`
7265
+ );
7266
+ if (orch.policy && !orch.policy.passed) {
7267
+ const errorCount = orch.policy.violations.filter(
7268
+ (v) => v.severity === "error"
7269
+ ).length;
7270
+ lines.push(
7271
+ `Policy: FAILED \u2014 ${errorCount} error${errorCount !== 1 ? "s" : ""}`
7272
+ );
7273
+ }
7274
+ if (orch.review) {
7275
+ lines.push(`Review: ${orch.review.passed ? "passed" : "failed"}`);
7276
+ }
7277
+ if (orch.costSummary) {
7278
+ lines.push(`Cost: ${orch.costSummary}`);
7279
+ }
7280
+ return lines.join("\n");
7281
+ }
7282
+
7283
+ // src/orchestrator/index.ts
7284
+ init_dag();
6140
7285
 
6141
7286
  // src/commands.ts
6142
7287
  init_registry();
@@ -8043,7 +9188,7 @@ function handleReset(action) {
8043
9188
  function handleUpdate() {
8044
9189
  try {
8045
9190
  const current = execFileSync3("npm", ["view", "@aman_asmuei/aman-agent", "version"], { encoding: "utf-8" }).trim();
8046
- const local = true ? "0.40.0" : "unknown";
9191
+ const local = true ? "0.41.0" : "unknown";
8047
9192
  if (current === local) {
8048
9193
  return { handled: true, output: `${pc6.green("Up to date")} \u2014 v${local}` };
8049
9194
  }
@@ -8862,21 +10007,57 @@ async function handleOrchestrateCommand(action, args, ctx) {
8862
10007
  if (!action) {
8863
10008
  return {
8864
10009
  handled: true,
8865
- output: `Usage: /orchestrate <requirement>
8866
-
8867
- Decomposes a requirement into a task DAG and executes it with parallel agents.
8868
-
8869
- Alias: /orch`
10010
+ output: [
10011
+ "Usage: /orchestrate <requirement>",
10012
+ "",
10013
+ "Decomposes a requirement into a task DAG and executes it with parallel agents.",
10014
+ "Auto-detects project type, selects template, runs policy check, and tracks cost.",
10015
+ "",
10016
+ "Options (pass as first arg):",
10017
+ " --template <name> Force a template (full-feature, bug-fix, security-audit)",
10018
+ " --no-review Skip self-review loop",
10019
+ " --no-policy Skip policy check",
10020
+ "",
10021
+ "Alias: /orch"
10022
+ ].join("\n")
8870
10023
  };
8871
10024
  }
8872
- const requirement = [action, ...args].join(" ");
8873
10025
  if (!ctx.llmClient) {
8874
10026
  return { handled: true, output: pc6.red("Orchestration requires an LLM client. Not available.") };
8875
10027
  }
10028
+ let templateName;
10029
+ let enableSelfReview = true;
10030
+ let enablePolicyCheck = true;
10031
+ const filtered = [];
10032
+ const allArgs = [action, ...args];
10033
+ for (let i = 0; i < allArgs.length; i++) {
10034
+ if (allArgs[i] === "--template" && allArgs[i + 1]) {
10035
+ templateName = allArgs[++i];
10036
+ } else if (allArgs[i] === "--no-review") {
10037
+ enableSelfReview = false;
10038
+ } else if (allArgs[i] === "--no-policy") {
10039
+ enablePolicyCheck = false;
10040
+ } else {
10041
+ filtered.push(allArgs[i]);
10042
+ }
10043
+ }
10044
+ const requirement = filtered.join(" ");
10045
+ if (!requirement.trim()) {
10046
+ return { handled: true, output: pc6.red("Please provide a requirement to orchestrate.") };
10047
+ }
8876
10048
  try {
8877
- const dag = await decomposeRequirement(requirement, ctx.llmClient);
8878
- const display = formatDAGForDisplay(dag);
8879
- return { handled: true, output: display };
10049
+ const router = createModelRouter({ standard: ctx.llmClient });
10050
+ const result = await smartOrchestrate({
10051
+ requirement,
10052
+ client: ctx.llmClient,
10053
+ router,
10054
+ projectPath: process.cwd(),
10055
+ templateName,
10056
+ enablePolicyCheck,
10057
+ enableSelfReview,
10058
+ enableCostTracking: true
10059
+ });
10060
+ return { handled: true, output: result.summary };
8880
10061
  } catch (err) {
8881
10062
  const msg = err instanceof Error ? err.message : String(err);
8882
10063
  return { handled: true, output: pc6.red(`Orchestration failed: ${msg}`) };
@@ -8931,11 +10112,22 @@ async function handleGitHubCommand(action, args, ctx) {
8931
10112
  try {
8932
10113
  const issue = await fetchIssue(issueNum);
8933
10114
  const requirement = formatIssueAsRequirement(issue);
8934
- const dag = await decomposeRequirement(requirement, ctx.llmClient);
8935
- const display = formatDAGForDisplay(dag);
8936
- return { handled: true, output: `${pc6.bold(`Plan for #${issue.number}: ${issue.title}`)}
10115
+ const router = createModelRouter({ standard: ctx.llmClient });
10116
+ const result = await smartOrchestrate({
10117
+ requirement,
10118
+ client: ctx.llmClient,
10119
+ router,
10120
+ projectPath: process.cwd(),
10121
+ enablePolicyCheck: true,
10122
+ enableSelfReview: false,
10123
+ enableCostTracking: true
10124
+ });
10125
+ return {
10126
+ handled: true,
10127
+ output: `${pc6.bold(`Plan for #${issue.number}: ${issue.title}`)}
8937
10128
 
8938
- ${display}` };
10129
+ ${result.summary}`
10130
+ };
8939
10131
  } catch (err) {
8940
10132
  const msg = err instanceof Error ? err.message : String(err);
8941
10133
  return { handled: true, output: pc6.red(`Failed to plan issue #${issueNum}: ${msg}`) };
@@ -11150,7 +12342,7 @@ var Inbox = class {
11150
12342
  // package.json
11151
12343
  var package_default = {
11152
12344
  name: "@aman_asmuei/aman-agent",
11153
- version: "0.40.0",
12345
+ version: "0.41.0",
11154
12346
  description: "Your AI companion, running locally \u2014 powered by the aman ecosystem",
11155
12347
  type: "module",
11156
12348
  engines: {
@@ -11517,7 +12709,7 @@ function bootstrapEcosystem() {
11517
12709
  return true;
11518
12710
  }
11519
12711
  var program = new Command();
11520
- program.name("aman-agent").description("Your AI companion, running locally").version("0.40.0").option("--model <model>", "Override LLM model").option("--budget <tokens>", "Token budget for system prompt (default: 8000)", parseInt).option("--profile <name>", "Use a specific agent profile (e.g., coder, writer, researcher)").action(async (options) => {
12712
+ program.name("aman-agent").description("Your AI companion, running locally").version("0.41.0").option("--model <model>", "Override LLM model").option("--budget <tokens>", "Token budget for system prompt (default: 8000)", parseInt).option("--profile <name>", "Use a specific agent profile (e.g., coder, writer, researcher)").action(async (options) => {
11521
12713
  p4.intro(pc9.bold("aman agent") + pc9.dim(" \u2014 your AI companion"));
11522
12714
  let config = loadConfig();
11523
12715
  if (!config) {