@caatinga/cli 0.2.0 → 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 (34) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +101 -34
  3. package/dist/index.js +326 -39
  4. package/package.json +2 -2
  5. package/templates/marketplace-with-token/README.md +4 -2
  6. package/templates/marketplace-with-token/caatinga.config.ts +2 -2
  7. package/templates/marketplace-with-token/caatinga.template.json +1 -1
  8. package/templates/marketplace-with-token/contracts/marketplace/Cargo.lock +1731 -0
  9. package/templates/marketplace-with-token/contracts/marketplace/Cargo.toml +1 -0
  10. package/templates/marketplace-with-token/contracts/marketplace/src/lib.rs +31 -1
  11. package/templates/marketplace-with-token/contracts/token/Cargo.lock +1731 -0
  12. package/templates/marketplace-with-token/contracts/token/Cargo.toml +1 -0
  13. package/templates/marketplace-with-token/index.html +12 -0
  14. package/templates/marketplace-with-token/package.json +14 -3
  15. package/templates/marketplace-with-token/src/App.tsx +57 -0
  16. package/templates/marketplace-with-token/src/main.ts +3 -1
  17. package/templates/marketplace-with-token/src/main.tsx +10 -0
  18. package/templates/marketplace-with-token/src/styles.css +157 -0
  19. package/templates/marketplace-with-token/tsconfig.json +14 -4
  20. package/templates/marketplace-with-token/vite.config.ts +6 -0
  21. package/templates/react-vite-counter/README.md +1 -1
  22. package/templates/react-vite-counter/caatinga.artifacts.json +10 -0
  23. package/templates/react-vite-counter/caatinga.config.ts +1 -1
  24. package/templates/react-vite-counter/caatinga.template.json +1 -1
  25. package/templates/react-vite-counter/contracts/counter/Cargo.lock +1731 -0
  26. package/templates/react-vite-counter/contracts/counter/Cargo.toml +1 -0
  27. package/templates/react-vite-counter/package.json +3 -3
  28. package/templates/react-vite-counter/src/caatinga.ts +20 -0
  29. package/templates/react-vite-counter/src/components/CounterCard.tsx +40 -3
  30. package/templates/react-vite-counter/src/components/WalletButton.tsx +58 -5
  31. package/templates/react-vite-counter/src/contracts/generated/counter.ts +49 -0
  32. package/templates/react-vite-counter/src/styles.css +21 -0
  33. package/templates/react-vite-counter/tsconfig.json +1 -1
  34. package/templates/react-vite-counter/src/contracts/generated/.gitkeep +0 -1
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) Kaleido contributors
3
+ Copyright (c) Caatinga contributors
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # @caatinga/cli
2
2
 
3
+ Developer toolkit for Stellar / Soroban dApps — `init`, `build`, `deploy`, `generate`, and `invoke`.
4
+
3
5
  ## Install
4
6
 
5
7
  ```bash
@@ -7,62 +9,127 @@ npm install -g @caatinga/cli
7
9
  caatinga --help
8
10
  ```
9
11
 
12
+ Inside a generated project, prefer `npx caatinga` so the project-local workflow stays explicit.
13
+
10
14
  ## Requirements
11
15
 
12
16
  - Node.js `>=20`
