nexus-prime 7.9.21 → 7.9.23
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/agents/adapters/ide-compat.d.ts +3 -3
- package/dist/agents/adapters/ide-compat.js +51 -1
- package/dist/agents/adapters/mcp/definitions.js +4 -1
- package/dist/agents/adapters/mcp/dispatch.js +66 -4
- package/dist/agents/adapters/mcp/handlers/memory.js +44 -5
- package/dist/agents/adapters/mcp/handlers/orchestration.js +91 -0
- package/dist/agents/adapters/mcp/runHandler.js +3 -0
- package/dist/agents/adapters/mcp/util/detect-caller.js +21 -0
- package/dist/agents/adapters/mcp.js +1 -1
- package/dist/agents/adapters.d.ts +10 -1
- package/dist/agents/adapters.js +21 -0
- package/dist/agents/core/types.d.ts +1 -1
- package/dist/cli/hook.d.ts +4 -6
- package/dist/cli/hook.js +6 -8
- package/dist/cli/install-wizard.js +5 -1
- package/dist/cli.js +181 -15
- package/dist/core/types.d.ts +1 -1
- package/dist/dashboard/app/styles/board.css +85 -1
- package/dist/dashboard/app/styles/runtime.css +148 -0
- package/dist/dashboard/app/styles/workforce.css +28 -0
- package/dist/dashboard/app/views/board.js +56 -0
- package/dist/dashboard/app/views/memory.js +71 -10
- package/dist/dashboard/app/views/runtime.js +138 -4
- package/dist/dashboard/app/views/workforce.js +11 -4
- package/dist/dashboard/routes/events.js +3 -0
- package/dist/dashboard/selectors/operate-selector.js +5 -0
- package/dist/dashboard/selectors/runs-selector.js +5 -0
- package/dist/dashboard/server.js +6 -0
- package/dist/dashboard/types.d.ts +4 -0
- package/dist/engines/client-bootstrap.d.ts +5 -1
- package/dist/engines/client-bootstrap.js +105 -10
- package/dist/engines/client-registry.js +51 -0
- package/dist/engines/event-bus.d.ts +20 -2
- package/dist/engines/feature-registry.js +1 -0
- package/dist/engines/instruction-gateway.d.ts +9 -0
- package/dist/engines/instruction-gateway.js +113 -4
- package/dist/engines/memory/types.d.ts +28 -0
- package/dist/engines/memory-bridge.d.ts +1 -1
- package/dist/engines/memory-bridge.js +1 -1
- package/dist/engines/memory.d.ts +5 -0
- package/dist/engines/memory.js +144 -12
- package/dist/engines/orchestrator/decision-spine.d.ts +26 -0
- package/dist/engines/orchestrator/decision-spine.js +145 -6
- package/dist/engines/orchestrator/funnel.js +8 -1
- package/dist/engines/orchestrator/scoring.d.ts +1 -1
- package/dist/engines/orchestrator/scoring.js +24 -2
- package/dist/engines/orchestrator.d.ts +3 -0
- package/dist/engines/orchestrator.js +73 -13
- package/dist/engines/peer-connectors.d.ts +1 -1
- package/dist/engines/peer-connectors.js +9 -2
- package/dist/engines/runtime-registry.d.ts +9 -0
- package/dist/index.js +9 -0
- package/dist/install/state-locator.d.ts +1 -1
- package/dist/install/state-locator.js +3 -0
- package/dist/synapse/bootstrap.js +3 -0
- package/dist/synapse/mandate/pipeline.js +52 -5
- package/dist/synapse/sorties/runner.js +32 -0
- package/dist/synapse/types.d.ts +27 -0
- package/package.json +1 -1
|
@@ -35,6 +35,15 @@ import { resolveWorkspaceContext } from './workspace-resolver.js';
|
|
|
35
35
|
import { resolveWorkspaceStateRoot } from './workspace-resolver.js';
|
|
36
36
|
import { bootstrapFast, hasValidBootstrapReceipt, writeBootstrapReceipt, buildRepoIdentity, } from './bootstrap/index.js';
|
|
37
37
|
import { GhostPass, createSubAgentRuntime, } from '../phantom/index.js';
|
|
38
|
+
function deferNexusEvent(type, payload) {
|
|
39
|
+
const handle = setImmediate(() => {
|
|
40
|
+
try {
|
|
41
|
+
nexusEventBus.emit(type, payload);
|
|
42
|
+
}
|
|
43
|
+
catch { /* advisory telemetry must not block orchestration */ }
|
|
44
|
+
});
|
|
45
|
+
handle.unref?.();
|
|
46
|
+
}
|
|
38
47
|
// ─── Types and constants (extracted to orchestrator/types.ts) ─────────────────
|
|
39
48
|
export * from './orchestrator/types.js';
|
|
40
49
|
import { MAX_AUTONOMY_HISTORY, MAX_DISCOVERED_FILES, DISCOVERY_EXTENSIONS, DISCOVERY_IGNORES, DISCOVERY_FILENAME_SKIPS, DISCOVERY_BINARY_EXTENSIONS, DISCOVERY_DEFAULT_MAX_FILE_BYTES, } from './orchestrator/types.js';
|
|
@@ -81,6 +90,8 @@ export class OrchestratorEngine {
|
|
|
81
90
|
workflowCatalogCache;
|
|
82
91
|
hookCatalogCache;
|
|
83
92
|
automationCatalogCache;
|
|
93
|
+
clientSnapshotCache;
|
|
94
|
+
CLIENT_SNAPSHOT_CACHE_TTL_MS = 1_000;
|
|
84
95
|
specialistCatalogItems;
|
|
85
96
|
crewCatalogItems;
|
|
86
97
|
crGraphClient;
|
|
@@ -203,7 +214,7 @@ export class OrchestratorEngine {
|
|
|
203
214
|
this.agents.set(id, agent);
|
|
204
215
|
inductedAgents.push(agent);
|
|
205
216
|
}
|
|
206
|
-
|
|
217
|
+
deferNexusEvent('nexusnet.sync', { newItemsCount: inductedAgents.length });
|
|
207
218
|
return inductedAgents;
|
|
208
219
|
}
|
|
209
220
|
decomposeTask(task) {
|
|
@@ -321,7 +332,7 @@ export class OrchestratorEngine {
|
|
|
321
332
|
});
|
|
322
333
|
const selections = await this.resolveSelections(task, intent, planner, knowledgeFabric, options);
|
|
323
334
|
const catalogHealth = this.scanCatalogHealth(selections);
|
|
324
|
-
const tokenBudget = toSourceAwareTokenBudget(knowledgeFabric, plannedFiles, 'knowledge-fabric-source-aware-budget');
|
|
335
|
+
const tokenBudget = toSourceAwareTokenBudget(knowledgeFabric, plannedFiles, 'knowledge-fabric-source-aware-budget', task);
|
|
325
336
|
const workerCount = decideWorkers(options.workers, planner.swarmDecision.workers, phases.length, intent, this.sessionState.repeatedFailures, knowledgeFabric);
|
|
326
337
|
const mode = determineMode(intent, phases.length, workerCount, this.sessionState.repeatedFailures);
|
|
327
338
|
const taskGraph = buildTaskGraph(task, phases, intent);
|
|
@@ -1245,6 +1256,8 @@ export class OrchestratorEngine {
|
|
|
1245
1256
|
estimatedCompressionPct: tokenPlan && tokenPlan.totalEstimatedTokens + tokenPlan.savings > 0
|
|
1246
1257
|
? Math.round((tokenPlan.savings / (tokenPlan.totalEstimatedTokens + tokenPlan.savings)) * 100)
|
|
1247
1258
|
: 0,
|
|
1259
|
+
codeBlockTemplates: tokenBudget.codeBlocks?.templates,
|
|
1260
|
+
codeBlockReservedTokens: tokenBudget.codeBlocks?.reservedTokens,
|
|
1248
1261
|
},
|
|
1249
1262
|
memoryMatches,
|
|
1250
1263
|
memoryStats,
|
|
@@ -1589,19 +1602,27 @@ export class OrchestratorEngine {
|
|
|
1589
1602
|
return RunManagement.pruneStaleAutonomySessions(this._runMgrCtx());
|
|
1590
1603
|
}
|
|
1591
1604
|
resolvePrimaryClient() {
|
|
1592
|
-
|
|
1593
|
-
if (primary)
|
|
1594
|
-
return this.toClientSnapshot(primary);
|
|
1595
|
-
const detected = this.detectCurrentClientFromEnv();
|
|
1596
|
-
return detected ? this.toClientSnapshot(detected) : undefined;
|
|
1605
|
+
return this.getClientSnapshot().primary;
|
|
1597
1606
|
}
|
|
1598
1607
|
listDetectedClients() {
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1608
|
+
return this.getClientSnapshot().clients;
|
|
1609
|
+
}
|
|
1610
|
+
getClientSnapshot() {
|
|
1611
|
+
const now = Date.now();
|
|
1612
|
+
if (this.clientSnapshotCache && now - this.clientSnapshotCache.ts < this.CLIENT_SNAPSHOT_CACHE_TTL_MS) {
|
|
1613
|
+
return this.clientSnapshotCache;
|
|
1614
|
+
}
|
|
1615
|
+
const records = this.clientRegistry?.listClients?.() ?? [];
|
|
1616
|
+
const clients = records.length > 0
|
|
1617
|
+
? records.map((client) => this.toClientSnapshot(client))
|
|
1618
|
+
: (() => {
|
|
1619
|
+
const detected = this.detectCurrentClientFromEnv();
|
|
1620
|
+
return detected ? [this.toClientSnapshot(detected)] : [];
|
|
1621
|
+
})();
|
|
1622
|
+
const primary = clients.find((client) => client.state === 'primaryActive')
|
|
1623
|
+
?? clients.find((client) => client.state !== 'offline');
|
|
1624
|
+
this.clientSnapshotCache = { ts: now, primary, clients };
|
|
1625
|
+
return this.clientSnapshotCache;
|
|
1605
1626
|
}
|
|
1606
1627
|
detectCurrentClientFromEnv() {
|
|
1607
1628
|
if (process.env.CODEX_HOME || process.env.CODEX_SESSION) {
|
|
@@ -1669,6 +1690,45 @@ export class OrchestratorEngine {
|
|
|
1669
1690
|
lastSeen: Date.now(),
|
|
1670
1691
|
};
|
|
1671
1692
|
}
|
|
1693
|
+
if (process.env.HERMES_HOME || process.env.HERMES_SESSION) {
|
|
1694
|
+
return {
|
|
1695
|
+
clientId: 'hermes',
|
|
1696
|
+
displayName: 'Hermes',
|
|
1697
|
+
state: 'primaryActive',
|
|
1698
|
+
source: 'manual',
|
|
1699
|
+
inferred: false,
|
|
1700
|
+
confidence: 1,
|
|
1701
|
+
evidence: ['env:HERMES detected'],
|
|
1702
|
+
metadata: {},
|
|
1703
|
+
lastSeen: Date.now(),
|
|
1704
|
+
};
|
|
1705
|
+
}
|
|
1706
|
+
if (process.env.NANOCLAW_HOME || process.env.NANOCLAW_SESSION) {
|
|
1707
|
+
return {
|
|
1708
|
+
clientId: 'nanoclaw',
|
|
1709
|
+
displayName: 'NanoClaw',
|
|
1710
|
+
state: 'primaryActive',
|
|
1711
|
+
source: 'manual',
|
|
1712
|
+
inferred: false,
|
|
1713
|
+
confidence: 1,
|
|
1714
|
+
evidence: ['env:NANOCLAW detected'],
|
|
1715
|
+
metadata: {},
|
|
1716
|
+
lastSeen: Date.now(),
|
|
1717
|
+
};
|
|
1718
|
+
}
|
|
1719
|
+
if (process.env.PICOCLAW_HOME || process.env.PICOCLAW_SESSION) {
|
|
1720
|
+
return {
|
|
1721
|
+
clientId: 'picoclaw',
|
|
1722
|
+
displayName: 'PicoClaw',
|
|
1723
|
+
state: 'primaryActive',
|
|
1724
|
+
source: 'manual',
|
|
1725
|
+
inferred: false,
|
|
1726
|
+
confidence: 1,
|
|
1727
|
+
evidence: ['env:PICOCLAW detected'],
|
|
1728
|
+
metadata: {},
|
|
1729
|
+
lastSeen: Date.now(),
|
|
1730
|
+
};
|
|
1731
|
+
}
|
|
1672
1732
|
if (process.env.WINDSURF_HOME || process.env.WINDSURF_SESSION) {
|
|
1673
1733
|
return {
|
|
1674
1734
|
clientId: 'windsurf',
|
|
@@ -29,7 +29,7 @@ export interface PeerProfile {
|
|
|
29
29
|
export declare function detectAtlasFoundation(): AtlasFoundationState;
|
|
30
30
|
/**
|
|
31
31
|
* Scans standard paths in the user's home directory to dynamically
|
|
32
|
-
* discover peer AI agent ecosystems like OpenClaw, Hermes, PicoClaw, or Atlas.
|
|
32
|
+
* discover peer AI agent ecosystems like OpenClaw, Hermes, NanoClaw, PicoClaw, or Atlas.
|
|
33
33
|
*
|
|
34
34
|
* @returns Array of detected peer profiles
|
|
35
35
|
*/
|
|
@@ -64,24 +64,31 @@ export function detectAtlasFoundation() {
|
|
|
64
64
|
}
|
|
65
65
|
/**
|
|
66
66
|
* Scans standard paths in the user's home directory to dynamically
|
|
67
|
-
* discover peer AI agent ecosystems like OpenClaw, Hermes, PicoClaw, or Atlas.
|
|
67
|
+
* discover peer AI agent ecosystems like OpenClaw, Hermes, NanoClaw, PicoClaw, or Atlas.
|
|
68
68
|
*
|
|
69
69
|
* @returns Array of detected peer profiles
|
|
70
70
|
*/
|
|
71
71
|
export async function detectAllPeers() {
|
|
72
72
|
const home = os.homedir();
|
|
73
73
|
const peers = [];
|
|
74
|
+
const seenPeerIds = new Set();
|
|
74
75
|
const candidates = [
|
|
75
76
|
{ id: 'openclaw', relativeConfig: '.openclaw/openclaw.json' },
|
|
76
77
|
{ id: 'hermes', relativeConfig: '.hermes/config.yaml' },
|
|
78
|
+
{ id: 'hermes', relativeConfig: '.hermes/mcp.json' },
|
|
79
|
+
{ id: 'nanoclaw', relativeConfig: '.nanoclaw/mcp.json' },
|
|
77
80
|
{ id: 'picoclaw', relativeConfig: '.picoclaw/config.yaml' },
|
|
81
|
+
{ id: 'picoclaw', relativeConfig: '.picoclaw/mcp.json' },
|
|
78
82
|
{ id: 'opencode', relativeConfig: '.config/opencode/opencode.json' },
|
|
79
83
|
];
|
|
80
84
|
for (const c of candidates) {
|
|
81
85
|
const fullPath = path.join(home, c.relativeConfig);
|
|
82
86
|
try {
|
|
83
87
|
if (fs.existsSync(fullPath)) {
|
|
84
|
-
|
|
88
|
+
if (seenPeerIds.has(c.id))
|
|
89
|
+
continue;
|
|
90
|
+
seenPeerIds.add(c.id);
|
|
91
|
+
const capabilities = ['skill-sharing', 'memory-sync', 'tool-relay', 'token-budgeting', 'workforce-hiring'];
|
|
85
92
|
peers.push({
|
|
86
93
|
id: c.id,
|
|
87
94
|
configPath: fullPath,
|
|
@@ -194,6 +194,15 @@ export interface RuntimeSourceAwareTokenBudgetSnapshot {
|
|
|
194
194
|
reason: string;
|
|
195
195
|
}>;
|
|
196
196
|
dominantSource?: string;
|
|
197
|
+
codeBlocks?: {
|
|
198
|
+
requested: boolean;
|
|
199
|
+
detectedBlocks: number;
|
|
200
|
+
reservedTokens: number;
|
|
201
|
+
templates: string[];
|
|
202
|
+
languages: string[];
|
|
203
|
+
};
|
|
204
|
+
qualityGates?: string[];
|
|
205
|
+
recommendations?: string[];
|
|
197
206
|
}
|
|
198
207
|
export interface RuntimeTaskGraphPhase {
|
|
199
208
|
id: string;
|
package/dist/index.js
CHANGED
|
@@ -1192,6 +1192,15 @@ function detectCurrentClient() {
|
|
|
1192
1192
|
if (process.env.OPENCLAW_HOME || process.env.ANTIGRAVITY_HOME) {
|
|
1193
1193
|
return { clientId: 'antigravity', source: 'env' };
|
|
1194
1194
|
}
|
|
1195
|
+
if (process.env.HERMES_HOME || process.env.HERMES_SESSION) {
|
|
1196
|
+
return { clientId: 'hermes', source: 'env' };
|
|
1197
|
+
}
|
|
1198
|
+
if (process.env.NANOCLAW_HOME || process.env.NANOCLAW_SESSION) {
|
|
1199
|
+
return { clientId: 'nanoclaw', source: 'env' };
|
|
1200
|
+
}
|
|
1201
|
+
if (process.env.PICOCLAW_HOME || process.env.PICOCLAW_SESSION) {
|
|
1202
|
+
return { clientId: 'picoclaw', source: 'env' };
|
|
1203
|
+
}
|
|
1195
1204
|
if (process.env.WINDSURF_HOME || process.env.WINDSURF_SESSION) {
|
|
1196
1205
|
return { clientId: 'windsurf', source: 'env' };
|
|
1197
1206
|
}
|
|
@@ -36,7 +36,7 @@ export interface NgramArchiveEntry {
|
|
|
36
36
|
export declare function enumerateNgramArchives(stateDir?: string): NgramArchiveEntry[];
|
|
37
37
|
/** Known IDE registration targets discovered in a workspace + home dir. */
|
|
38
38
|
export interface RegistrationTarget {
|
|
39
|
-
id: 'aider' | 'antigravity' | 'claude-desktop' | 'claude-home' | 'claude-workspace' | 'cline' | 'codex-json' | 'codex-toml' | 'continue' | 'cursor-home' | 'cursor-workspace' | 'opencode' | 'openclaw' | 'vscode-workspace' | 'windsurf';
|
|
39
|
+
id: 'aider' | 'antigravity' | 'claude-desktop' | 'claude-home' | 'claude-workspace' | 'cline' | 'codex-json' | 'codex-toml' | 'continue' | 'cursor-home' | 'cursor-workspace' | 'hermes' | 'nanoclaw' | 'opencode' | 'openclaw' | 'picoclaw' | 'vscode-workspace' | 'windsurf';
|
|
40
40
|
filePath: string;
|
|
41
41
|
jsonPath: string[];
|
|
42
42
|
}
|
|
@@ -136,6 +136,9 @@ export function enumerateRegistrationTargets(workspaceRoot, home = os.homedir())
|
|
|
136
136
|
{ id: 'windsurf', filePath: path.join(home, '.windsurf', 'mcp.json'), jsonPath: ['mcpServers', 'nexus-prime'] },
|
|
137
137
|
{ id: 'antigravity', filePath: path.join(home, '.antigravity', 'mcp.json'), jsonPath: ['mcpServers', 'nexus-prime'] },
|
|
138
138
|
{ id: 'openclaw', filePath: path.join(home, '.openclaw', 'openclaw.json'), jsonPath: ['mcpServers', 'nexus-prime'] },
|
|
139
|
+
{ id: 'hermes', filePath: path.join(home, '.hermes', 'mcp.json'), jsonPath: ['mcpServers', 'nexus-prime'] },
|
|
140
|
+
{ id: 'nanoclaw', filePath: path.join(home, '.nanoclaw', 'mcp.json'), jsonPath: ['mcpServers', 'nexus-prime'] },
|
|
141
|
+
{ id: 'picoclaw', filePath: path.join(home, '.picoclaw', 'mcp.json'), jsonPath: ['mcpServers', 'nexus-prime'] },
|
|
139
142
|
{ id: 'aider', filePath: path.join(home, '.aider', 'mcp.json'), jsonPath: ['mcpServers', 'nexus-prime'] },
|
|
140
143
|
{ id: 'continue', filePath: path.join(home, '.continue', 'config.json'), jsonPath: ['mcpServers', 'nexus-prime'] },
|
|
141
144
|
{ id: 'cline', filePath: path.join(home, '.vscode', 'cline-mcp.json'), jsonPath: ['mcpServers', 'nexus-prime'] },
|
|
@@ -86,6 +86,9 @@ function hireOperativeDirect(db, providers, input) {
|
|
|
86
86
|
operativeId: operative.id,
|
|
87
87
|
name: operative.name,
|
|
88
88
|
skillId: operative.skillId,
|
|
89
|
+
specialistId: operative.specialistId,
|
|
90
|
+
roleTitle: operative.roleTitle,
|
|
91
|
+
reportsToOperativeId: operative.reportsToOperativeId,
|
|
89
92
|
strikeTeamId: operative.strikeTeamId,
|
|
90
93
|
});
|
|
91
94
|
storeOperationalMemory(providers, `[Synapse:Hire] ${operative.name} hired as ${operative.roleTitle ?? 'Operative'}`, ['#hire'], {
|
|
@@ -10,6 +10,17 @@ import { safePublish } from '../coordination/safe-publish.js';
|
|
|
10
10
|
function unique(values) {
|
|
11
11
|
return [...new Set(values)];
|
|
12
12
|
}
|
|
13
|
+
function boundedRequestedOperatives(opts) {
|
|
14
|
+
const requested = Number(opts.maxOperatives ?? SynapseConfig.maxOpsPerTeam);
|
|
15
|
+
const safeRequested = Number.isFinite(requested) && requested > 0 ? Math.floor(requested) : SynapseConfig.maxOpsPerTeam;
|
|
16
|
+
return Math.max(1, Math.min(safeRequested, SynapseConfig.maxOpsPerTeam));
|
|
17
|
+
}
|
|
18
|
+
function decideMandateOperativeCount(signals, matched, missionTitles, opts) {
|
|
19
|
+
const requested = boundedRequestedOperatives(opts);
|
|
20
|
+
const evidenceCount = Math.max(matched.skills.length, matched.specialists.length, missionTitles.length);
|
|
21
|
+
const complexityFloor = signals.complexity === 'read' ? 1 : 2;
|
|
22
|
+
return Math.max(1, Math.min(requested, Math.max(evidenceCount || 1, complexityFloor)));
|
|
23
|
+
}
|
|
13
24
|
function deriveMissionTitles(mandateText, complexity, hints, planner) {
|
|
14
25
|
const plannerHints = [
|
|
15
26
|
...planner.plannerState.selectedSpecialists.map((specialist) => `Coordinate with ${specialist.name}`),
|
|
@@ -29,7 +40,7 @@ export async function executeMandatePipeline(db, mandateText, providers, opts =
|
|
|
29
40
|
const planner = planTask({
|
|
30
41
|
goal: mandateText,
|
|
31
42
|
files: [],
|
|
32
|
-
workers: Math.max(2,
|
|
43
|
+
workers: Math.max(2, boundedRequestedOperatives(opts)),
|
|
33
44
|
roles: ['planner', 'coder'],
|
|
34
45
|
strategies: ['standard'],
|
|
35
46
|
verifyCommands: [],
|
|
@@ -63,7 +74,7 @@ export async function executeMandatePipeline(db, mandateText, providers, opts =
|
|
|
63
74
|
manualOverrides: [],
|
|
64
75
|
});
|
|
65
76
|
const missionTitles = deriveMissionTitles(mandateText, signals.complexity, signals.subGoalHints, planner);
|
|
66
|
-
const maxOps =
|
|
77
|
+
const maxOps = decideMandateOperativeCount(signals, matched, missionTitles, opts);
|
|
67
78
|
const budget = opts.budgetUsd ?? SynapseConfig.defaultBudgetUsd;
|
|
68
79
|
const team = db.transaction(() => {
|
|
69
80
|
const teamId = randomUUID();
|
|
@@ -71,9 +82,11 @@ export async function executeMandatePipeline(db, mandateText, providers, opts =
|
|
|
71
82
|
const worklistId = providers.coordination?.getWorklistId(teamId) ?? null;
|
|
72
83
|
const blueprintId = worklistId ? `implicit-blueprint:${teamId}` : null;
|
|
73
84
|
let leadOperativeId = null;
|
|
85
|
+
const hiringPlan = [];
|
|
86
|
+
const missionPlan = [];
|
|
74
87
|
const operativeIds = Array.from({ length: maxOps }, (_, index) => {
|
|
75
|
-
const skill = matched.skills[index
|
|
76
|
-
const specialist = matched.specialists[index
|
|
88
|
+
const skill = matched.skills.length > 0 ? matched.skills[index % matched.skills.length] : undefined;
|
|
89
|
+
const specialist = matched.specialists.length > 0 ? matched.specialists[index % matched.specialists.length] : null;
|
|
77
90
|
const operative = insertOperative(db, {
|
|
78
91
|
id: randomUUID(),
|
|
79
92
|
name: `operative-${teamId.slice(0, 4)}-${index + 1}`,
|
|
@@ -89,10 +102,22 @@ export async function executeMandatePipeline(db, mandateText, providers, opts =
|
|
|
89
102
|
});
|
|
90
103
|
if (index === 0)
|
|
91
104
|
leadOperativeId = operative.id;
|
|
105
|
+
hiringPlan.push({
|
|
106
|
+
operativeId: operative.id,
|
|
107
|
+
name: operative.name,
|
|
108
|
+
roleTitle: operative.roleTitle,
|
|
109
|
+
skillId: operative.skillId,
|
|
110
|
+
specialistId: operative.specialistId,
|
|
111
|
+
reportsToOperativeId: operative.reportsToOperativeId,
|
|
112
|
+
budgetCapUsd: operative.budgetCapUsd,
|
|
113
|
+
});
|
|
92
114
|
nexusEventBus.emit('synapse.operative.hired', {
|
|
93
115
|
operativeId: operative.id,
|
|
94
116
|
name: operative.name,
|
|
95
117
|
skillId: operative.skillId,
|
|
118
|
+
specialistId: operative.specialistId,
|
|
119
|
+
roleTitle: operative.roleTitle,
|
|
120
|
+
reportsToOperativeId: operative.reportsToOperativeId,
|
|
96
121
|
strikeTeamId: teamId,
|
|
97
122
|
});
|
|
98
123
|
return operative.id;
|
|
@@ -115,6 +140,13 @@ export async function executeMandatePipeline(db, mandateText, providers, opts =
|
|
|
115
140
|
budgetScopeId: teamId,
|
|
116
141
|
});
|
|
117
142
|
updateOperativeMission(db, operativeId, mission.id, teamId);
|
|
143
|
+
missionPlan.push({
|
|
144
|
+
missionId: mission.id,
|
|
145
|
+
title: mission.title,
|
|
146
|
+
assignedOperativeId: operativeId,
|
|
147
|
+
complexity: mission.complexity,
|
|
148
|
+
requiresApprovalGate: mission.requiresApprovalGate,
|
|
149
|
+
});
|
|
118
150
|
nexusEventBus.emit('synapse.mission.assigned', {
|
|
119
151
|
operativeId,
|
|
120
152
|
missionId: mission.id,
|
|
@@ -135,6 +167,15 @@ export async function executeMandatePipeline(db, mandateText, providers, opts =
|
|
|
135
167
|
}, 'mandate');
|
|
136
168
|
return mission.id;
|
|
137
169
|
});
|
|
170
|
+
const selectionSummary = {
|
|
171
|
+
domains: signals.domains,
|
|
172
|
+
complexity: signals.complexity,
|
|
173
|
+
skills: unique(matched.skills.slice(0, maxOps).map((skill) => skill.name).filter(Boolean)),
|
|
174
|
+
specialists: unique(matched.specialists.slice(0, maxOps).map((specialist) => specialist.name).filter(Boolean)),
|
|
175
|
+
workflows: unique(planner.plannerState.selectedWorkflows),
|
|
176
|
+
operativeCount: operativeIds.length,
|
|
177
|
+
missionCount: missionIds.length,
|
|
178
|
+
};
|
|
138
179
|
insertStrikeTeam(db, {
|
|
139
180
|
id: teamId,
|
|
140
181
|
mandateText,
|
|
@@ -147,6 +188,7 @@ export async function executeMandatePipeline(db, mandateText, providers, opts =
|
|
|
147
188
|
strikeTeamId: teamId,
|
|
148
189
|
operativeCount: operativeIds.length,
|
|
149
190
|
missionCount: missionIds.length,
|
|
191
|
+
selectionSummary,
|
|
150
192
|
worklistId,
|
|
151
193
|
correlationId: teamId,
|
|
152
194
|
});
|
|
@@ -164,7 +206,12 @@ export async function executeMandatePipeline(db, mandateText, providers, opts =
|
|
|
164
206
|
containerTags: [`#team:${teamId}`, ...(worklistId ? [`#worklist:${worklistId}`] : [])],
|
|
165
207
|
},
|
|
166
208
|
});
|
|
167
|
-
return
|
|
209
|
+
return {
|
|
210
|
+
...getStrikeTeam(db, teamId),
|
|
211
|
+
selectionSummary,
|
|
212
|
+
hiringPlan,
|
|
213
|
+
missionPlan,
|
|
214
|
+
};
|
|
168
215
|
})();
|
|
169
216
|
nexusEventBus.emit('synapse.striketeam.finished', {
|
|
170
217
|
strikeTeamId: team.id,
|
|
@@ -57,6 +57,15 @@ function createSyntheticSortie(db, operative, mission, status) {
|
|
|
57
57
|
completedAt: new Date().toISOString(),
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
|
+
function extractWorkflowSelectorsFromMission(title) {
|
|
61
|
+
const selectors = new Set();
|
|
62
|
+
for (const match of title.matchAll(/Execute workflow:\s*([^.;\n]+)/gi)) {
|
|
63
|
+
const selector = match[1]?.trim();
|
|
64
|
+
if (selector)
|
|
65
|
+
selectors.add(selector);
|
|
66
|
+
}
|
|
67
|
+
return [...selectors];
|
|
68
|
+
}
|
|
60
69
|
export async function runSortie(db, operative, providers) {
|
|
61
70
|
const mission = getMission(db, operative.missionId);
|
|
62
71
|
if (!mission) {
|
|
@@ -138,10 +147,33 @@ export async function runSortie(db, operative, providers) {
|
|
|
138
147
|
});
|
|
139
148
|
}
|
|
140
149
|
try {
|
|
150
|
+
const workflowSelectors = extractWorkflowSelectorsFromMission(mission.title);
|
|
151
|
+
nexusEventBus.emit('synapse.sortie.selection', {
|
|
152
|
+
sortieId: sortie.id,
|
|
153
|
+
operativeId: operative.id,
|
|
154
|
+
missionId: mission.id,
|
|
155
|
+
strikeTeamId: mission.strikeTeamId,
|
|
156
|
+
skillId: operative.skillId,
|
|
157
|
+
specialistId: operative.specialistId,
|
|
158
|
+
workflowSelectors,
|
|
159
|
+
workerCount: 1,
|
|
160
|
+
});
|
|
161
|
+
safePublish(providers.coordination, {
|
|
162
|
+
phase: 'sortie',
|
|
163
|
+
summary: `Selection for ${mission.title}: skill=${operative.skillId ?? 'none'} specialist=${operative.specialistId ?? 'none'} workflows=${workflowSelectors.join(', ') || 'none'}`,
|
|
164
|
+
strikeTeamId: mission.strikeTeamId,
|
|
165
|
+
worklistId,
|
|
166
|
+
workItemId: mission.id,
|
|
167
|
+
operativeId: operative.id,
|
|
168
|
+
sortieId: sortie.id,
|
|
169
|
+
correlationId,
|
|
170
|
+
status: 'selected',
|
|
171
|
+
});
|
|
141
172
|
const execution = await providers.orchestrator.orchestrate(goal, {
|
|
142
173
|
files: [],
|
|
143
174
|
workers: 1,
|
|
144
175
|
skillNames: operative.skillId ? [operative.skillId] : [],
|
|
176
|
+
workflowSelectors,
|
|
145
177
|
specialistSelectors: operative.specialistId ? [operative.specialistId] : [],
|
|
146
178
|
executionMode: 'autonomous',
|
|
147
179
|
});
|
package/dist/synapse/types.d.ts
CHANGED
|
@@ -61,6 +61,22 @@ export interface OperativeUpdateInput {
|
|
|
61
61
|
strikeTeamId?: string | null;
|
|
62
62
|
reason?: string | null;
|
|
63
63
|
}
|
|
64
|
+
export interface StrikeTeamHiringPlanEntry {
|
|
65
|
+
operativeId: string;
|
|
66
|
+
name: string;
|
|
67
|
+
roleTitle: string | null;
|
|
68
|
+
skillId: string | null;
|
|
69
|
+
specialistId: string | null;
|
|
70
|
+
reportsToOperativeId: string | null;
|
|
71
|
+
budgetCapUsd: number;
|
|
72
|
+
}
|
|
73
|
+
export interface StrikeTeamMissionPlanEntry {
|
|
74
|
+
missionId: string;
|
|
75
|
+
title: string;
|
|
76
|
+
assignedOperativeId: string;
|
|
77
|
+
complexity: MissionComplexity;
|
|
78
|
+
requiresApprovalGate: boolean;
|
|
79
|
+
}
|
|
64
80
|
export interface StrikeTeam {
|
|
65
81
|
id: string;
|
|
66
82
|
mandateText: string;
|
|
@@ -69,6 +85,17 @@ export interface StrikeTeam {
|
|
|
69
85
|
blueprintId: string | null;
|
|
70
86
|
status: 'deploying' | 'active' | 'converging' | 'done' | 'standdown';
|
|
71
87
|
createdAt: string;
|
|
88
|
+
selectionSummary?: {
|
|
89
|
+
domains: string[];
|
|
90
|
+
complexity: MissionComplexity;
|
|
91
|
+
skills: string[];
|
|
92
|
+
specialists: string[];
|
|
93
|
+
workflows: string[];
|
|
94
|
+
operativeCount: number;
|
|
95
|
+
missionCount: number;
|
|
96
|
+
};
|
|
97
|
+
hiringPlan?: StrikeTeamHiringPlanEntry[];
|
|
98
|
+
missionPlan?: StrikeTeamMissionPlanEntry[];
|
|
72
99
|
}
|
|
73
100
|
export interface Mission {
|
|
74
101
|
id: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexus-prime",
|
|
3
|
-
"version": "7.9.
|
|
3
|
+
"version": "7.9.23",
|
|
4
4
|
"description": "Local-first MCP control plane for coding agents with bootstrap-orchestrate execution, memory fabric, token budgeting, and worktree-backed swarms",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|