@configdirector/cli 0.1.0-beta.2 → 0.8.0-beta.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/CHANGELOG.md +63 -0
- package/README.md +210 -10
- package/dist/configdirector.mjs +1633 -80
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,69 @@ All notable changes to `@configdirector/cli` are documented here. The format fol
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.8.0-beta.1] - 2026-10-18
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- `configdirector repositories list` lists the repositories whose scan was uploaded to the project, one per line, with the commit, when it was scanned in UTC, and how many references and dynamic references it holds, and ends with how many scanned repositories the project has out of the 50 it can hold, as in `web-app has 2 of the 50 scanned repositories a project can hold.` A repository uploaded without a commit shows `no commit`. With `--json`, it prints the Admin API's response as received. It needs `projects:read` and `code-references:read`.
|
|
12
|
+
- `configdirector repositories remove <name>` removes a scanned repository and all its references from the project, so a repository that was renamed or retired stops counting toward the 50, and the dashboard stops using its references to show where each config is read and which configs no repository reads. It asks for no confirmation and prints `Removed acme/storefront and its code references from web-app.`; `--json` prints `{ "removedRepository": "acme/storefront" }` with the name as given. When no scanned repository in the project has the name, it exits with 2 and lists the names the project has. It needs `projects:read` and `code-references:update`, and `code-references:read` to list the names. Removals do not appear in the audit log.
|
|
13
|
+
|
|
14
|
+
## [0.7.0-beta.1] - 2026-10-17
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- `configdirector scan --upload` sends the scan to the project, so the dashboard can show where each config is read and which configs no repository reads. Each upload replaces all the references the project held for the repository. The CLI does not check which branch is checked out, so run it on pushes to the default branch, and keep `validate` for pull requests.
|
|
19
|
+
- The repository is named after the path of its git remote `origin`, without the host and `.git`, so `https://github.com/acme/shop.git`, `git@github.com:acme/shop.git` and `ssh://git@github.com/acme/shop.git` all upload to `acme/shop`. The upload also sends the remote's URL and the commit checked out, both read by running `git`; the user name and password of an `https` remote, such as the job token GitLab CI puts there, are removed first. `--repository <name>` names the repository yourself. Without it, `scan --upload` exits with 2 when `git` is not installed, when the directory is not in a git repository, or when that repository has no `origin` remote; with it, each of those cases uploads with no remote URL and no commit. A repository with no commit yet uploads with no commit.
|
|
20
|
+
- The upload holds the references and dynamic references `scan --json` prints, whatever `ignoreKeys` lists, except a reference to a key that cannot be a config key, which is left out and counted. The output is the scan's, then a line such as `Uploaded the scan of acme/shop at 4d40f50 to web-app: 12 references and 1 dynamic reference, with 0 left out for a key that cannot be a config key.` With `--json`, it prints the Admin API's response as received.
|
|
21
|
+
- A scan that finds no source file exits with 2 and uploads nothing, so a wrong path or `include` never empties the repository's references; a scan that reads files and finds no reference uploads an empty set. When the project already holds its maximum of scanned repositories, `scan --upload` exits with 2 and names `configdirector repositories remove`. It needs `projects:read`, `configs:read` and `code-references:update`.
|
|
22
|
+
|
|
23
|
+
## [0.6.0-beta.1] - 2026-10-17
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- `configdirector configs archive <key>` archives a config: it is removed from the project and from what SDKs receive, so applications get their in-code default value for it. It can be restored from the dashboard for 30 days, and after that it is deleted for good. The key can be the config's current key or an old one.
|
|
28
|
+
- `configs archive` asks for no confirmation and does not check whether the code still reads the key, so run `configdirector scan` first. It prints `Archived new-checkout in web-app. It can be restored from the dashboard for 30 days.`, and `--json` prints `{ "archivedConfigKey": "new-checkout" }` with the key as given, as the MCP server's `archive_config` tool does. It exits with 2 when no config in the project has the key, which includes a config already archived. It needs `projects:read` and `configs:archive`. The change shows in the audit log with the source CLI.
|
|
29
|
+
|
|
30
|
+
## [0.5.0-beta.1] - 2026-10-17
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- `configdirector targeting-rules set <key> --environment <slug> --rules <file>` replaces a config's targeting rules in one environment with the rules in a JSON file, or in stdin with `--rules -`. The file holds `defaultValue`, the default targeting rule value, and `rules`, exactly as the Admin API takes them, so you can take an environment's entry of `targets` from `configs get --json`, edit it and write it back. Every rule of the environment is replaced. A rule, condition or percentage without an `id` gets a new one, and the IDs given are kept. The CLI checks only that the file holds a JSON object: ConfigDirector checks the rules, and when it refuses them `set` exits with 2 and lists its reasons.
|
|
35
|
+
- `targeting-rules set` asks for no confirmation and treats a live environment like any other. It prints the key, the environment, the number of rules and the default targeting rule value it wrote. `--json` prints the request it sent, with the IDs it gave, since the Admin API answers with no body. It exits with 2 when no config in the project has the key, or when no environment has the slug, listing the project's environment slugs. It needs `projects:read`, `environments:read` and `config-targeting-rules:update`. The change shows in the audit log with the source CLI.
|
|
36
|
+
- `configdirector targeting-rules reference` prints the format targeting rules take: notes on how rules are evaluated, then the condition kinds, the attributes a condition can test, the context kind operators, the segment operators and the operators for each target type. `--json` prints the whole document as received, including the JSON Schema of the request `targeting-rules set` sends. It needs an API token, with any permissions, and no project. The notes are the ones the MCP server's `get_targeting_rules_reference` tool gives, so they name the MCP tools: `update_targeting_rules` is what `targeting-rules set` does, and `get_config` what `configs get` does.
|
|
37
|
+
|
|
38
|
+
## [0.4.0-beta.1] - 2026-10-17
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- `configdirector configs create` creates a config from options that match the Admin API's fields one to one, with no guessing and no prompts. `--key`, `--type`, `--role`, `--lifetime` and `--default-value` are required; `--default-value` is the default targeting rule value every environment starts with, not the in-code default value. `--description`, `--client-only` or `--server-only` (client and server SDKs without either), `--tag <name>`, repeatable, naming an existing tag, and `--variation <name=value>`, repeatable, for an experiment, are optional.
|
|
43
|
+
- The values of `--default-value` and `--variation` are read in the config's type: `true` or `false`, a number, text, or JSON for a JSON config, with `@file` reading the JSON from a file. A value that does not fit the type is a usage error, and nothing is sent.
|
|
44
|
+
- Constraint options, each accepted only by its types: `--min` and `--max`, which a value may equal, for an integer, float or timespan; `--exclusive-min` and `--exclusive-max` for an integer or float; `--unit` and `--allow-fractions` for a timespan, which needs `--unit`, `--min` and `--max`; `--allowed-value`, repeatable, and `--enum-value-type string|number` (default `string`) for an enum; `--https-only` for a URL, without which any HTTP or HTTPS URL is accepted; and `--json-schema <file>` for a JSON config. An option of another type is a usage error naming the types it belongs to. A timespan without `--unit`, `--min` or `--max` is a usage error too. `configs create --help` lists them grouped by type.
|
|
45
|
+
- `configs create` prints the created config's key, type, role, lifetime and availability, and the default targeting rule value every environment starts with; `--json` prints the created config as received. When the project already has a config with the key, nothing is created: it prints that config's key, type, role, lifetime and lifecycle state and exits with 1, and `--json` prints that config as received. Any other refusal exits with 2 and lists the Admin API's reasons. It needs `projects:read`, `configs:create` and `configs:read`, and `tags:read` and `config-settings:update` for `--tag`. The config shows in the audit log with the source CLI.
|
|
46
|
+
|
|
47
|
+
## [0.3.0-beta.1] - 2026-10-17
|
|
48
|
+
|
|
49
|
+
### Added
|
|
50
|
+
|
|
51
|
+
- `configdirector projects list` lists your organization's projects with their slugs and names, whichever project `--project`, `CONFIGDIRECTOR_PROJECT` or `configdirector.json` selects.
|
|
52
|
+
- `configdirector environments list` lists the project's environments with their slugs and names, marking the live ones.
|
|
53
|
+
- `configdirector configs list` lists the project's configs with their type, role, lifetime and lifecycle state. `--tag <name>`, repeatable, lists the configs that have any of the tags, and a name no tag has exits with 2; it needs the `tags:read` permission. `--untagged` lists the configs without tags and cannot be combined with `--tag`. `--state <state>` lists the configs in one lifecycle state: `new`, `in-use`, `settled`, `archive-ready` or `stale`.
|
|
54
|
+
- `configdirector configs get <key>` shows a config's settings, including its type's constraints, then its targeting rules in every environment, written as `evaluate` writes them, with the default targeting rule value last. A segment condition names the segment, or shows its ID when the token lacks `segments:read`. An old key works, and the output says which key is current.
|
|
55
|
+
- `configdirector configs activity <key>` shows when SDKs last evaluated a config, one line per environment, SDK key kind, SDK name and SDK version, with the time in UTC.
|
|
56
|
+
- `configdirector segments list` lists the project's segments with how many configs use each, and `configdirector segments get <key>` shows a segment's condition groups and its environment overrides, naming each override's environment by its slug, or by its ID when the token lacks `environments:read`.
|
|
57
|
+
- With `--json`, each new command prints the Admin API's response as received, except `configs list --state`, which prints only the configs in that state. A key no config or segment has exits with 2. Every new command but `projects list` takes the project from `--project`, `CONFIGDIRECTOR_PROJECT` or `configdirector.json`, as `scan` does.
|
|
58
|
+
- `scan` finds the calls of a Kotlin, Java or C# file that reaches the client through a class of your own whose file imports the SDK, such as `Flags.client.getBoolean("new-checkout", false)` with an `object Flags` holding the client, in a file that never names the SDK. The class must be in a file named after it, such as `Flags.kt`, `Flags.java` or `Flags.cs`. Kotlin and Java find it through an import, a static import, a wildcard import, or in the file's own directory for a class of the same package; C# finds it anywhere in the project of the nearest `.csproj`, so a global using of the SDK's namespace works. Only that one class is read, not the classes it uses in turn, and a Kotlin client declared at the top level of a file is not followed. A call that only looks like an SDK call, such as Android's `SharedPreferences.getBoolean` or ASP.NET's `IConfiguration.GetValue`, is still not reported in a file that uses no such class.
|
|
59
|
+
|
|
60
|
+
## [0.2.0-beta.1] - 2026-10-17
|
|
61
|
+
|
|
62
|
+
### Added
|
|
63
|
+
|
|
64
|
+
- `configdirector evaluate <key> --environment <slug>` shows the value a context gets for a config in an environment, and why. It uses the evaluator the SDKs use, so the value is the one your application gets.
|
|
65
|
+
- `evaluate` prints the value and the rule that served it, or the default targeting rule. Then it lists each rule in order with what it tests and its outcome. A rule that did not match names the first condition that failed and the context's value for it, or the bucket a percentage rollout put the context in. A rule after the one that served the value is not evaluated, and a rule that could not be evaluated is shown as errored.
|
|
66
|
+
- An old key of a renamed config evaluates the config, and the output says which key is current. `--json` prints the Admin API's response as received. Nothing is recorded: an evaluation from the CLI is not SDK activity.
|
|
67
|
+
- `evaluate` takes the context one of three ways. `--context-kind` (default `user`), `--context-id`, `--context-name` and the repeatable `--context-trait name=value` give it option by option, and `name:=<json>` gives a trait a number, boolean, array or object value, as in `--context-trait beta:=true`. `--context-json '{...}'` or `--context-json @file` gives the whole context as a JSON object. `--saved-context <kind>:<identifier>` names a context ConfigDirector saved from SDK evaluations in that environment. Combining two of these ways is a usage error. With none, the config is evaluated for an empty context, as an SDK given none would.
|
|
68
|
+
- `evaluate` needs the `environments:read` permission as well as `projects:read` and `configs:read`, and `contexts:read` for `--saved-context`. It exits with 2 when no config in the project has the key, when no environment has the slug, listing the project's environment slugs, or when no saved context in the environment has the context kind and identifier. The project comes from `--project`, `CONFIGDIRECTOR_PROJECT` or `configdirector.json`, as for `scan`.
|
|
69
|
+
|
|
7
70
|
## [0.1.0-beta.2] - 2026-10-16
|
|
8
71
|
|
|
9
72
|
### Changed
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ConfigDirector CLI
|
|
2
2
|
|
|
3
|
-
`configdirector` is the command line tool for [ConfigDirector](https://www.configdirector.com), the managed configuration and feature flag service. It is in beta: commands and output may change before 1.0. This release signs in, links a repository to a project, lists where the repository's code reads config keys,
|
|
3
|
+
`configdirector` is the command line tool for [ConfigDirector](https://www.configdirector.com), the managed configuration and feature flag service. It is in beta: commands and output may change before 1.0. This release signs in, links a repository to a project, lists where the repository's code reads config keys, checks those keys against the project's configs, shows the value a context gets for a config and why, reads a project's environments, configs, targeting rules and segments, creates configs, replaces a config's targeting rules in an environment, archives configs, uploads the repository's code references to the project, and lists and removes the project's scanned repositories.
|
|
4
4
|
|
|
5
5
|
The [CLI page of the ConfigDirector docs](https://docs.configdirector.com/integrations/cli) covers the API token, CI setup for GitHub Actions and GitLab, and what each problem `validate` reports means for your build.
|
|
6
6
|
|
|
@@ -46,14 +46,55 @@ A call that passes a constant instead of a string is reported under the constant
|
|
|
46
46
|
|
|
47
47
|
The scan also looks for the project's current and deprecated keys wherever they appear as a quoted string outside those calls, such as in a wrapper function, a key list or a test fixture, and reports each as an indirect reference under its key. An indirect reference in a test directory or a test-named file, such as `test/`, `checkout.test.ts`, `checkout_test.go`, `test_checkout.py` or `CheckoutTests.cs`, is marked as a test, whereas a direct reference is marked as a test only when the call is a test client call. The definition of a constant that an SDK call reads is not repeated as an indirect reference.
|
|
48
48
|
|
|
49
|
-
A call is found when its file imports the SDK, or imports a file of the repository that does, such as the setup module the SDK docs create. In Swift and Go, it is also found when another file of the same Swift target or Go package imports the SDK, since those files use each other's declarations without an import. A `getValue` from another library is not reported unless its file,
|
|
49
|
+
A call is found when its file imports the SDK, or imports a file of the repository that does, such as the setup module the SDK docs create. In Swift and Go, it is also found when another file of the same Swift target or Go package imports the SDK, since those files use each other's declarations without an import. In Kotlin, Java and C#, it is also found when the file uses a class of your own whose file imports the SDK, such as an `object Flags` or a static class that holds the client. A `getValue` from another library is not reported unless its file, its Swift target or Go package, or a class of your own that it uses imports one of those, so Android's `SharedPreferences.getBoolean` and ASP.NET's `IConfiguration.GetValue` are not reported next to a class that holds the client. Imports are followed one level deep: relative imports and path aliases in JavaScript and TypeScript, Python modules, Dart files including your own `package:` imports, and Go packages of the same module. When the imported file does not import the SDK itself, the scan follows what it re-exports, up to two steps, so an `index` file or a barrel library in front of the setup module works: `export { client } from "./setup"` and `export * from "./setup"` in JavaScript and TypeScript, `export 'src/setup.dart';` in Dart, and relative imports such as `from .flags import client` in a Python package's `__init__.py`. A file that reaches the client through a second ordinary import, a re-export written as an import followed by a separate `export`, or a CommonJS `module.exports` is not scanned. A Go package is the `.go` files of one directory with the same `package` name, so an external test package such as `package shop_test` counts only through its own imports. A Swift target is found from the nearest `Package.swift` or Xcode project above the file: in a Swift package, each directory under `Sources/` or `Tests/` is a target; an Xcode project's directory is one target; with neither, the file's own directory is. A class of your own counts when its file is named after it, such as `Flags.kt`, `Flags.java` or `Flags.cs`, and only that class is read, not the classes it uses in turn. Kotlin and Java find it through the file's imports, including `import static` and wildcard imports, under the source directory its `package` points to, and among the files of its own directory, so a class of the same package in another source directory or module, such as a test in `src/test/java` using a class of `src/main/java`, is not followed. When the directory does not match the `package`, as when the directories leave out the common root package, the imports are not followed. C# finds it as a `.cs` file of that name anywhere in the project of the nearest `.csproj`, outside `bin`, `obj` and the directories the scan always skips, whatever brings the SDK's namespace in, a global using included. A Kotlin client declared at the top level of a file, outside any object or class, is not followed. Nuxt's auto-imported composables need no import. A Kotlin or Java file belongs to the Android SDK when the nearest Gradle build file above it is an Android module, and to the Java server SDK otherwise. A Nuxt file belongs to the Nuxt server SDK when it is in the `server` directory next to the nearest `nuxt.config`, and to the Nuxt client SDK otherwise; a Next.js file belongs to the client or the server SDK by the entry point it imports.
|
|
50
50
|
|
|
51
|
-
A path alias such as `@/lib/config-director` is resolved the way TypeScript resolves it, from `compilerOptions.paths` and `baseUrl` in the nearest `tsconfig.json` above the importing file, or `jsconfig.json` when that directory has no `tsconfig.json`. Configs it extends with a relative path count, and when it declares no aliases of its own, the configs listed in its `references` are tried in order, as in Vite's templates. Nuxt's `~` and `@` aliases work once `nuxt prepare`, a dev run or a build has generated the `.nuxt` configs. Aliases set only in bundler configuration, such as `resolve.alias` in `vite.config.ts` or webpack, are not followed. These configs and the files they point to, like the other files of a Swift target or Go package, are read even when the scan would skip them, as long as they are under 1 MB.
|
|
51
|
+
A path alias such as `@/lib/config-director` is resolved the way TypeScript resolves it, from `compilerOptions.paths` and `baseUrl` in the nearest `tsconfig.json` above the importing file, or `jsconfig.json` when that directory has no `tsconfig.json`. Configs it extends with a relative path count, and when it declares no aliases of its own, the configs listed in its `references` are tried in order, as in Vite's templates. Nuxt's `~` and `@` aliases work once `nuxt prepare`, a dev run or a build has generated the `.nuxt` configs. Aliases set only in bundler configuration, such as `resolve.alias` in `vite.config.ts` or webpack, are not followed. These configs and the files they point to, like the other files of a Swift target or Go package and the Kotlin, Java and C# classes a file uses, are read even when the scan would skip them, as long as they are under 1 MB; only C# classes in `bin`, `obj` and the directories the scan always skips are not looked for.
|
|
52
52
|
|
|
53
53
|
The scan skips what `.gitignore` ignores, the `node_modules`, `vendor`, `build`, `dist` and `target` directories, binary files and files over 1 MB. In `configdirector.json`, `include` limits the scan to the files matching its globs, and `exclude` skips the files matching its globs.
|
|
54
54
|
|
|
55
55
|
With `--json`, `scan` prints the references for scripts and CI; `schema/scan-output.schema.json` in the package describes that output. Each reference has a `kind`, `direct` or `indirect`, and a direct reference resolved from a constant carries the constant as `argument`.
|
|
56
56
|
|
|
57
|
+
## Upload the scan to ConfigDirector
|
|
58
|
+
|
|
59
|
+
From the repository root, on the default branch:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
configdirector scan --upload
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`--upload` sends the scan to the project, so the dashboard can show where each config is read and which configs no repository reads. Each upload replaces all the references the project held for the repository. The CLI does not check which branch is checked out, so run it on pushes to the default branch, and keep `validate` for pull requests.
|
|
66
|
+
|
|
67
|
+
The repository is named after the path of its git remote `origin`, without the host and `.git`: `https://github.com/acme/shop.git`, `git@github.com:acme/shop.git` and `ssh://git@github.com/acme/shop.git` all upload to `acme/shop`, and a GitLab subgroup keeps its whole path, such as `group/subgroup/app`. The upload also sends the remote's URL, without the user name and password of an `https` remote, such as the job token GitLab CI puts there, and the commit checked out, both read by running `git`. `--repository <name>` names the repository yourself. Without it, `scan --upload` exits with 2 when `git` is not installed, when the directory is not in a git repository, or when that repository has no `origin` remote; with it, each of those cases uploads with no remote URL and no commit. A repository with no commit yet uploads with no commit.
|
|
68
|
+
|
|
69
|
+
The upload holds the references and dynamic references `scan --json` prints, whatever `ignoreKeys` lists, except a reference to a key that cannot be a config key, such as one shorter than 4 characters, which is left out and counted. The output is the scan's, then a line naming the repository, the commit, the project, how many references were sent and how many were left out. A scan that finds no source file exits with 2 and uploads nothing, so a wrong path or `include` never empties the repository's references; a scan that reads files and finds no reference uploads an empty set. With `--json`, it prints the Admin API's response as received.
|
|
70
|
+
|
|
71
|
+
A project holds at most 50 scanned repositories, and one upload holds at most 10,000 references, dynamic references included; going over either exits with 2. `scan --upload` needs `projects:read`, `configs:read` and `code-references:update`. Uploads do not appear in the audit log.
|
|
72
|
+
|
|
73
|
+
## List and remove scanned repositories
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
configdirector repositories list
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`repositories list` lists the repositories whose scan was uploaded to the project, one per line, with the commit, when it was scanned in UTC, and how many references and dynamic references it holds, and ends with how many scanned repositories the project has out of the 50 it can hold:
|
|
80
|
+
|
|
81
|
+
```txt
|
|
82
|
+
ConfigDirector/cli 4d40f50 2026-10-17 10:00 UTC 12 references 1 dynamic reference
|
|
83
|
+
acme/storefront 9f3e2a1 2026-10-16 09:12 UTC 1 reference 0 dynamic references
|
|
84
|
+
|
|
85
|
+
web-app has 2 of the 50 scanned repositories a project can hold.
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
A repository uploaded without a commit shows `no commit`. With `--json`, it prints the Admin API's response as received, which also holds each repository's remote URL and how many files its scan read. `repositories list` needs `projects:read` and `code-references:read`.
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
configdirector repositories remove acme/storefront
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Nothing removes a scanned repository on its own: a repository that is renamed or retired keeps its last upload, keeps counting toward the 50, and the dashboard keeps using its references to show where each config is read and which configs no repository reads. `repositories remove <name>` removes the repository and all its references from the project, with no confirmation, and prints `Removed acme/storefront and its code references from web-app.` To rename a repository, remove the old name and upload under the new one; a removed repository that uploads again is added back. When no scanned repository in the project has the name, it exits with 2 and lists the names the project has. With `--json`, it prints `{ "removedRepository": "acme/storefront" }`, with the name as given.
|
|
95
|
+
|
|
96
|
+
`repositories remove` needs `projects:read` and `code-references:update`, and `code-references:read` to list the names when none matches. Removals do not appear in the audit log.
|
|
97
|
+
|
|
57
98
|
## Check the keys the code reads
|
|
58
99
|
|
|
59
100
|
From the repository root, or as a CI step:
|
|
@@ -74,16 +115,175 @@ A test client call, such as `setValue` or `createTestClient`, is checked for unk
|
|
|
74
115
|
|
|
75
116
|
The output lists the problems grouped by kind, with the file, the line, the key and what is wrong, such as the type a timespan is served as, then counts the references checked. With `--json`, `validate` prints the scan's JSON with a `findings` array; `schema/scan-output.schema.json` describes it.
|
|
76
117
|
|
|
118
|
+
## See what a context gets for a config
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
configdirector evaluate new-checkout --environment production --context-id 123 --context-trait plan=pro
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
`evaluate` evaluates the environment's saved targeting rules for a context with the evaluator the SDKs use, so the value it shows is the one your application gets. It also shows the rule that served the value, and what each rule tests and what happened to it:
|
|
125
|
+
|
|
126
|
+
```txt
|
|
127
|
+
new-checkout in Production for user 123
|
|
128
|
+
|
|
129
|
+
true, served by rule 2
|
|
130
|
+
|
|
131
|
+
1. 50% get true not matched: bucket 71.3 is outside 0 to 50
|
|
132
|
+
2. plan is one of pro, team: true matched
|
|
133
|
+
3. in segment Beta testers: true not evaluated
|
|
134
|
+
Default targeting rule: false
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
A rule that did not match names the first condition that failed and the context's value for it, as in `plan is one of pro, team, but it is "free"`, or the bucket a percentage rollout put the context in. A rule after the one that served the value is not evaluated, and a rule that could not be evaluated is shown as errored.
|
|
138
|
+
|
|
139
|
+
`--environment` takes the environment's slug and is required. Give the context one of three ways:
|
|
140
|
+
|
|
141
|
+
- `--context-kind` (default `user`), `--context-id`, `--context-name`, and `--context-trait name=value` for each trait. A trait's value is a string; write `name:=` followed by JSON for a number, boolean, array or object, as in `--context-trait beta:=true` or `--context-trait age:=30`. For nested traits, use `--context-json`.
|
|
142
|
+
- `--context-json '{"identifier": "123", "traits": {"plan": "pro"}}'`, or `--context-json @context.json` to read it from a file. The object takes `kind`, `identifier`, `name` and `traits`.
|
|
143
|
+
- `--saved-context user:123`, the context kind and identifier of a context ConfigDirector saved from SDK evaluations in that environment. It is evaluated with its stored name and traits.
|
|
144
|
+
|
|
145
|
+
Without any of them, the config is evaluated for an empty context, as an SDK given none would. A renamed config can be evaluated by an old key; the output then starts with a line naming the current key. With `--json`, `evaluate` prints the Admin API's response as received.
|
|
146
|
+
|
|
147
|
+
`evaluate` needs a token with `environments:read` as well as `projects:read` and `configs:read`, and `contexts:read` for `--saved-context`. Nothing is recorded: an evaluation from the CLI is not SDK activity.
|
|
148
|
+
|
|
149
|
+
## Browse the project
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
configdirector projects list
|
|
153
|
+
configdirector environments list
|
|
154
|
+
configdirector configs list [--tag <name>] [--untagged] [--state <state>]
|
|
155
|
+
configdirector configs get <key>
|
|
156
|
+
configdirector configs activity <key>
|
|
157
|
+
configdirector segments list
|
|
158
|
+
configdirector segments get <key>
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
`projects list` lists your organization's projects with their slugs and names, whichever project is selected. The other commands read the project from `--project`, `CONFIGDIRECTOR_PROJECT` or `configdirector.json`, as `scan` does:
|
|
162
|
+
|
|
163
|
+
- `environments list` lists the environments with their slugs and names, marking the live ones.
|
|
164
|
+
- `configs list` lists the configs with their type, role, lifetime and lifecycle state. `--tag <name>`, repeatable, lists the configs that have any of the tags; `--untagged` lists the configs without tags and cannot be combined with `--tag`; `--state` lists the configs in one lifecycle state: `new`, `in-use`, `settled`, `archive-ready` or `stale`. A tag name no tag has exits with 2.
|
|
165
|
+
- `configs get <key>` shows the config's settings, including its type's constraints, then each environment's targeting rules in order, written as `evaluate` writes them, with the default targeting rule value last. An old key works, and the output then starts with a line naming the current key.
|
|
166
|
+
- `configs activity <key>` shows when SDKs last evaluated the config, one line per environment, SDK key kind, SDK name and SDK version, with the time in UTC.
|
|
167
|
+
- `segments list` lists the segments with how many configs use each, and `segments get <key>` shows a segment's condition groups and its environment overrides.
|
|
168
|
+
|
|
169
|
+
```txt
|
|
170
|
+
new-checkout
|
|
171
|
+
Description: Shows the new checkout flow
|
|
172
|
+
Type: boolean
|
|
173
|
+
Role: flag
|
|
174
|
+
Lifetime: temporary
|
|
175
|
+
Availability: client and server SDKs
|
|
176
|
+
Lifecycle state: in-use
|
|
177
|
+
Tags: checkout
|
|
178
|
+
|
|
179
|
+
test
|
|
180
|
+
Default targeting rule: false
|
|
181
|
+
|
|
182
|
+
production (live)
|
|
183
|
+
1. plan is one of pro, team: true
|
|
184
|
+
2. 30% get true, 70% get false
|
|
185
|
+
3. in segment Beta testers: true
|
|
186
|
+
Default targeting rule: false
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
With `--json`, each prints the Admin API's response as received, except `configs list --state`, which prints only the configs in that state. A key no config or segment has exits with 2.
|
|
190
|
+
|
|
191
|
+
`projects list` needs `projects:read`. The others need `projects:read` to find the project, and `environments list` needs `environments:read`, `configs list`, `configs get` and `configs activity` need `configs:read`, plus `tags:read` for `--tag`, and `segments list` and `segments get` need `segments:read`. Without `segments:read`, `configs get` shows a segment condition's segment ID instead of its name; without `environments:read`, `segments get` names an override's environment by its ID instead of its slug.
|
|
192
|
+
|
|
193
|
+
## Create a config
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
configdirector configs create --key new-checkout --type boolean --role flag --lifetime temporary --default-value false
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
`configs create` creates a config from options that match the Admin API's fields one to one, with no guessing and no prompts:
|
|
200
|
+
|
|
201
|
+
```txt
|
|
202
|
+
Created new-checkout in web-app: boolean, flag, temporary, client and server SDKs.
|
|
203
|
+
Default targeting rule in every environment: false
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
- `--key`, `--type` (`boolean`, `string`, `integer`, `float`, `timespan`, `enum`, `url` or `json`), `--role` (`config`, `flag`, `kill-switch` or `experiment`), `--lifetime` (`temporary` or `permanent`) and `--default-value` are required. `--default-value` is the default targeting rule value every environment starts with, not the in-code default value an application passes to the SDK.
|
|
207
|
+
- `--description <text>`; `--client-only` or `--server-only`, without which client and server SDKs both receive the config; `--tag <name>`, repeatable, naming an existing tag of the project; and `--variation <name=value>`, repeatable, for an experiment's variations.
|
|
208
|
+
- The values of `--default-value` and `--variation` are read in the config's type: `true` or `false`, a number for an integer, float or timespan, the text as written for a string, enum or URL, and JSON for a JSON config, with `@file` reading it from a file. A value that does not fit the type is a usage error.
|
|
209
|
+
- Constraints, each accepted only by its types: `--min` and `--max` (a value may equal them) for an integer, float or timespan; `--exclusive-min` and `--exclusive-max` for an integer or float; `--unit` (`milliseconds`, `seconds` or `minutes`) and `--allow-fractions` for a timespan, which needs `--unit`, `--min` and `--max`; `--allowed-value`, repeatable, and `--enum-value-type string|number` (default `string`) for an enum; `--https-only` for a URL, without which any HTTP or HTTPS URL is accepted; and `--json-schema <file>` for a JSON config. An option of another type is a usage error naming the types it belongs to. A timespan without `--unit`, `--min` or `--max` is a usage error too.
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
configdirector configs create --key checkout-timeout --type timespan --role config --lifetime permanent \
|
|
213
|
+
--unit seconds --min 1 --max 120 --default-value 30 --server-only
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
When the project already has a config with the key, as its current key or an old one, nothing is created: the command prints that config's key, type, role, lifetime and lifecycle state, and exits with 1. When ConfigDirector refuses the config for another reason, it exits with 2 and lists the reasons. With `--json`, it prints the created config as received, or the existing config when the key is taken.
|
|
217
|
+
|
|
218
|
+
`configs create` needs `projects:read`, `configs:create`, and `configs:read` to show the config that already has the key; `--tag` also needs `tags:read` and `config-settings:update`. The config shows in the audit log with the source CLI.
|
|
219
|
+
|
|
220
|
+
## Change targeting rules
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
configdirector targeting-rules set new-checkout --environment production --rules rules.json
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
`targeting-rules set` replaces every targeting rule of the config in one environment with the rules in the file, or in stdin with `--rules -`:
|
|
227
|
+
|
|
228
|
+
```json
|
|
229
|
+
{
|
|
230
|
+
"defaultValue": false,
|
|
231
|
+
"rules": [
|
|
232
|
+
{
|
|
233
|
+
"type": "conditional",
|
|
234
|
+
"order": 0,
|
|
235
|
+
"conditions": [
|
|
236
|
+
{
|
|
237
|
+
"kind": "attribute",
|
|
238
|
+
"attribute": "traits",
|
|
239
|
+
"trait": "/plan",
|
|
240
|
+
"operator": "is one of",
|
|
241
|
+
"targetType": "text",
|
|
242
|
+
"targetValues": ["pro", "team"]
|
|
243
|
+
}
|
|
244
|
+
],
|
|
245
|
+
"target": "value",
|
|
246
|
+
"value": true
|
|
247
|
+
}
|
|
248
|
+
]
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
- The file holds `defaultValue`, the default targeting rule value, and `rules`, exactly as the Admin API takes them. An environment's entry of `targets` in `configs get --json` has that shape, so you can edit it and write it back. Rules left out of the file are removed.
|
|
253
|
+
- A rule, condition or percentage without an `id` gets a new one, and the IDs given are kept.
|
|
254
|
+
- The CLI checks only that the file holds a JSON object. ConfigDirector checks the rules, and when it refuses them the command exits with 2 and lists its reasons.
|
|
255
|
+
- It asks for no confirmation and treats a live environment like any other. It prints what it wrote: `Replaced the targeting rules of new-checkout in production with 1 rule and the default targeting rule value false.` With `--json`, it prints the request it sent, with the IDs it gave.
|
|
256
|
+
|
|
257
|
+
`targeting-rules reference` prints the format: notes on how rules are evaluated, the condition kinds, the attributes a condition can test, and the operators for context kinds, segments and each target type. With `--json`, it prints the whole document as received, including the JSON Schema of the request `targeting-rules set` sends. Its notes name the MCP server's tools: `update_targeting_rules` is what `targeting-rules set` does, and `get_config` what `configs get` does.
|
|
258
|
+
|
|
259
|
+
`targeting-rules set` needs `projects:read`, `environments:read` and `config-targeting-rules:update`. `targeting-rules reference` needs only a valid token and no project.
|
|
260
|
+
|
|
261
|
+
## Archive a config
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
configdirector configs archive new-checkout
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
`configs archive` archives a config: it is removed from the project and from what SDKs receive, so applications get their in-code default value for it. It can be restored from the dashboard for 30 days, and after that it is deleted for good:
|
|
268
|
+
|
|
269
|
+
```txt
|
|
270
|
+
Archived new-checkout in web-app. It can be restored from the dashboard for 30 days.
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
It asks for no confirmation and does not check whether the code still reads the key, so run `configdirector scan` first. A renamed config can be archived by an old key. When no config in the project has the key, which includes a config already archived, it exits with 2. With `--json`, it prints `{ "archivedConfigKey": "new-checkout" }`, with the key as given.
|
|
274
|
+
|
|
275
|
+
`configs archive` needs `projects:read` and `configs:archive`. The change shows in the audit log with the source CLI.
|
|
276
|
+
|
|
77
277
|
## Options
|
|
78
278
|
|
|
79
|
-
| Option | Environment variable | Meaning
|
|
80
|
-
| ------------------ | ------------------------- |
|
|
81
|
-
| `--token <token>` | `CONFIGDIRECTOR_TOKEN` | API token. Without either, the token saved by `login` is used.
|
|
82
|
-
| `--base-url <url>` | `CONFIGDIRECTOR_BASE_URL` | API host. Defaults to `https://api.configdirector.com`.
|
|
83
|
-
| `--project <slug>` | `CONFIGDIRECTOR_PROJECT` | Project slug. Without either,
|
|
84
|
-
| `--json` | | Print JSON on stdout. Errors always go to stderr.
|
|
279
|
+
| Option | Environment variable | Meaning |
|
|
280
|
+
| ------------------ | ------------------------- | ------------------------------------------------------------------------------------------------------------- |
|
|
281
|
+
| `--token <token>` | `CONFIGDIRECTOR_TOKEN` | API token. Without either, the token saved by `login` is used. |
|
|
282
|
+
| `--base-url <url>` | `CONFIGDIRECTOR_BASE_URL` | API host. Defaults to `https://api.configdirector.com`. |
|
|
283
|
+
| `--project <slug>` | `CONFIGDIRECTOR_PROJECT` | Project slug. Without either, every command that reads a project uses the `project` in `configdirector.json`. |
|
|
284
|
+
| `--json` | | Print JSON on stdout. Errors always go to stderr. |
|
|
85
285
|
|
|
86
|
-
The command exits with 0 when it succeeds, 1 when `validate` found a problem, and 2 when it could not run: a usage mistake, a rejected token, a suspended service or an
|
|
286
|
+
The command exits with 0 when it succeeds, 1 when `validate` found a problem or `configs create` found a config that already has the key, and 2 when it could not run: a usage mistake, a rejected token, a suspended service, an unreachable API, or something the command names that does not exist, such as a config key, an environment, a saved context, a segment key, a tag or a scanned repository. A CI job can therefore tell a wrong config key from an outage.
|
|
87
287
|
|
|
88
288
|
## License
|
|
89
289
|
|