piezas 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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +51 -22
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "piezas",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Set up Piezas in your project — installs the SDK and configures AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
package/src/index.js CHANGED
@@ -690,7 +690,8 @@ async function waitForEnvKey(projectDir, timeoutSeconds, intervalMs) {
690
690
  }
691
691
 
692
692
  // resolveApiKey implements the key-intake precedence:
693
- // existing .env key > --key flag > process env > interactive prompt > --wait.
693
+ // existing .env key > --key flag > process env > `piezas login` auto-mint >
694
+ // interactive paste prompt > --wait.
694
695
  // Only explicitly provided keys (--key/prompt/wait) may replace an existing
695
696
  // .env value; the process env never overrides an already-configured project.
696
697
  async function resolveApiKey(envPath, projectDir, options) {
@@ -709,6 +710,15 @@ async function resolveApiKey(envPath, projectDir, options) {
709
710
  return { key: processKey, source: 'process-env' };
710
711
  }
711
712
 
713
+ // Signed in via `piezas login`? Create the app and mint its key right here,
714
+ // from the terminal -- no dashboard visit, no copy-paste. This runs BEFORE the
715
+ // manual paste prompt so a logged-in user is never sent to the web UI to fetch
716
+ // a key by hand. Declining the offer falls through to the manual paths below.
717
+ const minted = await resolveKeyViaLogin(projectDir, options);
718
+ if (minted) {
719
+ return minted;
720
+ }
721
+
712
722
  if (options.interactive && !options.yes) {
713
723
  const promptFn = options.promptFn ?? promptViaTerminal;
714
724
  const answer = String((await promptFn(KEY_PROMPT)) ?? '').trim();
@@ -726,13 +736,6 @@ async function resolveApiKey(envPath, projectDir, options) {
726
736
  }
727
737
  }
728
738
 
729
- // Nothing resolved: with a saved `piezas login` session (and a TTY or an
730
- // explicit --from-login) create the app + mint a key via the platform.
731
- const minted = await resolveKeyViaLogin(projectDir, options);
732
- if (minted) {
733
- return minted;
734
- }
735
-
736
739
  return { key: undefined, source: 'none' };
737
740
  }
738
741
 
