loopgraph 0.1.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/LICENSE +21 -0
- package/README.md +51 -0
- package/dist/adapters/agenthub/extract.d.ts +63 -0
- package/dist/adapters/agenthub/extract.js +144 -0
- package/dist/adapters/agenthub/facts.d.ts +27 -0
- package/dist/adapters/agenthub/facts.js +89 -0
- package/dist/adapters/agenthub/index.d.ts +13 -0
- package/dist/adapters/agenthub/index.js +18 -0
- package/dist/adapters/registry.d.ts +4 -0
- package/dist/adapters/registry.js +17 -0
- package/dist/adapters/types.d.ts +40 -0
- package/dist/adapters/types.js +2 -0
- package/dist/cache/content-cache.d.ts +46 -0
- package/dist/cache/content-cache.js +123 -0
- package/dist/cli/args.d.ts +7 -0
- package/dist/cli/args.js +26 -0
- package/dist/cli/assets/agent-kit.d.ts +15 -0
- package/dist/cli/assets/agent-kit.js +167 -0
- package/dist/cli/commands/check.d.ts +38 -0
- package/dist/cli/commands/check.js +70 -0
- package/dist/cli/commands/import.d.ts +6 -0
- package/dist/cli/commands/import.js +34 -0
- package/dist/cli/commands/init.d.ts +13 -0
- package/dist/cli/commands/init.js +70 -0
- package/dist/cli/commands/inspect.d.ts +23 -0
- package/dist/cli/commands/inspect.js +35 -0
- package/dist/cli/commands/snapshot.d.ts +121 -0
- package/dist/cli/commands/snapshot.js +0 -0
- package/dist/cli/commands/view.d.ts +34 -0
- package/dist/cli/commands/view.js +45 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.js +19 -0
- package/dist/cli/run.d.ts +11 -0
- package/dist/cli/run.js +329 -0
- package/dist/loader/find-yaml-files.d.ts +26 -0
- package/dist/loader/find-yaml-files.js +51 -0
- package/dist/loader/index.d.ts +4 -0
- package/dist/loader/index.js +4 -0
- package/dist/loader/load-model.d.ts +32 -0
- package/dist/loader/load-model.js +54 -0
- package/dist/loader/model-graph.d.ts +43 -0
- package/dist/loader/model-graph.js +78 -0
- package/dist/mcp/server.d.ts +5 -0
- package/dist/mcp/server.js +53 -0
- package/dist/query/diff.d.ts +47 -0
- package/dist/query/diff.js +130 -0
- package/dist/query/effective-constraints.d.ts +48 -0
- package/dist/query/effective-constraints.js +81 -0
- package/dist/query/index.d.ts +7 -0
- package/dist/query/index.js +7 -0
- package/dist/query/queries.d.ts +111 -0
- package/dist/query/queries.js +172 -0
- package/dist/query/run-query.d.ts +16 -0
- package/dist/query/run-query.js +181 -0
- package/dist/query/side-channel.d.ts +25 -0
- package/dist/query/side-channel.js +46 -0
- package/dist/query/slice.d.ts +57 -0
- package/dist/query/slice.js +124 -0
- package/dist/query/summary.d.ts +9 -0
- package/dist/query/summary.js +180 -0
- package/dist/schema/index.d.ts +3 -0
- package/dist/schema/index.js +3 -0
- package/dist/schema/model.d.ts +661 -0
- package/dist/schema/model.js +183 -0
- package/dist/schema/status.d.ts +18 -0
- package/dist/schema/status.js +28 -0
- package/dist/staleness.d.ts +57 -0
- package/dist/staleness.js +148 -0
- package/dist/validate/anchor.d.ts +4 -0
- package/dist/validate/anchor.js +32 -0
- package/dist/validate/baseline.d.ts +11 -0
- package/dist/validate/baseline.js +18 -0
- package/dist/validate/checks.d.ts +59 -0
- package/dist/validate/checks.js +303 -0
- package/dist/validate/index.d.ts +6 -0
- package/dist/validate/index.js +6 -0
- package/dist/validate/inv1/check.d.ts +36 -0
- package/dist/validate/inv1/check.js +96 -0
- package/dist/validate/inv1/config.d.ts +75 -0
- package/dist/validate/inv1/config.js +63 -0
- package/dist/validate/inv1/scan.d.ts +49 -0
- package/dist/validate/inv1/scan.js +172 -0
- package/dist/validate/t0.d.ts +27 -0
- package/dist/validate/t0.js +31 -0
- package/dist/validate/types.d.ts +16 -0
- package/dist/validate/types.js +4 -0
- package/dist/validate/unregistered.d.ts +70 -0
- package/dist/validate/unregistered.js +111 -0
- package/dist/views/flow-mermaid.d.ts +30 -0
- package/dist/views/flow-mermaid.js +89 -0
- package/dist/views/index.d.ts +3 -0
- package/dist/views/index.js +3 -0
- package/dist/views/validate-mermaid.d.ts +39 -0
- package/dist/views/validate-mermaid.js +110 -0
- package/package.json +46 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import { createRequire } from "node:module";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { dirname, join } from "node:path";
|
|
7
|
+
import { promisify } from "node:util";
|
|
8
|
+
const execFileAsync = promisify(execFile);
|
|
9
|
+
const INSTALL_HINT = '@mermaid-js/mermaid-cli is not installed — run "pnpm add -D @mermaid-js/mermaid-cli puppeteer" to enable mermaid diagram validation';
|
|
10
|
+
/**
|
|
11
|
+
* Walks up from `fromFile` looking for the package.json whose `name`
|
|
12
|
+
* matches `packageName`. Needed because @mermaid-js/mermaid-cli's own
|
|
13
|
+
* `exports` map doesn't expose `./package.json` as a resolvable
|
|
14
|
+
* subpath (only `.` is), so `require.resolve("<pkg>/package.json")`
|
|
15
|
+
* throws even when the package is installed — this walks up from a
|
|
16
|
+
* subpath resolution that IS allowed (the package's main entry) instead
|
|
17
|
+
* of relying on an exports-restricted path.
|
|
18
|
+
*/
|
|
19
|
+
function findPackageRoot(fromFile, packageName) {
|
|
20
|
+
let dir = dirname(fromFile);
|
|
21
|
+
while (true) {
|
|
22
|
+
const candidate = join(dir, "package.json");
|
|
23
|
+
if (existsSync(candidate)) {
|
|
24
|
+
try {
|
|
25
|
+
const pkg = JSON.parse(readFileSync(candidate, "utf8"));
|
|
26
|
+
if (pkg.name === packageName)
|
|
27
|
+
return dir;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// malformed package.json at this level — keep climbing, it's not necessarily the package root
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const parent = dirname(dir);
|
|
34
|
+
if (parent === dir)
|
|
35
|
+
return undefined;
|
|
36
|
+
dir = parent;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Resolves the installed `mmdc` script's absolute path via node module
|
|
41
|
+
* resolution (not `npx`/`PATH` lookup) — deterministic regardless of the
|
|
42
|
+
* caller's cwd or shell PATH, and never reaches the network: if the
|
|
43
|
+
* package isn't resolvable, this returns undefined rather than falling
|
|
44
|
+
* back to fetching it.
|
|
45
|
+
*/
|
|
46
|
+
function resolveMmdcBin() {
|
|
47
|
+
try {
|
|
48
|
+
const require = createRequire(import.meta.url);
|
|
49
|
+
const entryPath = require.resolve("@mermaid-js/mermaid-cli"); // the "." export — always resolvable if installed
|
|
50
|
+
const pkgRoot = findPackageRoot(entryPath, "@mermaid-js/mermaid-cli");
|
|
51
|
+
if (!pkgRoot)
|
|
52
|
+
return undefined;
|
|
53
|
+
const pkg = JSON.parse(readFileSync(join(pkgRoot, "package.json"), "utf8"));
|
|
54
|
+
const binRel = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.mmdc;
|
|
55
|
+
return binRel ? join(pkgRoot, binRel) : undefined;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function extractErrorMessage(err) {
|
|
62
|
+
const withStderr = err;
|
|
63
|
+
const text = withStderr.stderr && withStderr.stderr.trim().length > 0
|
|
64
|
+
? withStderr.stderr
|
|
65
|
+
: withStderr.message;
|
|
66
|
+
return (text ?? String(err)).trim();
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Renders `mermaidText` with mermaid-cli (`mmdc`) to a throwaway SVG and
|
|
70
|
+
* reports whether it actually rendered — the "写出即验证" enforcement
|
|
71
|
+
* from Decision record 004 技术点 5. A generated diagram nobody opens
|
|
72
|
+
* until much later isn't validated, it's just written; this is the
|
|
73
|
+
* module that makes "validated" mean something.
|
|
74
|
+
*
|
|
75
|
+
* Deliberately NOT on loopgraph's default `view` CLI path (see
|
|
76
|
+
* src/cli/commands/view.ts): mmdc needs a real puppeteer-launched
|
|
77
|
+
* browser (~300MB Chromium download on first install), which the
|
|
78
|
+
* project's own lightness principle (proposal 001 §6: views generation
|
|
79
|
+
* isn't in the CI gating path) says shouldn't be a hard runtime
|
|
80
|
+
* requirement for every consumer that installs loopgraph. It's a
|
|
81
|
+
* devDependency here so loopgraph's OWN test suite can prove the
|
|
82
|
+
* generator produces valid mermaid (test/validate-mermaid.test.ts,
|
|
83
|
+
* test/view-cli.test.ts), and available to end users only when they
|
|
84
|
+
* opt in with `loopgraph view --validate` AND have separately installed
|
|
85
|
+
* `@mermaid-js/mermaid-cli` themselves.
|
|
86
|
+
*/
|
|
87
|
+
export async function validateMermaid(mermaidText, options = {}) {
|
|
88
|
+
const bin = options.mmdcBinPath ?? resolveMmdcBin();
|
|
89
|
+
if (!bin || !existsSync(bin))
|
|
90
|
+
return { status: "unavailable", reason: INSTALL_HINT };
|
|
91
|
+
const dir = await mkdtemp(join(tmpdir(), "loopgraph-mmdc-"));
|
|
92
|
+
try {
|
|
93
|
+
const inputPath = join(dir, "diagram.mmd");
|
|
94
|
+
const outputPath = join(dir, "diagram.svg");
|
|
95
|
+
await writeFile(inputPath, mermaidText, "utf8");
|
|
96
|
+
try {
|
|
97
|
+
await execFileAsync(process.execPath, [bin, "-i", inputPath, "-o", outputPath], {
|
|
98
|
+
timeout: 60_000,
|
|
99
|
+
});
|
|
100
|
+
return { status: "valid" };
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
return { status: "invalid", error: extractErrorMessage(err) };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
finally {
|
|
107
|
+
await rm(dir, { recursive: true, force: true });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=validate-mermaid.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "loopgraph",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Model-driven engineering control system: behavioral model as spec source of truth, code/tests/observability as projections and evidence.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"bin": {
|
|
8
|
+
"loopgraph": "dist/cli/index.js"
|
|
9
|
+
},
|
|
10
|
+
"//files": "Ship the dist engine only; seeds/examples/research/docs are excluded so the published package carries no target-repo internals.",
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"!dist/**/*.map"
|
|
14
|
+
],
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=22.0.0"
|
|
17
|
+
},
|
|
18
|
+
"packageManager": "pnpm@10.17.1",
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc -p tsconfig.build.json",
|
|
21
|
+
"test": "vitest run",
|
|
22
|
+
"test:watch": "vitest",
|
|
23
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
24
|
+
"lint": "biome check .",
|
|
25
|
+
"lint:fix": "biome check --write ."
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
29
|
+
"typescript": "5.9.3",
|
|
30
|
+
"yaml": "^2.6.1",
|
|
31
|
+
"zod": "^3.24.1"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@biomejs/biome": "^1.9.4",
|
|
35
|
+
"@mermaid-js/mermaid-cli": "^11.16.0",
|
|
36
|
+
"@types/node": "^22.10.5",
|
|
37
|
+
"puppeteer": "^25.3.0",
|
|
38
|
+
"tsx": "^4.19.2",
|
|
39
|
+
"vitest": "^2.1.8"
|
|
40
|
+
},
|
|
41
|
+
"pnpm": {
|
|
42
|
+
"onlyBuiltDependencies": [
|
|
43
|
+
"puppeteer"
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
}
|