@rayul/kordis 0.1.10 → 0.1.11
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-using/SKILL.md +10 -6
- package/dist/index.js +205 -43
- package/package.json +3 -1
|
@@ -100,12 +100,16 @@ auto-resolve silently.
|
|
|
100
100
|
`"following <full_slug>@<version>"`). RECOMMENDED: end your reply with that
|
|
101
101
|
exact line. Skip only when it would clutter a casual non-technical reply.
|
|
102
102
|
|
|
103
|
-
## Bundled assets
|
|
104
|
-
|
|
105
|
-
`scripts
|
|
106
|
-
SKILL.md
|
|
107
|
-
|
|
108
|
-
|
|
103
|
+
## Bundled assets
|
|
104
|
+
Skills published as a `.skill` bundle or directory include `assets/`,
|
|
105
|
+
`references/`, `scripts/`, and `agents/` subdirectories alongside
|
|
106
|
+
`SKILL.md`. After `kordis pull`, these files land next to `SKILL.md` in
|
|
107
|
+
the tool's skill directory (e.g. `.claude/skills/<name>/assets/foo.html`)
|
|
108
|
+
and are directly readable by the agent.
|
|
109
|
+
|
|
110
|
+
If a skill body references a helper file and the file isn't present after
|
|
111
|
+
pull, the package was published as a single-file skill — follow its
|
|
112
|
+
`homepage` to the upstream source.
|
|
109
113
|
|
|
110
114
|
## Examples
|
|
111
115
|
|
package/dist/index.js
CHANGED
|
@@ -459,7 +459,7 @@ var init_auth = __esm({
|
|
|
459
459
|
|
|
460
460
|
// ../../packages/contracts/src/api.ts
|
|
461
461
|
import { z as z9 } from "zod";
|
|
462
|
-
var SearchQuerySchema, SearchResponseSchema, TrendingQuerySchema, RisingQuerySchema, StarResponseSchema, PublishPackageRequestSchema, PublishWaitQuerySchema, PublishPackageResponseSchema, PackagePathParamsSchema, ContentQuerySchema, PackageContentResponseSchema, JitReadRequestSchema, JitReadResponseSchema, PullPackageResponseSchema, ListVersionsResponseSchema, VersionDiffQuerySchema, ListCommentsQuerySchema, ListCommentsResponseSchema, UserProfileResponseSchema, UserPackagesQuerySchema;
|
|
462
|
+
var SearchQuerySchema, SearchResponseSchema, TrendingQuerySchema, RisingQuerySchema, StarResponseSchema, AssetSchema, PublishPackageRequestSchema, PublishWaitQuerySchema, PublishPackageResponseSchema, PackagePathParamsSchema, ContentQuerySchema, PackageContentResponseSchema, JitReadRequestSchema, JitReadResponseSchema, PullPackageResponseSchema, ListVersionsResponseSchema, VersionDiffQuerySchema, ListCommentsQuerySchema, ListCommentsResponseSchema, UserProfileResponseSchema, UserPackagesQuerySchema;
|
|
463
463
|
var init_api = __esm({
|
|
464
464
|
"../../packages/contracts/src/api.ts"() {
|
|
465
465
|
"use strict";
|
|
@@ -498,6 +498,11 @@ var init_api = __esm({
|
|
|
498
498
|
starred: z9.boolean(),
|
|
499
499
|
star_count: z9.number().int().nonnegative()
|
|
500
500
|
});
|
|
501
|
+
AssetSchema = z9.object({
|
|
502
|
+
path: z9.string().min(1).max(255),
|
|
503
|
+
content: z9.string(),
|
|
504
|
+
encoding: z9.enum(["utf8", "base64"]).default("utf8")
|
|
505
|
+
});
|
|
501
506
|
PublishPackageRequestSchema = z9.object({
|
|
502
507
|
/**
|
|
503
508
|
* Raw source content — YAML frontmatter + markdown body. Server parses and
|
|
@@ -528,7 +533,12 @@ var init_api = __esm({
|
|
|
528
533
|
/**
|
|
529
534
|
* Skip draft validation (preview mode) — only allowed in dev builds.
|
|
530
535
|
*/
|
|
531
|
-
dry_run: z9.boolean().optional()
|
|
536
|
+
dry_run: z9.boolean().optional(),
|
|
537
|
+
/**
|
|
538
|
+
* Bundled files beyond SKILL.md: assets, references, scripts, agents, etc.
|
|
539
|
+
* Max 50 entries; max 2 MB per file; max 5 MB total bundle.
|
|
540
|
+
*/
|
|
541
|
+
assets: z9.array(AssetSchema).max(50).optional()
|
|
532
542
|
});
|
|
533
543
|
PublishWaitQuerySchema = z9.object({
|
|
534
544
|
/**
|
|
@@ -574,8 +584,9 @@ var init_api = __esm({
|
|
|
574
584
|
version: SemverSchema,
|
|
575
585
|
format: z9.string(),
|
|
576
586
|
content: z9.string(),
|
|
577
|
-
notes: z9.array(z9.string()).default([])
|
|
587
|
+
notes: z9.array(z9.string()).default([]),
|
|
578
588
|
// translator warnings, e.g. ".mdc → Claude: @filepath unsupported"
|
|
589
|
+
assets: z9.array(AssetSchema).default([])
|
|
579
590
|
});
|
|
580
591
|
JitReadRequestSchema = z9.object({
|
|
581
592
|
/**
|
|
@@ -1004,6 +1015,7 @@ import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, unlink
|
|
|
1004
1015
|
import { homedir as homedir2 } from "os";
|
|
1005
1016
|
import { join as join2 } from "path";
|
|
1006
1017
|
var SERVICE = "kordis";
|
|
1018
|
+
var plaintextWarningEmitted = false;
|
|
1007
1019
|
async function loadKeytar() {
|
|
1008
1020
|
try {
|
|
1009
1021
|
const mod = await import("keytar");
|
|
@@ -1031,6 +1043,16 @@ async function createKeychain() {
|
|
|
1031
1043
|
}
|
|
1032
1044
|
};
|
|
1033
1045
|
}
|
|
1046
|
+
if (!plaintextWarningEmitted && process.env["KORDIS_JSON"] !== "1") {
|
|
1047
|
+
plaintextWarningEmitted = true;
|
|
1048
|
+
const yellow = "\x1B[33m";
|
|
1049
|
+
const reset = "\x1B[0m";
|
|
1050
|
+
process.stderr.write(
|
|
1051
|
+
`${yellow}[kordis] WARNING: OS keychain unavailable; falling back to plaintext token storage at ~/.kordis/.tokens.json (mode 0600).
|
|
1052
|
+
[kordis] On macOS install Xcode Command Line Tools, on Linux install libsecret-1-dev to enable keytar.${reset}
|
|
1053
|
+
`
|
|
1054
|
+
);
|
|
1055
|
+
}
|
|
1034
1056
|
const store = await readAll();
|
|
1035
1057
|
return {
|
|
1036
1058
|
async save(username, tokens) {
|
|
@@ -1321,8 +1343,9 @@ function searchCommand() {
|
|
|
1321
1343
|
|
|
1322
1344
|
// src/commands/push.ts
|
|
1323
1345
|
import { Command as Command4 } from "commander";
|
|
1324
|
-
import { readFile as readFile3 } from "fs/promises";
|
|
1325
|
-
import { resolve } from "path";
|
|
1346
|
+
import { readFile as readFile3, stat, readdir } from "fs/promises";
|
|
1347
|
+
import { resolve, join as join4, posix, sep } from "path";
|
|
1348
|
+
import JSZip from "jszip";
|
|
1326
1349
|
|
|
1327
1350
|
// ../../packages/harness-schema/src/parser.ts
|
|
1328
1351
|
import { parse as parseYaml } from "yaml";
|
|
@@ -1366,21 +1389,30 @@ var FrontmatterParseError = class extends Error {
|
|
|
1366
1389
|
|
|
1367
1390
|
// src/commands/push.ts
|
|
1368
1391
|
function pushCommand() {
|
|
1369
|
-
return new Command4("push").description("publish a new package or a new version").argument("<
|
|
1392
|
+
return new Command4("push").description("publish a new package or a new version").argument("<path>", "SKILL.md file, .skill ZIP, or skill directory").option("--bump <strategy>", "patch|minor|major (update only)", "patch").option(
|
|
1370
1393
|
"--slug <slug>",
|
|
1371
1394
|
'override slug; accepts "user/slug" to point at a specific package'
|
|
1372
1395
|
).option("--type <type>", "override type inference").option("--changelog <text>", "optional changelog entry").option("--dry-run", "validate only; do not publish").option("--no-wait", "return immediately without waiting for review").action(
|
|
1373
|
-
async (
|
|
1396
|
+
async (path, opts) => {
|
|
1374
1397
|
const bundle = await useClient();
|
|
1375
|
-
const abs = resolve(process.cwd(),
|
|
1376
|
-
const
|
|
1398
|
+
const abs = resolve(process.cwd(), path);
|
|
1399
|
+
const s = await stat(abs);
|
|
1400
|
+
let content;
|
|
1401
|
+
let assets = [];
|
|
1402
|
+
if (s.isDirectory()) {
|
|
1403
|
+
({ content, assets } = await bundleDirectory(abs));
|
|
1404
|
+
} else if (abs.endsWith(".skill")) {
|
|
1405
|
+
({ content, assets } = await bundleSkillZip(abs));
|
|
1406
|
+
} else {
|
|
1407
|
+
content = await readFile3(abs, "utf8");
|
|
1408
|
+
}
|
|
1377
1409
|
let targetUser = null;
|
|
1378
1410
|
let targetSlug = null;
|
|
1379
1411
|
if (opts.slug && opts.slug.includes("/")) {
|
|
1380
|
-
const [u,
|
|
1381
|
-
if (u &&
|
|
1412
|
+
const [u, s2] = opts.slug.split("/", 2);
|
|
1413
|
+
if (u && s2) {
|
|
1382
1414
|
targetUser = u;
|
|
1383
|
-
targetSlug =
|
|
1415
|
+
targetSlug = s2;
|
|
1384
1416
|
}
|
|
1385
1417
|
} else {
|
|
1386
1418
|
let nameFromFm = null;
|
|
@@ -1415,6 +1447,7 @@ function pushCommand() {
|
|
|
1415
1447
|
(api) => api.publish(
|
|
1416
1448
|
{
|
|
1417
1449
|
content,
|
|
1450
|
+
assets: assets.length > 0 ? assets : void 0,
|
|
1418
1451
|
bump: opts.bump,
|
|
1419
1452
|
slug: opts.slug && !opts.slug.includes("/") ? opts.slug : void 0,
|
|
1420
1453
|
target_full_slug: targetFullSlug,
|
|
@@ -1434,6 +1467,9 @@ function pushCommand() {
|
|
|
1434
1467
|
printHuman(
|
|
1435
1468
|
`${c.bold(res.full_slug)} ${c.gray(`v${res.version}`)} \u2192 ${res.status === "published" ? c.green("published") : res.status === "pending" ? c.yellow("pending review") : c.red("rejected")}`
|
|
1436
1469
|
);
|
|
1470
|
+
if (assets.length > 0) {
|
|
1471
|
+
printHuman(c.gray(` + ${assets.length} bundled file(s)`));
|
|
1472
|
+
}
|
|
1437
1473
|
printHuman(` ${c.cyan(res.url)}`);
|
|
1438
1474
|
if (res.status === "pending") {
|
|
1439
1475
|
printHuman(
|
|
@@ -1453,11 +1489,94 @@ function pushCommand() {
|
|
|
1453
1489
|
}
|
|
1454
1490
|
);
|
|
1455
1491
|
}
|
|
1492
|
+
var EXCLUDE_NAMES = /* @__PURE__ */ new Set([".DS_Store", "Thumbs.db", ".gitkeep"]);
|
|
1493
|
+
var EXCLUDE_DIRS = /* @__PURE__ */ new Set(["__pycache__", "node_modules", ".git", "evals", "dist", ".turbo"]);
|
|
1494
|
+
var EXCLUDE_EXTS = /* @__PURE__ */ new Set([".pyc", ".pyo", ".rbc"]);
|
|
1495
|
+
function shouldExclude(relPath, isDir) {
|
|
1496
|
+
const parts = relPath.split(posix.sep);
|
|
1497
|
+
const name = parts[parts.length - 1];
|
|
1498
|
+
if (EXCLUDE_NAMES.has(name)) return true;
|
|
1499
|
+
if (isDir && EXCLUDE_DIRS.has(name)) return true;
|
|
1500
|
+
const ext = name.includes(".") ? "." + name.split(".").pop() : "";
|
|
1501
|
+
if (EXCLUDE_EXTS.has(ext)) return true;
|
|
1502
|
+
return false;
|
|
1503
|
+
}
|
|
1504
|
+
async function walkDir(base, relDir, collected) {
|
|
1505
|
+
const entries = await readdir(join4(base, relDir), { withFileTypes: true });
|
|
1506
|
+
for (const entry of entries) {
|
|
1507
|
+
const rel = relDir ? `${relDir}/${entry.name}` : entry.name;
|
|
1508
|
+
if (shouldExclude(rel, entry.isDirectory())) continue;
|
|
1509
|
+
if (entry.isDirectory()) {
|
|
1510
|
+
await walkDir(base, rel, collected);
|
|
1511
|
+
} else if (entry.isFile()) {
|
|
1512
|
+
collected.push({ rel, abs: join4(base, rel) });
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
async function readAsset(absPath) {
|
|
1517
|
+
const buf = await readFile3(absPath);
|
|
1518
|
+
const text = buf.toString("utf8");
|
|
1519
|
+
const roundtrip = Buffer.from(text, "utf8");
|
|
1520
|
+
if (roundtrip.equals(buf)) {
|
|
1521
|
+
return { content: text, encoding: "utf8" };
|
|
1522
|
+
}
|
|
1523
|
+
const b64 = buf.toString("base64");
|
|
1524
|
+
printHuman(c.gray(` \u2192 encoding ${absPath.split(sep).pop()} as base64`));
|
|
1525
|
+
return { content: b64, encoding: "base64" };
|
|
1526
|
+
}
|
|
1527
|
+
async function bundleDirectory(dir) {
|
|
1528
|
+
const all = [];
|
|
1529
|
+
await walkDir(dir, "", all);
|
|
1530
|
+
const skillEntry = all.find((f) => f.rel === "SKILL.md");
|
|
1531
|
+
if (!skillEntry) {
|
|
1532
|
+
throw new Error(`No SKILL.md found in directory ${dir}. Push a directory that has SKILL.md at its root.`);
|
|
1533
|
+
}
|
|
1534
|
+
const content = await readFile3(skillEntry.abs, "utf8");
|
|
1535
|
+
const assets = [];
|
|
1536
|
+
for (const f of all) {
|
|
1537
|
+
if (f.rel === "SKILL.md") continue;
|
|
1538
|
+
const { content: fc, encoding } = await readAsset(f.abs);
|
|
1539
|
+
assets.push({ path: f.rel, content: fc, encoding });
|
|
1540
|
+
}
|
|
1541
|
+
return { content, assets };
|
|
1542
|
+
}
|
|
1543
|
+
async function bundleSkillZip(zipPath) {
|
|
1544
|
+
const buf = await readFile3(zipPath);
|
|
1545
|
+
const zip = await JSZip.loadAsync(buf);
|
|
1546
|
+
const entries = Object.keys(zip.files).filter((k) => !zip.files[k].dir);
|
|
1547
|
+
if (entries.length === 0) throw new Error(".skill file is empty");
|
|
1548
|
+
const firstParts = entries[0].split("/");
|
|
1549
|
+
const prefix = firstParts.length > 1 ? firstParts[0] + "/" : "";
|
|
1550
|
+
const stripped = entries.map((k) => ({
|
|
1551
|
+
zipKey: k,
|
|
1552
|
+
rel: prefix ? k.slice(prefix.length) : k
|
|
1553
|
+
})).filter((f) => f.rel.length > 0 && !shouldExclude(f.rel, false));
|
|
1554
|
+
const skillEntry = stripped.find((f) => f.rel === "SKILL.md");
|
|
1555
|
+
if (!skillEntry) {
|
|
1556
|
+
throw new Error(`.skill ZIP has no SKILL.md at its root (prefix="${prefix}")`);
|
|
1557
|
+
}
|
|
1558
|
+
const content = await zip.files[skillEntry.zipKey].async("string");
|
|
1559
|
+
const assets = [];
|
|
1560
|
+
for (const f of stripped) {
|
|
1561
|
+
if (f.rel === "SKILL.md") continue;
|
|
1562
|
+
const rawBuf = await zip.files[f.zipKey].async("uint8array");
|
|
1563
|
+
const buf2 = Buffer.from(rawBuf);
|
|
1564
|
+
const text = buf2.toString("utf8");
|
|
1565
|
+
const roundtrip = Buffer.from(text, "utf8");
|
|
1566
|
+
if (roundtrip.equals(buf2)) {
|
|
1567
|
+
assets.push({ path: f.rel, content: text, encoding: "utf8" });
|
|
1568
|
+
} else {
|
|
1569
|
+
printHuman(c.gray(` \u2192 encoding ${f.rel} as base64`));
|
|
1570
|
+
assets.push({ path: f.rel, content: buf2.toString("base64"), encoding: "base64" });
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
return { content, assets };
|
|
1574
|
+
}
|
|
1456
1575
|
|
|
1457
1576
|
// src/commands/pull.ts
|
|
1458
1577
|
import { Command as Command5 } from "commander";
|
|
1459
1578
|
import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
|
|
1460
|
-
import { dirname as dirname2, join as
|
|
1579
|
+
import { dirname as dirname2, join as join5 } from "path";
|
|
1461
1580
|
|
|
1462
1581
|
// ../../packages/harness-schema/src/deps.ts
|
|
1463
1582
|
init_src();
|
|
@@ -1777,7 +1896,12 @@ var BLOCKING_CODES = /* @__PURE__ */ new Set([
|
|
|
1777
1896
|
"missing_description",
|
|
1778
1897
|
"invalid_frontmatter",
|
|
1779
1898
|
"content_too_short",
|
|
1780
|
-
"content_too_long"
|
|
1899
|
+
"content_too_long",
|
|
1900
|
+
// asset-bundle codes
|
|
1901
|
+
"asset_path_unsafe",
|
|
1902
|
+
"asset_too_large",
|
|
1903
|
+
"bundle_too_large",
|
|
1904
|
+
"too_many_assets"
|
|
1781
1905
|
]);
|
|
1782
1906
|
function earlyExit(firstFlag, override = {}) {
|
|
1783
1907
|
return {
|
|
@@ -1860,10 +1984,11 @@ function buildSkillFile(input, outputPath) {
|
|
|
1860
1984
|
}
|
|
1861
1985
|
frontmatter.push("---");
|
|
1862
1986
|
const content = frontmatter.join("\n") + "\n\n" + body;
|
|
1987
|
+
const resolvedPath = outputPath.replace("{name}", String(name));
|
|
1863
1988
|
return {
|
|
1864
1989
|
files: [
|
|
1865
1990
|
{
|
|
1866
|
-
path:
|
|
1991
|
+
path: resolvedPath,
|
|
1867
1992
|
content,
|
|
1868
1993
|
mergeable: false,
|
|
1869
1994
|
format: "markdown"
|
|
@@ -1873,17 +1998,45 @@ function buildSkillFile(input, outputPath) {
|
|
|
1873
1998
|
format: "agent-skills"
|
|
1874
1999
|
};
|
|
1875
2000
|
}
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
2001
|
+
function buildSkillDir(input, outputPath) {
|
|
2002
|
+
const result = buildSkillFile(input, outputPath);
|
|
2003
|
+
const skillMdPath = result.files[0].path;
|
|
2004
|
+
const skillDir = skillMdPath.slice(0, skillMdPath.lastIndexOf("/"));
|
|
2005
|
+
const assetFiles = (input.assets ?? []).map((asset) => ({
|
|
2006
|
+
path: `${skillDir}/${asset.path}`,
|
|
2007
|
+
content: asset.content,
|
|
2008
|
+
mergeable: false,
|
|
2009
|
+
format: "plain",
|
|
2010
|
+
encoding: asset.encoding ?? "utf8"
|
|
2011
|
+
}));
|
|
2012
|
+
return {
|
|
2013
|
+
files: [...result.files, ...assetFiles],
|
|
2014
|
+
notes: result.notes,
|
|
2015
|
+
format: result.format
|
|
2016
|
+
};
|
|
2017
|
+
}
|
|
2018
|
+
function buildSkillSingleFile(input, outputPath) {
|
|
2019
|
+
const result = buildSkillFile(input, outputPath);
|
|
2020
|
+
const notes = [...result.notes];
|
|
2021
|
+
if (input.assets && input.assets.length > 0) {
|
|
2022
|
+
const tool = outputPath.split("/")[0]?.replace(".", "") ?? "this tool";
|
|
2023
|
+
notes.push(
|
|
2024
|
+
`${input.assets.length} bundled asset(s) not installed \u2014 ${tool} uses single-file skill convention. Pull with --tool claude-code to install the full bundle.`
|
|
2025
|
+
);
|
|
2026
|
+
}
|
|
2027
|
+
return { ...result, notes };
|
|
2028
|
+
}
|
|
2029
|
+
var skillToClaude = (input) => buildSkillDir(input, ".claude/skills/{name}/SKILL.md");
|
|
2030
|
+
var skillToCodex = (input) => buildSkillDir(input, ".codex/skills/{name}/SKILL.md");
|
|
2031
|
+
var skillToCursor = (input) => buildSkillSingleFile(input, ".cursor/skills/{name}.md");
|
|
2032
|
+
var skillToWindsurf = (input) => buildSkillSingleFile(input, ".windsurf/skills/{name}.md");
|
|
2033
|
+
var skillToContinue = (input) => buildSkillSingleFile(input, ".continue/skills/{name}.md");
|
|
2034
|
+
var skillToCopilot = (input) => buildSkillSingleFile(input, ".github/skills/{name}.md");
|
|
2035
|
+
var skillToGeminiCli = (input) => buildSkillDir(input, ".gemini/skills/{name}/SKILL.md");
|
|
2036
|
+
var skillToOpenCode = (input) => buildSkillSingleFile(input, ".opencode/skills/{name}.md");
|
|
2037
|
+
var skillToAntigravity = (input) => buildSkillSingleFile(input, ".antigravity/skills/{name}.md");
|
|
1885
2038
|
var skillCanonical = (input) => {
|
|
1886
|
-
const res =
|
|
2039
|
+
const res = buildSkillDir(input, "SKILL.md");
|
|
1887
2040
|
res.format = "agent-skills-canonical";
|
|
1888
2041
|
return res;
|
|
1889
2042
|
};
|
|
@@ -2287,12 +2440,13 @@ function pullCommand() {
|
|
|
2287
2440
|
fullSlug,
|
|
2288
2441
|
frontmatter: parsed.frontmatter.data,
|
|
2289
2442
|
body: parsed.body,
|
|
2290
|
-
version: contentRes.version
|
|
2443
|
+
version: contentRes.version,
|
|
2444
|
+
assets: contentRes.assets
|
|
2291
2445
|
});
|
|
2292
2446
|
for (const f of result.files) {
|
|
2293
|
-
const abs =
|
|
2447
|
+
const abs = join5(installRoot, f.path);
|
|
2294
2448
|
await mkdir3(dirname2(abs), { recursive: true });
|
|
2295
|
-
await
|
|
2449
|
+
await writeEmittedFile(abs, f.content, f.encoding);
|
|
2296
2450
|
written.push(abs);
|
|
2297
2451
|
}
|
|
2298
2452
|
notes.push(...result.notes);
|
|
@@ -2303,15 +2457,16 @@ function pullCommand() {
|
|
|
2303
2457
|
fullSlug,
|
|
2304
2458
|
frontmatter: parsed.frontmatter.data,
|
|
2305
2459
|
body: parsed.body,
|
|
2306
|
-
version: contentRes.version
|
|
2460
|
+
version: contentRes.version,
|
|
2461
|
+
assets: contentRes.assets
|
|
2307
2462
|
});
|
|
2308
2463
|
notes.push(
|
|
2309
2464
|
`Tool "${format}" is not supported for type "${parsed.type}"; installed canonical form instead.`
|
|
2310
2465
|
);
|
|
2311
2466
|
for (const f of result.files) {
|
|
2312
|
-
const abs =
|
|
2467
|
+
const abs = join5(installRoot, f.path);
|
|
2313
2468
|
await mkdir3(dirname2(abs), { recursive: true });
|
|
2314
|
-
await
|
|
2469
|
+
await writeEmittedFile(abs, f.content, f.encoding);
|
|
2315
2470
|
written.push(abs);
|
|
2316
2471
|
}
|
|
2317
2472
|
} else {
|
|
@@ -2339,7 +2494,7 @@ function pullCommand() {
|
|
|
2339
2494
|
);
|
|
2340
2495
|
}
|
|
2341
2496
|
async function detectTool(root) {
|
|
2342
|
-
const { stat } = await import("fs/promises");
|
|
2497
|
+
const { stat: stat2 } = await import("fs/promises");
|
|
2343
2498
|
const checks = [
|
|
2344
2499
|
[".claude", "claude-code"],
|
|
2345
2500
|
[".cursor", "cursor"],
|
|
@@ -2355,13 +2510,20 @@ async function detectTool(root) {
|
|
|
2355
2510
|
];
|
|
2356
2511
|
for (const [path, tool] of checks) {
|
|
2357
2512
|
try {
|
|
2358
|
-
await
|
|
2513
|
+
await stat2(join5(root, path));
|
|
2359
2514
|
return tool;
|
|
2360
2515
|
} catch {
|
|
2361
2516
|
}
|
|
2362
2517
|
}
|
|
2363
2518
|
return null;
|
|
2364
2519
|
}
|
|
2520
|
+
async function writeEmittedFile(abs, content, encoding) {
|
|
2521
|
+
if (encoding === "base64") {
|
|
2522
|
+
await writeFile3(abs, Buffer.from(content, "base64"));
|
|
2523
|
+
} else {
|
|
2524
|
+
await writeFile3(abs, content, "utf8");
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2365
2527
|
|
|
2366
2528
|
// src/commands/read.ts
|
|
2367
2529
|
import { Command as Command6 } from "commander";
|
|
@@ -2461,7 +2623,7 @@ function logoutCommand() {
|
|
|
2461
2623
|
// src/commands/setup.ts
|
|
2462
2624
|
import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir4, access } from "fs/promises";
|
|
2463
2625
|
import { homedir as homedir3 } from "os";
|
|
2464
|
-
import { join as
|
|
2626
|
+
import { join as join6, dirname as dirname3 } from "path";
|
|
2465
2627
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2466
2628
|
import { Command as Command9 } from "commander";
|
|
2467
2629
|
var MARKER_START = "<!-- kordis-start -->";
|
|
@@ -2494,18 +2656,18 @@ function assetRoots() {
|
|
|
2494
2656
|
const __dir2 = dirname3(fileURLToPath2(import.meta.url));
|
|
2495
2657
|
return {
|
|
2496
2658
|
// Built binary: bin/kordis.js → assets/ is one level up
|
|
2497
|
-
bundled:
|
|
2659
|
+
bundled: join6(__dir2, "..", "assets"),
|
|
2498
2660
|
// Dev mode: src/commands/setup.ts → 4 levels up to repo root, then packages/skills/
|
|
2499
|
-
source:
|
|
2661
|
+
source: join6(__dir2, "..", "..", "..", "..", "packages", "skills")
|
|
2500
2662
|
};
|
|
2501
2663
|
}
|
|
2502
2664
|
async function pickAssetRoot() {
|
|
2503
2665
|
const { bundled, source } = assetRoots();
|
|
2504
|
-
return await exists(
|
|
2666
|
+
return await exists(join6(bundled, "KORDIS.md")) ? bundled : source;
|
|
2505
2667
|
}
|
|
2506
2668
|
async function loadHubContent() {
|
|
2507
2669
|
const root = await pickAssetRoot();
|
|
2508
|
-
const raw = await readFile4(
|
|
2670
|
+
const raw = await readFile4(join6(root, "KORDIS.md"), "utf-8");
|
|
2509
2671
|
if (raw.startsWith("---")) {
|
|
2510
2672
|
const end = raw.indexOf("\n---", 4);
|
|
2511
2673
|
if (end !== -1) return raw.slice(end + 4).trimStart();
|
|
@@ -2514,7 +2676,7 @@ async function loadHubContent() {
|
|
|
2514
2676
|
}
|
|
2515
2677
|
async function loadSubSkillContent(name) {
|
|
2516
2678
|
const root = await pickAssetRoot();
|
|
2517
|
-
return readFile4(
|
|
2679
|
+
return readFile4(join6(root, name, "SKILL.md"), "utf-8");
|
|
2518
2680
|
}
|
|
2519
2681
|
async function injectBlock(filePath, content, dryRun) {
|
|
2520
2682
|
const block = `${MARKER_START}
|
|
@@ -2582,8 +2744,8 @@ function setupCommand() {
|
|
|
2582
2744
|
let anyFound = false;
|
|
2583
2745
|
const changedTools = /* @__PURE__ */ new Set();
|
|
2584
2746
|
for (const target of HUB_TARGETS) {
|
|
2585
|
-
const dirPath =
|
|
2586
|
-
const filePath =
|
|
2747
|
+
const dirPath = join6(home, target.dir);
|
|
2748
|
+
const filePath = join6(home, target.file);
|
|
2587
2749
|
if (!await exists(dirPath)) {
|
|
2588
2750
|
if (!opts.silent) {
|
|
2589
2751
|
printHuman(c.gray(` - ${target.tool.padEnd(12)} not installed, skipped`));
|
|
@@ -2610,10 +2772,10 @@ function setupCommand() {
|
|
|
2610
2772
|
}
|
|
2611
2773
|
}
|
|
2612
2774
|
for (const target of SKILL_TARGETS) {
|
|
2613
|
-
const dirPath =
|
|
2775
|
+
const dirPath = join6(home, target.dir);
|
|
2614
2776
|
if (!await exists(dirPath)) continue;
|
|
2615
2777
|
for (const subName of SUB_SKILLS) {
|
|
2616
|
-
const filePath =
|
|
2778
|
+
const filePath = join6(home, target.skillsDir, subName, "SKILL.md");
|
|
2617
2779
|
const dest = `~/${target.skillsDir}/${subName}/SKILL.md`;
|
|
2618
2780
|
try {
|
|
2619
2781
|
const result = await copyBundledSkill(filePath, subSkillContents[subName], dryRun);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rayul/kordis",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
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",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@iarna/toml": "^2.2.5",
|
|
28
28
|
"commander": "^12.1.0",
|
|
29
|
+
"jszip": "^3.10.1",
|
|
29
30
|
"kleur": "^4.1.5",
|
|
30
31
|
"open": "^10.1.0",
|
|
31
32
|
"ora": "^8.1.1",
|
|
@@ -42,6 +43,7 @@
|
|
|
42
43
|
"@kordis/contracts": "workspace:*",
|
|
43
44
|
"@kordis/harness-schema": "workspace:*",
|
|
44
45
|
"@kordis/translators": "workspace:*",
|
|
46
|
+
"@types/jszip": "^3.4.1",
|
|
45
47
|
"@types/node": "^22.9.0",
|
|
46
48
|
"@types/prompts": "^2.4.9",
|
|
47
49
|
"tsup": "^8.3.5",
|