mycelium-cli 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,72 @@
1
+ """
2
+ `mycelium test` — dry-run the agent against a simulated ledger.
3
+
4
+ Runs the project's agent script exactly as `mycelium run` would, but with
5
+ dry-run mode forced on (MYCELIUM_DRY_RUN=1): every state-changing contract call
6
+ the agent makes is *simulated* (no signature, no fee, no on-chain mutation) and
7
+ recorded. Afterwards it prints a summary of every on-chain action the agent
8
+ would have taken, with the simulated return value and estimated fee — so you can
9
+ see what your agent does before it spends real lumens on testnet.
10
+
11
+ Read-only calls behave identically to a live run, so views still return real data.
12
+ """
13
+
14
+ import os
15
+ import sys
16
+ from typing import Optional
17
+
18
+ from mycelium_cli.config import get_value
19
+ from mycelium_cli.commands.agent import run_agent
20
+
21
+
22
+ def _stroops_to_xlm(stroops: Optional[int]) -> str:
23
+ if stroops is None:
24
+ return "—"
25
+ return f"{stroops / 1e7:.7f}"
26
+
27
+
28
+ def _print_summary() -> None:
29
+ from mycelium_sdk import context as ctx_mod
30
+
31
+ log = ctx_mod.DRY_RUN_LOG
32
+ print("\n──────── dry-run summary ────────")
33
+ if not log:
34
+ print(" No state-changing contract calls were attempted.")
35
+ print(" (Read-only calls run normally and are not listed here.)\n")
36
+ return
37
+
38
+ total_fee = 0
39
+ for i, rec in enumerate(log, 1):
40
+ args = ", ".join(map(repr, rec["args"]))
41
+ print(f" {i}. {rec['function']}({args})")
42
+ print(f" contract : {rec['contract_id']}")
43
+ print(f" returns : {rec['sim_return']}")
44
+ print(f" est fee : {_stroops_to_xlm(rec['est_fee_stroops'])} XLM")
45
+ if rec["est_fee_stroops"]:
46
+ total_fee += rec["est_fee_stroops"]
47
+ print(f"\n {len(log)} action(s) simulated · est. total fees {_stroops_to_xlm(total_fee)} XLM")
48
+ print(" Nothing was signed or submitted. Run `mycelium run` to execute for real.\n")
49
+
50
+
51
+ def run_test(file: Optional[str] = None, contract: Optional[str] = None) -> list:
52
+ from mycelium_sdk import context as ctx_mod
53
+
54
+ file = file or get_value("agent", "script", "agent.py")
55
+ contract = contract or get_value("onchain", "contract_id") or ""
56
+ network = get_value("onchain", "network", "testnet")
57
+
58
+ if not os.path.exists(file):
59
+ print(f"Error: agent script {file} not found. Pass it explicitly or run from the project dir.")
60
+ sys.exit(1)
61
+
62
+ print(f"[test] Dry-running {file} ({network}) — state changes will be simulated only.\n")
63
+ os.environ["MYCELIUM_DRY_RUN"] = "1"
64
+ os.environ.setdefault("MYCELIUM_NETWORK", network)
65
+ ctx_mod.reset_dry_run_log()
66
+
67
+ try:
68
+ run_agent(file, contract)
69
+ finally:
70
+ _print_summary()
71
+
72
+ return list(ctx_mod.DRY_RUN_LOG)
mycelium_cli/config.py ADDED
@@ -0,0 +1,47 @@
1
+ """
2
+ mycelium.toml read/write helpers.
3
+
4
+ Reading uses the stdlib `tomllib` (Python 3.11+); writing uses `tomli-w`. We
5
+ only ever patch flat values (e.g. `onchain.contract_id` after deploy), so the
6
+ lack of comment preservation is acceptable.
7
+ """
8
+
9
+ import os
10
+ import tomllib
11
+
12
+ import tomli_w
13
+
14
+ DEFAULT_CONFIG_PATH = "mycelium.toml"
15
+
16
+
17
+ def load_config(path: str = DEFAULT_CONFIG_PATH) -> dict:
18
+ """Load and parse a mycelium.toml file. Raises FileNotFoundError if absent."""
19
+ if not os.path.exists(path):
20
+ raise FileNotFoundError(
21
+ f"{path} not found. Run `mycelium init <name>` first, or run from a project directory."
22
+ )
23
+ with open(path, "rb") as f:
24
+ return tomllib.load(f)
25
+
26
+
27
+ def save_config(data: dict, path: str = DEFAULT_CONFIG_PATH) -> None:
28
+ """Serialize a config dict back to TOML."""
29
+ with open(path, "wb") as f:
30
+ tomli_w.dump(data, f)
31
+
32
+
33
+ def set_value(table: str, key: str, value, path: str = DEFAULT_CONFIG_PATH) -> dict:
34
+ """Set `[table].key = value` in the config file, creating the table if needed."""
35
+ data = load_config(path)
36
+ data.setdefault(table, {})[key] = value
37
+ save_config(data, path)
38
+ return data
39
+
40
+
41
+ def get_value(table: str, key: str, default=None, path: str = DEFAULT_CONFIG_PATH):
42
+ """Read `[table].key`, returning `default` if missing."""
43
+ try:
44
+ data = load_config(path)
45
+ except FileNotFoundError:
46
+ return default
47
+ return data.get(table, {}).get(key, default)
mycelium_cli/main.py ADDED
@@ -0,0 +1,298 @@
1
+ """Mycelium CLI entry point (Typer)."""
2
+
3
+ import os
4
+
5
+ import typer
6
+
7
+ from mycelium_sdk.banner import show_startup_banner
8
+ from mycelium_cli.commands.init import run_init, validate_unique_name, VALID_FRAMEWORKS
9
+ from mycelium_cli.commands.newwallet import run_newwallet, DEFAULT_WALLET_PATH
10
+ from mycelium_cli.commands.compile import run_compile
11
+ from mycelium_cli.commands.deploy import run_deploy
12
+ from mycelium_cli.commands.register import run_register
13
+ from mycelium_cli.commands.check import run_check
14
+ from mycelium_cli.commands.agent import run_agent
15
+ from mycelium_cli.commands.discover import run_discover
16
+ from mycelium_cli.commands.resolve import run_resolve
17
+ from mycelium_cli.commands.status import run_status
18
+ from mycelium_cli.commands.fund import run_fund
19
+ from mycelium_cli.commands.call import run_call
20
+ from mycelium_cli.commands.pay import run_pay
21
+ from mycelium_cli.commands.doctor import run_doctor
22
+ from mycelium_cli.commands.events import run_events
23
+ from mycelium_cli.commands.run import run_run
24
+ from mycelium_cli.commands.test import run_test
25
+
26
+ app = typer.Typer(help="Mycelium Developer Framework CLI")
27
+
28
+ PASSPHRASE_ENV_VAR = "MYCELIUM_DECRYPT_KEY"
29
+
30
+
31
+ @app.callback(invoke_without_command=True)
32
+ def _root(ctx: typer.Context):
33
+ """Mycelium Developer Framework CLI."""
34
+ show_startup_banner()
35
+ if ctx.invoked_subcommand is None:
36
+ typer.echo(ctx.get_help())
37
+ raise typer.Exit()
38
+
39
+
40
+ def _resolve_passphrase(label: str, confirm: bool = False) -> str:
41
+ """Use MYCELIUM_DECRYPT_KEY if set, otherwise prompt interactively."""
42
+ env_value = os.environ.get(PASSPHRASE_ENV_VAR)
43
+ if env_value:
44
+ return env_value
45
+ return typer.prompt(label, hide_input=True, confirmation_prompt=confirm)
46
+
47
+
48
+ def _select_model(framework: str) -> tuple[str, str | None]:
49
+ """
50
+ Resolve the target model for `framework`, returning (model, api_key).
51
+
52
+ For API-backed frameworks we NEVER let the developer free-type a model name
53
+ (a hallucinated id fails at runtime). Instead we take their API key, query
54
+ the provider's live model catalogue, and have them pick from the real list.
55
+ If discovery fails (bad key / offline) we fall back to manual entry so the
56
+ wizard never hard-blocks. `api_key` is None for non-API frameworks.
57
+ """
58
+ from mycelium_sdk import models as model_discovery
59
+
60
+ if not model_discovery.supports_discovery(framework):
61
+ return typer.prompt("Target model", default="custom"), None
62
+
63
+ # Cloud providers need a key; local runtimes (ollama) need a base URL instead.
64
+ api_key = None
65
+ base_url = None
66
+ if model_discovery.requires_api_key(framework):
67
+ api_key = typer.prompt(f"{framework.capitalize()} API key", hide_input=True).strip()
68
+ else:
69
+ base_url = typer.prompt(
70
+ f"{framework.capitalize()} server URL",
71
+ default=model_discovery.DEFAULT_OLLAMA_URL,
72
+ ).strip()
73
+
74
+ typer.echo(f" Fetching available {framework} models...")
75
+ try:
76
+ available = model_discovery.list_models(framework, api_key, base_url=base_url)
77
+ except model_discovery.ModelDiscoveryError as exc:
78
+ typer.echo(f" ⚠ Could not list models ({exc}).")
79
+ return typer.prompt("Enter the model id manually"), api_key
80
+
81
+ typer.echo(f" {len(available)} models available:")
82
+ for i, name in enumerate(available, 1):
83
+ typer.echo(f" [{i}] {name}")
84
+ while True:
85
+ choice = typer.prompt("Select a model by number")
86
+ try:
87
+ idx = int(choice)
88
+ if 1 <= idx <= len(available):
89
+ return available[idx - 1], api_key
90
+ except ValueError:
91
+ pass
92
+ typer.echo(f" Enter a number between 1 and {len(available)}.")
93
+
94
+
95
+ @app.command()
96
+ def init(
97
+ project_name: str = typer.Argument(..., help="Name of the new project"),
98
+ non_interactive: bool = typer.Option(
99
+ False, "--yes", "--non-interactive", help="Skip prompts, use defaults"
100
+ ),
101
+ ):
102
+ """Initialize a new Mycelium agent project."""
103
+ framework, model, unique_name, api_key = "custom", "custom", project_name, None
104
+
105
+ if not non_interactive:
106
+ framework = typer.prompt(f"AI framework {list(VALID_FRAMEWORKS)}", default="custom")
107
+ while framework not in VALID_FRAMEWORKS:
108
+ typer.echo(f" Must be one of {list(VALID_FRAMEWORKS)}.")
109
+ framework = typer.prompt("AI framework", default="custom")
110
+ model, api_key = _select_model(framework)
111
+ unique_name = typer.prompt("Unique name (^[a-zA-Z0-9_]{3,30}$)", default=project_name)
112
+ while not validate_unique_name(unique_name):
113
+ typer.echo(" Invalid: 3-30 chars, alphanumeric/underscore only.")
114
+ unique_name = typer.prompt("Unique name", default=project_name)
115
+
116
+ path = run_init(
117
+ project_name, framework=framework, model=model, unique_name=unique_name, api_key=api_key
118
+ )
119
+ typer.echo(f"✓ Project '{path}' initialized.")
120
+ typer.echo(" Next: cd into it, run `mycelium newwallet`, then `mycelium compile`.")
121
+
122
+
123
+ @app.command()
124
+ def newwallet(
125
+ path: str = typer.Option(DEFAULT_WALLET_PATH, help="Wallet output path"),
126
+ force: bool = typer.Option(False, "--force", help="Overwrite an existing wallet"),
127
+ ):
128
+ """Generate an encrypted Ed25519 wallet."""
129
+ passphrase = _resolve_passphrase("Encryption passphrase", confirm=True)
130
+ public_key = run_newwallet(path=path, passphrase=passphrase, force=force)
131
+ typer.echo(f"✓ Wallet created at {path}")
132
+ typer.echo(f" Public key: {public_key}")
133
+
134
+
135
+ @app.command()
136
+ def compile(
137
+ file: str = typer.Argument(None, help="Contract file (defaults to mycelium.toml)"),
138
+ output: str = typer.Option(None, "-o", "--output", help="Output WASM path"),
139
+ optimize: bool = typer.Option(False, "--optimize", help="Size-optimize the WASM"),
140
+ ):
141
+ """Compile a Python contract to Soroban WASM."""
142
+ run_compile(file, output, optimize=optimize)
143
+
144
+
145
+ @app.command()
146
+ def check(file: str = typer.Argument(..., help="Python contract file to validate")):
147
+ """Validate a contract's AST and types without compiling."""
148
+ run_check(file)
149
+
150
+
151
+ @app.command()
152
+ def deploy(
153
+ network: str = typer.Option("testnet", help="testnet or mainnet"),
154
+ wasm: str = typer.Option(None, help="WASM path (defaults to mycelium.toml)"),
155
+ wallet: str = typer.Option(DEFAULT_WALLET_PATH, help="Wallet path"),
156
+ ):
157
+ """Deploy the compiled contract to Stellar/Soroban."""
158
+ passphrase = _resolve_passphrase("Wallet passphrase")
159
+ run_deploy(network=network, wasm_path=wasm, wallet_path=wallet, passphrase=passphrase)
160
+
161
+
162
+ @app.command()
163
+ def register(
164
+ network: str = typer.Option(None, help="testnet or mainnet (defaults to mycelium.toml)"),
165
+ wallet: str = typer.Option(DEFAULT_WALLET_PATH, help="Wallet path"),
166
+ ):
167
+ """Register the agent's unique name on the Hive Registry."""
168
+ passphrase = _resolve_passphrase("Wallet passphrase")
169
+ run_register(network=network, wallet_path=wallet, passphrase=passphrase)
170
+
171
+
172
+ @app.command()
173
+ def agent(
174
+ file: str = typer.Argument(..., help="Agent runtime script"),
175
+ contract: str = typer.Option(..., "--contract", help="On-chain contract id to bind"),
176
+ ):
177
+ """Start a Mycelium agent runtime."""
178
+ run_agent(file, contract)
179
+
180
+
181
+ @app.command()
182
+ def agents(
183
+ network: str = typer.Option(None, help="testnet or mainnet (defaults to mycelium.toml)"),
184
+ registry: str = typer.Option(None, "--registry", help="Hive Registry contract id override"),
185
+ start_ledger: int = typer.Option(
186
+ None, "--start-ledger", help="First ledger to scan (defaults to the RPC retention horizon)"
187
+ ),
188
+ no_resolve: bool = typer.Option(
189
+ False, "--no-resolve", help="Skip per-agent resolution (faster; names + addresses only)"
190
+ ),
191
+ ):
192
+ """Discover every agent registered on the Hive Registry (read-only, no wallet)."""
193
+ run_discover(
194
+ network=network, registry=registry, start_ledger=start_ledger, resolve=not no_resolve
195
+ )
196
+
197
+
198
+ @app.command()
199
+ def resolve(
200
+ name: str = typer.Argument(..., help="Unique agent name to look up"),
201
+ network: str = typer.Option(None, help="testnet or mainnet (defaults to mycelium.toml)"),
202
+ registry: str = typer.Option(None, "--registry", help="Hive Registry contract id override"),
203
+ ):
204
+ """Resolve a single agent name to its Hive Registry entry (read-only, no wallet)."""
205
+ run_resolve(name, network=network, registry=registry)
206
+
207
+
208
+ @app.command()
209
+ def status(
210
+ network: str = typer.Option(None, help="testnet or mainnet (defaults to mycelium.toml)"),
211
+ wallet: str = typer.Option(DEFAULT_WALLET_PATH, help="Wallet path"),
212
+ ):
213
+ """Show wallet, balance, network, deploy, and registry state in one screen."""
214
+ run_status(network=network, wallet_path=wallet)
215
+
216
+
217
+ @app.command()
218
+ def fund(
219
+ address: str = typer.Option(None, "--address", help="Address to fund (defaults to project wallet)"),
220
+ network: str = typer.Option(None, help="testnet or mainnet (defaults to mycelium.toml)"),
221
+ wallet: str = typer.Option(DEFAULT_WALLET_PATH, help="Wallet path"),
222
+ ):
223
+ """Top up a testnet wallet from Friendbot."""
224
+ run_fund(address=address, network=network, wallet_path=wallet)
225
+
226
+
227
+ @app.command()
228
+ def call(
229
+ function_name: str = typer.Argument(..., help="Contract function to invoke"),
230
+ args: list[str] = typer.Argument(None, help="Positional arguments (ints/bools/addresses auto-typed)"),
231
+ contract: str = typer.Option(None, "--contract", help="Contract id (defaults to mycelium.toml)"),
232
+ network: str = typer.Option(None, help="testnet or mainnet (defaults to mycelium.toml)"),
233
+ send: bool = typer.Option(False, "--send", help="Sign & submit a state-changing tx (default: read-only)"),
234
+ wallet: str = typer.Option(DEFAULT_WALLET_PATH, help="Wallet path (only with --send)"),
235
+ ):
236
+ """Invoke a deployed contract function (read-only by default)."""
237
+ passphrase = _resolve_passphrase("Wallet passphrase") if send else None
238
+ run_call(
239
+ function_name, args=args, contract=contract, network=network,
240
+ send=send, wallet_path=wallet, passphrase=passphrase,
241
+ )
242
+
243
+
244
+ @app.command()
245
+ def pay(
246
+ recipient: str = typer.Argument(..., help="Registry name or G... address to pay"),
247
+ amount: str = typer.Argument(..., help="Amount of XLM to send"),
248
+ network: str = typer.Option(None, help="testnet or mainnet (defaults to mycelium.toml)"),
249
+ wallet: str = typer.Option(DEFAULT_WALLET_PATH, help="Wallet path"),
250
+ ):
251
+ """Send an XLM payment to a registry name or address (M2M settlement)."""
252
+ passphrase = _resolve_passphrase("Wallet passphrase")
253
+ run_pay(recipient, amount, network=network, wallet_path=wallet, passphrase=passphrase)
254
+
255
+
256
+ @app.command()
257
+ def doctor(
258
+ network: str = typer.Option(None, help="testnet or mainnet (defaults to mycelium.toml)"),
259
+ ):
260
+ """Verify the toolchain (stellar-cli, rust+wasm, RPC) and print fixes."""
261
+ run_doctor(network=network)
262
+
263
+
264
+ @app.command()
265
+ def events(
266
+ contract: str = typer.Option(None, "--contract", help="Contract id (defaults to mycelium.toml)"),
267
+ network: str = typer.Option(None, help="testnet or mainnet (defaults to mycelium.toml)"),
268
+ start_ledger: int = typer.Option(None, "--start-ledger", help="First ledger to scan"),
269
+ follow: bool = typer.Option(False, "--follow", "-f", help="Stream new events until interrupted"),
270
+ ):
271
+ """Show (or stream with --follow) a contract's on-chain events."""
272
+ run_events(contract=contract, network=network, start_ledger=start_ledger, follow=follow)
273
+
274
+
275
+ @app.command()
276
+ def run(
277
+ file: str = typer.Argument(None, help="Agent script (defaults to agent.py)"),
278
+ contract: str = typer.Option(None, "--contract", help="Contract id (defaults to mycelium.toml)"),
279
+ ):
280
+ """Run the project's agent, auto-reading contract id + network from mycelium.toml."""
281
+ run_run(file=file, contract=contract)
282
+
283
+
284
+ @app.command()
285
+ def test(
286
+ file: str = typer.Argument(None, help="Agent script (defaults to agent.py)"),
287
+ contract: str = typer.Option(None, "--contract", help="Contract id (defaults to mycelium.toml)"),
288
+ ):
289
+ """Dry-run the agent: simulate every on-chain action without signing or spending."""
290
+ run_test(file=file, contract=contract)
291
+
292
+
293
+ def main():
294
+ app()
295
+
296
+
297
+ if __name__ == "__main__":
298
+ main()
@@ -0,0 +1,239 @@
1
+ Metadata-Version: 2.4
2
+ Name: mycelium-cli
3
+ Version: 0.1.0
4
+ Summary: Mycelium CLI — init, newwallet, compile, deploy, register
5
+ Requires-Python: >=3.10
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: typer>=0.9
8
+ Requires-Dist: tomli-w>=1.0
9
+ Requires-Dist: stellar-sdk<15,>=14
10
+
11
+ # Mycelium CLI
12
+
13
+ The Mycelium CLI (`mycelium` command-line tool) is the developer command center for the Mycelium framework. It provides interactive scaffolding, local wallet/keypair management, contract checking and compilation, Soroban blockchain deployments, agent directory registration in the Hive registry, and execution runners for autonomous agent loops.
14
+
15
+ ---
16
+
17
+ ## 🚀 Installation & Setup
18
+
19
+ Install the CLI toolchain directly from PyPI (packaged within `mycelium-cli` or bundled inside the parent `mycelium-stellar` wrapper):
20
+
21
+ ```bash
22
+ pip install mycelium-cli
23
+ ```
24
+
25
+ Verify that the installation was successful by running:
26
+ ```bash
27
+ mycelium --help
28
+ ```
29
+
30
+ ---
31
+
32
+ ## ⚙️ Configuration Reference (`mycelium.toml`)
33
+
34
+ All Mycelium CLI operations run relative to a project root containing a `mycelium.toml` file. This configuration serves as the single source of truth for the local agent and its corresponding on-chain contract.
35
+
36
+ ```toml
37
+ [project]
38
+ name = "sentinel_agent"
39
+ version = "0.1.0"
40
+ author = "Developer"
41
+
42
+ [agent]
43
+ framework = "gemini" # Options: "langgraph" | "gemini" | "anthropic" | "custom"
44
+ model = "gemini-2.0-flash" # Target LLM model string
45
+ unique_name = "sentinel_alpha" # Alphanumeric agent registry name
46
+
47
+ [onchain]
48
+ source_contract = "contract.py" # Path to smart contract source file
49
+ target_wasm = "build/contract.wasm" # Output binary path
50
+ network = "testnet" # Default ledger target: "testnet" | "mainnet"
51
+ contract_id = "CC..." # Automatically populated after deployment
52
+ wallet_public_key = "GD..." # Automatically populated after deployment
53
+
54
+ [registry]
55
+ hive_registry_address = "CCQ..." # Hex contract address of the Hive Registry
56
+ service_endpoint = "https://agent.sentinel.mycelium.sh" # Agent API URL
57
+ capabilities = ["data-analysis", "stellar-arbitrage"] # List of capability tags
58
+ ```
59
+
60
+ ---
61
+
62
+ ## 🛠️ Complete CLI Command Reference
63
+
64
+ ### 1. `mycelium init`
65
+ Scaffolds a new Mycelium project from scratch. It launches an interactive setup wizard that prompts you for project properties.
66
+
67
+ * **Syntax**:
68
+ ```bash
69
+ mycelium init <project_name> [options]
70
+ ```
71
+ * **Interactive Wizard Options**:
72
+ - **AI Core Framework**: Select from `langgraph`, `gemini`, `anthropic`, or `custom`.
73
+ - **Target LLM Model**: Pick from recommended defaults or input a custom string.
74
+ - **Unique Name**: Choose a registry name (regex validated against `^[a-zA-Z0-9_]{3,30}$`).
75
+ * **Flags**:
76
+ - `--yes` / `-y`: Skip all interactive questions and initialize using standard default configurations.
77
+ - `--force` / `-f`: Overwrite the destination directory if it already exists.
78
+
79
+ ### 2. `mycelium newwallet`
80
+ Generates a new secure Stellar keypair (Ed25519) and saves it to `.mycelium/wallet.json`.
81
+
82
+ * **Syntax**:
83
+ ```bash
84
+ mycelium newwallet [options]
85
+ ```
86
+ * **Security Details**:
87
+ - The secret seed is encrypted at rest using PBKDF2-HMAC-SHA256 (600,000 iterations) + AES-256-GCM.
88
+ - Prompts securely for an encryption passphrase.
89
+ - Filesystem permissions on `.mycelium/wallet.json` are automatically restricted to `0600` (read/write by owner only).
90
+ * **Flags**:
91
+ - `--passphrase <text>`: Provide the encryption passphrase directly (convenient for automated environments).
92
+ - `--force`: Force generation, overwriting any existing wallet configuration.
93
+
94
+ ### 3. `mycelium compile`
95
+ Parses and compiles a Python-DSL contract file into a WebAssembly contract binary.
96
+
97
+ * **Syntax**:
98
+ ```bash
99
+ mycelium compile [source_file] [options]
100
+ ```
101
+ * **Flags**:
102
+ - `--output <path>` / `-o <path>`: Specify the output WASM file path (defaults to `build/contract.wasm`).
103
+ - `--optimize`: Enable maximum optimization passes (release profile, targeting size reduction).
104
+
105
+ ### 4. `mycelium check`
106
+ Performs static evaluation and type verification on a contract script without generating a WASM binary. Useful for checking syntax in IDEs, git pre-commit hooks, or CI pipelines.
107
+
108
+ * **Syntax**:
109
+ ```bash
110
+ mycelium check [source_file]
111
+ ```
112
+
113
+ ### 5. `mycelium deploy`
114
+ Deploys the compiled WASM binary directly to Stellar/Soroban.
115
+
116
+ * **Syntax**:
117
+ ```bash
118
+ mycelium deploy [options]
119
+ ```
120
+ * **Behaviors**:
121
+ - **Testnet**: Checks the balance. If the balance is zero, the CLI automatically requests funds from the Stellar Friendbot API, waits for ledger confirmation, and broadcasts the deployment transaction.
122
+ - **Mainnet**: Asserts the wallet has a minimum balance of `5 XLM` (to satisfy reserves). If insufficient, it halts with an error and displays the public key.
123
+ - On success, updates `contract_id` and `wallet_public_key` in `mycelium.toml`.
124
+ * **Flags**:
125
+ - `--network <name>`: Override the network target (`testnet` or `mainnet`).
126
+ - `--wasm <path>`: Override the WASM file path to deploy.
127
+
128
+ ### 6. `mycelium register`
129
+ Submits a signed transaction to the global Hive Registry mapping your agent's configuration parameters.
130
+
131
+ * **Syntax**:
132
+ ```bash
133
+ mycelium register [options]
134
+ ```
135
+ * **Details**:
136
+ - Packages the agent name, service endpoint, public address, and the SHA-256 hash of capability tags.
137
+ - Verifies that local keys match the owner keys if updating an existing registration.
138
+
139
+ ### 7. `mycelium status`
140
+ Displays the comprehensive deployment and configuration status of the active project in a single screen.
141
+
142
+ * **Syntax**:
143
+ ```bash
144
+ mycelium status
145
+ ```
146
+ * **Output Fields**:
147
+ - **Wallet Address**: G-address extracted from local wallet config.
148
+ - **Wallet Balance**: Balance retrieved from Horizon RPC.
149
+ - **Network**: Deployed target network passphrase identifier.
150
+ - **Contract Deployment**: Verification status of the contract ID on the ledger.
151
+ - **Registry Entry**: Name verification, registration state, reputation score, and API endpoint details.
152
+
153
+ ### 8. `mycelium fund`
154
+ Explicitly requests Friendbot funding for the agent's wallet. Used to top up testnet gas balances.
155
+
156
+ * **Syntax**:
157
+ ```bash
158
+ mycelium fund [options]
159
+ ```
160
+ * **Flags**:
161
+ - `--amount <number>`: Request a specific amount (if supported by network node limits).
162
+
163
+ ### 9. `mycelium call`
164
+ Invokes an on-chain contract function directly from your terminal.
165
+
166
+ * **Syntax**:
167
+ ```bash
168
+ mycelium call <function_name> [args...] [options]
169
+ ```
170
+ * **Details**:
171
+ - Automatically maps plain argument strings to the correct Soroban type based on the contract specification.
172
+ * **Flags**:
173
+ - `--read-only`: Execute as a simulate-only view invocation (free, does not require passphrase or signature).
174
+ - `--contract <id>`: Override the target contract ID.
175
+
176
+ ### 10. `mycelium resolve`
177
+ Queries the on-chain Hive Registry to resolve details of another agent by its name.
178
+
179
+ * **Syntax**:
180
+ ```bash
181
+ mycelium resolve <agent_name>
182
+ ```
183
+
184
+ ### 11. `mycelium pay`
185
+ Triggers an agent-to-agent XLM settlement payment. It resolves the destination agent's wallet address from the registry.
186
+
187
+ * **Syntax**:
188
+ ```bash
189
+ mycelium pay <recipient_name_or_address> <amount_xlm>
190
+ ```
191
+
192
+ ### 12. `mycelium events` / `mycelium logs`
193
+ Streams on-chain event topics emitted by the agent's smart contract.
194
+
195
+ * **Syntax**:
196
+ ```bash
197
+ mycelium events [options]
198
+ ```
199
+ * **Flags**:
200
+ - `--contract <id>`: Override the contract ID to monitor.
201
+ - `--start-ledger <number>`: Begin streaming historical events from a specific ledger sequence.
202
+
203
+ ### 13. `mycelium doctor`
204
+ Runs a suite of sanity checks to verify the state of your local toolchain:
205
+ 1. Asserts `stellar-cli` is present on your system path.
206
+ 2. Checks if local cargo/wasm targets are properly configured.
207
+ 3. Tests network connectivity and latency to Horizon and Soroban RPC nodes.
208
+ 4. Identifies version mismatches and prints corrective shell actions.
209
+
210
+ * **Syntax**:
211
+ ```bash
212
+ mycelium doctor
213
+ ```
214
+
215
+ ### 14. `mycelium run`
216
+ Spins up the agent's execution loop (`agent.py`) in your terminal, pre-loading context configurations, wallet files, and contract IDs from the project directory.
217
+
218
+ * **Syntax**:
219
+ ```bash
220
+ mycelium run [options]
221
+ ```
222
+ * **Flags**:
223
+ - `--steps <number>`: Limit the maximum number of steps the LLM loop is permitted to run.
224
+
225
+ ### 15. `mycelium test`
226
+ Performs a simulation dry-run of the agent loop. It intercepts all state-changing contract calls, executes them via simulation, logs estimated resource fees, and returns without signing or broadcasting transactions.
227
+
228
+ * **Syntax**:
229
+ ```bash
230
+ mycelium test
231
+ ```
232
+
233
+ ---
234
+
235
+ ## 🔐 Environment Variables
236
+
237
+ * `MYCELIUM_DECRYPT_KEY`: Set this env variable to bypass interactive wallet decryption password prompts. Essential for CI/CD and non-interactive workflows.
238
+ * `MYCELIUM_CONTRACT_ID`: Override default contract target.
239
+ * `STELLAR_NETWORK`: Overrides default network selection (`testnet` / `mainnet`).
@@ -0,0 +1,26 @@
1
+ mycelium_cli/__init__.py,sha256=tpCzAXMonpTR8IZGY0iylQ4F7z53U94PimWsUmz9WkE,23
2
+ mycelium_cli/config.py,sha256=6sGrJxXgRfC6PkpgZneDRAi41NFKxl3jjInsHiWWR98,1469
3
+ mycelium_cli/main.py,sha256=a-YO4uwn_9mud3LrIvFr0Hx7koNf0RKPdAfDoTCNlFg,12174
4
+ mycelium_cli/commands/__init__.py,sha256=2bKymwd1hBv5CD-sr9Fi7PRbj6EfrtzlFX9CoKerQtU,26
5
+ mycelium_cli/commands/agent.py,sha256=c-lzZhN3F9kCP_NCAE3abcSdAIUG09KXtCXkaoKDcxI,2869
6
+ mycelium_cli/commands/call.py,sha256=1lJKLv-dPLMyPQQGjQ0c5EHJhpazPy33LqYgvBa-UrM,3117
7
+ mycelium_cli/commands/check.py,sha256=4jn47BAtpUwqajFeE4_lwozEbA8seURz2medy0mXsNc,662
8
+ mycelium_cli/commands/compile.py,sha256=uM1OCN9s0w1TKPYH7I6-tCFwc3cG7ztk15-TsrlnTQs,1962
9
+ mycelium_cli/commands/deploy.py,sha256=0o7uSyEJd1uuUQn7aeeWBeegyab5uKz-AQ4BtM0D8Ws,4993
10
+ mycelium_cli/commands/discover.py,sha256=SNNyeZzc-G8WqvGi5oQx0A9dI7CiZiJBNLPwF_RWxW0,2495
11
+ mycelium_cli/commands/doctor.py,sha256=TzKR14VHSGVD0BBDIDo1QqG1j8frUlQJpsxHgYkDbSs,3586
12
+ mycelium_cli/commands/events.py,sha256=M2jvIMJSZRFHWViawxLu3TrHJqmBhMOXuD1PMPKhik0,4068
13
+ mycelium_cli/commands/fund.py,sha256=CmXjmSOS7L3zJbuC1ZfcLE8P-NWclomG8nU8wCCTxp4,2148
14
+ mycelium_cli/commands/init.py,sha256=qXdp0N6-gFHp3MYP0yY6odh8J9p8VQXPDVSFiXOyA4A,6579
15
+ mycelium_cli/commands/newwallet.py,sha256=Fmu_GDVjeZyWX3S8dyMHzDw4j-65FtQKwaqKPO-zH-A,2053
16
+ mycelium_cli/commands/pay.py,sha256=8On-vC-5IAeBb8VEXNfZU0lTLfpVPpn_JfwTLCbNmGw,2905
17
+ mycelium_cli/commands/register.py,sha256=rKYPk4-EUcUDEV4O6OAy1z-NO3bO-BuA78Xlpr8x8Kg,2425
18
+ mycelium_cli/commands/resolve.py,sha256=NOsUOqV-Pe_P8nz_3agHbEUzEK5t8FyAI7i5vcMN-Do,1939
19
+ mycelium_cli/commands/run.py,sha256=foQSkQxq4qcft6hZXr68mzxQq00B-3fbPLiRUv5b5hs,1208
20
+ mycelium_cli/commands/status.py,sha256=ydVsmbTefvfP08doUXB1dPWerRjfSbWZOY89an1nJYQ,4295
21
+ mycelium_cli/commands/test.py,sha256=wmltJEVD8GQnKBoUwxPv3P9gxQVU1tURqsc3ijze-W0,2703
22
+ mycelium_cli-0.1.0.dist-info/METADATA,sha256=kpBlnMOZYNwT88E8lVxWFpp4RiloAiyijyXErztqhXU,8901
23
+ mycelium_cli-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
24
+ mycelium_cli-0.1.0.dist-info/entry_points.txt,sha256=i9ViGx8gDutPLaEaPtl77T2u-WVOVZFWz3I8Bo1viqg,52
25
+ mycelium_cli-0.1.0.dist-info/top_level.txt,sha256=TiBW8eXzuqoNq1iHWzrjkpZ1RK2TXNd144SXBzcICds,13
26
+ mycelium_cli-0.1.0.dist-info/RECORD,,