nexarch 0.1.23 → 0.1.25
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/commands/init-agent.js +1 -1
- package/dist/commands/init-project.js +114 -15
- package/package.json +1 -1
|
@@ -4,7 +4,7 @@ import { join } from "path";
|
|
|
4
4
|
import process from "process";
|
|
5
5
|
import { requireCredentials } from "../lib/credentials.js";
|
|
6
6
|
import { callMcpTool, mcpInitialize, mcpListTools } from "../lib/mcp.js";
|
|
7
|
-
const CLI_VERSION = "0.1.
|
|
7
|
+
const CLI_VERSION = "0.1.25";
|
|
8
8
|
const AGENT_ENTITY_TYPE = "agent";
|
|
9
9
|
const TECH_COMPONENT_ENTITY_TYPE = "technology_component";
|
|
10
10
|
function parseFlag(args, flag) {
|
|
@@ -115,6 +115,34 @@ function readRootPackage(pkgPath) {
|
|
|
115
115
|
return {};
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
|
+
// Guess entity type + subtype for a sub-package based on its path and package.json scripts.
|
|
119
|
+
function classifySubPackage(pkgPath, relativePath) {
|
|
120
|
+
const topDir = relativePath.split("/")[0] ?? "";
|
|
121
|
+
// packages/* → shared library/component
|
|
122
|
+
if (topDir === "packages") {
|
|
123
|
+
const name = relativePath.split("/")[1] ?? "";
|
|
124
|
+
if (name.includes("ui") || name.includes("components"))
|
|
125
|
+
return { entityType: "technology_component", subtype: "tech_framework" };
|
|
126
|
+
if (name.includes("types") || name.includes("shared"))
|
|
127
|
+
return { entityType: "technology_component", subtype: "tech_library" };
|
|
128
|
+
return { entityType: "technology_component", subtype: "tech_library" };
|
|
129
|
+
}
|
|
130
|
+
// apps/* or src/* → deployable application; check scripts
|
|
131
|
+
try {
|
|
132
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
133
|
+
const scripts = Object.keys(pkg.scripts ?? {});
|
|
134
|
+
const hasServer = scripts.some((s) => ["start", "dev", "serve", "build"].includes(s));
|
|
135
|
+
if (hasServer) {
|
|
136
|
+
const name = relativePath.toLowerCase();
|
|
137
|
+
if (name.includes("crawl") || name.includes("worker") || name.includes("job") || name.includes("etl")) {
|
|
138
|
+
return { entityType: "application", subtype: "app_integration_service" };
|
|
139
|
+
}
|
|
140
|
+
return { entityType: "application", subtype: "app_custom_built" };
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch { }
|
|
144
|
+
return { entityType: "technology_component", subtype: "tech_library" };
|
|
145
|
+
}
|
|
118
146
|
// Resolve workspace glob patterns (e.g. "apps/*", "packages/*") to actual directories.
|
|
119
147
|
// Handles the common case of a single wildcard — no full glob library needed.
|
|
120
148
|
function resolveWorkspaceDirs(rootDir, workspaces) {
|
|
@@ -205,24 +233,34 @@ function scanProject(dir) {
|
|
|
205
233
|
const names = new Set();
|
|
206
234
|
let projectName = basename(dir);
|
|
207
235
|
const subPackages = [];
|
|
236
|
+
let rootDepNames = new Set();
|
|
208
237
|
const pkgPaths = findPackageJsonPaths(dir);
|
|
209
238
|
const rootPkgPath = join(dir, "package.json");
|
|
210
239
|
for (const pkgPath of pkgPaths) {
|
|
211
240
|
const pkg = readRootPackage(pkgPath);
|
|
241
|
+
const deps = collectPackageDeps(pkgPath);
|
|
212
242
|
if (pkgPath === rootPkgPath) {
|
|
213
243
|
if (pkg.name)
|
|
214
244
|
projectName = pkg.name;
|
|
245
|
+
rootDepNames = new Set(deps);
|
|
215
246
|
}
|
|
216
247
|
else {
|
|
217
248
|
// Record as a sub-package for enrichment task
|
|
218
249
|
const relativePath = pkgPath.replace(dir + "/", "").replace("/package.json", "");
|
|
250
|
+
const packageName = pkg.name ?? relativePath;
|
|
251
|
+
const { entityType, subtype } = classifySubPackage(pkgPath, relativePath);
|
|
252
|
+
const externalKey = `${entityType}:${slugify(packageName)}`;
|
|
219
253
|
subPackages.push({
|
|
220
|
-
name:
|
|
254
|
+
name: packageName,
|
|
221
255
|
relativePath,
|
|
222
256
|
packageJsonPath: pkgPath,
|
|
257
|
+
depNames: deps,
|
|
258
|
+
entityType,
|
|
259
|
+
subtype,
|
|
260
|
+
externalKey,
|
|
223
261
|
});
|
|
224
262
|
}
|
|
225
|
-
for (const dep of
|
|
263
|
+
for (const dep of deps)
|
|
226
264
|
names.add(dep);
|
|
227
265
|
}
|
|
228
266
|
// .env files at root
|
|
@@ -241,7 +279,7 @@ function scanProject(dir) {
|
|
|
241
279
|
names.add(name);
|
|
242
280
|
for (const name of detectFromFilesystem(dir))
|
|
243
281
|
names.add(name);
|
|
244
|
-
return { projectName, packageJsonCount: pkgPaths.length, detectedNames: Array.from(names), subPackages };
|
|
282
|
+
return { projectName, packageJsonCount: pkgPaths.length, detectedNames: Array.from(names), rootDepNames, subPackages };
|
|
245
283
|
}
|
|
246
284
|
// ─── Relationship type selection ──────────────────────────────────────────────
|
|
247
285
|
function pickRelationshipType(entityTypeCode) {
|
|
@@ -268,7 +306,7 @@ export async function initProject(args) {
|
|
|
268
306
|
const mcpOpts = { companyId: creds.companyId };
|
|
269
307
|
if (!asJson)
|
|
270
308
|
console.log(`Scanning ${dir}…`);
|
|
271
|
-
const { projectName, packageJsonCount, detectedNames, subPackages } = scanProject(dir);
|
|
309
|
+
const { projectName, packageJsonCount, detectedNames, rootDepNames, subPackages } = scanProject(dir);
|
|
272
310
|
const displayName = nameOverride ?? projectName;
|
|
273
311
|
const projectSlug = slugify(displayName);
|
|
274
312
|
const projectExternalKey = `${entityTypeOverride}:${projectSlug}`;
|
|
@@ -358,23 +396,66 @@ export async function initProject(args) {
|
|
|
358
396
|
confidence: 0.95,
|
|
359
397
|
});
|
|
360
398
|
}
|
|
361
|
-
//
|
|
399
|
+
// Auto-create stub entities for each sub-package
|
|
400
|
+
const seenSubKeys = new Set();
|
|
401
|
+
for (const sp of subPackages) {
|
|
402
|
+
if (seenSubKeys.has(sp.externalKey))
|
|
403
|
+
continue;
|
|
404
|
+
seenSubKeys.add(sp.externalKey);
|
|
405
|
+
entities.push({
|
|
406
|
+
externalKey: sp.externalKey,
|
|
407
|
+
entityTypeCode: sp.entityType,
|
|
408
|
+
entitySubtypeCode: sp.subtype,
|
|
409
|
+
name: sp.name,
|
|
410
|
+
confidence: 0.8,
|
|
411
|
+
attributes: { source_dir: `${dir}/${sp.relativePath}`, scanned_at: nowIso },
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
// Build a lookup from input name to resolved result for enrichment task and sub-app wiring
|
|
415
|
+
const resolvedByInput = new Map();
|
|
416
|
+
for (const r of resolvedItems) {
|
|
417
|
+
if (r.canonicalExternalRef)
|
|
418
|
+
resolvedByInput.set(r.input, r);
|
|
419
|
+
if (r.normalised && r.canonicalExternalRef)
|
|
420
|
+
resolvedByInput.set(r.normalised, r);
|
|
421
|
+
}
|
|
422
|
+
// Build relationships:
|
|
423
|
+
// - Root-level deps → wired to the top-level project entity
|
|
424
|
+
// - Sub-package deps → wired to each sub-package entity
|
|
425
|
+
// - Sub-packages that are apps → part_of the top-level project
|
|
362
426
|
const relationships = [];
|
|
363
427
|
const seenRelPairs = new Set();
|
|
428
|
+
function addRel(type, from, to, confidence = 0.9) {
|
|
429
|
+
const key = `${type}::${from}::${to}`;
|
|
430
|
+
if (seenRelPairs.has(key))
|
|
431
|
+
return;
|
|
432
|
+
seenRelPairs.add(key);
|
|
433
|
+
relationships.push({ relationshipTypeCode: type, fromEntityExternalKey: from, toEntityExternalKey: to, confidence });
|
|
434
|
+
}
|
|
435
|
+
// Root-level deps → top-level project
|
|
364
436
|
for (const r of resolvedItems) {
|
|
365
437
|
if (!r.canonicalExternalRef || !r.entityTypeCode)
|
|
366
438
|
continue;
|
|
367
|
-
|
|
368
|
-
const pairKey = `${relType}::${projectExternalKey}::${r.canonicalExternalRef}`;
|
|
369
|
-
if (seenRelPairs.has(pairKey))
|
|
439
|
+
if (!rootDepNames.has(r.input) && !rootDepNames.has(r.normalised))
|
|
370
440
|
continue;
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
});
|
|
441
|
+
addRel(pickRelationshipType(r.entityTypeCode), projectExternalKey, r.canonicalExternalRef);
|
|
442
|
+
}
|
|
443
|
+
// Sub-package relationships
|
|
444
|
+
for (const sp of subPackages) {
|
|
445
|
+
if (!sp.externalKey || seenSubKeys.has(`rel:${sp.externalKey}`))
|
|
446
|
+
continue;
|
|
447
|
+
seenSubKeys.add(`rel:${sp.externalKey}`);
|
|
448
|
+
// Apps are part_of the top-level project
|
|
449
|
+
if (sp.entityType === "application") {
|
|
450
|
+
addRel("part_of", sp.externalKey, projectExternalKey);
|
|
451
|
+
}
|
|
452
|
+
// Wire each sub-package's resolved deps to itself
|
|
453
|
+
for (const depName of sp.depNames) {
|
|
454
|
+
const r = resolvedByInput.get(depName);
|
|
455
|
+
if (!r?.canonicalExternalRef || !r.entityTypeCode)
|
|
456
|
+
continue;
|
|
457
|
+
addRel(pickRelationshipType(r.entityTypeCode), sp.externalKey, r.canonicalExternalRef);
|
|
458
|
+
}
|
|
378
459
|
}
|
|
379
460
|
if (!asJson)
|
|
380
461
|
console.log(`\nWriting to graph…`);
|
|
@@ -497,5 +578,23 @@ ${subPackages.map((sp) => ` • ${sp.name} (${sp.relativePath})`).join("\n")
|
|
|
497
578
|
--to "<library-key>" \\
|
|
498
579
|
--type "depends_on"
|
|
499
580
|
(FROM = ${projectExternalKey}, TO = the library)
|
|
581
|
+
|
|
582
|
+
⚠️ WIRE DEPENDENCIES TO THE SUB-APP THAT DECLARES THEM, NOT TO THE PARENT.
|
|
583
|
+
After registering each sub-app/library entity, wire its npm dependencies to IT:
|
|
584
|
+
npx nexarch add-relationship \\
|
|
585
|
+
--from "<sub-app-or-library-key>" \\
|
|
586
|
+
--to "<resolved-tech-ref>" \\
|
|
587
|
+
--type "depends_on"
|
|
588
|
+
|
|
589
|
+
Pre-resolved dependencies per sub-package (wire these after registering each entity):
|
|
590
|
+
${subPackages.map((sp) => {
|
|
591
|
+
const resolved = sp.depNames
|
|
592
|
+
.map((d) => resolvedByInput.get(d))
|
|
593
|
+
.filter((r) => !!r?.canonicalExternalRef);
|
|
594
|
+
if (resolved.length === 0)
|
|
595
|
+
return ` • ${sp.name}: (no pre-resolved deps — check package.json manually)`;
|
|
596
|
+
const lines = resolved.map((r) => ` --to "${r.canonicalExternalRef}" # ${r.canonicalName}`);
|
|
597
|
+
return ` • ${sp.name} (<sub-app-key> depends_on):\n${lines.join("\n")}`;
|
|
598
|
+
}).join("\n\n")}
|
|
500
599
|
` : ""}`);
|
|
501
600
|
}
|