dero-mcp-server 0.1.2 → 0.2.2

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.
Files changed (38) hide show
  1. package/README.md +8 -8
  2. package/data/docs-index.json +17 -9
  3. package/dist/citations.d.ts +70 -0
  4. package/dist/citations.d.ts.map +1 -0
  5. package/dist/citations.js +162 -0
  6. package/dist/citations.js.map +1 -0
  7. package/dist/composites/_shared.d.ts +119 -0
  8. package/dist/composites/_shared.d.ts.map +1 -0
  9. package/dist/composites/_shared.js +152 -0
  10. package/dist/composites/_shared.js.map +1 -0
  11. package/dist/composites/diagnose-chain-health.d.ts +64 -0
  12. package/dist/composites/diagnose-chain-health.d.ts.map +1 -0
  13. package/dist/composites/diagnose-chain-health.js +144 -0
  14. package/dist/composites/diagnose-chain-health.js.map +1 -0
  15. package/dist/composites/estimate-deploy-cost.d.ts +83 -0
  16. package/dist/composites/estimate-deploy-cost.d.ts.map +1 -0
  17. package/dist/composites/estimate-deploy-cost.js +116 -0
  18. package/dist/composites/estimate-deploy-cost.js.map +1 -0
  19. package/dist/composites/explain-smart-contract.d.ts +64 -0
  20. package/dist/composites/explain-smart-contract.d.ts.map +1 -0
  21. package/dist/composites/explain-smart-contract.js +149 -0
  22. package/dist/composites/explain-smart-contract.js.map +1 -0
  23. package/dist/composites/recommend-docs-path.d.ts +97 -0
  24. package/dist/composites/recommend-docs-path.d.ts.map +1 -0
  25. package/dist/composites/recommend-docs-path.js +149 -0
  26. package/dist/composites/recommend-docs-path.js.map +1 -0
  27. package/dist/composites/trace-transaction-with-context.d.ts +107 -0
  28. package/dist/composites/trace-transaction-with-context.d.ts.map +1 -0
  29. package/dist/composites/trace-transaction-with-context.js +217 -0
  30. package/dist/composites/trace-transaction-with-context.js.map +1 -0
  31. package/dist/server.d.ts.map +1 -1
  32. package/dist/server.js +334 -112
  33. package/dist/server.js.map +1 -1
  34. package/dist/tool-descriptions.d.ts +50 -0
  35. package/dist/tool-descriptions.d.ts.map +1 -0
  36. package/dist/tool-descriptions.js +246 -0
  37. package/dist/tool-descriptions.js.map +1 -0
  38. package/package.json +5 -1