13
- - Stellar CLI `>=22.0.0` and `<=25.2.0` available on `PATH`
14
- - A Caatinga project with `caatinga.config.ts` for project commands such as `build`, `deploy`, `generate`, and `invoke`
17
+ - [Stellar CLI](https://developers.stellar.org/docs/tools/developer-tools/cli/stellar-cli) `>=23.0.0` and `<=25.2.0` on `PATH` (22.x breaks `caatinga invoke` signing)
18
+ - Rust 1.84.0 or newer with the `wasm32v1-none` target (contract builds)
19
+ - A funded Stellar CLI identity for `deploy` and `invoke` (for example `alice`)
15
20
 
16
- If your local machine is on a newer Stellar CLI, `--allow-untested-stellar-cli` is the local-only escape hatch. CI and release workflows should stay on the supported range.
21
+ ```bash
22
+ rustup target add wasm32v1-none
23
+ stellar keys generate alice --fund --network testnet
24
+ ```
25
+
26
+ If your machine runs a newer Stellar CLI, `--allow-untested-stellar-cli` is the local-only escape hatch. CI and release workflows must stay on the supported range.
27
+
28
+ ## Quick start
29
+
30
+ ```bash
31
+ caatinga init my-dapp
32
+ cd my-dapp
33
+ npm install
34
+
35
+ npx caatinga build counter
36
+ npx caatinga deploy counter --network testnet --source alice
37
+ npx caatinga generate counter --network testnet
38
+ npx caatinga invoke counter.increment --network testnet --source alice
39
+ ```
40
+
41
+ `deploy` writes contract IDs to `caatinga.artifacts.json`. `generate` creates TypeScript bindings under the path configured in `caatinga.config.ts` (templates default to `contracts/generated/`).
17
42
 
18
43
  ## Commands
19
44
 
20
- - `caatinga init <projectName>` creates a project from a bundled template and writes `caatinga.artifacts.json`
21
- - `caatinga build [contract]` builds one configured contract through Stellar CLI and defaults to `counter` when omitted
22
- - `caatinga deploy [contract] --source <identity> [--network <network>] [--force] [--no-deps]` deploys contracts and records contract IDs in `caatinga.artifacts.json`
23
- - `caatinga generate <contract> [--network <network>]` generates TypeScript bindings from a deployed contract ID
24
- - `caatinga invoke <contract.method> --source <identity> [args...]` invokes a deployed contract method through the configured workflow
45
+ | Command | What it does |
46
+ | --- | --- |
47
+ | `caatinga init <projectName>` | Create a project from a bundled template and write `caatinga.artifacts.json` |
48
+ | `caatinga doctor [--network <network>] [--source <identity>]` | Check local Node, Stellar CLI, Rust, config, artifacts, network, and source identity setup |
49
+ | `caatinga build [contract]` | Compile contract WASM through Stellar CLI (default contract: `counter`) |
50
+ | `caatinga deploy [contract]` | Deploy one contract or the full configured graph; record IDs in artifacts |
51
+ | `caatinga generate <contract>` | Generate TypeScript bindings from a deployed contract ID |
52
+ | `caatinga invoke <contract.method>` | Invoke a deployed contract method; extra args forward to Stellar CLI |
25
53
 
26
54
  The supported CLI flow is `init -> build -> deploy -> generate -> invoke`.
27
55
 
28
- ## Supported Inputs
56
+ ### `init`
57
+
58
+ - `-t, --template <name>` selects a bundled template (default: `react-vite-counter`)
59
+ - Official templates: `react-vite-counter` (single counter dApp), `marketplace-with-token` (experimental multi-contract layout with `dependsOn` and deploy-arg placeholders)
60
+ - `init` validates `caatinga.template.json` before copying files
61
+
62
+ ### `build`
63
+
64
+ - `[contract]` defaults to `counter` when omitted
65
+ - `--allow-untested-stellar-cli` allows a Stellar CLI newer than Caatinga's tested maximum (local only)
29
66
 
30
- - `--source` accepts a Stellar CLI identity alias or public `G...` account address
31
- - `--network <network>` selects a configured network such as `testnet`
32
- - `invoke` expects a `<contract.method>` target and forwards extra args to the underlying Stellar contract invocation
33
- - `deploy --no-deps` is supported only when deploying a single named contract
67
+ ### `doctor`
68
+
69
+ - `-n, --network <network>` validates that the network exists in `caatinga.config.ts`
70
+ - `-s, --source <identity>` validates that the local Stellar CLI identity exists
71
+ - exits `0` when all diagnostics pass and non-zero when a blocking diagnostic fails
72
+
73
+ ### `deploy`
74
+
75
+ - Omit `[contract]` to deploy the full configured dependency graph
76
+ - `-n, --network <network>` selects a network from `caatinga.config.ts` (for example `testnet`)
77
+ - `-s, --source <identity>` is required; must be a Stellar CLI identity alias that can sign (for example `alice`)
78
+ - `--force` redeploys even when artifacts already store a contract ID
79
+ - `--no-deps` skips dependency deployment for a single named contract (`--no-deps` requires `[contract]`)
80
+ - `--allow-untested-stellar-cli` for local experiments only
81
+
82
+ Dependencies listed in `dependsOn` deploy first unless `--no-deps` is set. Deploy args may reference `${contracts.<name>.contractId}` placeholders resolved from artifacts.
83
+
84
+ ### `generate` and `invoke`
85
+
86
+ - `-n, --network <network>` selects the network used to resolve deployed contract IDs
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
+
90
+ `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
+
92
+ ## Supported inputs
93
+
94
+ - `--source` accepts a local Stellar CLI identity alias that can sign transactions; public `G...` addresses and secret keys are rejected
95
+ - `--network` must match a network defined in `caatinga.config.ts`
96
+ - Project commands require `caatinga.config.ts` in the working directory
34
97
 
35
98
  Unsupported input posture:
36
99
 
37
100
  - secret keys and seed phrases are not supported CLI inputs
38
- - undocumented private flags or internal repo file paths are not part of the package contract
101
+ - undocumented private flags, internal repo paths, and hidden commands are not part of the package contract
102
+
103
+ ## Error behavior
104
+
105
+ `@caatinga/cli` emits documented `CAATINGA_*` error codes for automation. Match on the error code, not human-readable text.
106
+
107
+ Common codes:
108
+
109
+ - `CAATINGA_CONFIG_NOT_FOUND`, `CAATINGA_INVALID_CONFIG`
110
+ - `CAATINGA_STELLAR_CLI_NOT_FOUND`, `CAATINGA_UNSUPPORTED_CLI_VERSION`, `CAATINGA_UNTESTED_CLI_VERSION`
111
+ - `CAATINGA_BUILD_FAILED`, `CAATINGA_DEPLOY_FAILED`, `CAATINGA_BINDINGS_FAILED`, `CAATINGA_INVOKE_FAILED`
112
+ - `CAATINGA_CONTRACT_ID_NOT_FOUND`, `CAATINGA_SOURCE_ACCOUNT_REQUIRED`, `CAATINGA_UNSAFE_SOURCE_ACCOUNT`
113
+ - `CAATINGA_CONTRACT_DEPENDENCY_NOT_FOUND`, `CAATINGA_CONTRACT_DEPENDENCY_CYCLE`
114
+ - `CAATINGA_DEPLOY_ARG_PLACEHOLDER_INVALID`, `CAATINGA_DEPLOY_ARG_PLACEHOLDER_UNRESOLVED`
115
+ - `CAATINGA_TEMPLATE_MANIFEST_NOT_FOUND`, `CAATINGA_TEMPLATE_INCOMPATIBLE`
39
116
 
40
- ## Error Behavior
117
+ Full table: [docs/errors.md](https://github.com/Dione-b/caatinga/blob/main/docs/errors.md)
41
118
 
42
- `@caatinga/cli` emits documented `CAATINGA_*` error codes for automation. Consumers should match on the error code, not human-readable text.
119
+ ## Browser and client apps
43
120
 
44
- Common codes include:
121
+ For wallet-backed invocation in the browser, use [`@caatinga/client`](https://www.npmjs.com/package/@caatinga/client) with generated bindings and `caatinga.artifacts.json`.
45
122
 
46
- - `CAATINGA_CONFIG_NOT_FOUND`
47
- - `CAATINGA_INVALID_CONFIG`
48
- - `CAATINGA_STELLAR_CLI_NOT_FOUND`
49
- - `CAATINGA_BUILD_FAILED`
50
- - `CAATINGA_DEPLOY_FAILED`
51
- - `CAATINGA_BINDINGS_FAILED`
52
- - `CAATINGA_INVOKE_FAILED`
53
- - `CAATINGA_CONTRACT_ID_NOT_FOUND`
54
- - `CAATINGA_SOURCE_ACCOUNT_REQUIRED`
55
- - `CAATINGA_TEMPLATE_MANIFEST_NOT_FOUND`
56
- - `CAATINGA_TEMPLATE_INCOMPATIBLE`
123
+ ## Relationship to `@caatinga/core`
57
124
 
58
- ## Relationship To `@caatinga/core`
125
+ `@caatinga/cli` is the supported end-user entrypoint. It stays thin and delegates config loading, artifacts, command orchestration, Stellar CLI version checks, and shared errors to `@caatinga/core`.
59
126
 
60
- `@caatinga/cli` is the supported end-user entrypoint for Caatinga's command workflow. It intentionally stays thin and delegates config loading, artifacts, command orchestration, and shared error primitives to `@caatinga/core`.
127
+ Prefer the CLI contract over importing `@caatinga/core` directly unless you are building advanced tooling on Caatinga internals.
61
128
 
62
- If you want the stable packaged workflow, prefer the CLI contract over importing `@caatinga/core` directly.
129
+ ## Versioning and stability
63
130
 
64
- ## Versioning And Stability
131
+ Stability applies to the documented commands, inputs, templates bundled with the published CLI, and `CAATINGA_*` error codes.
65
132
 
66
- This package is the primary supported consumer surface for the Caatinga workflow. Stability applies to the documented commands, inputs, and `CAATINGA_*` error contract.
133
+ Undocumented internals, private module paths, and hidden commands such as `caatinga dev` are not part of the stability promise.
67
134
 
68
- Undocumented internals, private module paths, and reserved hidden commands such as `caatinga dev` are not part of the stability promise.
135
+ Further reference: [CLI docs](https://github.com/Dione-b/caatinga/blob/main/docs/cli.md), [config](https://github.com/Dione-b/caatinga/blob/main/docs/config.md), [Stellar CLI version contract](https://github.com/Dione-b/caatinga/blob/main/docs/stellar-cli-version-contract.md).
package/dist/index.js CHANGED
@@ -1,5 +1,34 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // src/utils/preflight.ts
4
+ import chalk from "chalk";
5
+ var NODE_MIN_MAJOR = 20;
6
+ function checkNodeVersion() {
7
+ const major = parseInt(process.versions.node.split(".")[0] ?? "0", 10);
8
+ if (major < NODE_MIN_MAJOR) {
9
+ return `Node.js ${process.versions.node} is below the required minimum v${NODE_MIN_MAJOR}.
10
+ Install Node.js ${NODE_MIN_MAJOR} or newer: https://nodejs.org/`;
11
+ }
12
+ return null;
13
+ }
14
+ function runPreflight() {
15
+ const failures = [];
16
+ const nodeFailure = checkNodeVersion();
17
+ if (nodeFailure) failures.push(nodeFailure);
18
+ if (failures.length > 0) return { ok: false, failures };
19
+ return { ok: true };
20
+ }
21
+ function assertPreflight() {
22
+ const result = runPreflight();
23
+ if (result.ok) return;
24
+ console.error(chalk.red.bold("\n\u2716 Caatinga preflight check failed\n"));
25
+ for (const failure of result.failures) {
26
+ console.error(chalk.red(` \u2022 ${failure}
27
+ `));
28
+ }
29
+ process.exit(1);
30
+ }
31
+
3
32
  // src/program.ts
