@rayul/kordis 0.14.0 → 0.15.0
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 +9 -0
- package/assets/MEMGINEERING.md +7 -6
- package/assets/kordis-search/SKILL.md +31 -0
- package/assets/kordis-using/SKILL.md +43 -7
- package/assets/memgineering-registry/SKILL.md +45 -29
- package/assets/memgineering-writing/SKILL.md +2 -0
- package/dist/index.js +230 -72
- package/package.json +1 -1
package/assets/KORDIS.md
CHANGED
|
@@ -35,6 +35,15 @@ from reusable domain knowledge, structure, or templates, run
|
|
|
35
35
|
`kordis read <full_slug>` before proceeding; otherwise continue ad hoc.
|
|
36
36
|
NEVER fabricate a slug.
|
|
37
37
|
|
|
38
|
+
**Search in the user's own words** — NEVER translate the user's query
|
|
39
|
+
before searching, in any language. Pass their words through verbatim. The
|
|
40
|
+
server already translates the non-Latin words it knows AND keeps the
|
|
41
|
+
originals in the same query, so a query you pre-translated searches strictly
|
|
42
|
+
less: it can no longer reach titles and keywords written in that language.
|
|
43
|
+
The answer names what else was searched and which words it could not
|
|
44
|
+
translate — relay both, because a word it skipped may be the one that
|
|
45
|
+
mattered.
|
|
46
|
+
|
|
38
47
|
**Judgment patterns** — `judgment-pattern` packages carry agentic _judgment_
|
|
39
48
|
(when to switch modes, what to verify, what NOT to do), not installable files.
|
|
40
49
|
Don't install them: `kordis read` one, or `kordis adapt <slug>` to get a brief
|
package/assets/MEMGINEERING.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: memgineering
|
|
3
3
|
description: Use whenever the user refers to something they told you before, asks what was decided, tells you something worth keeping, or settles something that should hold next time. The memory lives in their own folder and outlives this session; check it before answering from guesswork, and write to it when you learn something durable.
|
|
4
4
|
type: skill
|
|
5
|
-
version: 0.
|
|
5
|
+
version: 0.20.0
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# memgineering
|
|
@@ -68,11 +68,12 @@ never attribute a decision to somebody this conversation has not mentioned.
|
|
|
68
68
|
|
|
69
69
|
## The public layer
|
|
70
70
|
|
|
71
|
-
`memgineering search <words>` finds one,
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
71
|
+
`memgineering registry search <words>` finds one,
|
|
72
|
+
`memgineering registry read <user>/<slug>` inlines it and
|
|
73
|
+
`memgineering registry adapt <user>/<slug>` briefs you on fitting it here.
|
|
74
|
+
Neither writes a file or a note, so an empty brain works from day one; only
|
|
75
|
+
what this user confirms goes in. `memgineering registry publish <ref>` sends
|
|
76
|
+
one out — dry run until `--yes`, only when they said to.
|
|
76
77
|
|
|
77
78
|
## Where the detail is
|
|
78
79
|
|
|
@@ -67,6 +67,21 @@ the right filters.
|
|
|
67
67
|
ALWAYS with `--json`. **Success criteria**: CLI exits 0 and returns a results
|
|
68
68
|
array.
|
|
69
69
|
|
|
70
|
+
**If the response carries `query_translation`, SAY SO in your answer.** It has
|
|
71
|
+
three parts and each changes how the user should read your results:
|
|
72
|
+
`translated` (what else was searched on their behalf — a slash means either
|
|
73
|
+
word matches), and `unmapped` (words the lexicon did not know, which therefore
|
|
74
|
+
reached the index only as typed). One sentence before the results is enough:
|
|
75
|
+
"searched your words as typed, and also as `commit message rule/convention`".
|
|
76
|
+
|
|
77
|
+
This is a rule, not a flourish. The user cannot see the field — only you can —
|
|
78
|
+
so an unreported translation makes a widened search look like a narrow one, and
|
|
79
|
+
an unreported `unmapped` makes a thin answer read as "the registry has nothing"
|
|
80
|
+
when it may mean "two of your three words were never looked up". Measured
|
|
81
|
+
2026-09-07: agents that had this only as an example in the Examples section
|
|
82
|
+
relayed it 0 times out of 2 on the weaker tier while seeing the field every
|
|
83
|
+
time.
|
|
84
|
+
|
|
70
85
|
### 3. Triage the results
|
|
71
86
|
|
|
72
87
|
- Prefer `review_status: passed`, higher `stars`, then `tier: A`.
|
|
@@ -109,6 +124,22 @@ User: "find me a Python skill"
|
|
|
109
124
|
- ask which to read or pull
|
|
110
125
|
</example>
|
|
111
126
|
|
|
127
|
+
<example>
|
|
128
|
+
User: "커밋 메시지 규칙 패키지 있어?"
|
|
129
|
+
- kordis search "커밋 메시지 규칙" --json — the user's words, VERBATIM
|
|
130
|
+
- do NOT search `"commit message rule"` instead. The registry being mostly
|
|
131
|
+
English is not a reason to translate first: the server already searches the
|
|
132
|
+
English terms AND the Korean originals in one query, so your translation
|
|
133
|
+
only subtracts — Korean titles and the Korean keywords on English packages
|
|
134
|
+
become unreachable
|
|
135
|
+
- the response carries `query_translation` {original, translated, unmapped}
|
|
136
|
+
- tell the user what else was searched ("commit message rule/convention" — a
|
|
137
|
+
slash means either word matches) and
|
|
138
|
+
which words the lexicon skipped (`unmapped`); a row may have matched only
|
|
139
|
+
the translation. If `unmapped` is non-empty and the answer is thin, say so
|
|
140
|
+
before concluding the registry has nothing — those words were never searched
|
|
141
|
+
</example>
|
|
142
|
+
|
|
112
143
|
<example>
|
|
113
144
|
User: "convert this .hwp file to text"
|
|
114
145
|
- kordis search hwp --json
|
|
@@ -86,13 +86,41 @@ Writes files into the current project.
|
|
|
86
86
|
| `--no-with-required` | skip transitive required deps (advanced; default installs) |
|
|
87
87
|
|
|
88
88
|
IMPORTANT: `pull` **fails fast** when the target tool can't be inferred from
|
|
89
|
-
the cwd
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
the cwd. Pass `--tool <name>` explicitly in a project that has not been
|
|
90
|
+
initialised for any tool yet. Don't rely on the old "drop a canonical
|
|
91
|
+
SKILL.md at cwd" fallback — Claude Code never picked it up.
|
|
92
|
+
|
|
93
|
+
Auto-detection is ordered by EVIDENCE, not by vendor. A project is matched
|
|
94
|
+
against, in order: `.claude/` → `.codex/` → `.gemini/` → `.agents/` →
|
|
95
|
+
`AGENTS.md` → `CLAUDE.md` → `GEMINI.md`, then the rules-file markers
|
|
96
|
+
(`.cursorrules`, `.windsurfrules`, `.github/copilot-instructions.md`).
|
|
97
|
+
A bare `.cursor/`, `.continue/`, `.windsurf/`, `.antigravity/` or
|
|
98
|
+
`.opencode/` directory no longer selects its own vendor — nothing has been
|
|
99
|
+
shown to read `<vendor>/skills/`. They still DETECT, and they resolve to
|
|
100
|
+
`agents-md`, so such a project gets its package somewhere with evidence behind
|
|
101
|
+
it rather than an error. An explicit `--tool` always wins over detection and
|
|
102
|
+
never changes behaviour.
|
|
103
|
+
|
|
104
|
+
`AGENTS.md` alone now resolves to `agents-md`, not to `codex`. AGENTS.md is a
|
|
105
|
+
cross-vendor standard (an Agentic AI Foundation project alongside MCP and
|
|
106
|
+
goose), so a project carrying one is not thereby a Codex project.
|
|
93
107
|
|
|
94
108
|
Valid `--tool` values: `claude-code`, `codex`, `cursor`, `continue`,
|
|
95
|
-
`windsurf`, `antigravity`, `copilot`.
|
|
109
|
+
`windsurf`, `antigravity`, `copilot`, `opencode`, `gemini-cli`, `agents-md`.
|
|
110
|
+
|
|
111
|
+
**PASS `--tool <your own tool>` WHEN YOU ARE THE ONE WHO WILL USE THE SKILL.**
|
|
112
|
+
Detection reads the project's markers, which answer "what convention does this
|
|
113
|
+
repo follow" — not "which agent is about to consume this". When the user asks
|
|
114
|
+
YOU to install a skill so that YOU behave differently from now on, the right
|
|
115
|
+
target is your own tool home, and you know that better than the directory
|
|
116
|
+
does. Say `--tool claude-code` (or `codex`, `gemini-cli`, …) and, for a habit
|
|
117
|
+
meant to outlive this one repo, `--target "$HOME"`.
|
|
118
|
+
|
|
119
|
+
Leave detection to decide when the project's convention is the point: setting a
|
|
120
|
+
repo up for whoever works in it next, or installing on behalf of a tool that is
|
|
121
|
+
not you. Measured 2026-09-07: an agent that skipped this pulled with detection,
|
|
122
|
+
read `--help`, `rm -rf`'d what it had just installed, and pulled again with
|
|
123
|
+
`--tool` — four steps to reach the target it wanted from the start.
|
|
96
124
|
|
|
97
125
|
### `kordis info <full_slug> --json`
|
|
98
126
|
|
|
@@ -107,8 +135,16 @@ user is about to execute foreign code or runtime config.
|
|
|
107
135
|
LLM-facing recipe (Markdown body following the open Agent Skills spec).
|
|
108
136
|
|
|
109
137
|
- DEFAULT: `read`.
|
|
110
|
-
- `pull` writes to the
|
|
111
|
-
|
|
138
|
+
- `pull` writes to the detected tool's skill path — `.claude/skills/<name>/SKILL.md`
|
|
139
|
+
for Claude Code, `.codex/skills/…` for Codex, `.gemini/skills/…` for Gemini CLI,
|
|
140
|
+
and `.agents/skills/<name>/SKILL.md` for `agents-md`.
|
|
141
|
+
- `.agents/skills/` is the shared one: measured 2026-09-06, both Codex 0.153.4
|
|
142
|
+
and Gemini CLI 0.56.0 load it, at project level and at `~/.agents/skills`.
|
|
143
|
+
So a package installed there is picked up by either without further setup.
|
|
144
|
+
Claude Code does not read it and keeps `.claude/skills/`.
|
|
145
|
+
- Gemini CLI only loads PROJECT skills in a folder the user has marked trusted.
|
|
146
|
+
If a freshly pulled skill does not show up, that trust prompt is the reason,
|
|
147
|
+
not the install.
|
|
112
148
|
|
|
113
149
|
### `project-rules`
|
|
114
150
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: memgineering-registry
|
|
3
3
|
description: Use when the user wants judgment somebody else has already settled — "what do other people do about this", "is there a pattern for it", "read that judgment", "adapt that pattern to this repo", "fit it to our setup", "how do others handle X" — or when one of their own decisions should go out: "publish this decision", "share this rule", "put it on memgineering", "send it to the registry". Also when they ask whether what you read gets stored. Covers the public layer: reading somebody else's judgment into context, the transplant brief, publishing one claim out of this brain, lineage, why reading is never copying, and how author-controlled text is fenced.
|
|
4
4
|
type: skill
|
|
5
|
-
version: 0.
|
|
5
|
+
version: 0.20.0
|
|
6
6
|
allowed-tools: Bash(memgineering:*)
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -12,16 +12,19 @@ memgineering.com is where settled decisions live in public. A package there is
|
|
|
12
12
|
one person's judgment — a decision, a preference, or a procedure — carrying the
|
|
13
13
|
scope it holds in, when it was true, and what it rests on.
|
|
14
14
|
|
|
15
|
-
Five verbs reach it
|
|
16
|
-
note. An identifier looks like
|
|
17
|
-
comes from the user, or from
|
|
18
|
-
read.
|
|
15
|
+
Five verbs reach it, all of them under `memgineering registry`. None of them
|
|
16
|
+
installs anything, and none of them writes a note. An identifier looks like
|
|
17
|
+
`<username>/<slug>`, optionally `@<version>`; it comes from the user, or from
|
|
18
|
+
the attribution line under something you already read.
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
Each one still answers to its bare name as well, which prints a line on stderr
|
|
21
|
+
saying so and is not the documented form — write the namespaced spelling.
|
|
22
|
+
|
|
23
|
+
## `registry search` — find one without knowing its name
|
|
21
24
|
|
|
22
25
|
```
|
|
23
|
-
memgineering search additive migrations
|
|
24
|
-
memgineering search --type judgment-pattern --limit 5
|
|
26
|
+
memgineering registry search additive migrations
|
|
27
|
+
memgineering registry search --type judgment-pattern --limit 5
|
|
25
28
|
```
|
|
26
29
|
|
|
27
30
|
Titles, one-line descriptions, and the verb that would fetch each result. No
|
|
@@ -33,11 +36,23 @@ to drop the filter or broaden the words, and the same sentence is on `hint`
|
|
|
33
36
|
under `--json`. Take it. Guessing a third phrasing when the tool has already
|
|
34
37
|
named the lever is how one lookup becomes five.
|
|
35
38
|
|
|
36
|
-
|
|
39
|
+
NEVER translate the user's words before searching. Pass them as typed, in
|
|
40
|
+
whatever script they arrive in. That the registry is mostly English is not a
|
|
41
|
+
reason to search in English first: the server translates the words a fixed
|
|
42
|
+
lexicon knows AND searches the originals in the same query, so a pre-translated
|
|
43
|
+
query searches strictly less — the Korean titles, and the Korean keywords
|
|
44
|
+
carried by English packages, stop being reachable. The answer carries a line
|
|
45
|
+
naming what else was searched and which words were skipped
|
|
46
|
+
(`query_translation` under `--json`: `original`, `translated`, `unmapped`).
|
|
47
|
+
Relay that line — a row may have matched only the translation, and a skipped
|
|
48
|
+
word may be the one that mattered. When `unmapped` is non-empty, never report
|
|
49
|
+
"the registry has nothing" without saying which words were never searched.
|
|
50
|
+
|
|
51
|
+
## `registry read` — somebody else's judgment, in your context
|
|
37
52
|
|
|
38
53
|
```
|
|
39
|
-
memgineering read gaeullee824/ask-before-acting
|
|
40
|
-
memgineering read gaeullee824/ask-before-acting@1.2.0 --json
|
|
54
|
+
memgineering registry read gaeullee824/ask-before-acting
|
|
55
|
+
memgineering registry read gaeullee824/ask-before-acting@1.2.0 --json
|
|
41
56
|
```
|
|
42
57
|
|
|
43
58
|
Prints the body and one provenance line: what was read, of what kind, from
|
|
@@ -51,11 +66,11 @@ user that before you use it, not after.
|
|
|
51
66
|
claim about their own judgment and nothing has checked it. Weight what you
|
|
52
67
|
read accordingly, and say which tier it was when you hand it to the user.
|
|
53
68
|
|
|
54
|
-
## `info` — what it is, before you read it
|
|
69
|
+
## `registry info` — what it is, before you read it
|
|
55
70
|
|
|
56
71
|
```
|
|
57
|
-
memgineering info gaeullee824/ask-before-acting
|
|
58
|
-
memgineering info gaeullee824/ask-before-acting@1.2.0
|
|
72
|
+
memgineering registry info gaeullee824/ask-before-acting
|
|
73
|
+
memgineering registry info gaeullee824/ask-before-acting@1.2.0
|
|
59
74
|
```
|
|
60
75
|
|
|
61
76
|
Metadata only, and no body is fetched: title, description, kind, version,
|
|
@@ -67,10 +82,10 @@ Reach for it when a search result is close but not obviously right, or on a
|
|
|
67
82
|
package nothing can read: a hook or an MCP server has no body to inline, so
|
|
68
83
|
`read` would be refused and this is the verb that still answers.
|
|
69
84
|
|
|
70
|
-
## `adapt` — a transplant brief for THIS project
|
|
85
|
+
## `registry adapt` — a transplant brief for THIS project
|
|
71
86
|
|
|
72
87
|
```
|
|
73
|
-
memgineering adapt gaeullee824/ask-before-acting
|
|
88
|
+
memgineering registry adapt gaeullee824/ask-before-acting
|
|
74
89
|
```
|
|
75
90
|
|
|
76
91
|
**Run it from the user's project root.** It reads the harness in the current
|
|
@@ -104,8 +119,8 @@ That row goes to whichever brain this machine is pointed at, and `read` and
|
|
|
104
119
|
`adapt` both take the pair `publish` takes for naming a different one:
|
|
105
120
|
|
|
106
121
|
```
|
|
107
|
-
memgineering read gaeullee824/ask-before-acting --local
|
|
108
|
-
memgineering adapt gaeullee824/ask-before-acting --vault ~/notes
|
|
122
|
+
memgineering registry read gaeullee824/ask-before-acting --local
|
|
123
|
+
memgineering registry adapt gaeullee824/ask-before-acting --vault ~/notes
|
|
109
124
|
```
|
|
110
125
|
|
|
111
126
|
`--local` files the row beside the brain on this disk even when the machine is
|
|
@@ -141,11 +156,11 @@ you need the raw bytes, strip the first and last line using the sentinel value;
|
|
|
141
156
|
do not pattern-match the marker text, because marker-looking lines inside a
|
|
142
157
|
body are neutralized with a zero-width space and are part of the data.
|
|
143
158
|
|
|
144
|
-
## `publish` — one decision of theirs, out
|
|
159
|
+
## `registry publish` — one decision of theirs, out
|
|
145
160
|
|
|
146
161
|
```
|
|
147
|
-
memgineering publish friday-review
|
|
148
|
-
memgineering publish friday-review --yes --reason "<the user's own words>"
|
|
162
|
+
memgineering registry publish friday-review
|
|
163
|
+
memgineering registry publish friday-review --yes --reason "<the user's own words>"
|
|
149
164
|
```
|
|
150
165
|
|
|
151
166
|
Bare, it sends nothing: it prints the exact bytes that would leave and says so.
|
|
@@ -170,13 +185,13 @@ A note that declares `never_store` words is refused too — that is the boundary
|
|
|
170
185
|
itself, not a judgment to share.
|
|
171
186
|
|
|
172
187
|
**Publishing the same decision again.** When the note has changed and its
|
|
173
|
-
package already exists, `memgineering publish <ref> --bump patch`
|
|
174
|
-
next version of it — `minor` or `major` when the judgment moved
|
|
175
|
-
name only holds one of each version, so without `--bump` a second
|
|
176
|
-
the same name is refused. A `--bump` is refused too if the
|
|
177
|
-
different note; give that one its own `--slug`. If the
|
|
178
|
-
rejected by review, its body cannot be fetched to check
|
|
179
|
-
ahead on the account alone and prints a line saying so.
|
|
188
|
+
package already exists, `memgineering registry publish <ref> --bump patch`
|
|
189
|
+
publishes the next version of it — `minor` or `major` when the judgment moved
|
|
190
|
+
further. The name only holds one of each version, so without `--bump` a second
|
|
191
|
+
publish under the same name is refused. A `--bump` is refused too if the
|
|
192
|
+
package came from a different note; give that one its own `--slug`. If the
|
|
193
|
+
published version was rejected by review, its body cannot be fetched to check
|
|
194
|
+
that — the bump goes ahead on the account alone and prints a line saying so.
|
|
180
195
|
|
|
181
196
|
What crosses: the claim, its scope, its validity, its evidence, and the note's
|
|
182
197
|
title and summary. **Not the body.** `--slug` names the package when the title
|
|
@@ -202,7 +217,8 @@ another machine leaves no record here.
|
|
|
202
217
|
|
|
203
218
|
Installing files, stars, follows, comments, and withdrawing a release stay in
|
|
204
219
|
the `kordis` CLI for one release window. The public layer's verbs are
|
|
205
|
-
`search`, `info`, `read`, `adapt` and
|
|
220
|
+
`registry search`, `registry info`, `registry read`, `registry adapt` and
|
|
221
|
+
`registry publish`.
|
|
206
222
|
|
|
207
223
|
`memgineering pull` is unrelated: it is the brain verb for a hosted brain, not
|
|
208
224
|
a registry install.
|
|
@@ -188,6 +188,8 @@ neither the command nor you should rewrite it uninvited.
|
|
|
188
188
|
```
|
|
189
189
|
memgineering retire <ref> --reason "the date moved" # no longer current, still visible
|
|
190
190
|
memgineering exclude path/to/note.md --reason "it has someone's phone number in it" # stop reading it
|
|
191
|
+
memgineering retract --actor "mcp:ChatGPT" --since 2026-09-01 # SHOWS what one writer / window wrote
|
|
192
|
+
memgineering retract --actor "mcp:ChatGPT" --since 2026-09-01 --yes # retires all of it, one ledger row each
|
|
191
193
|
```
|
|
192
194
|
|
|
193
195
|
Retiring keeps the note in recall, ranked last and labelled. Excluding takes it
|
package/dist/index.js
CHANGED
|
@@ -36,7 +36,8 @@ var init_primitives = __esm({
|
|
|
36
36
|
"continue",
|
|
37
37
|
"copilot",
|
|
38
38
|
"opencode",
|
|
39
|
-
"gemini-cli"
|
|
39
|
+
"gemini-cli",
|
|
40
|
+
"agents-md"
|
|
40
41
|
]);
|
|
41
42
|
TagSchema = z.string().min(1).max(32).regex(/^[a-z0-9]+(-[a-z0-9]+)*$/);
|
|
42
43
|
UrlSchema = z.string().url().startsWith("http");
|
|
@@ -502,12 +503,34 @@ var init_manifest = __esm({
|
|
|
502
503
|
modes: ["read", "install"],
|
|
503
504
|
default: "read"
|
|
504
505
|
}),
|
|
505
|
-
// Rules merge into a file the project already owns (.
|
|
506
|
-
//
|
|
506
|
+
// Rules merge into a file the project already owns (CLAUDE.md, AGENTS.md,
|
|
507
|
+
// GEMINI.md, …) — the reason they need review, not just approval.
|
|
508
|
+
//
|
|
509
|
+
// Cursor is the exception, and it is declared per host rather than folded
|
|
510
|
+
// into the wildcard. Its current rules format is one `.mdc` file per rule
|
|
511
|
+
// under `.cursor/rules/`, so Kordis writes a whole file Cursor did not have
|
|
512
|
+
// instead of appending to a file the project owns. That is a `create`, and
|
|
513
|
+
// declaring it as a merge would be a false statement about what install
|
|
514
|
+
// does — `packages/translators/src/parity.test.ts` compares this table
|
|
515
|
+
// against what the translators actually emit, per host, and catches exactly
|
|
516
|
+
// that. Risk is unchanged: `deriveAggregates` still sees a merge among the
|
|
517
|
+
// effects, so project-rules stays `review-required`.
|
|
507
518
|
"project-rules": (input) => build(input, {
|
|
508
519
|
kind: "rules",
|
|
509
520
|
profile: null,
|
|
510
|
-
effects: [
|
|
521
|
+
effects: [
|
|
522
|
+
{ host: "claude-code", phase: "install", mode: "filesystem-merge" },
|
|
523
|
+
{ host: "codex", phase: "install", mode: "filesystem-merge" },
|
|
524
|
+
{ host: "agents-md", phase: "install", mode: "filesystem-merge" },
|
|
525
|
+
{ host: "gemini-cli", phase: "install", mode: "filesystem-merge" },
|
|
526
|
+
{ host: "windsurf", phase: "install", mode: "filesystem-merge" },
|
|
527
|
+
{ host: "copilot", phase: "install", mode: "filesystem-merge" },
|
|
528
|
+
{ host: "continue", phase: "install", mode: "filesystem-merge" },
|
|
529
|
+
{ host: "antigravity", phase: "install", mode: "filesystem-merge" },
|
|
530
|
+
{ host: "opencode", phase: "install", mode: "filesystem-merge" },
|
|
531
|
+
{ host: "canonical", phase: "install", mode: "filesystem-merge" },
|
|
532
|
+
{ host: "cursor", phase: "install", mode: "filesystem-create" }
|
|
533
|
+
],
|
|
511
534
|
modes: ["read", "install"],
|
|
512
535
|
default: "read"
|
|
513
536
|
}),
|
|
@@ -1035,7 +1058,7 @@ var init_auth = __esm({
|
|
|
1035
1058
|
|
|
1036
1059
|
// ../../packages/contracts/src/api.ts
|
|
1037
1060
|
import { z as z11 } from "zod";
|
|
1038
|
-
var SearchQuerySchema, SearchResponseSchema, TrendingQuerySchema, RisingQuerySchema, StarResponseSchema, AssetSchema, LineageEdgeInputSchema, LineageRelativeSchema, LineageStatsSchema, LineageGraphResponseSchema, PublishPackageRequestSchema, PublishWaitQuerySchema, PublishPackageResponseSchema, PackagePathParamsSchema, ContentQuerySchema, PackageContentResponseSchema, JitReadRequestSchema, JitReadResponseSchema, PullPackageRequestSchema, PullPackageResponseSchema, YankRequestSchema, YankResponseSchema, ResolveVersionQuerySchema, ResolveVersionResponseSchema, GetPackageQuerySchema, ListVersionsResponseSchema, VersionDiffQuerySchema, ListCommentsQuerySchema, ListCommentsResponseSchema, UserProfileResponseSchema, UserPackagesQuerySchema, ListUserPackagesResponseSchema, ListUserStarsResponseSchema, FollowResponseSchema, ListFollowersQuerySchema, ListFollowersResponseSchema;
|
|
1061
|
+
var SearchQuerySchema, SearchQueryTranslationSchema, SearchResponseSchema, TrendingQuerySchema, RisingQuerySchema, StarResponseSchema, AssetSchema, LineageEdgeInputSchema, LineageRelativeSchema, LineageStatsSchema, LineageGraphResponseSchema, PublishPackageRequestSchema, PublishWaitQuerySchema, PublishPackageResponseSchema, PackagePathParamsSchema, ContentQuerySchema, PackageContentResponseSchema, JitReadRequestSchema, JitReadResponseSchema, PullPackageRequestSchema, PullPackageResponseSchema, YankRequestSchema, YankResponseSchema, ResolveVersionQuerySchema, ResolveVersionResponseSchema, GetPackageQuerySchema, ListVersionsResponseSchema, VersionDiffQuerySchema, ListCommentsQuerySchema, ListCommentsResponseSchema, UserProfileResponseSchema, UserPackagesQuerySchema, ListUserPackagesResponseSchema, ListUserStarsResponseSchema, FollowResponseSchema, ListFollowersQuerySchema, ListFollowersResponseSchema;
|
|
1039
1062
|
var init_api = __esm({
|
|
1040
1063
|
"../../packages/contracts/src/api.ts"() {
|
|
1041
1064
|
"use strict";
|
|
@@ -1057,7 +1080,15 @@ var init_api = __esm({
|
|
|
1057
1080
|
limit: z11.coerce.number().int().min(1).max(100).default(20),
|
|
1058
1081
|
cursor: CursorSchema.optional()
|
|
1059
1082
|
});
|
|
1060
|
-
|
|
1083
|
+
SearchQueryTranslationSchema = z11.object({
|
|
1084
|
+
kind: z11.literal("lexicon"),
|
|
1085
|
+
original: z11.string(),
|
|
1086
|
+
translated: z11.string(),
|
|
1087
|
+
unmapped: z11.array(z11.string())
|
|
1088
|
+
});
|
|
1089
|
+
SearchResponseSchema = paginatedResponseSchema(PackageSummarySchema).extend({
|
|
1090
|
+
query_translation: SearchQueryTranslationSchema.optional()
|
|
1091
|
+
});
|
|
1061
1092
|
TrendingQuerySchema = z11.object({
|
|
1062
1093
|
window: TimeWindowSchema.default("24h"),
|
|
1063
1094
|
type: HarnessTypeSchema.optional(),
|
|
@@ -1308,7 +1339,22 @@ var init_api = __esm({
|
|
|
1308
1339
|
* Walk depth-0 `recommended` deps (transitive recommends NOT followed).
|
|
1309
1340
|
* Default false — opt-in noise.
|
|
1310
1341
|
*/
|
|
1311
|
-
with_recommends: z11.boolean().optional().default(false)
|
|
1342
|
+
with_recommends: z11.boolean().optional().default(false),
|
|
1343
|
+
/**
|
|
1344
|
+
* 2026-09-06 — which install target the CLI resolved for this pull
|
|
1345
|
+
* ('claude-code', 'agents-md', …). Recorded on `package_pull_events.tool`;
|
|
1346
|
+
* the server never derives it, because only the client knows which tool
|
|
1347
|
+
* home it is actually writing into.
|
|
1348
|
+
*
|
|
1349
|
+
* Why this ships without coordinating a CLI and a server release: this
|
|
1350
|
+
* schema is a NON-STRICT `z.object`, so an OLD server handed the new field
|
|
1351
|
+
* strips it rather than returning 400, and a NEW server handed no field
|
|
1352
|
+
* records NULL. Both directions degrade to "tool not recorded", which is
|
|
1353
|
+
* exactly what the nullable column already means — so CLI and server can
|
|
1354
|
+
* roll out in either order, which matters here because this repo has no CD
|
|
1355
|
+
* and the server is deployed by hand.
|
|
1356
|
+
*/
|
|
1357
|
+
tool: ToolSlugSchema.optional()
|
|
1312
1358
|
});
|
|
1313
1359
|
PullPackageResponseSchema = z11.object({
|
|
1314
1360
|
status: z11.enum(["installed", "already_installed", "skipped"]),
|
|
@@ -1451,8 +1497,12 @@ var init_context = __esm({
|
|
|
1451
1497
|
* Which agentic tool configs exist locally. Presence only — no file
|
|
1452
1498
|
* contents inspected. Used to boost packages whose `tools_compatible`
|
|
1453
1499
|
* overlaps.
|
|
1500
|
+
*
|
|
1501
|
+
* The cap is derived from the enum rather than written as a literal: a
|
|
1502
|
+
* hand-written `.max(8)` silently started rejecting honest payloads the
|
|
1503
|
+
* moment a tenth member was added, and nothing in the type system says so.
|
|
1454
1504
|
*/
|
|
1455
|
-
tools: z12.array(ToolSlugSchema).max(
|
|
1505
|
+
tools: z12.array(ToolSlugSchema).max(ToolSlugSchema.options.length).optional(),
|
|
1456
1506
|
/**
|
|
1457
1507
|
* Top-3 file extensions in CWD (excluding `.git`, `node_modules`,
|
|
1458
1508
|
* `dist`, `.next`, build artifacts). Each entry is a short lowercase
|
|
@@ -1920,6 +1970,15 @@ var init_client = __esm({
|
|
|
1920
1970
|
{ query: { range } }
|
|
1921
1971
|
);
|
|
1922
1972
|
}
|
|
1973
|
+
/**
|
|
1974
|
+
* `opts` is the CONTRACT's request type, not a hand-written copy of it.
|
|
1975
|
+
* The copy that used to live here listed three fields and silently stopped
|
|
1976
|
+
* matching the schema the moment a fourth (`tool`, 2026-09-06) was added —
|
|
1977
|
+
* callers could not pass the new field without casting, and nothing failed
|
|
1978
|
+
* until someone tried. Taking `PullPackageRequestInput` means a field added
|
|
1979
|
+
* to the schema is transmissible the same day, and a field REMOVED from it
|
|
1980
|
+
* becomes a compile error here instead of a body the server ignores.
|
|
1981
|
+
*/
|
|
1923
1982
|
pull(username, slug, opts = {}) {
|
|
1924
1983
|
return this.request(`/api/packages/${seg(username)}/${seg(slug)}/pull`, {
|
|
1925
1984
|
method: "POST",
|
|
@@ -6521,7 +6580,14 @@ async function detectTools() {
|
|
|
6521
6580
|
{ tool: "claude-code", paths: [join4(homedir2(), ".claude", "skills")] },
|
|
6522
6581
|
{ tool: "codex", paths: [join4(homedir2(), ".codex"), join4(homedir2(), ".codex", "skills")] },
|
|
6523
6582
|
{ tool: "cursor", paths: [join4(homedir2(), ".cursor")] },
|
|
6524
|
-
{ tool: "gemini-cli", paths: [join4(homedir2(), ".gemini"), join4(homedir2(), ".gemini", "skills")] }
|
|
6583
|
+
{ tool: "gemini-cli", paths: [join4(homedir2(), ".gemini"), join4(homedir2(), ".gemini", "skills")] },
|
|
6584
|
+
// `~/.agents/skills` is not one vendor's directory — measured 2026-09-06,
|
|
6585
|
+
// both codex-cli 0.153.4 and gemini-cli 0.56.0 load skills from it (Codex
|
|
6586
|
+
// lists it as a skill root; Gemini reaches it via `getUserAgentSkillsDir`).
|
|
6587
|
+
// Its presence therefore means "this machine follows the AGENTS.md
|
|
6588
|
+
// convention", which is exactly the personalization signal `agents-md`
|
|
6589
|
+
// packages should be ranked on.
|
|
6590
|
+
{ tool: "agents-md", paths: [join4(homedir2(), ".agents", "skills")] }
|
|
6525
6591
|
];
|
|
6526
6592
|
const found = [];
|
|
6527
6593
|
for (const { tool, paths } of checks) {
|
|
@@ -7234,6 +7300,7 @@ async function maybeRenderReminder() {
|
|
|
7234
7300
|
}
|
|
7235
7301
|
|
|
7236
7302
|
// src/commands/search.ts
|
|
7303
|
+
init_src();
|
|
7237
7304
|
var SORT_MODES = [
|
|
7238
7305
|
"relevance",
|
|
7239
7306
|
"stars",
|
|
@@ -7244,17 +7311,7 @@ var SORT_MODES = [
|
|
|
7244
7311
|
"rising"
|
|
7245
7312
|
];
|
|
7246
7313
|
var TIME_WINDOWS = ["24h", "7d", "30d"];
|
|
7247
|
-
var TOOL_SLUGS =
|
|
7248
|
-
"claude-code",
|
|
7249
|
-
"codex",
|
|
7250
|
-
"cursor",
|
|
7251
|
-
"antigravity",
|
|
7252
|
-
"windsurf",
|
|
7253
|
-
"continue",
|
|
7254
|
-
"copilot",
|
|
7255
|
-
"opencode",
|
|
7256
|
-
"gemini-cli"
|
|
7257
|
-
];
|
|
7314
|
+
var TOOL_SLUGS = ToolSlugSchema.options;
|
|
7258
7315
|
var TOOL_ALIASES = {
|
|
7259
7316
|
claude: "claude-code",
|
|
7260
7317
|
gemini: "gemini-cli"
|
|
@@ -7321,13 +7378,24 @@ function searchCommand() {
|
|
|
7321
7378
|
});
|
|
7322
7379
|
}
|
|
7323
7380
|
const queryProvided = query.length > 0;
|
|
7324
|
-
const
|
|
7381
|
+
const untranslatedWords = res.query_translation && res.query_translation.unmapped.length > 0 ? res.query_translation.unmapped.map(stripControl).join(", ") : "";
|
|
7382
|
+
const partialNote = untranslatedWords === "" ? "" : `${untranslatedWords} could not be translated and were searched only as typed, so this answer may be partial \u2014 tell the user which words those were before judging what the registry has. `;
|
|
7383
|
+
const baseEmptyHint = opts.type ? `no packages of type "${opts.type}" match. Try without --type, or list everything: kordis search --type ${opts.type} --sort recent --limit 25` : queryProvided ? "narrow with `--type skill|mcp-server|project-rules|custom-agent|hook|judgment-pattern` or `--tag <topic>` (e.g. aws, fastapi), broaden the keywords, or browse `--sort trending`" : 'try keywords (e.g. `kordis search "topic"`), `--tag <topic>`, or `kordis search --trending`';
|
|
7384
|
+
const emptyHintForJson = partialNote === "" ? baseEmptyHint : `${partialNote}Then ${baseEmptyHint}`;
|
|
7325
7385
|
printDual({
|
|
7326
|
-
json: res.results.length === 0 ? { ...res, hint:
|
|
7386
|
+
json: res.results.length === 0 ? { ...res, hint: emptyHintForJson } : (
|
|
7387
|
+
// A non-empty answer to a partly-untranslated query is still a
|
|
7388
|
+
// partial one, and rows that look plausible are exactly when
|
|
7389
|
+
// that goes unsaid: the session this came from read ten
|
|
7390
|
+
// unrelated hits and reported the registry had nothing, never
|
|
7391
|
+
// mentioning that two of its three words were never looked up.
|
|
7392
|
+
partialNote === "" ? res : { ...res, hint: partialNote.trimEnd() }
|
|
7393
|
+
),
|
|
7327
7394
|
human: () => {
|
|
7328
7395
|
if (res.results.length === 0) {
|
|
7329
7396
|
printHuman(c.yellow("(no results)"));
|
|
7330
|
-
|
|
7397
|
+
printTranslation(res.query_translation);
|
|
7398
|
+
printHuman(c.gray(` \u2192 ${baseEmptyHint}`));
|
|
7331
7399
|
return;
|
|
7332
7400
|
}
|
|
7333
7401
|
if (typeof res.total === "number") {
|
|
@@ -7338,6 +7406,7 @@ function searchCommand() {
|
|
|
7338
7406
|
);
|
|
7339
7407
|
printHuman("");
|
|
7340
7408
|
}
|
|
7409
|
+
printTranslation(res.query_translation);
|
|
7341
7410
|
for (const p of res.results) {
|
|
7342
7411
|
printHuman(
|
|
7343
7412
|
`${c.bold(p.full_slug)} ${c.gray(`v${p.current_version}`)} ${c.cyan(`[${p.type}]`)}`
|
|
@@ -7365,6 +7434,22 @@ function searchCommand() {
|
|
|
7365
7434
|
});
|
|
7366
7435
|
});
|
|
7367
7436
|
}
|
|
7437
|
+
function printTranslation(fb) {
|
|
7438
|
+
if (!fb) return;
|
|
7439
|
+
printHuman(
|
|
7440
|
+
c.gray(
|
|
7441
|
+
`Korean words in "${stripControl(fb.original)}" were also searched as "${stripControl(fb.translated)}" (registry ko\u2192en lexicon)`
|
|
7442
|
+
)
|
|
7443
|
+
);
|
|
7444
|
+
if (fb.unmapped.length > 0) {
|
|
7445
|
+
printHuman(
|
|
7446
|
+
c.yellow(
|
|
7447
|
+
`\u26A0 NOT searched: ${fb.unmapped.map(stripControl).join(", ")} \u2014 no lexicon entry. Say so before reporting that nothing was found.`
|
|
7448
|
+
)
|
|
7449
|
+
);
|
|
7450
|
+
}
|
|
7451
|
+
printHuman("");
|
|
7452
|
+
}
|
|
7368
7453
|
|
|
7369
7454
|
// src/commands/push.ts
|
|
7370
7455
|
init_parser();
|
|
@@ -7617,13 +7702,11 @@ var ProjectRulesFrontmatterSchema = z18.object({
|
|
|
7617
7702
|
/** When true, installation is idempotent via `<!-- kordis:... -->` markers. */
|
|
7618
7703
|
mergeable: z18.boolean().default(true),
|
|
7619
7704
|
license: z18.string().max(64).optional()
|
|
7620
|
-
}).strict().refine(
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
{ message: 'scope="globs" requires a non-empty globs list' }
|
|
7626
|
-
);
|
|
7705
|
+
}).strict().refine((v) => v.scope !== "nested" || !!v.target_path, {
|
|
7706
|
+
message: 'scope="nested" requires target_path'
|
|
7707
|
+
}).refine((v) => v.scope !== "globs" || v.globs && v.globs.length > 0, {
|
|
7708
|
+
message: 'scope="globs" requires a non-empty globs list'
|
|
7709
|
+
});
|
|
7627
7710
|
|
|
7628
7711
|
// ../../packages/harness-schema/src/types/custom-agent.ts
|
|
7629
7712
|
init_src();
|
|
@@ -8652,9 +8735,10 @@ function buildSkillFile(input, outputPath) {
|
|
|
8652
8735
|
function buildSkillDir(input, outputPath) {
|
|
8653
8736
|
const result = buildSkillFile(input, outputPath);
|
|
8654
8737
|
const skillMdPath = result.files[0].path;
|
|
8655
|
-
const
|
|
8738
|
+
const slash = skillMdPath.lastIndexOf("/");
|
|
8739
|
+
const skillDir = slash === -1 ? "" : skillMdPath.slice(0, slash);
|
|
8656
8740
|
const assetFiles = (input.assets ?? []).map((asset) => ({
|
|
8657
|
-
path: `${skillDir}/${asset.path}
|
|
8741
|
+
path: skillDir ? `${skillDir}/${asset.path}` : asset.path,
|
|
8658
8742
|
content: asset.content,
|
|
8659
8743
|
mergeable: false,
|
|
8660
8744
|
format: "plain",
|
|
@@ -8686,6 +8770,7 @@ var skillToCopilot = (input) => buildSkillSingleFile(input, ".github/skills/{nam
|
|
|
8686
8770
|
var skillToGeminiCli = (input) => buildSkillDir(input, ".gemini/skills/{name}/SKILL.md");
|
|
8687
8771
|
var skillToOpenCode = (input) => buildSkillSingleFile(input, ".opencode/skills/{name}.md");
|
|
8688
8772
|
var skillToAntigravity = (input) => buildSkillSingleFile(input, ".antigravity/skills/{name}.md");
|
|
8773
|
+
var skillToAgentsMd = (input) => buildSkillDir(input, ".agents/skills/{name}/SKILL.md");
|
|
8689
8774
|
var skillCanonical = (input) => {
|
|
8690
8775
|
const res = buildSkillDir(input, "SKILL.md");
|
|
8691
8776
|
res.format = "agent-skills-canonical";
|
|
@@ -8702,15 +8787,39 @@ function fence(input) {
|
|
|
8702
8787
|
}
|
|
8703
8788
|
var TOOL_FILE_SPEC = {
|
|
8704
8789
|
claude: { path: "CLAUDE.md", format: "markdown" },
|
|
8790
|
+
// Same file, two entries on purpose: `codex` is one vendor that reads
|
|
8791
|
+
// AGENTS.md, `agents-md` is the convention itself. Splitting them lets the
|
|
8792
|
+
// label stop lying without changing a byte of what gets written.
|
|
8705
8793
|
codex: { path: "AGENTS.md", format: "markdown" },
|
|
8706
|
-
|
|
8707
|
-
|
|
8708
|
-
|
|
8709
|
-
|
|
8710
|
-
|
|
8711
|
-
|
|
8712
|
-
|
|
8713
|
-
|
|
8794
|
+
"agents-md": { path: "AGENTS.md", format: "markdown" },
|
|
8795
|
+
// Gemini CLI's context file is GEMINI.md, and it is not an AGENTS.md reader:
|
|
8796
|
+
// the shipped 0.56.0 bundle has `DEFAULT_CONTEXT_FILENAME = "GEMINI.md"` and
|
|
8797
|
+
// zero occurrences of the string `AGENTS.md` anywhere in it (checked
|
|
8798
|
+
// 2026-09-06). A `.gemini/rules/project.md` spec used to sit here as well and
|
|
8799
|
+
// was never reachable — no such path exists in that bundle either.
|
|
8800
|
+
"gemini-cli": { path: "GEMINI.md", format: "markdown" },
|
|
8801
|
+
// `cursor` is deliberately absent from this table — `.cursor/rules/*.mdc`
|
|
8802
|
+
// is a per-package path with YAML frontmatter and a whole-file write, none
|
|
8803
|
+
// of which `ToolSpec`/`build()` can express. See `projectRulesToCursor`.
|
|
8804
|
+
//
|
|
8805
|
+
// `windsurf` is a LEGACY VENDOR NAME. Cognition rebranded Windsurf to Devin
|
|
8806
|
+
// Desktop in 2026-06 and retired Cascade on 2026-07-01, so this slug names a
|
|
8807
|
+
// product that no longer ships under that name. The slug stays because it is
|
|
8808
|
+
// a member of `ToolSlugSchema`, it is recorded in published packages'
|
|
8809
|
+
// `compatibility.hosts`, and people have scripted `--tool windsurf`.
|
|
8810
|
+
//
|
|
8811
|
+
// `.windsurfrules` is UNVERIFIED, and that is the honest status rather than
|
|
8812
|
+
// an oversight: no current Devin Desktop documentation has been read
|
|
8813
|
+
// first-hand for this path, and the Windsurf docs that once described it went
|
|
8814
|
+
// with the product name. It is kept because it is what Kordis has always
|
|
8815
|
+
// written here — not because anything confirmed it.
|
|
8816
|
+
//
|
|
8817
|
+
// Do NOT "fix" this by inventing `.devin/rules/`. There is no evidence for
|
|
8818
|
+
// that path either, and writing to a guessed path is the exact failure this
|
|
8819
|
+
// arc is correcting (compare the dead `.gemini/rules/project.md` above).
|
|
8820
|
+
// Establishing Devin Desktop's real rules location — and its skills
|
|
8821
|
+
// location, `skillToWindsurf` in `../skill/identity.ts` — is a separate
|
|
8822
|
+
// track that needs the product in hand.
|
|
8714
8823
|
windsurf: { path: ".windsurfrules", format: "plain" },
|
|
8715
8824
|
copilot: {
|
|
8716
8825
|
path: ".github/copilot-instructions.md",
|
|
@@ -8728,10 +8837,20 @@ var TOOL_FILE_SPEC = {
|
|
|
8728
8837
|
path: ".antigravity/rules/project.md",
|
|
8729
8838
|
format: "markdown"
|
|
8730
8839
|
},
|
|
8731
|
-
|
|
8732
|
-
|
|
8733
|
-
|
|
8734
|
-
|
|
8840
|
+
// `.opencode/rules/project.md` is DISPROVEN, not merely unverified: OpenCode
|
|
8841
|
+
// reads the project's `AGENTS.md` for rules (opencode.ai/docs/rules, checked
|
|
8842
|
+
// 2026-09-06; global copy at `~/.config/opencode/AGENTS.md`), and
|
|
8843
|
+
// `.opencode/` appears nowhere in that documentation. So every rules package
|
|
8844
|
+
// ever installed through this entry landed in a file OpenCode does not read.
|
|
8845
|
+
// Full evidence on `skillToOpenCode` (`../skill/identity.ts`).
|
|
8846
|
+
//
|
|
8847
|
+
// Detection no longer routes here: `TOOL_MARKERS`
|
|
8848
|
+
// (`apps/cli/src/commands/pull.ts`) maps an `AGENTS.md` project to
|
|
8849
|
+
// `agents-md`, and there is no `.opencode` marker, so an OpenCode project
|
|
8850
|
+
// now gets `AGENTS.md` written. This entry survives only for an explicit
|
|
8851
|
+
// `--tool opencode`, and only so that flag keeps working for anyone who
|
|
8852
|
+
// scripted it — the path it writes is still the wrong one.
|
|
8853
|
+
// @deprecated Use `--tool agents-md` (or plain detection) instead.
|
|
8735
8854
|
opencode: { path: ".opencode/rules/project.md", format: "markdown" }
|
|
8736
8855
|
};
|
|
8737
8856
|
function build2(spec, input, formatName) {
|
|
@@ -8750,13 +8869,37 @@ function build2(spec, input, formatName) {
|
|
|
8750
8869
|
}
|
|
8751
8870
|
var projectRulesToClaude = (input) => build2(TOOL_FILE_SPEC["claude"], input, "claude-md");
|
|
8752
8871
|
var projectRulesToCodex = (input) => build2(TOOL_FILE_SPEC["codex"], input, "agents-md");
|
|
8753
|
-
var
|
|
8754
|
-
var
|
|
8872
|
+
var projectRulesToAgentsMd = (input) => build2(TOOL_FILE_SPEC["agents-md"], input, "agents-md");
|
|
8873
|
+
var projectRulesToGeminiCli = (input) => build2(TOOL_FILE_SPEC["gemini-cli"], input, "gemini-md");
|
|
8874
|
+
var CURSOR_RULE_DIR = ".cursor/rules";
|
|
8875
|
+
var projectRulesToCursor = (input) => {
|
|
8876
|
+
const slug = input.fullSlug.split("/")[1] ?? input.fullSlug;
|
|
8877
|
+
const description = typeof input.frontmatter["description"] === "string" ? input.frontmatter["description"] : input.fullSlug;
|
|
8878
|
+
const frontmatter = `---
|
|
8879
|
+
description: ${JSON.stringify(description)}
|
|
8880
|
+
alwaysApply: true
|
|
8881
|
+
---
|
|
8882
|
+
|
|
8883
|
+
`;
|
|
8884
|
+
return {
|
|
8885
|
+
files: [
|
|
8886
|
+
{
|
|
8887
|
+
path: `${CURSOR_RULE_DIR}/kordis-${slug}.mdc`,
|
|
8888
|
+
content: frontmatter + fence(input),
|
|
8889
|
+
mergeable: false,
|
|
8890
|
+
format: "markdown"
|
|
8891
|
+
}
|
|
8892
|
+
],
|
|
8893
|
+
notes: [
|
|
8894
|
+
`Cursor rule installed at ${CURSOR_RULE_DIR}/kordis-${slug}.mdc with alwaysApply: true \u2014 it is in context for every request. Delete the file to stop that.`
|
|
8895
|
+
],
|
|
8896
|
+
format: "cursor-mdc"
|
|
8897
|
+
};
|
|
8898
|
+
};
|
|
8755
8899
|
var projectRulesToWindsurf = (input) => build2(TOOL_FILE_SPEC["windsurf"], input, "windsurfrules");
|
|
8756
8900
|
var projectRulesToCopilot = (input) => build2(TOOL_FILE_SPEC["copilot"], input, "copilot-instructions-md");
|
|
8757
8901
|
var projectRulesToContinue = (input) => build2(TOOL_FILE_SPEC["continue"], input, "continue-rules-md");
|
|
8758
8902
|
var projectRulesToAntigravity = (input) => build2(TOOL_FILE_SPEC["antigravity"], input, "antigravity-rules-md");
|
|
8759
|
-
var projectRulesToGeminiCli = (input) => build2(TOOL_FILE_SPEC["gemini-cli"], input, "gemini-cli-rules-md");
|
|
8760
8903
|
var projectRulesToOpenCode = (input) => build2(TOOL_FILE_SPEC["opencode"], input, "opencode-rules-md");
|
|
8761
8904
|
var projectRulesCanonical = (input) => ({
|
|
8762
8905
|
files: [
|
|
@@ -9072,7 +9215,8 @@ var REGISTRY = {
|
|
|
9072
9215
|
copilot: skillToCopilot,
|
|
9073
9216
|
"gemini-cli": skillToGeminiCli,
|
|
9074
9217
|
opencode: skillToOpenCode,
|
|
9075
|
-
antigravity: skillToAntigravity
|
|
9218
|
+
antigravity: skillToAntigravity,
|
|
9219
|
+
"agents-md": skillToAgentsMd
|
|
9076
9220
|
},
|
|
9077
9221
|
"project-rules": {
|
|
9078
9222
|
canonical: projectRulesCanonical,
|
|
@@ -9084,9 +9228,8 @@ var REGISTRY = {
|
|
|
9084
9228
|
copilot: projectRulesToCopilot,
|
|
9085
9229
|
"gemini-cli": projectRulesToGeminiCli,
|
|
9086
9230
|
opencode: projectRulesToOpenCode,
|
|
9087
|
-
antigravity: projectRulesToAntigravity
|
|
9088
|
-
|
|
9089
|
-
// to its own dir and "codex" to AGENTS.md. GEMINI.md alias below.
|
|
9231
|
+
antigravity: projectRulesToAntigravity,
|
|
9232
|
+
"agents-md": projectRulesToAgentsMd
|
|
9090
9233
|
},
|
|
9091
9234
|
"mcp-server": {
|
|
9092
9235
|
canonical: mcpCanonical,
|
|
@@ -9110,7 +9253,6 @@ var REGISTRY = {
|
|
|
9110
9253
|
"claude-code": judgmentToClaude
|
|
9111
9254
|
}
|
|
9112
9255
|
};
|
|
9113
|
-
REGISTRY["project-rules"]["gemini-cli"] = projectRulesToGemini;
|
|
9114
9256
|
var TranslatorNotSupportedError = class extends Error {
|
|
9115
9257
|
type;
|
|
9116
9258
|
format;
|
|
@@ -9339,11 +9481,13 @@ async function doPullInstall(fullSlug, tool, installRoot, opts = {}) {
|
|
|
9339
9481
|
throw e;
|
|
9340
9482
|
}
|
|
9341
9483
|
const bundle = await useClient();
|
|
9342
|
-
const
|
|
9484
|
+
const pullBody = {
|
|
9343
9485
|
...opts.version ? { version: opts.version } : {},
|
|
9344
9486
|
...opts.withRequired !== void 0 ? { with_required: opts.withRequired } : {},
|
|
9345
|
-
...opts.withRecommends !== void 0 ? { with_recommends: opts.withRecommends } : {}
|
|
9346
|
-
|
|
9487
|
+
...opts.withRecommends !== void 0 ? { with_recommends: opts.withRecommends } : {},
|
|
9488
|
+
tool
|
|
9489
|
+
};
|
|
9490
|
+
const pullRes = await bundle.api.pull(username, slug, pullBody);
|
|
9347
9491
|
const contentRes = await bundle.api.getContent(username, slug, {
|
|
9348
9492
|
format: "canonical",
|
|
9349
9493
|
// Server resolved the range during pull; pass the concrete version
|
|
@@ -9463,9 +9607,12 @@ function pullCommand() {
|
|
|
9463
9607
|
const installRoot = opts.target ?? userCwd;
|
|
9464
9608
|
const detected = opts.tool ?? await detectTool(installRoot);
|
|
9465
9609
|
if (!detected) {
|
|
9466
|
-
|
|
9467
|
-
"Cannot detect target tool from the current directory
|
|
9610
|
+
const e = new Error(
|
|
9611
|
+
"Cannot detect target tool from the current directory."
|
|
9468
9612
|
);
|
|
9613
|
+
e.hint = `Pass --tool <name> explicitly. Valid: ${ToolSlugSchema.options.join(", ")}.
|
|
9614
|
+
Or run \`kordis pull\` inside a project that already has one of: ${TOOL_MARKERS.map(([marker]) => marker).join(", ")}.`;
|
|
9615
|
+
throw e;
|
|
9469
9616
|
}
|
|
9470
9617
|
const rootLabel = pin ? `${parsed.fullSlug}@${pin}` : parsed.fullSlug;
|
|
9471
9618
|
const spin = spinner(`Pulling ${rootLabel}`);
|
|
@@ -9560,22 +9707,33 @@ function pullCommand() {
|
|
|
9560
9707
|
}
|
|
9561
9708
|
);
|
|
9562
9709
|
}
|
|
9710
|
+
var TOOL_MARKERS = [
|
|
9711
|
+
[".claude", "claude-code"],
|
|
9712
|
+
[".codex", "codex"],
|
|
9713
|
+
[".gemini", "gemini-cli"],
|
|
9714
|
+
// The shared skills dir. Both Codex and Gemini read it; neither owns it.
|
|
9715
|
+
[".agents", "agents-md"],
|
|
9716
|
+
// Was `codex` until 2026-09-06. AGENTS.md is a convention, not a vendor.
|
|
9717
|
+
["AGENTS.md", "agents-md"],
|
|
9718
|
+
["CLAUDE.md", "claude-code"],
|
|
9719
|
+
["GEMINI.md", "gemini-cli"],
|
|
9720
|
+
// Project-rules markers only — about rules files, not skill routing.
|
|
9721
|
+
[".cursorrules", "cursor"],
|
|
9722
|
+
[".windsurfrules", "windsurf"],
|
|
9723
|
+
[".github/copilot-instructions.md", "copilot"],
|
|
9724
|
+
// Vendor directories with no evidence behind their skills path. Present =
|
|
9725
|
+
// "a project set up for an agentic tool", which is true and useful; it just
|
|
9726
|
+
// does not license writing to `<vendor>/skills/`. Last, so everything above
|
|
9727
|
+
// wins first.
|
|
9728
|
+
[".cursor", "agents-md"],
|
|
9729
|
+
[".continue", "agents-md"],
|
|
9730
|
+
[".windsurf", "agents-md"],
|
|
9731
|
+
[".antigravity", "agents-md"],
|
|
9732
|
+
[".opencode", "agents-md"]
|
|
9733
|
+
];
|
|
9563
9734
|
async function detectTool(root) {
|
|
9564
9735
|
const { stat: stat3 } = await import("fs/promises");
|
|
9565
|
-
const
|
|
9566
|
-
[".claude", "claude-code"],
|
|
9567
|
-
[".cursor", "cursor"],
|
|
9568
|
-
[".continue", "continue"],
|
|
9569
|
-
[".windsurf", "windsurf"],
|
|
9570
|
-
[".antigravity", "antigravity"],
|
|
9571
|
-
[".codex", "codex"],
|
|
9572
|
-
["AGENTS.md", "codex"],
|
|
9573
|
-
["CLAUDE.md", "claude-code"],
|
|
9574
|
-
[".cursorrules", "cursor"],
|
|
9575
|
-
[".windsurfrules", "windsurf"],
|
|
9576
|
-
[".github/copilot-instructions.md", "copilot"]
|
|
9577
|
-
];
|
|
9578
|
-
for (const [path2, tool] of checks) {
|
|
9736
|
+
for (const [path2, tool] of TOOL_MARKERS) {
|
|
9579
9737
|
try {
|
|
9580
9738
|
await stat3(join10(root, path2));
|
|
9581
9739
|
return tool;
|
|
@@ -13593,7 +13751,7 @@ function memoryCommand() {
|
|
|
13593
13751
|
}
|
|
13594
13752
|
|
|
13595
13753
|
// src/index.ts
|
|
13596
|
-
var ALIAS_NOTICE = "kordis is now part of memgineering \u2014 `kordis` keeps working as an alias until memgineering 0.
|
|
13754
|
+
var ALIAS_NOTICE = "kordis is now part of memgineering \u2014 `kordis` keeps working as an alias until memgineering 0.21.0; the same verbs live at `memgineering registry <verb>`.";
|
|
13597
13755
|
var aliasNoticePrinted = false;
|
|
13598
13756
|
function printAliasNotice() {
|
|
13599
13757
|
if (aliasNoticePrinted) return;
|
package/package.json
CHANGED