@wrongstack/core 0.5.5 → 0.5.6
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/coordination/index.d.ts +2 -1
- package/dist/coordination/index.js +269 -15
- package/dist/coordination/index.js.map +1 -1
- package/dist/defaults/index.d.ts +3 -2
- package/dist/defaults/index.js +409 -15
- package/dist/defaults/index.js.map +1 -1
- package/dist/director-state-BmYi3DGA.d.ts +108 -0
- package/dist/{index-De4R4rQ7.d.ts → index-BDnUCRvL.d.ts} +108 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +414 -18
- package/dist/index.js.map +1 -1
- package/dist/{director-state-BUxlqkOa.d.ts → plan-templates-DaxTCPfk.d.ts} +33 -72
- package/dist/storage/index.d.ts +2 -1
- package/dist/storage/index.js +206 -2
- package/dist/storage/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12,6 +12,13 @@ import { Readable } from 'stream';
|
|
|
12
12
|
import { pipeline } from 'stream/promises';
|
|
13
13
|
import { spawn } from 'child_process';
|
|
14
14
|
|
|
15
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
16
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
17
|
+
}) : x)(function(x) {
|
|
18
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
19
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
20
|
+
});
|
|
21
|
+
|
|
15
22
|
// src/types/errors.ts
|
|
16
23
|
var WrongStackError = class extends Error {
|
|
17
24
|
code;
|
|
@@ -5341,9 +5348,149 @@ function matchIndex(plan, idOrIndex) {
|
|
|
5341
5348
|
const lower = idOrIndex.toLowerCase();
|
|
5342
5349
|
return plan.items.findIndex((it) => it.title.toLowerCase().includes(lower));
|
|
5343
5350
|
}
|
|
5351
|
+
function deriveTodosFromPlanItem(plan, idOrIndex, subtasks) {
|
|
5352
|
+
const idx = matchIndex(plan, idOrIndex);
|
|
5353
|
+
if (idx === -1) return null;
|
|
5354
|
+
const item = plan.items[idx];
|
|
5355
|
+
if (!item) return null;
|
|
5356
|
+
let updatedPlan = plan;
|
|
5357
|
+
if (item.status !== "done") {
|
|
5358
|
+
updatedPlan = setPlanItemStatus(plan, idOrIndex, "in_progress");
|
|
5359
|
+
}
|
|
5360
|
+
const todos = [];
|
|
5361
|
+
todos.push({
|
|
5362
|
+
id: `todo_${Date.now()}_plan`,
|
|
5363
|
+
content: item.title,
|
|
5364
|
+
status: "in_progress",
|
|
5365
|
+
activeForm: item.title
|
|
5366
|
+
});
|
|
5367
|
+
if (subtasks && subtasks.length > 0) {
|
|
5368
|
+
for (const st of subtasks) {
|
|
5369
|
+
todos.push({
|
|
5370
|
+
id: `todo_${Date.now()}_${randomUUID().slice(0, 6)}`,
|
|
5371
|
+
content: st,
|
|
5372
|
+
status: "pending"
|
|
5373
|
+
});
|
|
5374
|
+
}
|
|
5375
|
+
}
|
|
5376
|
+
return { plan: updatedPlan, todos };
|
|
5377
|
+
}
|
|
5344
5378
|
function attachPlanCheckpoint(_state, _filePath, _sessionId) {
|
|
5345
5379
|
return () => void 0;
|
|
5346
5380
|
}
|
|
5381
|
+
|
|
5382
|
+
// src/storage/plan-templates.ts
|
|
5383
|
+
var templates = {
|
|
5384
|
+
"new-feature": {
|
|
5385
|
+
name: "new-feature",
|
|
5386
|
+
description: "Standard workflow for adding a new feature",
|
|
5387
|
+
category: "development",
|
|
5388
|
+
items: [
|
|
5389
|
+
{ title: "Write specification / design doc", details: "Define scope, acceptance criteria, edge cases" },
|
|
5390
|
+
{ title: "Set up feature branch", details: "git checkout -b feature/..." },
|
|
5391
|
+
{ title: "Implement core logic", details: "TDD preferred \u2014 write tests first" },
|
|
5392
|
+
{ title: "Add unit tests", details: ">= 80% coverage for new code" },
|
|
5393
|
+
{ title: "Add integration tests", details: "End-to-end happy path + error paths" },
|
|
5394
|
+
{ title: "Update documentation", details: "README, API docs, changelog" },
|
|
5395
|
+
{ title: "Code review", details: "Self-review before requesting review" },
|
|
5396
|
+
{ title: "Merge and deploy", details: "CI green, tag release" }
|
|
5397
|
+
]
|
|
5398
|
+
},
|
|
5399
|
+
"bug-fix": {
|
|
5400
|
+
name: "bug-fix",
|
|
5401
|
+
description: "Systematic approach to fixing bugs",
|
|
5402
|
+
category: "maintenance",
|
|
5403
|
+
items: [
|
|
5404
|
+
{ title: "Reproduce the bug", details: "Minimal reproduction case" },
|
|
5405
|
+
{ title: "Root cause analysis", details: "Trace through logs, debugger" },
|
|
5406
|
+
{ title: "Write failing test", details: "Test must fail before fix" },
|
|
5407
|
+
{ title: "Implement fix", details: "Smallest possible change" },
|
|
5408
|
+
{ title: "Verify fix", details: "Test passes, reproduction no longer fails" },
|
|
5409
|
+
{ title: "Regression test", details: "Ensure no related tests broken" },
|
|
5410
|
+
{ title: "Document in changelog", details: "Brief description + issue link" }
|
|
5411
|
+
]
|
|
5412
|
+
},
|
|
5413
|
+
"refactor": {
|
|
5414
|
+
name: "refactor",
|
|
5415
|
+
description: "Safe refactoring workflow",
|
|
5416
|
+
category: "maintenance",
|
|
5417
|
+
items: [
|
|
5418
|
+
{ title: "Identify refactoring target", details: "Code smell, performance bottleneck, or tech debt" },
|
|
5419
|
+
{ title: "Ensure test coverage", details: "Existing tests must pass before and after" },
|
|
5420
|
+
{ title: "Write characterization tests", details: "Capture current behavior if tests weak" },
|
|
5421
|
+
{ title: "Apply refactoring", details: "Small steps, frequent commits" },
|
|
5422
|
+
{ title: "Run full test suite", details: "All tests must pass" },
|
|
5423
|
+
{ title: "Performance check", details: "Ensure no regression" },
|
|
5424
|
+
{ title: "Code review", details: "Explain the why, not just the what" }
|
|
5425
|
+
]
|
|
5426
|
+
},
|
|
5427
|
+
"release": {
|
|
5428
|
+
name: "release",
|
|
5429
|
+
description: "Preparing a new release",
|
|
5430
|
+
category: "release",
|
|
5431
|
+
items: [
|
|
5432
|
+
{ title: "Version bump", details: "package.json, lockfiles, tags" },
|
|
5433
|
+
{ title: "Update changelog", details: "All changes since last release" },
|
|
5434
|
+
{ title: "Run full test suite", details: "Unit + integration + e2e" },
|
|
5435
|
+
{ title: "Build artifacts", details: "Docker images, bundles, binaries" },
|
|
5436
|
+
{ title: "Staging smoke tests", details: "Deploy to staging, verify" },
|
|
5437
|
+
{ title: "Production deploy", details: "Blue-green or canary" },
|
|
5438
|
+
{ title: "Post-deploy verification", details: "Health checks, error rates" },
|
|
5439
|
+
{ title: "Announce release", details: "Slack, email, GitHub release notes" }
|
|
5440
|
+
]
|
|
5441
|
+
},
|
|
5442
|
+
"security-audit": {
|
|
5443
|
+
name: "security-audit",
|
|
5444
|
+
description: "Security review and hardening",
|
|
5445
|
+
category: "infrastructure",
|
|
5446
|
+
items: [
|
|
5447
|
+
{ title: "Dependency audit", details: "npm audit, Snyk, Dependabot alerts" },
|
|
5448
|
+
{ title: "Secret scan", details: "git-secrets, truffleHog, manual review" },
|
|
5449
|
+
{ title: "Access control review", details: "IAM, roles, least privilege" },
|
|
5450
|
+
{ title: "Input validation audit", details: "SQL injection, XSS, path traversal" },
|
|
5451
|
+
{ title: "Authentication review", details: "Session management, MFA, password policy" },
|
|
5452
|
+
{ title: "Logging and monitoring", details: "PII in logs, audit trails" },
|
|
5453
|
+
{ title: "Incident response plan", details: "Runbooks, contacts, escalation" }
|
|
5454
|
+
]
|
|
5455
|
+
},
|
|
5456
|
+
"onboarding": {
|
|
5457
|
+
name: "onboarding",
|
|
5458
|
+
description: "New developer onboarding checklist",
|
|
5459
|
+
category: "infrastructure",
|
|
5460
|
+
items: [
|
|
5461
|
+
{ title: "Repository access", details: "GitHub/GitLab permissions" },
|
|
5462
|
+
{ title: "Local environment setup", details: "Docker, dependencies, env files" },
|
|
5463
|
+
{ title: "Run tests locally", details: "Verify green suite" },
|
|
5464
|
+
{ title: "Read architecture docs", details: "ADR, README, onboarding guide" },
|
|
5465
|
+
{ title: "First commit", details: "Docs fix or small improvement" },
|
|
5466
|
+
{ title: "Pair programming session", details: "Walk through codebase with buddy" },
|
|
5467
|
+
{ title: "Deploy to staging", details: "Verify CI/CD access" }
|
|
5468
|
+
]
|
|
5469
|
+
}
|
|
5470
|
+
};
|
|
5471
|
+
function listPlanTemplates() {
|
|
5472
|
+
return Object.values(templates);
|
|
5473
|
+
}
|
|
5474
|
+
function getPlanTemplate(name) {
|
|
5475
|
+
return templates[name];
|
|
5476
|
+
}
|
|
5477
|
+
function formatPlanTemplates() {
|
|
5478
|
+
const cats = /* @__PURE__ */ new Map();
|
|
5479
|
+
for (const t2 of Object.values(templates)) {
|
|
5480
|
+
const arr = cats.get(t2.category) ?? [];
|
|
5481
|
+
arr.push(t2);
|
|
5482
|
+
cats.set(t2.category, arr);
|
|
5483
|
+
}
|
|
5484
|
+
const lines = ["Available plan templates:"];
|
|
5485
|
+
for (const [cat, items] of cats) {
|
|
5486
|
+
lines.push(`
|
|
5487
|
+
${cat}:`);
|
|
5488
|
+
for (const t2 of items) {
|
|
5489
|
+
lines.push(` ${t2.name.padEnd(18)} \u2014 ${t2.description}`);
|
|
5490
|
+
}
|
|
5491
|
+
}
|
|
5492
|
+
return lines.join("\n");
|
|
5493
|
+
}
|
|
5347
5494
|
async function loadDirectorState(filePath) {
|
|
5348
5495
|
let raw;
|
|
5349
5496
|
try {
|
|
@@ -5359,15 +5506,48 @@ async function loadDirectorState(filePath) {
|
|
|
5359
5506
|
return null;
|
|
5360
5507
|
}
|
|
5361
5508
|
}
|
|
5509
|
+
async function acquireDirectorStateLock(lockPath, processId = process.pid) {
|
|
5510
|
+
let existing;
|
|
5511
|
+
try {
|
|
5512
|
+
existing = await fsp2.readFile(lockPath, "utf8");
|
|
5513
|
+
} catch {
|
|
5514
|
+
}
|
|
5515
|
+
if (existing) {
|
|
5516
|
+
try {
|
|
5517
|
+
const lock2 = JSON.parse(existing);
|
|
5518
|
+
try {
|
|
5519
|
+
process.kill(lock2.pid, 0);
|
|
5520
|
+
return false;
|
|
5521
|
+
} catch {
|
|
5522
|
+
}
|
|
5523
|
+
} catch {
|
|
5524
|
+
}
|
|
5525
|
+
}
|
|
5526
|
+
const lock = {
|
|
5527
|
+
pid: processId,
|
|
5528
|
+
hostname: __require("os").hostname(),
|
|
5529
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5530
|
+
};
|
|
5531
|
+
await atomicWrite(lockPath, JSON.stringify(lock), { mode: 384 });
|
|
5532
|
+
return true;
|
|
5533
|
+
}
|
|
5534
|
+
async function releaseDirectorStateLock(lockPath) {
|
|
5535
|
+
try {
|
|
5536
|
+
await fsp2.unlink(lockPath);
|
|
5537
|
+
} catch {
|
|
5538
|
+
}
|
|
5539
|
+
}
|
|
5362
5540
|
var DirectorStateCheckpoint = class {
|
|
5363
5541
|
snapshot;
|
|
5364
5542
|
filePath;
|
|
5543
|
+
lockPath;
|
|
5365
5544
|
timer = null;
|
|
5366
5545
|
debounceMs;
|
|
5367
5546
|
writing = false;
|
|
5368
5547
|
rewriteRequested = false;
|
|
5369
5548
|
constructor(filePath, init, debounceMs = 250) {
|
|
5370
5549
|
this.filePath = filePath;
|
|
5550
|
+
this.lockPath = `${filePath}.lock`;
|
|
5371
5551
|
this.debounceMs = debounceMs;
|
|
5372
5552
|
this.snapshot = {
|
|
5373
5553
|
version: 1,
|
|
@@ -5377,10 +5557,36 @@ var DirectorStateCheckpoint = class {
|
|
|
5377
5557
|
maxSpawns: init.maxSpawns,
|
|
5378
5558
|
spawnDepth: init.spawnDepth,
|
|
5379
5559
|
maxSpawnDepth: init.maxSpawnDepth,
|
|
5560
|
+
directorBudget: init.directorBudget,
|
|
5380
5561
|
subagents: [],
|
|
5381
5562
|
tasks: []
|
|
5382
5563
|
};
|
|
5383
5564
|
}
|
|
5565
|
+
/**
|
|
5566
|
+
* Attempt to acquire the lock for this checkpoint. Call this before
|
|
5567
|
+
* resuming a crashed director run. If it returns false, another
|
|
5568
|
+
* director process is still running this fleet — do not resume.
|
|
5569
|
+
*/
|
|
5570
|
+
async acquireLock() {
|
|
5571
|
+
return acquireDirectorStateLock(this.lockPath);
|
|
5572
|
+
}
|
|
5573
|
+
/**
|
|
5574
|
+
* Release the lock on graceful shutdown. Call `flush()` first to ensure
|
|
5575
|
+
* the final checkpoint state is on disk before removing the lock.
|
|
5576
|
+
* Without this, the next resume will see a stale-lock and refuse.
|
|
5577
|
+
*/
|
|
5578
|
+
async releaseLock() {
|
|
5579
|
+
return releaseDirectorStateLock(this.lockPath);
|
|
5580
|
+
}
|
|
5581
|
+
/**
|
|
5582
|
+
* Resume from a snapshot previously loaded via `loadDirectorState()`.
|
|
5583
|
+
* Use this when `--resume <runId>` is triggered — the snapshot has
|
|
5584
|
+
* the full fleet state (subagents, tasks) from before the crash; the
|
|
5585
|
+
* checkpoint continues from there.
|
|
5586
|
+
*/
|
|
5587
|
+
resume(snapshot) {
|
|
5588
|
+
this.snapshot = snapshot;
|
|
5589
|
+
}
|
|
5384
5590
|
current() {
|
|
5385
5591
|
return this.snapshot;
|
|
5386
5592
|
}
|
|
@@ -8115,6 +8321,9 @@ function makeSpawnTool(director, roster) {
|
|
|
8115
8321
|
if (err instanceof DirectorBudgetError) {
|
|
8116
8322
|
return { error: err.message, kind: err.kind, limit: err.limit, observed: err.observed };
|
|
8117
8323
|
}
|
|
8324
|
+
if (err instanceof DirectorCostCapError) {
|
|
8325
|
+
return { error: err.message, kind: err.kind, limit: err.limit, observed: err.observed };
|
|
8326
|
+
}
|
|
8118
8327
|
return { error: err instanceof Error ? err.message : String(err) };
|
|
8119
8328
|
}
|
|
8120
8329
|
}
|
|
@@ -8252,6 +8461,65 @@ function makeFleetUsageTool(director) {
|
|
|
8252
8461
|
}
|
|
8253
8462
|
};
|
|
8254
8463
|
}
|
|
8464
|
+
function makeFleetSessionTool(director) {
|
|
8465
|
+
return {
|
|
8466
|
+
name: "fleet_session",
|
|
8467
|
+
description: "Read a subagent's JSONL transcript and extract its last assistant text, stop reason, and tool-use count. Use this to see what a running or timed-out subagent actually produced.",
|
|
8468
|
+
permission: "auto",
|
|
8469
|
+
mutating: false,
|
|
8470
|
+
inputSchema: {
|
|
8471
|
+
type: "object",
|
|
8472
|
+
properties: {
|
|
8473
|
+
subagentId: { type: "string", description: "Subagent id to read the transcript of." },
|
|
8474
|
+
/** Number of trailing lines to return (last N JSONL lines). Default: all. */
|
|
8475
|
+
tail: { type: "number", description: "Number of trailing JSONL lines to return. Omit for the full transcript." }
|
|
8476
|
+
},
|
|
8477
|
+
required: ["subagentId"]
|
|
8478
|
+
},
|
|
8479
|
+
async execute(input) {
|
|
8480
|
+
const i = input;
|
|
8481
|
+
const result = await director.readSession(i.subagentId, i.tail);
|
|
8482
|
+
if (!result) {
|
|
8483
|
+
return {
|
|
8484
|
+
error: `fleet_session: transcript unavailable for "${i.subagentId}". Is sessionsRoot configured?`
|
|
8485
|
+
};
|
|
8486
|
+
}
|
|
8487
|
+
return result;
|
|
8488
|
+
}
|
|
8489
|
+
};
|
|
8490
|
+
}
|
|
8491
|
+
function makeFleetHealthTool(director) {
|
|
8492
|
+
return {
|
|
8493
|
+
name: "fleet_health",
|
|
8494
|
+
description: "Per-subagent health report: budget pressure (pct of limits consumed), last activity timestamp, and current status. Use to decide whether to assign more work to a subagent or spawn a fresh one.",
|
|
8495
|
+
permission: "auto",
|
|
8496
|
+
mutating: false,
|
|
8497
|
+
inputSchema: { type: "object", properties: {}, required: [] },
|
|
8498
|
+
async execute() {
|
|
8499
|
+
const status = director.status();
|
|
8500
|
+
const snapshot = director.snapshot();
|
|
8501
|
+
const subagents = status.subagents ?? [];
|
|
8502
|
+
const perSubagent = snapshot.perSubagent ?? {};
|
|
8503
|
+
return {
|
|
8504
|
+
subagents: subagents.map((s) => {
|
|
8505
|
+
const usage = perSubagent[s.id];
|
|
8506
|
+
return {
|
|
8507
|
+
id: s.id,
|
|
8508
|
+
status: s.status,
|
|
8509
|
+
lastEventAt: usage?.lastEventAt,
|
|
8510
|
+
// Budget pressure: fraction of each limit consumed if we have it.
|
|
8511
|
+
// BudgetWarning events carry used/limit ratios; surface them here.
|
|
8512
|
+
budgetPressure: {
|
|
8513
|
+
iterations: usage?.iterations,
|
|
8514
|
+
toolCalls: usage?.toolCalls,
|
|
8515
|
+
costUsd: usage?.cost
|
|
8516
|
+
}
|
|
8517
|
+
};
|
|
8518
|
+
})
|
|
8519
|
+
};
|
|
8520
|
+
}
|
|
8521
|
+
};
|
|
8522
|
+
}
|
|
8255
8523
|
|
|
8256
8524
|
// src/coordination/director.ts
|
|
8257
8525
|
var DirectorBudgetError = class extends Error {
|
|
@@ -8268,6 +8536,20 @@ var DirectorBudgetError = class extends Error {
|
|
|
8268
8536
|
this.observed = observed;
|
|
8269
8537
|
}
|
|
8270
8538
|
};
|
|
8539
|
+
var DirectorCostCapError = class extends Error {
|
|
8540
|
+
kind;
|
|
8541
|
+
limit;
|
|
8542
|
+
observed;
|
|
8543
|
+
constructor(limit, observed) {
|
|
8544
|
+
super(
|
|
8545
|
+
`Director cost cap exceeded: total fleet spend ${observed.toFixed(4)} exceeds maxCostUsd ${limit.toFixed(4)}`
|
|
8546
|
+
);
|
|
8547
|
+
this.name = "DirectorCostCapError";
|
|
8548
|
+
this.kind = "max_cost_usd";
|
|
8549
|
+
this.limit = limit;
|
|
8550
|
+
this.observed = observed;
|
|
8551
|
+
}
|
|
8552
|
+
};
|
|
8271
8553
|
var Director = class {
|
|
8272
8554
|
id;
|
|
8273
8555
|
fleet;
|
|
@@ -8322,6 +8604,14 @@ var Director = class {
|
|
|
8322
8604
|
/** Debounce timer for periodic manifest writes. */
|
|
8323
8605
|
manifestTimer = null;
|
|
8324
8606
|
manifestDebounceMs;
|
|
8607
|
+
/** Fleet-wide cost cap. Infinity means no cap. */
|
|
8608
|
+
maxCostUsd;
|
|
8609
|
+
/** Max auto-extensions per subagent per budget kind before denying. */
|
|
8610
|
+
maxBudgetExtensions;
|
|
8611
|
+
/** Sessions root for direct subagent JSONL reads (fleet_session tool). */
|
|
8612
|
+
sessionsRoot;
|
|
8613
|
+
/** Director run id for JSONL path resolution. */
|
|
8614
|
+
directorRunId;
|
|
8325
8615
|
/** Resolves task descriptions back from `assign()` so completion events
|
|
8326
8616
|
* can also carry a human-readable title. */
|
|
8327
8617
|
taskDescriptions = /* @__PURE__ */ new Map();
|
|
@@ -8348,12 +8638,17 @@ var Director = class {
|
|
|
8348
8638
|
this.spawnDepth = opts.spawnDepth ?? 0;
|
|
8349
8639
|
this.sessionWriter = opts.sessionWriter ?? null;
|
|
8350
8640
|
this.manifestDebounceMs = opts.manifestDebounceMs ?? 2e3;
|
|
8641
|
+
this.maxCostUsd = opts.directorBudget?.maxCostUsd ?? Number.POSITIVE_INFINITY;
|
|
8642
|
+
this.maxBudgetExtensions = opts.maxBudgetExtensions ?? 2;
|
|
8643
|
+
this.sessionsRoot = opts.sessionsRoot;
|
|
8644
|
+
this.directorRunId = opts.directorRunId ?? this.id;
|
|
8351
8645
|
this.stateCheckpoint = opts.stateCheckpointPath ? new DirectorStateCheckpoint(opts.stateCheckpointPath, {
|
|
8352
8646
|
directorRunId: this.id,
|
|
8353
8647
|
maxSpawns: opts.maxSpawns,
|
|
8354
8648
|
spawnDepth: this.spawnDepth,
|
|
8355
|
-
maxSpawnDepth: this.maxSpawnDepth
|
|
8356
|
-
|
|
8649
|
+
maxSpawnDepth: this.maxSpawnDepth,
|
|
8650
|
+
directorBudget: opts.directorBudget
|
|
8651
|
+
}, opts.checkpointDebounceMs ?? 250) : null;
|
|
8357
8652
|
if (this.sharedScratchpadPath) {
|
|
8358
8653
|
void fsp2.mkdir(this.sharedScratchpadPath, { recursive: true }).catch(() => void 0);
|
|
8359
8654
|
}
|
|
@@ -8414,7 +8709,7 @@ var Director = class {
|
|
|
8414
8709
|
const payload = e.payload;
|
|
8415
8710
|
const guardKey = `${e.subagentId}:${payload.kind}`;
|
|
8416
8711
|
const prior = extendCounts.get(guardKey) ?? 0;
|
|
8417
|
-
if (prior >=
|
|
8712
|
+
if (prior >= this.maxBudgetExtensions) {
|
|
8418
8713
|
payload.deny();
|
|
8419
8714
|
extendCounts.delete(guardKey);
|
|
8420
8715
|
return;
|
|
@@ -8475,6 +8770,12 @@ var Director = class {
|
|
|
8475
8770
|
if (this.spawnCount >= this.maxSpawns) {
|
|
8476
8771
|
throw new DirectorBudgetError("max_spawns", this.maxSpawns, this.spawnCount + 1);
|
|
8477
8772
|
}
|
|
8773
|
+
if (this.maxCostUsd < Number.POSITIVE_INFINITY) {
|
|
8774
|
+
const totalCost = this.usage.snapshot().total?.cost ?? 0;
|
|
8775
|
+
if (totalCost >= this.maxCostUsd) {
|
|
8776
|
+
throw new DirectorCostCapError(this.maxCostUsd, totalCost);
|
|
8777
|
+
}
|
|
8778
|
+
}
|
|
8478
8779
|
const result = await this.coordinator.spawn(config);
|
|
8479
8780
|
this.spawnCount += 1;
|
|
8480
8781
|
this.subagentMeta.set(result.subagentId, {
|
|
@@ -8654,6 +8955,7 @@ var Director = class {
|
|
|
8654
8955
|
if (this.stateCheckpoint) {
|
|
8655
8956
|
this.stateCheckpoint.setUsage(this.usage.snapshot());
|
|
8656
8957
|
await this.stateCheckpoint.flush().catch((err) => this.logShutdownError("state_checkpoint_flush", err));
|
|
8958
|
+
await this.stateCheckpoint.releaseLock().catch((err) => this.logShutdownError("state_checkpoint_lock_release", err));
|
|
8657
8959
|
}
|
|
8658
8960
|
}
|
|
8659
8961
|
/**
|
|
@@ -8757,6 +9059,58 @@ var Director = class {
|
|
|
8757
9059
|
completedResults() {
|
|
8758
9060
|
return Array.from(this.completed.values());
|
|
8759
9061
|
}
|
|
9062
|
+
/**
|
|
9063
|
+
* Inject a previously-saved checkpoint snapshot. Call this right after
|
|
9064
|
+
* constructing a Director during a `--resume` run so the in-memory state
|
|
9065
|
+
* (subagents, tasks, waiters) reflects the pre-crash reality instead of
|
|
9066
|
+
* starting from a blank slate. The director then resumes from there —
|
|
9067
|
+
* completing any in-flight tasks and ignoring tasks that already reached
|
|
9068
|
+
* a terminal state in the prior run.
|
|
9069
|
+
*/
|
|
9070
|
+
setCheckpointState(snapshot) {
|
|
9071
|
+
this.stateCheckpoint?.resume(snapshot);
|
|
9072
|
+
}
|
|
9073
|
+
/**
|
|
9074
|
+
* Read a subagent's JSONL transcript directly from disk (no bridge
|
|
9075
|
+
* round-trip needed). Returns the last assistant text, stop reason,
|
|
9076
|
+
* tool-use count, and line count — or null if the file is unavailable.
|
|
9077
|
+
* Requires `sessionsRoot` to be set on construction.
|
|
9078
|
+
*/
|
|
9079
|
+
async readSession(subagentId, tail) {
|
|
9080
|
+
if (!this.sessionsRoot) return null;
|
|
9081
|
+
const filePath = path6.join(this.sessionsRoot, this.directorRunId, `${subagentId}.jsonl`);
|
|
9082
|
+
let raw;
|
|
9083
|
+
try {
|
|
9084
|
+
raw = await fsp2.readFile(filePath, "utf8");
|
|
9085
|
+
} catch {
|
|
9086
|
+
return null;
|
|
9087
|
+
}
|
|
9088
|
+
const lines = raw.split("\n").filter((l) => l.trim());
|
|
9089
|
+
const targetLines = tail ? lines.slice(-tail) : lines;
|
|
9090
|
+
let lastAssistantText;
|
|
9091
|
+
let lastStopReason;
|
|
9092
|
+
let toolUses = 0;
|
|
9093
|
+
for (const line of targetLines) {
|
|
9094
|
+
try {
|
|
9095
|
+
const ev = JSON.parse(line);
|
|
9096
|
+
if (ev.type === "assistant" && typeof ev.text === "string") {
|
|
9097
|
+
lastAssistantText = ev.text;
|
|
9098
|
+
} else if (ev.type === "stop" && ev.stopReason) {
|
|
9099
|
+
lastStopReason = ev.stopReason;
|
|
9100
|
+
} else if (ev.type === "tool_use") {
|
|
9101
|
+
toolUses++;
|
|
9102
|
+
}
|
|
9103
|
+
} catch {
|
|
9104
|
+
}
|
|
9105
|
+
}
|
|
9106
|
+
return {
|
|
9107
|
+
lastAssistantText,
|
|
9108
|
+
lastStopReason,
|
|
9109
|
+
toolUsesObserved: toolUses,
|
|
9110
|
+
events: targetLines.length,
|
|
9111
|
+
path: filePath
|
|
9112
|
+
};
|
|
9113
|
+
}
|
|
8760
9114
|
snapshot() {
|
|
8761
9115
|
return this.usage.snapshot();
|
|
8762
9116
|
}
|
|
@@ -8835,10 +9189,28 @@ var Director = class {
|
|
|
8835
9189
|
makeRollUpTool(this),
|
|
8836
9190
|
makeTerminateTool(this),
|
|
8837
9191
|
makeFleetStatusTool(this),
|
|
8838
|
-
makeFleetUsageTool(this)
|
|
9192
|
+
makeFleetUsageTool(this),
|
|
9193
|
+
makeFleetSessionTool(this),
|
|
9194
|
+
makeFleetHealthTool(this)
|
|
8839
9195
|
];
|
|
8840
9196
|
return t2;
|
|
8841
9197
|
}
|
|
9198
|
+
/**
|
|
9199
|
+
* Attempt to acquire the checkpoint lock. Must be called before
|
|
9200
|
+
* resuming — if another director process is alive, this returns
|
|
9201
|
+
* false and the caller should not proceed with the resume.
|
|
9202
|
+
*/
|
|
9203
|
+
async acquireCheckpointLock() {
|
|
9204
|
+
return this.stateCheckpoint ? this.stateCheckpoint.acquireLock() : true;
|
|
9205
|
+
}
|
|
9206
|
+
/**
|
|
9207
|
+
* Resume from a prior checkpoint snapshot (loaded via
|
|
9208
|
+
* `loadDirectorState()`). Re-attach to the fleet mid-flight so
|
|
9209
|
+
* subsequent spawn/assign calls update the checkpoint normally.
|
|
9210
|
+
*/
|
|
9211
|
+
resumeFromCheckpoint(snapshot) {
|
|
9212
|
+
this.stateCheckpoint?.resume(snapshot);
|
|
9213
|
+
}
|
|
8842
9214
|
};
|
|
8843
9215
|
function createDelegateTool(opts) {
|
|
8844
9216
|
const defaultTimeoutMs = opts.defaultTimeoutMs ?? 4 * 60 * 60 * 1e3;
|
|
@@ -8944,7 +9316,7 @@ function createDelegateTool(opts) {
|
|
|
8944
9316
|
if (typeof i.maxToolCalls === "number" && i.maxToolCalls > 0) {
|
|
8945
9317
|
cfg.maxToolCalls = i.maxToolCalls;
|
|
8946
9318
|
}
|
|
8947
|
-
const SUBAGENT_TIMEOUT_BUFFER_MS = 3e4;
|
|
9319
|
+
const SUBAGENT_TIMEOUT_BUFFER_MS = opts.subagentTimeoutBufferMs ?? 3e4;
|
|
8948
9320
|
const desiredSubTimeout = Math.max(3e4, timeoutMs - SUBAGENT_TIMEOUT_BUFFER_MS);
|
|
8949
9321
|
if (!cfg.timeoutMs || cfg.timeoutMs > desiredSubTimeout) {
|
|
8950
9322
|
cfg.timeoutMs = desiredSubTimeout;
|
|
@@ -8996,7 +9368,7 @@ function createDelegateTool(opts) {
|
|
|
8996
9368
|
toolCalls: result.toolCalls,
|
|
8997
9369
|
durationMs: result.durationMs,
|
|
8998
9370
|
...partial ? { partial } : {},
|
|
8999
|
-
...hintForKind(errorKind, retryable, backoffMs) ? { hint: hintForKind(errorKind, retryable, backoffMs) } : {}
|
|
9371
|
+
...hintForKind(errorKind, retryable, backoffMs, partial) ? { hint: hintForKind(errorKind, retryable, backoffMs, partial) } : {}
|
|
9000
9372
|
};
|
|
9001
9373
|
} catch (err) {
|
|
9002
9374
|
return {
|
|
@@ -9016,7 +9388,7 @@ function instantiateRosterConfig2(role, base) {
|
|
|
9016
9388
|
id: `${role}-${randomUUID().slice(0, 8)}`
|
|
9017
9389
|
};
|
|
9018
9390
|
}
|
|
9019
|
-
function hintForKind(kind, retryable, backoffMs) {
|
|
9391
|
+
function hintForKind(kind, retryable, backoffMs, partial) {
|
|
9020
9392
|
if (!kind) return void 0;
|
|
9021
9393
|
switch (kind) {
|
|
9022
9394
|
case "provider_rate_limit":
|
|
@@ -9032,16 +9404,40 @@ function hintForKind(kind, retryable, backoffMs) {
|
|
|
9032
9404
|
case "budget_iterations":
|
|
9033
9405
|
case "budget_tool_calls":
|
|
9034
9406
|
case "budget_tokens":
|
|
9035
|
-
case "budget_cost":
|
|
9036
|
-
|
|
9037
|
-
|
|
9038
|
-
|
|
9407
|
+
case "budget_cost": {
|
|
9408
|
+
const base = "Subagent exhausted its budget. The coordinator may auto-extend; otherwise raise the matching `max*` field (e.g. maxToolCalls: 600) on the next delegate, or split the task.";
|
|
9409
|
+
if (partial?.lastAssistantText) {
|
|
9410
|
+
return `${base}
|
|
9411
|
+
|
|
9412
|
+
Partial output produced before budget hit:
|
|
9413
|
+
${partial.lastAssistantText}`;
|
|
9414
|
+
}
|
|
9415
|
+
return base;
|
|
9416
|
+
}
|
|
9417
|
+
case "budget_timeout": {
|
|
9418
|
+
const base = "Subagent hit its wall-clock budget. Raise `timeoutMs` on the next delegate or split the task.";
|
|
9419
|
+
if (partial?.lastAssistantText) {
|
|
9420
|
+
return `${base}
|
|
9421
|
+
|
|
9422
|
+
Partial output produced before timeout:
|
|
9423
|
+
${partial.lastAssistantText}`;
|
|
9424
|
+
}
|
|
9425
|
+
return base;
|
|
9426
|
+
}
|
|
9039
9427
|
case "aborted_by_parent":
|
|
9040
9428
|
return "Subagent was aborted (user Ctrl+C, parent unwound, or sibling failure cascade). Not retryable until the abort condition is resolved.";
|
|
9041
9429
|
case "empty_response":
|
|
9042
9430
|
return "Subagent ended its turn with no text and no tool calls. Almost always a prompt / config issue \u2014 clarify the task or check the model.";
|
|
9043
|
-
case "tool_failed":
|
|
9044
|
-
|
|
9431
|
+
case "tool_failed": {
|
|
9432
|
+
const base = "A tool inside the subagent returned ok:false. Retry with corrected inputs.";
|
|
9433
|
+
if (partial?.lastAssistantText) {
|
|
9434
|
+
return `${base}
|
|
9435
|
+
|
|
9436
|
+
Agent reasoning before failure:
|
|
9437
|
+
${partial.lastAssistantText}`;
|
|
9438
|
+
}
|
|
9439
|
+
return base;
|
|
9440
|
+
}
|
|
9045
9441
|
case "bridge_failed":
|
|
9046
9442
|
return "Parent-child bridge transport failed. This is rare \u2014 restart the session and retry.";
|
|
9047
9443
|
default:
|
|
@@ -15084,16 +15480,16 @@ Use \`/security report <number>\` to view a specific report.` };
|
|
|
15084
15480
|
}
|
|
15085
15481
|
const index = parseInt(reportId, 10) - 1;
|
|
15086
15482
|
if (!isNaN(index) && reports[index]) {
|
|
15087
|
-
const { readFile:
|
|
15088
|
-
const content = await
|
|
15483
|
+
const { readFile: readFile28 } = await import('fs/promises');
|
|
15484
|
+
const content = await readFile28(join(reportsDir, reports[index]), "utf-8");
|
|
15089
15485
|
return { message: `# Security Report
|
|
15090
15486
|
|
|
15091
15487
|
${content}` };
|
|
15092
15488
|
}
|
|
15093
15489
|
const match = reports.find((r) => r.includes(reportId));
|
|
15094
15490
|
if (match) {
|
|
15095
|
-
const { readFile:
|
|
15096
|
-
const content = await
|
|
15491
|
+
const { readFile: readFile28 } = await import('fs/promises');
|
|
15492
|
+
const content = await readFile28(join(reportsDir, match), "utf-8");
|
|
15097
15493
|
return { message: `# Security Report
|
|
15098
15494
|
|
|
15099
15495
|
${content}` };
|
|
@@ -17353,6 +17749,6 @@ function wrapApiForCapabilityCheck(plugin, api, log, enforce = false) {
|
|
|
17353
17749
|
});
|
|
17354
17750
|
}
|
|
17355
17751
|
|
|
17356
|
-
export { AISpecBuilder, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, Agent, AgentError, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutonomousRunner, BUG_HUNTER_AGENT, BudgetExceededError, CONTEXT_WINDOW_MODES, ConfigError, ConfigMigrationError, Container, Context, ConversationState, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_CONTEXT_WINDOW_MODE_ID, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_MAX_ITERATIONS, DEFAULT_MODES, DEFAULT_RECOVERY_STRATEGIES, DEFAULT_SPEC_TEMPLATE, DEFAULT_SUBAGENT_BASELINE, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPathResolver, DefaultPermissionPolicy, DefaultPluginAPI, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, DefaultSkillLoader, DefaultSystemPromptBuilder, DefaultTaskStore, DefaultTokenCounter, Director, DirectorBudgetError, DirectorStateCheckpoint, DoneConditionChecker, EventBus, ExtensionRegistry, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FleetBus, FleetUsageAggregator, GitignoreUpdater, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, InMemoryMetricsSink, InputBuilder, IntelligentCompactor, KERNEL_API_VERSION, LAYER_1_IDENTITY, LLMSelector, NoopMetricsSink, NoopTracer, OTelTracer, PROMETHEUS_CONTENT_TYPE, Pipeline, PluginError, ProviderError, ProviderRegistry, QueueStore, REFACTOR_PLANNER_AGENT, RecoveryLock, ReportGenerator, RunController, SECURITY_SCANNER_AGENT, SPEC_TEMPLATES, ScopedEventBus, SecurityScanner, SecurityScannerOrchestrator, SelectiveCompactor, SessionAnalyzer, SessionError, SkillGenerator, SkillInstaller, SkillManifestStore, SlashCommandRegistry, SpecDrivenDev, SpecParser, SpecStore, SpecVersioning, SubagentBudget, TOKENS, TaskFlow, TaskGenerator, TaskGraphStore, TaskTracker, TechStackDetector, ToolError, ToolExecutor, ToolRegistry, WrongStackError, addPlanItem, allServers, analyzeCriticalPath, applyRosterBudget, asBlocks, asText, atomicWrite, attachPlanCheckpoint, attachTodosCheckpoint, awsServer, blockServer, braveSearchServer, buildChildEnv, buildOtlpMetricsRequest, buildOtlpTracesRequest, buildRecoveryStrategies, classifyFamily, clearPlan, color, compileGlob, compileUserRegex, composeDirectorPrompt, composeSubagentPrompt, computeTaskProgress, context7Server, contextManagerTool, createAutoExecutor, createContextManagerTool, createDefaultPipelines, createDelegateTool, createMessage, createSecuritySlashCommand, createToolOutputSerializer, decryptConfigSecrets, defaultGitignoreUpdater, defaultOrchestrator, defaultReportGenerator, defaultSecurityScanner, defaultSkillGenerator, defaultTechStackDetector, detectNewlineStyle, downloadGitHubTarball, emptyPlan, encryptConfigSecrets, ensureDir, estimateRequestTokens, estimateTextTokens, estimateToolDefTokens, estimateToolInputTokens, estimateToolResultTokens, everArtServer, extractRunEnv, filesystemServer, findCriticalPath, formatContextWindowModeList, formatPlan, formatTodosList, getContextWindowMode, getTemplate, githubServer, googleMapsServer, isAgentError, isConfigError, isContextWindowModeId, isImageBlock, isPluginError, isSessionError, isTextBlock, isThinkingBlock, isToolError, isToolResultBlock, isToolUseBlock, isWrongStackError, listContextWindowModes, listTemplates, loadDirectorState, loadPlan, loadPlugins, loadProjectModes, loadTodosCheckpoint, loadUserModes, makeAgentSubagentRunner, makeDirectorSessionFactory, matchAny, matchGlob, migratePlaintextSecrets, miniMaxVisionServer, normalizeToLf, parseSkillRef, projectHash, removePlanItem, renderProgress, renderPrometheus, renderSpecAnalysis, renderTaskGraph, renderTaskList, repairToolUseAdjacency, resolveContextWindowPolicy, resolveWstackPaths, rewriteConfigEncrypted, rosterSummaryFromConfigs, runConfigMigrations, safeParse, safeStringify, sanitizeJsonString, savePlan, saveTodosCheckpoint, securitySlashCommand, sentinelServer, setPlanItemStatus, slackServer, startMetricsServer, startOtlpMetricsExporter, startOtlpTraceExporter, stripAnsi, templateToMarkdown, toStyle, toWrongStackError, topologicalSort, unifiedDiff, unloadPlugins, validateAgainstSchema, wireMetricsToEvents, wrapAsState, zaiVisionServer };
|
|
17752
|
+
export { AISpecBuilder, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, Agent, AgentError, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutonomousRunner, BUG_HUNTER_AGENT, BudgetExceededError, CONTEXT_WINDOW_MODES, ConfigError, ConfigMigrationError, Container, Context, ConversationState, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_CONTEXT_WINDOW_MODE_ID, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_MAX_ITERATIONS, DEFAULT_MODES, DEFAULT_RECOVERY_STRATEGIES, DEFAULT_SPEC_TEMPLATE, DEFAULT_SUBAGENT_BASELINE, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPathResolver, DefaultPermissionPolicy, DefaultPluginAPI, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, DefaultSkillLoader, DefaultSystemPromptBuilder, DefaultTaskStore, DefaultTokenCounter, Director, DirectorBudgetError, DirectorStateCheckpoint, DoneConditionChecker, EventBus, ExtensionRegistry, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FleetBus, FleetUsageAggregator, GitignoreUpdater, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, InMemoryMetricsSink, InputBuilder, IntelligentCompactor, KERNEL_API_VERSION, LAYER_1_IDENTITY, LLMSelector, NoopMetricsSink, NoopTracer, OTelTracer, PROMETHEUS_CONTENT_TYPE, Pipeline, PluginError, ProviderError, ProviderRegistry, QueueStore, REFACTOR_PLANNER_AGENT, RecoveryLock, ReportGenerator, RunController, SECURITY_SCANNER_AGENT, SPEC_TEMPLATES, ScopedEventBus, SecurityScanner, SecurityScannerOrchestrator, SelectiveCompactor, SessionAnalyzer, SessionError, SkillGenerator, SkillInstaller, SkillManifestStore, SlashCommandRegistry, SpecDrivenDev, SpecParser, SpecStore, SpecVersioning, SubagentBudget, TOKENS, TaskFlow, TaskGenerator, TaskGraphStore, TaskTracker, TechStackDetector, ToolError, ToolExecutor, ToolRegistry, WrongStackError, addPlanItem, allServers, analyzeCriticalPath, applyRosterBudget, asBlocks, asText, atomicWrite, attachPlanCheckpoint, attachTodosCheckpoint, awsServer, blockServer, braveSearchServer, buildChildEnv, buildOtlpMetricsRequest, buildOtlpTracesRequest, buildRecoveryStrategies, classifyFamily, clearPlan, color, compileGlob, compileUserRegex, composeDirectorPrompt, composeSubagentPrompt, computeTaskProgress, context7Server, contextManagerTool, createAutoExecutor, createContextManagerTool, createDefaultPipelines, createDelegateTool, createMessage, createSecuritySlashCommand, createToolOutputSerializer, decryptConfigSecrets, defaultGitignoreUpdater, defaultOrchestrator, defaultReportGenerator, defaultSecurityScanner, defaultSkillGenerator, defaultTechStackDetector, deriveTodosFromPlanItem, detectNewlineStyle, downloadGitHubTarball, emptyPlan, encryptConfigSecrets, ensureDir, estimateRequestTokens, estimateTextTokens, estimateToolDefTokens, estimateToolInputTokens, estimateToolResultTokens, everArtServer, extractRunEnv, filesystemServer, findCriticalPath, formatContextWindowModeList, formatPlan, formatPlanTemplates, formatTodosList, getContextWindowMode, getPlanTemplate, getTemplate, githubServer, googleMapsServer, isAgentError, isConfigError, isContextWindowModeId, isImageBlock, isPluginError, isSessionError, isTextBlock, isThinkingBlock, isToolError, isToolResultBlock, isToolUseBlock, isWrongStackError, listContextWindowModes, listPlanTemplates, listTemplates, loadDirectorState, loadPlan, loadPlugins, loadProjectModes, loadTodosCheckpoint, loadUserModes, makeAgentSubagentRunner, makeDirectorSessionFactory, matchAny, matchGlob, migratePlaintextSecrets, miniMaxVisionServer, normalizeToLf, parseSkillRef, projectHash, removePlanItem, renderProgress, renderPrometheus, renderSpecAnalysis, renderTaskGraph, renderTaskList, repairToolUseAdjacency, resolveContextWindowPolicy, resolveWstackPaths, rewriteConfigEncrypted, rosterSummaryFromConfigs, runConfigMigrations, safeParse, safeStringify, sanitizeJsonString, savePlan, saveTodosCheckpoint, securitySlashCommand, sentinelServer, setPlanItemStatus, slackServer, startMetricsServer, startOtlpMetricsExporter, startOtlpTraceExporter, stripAnsi, templateToMarkdown, toStyle, toWrongStackError, topologicalSort, unifiedDiff, unloadPlugins, validateAgainstSchema, wireMetricsToEvents, wrapAsState, zaiVisionServer };
|
|
17357
17753
|
//# sourceMappingURL=index.js.map
|
|
17358
17754
|
//# sourceMappingURL=index.js.map
|