4
33
  import { Command } from "commander";
5
34
 
@@ -7,47 +36,54 @@ import { Command } from "commander";
7
36
  import { buildContract, loadConfig } from "@caatinga/core";
8
37
 
9
38
  // src/utils/errors.ts
39
+ import chalk2 from "chalk";
10
40
  import { toCaatingaError } from "@caatinga/core";
41
+ var SEPARATOR = chalk2.gray("\u2500".repeat(50));
42
+ function printError(error) {
43
+ const caatingaError = toCaatingaError(error);
44
+ console.error("");
45
+ console.error(SEPARATOR);
46
+ console.error(chalk2.red.bold(" \u2716 Error"));
47
+ console.error(SEPARATOR);
48
+ console.error(chalk2.red(` ${caatingaError.message}`));
49
+ console.error("");
50
+ console.error(chalk2.gray(` Code: ${caatingaError.code}`));
51
+ if (caatingaError.hint) {
52
+ console.error("");
53
+ console.error(chalk2.yellow(` Hint: ${caatingaError.hint}`));
54
+ }
55
+ console.error(SEPARATOR);
56
+ console.error("");
57
+ }
58
+ async function runCliAction(action) {
59
+ try {
60
+ await action();
61
+ } catch (error) {
62
+ printError(error);
63
+ process.exitCode = 1;
64
+ }
65
+ }
11
66
 
