@gonzih/cc-agent 0.15.23 → 0.15.25

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
@@ -20,13 +20,14 @@
20
20
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
21
21
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
22
22
  import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
23
- import { JobManager, normalizeRepoUrl } from "./agent.js";
23
+ import { JobManager, repoKey, normalizeRepoUrl } from "./agent.js";
24
24
  import { listDrivers, getDriverStatus } from "./drivers/index.js";
25
25
  import { runSwarm, getSwarmStatus, SWARM_MAX_AGENTS_HARD_CAP } from "./swarm.js";
26
+ import { runWorkflow, getWorkflowStatus, WORKFLOW_MAX_STAGES_HARD_CAP } from "./workflow.js";
26
27
  import { MetaAgentManager } from "./meta-agent.js";
27
28
  import { buildEvaluatorTask } from "./evaluator.js";
28
29
  import { loadProfiles, upsertProfile, deleteProfile, getProfile, interpolate } from "./profiles.js";
29
- import { planStore, jobStore, learningsStore, profileStore } from "./store.js";
30
+ import { planStore, jobStore, learningsStore, profileStore, wikiStore } from "./store.js";
30
31
  import { seedBuiltinProfiles } from "./seeds.js";
31
32
  import { getNamespace } from "./namespace.js";
32
33
  import { initRedis, getRedis } from "./redis.js";
@@ -535,6 +536,92 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
535
536
  },
536
537
  },
537
538
  },
539
+ {
540
+ name: "get_wiki",
541
+ description: "Return all wiki pages for a repo. Wiki pages are structured knowledge injected automatically into every spawn_agent call for the repo. Use this to inspect what knowledge is stored.",
542
+ inputSchema: {
543
+ type: "object",
544
+ properties: {
545
+ repo_url: {
546
+ type: "string",
547
+ description: "Repository URL, e.g. 'https://github.com/gonzih/cc-agent'",
548
+ },
549
+ },
550
+ required: ["repo_url"],
551
+ },
552
+ },
553
+ {
554
+ name: "get_wiki_page",
555
+ description: "Return a single wiki page by name for a repo.",
556
+ inputSchema: {
557
+ type: "object",
558
+ properties: {
559
+ repo_url: {
560
+ type: "string",
561
+ description: "Repository URL",
562
+ },
563
+ page: {
564
+ type: "string",
565
+ description: "Page name to retrieve",
566
+ },
567
+ },
568
+ required: ["repo_url", "page"],
569
+ },
570
+ },
571
+ {
572
+ name: "update_wiki_page",
573
+ description: "Create or update a wiki page for a repo. Content is markdown. Pages are auto-injected into spawn_agent calls for this repo.",
574
+ inputSchema: {
575
+ type: "object",
576
+ properties: {
577
+ repo_url: {
578
+ type: "string",
579
+ description: "Repository URL",
580
+ },
581
+ page: {
582
+ type: "string",
583
+ description: "Page name (human-readable, e.g. 'Architecture', 'Gotchas')",
584
+ },
585
+ content: {
586
+ type: "string",
587
+ description: "Markdown content for the page",
588
+ },
589
+ },
590
+ required: ["repo_url", "page", "content"],
591
+ },
592
+ },
593
+ {
594
+ name: "delete_wiki_page",
595
+ description: "Delete a single wiki page for a repo.",
596
+ inputSchema: {
597
+ type: "object",
598
+ properties: {
599
+ repo_url: {
600
+ type: "string",
601
+ description: "Repository URL",
602
+ },
603
+ page: {
604
+ type: "string",
605
+ description: "Page name to delete",
606
+ },
607
+ },
608
+ required: ["repo_url", "page"],
609
+ },
610
+ },
611
+ {
612
+ name: "list_wiki_pages",
613
+ description: "List all wiki page names for a repo.",
614
+ inputSchema: {
615
+ type: "object",
616
+ properties: {
617
+ repo_url: {
618
+ type: "string",
619
+ description: "Repository URL",
620
+ },
621
+ },
622
+ required: ["repo_url"],
623
+ },
624
+ },
538
625
  {
539
626
  name: "docker_ps",
540
627
  description: "List currently running cc-agent Docker containers. Shows container name, status, and uptime.",
@@ -778,6 +865,55 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
778
865
  required: ["swarm_id"],
779
866
  },
780
867
  },
