@shapeshift-labs/frontier-swarm 0.5.3 → 0.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -88,6 +88,8 @@ export const FRONTIER_SWARM_LANE_PLAYBOOK_KIND = 'frontier.swarm.lane-playbook';
88
88
  export const FRONTIER_SWARM_LANE_PLAYBOOK_VERSION = 1;
89
89
  export const FRONTIER_SWARM_PATCH_STACK_PLAN_KIND = 'frontier.swarm.patch-stack-plan';
90
90
  export const FRONTIER_SWARM_PATCH_STACK_PLAN_VERSION = 1;
91
+ export const FRONTIER_SWARM_COORDINATOR_DASHBOARD_KIND = 'frontier.swarm.coordinator-dashboard';
92
+ export const FRONTIER_SWARM_COORDINATOR_DASHBOARD_VERSION = 1;
91
93
  export const FRONTIER_SWARM_DEFAULT_CODEX_COMPUTE_ID = 'codex.gpt-5.5.xhigh';
92
94
  export const FRONTIER_SWARM_DEFAULT_MODEL = 'gpt-5.5';
93
95
  export const FRONTIER_SWARM_DEFAULT_REASONING_EFFORT = 'xhigh';
@@ -1606,6 +1608,154 @@ export function createSwarmPatchStackPlan(input) {
1606
1608
  ...(toJsonObject(input.metadata) ? { metadata: toJsonObject(input.metadata) } : {})
1607
1609
  };
1608
1610
  }
