@rayul/kordis 0.1.1 → 0.1.2

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/assets/KORDIS.md CHANGED
@@ -1,86 +1,31 @@
1
1
  ---
2
2
  name: kordis
3
- description: Use Kordis to discover, install, and publish agentic-coding packages (skills, project rules, MCP servers, custom agents, hooks). Invoke whenever the user says "find a skill for X", "install Y", "publish this as a skill", "share this prompt", or mentions a `{username}/{slug}` package identifier.
4
- version: 0.0.1
3
+ description: Use Kordis whenever the user mentions finding, installing, sharing, or publishing skills, project-rules, custom-agents, MCP servers, or hooks; or names any `<username>/<slug>` identifier. Pushy on purpose — Claude under-triggers. Detailed flows live in four on-demand sub-skills installed alongside this hub.
4
+ type: skill
5
+ version: 0.1.2
5
6
  ---
6
7
 
7
- # Kordis Skill
8
+ # Kordis
8
9
 
9
- Kordis is the public registry for agentic-coding packages. You install and publish by shelling out to the `kordis` CLI — never by editing tool-specific files (CLAUDE.md, `.cursorrules`, `.mcp.json`, etc.) manually.
10
+ Kordis is the public registry for agentic-coding packages (`skill`,
11
+ `project-rules`, `custom-agent`, `mcp-server`, `hook`). ALWAYS use the `kordis`
12
+ CLI — NEVER hand-edit `.cursorrules`, `.mcp.json`, `.claude/agents/`,
13
+ `.claude/skills/`, or other tool config files for Kordis content. Hand-edits
14
+ drift; the CLI keeps state coherent and resolves dependencies.
10
15
 
11
- ## When to invoke
16
+ Trigger Kordis when the user:
17
+ - asks to find, install, share, or publish such a package
18
+ - names a `<username>/<slug>` identifier
19
+ - asks what is trending or rising
12
20
 
13
- - User asks to find / try / install a skill, rule, agent, MCP server, or hook.
14
- - User references a `{username}/{slug}` identifier.
15
- - User says "publish this", "share this to Kordis", "push this rule".
16
- - User asks what packages they have installed or what's trending.
21
+ Verbs: `kordis search`, `info`, `read`, `pull`, `push`, `comment`, `star`,
22
+ `whoami`/`login`/`logout`. ALWAYS pass `--json` when parsing programmatically.
17
23
 
18
- ## Primary verbs
24
+ Detail lives in four on-demand sub-skills (auto-loaded by description match):
25
+ - `kordis-search` — find and browse packages
26
+ - `kordis-using` — `read` vs `pull`, behaviour per package type, attribution
27
+ - `kordis-publishing` — author and push packages
28
+ - `kordis-social` — comment, star, identity
19
29
 
