@meltstudio/meltctl 4.93.2 → 4.95.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.
Files changed (2) hide show
  1. package/dist/index.js +224 -1
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ var CLI_VERSION;
14
14
  var init_version = __esm({
15
15
  "src/utils/version.ts"() {
16
16
  "use strict";
17
- CLI_VERSION = "4.93.2";
17
+ CLI_VERSION = "4.95.0";
18
18
  }
19
19
  });
20
20
 
@@ -928,6 +928,17 @@ function createPmResource(config) {
928
928
  async runProjectAudit(projectId) {
929
929
  const res = await apiFetch(config, `/pm/project-audit/run/${projectId}`, { method: "POST" });
930
930
  return unwrap("run project audit", res);
931
+ },
932
+ /**
933
+ * Composite project-health snapshot — wraps every dimension that goes
934
+ * into the dashboard's health-score for one project (audit freshness,
935
+ * findings, board health, plan recency, activity, standup compliance,
936
+ * tickets) into a single response. Powers the `get_project_health`
937
+ * MCP tool.
938
+ */
939
+ async getProjectHealth(projectId) {
940
+ const res = await apiFetch(config, `/pm/project-health/${projectId}`);
941
+ return unwrap("get project health", res);
931
942
  }
932
943
  };
933
944
  }
@@ -2567,6 +2578,10 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2567
2578
  import { z as z22 } from "zod";
2568
2579
  import { z as z3 } from "zod";
2569
2580
  import { z as z4 } from "zod";
