sandstream-kit 1.4.0 → 1.4.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/README.md CHANGED
@@ -6,8 +6,28 @@ For AI agents and humans. Manages tools, auth, secrets, and project setup. Zero
6
6
 
7
7
  🌐 [sandstre.am/kit](https://sandstre.am/kit)
8
8
 
9
+ ## Quick start
10
+
11
+ **Prerequisites:** Node.js 22+, git, and [mise](https://mise.jdx.dev) for installing tools (`brew install mise`, or `curl https://mise.run | sh`).
12
+
9
13
  ```bash
14
+ # zero install (also sidesteps npm -g permission issues):
10
15
  npx sandstream-kit setup
16
+
17
+ # or install globally:
18
+ npm i -g sandstream-kit
19
+ # if npm -g is permission-blocked, use a user-owned prefix instead of sudo:
20
+ # npm config set prefix ~/.npm-global
21
+ # echo 'export PATH="$HOME/.npm-global/bin:$PATH"' >> ~/.zshrc && source ~/.zshrc
22
+ ```
23
+
24
+ Then, in a repo:
25
+
26
+ ```bash
27
+ kit init # detect the stack → generate .kit.toml
28
+ kit check # what's set up vs missing (tools, services, secrets, hooks, security)
29
+ kit setup # install tools (via mise), git hooks, logins, secrets
30
+ kit context check # lock each CLI to the declared account + project (no wrong-org pushes)
11
31
  ```
12
32
 
13
33
  ## Problem
package/dist/cli.js CHANGED
@@ -55,7 +55,7 @@ import { promptConfirm } from "./utils/prompt.js";
55
55
  import { c } from "./utils/colors.js";
56
56
  import { gatherStatus } from "./status.js";
57
57
  import { KIT_FILE, resolveConfigPath } from "./cli-shared.js";
58
- import { checkContext, applyContext, contextPrompt } from "./context-lock.js";
58
+ import { checkContext, applyContext, contextPrompt, gatherLive, suggestContextToml } from "./context-lock.js";
59
59
  import { cmdEnv } from "./commands/env.js";
60
60
  import { cmdAuth } from "./commands/auth.js";
61
61
  import { cmdAudit } from "./commands/audit.js";
@@ -516,14 +516,18 @@ async function cmdLogin() {
516
516
  ? `${c.red}✗${c.reset}`
517
517
  : r.action === "login_unverified"
518
518
  ? `${c.yellow}?${c.reset}`
519
- : `${c.green}✓${c.reset}`;
519
+ : r.action === "manual"
520
+ ? `${c.yellow}!${c.reset}`
521
+ : `${c.green}✓${c.reset}`;
520
522
  const label = r.action === "already_authenticated"
521
523
  ? `${c.dim}already authenticated${c.reset}`
522
524
  : r.action === "logged_in"
523
525
  ? `${c.green}logged in${c.reset}`
524
526
  : r.action === "login_unverified"
525
527
  ? `${c.yellow}login unverified${c.reset}`
526
- : `${c.red}failed${c.reset}`;
528
+ : r.action === "manual"
529
+ ? `${c.yellow}manual${c.reset}`
530
+ : `${c.red}failed${c.reset}`;
527
531
  console.log(` ${icon} ${r.name} ${label} ${c.dim}${r.detail}${c.reset}`);
528
532
  if (r.action === "failed" || r.action === "login_unverified")
529
533
  allOk = false;
@@ -599,7 +603,7 @@ async function cmdSecrets() {
599
603
  template: secretsConfig.template,
600
604
  },
601
605
  }, async () => {
602
- const { results, written, fromTemplate } = await generateSecrets(secretsConfig);
606
+ const { results, written, fromTemplate, skipped } = await generateSecrets(secretsConfig);
603
607
  let allOk = true;
604
608
  for (const r of results) {
605
609
  const icon = r.resolved
@@ -618,6 +622,9 @@ async function cmdSecrets() {
618
622
  : "from keys";
619
623
  console.log(`\n ${c.green}✓${c.reset} Wrote .env.local ${c.dim}(${source})${c.reset}`);
620
624
  }
625
+ else if (skipped === "nothing-resolved") {
626
+ console.log(`\n ${c.yellow}!${c.reset} Skipped .env.local ${c.dim}— no secrets resolved (vault empty/unauthed); existing file left intact${c.reset}`);
627
+ }
621
628
  console.log();
622
629
  return allOk;
623
630
  });
@@ -2728,7 +2735,16 @@ async function cmdContextCheck() {
2728
2735
  return findings.every((f) => f.status !== "mismatch");
2729
2736
  }
2730
2737
  if (!config.context) {
2731
- console.log(`${c.dim}No [context] declared in .kit.toml. Add one to lock each CLI to its account + project.${c.reset}`);
2738
+ console.log(`${c.dim}No [context] declared in .kit.toml each CLI is unlocked from its account + project.${c.reset}`);
2739
+ const suggestion = suggestContextToml(await gatherLive(process.cwd()));
2740
+ if (suggestion) {
2741
+ console.log(`\nDetected here — add a ${c.bold}[context]${c.reset} block to .kit.toml to lock it:\n`);
2742
+ console.log(suggestion);
2743
+ console.log(`\n${c.yellow}Verify each value is correct for THIS repo before trusting it.${c.reset} ${c.dim}kit detected the currently-active CLI state, which is exactly what the lock exists to question. Then re-run kit context check.${c.reset}`);
2744
+ }
2745
+ else {
2746
+ console.log(`${c.dim}Add one to lock each CLI to its account + project (gcloud/vercel/github/git/npm).${c.reset}`);
2747
+ }
2732
2748
  return true;
2733
2749
  }
2734
2750
  console.log(`${c.bold}Context lock${c.reset}\n`);
@@ -3279,6 +3295,8 @@ function cmdHelp(subcommand) {
3279
3295
  }
3280
3296
  const bold = c.bold, cyan = c.cyan, dim = c.dim, reset = c.reset, green = c.green;
3281
3297
  console.log(`${bold}kit${reset} ${dim}v${KIT_VERSION}${reset} — developer environment manager\n`);
3298
+ console.log(`${bold}Get going:${reset} ${dim}npx sandstream-kit setup${reset} ${dim}or${reset} ${green}kit init${reset} ${dim}→${reset} ${green}kit check${reset} ${dim}→${reset} ${green}kit setup${reset}`);
3299
+ console.log(`${dim}Prereqs: Node 22+, git, and mise (brew install mise) for installing tools.${reset}\n`);
3282
3300
  console.log(`${bold}Usage:${reset} kit ${cyan}<command>${reset} ${dim}[options]${reset}\n`);
3283
3301
  console.log(`${bold}Commands:${reset}`);
3284
3302
  const maxLen = Math.max(...Object.keys(COMMAND_HELP).map((k) => k.length));