12
67
  // src/utils/logger.ts
13
- import chalk from "chalk";
68
+ import chalk3 from "chalk";
14
69
  var logger = {
15
70
  info(message) {
16
71
  console.log(message);
17
72
  },
18
73
  success(message) {
19
- console.log(chalk.green(message));
74
+ console.log(chalk3.green(message));
20
75
  },
21
76
  warn(message) {
22
- console.warn(chalk.yellow(message));
77
+ console.warn(chalk3.yellow(message));
23
78
  },
24
79
  error(message) {
25
- console.error(chalk.red(message));
80
+ console.error(chalk3.red(message));
26
81
  },
27
82
  muted(message) {
28
- console.log(chalk.gray(message));
83
+ console.log(chalk3.gray(message));
29
84
  }
30
85
  };
31
86
 
32
- // src/utils/errors.ts
33
- function printError(error) {
34
- const caatingaError = toCaatingaError(error);
35
- logger.error(`Error: ${caatingaError.message}`);
36
- logger.info("");
37
- logger.info(`Code: ${caatingaError.code}`);
38
- if (caatingaError.hint) {
39
- logger.info(`Hint: ${caatingaError.hint}`);
40
- }
41
- }
42
- async function runCliAction(action) {
43
- try {
44
- await action();
45
- } catch (error) {
46
- printError(error);
47
- process.exitCode = 1;
48
- }
49
- }
50
-
51
87
  // src/commands/build.command.ts
