@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.
- package/README.md +88 -0
- package/package.json +34 -38
- package/src/commands/auth/index.ts +940 -0
- package/src/commands/cache/index.ts +361 -0
- package/src/commands/config/README.md +239 -0
- package/src/commands/config/index.ts +164 -0
- package/src/commands/env/README.md +197 -0
- package/src/commands/env/index.ts +392 -0
- package/src/commands/exec/README.md +110 -0
- package/src/commands/exec/index.ts +195 -0
- package/src/commands/get/index.ts +198 -0
- package/src/commands/index.ts +30 -0
- package/src/commands/inspect/index.ts +264 -0
- package/src/commands/install/README.md +146 -0
- package/src/commands/install/index.ts +682 -0
- package/src/commands/list/README.md +115 -0
- package/src/commands/list/index.ts +138 -0
- package/src/commands/publish/index.ts +350 -0
- package/src/commands/report/index.ts +366 -0
- package/src/commands/run/README.md +124 -0
- package/src/commands/run/index.ts +686 -0
- package/src/commands/search/index.ts +368 -0
- package/src/commands/setup/index.ts +274 -0
- package/src/commands/sign/index.ts +652 -0
- package/src/commands/trust/README.md +214 -0
- package/src/commands/trust/index.ts +453 -0
- package/src/commands/unyank/index.ts +107 -0
- package/src/commands/yank/index.ts +143 -0
- package/src/index.ts +96 -0
- package/src/types.ts +81 -0
- package/src/utils/errors.ts +409 -0
- package/src/utils/exit-codes.ts +159 -0
- package/src/utils/ignore.ts +147 -0
- package/src/utils/index.ts +107 -0
- package/src/utils/output.ts +242 -0
- package/src/utils/spinner.ts +214 -0
- package/tests/commands/auth.test.ts +217 -0
- package/tests/commands/cache.test.ts +286 -0
- package/tests/commands/config.test.ts +277 -0
- package/tests/commands/env.test.ts +293 -0
- package/tests/commands/exec.test.ts +112 -0
- package/tests/commands/get.test.ts +179 -0
- package/tests/commands/inspect.test.ts +201 -0
- package/tests/commands/install-integration.test.ts +343 -0
- package/tests/commands/install.test.ts +288 -0
- package/tests/commands/list.test.ts +160 -0
- package/tests/commands/publish.test.ts +186 -0
- package/tests/commands/report.test.ts +194 -0
- package/tests/commands/run.test.ts +231 -0
- package/tests/commands/search.test.ts +131 -0
- package/tests/commands/sign.test.ts +164 -0
- package/tests/commands/trust.test.ts +236 -0
- package/tests/commands/unyank.test.ts +114 -0
- package/tests/commands/yank.test.ts +154 -0
- package/tests/e2e.test.ts +554 -0
- package/tests/fixtures/calculator/enact.yaml +34 -0
- package/tests/fixtures/echo-tool/enact.md +31 -0
- package/tests/fixtures/env-tool/enact.yaml +19 -0
- package/tests/fixtures/greeter/enact.yaml +18 -0
- package/tests/fixtures/invalid-tool/enact.yaml +4 -0
- package/tests/index.test.ts +8 -0
- package/tests/types.test.ts +84 -0
- package/tests/utils/errors.test.ts +303 -0
- package/tests/utils/exit-codes.test.ts +189 -0
- package/tests/utils/ignore.test.ts +461 -0
- package/tests/utils/output.test.ts +126 -0
- package/tsconfig.json +17 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/dist/index.js +0 -231612
- package/dist/index.js.bak +0 -231611
- package/dist/web/static/app.js +0 -663
- package/dist/web/static/index.html +0 -117
- 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
|