Commit 46d370e
feat: instance profiles for multi-instance config (#64)
* feat: add instance profiles for multi-instance config
Adds named instance configurations stored in ~/.ascend-tools/config.toml,
similar to Snowflake CLI connections or AWS profiles. Users can configure
multiple Ascend instances and switch between them with --instance <name>
or ASCEND_INSTANCE env var.
Config resolution order: CLI flags > instance config > env vars > error.
Fully backward compatible — existing env var workflows continue to work
unchanged when no config file is present.
Key changes:
- New InstanceEntry type and TOML config file parsing in ascend-tools-core
- Config::with_overrides_and_instance() method with 4-level resolution
- instance_config module for add/remove/list/set-default operations
- New `instance` CLI subcommand (add, list, remove, set-default)
- Global --instance flag and ASCEND_INSTANCE env var support
- Python Client(instance="staging") and JS Client(null, null, null, "staging")
- service_account_key_env field stores env var name (never the secret)
- Uses toml_edit for format-preserving config file writes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use print_subcommand_help for instance command consistency
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: rename --service-account-key-env to --key-env on instance add
Avoids confusion with the global --service-account-key flag. Clap was
suggesting --service-account-key (the actual secret) when users mistyped
--service-account-key-env (the env var name). Shorter flag is clearer.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: revert to --service-account-key-env flag name
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: remove Clap env= on auth flags so instance config takes priority
Clap's env attribute reads env vars and treats them as CLI-level
overrides, which meant shell env vars always won over instance config.
The config module already handles env vars as a proper fallback, so
Clap's env handling was redundant and broke the resolution order.
Also fix integration tests to pass auth via CLI flags (highest priority)
so they're immune to config file state on the test machine.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: harden instance config management
- Fix double config file read in load_instance_entry error path by using
remove_entry() instead of into_iter().find() + redundant load
- Add instance name validation (alphanumeric, hyphens, underscores only;
reject reserved "default_instance" key)
- Auto-set default_instance on first instance add when no default exists
- Clear dangling default_instance reference when removing the default instance
- Show effective key_env in instance add confirmation message
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test: comprehensive coverage for instance config
Refactor config internals to separate pure logic from I/O:
- Extract select_instance_entry() for testable instance routing
- Add path-parameterized CRUD helpers (add_at, remove_at, etc.)
Add 25 new tests covering all previously untested branches:
- select_instance_entry: all 8 routing paths (explicit found/not-found,
default found/missing, implicit fallback, available list)
- parse_config_toml edge cases: only-default-key, non-table values
ignored, wrong-type fields error, extra fields forward compat
- CRUD filesystem tests: add creates file + auto-sets default, second
add preserves default, add rejects invalid names, update existing,
remove instance, remove clears dangling default, remove nonexistent
errors, list empty/nonexistent, set-default, set-default nonexistent
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: add instance profiles documentation across all SDKs
- CLI: add instance config section, resolution order, manage instances
- Python: document Client(instance="staging") and resolution order
- JavaScript: document named instance constructor pattern
- Rust: document Config::with_overrides_and_instance()
- MCP: document config.toml and ASCEND_INSTANCE inheritance
- Fix rustfmt formatting in config.rs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: deduplicate instance config CRUD and eliminate magic strings
- Extract load_document(), load_or_create_document(), save_document()
helpers to remove 3x read+parse and 3x write boilerplate
- Extract available_instances() helper for 2x duplicate listing pattern
- Add DEFAULT_INSTANCE_KEY and DEFAULT_INSTANCE_NAME constants replacing
12 "default_instance" and 2 "default" magic string literals
- Use print_json() in instance list for consistency with other CLI handlers
- Remove unused config_dir_path()
- Remove unnecessary WHAT comments
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>1 parent bc92c2a commit 46d370e
File tree
20 files changed
+1493
-65
lines changed- crates
- ascend-tools-cli
- src
- tests
- ascend-tools-core
- src
- ascend-tools-js
- src
- ascend-tools-py/src
- docs
- tests/app
20 files changed
+1493
-65
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
31 | | - | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
32 | 66 | | |
33 | 67 | | |
34 | 68 | | |
| |||
38 | 72 | | |
39 | 73 | | |
40 | 74 | | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
41 | 82 | | |
42 | 83 | | |
43 | 84 | | |
| |||
49 | 90 | | |
50 | 91 | | |
51 | 92 | | |
52 | | - | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
53 | 99 | | |
54 | 100 | | |
55 | 101 | | |
| |||
138 | 184 | | |
139 | 185 | | |
140 | 186 | | |
141 | | - | |
| 187 | + | |
142 | 188 | | |
143 | 189 | | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
144 | 193 | | |
145 | 194 | | |
146 | 195 | | |
| |||
194 | 243 | | |
195 | 244 | | |
196 | 245 | | |
197 | | - | |
| 246 | + | |
198 | 247 | | |
199 | 248 | | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
200 | 252 | | |
201 | 253 | | |
202 | 254 | | |
| |||
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| 11 | + | |
11 | 12 | | |
12 | 13 | | |
13 | 14 | | |
| |||
24 | 25 | | |
25 | 26 | | |
26 | 27 | | |
27 | | - | |
28 | | - | |
29 | | - | |
30 | | - | |
31 | | - | |
32 | | - | |
33 | | - | |
| 28 | + | |
| 29 | + | |
34 | 30 | | |
35 | 31 | | |
36 | | - | |
37 | | - | |
38 | | - | |
39 | | - | |
40 | | - | |
41 | | - | |
42 | | - | |
| 32 | + | |
| 33 | + | |
43 | 34 | | |
44 | 35 | | |
45 | | - | |
46 | | - | |
| 36 | + | |
| 37 | + | |
47 | 38 | | |
48 | 39 | | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
49 | 44 | | |
50 | 45 | | |
51 | 46 | | |
| |||
132 | 127 | | |
133 | 128 | | |
134 | 129 | | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
135 | 143 | | |
136 | 144 | | |
137 | 145 | | |
| |||
173 | 181 | | |
174 | 182 | | |
175 | 183 | | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
176 | 188 | | |
177 | | - | |
| 189 | + | |
178 | 190 | | |
179 | 191 | | |
180 | 192 | | |
| 193 | + | |
181 | 194 | | |
182 | 195 | | |
183 | 196 | | |
| |||
187 | 200 | | |
188 | 201 | | |
189 | 202 | | |
190 | | - | |
| 203 | + | |
191 | 204 | | |
192 | 205 | | |
193 | 206 | | |
| 207 | + | |
194 | 208 | | |
195 | 209 | | |
196 | 210 | | |
| |||
213 | 227 | | |
214 | 228 | | |
215 | 229 | | |
216 | | - | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
217 | 234 | | |
218 | 235 | | |
219 | 236 | | |
| |||
0 commit comments