@@ -1055,16 +1058,29 @@ async function resolveKeyViaLogin(projectDir, options) {
1055
1058
  const credentials = readCredentials(env);
1056
1059
  if (!credentials) return undefined;
1057
1060
 
1058
- const appName = (typeof options.app === 'string' && options.app.trim())
1061
+ const flagApp = (typeof options.app === 'string' && options.app.trim())
1059
1062
  ? options.app.trim()
1060
- : basename(projectDir);
1061
-
1062
- if (!options.fromLogin) {
1063
+ : undefined;
1064
+ const defaultName = flagApp || basename(projectDir);
1065
+ let appName = defaultName;
1066
+
1067
+ // Interactive (and not the non-interactive --from-login shortcut, and no
1068
+ // explicit --app): offer an explicit choice -- create a new app now (which
1069
+ // mints its key for you), or paste a key you already made in the dashboard.
1070
+ // Choosing "paste" (2) returns undefined so the caller falls through to the
1071
+ // paste prompt. Choosing "create" (1, the default) asks for the app name and
1072
+ // mints its key here -- no dashboard visit. An explicit --app skips the menu
1073
+ // and creates that app directly.
1074
+ if (!flagApp && !options.fromLogin && options.interactive && !options.yes) {
1063
1075
  const promptFn = options.promptFn ?? promptViaTerminal;
1064
- const answer = String(
1065
- (await promptFn(`You are signed in as ${credentials.email}. Create app "${appName}" and mint an API key now? [Y/n] `)) ?? '',
1066
- ).trim().toLowerCase();
1067
- if (answer === 'n' || answer === 'no') return undefined;
1076
+ log('');
1077
+ log(` Signed in as ${credentials.email}. How would you like to get your API key?`);
1078
+ log(" 1) Create a new app now - we'll mint its key (recommended)");
1079
+ log(' 2) Paste a key you already created in the dashboard');
1080
+ const choice = String((await promptFn(' Choose 1 or 2 [1]: ')) ?? '').trim();
1081
+ if (choice === '2') return undefined;
1082
+ const answer = String((await promptFn(` Name for the new app [${defaultName}]: `)) ?? '').trim();
1083
+ appName = answer || defaultName;
1068
1084
  }
1069
1085
 
1070
1086
  const fetchFn = options.fetchFn ?? fetch;
@@ -1120,7 +1136,7 @@ async function resolveKeyViaLogin(projectDir, options) {
1120
1136
  return undefined;
1121
1137
  }
1122
1138
  log(` Minted a live API key for "${app.name}"`);
1123
- return { key: minted.data.key, source: 'login' };
1139
+ return { key: minted.data.key, source: 'login', appName: app.name };
1124
1140
  } catch (error) {
1125
1141
  log(` Could not reach Piezas (${error?.message || 'network error'}) - continuing without a key.`);
1126
1142
  return undefined;
@@ -1282,6 +1298,18 @@ async function runInit(options) {
1282
1298
  }
1283
1299
  }
1284
1300
 
1301
+ // When the app name came from the login prompt (not --app), record it in the
1302
+ // manifest so doctor/agents and the app we just created agree. Cosmetic — the
1303
+ // key is already written — so a write failure here is non-fatal.
1304
+ if (resolved.appName && manifest && manifest.appName !== resolved.appName) {
1305
+ manifest.appName = resolved.appName;
1306
+ try {
1307
+ writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
1308
+ } catch {
1309
+ // ignore — manifest metadata is informational
1310
+ }
1311
+ }
1312
+
1285
1313
  log('\n Done! Your project is set up for Piezas.\n');
1286
1314
  log(' Your AI coding agent now knows how to use Piezas:');
1287
1315
  log(' Claude Code -> /piezas or reads CLAUDE.md automatically');
@@ -1292,8 +1320,8 @@ async function runInit(options) {
1292
1320
  log('');
1293
1321
  if (apiKeyStatus === 'missing') {
1294
1322
  log(' apiKey: missing');
1295
- log(` Put PIEZAS_API_KEY=<your key> in ${envPath} (dashboard -> API Keys -> "Download .env"), or rerun: npx piezas init --key <key>`);
1296
- log(' No account key handy? Run `npx piezas login`, then `npx piezas init --from-login` to create an app + key from the terminal.');
1323
+ log(' Easiest: run `npx piezas login`, then re-run `npx piezas init` - it creates your app and API key automatically.');
1324
+ log(` Already have a key? Rerun: npx piezas init --key <key> (or add PIEZAS_API_KEY to ${envPath}).`);
1297
1325
  } else if (apiKeyStatus === 'configured') {
1298
1326
  log(` apiKey: configured (already in ${envPath})`);
1299
1327
  } else {
@@ -1303,8 +1331,8 @@ async function runInit(options) {
1303
1331
  log(' Next steps:');
1304
1332
  let step = 1;
1305
1333
  if (apiKeyStatus === 'missing') {
1306
- log(` ${step++}. Get an API key at https://app.piezas.ai (dashboard -> API Keys)`);
1307
- log(` ${step++}. Add PIEZAS_API_KEY=sk_live_xxx to .env (server-side only)`);
1334
+ log(` ${step++}. Run \`npx piezas login\`, then re-run \`npx piezas init\` to create your app + key`);
1335
+ log(` ${step++}. (or add an existing PIEZAS_API_KEY=sk_live_xxx to .env, server-side only)`);
1308
1336
  }
1309
1337
  log(` ${step++}. Run /piezas-spec [idea] or ask for Piezas spec mode`);
1310
1338
  log(` ${step++}. After the spec is written, tell your AI agent to code from SPEC.md`);
@@ -1799,7 +1827,8 @@ function help() {
1799
1827
  console.log(' --wait Watch the folder for a downloaded .env (.env / .env.download / env.txt)');
1800
1828
  console.log(' --wait-timeout <seconds> How long --wait polls before giving up (default 300)');
1801
1829
  console.log(' --app <name> App name recorded in piezas.manifest.json (and used for auto-created apps)');
1802
- console.log(' --from-login When no key is found, create an app + key with your saved login');
1830
+ console.log(' --from-login Non-interactive: create an app + key from your saved login (CI/agents;');
1831
+ console.log(' interactive `init` already offers this when you are signed in)');
1803
1832
  console.log(' --yes Non-interactive: never prompt (for agents/CI)');
1804
1833
  console.log(' --json Print a machine-readable JSON summary');
1805
1834
  console.log(' --mode next-bff|static|server-runtime|custom-backend');