@caatinga/cli 0.2.4 → 2.0.1
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 +6 -7
- package/dist/index.js +198 -150
- package/package.json +3 -2
- package/templates/marketplace-with-token/caatinga.template.json +1 -1
- package/templates/marketplace-with-token/contracts/marketplace/test_snapshots/test/stores_token_contract_id_in_constructor.1.json +86 -0
- package/templates/marketplace-with-token/package.json +3 -3
- package/templates/react-vite-counter/README.md +18 -2
- package/templates/react-vite-counter/caatinga.template.json +1 -1
- package/templates/react-vite-counter/contracts/counter/src/lib.rs +70 -6
- package/templates/react-vite-counter/contracts/counter/test_snapshots/test/get_returns_zero_before_increment.1.json +76 -0
- package/templates/react-vite-counter/contracts/counter/test_snapshots/test/increment_returns_overflow_error.1.json +91 -0
- package/templates/react-vite-counter/contracts/counter/test_snapshots/test/increments_counter.1.json +91 -0
- package/templates/react-vite-counter/contracts/counter/test_snapshots/test/repeated_increments_preserve_state.1.json +92 -0
- package/templates/react-vite-counter/package.json +4 -5
- package/templates/react-vite-counter/pnpm-workspace.yaml +12 -0
- package/templates/react-vite-counter/src/App.tsx +26 -2
- package/templates/react-vite-counter/src/components/CounterCard.tsx +31 -6
- package/templates/react-vite-counter/src/components/LoadingModal.tsx +14 -0
- package/templates/react-vite-counter/src/components/WalletButton.tsx +3 -39
- package/templates/react-vite-counter/src/context/WalletContext.tsx +64 -0
- package/templates/react-vite-counter/src/contracts/generated/counter.ts +1 -1
- package/templates/react-vite-counter/src/stubs/hot-wallet.ts +14 -0
- package/templates/react-vite-counter/src/styles.css +51 -0
- package/templates/react-vite-counter/src/wallet.ts +3 -3
- package/templates/react-vite-counter/vite.config.ts +5 -6
- package/templates/react-vite-counter/src/hooks/useStellarWallet.ts +0 -70
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ Inside a generated project, prefer `npx caatinga` so the project-local workflow
|
|
|
14
14
|
## Requirements
|
|
15
15
|
|
|
16
16
|
- Node.js `>=20`
|
|
17
|
-
- [Stellar CLI](https://developers.stellar.org/docs/tools/developer-tools/cli/stellar-cli) `>=23.0.0`
|
|
17
|
+
- [Stellar CLI](https://developers.stellar.org/docs/tools/developer-tools/cli/stellar-cli) `>=23.0.0` on `PATH` (22.x breaks `caatinga invoke` signing)
|
|
18
18
|
- Rust 1.84.0 or newer with the `wasm32v1-none` target (contract builds)
|
|
19
19
|
- A funded Stellar CLI identity for `deploy` and `invoke` (for example `alice`)
|
|
20
20
|
|
|
@@ -23,7 +23,7 @@ rustup target add wasm32v1-none
|
|
|
23
23
|
stellar keys generate alice --fund --network testnet
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
Stellar CLI versions newer than the last-tested `25.2.0` are accepted with a non-fatal stderr advisory and a `caatinga doctor` warning; no override flag is required.
|
|
27
27
|
|
|
28
28
|
## Quick start
|
|
29
29
|
|
|
@@ -31,6 +31,7 @@ If your machine runs a newer Stellar CLI, `--allow-untested-stellar-cli` is the
|
|
|
31
31
|
caatinga init my-dapp
|
|
32
32
|
cd my-dapp
|
|
33
33
|
npm install
|
|
34
|
+
# pnpm alternative: pnpm install (template includes pnpm-workspace.yaml for pnpm 10.26+/11)
|
|
34
35
|
|
|
35
36
|
npx caatinga build counter
|
|
36
37
|
npx caatinga deploy counter --network testnet --source alice
|
|
@@ -38,7 +39,7 @@ npx caatinga generate counter --network testnet
|
|
|
38
39
|
npx caatinga invoke counter.increment --network testnet --source alice
|
|
39
40
|
```
|
|
40
41
|
|
|
41
|
-
`deploy` writes contract IDs to `caatinga.artifacts.json
|
|
42
|
+
`build` only compiles the WASM file. `deploy` writes contract IDs to `caatinga.artifacts.json`, and the frontend/client flow needs those IDs before it can resolve a contract. `generate` creates TypeScript bindings under the path configured in `caatinga.config.ts` (templates default to `contracts/generated/`).
|
|
42
43
|
|
|
43
44
|
## Commands
|
|
44
45
|
|
|
@@ -62,7 +63,7 @@ The supported CLI flow is `init -> build -> deploy -> generate -> invoke`.
|
|
|
62
63
|
### `build`
|
|
63
64
|
|
|
64
65
|
- `[contract]` defaults to `counter` when omitted
|
|
65
|
-
-
|
|
66
|
+
- prints a deploy reminder when the default network lacks a `contractId` in `caatinga.artifacts.json`; this warning does not fail the build
|
|
66
67
|
|
|
67
68
|
### `doctor`
|
|
68
69
|
|
|
@@ -77,7 +78,6 @@ The supported CLI flow is `init -> build -> deploy -> generate -> invoke`.
|
|
|
77
78
|
- `-s, --source <identity>` is required; must be a Stellar CLI identity alias that can sign (for example `alice`)
|
|
78
79
|
- `--force` redeploys even when artifacts already store a contract ID
|
|
79
80
|
- `--no-deps` skips dependency deployment for a single named contract (`--no-deps` requires `[contract]`)
|
|
80
|
-
- `--allow-untested-stellar-cli` for local experiments only
|
|
81
81
|
|
|
82
82
|
Dependencies listed in `dependsOn` deploy first unless `--no-deps` is set. Deploy args may reference `${contracts.<name>.contractId}` placeholders resolved from artifacts.
|
|
83
83
|
|
|
@@ -85,7 +85,6 @@ Dependencies listed in `dependsOn` deploy first unless `--no-deps` is set. Deplo
|
|
|
85
85
|
|
|
86
86
|
- `-n, --network <network>` selects the network used to resolve deployed contract IDs
|
|
87
87
|
- `invoke` expects `<contract.method>` (for example `counter.increment`) and forwards `[args...]` to the underlying Stellar invocation
|
|
88
|
-
- Both accept `--allow-untested-stellar-cli` for local experiments only
|
|
89
88
|
|
|
90
89
|
`caatinga dev` is reserved, hidden in pre-v1 builds, and not part of the stability promise. Use your frontend dev server (for example Vite) alongside the commands above.
|
|
91
90
|
|
|
@@ -107,7 +106,7 @@ Unsupported input posture:
|
|
|
107
106
|
Common codes:
|
|
108
107
|
|
|
109
108
|
- `CAATINGA_CONFIG_NOT_FOUND`, `CAATINGA_INVALID_CONFIG`
|
|
110
|
-
- `CAATINGA_STELLAR_CLI_NOT_FOUND`, `CAATINGA_UNSUPPORTED_CLI_VERSION
|
|
109
|
+
- `CAATINGA_STELLAR_CLI_NOT_FOUND`, `CAATINGA_UNSUPPORTED_CLI_VERSION`
|
|
111
110
|
- `CAATINGA_BUILD_FAILED`, `CAATINGA_DEPLOY_FAILED`, `CAATINGA_BINDINGS_FAILED`, `CAATINGA_INVOKE_FAILED`
|
|
112
111
|
- `CAATINGA_CONTRACT_ID_NOT_FOUND`, `CAATINGA_SOURCE_ACCOUNT_REQUIRED`, `CAATINGA_UNSAFE_SOURCE_ACCOUNT`
|
|
113
112
|
- `CAATINGA_CONTRACT_DEPENDENCY_NOT_FOUND`, `CAATINGA_CONTRACT_DEPENDENCY_CYCLE`
|
package/dist/index.js
CHANGED
|
@@ -2,21 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
// src/utils/preflight.ts
|
|
4
4
|
import chalk from "chalk";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
import { NODE_MIN_MAJOR as NODE_MIN_MAJOR2 } from "@caatinga/core/runtime/requirements";
|
|
6
|
+
|
|
7
|
+
// src/diagnostics/node-diagnostic.ts
|
|
8
|
+
import { NODE_MIN_MAJOR } from "@caatinga/core/runtime/requirements";
|
|
9
|
+
function nodeDiagnostic() {
|
|
10
|
+
const version = process.versions.node;
|
|
11
|
+
const major = Number.parseInt(version.split(".")[0] ?? "0", 10);
|
|
8
12
|
if (major < NODE_MIN_MAJOR) {
|
|
9
|
-
return
|
|
10
|
-
|
|
13
|
+
return {
|
|
14
|
+
ok: false,
|
|
15
|
+
label: `Node.js ${version} is below the required minimum ${NODE_MIN_MAJOR}.0.0`,
|
|
16
|
+
fix: `Install Node.js ${NODE_MIN_MAJOR} or newer.`
|
|
17
|
+
};
|
|
11
18
|
}
|
|
12
|
-
return
|
|
19
|
+
return { ok: true, label: `Node.js ${version}` };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// src/utils/preflight.ts
|
|
23
|
+
function formatNodePreflightFailure() {
|
|
24
|
+
const version = process.versions.node;
|
|
25
|
+
return `Node.js ${version} is below the required minimum v${NODE_MIN_MAJOR2}.
|
|
26
|
+
Install Node.js ${NODE_MIN_MAJOR2} or newer: https://nodejs.org/`;
|
|
13
27
|
}
|
|
14
28
|
function runPreflight() {
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (failures.length > 0) return { ok: false, failures };
|
|
19
|
-
return { ok: true };
|
|
29
|
+
const diagnostic = nodeDiagnostic();
|
|
30
|
+
if (diagnostic.ok) return { ok: true };
|
|
31
|
+
return { ok: false, failures: [formatNodePreflightFailure()] };
|
|
20
32
|
}
|
|
21
33
|
function assertPreflight() {
|
|
22
34
|
const result = runPreflight();
|
|
@@ -33,7 +45,7 @@ function assertPreflight() {
|
|
|
33
45
|
import { Command } from "commander";
|
|
34
46
|
|
|
35
47
|
// src/commands/build.command.ts
|
|
36
|
-
import { buildContract, loadConfig } from "@caatinga/core";
|
|
48
|
+
import { buildContract, CaatingaError, CaatingaErrorCode, loadConfig as loadConfig2 } from "@caatinga/core";
|
|
37
49
|
|
|
38
50
|
// src/utils/errors.ts
|
|
39
51
|
import chalk2 from "chalk";
|
|
@@ -84,34 +96,82 @@ var logger = {
|
|
|
84
96
|
}
|
|
85
97
|
};
|
|
86
98
|
|
|
99
|
+
// src/commands/doctor-deploy-coverage.ts
|
|
100
|
+
import { loadConfig, readArtifacts, resolveNetwork } from "@caatinga/core";
|
|
101
|
+
async function evaluateDeployCoverage(options) {
|
|
102
|
+
const cwd = options.cwd;
|
|
103
|
+
const config = await loadConfig({ cwd });
|
|
104
|
+
const network = resolveNetwork(config, options.networkName);
|
|
105
|
+
const artifacts = await readArtifacts(cwd);
|
|
106
|
+
const lines = [];
|
|
107
|
+
for (const name of Object.keys(config.contracts)) {
|
|
108
|
+
const contractId = artifacts.networks[network.name]?.contracts[name]?.contractId;
|
|
109
|
+
if (contractId) {
|
|
110
|
+
lines.push({ name, ok: true, contractId });
|
|
111
|
+
} else {
|
|
112
|
+
lines.push({
|
|
113
|
+
name,
|
|
114
|
+
ok: false,
|
|
115
|
+
fix: `Run: caatinga deploy ${name} --network ${network.name} --source <identity>`
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return { lines, complete: lines.every((line) => line.ok) };
|
|
120
|
+
}
|
|
121
|
+
|
|
87
122
|
// src/commands/build.command.ts
|
|
88
123
|
function registerBuildCommand(program2) {
|
|
89
|
-
program2.command("build").description("Build a configured Soroban contract").argument("[contract]", "Contract name", "counter").
|
|
90
|
-
const config = await
|
|
124
|
+
program2.command("build").description("Build a configured Soroban contract").argument("[contract]", "Contract name", "counter").action((contractName) => runCliAction(async () => {
|
|
125
|
+
const config = await loadConfig2();
|
|
91
126
|
const result = await buildContract({
|
|
92
127
|
config,
|
|
93
|
-
contractName
|
|
94
|
-
allowUntestedStellarCli: options.allowUntestedStellarCli === true
|
|
128
|
+
contractName
|
|
95
129
|
});
|
|
96
130
|
logger.success("Contract built");
|
|
97
131
|
logger.info("");
|
|
98
132
|
logger.info(`Contract: ${result.contract.name}`);
|
|
99
133
|
logger.info(`WASM: ${result.contract.config.wasm}`);
|
|
134
|
+
await warnIfDefaultNetworkNeedsDeploy(config);
|
|
100
135
|
}));
|
|
101
136
|
}
|
|
137
|
+
async function warnIfDefaultNetworkNeedsDeploy(config) {
|
|
138
|
+
let missingDeployCommands;
|
|
139
|
+
try {
|
|
140
|
+
const coverage = await evaluateDeployCoverage({ networkName: config.defaultNetwork });
|
|
141
|
+
if (coverage.complete) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
missingDeployCommands = coverage.lines.filter((line) => !line.ok).map((line) => line.fix?.replace(/^Run: /, "")).filter((fix) => Boolean(fix));
|
|
145
|
+
} catch (error) {
|
|
146
|
+
if (!(error instanceof CaatingaError) || error.code !== CaatingaErrorCode.ARTIFACT_NOT_FOUND) {
|
|
147
|
+
throw error;
|
|
148
|
+
}
|
|
149
|
+
missingDeployCommands = Object.keys(config.contracts).map(
|
|
150
|
+
(name) => `caatinga deploy ${name} --network ${config.defaultNetwork} --source <identity>`
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
if (missingDeployCommands.length === 0) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
logger.warn("");
|
|
157
|
+
for (const command of missingDeployCommands) {
|
|
158
|
+
logger.warn(`Next: ${command}`);
|
|
159
|
+
}
|
|
160
|
+
logger.warn("The frontend needs contractId in caatinga.artifacts.json; build alone is not enough.");
|
|
161
|
+
}
|
|
102
162
|
|
|
103
163
|
// src/commands/deploy.command.ts
|
|
104
|
-
import { deployContractGraph, CaatingaError, CaatingaErrorCode, loadConfig as
|
|
164
|
+
import { deployContractGraph, CaatingaError as CaatingaError2, CaatingaErrorCode as CaatingaErrorCode2, loadConfig as loadConfig3 } from "@caatinga/core";
|
|
105
165
|
function registerDeployCommand(program2) {
|
|
106
|
-
program2.command("deploy").description("Deploy one or all configured Soroban contracts").argument("[contract]", "Contract name").option("-n, --network <network>", "Configured network name").requiredOption("-s, --source <source>", "Stellar CLI identity alias that can sign (for example alice)").option("--force", "Redeploy contracts even if artifacts already contain contract IDs").option("--no-deps", "Do not deploy missing dependencies for a selected contract").option("--no-stale-check", "Do not warn when WASM may be older than contract sources").option("--
|
|
166
|
+
program2.command("deploy").description("Deploy one or all configured Soroban contracts").argument("[contract]", "Contract name").option("-n, --network <network>", "Configured network name").requiredOption("-s, --source <source>", "Stellar CLI identity alias that can sign (for example alice)").option("--force", "Redeploy contracts even if artifacts already contain contract IDs").option("--no-deps", "Do not deploy missing dependencies for a selected contract").option("--no-stale-check", "Do not warn when WASM may be older than contract sources").option("--verify-deps", "Verify dependency contract IDs exist on-chain before deploy").action((contractName, options) => runCliAction(async () => {
|
|
107
167
|
if (options.deps === false && !contractName) {
|
|
108
|
-
throw new
|
|
168
|
+
throw new CaatingaError2(
|
|
109
169
|
"`--no-deps` requires a contract name.",
|
|
110
|
-
|
|
170
|
+
CaatingaErrorCode2.INVALID_CONFIG,
|
|
111
171
|
"Select a single contract or omit `--no-deps` to deploy the full graph."
|
|
112
172
|
);
|
|
113
173
|
}
|
|
114
|
-
const config = await
|
|
174
|
+
const config = await loadConfig3();
|
|
115
175
|
const result = await deployContractGraph({
|
|
116
176
|
config,
|
|
117
177
|
contractName,
|
|
@@ -120,8 +180,7 @@ function registerDeployCommand(program2) {
|
|
|
120
180
|
includeDependencies: options.deps !== false,
|
|
121
181
|
force: options.force === true,
|
|
122
182
|
checkStaleWasm: options.staleCheck !== false,
|
|
123
|
-
verifyDeps: options.verifyDeps === true
|
|
124
|
-
allowUntestedStellarCli: options.allowUntestedStellarCli === true
|
|
183
|
+
verifyDeps: options.verifyDeps === true
|
|
125
184
|
});
|
|
126
185
|
for (const warning of result.staleWasmWarnings) {
|
|
127
186
|
logger.warn(warning.message);
|
|
@@ -154,76 +213,56 @@ function registerDevCommand(program2) {
|
|
|
154
213
|
}
|
|
155
214
|
|
|
156
215
|
// src/commands/doctor.command.ts
|
|
157
|
-
import {
|
|
158
|
-
import {
|
|
159
|
-
assertSupportedStellarCliVersion,
|
|
160
|
-
CaatingaError as CaatingaError2,
|
|
161
|
-
CaatingaErrorCode as CaatingaErrorCode2,
|
|
162
|
-
loadConfig as loadConfig4,
|
|
163
|
-
parseStellarCliVersion,
|
|
164
|
-
readArtifacts as readArtifacts2,
|
|
165
|
-
resolveNetwork as resolveNetwork2,
|
|
166
|
-
runCommand,
|
|
167
|
-
validateSourceShape
|
|
168
|
-
} from "@caatinga/core";
|
|
216
|
+
import { CaatingaError as CaatingaError5, CaatingaErrorCode as CaatingaErrorCode3 } from "@caatinga/core";
|
|
169
217
|
|
|
170
|
-
// src/
|
|
171
|
-
import {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
name,
|
|
185
|
-
ok: false,
|
|
186
|
-
fix: `Run: caatinga deploy ${name} --network ${network.name}`
|
|
187
|
-
});
|
|
188
|
-
}
|
|
218
|
+
// src/diagnostics/project-diagnostic.ts
|
|
219
|
+
import { access } from "fs/promises";
|
|
220
|
+
import { CaatingaError as CaatingaError3, loadConfig as loadConfig4, readArtifacts as readArtifacts2, resolveNetwork as resolveNetwork2 } from "@caatinga/core";
|
|
221
|
+
async function configDiagnostic() {
|
|
222
|
+
try {
|
|
223
|
+
await loadConfig4();
|
|
224
|
+
return { ok: true, label: "caatinga.config.ts found" };
|
|
225
|
+
} catch (error) {
|
|
226
|
+
const hint = error instanceof CaatingaError3 ? error.hint : void 0;
|
|
227
|
+
return {
|
|
228
|
+
ok: false,
|
|
229
|
+
label: "caatinga.config.ts not ready",
|
|
230
|
+
fix: hint ?? "Run this command from a Caatinga project root."
|
|
231
|
+
};
|
|
189
232
|
}
|
|
190
|
-
return { lines, complete: lines.every((line) => line.ok) };
|
|
191
233
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const major = Number.parseInt(version.split(".")[0] ?? "0", 10);
|
|
199
|
-
if (major < NODE_MIN_MAJOR2) {
|
|
234
|
+
async function artifactsDiagnostic() {
|
|
235
|
+
try {
|
|
236
|
+
await access("caatinga.artifacts.json");
|
|
237
|
+
await readArtifacts2();
|
|
238
|
+
return { ok: true, label: "caatinga.artifacts.json found" };
|
|
239
|
+
} catch {
|
|
200
240
|
return {
|
|
201
241
|
ok: false,
|
|
202
|
-
label:
|
|
203
|
-
fix:
|
|
242
|
+
label: "caatinga.artifacts.json not found or invalid",
|
|
243
|
+
fix: "Run caatinga init, or restore a valid caatinga.artifacts.json file."
|
|
204
244
|
};
|
|
205
245
|
}
|
|
206
|
-
return { ok: true, label: `Node.js ${version}` };
|
|
207
246
|
}
|
|
208
|
-
async function
|
|
247
|
+
async function networkDiagnostic(networkName) {
|
|
248
|
+
if (!networkName) return void 0;
|
|
209
249
|
try {
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
const version = assertSupportedStellarCliVersion({
|
|
214
|
-
version: parseStellarCliVersion(result.all || result.stdout || result.stderr),
|
|
215
|
-
allowUntested
|
|
216
|
-
});
|
|
217
|
-
return { ok: true, label: `Stellar CLI ${version}` };
|
|
250
|
+
const config = await loadConfig4();
|
|
251
|
+
const network = resolveNetwork2(config, networkName);
|
|
252
|
+
return { ok: true, label: `network ${network.name} found` };
|
|
218
253
|
} catch (error) {
|
|
219
|
-
const hint = error instanceof
|
|
254
|
+
const hint = error instanceof CaatingaError3 ? error.hint : void 0;
|
|
220
255
|
return {
|
|
221
256
|
ok: false,
|
|
222
|
-
label:
|
|
223
|
-
fix: hint ?? "
|
|
257
|
+
label: `network ${networkName} not found`,
|
|
258
|
+
fix: hint ?? `Add "${networkName}" to caatinga.config.ts networks.`
|
|
224
259
|
};
|
|
225
260
|
}
|
|
226
261
|
}
|
|
262
|
+
|
|
263
|
+
// src/diagnostics/rust-diagnostic.ts
|
|
264
|
+
import { CURRENT_RUST_WASM_TARGET } from "@caatinga/core/runtime/requirements";
|
|
265
|
+
import { runCommand } from "@caatinga/core";
|
|
227
266
|
async function rustDiagnostic() {
|
|
228
267
|
try {
|
|
229
268
|
const result = await runCommand("rustc", ["--version"]);
|
|
@@ -232,7 +271,7 @@ async function rustDiagnostic() {
|
|
|
232
271
|
return {
|
|
233
272
|
ok: false,
|
|
234
273
|
label: "Rust not found",
|
|
235
|
-
fix:
|
|
274
|
+
fix: `Install Rust, then run: rustup target add ${CURRENT_RUST_WASM_TARGET}`
|
|
236
275
|
};
|
|
237
276
|
}
|
|
238
277
|
}
|
|
@@ -240,63 +279,25 @@ async function wasmTargetDiagnostic() {
|
|
|
240
279
|
try {
|
|
241
280
|
const result = await runCommand("rustup", ["target", "list", "--installed"]);
|
|
242
281
|
const installedTargets = result.stdout || result.all;
|
|
243
|
-
if (installedTargets.split(/\r?\n/).includes(
|
|
244
|
-
return { ok: true, label: `${
|
|
282
|
+
if (installedTargets.split(/\r?\n/).includes(CURRENT_RUST_WASM_TARGET)) {
|
|
283
|
+
return { ok: true, label: `${CURRENT_RUST_WASM_TARGET} target installed` };
|
|
245
284
|
}
|
|
246
285
|
return {
|
|
247
286
|
ok: false,
|
|
248
|
-
label: `${
|
|
249
|
-
fix: `Run: rustup target add ${
|
|
287
|
+
label: `${CURRENT_RUST_WASM_TARGET} target not installed`,
|
|
288
|
+
fix: `Run: rustup target add ${CURRENT_RUST_WASM_TARGET}`
|
|
250
289
|
};
|
|
251
290
|
} catch {
|
|
252
291
|
return {
|
|
253
292
|
ok: false,
|
|
254
293
|
label: "rustup not found",
|
|
255
|
-
fix:
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
async function configDiagnostic() {
|
|
260
|
-
try {
|
|
261
|
-
await loadConfig4();
|
|
262
|
-
return { ok: true, label: "caatinga.config.ts found" };
|
|
263
|
-
} catch (error) {
|
|
264
|
-
const hint = error instanceof CaatingaError2 ? error.hint : void 0;
|
|
265
|
-
return {
|
|
266
|
-
ok: false,
|
|
267
|
-
label: "caatinga.config.ts not ready",
|
|
268
|
-
fix: hint ?? "Run this command from a Caatinga project root."
|
|
269
|
-
};
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
async function artifactsDiagnostic() {
|
|
273
|
-
try {
|
|
274
|
-
await access("caatinga.artifacts.json");
|
|
275
|
-
await readArtifacts2();
|
|
276
|
-
return { ok: true, label: "caatinga.artifacts.json found" };
|
|
277
|
-
} catch {
|
|
278
|
-
return {
|
|
279
|
-
ok: false,
|
|
280
|
-
label: "caatinga.artifacts.json not found or invalid",
|
|
281
|
-
fix: "Run caatinga init, or restore a valid caatinga.artifacts.json file."
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
async function networkDiagnostic(networkName) {
|
|
286
|
-
if (!networkName) return void 0;
|
|
287
|
-
try {
|
|
288
|
-
const config = await loadConfig4();
|
|
289
|
-
const network = resolveNetwork2(config, networkName);
|
|
290
|
-
return { ok: true, label: `network ${network.name} found` };
|
|
291
|
-
} catch (error) {
|
|
292
|
-
const hint = error instanceof CaatingaError2 ? error.hint : void 0;
|
|
293
|
-
return {
|
|
294
|
-
ok: false,
|
|
295
|
-
label: `network ${networkName} not found`,
|
|
296
|
-
fix: hint ?? `Add "${networkName}" to caatinga.config.ts networks.`
|
|
294
|
+
fix: `Install rustup, then run: rustup target add ${CURRENT_RUST_WASM_TARGET}`
|
|
297
295
|
};
|
|
298
296
|
}
|
|
299
297
|
}
|
|
298
|
+
|
|
299
|
+
// src/diagnostics/source-diagnostic.ts
|
|
300
|
+
import { runCommand as runCommand2, validateSourceShape } from "@caatinga/core";
|
|
300
301
|
async function sourceDiagnostic(source) {
|
|
301
302
|
if (!source) return void 0;
|
|
302
303
|
const unsafeSource = validateSourceShape(source);
|
|
@@ -308,7 +309,7 @@ async function sourceDiagnostic(source) {
|
|
|
308
309
|
};
|
|
309
310
|
}
|
|
310
311
|
try {
|
|
311
|
-
await
|
|
312
|
+
await runCommand2("stellar", ["keys", "public-key", source]);
|
|
312
313
|
return { ok: true, label: `source identity ${source} found` };
|
|
313
314
|
} catch {
|
|
314
315
|
return {
|
|
@@ -318,8 +319,64 @@ async function sourceDiagnostic(source) {
|
|
|
318
319
|
};
|
|
319
320
|
}
|
|
320
321
|
}
|
|
322
|
+
|
|
323
|
+
// src/diagnostics/stellar-diagnostic.ts
|
|
324
|
+
import {
|
|
325
|
+
CaatingaError as CaatingaError4,
|
|
326
|
+
checkStellarCliVersion
|
|
327
|
+
} from "@caatinga/core";
|
|
328
|
+
async function stellarDiagnostic() {
|
|
329
|
+
const warnings = [];
|
|
330
|
+
try {
|
|
331
|
+
const report = await checkStellarCliVersion({
|
|
332
|
+
onWarning: (warning) => {
|
|
333
|
+
warnings.push({ code: warning.code, message: warning.message });
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
return {
|
|
337
|
+
ok: true,
|
|
338
|
+
label: `Stellar CLI ${report.version}`,
|
|
339
|
+
warnings: warnings.length > 0 ? warnings : void 0
|
|
340
|
+
};
|
|
341
|
+
} catch (error) {
|
|
342
|
+
if (error instanceof CaatingaError4) {
|
|
343
|
+
return {
|
|
344
|
+
ok: false,
|
|
345
|
+
label: "Stellar CLI not ready",
|
|
346
|
+
fix: error.hint ?? "Install Stellar CLI: cargo install --locked stellar-cli --version 25.2.0"
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
logger.error(String(error));
|
|
350
|
+
return {
|
|
351
|
+
ok: false,
|
|
352
|
+
label: "Stellar CLI not ready",
|
|
353
|
+
fix: "Install Stellar CLI: cargo install --locked stellar-cli --version 25.2.0"
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// src/diagnostics/run-all.ts
|
|
359
|
+
async function runAllDiagnostics(options) {
|
|
360
|
+
return [
|
|
361
|
+
nodeDiagnostic(),
|
|
362
|
+
await stellarDiagnostic(),
|
|
363
|
+
await rustDiagnostic(),
|
|
364
|
+
await wasmTargetDiagnostic(),
|
|
365
|
+
await configDiagnostic(),
|
|
366
|
+
await artifactsDiagnostic(),
|
|
367
|
+
await networkDiagnostic(options.network),
|
|
368
|
+
await sourceDiagnostic(options.source)
|
|
369
|
+
].filter((diagnostic) => diagnostic !== void 0);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// src/diagnostics/types.ts
|
|
321
373
|
function printDiagnostic(diagnostic) {
|
|
322
|
-
|
|
374
|
+
const warnings = diagnostic.warnings ?? [];
|
|
375
|
+
const suffix = warnings.length > 0 ? ` (${warnings.length} warning${warnings.length === 1 ? "" : "s"})` : "";
|
|
376
|
+
logger.info(`${diagnostic.ok ? "\u2713" : "\u2717"} ${diagnostic.label}${suffix}`);
|
|
377
|
+
for (const warning of warnings) {
|
|
378
|
+
logger.info(` ! ${warning.code}: ${warning.message}`);
|
|
379
|
+
}
|
|
323
380
|
}
|
|
324
381
|
function printFixes(diagnostics) {
|
|
325
382
|
const failures = diagnostics.filter((diagnostic) => !diagnostic.ok);
|
|
@@ -330,6 +387,8 @@ function printFixes(diagnostics) {
|
|
|
330
387
|
if (failure.fix) logger.info(failure.fix);
|
|
331
388
|
}
|
|
332
389
|
}
|
|
390
|
+
|
|
391
|
+
// src/commands/doctor.command.ts
|
|
333
392
|
function printDeployCoverageLine(line) {
|
|
334
393
|
if (line.ok) {
|
|
335
394
|
logger.info(`\u2713 ${line.name} \u2014 ${line.contractId}`);
|
|
@@ -347,28 +406,19 @@ async function reportDeployCoverage(networkName) {
|
|
|
347
406
|
}
|
|
348
407
|
if (!coverage.complete) {
|
|
349
408
|
const missing = coverage.lines.filter((line) => !line.ok).map((line) => line.name);
|
|
350
|
-
throw new
|
|
409
|
+
throw new CaatingaError5(
|
|
351
410
|
`Not all configured contracts are deployed on ${networkName}.`,
|
|
352
|
-
|
|
411
|
+
CaatingaErrorCode3.DOCTOR_PARTIAL_DEPLOY,
|
|
353
412
|
`Deploy missing contracts: ${missing.join(", ")}. See the commands above.`
|
|
354
413
|
);
|
|
355
414
|
}
|
|
356
415
|
return true;
|
|
357
416
|
}
|
|
358
417
|
function registerDoctorCommand(program2) {
|
|
359
|
-
program2.command("doctor").description("Check local Caatinga, Stellar CLI, Rust, config, and source identity setup").option("-n, --network <network>", "Configured network name to validate").option("-s, --source <source>", "Stellar CLI identity alias to validate").
|
|
418
|
+
program2.command("doctor").description("Check local Caatinga, Stellar CLI, Rust, config, and source identity setup").option("-n, --network <network>", "Configured network name to validate").option("-s, --source <source>", "Stellar CLI identity alias to validate").action((options) => runCliAction(async () => {
|
|
360
419
|
logger.info("Caatinga Doctor");
|
|
361
420
|
logger.info("");
|
|
362
|
-
const diagnostics =
|
|
363
|
-
nodeDiagnostic(),
|
|
364
|
-
await stellarDiagnostic(options.allowUntestedStellarCli === true),
|
|
365
|
-
await rustDiagnostic(),
|
|
366
|
-
await wasmTargetDiagnostic(),
|
|
367
|
-
await configDiagnostic(),
|
|
368
|
-
await artifactsDiagnostic(),
|
|
369
|
-
await networkDiagnostic(options.network),
|
|
370
|
-
await sourceDiagnostic(options.source)
|
|
371
|
-
].filter((diagnostic) => diagnostic !== void 0);
|
|
421
|
+
const diagnostics = await runAllDiagnostics(options);
|
|
372
422
|
for (const diagnostic of diagnostics) {
|
|
373
423
|
printDiagnostic(diagnostic);
|
|
374
424
|
}
|
|
@@ -393,13 +443,12 @@ function registerDoctorCommand(program2) {
|
|
|
393
443
|
// src/commands/generate.command.ts
|
|
394
444
|
import { generateBindings, loadConfig as loadConfig5 } from "@caatinga/core";
|
|
395
445
|
function registerGenerateCommand(program2) {
|
|
396
|
-
program2.command("generate").description("Generate TypeScript bindings for a deployed contract").argument("<contract>", "Contract name").option("-n, --network <network>", "Configured network name").
|
|
446
|
+
program2.command("generate").description("Generate TypeScript bindings for a deployed contract").argument("<contract>", "Contract name").option("-n, --network <network>", "Configured network name").action((contractName, options) => runCliAction(async () => {
|
|
397
447
|
const config = await loadConfig5();
|
|
398
448
|
const result = await generateBindings({
|
|
399
449
|
config,
|
|
400
450
|
contractName,
|
|
401
|
-
networkName: options.network
|
|
402
|
-
allowUntestedStellarCli: options.allowUntestedStellarCli === true
|
|
451
|
+
networkName: options.network
|
|
403
452
|
});
|
|
404
453
|
logger.success("Client generated");
|
|
405
454
|
logger.info("");
|
|
@@ -417,7 +466,7 @@ import { createProjectFromTemplate } from "@caatinga/core";
|
|
|
417
466
|
import { access as access2 } from "fs/promises";
|
|
418
467
|
import path from "path";
|
|
419
468
|
import { fileURLToPath } from "url";
|
|
420
|
-
import { CaatingaError as
|
|
469
|
+
import { CaatingaError as CaatingaError6, CaatingaErrorCode as CaatingaErrorCode4 } from "@caatinga/core";
|
|
421
470
|
async function resolveTemplateDir(templateName) {
|
|
422
471
|
const candidates = buildTemplateCandidates(templateName);
|
|
423
472
|
if (process.env.CAATINGA_DEBUG_TEMPLATE_RESOLUTION === "1") {
|
|
@@ -439,9 +488,9 @@ async function resolveTemplateDir(templateName) {
|
|
|
439
488
|
} catch {
|
|
440
489
|
}
|
|
441
490
|
}
|
|
442
|
-
throw new
|
|
491
|
+
throw new CaatingaError6(
|
|
443
492
|
`Template "${templateName}" was not found.`,
|
|
444
|
-
|
|
493
|
+
CaatingaErrorCode4.TEMPLATE_NOT_FOUND,
|
|
445
494
|
"Set CAATINGA_TEMPLATES_DIR, run `pnpm build` before `pnpm pack`, or run from a Caatinga checkout that includes packages/templates."
|
|
446
495
|
);
|
|
447
496
|
}
|
|
@@ -498,15 +547,14 @@ function registerInitCommand(program2) {
|
|
|
498
547
|
// src/commands/invoke.command.ts
|
|
499
548
|
import { invokeContract, loadConfig as loadConfig6 } from "@caatinga/core";
|
|
500
549
|
function registerInvokeCommand(program2) {
|
|
501
|
-
program2.command("invoke").description("Invoke a deployed contract function").argument("<target>", "Invoke target in contract.method format").argument("[args...]", "Arguments forwarded to Stellar CLI after the method name").option("-n, --network <network>", "Configured network name").requiredOption("-s, --source <source>", "Stellar CLI identity alias that can sign (for example alice)").
|
|
550
|
+
program2.command("invoke").description("Invoke a deployed contract function").argument("<target>", "Invoke target in contract.method format").argument("[args...]", "Arguments forwarded to Stellar CLI after the method name").option("-n, --network <network>", "Configured network name").requiredOption("-s, --source <source>", "Stellar CLI identity alias that can sign (for example alice)").allowUnknownOption(true).allowExcessArguments(true).action((target, args, options) => runCliAction(async () => {
|
|
502
551
|
const config = await loadConfig6();
|
|
503
552
|
const result = await invokeContract({
|
|
504
553
|
config,
|
|
505
554
|
target,
|
|
506
555
|
args,
|
|
507
556
|
networkName: options.network,
|
|
508
|
-
source: options.source
|
|
509
|
-
allowUntestedStellarCli: options.allowUntestedStellarCli === true
|
|
557
|
+
source: options.source
|
|
510
558
|
});
|
|
511
559
|
logger.success("Invoke complete");
|
|
512
560
|
logger.info("");
|
|
@@ -521,7 +569,7 @@ function registerInvokeCommand(program2) {
|
|
|
521
569
|
}
|
|
522
570
|
|
|
523
571
|
// src/version.ts
|
|
524
|
-
var CAATINGA_CLI_VERSION = "0.
|
|
572
|
+
var CAATINGA_CLI_VERSION = "2.0.1";
|
|
525
573
|
|
|
526
574
|
// src/program.ts
|
|
527
575
|
function createProgram() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@caatinga/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Caatinga CLI for building dApps on Stellar/Soroban",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"stellar",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"LICENSE"
|
|
44
44
|
],
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@caatinga/core": "^0.
|
|
46
|
+
"@caatinga/core": "^2.0.1",
|
|
47
47
|
"chalk": "^5.4.1",
|
|
48
48
|
"commander": "^12.1.0"
|
|
49
49
|
},
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
},
|
|
56
56
|
"scripts": {
|
|
57
57
|
"build": "tsup src/index.ts --format esm --dts --clean && rm -rf ./templates && cp -r ../templates ./templates",
|
|
58
|
+
"predev": "pnpm --filter @caatinga/core build",
|
|
58
59
|
"dev": "tsx src/index.ts",
|
|
59
60
|
"test": "vitest run --pool=threads",
|
|
60
61
|
"typecheck": "tsc --noEmit"
|