luckiest-co 1.0.35 → 1.0.36

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.
@@ -9,7 +9,7 @@
9
9
  "name": "luckiest",
10
10
  "source": "./",
11
11
  "description": "Plan, go, finish, plus bundled free Luckiest skills that work in Claude Code, web chat, and Cowork.",
12
- "version": "0.1.34",
12
+ "version": "0.1.35",
13
13
  "author": { "name": "Luckiest" }
14
14
  }
15
15
  ]
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "luckiest",
3
3
  "description": "Plan, go, finish. Guided planning, progress dashboards, and your luckiest.co tribe inside Claude Code.",
4
- "version": "0.1.34",
4
+ "version": "0.1.35",
5
5
  "author": { "name": "Luckiest" }
6
6
  }
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env node
2
+
3
+ // Release bump: patch-bumps the npm version and the plugin version, then dates
4
+ // the CHANGELOG (turns "## Unreleased" into the release header, or adds one).
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ const green = '\x1b[32m';
10
+ const reset = '\x1b[0m';
11
+
12
+ const VERSION_RE = /("version":\s*")(\d+)\.(\d+)\.(\d+)(")/;
13
+
14
+ const patch = (v) => v.replace(/\d+$/, (n) => Number(n) + 1);
15
+
16
+ /** Bumps all four release files in dir. Returns { npm, plugin }. Writes nothing if the plugin versions disagree. */
17
+ function bumpVersion({ dir = path.join(__dirname, '..'), date = new Date().toLocaleDateString('en-CA') } = {}) {
18
+ const files = {
19
+ pkg: path.join(dir, 'package.json'),
20
+ plugin: path.join(dir, '.claude-plugin/plugin.json'),
21
+ market: path.join(dir, '.claude-plugin/marketplace.json'),
22
+ changelog: path.join(dir, 'CHANGELOG.md'),
23
+ };
24
+ const text = Object.fromEntries(Object.entries(files).map(([k, f]) => [k, fs.readFileSync(f, 'utf8')]));
25
+ const current = (k) => {
26
+ const m = text[k].match(VERSION_RE);
27
+ if (!m) throw new Error(`No version found in ${files[k]}`);
28
+ return `${m[2]}.${m[3]}.${m[4]}`;
29
+ };
30
+
31
+ const oldPlugin = current('plugin');
32
+ if (current('market') !== oldPlugin) {
33
+ throw new Error(`plugin.json (${oldPlugin}) and marketplace.json (${current('market')}) disagree. Fix them by hand first.`);
34
+ }
35
+ const npm = patch(current('pkg'));
36
+ const plugin = patch(oldPlugin);
37
+
38
+ // ponytail: replaces the first "version" in each file, which is the right one in all three today.
39
+ const write = (k, v) => fs.writeFileSync(files[k], text[k].replace(VERSION_RE, `$1${v}$5`));
40
+ write('pkg', npm);
41
+ write('plugin', plugin);
42
+ write('market', plugin);
43
+ // An "## Unreleased" section becomes the dated header, notes and all. Otherwise a fresh header goes on top.
44
+ const header = `## ${plugin} — ${date} (npm luckiest-co ${npm})`;
45
+ const unreleased = /^## Unreleased$/m;
46
+ fs.writeFileSync(files.changelog, unreleased.test(text.changelog)
47
+ ? text.changelog.replace(unreleased, header)
48
+ : `${header}\n\n${text.changelog}`);
49
+ return { npm, plugin };
50
+ }
51
+
52
+ if (require.main === module) {
53
+ try {
54
+ const { npm, plugin } = bumpVersion();
55
+ console.log(` ${green}Bumped to npm luckiest-co ${npm}, plugin ${plugin}.${reset} Check the notes under the new CHANGELOG.md header.`);
56
+ } catch (err) {
57
+ console.error(` ${err.message}`);
58
+ process.exit(1);
59
+ }
60
+ }
61
+
62
+ module.exports = { bumpVersion };
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env node
2
+
3
+ // Plugin repo sync: mirrors this package into the public marketplace repo
4
+ // (luckiestco/luckiest-plugin) and opens a PR there. Run after the release is
5
+ // bumped and published. --dry-run stops before anything is pushed.
6
+
7
+ const { execFileSync } = require('child_process');
8
+ const fs = require('fs');
9
+ const os = require('os');
10
+ const path = require('path');
11
+
12
+ const green = '\x1b[32m';
13
+ const yellow = '\x1b[33m';
14
+ const reset = '\x1b[0m';
15
+
16
+ const REPO = process.env.LUCKIEST_PLUGIN_REPO || 'luckiestco/luckiest-plugin';
17
+
18
+ const sh = (cmd, args, cwd) => execFileSync(cmd, args, { cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] }).trimEnd();
19
+ const versionOf = (dir, file) => JSON.parse(fs.readFileSync(path.join(dir, file), 'utf8')).version;
20
+
21
+ /** Returns { status: 'synced' | 'dry-run' | 'pr', dir, changes, url }. */
22
+ function syncPluginRepo({ src = path.join(__dirname, '..'), remote = `https://github.com/${REPO}.git`, dryRun = false } = {}) {
23
+ const plugin = versionOf(src, '.claude-plugin/plugin.json');
24
+ const npm = versionOf(src, 'package.json');
25
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'luckiest-plugin-sync-'));
26
+ sh('git', ['clone', '--depth', '1', remote, dir]);
27
+
28
+ if (versionOf(dir, '.claude-plugin/plugin.json') === plugin) return { status: 'synced', dir, changes: [] };
29
+
30
+ // --checksum: a same-size edit with a matching mtime is otherwise skipped (a version bump is same-size).
31
+ sh('rsync', ['-a', '--checksum', '--delete', '--exclude', '.git', '--exclude', '.DS_Store', '--exclude', '__pycache__', `${src}/`, `${dir}/`]);
32
+ const changes = sh('git', ['status', '--porcelain'], dir).split('\n').filter(Boolean);
33
+ if (dryRun) return { status: 'dry-run', dir, changes };
34
+
35
+ const branch = `sync-${plugin}`;
36
+ const title = `Sync plugin ${plugin} (npm luckiest-co ${npm})`;
37
+ sh('git', ['switch', '-c', branch], dir);
38
+ sh('git', ['add', '-A'], dir);
39
+ sh('git', ['commit', '-m', title], dir);
40
+ sh('git', ['push', '-u', 'origin', branch], dir);
41
+ const url = sh('gh', ['pr', 'create', '--repo', REPO, '--head', branch, '--title', title, '--body', `Mirrors packages/luckiest-plugin at plugin ${plugin}.`], dir);
42
+ return { status: 'pr', dir, changes, url };
43
+ }
44
+
45
+ if (require.main === module) {
46
+ try {
47
+ const { status, dir, changes, url } = syncPluginRepo({ dryRun: process.argv.includes('--dry-run') });
48
+ if (status === 'synced') console.log(` ${green}${REPO} already has this plugin version.${reset}`);
49
+ if (status === 'dry-run') console.log(` ${yellow}Dry run, nothing pushed.${reset} ${changes.length} changed files in ${dir}:\n${changes.map((c) => ` ${c}`).join('\n')}`);
50
+ if (status === 'pr') console.log(` ${green}Opened ${url}${reset}`);
51
+ } catch (err) {
52
+ console.error(` ${(err.stderr || err.message).toString().trim()}`);
53
+ process.exit(1);
54
+ }
55
+ }
56
+
57
+ module.exports = { syncPluginRepo };
package/package.json CHANGED
@@ -1,10 +1,15 @@
1
1
  {
2
2
  "name": "luckiest-co",
3
- "version": "1.0.35",
3
+ "version": "1.0.36",
4
4
  "description": "Luckiest for Claude Code: plan, go, finish. Your luckiest.co skills and tribe, inside Claude.",
5
5
  "bin": {
6
6
  "luckiest-co": "./bin/install.js"
7
7
  },
8
+ "scripts": {
9
+ "prepublishOnly": "node bin/check-version.js",
10
+ "bump": "node bin/bump-version.js",
11
+ "sync-plugin": "node bin/sync-plugin-repo.js"
12
+ },
8
13
  "files": [
9
14
  "bin",
10
15
  "commands",
@@ -15,7 +20,8 @@
15
20
  ".claude-plugin",
16
21
  "!**/__pycache__",
17
22
  "!**/*.pyc",
18
- "!bin/*.test.js"
23
+ "!bin/*.test.js",
24
+ "!bin/check-version.js"
19
25
  ],
20
26
  "license": "SEE LICENSE IN LICENSE",
21
27
  "engines": {
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  name: luckiest-charms
3
+ user-invocable: false
3
4
  description: "Your Luckiest charms balance and recent related activity. Use when the user says /luckiest charms, luckiest charms, or asks about their charms."
4
5
  ---
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  name: luckiest-finish
3
+ user-invocable: false
3
4
  description: "Wrap up a completed Luckiest plan: recap what shipped, close it out, award charms. Use when the user says /luckiest finish, luckiest finish, or all plan tasks are done."
4
5
  ---
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  name: luckiest-go
3
+ user-invocable: false
3
4
  description: "Run the active Luckiest plan, one task at a time, checked as it goes. Use when the user says /luckiest go, luckiest go, or wants to continue their staged Luckiest plan."
4
5
  ---
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  name: luckiest-helpers
3
+ user-invocable: false
3
4
  description: "See who in your Luckiest tribe needs a hand right now, and claim a request to help. Use when the user says /luckiest helpers, luckiest helpers, or asks who needs help."
4
5
  ---
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  name: luckiest-home
3
+ user-invocable: false
3
4
  description: "The Luckiest community dashboard: wishes and charms, plan progress, tribe pulse, and who needs help. Use when the user says /luckiest home, luckiest home, or asks for their Luckiest dashboard."
4
5
  ---
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  name: luckiest-leaderboard
3
+ user-invocable: false
3
4
  description: "See how the Luckiest tribe ranks: top scores, one bar chart. Use when the user says /luckiest leaderboard, luckiest leaderboard, or asks for tribe rankings."
4
5
  ---
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  name: luckiest-merge
3
+ user-invocable: false
3
4
  description: "Merge two overlapping Luckiest skills into one, after the user reviews the diff. Use when the user says /luckiest merge, luckiest merge, or wants to combine overlapping skills."
4
5
  ---
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  name: luckiest-next
3
+ user-invocable: false
3
4
  description: "Do the suggested next step: runs the last Next line from this chat, or picks up the plan where it stands. Use when the user says /next, /luckiest next, luckiest next, or next step."
4
5
  ---
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  name: luckiest-overlaps
3
+ user-invocable: false
3
4
  description: "Find installed Luckiest skills that overlap with your own, and resolve them. Use when the user says /luckiest overlaps, luckiest overlaps, or asks about duplicate skills."
4
5
  ---
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  name: luckiest-plan
3
+ user-invocable: false
3
4
  description: "Use when the user says /luckiest plan or luckiest plan, or wants to plan a feature, a launch, or their next piece of work before building it, even if they do not say plan (for example \"what should I build next\" or \"break this down into tasks\"). Looks at the project first, drafts 3 to 7 tasks with a suggested skill, model, and runnable check each, saves the context for /luckiest go, and stages the plan after one approval question."
4
5
  ---
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  name: luckiest-skills
3
+ user-invocable: false
3
4
  description: "Your Luckiest skills: list what is installed, pull new purchases. Use when the user says /luckiest skills, luckiest skills, or asks what Luckiest skills they have."
4
5
  ---
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  name: luckiest-start
3
+ user-invocable: false
3
4
  description: "A short interview about your project that writes your Brand Brief. Use when the user says /luckiest start, luckiest start, or wants to set up Luckiest for a project."
4
5
  ---
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  name: luckiest-status
3
+ user-invocable: false
3
4
  description: "Where you are in your Luckiest plan: progress, tasks, and your one next step. Use when the user says /luckiest status, luckiest status, or asks where their plan stands."
4
5
  ---
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  name: luckiest-updates
3
+ user-invocable: false
3
4
  description: "Check for updates to your installed Luckiest skills and plugin. Use when the user says /luckiest updates, luckiest updates, or asks if their Luckiest install is current."
4
5
  ---
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  name: luckiest-vouch
3
+ user-invocable: false
3
4
  description: "Request or approve a warm intro to someone outside your Luckiest tribe. Use when the user says /luckiest vouch, luckiest vouch, or asks for an intro."
4
5
  ---
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  name: luckiest-wishes
3
+ user-invocable: false
3
4
  description: "Your Luckiest wishes balance and recent related activity. Use when the user says /luckiest wishes, luckiest wishes, or asks about their wishes."
4
5
  ---
5
6