@meltstudio/meltctl 5.14.0 → 5.16.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 +28 -25
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7450,7 +7450,7 @@ var CLI_VERSION;
7450
7450
  var init_version = __esm({
7451
7451
  "src/utils/version.ts"() {
7452
7452
  "use strict";
7453
- CLI_VERSION = "5.14.0";
7453
+ CLI_VERSION = "5.16.0";
7454
7454
  }
7455
7455
  });
7456
7456
 
@@ -26583,7 +26583,7 @@ function createPlansResource(config2) {
26583
26583
  const path10 = `/plans${query ? `?${query}` : ""}`;
26584
26584
  const { data, status } = await apiFetch(config2, path10);
26585
26585
  if (status === 403)
26586
- throw new Error("Access denied. Only Team Managers can list plans.");
26586
+ throw new Error(`Access denied. ${data.error ?? ""}`.trim());
26587
26587
  if (status !== 200)
26588
26588
  throw new Error(data.error ?? `Failed to list plans (${status})`);
26589
26589
  return data;
@@ -26591,7 +26591,7 @@ function createPlansResource(config2) {
26591
26591
  async get(id) {
26592
26592
  const { data, status } = await apiFetch(config2, `/plans/${id}`);
26593
26593
  if (status === 403)
26594
- throw new Error("Access denied. Only Team Managers can view plans.");
26594
+ throw new Error(`Access denied. ${data.error ?? ""}`.trim());
26595
26595
  if (status === 404)
26596
26596
  throw new Error(`Plan not found: ${id}`);
26597
26597
  if (status !== 200)
@@ -27211,8 +27211,9 @@ function createBoardAuditsResource(config2) {
27211
27211
  // ../sdk/dist/resources/pm.js
27212
27212
  function unwrap(label, response, okStatus = 200) {
27213
27213
  const okStatuses = Array.isArray(okStatus) ? okStatus : [okStatus];
27214
- if (response.status === 403)
27215
- throw new Error(`Access denied (${label})`);
27214
+ if (response.status === 403) {
27215
+ throw new Error(response.data.error ? `Access denied (${label}): ${response.data.error}` : `Access denied (${label})`);
27216
+ }
27216
27217
  if (!okStatuses.includes(response.status)) {
27217
27218
  throw new Error(response.data.error ?? `Failed: ${label} (${response.status})`);
27218
27219
  }
@@ -27939,9 +27940,9 @@ function createProfileAuditsResource(config2) {
27939
27940
  function createSupportEffortResource(config2) {
27940
27941
  return {
27941
27942
  /**
27942
- * Get the by-project + by-architect rollups, the week/month trend, and the
27943
- * actionable missing-time worklist. `period` selects the trend granularity
27944
- * (default 'week').
27943
+ * Get the by-project + by-architect rollups, the project × month matrix
27944
+ * (last 6 months), the week/month trend, and the actionable missing-time
27945
+ * worklist. `period` selects the trend granularity (default 'week').
27945
27946
  */
27946
27947
  async get(opts = {}) {
27947
27948
  const params = new URLSearchParams();
@@ -53253,7 +53254,7 @@ function createPlansResource2(config2) {
53253
53254
  const path22 = `/plans${query ? `?${query}` : ""}`;
53254
53255
  const { data, status } = await apiFetch2(config2, path22);
53255
53256
  if (status === 403)
53256
- throw new Error("Access denied. Only Team Managers can list plans.");
53257
+ throw new Error(`Access denied. ${data.error ?? ""}`.trim());
53257
53258
  if (status !== 200)
53258
53259
  throw new Error(data.error ?? `Failed to list plans (${status})`);
53259
53260
  return data;
@@ -53261,7 +53262,7 @@ function createPlansResource2(config2) {
53261
53262
  async get(id) {
53262
53263
  const { data, status } = await apiFetch2(config2, `/plans/${id}`);
53263
53264
  if (status === 403)
53264
- throw new Error("Access denied. Only Team Managers can view plans.");
53265
+ throw new Error(`Access denied. ${data.error ?? ""}`.trim());
53265
53266
  if (status === 404)
53266
53267
  throw new Error(`Plan not found: ${id}`);
53267
53268
  if (status !== 200)
@@ -53855,8 +53856,9 @@ function createBoardAuditsResource2(config2) {
53855
53856
  }
53856
53857
  function unwrap2(label, response, okStatus = 200) {
53857
53858
  const okStatuses = Array.isArray(okStatus) ? okStatus : [okStatus];
53858
- if (response.status === 403)
53859
- throw new Error(`Access denied (${label})`);
53859
+ if (response.status === 403) {
53860
+ throw new Error(response.data.error ? `Access denied (${label}): ${response.data.error}` : `Access denied (${label})`);
53861
+ }
53860
53862
  if (!okStatuses.includes(response.status)) {
53861
53863
  throw new Error(response.data.error ?? `Failed: ${label} (${response.status})`);
53862
53864
  }
@@ -54567,9 +54569,9 @@ function createProfileAuditsResource2(config2) {
54567
54569
  function createSupportEffortResource2(config2) {
54568
54570
  return {
54569
54571
  /**
54570
- * Get the by-project + by-architect rollups, the week/month trend, and the
54571
- * actionable missing-time worklist. `period` selects the trend granularity
54572
- * (default 'week').
54572
+ * Get the by-project + by-architect rollups, the project × month matrix
54573
+ * (last 6 months), the week/month trend, and the actionable missing-time
54574
+ * worklist. `period` selects the trend granularity (default 'week').
54573
54575
  */
54574
54576
  async get(opts = {}) {
54575
54577
  const params = new URLSearchParams();
@@ -55246,7 +55248,7 @@ function registerProjectTools(server, getClient2) {
55246
55248
  "list_projects",
55247
55249
  {
55248
55250
  title: "List projects",
55249
- description: "Lists Melt projects the authenticated user can see. Defaults: hasPM=true (only actively-managed projects), includeInternal=false (Melt's own internal projects hidden). Use this to resolve a project's name to its numeric `projectId` before calling any other tool. Returns id, name, client, project manager, and repo count per project.",
55251
+ description: "Lists Melt projects the authenticated user can see. Managers see every project; non-managers (devs) see only the projects they're assigned to, PM, or recently worked on \u2014 a project missing from this list is out of their scope, not nonexistent. Defaults: hasPM=true (only actively-managed projects), includeInternal=false (Melt's own internal projects hidden). Use this to resolve a project's name to its numeric `projectId` before calling any other tool. Returns id, name, client, project manager, and repo count per project.",
55250
55252
  inputSchema: {
55251
55253
  hasPM: external_exports.boolean().optional().describe(
55252
55254
  "Default true. When true, only projects with a project manager assigned are returned (recommended for AI agent flows). Set false to include unmanaged projects."
@@ -55262,7 +55264,7 @@ function registerProjectTools(server, getClient2) {
55262
55264
  "get_project_settings",
55263
55265
  {
55264
55266
  title: "Get project settings",
55265
- description: 'Returns the project\'s PM-skills settings: cadence (weekly/biweekly/monthly), start_day, demo_day, team_size, velocity_override, Linear workspace, Notion URLs, code repo path, tech-support contact, default language, project glossary, project stage, default jump duration weeks. Includes a `warnings` array flagging settings whose absence breaks downstream behavior (e.g., "calculator: missing teamSize"). Returns sensible defaults if no settings row exists yet (cadence=weekly, start_day=Monday, demo_day=Friday, defaultLanguage=English, defaultJumpDurationWeeks=1).',
55267
+ description: 'Returns the project\'s PM-skills settings: cadence (weekly/biweekly/monthly), start_day, demo_day, team_size, velocity_override, Linear workspace, Notion URLs, code repo path, tech-support contact, default language, project glossary, project stage, default jump duration weeks. Includes a `warnings` array flagging settings whose absence breaks downstream behavior (e.g., "calculator: missing teamSize"). Returns sensible defaults if no settings row exists yet (cadence=weekly, start_day=Monday, demo_day=Friday, defaultLanguage=English, defaultJumpDurationWeeks=1). Non-managers get a 403 for projects outside their assigned/recently-worked scope \u2014 explain the scoping to the user instead of retrying.',
55266
55268
  inputSchema: {
55267
55269
  projectId: external_exports.number().int().positive().describe("Strapi project id from list_projects.")
55268
55270
  }
@@ -55318,7 +55320,7 @@ function registerProjectTools(server, getClient2) {
55318
55320
  "get_project_context",
55319
55321
  {
55320
55322
  title: "Get project context",
55321
- description: "Read-only project identity + the PM-owned canonical project stage. Returns: projectId, projectName, client, pmEmail, repos[], projectStage (prototype | early_revenue | growth | scale | null), projectStageSetBy, projectStageSetAt. Call this at the start of an audit run instead of trusting AGENTS.md self-declaration \u2014 the stage drives audit calibration. Auth-only (no manager check), so devs running the audit skill from their own machine can call it directly.",
55323
+ description: "Read-only project identity + the PM-owned canonical project stage. Returns: projectId, projectName, client, pmEmail, repos[], projectStage (prototype | early_revenue | growth | scale | null), projectStageSetBy, projectStageSetAt. Call this at the start of an audit run instead of trusting AGENTS.md self-declaration \u2014 the stage drives audit calibration. Auth-only (no manager check), so devs running the audit skill from their own machine can call it directly for their own projects; a 403 means the project is outside the dev's assigned/recently-worked scope \u2014 explain the scoping instead of retrying.",
55322
55324
  inputSchema: {
55323
55325
  projectId: external_exports.number().int().positive().describe("Strapi project id from list_projects.")
55324
55326
  }
@@ -55372,7 +55374,7 @@ function registerPhaseTools(server, getClient2) {
55372
55374
  "list_phases",
55373
55375
  {
55374
55376
  title: "List phases",
55375
- description: "Lists phases on a project. Each entry includes target_shape, computed current_shape, primary flag, active flag, the assigned features (with their stage_snapshot at join time + live current_stage), and timestamps. Includes closed phases when includeClosed=true.",
55377
+ description: "Lists phases on a project. Each entry includes target_shape, computed current_shape, primary flag, active flag, the assigned features (with their stage_snapshot at join time + live current_stage), and timestamps. Includes closed phases when includeClosed=true. Non-managers get a 403 for projects outside their assigned/recently-worked scope \u2014 explain the scoping to the user instead of retrying.",
55376
55378
  inputSchema: {
55377
55379
  projectId: external_exports.number().int().positive(),
55378
55380
  includeClosed: external_exports.boolean().optional().describe("Default false. Set true to include closed phases as history.")
@@ -55574,7 +55576,7 @@ function registerFeatureTools(server, getClient2) {
55574
55576
  "list_features",
55575
55577
  {
55576
55578
  title: "List features",
55577
- description: "Lists features on the project. Each entry has id, name, category, description, current_stage, status, prd_path, client_notes, and starting_point. Per-phase target stage + Linear epic live on the phase membership (see list_phases), not the feature row. Optional filters narrow server-side: phaseId returns only features assigned to that phase; status / category / currentStage filter on the matching column.",
55579
+ description: "Lists features on the project. Each entry has id, name, category, description, current_stage, status, prd_path, client_notes, and starting_point. Per-phase target stage + Linear epic live on the phase membership (see list_phases), not the feature row. Optional filters narrow server-side: phaseId returns only features assigned to that phase; status / category / currentStage filter on the matching column. Non-managers get a 403 for projects outside their assigned/recently-worked scope \u2014 explain the scoping to the user instead of retrying.",
55578
55580
  inputSchema: {
55579
55581
  projectId: external_exports.number().int().positive(),
55580
55582
  phaseId: external_exports.string().uuid().optional().describe("Limit to features assigned to this phase (phase_features join)."),
@@ -55690,7 +55692,7 @@ function registerPlanTools(server, getClient2) {
55690
55692
  "list_plans",
55691
55693
  {
55692
55694
  title: "List plans",
55693
- 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.",
55695
+ 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. Managers see every plan; non-managers see plans they authored plus plans on repos of their assigned/recently-worked projects.",
55694
55696
  inputSchema: {
55695
55697
  projectId: external_exports.number().int().positive().optional().describe("Strapi project id from list_projects. Omit to list across all projects."),
55696
55698
  status: external_exports.string().optional().describe("Common values: 'submitted', 'in_review', 'completed'."),
@@ -55708,7 +55710,7 @@ function registerPlanTools(server, getClient2) {
55708
55710
  "get_plan",
55709
55711
  {
55710
55712
  title: "Get plan",
55711
- 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.",
55713
+ 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. Non-managers can read their own plans plus plans on repos of their assigned/recently-worked projects; anything else returns a 403 \u2014 explain the scoping to the user instead of retrying.",
55712
55714
  inputSchema: {
55713
55715
  planId: external_exports.string().uuid()
55714
55716
  }
@@ -55783,7 +55785,7 @@ function registerProjectHealthTools(server, getClient2) {
55783
55785
  "get_project_health",
55784
55786
  {
55785
55787
  title: "Get project health",
55786
- description: "Composite read-only snapshot of one project's health: 0-100 score; `issues` \u2014 the full list of open health issues (each with label, dimension, severity, and a one-line howToFix), which are the EXACT items shown on the project's dashboard health card (e.g. 'PM silent in active cycle', 'Roadmap status differs from Linear', 'No roadmap'); 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, and the project's RSK risks (open/mitigated counts, red-zone count, top 3 open risks with impact \xD7 probability scores AND the PM's latest weekly status comment on each one). Risks + comments come from a weekly mirror of the RSK Linear board, refreshed every Tuesday evening right after the team's risk-review meeting \u2014 so 'latestComment' is normally the just-logged update for the week. Use this for 'how's project X doing?' / 'what needs attention on X?' questions \u2014 prefer surfacing the `issues` list (worst severity first) over just the score. Pulls in one round trip what would otherwise be 8+ separate tool calls; score + issues match the dashboard's project cards.",
55788
+ description: "Composite read-only snapshot of one project's health: 0-100 score; `issues` \u2014 the full list of open health issues (each with label, dimension, severity, and a one-line howToFix), which are the EXACT items shown on the project's dashboard health card (e.g. 'PM silent in active cycle', 'Roadmap status differs from Linear', 'No roadmap'); 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, and the project's RSK risks (open/mitigated counts, red-zone count, top 3 open risks with impact \xD7 probability scores AND the PM's latest weekly status comment on each one). Risks + comments come from a weekly mirror of the RSK Linear board, refreshed every Tuesday evening right after the team's risk-review meeting \u2014 so 'latestComment' is normally the just-logged update for the week. Use this for 'how's project X doing?' / 'what needs attention on X?' questions \u2014 prefer surfacing the `issues` list (worst severity first) over just the score. Pulls in one round trip what would otherwise be 8+ separate tool calls; score + issues match the dashboard's project cards. Non-managers get a 403 for projects outside their assigned/recently-worked scope \u2014 explain the scoping to the user instead of retrying.",
55787
55789
  inputSchema: {
55788
55790
  projectId: external_exports.number().int().positive().describe(
55789
55791
  "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."
@@ -55836,7 +55838,7 @@ function registerFindingsTools(server, getClient2) {
55836
55838
  "list_findings",
55837
55839
  {
55838
55840
  title: "List audit findings",
55839
- 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.",
55841
+ 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; managers see every finding, while non-managers see only findings on repos of their assigned/recently-worked projects (an empty result may mean out-of-scope, not clean).",
55840
55842
  inputSchema: {
55841
55843
  projectId: external_exports.number().int().positive().optional().describe("Strapi project id \u2014 scopes findings to that project\u2019s repos."),
55842
55844
  repository: external_exports.string().optional().describe("Full repo slug, e.g. 'MeltStudio/atlas-api'. Scopes to a single repo."),
@@ -55961,6 +55963,7 @@ async function getSupportEffort(client, input) {
55961
55963
  asOf: data.asOf,
55962
55964
  byProject: data.byProject,
55963
55965
  byArchitect: data.byArchitect,
55966
+ byProjectMonthly: data.byProjectMonthly,
55964
55967
  trend: data.trend,
55965
55968
  // Surface the count prominently; the full actionable list is available via
55966
55969
  // the read API / dashboard page (Slice 2) rather than flooding the tool.
@@ -55973,7 +55976,7 @@ function registerSupportEffortTools(server, getClient2) {
55973
55976
  "get_support_effort",
55974
55977
  {
55975
55978
  title: "Get tech-support effort",
55976
- description: "Tech-support / DevOps effort rollup for the 'Tech Support Ops' Linear team (key DEV). Returns logged hours (parsed from each ticket's self-reported 'Time Spent' label \u2014 the architect's active effort, NOT cycle time) and ticket counts rolled up two ways: `byProject` (which client/product the support load lands on) and `byArchitect` (who is carrying it). Each rollup entry has ticketCount, totalLoggedMinutes, avgLoggedMinutes, and missingTimeCount. Also returns `missingTimeCount`: the number of Done tickets with no time label (a data-quality gap that makes the hours less trustworthy \u2014 the dashboard page surfaces the actionable list). `period` selects the trend granularity (week|month, default week). Manager-gated. Use for 'how much support work did <project> need?', 'who's carrying the support load?', and 'is our support time logged completely?'.",
55979
+ description: "Tech-support / DevOps effort rollup for the 'Tech Support Ops' Linear team (key DEV). Returns logged hours (parsed from each ticket's self-reported 'Time Spent' label \u2014 the architect's active effort, NOT cycle time) and ticket counts rolled up two ways: `byProject` (which client/product the support load lands on) and `byArchitect` (who is carrying it). Each rollup entry has ticketCount, totalLoggedMinutes, avgLoggedMinutes, and missingTimeCount. `byProjectMonthly` is a project \xD7 month matrix over the last 6 months (oldest \u2192 newest, zero-filled): each entry has projectId, projectName, and months[{period 'YYYY-MM', ticketCount, totalLoggedMinutes}] \u2014 use it for 'how much did project X cost us in June?' or 'how is support spend distributed across projects month over month?'. Also returns `missingTimeCount`: the number of Done tickets with no time label (a data-quality gap that makes the hours less trustworthy \u2014 the dashboard page surfaces the actionable list). Only tickets completed on/after 2026-07-01 count as missing time \u2014 older gaps are not backfillable and are exempt, though their logged hours still aggregate. `period` selects the trend granularity (week|month, default week). Manager-gated. Use for 'how much support work did <project> need?', 'who's carrying the support load?', and 'is our support time logged completely?'.",
55977
55980
  inputSchema: {
55978
55981
  period: external_exports.enum(["week", "month"]).optional().describe("Trend bucket granularity. Default week.")
55979
55982
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meltstudio/meltctl",
3
- "version": "5.14.0",
3
+ "version": "5.16.0",
4
4
  "description": "AI-first development tooling for Melt teams — companion CLI for the org-distributed Claude Code dev skills",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",