@enactprotocol/cli 1.2.13 → 2.0.0

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 (73) hide show
  1. package/README.md +88 -0
  2. package/package.json +34 -38
  3. package/src/commands/auth/index.ts +940 -0
  4. package/src/commands/cache/index.ts +361 -0
  5. package/src/commands/config/README.md +239 -0
  6. package/src/commands/config/index.ts +164 -0
  7. package/src/commands/env/README.md +197 -0
  8. package/src/commands/env/index.ts +392 -0
  9. package/src/commands/exec/README.md +110 -0
  10. package/src/commands/exec/index.ts +195 -0
  11. package/src/commands/get/index.ts +198 -0
  12. package/src/commands/index.ts +30 -0
  13. package/src/commands/inspect/index.ts +264 -0
  14. package/src/commands/install/README.md +146 -0
  15. package/src/commands/install/index.ts +682 -0
  16. package/src/commands/list/README.md +115 -0
  17. package/src/commands/list/index.ts +138 -0
  18. package/src/commands/publish/index.ts +350 -0
  19. package/src/commands/report/index.ts +366 -0
  20. package/src/commands/run/README.md +124 -0
  21. package/src/commands/run/index.ts +686 -0
  22. package/src/commands/search/index.ts +368 -0
  23. package/src/commands/setup/index.ts +274 -0
  24. package/src/commands/sign/index.ts +652 -0
  25. package/src/commands/trust/README.md +214 -0
  26. package/src/commands/trust/index.ts +453 -0
  27. package/src/commands/unyank/index.ts +107 -0
  28. package/src/commands/yank/index.ts +143 -0
  29. package/src/index.ts +96 -0
  30. package/src/types.ts +81 -0
  31. package/src/utils/errors.ts +409 -0
  32. package/src/utils/exit-codes.ts +159 -0
  33. package/src/utils/ignore.ts +147 -0
  34. package/src/utils/index.ts +107 -0
  35. package/src/utils/output.ts +242 -0
  36. package/src/utils/spinner.ts +214 -0
  37. package/tests/commands/auth.test.ts +217 -0
  38. package/tests/commands/cache.test.ts +286 -0
  39. package/tests/commands/config.test.ts +277 -0
  40. package/tests/commands/env.test.ts +293 -0
  41. package/tests/commands/exec.test.ts +112 -0
  42. package/tests/commands/get.test.ts +179 -0
  43. package/tests/commands/inspect.test.ts +201 -0
  44. package/tests/commands/install-integration.test.ts +343 -0
  45. package/tests/commands/install.test.ts +288 -0
  46. package/tests/commands/list.test.ts +160 -0
  47. package/tests/commands/publish.test.ts +186 -0
  48. package/tests/commands/report.test.ts +194 -0
  49. package/tests/commands/run.test.ts +231 -0
  50. package/tests/commands/search.test.ts +131 -0
  51. package/tests/commands/sign.test.ts +164 -0
  52. package/tests/commands/trust.test.ts +236 -0
  53. package/tests/commands/unyank.test.ts +114 -0
  54. package/tests/commands/yank.test.ts +154 -0
  55. package/tests/e2e.test.ts +554 -0
  56. package/tests/fixtures/calculator/enact.yaml +34 -0
  57. package/tests/fixtures/echo-tool/enact.md +31 -0
  58. package/tests/fixtures/env-tool/enact.yaml +19 -0
  59. package/tests/fixtures/greeter/enact.yaml +18 -0
  60. package/tests/fixtures/invalid-tool/enact.yaml +4 -0
  61. package/tests/index.test.ts +8 -0
  62. package/tests/types.test.ts +84 -0
  63. package/tests/utils/errors.test.ts +303 -0
  64. package/tests/utils/exit-codes.test.ts +189 -0
  65. package/tests/utils/ignore.test.ts +461 -0
  66. package/tests/utils/output.test.ts +126 -0
  67. package/tsconfig.json +17 -0
  68. package/tsconfig.tsbuildinfo +1 -0
  69. package/dist/index.js +0 -231612
  70. package/dist/index.js.bak +0 -231611
  71. package/dist/web/static/app.js +0 -663
  72. package/dist/web/static/index.html +0 -117
  73. package/dist/web/static/style.css +0 -291
