@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/README.md +113 -43
- package/dist/delegate.js +3 -1
- package/dist/delegate.js.map +1 -1
- package/dist/index.js +1515 -41
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
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
|
|
735
|
-
if (nodeIds.has(
|
|
736
|
-
throw new DAGValidationError(`Duplicate 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(
|
|
738
|
+
nodeIds.add(node2.id);
|
|
739
739
|
}
|
|
740
|
-
for (const
|
|
741
|
-
for (const dep of
|
|
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 "${
|
|
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
|
|
768
|
-
inDegree.set(
|
|
769
|
-
adj.set(
|
|
767
|
+
for (const node2 of dag.nodes) {
|
|
768
|
+
inDegree.set(node2.id, 0);
|
|
769
|
+
adj.set(node2.id, []);
|
|
770
770
|
}
|
|
771
|
-
for (const
|
|
772
|
-
for (const dep of
|
|
773
|
-
adj.get(dep).push(
|
|
774
|
-
inDegree.set(
|
|
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
|
-
|
|
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/
|
|
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
|
|
6132
|
-
const depLabel =
|
|
6133
|
-
lines.push(`- **${
|
|
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.
|
|
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:
|
|
8866
|
-
|
|
8867
|
-
|
|
8868
|
-
|
|
8869
|
-
|
|
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
|
|
8878
|
-
const
|
|
8879
|
-
|
|
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
|
|
8935
|
-
const
|
|
8936
|
-
|
|
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
|
-
${
|
|
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.
|
|
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.
|
|
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");
|