@documentation-robotics/cli 0.1.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/PYTHON_CLI_PARITY.md +265 -0
- package/PYTHON_CLI_STRUCTURE_UPDATE.md +246 -0
- package/README.md +926 -0
- package/biome.json +42 -0
- package/bunfig.toml +3 -0
- package/dist/ai/claude-client.js +71 -0
- package/dist/ai/claude-client.js.map +7 -0
- package/dist/ai/context-provider.js +129 -0
- package/dist/ai/context-provider.js.map +7 -0
- package/dist/ai/tools.js +231 -0
- package/dist/ai/tools.js.map +7 -0
- package/dist/cli.js +224 -0
- package/dist/cli.js.map +7 -0
- package/dist/commands/add.js +51 -0
- package/dist/commands/add.js.map +7 -0
- package/dist/commands/changeset.js +174 -0
- package/dist/commands/changeset.js.map +7 -0
- package/dist/commands/chat.js +111 -0
- package/dist/commands/chat.js.map +7 -0
- package/dist/commands/conformance.js +132 -0
- package/dist/commands/conformance.js.map +7 -0
- package/dist/commands/delete.js +31 -0
- package/dist/commands/delete.js.map +7 -0
- package/dist/commands/element.js +28 -0
- package/dist/commands/element.js.map +7 -0
- package/dist/commands/export.js +65 -0
- package/dist/commands/export.js.map +7 -0
- package/dist/commands/info.js +40 -0
- package/dist/commands/info.js.map +7 -0
- package/dist/commands/init.js +45 -0
- package/dist/commands/init.js.map +7 -0
- package/dist/commands/list.js +32 -0
- package/dist/commands/list.js.map +7 -0
- package/dist/commands/migrate.js +36 -0
- package/dist/commands/migrate.js.map +7 -0
- package/dist/commands/project.js +74 -0
- package/dist/commands/project.js.map +7 -0
- package/dist/commands/relationship.js +118 -0
- package/dist/commands/relationship.js.map +7 -0
- package/dist/commands/search.js +48 -0
- package/dist/commands/search.js.map +7 -0
- package/dist/commands/show.js +38 -0
- package/dist/commands/show.js.map +7 -0
- package/dist/commands/trace.js +60 -0
- package/dist/commands/trace.js.map +7 -0
- package/dist/commands/update.js +37 -0
- package/dist/commands/update.js.map +7 -0
- package/dist/commands/upgrade.js +152 -0
- package/dist/commands/upgrade.js.map +7 -0
- package/dist/commands/validate.js +71 -0
- package/dist/commands/validate.js.map +7 -0
- package/dist/commands/version.js +20 -0
- package/dist/commands/version.js.map +7 -0
- package/dist/commands/visualize.js +51 -0
- package/dist/commands/visualize.js.map +7 -0
- package/dist/core/active-changeset.js +52 -0
- package/dist/core/active-changeset.js.map +7 -0
- package/dist/core/changeset.js +244 -0
- package/dist/core/changeset.js.map +7 -0
- package/dist/core/dependency-tracker.js +322 -0
- package/dist/core/dependency-tracker.js.map +7 -0
- package/dist/core/element.js +65 -0
- package/dist/core/element.js.map +7 -0
- package/dist/core/layer.js +75 -0
- package/dist/core/layer.js.map +7 -0
- package/dist/core/manifest.js +57 -0
- package/dist/core/manifest.js.map +7 -0
- package/dist/core/migration-registry.js +131 -0
- package/dist/core/migration-registry.js.map +7 -0
- package/dist/core/model.js +455 -0
- package/dist/core/model.js.map +7 -0
- package/dist/core/projection-engine.js +288 -0
- package/dist/core/projection-engine.js.map +7 -0
- package/dist/core/reference-registry.js +188 -0
- package/dist/core/reference-registry.js.map +7 -0
- package/dist/core/relationship-registry.js +114 -0
- package/dist/core/relationship-registry.js.map +7 -0
- package/dist/core/relationships.js +78 -0
- package/dist/core/relationships.js.map +7 -0
- package/dist/export/archimate-exporter.js +111 -0
- package/dist/export/archimate-exporter.js.map +7 -0
- package/dist/export/export-manager.js +63 -0
- package/dist/export/export-manager.js.map +7 -0
- package/dist/export/graphml-exporter.js +39 -0
- package/dist/export/graphml-exporter.js.map +7 -0
- package/dist/export/index.js +17 -0
- package/dist/export/index.js.map +7 -0
- package/dist/export/json-schema-exporter.js +60 -0
- package/dist/export/json-schema-exporter.js.map +7 -0
- package/dist/export/markdown-exporter.js +99 -0
- package/dist/export/markdown-exporter.js.map +7 -0
- package/dist/export/openapi-exporter.js +85 -0
- package/dist/export/openapi-exporter.js.map +7 -0
- package/dist/export/plantuml-exporter.js +60 -0
- package/dist/export/plantuml-exporter.js.map +7 -0
- package/dist/export/types.js +36 -0
- package/dist/export/types.js.map +7 -0
- package/dist/schemas/bundled/01-motivation-layer.schema.json +942 -0
- package/dist/schemas/bundled/02-business-layer.schema.json +1293 -0
- package/dist/schemas/bundled/03-security-layer.schema.json +2177 -0
- package/dist/schemas/bundled/04-application-layer.schema.json +1328 -0
- package/dist/schemas/bundled/05-technology-layer.schema.json +1465 -0
- package/dist/schemas/bundled/06-api-layer.schema.json +1743 -0
- package/dist/schemas/bundled/07-data-model-layer.schema.json +1253 -0
- package/dist/schemas/bundled/08-datastore-layer.schema.json +892 -0
- package/dist/schemas/bundled/09-ux-layer.schema.json +1506 -0
- package/dist/schemas/bundled/10-navigation-layer.schema.json +843 -0
- package/dist/schemas/bundled/11-apm-observability-layer.schema.json +1430 -0
- package/dist/schemas/bundled/12-testing-layer.schema.json +1091 -0
- package/dist/schemas/bundled/common/layer-extensions.schema.json +266 -0
- package/dist/schemas/bundled/common/predicates.schema.json +493 -0
- package/dist/schemas/bundled/common/relationships.schema.json +791 -0
- package/dist/schemas/bundled/common/source-references.schema.json +71 -0
- package/dist/schemas/bundled/link-registry.json +1839 -0
- package/dist/schemas/bundled/link-registry.schema.json +339 -0
- package/dist/schemas/bundled/relationship-catalog.json +1302 -0
- package/dist/schemas/bundled/relationship-type.schema.json +221 -0
- package/dist/server/server.js +1207 -0
- package/dist/server/server.js.map +7 -0
- package/dist/server/telemetry-middleware.js +24 -0
- package/dist/server/telemetry-middleware.js.map +7 -0
- package/dist/telemetry/console-interceptor.js +34 -0
- package/dist/telemetry/console-interceptor.js.map +7 -0
- package/dist/telemetry/index.js +54 -0
- package/dist/telemetry/index.js.map +7 -0
- package/dist/telemetry/resilient-exporter.js +41 -0
- package/dist/telemetry/resilient-exporter.js.map +7 -0
- package/dist/telemetry/resilient-log-exporter.js +41 -0
- package/dist/telemetry/resilient-log-exporter.js.map +7 -0
- package/dist/telemetry/test-instrumentation.js +32 -0
- package/dist/telemetry/test-instrumentation.js.map +7 -0
- package/dist/types/index.js +1 -0
- package/dist/types/index.js.map +7 -0
- package/dist/utils/element-utils.js +11 -0
- package/dist/utils/element-utils.js.map +7 -0
- package/dist/utils/errors.js +105 -0
- package/dist/utils/errors.js.map +7 -0
- package/dist/utils/file-io.js +69 -0
- package/dist/utils/file-io.js.map +7 -0
- package/dist/utils/globals.js +28 -0
- package/dist/utils/globals.js.map +7 -0
- package/dist/utils/model-path.js +22 -0
- package/dist/utils/model-path.js.map +7 -0
- package/dist/utils/project-paths.js +45 -0
- package/dist/utils/project-paths.js.map +7 -0
- package/dist/utils/spec-installer.js +85 -0
- package/dist/utils/spec-installer.js.map +7 -0
- package/dist/utils/spec-version.js +33 -0
- package/dist/utils/spec-version.js.map +7 -0
- package/dist/validators/index.js +15 -0
- package/dist/validators/index.js.map +7 -0
- package/dist/validators/naming-validator.js +82 -0
- package/dist/validators/naming-validator.js.map +7 -0
- package/dist/validators/reference-validator.js +106 -0
- package/dist/validators/reference-validator.js.map +7 -0
- package/dist/validators/schema-validator.js +148 -0
- package/dist/validators/schema-validator.js.map +7 -0
- package/dist/validators/semantic-validator.js +80 -0
- package/dist/validators/semantic-validator.js.map +7 -0
- package/dist/validators/types.js +48 -0
- package/dist/validators/types.js.map +7 -0
- package/dist/validators/validator.js +67 -0
- package/dist/validators/validator.js.map +7 -0
- package/docs/TEST-INSTRUMENTATION.md +405 -0
- package/docs/telemetry.md +427 -0
- package/package.json +70 -0
- package/test-debug.js +33 -0
- package/test-special.mjs +46 -0
- package/test_runner.ts +7 -0
package/biome.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/1.8.0/schema.json",
|
|
3
|
+
"vcs": {
|
|
4
|
+
"enabled": true,
|
|
5
|
+
"clientKind": "git",
|
|
6
|
+
"useIgnoreFile": true
|
|
7
|
+
},
|
|
8
|
+
"files": {
|
|
9
|
+
"ignoreUnknown": false,
|
|
10
|
+
"ignore": ["node_modules", "dist", ".bun"]
|
|
11
|
+
},
|
|
12
|
+
"linter": {
|
|
13
|
+
"enabled": true,
|
|
14
|
+
"rules": {
|
|
15
|
+
"recommended": true,
|
|
16
|
+
"suspicious": {
|
|
17
|
+
"noExplicitAny": "error",
|
|
18
|
+
"noArrayIndexKey": "warn"
|
|
19
|
+
},
|
|
20
|
+
"style": {
|
|
21
|
+
"noImplicitBoolean": "error",
|
|
22
|
+
"useConsistentVariableDeclarations": "error"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"formatter": {
|
|
27
|
+
"enabled": true,
|
|
28
|
+
"indentStyle": "space",
|
|
29
|
+
"indentSize": 2,
|
|
30
|
+
"lineWidth": 100,
|
|
31
|
+
"trailingComma": "es5"
|
|
32
|
+
},
|
|
33
|
+
"javascript": {
|
|
34
|
+
"formatter": {
|
|
35
|
+
"quoteStyle": "single",
|
|
36
|
+
"trailingCommas": "es5"
|
|
37
|
+
},
|
|
38
|
+
"parser": {
|
|
39
|
+
"unsafeParameterDecoratorsEnabled": true
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
package/bunfig.toml
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
2
|
+
class ClaudeClient {
|
|
3
|
+
client;
|
|
4
|
+
conversationHistory = [];
|
|
5
|
+
constructor(apiKey) {
|
|
6
|
+
this.client = new Anthropic({ apiKey });
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Send a chat message and stream the response
|
|
10
|
+
* @param userMessage The message from the user
|
|
11
|
+
* @param options Configuration options for the API call
|
|
12
|
+
* @returns An async iterable of response text chunks
|
|
13
|
+
*/
|
|
14
|
+
async chat(userMessage, options = {}) {
|
|
15
|
+
this.conversationHistory.push({
|
|
16
|
+
role: "user",
|
|
17
|
+
content: userMessage
|
|
18
|
+
});
|
|
19
|
+
const messages = this.conversationHistory.map((msg) => ({
|
|
20
|
+
role: msg.role,
|
|
21
|
+
content: msg.content
|
|
22
|
+
})), params = {
|
|
23
|
+
model: options.model || "claude-sonnet-4-5-20250929",
|
|
24
|
+
max_tokens: options.maxTokens || 4096,
|
|
25
|
+
messages
|
|
26
|
+
};
|
|
27
|
+
options.systemPrompt && (params.system = options.systemPrompt), options.tools && options.tools.length > 0 && (params.tools = options.tools);
|
|
28
|
+
const stream = await this.client.messages.stream(params);
|
|
29
|
+
return this.streamResponse(stream);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Stream response from Claude API and accumulate to conversation history
|
|
33
|
+
* @param stream The stream from Claude API
|
|
34
|
+
* @returns An async iterable of text chunks
|
|
35
|
+
*/
|
|
36
|
+
async *streamResponse(stream) {
|
|
37
|
+
let assistantMessage = "";
|
|
38
|
+
for await (const chunk of stream)
|
|
39
|
+
if (chunk.type === "content_block_delta" && chunk.delta.type === "text_delta") {
|
|
40
|
+
const text = chunk.delta.text || "";
|
|
41
|
+
assistantMessage += text, yield text;
|
|
42
|
+
}
|
|
43
|
+
this.conversationHistory.push({
|
|
44
|
+
role: "assistant",
|
|
45
|
+
content: assistantMessage
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Clear conversation history
|
|
50
|
+
*/
|
|
51
|
+
clearHistory() {
|
|
52
|
+
this.conversationHistory = [];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get conversation history
|
|
56
|
+
* @returns Copy of conversation history
|
|
57
|
+
*/
|
|
58
|
+
getHistory() {
|
|
59
|
+
return [...this.conversationHistory];
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Get the number of messages in history
|
|
63
|
+
*/
|
|
64
|
+
getHistoryLength() {
|
|
65
|
+
return this.conversationHistory.length;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export {
|
|
69
|
+
ClaudeClient
|
|
70
|
+
};
|
|
71
|
+
//# sourceMappingURL=claude-client.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/ai/claude-client.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Claude Client for Anthropic SDK Integration\n * Handles streaming message responses and conversation history management\n *\n * IMPORTANT: This is legacy SDK-based chat infrastructure maintained for programmatic usage.\n * The `dr chat` CLI command uses Claude Code CLI subprocess instead (see commands/chat.ts).\n * Use this class only for direct Anthropic SDK integration in other contexts.\n */\n\nimport Anthropic from '@anthropic-ai/sdk';\n\n/**\n * Chat message in conversation history\n */\nexport interface ChatMessage {\n role: 'user' | 'assistant';\n content: string;\n}\n\n/**\n * Claude client for managing conversations with the Anthropic API\n */\nexport class ClaudeClient {\n private client: Anthropic;\n private conversationHistory: ChatMessage[] = [];\n\n constructor(apiKey: string) {\n this.client = new Anthropic({ apiKey });\n }\n\n /**\n * Send a chat message and stream the response\n * @param userMessage The message from the user\n * @param options Configuration options for the API call\n * @returns An async iterable of response text chunks\n */\n async chat(\n userMessage: string,\n options: {\n model?: string;\n maxTokens?: number;\n systemPrompt?: string;\n tools?: any[];\n } = {}\n ): Promise<AsyncIterable<string>> {\n // Add user message to history\n this.conversationHistory.push({\n role: 'user',\n content: userMessage,\n });\n\n // Create API request parameters\n const messages = this.conversationHistory.map((msg) => ({\n role: msg.role,\n content: msg.content,\n }));\n\n const params: any = {\n model: options.model || 'claude-sonnet-4-5-20250929',\n max_tokens: options.maxTokens || 4096,\n messages,\n };\n\n if (options.systemPrompt) {\n params.system = options.systemPrompt;\n }\n\n if (options.tools && options.tools.length > 0) {\n params.tools = options.tools;\n }\n\n // Create the stream\n const stream = await this.client.messages.stream(params);\n\n // Return async iterable that accumulates and yields response text\n return this.streamResponse(stream);\n }\n\n /**\n * Stream response from Claude API and accumulate to conversation history\n * @param stream The stream from Claude API\n * @returns An async iterable of text chunks\n */\n private async *streamResponse(stream: any): AsyncIterable<string> {\n let assistantMessage = '';\n\n for await (const chunk of stream) {\n if (chunk.type === 'content_block_delta' && chunk.delta.type === 'text_delta') {\n const text = chunk.delta.text || '';\n assistantMessage += text;\n yield text;\n }\n }\n\n // Add complete assistant message to history\n this.conversationHistory.push({\n role: 'assistant',\n content: assistantMessage,\n });\n }\n\n /**\n * Clear conversation history\n */\n clearHistory(): void {\n this.conversationHistory = [];\n }\n\n /**\n * Get conversation history\n * @returns Copy of conversation history\n */\n getHistory(): ChatMessage[] {\n return [...this.conversationHistory];\n }\n\n /**\n * Get the number of messages in history\n */\n getHistoryLength(): number {\n return this.conversationHistory.length;\n }\n}\n"],
|
|
5
|
+
"mappings": "AASA,OAAO,eAAe;AAahB,MAAO,aAAY;EACf;EACA,sBAAqC,CAAA;EAE7C,YAAY,QAAc;AACxB,SAAK,SAAS,IAAI,UAAU,EAAE,OAAM,CAAE;EACxC;;;;;;;EAQA,MAAM,KACJ,aACA,UAKI,CAAA,GAAE;AAGN,SAAK,oBAAoB,KAAK;MAC5B,MAAM;MACN,SAAS;KACV;AAGD,UAAM,WAAW,KAAK,oBAAoB,IAAI,CAAC,SAAS;MACtD,MAAM,IAAI;MACV,SAAS,IAAI;MACb,GAEI,SAAc;MAClB,OAAO,QAAQ,SAAS;MACxB,YAAY,QAAQ,aAAa;MACjC;;AAGF,IAAI,QAAQ,iBACV,OAAO,SAAS,QAAQ,eAGtB,QAAQ,SAAS,QAAQ,MAAM,SAAS,MAC1C,OAAO,QAAQ,QAAQ;AAIzB,UAAM,SAAS,MAAM,KAAK,OAAO,SAAS,OAAO,MAAM;AAGvD,WAAO,KAAK,eAAe,MAAM;EACnC;;;;;;EAOQ,OAAO,eAAe,QAAW;AACvC,QAAI,mBAAmB;AAEvB,qBAAiB,SAAS;AACxB,UAAI,MAAM,SAAS,yBAAyB,MAAM,MAAM,SAAS,cAAc;AAC7E,cAAM,OAAO,MAAM,MAAM,QAAQ;AACjC,4BAAoB,MACpB,MAAM;MACR;AAIF,SAAK,oBAAoB,KAAK;MAC5B,MAAM;MACN,SAAS;KACV;EACH;;;;EAKA,eAAY;AACV,SAAK,sBAAsB,CAAA;EAC7B;;;;;EAMA,aAAU;AACR,WAAO,CAAC,GAAG,KAAK,mBAAmB;EACrC;;;;EAKA,mBAAgB;AACd,WAAO,KAAK,oBAAoB;EAClC;;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { readFile } from "fs/promises";
|
|
2
|
+
import { fileURLToPath } from "url";
|
|
3
|
+
import { dirname, join } from "path";
|
|
4
|
+
class ModelContextProvider {
|
|
5
|
+
model;
|
|
6
|
+
layerNameMap = {
|
|
7
|
+
motivation: "01",
|
|
8
|
+
business: "02",
|
|
9
|
+
security: "03",
|
|
10
|
+
application: "04",
|
|
11
|
+
technology: "05",
|
|
12
|
+
api: "06",
|
|
13
|
+
"data-model": "07",
|
|
14
|
+
"data-store": "08",
|
|
15
|
+
ux: "09",
|
|
16
|
+
navigation: "10",
|
|
17
|
+
apm: "11",
|
|
18
|
+
testing: "12"
|
|
19
|
+
};
|
|
20
|
+
constructor(model) {
|
|
21
|
+
this.model = model;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Generate markdown context about the current architecture model
|
|
25
|
+
* @returns Markdown string with model overview and element summaries
|
|
26
|
+
*/
|
|
27
|
+
async generateContext() {
|
|
28
|
+
const context = [];
|
|
29
|
+
context.push(`# Current Architecture Model
|
|
30
|
+
`), context.push(`**Name**: ${this.model.manifest.name}`), context.push(`**Version**: ${this.model.manifest.version}`), this.model.manifest.description && context.push(`**Description**: ${this.model.manifest.description}`), context.push(""), context.push(`## Layers Overview
|
|
31
|
+
`);
|
|
32
|
+
const layerNames = this.model.getLayerNames(), layerDetails = [];
|
|
33
|
+
for (const layerName of layerNames) {
|
|
34
|
+
const layer = await this.model.getLayer(layerName);
|
|
35
|
+
if (layer) {
|
|
36
|
+
const elementCount = layer.listElements().length;
|
|
37
|
+
layerDetails.push(`- **${layerName}**: ${elementCount} elements`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
layerDetails.length > 0 ? context.push(layerDetails.join(`
|
|
41
|
+
`)) : context.push("_No layers loaded_"), context.push(""), context.push(`## Element Summary
|
|
42
|
+
`);
|
|
43
|
+
for (const layerName of layerNames) {
|
|
44
|
+
const layer = await this.model.getLayer(layerName);
|
|
45
|
+
if (!layer)
|
|
46
|
+
continue;
|
|
47
|
+
const elements = layer.listElements();
|
|
48
|
+
if (elements.length === 0)
|
|
49
|
+
continue;
|
|
50
|
+
context.push(`### ${layerName}
|
|
51
|
+
`);
|
|
52
|
+
const displayElements = elements.slice(0, 10);
|
|
53
|
+
for (const element of displayElements) {
|
|
54
|
+
const desc = element.description ? ` - ${element.description}` : "";
|
|
55
|
+
context.push(`- \`${element.id}\` (${element.type}): ${element.name}${desc}`);
|
|
56
|
+
}
|
|
57
|
+
elements.length > 10 && context.push(`- ... and ${elements.length - 10} more elements`), context.push("");
|
|
58
|
+
}
|
|
59
|
+
return context.join(`
|
|
60
|
+
`);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Generate markdown context about the testing layer specification
|
|
64
|
+
* @returns Markdown string with testing layer specification
|
|
65
|
+
*/
|
|
66
|
+
async generateTestingLayerSpec() {
|
|
67
|
+
return this.generateLayerSpec("testing");
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Generate markdown context about a specific layer specification
|
|
71
|
+
* @param layerName The layer name (e.g., 'motivation', 'business', 'api')
|
|
72
|
+
* @returns Markdown string with layer specification
|
|
73
|
+
*/
|
|
74
|
+
async generateLayerSpec(layerName) {
|
|
75
|
+
try {
|
|
76
|
+
const specPath = this.getLayerSpecPath(layerName);
|
|
77
|
+
return await readFile(specPath, "utf-8");
|
|
78
|
+
} catch {
|
|
79
|
+
return `# ${layerName} Layer
|
|
80
|
+
|
|
81
|
+
_Layer specification not found._`;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Get the file path for a layer specification
|
|
86
|
+
* @param layerName The layer name
|
|
87
|
+
* @returns The file path to the layer specification
|
|
88
|
+
*/
|
|
89
|
+
getLayerSpecPath(layerName) {
|
|
90
|
+
const normalizedName = layerName.toLowerCase().replace(/\s+/g, "-"), layerNumber = this.layerNameMap[normalizedName];
|
|
91
|
+
if (!layerNumber)
|
|
92
|
+
throw new Error(`Unknown layer: ${layerName}`);
|
|
93
|
+
const __filename = fileURLToPath(import.meta.url), __dirname = dirname(__filename), specDir = join(__dirname, "../../spec/layers");
|
|
94
|
+
let fileName;
|
|
95
|
+
return normalizedName === "data-store" ? fileName = `${layerNumber}-datastore-layer.md` : normalizedName === "apm" ? fileName = `${layerNumber}-apm-observability-layer.md` : fileName = `${layerNumber}-${normalizedName}-layer.md`, join(specDir, fileName);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get a list of all available layers
|
|
99
|
+
* @returns Array of layer names
|
|
100
|
+
*/
|
|
101
|
+
getAvailableLayers() {
|
|
102
|
+
return Object.keys(this.layerNameMap);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Get element count for a specific layer
|
|
106
|
+
* @param layerName The layer name
|
|
107
|
+
* @returns The number of elements in the layer, or 0 if not loaded
|
|
108
|
+
*/
|
|
109
|
+
async getLayerElementCount(layerName) {
|
|
110
|
+
const layer = await this.model.getLayer(layerName);
|
|
111
|
+
return layer ? layer.listElements().length : 0;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Get total element count across all layers
|
|
115
|
+
* @returns Total number of elements
|
|
116
|
+
*/
|
|
117
|
+
async getTotalElementCount() {
|
|
118
|
+
let total = 0;
|
|
119
|
+
for (const layerName of this.model.getLayerNames()) {
|
|
120
|
+
const layer = await this.model.getLayer(layerName);
|
|
121
|
+
layer && (total += layer.listElements().length);
|
|
122
|
+
}
|
|
123
|
+
return total;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
export {
|
|
127
|
+
ModelContextProvider
|
|
128
|
+
};
|
|
129
|
+
//# sourceMappingURL=context-provider.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/ai/context-provider.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Model Context Provider\n * Generates context about the architecture model for Claude to use\n *\n * NOTE: This provider is used for both Claude Code CLI subprocess (commands/chat.ts)\n * and legacy SDK-based chat (legacy use cases only). See claude-client.ts for details.\n */\n\nimport { Model } from '../core/model.js';\nimport { readFile } from 'fs/promises';\nimport { fileURLToPath } from 'url';\nimport { dirname, join } from 'path';\n\n/**\n * Provides context about the model for AI interactions\n */\nexport class ModelContextProvider {\n private model: Model;\n private layerNameMap: Record<string, string> = {\n motivation: '01',\n business: '02',\n security: '03',\n application: '04',\n technology: '05',\n api: '06',\n 'data-model': '07',\n 'data-store': '08',\n ux: '09',\n navigation: '10',\n apm: '11',\n testing: '12',\n };\n\n constructor(model: Model) {\n this.model = model;\n }\n\n /**\n * Generate markdown context about the current architecture model\n * @returns Markdown string with model overview and element summaries\n */\n async generateContext(): Promise<string> {\n const context: string[] = [];\n\n context.push('# Current Architecture Model\\n');\n context.push(`**Name**: ${this.model.manifest.name}`);\n context.push(`**Version**: ${this.model.manifest.version}`);\n if (this.model.manifest.description) {\n context.push(`**Description**: ${this.model.manifest.description}`);\n }\n context.push('');\n\n context.push('## Layers Overview\\n');\n\n // Get all available layers\n const layerNames = this.model.getLayerNames();\n const layerDetails: string[] = [];\n\n for (const layerName of layerNames) {\n const layer = await this.model.getLayer(layerName);\n if (layer) {\n const elementCount = layer.listElements().length;\n layerDetails.push(`- **${layerName}**: ${elementCount} elements`);\n }\n }\n\n if (layerDetails.length > 0) {\n context.push(layerDetails.join('\\n'));\n } else {\n context.push('_No layers loaded_');\n }\n\n context.push('');\n context.push('## Element Summary\\n');\n\n // Show elements per layer\n for (const layerName of layerNames) {\n const layer = await this.model.getLayer(layerName);\n if (!layer) continue;\n\n const elements = layer.listElements();\n if (elements.length === 0) continue;\n\n context.push(`### ${layerName}\\n`);\n\n // Show up to 10 elements per layer\n const displayElements = elements.slice(0, 10);\n for (const element of displayElements) {\n const desc = element.description ? ` - ${element.description}` : '';\n context.push(`- \\`${element.id}\\` (${element.type}): ${element.name}${desc}`);\n }\n\n if (elements.length > 10) {\n context.push(`- ... and ${elements.length - 10} more elements`);\n }\n\n context.push('');\n }\n\n return context.join('\\n');\n }\n\n /**\n * Generate markdown context about the testing layer specification\n * @returns Markdown string with testing layer specification\n */\n async generateTestingLayerSpec(): Promise<string> {\n return this.generateLayerSpec('testing');\n }\n\n /**\n * Generate markdown context about a specific layer specification\n * @param layerName The layer name (e.g., 'motivation', 'business', 'api')\n * @returns Markdown string with layer specification\n */\n async generateLayerSpec(layerName: string): Promise<string> {\n try {\n const specPath = this.getLayerSpecPath(layerName);\n const content = await readFile(specPath, 'utf-8');\n return content;\n } catch (error) {\n return `# ${layerName} Layer\\n\\n_Layer specification not found._`;\n }\n }\n\n /**\n * Get the file path for a layer specification\n * @param layerName The layer name\n * @returns The file path to the layer specification\n */\n private getLayerSpecPath(layerName: string): string {\n const normalizedName = layerName.toLowerCase().replace(/\\s+/g, '-');\n const layerNumber = this.layerNameMap[normalizedName];\n\n if (!layerNumber) {\n throw new Error(`Unknown layer: ${layerName}`);\n }\n\n // Get the path relative to this file, going up to cli, then to spec\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n const specDir = join(__dirname, '../../spec/layers');\n\n // Handle special case for data-store which is called datastore in spec\n let fileName: string;\n if (normalizedName === 'data-store') {\n fileName = `${layerNumber}-datastore-layer.md`;\n } else if (normalizedName === 'apm') {\n fileName = `${layerNumber}-apm-observability-layer.md`;\n } else {\n fileName = `${layerNumber}-${normalizedName}-layer.md`;\n }\n\n return join(specDir, fileName);\n }\n\n /**\n * Get a list of all available layers\n * @returns Array of layer names\n */\n getAvailableLayers(): string[] {\n return Object.keys(this.layerNameMap);\n }\n\n /**\n * Get element count for a specific layer\n * @param layerName The layer name\n * @returns The number of elements in the layer, or 0 if not loaded\n */\n async getLayerElementCount(layerName: string): Promise<number> {\n const layer = await this.model.getLayer(layerName);\n return layer ? layer.listElements().length : 0;\n }\n\n /**\n * Get total element count across all layers\n * @returns Total number of elements\n */\n async getTotalElementCount(): Promise<number> {\n let total = 0;\n for (const layerName of this.model.getLayerNames()) {\n const layer = await this.model.getLayer(layerName);\n if (layer) {\n total += layer.listElements().length;\n }\n }\n return total;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/ai/tools.js
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { DependencyTracker, TraceDirection } from "../core/dependency-tracker.js";
|
|
2
|
+
import { ReferenceRegistry } from "../core/reference-registry.js";
|
|
3
|
+
function getModelTools() {
|
|
4
|
+
return [
|
|
5
|
+
{
|
|
6
|
+
name: "dr_list",
|
|
7
|
+
description: "List elements in a specific layer of the architecture model",
|
|
8
|
+
input_schema: {
|
|
9
|
+
type: "object",
|
|
10
|
+
properties: {
|
|
11
|
+
layer: {
|
|
12
|
+
type: "string",
|
|
13
|
+
description: "Layer name (motivation, business, security, application, technology, api, data-model, data-store, ux, navigation, apm, testing)"
|
|
14
|
+
},
|
|
15
|
+
type: {
|
|
16
|
+
type: "string",
|
|
17
|
+
description: "Optional: filter by element type"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
required: ["layer"]
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: "dr_find",
|
|
25
|
+
description: "Find a specific element by its ID in the architecture model",
|
|
26
|
+
input_schema: {
|
|
27
|
+
type: "object",
|
|
28
|
+
properties: {
|
|
29
|
+
id: {
|
|
30
|
+
type: "string",
|
|
31
|
+
description: "Element ID to find (format: {layer}-{type}-{kebab-case-name})"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
required: ["id"]
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: "dr_search",
|
|
39
|
+
description: "Search for elements by name, description, or ID in the architecture model",
|
|
40
|
+
input_schema: {
|
|
41
|
+
type: "object",
|
|
42
|
+
properties: {
|
|
43
|
+
query: {
|
|
44
|
+
type: "string",
|
|
45
|
+
description: "Search query (searches names, descriptions, and IDs)"
|
|
46
|
+
},
|
|
47
|
+
layers: {
|
|
48
|
+
type: "array",
|
|
49
|
+
items: { type: "string" },
|
|
50
|
+
description: "Optional: limit search to specific layers"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
required: ["query"]
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "dr_trace",
|
|
58
|
+
description: "Trace dependencies for an element (what depends on it, what it depends on, or both)",
|
|
59
|
+
input_schema: {
|
|
60
|
+
type: "object",
|
|
61
|
+
properties: {
|
|
62
|
+
id: {
|
|
63
|
+
type: "string",
|
|
64
|
+
description: "Element ID to trace dependencies for"
|
|
65
|
+
},
|
|
66
|
+
direction: {
|
|
67
|
+
type: "string",
|
|
68
|
+
enum: ["up", "down", "both"],
|
|
69
|
+
description: "Dependency direction: up=dependents, down=dependencies, both=both (default: both)"
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
required: ["id"]
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
];
|
|
76
|
+
}
|
|
77
|
+
async function executeModelTool(toolName, args, model) {
|
|
78
|
+
switch (toolName) {
|
|
79
|
+
case "dr_list":
|
|
80
|
+
return await executeDrList(args, model);
|
|
81
|
+
case "dr_find":
|
|
82
|
+
return await executeDrFind(args, model);
|
|
83
|
+
case "dr_search":
|
|
84
|
+
return await executeDrSearch(args, model);
|
|
85
|
+
case "dr_trace":
|
|
86
|
+
return await executeDrTrace(args, model);
|
|
87
|
+
default:
|
|
88
|
+
return { error: `Unknown tool: ${toolName}` };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async function executeDrList(args, model) {
|
|
92
|
+
const layerName = args.layer, filterType = args.type;
|
|
93
|
+
if (!layerName)
|
|
94
|
+
return { error: "layer parameter is required" };
|
|
95
|
+
try {
|
|
96
|
+
const layer = await model.getLayer(layerName);
|
|
97
|
+
if (!layer)
|
|
98
|
+
return {
|
|
99
|
+
error: `Layer '${layerName}' not found or not loaded`,
|
|
100
|
+
availableLayers: model.getLayerNames()
|
|
101
|
+
};
|
|
102
|
+
let elements = layer.listElements();
|
|
103
|
+
return filterType && (elements = elements.filter((e) => e.type === filterType)), {
|
|
104
|
+
layer: layerName,
|
|
105
|
+
elementCount: elements.length,
|
|
106
|
+
elements: elements.map((e) => ({
|
|
107
|
+
id: e.id,
|
|
108
|
+
type: e.type,
|
|
109
|
+
name: e.name,
|
|
110
|
+
description: e.description || ""
|
|
111
|
+
}))
|
|
112
|
+
};
|
|
113
|
+
} catch (error) {
|
|
114
|
+
return {
|
|
115
|
+
error: error instanceof Error ? error.message : String(error)
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async function executeDrFind(args, model) {
|
|
120
|
+
const id = args.id;
|
|
121
|
+
if (!id)
|
|
122
|
+
return { error: "id parameter is required" };
|
|
123
|
+
try {
|
|
124
|
+
for (const layerName of model.getLayerNames()) {
|
|
125
|
+
const layer = await model.getLayer(layerName);
|
|
126
|
+
if (!layer)
|
|
127
|
+
continue;
|
|
128
|
+
const element = layer.getElement(id);
|
|
129
|
+
if (element)
|
|
130
|
+
return {
|
|
131
|
+
found: !0,
|
|
132
|
+
element: {
|
|
133
|
+
id: element.id,
|
|
134
|
+
type: element.type,
|
|
135
|
+
name: element.name,
|
|
136
|
+
description: element.description || "",
|
|
137
|
+
layer: layerName,
|
|
138
|
+
properties: element.properties || {}
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
found: !1,
|
|
144
|
+
error: `Element with id '${id}' not found`
|
|
145
|
+
};
|
|
146
|
+
} catch (error) {
|
|
147
|
+
return {
|
|
148
|
+
error: error instanceof Error ? error.message : String(error)
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async function executeDrSearch(args, model) {
|
|
153
|
+
const query = args.query?.toLowerCase(), layerFilter = args.layers || void 0;
|
|
154
|
+
if (!query)
|
|
155
|
+
return { error: "query parameter is required" };
|
|
156
|
+
try {
|
|
157
|
+
const results = [];
|
|
158
|
+
for (const layerName of model.getLayerNames()) {
|
|
159
|
+
if (layerFilter && !layerFilter.includes(layerName))
|
|
160
|
+
continue;
|
|
161
|
+
const layer = await model.getLayer(layerName);
|
|
162
|
+
if (!layer)
|
|
163
|
+
continue;
|
|
164
|
+
const elements = layer.listElements();
|
|
165
|
+
for (const element of elements) {
|
|
166
|
+
const idMatches = element.id.toLowerCase().includes(query), nameMatches = element.name.toLowerCase().includes(query), descMatches = element.description && element.description.toLowerCase().includes(query);
|
|
167
|
+
(idMatches || nameMatches || descMatches) && results.push({
|
|
168
|
+
id: element.id,
|
|
169
|
+
type: element.type,
|
|
170
|
+
name: element.name,
|
|
171
|
+
description: element.description || "",
|
|
172
|
+
layer: layerName,
|
|
173
|
+
matchReason: idMatches && nameMatches ? "id and name" : idMatches ? "id" : nameMatches ? "name" : "description"
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
query,
|
|
179
|
+
resultCount: results.length,
|
|
180
|
+
results
|
|
181
|
+
};
|
|
182
|
+
} catch (error) {
|
|
183
|
+
return {
|
|
184
|
+
error: error instanceof Error ? error.message : String(error)
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
async function executeDrTrace(args, model) {
|
|
189
|
+
const id = args.id, direction = args.direction || "both";
|
|
190
|
+
if (!id)
|
|
191
|
+
return { error: "id parameter is required" };
|
|
192
|
+
if (!["up", "down", "both"].includes(direction))
|
|
193
|
+
return { error: "direction must be one of: up, down, both" };
|
|
194
|
+
try {
|
|
195
|
+
const registry = new ReferenceRegistry();
|
|
196
|
+
for (const layerName of model.getLayerNames()) {
|
|
197
|
+
const layer = await model.getLayer(layerName);
|
|
198
|
+
if (layer)
|
|
199
|
+
for (const element of layer.listElements())
|
|
200
|
+
registry.registerElement(element);
|
|
201
|
+
}
|
|
202
|
+
const tracker = new DependencyTracker(registry), result = {
|
|
203
|
+
id,
|
|
204
|
+
direction
|
|
205
|
+
};
|
|
206
|
+
if (direction === "down" || direction === "both")
|
|
207
|
+
try {
|
|
208
|
+
const dependencies = tracker.traceDependencies(id, TraceDirection.UP, null);
|
|
209
|
+
result.dependencies = dependencies, result.dependencyCount = dependencies.length;
|
|
210
|
+
} catch {
|
|
211
|
+
result.dependencies = [], result.dependencyCount = 0;
|
|
212
|
+
}
|
|
213
|
+
if (direction === "up" || direction === "both")
|
|
214
|
+
try {
|
|
215
|
+
const dependents = tracker.traceDependencies(id, TraceDirection.DOWN, null);
|
|
216
|
+
result.dependents = dependents, result.dependentCount = dependents.length;
|
|
217
|
+
} catch {
|
|
218
|
+
result.dependents = [], result.dependentCount = 0;
|
|
219
|
+
}
|
|
220
|
+
return result;
|
|
221
|
+
} catch (error) {
|
|
222
|
+
return {
|
|
223
|
+
error: error instanceof Error ? error.message : String(error)
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
export {
|
|
228
|
+
executeModelTool,
|
|
229
|
+
getModelTools
|
|
230
|
+
};
|
|
231
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/ai/tools.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Tool Definitions for Claude AI Integration\n * Defines tools for dr_list, dr_find, dr_search, and dr_trace\n *\n * NOTE: These tool definitions are used for legacy SDK-based chat only.\n * The `dr chat` command uses Claude Code CLI subprocess with Bash and Read tools instead.\n */\n\nimport { Model } from '../core/model.js';\nimport { DependencyTracker, TraceDirection } from '../core/dependency-tracker.js';\nimport { ReferenceRegistry } from '../core/reference-registry.js';\n\n/**\n * Get tool definitions for Claude to use with the model\n * @returns Array of tool definitions in Claude format\n */\nexport function getModelTools(): any[] {\n return [\n {\n name: 'dr_list',\n description: 'List elements in a specific layer of the architecture model',\n input_schema: {\n type: 'object',\n properties: {\n layer: {\n type: 'string',\n description:\n 'Layer name (motivation, business, security, application, technology, api, data-model, data-store, ux, navigation, apm, testing)',\n },\n type: {\n type: 'string',\n description: 'Optional: filter by element type',\n },\n },\n required: ['layer'],\n },\n },\n {\n name: 'dr_find',\n description: 'Find a specific element by its ID in the architecture model',\n input_schema: {\n type: 'object',\n properties: {\n id: {\n type: 'string',\n description: 'Element ID to find (format: {layer}-{type}-{kebab-case-name})',\n },\n },\n required: ['id'],\n },\n },\n {\n name: 'dr_search',\n description: 'Search for elements by name, description, or ID in the architecture model',\n input_schema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'Search query (searches names, descriptions, and IDs)',\n },\n layers: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional: limit search to specific layers',\n },\n },\n required: ['query'],\n },\n },\n {\n name: 'dr_trace',\n description:\n 'Trace dependencies for an element (what depends on it, what it depends on, or both)',\n input_schema: {\n type: 'object',\n properties: {\n id: {\n type: 'string',\n description: 'Element ID to trace dependencies for',\n },\n direction: {\n type: 'string',\n enum: ['up', 'down', 'both'],\n description:\n 'Dependency direction: up=dependents, down=dependencies, both=both (default: both)',\n },\n },\n required: ['id'],\n },\n },\n ];\n}\n\n/**\n * Execute a tool and return the result\n * @param toolName Name of the tool to execute\n * @param args Tool arguments\n * @param model The architecture model\n * @returns Tool execution result as JSON\n */\nexport async function executeModelTool(\n toolName: string,\n args: Record<string, unknown>,\n model: Model\n): Promise<any> {\n switch (toolName) {\n case 'dr_list':\n return await executeDrList(args, model);\n\n case 'dr_find':\n return await executeDrFind(args, model);\n\n case 'dr_search':\n return await executeDrSearch(args, model);\n\n case 'dr_trace':\n return await executeDrTrace(args, model);\n\n default:\n return { error: `Unknown tool: ${toolName}` };\n }\n}\n\n/**\n * Execute dr_list tool\n */\nasync function executeDrList(args: Record<string, unknown>, model: Model): Promise<any> {\n const layerName = args.layer as string;\n const filterType = args.type as string | undefined;\n\n if (!layerName) {\n return { error: 'layer parameter is required' };\n }\n\n try {\n const layer = await model.getLayer(layerName);\n\n if (!layer) {\n return {\n error: `Layer '${layerName}' not found or not loaded`,\n availableLayers: model.getLayerNames(),\n };\n }\n\n let elements = layer.listElements();\n\n if (filterType) {\n elements = elements.filter((e) => e.type === filterType);\n }\n\n return {\n layer: layerName,\n elementCount: elements.length,\n elements: elements.map((e) => ({\n id: e.id,\n type: e.type,\n name: e.name,\n description: e.description || '',\n })),\n };\n } catch (error) {\n return {\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\n/**\n * Execute dr_find tool\n */\nasync function executeDrFind(args: Record<string, unknown>, model: Model): Promise<any> {\n const id = args.id as string;\n\n if (!id) {\n return { error: 'id parameter is required' };\n }\n\n try {\n // Search through all layers for the element\n for (const layerName of model.getLayerNames()) {\n const layer = await model.getLayer(layerName);\n if (!layer) continue;\n\n const element = layer.getElement(id);\n if (element) {\n return {\n found: true,\n element: {\n id: element.id,\n type: element.type,\n name: element.name,\n description: element.description || '',\n layer: layerName,\n properties: element.properties || {},\n },\n };\n }\n }\n\n return {\n found: false,\n error: `Element with id '${id}' not found`,\n };\n } catch (error) {\n return {\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\n/**\n * Execute dr_search tool\n */\nasync function executeDrSearch(args: Record<string, unknown>, model: Model): Promise<any> {\n const query = (args.query as string)?.toLowerCase();\n const layerFilter = (args.layers as string[]) || undefined;\n\n if (!query) {\n return { error: 'query parameter is required' };\n }\n\n try {\n const results: any[] = [];\n\n for (const layerName of model.getLayerNames()) {\n // Skip if layer is in exclude list\n if (layerFilter && !layerFilter.includes(layerName)) {\n continue;\n }\n\n const layer = await model.getLayer(layerName);\n if (!layer) continue;\n\n const elements = layer.listElements();\n\n for (const element of elements) {\n const idMatches = element.id.toLowerCase().includes(query);\n const nameMatches = element.name.toLowerCase().includes(query);\n const descMatches =\n element.description && element.description.toLowerCase().includes(query);\n\n if (idMatches || nameMatches || descMatches) {\n results.push({\n id: element.id,\n type: element.type,\n name: element.name,\n description: element.description || '',\n layer: layerName,\n matchReason:\n idMatches && nameMatches\n ? 'id and name'\n : idMatches\n ? 'id'\n : nameMatches\n ? 'name'\n : 'description',\n });\n }\n }\n }\n\n return {\n query,\n resultCount: results.length,\n results,\n };\n } catch (error) {\n return {\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\n/**\n * Execute dr_trace tool\n */\nasync function executeDrTrace(args: Record<string, unknown>, model: Model): Promise<any> {\n const id = args.id as string;\n const direction = (args.direction as string) || 'both';\n\n if (!id) {\n return { error: 'id parameter is required' };\n }\n\n if (!['up', 'down', 'both'].includes(direction)) {\n return { error: 'direction must be one of: up, down, both' };\n }\n\n try {\n // Build registry by collecting all references from all loaded layers\n const registry = new ReferenceRegistry();\n\n for (const layerName of model.getLayerNames()) {\n const layer = await model.getLayer(layerName);\n if (!layer) continue;\n\n for (const element of layer.listElements()) {\n registry.registerElement(element);\n }\n }\n\n // Create dependency tracker with registry\n const tracker = new DependencyTracker(registry);\n\n const result: any = {\n id,\n direction,\n };\n\n // Get dependencies (elements this one depends on)\n if (direction === 'down' || direction === 'both') {\n try {\n const dependencies = tracker.traceDependencies(id, TraceDirection.UP, null);\n result.dependencies = dependencies;\n result.dependencyCount = dependencies.length;\n } catch (e) {\n result.dependencies = [];\n result.dependencyCount = 0;\n }\n }\n\n // Get dependents (elements that depend on this one)\n if (direction === 'up' || direction === 'both') {\n try {\n const dependents = tracker.traceDependencies(id, TraceDirection.DOWN, null);\n result.dependents = dependents;\n result.dependentCount = dependents.length;\n } catch (e) {\n result.dependents = [];\n result.dependentCount = 0;\n }\n }\n\n return result;\n } catch (error) {\n return {\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|