@@ -0,0 +1,164 @@
1
+ /**
2
+ * enact config command
3
+ *
4
+ * Manage CLI configuration.
5
+ */
6
+
7
+ import { getConfigPath, getConfigValue, loadConfig, setConfigValue } from "@enactprotocol/shared";
8
+ import type { Command } from "commander";
9
+ import type { CommandContext, GlobalOptions } from "../../types";
10
+ import { dim, error, formatError, info, json, keyValue, newline, success } from "../../utils";
11
+
12
+ interface ConfigOptions extends GlobalOptions {}
13
+
14
+ /**
15
+ * Get a config value
16
+ */
17
+ async function configGetHandler(
18
+ key: string,
19
+ options: ConfigOptions,
20
+ _ctx: CommandContext
21
+ ): Promise<void> {
22
+ const value = getConfigValue(key, undefined);
23
+
24
+ if (options.json) {
25
+ json({ key, value });
26
+ return;
27
+ }
28
+
29
+ if (value === undefined) {
30
+ info(`Configuration key '${key}' is not set`);
31
+ } else {
32
+ keyValue(key, typeof value === "object" ? JSON.stringify(value) : String(value));
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Set a config value
38
+ */
39
+ async function configSetHandler(
40
+ key: string,
41
+ value: string,
42
+ options: ConfigOptions,
43
+ _ctx: CommandContext
44
+ ): Promise<void> {
45
+ // Try to parse value as JSON for complex values
46
+ let parsedValue: unknown = value;
47
+ try {
48
+ parsedValue = JSON.parse(value);
49
+ } catch {
50
+ // Keep as string if not valid JSON
51
+ }
52
+
53
+ setConfigValue(key, parsedValue);
54
+
55
+ if (options.json) {
56
+ json({ key, value: parsedValue, set: true });
57
+ return;
58
+ }
59
+
60
+ success(`Set ${key} = ${value}`);
61
+ }
62
+
63
+ /**
64
+ * List all config values
65
+ */
66
+ async function configListHandler(options: ConfigOptions, _ctx: CommandContext): Promise<void> {
67
+ const config = loadConfig();
68
+
69
+ if (options.json) {
70
+ json(config);
71
+ return;
72
+ }
73
+
74
+ dim(`Configuration file: ${getConfigPath()}`);
75
+ newline();
76
+
77
+ // Flatten config for display
78
+ function displayObject(obj: Record<string, unknown>, prefix = ""): void {
79
+ for (const [key, value] of Object.entries(obj)) {
80
+ const fullKey = prefix ? `${prefix}.${key}` : key;
81
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
82
+ displayObject(value as Record<string, unknown>, fullKey);
83
+ } else {
84
+ const displayValue = Array.isArray(value) ? JSON.stringify(value) : String(value);
85
+ keyValue(fullKey, displayValue);
86
+ }
87
+ }
88
+ }
89
+
90
+ displayObject(config as unknown as Record<string, unknown>);
91
+ }
92
+
93
+ /**
94
+ * Configure the config command
95
+ */
96
+ export function configureConfigCommand(program: Command): void {
97
+ const config = program.command("config").description("Manage CLI configuration");
98
+
99
+ // config get
100
+ config
101
+ .command("get")
102
+ .description("Get a configuration value")
103
+ .argument("<key>", "Configuration key (dot notation, e.g., trust.policy)")
104
+ .option("--json", "Output as JSON")
105
+ .action(async (key: string, options: ConfigOptions) => {
106
+ const ctx: CommandContext = {
107
+ cwd: process.cwd(),
108
+ options,
109
+ isCI: Boolean(process.env.CI),
110
+ isInteractive: process.stdout.isTTY ?? false,
111
+ };
112
+
113
+ try {
114
+ await configGetHandler(key, options, ctx);
115
+ } catch (err) {
116
+ error(formatError(err));
117
+ process.exit(1);
118
+ }
119
+ });
120
+
121
+ // config set
122
+ config
123
+ .command("set")
124
+ .description("Set a configuration value")
125
+ .argument("<key>", "Configuration key (dot notation, e.g., trust.policy)")
126
+ .argument("<value>", "Value to set (JSON for complex values)")
127
+ .option("--json", "Output as JSON")
128
+ .action(async (key: string, value: string, options: ConfigOptions) => {
129
+ const ctx: CommandContext = {
130
+ cwd: process.cwd(),
131
+ options,
132
+ isCI: Boolean(process.env.CI),
133
+ isInteractive: process.stdout.isTTY ?? false,
134
+ };
135
+
136
+ try {
137
+ await configSetHandler(key, value, options, ctx);
138
+ } catch (err) {
139
+ error(formatError(err));
140
+ process.exit(1);
141
+ }
142
+ });
143
+
144
+ // config list
145
+ config
146
+ .command("list")
147
+ .description("List all configuration values")
148
+ .option("--json", "Output as JSON")
149
+ .action(async (options: ConfigOptions) => {
150
+ const ctx: CommandContext = {
151
+ cwd: process.cwd(),
152
+ options,
153
+ isCI: Boolean(process.env.CI),
154
+ isInteractive: process.stdout.isTTY ?? false,
155
+ };
156
+
157
+ try {
158
+ await configListHandler(options, ctx);
159
+ } catch (err) {
160
+ error(formatError(err));
161
+ process.exit(1);
162
+ }
163
+ });
164
+ }
@@ -0,0 +1,197 @@
1
+ # enact env
2
+
3
+ Manage environment variables and secrets.
4
+
5
+ ## Synopsis
6
+
7
+ ```bash
8
+ enact env <subcommand> [options]
9
+ ```
10
+
11
+ ## Description
12
+
13
+ The `env` command manages two types of values:
14
+
15
+ 1. **Environment Variables** - Stored in `.env` files (local or global)
16
+ 2. **Secrets** - Stored securely in the OS keyring (macOS Keychain, Windows Credential Manager, Linux Secret Service)
17
+
18
+ ## Subcommands
19
+
20
+ ### env set
21
+
22
+ Set an environment variable or secret.
23
+
24
+ ```bash
25
+ enact env set <key> [value] [options]
26
+ ```
27
+
28
+ **Options:**
29
+ | Option | Description |
30
+ |--------|-------------|
31
+ | `-s, --secret` | Store as secret in OS keyring |
32
+ | `-n, --namespace <ns>` | Namespace for secret (required with `--secret`) |
33
+ | `-l, --local` | Set in project `.enact/.env` instead of global |
34
+ | `--json` | Output as JSON |
35
+
36
+ **Examples:**
37
+
38
+ ```bash
39
+ # Set global environment variable
40
+ enact env set API_URL https://api.example.com
41
+
42
+ # Set project-local environment variable
43
+ enact env set API_URL https://dev.example.com --local
44
+
45
+ # Set secret with value
46
+ enact env set API_KEY sk-12345 --secret --namespace alice/api
47
+
48
+ # Set secret interactively (prompts for value)
49
+ enact env set API_KEY --secret --namespace alice/api
50
+ ```
51
+
52
+ ### env get
53
+
54
+ Get an environment variable or check if a secret exists.
55
+
56
+ ```bash
57
+ enact env get <key> [options]
58
+ ```
59
+
60
+ **Options:**
61
+ | Option | Description |
62
+ |--------|-------------|
63
+ | `-s, --secret` | Check secret in OS keyring (never shows value) |
64
+ | `-n, --namespace <ns>` | Namespace for secret (required with `--secret`) |
65
+ | `--json` | Output as JSON |
66
+
67
+ **Examples:**
68
+
69
+ ```bash
70
+ # Get environment variable with resolution source
71
+ enact env get API_URL
72
+
73
+ # Check if secret exists (never shows value)
74
+ enact env get API_KEY --secret --namespace alice/api
75
+ ```
76
+
77
+ ### env list
78
+
79
+ List environment variables or secrets.
80
+
81
+ ```bash
82
+ enact env list [options]
83
+ ```
84
+
85
+ **Options:**
86
+ | Option | Description |
87
+ |--------|-------------|
88
+ | `-s, --secret` | List secrets from OS keyring |
89
+ | `-n, --namespace <ns>` | Namespace for secrets (required with `--secret`) |
90
+ | `-l, --local` | Show only project variables |
91
+ | `-g, --global` | Show only global variables |
92
+ | `--json` | Output as JSON |
93
+
94
+ **Examples:**
95
+
96
+ ```bash
97
+ # List all environment variables
98
+ enact env list
99
+
100
+ # List only local variables
101
+ enact env list --local
102
+
103
+ # List secrets for a namespace
104
+ enact env list --secret --namespace alice/api
105
+ ```
106
+
107
+ ### env delete
108
+
109
+ Delete an environment variable or secret.
110
+
111
+ ```bash
112
+ enact env delete <key> [options]
113
+ ```
114
+
115
+ **Options:**
116
+ | Option | Description |
117
+ |--------|-------------|
118
+ | `-s, --secret` | Delete secret from OS keyring |
119
+ | `-n, --namespace <ns>` | Namespace for secret (required with `--secret`) |
120
+ | `-l, --local` | Delete from project `.enact/.env` |
121
+ | `--json` | Output as JSON |
122
+
123
+ **Examples:**
124
+
125
+ ```bash
126
+ # Delete global environment variable
127
+ enact env delete API_URL
128
+
129
+ # Delete local environment variable
130
+ enact env delete API_URL --local
131
+
132
+ # Delete secret
133
+ enact env delete API_KEY --secret --namespace alice/api
134
+ ```
135
+
136
+ ## Environment Variable Resolution
137
+
138
+ When a tool runs, environment variables are resolved in this order:
139
+
140
+ 1. **Local** - `.enact/.env` in the project directory
141
+ 2. **Global** - `~/.enact/.env`
142
+ 3. **Manifest defaults** - Default values from `enact.yaml`
143
+
144
+ ## Secret Namespaces
145
+
146
+ Secrets use namespace inheritance. When a tool requests a secret, Enact walks up the namespace path:
147
+
148
+ ```
149
+ Tool: alice/api/slack/notifier
150
+ Needs: API_TOKEN
151
+
152
+ Lookup order:
153
+ 1. alice/api/slack:API_TOKEN
154
+ 2. alice/api:API_TOKEN ✓ found
155
+ 3. alice:API_TOKEN
156
+ ```
157
+
158
+ This allows you to set secrets at different levels of specificity.
159
+
160
+ ## Security
161
+
162
+ ### Secrets vs Environment Variables
163
+
164
+ | Feature | Secrets | Environment Variables |
165
+ |---------|---------|----------------------|
166
+ | Storage | OS Keyring | `.env` files |
167
+ | Can be shown | Never | Yes |
168
+ | Namespace scoped | Yes | No |
169
+ | Version controlled | No | Optional |
170
+ | Use case | API keys, passwords | URLs, flags, config |
171
+
172
+ ### Secret Safety
173
+
174
+ - Secrets are **never** written to disk or shown in output
175
+ - `enact env get --secret` only confirms existence
176
+ - Secrets are injected into containers as environment variables at runtime
177
+ - The OS keyring provides encryption at rest
178
+
179
+ ## File Locations
180
+
181
+ | Type | Location |
182
+ |------|----------|
183
+ | Global env | `~/.enact/.env` |
184
+ | Local env | `.enact/.env` (project) |
185
+ | Secrets | OS Keyring (service: `enact-cli`) |
186
+
187
+ ## Exit Codes
188
+
189
+ | Code | Description |
190
+ |------|-------------|
191
+ | `0` | Success |
192
+ | `1` | Error |
193
+
194
+ ## See Also
195
+
196
+ - [enact run](../run/README.md) - How secrets are used during execution
197
+ - [enact config](../config/README.md) - Manage CLI configuration