feat(cli): claudemesh skill prints bundled SKILL.md (v1.18.0)
Zero-install access to the protocol reference: a fresh `npm i -g claudemesh-cli` user (or someone running the prebuilt binary) can now `claudemesh skill | claude --skill-add -` without copying any files into ~/.claude/skills. The skill markdown is embedded into the CLI bundle at build time via Bun's text-import attribute. Also replaces two `<> ALL(...)` raw SQL fragments in the dashboard unread-count queries with drizzle's notInArray() helper — matches the same fix already applied to /v1/me/topics in the API package. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "claudemesh-cli",
|
"name": "claudemesh-cli",
|
||||||
"version": "1.17.0",
|
"version": "1.18.0",
|
||||||
"description": "Peer mesh for Claude Code sessions — CLI + MCP server.",
|
"description": "Peer mesh for Claude Code sessions — CLI + MCP server.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"claude-code",
|
"claude-code",
|
||||||
|
|||||||
21
apps/cli/src/commands/skill.ts
Normal file
21
apps/cli/src/commands/skill.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* `claudemesh skill` — print the bundled SKILL.md to stdout.
|
||||||
|
*
|
||||||
|
* Zero-install access: the skill is embedded into the binary at build
|
||||||
|
* time via Bun's text-import attribute, so a fresh `npm i -g` user
|
||||||
|
* (or someone running the prebuilt binary) can pipe the contents into
|
||||||
|
* Claude Code (or anywhere else) without copying files into
|
||||||
|
* ~/.claude/skills.
|
||||||
|
*
|
||||||
|
* claudemesh skill | claude --skill-add -
|
||||||
|
* claudemesh skill > /tmp/cm.md
|
||||||
|
*/
|
||||||
|
|
||||||
|
import skillContent from "../../skills/claudemesh/SKILL.md" with { type: "text" };
|
||||||
|
import { EXIT } from "~/constants/exit-codes.js";
|
||||||
|
|
||||||
|
export async function runSkill(): Promise<number> {
|
||||||
|
process.stdout.write(skillContent);
|
||||||
|
if (!skillContent.endsWith("\n")) process.stdout.write("\n");
|
||||||
|
return EXIT.SUCCESS;
|
||||||
|
}
|
||||||
@@ -123,6 +123,7 @@ Topic (conversation scope, v0.2.0)
|
|||||||
claudemesh topic tail <topic> live SSE tail [--limit --forward-only]
|
claudemesh topic tail <topic> live SSE tail [--limit --forward-only]
|
||||||
claudemesh topic post <t> <msg> encrypted REST post (v0.3.0 v2) [--reply-to <id>]
|
claudemesh topic post <t> <msg> encrypted REST post (v0.3.0 v2) [--reply-to <id>]
|
||||||
claudemesh send "#topic" "msg" send to a topic (WS path, v1 plaintext)
|
claudemesh send "#topic" "msg" send to a topic (WS path, v1 plaintext)
|
||||||
|
claudemesh skill print the bundled SKILL.md to stdout
|
||||||
claudemesh me cross-mesh workspace overview (v0.4.0)
|
claudemesh me cross-mesh workspace overview (v0.4.0)
|
||||||
claudemesh me topics cross-mesh topic list [--unread]
|
claudemesh me topics cross-mesh topic list [--unread]
|
||||||
claudemesh me notifications cross-mesh @-mentions [--all] [--since=ISO]
|
claudemesh me notifications cross-mesh @-mentions [--all] [--since=ISO]
|
||||||
@@ -538,10 +539,14 @@ async function main(): Promise<void> {
|
|||||||
case "skill": {
|
case "skill": {
|
||||||
const sub = positionals[0];
|
const sub = positionals[0];
|
||||||
const f = { mesh: flags.mesh as string, json: !!flags.json };
|
const f = { mesh: flags.mesh as string, json: !!flags.json };
|
||||||
if (sub === "list") { const { runSkillList } = await import("~/commands/platform-actions.js"); process.exit(await runSkillList({ ...f, query: positionals[1] })); }
|
// No subcommand → print the bundled SKILL.md to stdout. Lets a
|
||||||
|
// fresh user pipe `claudemesh skill | claude --skill-add -`
|
||||||
|
// without copying anything into ~/.claude/skills (v1.18.0).
|
||||||
|
if (!sub) { const { runSkill } = await import("~/commands/skill.js"); process.exit(await runSkill()); }
|
||||||
|
else if (sub === "list") { const { runSkillList } = await import("~/commands/platform-actions.js"); process.exit(await runSkillList({ ...f, query: positionals[1] })); }
|
||||||
else if (sub === "get") { const { runSkillGet } = await import("~/commands/platform-actions.js"); process.exit(await runSkillGet(positionals[1] ?? "", f)); }
|
else if (sub === "get") { const { runSkillGet } = await import("~/commands/platform-actions.js"); process.exit(await runSkillGet(positionals[1] ?? "", f)); }
|
||||||
else if (sub === "remove") { const { runSkillRemove } = await import("~/commands/platform-actions.js"); process.exit(await runSkillRemove(positionals[1] ?? "", f)); }
|
else if (sub === "remove") { const { runSkillRemove } = await import("~/commands/platform-actions.js"); process.exit(await runSkillRemove(positionals[1] ?? "", f)); }
|
||||||
else { console.error("Usage: claudemesh skill <list|get|remove>"); process.exit(EXIT.INVALID_ARGS); }
|
else { console.error("Usage: claudemesh skill (print bundled SKILL.md)\n claudemesh skill <list|get|remove>"); process.exit(EXIT.INVALID_ARGS); }
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "vault": {
|
case "vault": {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
meshTopicMember,
|
meshTopicMember,
|
||||||
meshTopicMessage,
|
meshTopicMessage,
|
||||||
} from "@turbostarter/db/schema/mesh";
|
} from "@turbostarter/db/schema/mesh";
|
||||||
import { aliasedTable, and, count, desc, eq, gt, inArray, isNull, or, sql } from "drizzle-orm";
|
import { aliasedTable, and, count, desc, eq, gt, inArray, isNull, notInArray, or, sql } from "drizzle-orm";
|
||||||
|
|
||||||
import { appConfig } from "~/config/app";
|
import { appConfig } from "~/config/app";
|
||||||
import { pathsConfig } from "~/config/paths";
|
import { pathsConfig } from "~/config/paths";
|
||||||
@@ -110,7 +110,7 @@ export default async function UniversePage() {
|
|||||||
and(
|
and(
|
||||||
inArray(meshTopic.meshId, meshIds),
|
inArray(meshTopic.meshId, meshIds),
|
||||||
isNull(meshTopic.archivedAt),
|
isNull(meshTopic.archivedAt),
|
||||||
sql`${meshTopicMessage.senderMemberId} <> ALL(${myMemberIds})`,
|
notInArray(meshTopicMessage.senderMemberId, myMemberIds),
|
||||||
or(
|
or(
|
||||||
isNull(meshTopicMember.lastReadAt),
|
isNull(meshTopicMember.lastReadAt),
|
||||||
sql`${meshTopicMessage.createdAt} > ${meshTopicMember.lastReadAt}`,
|
sql`${meshTopicMessage.createdAt} > ${meshTopicMember.lastReadAt}`,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
meshTopicMember,
|
meshTopicMember,
|
||||||
meshTopicMessage,
|
meshTopicMessage,
|
||||||
} from "@turbostarter/db/schema/mesh";
|
} from "@turbostarter/db/schema/mesh";
|
||||||
import { and, asc, count, eq, inArray, isNull, or, sql } from "drizzle-orm";
|
import { and, asc, count, eq, inArray, isNull, notInArray, or, sql } from "drizzle-orm";
|
||||||
|
|
||||||
import { pathsConfig } from "~/config/paths";
|
import { pathsConfig } from "~/config/paths";
|
||||||
import { getSession } from "~/lib/auth/server";
|
import { getSession } from "~/lib/auth/server";
|
||||||
@@ -107,7 +107,7 @@ export default async function WorkspaceTopicsPage() {
|
|||||||
.where(
|
.where(
|
||||||
and(
|
and(
|
||||||
inArray(meshTopicMessage.topicId, topicIds),
|
inArray(meshTopicMessage.topicId, topicIds),
|
||||||
sql`${meshTopicMessage.senderMemberId} <> ALL(${myMemberIds})`,
|
notInArray(meshTopicMessage.senderMemberId, myMemberIds),
|
||||||
or(
|
or(
|
||||||
isNull(meshTopicMember.lastReadAt),
|
isNull(meshTopicMember.lastReadAt),
|
||||||
sql`${meshTopicMessage.createdAt} > ${meshTopicMember.lastReadAt}`,
|
sql`${meshTopicMessage.createdAt} > ${meshTopicMember.lastReadAt}`,
|
||||||
|
|||||||
@@ -298,6 +298,15 @@ level, or wire claudemesh to messaging surfaces beyond Claude Code.
|
|||||||
default returns last 30d). CLI: omitting `--mesh` on each
|
default returns last 30d). CLI: omitting `--mesh` on each
|
||||||
verb routes through the matching aggregator. *Shipped
|
verb routes through the matching aggregator. *Shipped
|
||||||
2026-05-03 in CLI v1.16.0.*
|
2026-05-03 in CLI v1.16.0.*
|
||||||
|
- **v0.5.2 — `claudemesh skill` prints the bundled SKILL.md** —
|
||||||
|
zero-install access for the protocol reference. SKILL.md is
|
||||||
|
embedded into the CLI bundle at build time via Bun's
|
||||||
|
text-import attribute, so `claudemesh skill` works on a
|
||||||
|
fresh `npm i -g` or the prebuilt binary without any
|
||||||
|
`~/.claude/skills/` setup. Pipe it: `claudemesh skill |
|
||||||
|
claude --skill-add -`. Existing `claudemesh skill <list|get|
|
||||||
|
remove>` subcommands (mesh-shared skills) preserved. *Shipped
|
||||||
|
2026-05-03 in CLI v1.18.0.*
|
||||||
- **v0.5.1 — peer list self-marking + send self-DM guard** —
|
- **v0.5.1 — peer list self-marking + send self-DM guard** —
|
||||||
`peer list` now tags rows from the caller's own member with
|
`peer list` now tags rows from the caller's own member with
|
||||||
`(this session)` or `(your other session)`, so a paste from
|
`(this session)` or `(your other session)`, so a paste from
|
||||||
|
|||||||
Reference in New Issue
Block a user