52
88
  function registerBuildCommand(program2) {
53
89
  program2.command("build").description("Build a configured Soroban contract").argument("[contract]", "Contract name", "counter").option("--allow-untested-stellar-cli", "Allow local use of a Stellar CLI version newer than Caatinga's tested maximum").action((contractName, options) => runCliAction(async () => {
@@ -67,7 +103,7 @@ function registerBuildCommand(program2) {
67
103
  // src/commands/deploy.command.ts
68
104
  import { deployContractGraph, CaatingaError, CaatingaErrorCode, loadConfig as loadConfig2 } from "@caatinga/core";
69
105
  function registerDeployCommand(program2) {
70
- 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 or public account address").option("--force", "Redeploy contracts even if artifacts already contain contract IDs").option("--no-deps", "Do not deploy missing dependencies for a selected contract").option("--allow-untested-stellar-cli", "Allow local use of a Stellar CLI version newer than Caatinga's tested maximum").action((contractName, options) => runCliAction(async () => {
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("--allow-untested-stellar-cli", "Allow local use of a Stellar CLI version newer than Caatinga's tested maximum").option("--verify-deps", "Verify dependency contract IDs exist on-chain before deploy").action((contractName, options) => runCliAction(async () => {
71
107
  if (options.deps === false && !contractName) {
72
108
  throw new CaatingaError(
73
109
  "`--no-deps` requires a contract name.",
@@ -83,14 +119,23 @@ function registerDeployCommand(program2) {
83
119
  source: options.source,
84
120
  includeDependencies: options.deps !== false,
85
121
  force: options.force === true,
122
+ checkStaleWasm: options.staleCheck !== false,
123
+ verifyDeps: options.verifyDeps === true,
86
124
  allowUntestedStellarCli: options.allowUntestedStellarCli === true
87
125
  });
126
+ for (const warning of result.staleWasmWarnings) {
127
+ logger.warn(warning.message);
128
+ }
88
129
  logger.success("Deploy complete");
89
130
  logger.info("");
90
131
  logger.info(`Network: ${result.network.name}`);
132
+ for (const skipped of result.skippedContracts) {
133
+ logger.info(`[skipped] ${skipped.name} \u2014 already deployed on ${result.network.name}`);
134
+ logger.info(` Contract ID: ${skipped.contractId}`);
135
+ }
91
136
  for (const contract of result.deployedContracts) {
92
- logger.info(`Contract: ${contract.name}`);
93
- logger.info(`Contract ID: ${contract.contractId}`);
137
+ logger.info(`[deployed] ${contract.name}`);
138
+ logger.info(` Contract ID: ${contract.contractId}`);
94
139
  }
95
140
  logger.info("Artifacts updated: caatinga.artifacts.json");
96
141
  }));
@@ -108,11 +153,248 @@ function registerDevCommand(program2) {
108
153
  dev.configureHelp({ visibleOptions: () => [] });
109
154
  }
110
155
 
156
+ // src/commands/doctor.command.ts
157
+ import { access } from "fs/promises";
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";
169
+
170
+ // src/commands/doctor-deploy-coverage.ts
171
+ import { loadConfig as loadConfig3, readArtifacts, resolveNetwork } from "@caatinga/core";
172
+ async function evaluateDeployCoverage(options) {
173
+ const cwd = options.cwd;
174
+ const config = await loadConfig3({ cwd });
175
+ const network = resolveNetwork(config, options.networkName);
176
+ const artifacts = await readArtifacts(cwd);
177
+ const lines = [];
178
+ for (const name of Object.keys(config.contracts)) {
179
+ const contractId = artifacts.networks[network.name]?.contracts[name]?.contractId;
180
+ if (contractId) {
181
+ lines.push({ name, ok: true, contractId });
182
+ } else {
183
+ lines.push({
184
+ name,
185
+ ok: false,
186
+ fix: `Run: caatinga deploy ${name} --network ${network.name}`
187
+ });
188
+ }
189
+ }
190
+ return { lines, complete: lines.every((line) => line.ok) };
191
+ }
192
+
193
+ // src/commands/doctor.command.ts
194
+ var NODE_MIN_MAJOR2 = 20;
195
+ var WASM_TARGET = "wasm32v1-none";
196
+ function nodeDiagnostic() {
197
+ const version = process.versions.node;
198
+ const major = Number.parseInt(version.split(".")[0] ?? "0", 10);
199
+ if (major < NODE_MIN_MAJOR2) {
200
+ return {
201
+ ok: false,
202
+ label: `Node.js ${version} is below the required minimum ${NODE_MIN_MAJOR2}.0.0`,
203
+ fix: `Install Node.js ${NODE_MIN_MAJOR2} or newer.`
204
+ };
205
+ }
206
+ return { ok: true, label: `Node.js ${version}` };
207
+ }
208
+ async function stellarDiagnostic(allowUntested) {
209
+ try {
210
+ const result = await runCommand("stellar", ["--version"], {
211
+ skipStellarVersionCheck: true
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}` };
218
+ } catch (error) {
219
+ const hint = error instanceof CaatingaError2 ? error.hint : void 0;
220
+ return {
221
+ ok: false,
222
+ label: "Stellar CLI not ready",
223
+ fix: hint ?? "Install Stellar CLI: cargo install --locked stellar-cli --version 25.2.0"
224
+ };
225
+ }
226
+ }
227
+ async function rustDiagnostic() {
228
+ try {
229
+ const result = await runCommand("rustc", ["--version"]);
230
+ return { ok: true, label: result.stdout || result.all || "Rust installed" };
231
+ } catch {
232
+ return {
233
+ ok: false,
234
+ label: "Rust not found",
235
+ fix: "Install Rust, then run: rustup target add wasm32v1-none"
236
+ };
237
+ }
238
+ }
239
+ async function wasmTargetDiagnostic() {
240
+ try {
241
+ const result = await runCommand("rustup", ["target", "list", "--installed"]);
242
+ const installedTargets = result.stdout || result.all;
243
+ if (installedTargets.split(/\r?\n/).includes(WASM_TARGET)) {
244
+ return { ok: true, label: `${WASM_TARGET} target installed` };
245
+ }
246
+ return {
247
+ ok: false,
248
+ label: `${WASM_TARGET} target not installed`,
249
+ fix: `Run: rustup target add ${WASM_TARGET}`
250
+ };
251
+ } catch {
252
+ return {
253
+ ok: false,
254
+ label: "rustup not found",
255
+ fix: "Install rustup, then run: rustup target add wasm32v1-none"
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.`
297
+ };
298
+ }
299
+ }
300
+ async function sourceDiagnostic(source) {
301
+ if (!source) return void 0;
302
+ const unsafeSource = validateSourceShape(source);
303
+ if (unsafeSource) {
304
+ return {
305
+ ok: false,
306
+ label: `source identity ${source} rejected (${unsafeSource.code})`,
307
+ fix: unsafeSource.hint
308
+ };
309
+ }
310
+ try {
311
+ await runCommand("stellar", ["keys", "public-key", source]);
312
+ return { ok: true, label: `source identity ${source} found` };
313
+ } catch {
314
+ return {
315
+ ok: false,
316
+ label: `source identity ${source} not found`,
317
+ fix: `Create and fund it: stellar keys generate ${source} --fund --network testnet`
318
+ };
319
+ }
320
+ }
321
+ function printDiagnostic(diagnostic) {
322
+ logger.info(`${diagnostic.ok ? "\u2713" : "\u2717"} ${diagnostic.label}`);
323
+ }
324
+ function printFixes(diagnostics) {
325
+ const failures = diagnostics.filter((diagnostic) => !diagnostic.ok);
326
+ if (failures.length === 0) return;
327
+ logger.info("");
328
+ logger.info("Fix:");
329
+ for (const failure of failures) {
330
+ if (failure.fix) logger.info(failure.fix);
331
+ }
332
+ }
333
+ function printDeployCoverageLine(line) {
334
+ if (line.ok) {
335
+ logger.info(`\u2713 ${line.name} \u2014 ${line.contractId}`);
336
+ return;
337
+ }
338
+ logger.info(`\u2717 ${line.name}`);
339
+ if (line.fix) logger.info(` ${line.fix}`);
340
+ }
341
+ async function reportDeployCoverage(networkName) {
342
+ const coverage = await evaluateDeployCoverage({ networkName });
343
+ logger.info("");
344
+ logger.info(`Deploy coverage (${networkName}):`);
345
+ for (const line of coverage.lines) {
346
+ printDeployCoverageLine(line);
347
+ }
348
+ if (!coverage.complete) {
349
+ const missing = coverage.lines.filter((line) => !line.ok).map((line) => line.name);
350
+ throw new CaatingaError2(
351
+ `Not all configured contracts are deployed on ${networkName}.`,
352
+ CaatingaErrorCode2.DOCTOR_PARTIAL_DEPLOY,
353
+ `Deploy missing contracts: ${missing.join(", ")}. See the commands above.`
354
+ );
355
+ }
356
+ return true;
357
+ }
358
+ 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").option("--allow-untested-stellar-cli", "Allow local use of a Stellar CLI version newer than Caatinga's tested maximum").action((options) => runCliAction(async () => {
360
+ logger.info("Caatinga Doctor");
361
+ 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);
372
+ for (const diagnostic of diagnostics) {
373
+ printDiagnostic(diagnostic);
374
+ }
375
+ printFixes(diagnostics);
376
+ let ready = diagnostics.every((diagnostic) => diagnostic.ok);
377
+ if (options.network && ready) {
378
+ try {
379
+ await reportDeployCoverage(options.network);
380
+ } catch (error) {
381
+ ready = false;
382
+ throw error;
383
+ }
384
+ }
385
+ logger.info("");
386
+ logger.info(`Status: ${ready ? "ready" : "blocked"}`);
387
+ if (!ready) {
388
+ process.exitCode = 1;
389
+ }
390
+ }));
391
+ }
392
+
111
393
  // src/commands/generate.command.ts
112
- import { generateBindings, loadConfig as loadConfig3 } from "@caatinga/core";
394
+ import { generateBindings, loadConfig as loadConfig5 } from "@caatinga/core";
113
395
  function registerGenerateCommand(program2) {
114
396
  program2.command("generate").description("Generate TypeScript bindings for a deployed contract").argument("<contract>", "Contract name").option("-n, --network <network>", "Configured network name").option("--allow-untested-stellar-cli", "Allow local use of a Stellar CLI version newer than Caatinga's tested maximum").action((contractName, options) => runCliAction(async () => {
115
- const config = await loadConfig3();
397
+ const config = await loadConfig5();
116
398
  const result = await generateBindings({
117
399
  config,
118
400
  contractName,
@@ -132,10 +414,10 @@ import path2 from "path";
132
414
  import { createProjectFromTemplate } from "@caatinga/core";
133
415
 
134
416
  // src/utils/template-path.ts
135
- import { access } from "fs/promises";
417
+ import { access as access2 } from "fs/promises";
136
418
  import path from "path";
137
419
  import { fileURLToPath } from "url";
138
- import { CaatingaError as CaatingaError2, CaatingaErrorCode as CaatingaErrorCode2 } from "@caatinga/core";
420
+ import { CaatingaError as CaatingaError3, CaatingaErrorCode as CaatingaErrorCode3 } from "@caatinga/core";
139
421
  async function resolveTemplateDir(templateName) {
140
422
  const envTemplatesDir = process.env.CAATINGA_TEMPLATES_DIR;
141
423
  const candidates = [
@@ -145,14 +427,14 @@ async function resolveTemplateDir(templateName) {
145
427
  ].filter((candidate) => Boolean(candidate));
146
428
  for (const candidate of candidates) {
147
429
  try {
148
- await access(candidate);
430
+ await access2(candidate);
149
431
  return candidate;
150
432
  } catch {
151
433
  }
152
434
  }
153
- throw new CaatingaError2(
435
+ throw new CaatingaError3(
154
436
  `Template "${templateName}" was not found.`,
155
- CaatingaErrorCode2.TEMPLATE_NOT_FOUND,
437
+ CaatingaErrorCode3.TEMPLATE_NOT_FOUND,
156
438
  "Set CAATINGA_TEMPLATES_DIR or run from a Caatinga checkout that includes packages/templates."
157
439
  );
158
440
  }
@@ -191,15 +473,18 @@ function registerInitCommand(program2) {
191
473
  logger.info("Next steps:");
192
474
  logger.info(` cd ${projectDirectory}`);
193
475
  logger.info(" npm install");
194
- logger.info(" npx caatinga build counter");
476
+ const defaultContract = result.template.contracts.default;
477
+ logger.info(
478
+ defaultContract ? ` npx caatinga build ${defaultContract}` : " npx caatinga build"
479
+ );
195
480
  }));
196
481
  }
197
482
 
198
483
  // src/commands/invoke.command.ts
199
- import { invokeContract, loadConfig as loadConfig4 } from "@caatinga/core";
484
+ import { invokeContract, loadConfig as loadConfig6 } from "@caatinga/core";
200
485
  function registerInvokeCommand(program2) {
201
- 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 or public account address").option("--allow-untested-stellar-cli", "Allow local use of a Stellar CLI version newer than Caatinga's tested maximum").allowUnknownOption(true).allowExcessArguments(true).action((target, args, options) => runCliAction(async () => {
202
- const config = await loadConfig4();
486
+ 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)").option("--allow-untested-stellar-cli", "Allow local use of a Stellar CLI version newer than Caatinga's tested maximum").allowUnknownOption(true).allowExcessArguments(true).action((target, args, options) => runCliAction(async () => {
487
+ const config = await loadConfig6();
203
488
  const result = await invokeContract({
204
489
  config,
205
490
  target,
@@ -221,7 +506,7 @@ function registerInvokeCommand(program2) {
221
506
  }
222
507
 
223
508
  // src/version.ts
224
- var CAATINGA_CLI_VERSION = "0.2.0";
509
+ var CAATINGA_CLI_VERSION = "0.2.2";
225
510
 
226
511
  // src/program.ts
227
512
  function createProgram() {
@@ -229,6 +514,7 @@ function createProgram() {
229
514
  program2.name("caatinga").description("Developer toolkit for Stellar/Soroban dApps").version(CAATINGA_CLI_VERSION);
230
515
  registerInitCommand(program2);
231
516
  registerDevCommand(program2);
517
+ registerDoctorCommand(program2);
232
518
  registerBuildCommand(program2);
233
519
  registerDeployCommand(program2);
234
520
  registerGenerateCommand(program2);
@@ -237,6 +523,7 @@ function createProgram() {
237
523
  }
238
524
 
239
525
  // src/index.ts
526
+ assertPreflight();
240
527
  var program = createProgram();
241
528
  void program.parseAsync(process.argv).catch((error) => {
242
529
  console.error(error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@caatinga/cli",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
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.2.0",
46
+ "@caatinga/core": "^0.2.2",
47
47
  "chalk": "^5.4.1",
48
48
  "commander": "^12.1.0"
49
49
  },