@meltstudio/meltctl 4.190.0 → 4.192.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 +112 -10
  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.190.0";
17
+ CLI_VERSION = "4.192.0";
18
18
  }
19
19
  });
20
20
 
@@ -723,6 +723,10 @@ function createFindingsResource(config) {
723
723
  const params = new URLSearchParams();
724
724
  if (filters?.repository)
725
725
  params.set("repository", filters.repository);
726
+ if (filters?.personEmail)
727
+ params.set("personEmail", filters.personEmail);
728
+ if (filters?.scope)
729
+ params.set("scope", filters.scope);
726
730
  if (filters?.status)
727
731
  params.set("status", filters.status);
728
732
  if (filters?.severity)
@@ -784,6 +788,20 @@ function createFindingsResource(config) {
784
788
  throw new Error(errMessage ?? `Failed to fetch findings stats (${status})`);
785
789
  }
786
790
  return data;
791
+ },
792
+ /**
793
+ * #419: per-person rollup for the /findings "By Person" tab. Manager-only;
794
+ * non-manager callers get an empty array (the server enforces).
795
+ */
796
+ async getStatsByPerson() {
797
+ const { data, status } = await apiFetch(config, "/findings/stats/by-person");
798
+ if (status === 403)
799
+ throw new Error("Access denied. Only Team Managers can view profile-audit stats.");
800
+ if (status !== 200) {
801
+ const errMessage = data && typeof data === "object" && "error" in data ? data.error : void 0;
802
+ throw new Error(errMessage ?? `Failed to fetch findings-by-person stats (${status})`);
803
+ }
804
+ return data;
787
805
  }
788
806
  };
789
807
  }
@@ -1179,9 +1197,16 @@ function createPmResource(config) {
1179
1197
  * findings, board health, plan recency, activity, standup compliance,
1180
1198
  * tickets) into a single response. Powers the `get_project_health`
1181
1199
  * MCP tool.
1200
+ *
1201
+ * Pass `{ expandFindings: true }` to also receive `findingIssues`: the
1202
+ * project's open `audit_findings` rendered as per-finding `HealthIssue`s
1203
+ * for the project page's unified Issues section (#460/#461). The flag is
1204
+ * opt-in so MCP tool calls keep their lean shape and findings-heavy
1205
+ * projects don't blow up agent token budgets.
1182
1206
  */