20
- | verb | purpose | sub-skill |
21
- |------|---------|-----------|
22
- | `kordis search <query>` | find packages | `SEARCH` |
23
- | `kordis info <full_slug>` | inspect a package | `READ` |
24
- | `kordis read <full_slug>` | **JIT** — fetch body into your context, no install | `READ` |
25
- | `kordis pull <full_slug>` | install into the current project | `READ` |
26
- | `kordis push <file>` | publish a new package or version | `WRITE` |
27
- | `kordis whoami` / `login` / `logout` | identity + session | `SOCIAL` |
28
-
29
- Always pass `--json` when you need the response programmatically. Human output is for the user; agent parsing lives behind `--json`.
30
-
31
- ## JIT read vs install — choose deliberately
32
-
33
- Two ways to use a package's guidance. Pick the one that matches the user's intent, not your own convenience.
34
-
35
- | Mode | Use when | Effect |
36
- |------|----------|--------|
37
- | `kordis read <slug>` | **One-shot sub-task.** You'll consult the skill once for the current task and move on. The user said "do X for me", "handle this file", "explain how Y works." | Body returned to your context (stdout). Nothing written to disk. |
38
- | `kordis pull <slug>` | **Long-term adoption.** The user said "install Y", "make this project use Z", "set up A for ongoing work." The skill should keep working in future sessions. | Files written into the project's tool-specific path. |
39
-
40
- **Default to `read`** when you spontaneously realize a Kordis skill exists for the task at hand. **Default to `pull`** when the user explicitly asks to adopt a package.
41
-
42
- Restrictions on `read`:
43
- - Eligible types: `skill`, `project-rules`, `custom-agent` (text-bearing).
44
- - Ineligible: `mcp-server`, `hook`. The CLI errors with `jit_blocked` (exit 33, flag `type_ineligible`) — fall back to `kordis pull`.
45
- - Trust gate: only `review_status=passed` versions are returned by default. For `pending_review`, re-run with `--allow-pending` only after telling the user the skill has not been AI-reviewed yet.
46
-
47
- Pin a version when reproducibility matters: `kordis read foo/bar@1.2.0`. A bare slug fetches the latest passed version; the response always includes the resolved version so you can record it.
48
-
49
- ## Attribution
50
-
51
- The `read` response includes an `attribution` string (e.g. `"following rayul/hwp-reader@0.3.1"`). Including it in your reply to the user is **recommended**:
52
- - It lets the user verify which guidance you followed.
53
- - It's how creators see their work being used.
54
- - It supports reproducibility (the user can repeat the workflow with the same version).
55
-
56
- Skip it only if it would clutter a non-technical answer (e.g. the user asked a casual question and a one-line credit at the end is enough). When in doubt, include it.
57
-
58
- ## Identity
59
-
60
- `full_slug` is always `{username}/{slug}`. Usernames are immutable; slugs are lowercase-with-hyphens. Versions are semver.
61
-
62
- ## Sub-skills
63
-
64
- - `kordis read rayul/kordis-search` — searching / browsing / trending / rising
65
- - `kordis read rayul/kordis-read` — info / content / pull / dependency handling
66
- - `kordis read rayul/kordis-write` — authoring + publishing + updating
67
- - `kordis read rayul/kordis-social` — comments, stars, notifications, mod actions
68
-
69
- Load the sub-skill that matches the user's intent rather than repeating the detail here.
70
-
71
- ## Error handling
72
-
73
- The CLI's `--json` mode emits `{ error: { code, message, flags?, request_id? } }` on failure. Key codes:
74
-
75
- | code | action |
76
- |------|--------|
77
- | `not_authenticated` (exit 10) | run `kordis login`, then retry |
78
- | `validation_failed` (30) | fix the flags listed and retry |
79
- | `ai_review_rejected` (32) | explain to the user; do not auto-retry |
80
- | `conflict` (40) | slug taken → suggest a new name |
81
- | `rate_limited` (31) | wait `retry_after_seconds` |
82
- | `network_unreachable` (20) | retry with backoff |
83
-
84
- ## Agent skills compliance
85
-
86
- The skill files Kordis ships respect the Agent Skills open spec verbatim — no Kordis-specific extensions leak into your `SKILL.md`. Kordis-internal metadata lives on the registry entry, not in the skill file. Install `kordis/agent-skills` for the canonical workflow if the user is authoring their own skills.
30
+ If `kordis: command not found`, install with `npm i -g @rayul/kordis` and
31
+ ensure your npm-global `bin` (commonly `~/.npm-global/bin`) is on `PATH`.
@@ -0,0 +1,64 @@
1
+ ---
2
+ name: kordis-publishing
3
+ description: Use whenever the user wants to publish, share, or push a package to Kordis — phrases like "publish this", "share this skill to Kordis", "push this rule", "release a new version of <slug>". Covers dry-run flow, frontmatter requirements, and the AI review pipeline.
4
+ type: skill
5
+ allowed-tools: ["Bash(kordis:*)", "Read", "Edit"]
6
+ ---
7
+
8
+ # Kordis: Authoring & Publishing
9
+
10
+ ## Goal
11
+ Publish a valid, AI-review-passing version. ALWAYS dry-run first.
12
+
13
+ ## Frontmatter requirements
14
+ - `name` — must equal slug, lowercase-with-hyphens.
15
+ - `description` — 1–2 sentences, slightly pushy ("Use whenever the user…").
16
+ Claude under-triggers without pushiness.
17
+ - `version` — semver.
18
+ - `license` — SPDX (e.g. `MIT`, `Apache-2.0`, `CC-BY-4.0`).
19
+ - Optional: `homepage`, `tags`.
20
+
21
+ If the body is third-party content, MUST preserve the original copyright and
22
+ license text inside the body and link to source via `homepage`.
23
+
24
+ ## Steps
25
+
26
+ ### 1. Dry-run
27
+ `kordis push <file> --dry-run --json`. Returns the same validation, conflict,
28
+ and AI-review verdicts a real push would produce.
29
+
30
+ **Success criteria**: dry-run returns a `status: "published"`-shaped envelope
31
+ with no error flags.
32
+
33
+ ### 2. Resolve flags
34
+ Possible verdicts:
35
+ - `validation_failed` (exit 30) — fix every listed flag, re-dry-run.
36
+ - `conflict` (exit 40) — slug taken; suggest a different slug.
37
+ - `ai_review_rejected` (exit 32) — EXPLAIN the rejection to the user. Do NOT
38
+ silently retry.
39
+ - `rate_limited` (exit 31) — wait `retry_after_seconds`.
40
+
41
+ **Success criteria**: dry-run is clean.
42
+
43
+ ### 3. Real push
44
+ `kordis push <file> --json`.
45
+
46
+ **Success criteria**: returns `{full_slug, version, url}`. Show all three to
47
+ the user.
48
+
49
+ ## Examples
50
+
51
+ <example>
52
+ User: "publish my new skill"
53
+ 1. kordis push ./SKILL.md --dry-run --json
54
+ 2. validation_failed → list each flag, fix the file, re-run
55
+ 3. clean → kordis push ./SKILL.md --json
56
+ 4. show {full_slug, version, url}
57
+ </example>
58
+
59
+ <example>
60
+ User: "release v0.2.0 of <full_slug>"
61
+ 1. update `version: 0.2.0` in the file's frontmatter
62
+ 2. kordis push <file> --dry-run --json
63
+ 3. clean → kordis push <file> --json
64
+ </example>
@@ -0,0 +1,64 @@
1
+ ---
2
+ name: kordis-search
3
+ description: Use whenever the user wants to find, browse, or discover Kordis packages. Triggers include "find a Kordis skill for…", "search Kordis for…", "what's trending on Kordis", "is there a Kordis package for…", or any phrase pairing a topic with the word "Kordis". Pushy on purpose — Claude tends to skip Kordis search when it would help.
4
+ type: skill
5
+ allowed-tools: ["Bash(kordis:*)"]
6
+ ---
7
+
8
+ # Kordis: Search & Discovery
9
+
10
+ ## Goal
11
+ Help the user find a Kordis package that fits their need. ALWAYS rely on real
12
+ search results — NEVER fabricate slugs.
13
+
14
+ ## Commands
15
+ - `kordis search <query> --json` — keyword search, ranked. Filters:
16
+ `--type {skill|project-rules|custom-agent|mcp-server|hook}`,
17
+ `--tier {A|B}`, `--sort {stars|recent}`.
18
+ - `kordis search --trending --json` — discovery without query.
19
+ - `kordis search --rising --json` — fast-moving newcomers.
20
+ - `kordis info <full_slug> --json` — inspect metadata before reading or
21
+ pulling.
22
+
23
+ ## Steps
24
+
25
+ ### 1. Form the query
26
+ Pick a keyword that matches the user's task; restrict by `--type` if the user
27
+ named one. **Success criteria**: a non-empty query string and (when known) the
28
+ right `--type` filter.
29
+
30
+ ### 2. Run the search
31
+ ALWAYS with `--json`. **Success criteria**: CLI exits 0 and returns a results
32
+ array.
33
+
34
+ ### 3. Triage the results
35
+ - Prefer tier A, `review_status=passed`, higher star count.
36
+ - IMPORTANT: if results are 0, RELAX one filter at a time before giving up.
37
+ Do NOT invent a slug to fill the gap.
38
+ - Surface the top 3–5 to the user with slug, type, tier, stars, and a
39
+ one-line description.
40
+
41
+ **Success criteria**: user picked one, or you reported "no fit" honestly.
42
+
43
+ ## Examples
44
+
45
+ <example>
46
+ User: "find me a popular Python skill"
47
+ - kordis search python --type skill --sort stars --json
48
+ - list top 5 with slugs and one-line descriptions
49
+ - ask which to read or pull
50
+ </example>
51
+
52
+ <example>
53
+ User: "convert this .hwp file to text"
54
+ - kordis search hwp --json
55
+ - if 0 results, drop optional filters and retry; otherwise pick the top
56
+ passed result and hand off to kordis-using
57
+ - if still 0, tell the user honestly and fall back to a generic library
58
+ </example>
59
+
60
+ <example>
61
+ User: "what's trending on Kordis"
62
+ - kordis search --trending --json
63
+ - show top 5–10; do NOT fetch bodies unless asked
64
+ </example>
@@ -0,0 +1,49 @@
1
+ ---
2
+ name: kordis-social
3
+ description: Use whenever the user wants to interact with the Kordis community — log in, leave a review or question on a package, star a package, or check identity. Triggers include "leave a review on…", "star <slug>", "comment on <slug>", "log into Kordis", "who am I logged in as".
4
+ type: skill
5
+ allowed-tools: ["Bash(kordis:*)"]
6
+ ---
7
+
8
+ # Kordis: Social
9
+
10
+ ## Goal
11
+ Drive identity (login state) and community interactions (comments, stars).
12
+
13
+ ## Commands
14
+ - `kordis whoami --json` — current login state.
15
+ - `kordis login` — opens device-flow pairing in the browser. Required before
16
+ `push` or any authenticated action.
17
+ - `kordis logout` — clears local tokens.
18
+ - `kordis comment <full_slug> --kind <kind> --title <t> --body <b>`.
19
+ `<kind>` ∈ `{review, question, issue, note}`.
20
+ - `kordis star <full_slug>` / `kordis unstar <full_slug>`.
21
+
22
+ ## Steps
23
+
24
+ ### 1. Verify identity (if needed)
25
+ `kordis whoami --json`. If `not_authenticated` (exit 10) → `kordis login`,
26
+ then retry.
27
+
28
+ **Success criteria**: `whoami` returns a username.
29
+
30
+ ### 2. Run the action
31
+ Match command to user intent.
32
+
33
+ **Success criteria**: command exits 0; surface returned IDs / URLs to the
34
+ user.
35
+
36
+ ## Examples
37
+
38
+ <example>
39
+ User: "leave a review on foo/bar saying it works"
40
+ - kordis whoami --json # ensure logged in
41
+ - kordis star foo/bar
42
+ - kordis comment foo/bar --kind review --title "Works" --body "<paraphrase>"
43
+ </example>
44
+
45
+ <example>
46
+ User: "who am I logged into Kordis as"
47
+ - kordis whoami --json
48
+ - show username + session expiry
49
+ </example>
@@ -0,0 +1,97 @@
1
+ ---
2
+ name: kordis-using
3
+ description: Use whenever the user wants to consult or install a Kordis package — including any `<username>/<slug>` reference, "install this skill", "use the X skill", "fetch the Y rule", "set this repo up with…". Covers JIT read vs pull, the five Kordis package types, dependencies, and attribution. Load eagerly when in doubt.
4
+ type: skill
5
+ allowed-tools: ["Bash(kordis:*)"]
6
+ ---
7
+
8
+ # Kordis: Reading & Installing
9
+
10
+ ## Goal
11
+ Pick the right mode (`read` vs `pull`), respect type-specific restrictions,
12
+ surface dependencies, and credit the author.
13
+
14
+ ## read vs pull
15
+
16
+ | Mode | Use when | Effect |
17
+ | ----- | ------------------------------------------ | ---------------------------------------- |
18
+ | read | One-shot consultation, you'll use it once. | Body returned to context. No disk write. |
19
+ | pull | Long-term: user said "install" / "set up". | Files written into the current project. |
20
+
21
+ DEFAULT to `read` when you spontaneously want to consult a skill. DEFAULT to
22
+ `pull` when the user explicitly asks to adopt a package.
23
+
24
+ `read` restrictions:
25
+ - Eligible: `skill`, `project-rules`, `custom-agent`.
26
+ - INELIGIBLE: `mcp-server`, `hook` → must `pull`. CLI exits 33 (`jit_blocked`).
27
+ - Trust gate: only `review_status=passed` returned by default. For
28
+ `pending_review`, re-run with `--allow-pending` AFTER warning the user it
29
+ has not been AI-reviewed.
30
+
31
+ Pin a version when reproducibility matters:
32
+ `kordis read <full_slug>@<version>`.
33
+
34
+ ## Behaviour per package type
35
+
36
+ ### `skill`
37
+ LLM-facing recipe (Markdown body following the open Agent Skills spec).
38
+ - DEFAULT: `read`.
39
+ - `pull` writes to `~/.claude/skills/<slug>/SKILL.md`.
40
+
41
+ ### `project-rules`
42
+ Repo-scoped agent instructions (Cursor `.cursorrules`, Claude Code project
43
+ `CLAUDE.md` snippets, etc.). Only meaningful inside a project.
44
+ - DEFAULT: `pull`. `read` allowed for inspection.
45
+ - `pull` writes inside the **current repo**, never `$HOME`.
46
+
47
+ ### `custom-agent`
48
+ Sub-agent definitions (e.g. Claude Code `.claude/agents/`).
49
+ - `read` allowed (preview the agent's system prompt).
50
+ - `pull` to make the agent invokable; tell the user how to call it after.
51
+
52
+ ### `mcp-server`
53
+ Model Context Protocol server packages.
54
+ - `read` is INELIGIBLE → CLI returns `jit_blocked`. ALWAYS `pull`.
55
+ - After pull, instruct the user to restart the agent and supply any required
56
+ env vars.
57
+
58
+ ### `hook`
59
+ Event-driven scripts (pre-commit, pre-tool-call, etc.) that run on the user's
60
+ machine.
61
+ - `read` is INELIGIBLE → ALWAYS `pull`.
62
+ - IMPORTANT: hooks execute arbitrary code. EXPLAIN in plain words what the
63
+ hook does, and confirm with the user BEFORE pulling.
64
+
65
+ ## Dependencies
66
+ If `kordis pull` reports unresolved dependencies, the CLI lists them with
67
+ `<full_slug>`s. Surface the dependency tree to the user FIRST. Never
68
+ auto-resolve silently.
69
+
70
+ ## Attribution
71
+ `kordis read` returns an `attribution` string naming the package and version.
72
+ RECOMMENDED: end your reply with `following <full_slug>@<version>`. Skip only
73
+ when it would clutter a casual non-technical reply.
74
+
75
+ ## Examples
76
+
77
+ <example>
78
+ User: "extract structured data from this PDF"
79
+ - (delegate search to kordis-search → picks <full_slug>)
80
+ - kordis read <full_slug> --json
81
+ - follow the body, end reply with "following <full_slug>@<version>"
82
+ </example>
83
+
84
+ <example>
85
+ User: "install the github MCP server from Kordis"
86
+ - kordis info <full_slug> --json (note auth requirements + runtime)
87
+ - kordis pull <full_slug> # read is jit_blocked for mcp-server
88
+ - tell user to restart the agent and supply any tokens
89
+ </example>
90
+
91
+ <example>
92
+ User: "add a pre-commit hook that blocks committing API keys"
93
+ - kordis info <full_slug> --json
94
+ - explain in plain words what the hook does
95
+ - confirm with the user before pulling
96
+ - kordis pull <full_slug>
97
+ </example>
package/dist/index.js CHANGED
@@ -2329,11 +2329,20 @@ import { fileURLToPath as fileURLToPath2 } from "url";
2329
2329
  import { Command as Command9 } from "commander";
2330
2330
  var MARKER_START = "<!-- kordis-start -->";
2331
2331
  var MARKER_END = "<!-- kordis-end -->";
2332
- var TARGETS = [
2332
+ var HUB_TARGETS = [
2333
2333
  { tool: "Claude Code", dir: ".claude", file: ".claude/CLAUDE.md" },
2334
2334
  { tool: "Codex CLI", dir: ".codex", file: ".codex/AGENTS.md" },
2335
2335
  { tool: "Gemini CLI", dir: ".gemini", file: ".gemini/GEMINI.md" }
2336
2336
  ];
2337
+ var SUB_SKILLS = [
2338
+ "kordis-search",
2339
+ "kordis-using",
2340
+ "kordis-publishing",
2341
+ "kordis-social"
2342
+ ];
2343
+ var SKILL_TARGETS = [
2344
+ { tool: "Claude Code", dir: ".claude", skillsDir: ".claude/skills" }
2345
+ ];
2337
2346
  async function exists(path) {
2338
2347
  try {
2339
2348
  await access(path);
@@ -2342,18 +2351,32 @@ async function exists(path) {
2342
2351
  return false;
2343
2352
  }
2344
2353
  }
2345
- async function loadGuideContent() {
2354
+ function assetRoots() {
2346
2355
  const __dir2 = dirname3(fileURLToPath2(import.meta.url));
2347
- const bundled = join5(__dir2, "..", "assets", "KORDIS.md");
2348
- const source = join5(__dir2, "..", "..", "..", "..", "packages", "skills", "KORDIS.md");
2349
- const path = await exists(bundled) ? bundled : source;
2350
- const raw = await readFile4(path, "utf-8");
2356
+ return {
2357
+ // Built binary: bin/kordis.js → assets/ is one level up
2358
+ bundled: join5(__dir2, "..", "assets"),
2359
+ // Dev mode: src/commands/setup.ts → 4 levels up to repo root, then packages/skills/
2360
+ source: join5(__dir2, "..", "..", "..", "..", "packages", "skills")
2361
+ };
2362
+ }
2363
+ async function pickAssetRoot() {
2364
+ const { bundled, source } = assetRoots();
2365
+ return await exists(join5(bundled, "KORDIS.md")) ? bundled : source;
2366
+ }
2367
+ async function loadHubContent() {
2368
+ const root = await pickAssetRoot();
2369
+ const raw = await readFile4(join5(root, "KORDIS.md"), "utf-8");
2351
2370
  if (raw.startsWith("---")) {
2352
2371
  const end = raw.indexOf("\n---", 4);
2353
2372
  if (end !== -1) return raw.slice(end + 4).trimStart();
2354
2373
  }
2355
2374
  return raw;
2356
2375
  }
2376
+ async function loadSubSkillContent(name) {
2377
+ const root = await pickAssetRoot();
2378
+ return readFile4(join5(root, name, "SKILL.md"), "utf-8");
2379
+ }
2357
2380
  async function injectBlock(filePath, content, dryRun) {
2358
2381
  const block = `${MARKER_START}
2359
2382
  ${content.trimEnd()}
@@ -2388,20 +2411,38 @@ ${MARKER_END}`;
2388
2411
  }
2389
2412
  return "injected";
2390
2413
  }
2414
+ async function copyBundledSkill(filePath, content, dryRun) {
2415
+ let existing = null;
2416
+ try {
2417
+ existing = await readFile4(filePath, "utf-8");
2418
+ } catch {
2419
+ }
2420
+ if (existing === content) return "unchanged";
2421
+ if (!dryRun) {
2422
+ await mkdir4(dirname3(filePath), { recursive: true });
2423
+ await writeFile4(filePath, content, "utf-8");
2424
+ }
2425
+ return existing === null ? "injected" : "updated";
2426
+ }
2391
2427
  function setupCommand() {
2392
2428
  return new Command9("setup").description("inject kordis usage guide into global agent instruction files").option("--silent", "suppress errors \u2014 safe for postinstall").option("--dry-run", "detect installed tools without writing any files").action(async (opts) => {
2393
2429
  const home = homedir3();
2394
2430
  const dryRun = opts.dryRun ?? false;
2395
- let guideContent;
2431
+ let hubContent;
2432
+ let subSkillContents;
2396
2433
  try {
2397
- guideContent = await loadGuideContent();
2434
+ hubContent = await loadHubContent();
2435
+ const entries = await Promise.all(
2436
+ SUB_SKILLS.map(async (name) => [name, await loadSubSkillContent(name)])
2437
+ );
2438
+ subSkillContents = Object.fromEntries(entries);
2398
2439
  } catch (err) {
2399
2440
  if (opts.silent) return;
2400
2441
  throw err;
2401
2442
  }
2402
2443
  let anyFound = false;
2403
- const changedTools = [];
2404
- for (const target of TARGETS) {
2444
+ const changedTools = /* @__PURE__ */ new Set();
2445
+ for (const target of HUB_TARGETS) {
2405
2446
  const dirPath = join5(home, target.dir);
2406
2447
  const filePath = join5(home, target.file);
2407
2448
  if (!await exists(dirPath)) {
@@ -2412,15 +2453,15 @@ function setupCommand() {
2412
2453
  }
2413
2454
  anyFound = true;
2414
2455
  try {
2415
- const result = await injectBlock(filePath, guideContent, dryRun);
2416
- if (result !== "unchanged") changedTools.push(target.tool);
2456
+ const result = await injectBlock(filePath, hubContent, dryRun);
2457
+ if (result !== "unchanged") changedTools.add(target.tool);
2417
2458
  if (opts.silent) continue;
2418
- const label = `${target.tool.padEnd(12)}`;
2459
+ const label = target.tool.padEnd(12);
2419
2460
  const dest = `~/${target.file}`;
2420
2461
  if (result === "unchanged") {
2421
2462
  printHuman(c.gray(` \u2713 ${label} already up-to-date`));
2422
2463
  } else if (dryRun) {
2423
- printHuman(` ~ ${label} ${c.cyan(dest)} (dry-run: would ${result})`);
2464
+ printHuman(` ~ ${label} ${c.cyan(dest)} (dry-run: would ${result === "injected" ? "inject" : "update"})`);
2424
2465
  } else {
2425
2466
  printHuman(c.green(` \u2713 ${label} \u2192 ${dest}`));
2426
2467
  }
@@ -2429,10 +2470,34 @@ function setupCommand() {
2429
2470
  printHuman(c.red(` \u2717 ${target.tool}: ${err.message}`));
2430
2471
  }
2431
2472
  }
2473
+ for (const target of SKILL_TARGETS) {
2474
+ const dirPath = join5(home, target.dir);
2475
+ if (!await exists(dirPath)) continue;
2476
+ for (const subName of SUB_SKILLS) {
2477
+ const filePath = join5(home, target.skillsDir, subName, "SKILL.md");
2478
+ const dest = `~/${target.skillsDir}/${subName}/SKILL.md`;
2479
+ try {
2480
+ const result = await copyBundledSkill(filePath, subSkillContents[subName], dryRun);
2481
+ if (result !== "unchanged") changedTools.add(target.tool);
2482
+ if (opts.silent) continue;
2483
+ const label = `${target.tool} \xB7 ${subName}`.padEnd(34);
2484
+ if (result === "unchanged") {
2485
+ printHuman(c.gray(` \u2713 ${label} already up-to-date`));
2486
+ } else if (dryRun) {
2487
+ printHuman(` ~ ${label} ${c.cyan(dest)} (dry-run: would ${result === "injected" ? "inject" : "update"})`);
2488
+ } else {
2489
+ printHuman(c.green(` \u2713 ${label} \u2192 ${dest}`));
2490
+ }
2491
+ } catch (err) {
2492
+ if (opts.silent) continue;
2493
+ printHuman(c.red(` \u2717 ${target.tool} \xB7 ${subName}: ${err.message}`));
2494
+ }
2495
+ }
2496
+ }
2432
2497
  if (opts.silent) {
2433
- if (changedTools.length > 0 && !dryRun) {
2498
+ if (changedTools.size > 0 && !dryRun) {
2434
2499
  printHuman(
2435
- c.green("\u2713 kordis") + ` registered with ${changedTools.join(", ")} \xB7 restart your agent session to apply`
2500
+ c.green("\u2713 kordis") + ` registered with ${[...changedTools].join(", ")} \xB7 restart your agent session to apply`
2436
2501
  );
2437
2502
  }
2438
2503
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rayul/kordis",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "private": false,
5
5
  "description": "Command-line client for the Kordis registry — discover, install, and publish agentic-coding packages.",
6
6
  "license": "MIT",
@@ -17,7 +17,7 @@
17
17
  ],
18
18
  "scripts": {
19
19
  "dev": "tsx src/index.ts",
20
- "build": "tsup && mkdir -p assets && cp ../../packages/skills/KORDIS.md assets/KORDIS.md",
20
+ "build": "tsup && rm -rf assets && mkdir -p assets && cp -R ../../packages/skills/. assets/",
21
21
  "typecheck": "tsc --noEmit",
22
22
  "test": "vitest run",
23
23
  "postinstall": "node ./bin/kordis.js setup --silent"