sticky-note-cli 3.1.0 → 3.1.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.
Files changed (2) hide show
  1. package/bin/cli.js +121 -78
  2. package/package.json +5 -5
package/bin/cli.js CHANGED
@@ -574,6 +574,7 @@ async function cmdInit() {
574
574
  print("");
575
575
 
576
576
  let mcpServers, skills, conventions, staleDaysResolved, injectTokenBudgetResolved;
577
+ let wantsCloud = false;
577
578
 
578
579
  if (ciMode) {
579
580
  // CI mode: no prompts, use env vars
@@ -596,6 +597,7 @@ async function cmdInit() {
596
597
  conventions = convRaw ? convRaw.split(",").map(s => s.trim()).filter(Boolean) : [];
597
598
  staleDaysResolved = parseIntOr(staleDaysRaw, 14);
598
599
  injectTokenBudgetResolved = 1000;
600
+ wantsCloud = v3Mode; // --v3 in CI mode implies cloud
599
601
  } else {
600
602
  // Interactive prompts
601
603
  const rl = readline.createInterface({
@@ -623,6 +625,13 @@ async function cmdInit() {
623
625
  // Sync MCP servers from teammate's sticky-note config
624
626
  await syncMcpFromStickyNote(rl);
625
627
 
628
+ const cloudAnswer = await ask(
629
+ rl,
630
+ "Set up Cloudflare cloud backend for real-time team sync? (y/N)",
631
+ v3Mode ? "y" : "N"
632
+ );
633
+ wantsCloud = cloudAnswer.toLowerCase() === "y" || cloudAnswer.toLowerCase() === "yes";
634
+
626
635
  rl.close();
627
636
 
628
637
  // Build MCP server list: prefer detected objects, fall back to names
@@ -643,20 +652,36 @@ async function cmdInit() {
643
652
  injectTokenBudgetResolved = parseIntOr(injectTokenBudget, 1000);
644
653
  }
645
654
 
646
- // V3: write .env.sticky if STICKY_URL is available
647
- if (v3Mode || process.env.STICKY_URL) {
655
+ // Cloud backend: provision inline if requested, or write existing STICKY_URL from env
656
+ if (wantsCloud) {
657
+ print("\n Cloud Backend Setup...\n");
658
+ const cloudResult = provisionCloudBackend();
659
+ if (cloudResult === null) {
660
+ print(" [ERR] `wrangler` CLI not found.");
661
+ print(" Install it: npm install -g wrangler");
662
+ print(" Then authenticate: wrangler login");
663
+ print(" And run `npx sticky-note deploy-backend` when ready.\n");
664
+ } else if (cloudResult.error) {
665
+ print(" [WARN] Cloud setup failed: " + cloudResult.error);
666
+ print(" Run `npx sticky-note deploy-backend` to retry.\n");
667
+ } else {
668
+ if (cloudResult.secretSet) {
669
+ print("\n Share STICKY_URL and STICKY_API_KEY with teammates securely.");
670
+ print(" (e.g. org secrets, 1Password — do not commit .env.sticky)\n");
671
+ } else {
672
+ print("\n [!] API key written to .env.sticky but NOT yet set on the Worker.");
673
+ print(" Run the manual command shown above, then share with your team.\n");
674
+ }
675
+ }
676
+ } else if (process.env.STICKY_URL) {
677
+ // Write existing STICKY_URL from environment into .env.sticky
648
678
  const envStickyPath = path.join(process.cwd(), ".env.sticky");
649
- const stickyUrl = process.env.STICKY_URL || "";
679
+ const stickyUrl = process.env.STICKY_URL;
650
680
  const stickyApiKey = process.env.STICKY_API_KEY || "";
651
- if (stickyUrl) {
652
- let content = `STICKY_URL=${stickyUrl}\n`;
653
- if (stickyApiKey) content += `STICKY_API_KEY=${stickyApiKey}\n`;
654
- fs.writeFileSync(envStickyPath, content, "utf-8");
655
- print(" [OK] .env.sticky (cloud backend configured)");
656
- } else if (v3Mode && !ciMode) {
657
- print(" [WARN] --v3 specified but STICKY_URL not set.");
658
- print(" Run `npx sticky-note deploy-backend` to provision a cloud backend.");
659
- }
681
+ let content = `STICKY_URL=${stickyUrl}\n`;
682
+ if (stickyApiKey) content += `STICKY_API_KEY=${stickyApiKey}\n`;
683
+ fs.writeFileSync(envStickyPath, content, "utf-8");
684
+ print(" [OK] .env.sticky (cloud backend configured)");
660
685
  }
661
686
 
662
687
  print("\n 📁 Creating files...\n");
@@ -2859,106 +2884,124 @@ function cmdGc() {
2859
2884
  // DEPLOY-BACKEND command (V3)
2860
2885
  // ──────────────────────────────────────────────
2861
2886
 
2862
- function cmdDeployBackend() {
2863
- printBanner();
2864
- print(" Deploy Cloudflare KV Backend\n");
2865
-
2887
+ // Shared provisioning logic used by both cmdInit and cmdDeployBackend.
2888
+ // Returns null if wrangler is missing.
2889
+ // Returns { workerUrl, apiKey, secretSet } on success.
2890
+ // Returns { error } on deployment failure.
2891
+ function provisionCloudBackend() {
2866
2892
  // Check wrangler
2867
2893
  try {
2868
2894
  execSync("wrangler --version", { stdio: "pipe" });
2869
2895
  } catch (_) {
2870
- print(" [ERR] `wrangler` CLI not found.");
2871
- print(" Install it: npm install -g wrangler");
2872
- print(" Then authenticate: wrangler login\n");
2873
- process.exit(1);
2896
+ return null; // caller prints the install message
2874
2897
  }
2875
2898
 
2876
2899
  const serverDir = path.join(__dirname, "..", "sticky-server");
2877
2900
  if (!fs.existsSync(path.join(serverDir, "worker.js"))) {
2878
- print(" [ERR] sticky-server/worker.js not found.");
2879
- print(" Make sure you have the full sticky-note package.\n");
2880
- process.exit(1);
2901
+ return { error: "sticky-server/worker.js not found. Make sure you have the full sticky-note package." };
2881
2902
  }
2882
2903
 
2904
+ // Step 1: KV namespace
2883
2905
  print(" Step 1: Creating KV namespace...");
2906
+ let kvResult;
2884
2907
  try {
2885
- const result = execSync("wrangler kv:namespace create STICKY_KV", {
2908
+ kvResult = execSync("wrangler kv:namespace create STICKY_KV", {
2886
2909
  cwd: serverDir,
2887
2910
  encoding: "utf-8",
2888
2911
  stdio: ["pipe", "pipe", "pipe"],
2889
2912
  });
2890
2913
  print(" [OK] KV namespace created");
2891
-
2892
- // Extract namespace ID from wrangler output
2893
- const idMatch = result.match(/id\s*=\s*"([^"]+)"/);
2894
- if (idMatch) {
2895
- const namespaceId = idMatch[1];
2896
- // Update wrangler.toml with real namespace ID
2897
- const tomlPath = path.join(serverDir, "wrangler.toml");
2898
- let toml = fs.readFileSync(tomlPath, "utf-8");
2899
- toml = toml.replace("PLACEHOLDER_KV_NAMESPACE_ID", namespaceId);
2900
- fs.writeFileSync(tomlPath, toml);
2901
- print(` [OK] wrangler.toml updated with namespace ID`);
2902
- }
2903
2914
  } catch (err) {
2904
- print(" [ERR] Failed to create KV namespace: " + (err.message || err));
2905
- print(" Make sure you're logged in: wrangler login\n");
2906
- process.exit(1);
2915
+ return { error: "Failed to create KV namespace: " + (err.message || err) + "\n Make sure you're logged in: wrangler login" };
2916
+ }
2917
+
2918
+ const idMatch = kvResult.match(/id\s*=\s*"([^"]+)"/);
2919
+ if (idMatch) {
2920
+ const tomlPath = path.join(serverDir, "wrangler.toml");
2921
+ let toml = fs.readFileSync(tomlPath, "utf-8");
2922
+ toml = toml.replace("PLACEHOLDER_KV_NAMESPACE_ID", idMatch[1]);
2923
+ fs.writeFileSync(tomlPath, toml);
2924
+ print(" [OK] wrangler.toml updated with namespace ID");
2907
2925
  }
2908
2926
 
2927
+ // Step 2: Deploy Worker
2909
2928
  print(" Step 2: Deploying Worker...");
2929
+ let deployResult;
2910
2930
  try {
2911
- const result = execSync("wrangler deploy", {
2931
+ deployResult = execSync("wrangler deploy", {
2912
2932
  cwd: serverDir,
2913
2933
  encoding: "utf-8",
2914
2934
  stdio: ["pipe", "pipe", "pipe"],
2915
2935
  });
2916
- // Extract worker URL
2917
- const urlMatch = result.match(/(https:\/\/[^\s]+\.workers\.dev)/);
2918
- const workerUrl = urlMatch ? urlMatch[1] : null;
2936
+ } catch (err) {
2937
+ return { error: "Failed to deploy Worker: " + (err.message || err) };
2938
+ }
2919
2939
 
2920
- const apiKey = require("crypto").randomBytes(24).toString("base64url");
2940
+ const urlMatch = deployResult.match(/(https:\/\/[^\s]+\.workers\.dev)/);
2941
+ const workerUrl = urlMatch ? urlMatch[1] : null;
2942
+ const apiKey = require("crypto").randomBytes(24).toString("base64url");
2921
2943
 
2922
- if (workerUrl) {
2923
- print(` [OK] Worker deployed: ${workerUrl}`);
2944
+ if (workerUrl) {
2945
+ print(` [OK] Worker deployed: ${workerUrl}`);
2946
+ } else {
2947
+ print(" [OK] Worker deployed (URL not detected — check wrangler output)");
2948
+ }
2924
2949
 
2925
- print(" Step 3: Setting API key on Worker...");
2926
- let secretSet = false;
2927
- try {
2928
- execSync("wrangler secret put STICKY_API_KEY", {
2929
- cwd: serverDir,
2930
- input: apiKey,
2931
- encoding: "utf-8",
2932
- stdio: ["pipe", "pipe", "pipe"],
2933
- });
2934
- print(" [OK] STICKY_API_KEY secret set on Worker");
2935
- secretSet = true;
2936
- } catch (err) {
2937
- print(" [WARN] Could not set STICKY_API_KEY automatically: " + (err.message || err));
2938
- print(` Set it manually: echo '${apiKey}' | wrangler secret put STICKY_API_KEY`);
2939
- }
2950
+ // Step 3: Set API key
2951
+ print(" Step 3: Setting API key on Worker...");
2952
+ let secretSet = false;
2953
+ try {
2954
+ execSync("wrangler secret put STICKY_API_KEY", {
2955
+ cwd: serverDir,
2956
+ input: apiKey,
2957
+ encoding: "utf-8",
2958
+ stdio: ["pipe", "pipe", "pipe"],
2959
+ });
2960
+ print(" [OK] STICKY_API_KEY set on Worker");
2961
+ secretSet = true;
2962
+ } catch (err) {
2963
+ print(" [WARN] Could not set STICKY_API_KEY automatically: " + (err.message || err));
2964
+ if (workerUrl) print(` Set it manually: echo '${apiKey}' | wrangler secret put STICKY_API_KEY`);
2965
+ }
2940
2966
 
2941
- // Always write .env.sticky so the key is available even if secret-put failed
2942
- const envPath = path.join(process.cwd(), ".env.sticky");
2943
- fs.writeFileSync(envPath, `STICKY_URL=${workerUrl}\nSTICKY_API_KEY=${apiKey}\n`, "utf-8");
2944
- print(" [OK] .env.sticky written with STICKY_URL and STICKY_API_KEY");
2967
+ // Write .env.sticky
2968
+ if (workerUrl) {
2969
+ const envPath = path.join(process.cwd(), ".env.sticky");
2970
+ fs.writeFileSync(envPath, `STICKY_URL=${workerUrl}\nSTICKY_API_KEY=${apiKey}\n`, "utf-8");
2971
+ print(" [OK] .env.sticky written with STICKY_URL and STICKY_API_KEY");
2972
+ }
2945
2973
 
2946
- if (secretSet) {
2947
- print("\n Share STICKY_URL and STICKY_API_KEY with your team securely");
2948
- print(" (e.g. org secrets, 1Password). Do not commit .env.sticky.\n");
2949
- } else {
2950
- print("\n [!] API key is in .env.sticky but NOT yet set on the Worker.");
2951
- print(" Run the manual command above, then share with your team.\n");
2952
- }
2953
- } else {
2954
- print(" [OK] Worker deployed (URL not detected — check wrangler output)");
2955
- }
2956
- } catch (err) {
2957
- print(" [ERR] Failed to deploy Worker: " + (err.message || err));
2974
+ return { workerUrl, apiKey, secretSet };
2975
+ }
2976
+
2977
+ function cmdDeployBackend() {
2978
+ printBanner();
2979
+ print(" Deploy Cloudflare KV Backend\n");
2980
+
2981
+ const result = provisionCloudBackend();
2982
+
2983
+ if (result === null) {
2984
+ print(" [ERR] `wrangler` CLI not found.");
2985
+ print(" Install it: npm install -g wrangler");
2986
+ print(" Then authenticate: wrangler login\n");
2987
+ process.exit(1);
2988
+ }
2989
+
2990
+ if (result.error) {
2991
+ print(" [ERR] " + result.error + "\n");
2958
2992
  process.exit(1);
2959
2993
  }
2960
2994
 
2961
- print("\n Backend ready! Run `npx sticky-note init --v3` in your repos.\n");
2995
+ const { secretSet } = result;
2996
+ if (secretSet) {
2997
+ print("\n Share STICKY_URL and STICKY_API_KEY with your team securely");
2998
+ print(" (e.g. org secrets, 1Password). Do not commit .env.sticky.\n");
2999
+ } else {
3000
+ print("\n [!] API key is in .env.sticky but NOT yet set on the Worker.");
3001
+ print(" Run the manual command above, then share with your team.\n");
3002
+ }
3003
+
3004
+ print("\n Backend ready! Run `npx sticky-note init` in your repos.\n");
2962
3005
  }
2963
3006
 
2964
3007
  // ──────────────────────────────────────────────
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "sticky-note-cli",
3
- "version": "3.1.0",
3
+ "version": "3.1.1",
4
4
  "description": "Human-to-human handoff for AI coding assistants. Git-backed shared memory for Claude Code and Copilot CLI.",
5
5
  "license": "MIT",
6
6
  "bin": {
7
- "sticky-note": "./bin/cli.js",
8
- "sticky-note-cli": "./bin/cli.js",
9
- "sticky-note-mcp": "./bin/mcp-server.js"
7
+ "sticky-note": "bin/cli.js",
8
+ "sticky-note-cli": "bin/cli.js",
9
+ "sticky-note-mcp": "bin/mcp-server.js"
10
10
  },
11
11
  "keywords": [
12
12
  "ai",
@@ -21,7 +21,7 @@
21
21
  "homepage": "https://github.com/BandaruDheeraj/sticky-note#readme",
22
22
  "repository": {
23
23
  "type": "git",
24
- "url": "https://github.com/BandaruDheeraj/sticky-note.git"
24
+ "url": "git+https://github.com/BandaruDheeraj/sticky-note.git"
25
25
  },
26
26
  "files": [
27
27
  "bin/",