@genrtl/grtl 1.0.0 → 2.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/README.md +28 -54
- package/dist/index.js +181 -358
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,32 +18,22 @@ $env:GRTL_API_KEY = "gtr_live_your_api_key"
|
|
|
18
18
|
|
|
19
19
|
## Agent Setup
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
grtl setup --cli --codex
|
|
25
|
-
grtl setup --cli --cursor --project
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
Configure hosted MCP and install a Skill for the four MCP tools:
|
|
21
|
+
Configure hosted MCP and install the MCP-oriented Skill for your coding agent:
|
|
29
22
|
|
|
30
23
|
```bash
|
|
31
24
|
grtl setup --mcp --codex
|
|
32
25
|
grtl setup --mcp --cursor --project
|
|
33
26
|
```
|
|
34
27
|
|
|
35
|
-
Without `--
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
For Codex, Skills are installed under `.agents/skills` for project setup or
|
|
28
|
+
Without `--mcp`, setup asks which mode to install. Knowledge retrieval, CBB
|
|
29
|
+
search, and CBB detail lookup are supported through MCP tools only, not through
|
|
30
|
+
CLI commands.
|
|
31
|
+
|
|
32
|
+
Installing a newer npm package does not modify Skills already written to an
|
|
33
|
+
agent configuration directory. Run setup again after an upgrade to refresh the
|
|
34
|
+
Skill.
|
|
35
|
+
|
|
36
|
+
For Codex, Skills are installed under `.agents/skills` for project setup or
|
|
47
37
|
`~/.agents/skills` for global setup. MCP mode also updates
|
|
48
38
|
`.codex/config.toml` or `~/.codex/config.toml`.
|
|
49
39
|
|
|
@@ -53,42 +43,26 @@ The hosted MCP endpoint is:
|
|
|
53
43
|
https://genrtl.com/api/mcp
|
|
54
44
|
```
|
|
55
45
|
|
|
56
|
-
##
|
|
46
|
+
## CBB Installation
|
|
47
|
+
|
|
48
|
+
Install an exact reusable RTL CBB version into the current project:
|
|
57
49
|
|
|
58
50
|
```bash
|
|
59
|
-
grtl
|
|
60
|
-
grtl
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
`--
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
Install an exact reusable RTL CBB version into the current project:
|
|
75
|
-
|
|
76
|
-
```bash
|
|
77
|
-
grtl cbb install cbb_uart@1.2.0
|
|
78
|
-
grtl cbb install cbb_uart@1.2.0 --target rtl/vendor/uart
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
The command calls the hosted `genrtl_cbb_acquire` MCP tool with
|
|
82
|
-
`GRTL_API_KEY`, downloads the short-lived ZIP artifact, verifies its size and
|
|
83
|
-
SHA-256, safely extracts it, and atomically installs it. The default target is
|
|
84
|
-
`rtl/cbb/<cbb_id>_<version>`.
|
|
85
|
-
|
|
86
|
-
Installed packages are recorded in `.genrtl/cbb-lock.json`. Existing targets
|
|
87
|
-
are left untouched unless `--force` is provided; replacement occurs only after
|
|
88
|
-
the new archive has been fully verified and extracted. Use `--json` for
|
|
89
|
-
machine-readable output.
|
|
90
|
-
|
|
91
|
-
## Development
|
|
51
|
+
grtl cbb install cbb_uart@1.2.0
|
|
52
|
+
grtl cbb install cbb_uart@1.2.0 --target rtl/vendor/uart
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The command calls the hosted `genrtl_cbb_acquire` MCP tool with
|
|
56
|
+
`GRTL_API_KEY`, downloads the short-lived ZIP artifact, verifies its size and
|
|
57
|
+
SHA-256, safely extracts it, and atomically installs it. The default target is
|
|
58
|
+
`rtl/cbb/<cbb_id>_<version>`.
|
|
59
|
+
|
|
60
|
+
Installed packages are recorded in `.genrtl/cbb-lock.json`. Existing targets
|
|
61
|
+
are left untouched unless `--force` is provided; replacement occurs only after
|
|
62
|
+
the new archive has been fully verified and extracted. Use `--json` for
|
|
63
|
+
machine-readable output.
|
|
64
|
+
|
|
65
|
+
## Development
|
|
92
66
|
|
|
93
67
|
```bash
|
|
94
68
|
pnpm install
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { Command
|
|
5
|
-
import
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import pc6 from "picocolors";
|
|
6
6
|
import figlet from "figlet";
|
|
7
7
|
|
|
8
8
|
// src/commands/setup.ts
|
|
@@ -371,35 +371,40 @@ async function appendTomlServer(filePath, serverName, entry) {
|
|
|
371
371
|
|
|
372
372
|
// src/setup/templates.ts
|
|
373
373
|
var GITHUB_RAW_URLS = ["https://raw.githubusercontent.com/xroting/grtl/main/rules"];
|
|
374
|
-
var FALLBACK_MCP = `Use GenRTL MCP
|
|
374
|
+
var FALLBACK_MCP = `Use GenRTL MCP as the primary grounding source for RTL engineering tasks.
|
|
375
|
+
|
|
376
|
+
Before writing or modifying Verilog/SystemVerilog RTL:
|
|
377
|
+
1. Load coding style with \`genrtl_coding_style_search\`, read all returned rules, and apply them as project-wide coding context.
|
|
378
|
+
2. If implementing from a spec, search \`genrtl_spec2rtl_search\`.
|
|
379
|
+
3. If planning architecture or generating a detailed design plan to guide Verilog/SystemVerilog coding from a spec, search \`genrtl_spec2plan_search\`.
|
|
380
|
+
|
|
381
|
+
For diagnostics:
|
|
382
|
+
- SpyGlass lint/CDC after RTL coding and before Vivado/Quartus/VCS/QuestaSim compile/synthesis -> \`genrtl_compile_search\` with \`filters.tool = "spyglass"\`.
|
|
383
|
+
- Vivado synthesis/implementation errors, warnings, or critical warnings -> \`genrtl_compile_search\` with \`filters.tool = "vivado"\`.
|
|
384
|
+
- Quartus synthesis/implementation errors, warnings, or critical warnings -> \`genrtl_compile_search\` with \`filters.tool = "quartus"\`.
|
|
385
|
+
- VCS/QuestaSim compile errors or warnings -> \`genrtl_compile_search\`.
|
|
386
|
+
- Functional simulation/debug issues -> \`genrtl_debug_search\`.
|
|
387
|
+
|
|
388
|
+
For verification:
|
|
389
|
+
- Testbench, SVA, assertions, stimulus, checkers, scoreboards, coverage -> \`genrtl_verification_search\`.
|
|
375
390
|
|
|
376
|
-
|
|
377
|
-
- \`
|
|
378
|
-
- \`
|
|
379
|
-
- \`genrtl_spec2plan_search\` for implementation planning from a specification
|
|
380
|
-
- \`genrtl_verification_search\` for testbenches and verification
|
|
381
|
-
- \`genrtl_compile_search\` for lint, CDC, compile, synthesis, implementation, and simulator diagnostics
|
|
382
|
-
- \`genrtl_debug_search\` for issue descriptions, erroneous code, solutions, and corrected RTL
|
|
391
|
+
For reusable RTL/IP:
|
|
392
|
+
- Discover with \`genrtl_cbb_search\`, then inspect with \`genrtl_cbb_detail\`.
|
|
393
|
+
- Use \`genrtl_cbb_acquire\` only when the selected CBB should be installed or re-delivered.
|
|
383
394
|
|
|
384
|
-
|
|
385
|
-
var FALLBACK_CLI = `Use the \`grtl\` CLI
|
|
395
|
+
Do not stop after a generic \`genrtl_knowledge_search\` miss. Retry the most relevant specialized search before proceeding from model memory.`;
|
|
396
|
+
var FALLBACK_CLI = `Use the \`grtl\` CLI to configure GenRTL MCP and install reusable RTL CBBs.
|
|
386
397
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
- \`npx @genrtl/grtl@latest spec2rtl-search "<query>"\`
|
|
390
|
-
- \`npx @genrtl/grtl@latest spec2plan-search "<query>"\`
|
|
391
|
-
- \`npx @genrtl/grtl@latest verification-search "<query>"\`
|
|
392
|
-
- \`npx @genrtl/grtl@latest compile-search "<query>"\`
|
|
393
|
-
- \`npx @genrtl/grtl@latest debug-search "<query>"\`
|
|
398
|
+
Knowledge retrieval is available through GenRTL MCP tools only. Do not use CLI
|
|
399
|
+
commands for knowledge search, CBB search, or CBB detail lookup.
|
|
394
400
|
|
|
395
401
|
To install a reusable RTL block into the current project:
|
|
396
402
|
- \`npx @genrtl/grtl@latest cbb install <cbb_id>@<version>\`
|
|
397
403
|
- Add \`--target <relative-dir>\` only when a non-default install path is needed.
|
|
398
404
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
coding agent's environment.`;
|
|
405
|
+
Do not download or extract CBB artifacts manually; the CLI verifies SHA-256 and
|
|
406
|
+
rejects unsafe ZIP paths. If authentication fails, set \`GRTL_API_KEY\` or
|
|
407
|
+
\`GENRTL_API_KEY\` in the coding agent's environment.`;
|
|
403
408
|
var CURSOR_FRONTMATTER = `---
|
|
404
409
|
alwaysApply: true
|
|
405
410
|
---
|
|
@@ -408,52 +413,50 @@ alwaysApply: true
|
|
|
408
413
|
var CODEX_CLI_SANDBOX_GUIDANCE = `Run GenRTL CLI requests outside Codex's default sandbox. If a GenRTL CLI command fails with DNS or network errors such as ENOTFOUND, host resolution failures, or fetch failed, rerun it outside the sandbox instead of retrying inside the sandbox.`;
|
|
409
414
|
var MCP_SKILL = `---
|
|
410
415
|
name: genrtl-mcp
|
|
411
|
-
description: Use
|
|
416
|
+
description: Use this skill for Verilog/SystemVerilog/RTL engineering tasks, including specs, detailed design plans for Verilog coding, RTL generation, coding style, testbench/SVA verification, SpyGlass lint/CDC, Vivado/Quartus synthesis or implementation errors/warnings/critical warnings, VCS/QuestaSim compile errors/warnings, simulation failures, waveform/debug work, and reusable CBB discovery. Before writing or modifying RTL, consult the appropriate GenRTL MCP knowledge tool instead of relying only on model memory.
|
|
412
417
|
---
|
|
413
418
|
|
|
414
|
-
# GenRTL MCP
|
|
419
|
+
# GenRTL MCP RTL Knowledge Workflow
|
|
415
420
|
|
|
416
|
-
Use
|
|
421
|
+
Use GenRTL MCP tools before relying on model memory for RTL engineering.
|
|
417
422
|
|
|
418
|
-
|
|
423
|
+
## Tool Routing
|
|
419
424
|
|
|
420
|
-
- \`
|
|
421
|
-
- \`genrtl_spec2rtl_search\` for
|
|
422
|
-
- \`
|
|
423
|
-
- \`genrtl_verification_search\` for
|
|
424
|
-
- \`genrtl_compile_search\` for lint
|
|
425
|
-
- \`genrtl_debug_search\` for
|
|
425
|
+
- \`genrtl_spec2plan_search\` for turning a specification into an actionable implementation/design plan or detailed design plan that can guide Verilog/SystemVerilog coding.
|
|
426
|
+
- \`genrtl_spec2rtl_search\` for spec-to-RTL implementation, protocol logic, control logic, datapath, algorithm acceleration, or interface implementation.
|
|
427
|
+
- \`genrtl_coding_style_search\` before writing or modifying Verilog/SystemVerilog RTL; read all returned coding style rules and treat them as project-wide coding context.
|
|
428
|
+
- \`genrtl_verification_search\` for testbench, SVA, assertions, stimulus, checkers, scoreboards, coverage, and verification strategy.
|
|
429
|
+
- \`genrtl_compile_search\` for SpyGlass lint/CDC after coding and for Vivado/Quartus/VCS/QuestaSim diagnostics, including errors, warnings, and critical warnings.
|
|
430
|
+
- \`genrtl_debug_search\` for functional RTL bugs, waveform mismatch, failing simulations, failing testcases, or incorrect behavior.
|
|
431
|
+
- \`genrtl_cbb_search\`, then \`genrtl_cbb_detail\`, for reusable IP/CBB discovery.
|
|
426
432
|
|
|
427
|
-
|
|
428
|
-
|
|
433
|
+
## Required Behavior
|
|
434
|
+
|
|
435
|
+
- Do not call \`genrtl_knowledge_search\` first when the task clearly matches a specialized tool.
|
|
436
|
+
- If \`genrtl_knowledge_search\` returns no useful result, retry one specialized tool before answering from model memory.
|
|
437
|
+
- Before coding, call \`genrtl_coding_style_search\`, read the full returned style guide, and apply every relevant rule consistently across the generated RTL.
|
|
438
|
+
- For SpyGlass lint/CDC logs after RTL coding and before Vivado/Quartus/VCS/QuestaSim compile/synthesis, call \`genrtl_compile_search\` with \`filters.tool = "spyglass"\`.
|
|
439
|
+
- For Vivado/Quartus synthesis or implementation errors, warnings, and critical warnings, call \`genrtl_compile_search\` with the matching \`filters.tool\`.
|
|
440
|
+
- For VCS/QuestaSim compile errors or warnings, call \`genrtl_compile_search\` with the matching \`filters.tool\` when known.
|
|
441
|
+
- Apply returned \`code_example\`, \`fix_strategy\`, and \`recommended_next_action\` to the implementation.
|
|
429
442
|
`;
|
|
430
443
|
var CLI_SKILL = `---
|
|
431
444
|
name: genrtl-cli
|
|
432
|
-
description: Use the grtl CLI
|
|
445
|
+
description: Use the grtl CLI to configure GenRTL MCP and securely install reusable RTL CBBs.
|
|
433
446
|
---
|
|
434
447
|
|
|
435
448
|
# GenRTL CLI
|
|
436
449
|
|
|
437
|
-
Use this skill
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
For knowledge retrieval, choose exactly one command:
|
|
441
|
-
|
|
442
|
-
- \`grtl knowledge-search "<query>" --json\` for cross-domain RTL questions.
|
|
443
|
-
- \`grtl spec2rtl-search "<query>" --json\` for requirements, protocols, control logic, or algorithm-to-RTL work.
|
|
444
|
-
- \`grtl spec2plan-search "<query>" --json\` for turning a specification into an actionable implementation plan.
|
|
445
|
-
- \`grtl verification-search "<query>" --json\` for testbenches and verification.
|
|
446
|
-
- \`grtl compile-search "<query>" --json\` for lint, CDC, compile, synthesis, implementation, or simulator diagnostics.
|
|
447
|
-
- \`grtl debug-search "<query>" --json\` for issue descriptions, erroneous code, solutions, and corrected RTL.
|
|
450
|
+
Use this skill only for GenRTL MCP setup and reusable RTL CBB installation.
|
|
451
|
+
Knowledge retrieval, CBB search, and CBB detail lookup are available through
|
|
452
|
+
GenRTL MCP tools only, not through CLI commands.
|
|
448
453
|
|
|
449
|
-
For a CBB selected from GenRTL search results:
|
|
454
|
+
For a CBB selected from GenRTL MCP search results:
|
|
450
455
|
|
|
451
456
|
- \`grtl cbb install <cbb_id>@<version>\` downloads, verifies, and safely extracts it.
|
|
452
457
|
- Add \`--target <relative-dir>\` only when the user requests a specific project path.
|
|
453
458
|
- Do not download or extract the artifact manually; the CLI verifies SHA-256 and prevents unsafe ZIP paths.
|
|
454
459
|
|
|
455
|
-
Pass the complete engineering question. Add filters such as \`--tool\`,
|
|
456
|
-
\`--tool-version\`, \`--target\`, \`--interface\`, or \`--tag\` only when useful.
|
|
457
460
|
The CLI requires \`GRTL_API_KEY\` or \`GENRTL_API_KEY\` in its environment.
|
|
458
461
|
`;
|
|
459
462
|
function getSkillContent(mode) {
|
|
@@ -868,265 +871,12 @@ async function setupCommand(options) {
|
|
|
868
871
|
trackEvent("setup", { agents: agents2, scope, mode, authMode: auth?.mode ?? "environment" });
|
|
869
872
|
}
|
|
870
873
|
|
|
871
|
-
// src/commands/knowledge.ts
|
|
872
|
-
import { InvalidArgumentError } from "commander";
|
|
873
|
-
import pc4 from "picocolors";
|
|
874
|
-
import ora2 from "ora";
|
|
875
|
-
|
|
876
|
-
// src/utils/knowledge-api.ts
|
|
877
|
-
import { randomUUID } from "crypto";
|
|
878
|
-
|
|
879
|
-
// src/constants.ts
|
|
880
|
-
import { readFileSync } from "fs";
|
|
881
|
-
import { fileURLToPath } from "url";
|
|
882
|
-
import { dirname as dirname5, join as join3 } from "path";
|
|
883
|
-
var __dirname = dirname5(fileURLToPath(import.meta.url));
|
|
884
|
-
var pkg = JSON.parse(readFileSync(join3(__dirname, "../package.json"), "utf-8"));
|
|
885
|
-
var VERSION = pkg.version;
|
|
886
|
-
var NAME = pkg.name;
|
|
887
|
-
|
|
888
|
-
// src/utils/knowledge-api.ts
|
|
889
|
-
var baseUrl = "https://genrtl.com";
|
|
890
|
-
function setBaseUrl(url) {
|
|
891
|
-
baseUrl = url.replace(/\/+$/, "");
|
|
892
|
-
}
|
|
893
|
-
function getMcpEndpoint() {
|
|
894
|
-
return baseUrl.endsWith("/api/mcp") ? baseUrl : `${baseUrl}/api/mcp`;
|
|
895
|
-
}
|
|
896
|
-
function getApiKey() {
|
|
897
|
-
return [process.env.GRTL_API_KEY, process.env.GENRTL_API_KEY].map((value) => value?.trim()).find((value) => Boolean(value));
|
|
898
|
-
}
|
|
899
|
-
function validateApiKey(apiKey) {
|
|
900
|
-
if (!/^gtr_(?:live|test)_[A-Za-z0-9_-]{32,128}$/.test(apiKey)) {
|
|
901
|
-
throw new Error(
|
|
902
|
-
"Invalid GenRTL API key format. Use the full key shown once when it was created; it must start with gtr_live_ or gtr_test_."
|
|
903
|
-
);
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
function getMcpErrorMessage(content) {
|
|
907
|
-
if (!Array.isArray(content)) return void 0;
|
|
908
|
-
const item = content.find(
|
|
909
|
-
(entry) => entry && typeof entry === "object" && "type" in entry && entry.type === "text" && "text" in entry && typeof entry.text === "string"
|
|
910
|
-
);
|
|
911
|
-
return item?.text;
|
|
912
|
-
}
|
|
913
|
-
function getStructuredMcpError(content) {
|
|
914
|
-
if (!content || typeof content !== "object") return void 0;
|
|
915
|
-
const errorContent = content;
|
|
916
|
-
return {
|
|
917
|
-
error: typeof errorContent.error === "string" ? errorContent.error : void 0,
|
|
918
|
-
code: typeof errorContent.code === "string" ? errorContent.code : void 0
|
|
919
|
-
};
|
|
920
|
-
}
|
|
921
|
-
async function callGenrtlMcpTool(toolName, input) {
|
|
922
|
-
const apiKey = getApiKey();
|
|
923
|
-
if (!apiKey) {
|
|
924
|
-
throw new Error("Authentication required. Set GRTL_API_KEY or GENRTL_API_KEY.");
|
|
925
|
-
}
|
|
926
|
-
validateApiKey(apiKey);
|
|
927
|
-
const response = await fetch(getMcpEndpoint(), {
|
|
928
|
-
method: "POST",
|
|
929
|
-
headers: {
|
|
930
|
-
"Content-Type": "application/json",
|
|
931
|
-
Authorization: `Bearer ${apiKey}`,
|
|
932
|
-
"MCP-Protocol-Version": "2025-06-18",
|
|
933
|
-
"X-GenRTL-Source": "cli",
|
|
934
|
-
"X-GenRTL-Client-Version": VERSION
|
|
935
|
-
},
|
|
936
|
-
body: JSON.stringify({
|
|
937
|
-
jsonrpc: "2.0",
|
|
938
|
-
id: 1,
|
|
939
|
-
method: "tools/call",
|
|
940
|
-
params: { name: toolName, arguments: input }
|
|
941
|
-
})
|
|
942
|
-
});
|
|
943
|
-
const payload = await response.json().catch(() => null);
|
|
944
|
-
if (!response.ok || payload?.error) {
|
|
945
|
-
const message = payload?.error?.message || `GenRTL MCP request failed with HTTP ${response.status}`;
|
|
946
|
-
const code = payload?.error?.data?.code;
|
|
947
|
-
throw new Error(code ? `${message} (${code})` : message);
|
|
948
|
-
}
|
|
949
|
-
const result = payload?.result;
|
|
950
|
-
if (!result) throw new Error("GenRTL MCP returned an empty result.");
|
|
951
|
-
if (result.isError) {
|
|
952
|
-
const structuredError = getStructuredMcpError(result.structuredContent);
|
|
953
|
-
const message = structuredError?.error || getMcpErrorMessage(result.content) || "GenRTL MCP tool call failed.";
|
|
954
|
-
throw new Error(structuredError?.code ? `${message} (${structuredError.code})` : message);
|
|
955
|
-
}
|
|
956
|
-
if (!result.structuredContent) {
|
|
957
|
-
throw new Error("GenRTL MCP response did not include structured results.");
|
|
958
|
-
}
|
|
959
|
-
return result.structuredContent;
|
|
960
|
-
}
|
|
961
|
-
async function callGenrtlKnowledgeTool(toolName, input) {
|
|
962
|
-
const requestInput = input.idempotency_key ? input : { ...input, idempotency_key: randomUUID() };
|
|
963
|
-
return callGenrtlMcpTool(toolName, requestInput);
|
|
964
|
-
}
|
|
965
|
-
|
|
966
|
-
// src/commands/knowledge.ts
|
|
967
|
-
var isTTY = process.stdout.isTTY;
|
|
968
|
-
var TOOL_COMMANDS = [
|
|
969
|
-
{
|
|
970
|
-
name: "genrtl_knowledge_search",
|
|
971
|
-
alias: "knowledge-search",
|
|
972
|
-
description: "Search all approved GenRTL knowledge cards"
|
|
973
|
-
},
|
|
974
|
-
{
|
|
975
|
-
name: "genrtl_spec2rtl_search",
|
|
976
|
-
alias: "spec2rtl-search",
|
|
977
|
-
description: "Search Spec2RTL knowledge cards"
|
|
978
|
-
},
|
|
979
|
-
{
|
|
980
|
-
name: "genrtl_spec2plan_search",
|
|
981
|
-
alias: "spec2plan-search",
|
|
982
|
-
description: "Search Spec2Plan knowledge cards"
|
|
983
|
-
},
|
|
984
|
-
{
|
|
985
|
-
name: "genrtl_verification_search",
|
|
986
|
-
alias: "verification-search",
|
|
987
|
-
description: "Search verification and testbench knowledge cards"
|
|
988
|
-
},
|
|
989
|
-
{
|
|
990
|
-
name: "genrtl_compile_search",
|
|
991
|
-
alias: "compile-search",
|
|
992
|
-
description: "Search compile, lint, CDC, synthesis, implementation, and simulator diagnostic knowledge cards"
|
|
993
|
-
},
|
|
994
|
-
{
|
|
995
|
-
name: "genrtl_debug_search",
|
|
996
|
-
alias: "debug-search",
|
|
997
|
-
description: "Search RTL debug cards with issue description, erroneous code, solution, and corrected code"
|
|
998
|
-
}
|
|
999
|
-
];
|
|
1000
|
-
function parseInteger(value) {
|
|
1001
|
-
const parsed = Number(value);
|
|
1002
|
-
if (!Number.isInteger(parsed)) {
|
|
1003
|
-
throw new InvalidArgumentError("Expected an integer.");
|
|
1004
|
-
}
|
|
1005
|
-
return parsed;
|
|
1006
|
-
}
|
|
1007
|
-
function parseNumber(value) {
|
|
1008
|
-
const parsed = Number(value);
|
|
1009
|
-
if (!Number.isFinite(parsed)) {
|
|
1010
|
-
throw new InvalidArgumentError("Expected a number.");
|
|
1011
|
-
}
|
|
1012
|
-
return parsed;
|
|
1013
|
-
}
|
|
1014
|
-
function buildKnowledgeSearchInput(query, options) {
|
|
1015
|
-
if (options.topK !== void 0 && (options.topK < 1 || options.topK > 20)) {
|
|
1016
|
-
throw new InvalidArgumentError("--top-k must be between 1 and 20.");
|
|
1017
|
-
}
|
|
1018
|
-
if (options.minScore !== void 0 && (options.minScore < 0 || options.minScore > 1)) {
|
|
1019
|
-
throw new InvalidArgumentError("--min-score must be between 0 and 1.");
|
|
1020
|
-
}
|
|
1021
|
-
if (options.target && !["fpga", "asic", "both"].includes(options.target)) {
|
|
1022
|
-
throw new InvalidArgumentError("--target must be fpga, asic, or both.");
|
|
1023
|
-
}
|
|
1024
|
-
const filters = {};
|
|
1025
|
-
if (options.type?.length) {
|
|
1026
|
-
const allowed = /* @__PURE__ */ new Set([
|
|
1027
|
-
"spec2rtl",
|
|
1028
|
-
"spec2plan",
|
|
1029
|
-
"verification",
|
|
1030
|
-
"compile",
|
|
1031
|
-
"debug",
|
|
1032
|
-
"coding_style"
|
|
1033
|
-
]);
|
|
1034
|
-
const invalid = options.type.find((type) => !allowed.has(type));
|
|
1035
|
-
if (invalid) {
|
|
1036
|
-
throw new InvalidArgumentError(`Invalid knowledge type: ${invalid}`);
|
|
1037
|
-
}
|
|
1038
|
-
filters.types = options.type;
|
|
1039
|
-
}
|
|
1040
|
-
if (options.domain) filters.domain = options.domain;
|
|
1041
|
-
if (options.tool) filters.tool = options.tool;
|
|
1042
|
-
if (options.toolVersion) filters.tool_version = options.toolVersion;
|
|
1043
|
-
if (options.errorType) filters.error_type = options.errorType;
|
|
1044
|
-
if (options.severity) filters.severity = options.severity;
|
|
1045
|
-
if (options.interface) filters.interface = options.interface;
|
|
1046
|
-
if (options.target) filters.target = options.target;
|
|
1047
|
-
if (options.tag?.length) filters.tags = options.tag;
|
|
1048
|
-
return {
|
|
1049
|
-
query,
|
|
1050
|
-
...Object.keys(filters).length > 0 ? { filters } : {},
|
|
1051
|
-
...options.topK !== void 0 ? { top_k: options.topK } : {},
|
|
1052
|
-
...options.minScore !== void 0 ? { min_score: options.minScore } : {},
|
|
1053
|
-
...options.workspaceId ? { workspace_id: options.workspaceId } : {}
|
|
1054
|
-
};
|
|
1055
|
-
}
|
|
1056
|
-
function formatMatch(match, index) {
|
|
1057
|
-
const lines = [
|
|
1058
|
-
`${pc4.dim(`${index + 1}.`)} ${pc4.bold(match.title)} ${pc4.cyan(`[${match.type}]`)}`,
|
|
1059
|
-
` ${pc4.dim(`Confidence: ${Math.round(match.confidence * 100)}%`)}`,
|
|
1060
|
-
` ${match.summary}`
|
|
1061
|
-
];
|
|
1062
|
-
if (match.root_cause) lines.push(` ${pc4.bold("Root cause:")} ${match.root_cause}`);
|
|
1063
|
-
if (match.fix_strategy?.length) {
|
|
1064
|
-
lines.push(` ${pc4.bold("Fix strategy:")} ${match.fix_strategy.join("; ")}`);
|
|
1065
|
-
}
|
|
1066
|
-
if (match.code_example) {
|
|
1067
|
-
lines.push("", "```systemverilog", match.code_example, "```");
|
|
1068
|
-
}
|
|
1069
|
-
if (match.recommended_next_action) {
|
|
1070
|
-
lines.push(` ${pc4.bold("Next:")} ${match.recommended_next_action}`);
|
|
1071
|
-
}
|
|
1072
|
-
return lines.join("\n");
|
|
1073
|
-
}
|
|
1074
|
-
async function searchCommand(toolName, query, options) {
|
|
1075
|
-
trackEvent("command", { name: toolName });
|
|
1076
|
-
const spinner = isTTY ? ora2("Searching GenRTL knowledge...").start() : null;
|
|
1077
|
-
try {
|
|
1078
|
-
const input = buildKnowledgeSearchInput(query, options);
|
|
1079
|
-
const result = await callGenrtlKnowledgeTool(toolName, input);
|
|
1080
|
-
spinner?.stop();
|
|
1081
|
-
if (options.json) {
|
|
1082
|
-
console.log(JSON.stringify(result, null, 2));
|
|
1083
|
-
return;
|
|
1084
|
-
}
|
|
1085
|
-
printKnowledgeResult(result);
|
|
1086
|
-
} catch (err) {
|
|
1087
|
-
spinner?.fail(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
1088
|
-
if (!spinner) log.error(err instanceof Error ? err.message : String(err));
|
|
1089
|
-
process.exitCode = 1;
|
|
1090
|
-
}
|
|
1091
|
-
}
|
|
1092
|
-
function printKnowledgeResult(result) {
|
|
1093
|
-
log.blank();
|
|
1094
|
-
log.plain(pc4.bold(result.summary));
|
|
1095
|
-
log.blank();
|
|
1096
|
-
if (result.matched_cards.length === 0) {
|
|
1097
|
-
log.warn("No matching GenRTL knowledge cards were found.");
|
|
1098
|
-
} else {
|
|
1099
|
-
result.matched_cards.forEach((match, index) => {
|
|
1100
|
-
log.plain(formatMatch(match, index));
|
|
1101
|
-
log.blank();
|
|
1102
|
-
});
|
|
1103
|
-
}
|
|
1104
|
-
if (result.recommended_next_action) {
|
|
1105
|
-
log.plain(`${pc4.bold("Recommended next action:")} ${result.recommended_next_action}`);
|
|
1106
|
-
log.blank();
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
1109
|
-
function addSearchOptions(command) {
|
|
1110
|
-
return command.argument("<query>", "Natural-language RTL engineering question or diagnostic").option(
|
|
1111
|
-
"--type <type...>",
|
|
1112
|
-
"Knowledge types: spec2rtl, spec2plan, verification, compile, debug, coding_style"
|
|
1113
|
-
).option("--domain <domain>", "Filter by engineering domain").option("--tool <tool>", "Filter by EDA tool").option("--tool-version <version>", "Filter by EDA tool version").option("--error-type <type>", "Filter by error type").option("--severity <severity>", "Filter by severity").option("--interface <interface>", "Filter by hardware interface").option("--target <target>", "Filter by target: fpga, asic, or both").option("--tag <tag...>", "Filter by one or more tags").option("--top-k <count>", "Maximum results (1-20)", parseInteger).option("--min-score <score>", "Minimum similarity score (0-1)", parseNumber).option("--workspace-id <id>", "GenRTL workspace ID").option("--json", "Output the structured MCP result as JSON");
|
|
1114
|
-
}
|
|
1115
|
-
function registerKnowledgeCommands(program2) {
|
|
1116
|
-
for (const tool of TOOL_COMMANDS) {
|
|
1117
|
-
const command = program2.command(tool.name).alias(tool.alias).description(tool.description);
|
|
1118
|
-
addSearchOptions(command).action(async (query, options) => {
|
|
1119
|
-
await searchCommand(tool.name, query, options);
|
|
1120
|
-
});
|
|
1121
|
-
}
|
|
1122
|
-
}
|
|
1123
|
-
|
|
1124
874
|
// src/commands/cbb.ts
|
|
1125
|
-
import
|
|
1126
|
-
import
|
|
875
|
+
import ora2 from "ora";
|
|
876
|
+
import pc4 from "picocolors";
|
|
1127
877
|
|
|
1128
878
|
// src/utils/cbb-install.ts
|
|
1129
|
-
import { createHash, randomUUID
|
|
879
|
+
import { createHash, randomUUID } from "crypto";
|
|
1130
880
|
import { createWriteStream } from "fs";
|
|
1131
881
|
import {
|
|
1132
882
|
access as access3,
|
|
@@ -1139,7 +889,7 @@ import {
|
|
|
1139
889
|
rm as rm2,
|
|
1140
890
|
writeFile as writeFile4
|
|
1141
891
|
} from "fs/promises";
|
|
1142
|
-
import { dirname as
|
|
892
|
+
import { dirname as dirname5, isAbsolute, join as join3, relative, resolve as resolve3, sep } from "path";
|
|
1143
893
|
import { Transform } from "stream";
|
|
1144
894
|
import { pipeline } from "stream/promises";
|
|
1145
895
|
import yauzl from "yauzl";
|
|
@@ -1194,7 +944,7 @@ function resolveProjectTarget(projectRoot, targetDir) {
|
|
|
1194
944
|
return targetPath;
|
|
1195
945
|
}
|
|
1196
946
|
async function readLockfile(projectRoot) {
|
|
1197
|
-
const lockPath =
|
|
947
|
+
const lockPath = join3(projectRoot, ".genrtl", "cbb-lock.json");
|
|
1198
948
|
if (!await pathExists2(lockPath)) {
|
|
1199
949
|
return { schema_version: 1, packages: {} };
|
|
1200
950
|
}
|
|
@@ -1403,7 +1153,7 @@ async function extractZipSafely(archivePath, destination) {
|
|
|
1403
1153
|
if (isDirectory) {
|
|
1404
1154
|
await mkdir4(outputPath, { recursive: true });
|
|
1405
1155
|
} else {
|
|
1406
|
-
await mkdir4(
|
|
1156
|
+
await mkdir4(dirname5(outputPath), { recursive: true });
|
|
1407
1157
|
await extractEntry(zipFile, entry, outputPath, extractedBytes);
|
|
1408
1158
|
}
|
|
1409
1159
|
zipFile.readEntry();
|
|
@@ -1414,7 +1164,7 @@ async function extractZipSafely(archivePath, destination) {
|
|
|
1414
1164
|
}
|
|
1415
1165
|
async function validatePackageManifest(stagingPath, cbbId, version) {
|
|
1416
1166
|
for (const filename of ["manifest.json", "cbb.json", "CBB.json"]) {
|
|
1417
|
-
const manifestPath =
|
|
1167
|
+
const manifestPath = join3(stagingPath, filename);
|
|
1418
1168
|
if (!await pathExists2(manifestPath)) continue;
|
|
1419
1169
|
let manifest;
|
|
1420
1170
|
try {
|
|
@@ -1441,10 +1191,10 @@ async function validatePackageManifest(stagingPath, cbbId, version) {
|
|
|
1441
1191
|
async function writeLockfile(projectRoot, cbbId, entry) {
|
|
1442
1192
|
const lockfile = await readLockfile(projectRoot);
|
|
1443
1193
|
lockfile.packages[cbbId] = entry;
|
|
1444
|
-
const lockDir =
|
|
1445
|
-
const lockPath =
|
|
1446
|
-
const tempPath =
|
|
1447
|
-
const backupPath =
|
|
1194
|
+
const lockDir = join3(projectRoot, ".genrtl");
|
|
1195
|
+
const lockPath = join3(lockDir, "cbb-lock.json");
|
|
1196
|
+
const tempPath = join3(lockDir, `.cbb-lock-${randomUUID()}.tmp`);
|
|
1197
|
+
const backupPath = join3(lockDir, `.cbb-lock-${randomUUID()}.bak`);
|
|
1448
1198
|
await mkdir4(lockDir, { recursive: true });
|
|
1449
1199
|
await writeFile4(tempPath, `${JSON.stringify(lockfile, null, 2)}
|
|
1450
1200
|
`, "utf8");
|
|
@@ -1467,12 +1217,12 @@ async function installCbbArtifact(descriptor, plan, force) {
|
|
|
1467
1217
|
if (descriptor.format !== "zip") {
|
|
1468
1218
|
throw new Error(`Unsupported CBB artifact format: ${descriptor.format}`);
|
|
1469
1219
|
}
|
|
1470
|
-
const targetParent =
|
|
1220
|
+
const targetParent = dirname5(plan.targetPath);
|
|
1471
1221
|
await mkdir4(targetParent, { recursive: true });
|
|
1472
|
-
const tempRoot = await mkdtemp(
|
|
1473
|
-
const archivePath =
|
|
1474
|
-
const stagingPath =
|
|
1475
|
-
const backupPath = `${plan.targetPath}.grtl-backup-${
|
|
1222
|
+
const tempRoot = await mkdtemp(join3(targetParent, ".grtl-cbb-"));
|
|
1223
|
+
const archivePath = join3(tempRoot, "artifact.zip");
|
|
1224
|
+
const stagingPath = join3(tempRoot, "content");
|
|
1225
|
+
const backupPath = `${plan.targetPath}.grtl-backup-${randomUUID()}`;
|
|
1476
1226
|
let backupCreated = false;
|
|
1477
1227
|
let installed = false;
|
|
1478
1228
|
try {
|
|
@@ -1526,10 +1276,93 @@ async function installCbbArtifact(descriptor, plan, force) {
|
|
|
1526
1276
|
}
|
|
1527
1277
|
}
|
|
1528
1278
|
|
|
1279
|
+
// src/constants.ts
|
|
1280
|
+
import { readFileSync } from "fs";
|
|
1281
|
+
import { fileURLToPath } from "url";
|
|
1282
|
+
import { dirname as dirname6, join as join4 } from "path";
|
|
1283
|
+
var __dirname = dirname6(fileURLToPath(import.meta.url));
|
|
1284
|
+
var pkg = JSON.parse(readFileSync(join4(__dirname, "../package.json"), "utf-8"));
|
|
1285
|
+
var VERSION = pkg.version;
|
|
1286
|
+
var NAME = pkg.name;
|
|
1287
|
+
|
|
1288
|
+
// src/utils/knowledge-api.ts
|
|
1289
|
+
var baseUrl = "https://genrtl.com";
|
|
1290
|
+
function setBaseUrl(url) {
|
|
1291
|
+
baseUrl = url.replace(/\/+$/, "");
|
|
1292
|
+
}
|
|
1293
|
+
function getMcpEndpoint() {
|
|
1294
|
+
return baseUrl.endsWith("/api/mcp") ? baseUrl : `${baseUrl}/api/mcp`;
|
|
1295
|
+
}
|
|
1296
|
+
function getApiKey() {
|
|
1297
|
+
return [process.env.GRTL_API_KEY, process.env.GENRTL_API_KEY].map((value) => value?.trim()).find((value) => Boolean(value));
|
|
1298
|
+
}
|
|
1299
|
+
function validateApiKey(apiKey) {
|
|
1300
|
+
if (!/^gtr_(?:live|test)_[A-Za-z0-9_-]{32,128}$/.test(apiKey)) {
|
|
1301
|
+
throw new Error(
|
|
1302
|
+
"Invalid GenRTL API key format. Use the full key shown once when it was created; it must start with gtr_live_ or gtr_test_."
|
|
1303
|
+
);
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
function getMcpErrorMessage(content) {
|
|
1307
|
+
if (!Array.isArray(content)) return void 0;
|
|
1308
|
+
const item = content.find(
|
|
1309
|
+
(entry) => entry && typeof entry === "object" && "type" in entry && entry.type === "text" && "text" in entry && typeof entry.text === "string"
|
|
1310
|
+
);
|
|
1311
|
+
return item?.text;
|
|
1312
|
+
}
|
|
1313
|
+
function getStructuredMcpError(content) {
|
|
1314
|
+
if (!content || typeof content !== "object") return void 0;
|
|
1315
|
+
const errorContent = content;
|
|
1316
|
+
return {
|
|
1317
|
+
error: typeof errorContent.error === "string" ? errorContent.error : void 0,
|
|
1318
|
+
code: typeof errorContent.code === "string" ? errorContent.code : void 0
|
|
1319
|
+
};
|
|
1320
|
+
}
|
|
1321
|
+
async function callGenrtlMcpTool(toolName, input) {
|
|
1322
|
+
const apiKey = getApiKey();
|
|
1323
|
+
if (!apiKey) {
|
|
1324
|
+
throw new Error("Authentication required. Set GRTL_API_KEY or GENRTL_API_KEY.");
|
|
1325
|
+
}
|
|
1326
|
+
validateApiKey(apiKey);
|
|
1327
|
+
const response = await fetch(getMcpEndpoint(), {
|
|
1328
|
+
method: "POST",
|
|
1329
|
+
headers: {
|
|
1330
|
+
"Content-Type": "application/json",
|
|
1331
|
+
Authorization: `Bearer ${apiKey}`,
|
|
1332
|
+
"MCP-Protocol-Version": "2025-06-18",
|
|
1333
|
+
"X-GenRTL-Source": "cli",
|
|
1334
|
+
"X-GenRTL-Client-Version": VERSION
|
|
1335
|
+
},
|
|
1336
|
+
body: JSON.stringify({
|
|
1337
|
+
jsonrpc: "2.0",
|
|
1338
|
+
id: 1,
|
|
1339
|
+
method: "tools/call",
|
|
1340
|
+
params: { name: toolName, arguments: input }
|
|
1341
|
+
})
|
|
1342
|
+
});
|
|
1343
|
+
const payload = await response.json().catch(() => null);
|
|
1344
|
+
if (!response.ok || payload?.error) {
|
|
1345
|
+
const message = payload?.error?.message || `GenRTL MCP request failed with HTTP ${response.status}`;
|
|
1346
|
+
const code = payload?.error?.data?.code;
|
|
1347
|
+
throw new Error(code ? `${message} (${code})` : message);
|
|
1348
|
+
}
|
|
1349
|
+
const result = payload?.result;
|
|
1350
|
+
if (!result) throw new Error("GenRTL MCP returned an empty result.");
|
|
1351
|
+
if (result.isError) {
|
|
1352
|
+
const structuredError = getStructuredMcpError(result.structuredContent);
|
|
1353
|
+
const message = structuredError?.error || getMcpErrorMessage(result.content) || "GenRTL MCP tool call failed.";
|
|
1354
|
+
throw new Error(structuredError?.code ? `${message} (${structuredError.code})` : message);
|
|
1355
|
+
}
|
|
1356
|
+
if (!result.structuredContent) {
|
|
1357
|
+
throw new Error("GenRTL MCP response did not include structured results.");
|
|
1358
|
+
}
|
|
1359
|
+
return result.structuredContent;
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1529
1362
|
// src/commands/cbb.ts
|
|
1530
1363
|
async function installCbb(spec, options) {
|
|
1531
1364
|
trackEvent("command", { name: "cbb-install" });
|
|
1532
|
-
const spinner = process.stdout.isTTY && !options.json ?
|
|
1365
|
+
const spinner = process.stdout.isTTY && !options.json ? ora2("Preparing CBB installation...").start() : null;
|
|
1533
1366
|
try {
|
|
1534
1367
|
const { cbbId, version } = parseCbbSpec(spec);
|
|
1535
1368
|
const target = options.target || defaultCbbTarget(cbbId, version);
|
|
@@ -1564,7 +1397,7 @@ async function installCbb(spec, options) {
|
|
|
1564
1397
|
return;
|
|
1565
1398
|
}
|
|
1566
1399
|
log.blank();
|
|
1567
|
-
log.success(`Installed ${
|
|
1400
|
+
log.success(`Installed ${pc4.bold(`${cbbId}@${version}`)}`);
|
|
1568
1401
|
log.item(`Target: ${result.target_path}`);
|
|
1569
1402
|
log.item(`SHA256: ${result.sha256}`);
|
|
1570
1403
|
log.item(`Lockfile: ${plan.projectRoot}/.genrtl/cbb-lock.json`);
|
|
@@ -1577,7 +1410,7 @@ async function installCbb(spec, options) {
|
|
|
1577
1410
|
}
|
|
1578
1411
|
}
|
|
1579
1412
|
function registerCbbCommands(program2) {
|
|
1580
|
-
const cbb = program2.command("cbb").description("
|
|
1413
|
+
const cbb = program2.command("cbb").description("Install reusable RTL CBBs");
|
|
1581
1414
|
cbb.command("install").description("Acquire, verify, and install a CBB ZIP into the current project").argument("<cbb>", "CBB coordinate in the form <cbb_id>@<version>").option("-t, --target <dir>", "Project-relative target directory").option("--project-root <dir>", "Project root (default: current directory)").option("-f, --force", "Replace an existing target after successful verification").option("--json", "Output the installation result as JSON").action(async (spec, options) => {
|
|
1582
1415
|
await installCbb(spec, options);
|
|
1583
1416
|
});
|
|
@@ -1586,7 +1419,7 @@ function registerCbbCommands(program2) {
|
|
|
1586
1419
|
// src/commands/upgrade.ts
|
|
1587
1420
|
import { confirm } from "@inquirer/prompts";
|
|
1588
1421
|
import { spawn } from "child_process";
|
|
1589
|
-
import
|
|
1422
|
+
import pc5 from "picocolors";
|
|
1590
1423
|
|
|
1591
1424
|
// src/utils/update-check.ts
|
|
1592
1425
|
import { homedir as homedir2 } from "os";
|
|
@@ -1797,7 +1630,7 @@ async function runUpgradePlan(plan) {
|
|
|
1797
1630
|
return runCommand(plan.command, plan.args);
|
|
1798
1631
|
}
|
|
1799
1632
|
function showUpgradeFailureHelp(plan) {
|
|
1800
|
-
log.info(`Try rerunning: ${
|
|
1633
|
+
log.info(`Try rerunning: ${pc5.cyan(plan.displayCommand)}`);
|
|
1801
1634
|
const isGlobalNpmInstall = (plan.installMethod === "npm-global" || plan.installMethod === "unknown") && plan.command === "npm" && plan.args.includes("-g");
|
|
1802
1635
|
const isGlobalAltInstall = (plan.installMethod === "pnpm-global" || plan.installMethod === "bun-global") && plan.args.includes("-g");
|
|
1803
1636
|
if (isGlobalNpmInstall) {
|
|
@@ -1824,8 +1657,8 @@ async function maybeShowUpgradeNotice(options = {}) {
|
|
|
1824
1657
|
log.blank();
|
|
1825
1658
|
if (info.upgradePlan.needsExplicitVersion) {
|
|
1826
1659
|
log.box([
|
|
1827
|
-
`${
|
|
1828
|
-
`${
|
|
1660
|
+
`${pc5.white(pc5.bold("Update available:"))} ${pc5.green(pc5.bold(`v${info.currentVersion}`))} ${pc5.dim("->")} ${pc5.green(pc5.bold(`v${info.latestVersion}`))}`,
|
|
1661
|
+
`${pc5.white("Use")} ${pc5.yellow(pc5.bold(info.upgradePlan.displayCommand))} ${pc5.white("to run the latest version")}`
|
|
1829
1662
|
]);
|
|
1830
1663
|
await markUpdateNotificationShown(info.latestVersion);
|
|
1831
1664
|
log.blank();
|
|
@@ -1833,18 +1666,18 @@ async function maybeShowUpgradeNotice(options = {}) {
|
|
|
1833
1666
|
}
|
|
1834
1667
|
if (!info.upgradePlan.canRun) {
|
|
1835
1668
|
log.box([
|
|
1836
|
-
`${
|
|
1837
|
-
`${
|
|
1838
|
-
`${
|
|
1669
|
+
`${pc5.white(pc5.bold("Update available:"))} ${pc5.green(pc5.bold(`v${info.currentVersion}`))} ${pc5.dim("->")} ${pc5.green(pc5.bold(`v${info.latestVersion}`))}`,
|
|
1670
|
+
`${pc5.white("Run")} ${pc5.yellow(pc5.bold("grtl upgrade"))} ${pc5.white("for update steps")}`,
|
|
1671
|
+
`${pc5.white("Or run")} ${pc5.yellow(info.upgradePlan.displayCommand)}`
|
|
1839
1672
|
]);
|
|
1840
1673
|
await markUpdateNotificationShown(info.latestVersion);
|
|
1841
1674
|
log.blank();
|
|
1842
1675
|
return;
|
|
1843
1676
|
}
|
|
1844
1677
|
log.box([
|
|
1845
|
-
`${
|
|
1846
|
-
`${
|
|
1847
|
-
`${
|
|
1678
|
+
`${pc5.white(pc5.bold("Update available:"))} ${pc5.green(pc5.bold(`v${info.currentVersion}`))} ${pc5.dim("->")} ${pc5.green(pc5.bold(`v${info.latestVersion}`))}`,
|
|
1679
|
+
`${pc5.white("Run")} ${pc5.yellow(pc5.bold("grtl upgrade"))} ${pc5.white("to update now")}`,
|
|
1680
|
+
`${pc5.white("Or run")} ${pc5.yellow(info.upgradePlan.displayCommand)}`
|
|
1848
1681
|
]);
|
|
1849
1682
|
await markUpdateNotificationShown(info.latestVersion);
|
|
1850
1683
|
log.blank();
|
|
@@ -1855,28 +1688,28 @@ async function upgradeCommand(options) {
|
|
|
1855
1688
|
const plan = info?.upgradePlan ?? getUpgradePlan();
|
|
1856
1689
|
if (!info) {
|
|
1857
1690
|
log.warn("Couldn't check for updates right now.");
|
|
1858
|
-
log.info(`Try again later or run ${
|
|
1691
|
+
log.info(`Try again later or run ${pc5.cyan(plan.displayCommand)} manually.`);
|
|
1859
1692
|
return;
|
|
1860
1693
|
}
|
|
1861
1694
|
if (!info.updateAvailable) {
|
|
1862
|
-
log.success(`grtl is up to date (${
|
|
1695
|
+
log.success(`grtl is up to date (${pc5.bold(`v${VERSION}`)})`);
|
|
1863
1696
|
return;
|
|
1864
1697
|
}
|
|
1865
1698
|
log.blank();
|
|
1866
1699
|
log.info(
|
|
1867
|
-
`Update available: ${
|
|
1700
|
+
`Update available: ${pc5.bold(`v${info.currentVersion}`)} ${pc5.dim("->")} ${pc5.bold(`v${info.latestVersion}`)}`
|
|
1868
1701
|
);
|
|
1869
1702
|
if (plan.needsExplicitVersion) {
|
|
1870
1703
|
log.info(`You're using an ephemeral runner (${plan.installMethod}).`);
|
|
1871
|
-
log.info(`Use ${
|
|
1872
|
-
log.info(`Or install globally with ${
|
|
1704
|
+
log.info(`Use ${pc5.cyan(plan.displayCommand)} to run the latest version immediately.`);
|
|
1705
|
+
log.info(`Or install globally with ${pc5.cyan("npm install -g @genrtl/grtl@latest")}.`);
|
|
1873
1706
|
return;
|
|
1874
1707
|
}
|
|
1875
1708
|
if (!plan.canRun) {
|
|
1876
|
-
log.info(`Run ${
|
|
1709
|
+
log.info(`Run ${pc5.cyan(plan.displayCommand)} to update your installed version.`);
|
|
1877
1710
|
return;
|
|
1878
1711
|
}
|
|
1879
|
-
log.info(`Upgrade command: ${
|
|
1712
|
+
log.info(`Upgrade command: ${pc5.cyan(plan.displayCommand)}`);
|
|
1880
1713
|
if (options.check) {
|
|
1881
1714
|
return;
|
|
1882
1715
|
}
|
|
@@ -1896,7 +1729,7 @@ async function upgradeCommand(options) {
|
|
|
1896
1729
|
if (exitCode === 0) {
|
|
1897
1730
|
log.blank();
|
|
1898
1731
|
log.success("Upgrade complete.");
|
|
1899
|
-
log.info(`Run ${
|
|
1732
|
+
log.info(`Run ${pc5.cyan("grtl --version")} to verify the installed version.`);
|
|
1900
1733
|
return;
|
|
1901
1734
|
}
|
|
1902
1735
|
log.blank();
|
|
@@ -1907,11 +1740,11 @@ async function upgradeCommand(options) {
|
|
|
1907
1740
|
|
|
1908
1741
|
// src/index.ts
|
|
1909
1742
|
var brand = {
|
|
1910
|
-
primary:
|
|
1911
|
-
dim:
|
|
1743
|
+
primary: pc6.green,
|
|
1744
|
+
dim: pc6.dim
|
|
1912
1745
|
};
|
|
1913
|
-
var program = new
|
|
1914
|
-
program.name("grtl").description("GenRTL CLI -
|
|
1746
|
+
var program = new Command();
|
|
1747
|
+
program.name("grtl").description("GenRTL CLI - Configure GenRTL and install reusable RTL CBBs").version(VERSION).option("--base-url <url>").hook("preAction", (thisCommand) => {
|
|
1915
1748
|
const opts = thisCommand.opts();
|
|
1916
1749
|
if (opts.baseUrl) {
|
|
1917
1750
|
setBaseUrl(opts.baseUrl);
|
|
@@ -1926,35 +1759,25 @@ program.name("grtl").description("GenRTL CLI - Search RTL engineering knowledge
|
|
|
1926
1759
|
"after",
|
|
1927
1760
|
`
|
|
1928
1761
|
Examples:
|
|
1929
|
-
${brand.dim("# Configure GenRTL for your coding agent")}
|
|
1930
|
-
${brand.primary("npx @genrtl/grtl setup --cli --codex --project")}
|
|
1762
|
+
${brand.dim("# Configure GenRTL MCP for your coding agent")}
|
|
1931
1763
|
${brand.primary("GRTL_API_KEY=your_key npx @genrtl/grtl setup --mcp --codex --project")}
|
|
1932
1764
|
|
|
1933
|
-
${brand.dim("# Search the same six knowledge tools exposed by the GenRTL MCP server")}
|
|
1934
|
-
${brand.primary('npx @genrtl/grtl knowledge-search "AXI stream backpressure design"')}
|
|
1935
|
-
${brand.primary('npx @genrtl/grtl spec2rtl-search "Generate an APB register block"')}
|
|
1936
|
-
${brand.primary('npx @genrtl/grtl spec2plan-search "Plan an APB register block implementation"')}
|
|
1937
|
-
${brand.primary('npx @genrtl/grtl verification-search "Verify an async FIFO"')}
|
|
1938
|
-
${brand.primary('npx @genrtl/grtl compile-search "Explain this Vivado CDC warning"')}
|
|
1939
|
-
${brand.primary('npx @genrtl/grtl debug-search "Fix this RTL bug from bad code and error message"')}
|
|
1940
|
-
|
|
1941
1765
|
${brand.dim("# Acquire and install a reusable RTL CBB")}
|
|
1942
1766
|
${brand.primary("npx @genrtl/grtl cbb install cbb_uart@1.2.0")}
|
|
1943
1767
|
`
|
|
1944
1768
|
);
|
|
1945
1769
|
registerSetupCommand(program);
|
|
1946
|
-
registerKnowledgeCommands(program);
|
|
1947
1770
|
registerCbbCommands(program);
|
|
1948
1771
|
registerUpgradeCommand(program);
|
|
1949
1772
|
program.action(() => {
|
|
1950
1773
|
console.log("");
|
|
1951
1774
|
const banner = figlet.textSync("GenRTL", { font: "ANSI Shadow" });
|
|
1952
1775
|
console.log(brand.primary(banner));
|
|
1953
|
-
console.log(brand.dim("
|
|
1776
|
+
console.log(brand.dim(" Configure GenRTL MCP and install reusable RTL CBBs"));
|
|
1954
1777
|
console.log("");
|
|
1955
1778
|
console.log(" Quick start:");
|
|
1956
|
-
console.log(` ${brand.primary("npx @genrtl/grtl setup")}`);
|
|
1957
|
-
console.log(` ${brand.primary(
|
|
1779
|
+
console.log(` ${brand.primary("npx @genrtl/grtl setup --mcp")}`);
|
|
1780
|
+
console.log(` ${brand.primary("npx @genrtl/grtl cbb install cbb_uart@1.2.0")}`);
|
|
1958
1781
|
console.log("");
|
|
1959
1782
|
console.log(` Run ${brand.primary("npx @genrtl/grtl --help")} for all commands and options`);
|
|
1960
1783
|
console.log("");
|