2581
+ import { z as z5 } from "zod";
2582
+ import { z as z6 } from "zod";
2583
+ import { z as z7 } from "zod";
2584
+ import { z as z8 } from "zod";
2570
2585
  function createAuditsResource2(config) {
2571
2586
  return {
2572
2587
  async submit(input3) {
@@ -3203,6 +3218,17 @@ function createPmResource2(config) {
3203
3218
  async runProjectAudit(projectId) {
3204
3219
  const res = await apiFetch2(config, `/pm/project-audit/run/${projectId}`, { method: "POST" });
3205
3220
  return unwrap2("run project audit", res);
3221
+ },
3222
+ /**
3223
+ * Composite project-health snapshot — wraps every dimension that goes
3224
+ * into the dashboard's health-score for one project (audit freshness,
3225
+ * findings, board health, plan recency, activity, standup compliance,
3226
+ * tickets) into a single response. Powers the `get_project_health`
3227
+ * MCP tool.
3228
+ */
3229
+ async getProjectHealth(projectId) {
3230
+ const res = await apiFetch2(config, `/pm/project-health/${projectId}`);
3231
+ return unwrap2("get project health", res);
3206
3232
  }
3207
3233
  };
3208
3234
  }
@@ -3511,6 +3537,199 @@ function registerFeatureTools(server, client) {
3511
3537
  (args) => createFeature(client, args)
3512
3538
  );
3513
3539
  }
3540
+ var FLAG_STATUS_VALUES = ["open", "resolved", "dismissed", "all"];
3541
+ async function listAuditFlags(client, input3) {
3542
+ return safe(() => client.pm.listAuditFlags(input3.projectId, input3.status ?? "open"));
3543
+ }
3544
+ async function dismissAuditFlag(client, input3) {
3545
+ return safe(() => client.pm.dismissAuditFlag(input3.flagId, input3.reason));
3546
+ }
3547
+ async function getAuditCatalog(client) {
3548
+ return safe(() => client.pm.getAuditCatalog());
3549
+ }
3550
+ async function runProjectAudit(client, input3) {
3551
+ return safe(() => client.pm.runProjectAudit(input3.projectId));
3552
+ }
3553
+ var listAuditFlagsInputSchema = z5.object({
3554
+ projectId: z5.number().int().positive(),
3555
+ status: z5.enum(FLAG_STATUS_VALUES).optional()
3556
+ });
3557
+ var dismissAuditFlagInputSchema = z5.object({
3558
+ flagId: z5.string().uuid(),
3559
+ reason: z5.string().min(1)
3560
+ });
3561
+ function registerAuditTools(server, client) {
3562
+ server.registerTool(
3563
+ "list_audit_flags",
3564
+ {
3565
+ title: "List project audit flags",
3566
+ description: "Lists audit flags the nightly cron has raised for a project. Each entry pairs the flag (id, severity, evidence, entity it points at, first/last seen, occurrence count, dismissed-by/reason if applicable) with its catalog entry (human-readable title + description + rule type). Default status='open'; pass 'all' to include resolved + dismissed for context.",
3567
+ inputSchema: {
3568
+ projectId: z5.number().int().positive(),
3569
+ status: z5.enum(FLAG_STATUS_VALUES).optional().describe(
3570
+ "Default 'open'. 'resolved' = fixed (flag no longer tripping on latest run). 'dismissed' = PM marked intentionally accepted. 'all' = every flag ever raised on this project."
3571
+ )
3572
+ }
3573
+ },
3574
+ (args) => listAuditFlags(client, args)
3575
+ );
3576
+ server.registerTool(
3577
+ "get_audit_catalog",
3578
+ {
3579
+ title: "Get audit catalog",
3580
+ description: "Returns every audit rule the system knows about (code, category, title, description, severity, rubric version). Use this to explain to a PM what a specific flag means, or to enumerate what kinds of things we audit for. Catalog is read-only \u2014 new entries land via migration.",
3581
+ inputSchema: {}
3582
+ },
3583
+ () => getAuditCatalog(client)
3584
+ );
3585
+ server.registerTool(
3586
+ "dismiss_audit_flag",
3587
+ {
3588
+ title: "Dismiss audit flag",
3589
+ description: "Marks an audit flag as intentionally dismissed with a reason. Use when the PM has reviewed the flag and decided it's a false positive, out of scope, or an accepted trade-off. The reason is stored on the flag + visible in the audit trail; dismissals show up again the next time the flag re-fires unless the underlying rule is retired. This is a write \u2014 confirm with the PM before calling.",
3590
+ inputSchema: {
3591
+ flagId: z5.string().uuid(),
3592
+ reason: z5.string().min(1).describe(
3593
+ "Why this flag is being dismissed. Stored verbatim and shown in the audit trail."
3594
+ )
3595
+ }
3596
+ },
3597
+ (args) => dismissAuditFlag(client, args)
3598
+ );
3599
+ server.registerTool(
3600
+ "run_project_audit",
3601
+ {
3602
+ title: "Run project audit now",
3603
+ description: "Triggers an immediate audit run for a single project (same checks the nightly cron performs). Returns {fired, resolved, checkErrors}: how many new flags raised, how many existing flags cleared, and any per-check errors. Useful after a PM fixes something and wants to verify it cleared without waiting for tomorrow's cron.",
3604
+ inputSchema: {
3605
+ projectId: z5.number().int().positive()
3606
+ }
3607
+ },
3608
+ (args) => runProjectAudit(client, args)
3609
+ );
3610
+ }
3611
+ async function listPlans(client, input3 = {}) {
3612
+ return safe(() => client.plans.list(input3));
3613
+ }
3614
+ async function getPlan(client, input3) {
3615
+ return safe(() => client.plans.get(input3.planId));
3616
+ }
3617
+ var listPlansInputSchema = z6.object({
3618
+ projectId: z6.number().int().positive().optional(),
3619
+ status: z6.string().optional(),
3620
+ author: z6.string().optional(),
3621
+ ticket: z6.string().optional(),
3622
+ repository: z6.string().optional(),
3623
+ limit: z6.number().int().positive().max(200).optional()
3624
+ });
3625
+ function registerPlanTools(server, client) {
3626
+ server.registerTool(
3627
+ "list_plans",
3628
+ {
3629
+ title: "List plans",
3630
+ description: "Lists recent dev-submitted plans (list view \u2014 no plan content). Each entry has id, project, repository, author email, branch, commit, ticket id, status, and the aggregate rubric score if scored. Filterable by projectId, status, author (email), ticket id, repository. Defaults to no filters; pass `limit` to cap the return size. Use `get_plan` to read a plan's full markdown content.",
3631
+ inputSchema: {
3632
+ projectId: z6.number().int().positive().optional().describe("Strapi project id from list_projects. Omit to list across all projects."),
3633
+ status: z6.string().optional().describe("Common values: 'submitted', 'in_review', 'completed'."),
3634
+ author: z6.string().optional().describe("Filter to one author's plans (e.g. 'dev@meltstudio.co')."),
3635
+ ticket: z6.string().optional().describe(
3636
+ "Filter to one ticket id (e.g. 'SD-562'). Useful for finding the plan tied to a specific bit of work."
3637
+ ),
3638
+ repository: z6.string().optional().describe("Filter to one repo path (e.g. 'MeltStudio/mc-backend')."),
3639
+ limit: z6.number().int().positive().max(200).optional().describe("Cap the return size. Default is whatever the API returns (typically 50).")
3640
+ }
3641
+ },
3642
+ (args) => listPlans(client, args)
3643
+ );
3644
+ server.registerTool(
3645
+ "get_plan",
3646
+ {
3647
+ title: "Get plan",
3648
+ description: "Returns one plan's full detail including the markdown `content`, `scoreSummary` (per-rubric-dimension scoring output), and any metadata the dev submitted. Use this after `list_plans` when the agent needs to read what the plan actually says.",
3649
+ inputSchema: {
3650
+ planId: z6.string().uuid()
3651
+ }
3652
+ },
3653
+ (args) => getPlan(client, args)
3654
+ );
3655
+ }
3656
+ async function listBoardAudits(client, input3 = {}) {
3657
+ return safe(() => client.boardAudits.list(input3));
3658
+ }
3659
+ async function getBoardAudit(client, input3) {
3660
+ return safe(() => client.boardAudits.get(input3.auditId));
3661
+ }
3662
+ async function listLatestBoardAudits(client) {
3663
+ return safe(() => client.boardAudits.getLatestByProject());
3664
+ }
3665
+ async function getBoardAuditCatalog(client) {
3666
+ return safe(() => client.boardAudits.getCatalog());
3667
+ }
3668
+ var listBoardAuditsInputSchema = z7.object({
3669
+ projectId: z7.number().int().positive().optional(),
3670
+ limit: z7.number().int().positive().max(200).optional()
3671
+ });
3672
+ function registerBoardAuditTools(server, client) {
3673
+ server.registerTool(
3674
+ "list_board_audits",
3675
+ {
3676
+ title: "List board audits",
3677
+ description: "Lists recent board-hygiene audits. Each entry has id, projectId, the overall score, counts of open findings by severity, and the run timestamp. Filterable by projectId + limit. Use `get_board_audit` for the detailed finding list.",
3678
+ inputSchema: {
3679
+ projectId: z7.number().int().positive().optional().describe("Strapi project id. Omit to list across all accessible projects."),
3680
+ limit: z7.number().int().positive().max(200).optional()
3681
+ }
3682
+ },
3683
+ (args) => listBoardAudits(client, args)
3684
+ );
3685
+ server.registerTool(
3686
+ "get_board_audit",
3687
+ {
3688
+ title: "Get board audit",
3689
+ description: "Returns one board audit's full detail: overall score, per-finding breakdown (category, severity, entity reference, evidence), and the catalog metadata for each rule that fired. Use this to answer 'why did this project score low' questions.",
3690
+ inputSchema: {
3691
+ auditId: z7.string().uuid()
3692
+ }
3693
+ },
3694
+ (args) => getBoardAudit(client, args)
3695
+ );
3696
+ server.registerTool(
3697
+ "list_latest_board_audits",
3698
+ {
3699
+ title: "List latest board audits by project",
3700
+ description: "Cross-project rollup: one entry per project showing its most recent board audit (score, severity-binned finding counts, run timestamp). Use this for questions like 'which of my projects has the worst board hygiene right now?' Cheaper than calling `list_board_audits` per project.",
3701
+ inputSchema: {}
3702
+ },
3703
+ () => listLatestBoardAudits(client)
3704
+ );
3705
+ server.registerTool(
3706
+ "get_board_audit_catalog",
3707
+ {
3708
+ title: "Get board-audit catalog",
3709
+ description: "Returns every board-audit rule the system knows about (code, category, title, description, severity). Complements `get_audit_catalog` (which is for project-level flags); this one covers ticket-tracker hygiene checks.",
3710
+ inputSchema: {}
3711
+ },
3712
+ () => getBoardAuditCatalog(client)
3713
+ );
3714
+ }
3715
+ async function getProjectHealth(client, input3) {
3716
+ return safe(() => client.pm.getProjectHealth(input3.projectId));
3717
+ }
3718
+ function registerProjectHealthTools(server, client) {
3719
+ server.registerTool(
3720
+ "get_project_health",
3721
+ {
3722
+ title: "Get project health",
3723
+ description: "Composite read-only snapshot of one project's health: 0-100 score, audit-freshness numbers, findings (critical/high/missing/warning counts), board-audit aggregate + age, ticket counts (open/started/overdue), standup compliance (last 14 days), plan recency, last CLI activity. Use this for 'how's project X doing?' questions \u2014 it pulls in one round trip what would otherwise be 7+ separate tool calls. Score formula matches the dashboard's project cards.",
3724
+ inputSchema: {
3725
+ projectId: z8.number().int().positive().describe(
3726
+ "Strapi project id from list_projects. The project must have at least one linked repository \u2014 otherwise the score is undefined and the tool returns 422."
3727
+ )
3728
+ }
3729
+ },
3730
+ (args) => getProjectHealth(client, args)
3731
+ );
3732
+ }
3514
3733
  var VERSION = "0.0.0";
3515
3734
  function createMcpServer(client) {
3516
3735
  const server = new McpServer(
@@ -3520,6 +3739,10 @@ function createMcpServer(client) {
3520
3739
  registerProjectTools(server, client);
3521
3740
  registerPhaseTools(server, client);
3522
3741
  registerFeatureTools(server, client);
3742
+ registerAuditTools(server, client);
3743
+ registerPlanTools(server, client);
3744
+ registerBoardAuditTools(server, client);
3745
+ registerProjectHealthTools(server, client);
3523
3746
  return server;
3524
3747
  }
3525
3748
  async function startServer() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meltstudio/meltctl",
3
- "version": "4.93.2",
3
+ "version": "4.95.0",
4
4
  "description": "AI-first development tools for teams - set up AGENTS.md, Claude Code, Cursor, and OpenCode standards",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",