harmony-mcp 1.9.4 → 1.9.6
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/cli.js +180 -12
- package/dist/index.js +180 -12
- package/dist/server.js +31967 -0
- package/package.json +4 -2
package/dist/cli.js
CHANGED
|
@@ -30470,6 +30470,9 @@ class HarmonyApiClient {
|
|
|
30470
30470
|
async deleteMemoryEntity(entityId) {
|
|
30471
30471
|
return this.request("DELETE", `/memory/entities/${entityId}`);
|
|
30472
30472
|
}
|
|
30473
|
+
async touchMemoryEntity(entityId) {
|
|
30474
|
+
return this.request("POST", `/memory/entities/${entityId}/touch`);
|
|
30475
|
+
}
|
|
30473
30476
|
async createMemoryRelation(data) {
|
|
30474
30477
|
return this.request("POST", "/memory/relations", data);
|
|
30475
30478
|
}
|
|
@@ -30577,6 +30580,9 @@ class HarmonyApiClient {
|
|
|
30577
30580
|
async updatePlan(planId, updates) {
|
|
30578
30581
|
return this.request("PATCH", `/plans/${planId}`, updates);
|
|
30579
30582
|
}
|
|
30583
|
+
async updatePlanTask(planId, taskId, updates) {
|
|
30584
|
+
return this.request("PATCH", `/plans/${planId}/tasks/${taskId}`, updates);
|
|
30585
|
+
}
|
|
30580
30586
|
}
|
|
30581
30587
|
var client = null;
|
|
30582
30588
|
function getClient() {
|
|
@@ -31056,6 +31062,11 @@ function evaluateLifecycle(entity) {
|
|
|
31056
31062
|
reviewReason
|
|
31057
31063
|
};
|
|
31058
31064
|
}
|
|
31065
|
+
function buildContradictionQuery(type, tags) {
|
|
31066
|
+
if (tags.length === 0)
|
|
31067
|
+
return null;
|
|
31068
|
+
return { type, tags };
|
|
31069
|
+
}
|
|
31059
31070
|
// ../memory/src/graph-walk.ts
|
|
31060
31071
|
async function discoverRelatedContext(client2, startIds, maxDepth = 2, maxEntities = 20, minConfidence = 0.5) {
|
|
31061
31072
|
const visited = new Set;
|
|
@@ -31735,15 +31746,7 @@ function mapToContextEntity(raw) {
|
|
|
31735
31746
|
};
|
|
31736
31747
|
}
|
|
31737
31748
|
async function incrementAccessCounts(client3, entityIds) {
|
|
31738
|
-
|
|
31739
|
-
try {
|
|
31740
|
-
await client3.updateMemoryEntity(id, {
|
|
31741
|
-
metadata: {
|
|
31742
|
-
_last_context_load: new Date().toISOString()
|
|
31743
|
-
}
|
|
31744
|
-
});
|
|
31745
|
-
} catch {}
|
|
31746
|
-
}
|
|
31749
|
+
await Promise.allSettled(entityIds.map((id) => client3.touchMemoryEntity(id)));
|
|
31747
31750
|
}
|
|
31748
31751
|
var manifestCache = new Map;
|
|
31749
31752
|
var MAX_CACHE_SIZE = 50;
|
|
@@ -32770,6 +32773,11 @@ var TOOLS = {
|
|
|
32770
32773
|
enum: ["user", "agent", "imported"],
|
|
32771
32774
|
description: "Plan source: agent for AI-generated plans (default: agent)"
|
|
32772
32775
|
},
|
|
32776
|
+
workflowPhase: {
|
|
32777
|
+
type: "string",
|
|
32778
|
+
enum: ["plan", "execute", "verify", "done"],
|
|
32779
|
+
description: "GSD workflow phase (default: plan)"
|
|
32780
|
+
},
|
|
32773
32781
|
tasks: {
|
|
32774
32782
|
type: "array",
|
|
32775
32783
|
items: {
|
|
@@ -32810,7 +32818,7 @@ var TOOLS = {
|
|
|
32810
32818
|
}
|
|
32811
32819
|
},
|
|
32812
32820
|
harmony_update_plan: {
|
|
32813
|
-
description: "Update an existing plan. Can update title, content, or
|
|
32821
|
+
description: "Update an existing plan. Can update title, content, status, or workflow phase.",
|
|
32814
32822
|
inputSchema: {
|
|
32815
32823
|
type: "object",
|
|
32816
32824
|
properties: {
|
|
@@ -32824,11 +32832,35 @@ var TOOLS = {
|
|
|
32824
32832
|
type: "string",
|
|
32825
32833
|
enum: ["draft", "active", "archived"],
|
|
32826
32834
|
description: "New status"
|
|
32835
|
+
},
|
|
32836
|
+
workflowPhase: {
|
|
32837
|
+
type: "string",
|
|
32838
|
+
enum: ["plan", "execute", "verify", "done"],
|
|
32839
|
+
description: "GSD workflow phase"
|
|
32827
32840
|
}
|
|
32828
32841
|
},
|
|
32829
32842
|
required: ["planId"]
|
|
32830
32843
|
}
|
|
32831
32844
|
},
|
|
32845
|
+
harmony_advance_plan: {
|
|
32846
|
+
description: "Advance a plan to the next GSD workflow phase with side effects. plan→execute: auto-creates cards from tasks, sets plan active. execute→verify: checks card status. verify→done: archives plan. Creates memory entities at each transition.",
|
|
32847
|
+
inputSchema: {
|
|
32848
|
+
type: "object",
|
|
32849
|
+
properties: {
|
|
32850
|
+
planId: { type: "string", description: "Plan ID to advance" },
|
|
32851
|
+
phase: {
|
|
32852
|
+
type: "string",
|
|
32853
|
+
enum: ["execute", "verify", "done"],
|
|
32854
|
+
description: "Target phase to advance to"
|
|
32855
|
+
},
|
|
32856
|
+
summary: {
|
|
32857
|
+
type: "string",
|
|
32858
|
+
description: "Summary of what happened in the current phase. Stored as a memory entity (decision/pattern/lesson)."
|
|
32859
|
+
}
|
|
32860
|
+
},
|
|
32861
|
+
required: ["planId", "phase"]
|
|
32862
|
+
}
|
|
32863
|
+
},
|
|
32832
32864
|
harmony_review_learnings: {
|
|
32833
32865
|
description: "List pending auto-extracted memories awaiting human review. These are memories automatically created from agent work sessions.",
|
|
32834
32866
|
inputSchema: {
|
|
@@ -33553,6 +33585,7 @@ class HarmonyMCPServer {
|
|
|
33553
33585
|
throw new Error("No workspace specified. Use harmony_set_workspace_context or provide workspaceId.");
|
|
33554
33586
|
}
|
|
33555
33587
|
const entityType = args.type || "context";
|
|
33588
|
+
const entityTags = args.tags || [];
|
|
33556
33589
|
const result = await client3.createMemoryEntity({
|
|
33557
33590
|
workspace_id: workspaceId,
|
|
33558
33591
|
project_id: args.projectId || getActiveProjectId() || undefined,
|
|
@@ -33563,10 +33596,39 @@ class HarmonyMCPServer {
|
|
|
33563
33596
|
content,
|
|
33564
33597
|
metadata: args.metadata,
|
|
33565
33598
|
confidence: args.confidence,
|
|
33566
|
-
tags:
|
|
33599
|
+
tags: entityTags.length > 0 ? entityTags : undefined,
|
|
33567
33600
|
agent_identifier: "claude-code"
|
|
33568
33601
|
});
|
|
33569
|
-
|
|
33602
|
+
const contradictionQuery = buildContradictionQuery(entityType, entityTags);
|
|
33603
|
+
let potentialContradictions = [];
|
|
33604
|
+
if (contradictionQuery) {
|
|
33605
|
+
try {
|
|
33606
|
+
const newEntityId = result.entity?.id;
|
|
33607
|
+
const { entities: candidates } = await client3.listMemoryEntities({
|
|
33608
|
+
workspace_id: workspaceId,
|
|
33609
|
+
type: contradictionQuery.type,
|
|
33610
|
+
tags: contradictionQuery.tags,
|
|
33611
|
+
limit: 10
|
|
33612
|
+
});
|
|
33613
|
+
potentialContradictions = candidates.filter((c) => c.id !== newEntityId).map((c) => ({ id: c.id, title: c.title, tags: c.tags || [] }));
|
|
33614
|
+
if (newEntityId && potentialContradictions.length > 0) {
|
|
33615
|
+
Promise.all(potentialContradictions.map((c) => client3.createMemoryRelation({
|
|
33616
|
+
source_id: newEntityId,
|
|
33617
|
+
target_id: c.id,
|
|
33618
|
+
relation_type: "contradicts",
|
|
33619
|
+
confidence: 0.5
|
|
33620
|
+
}).catch(() => {}))).catch(() => {});
|
|
33621
|
+
}
|
|
33622
|
+
} catch {}
|
|
33623
|
+
}
|
|
33624
|
+
return {
|
|
33625
|
+
success: true,
|
|
33626
|
+
...result,
|
|
33627
|
+
...potentialContradictions.length > 0 && {
|
|
33628
|
+
potentialContradictions,
|
|
33629
|
+
contradictionNote: `Found ${potentialContradictions.length} existing memor${potentialContradictions.length === 1 ? "y" : "ies"} with same type and overlapping tags. 'contradicts' relations created automatically. Review these to resolve or confirm.`
|
|
33630
|
+
}
|
|
33631
|
+
};
|
|
33570
33632
|
}
|
|
33571
33633
|
case "harmony_recall": {
|
|
33572
33634
|
const workspaceId = args.workspaceId || getActiveWorkspaceId();
|
|
@@ -33750,6 +33812,7 @@ class HarmonyMCPServer {
|
|
|
33750
33812
|
title,
|
|
33751
33813
|
content: args.content,
|
|
33752
33814
|
source: args.source || "agent",
|
|
33815
|
+
workflowPhase: args.workflowPhase || "plan",
|
|
33753
33816
|
tasks: args.tasks
|
|
33754
33817
|
});
|
|
33755
33818
|
const planUrl = `https://gethmy.com/plans/${result.plan.id}`;
|
|
@@ -33796,9 +33859,114 @@ class HarmonyMCPServer {
|
|
|
33796
33859
|
if (args.status !== undefined) {
|
|
33797
33860
|
updates.status = exports_external.enum(["draft", "active", "archived"]).parse(args.status);
|
|
33798
33861
|
}
|
|
33862
|
+
if (args.workflowPhase !== undefined) {
|
|
33863
|
+
updates.workflowPhase = exports_external.enum(["plan", "execute", "verify", "done"]).parse(args.workflowPhase);
|
|
33864
|
+
}
|
|
33799
33865
|
const result = await client3.updatePlan(planId, updates);
|
|
33800
33866
|
return { success: true, plan: result.plan };
|
|
33801
33867
|
}
|
|
33868
|
+
case "harmony_advance_plan": {
|
|
33869
|
+
const planId = exports_external.string().uuid().parse(args.planId);
|
|
33870
|
+
const targetPhase = exports_external.enum(["execute", "verify", "done"]).parse(args.phase);
|
|
33871
|
+
const summary = args.summary;
|
|
33872
|
+
const planResult = await client3.getPlan(planId);
|
|
33873
|
+
const plan = planResult.plan;
|
|
33874
|
+
const tasks = planResult.tasks;
|
|
33875
|
+
const currentPhase = plan.workflow_phase || "plan";
|
|
33876
|
+
const validTransitions = {
|
|
33877
|
+
plan: "execute",
|
|
33878
|
+
execute: "verify",
|
|
33879
|
+
verify: "done"
|
|
33880
|
+
};
|
|
33881
|
+
if (validTransitions[currentPhase] !== targetPhase) {
|
|
33882
|
+
throw new Error(`Invalid transition: cannot advance from "${currentPhase}" to "${targetPhase}". Expected "${validTransitions[currentPhase]}".`);
|
|
33883
|
+
}
|
|
33884
|
+
const results = {};
|
|
33885
|
+
const workspaceId = getActiveWorkspaceId() || "";
|
|
33886
|
+
if (targetPhase === "execute") {
|
|
33887
|
+
const projectId = plan.project_id;
|
|
33888
|
+
const boardResult = await client3.getBoard(projectId, { summary: true });
|
|
33889
|
+
const columns = boardResult.columns || [];
|
|
33890
|
+
const todoColumn = columns.find((c) => c.name.toLowerCase().includes("to do") || c.name.toLowerCase() === "todo") || columns[0];
|
|
33891
|
+
if (todoColumn && tasks.length > 0) {
|
|
33892
|
+
let cardsCreated = 0;
|
|
33893
|
+
for (const task of tasks) {
|
|
33894
|
+
if (task.card_id)
|
|
33895
|
+
continue;
|
|
33896
|
+
try {
|
|
33897
|
+
const cardResult = await client3.createCard(projectId, {
|
|
33898
|
+
title: task.content,
|
|
33899
|
+
columnId: todoColumn.id,
|
|
33900
|
+
description: `From plan: ${plan.title}`,
|
|
33901
|
+
priority: task.priority || "medium"
|
|
33902
|
+
});
|
|
33903
|
+
const card = cardResult.card;
|
|
33904
|
+
await client3.updatePlanTask(planId, task.id, { cardId: card.id });
|
|
33905
|
+
cardsCreated++;
|
|
33906
|
+
} catch (e) {}
|
|
33907
|
+
}
|
|
33908
|
+
results.cardsCreated = cardsCreated;
|
|
33909
|
+
}
|
|
33910
|
+
await client3.updatePlan(planId, { status: "active", workflowPhase: "execute" });
|
|
33911
|
+
results.planStatus = "active";
|
|
33912
|
+
if (summary && workspaceId) {
|
|
33913
|
+
try {
|
|
33914
|
+
const memResult = await client3.createMemoryEntity({
|
|
33915
|
+
title: `Decision: ${plan.title}`,
|
|
33916
|
+
content: summary,
|
|
33917
|
+
type: "decision",
|
|
33918
|
+
scope: "project",
|
|
33919
|
+
workspaceId,
|
|
33920
|
+
projectId,
|
|
33921
|
+
tags: ["gsd", "plan"],
|
|
33922
|
+
confidence: 0.8
|
|
33923
|
+
});
|
|
33924
|
+
results.memoryEntityId = memResult.entity?.id;
|
|
33925
|
+
} catch (_) {}
|
|
33926
|
+
}
|
|
33927
|
+
} else if (targetPhase === "verify") {
|
|
33928
|
+
await client3.updatePlan(planId, { workflowPhase: "verify" });
|
|
33929
|
+
if (summary && workspaceId) {
|
|
33930
|
+
try {
|
|
33931
|
+
const memResult = await client3.createMemoryEntity({
|
|
33932
|
+
title: `Pattern: ${plan.title}`,
|
|
33933
|
+
content: summary,
|
|
33934
|
+
type: "pattern",
|
|
33935
|
+
scope: "project",
|
|
33936
|
+
workspaceId,
|
|
33937
|
+
projectId: plan.project_id,
|
|
33938
|
+
tags: ["gsd", "execute"],
|
|
33939
|
+
confidence: 0.8
|
|
33940
|
+
});
|
|
33941
|
+
results.memoryEntityId = memResult.entity?.id;
|
|
33942
|
+
} catch (_) {}
|
|
33943
|
+
}
|
|
33944
|
+
} else if (targetPhase === "done") {
|
|
33945
|
+
await client3.updatePlan(planId, { status: "archived", workflowPhase: "done" });
|
|
33946
|
+
results.planStatus = "archived";
|
|
33947
|
+
if (summary && workspaceId) {
|
|
33948
|
+
try {
|
|
33949
|
+
const memResult = await client3.createMemoryEntity({
|
|
33950
|
+
title: `Lesson: ${plan.title}`,
|
|
33951
|
+
content: summary,
|
|
33952
|
+
type: "lesson",
|
|
33953
|
+
scope: "project",
|
|
33954
|
+
workspaceId,
|
|
33955
|
+
projectId: plan.project_id,
|
|
33956
|
+
tags: ["gsd", "verify"],
|
|
33957
|
+
confidence: 0.8
|
|
33958
|
+
});
|
|
33959
|
+
results.memoryEntityId = memResult.entity?.id;
|
|
33960
|
+
} catch (_) {}
|
|
33961
|
+
}
|
|
33962
|
+
}
|
|
33963
|
+
return {
|
|
33964
|
+
success: true,
|
|
33965
|
+
previousPhase: currentPhase,
|
|
33966
|
+
newPhase: targetPhase,
|
|
33967
|
+
...results
|
|
33968
|
+
};
|
|
33969
|
+
}
|
|
33802
33970
|
case "harmony_debug_context": {
|
|
33803
33971
|
const entityId = exports_external.string().uuid().parse(args.entityId);
|
|
33804
33972
|
const taskContext = exports_external.string().min(1).parse(args.taskContext);
|
package/dist/index.js
CHANGED
|
@@ -28230,6 +28230,9 @@ class HarmonyApiClient {
|
|
|
28230
28230
|
async deleteMemoryEntity(entityId) {
|
|
28231
28231
|
return this.request("DELETE", `/memory/entities/${entityId}`);
|
|
28232
28232
|
}
|
|
28233
|
+
async touchMemoryEntity(entityId) {
|
|
28234
|
+
return this.request("POST", `/memory/entities/${entityId}/touch`);
|
|
28235
|
+
}
|
|
28233
28236
|
async createMemoryRelation(data) {
|
|
28234
28237
|
return this.request("POST", "/memory/relations", data);
|
|
28235
28238
|
}
|
|
@@ -28337,6 +28340,9 @@ class HarmonyApiClient {
|
|
|
28337
28340
|
async updatePlan(planId, updates) {
|
|
28338
28341
|
return this.request("PATCH", `/plans/${planId}`, updates);
|
|
28339
28342
|
}
|
|
28343
|
+
async updatePlanTask(planId, taskId, updates) {
|
|
28344
|
+
return this.request("PATCH", `/plans/${planId}/tasks/${taskId}`, updates);
|
|
28345
|
+
}
|
|
28340
28346
|
}
|
|
28341
28347
|
var client = null;
|
|
28342
28348
|
function getClient() {
|
|
@@ -28816,6 +28822,11 @@ function evaluateLifecycle(entity) {
|
|
|
28816
28822
|
reviewReason
|
|
28817
28823
|
};
|
|
28818
28824
|
}
|
|
28825
|
+
function buildContradictionQuery(type, tags) {
|
|
28826
|
+
if (tags.length === 0)
|
|
28827
|
+
return null;
|
|
28828
|
+
return { type, tags };
|
|
28829
|
+
}
|
|
28819
28830
|
// ../memory/src/graph-walk.ts
|
|
28820
28831
|
async function discoverRelatedContext(client2, startIds, maxDepth = 2, maxEntities = 20, minConfidence = 0.5) {
|
|
28821
28832
|
const visited = new Set;
|
|
@@ -29495,15 +29506,7 @@ function mapToContextEntity(raw) {
|
|
|
29495
29506
|
};
|
|
29496
29507
|
}
|
|
29497
29508
|
async function incrementAccessCounts(client3, entityIds) {
|
|
29498
|
-
|
|
29499
|
-
try {
|
|
29500
|
-
await client3.updateMemoryEntity(id, {
|
|
29501
|
-
metadata: {
|
|
29502
|
-
_last_context_load: new Date().toISOString()
|
|
29503
|
-
}
|
|
29504
|
-
});
|
|
29505
|
-
} catch {}
|
|
29506
|
-
}
|
|
29509
|
+
await Promise.allSettled(entityIds.map((id) => client3.touchMemoryEntity(id)));
|
|
29507
29510
|
}
|
|
29508
29511
|
var manifestCache = new Map;
|
|
29509
29512
|
var MAX_CACHE_SIZE = 50;
|
|
@@ -30530,6 +30533,11 @@ var TOOLS = {
|
|
|
30530
30533
|
enum: ["user", "agent", "imported"],
|
|
30531
30534
|
description: "Plan source: agent for AI-generated plans (default: agent)"
|
|
30532
30535
|
},
|
|
30536
|
+
workflowPhase: {
|
|
30537
|
+
type: "string",
|
|
30538
|
+
enum: ["plan", "execute", "verify", "done"],
|
|
30539
|
+
description: "GSD workflow phase (default: plan)"
|
|
30540
|
+
},
|
|
30533
30541
|
tasks: {
|
|
30534
30542
|
type: "array",
|
|
30535
30543
|
items: {
|
|
@@ -30570,7 +30578,7 @@ var TOOLS = {
|
|
|
30570
30578
|
}
|
|
30571
30579
|
},
|
|
30572
30580
|
harmony_update_plan: {
|
|
30573
|
-
description: "Update an existing plan. Can update title, content, or
|
|
30581
|
+
description: "Update an existing plan. Can update title, content, status, or workflow phase.",
|
|
30574
30582
|
inputSchema: {
|
|
30575
30583
|
type: "object",
|
|
30576
30584
|
properties: {
|
|
@@ -30584,11 +30592,35 @@ var TOOLS = {
|
|
|
30584
30592
|
type: "string",
|
|
30585
30593
|
enum: ["draft", "active", "archived"],
|
|
30586
30594
|
description: "New status"
|
|
30595
|
+
},
|
|
30596
|
+
workflowPhase: {
|
|
30597
|
+
type: "string",
|
|
30598
|
+
enum: ["plan", "execute", "verify", "done"],
|
|
30599
|
+
description: "GSD workflow phase"
|
|
30587
30600
|
}
|
|
30588
30601
|
},
|
|
30589
30602
|
required: ["planId"]
|
|
30590
30603
|
}
|
|
30591
30604
|
},
|
|
30605
|
+
harmony_advance_plan: {
|
|
30606
|
+
description: "Advance a plan to the next GSD workflow phase with side effects. plan→execute: auto-creates cards from tasks, sets plan active. execute→verify: checks card status. verify→done: archives plan. Creates memory entities at each transition.",
|
|
30607
|
+
inputSchema: {
|
|
30608
|
+
type: "object",
|
|
30609
|
+
properties: {
|
|
30610
|
+
planId: { type: "string", description: "Plan ID to advance" },
|
|
30611
|
+
phase: {
|
|
30612
|
+
type: "string",
|
|
30613
|
+
enum: ["execute", "verify", "done"],
|
|
30614
|
+
description: "Target phase to advance to"
|
|
30615
|
+
},
|
|
30616
|
+
summary: {
|
|
30617
|
+
type: "string",
|
|
30618
|
+
description: "Summary of what happened in the current phase. Stored as a memory entity (decision/pattern/lesson)."
|
|
30619
|
+
}
|
|
30620
|
+
},
|
|
30621
|
+
required: ["planId", "phase"]
|
|
30622
|
+
}
|
|
30623
|
+
},
|
|
30592
30624
|
harmony_review_learnings: {
|
|
30593
30625
|
description: "List pending auto-extracted memories awaiting human review. These are memories automatically created from agent work sessions.",
|
|
30594
30626
|
inputSchema: {
|
|
@@ -31313,6 +31345,7 @@ class HarmonyMCPServer {
|
|
|
31313
31345
|
throw new Error("No workspace specified. Use harmony_set_workspace_context or provide workspaceId.");
|
|
31314
31346
|
}
|
|
31315
31347
|
const entityType = args.type || "context";
|
|
31348
|
+
const entityTags = args.tags || [];
|
|
31316
31349
|
const result = await client3.createMemoryEntity({
|
|
31317
31350
|
workspace_id: workspaceId,
|
|
31318
31351
|
project_id: args.projectId || getActiveProjectId() || undefined,
|
|
@@ -31323,10 +31356,39 @@ class HarmonyMCPServer {
|
|
|
31323
31356
|
content,
|
|
31324
31357
|
metadata: args.metadata,
|
|
31325
31358
|
confidence: args.confidence,
|
|
31326
|
-
tags:
|
|
31359
|
+
tags: entityTags.length > 0 ? entityTags : undefined,
|
|
31327
31360
|
agent_identifier: "claude-code"
|
|
31328
31361
|
});
|
|
31329
|
-
|
|
31362
|
+
const contradictionQuery = buildContradictionQuery(entityType, entityTags);
|
|
31363
|
+
let potentialContradictions = [];
|
|
31364
|
+
if (contradictionQuery) {
|
|
31365
|
+
try {
|
|
31366
|
+
const newEntityId = result.entity?.id;
|
|
31367
|
+
const { entities: candidates } = await client3.listMemoryEntities({
|
|
31368
|
+
workspace_id: workspaceId,
|
|
31369
|
+
type: contradictionQuery.type,
|
|
31370
|
+
tags: contradictionQuery.tags,
|
|
31371
|
+
limit: 10
|
|
31372
|
+
});
|
|
31373
|
+
potentialContradictions = candidates.filter((c) => c.id !== newEntityId).map((c) => ({ id: c.id, title: c.title, tags: c.tags || [] }));
|
|
31374
|
+
if (newEntityId && potentialContradictions.length > 0) {
|
|
31375
|
+
Promise.all(potentialContradictions.map((c) => client3.createMemoryRelation({
|
|
31376
|
+
source_id: newEntityId,
|
|
31377
|
+
target_id: c.id,
|
|
31378
|
+
relation_type: "contradicts",
|
|
31379
|
+
confidence: 0.5
|
|
31380
|
+
}).catch(() => {}))).catch(() => {});
|
|
31381
|
+
}
|
|
31382
|
+
} catch {}
|
|
31383
|
+
}
|
|
31384
|
+
return {
|
|
31385
|
+
success: true,
|
|
31386
|
+
...result,
|
|
31387
|
+
...potentialContradictions.length > 0 && {
|
|
31388
|
+
potentialContradictions,
|
|
31389
|
+
contradictionNote: `Found ${potentialContradictions.length} existing memor${potentialContradictions.length === 1 ? "y" : "ies"} with same type and overlapping tags. 'contradicts' relations created automatically. Review these to resolve or confirm.`
|
|
31390
|
+
}
|
|
31391
|
+
};
|
|
31330
31392
|
}
|
|
31331
31393
|
case "harmony_recall": {
|
|
31332
31394
|
const workspaceId = args.workspaceId || getActiveWorkspaceId();
|
|
@@ -31510,6 +31572,7 @@ class HarmonyMCPServer {
|
|
|
31510
31572
|
title,
|
|
31511
31573
|
content: args.content,
|
|
31512
31574
|
source: args.source || "agent",
|
|
31575
|
+
workflowPhase: args.workflowPhase || "plan",
|
|
31513
31576
|
tasks: args.tasks
|
|
31514
31577
|
});
|
|
31515
31578
|
const planUrl = `https://gethmy.com/plans/${result.plan.id}`;
|
|
@@ -31556,9 +31619,114 @@ class HarmonyMCPServer {
|
|
|
31556
31619
|
if (args.status !== undefined) {
|
|
31557
31620
|
updates.status = exports_external.enum(["draft", "active", "archived"]).parse(args.status);
|
|
31558
31621
|
}
|
|
31622
|
+
if (args.workflowPhase !== undefined) {
|
|
31623
|
+
updates.workflowPhase = exports_external.enum(["plan", "execute", "verify", "done"]).parse(args.workflowPhase);
|
|
31624
|
+
}
|
|
31559
31625
|
const result = await client3.updatePlan(planId, updates);
|
|
31560
31626
|
return { success: true, plan: result.plan };
|
|
31561
31627
|
}
|
|
31628
|
+
case "harmony_advance_plan": {
|
|
31629
|
+
const planId = exports_external.string().uuid().parse(args.planId);
|
|
31630
|
+
const targetPhase = exports_external.enum(["execute", "verify", "done"]).parse(args.phase);
|
|
31631
|
+
const summary = args.summary;
|
|
31632
|
+
const planResult = await client3.getPlan(planId);
|
|
31633
|
+
const plan = planResult.plan;
|
|
31634
|
+
const tasks = planResult.tasks;
|
|
31635
|
+
const currentPhase = plan.workflow_phase || "plan";
|
|
31636
|
+
const validTransitions = {
|
|
31637
|
+
plan: "execute",
|
|
31638
|
+
execute: "verify",
|
|
31639
|
+
verify: "done"
|
|
31640
|
+
};
|
|
31641
|
+
if (validTransitions[currentPhase] !== targetPhase) {
|
|
31642
|
+
throw new Error(`Invalid transition: cannot advance from "${currentPhase}" to "${targetPhase}". Expected "${validTransitions[currentPhase]}".`);
|
|
31643
|
+
}
|
|
31644
|
+
const results = {};
|
|
31645
|
+
const workspaceId = getActiveWorkspaceId() || "";
|
|
31646
|
+
if (targetPhase === "execute") {
|
|
31647
|
+
const projectId = plan.project_id;
|
|
31648
|
+
const boardResult = await client3.getBoard(projectId, { summary: true });
|
|
31649
|
+
const columns = boardResult.columns || [];
|
|
31650
|
+
const todoColumn = columns.find((c) => c.name.toLowerCase().includes("to do") || c.name.toLowerCase() === "todo") || columns[0];
|
|
31651
|
+
if (todoColumn && tasks.length > 0) {
|
|
31652
|
+
let cardsCreated = 0;
|
|
31653
|
+
for (const task of tasks) {
|
|
31654
|
+
if (task.card_id)
|
|
31655
|
+
continue;
|
|
31656
|
+
try {
|
|
31657
|
+
const cardResult = await client3.createCard(projectId, {
|
|
31658
|
+
title: task.content,
|
|
31659
|
+
columnId: todoColumn.id,
|
|
31660
|
+
description: `From plan: ${plan.title}`,
|
|
31661
|
+
priority: task.priority || "medium"
|
|
31662
|
+
});
|
|
31663
|
+
const card = cardResult.card;
|
|
31664
|
+
await client3.updatePlanTask(planId, task.id, { cardId: card.id });
|
|
31665
|
+
cardsCreated++;
|
|
31666
|
+
} catch (e) {}
|
|
31667
|
+
}
|
|
31668
|
+
results.cardsCreated = cardsCreated;
|
|
31669
|
+
}
|
|
31670
|
+
await client3.updatePlan(planId, { status: "active", workflowPhase: "execute" });
|
|
31671
|
+
results.planStatus = "active";
|
|
31672
|
+
if (summary && workspaceId) {
|
|
31673
|
+
try {
|
|
31674
|
+
const memResult = await client3.createMemoryEntity({
|
|
31675
|
+
title: `Decision: ${plan.title}`,
|
|
31676
|
+
content: summary,
|
|
31677
|
+
type: "decision",
|
|
31678
|
+
scope: "project",
|
|
31679
|
+
workspaceId,
|
|
31680
|
+
projectId,
|
|
31681
|
+
tags: ["gsd", "plan"],
|
|
31682
|
+
confidence: 0.8
|
|
31683
|
+
});
|
|
31684
|
+
results.memoryEntityId = memResult.entity?.id;
|
|
31685
|
+
} catch (_) {}
|
|
31686
|
+
}
|
|
31687
|
+
} else if (targetPhase === "verify") {
|
|
31688
|
+
await client3.updatePlan(planId, { workflowPhase: "verify" });
|
|
31689
|
+
if (summary && workspaceId) {
|
|
31690
|
+
try {
|
|
31691
|
+
const memResult = await client3.createMemoryEntity({
|
|
31692
|
+
title: `Pattern: ${plan.title}`,
|
|
31693
|
+
content: summary,
|
|
31694
|
+
type: "pattern",
|
|
31695
|
+
scope: "project",
|
|
31696
|
+
workspaceId,
|
|
31697
|
+
projectId: plan.project_id,
|
|
31698
|
+
tags: ["gsd", "execute"],
|
|
31699
|
+
confidence: 0.8
|
|
31700
|
+
});
|
|
31701
|
+
results.memoryEntityId = memResult.entity?.id;
|
|
31702
|
+
} catch (_) {}
|
|
31703
|
+
}
|
|
31704
|
+
} else if (targetPhase === "done") {
|
|
31705
|
+
await client3.updatePlan(planId, { status: "archived", workflowPhase: "done" });
|
|
31706
|
+
results.planStatus = "archived";
|
|
31707
|
+
if (summary && workspaceId) {
|
|
31708
|
+
try {
|
|
31709
|
+
const memResult = await client3.createMemoryEntity({
|
|
31710
|
+
title: `Lesson: ${plan.title}`,
|
|
31711
|
+
content: summary,
|
|
31712
|
+
type: "lesson",
|
|
31713
|
+
scope: "project",
|
|
31714
|
+
workspaceId,
|
|
31715
|
+
projectId: plan.project_id,
|
|
31716
|
+
tags: ["gsd", "verify"],
|
|
31717
|
+
confidence: 0.8
|
|
31718
|
+
});
|
|
31719
|
+
results.memoryEntityId = memResult.entity?.id;
|
|
31720
|
+
} catch (_) {}
|
|
31721
|
+
}
|
|
31722
|
+
}
|
|
31723
|
+
return {
|
|
31724
|
+
success: true,
|
|
31725
|
+
previousPhase: currentPhase,
|
|
31726
|
+
newPhase: targetPhase,
|
|
31727
|
+
...results
|
|
31728
|
+
};
|
|
31729
|
+
}
|
|
31562
31730
|
case "harmony_debug_context": {
|
|
31563
31731
|
const entityId = exports_external.string().uuid().parse(args.entityId);
|
|
31564
31732
|
const taskContext = exports_external.string().min(1).parse(args.taskContext);
|