@aman_asmuei/aman-agent 0.40.0 → 0.42.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"() {
@@ -1913,6 +1939,19 @@ var DEFAULT_HOOKS = {
1913
1939
  featureHints: true,
1914
1940
  personalityAdapt: true
1915
1941
  };
1942
+ var DEFAULT_MIRROR = {
1943
+ enabled: true,
1944
+ dir: "",
1945
+ // populated in loadConfig via homeDir() — empty string is a sentinel
1946
+ tiers: ["core", "working", "archival"],
1947
+ autoSyncOnStartup: true
1948
+ };
1949
+ function expandHome(p5) {
1950
+ if (p5.startsWith("~/") || p5 === "~") {
1951
+ return path.join(os.homedir(), p5.slice(1));
1952
+ }
1953
+ return p5;
1954
+ }
1916
1955
  function homeDir() {
1917
1956
  return process.env.AMAN_HOME || process.env.AMAN_AGENT_HOME || path.join(os.homedir(), ".aman-agent");
1918
1957
  }
@@ -1943,6 +1982,12 @@ function loadConfig() {
1943
1982
  try {
1944
1983
  const raw = JSON.parse(fs.readFileSync(p5, "utf-8"));
1945
1984
  raw.hooks = { ...DEFAULT_HOOKS, ...raw.hooks };
1985
+ raw.mirror = {
1986
+ ...DEFAULT_MIRROR,
1987
+ dir: path.join(homeDir(), "memories"),
1988
+ ...raw.mirror ?? {}
1989
+ };
1990
+ raw.mirror.dir = expandHome(raw.mirror.dir);
1946
1991
  return raw;
1947
1992
  } catch {
1948
1993
  return null;
@@ -3360,12 +3405,15 @@ import {
3360
3405
  syncFromClaude,
3361
3406
  exportForTeam,
3362
3407
  importFromTeam,
3363
- syncToCopilot
3408
+ syncToCopilot,
3409
+ MirrorEngine,
3410
+ parseFrontmatter
3364
3411
  } from "@aman_asmuei/amem-core";
3365
3412
  import path7 from "path";
3366
3413
  import os6 from "os";
3367
3414
  import fs7 from "fs";
3368
3415
  var db = null;
3416
+ var mirrorEngine = null;
3369
3417
  var currentProject = "global";
3370
3418
  async function initMemory(project) {
3371
3419
  if (db) return db;
@@ -3394,6 +3442,23 @@ async function initMemory(project) {
3394
3442
  }
3395
3443
  }
3396
3444
  currentProject = project ?? "global";
3445
+ try {
3446
+ const agentCfg = loadConfig();
3447
+ const mirrorCfg = agentCfg?.mirror;
3448
+ const enabled = mirrorCfg?.enabled ?? true;
3449
+ if (enabled) {
3450
+ const dir = expandHome(mirrorCfg?.dir ?? path7.join(homeDir(), "memories"));
3451
+ const tiers = mirrorCfg?.tiers ?? ["core", "working", "archival"];
3452
+ mirrorEngine = new MirrorEngine(db, {
3453
+ dir,
3454
+ tiers,
3455
+ includeIndex: true
3456
+ });
3457
+ }
3458
+ } catch (err) {
3459
+ console.warn(`[amem-mirror] construction failed: ${err instanceof Error ? err.message : String(err)}`);
3460
+ mirrorEngine = null;
3461
+ }
3397
3462
  preloadEmbeddings();
3398
3463
  setTimeout(() => {
3399
3464
  try {
@@ -3423,7 +3488,12 @@ async function memoryContext(topic, maxTokens) {
3423
3488
  return buildContext(getDb(), topic, { maxTokens, scope: currentProject });
3424
3489
  }
3425
3490
  async function memoryStore(opts) {
3426
- return storeMemory(getDb(), opts);
3491
+ const result = await storeMemory(getDb(), opts);
3492
+ if (result.action !== "private" && mirrorEngine) {
3493
+ const saved = getDb().getById(result.id);
3494
+ if (saved) void mirrorEngine.onSave(saved);
3495
+ }
3496
+ return result;
3427
3497
  }
3428
3498
  function memoryLog(sessionId, role, content) {
3429
3499
  return getDb().appendLog({
@@ -3447,6 +3517,7 @@ async function memoryForget(opts) {
3447
3517
  db2.deleteMemory(fullId);
3448
3518
  const vecIdx = getVectorIndex();
3449
3519
  if (vecIdx) vecIdx.remove(fullId);
3520
+ void mirrorEngine?.onDelete(fullId, memory.type);
3450
3521
  return { deleted: 1, message: `Deleted: "${memory.content}" (${memory.type})` };
3451
3522
  }
3452
3523
  if (opts.type) {
@@ -3457,6 +3528,7 @@ async function memoryForget(opts) {
3457
3528
  for (const m of matches) {
3458
3529
  db2.deleteMemory(m.id);
3459
3530
  if (vecIdx) vecIdx.remove(m.id);
3531
+ void mirrorEngine?.onDelete(m.id, m.type);
3460
3532
  }
3461
3533
  return { deleted: matches.length, message: `Deleted ${matches.length} "${opts.type}" memories.` };
3462
3534
  }
@@ -3468,6 +3540,7 @@ async function memoryForget(opts) {
3468
3540
  for (const m of matches) {
3469
3541
  db2.deleteMemory(m.id);
3470
3542
  if (vecIdx) vecIdx.remove(m.id);
3543
+ void mirrorEngine?.onDelete(m.id, m.type);
3471
3544
  }
3472
3545
  return { deleted: matches.length, message: `Deleted ${matches.length} memories matching "${opts.query}".` };
3473
3546
  }
@@ -3623,6 +3696,140 @@ async function memorySync(action, opts = {}) {
3623
3696
  return { ok: false, error: err instanceof Error ? err.message : String(err) };
3624
3697
  }
3625
3698
  }
3699
+ function getMirrorEngine() {
3700
+ return mirrorEngine;
3701
+ }
3702
+ function extractAmemFields(raw) {
3703
+ const out = {};
3704
+ const block = raw.match(/^---\s*\n([\s\S]*?)\n---/);
3705
+ if (!block) return out;
3706
+ for (const line of block[1].split("\n")) {
3707
+ const kv = line.match(/^(amem_\w+)\s*:\s*(.+)$/);
3708
+ if (!kv) continue;
3709
+ const key = kv[1];
3710
+ const val = kv[2].trim();
3711
+ switch (key) {
3712
+ case "amem_id":
3713
+ out.amemId = val;
3714
+ break;
3715
+ case "amem_type":
3716
+ out.amemType = val;
3717
+ break;
3718
+ case "amem_tier":
3719
+ out.amemTier = val;
3720
+ break;
3721
+ case "amem_confidence": {
3722
+ const n = Number(val);
3723
+ if (Number.isFinite(n)) out.amemConfidence = n;
3724
+ break;
3725
+ }
3726
+ case "amem_tags":
3727
+ out.amemTags = val.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
3728
+ break;
3729
+ case "amem_created": {
3730
+ const t = Date.parse(val);
3731
+ if (!Number.isNaN(t)) out.amemCreated = t;
3732
+ break;
3733
+ }
3734
+ }
3735
+ }
3736
+ return out;
3737
+ }
3738
+ var CLAUDE_TO_AMEM_TYPE = {
3739
+ feedback: "correction",
3740
+ project: "decision",
3741
+ user: "preference",
3742
+ reference: "topology"
3743
+ };
3744
+ async function startupAutoSync() {
3745
+ const cfg = loadConfig();
3746
+ const autoSync = cfg?.mirror?.autoSyncOnStartup ?? true;
3747
+ const enabled = cfg?.mirror?.enabled ?? true;
3748
+ if (!enabled || !autoSync) return null;
3749
+ const engine = mirrorEngine;
3750
+ if (!engine) return null;
3751
+ const dir = engine.status().dir;
3752
+ try {
3753
+ return await syncFromMirrorDir(dir);
3754
+ } catch {
3755
+ return null;
3756
+ }
3757
+ }
3758
+ async function syncFromMirrorDir(dir) {
3759
+ const db2 = getDb();
3760
+ const result = {
3761
+ imported: 0,
3762
+ skipped: 0,
3763
+ updated: 0,
3764
+ details: [],
3765
+ projectsScanned: 1
3766
+ };
3767
+ if (!fs7.existsSync(dir)) return result;
3768
+ const targets = [];
3769
+ const walk = (d) => {
3770
+ for (const name of fs7.readdirSync(d)) {
3771
+ if (name === "INDEX.md") continue;
3772
+ const full = path7.join(d, name);
3773
+ const stat = fs7.statSync(full);
3774
+ if (stat.isDirectory()) walk(full);
3775
+ else if (name.endsWith(".md")) targets.push(full);
3776
+ }
3777
+ };
3778
+ try {
3779
+ walk(dir);
3780
+ } catch {
3781
+ return result;
3782
+ }
3783
+ for (const filePath of targets) {
3784
+ const raw = fs7.readFileSync(filePath, "utf-8");
3785
+ const parsed = parseFrontmatter(raw, filePath);
3786
+ if (!parsed) {
3787
+ result.skipped++;
3788
+ result.details.push({ action: "skipped", name: filePath, type: "unknown", reason: "invalid frontmatter" });
3789
+ continue;
3790
+ }
3791
+ const amem = extractAmemFields(raw);
3792
+ const resolvedType = amem.amemType ?? CLAUDE_TO_AMEM_TYPE[parsed.type];
3793
+ if (!resolvedType) {
3794
+ result.skipped++;
3795
+ result.details.push({ action: "skipped", name: parsed.name, type: parsed.type, reason: `Unknown type: ${parsed.type}` });
3796
+ continue;
3797
+ }
3798
+ const content = parsed.body;
3799
+ if (!content.trim()) {
3800
+ result.skipped++;
3801
+ result.details.push({ action: "skipped", name: parsed.name, type: resolvedType, reason: "empty body" });
3802
+ continue;
3803
+ }
3804
+ const existing = db2.findByContentHash(content);
3805
+ if (existing) {
3806
+ result.skipped++;
3807
+ result.details.push({ action: "skipped", name: parsed.name, type: resolvedType, reason: "duplicate content" });
3808
+ continue;
3809
+ }
3810
+ const embedding = await generateEmbedding(content);
3811
+ const confidence = amem.amemConfidence ?? 0.8;
3812
+ const isGlobal = resolvedType === "preference" || resolvedType === "correction";
3813
+ const scope = isGlobal ? "global" : currentProject;
3814
+ const tags = amem.amemTags ?? ["mirror-sync"];
3815
+ db2.insertMemory({
3816
+ content,
3817
+ type: resolvedType,
3818
+ tags,
3819
+ confidence,
3820
+ source: "mirror-sync",
3821
+ embedding,
3822
+ scope,
3823
+ ...amem.amemTier ? { tier: amem.amemTier } : {},
3824
+ // Preserve original creation time when the mirror file carries it,
3825
+ // so round-tripped memories keep their chronology for recency decay.
3826
+ ...amem.amemCreated ? { validFrom: amem.amemCreated } : {}
3827
+ });
3828
+ result.imported++;
3829
+ result.details.push({ action: "imported", name: parsed.name, type: resolvedType });
3830
+ }
3831
+ return result;
3832
+ }
3626
3833
 
3627
3834
  // src/profile-templates.ts
3628
3835
  import fs8 from "fs";
@@ -3756,6 +3963,9 @@ var ORCHESTRATOR_PROFILES = [
3756
3963
  testerProfile,
3757
3964
  reviewerProfile
3758
3965
  ];
3966
+ function getOrchestratorProfile(name) {
3967
+ return ORCHESTRATOR_PROFILES.find((p5) => p5.name === name);
3968
+ }
3759
3969
 
3760
3970
  // src/profile-templates.ts
3761
3971
  var BUILT_IN_PROFILES = [
@@ -6074,21 +6284,950 @@ async function delegatePipeline(steps, initialInput, client, mcpManager, options
6074
6284
 
6075
6285
  // src/orchestrator/index.ts
6076
6286
  init_types();
6287
+
6288
+ // src/orchestrator/state-machine.ts
6289
+ var ORCHESTRATION_TRANSITIONS = {
6290
+ pending: ["running", "cancelled"],
6291
+ running: ["awaiting_approval", "paused", "completed", "failed", "cancelled"],
6292
+ awaiting_approval: ["approved", "cancelled", "failed"],
6293
+ approved: ["running", "cancelled"],
6294
+ paused: ["running", "cancelled", "failed"],
6295
+ completed: [],
6296
+ failed: [],
6297
+ cancelled: []
6298
+ };
6299
+ var TASK_TRANSITIONS = {
6300
+ pending: ["ready", "skipped", "blocked"],
6301
+ ready: ["running", "skipped", "blocked"],
6302
+ running: ["completed", "failed"],
6303
+ completed: [],
6304
+ failed: ["ready"],
6305
+ skipped: [],
6306
+ blocked: ["ready", "skipped"]
6307
+ };
6308
+ var TERMINAL_ORCHESTRATION = /* @__PURE__ */ new Set([
6309
+ "completed",
6310
+ "failed",
6311
+ "cancelled"
6312
+ ]);
6313
+ var InvalidTransitionError = class extends Error {
6314
+ constructor(from, to, entity = "orchestration") {
6315
+ super(
6316
+ `Invalid ${entity} transition: ${from} \u2192 ${to}`
6317
+ );
6318
+ this.from = from;
6319
+ this.to = to;
6320
+ this.entity = entity;
6321
+ this.name = "InvalidTransitionError";
6322
+ }
6323
+ from;
6324
+ to;
6325
+ entity;
6326
+ };
6327
+ function createOrchestrationState(dag) {
6328
+ const now = Date.now();
6329
+ const taskStatuses = /* @__PURE__ */ new Map();
6330
+ for (const node2 of dag.nodes) {
6331
+ taskStatuses.set(node2.id, "pending");
6332
+ }
6333
+ return {
6334
+ dag,
6335
+ status: "pending",
6336
+ taskStatuses,
6337
+ taskResults: /* @__PURE__ */ new Map(),
6338
+ activeGate: null,
6339
+ startedAt: now,
6340
+ updatedAt: now
6341
+ };
6342
+ }
6343
+ function canTransition(state, to) {
6344
+ return ORCHESTRATION_TRANSITIONS[state.status].includes(to);
6345
+ }
6346
+ function cloneState(state) {
6347
+ return {
6348
+ ...state,
6349
+ taskStatuses: new Map(state.taskStatuses),
6350
+ taskResults: new Map(state.taskResults),
6351
+ updatedAt: Date.now()
6352
+ };
6353
+ }
6354
+ function transition(state, to, error) {
6355
+ if (!canTransition(state, to)) {
6356
+ throw new InvalidTransitionError(state.status, to);
6357
+ }
6358
+ const next = cloneState(state);
6359
+ next.status = to;
6360
+ if (TERMINAL_ORCHESTRATION.has(to)) {
6361
+ next.completedAt = next.updatedAt;
6362
+ }
6363
+ if (error !== void 0) {
6364
+ next.error = error;
6365
+ }
6366
+ return next;
6367
+ }
6368
+ function transitionTask(state, taskId, to) {
6369
+ const current = state.taskStatuses.get(taskId);
6370
+ if (current === void 0) {
6371
+ throw new Error(`Unknown task id: ${taskId}`);
6372
+ }
6373
+ if (!TASK_TRANSITIONS[current].includes(to)) {
6374
+ throw new InvalidTransitionError(current, to, "task");
6375
+ }
6376
+ const next = cloneState(state);
6377
+ next.taskStatuses.set(taskId, to);
6378
+ return next;
6379
+ }
6380
+
6381
+ // src/orchestrator/index.ts
6077
6382
  init_dag();
6383
+
6384
+ // src/orchestrator/model-router.ts
6385
+ function createModelRouter(clients) {
6386
+ return {
6387
+ getClient(tier) {
6388
+ if (tier === "fast") return clients.fast ?? clients.standard;
6389
+ if (tier === "advanced") return clients.advanced ?? clients.standard;
6390
+ return clients.standard;
6391
+ }
6392
+ };
6393
+ }
6394
+
6395
+ // src/orchestrator/audit.ts
6396
+ function createAuditLog(orchestrationId) {
6397
+ return { orchestrationId, events: [] };
6398
+ }
6399
+ function recordAuditEvent(log5, event) {
6400
+ log5.events.push({ ...event, timestamp: Date.now() });
6401
+ }
6402
+
6403
+ // src/orchestrator/index.ts
6078
6404
  init_decompose();
6079
6405
 
6080
6406
  // src/orchestrator/scheduler.ts
6081
6407
  init_dag();
6408
+ async function runScheduler(dag, router, options, callbacks) {
6409
+ const startTime = Date.now();
6410
+ const maxParallel = options?.maxParallelTasks ?? 4;
6411
+ const mcpManager = options?.mcpManager ?? null;
6412
+ validateDAG(dag);
6413
+ let state = createOrchestrationState(dag);
6414
+ const auditLog = createAuditLog(dag.id);
6415
+ state = transition(state, "running");
6416
+ recordAuditEvent(auditLog, {
6417
+ type: "orchestration_started",
6418
+ message: `Orchestration "${dag.name}" started`
6419
+ });
6420
+ const resolvedGates = /* @__PURE__ */ new Set();
6421
+ const running = /* @__PURE__ */ new Map();
6422
+ async function transitionOrch(to, error) {
6423
+ const from = state.status;
6424
+ state = transition(state, to, error);
6425
+ if (callbacks?.onPhaseTransition) {
6426
+ await callbacks.onPhaseTransition(from, to);
6427
+ }
6428
+ }
6429
+ function dispatchTask(nodeId) {
6430
+ const node2 = dag.nodes.find((n) => n.id === nodeId);
6431
+ state = transitionTask(state, nodeId, "ready");
6432
+ state = transitionTask(state, nodeId, "running");
6433
+ const taskPromise = (async () => {
6434
+ if (callbacks?.onTaskStarted) {
6435
+ await callbacks.onTaskStarted(nodeId, node2.name);
6436
+ }
6437
+ recordAuditEvent(auditLog, {
6438
+ type: "task_started",
6439
+ message: `Task "${node2.name}" started`,
6440
+ taskId: nodeId
6441
+ });
6442
+ const startedAt = Date.now();
6443
+ const client = router.getClient(node2.tier);
6444
+ const taskDesc = [node2.name, node2.description, node2.context].filter(Boolean).join(": ");
6445
+ try {
6446
+ const delegationResult = await delegateTask(
6447
+ taskDesc,
6448
+ node2.profile,
6449
+ client,
6450
+ mcpManager,
6451
+ { silent: true }
6452
+ );
6453
+ const completedAt = Date.now();
6454
+ if (delegationResult.success) {
6455
+ const taskResult = {
6456
+ nodeId,
6457
+ status: "completed",
6458
+ output: delegationResult.response,
6459
+ toolsUsed: delegationResult.toolsUsed,
6460
+ turns: delegationResult.turns,
6461
+ startedAt,
6462
+ completedAt,
6463
+ tier: node2.tier
6464
+ };
6465
+ state = transitionTask(state, nodeId, "completed");
6466
+ state.taskResults.set(nodeId, taskResult);
6467
+ recordAuditEvent(auditLog, {
6468
+ type: "task_completed",
6469
+ message: `Task "${node2.name}" completed`,
6470
+ taskId: nodeId
6471
+ });
6472
+ if (callbacks?.onTaskCompleted) {
6473
+ await callbacks.onTaskCompleted(nodeId, node2.name, taskResult);
6474
+ }
6475
+ } else {
6476
+ const taskResult = {
6477
+ nodeId,
6478
+ status: "failed",
6479
+ error: delegationResult.error ?? "Task failed",
6480
+ toolsUsed: delegationResult.toolsUsed,
6481
+ turns: delegationResult.turns,
6482
+ startedAt,
6483
+ completedAt,
6484
+ tier: node2.tier
6485
+ };
6486
+ state = transitionTask(state, nodeId, "failed");
6487
+ state.taskResults.set(nodeId, taskResult);
6488
+ recordAuditEvent(auditLog, {
6489
+ type: "task_failed",
6490
+ message: `Task "${node2.name}" failed: ${delegationResult.error}`,
6491
+ taskId: nodeId
6492
+ });
6493
+ if (callbacks?.onTaskFailed) {
6494
+ await callbacks.onTaskFailed(nodeId, node2.name, delegationResult.error ?? "Task failed");
6495
+ }
6496
+ }
6497
+ } catch (err) {
6498
+ const completedAt = Date.now();
6499
+ const errorMsg = err instanceof Error ? err.message : String(err);
6500
+ const taskResult = {
6501
+ nodeId,
6502
+ status: "failed",
6503
+ error: errorMsg,
6504
+ toolsUsed: [],
6505
+ turns: 0,
6506
+ startedAt,
6507
+ completedAt,
6508
+ tier: node2.tier
6509
+ };
6510
+ state = transitionTask(state, nodeId, "failed");
6511
+ state.taskResults.set(nodeId, taskResult);
6512
+ recordAuditEvent(auditLog, {
6513
+ type: "task_failed",
6514
+ message: `Task "${node2.name}" threw: ${errorMsg}`,
6515
+ taskId: nodeId
6516
+ });
6517
+ if (callbacks?.onTaskFailed) {
6518
+ await callbacks.onTaskFailed(nodeId, node2.name, errorMsg);
6519
+ }
6520
+ }
6521
+ })();
6522
+ running.set(nodeId, taskPromise);
6523
+ taskPromise.then(() => running.delete(nodeId));
6524
+ }
6525
+ try {
6526
+ while (true) {
6527
+ if (["completed", "failed", "cancelled"].includes(state.status)) {
6528
+ break;
6529
+ }
6530
+ const hasFailed = [...state.taskStatuses.values()].some((s) => s === "failed");
6531
+ if (hasFailed) {
6532
+ await transitionOrch("failed", "A task failed");
6533
+ recordAuditEvent(auditLog, {
6534
+ type: "orchestration_failed",
6535
+ message: "Orchestration failed due to task failure"
6536
+ });
6537
+ break;
6538
+ }
6539
+ let gateHandled = false;
6540
+ for (const gate of dag.gates) {
6541
+ if (resolvedGates.has(gate.id)) continue;
6542
+ const allAfterDone = gate.afterNodes.every(
6543
+ (id) => state.taskStatuses.get(id) === "completed"
6544
+ );
6545
+ if (!allAfterDone) continue;
6546
+ gateHandled = true;
6547
+ await transitionOrch("awaiting_approval");
6548
+ recordAuditEvent(auditLog, {
6549
+ type: "approval_requested",
6550
+ message: `Gate "${gate.name}" requires approval`,
6551
+ gateId: gate.id
6552
+ });
6553
+ let approved = false;
6554
+ if (callbacks?.onApprovalRequired) {
6555
+ approved = await callbacks.onApprovalRequired(gate.id, gate.name);
6556
+ }
6557
+ if (approved) {
6558
+ resolvedGates.add(gate.id);
6559
+ await transitionOrch("approved");
6560
+ recordAuditEvent(auditLog, {
6561
+ type: "approval_granted",
6562
+ message: `Gate "${gate.name}" approved`,
6563
+ gateId: gate.id
6564
+ });
6565
+ await transitionOrch("running");
6566
+ recordAuditEvent(auditLog, {
6567
+ type: "gate_resolved",
6568
+ message: `Gate "${gate.name}" resolved, resuming`,
6569
+ gateId: gate.id
6570
+ });
6571
+ } else {
6572
+ await transitionOrch("cancelled");
6573
+ recordAuditEvent(auditLog, {
6574
+ type: "approval_denied",
6575
+ message: `Gate "${gate.name}" denied, cancelling`,
6576
+ gateId: gate.id
6577
+ });
6578
+ break;
6579
+ }
6580
+ }
6581
+ if (["completed", "failed", "cancelled"].includes(state.status)) {
6582
+ break;
6583
+ }
6584
+ const readyNodes = getReadyNodes(dag, state.taskStatuses, resolvedGates);
6585
+ if (readyNodes.length === 0 && running.size === 0) {
6586
+ const allCompleted = [...state.taskStatuses.values()].every(
6587
+ (s) => s === "completed" || s === "skipped"
6588
+ );
6589
+ if (allCompleted) {
6590
+ await transitionOrch("completed");
6591
+ recordAuditEvent(auditLog, {
6592
+ type: "orchestration_completed",
6593
+ message: `Orchestration "${dag.name}" completed successfully`
6594
+ });
6595
+ break;
6596
+ } else {
6597
+ await transitionOrch("failed", "Scheduler stuck: no ready or running tasks");
6598
+ recordAuditEvent(auditLog, {
6599
+ type: "orchestration_failed",
6600
+ message: "Orchestration stuck with no progress possible"
6601
+ });
6602
+ break;
6603
+ }
6604
+ }
6605
+ const availableSlots = maxParallel - running.size;
6606
+ const toDispatch = readyNodes.slice(0, availableSlots);
6607
+ for (const nodeId of toDispatch) {
6608
+ dispatchTask(nodeId);
6609
+ }
6610
+ if (running.size > 0) {
6611
+ await Promise.race(running.values());
6612
+ }
6613
+ }
6614
+ } catch (err) {
6615
+ const errorMsg = err instanceof Error ? err.message : String(err);
6616
+ if (!["completed", "failed", "cancelled"].includes(state.status)) {
6617
+ try {
6618
+ state = transition(state, "failed", errorMsg);
6619
+ } catch {
6620
+ }
6621
+ }
6622
+ recordAuditEvent(auditLog, {
6623
+ type: "orchestration_failed",
6624
+ message: `Orchestration error: ${errorMsg}`
6625
+ });
6626
+ }
6627
+ return {
6628
+ status: state.status,
6629
+ taskResults: state.taskResults,
6630
+ auditLog,
6631
+ error: state.error,
6632
+ durationMs: Date.now() - startTime
6633
+ };
6634
+ }
6635
+
6636
+ // src/orchestrator/review-loop.ts
6637
+ function buildReviewDAG(originalDAG, taskResults) {
6638
+ let context = "Review the following completed work:\n\n";
6639
+ for (const node2 of originalDAG.nodes) {
6640
+ const result = taskResults.get(node2.id);
6641
+ context += `## Task: ${node2.name}
6642
+ `;
6643
+ context += `Profile: ${node2.profile}
6644
+ `;
6645
+ context += `Output: ${result?.output ?? "(no output)"}
6646
+
6647
+ `;
6648
+ }
6649
+ return {
6650
+ id: `review-${originalDAG.id}`,
6651
+ name: `Review: ${originalDAG.name}`,
6652
+ goal: `Review the completed work from "${originalDAG.name}"`,
6653
+ nodes: [
6654
+ {
6655
+ id: "code-review",
6656
+ name: "Code Review",
6657
+ profile: "reviewer",
6658
+ tier: "standard",
6659
+ dependencies: [],
6660
+ context
6661
+ },
6662
+ {
6663
+ id: "test-review",
6664
+ name: "Test Review",
6665
+ profile: "tester",
6666
+ tier: "standard",
6667
+ dependencies: [],
6668
+ context
6669
+ }
6670
+ ],
6671
+ gates: []
6672
+ };
6673
+ }
6674
+ async function runReviewLoop(originalDAG, taskResults, options) {
6675
+ const reviewDAG = buildReviewDAG(originalDAG, taskResults);
6676
+ const schedulerResult = await runScheduler(
6677
+ reviewDAG,
6678
+ options.router,
6679
+ {},
6680
+ options.callbacks
6681
+ );
6682
+ if (schedulerResult.status === "completed") {
6683
+ return {
6684
+ passed: true,
6685
+ iterations: 1,
6686
+ reviewResult: schedulerResult
6687
+ };
6688
+ }
6689
+ return {
6690
+ passed: false,
6691
+ iterations: 1,
6692
+ reason: schedulerResult.error,
6693
+ reviewResult: schedulerResult
6694
+ };
6695
+ }
6696
+
6697
+ // src/orchestrator/circuit-breaker.ts
6698
+ var DEFAULTS = {
6699
+ failureThreshold: 3,
6700
+ resetTimeoutMs: 6e4,
6701
+ halfOpenMaxAttempts: 1
6702
+ };
6703
+ function createCircuitBreaker(name, options) {
6704
+ const opts = { ...DEFAULTS, ...options };
6705
+ let state = "closed";
6706
+ let failures = 0;
6707
+ let lastFailureAt = null;
6708
+ let openedAt = null;
6709
+ let halfOpenAttempts = 0;
6710
+ function checkHalfOpen() {
6711
+ if (state === "open" && openedAt !== null && Date.now() - openedAt >= opts.resetTimeoutMs) {
6712
+ state = "half-open";
6713
+ halfOpenAttempts = 0;
6714
+ }
6715
+ }
6716
+ return {
6717
+ get name() {
6718
+ return name;
6719
+ },
6720
+ get state() {
6721
+ checkHalfOpen();
6722
+ return state;
6723
+ },
6724
+ get failures() {
6725
+ return failures;
6726
+ },
6727
+ get lastFailureAt() {
6728
+ return lastFailureAt;
6729
+ },
6730
+ canExecute() {
6731
+ checkHalfOpen();
6732
+ if (state === "closed") return true;
6733
+ if (state === "open") return false;
6734
+ if (halfOpenAttempts >= opts.halfOpenMaxAttempts) return false;
6735
+ halfOpenAttempts++;
6736
+ return true;
6737
+ },
6738
+ recordSuccess() {
6739
+ if (state === "half-open") {
6740
+ state = "closed";
6741
+ failures = 0;
6742
+ lastFailureAt = null;
6743
+ openedAt = null;
6744
+ halfOpenAttempts = 0;
6745
+ }
6746
+ },
6747
+ recordFailure() {
6748
+ failures++;
6749
+ lastFailureAt = Date.now();
6750
+ if (state === "half-open") {
6751
+ state = "open";
6752
+ openedAt = Date.now();
6753
+ halfOpenAttempts = 0;
6754
+ } else if (failures >= opts.failureThreshold) {
6755
+ state = "open";
6756
+ openedAt = Date.now();
6757
+ }
6758
+ },
6759
+ reset() {
6760
+ state = "closed";
6761
+ failures = 0;
6762
+ lastFailureAt = null;
6763
+ openedAt = null;
6764
+ halfOpenAttempts = 0;
6765
+ }
6766
+ };
6767
+ }
6768
+ function createCircuitBreakerRegistry(options) {
6769
+ const breakers = /* @__PURE__ */ new Map();
6770
+ return {
6771
+ get(name) {
6772
+ let cb = breakers.get(name);
6773
+ if (!cb) {
6774
+ cb = createCircuitBreaker(name, options);
6775
+ breakers.set(name, cb);
6776
+ }
6777
+ return cb;
6778
+ },
6779
+ getAll() {
6780
+ return [...breakers.values()];
6781
+ },
6782
+ resetAll() {
6783
+ for (const cb of breakers.values()) {
6784
+ cb.reset();
6785
+ }
6786
+ },
6787
+ formatStatus() {
6788
+ if (breakers.size === 0) {
6789
+ return "No circuit breakers registered.";
6790
+ }
6791
+ const lines = [...breakers.values()].map(
6792
+ (cb) => ` ${cb.name}: state=${cb.state} failures=${cb.failures}`
6793
+ );
6794
+ return `Circuit breakers (${breakers.size}):
6795
+ ${lines.join("\n")}`;
6796
+ }
6797
+ };
6798
+ }
6082
6799
 
6083
6800
  // src/orchestrator/checkpoint.ts
6084
6801
  import { readFile as readFile2, writeFile, mkdir } from "fs/promises";
6085
6802
  import { join } from "path";
6086
6803
 
6804
+ // src/orchestrator/cost-tracker.ts
6805
+ var DEFAULT_TIER_COSTS = {
6806
+ fast: {
6807
+ inputTokensPerDollar: 5e6,
6808
+ outputTokensPerDollar: 125e4
6809
+ },
6810
+ // ~$0.20/$0.80 per 1M
6811
+ standard: {
6812
+ inputTokensPerDollar: 333333,
6813
+ outputTokensPerDollar: 66667
6814
+ },
6815
+ // ~$3/$15 per 1M
6816
+ advanced: {
6817
+ inputTokensPerDollar: 66667,
6818
+ outputTokensPerDollar: 13333
6819
+ }
6820
+ // ~$15/$75 per 1M
6821
+ };
6822
+ function createCostTracker(options) {
6823
+ const budgetLimit = options?.budgetLimit ?? null;
6824
+ const tierCosts = {
6825
+ ...DEFAULT_TIER_COSTS,
6826
+ ...options?.tierCosts
6827
+ };
6828
+ const _entries = [];
6829
+ function estimateCost(tier, inputTokens, outputTokens) {
6830
+ const rates = tierCosts[tier];
6831
+ return inputTokens / rates.inputTokensPerDollar + outputTokens / rates.outputTokensPerDollar;
6832
+ }
6833
+ function record(taskId, tier, inputTokens, outputTokens) {
6834
+ _entries.push({
6835
+ tier,
6836
+ taskId,
6837
+ inputTokens,
6838
+ outputTokens,
6839
+ estimatedCost: estimateCost(tier, inputTokens, outputTokens),
6840
+ timestamp: Date.now()
6841
+ });
6842
+ }
6843
+ function totalCost() {
6844
+ return _entries.reduce((sum, e) => sum + e.estimatedCost, 0);
6845
+ }
6846
+ function costByTier() {
6847
+ const result = {
6848
+ fast: 0,
6849
+ standard: 0,
6850
+ advanced: 0
6851
+ };
6852
+ for (const entry of _entries) {
6853
+ result[entry.tier] += entry.estimatedCost;
6854
+ }
6855
+ return result;
6856
+ }
6857
+ function entries() {
6858
+ return [..._entries];
6859
+ }
6860
+ function isOverBudget() {
6861
+ if (budgetLimit === null) return false;
6862
+ return totalCost() > budgetLimit;
6863
+ }
6864
+ function remainingBudget() {
6865
+ if (budgetLimit === null) return null;
6866
+ return budgetLimit - totalCost();
6867
+ }
6868
+ function formatSummary() {
6869
+ const total = totalCost();
6870
+ const byTier = costByTier();
6871
+ const lines = [];
6872
+ lines.push(`Total: $${total.toFixed(4)}`);
6873
+ for (const tier of ["fast", "standard", "advanced"]) {
6874
+ if (byTier[tier] > 0) {
6875
+ lines.push(` ${tier}: $${byTier[tier].toFixed(4)}`);
6876
+ }
6877
+ }
6878
+ if (budgetLimit !== null) {
6879
+ const remaining = remainingBudget();
6880
+ lines.push(
6881
+ `Budget: $${budgetLimit.toFixed(2)} | Remaining: $${remaining.toFixed(4)}`
6882
+ );
6883
+ }
6884
+ lines.push(`Entries: ${_entries.length}`);
6885
+ return lines.join("\n");
6886
+ }
6887
+ return {
6888
+ record,
6889
+ totalCost,
6890
+ costByTier,
6891
+ entries,
6892
+ isOverBudget,
6893
+ remainingBudget,
6894
+ formatSummary
6895
+ };
6896
+ }
6897
+
6898
+ // src/orchestrator/policy.ts
6899
+ var maxTaskCount = {
6900
+ name: "max-task-count",
6901
+ description: "DAG has more than 20 tasks",
6902
+ severity: "warning",
6903
+ check: (dag) => {
6904
+ if (dag.nodes.length > 20) {
6905
+ return [
6906
+ {
6907
+ rule: "max-task-count",
6908
+ severity: "warning",
6909
+ message: `DAG has ${dag.nodes.length} tasks (limit: 20)`
6910
+ }
6911
+ ];
6912
+ }
6913
+ return [];
6914
+ }
6915
+ };
6916
+ var requiresReview = {
6917
+ name: "requires-review",
6918
+ description: 'No node with profile "reviewer" exists',
6919
+ severity: "warning",
6920
+ check: (dag) => {
6921
+ const hasReviewer = dag.nodes.some((n) => n.profile === "reviewer");
6922
+ if (!hasReviewer) {
6923
+ return [
6924
+ {
6925
+ rule: "requires-review",
6926
+ severity: "warning",
6927
+ message: "DAG has no reviewer node \u2014 consider adding a code review step"
6928
+ }
6929
+ ];
6930
+ }
6931
+ return [];
6932
+ }
6933
+ };
6934
+ var requiresTesting = {
6935
+ name: "requires-testing",
6936
+ description: 'No node with profile "tester" exists',
6937
+ severity: "warning",
6938
+ check: (dag) => {
6939
+ const hasTester = dag.nodes.some((n) => n.profile === "tester");
6940
+ if (!hasTester) {
6941
+ return [
6942
+ {
6943
+ rule: "requires-testing",
6944
+ severity: "warning",
6945
+ message: "DAG has no tester node \u2014 consider adding a testing step"
6946
+ }
6947
+ ];
6948
+ }
6949
+ return [];
6950
+ }
6951
+ };
6952
+ var noOrphanNodes = {
6953
+ name: "no-orphan-nodes",
6954
+ description: "Every node is either a root or has valid dependencies",
6955
+ severity: "error",
6956
+ check: (dag) => {
6957
+ const nodeIds = new Set(dag.nodes.map((n) => n.id));
6958
+ const violations = [];
6959
+ for (const node2 of dag.nodes) {
6960
+ for (const dep of node2.dependencies) {
6961
+ if (!nodeIds.has(dep)) {
6962
+ violations.push({
6963
+ rule: "no-orphan-nodes",
6964
+ severity: "error",
6965
+ message: `Node "${node2.id}" depends on "${dep}" which does not exist`,
6966
+ nodeId: node2.id
6967
+ });
6968
+ }
6969
+ }
6970
+ }
6971
+ return violations;
6972
+ }
6973
+ };
6974
+ var approvalBeforeDeploy = {
6975
+ name: "approval-before-deploy",
6976
+ description: "If any node name contains 'deploy' or 'release', an approval gate should exist",
6977
+ severity: "warning",
6978
+ check: (dag) => {
6979
+ const deployNodes = dag.nodes.filter((n) => {
6980
+ const lower = n.name.toLowerCase();
6981
+ return lower.includes("deploy") || lower.includes("release");
6982
+ });
6983
+ if (deployNodes.length === 0) return [];
6984
+ const hasApprovalGate = dag.gates.some((g) => g.type === "approval");
6985
+ if (hasApprovalGate) return [];
6986
+ return deployNodes.map((n) => ({
6987
+ rule: "approval-before-deploy",
6988
+ severity: "warning",
6989
+ message: `Node "${n.name}" looks like a deploy/release step but no approval gate exists`,
6990
+ nodeId: n.id
6991
+ }));
6992
+ }
6993
+ };
6994
+ var noAdvancedWithoutJustification = {
6995
+ name: "no-advanced-without-justification",
6996
+ description: 'Nodes with tier "advanced" flagged for cost awareness',
6997
+ severity: "info",
6998
+ check: (dag) => dag.nodes.filter((n) => n.tier === "advanced").map((n) => ({
6999
+ rule: "no-advanced-without-justification",
7000
+ severity: "info",
7001
+ message: `Node "${n.id}" uses advanced tier \u2014 ensure this is justified for cost`,
7002
+ nodeId: n.id
7003
+ }))
7004
+ };
7005
+ var maxParallelDepth = {
7006
+ name: "max-parallel-depth",
7007
+ description: "DAG has more than 5 levels of depth",
7008
+ severity: "warning",
7009
+ check: (dag) => {
7010
+ const nodeIds = new Set(dag.nodes.map((n) => n.id));
7011
+ const depthMap = /* @__PURE__ */ new Map();
7012
+ function getDepth(node2, visited) {
7013
+ if (depthMap.has(node2.id)) return depthMap.get(node2.id);
7014
+ if (visited.has(node2.id)) return 0;
7015
+ visited.add(node2.id);
7016
+ let maxDep = 0;
7017
+ for (const depId of node2.dependencies) {
7018
+ const depNode = dag.nodes.find((n) => n.id === depId);
7019
+ if (depNode) {
7020
+ maxDep = Math.max(maxDep, getDepth(depNode, visited) + 1);
7021
+ }
7022
+ }
7023
+ depthMap.set(node2.id, maxDep);
7024
+ return maxDep;
7025
+ }
7026
+ for (const node2 of dag.nodes) {
7027
+ getDepth(node2, /* @__PURE__ */ new Set());
7028
+ }
7029
+ const maxDepth = Math.max(0, ...depthMap.values());
7030
+ if (maxDepth > 5) {
7031
+ return [
7032
+ {
7033
+ rule: "max-parallel-depth",
7034
+ severity: "warning",
7035
+ message: `DAG depth is ${maxDepth} (limit: 5)`
7036
+ }
7037
+ ];
7038
+ }
7039
+ return [];
7040
+ }
7041
+ };
7042
+ function getDefaultPolicies() {
7043
+ return [
7044
+ maxTaskCount,
7045
+ requiresReview,
7046
+ requiresTesting,
7047
+ noOrphanNodes,
7048
+ approvalBeforeDeploy,
7049
+ noAdvancedWithoutJustification,
7050
+ maxParallelDepth
7051
+ ];
7052
+ }
7053
+ function evaluatePolicy(dag, rules) {
7054
+ const effectiveRules = rules ?? getDefaultPolicies();
7055
+ const violations = [];
7056
+ for (const rule of effectiveRules) {
7057
+ violations.push(...rule.check(dag));
7058
+ }
7059
+ const hasErrors = violations.some((v) => v.severity === "error");
7060
+ return {
7061
+ passed: !hasErrors,
7062
+ violations
7063
+ };
7064
+ }
7065
+
7066
+ // src/orchestrator/runner.ts
7067
+ async function runOrchestrationFull(dag, options) {
7068
+ const startTime = Date.now();
7069
+ let policyResult;
7070
+ if (options.enablePolicyCheck) {
7071
+ policyResult = evaluatePolicy(dag);
7072
+ if (!policyResult.passed) {
7073
+ const errorMessages = policyResult.violations.filter((v) => v.severity === "error").map((v) => v.message).join("; ");
7074
+ return {
7075
+ scheduler: {
7076
+ status: "failed",
7077
+ taskResults: /* @__PURE__ */ new Map(),
7078
+ auditLog: createAuditLog(dag.id),
7079
+ error: `Policy check failed: ${errorMessages}`,
7080
+ durationMs: Date.now() - startTime
7081
+ },
7082
+ policy: policyResult,
7083
+ success: false,
7084
+ durationMs: Date.now() - startTime
7085
+ };
7086
+ }
7087
+ }
7088
+ const circuitBreakers = options.enableCircuitBreaker ? createCircuitBreakerRegistry() : void 0;
7089
+ const costTracker = options.enableCostTracking ? createCostTracker({ budgetLimit: options.budgetLimit }) : void 0;
7090
+ const wrappedCallbacks = {
7091
+ ...options.callbacks,
7092
+ onTaskStarted: async (nodeId, nodeName) => {
7093
+ const node2 = dag.nodes.find((n) => n.id === nodeId);
7094
+ if (circuitBreakers && node2) {
7095
+ circuitBreakers.get(node2.profile).canExecute();
7096
+ }
7097
+ await options.callbacks?.onTaskStarted?.(nodeId, nodeName);
7098
+ },
7099
+ onTaskCompleted: async (nodeId, nodeName, result) => {
7100
+ const node2 = dag.nodes.find((n) => n.id === nodeId);
7101
+ if (node2) {
7102
+ circuitBreakers?.get(node2.profile).recordSuccess();
7103
+ costTracker?.record(nodeId, node2.tier, result.turns * 500, result.turns * 200);
7104
+ }
7105
+ await options.callbacks?.onTaskCompleted?.(nodeId, nodeName, result);
7106
+ },
7107
+ onTaskFailed: async (nodeId, nodeName, error) => {
7108
+ const node2 = dag.nodes.find((n) => n.id === nodeId);
7109
+ if (node2) {
7110
+ circuitBreakers?.get(node2.profile).recordFailure();
7111
+ }
7112
+ await options.callbacks?.onTaskFailed?.(nodeId, nodeName, error);
7113
+ }
7114
+ };
7115
+ const schedulerResult = await runScheduler(dag, options.router, {
7116
+ maxParallelTasks: options.maxParallelTasks
7117
+ }, wrappedCallbacks);
7118
+ let reviewResult;
7119
+ if (options.enableSelfReview && schedulerResult.status === "completed") {
7120
+ reviewResult = await runReviewLoop(dag, schedulerResult.taskResults, {
7121
+ router: options.router
7122
+ });
7123
+ }
7124
+ const success = schedulerResult.status === "completed" && (reviewResult ? reviewResult.passed : true) && (costTracker ? !costTracker.isOverBudget() : true);
7125
+ return {
7126
+ scheduler: schedulerResult,
7127
+ policy: policyResult,
7128
+ review: reviewResult,
7129
+ costSummary: costTracker?.formatSummary(),
7130
+ circuitBreakerStatus: circuitBreakers?.formatStatus(),
7131
+ success,
7132
+ durationMs: Date.now() - startTime
7133
+ };
7134
+ }
7135
+
6087
7136
  // src/orchestrator/smart-orchestrate.ts
6088
7137
  init_decompose();
6089
7138
 
6090
7139
  // src/orchestrator/templates/index.ts
6091
7140
  init_dag();
7141
+ function node(id, profile, tier, deps = []) {
7142
+ return {
7143
+ id,
7144
+ name: id.charAt(0).toUpperCase() + id.slice(1),
7145
+ profile,
7146
+ tier,
7147
+ dependencies: deps
7148
+ };
7149
+ }
7150
+ function approvalGate(id, afterNodes, beforeNodes) {
7151
+ return {
7152
+ id,
7153
+ name: `Approval: ${id}`,
7154
+ type: "approval",
7155
+ afterNodes,
7156
+ beforeNodes
7157
+ };
7158
+ }
7159
+ function fullFeatureTemplate(options) {
7160
+ const gates = [];
7161
+ if (options.requireApproval) {
7162
+ gates.push(approvalGate("approval", ["review", "test"], ["finalize"]));
7163
+ }
7164
+ const dag = {
7165
+ id: `full-feature-${options.name}`,
7166
+ name: `Full Feature: ${options.name}`,
7167
+ goal: options.goal,
7168
+ nodes: [
7169
+ node("design", "architect", "advanced"),
7170
+ node("implement", "coder", "standard", ["design"]),
7171
+ node("review", "reviewer", "standard", ["implement"]),
7172
+ node("test", "tester", "standard", ["implement"]),
7173
+ node("finalize", "coder", "standard", ["review", "test"])
7174
+ ],
7175
+ gates
7176
+ };
7177
+ validateDAG(dag);
7178
+ return dag;
7179
+ }
7180
+ function bugFixTemplate(options) {
7181
+ const nodes = [
7182
+ node("reproduce", "tester", "standard"),
7183
+ node("fix", "coder", "standard", ["reproduce"]),
7184
+ node("test", "tester", "standard", ["fix"]),
7185
+ node("review", "reviewer", "standard", ["test"])
7186
+ ];
7187
+ const gates = [];
7188
+ if (options.requireApproval) {
7189
+ nodes.push(node("verify", "tester", "standard", ["review"]));
7190
+ gates.push(approvalGate("approval", ["review"], ["verify"]));
7191
+ }
7192
+ const dag = {
7193
+ id: `bug-fix-${options.name}`,
7194
+ name: `Bug Fix: ${options.name}`,
7195
+ goal: options.goal,
7196
+ nodes,
7197
+ gates
7198
+ };
7199
+ validateDAG(dag);
7200
+ return dag;
7201
+ }
7202
+ function securityAuditTemplate(options) {
7203
+ const gates = [];
7204
+ if (options.requireApproval) {
7205
+ gates.push(approvalGate("approval", ["triage"], ["fix"]));
7206
+ }
7207
+ const dag = {
7208
+ id: `security-audit-${options.name}`,
7209
+ name: `Security Audit: ${options.name}`,
7210
+ goal: options.goal,
7211
+ nodes: [
7212
+ node("scan", "security", "standard"),
7213
+ node("triage", "security", "standard", ["scan"]),
7214
+ node("fix", "coder", "standard", ["triage"]),
7215
+ node("rescan", "security", "standard", ["fix"]),
7216
+ node("review", "reviewer", "standard", ["rescan"])
7217
+ ],
7218
+ gates
7219
+ };
7220
+ validateDAG(dag);
7221
+ return dag;
7222
+ }
7223
+ var TEMPLATES = {
7224
+ "full-feature": fullFeatureTemplate,
7225
+ "bug-fix": bugFixTemplate,
7226
+ "security-audit": securityAuditTemplate
7227
+ };
7228
+ function getTemplate(name) {
7229
+ return TEMPLATES[name];
7230
+ }
6092
7231
 
6093
7232
  // src/project/detector.ts
6094
7233
  var FRONTEND_FRAMEWORKS = /* @__PURE__ */ new Set(["react", "vue", "svelte"]);
@@ -6106,11 +7245,92 @@ var BACKEND_FRAMEWORKS = /* @__PURE__ */ new Set([
6106
7245
  "django",
6107
7246
  "flask"
6108
7247
  ]);
7248
+ var ML_FRAMEWORKS = /* @__PURE__ */ new Set(["torch", "tensorflow", "sklearn", "pytorch", "pandas", "numpy"]);
6109
7249
  var WEB_FRAMEWORKS = /* @__PURE__ */ new Set([
6110
7250
  ...FRONTEND_FRAMEWORKS,
6111
7251
  ...FULLSTACK_FRAMEWORKS,
6112
7252
  ...BACKEND_FRAMEWORKS
6113
7253
  ]);
7254
+ var TEMPLATE_MAP = {
7255
+ "web-frontend": "full-feature",
7256
+ "web-fullstack": "full-feature",
7257
+ "api-backend": "full-feature",
7258
+ mobile: "full-feature",
7259
+ "cli-tool": "bug-fix",
7260
+ library: "full-feature",
7261
+ "ml-data": "full-feature",
7262
+ monorepo: "full-feature",
7263
+ unknown: "full-feature"
7264
+ };
7265
+ var PROFILE_MAP = {
7266
+ "web-frontend": ["architect", "coder", "tester", "reviewer"],
7267
+ "web-fullstack": ["architect", "coder", "security", "tester", "reviewer"],
7268
+ "api-backend": ["architect", "coder", "security", "tester", "reviewer"],
7269
+ mobile: ["architect", "coder", "tester", "reviewer"],
7270
+ "cli-tool": ["coder", "tester", "reviewer"],
7271
+ library: ["architect", "coder", "tester", "reviewer"],
7272
+ "ml-data": ["architect", "coder", "tester"],
7273
+ monorepo: ["architect", "coder", "security", "tester", "reviewer"],
7274
+ unknown: ["coder", "tester", "reviewer"]
7275
+ };
7276
+ var DESCRIPTION_MAP = {
7277
+ "web-frontend": "Frontend web application",
7278
+ "web-fullstack": "Full-stack web application with database",
7279
+ "api-backend": "API/backend service",
7280
+ mobile: "Mobile application",
7281
+ "cli-tool": "Command-line tool",
7282
+ library: "Reusable library/package",
7283
+ "ml-data": "Machine learning / data science project",
7284
+ monorepo: "Monorepo with multiple packages",
7285
+ unknown: "Unknown project type"
7286
+ };
7287
+ function hasAny(items, set) {
7288
+ return items.some((i) => set.has(i));
7289
+ }
7290
+ function classifyProject(stack) {
7291
+ let type;
7292
+ let confidence;
7293
+ if (stack.isMonorepo) {
7294
+ type = "monorepo";
7295
+ confidence = 0.9;
7296
+ } else if (hasAny(stack.frameworks, /* @__PURE__ */ new Set(["flutter"])) || stack.languages.includes("dart")) {
7297
+ type = "mobile";
7298
+ confidence = 0.9;
7299
+ } else if (hasAny(stack.frameworks, FULLSTACK_FRAMEWORKS) && stack.databases.length > 0) {
7300
+ type = "web-fullstack";
7301
+ confidence = 0.9;
7302
+ } else if (hasAny(stack.frameworks, BACKEND_FRAMEWORKS)) {
7303
+ type = "api-backend";
7304
+ confidence = 0.9;
7305
+ } else if (hasAny(stack.frameworks, FRONTEND_FRAMEWORKS)) {
7306
+ type = "web-frontend";
7307
+ confidence = 0.85;
7308
+ } else if (stack.languages.includes("python") && !hasAny(stack.frameworks, WEB_FRAMEWORKS)) {
7309
+ if (hasAny(stack.frameworks, ML_FRAMEWORKS)) {
7310
+ type = "ml-data";
7311
+ confidence = 0.8;
7312
+ } else {
7313
+ type = "cli-tool";
7314
+ confidence = 0.6;
7315
+ }
7316
+ } else if (stack.languages.length > 0 && stack.frameworks.length === 0) {
7317
+ type = "library";
7318
+ confidence = 0.6;
7319
+ } else if (stack.languages.length === 0 && stack.frameworks.length === 0) {
7320
+ type = "unknown";
7321
+ confidence = 0.3;
7322
+ } else {
7323
+ type = "unknown";
7324
+ confidence = 0.3;
7325
+ }
7326
+ return {
7327
+ type,
7328
+ confidence,
7329
+ suggestedTemplate: TEMPLATE_MAP[type],
7330
+ suggestedProfiles: PROFILE_MAP[type],
7331
+ description: DESCRIPTION_MAP[type]
7332
+ };
7333
+ }
6114
7334
 
6115
7335
  // src/orchestrator/smart-orchestrate.ts
6116
7336
  init_stack_detector();
@@ -6119,24 +7339,130 @@ init_stack_detector();
6119
7339
  import fs18 from "fs";
6120
7340
  import path18 from "path";
6121
7341
  import os15 from "os";
7342
+ function isProfileInstalled(profileName, profilesDir) {
7343
+ return fs18.existsSync(path18.join(profilesDir, profileName, "core.md"));
7344
+ }
7345
+ function installProfile(profileName, profilesDir) {
7346
+ const profile = getOrchestratorProfile(profileName);
7347
+ if (!profile) return false;
7348
+ const profileDir = path18.join(profilesDir, profileName);
7349
+ fs18.mkdirSync(profileDir, { recursive: true });
7350
+ fs18.writeFileSync(path18.join(profileDir, "core.md"), profile.core, "utf-8");
7351
+ if (profile.rules) {
7352
+ fs18.writeFileSync(path18.join(profileDir, "rules.md"), profile.rules, "utf-8");
7353
+ }
7354
+ return true;
7355
+ }
7356
+ function ensureAllProfilesInstalled(profilesDir) {
7357
+ const installed = [];
7358
+ const skipped = [];
7359
+ for (const profile of ORCHESTRATOR_PROFILES) {
7360
+ if (isProfileInstalled(profile.name, profilesDir)) {
7361
+ skipped.push(profile.name);
7362
+ } else {
7363
+ installProfile(profile.name, profilesDir);
7364
+ installed.push(profile.name);
7365
+ }
7366
+ }
7367
+ return { installed, skipped };
7368
+ }
7369
+ function getProfilesDir() {
7370
+ const acoreHome = process.env.ACORE_HOME;
7371
+ if (acoreHome) {
7372
+ return path18.join(acoreHome, "profiles");
7373
+ }
7374
+ return path18.join(os15.homedir(), ".acore", "profiles");
7375
+ }
6122
7376
 
6123
- // src/orchestrator/index.ts
6124
- init_dag();
7377
+ // src/orchestrator/smart-orchestrate.ts
6125
7378
  function formatDAGForDisplay(dag) {
6126
7379
  const lines = [];
6127
7380
  lines.push(`## ${dag.name}`);
6128
7381
  lines.push(`**Goal:** ${dag.goal}`);
6129
7382
  lines.push(`**Tasks:** ${dag.nodes.length} | **Gates:** ${dag.gates.length}`);
6130
7383
  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}`);
7384
+ for (const node2 of dag.nodes) {
7385
+ const depLabel = node2.dependencies.length === 0 ? "(root)" : `(after: ${node2.dependencies.join(", ")})`;
7386
+ lines.push(`- **${node2.name}** \u2192 ${node2.profile} [${node2.tier}] ${depLabel}`);
6134
7387
  }
6135
7388
  for (const gate of dag.gates) {
6136
7389
  lines.push(`- \u{1F512} **${gate.name}** [${gate.type}]`);
6137
7390
  }
6138
7391
  return lines.join("\n");
6139
7392
  }
7393
+ async function smartOrchestrate(options) {
7394
+ ensureAllProfilesInstalled(getProfilesDir());
7395
+ let projectType;
7396
+ let templateName = options.templateName;
7397
+ if (options.projectPath && !templateName) {
7398
+ const stack = scanStack(options.projectPath);
7399
+ const classification = classifyProject(stack);
7400
+ projectType = classification.type;
7401
+ templateName = classification.suggestedTemplate;
7402
+ }
7403
+ let dag;
7404
+ if (templateName) {
7405
+ const templateFn = getTemplate(templateName);
7406
+ if (templateFn) {
7407
+ dag = templateFn({ name: "Orchestration", goal: options.requirement });
7408
+ } else {
7409
+ dag = await decomposeRequirement(options.requirement, options.client);
7410
+ templateName = void 0;
7411
+ }
7412
+ } else {
7413
+ dag = await decomposeRequirement(options.requirement, options.client);
7414
+ }
7415
+ const orchestration = await runOrchestrationFull(dag, {
7416
+ router: options.router,
7417
+ enablePolicyCheck: options.enablePolicyCheck,
7418
+ enableSelfReview: options.enableSelfReview,
7419
+ enableCostTracking: options.enableCostTracking,
7420
+ budgetLimit: options.budgetLimit,
7421
+ callbacks: options.callbacks
7422
+ });
7423
+ const summary = formatSmartResult({
7424
+ dag,
7425
+ projectType,
7426
+ templateUsed: templateName,
7427
+ orchestration,
7428
+ summary: ""
7429
+ });
7430
+ return { dag, projectType, templateUsed: templateName, orchestration, summary };
7431
+ }
7432
+ function formatSmartResult(result) {
7433
+ const lines = [];
7434
+ if (result.projectType) {
7435
+ lines.push(`Project type: ${result.projectType}`);
7436
+ }
7437
+ if (result.templateUsed) {
7438
+ lines.push(`Template: ${result.templateUsed}`);
7439
+ }
7440
+ lines.push("");
7441
+ lines.push(formatDAGForDisplay(result.dag));
7442
+ lines.push("");
7443
+ const orch = result.orchestration;
7444
+ lines.push(
7445
+ `Status: ${orch.success ? "completed" : "failed"} (${orch.durationMs}ms)`
7446
+ );
7447
+ if (orch.policy && !orch.policy.passed) {
7448
+ const errorCount = orch.policy.violations.filter(
7449
+ (v) => v.severity === "error"
7450
+ ).length;
7451
+ lines.push(
7452
+ `Policy: FAILED \u2014 ${errorCount} error${errorCount !== 1 ? "s" : ""}`
7453
+ );
7454
+ }
7455
+ if (orch.review) {
7456
+ lines.push(`Review: ${orch.review.passed ? "passed" : "failed"}`);
7457
+ }
7458
+ if (orch.costSummary) {
7459
+ lines.push(`Cost: ${orch.costSummary}`);
7460
+ }
7461
+ return lines.join("\n");
7462
+ }
7463
+
7464
+ // src/orchestrator/index.ts
7465
+ init_dag();
6140
7466
 
6141
7467
  // src/commands.ts
6142
7468
  init_registry();
@@ -7483,7 +8809,7 @@ async function handleMemoryCommand(action, args, ctx) {
7483
8809
  return { handled: true, output: pc6.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
7484
8810
  }
7485
8811
  }
7486
- if (action && !["search", "clear", "timeline", "stats", "export", "since", "fts", "help", "doctor", "repair", "config", "reflect", "consolidate", "tier", "detail", "relate", "expire", "versions", "sync"].includes(action)) {
8812
+ if (action && !["search", "clear", "timeline", "stats", "export", "since", "fts", "help", "doctor", "repair", "config", "reflect", "consolidate", "tier", "detail", "relate", "expire", "versions", "sync", "mirror"].includes(action)) {
7487
8813
  try {
7488
8814
  const topic = [action, ...args].join(" ");
7489
8815
  const result = await memoryContext(topic);
@@ -7594,6 +8920,24 @@ async function handleMemoryCommand(action, args, ctx) {
7594
8920
  }
7595
8921
  if (action === "export") {
7596
8922
  try {
8923
+ const toDir = parseFlagValue(args, "--to");
8924
+ if (toDir !== void 0) {
8925
+ const engine = getMirrorEngine();
8926
+ if (!engine) {
8927
+ return { handled: true, output: pc6.yellow("Mirror is disabled \u2014 enable via config.mirror.enabled in config.json.") };
8928
+ }
8929
+ const resolved = expandHome(toDir);
8930
+ const res = await engine.exportSnapshot(resolved);
8931
+ const lines2 = [
8932
+ `Wrote ${res.written} files to ${resolved} (${res.skipped} skipped, ${res.errors.length} errors).`
8933
+ ];
8934
+ if (res.errors.length > 0) {
8935
+ lines2.push("");
8936
+ for (const e of res.errors.slice(0, 5)) lines2.push(` - ${e}`);
8937
+ if (res.errors.length > 5) lines2.push(` ...and ${res.errors.length - 5} more`);
8938
+ }
8939
+ return { handled: true, output: lines2.join("\n") };
8940
+ }
7597
8941
  const format = args[0] === "json" ? "json" : "markdown";
7598
8942
  const memories = memoryExport();
7599
8943
  if (memories.length === 0) {
@@ -7674,12 +9018,16 @@ async function handleMemoryCommand(action, args, ctx) {
7674
9018
  ` ${pc6.cyan("/memory since")} <Nh|Nd|Nw> Memories from time window`,
7675
9019
  ` ${pc6.cyan("/memory stats")} Show memory statistics`,
7676
9020
  ` ${pc6.cyan("/memory export")} [json] Export all memories`,
9021
+ ` ${pc6.cyan("/memory export --to")} <dir> Snapshot mirror-format files to <dir>`,
7677
9022
  ` ${pc6.cyan("/memory timeline")} View memory timeline`,
7678
9023
  ` ${pc6.cyan("/memory clear")} <query> Delete matching memories`,
7679
9024
  ` ${pc6.cyan("/memory clear --type")} <type> Delete all of a type`,
7680
9025
  ` ${pc6.cyan("/memory doctor")} Run memory diagnostics`,
7681
9026
  ` ${pc6.cyan("/memory repair")} Dry-run repair (safe)`,
7682
- ` ${pc6.cyan("/memory config")} [key=value] View or update config (e.g. consolidation.maxStaleDays=60)`
9027
+ ` ${pc6.cyan("/memory config")} [key=value] View or update config (e.g. consolidation.maxStaleDays=60)`,
9028
+ ` ${pc6.cyan("/memory mirror status")} Show mirror dir, file count, health`,
9029
+ ` ${pc6.cyan("/memory mirror rebuild")} Rebuild the mirror from the DB`,
9030
+ ` ${pc6.cyan("/memory sync --from")} <dir> Import edits from a mirror-format dir`
7683
9031
  ].join("\n") };
7684
9032
  }
7685
9033
  if (action === "doctor") {
@@ -7864,7 +9212,51 @@ async function handleMemoryCommand(action, args, ctx) {
7864
9212
  }
7865
9213
  return { handled: true, output: lines.join("\n") };
7866
9214
  }
9215
+ if (action === "mirror") {
9216
+ const sub = args[0];
9217
+ try {
9218
+ if (sub === "status") {
9219
+ const engine = getMirrorEngine();
9220
+ if (!engine) return { handled: true, output: pc6.yellow("Mirror is disabled \u2014 enable via config.mirror.enabled in config.json.") };
9221
+ const s = engine.status();
9222
+ const last = s.lastWriteAt ? `${new Date(s.lastWriteAt).toISOString()} (${relativeTimeFromNow(s.lastWriteAt)})` : "never";
9223
+ const lines = [
9224
+ pc6.bold("Mirror:"),
9225
+ ` Dir: ${s.dir}`,
9226
+ ` File count: ${s.fileCount}`,
9227
+ ` Last write: ${last}`,
9228
+ ` Health: ${s.healthy ? "healthy" : "drifted"}`
9229
+ ];
9230
+ return { handled: true, output: lines.join("\n") };
9231
+ }
9232
+ if (sub === "rebuild") {
9233
+ const engine = getMirrorEngine();
9234
+ if (!engine) return { handled: true, output: pc6.yellow("Mirror is disabled \u2014 enable via config.mirror.enabled in config.json.") };
9235
+ const res = await engine.fullMirror();
9236
+ return {
9237
+ handled: true,
9238
+ output: `Rebuilt mirror: ${res.written} files written, ${res.skipped} skipped, ${res.errors.length} errors.`
9239
+ };
9240
+ }
9241
+ return { handled: true, output: pc6.yellow("Unknown mirror subcommand; try 'status' or 'rebuild'.") };
9242
+ } catch (err) {
9243
+ return { handled: true, output: pc6.red(`Mirror error: ${err instanceof Error ? err.message : String(err)}`) };
9244
+ }
9245
+ }
7867
9246
  if (action === "sync") {
9247
+ const fromDir = parseFlagValue(args, "--from");
9248
+ if (fromDir !== void 0) {
9249
+ try {
9250
+ const resolved = expandHome(fromDir);
9251
+ const res = await syncFromMirrorDir(resolved);
9252
+ return {
9253
+ handled: true,
9254
+ output: `Synced ${res.imported} memories from ${resolved} (${res.skipped} skipped, ${res.updated} updated).`
9255
+ };
9256
+ } catch (err) {
9257
+ return { handled: true, output: pc6.red(`Sync error: ${err instanceof Error ? err.message : String(err)}`) };
9258
+ }
9259
+ }
7868
9260
  const syncAction = args[0];
7869
9261
  if (!syncAction) {
7870
9262
  return { handled: true, output: pc6.yellow("Usage: /memory sync <import-claude|export-team|import-team|sync-copilot>") };
@@ -7886,6 +9278,25 @@ ${JSON.stringify(result, null, 2)}` };
7886
9278
  }
7887
9279
  return { handled: true, output: pc6.yellow(`Unknown action: /memory ${action}. Try /memory --help`) };
7888
9280
  }
9281
+ function parseFlagValue(args, flag) {
9282
+ for (let i = 0; i < args.length; i++) {
9283
+ const a = args[i];
9284
+ if (a === flag) {
9285
+ return args[i + 1];
9286
+ }
9287
+ if (a.startsWith(`${flag}=`)) {
9288
+ return a.slice(flag.length + 1);
9289
+ }
9290
+ }
9291
+ return void 0;
9292
+ }
9293
+ function relativeTimeFromNow(ts) {
9294
+ const delta = Date.now() - ts;
9295
+ if (delta < 6e4) return "just now";
9296
+ if (delta < 36e5) return `${Math.round(delta / 6e4)}m ago`;
9297
+ if (delta < 864e5) return `${Math.round(delta / 36e5)}h ago`;
9298
+ return `${Math.round(delta / 864e5)}d ago`;
9299
+ }
7889
9300
  function handleStatusCommand(ctx) {
7890
9301
  const mcpToolCount = ctx.mcpManager ? ctx.mcpManager.getTools().length : 0;
7891
9302
  const amemConnected = isMemoryInitialized();
@@ -8043,7 +9454,7 @@ function handleReset(action) {
8043
9454
  function handleUpdate() {
8044
9455
  try {
8045
9456
  const current = execFileSync3("npm", ["view", "@aman_asmuei/aman-agent", "version"], { encoding: "utf-8" }).trim();
8046
- const local = true ? "0.40.0" : "unknown";
9457
+ const local = true ? "0.42.0" : "unknown";
8047
9458
  if (current === local) {
8048
9459
  return { handled: true, output: `${pc6.green("Up to date")} \u2014 v${local}` };
8049
9460
  }
@@ -8862,21 +10273,57 @@ async function handleOrchestrateCommand(action, args, ctx) {
8862
10273
  if (!action) {
8863
10274
  return {
8864
10275
  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`
10276
+ output: [
10277
+ "Usage: /orchestrate <requirement>",
10278
+ "",
10279
+ "Decomposes a requirement into a task DAG and executes it with parallel agents.",
10280
+ "Auto-detects project type, selects template, runs policy check, and tracks cost.",
10281
+ "",
10282
+ "Options (pass as first arg):",
10283
+ " --template <name> Force a template (full-feature, bug-fix, security-audit)",
10284
+ " --no-review Skip self-review loop",
10285
+ " --no-policy Skip policy check",
10286
+ "",
10287
+ "Alias: /orch"
10288
+ ].join("\n")
8870
10289
  };
8871
10290
  }
8872
- const requirement = [action, ...args].join(" ");
8873
10291
  if (!ctx.llmClient) {
8874
10292
  return { handled: true, output: pc6.red("Orchestration requires an LLM client. Not available.") };
8875
10293
  }
10294
+ let templateName;
10295
+ let enableSelfReview = true;
10296
+ let enablePolicyCheck = true;
10297
+ const filtered = [];
10298
+ const allArgs = [action, ...args];
10299
+ for (let i = 0; i < allArgs.length; i++) {
10300
+ if (allArgs[i] === "--template" && allArgs[i + 1]) {
10301
+ templateName = allArgs[++i];
10302
+ } else if (allArgs[i] === "--no-review") {
10303
+ enableSelfReview = false;
10304
+ } else if (allArgs[i] === "--no-policy") {
10305
+ enablePolicyCheck = false;
10306
+ } else {
10307
+ filtered.push(allArgs[i]);
10308
+ }
10309
+ }
10310
+ const requirement = filtered.join(" ");
10311
+ if (!requirement.trim()) {
10312
+ return { handled: true, output: pc6.red("Please provide a requirement to orchestrate.") };
10313
+ }
8876
10314
  try {
8877
- const dag = await decomposeRequirement(requirement, ctx.llmClient);
8878
- const display = formatDAGForDisplay(dag);
8879
- return { handled: true, output: display };
10315
+ const router = createModelRouter({ standard: ctx.llmClient });
10316
+ const result = await smartOrchestrate({
10317
+ requirement,
10318
+ client: ctx.llmClient,
10319
+ router,
10320
+ projectPath: process.cwd(),
10321
+ templateName,
10322
+ enablePolicyCheck,
10323
+ enableSelfReview,
10324
+ enableCostTracking: true
10325
+ });
10326
+ return { handled: true, output: result.summary };
8880
10327
  } catch (err) {
8881
10328
  const msg = err instanceof Error ? err.message : String(err);
8882
10329
  return { handled: true, output: pc6.red(`Orchestration failed: ${msg}`) };
@@ -8931,11 +10378,22 @@ async function handleGitHubCommand(action, args, ctx) {
8931
10378
  try {
8932
10379
  const issue = await fetchIssue(issueNum);
8933
10380
  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}`)}
10381
+ const router = createModelRouter({ standard: ctx.llmClient });
10382
+ const result = await smartOrchestrate({
10383
+ requirement,
10384
+ client: ctx.llmClient,
10385
+ router,
10386
+ projectPath: process.cwd(),
10387
+ enablePolicyCheck: true,
10388
+ enableSelfReview: false,
10389
+ enableCostTracking: true
10390
+ });
10391
+ return {
10392
+ handled: true,
10393
+ output: `${pc6.bold(`Plan for #${issue.number}: ${issue.title}`)}
8937
10394
 
8938
- ${display}` };
10395
+ ${result.summary}`
10396
+ };
8939
10397
  } catch (err) {
8940
10398
  const msg = err instanceof Error ? err.message : String(err);
8941
10399
  return { handled: true, output: pc6.red(`Failed to plan issue #${issueNum}: ${msg}`) };
@@ -11150,7 +12608,7 @@ var Inbox = class {
11150
12608
  // package.json
11151
12609
  var package_default = {
11152
12610
  name: "@aman_asmuei/aman-agent",
11153
- version: "0.40.0",
12611
+ version: "0.42.0",
11154
12612
  description: "Your AI companion, running locally \u2014 powered by the aman ecosystem",
11155
12613
  type: "module",
11156
12614
  engines: {
@@ -11173,10 +12631,10 @@ var package_default = {
11173
12631
  prepublishOnly: "npm run build"
11174
12632
  },
11175
12633
  dependencies: {
11176
- "@aman_asmuei/aman-core": "^0.3.0",
11177
12634
  "@aman_asmuei/acore-core": "^0.2.0",
12635
+ "@aman_asmuei/aman-core": "^0.3.0",
12636
+ "@aman_asmuei/amem-core": "^0.6.0",
11178
12637
  "@aman_asmuei/arules-core": "^0.2.0",
11179
- "@aman_asmuei/amem-core": "^0.5.0",
11180
12638
  "@anthropic-ai/sdk": "^0.39.0",
11181
12639
  "@clack/prompts": "^0.9.1",
11182
12640
  "@modelcontextprotocol/sdk": "^1.27.1",
@@ -11517,7 +12975,7 @@ function bootstrapEcosystem() {
11517
12975
  return true;
11518
12976
  }
11519
12977
  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) => {
12978
+ program.name("aman-agent").description("Your AI companion, running locally").version("0.42.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
12979
  p4.intro(pc9.bold("aman agent") + pc9.dim(" \u2014 your AI companion"));
11522
12980
  let config = loadConfig();
11523
12981
  if (!config) {
@@ -11791,6 +13249,22 @@ program.name("aman-agent").description("Your AI companion, running locally").ver
11791
13249
  } catch (err) {
11792
13250
  p4.log.warning(`Memory initialization failed: ${err instanceof Error ? err.message : String(err)}`);
11793
13251
  }
13252
+ if (isMemoryInitialized()) {
13253
+ const mirrorSpinner = p4.spinner();
13254
+ mirrorSpinner.start("Checking mirror dir for updates");
13255
+ try {
13256
+ const syncResult = await startupAutoSync();
13257
+ mirrorSpinner.stop(
13258
+ syncResult && syncResult.imported > 0 ? `[mirror] synced ${syncResult.imported} new` : ""
13259
+ );
13260
+ } catch (err) {
13261
+ mirrorSpinner.stop(
13262
+ pc9.dim(
13263
+ `[mirror] auto-sync skipped: ${err instanceof Error ? err.message : String(err)}`
13264
+ )
13265
+ );
13266
+ }
13267
+ }
11794
13268
  if (isMemoryInitialized()) {
11795
13269
  const memSpinner = p4.spinner();
11796
13270
  memSpinner.start("Consolidating memory");