868
+ {
869
+ name: "generate_workflow",
870
+ description: "Auto-decompose a high-level goal into an ordered sequence of stages, then spawn all jobs with stage-based dependency enforcement. Returns immediately with workflow_id, job_ids, and the stage breakdown. Use get_workflow_status to poll progress. Each stage only starts after ALL jobs in the prior stage complete — guaranteeing ordered execution even across 100s of agents.",
871
+ inputSchema: {
872
+ type: "object",
873
+ properties: {
874
+ goal: {
875
+ type: "string",
876
+ description: "High-level natural language goal to decompose into workflow stages (e.g. 'build, test, and deploy X')",
877
+ },
878
+ repo_url: {
879
+ type: "string",
880
+ description: "Git repository URL for all spawned agents (https://github.com/owner/repo)",
881
+ },
882
+ max_stages: {
883
+ type: "number",
884
+ description: `Maximum number of sequential stages (default 8, hard cap ${WORKFLOW_MAX_STAGES_HARD_CAP})`,
885
+ },
886
+ max_agents_per_stage: {
887
+ type: "number",
888
+ description: "Maximum number of parallel agents per stage (default 3)",
889
+ },
890
+ max_budget_per_agent: {
891
+ type: "number",
892
+ description: "Maximum USD budget per spawned agent (default 5)",
893
+ },
894
+ agent_model: {
895
+ type: "string",
896
+ description: "Model override for spawned agents (optional)",
897
+ },
898
+ agent_driver: {
899
+ type: "string",
900
+ description: "Driver override for spawned agents (optional, e.g. 'claude', 'aider')",
901
+ },
902
+ },
903
+ required: ["goal", "repo_url"],
904
+ },
905
+ },
906
+ {
907
+ name: "get_workflow_status",
908
+ description: "Poll the status of a workflow created by generate_workflow. Returns goal, stage breakdown, per-step job IDs and statuses.",
909
+ inputSchema: {
910
+ type: "object",
911
+ properties: {
912
+ workflow_id: { type: "string", description: "Workflow ID returned by generate_workflow" },
913
+ },
914
+ required: ["workflow_id"],
915
+ },
916
+ },
781
917
  ],
782
918
  }));
783
919
  server.setRequestHandler(CallToolRequestSchema, async (req) => {
@@ -1397,6 +1533,70 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
1397
1533
  }],
1398
1534
  };
1399
1535
  }
1536
+ case "get_wiki": {
1537
+ const repoUrl = normalizeRepoUrl(a.repo_url);
1538
+ const slug = repoKey(repoUrl);
1539
+ logger.info("[mcp] get_wiki", { slug });
1540
+ const pages = await wikiStore.getAllPages(slug);
1541
+ return {
1542
+ content: [{
1543
+ type: "text",
1544
+ text: JSON.stringify({ repo: slug, pages, total: pages.length }),
1545
+ }],
1546
+ };
1547
+ }
1548
+ case "get_wiki_page": {
1549
+ const repoUrl = normalizeRepoUrl(a.repo_url);
1550
+ const slug = repoKey(repoUrl);
1551
+ const page = a.page;
1552
+ logger.info("[mcp] get_wiki_page", { slug, page });
1553
+ const content = await wikiStore.getPage(slug, page);
1554
+ return {
1555
+ content: [{
1556
+ type: "text",
1557
+ text: JSON.stringify({ repo: slug, page, content, found: content !== null }),
1558
+ }],
1559
+ };
1560
+ }
1561
+ case "update_wiki_page": {
1562
+ const repoUrl = normalizeRepoUrl(a.repo_url);
1563
+ const slug = repoKey(repoUrl);
1564
+ const page = a.page;
1565
+ const content = a.content;
1566
+ logger.info("[mcp] update_wiki_page", { slug, page, length: content.length });
1567
+ await wikiStore.savePage(slug, page, content);
1568
+ return {
1569
+ content: [{
1570
+ type: "text",
1571
+ text: JSON.stringify({ ok: true, repo: slug, page }),
1572
+ }],
1573
+ };
1574
+ }
1575
+ case "delete_wiki_page": {
1576
+ const repoUrl = normalizeRepoUrl(a.repo_url);
1577
+ const slug = repoKey(repoUrl);
1578
+ const page = a.page;
1579
+ logger.info("[mcp] delete_wiki_page", { slug, page });
1580
+ const deleted = await wikiStore.deletePage(slug, page);
1581
+ return {
1582
+ content: [{
1583
+ type: "text",
1584
+ text: JSON.stringify({ ok: deleted, repo: slug, page }),
1585
+ }],
1586
+ };
1587
+ }
1588
+ case "list_wiki_pages": {
1589
+ const repoUrl = normalizeRepoUrl(a.repo_url);
1590
+ const slug = repoKey(repoUrl);
1591
+ logger.info("[mcp] list_wiki_pages", { slug });
1592
+ const pages = await wikiStore.listPages(slug);
1593
+ return {
1594
+ content: [{
1595
+ type: "text",
1596
+ text: JSON.stringify({ repo: slug, pages, total: pages.length }),
1597
+ }],
1598
+ };
1599
+ }
1400
1600
  case "docker_ps": {
1401
1601
  logger.info("[mcp] docker_ps");
1402
1602
  const containers = await listCcAgentContainers();
@@ -1852,6 +2052,108 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
1852
2052
  }],
