@sentientui/cli 0.2.3 → 0.2.5

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Carlos Sánchez Campos / SentientUI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.cjs CHANGED
@@ -4,27 +4,17 @@ var __create = Object.create;
4
4
  var __defProp = Object.defineProperty;
5
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
8
7
  var __getProtoOf = Object.getPrototypeOf;
9
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
10
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
11
- var __defNormalProp = (obj, key2, value) => key2 in obj ? __defProp(obj, key2, { enumerable: true, configurable: true, writable: true, value }) : obj[key2] = value;
12
- var __spreadValues = (a, b) => {
13
- for (var prop in b || (b = {}))
14
- if (__hasOwnProp.call(b, prop))
15
- __defNormalProp(a, prop, b[prop]);
16
- if (__getOwnPropSymbols)
17
- for (var prop of __getOwnPropSymbols(b)) {
18
- if (__propIsEnum.call(b, prop))
19
- __defNormalProp(a, prop, b[prop]);
20
- }
21
- return a;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
22
12
  };
23
13
  var __copyProps = (to, from, except, desc) => {
24
14
  if (from && typeof from === "object" || typeof from === "function") {
25
- for (let key2 of __getOwnPropNames(from))
26
- if (!__hasOwnProp.call(to, key2) && key2 !== except)
27
- __defProp(to, key2, { get: () => from[key2], enumerable: !(desc = __getOwnPropDesc(from, key2)) || desc.enumerable });
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
28
18
  }
29
19
  return to;
30
20
  };
@@ -36,6 +26,17 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
36
26
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
37
27
  mod
38
28
  ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // src/index.ts
32
+ var index_exports = {};
33
+ __export(index_exports, {
34
+ main: () => main,
35
+ parseArgs: () => parseArgs
36
+ });
37
+ module.exports = __toCommonJS(index_exports);
38
+ var import_node_fs4 = require("fs");
39
+ var import_node_url = require("url");
39
40
 
40
41
  // src/init.ts
41
42
  var import_node_child_process = require("child_process");
@@ -46,14 +47,14 @@ var import_node_path = __toESM(require("path"), 1);
46
47
  function readPackageJson(cwd) {
47
48
  try {
48
49
  return JSON.parse((0, import_node_fs.readFileSync)(import_node_path.default.join(cwd, "package.json"), "utf-8"));
49
- } catch (e) {
50
+ } catch {
50
51
  return null;
51
52
  }
52
53
  }
