@a-company/paradigm 3.21.0 → 3.22.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.
@@ -0,0 +1,160 @@
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-BPKQYSQK.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 CATEGORY_PREFIXES = {
37
+ component: "#",
38
+ flow: "$",
39
+ gate: "^",
40
+ signal: "!",
41
+ aspect: "~"
42
+ };
43
+ var NODE_W = 200;
44
+ var NODE_H = 60;
45
+ var NODE_GAP = 20;
46
+ var GPAD = 40;
47
+ var GHEADER = 50;
48
+ var GGAP = 60;
49
+ var SCAN_CATEGORY_MAP = {
50
+ components: "component",
51
+ flows: "flow",
52
+ gates: "gate",
53
+ signals: "signal",
54
+ aspects: "aspect"
55
+ };
56
+ function loadSymbolsFromIndex(projectDir) {
57
+ const indexPath = pathMod.join(projectDir, ".paradigm", "scan-index.json");
58
+ if (!fs.existsSync(indexPath)) return [];
59
+ const raw = JSON.parse(fs.readFileSync(indexPath, "utf8"));
60
+ const out = [];
61
+ for (const [sectionKey, categoryName] of Object.entries(SCAN_CATEGORY_MAP)) {
62
+ const section = raw[sectionKey];
63
+ if (!section || typeof section !== "object") continue;
64
+ for (const [id, sym] of Object.entries(section)) {
65
+ const s = sym;
66
+ out.push({ id, name: id, category: categoryName, prefix: CATEGORY_PREFIXES[categoryName] || "#", description: s.description, path: s.path });
67
+ }
68
+ }
69
+ return out;
70
+ }
71
+ function resolveSymbol(name, all) {
72
+ const stripped = name.replace(/^[#$^!~]/, "");
73
+ return all.find((s) => s.id === stripped || s.name === stripped || s.id === name || s.name === name);
74
+ }
75
+ function cliBuildGraphState(projectDir, symbolFilter, groups, links, graphName = "Generated Graph") {
76
+ const allSymbols = loadSymbolsFromIndex(projectDir);
77
+ let included = symbolFilter && symbolFilter.length > 0 ? symbolFilter.map((n) => resolveSymbol(n, allSymbols)).filter(Boolean) : allSymbols;
78
+ const nodes = [];
79
+ const edges = [];
80
+ const groupIdMap = /* @__PURE__ */ new Map();
81
+ const assigned = /* @__PURE__ */ new Set();
82
+ let nextX = 0;
83
+ if (groups && groups.length > 0) {
84
+ for (const g of groups) {
85
+ const gid = `group-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
86
+ groupIdMap.set(g.label, gid);
87
+ const members = g.symbols.map((n) => resolveSymbol(n, included)).filter(Boolean);
88
+ const cols = Math.max(Math.ceil(Math.sqrt(members.length)), 1);
89
+ const rows = Math.max(Math.ceil(members.length / cols), 1);
90
+ for (let i = 0; i < members.length; i++) {
91
+ const sym = members[i];
92
+ const c = i % cols, r = Math.floor(i / cols);
93
+ 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}` } });
94
+ assigned.add(sym.id);
95
+ }
96
+ const gw = GPAD * 2 + cols * NODE_W + (cols - 1) * NODE_GAP;
97
+ const gh = GHEADER + GPAD * 2 + rows * NODE_H + (rows - 1) * NODE_GAP;
98
+ nodes.unshift({ id: gid, type: "groupNode", position: { x: nextX, y: 0 }, style: { width: gw, height: gh }, data: { type: "group", label: g.label } });
99
+ nextX += gw + GGAP;
100
+ }
101
+ }
102
+ const ungrouped = included.filter((s) => !assigned.has(s.id));
103
+ if (ungrouped.length > 0) {
104
+ const startY = groups && groups.length > 0 ? 400 : 0;
105
+ const cols = Math.max(Math.ceil(Math.sqrt(ungrouped.length)), 1);
106
+ for (let i = 0; i < ungrouped.length; i++) {
107
+ const sym = ungrouped[i];
108
+ const c = i % cols, r = Math.floor(i / cols);
109
+ 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}` } });
110
+ }
111
+ }
112
+ if (links && links.length > 0) {
113
+ for (const l of links) {
114
+ const src = groupIdMap.get(l.source), tgt = groupIdMap.get(l.target);
115
+ if (src && tgt) edges.push({ id: `e-${src}-${tgt}`, source: src, target: tgt, type: "default", label: l.label, data: { label: l.label } });
116
+ }
117
+ }
118
+ return { version: "1.0", name: graphName, projectId: pathMod.basename(projectDir), lastModified: (/* @__PURE__ */ new Date()).toISOString(), nodes, edges };
119
+ }
120
+ async function graphGenerateCommand(path, options) {
121
+ const projectDir = path || process.cwd();
122
+ try {
123
+ const symbolFilter = options.symbols ? options.symbols.split(",").map((s) => s.trim()) : void 0;
124
+ const groups = options.group?.map((g) => {
125
+ const colonIdx = g.indexOf(":");
126
+ if (colonIdx === -1) {
127
+ console.error(chalk.red(`Invalid group format: "${g}". Expected "Label:#sym1,#sym2"`));
128
+ process.exit(1);
129
+ }
130
+ return { label: g.slice(0, colonIdx), symbols: g.slice(colonIdx + 1).split(",").map((s) => s.trim()) };
131
+ });
132
+ const links = options.link?.map((l) => {
133
+ const arrowIdx = l.indexOf(">");
134
+ if (arrowIdx === -1) {
135
+ console.error(chalk.red(`Invalid link format: "${l}". Expected "Source>Target:label"`));
136
+ process.exit(1);
137
+ }
138
+ const source = l.slice(0, arrowIdx);
139
+ const rest = l.slice(arrowIdx + 1);
140
+ const colonIdx = rest.indexOf(":");
141
+ return { source, target: colonIdx === -1 ? rest : rest.slice(0, colonIdx), label: colonIdx === -1 ? void 0 : rest.slice(colonIdx + 1) };
142
+ });
143
+ const state = cliBuildGraphState(projectDir, symbolFilter, groups, links, options.name || "Generated Graph");
144
+ const json = JSON.stringify(state, null, 2);
145
+ if (options.output) {
146
+ fs.writeFileSync(options.output, json, "utf8");
147
+ console.log(chalk.green(`Graph written to ${options.output}`));
148
+ console.log(chalk.gray(`${state.nodes.length} nodes, ${state.edges.length} edges`));
149
+ } else {
150
+ process.stdout.write(json + "\n");
151
+ }
152
+ } catch (error) {
153
+ console.error(chalk.red("Failed to generate graph:"), error.message);
154
+ process.exit(1);
155
+ }
156
+ }
157
+ export {
158
+ graphCommand,
159
+ graphGenerateCommand
160
+ };
@@ -0,0 +1,188 @@
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 path2 from "path";
7
+ import * as fs2 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/index.ts
87
+ var __filename = fileURLToPath(import.meta.url);
88
+ var __dirname = path2.dirname(__filename);
89
+ var log = {
90
+ component(name) {
91
+ const symbol = chalk.magenta(`#${name}`);
92
+ return {
93
+ info: (msg, data) => {
94
+ const dataStr = data ? chalk.gray(` ${Object.entries(data).map(([k, v]) => `${k}=${v}`).join(" ")}`) : "";
95
+ console.log(`${chalk.blue("i")} ${symbol} ${msg}${dataStr}`);
96
+ },
97
+ success: (msg, data) => {
98
+ const dataStr = data ? chalk.gray(` ${Object.entries(data).map(([k, v]) => `${k}=${v}`).join(" ")}`) : "";
99
+ console.log(`${chalk.green("+")} ${symbol} ${msg}${dataStr}`);
100
+ },
101
+ warn: (msg, data) => {
102
+ const dataStr = data ? chalk.gray(` ${Object.entries(data).map(([k, v]) => `${k}=${v}`).join(" ")}`) : "";
103
+ console.log(`${chalk.yellow("!")} ${symbol} ${msg}${dataStr}`);
104
+ },
105
+ error: (msg, data) => {
106
+ const dataStr = data ? chalk.gray(` ${Object.entries(data).map(([k, v]) => `${k}=${v}`).join(" ")}`) : "";
107
+ console.error(`${chalk.red("x")} ${symbol} ${msg}${dataStr}`);
108
+ }
109
+ };
110
+ }
111
+ };
112
+ function createGraphApp(options) {
113
+ const app = express();
114
+ app.use(express.json());
115
+ app.use((_req, res, next) => {
116
+ res.header("Access-Control-Allow-Origin", "*");
117
+ res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
118
+ res.header("Access-Control-Allow-Headers", "Content-Type");
119
+ if (_req.method === "OPTIONS") {
120
+ res.sendStatus(204);
121
+ return;
122
+ }
123
+ next();
124
+ });
125
+ app.use("/api/symbols", createSymbolsRouter(options.projectDir));
126
+ app.get("/api/health", (_req, res) => {
127
+ res.json({ status: "ok", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
128
+ });
129
+ let uiDistPath = path2.join(__dirname, "..", "graph-ui", "dist");
130
+ if (!fs2.existsSync(uiDistPath)) {
131
+ uiDistPath = path2.join(__dirname, "..", "..", "graph-ui", "dist");
132
+ }
133
+ if (fs2.existsSync(uiDistPath)) {
134
+ app.use(express.static(uiDistPath));
135
+ app.get("{*path}", (req, res) => {
136
+ if (!req.path.startsWith("/api")) {
137
+ res.sendFile(path2.join(uiDistPath, "index.html"));
138
+ }
139
+ });
140
+ } else {
141
+ app.get("/", (_req, res) => {
142
+ res.send(`
143
+ <html>
144
+ <head><title>Paradigm Graph</title></head>
145
+ <body style="background:#0a0a0f;color:#e2e8f0;font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0">
146
+ <div style="text-align:center">
147
+ <h1>Paradigm Graph</h1>
148
+ <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>
149
+ <p style="color:#94a3b8">API available at <a href="/api/symbols" style="color:#7dd3fc">/api/symbols</a></p>
150
+ </div>
151
+ </body>
152
+ </html>
153
+ `);
154
+ });
155
+ }
156
+ return app;
157
+ }
158
+ async function startGraphServer(options) {
159
+ const app = createGraphApp(options);
160
+ log.component("graph-server").info("Starting server", { port: options.port });
161
+ log.component("graph-server").info("Project directory", { path: options.projectDir });
162
+ return new Promise((resolve, reject) => {
163
+ const server = app.listen(options.port, () => {
164
+ log.component("graph-server").success("Server running", { url: `http://localhost:${options.port}` });
165
+ if (options.open) {
166
+ import("open").then((openModule) => {
167
+ openModule.default(`http://localhost:${options.port}`);
168
+ log.component("graph-server").info("Opened browser");
169
+ }).catch(() => {
170
+ log.component("graph-server").warn("Could not open browser automatically");
171
+ });
172
+ }
173
+ resolve();
174
+ });
175
+ server.on("error", (err) => {
176
+ if (err.code === "EADDRINUSE") {
177
+ log.component("graph-server").error("Port already in use", { port: options.port });
178
+ } else {
179
+ log.component("graph-server").error("Server error", { error: err.message });
180
+ }
181
+ reject(err);
182
+ });
183
+ });
184
+ }
185
+ export {
186
+ createGraphApp,
187
+ startGraphServer
188
+ };
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-BFZXFAFL.js");
665
+ await graphCommand(path2, options);
666
+ });
667
+ graphCmd.command("generate").description("Generate GraphState JSON from symbols (for agents / piping)").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)').option("-n, --name <name>", "Graph name", "Generated Graph").option("-o, --output <file>", "Write to file instead of stdout").action(async (path2, options) => {
668
+ const { graphGenerateCommand } = await import("./graph-BFZXFAFL.js");
669
+ await graphGenerateCommand(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");