nexarch 0.13.3 → 0.13.4
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-project.js +13 -7
- package/dist/commands/search-icons.js +64 -0
- package/dist/index.js +8 -0
- package/dist/lib/skills.js +18 -1
- package/package.json +2 -2
|
@@ -2343,7 +2343,7 @@ export async function initProject(args) {
|
|
|
2343
2343
|
pendingSteps.push({
|
|
2344
2344
|
step: stepNum++,
|
|
2345
2345
|
action: "enrich_entity",
|
|
2346
|
-
instruction: `Enrich the application entity with a meaningful name, description, subtype, and icon.`,
|
|
2346
|
+
instruction: `Enrich the application entity with a meaningful name, description, subtype, and icon. Find a real icon name with \`nexarch search-icons "<what the application is>"\`; a guessed name that doesn't exist is dropped without an error.`,
|
|
2347
2347
|
command: `nexarch update-entity --key "${projectExternalKey}" --entity-type "${entityTypeOverride}"${entityTypeOverride === "application" ? ' --subtype "<subtype>" --icon "<lucide-icon>"' : ""} --name "..." --description "..."`,
|
|
2348
2348
|
...(entityTypeOverride === "application"
|
|
2349
2349
|
? { notes: [APPLICATION_SUBTYPE_HINT, "Choose app_custom_built as the default if none of the others clearly apply."] }
|
|
@@ -2384,9 +2384,11 @@ export async function initProject(args) {
|
|
|
2384
2384
|
instruction: `Review the codebase to identify discrete application functions (what the application does). ` +
|
|
2385
2385
|
`Examine named modules, route layout, service boundaries, and any architecture documentation. ` +
|
|
2386
2386
|
`Register functions as application_function entities with subtype core_function (primary business function), supporting_function (auxiliary/enablement), integration_function (external connectivity), or data_function (data processing). ` +
|
|
2387
|
-
`Only register functions clearly evidenced by the codebase — do not invent them. ${DESCRIPTION_GUIDANCE}
|
|
2387
|
+
`Only register functions clearly evidenced by the codebase — do not invent them. ${DESCRIPTION_GUIDANCE} ` +
|
|
2388
|
+
`Give each function an icon for what it does: find a real name with \`nexarch search-icons "<what it does>"\` (or nexarch_search_icons) and pass it as --icon. Don't guess a name; one that doesn't exist is dropped without an error. If two searches find nothing fitting, leave the icon off.`,
|
|
2388
2389
|
commandTemplates: {
|
|
2389
|
-
|
|
2390
|
+
searchIcons: `nexarch search-icons "<what the function does>"`,
|
|
2391
|
+
updateEntity: `nexarch update-entity --key "application_function:${projectSlug}_<function_slug>" --entity-type application_function --subtype core_function --icon "<name from search-icons>" --name "..." --description "..."`,
|
|
2390
2392
|
addRelationship: `nexarch add-relationship --from "application_function:${projectSlug}_<function_slug>" --to ${projectConstruct && isMonorepo ? '"<owning application key from classifyPackages>"' : `"${projectExternalKey}"`} --type part_of`,
|
|
2391
2393
|
note: "Functions are structural decomposition only: do not add runtime dependencies from an application_function. Model independently deployable services as applications or application components, then relate those boundaries with depends_on or integrates_with.",
|
|
2392
2394
|
},
|
|
@@ -2405,7 +2407,7 @@ export async function initProject(args) {
|
|
|
2405
2407
|
pendingSteps.push({
|
|
2406
2408
|
step: stepNum++,
|
|
2407
2409
|
action: "register_decision_records",
|
|
2408
|
-
instruction: `Look for ADRs (docs/adr/, decisions/, ADR-*.md) and register
|
|
2410
|
+
instruction: `Look for ADRs (docs/adr/, decisions/, ADR-*.md) and register the architectural ones as decision_record entities: a decision that crosses a boundary between applications, services or teams; changes an integration, data ownership, security or deployment; adopts, replaces or retires a technology others depend on; or is expensive to reverse. Skip design decisions inside one application, even when they are written up as ADRs.`,
|
|
2409
2411
|
commandTemplates: {
|
|
2410
2412
|
updateEntity: `nexarch update-entity --key "decision_record:${projectSlug}_<adr_slug>" --entity-type decision_record --subtype decision_architecture --name "..." --attributes-json '{"decision":{"summary":"...","detail":"..."}}'`,
|
|
2411
2413
|
addRelationship: `nexarch add-relationship --from "decision_record:${projectSlug}_<adr_slug>" --to ${projectConstruct && isMonorepo ? '"<the relevant application key>"' : `"${projectExternalKey}"`} --type decides`,
|
|
@@ -2519,7 +2521,7 @@ export async function initProject(args) {
|
|
|
2519
2521
|
unresolvedNames: unresolvedItems.map((r) => r.input),
|
|
2520
2522
|
iconHints: {
|
|
2521
2523
|
provider: "lucide",
|
|
2522
|
-
note: "Use
|
|
2524
|
+
note: "Use a name returned by `nexarch search-icons` (or nexarch_search_icons); a guessed name that doesn't exist is dropped without an error. Omit when nothing fits.",
|
|
2523
2525
|
},
|
|
2524
2526
|
};
|
|
2525
2527
|
}
|
|
@@ -2643,15 +2645,19 @@ export async function initProject(args) {
|
|
|
2643
2645
|
lines.push(` Use subtype core_function (primary business function), supporting_function (auxiliary/enablement),`);
|
|
2644
2646
|
lines.push(` integration_function (external connectivity), or data_function (data processing).`);
|
|
2645
2647
|
lines.push(` Only register functions clearly evidenced by the codebase — do not invent them. ${DESCRIPTION_GUIDANCE}`);
|
|
2648
|
+
lines.push(` Give each function an icon for what it does. Find a real name first; a guessed one is dropped without an error:`);
|
|
2649
|
+
lines.push(` nexarch search-icons "<what the function does>"`);
|
|
2646
2650
|
lines.push(` For each one found:`);
|
|
2647
2651
|
const fnOwnerTarget = projectConstruct && isMonorepo ? '"<owning application key from CLASSIFY_THESE>"' : `"${projectExternalKey}"`;
|
|
2648
|
-
lines.push(` nexarch update-entity --key "application_function:${projectExternalKey.split(":")[1] ?? "project"}_<function_slug>" --entity-type application_function --subtype core_function --name "..." --description "..."`);
|
|
2652
|
+
lines.push(` nexarch update-entity --key "application_function:${projectExternalKey.split(":")[1] ?? "project"}_<function_slug>" --entity-type application_function --subtype core_function --icon "<name from search-icons>" --name "..." --description "..."`);
|
|
2649
2653
|
lines.push(` nexarch add-relationship --from "application_function:${projectExternalKey.split(":")[1] ?? "project"}_<function_slug>" --to ${fnOwnerTarget} --type part_of`);
|
|
2650
2654
|
lines.push(" Functions are structural only: model runtime/service dependencies between application or application_component boundaries, never from an application_function.");
|
|
2651
2655
|
}
|
|
2652
2656
|
lines.push(` ${step++}. Scan the READMEs for platforms/SaaS not auto-detected (Vercel, Neon, Stripe, etc.).`);
|
|
2653
2657
|
lines.push(` For each found: nexarch resolve-names --names "..." --json → nexarch update-entity → nexarch add-relationship`);
|
|
2654
|
-
lines.push(` ${step++}. Look for ADRs (docs/adr/, decisions/, ADR-*.md) and register decision_record entities.`);
|
|
2658
|
+
lines.push(` ${step++}. Look for ADRs (docs/adr/, decisions/, ADR-*.md) and register the architectural ones as decision_record entities.`);
|
|
2659
|
+
lines.push(` Architectural means it crosses a boundary between applications, services or teams; changes an integration, data ownership, security or deployment;`);
|
|
2660
|
+
lines.push(` adopts or retires a technology others depend on; or is expensive to reverse. Skip design decisions inside one application.`);
|
|
2655
2661
|
lines.push(` nexarch update-entity --key "decision_record:${projectExternalKey.split(":")[1] ?? "project"}_<adr_slug>" --entity-type decision_record --subtype decision_architecture --name "..." --attributes-json '{"decision":{"summary":"...","detail":"..."}}'`);
|
|
2656
2662
|
lines.push(` nexarch add-relationship --from "decision_record:..." --to ${projectConstruct && isMonorepo ? '"<the relevant application key>"' : `"${projectExternalKey}"`} --type decides`);
|
|
2657
2663
|
lines.push("");
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import process from "process";
|
|
2
|
+
import { requireCredentials } from "../lib/credentials.js";
|
|
3
|
+
import { callMcpTool } from "../lib/mcp.js";
|
|
4
|
+
function parseOptionValue(args, option) {
|
|
5
|
+
const idx = args.indexOf(option);
|
|
6
|
+
if (idx === -1)
|
|
7
|
+
return null;
|
|
8
|
+
const value = args[idx + 1];
|
|
9
|
+
if (!value || value.startsWith("--"))
|
|
10
|
+
return null;
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The words to search for: everything that isn't an option or an option's
|
|
15
|
+
* value, so both `search-icons database` and `search-icons "event stream"` work.
|
|
16
|
+
*/
|
|
17
|
+
export function searchIconsQuery(args) {
|
|
18
|
+
const valued = new Set(["--limit"]);
|
|
19
|
+
const words = [];
|
|
20
|
+
for (let i = 0; i < args.length; i++) {
|
|
21
|
+
if (valued.has(args[i])) {
|
|
22
|
+
i++;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (args[i].startsWith("--"))
|
|
26
|
+
continue;
|
|
27
|
+
words.push(args[i]);
|
|
28
|
+
}
|
|
29
|
+
return words.join(" ").trim();
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Finds real icon names for `update-entity --icon`. The gateway silently drops
|
|
33
|
+
* an icon name that doesn't exist, so an agent guessing from memory ends up
|
|
34
|
+
* with no icon and no error; this searches the same validated set it checks.
|
|
35
|
+
*/
|
|
36
|
+
export async function searchIcons(args) {
|
|
37
|
+
const asJson = args.includes("--json");
|
|
38
|
+
const query = searchIconsQuery(args);
|
|
39
|
+
if (!query) {
|
|
40
|
+
console.error('error: say what the icon should show, e.g. nexarch search-icons "credit card"');
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
const limitRaw = parseOptionValue(args, "--limit");
|
|
44
|
+
const limit = limitRaw ? Number(limitRaw) : undefined;
|
|
45
|
+
if (limitRaw && (!Number.isInteger(limit) || limit < 1)) {
|
|
46
|
+
console.error("error: --limit must be a whole number of 1 or more");
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
const creds = requireCredentials();
|
|
50
|
+
const raw = await callMcpTool("nexarch_search_icons", { query, ...(limit ? { limit } : {}) }, { companyId: creds.companyId });
|
|
51
|
+
const result = JSON.parse(raw.content?.[0]?.text ?? "{}");
|
|
52
|
+
if (asJson) {
|
|
53
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (!result.matches?.length) {
|
|
57
|
+
console.log(`No icons match "${query}".`);
|
|
58
|
+
console.log("Icon names are literal objects and actions (database, file, box). Try one more concrete word; if that also finds nothing, leave the icon unset.");
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
for (const name of result.matches)
|
|
62
|
+
console.log(name);
|
|
63
|
+
console.log(`\n${result.matches.length} of ${result.totalMatches} match${result.totalMatches === 1 ? "" : "es"}. Use one with: nexarch update-entity --key "<key>" --icon "${result.matches[0]}"`);
|
|
64
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -13,6 +13,7 @@ import { updateEntity } from "./commands/update-entity.js";
|
|
|
13
13
|
import { addRelationship } from "./commands/add-relationship.js";
|
|
14
14
|
import { registerAlias } from "./commands/register-alias.js";
|
|
15
15
|
import { resolveNames } from "./commands/resolve-names.js";
|
|
16
|
+
import { searchIcons } from "./commands/search-icons.js";
|
|
16
17
|
import { feedback } from "./commands/feedback.js";
|
|
17
18
|
import { listEntities } from "./commands/list-entities.js";
|
|
18
19
|
import { listRelationships } from "./commands/list-relationships.js";
|
|
@@ -57,6 +58,7 @@ const commands = {
|
|
|
57
58
|
"add-relationship": addRelationship,
|
|
58
59
|
"register-alias": registerAlias,
|
|
59
60
|
"resolve-names": resolveNames,
|
|
61
|
+
"search-icons": searchIcons,
|
|
60
62
|
feedback,
|
|
61
63
|
"list-entities": listEntities,
|
|
62
64
|
"list-relationships": listRelationships,
|
|
@@ -232,6 +234,12 @@ Usage:
|
|
|
232
234
|
results before calling add-relationship.
|
|
233
235
|
Options: --names <csv> (required, e.g. "vercel,neon")
|
|
234
236
|
--json
|
|
237
|
+
nexarch search-icons <words>
|
|
238
|
+
Find real icon names for update-entity --icon. An icon
|
|
239
|
+
name that doesn't exist is dropped without an error, so
|
|
240
|
+
look one up rather than guessing.
|
|
241
|
+
Options: --limit <n> (default 20, max 50)
|
|
242
|
+
--json
|
|
235
243
|
nexarch feedback
|
|
236
244
|
Report a Nexarch usability problem or tool error.
|
|
237
245
|
Options: --kind <usability|error> (required)
|
package/dist/lib/skills.js
CHANGED
|
@@ -240,7 +240,7 @@ evidence — never invent a compliance status that isn't stored.
|
|
|
240
240
|
`;
|
|
241
241
|
const DECISION_RECORDS_SKILL_BODY = `---
|
|
242
242
|
name: nexarch-decision-records
|
|
243
|
-
description: Record an architectural decision in Nexarch, or check what's already been decided about something. Use when a decision
|
|
243
|
+
description: Record an architectural decision in Nexarch, or check what's already been decided about something. Use when a decision crosses a boundary between applications, services or teams, changes an integration, data ownership, security or deployment, adopts a technology others depend on, or is expensive to reverse; when ADR/RFC documents are found in a repository; when asked what's already been decided about a topic; or when a new decision replaces an older one. Not for design decisions inside one application. Requires the Nexarch MCP tools (nexarch_*).
|
|
244
244
|
---
|
|
245
245
|
|
|
246
246
|
# Nexarch Decision Records
|
|
@@ -252,6 +252,23 @@ skill is for recording one as it happens — mining a whole repository's ADR
|
|
|
252
252
|
history systematically is a separate, human-triggered Decision Review
|
|
253
253
|
command from the application's page in the workspace.
|
|
254
254
|
|
|
255
|
+
## Architectural, not design
|
|
256
|
+
|
|
257
|
+
Record only architectural decisions. A decision is architectural when it does
|
|
258
|
+
at least one of these:
|
|
259
|
+
|
|
260
|
+
- crosses a boundary between applications, services or teams
|
|
261
|
+
- changes an integration, data ownership, security or authentication, or how
|
|
262
|
+
the system is deployed
|
|
263
|
+
- adopts, replaces or retires a technology that other systems or teams depend on
|
|
264
|
+
- is expensive to reverse once other work builds on it
|
|
265
|
+
|
|
266
|
+
Anything else is a design decision — screen layouts, interaction patterns,
|
|
267
|
+
component library choices, internal module structure, naming. It belongs in
|
|
268
|
+
the repository's design documentation, not in the graph. When unsure, ask:
|
|
269
|
+
if this decision changed, would another team or system have to change too? If
|
|
270
|
+
not, do not record it, even when it is written up as an ADR.
|
|
271
|
+
|
|
255
272
|
## Before recording
|
|
256
273
|
|
|
257
274
|
\`nexarch_resolve_reference\` / \`nexarch_list_entities\` for an existing
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexarch",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.4",
|
|
4
4
|
"description": "Your architecture workspace for AI delivery.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nexarch",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"prepublishOnly": "tsc",
|
|
27
27
|
"dev": "tsx src/index.ts",
|
|
28
28
|
"typecheck": "tsc --noEmit",
|
|
29
|
-
"test": "tsx scripts/test-mcp-proxy-response.ts && tsx scripts/test-trust-reattest.ts && tsx scripts/test-similar-applications.ts && tsx scripts/test-iac-tool.ts && tsx scripts/test-ansible.ts && tsx scripts/test-reference-sightings.ts"
|
|
29
|
+
"test": "tsx scripts/test-mcp-proxy-response.ts && tsx scripts/test-trust-reattest.ts && tsx scripts/test-similar-applications.ts && tsx scripts/test-iac-tool.ts && tsx scripts/test-ansible.ts && tsx scripts/test-reference-sightings.ts && tsx scripts/test-search-icons.ts"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@types/node": "^22",
|