1611
+ export function createSwarmCoordinatorDashboard(input = {}) {
1612
+ const generatedAt = input.generatedAt ?? Date.now();
1613
+ const runId = input.run?.id ?? input.mergeIndex?.runId ?? input.queueOverlay?.runId;
1614
+ const planId = input.plan?.id ?? input.mergeIndex?.planId;
1615
+ const bundles = input.bundles ?? input.run?.results.map((result) => createSwarmMergeBundle({
1616
+ runId,
1617
+ planId,
1618
+ job: input.plan?.jobs.find((job) => job.id === result.jobId),
1619
+ result,
1620
+ generatedAt
1621
+ })) ?? [];
1622
+ const mergeIndex = input.mergeIndex ?? (bundles.length ? createSwarmMergeIndex({ runId, planId, bundles, generatedAt }) : undefined);
1623
+ const queueOverlay = input.queueOverlay ?? (bundles.length ? createSwarmQueueOverlay({ runId, bundles, generatedAt }) : undefined);
1624
+ const evidenceIndex = input.evidenceIndex ?? (input.run ? createSwarmEvidenceIndex({ run: input.run, generatedAt }) : undefined);
1625
+ const admission = input.admission;
1626
+ const jobsById = new Map((input.plan?.jobs ?? []).map((job) => [job.id, job]));
1627
+ const resultsById = new Map((input.run?.results ?? []).map((result) => [result.jobId, result]));
1628
+ const entriesById = new Map((mergeIndex?.entries ?? []).map((entry) => [entry.jobId, entry]));
1629
+ const bundlesById = new Map(bundles.map((bundle) => [bundle.jobId, bundle]));
1630
+ const processes = normalizeCoordinatorProcesses(input.processes ?? []);
1631
+ const processesByJob = groupObjects(processes.filter((process) => process.jobId), (process) => process.jobId);
1632
+ const duplicateGroups = createCoordinatorDuplicateGroups(mergeIndex?.entries ?? []);
1633
+ const duplicateByJob = new Map();
1634
+ for (const group of duplicateGroups) {
1635
+ for (const jobId of group.jobIds)
1636
+ duplicateByJob.set(jobId, group);
1637
+ }
1638
+ const admissionDeferred = new Map((admission?.deferred ?? []).map((entry) => [entry.jobId, entry.reasons]));
1639
+ const admitted = new Set(admission?.admitted ?? []);
1640
+ const jobIds = uniqueStrings([
1641
+ ...(input.plan?.jobs ?? []).map((job) => job.id),
1642
+ ...(input.run?.results ?? []).map((result) => result.jobId),
1643
+ ...(mergeIndex?.entries ?? []).map((entry) => entry.jobId),
1644
+ ...processes.map((process) => process.jobId)
1645
+ ]).sort();
1646
+ const jobs = jobIds.map((jobId) => {
1647
+ const planJob = jobsById.get(jobId);
1648
+ const result = resultsById.get(jobId);
1649
+ const entry = entriesById.get(jobId);
1650
+ const bundle = bundlesById.get(jobId);
1651
+ const processList = processesByJob[jobId] ?? [];
1652
+ const duplicateGroup = duplicateByJob.get(jobId);
1653
+ const admissionReasons = admissionDeferred.get(jobId) ?? [];
1654
+ const admissionStatus = admitted.has(jobId)
1655
+ ? 'admitted'
1656
+ : admissionReasons.length
1657
+ ? 'deferred'
1658
+ : entry?.autoMergeable
1659
+ ? 'not-admissible'
1660
+ : 'unknown';
1661
+ const score = scoreCoordinatorMergeJob(entry, bundle, evidenceIndex?.byJobId[jobId]?.length ?? 0, duplicateGroup, admissionStatus, admissionReasons);
1662
+ const evidencePaths = uniqueStrings([
1663
+ ...(entry?.evidencePaths ?? []),
1664
+ ...(result?.evidencePaths ?? []),
1665
+ ...(bundle?.evidencePaths ?? [])
1666
+ ]);
1667
+ const changedRegions = uniqueStrings([...(entry?.changedRegions ?? []), ...(result?.changedRegions ?? []), ...(bundle?.changedRegions ?? [])]);
1668
+ return {
1669
+ jobId,
1670
+ ...(entry?.taskId ?? result?.queueItemIds[0] ?? planJob?.taskId ? { taskId: entry?.taskId ?? result?.queueItemIds[0] ?? planJob?.taskId } : {}),
1671
+ ...(entry?.lane ?? planJob?.lane ? { lane: entry?.lane ?? planJob?.lane } : {}),
1672
+ ...(entry?.title ?? planJob?.title ? { title: entry?.title ?? planJob?.title } : {}),
1673
+ status: entry?.status ?? result?.status ?? planJob?.status ?? 'planned',
1674
+ liveness: coordinatorJobLiveness(result, entry, processList),
1675
+ mergeReadiness: entry?.mergeReadiness ?? result?.mergeReadiness ?? 'blocked',
1676
+ disposition: entry?.disposition ?? result?.mergeDisposition ?? 'blocked',
1677
+ riskLevel: entry?.riskLevel ?? result?.riskLevel ?? 'unknown',
1678
+ mergeScore: score.score,
1679
+ mergeScoreReasons: score.reasons,
1680
+ admissionStatus,
1681
+ admissionReasons,
1682
+ staleAgainstHead: Boolean(entry?.staleAgainstHead || bundle?.staleAgainstHead),
1683
+ ...(duplicateGroup ? { duplicateGroupId: duplicateGroup.id, ...(duplicateGroup.jobIds[0] !== jobId ? { duplicateOf: duplicateGroup.jobIds[0] } : {}) } : {}),
1684
+ changedPaths: uniqueStrings([...(entry?.changedPaths ?? []), ...(result?.changedPaths ?? []), ...(bundle?.changedPaths ?? [])]),
1685
+ changedRegions,
1686
+ semanticRegions: changedRegions,
1687
+ ownershipViolations: uniqueStrings([...(entry?.ownershipViolations ?? []), ...(result?.ownershipViolations ?? []), ...(bundle?.ownershipViolations ?? [])]),
1688
+ ...(entry?.patchPath ?? result?.patchPath ?? bundle?.patchPath ? { patchPath: entry?.patchPath ?? result?.patchPath ?? bundle?.patchPath } : {}),
1689
+ evidencePaths,
1690
+ ...(primaryEvidencePath(evidencePaths) ? { primaryEvidencePath: primaryEvidencePath(evidencePaths) } : {}),
1691
+ sourceCitations: createCoordinatorSourceCitations(entry, evidenceIndex),
1692
+ tests: {
1693
+ passed: bundle?.commandsPassed.length ?? result?.verification.filter((test) => test.status === 0).length ?? 0,
1694
+ failed: bundle?.commandsFailed.length ?? result?.verification.filter((test) => test.status !== undefined && test.status !== 0).length ?? 0,
1695
+ requiredFailed: bundle?.commandsFailed.length ?? result?.verification.filter((test) => test.required !== false && test.status !== undefined && test.status !== 0).length ?? 0
1696
+ },
1697
+ ...(entry?.semanticImport ?? result?.semanticImport ?? bundle?.semanticImport ? {
1698
+ semanticImport: cloneJsonValue(entry?.semanticImport ?? result?.semanticImport ?? bundle?.semanticImport)
1699
+ } : {}),
1700
+ generatedAt
1701
+ };
1702
+ }).sort((left, right) => right.mergeScore - left.mergeScore || left.jobId.localeCompare(right.jobId));
1703
+ const byLane = groupIds(jobs, (job) => job.lane ?? 'unassigned');
1704
+ const byDisposition = groupIds(jobs, (job) => job.disposition);
1705
+ const byLiveness = groupIds(jobs, (job) => job.liveness);
1706
+ return {
1707
+ kind: FRONTIER_SWARM_COORDINATOR_DASHBOARD_KIND,
1708
+ version: FRONTIER_SWARM_COORDINATOR_DASHBOARD_VERSION,
1709
+ id: input.id ?? 'swarm-coordinator-dashboard:' + stableHash([runId, planId, jobs, duplicateGroups, generatedAt]),
1710
+ ...(runId ? { runId } : {}),
1711
+ ...(planId ? { planId } : {}),
1712
+ generatedAt,
1713
+ jobs,
1714
+ duplicateGroups,
1715
+ processes,
1716
+ byLane,
1717
+ byDisposition,
1718
+ byLiveness,
1719
+ ...(mergeIndex ? { mergeIndex } : {}),
1720
+ ...(queueOverlay ? { queueOverlay } : {}),
1721
+ ...(evidenceIndex ? { evidenceIndex } : {}),
1722
+ ...(admission ? { admission } : {}),
1723
+ summary: {
1724
+ jobCount: jobs.length,
1725
+ readyToApplyCount: jobs.filter((job) => job.disposition === 'auto-mergeable' && job.admissionStatus !== 'deferred').length,
1726
+ needsHumanPortCount: jobs.filter((job) => job.disposition === 'needs-port').length,
1727
+ failedEvidenceCount: jobs.filter((job) => job.disposition === 'rejected' || job.disposition === 'blocked' || job.tests.requiredFailed > 0).length,
1728
+ staleAgainstHeadCount: jobs.filter((job) => job.staleAgainstHead).length,
1729
+ duplicateGroupCount: duplicateGroups.length,
1730
+ semanticSidecarCount: jobs.filter((job) => job.semanticImport && job.semanticImport.total > 0).length,
1731
+ semanticRegionCount: jobs.reduce((total, job) => total + job.semanticRegions.length, 0),
1732
+ averageMergeScore: averageScore(jobs.map((job) => job.mergeScore))
1733
+ },
1734
+ ...(toJsonObject(input.metadata) ? { metadata: toJsonObject(input.metadata) } : {})
1735
+ };
1736
+ }
1737
+ export function querySwarmCoordinatorDashboard(dashboard, query = {}) {
1738
+ const jobs = dashboard.jobs.filter((job) => ((query.jobId === undefined || job.jobId === query.jobId)
1739
+ && (query.lane === undefined || job.lane === query.lane)
1740
+ && (query.disposition === undefined || job.disposition === query.disposition)
1741
+ && (query.liveness === undefined || job.liveness === query.liveness)
1742
+ && (query.admissionStatus === undefined || job.admissionStatus === query.admissionStatus)
1743
+ && (query.pathIncludes === undefined || job.changedPaths.concat(job.evidencePaths).some((entry) => entry.includes(query.pathIncludes)))
1744
+ && (query.region === undefined || job.changedRegions.includes(query.region) || job.semanticRegions.includes(query.region))
1745
+ && (query.hasSemanticImport === undefined || Boolean(job.semanticImport && job.semanticImport.total > 0) === query.hasSemanticImport)
1746
+ && (query.hasSemanticRegions === undefined || (job.semanticRegions.length > 0) === query.hasSemanticRegions)
1747
+ && (query.staleAgainstHead === undefined || job.staleAgainstHead === query.staleAgainstHead)
1748
+ && (query.duplicateOnly !== true || Boolean(job.duplicateGroupId))
1749
+ && (query.minMergeScore === undefined || job.mergeScore >= query.minMergeScore)
1750
+ && (query.maxMergeScore === undefined || job.mergeScore <= query.maxMergeScore)));
1751
+ return {
1752
+ jobs,
1753
+ summary: {
1754
+ jobCount: jobs.length,
1755
+ averageMergeScore: averageScore(jobs.map((job) => job.mergeScore))
1756
+ }
1757
+ };
1758
+ }
1609
1759
  export function resolveSwarmCompute(manifestInput, taskInput) {
1610
1760
  const compiled = compileSwarm(manifestInput);
1611
1761
  const task = isSwarmTask(taskInput) ? taskInput : normalizeTask(taskInput);
@@ -2637,6 +2787,172 @@ function patchStackKey(entry) {
2637
2787
  const firstPath = entry.changedPaths[0] ?? 'evidence-only';
2638
2788
  return `${lane}:${firstPath.split('/').slice(0, 2).join('/') || firstPath}`;
2639
2789
  }
2790
+ function normalizeCoordinatorProcesses(input) {
2791
+ return input.map((entry) => ({
2792
+ ...(entry.pid !== undefined ? { pid: Math.floor(entry.pid) } : {}),
2793
+ role: entry.role ?? 'worker',
2794
+ ...(entry.jobId ? { jobId: entry.jobId } : {}),
2795
+ ...(entry.runId ? { runId: entry.runId } : {}),
2796
+ status: entry.status ?? 'unknown',
2797
+ ...(entry.startedAt !== undefined ? { startedAt: entry.startedAt } : {}),
2798
+ ...(entry.lastSeenAt !== undefined ? { lastSeenAt: entry.lastSeenAt } : {}),
2799
+ command: [...(entry.command ?? [])],
2800
+ ...(toJsonObject(entry.metadata) ? { metadata: toJsonObject(entry.metadata) } : {})
2801
+ })).sort((left, right) => (left.jobId ?? '').localeCompare(right.jobId ?? '') || (left.pid ?? 0) - (right.pid ?? 0));
2802
+ }
2803
+ function createCoordinatorDuplicateGroups(entries) {
2804
+ const groups = new Map();
2805
+ for (const entry of entries) {
2806
+ for (const key of coordinatorDuplicateKeys(entry))
2807
+ groups.set(key, [...(groups.get(key) ?? []), entry]);
2808
+ }
2809
+ return Array.from(groups.entries())
2810
+ .filter(([, groupEntries]) => groupEntries.length > 1)
2811
+ .map(([key, groupEntries]) => {
2812
+ const jobIds = groupEntries.map((entry) => entry.jobId).sort();
2813
+ return {
2814
+ id: 'swarm-duplicate-group:' + stableHash([key, jobIds]),
2815
+ key,
2816
+ jobIds,
2817
+ reason: key.startsWith('queue:') ? 'same-queue-item' : key.startsWith('region:') ? 'same-semantic-region' : 'same-changed-paths'
2818
+ };
2819
+ })
2820
+ .sort((left, right) => left.key.localeCompare(right.key));
2821
+ }
2822
+ function coordinatorDuplicateKeys(entry) {
2823
+ const keys = [];
2824
+ if (entry.queueItemIds.length)
2825
+ keys.push(`queue:${entry.queueItemIds.slice().sort().join('|')}`);
2826
+ if (entry.changedRegions.length)
2827
+ keys.push(`region:${entry.changedRegions.slice().sort().join('|')}`);
2828
+ if (entry.changedPaths.length)
2829
+ keys.push(`path:${entry.changedPaths.slice().sort().join('|')}`);
2830
+ return keys;
2831
+ }
2832
+ function scoreCoordinatorMergeJob(entry, bundle, evidenceEntryCount, duplicateGroup, admissionStatus, admissionReasons) {
2833
+ if (!entry)
2834
+ return { score: 10, reasons: ['no-merge-index-entry'] };
2835
+ let score = entry.disposition === 'auto-mergeable' && entry.autoMergeable ? 85 : entry.disposition === 'needs-port' ? 60 : entry.disposition === 'discovery-only' ? 35 : 15;
2836
+ const reasons = [];
2837
+ if (entry.staleAgainstHead) {
2838
+ score -= 45;
2839
+ reasons.push('stale-against-head');
2840
+ }
2841
+ if (entry.conflictingJobIds.length) {
2842
+ score -= Math.min(35, 15 + entry.conflictingJobIds.length * 5);
2843
+ reasons.push('conflicting-changes');
2844
+ }
2845
+ if (entry.ownershipViolations.length) {
2846
+ score -= 40;
2847
+ reasons.push('ownership-violations');
2848
+ }
2849
+ if (bundle?.commandsFailed.length) {
2850
+ score -= Math.min(35, 15 + bundle.commandsFailed.length * 10);
2851
+ reasons.push('failed-required-commands');
2852
+ }
2853
+ if (entry.evidencePaths.length === 0 && evidenceEntryCount === 0) {
2854
+ score -= 15;
2855
+ reasons.push('missing-evidence');
2856
+ }
2857
+ if (entry.riskLevel === 'high') {
2858
+ score -= 15;
2859
+ reasons.push('high-risk');
2860
+ }
2861
+ else if (entry.riskLevel === 'unknown') {
2862
+ score -= 8;
2863
+ reasons.push('unknown-risk');
2864
+ }
2865
+ else if (entry.riskLevel === 'medium') {
2866
+ score -= 5;
2867
+ }
2868
+ if (entry.disposition === 'needs-port')
2869
+ reasons.push('needs-human-port');
2870
+ if (entry.disposition === 'discovery-only')
2871
+ reasons.push('discovery-only');
2872
+ if (duplicateGroup) {
2873
+ score -= 12;
2874
+ reasons.push('duplicate-candidate');
2875
+ }
2876
+ if (admissionStatus === 'deferred') {
2877
+ score -= 10;
2878
+ reasons.push(...admissionReasons);
2879
+ }
2880
+ if (entry.semanticImport && entry.changedPaths.length > 0) {
2881
+ const symbols = entry.semanticImport.semanticIndex.symbols;
2882
+ const regions = entry.semanticImport.semanticSidecars.ownershipRegions;
2883
+ const errors = entry.semanticImport.errors;
2884
+ if (symbols > 0 && regions > 0) {
2885
+ score += 8;
2886
+ reasons.push('semantic-sidecar-usable');
2887
+ }
2888
+ if (entry.semanticImport.semanticSidecars.empty > 0 || symbols === 0) {
2889
+ score -= 8;
2890
+ reasons.push('weak-semantic-sidecar');
2891
+ }
2892
+ if (errors > 0) {
2893
+ score -= Math.min(25, errors * 10);
2894
+ reasons.push('semantic-import-errors');
2895
+ }
2896
+ }
2897
+ else if (entry.changedPaths.length > 0) {
2898
+ score -= 5;
2899
+ reasons.push('missing-semantic-sidecar');
2900
+ }
2901
+ if (bundle?.commandsPassed.length)
2902
+ score += Math.min(8, bundle.commandsPassed.length * 2);
2903
+ return { score: clampScore(score), reasons: uniqueStrings(reasons) };
2904
+ }
2905
+ function coordinatorJobLiveness(result, entry, processes) {
2906
+ if (result || entry)
2907
+ return 'finished';
2908
+ if (processes.some((process) => process.status === 'running'))
2909
+ return 'running';
2910
+ if (processes.some((process) => process.status === 'missing'))
2911
+ return 'missing';
2912
+ return 'unknown';
2913
+ }
2914
+ function primaryEvidencePath(paths) {
2915
+ return paths.find((entry) => entry.endsWith('/evidence.json') || entry === 'evidence.json')
2916
+ ?? paths.find((entry) => entry.endsWith('/merge.json') || entry === 'merge.json')
2917
+ ?? paths.find((entry) => entry.endsWith('/last-message.md') || entry.endsWith('/last.md'))
2918
+ ?? paths[0];
2919
+ }
2920
+ function createCoordinatorSourceCitations(entry, evidenceIndex) {
2921
+ const citations = [];
2922
+ for (const file of entry?.changedPaths ?? [])
2923
+ citations.push({ path: file, kind: 'changed-source' });
2924
+ for (const region of entry?.changedRegions ?? [])
2925
+ citations.push({ path: region, kind: 'semantic-region', region });
2926
+ for (const evidence of evidenceIndex?.byJobId[entry?.jobId ?? ''] ?? []) {
2927
+ if (!evidence.path)
2928
+ continue;
2929
+ citations.push({
2930
+ path: evidence.path,
2931
+ kind: evidence.kind,
2932
+ ...(evidence.topic ? { symbol: evidence.topic } : {}),
2933
+ confidence: evidence.confidence,
2934
+ ...(Object.keys(evidence.facets).length ? { metadata: { facets: evidence.facets } } : {})
2935
+ });
2936
+ }
2937
+ const seen = new Set();
2938
+ return citations.filter((citation) => {
2939
+ const key = `${citation.kind}:${citation.path}:${citation.symbol ?? ''}:${citation.region ?? ''}`;
2940
+ if (seen.has(key))
2941
+ return false;
2942
+ seen.add(key);
2943
+ return true;
2944
+ }).sort((left, right) => left.kind.localeCompare(right.kind) || left.path.localeCompare(right.path));
2945
+ }
2946
+ function averageScore(scores) {
2947
+ if (scores.length === 0)
2948
+ return 0;
2949
+ return Math.round(scores.reduce((sum, score) => sum + score, 0) / scores.length);
2950
+ }
2951
+ function clampScore(value) {
2952
+ if (!Number.isFinite(value))
2953
+ return 0;
2954
+ return Math.max(0, Math.min(100, Math.round(value)));
2955
+ }
2640
2956
  function riskRank(risk) {
2641
2957
  if (risk === 'low')
2642
2958
  return 0;
@@ -3170,6 +3486,7 @@ function normalizeSemanticImportSummary(input) {
3170
3486
  semanticIndex: normalizeSemanticIndexSummary(object.semanticIndex),
3171
3487
  semanticSidecars: normalizeSemanticSidecarSummary(object.semanticSidecars),
3172
3488
  sourceProjections: normalizeSourceProjectionSummary(object.sourceProjections),
3489
+ nativeCompiles: normalizeNativeCompileSummary(object.nativeCompiles),
3173
3490
  readiness: normalizeCounterRecord(object.readiness),
3174
3491
  ...(metadata ? { metadata } : {})
3175
3492
  };
@@ -3205,6 +3522,18 @@ function normalizeSourceProjectionSummary(input) {
3205
3522
  blocked: nonNegativeCount(object?.blocked)
3206
3523
  };
3207
3524
  }
3525
+ function normalizeNativeCompileSummary(input) {
3526
+ const object = toJsonObject(input);
3527
+ return {
3528
+ total: nonNegativeCount(object?.total),
3529
+ emitted: nonNegativeCount(object?.emitted),
3530
+ preserved: nonNegativeCount(object?.preserved),
3531
+ targetStubs: nonNegativeCount(object?.targetStubs),
3532
+ ready: nonNegativeCount(object?.ready),
3533
+ needsReview: nonNegativeCount(object?.needsReview),
3534
+ blocked: nonNegativeCount(object?.blocked)
3535
+ };
3536
+ }
3208
3537
  function normalizeCounterRecord(input) {
3209
3538
  const object = toJsonObject(input);
3210
3539
  if (!object)