@hasna/skills 0.10.18 → 0.10.19
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/README.md +15 -4
- package/bin/index.js +94 -34
- package/bin/mcp.js +1 -1
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/index.js +1 -1
- package/dist/sdk/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -466,8 +466,18 @@ preserves and reads back the original policy before writing. Claude upgrades to
|
|
|
466
466
|
verbosity preferences. Provider mappings, environment, hooks, plugins, skill rules
|
|
467
467
|
and all unknown settings stay bound. Runtime hooks never silently upgrade a witness.
|
|
468
468
|
|
|
469
|
-
A
|
|
470
|
-
|
|
469
|
+
A Codex 0.159.2 native `skills/list` receipt can be captured through the
|
|
470
|
+
package-owned client into a new private file, then reviewed and passed to
|
|
471
|
+
`hook install` with `--codex-native-catalog <file>`:
|
|
472
|
+
|
|
473
|
+
```bash
|
|
474
|
+
skills hook native-catalog --cwd /absolute/project --output /private/catalog.json --json
|
|
475
|
+
skills hook install --agent codex --codex-native-catalog /private/catalog.json --json
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
The capture refuses an existing output file, writes mode `0600`, verifies the
|
|
479
|
+
exact bytes, and reports only version, directory, count, file path and SHA-256.
|
|
480
|
+
Its safe catalog shape is `{version,cwd,skills}`;
|
|
471
481
|
each skill has `{name,path,enabled,pluginId}`. The installer matches the native
|
|
472
482
|
qualified name against a bounded explicit frontmatter name and owning plugin
|
|
473
483
|
manifest. It preserves path disables and adds exact qualified name disables.
|
|
@@ -480,8 +490,9 @@ Only manifest version metadata may vary. Reviewed app declarations use the impli
|
|
|
480
490
|
file and its presence stay bound; it preserves existing connector availability and
|
|
481
491
|
native capability hints. Changed or unknown app fields, custom references, native
|
|
482
492
|
hooks, commands and MCP controls refuse. Name controls suppress Skills, not every
|
|
483
|
-
plugin capability. No prompt hook starts an app server to obtain this receipt:
|
|
484
|
-
startup can maintain caches.
|
|
493
|
+
plugin capability. No prompt hook starts an app server to obtain this receipt:
|
|
494
|
+
native startup can maintain caches. The explicit capture starts and closes only its
|
|
495
|
+
own bounded native client; it does not reload an existing agent session.
|
|
485
496
|
Neither a receipt nor a config write proves an existing session adopted new rules;
|
|
486
497
|
use the actual native session's supported acceptance path separately.
|
|
487
498
|
|
package/bin/index.js
CHANGED
|
@@ -36868,7 +36868,7 @@ var package_default;
|
|
|
36868
36868
|
var init_package = __esm(() => {
|
|
36869
36869
|
package_default = {
|
|
36870
36870
|
name: "@hasna/skills",
|
|
36871
|
-
version: "0.10.
|
|
36871
|
+
version: "0.10.19",
|
|
36872
36872
|
description: "Skills library for AI coding agents",
|
|
36873
36873
|
type: "module",
|
|
36874
36874
|
bin: {
|
|
@@ -51052,6 +51052,24 @@ function projectCodexNativeSkillCatalog(response, cwd2) {
|
|
|
51052
51052
|
return { name: value.name, path: value.path, enabled: value.enabled, pluginId: value.pluginId ?? null };
|
|
51053
51053
|
});
|
|
51054
51054
|
}
|
|
51055
|
+
async function captureCodexNativeSkillCatalog(options, connect = connectCodexHookRpc) {
|
|
51056
|
+
if (!absolutePath2(options.cwd) || !absolutePath2(options.home))
|
|
51057
|
+
refuse();
|
|
51058
|
+
const rpc = await connect({
|
|
51059
|
+
command: options.command,
|
|
51060
|
+
home: options.home,
|
|
51061
|
+
...options.codexHome === undefined ? {} : { codexHome: options.codexHome },
|
|
51062
|
+
...options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }
|
|
51063
|
+
});
|
|
51064
|
+
try {
|
|
51065
|
+
if (!SUPPORTED_NAME_CONTROL_VERSIONS.has(rpc.version))
|
|
51066
|
+
throw new Error("CODEX_NATIVE_SKILL_CATALOG_UNSUPPORTED_VERSION");
|
|
51067
|
+
const response = await rpc.request("skills/list", { cwds: [options.cwd], forceReload: true });
|
|
51068
|
+
return { version: rpc.version, cwd: options.cwd, skills: projectCodexNativeSkillCatalog(response, options.cwd) };
|
|
51069
|
+
} finally {
|
|
51070
|
+
await rpc.close();
|
|
51071
|
+
}
|
|
51072
|
+
}
|
|
51055
51073
|
function canonicalPath(path) {
|
|
51056
51074
|
try {
|
|
51057
51075
|
return realpathSync4(path);
|
|
@@ -112194,7 +112212,9 @@ var exports_agent_integration = {};
|
|
|
112194
112212
|
__export(exports_agent_integration, {
|
|
112195
112213
|
registerAgentIntegration: () => registerAgentIntegration
|
|
112196
112214
|
});
|
|
112197
|
-
import { readFileSync as readFileSync41 } from "fs";
|
|
112215
|
+
import { existsSync as existsSync35, lstatSync as lstatSync32, readFileSync as readFileSync41, writeFileSync as writeFileSync26 } from "fs";
|
|
112216
|
+
import { createHash as createHash31 } from "crypto";
|
|
112217
|
+
import { homedir as homedir13 } from "os";
|
|
112198
112218
|
import { isAbsolute as isAbsolute29 } from "path";
|
|
112199
112219
|
function pinnedHookProfile(input3, configuredProfile) {
|
|
112200
112220
|
try {
|
|
@@ -112261,6 +112281,45 @@ function agents(value) {
|
|
|
112261
112281
|
}
|
|
112262
112282
|
function registerAgentIntegration(parent) {
|
|
112263
112283
|
const hook = parent.command("hook").description("Load selected Skills context through agent lifecycle hooks");
|
|
112284
|
+
hook.command("native-catalog").requiredOption("--cwd <path>", "Absolute project directory observed by native Codex skills/list").requiredOption("--output <file>", "New private file for the projected native catalog").option("--codex-command <path>", "Installed Codex executable used by the native client", "codex").option("--json", "Output bounded capture metadata as JSON", false).description("Capture a reviewed Codex native skill catalog for exact hook enrollment").action(async (options) => {
|
|
112285
|
+
try {
|
|
112286
|
+
if (!isAbsolute29(options.cwd) || !isAbsolute29(options.output))
|
|
112287
|
+
throw new Error("CODEX_NATIVE_SKILL_CATALOG_ABSOLUTE_PATH_REQUIRED");
|
|
112288
|
+
if (existsSync35(options.output))
|
|
112289
|
+
throw new Error("CODEX_NATIVE_SKILL_CATALOG_OUTPUT_EXISTS");
|
|
112290
|
+
const catalog = await captureCodexNativeSkillCatalog({
|
|
112291
|
+
command: options.codexCommand,
|
|
112292
|
+
home: homedir13(),
|
|
112293
|
+
...process.env.CODEX_HOME === undefined ? {} : { codexHome: process.env.CODEX_HOME },
|
|
112294
|
+
cwd: options.cwd
|
|
112295
|
+
});
|
|
112296
|
+
const bytes = JSON.stringify(catalog, null, 2) + `
|
|
112297
|
+
`;
|
|
112298
|
+
try {
|
|
112299
|
+
writeFileSync26(options.output, bytes, { flag: "wx", mode: 384 });
|
|
112300
|
+
} catch (error61) {
|
|
112301
|
+
if (error61 && typeof error61 === "object" && "code" in error61 && error61.code === "EEXIST")
|
|
112302
|
+
throw new Error("CODEX_NATIVE_SKILL_CATALOG_OUTPUT_EXISTS");
|
|
112303
|
+
throw error61;
|
|
112304
|
+
}
|
|
112305
|
+
const written = lstatSync32(options.output);
|
|
112306
|
+
if (!written.isFile() || written.isSymbolicLink() || (written.mode & 63) !== 0 || readFileSync41(options.output, "utf8") !== bytes)
|
|
112307
|
+
throw new Error("CODEX_NATIVE_SKILL_CATALOG_READBACK_FAILED");
|
|
112308
|
+
const receipt = {
|
|
112309
|
+
version: catalog.version,
|
|
112310
|
+
cwd: catalog.cwd,
|
|
112311
|
+
skillCount: catalog.skills.length,
|
|
112312
|
+
output: options.output,
|
|
112313
|
+
bytes: Buffer.byteLength(bytes),
|
|
112314
|
+
sha256: createHash31("sha256").update(bytes).digest("hex")
|
|
112315
|
+
};
|
|
112316
|
+
await writeCliOutput(options.json ? JSON.stringify(receipt) : `Captured ${receipt.skillCount} native Codex skill(s) in ${receipt.output}.`);
|
|
112317
|
+
} catch (error61) {
|
|
112318
|
+
const message = error61 instanceof Error && /^[A-Z][A-Z0-9_]{2,120}$/.test(error61.message) ? error61.message : "CODEX_NATIVE_SKILL_CATALOG_CAPTURE_FAILED";
|
|
112319
|
+
console.error(message);
|
|
112320
|
+
process.exitCode = 1;
|
|
112321
|
+
}
|
|
112322
|
+
});
|
|
112264
112323
|
hook.command("witness").requiredOption("--kind <kind>", "claude-settings-v3, claude-settings-v2, codex-settings-v1 or claude-marketplace-registry-v2").requiredOption("--path <path>", "Canonical absolute path to the reviewed settings or registry file").option("--json", "Output the discovery witness as JSON", false).description("Capture an explicit versioned review witness without installing it").action(async (options) => {
|
|
112265
112324
|
const capture2 = options.kind === "codex-settings-v1" ? captureCodexSettings : options.kind === "claude-settings-v3" ? captureClaudeSettingsV3 : options.kind === "claude-settings-v2" ? captureClaudeSettingsV2 : options.kind === "claude-marketplace-registry-v2" ? captureClaudeMarketplaceRegistryV2 : null;
|
|
112266
112325
|
if (!capture2)
|
|
@@ -112492,6 +112551,7 @@ var init_agent_integration2 = __esm(() => {
|
|
|
112492
112551
|
init_claude_settings_witness();
|
|
112493
112552
|
init_codex_settings_witness();
|
|
112494
112553
|
init_claude_marketplace_registry();
|
|
112554
|
+
init_codex_native_skill_catalog();
|
|
112495
112555
|
RECOVERABLE_CONTEXT_CACHE_ERRORS = new Set(["CACHED_PROFILE_EXPIRED", "CACHED_PROFILE_MISSING", "CACHED_BUNDLE_MISSING"]);
|
|
112496
112556
|
});
|
|
112497
112557
|
|
|
@@ -112630,7 +112690,7 @@ var exports_profiles = {};
|
|
|
112630
112690
|
__export(exports_profiles, {
|
|
112631
112691
|
registerProfiles: () => registerProfiles
|
|
112632
112692
|
});
|
|
112633
|
-
import { closeSync as closeSync21, constants as constants20, fstatSync as fstatSync21, openSync as openSync21, readSync as readSync17, writeFileSync as
|
|
112693
|
+
import { closeSync as closeSync21, constants as constants20, fstatSync as fstatSync21, openSync as openSync21, readSync as readSync17, writeFileSync as writeFileSync27 } from "fs";
|
|
112634
112694
|
function readProfileInput(path) {
|
|
112635
112695
|
const fd = openSync21(path, constants20.O_RDONLY | constants20.O_NONBLOCK);
|
|
112636
112696
|
try {
|
|
@@ -112658,7 +112718,7 @@ function registerProfiles(parent) {
|
|
|
112658
112718
|
try {
|
|
112659
112719
|
const profile = await readSkillProfile(id3), text4 = JSON.stringify(profile, null, 2);
|
|
112660
112720
|
if (options.save)
|
|
112661
|
-
|
|
112721
|
+
writeFileSync27(options.save, JSON.stringify(profile), { mode: 384, flag: "wx" });
|
|
112662
112722
|
await writeCliOutput(options.json ? text4 : `${profile.id} at ${profile.revision}: ${profile.selections.map((skill) => `${skill.slug}@${skill.version}`).join(", ")}`);
|
|
112663
112723
|
} catch (error61) {
|
|
112664
112724
|
console.error(error61.message);
|
|
@@ -112705,7 +112765,7 @@ import {
|
|
|
112705
112765
|
fstatSync as fstatSync23,
|
|
112706
112766
|
openSync as openSync23,
|
|
112707
112767
|
readSync as readSync18,
|
|
112708
|
-
writeFileSync as
|
|
112768
|
+
writeFileSync as writeFileSync28
|
|
112709
112769
|
} from "fs";
|
|
112710
112770
|
function readInput(path) {
|
|
112711
112771
|
const fd = openSync23(path, constants21.O_RDONLY | constants21.O_NONBLOCK);
|
|
@@ -112738,7 +112798,7 @@ function registerGrants(parent) {
|
|
|
112738
112798
|
try {
|
|
112739
112799
|
const policy = await readExecutionGrantPolicy(profile, options.revision);
|
|
112740
112800
|
if (options.save)
|
|
112741
|
-
|
|
112801
|
+
writeFileSync28(options.save, JSON.stringify(policy, null, 2), {
|
|
112742
112802
|
mode: 384,
|
|
112743
112803
|
flag: "wx"
|
|
112744
112804
|
});
|
|
@@ -112765,14 +112825,14 @@ var init_grants = __esm(() => {
|
|
|
112765
112825
|
});
|
|
112766
112826
|
|
|
112767
112827
|
// src/lib/station-hydrate.ts
|
|
112768
|
-
import { createHash as
|
|
112828
|
+
import { createHash as createHash32 } from "crypto";
|
|
112769
112829
|
import {
|
|
112770
112830
|
copyFileSync as copyFileSync3,
|
|
112771
112831
|
mkdirSync as mkdirSync28,
|
|
112772
112832
|
readdirSync as readdirSync24,
|
|
112773
112833
|
readFileSync as readFileSync42,
|
|
112774
112834
|
statSync as statSync22,
|
|
112775
|
-
writeFileSync as
|
|
112835
|
+
writeFileSync as writeFileSync29
|
|
112776
112836
|
} from "fs";
|
|
112777
112837
|
import { dirname as dirname35, join as join61, resolve as resolve26, sep as sep13 } from "path";
|
|
112778
112838
|
function fail5(code2, message, detail = []) {
|
|
@@ -112968,7 +113028,7 @@ function skillSha256(skill) {
|
|
|
112968
113028
|
return sha256File(skill.files[0].winner.fullPath);
|
|
112969
113029
|
}
|
|
112970
113030
|
const joined = skill.files.map((file2) => sha256File(file2.winner.fullPath));
|
|
112971
|
-
return
|
|
113031
|
+
return createHash32("sha256").update(joined.sort().join(`
|
|
112972
113032
|
`)).digest("hex");
|
|
112973
113033
|
}
|
|
112974
113034
|
function writeStationHydration(options) {
|
|
@@ -113050,7 +113110,7 @@ function writeStationHydration(options) {
|
|
|
113050
113110
|
};
|
|
113051
113111
|
const hydrationManifestPath = join61(dirname35(cacheRoot), `hydration-${options.stationId}.json`);
|
|
113052
113112
|
mkdirSync28(dirname35(hydrationManifestPath), { recursive: true });
|
|
113053
|
-
|
|
113113
|
+
writeFileSync29(hydrationManifestPath, `${JSON.stringify(hydration, null, 2)}
|
|
113054
113114
|
`);
|
|
113055
113115
|
return {
|
|
113056
113116
|
...base3,
|
|
@@ -113125,8 +113185,8 @@ var init_hydrate = __esm(() => {
|
|
|
113125
113185
|
});
|
|
113126
113186
|
|
|
113127
113187
|
// src/lib/prepare-skill.ts
|
|
113128
|
-
import { createHash as
|
|
113129
|
-
import { chmodSync as chmodSync5, existsSync as
|
|
113188
|
+
import { createHash as createHash33, randomUUID as randomUUID12 } from "crypto";
|
|
113189
|
+
import { chmodSync as chmodSync5, existsSync as existsSync36, lstatSync as lstatSync33, mkdirSync as mkdirSync29, mkdtempSync as mkdtempSync6, readFileSync as readFileSync43, readdirSync as readdirSync25, renameSync as renameSync14, rmSync as rmSync9, writeFileSync as writeFileSync30 } from "fs";
|
|
113130
113190
|
import { tmpdir as tmpdir2 } from "os";
|
|
113131
113191
|
import { dirname as dirname36, isAbsolute as isAbsolute30, join as join62, relative as relative10, resolve as resolve27, sep as sep14 } from "path";
|
|
113132
113192
|
function prepareSkill(name, options) {
|
|
@@ -113175,10 +113235,10 @@ function prepareSkill(name, options) {
|
|
|
113175
113235
|
for (const file2 of before2.files) {
|
|
113176
113236
|
const destination = join62(staging, file2.path);
|
|
113177
113237
|
mkdirSync29(dirname36(destination), { recursive: true });
|
|
113178
|
-
|
|
113238
|
+
writeFileSync30(destination, file2.bytes, { mode: file2.mode });
|
|
113179
113239
|
}
|
|
113180
113240
|
const stagedManifest = join62(staging, "skill.json");
|
|
113181
|
-
|
|
113241
|
+
writeFileSync30(stagedManifest, `${JSON.stringify(candidate2, null, 2)}
|
|
113182
113242
|
`);
|
|
113183
113243
|
const contentHash = computeContentHash(staging);
|
|
113184
113244
|
const changed3 = options.version !== previousVersion || kind !== manifest.kind || contentHash !== provenance?.content_hash;
|
|
@@ -113188,7 +113248,7 @@ function prepareSkill(name, options) {
|
|
|
113188
113248
|
candidate2.provenance.content_hash = contentHash;
|
|
113189
113249
|
const candidateBytes = `${JSON.stringify(candidate2, null, 2)}
|
|
113190
113250
|
`;
|
|
113191
|
-
|
|
113251
|
+
writeFileSync30(stagedManifest, candidateBytes);
|
|
113192
113252
|
validateRawCandidate(candidate2);
|
|
113193
113253
|
validateRuntimeEntrypoint(candidate2, staging);
|
|
113194
113254
|
const validation = validatePortableSkillDirectory(normalized, staging);
|
|
@@ -113202,7 +113262,7 @@ ${validation.issues.map((issue2) => `${issue2.code}: ${issue2.message}`).join(`
|
|
|
113202
113262
|
if (changed3 && !options.dryRun) {
|
|
113203
113263
|
const temporary = join62(path, `.skill-prepare-${randomUUID12()}.tmp`);
|
|
113204
113264
|
try {
|
|
113205
|
-
|
|
113265
|
+
writeFileSync30(temporary, candidateBytes, { flag: "wx", mode: manifestFile.mode });
|
|
113206
113266
|
chmodSync5(temporary, manifestFile.mode);
|
|
113207
113267
|
renameSync14(temporary, join62(path, "skill.json"));
|
|
113208
113268
|
} finally {
|
|
@@ -113235,7 +113295,7 @@ function validateRuntimeEntrypoint(candidate2, root2) {
|
|
|
113235
113295
|
if (typeof entry !== "string")
|
|
113236
113296
|
return;
|
|
113237
113297
|
const target = resolve27(root2, entry), rel = relative10(root2, target);
|
|
113238
|
-
if (isAbsolute30(entry) || /^[a-zA-Z]:/.test(entry) || entry.includes("\\") || !rel || rel === ".." || rel.startsWith(`..${sep14}`) || isAbsolute30(rel) || !
|
|
113298
|
+
if (isAbsolute30(entry) || /^[a-zA-Z]:/.test(entry) || entry.includes("\\") || !rel || rel === ".." || rel.startsWith(`..${sep14}`) || isAbsolute30(rel) || !existsSync36(target) || !lstatSync33(target).isFile()) {
|
|
113239
113299
|
throw new Error("Executable runtime.entrypoint must name an existing regular file inside the skill directory.");
|
|
113240
113300
|
}
|
|
113241
113301
|
}
|
|
@@ -113320,11 +113380,11 @@ function compareVersions(left, right) {
|
|
|
113320
113380
|
return 0;
|
|
113321
113381
|
}
|
|
113322
113382
|
function snapshot2(root2) {
|
|
113323
|
-
const rootStat =
|
|
113383
|
+
const rootStat = lstatSync33(root2);
|
|
113324
113384
|
if (rootStat.isSymbolicLink() || !rootStat.isDirectory())
|
|
113325
113385
|
throw new Error("Skill root must be a real directory, not a symlink.");
|
|
113326
113386
|
const files = [], directories = [];
|
|
113327
|
-
const hash6 =
|
|
113387
|
+
const hash6 = createHash33("sha256").update(`${rootStat.dev}:${rootStat.ino}\x00`);
|
|
113328
113388
|
let count = 0, bytes = 0;
|
|
113329
113389
|
const walk2 = (relative11) => {
|
|
113330
113390
|
for (const name of readdirSync25(join62(root2, relative11)).sort()) {
|
|
@@ -113333,7 +113393,7 @@ function snapshot2(root2) {
|
|
|
113333
113393
|
const path = relative11 ? `${relative11}/${name}` : name;
|
|
113334
113394
|
if (++count > 20000)
|
|
113335
113395
|
throw new Error("Skill exceeds the preparation entry limit (20000).");
|
|
113336
|
-
const absolute = join62(root2, path), stat3 =
|
|
113396
|
+
const absolute = join62(root2, path), stat3 = lstatSync33(absolute);
|
|
113337
113397
|
if (stat3.isSymbolicLink())
|
|
113338
113398
|
throw new Error(`Skill contains a symlink: ${path}. No files were changed.`);
|
|
113339
113399
|
if (stat3.isDirectory() && name === "node_modules")
|
|
@@ -113748,7 +113808,7 @@ var init_schedule = __esm(() => {
|
|
|
113748
113808
|
});
|
|
113749
113809
|
|
|
113750
113810
|
// src/lib/registry-sync.ts
|
|
113751
|
-
import { mkdirSync as mkdirSync30, writeFileSync as
|
|
113811
|
+
import { mkdirSync as mkdirSync30, writeFileSync as writeFileSync31 } from "fs";
|
|
113752
113812
|
import { dirname as dirname37, relative as relative11 } from "path";
|
|
113753
113813
|
function createRegistrySyncArtifact(options = {}) {
|
|
113754
113814
|
const profile = options.profile ?? "all";
|
|
@@ -113807,7 +113867,7 @@ function createRegistrySyncArtifact(options = {}) {
|
|
|
113807
113867
|
}
|
|
113808
113868
|
function writeRegistrySyncArtifact(path, artifact) {
|
|
113809
113869
|
mkdirSync30(dirname37(path), { recursive: true });
|
|
113810
|
-
|
|
113870
|
+
writeFileSync31(path, `${JSON.stringify(artifact, null, 2)}
|
|
113811
113871
|
`);
|
|
113812
113872
|
}
|
|
113813
113873
|
function buildDocs(name) {
|
|
@@ -113826,7 +113886,7 @@ var init_registry_sync = __esm(() => {
|
|
|
113826
113886
|
});
|
|
113827
113887
|
|
|
113828
113888
|
// src/lib/review-export.ts
|
|
113829
|
-
import { constants as constants22, closeSync as closeSync25, existsSync as
|
|
113889
|
+
import { constants as constants22, closeSync as closeSync25, existsSync as existsSync37, fstatSync as fstatSync25, fsyncSync as fsyncSync7, lstatSync as lstatSync34, openSync as openSync25, realpathSync as realpathSync18, statSync as statSync23, writeFileSync as writeFileSync32 } from "fs";
|
|
113830
113890
|
import { basename as basename15, dirname as dirname38, isAbsolute as isAbsolute31, join as join63, parse as parse12, resolve as resolve28, sep as sep15 } from "path";
|
|
113831
113891
|
function exactVersion(spec) {
|
|
113832
113892
|
const at2 = spec.indexOf("@");
|
|
@@ -113842,7 +113902,7 @@ function assertPrivateDestination(output2) {
|
|
|
113842
113902
|
throw new Error("Review output must be an absolute, normalized .tar.gz path.");
|
|
113843
113903
|
}
|
|
113844
113904
|
const parent = dirname38(output2);
|
|
113845
|
-
if (realpathSync18(parent) !== parent ||
|
|
113905
|
+
if (realpathSync18(parent) !== parent || lstatSync34(parent).isSymbolicLink()) {
|
|
113846
113906
|
throw new Error("Review output parent must be a real directory, not a symlink.");
|
|
113847
113907
|
}
|
|
113848
113908
|
const parentStat = statSync23(parent);
|
|
@@ -113854,7 +113914,7 @@ function assertPrivateDestination(output2) {
|
|
|
113854
113914
|
throw new Error("Review output cannot be placed in agent-native discovery or Skills installation paths.");
|
|
113855
113915
|
}
|
|
113856
113916
|
for (let current = parent;; current = dirname38(current)) {
|
|
113857
|
-
if (
|
|
113917
|
+
if (existsSync37(join63(current, ".git"))) {
|
|
113858
113918
|
throw new Error("Review output cannot be placed inside a Git worktree.");
|
|
113859
113919
|
}
|
|
113860
113920
|
if (current === parse12(current).root)
|
|
@@ -113865,7 +113925,7 @@ function assertPrivateDestination(output2) {
|
|
|
113865
113925
|
async function exportSkillVersionForReview(spec, output2, client2) {
|
|
113866
113926
|
const { slug: slug2, version: version2 } = exactVersion(spec);
|
|
113867
113927
|
const target = assertPrivateDestination(output2);
|
|
113868
|
-
if (
|
|
113928
|
+
if (existsSync37(target))
|
|
113869
113929
|
throw new Error("Review output already exists; choose a new filename.");
|
|
113870
113930
|
const metadata = await client2.getSkillVersion(slug2, version2);
|
|
113871
113931
|
if (!metadata)
|
|
@@ -113892,7 +113952,7 @@ async function exportSkillVersionForReview(spec, output2, client2) {
|
|
|
113892
113952
|
}
|
|
113893
113953
|
const fd = openSync25(target, constants22.O_WRONLY | constants22.O_CREAT | constants22.O_EXCL | constants22.O_NOFOLLOW, 384);
|
|
113894
113954
|
try {
|
|
113895
|
-
|
|
113955
|
+
writeFileSync32(fd, bytes);
|
|
113896
113956
|
fsyncSync7(fd);
|
|
113897
113957
|
if (fstatSync25(fd).size !== bytes.byteLength)
|
|
113898
113958
|
throw new Error("Incomplete review output write.");
|
|
@@ -114139,7 +114199,7 @@ __export(exports_publish, {
|
|
|
114139
114199
|
PushSkillError: () => PushSkillError
|
|
114140
114200
|
});
|
|
114141
114201
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
114142
|
-
import { existsSync as
|
|
114202
|
+
import { existsSync as existsSync38, readFileSync as readFileSync44 } from "fs";
|
|
114143
114203
|
import { hostname as hostname5 } from "os";
|
|
114144
114204
|
import { join as join64 } from "path";
|
|
114145
114205
|
function registerPublish(parent) {
|
|
@@ -114194,7 +114254,7 @@ async function pushSkill(name, options = {}) {
|
|
|
114194
114254
|
await verifyPackedCanonicalHash(skill.name, packed);
|
|
114195
114255
|
const versionManifest = buildVersionManifest(skill.path, packed);
|
|
114196
114256
|
const skillMdPath = join64(skill.path, "SKILL.md");
|
|
114197
|
-
const skillMd =
|
|
114257
|
+
const skillMd = existsSync38(skillMdPath) ? readFileSync44(skillMdPath, "utf-8") : undefined;
|
|
114198
114258
|
const base3 = {
|
|
114199
114259
|
slug: skill.name,
|
|
114200
114260
|
path: skill.path,
|
|
@@ -115913,7 +115973,7 @@ var init_storage2 = __esm(() => {
|
|
|
115913
115973
|
});
|
|
115914
115974
|
|
|
115915
115975
|
// src/lib/registry-reconcile.ts
|
|
115916
|
-
import { existsSync as
|
|
115976
|
+
import { existsSync as existsSync39, readFileSync as readFileSync45, statSync as statSync24, writeFileSync as writeFileSync33 } from "fs";
|
|
115917
115977
|
import { join as join65 } from "path";
|
|
115918
115978
|
function isDirectory2(path) {
|
|
115919
115979
|
try {
|
|
@@ -115930,7 +115990,7 @@ function migrationNeeded(options) {
|
|
|
115930
115990
|
}
|
|
115931
115991
|
function readBaseline(skillDir) {
|
|
115932
115992
|
const markerPath = join65(skillDir, PULL_MARKER_FILE);
|
|
115933
|
-
if (!
|
|
115993
|
+
if (!existsSync39(markerPath))
|
|
115934
115994
|
return;
|
|
115935
115995
|
try {
|
|
115936
115996
|
const marker = JSON.parse(readFileSync45(markerPath, "utf-8"));
|
|
@@ -115946,7 +116006,7 @@ function readBaseline(skillDir) {
|
|
|
115946
116006
|
}
|
|
115947
116007
|
function readCursor(root2) {
|
|
115948
116008
|
const path = join65(root2, SYNC_CURSOR_FILE);
|
|
115949
|
-
if (!
|
|
116009
|
+
if (!existsSync39(path))
|
|
115950
116010
|
return { runCount: 0 };
|
|
115951
116011
|
try {
|
|
115952
116012
|
const cursor2 = JSON.parse(readFileSync45(path, "utf-8"));
|
|
@@ -115977,7 +116037,7 @@ function remoteRowToSkill(record11) {
|
|
|
115977
116037
|
}
|
|
115978
116038
|
function recheckLocalSide(plannedLocal, localDir, ops = {
|
|
115979
116039
|
pack: (dir) => packSkillBundle(dir).sha256,
|
|
115980
|
-
exists:
|
|
116040
|
+
exists: existsSync39
|
|
115981
116041
|
}) {
|
|
115982
116042
|
let localNow;
|
|
115983
116043
|
try {
|
|
@@ -116228,7 +116288,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
116228
116288
|
runCount: readCursor(root2).runCount + 1,
|
|
116229
116289
|
summary
|
|
116230
116290
|
};
|
|
116231
|
-
|
|
116291
|
+
writeFileSync33(join65(root2, SYNC_CURSOR_FILE), `${JSON.stringify(cursor2, null, 2)}
|
|
116232
116292
|
`);
|
|
116233
116293
|
return {
|
|
116234
116294
|
corpusRoot: root2,
|
package/bin/mcp.js
CHANGED
|
@@ -20019,7 +20019,7 @@ var package_default;
|
|
|
20019
20019
|
var init_package = __esm(() => {
|
|
20020
20020
|
package_default = {
|
|
20021
20021
|
name: "@hasna/skills",
|
|
20022
|
-
version: "0.10.
|
|
20022
|
+
version: "0.10.19",
|
|
20023
20023
|
description: "Skills library for AI coding agents",
|
|
20024
20024
|
type: "module",
|
|
20025
20025
|
bin: {
|
package/bin/migrate.js
CHANGED
package/bin/server.js
CHANGED
|
@@ -24122,7 +24122,7 @@ var init_dist_es9 = __esm(() => {
|
|
|
24122
24122
|
// package.json
|
|
24123
24123
|
var package_default = {
|
|
24124
24124
|
name: "@hasna/skills",
|
|
24125
|
-
version: "0.10.
|
|
24125
|
+
version: "0.10.19",
|
|
24126
24126
|
description: "Skills library for AI coding agents",
|
|
24127
24127
|
type: "module",
|
|
24128
24128
|
bin: {
|
package/bin/worker.js
CHANGED
|
@@ -24125,7 +24125,7 @@ import { randomUUID as randomUUID6 } from "crypto";
|
|
|
24125
24125
|
// package.json
|
|
24126
24126
|
var package_default = {
|
|
24127
24127
|
name: "@hasna/skills",
|
|
24128
|
-
version: "0.10.
|
|
24128
|
+
version: "0.10.19",
|
|
24129
24129
|
description: "Skills library for AI coding agents",
|
|
24130
24130
|
type: "module",
|
|
24131
24131
|
bin: {
|
package/dist/index.js
CHANGED
|
@@ -10877,7 +10877,7 @@ function replaceSkillSession(expected, replacement, plan, options = {}, beforeCo
|
|
|
10877
10877
|
// package.json
|
|
10878
10878
|
var package_default = {
|
|
10879
10879
|
name: "@hasna/skills",
|
|
10880
|
-
version: "0.10.
|
|
10880
|
+
version: "0.10.19",
|
|
10881
10881
|
description: "Skills library for AI coding agents",
|
|
10882
10882
|
type: "module",
|
|
10883
10883
|
bin: {
|
package/dist/sdk/index.js
CHANGED
|
@@ -32373,7 +32373,7 @@ var init_event_sink = __esm(() => {
|
|
|
32373
32373
|
// package.json
|
|
32374
32374
|
var package_default = {
|
|
32375
32375
|
name: "@hasna/skills",
|
|
32376
|
-
version: "0.10.
|
|
32376
|
+
version: "0.10.19",
|
|
32377
32377
|
description: "Skills library for AI coding agents",
|
|
32378
32378
|
type: "module",
|
|
32379
32379
|
bin: {
|