@@ -0,0 +1,64 @@
1
+ /**
2
+ * `diagnose_chain_health` — Phase C composite #1.
3
+ *
4
+ * Decorator-style composite that replaces four agent round-trips
5
+ * (`DERO.Ping` + `DERO.GetInfo` + `DERO.GetHeight` + `DERO.GetTxPool`) and
6
+ * the "what does this field mean?" docs lookup with a single narrative
7
+ * response carrying chain metadata, mempool snapshot, narrative summary,
8
+ * and curated docs citations.
9
+ *
10
+ * Design contract: `docs/composites.md` § 1 (lowest-risk composite, ships
11
+ * first to prove the composite plumbing — shared utils + flow test pattern
12
+ * + smoke assertions — end-to-end).
13
+ *
14
+ * Failure model:
15
+ * - `DERO.Ping` is the only required step. Its failure halts the chain
16
+ * and the handler throws so `withStructuredErrors` surfaces a
17
+ * structured `RPC_UNREACHABLE` error.
18
+ * - `DERO.GetInfo`, `DERO.GetHeight`, and `DERO.GetTxPool` are
19
+ * non-required. Their failures degrade `status` to `partial` and
20
+ * leave the corresponding response field null, but the composite
21
+ * still returns a useful payload.
22
+ */
23
+ import { z } from 'zod';
24
+ import { type DeroDaemonRpc } from './_shared.js';
25
+ export declare const diagnoseChainHealthInputSchema: {
26
+ readonly include_tx_pool: z.ZodOptional<z.ZodBoolean>;
27
+ };
28
+ type DiagnoseInput = {
29
+ include_tx_pool?: boolean;
30
+ };
31
+ type DiagnoseStatus = 'healthy' | 'lagging' | 'partial' | 'unreachable';
32
+ type DiagnoseSignal = {
33
+ key: string;
34
+ value: string | number;
35
+ note?: string;
36
+ };
37
+ export declare function diagnoseChainHealth(rpc: DeroDaemonRpc, args: DiagnoseInput): Promise<{
38
+ status: DiagnoseStatus;
39
+ narrative: string;
40
+ signals: DiagnoseSignal[];
41
+ chain: {
42
+ topoheight: number;
43
+ stableheight: number | null;
44
+ height: number | null;
45
+ network: string | null;
46
+ version: string | null;
47
+ difficulty: string | number | null;
48
+ total_supply: string | number | null;
49
+ } | null;
50
+ mempool: {
51
+ pending: number;
52
+ sample: string[];
53
+ } | null;
54
+ _diagnostics: {
55
+ step_latency_ms: Record<string, number>;
56
+ total_ms: number;
57
+ halted_at: string | null;
58
+ include_tx_pool: boolean;
59
+ };
60
+ } & {
61
+ related_docs?: import("../citations.js").DeroCitation[];
62
+ }>;
63
+ export {};
64
+ //# sourceMappingURL=diagnose-chain-health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnose-chain-health.d.ts","sourceRoot":"","sources":["../../src/composites/diagnose-chain-health.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAML,KAAK,aAAa,EACnB,MAAM,cAAc,CAAA;AAErB,eAAO,MAAM,8BAA8B;;CAKjC,CAAA;AAEV,KAAK,aAAa,GAAG;IAAE,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,CAAA;AAyBlD,KAAK,cAAc,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAA;AAEvE,KAAK,cAAc,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AA4E5E,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;GA+DhF"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * `diagnose_chain_health` — Phase C composite #1.
3
+ *
4
+ * Decorator-style composite that replaces four agent round-trips
5
+ * (`DERO.Ping` + `DERO.GetInfo` + `DERO.GetHeight` + `DERO.GetTxPool`) and
6
+ * the "what does this field mean?" docs lookup with a single narrative
7
+ * response carrying chain metadata, mempool snapshot, narrative summary,
8
+ * and curated docs citations.
9
+ *
10
+ * Design contract: `docs/composites.md` § 1 (lowest-risk composite, ships
11
+ * first to prove the composite plumbing — shared utils + flow test pattern
12
+ * + smoke assertions — end-to-end).
13
+ *
14
+ * Failure model:
15
+ * - `DERO.Ping` is the only required step. Its failure halts the chain
16
+ * and the handler throws so `withStructuredErrors` surfaces a
17
+ * structured `RPC_UNREACHABLE` error.
18
+ * - `DERO.GetInfo`, `DERO.GetHeight`, and `DERO.GetTxPool` are
19
+ * non-required. Their failures degrade `status` to `partial` and
20
+ * leave the corresponding response field null, but the composite
21
+ * still returns a useful payload.
22
+ */
23
+ import { z } from 'zod';
24
+ import { attachCitations, runChain, stepLatencies, stepValue, } from './_shared.js';
25
+ export const diagnoseChainHealthInputSchema = {
26
+ include_tx_pool: z
27
+ .boolean()
28
+ .optional()
29
+ .describe('Include mempool snapshot in narrative and response. Default true.'),
30
+ };
31
+ const LAG_DEPTH_LAGGING_THRESHOLD = 50;
32
+ /**
33
+ * Pure function: turn the three RPC payloads (any of which may be null
34
+ * if the corresponding step failed) into a status, narrative, and
35
+ * machine-readable signals block. Kept inside this file because it is
36
+ * tightly coupled to the response shape and is not reused elsewhere.
37
+ */
38
+ function summarizeChainHealth(info, height, txPool, txPoolRequested) {
39
+ const signals = [];
40
+ if (!info || typeof info.topoheight !== 'number' || typeof info.stableheight !== 'number') {
41
+ return {
42
+ status: 'partial',
43
+ narrative: 'Daemon ping succeeded but chain info was unavailable; only liveness can be confirmed. Inspect daemon logs and retry.',
44
+ signals,
45
+ };
46
+ }
47
+ const lagDepth = info.topoheight - info.stableheight;
48
+ signals.push({ key: 'topoheight', value: info.topoheight });
49
+ signals.push({ key: 'stableheight', value: info.stableheight });
50
+ signals.push({
51
+ key: 'lag_depth',
52
+ value: lagDepth,
53
+ note: 'topoheight minus stableheight; values above 50 suggest the node is catching up',
54
+ });
55
+ if (info.network)
56
+ signals.push({ key: 'network', value: info.network });
57
+ if (info.version)
58
+ signals.push({ key: 'version', value: info.version });
59
+ if (height && typeof height.topoheight === 'number' && height.topoheight !== info.topoheight) {
60
+ signals.push({
61
+ key: 'topoheight_drift',
62
+ value: height.topoheight - info.topoheight,
63
+ note: 'GetHeight reported a different topoheight than GetInfo; values within +/-1 are normal between RPC calls',
64
+ });
65
+ }
66
+ let status = 'healthy';
67
+ const narrativeParts = [];
68
+ if (lagDepth > LAG_DEPTH_LAGGING_THRESHOLD) {
69
+ status = 'lagging';
70
+ narrativeParts.push(`Chain shows a lag depth of ${lagDepth} blocks between topoheight (${info.topoheight}) and stableheight (${info.stableheight}); typical depth is under ${LAG_DEPTH_LAGGING_THRESHOLD}, so the node may be catching up.`);
71
+ }
72
+ else {
73
+ narrativeParts.push(`Chain appears healthy on ${info.network ?? 'unknown network'} (version ${info.version ?? 'unknown'}): topoheight ${info.topoheight}, stableheight ${info.stableheight}, lag depth ${lagDepth}.`);
74
+ }
75
+ if (!txPoolRequested) {
76
+ narrativeParts.push('Mempool snapshot was skipped by request (include_tx_pool=false).');
77
+ }
78
+ else if (!txPool) {
79
+ if (status === 'healthy')
80
+ status = 'partial';
81
+ narrativeParts.push('Mempool snapshot failed; mempool state is unknown for this report.');
82
+ }
83
+ else {
84
+ const pending = Array.isArray(txPool.tx_hashes) ? txPool.tx_hashes.length : 0;
85
+ signals.push({ key: 'mempool_pending', value: pending });
86
+ narrativeParts.push(pending === 0
87
+ ? 'Mempool is empty.'
88
+ : `Mempool has ${pending} pending transaction${pending === 1 ? '' : 's'}.`);
89
+ }
90
+ return { status, narrative: narrativeParts.join(' '), signals };
91
+ }
92
+ export async function diagnoseChainHealth(rpc, args) {
93
+ const includeTxPool = args.include_tx_pool !== false;
94
+ const steps = [
95
+ { name: 'ping', required: true, fn: () => rpc('DERO.Ping') },
96
+ { name: 'info', required: false, fn: () => rpc('DERO.GetInfo') },
97
+ { name: 'height', required: false, fn: () => rpc('DERO.GetHeight') },
98
+ ...(includeTxPool
99
+ ? [{ name: 'tx_pool', required: false, fn: () => rpc('DERO.GetTxPool') }]
100
+ : []),
101
+ ];
102
+ const chain = await runChain(steps);
103
+ if (chain.haltedAt === 'ping') {
104
+ const pingResult = chain.results.find((r) => r.name === 'ping');
105
+ const detail = pingResult?.error?.message ?? 'unknown error';
106
+ // `withStructuredErrors` classifies this message into RPC_UNREACHABLE.
107
+ throw new Error(`fetch failed: ${detail}`);
108
+ }
109
+ const info = stepValue(chain, 'info');
110
+ const height = stepValue(chain, 'height');
111
+ const txPool = includeTxPool ? stepValue(chain, 'tx_pool') : null;
112
+ const { status, narrative, signals } = summarizeChainHealth(info, height, txPool, includeTxPool);
113
+ const chainData = info && typeof info.topoheight === 'number'
114
+ ? {
115
+ topoheight: info.topoheight,
116
+ stableheight: info.stableheight ?? null,
117
+ height: info.height ?? null,
118
+ network: info.network ?? null,
119
+ version: info.version ?? null,
120
+ difficulty: info.difficulty ?? null,
121
+ total_supply: info.total_supply ?? null,
122
+ }
123
+ : null;
124
+ const mempool = txPool
125
+ ? {
126
+ pending: Array.isArray(txPool.tx_hashes) ? txPool.tx_hashes.length : 0,
127
+ sample: (txPool.tx_hashes ?? []).slice(0, 5),
128
+ }
129
+ : null;
130
+ return attachCitations({
131
+ status,
132
+ narrative,
133
+ signals,
134
+ chain: chainData,
135
+ mempool,
136
+ _diagnostics: {
137
+ step_latency_ms: stepLatencies(chain),
138
+ total_ms: chain.totalMs,
139
+ halted_at: chain.haltedAt,
140
+ include_tx_pool: includeTxPool,
141
+ },
142
+ }, 'diagnose_chain_health');
143
+ }
144
+ //# sourceMappingURL=diagnose-chain-health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnose-chain-health.js","sourceRoot":"","sources":["../../src/composites/diagnose-chain-health.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * `estimate_deploy_cost` — Phase C composite #4.
3
+ *
4
+ * Wedge: `dero_get_gas_estimate` returns raw `gascompute` and
5
+ * `gasstorage` numbers. Agents have to know that the first is DVM
6
+ * execution cost and the second is on-chain byte cost — and have to
7
+ * separately call `dero_get_sc` to understand what they are about to
8
+ * deploy. This composite returns the estimate, the parsed contract
9
+ * surface (functions / stringkeys / uint64keys), a plain-text
10
+ * breakdown explaining what each number means, and the curated
11
+ * "Create, Deploy & Use a Smart Contract" docs page as a citation.
12
+ *
13
+ * Design contract: `docs/composites.md` § 4. Sequencing rule: SHIP
14
+ * FOURTH. Numeric semantics; relies on `extractScSurface` (composite
15
+ * #2) being stable. Must not ship before composite #2 because the
16
+ * surface enrichment proves out the reuse path planned in the design
17
+ * doc.
18
+ *
19
+ * Failure model:
20
+ * - DVM compile failure (daemon returns `RPC error -32098`) → the
21
+ * classifier branch in `withStructuredErrors` surfaces this as
22
+ * `INVALID_INPUT` with an actionable hint. The daemon's exact
23
+ * compile message stays in `_meta.error.raw`.
24
+ * - Invalid signer address → daemon usually emits `RPC error
25
+ * -32602` (RPC_INVALID_PARAMS); existing classifier branch
26
+ * handles it.
27
+ * - Daemon returns a non-"OK" status with 0/0 numbers → return
28
+ * the estimate as-is and set `breakdown: null`. NEVER fabricate
29
+ * a breakdown when the numbers are 0/0 with a non-success
30
+ * status; the agent must see the daemon's exact status string.
31
+ */
32
+ import { z } from 'zod';
33
+ import { type DeroDaemonRpc } from './_shared.js';
34
+ export declare const estimateDeployCostInputSchema: {
35
+ readonly sc: z.ZodString;
36
+ readonly signer: z.ZodOptional<z.ZodString>;
37
+ readonly include_breakdown: z.ZodOptional<z.ZodBoolean>;
38
+ };
39
+ type EstimateInput = {
40
+ sc: string;
41
+ signer?: string;
42
+ include_breakdown?: boolean;
43
+ };
44
+ type EstimateBreakdown = {
45
+ compute_note: string;
46
+ storage_note: string;
47
+ total_units: number;
48
+ };
49
+ /**
50
+ * Pure function: turn a (gascompute, gasstorage) pair into a
51
+ * plain-language breakdown. Returns `null` when either number is
52
+ * unavailable or non-numeric, OR when the daemon returned 0/0 with a
53
+ * non-"OK" status (in which case fabricating a breakdown would
54
+ * mislead the agent — the design contract is explicit on this).
55
+ *
56
+ * The DVM denominates gas in atomic units (the daemon docs call them
57
+ * "gas units"). Converting to DERO requires the fee-per-gas table,
58
+ * which is itself a separate query. We deliberately do NOT convert
59
+ * here and instead surface the raw unit total plus a note pointing
60
+ * the agent at the docs.
61
+ */
62
+ export declare function buildBreakdown(gascompute: number | string | undefined, gasstorage: number | string | undefined, status: string | undefined): EstimateBreakdown | null;
63
+ export declare function estimateDeployCost(rpc: DeroDaemonRpc, args: EstimateInput): Promise<{
64
+ estimate: {
65
+ gascompute: number | null;
66
+ gasstorage: number | null;
67
+ status: string | null;
68
+ };
69
+ breakdown: EstimateBreakdown | null;
70
+ signer_used: string | null;
71
+ include_breakdown: boolean;
72
+ sc_surface: {
73
+ functions: import("./_shared.js").DvmFunctionSignature[];
74
+ stringkeys: string[];
75
+ uint64keys: string[];
76
+ raw_code_length: number;
77
+ function_count: number;
78
+ };
79
+ } & {
80
+ related_docs?: import("../citations.js").DeroCitation[];
81
+ }>;
82
+ export {};
83
+ //# sourceMappingURL=estimate-deploy-cost.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"estimate-deploy-cost.d.ts","sourceRoot":"","sources":["../../src/composites/estimate-deploy-cost.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,cAAc,CAAA;AAIrB,eAAO,MAAM,6BAA6B;;;;CAgBhC,CAAA;AAEV,KAAK,aAAa,GAAG;IACnB,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B,CAAA;AASD,KAAK,iBAAiB,GAAG;IACvB,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,EACvC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,EACvC,MAAM,EAAE,MAAM,GAAG,SAAS,GACzB,iBAAiB,GAAG,IAAI,CAU1B;AAED,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa;;;;;;;;;;;;;;;;;;GAgD/E"}
@@ -0,0 +1,116 @@
1
+ /**
2
+ * `estimate_deploy_cost` — Phase C composite #4.
3
+ *
4
+ * Wedge: `dero_get_gas_estimate` returns raw `gascompute` and
5
+ * `gasstorage` numbers. Agents have to know that the first is DVM
6
+ * execution cost and the second is on-chain byte cost — and have to
7
+ * separately call `dero_get_sc` to understand what they are about to
8
+ * deploy. This composite returns the estimate, the parsed contract
9
+ * surface (functions / stringkeys / uint64keys), a plain-text
10
+ * breakdown explaining what each number means, and the curated
11
+ * "Create, Deploy & Use a Smart Contract" docs page as a citation.
12
+ *
13
+ * Design contract: `docs/composites.md` § 4. Sequencing rule: SHIP
14
+ * FOURTH. Numeric semantics; relies on `extractScSurface` (composite
15
+ * #2) being stable. Must not ship before composite #2 because the
16
+ * surface enrichment proves out the reuse path planned in the design
17
+ * doc.
18
+ *
19
+ * Failure model:
20
+ * - DVM compile failure (daemon returns `RPC error -32098`) → the
21
+ * classifier branch in `withStructuredErrors` surfaces this as
22
+ * `INVALID_INPUT` with an actionable hint. The daemon's exact
23
+ * compile message stays in `_meta.error.raw`.
24
+ * - Invalid signer address → daemon usually emits `RPC error
25
+ * -32602` (RPC_INVALID_PARAMS); existing classifier branch
26
+ * handles it.
27
+ * - Daemon returns a non-"OK" status with 0/0 numbers → return
28
+ * the estimate as-is and set `breakdown: null`. NEVER fabricate
29
+ * a breakdown when the numbers are 0/0 with a non-success
30
+ * status; the agent must see the daemon's exact status string.
31
+ */
32
+ import { z } from 'zod';
33
+ import { attachCitations, extractScSurface, } from './_shared.js';
34
+ const DERO_ADDRESS_REGEX = /^(dero1|deto1)[0-9a-z]+$/i;
35
+ export const estimateDeployCostInputSchema = {
36
+ sc: z
37
+ .string()
38
+ .min(1)
39
+ .describe('DVM-BASIC contract source to deploy. MUST be the full contract (Function ... End Function blocks), not a function body alone.'),
40
+ signer: z
41
+ .string()
42
+ .regex(DERO_ADDRESS_REGEX, 'Expected DERO address starting with dero1 or deto1')
43
+ .optional()
44
+ .describe('Optional dero1.../deto1... signer for the eventual deploy tx.'),
45
+ include_breakdown: z
46
+ .boolean()
47
+ .optional()
48
+ .describe('Default true. Set false to return raw estimate numbers only.'),
49
+ };
50
+ /**
51
+ * Pure function: turn a (gascompute, gasstorage) pair into a
52
+ * plain-language breakdown. Returns `null` when either number is
53
+ * unavailable or non-numeric, OR when the daemon returned 0/0 with a
54
+ * non-"OK" status (in which case fabricating a breakdown would
55
+ * mislead the agent — the design contract is explicit on this).
56
+ *
57
+ * The DVM denominates gas in atomic units (the daemon docs call them
58
+ * "gas units"). Converting to DERO requires the fee-per-gas table,
59
+ * which is itself a separate query. We deliberately do NOT convert
60
+ * here and instead surface the raw unit total plus a note pointing
61
+ * the agent at the docs.
62
+ */
63
+ export function buildBreakdown(gascompute, gasstorage, status) {
64
+ const compute = typeof gascompute === 'number' ? gascompute : Number(gascompute);
65
+ const storage = typeof gasstorage === 'number' ? gasstorage : Number(gasstorage);
66
+ if (!Number.isFinite(compute) || !Number.isFinite(storage))
67
+ return null;
68
+ if (compute === 0 && storage === 0 && status !== 'OK')
69
+ return null;
70
+ return {
71
+ compute_note: `gascompute=${compute} — DVM execution cost (units the daemon charges for running the contract's Initialize and any reachable functions during the deploy). Higher when the contract has more code paths.`,
72
+ storage_note: `gasstorage=${storage} — on-chain byte cost (units the daemon charges for storing the contract code blob and its initial state). Roughly proportional to source length.`,
73
+ total_units: compute + storage,
74
+ };
75
+ }
76
+ export async function estimateDeployCost(rpc, args) {
77
+ const params = { sc: args.sc };
78
+ if (args.signer)
79
+ params.signer = args.signer;
80
+ // Required call. DVM compile failures throw RPC error -32098 which
81
+ // the classifier branch in src/server.ts maps to INVALID_INPUT.
82
+ const raw = (await rpc('DERO.GetGasEstimate', params)) ?? {};
83
+ const gascompute = typeof raw.gascompute === 'number' || typeof raw.gascompute === 'string'
84
+ ? Number(raw.gascompute)
85
+ : null;
86
+ const gasstorage = typeof raw.gasstorage === 'number' || typeof raw.gasstorage === 'string'
87
+ ? Number(raw.gasstorage)
88
+ : null;
89
+ const status = typeof raw.status === 'string' ? raw.status : null;
90
+ const includeBreakdown = args.include_breakdown !== false;
91
+ const breakdown = includeBreakdown ? buildBreakdown(raw.gascompute, raw.gasstorage, raw.status ?? undefined) : null;
92
+ // Wedge enrichment: parse the SC source the user just submitted so
93
+ // the agent can show "you're about to deploy X functions" alongside
94
+ // the gas numbers. Reuses extractScSurface from composite #2, with
95
+ // the user-provided `sc` shaped as a DeroGetScResult so the same
96
+ // extractor can run unchanged.
97
+ const surface = extractScSurface({ code: args.sc });
98
+ return attachCitations({
99
+ estimate: {
100
+ gascompute,
101
+ gasstorage,
102
+ status,
103
+ },
104
+ breakdown,
105
+ signer_used: args.signer ?? null,
106
+ include_breakdown: includeBreakdown,
107
+ sc_surface: {
108
+ functions: surface.functions,
109
+ stringkeys: surface.stringkeys,
110
+ uint64keys: surface.uint64keys,
111
+ raw_code_length: surface.raw_code_length,
112
+ function_count: surface.functions.length,
113
+ },
114
+ }, 'estimate_deploy_cost');
115
+ }
116
+ //# sourceMappingURL=estimate-deploy-cost.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"estimate-deploy-cost.js","sourceRoot":"","sources":["../../src/composites/estimate-deploy-cost.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * `explain_smart_contract` — Phase C composite #2.
3
+ *
4
+ * Wedge-defining composite. Today an agent calls `dero_get_sc`, gets a
5
+ * raw code blob with stringkeys/uint64keys/balances, and must know
6
+ * DVM-BASIC syntax to interpret it. This composite extracts the
7
+ * contract's function surface and stitches it to the right bundled DVM
8
+ * docs page — something no generic chain MCP can replicate because no
9
+ * other chain MCP ships the docs index in-process.
10
+ *
11
+ * Design contract: `docs/composites.md` § 2. Sequencing rule: SHIP
12
+ * SECOND — establishes the SC-introspection pattern (`extractScSurface`)
13
+ * that `trace_transaction_with_context` and `estimate_deploy_cost` reuse.
14
+ *
15
+ * Failure model:
16
+ * - `DERO.GetSC` failing entirely → handler throws so
17
+ * `withStructuredErrors` surfaces a structured error to the agent.
18
+ * - `DERO.GetSC` succeeds but returns no `code` → response carries
19
+ * `surface.has_code: false`, `functions: []`, narrative explains
20
+ * the SCID is unknown or has no on-chain code, and `_meta.error`
21
+ * style hint points at `dero_docs_search("smart contract")`.
22
+ * - Code present but `extractScSurface` finds zero functions →
23
+ * return surface with `functions: []` and a narrative noting
24
+ * parse-uncertainty. NEVER swallow the raw code; surface
25
+ * `raw_code_length` so the agent knows to fall back to `dero_get_sc`.
26
+ */
27
+ import { z } from 'zod';
28
+ import { type DeroDaemonRpc, type DeroScSurface } from './_shared.js';
29
+ export declare const explainSmartContractInputSchema: {
30
+ readonly scid: z.ZodString;
31
+ readonly topoheight: z.ZodOptional<z.ZodNumber>;
32
+ };
33
+ type ExplainInput = {
34
+ scid: string;
35
+ topoheight?: number;
36
+ };
37
+ type ContractKind = 'token' | 'registry' | 'minimal' | 'generic';
38
+ /**
39
+ * Classify a contract from its surface + raw code so we can pick the
40
+ * most relevant docs page as "primary". Pure function, deterministic,
41
+ * unit-testable. Returns the classification AND the slug to elevate.
42
+ */
43
+ export declare function classifyContractAndPickDoc(surface: DeroScSurface, code: string): {
44
+ kind: ContractKind;
45
+ primarySlug: string;
46
+ };
47
+ export declare function explainSmartContract(rpc: DeroDaemonRpc, args: ExplainInput): Promise<{
48
+ scid: string;
49
+ topoheight: number | null;
50
+ kind: ContractKind;
51
+ surface: {
52
+ functions: import("./_shared.js").DvmFunctionSignature[];
53
+ stringkeys: string[];
54
+ uint64keys: string[];
55
+ balances: Record<string, string | number>;
56
+ };
57
+ narrative: string;
58
+ raw_code_length: number;
59
+ has_code: boolean;
60
+ } & {
61
+ related_docs?: import("../citations.js").DeroCitation[];
62
+ }>;
63
+ export {};
64
+ //# sourceMappingURL=explain-smart-contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explain-smart-contract.d.ts","sourceRoot":"","sources":["../../src/composites/explain-smart-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAGL,KAAK,aAAa,EAElB,KAAK,aAAa,EACnB,MAAM,cAAc,CAAA;AAIrB,eAAO,MAAM,+BAA+B;;;CAUlC,CAAA;AAEV,KAAK,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAWzD,KAAK,YAAY,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAA;AAEhE;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,aAAa,EACtB,IAAI,EAAE,MAAM,GACX;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CA6B7C;AA2CD,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,YAAY;;;;;;;;;;;;;;;GAmDhF"}
@@ -0,0 +1,149 @@
1
+ /**
2
+ * `explain_smart_contract` — Phase C composite #2.
3
+ *
4
+ * Wedge-defining composite. Today an agent calls `dero_get_sc`, gets a
5
+ * raw code blob with stringkeys/uint64keys/balances, and must know
6
+ * DVM-BASIC syntax to interpret it. This composite extracts the
7
+ * contract's function surface and stitches it to the right bundled DVM
8
+ * docs page — something no generic chain MCP can replicate because no
9
+ * other chain MCP ships the docs index in-process.
10
+ *
11
+ * Design contract: `docs/composites.md` § 2. Sequencing rule: SHIP
12
+ * SECOND — establishes the SC-introspection pattern (`extractScSurface`)
13
+ * that `trace_transaction_with_context` and `estimate_deploy_cost` reuse.
14
+ *
15
+ * Failure model:
16
+ * - `DERO.GetSC` failing entirely → handler throws so
17
+ * `withStructuredErrors` surfaces a structured error to the agent.
18
+ * - `DERO.GetSC` succeeds but returns no `code` → response carries
19
+ * `surface.has_code: false`, `functions: []`, narrative explains
20
+ * the SCID is unknown or has no on-chain code, and `_meta.error`
21
+ * style hint points at `dero_docs_search("smart contract")`.
22
+ * - Code present but `extractScSurface` finds zero functions →
23
+ * return surface with `functions: []` and a narrative noting
24
+ * parse-uncertainty. NEVER swallow the raw code; surface
25
+ * `raw_code_length` so the agent knows to fall back to `dero_get_sc`.
26
+ */
27
+ import { z } from 'zod';
28
+ import { attachCitations, extractScSurface, } from './_shared.js';
29
+ const SCID_HEX_REGEX = /^[0-9a-fA-F]{64}$/;
30
+ export const explainSmartContractInputSchema = {
31
+ scid: z
32
+ .string()
33
+ .regex(SCID_HEX_REGEX, 'Expected 64-character hex Smart Contract ID')
34
+ .describe('64-char hex Smart Contract ID'),
35
+ topoheight: z
36
+ .number()
37
+ .int()
38
+ .optional()
39
+ .describe('Optional topo height; omit for latest tip'),
40
+ };
41
+ // ---------------- Heuristic docs routing ----------------
42
+ //
43
+ // The four bundled DVM docs slugs we can route to. Validated by the
44
+ // citation CI guard via `RELATED_DOCS_BY_TOOL.explain_smart_contract`.
45
+ const DVM_DOC_FUNDAMENTALS = 'dvm/smart-contract-fundamentals';
46
+ const DVM_DOC_LANGUAGE = 'dvm/dvm-basic';
47
+ const DVM_DOC_DEPLOY = 'dvm/create-deploy-use-smart-contract';
48
+ const DVM_DOC_PLATFORM = 'dvm/dero-virtual-machine';
49
+ /**
50
+ * Classify a contract from its surface + raw code so we can pick the
51
+ * most relevant docs page as "primary". Pure function, deterministic,
52
+ * unit-testable. Returns the classification AND the slug to elevate.
53
+ */
54
+ export function classifyContractAndPickDoc(surface, code) {
55
+ const functionNames = new Set(surface.functions.map((f) => f.name.toLowerCase()));
56
+ const codeUpper = code.toUpperCase();
57
+ const looksLikeToken = codeUpper.includes('SEND_ASSET_TO_ADDRESS') ||
58
+ functionNames.has('mint') ||
59
+ functionNames.has('burn') ||
60
+ (functionNames.has('transfer') && functionNames.has('transferownership'));
61
+ if (looksLikeToken) {
62
+ return { kind: 'token', primarySlug: DVM_DOC_LANGUAGE };
63
+ }
64
+ const looksLikeRegistry = codeUpper.includes('EXISTS(') ||
65
+ functionNames.has('register') ||
66
+ functionNames.has('lookup') ||
67
+ functionNames.has('reserve');
68
+ if (looksLikeRegistry) {
69
+ return { kind: 'registry', primarySlug: DVM_DOC_FUNDAMENTALS };
70
+ }
71
+ if (surface.functions.length <= 1) {
72
+ return { kind: 'minimal', primarySlug: DVM_DOC_DEPLOY };
73
+ }
74
+ return { kind: 'generic', primarySlug: DVM_DOC_FUNDAMENTALS };
75
+ }
76
+ // ---------------- Narrative ----------------
77
+ //
78
+ // Lives next to the composite (not in `_shared.ts`) because the shape is
79
+ // tightly coupled to composite #2's response. Pure function for testability.
80
+ function buildNarrative(scid, topoheight, surface, kind) {
81
+ if (!surface.has_code) {
82
+ return `SCID ${scid} returned no on-chain code at topoheight ${topoheight ?? 'tip'}. Either the contract does not exist or it was deployed without code. Try dero_docs_search("smart contract") for installation context, or re-check the SCID.`;
83
+ }
84
+ const fnCount = surface.functions.length;
85
+ const stringCount = surface.stringkeys.length;
86
+ const uint64Count = surface.uint64keys.length;
87
+ const balanceCount = Object.keys(surface.balances).length;
88
+ if (fnCount === 0) {
89
+ return `Found ${surface.raw_code_length} bytes of code at SCID ${scid} (topoheight ${topoheight ?? 'tip'}) but no DVM-BASIC Function declarations were recognized by the parser. The raw code is still available via dero_get_sc; ${stringCount} stored string keys and ${uint64Count} uint64 keys are present, with ${balanceCount} asset balance(s).`;
90
+ }
91
+ const kindPhrase = {
92
+ token: 'has a token-style surface (transfer/asset operations)',
93
+ registry: 'has a registry-style surface (Register/Lookup/EXISTS pattern)',
94
+ minimal: 'is a minimal contract (Initialize-only or single function)',
95
+ generic: 'has a generic state-machine surface',
96
+ };
97
+ const fnList = surface.functions
98
+ .slice(0, 6)
99
+ .map((f) => (f.args.length > 0 ? `${f.name}(${f.args.length}-arg)` : `${f.name}()`))
100
+ .join(', ');
101
+ const more = fnCount > 6 ? ` (+${fnCount - 6} more)` : '';
102
+ return `SCID ${scid} at topoheight ${topoheight ?? 'tip'} ${kindPhrase[kind]}. Exposes ${fnCount} function${fnCount === 1 ? '' : 's'}: ${fnList}${more}. State carries ${stringCount} string key${stringCount === 1 ? '' : 's'} and ${uint64Count} uint64 key${uint64Count === 1 ? '' : 's'}, with ${balanceCount} asset balance entr${balanceCount === 1 ? 'y' : 'ies'}. See the cited docs page for the DVM concept that best matches this surface.`;
103
+ }
104
+ // ---------------- Handler ----------------
105
+ export async function explainSmartContract(rpc, args) {
106
+ const params = {
107
+ scid: args.scid,
108
+ code: true,
109
+ variables: true,
110
+ };
111
+ if (args.topoheight !== undefined)
112
+ params.topoheight = args.topoheight;
113
+ // Required call. Failure propagates through withStructuredErrors.
114
+ const raw = (await rpc('DERO.GetSC', params)) ?? {};
115
+ const surface = extractScSurface(raw);
116
+ const code = typeof raw.code === 'string' ? raw.code : '';
117
+ const { kind, primarySlug } = classifyContractAndPickDoc(surface, code);
118
+ const responseTopoheight = typeof args.topoheight === 'number' && Number.isFinite(args.topoheight)
119
+ ? args.topoheight
120
+ : null;
121
+ const narrative = buildNarrative(args.scid, responseTopoheight, surface, kind);
122
+ // Compose the payload, then attach static citations and re-order so the
123
+ // heuristic's pick is first. Static citation order (in RELATED_DOCS_BY_TOOL)
124
+ // ends up as the fallback order when the heuristic returns a slug already
125
+ // at position 0.
126
+ const payload = attachCitations({
127
+ scid: args.scid,
128
+ topoheight: responseTopoheight,
129
+ kind,
130
+ surface: {
131
+ functions: surface.functions,
132
+ stringkeys: surface.stringkeys,
133
+ uint64keys: surface.uint64keys,
134
+ balances: surface.balances,
135
+ },
136
+ narrative,
137
+ raw_code_length: surface.raw_code_length,
138
+ has_code: surface.has_code,
139
+ }, 'explain_smart_contract');
140
+ if (payload.related_docs && payload.related_docs.length > 0) {
141
+ const idx = payload.related_docs.findIndex((d) => d.slug === primarySlug);
142
+ if (idx > 0) {
143
+ const [picked] = payload.related_docs.splice(idx, 1);
144
+ payload.related_docs.unshift(picked);
145
+ }
146
+ }
147
+ return payload;
148
+ }
149
+ //# sourceMappingURL=explain-smart-contract.js.map