@genrtl/grtl 0.4.1 → 2.0.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 +26 -51
- package/dist/index.js +180 -338
- 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,41 +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
|
-
grtl spec2plan-search "Plan an APB register block implementation"
|
|
62
|
-
grtl verification-search "Verify an async FIFO"
|
|
63
|
-
grtl debug-search "Explain this Vivado CDC warning"
|
|
51
|
+
grtl cbb install cbb_uart@1.2.0
|
|
52
|
+
grtl cbb install cbb_uart@1.2.0 --target rtl/vendor/uart
|
|
64
53
|
```
|
|
65
54
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
grtl cbb install cbb_uart@1.2.0 --target rtl/vendor/uart
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
The command calls the hosted `genrtl_cbb_acquire` MCP tool with
|
|
81
|
-
`GRTL_API_KEY`, downloads the short-lived ZIP artifact, verifies its size and
|
|
82
|
-
SHA-256, safely extracts it, and atomically installs it. The default target is
|
|
83
|
-
`rtl/cbb/<cbb_id>_<version>`.
|
|
84
|
-
|
|
85
|
-
Installed packages are recorded in `.genrtl/cbb-lock.json`. Existing targets
|
|
86
|
-
are left untouched unless `--force` is provided; replacement occurs only after
|
|
87
|
-
the new archive has been fully verified and extracted. Use `--json` for
|
|
88
|
-
machine-readable output.
|
|
89
|
-
|
|
90
|
-
## Development
|
|
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
|
|
91
66
|
|
|
92
67
|
```bash
|
|
93
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,33 +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. Search coding style with \`genrtl_coding_style_search\`.
|
|
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_debug_search\` for lint, CDC, compile, synthesis, and RTL bugs
|
|
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.
|
|
382
394
|
|
|
383
|
-
|
|
384
|
-
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.
|
|
385
397
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
- \`npx @genrtl/grtl@latest spec2rtl-search "<query>"\`
|
|
389
|
-
- \`npx @genrtl/grtl@latest spec2plan-search "<query>"\`
|
|
390
|
-
- \`npx @genrtl/grtl@latest verification-search "<query>"\`
|
|
391
|
-
- \`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.
|
|
392
400
|
|
|
393
401
|
To install a reusable RTL block into the current project:
|
|
394
402
|
- \`npx @genrtl/grtl@latest cbb install <cbb_id>@<version>\`
|
|
395
403
|
- Add \`--target <relative-dir>\` only when a non-default install path is needed.
|
|
396
404
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
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.`;
|
|
401
408
|
var CURSOR_FRONTMATTER = `---
|
|
402
409
|
alwaysApply: true
|
|
403
410
|
---
|
|
@@ -406,50 +413,49 @@ alwaysApply: true
|
|
|
406
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.`;
|
|
407
414
|
var MCP_SKILL = `---
|
|
408
415
|
name: genrtl-mcp
|
|
409
|
-
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.
|
|
410
417
|
---
|
|
411
418
|
|
|
412
|
-
# GenRTL MCP
|
|
419
|
+
# GenRTL MCP RTL Knowledge Workflow
|
|
413
420
|
|
|
414
|
-
Use
|
|
421
|
+
Use GenRTL MCP tools before relying on model memory for RTL engineering.
|
|
415
422
|
|
|
416
|
-
|
|
423
|
+
## Tool Routing
|
|
417
424
|
|
|
418
|
-
- \`
|
|
419
|
-
- \`genrtl_spec2rtl_search\` for
|
|
420
|
-
- \`
|
|
421
|
-
- \`genrtl_verification_search\` for
|
|
422
|
-
- \`
|
|
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.
|
|
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.
|
|
423
432
|
|
|
424
|
-
|
|
425
|
-
|
|
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
|
+
- For SpyGlass lint/CDC logs after RTL coding and before Vivado/Quartus/VCS/QuestaSim compile/synthesis, call \`genrtl_compile_search\` with \`filters.tool = "spyglass"\`.
|
|
438
|
+
- For Vivado/Quartus synthesis or implementation errors, warnings, and critical warnings, call \`genrtl_compile_search\` with the matching \`filters.tool\`.
|
|
439
|
+
- For VCS/QuestaSim compile errors or warnings, call \`genrtl_compile_search\` with the matching \`filters.tool\` when known.
|
|
440
|
+
- Apply returned \`code_example\`, \`fix_strategy\`, and \`recommended_next_action\` to the implementation.
|
|
426
441
|
`;
|
|
427
442
|
var CLI_SKILL = `---
|
|
428
443
|
name: genrtl-cli
|
|
429
|
-
description: Use the grtl CLI
|
|
444
|
+
description: Use the grtl CLI to configure GenRTL MCP and securely install reusable RTL CBBs.
|
|
430
445
|
---
|
|
431
446
|
|
|
432
447
|
# GenRTL CLI
|
|
433
448
|
|
|
434
|
-
Use this skill
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
For knowledge retrieval, choose exactly one command:
|
|
438
|
-
|
|
439
|
-
- \`grtl knowledge-search "<query>" --json\` for cross-domain RTL questions.
|
|
440
|
-
- \`grtl spec2rtl-search "<query>" --json\` for requirements, protocols, control logic, or algorithm-to-RTL work.
|
|
441
|
-
- \`grtl spec2plan-search "<query>" --json\` for turning a specification into an actionable implementation plan.
|
|
442
|
-
- \`grtl verification-search "<query>" --json\` for testbenches and verification.
|
|
443
|
-
- \`grtl debug-search "<query>" --json\` for lint, CDC, compile, synthesis, or RTL bugs.
|
|
449
|
+
Use this skill only for GenRTL MCP setup and reusable RTL CBB installation.
|
|
450
|
+
Knowledge retrieval, CBB search, and CBB detail lookup are available through
|
|
451
|
+
GenRTL MCP tools only, not through CLI commands.
|
|
444
452
|
|
|
445
|
-
For a CBB selected from GenRTL search results:
|
|
453
|
+
For a CBB selected from GenRTL MCP search results:
|
|
446
454
|
|
|
447
455
|
- \`grtl cbb install <cbb_id>@<version>\` downloads, verifies, and safely extracts it.
|
|
448
456
|
- Add \`--target <relative-dir>\` only when the user requests a specific project path.
|
|
449
457
|
- Do not download or extract the artifact manually; the CLI verifies SHA-256 and prevents unsafe ZIP paths.
|
|
450
458
|
|
|
451
|
-
Pass the complete engineering question. Add filters such as \`--tool\`,
|
|
452
|
-
\`--tool-version\`, \`--target\`, \`--interface\`, or \`--tag\` only when useful.
|
|
453
459
|
The CLI requires \`GRTL_API_KEY\` or \`GENRTL_API_KEY\` in its environment.
|
|
454
460
|
`;
|
|
455
461
|
function getSkillContent(mode) {
|
|
@@ -864,250 +870,12 @@ async function setupCommand(options) {
|
|
|
864
870
|
trackEvent("setup", { agents: agents2, scope, mode, authMode: auth?.mode ?? "environment" });
|
|
865
871
|
}
|
|
866
872
|
|
|
867
|
-
// src/commands/knowledge.ts
|
|
868
|
-
import { InvalidArgumentError } from "commander";
|
|
869
|
-
import pc4 from "picocolors";
|
|
870
|
-
import ora2 from "ora";
|
|
871
|
-
|
|
872
|
-
// src/utils/knowledge-api.ts
|
|
873
|
-
import { randomUUID } from "crypto";
|
|
874
|
-
|
|
875
|
-
// src/constants.ts
|
|
876
|
-
import { readFileSync } from "fs";
|
|
877
|
-
import { fileURLToPath } from "url";
|
|
878
|
-
import { dirname as dirname5, join as join3 } from "path";
|
|
879
|
-
var __dirname = dirname5(fileURLToPath(import.meta.url));
|
|
880
|
-
var pkg = JSON.parse(readFileSync(join3(__dirname, "../package.json"), "utf-8"));
|
|
881
|
-
var VERSION = pkg.version;
|
|
882
|
-
var NAME = pkg.name;
|
|
883
|
-
|
|
884
|
-
// src/utils/knowledge-api.ts
|
|
885
|
-
var baseUrl = "https://genrtl.com";
|
|
886
|
-
function setBaseUrl(url) {
|
|
887
|
-
baseUrl = url.replace(/\/+$/, "");
|
|
888
|
-
}
|
|
889
|
-
function getMcpEndpoint() {
|
|
890
|
-
return baseUrl.endsWith("/api/mcp") ? baseUrl : `${baseUrl}/api/mcp`;
|
|
891
|
-
}
|
|
892
|
-
function getApiKey() {
|
|
893
|
-
return [process.env.GRTL_API_KEY, process.env.GENRTL_API_KEY].map((value) => value?.trim()).find((value) => Boolean(value));
|
|
894
|
-
}
|
|
895
|
-
function validateApiKey(apiKey) {
|
|
896
|
-
if (!/^gtr_(?:live|test)_[A-Za-z0-9_-]{32,128}$/.test(apiKey)) {
|
|
897
|
-
throw new Error(
|
|
898
|
-
"Invalid GenRTL API key format. Use the full key shown once when it was created; it must start with gtr_live_ or gtr_test_."
|
|
899
|
-
);
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
function getMcpErrorMessage(content) {
|
|
903
|
-
if (!Array.isArray(content)) return void 0;
|
|
904
|
-
const item = content.find(
|
|
905
|
-
(entry) => entry && typeof entry === "object" && "type" in entry && entry.type === "text" && "text" in entry && typeof entry.text === "string"
|
|
906
|
-
);
|
|
907
|
-
return item?.text;
|
|
908
|
-
}
|
|
909
|
-
function getStructuredMcpError(content) {
|
|
910
|
-
if (!content || typeof content !== "object") return void 0;
|
|
911
|
-
const errorContent = content;
|
|
912
|
-
return {
|
|
913
|
-
error: typeof errorContent.error === "string" ? errorContent.error : void 0,
|
|
914
|
-
code: typeof errorContent.code === "string" ? errorContent.code : void 0
|
|
915
|
-
};
|
|
916
|
-
}
|
|
917
|
-
async function callGenrtlMcpTool(toolName, input) {
|
|
918
|
-
const apiKey = getApiKey();
|
|
919
|
-
if (!apiKey) {
|
|
920
|
-
throw new Error("Authentication required. Set GRTL_API_KEY or GENRTL_API_KEY.");
|
|
921
|
-
}
|
|
922
|
-
validateApiKey(apiKey);
|
|
923
|
-
const response = await fetch(getMcpEndpoint(), {
|
|
924
|
-
method: "POST",
|
|
925
|
-
headers: {
|
|
926
|
-
"Content-Type": "application/json",
|
|
927
|
-
Authorization: `Bearer ${apiKey}`,
|
|
928
|
-
"MCP-Protocol-Version": "2025-06-18",
|
|
929
|
-
"X-GenRTL-Source": "cli",
|
|
930
|
-
"X-GenRTL-Client-Version": VERSION
|
|
931
|
-
},
|
|
932
|
-
body: JSON.stringify({
|
|
933
|
-
jsonrpc: "2.0",
|
|
934
|
-
id: 1,
|
|
935
|
-
method: "tools/call",
|
|
936
|
-
params: { name: toolName, arguments: input }
|
|
937
|
-
})
|
|
938
|
-
});
|
|
939
|
-
const payload = await response.json().catch(() => null);
|
|
940
|
-
if (!response.ok || payload?.error) {
|
|
941
|
-
const message = payload?.error?.message || `GenRTL MCP request failed with HTTP ${response.status}`;
|
|
942
|
-
const code = payload?.error?.data?.code;
|
|
943
|
-
throw new Error(code ? `${message} (${code})` : message);
|
|
944
|
-
}
|
|
945
|
-
const result = payload?.result;
|
|
946
|
-
if (!result) throw new Error("GenRTL MCP returned an empty result.");
|
|
947
|
-
if (result.isError) {
|
|
948
|
-
const structuredError = getStructuredMcpError(result.structuredContent);
|
|
949
|
-
const message = structuredError?.error || getMcpErrorMessage(result.content) || "GenRTL MCP tool call failed.";
|
|
950
|
-
throw new Error(structuredError?.code ? `${message} (${structuredError.code})` : message);
|
|
951
|
-
}
|
|
952
|
-
if (!result.structuredContent) {
|
|
953
|
-
throw new Error("GenRTL MCP response did not include structured results.");
|
|
954
|
-
}
|
|
955
|
-
return result.structuredContent;
|
|
956
|
-
}
|
|
957
|
-
async function callGenrtlKnowledgeTool(toolName, input) {
|
|
958
|
-
const requestInput = input.idempotency_key ? input : { ...input, idempotency_key: randomUUID() };
|
|
959
|
-
return callGenrtlMcpTool(toolName, requestInput);
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
// src/commands/knowledge.ts
|
|
963
|
-
var isTTY = process.stdout.isTTY;
|
|
964
|
-
var TOOL_COMMANDS = [
|
|
965
|
-
{
|
|
966
|
-
name: "genrtl_knowledge_search",
|
|
967
|
-
alias: "knowledge-search",
|
|
968
|
-
description: "Search all approved GenRTL knowledge cards"
|
|
969
|
-
},
|
|
970
|
-
{
|
|
971
|
-
name: "genrtl_spec2rtl_search",
|
|
972
|
-
alias: "spec2rtl-search",
|
|
973
|
-
description: "Search Spec2RTL knowledge cards"
|
|
974
|
-
},
|
|
975
|
-
{
|
|
976
|
-
name: "genrtl_spec2plan_search",
|
|
977
|
-
alias: "spec2plan-search",
|
|
978
|
-
description: "Search Spec2Plan knowledge cards"
|
|
979
|
-
},
|
|
980
|
-
{
|
|
981
|
-
name: "genrtl_verification_search",
|
|
982
|
-
alias: "verification-search",
|
|
983
|
-
description: "Search verification and testbench knowledge cards"
|
|
984
|
-
},
|
|
985
|
-
{
|
|
986
|
-
name: "genrtl_debug_search",
|
|
987
|
-
alias: "debug-search",
|
|
988
|
-
description: "Search lint, CDC, compile, synthesis, and RTL debug knowledge cards"
|
|
989
|
-
}
|
|
990
|
-
];
|
|
991
|
-
function parseInteger(value) {
|
|
992
|
-
const parsed = Number(value);
|
|
993
|
-
if (!Number.isInteger(parsed)) {
|
|
994
|
-
throw new InvalidArgumentError("Expected an integer.");
|
|
995
|
-
}
|
|
996
|
-
return parsed;
|
|
997
|
-
}
|
|
998
|
-
function parseNumber(value) {
|
|
999
|
-
const parsed = Number(value);
|
|
1000
|
-
if (!Number.isFinite(parsed)) {
|
|
1001
|
-
throw new InvalidArgumentError("Expected a number.");
|
|
1002
|
-
}
|
|
1003
|
-
return parsed;
|
|
1004
|
-
}
|
|
1005
|
-
function buildKnowledgeSearchInput(query, options) {
|
|
1006
|
-
if (options.topK !== void 0 && (options.topK < 1 || options.topK > 20)) {
|
|
1007
|
-
throw new InvalidArgumentError("--top-k must be between 1 and 20.");
|
|
1008
|
-
}
|
|
1009
|
-
if (options.minScore !== void 0 && (options.minScore < 0 || options.minScore > 1)) {
|
|
1010
|
-
throw new InvalidArgumentError("--min-score must be between 0 and 1.");
|
|
1011
|
-
}
|
|
1012
|
-
if (options.target && !["fpga", "asic", "both"].includes(options.target)) {
|
|
1013
|
-
throw new InvalidArgumentError("--target must be fpga, asic, or both.");
|
|
1014
|
-
}
|
|
1015
|
-
const filters = {};
|
|
1016
|
-
if (options.type?.length) {
|
|
1017
|
-
const allowed = /* @__PURE__ */ new Set(["spec2rtl", "spec2plan", "verification", "debug"]);
|
|
1018
|
-
const invalid = options.type.find((type) => !allowed.has(type));
|
|
1019
|
-
if (invalid) {
|
|
1020
|
-
throw new InvalidArgumentError(`Invalid knowledge type: ${invalid}`);
|
|
1021
|
-
}
|
|
1022
|
-
filters.types = options.type;
|
|
1023
|
-
}
|
|
1024
|
-
if (options.domain) filters.domain = options.domain;
|
|
1025
|
-
if (options.tool) filters.tool = options.tool;
|
|
1026
|
-
if (options.toolVersion) filters.tool_version = options.toolVersion;
|
|
1027
|
-
if (options.errorType) filters.error_type = options.errorType;
|
|
1028
|
-
if (options.severity) filters.severity = options.severity;
|
|
1029
|
-
if (options.interface) filters.interface = options.interface;
|
|
1030
|
-
if (options.target) filters.target = options.target;
|
|
1031
|
-
if (options.tag?.length) filters.tags = options.tag;
|
|
1032
|
-
return {
|
|
1033
|
-
query,
|
|
1034
|
-
...Object.keys(filters).length > 0 ? { filters } : {},
|
|
1035
|
-
...options.topK !== void 0 ? { top_k: options.topK } : {},
|
|
1036
|
-
...options.minScore !== void 0 ? { min_score: options.minScore } : {},
|
|
1037
|
-
...options.workspaceId ? { workspace_id: options.workspaceId } : {}
|
|
1038
|
-
};
|
|
1039
|
-
}
|
|
1040
|
-
function formatMatch(match, index) {
|
|
1041
|
-
const lines = [
|
|
1042
|
-
`${pc4.dim(`${index + 1}.`)} ${pc4.bold(match.title)} ${pc4.cyan(`[${match.type}]`)}`,
|
|
1043
|
-
` ${pc4.dim(`Confidence: ${Math.round(match.confidence * 100)}%`)}`,
|
|
1044
|
-
` ${match.summary}`
|
|
1045
|
-
];
|
|
1046
|
-
if (match.root_cause) lines.push(` ${pc4.bold("Root cause:")} ${match.root_cause}`);
|
|
1047
|
-
if (match.fix_strategy?.length) {
|
|
1048
|
-
lines.push(` ${pc4.bold("Fix strategy:")} ${match.fix_strategy.join("; ")}`);
|
|
1049
|
-
}
|
|
1050
|
-
if (match.code_example) {
|
|
1051
|
-
lines.push("", "```systemverilog", match.code_example, "```");
|
|
1052
|
-
}
|
|
1053
|
-
if (match.recommended_next_action) {
|
|
1054
|
-
lines.push(` ${pc4.bold("Next:")} ${match.recommended_next_action}`);
|
|
1055
|
-
}
|
|
1056
|
-
return lines.join("\n");
|
|
1057
|
-
}
|
|
1058
|
-
async function searchCommand(toolName, query, options) {
|
|
1059
|
-
trackEvent("command", { name: toolName });
|
|
1060
|
-
const spinner = isTTY ? ora2("Searching GenRTL knowledge...").start() : null;
|
|
1061
|
-
try {
|
|
1062
|
-
const input = buildKnowledgeSearchInput(query, options);
|
|
1063
|
-
const result = await callGenrtlKnowledgeTool(toolName, input);
|
|
1064
|
-
spinner?.stop();
|
|
1065
|
-
if (options.json) {
|
|
1066
|
-
console.log(JSON.stringify(result, null, 2));
|
|
1067
|
-
return;
|
|
1068
|
-
}
|
|
1069
|
-
printKnowledgeResult(result);
|
|
1070
|
-
} catch (err) {
|
|
1071
|
-
spinner?.fail(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
1072
|
-
if (!spinner) log.error(err instanceof Error ? err.message : String(err));
|
|
1073
|
-
process.exitCode = 1;
|
|
1074
|
-
}
|
|
1075
|
-
}
|
|
1076
|
-
function printKnowledgeResult(result) {
|
|
1077
|
-
log.blank();
|
|
1078
|
-
log.plain(pc4.bold(result.summary));
|
|
1079
|
-
log.blank();
|
|
1080
|
-
if (result.matched_cards.length === 0) {
|
|
1081
|
-
log.warn("No matching GenRTL knowledge cards were found.");
|
|
1082
|
-
} else {
|
|
1083
|
-
result.matched_cards.forEach((match, index) => {
|
|
1084
|
-
log.plain(formatMatch(match, index));
|
|
1085
|
-
log.blank();
|
|
1086
|
-
});
|
|
1087
|
-
}
|
|
1088
|
-
if (result.recommended_next_action) {
|
|
1089
|
-
log.plain(`${pc4.bold("Recommended next action:")} ${result.recommended_next_action}`);
|
|
1090
|
-
log.blank();
|
|
1091
|
-
}
|
|
1092
|
-
}
|
|
1093
|
-
function addSearchOptions(command) {
|
|
1094
|
-
return command.argument("<query>", "Natural-language RTL engineering question or diagnostic").option("--type <type...>", "Knowledge types: spec2rtl, spec2plan, verification, debug").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");
|
|
1095
|
-
}
|
|
1096
|
-
function registerKnowledgeCommands(program2) {
|
|
1097
|
-
for (const tool of TOOL_COMMANDS) {
|
|
1098
|
-
const command = program2.command(tool.name).alias(tool.alias).description(tool.description);
|
|
1099
|
-
addSearchOptions(command).action(async (query, options) => {
|
|
1100
|
-
await searchCommand(tool.name, query, options);
|
|
1101
|
-
});
|
|
1102
|
-
}
|
|
1103
|
-
}
|
|
1104
|
-
|
|
1105
873
|
// src/commands/cbb.ts
|
|
1106
|
-
import
|
|
1107
|
-
import
|
|
874
|
+
import ora2 from "ora";
|
|
875
|
+
import pc4 from "picocolors";
|
|
1108
876
|
|
|
1109
877
|
// src/utils/cbb-install.ts
|
|
1110
|
-
import { createHash, randomUUID
|
|
878
|
+
import { createHash, randomUUID } from "crypto";
|
|
1111
879
|
import { createWriteStream } from "fs";
|
|
1112
880
|
import {
|
|
1113
881
|
access as access3,
|
|
@@ -1120,7 +888,7 @@ import {
|
|
|
1120
888
|
rm as rm2,
|
|
1121
889
|
writeFile as writeFile4
|
|
1122
890
|
} from "fs/promises";
|
|
1123
|
-
import { dirname as
|
|
891
|
+
import { dirname as dirname5, isAbsolute, join as join3, relative, resolve as resolve3, sep } from "path";
|
|
1124
892
|
import { Transform } from "stream";
|
|
1125
893
|
import { pipeline } from "stream/promises";
|
|
1126
894
|
import yauzl from "yauzl";
|
|
@@ -1175,7 +943,7 @@ function resolveProjectTarget(projectRoot, targetDir) {
|
|
|
1175
943
|
return targetPath;
|
|
1176
944
|
}
|
|
1177
945
|
async function readLockfile(projectRoot) {
|
|
1178
|
-
const lockPath =
|
|
946
|
+
const lockPath = join3(projectRoot, ".genrtl", "cbb-lock.json");
|
|
1179
947
|
if (!await pathExists2(lockPath)) {
|
|
1180
948
|
return { schema_version: 1, packages: {} };
|
|
1181
949
|
}
|
|
@@ -1384,7 +1152,7 @@ async function extractZipSafely(archivePath, destination) {
|
|
|
1384
1152
|
if (isDirectory) {
|
|
1385
1153
|
await mkdir4(outputPath, { recursive: true });
|
|
1386
1154
|
} else {
|
|
1387
|
-
await mkdir4(
|
|
1155
|
+
await mkdir4(dirname5(outputPath), { recursive: true });
|
|
1388
1156
|
await extractEntry(zipFile, entry, outputPath, extractedBytes);
|
|
1389
1157
|
}
|
|
1390
1158
|
zipFile.readEntry();
|
|
@@ -1395,7 +1163,7 @@ async function extractZipSafely(archivePath, destination) {
|
|
|
1395
1163
|
}
|
|
1396
1164
|
async function validatePackageManifest(stagingPath, cbbId, version) {
|
|
1397
1165
|
for (const filename of ["manifest.json", "cbb.json", "CBB.json"]) {
|
|
1398
|
-
const manifestPath =
|
|
1166
|
+
const manifestPath = join3(stagingPath, filename);
|
|
1399
1167
|
if (!await pathExists2(manifestPath)) continue;
|
|
1400
1168
|
let manifest;
|
|
1401
1169
|
try {
|
|
@@ -1422,10 +1190,10 @@ async function validatePackageManifest(stagingPath, cbbId, version) {
|
|
|
1422
1190
|
async function writeLockfile(projectRoot, cbbId, entry) {
|
|
1423
1191
|
const lockfile = await readLockfile(projectRoot);
|
|
1424
1192
|
lockfile.packages[cbbId] = entry;
|
|
1425
|
-
const lockDir =
|
|
1426
|
-
const lockPath =
|
|
1427
|
-
const tempPath =
|
|
1428
|
-
const backupPath =
|
|
1193
|
+
const lockDir = join3(projectRoot, ".genrtl");
|
|
1194
|
+
const lockPath = join3(lockDir, "cbb-lock.json");
|
|
1195
|
+
const tempPath = join3(lockDir, `.cbb-lock-${randomUUID()}.tmp`);
|
|
1196
|
+
const backupPath = join3(lockDir, `.cbb-lock-${randomUUID()}.bak`);
|
|
1429
1197
|
await mkdir4(lockDir, { recursive: true });
|
|
1430
1198
|
await writeFile4(tempPath, `${JSON.stringify(lockfile, null, 2)}
|
|
1431
1199
|
`, "utf8");
|
|
@@ -1448,12 +1216,12 @@ async function installCbbArtifact(descriptor, plan, force) {
|
|
|
1448
1216
|
if (descriptor.format !== "zip") {
|
|
1449
1217
|
throw new Error(`Unsupported CBB artifact format: ${descriptor.format}`);
|
|
1450
1218
|
}
|
|
1451
|
-
const targetParent =
|
|
1219
|
+
const targetParent = dirname5(plan.targetPath);
|
|
1452
1220
|
await mkdir4(targetParent, { recursive: true });
|
|
1453
|
-
const tempRoot = await mkdtemp(
|
|
1454
|
-
const archivePath =
|
|
1455
|
-
const stagingPath =
|
|
1456
|
-
const backupPath = `${plan.targetPath}.grtl-backup-${
|
|
1221
|
+
const tempRoot = await mkdtemp(join3(targetParent, ".grtl-cbb-"));
|
|
1222
|
+
const archivePath = join3(tempRoot, "artifact.zip");
|
|
1223
|
+
const stagingPath = join3(tempRoot, "content");
|
|
1224
|
+
const backupPath = `${plan.targetPath}.grtl-backup-${randomUUID()}`;
|
|
1457
1225
|
let backupCreated = false;
|
|
1458
1226
|
let installed = false;
|
|
1459
1227
|
try {
|
|
@@ -1507,10 +1275,93 @@ async function installCbbArtifact(descriptor, plan, force) {
|
|
|
1507
1275
|
}
|
|
1508
1276
|
}
|
|
1509
1277
|
|
|
1278
|
+
// src/constants.ts
|
|
1279
|
+
import { readFileSync } from "fs";
|
|
1280
|
+
import { fileURLToPath } from "url";
|
|
1281
|
+
import { dirname as dirname6, join as join4 } from "path";
|
|
1282
|
+
var __dirname = dirname6(fileURLToPath(import.meta.url));
|
|
1283
|
+
var pkg = JSON.parse(readFileSync(join4(__dirname, "../package.json"), "utf-8"));
|
|
1284
|
+
var VERSION = pkg.version;
|
|
1285
|
+
var NAME = pkg.name;
|
|
1286
|
+
|
|
1287
|
+
// src/utils/knowledge-api.ts
|
|
1288
|
+
var baseUrl = "https://genrtl.com";
|
|
1289
|
+
function setBaseUrl(url) {
|
|
1290
|
+
baseUrl = url.replace(/\/+$/, "");
|
|
1291
|
+
}
|
|
1292
|
+
function getMcpEndpoint() {
|
|
1293
|
+
return baseUrl.endsWith("/api/mcp") ? baseUrl : `${baseUrl}/api/mcp`;
|
|
1294
|
+
}
|
|
1295
|
+
function getApiKey() {
|
|
1296
|
+
return [process.env.GRTL_API_KEY, process.env.GENRTL_API_KEY].map((value) => value?.trim()).find((value) => Boolean(value));
|
|
1297
|
+
}
|
|
1298
|
+
function validateApiKey(apiKey) {
|
|
1299
|
+
if (!/^gtr_(?:live|test)_[A-Za-z0-9_-]{32,128}$/.test(apiKey)) {
|
|
1300
|
+
throw new Error(
|
|
1301
|
+
"Invalid GenRTL API key format. Use the full key shown once when it was created; it must start with gtr_live_ or gtr_test_."
|
|
1302
|
+
);
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
function getMcpErrorMessage(content) {
|
|
1306
|
+
if (!Array.isArray(content)) return void 0;
|
|
1307
|
+
const item = content.find(
|
|
1308
|
+
(entry) => entry && typeof entry === "object" && "type" in entry && entry.type === "text" && "text" in entry && typeof entry.text === "string"
|
|
1309
|
+
);
|
|
1310
|
+
return item?.text;
|
|
1311
|
+
}
|
|
1312
|
+
function getStructuredMcpError(content) {
|
|
1313
|
+
if (!content || typeof content !== "object") return void 0;
|
|
1314
|
+
const errorContent = content;
|
|
1315
|
+
return {
|
|
1316
|
+
error: typeof errorContent.error === "string" ? errorContent.error : void 0,
|
|
1317
|
+
code: typeof errorContent.code === "string" ? errorContent.code : void 0
|
|
1318
|
+
};
|
|
1319
|
+
}
|
|
1320
|
+
async function callGenrtlMcpTool(toolName, input) {
|
|
1321
|
+
const apiKey = getApiKey();
|
|
1322
|
+
if (!apiKey) {
|
|
1323
|
+
throw new Error("Authentication required. Set GRTL_API_KEY or GENRTL_API_KEY.");
|
|
1324
|
+
}
|
|
1325
|
+
validateApiKey(apiKey);
|
|
1326
|
+
const response = await fetch(getMcpEndpoint(), {
|
|
1327
|
+
method: "POST",
|
|
1328
|
+
headers: {
|
|
1329
|
+
"Content-Type": "application/json",
|
|
1330
|
+
Authorization: `Bearer ${apiKey}`,
|
|
1331
|
+
"MCP-Protocol-Version": "2025-06-18",
|
|
1332
|
+
"X-GenRTL-Source": "cli",
|
|
1333
|
+
"X-GenRTL-Client-Version": VERSION
|
|
1334
|
+
},
|
|
1335
|
+
body: JSON.stringify({
|
|
1336
|
+
jsonrpc: "2.0",
|
|
1337
|
+
id: 1,
|
|
1338
|
+
method: "tools/call",
|
|
1339
|
+
params: { name: toolName, arguments: input }
|
|
1340
|
+
})
|
|
1341
|
+
});
|
|
1342
|
+
const payload = await response.json().catch(() => null);
|
|
1343
|
+
if (!response.ok || payload?.error) {
|
|
1344
|
+
const message = payload?.error?.message || `GenRTL MCP request failed with HTTP ${response.status}`;
|
|
1345
|
+
const code = payload?.error?.data?.code;
|
|
1346
|
+
throw new Error(code ? `${message} (${code})` : message);
|
|
1347
|
+
}
|
|
1348
|
+
const result = payload?.result;
|
|
1349
|
+
if (!result) throw new Error("GenRTL MCP returned an empty result.");
|
|
1350
|
+
if (result.isError) {
|
|
1351
|
+
const structuredError = getStructuredMcpError(result.structuredContent);
|
|
1352
|
+
const message = structuredError?.error || getMcpErrorMessage(result.content) || "GenRTL MCP tool call failed.";
|
|
1353
|
+
throw new Error(structuredError?.code ? `${message} (${structuredError.code})` : message);
|
|
1354
|
+
}
|
|
1355
|
+
if (!result.structuredContent) {
|
|
1356
|
+
throw new Error("GenRTL MCP response did not include structured results.");
|
|
1357
|
+
}
|
|
1358
|
+
return result.structuredContent;
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1510
1361
|
// src/commands/cbb.ts
|
|
1511
1362
|
async function installCbb(spec, options) {
|
|
1512
1363
|
trackEvent("command", { name: "cbb-install" });
|
|
1513
|
-
const spinner = process.stdout.isTTY && !options.json ?
|
|
1364
|
+
const spinner = process.stdout.isTTY && !options.json ? ora2("Preparing CBB installation...").start() : null;
|
|
1514
1365
|
try {
|
|
1515
1366
|
const { cbbId, version } = parseCbbSpec(spec);
|
|
1516
1367
|
const target = options.target || defaultCbbTarget(cbbId, version);
|
|
@@ -1545,7 +1396,7 @@ async function installCbb(spec, options) {
|
|
|
1545
1396
|
return;
|
|
1546
1397
|
}
|
|
1547
1398
|
log.blank();
|
|
1548
|
-
log.success(`Installed ${
|
|
1399
|
+
log.success(`Installed ${pc4.bold(`${cbbId}@${version}`)}`);
|
|
1549
1400
|
log.item(`Target: ${result.target_path}`);
|
|
1550
1401
|
log.item(`SHA256: ${result.sha256}`);
|
|
1551
1402
|
log.item(`Lockfile: ${plan.projectRoot}/.genrtl/cbb-lock.json`);
|
|
@@ -1558,7 +1409,7 @@ async function installCbb(spec, options) {
|
|
|
1558
1409
|
}
|
|
1559
1410
|
}
|
|
1560
1411
|
function registerCbbCommands(program2) {
|
|
1561
|
-
const cbb = program2.command("cbb").description("
|
|
1412
|
+
const cbb = program2.command("cbb").description("Install reusable RTL CBBs");
|
|
1562
1413
|
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) => {
|
|
1563
1414
|
await installCbb(spec, options);
|
|
1564
1415
|
});
|
|
@@ -1567,7 +1418,7 @@ function registerCbbCommands(program2) {
|
|
|
1567
1418
|
// src/commands/upgrade.ts
|
|
1568
1419
|
import { confirm } from "@inquirer/prompts";
|
|
1569
1420
|
import { spawn } from "child_process";
|
|
1570
|
-
import
|
|
1421
|
+
import pc5 from "picocolors";
|
|
1571
1422
|
|
|
1572
1423
|
// src/utils/update-check.ts
|
|
1573
1424
|
import { homedir as homedir2 } from "os";
|
|
@@ -1778,7 +1629,7 @@ async function runUpgradePlan(plan) {
|
|
|
1778
1629
|
return runCommand(plan.command, plan.args);
|
|
1779
1630
|
}
|
|
1780
1631
|
function showUpgradeFailureHelp(plan) {
|
|
1781
|
-
log.info(`Try rerunning: ${
|
|
1632
|
+
log.info(`Try rerunning: ${pc5.cyan(plan.displayCommand)}`);
|
|
1782
1633
|
const isGlobalNpmInstall = (plan.installMethod === "npm-global" || plan.installMethod === "unknown") && plan.command === "npm" && plan.args.includes("-g");
|
|
1783
1634
|
const isGlobalAltInstall = (plan.installMethod === "pnpm-global" || plan.installMethod === "bun-global") && plan.args.includes("-g");
|
|
1784
1635
|
if (isGlobalNpmInstall) {
|
|
@@ -1805,8 +1656,8 @@ async function maybeShowUpgradeNotice(options = {}) {
|
|
|
1805
1656
|
log.blank();
|
|
1806
1657
|
if (info.upgradePlan.needsExplicitVersion) {
|
|
1807
1658
|
log.box([
|
|
1808
|
-
`${
|
|
1809
|
-
`${
|
|
1659
|
+
`${pc5.white(pc5.bold("Update available:"))} ${pc5.green(pc5.bold(`v${info.currentVersion}`))} ${pc5.dim("->")} ${pc5.green(pc5.bold(`v${info.latestVersion}`))}`,
|
|
1660
|
+
`${pc5.white("Use")} ${pc5.yellow(pc5.bold(info.upgradePlan.displayCommand))} ${pc5.white("to run the latest version")}`
|
|
1810
1661
|
]);
|
|
1811
1662
|
await markUpdateNotificationShown(info.latestVersion);
|
|
1812
1663
|
log.blank();
|
|
@@ -1814,18 +1665,18 @@ async function maybeShowUpgradeNotice(options = {}) {
|
|
|
1814
1665
|
}
|
|
1815
1666
|
if (!info.upgradePlan.canRun) {
|
|
1816
1667
|
log.box([
|
|
1817
|
-
`${
|
|
1818
|
-
`${
|
|
1819
|
-
`${
|
|
1668
|
+
`${pc5.white(pc5.bold("Update available:"))} ${pc5.green(pc5.bold(`v${info.currentVersion}`))} ${pc5.dim("->")} ${pc5.green(pc5.bold(`v${info.latestVersion}`))}`,
|
|
1669
|
+
`${pc5.white("Run")} ${pc5.yellow(pc5.bold("grtl upgrade"))} ${pc5.white("for update steps")}`,
|
|
1670
|
+
`${pc5.white("Or run")} ${pc5.yellow(info.upgradePlan.displayCommand)}`
|
|
1820
1671
|
]);
|
|
1821
1672
|
await markUpdateNotificationShown(info.latestVersion);
|
|
1822
1673
|
log.blank();
|
|
1823
1674
|
return;
|
|
1824
1675
|
}
|
|
1825
1676
|
log.box([
|
|
1826
|
-
`${
|
|
1827
|
-
`${
|
|
1828
|
-
`${
|
|
1677
|
+
`${pc5.white(pc5.bold("Update available:"))} ${pc5.green(pc5.bold(`v${info.currentVersion}`))} ${pc5.dim("->")} ${pc5.green(pc5.bold(`v${info.latestVersion}`))}`,
|
|
1678
|
+
`${pc5.white("Run")} ${pc5.yellow(pc5.bold("grtl upgrade"))} ${pc5.white("to update now")}`,
|
|
1679
|
+
`${pc5.white("Or run")} ${pc5.yellow(info.upgradePlan.displayCommand)}`
|
|
1829
1680
|
]);
|
|
1830
1681
|
await markUpdateNotificationShown(info.latestVersion);
|
|
1831
1682
|
log.blank();
|
|
@@ -1836,28 +1687,28 @@ async function upgradeCommand(options) {
|
|
|
1836
1687
|
const plan = info?.upgradePlan ?? getUpgradePlan();
|
|
1837
1688
|
if (!info) {
|
|
1838
1689
|
log.warn("Couldn't check for updates right now.");
|
|
1839
|
-
log.info(`Try again later or run ${
|
|
1690
|
+
log.info(`Try again later or run ${pc5.cyan(plan.displayCommand)} manually.`);
|
|
1840
1691
|
return;
|
|
1841
1692
|
}
|
|
1842
1693
|
if (!info.updateAvailable) {
|
|
1843
|
-
log.success(`grtl is up to date (${
|
|
1694
|
+
log.success(`grtl is up to date (${pc5.bold(`v${VERSION}`)})`);
|
|
1844
1695
|
return;
|
|
1845
1696
|
}
|
|
1846
1697
|
log.blank();
|
|
1847
1698
|
log.info(
|
|
1848
|
-
`Update available: ${
|
|
1699
|
+
`Update available: ${pc5.bold(`v${info.currentVersion}`)} ${pc5.dim("->")} ${pc5.bold(`v${info.latestVersion}`)}`
|
|
1849
1700
|
);
|
|
1850
1701
|
if (plan.needsExplicitVersion) {
|
|
1851
1702
|
log.info(`You're using an ephemeral runner (${plan.installMethod}).`);
|
|
1852
|
-
log.info(`Use ${
|
|
1853
|
-
log.info(`Or install globally with ${
|
|
1703
|
+
log.info(`Use ${pc5.cyan(plan.displayCommand)} to run the latest version immediately.`);
|
|
1704
|
+
log.info(`Or install globally with ${pc5.cyan("npm install -g @genrtl/grtl@latest")}.`);
|
|
1854
1705
|
return;
|
|
1855
1706
|
}
|
|
1856
1707
|
if (!plan.canRun) {
|
|
1857
|
-
log.info(`Run ${
|
|
1708
|
+
log.info(`Run ${pc5.cyan(plan.displayCommand)} to update your installed version.`);
|
|
1858
1709
|
return;
|
|
1859
1710
|
}
|
|
1860
|
-
log.info(`Upgrade command: ${
|
|
1711
|
+
log.info(`Upgrade command: ${pc5.cyan(plan.displayCommand)}`);
|
|
1861
1712
|
if (options.check) {
|
|
1862
1713
|
return;
|
|
1863
1714
|
}
|
|
@@ -1877,7 +1728,7 @@ async function upgradeCommand(options) {
|
|
|
1877
1728
|
if (exitCode === 0) {
|
|
1878
1729
|
log.blank();
|
|
1879
1730
|
log.success("Upgrade complete.");
|
|
1880
|
-
log.info(`Run ${
|
|
1731
|
+
log.info(`Run ${pc5.cyan("grtl --version")} to verify the installed version.`);
|
|
1881
1732
|
return;
|
|
1882
1733
|
}
|
|
1883
1734
|
log.blank();
|
|
@@ -1888,11 +1739,11 @@ async function upgradeCommand(options) {
|
|
|
1888
1739
|
|
|
1889
1740
|
// src/index.ts
|
|
1890
1741
|
var brand = {
|
|
1891
|
-
primary:
|
|
1892
|
-
dim:
|
|
1742
|
+
primary: pc6.green,
|
|
1743
|
+
dim: pc6.dim
|
|
1893
1744
|
};
|
|
1894
|
-
var program = new
|
|
1895
|
-
program.name("grtl").description("GenRTL CLI -
|
|
1745
|
+
var program = new Command();
|
|
1746
|
+
program.name("grtl").description("GenRTL CLI - Configure GenRTL and install reusable RTL CBBs").version(VERSION).option("--base-url <url>").hook("preAction", (thisCommand) => {
|
|
1896
1747
|
const opts = thisCommand.opts();
|
|
1897
1748
|
if (opts.baseUrl) {
|
|
1898
1749
|
setBaseUrl(opts.baseUrl);
|
|
@@ -1907,34 +1758,25 @@ program.name("grtl").description("GenRTL CLI - Search RTL engineering knowledge
|
|
|
1907
1758
|
"after",
|
|
1908
1759
|
`
|
|
1909
1760
|
Examples:
|
|
1910
|
-
${brand.dim("# Configure GenRTL for your coding agent")}
|
|
1911
|
-
${brand.primary("npx @genrtl/grtl setup --cli --codex --project")}
|
|
1761
|
+
${brand.dim("# Configure GenRTL MCP for your coding agent")}
|
|
1912
1762
|
${brand.primary("GRTL_API_KEY=your_key npx @genrtl/grtl setup --mcp --codex --project")}
|
|
1913
1763
|
|
|
1914
|
-
${brand.dim("# Search the same five tools exposed by the GenRTL MCP server")}
|
|
1915
|
-
${brand.primary('npx @genrtl/grtl knowledge-search "AXI stream backpressure design"')}
|
|
1916
|
-
${brand.primary('npx @genrtl/grtl spec2rtl-search "Generate an APB register block"')}
|
|
1917
|
-
${brand.primary('npx @genrtl/grtl spec2plan-search "Plan an APB register block implementation"')}
|
|
1918
|
-
${brand.primary('npx @genrtl/grtl verification-search "Verify an async FIFO"')}
|
|
1919
|
-
${brand.primary('npx @genrtl/grtl debug-search "Explain this Vivado CDC warning"')}
|
|
1920
|
-
|
|
1921
1764
|
${brand.dim("# Acquire and install a reusable RTL CBB")}
|
|
1922
1765
|
${brand.primary("npx @genrtl/grtl cbb install cbb_uart@1.2.0")}
|
|
1923
1766
|
`
|
|
1924
1767
|
);
|
|
1925
1768
|
registerSetupCommand(program);
|
|
1926
|
-
registerKnowledgeCommands(program);
|
|
1927
1769
|
registerCbbCommands(program);
|
|
1928
1770
|
registerUpgradeCommand(program);
|
|
1929
1771
|
program.action(() => {
|
|
1930
1772
|
console.log("");
|
|
1931
1773
|
const banner = figlet.textSync("GenRTL", { font: "ANSI Shadow" });
|
|
1932
1774
|
console.log(brand.primary(banner));
|
|
1933
|
-
console.log(brand.dim("
|
|
1775
|
+
console.log(brand.dim(" Configure GenRTL MCP and install reusable RTL CBBs"));
|
|
1934
1776
|
console.log("");
|
|
1935
1777
|
console.log(" Quick start:");
|
|
1936
|
-
console.log(` ${brand.primary("npx @genrtl/grtl setup")}`);
|
|
1937
|
-
console.log(` ${brand.primary(
|
|
1778
|
+
console.log(` ${brand.primary("npx @genrtl/grtl setup --mcp")}`);
|
|
1779
|
+
console.log(` ${brand.primary("npx @genrtl/grtl cbb install cbb_uart@1.2.0")}`);
|
|
1938
1780
|
console.log("");
|
|
1939
1781
|
console.log(` Run ${brand.primary("npx @genrtl/grtl --help")} for all commands and options`);
|
|
1940
1782
|
console.log("");
|