sysprom 1.14.0 → 1.15.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/README.md +19 -2
- package/dist/src/cli/commands/infer.d.ts +2 -0
- package/dist/src/cli/commands/infer.js +206 -0
- package/dist/src/cli/program.js +2 -0
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/mcp/server.js +74 -1
- package/dist/src/operations/index.d.ts +4 -0
- package/dist/src/operations/index.js +5 -0
- package/dist/src/operations/infer-completeness.d.ts +414 -0
- package/dist/src/operations/infer-completeness.js +131 -0
- package/dist/src/operations/infer-derived.d.ts +375 -0
- package/dist/src/operations/infer-derived.js +158 -0
- package/dist/src/operations/infer-impact.d.ts +1246 -0
- package/dist/src/operations/infer-impact.js +144 -0
- package/dist/src/operations/infer-lifecycle.d.ts +421 -0
- package/dist/src/operations/infer-lifecycle.js +119 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -52,13 +52,20 @@ sysprom update node D1 --status deprecated
|
|
|
52
52
|
sysprom update add-rel D1 affects EL5
|
|
53
53
|
sysprom update remove-rel D1 affects EL5
|
|
54
54
|
sysprom update meta --fields version=2
|
|
55
|
+
|
|
56
|
+
# Inference operations (deterministic graph analysis)
|
|
57
|
+
sysprom infer completeness # Score node completeness (0-1)
|
|
58
|
+
sysprom infer lifecycle # Infer lifecycle phases
|
|
59
|
+
sysprom infer impact I1 # Trace impact from node
|
|
60
|
+
sysprom infer derived # Compute transitive closure
|
|
61
|
+
sysprom infer all # Run all analyses
|
|
55
62
|
```
|
|
56
63
|
|
|
57
64
|
All commands auto-detect the document — they search the current directory for `.SysProM.json`, `.SysProM.md`, or `.SysProM/` (in that priority order), then fall back to `.spm.json`, `.spm.md`, or `.spm/`. Use `--path` to specify an explicit path. Note: `spm` is an alias for `sysprom` for backwards compatibility.
|
|
58
65
|
|
|
59
66
|
## MCP Server
|
|
60
67
|
|
|
61
|
-
SysProM includes an MCP (Model Context Protocol) server exposing
|
|
68
|
+
SysProM includes an MCP (Model Context Protocol) server exposing 15 tools over stdio transport. Any MCP-compatible agent — Cursor, Windsurf, VS Code Copilot, Cline, or custom clients — can use it.
|
|
62
69
|
|
|
63
70
|
### Configuration
|
|
64
71
|
|
|
@@ -96,6 +103,10 @@ sysprom mcp # starts the MCP server on stdio
|
|
|
96
103
|
| `update-node` | Update fields on an existing node |
|
|
97
104
|
| `add-relationship` | Add a relationship between nodes |
|
|
98
105
|
| `remove-relationship` | Remove a relationship |
|
|
106
|
+
| `infer-completeness` | Score node completeness (0-1) based on refinement relationships |
|
|
107
|
+
| `infer-lifecycle` | Infer lifecycle phase from status and lifecycle fields |
|
|
108
|
+
| `infer-impact` | Trace impact propagation from a starting node |
|
|
109
|
+
| `infer-derived` | Compute transitive closure and inverse relationships |
|
|
99
110
|
|
|
100
111
|
All tools accept a `path` parameter to specify the SysProM document location.
|
|
101
112
|
|
|
@@ -134,6 +145,12 @@ import {
|
|
|
134
145
|
removeRelationship,
|
|
135
146
|
updateMetadata,
|
|
136
147
|
|
|
148
|
+
// Inference
|
|
149
|
+
inferCompletenessOp,
|
|
150
|
+
inferLifecycleOp,
|
|
151
|
+
inferImpactOp,
|
|
152
|
+
inferDerivedOp,
|
|
153
|
+
|
|
137
154
|
// File I/O
|
|
138
155
|
loadDocument,
|
|
139
156
|
saveDocument,
|
|
@@ -212,7 +229,7 @@ SysProM models systems as directed graphs across abstraction layers — intent,
|
|
|
212
229
|
<tr><td><a href="https://github.com/Priivacy-ai/spec-kitty">Spec Kitty</a></td><td>✅</td><td>🔶</td><td>✅</td><td>🔶</td><td></td><td>🔶</td><td>🔶</td><td>🔶</td><td></td><td></td><td>🔶</td><td>✅</td><td>✅</td><td>✅</td></tr>
|
|
213
230
|
<tr><td><a href="https://github.com/shotgun-sh/shotgun">Shotgun</a></td><td>✅</td><td>🔶</td><td>🔶</td><td></td><td></td><td>🔶</td><td></td><td>🔶</td><td></td><td></td><td>🔶</td><td>🔶</td><td>✅</td><td>🔶</td></tr>
|
|
214
231
|
<tr><td><a href="https://github.com/obra/superpowers">Superpowers</a></td><td>✅</td><td>🔶</td><td>🔶</td><td>🔶</td><td></td><td>🔶</td><td>✅</td><td>🔶</td><td></td><td>✅</td><td>🔶</td><td>✅</td><td>✅</td><td>✅</td></tr>
|
|
215
|
-
<tr><td><strong>SysProM</strong></td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>🔶</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td
|
|
232
|
+
<tr><td><strong>SysProM</strong></td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>🔶</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>🔶</td><td>✅</td><td>✅</td><td>✅</td></tr>
|
|
216
233
|
</tbody>
|
|
217
234
|
</table>
|
|
218
235
|
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import pc from "picocolors";
|
|
2
|
+
import * as z from "zod";
|
|
3
|
+
import { readOpts, loadDoc } from "../shared.js";
|
|
4
|
+
import { inferCompletenessOp, inferLifecycleOp, inferImpactOp, inferDerivedOp, } from "../../operations/index.js";
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Presentation helpers
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
function printCompletenessNode(r) {
|
|
9
|
+
const scoreColour = r.score === 1 ? pc.green : r.score >= 0.5 ? pc.yellow : pc.red;
|
|
10
|
+
console.log(`${pc.cyan(r.id.padEnd(12))} ${pc.dim(r.type.padEnd(16))} ${pc.bold(r.name)} ${scoreColour(`[${(r.score * 100).toFixed(0)}%]`)}`);
|
|
11
|
+
for (const issue of r.issues) {
|
|
12
|
+
console.log(` ${pc.dim("•")} ${pc.red(issue)}`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function printLifecycleNode(r) {
|
|
16
|
+
const phaseColours = {
|
|
17
|
+
early: pc.blue,
|
|
18
|
+
middle: pc.yellow,
|
|
19
|
+
late: pc.green,
|
|
20
|
+
terminal: pc.red,
|
|
21
|
+
unknown: pc.dim,
|
|
22
|
+
};
|
|
23
|
+
const colour = phaseColours[r.inferredPhase] ?? pc.dim;
|
|
24
|
+
console.log(`${pc.cyan(r.id.padEnd(12))} ${pc.dim(r.type.padEnd(16))} ${pc.bold(r.name)} ${colour(`[${r.inferredPhase}]`)} ${pc.dim(r.inferredState)}`);
|
|
25
|
+
}
|
|
26
|
+
function printImpactNode(r) {
|
|
27
|
+
const typeColours = {
|
|
28
|
+
direct: pc.red,
|
|
29
|
+
transitive: pc.yellow,
|
|
30
|
+
potential: pc.blue,
|
|
31
|
+
};
|
|
32
|
+
const colour = typeColours[r.impactType] ?? pc.dim;
|
|
33
|
+
const nodeName = r.node ? r.node.name : "(unknown)";
|
|
34
|
+
const indent = " ".repeat(r.distance);
|
|
35
|
+
console.log(`${indent}${pc.cyan(r.id)} ${pc.dim(`(${String(r.distance)})`)} ${colour(`[${r.impactType}]`)} ${pc.bold(nodeName)}`);
|
|
36
|
+
}
|
|
37
|
+
function printDerivedRelationship(r) {
|
|
38
|
+
const typeColours = {
|
|
39
|
+
transitive: pc.yellow,
|
|
40
|
+
composite: pc.blue,
|
|
41
|
+
inverse: pc.green,
|
|
42
|
+
};
|
|
43
|
+
const colour = typeColours[r.derivationType] ?? pc.dim;
|
|
44
|
+
console.log(`${pc.cyan(r.from.padEnd(12))} ${colour(r.type.padEnd(20))} ${pc.cyan(r.to)} ${pc.dim(`[${r.derivationType}]`)}`);
|
|
45
|
+
}
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
// Arg/opt schemas
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
const impactArgs = z.object({
|
|
50
|
+
id: z.string().describe("node ID to start impact analysis from"),
|
|
51
|
+
});
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Subcommands
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
const completenessSubcommand = {
|
|
56
|
+
name: "completeness",
|
|
57
|
+
description: inferCompletenessOp.def.description,
|
|
58
|
+
apiLink: inferCompletenessOp.def.name,
|
|
59
|
+
opts: readOpts,
|
|
60
|
+
action(_rawArgs, rawOpts) {
|
|
61
|
+
const opts = readOpts.parse(rawOpts);
|
|
62
|
+
const { doc } = loadDoc(opts.path);
|
|
63
|
+
const result = inferCompletenessOp({ doc });
|
|
64
|
+
if (opts.json) {
|
|
65
|
+
console.log(JSON.stringify(result, null, 2));
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
console.log(pc.bold("\nCompleteness Analysis\n") +
|
|
69
|
+
pc.dim(`Average score: ${(result.averageScore * 100).toFixed(1)}% | `) +
|
|
70
|
+
pc.green(`${String(result.completeNodes)} complete`) +
|
|
71
|
+
pc.dim(" | ") +
|
|
72
|
+
pc.red(`${String(result.incompleteNodes)} incomplete`) +
|
|
73
|
+
"\n");
|
|
74
|
+
// Show incomplete nodes first
|
|
75
|
+
const incomplete = result.nodes.filter((n) => n.score < 1);
|
|
76
|
+
const complete = result.nodes.filter((n) => n.score === 1);
|
|
77
|
+
if (incomplete.length > 0) {
|
|
78
|
+
console.log(pc.dim("Incomplete nodes:"));
|
|
79
|
+
for (const n of incomplete)
|
|
80
|
+
printCompletenessNode(n);
|
|
81
|
+
console.log();
|
|
82
|
+
}
|
|
83
|
+
console.log(pc.dim(`${String(complete.length)} fully complete nodes`));
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
const lifecycleSubcommand = {
|
|
88
|
+
name: "lifecycle",
|
|
89
|
+
description: inferLifecycleOp.def.description,
|
|
90
|
+
apiLink: inferLifecycleOp.def.name,
|
|
91
|
+
opts: readOpts,
|
|
92
|
+
action(_rawArgs, rawOpts) {
|
|
93
|
+
const opts = readOpts.parse(rawOpts);
|
|
94
|
+
const { doc } = loadDoc(opts.path);
|
|
95
|
+
const result = inferLifecycleOp({ doc });
|
|
96
|
+
if (opts.json) {
|
|
97
|
+
console.log(JSON.stringify(result, null, 2));
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
console.log(pc.bold("\nLifecycle Analysis\n") +
|
|
101
|
+
pc.dim(`Early: ${String(result.summary.early)} | Middle: ${String(result.summary.middle)} | Late: ${String(result.summary.late)} | Terminal: ${String(result.summary.terminal)} | Unknown: ${String(result.summary.unknown)}`) +
|
|
102
|
+
"\n");
|
|
103
|
+
for (const n of result.nodes)
|
|
104
|
+
printLifecycleNode(n);
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
const impactSubcommand = {
|
|
109
|
+
name: "impact",
|
|
110
|
+
description: inferImpactOp.def.description,
|
|
111
|
+
apiLink: inferImpactOp.def.name,
|
|
112
|
+
args: impactArgs,
|
|
113
|
+
opts: readOpts,
|
|
114
|
+
action(rawArgs, rawOpts) {
|
|
115
|
+
const args = impactArgs.parse(rawArgs);
|
|
116
|
+
const opts = readOpts.parse(rawOpts);
|
|
117
|
+
const { doc } = loadDoc(opts.path);
|
|
118
|
+
const result = inferImpactOp({ doc, startId: args.id });
|
|
119
|
+
if (opts.json) {
|
|
120
|
+
console.log(JSON.stringify(result, null, 2));
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
console.log(pc.bold(`\nImpact Analysis from ${args.id}\n`) +
|
|
124
|
+
pc.dim(`Direct: ${String(result.summary.direct)} | Transitive: ${String(result.summary.transitive)} | Potential: ${String(result.summary.potential)} | Total: ${String(result.summary.total)}`) +
|
|
125
|
+
"\n");
|
|
126
|
+
if (result.impactedNodes.length === 0) {
|
|
127
|
+
console.log(pc.dim("No impacted nodes found"));
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
for (const n of result.impactedNodes)
|
|
131
|
+
printImpactNode(n);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
const derivedSubcommand = {
|
|
137
|
+
name: "derived",
|
|
138
|
+
description: inferDerivedOp.def.description,
|
|
139
|
+
apiLink: inferDerivedOp.def.name,
|
|
140
|
+
opts: readOpts,
|
|
141
|
+
action(_rawArgs, rawOpts) {
|
|
142
|
+
const opts = readOpts.parse(rawOpts);
|
|
143
|
+
const { doc } = loadDoc(opts.path);
|
|
144
|
+
const result = inferDerivedOp({ doc });
|
|
145
|
+
if (opts.json) {
|
|
146
|
+
console.log(JSON.stringify(result, null, 2));
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
console.log(pc.bold("\nDerived Relationships\n") +
|
|
150
|
+
pc.dim(`Transitive: ${String(result.summary.transitive)} | Composite: ${String(result.summary.composite)} | Inverse: ${String(result.summary.inverse)} | Total: ${String(result.summary.total)}`) +
|
|
151
|
+
"\n");
|
|
152
|
+
if (result.derivedRelationships.length === 0) {
|
|
153
|
+
console.log(pc.dim("No derived relationships found"));
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
for (const r of result.derivedRelationships)
|
|
157
|
+
printDerivedRelationship(r);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
const allSubcommand = {
|
|
163
|
+
name: "all",
|
|
164
|
+
description: "Run all inference analyses",
|
|
165
|
+
opts: readOpts,
|
|
166
|
+
action(_rawArgs, rawOpts) {
|
|
167
|
+
const opts = readOpts.parse(rawOpts);
|
|
168
|
+
const { doc } = loadDoc(opts.path);
|
|
169
|
+
// Completeness
|
|
170
|
+
console.log(pc.bold("\n=== Completeness ===\n"));
|
|
171
|
+
const completeness = inferCompletenessOp({ doc });
|
|
172
|
+
console.log(pc.dim(`Average score: ${(completeness.averageScore * 100).toFixed(1)}% | `) +
|
|
173
|
+
pc.green(`${String(completeness.completeNodes)} complete`) +
|
|
174
|
+
pc.dim(" | ") +
|
|
175
|
+
pc.red(`${String(completeness.incompleteNodes)} incomplete`));
|
|
176
|
+
// Lifecycle
|
|
177
|
+
console.log(pc.bold("\n=== Lifecycle ===\n"));
|
|
178
|
+
const lifecycle = inferLifecycleOp({ doc });
|
|
179
|
+
console.log(pc.dim(`Early: ${String(lifecycle.summary.early)} | Middle: ${String(lifecycle.summary.middle)} | Late: ${String(lifecycle.summary.late)} | Terminal: ${String(lifecycle.summary.terminal)} | Unknown: ${String(lifecycle.summary.unknown)}`));
|
|
180
|
+
// Derived
|
|
181
|
+
console.log(pc.bold("\n=== Derived Relationships ===\n"));
|
|
182
|
+
const derived = inferDerivedOp({ doc });
|
|
183
|
+
console.log(pc.dim(`Transitive: ${String(derived.summary.transitive)} | Composite: ${String(derived.summary.composite)} | Inverse: ${String(derived.summary.inverse)} | Total: ${String(derived.summary.total)}`));
|
|
184
|
+
if (opts.json) {
|
|
185
|
+
console.log(JSON.stringify({
|
|
186
|
+
completeness,
|
|
187
|
+
lifecycle,
|
|
188
|
+
derived,
|
|
189
|
+
}, null, 2));
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
// ---------------------------------------------------------------------------
|
|
194
|
+
// Main command
|
|
195
|
+
// ---------------------------------------------------------------------------
|
|
196
|
+
export const inferCommand = {
|
|
197
|
+
name: "infer",
|
|
198
|
+
description: "Infer completeness, lifecycle, impact, and derived relationships",
|
|
199
|
+
subcommands: [
|
|
200
|
+
completenessSubcommand,
|
|
201
|
+
lifecycleSubcommand,
|
|
202
|
+
impactSubcommand,
|
|
203
|
+
derivedSubcommand,
|
|
204
|
+
allSubcommand,
|
|
205
|
+
],
|
|
206
|
+
};
|
package/dist/src/cli/program.js
CHANGED
|
@@ -43,6 +43,7 @@ import { speckitCommand } from "./commands/speckit.js";
|
|
|
43
43
|
import { taskCommand } from "./commands/task.js";
|
|
44
44
|
import { planCommand } from "./commands/plan.js";
|
|
45
45
|
import { syncCommandDef } from "./commands/sync.js";
|
|
46
|
+
import { inferCommand } from "./commands/infer.js";
|
|
46
47
|
export const program = new Command();
|
|
47
48
|
program
|
|
48
49
|
.name("sysprom")
|
|
@@ -71,6 +72,7 @@ export const commands = [
|
|
|
71
72
|
taskCommand,
|
|
72
73
|
planCommand,
|
|
73
74
|
syncCommandDef,
|
|
75
|
+
inferCommand,
|
|
74
76
|
];
|
|
75
77
|
for (const cmd of commands) {
|
|
76
78
|
buildCommander(cmd, program);
|
package/dist/src/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* @packageDocumentation
|
|
7
7
|
*/
|
|
8
8
|
export { SysProMDocument, Node, Relationship, NodeType, NodeStatus, RelationshipType, Text, Option, Operation, Task, ExternalReference, ExternalReferenceRole, Metadata, NODE_TYPE_LABELS, NODE_LABEL_TO_TYPE, RELATIONSHIP_TYPE_LABELS, RELATIONSHIP_LABEL_TO_TYPE, EXTERNAL_REFERENCE_ROLE_LABELS, EXTERNAL_REFERENCE_LABEL_TO_ROLE, NODE_STATUSES, NODE_FILE_MAP, NODE_ID_PREFIX, toJSONSchema, } from "./schema.js";
|
|
9
|
-
export { defineOperation, type OperationDef, type DefinedOperation, addNodeOp, removeNodeOp, updateNodeOp, addRelationshipOp, removeRelationshipOp, updateMetadataOp, nextIdOp, initDocumentOp, addPlanTaskOp, updatePlanTaskOp, markTaskDoneOp, markTaskUndoneOp, taskListOp, planInitOp, planAddTaskOp, planStatusOp, planProgressOp, planGateOp, queryNodesOp, queryNodeOp, queryRelationshipsOp, traceFromNodeOp, timelineOp, nodeHistoryOp, stateAtOp, validateOp, statsOp, searchOp, checkOp, graphOp, renameOp, jsonToMarkdownOp, markdownToJsonOp, speckitImportOp, speckitExportOp, speckitSyncOp, speckitDiffOp, type RemoveResult, type ValidationResult, type DocumentStats, type NodeDetail, type TraceNode, type TimelineEvent, type NodeState, type PlanStatusResult, type PhaseProgressResult, type GateResultOutput, type SyncResult, type DiffResult, } from "./operations/index.js";
|
|
9
|
+
export { defineOperation, type OperationDef, type DefinedOperation, addNodeOp, removeNodeOp, updateNodeOp, addRelationshipOp, removeRelationshipOp, updateMetadataOp, nextIdOp, initDocumentOp, addPlanTaskOp, updatePlanTaskOp, markTaskDoneOp, markTaskUndoneOp, taskListOp, planInitOp, planAddTaskOp, planStatusOp, planProgressOp, planGateOp, queryNodesOp, queryNodeOp, queryRelationshipsOp, traceFromNodeOp, timelineOp, nodeHistoryOp, stateAtOp, validateOp, statsOp, searchOp, checkOp, graphOp, renameOp, jsonToMarkdownOp, markdownToJsonOp, speckitImportOp, speckitExportOp, speckitSyncOp, speckitDiffOp, inferCompletenessOp, inferLifecycleOp, inferImpactOp, inferDerivedOp, type RemoveResult, type ValidationResult, type DocumentStats, type NodeDetail, type TraceNode, type TimelineEvent, type NodeState, type PlanStatusResult, type PhaseProgressResult, type GateResultOutput, type SyncResult, type DiffResult, type CompletenessOutput, type LifecycleOutput, type ImpactOutput, type DerivedOutput, } from "./operations/index.js";
|
|
10
10
|
export { jsonToMarkdownSingle, jsonToMarkdownMultiDoc, jsonToMarkdown, type ConvertOptions, } from "./json-to-md.js";
|
|
11
11
|
export { markdownSingleToJson, markdownMultiDocToJson, markdownToJson, } from "./md-to-json.js";
|
|
12
12
|
export { RELATIONSHIP_ENDPOINT_TYPES, isValidEndpointPair, } from "./endpoint-types.js";
|
package/dist/src/index.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// Schema types and validators
|
|
9
9
|
export { SysProMDocument, Node, Relationship, NodeType, NodeStatus, RelationshipType, Text, Option, Operation, Task, ExternalReference, ExternalReferenceRole, Metadata, NODE_TYPE_LABELS, NODE_LABEL_TO_TYPE, RELATIONSHIP_TYPE_LABELS, RELATIONSHIP_LABEL_TO_TYPE, EXTERNAL_REFERENCE_ROLE_LABELS, EXTERNAL_REFERENCE_LABEL_TO_ROLE, NODE_STATUSES, NODE_FILE_MAP, NODE_ID_PREFIX, toJSONSchema, } from "./schema.js";
|
|
10
10
|
// Operations (single source of truth for domain logic + metadata)
|
|
11
|
-
export { defineOperation, addNodeOp, removeNodeOp, updateNodeOp, addRelationshipOp, removeRelationshipOp, updateMetadataOp, nextIdOp, initDocumentOp, addPlanTaskOp, updatePlanTaskOp, markTaskDoneOp, markTaskUndoneOp, taskListOp, planInitOp, planAddTaskOp, planStatusOp, planProgressOp, planGateOp, queryNodesOp, queryNodeOp, queryRelationshipsOp, traceFromNodeOp, timelineOp, nodeHistoryOp, stateAtOp, validateOp, statsOp, searchOp, checkOp, graphOp, renameOp, jsonToMarkdownOp, markdownToJsonOp, speckitImportOp, speckitExportOp, speckitSyncOp, speckitDiffOp, } from "./operations/index.js";
|
|
11
|
+
export { defineOperation, addNodeOp, removeNodeOp, updateNodeOp, addRelationshipOp, removeRelationshipOp, updateMetadataOp, nextIdOp, initDocumentOp, addPlanTaskOp, updatePlanTaskOp, markTaskDoneOp, markTaskUndoneOp, taskListOp, planInitOp, planAddTaskOp, planStatusOp, planProgressOp, planGateOp, queryNodesOp, queryNodeOp, queryRelationshipsOp, traceFromNodeOp, timelineOp, nodeHistoryOp, stateAtOp, validateOp, statsOp, searchOp, checkOp, graphOp, renameOp, jsonToMarkdownOp, markdownToJsonOp, speckitImportOp, speckitExportOp, speckitSyncOp, speckitDiffOp, inferCompletenessOp, inferLifecycleOp, inferImpactOp, inferDerivedOp, } from "./operations/index.js";
|
|
12
12
|
// Conversion
|
|
13
13
|
export { jsonToMarkdownSingle, jsonToMarkdownMultiDoc, jsonToMarkdown, } from "./json-to-md.js";
|
|
14
14
|
export { markdownSingleToJson, markdownMultiDocToJson, markdownToJson, } from "./md-to-json.js";
|
package/dist/src/mcp/server.js
CHANGED
|
@@ -4,7 +4,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
4
4
|
import * as z from "zod";
|
|
5
5
|
import { loadDocument, saveDocument } from "../io.js";
|
|
6
6
|
import { NodeType, RelationshipType } from "../schema.js";
|
|
7
|
-
import { validateOp, statsOp, queryNodesOp, queryNodeOp, queryRelationshipsOp, traceFromNodeOp, addNodeOp, removeNodeOp, updateNodeOp, addRelationshipOp, removeRelationshipOp, nextIdOp, } from "../operations/index.js";
|
|
7
|
+
import { validateOp, statsOp, queryNodesOp, queryNodeOp, queryRelationshipsOp, traceFromNodeOp, addNodeOp, removeNodeOp, updateNodeOp, addRelationshipOp, removeRelationshipOp, nextIdOp, inferCompletenessOp, inferLifecycleOp, inferImpactOp, inferDerivedOp, } from "../operations/index.js";
|
|
8
8
|
// Create MCP server instance
|
|
9
9
|
const server = new McpServer({
|
|
10
10
|
name: "sysprom-mcp",
|
|
@@ -318,6 +318,79 @@ server.registerTool("remove-relationship", {
|
|
|
318
318
|
],
|
|
319
319
|
};
|
|
320
320
|
});
|
|
321
|
+
// Register infer-completeness tool
|
|
322
|
+
server.registerTool("infer-completeness", {
|
|
323
|
+
description: "Infer completeness of nodes based on expected refinement relationships",
|
|
324
|
+
inputSchema: z.object({
|
|
325
|
+
path: z.string().describe("Path to SysProM file"),
|
|
326
|
+
}),
|
|
327
|
+
}, ({ path }) => {
|
|
328
|
+
const { doc } = loadDocument(path);
|
|
329
|
+
const result = inferCompletenessOp({ doc });
|
|
330
|
+
return {
|
|
331
|
+
content: [
|
|
332
|
+
{
|
|
333
|
+
type: "text",
|
|
334
|
+
text: JSON.stringify(result, null, 2),
|
|
335
|
+
},
|
|
336
|
+
],
|
|
337
|
+
};
|
|
338
|
+
});
|
|
339
|
+
// Register infer-lifecycle tool
|
|
340
|
+
server.registerTool("infer-lifecycle", {
|
|
341
|
+
description: "Infer lifecycle state for nodes based on status and lifecycle fields",
|
|
342
|
+
inputSchema: z.object({
|
|
343
|
+
path: z.string().describe("Path to SysProM file"),
|
|
344
|
+
}),
|
|
345
|
+
}, ({ path }) => {
|
|
346
|
+
const { doc } = loadDocument(path);
|
|
347
|
+
const result = inferLifecycleOp({ doc });
|
|
348
|
+
return {
|
|
349
|
+
content: [
|
|
350
|
+
{
|
|
351
|
+
type: "text",
|
|
352
|
+
text: JSON.stringify(result, null, 2),
|
|
353
|
+
},
|
|
354
|
+
],
|
|
355
|
+
};
|
|
356
|
+
});
|
|
357
|
+
// Register infer-impact tool
|
|
358
|
+
server.registerTool("infer-impact", {
|
|
359
|
+
description: "Infer impact from a node through the graph following impact relationships",
|
|
360
|
+
inputSchema: z.object({
|
|
361
|
+
path: z.string().describe("Path to SysProM file"),
|
|
362
|
+
startId: z.string().describe("Node ID to start impact analysis from"),
|
|
363
|
+
}),
|
|
364
|
+
}, ({ path, startId }) => {
|
|
365
|
+
const { doc } = loadDocument(path);
|
|
366
|
+
const result = inferImpactOp({ doc, startId });
|
|
367
|
+
return {
|
|
368
|
+
content: [
|
|
369
|
+
{
|
|
370
|
+
type: "text",
|
|
371
|
+
text: JSON.stringify(result, null, 2),
|
|
372
|
+
},
|
|
373
|
+
],
|
|
374
|
+
};
|
|
375
|
+
});
|
|
376
|
+
// Register infer-derived tool
|
|
377
|
+
server.registerTool("infer-derived", {
|
|
378
|
+
description: "Infer derived relationships from transitive closure, inverses, and composites",
|
|
379
|
+
inputSchema: z.object({
|
|
380
|
+
path: z.string().describe("Path to SysProM file"),
|
|
381
|
+
}),
|
|
382
|
+
}, ({ path }) => {
|
|
383
|
+
const { doc } = loadDocument(path);
|
|
384
|
+
const result = inferDerivedOp({ doc });
|
|
385
|
+
return {
|
|
386
|
+
content: [
|
|
387
|
+
{
|
|
388
|
+
type: "text",
|
|
389
|
+
text: JSON.stringify(result, null, 2),
|
|
390
|
+
},
|
|
391
|
+
],
|
|
392
|
+
};
|
|
393
|
+
});
|
|
321
394
|
// Start server
|
|
322
395
|
async function main() {
|
|
323
396
|
const transport = new StdioServerTransport();
|
|
@@ -37,3 +37,7 @@ export { speckitImportOp } from "./speckit-import.js";
|
|
|
37
37
|
export { speckitExportOp } from "./speckit-export.js";
|
|
38
38
|
export { speckitSyncOp, type SyncResult } from "./speckit-sync.js";
|
|
39
39
|
export { speckitDiffOp, type DiffResult } from "./speckit-diff.js";
|
|
40
|
+
export { inferCompletenessOp, type CompletenessResult, type CompletenessOutput, } from "./infer-completeness.js";
|
|
41
|
+
export { inferLifecycleOp, type LifecycleResult, type LifecycleOutput, } from "./infer-lifecycle.js";
|
|
42
|
+
export { inferImpactOp, type ImpactNode, type ImpactOutput, } from "./infer-impact.js";
|
|
43
|
+
export { inferDerivedOp, type DerivedRelationship, type DerivedOutput, } from "./infer-derived.js";
|
|
@@ -45,3 +45,8 @@ export { speckitImportOp } from "./speckit-import.js";
|
|
|
45
45
|
export { speckitExportOp } from "./speckit-export.js";
|
|
46
46
|
export { speckitSyncOp } from "./speckit-sync.js";
|
|
47
47
|
export { speckitDiffOp } from "./speckit-diff.js";
|
|
48
|
+
// Inference operations
|
|
49
|
+
export { inferCompletenessOp, } from "./infer-completeness.js";
|
|
50
|
+
export { inferLifecycleOp, } from "./infer-lifecycle.js";
|
|
51
|
+
export { inferImpactOp, } from "./infer-impact.js";
|
|
52
|
+
export { inferDerivedOp, } from "./infer-derived.js";
|