@codazen/harmonica-mcp 3.8.6 → 3.9.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 +800 -187
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -21545,11 +21545,11 @@ async function validateAuth(client, orgIdentifier, isOrgSlug, userId) {
|
|
|
21545
21545
|
async function assertProjectInOrg(client, systemId, orgId) {
|
|
21546
21546
|
const project = await client.getSystem(systemId);
|
|
21547
21547
|
if (!project) {
|
|
21548
|
-
throw new Error(`
|
|
21548
|
+
throw new Error(`System not found: "${systemId}"`);
|
|
21549
21549
|
}
|
|
21550
21550
|
if (project.orgId !== orgId) {
|
|
21551
21551
|
throw new Error(
|
|
21552
|
-
`
|
|
21552
|
+
`System "${systemId}" does not belong to the configured organization. Access denied.`
|
|
21553
21553
|
);
|
|
21554
21554
|
}
|
|
21555
21555
|
}
|
|
@@ -21560,7 +21560,7 @@ async function assertRevisionInProject(client, revisionId, systemId) {
|
|
|
21560
21560
|
}
|
|
21561
21561
|
if (revision.systemId !== systemId) {
|
|
21562
21562
|
throw new Error(
|
|
21563
|
-
`Revision "${revisionId}" does not belong to
|
|
21563
|
+
`Revision "${revisionId}" does not belong to system "${systemId}". Access denied.`
|
|
21564
21564
|
);
|
|
21565
21565
|
}
|
|
21566
21566
|
}
|
|
@@ -21578,11 +21578,11 @@ async function assertBeatInOrg(client, beatId, orgId) {
|
|
|
21578
21578
|
async function fetchProjectInOrg(client, systemId, orgId) {
|
|
21579
21579
|
const project = await client.getSystem(systemId);
|
|
21580
21580
|
if (!project) {
|
|
21581
|
-
throw new Error(`
|
|
21581
|
+
throw new Error(`System not found: "${systemId}"`);
|
|
21582
21582
|
}
|
|
21583
21583
|
if (project.orgId !== orgId) {
|
|
21584
21584
|
throw new Error(
|
|
21585
|
-
`
|
|
21585
|
+
`System "${systemId}" does not belong to the configured organization. Access denied.`
|
|
21586
21586
|
);
|
|
21587
21587
|
}
|
|
21588
21588
|
return project;
|
|
@@ -22853,7 +22853,7 @@ function formatNoteList(notes) {
|
|
|
22853
22853
|
return parts.join("\n");
|
|
22854
22854
|
}
|
|
22855
22855
|
function formatDocumentList(docs, allNotes) {
|
|
22856
|
-
if (docs.length === 0) return "No documents uploaded for this
|
|
22856
|
+
if (docs.length === 0) return "No documents uploaded for this system.";
|
|
22857
22857
|
const lines = docs.map((doc) => {
|
|
22858
22858
|
const meta = doc.documentMeta;
|
|
22859
22859
|
const status = meta?.documentStatus ?? "unknown";
|
|
@@ -23927,7 +23927,7 @@ function registerCheckTools(server, ctx, client) {
|
|
|
23927
23927
|
} else {
|
|
23928
23928
|
const result = await client.listSystemChecks(systemId, checkType, { limit: 200 });
|
|
23929
23929
|
checks = result.checks;
|
|
23930
|
-
scope = `
|
|
23930
|
+
scope = `system ${systemId}`;
|
|
23931
23931
|
}
|
|
23932
23932
|
if (checks.length === 0) {
|
|
23933
23933
|
return { content: [{ type: "text", text: `No checks found for ${scope}.` }] };
|
|
@@ -23950,9 +23950,9 @@ function registerCheckTools(server, ctx, client) {
|
|
|
23950
23950
|
try {
|
|
23951
23951
|
const checks = await client.listLatestSystemChecks(systemId);
|
|
23952
23952
|
if (checks.length === 0) {
|
|
23953
|
-
return { content: [{ type: "text", text: `No checks found for
|
|
23953
|
+
return { content: [{ type: "text", text: `No checks found for system ${systemId}.` }] };
|
|
23954
23954
|
}
|
|
23955
|
-
const text = formatCheckList(checks, `latest per target \xB7
|
|
23955
|
+
const text = formatCheckList(checks, `latest per target \xB7 system ${systemId}`);
|
|
23956
23956
|
return { content: [{ type: "text", text }] };
|
|
23957
23957
|
} catch (err) {
|
|
23958
23958
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -24690,7 +24690,7 @@ function registerDropTools(server, ctx, client) {
|
|
|
24690
24690
|
);
|
|
24691
24691
|
server.tool(
|
|
24692
24692
|
"create_drop",
|
|
24693
|
-
"Create a Drop (release container) in an Account. Drops group Beat Revisions for coordinated release. The dropCode is auto-generated as D-NNN per Account. Drops are cross-
|
|
24693
|
+
"Create a Drop (release container) in an Account. Drops group Beat Revisions for coordinated release. The dropCode is auto-generated as D-NNN per Account. Drops are cross-system: a single Drop can include Revisions from any System in the Account.",
|
|
24694
24694
|
{
|
|
24695
24695
|
accountId: external_exports.string().describe("The account ID"),
|
|
24696
24696
|
name: external_exports.string().min(1).max(200).describe('Drop name (e.g. "MVP", "Phase 2", "Hotfix 2026-Q2")'),
|
|
@@ -26336,11 +26336,18 @@ var NoteStatusSchema = external_exports.enum([
|
|
|
26336
26336
|
]);
|
|
26337
26337
|
var SystemStatusSchema = external_exports.enum(["active", "archived", "draft"]);
|
|
26338
26338
|
var ChangeImportanceSchema = external_exports.enum(["minor", "moderate", "major"]);
|
|
26339
|
+
var normalizeSystemId = (raw) => {
|
|
26340
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return raw;
|
|
26341
|
+
const b = raw;
|
|
26342
|
+
const id = b["systemId"] || b["projectId"];
|
|
26343
|
+
if (!id) return raw;
|
|
26344
|
+
return { ...b, systemId: id, projectId: id };
|
|
26345
|
+
};
|
|
26339
26346
|
var BeatApiSchema = external_exports.preprocess(
|
|
26340
26347
|
(raw) => {
|
|
26341
26348
|
if (typeof raw !== "object" || raw === null) return raw;
|
|
26342
26349
|
const b = raw;
|
|
26343
|
-
const id = b["systemId"]
|
|
26350
|
+
const id = b["systemId"] || b["projectId"];
|
|
26344
26351
|
if (!id) return raw;
|
|
26345
26352
|
return { ...b, systemId: id, projectId: id };
|
|
26346
26353
|
},
|
|
@@ -26373,34 +26380,39 @@ var RevisionScmSchema = external_exports.object({
|
|
|
26373
26380
|
state: external_exports.enum(["draft", "open", "merged", "closed"]),
|
|
26374
26381
|
mergeSha: external_exports.string().optional()
|
|
26375
26382
|
});
|
|
26376
|
-
var RevisionApiSchema = external_exports.
|
|
26377
|
-
|
|
26378
|
-
|
|
26379
|
-
|
|
26380
|
-
|
|
26381
|
-
|
|
26382
|
-
|
|
26383
|
-
|
|
26384
|
-
|
|
26385
|
-
|
|
26386
|
-
|
|
26387
|
-
|
|
26388
|
-
|
|
26389
|
-
|
|
26390
|
-
|
|
26391
|
-
|
|
26392
|
-
|
|
26393
|
-
|
|
26394
|
-
|
|
26395
|
-
|
|
26396
|
-
|
|
26397
|
-
|
|
26398
|
-
|
|
26399
|
-
|
|
26383
|
+
var RevisionApiSchema = external_exports.preprocess(
|
|
26384
|
+
normalizeSystemId,
|
|
26385
|
+
external_exports.object({
|
|
26386
|
+
revisionId: external_exports.string(),
|
|
26387
|
+
beatId: external_exports.string(),
|
|
26388
|
+
systemId: external_exports.string(),
|
|
26389
|
+
projectId: external_exports.string(),
|
|
26390
|
+
status: RevisionStatusSchema,
|
|
26391
|
+
title: external_exports.string().default(""),
|
|
26392
|
+
versionNumber: external_exports.number(),
|
|
26393
|
+
changeSummary: external_exports.string().nullish(),
|
|
26394
|
+
changeImportance: ChangeImportanceSchema.nullish(),
|
|
26395
|
+
primaryUser: external_exports.string(),
|
|
26396
|
+
description: external_exports.string().nullish(),
|
|
26397
|
+
tags: external_exports.array(external_exports.string()).nullish(),
|
|
26398
|
+
priority: external_exports.number().nullish(),
|
|
26399
|
+
estimatedEffort: external_exports.string().nullish(),
|
|
26400
|
+
humanAssignee: HumanAssigneeSchema.nullish(),
|
|
26401
|
+
agentAssignee: AgentAssigneeSchema.nullish(),
|
|
26402
|
+
scm: RevisionScmSchema.optional(),
|
|
26403
|
+
// The Layer this Revision was created under (immutable). Absent on Revisions
|
|
26404
|
+
// predating Layers — never backfilled — so consumers group those as "Unassigned".
|
|
26405
|
+
layerId: external_exports.string().nullish(),
|
|
26406
|
+
createdAt: external_exports.string(),
|
|
26407
|
+
updatedAt: external_exports.string()
|
|
26408
|
+
}).passthrough()
|
|
26409
|
+
);
|
|
26410
|
+
var NoteApiSchema = external_exports.preprocess(normalizeSystemId, external_exports.object({
|
|
26400
26411
|
noteId: external_exports.string(),
|
|
26401
26412
|
noteType: NoteTypeSchema,
|
|
26402
26413
|
status: NoteStatusSchema,
|
|
26403
26414
|
content: external_exports.string(),
|
|
26415
|
+
systemId: external_exports.string().nullish(),
|
|
26404
26416
|
projectId: external_exports.string().nullish(),
|
|
26405
26417
|
beatId: external_exports.string().nullish(),
|
|
26406
26418
|
revisionId: external_exports.string().nullish(),
|
|
@@ -26412,18 +26424,22 @@ var NoteApiSchema = external_exports.object({
|
|
|
26412
26424
|
agentAssignee: AgentAssigneeSchema.nullish(),
|
|
26413
26425
|
createdAt: external_exports.string(),
|
|
26414
26426
|
updatedAt: external_exports.string()
|
|
26415
|
-
}).passthrough();
|
|
26416
|
-
var SystemApiSchema = external_exports.
|
|
26417
|
-
|
|
26418
|
-
|
|
26419
|
-
|
|
26420
|
-
|
|
26421
|
-
|
|
26422
|
-
|
|
26423
|
-
|
|
26424
|
-
|
|
26425
|
-
|
|
26426
|
-
|
|
26427
|
+
}).passthrough());
|
|
26428
|
+
var SystemApiSchema = external_exports.preprocess(
|
|
26429
|
+
normalizeSystemId,
|
|
26430
|
+
external_exports.object({
|
|
26431
|
+
systemId: external_exports.string(),
|
|
26432
|
+
projectId: external_exports.string(),
|
|
26433
|
+
title: external_exports.string(),
|
|
26434
|
+
status: SystemStatusSchema,
|
|
26435
|
+
description: external_exports.string().optional(),
|
|
26436
|
+
strategy: external_exports.string().optional(),
|
|
26437
|
+
orgId: external_exports.string().optional(),
|
|
26438
|
+
ownerUserId: external_exports.string().optional(),
|
|
26439
|
+
createdAt: external_exports.string(),
|
|
26440
|
+
updatedAt: external_exports.string()
|
|
26441
|
+
}).passthrough()
|
|
26442
|
+
);
|
|
26427
26443
|
var BeatsResponseSchema = external_exports.object({
|
|
26428
26444
|
beats: external_exports.array(BeatApiSchema),
|
|
26429
26445
|
total: external_exports.number().optional(),
|
|
@@ -26608,37 +26624,45 @@ var CHECK_TARGET_TYPES = [
|
|
|
26608
26624
|
"organization"
|
|
26609
26625
|
];
|
|
26610
26626
|
var CheckTargetTypeSchema = external_exports.enum(CHECK_TARGET_TYPES);
|
|
26611
|
-
var CheckApiSchema = external_exports.
|
|
26612
|
-
|
|
26613
|
-
|
|
26614
|
-
|
|
26615
|
-
|
|
26616
|
-
|
|
26617
|
-
|
|
26618
|
-
|
|
26619
|
-
|
|
26620
|
-
|
|
26621
|
-
|
|
26622
|
-
|
|
26623
|
-
|
|
26624
|
-
|
|
26625
|
-
|
|
26626
|
-
|
|
26627
|
-
|
|
26628
|
-
|
|
26629
|
-
|
|
26630
|
-
|
|
26631
|
-
|
|
26632
|
-
|
|
26633
|
-
|
|
26634
|
-
|
|
26635
|
-
|
|
26636
|
-
|
|
26637
|
-
|
|
26638
|
-
|
|
26639
|
-
|
|
26640
|
-
|
|
26641
|
-
|
|
26627
|
+
var CheckApiSchema = external_exports.preprocess(
|
|
26628
|
+
normalizeSystemId,
|
|
26629
|
+
external_exports.object({
|
|
26630
|
+
checkId: external_exports.string(),
|
|
26631
|
+
checkType: CheckTypeSchema,
|
|
26632
|
+
targetType: CheckTargetTypeSchema,
|
|
26633
|
+
targetId: external_exports.string(),
|
|
26634
|
+
systemId: external_exports.string().optional(),
|
|
26635
|
+
projectId: external_exports.string().optional(),
|
|
26636
|
+
overallScore: external_exports.number(),
|
|
26637
|
+
dimensions: external_exports.array(CheckDimensionScoreSchema),
|
|
26638
|
+
summary: external_exports.string(),
|
|
26639
|
+
topSuggestion: external_exports.string().optional(),
|
|
26640
|
+
gaps: external_exports.array(CheckGapSchema).optional(),
|
|
26641
|
+
taskId: external_exports.string().optional(),
|
|
26642
|
+
triggeredBy: external_exports.string().optional(),
|
|
26643
|
+
createdAt: external_exports.string(),
|
|
26644
|
+
updatedAt: external_exports.string()
|
|
26645
|
+
}).passthrough()
|
|
26646
|
+
);
|
|
26647
|
+
var SystemCheckApiSchema = external_exports.preprocess(
|
|
26648
|
+
normalizeSystemId,
|
|
26649
|
+
external_exports.object({
|
|
26650
|
+
checkId: external_exports.string(),
|
|
26651
|
+
checkType: CheckTypeSchema,
|
|
26652
|
+
targetType: CheckTargetTypeSchema,
|
|
26653
|
+
targetId: external_exports.string(),
|
|
26654
|
+
systemId: external_exports.string().optional(),
|
|
26655
|
+
projectId: external_exports.string().optional(),
|
|
26656
|
+
overallScore: external_exports.number(),
|
|
26657
|
+
summary: external_exports.string(),
|
|
26658
|
+
triggeredBy: external_exports.string().optional(),
|
|
26659
|
+
createdAt: external_exports.string(),
|
|
26660
|
+
updatedAt: external_exports.string(),
|
|
26661
|
+
/** Populated only when the API was called with ?includeDimensions=true.
|
|
26662
|
+
* Read-time enrichment from the underlying Check entity. */
|
|
26663
|
+
dimensions: external_exports.array(CheckDimensionScoreSchema).optional()
|
|
26664
|
+
}).passthrough()
|
|
26665
|
+
);
|
|
26642
26666
|
var CheckResponseSchema = external_exports.object({ check: CheckApiSchema }).passthrough();
|
|
26643
26667
|
var ChecksResponseSchema = external_exports.object({ checks: external_exports.array(SystemCheckApiSchema), nextCursor: external_exports.string().optional() }).passthrough();
|
|
26644
26668
|
var TaskStatusSchema2 = external_exports.enum(["pending", "running", "completed", "failed"]);
|
|
@@ -26683,21 +26707,25 @@ var OrgMemberSchema = external_exports.object({
|
|
|
26683
26707
|
var OrganizationsResponseSchema = external_exports.array(OrganizationSummarySchema);
|
|
26684
26708
|
var OrgMembersResponseSchema = external_exports.array(OrgMemberSchema);
|
|
26685
26709
|
var WrappedOrgMembersResponseSchema = external_exports.object({ members: OrgMembersResponseSchema });
|
|
26686
|
-
var ActivitySchema = external_exports.
|
|
26687
|
-
|
|
26688
|
-
|
|
26689
|
-
|
|
26690
|
-
|
|
26691
|
-
|
|
26692
|
-
|
|
26693
|
-
|
|
26694
|
-
|
|
26695
|
-
|
|
26696
|
-
|
|
26697
|
-
|
|
26698
|
-
|
|
26699
|
-
|
|
26700
|
-
|
|
26710
|
+
var ActivitySchema = external_exports.preprocess(
|
|
26711
|
+
normalizeSystemId,
|
|
26712
|
+
external_exports.object({
|
|
26713
|
+
activityId: external_exports.string(),
|
|
26714
|
+
systemId: external_exports.string(),
|
|
26715
|
+
projectId: external_exports.string(),
|
|
26716
|
+
action: external_exports.string(),
|
|
26717
|
+
importance: external_exports.enum(["minor", "moderate", "major"]),
|
|
26718
|
+
reason: external_exports.string(),
|
|
26719
|
+
// actorType is typed as string (not a strict enum) because the API accepts values
|
|
26720
|
+
// beyond 'user'/'system' (e.g. 'human', 'agent') depending on the call site.
|
|
26721
|
+
actorType: external_exports.string().optional(),
|
|
26722
|
+
actorId: external_exports.string().optional(),
|
|
26723
|
+
affectedBeatIds: external_exports.array(external_exports.string()).optional(),
|
|
26724
|
+
affectedBeatTitles: external_exports.array(external_exports.string()).optional(),
|
|
26725
|
+
metadata: external_exports.record(external_exports.unknown()).optional(),
|
|
26726
|
+
createdAt: external_exports.string()
|
|
26727
|
+
}).passthrough()
|
|
26728
|
+
);
|
|
26701
26729
|
var ActivitiesResponseSchema = external_exports.object({
|
|
26702
26730
|
activities: external_exports.array(ActivitySchema),
|
|
26703
26731
|
hasMore: external_exports.boolean(),
|
|
@@ -26725,26 +26753,30 @@ var NotificationsResponseSchema = external_exports.object({
|
|
|
26725
26753
|
nextCursor: external_exports.string().optional()
|
|
26726
26754
|
}).passthrough();
|
|
26727
26755
|
var UnreadCountResponseSchema = external_exports.object({ count: external_exports.number() }).passthrough();
|
|
26728
|
-
var TriageActionSchema = external_exports.
|
|
26729
|
-
|
|
26730
|
-
|
|
26731
|
-
|
|
26732
|
-
|
|
26733
|
-
|
|
26734
|
-
|
|
26735
|
-
|
|
26736
|
-
|
|
26737
|
-
|
|
26738
|
-
|
|
26739
|
-
|
|
26740
|
-
|
|
26741
|
-
|
|
26742
|
-
|
|
26743
|
-
|
|
26744
|
-
|
|
26745
|
-
|
|
26746
|
-
|
|
26747
|
-
|
|
26756
|
+
var TriageActionSchema = external_exports.preprocess(
|
|
26757
|
+
normalizeSystemId,
|
|
26758
|
+
external_exports.object({
|
|
26759
|
+
actionKey: external_exports.string(),
|
|
26760
|
+
systemId: external_exports.string(),
|
|
26761
|
+
projectId: external_exports.string(),
|
|
26762
|
+
entityId: external_exports.string().optional(),
|
|
26763
|
+
entityType: external_exports.enum(["beat", "revision", "note"]).optional(),
|
|
26764
|
+
beatId: external_exports.string().optional(),
|
|
26765
|
+
category: external_exports.string(),
|
|
26766
|
+
priority: external_exports.string(),
|
|
26767
|
+
beatStatus: external_exports.string().optional(),
|
|
26768
|
+
title: external_exports.string(),
|
|
26769
|
+
description: external_exports.string(),
|
|
26770
|
+
status: external_exports.enum(["open", "acted", "dismissed", "resolved"]),
|
|
26771
|
+
decision: external_exports.enum(["auto-execute", "escalate", "skip"]).optional(),
|
|
26772
|
+
taskId: external_exports.string().optional(),
|
|
26773
|
+
taskStatus: external_exports.string().optional(),
|
|
26774
|
+
firstSeenAt: external_exports.string(),
|
|
26775
|
+
lastSeenAt: external_exports.string(),
|
|
26776
|
+
dismissedBy: external_exports.string().optional(),
|
|
26777
|
+
dismissedAt: external_exports.string().optional()
|
|
26778
|
+
}).passthrough()
|
|
26779
|
+
);
|
|
26748
26780
|
var TriageActionsResponseSchema = external_exports.object({
|
|
26749
26781
|
actions: external_exports.array(TriageActionSchema)
|
|
26750
26782
|
}).passthrough();
|
|
@@ -26761,15 +26793,16 @@ var NextActionSchema = external_exports.object({
|
|
|
26761
26793
|
var NextActionsResponseSchema = external_exports.object({
|
|
26762
26794
|
actions: external_exports.array(NextActionSchema)
|
|
26763
26795
|
}).passthrough();
|
|
26764
|
-
var SearchResultSchema = external_exports.object({
|
|
26796
|
+
var SearchResultSchema = external_exports.preprocess(normalizeSystemId, external_exports.object({
|
|
26765
26797
|
entityId: external_exports.string(),
|
|
26766
|
-
entityType: external_exports.enum(["beat", "note", "revision", "beatVersion", "drop", "project"]),
|
|
26798
|
+
entityType: external_exports.enum(["beat", "note", "revision", "beatVersion", "drop", "project", "system"]),
|
|
26767
26799
|
score: external_exports.number(),
|
|
26768
26800
|
snippet: external_exports.string(),
|
|
26801
|
+
systemId: external_exports.string().optional(),
|
|
26769
26802
|
projectId: external_exports.string().optional(),
|
|
26770
26803
|
projectName: external_exports.string().optional(),
|
|
26771
26804
|
teamspaceId: external_exports.string().optional()
|
|
26772
|
-
}).passthrough();
|
|
26805
|
+
}).passthrough());
|
|
26773
26806
|
var SearchScopeSchema = external_exports.object({
|
|
26774
26807
|
kind: external_exports.enum(["project", "teamspace", "org"]),
|
|
26775
26808
|
id: external_exports.string()
|
|
@@ -26805,34 +26838,50 @@ var LandscapeMetaSchema = external_exports.object({
|
|
|
26805
26838
|
cacheHit: external_exports.boolean(),
|
|
26806
26839
|
projectionHash: external_exports.string()
|
|
26807
26840
|
}).passthrough();
|
|
26808
|
-
var LandscapeResponseSchema = external_exports.
|
|
26809
|
-
|
|
26810
|
-
|
|
26811
|
-
|
|
26812
|
-
|
|
26813
|
-
|
|
26814
|
-
|
|
26815
|
-
|
|
26816
|
-
|
|
26817
|
-
|
|
26818
|
-
|
|
26819
|
-
|
|
26820
|
-
|
|
26841
|
+
var LandscapeResponseSchema = external_exports.preprocess(
|
|
26842
|
+
(raw) => {
|
|
26843
|
+
if (typeof raw !== "object" || raw === null) return raw;
|
|
26844
|
+
const r = raw;
|
|
26845
|
+
const sb = r["scopeBoundary"];
|
|
26846
|
+
if (typeof sb === "object" && sb !== null) {
|
|
26847
|
+
const s = sb;
|
|
26848
|
+
const id = s["systemId"] || s["projectId"];
|
|
26849
|
+
if (id) return { ...r, scopeBoundary: { ...s, systemId: id, projectId: id } };
|
|
26850
|
+
}
|
|
26851
|
+
return r;
|
|
26852
|
+
},
|
|
26853
|
+
external_exports.object({
|
|
26854
|
+
points: external_exports.array(LandscapePointSchema),
|
|
26855
|
+
links: external_exports.array(external_exports.object({ from: external_exports.string(), to: external_exports.string() }).passthrough()),
|
|
26856
|
+
clusters: external_exports.array(LandscapeClusterSchema),
|
|
26857
|
+
scopeBoundary: external_exports.object({
|
|
26858
|
+
systemId: external_exports.string().optional(),
|
|
26859
|
+
projectId: external_exports.string().optional(),
|
|
26860
|
+
cx: external_exports.number(),
|
|
26861
|
+
cy: external_exports.number(),
|
|
26862
|
+
radius: external_exports.number(),
|
|
26863
|
+
label: external_exports.string()
|
|
26864
|
+
}).passthrough().optional(),
|
|
26865
|
+
meta: LandscapeMetaSchema
|
|
26866
|
+
}).passthrough()
|
|
26867
|
+
);
|
|
26821
26868
|
var ClusterDescriptionSchema = external_exports.object({
|
|
26822
26869
|
title: external_exports.string(),
|
|
26823
26870
|
description: external_exports.string()
|
|
26824
26871
|
}).passthrough();
|
|
26825
|
-
var BeatVersionItemSchema = external_exports.object({
|
|
26872
|
+
var BeatVersionItemSchema = external_exports.preprocess(normalizeSystemId, external_exports.object({
|
|
26826
26873
|
beatVersionId: external_exports.string(),
|
|
26827
26874
|
beatId: external_exports.string(),
|
|
26875
|
+
systemId: external_exports.string().optional(),
|
|
26828
26876
|
projectId: external_exports.string().optional(),
|
|
26829
26877
|
status: external_exports.string()
|
|
26830
|
-
}).passthrough();
|
|
26878
|
+
}).passthrough());
|
|
26831
26879
|
var BeatVersionsResponseSchema = external_exports.object({
|
|
26832
26880
|
beatVersions: external_exports.array(BeatVersionItemSchema)
|
|
26833
26881
|
}).passthrough();
|
|
26834
26882
|
var ConversationSummaryBaseSchema = external_exports.object({
|
|
26835
26883
|
conversationId: external_exports.string(),
|
|
26884
|
+
systemId: external_exports.string().optional(),
|
|
26836
26885
|
projectId: external_exports.string().optional(),
|
|
26837
26886
|
teamspaceId: external_exports.string().optional(),
|
|
26838
26887
|
userId: external_exports.string(),
|
|
@@ -26846,7 +26895,7 @@ var ConversationSummaryBaseSchema = external_exports.object({
|
|
|
26846
26895
|
createdAt: external_exports.string(),
|
|
26847
26896
|
updatedAt: external_exports.string()
|
|
26848
26897
|
});
|
|
26849
|
-
var ConversationSummarySchema = ConversationSummaryBaseSchema.passthrough();
|
|
26898
|
+
var ConversationSummarySchema = external_exports.preprocess(normalizeSystemId, ConversationSummaryBaseSchema.passthrough());
|
|
26850
26899
|
var StoredMessageSchema = external_exports.object({
|
|
26851
26900
|
messageId: external_exports.string(),
|
|
26852
26901
|
conversationId: external_exports.string(),
|
|
@@ -26963,6 +27012,93 @@ var WorkItemEstimateHintApiSchema = external_exports.object({
|
|
|
26963
27012
|
});
|
|
26964
27013
|
var WorkItemsResponseSchema = external_exports.object({ workItems: external_exports.array(WorkItemApiSchema) }).passthrough();
|
|
26965
27014
|
var WorkItemResponseSchema = external_exports.object({ workItem: WorkItemApiSchema, estimateHint: WorkItemEstimateHintApiSchema.optional() }).passthrough();
|
|
27015
|
+
var WORK_INTAKE_STATUSES = [
|
|
27016
|
+
"requested",
|
|
27017
|
+
"needs_decision",
|
|
27018
|
+
"accepted",
|
|
27019
|
+
"done"
|
|
27020
|
+
];
|
|
27021
|
+
var WorkIntakeStatusApiSchema = external_exports.enum(WORK_INTAKE_STATUSES);
|
|
27022
|
+
var NEEDS_DECISION_REASONS = [
|
|
27023
|
+
"out_of_scope",
|
|
27024
|
+
"exceeds_capacity",
|
|
27025
|
+
"incoherent_with_decision"
|
|
27026
|
+
];
|
|
27027
|
+
var NeedsDecisionReasonApiSchema = external_exports.enum(NEEDS_DECISION_REASONS);
|
|
27028
|
+
var WORK_ORDER_SIZES = [
|
|
27029
|
+
"XS",
|
|
27030
|
+
"S",
|
|
27031
|
+
"M",
|
|
27032
|
+
"L",
|
|
27033
|
+
"XL"
|
|
27034
|
+
];
|
|
27035
|
+
var WorkOrderSizeApiSchema = external_exports.enum(WORK_ORDER_SIZES);
|
|
27036
|
+
var WORK_REQUEST_ORIGINS = [
|
|
27037
|
+
"client",
|
|
27038
|
+
"internal"
|
|
27039
|
+
];
|
|
27040
|
+
var WorkRequestOriginApiSchema = external_exports.enum(WORK_REQUEST_ORIGINS);
|
|
27041
|
+
var WorkRequestApiSchema = external_exports.object({
|
|
27042
|
+
workRequestId: external_exports.string(),
|
|
27043
|
+
movementId: external_exports.string(),
|
|
27044
|
+
teamspaceId: external_exports.string(),
|
|
27045
|
+
orgId: external_exports.string(),
|
|
27046
|
+
title: external_exports.string(),
|
|
27047
|
+
/** The ask as written, in the requester's own language. */
|
|
27048
|
+
body: external_exports.string().optional(),
|
|
27049
|
+
requester: HumanAssigneeApiSchema,
|
|
27050
|
+
/** Where the ask entered — one entity covers both, only the entry point differs. */
|
|
27051
|
+
origin: WorkRequestOriginApiSchema,
|
|
27052
|
+
createdBy: external_exports.string().optional(),
|
|
27053
|
+
version: external_exports.number().optional(),
|
|
27054
|
+
createdAt: external_exports.string(),
|
|
27055
|
+
updatedAt: external_exports.string()
|
|
27056
|
+
}).passthrough();
|
|
27057
|
+
var WorkOrderApiSchema = external_exports.object({
|
|
27058
|
+
workOrderId: external_exports.string(),
|
|
27059
|
+
/** Immutable lineage back to the ask this Order was split from. */
|
|
27060
|
+
workRequestId: external_exports.string(),
|
|
27061
|
+
/** Mutable — an Order moves Tracks when an early split guess turns out wrong. */
|
|
27062
|
+
trackId: external_exports.string(),
|
|
27063
|
+
teamspaceId: external_exports.string(),
|
|
27064
|
+
orgId: external_exports.string(),
|
|
27065
|
+
title: external_exports.string(),
|
|
27066
|
+
description: external_exports.string().optional(),
|
|
27067
|
+
status: WorkIntakeStatusApiSchema,
|
|
27068
|
+
/** Present if and only if status is `needs_decision` — the reason IS the routing. */
|
|
27069
|
+
needsDecisionReason: NeedsDecisionReasonApiSchema.optional(),
|
|
27070
|
+
/** Absent when the Order arrived before it was sized, which the composition counts. */
|
|
27071
|
+
size: WorkOrderSizeApiSchema.optional(),
|
|
27072
|
+
createdBy: external_exports.string().optional(),
|
|
27073
|
+
version: external_exports.number().optional(),
|
|
27074
|
+
createdAt: external_exports.string(),
|
|
27075
|
+
updatedAt: external_exports.string()
|
|
27076
|
+
}).passthrough();
|
|
27077
|
+
var WorkRequestSizeEntryApiSchema = external_exports.object({
|
|
27078
|
+
size: WorkOrderSizeApiSchema,
|
|
27079
|
+
count: external_exports.number()
|
|
27080
|
+
});
|
|
27081
|
+
var WorkRequestSizeCompositionApiSchema = external_exports.object({
|
|
27082
|
+
/** Largest first, so a display reads "a large and a medium". */
|
|
27083
|
+
entries: external_exports.array(WorkRequestSizeEntryApiSchema),
|
|
27084
|
+
/** Orders carrying no usable size — counted, never silently dropped. */
|
|
27085
|
+
unsized: external_exports.number(),
|
|
27086
|
+
/** Sized orders only. */
|
|
27087
|
+
totalValueUnits: external_exports.number()
|
|
27088
|
+
});
|
|
27089
|
+
var WorkRequestOrderApiSchema = WorkOrderApiSchema.extend({
|
|
27090
|
+
/** Absent — not null — when the Track no longer resolves. */
|
|
27091
|
+
trackTitle: external_exports.string().optional()
|
|
27092
|
+
}).passthrough();
|
|
27093
|
+
var WorkRequestsResponseSchema = external_exports.object({ workRequests: external_exports.array(WorkRequestApiSchema) }).passthrough();
|
|
27094
|
+
var WorkOrdersResponseSchema = external_exports.object({ workOrders: external_exports.array(WorkOrderApiSchema) }).passthrough();
|
|
27095
|
+
var WorkRequestResponseSchema = external_exports.object({ workRequest: WorkRequestApiSchema }).passthrough();
|
|
27096
|
+
var WorkOrderResponseSchema = external_exports.object({ workOrder: WorkOrderApiSchema }).passthrough();
|
|
27097
|
+
var WorkRequestDetailResponseSchema = external_exports.object({
|
|
27098
|
+
workRequest: WorkRequestApiSchema,
|
|
27099
|
+
orders: external_exports.array(WorkRequestOrderApiSchema),
|
|
27100
|
+
size: WorkRequestSizeCompositionApiSchema
|
|
27101
|
+
}).passthrough();
|
|
26966
27102
|
var AccountStatusSchema = external_exports.enum(["active", "inactive", "archived"]);
|
|
26967
27103
|
var AccountApiSchema = external_exports.object({
|
|
26968
27104
|
accountId: external_exports.string(),
|
|
@@ -26999,7 +27135,7 @@ var LayerApiSchema = external_exports.preprocess(
|
|
|
26999
27135
|
(raw) => {
|
|
27000
27136
|
if (typeof raw !== "object" || raw === null) return raw;
|
|
27001
27137
|
const l = raw;
|
|
27002
|
-
const id = l["systemId"]
|
|
27138
|
+
const id = l["systemId"] || l["projectId"];
|
|
27003
27139
|
if (!id) return raw;
|
|
27004
27140
|
return { ...l, systemId: id, projectId: id };
|
|
27005
27141
|
},
|
|
@@ -27058,10 +27194,11 @@ var DELIVERABLE_GROUP_STATUSES = [
|
|
|
27058
27194
|
"cancelled"
|
|
27059
27195
|
];
|
|
27060
27196
|
var DeliverableGroupStatusSchema = external_exports.enum(DELIVERABLE_GROUP_STATUSES);
|
|
27061
|
-
var DeliverableGroupApiSchema = external_exports.object({
|
|
27197
|
+
var DeliverableGroupApiSchema = external_exports.preprocess(normalizeSystemId, external_exports.object({
|
|
27062
27198
|
deliverableGroupId: external_exports.string(),
|
|
27063
27199
|
groupCode: external_exports.string(),
|
|
27064
27200
|
teamspaceId: external_exports.string(),
|
|
27201
|
+
systemId: external_exports.string().nullish(),
|
|
27065
27202
|
projectId: external_exports.string().nullish(),
|
|
27066
27203
|
movementId: external_exports.string().nullish(),
|
|
27067
27204
|
orgId: external_exports.string(),
|
|
@@ -27079,7 +27216,7 @@ var DeliverableGroupApiSchema = external_exports.object({
|
|
|
27079
27216
|
version: external_exports.number().nullish(),
|
|
27080
27217
|
createdAt: external_exports.string(),
|
|
27081
27218
|
updatedAt: external_exports.string()
|
|
27082
|
-
}).passthrough();
|
|
27219
|
+
}).passthrough());
|
|
27083
27220
|
var DeliverableGroupsResponseSchema = external_exports.object({
|
|
27084
27221
|
deliverableGroups: external_exports.array(DeliverableGroupApiSchema)
|
|
27085
27222
|
}).passthrough();
|
|
@@ -27096,27 +27233,34 @@ var MovementDropSummaryApiSchema = external_exports.object({
|
|
|
27096
27233
|
var MovementDropsResponseSchema = external_exports.object({
|
|
27097
27234
|
drops: external_exports.array(MovementDropSummaryApiSchema)
|
|
27098
27235
|
}).passthrough();
|
|
27099
|
-
var WorkPlanBeatVersionApiSchema = external_exports.
|
|
27100
|
-
|
|
27101
|
-
|
|
27102
|
-
|
|
27103
|
-
|
|
27104
|
-
|
|
27105
|
-
|
|
27106
|
-
|
|
27107
|
-
|
|
27108
|
-
|
|
27109
|
-
|
|
27110
|
-
|
|
27111
|
-
|
|
27112
|
-
|
|
27113
|
-
|
|
27236
|
+
var WorkPlanBeatVersionApiSchema = external_exports.preprocess(
|
|
27237
|
+
normalizeSystemId,
|
|
27238
|
+
external_exports.object({
|
|
27239
|
+
beatVersionId: external_exports.string(),
|
|
27240
|
+
beatId: external_exports.string(),
|
|
27241
|
+
systemId: external_exports.string().optional(),
|
|
27242
|
+
projectId: external_exports.string().optional(),
|
|
27243
|
+
versionNumber: external_exports.number(),
|
|
27244
|
+
title: external_exports.string(),
|
|
27245
|
+
status: BeatVersionStatusSchema,
|
|
27246
|
+
// Derived Value Units (VU = Δf × W), read-only. 0 when the BV has no confirmed
|
|
27247
|
+
// value-velocity inputs. Computed server-side from the parent Beat's weight.
|
|
27248
|
+
// `.default(0)` tolerates a rolling deploy where an older API omits the field —
|
|
27249
|
+
// validatedApiFetch would otherwise throw and drop the whole hook into error.
|
|
27250
|
+
valueUnits: external_exports.number().default(0),
|
|
27251
|
+
createdAt: external_exports.string(),
|
|
27252
|
+
updatedAt: external_exports.string()
|
|
27253
|
+
}).passthrough()
|
|
27254
|
+
);
|
|
27114
27255
|
var DeliverableGroupBeatVersionsResponseSchema = external_exports.object({
|
|
27115
27256
|
beatVersions: external_exports.array(WorkPlanBeatVersionApiSchema)
|
|
27116
27257
|
}).passthrough();
|
|
27117
27258
|
var RevisionClaimActorSchema = external_exports.union([
|
|
27118
27259
|
external_exports.object({ kind: external_exports.literal("user"), userId: external_exports.string() }),
|
|
27119
|
-
external_exports.
|
|
27260
|
+
external_exports.preprocess(
|
|
27261
|
+
normalizeSystemId,
|
|
27262
|
+
external_exports.object({ kind: external_exports.literal("agent"), agentId: external_exports.string(), systemId: external_exports.string(), projectId: external_exports.string() })
|
|
27263
|
+
)
|
|
27120
27264
|
]);
|
|
27121
27265
|
var RevisionClaimSchema = external_exports.object({
|
|
27122
27266
|
claimId: external_exports.string(),
|
|
@@ -27127,33 +27271,41 @@ var RevisionClaimSchema = external_exports.object({
|
|
|
27127
27271
|
var RevisionClaimsResponseSchema = external_exports.object({
|
|
27128
27272
|
claims: external_exports.array(RevisionClaimSchema)
|
|
27129
27273
|
}).passthrough();
|
|
27130
|
-
var ProposedRevisionSchema = external_exports.
|
|
27131
|
-
|
|
27132
|
-
|
|
27133
|
-
|
|
27134
|
-
|
|
27135
|
-
|
|
27136
|
-
|
|
27137
|
-
|
|
27138
|
-
|
|
27274
|
+
var ProposedRevisionSchema = external_exports.preprocess(
|
|
27275
|
+
normalizeSystemId,
|
|
27276
|
+
external_exports.object({
|
|
27277
|
+
revisionId: external_exports.string(),
|
|
27278
|
+
title: external_exports.string(),
|
|
27279
|
+
state: external_exports.string(),
|
|
27280
|
+
beatId: external_exports.string(),
|
|
27281
|
+
beatTitle: external_exports.string().optional(),
|
|
27282
|
+
systemId: external_exports.string().optional(),
|
|
27283
|
+
projectId: external_exports.string().optional(),
|
|
27284
|
+
projectTitle: external_exports.string().optional()
|
|
27285
|
+
}).passthrough()
|
|
27286
|
+
);
|
|
27139
27287
|
var ReleaseIntervalSchema = external_exports.object({
|
|
27140
27288
|
averageIntervalDays: external_exports.number(),
|
|
27141
27289
|
sampleSize: external_exports.number(),
|
|
27142
27290
|
isFallback: external_exports.boolean()
|
|
27143
27291
|
}).passthrough();
|
|
27144
|
-
var EligibleBeatVersionForDropSchema = external_exports.
|
|
27145
|
-
|
|
27146
|
-
|
|
27147
|
-
|
|
27148
|
-
|
|
27149
|
-
|
|
27150
|
-
|
|
27151
|
-
|
|
27152
|
-
|
|
27153
|
-
|
|
27154
|
-
|
|
27155
|
-
|
|
27156
|
-
|
|
27292
|
+
var EligibleBeatVersionForDropSchema = external_exports.preprocess(
|
|
27293
|
+
normalizeSystemId,
|
|
27294
|
+
external_exports.object({
|
|
27295
|
+
beatVersionId: external_exports.string(),
|
|
27296
|
+
title: external_exports.string(),
|
|
27297
|
+
state: external_exports.string(),
|
|
27298
|
+
beatId: external_exports.string(),
|
|
27299
|
+
beatTitle: external_exports.string().optional(),
|
|
27300
|
+
systemId: external_exports.string().optional(),
|
|
27301
|
+
projectId: external_exports.string().optional(),
|
|
27302
|
+
projectTitle: external_exports.string().optional(),
|
|
27303
|
+
createdAt: external_exports.string(),
|
|
27304
|
+
updatedAt: external_exports.string(),
|
|
27305
|
+
humanAssignee: external_exports.object({ email: external_exports.string(), name: external_exports.string() }).optional(),
|
|
27306
|
+
currentDropAssignment: external_exports.object({ dropId: external_exports.string(), dropCode: external_exports.string().optional(), state: external_exports.string() }).optional()
|
|
27307
|
+
}).passthrough()
|
|
27308
|
+
);
|
|
27157
27309
|
var ScoredDropCandidateSchema = external_exports.object({
|
|
27158
27310
|
bv: EligibleBeatVersionForDropSchema,
|
|
27159
27311
|
// Score fields are nullable — the ranking engine returns null when there is
|
|
@@ -27393,7 +27545,7 @@ ${formatDeliveryPolicy(
|
|
|
27393
27545
|
function registerNoteTools(server, ctx, client) {
|
|
27394
27546
|
server.tool(
|
|
27395
27547
|
"list_notes",
|
|
27396
|
-
"List Notes for a system. Without beatId: returns all notes (system-level + beat-level). With beatId: returns only notes scoped to that beat. Filterable by type, status, revisionId, beatVersionId, and significance. Use offset/limit to paginate beat-scoped results; use cursor for
|
|
27548
|
+
"List Notes for a system. Without beatId: returns all notes (system-level + beat-level). With beatId: returns only notes scoped to that beat. Filterable by type, status, revisionId, beatVersionId, and significance. Use offset/limit to paginate beat-scoped results; use cursor for system-wide results.",
|
|
27397
27549
|
{
|
|
27398
27550
|
systemId: external_exports.string().describe("The system ID"),
|
|
27399
27551
|
beatId: external_exports.string().optional().describe("Scope to a specific beat (omit for all system notes)"),
|
|
@@ -27405,7 +27557,7 @@ function registerNoteTools(server, ctx, client) {
|
|
|
27405
27557
|
significance: external_exports.enum(DECISION_SIGNIFICANCE_VALUES2).optional().describe("Filter decision Notes by significance tier (strategic | structural | implementation). Notes without a significance value are treated as implementation."),
|
|
27406
27558
|
offset: external_exports.coerce.number().int().min(0).default(0).describe("Notes to skip for pagination (applies to beat-scoped and source-document-filtered results only)"),
|
|
27407
27559
|
limit: external_exports.coerce.number().int().min(1).max(500).default(100).describe("Max notes to return (default 100, max 500)"),
|
|
27408
|
-
cursor: external_exports.string().optional().describe("Opaque pagination cursor from a previous response \u2014 use for
|
|
27560
|
+
cursor: external_exports.string().optional().describe("Opaque pagination cursor from a previous response \u2014 use for system-wide note pagination (no beatId)"),
|
|
27409
27561
|
orderBy: external_exports.enum(["newest", "oldest"]).optional().describe("Sort order \u2014 newest or oldest first. Applies to beat-scoped queries (beatId provided); omit to use DynamoDB scan order.")
|
|
27410
27562
|
},
|
|
27411
27563
|
async ({ systemId, beatId, noteType, status, revisionId, beatVersionId, sourceDocumentNoteId, significance, offset = 0, limit = 100, cursor, orderBy }) => {
|
|
@@ -27463,7 +27615,7 @@ function registerNoteTools(server, ctx, client) {
|
|
|
27463
27615
|
allNotesResult = await client.listAllSystemNotes(systemId, filters, SOURCE_DOC_FETCH_LIMIT);
|
|
27464
27616
|
} catch (err) {
|
|
27465
27617
|
const message = err instanceof Error ? err.message : String(err);
|
|
27466
|
-
return { content: [{ type: "text", text: `Failed to list
|
|
27618
|
+
return { content: [{ type: "text", text: `Failed to list system notes: ${message}` }], isError: true };
|
|
27467
27619
|
}
|
|
27468
27620
|
const { notes: allNotes, hasMore: corpusTruncated } = allNotesResult;
|
|
27469
27621
|
const filtered = allNotes.filter((n) => n.sourceSubmissionId === sourceDocumentNoteId);
|
|
@@ -27471,7 +27623,7 @@ function registerNoteTools(server, ctx, client) {
|
|
|
27471
27623
|
page = filtered.slice(offset, offset + limit);
|
|
27472
27624
|
hasMore = offset + limit < total;
|
|
27473
27625
|
const truncationWarning = corpusTruncated ? `
|
|
27474
|
-
> \u26A0\uFE0F
|
|
27626
|
+
> \u26A0\uFE0F System has >5000 notes; sourceDocumentNoteId filter may be incomplete.
|
|
27475
27627
|
` : "";
|
|
27476
27628
|
header = (hasMore ? `Showing ${offset + 1}\u2013${offset + page.length} of ${total} notes. Use offset=${offset + limit} to continue.
|
|
27477
27629
|
|
|
@@ -27484,7 +27636,7 @@ function registerNoteTools(server, ctx, client) {
|
|
|
27484
27636
|
projectNotesResult = await client.listAllSystemNotes(systemId, filters, limit, cursor);
|
|
27485
27637
|
} catch (err) {
|
|
27486
27638
|
const message = err instanceof Error ? err.message : String(err);
|
|
27487
|
-
return { content: [{ type: "text", text: `Failed to list
|
|
27639
|
+
return { content: [{ type: "text", text: `Failed to list system notes: ${message}` }], isError: true };
|
|
27488
27640
|
}
|
|
27489
27641
|
const { notes: rawNotes, cursor: nextCursor, hasMore: serviceHasMore } = projectNotesResult;
|
|
27490
27642
|
hasMore = serviceHasMore;
|
|
@@ -27570,7 +27722,7 @@ function registerNoteTools(server, ctx, client) {
|
|
|
27570
27722
|
const DOCUMENT_FETCH_LIMIT = 5e3;
|
|
27571
27723
|
const { notes: docs, hasMore: truncated } = await client.listAllSystemNotes(systemId, { noteType: "document" }, DOCUMENT_FETCH_LIMIT);
|
|
27572
27724
|
const visibleDocs = docs.filter((d) => d.status !== DISMISSED_NOTE_STATUS);
|
|
27573
|
-
const truncationNotice = truncated && visibleDocs.length > 0 ? "\n\n> \u26A0\uFE0F This
|
|
27725
|
+
const truncationNotice = truncated && visibleDocs.length > 0 ? "\n\n> \u26A0\uFE0F This system has more than 5000 documents. Some documents may not be shown.\n" : "";
|
|
27574
27726
|
const text = formatDocumentList(visibleDocs) + truncationNotice;
|
|
27575
27727
|
return { content: [{ type: "text", text }] };
|
|
27576
27728
|
}
|
|
@@ -27619,8 +27771,8 @@ function registerNoteTools(server, ctx, client) {
|
|
|
27619
27771
|
"Create a new Note. Provide exactly one of systemId, teamspaceId, movementId, or none (org-level): systemId scopes the note to a system (optionally with beatId), teamspaceId scopes it to a teamspace (no cascade to child systems), movementId scopes it to a Movement (commercial SOW container \u2014 engagement-level knowledge), and omitting all creates an org-level note that applies across all systems.",
|
|
27620
27772
|
{
|
|
27621
27773
|
systemId: external_exports.string().optional().describe("The system ID (omit for teamspace-, movement-, or org-level note)"),
|
|
27622
|
-
teamspaceId: external_exports.string().optional().describe("The teamspace ID (omit for
|
|
27623
|
-
movementId: external_exports.string().min(1).optional().describe("The Movement ID (omit for
|
|
27774
|
+
teamspaceId: external_exports.string().optional().describe("The teamspace ID (omit for system-, movement-, or org-level note)"),
|
|
27775
|
+
movementId: external_exports.string().min(1).optional().describe("The Movement ID (omit for system-, teamspace-, or org-level note)"),
|
|
27624
27776
|
noteType: external_exports.enum(NOTE_TYPE_VALUES).describe("The type of note"),
|
|
27625
27777
|
content: external_exports.string().describe("The note content"),
|
|
27626
27778
|
beatId: external_exports.string().optional().describe("Beat ID if this note is beat-scoped (requires systemId)"),
|
|
@@ -27725,7 +27877,7 @@ ${text}` }] };
|
|
|
27725
27877
|
content: external_exports.string().optional().describe("Updated content"),
|
|
27726
27878
|
rationale: external_exports.string().optional().describe("Why this note exists or why this decision was made"),
|
|
27727
27879
|
response: external_exports.string().optional().describe("User response (for resolving assumptions)"),
|
|
27728
|
-
beatId: external_exports.string().nullable().optional().describe("Move this note to a different beat, or null to unscope it back to
|
|
27880
|
+
beatId: external_exports.string().nullable().optional().describe("Move this note to a different beat, or null to unscope it back to system level (updates all index items transactionally)"),
|
|
27729
27881
|
revisionId: external_exports.string().optional().describe("Revision ID to associate this note with (revision-scoped assumptions, decisions, or guidance)"),
|
|
27730
27882
|
dependsOnNotes: external_exports.array(external_exports.string()).optional().describe("Note IDs this note depends on (child \u2192 parent links for consolidation)"),
|
|
27731
27883
|
humanAssignee: humanAssigneeSchema.nullable().optional().describe("Assign or reassign this note to a person (null to clear)"),
|
|
@@ -28660,7 +28812,7 @@ function registerOnboardingTools(server, ctx, client) {
|
|
|
28660
28812
|
server.tool(
|
|
28661
28813
|
"create_teamspace_onboarding_batch",
|
|
28662
28814
|
[
|
|
28663
|
-
"Create a Teamspace,
|
|
28815
|
+
"Create a Teamspace, Systems, and Notes",
|
|
28664
28816
|
"from a PM-approved onboarding payload in a single batch operation.",
|
|
28665
28817
|
"Call this after the PM approves the pre-flight review card from initiate_teamspace_onboarding.",
|
|
28666
28818
|
"Returns a creation receipt with IDs and counts for all created entities.",
|
|
@@ -28668,8 +28820,8 @@ function registerOnboardingTools(server, ctx, client) {
|
|
|
28668
28820
|
].join(" "),
|
|
28669
28821
|
{
|
|
28670
28822
|
teamspaceName: external_exports.string().min(1).max(200).describe("Teamspace display name"),
|
|
28671
|
-
projects: external_exports.array(OnboardingProjectInputSchema).min(1).describe("Phase 1
|
|
28672
|
-
teamspaceNotes: external_exports.array(OnboardingNoteInputSchema).describe("Constraints, assumptions, and context notes at the Teamspace/
|
|
28823
|
+
projects: external_exports.array(OnboardingProjectInputSchema).min(1).describe("Phase 1 systems to create, each linked to the Teamspace"),
|
|
28824
|
+
teamspaceNotes: external_exports.array(OnboardingNoteInputSchema).describe("Constraints, assumptions, and context notes at the Teamspace/system level")
|
|
28673
28825
|
},
|
|
28674
28826
|
async ({
|
|
28675
28827
|
teamspaceName,
|
|
@@ -28710,7 +28862,7 @@ Error: ${msg}`);
|
|
|
28710
28862
|
const msg = err instanceof Error ? err.message : String(err);
|
|
28711
28863
|
lines.push(`
|
|
28712
28864
|
Projects created: ${createdProjects.length}`);
|
|
28713
|
-
lines.unshift(`\u26A0\uFE0F Onboarding batch partially created \u2014 stopped at:
|
|
28865
|
+
lines.unshift(`\u26A0\uFE0F Onboarding batch partially created \u2014 stopped at: system "${p.title}"
|
|
28714
28866
|
Error: ${msg}`);
|
|
28715
28867
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
28716
28868
|
}
|
|
@@ -31579,6 +31731,337 @@ function registerWorkItemTools(server, _ctx, client) {
|
|
|
31579
31731
|
);
|
|
31580
31732
|
}
|
|
31581
31733
|
|
|
31734
|
+
// ../../libs/harmonica-services/src/mcp/tools/work-order-tools.ts
|
|
31735
|
+
var WORK_INTAKE_STATUS_ENUM = [
|
|
31736
|
+
"requested",
|
|
31737
|
+
"needs_decision",
|
|
31738
|
+
"accepted",
|
|
31739
|
+
"done"
|
|
31740
|
+
];
|
|
31741
|
+
var NEEDS_DECISION_REASON_ENUM = [
|
|
31742
|
+
"out_of_scope",
|
|
31743
|
+
"exceeds_capacity",
|
|
31744
|
+
"incoherent_with_decision"
|
|
31745
|
+
];
|
|
31746
|
+
var WORK_ORDER_SIZE_ENUM = [
|
|
31747
|
+
"XS",
|
|
31748
|
+
"S",
|
|
31749
|
+
"M",
|
|
31750
|
+
"L",
|
|
31751
|
+
"XL"
|
|
31752
|
+
];
|
|
31753
|
+
function oneLine(value) {
|
|
31754
|
+
return value.replace(/[\r\n]+/g, " ");
|
|
31755
|
+
}
|
|
31756
|
+
function formatOrderLine(o) {
|
|
31757
|
+
const reason = o.needsDecisionReason ? ` [${o.needsDecisionReason}]` : "";
|
|
31758
|
+
return `[${o.workOrderId}] ${oneLine(o.title)} \u2014 ${o.status}${reason}, ${o.size ?? "unsized"}, on ${o.trackId}`;
|
|
31759
|
+
}
|
|
31760
|
+
function registerWorkOrderTools(server, _ctx, client) {
|
|
31761
|
+
server.tool(
|
|
31762
|
+
"list_track_work_orders",
|
|
31763
|
+
'List the Work Orders placed on a Track (DeliverableGroup). A Work Order is the internal unit of agreed work. Recognition cues: "what is committed on this track", "list the orders" \u2192 list_track_work_orders.',
|
|
31764
|
+
{
|
|
31765
|
+
trackId: external_exports.string().describe("The Track (DeliverableGroup) ID")
|
|
31766
|
+
},
|
|
31767
|
+
async ({ trackId }) => {
|
|
31768
|
+
const orders = await client.listTrackWorkOrders(trackId);
|
|
31769
|
+
const text = orders.length === 0 ? "No work orders found." : orders.map(formatOrderLine).join("\n");
|
|
31770
|
+
return { content: [{ type: "text", text }] };
|
|
31771
|
+
}
|
|
31772
|
+
);
|
|
31773
|
+
server.tool(
|
|
31774
|
+
"list_work_request_work_orders",
|
|
31775
|
+
"List the Work Orders one Work Request split into \u2014 the lineage view. A four-way split shows four orders here, each possibly on a different Track and in a different state.",
|
|
31776
|
+
{
|
|
31777
|
+
workRequestId: external_exports.string().describe("The Work Request ID")
|
|
31778
|
+
},
|
|
31779
|
+
async ({ workRequestId }) => {
|
|
31780
|
+
const orders = await client.listWorkRequestWorkOrders(workRequestId);
|
|
31781
|
+
const text = orders.length === 0 ? "No work orders found \u2014 this request has not been split yet." : orders.map(formatOrderLine).join("\n");
|
|
31782
|
+
return { content: [{ type: "text", text }] };
|
|
31783
|
+
}
|
|
31784
|
+
);
|
|
31785
|
+
server.tool(
|
|
31786
|
+
"get_work_order",
|
|
31787
|
+
"Get a Work Order by ID. Returns its title, status (with the routing reason when it is awaiting a decision), t-shirt size, the Track it sits on, and the Work Request it was split from.",
|
|
31788
|
+
{
|
|
31789
|
+
workOrderId: external_exports.string().describe("The Work Order ID (e.g., wo-abc123)")
|
|
31790
|
+
},
|
|
31791
|
+
async ({ workOrderId }) => {
|
|
31792
|
+
const wo = await client.getWorkOrder(workOrderId);
|
|
31793
|
+
if (!wo) {
|
|
31794
|
+
return { content: [{ type: "text", text: `Work order not found: ${workOrderId}` }] };
|
|
31795
|
+
}
|
|
31796
|
+
const lines = [
|
|
31797
|
+
`ID: ${wo.workOrderId}`,
|
|
31798
|
+
`Title: ${oneLine(wo.title)}`,
|
|
31799
|
+
`From Work Request: ${wo.workRequestId}`,
|
|
31800
|
+
`Track: ${wo.trackId}`,
|
|
31801
|
+
`Status: ${wo.status}`,
|
|
31802
|
+
wo.needsDecisionReason ? `Routing Reason: ${wo.needsDecisionReason}` : null,
|
|
31803
|
+
wo.size !== void 0 ? `Size: ${wo.size}` : "Size: unsized",
|
|
31804
|
+
wo.description ? `Description: ${oneLine(wo.description)}` : null,
|
|
31805
|
+
wo.createdBy ? `Created By: ${wo.createdBy}` : null,
|
|
31806
|
+
`Created: ${wo.createdAt}`,
|
|
31807
|
+
`Updated: ${wo.updatedAt}`
|
|
31808
|
+
].filter(Boolean).join("\n");
|
|
31809
|
+
return { content: [{ type: "text", text: lines }] };
|
|
31810
|
+
}
|
|
31811
|
+
);
|
|
31812
|
+
server.tool(
|
|
31813
|
+
"create_work_order",
|
|
31814
|
+
'Split a Work Request into an agreed Work Order on a Track. Called once per piece: a request covering two separate lines of work becomes two orders. Starts in "requested" status \u2014 moving it past the coherence gate is transition_work_order_status. The Track must belong to the same teamspace and Account as the Request; the service refuses a placement that crosses either boundary.',
|
|
31815
|
+
{
|
|
31816
|
+
trackId: external_exports.string().describe("The Track (DeliverableGroup) this order is placed on"),
|
|
31817
|
+
workRequestId: external_exports.string().min(1).describe("The Work Request this order was split from \u2014 immutable lineage"),
|
|
31818
|
+
title: external_exports.string().min(1).max(300).describe("Work order title"),
|
|
31819
|
+
description: external_exports.string().max(1e4).optional().describe("Optional detail beyond the title"),
|
|
31820
|
+
size: external_exports.enum(WORK_ORDER_SIZE_ENUM).optional().describe("Optional t-shirt size. An order can arrive before it is sized; a request's composition counts unsized orders rather than hiding them."),
|
|
31821
|
+
createdBy: external_exports.string().optional().describe("Optional creator identity for audit")
|
|
31822
|
+
},
|
|
31823
|
+
async ({ trackId, workRequestId, title, description, size, createdBy }) => {
|
|
31824
|
+
const wo = await client.createWorkOrder({
|
|
31825
|
+
trackId,
|
|
31826
|
+
workRequestId,
|
|
31827
|
+
title,
|
|
31828
|
+
...description !== void 0 && { description },
|
|
31829
|
+
...size !== void 0 && { size },
|
|
31830
|
+
...createdBy !== void 0 && { createdBy }
|
|
31831
|
+
});
|
|
31832
|
+
return {
|
|
31833
|
+
content: [{ type: "text", text: `Created work order: ${formatOrderLine(wo)}` }]
|
|
31834
|
+
};
|
|
31835
|
+
}
|
|
31836
|
+
);
|
|
31837
|
+
server.tool(
|
|
31838
|
+
"update_work_order",
|
|
31839
|
+
"Update content fields on a Work Order (title, description, size). To move it between Tracks use move_work_order; to change its status use transition_work_order_status. The Work Request it came from cannot be changed \u2014 that lineage is immutable.",
|
|
31840
|
+
{
|
|
31841
|
+
workOrderId: external_exports.string().describe("The Work Order ID"),
|
|
31842
|
+
title: external_exports.string().min(1).max(300).optional().describe("New title"),
|
|
31843
|
+
description: external_exports.string().max(1e4).nullable().optional().describe("New description. Pass null to clear; omit to leave untouched."),
|
|
31844
|
+
size: external_exports.enum(WORK_ORDER_SIZE_ENUM).nullable().optional().describe("New t-shirt size. Pass null to return it to unsized; omit to leave untouched.")
|
|
31845
|
+
},
|
|
31846
|
+
async ({ workOrderId, title, description, size }) => {
|
|
31847
|
+
if (title === void 0 && description === void 0 && size === void 0) {
|
|
31848
|
+
return {
|
|
31849
|
+
content: [
|
|
31850
|
+
{ type: "text", text: "Nothing to update: pass at least one of title, description, or size." }
|
|
31851
|
+
],
|
|
31852
|
+
isError: true
|
|
31853
|
+
};
|
|
31854
|
+
}
|
|
31855
|
+
const wo = await client.updateWorkOrder(workOrderId, {
|
|
31856
|
+
...title !== void 0 && { title },
|
|
31857
|
+
...description !== void 0 && { description },
|
|
31858
|
+
...size !== void 0 && { size }
|
|
31859
|
+
});
|
|
31860
|
+
if (!wo) {
|
|
31861
|
+
return { content: [{ type: "text", text: `Work order not found: ${workOrderId}` }] };
|
|
31862
|
+
}
|
|
31863
|
+
return { content: [{ type: "text", text: `Updated work order: ${formatOrderLine(wo)}` }] };
|
|
31864
|
+
}
|
|
31865
|
+
);
|
|
31866
|
+
server.tool(
|
|
31867
|
+
"move_work_order",
|
|
31868
|
+
"Move a Work Order to a different Track \u2014 the reversal path for a bad early split guess. The destination must belong to the same teamspace and Account as the order's Work Request; the service refuses a placement that crosses either boundary.",
|
|
31869
|
+
{
|
|
31870
|
+
workOrderId: external_exports.string().describe("The Work Order ID"),
|
|
31871
|
+
newTrackId: external_exports.string().describe("The destination Track (DeliverableGroup) ID")
|
|
31872
|
+
},
|
|
31873
|
+
async ({ workOrderId, newTrackId }) => {
|
|
31874
|
+
const wo = await client.moveWorkOrder(workOrderId, newTrackId);
|
|
31875
|
+
if (!wo) {
|
|
31876
|
+
return { content: [{ type: "text", text: `Work order not found: ${workOrderId}` }] };
|
|
31877
|
+
}
|
|
31878
|
+
return {
|
|
31879
|
+
content: [{ type: "text", text: `Moved work order to Track ${wo.trackId}: ${formatOrderLine(wo)}` }]
|
|
31880
|
+
};
|
|
31881
|
+
}
|
|
31882
|
+
);
|
|
31883
|
+
server.tool(
|
|
31884
|
+
"transition_work_order_status",
|
|
31885
|
+
"Move a Work Order through the intake gate: requested \u2192 accepted is the coherence gate itself, and there is no shortcut past it. Routing an order to needs_decision REQUIRES a reason, because the reason is the routing: out_of_scope goes back to the customer, exceeds_capacity goes to the Orchestrator, incoherent_with_decision goes back for reframing. A routed order returns to requested once resolved.",
|
|
31886
|
+
{
|
|
31887
|
+
workOrderId: external_exports.string().describe("The Work Order ID"),
|
|
31888
|
+
status: external_exports.enum(WORK_INTAKE_STATUS_ENUM).describe("Target status"),
|
|
31889
|
+
reason: external_exports.enum(NEEDS_DECISION_REASON_ENUM).optional().describe("Required when \u2014 and only when \u2014 status is needs_decision. The reason IS the routing.")
|
|
31890
|
+
},
|
|
31891
|
+
async ({ workOrderId, status, reason }) => {
|
|
31892
|
+
if (status === "needs_decision" && reason === void 0) {
|
|
31893
|
+
return {
|
|
31894
|
+
content: [
|
|
31895
|
+
{
|
|
31896
|
+
type: "text",
|
|
31897
|
+
text: "Routing an order to needs_decision requires a reason \u2014 the reason is the routing. Pass one of: out_of_scope, exceeds_capacity, incoherent_with_decision."
|
|
31898
|
+
}
|
|
31899
|
+
],
|
|
31900
|
+
isError: true
|
|
31901
|
+
};
|
|
31902
|
+
}
|
|
31903
|
+
if (status !== "needs_decision" && reason !== void 0) {
|
|
31904
|
+
return {
|
|
31905
|
+
content: [
|
|
31906
|
+
{
|
|
31907
|
+
type: "text",
|
|
31908
|
+
text: `A routing reason is only meaningful on a transition to needs_decision, not to ${status}.`
|
|
31909
|
+
}
|
|
31910
|
+
],
|
|
31911
|
+
isError: true
|
|
31912
|
+
};
|
|
31913
|
+
}
|
|
31914
|
+
const wo = await client.transitionWorkOrderStatus(workOrderId, status, reason);
|
|
31915
|
+
if (!wo) {
|
|
31916
|
+
return { content: [{ type: "text", text: `Work order not found: ${workOrderId}` }] };
|
|
31917
|
+
}
|
|
31918
|
+
return {
|
|
31919
|
+
content: [{ type: "text", text: `Transitioned work order: ${formatOrderLine(wo)}` }]
|
|
31920
|
+
};
|
|
31921
|
+
}
|
|
31922
|
+
);
|
|
31923
|
+
}
|
|
31924
|
+
|
|
31925
|
+
// ../../libs/harmonica-services/src/mcp/tools/work-request-tools.ts
|
|
31926
|
+
var WORK_REQUEST_ORIGIN_ENUM = [
|
|
31927
|
+
"client",
|
|
31928
|
+
"internal"
|
|
31929
|
+
];
|
|
31930
|
+
function oneLine2(value) {
|
|
31931
|
+
return value.replace(/[\r\n]+/g, " ");
|
|
31932
|
+
}
|
|
31933
|
+
function formatSizeComposition(size) {
|
|
31934
|
+
const parts = size.entries.map((e) => `${e.count}${e.size}`);
|
|
31935
|
+
if (size.unsized > 0) parts.push(`${size.unsized} unsized`);
|
|
31936
|
+
if (parts.length === 0) return "no orders yet";
|
|
31937
|
+
return `${parts.join(" + ")} (${size.totalValueUnits} value units)`;
|
|
31938
|
+
}
|
|
31939
|
+
function registerWorkRequestTools(server, _ctx, client) {
|
|
31940
|
+
server.tool(
|
|
31941
|
+
"list_movement_work_requests",
|
|
31942
|
+
`List the Work Requests filed against a Movement. A Work Request is the customer's ask in their own language, before it is sized or agreed. Recognition cues: "what has the client asked for", "list the requests on this engagement" \u2192 list_movement_work_requests.`,
|
|
31943
|
+
{
|
|
31944
|
+
movementId: external_exports.string().describe("The Movement (engagement) ID")
|
|
31945
|
+
},
|
|
31946
|
+
async ({ movementId }) => {
|
|
31947
|
+
const requests = await client.listMovementWorkRequests(movementId);
|
|
31948
|
+
const text = requests.length === 0 ? "No work requests found." : requests.map((wr) => `[${wr.workRequestId}] ${oneLine2(wr.title)} \u2014 from ${oneLine2(wr.requester.name)} (${wr.origin})`).join("\n");
|
|
31949
|
+
return { content: [{ type: "text", text }] };
|
|
31950
|
+
}
|
|
31951
|
+
);
|
|
31952
|
+
server.tool(
|
|
31953
|
+
"get_work_request",
|
|
31954
|
+
"Get a Work Request with the Work Orders it split into and their combined size composition. Note there is no request-level status: each Order carries its own, because a split whose halves sit in different states cannot be reduced to one word.",
|
|
31955
|
+
{
|
|
31956
|
+
workRequestId: external_exports.string().describe("The Work Request ID (e.g., wr-abc123)")
|
|
31957
|
+
},
|
|
31958
|
+
async ({ workRequestId }) => {
|
|
31959
|
+
const detail = await client.getWorkRequestDetail(workRequestId);
|
|
31960
|
+
if (!detail) {
|
|
31961
|
+
return { content: [{ type: "text", text: `Work request not found: ${workRequestId}` }] };
|
|
31962
|
+
}
|
|
31963
|
+
const { workRequest: wr, orders, size } = detail;
|
|
31964
|
+
const orderLines = orders.length === 0 ? ["Orders: none yet \u2014 this request has not been split"] : [
|
|
31965
|
+
"Orders:",
|
|
31966
|
+
...orders.map((o) => {
|
|
31967
|
+
const track = o.trackTitle ? `${oneLine2(o.trackTitle)} (${o.trackId})` : o.trackId;
|
|
31968
|
+
const reason = o.needsDecisionReason ? ` [${o.needsDecisionReason}]` : "";
|
|
31969
|
+
const sized = o.size ?? "unsized";
|
|
31970
|
+
return ` [${o.workOrderId}] ${oneLine2(o.title)} \u2014 ${o.status}${reason}, ${sized}, on ${track}`;
|
|
31971
|
+
})
|
|
31972
|
+
];
|
|
31973
|
+
const lines = [
|
|
31974
|
+
`ID: ${wr.workRequestId}`,
|
|
31975
|
+
`Title: ${oneLine2(wr.title)}`,
|
|
31976
|
+
`Movement: ${wr.movementId}`,
|
|
31977
|
+
`Requester: ${oneLine2(wr.requester.name)} <${wr.requester.email}>`,
|
|
31978
|
+
`Origin: ${wr.origin}`,
|
|
31979
|
+
wr.body ? `Ask: ${oneLine2(wr.body)}` : null,
|
|
31980
|
+
`Size: ${formatSizeComposition(size)}`,
|
|
31981
|
+
...orderLines,
|
|
31982
|
+
wr.createdBy ? `Created By: ${wr.createdBy}` : null,
|
|
31983
|
+
`Created: ${wr.createdAt}`,
|
|
31984
|
+
`Updated: ${wr.updatedAt}`
|
|
31985
|
+
].filter(Boolean).join("\n");
|
|
31986
|
+
return { content: [{ type: "text", text: lines }] };
|
|
31987
|
+
}
|
|
31988
|
+
);
|
|
31989
|
+
server.tool(
|
|
31990
|
+
"create_work_request",
|
|
31991
|
+
"File a Work Request against a Movement \u2014 how work arrives, in the requester's own language, before it is sized or agreed. Splitting it into Work Orders is a separate step (create_work_order).",
|
|
31992
|
+
{
|
|
31993
|
+
movementId: external_exports.string().describe("The Movement (engagement) this request is filed against"),
|
|
31994
|
+
title: external_exports.string().min(1).max(300).describe("Short title for the ask"),
|
|
31995
|
+
body: external_exports.string().max(1e4).optional().describe("The ask as written, in the requester's own words"),
|
|
31996
|
+
requesterName: external_exports.string().min(1).describe("Who is asking \u2014 display name"),
|
|
31997
|
+
requesterEmail: external_exports.string().email().describe("Who is asking \u2014 email"),
|
|
31998
|
+
origin: external_exports.enum(WORK_REQUEST_ORIGIN_ENUM).describe('Where the ask came from: "client" or "internal". One entity covers both \u2014 only the entry point differs.'),
|
|
31999
|
+
createdBy: external_exports.string().optional().describe("Optional creator identity for audit")
|
|
32000
|
+
},
|
|
32001
|
+
async ({ movementId, title, body, requesterName, requesterEmail, origin, createdBy }) => {
|
|
32002
|
+
const wr = await client.createWorkRequest({
|
|
32003
|
+
movementId,
|
|
32004
|
+
title,
|
|
32005
|
+
...body !== void 0 && { body },
|
|
32006
|
+
requester: { name: requesterName, email: requesterEmail },
|
|
32007
|
+
origin,
|
|
32008
|
+
...createdBy !== void 0 && { createdBy }
|
|
32009
|
+
});
|
|
32010
|
+
return {
|
|
32011
|
+
content: [
|
|
32012
|
+
{
|
|
32013
|
+
type: "text",
|
|
32014
|
+
text: `Filed work request: [${wr.workRequestId}] ${wr.title} \u2014 from ${wr.requester.name} (${wr.origin})`
|
|
32015
|
+
}
|
|
32016
|
+
]
|
|
32017
|
+
};
|
|
32018
|
+
}
|
|
32019
|
+
);
|
|
32020
|
+
server.tool(
|
|
32021
|
+
"update_work_request",
|
|
32022
|
+
"Reword a Work Request (title, body, requester). A Request cannot be moved to another Movement, and has no status to set \u2014 its Orders carry the state.",
|
|
32023
|
+
{
|
|
32024
|
+
workRequestId: external_exports.string().describe("The Work Request ID"),
|
|
32025
|
+
title: external_exports.string().min(1).max(300).optional().describe("New title"),
|
|
32026
|
+
body: external_exports.string().max(1e4).nullable().optional().describe("The ask as written. Pass null to clear; omit to leave untouched."),
|
|
32027
|
+
requesterName: external_exports.string().min(1).optional().describe("New requester display name (requires requesterEmail too)"),
|
|
32028
|
+
requesterEmail: external_exports.string().email().optional().describe("New requester email (requires requesterName too)")
|
|
32029
|
+
},
|
|
32030
|
+
async ({ workRequestId, title, body, requesterName, requesterEmail }) => {
|
|
32031
|
+
if (requesterName === void 0 !== (requesterEmail === void 0)) {
|
|
32032
|
+
return {
|
|
32033
|
+
content: [
|
|
32034
|
+
{
|
|
32035
|
+
type: "text",
|
|
32036
|
+
text: "Changing the requester requires both requesterName and requesterEmail."
|
|
32037
|
+
}
|
|
32038
|
+
],
|
|
32039
|
+
isError: true
|
|
32040
|
+
};
|
|
32041
|
+
}
|
|
32042
|
+
if (title === void 0 && body === void 0 && requesterName === void 0) {
|
|
32043
|
+
return {
|
|
32044
|
+
content: [
|
|
32045
|
+
{ type: "text", text: "Nothing to update: pass at least one of title, body, or requester." }
|
|
32046
|
+
],
|
|
32047
|
+
isError: true
|
|
32048
|
+
};
|
|
32049
|
+
}
|
|
32050
|
+
const wr = await client.updateWorkRequest(workRequestId, {
|
|
32051
|
+
...title !== void 0 && { title },
|
|
32052
|
+
...body !== void 0 && { body },
|
|
32053
|
+
...requesterName !== void 0 && requesterEmail !== void 0 && { requester: { name: requesterName, email: requesterEmail } }
|
|
32054
|
+
});
|
|
32055
|
+
if (!wr) {
|
|
32056
|
+
return { content: [{ type: "text", text: `Work request not found: ${workRequestId}` }] };
|
|
32057
|
+
}
|
|
32058
|
+
return {
|
|
32059
|
+
content: [{ type: "text", text: `Updated work request: [${wr.workRequestId}] ${wr.title}` }]
|
|
32060
|
+
};
|
|
32061
|
+
}
|
|
32062
|
+
);
|
|
32063
|
+
}
|
|
32064
|
+
|
|
31582
32065
|
// ../../libs/harmonica-services/src/mcp/tools/workflow-tools.ts
|
|
31583
32066
|
var TASK_STATUSES = ["pending", "running", "completed", "failed"];
|
|
31584
32067
|
function registerWorkflowTools(server, ctx, client) {
|
|
@@ -32043,6 +32526,8 @@ function registerAllTools(server, ctx, client, profile) {
|
|
|
32043
32526
|
registerAccountTools(server, ctx, client);
|
|
32044
32527
|
registerMovementTools(server, ctx, client);
|
|
32045
32528
|
registerWorkItemTools(server, ctx, client);
|
|
32529
|
+
registerWorkRequestTools(server, ctx, client);
|
|
32530
|
+
registerWorkOrderTools(server, ctx, client);
|
|
32046
32531
|
registerBarTools(server, ctx, client);
|
|
32047
32532
|
registerCadenceScheduleTools(server, ctx, client);
|
|
32048
32533
|
registerPulseReportTools(server, ctx, client);
|
|
@@ -33766,6 +34251,134 @@ function createHttpClient(config2) {
|
|
|
33766
34251
|
if (!parsed.success) throw new Error(`Unexpected WorkItem shape from API: ${parsed.error.message}`);
|
|
33767
34252
|
return parsed.data;
|
|
33768
34253
|
},
|
|
34254
|
+
// Work intake (B-331) — against the endpoints the API layer shipped in v3.
|
|
34255
|
+
createWorkRequest: async (input) => {
|
|
34256
|
+
const { movementId, title, body: askBody, requester, origin, createdBy } = input;
|
|
34257
|
+
const body = {
|
|
34258
|
+
title,
|
|
34259
|
+
...askBody !== void 0 && { body: askBody },
|
|
34260
|
+
requester,
|
|
34261
|
+
origin,
|
|
34262
|
+
...createdBy !== void 0 && { createdBy }
|
|
34263
|
+
};
|
|
34264
|
+
const res = await request(
|
|
34265
|
+
"POST",
|
|
34266
|
+
`/api/movements/${encodeURIComponent(movementId)}/work-requests`,
|
|
34267
|
+
body
|
|
34268
|
+
);
|
|
34269
|
+
if (res === void 0) throw new Error(`Movement ${movementId} not found`);
|
|
34270
|
+
const parsed = WorkRequestApiSchema.safeParse(res.workRequest);
|
|
34271
|
+
if (!parsed.success) throw new Error(`Unexpected WorkRequest shape from API: ${parsed.error.message}`);
|
|
34272
|
+
return parsed.data;
|
|
34273
|
+
},
|
|
34274
|
+
getWorkRequest: async (workRequestId) => {
|
|
34275
|
+
const res = await request(
|
|
34276
|
+
"GET",
|
|
34277
|
+
`/api/work-requests/${encodeURIComponent(workRequestId)}`
|
|
34278
|
+
);
|
|
34279
|
+
if (res === void 0) return void 0;
|
|
34280
|
+
const parsed = WorkRequestApiSchema.safeParse(res.workRequest);
|
|
34281
|
+
if (!parsed.success) throw new Error(`Unexpected WorkRequest shape from API: ${parsed.error.message}`);
|
|
34282
|
+
return parsed.data;
|
|
34283
|
+
},
|
|
34284
|
+
getWorkRequestDetail: async (workRequestId) => {
|
|
34285
|
+
const res = await request("GET", `/api/work-requests/${encodeURIComponent(workRequestId)}`);
|
|
34286
|
+
if (res === void 0) return void 0;
|
|
34287
|
+
const parsed = WorkRequestDetailResponseSchema.safeParse(res);
|
|
34288
|
+
if (!parsed.success) throw new Error(`Unexpected WorkRequest detail shape from API: ${parsed.error.message}`);
|
|
34289
|
+
return parsed.data;
|
|
34290
|
+
},
|
|
34291
|
+
updateWorkRequest: async (workRequestId, updates) => {
|
|
34292
|
+
const res = await request(
|
|
34293
|
+
"PATCH",
|
|
34294
|
+
`/api/work-requests/${encodeURIComponent(workRequestId)}`,
|
|
34295
|
+
updates
|
|
34296
|
+
);
|
|
34297
|
+
if (res === void 0) return void 0;
|
|
34298
|
+
const parsed = WorkRequestApiSchema.safeParse(res.workRequest);
|
|
34299
|
+
if (!parsed.success) throw new Error(`Unexpected WorkRequest shape from API: ${parsed.error.message}`);
|
|
34300
|
+
return parsed.data;
|
|
34301
|
+
},
|
|
34302
|
+
listMovementWorkRequests: async (movementId) => {
|
|
34303
|
+
const res = await request("GET", `/api/movements/${encodeURIComponent(movementId)}/work-requests`);
|
|
34304
|
+
if (res === void 0) throw new Error(`Movement ${movementId} not found`);
|
|
34305
|
+
const parsed = WorkRequestsResponseSchema.safeParse(res);
|
|
34306
|
+
if (!parsed.success) throw new Error(`Unexpected work requests list shape from API: ${parsed.error.message}`);
|
|
34307
|
+
return parsed.data.workRequests;
|
|
34308
|
+
},
|
|
34309
|
+
createWorkOrder: async (input) => {
|
|
34310
|
+
const { trackId, workRequestId, title, description, size, createdBy } = input;
|
|
34311
|
+
const body = {
|
|
34312
|
+
workRequestId,
|
|
34313
|
+
title,
|
|
34314
|
+
...description !== void 0 && { description },
|
|
34315
|
+
...size !== void 0 && { size },
|
|
34316
|
+
...createdBy !== void 0 && { createdBy }
|
|
34317
|
+
};
|
|
34318
|
+
const res = await request(
|
|
34319
|
+
"POST",
|
|
34320
|
+
`/api/deliverable-groups/${encodeURIComponent(trackId)}/work-orders`,
|
|
34321
|
+
body
|
|
34322
|
+
);
|
|
34323
|
+
if (res === void 0) throw new Error(`Track ${trackId} not found`);
|
|
34324
|
+
const parsed = WorkOrderApiSchema.safeParse(res.workOrder);
|
|
34325
|
+
if (!parsed.success) throw new Error(`Unexpected WorkOrder shape from API: ${parsed.error.message}`);
|
|
34326
|
+
return parsed.data;
|
|
34327
|
+
},
|
|
34328
|
+
getWorkOrder: async (workOrderId) => {
|
|
34329
|
+
const res = await request("GET", `/api/work-orders/${encodeURIComponent(workOrderId)}`);
|
|
34330
|
+
if (res === void 0) return void 0;
|
|
34331
|
+
const parsed = WorkOrderApiSchema.safeParse(res.workOrder);
|
|
34332
|
+
if (!parsed.success) throw new Error(`Unexpected WorkOrder shape from API: ${parsed.error.message}`);
|
|
34333
|
+
return parsed.data;
|
|
34334
|
+
},
|
|
34335
|
+
updateWorkOrder: async (workOrderId, updates) => {
|
|
34336
|
+
const res = await request(
|
|
34337
|
+
"PATCH",
|
|
34338
|
+
`/api/work-orders/${encodeURIComponent(workOrderId)}`,
|
|
34339
|
+
updates
|
|
34340
|
+
);
|
|
34341
|
+
if (res === void 0) return void 0;
|
|
34342
|
+
const parsed = WorkOrderApiSchema.safeParse(res.workOrder);
|
|
34343
|
+
if (!parsed.success) throw new Error(`Unexpected WorkOrder shape from API: ${parsed.error.message}`);
|
|
34344
|
+
return parsed.data;
|
|
34345
|
+
},
|
|
34346
|
+
listTrackWorkOrders: async (trackId) => {
|
|
34347
|
+
const res = await request("GET", `/api/deliverable-groups/${encodeURIComponent(trackId)}/work-orders`);
|
|
34348
|
+
if (res === void 0) throw new Error(`Track ${trackId} not found`);
|
|
34349
|
+
const parsed = WorkOrdersResponseSchema.safeParse(res);
|
|
34350
|
+
if (!parsed.success) throw new Error(`Unexpected work orders list shape from API: ${parsed.error.message}`);
|
|
34351
|
+
return parsed.data.workOrders;
|
|
34352
|
+
},
|
|
34353
|
+
listWorkRequestWorkOrders: async (workRequestId) => {
|
|
34354
|
+
const res = await request("GET", `/api/work-requests/${encodeURIComponent(workRequestId)}/work-orders`);
|
|
34355
|
+
if (res === void 0) throw new Error(`Work request ${workRequestId} not found`);
|
|
34356
|
+
const parsed = WorkOrdersResponseSchema.safeParse(res);
|
|
34357
|
+
if (!parsed.success) throw new Error(`Unexpected work orders list shape from API: ${parsed.error.message}`);
|
|
34358
|
+
return parsed.data.workOrders;
|
|
34359
|
+
},
|
|
34360
|
+
moveWorkOrder: async (workOrderId, newTrackId) => {
|
|
34361
|
+
const res = await request(
|
|
34362
|
+
"POST",
|
|
34363
|
+
`/api/work-orders/${encodeURIComponent(workOrderId)}/move`,
|
|
34364
|
+
{ newTrackId }
|
|
34365
|
+
);
|
|
34366
|
+
if (res === void 0) return void 0;
|
|
34367
|
+
const parsed = WorkOrderApiSchema.safeParse(res.workOrder);
|
|
34368
|
+
if (!parsed.success) throw new Error(`Unexpected WorkOrder shape from API: ${parsed.error.message}`);
|
|
34369
|
+
return parsed.data;
|
|
34370
|
+
},
|
|
34371
|
+
transitionWorkOrderStatus: async (workOrderId, toStatus, reason) => {
|
|
34372
|
+
const res = await request(
|
|
34373
|
+
"POST",
|
|
34374
|
+
`/api/work-orders/${encodeURIComponent(workOrderId)}/status`,
|
|
34375
|
+
{ status: toStatus, ...reason !== void 0 && { reason } }
|
|
34376
|
+
);
|
|
34377
|
+
if (res === void 0) return void 0;
|
|
34378
|
+
const parsed = WorkOrderApiSchema.safeParse(res.workOrder);
|
|
34379
|
+
if (!parsed.success) throw new Error(`Unexpected WorkOrder shape from API: ${parsed.error.message}`);
|
|
34380
|
+
return parsed.data;
|
|
34381
|
+
},
|
|
33769
34382
|
// Accounts (B-242 / org-scoped paying client entity that owns Movements)
|
|
33770
34383
|
createAccount: async (input) => {
|
|
33771
34384
|
const { orgId, name, description, createdBy, parentAccountId, accountType, accountCode } = input;
|
|
@@ -34317,7 +34930,7 @@ function loadConfig() {
|
|
|
34317
34930
|
};
|
|
34318
34931
|
}
|
|
34319
34932
|
async function main() {
|
|
34320
|
-
console.error(`[harmonica-mcp] v${"3.
|
|
34933
|
+
console.error(`[harmonica-mcp] v${"3.9.0"} starting\u2026`);
|
|
34321
34934
|
const config2 = loadConfig();
|
|
34322
34935
|
const client = createHttpClient({
|
|
34323
34936
|
apiBaseUrl: config2.apiBaseUrl,
|