@a-company/paradigm 3.21.0 → 3.23.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/dist/graph-5VSRBRKZ.js +163 -0
- package/dist/graph-server-BZ73HTAT.js +251 -0
- package/dist/index.js +8 -0
- package/dist/mcp.js +277 -16
- package/graph-ui/dist/assets/index-BlgXTl53.css +1 -0
- package/graph-ui/dist/assets/index-Bq5nXK8p.js +63 -0
- package/graph-ui/dist/index.html +13 -0
- package/package.json +4 -2
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "./chunk-ZXMDA7VB.js";
|
|
3
|
+
|
|
4
|
+
// src/commands/graph.ts
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
import * as fs from "fs";
|
|
7
|
+
import * as pathMod from "path";
|
|
8
|
+
async function graphCommand(path, options) {
|
|
9
|
+
const projectDir = path || process.cwd();
|
|
10
|
+
const port = parseInt(options.port || "3841", 10);
|
|
11
|
+
const shouldOpen = options.open !== false;
|
|
12
|
+
console.log(chalk.cyan("\nStarting Symbol Graph...\n"));
|
|
13
|
+
try {
|
|
14
|
+
const { startGraphServer } = await import("./graph-server-BZ73HTAT.js");
|
|
15
|
+
console.log(chalk.gray(`Project: ${projectDir}`));
|
|
16
|
+
console.log(chalk.gray(`Port: ${port}`));
|
|
17
|
+
console.log();
|
|
18
|
+
await startGraphServer({ port, projectDir, open: shouldOpen });
|
|
19
|
+
console.log(chalk.green(`
|
|
20
|
+
Symbol Graph is running at http://localhost:${port}`));
|
|
21
|
+
console.log(chalk.gray("\nPress Ctrl+C to stop\n"));
|
|
22
|
+
await new Promise(() => {
|
|
23
|
+
});
|
|
24
|
+
} catch (error) {
|
|
25
|
+
if (error.code === "EADDRINUSE") {
|
|
26
|
+
console.error(chalk.red(`
|
|
27
|
+
Error: Port ${port} is already in use.`));
|
|
28
|
+
console.log(chalk.gray(`Try: paradigm graph --port ${port + 1}
|
|
29
|
+
`));
|
|
30
|
+
} else {
|
|
31
|
+
console.error(chalk.red("\nFailed to start Symbol Graph:"), error);
|
|
32
|
+
}
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
var GRAPHS_DIR = ".paradigm/graphs";
|
|
37
|
+
var CATEGORY_PREFIXES = {
|
|
38
|
+
component: "#",
|
|
39
|
+
flow: "$",
|
|
40
|
+
gate: "^",
|
|
41
|
+
signal: "!",
|
|
42
|
+
aspect: "~"
|
|
43
|
+
};
|
|
44
|
+
var NODE_W = 200;
|
|
45
|
+
var NODE_H = 60;
|
|
46
|
+
var NODE_GAP = 20;
|
|
47
|
+
var GPAD = 40;
|
|
48
|
+
var GHEADER = 50;
|
|
49
|
+
var GGAP = 60;
|
|
50
|
+
var SCAN_CATEGORY_MAP = {
|
|
51
|
+
components: "component",
|
|
52
|
+
flows: "flow",
|
|
53
|
+
gates: "gate",
|
|
54
|
+
signals: "signal",
|
|
55
|
+
aspects: "aspect"
|
|
56
|
+
};
|
|
57
|
+
function loadSymbolsFromIndex(projectDir) {
|
|
58
|
+
const indexPath = pathMod.join(projectDir, ".paradigm", "scan-index.json");
|
|
59
|
+
if (!fs.existsSync(indexPath)) return [];
|
|
60
|
+
const raw = JSON.parse(fs.readFileSync(indexPath, "utf8"));
|
|
61
|
+
const out = [];
|
|
62
|
+
for (const [sectionKey, categoryName] of Object.entries(SCAN_CATEGORY_MAP)) {
|
|
63
|
+
const section = raw[sectionKey];
|
|
64
|
+
if (!section || typeof section !== "object") continue;
|
|
65
|
+
for (const [id, sym] of Object.entries(section)) {
|
|
66
|
+
const s = sym;
|
|
67
|
+
out.push({ id, name: id, category: categoryName, prefix: CATEGORY_PREFIXES[categoryName] || "#", description: s.description, path: s.path });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
function resolveSymbol(name, all) {
|
|
73
|
+
const stripped = name.replace(/^[#$^!~]/, "");
|
|
74
|
+
return all.find((s) => s.id === stripped || s.name === stripped || s.id === name || s.name === name);
|
|
75
|
+
}
|
|
76
|
+
function cliBuildGraphState(projectDir, symbolFilter, groups, links, graphName = "Generated Graph") {
|
|
77
|
+
const allSymbols = loadSymbolsFromIndex(projectDir);
|
|
78
|
+
let included = symbolFilter && symbolFilter.length > 0 ? symbolFilter.map((n) => resolveSymbol(n, allSymbols)).filter(Boolean) : allSymbols;
|
|
79
|
+
const nodes = [];
|
|
80
|
+
const edges = [];
|
|
81
|
+
const groupIdMap = /* @__PURE__ */ new Map();
|
|
82
|
+
const assigned = /* @__PURE__ */ new Set();
|
|
83
|
+
let nextX = 0;
|
|
84
|
+
if (groups && groups.length > 0) {
|
|
85
|
+
for (const g of groups) {
|
|
86
|
+
const gid = `group-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
|
|
87
|
+
groupIdMap.set(g.label, gid);
|
|
88
|
+
const members = g.symbols.map((n) => resolveSymbol(n, included)).filter(Boolean);
|
|
89
|
+
const cols = Math.max(Math.ceil(Math.sqrt(members.length)), 1);
|
|
90
|
+
const rows = Math.max(Math.ceil(members.length / cols), 1);
|
|
91
|
+
for (let i = 0; i < members.length; i++) {
|
|
92
|
+
const sym = members[i];
|
|
93
|
+
const c = i % cols, r = Math.floor(i / cols);
|
|
94
|
+
nodes.push({ id: `sym-${sym.id}`, type: "symbolNode", position: { x: GPAD + c * (NODE_W + NODE_GAP), y: GHEADER + GPAD + r * (NODE_H + NODE_GAP) }, parentId: gid, data: { type: "symbol", symbol: sym, label: `${CATEGORY_PREFIXES[sym.category] || "#"}${sym.name}` } });
|
|
95
|
+
assigned.add(sym.id);
|
|
96
|
+
}
|
|
97
|
+
const gw = GPAD * 2 + cols * NODE_W + (cols - 1) * NODE_GAP;
|
|
98
|
+
const gh = GHEADER + GPAD * 2 + rows * NODE_H + (rows - 1) * NODE_GAP;
|
|
99
|
+
nodes.unshift({ id: gid, type: "groupNode", position: { x: nextX, y: 0 }, style: { width: gw, height: gh }, data: { type: "group", label: g.label } });
|
|
100
|
+
nextX += gw + GGAP;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const ungrouped = included.filter((s) => !assigned.has(s.id));
|
|
104
|
+
if (ungrouped.length > 0) {
|
|
105
|
+
const startY = groups && groups.length > 0 ? 400 : 0;
|
|
106
|
+
const cols = Math.max(Math.ceil(Math.sqrt(ungrouped.length)), 1);
|
|
107
|
+
for (let i = 0; i < ungrouped.length; i++) {
|
|
108
|
+
const sym = ungrouped[i];
|
|
109
|
+
const c = i % cols, r = Math.floor(i / cols);
|
|
110
|
+
nodes.push({ id: `sym-${sym.id}`, type: "symbolNode", position: { x: c * (NODE_W + NODE_GAP), y: startY + r * (NODE_H + NODE_GAP) }, data: { type: "symbol", symbol: sym, label: `${CATEGORY_PREFIXES[sym.category] || "#"}${sym.name}` } });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (links && links.length > 0) {
|
|
114
|
+
for (const l of links) {
|
|
115
|
+
const src = groupIdMap.get(l.source), tgt = groupIdMap.get(l.target);
|
|
116
|
+
if (src && tgt) edges.push({ id: `e-${src}-${tgt}`, source: src, target: tgt, type: "default", label: l.label, data: { label: l.label } });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return { version: "1.0", name: graphName, projectId: pathMod.basename(projectDir), lastModified: (/* @__PURE__ */ new Date()).toISOString(), nodes, edges };
|
|
120
|
+
}
|
|
121
|
+
async function graphGenerateCommand(name, path, options) {
|
|
122
|
+
const projectDir = path || process.cwd();
|
|
123
|
+
const slug = name.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
124
|
+
try {
|
|
125
|
+
const symbolFilter = options.symbols ? options.symbols.split(",").map((s) => s.trim()) : void 0;
|
|
126
|
+
const groups = options.group?.map((g) => {
|
|
127
|
+
const colonIdx = g.indexOf(":");
|
|
128
|
+
if (colonIdx === -1) {
|
|
129
|
+
console.error(chalk.red(`Invalid group format: "${g}". Expected "Label:#sym1,#sym2"`));
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
return { label: g.slice(0, colonIdx), symbols: g.slice(colonIdx + 1).split(",").map((s) => s.trim()) };
|
|
133
|
+
});
|
|
134
|
+
const links = options.link?.map((l) => {
|
|
135
|
+
const arrowIdx = l.indexOf(">");
|
|
136
|
+
if (arrowIdx === -1) {
|
|
137
|
+
console.error(chalk.red(`Invalid link format: "${l}". Expected "Source>Target:label"`));
|
|
138
|
+
process.exit(1);
|
|
139
|
+
}
|
|
140
|
+
const source = l.slice(0, arrowIdx);
|
|
141
|
+
const rest = l.slice(arrowIdx + 1);
|
|
142
|
+
const colonIdx = rest.indexOf(":");
|
|
143
|
+
return { source, target: colonIdx === -1 ? rest : rest.slice(0, colonIdx), label: colonIdx === -1 ? void 0 : rest.slice(colonIdx + 1) };
|
|
144
|
+
});
|
|
145
|
+
const state = cliBuildGraphState(projectDir, symbolFilter, groups, links, name);
|
|
146
|
+
const json = JSON.stringify(state, null, 2);
|
|
147
|
+
const graphsDir = pathMod.join(projectDir, GRAPHS_DIR);
|
|
148
|
+
if (!fs.existsSync(graphsDir)) fs.mkdirSync(graphsDir, { recursive: true });
|
|
149
|
+
const outPath = pathMod.join(graphsDir, `${slug}.graph.json`);
|
|
150
|
+
fs.writeFileSync(outPath, json, "utf8");
|
|
151
|
+
console.log(chalk.green(`Graph saved to ${outPath}`));
|
|
152
|
+
console.log(chalk.gray(`${state.nodes.length} nodes, ${state.edges.length} edges, ${(json.length / 1024).toFixed(1)} KB`));
|
|
153
|
+
console.log(chalk.gray(`
|
|
154
|
+
View: paradigm graph`));
|
|
155
|
+
} catch (error) {
|
|
156
|
+
console.error(chalk.red("Failed to generate graph:"), error.message);
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
export {
|
|
161
|
+
graphCommand,
|
|
162
|
+
graphGenerateCommand
|
|
163
|
+
};
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "./chunk-ZXMDA7VB.js";
|
|
3
|
+
|
|
4
|
+
// src/graph-server/index.ts
|
|
5
|
+
import express from "express";
|
|
6
|
+
import * as path3 from "path";
|
|
7
|
+
import * as fs3 from "fs";
|
|
8
|
+
import { fileURLToPath } from "url";
|
|
9
|
+
import chalk from "chalk";
|
|
10
|
+
|
|
11
|
+
// src/graph-server/routes/symbols.ts
|
|
12
|
+
import { Router } from "express";
|
|
13
|
+
import * as fs from "fs";
|
|
14
|
+
import * as path from "path";
|
|
15
|
+
function createSymbolsRouter(projectDir) {
|
|
16
|
+
const router = Router();
|
|
17
|
+
router.get("/", (_req, res) => {
|
|
18
|
+
const indexPath = path.join(projectDir, ".paradigm", "scan-index.json");
|
|
19
|
+
if (!fs.existsSync(indexPath)) {
|
|
20
|
+
res.status(404).json({
|
|
21
|
+
error: "scan-index.json not found",
|
|
22
|
+
hint: "Run `paradigm scan` to generate the symbol index."
|
|
23
|
+
});
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const raw = fs.readFileSync(indexPath, "utf-8");
|
|
28
|
+
const index = JSON.parse(raw);
|
|
29
|
+
const categoryMap = {
|
|
30
|
+
components: "component",
|
|
31
|
+
features: "component",
|
|
32
|
+
flows: "flow",
|
|
33
|
+
state: "component",
|
|
34
|
+
gates: "gate",
|
|
35
|
+
signals: "signal",
|
|
36
|
+
aspects: "aspect",
|
|
37
|
+
screens: "component"
|
|
38
|
+
};
|
|
39
|
+
const prefixMap = {
|
|
40
|
+
component: "#",
|
|
41
|
+
flow: "$",
|
|
42
|
+
gate: "^",
|
|
43
|
+
signal: "!",
|
|
44
|
+
aspect: "~"
|
|
45
|
+
};
|
|
46
|
+
const symbols = [];
|
|
47
|
+
const seen = /* @__PURE__ */ new Set();
|
|
48
|
+
for (const [sectionKey, category] of Object.entries(categoryMap)) {
|
|
49
|
+
const entries = index[sectionKey];
|
|
50
|
+
if (!entries || typeof entries !== "object") continue;
|
|
51
|
+
const items = Array.isArray(entries) ? entries : Object.values(entries);
|
|
52
|
+
for (const entry of items) {
|
|
53
|
+
const name = entry.name || entry.id || "";
|
|
54
|
+
if (!name || seen.has(name)) continue;
|
|
55
|
+
seen.add(name);
|
|
56
|
+
symbols.push({
|
|
57
|
+
id: name,
|
|
58
|
+
name,
|
|
59
|
+
category,
|
|
60
|
+
prefix: prefixMap[category] || "#",
|
|
61
|
+
description: entry.description || "",
|
|
62
|
+
path: entry.path || entry.file || "",
|
|
63
|
+
tags: entry.tags || [],
|
|
64
|
+
related: entry.related || []
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
res.json({
|
|
69
|
+
symbols,
|
|
70
|
+
meta: {
|
|
71
|
+
total: symbols.length,
|
|
72
|
+
projectDir,
|
|
73
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
} catch (err) {
|
|
77
|
+
res.status(500).json({
|
|
78
|
+
error: "Failed to read scan-index.json",
|
|
79
|
+
details: err.message
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
return router;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// src/graph-server/routes/graphs.ts
|
|
87
|
+
import { Router as Router2 } from "express";
|
|
88
|
+
import * as fs2 from "fs";
|
|
89
|
+
import * as path2 from "path";
|
|
90
|
+
var GRAPHS_DIR = ".paradigm/graphs";
|
|
91
|
+
function createGraphsRouter(projectDir) {
|
|
92
|
+
const router = Router2();
|
|
93
|
+
const graphsPath = path2.join(projectDir, GRAPHS_DIR);
|
|
94
|
+
router.get("/", (_req, res) => {
|
|
95
|
+
if (!fs2.existsSync(graphsPath)) {
|
|
96
|
+
res.json({ graphs: [] });
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
const files = fs2.readdirSync(graphsPath).filter((f) => f.endsWith(".graph.json"));
|
|
101
|
+
const graphs = files.map((file) => {
|
|
102
|
+
const filePath = path2.join(graphsPath, file);
|
|
103
|
+
const stat = fs2.statSync(filePath);
|
|
104
|
+
const slug = file.replace(/\.graph\.json$/, "");
|
|
105
|
+
let name = slug;
|
|
106
|
+
let nodeCount = 0;
|
|
107
|
+
let edgeCount = 0;
|
|
108
|
+
try {
|
|
109
|
+
const raw = JSON.parse(fs2.readFileSync(filePath, "utf8"));
|
|
110
|
+
name = raw.name || slug;
|
|
111
|
+
nodeCount = Array.isArray(raw.nodes) ? raw.nodes.length : 0;
|
|
112
|
+
edgeCount = Array.isArray(raw.edges) ? raw.edges.length : 0;
|
|
113
|
+
} catch {
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
slug,
|
|
117
|
+
file,
|
|
118
|
+
name,
|
|
119
|
+
nodes: nodeCount,
|
|
120
|
+
edges: edgeCount,
|
|
121
|
+
size: stat.size,
|
|
122
|
+
modified: stat.mtime.toISOString()
|
|
123
|
+
};
|
|
124
|
+
});
|
|
125
|
+
graphs.sort((a, b) => b.modified.localeCompare(a.modified));
|
|
126
|
+
res.json({ graphs });
|
|
127
|
+
} catch (err) {
|
|
128
|
+
res.status(500).json({ error: "Failed to list graphs", details: err.message });
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
router.get("/:slug", (req, res) => {
|
|
132
|
+
const slug = req.params.slug;
|
|
133
|
+
const filePath = path2.join(graphsPath, `${slug}.graph.json`);
|
|
134
|
+
if (!fs2.existsSync(filePath)) {
|
|
135
|
+
res.status(404).json({ error: `Graph "${slug}" not found` });
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
const raw = fs2.readFileSync(filePath, "utf8");
|
|
140
|
+
res.type("application/json").send(raw);
|
|
141
|
+
} catch (err) {
|
|
142
|
+
res.status(500).json({ error: "Failed to read graph", details: err.message });
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
return router;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// src/graph-server/index.ts
|
|
149
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
150
|
+
var __dirname = path3.dirname(__filename);
|
|
151
|
+
var log = {
|
|
152
|
+
component(name) {
|
|
153
|
+
const symbol = chalk.magenta(`#${name}`);
|
|
154
|
+
return {
|
|
155
|
+
info: (msg, data) => {
|
|
156
|
+
const dataStr = data ? chalk.gray(` ${Object.entries(data).map(([k, v]) => `${k}=${v}`).join(" ")}`) : "";
|
|
157
|
+
console.log(`${chalk.blue("i")} ${symbol} ${msg}${dataStr}`);
|
|
158
|
+
},
|
|
159
|
+
success: (msg, data) => {
|
|
160
|
+
const dataStr = data ? chalk.gray(` ${Object.entries(data).map(([k, v]) => `${k}=${v}`).join(" ")}`) : "";
|
|
161
|
+
console.log(`${chalk.green("+")} ${symbol} ${msg}${dataStr}`);
|
|
162
|
+
},
|
|
163
|
+
warn: (msg, data) => {
|
|
164
|
+
const dataStr = data ? chalk.gray(` ${Object.entries(data).map(([k, v]) => `${k}=${v}`).join(" ")}`) : "";
|
|
165
|
+
console.log(`${chalk.yellow("!")} ${symbol} ${msg}${dataStr}`);
|
|
166
|
+
},
|
|
167
|
+
error: (msg, data) => {
|
|
168
|
+
const dataStr = data ? chalk.gray(` ${Object.entries(data).map(([k, v]) => `${k}=${v}`).join(" ")}`) : "";
|
|
169
|
+
console.error(`${chalk.red("x")} ${symbol} ${msg}${dataStr}`);
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
function createGraphApp(options) {
|
|
175
|
+
const app = express();
|
|
176
|
+
app.use(express.json());
|
|
177
|
+
app.use((_req, res, next) => {
|
|
178
|
+
res.header("Access-Control-Allow-Origin", "*");
|
|
179
|
+
res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
|
|
180
|
+
res.header("Access-Control-Allow-Headers", "Content-Type");
|
|
181
|
+
if (_req.method === "OPTIONS") {
|
|
182
|
+
res.sendStatus(204);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
next();
|
|
186
|
+
});
|
|
187
|
+
app.use("/api/symbols", createSymbolsRouter(options.projectDir));
|
|
188
|
+
app.use("/api/graphs", createGraphsRouter(options.projectDir));
|
|
189
|
+
app.get("/api/health", (_req, res) => {
|
|
190
|
+
res.json({ status: "ok", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
191
|
+
});
|
|
192
|
+
let uiDistPath = path3.join(__dirname, "..", "graph-ui", "dist");
|
|
193
|
+
if (!fs3.existsSync(uiDistPath)) {
|
|
194
|
+
uiDistPath = path3.join(__dirname, "..", "..", "graph-ui", "dist");
|
|
195
|
+
}
|
|
196
|
+
if (fs3.existsSync(uiDistPath)) {
|
|
197
|
+
app.use(express.static(uiDistPath));
|
|
198
|
+
app.get("{*path}", (req, res) => {
|
|
199
|
+
if (!req.path.startsWith("/api")) {
|
|
200
|
+
res.sendFile(path3.join(uiDistPath, "index.html"));
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
} else {
|
|
204
|
+
app.get("/", (_req, res) => {
|
|
205
|
+
res.send(`
|
|
206
|
+
<html>
|
|
207
|
+
<head><title>Paradigm Graph</title></head>
|
|
208
|
+
<body style="background:#0a0a0f;color:#e2e8f0;font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0">
|
|
209
|
+
<div style="text-align:center">
|
|
210
|
+
<h1>Paradigm Graph</h1>
|
|
211
|
+
<p style="color:#94a3b8">UI not built yet. Run <code style="background:#1e293b;padding:4px 8px;border-radius:4px">cd graph-ui && npx vite build</code></p>
|
|
212
|
+
<p style="color:#94a3b8">API available at <a href="/api/symbols" style="color:#7dd3fc">/api/symbols</a></p>
|
|
213
|
+
</div>
|
|
214
|
+
</body>
|
|
215
|
+
</html>
|
|
216
|
+
`);
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
return app;
|
|
220
|
+
}
|
|
221
|
+
async function startGraphServer(options) {
|
|
222
|
+
const app = createGraphApp(options);
|
|
223
|
+
log.component("graph-server").info("Starting server", { port: options.port });
|
|
224
|
+
log.component("graph-server").info("Project directory", { path: options.projectDir });
|
|
225
|
+
return new Promise((resolve, reject) => {
|
|
226
|
+
const server = app.listen(options.port, () => {
|
|
227
|
+
log.component("graph-server").success("Server running", { url: `http://localhost:${options.port}` });
|
|
228
|
+
if (options.open) {
|
|
229
|
+
import("open").then((openModule) => {
|
|
230
|
+
openModule.default(`http://localhost:${options.port}`);
|
|
231
|
+
log.component("graph-server").info("Opened browser");
|
|
232
|
+
}).catch(() => {
|
|
233
|
+
log.component("graph-server").warn("Could not open browser automatically");
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
resolve();
|
|
237
|
+
});
|
|
238
|
+
server.on("error", (err) => {
|
|
239
|
+
if (err.code === "EADDRINUSE") {
|
|
240
|
+
log.component("graph-server").error("Port already in use", { port: options.port });
|
|
241
|
+
} else {
|
|
242
|
+
log.component("graph-server").error("Server error", { error: err.message });
|
|
243
|
+
}
|
|
244
|
+
reject(err);
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
export {
|
|
249
|
+
createGraphApp,
|
|
250
|
+
startGraphServer
|
|
251
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -660,6 +660,14 @@ loreCmd.option("-p, --port <port>", "Port to run on", "3840").option("--no-open"
|
|
|
660
660
|
const { loreServeCommand } = await import("./serve-DIALBCTU.js");
|
|
661
661
|
await loreServeCommand(void 0, options);
|
|
662
662
|
});
|
|
663
|
+
var graphCmd = program.command("graph").description("Interactive symbol relationship graph").argument("[path]", "Project directory", void 0).option("-p, --port <port>", "Port to run on", "3841").option("--no-open", "Don't open browser automatically").action(async (path2, options) => {
|
|
664
|
+
const { graphCommand } = await import("./graph-5VSRBRKZ.js");
|
|
665
|
+
await graphCommand(path2, options);
|
|
666
|
+
});
|
|
667
|
+
graphCmd.command("generate").description("Generate a named graph file in .paradigm/graphs/").argument("<name>", "Graph name (used as filename: {name}.graph.json)").argument("[path]", "Project directory", void 0).option("-s, --symbols <list>", "Comma-separated symbol names to include").option("-g, --group <spec...>", 'Group spec: "Label:#sym1,#sym2" (repeatable)').option("-l, --link <spec...>", 'Link spec: "Source>Target:label" (repeatable)').action(async (name, path2, options) => {
|
|
668
|
+
const { graphGenerateCommand } = await import("./graph-5VSRBRKZ.js");
|
|
669
|
+
await graphGenerateCommand(name, path2, options);
|
|
670
|
+
});
|
|
663
671
|
var habitsCmd = program.command("habits").description("Behavioral habits - practice tracking and compliance");
|
|
664
672
|
habitsCmd.command("list").alias("ls").description("List all configured habits").option("--trigger <trigger>", "Filter by trigger: preflight, postflight, on-stop, on-commit").option("--category <category>", "Filter by category: discovery, verification, testing, documentation, collaboration, security").option("--json", "Output as JSON").action(async (options) => {
|
|
665
673
|
const { habitsListCommand } = await import("./habits-7BORPC2F.js");
|