@toolbaux/guardian 0.1.12 → 0.1.13

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.
@@ -103,27 +103,94 @@ const SKIP_SERVICES = new Set(["str", "dict", "int", "len", "float", "max", "joi
103
103
  function compact(obj) {
104
104
  return JSON.stringify(obj);
105
105
  }
106
+ function normalize(p) {
107
+ return p.replace(/^\.\//, "").replace(/\/\//g, "/");
108
+ }
106
109
  function findModule(data, file) {
107
- return data.service_map?.find((m) => m.path && file.replace(/^\.\//, "").startsWith(m.path.replace(/^\.\//, "")));
110
+ const f = normalize(file);
111
+ return data.service_map?.find((m) => {
112
+ const mp = normalize(m.path || "");
113
+ return mp && (f.startsWith(mp + "/") || f === mp);
114
+ }) || data.service_map?.find((m) => {
115
+ // Fallback: match by module ID (handles doubled paths)
116
+ const mid = normalize(m.id || "");
117
+ return mid && f.includes(mid);
118
+ });
108
119
  }
109
120
  function findEndpointsInFile(data, file) {
110
- const f = file.replace(/^\.\//, "");
111
- return Object.values(data.api_registry || {}).filter((ep) => ep.file && f.includes(ep.file.replace(/^\.\//, "")));
121
+ const f = normalize(file);
122
+ const basename = path.basename(f);
123
+ return Object.values(data.api_registry || {}).filter((ep) => {
124
+ const ef = normalize(ep.file || "");
125
+ return ef && (f.includes(ef) || ef.includes(f) || ef.endsWith(basename));
126
+ });
112
127
  }
113
128
  function findModelsInFile(data, file) {
114
- const f = file.replace(/^\.\//, "");
115
- return Object.values(data.model_registry || {}).filter((m) => m.file && f.includes(m.file.replace(/^\.\//, "")));
129
+ const f = normalize(file);
130
+ const basename = path.basename(f);
131
+ return Object.values(data.model_registry || {}).filter((m) => {
132
+ const mf = normalize(m.file || "");
133
+ return mf && (f.includes(mf) || mf.includes(f) || mf.endsWith(basename));
134
+ });
116
135
  }
117
136
  // ── Tool implementations (compact JSON, no redundancy) ──
118
137
  async function orient() {
138
+ // Read architecture-context.md first — it has the richest summary
139
+ const contextPath = path.join(path.dirname(intelPath), "architecture-context.md");
140
+ try {
141
+ const raw = await fs.readFile(contextPath, "utf8");
142
+ // Extract the content between guardian:context markers
143
+ const match = raw.match(/<!-- guardian:context[^>]*-->([\s\S]*?)<!-- \/guardian:context -->/);
144
+ if (match) {
145
+ // Parse the markdown into compact structured data
146
+ const content = match[1];
147
+ const lines = content.split("\n").map((l) => l.trim()).filter(Boolean);
148
+ // Extract key sections
149
+ const desc = raw.match(/Description: (.+)/)?.[1] || "";
150
+ const codeMap = lines.find((l) => l.startsWith("**Backend:**")) || "";
151
+ // Module map with exports
152
+ const moduleLines = lines.filter((l) => l.startsWith("- **backend/") || l.startsWith("- **frontend/"));
153
+ const modules = moduleLines.map((l) => {
154
+ const m = l.match(/\*\*([^*]+)\*\*\s*\(([^)]+)\)\s*[—–-]\s*(.*)/);
155
+ return m ? [m[1], m[2], m[3].slice(0, 60)] : null;
156
+ }).filter(Boolean);
157
+ // Dependencies
158
+ const deps = lines.filter((l) => l.includes("→")).map((l) => l.replace(/^- /, ""));
159
+ // High-coupling files
160
+ const coupling = lines.filter((l) => l.match(/score \d/)).map((l) => l.replace(/^- /, ""));
161
+ // Structural intelligence
162
+ const si = lines.filter((l) => l.includes("depth=")).map((l) => l.replace(/^- /, ""));
163
+ // Model-endpoint map
164
+ const modelEp = lines.filter((l) => l.includes("endpoints) ->")).map((l) => l.replace(/^- /, ""));
165
+ return compact({
166
+ desc: desc.slice(0, 120),
167
+ map: codeMap,
168
+ modules,
169
+ deps,
170
+ coupling: coupling.slice(0, 5),
171
+ si: si.slice(0, 5),
172
+ modelEp,
173
+ });
174
+ }
175
+ }
176
+ catch { }
177
+ // Fallback: build from codebase-intelligence.json
119
178
  const d = await loadIntel();
120
179
  const c = d.meta?.counts || {};
180
+ // Compute endpoint counts from api_registry (service_map counts are often 0)
181
+ const epByMod = {};
182
+ for (const ep of Object.values(d.api_registry || {})) {
183
+ epByMod[ep.module] = (epByMod[ep.module] || 0) + 1;
184
+ }
121
185
  const mods = (d.service_map || []).filter((m) => m.file_count > 0);
122
- const topMods = mods.sort((a, b) => (b.endpoint_count || 0) - (a.endpoint_count || 0)).slice(0, 6);
186
+ const topMods = mods
187
+ .map((m) => ({ ...m, ep_count: epByMod[m.id] || 0 }))
188
+ .sort((a, b) => b.ep_count - a.ep_count)
189
+ .slice(0, 6);
123
190
  return compact({
124
191
  p: d.meta?.project,
125
192
  ep: c.endpoints, mod: c.models, pg: c.pages, m: c.modules,
126
- top: topMods.map((m) => [m.id, m.endpoint_count, m.layer]),
193
+ top: topMods.map((m) => [m.id, m.ep_count, m.layer]),
127
194
  pages: (d.frontend_pages || []).map((p) => p.path),
128
195
  });
129
196
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toolbaux/guardian",
3
- "version": "0.1.12",
3
+ "version": "0.1.13",
4
4
  "type": "module",
5
5
  "description": "Architectural intelligence for codebases. Verify that AI-generated code matches your architectural intent.",
6
6
  "keywords": [