@codazen/harmonica-mcp 4.0.2 → 4.2.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 +63 -27
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -26329,6 +26329,15 @@ var normalizeSystemId = (raw) => {
|
|
|
26329
26329
|
if (!id) return raw;
|
|
26330
26330
|
return { ...b, systemId: id };
|
|
26331
26331
|
};
|
|
26332
|
+
var normalizeSystemIdAndName = (raw) => {
|
|
26333
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return raw;
|
|
26334
|
+
const b = raw;
|
|
26335
|
+
const result = { ...b };
|
|
26336
|
+
const id = b["systemId"] || b["projectId"];
|
|
26337
|
+
if (id) result["systemId"] = id;
|
|
26338
|
+
if ((b["systemName"] == null || b["systemName"] === "") && b["projectName"]) result["systemName"] = b["projectName"];
|
|
26339
|
+
return result;
|
|
26340
|
+
};
|
|
26332
26341
|
var normalizeSystemIdAndTitle = (raw) => {
|
|
26333
26342
|
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return raw;
|
|
26334
26343
|
const b = raw;
|
|
@@ -26344,15 +26353,17 @@ var BeatApiSchema = external_exports.preprocess(
|
|
|
26344
26353
|
if (typeof raw !== "object" || raw === null) return raw;
|
|
26345
26354
|
const b = raw;
|
|
26346
26355
|
const id = b["systemId"] || b["projectId"];
|
|
26347
|
-
|
|
26348
|
-
|
|
26356
|
+
const result = { ...b };
|
|
26357
|
+
if (id) result["systemId"] = id;
|
|
26358
|
+
if ((b["systemName"] == null || b["systemName"] === "") && b["projectName"]) result["systemName"] = b["projectName"];
|
|
26359
|
+
return result;
|
|
26349
26360
|
},
|
|
26350
26361
|
external_exports.object({
|
|
26351
26362
|
beatId: external_exports.string(),
|
|
26352
26363
|
systemId: external_exports.string(),
|
|
26353
|
-
/** Source
|
|
26354
|
-
* multi-
|
|
26355
|
-
|
|
26364
|
+
/** Source system's title; attached by the flat /api/beats endpoint for
|
|
26365
|
+
* multi-system (teamspace/org) responses. */
|
|
26366
|
+
systemName: external_exports.string().nullish(),
|
|
26356
26367
|
title: external_exports.string(),
|
|
26357
26368
|
version: external_exports.number().nullish(),
|
|
26358
26369
|
description: external_exports.string().nullish(),
|
|
@@ -26612,6 +26623,7 @@ var CHECK_TARGET_TYPES = [
|
|
|
26612
26623
|
"revision",
|
|
26613
26624
|
"beat_version",
|
|
26614
26625
|
"project",
|
|
26626
|
+
"system",
|
|
26615
26627
|
"drop",
|
|
26616
26628
|
"organization"
|
|
26617
26629
|
];
|
|
@@ -26818,13 +26830,13 @@ var NextActionSchema = external_exports.object({
|
|
|
26818
26830
|
var NextActionsResponseSchema = external_exports.object({
|
|
26819
26831
|
actions: external_exports.array(NextActionSchema)
|
|
26820
26832
|
}).passthrough();
|
|
26821
|
-
var SearchResultSchema = external_exports.preprocess(
|
|
26833
|
+
var SearchResultSchema = external_exports.preprocess(normalizeSystemIdAndName, external_exports.object({
|
|
26822
26834
|
entityId: external_exports.string(),
|
|
26823
26835
|
entityType: external_exports.enum(["beat", "note", "revision", "beatVersion", "drop", "project", "system"]),
|
|
26824
26836
|
score: external_exports.number(),
|
|
26825
26837
|
snippet: external_exports.string(),
|
|
26826
26838
|
systemId: external_exports.string().optional(),
|
|
26827
|
-
|
|
26839
|
+
systemName: external_exports.string().optional(),
|
|
26828
26840
|
teamspaceId: external_exports.string().optional()
|
|
26829
26841
|
}).passthrough());
|
|
26830
26842
|
var SearchScopeSchema = external_exports.object({
|
|
@@ -27816,7 +27828,7 @@ function registerNoteTools(server, ctx, client) {
|
|
|
27816
27828
|
const noteId = await client.getNextNoteId(projectCode, systemId);
|
|
27817
27829
|
note = await client.createNote({
|
|
27818
27830
|
noteId,
|
|
27819
|
-
|
|
27831
|
+
systemId,
|
|
27820
27832
|
beatId,
|
|
27821
27833
|
revisionId,
|
|
27822
27834
|
beatVersionId,
|
|
@@ -28157,9 +28169,9 @@ ${trimmed}` : `# ${title}`;
|
|
|
28157
28169
|
}
|
|
28158
28170
|
|
|
28159
28171
|
// ../../libs/harmonica-services/src/mcp/tools/notebook-tools.ts
|
|
28160
|
-
var SCOPE_TYPE_VALUES = ["org", "teamspace", "
|
|
28172
|
+
var SCOPE_TYPE_VALUES = ["org", "teamspace", "system", "account", "project"];
|
|
28161
28173
|
var scopeRefSchema = external_exports.object({
|
|
28162
|
-
scopeType: external_exports.enum(SCOPE_TYPE_VALUES).describe("Scope type \u2014 org, teamspace,
|
|
28174
|
+
scopeType: external_exports.enum(SCOPE_TYPE_VALUES).describe("Scope type \u2014 org, teamspace, system, or account"),
|
|
28163
28175
|
scopeId: external_exports.string().min(1).describe("ID of the scope entity")
|
|
28164
28176
|
});
|
|
28165
28177
|
function formatNotebook(nb) {
|
|
@@ -28384,7 +28396,7 @@ ${formatTree(tree.root)}` }] };
|
|
|
28384
28396
|
if (!scopeProjectId) {
|
|
28385
28397
|
try {
|
|
28386
28398
|
const bindings = await client.getNotebookScopeBindings(notebookId);
|
|
28387
|
-
scopeProjectId = bindings?.find((b) => b.scopeType === "project")?.scopeId;
|
|
28399
|
+
scopeProjectId = bindings?.find((b) => b.scopeType === "system" || b.scopeType === "project")?.scopeId;
|
|
28388
28400
|
} catch {
|
|
28389
28401
|
}
|
|
28390
28402
|
}
|
|
@@ -28550,7 +28562,7 @@ ${formatNotebook(updated)}` }] };
|
|
|
28550
28562
|
);
|
|
28551
28563
|
server.tool(
|
|
28552
28564
|
"set_notebook_scopes",
|
|
28553
|
-
"Replace all scope bindings for a Notebook. Pass an empty array to remove all bindings. Bindable scope types: org, teamspace,
|
|
28565
|
+
"Replace all scope bindings for a Notebook. Pass an empty array to remove all bindings. Bindable scope types: org, teamspace, system. (systemContainer is reserved.)",
|
|
28554
28566
|
{
|
|
28555
28567
|
notebookId: external_exports.string().describe("The Notebook ID"),
|
|
28556
28568
|
scopes: external_exports.array(scopeRefSchema).max(45).describe("New complete set of scope bindings (max 45)")
|
|
@@ -28915,7 +28927,7 @@ Systems (${createdProjects.length}):`);
|
|
|
28915
28927
|
const n = await client.createNote({
|
|
28916
28928
|
noteId: `N-TEMP-${(0, import_node_crypto.randomUUID)()}`,
|
|
28917
28929
|
// overridden server-side
|
|
28918
|
-
|
|
28930
|
+
systemId: project.systemId,
|
|
28919
28931
|
noteType: note.noteType,
|
|
28920
28932
|
content: note.content,
|
|
28921
28933
|
rationale: note.rationale,
|
|
@@ -29575,6 +29587,7 @@ function registerPulseReportTools(server, _ctx, client) {
|
|
|
29575
29587
|
}
|
|
29576
29588
|
|
|
29577
29589
|
// ../../libs/harmonica-services/src/delivery-policy.decide.ts
|
|
29590
|
+
var DELIVERY_STEPS = ["openPullRequest", "requestAgentReview", "watchPullRequest"];
|
|
29578
29591
|
function decideDeliveryStep(resolution, step) {
|
|
29579
29592
|
if (!resolution.resolved) return "ask";
|
|
29580
29593
|
const value = resolution.policy[step];
|
|
@@ -29582,6 +29595,19 @@ function decideDeliveryStep(resolution, step) {
|
|
|
29582
29595
|
if (value === false) return "prohibited";
|
|
29583
29596
|
return "ask";
|
|
29584
29597
|
}
|
|
29598
|
+
function mergeAgentDeliveryPolicy(current, patch) {
|
|
29599
|
+
const merged = { ...current };
|
|
29600
|
+
for (const step of DELIVERY_STEPS) {
|
|
29601
|
+
if (!(step in patch)) continue;
|
|
29602
|
+
const value = patch[step];
|
|
29603
|
+
if (value === null) {
|
|
29604
|
+
delete merged[step];
|
|
29605
|
+
} else if (value === true || value === false) {
|
|
29606
|
+
merged[step] = value;
|
|
29607
|
+
}
|
|
29608
|
+
}
|
|
29609
|
+
return merged;
|
|
29610
|
+
}
|
|
29585
29611
|
|
|
29586
29612
|
// ../../libs/harmonica-services/src/mcp/tools/revision-lifecycle-tools.ts
|
|
29587
29613
|
async function checkDeliveryStep(client, revisionId, step) {
|
|
@@ -29958,9 +29984,10 @@ Accepts the full PR metadata (number, url, branch, state, optional mergeSha). Fi
|
|
|
29958
29984
|
revisionId: external_exports.string().describe("The Revision ID whose PR to review (e.g., rev-abc123)"),
|
|
29959
29985
|
autoMerge: external_exports.boolean().optional().describe("Merge automatically once converged. Default false \u2192 stop at ready-for-review."),
|
|
29960
29986
|
maxIterations: external_exports.number().int().min(1).max(3).optional().describe("Review rounds (default and hard cap: 3)."),
|
|
29961
|
-
confirm: external_exports.boolean().optional().describe("Set true to start the review. Omitted/false performs a dry-run \u2014 no session, scan, or task is created.")
|
|
29987
|
+
confirm: external_exports.boolean().optional().describe("Set true to start the review. Omitted/false performs a dry-run \u2014 no session, scan, or task is created."),
|
|
29988
|
+
requestingSessionId: external_exports.string().min(1).optional().describe("Your current Session ID (sess-<uuid>). Pass it so the review Session nests under yours and reports its outcome back to you when it finishes \u2014 otherwise you have no way to learn how the review turned out.")
|
|
29962
29989
|
},
|
|
29963
|
-
async ({ revisionId, autoMerge, maxIterations, confirm }) => {
|
|
29990
|
+
async ({ revisionId, autoMerge, maxIterations, confirm, requestingSessionId }) => {
|
|
29964
29991
|
try {
|
|
29965
29992
|
const revision = await client.getRevision(revisionId);
|
|
29966
29993
|
if (!revision) {
|
|
@@ -29971,7 +29998,7 @@ Accepts the full PR metadata (number, url, branch, state, optional mergeSha). Fi
|
|
|
29971
29998
|
if ("refusal" in latitude) {
|
|
29972
29999
|
return { content: [{ type: "text", text: latitude.refusal }], isError: true };
|
|
29973
30000
|
}
|
|
29974
|
-
const result = await client.requestCodeReview({ revisionId, autoMerge, maxIterations, confirm });
|
|
30001
|
+
const result = await client.requestCodeReview({ revisionId, autoMerge, maxIterations, confirm, requestingSessionId });
|
|
29975
30002
|
if (!result.success) {
|
|
29976
30003
|
return { content: [{ type: "text", text: `Failed to request code review (${result.error.code}): ${result.error.message}` }], isError: true };
|
|
29977
30004
|
}
|
|
@@ -30685,7 +30712,7 @@ function formatImportSummary(result, targetTeamspaceId) {
|
|
|
30685
30712
|
lines.push("", `Errors (${result.errors.length}):`);
|
|
30686
30713
|
result.errors.forEach((e) => lines.push(` - ${e}`));
|
|
30687
30714
|
}
|
|
30688
|
-
const hasTeamspaceData = result.
|
|
30715
|
+
const hasTeamspaceData = result.systemTeamspaceId !== void 0 || (result.counts.drops ?? 0) + (result.counts.deliverables ?? 0) > 0;
|
|
30689
30716
|
if (!targetTeamspaceId && hasTeamspaceData) {
|
|
30690
30717
|
lines.push(
|
|
30691
30718
|
"",
|
|
@@ -30733,13 +30760,17 @@ function assertSnapshotShape(val, sourceHint) {
|
|
|
30733
30760
|
}
|
|
30734
30761
|
|
|
30735
30762
|
// ../../libs/harmonica-services/src/mcp/tools/subscription-tools.ts
|
|
30736
|
-
var ENTITY_TYPES = ["
|
|
30763
|
+
var ENTITY_TYPES = ["system", "beat", "revision"];
|
|
30764
|
+
var entityTypeField = external_exports.preprocess(
|
|
30765
|
+
(v) => v === "project" ? "system" : v,
|
|
30766
|
+
external_exports.enum(ENTITY_TYPES)
|
|
30767
|
+
);
|
|
30737
30768
|
function registerSubscriptionTools(server, ctx, client) {
|
|
30738
30769
|
server.tool(
|
|
30739
30770
|
"subscribe_to_entity",
|
|
30740
|
-
"Follow a
|
|
30771
|
+
"Follow a System, Beat, or Revision to receive notifications when it changes. You are auto-subscribed to things you own \u2014 use this to follow additional entities.",
|
|
30741
30772
|
{
|
|
30742
|
-
entityType:
|
|
30773
|
+
entityType: entityTypeField.describe("Type of entity to follow"),
|
|
30743
30774
|
entityId: external_exports.string().describe("The entity ID (system ID, beat ID, or revision ID)"),
|
|
30744
30775
|
systemId: external_exports.string().describe("The system ID (for access control)")
|
|
30745
30776
|
},
|
|
@@ -30761,9 +30792,9 @@ function registerSubscriptionTools(server, ctx, client) {
|
|
|
30761
30792
|
);
|
|
30762
30793
|
server.tool(
|
|
30763
30794
|
"unsubscribe_from_entity",
|
|
30764
|
-
"Stop following a
|
|
30795
|
+
"Stop following a System, Beat, or Revision. Use durable=true to prevent auto-resubscribe if you are later re-assigned.",
|
|
30765
30796
|
{
|
|
30766
|
-
entityType:
|
|
30797
|
+
entityType: entityTypeField.describe("Type of entity to unfollow"),
|
|
30767
30798
|
entityId: external_exports.string().describe("The entity ID"),
|
|
30768
30799
|
durable: external_exports.boolean().optional().default(false).describe("If true, prevents auto-resubscribe on reassignment")
|
|
30769
30800
|
},
|
|
@@ -30959,8 +30990,14 @@ function registerSystemTools(server, ctx, client) {
|
|
|
30959
30990
|
if (Object.keys(nonEmpty).length === 0) {
|
|
30960
30991
|
return { content: [{ type: "text", text: "No updates provided." }], isError: true };
|
|
30961
30992
|
}
|
|
30962
|
-
await
|
|
30993
|
+
const currentSystem = await fetchSystemInOrg(client, systemId, ctx.orgId);
|
|
30963
30994
|
if (nonEmpty["accountId"] === "") delete nonEmpty["accountId"];
|
|
30995
|
+
if (nonEmpty["agentDeliveryPolicy"] && typeof nonEmpty["agentDeliveryPolicy"] === "object") {
|
|
30996
|
+
nonEmpty["agentDeliveryPolicy"] = mergeAgentDeliveryPolicy(
|
|
30997
|
+
currentSystem.agentDeliveryPolicy,
|
|
30998
|
+
nonEmpty["agentDeliveryPolicy"]
|
|
30999
|
+
);
|
|
31000
|
+
}
|
|
30964
31001
|
if (typeof updates.teamspaceId === "string") {
|
|
30965
31002
|
const teamspace = await client.getTeamspace(updates.teamspaceId);
|
|
30966
31003
|
if (!teamspace) {
|
|
@@ -33160,9 +33197,8 @@ function createHttpClient(config2) {
|
|
|
33160
33197
|
return result?.note ?? result;
|
|
33161
33198
|
},
|
|
33162
33199
|
createNote: async (input) => {
|
|
33163
|
-
const
|
|
33164
|
-
|
|
33165
|
-
if (!effectiveSystemId) throw new Error("createNote: systemId (or legacy projectId) is required");
|
|
33200
|
+
const effectiveSystemId = input.systemId;
|
|
33201
|
+
if (!effectiveSystemId) throw new Error("createNote: systemId is required");
|
|
33166
33202
|
const result = await request("POST", `/api/systems/${encodeURIComponent(effectiveSystemId)}/notes`, input);
|
|
33167
33203
|
return result?.note ?? result;
|
|
33168
33204
|
},
|
|
@@ -34994,7 +35030,7 @@ function loadConfig() {
|
|
|
34994
35030
|
};
|
|
34995
35031
|
}
|
|
34996
35032
|
async function main() {
|
|
34997
|
-
console.error(`[harmonica-mcp] v${"4.0
|
|
35033
|
+
console.error(`[harmonica-mcp] v${"4.2.0"} starting\u2026`);
|
|
34998
35034
|
const config2 = loadConfig();
|
|
34999
35035
|
const client = createHttpClient({
|
|
35000
35036
|
apiBaseUrl: config2.apiBaseUrl,
|