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.
- package/bin/cli.js +121 -78
- 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
|
-
//
|
|
647
|
-
if (
|
|
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
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
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
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
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
|
-
|
|
2931
|
+
deployResult = execSync("wrangler deploy", {
|
|
2912
2932
|
cwd: serverDir,
|
|
2913
2933
|
encoding: "utf-8",
|
|
2914
2934
|
stdio: ["pipe", "pipe", "pipe"],
|
|
2915
2935
|
});
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2936
|
+
} catch (err) {
|
|
2937
|
+
return { error: "Failed to deploy Worker: " + (err.message || err) };
|
|
2938
|
+
}
|
|
2919
2939
|
|
|
2920
|
-
|
|
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
|
-
|
|
2923
|
-
|
|
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
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
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
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
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
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
print("
|
|
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
|
-
|
|
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.
|
|
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": "
|
|
8
|
-
"sticky-note-cli": "
|
|
9
|
-
"sticky-note-mcp": "
|
|
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/",
|