@codazen/harmonica-mcp 3.7.1 → 3.8.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 +228 -105
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -21972,9 +21972,9 @@ function formatActivity(a) {
|
|
|
21972
21972
|
function registerActivityTools(server, ctx, client) {
|
|
21973
21973
|
server.tool(
|
|
21974
21974
|
"list_activities",
|
|
21975
|
-
"List
|
|
21975
|
+
"List system activity audit trail \u2014 shows beat changes, revision transitions, note operations, merges, splits, and reassignments. Sorted newest-first.",
|
|
21976
21976
|
{
|
|
21977
|
-
systemId: external_exports.string().describe("The
|
|
21977
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
21978
21978
|
limit: external_exports.coerce.number().min(1).max(100).optional().describe("Max activities to return (default 30)"),
|
|
21979
21979
|
importance: external_exports.enum(IMPORTANCE_VALUES).optional().describe("Filter by minimum importance level")
|
|
21980
21980
|
},
|
|
@@ -22005,7 +22005,7 @@ function registerAnalysisTools(server, ctx, client) {
|
|
|
22005
22005
|
"cluster_entities",
|
|
22006
22006
|
"Cluster any embeddable entity type (notes, beats, revisions) by vector similarity using DBSCAN. Returns groups of related entities \u2014 useful for understanding subsystem boundaries, finding duplicates, and planning batched work.",
|
|
22007
22007
|
{
|
|
22008
|
-
systemId: external_exports.string().describe("The
|
|
22008
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
22009
22009
|
entityType: ENTITY_TYPE_SCHEMA.describe("Entity type to cluster. Default: revision"),
|
|
22010
22010
|
threshold: external_exports.coerce.number().min(0).max(1).optional().default(0.75).describe("DBSCAN similarity threshold (0-1). Higher = tighter clusters. Default 0.75"),
|
|
22011
22011
|
minClusterSize: external_exports.coerce.number().int().min(2).optional().default(3).describe("Minimum cluster size. Default 3")
|
|
@@ -22034,9 +22034,9 @@ Analyzed: ${result.totalAnalyzed} | Clusters: ${result.clusters.length} | Noise:
|
|
|
22034
22034
|
);
|
|
22035
22035
|
server.tool(
|
|
22036
22036
|
"run_clustered_analysis",
|
|
22037
|
-
"Run batched analysis on clustered
|
|
22037
|
+
"Run batched analysis on clustered system entities. Groups entities by vector similarity, then runs a specified analysis type (docs, completeness, tech_debt, security) per cluster. Returns aggregated results.",
|
|
22038
22038
|
{
|
|
22039
|
-
systemId: external_exports.string().describe("The
|
|
22039
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
22040
22040
|
analysisType: ANALYSIS_TYPE_SCHEMA.describe("Type of analysis to run"),
|
|
22041
22041
|
entityType: ENTITY_TYPE_SCHEMA.describe("Entity type to cluster. Default: revision"),
|
|
22042
22042
|
threshold: external_exports.coerce.number().min(0).max(1).optional().default(0.7).describe("DBSCAN similarity threshold (0-1). Default 0.7"),
|
|
@@ -22071,9 +22071,9 @@ ${result.noise.join(", ")}` : "");
|
|
|
22071
22071
|
function registerAuditIntegrityTools(server, ctx, client) {
|
|
22072
22072
|
server.tool(
|
|
22073
22073
|
"verify_audit_integrity",
|
|
22074
|
-
"Verify the cryptographic integrity of audit trail records for a
|
|
22074
|
+
"Verify the cryptographic integrity of audit trail records for a system. Checks SHA-256 hashes on Activity and PromptLog records to detect any post-creation tampering.",
|
|
22075
22075
|
{
|
|
22076
|
-
systemId: external_exports.string().describe("The
|
|
22076
|
+
systemId: external_exports.string().describe("The system ID to verify"),
|
|
22077
22077
|
limit: external_exports.number().optional().describe("Max records to verify (default 100)")
|
|
22078
22078
|
},
|
|
22079
22079
|
async ({ systemId, limit }) => {
|
|
@@ -22287,7 +22287,7 @@ Rationale: ${rationale}`;
|
|
|
22287
22287
|
"bulk_reassign_revisions",
|
|
22288
22288
|
"Reassign multiple revisions to new home Beats in a single call. Each item names a revision and its target Beat (different items can target different Beats \u2014 e.g., redistributing one Beat's revisions across several after decomposition). Each reassignment archives the original revision and creates a copy on the target Beat, identical to reassign_revision. Returns per-item success/failure so partial failures don't abort the batch. Use when migrating many revisions at once after a Beat split.",
|
|
22289
22289
|
{
|
|
22290
|
-
systemId: external_exports.string().describe("The
|
|
22290
|
+
systemId: external_exports.string().describe("The system ID (for access control \u2014 all revisions and target beats must belong to this system)"),
|
|
22291
22291
|
items: external_exports.array(external_exports.object({
|
|
22292
22292
|
revisionId: external_exports.string().describe("The revision ID to reassign"),
|
|
22293
22293
|
toBeatId: external_exports.string().describe("The target beat ID for this specific revision")
|
|
@@ -22328,7 +22328,7 @@ Rationale: ${rationale}`;
|
|
|
22328
22328
|
"reassign_revision",
|
|
22329
22329
|
"Reassign a misattributed revision from one Beat to another. Creates a copy on the target Beat and archives the original. Logs a revision_reassigned activity for audit trail.",
|
|
22330
22330
|
{
|
|
22331
|
-
systemId: external_exports.string().describe("The
|
|
22331
|
+
systemId: external_exports.string().describe("The system ID (for access control)"),
|
|
22332
22332
|
revisionId: external_exports.string().describe("The revision ID to reassign"),
|
|
22333
22333
|
toBeatId: external_exports.string().describe("The target beat ID"),
|
|
22334
22334
|
reason: external_exports.string().describe("Why this revision is being reassigned")
|
|
@@ -22434,7 +22434,7 @@ function registerBeatPlanningTools(server, ctx, client) {
|
|
|
22434
22434
|
"Plan the implementation of a Beat Revision via a conversational turn. Uses the revision description and Beat notes as context. Use this during the planning or building stage to refine scope, explore implementation details, or assess readiness.",
|
|
22435
22435
|
{
|
|
22436
22436
|
revisionId: external_exports.string().describe("The revision ID to plan"),
|
|
22437
|
-
systemId: external_exports.string().describe("The
|
|
22437
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
22438
22438
|
message: external_exports.string().describe(
|
|
22439
22439
|
'Your planning message \u2014 e.g. "Review the revision scope", "What should we consider for the auth flow?", or "Does this cover the acceptance criteria?"'
|
|
22440
22440
|
),
|
|
@@ -22536,7 +22536,7 @@ ${d.rationale}${d.suggestions?.length ? `
|
|
|
22536
22536
|
function registerBeatQualityTools(server, ctx, client) {
|
|
22537
22537
|
const schema = {
|
|
22538
22538
|
beatId: external_exports.string().describe("The beat ID (e.g., TF-B-001)"),
|
|
22539
|
-
systemId: external_exports.string().describe("The
|
|
22539
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
22540
22540
|
wait: external_exports.boolean().optional().describe("If true, block until the check completes and return the scorecard inline. Default: false (returns taskId immediately).")
|
|
22541
22541
|
};
|
|
22542
22542
|
const handler = async ({ beatId, systemId, wait }) => {
|
|
@@ -22585,7 +22585,7 @@ function registerBeatReframeTools(server, ctx, client) {
|
|
|
22585
22585
|
"Reframe a Beat's title and description to meet business-outcome quality rules \u2014 outcome-first, plain English, non-technical audience. Returns a proposed rewrite for review.",
|
|
22586
22586
|
{
|
|
22587
22587
|
beatId: external_exports.string().describe("The beat ID (e.g., TF-B-001)"),
|
|
22588
|
-
systemId: external_exports.string().describe("The
|
|
22588
|
+
systemId: external_exports.string().describe("The system ID")
|
|
22589
22589
|
},
|
|
22590
22590
|
async ({ beatId, systemId }) => {
|
|
22591
22591
|
try {
|
|
@@ -23095,9 +23095,9 @@ function formatLayerDetail(layer) {
|
|
|
23095
23095
|
function registerBeatTools(server, ctx, client) {
|
|
23096
23096
|
server.tool(
|
|
23097
23097
|
"list_beats",
|
|
23098
|
-
"List beats in a
|
|
23098
|
+
"List beats in a system. Use offset/limit to paginate large result sets.",
|
|
23099
23099
|
{
|
|
23100
|
-
systemId: external_exports.string().describe("The
|
|
23100
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
23101
23101
|
offset: external_exports.coerce.number().int().min(0).default(0).describe("Number of beats to skip (for pagination)"),
|
|
23102
23102
|
limit: external_exports.coerce.number().int().min(1).max(500).default(100).describe("Max beats to return (default 100, max 500)"),
|
|
23103
23103
|
includeArchived: external_exports.boolean().optional().default(false).describe("Include archived and deprecated beats (excluded by default)")
|
|
@@ -23139,7 +23139,7 @@ function registerBeatTools(server, ctx, client) {
|
|
|
23139
23139
|
"Get the full decision lineage timeline for a beat (revisions, status changes, edits, proposals)",
|
|
23140
23140
|
{
|
|
23141
23141
|
beatId: external_exports.string().describe("The beat ID"),
|
|
23142
|
-
systemId: external_exports.string().optional().describe("
|
|
23142
|
+
systemId: external_exports.string().optional().describe("System ID (auto-resolved from beat if omitted)")
|
|
23143
23143
|
},
|
|
23144
23144
|
async ({ beatId, systemId }) => {
|
|
23145
23145
|
const beat = await fetchBeatInOrg(client, beatId, ctx.orgId);
|
|
@@ -23154,9 +23154,9 @@ function registerBeatTools(server, ctx, client) {
|
|
|
23154
23154
|
);
|
|
23155
23155
|
server.tool(
|
|
23156
23156
|
"create_beat",
|
|
23157
|
-
"Create a new beat in a
|
|
23157
|
+
"Create a new beat in a system. Title must be outcome-first (what changes for the user, not what we build). Description is the Beat Coda \u2014 second-person resolved expression of the capability (1-3 sentences). Avoid jargon and user-story format. Read harmonica://guidelines/beat-quality for full rules. Auto-generates beat ID if not provided.",
|
|
23158
23158
|
{
|
|
23159
|
-
systemId: external_exports.string().describe("The
|
|
23159
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
23160
23160
|
title: external_exports.string().describe('Beat title \u2014 outcome-first, e.g. "At-risk shipments screen used daily by Ops"'),
|
|
23161
23161
|
description: external_exports.string().optional().describe("Beat Coda \u2014 second-person resolved expression of what the capability looks like when complete (1-3 sentences)"),
|
|
23162
23162
|
tags: external_exports.array(external_exports.string()).optional().describe("Tags for categorization"),
|
|
@@ -23238,7 +23238,7 @@ ${formatBeatDetail(beat)}${similarityWarning}` }] };
|
|
|
23238
23238
|
maxConcurrentRevisions: external_exports.coerce.number().min(0).describe("Recommended max active revisions (0 = no cap)"),
|
|
23239
23239
|
allowOverlap: external_exports.boolean().describe("Whether overlapping work on this Beat is acceptable"),
|
|
23240
23240
|
scopeOverlapStrategy: external_exports.enum(["block", "warn", "allow"]).describe("Advisory only \u2014 how the UI/MCP should react when limits are exceeded")
|
|
23241
|
-
}).nullable().optional().describe("Per-Beat concurrency guidance (advisory, not a gate). Omit to leave unchanged; pass null to clear and use the
|
|
23241
|
+
}).nullable().optional().describe("Per-Beat concurrency guidance (advisory, not a gate). Omit to leave unchanged; pass null to clear and use the system default.")
|
|
23242
23242
|
},
|
|
23243
23243
|
async ({ beatId, changeSummary, ...changes }) => {
|
|
23244
23244
|
try {
|
|
@@ -23277,10 +23277,10 @@ ${formatBeatDetail(beat)}${similarityWarning}` }] };
|
|
|
23277
23277
|
);
|
|
23278
23278
|
server.tool(
|
|
23279
23279
|
"list_revisions",
|
|
23280
|
-
"List revisions for a
|
|
23280
|
+
"List revisions for a system, optionally filtered by binary status (`active` or `archived`). Archived revisions are excluded by default. Use beatId to scope results to a single beat.",
|
|
23281
23281
|
{
|
|
23282
|
-
systemId: external_exports.string().describe("The
|
|
23283
|
-
beatId: external_exports.string().optional().describe("Scope to a specific beat (omit for all
|
|
23282
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
23283
|
+
beatId: external_exports.string().optional().describe("Scope to a specific beat (omit for all system revisions)"),
|
|
23284
23284
|
status: external_exports.enum(["active", "archived"]).optional().describe("Filter by binary Revision status (default: all non-archived)"),
|
|
23285
23285
|
includeArchived: external_exports.boolean().optional().default(false).describe("Include archived revisions (excluded by default)")
|
|
23286
23286
|
},
|
|
@@ -23397,10 +23397,10 @@ var PlanVersionsIdempotencyError = class extends Error {
|
|
|
23397
23397
|
function registerBeatVersionTools(server, ctx, client) {
|
|
23398
23398
|
server.tool(
|
|
23399
23399
|
"list_beat_versions",
|
|
23400
|
-
"List Beat Versions for a Beat or
|
|
23400
|
+
"List Beat Versions for a Beat or System. Beat Versions are the shippable planning increments that advance a Beat toward its goal. Use beatId to scope to a specific Beat, or omit for all Beat Versions in the system. Status is binary (active | archived); by default excludes archived.",
|
|
23401
23401
|
{
|
|
23402
|
-
systemId: external_exports.string().describe("The
|
|
23403
|
-
beatId: external_exports.string().optional().describe("Filter to a specific Beat (omit for all Beat Versions in
|
|
23402
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
23403
|
+
beatId: external_exports.string().optional().describe("Filter to a specific Beat (omit for all Beat Versions in system)"),
|
|
23404
23404
|
status: external_exports.enum(BEAT_VERSION_STATUSES).optional().describe("Filter to a specific status (active | archived)"),
|
|
23405
23405
|
includeTerminal: external_exports.boolean().optional().describe("Include archived Beat Versions. Default: false.")
|
|
23406
23406
|
},
|
|
@@ -23672,10 +23672,10 @@ function registerBeatVersionTools(server, ctx, client) {
|
|
|
23672
23672
|
);
|
|
23673
23673
|
server.tool(
|
|
23674
23674
|
"relocate_beat_version",
|
|
23675
|
-
"Move a Beat Version from one parent Beat to another within the same
|
|
23675
|
+
"Move a Beat Version from one parent Beat to another within the same system, re-parenting all child Revisions and keeping every DynamoDB index consistent. Use when a Beat Version was planned under the wrong Beat or the scope of a Beat has been reorganized. Dry-run by default (confirm=false): shows what would change without writing. Pass confirm=true to execute. Blocked on released Drops by default \u2014 pass overrideReleasedDropLock=true to proceed (preserves Drop membership for audit trail).",
|
|
23676
23676
|
{
|
|
23677
23677
|
beatVersionId: external_exports.string().describe("The Beat Version ID to relocate (e.g., bv-abc123)"),
|
|
23678
|
-
targetBeatId: external_exports.string().describe("The Beat ID to relocate the Beat Version to (must be in the same
|
|
23678
|
+
targetBeatId: external_exports.string().describe("The Beat ID to relocate the Beat Version to (must be in the same system)"),
|
|
23679
23679
|
reason: external_exports.string().min(1).describe("Why this relocation is being made (recorded in audit trail)"),
|
|
23680
23680
|
confirm: external_exports.boolean().optional().describe("Set true to execute the relocation. Default false (dry-run describes the move)."),
|
|
23681
23681
|
overrideReleasedDropLock: external_exports.boolean().optional().describe("Allow relocation even when the Beat Version belongs to a released Drop (preserves Drop membership). Default false.")
|
|
@@ -23829,9 +23829,9 @@ function registerCheckTools(server, ctx, client) {
|
|
|
23829
23829
|
);
|
|
23830
23830
|
server.tool(
|
|
23831
23831
|
"list_checks",
|
|
23832
|
-
"List persisted checks for a
|
|
23832
|
+
"List persisted checks for a system, beat, beat version, or revision. Shows score trends over time. Filter by check type.",
|
|
23833
23833
|
{
|
|
23834
|
-
systemId: external_exports.string().describe("The
|
|
23834
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
23835
23835
|
beatId: external_exports.string().optional().describe("List checks for this specific beat"),
|
|
23836
23836
|
beatVersionId: external_exports.string().optional().describe("List checks for this specific beat version"),
|
|
23837
23837
|
revisionId: external_exports.string().optional().describe("List checks for this specific revision"),
|
|
@@ -23942,9 +23942,9 @@ function registerCheckTools(server, ctx, client) {
|
|
|
23942
23942
|
);
|
|
23943
23943
|
server.tool(
|
|
23944
23944
|
"list_latest_checks",
|
|
23945
|
-
"List the latest check per target (Beat, Beat Version, Revision) across a whole
|
|
23945
|
+
"List the latest check per target (Beat, Beat Version, Revision) across a whole system in one call \u2014 the most recent score of each type for each entity. Use this for an at-a-glance quality snapshot of every capability; use list_checks when you need the full history of one target.",
|
|
23946
23946
|
{
|
|
23947
|
-
systemId: external_exports.string().describe("The
|
|
23947
|
+
systemId: external_exports.string().describe("The system ID")
|
|
23948
23948
|
},
|
|
23949
23949
|
async ({ systemId }) => {
|
|
23950
23950
|
try {
|
|
@@ -23966,8 +23966,8 @@ function registerCheckTools(server, ctx, client) {
|
|
|
23966
23966
|
{
|
|
23967
23967
|
checkType: external_exports.enum(["beat_coda_quality", "beat_quality", "beat_version_quality", "plan_quality", "build_quality"]).describe("Type of check to run. beat_quality is the deprecated alias of beat_coda_quality. plan_quality is the deprecated alias of beat_version_quality."),
|
|
23968
23968
|
targetId: external_exports.string().describe("The target entity ID \u2014 a beatId for beat_coda_quality, or a Beat Version ID (bv-*) for beat_version_quality and build_quality"),
|
|
23969
|
-
systemId: external_exports.string().describe("The
|
|
23970
|
-
branch: external_exports.string().optional().describe("Override the git branch for code checks (default:
|
|
23969
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
23970
|
+
branch: external_exports.string().optional().describe("Override the git branch for code checks (default: system default branch)"),
|
|
23971
23971
|
localPath: external_exports.string().optional().describe("Absolute path to an already-cloned local copy of the repo \u2014 skips git clone entirely (useful for large repos or offline use)")
|
|
23972
23972
|
},
|
|
23973
23973
|
async ({ checkType, targetId, systemId, branch, localPath }) => {
|
|
@@ -24555,7 +24555,7 @@ function registerDropQualityTools(server, ctx, client) {
|
|
|
24555
24555
|
"Run a five-dimension coherence check on a Drop (Substantial, Harmonious, Clear, Focused, Strategically Aligned), graded LLM-only on the Drop's Beat Versions and their parent Beats/Projects/Codas. By default returns a taskId immediately \u2014 set wait=true to block and receive the full scorecard inline.",
|
|
24556
24556
|
{
|
|
24557
24557
|
dropId: external_exports.string().min(1).describe("The Drop ID (e.g. drop-abc123) to grade"),
|
|
24558
|
-
systemId: external_exports.string().min(1).describe("A
|
|
24558
|
+
systemId: external_exports.string().min(1).describe("A system within this Drop \u2014 the check record is attributed to it (Drops span systems, so the result is recorded under one member system)"),
|
|
24559
24559
|
wait: external_exports.boolean().optional().describe("Block until the check completes and return the scorecard inline. Default: false.")
|
|
24560
24560
|
},
|
|
24561
24561
|
async ({ dropId, systemId, wait }) => {
|
|
@@ -25004,7 +25004,7 @@ function registerEmbeddingTools(server, ctx, client) {
|
|
|
25004
25004
|
"Find Notes semantically similar to one or more Notes. Accepts a single Note ID or an array of Note IDs for batch duplicate detection. Results are grouped by source Note.",
|
|
25005
25005
|
{
|
|
25006
25006
|
noteId: external_exports.union([external_exports.string(), external_exports.array(external_exports.string())]).describe("Note ID or array of Note IDs to find similar notes for"),
|
|
25007
|
-
systemId: external_exports.string().describe("The
|
|
25007
|
+
systemId: external_exports.string().describe("The system ID the notes belong to"),
|
|
25008
25008
|
threshold: external_exports.coerce.number().min(0).max(1).optional().default(0.7).describe("Minimum similarity score (0-1). Default 0.7"),
|
|
25009
25009
|
limit: external_exports.coerce.number().int().min(1).max(50).optional().default(10).describe("Max results per source note. Default 10"),
|
|
25010
25010
|
includeArchived: external_exports.boolean().optional().default(false).describe("Include archived/deprecated notes in results (excluded by default)"),
|
|
@@ -25031,7 +25031,7 @@ function registerEmbeddingTools(server, ctx, client) {
|
|
|
25031
25031
|
"Find Beats semantically similar to a given Beat. Useful for detecting duplicates, dependencies, or related capabilities.",
|
|
25032
25032
|
{
|
|
25033
25033
|
beatId: external_exports.string().describe("The beat ID to find similar beats for"),
|
|
25034
|
-
systemId: external_exports.string().describe("The
|
|
25034
|
+
systemId: external_exports.string().describe("The system ID the beat belongs to"),
|
|
25035
25035
|
threshold: external_exports.coerce.number().min(0).max(1).optional().default(0.7).describe("Minimum similarity score (0-1). Default 0.7"),
|
|
25036
25036
|
limit: external_exports.coerce.number().int().min(1).max(50).optional().default(10).describe("Max results to return. Default 10"),
|
|
25037
25037
|
includeArchived: external_exports.boolean().optional().default(false).describe("Include archived/deprecated beats in results (excluded by default)")
|
|
@@ -25048,7 +25048,7 @@ function registerEmbeddingTools(server, ctx, client) {
|
|
|
25048
25048
|
"Find Beats semantically related to a given Note. Surfaces missing affectsBeats links and helps classify unassigned Notes.",
|
|
25049
25049
|
{
|
|
25050
25050
|
noteId: external_exports.string().describe("The note ID to find related beats for"),
|
|
25051
|
-
systemId: external_exports.string().describe("The
|
|
25051
|
+
systemId: external_exports.string().describe("The system ID the note belongs to"),
|
|
25052
25052
|
threshold: external_exports.coerce.number().min(0).max(1).optional().default(0.7).describe("Minimum similarity score (0-1). Default 0.7"),
|
|
25053
25053
|
limit: external_exports.coerce.number().int().min(1).max(50).optional().default(10).describe("Max results to return. Default 10")
|
|
25054
25054
|
},
|
|
@@ -25063,7 +25063,7 @@ function registerEmbeddingTools(server, ctx, client) {
|
|
|
25063
25063
|
"cluster_notes",
|
|
25064
25064
|
"Cluster semantically similar Notes using DBSCAN on vector embeddings. Returns clusters for review with member previews. Use this to discover natural groupings among notes and consolidate them under parent summary notes.",
|
|
25065
25065
|
{
|
|
25066
|
-
systemId: external_exports.string().describe("The
|
|
25066
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
25067
25067
|
threshold: external_exports.coerce.number().min(0).max(1).optional().default(0.75).describe("Cosine similarity threshold for clustering (0-1). Higher = tighter clusters. Default 0.75"),
|
|
25068
25068
|
minClusterSize: external_exports.coerce.number().int().min(2).optional().default(3).describe("Minimum notes to form a cluster. Default 3"),
|
|
25069
25069
|
includeLinked: external_exports.coerce.boolean().optional().default(false).describe("Include notes that already have dependsOnNotes links. Default false (excludes them). Set true for thematic grouping pass.")
|
|
@@ -25094,7 +25094,7 @@ ${members}`;
|
|
|
25094
25094
|
"consolidate_notes",
|
|
25095
25095
|
"Two-pass note consolidation: clusters notes via DBSCAN, then sends each cluster to an LLM for contextual analysis. Returns consolidation proposals (should these be grouped under a parent summary?) without modifying data. Use cluster_notes for a quick vector-only view; use this when ready to act on consolidation.",
|
|
25096
25096
|
{
|
|
25097
|
-
systemId: external_exports.string().describe("The
|
|
25097
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
25098
25098
|
threshold: external_exports.coerce.number().min(0).max(1).optional().default(0.65).describe("Cosine similarity threshold for clustering (0-1). Default 0.65"),
|
|
25099
25099
|
minClusterSize: external_exports.coerce.number().int().min(2).optional().default(2).describe("Minimum notes to form a cluster. Default 2"),
|
|
25100
25100
|
includeLinked: external_exports.coerce.boolean().optional().default(false).describe("Include notes that already have dependsOnNotes links. Default false.")
|
|
@@ -25821,9 +25821,9 @@ function formatNextActions(actions) {
|
|
|
25821
25821
|
function registerNextActionsTools(server, ctx, client) {
|
|
25822
25822
|
server.tool(
|
|
25823
25823
|
"get_next_actions",
|
|
25824
|
-
"Get prioritized list of recommended next actions for a
|
|
25824
|
+
"Get prioritized list of recommended next actions for a system. Analyzes Beats, Revisions, and Notes to surface the highest-priority work: P0 (urgent bugs) \u2192 P1 (deploy) \u2192 P2 (build) \u2192 P3 (plan) \u2192 P4 (compose) \u2192 P5 (maintenance).",
|
|
25825
25825
|
{
|
|
25826
|
-
systemId: external_exports.string().describe("The
|
|
25826
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
25827
25827
|
limit: external_exports.coerce.number().optional().default(10).describe("Max actions to return")
|
|
25828
25828
|
},
|
|
25829
25829
|
async ({ systemId, limit }) => {
|
|
@@ -25841,7 +25841,7 @@ function registerNextActionsTools(server, ctx, client) {
|
|
|
25841
25841
|
"list_triage_actions",
|
|
25842
25842
|
"List active triage actions from the ledger (open + acted). This is the stateful view of what needs attention \u2014 includes status tracking, task progress, and escalation state. Use this instead of get_next_actions when triage has been run.",
|
|
25843
25843
|
{
|
|
25844
|
-
systemId: external_exports.string().describe("The
|
|
25844
|
+
systemId: external_exports.string().describe("The system ID")
|
|
25845
25845
|
},
|
|
25846
25846
|
async ({ systemId }) => {
|
|
25847
25847
|
try {
|
|
@@ -25858,7 +25858,7 @@ function registerNextActionsTools(server, ctx, client) {
|
|
|
25858
25858
|
"dismiss_triage_action",
|
|
25859
25859
|
'Dismiss a triage action (human decides "not now"). The action will not be re-escalated until the underlying state changes.',
|
|
25860
25860
|
{
|
|
25861
|
-
systemId: external_exports.string().describe("The
|
|
25861
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
25862
25862
|
actionKey: external_exports.string().describe("The action key to dismiss (from list_triage_actions)")
|
|
25863
25863
|
},
|
|
25864
25864
|
async ({ systemId, actionKey }) => {
|
|
@@ -25905,6 +25905,126 @@ function formatTriageActions(actions) {
|
|
|
25905
25905
|
// ../../libs/harmonica-services/src/mcp/tools/note-element-tools.ts
|
|
25906
25906
|
var import_crypto3 = require("crypto");
|
|
25907
25907
|
|
|
25908
|
+
// ../../libs/harmonica-schemas/src/azure-marketplace.ts
|
|
25909
|
+
var AzureMarketplaceSubscriptionSchema = external_exports.object({
|
|
25910
|
+
id: external_exports.string(),
|
|
25911
|
+
publisherId: external_exports.string().optional(),
|
|
25912
|
+
offerId: external_exports.string().optional(),
|
|
25913
|
+
name: external_exports.string().optional(),
|
|
25914
|
+
saasSubscriptionStatus: external_exports.string().optional(),
|
|
25915
|
+
planId: external_exports.string().optional(),
|
|
25916
|
+
quantity: external_exports.number().optional(),
|
|
25917
|
+
beneficiary: external_exports.object({
|
|
25918
|
+
emailId: external_exports.string().optional(),
|
|
25919
|
+
objectId: external_exports.string().optional(),
|
|
25920
|
+
tenantId: external_exports.string().optional()
|
|
25921
|
+
}).optional(),
|
|
25922
|
+
purchaser: external_exports.object({
|
|
25923
|
+
emailId: external_exports.string().optional(),
|
|
25924
|
+
objectId: external_exports.string().optional(),
|
|
25925
|
+
tenantId: external_exports.string().optional()
|
|
25926
|
+
}).optional()
|
|
25927
|
+
});
|
|
25928
|
+
var AzureSubscribedSchema = external_exports.object({
|
|
25929
|
+
action: external_exports.literal("Subscribe"),
|
|
25930
|
+
// Non-blank, not merely non-empty. A bare z.string() accepts "", which would
|
|
25931
|
+
// derive the slug "az-" — 3 chars, trailing dash, invalid under the repository
|
|
25932
|
+
// slug invariant. And .min(1) alone still admits " ", which normalizes to
|
|
25933
|
+
// nothing and falls through to the hash fallback, quietly provisioning an org
|
|
25934
|
+
// under a hashed slug for input that is plainly garbage. Reject it at the
|
|
25935
|
+
// boundary instead.
|
|
25936
|
+
subscriptionId: external_exports.string().min(1).refine((v) => v.trim().length > 0, {
|
|
25937
|
+
message: "subscriptionId must not be blank"
|
|
25938
|
+
}),
|
|
25939
|
+
offerId: external_exports.string(),
|
|
25940
|
+
planId: external_exports.string(),
|
|
25941
|
+
quantity: external_exports.number().optional(),
|
|
25942
|
+
timeStamp: external_exports.string(),
|
|
25943
|
+
operationId: external_exports.string(),
|
|
25944
|
+
subscription: AzureMarketplaceSubscriptionSchema
|
|
25945
|
+
});
|
|
25946
|
+
var AzureUnsubscribedSchema = external_exports.object({
|
|
25947
|
+
action: external_exports.literal("Unsubscribe"),
|
|
25948
|
+
// Non-blank, not merely non-empty. A bare z.string() accepts "", which would
|
|
25949
|
+
// derive the slug "az-" — 3 chars, trailing dash, invalid under the repository
|
|
25950
|
+
// slug invariant. And .min(1) alone still admits " ", which normalizes to
|
|
25951
|
+
// nothing and falls through to the hash fallback, quietly provisioning an org
|
|
25952
|
+
// under a hashed slug for input that is plainly garbage. Reject it at the
|
|
25953
|
+
// boundary instead.
|
|
25954
|
+
subscriptionId: external_exports.string().min(1).refine((v) => v.trim().length > 0, {
|
|
25955
|
+
message: "subscriptionId must not be blank"
|
|
25956
|
+
}),
|
|
25957
|
+
offerId: external_exports.string(),
|
|
25958
|
+
planId: external_exports.string(),
|
|
25959
|
+
timeStamp: external_exports.string(),
|
|
25960
|
+
operationId: external_exports.string(),
|
|
25961
|
+
subscription: AzureMarketplaceSubscriptionSchema
|
|
25962
|
+
});
|
|
25963
|
+
var AzureChangePlanSchema = external_exports.object({
|
|
25964
|
+
action: external_exports.literal("ChangePlan"),
|
|
25965
|
+
// Non-blank, not merely non-empty. A bare z.string() accepts "", which would
|
|
25966
|
+
// derive the slug "az-" — 3 chars, trailing dash, invalid under the repository
|
|
25967
|
+
// slug invariant. And .min(1) alone still admits " ", which normalizes to
|
|
25968
|
+
// nothing and falls through to the hash fallback, quietly provisioning an org
|
|
25969
|
+
// under a hashed slug for input that is plainly garbage. Reject it at the
|
|
25970
|
+
// boundary instead.
|
|
25971
|
+
subscriptionId: external_exports.string().min(1).refine((v) => v.trim().length > 0, {
|
|
25972
|
+
message: "subscriptionId must not be blank"
|
|
25973
|
+
}),
|
|
25974
|
+
offerId: external_exports.string(),
|
|
25975
|
+
planId: external_exports.string(),
|
|
25976
|
+
timeStamp: external_exports.string(),
|
|
25977
|
+
operationId: external_exports.string(),
|
|
25978
|
+
subscription: AzureMarketplaceSubscriptionSchema
|
|
25979
|
+
});
|
|
25980
|
+
var AzureSuspendSchema = external_exports.object({
|
|
25981
|
+
action: external_exports.literal("Suspend"),
|
|
25982
|
+
// Non-blank, not merely non-empty. A bare z.string() accepts "", which would
|
|
25983
|
+
// derive the slug "az-" — 3 chars, trailing dash, invalid under the repository
|
|
25984
|
+
// slug invariant. And .min(1) alone still admits " ", which normalizes to
|
|
25985
|
+
// nothing and falls through to the hash fallback, quietly provisioning an org
|
|
25986
|
+
// under a hashed slug for input that is plainly garbage. Reject it at the
|
|
25987
|
+
// boundary instead.
|
|
25988
|
+
subscriptionId: external_exports.string().min(1).refine((v) => v.trim().length > 0, {
|
|
25989
|
+
message: "subscriptionId must not be blank"
|
|
25990
|
+
}),
|
|
25991
|
+
offerId: external_exports.string(),
|
|
25992
|
+
planId: external_exports.string(),
|
|
25993
|
+
timeStamp: external_exports.string(),
|
|
25994
|
+
operationId: external_exports.string(),
|
|
25995
|
+
subscription: AzureMarketplaceSubscriptionSchema
|
|
25996
|
+
});
|
|
25997
|
+
var AzureReinstateSchema = external_exports.object({
|
|
25998
|
+
action: external_exports.literal("Reinstate"),
|
|
25999
|
+
// Non-blank, not merely non-empty. A bare z.string() accepts "", which would
|
|
26000
|
+
// derive the slug "az-" — 3 chars, trailing dash, invalid under the repository
|
|
26001
|
+
// slug invariant. And .min(1) alone still admits " ", which normalizes to
|
|
26002
|
+
// nothing and falls through to the hash fallback, quietly provisioning an org
|
|
26003
|
+
// under a hashed slug for input that is plainly garbage. Reject it at the
|
|
26004
|
+
// boundary instead.
|
|
26005
|
+
subscriptionId: external_exports.string().min(1).refine((v) => v.trim().length > 0, {
|
|
26006
|
+
message: "subscriptionId must not be blank"
|
|
26007
|
+
}),
|
|
26008
|
+
offerId: external_exports.string(),
|
|
26009
|
+
planId: external_exports.string(),
|
|
26010
|
+
timeStamp: external_exports.string(),
|
|
26011
|
+
operationId: external_exports.string(),
|
|
26012
|
+
subscription: AzureMarketplaceSubscriptionSchema
|
|
26013
|
+
});
|
|
26014
|
+
var AzureMarketplaceWebhookEventSchema = external_exports.discriminatedUnion("action", [
|
|
26015
|
+
AzureSubscribedSchema,
|
|
26016
|
+
AzureUnsubscribedSchema,
|
|
26017
|
+
AzureChangePlanSchema,
|
|
26018
|
+
AzureSuspendSchema,
|
|
26019
|
+
AzureReinstateSchema
|
|
26020
|
+
]);
|
|
26021
|
+
var AZURE_MARKETPLACE_WEBHOOK_ACTIONS = AzureMarketplaceWebhookEventSchema.options.map(
|
|
26022
|
+
(o) => o.shape.action.value
|
|
26023
|
+
);
|
|
26024
|
+
var AzureMarketplaceActivateBodySchema = external_exports.object({
|
|
26025
|
+
token: external_exports.string().min(1)
|
|
26026
|
+
});
|
|
26027
|
+
|
|
25908
26028
|
// ../../libs/harmonica-schemas/src/compose-beat-versions.ts
|
|
25909
26029
|
var BeatVersionDraftSchema = external_exports.object({
|
|
25910
26030
|
title: external_exports.string().min(1).max(300),
|
|
@@ -26504,7 +26624,7 @@ var CheckApiSchema = external_exports.object({
|
|
|
26504
26624
|
createdAt: external_exports.string(),
|
|
26505
26625
|
updatedAt: external_exports.string()
|
|
26506
26626
|
}).passthrough();
|
|
26507
|
-
var
|
|
26627
|
+
var SystemCheckApiSchema = external_exports.object({
|
|
26508
26628
|
checkId: external_exports.string(),
|
|
26509
26629
|
checkType: CheckTypeSchema,
|
|
26510
26630
|
targetType: CheckTargetTypeSchema,
|
|
@@ -26520,7 +26640,7 @@ var ProjectCheckApiSchema = external_exports.object({
|
|
|
26520
26640
|
dimensions: external_exports.array(CheckDimensionScoreSchema).optional()
|
|
26521
26641
|
}).passthrough();
|
|
26522
26642
|
var CheckResponseSchema = external_exports.object({ check: CheckApiSchema }).passthrough();
|
|
26523
|
-
var ChecksResponseSchema = external_exports.object({ checks: external_exports.array(
|
|
26643
|
+
var ChecksResponseSchema = external_exports.object({ checks: external_exports.array(SystemCheckApiSchema), nextCursor: external_exports.string().optional() }).passthrough();
|
|
26524
26644
|
var TaskStatusSchema2 = external_exports.enum(["pending", "running", "completed", "failed"]);
|
|
26525
26645
|
var TaskProgressSchema = external_exports.object({
|
|
26526
26646
|
current: external_exports.number(),
|
|
@@ -27273,10 +27393,10 @@ ${formatDeliveryPolicy(
|
|
|
27273
27393
|
function registerNoteTools(server, ctx, client) {
|
|
27274
27394
|
server.tool(
|
|
27275
27395
|
"list_notes",
|
|
27276
|
-
"List Notes for a
|
|
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 project-wide results.",
|
|
27277
27397
|
{
|
|
27278
|
-
systemId: external_exports.string().describe("The
|
|
27279
|
-
beatId: external_exports.string().optional().describe("Scope to a specific beat (omit for all
|
|
27398
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
27399
|
+
beatId: external_exports.string().optional().describe("Scope to a specific beat (omit for all system notes)"),
|
|
27280
27400
|
noteType: external_exports.union([external_exports.enum(NOTE_TYPE_VALUES), external_exports.array(external_exports.enum(NOTE_TYPE_VALUES)).min(1)]).optional().describe('Filter by note type \u2014 single value or array for multi-select (e.g. ["constraint", "assumption"])'),
|
|
27281
27401
|
status: external_exports.enum(NOTE_STATUS_VALUES).optional().describe("Filter by status"),
|
|
27282
27402
|
revisionId: external_exports.string().optional().describe("Filter to notes scoped to a specific revision"),
|
|
@@ -27441,9 +27561,9 @@ function registerNoteTools(server, ctx, client) {
|
|
|
27441
27561
|
);
|
|
27442
27562
|
server.tool(
|
|
27443
27563
|
"list_documents",
|
|
27444
|
-
"List uploaded documents for a
|
|
27564
|
+
"List uploaded documents for a system with processing status, filename, child note count, and AI summary. Use get_note with a document note ID for full details.",
|
|
27445
27565
|
{
|
|
27446
|
-
systemId: external_exports.string().describe("The
|
|
27566
|
+
systemId: external_exports.string().describe("The system ID")
|
|
27447
27567
|
},
|
|
27448
27568
|
async ({ systemId }) => {
|
|
27449
27569
|
await assertProjectInOrg(client, systemId, ctx.orgId);
|
|
@@ -27459,7 +27579,7 @@ function registerNoteTools(server, ctx, client) {
|
|
|
27459
27579
|
"get_note",
|
|
27460
27580
|
"Get full details of a single Note by ID",
|
|
27461
27581
|
{
|
|
27462
|
-
systemId: external_exports.string().optional().describe("The
|
|
27582
|
+
systemId: external_exports.string().optional().describe("The system ID (for access control). Provide systemId or orgId, not both."),
|
|
27463
27583
|
orgId: external_exports.string().optional().describe("The org ID (for org-level notes). Provide orgId or systemId, not both."),
|
|
27464
27584
|
noteId: external_exports.string().describe("The note ID")
|
|
27465
27585
|
},
|
|
@@ -27496,9 +27616,9 @@ function registerNoteTools(server, ctx, client) {
|
|
|
27496
27616
|
);
|
|
27497
27617
|
server.tool(
|
|
27498
27618
|
"create_note",
|
|
27499
|
-
"Create a new Note. Provide exactly one of systemId, teamspaceId, movementId, or none (org-level): systemId scopes the note to a
|
|
27619
|
+
"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.",
|
|
27500
27620
|
{
|
|
27501
|
-
systemId: external_exports.string().optional().describe("The
|
|
27621
|
+
systemId: external_exports.string().optional().describe("The system ID (omit for teamspace-, movement-, or org-level note)"),
|
|
27502
27622
|
teamspaceId: external_exports.string().optional().describe("The teamspace ID (omit for project-, movement-, or org-level note)"),
|
|
27503
27623
|
movementId: external_exports.string().min(1).optional().describe("The Movement ID (omit for project-, teamspace-, or org-level note)"),
|
|
27504
27624
|
noteType: external_exports.enum(NOTE_TYPE_VALUES).describe("The type of note"),
|
|
@@ -27597,7 +27717,7 @@ ${text}` }] };
|
|
|
27597
27717
|
"update_note",
|
|
27598
27718
|
"Update a Note (status, content, response, etc.). humanAssignee and agentAssignee are independent fields \u2014 both can be set simultaneously (a note can have a human owner and an agent collaborator). Set either to null to clear it.",
|
|
27599
27719
|
{
|
|
27600
|
-
systemId: external_exports.string().optional().describe("The
|
|
27720
|
+
systemId: external_exports.string().optional().describe("The system ID (for access control). Provide systemId or orgId, not both."),
|
|
27601
27721
|
orgId: external_exports.string().optional().describe("The org ID (for org-level notes). Provide orgId or systemId, not both."),
|
|
27602
27722
|
noteId: external_exports.string().describe("The note ID to update"),
|
|
27603
27723
|
noteType: external_exports.enum(NOTE_TYPE_VALUES).optional().describe("Reclassify the note type (e.g. assumption \u2192 guidance)"),
|
|
@@ -27679,7 +27799,7 @@ ${text}` }] };
|
|
|
27679
27799
|
"bulk_update_notes",
|
|
27680
27800
|
"Update multiple Notes in one call, applying the same fields to all. More efficient than calling update_note N times. Returns updated notes and any per-note failures.",
|
|
27681
27801
|
{
|
|
27682
|
-
systemId: external_exports.string().describe("The
|
|
27802
|
+
systemId: external_exports.string().describe("The system ID (for access control)"),
|
|
27683
27803
|
noteIds: external_exports.array(external_exports.string()).min(1).max(100).describe("Note IDs to update (max 100 per call)"),
|
|
27684
27804
|
noteType: external_exports.enum(NOTE_TYPE_VALUES).optional().describe("Reclassify all notes to this type"),
|
|
27685
27805
|
status: external_exports.enum(NOTE_STATUS_VALUES).optional().describe("New status for all notes"),
|
|
@@ -27721,7 +27841,7 @@ ${text}` }] };
|
|
|
27721
27841
|
"reassign_note",
|
|
27722
27842
|
"Reassign a misattributed note to a different beat (with audit trail)",
|
|
27723
27843
|
{
|
|
27724
|
-
systemId: external_exports.string().describe("The
|
|
27844
|
+
systemId: external_exports.string().describe("The system ID (for access control)"),
|
|
27725
27845
|
noteId: external_exports.string().describe("The note ID to reassign"),
|
|
27726
27846
|
targetBeatId: external_exports.string().describe("The beat ID to move the note to"),
|
|
27727
27847
|
targetRevisionId: external_exports.string().optional().describe("Optional revision ID to scope the note to"),
|
|
@@ -27745,7 +27865,7 @@ ${text}` }] };
|
|
|
27745
27865
|
"remove_note",
|
|
27746
27866
|
"Soft-remove a misattributed note by dismissing it (with audit trail)",
|
|
27747
27867
|
{
|
|
27748
|
-
systemId: external_exports.string().min(1).describe("The
|
|
27868
|
+
systemId: external_exports.string().min(1).describe("The system ID (for access control)"),
|
|
27749
27869
|
noteId: external_exports.string().min(1).describe("The note ID to remove"),
|
|
27750
27870
|
reason: external_exports.string().min(1).max(500).optional().describe('Why this note is being removed (defaults to "Removed via remove_note")')
|
|
27751
27871
|
},
|
|
@@ -27772,7 +27892,7 @@ ${text}` }] };
|
|
|
27772
27892
|
"dismiss_document",
|
|
27773
27893
|
"Soft-remove an uploaded document by dismissing it \u2014 it will no longer appear in list_documents output. Only works on document-type notes; use remove_note for non-document notes.",
|
|
27774
27894
|
{
|
|
27775
|
-
systemId: external_exports.string().min(1).describe("The
|
|
27895
|
+
systemId: external_exports.string().min(1).describe("The system ID (for access control)"),
|
|
27776
27896
|
noteId: external_exports.string().min(1).describe("The document note ID to dismiss"),
|
|
27777
27897
|
reason: external_exports.string().min(1).max(500).optional().describe('Why this document is being dismissed (defaults to "Dismissed via dismiss_document")')
|
|
27778
27898
|
},
|
|
@@ -27805,7 +27925,7 @@ ${text}` }] };
|
|
|
27805
27925
|
"list_key_assumptions",
|
|
27806
27926
|
"Get key assumptions sorted by criticality (highest risk first)",
|
|
27807
27927
|
{
|
|
27808
|
-
systemId: external_exports.string().describe("The
|
|
27928
|
+
systemId: external_exports.string().describe("The system ID")
|
|
27809
27929
|
},
|
|
27810
27930
|
async ({ systemId }) => {
|
|
27811
27931
|
await assertProjectInOrg(client, systemId, ctx.orgId);
|
|
@@ -27888,7 +28008,7 @@ function formatTree(node, depth = 0) {
|
|
|
27888
28008
|
function registerNotebookTools(server, ctx, client) {
|
|
27889
28009
|
server.tool(
|
|
27890
28010
|
"create_notebook",
|
|
27891
|
-
"Create a new Notebook in the configured organization. Optionally bind it to one or more scopes (org, teamspace, or
|
|
28011
|
+
"Create a new Notebook in the configured organization. Optionally bind it to one or more scopes (org, teamspace, or system) at creation.",
|
|
27892
28012
|
{
|
|
27893
28013
|
title: external_exports.string().min(1).max(300).describe("Notebook title (1\u2013300 characters)"),
|
|
27894
28014
|
description: external_exports.string().max(2e4).optional().describe("Optional description (max 20 000 characters)"),
|
|
@@ -28065,7 +28185,7 @@ ${formatTree(tree.root)}` }] };
|
|
|
28065
28185
|
);
|
|
28066
28186
|
server.tool(
|
|
28067
28187
|
"add_notebook_collection",
|
|
28068
|
-
"Add a live-collection section to a Notebook page. Unlike a normal section, its members are resolved from a live query at read time (never hand-picked), so it stays current on its own as notes are created, edited, or retired. v1 supports the
|
|
28188
|
+
"Add a live-collection section to a Notebook page. Unlike a normal section, its members are resolved from a live query at read time (never hand-picked), so it stays current on its own as notes are created, edited, or retired. v1 supports the system Decision Log: every decision note in a system (including beat-scoped), newest first. Attach under a page (defaults to the notebook root).",
|
|
28069
28189
|
{
|
|
28070
28190
|
notebookId: external_exports.string().describe("The Notebook ID"),
|
|
28071
28191
|
heading: external_exports.string().min(1).max(200).describe('Section label, e.g. "Decision Log"'),
|
|
@@ -28288,7 +28408,7 @@ ${scopeText}` }] };
|
|
|
28288
28408
|
);
|
|
28289
28409
|
server.tool(
|
|
28290
28410
|
"list_notebooks",
|
|
28291
|
-
"List Notebooks reachable from a scope (org, teamspace, or
|
|
28411
|
+
"List Notebooks reachable from a scope (org, teamspace, or system). Returns all notebooks bound to that scope.",
|
|
28292
28412
|
{
|
|
28293
28413
|
scopeType: external_exports.enum(SCOPE_TYPE_VALUES).describe("Scope type \u2014 org, teamspace, or project"),
|
|
28294
28414
|
scopeId: external_exports.string().min(1).describe("ID of the scope entity"),
|
|
@@ -28499,27 +28619,27 @@ function registerOnboardingTools(server, ctx, client) {
|
|
|
28499
28619
|
server.tool(
|
|
28500
28620
|
"draft_onboarding_beats",
|
|
28501
28621
|
[
|
|
28502
|
-
"Generate an initial Beat structure for a newly created
|
|
28503
|
-
"Call this after create_teamspace_onboarding_batch to draft 3\u20135 Beats based on the
|
|
28622
|
+
"Generate an initial Beat structure for a newly created system.",
|
|
28623
|
+
"Call this after create_teamspace_onboarding_batch to draft 3\u20135 Beats based on the system context.",
|
|
28504
28624
|
"Returns Beat suggestions with titles, descriptions, and any Maya recommendations to convert a suggestion to a Note instead.",
|
|
28505
28625
|
"The PM reviews and confirms \u2014 use create_beat for each approved Beat, create_note for any Note conversions."
|
|
28506
28626
|
].join(" "),
|
|
28507
28627
|
{
|
|
28508
|
-
systemId: external_exports.string().describe("The newly created
|
|
28509
|
-
|
|
28628
|
+
systemId: external_exports.string().describe("The newly created system ID"),
|
|
28629
|
+
systemTitle: external_exports.string().describe("The system title"),
|
|
28510
28630
|
projectDescription: external_exports.string().optional().describe("Discovery context: pain points, goals, and constraints summary to inform the Beat structure"),
|
|
28511
28631
|
analysisJson: external_exports.string().optional().describe("JSON-serialized DiscoveryAnalysis from initiate_teamspace_onboarding. Pass this to produce Beats grounded in the actual discovery data.")
|
|
28512
28632
|
},
|
|
28513
|
-
async ({ systemId,
|
|
28633
|
+
async ({ systemId, systemTitle, projectDescription, analysisJson }) => {
|
|
28514
28634
|
await assertProjectInOrg(client, systemId, ctx.orgId);
|
|
28515
|
-
const result = await client.draftOnboardingBeats(systemId, {
|
|
28635
|
+
const result = await client.draftOnboardingBeats(systemId, { systemTitle, projectDescription, analysisJson });
|
|
28516
28636
|
if (!result.suggestions || result.suggestions.length === 0) {
|
|
28517
28637
|
return {
|
|
28518
28638
|
content: [{ type: "text", text: "Failed to generate Beat suggestions. Try providing more project context." }]
|
|
28519
28639
|
};
|
|
28520
28640
|
}
|
|
28521
28641
|
const lines = [
|
|
28522
|
-
`## Beat Draft for "${
|
|
28642
|
+
`## Beat Draft for "${systemTitle}" (${result.suggestions.length} suggestions)`,
|
|
28523
28643
|
"",
|
|
28524
28644
|
...result.suggestions.flatMap((s, i) => {
|
|
28525
28645
|
const sug = s;
|
|
@@ -28816,7 +28936,7 @@ function registerOrganizationTools(server, ctx, client) {
|
|
|
28816
28936
|
if (result.error) {
|
|
28817
28937
|
return { content: [{ type: "text", text: result.error }], isError: true };
|
|
28818
28938
|
}
|
|
28819
|
-
const transferred = result.
|
|
28939
|
+
const transferred = result.system;
|
|
28820
28940
|
if (!transferred) {
|
|
28821
28941
|
return { content: [{ type: "text", text: "Transfer succeeded but system data was not returned." }], isError: true };
|
|
28822
28942
|
}
|
|
@@ -28946,11 +29066,11 @@ ${d.rationale}${d.suggestions?.length ? `
|
|
|
28946
29066
|
function registerPlanQualityTools(server, ctx, client) {
|
|
28947
29067
|
const schema = {
|
|
28948
29068
|
beatVersionId: external_exports.string().describe("The Beat Version ID (e.g., bv-abc123). beat_version_quality targets Beat Versions only."),
|
|
28949
|
-
systemId: external_exports.string().describe("The
|
|
29069
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
28950
29070
|
// The completeness dimension probes the codebase, so this tool accepts the
|
|
28951
29071
|
// same repo overrides as run_check — without them the probe could only ever
|
|
28952
29072
|
// read the default branch from this surface.
|
|
28953
|
-
branch: external_exports.string().optional().describe("Override the git branch the completeness dimension probes (default: the branch of an open child Revision, else the
|
|
29073
|
+
branch: external_exports.string().optional().describe("Override the git branch the completeness dimension probes (default: the branch of an open child Revision, else the system default branch)"),
|
|
28954
29074
|
localPath: external_exports.string().optional().describe("Absolute path to an already-cloned local copy of the repo \u2014 the completeness probe reads it instead of cloning"),
|
|
28955
29075
|
wait: external_exports.boolean().optional().describe("If true, block until the check completes and return the scorecard inline. Default: false (returns taskId immediately).")
|
|
28956
29076
|
};
|
|
@@ -29103,9 +29223,9 @@ function formatConsolidationResult(primaryId, primary, archivedBeatIds, notesRea
|
|
|
29103
29223
|
function registerPortfolioCoherenceTools(server, ctx, client) {
|
|
29104
29224
|
server.tool(
|
|
29105
29225
|
"check_portfolio_coherence",
|
|
29106
|
-
"Run a portfolio coherence check on a
|
|
29226
|
+
"Run a portfolio coherence check on a system. Clusters Beats by semantic similarity to surface fragmentation (merge candidates) and checks what fraction of Beats name an outcome their authoriser would recognise. By default returns a taskId immediately \u2014 set wait=true to block and receive the full report inline.",
|
|
29107
29227
|
{
|
|
29108
|
-
systemId: external_exports.string().min(1).describe("The
|
|
29228
|
+
systemId: external_exports.string().min(1).describe("The system ID"),
|
|
29109
29229
|
wait: external_exports.boolean().optional().describe("Block until the check completes and return the report inline. Default: false.")
|
|
29110
29230
|
},
|
|
29111
29231
|
async ({ systemId, wait }) => {
|
|
@@ -29137,7 +29257,7 @@ function registerPortfolioCoherenceTools(server, ctx, client) {
|
|
|
29137
29257
|
"consolidate_beats",
|
|
29138
29258
|
"Consolidate a fragmented Beat cluster \u2014 identified by check_portfolio_coherence \u2014 into a single VP-level capability. By default (confirm omitted or false) returns a dry-run preview: surviving Beat, Beats to archive, Notes to reassign, and any in-flight Beat Versions. Set confirm=true to execute the merge.",
|
|
29139
29259
|
{
|
|
29140
|
-
systemId: external_exports.string().min(1).describe("The
|
|
29260
|
+
systemId: external_exports.string().min(1).describe("The system ID \u2014 all beatIds must belong to this system"),
|
|
29141
29261
|
beatIds: external_exports.array(external_exports.string().min(1)).min(2).max(50).describe("All Beat IDs in the cluster (including the one that will survive)"),
|
|
29142
29262
|
primaryBeatId: external_exports.string().min(1).optional().describe("Beat ID that survives \u2014 defaults to beatIds[0] if omitted"),
|
|
29143
29263
|
rationale: external_exports.string().max(2e3).optional().describe("Why these Beats are being merged \u2014 auto-generated if omitted"),
|
|
@@ -29321,14 +29441,14 @@ This is a deliberate choice by whoever configured the System, and \`confirm: tru
|
|
|
29321
29441
|
function registerRevisionLifecycleTools(server, ctx, client) {
|
|
29322
29442
|
server.tool(
|
|
29323
29443
|
"create_revision",
|
|
29324
|
-
"Create a new revision on a Beat. A Revision's canonical status starts `active`; PR progression is tracked separately on `scm.state` (`draft` \u2192 `open` \u2192 `merged` / `closed`). Environment progression (`in_staging`, `ready_for_production`, `live`) is tracked on the parent Beat Version, not the Revision. `beatVersionId` is optional \u2014 omit it for hotfixes, dep bumps, or other operational fixes that don't belong to a planning increment. Orphan Revisions (no BV) must carry their own `description` since there's no BV context to inherit. `baseRevisionId` stacks this Revision's PR/session checkout on another Revision's branch instead of the
|
|
29444
|
+
"Create a new revision on a Beat. A Revision's canonical status starts `active`; PR progression is tracked separately on `scm.state` (`draft` \u2192 `open` \u2192 `merged` / `closed`). Environment progression (`in_staging`, `ready_for_production`, `live`) is tracked on the parent Beat Version, not the Revision. `beatVersionId` is optional \u2014 omit it for hotfixes, dep bumps, or other operational fixes that don't belong to a planning increment. Orphan Revisions (no BV) must carry their own `description` since there's no BV context to inherit. `baseRevisionId` stacks this Revision's PR/session checkout on another Revision's branch instead of the system default \u2014 for GitHub stacked PRs, must reference a Revision in the same system (validated server-side). Use this to add revisions alongside existing ones \u2014 no idempotency guard. AFTER creating a revision you intend to work on, call `create_claim` on it before writing any code \u2014 the claim signals to other agents/humans that the Revision is actively being worked, preventing duplicate work \u2014 and `release_claim` when you finish or hand off.",
|
|
29325
29445
|
{
|
|
29326
29446
|
beatId: external_exports.string().describe("The beat ID to create the revision on"),
|
|
29327
29447
|
title: external_exports.string().describe("Title for this revision"),
|
|
29328
29448
|
description: external_exports.string().describe("What this revision delivers. Required when beatVersionId is omitted (the description is the audit-trail floor for orphan Revisions)."),
|
|
29329
29449
|
changeSummary: external_exports.string().describe("Brief summary of the change"),
|
|
29330
29450
|
beatVersionId: external_exports.string().min(1).optional().describe("Beat Version ID to associate this revision with. Omit for hotfixes / orphan changes that don't fit a planning increment."),
|
|
29331
|
-
baseRevisionId: external_exports.string().min(1).optional().describe("Existing Revision (same
|
|
29451
|
+
baseRevisionId: external_exports.string().min(1).optional().describe("Existing Revision (same system) to stack this one on top of \u2014 its PR and agent session will target that Revision's branch instead of the system default (GitHub stacked PRs)."),
|
|
29332
29452
|
tags: external_exports.array(external_exports.string()).optional().describe("Tags for categorization"),
|
|
29333
29453
|
priority: external_exports.coerce.number().optional().describe("Priority (lower = higher priority)"),
|
|
29334
29454
|
estimatedEffort: external_exports.string().optional().describe("Estimated effort (e.g., S, M, L, XL)"),
|
|
@@ -29449,10 +29569,13 @@ function registerRevisionLifecycleTools(server, ctx, client) {
|
|
|
29449
29569
|
return { content: [{ type: "text", text: `Beat Version not found: "${beatVersionId}"` }], isError: true };
|
|
29450
29570
|
}
|
|
29451
29571
|
const bvSystemId = bv.systemId ?? bv.projectId;
|
|
29452
|
-
|
|
29453
|
-
if (!bvSystemId || !revSystemId) {
|
|
29572
|
+
if (!bvSystemId) {
|
|
29454
29573
|
return { content: [{ type: "text", text: `Beat Version "${beatVersionId}" has no system identifier \u2014 record may be corrupt.` }], isError: true };
|
|
29455
29574
|
}
|
|
29575
|
+
const revSystemId = revision.systemId ?? revision.projectId;
|
|
29576
|
+
if (!revSystemId) {
|
|
29577
|
+
return { content: [{ type: "text", text: `Revision "${revisionId}" has no system identifier \u2014 record may be corrupt.` }], isError: true };
|
|
29578
|
+
}
|
|
29456
29579
|
if (bv.beatId !== revision.beatId || bvSystemId !== revSystemId) {
|
|
29457
29580
|
return { content: [{ type: "text", text: `Beat Version "${beatVersionId}" belongs to a different Beat.` }], isError: true };
|
|
29458
29581
|
}
|
|
@@ -29595,7 +29718,7 @@ Accepts the full PR metadata (number, url, branch, state, optional mergeSha). Fi
|
|
|
29595
29718
|
);
|
|
29596
29719
|
server.tool(
|
|
29597
29720
|
"create_pr_for_revision",
|
|
29598
|
-
"Open a Harmonica-initiated DRAFT pull request for a revision and link it back via revision.scm. Cuts a branch (agent/rev-<short>-<slug>), bootstraps it with an empty commit, opens a draft PR whose body starts with the `Harmonica: rev-<uuid>` marker, then records the PR on the revision. Rejects if the revision already has a linked PR, or if the
|
|
29721
|
+
"Open a Harmonica-initiated DRAFT pull request for a revision and link it back via revision.scm. Cuts a branch (agent/rev-<short>-<slug>), bootstraps it with an empty commit, opens a draft PR whose body starts with the `Harmonica: rev-<uuid>` marker, then records the PR on the revision. Rejects if the revision already has a linked PR, or if the system has no repo configured. Dry-run by default \u2014 call with `confirm: true` to actually create the branch and PR. Leaves the revision in `draft`; transition it to `open` when the PR is marked ready for review.",
|
|
29599
29722
|
{
|
|
29600
29723
|
revisionId: external_exports.string().describe("The revision ID (e.g., rev-abc123)"),
|
|
29601
29724
|
confirm: external_exports.boolean().optional().describe("Set true to create the branch + draft PR. Omitted/false performs a dry-run that only describes what would happen \u2014 no GitHub or DB writes.")
|
|
@@ -29885,7 +30008,7 @@ function registerRevisionQualityTools(server, ctx, client) {
|
|
|
29885
30008
|
"Run a five-dimension PR-readiness check on a Revision (Scoped, Traceable, Testable, Review-ready, Non-duplicating). Advisory only \u2014 no lifecycle transition or creation path gates on this score. By default returns a jobId immediately (fire-and-forget) \u2014 use get_job_status or list_checks to retrieve results. Set wait=true to block until the check completes and receive the scorecard inline. WARNING: wait=true holds the MCP session open for 30\u201360s \u2014 for bulk operations, omit wait and poll get_job_status separately.",
|
|
29886
30009
|
{
|
|
29887
30010
|
revisionId: external_exports.string().describe("The Revision ID (e.g., rev-abc123). revision_quality targets Revisions only."),
|
|
29888
|
-
systemId: external_exports.string().describe("The
|
|
30011
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
29889
30012
|
wait: external_exports.boolean().optional().describe("If true, block until the check completes and return the scorecard inline. Default: false (returns taskId immediately).")
|
|
29890
30013
|
},
|
|
29891
30014
|
async ({ revisionId, systemId, wait }) => {
|
|
@@ -30446,8 +30569,8 @@ function registerSubscriptionTools(server, ctx, client) {
|
|
|
30446
30569
|
"Follow a Project, Beat, or Revision to receive notifications when it changes. You are auto-subscribed to things you own \u2014 use this to follow additional entities.",
|
|
30447
30570
|
{
|
|
30448
30571
|
entityType: external_exports.enum(ENTITY_TYPES).describe("Type of entity to follow"),
|
|
30449
|
-
entityId: external_exports.string().describe("The entity ID (
|
|
30450
|
-
systemId: external_exports.string().describe("The
|
|
30572
|
+
entityId: external_exports.string().describe("The entity ID (system ID, beat ID, or revision ID)"),
|
|
30573
|
+
systemId: external_exports.string().describe("The system ID (for access control)")
|
|
30451
30574
|
},
|
|
30452
30575
|
async ({ entityType, entityId, systemId }) => {
|
|
30453
30576
|
try {
|
|
@@ -30491,7 +30614,7 @@ function registerSubscriptionTools(server, ctx, client) {
|
|
|
30491
30614
|
);
|
|
30492
30615
|
server.tool(
|
|
30493
30616
|
"list_subscriptions",
|
|
30494
|
-
"List entities you are currently following. Optionally filter by entity type (
|
|
30617
|
+
"List entities you are currently following. Optionally filter by entity type (system, beat, revision).",
|
|
30495
30618
|
{
|
|
30496
30619
|
entityType: external_exports.enum(ENTITY_TYPES).optional().describe("Filter by entity type")
|
|
30497
30620
|
},
|
|
@@ -30603,7 +30726,7 @@ function registerProjectTools(server, ctx, client) {
|
|
|
30603
30726
|
};
|
|
30604
30727
|
server.tool(
|
|
30605
30728
|
"list_systems",
|
|
30606
|
-
"List all systems
|
|
30729
|
+
"List all systems in the configured organization",
|
|
30607
30730
|
{
|
|
30608
30731
|
teamspaceId: external_exports.string().optional().describe("Filter to systems belonging to a specific teamspace. Empty or whitespace-only treated as no filter.")
|
|
30609
30732
|
},
|
|
@@ -31104,9 +31227,9 @@ function registerValueVelocityTools(server, ctx, client) {
|
|
|
31104
31227
|
);
|
|
31105
31228
|
server.tool(
|
|
31106
31229
|
"propose_enablement_edges",
|
|
31107
|
-
'Propose directed enablement edges for a
|
|
31230
|
+
'Propose directed enablement edges for a system \u2014 "Beat A accelerates Beat B". The LLM analyzes system Beats and proposes which ones unlock or accelerate others. Only proposed edges are created; a human must confirm before they affect Value Velocity scores. Pass beatId to scope the pass to edges FROM one Beat \u2014 strongly recommended on a large portfolio, where an unscoped pass can exceed the request timeout. If you already know the edge you want, skip proposing and use create_enablement_edge instead.',
|
|
31108
31231
|
{
|
|
31109
|
-
systemId: external_exports.string().describe("The
|
|
31232
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
31110
31233
|
beatId: external_exports.string().min(1).optional().describe("Scope the pass to edges FROM this Beat. Omit for a whole-project pass (slow on large portfolios).")
|
|
31111
31234
|
},
|
|
31112
31235
|
async ({ systemId, beatId }) => {
|
|
@@ -31492,9 +31615,9 @@ ${JSON.stringify(task.result, null, 2)}
|
|
|
31492
31615
|
);
|
|
31493
31616
|
server.tool(
|
|
31494
31617
|
"list_tasks",
|
|
31495
|
-
"DEPRECATED: use `list_jobs`. List background jobs for a
|
|
31618
|
+
"DEPRECATED: use `list_jobs`. List background jobs for a system with optional status filter.",
|
|
31496
31619
|
{
|
|
31497
|
-
systemId: external_exports.string().describe("The
|
|
31620
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
31498
31621
|
status: external_exports.enum(TASK_STATUSES).optional().describe("Filter by status"),
|
|
31499
31622
|
limit: external_exports.coerce.number().optional().default(20).describe("Max number of jobs to return")
|
|
31500
31623
|
},
|
|
@@ -31550,9 +31673,9 @@ ${JSON.stringify(task.result, null, 2)}
|
|
|
31550
31673
|
);
|
|
31551
31674
|
server.tool(
|
|
31552
31675
|
"list_jobs",
|
|
31553
|
-
"List background jobs for a
|
|
31676
|
+
"List background jobs for a system with optional status filter",
|
|
31554
31677
|
{
|
|
31555
|
-
systemId: external_exports.string().describe("The
|
|
31678
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
31556
31679
|
status: external_exports.enum(TASK_STATUSES).optional().describe("Filter by status"),
|
|
31557
31680
|
limit: external_exports.coerce.number().optional().default(20).describe("Max number of jobs to return")
|
|
31558
31681
|
},
|
|
@@ -31576,7 +31699,7 @@ ${JSON.stringify(task.result, null, 2)}
|
|
|
31576
31699
|
"draft_coda",
|
|
31577
31700
|
"Generate and apply a Coda (description) for a Beat that has a title but no description. Uses project context, sibling Beats, related Notes, and codebase grep to write a resolved expression of the capability. The Coda is applied directly to the Beat, making it eligible for plan_beat_versions once a beat_quality check passes. An activity is logged so the Beat owner can review and edit. Returns a job ID \u2014 use get_job_status to track progress.",
|
|
31578
31701
|
{
|
|
31579
|
-
systemId: external_exports.string().describe("The
|
|
31702
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
31580
31703
|
beatId: external_exports.string().describe("The beat ID (must have a title but no description)")
|
|
31581
31704
|
},
|
|
31582
31705
|
async ({ systemId, beatId }) => {
|
|
@@ -31609,7 +31732,7 @@ ${JSON.stringify(task.result, null, 2)}
|
|
|
31609
31732
|
"validate_assumptions",
|
|
31610
31733
|
"Validate unvalidated assumption Notes against the codebase. Checks if assumptions are confirmed (validated), contradicted (invalidated), or have insufficient evidence (unvalidated). Low-criticality assumptions are auto-resolved; high-criticality are flagged for human review. Returns a job ID \u2014 use get_job_status to track progress.",
|
|
31611
31734
|
{
|
|
31612
|
-
systemId: external_exports.string().describe("The
|
|
31735
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
31613
31736
|
noteIds: external_exports.array(external_exports.string()).optional().describe("Specific assumption note IDs to validate. If omitted, validates all unvalidated assumptions.")
|
|
31614
31737
|
},
|
|
31615
31738
|
async ({ systemId, noteIds }) => {
|
|
@@ -31641,9 +31764,9 @@ ${JSON.stringify(task.result, null, 2)}
|
|
|
31641
31764
|
);
|
|
31642
31765
|
server.tool(
|
|
31643
31766
|
"start_session",
|
|
31644
|
-
'Start an agent session from a free-form message \u2014 like opening a Claude Code conversation pointed at your
|
|
31767
|
+
'Start an agent session from a free-form message \u2014 like opening a Claude Code conversation pointed at your system. The message is the only instruction: describe what you want ("investigate why login fails", "implement revision rev-abc123", "what does the auth flow do?") and the agent resolves any entity references itself and does whatever the work needs \u2014 investigate and report findings, or change code and open a PR. A findings-only result with no PR is a valid outcome. Returns a job ID \u2014 use get_job_status to track progress. Requires agent sessions enabled on the system.',
|
|
31645
31768
|
{
|
|
31646
|
-
systemId: external_exports.string().min(1).describe("The
|
|
31769
|
+
systemId: external_exports.string().min(1).describe("The system ID \u2014 the trusted scope the session is rooted at"),
|
|
31647
31770
|
message: external_exports.string().min(1).describe("Free-form first message describing what the session should do"),
|
|
31648
31771
|
revisionId: external_exports.string().min(1).optional().describe("Optional Revision ID (rev-<uuid>). When provided, the Worker routes to the typed implementation session path (prepareRevisionImplementationSession), enabling file hint generation and richer session context. Omit for investigation, planning, or freeform sessions.")
|
|
31649
31772
|
},
|
|
@@ -31681,7 +31804,7 @@ ${JSON.stringify(task.result, null, 2)}
|
|
|
31681
31804
|
"plan_revision_batch",
|
|
31682
31805
|
"Autonomously generate an implementation plan for planning Revisions. If revisionIds are omitted, discovers all unplanned planning Revisions and plans them all. Uses codebase-aware agent sessions when available, LLM-only fallback otherwise. Returns a job ID \u2014 use get_job_status to track progress.",
|
|
31683
31806
|
{
|
|
31684
|
-
systemId: external_exports.string().describe("The
|
|
31807
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
31685
31808
|
revisionIds: external_exports.array(external_exports.string()).optional().describe("Specific revision IDs to plan. If omitted, auto-discovers all unplanned planning revisions.")
|
|
31686
31809
|
},
|
|
31687
31810
|
async ({ systemId, revisionIds }) => {
|
|
@@ -31712,9 +31835,9 @@ ${JSON.stringify(task.result, null, 2)}
|
|
|
31712
31835
|
);
|
|
31713
31836
|
server.tool(
|
|
31714
31837
|
"run_triage",
|
|
31715
|
-
"Run the autonomous triage loop for a
|
|
31838
|
+
"Run the autonomous triage loop for a system. Analyzes next actions, auto-executes safe actions (draft_coda, plan_revision_batch), and escalates items that need human judgment. Requires agentCapabilities.triage enabled on the system. Returns a job ID \u2014 use get_job_status to track progress.",
|
|
31716
31839
|
{
|
|
31717
|
-
systemId: external_exports.string().describe("The
|
|
31840
|
+
systemId: external_exports.string().describe("The system ID")
|
|
31718
31841
|
},
|
|
31719
31842
|
async ({ systemId }) => {
|
|
31720
31843
|
try {
|
|
@@ -31757,7 +31880,7 @@ ${JSON.stringify(task.result, null, 2)}
|
|
|
31757
31880
|
"Returns a job ID \u2014 use `get_job_status` to track progress."
|
|
31758
31881
|
].join("\n"),
|
|
31759
31882
|
{
|
|
31760
|
-
systemId: external_exports.string().describe("The
|
|
31883
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
31761
31884
|
content: external_exports.string().describe('Document content \u2014 plain text (default) or base64-encoded binary (when encoding is "base64")'),
|
|
31762
31885
|
filename: external_exports.string().optional().default("document.txt").describe('Original filename with extension (e.g., "sow.pdf", "spec.docx"). Used for format detection in binary mode.'),
|
|
31763
31886
|
encoding: external_exports.enum(["base64"]).optional().describe('Set to "base64" when submitting binary files (DOCX, XLSX, PPTX, PDF). Omit for plain text.')
|
|
@@ -32207,13 +32330,13 @@ function createHttpClient(config2) {
|
|
|
32207
32330
|
`/api/organizations/${encodeURIComponent(sourceOrgId)}/transfer-project`,
|
|
32208
32331
|
{ systemId: projectId, targetOrgId }
|
|
32209
32332
|
);
|
|
32210
|
-
const
|
|
32211
|
-
...result.
|
|
32212
|
-
systemId: result.
|
|
32213
|
-
title: result.
|
|
32214
|
-
orgId: result.
|
|
32333
|
+
const system = result?.system ? {
|
|
32334
|
+
...result.system,
|
|
32335
|
+
systemId: result.system.id ?? result.system.systemId ?? result.system.projectId,
|
|
32336
|
+
title: result.system.name ?? result.system.title,
|
|
32337
|
+
orgId: result.system.organizationId ?? result.system.orgId
|
|
32215
32338
|
} : void 0;
|
|
32216
|
-
return { success: result?.success ?? false,
|
|
32339
|
+
return { success: result?.success ?? false, system };
|
|
32217
32340
|
} catch (err) {
|
|
32218
32341
|
if (err instanceof Error) return { success: false, error: err.message };
|
|
32219
32342
|
return { success: false, error: String(err) };
|
|
@@ -34194,7 +34317,7 @@ function loadConfig() {
|
|
|
34194
34317
|
};
|
|
34195
34318
|
}
|
|
34196
34319
|
async function main() {
|
|
34197
|
-
console.error(`[harmonica-mcp] v${"3.
|
|
34320
|
+
console.error(`[harmonica-mcp] v${"3.8.0"} starting\u2026`);
|
|
34198
34321
|
const config2 = loadConfig();
|
|
34199
34322
|
const client = createHttpClient({
|
|
34200
34323
|
apiBaseUrl: config2.apiBaseUrl,
|