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.
Files changed (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +51 -0
  3. package/dist/adapters/agenthub/extract.d.ts +63 -0
  4. package/dist/adapters/agenthub/extract.js +144 -0
  5. package/dist/adapters/agenthub/facts.d.ts +27 -0
  6. package/dist/adapters/agenthub/facts.js +89 -0
  7. package/dist/adapters/agenthub/index.d.ts +13 -0
  8. package/dist/adapters/agenthub/index.js +18 -0
  9. package/dist/adapters/registry.d.ts +4 -0
  10. package/dist/adapters/registry.js +17 -0
  11. package/dist/adapters/types.d.ts +40 -0
  12. package/dist/adapters/types.js +2 -0
  13. package/dist/cache/content-cache.d.ts +46 -0
  14. package/dist/cache/content-cache.js +123 -0
  15. package/dist/cli/args.d.ts +7 -0
  16. package/dist/cli/args.js +26 -0
  17. package/dist/cli/assets/agent-kit.d.ts +15 -0
  18. package/dist/cli/assets/agent-kit.js +167 -0
  19. package/dist/cli/commands/check.d.ts +38 -0
  20. package/dist/cli/commands/check.js +70 -0
  21. package/dist/cli/commands/import.d.ts +6 -0
  22. package/dist/cli/commands/import.js +34 -0
  23. package/dist/cli/commands/init.d.ts +13 -0
  24. package/dist/cli/commands/init.js +70 -0
  25. package/dist/cli/commands/inspect.d.ts +23 -0
  26. package/dist/cli/commands/inspect.js +35 -0
  27. package/dist/cli/commands/snapshot.d.ts +121 -0
  28. package/dist/cli/commands/snapshot.js +0 -0
  29. package/dist/cli/commands/view.d.ts +34 -0
  30. package/dist/cli/commands/view.js +45 -0
  31. package/dist/cli/index.d.ts +3 -0
  32. package/dist/cli/index.js +19 -0
  33. package/dist/cli/run.d.ts +11 -0
  34. package/dist/cli/run.js +329 -0
  35. package/dist/loader/find-yaml-files.d.ts +26 -0
  36. package/dist/loader/find-yaml-files.js +51 -0
  37. package/dist/loader/index.d.ts +4 -0
  38. package/dist/loader/index.js +4 -0
  39. package/dist/loader/load-model.d.ts +32 -0
  40. package/dist/loader/load-model.js +54 -0
  41. package/dist/loader/model-graph.d.ts +43 -0
  42. package/dist/loader/model-graph.js +78 -0
  43. package/dist/mcp/server.d.ts +5 -0
  44. package/dist/mcp/server.js +53 -0
  45. package/dist/query/diff.d.ts +47 -0
  46. package/dist/query/diff.js +130 -0
  47. package/dist/query/effective-constraints.d.ts +48 -0
  48. package/dist/query/effective-constraints.js +81 -0
  49. package/dist/query/index.d.ts +7 -0
  50. package/dist/query/index.js +7 -0
  51. package/dist/query/queries.d.ts +111 -0
  52. package/dist/query/queries.js +172 -0
  53. package/dist/query/run-query.d.ts +16 -0
  54. package/dist/query/run-query.js +181 -0
  55. package/dist/query/side-channel.d.ts +25 -0
  56. package/dist/query/side-channel.js +46 -0
  57. package/dist/query/slice.d.ts +57 -0
  58. package/dist/query/slice.js +124 -0
  59. package/dist/query/summary.d.ts +9 -0
  60. package/dist/query/summary.js +180 -0
  61. package/dist/schema/index.d.ts +3 -0
  62. package/dist/schema/index.js +3 -0
  63. package/dist/schema/model.d.ts +661 -0
  64. package/dist/schema/model.js +183 -0
  65. package/dist/schema/status.d.ts +18 -0
  66. package/dist/schema/status.js +28 -0
  67. package/dist/staleness.d.ts +57 -0
  68. package/dist/staleness.js +148 -0
  69. package/dist/validate/anchor.d.ts +4 -0
  70. package/dist/validate/anchor.js +32 -0
  71. package/dist/validate/baseline.d.ts +11 -0
  72. package/dist/validate/baseline.js +18 -0
  73. package/dist/validate/checks.d.ts +59 -0
  74. package/dist/validate/checks.js +303 -0
  75. package/dist/validate/index.d.ts +6 -0
  76. package/dist/validate/index.js +6 -0
  77. package/dist/validate/inv1/check.d.ts +36 -0
  78. package/dist/validate/inv1/check.js +96 -0
  79. package/dist/validate/inv1/config.d.ts +75 -0
  80. package/dist/validate/inv1/config.js +63 -0
  81. package/dist/validate/inv1/scan.d.ts +49 -0
  82. package/dist/validate/inv1/scan.js +172 -0
  83. package/dist/validate/t0.d.ts +27 -0
  84. package/dist/validate/t0.js +31 -0
  85. package/dist/validate/types.d.ts +16 -0
  86. package/dist/validate/types.js +4 -0
  87. package/dist/validate/unregistered.d.ts +70 -0
  88. package/dist/validate/unregistered.js +111 -0
  89. package/dist/views/flow-mermaid.d.ts +30 -0
  90. package/dist/views/flow-mermaid.js +89 -0
  91. package/dist/views/index.d.ts +3 -0
  92. package/dist/views/index.js +3 -0
  93. package/dist/views/validate-mermaid.d.ts +39 -0
  94. package/dist/views/validate-mermaid.js +110 -0
  95. 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
+ }