53
54
  function detectFramework(cwd) {
54
55
  const pkg = readPackageJson(cwd);
55
56
  if (!pkg) return "unknown";
56
- const deps = __spreadValues(__spreadValues({}, pkg.dependencies), pkg.devDependencies);
57
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
57
58
  const has = (dir) => (0, import_node_fs.existsSync)(import_node_path.default.join(cwd, dir));
58
59
  if (deps["next"]) {
59
60
  if (has("app") || has(import_node_path.default.join("src", "app"))) return "next-app";
@@ -88,15 +89,25 @@ function installCommand(pm, pkgName) {
88
89
  var import_node_fs2 = require("fs");
89
90
  var import_node_path2 = __toESM(require("path"), 1);
90
91
  function envVarName(framework) {
91
- return framework === "vite" ? "VITE_SENTIENT_API_KEY" : "NEXT_PUBLIC_SENTIENT_API_KEY";
92
+ switch (framework) {
93
+ case "cra":
94
+ return "REACT_APP_SENTIENT_API_KEY";
95
+ case "vite":
96
+ case "remix":
97
+ return "VITE_SENTIENT_API_KEY";
98
+ case "next-app":
99
+ case "next-pages":
100
+ case "unknown":
101
+ return "NEXT_PUBLIC_SENTIENT_API_KEY";
102
+ }
92
103
  }
93
- function writeEnvFile(cwd, framework, key2) {
104
+ function writeEnvFile(cwd, framework, key) {
94
105
  const varName = envVarName(framework);
95
106
  const file = import_node_path2.default.join(cwd, ".env.local");
96
107
  const block = [
97
108
  "",
98
109
  "# SentientUI \u2014 leave empty for local mode (decisions are simulated on-device; nothing is sent)",
99
- `${varName}=${key2 != null ? key2 : ""}`,
110
+ `${varName}=${key ?? ""}`,
100
111
  ""
101
112
  ].join("\n");
102
113
  if (!(0, import_node_fs2.existsSync)(file)) {
@@ -104,7 +115,7 @@ function writeEnvFile(cwd, framework, key2) {
104
115
  return "created";
105
116
  }
106
117
  const existing = (0, import_node_fs2.readFileSync)(file, "utf-8");
107
- const assigned = existing.split(/\r?\n/).some((line) => line.trim().startsWith(`${varName}=`));
118
+ const assigned = existing.split(/\r?\n/).some((line) => line.trim().replace(/^#+\s*/, "").startsWith(`${varName}=`));
108
119
  if (assigned) return "kept";
109
120
  (0, import_node_fs2.appendFileSync)(file, block, "utf-8");
110
121
  return "appended";
@@ -205,7 +216,7 @@ createRoot(document.getElementById('root')!).render(
205
216
  import { AdaptiveProvider } from '@sentientui/react';
206
217
 
207
218
  // inside the Layout/App component body:
208
- <AdaptiveProvider apiKey="" context="landing">
219
+ <AdaptiveProvider apiKey={import.meta.env.${envVar} ?? ''} context="landing">
209
220
  <Outlet />
210
221
  </AdaptiveProvider>`;
211
222
  case "cra":
@@ -236,11 +247,39 @@ function finale(framework) {
236
247
  return `open http://localhost:${port}?sentient_persona=buyer`;
237
248
  }
238
249
 
250
+ // src/validate-key.ts
251
+ function isPublishableKey(key) {
252
+ return key.startsWith("pk_");
253
+ }
254
+ function warnIfNotPublishableKey(key, log = (line) => console.warn(line)) {
255
+ if (!key || isPublishableKey(key)) return false;
256
+ const looksSecret = key.startsWith("sk_");
257
+ log("");
258
+ log("\u26A0 ============================ SECURITY WARNING ============================");
259
+ log(`\u26A0 The key you passed ("${key.slice(0, 6)}\u2026") is NOT a publishable pk_ key.`);
260
+ if (looksSecret) {
261
+ log("\u26A0 It looks like a SECRET server key (sk_\u2026). Do NOT ship it to the browser.");
262
+ }
263
+ log("\u26A0 This CLI writes the key into a CLIENT-exposed env var, so it is bundled");
264
+ log("\u26A0 into your site and visible to every visitor. Only publishable pk_ keys");
265
+ log("\u26A0 belong in client env. Get your pk_ key from the SentientUI dashboard.");
266
+ log("\u26A0 =======================================================================");
267
+ log("");
268
+ return true;
269
+ }
270
+ function assertPublishableKey(key, log = (line) => console.error(line)) {
271
+ if (warnIfNotPublishableKey(key, log)) {
272
+ throw new Error(
273
+ "Refusing to write a non-publishable key into a client-exposed env var. Only publishable pk_ keys belong in the browser bundle \u2014 pass your pk_ key from the SentientUI dashboard, or omit --key for local mode."
274
+ );
275
+ }
276
+ }
277
+
239
278
  // src/init.ts
240
279
  function runInit(opts) {
241
- var _a, _b, _c;
242
- const log = (_a = opts.log) != null ? _a : ((line) => console.log(line));
243
- const exec = (_b = opts.exec) != null ? _b : ((command2, cwd) => (0, import_node_child_process.execSync)(command2, { cwd, stdio: "inherit" }));
280
+ const log = opts.log ?? ((line) => console.log(line));
281
+ const exec = opts.exec ?? ((command, cwd) => (0, import_node_child_process.execSync)(command, { cwd, stdio: "inherit" }));
282
+ assertPublishableKey(opts.key, log);
244
283
  const framework = detectFramework(opts.cwd);
245
284
  log(`[sentientui] detected framework: ${framework}`);
246
285
  if (framework === "unknown") {
@@ -253,7 +292,7 @@ function runInit(opts) {
253
292
  exec(install, opts.cwd);
254
293
  const envResult = writeEnvFile(opts.cwd, framework, opts.key);
255
294
  log(
256
- `[sentientui] .env.local ${envResult}: ${envVarName(framework)}=${(_c = opts.key) != null ? _c : "(empty \u2014 local mode)"}`
295
+ `[sentientui] .env.local ${envResult}: ${envVarName(framework)}=${opts.key ?? "(empty \u2014 local mode)"}`
257
296
  );
258
297
  const scaffolded = scaffoldExample(opts.cwd);
259
298
  log(
@@ -268,27 +307,50 @@ function runInit(opts) {
268
307
  }
269
308
 
270
309
  // src/index.ts
310
+ var import_meta = {};
271
311
  function parseArgs(argv) {
272
312
  const args = [...argv];
273
- const command2 = args.shift();
274
- let key2;
313
+ const command = args.shift();
314
+ let key;
275
315
  for (let i = 0; i < args.length; i++) {
276
- if (args[i] === "--key") {
277
- key2 = args[i + 1];
316
+ const arg = args[i];
317
+ if (arg === "--key") {
318
+ key = args[i + 1];
278
319
  i++;
320
+ } else if (arg.startsWith("--key=")) {
321
+ key = arg.slice("--key=".length);
279
322
  }
280
323
  }
281
- return { command: command2, key: key2 };
324
+ return { command, key };
282
325
  }
283
- var { command, key } = parseArgs(process.argv.slice(2));
284
- if (command === "init") {
326
+ function main(argv) {
327
+ const { command, key } = parseArgs(argv);
328
+ if (command === "init") {
329
+ try {
330
+ runInit({ cwd: process.cwd(), key });
331
+ } catch (err) {
332
+ console.error(`[sentientui] init failed: ${String(err)}`);
333
+ process.exit(1);
334
+ }
335
+ } else {
336
+ console.log("Usage: npx @sentientui/cli init [--key pk_...] [--yes]");
337
+ process.exit(command ? 1 : 0);
338
+ }
339
+ }
340
+ function isRunAsScript() {
285
341
  try {
286
- runInit({ cwd: process.cwd(), key });
287
- } catch (err) {
288
- console.error(`[sentientui] init failed: ${String(err)}`);
289
- process.exit(1);
342
+ const entry = process.argv[1];
343
+ if (!entry) return false;
344
+ return (0, import_node_fs4.realpathSync)((0, import_node_url.fileURLToPath)(import_meta.url)) === (0, import_node_fs4.realpathSync)(entry);
345
+ } catch {
346
+ return false;
290
347
  }
291
- } else {
292
- console.log("Usage: npx @sentientui/cli init [--key pk_...] [--yes]");
293
- process.exit(command ? 1 : 0);
294
348
  }
349
+ if (isRunAsScript()) {
350
+ main(process.argv.slice(2));
351
+ }
352
+ // Annotate the CommonJS export names for ESM import in node:
353
+ 0 && (module.exports = {
354
+ main,
355
+ parseArgs
356
+ });
package/dist/index.js CHANGED
@@ -1,20 +1,8 @@
1
1
  #!/usr/bin/env node
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
4
- var __hasOwnProp = Object.prototype.hasOwnProperty;
5
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
6
- var __defNormalProp = (obj, key2, value) => key2 in obj ? __defProp(obj, key2, { enumerable: true, configurable: true, writable: true, value }) : obj[key2] = value;
7
- var __spreadValues = (a, b) => {
8
- for (var prop in b || (b = {}))
9
- if (__hasOwnProp.call(b, prop))
10
- __defNormalProp(a, prop, b[prop]);
11
- if (__getOwnPropSymbols)
12
- for (var prop of __getOwnPropSymbols(b)) {
13
- if (__propIsEnum.call(b, prop))
14
- __defNormalProp(a, prop, b[prop]);
15
- }
16
- return a;
17
- };
2
+
3
+ // src/index.ts
4
+ import { realpathSync } from "fs";
5
+ import { fileURLToPath } from "url";
18
6
 
19
7
  // src/init.ts
20
8
  import { execSync } from "child_process";
@@ -25,14 +13,14 @@ import path from "path";
25
13
  function readPackageJson(cwd) {
26
14
  try {
27
15
  return JSON.parse(readFileSync(path.join(cwd, "package.json"), "utf-8"));
28
- } catch (e) {
16
+ } catch {
29
17
  return null;
30
18
  }
31
19
  }
32
20
  function detectFramework(cwd) {
33
21
  const pkg = readPackageJson(cwd);
34
22
  if (!pkg) return "unknown";
35
- const deps = __spreadValues(__spreadValues({}, pkg.dependencies), pkg.devDependencies);
23
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
36
24
  const has = (dir) => existsSync(path.join(cwd, dir));
37
25
  if (deps["next"]) {
38
26
  if (has("app") || has(path.join("src", "app"))) return "next-app";
@@ -67,15 +55,25 @@ function installCommand(pm, pkgName) {
67
55
  import { existsSync as existsSync2, readFileSync as readFileSync2, appendFileSync, writeFileSync } from "fs";
68
56
  import path2 from "path";
69
57
  function envVarName(framework) {
70
- return framework === "vite" ? "VITE_SENTIENT_API_KEY" : "NEXT_PUBLIC_SENTIENT_API_KEY";
58
+ switch (framework) {
59
+ case "cra":
60
+ return "REACT_APP_SENTIENT_API_KEY";
61
+ case "vite":
62
+ case "remix":
63
+ return "VITE_SENTIENT_API_KEY";
64
+ case "next-app":
65
+ case "next-pages":
66
+ case "unknown":
67
+ return "NEXT_PUBLIC_SENTIENT_API_KEY";
68
+ }
71
69
  }
72
- function writeEnvFile(cwd, framework, key2) {
70
+ function writeEnvFile(cwd, framework, key) {
73
71
  const varName = envVarName(framework);
74
72
  const file = path2.join(cwd, ".env.local");
75
73
  const block = [
76
74
  "",
77
75
  "# SentientUI \u2014 leave empty for local mode (decisions are simulated on-device; nothing is sent)",
78
- `${varName}=${key2 != null ? key2 : ""}`,
76
+ `${varName}=${key ?? ""}`,
79
77
  ""
80
78
  ].join("\n");
81
79
  if (!existsSync2(file)) {
@@ -83,7 +81,7 @@ function writeEnvFile(cwd, framework, key2) {
83
81
  return "created";
84
82
  }
85
83
  const existing = readFileSync2(file, "utf-8");
86
- const assigned = existing.split(/\r?\n/).some((line) => line.trim().startsWith(`${varName}=`));
84
+ const assigned = existing.split(/\r?\n/).some((line) => line.trim().replace(/^#+\s*/, "").startsWith(`${varName}=`));
87
85
  if (assigned) return "kept";
88
86
  appendFileSync(file, block, "utf-8");
89
87
  return "appended";
@@ -184,7 +182,7 @@ createRoot(document.getElementById('root')!).render(
184
182
  import { AdaptiveProvider } from '@sentientui/react';
185
183
 
186
184
  // inside the Layout/App component body:
187
- <AdaptiveProvider apiKey="" context="landing">
185
+ <AdaptiveProvider apiKey={import.meta.env.${envVar} ?? ''} context="landing">
188
186
  <Outlet />
189
187
  </AdaptiveProvider>`;
190
188
  case "cra":
@@ -215,11 +213,39 @@ function finale(framework) {
215
213
  return `open http://localhost:${port}?sentient_persona=buyer`;
216
214
  }
217
215
 
216
+ // src/validate-key.ts
217
+ function isPublishableKey(key) {
218
+ return key.startsWith("pk_");
219
+ }
220
+ function warnIfNotPublishableKey(key, log = (line) => console.warn(line)) {
221
+ if (!key || isPublishableKey(key)) return false;
222
+ const looksSecret = key.startsWith("sk_");
223
+ log("");
224
+ log("\u26A0 ============================ SECURITY WARNING ============================");
225
+ log(`\u26A0 The key you passed ("${key.slice(0, 6)}\u2026") is NOT a publishable pk_ key.`);
226
+ if (looksSecret) {
227
+ log("\u26A0 It looks like a SECRET server key (sk_\u2026). Do NOT ship it to the browser.");
228
+ }
229
+ log("\u26A0 This CLI writes the key into a CLIENT-exposed env var, so it is bundled");
230
+ log("\u26A0 into your site and visible to every visitor. Only publishable pk_ keys");
231
+ log("\u26A0 belong in client env. Get your pk_ key from the SentientUI dashboard.");
232
+ log("\u26A0 =======================================================================");
233
+ log("");
234
+ return true;
235
+ }
236
+ function assertPublishableKey(key, log = (line) => console.error(line)) {
237
+ if (warnIfNotPublishableKey(key, log)) {
238
+ throw new Error(
239
+ "Refusing to write a non-publishable key into a client-exposed env var. Only publishable pk_ keys belong in the browser bundle \u2014 pass your pk_ key from the SentientUI dashboard, or omit --key for local mode."
240
+ );
241
+ }
242
+ }
243
+
218
244
  // src/init.ts
219
245
  function runInit(opts) {
220
- var _a, _b, _c;
221
- const log = (_a = opts.log) != null ? _a : ((line) => console.log(line));
222
- const exec = (_b = opts.exec) != null ? _b : ((command2, cwd) => execSync(command2, { cwd, stdio: "inherit" }));
246
+ const log = opts.log ?? ((line) => console.log(line));
247
+ const exec = opts.exec ?? ((command, cwd) => execSync(command, { cwd, stdio: "inherit" }));
248
+ assertPublishableKey(opts.key, log);
223
249
  const framework = detectFramework(opts.cwd);
224
250
  log(`[sentientui] detected framework: ${framework}`);
225
251
  if (framework === "unknown") {
@@ -232,7 +258,7 @@ function runInit(opts) {
232
258
  exec(install, opts.cwd);
233
259
  const envResult = writeEnvFile(opts.cwd, framework, opts.key);
234
260
  log(
235
- `[sentientui] .env.local ${envResult}: ${envVarName(framework)}=${(_c = opts.key) != null ? _c : "(empty \u2014 local mode)"}`
261
+ `[sentientui] .env.local ${envResult}: ${envVarName(framework)}=${opts.key ?? "(empty \u2014 local mode)"}`
236
262
  );
237
263
  const scaffolded = scaffoldExample(opts.cwd);
238
264
  log(
@@ -249,25 +275,46 @@ function runInit(opts) {
249
275
  // src/index.ts
250
276
  function parseArgs(argv) {
251
277
  const args = [...argv];
252
- const command2 = args.shift();
253
- let key2;
278
+ const command = args.shift();
279
+ let key;
254
280
  for (let i = 0; i < args.length; i++) {
255
- if (args[i] === "--key") {
256
- key2 = args[i + 1];
281
+ const arg = args[i];
282
+ if (arg === "--key") {
283
+ key = args[i + 1];
257
284
  i++;
285
+ } else if (arg.startsWith("--key=")) {
286
+ key = arg.slice("--key=".length);
287
+ }
288
+ }
289
+ return { command, key };
290
+ }
291
+ function main(argv) {
292
+ const { command, key } = parseArgs(argv);
293
+ if (command === "init") {
294
+ try {
295
+ runInit({ cwd: process.cwd(), key });
296
+ } catch (err) {
297
+ console.error(`[sentientui] init failed: ${String(err)}`);
298
+ process.exit(1);
258
299
  }
300
+ } else {
301
+ console.log("Usage: npx @sentientui/cli init [--key pk_...] [--yes]");
302
+ process.exit(command ? 1 : 0);
259
303
  }
260
- return { command: command2, key: key2 };
261
304
  }
262
- var { command, key } = parseArgs(process.argv.slice(2));
263
- if (command === "init") {
305
+ function isRunAsScript() {
264
306
  try {
265
- runInit({ cwd: process.cwd(), key });
266
- } catch (err) {
267
- console.error(`[sentientui] init failed: ${String(err)}`);
268
- process.exit(1);
307
+ const entry = process.argv[1];
308
+ if (!entry) return false;
309
+ return realpathSync(fileURLToPath(import.meta.url)) === realpathSync(entry);
310
+ } catch {
311
+ return false;
269
312
  }
270
- } else {
271
- console.log("Usage: npx @sentientui/cli init [--key pk_...] [--yes]");
272
- process.exit(command ? 1 : 0);
273
313
  }
314
+ if (isRunAsScript()) {
315
+ main(process.argv.slice(2));
316
+ }
317
+ export {
318
+ main,
319
+ parseArgs
320
+ };
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@sentientui/cli",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "SentientUI CLI — `npx @sentientui/cli init` sets up adaptive UI in an existing React app (installs the SDK, writes env config, scaffolds an example, and prints the wrap instructions)",
5
+ "license": "MIT",
5
6
  "homepage": "https://sentient-ui.com",
6
7
  "repository": {
7
8
  "type": "git",
@@ -40,6 +41,7 @@
40
41
  "build": "tsup",
41
42
  "test": "vitest run",
42
43
  "typecheck": "tsc --noEmit",
43
- "dev": "tsx src/index.ts"
44
+ "dev": "tsx src/index.ts",
45
+ "lint": "eslint src"
44
46
  }
45
47
  }