@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 +22 -77
- package/assets/kordis-publishing/SKILL.md +64 -0
- package/assets/kordis-search/SKILL.md +64 -0
- package/assets/kordis-social/SKILL.md +49 -0
- package/assets/kordis-using/SKILL.md +97 -0
- package/dist/index.js +81 -16
- package/package.json +2 -2
package/assets/KORDIS.md
CHANGED
|
@@ -1,86 +1,31 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: kordis
|
|
3
|
-
description: Use Kordis
|
|
4
|
-
|
|
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
|
|
8
|
+
# Kordis
|
|
8
9
|
|
|
9
|
-
Kordis is the public registry for agentic-coding packages
|
|
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
|
-
|
|
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
|
-
|
|
14
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
2354
|
+
function assetRoots() {
|
|
2346
2355
|
const __dir2 = dirname3(fileURLToPath2(import.meta.url));
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
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
|
|
2431
|
+
let hubContent;
|
|
2432
|
+
let subSkillContents;
|
|
2396
2433
|
try {
|
|
2397
|
-
|
|
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
|
|
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,
|
|
2416
|
-
if (result !== "unchanged") changedTools.
|
|
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 =
|
|
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.
|
|
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.
|
|
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
|
|
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"
|