@sente-labs/cli 0.2.0 → 0.3.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/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.2.0',
48
+ 'User-Agent': 'sente-cli/0.3.0',
49
49
  },
50
50
  };
51
51
  if (opts.body !== undefined) {
package/dist/index.js CHANGED
@@ -8,11 +8,20 @@ const project_1 = require("./commands/project");
8
8
  const task_1 = require("./commands/task");
9
9
  const init_1 = require("./commands/init");
10
10
  const secret_1 = require("./commands/secret");
11
+ const autoupdate_1 = require("./skill/autoupdate");
12
+ // Silently refresh the installed Claude Code skill to match the running CLI.
13
+ // Synchronous + cheap (a file stat + at most one small write). No-op if the
14
+ // user customized the skill (no version marker) or --json mode is active.
15
+ (0, autoupdate_1.autoUpdateSkillIfStale)();
16
+ // Fire-and-forget npm registry check. Cached for 24h. Prints a one-line
17
+ // nudge to stderr if a newer CLI is available. Never blocks the user's
18
+ // command; settles at most by the time their action returns.
19
+ void (0, autoupdate_1.checkForCliUpdate)();
11
20
  const program = new commander_1.Command();
12
21
  program
13
22
  .name('sente')
14
23
  .description('Sente CLI -- manage QA tests from the command line and Claude Code')
15
- .version('0.2.0')
24
+ .version('0.3.0')
16
25
  .option('--json', 'Emit machine-readable JSON instead of human output');
17
26
  /**
18
27
  * Global options aren't auto-propagated to subcommands by Commander, so we
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;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"}
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;AAC3D,mDAA+E;AAG/E,6EAA6E;AAC7E,4EAA4E;AAC5E,0EAA0E;AAC1E,IAAA,mCAAsB,GAAE,CAAC;AAEzB,wEAAwE;AACxE,uEAAuE;AACvE,6DAA6D;AAC7D,KAAK,IAAA,8BAAiB,GAAE,CAAC;AAEzB,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"}
@@ -3,6 +3,8 @@ name: sente
3
3
  description: Author and update Sente QA tests for the user's app from within Claude Code. Use when the user finishes a feature, prepares a commit or PR, debugs a failing Sente test, references a Sente task, or mentions "Sente". Drafts well-structured action/assertion steps from the repo context and creates them via the `sente` CLI; reads run results to distinguish app regressions from test issues.
4
4
  ---
5
5
 
6
+ <!-- sente-cli-version: __CLI_VERSION__ -- auto-managed by the sente CLI. If you remove this line, the CLI will stop auto-updating this file. -->
7
+
6
8
  # Sente
7
9
 
8
10
  Sente runs QA tests against the user's deployed staging environment via a cloud-hosted Chrome browser. This skill lets you author and maintain those tests from inside Claude Code using the `sente` CLI.
@@ -80,7 +82,7 @@ The agent that runs your tests enforces this style. Steps that follow it pass mo
80
82
 
81
83
  ### Hard rules
82
84
 
83
- - **Secrets** use literal placeholder syntax: `{{secret.name_here}}`. Never embed values. List existing secrets with `sente secret list --json` (when available).
85
+ - **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
86
  - **Never invent dropdown values**, product names, or emails. If you don't know, ask the user.
85
87
  - **Combine related micro-actions into one step** (form fill + submit = one step).
86
88
  - **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 +107,16 @@ The top-level `--instruction` is consulted by the agent when step text is ambigu
105
107
  | `sente task results <id> --failed-step --json` | Focused failure payload for diagnosis |
106
108
  | `sente task results <id> --json` | Full step-by-step results |
107
109
  | `sente sync --json` | Re-pull tasks into `.sente/tasks.json` |
110
+ | `sente secret list --json` | List secrets (metadata only; values are never returned) |
111
+ | `sente secret create --name <key> --project <projectId> [--target-url <url>]` | Create a secret. Hidden prompt for value, or `--value-stdin` for piping |
112
+ | `sente secret link <secretId> <projectId>` / `unlink ...` | Link/unlink an existing secret to a project |
113
+ | `sente secret delete <secretId>` | Delete a secret (removes from all linked projects) |
108
114
 
109
115
  Use `--json` for every CLI call — outputs are stable JSON shaped for programmatic consumption.
110
116
 
111
117
  ## Error handling
112
118
 
113
119
  - `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.
120
+ - `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
121
  - `INVALID_PAT`: the stored PAT is bad. Ask the user to re-run `sente login` after issuing a new token.
116
122
  - `NETWORK_ERROR`: the gateway is unreachable. Surface the host to the user.
@@ -0,0 +1,171 @@
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.autoUpdateSkillIfStale = autoUpdateSkillIfStale;
37
+ exports.checkForCliUpdate = checkForCliUpdate;
38
+ const fs = __importStar(require("fs"));
39
+ const os = __importStar(require("os"));
40
+ const path = __importStar(require("path"));
41
+ const template_1 = require("./template");
42
+ const config_1 = require("../config");
43
+ /**
44
+ * Silent skill refresh. If the installed skill has a version marker that
45
+ * differs from the current CLI's bundled version, overwrite it.
46
+ *
47
+ * - No marker → user-customized skill; leave it alone.
48
+ * - Marker matches CLI version → up to date; no-op.
49
+ * - Marker differs → auto-upgrade. Print a one-line stderr notice.
50
+ *
51
+ * All errors are swallowed: this is a UX nicety, not a correctness gate.
52
+ * Skipped when `--json` is in argv so machine consumers see clean output.
53
+ */
54
+ function autoUpdateSkillIfStale() {
55
+ if (process.argv.includes('--json'))
56
+ return;
57
+ try {
58
+ const dest = (0, template_1.skillInstallPath)(os.homedir());
59
+ if (!fs.existsSync(dest))
60
+ return; // never installed; not our place
61
+ const installed = fs.readFileSync(dest, 'utf8');
62
+ const installedVersion = (0, template_1.readSkillVersion)(installed);
63
+ if (!installedVersion)
64
+ return; // user-customized; respect it
65
+ if (installedVersion === template_1.CLI_VERSION)
66
+ return; // already current
67
+ fs.writeFileSync(dest, template_1.SKILL_MD);
68
+ process.stderr.write(`sente: refreshed Claude Code skill (${installedVersion} -> ${template_1.CLI_VERSION}). Restart Claude Code to pick up changes.\n`);
69
+ }
70
+ catch {
71
+ // Best-effort. Never crash the user's command on update failures.
72
+ }
73
+ }
74
+ const CACHE_PATH = path.join(config_1.CREDENTIALS_DIR, 'update-check.json');
75
+ const CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24h
76
+ const REGISTRY_URL = 'https://registry.npmjs.org/@sente-labs%2fcli/latest';
77
+ /**
78
+ * Background-ish: hit the npm registry at most once per 24h to learn the
79
+ * latest published CLI version. If the local version is older, print a
80
+ * one-line nudge to stderr.
81
+ *
82
+ * - Network failures, registry errors → silent skip.
83
+ * - --json mode → silent skip.
84
+ * - No SENTE_DISABLE_UPDATE_CHECK env var path so users can opt out.
85
+ *
86
+ * Returns a promise the caller MAY await; the entry point fires-and-forgets
87
+ * by returning before the request settles, so the user's command doesn't
88
+ * pay the network latency.
89
+ */
90
+ async function checkForCliUpdate() {
91
+ if (process.argv.includes('--json'))
92
+ return;
93
+ if (process.env.SENTE_DISABLE_UPDATE_CHECK)
94
+ return;
95
+ try {
96
+ const cached = readCache();
97
+ const now = Date.now();
98
+ let latest = null;
99
+ if (cached && now - new Date(cached.checkedAt).getTime() < CACHE_TTL_MS) {
100
+ latest = cached.latestVersion;
101
+ }
102
+ else {
103
+ latest = await fetchLatestVersion();
104
+ if (latest)
105
+ writeCache({ checkedAt: new Date().toISOString(), latestVersion: latest });
106
+ }
107
+ if (!latest)
108
+ return;
109
+ if (isNewer(latest, template_1.CLI_VERSION)) {
110
+ process.stderr.write(`sente: ${template_1.CLI_VERSION} -> ${latest} available. Run: npm i -g @sente-labs/cli@latest\n`);
111
+ }
112
+ }
113
+ catch {
114
+ // ignore
115
+ }
116
+ }
117
+ async function fetchLatestVersion() {
118
+ try {
119
+ const controller = new AbortController();
120
+ const timeout = setTimeout(() => controller.abort(), 3000);
121
+ const res = await fetch(REGISTRY_URL, { signal: controller.signal });
122
+ clearTimeout(timeout);
123
+ if (!res.ok)
124
+ return null;
125
+ const body = (await res.json());
126
+ return typeof body.version === 'string' ? body.version : null;
127
+ }
128
+ catch {
129
+ return null;
130
+ }
131
+ }
132
+ function readCache() {
133
+ try {
134
+ if (!fs.existsSync(CACHE_PATH))
135
+ return null;
136
+ return JSON.parse(fs.readFileSync(CACHE_PATH, 'utf8'));
137
+ }
138
+ catch {
139
+ return null;
140
+ }
141
+ }
142
+ function writeCache(c) {
143
+ try {
144
+ if (!fs.existsSync(config_1.CREDENTIALS_DIR)) {
145
+ fs.mkdirSync(config_1.CREDENTIALS_DIR, { recursive: true, mode: 0o700 });
146
+ }
147
+ fs.writeFileSync(CACHE_PATH, JSON.stringify(c, null, 2));
148
+ }
149
+ catch {
150
+ // ignore
151
+ }
152
+ }
153
+ /**
154
+ * Compare two semver-ish version strings ("0.2.1", "0.3.0"). Returns true
155
+ * if `candidate` is strictly newer than `current`. Doesn't handle prerelease
156
+ * tags (we'll never ship those for now).
157
+ */
158
+ function isNewer(candidate, current) {
159
+ const a = candidate.split('.').map((n) => parseInt(n, 10));
160
+ const b = current.split('.').map((n) => parseInt(n, 10));
161
+ for (let i = 0; i < Math.max(a.length, b.length); i++) {
162
+ const ai = a[i] ?? 0;
163
+ const bi = b[i] ?? 0;
164
+ if (ai > bi)
165
+ return true;
166
+ if (ai < bi)
167
+ return false;
168
+ }
169
+ return false;
170
+ }
171
+ //# sourceMappingURL=autoupdate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autoupdate.js","sourceRoot":"","sources":["../../src/skill/autoupdate.ts"],"names":[],"mappings":"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"}
@@ -33,22 +33,36 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.SKILL_MD = void 0;
36
+ exports.SKILL_MD = exports.CLI_VERSION = void 0;
37
37
  exports.skillInstallPath = skillInstallPath;
38
+ exports.readSkillVersion = readSkillVersion;
38
39
  const fs = __importStar(require("fs"));
39
40
  const path = __importStar(require("path"));
41
+ // Read package.json once at module load so the bundled skill carries the
42
+ // running CLI version. The file is two levels up from dist/skill/template.js
43
+ // at runtime and from src/skill/template.ts at dev time -- same depth.
44
+ const PKG = JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'package.json'), 'utf8'));
45
+ exports.CLI_VERSION = PKG.version;
46
+ const RAW_SKILL = fs.readFileSync(path.join(__dirname, 'SKILL.md'), 'utf8');
40
47
  /**
41
- * Bundled SKILL.md content. The .md file lives next to this module both at
42
- * dev time (src/skill/) and at runtime (dist/skill/, copied by the build script).
43
- *
44
- * Read once at module load so callers can pass the content around freely.
45
- */
46
- exports.SKILL_MD = fs.readFileSync(path.join(__dirname, 'SKILL.md'), 'utf8');
47
- /**
48
- * Where the skill gets installed for Claude Code to discover it.
49
- * Path is the standard convention documented at https://code.claude.com/docs/en/skills.
48
+ * Bundled SKILL.md content with `__CLI_VERSION__` replaced by the actual
49
+ * CLI version. The marker is embedded in an HTML comment so we can detect
50
+ * drift at runtime without parsing the YAML frontmatter.
50
51
  */
