@miadi/stateloom-mcp 0.1.1
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/projectSwitch.d.ts +11 -0
- package/dist/projectSwitch.js +18 -0
- package/dist/server.d.ts +29 -0
- package/dist/server.js +866 -0
- package/dist/tests/projectSwitch.test.d.ts +1 -0
- package/dist/tests/projectSwitch.test.js +41 -0
- package/package.json +26 -0
- package/src/projectSwitch.ts +32 -0
- package/src/server.ts +1080 -0
- package/src/tests/projectSwitch.test.ts +47 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path power (HANDOFF v2, Phase 2 deliverable 1): the pure logic behind the
|
|
3
|
+
* `set_project_file` MCP tool. An agent may point the loom at any `.json`
|
|
4
|
+
* document path; the switch must absolute-resolve the path, report whether a
|
|
5
|
+
* file is already there (missing is legitimate — create_state_machine writes
|
|
6
|
+
* it next), and refuse non-JSON paths outright.
|
|
7
|
+
*/
|
|
8
|
+
import { test } from "node:test";
|
|
9
|
+
import assert from "node:assert/strict";
|
|
10
|
+
import { mkdtempSync, writeFileSync, rmSync } from "node:fs";
|
|
11
|
+
import { join, resolve } from "node:path";
|
|
12
|
+
import { tmpdir } from "node:os";
|
|
13
|
+
import { resolveProjectSwitch } from "../projectSwitch.js";
|
|
14
|
+
test("projectSwitch: relative path resolves absolute and previous is carried", () => {
|
|
15
|
+
const r = resolveProjectSwitch("./some/machine.smdf.json", "/prev/doc.smdf.json");
|
|
16
|
+
assert.equal(r.path, resolve("./some/machine.smdf.json"));
|
|
17
|
+
assert.equal(r.previous, "/prev/doc.smdf.json");
|
|
18
|
+
assert.equal(r.exists, false);
|
|
19
|
+
});
|
|
20
|
+
test("projectSwitch: reports exists=true for a file already on disk", () => {
|
|
21
|
+
const dir = mkdtempSync(join(tmpdir(), "loom-switch-"));
|
|
22
|
+
const file = join(dir, "episode.smdf.json");
|
|
23
|
+
writeFileSync(file, JSON.stringify({ stateMachine: { settings: {}, events: [], state: { name: "Root" } } }));
|
|
24
|
+
try {
|
|
25
|
+
const r = resolveProjectSwitch(file, "/prev/doc.smdf.json");
|
|
26
|
+
assert.equal(r.path, file);
|
|
27
|
+
assert.equal(r.exists, true);
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
rmSync(dir, { recursive: true, force: true });
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
test("projectSwitch: refuses a non-.json path", () => {
|
|
34
|
+
assert.throws(() => resolveProjectSwitch("/tmp/machine.yaml", "/prev/doc.smdf.json"), /\.json/);
|
|
35
|
+
});
|
|
36
|
+
test("projectSwitch: switching to the same path is allowed and reports it", () => {
|
|
37
|
+
const r = resolveProjectSwitch("/prev/doc.smdf.json", "/prev/doc.smdf.json");
|
|
38
|
+
assert.equal(r.path, "/prev/doc.smdf.json");
|
|
39
|
+
assert.equal(r.previous, "/prev/doc.smdf.json");
|
|
40
|
+
assert.equal(r.unchanged, true);
|
|
41
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@miadi/stateloom-mcp",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "MCP server for miadi-stateloom (formerly smcraft-mcp) — lets LLM agents design state machines through conversation",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/server.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"stateloom-mcp": "dist/server.js",
|
|
9
|
+
"smcraft-mcp": "dist/server.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"start": "node dist/server.js",
|
|
14
|
+
"test": "node --test dist/tests/*.test.js"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@miadi/stateloom-client": "^0.1.0",
|
|
18
|
+
"@miadi/stateloom-protocol": "^0.1.1",
|
|
19
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
20
|
+
"zod": "^4.3.6"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/node": "^22.19.13",
|
|
24
|
+
"typescript": "^5.7.0"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure logic behind the `set_project_file` MCP tool (path power — the agent
|
|
3
|
+
* chooses which `.smdf.json` document the loom weaves).
|
|
4
|
+
*/
|
|
5
|
+
import { existsSync } from "fs";
|
|
6
|
+
import { resolve } from "path";
|
|
7
|
+
|
|
8
|
+
export interface SwitchResult {
|
|
9
|
+
/** Absolute path of the newly active document. */
|
|
10
|
+
path: string;
|
|
11
|
+
/** The previously active absolute path. */
|
|
12
|
+
previous: string;
|
|
13
|
+
/** Whether a file already exists at the new path (missing is fine). */
|
|
14
|
+
exists: boolean;
|
|
15
|
+
/** True when the new path equals the previous one. */
|
|
16
|
+
unchanged: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function resolveProjectSwitch(next: string, previous: string): SwitchResult {
|
|
20
|
+
const path = resolve(next);
|
|
21
|
+
if (!path.endsWith(".json")) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
`project file must be a .json document (got '${path}') — the loom weaves .smdf.json files`,
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
path,
|
|
28
|
+
previous,
|
|
29
|
+
exists: existsSync(path),
|
|
30
|
+
unchanged: path === previous,
|
|
31
|
+
};
|
|
32
|
+
}
|