@versatly/workgraph 1.1.0 → 1.2.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/{chunk-OTSECVE5.js → chunk-G6B47IBD.js} +3 -0
- package/dist/{chunk-TOFSHG5S.js → chunk-MCHTUXG2.js} +365 -56
- package/dist/cli.js +82 -2
- package/dist/index.d.ts +139 -1
- package/dist/index.js +4 -2
- package/dist/mcp-server.js +1 -1
- package/package.json +1 -1
|
@@ -3,13 +3,16 @@ import {
|
|
|
3
3
|
allClaims,
|
|
4
4
|
append,
|
|
5
5
|
checkpoint,
|
|
6
|
+
claim,
|
|
6
7
|
create,
|
|
7
8
|
createRun,
|
|
8
9
|
createThread,
|
|
10
|
+
done,
|
|
9
11
|
historyOf,
|
|
10
12
|
keywordSearch,
|
|
11
13
|
list,
|
|
12
14
|
listReadyThreads,
|
|
15
|
+
listReadyThreadsInSpace,
|
|
13
16
|
listRuns,
|
|
14
17
|
listTypes,
|
|
15
18
|
loadPolicyRegistry,
|
|
@@ -23,7 +26,7 @@ import {
|
|
|
23
26
|
saveRegistry,
|
|
24
27
|
stop,
|
|
25
28
|
update
|
|
26
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-G6B47IBD.js";
|
|
27
30
|
|
|
28
31
|
// src/workspace.ts
|
|
29
32
|
var workspace_exports = {};
|
|
@@ -300,7 +303,7 @@ function renderCommandCenter(input) {
|
|
|
300
303
|
const claimsSection = [
|
|
301
304
|
"## Active Claims",
|
|
302
305
|
"",
|
|
303
|
-
...input.claims.length > 0 ? input.claims.map((
|
|
306
|
+
...input.claims.length > 0 ? input.claims.map((claim2) => `- ${claim2.owner} -> \`${claim2.target}\``) : ["- None"],
|
|
304
307
|
""
|
|
305
308
|
];
|
|
306
309
|
const blockedSection = [
|
|
@@ -1610,6 +1613,311 @@ function supportedIntegrationList() {
|
|
|
1610
1613
|
return Object.keys(INTEGRATIONS).sort().join(", ");
|
|
1611
1614
|
}
|
|
1612
1615
|
|
|
1616
|
+
// src/swarm.ts
|
|
1617
|
+
var swarm_exports = {};
|
|
1618
|
+
__export(swarm_exports, {
|
|
1619
|
+
createPlanTemplate: () => createPlanTemplate,
|
|
1620
|
+
deployPlan: () => deployPlan,
|
|
1621
|
+
getSwarmStatus: () => getSwarmStatus,
|
|
1622
|
+
synthesize: () => synthesize,
|
|
1623
|
+
validatePlan: () => validatePlan,
|
|
1624
|
+
workerClaim: () => workerClaim,
|
|
1625
|
+
workerComplete: () => workerComplete,
|
|
1626
|
+
workerLoop: () => workerLoop
|
|
1627
|
+
});
|
|
1628
|
+
import * as fs7 from "fs";
|
|
1629
|
+
import * as path7 from "path";
|
|
1630
|
+
function createPlanTemplate(goal) {
|
|
1631
|
+
return {
|
|
1632
|
+
goal,
|
|
1633
|
+
tasks: [],
|
|
1634
|
+
phases: [],
|
|
1635
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1636
|
+
estimatedTotalMinutes: 0
|
|
1637
|
+
};
|
|
1638
|
+
}
|
|
1639
|
+
function validatePlan(plan) {
|
|
1640
|
+
const errors = [];
|
|
1641
|
+
if (!plan.goal.title) errors.push("Goal title is required");
|
|
1642
|
+
if (plan.tasks.length === 0) errors.push("Plan has no tasks");
|
|
1643
|
+
if (plan.tasks.length > (plan.goal.maxTasks ?? 1e3)) {
|
|
1644
|
+
errors.push(`Plan has ${plan.tasks.length} tasks, exceeds max ${plan.goal.maxTasks ?? 1e3}`);
|
|
1645
|
+
}
|
|
1646
|
+
const taskTitles = new Set(plan.tasks.map((t) => t.title));
|
|
1647
|
+
for (const task of plan.tasks) {
|
|
1648
|
+
for (const dep of task.dependsOn ?? []) {
|
|
1649
|
+
if (!taskTitles.has(dep)) {
|
|
1650
|
+
errors.push(`Task "${task.title}" depends on unknown task "${dep}"`);
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
}
|
|
1654
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1655
|
+
const stack = /* @__PURE__ */ new Set();
|
|
1656
|
+
const depMap = /* @__PURE__ */ new Map();
|
|
1657
|
+
for (const task of plan.tasks) {
|
|
1658
|
+
depMap.set(task.title, task.dependsOn ?? []);
|
|
1659
|
+
}
|
|
1660
|
+
function hasCycle(node) {
|
|
1661
|
+
if (stack.has(node)) return true;
|
|
1662
|
+
if (visited.has(node)) return false;
|
|
1663
|
+
visited.add(node);
|
|
1664
|
+
stack.add(node);
|
|
1665
|
+
for (const dep of depMap.get(node) ?? []) {
|
|
1666
|
+
if (hasCycle(dep)) return true;
|
|
1667
|
+
}
|
|
1668
|
+
stack.delete(node);
|
|
1669
|
+
return false;
|
|
1670
|
+
}
|
|
1671
|
+
for (const task of plan.tasks) {
|
|
1672
|
+
visited.clear();
|
|
1673
|
+
stack.clear();
|
|
1674
|
+
if (hasCycle(task.title)) {
|
|
1675
|
+
errors.push(`Circular dependency detected involving "${task.title}"`);
|
|
1676
|
+
break;
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
for (const phase of plan.phases) {
|
|
1680
|
+
for (const idx of phase.taskIndices) {
|
|
1681
|
+
if (idx < 0 || idx >= plan.tasks.length) {
|
|
1682
|
+
errors.push(`Phase "${phase.name}" references invalid task index ${idx}`);
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
return { valid: errors.length === 0, errors };
|
|
1687
|
+
}
|
|
1688
|
+
function deployPlan(workspacePath, plan, actor) {
|
|
1689
|
+
const validation = validatePlan(plan);
|
|
1690
|
+
if (!validation.valid) {
|
|
1691
|
+
throw new Error(`Invalid plan: ${validation.errors.join("; ")}`);
|
|
1692
|
+
}
|
|
1693
|
+
const spaceSlug = slugify(`swarm-${plan.goal.title}`);
|
|
1694
|
+
const spacePath = path7.join("spaces", `${spaceSlug}.md`);
|
|
1695
|
+
const spaceFullPath = path7.join(workspacePath, spacePath);
|
|
1696
|
+
if (!fs7.existsSync(spaceFullPath)) {
|
|
1697
|
+
const spaceDir = path7.join(workspacePath, "spaces");
|
|
1698
|
+
fs7.mkdirSync(spaceDir, { recursive: true });
|
|
1699
|
+
const spaceFrontmatter = [
|
|
1700
|
+
"---",
|
|
1701
|
+
`title: "Swarm: ${plan.goal.title}"`,
|
|
1702
|
+
`status: active`,
|
|
1703
|
+
`created: '${(/* @__PURE__ */ new Date()).toISOString()}'`,
|
|
1704
|
+
`updated: '${(/* @__PURE__ */ new Date()).toISOString()}'`,
|
|
1705
|
+
"---",
|
|
1706
|
+
"",
|
|
1707
|
+
`# Swarm Space: ${plan.goal.title}`,
|
|
1708
|
+
"",
|
|
1709
|
+
plan.goal.description,
|
|
1710
|
+
"",
|
|
1711
|
+
`Total tasks: ${plan.tasks.length}`
|
|
1712
|
+
].join("\n");
|
|
1713
|
+
fs7.writeFileSync(spaceFullPath, spaceFrontmatter);
|
|
1714
|
+
}
|
|
1715
|
+
const threadPaths = [];
|
|
1716
|
+
const slugMap = /* @__PURE__ */ new Map();
|
|
1717
|
+
for (const task of plan.tasks) {
|
|
1718
|
+
const taskSlug = slugify(task.title);
|
|
1719
|
+
slugMap.set(task.title, taskSlug);
|
|
1720
|
+
}
|
|
1721
|
+
for (const task of plan.tasks) {
|
|
1722
|
+
const taskSlug = slugMap.get(task.title);
|
|
1723
|
+
let body = `# ${task.title}
|
|
1724
|
+
|
|
1725
|
+
${task.description}
|
|
1726
|
+
`;
|
|
1727
|
+
if (task.dependsOn && task.dependsOn.length > 0) {
|
|
1728
|
+
body += `
|
|
1729
|
+
## Dependencies
|
|
1730
|
+
`;
|
|
1731
|
+
for (const dep of task.dependsOn) {
|
|
1732
|
+
const depSlug = slugMap.get(dep);
|
|
1733
|
+
if (depSlug) {
|
|
1734
|
+
body += `- [[${depSlug}]]
|
|
1735
|
+
`;
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
body += `
|
|
1740
|
+
## Output
|
|
1741
|
+
|
|
1742
|
+
_Agent writes result here._
|
|
1743
|
+
`;
|
|
1744
|
+
if (task.tags && task.tags.length > 0) {
|
|
1745
|
+
body += `
|
|
1746
|
+
Tags: ${task.tags.join(", ")}
|
|
1747
|
+
`;
|
|
1748
|
+
}
|
|
1749
|
+
const created = createThread(workspacePath, task.title, body, actor, {
|
|
1750
|
+
priority: task.priority,
|
|
1751
|
+
space: `spaces/${spaceSlug}`
|
|
1752
|
+
});
|
|
1753
|
+
threadPaths.push(created.path);
|
|
1754
|
+
}
|
|
1755
|
+
const deployment = {
|
|
1756
|
+
planPath: path7.join(".workgraph", `swarm-${spaceSlug}.json`),
|
|
1757
|
+
workspacePath,
|
|
1758
|
+
threadPaths,
|
|
1759
|
+
spaceSlug,
|
|
1760
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1761
|
+
status: "deployed"
|
|
1762
|
+
};
|
|
1763
|
+
const manifestPath = path7.join(workspacePath, deployment.planPath);
|
|
1764
|
+
fs7.mkdirSync(path7.dirname(manifestPath), { recursive: true });
|
|
1765
|
+
fs7.writeFileSync(manifestPath, JSON.stringify({ plan, deployment }, null, 2));
|
|
1766
|
+
append(workspacePath, actor, "create", deployment.planPath, "swarm");
|
|
1767
|
+
return deployment;
|
|
1768
|
+
}
|
|
1769
|
+
function getSwarmStatus(workspacePath, spaceSlug) {
|
|
1770
|
+
const manifestPath = path7.join(workspacePath, ".workgraph", `swarm-${spaceSlug}.json`);
|
|
1771
|
+
if (!fs7.existsSync(manifestPath)) {
|
|
1772
|
+
throw new Error(`No swarm deployment found for space "${spaceSlug}"`);
|
|
1773
|
+
}
|
|
1774
|
+
const manifest = JSON.parse(fs7.readFileSync(manifestPath, "utf-8"));
|
|
1775
|
+
const deployment = manifest.deployment;
|
|
1776
|
+
const threads = [];
|
|
1777
|
+
let claimed = 0;
|
|
1778
|
+
let done2 = 0;
|
|
1779
|
+
let blocked = 0;
|
|
1780
|
+
let open = 0;
|
|
1781
|
+
for (const threadPath of deployment.threadPaths) {
|
|
1782
|
+
const t = read(workspacePath, threadPath);
|
|
1783
|
+
if (!t) continue;
|
|
1784
|
+
const status = String(t.fields.status ?? "open");
|
|
1785
|
+
const threadInfo = {
|
|
1786
|
+
path: threadPath,
|
|
1787
|
+
title: String(t.fields.title ?? ""),
|
|
1788
|
+
status,
|
|
1789
|
+
owner: t.fields.owner ? String(t.fields.owner) : void 0,
|
|
1790
|
+
priority: String(t.fields.priority ?? "medium")
|
|
1791
|
+
};
|
|
1792
|
+
threads.push(threadInfo);
|
|
1793
|
+
if (status === "done") done2++;
|
|
1794
|
+
else if (status === "active") claimed++;
|
|
1795
|
+
else if (status === "blocked") blocked++;
|
|
1796
|
+
else open++;
|
|
1797
|
+
}
|
|
1798
|
+
const total = deployment.threadPaths.length;
|
|
1799
|
+
const readyToClaim = open;
|
|
1800
|
+
const percentComplete = total > 0 ? Math.round(done2 / total * 100) : 0;
|
|
1801
|
+
if (done2 === total) deployment.status = "done";
|
|
1802
|
+
else if (claimed > 0 || done2 > 0) deployment.status = "running";
|
|
1803
|
+
return {
|
|
1804
|
+
deployment,
|
|
1805
|
+
total,
|
|
1806
|
+
claimed,
|
|
1807
|
+
done: done2,
|
|
1808
|
+
blocked,
|
|
1809
|
+
open,
|
|
1810
|
+
readyToClaim,
|
|
1811
|
+
percentComplete,
|
|
1812
|
+
threads
|
|
1813
|
+
};
|
|
1814
|
+
}
|
|
1815
|
+
function workerClaim(workspacePath, spaceSlug, agent) {
|
|
1816
|
+
const ready = listReadyThreadsInSpace(workspacePath, `spaces/${spaceSlug}`);
|
|
1817
|
+
if (ready.length === 0) return null;
|
|
1818
|
+
const priorityOrder = {
|
|
1819
|
+
critical: 0,
|
|
1820
|
+
high: 1,
|
|
1821
|
+
medium: 2,
|
|
1822
|
+
low: 3
|
|
1823
|
+
};
|
|
1824
|
+
ready.sort((a, b) => {
|
|
1825
|
+
const aPri = priorityOrder[String(a.fields.priority)] ?? 2;
|
|
1826
|
+
const bPri = priorityOrder[String(b.fields.priority)] ?? 2;
|
|
1827
|
+
return aPri - bPri;
|
|
1828
|
+
});
|
|
1829
|
+
const target = ready[0];
|
|
1830
|
+
return claim(workspacePath, target.path, agent);
|
|
1831
|
+
}
|
|
1832
|
+
function workerComplete(workspacePath, threadPath, agent, result) {
|
|
1833
|
+
const t = read(workspacePath, threadPath);
|
|
1834
|
+
if (!t) throw new Error(`Thread not found: ${threadPath}`);
|
|
1835
|
+
const currentBody = t.body ?? "";
|
|
1836
|
+
const updatedBody = currentBody.replace(
|
|
1837
|
+
"_Agent writes result here._",
|
|
1838
|
+
result
|
|
1839
|
+
);
|
|
1840
|
+
return done(workspacePath, threadPath, agent, updatedBody);
|
|
1841
|
+
}
|
|
1842
|
+
async function workerLoop(workspacePath, spaceSlug, agent, workFn, options) {
|
|
1843
|
+
let completed = 0;
|
|
1844
|
+
let errors = 0;
|
|
1845
|
+
const maxTasks = options?.maxTasks ?? Infinity;
|
|
1846
|
+
const delayMs = options?.delayMs ?? 1e3;
|
|
1847
|
+
while (completed + errors < maxTasks) {
|
|
1848
|
+
const claimed = workerClaim(workspacePath, spaceSlug, agent);
|
|
1849
|
+
if (!claimed) break;
|
|
1850
|
+
try {
|
|
1851
|
+
const result = await workFn(claimed);
|
|
1852
|
+
workerComplete(workspacePath, claimed.path, agent, result);
|
|
1853
|
+
completed++;
|
|
1854
|
+
} catch (err) {
|
|
1855
|
+
errors++;
|
|
1856
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
1857
|
+
try {
|
|
1858
|
+
update(workspacePath, claimed.path, {
|
|
1859
|
+
status: "blocked"
|
|
1860
|
+
}, `Error: ${errorMsg}`, agent);
|
|
1861
|
+
} catch {
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1864
|
+
if (delayMs > 0) {
|
|
1865
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
return { completed, errors };
|
|
1869
|
+
}
|
|
1870
|
+
function synthesize(workspacePath, spaceSlug) {
|
|
1871
|
+
const status = getSwarmStatus(workspacePath, spaceSlug);
|
|
1872
|
+
const sections = [];
|
|
1873
|
+
const manifestPath = path7.join(workspacePath, ".workgraph", `swarm-${spaceSlug}.json`);
|
|
1874
|
+
const manifest = JSON.parse(fs7.readFileSync(manifestPath, "utf-8"));
|
|
1875
|
+
const plan = manifest.plan;
|
|
1876
|
+
sections.push(`# ${plan.goal.title}
|
|
1877
|
+
`);
|
|
1878
|
+
sections.push(`${plan.goal.description}
|
|
1879
|
+
`);
|
|
1880
|
+
sections.push(`---
|
|
1881
|
+
`);
|
|
1882
|
+
for (const threadInfo of status.threads) {
|
|
1883
|
+
const t = read(workspacePath, threadInfo.path);
|
|
1884
|
+
if (!t) continue;
|
|
1885
|
+
if (threadInfo.status !== "done") {
|
|
1886
|
+
sections.push(`## [PENDING] ${threadInfo.title}
|
|
1887
|
+
|
|
1888
|
+
_Not yet completed._
|
|
1889
|
+
`);
|
|
1890
|
+
continue;
|
|
1891
|
+
}
|
|
1892
|
+
const body = t.body ?? "";
|
|
1893
|
+
const result = body.replace(/^#\s+.*\n/, "").trim();
|
|
1894
|
+
if (result && result !== "_Agent writes result here._") {
|
|
1895
|
+
sections.push(`## ${threadInfo.title}
|
|
1896
|
+
|
|
1897
|
+
${result}
|
|
1898
|
+
`);
|
|
1899
|
+
} else {
|
|
1900
|
+
sections.push(`## ${threadInfo.title}
|
|
1901
|
+
|
|
1902
|
+
_Completed but no output found._
|
|
1903
|
+
`);
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
sections.push(`
|
|
1907
|
+
---
|
|
1908
|
+
`);
|
|
1909
|
+
sections.push(`*Generated from swarm "${plan.goal.title}" \u2014 ${status.done}/${status.total} tasks completed.*
|
|
1910
|
+
`);
|
|
1911
|
+
return {
|
|
1912
|
+
markdown: sections.join("\n"),
|
|
1913
|
+
completedCount: status.done,
|
|
1914
|
+
totalCount: status.total
|
|
1915
|
+
};
|
|
1916
|
+
}
|
|
1917
|
+
function slugify(text) {
|
|
1918
|
+
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").substring(0, 80);
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1613
1921
|
// src/diagnostics/index.ts
|
|
1614
1922
|
var diagnostics_exports = {};
|
|
1615
1923
|
__export(diagnostics_exports, {
|
|
@@ -1625,8 +1933,8 @@ __export(diagnostics_exports, {
|
|
|
1625
1933
|
});
|
|
1626
1934
|
|
|
1627
1935
|
// src/diagnostics/doctor.ts
|
|
1628
|
-
import
|
|
1629
|
-
import
|
|
1936
|
+
import fs8 from "fs";
|
|
1937
|
+
import path9 from "path";
|
|
1630
1938
|
import YAML2 from "yaml";
|
|
1631
1939
|
|
|
1632
1940
|
// src/diagnostics/format.ts
|
|
@@ -1690,7 +1998,7 @@ function inferPrimitiveTypeFromPath(targetPath) {
|
|
|
1690
1998
|
}
|
|
1691
1999
|
|
|
1692
2000
|
// src/diagnostics/primitives.ts
|
|
1693
|
-
import
|
|
2001
|
+
import path8 from "path";
|
|
1694
2002
|
function loadPrimitiveInventory(workspacePath) {
|
|
1695
2003
|
const registry = loadRegistry(workspacePath);
|
|
1696
2004
|
const allPrimitives = queryPrimitives(workspacePath);
|
|
@@ -1708,7 +2016,7 @@ function loadPrimitiveInventory(workspacePath) {
|
|
|
1708
2016
|
const requiredFields = Object.entries(typeDef?.fields ?? {}).filter(([, fieldDef]) => fieldDef.required === true).map(([fieldName]) => fieldName);
|
|
1709
2017
|
const presentCount = requiredFields.filter((fieldName) => hasRequiredValue(instance.fields[fieldName])).length;
|
|
1710
2018
|
const frontmatterCompleteness = requiredFields.length === 0 ? 1 : presentCount / requiredFields.length;
|
|
1711
|
-
const slug =
|
|
2019
|
+
const slug = path8.basename(instance.path, ".md");
|
|
1712
2020
|
return {
|
|
1713
2021
|
...instance,
|
|
1714
2022
|
slug,
|
|
@@ -2050,8 +2358,8 @@ function collectStaleRuns(workspacePath, staleAfterMs, now) {
|
|
|
2050
2358
|
}
|
|
2051
2359
|
function collectPrimitiveRegistryReferenceIssues(workspacePath, inventory) {
|
|
2052
2360
|
const issues = [];
|
|
2053
|
-
const manifestPath =
|
|
2054
|
-
if (!
|
|
2361
|
+
const manifestPath = path9.join(workspacePath, ".workgraph", "primitive-registry.yaml");
|
|
2362
|
+
if (!fs8.existsSync(manifestPath)) {
|
|
2055
2363
|
issues.push({
|
|
2056
2364
|
code: "broken-primitive-registry-reference",
|
|
2057
2365
|
severity: "error",
|
|
@@ -2062,7 +2370,7 @@ function collectPrimitiveRegistryReferenceIssues(workspacePath, inventory) {
|
|
|
2062
2370
|
}
|
|
2063
2371
|
let parsed;
|
|
2064
2372
|
try {
|
|
2065
|
-
parsed = YAML2.parse(
|
|
2373
|
+
parsed = YAML2.parse(fs8.readFileSync(manifestPath, "utf-8"));
|
|
2066
2374
|
} catch (error) {
|
|
2067
2375
|
issues.push({
|
|
2068
2376
|
code: "broken-primitive-registry-reference",
|
|
@@ -2114,7 +2422,7 @@ function collectPrimitiveRegistryReferenceIssues(workspacePath, inventory) {
|
|
|
2114
2422
|
path: ".workgraph/primitive-registry.yaml"
|
|
2115
2423
|
});
|
|
2116
2424
|
}
|
|
2117
|
-
if (!
|
|
2425
|
+
if (!fs8.existsSync(path9.join(workspacePath, directory))) {
|
|
2118
2426
|
issues.push({
|
|
2119
2427
|
code: "broken-primitive-registry-reference",
|
|
2120
2428
|
severity: "error",
|
|
@@ -2149,8 +2457,8 @@ function collectPrimitiveRegistryReferenceIssues(workspacePath, inventory) {
|
|
|
2149
2457
|
function collectEmptyPrimitiveDirectoryIssues(workspacePath, inventory) {
|
|
2150
2458
|
const issues = [];
|
|
2151
2459
|
for (const typeDef of inventory.typeDefs.values()) {
|
|
2152
|
-
const directoryPath =
|
|
2153
|
-
if (!
|
|
2460
|
+
const directoryPath = path9.join(workspacePath, typeDef.directory);
|
|
2461
|
+
if (!fs8.existsSync(directoryPath)) continue;
|
|
2154
2462
|
const markdownCount = listMarkdownFilesRecursive(directoryPath).length;
|
|
2155
2463
|
if (markdownCount > 0) continue;
|
|
2156
2464
|
issues.push({
|
|
@@ -2179,10 +2487,10 @@ function removeOrphanLinks(workspacePath, orphanLinks) {
|
|
|
2179
2487
|
}
|
|
2180
2488
|
let removedLinks = 0;
|
|
2181
2489
|
for (const [sourcePath, tokenSet] of tokensBySource.entries()) {
|
|
2182
|
-
const absPath =
|
|
2183
|
-
if (!
|
|
2490
|
+
const absPath = path9.join(workspacePath, sourcePath);
|
|
2491
|
+
if (!fs8.existsSync(absPath)) continue;
|
|
2184
2492
|
try {
|
|
2185
|
-
const raw =
|
|
2493
|
+
const raw = fs8.readFileSync(absPath, "utf-8");
|
|
2186
2494
|
let fileRemoved = 0;
|
|
2187
2495
|
const updated = raw.replace(/\[\[([^[\]]+)\]\]/g, (token) => {
|
|
2188
2496
|
if (!tokenSet.has(token)) return token;
|
|
@@ -2190,7 +2498,7 @@ function removeOrphanLinks(workspacePath, orphanLinks) {
|
|
|
2190
2498
|
return "";
|
|
2191
2499
|
});
|
|
2192
2500
|
if (fileRemoved === 0) continue;
|
|
2193
|
-
|
|
2501
|
+
fs8.writeFileSync(absPath, updated, "utf-8");
|
|
2194
2502
|
removedLinks += fileRemoved;
|
|
2195
2503
|
filesUpdated.push(sourcePath);
|
|
2196
2504
|
} catch (error) {
|
|
@@ -2255,10 +2563,10 @@ function cancelStaleRuns(workspacePath, staleRuns, actor) {
|
|
|
2255
2563
|
return { cancelled, errors };
|
|
2256
2564
|
}
|
|
2257
2565
|
function readDispatchRunsSnapshot(workspacePath) {
|
|
2258
|
-
const runsPath =
|
|
2259
|
-
if (!
|
|
2566
|
+
const runsPath = path9.join(workspacePath, ".workgraph", "dispatch-runs.json");
|
|
2567
|
+
if (!fs8.existsSync(runsPath)) return [];
|
|
2260
2568
|
try {
|
|
2261
|
-
const parsed = JSON.parse(
|
|
2569
|
+
const parsed = JSON.parse(fs8.readFileSync(runsPath, "utf-8"));
|
|
2262
2570
|
return Array.isArray(parsed.runs) ? parsed.runs : [];
|
|
2263
2571
|
} catch {
|
|
2264
2572
|
return [];
|
|
@@ -2269,9 +2577,9 @@ function listMarkdownFilesRecursive(rootDirectory) {
|
|
|
2269
2577
|
const stack = [rootDirectory];
|
|
2270
2578
|
while (stack.length > 0) {
|
|
2271
2579
|
const current = stack.pop();
|
|
2272
|
-
const entries =
|
|
2580
|
+
const entries = fs8.readdirSync(current, { withFileTypes: true });
|
|
2273
2581
|
for (const entry of entries) {
|
|
2274
|
-
const absPath =
|
|
2582
|
+
const absPath = path9.join(current, entry.name);
|
|
2275
2583
|
if (entry.isDirectory()) {
|
|
2276
2584
|
stack.push(absPath);
|
|
2277
2585
|
continue;
|
|
@@ -2415,7 +2723,7 @@ function toNullableString(value) {
|
|
|
2415
2723
|
}
|
|
2416
2724
|
|
|
2417
2725
|
// src/diagnostics/viz.ts
|
|
2418
|
-
import
|
|
2726
|
+
import path10 from "path";
|
|
2419
2727
|
var TYPE_COLORS = ["cyan", "magenta", "yellow", "green", "blue", "red"];
|
|
2420
2728
|
function visualizeVaultGraph(workspacePath, options = {}) {
|
|
2421
2729
|
const inventory = loadPrimitiveInventory(workspacePath);
|
|
@@ -2555,7 +2863,7 @@ function resolveFocusPath(focusInput, inventory) {
|
|
|
2555
2863
|
const directCandidate = normalized.endsWith(".md") ? normalized : `${normalized}.md`;
|
|
2556
2864
|
if (inventory.byPath.has(normalized)) return normalized;
|
|
2557
2865
|
if (inventory.byPath.has(directCandidate)) return directCandidate;
|
|
2558
|
-
const slug =
|
|
2866
|
+
const slug = path10.basename(normalized, ".md");
|
|
2559
2867
|
const candidates = inventory.slugToPaths.get(slug) ?? [];
|
|
2560
2868
|
if (candidates.length === 1) return candidates[0];
|
|
2561
2869
|
if (candidates.length > 1) {
|
|
@@ -2863,8 +3171,8 @@ __export(autonomy_daemon_exports, {
|
|
|
2863
3171
|
startAutonomyDaemon: () => startAutonomyDaemon,
|
|
2864
3172
|
stopAutonomyDaemon: () => stopAutonomyDaemon
|
|
2865
3173
|
});
|
|
2866
|
-
import
|
|
2867
|
-
import
|
|
3174
|
+
import fs9 from "fs";
|
|
3175
|
+
import path11 from "path";
|
|
2868
3176
|
import { spawn } from "child_process";
|
|
2869
3177
|
var DAEMON_DIR = ".workgraph/daemon";
|
|
2870
3178
|
var AUTONOMY_PID_FILE = "autonomy.pid";
|
|
@@ -2873,29 +3181,29 @@ var AUTONOMY_LOG_FILE = "autonomy.log";
|
|
|
2873
3181
|
var AUTONOMY_META_FILE = "autonomy-process.json";
|
|
2874
3182
|
function startAutonomyDaemon(workspacePath, input) {
|
|
2875
3183
|
const daemonDir = ensureDaemonDir(workspacePath);
|
|
2876
|
-
const pidPath =
|
|
2877
|
-
const heartbeatPath = input.heartbeatPath ? resolvePathWithinWorkspace4(workspacePath, input.heartbeatPath) :
|
|
2878
|
-
const logPath = input.logPath ? resolvePathWithinWorkspace4(workspacePath, input.logPath) :
|
|
2879
|
-
const metaPath =
|
|
3184
|
+
const pidPath = path11.join(daemonDir, AUTONOMY_PID_FILE);
|
|
3185
|
+
const heartbeatPath = input.heartbeatPath ? resolvePathWithinWorkspace4(workspacePath, input.heartbeatPath) : path11.join(daemonDir, AUTONOMY_HEARTBEAT_FILE);
|
|
3186
|
+
const logPath = input.logPath ? resolvePathWithinWorkspace4(workspacePath, input.logPath) : path11.join(daemonDir, AUTONOMY_LOG_FILE);
|
|
3187
|
+
const metaPath = path11.join(daemonDir, AUTONOMY_META_FILE);
|
|
2880
3188
|
const existing = readAutonomyDaemonStatus(workspacePath, { cleanupStalePidFile: true });
|
|
2881
3189
|
if (existing.running) {
|
|
2882
3190
|
throw new Error(`Autonomy daemon already running (pid=${existing.pid}). Stop it before starting a new one.`);
|
|
2883
3191
|
}
|
|
2884
|
-
const logFd =
|
|
3192
|
+
const logFd = fs9.openSync(logPath, "a");
|
|
2885
3193
|
const args = buildAutonomyDaemonArgs(workspacePath, input, heartbeatPath);
|
|
2886
3194
|
const child = spawn(process.execPath, args, {
|
|
2887
3195
|
detached: true,
|
|
2888
3196
|
stdio: ["ignore", logFd, logFd],
|
|
2889
3197
|
env: process.env
|
|
2890
3198
|
});
|
|
2891
|
-
|
|
3199
|
+
fs9.closeSync(logFd);
|
|
2892
3200
|
child.unref();
|
|
2893
3201
|
if (!child.pid) {
|
|
2894
3202
|
throw new Error("Failed to start autonomy daemon: missing child process pid.");
|
|
2895
3203
|
}
|
|
2896
|
-
|
|
3204
|
+
fs9.writeFileSync(pidPath, `${child.pid}
|
|
2897
3205
|
`, "utf-8");
|
|
2898
|
-
|
|
3206
|
+
fs9.writeFileSync(metaPath, JSON.stringify({
|
|
2899
3207
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2900
3208
|
pid: child.pid,
|
|
2901
3209
|
args,
|
|
@@ -2929,9 +3237,9 @@ async function stopAutonomyDaemon(workspacePath, input = {}) {
|
|
|
2929
3237
|
await waitForProcessExit(pid, 1500);
|
|
2930
3238
|
stopped = !isProcessAlive(pid);
|
|
2931
3239
|
}
|
|
2932
|
-
const pidPath =
|
|
2933
|
-
if (stopped &&
|
|
2934
|
-
|
|
3240
|
+
const pidPath = path11.join(ensureDaemonDir(workspacePath), AUTONOMY_PID_FILE);
|
|
3241
|
+
if (stopped && fs9.existsSync(pidPath)) {
|
|
3242
|
+
fs9.rmSync(pidPath, { force: true });
|
|
2935
3243
|
}
|
|
2936
3244
|
return {
|
|
2937
3245
|
stopped,
|
|
@@ -2942,14 +3250,14 @@ async function stopAutonomyDaemon(workspacePath, input = {}) {
|
|
|
2942
3250
|
}
|
|
2943
3251
|
function readAutonomyDaemonStatus(workspacePath, options = {}) {
|
|
2944
3252
|
const daemonDir = ensureDaemonDir(workspacePath);
|
|
2945
|
-
const pidPath =
|
|
2946
|
-
const meta = readDaemonMeta(
|
|
2947
|
-
const logPath = meta?.logPath ? String(meta.logPath) :
|
|
2948
|
-
const heartbeatPath = meta?.heartbeatPath ? String(meta.heartbeatPath) :
|
|
3253
|
+
const pidPath = path11.join(daemonDir, AUTONOMY_PID_FILE);
|
|
3254
|
+
const meta = readDaemonMeta(path11.join(daemonDir, AUTONOMY_META_FILE));
|
|
3255
|
+
const logPath = meta?.logPath ? String(meta.logPath) : path11.join(daemonDir, AUTONOMY_LOG_FILE);
|
|
3256
|
+
const heartbeatPath = meta?.heartbeatPath ? String(meta.heartbeatPath) : path11.join(daemonDir, AUTONOMY_HEARTBEAT_FILE);
|
|
2949
3257
|
const pid = readPid(pidPath);
|
|
2950
3258
|
const running = pid ? isProcessAlive(pid) : false;
|
|
2951
|
-
if (!running && pid && options.cleanupStalePidFile !== false &&
|
|
2952
|
-
|
|
3259
|
+
if (!running && pid && options.cleanupStalePidFile !== false && fs9.existsSync(pidPath)) {
|
|
3260
|
+
fs9.rmSync(pidPath, { force: true });
|
|
2953
3261
|
}
|
|
2954
3262
|
return {
|
|
2955
3263
|
running,
|
|
@@ -2962,7 +3270,7 @@ function readAutonomyDaemonStatus(workspacePath, options = {}) {
|
|
|
2962
3270
|
}
|
|
2963
3271
|
function buildAutonomyDaemonArgs(workspacePath, input, heartbeatPath) {
|
|
2964
3272
|
const args = [
|
|
2965
|
-
|
|
3273
|
+
path11.resolve(input.cliEntrypointPath),
|
|
2966
3274
|
"autonomy",
|
|
2967
3275
|
"run",
|
|
2968
3276
|
"-w",
|
|
@@ -3020,22 +3328,22 @@ function waitForProcessExit(pid, timeoutMs) {
|
|
|
3020
3328
|
});
|
|
3021
3329
|
}
|
|
3022
3330
|
function ensureDaemonDir(workspacePath) {
|
|
3023
|
-
const daemonDir =
|
|
3024
|
-
if (!
|
|
3331
|
+
const daemonDir = path11.join(workspacePath, DAEMON_DIR);
|
|
3332
|
+
if (!fs9.existsSync(daemonDir)) fs9.mkdirSync(daemonDir, { recursive: true });
|
|
3025
3333
|
return daemonDir;
|
|
3026
3334
|
}
|
|
3027
3335
|
function readPid(pidPath) {
|
|
3028
|
-
if (!
|
|
3029
|
-
const raw =
|
|
3336
|
+
if (!fs9.existsSync(pidPath)) return void 0;
|
|
3337
|
+
const raw = fs9.readFileSync(pidPath, "utf-8").trim();
|
|
3030
3338
|
if (!raw) return void 0;
|
|
3031
3339
|
const parsed = Number(raw);
|
|
3032
3340
|
if (!Number.isInteger(parsed) || parsed <= 0) return void 0;
|
|
3033
3341
|
return parsed;
|
|
3034
3342
|
}
|
|
3035
3343
|
function readHeartbeat(heartbeatPath) {
|
|
3036
|
-
if (!
|
|
3344
|
+
if (!fs9.existsSync(heartbeatPath)) return void 0;
|
|
3037
3345
|
try {
|
|
3038
|
-
const parsed = JSON.parse(
|
|
3346
|
+
const parsed = JSON.parse(fs9.readFileSync(heartbeatPath, "utf-8"));
|
|
3039
3347
|
if (!parsed || typeof parsed !== "object") return void 0;
|
|
3040
3348
|
return parsed;
|
|
3041
3349
|
} catch {
|
|
@@ -3043,9 +3351,9 @@ function readHeartbeat(heartbeatPath) {
|
|
|
3043
3351
|
}
|
|
3044
3352
|
}
|
|
3045
3353
|
function readDaemonMeta(metaPath) {
|
|
3046
|
-
if (!
|
|
3354
|
+
if (!fs9.existsSync(metaPath)) return void 0;
|
|
3047
3355
|
try {
|
|
3048
|
-
const parsed = JSON.parse(
|
|
3356
|
+
const parsed = JSON.parse(fs9.readFileSync(metaPath, "utf-8"));
|
|
3049
3357
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
|
|
3050
3358
|
return parsed;
|
|
3051
3359
|
} catch {
|
|
@@ -3063,9 +3371,9 @@ function isProcessAlive(pid) {
|
|
|
3063
3371
|
}
|
|
3064
3372
|
function isZombieProcess(pid) {
|
|
3065
3373
|
const statPath = `/proc/${pid}/stat`;
|
|
3066
|
-
if (!
|
|
3374
|
+
if (!fs9.existsSync(statPath)) return false;
|
|
3067
3375
|
try {
|
|
3068
|
-
const stat =
|
|
3376
|
+
const stat = fs9.readFileSync(statPath, "utf-8");
|
|
3069
3377
|
const closingIdx = stat.indexOf(")");
|
|
3070
3378
|
if (closingIdx === -1 || closingIdx + 2 >= stat.length) return false;
|
|
3071
3379
|
const state = stat.slice(closingIdx + 2, closingIdx + 3);
|
|
@@ -3075,9 +3383,9 @@ function isZombieProcess(pid) {
|
|
|
3075
3383
|
}
|
|
3076
3384
|
}
|
|
3077
3385
|
function resolvePathWithinWorkspace4(workspacePath, filePath) {
|
|
3078
|
-
const base =
|
|
3079
|
-
const resolved =
|
|
3080
|
-
if (!resolved.startsWith(base +
|
|
3386
|
+
const base = path11.resolve(workspacePath);
|
|
3387
|
+
const resolved = path11.resolve(base, filePath);
|
|
3388
|
+
if (!resolved.startsWith(base + path11.sep) && resolved !== base) {
|
|
3081
3389
|
throw new Error(`Invalid path outside workspace: ${filePath}`);
|
|
3082
3390
|
}
|
|
3083
3391
|
return resolved;
|
|
@@ -3102,6 +3410,7 @@ export {
|
|
|
3102
3410
|
fetchSkillMarkdownFromUrl,
|
|
3103
3411
|
clawdapus_exports,
|
|
3104
3412
|
integration_exports,
|
|
3413
|
+
swarm_exports,
|
|
3105
3414
|
diagnostics_exports,
|
|
3106
3415
|
autonomy_daemon_exports
|
|
3107
3416
|
};
|
package/dist/cli.js
CHANGED
|
@@ -11,9 +11,10 @@ import {
|
|
|
11
11
|
onboard_exports,
|
|
12
12
|
search_qmd_adapter_exports,
|
|
13
13
|
skill_exports,
|
|
14
|
+
swarm_exports,
|
|
14
15
|
trigger_exports,
|
|
15
16
|
workspace_exports
|
|
16
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-MCHTUXG2.js";
|
|
17
18
|
import {
|
|
18
19
|
autonomy_exports,
|
|
19
20
|
dispatch_exports,
|
|
@@ -29,7 +30,7 @@ import {
|
|
|
29
30
|
thread_audit_exports,
|
|
30
31
|
thread_exports,
|
|
31
32
|
trigger_engine_exports
|
|
32
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-G6B47IBD.js";
|
|
33
34
|
|
|
34
35
|
// src/cli.ts
|
|
35
36
|
import fs from "fs";
|
|
@@ -1898,6 +1899,85 @@ addWorkspaceOption(
|
|
|
1898
1899
|
readOnly: !!opts.readOnly
|
|
1899
1900
|
});
|
|
1900
1901
|
});
|
|
1902
|
+
var swarmCmd = program.command("swarm").description("Decompose goals into tasks and orchestrate agent swarms");
|
|
1903
|
+
addWorkspaceOption(
|
|
1904
|
+
swarmCmd.command("deploy <planFile>").description("Deploy a swarm plan (JSON) into the workspace as threads").option("-a, --actor <name>", "Actor name", DEFAULT_ACTOR).option("--json", "Emit structured JSON output")
|
|
1905
|
+
).action(
|
|
1906
|
+
(planFile, opts) => runCommand(
|
|
1907
|
+
opts,
|
|
1908
|
+
() => {
|
|
1909
|
+
const workspacePath = resolveWorkspacePath(opts);
|
|
1910
|
+
const planPath = path.resolve(planFile);
|
|
1911
|
+
const planData = JSON.parse(fs.readFileSync(planPath, "utf-8"));
|
|
1912
|
+
return swarm_exports.deployPlan(workspacePath, planData, opts.actor);
|
|
1913
|
+
},
|
|
1914
|
+
(result) => [
|
|
1915
|
+
`Swarm deployed: ${result.spaceSlug}`,
|
|
1916
|
+
`Threads: ${result.threadPaths.length}`,
|
|
1917
|
+
`Status: ${result.status}`
|
|
1918
|
+
]
|
|
1919
|
+
)
|
|
1920
|
+
);
|
|
1921
|
+
addWorkspaceOption(
|
|
1922
|
+
swarmCmd.command("status <spaceSlug>").description("Show swarm progress").option("--json", "Emit structured JSON output")
|
|
1923
|
+
).action(
|
|
1924
|
+
(spaceSlug, opts) => runCommand(
|
|
1925
|
+
opts,
|
|
1926
|
+
() => swarm_exports.getSwarmStatus(resolveWorkspacePath(opts), spaceSlug),
|
|
1927
|
+
(result) => [
|
|
1928
|
+
`Swarm: ${result.deployment.spaceSlug} [${result.deployment.status}]`,
|
|
1929
|
+
`Progress: ${result.done}/${result.total} (${result.percentComplete}%)`,
|
|
1930
|
+
`Claimed: ${result.claimed} | Open: ${result.open} | Blocked: ${result.blocked}`,
|
|
1931
|
+
`Ready to claim: ${result.readyToClaim}`
|
|
1932
|
+
]
|
|
1933
|
+
)
|
|
1934
|
+
);
|
|
1935
|
+
addWorkspaceOption(
|
|
1936
|
+
swarmCmd.command("claim <spaceSlug>").description("Claim the next available task in a swarm").option("-a, --actor <name>", "Worker agent name", DEFAULT_ACTOR).option("--json", "Emit structured JSON output")
|
|
1937
|
+
).action(
|
|
1938
|
+
(spaceSlug, opts) => runCommand(
|
|
1939
|
+
opts,
|
|
1940
|
+
() => {
|
|
1941
|
+
const result = swarm_exports.workerClaim(resolveWorkspacePath(opts), spaceSlug, opts.actor);
|
|
1942
|
+
if (!result) return { claimed: false, message: "No tasks available" };
|
|
1943
|
+
return { claimed: true, path: result.path, title: result.fields.title };
|
|
1944
|
+
},
|
|
1945
|
+
(result) => result.claimed ? [`Claimed: ${result.path} \u2014 ${result.title}`] : ["No tasks available to claim"]
|
|
1946
|
+
)
|
|
1947
|
+
);
|
|
1948
|
+
addWorkspaceOption(
|
|
1949
|
+
swarmCmd.command("complete <threadPath>").description("Mark a swarm task as done with result").option("-a, --actor <name>", "Worker agent name", DEFAULT_ACTOR).requiredOption("--result <text>", "Result text (or @file to read from file)").option("--json", "Emit structured JSON output")
|
|
1950
|
+
).action(
|
|
1951
|
+
(threadPath, opts) => runCommand(
|
|
1952
|
+
opts,
|
|
1953
|
+
() => {
|
|
1954
|
+
let resultText = opts.result;
|
|
1955
|
+
if (resultText.startsWith("@")) {
|
|
1956
|
+
resultText = fs.readFileSync(resultText.slice(1), "utf-8");
|
|
1957
|
+
}
|
|
1958
|
+
return swarm_exports.workerComplete(resolveWorkspacePath(opts), threadPath, opts.actor, resultText);
|
|
1959
|
+
},
|
|
1960
|
+
(result) => [`Completed: ${result.path}`]
|
|
1961
|
+
)
|
|
1962
|
+
);
|
|
1963
|
+
addWorkspaceOption(
|
|
1964
|
+
swarmCmd.command("synthesize <spaceSlug>").description("Merge all completed task results into a single document").option("-o, --output <file>", "Output file path").option("--json", "Emit structured JSON output")
|
|
1965
|
+
).action(
|
|
1966
|
+
(spaceSlug, opts) => runCommand(
|
|
1967
|
+
opts,
|
|
1968
|
+
() => {
|
|
1969
|
+
const result = swarm_exports.synthesize(resolveWorkspacePath(opts), spaceSlug);
|
|
1970
|
+
if (opts.output) {
|
|
1971
|
+
fs.writeFileSync(path.resolve(opts.output), result.markdown);
|
|
1972
|
+
}
|
|
1973
|
+
return result;
|
|
1974
|
+
},
|
|
1975
|
+
(result) => [
|
|
1976
|
+
`Synthesized: ${result.completedCount}/${result.totalCount} tasks`,
|
|
1977
|
+
opts.output ? `Written to: ${opts.output}` : result.markdown
|
|
1978
|
+
]
|
|
1979
|
+
)
|
|
1980
|
+
);
|
|
1901
1981
|
await program.parseAsync();
|
|
1902
1982
|
function addWorkspaceOption(command) {
|
|
1903
1983
|
return command.option("-w, --workspace <path>", "Workgraph workspace path").option("--vault <path>", "Alias for --workspace").option("--shared-vault <path>", "Shared vault path (e.g. mounted via Tailscale)").option("--dry-run", "Execute against a temporary workspace copy and discard changes");
|
package/dist/index.d.ts
CHANGED
|
@@ -1448,6 +1448,144 @@ declare function parseCronExpression(expression: string): CronSchedule;
|
|
|
1448
1448
|
declare function matchesCronSchedule(schedule: CronSchedule, date: Date): boolean;
|
|
1449
1449
|
declare function nextCronMatch(scheduleOrExpression: CronSchedule | string, after: Date, maxSearchMinutes?: number): Date | null;
|
|
1450
1450
|
|
|
1451
|
+
/**
|
|
1452
|
+
* WorkGraph Swarm — Decompose goals into hundreds of tasks,
|
|
1453
|
+
* spawn agent containers to claim and complete them, merge results.
|
|
1454
|
+
*
|
|
1455
|
+
* Architecture:
|
|
1456
|
+
* 1. Planner: Takes a goal → decomposes into N threads with dependencies
|
|
1457
|
+
* 2. Orchestrator: Spawns containers, each runs a worker that claims threads
|
|
1458
|
+
* 3. Worker: Claims a thread, does work, writes result, marks done
|
|
1459
|
+
* 4. Synthesizer: Watches for completion, merges results
|
|
1460
|
+
*/
|
|
1461
|
+
|
|
1462
|
+
interface SwarmGoal {
|
|
1463
|
+
title: string;
|
|
1464
|
+
description: string;
|
|
1465
|
+
outputFormat?: 'markdown' | 'json' | 'code';
|
|
1466
|
+
maxTasks?: number;
|
|
1467
|
+
maxConcurrent?: number;
|
|
1468
|
+
tags?: string[];
|
|
1469
|
+
}
|
|
1470
|
+
interface SwarmTask {
|
|
1471
|
+
title: string;
|
|
1472
|
+
description: string;
|
|
1473
|
+
priority: 'critical' | 'high' | 'medium' | 'low';
|
|
1474
|
+
dependsOn?: string[];
|
|
1475
|
+
estimatedMinutes?: number;
|
|
1476
|
+
outputType?: string;
|
|
1477
|
+
tags?: string[];
|
|
1478
|
+
}
|
|
1479
|
+
interface SwarmPlan {
|
|
1480
|
+
goal: SwarmGoal;
|
|
1481
|
+
tasks: SwarmTask[];
|
|
1482
|
+
phases: SwarmPhase[];
|
|
1483
|
+
createdAt: string;
|
|
1484
|
+
estimatedTotalMinutes: number;
|
|
1485
|
+
}
|
|
1486
|
+
interface SwarmPhase {
|
|
1487
|
+
name: string;
|
|
1488
|
+
description: string;
|
|
1489
|
+
taskIndices: number[];
|
|
1490
|
+
parallel: boolean;
|
|
1491
|
+
}
|
|
1492
|
+
interface SwarmDeployment {
|
|
1493
|
+
planPath: string;
|
|
1494
|
+
workspacePath: string;
|
|
1495
|
+
threadPaths: string[];
|
|
1496
|
+
spaceSlug: string;
|
|
1497
|
+
createdAt: string;
|
|
1498
|
+
status: 'deployed' | 'running' | 'completing' | 'done' | 'failed';
|
|
1499
|
+
}
|
|
1500
|
+
interface SwarmStatus {
|
|
1501
|
+
deployment: SwarmDeployment;
|
|
1502
|
+
total: number;
|
|
1503
|
+
claimed: number;
|
|
1504
|
+
done: number;
|
|
1505
|
+
blocked: number;
|
|
1506
|
+
open: number;
|
|
1507
|
+
readyToClaim: number;
|
|
1508
|
+
percentComplete: number;
|
|
1509
|
+
threads: Array<{
|
|
1510
|
+
path: string;
|
|
1511
|
+
title: string;
|
|
1512
|
+
status: string;
|
|
1513
|
+
owner?: string;
|
|
1514
|
+
priority: string;
|
|
1515
|
+
}>;
|
|
1516
|
+
}
|
|
1517
|
+
/**
|
|
1518
|
+
* Generate a swarm plan from a goal description.
|
|
1519
|
+
* This creates the plan structure — call deployPlan() to create actual threads.
|
|
1520
|
+
*
|
|
1521
|
+
* In production, pipe goal through an LLM for decomposition.
|
|
1522
|
+
* This function provides the structured output format the LLM should produce.
|
|
1523
|
+
*/
|
|
1524
|
+
declare function createPlanTemplate(goal: SwarmGoal): SwarmPlan;
|
|
1525
|
+
/**
|
|
1526
|
+
* Validate a swarm plan for internal consistency.
|
|
1527
|
+
*/
|
|
1528
|
+
declare function validatePlan(plan: SwarmPlan): {
|
|
1529
|
+
valid: boolean;
|
|
1530
|
+
errors: string[];
|
|
1531
|
+
};
|
|
1532
|
+
/**
|
|
1533
|
+
* Deploy a swarm plan into a WorkGraph workspace.
|
|
1534
|
+
* Creates a space for the swarm and threads for each task.
|
|
1535
|
+
* Dependencies are encoded as wiki-links in thread bodies.
|
|
1536
|
+
*/
|
|
1537
|
+
declare function deployPlan(workspacePath: string, plan: SwarmPlan, actor: string): SwarmDeployment;
|
|
1538
|
+
/**
|
|
1539
|
+
* Get the current status of a swarm deployment.
|
|
1540
|
+
*/
|
|
1541
|
+
declare function getSwarmStatus(workspacePath: string, spaceSlug: string): SwarmStatus;
|
|
1542
|
+
/**
|
|
1543
|
+
* Worker claims the next available task in a swarm.
|
|
1544
|
+
* Returns the thread to work on, or null if nothing available.
|
|
1545
|
+
*/
|
|
1546
|
+
declare function workerClaim(workspacePath: string, spaceSlug: string, agent: string): PrimitiveInstance | null;
|
|
1547
|
+
/**
|
|
1548
|
+
* Worker completes a task, writing result to the thread body.
|
|
1549
|
+
*/
|
|
1550
|
+
declare function workerComplete(workspacePath: string, threadPath: string, agent: string, result: string): PrimitiveInstance;
|
|
1551
|
+
/**
|
|
1552
|
+
* Worker loop: claim → work → complete → repeat until no tasks left.
|
|
1553
|
+
* The workFn receives the thread and returns the result string.
|
|
1554
|
+
*/
|
|
1555
|
+
declare function workerLoop(workspacePath: string, spaceSlug: string, agent: string, workFn: (thread: PrimitiveInstance) => Promise<string>, options?: {
|
|
1556
|
+
maxTasks?: number;
|
|
1557
|
+
delayMs?: number;
|
|
1558
|
+
}): Promise<{
|
|
1559
|
+
completed: number;
|
|
1560
|
+
errors: number;
|
|
1561
|
+
}>;
|
|
1562
|
+
/**
|
|
1563
|
+
* Collect all completed task results from a swarm into a single document.
|
|
1564
|
+
*/
|
|
1565
|
+
declare function synthesize(workspacePath: string, spaceSlug: string): {
|
|
1566
|
+
markdown: string;
|
|
1567
|
+
completedCount: number;
|
|
1568
|
+
totalCount: number;
|
|
1569
|
+
};
|
|
1570
|
+
|
|
1571
|
+
type swarm_SwarmDeployment = SwarmDeployment;
|
|
1572
|
+
type swarm_SwarmGoal = SwarmGoal;
|
|
1573
|
+
type swarm_SwarmPhase = SwarmPhase;
|
|
1574
|
+
type swarm_SwarmPlan = SwarmPlan;
|
|
1575
|
+
type swarm_SwarmStatus = SwarmStatus;
|
|
1576
|
+
type swarm_SwarmTask = SwarmTask;
|
|
1577
|
+
declare const swarm_createPlanTemplate: typeof createPlanTemplate;
|
|
1578
|
+
declare const swarm_deployPlan: typeof deployPlan;
|
|
1579
|
+
declare const swarm_getSwarmStatus: typeof getSwarmStatus;
|
|
1580
|
+
declare const swarm_synthesize: typeof synthesize;
|
|
1581
|
+
declare const swarm_validatePlan: typeof validatePlan;
|
|
1582
|
+
declare const swarm_workerClaim: typeof workerClaim;
|
|
1583
|
+
declare const swarm_workerComplete: typeof workerComplete;
|
|
1584
|
+
declare const swarm_workerLoop: typeof workerLoop;
|
|
1585
|
+
declare namespace swarm {
|
|
1586
|
+
export { type swarm_SwarmDeployment as SwarmDeployment, type swarm_SwarmGoal as SwarmGoal, type swarm_SwarmPhase as SwarmPhase, type swarm_SwarmPlan as SwarmPlan, type swarm_SwarmStatus as SwarmStatus, type swarm_SwarmTask as SwarmTask, swarm_createPlanTemplate as createPlanTemplate, swarm_deployPlan as deployPlan, swarm_getSwarmStatus as getSwarmStatus, swarm_synthesize as synthesize, swarm_validatePlan as validatePlan, swarm_workerClaim as workerClaim, swarm_workerComplete as workerComplete, swarm_workerLoop as workerLoop };
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1451
1589
|
type DoctorSeverity = 'warning' | 'error';
|
|
1452
1590
|
interface DoctorIssue {
|
|
1453
1591
|
code: string;
|
|
@@ -1780,4 +1918,4 @@ declare class CursorCloudAdapter implements DispatchAdapter {
|
|
|
1780
1918
|
execute(input: DispatchAdapterExecutionInput): Promise<DispatchAdapterExecutionResult>;
|
|
1781
1919
|
}
|
|
1782
1920
|
|
|
1783
|
-
export { type CronField, type CronSchedule, CursorCloudAdapter, type DispatchAdapter, type DispatchAdapterCreateInput, type DispatchAdapterExecutionInput, type DispatchAdapterExecutionResult, type DispatchAdapterLogEntry, type DispatchAdapterRunStatus, type DispatchRun, type FieldDefinition, type InstallSkillIntegrationOptions, type InstallSkillIntegrationResult, type LedgerChainState, type LedgerEntry, type LedgerIndex, type LedgerOp, type PolicyParty, type PolicyRegistry, type PrimitiveInstance, type PrimitiveQueryFilters, type PrimitiveTypeDefinition, type Registry, type RunStatus, type SkillIntegrationProvider, THREAD_STATUS_TRANSITIONS, type ThreadStatus, type WorkgraphBrief, type WorkgraphLensDescriptor, type WorkgraphLensId, type WorkgraphLensItem, type WorkgraphLensOptions, type WorkgraphLensResult, type WorkgraphLensSection, type WorkgraphMaterializeLensOptions, type WorkgraphMaterializedLensResult, type WorkgraphStatusSnapshot, type WorkgraphWorkspaceConfig, agent, autonomy, autonomyDaemon, bases, board, claimLease, clawdapus, commandCenter, index as diagnostics, dispatch, fetchSkillMarkdownFromUrl, gate, graph, installSkillIntegration, integration, ledger, lens, matchesCronSchedule, nextCronMatch, onboard, orientation, parseCronExpression, policy, query, registry, searchQmdAdapter, skill, store, thread, threadAudit, trigger, triggerEngine, workspace };
|
|
1921
|
+
export { type CronField, type CronSchedule, CursorCloudAdapter, type DispatchAdapter, type DispatchAdapterCreateInput, type DispatchAdapterExecutionInput, type DispatchAdapterExecutionResult, type DispatchAdapterLogEntry, type DispatchAdapterRunStatus, type DispatchRun, type FieldDefinition, type InstallSkillIntegrationOptions, type InstallSkillIntegrationResult, type LedgerChainState, type LedgerEntry, type LedgerIndex, type LedgerOp, type PolicyParty, type PolicyRegistry, type PrimitiveInstance, type PrimitiveQueryFilters, type PrimitiveTypeDefinition, type Registry, type RunStatus, type SkillIntegrationProvider, THREAD_STATUS_TRANSITIONS, type ThreadStatus, type WorkgraphBrief, type WorkgraphLensDescriptor, type WorkgraphLensId, type WorkgraphLensItem, type WorkgraphLensOptions, type WorkgraphLensResult, type WorkgraphLensSection, type WorkgraphMaterializeLensOptions, type WorkgraphMaterializedLensResult, type WorkgraphStatusSnapshot, type WorkgraphWorkspaceConfig, agent, autonomy, autonomyDaemon, bases, board, claimLease, clawdapus, commandCenter, index as diagnostics, dispatch, fetchSkillMarkdownFromUrl, gate, graph, installSkillIntegration, integration, ledger, lens, matchesCronSchedule, nextCronMatch, onboard, orientation, parseCronExpression, policy, query, registry, searchQmdAdapter, skill, store, swarm, thread, threadAudit, trigger, triggerEngine, workspace };
|
package/dist/index.js
CHANGED
|
@@ -13,9 +13,10 @@ import {
|
|
|
13
13
|
onboard_exports,
|
|
14
14
|
search_qmd_adapter_exports,
|
|
15
15
|
skill_exports,
|
|
16
|
+
swarm_exports,
|
|
16
17
|
trigger_exports,
|
|
17
18
|
workspace_exports
|
|
18
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-MCHTUXG2.js";
|
|
19
20
|
import {
|
|
20
21
|
CursorCloudAdapter,
|
|
21
22
|
THREAD_STATUS_TRANSITIONS,
|
|
@@ -37,7 +38,7 @@ import {
|
|
|
37
38
|
thread_audit_exports,
|
|
38
39
|
thread_exports,
|
|
39
40
|
trigger_engine_exports
|
|
40
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-G6B47IBD.js";
|
|
41
42
|
export {
|
|
42
43
|
CursorCloudAdapter,
|
|
43
44
|
THREAD_STATUS_TRANSITIONS,
|
|
@@ -70,6 +71,7 @@ export {
|
|
|
70
71
|
search_qmd_adapter_exports as searchQmdAdapter,
|
|
71
72
|
skill_exports as skill,
|
|
72
73
|
store_exports as store,
|
|
74
|
+
swarm_exports as swarm,
|
|
73
75
|
thread_exports as thread,
|
|
74
76
|
thread_audit_exports as threadAudit,
|
|
75
77
|
trigger_exports as trigger,
|
package/dist/mcp-server.js
CHANGED
package/package.json
CHANGED