@wrongstack/core 0.267.0 → 0.268.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agent-bridge-STJ3JwwK.d.ts → agent-bridge-UhojbpWx.d.ts} +1 -1
- package/dist/{agent-subagent-runner-CzPGP3jA.d.ts → agent-subagent-runner-Bvtf1o9K.d.ts} +7 -7
- package/dist/{brain-Cdg77tVN.d.ts → brain-69wzMKp1.d.ts} +1 -1
- package/dist/{compactor-iMZ84CXq.d.ts → compactor-CBQAJoDc.d.ts} +1 -1
- package/dist/{config-Du3pYYln.d.ts → config-VKfOZ-6X.d.ts} +70 -2
- package/dist/{context-dT5Ueund.d.ts → context-C0U8B9NF.d.ts} +24 -1
- package/dist/coordination/index.d.ts +56 -160
- package/dist/coordination/index.js +333 -63
- package/dist/coordination/index.js.map +1 -1
- package/dist/defaults/index.d.ts +26 -25
- package/dist/defaults/index.js +94 -68
- package/dist/defaults/index.js.map +1 -1
- package/dist/execution/index.d.ts +72 -16
- package/dist/execution/index.js +151 -36
- package/dist/execution/index.js.map +1 -1
- package/dist/execution/prompt-enhancer.d.ts +1 -1
- package/dist/extension/index.d.ts +7 -6
- package/dist/global-mailbox-KByEFFBa.d.ts +663 -0
- package/dist/{goal-preamble-SulMTowG.d.ts → goal-preamble-CrYjmdw4.d.ts} +9 -9
- package/dist/{goal-store-CABDwdFE.d.ts → goal-store-Y_zdLZ3q.d.ts} +1 -1
- package/dist/hq/index.d.ts +195 -0
- package/dist/hq/index.js +1884 -0
- package/dist/hq/index.js.map +1 -0
- package/dist/{index-IEuxQd-E.d.ts → index-BfaS-f_m.d.ts} +2 -2
- package/dist/{index-DtCVWel4.d.ts → index-CtQnmkaS.d.ts} +8 -8
- package/dist/{index-Bms0m4oy.d.ts → index-gCv830d7.d.ts} +5 -5
- package/dist/index.d.ts +46 -42
- package/dist/index.js +2955 -1498
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +6 -6
- package/dist/infrastructure/index.js +45 -18
- package/dist/infrastructure/index.js.map +1 -1
- package/dist/kernel/index.d.ts +10 -9
- package/dist/{pipeline-BfD2k1rT.d.ts → mailbox-types-Ct2hJq0P.d.ts} +1 -244
- package/dist/{mcp-servers-C2cBTxUR.d.ts → mcp-servers-HT3Fi7Bl.d.ts} +10 -4
- package/dist/models/index.d.ts +5 -5
- package/dist/models/index.js +3 -2
- package/dist/models/index.js.map +1 -1
- package/dist/{models-registry-BqGZNJQ-.d.ts → models-registry-Bvcl3Vaa.d.ts} +1 -1
- package/dist/{multi-agent-coordinator-B8R43uPz.d.ts → multi-agent-coordinator-BACjsmkC.d.ts} +1 -1
- package/dist/{null-fleet-bus-CnXa5oTH.d.ts → null-fleet-bus-DA7fvhUg.d.ts} +6 -6
- package/dist/observability/index.d.ts +2 -2
- package/dist/{parallel-eternal-engine-DdNnw9BQ.d.ts → parallel-eternal-engine-Ci71gYu_.d.ts} +9 -15
- package/dist/{path-resolver-COIMLCQL.d.ts → path-resolver-O1IJnmKE.d.ts} +4 -3
- package/dist/{permission-B75JAi3-.d.ts → permission-Bd-57Lbl.d.ts} +1 -1
- package/dist/{permission-policy-DlR9eJAM.d.ts → permission-policy-uNXC6Kge.d.ts} +2 -3
- package/dist/pipeline-BDNvENyV.d.ts +245 -0
- package/dist/{plan-templates-DSIKCXZN.d.ts → plan-templates-EMsalEtN.d.ts} +5 -5
- package/dist/{provider-model-resolve-BNRsNuJx.d.ts → provider-model-resolve-CEb9x886.d.ts} +3 -3
- package/dist/{provider-runner-CX7iIvox.d.ts → provider-runner-DWJbpo70.d.ts} +3 -3
- package/dist/{retry-policy-BilV1ujH.d.ts → retry-policy-C3s_lvdK.d.ts} +1 -1
- package/dist/sdd/index.d.ts +9 -8
- package/dist/sdd/index.js +32 -2
- package/dist/sdd/index.js.map +1 -1
- package/dist/{secret-vault-gkvEZZfE.d.ts → secret-vault-Cgduf5xL.d.ts} +1 -1
- package/dist/security/index.d.ts +5 -5
- package/dist/security/index.js +39 -29
- package/dist/security/index.js.map +1 -1
- package/dist/{selector-Bc7eWtT3.d.ts → selector-47LBnBVk.d.ts} +1 -1
- package/dist/{session-event-bridge-D-araDEz.d.ts → session-event-bridge-Cw7oqmW2.d.ts} +1 -1
- package/dist/{session-reader-D7Dapswh.d.ts → session-reader-DD4v2Obw.d.ts} +1 -1
- package/dist/storage/index.d.ts +14 -12
- package/dist/storage/index.js +63 -36
- package/dist/storage/index.js.map +1 -1
- package/dist/tools/index.d.ts +2 -2
- package/dist/tools/index.js +166 -31
- package/dist/tools/index.js.map +1 -1
- package/dist/types/index.d.ts +20 -19
- package/dist/types/index.js +68 -51
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.d.ts +22 -3
- package/dist/utils/index.js +139 -1
- package/dist/utils/index.js.map +1 -1
- package/package.json +5 -1
|
@@ -3765,7 +3765,27 @@ Working rules:
|
|
|
3765
3765
|
id: "devops",
|
|
3766
3766
|
name: "DevOps",
|
|
3767
3767
|
role: "devops",
|
|
3768
|
-
tools: [
|
|
3768
|
+
tools: [
|
|
3769
|
+
...TOOLS.build,
|
|
3770
|
+
"mcp__ssh__ssh_list_servers",
|
|
3771
|
+
"mcp__ssh__ssh_connection_status",
|
|
3772
|
+
"mcp__ssh__ssh_execute",
|
|
3773
|
+
"mcp__ssh__ssh_execute_sudo",
|
|
3774
|
+
"mcp__ssh__ssh_upload",
|
|
3775
|
+
"mcp__ssh__ssh_download",
|
|
3776
|
+
"mcp__ssh__ssh_sync",
|
|
3777
|
+
"mcp__ssh__ssh_deploy",
|
|
3778
|
+
"mcp__ssh__ssh_health_check",
|
|
3779
|
+
"mcp__ssh__ssh_service_status",
|
|
3780
|
+
"mcp__ssh__ssh_process_manager",
|
|
3781
|
+
"mcp__ssh__ssh_tunnel",
|
|
3782
|
+
"mcp__ssh__ssh_backup_create",
|
|
3783
|
+
"mcp__ssh__ssh_backup_list",
|
|
3784
|
+
"mcp__ssh__ssh_backup_restore",
|
|
3785
|
+
"mcp__ssh__ssh_db_list",
|
|
3786
|
+
"mcp__ssh__ssh_db_query",
|
|
3787
|
+
"mcp__ssh__ssh_profile"
|
|
3788
|
+
],
|
|
3769
3789
|
prompt: `You are the DevOps agent. Your job is CI/CD, containerization, and
|
|
3770
3790
|
deployment configuration: make builds reproducible and deploys safe.
|
|
3771
3791
|
|
|
@@ -3774,6 +3794,7 @@ Scope:
|
|
|
3774
3794
|
- Write Dockerfiles/compose and optimize image size and layer caching
|
|
3775
3795
|
- Configure deployment (env, secrets handling, health checks, rollback)
|
|
3776
3796
|
- Diagnose flaky/broken pipelines
|
|
3797
|
+
- Use optional SSH MCP tools for remote hosts when the 'ssh' MCP server is enabled: list servers, run health checks, inspect services, transfer/deploy files, and open tunnels
|
|
3777
3798
|
|
|
3778
3799
|
Input format you accept:
|
|
3779
3800
|
{ "task": "ci | container | deploy | fix-pipeline", "platform": "github-actions | gitlab | docker | k8s", "target": "<what>" }
|
|
@@ -3788,7 +3809,8 @@ Working rules:
|
|
|
3788
3809
|
- Never hardcode secrets in config; reference the secret store
|
|
3789
3810
|
- Pin versions for reproducible builds; avoid floating :latest
|
|
3790
3811
|
- Every deploy path needs a rollback and a health check
|
|
3791
|
-
- Treat CI/CD changes as high-risk \u2014 explain blast radius before applying
|
|
3812
|
+
- Treat CI/CD changes as high-risk \u2014 explain blast radius before applying
|
|
3813
|
+
- For remote SSH work, start with ssh_list_servers / ssh_connection_status, prefer read-only checks first, and do not run destructive commands without explicit user approval`
|
|
3792
3814
|
},
|
|
3793
3815
|
budget: MEDIUM_BUDGET,
|
|
3794
3816
|
capability: {
|
|
@@ -3805,6 +3827,13 @@ Working rules:
|
|
|
3805
3827
|
"kubernetes",
|
|
3806
3828
|
"k8s",
|
|
3807
3829
|
"deploy",
|
|
3830
|
+
"ssh",
|
|
3831
|
+
"remote ssh",
|
|
3832
|
+
"remote server",
|
|
3833
|
+
"sftp",
|
|
3834
|
+
"tunnel",
|
|
3835
|
+
"bastion",
|
|
3836
|
+
"jump host",
|
|
3808
3837
|
"github actions",
|
|
3809
3838
|
"container"
|
|
3810
3839
|
]
|
|
@@ -6800,6 +6829,7 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
6800
6829
|
subagentId: result.subagentId,
|
|
6801
6830
|
taskId: result.taskId,
|
|
6802
6831
|
status: result.status,
|
|
6832
|
+
result: result.result,
|
|
6803
6833
|
iterations: result.iterations,
|
|
6804
6834
|
toolCalls: result.toolCalls,
|
|
6805
6835
|
durationMs: result.durationMs
|
|
@@ -8904,6 +8934,8 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
8904
8934
|
const cached = this._loadCache.get(id);
|
|
8905
8935
|
if (cached && cached.mtimeMs === stat6.mtimeMs && cached.size === stat6.size) {
|
|
8906
8936
|
cacheHit = true;
|
|
8937
|
+
this._loadCache.delete(id);
|
|
8938
|
+
this._loadCache.set(id, cached);
|
|
8907
8939
|
return cached.data;
|
|
8908
8940
|
}
|
|
8909
8941
|
const raw = await fsp6.readFile(file, "utf8");
|
|
@@ -10400,30 +10432,18 @@ var DefaultMailbox = class {
|
|
|
10400
10432
|
async query(q) {
|
|
10401
10433
|
const all = await this._readAll();
|
|
10402
10434
|
const limit = q.limit ?? 50;
|
|
10403
|
-
|
|
10404
|
-
|
|
10405
|
-
|
|
10406
|
-
|
|
10407
|
-
|
|
10408
|
-
|
|
10409
|
-
|
|
10410
|
-
|
|
10411
|
-
|
|
10412
|
-
|
|
10413
|
-
|
|
10414
|
-
filtered
|
|
10415
|
-
}
|
|
10416
|
-
if (q.type !== void 0) {
|
|
10417
|
-
filtered = filtered.filter((m) => m.type === q.type);
|
|
10418
|
-
}
|
|
10419
|
-
if (q.minPriority !== void 0) {
|
|
10420
|
-
const order = { low: 0, normal: 1, high: 2 };
|
|
10421
|
-
const min = order[q.minPriority];
|
|
10422
|
-
filtered = filtered.filter((m) => (order[m.priority] ?? 1) >= min);
|
|
10423
|
-
}
|
|
10424
|
-
if (q.since !== void 0) {
|
|
10425
|
-
const since = q.since;
|
|
10426
|
-
filtered = filtered.filter((m) => m.timestamp > since);
|
|
10435
|
+
const order = q.minPriority !== void 0 ? { low: 0, normal: 1, high: 2 } : null;
|
|
10436
|
+
const minPriorityRank = order && q.minPriority !== void 0 ? order[q.minPriority] : 0;
|
|
10437
|
+
const filtered = [];
|
|
10438
|
+
for (const msg of all) {
|
|
10439
|
+
if (q.to !== void 0 && msg.to !== q.to && msg.to !== "*") continue;
|
|
10440
|
+
if (q.from !== void 0 && msg.from !== q.from) continue;
|
|
10441
|
+
if (q.unreadBy !== void 0 && q.unreadBy in msg.readBy) continue;
|
|
10442
|
+
if (q.incompleteOnly && msg.completed) continue;
|
|
10443
|
+
if (q.type !== void 0 && msg.type !== q.type) continue;
|
|
10444
|
+
if (order !== null && (order[msg.priority] ?? 1) < minPriorityRank) continue;
|
|
10445
|
+
if (q.since !== void 0 && msg.timestamp <= q.since) continue;
|
|
10446
|
+
filtered.push(msg);
|
|
10427
10447
|
}
|
|
10428
10448
|
filtered.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
|
|
10429
10449
|
return filtered.slice(0, limit);
|
|
@@ -10744,6 +10764,8 @@ var GlobalMailbox = class {
|
|
|
10744
10764
|
clientRegistryPath;
|
|
10745
10765
|
/** Optional event bus for emitting agent registration/heartbeat events. */
|
|
10746
10766
|
_events;
|
|
10767
|
+
/** Optional HQ publisher for cross-project command-center telemetry. */
|
|
10768
|
+
_hqPublisher;
|
|
10747
10769
|
/**
|
|
10748
10770
|
* Local cache of the agent registry to avoid re-reading on every call.
|
|
10749
10771
|
* Time-bounded: the registry file is shared ACROSS PROCESSES (that's the
|
|
@@ -10781,12 +10803,28 @@ var GlobalMailbox = class {
|
|
|
10781
10803
|
/**
|
|
10782
10804
|
* @param projectDir — `~/.wrongstack/projects/<slug>/`
|
|
10783
10805
|
* @param events — optional EventBus for real-time TUI/WebUI notifications
|
|
10806
|
+
* @param hqPublisher — optional HQ publisher for cross-project telemetry
|
|
10784
10807
|
*/
|
|
10785
|
-
constructor(projectDir, events) {
|
|
10808
|
+
constructor(projectDir, events, hqPublisher) {
|
|
10786
10809
|
this.messagePath = path5.join(projectDir, MAILBOX_FILE2);
|
|
10787
10810
|
this.registryPath = path5.join(projectDir, "_mailbox.registry.json");
|
|
10788
10811
|
this.clientRegistryPath = path5.join(projectDir, CLIENT_REGISTRY_FILE);
|
|
10789
10812
|
this._events = events;
|
|
10813
|
+
this._hqPublisher = hqPublisher;
|
|
10814
|
+
}
|
|
10815
|
+
get hqMailboxId() {
|
|
10816
|
+
return `${path5.basename(path5.dirname(this.messagePath))}:mailbox`;
|
|
10817
|
+
}
|
|
10818
|
+
publishHqMailboxEvent(input) {
|
|
10819
|
+
try {
|
|
10820
|
+
this._hqPublisher?.publishMailboxEvent(input);
|
|
10821
|
+
} catch {
|
|
10822
|
+
}
|
|
10823
|
+
}
|
|
10824
|
+
publishHqMailboxSnapshot() {
|
|
10825
|
+
if (this._hqPublisher === void 0) return;
|
|
10826
|
+
void this._hqPublisher.publishMailboxSnapshot(this, { mailboxId: this.hqMailboxId }).catch(() => {
|
|
10827
|
+
});
|
|
10790
10828
|
}
|
|
10791
10829
|
// ── Messages ────────────────────────────────────────────────────────────
|
|
10792
10830
|
async send(input) {
|
|
@@ -10813,6 +10851,8 @@ var GlobalMailbox = class {
|
|
|
10813
10851
|
await fsp6.appendFile(this.messagePath, line, "utf8");
|
|
10814
10852
|
this._pushToCache(msg);
|
|
10815
10853
|
});
|
|
10854
|
+
this.publishHqMailboxEvent({ mailboxId: this.hqMailboxId, action: "message.sent", message: msg });
|
|
10855
|
+
this.publishHqMailboxSnapshot();
|
|
10816
10856
|
return msg;
|
|
10817
10857
|
}
|
|
10818
10858
|
async query(q) {
|
|
@@ -10879,6 +10919,14 @@ var GlobalMailbox = class {
|
|
|
10879
10919
|
cacheSnapshot = all;
|
|
10880
10920
|
});
|
|
10881
10921
|
if (cacheSnapshot) this._setMessageCache(cacheSnapshot);
|
|
10922
|
+
for (const message of updated) {
|
|
10923
|
+
this.publishHqMailboxEvent({
|
|
10924
|
+
mailboxId: this.hqMailboxId,
|
|
10925
|
+
action: message.completed ? "message.completed" : "message.read",
|
|
10926
|
+
message
|
|
10927
|
+
});
|
|
10928
|
+
}
|
|
10929
|
+
if (updated.length > 0) this.publishHqMailboxSnapshot();
|
|
10882
10930
|
return updated;
|
|
10883
10931
|
}
|
|
10884
10932
|
async unreadCount(forAgentId) {
|
|
@@ -10926,6 +10974,25 @@ var GlobalMailbox = class {
|
|
|
10926
10974
|
role: input.role,
|
|
10927
10975
|
source: input.source
|
|
10928
10976
|
});
|
|
10977
|
+
this.publishHqMailboxEvent({
|
|
10978
|
+
mailboxId: this.hqMailboxId,
|
|
10979
|
+
action: "agent.registered",
|
|
10980
|
+
agent: {
|
|
10981
|
+
agentId: input.agentId,
|
|
10982
|
+
name: input.name,
|
|
10983
|
+
...input.role !== void 0 ? { role: input.role } : {},
|
|
10984
|
+
sessionId: input.sessionId,
|
|
10985
|
+
status: "idle",
|
|
10986
|
+
iterations: 0,
|
|
10987
|
+
toolCalls: 0,
|
|
10988
|
+
lastActivityAt: now,
|
|
10989
|
+
lastSeenAt: now,
|
|
10990
|
+
online: true,
|
|
10991
|
+
pid: input.pid,
|
|
10992
|
+
...input.source !== void 0 ? { source: input.source } : {}
|
|
10993
|
+
}
|
|
10994
|
+
});
|
|
10995
|
+
this.publishHqMailboxSnapshot();
|
|
10929
10996
|
}
|
|
10930
10997
|
async heartbeat(input) {
|
|
10931
10998
|
const last = this._lastHeartbeat.get(input.agentId) ?? 0;
|
|
@@ -10956,6 +11023,12 @@ var GlobalMailbox = class {
|
|
|
10956
11023
|
currentTool: input.currentTool,
|
|
10957
11024
|
currentTask: input.currentTask
|
|
10958
11025
|
});
|
|
11026
|
+
this.publishHqMailboxEvent({
|
|
11027
|
+
mailboxId: this.hqMailboxId,
|
|
11028
|
+
action: "agent.heartbeat",
|
|
11029
|
+
summary: input.agentId
|
|
11030
|
+
});
|
|
11031
|
+
this.publishHqMailboxSnapshot();
|
|
10959
11032
|
}
|
|
10960
11033
|
async getAgentStatuses() {
|
|
10961
11034
|
await this._ensureRegistry();
|
|
@@ -11768,13 +11841,13 @@ function makeDependencyWatcherConfig(opts) {
|
|
|
11768
11841
|
const globPatterns = patterns.filter((p) => p.includes("*"));
|
|
11769
11842
|
const plainPatterns = patterns.filter((p) => !p.includes("*"));
|
|
11770
11843
|
function matchesPattern(filePath) {
|
|
11771
|
-
const
|
|
11772
|
-
if (plainPatterns.includes(
|
|
11844
|
+
const basename6 = filePath.split("/").pop()?.split("\\").pop() ?? "";
|
|
11845
|
+
if (plainPatterns.includes(basename6)) return true;
|
|
11773
11846
|
for (const gp of globPatterns) {
|
|
11774
11847
|
const regex = new RegExp(
|
|
11775
11848
|
"^" + gp.replace(/\./g, "\\.").replace(/\*/g, ".*") + "$"
|
|
11776
11849
|
);
|
|
11777
|
-
if (regex.test(
|
|
11850
|
+
if (regex.test(basename6)) return true;
|
|
11778
11851
|
}
|
|
11779
11852
|
return false;
|
|
11780
11853
|
}
|
|
@@ -12750,12 +12823,12 @@ var ConsensusProtocol = class {
|
|
|
12750
12823
|
* Initiate a vote on a proposed change. Updates the change node's status
|
|
12751
12824
|
* to 'proposed' and notifies eligible voters via FleetBus.
|
|
12752
12825
|
*/
|
|
12753
|
-
initiateVote(changeId) {
|
|
12826
|
+
async initiateVote(changeId) {
|
|
12754
12827
|
const change = this.graph.get(changeId);
|
|
12755
12828
|
if (!change || change.type !== "change") {
|
|
12756
12829
|
throw new Error(`ConsensusProtocol: no change found with id "${changeId}"`);
|
|
12757
12830
|
}
|
|
12758
|
-
this.graph.update(changeId, { status: "proposed", votes: [] });
|
|
12831
|
+
await this.graph.update(changeId, { status: "proposed", votes: [] });
|
|
12759
12832
|
const eligible = this._eligibleVoters(change);
|
|
12760
12833
|
this._notifyVoters(change, eligible, "vote_initiated");
|
|
12761
12834
|
}
|
|
@@ -12763,7 +12836,7 @@ var ConsensusProtocol = class {
|
|
|
12763
12836
|
* Cast a vote. Updates the change node in the graph and re-evaluates
|
|
12764
12837
|
* consensus. If the vote triggers a resolution, updates the change status.
|
|
12765
12838
|
*/
|
|
12766
|
-
castVote(changeId, voterId, value, rationale) {
|
|
12839
|
+
async castVote(changeId, voterId, value, rationale) {
|
|
12767
12840
|
const change = this.graph.get(changeId);
|
|
12768
12841
|
if (!change || change.type !== "change") {
|
|
12769
12842
|
throw new Error(`ConsensusProtocol: no change found for "${changeId}"`);
|
|
@@ -12786,7 +12859,7 @@ var ConsensusProtocol = class {
|
|
|
12786
12859
|
const existingIdx = change.votes.findIndex((v) => v.agentId === voterId);
|
|
12787
12860
|
const newVotes = existingIdx >= 0 ? change.votes.with(existingIdx, vote) : [...change.votes, vote];
|
|
12788
12861
|
const result = this._resolve(changeId, newVotes, eligible);
|
|
12789
|
-
this.graph.update(changeId, {
|
|
12862
|
+
await this.graph.update(changeId, {
|
|
12790
12863
|
votes: newVotes,
|
|
12791
12864
|
...result.outcome !== "pending" ? { status: this._toChangeStatus(result.outcome) } : {}
|
|
12792
12865
|
});
|
|
@@ -12797,13 +12870,13 @@ var ConsensusProtocol = class {
|
|
|
12797
12870
|
* Resolve the current vote without waiting for all eligible voters.
|
|
12798
12871
|
* Useful when a timeout fires or an agent decides to finalize early.
|
|
12799
12872
|
*/
|
|
12800
|
-
resolveNow(changeId) {
|
|
12873
|
+
async resolveNow(changeId) {
|
|
12801
12874
|
const change = this.graph.get(changeId);
|
|
12802
12875
|
if (!change) throw new Error(`ConsensusProtocol: unknown change "${changeId}"`);
|
|
12803
12876
|
const eligible = this._eligibleVoters(change);
|
|
12804
12877
|
const result = this._resolve(changeId, change.votes, eligible);
|
|
12805
12878
|
if (result.outcome !== "pending") {
|
|
12806
|
-
this.graph.update(changeId, { status: this._toChangeStatus(result.outcome) });
|
|
12879
|
+
await this.graph.update(changeId, { status: this._toChangeStatus(result.outcome) });
|
|
12807
12880
|
this._notifyVoters(change, eligible, "vote_resolved", { result });
|
|
12808
12881
|
}
|
|
12809
12882
|
return result;
|
|
@@ -13726,7 +13799,8 @@ Priority: ${goal.priority}`,
|
|
|
13726
13799
|
this.agentTaskCount(agentId, -1);
|
|
13727
13800
|
await this.graph.update(taskId, {
|
|
13728
13801
|
status: "done",
|
|
13729
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
13802
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
13803
|
+
..._result !== void 0 ? { result: _result } : {}
|
|
13730
13804
|
});
|
|
13731
13805
|
this.bidRetryCounts.delete(taskId);
|
|
13732
13806
|
this.pendingBids.delete(taskId);
|
|
@@ -13971,7 +14045,7 @@ ${goal.description}`,
|
|
|
13971
14045
|
this.agentTaskCounts.set(agentId, next);
|
|
13972
14046
|
}
|
|
13973
14047
|
};
|
|
13974
|
-
var AutonomousCoordinator = class {
|
|
14048
|
+
var AutonomousCoordinator = class _AutonomousCoordinator {
|
|
13975
14049
|
graph;
|
|
13976
14050
|
dag;
|
|
13977
14051
|
auction;
|
|
@@ -13987,6 +14061,8 @@ var AutonomousCoordinator = class {
|
|
|
13987
14061
|
onCoordinatorEvent;
|
|
13988
14062
|
running = false;
|
|
13989
14063
|
iterationCount = 0;
|
|
14064
|
+
lastSyncAt = 0;
|
|
14065
|
+
static SYNC_INTERVAL_MS = 5e3;
|
|
13990
14066
|
/** Tasks already handled by _onSubagentTerminated (to avoid double goal:failed on fleet event). */
|
|
13991
14067
|
_handledBySubagent = /* @__PURE__ */ new Set();
|
|
13992
14068
|
/** FleetBus subscription disposers, detached in dispose(). */
|
|
@@ -14043,7 +14119,7 @@ var AutonomousCoordinator = class {
|
|
|
14043
14119
|
const taskId = payload?.taskId;
|
|
14044
14120
|
if (!taskId || this._handledBySubagent.has(taskId)) return;
|
|
14045
14121
|
this._handledBySubagent.add(taskId);
|
|
14046
|
-
this.
|
|
14122
|
+
this._recordTaskFailed(taskId, payload?.error ?? "Task failed");
|
|
14047
14123
|
});
|
|
14048
14124
|
if (offFailed) this.unsubs.push(offFailed);
|
|
14049
14125
|
this._emit({ type: "coordinator:mode", mode: this.fleet ? "fleet" : "standalone" });
|
|
@@ -14062,6 +14138,7 @@ var AutonomousCoordinator = class {
|
|
|
14062
14138
|
const maxCost = opts.maxCostUsd;
|
|
14063
14139
|
try {
|
|
14064
14140
|
await this.graph.load();
|
|
14141
|
+
this._rebuildDagFromGraph();
|
|
14065
14142
|
const goalConfigs = await this._decomposeGoal(goal);
|
|
14066
14143
|
for (const g of goalConfigs) {
|
|
14067
14144
|
const goalId = await this.auction.publishTask(g);
|
|
@@ -14069,23 +14146,49 @@ var AutonomousCoordinator = class {
|
|
|
14069
14146
|
this._emit({ type: "goal:added", goalId, title: g.title, text: g.description });
|
|
14070
14147
|
}
|
|
14071
14148
|
while (this.running) {
|
|
14149
|
+
if (this.dag.getRunning().length > 0 && this.auction.getPendingTasks().length === 0) {
|
|
14150
|
+
await this._waitForDagProgress(1e3);
|
|
14151
|
+
continue;
|
|
14152
|
+
}
|
|
14072
14153
|
this.iterationCount++;
|
|
14154
|
+
await this._maybeSyncFromGraph();
|
|
14073
14155
|
if (this.iterationCount >= maxIterations) break;
|
|
14074
14156
|
if (maxCost !== void 0) {
|
|
14075
14157
|
const cost = this.fleetManager?.snapshot()?.total?.cost ?? 0;
|
|
14076
14158
|
if (cost >= maxCost) break;
|
|
14077
14159
|
}
|
|
14078
14160
|
if (opts.runUntilComplete && this.dag.isDone()) break;
|
|
14161
|
+
const pendingTasks = this.auction.getPendingTasks();
|
|
14162
|
+
const dispatchable = pendingTasks.filter((task) => {
|
|
14163
|
+
const dagNode = this.dag.getNode(task.id);
|
|
14164
|
+
return !dagNode || dagNode.status === "ready";
|
|
14165
|
+
});
|
|
14166
|
+
if (dispatchable.length === 0) {
|
|
14167
|
+
if (this.dag.getRunning().length > 0 || this.dag.getReady().length > 0) {
|
|
14168
|
+
await this._waitForDagProgress(1e3);
|
|
14169
|
+
continue;
|
|
14170
|
+
}
|
|
14171
|
+
if (pendingTasks.length > 0) {
|
|
14172
|
+
await this._waitForDagProgress(2e3);
|
|
14173
|
+
continue;
|
|
14174
|
+
}
|
|
14175
|
+
if (this.dag.hasDeadlock()) {
|
|
14176
|
+
const blocked = this.dag.getBlocked();
|
|
14177
|
+
(this.events?.emit)("autonomous:deadlock", { blocked });
|
|
14178
|
+
this._emit({ type: "deadlock:detected", goalId: blocked[0]?.id ?? "", text: `Deadlock detected: ${blocked.map((n) => n.id).join(", ")}` });
|
|
14179
|
+
}
|
|
14180
|
+
break;
|
|
14181
|
+
}
|
|
14079
14182
|
const decision = await this.brain.decideAuto({
|
|
14080
14183
|
id: randomUUID(),
|
|
14081
14184
|
source: "system",
|
|
14082
14185
|
decisionType: "prioritize_goals",
|
|
14083
|
-
question: `What should we work on next? Open goals: ${
|
|
14186
|
+
question: `What should we work on next? Open goals: ${dispatchable.map((g) => g.title).join(", ")}`,
|
|
14084
14187
|
context: {
|
|
14085
|
-
goals:
|
|
14188
|
+
goals: dispatchable,
|
|
14086
14189
|
fleetStatus: this._fleetStatus()
|
|
14087
14190
|
},
|
|
14088
|
-
options: this._goalToOptions(
|
|
14191
|
+
options: this._goalToOptions(dispatchable),
|
|
14089
14192
|
risk: "medium",
|
|
14090
14193
|
requiresConsensus: false
|
|
14091
14194
|
});
|
|
@@ -14132,6 +14235,55 @@ var AutonomousCoordinator = class {
|
|
|
14132
14235
|
this.running = false;
|
|
14133
14236
|
console.error(`[AutonomousCoordinator] stop signal received \u2014 shutting down (iteration ${this.iterationCount})`);
|
|
14134
14237
|
}
|
|
14238
|
+
/**
|
|
14239
|
+
* Report that a terminal worker (not a Director subagent) completed a claimed
|
|
14240
|
+
* task. This updates the auction, DAG, publishes a task-result fact, and
|
|
14241
|
+
* extracts follow-up goals — the same path as subagent completion.
|
|
14242
|
+
*/
|
|
14243
|
+
async reportTaskCompletion(taskId, result) {
|
|
14244
|
+
this._handledBySubagent.add(taskId);
|
|
14245
|
+
await this._completeTask(taskId, result);
|
|
14246
|
+
}
|
|
14247
|
+
/**
|
|
14248
|
+
* Report that a terminal worker failed a claimed task.
|
|
14249
|
+
*/
|
|
14250
|
+
async reportTaskFailure(taskId, error) {
|
|
14251
|
+
this._handledBySubagent.add(taskId);
|
|
14252
|
+
await this._failTask(taskId, error);
|
|
14253
|
+
}
|
|
14254
|
+
/**
|
|
14255
|
+
* Reload the KnowledgeGraph from disk and sync the in-memory DAG with any
|
|
14256
|
+
* changes published by other terminal sessions. New goals are added to the
|
|
14257
|
+
* DAG; existing goals whose status changed (e.g. completed by another
|
|
14258
|
+
* terminal) are transitioned accordingly.
|
|
14259
|
+
*
|
|
14260
|
+
* Safe to call at any time — also used internally by the run loop.
|
|
14261
|
+
*/
|
|
14262
|
+
async syncFromGraph() {
|
|
14263
|
+
await this.graph.load();
|
|
14264
|
+
this._rebuildDagFromGraph();
|
|
14265
|
+
this._syncDagStatuses();
|
|
14266
|
+
}
|
|
14267
|
+
_syncDagStatuses() {
|
|
14268
|
+
const goals = this.graph.getGoals({});
|
|
14269
|
+
for (const goal of goals) {
|
|
14270
|
+
const dagNode = this.dag.getNode(goal.id);
|
|
14271
|
+
if (!dagNode) continue;
|
|
14272
|
+
if (goal.status === "done" && dagNode.status !== "done" && dagNode.status !== "failed") {
|
|
14273
|
+
this.dag.complete(goal.id, goal.result ?? "Completed by another session");
|
|
14274
|
+
} else if (goal.status === "failed" && dagNode.status !== "failed" && dagNode.status !== "done") {
|
|
14275
|
+
this.dag.fail(goal.id, goal.result ?? "Failed by another session");
|
|
14276
|
+
} else if (goal.status === "in_progress" && (dagNode.status === "ready" || dagNode.status === "pending")) {
|
|
14277
|
+
this.dag.start(goal.id, goal.assignee ?? "another-session");
|
|
14278
|
+
}
|
|
14279
|
+
}
|
|
14280
|
+
}
|
|
14281
|
+
async _maybeSyncFromGraph() {
|
|
14282
|
+
const now = Date.now();
|
|
14283
|
+
if (now - this.lastSyncAt < _AutonomousCoordinator.SYNC_INTERVAL_MS) return;
|
|
14284
|
+
this.lastSyncAt = now;
|
|
14285
|
+
await this.syncFromGraph();
|
|
14286
|
+
}
|
|
14135
14287
|
/**
|
|
14136
14288
|
* Tear down the coordinator for good: stop the loop and detach all FleetBus
|
|
14137
14289
|
* subscriptions (this coordinator's + the auctioneer's) plus any open bid
|
|
@@ -14228,6 +14380,65 @@ ${input.detail}`
|
|
|
14228
14380
|
return goal;
|
|
14229
14381
|
}
|
|
14230
14382
|
// ── Private ───────────────────────────────────────────────────────────
|
|
14383
|
+
_waitForDagProgress(timeoutMs) {
|
|
14384
|
+
const before = this._dagProgressKey();
|
|
14385
|
+
if (this.dag.isDone()) return Promise.resolve();
|
|
14386
|
+
return new Promise((resolve3) => {
|
|
14387
|
+
let off;
|
|
14388
|
+
const timer = setTimeout(() => {
|
|
14389
|
+
off?.();
|
|
14390
|
+
resolve3();
|
|
14391
|
+
}, timeoutMs);
|
|
14392
|
+
off = this.dag.onEvent(() => {
|
|
14393
|
+
if (this._dagProgressKey() === before) return;
|
|
14394
|
+
clearTimeout(timer);
|
|
14395
|
+
off?.();
|
|
14396
|
+
resolve3();
|
|
14397
|
+
});
|
|
14398
|
+
});
|
|
14399
|
+
}
|
|
14400
|
+
_dagProgressKey() {
|
|
14401
|
+
const s = this.dag.stats();
|
|
14402
|
+
return `${s.pending}:${s.ready}:${s.running}:${s.done}:${s.failed}:${s.skipped}`;
|
|
14403
|
+
}
|
|
14404
|
+
_rebuildDagFromGraph() {
|
|
14405
|
+
const goals = this.graph.getGoals({});
|
|
14406
|
+
const knownGoalIds = new Set(goals.map((goal) => goal.id));
|
|
14407
|
+
const added = /* @__PURE__ */ new Set();
|
|
14408
|
+
const remaining = new Map(goals.map((goal) => [goal.id, goal]));
|
|
14409
|
+
while (remaining.size > 0) {
|
|
14410
|
+
let progressed = false;
|
|
14411
|
+
for (const [id, goal] of Array.from(remaining.entries())) {
|
|
14412
|
+
const deps = goal.blockedBy.filter((depId) => knownGoalIds.has(depId));
|
|
14413
|
+
if (!deps.every((depId) => added.has(depId))) continue;
|
|
14414
|
+
this._rebuildDagNode(goal, deps);
|
|
14415
|
+
added.add(id);
|
|
14416
|
+
remaining.delete(id);
|
|
14417
|
+
progressed = true;
|
|
14418
|
+
}
|
|
14419
|
+
if (!progressed) {
|
|
14420
|
+
for (const [id, goal] of Array.from(remaining.entries())) {
|
|
14421
|
+
this._rebuildDagNode(goal, []);
|
|
14422
|
+
added.add(id);
|
|
14423
|
+
remaining.delete(id);
|
|
14424
|
+
}
|
|
14425
|
+
}
|
|
14426
|
+
}
|
|
14427
|
+
}
|
|
14428
|
+
_rebuildDagNode(goal, deps) {
|
|
14429
|
+
this.dag.addNode(goal.id, goal.description, deps, { tags: goal.tags });
|
|
14430
|
+
if (goal.status === "in_progress") {
|
|
14431
|
+
this.dag.start(goal.id, goal.assignee ?? "unknown");
|
|
14432
|
+
return;
|
|
14433
|
+
}
|
|
14434
|
+
if (goal.status === "done") {
|
|
14435
|
+
this.dag.complete(goal.id, goal.result ?? "Persisted completion");
|
|
14436
|
+
return;
|
|
14437
|
+
}
|
|
14438
|
+
if (goal.status === "failed") {
|
|
14439
|
+
this.dag.fail(goal.id, goal.result ?? "Persisted failure");
|
|
14440
|
+
}
|
|
14441
|
+
}
|
|
14231
14442
|
async _decomposeGoal(goalText) {
|
|
14232
14443
|
const category = this._inferCategory(goalText);
|
|
14233
14444
|
const subGoals = [];
|
|
@@ -14264,13 +14475,7 @@ ${input.detail}`
|
|
|
14264
14475
|
const goalNode = this.graph.get(goalId);
|
|
14265
14476
|
if (!goalNode) return;
|
|
14266
14477
|
const title = goalNode.title || dagNode.description;
|
|
14267
|
-
|
|
14268
|
-
title,
|
|
14269
|
-
description: goalNode.description,
|
|
14270
|
-
priority: this._dagPriorityToGoal(dagNode.priority),
|
|
14271
|
-
tags: dagNode.tags
|
|
14272
|
-
});
|
|
14273
|
-
this._emit({ type: "task:ready", goalId, taskId, title });
|
|
14478
|
+
this._emit({ type: "task:ready", goalId, taskId: goalId, title });
|
|
14274
14479
|
if (this.director) {
|
|
14275
14480
|
const config = {
|
|
14276
14481
|
name: `worker-${goalId.slice(0, 8)}`,
|
|
@@ -14280,7 +14485,7 @@ ${input.detail}`
|
|
|
14280
14485
|
// 10 minutes per goal
|
|
14281
14486
|
};
|
|
14282
14487
|
const subagentId = await this.director.spawn(config);
|
|
14283
|
-
await this.auction.claim(
|
|
14488
|
+
await this.auction.claim(goalId, subagentId, config.name);
|
|
14284
14489
|
await this.director.assign({
|
|
14285
14490
|
id: goalId,
|
|
14286
14491
|
subagentId,
|
|
@@ -14288,6 +14493,78 @@ ${input.detail}`
|
|
|
14288
14493
|
});
|
|
14289
14494
|
}
|
|
14290
14495
|
}
|
|
14496
|
+
_stringifyTaskResult(result) {
|
|
14497
|
+
if (typeof result === "string" && result.trim()) return result.trim();
|
|
14498
|
+
if (result === void 0 || result === null) return "Subagent completed successfully";
|
|
14499
|
+
try {
|
|
14500
|
+
return JSON.stringify(result);
|
|
14501
|
+
} catch {
|
|
14502
|
+
return String(result);
|
|
14503
|
+
}
|
|
14504
|
+
}
|
|
14505
|
+
async _completeTask(taskId, result) {
|
|
14506
|
+
await this.auction.complete(taskId, result);
|
|
14507
|
+
if (this.dag.getNode(taskId)) {
|
|
14508
|
+
this.dag.complete(taskId, result);
|
|
14509
|
+
}
|
|
14510
|
+
await this._publishTaskResultFact(taskId, result);
|
|
14511
|
+
await this._createFollowUpGoalsFromResult(taskId, result);
|
|
14512
|
+
this._emit({ type: "task:completed", goalId: taskId, taskId, text: result });
|
|
14513
|
+
}
|
|
14514
|
+
async _publishTaskResultFact(taskId, result) {
|
|
14515
|
+
const key = `task-result:${taskId}`;
|
|
14516
|
+
if (this.graph.getFacts({ category: "quality" }).some((fact2) => fact2.key === key)) return;
|
|
14517
|
+
const goal = this.graph.get(taskId);
|
|
14518
|
+
const subject = goal?.type === "goal" ? `Task completed: ${goal.title}` : `Task completed: ${taskId}`;
|
|
14519
|
+
const fact = await this.graph.add({
|
|
14520
|
+
type: "fact",
|
|
14521
|
+
category: "quality",
|
|
14522
|
+
subject,
|
|
14523
|
+
detail: result,
|
|
14524
|
+
discoveredBy: this.selfAgentId,
|
|
14525
|
+
discoveredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14526
|
+
tags: ["task-result", "autonomous-coordinator"],
|
|
14527
|
+
key,
|
|
14528
|
+
related: [taskId]
|
|
14529
|
+
});
|
|
14530
|
+
this._emit({ type: "knowledge:added", knowledgeId: fact.id, title: subject, text: result });
|
|
14531
|
+
}
|
|
14532
|
+
async _createFollowUpGoalsFromResult(taskId, result) {
|
|
14533
|
+
const followUps = this._extractFollowUps(result);
|
|
14534
|
+
if (followUps.length === 0) return;
|
|
14535
|
+
const existing = this.graph.getGoals({});
|
|
14536
|
+
for (const title of followUps) {
|
|
14537
|
+
if (existing.some((goal2) => goal2.title === title && goal2.tags.includes("follow-up"))) continue;
|
|
14538
|
+
const goal = await this.createGoal({
|
|
14539
|
+
title,
|
|
14540
|
+
description: title,
|
|
14541
|
+
priority: "medium",
|
|
14542
|
+
tags: ["follow-up", "task-result", taskId]
|
|
14543
|
+
});
|
|
14544
|
+
this._emit({ type: "goal:added", goalId: goal.id, title: goal.title, text: goal.description });
|
|
14545
|
+
}
|
|
14546
|
+
}
|
|
14547
|
+
_extractFollowUps(result) {
|
|
14548
|
+
const found = [];
|
|
14549
|
+
for (const line of result.split(/\r?\n/)) {
|
|
14550
|
+
const match = /^\s*(?:[-*]\s*)?(?:NEXT|TODO|FOLLOW-?UP):\s*(.+)$/i.exec(line);
|
|
14551
|
+
const text = match?.[1]?.trim();
|
|
14552
|
+
if (!text || found.includes(text)) continue;
|
|
14553
|
+
found.push(text);
|
|
14554
|
+
if (found.length >= 5) break;
|
|
14555
|
+
}
|
|
14556
|
+
return found;
|
|
14557
|
+
}
|
|
14558
|
+
async _failTask(taskId, error) {
|
|
14559
|
+
await this.auction.fail(taskId, error);
|
|
14560
|
+
this._recordTaskFailed(taskId, error);
|
|
14561
|
+
}
|
|
14562
|
+
_recordTaskFailed(taskId, error) {
|
|
14563
|
+
if (this.dag.getNode(taskId)) {
|
|
14564
|
+
this.dag.fail(taskId, error);
|
|
14565
|
+
}
|
|
14566
|
+
this._emit({ type: "goal:failed", goalId: taskId, text: error });
|
|
14567
|
+
}
|
|
14291
14568
|
async _handlePendingChange(change) {
|
|
14292
14569
|
const result = this.consensus.getStatus(change.id);
|
|
14293
14570
|
if (result?.outcome !== "pending") return;
|
|
@@ -14328,16 +14605,15 @@ ${input.detail}`
|
|
|
14328
14605
|
_onSubagentTerminated(e) {
|
|
14329
14606
|
const payload = e.payload;
|
|
14330
14607
|
const subagentId = payload?.subagentId ?? e.subagentId;
|
|
14331
|
-
const
|
|
14332
|
-
const
|
|
14608
|
+
const rawStatus = payload?.stopReason ?? payload?.status ?? "unknown";
|
|
14609
|
+
const succeeded = rawStatus === "end_turn" || rawStatus === "ok" || rawStatus === "success";
|
|
14610
|
+
const tasks = payload?.taskId ? this.auction.getTasksForAgent(subagentId).filter((task) => task.id === payload.taskId) : this.auction.getTasksForAgent(subagentId);
|
|
14333
14611
|
for (const task of tasks) {
|
|
14334
14612
|
this._handledBySubagent.add(task.id);
|
|
14335
|
-
if (
|
|
14336
|
-
void this.
|
|
14337
|
-
this._emit({ type: "task:completed", goalId: task.id, taskId: task.id, text: "Subagent completed successfully" });
|
|
14613
|
+
if (succeeded) {
|
|
14614
|
+
void this._completeTask(task.id, this._stringifyTaskResult(payload?.result));
|
|
14338
14615
|
} else {
|
|
14339
|
-
void this.
|
|
14340
|
-
this._emit({ type: "goal:failed", goalId: task.id, text: `Subagent terminated: ${stopReason}` });
|
|
14616
|
+
void this._failTask(task.id, `Subagent terminated: ${rawStatus}`);
|
|
14341
14617
|
}
|
|
14342
14618
|
}
|
|
14343
14619
|
}
|
|
@@ -14372,12 +14648,6 @@ ${input.detail}`
|
|
|
14372
14648
|
_optionToGoal(optionId) {
|
|
14373
14649
|
return this.graph.get(optionId);
|
|
14374
14650
|
}
|
|
14375
|
-
_dagPriorityToGoal(p) {
|
|
14376
|
-
if (p <= 1) return "critical";
|
|
14377
|
-
if (p <= 2) return "high";
|
|
14378
|
-
if (p <= 4) return "medium";
|
|
14379
|
-
return "low";
|
|
14380
|
-
}
|
|
14381
14651
|
async _mailboxBroadcast(msg) {
|
|
14382
14652
|
if (!this.mailbox) return;
|
|
14383
14653
|
try {
|