luckiest-co 1.0.20 → 1.0.21
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/.claude-plugin/plugin.json +1 -1
- package/commands/status.md +10 -0
- package/hooks/hooks.json +11 -1
- package/hooks/update-notice.mjs +56 -0
- package/package.json +1 -1
- package/skills/luckiest-status/SKILL.md +10 -0
package/commands/status.md
CHANGED
|
@@ -46,6 +46,16 @@ Map each task's status to a glyph (these are the task status values, not the pla
|
|
|
46
46
|
- "assist" -> `?`
|
|
47
47
|
- "blocked" -> `✗`
|
|
48
48
|
|
|
49
|
+
## Update notice
|
|
50
|
+
|
|
51
|
+
If earlier in this session the Luckiest session-start hook reported a newer version (a line like "Luckiest X is available (you have Y)"), add one line under the dashboard, outside the code block:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
Update available: Y → X. Update the luckiest plugin from /plugin.
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Otherwise add nothing. Do not call any tool for this.
|
|
58
|
+
|
|
49
59
|
## Step 3: Recommend next action
|
|
50
60
|
|
|
51
61
|
End your response with exactly one line, nothing after it, derived from the MCP `nextAction` field:
|
package/hooks/hooks.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"description": "Luckiest plugin hooks — deterministic skill-usage telemetry on every Luckiest skill run.",
|
|
2
|
+
"description": "Luckiest plugin hooks — deterministic skill-usage telemetry on every Luckiest skill run, and a weekly update notice at session start.",
|
|
3
3
|
"hooks": {
|
|
4
4
|
"PostToolUse": [
|
|
5
5
|
{
|
|
@@ -11,6 +11,16 @@
|
|
|
11
11
|
}
|
|
12
12
|
]
|
|
13
13
|
}
|
|
14
|
+
],
|
|
15
|
+
"SessionStart": [
|
|
16
|
+
{
|
|
17
|
+
"hooks": [
|
|
18
|
+
{
|
|
19
|
+
"type": "command",
|
|
20
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/update-notice.mjs\""
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
14
24
|
]
|
|
15
25
|
}
|
|
16
26
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SessionStart hook: at most once every 7 days, compare this plugin's version to
|
|
3
|
+
// the published one and, only when behind, show one line in chat. Silent when
|
|
4
|
+
// current, when checked recently, or on any failure. Sends nothing: one GET of a
|
|
5
|
+
// public file.
|
|
6
|
+
// ponytail: marketplace installs only (registered via hooks.json). npx installs
|
|
7
|
+
// already self-update daily through `npx luckiest-co@latest --sync-only`, so the
|
|
8
|
+
// installer does not register this.
|
|
9
|
+
|
|
10
|
+
import { readFileSync, writeFileSync, mkdirSync, statSync } from "node:fs";
|
|
11
|
+
import { join, dirname } from "node:path";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
13
|
+
import { homedir } from "node:os";
|
|
14
|
+
|
|
15
|
+
const WEEK_MS = 7 * 24 * 60 * 60 * 1000;
|
|
16
|
+
const MANIFEST_URL =
|
|
17
|
+
process.env.LUCKIEST_PLUGIN_MANIFEST_URL ||
|
|
18
|
+
"https://raw.githubusercontent.com/luckiestco/luckiest-plugin/main/.claude-plugin/plugin.json";
|
|
19
|
+
const STAMP = join(homedir(), ".luckiest", "last-update-check");
|
|
20
|
+
|
|
21
|
+
const root = process.env.CLAUDE_PLUGIN_ROOT || join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
22
|
+
|
|
23
|
+
// Numeric major.minor.patch only, same rule as check_updates' cmpSemver.
|
|
24
|
+
export const newer = (a, b) => {
|
|
25
|
+
const pa = String(a).split(".").map((n) => parseInt(n, 10) || 0);
|
|
26
|
+
const pb = String(b).split(".").map((n) => parseInt(n, 10) || 0);
|
|
27
|
+
for (let i = 0; i < 3; i++) if ((pa[i] || 0) !== (pb[i] || 0)) return (pa[i] || 0) > (pb[i] || 0);
|
|
28
|
+
return false;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
async function main() {
|
|
32
|
+
try {
|
|
33
|
+
if (Date.now() - statSync(STAMP).mtimeMs < WEEK_MS) return;
|
|
34
|
+
} catch {
|
|
35
|
+
/* no stamp yet */
|
|
36
|
+
}
|
|
37
|
+
const installed = JSON.parse(readFileSync(join(root, ".claude-plugin", "plugin.json"), "utf8")).version;
|
|
38
|
+
const res = await fetch(MANIFEST_URL, { signal: AbortSignal.timeout(3000) });
|
|
39
|
+
if (!res.ok) return;
|
|
40
|
+
const latest = (await res.json()).version;
|
|
41
|
+
mkdirSync(dirname(STAMP), { recursive: true });
|
|
42
|
+
writeFileSync(STAMP, String(Date.now()));
|
|
43
|
+
if (!installed || !latest || !newer(latest, installed)) return;
|
|
44
|
+
const msg = `Luckiest ${latest} is available (you have ${installed}). Update the luckiest plugin from /plugin to get it.`;
|
|
45
|
+
process.stdout.write(
|
|
46
|
+
JSON.stringify({
|
|
47
|
+
systemMessage: msg,
|
|
48
|
+
hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: msg },
|
|
49
|
+
}),
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
54
|
+
await main().catch(() => {});
|
|
55
|
+
process.exit(0);
|
|
56
|
+
}
|
package/package.json
CHANGED
|
@@ -80,6 +80,16 @@ Map each task's status to a glyph (these are the task status values, not the pla
|
|
|
80
80
|
- "assist" -> `?`
|
|
81
81
|
- "blocked" -> `✗`
|
|
82
82
|
|
|
83
|
+
## Update notice
|
|
84
|
+
|
|
85
|
+
If earlier in this session the Luckiest session-start hook reported a newer version (a line like "Luckiest X is available (you have Y)"), add one line under the dashboard, outside the code block:
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
Update available: Y → X. Update the luckiest plugin from /plugin.
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Otherwise add nothing. Do not call any tool for this.
|
|
92
|
+
|
|
83
93
|
## Step 3: Recommend next action
|
|
84
94
|
|
|
85
95
|
End your response with exactly one line, nothing after it, derived from the MCP `nextAction` field:
|