@codazen/harmonica-mcp 3.7.2 → 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 +103 -103
- 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 }) => {
|
|
@@ -26624,7 +26624,7 @@ var CheckApiSchema = external_exports.object({
|
|
|
26624
26624
|
createdAt: external_exports.string(),
|
|
26625
26625
|
updatedAt: external_exports.string()
|
|
26626
26626
|
}).passthrough();
|
|
26627
|
-
var
|
|
26627
|
+
var SystemCheckApiSchema = external_exports.object({
|
|
26628
26628
|
checkId: external_exports.string(),
|
|
26629
26629
|
checkType: CheckTypeSchema,
|
|
26630
26630
|
targetType: CheckTargetTypeSchema,
|
|
@@ -26640,7 +26640,7 @@ var ProjectCheckApiSchema = external_exports.object({
|
|
|
26640
26640
|
dimensions: external_exports.array(CheckDimensionScoreSchema).optional()
|
|
26641
26641
|
}).passthrough();
|
|
26642
26642
|
var CheckResponseSchema = external_exports.object({ check: CheckApiSchema }).passthrough();
|
|
26643
|
-
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();
|
|
26644
26644
|
var TaskStatusSchema2 = external_exports.enum(["pending", "running", "completed", "failed"]);
|
|
26645
26645
|
var TaskProgressSchema = external_exports.object({
|
|
26646
26646
|
current: external_exports.number(),
|
|
@@ -27393,10 +27393,10 @@ ${formatDeliveryPolicy(
|
|
|
27393
27393
|
function registerNoteTools(server, ctx, client) {
|
|
27394
27394
|
server.tool(
|
|
27395
27395
|
"list_notes",
|
|
27396
|
-
"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.",
|
|
27397
27397
|
{
|
|
27398
|
-
systemId: external_exports.string().describe("The
|
|
27399
|
-
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)"),
|
|
27400
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"])'),
|
|
27401
27401
|
status: external_exports.enum(NOTE_STATUS_VALUES).optional().describe("Filter by status"),
|
|
27402
27402
|
revisionId: external_exports.string().optional().describe("Filter to notes scoped to a specific revision"),
|
|
@@ -27561,9 +27561,9 @@ function registerNoteTools(server, ctx, client) {
|
|
|
27561
27561
|
);
|
|
27562
27562
|
server.tool(
|
|
27563
27563
|
"list_documents",
|
|
27564
|
-
"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.",
|
|
27565
27565
|
{
|
|
27566
|
-
systemId: external_exports.string().describe("The
|
|
27566
|
+
systemId: external_exports.string().describe("The system ID")
|
|
27567
27567
|
},
|
|
27568
27568
|
async ({ systemId }) => {
|
|
27569
27569
|
await assertProjectInOrg(client, systemId, ctx.orgId);
|
|
@@ -27579,7 +27579,7 @@ function registerNoteTools(server, ctx, client) {
|
|
|
27579
27579
|
"get_note",
|
|
27580
27580
|
"Get full details of a single Note by ID",
|
|
27581
27581
|
{
|
|
27582
|
-
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."),
|
|
27583
27583
|
orgId: external_exports.string().optional().describe("The org ID (for org-level notes). Provide orgId or systemId, not both."),
|
|
27584
27584
|
noteId: external_exports.string().describe("The note ID")
|
|
27585
27585
|
},
|
|
@@ -27616,9 +27616,9 @@ function registerNoteTools(server, ctx, client) {
|
|
|
27616
27616
|
);
|
|
27617
27617
|
server.tool(
|
|
27618
27618
|
"create_note",
|
|
27619
|
-
"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.",
|
|
27620
27620
|
{
|
|
27621
|
-
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)"),
|
|
27622
27622
|
teamspaceId: external_exports.string().optional().describe("The teamspace ID (omit for project-, movement-, or org-level note)"),
|
|
27623
27623
|
movementId: external_exports.string().min(1).optional().describe("The Movement ID (omit for project-, teamspace-, or org-level note)"),
|
|
27624
27624
|
noteType: external_exports.enum(NOTE_TYPE_VALUES).describe("The type of note"),
|
|
@@ -27717,7 +27717,7 @@ ${text}` }] };
|
|
|
27717
27717
|
"update_note",
|
|
27718
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.",
|
|
27719
27719
|
{
|
|
27720
|
-
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."),
|
|
27721
27721
|
orgId: external_exports.string().optional().describe("The org ID (for org-level notes). Provide orgId or systemId, not both."),
|
|
27722
27722
|
noteId: external_exports.string().describe("The note ID to update"),
|
|
27723
27723
|
noteType: external_exports.enum(NOTE_TYPE_VALUES).optional().describe("Reclassify the note type (e.g. assumption \u2192 guidance)"),
|
|
@@ -27799,7 +27799,7 @@ ${text}` }] };
|
|
|
27799
27799
|
"bulk_update_notes",
|
|
27800
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.",
|
|
27801
27801
|
{
|
|
27802
|
-
systemId: external_exports.string().describe("The
|
|
27802
|
+
systemId: external_exports.string().describe("The system ID (for access control)"),
|
|
27803
27803
|
noteIds: external_exports.array(external_exports.string()).min(1).max(100).describe("Note IDs to update (max 100 per call)"),
|
|
27804
27804
|
noteType: external_exports.enum(NOTE_TYPE_VALUES).optional().describe("Reclassify all notes to this type"),
|
|
27805
27805
|
status: external_exports.enum(NOTE_STATUS_VALUES).optional().describe("New status for all notes"),
|
|
@@ -27841,7 +27841,7 @@ ${text}` }] };
|
|
|
27841
27841
|
"reassign_note",
|
|
27842
27842
|
"Reassign a misattributed note to a different beat (with audit trail)",
|
|
27843
27843
|
{
|
|
27844
|
-
systemId: external_exports.string().describe("The
|
|
27844
|
+
systemId: external_exports.string().describe("The system ID (for access control)"),
|
|
27845
27845
|
noteId: external_exports.string().describe("The note ID to reassign"),
|
|
27846
27846
|
targetBeatId: external_exports.string().describe("The beat ID to move the note to"),
|
|
27847
27847
|
targetRevisionId: external_exports.string().optional().describe("Optional revision ID to scope the note to"),
|
|
@@ -27865,7 +27865,7 @@ ${text}` }] };
|
|
|
27865
27865
|
"remove_note",
|
|
27866
27866
|
"Soft-remove a misattributed note by dismissing it (with audit trail)",
|
|
27867
27867
|
{
|
|
27868
|
-
systemId: external_exports.string().min(1).describe("The
|
|
27868
|
+
systemId: external_exports.string().min(1).describe("The system ID (for access control)"),
|
|
27869
27869
|
noteId: external_exports.string().min(1).describe("The note ID to remove"),
|
|
27870
27870
|
reason: external_exports.string().min(1).max(500).optional().describe('Why this note is being removed (defaults to "Removed via remove_note")')
|
|
27871
27871
|
},
|
|
@@ -27892,7 +27892,7 @@ ${text}` }] };
|
|
|
27892
27892
|
"dismiss_document",
|
|
27893
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.",
|
|
27894
27894
|
{
|
|
27895
|
-
systemId: external_exports.string().min(1).describe("The
|
|
27895
|
+
systemId: external_exports.string().min(1).describe("The system ID (for access control)"),
|
|
27896
27896
|
noteId: external_exports.string().min(1).describe("The document note ID to dismiss"),
|
|
27897
27897
|
reason: external_exports.string().min(1).max(500).optional().describe('Why this document is being dismissed (defaults to "Dismissed via dismiss_document")')
|
|
27898
27898
|
},
|
|
@@ -27925,7 +27925,7 @@ ${text}` }] };
|
|
|
27925
27925
|
"list_key_assumptions",
|
|
27926
27926
|
"Get key assumptions sorted by criticality (highest risk first)",
|
|
27927
27927
|
{
|
|
27928
|
-
systemId: external_exports.string().describe("The
|
|
27928
|
+
systemId: external_exports.string().describe("The system ID")
|
|
27929
27929
|
},
|
|
27930
27930
|
async ({ systemId }) => {
|
|
27931
27931
|
await assertProjectInOrg(client, systemId, ctx.orgId);
|
|
@@ -28008,7 +28008,7 @@ function formatTree(node, depth = 0) {
|
|
|
28008
28008
|
function registerNotebookTools(server, ctx, client) {
|
|
28009
28009
|
server.tool(
|
|
28010
28010
|
"create_notebook",
|
|
28011
|
-
"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.",
|
|
28012
28012
|
{
|
|
28013
28013
|
title: external_exports.string().min(1).max(300).describe("Notebook title (1\u2013300 characters)"),
|
|
28014
28014
|
description: external_exports.string().max(2e4).optional().describe("Optional description (max 20 000 characters)"),
|
|
@@ -28185,7 +28185,7 @@ ${formatTree(tree.root)}` }] };
|
|
|
28185
28185
|
);
|
|
28186
28186
|
server.tool(
|
|
28187
28187
|
"add_notebook_collection",
|
|
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
|
|
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).",
|
|
28189
28189
|
{
|
|
28190
28190
|
notebookId: external_exports.string().describe("The Notebook ID"),
|
|
28191
28191
|
heading: external_exports.string().min(1).max(200).describe('Section label, e.g. "Decision Log"'),
|
|
@@ -28408,7 +28408,7 @@ ${scopeText}` }] };
|
|
|
28408
28408
|
);
|
|
28409
28409
|
server.tool(
|
|
28410
28410
|
"list_notebooks",
|
|
28411
|
-
"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.",
|
|
28412
28412
|
{
|
|
28413
28413
|
scopeType: external_exports.enum(SCOPE_TYPE_VALUES).describe("Scope type \u2014 org, teamspace, or project"),
|
|
28414
28414
|
scopeId: external_exports.string().min(1).describe("ID of the scope entity"),
|
|
@@ -28619,27 +28619,27 @@ function registerOnboardingTools(server, ctx, client) {
|
|
|
28619
28619
|
server.tool(
|
|
28620
28620
|
"draft_onboarding_beats",
|
|
28621
28621
|
[
|
|
28622
|
-
"Generate an initial Beat structure for a newly created
|
|
28623
|
-
"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.",
|
|
28624
28624
|
"Returns Beat suggestions with titles, descriptions, and any Maya recommendations to convert a suggestion to a Note instead.",
|
|
28625
28625
|
"The PM reviews and confirms \u2014 use create_beat for each approved Beat, create_note for any Note conversions."
|
|
28626
28626
|
].join(" "),
|
|
28627
28627
|
{
|
|
28628
|
-
systemId: external_exports.string().describe("The newly created
|
|
28629
|
-
|
|
28628
|
+
systemId: external_exports.string().describe("The newly created system ID"),
|
|
28629
|
+
systemTitle: external_exports.string().describe("The system title"),
|
|
28630
28630
|
projectDescription: external_exports.string().optional().describe("Discovery context: pain points, goals, and constraints summary to inform the Beat structure"),
|
|
28631
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.")
|
|
28632
28632
|
},
|
|
28633
|
-
async ({ systemId,
|
|
28633
|
+
async ({ systemId, systemTitle, projectDescription, analysisJson }) => {
|
|
28634
28634
|
await assertProjectInOrg(client, systemId, ctx.orgId);
|
|
28635
|
-
const result = await client.draftOnboardingBeats(systemId, {
|
|
28635
|
+
const result = await client.draftOnboardingBeats(systemId, { systemTitle, projectDescription, analysisJson });
|
|
28636
28636
|
if (!result.suggestions || result.suggestions.length === 0) {
|
|
28637
28637
|
return {
|
|
28638
28638
|
content: [{ type: "text", text: "Failed to generate Beat suggestions. Try providing more project context." }]
|
|
28639
28639
|
};
|
|
28640
28640
|
}
|
|
28641
28641
|
const lines = [
|
|
28642
|
-
`## Beat Draft for "${
|
|
28642
|
+
`## Beat Draft for "${systemTitle}" (${result.suggestions.length} suggestions)`,
|
|
28643
28643
|
"",
|
|
28644
28644
|
...result.suggestions.flatMap((s, i) => {
|
|
28645
28645
|
const sug = s;
|
|
@@ -28936,7 +28936,7 @@ function registerOrganizationTools(server, ctx, client) {
|
|
|
28936
28936
|
if (result.error) {
|
|
28937
28937
|
return { content: [{ type: "text", text: result.error }], isError: true };
|
|
28938
28938
|
}
|
|
28939
|
-
const transferred = result.
|
|
28939
|
+
const transferred = result.system;
|
|
28940
28940
|
if (!transferred) {
|
|
28941
28941
|
return { content: [{ type: "text", text: "Transfer succeeded but system data was not returned." }], isError: true };
|
|
28942
28942
|
}
|
|
@@ -29066,11 +29066,11 @@ ${d.rationale}${d.suggestions?.length ? `
|
|
|
29066
29066
|
function registerPlanQualityTools(server, ctx, client) {
|
|
29067
29067
|
const schema = {
|
|
29068
29068
|
beatVersionId: external_exports.string().describe("The Beat Version ID (e.g., bv-abc123). beat_version_quality targets Beat Versions only."),
|
|
29069
|
-
systemId: external_exports.string().describe("The
|
|
29069
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
29070
29070
|
// The completeness dimension probes the codebase, so this tool accepts the
|
|
29071
29071
|
// same repo overrides as run_check — without them the probe could only ever
|
|
29072
29072
|
// read the default branch from this surface.
|
|
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
|
|
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)"),
|
|
29074
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"),
|
|
29075
29075
|
wait: external_exports.boolean().optional().describe("If true, block until the check completes and return the scorecard inline. Default: false (returns taskId immediately).")
|
|
29076
29076
|
};
|
|
@@ -29223,9 +29223,9 @@ function formatConsolidationResult(primaryId, primary, archivedBeatIds, notesRea
|
|
|
29223
29223
|
function registerPortfolioCoherenceTools(server, ctx, client) {
|
|
29224
29224
|
server.tool(
|
|
29225
29225
|
"check_portfolio_coherence",
|
|
29226
|
-
"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.",
|
|
29227
29227
|
{
|
|
29228
|
-
systemId: external_exports.string().min(1).describe("The
|
|
29228
|
+
systemId: external_exports.string().min(1).describe("The system ID"),
|
|
29229
29229
|
wait: external_exports.boolean().optional().describe("Block until the check completes and return the report inline. Default: false.")
|
|
29230
29230
|
},
|
|
29231
29231
|
async ({ systemId, wait }) => {
|
|
@@ -29257,7 +29257,7 @@ function registerPortfolioCoherenceTools(server, ctx, client) {
|
|
|
29257
29257
|
"consolidate_beats",
|
|
29258
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.",
|
|
29259
29259
|
{
|
|
29260
|
-
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"),
|
|
29261
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)"),
|
|
29262
29262
|
primaryBeatId: external_exports.string().min(1).optional().describe("Beat ID that survives \u2014 defaults to beatIds[0] if omitted"),
|
|
29263
29263
|
rationale: external_exports.string().max(2e3).optional().describe("Why these Beats are being merged \u2014 auto-generated if omitted"),
|
|
@@ -29441,14 +29441,14 @@ This is a deliberate choice by whoever configured the System, and \`confirm: tru
|
|
|
29441
29441
|
function registerRevisionLifecycleTools(server, ctx, client) {
|
|
29442
29442
|
server.tool(
|
|
29443
29443
|
"create_revision",
|
|
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
|
|
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.",
|
|
29445
29445
|
{
|
|
29446
29446
|
beatId: external_exports.string().describe("The beat ID to create the revision on"),
|
|
29447
29447
|
title: external_exports.string().describe("Title for this revision"),
|
|
29448
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)."),
|
|
29449
29449
|
changeSummary: external_exports.string().describe("Brief summary of the change"),
|
|
29450
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."),
|
|
29451
|
-
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)."),
|
|
29452
29452
|
tags: external_exports.array(external_exports.string()).optional().describe("Tags for categorization"),
|
|
29453
29453
|
priority: external_exports.coerce.number().optional().describe("Priority (lower = higher priority)"),
|
|
29454
29454
|
estimatedEffort: external_exports.string().optional().describe("Estimated effort (e.g., S, M, L, XL)"),
|
|
@@ -29718,7 +29718,7 @@ Accepts the full PR metadata (number, url, branch, state, optional mergeSha). Fi
|
|
|
29718
29718
|
);
|
|
29719
29719
|
server.tool(
|
|
29720
29720
|
"create_pr_for_revision",
|
|
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
|
|
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.",
|
|
29722
29722
|
{
|
|
29723
29723
|
revisionId: external_exports.string().describe("The revision ID (e.g., rev-abc123)"),
|
|
29724
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.")
|
|
@@ -30008,7 +30008,7 @@ function registerRevisionQualityTools(server, ctx, client) {
|
|
|
30008
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.",
|
|
30009
30009
|
{
|
|
30010
30010
|
revisionId: external_exports.string().describe("The Revision ID (e.g., rev-abc123). revision_quality targets Revisions only."),
|
|
30011
|
-
systemId: external_exports.string().describe("The
|
|
30011
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
30012
30012
|
wait: external_exports.boolean().optional().describe("If true, block until the check completes and return the scorecard inline. Default: false (returns taskId immediately).")
|
|
30013
30013
|
},
|
|
30014
30014
|
async ({ revisionId, systemId, wait }) => {
|
|
@@ -30569,8 +30569,8 @@ function registerSubscriptionTools(server, ctx, client) {
|
|
|
30569
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.",
|
|
30570
30570
|
{
|
|
30571
30571
|
entityType: external_exports.enum(ENTITY_TYPES).describe("Type of entity to follow"),
|
|
30572
|
-
entityId: external_exports.string().describe("The entity ID (
|
|
30573
|
-
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)")
|
|
30574
30574
|
},
|
|
30575
30575
|
async ({ entityType, entityId, systemId }) => {
|
|
30576
30576
|
try {
|
|
@@ -30614,7 +30614,7 @@ function registerSubscriptionTools(server, ctx, client) {
|
|
|
30614
30614
|
);
|
|
30615
30615
|
server.tool(
|
|
30616
30616
|
"list_subscriptions",
|
|
30617
|
-
"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).",
|
|
30618
30618
|
{
|
|
30619
30619
|
entityType: external_exports.enum(ENTITY_TYPES).optional().describe("Filter by entity type")
|
|
30620
30620
|
},
|
|
@@ -30726,7 +30726,7 @@ function registerProjectTools(server, ctx, client) {
|
|
|
30726
30726
|
};
|
|
30727
30727
|
server.tool(
|
|
30728
30728
|
"list_systems",
|
|
30729
|
-
"List all systems
|
|
30729
|
+
"List all systems in the configured organization",
|
|
30730
30730
|
{
|
|
30731
30731
|
teamspaceId: external_exports.string().optional().describe("Filter to systems belonging to a specific teamspace. Empty or whitespace-only treated as no filter.")
|
|
30732
30732
|
},
|
|
@@ -31227,9 +31227,9 @@ function registerValueVelocityTools(server, ctx, client) {
|
|
|
31227
31227
|
);
|
|
31228
31228
|
server.tool(
|
|
31229
31229
|
"propose_enablement_edges",
|
|
31230
|
-
'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.',
|
|
31231
31231
|
{
|
|
31232
|
-
systemId: external_exports.string().describe("The
|
|
31232
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
31233
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).")
|
|
31234
31234
|
},
|
|
31235
31235
|
async ({ systemId, beatId }) => {
|
|
@@ -31615,9 +31615,9 @@ ${JSON.stringify(task.result, null, 2)}
|
|
|
31615
31615
|
);
|
|
31616
31616
|
server.tool(
|
|
31617
31617
|
"list_tasks",
|
|
31618
|
-
"DEPRECATED: use `list_jobs`. List background jobs for a
|
|
31618
|
+
"DEPRECATED: use `list_jobs`. List background jobs for a system with optional status filter.",
|
|
31619
31619
|
{
|
|
31620
|
-
systemId: external_exports.string().describe("The
|
|
31620
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
31621
31621
|
status: external_exports.enum(TASK_STATUSES).optional().describe("Filter by status"),
|
|
31622
31622
|
limit: external_exports.coerce.number().optional().default(20).describe("Max number of jobs to return")
|
|
31623
31623
|
},
|
|
@@ -31673,9 +31673,9 @@ ${JSON.stringify(task.result, null, 2)}
|
|
|
31673
31673
|
);
|
|
31674
31674
|
server.tool(
|
|
31675
31675
|
"list_jobs",
|
|
31676
|
-
"List background jobs for a
|
|
31676
|
+
"List background jobs for a system with optional status filter",
|
|
31677
31677
|
{
|
|
31678
|
-
systemId: external_exports.string().describe("The
|
|
31678
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
31679
31679
|
status: external_exports.enum(TASK_STATUSES).optional().describe("Filter by status"),
|
|
31680
31680
|
limit: external_exports.coerce.number().optional().default(20).describe("Max number of jobs to return")
|
|
31681
31681
|
},
|
|
@@ -31699,7 +31699,7 @@ ${JSON.stringify(task.result, null, 2)}
|
|
|
31699
31699
|
"draft_coda",
|
|
31700
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.",
|
|
31701
31701
|
{
|
|
31702
|
-
systemId: external_exports.string().describe("The
|
|
31702
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
31703
31703
|
beatId: external_exports.string().describe("The beat ID (must have a title but no description)")
|
|
31704
31704
|
},
|
|
31705
31705
|
async ({ systemId, beatId }) => {
|
|
@@ -31732,7 +31732,7 @@ ${JSON.stringify(task.result, null, 2)}
|
|
|
31732
31732
|
"validate_assumptions",
|
|
31733
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.",
|
|
31734
31734
|
{
|
|
31735
|
-
systemId: external_exports.string().describe("The
|
|
31735
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
31736
31736
|
noteIds: external_exports.array(external_exports.string()).optional().describe("Specific assumption note IDs to validate. If omitted, validates all unvalidated assumptions.")
|
|
31737
31737
|
},
|
|
31738
31738
|
async ({ systemId, noteIds }) => {
|
|
@@ -31764,9 +31764,9 @@ ${JSON.stringify(task.result, null, 2)}
|
|
|
31764
31764
|
);
|
|
31765
31765
|
server.tool(
|
|
31766
31766
|
"start_session",
|
|
31767
|
-
'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.',
|
|
31768
31768
|
{
|
|
31769
|
-
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"),
|
|
31770
31770
|
message: external_exports.string().min(1).describe("Free-form first message describing what the session should do"),
|
|
31771
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.")
|
|
31772
31772
|
},
|
|
@@ -31804,7 +31804,7 @@ ${JSON.stringify(task.result, null, 2)}
|
|
|
31804
31804
|
"plan_revision_batch",
|
|
31805
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.",
|
|
31806
31806
|
{
|
|
31807
|
-
systemId: external_exports.string().describe("The
|
|
31807
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
31808
31808
|
revisionIds: external_exports.array(external_exports.string()).optional().describe("Specific revision IDs to plan. If omitted, auto-discovers all unplanned planning revisions.")
|
|
31809
31809
|
},
|
|
31810
31810
|
async ({ systemId, revisionIds }) => {
|
|
@@ -31835,9 +31835,9 @@ ${JSON.stringify(task.result, null, 2)}
|
|
|
31835
31835
|
);
|
|
31836
31836
|
server.tool(
|
|
31837
31837
|
"run_triage",
|
|
31838
|
-
"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.",
|
|
31839
31839
|
{
|
|
31840
|
-
systemId: external_exports.string().describe("The
|
|
31840
|
+
systemId: external_exports.string().describe("The system ID")
|
|
31841
31841
|
},
|
|
31842
31842
|
async ({ systemId }) => {
|
|
31843
31843
|
try {
|
|
@@ -31880,7 +31880,7 @@ ${JSON.stringify(task.result, null, 2)}
|
|
|
31880
31880
|
"Returns a job ID \u2014 use `get_job_status` to track progress."
|
|
31881
31881
|
].join("\n"),
|
|
31882
31882
|
{
|
|
31883
|
-
systemId: external_exports.string().describe("The
|
|
31883
|
+
systemId: external_exports.string().describe("The system ID"),
|
|
31884
31884
|
content: external_exports.string().describe('Document content \u2014 plain text (default) or base64-encoded binary (when encoding is "base64")'),
|
|
31885
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.'),
|
|
31886
31886
|
encoding: external_exports.enum(["base64"]).optional().describe('Set to "base64" when submitting binary files (DOCX, XLSX, PPTX, PDF). Omit for plain text.')
|
|
@@ -32330,13 +32330,13 @@ function createHttpClient(config2) {
|
|
|
32330
32330
|
`/api/organizations/${encodeURIComponent(sourceOrgId)}/transfer-project`,
|
|
32331
32331
|
{ systemId: projectId, targetOrgId }
|
|
32332
32332
|
);
|
|
32333
|
-
const
|
|
32334
|
-
...result.
|
|
32335
|
-
systemId: result.
|
|
32336
|
-
title: result.
|
|
32337
|
-
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
|
|
32338
32338
|
} : void 0;
|
|
32339
|
-
return { success: result?.success ?? false,
|
|
32339
|
+
return { success: result?.success ?? false, system };
|
|
32340
32340
|
} catch (err) {
|
|
32341
32341
|
if (err instanceof Error) return { success: false, error: err.message };
|
|
32342
32342
|
return { success: false, error: String(err) };
|
|
@@ -34317,7 +34317,7 @@ function loadConfig() {
|
|
|
34317
34317
|
};
|
|
34318
34318
|
}
|
|
34319
34319
|
async function main() {
|
|
34320
|
-
console.error(`[harmonica-mcp] v${"3.
|
|
34320
|
+
console.error(`[harmonica-mcp] v${"3.8.0"} starting\u2026`);
|
|
34321
34321
|
const config2 = loadConfig();
|
|
34322
34322
|
const client = createHttpClient({
|
|
34323
34323
|
apiBaseUrl: config2.apiBaseUrl,
|