1853
2053
  };
1854
2054
  }
2055
+ case "generate_workflow": {
2056
+ const repoUrl = normalizeRepoUrl(a.repo_url);
2057
+ const goal = a.goal;
2058
+ const maxStages = typeof a.max_stages === "number" ? a.max_stages : 8;
2059
+ const maxAgentsPerStage = typeof a.max_agents_per_stage === "number" ? a.max_agents_per_stage : 3;
2060
+ if (maxStages > WORKFLOW_MAX_STAGES_HARD_CAP) {
2061
+ return {
2062
+ content: [{
2063
+ type: "text",
2064
+ text: JSON.stringify({ error: `max_stages ${maxStages} exceeds hard cap of ${WORKFLOW_MAX_STAGES_HARD_CAP}` }),
2065
+ }],
2066
+ };
2067
+ }
2068
+ logger.info("[mcp] generate_workflow", {
2069
+ repo_url: repoUrl,
2070
+ goal: goal.slice(0, 80),
2071
+ max_stages: maxStages,
2072
+ max_agents_per_stage: maxAgentsPerStage,
2073
+ });
2074
+ try {
2075
+ const result = await runWorkflow({
2076
+ repoUrl,
2077
+ goal,
2078
+ maxStages,
2079
+ maxAgentsPerStage,
2080
+ maxBudgetPerAgent: typeof a.max_budget_per_agent === "number" ? a.max_budget_per_agent : 5,
2081
+ agentModel: a.agent_model,
2082
+ agentDriver: a.agent_driver,
2083
+ manager,
2084
+ redis: getRedis(),
2085
+ });
2086
+ return {
2087
+ content: [{
2088
+ type: "text",
2089
+ text: JSON.stringify({
2090
+ workflow_id: result.workflow_id,
2091
+ total_stages: result.total_stages,
2092
+ total_jobs: result.total_jobs,
2093
+ job_ids: result.job_ids,
2094
+ stages: result.stages,
2095
+ message: `Workflow started with ${result.total_jobs} agents across ${result.total_stages} stages. Use get_workflow_status to poll progress.`,
2096
+ }),
2097
+ }],
2098
+ };
2099
+ }
2100
+ catch (err) {
2101
+ logger.error("[mcp] generate_workflow failed", { err: String(err) });
2102
+ return {
2103
+ content: [{
2104
+ type: "text",
2105
+ text: JSON.stringify({ error: String(err) }),
2106
+ }],
2107
+ };
2108
+ }
2109
+ }
2110
+ case "get_workflow_status": {
2111
+ const workflowId = a.workflow_id;
2112
+ logger.info("[mcp] get_workflow_status", { workflow_id: workflowId });
2113
+ const record = await getWorkflowStatus(workflowId, getRedis());
2114
+ if (!record) {
2115
+ return {
2116
+ content: [{
2117
+ type: "text",
2118
+ text: JSON.stringify({ error: `Workflow '${workflowId}' not found` }),
2119
+ }],
2120
+ };
2121
+ }
2122
+ // Enrich with current job statuses per stage
2123
+ const enrichedStages = await Promise.all(record.stages.map(async (stage) => {
2124
+ const enrichedSteps = await Promise.all(stage.steps.map(async (step) => {
2125
+ let status;
2126
+ let score;
2127
+ if (step.job_id) {
2128
+ const jobRec = await jobStore.getJob(step.job_id);
2129
+ status = jobRec?.status;
2130
+ score = jobRec?.score;
2131
+ }
2132
+ return { ...step, status: status ?? "unknown", score: score ?? null };
2133
+ }));
2134
+ const stageStatuses = enrichedSteps.map((s) => s.status);
2135
+ const allDone = stageStatuses.every((s) => s === "done");
2136
+ const anyFailed = stageStatuses.some((s) => s === "failed");
2137
+ const stageStatus = allDone ? "done" : anyFailed ? "failed" : "running";
2138
+ return { stage: stage.stage, status: stageStatus, steps: enrichedSteps };
2139
+ }));
2140
+ return {
2141
+ content: [{
2142
+ type: "text",
2143
+ text: JSON.stringify({
2144
+ workflow_id: record.workflow_id,
2145
+ goal: record.goal,
2146
+ status: record.status,
2147
+ total_stages: record.stages.length,
2148
+ total_jobs: record.all_job_ids.length,
2149
+ stages: enrichedStages,
2150
+ created_at: record.created_at,
2151
+ completed_at: record.completed_at ?? null,
2152
+ error: record.error ?? null,
2153
+ }),
2154
+ }],
2155
+ };
2156
+ }
1855
2157
  default:
1856
2158
  throw new Error(`Unknown tool: ${name}`);
1857
2159
  }