@sente-labs/cli 0.1.1 → 0.2.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/dist/client.js CHANGED
@@ -45,7 +45,7 @@ class GatewayClient {
45
45
  headers: {
46
46
  Authorization: `Bearer ${this.creds.token}`,
47
47
  'Content-Type': 'application/json',
48
- 'User-Agent': 'sente-cli/0.1.1',
48
+ 'User-Agent': 'sente-cli/0.2.1',
49
49
  },
50
50
  };
51
51
  if (opts.body !== undefined) {
@@ -0,0 +1,245 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.registerSecretCommands = registerSecretCommands;
37
+ const readline = __importStar(require("readline"));
38
+ const client_1 = require("../client");
39
+ const output_1 = require("../output");
40
+ /**
41
+ * Read a secret value securely from the user. Two paths:
42
+ * - TTY interactive: prompt with input masking (no echo). User pastes value.
43
+ * - Non-TTY / --value-stdin: read entire stdin until EOF, strip trailing newline.
44
+ *
45
+ * We intentionally do NOT accept a `--value <plain>` flag because it leaks the
46
+ * value to shell history. `--value-stdin` is the only programmatic path.
47
+ */
48
+ async function readSecretValue(useStdin) {
49
+ if (useStdin || !process.stdin.isTTY) {
50
+ return readAllStdin();
51
+ }
52
+ return promptHidden('Secret value (input hidden): ');
53
+ }
54
+ function readAllStdin() {
55
+ return new Promise((resolve, reject) => {
56
+ let data = '';
57
+ process.stdin.setEncoding('utf8');
58
+ process.stdin.on('data', (chunk) => (data += chunk));
59
+ process.stdin.on('end', () => resolve(data.replace(/\n+$/, '')));
60
+ process.stdin.on('error', reject);
61
+ });
62
+ }
63
+ /**
64
+ * readline-based hidden prompt. Echoes nothing while the user types so the
65
+ * secret never appears on-screen or in scrollback. Falls back to plain prompt
66
+ * if stdin isn't a TTY (shouldn't happen since the caller already gates this).
67
+ */
68
+ function promptHidden(question) {
69
+ return new Promise((resolve) => {
70
+ const rl = readline.createInterface({
71
+ input: process.stdin,
72
+ output: process.stdout,
73
+ terminal: true,
74
+ });
75
+ // Mute the output stream during input so keystrokes don't echo.
76
+ const stdoutWrite = process.stdout.write.bind(process.stdout);
77
+ let muted = false;
78
+ rl._writeToOutput = (str) => {
79
+ if (muted) {
80
+ // After we mute, only let the newline at the end pass.
81
+ if (str.includes('\n'))
82
+ stdoutWrite('\n');
83
+ return;
84
+ }
85
+ stdoutWrite(str);
86
+ };
87
+ rl.question(question, (answer) => {
88
+ rl.close();
89
+ resolve(answer);
90
+ });
91
+ muted = true;
92
+ });
93
+ }
94
+ function promptText(question, fallback) {
95
+ return new Promise((resolve) => {
96
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
97
+ const suffix = fallback ? ` [${fallback}]` : '';
98
+ rl.question(`${question}${suffix}: `, (answer) => {
99
+ rl.close();
100
+ resolve(answer.trim() || fallback || '');
101
+ });
102
+ });
103
+ }
104
+ function registerSecretCommands(program, globalOpts) {
105
+ const secret = program.command('secret').description('Secret commands');
106
+ secret
107
+ .command('create')
108
+ .description('Create a new secret in the current organization')
109
+ .requiredOption('--name <key>', 'secret key (referenced in steps as {{secret.name}})')
110
+ .option('--description <text>', 'human-readable description')
111
+ .option('--target-url <url>', 'restrict secret to matching URLs')
112
+ .option('--project <id>', 'link the new secret to this project (repeatable)', collect, [])
113
+ .option('--value-stdin', 'read the secret value from stdin (use for piping)')
114
+ .action(async (cmdOpts) => {
115
+ const opts = globalOpts();
116
+ try {
117
+ const value = await readSecretValue(!!cmdOpts.valueStdin);
118
+ if (!value) {
119
+ throw new Error('Secret value is required.');
120
+ }
121
+ // Description is required by the gateway. Prompt for one if missing.
122
+ let description = cmdOpts.description;
123
+ if (!description) {
124
+ if (process.stdin.isTTY && !cmdOpts.valueStdin && !(0, output_1.isJson)(opts)) {
125
+ description = await promptText('Description (visible to the agent)');
126
+ }
127
+ if (!description) {
128
+ // Use the key as a fallback so the create still works in
129
+ // non-interactive contexts without a separate flag.
130
+ description = cmdOpts.name;
131
+ }
132
+ }
133
+ const client = new client_1.GatewayClient();
134
+ const res = await client.request('/api/secrets', {
135
+ method: 'POST',
136
+ body: {
137
+ key: cmdOpts.name,
138
+ description,
139
+ type: 'simple',
140
+ value,
141
+ targetUrl: cmdOpts.targetUrl,
142
+ projectIds: cmdOpts.project.length > 0 ? cmdOpts.project : undefined,
143
+ },
144
+ });
145
+ (0, output_1.printSuccess)({ secret: redact(res.secret) }, () => {
146
+ const s = res.secret;
147
+ process.stdout.write(`Created secret: ${s.key} (${s.id})\n`);
148
+ if (s.targetUrl)
149
+ process.stdout.write(`Target URL: ${s.targetUrl}\n`);
150
+ if (cmdOpts.project.length > 0) {
151
+ process.stdout.write(`Linked to ${cmdOpts.project.length} project(s).\n`);
152
+ }
153
+ process.stdout.write(`Reference in steps as: {{secret.${s.key}}}\n`);
154
+ }, opts);
155
+ }
156
+ catch (err) {
157
+ process.exit((0, output_1.printError)(err, opts));
158
+ }
159
+ });
160
+ secret
161
+ .command('list')
162
+ .description('List secrets visible to the current user')
163
+ .action(async () => {
164
+ const opts = globalOpts();
165
+ try {
166
+ const client = new client_1.GatewayClient();
167
+ const res = await client.request('/api/secrets');
168
+ (0, output_1.printSuccess)({ secrets: res.secrets.map(redact) }, () => {
169
+ if (res.secrets.length === 0) {
170
+ process.stdout.write('No secrets found.\n');
171
+ return;
172
+ }
173
+ for (const s of res.secrets) {
174
+ const projects = s.linkedProjects?.length
175
+ ? ` -> ${s.linkedProjects.map((p) => p.name).join(', ')}`
176
+ : '';
177
+ process.stdout.write(`${s.id} ${s.key.padEnd(28)} ${s.type}${projects}\n`);
178
+ }
179
+ }, opts);
180
+ }
181
+ catch (err) {
182
+ process.exit((0, output_1.printError)(err, opts));
183
+ }
184
+ });
185
+ secret
186
+ .command('link')
187
+ .description('Link a secret to a project')
188
+ .argument('<secretId>', 'secret id')
189
+ .argument('<projectId>', 'project id')
190
+ .action(async (secretId, projectId) => {
191
+ const opts = globalOpts();
192
+ try {
193
+ const client = new client_1.GatewayClient();
194
+ await client.request(`/api/secrets/${secretId}/link/${projectId}`, { method: 'POST' });
195
+ (0, output_1.printSuccess)({ ok: true, secretId, projectId }, `Linked secret ${secretId} to project ${projectId}`, opts);
196
+ }
197
+ catch (err) {
198
+ process.exit((0, output_1.printError)(err, opts));
199
+ }
200
+ });
201
+ secret
202
+ .command('unlink')
203
+ .description('Unlink a secret from a project')
204
+ .argument('<secretId>', 'secret id')
205
+ .argument('<projectId>', 'project id')
206
+ .action(async (secretId, projectId) => {
207
+ const opts = globalOpts();
208
+ try {
209
+ const client = new client_1.GatewayClient();
210
+ await client.request(`/api/secrets/${secretId}/link/${projectId}`, { method: 'DELETE' });
211
+ (0, output_1.printSuccess)({ ok: true, secretId, projectId }, `Unlinked secret ${secretId} from project ${projectId}`, opts);
212
+ }
213
+ catch (err) {
214
+ process.exit((0, output_1.printError)(err, opts));
215
+ }
216
+ });
217
+ secret
218
+ .command('delete')
219
+ .description('Delete a secret (removes it from all linked projects)')
220
+ .argument('<secretId>', 'secret id')
221
+ .action(async (secretId) => {
222
+ const opts = globalOpts();
223
+ try {
224
+ const client = new client_1.GatewayClient();
225
+ await client.request(`/api/secrets/${secretId}`, { method: 'DELETE' });
226
+ (0, output_1.printSuccess)({ ok: true, secretId }, `Deleted secret ${secretId}`, opts);
227
+ }
228
+ catch (err) {
229
+ process.exit((0, output_1.printError)(err, opts));
230
+ }
231
+ });
232
+ }
233
+ /**
234
+ * Strip anything that could contain the raw value from server responses before
235
+ * we print or return them. The gateway never sends values (only metadata), but
236
+ * defending in depth costs nothing.
237
+ */
238
+ function redact(s) {
239
+ const { ...safe } = s;
240
+ return safe;
241
+ }
242
+ function collect(value, previous) {
243
+ return previous.concat([value]);
244
+ }
245
+ //# sourceMappingURL=secret.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret.js","sourceRoot":"","sources":["../../src/commands/secret.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -7,11 +7,12 @@ const whoami_1 = require("./commands/whoami");
7
7
  const project_1 = require("./commands/project");
8
8
  const task_1 = require("./commands/task");
9
9
  const init_1 = require("./commands/init");
10
+ const secret_1 = require("./commands/secret");
10
11
  const program = new commander_1.Command();
11
12
  program
12
13
  .name('sente')
13
14
  .description('Sente CLI -- manage QA tests from the command line and Claude Code')
14
- .version('0.1.1')
15
+ .version('0.2.1')
15
16
  .option('--json', 'Emit machine-readable JSON instead of human output');
16
17
  /**
17
18
  * Global options aren't auto-propagated to subcommands by Commander, so we
@@ -26,6 +27,7 @@ const globalOpts = () => program.opts();
26
27
  (0, project_1.registerProjectCommands)(program, globalOpts);
27
28
  (0, project_1.registerSyncCommand)(program, globalOpts);
28
29
  (0, task_1.registerTaskCommands)(program, globalOpts);
30
+ (0, secret_1.registerSecretCommands)(program, globalOpts);
29
31
  program.parseAsync(process.argv).catch((err) => {
30
32
  // Defensive: command actions handle their own errors. This only catches
31
33
  // setup-time errors (e.g. unknown subcommand).
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AACA,yCAAoC;AACpC,4CAAwD;AACxD,8CAA0D;AAC1D,gDAAkF;AAClF,0CAAuD;AACvD,0CAAmF;AAGnF,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,OAAO,CAAC;KACb,WAAW,CAAC,oEAAoE,CAAC;KACjF,OAAO,CAAC,OAAO,CAAC;KAChB,MAAM,CAAC,QAAQ,EAAE,oDAAoD,CAAC,CAAC;AAE1E;;;;GAIG;AACH,MAAM,UAAU,GAAG,GAAe,EAAE,CAAC,OAAO,CAAC,IAAI,EAAc,CAAC;AAEhE,IAAA,4BAAoB,EAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AAC1C,IAAA,8BAAqB,EAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AAC3C,IAAA,0BAAmB,EAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AACzC,IAAA,kCAA2B,EAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AACjD,IAAA,iCAAuB,EAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AAC7C,IAAA,6BAAmB,EAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AACzC,IAAA,2BAAoB,EAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AAE1C,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IAC7C,wEAAwE;IACxE,+CAA+C;IAC/C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,GAAG,EAAE,OAAO,IAAI,GAAG,IAAI,CAAC,CAAC;IACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AACA,yCAAoC;AACpC,4CAAwD;AACxD,8CAA0D;AAC1D,gDAAkF;AAClF,0CAAuD;AACvD,0CAAmF;AACnF,8CAA2D;AAG3D,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,OAAO,CAAC;KACb,WAAW,CAAC,oEAAoE,CAAC;KACjF,OAAO,CAAC,OAAO,CAAC;KAChB,MAAM,CAAC,QAAQ,EAAE,oDAAoD,CAAC,CAAC;AAE1E;;;;GAIG;AACH,MAAM,UAAU,GAAG,GAAe,EAAE,CAAC,OAAO,CAAC,IAAI,EAAc,CAAC;AAEhE,IAAA,4BAAoB,EAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AAC1C,IAAA,8BAAqB,EAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AAC3C,IAAA,0BAAmB,EAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AACzC,IAAA,kCAA2B,EAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AACjD,IAAA,iCAAuB,EAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AAC7C,IAAA,6BAAmB,EAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AACzC,IAAA,2BAAoB,EAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AAC1C,IAAA,+BAAsB,EAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AAE5C,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IAC7C,wEAAwE;IACxE,+CAA+C;IAC/C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,GAAG,EAAE,OAAO,IAAI,GAAG,IAAI,CAAC,CAAC;IACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -80,7 +80,7 @@ The agent that runs your tests enforces this style. Steps that follow it pass mo
80
80
 
81
81
  ### Hard rules
82
82
 
83
- - **Secrets** use literal placeholder syntax: `{{secret.name_here}}`. Never embed values. List existing secrets with `sente secret list --json` (when available).
83
+ - **Secrets** use literal placeholder syntax: `{{secret.name_here}}`. Never embed values. List existing secrets with `sente secret list --json`. If the secret doesn't exist, create it with `sente secret create --name <key>` (prompts for value with no echo) or pipe via `echo "$VAL" | sente secret create --name <key> --value-stdin`. Link to the current project with `--project $(jq -r .projectId .sente/config.json)`.
84
84
  - **Never invent dropdown values**, product names, or emails. If you don't know, ask the user.
85
85
  - **Combine related micro-actions into one step** (form fill + submit = one step).
86
86
  - **At most 20 steps per task.** If a flow needs more, split into multiple tasks with a precondition note in the second one's instruction.
@@ -105,12 +105,16 @@ The top-level `--instruction` is consulted by the agent when step text is ambigu
105
105
  | `sente task results <id> --failed-step --json` | Focused failure payload for diagnosis |
106
106
  | `sente task results <id> --json` | Full step-by-step results |
107
107
  | `sente sync --json` | Re-pull tasks into `.sente/tasks.json` |
108
+ | `sente secret list --json` | List secrets (metadata only; values are never returned) |
109
+ | `sente secret create --name <key> --project <projectId> [--target-url <url>]` | Create a secret. Hidden prompt for value, or `--value-stdin` for piping |
110
+ | `sente secret link <secretId> <projectId>` / `unlink ...` | Link/unlink an existing secret to a project |
111
+ | `sente secret delete <secretId>` | Delete a secret (removes from all linked projects) |
108
112
 
109
113
  Use `--json` for every CLI call — outputs are stable JSON shaped for programmatic consumption.
110
114
 
111
115
  ## Error handling
112
116
 
113
117
  - `STEP_VALIDATION_FAILED` (HTTP 400): the `errors[]` array tells you exactly what to fix. Apply the fix to the steps file and retry.
114
- - `UNKNOWN_SECRET`: the referenced secret doesn't exist in this organization. Ask the user to create it via the web UI, or use a different secret.
118
+ - `UNKNOWN_SECRET`: the referenced secret doesn't exist in this organization. Either ask the user to create it (so they paste the value into a hidden prompt: `sente secret create --name <key> --project $(jq -r .projectId .sente/config.json)`), or rewrite the step to use a different existing secret. Never invent secret values yourself.
115
119
  - `INVALID_PAT`: the stored PAT is bad. Ask the user to re-run `sente login` after issuing a new token.
116
120
  - `NETWORK_ERROR`: the gateway is unreachable. Surface the host to the user.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sente-labs/cli",
3
- "version": "0.1.1",
3
+ "version": "0.2.1",
4
4
  "description": "Sente CLI -- author and manage QA tests from your terminal and Claude Code. Tests run against your staging URL after each deploy.",
5
5
  "bin": {
6
6
  "sente": "dist/index.js"