@codazen/harmonica-mcp 3.4.0 → 3.6.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/index.js +179 -352
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -21587,6 +21587,18 @@ async function fetchProjectInOrg(client, projectId, orgId) {
|
|
|
21587
21587
|
}
|
|
21588
21588
|
return project;
|
|
21589
21589
|
}
|
|
21590
|
+
async function fetchSystemInOrg(client, systemId, orgId) {
|
|
21591
|
+
const system = await client.getSystem(systemId);
|
|
21592
|
+
if (!system) {
|
|
21593
|
+
throw new Error(`System not found: "${systemId}"`);
|
|
21594
|
+
}
|
|
21595
|
+
if (system.orgId !== orgId) {
|
|
21596
|
+
throw new Error(
|
|
21597
|
+
`System "${systemId}" does not belong to the configured organization. Access denied.`
|
|
21598
|
+
);
|
|
21599
|
+
}
|
|
21600
|
+
return system;
|
|
21601
|
+
}
|
|
21590
21602
|
async function fetchBeatInOrg(client, beatId, orgId) {
|
|
21591
21603
|
const beat = await client.getBeat(beatId);
|
|
21592
21604
|
if (!beat) {
|
|
@@ -21968,7 +21980,7 @@ function registerActivityTools(server, ctx, client) {
|
|
|
21968
21980
|
},
|
|
21969
21981
|
async ({ projectId, limit, importance }) => {
|
|
21970
21982
|
await assertProjectInOrg(client, projectId, ctx.orgId);
|
|
21971
|
-
const { entries, hasMore } = await client.
|
|
21983
|
+
const { entries, hasMore } = await client.listSystemActivities(projectId, {
|
|
21972
21984
|
limit: limit ?? 30,
|
|
21973
21985
|
minImportance: importance
|
|
21974
21986
|
});
|
|
@@ -22689,7 +22701,7 @@ function formatDeliveryPolicy(policy, unresolvedReason) {
|
|
|
22689
22701
|
}
|
|
22690
22702
|
function formatProjectContext(project, notes, orgCoda) {
|
|
22691
22703
|
const sections = [];
|
|
22692
|
-
sections.push(`#
|
|
22704
|
+
sections.push(`# System: ${project.title}`);
|
|
22693
22705
|
sections.push(`**ID:** ${project.projectId}`);
|
|
22694
22706
|
sections.push(`**Status:** ${project.status.replace("_", " ")}`);
|
|
22695
22707
|
if (project.repoOwner && project.repoName) {
|
|
@@ -23275,7 +23287,7 @@ ${formatBeatDetail(beat)}${similarityWarning}` }] };
|
|
|
23275
23287
|
async ({ projectId, beatId, status, includeArchived }) => {
|
|
23276
23288
|
try {
|
|
23277
23289
|
await assertProjectInOrg(client, projectId, ctx.orgId);
|
|
23278
|
-
const revisions = beatId ? await client.listBeatRevisions(projectId, beatId, { status, includeArchived }) : await client.
|
|
23290
|
+
const revisions = beatId ? await client.listBeatRevisions(projectId, beatId, { status, includeArchived }) : await client.listSystemRevisions(projectId, { status, includeArchived });
|
|
23279
23291
|
return { content: [{ type: "text", text: formatRevisionSummaryTable(revisions) }] };
|
|
23280
23292
|
} catch (err) {
|
|
23281
23293
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -23936,7 +23948,7 @@ function registerCheckTools(server, ctx, client) {
|
|
|
23936
23948
|
},
|
|
23937
23949
|
async ({ projectId }) => {
|
|
23938
23950
|
try {
|
|
23939
|
-
const checks = await client.
|
|
23951
|
+
const checks = await client.listLatestSystemChecks(projectId);
|
|
23940
23952
|
if (checks.length === 0) {
|
|
23941
23953
|
return { content: [{ type: "text", text: `No checks found for project ${projectId}.` }] };
|
|
23942
23954
|
}
|
|
@@ -24316,18 +24328,6 @@ ${g.acceptanceCriteria}` : null,
|
|
|
24316
24328
|
};
|
|
24317
24329
|
}
|
|
24318
24330
|
);
|
|
24319
|
-
server.tool(
|
|
24320
|
-
"list_deliverable_group_deliverables",
|
|
24321
|
-
'List all Deliverables assigned to a DeliverableGroup. Use to answer "what deliverables are in this phase/milestone?" or "what has the team committed to in this engagement group?"',
|
|
24322
|
-
{
|
|
24323
|
-
deliverableGroupId: external_exports.string().describe("The DeliverableGroup ID")
|
|
24324
|
-
},
|
|
24325
|
-
async ({ deliverableGroupId }) => {
|
|
24326
|
-
const items = await client.listDeliverableGroupDeliverables(deliverableGroupId);
|
|
24327
|
-
const text = items.length === 0 ? "No deliverables in this group." : items.map((d) => `[${d.deliverableId}] teamspace: ${d.teamspaceId}`).join("\n");
|
|
24328
|
-
return { content: [{ type: "text", text }] };
|
|
24329
|
-
}
|
|
24330
|
-
);
|
|
24331
24331
|
server.tool(
|
|
24332
24332
|
"list_deliverable_group_drops",
|
|
24333
24333
|
'List all Drops linked to a DeliverableGroup. Use to answer "what releases are part of this phase?" or "which software drops are tied to this engagement milestone?"',
|
|
@@ -24385,108 +24385,6 @@ ${g.acceptanceCriteria}` : null,
|
|
|
24385
24385
|
);
|
|
24386
24386
|
}
|
|
24387
24387
|
|
|
24388
|
-
// ../../libs/harmonica-services/src/mcp/tools/deliverable-tools.ts
|
|
24389
|
-
var import_node_crypto = require("node:crypto");
|
|
24390
|
-
function registerDeliverableTools(server, ctx, client) {
|
|
24391
|
-
server.tool(
|
|
24392
|
-
"list_deliverables",
|
|
24393
|
-
"List all Deliverables (tangible client-facing artifacts or milestones owed by a date \u2014 e.g. board deck, roadmap doc, audit report) for a Teamspace.",
|
|
24394
|
-
{
|
|
24395
|
-
teamspaceId: external_exports.string().describe("The teamspace ID")
|
|
24396
|
-
},
|
|
24397
|
-
async ({ teamspaceId }) => {
|
|
24398
|
-
const deliverables = await client.listTeamspaceDeliverables(teamspaceId);
|
|
24399
|
-
const text = deliverables.length === 0 ? "No deliverables found." : deliverables.map(
|
|
24400
|
-
(d) => `[${d.deliverableId}] ${d.title} \u2014 ${d.status}${d.dueDate ? ` (due ${d.dueDate})` : ""}${d.deliverableGroupId ? ` (group: ${d.deliverableGroupId})` : ""}`
|
|
24401
|
-
).join("\n");
|
|
24402
|
-
return { content: [{ type: "text", text }] };
|
|
24403
|
-
}
|
|
24404
|
-
);
|
|
24405
|
-
server.tool(
|
|
24406
|
-
"get_deliverable",
|
|
24407
|
-
"Get a Deliverable (tangible client-facing artifact or milestone) by ID.",
|
|
24408
|
-
{
|
|
24409
|
-
deliverableId: external_exports.string().describe("The deliverable ID")
|
|
24410
|
-
},
|
|
24411
|
-
async ({ deliverableId }) => {
|
|
24412
|
-
const d = await client.getDeliverable(deliverableId);
|
|
24413
|
-
if (!d) return { content: [{ type: "text", text: `Deliverable not found: ${deliverableId}` }] };
|
|
24414
|
-
const text = [
|
|
24415
|
-
`ID: ${d.deliverableId}`,
|
|
24416
|
-
`Title: ${d.title}`,
|
|
24417
|
-
`Teamspace: ${d.teamspaceId}`,
|
|
24418
|
-
`Status: ${d.status}`,
|
|
24419
|
-
d.description ? `Description: ${d.description}` : null,
|
|
24420
|
-
d.dueDate ? `Due: ${d.dueDate}` : null,
|
|
24421
|
-
d.deliverableGroupId ? `Group: ${d.deliverableGroupId}` : null,
|
|
24422
|
-
`Version: ${d.version}`,
|
|
24423
|
-
`Created: ${d.createdAt}`
|
|
24424
|
-
].filter(Boolean).join("\n");
|
|
24425
|
-
return { content: [{ type: "text", text }] };
|
|
24426
|
-
}
|
|
24427
|
-
);
|
|
24428
|
-
server.tool(
|
|
24429
|
-
"create_deliverable",
|
|
24430
|
-
'Create a Deliverable in a Teamspace. A Deliverable is a tangible commitment the agency owes the client by a date \u2014 board presentation, roadmap document, audit report, design mockups, training session, etc. Use this when the user describes something we will hand over. Do NOT use this for software capabilities the product provides to its end users \u2014 those are Beats (use create_beat). Do NOT use this for context, assumptions, constraints, or decisions \u2014 those are Notes (use create_note). Recognition cue: phrases like "we owe them\u2026", "due by\u2026", "the deck", "the report" \u2192 Deliverable. "Users will be able to\u2026", "the screen that\u2026" \u2192 Beat.',
|
|
24431
|
-
{
|
|
24432
|
-
teamspaceId: external_exports.string().describe("The teamspace ID"),
|
|
24433
|
-
title: external_exports.string().min(1).max(300).describe("Deliverable title"),
|
|
24434
|
-
description: external_exports.string().max(2e3).optional().describe("Optional description"),
|
|
24435
|
-
dueDate: external_exports.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().describe("Due date (YYYY-MM-DD)"),
|
|
24436
|
-
status: external_exports.enum(["draft", "active", "delivered", "cancelled"]).optional().describe("Initial status (default: draft)"),
|
|
24437
|
-
deliverableGroupId: external_exports.string().optional().describe("Assign to a DeliverableGroup by ID at creation time")
|
|
24438
|
-
},
|
|
24439
|
-
async ({ teamspaceId, title, description, dueDate, status, deliverableGroupId }) => {
|
|
24440
|
-
const deliverableId = `dlv-${(0, import_node_crypto.randomUUID)()}`;
|
|
24441
|
-
const d = await client.createDeliverable({
|
|
24442
|
-
deliverableId,
|
|
24443
|
-
teamspaceId,
|
|
24444
|
-
orgId: ctx.orgId,
|
|
24445
|
-
title,
|
|
24446
|
-
description,
|
|
24447
|
-
dueDate,
|
|
24448
|
-
status,
|
|
24449
|
-
createdBy: ctx.user.userId,
|
|
24450
|
-
...deliverableGroupId !== void 0 && { deliverableGroupId }
|
|
24451
|
-
});
|
|
24452
|
-
return {
|
|
24453
|
-
content: [{
|
|
24454
|
-
type: "text",
|
|
24455
|
-
text: `Created deliverable: [${d.deliverableId}] ${d.title} \u2014 ${d.status}`
|
|
24456
|
-
}]
|
|
24457
|
-
};
|
|
24458
|
-
}
|
|
24459
|
-
);
|
|
24460
|
-
server.tool(
|
|
24461
|
-
"update_deliverable",
|
|
24462
|
-
"Update an existing Deliverable. Transition status as the artifact progresses: draft \u2192 active \u2192 delivered (or cancelled).",
|
|
24463
|
-
{
|
|
24464
|
-
deliverableId: external_exports.string().describe("The deliverable ID"),
|
|
24465
|
-
title: external_exports.string().min(1).max(300).optional().describe("New title"),
|
|
24466
|
-
description: external_exports.string().max(2e3).optional().describe("New description"),
|
|
24467
|
-
dueDate: external_exports.string().regex(/^\d{4}-\d{2}-\d{2}$/).nullable().optional().describe("New due date (YYYY-MM-DD), or null to clear"),
|
|
24468
|
-
status: external_exports.enum(["draft", "active", "delivered", "cancelled"]).optional().describe("New status"),
|
|
24469
|
-
deliverableGroupId: external_exports.string().nullable().optional().describe("Assign to a DeliverableGroup by ID, or null to ungroup")
|
|
24470
|
-
},
|
|
24471
|
-
async ({ deliverableId, title, description, dueDate, status, deliverableGroupId }) => {
|
|
24472
|
-
const updates = {};
|
|
24473
|
-
if (title !== void 0) updates["title"] = title;
|
|
24474
|
-
if (description !== void 0) updates["description"] = description;
|
|
24475
|
-
if (dueDate !== void 0) updates["dueDate"] = dueDate;
|
|
24476
|
-
if (status !== void 0) updates["status"] = status;
|
|
24477
|
-
if (deliverableGroupId !== void 0) updates["deliverableGroupId"] = deliverableGroupId;
|
|
24478
|
-
const d = await client.updateDeliverable(deliverableId, updates);
|
|
24479
|
-
if (!d) return { content: [{ type: "text", text: `Deliverable not found: ${deliverableId}` }] };
|
|
24480
|
-
return {
|
|
24481
|
-
content: [{
|
|
24482
|
-
type: "text",
|
|
24483
|
-
text: `Updated deliverable: [${d.deliverableId}] ${d.title} \u2014 ${d.status}`
|
|
24484
|
-
}]
|
|
24485
|
-
};
|
|
24486
|
-
}
|
|
24487
|
-
);
|
|
24488
|
-
}
|
|
24489
|
-
|
|
24490
24388
|
// ../../libs/harmonica-services/src/mcp/tools/downbeat-harmony-report-tools.ts
|
|
24491
24389
|
function formatQualifyingBeat(b) {
|
|
24492
24390
|
return `- \`${b.beatId}\` ${b.title}: ${b.signals.join(", ")}`;
|
|
@@ -25241,7 +25139,7 @@ var STAGE_ENUM = external_exports.enum([
|
|
|
25241
25139
|
"beta",
|
|
25242
25140
|
"prod"
|
|
25243
25141
|
]);
|
|
25244
|
-
function registerFeatureFlagTools(server,
|
|
25142
|
+
function registerFeatureFlagTools(server, ctx, client) {
|
|
25245
25143
|
server.tool(
|
|
25246
25144
|
"list_flags",
|
|
25247
25145
|
"List feature flags and their enabled stages. Use check_flag to test a single flag against a specific stage, or get_flag for full detail on one flag.",
|
|
@@ -25307,6 +25205,89 @@ function registerFeatureFlagTools(server, _ctx, client) {
|
|
|
25307
25205
|
}
|
|
25308
25206
|
}
|
|
25309
25207
|
);
|
|
25208
|
+
server.tool(
|
|
25209
|
+
"create_flag",
|
|
25210
|
+
"Create or update a feature flag with the specified enabled stages. Idempotent \u2014 calling with an existing flag name replaces its enabledIn list.",
|
|
25211
|
+
{
|
|
25212
|
+
name: external_exports.string().min(1).describe('Flag name (e.g. "rbac:enforcement")'),
|
|
25213
|
+
enabledIn: external_exports.array(STAGE_ENUM).describe("Stages to enable the flag in"),
|
|
25214
|
+
description: external_exports.string().optional().describe("Human-readable description of what this flag gates"),
|
|
25215
|
+
note: external_exports.string().optional().describe("Reason for this change (recorded in change history)")
|
|
25216
|
+
},
|
|
25217
|
+
async ({ name, enabledIn, description, note }) => {
|
|
25218
|
+
if (!ctx.user.email) {
|
|
25219
|
+
return { content: [{ type: "text", text: "Write operations require an authenticated user with a valid email." }], isError: true };
|
|
25220
|
+
}
|
|
25221
|
+
try {
|
|
25222
|
+
const flag = await client.createFlag(name, enabledIn, { description, note, updatedBy: ctx.user.email });
|
|
25223
|
+
return { content: [{ type: "text", text: formatFlag(flag) }] };
|
|
25224
|
+
} catch (err) {
|
|
25225
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
25226
|
+
return { content: [{ type: "text", text: `Failed to create flag: ${message}` }], isError: true };
|
|
25227
|
+
}
|
|
25228
|
+
}
|
|
25229
|
+
);
|
|
25230
|
+
server.tool(
|
|
25231
|
+
"set_flag",
|
|
25232
|
+
"Update which stages a feature flag is enabled in. Replaces the current enabledIn list entirely.",
|
|
25233
|
+
{
|
|
25234
|
+
name: external_exports.string().min(1).describe("Flag name"),
|
|
25235
|
+
enabledIn: external_exports.array(STAGE_ENUM).describe("New set of stages to enable the flag in. Pass [] to disable everywhere without archiving."),
|
|
25236
|
+
note: external_exports.string().optional().describe("Reason for this change (recorded in change history)")
|
|
25237
|
+
},
|
|
25238
|
+
async ({ name, enabledIn, note }) => {
|
|
25239
|
+
if (!ctx.user.email) {
|
|
25240
|
+
return { content: [{ type: "text", text: "Write operations require an authenticated user with a valid email." }], isError: true };
|
|
25241
|
+
}
|
|
25242
|
+
try {
|
|
25243
|
+
const flag = await client.setFlag(name, enabledIn, { note, updatedBy: ctx.user.email });
|
|
25244
|
+
return { content: [{ type: "text", text: formatFlag(flag) }] };
|
|
25245
|
+
} catch (err) {
|
|
25246
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
25247
|
+
return { content: [{ type: "text", text: `Failed to set flag: ${message}` }], isError: true };
|
|
25248
|
+
}
|
|
25249
|
+
}
|
|
25250
|
+
);
|
|
25251
|
+
server.tool(
|
|
25252
|
+
"archive_flag",
|
|
25253
|
+
"Archive a feature flag. Clears its enabledIn list and marks it archived so it cannot be re-enabled via set_flag. Use unarchive_flag to restore it.",
|
|
25254
|
+
{
|
|
25255
|
+
name: external_exports.string().min(1).describe("Flag name"),
|
|
25256
|
+
note: external_exports.string().optional().describe("Reason for archiving (recorded in change history)")
|
|
25257
|
+
},
|
|
25258
|
+
async ({ name, note }) => {
|
|
25259
|
+
if (!ctx.user.email) {
|
|
25260
|
+
return { content: [{ type: "text", text: "Write operations require an authenticated user with a valid email." }], isError: true };
|
|
25261
|
+
}
|
|
25262
|
+
try {
|
|
25263
|
+
const flag = await client.archiveFlag(name, { note, updatedBy: ctx.user.email });
|
|
25264
|
+
return { content: [{ type: "text", text: formatFlag(flag) }] };
|
|
25265
|
+
} catch (err) {
|
|
25266
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
25267
|
+
return { content: [{ type: "text", text: `Failed to archive flag: ${message}` }], isError: true };
|
|
25268
|
+
}
|
|
25269
|
+
}
|
|
25270
|
+
);
|
|
25271
|
+
server.tool(
|
|
25272
|
+
"unarchive_flag",
|
|
25273
|
+
"Restore an archived feature flag to operable state. The flag is re-enabled with an empty enabledIn list \u2014 use set_flag afterward to enable it in specific stages.",
|
|
25274
|
+
{
|
|
25275
|
+
name: external_exports.string().min(1).describe("Flag name"),
|
|
25276
|
+
note: external_exports.string().optional().describe("Reason for restoring (recorded in change history)")
|
|
25277
|
+
},
|
|
25278
|
+
async ({ name, note }) => {
|
|
25279
|
+
if (!ctx.user.email) {
|
|
25280
|
+
return { content: [{ type: "text", text: "Write operations require an authenticated user with a valid email." }], isError: true };
|
|
25281
|
+
}
|
|
25282
|
+
try {
|
|
25283
|
+
const flag = await client.unarchiveFlag(name, { note, updatedBy: ctx.user.email });
|
|
25284
|
+
return { content: [{ type: "text", text: formatFlag(flag) }] };
|
|
25285
|
+
} catch (err) {
|
|
25286
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
25287
|
+
return { content: [{ type: "text", text: `Failed to unarchive flag: ${message}` }], isError: true };
|
|
25288
|
+
}
|
|
25289
|
+
}
|
|
25290
|
+
);
|
|
25310
25291
|
}
|
|
25311
25292
|
function formatFlag(flag, history) {
|
|
25312
25293
|
const archived = flag.archivedAt ? " **(archived)**" : "";
|
|
@@ -25316,7 +25297,8 @@ function formatFlag(flag, history) {
|
|
|
25316
25297
|
`**Scope:** ${flag.scope}`,
|
|
25317
25298
|
`**Enabled in:** ${enabled}`,
|
|
25318
25299
|
flag.description ? `**Description:** ${flag.description}` : null,
|
|
25319
|
-
`**Last updated:** ${flag.updatedAt.slice(0, 10)} by ${flag.updatedBy}
|
|
25300
|
+
`**Last updated:** ${flag.updatedAt.slice(0, 10)} by ${flag.updatedBy}`,
|
|
25301
|
+
flag.archivedAt ? `**Archived:** ${flag.archivedAt.slice(0, 10)} by ${flag.archivedBy}` : null
|
|
25320
25302
|
].filter(Boolean).join("\n");
|
|
25321
25303
|
if (!history?.length) return parts;
|
|
25322
25304
|
const historyLines = history.map((h) => {
|
|
@@ -28429,7 +28411,7 @@ ${lines.join("\n")}` }] };
|
|
|
28429
28411
|
}
|
|
28430
28412
|
|
|
28431
28413
|
// ../../libs/harmonica-services/src/mcp/tools/onboarding-tools.ts
|
|
28432
|
-
var
|
|
28414
|
+
var import_node_crypto = require("node:crypto");
|
|
28433
28415
|
var OnboardingNoteInputSchema = external_exports.object({
|
|
28434
28416
|
noteType: external_exports.enum(["context", "assumption", "constraint", "guidance", "decision"]),
|
|
28435
28417
|
content: external_exports.string().min(1),
|
|
@@ -28441,11 +28423,6 @@ var OnboardingProjectInputSchema = external_exports.object({
|
|
|
28441
28423
|
description: external_exports.string().max(2e3).optional(),
|
|
28442
28424
|
notes: external_exports.array(OnboardingNoteInputSchema).optional()
|
|
28443
28425
|
});
|
|
28444
|
-
var OnboardingDeliverableInputSchema = external_exports.object({
|
|
28445
|
-
title: external_exports.string().min(1).max(300),
|
|
28446
|
-
description: external_exports.string().max(2e3).optional(),
|
|
28447
|
-
dueDate: external_exports.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional()
|
|
28448
|
-
});
|
|
28449
28426
|
function registerOnboardingTools(server, ctx, client) {
|
|
28450
28427
|
server.tool(
|
|
28451
28428
|
"initiate_teamspace_onboarding",
|
|
@@ -28543,7 +28520,7 @@ function registerOnboardingTools(server, ctx, client) {
|
|
|
28543
28520
|
server.tool(
|
|
28544
28521
|
"create_teamspace_onboarding_batch",
|
|
28545
28522
|
[
|
|
28546
|
-
"Create a Teamspace, Projects,
|
|
28523
|
+
"Create a Teamspace, Projects, and Notes",
|
|
28547
28524
|
"from a PM-approved onboarding payload in a single batch operation.",
|
|
28548
28525
|
"Call this after the PM approves the pre-flight review card from initiate_teamspace_onboarding.",
|
|
28549
28526
|
"Returns a creation receipt with IDs and counts for all created entities.",
|
|
@@ -28552,20 +28529,18 @@ function registerOnboardingTools(server, ctx, client) {
|
|
|
28552
28529
|
{
|
|
28553
28530
|
teamspaceName: external_exports.string().min(1).max(200).describe("Teamspace display name"),
|
|
28554
28531
|
projects: external_exports.array(OnboardingProjectInputSchema).min(1).describe("Phase 1 projects to create, each linked to the Teamspace"),
|
|
28555
|
-
teamspaceNotes: external_exports.array(OnboardingNoteInputSchema).describe("Constraints, assumptions, and context notes at the Teamspace/project level")
|
|
28556
|
-
deliverables: external_exports.array(OnboardingDeliverableInputSchema).describe("Deliverables detected from commitment language in documents")
|
|
28532
|
+
teamspaceNotes: external_exports.array(OnboardingNoteInputSchema).describe("Constraints, assumptions, and context notes at the Teamspace/project level")
|
|
28557
28533
|
},
|
|
28558
28534
|
async ({
|
|
28559
28535
|
teamspaceName,
|
|
28560
28536
|
projects,
|
|
28561
|
-
teamspaceNotes
|
|
28562
|
-
deliverables
|
|
28537
|
+
teamspaceNotes
|
|
28563
28538
|
}) => {
|
|
28564
28539
|
const lines = [];
|
|
28565
28540
|
let teamspace;
|
|
28566
28541
|
try {
|
|
28567
28542
|
teamspace = await client.createTeamspace({
|
|
28568
|
-
teamspaceId: (0,
|
|
28543
|
+
teamspaceId: (0, import_node_crypto.randomUUID)(),
|
|
28569
28544
|
slug: teamspaceName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, ""),
|
|
28570
28545
|
orgId: ctx.orgId,
|
|
28571
28546
|
name: teamspaceName,
|
|
@@ -28582,8 +28557,8 @@ Error: ${msg}`);
|
|
|
28582
28557
|
const createdProjects = [];
|
|
28583
28558
|
for (const p of projects) {
|
|
28584
28559
|
try {
|
|
28585
|
-
const project = await client.
|
|
28586
|
-
projectId: (0,
|
|
28560
|
+
const project = await client.createSystem({
|
|
28561
|
+
projectId: (0, import_node_crypto.randomUUID)(),
|
|
28587
28562
|
orgId: ctx.orgId,
|
|
28588
28563
|
teamspaceId: teamspace.teamspaceId,
|
|
28589
28564
|
ownerUserId: ctx.user?.userId ?? "system",
|
|
@@ -28627,7 +28602,7 @@ Projects (${createdProjects.length}):`);
|
|
|
28627
28602
|
for (const note of projects[i]?.notes ?? []) {
|
|
28628
28603
|
try {
|
|
28629
28604
|
const n = await client.createNote({
|
|
28630
|
-
noteId: `N-TEMP-${(0,
|
|
28605
|
+
noteId: `N-TEMP-${(0, import_node_crypto.randomUUID)()}`,
|
|
28631
28606
|
// overridden server-side
|
|
28632
28607
|
projectId: project.projectId,
|
|
28633
28608
|
noteType: note.noteType,
|
|
@@ -28644,24 +28619,6 @@ Projects (${createdProjects.length}):`);
|
|
|
28644
28619
|
}
|
|
28645
28620
|
lines.push(`
|
|
28646
28621
|
Notes filed: ${createdNotes.length}`);
|
|
28647
|
-
const createdDeliverables = [];
|
|
28648
|
-
for (const d of deliverables) {
|
|
28649
|
-
try {
|
|
28650
|
-
const del = await client.createDeliverable({
|
|
28651
|
-
deliverableId: (0, import_node_crypto2.randomUUID)(),
|
|
28652
|
-
// overridden server-side
|
|
28653
|
-
teamspaceId: teamspace.teamspaceId,
|
|
28654
|
-
orgId: ctx.orgId,
|
|
28655
|
-
title: d.title,
|
|
28656
|
-
description: d.description,
|
|
28657
|
-
dueDate: d.dueDate,
|
|
28658
|
-
createdBy: ctx.user?.userId ?? "mcp"
|
|
28659
|
-
});
|
|
28660
|
-
createdDeliverables.push(del.deliverableId);
|
|
28661
|
-
} catch {
|
|
28662
|
-
}
|
|
28663
|
-
}
|
|
28664
|
-
lines.push(`Deliverables: ${createdDeliverables.length}`);
|
|
28665
28622
|
lines.unshift(`\u2705 Onboarding batch created successfully.`);
|
|
28666
28623
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
28667
28624
|
}
|
|
@@ -29967,7 +29924,7 @@ function registerSessionTools(server, ctx, client) {
|
|
|
29967
29924
|
includeTerminal: external_exports.boolean().optional().describe("Include terminal (closed) sessions. Default false.")
|
|
29968
29925
|
},
|
|
29969
29926
|
async ({ systemId, status, includeTerminal }) => {
|
|
29970
|
-
const sessions = await client.
|
|
29927
|
+
const sessions = await client.listSystemSessions(systemId, {
|
|
29971
29928
|
status,
|
|
29972
29929
|
includeTerminal
|
|
29973
29930
|
});
|
|
@@ -30634,7 +30591,7 @@ function registerProjectTools(server, ctx, client) {
|
|
|
30634
30591
|
fetchProjectInOrg(client, systemId, ctx.orgId),
|
|
30635
30592
|
client.getOrg(ctx.orgId)
|
|
30636
30593
|
]);
|
|
30637
|
-
const notes = await client.
|
|
30594
|
+
const notes = await client.listSystemNotes(systemId, {
|
|
30638
30595
|
limit: noteLimit ?? DEFAULT_CONTEXT_NOTE_LIMIT
|
|
30639
30596
|
});
|
|
30640
30597
|
const text = formatProjectContext(project, notes, org?.coda);
|
|
@@ -30802,7 +30759,7 @@ function registerProjectTools(server, ctx, client) {
|
|
|
30802
30759
|
}
|
|
30803
30760
|
|
|
30804
30761
|
// ../../libs/harmonica-services/src/mcp/tools/teamspace-tools.ts
|
|
30805
|
-
var
|
|
30762
|
+
var import_node_crypto2 = require("node:crypto");
|
|
30806
30763
|
var EnsembleMemberSchema = external_exports.discriminatedUnion("type", [
|
|
30807
30764
|
external_exports.object({ type: external_exports.literal("human"), email: external_exports.string().email().max(254), name: external_exports.string().min(1).max(200) }),
|
|
30808
30765
|
external_exports.object({ type: external_exports.literal("agent"), agentId: external_exports.string().min(1).max(100), name: external_exports.string().min(1).max(200) })
|
|
@@ -30841,7 +30798,7 @@ function registerTeamspaceTools(server, ctx, client) {
|
|
|
30841
30798
|
if (!ts || ts.orgId !== ctx.orgId) {
|
|
30842
30799
|
return { content: [{ type: "text", text: `Teamspace not found: ${teamspaceId}` }], isError: true };
|
|
30843
30800
|
}
|
|
30844
|
-
const allProjects = await client.
|
|
30801
|
+
const allProjects = await client.listOrgSystems(ctx.orgId);
|
|
30845
30802
|
const tsProjects = allProjects.filter((p) => p.teamspaceId === teamspaceId);
|
|
30846
30803
|
const lines = [
|
|
30847
30804
|
`ID: ${ts.teamspaceId}`,
|
|
@@ -30878,7 +30835,7 @@ function registerTeamspaceTools(server, ctx, client) {
|
|
|
30878
30835
|
name: external_exports.string().min(1).max(200).describe("Teamspace name")
|
|
30879
30836
|
},
|
|
30880
30837
|
async ({ name }) => {
|
|
30881
|
-
const teamspaceId = `ts-${(0,
|
|
30838
|
+
const teamspaceId = `ts-${(0, import_node_crypto2.randomUUID)()}`;
|
|
30882
30839
|
const slug = generateTeamspaceSlug(name);
|
|
30883
30840
|
const ts = await client.createTeamspace({
|
|
30884
30841
|
teamspaceId,
|
|
@@ -31016,7 +30973,7 @@ function registerValueVelocityTools(server, ctx, client) {
|
|
|
31016
30973
|
try {
|
|
31017
30974
|
await assertProjectInOrg(client, systemId, ctx.orgId);
|
|
31018
30975
|
const [rankedResult, staleWResult] = await Promise.allSettled([
|
|
31019
|
-
withLeverage ? client.
|
|
30976
|
+
withLeverage ? client.rankSystemBeatVersionsWithLeverage(systemId, lens) : client.rankSystemBeatVersions(systemId, lens),
|
|
31020
30977
|
client.getStaleWBeatIds(systemId)
|
|
31021
30978
|
]);
|
|
31022
30979
|
if (rankedResult.status === "rejected") {
|
|
@@ -31510,7 +31467,7 @@ ${JSON.stringify(task.result, null, 2)}
|
|
|
31510
31467
|
},
|
|
31511
31468
|
async ({ projectId, status, limit }) => {
|
|
31512
31469
|
await assertProjectInOrg(client, projectId, ctx.orgId);
|
|
31513
|
-
const tasks = await client.
|
|
31470
|
+
const tasks = await client.listSystemTasks(projectId, {
|
|
31514
31471
|
status,
|
|
31515
31472
|
limit
|
|
31516
31473
|
});
|
|
@@ -31568,7 +31525,7 @@ ${JSON.stringify(task.result, null, 2)}
|
|
|
31568
31525
|
},
|
|
31569
31526
|
async ({ projectId, status, limit }) => {
|
|
31570
31527
|
await assertProjectInOrg(client, projectId, ctx.orgId);
|
|
31571
|
-
const tasks = await client.
|
|
31528
|
+
const tasks = await client.listSystemTasks(projectId, {
|
|
31572
31529
|
status,
|
|
31573
31530
|
limit
|
|
31574
31531
|
});
|
|
@@ -31870,7 +31827,6 @@ var TOOL_PROFILES = Object.freeze({
|
|
|
31870
31827
|
allow(registerBeatVersionTools, ["list_beat_versions", "get_beat_version"]),
|
|
31871
31828
|
allow(registerNoteTools, ["list_notes", "get_note", "create_note", "list_documents"]),
|
|
31872
31829
|
allow(registerDropTools, ["list_drops", "get_drop"]),
|
|
31873
|
-
allow(registerDeliverableTools, ["list_deliverables", "get_deliverable"]),
|
|
31874
31830
|
allow(registerEmbeddingTools, ["search", "find_similar_notes"])
|
|
31875
31831
|
])
|
|
31876
31832
|
});
|
|
@@ -31923,7 +31879,6 @@ function registerAllTools(server, ctx, client, profile) {
|
|
|
31923
31879
|
registerBaselineTools(server, ctx, client);
|
|
31924
31880
|
registerTeamspaceTools(server, ctx, client);
|
|
31925
31881
|
registerDeliverableGroupTools(server, ctx, client);
|
|
31926
|
-
registerDeliverableTools(server, ctx, client);
|
|
31927
31882
|
registerDropTools(server, ctx, client);
|
|
31928
31883
|
registerSessionTools(server, ctx, client);
|
|
31929
31884
|
registerOnboardingTools(server, ctx, client);
|
|
@@ -31942,12 +31897,12 @@ function registerAllTools(server, ctx, client, profile) {
|
|
|
31942
31897
|
// ../../libs/harmonica-services/src/mcp/resources/beat-resources.ts
|
|
31943
31898
|
function registerBeatResources(server, ctx, client) {
|
|
31944
31899
|
server.resource(
|
|
31945
|
-
"
|
|
31946
|
-
new ResourceTemplate("harmonica://
|
|
31947
|
-
async (uri, {
|
|
31948
|
-
const
|
|
31949
|
-
await
|
|
31950
|
-
const beats = await client.listSystemBeats(
|
|
31900
|
+
"system-beats",
|
|
31901
|
+
new ResourceTemplate("harmonica://system/{systemId}/beats", { list: void 0 }),
|
|
31902
|
+
async (uri, { systemId }) => {
|
|
31903
|
+
const sid = String(systemId);
|
|
31904
|
+
await fetchSystemInOrg(client, sid, ctx.orgId);
|
|
31905
|
+
const beats = await client.listSystemBeats(sid);
|
|
31951
31906
|
const text = formatBeatSummaryTable(beats);
|
|
31952
31907
|
return { contents: [{ uri: uri.href, text }] };
|
|
31953
31908
|
}
|
|
@@ -31982,14 +31937,14 @@ function registerGuidelinesResources(server, client) {
|
|
|
31982
31937
|
}
|
|
31983
31938
|
|
|
31984
31939
|
// ../../libs/harmonica-services/src/mcp/resources/system-resources.ts
|
|
31985
|
-
function
|
|
31940
|
+
function registerSystemResources(server, ctx, client) {
|
|
31986
31941
|
server.resource(
|
|
31987
|
-
"
|
|
31988
|
-
new ResourceTemplate("harmonica://
|
|
31989
|
-
async (uri, {
|
|
31990
|
-
const
|
|
31991
|
-
const project = await
|
|
31992
|
-
const notes = await client.listSystemNotes(
|
|
31942
|
+
"system-context",
|
|
31943
|
+
new ResourceTemplate("harmonica://system/{systemId}/context", { list: void 0 }),
|
|
31944
|
+
async (uri, { systemId }) => {
|
|
31945
|
+
const sid = String(systemId);
|
|
31946
|
+
const project = await fetchSystemInOrg(client, sid, ctx.orgId);
|
|
31947
|
+
const notes = await client.listSystemNotes(sid, { limit: DEFAULT_CONTEXT_NOTE_LIMIT });
|
|
31993
31948
|
const text = formatProjectContext(project, notes);
|
|
31994
31949
|
return { contents: [{ uri: uri.href, text }] };
|
|
31995
31950
|
}
|
|
@@ -31998,7 +31953,7 @@ function registerProjectResources(server, ctx, client) {
|
|
|
31998
31953
|
|
|
31999
31954
|
// ../../libs/harmonica-services/src/mcp/resources/index.ts
|
|
32000
31955
|
function registerAllResources(server, ctx, client) {
|
|
32001
|
-
|
|
31956
|
+
registerSystemResources(server, ctx, client);
|
|
32002
31957
|
registerBeatResources(server, ctx, client);
|
|
32003
31958
|
registerGuidelinesResources(server, client);
|
|
32004
31959
|
}
|
|
@@ -32269,46 +32224,11 @@ function createHttpClient(config2) {
|
|
|
32269
32224
|
if (!raw) return void 0;
|
|
32270
32225
|
return { ...raw, projectId: raw.id ?? raw.projectId, title: raw.name ?? raw.title, orgId: raw.organizationId ?? raw.orgId };
|
|
32271
32226
|
},
|
|
32272
|
-
// @deprecated aliases — remove in cleanup increment (BV2)
|
|
32273
|
-
listOrgProjects: async (orgId) => {
|
|
32274
|
-
const raw = await request("GET", `/api/organizations/${encodeURIComponent(orgId)}/projects/summaries`);
|
|
32275
|
-
return (raw ?? []).map((p) => ({ ...p, projectId: p.id, title: p.name, orgId: p.organizationId }));
|
|
32276
|
-
},
|
|
32277
|
-
getProject: async (projectId) => {
|
|
32278
|
-
const raw = await request("GET", `/api/systems/${encodeURIComponent(projectId)}`);
|
|
32279
|
-
if (!raw) return void 0;
|
|
32280
|
-
return {
|
|
32281
|
-
...raw,
|
|
32282
|
-
projectId: raw.id ?? raw.projectId,
|
|
32283
|
-
title: raw.name ?? raw.title,
|
|
32284
|
-
orgId: raw.organizationId ?? raw.orgId
|
|
32285
|
-
};
|
|
32286
|
-
},
|
|
32287
|
-
createProject: async (input) => {
|
|
32288
|
-
const raw = await request("POST", "/api/systems", {
|
|
32289
|
-
organizationId: input.orgId,
|
|
32290
|
-
teamspaceId: input.teamspaceId,
|
|
32291
|
-
name: input.title,
|
|
32292
|
-
description: input.description,
|
|
32293
|
-
strategy: input.strategy,
|
|
32294
|
-
// Without this the owning Account is dropped on the wire and the System
|
|
32295
|
-
// is created unlinked — invisible in the Account's Systems list.
|
|
32296
|
-
...input.accountId !== void 0 && { accountId: input.accountId }
|
|
32297
|
-
});
|
|
32298
|
-
return { ...raw, orgId: raw?.organizationId ?? raw?.orgId };
|
|
32299
|
-
},
|
|
32300
|
-
updateProject: (projectId, updates) => request("PATCH", `/api/systems/${encodeURIComponent(projectId)}`, updates),
|
|
32301
|
-
archiveProject: (projectId) => request("PATCH", `/api/systems/${encodeURIComponent(projectId)}/archive`),
|
|
32302
32227
|
getSystemFact: async (projectId) => {
|
|
32303
32228
|
const result = await request("GET", `/api/systems/${encodeURIComponent(projectId)}/facts`);
|
|
32304
32229
|
return result?.data;
|
|
32305
32230
|
},
|
|
32306
|
-
getProjectFact: async (projectId) => {
|
|
32307
|
-
const result = await request("GET", `/api/systems/${encodeURIComponent(projectId)}/facts`);
|
|
32308
|
-
return result?.data;
|
|
32309
|
-
},
|
|
32310
32231
|
saveSystemFact: (input) => request("PUT", `/api/systems/${encodeURIComponent(String(input.projectId))}/facts`, input),
|
|
32311
|
-
saveProjectFact: (input) => request("PUT", `/api/systems/${encodeURIComponent(String(input.projectId))}/facts`, input),
|
|
32312
32232
|
transitionSystemLifecycleState: async (projectId, targetState, options) => {
|
|
32313
32233
|
return request("POST", `/api/systems/${encodeURIComponent(projectId)}/lifecycle/transitions`, {
|
|
32314
32234
|
targetState,
|
|
@@ -32316,13 +32236,6 @@ function createHttpClient(config2) {
|
|
|
32316
32236
|
decisionNoteId: options.decisionNoteId
|
|
32317
32237
|
});
|
|
32318
32238
|
},
|
|
32319
|
-
transitionProjectLifecycleState: async (projectId, targetState, options) => {
|
|
32320
|
-
return request("POST", `/api/systems/${encodeURIComponent(projectId)}/lifecycle/transitions`, {
|
|
32321
|
-
targetState,
|
|
32322
|
-
reason: options.reason,
|
|
32323
|
-
decisionNoteId: options.decisionNoteId
|
|
32324
|
-
});
|
|
32325
|
-
},
|
|
32326
32239
|
// Beats
|
|
32327
32240
|
getNextBeatId: async (projectId) => {
|
|
32328
32241
|
const result = await request("POST", `/api/systems/${encodeURIComponent(projectId)}/beats/next-id`);
|
|
@@ -32500,22 +32413,6 @@ function createHttpClient(config2) {
|
|
|
32500
32413
|
const result = await request("GET", `/api/systems/${encodeURIComponent(projectId)}/notes${qs}`);
|
|
32501
32414
|
return result?.notes ?? [];
|
|
32502
32415
|
},
|
|
32503
|
-
listProjectNotes: async (projectId, filters) => {
|
|
32504
|
-
const params = new URLSearchParams();
|
|
32505
|
-
if (filters?.noteType) {
|
|
32506
|
-
const types = Array.isArray(filters.noteType) ? filters.noteType : [filters.noteType];
|
|
32507
|
-
types.forEach((t) => params.append("type", t));
|
|
32508
|
-
}
|
|
32509
|
-
if (filters?.status) params.set("status", filters.status);
|
|
32510
|
-
if (filters?.revisionId) params.set("revisionId", filters.revisionId);
|
|
32511
|
-
if (filters?.beatVersionId) params.set("beatVersionId", filters.beatVersionId);
|
|
32512
|
-
if (filters?.excludeChildren) params.set("excludeChildren", "true");
|
|
32513
|
-
if (filters?.significance) params.set("significance", filters.significance);
|
|
32514
|
-
if (filters?.limit !== void 0) params.set("limit", String(filters.limit));
|
|
32515
|
-
const qs = params.toString() ? `?${params.toString()}` : "";
|
|
32516
|
-
const result = await request("GET", `/api/systems/${encodeURIComponent(projectId)}/notes${qs}`);
|
|
32517
|
-
return result?.notes ?? [];
|
|
32518
|
-
},
|
|
32519
32416
|
listAllSystemNotes: async (projectId, filters, limit, cursor) => {
|
|
32520
32417
|
const params = new URLSearchParams();
|
|
32521
32418
|
if (filters?.noteType) {
|
|
@@ -32534,24 +32431,6 @@ function createHttpClient(config2) {
|
|
|
32534
32431
|
const result = await request("GET", `/api/systems/${encodeURIComponent(projectId)}/notes/all${qs}`);
|
|
32535
32432
|
return { notes: result?.notes ?? [], cursor: result?.cursor, hasMore: result?.hasMore ?? false };
|
|
32536
32433
|
},
|
|
32537
|
-
listAllProjectNotes: async (projectId, filters, limit, cursor) => {
|
|
32538
|
-
const params = new URLSearchParams();
|
|
32539
|
-
if (filters?.noteType) {
|
|
32540
|
-
const types = Array.isArray(filters.noteType) ? filters.noteType : [filters.noteType];
|
|
32541
|
-
types.forEach((t) => params.append("type", t));
|
|
32542
|
-
}
|
|
32543
|
-
if (filters?.excludeNoteType) params.set("excludeType", filters.excludeNoteType);
|
|
32544
|
-
if (filters?.status) params.set("status", filters.status);
|
|
32545
|
-
if (filters?.revisionId) params.set("revisionId", filters.revisionId);
|
|
32546
|
-
if (filters?.beatVersionId) params.set("beatVersionId", filters.beatVersionId);
|
|
32547
|
-
if (filters?.excludeChildren) params.set("excludeChildren", "true");
|
|
32548
|
-
if (filters?.significance) params.set("significance", filters.significance);
|
|
32549
|
-
if (limit !== void 0) params.set("limit", String(limit));
|
|
32550
|
-
if (cursor !== void 0) params.set("cursor", cursor);
|
|
32551
|
-
const qs = params.toString() ? `?${params.toString()}` : "";
|
|
32552
|
-
const result = await request("GET", `/api/systems/${encodeURIComponent(projectId)}/notes/all${qs}`);
|
|
32553
|
-
return { notes: result?.notes ?? [], cursor: result?.cursor, hasMore: result?.hasMore ?? false };
|
|
32554
|
-
},
|
|
32555
32434
|
listBeatNotes: async (beatId, filters) => {
|
|
32556
32435
|
const beat = await request("GET", `/api/beats/${encodeURIComponent(beatId)}`);
|
|
32557
32436
|
if (!beat) return [];
|
|
@@ -32644,7 +32523,6 @@ function createHttpClient(config2) {
|
|
|
32644
32523
|
},
|
|
32645
32524
|
// Gaps are deprecated — replaced by assumption Notes. Return empty results.
|
|
32646
32525
|
getSystemGaps: async () => [],
|
|
32647
|
-
getProjectGaps: async () => [],
|
|
32648
32526
|
updateInformationGap: async () => false,
|
|
32649
32527
|
// Revisions
|
|
32650
32528
|
createRevision: async (projectId, beatId, input) => {
|
|
@@ -32669,14 +32547,6 @@ function createHttpClient(config2) {
|
|
|
32669
32547
|
const result = await request("GET", `/api/systems/${encodeURIComponent(projectId)}/revisions${qs}`);
|
|
32670
32548
|
return result ?? [];
|
|
32671
32549
|
},
|
|
32672
|
-
listProjectRevisions: async (projectId, options) => {
|
|
32673
|
-
const params = new URLSearchParams();
|
|
32674
|
-
if (options?.status) params.set("status", options.status);
|
|
32675
|
-
if (options?.includeArchived) params.set("includeArchived", "true");
|
|
32676
|
-
const qs = params.toString() ? `?${params.toString()}` : "";
|
|
32677
|
-
const result = await request("GET", `/api/systems/${encodeURIComponent(projectId)}/revisions${qs}`);
|
|
32678
|
-
return result ?? [];
|
|
32679
|
-
},
|
|
32680
32550
|
listBeatRevisions: async (projectId, beatId, options) => {
|
|
32681
32551
|
const params = new URLSearchParams();
|
|
32682
32552
|
params.set("beatId", beatId);
|
|
@@ -32906,14 +32776,6 @@ function createHttpClient(config2) {
|
|
|
32906
32776
|
const result = await request("GET", `/api/sessions?${params.toString()}`);
|
|
32907
32777
|
return result ?? [];
|
|
32908
32778
|
},
|
|
32909
|
-
listProjectSessions: async (projectId, options) => {
|
|
32910
|
-
const params = new URLSearchParams();
|
|
32911
|
-
params.set("projectId", projectId);
|
|
32912
|
-
if (options?.status) params.set("status", options.status);
|
|
32913
|
-
if (options?.includeTerminal) params.set("includeTerminal", "true");
|
|
32914
|
-
const result = await request("GET", `/api/sessions?${params.toString()}`);
|
|
32915
|
-
return result ?? [];
|
|
32916
|
-
},
|
|
32917
32779
|
listBeatSessions: async (beatId, options) => {
|
|
32918
32780
|
const params = new URLSearchParams();
|
|
32919
32781
|
params.set("beatId", beatId);
|
|
@@ -33101,14 +32963,6 @@ function createHttpClient(config2) {
|
|
|
33101
32963
|
const result = await request("GET", `/api/systems/${encodeURIComponent(projectId)}/tasks${qs}`);
|
|
33102
32964
|
return result?.tasks ?? [];
|
|
33103
32965
|
},
|
|
33104
|
-
listProjectTasks: async (projectId, options) => {
|
|
33105
|
-
const params = new URLSearchParams();
|
|
33106
|
-
if (options?.status) params.set("status", options.status);
|
|
33107
|
-
if (options?.limit) params.set("limit", String(options.limit));
|
|
33108
|
-
const qs = params.toString() ? `?${params.toString()}` : "";
|
|
33109
|
-
const result = await request("GET", `/api/systems/${encodeURIComponent(projectId)}/tasks${qs}`);
|
|
33110
|
-
return result?.tasks ?? [];
|
|
33111
|
-
},
|
|
33112
32966
|
listTaskEvents: async (taskId, options) => {
|
|
33113
32967
|
const params = new URLSearchParams();
|
|
33114
32968
|
if (options?.afterSeq !== void 0) params.set("after", String(options.afterSeq));
|
|
@@ -33141,15 +32995,6 @@ function createHttpClient(config2) {
|
|
|
33141
32995
|
const result = await request("GET", path);
|
|
33142
32996
|
return { entries: result.activities ?? [], hasMore: false };
|
|
33143
32997
|
},
|
|
33144
|
-
listProjectActivities: async (projectId, options) => {
|
|
33145
|
-
const params = new URLSearchParams();
|
|
33146
|
-
if (options?.limit) params.set("limit", String(options.limit));
|
|
33147
|
-
if (options?.minImportance) params.set("importance", options.minImportance);
|
|
33148
|
-
const qs = params.toString();
|
|
33149
|
-
const path = `/api/systems/${encodeURIComponent(projectId)}/activities${qs ? `?${qs}` : ""}`;
|
|
33150
|
-
const result = await request("GET", path);
|
|
33151
|
-
return { entries: result.activities ?? [], hasMore: false };
|
|
33152
|
-
},
|
|
33153
32998
|
createActivity: async (input) => {
|
|
33154
32999
|
const result = await request("POST", `/api/systems/${encodeURIComponent(input.projectId)}/activities`, {
|
|
33155
33000
|
action: input.action,
|
|
@@ -33224,20 +33069,6 @@ function createHttpClient(config2) {
|
|
|
33224
33069
|
);
|
|
33225
33070
|
return result.ranked ?? [];
|
|
33226
33071
|
},
|
|
33227
|
-
rankProjectBeatVersions: async (projectId, lens) => {
|
|
33228
|
-
const result = await request(
|
|
33229
|
-
"GET",
|
|
33230
|
-
`/api/systems/${encodeURIComponent(projectId)}/beat-versions/ranked?lens=${encodeURIComponent(lens)}`
|
|
33231
|
-
);
|
|
33232
|
-
return result.ranked ?? [];
|
|
33233
|
-
},
|
|
33234
|
-
rankProjectBeatVersionsWithLeverage: async (projectId, lens) => {
|
|
33235
|
-
const result = await request(
|
|
33236
|
-
"GET",
|
|
33237
|
-
`/api/systems/${encodeURIComponent(projectId)}/beat-versions/ranked?lens=${encodeURIComponent(lens)}&withLeverage=true`
|
|
33238
|
-
);
|
|
33239
|
-
return result.ranked ?? [];
|
|
33240
|
-
},
|
|
33241
33072
|
// All four use requestOrThrow, not request. These endpoints answer 404 for a
|
|
33242
33073
|
// missing edge/Beat with a real domain message, and `request()` turns a 404
|
|
33243
33074
|
// into `undefined` — so the old `result.edge` access threw
|
|
@@ -33536,18 +33367,6 @@ function createHttpClient(config2) {
|
|
|
33536
33367
|
);
|
|
33537
33368
|
return { checks: res?.checks ?? [], nextCursor: res?.nextCursor };
|
|
33538
33369
|
},
|
|
33539
|
-
listProjectChecks: async (projectId, checkType, options) => {
|
|
33540
|
-
const params = new URLSearchParams();
|
|
33541
|
-
if (checkType) params.set("type", checkType);
|
|
33542
|
-
if (options?.limit !== void 0) params.set("limit", String(options.limit));
|
|
33543
|
-
if (options?.cursor) params.set("cursor", options.cursor);
|
|
33544
|
-
const qs = params.toString() ? `?${params.toString()}` : "";
|
|
33545
|
-
const res = await request(
|
|
33546
|
-
"GET",
|
|
33547
|
-
`/api/systems/${encodeURIComponent(projectId)}/checks${qs}`
|
|
33548
|
-
);
|
|
33549
|
-
return { checks: res?.checks ?? [], nextCursor: res?.nextCursor };
|
|
33550
|
-
},
|
|
33551
33370
|
listLatestSystemChecks: async (projectId) => {
|
|
33552
33371
|
const res = await request(
|
|
33553
33372
|
"GET",
|
|
@@ -33555,13 +33374,6 @@ function createHttpClient(config2) {
|
|
|
33555
33374
|
);
|
|
33556
33375
|
return res?.checks ?? [];
|
|
33557
33376
|
},
|
|
33558
|
-
listLatestProjectChecks: async (projectId) => {
|
|
33559
|
-
const res = await request(
|
|
33560
|
-
"GET",
|
|
33561
|
-
`/api/checks/latest?projectId=${encodeURIComponent(projectId)}`
|
|
33562
|
-
);
|
|
33563
|
-
return res?.checks ?? [];
|
|
33564
|
-
},
|
|
33565
33377
|
listBeatChecks: async (beatId, projectId, checkType) => {
|
|
33566
33378
|
const qs = checkType ? `?type=${encodeURIComponent(checkType)}` : "";
|
|
33567
33379
|
const res = await request(
|
|
@@ -33621,20 +33433,6 @@ function createHttpClient(config2) {
|
|
|
33621
33433
|
updateTeamspace: async (teamspaceId, updates) => {
|
|
33622
33434
|
return request("PATCH", `/api/teamspaces/${encodeURIComponent(teamspaceId)}`, updates);
|
|
33623
33435
|
},
|
|
33624
|
-
// Deliverables
|
|
33625
|
-
listTeamspaceDeliverables: async (teamspaceId) => {
|
|
33626
|
-
const res = await request("GET", `/api/teamspaces/${encodeURIComponent(teamspaceId)}/deliverables`);
|
|
33627
|
-
return res?.deliverables ?? [];
|
|
33628
|
-
},
|
|
33629
|
-
getDeliverable: async (deliverableId) => {
|
|
33630
|
-
return request("GET", `/api/deliverables/${encodeURIComponent(deliverableId)}`);
|
|
33631
|
-
},
|
|
33632
|
-
createDeliverable: async (input) => {
|
|
33633
|
-
return request("POST", `/api/teamspaces/${encodeURIComponent(input.teamspaceId)}/deliverables`, input);
|
|
33634
|
-
},
|
|
33635
|
-
updateDeliverable: async (deliverableId, updates) => {
|
|
33636
|
-
return request("PATCH", `/api/deliverables/${encodeURIComponent(deliverableId)}`, updates);
|
|
33637
|
-
},
|
|
33638
33436
|
// DeliverableGroups
|
|
33639
33437
|
listTeamspaceDeliverableGroups: async (teamspaceId) => {
|
|
33640
33438
|
const res = await request("GET", `/api/teamspaces/${encodeURIComponent(teamspaceId)}/deliverable-groups`);
|
|
@@ -33646,11 +33444,6 @@ function createHttpClient(config2) {
|
|
|
33646
33444
|
if (res === void 0) throw new Error(`Project ${projectId} not found`);
|
|
33647
33445
|
return res.deliverableGroups;
|
|
33648
33446
|
},
|
|
33649
|
-
listProjectDeliverableGroups: async (projectId) => {
|
|
33650
|
-
const res = await request("GET", `/api/systems/${encodeURIComponent(projectId)}/deliverable-groups`);
|
|
33651
|
-
if (res === void 0) throw new Error(`Project ${projectId} not found`);
|
|
33652
|
-
return res.deliverableGroups;
|
|
33653
|
-
},
|
|
33654
33447
|
listMovementDeliverableGroups: async (movementId) => {
|
|
33655
33448
|
const res = await request("GET", `/api/movements/${encodeURIComponent(movementId)}/deliverable-groups`);
|
|
33656
33449
|
if (res === void 0) throw new Error(`Movement ${movementId} not found`);
|
|
@@ -33687,10 +33480,6 @@ function createHttpClient(config2) {
|
|
|
33687
33480
|
...opts ?? {}
|
|
33688
33481
|
});
|
|
33689
33482
|
},
|
|
33690
|
-
listDeliverableGroupDeliverables: async (deliverableGroupId) => {
|
|
33691
|
-
const res = await request("GET", `/api/deliverable-groups/${encodeURIComponent(deliverableGroupId)}/deliverables`);
|
|
33692
|
-
return res?.deliverables ?? [];
|
|
33693
|
-
},
|
|
33694
33483
|
listDeliverableGroupDrops: async (deliverableGroupId) => {
|
|
33695
33484
|
const res = await request("GET", `/api/deliverable-groups/${encodeURIComponent(deliverableGroupId)}/drops`);
|
|
33696
33485
|
return res?.drops ?? [];
|
|
@@ -34270,16 +34059,54 @@ function createHttpClient(config2) {
|
|
|
34270
34059
|
);
|
|
34271
34060
|
return result?.usedBy;
|
|
34272
34061
|
},
|
|
34273
|
-
// Feature flags (B-135
|
|
34274
|
-
// npm package
|
|
34275
|
-
listFlags: async () => {
|
|
34276
|
-
|
|
34062
|
+
// Feature flags (B-135 v11) — routed through /api/mcp/feature-flags/* so the
|
|
34063
|
+
// published npm package (no DynamoDB credentials) can manage flags via HTTP.
|
|
34064
|
+
listFlags: async (options) => {
|
|
34065
|
+
const params = new URLSearchParams();
|
|
34066
|
+
if (options?.includeArchived) params.set("includeArchived", "true");
|
|
34067
|
+
if (options?.search) params.set("search", options.search);
|
|
34068
|
+
if (options?.cursor) params.set("cursor", options.cursor);
|
|
34069
|
+
if (options?.limit !== void 0) params.set("limit", String(options.limit));
|
|
34070
|
+
const qs = params.toString();
|
|
34071
|
+
return requestOrThrow(
|
|
34072
|
+
"GET",
|
|
34073
|
+
`/api/mcp/feature-flags${qs ? `?${qs}` : ""}`
|
|
34074
|
+
);
|
|
34075
|
+
},
|
|
34076
|
+
getFlag: async (name, options) => {
|
|
34077
|
+
const qs = options?.includeHistory ? "?includeHistory=true" : "";
|
|
34078
|
+
return request("GET", `/api/mcp/feature-flags/${encodeURIComponent(name)}${qs}`);
|
|
34079
|
+
},
|
|
34080
|
+
checkFlag: async (name, stage) => {
|
|
34081
|
+
const flag = await request(
|
|
34082
|
+
"GET",
|
|
34083
|
+
`/api/mcp/feature-flags/${encodeURIComponent(name)}`
|
|
34084
|
+
);
|
|
34085
|
+
return flag ? flag.enabledIn.includes(stage) : false;
|
|
34086
|
+
},
|
|
34087
|
+
createFlag: async (name, enabledIn, options) => {
|
|
34088
|
+
return requestOrThrow("POST", "/api/mcp/feature-flags", {
|
|
34089
|
+
name,
|
|
34090
|
+
enabledIn,
|
|
34091
|
+
description: options?.description,
|
|
34092
|
+
note: options?.note
|
|
34093
|
+
});
|
|
34277
34094
|
},
|
|
34278
|
-
|
|
34279
|
-
|
|
34095
|
+
setFlag: async (name, enabledIn, options) => {
|
|
34096
|
+
return requestOrThrow("PUT", `/api/mcp/feature-flags/${encodeURIComponent(name)}`, {
|
|
34097
|
+
enabledIn,
|
|
34098
|
+
note: options?.note
|
|
34099
|
+
});
|
|
34100
|
+
},
|
|
34101
|
+
archiveFlag: async (name, options) => {
|
|
34102
|
+
return requestOrThrow("POST", `/api/mcp/feature-flags/${encodeURIComponent(name)}/archive`, {
|
|
34103
|
+
note: options?.note
|
|
34104
|
+
});
|
|
34280
34105
|
},
|
|
34281
|
-
|
|
34282
|
-
|
|
34106
|
+
unarchiveFlag: async (name, options) => {
|
|
34107
|
+
return requestOrThrow("POST", `/api/mcp/feature-flags/${encodeURIComponent(name)}/unarchive`, {
|
|
34108
|
+
note: options?.note
|
|
34109
|
+
});
|
|
34283
34110
|
}
|
|
34284
34111
|
};
|
|
34285
34112
|
return client;
|
|
@@ -34330,7 +34157,7 @@ function loadConfig() {
|
|
|
34330
34157
|
};
|
|
34331
34158
|
}
|
|
34332
34159
|
async function main() {
|
|
34333
|
-
console.error(`[harmonica-mcp] v${"3.
|
|
34160
|
+
console.error(`[harmonica-mcp] v${"3.6.0"} starting\u2026`);
|
|
34334
34161
|
const config2 = loadConfig();
|
|
34335
34162
|
const client = createHttpClient({
|
|
34336
34163
|
apiBaseUrl: config2.apiBaseUrl,
|