52
+ exports.SKILL_MD = RAW_SKILL.replace('__CLI_VERSION__', exports.CLI_VERSION);
53
+ /** Standard Claude Code skill path. */
51
54
  function skillInstallPath(homeDir) {
52
55
  return path.join(homeDir, '.claude', 'skills', 'sente', 'SKILL.md');
53
56
  }
57
+ const VERSION_MARKER_RE = /<!--\s*sente-cli-version:\s*([0-9A-Za-z.\-_]+)/;
58
+ /**
59
+ * Read the embedded version marker from a skill file's contents.
60
+ * Returns null when:
61
+ * - The file has no marker (user-customized; we leave it alone).
62
+ * - The marker is malformed.
63
+ */
64
+ function readSkillVersion(content) {
65
+ const m = content.match(VERSION_MARKER_RE);
66
+ return m?.[1] ?? null;
67
+ }
54
68
  //# sourceMappingURL=template.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"template.js","sourceRoot":"","sources":["../../src/skill/template.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkBA,4CAEC;AApBD,uCAAyB;AACzB,2CAA6B;AAE7B;;;;;GAKG;AACU,QAAA,QAAQ,GAAW,EAAE,CAAC,YAAY,CAC7C,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,EAChC,MAAM,CACP,CAAC;AAEF;;;GAGG;AACH,SAAgB,gBAAgB,CAAC,OAAe;IAC9C,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;AACtE,CAAC"}
1
+ {"version":3,"file":"template.js","sourceRoot":"","sources":["../../src/skill/template.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsBA,4CAEC;AAUD,4CAGC;AArCD,uCAAyB;AACzB,2CAA6B;AAE7B,yEAAyE;AACzE,6EAA6E;AAC7E,uEAAuE;AACvE,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CACpB,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAC1E,CAAC;AAEW,QAAA,WAAW,GAAW,GAAG,CAAC,OAAO,CAAC;AAE/C,MAAM,SAAS,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,CAAC;AAE5E;;;;GAIG;AACU,QAAA,QAAQ,GAAW,SAAS,CAAC,OAAO,CAAC,iBAAiB,EAAE,mBAAW,CAAC,CAAC;AAElF,uCAAuC;AACvC,SAAgB,gBAAgB,CAAC,OAAe;IAC9C,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;AACtE,CAAC;AAED,MAAM,iBAAiB,GAAG,gDAAgD,CAAC;AAE3E;;;;;GAKG;AACH,SAAgB,gBAAgB,CAAC,OAAe;IAC9C,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;IAC3C,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AACxB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sente-labs/cli",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
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"