1183
- async getProjectHealth(projectId) {
1184
- const res = await apiFetch(config, `/pm/project-health/${projectId}`);
1207
+ async getProjectHealth(projectId, options) {
1208
+ const query = options?.expandFindings ? "?expandFindings=1" : "";
1209
+ const res = await apiFetch(config, `/pm/project-health/${projectId}${query}`);
1185
1210
  return unwrap("get project health", res);
1186
1211
  },
1187
1212
  // ─── Detailed risks (per-project + cross-project) ────────────────────
@@ -1548,7 +1573,13 @@ function createMeltClient(config) {
1548
1573
  import { z } from "zod";
1549
1574
  var auditFindingSchema = z.object({
1550
1575
  id: z.string(),
1551
- repository: z.string(),
1576
+ // Discriminator added with #419. 'project' is the original code/security/UX
1577
+ // shape — repository set, personEmail null. 'person' is the employee-profile
1578
+ // shape — personEmail set, repository null. Existing consumers can still
1579
+ // treat repository as the primary identity; the field is nullable now.
1580
+ scope: z.enum(["project", "person"]),
1581
+ repository: z.string().nullable(),
1582
+ personEmail: z.string().nullable(),
1552
1583
  project: z.string(),
1553
1584
  auditType: z.string(),
1554
1585
  catalogCode: z.string().nullable(),
@@ -1600,6 +1631,12 @@ var findingsStatsSchema = z.object({
1600
1631
  });
1601
1632
  var findingsListFiltersSchema = z.object({
1602
1633
  repository: z.string().optional(),
1634
+ // #419: filter to one employee's profile findings. Manager-only on the
1635
+ // server; non-manager callers passing this get an empty result.
1636
+ personEmail: z.string().optional(),
1637
+ // #419: 'project' | 'person'. Defaults to no filter when absent. Non-
1638
+ // managers cannot see scope='person' rows regardless of this value.
1639
+ scope: z.enum(["project", "person"]).optional(),
1603
1640
  status: z.string().optional(),
1604
1641
  severity: z.string().optional(),
1605
1642
  effort: z.string().optional(),
@@ -1615,6 +1652,14 @@ var findingsStatsByRepositoryEntrySchema = findingsStatsSchema.extend({
1615
1652
  repository: z.string()
1616
1653
  });
1617
1654
  var findingsStatsByRepositorySchema = z.array(findingsStatsByRepositoryEntrySchema);
1655
+ var findingsStatsByPersonEntrySchema = z.object({
1656
+ personEmail: z.string(),
1657
+ personName: z.string().nullable(),
1658
+ open: z.number(),
1659
+ worstSeverity: z.enum(["critical", "high", "medium", "low"]).nullable(),
1660
+ lastAuditedAt: z.string().nullable()
1661
+ });
1662
+ var findingsStatsByPersonSchema = z.array(findingsStatsByPersonEntrySchema);
1618
1663
  var extractionResultSchema = z.object({
1619
1664
  auditId: z.string(),
1620
1665
  findingsExtracted: z.number(),
@@ -3959,6 +4004,10 @@ function createFindingsResource2(config) {
3959
4004
  const params = new URLSearchParams();
3960
4005
  if (filters?.repository)
3961
4006
  params.set("repository", filters.repository);
4007
+ if (filters?.personEmail)
4008
+ params.set("personEmail", filters.personEmail);
4009
+ if (filters?.scope)
4010
+ params.set("scope", filters.scope);
3962
4011
  if (filters?.status)
3963
4012
  params.set("status", filters.status);
3964
4013
  if (filters?.severity)
@@ -4020,6 +4069,20 @@ function createFindingsResource2(config) {
4020
4069
  throw new Error(errMessage ?? `Failed to fetch findings stats (${status})`);
4021
4070
  }
4022
4071
  return data;
4072
+ },
4073
+ /**
4074
+ * #419: per-person rollup for the /findings "By Person" tab. Manager-only;
4075
+ * non-manager callers get an empty array (the server enforces).
4076
+ */
4077
+ async getStatsByPerson() {
4078
+ const { data, status } = await apiFetch2(config, "/findings/stats/by-person");
4079
+ if (status === 403)
4080
+ throw new Error("Access denied. Only Team Managers can view profile-audit stats.");
4081
+ if (status !== 200) {
4082
+ const errMessage = data && typeof data === "object" && "error" in data ? data.error : void 0;
4083
+ throw new Error(errMessage ?? `Failed to fetch findings-by-person stats (${status})`);
4084
+ }
4085
+ return data;
4023
4086
  }
4024
4087
  };
4025
4088
  }
@@ -4409,9 +4472,16 @@ function createPmResource2(config) {
4409
4472
  * findings, board health, plan recency, activity, standup compliance,
4410
4473
  * tickets) into a single response. Powers the `get_project_health`
4411
4474
  * MCP tool.
4475
+ *
4476
+ * Pass `{ expandFindings: true }` to also receive `findingIssues`: the
4477
+ * project's open `audit_findings` rendered as per-finding `HealthIssue`s
4478
+ * for the project page's unified Issues section (#460/#461). The flag is
4479
+ * opt-in so MCP tool calls keep their lean shape and findings-heavy
4480
+ * projects don't blow up agent token budgets.
4412
4481
  */
4413
- async getProjectHealth(projectId) {
4414
- const res = await apiFetch2(config, `/pm/project-health/${projectId}`);
4482
+ async getProjectHealth(projectId, options) {
4483
+ const query = options?.expandFindings ? "?expandFindings=1" : "";
4484
+ const res = await apiFetch2(config, `/pm/project-health/${projectId}${query}`);
4415
4485
  return unwrap2("get project health", res);
4416
4486
  },
4417
4487
  // ─── Detailed risks (per-project + cross-project) ────────────────────
@@ -4761,7 +4831,13 @@ function createMeltClient2(config) {
4761
4831
  }
4762
4832
  var auditFindingSchema2 = z2.object({
4763
4833
  id: z2.string(),
4764
- repository: z2.string(),
4834
+ // Discriminator added with #419. 'project' is the original code/security/UX
4835
+ // shape — repository set, personEmail null. 'person' is the employee-profile
4836
+ // shape — personEmail set, repository null. Existing consumers can still
4837
+ // treat repository as the primary identity; the field is nullable now.
4838
+ scope: z2.enum(["project", "person"]),
4839
+ repository: z2.string().nullable(),
4840
+ personEmail: z2.string().nullable(),
4765
4841
  project: z2.string(),
4766
4842
  auditType: z2.string(),
4767
4843
  catalogCode: z2.string().nullable(),
@@ -4813,6 +4889,12 @@ var findingsStatsSchema2 = z2.object({
4813
4889
  });
4814
4890
  var findingsListFiltersSchema2 = z2.object({
4815
4891
  repository: z2.string().optional(),
4892
+ // #419: filter to one employee's profile findings. Manager-only on the
4893
+ // server; non-manager callers passing this get an empty result.
4894
+ personEmail: z2.string().optional(),
4895
+ // #419: 'project' | 'person'. Defaults to no filter when absent. Non-
4896
+ // managers cannot see scope='person' rows regardless of this value.
4897
+ scope: z2.enum(["project", "person"]).optional(),
4816
4898
  status: z2.string().optional(),
4817
4899
  severity: z2.string().optional(),
4818
4900
  effort: z2.string().optional(),
@@ -4828,6 +4910,14 @@ var findingsStatsByRepositoryEntrySchema2 = findingsStatsSchema2.extend({
4828
4910
  repository: z2.string()
4829
4911
  });
4830
4912
  var findingsStatsByRepositorySchema2 = z2.array(findingsStatsByRepositoryEntrySchema2);
4913
+ var findingsStatsByPersonEntrySchema2 = z2.object({
4914
+ personEmail: z2.string(),
4915
+ personName: z2.string().nullable(),
4916
+ open: z2.number(),
4917
+ worstSeverity: z2.enum(["critical", "high", "medium", "low"]).nullable(),
4918
+ lastAuditedAt: z2.string().nullable()
4919
+ });
4920
+ var findingsStatsByPersonSchema2 = z2.array(findingsStatsByPersonEntrySchema2);
4831
4921
  var extractionResultSchema2 = z2.object({
4832
4922
  auditId: z2.string(),
4833
4923
  findingsExtracted: z2.number(),
@@ -5889,10 +5979,14 @@ async function listFindings(client, input3 = {}) {
5889
5979
  var listFindingsInputSchema = z10.object({
5890
5980
  projectId: z10.number().int().positive().optional(),
5891
5981
  repository: z10.string().optional(),
5982
+ // #419: filter to one employee's profile-audit findings. Manager-gated
5983
+ // server-side; non-manager callers get an empty result.
5984
+ personEmail: z10.string().email().optional(),
5985
+ scope: z10.enum(["project", "person"]).optional(),
5892
5986
  status: z10.enum(["pass", "warning", "missing", "na"]).optional(),
5893
5987
  severity: z10.enum(["critical", "high", "medium", "low"]).optional(),
5894
5988
  effort: z10.enum(["low", "medium", "high", "unknown"]).optional(),
5895
- auditType: z10.enum(["audit", "ux-audit", "security-audit"]).optional(),
5989
+ auditType: z10.enum(["audit", "ux-audit", "security-audit", "profile-audit"]).optional(),
5896
5990
  limit: z10.number().int().positive().max(500).optional()
5897
5991
  });
5898
5992
  function registerFindingsTools(server, getClient2) {
@@ -5900,16 +5994,24 @@ function registerFindingsTools(server, getClient2) {
5900
5994
  "list_findings",
5901
5995
  {
5902
5996
  title: "List audit findings",
5903
- description: "Lists code/security/UX audit findings. Each finding carries its check code, category, status (pass/warning/missing/na), severity (critical/high/medium/low), effort (low/medium/high \u2014 how much work the fix is, independent of severity), repository, and evidence (file/symbol) so you can see exactly what to fix. Filter by projectId, repository, status, severity, effort, or auditType. Results are ordered worst-first (missing > warning, then critical > high > \u2026). Use this to answer 'what's open on the app I'm working on?' \u2014 pass status='missing' or severity='critical' to focus on what matters, or effort='low' with severity='high'/'critical' to find cheap high-leverage wins. Read-only and open to any @meltstudio.co user.",
5997
+ description: "Lists code/security/UX audit findings, plus the People-Ops-facing Notion employee-profile audit (auditType='profile-audit', personEmail-keyed, manager-only). Each finding carries its check code, category, status (pass/warning/missing/na), severity (critical/high/medium/low), effort (low/medium/high \u2014 how much work the fix is, independent of severity), repository (project-scoped) or personEmail (person-scoped), and evidence (file/symbol or sentence) so you can see exactly what to fix. Filter by projectId, repository, personEmail, scope, status, severity, effort, or auditType. Results are ordered worst-first (missing > warning, then critical > high > \u2026). Profile-audit findings are filtered out for non-manager callers regardless of filters \u2014 they carry sensitive employee context. Read-only.",
5904
5998
  inputSchema: {
5905
5999
  projectId: z10.number().int().positive().optional().describe("Strapi project id \u2014 scopes findings to that project\u2019s repos."),
5906
6000
  repository: z10.string().optional().describe("Full repo slug, e.g. 'MeltStudio/atlas-api'. Scopes to a single repo."),
6001
+ personEmail: z10.string().email().optional().describe(
6002
+ "Scopes to one employee's profile-audit findings (#419). Manager-only \u2014 non-manager callers get an empty result."
6003
+ ),
6004
+ scope: z10.enum(["project", "person"]).optional().describe(
6005
+ "Filter by scope. 'project' = repo-scoped findings; 'person' = employee profile audits (manager-only)."
6006
+ ),
5907
6007
  status: z10.enum(["pass", "warning", "missing", "na"]).optional().describe("Filter by check status. 'missing' = the check failed outright."),
5908
6008
  severity: z10.enum(["critical", "high", "medium", "low"]).optional(),
5909
6009
  effort: z10.enum(["low", "medium", "high", "unknown"]).optional().describe(
5910
6010
  "Remediation effort. Combine effort=low with a high severity to find quick wins. 'unknown' = pass/na or not yet rated."
5911
6011
  ),
5912
- auditType: z10.enum(["audit", "ux-audit", "security-audit"]).optional(),
6012
+ auditType: z10.enum(["audit", "ux-audit", "security-audit", "profile-audit"]).optional().describe(
6013
+ "'audit' = tech, 'ux-audit' = UX, 'security-audit' = security, 'profile-audit' = employee Notion profile (manager-only)."
6014
+ ),
5913
6015
  limit: z10.number().int().positive().max(500).optional()
5914
6016
  }
5915
6017
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meltstudio/meltctl",
3
- "version": "4.190.0",
3
+ "version": "4.192.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",