@hasna/skills 0.7.1 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -0
- package/bin/index.js +809 -592
- package/bin/mcp.js +23 -2
- package/bin/migrate.js +1 -1
- package/bin/server.js +2 -3
- package/bin/worker.js +2 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +556 -361
- package/dist/lib/agent-discovery-bytes.d.ts +6 -0
- package/dist/lib/agent-discovery-directories.d.ts +8 -0
- package/dist/lib/agent-discovery.d.ts +7 -0
- package/dist/lib/agent-integration.d.ts +2 -0
- package/dist/lib/agent-policy-limits.d.ts +5 -0
- package/dist/sdk/index.js +579 -386
- package/package.json +1 -1
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.7.
|
|
36871
|
+
version: "0.7.2",
|
|
36872
36872
|
description: "Skills library for AI coding agents",
|
|
36873
36873
|
type: "module",
|
|
36874
36874
|
bin: {
|
|
@@ -43953,12 +43953,20 @@ function assertAgentPolicyCollections(policy) {
|
|
|
43953
43953
|
requireBound(object(source));
|
|
43954
43954
|
text(source.path);
|
|
43955
43955
|
requireBound(source.sha256 === null || typeof source.sha256 === "string" && /^[a-f0-9]{64}$/.test(source.sha256));
|
|
43956
|
+
if (source.hashMode !== undefined)
|
|
43957
|
+
requireBound(source.hashMode === "bytes" && source.format === undefined && source.fields === undefined);
|
|
43956
43958
|
if (source.format !== undefined)
|
|
43957
43959
|
requireBound(["json", "toml", "yaml"].includes(source.format));
|
|
43958
43960
|
if (source.fields !== undefined)
|
|
43959
43961
|
for (const field of array(source.fields, AGENT_POLICY_LIMITS.fields))
|
|
43960
43962
|
text(field, 256);
|
|
43961
43963
|
}
|
|
43964
|
+
if (value.directories !== undefined)
|
|
43965
|
+
for (const directory of array(value.directories, AGENT_POLICY_LIMITS.discoveryDirectories)) {
|
|
43966
|
+
requireBound(object(directory));
|
|
43967
|
+
text(directory.path);
|
|
43968
|
+
requireBound(directory.sha256 === null || typeof directory.sha256 === "string" && /^[a-f0-9]{64}$/.test(directory.sha256));
|
|
43969
|
+
}
|
|
43962
43970
|
if (value.builtinNames !== undefined)
|
|
43963
43971
|
for (const name of array(value.builtinNames, AGENT_POLICY_LIMITS.builtinNames))
|
|
43964
43972
|
text(name, 128);
|
|
@@ -43966,7 +43974,7 @@ function assertAgentPolicyCollections(policy) {
|
|
|
43966
43974
|
}
|
|
43967
43975
|
var AGENT_POLICY_LIMITS;
|
|
43968
43976
|
var init_agent_policy_limits = __esm(() => {
|
|
43969
|
-
AGENT_POLICY_LIMITS = Object.freeze({ bytes: 1024 * 1024, agents: 16, discoverySources: 2048, discoveryRoots: 512, builtinNames: 2048, rootAliases: 2, fields: 64, pathCharacters: 4096 });
|
|
43977
|
+
AGENT_POLICY_LIMITS = Object.freeze({ bytes: 1024 * 1024, agents: 16, discoverySources: 2048, discoveryRawSourceBytes: 64 * 1024 * 1024, discoveryRawTotalBytes: 256 * 1024 * 1024, discoveryRoots: 512, discoveryDirectories: 64, discoveryDirectoryEntries: 20000, discoveryDirectoryBytes: 8 * 1024 * 1024, builtinNames: 2048, rootAliases: 2, fields: 64, pathCharacters: 4096 });
|
|
43970
43978
|
});
|
|
43971
43979
|
|
|
43972
43980
|
// src/lib/managed-policy.ts
|
|
@@ -51155,6 +51163,10 @@ function configureHermesHooks(text2, supervisor, previous) {
|
|
|
51155
51163
|
function assertHermesEnvironment(home) {
|
|
51156
51164
|
if (process.env.TERMINAL_CWD)
|
|
51157
51165
|
throw new Error("NATIVE_SKILL_DRIFT: Hermes TERMINAL_CWD requires a separately reviewed effective project; unset it before using this adapter");
|
|
51166
|
+
for (const variable of ["HERMES_BUNDLED_PLUGINS", "HERMES_BUNDLED_SKILLS"]) {
|
|
51167
|
+
if (process.env[variable])
|
|
51168
|
+
throw new Error(`NATIVE_SKILL_DRIFT: Hermes ${variable} requires a dedicated discovery adapter; unset it before using this adapter`);
|
|
51169
|
+
}
|
|
51158
51170
|
const selected = process.env.HERMES_HOME?.trim();
|
|
51159
51171
|
if (selected && (!isAbsolute3(selected) || resolve5(selected) !== join17(resolve5(home), ".hermes")))
|
|
51160
51172
|
throw new Error("NATIVE_SKILL_DRIFT: custom Hermes homes/profiles require their own reviewed bridge");
|
|
@@ -51306,10 +51318,155 @@ var init_agent_hermes = __esm(() => {
|
|
|
51306
51318
|
EVENTS = ["pre_llm_call", "pre_tool_call"];
|
|
51307
51319
|
});
|
|
51308
51320
|
|
|
51309
|
-
// src/lib/agent-discovery.ts
|
|
51321
|
+
// src/lib/agent-discovery-directories.ts
|
|
51310
51322
|
import { createHash as createHash5 } from "crypto";
|
|
51311
|
-
import { lstatSync as lstatSync7,
|
|
51312
|
-
import { dirname as dirname6, isAbsolute as isAbsolute4, join as join18, resolve as resolve6
|
|
51323
|
+
import { lstatSync as lstatSync7, opendirSync as opendirSync2 } from "fs";
|
|
51324
|
+
import { dirname as dirname6, isAbsolute as isAbsolute4, join as join18, resolve as resolve6 } from "path";
|
|
51325
|
+
function need(value, message) {
|
|
51326
|
+
if (!value)
|
|
51327
|
+
throw new Error(message);
|
|
51328
|
+
}
|
|
51329
|
+
function safe(path) {
|
|
51330
|
+
need(typeof path === "string" && path.length <= AGENT_POLICY_LIMITS.pathCharacters && isAbsolute4(path) && resolve6(path) === path && !path.includes("\x00"), "Expected a canonical absolute discovery directory path");
|
|
51331
|
+
for (let cursor = path;; cursor = dirname6(cursor)) {
|
|
51332
|
+
need(!lstatSync7(cursor, { throwIfNoEntry: false })?.isSymbolicLink(), "Refusing symlink native discovery directory");
|
|
51333
|
+
if (dirname6(cursor) === cursor)
|
|
51334
|
+
break;
|
|
51335
|
+
}
|
|
51336
|
+
}
|
|
51337
|
+
function same(before2, after2) {
|
|
51338
|
+
return Boolean(after2 && after2.isDirectory() && before2.dev === after2.dev && before2.ino === after2.ino && before2.mtimeMs === after2.mtimeMs && before2.ctimeMs === after2.ctimeMs);
|
|
51339
|
+
}
|
|
51340
|
+
function capture(path, budget) {
|
|
51341
|
+
safe(path);
|
|
51342
|
+
const root = lstatSync7(path, { throwIfNoEntry: false });
|
|
51343
|
+
if (!root)
|
|
51344
|
+
return { path, sha256: null };
|
|
51345
|
+
need(root.isDirectory(), "Unsupported native discovery directory input");
|
|
51346
|
+
const hash2 = createHash5("sha256");
|
|
51347
|
+
function walk2(current, relative4, before2, depth) {
|
|
51348
|
+
need(depth <= 64, "Native discovery directory depth limit exceeded");
|
|
51349
|
+
const names = [], directory = opendirSync2(current);
|
|
51350
|
+
try {
|
|
51351
|
+
for (let entry = directory.readSync();entry; entry = directory.readSync()) {
|
|
51352
|
+
need(++budget.entries <= AGENT_POLICY_LIMITS.discoveryDirectoryEntries, "Native discovery directory entry limit exceeded");
|
|
51353
|
+
names.push(entry.name);
|
|
51354
|
+
}
|
|
51355
|
+
} finally {
|
|
51356
|
+
directory.closeSync();
|
|
51357
|
+
}
|
|
51358
|
+
need(new Set(names).size === names.length, "Ambiguous native discovery directory names");
|
|
51359
|
+
for (const name of names.sort()) {
|
|
51360
|
+
const child = join18(current, name), childRelative = relative4 ? `${relative4}/${name}` : name;
|
|
51361
|
+
need(child.length <= AGENT_POLICY_LIMITS.pathCharacters, "Native discovery directory path limit exceeded");
|
|
51362
|
+
const stat = lstatSync7(child);
|
|
51363
|
+
need(stat.isFile() || stat.isDirectory(), "Refusing symlink or special native discovery directory member");
|
|
51364
|
+
const row = JSON.stringify([childRelative, stat.isDirectory() ? "directory" : "file"]) + `
|
|
51365
|
+
`;
|
|
51366
|
+
budget.bytes += Buffer.byteLength(row);
|
|
51367
|
+
need(budget.bytes <= AGENT_POLICY_LIMITS.discoveryDirectoryBytes, "Native discovery directory metadata limit exceeded");
|
|
51368
|
+
hash2.update(row);
|
|
51369
|
+
if (stat.isDirectory())
|
|
51370
|
+
walk2(child, childRelative, stat, depth + 1);
|
|
51371
|
+
}
|
|
51372
|
+
need(same(before2, lstatSync7(current, { throwIfNoEntry: false })), "Native discovery directory changed while reading");
|
|
51373
|
+
}
|
|
51374
|
+
walk2(path, "", root, 0);
|
|
51375
|
+
safe(path);
|
|
51376
|
+
return { path, sha256: hash2.digest("hex") };
|
|
51377
|
+
}
|
|
51378
|
+
function captureDiscoveryDirectories(paths) {
|
|
51379
|
+
need(Array.isArray(paths) && paths.length <= AGENT_POLICY_LIMITS.discoveryDirectories && new Set(paths).size === paths.length, "Invalid native discovery directory collection");
|
|
51380
|
+
const budget = { entries: 0, bytes: 0 };
|
|
51381
|
+
return paths.map((path) => capture(path, budget));
|
|
51382
|
+
}
|
|
51383
|
+
function verifyDiscoveryDirectories(directories) {
|
|
51384
|
+
need(Array.isArray(directories) && directories.length <= AGENT_POLICY_LIMITS.discoveryDirectories, "Invalid native discovery directory collection");
|
|
51385
|
+
for (const directory of directories)
|
|
51386
|
+
need(directory && typeof directory === "object" && (directory.sha256 === null || typeof directory.sha256 === "string" && /^[a-f0-9]{64}$/.test(directory.sha256)), "Invalid native discovery directory digest");
|
|
51387
|
+
const current = captureDiscoveryDirectories(directories.map((directory) => directory.path));
|
|
51388
|
+
for (let i = 0;i < directories.length; i++)
|
|
51389
|
+
need(current[i].sha256 === directories[i].sha256, `Native discovery directory membership changed; run skills hook install with a fresh discovery review: ${directories[i].path}`);
|
|
51390
|
+
}
|
|
51391
|
+
var init_agent_discovery_directories = __esm(() => {
|
|
51392
|
+
init_agent_policy_limits();
|
|
51393
|
+
});
|
|
51394
|
+
|
|
51395
|
+
// src/lib/agent-discovery-bytes.ts
|
|
51396
|
+
import { createHash as createHash6 } from "crypto";
|
|
51397
|
+
import { closeSync as closeSync3, constants as constants4, fstatSync as fstatSync3, lstatSync as lstatSync8, openSync as openSync3, readSync as readSync3 } from "fs";
|
|
51398
|
+
import { dirname as dirname7, isAbsolute as isAbsolute5, resolve as resolve7 } from "path";
|
|
51399
|
+
function discoveryByteBudget() {
|
|
51400
|
+
return { remaining: AGENT_POLICY_LIMITS.discoveryRawTotalBytes };
|
|
51401
|
+
}
|
|
51402
|
+
function safe2(path) {
|
|
51403
|
+
if (typeof path !== "string" || !isAbsolute5(path) || path !== resolve7(path) || path.length > AGENT_POLICY_LIMITS.pathCharacters || path.includes("\x00"))
|
|
51404
|
+
throw new Error("Expected a canonical absolute raw discovery path");
|
|
51405
|
+
for (let cursor = path;; cursor = dirname7(cursor)) {
|
|
51406
|
+
if (lstatSync8(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
51407
|
+
throw new Error("Refusing symlink raw discovery input");
|
|
51408
|
+
if (dirname7(cursor) === cursor)
|
|
51409
|
+
break;
|
|
51410
|
+
}
|
|
51411
|
+
}
|
|
51412
|
+
function same2(left, right) {
|
|
51413
|
+
return left.dev === right.dev && left.ino === right.ino && left.size === right.size && left.mtimeMs === right.mtimeMs && left.ctimeMs === right.ctimeMs;
|
|
51414
|
+
}
|
|
51415
|
+
function consume(budget, bytes) {
|
|
51416
|
+
if (bytes > budget.remaining)
|
|
51417
|
+
throw new Error("Raw discovery aggregate byte limit exceeded");
|
|
51418
|
+
budget.remaining -= bytes;
|
|
51419
|
+
}
|
|
51420
|
+
function hashRawDiscoveryFile(path, budget, changes) {
|
|
51421
|
+
safe2(path);
|
|
51422
|
+
if (changes?.has(path)) {
|
|
51423
|
+
const text2 = changes.get(path), bytes = Buffer.byteLength(text2);
|
|
51424
|
+
if (bytes > AGENT_POLICY_LIMITS.discoveryRawSourceBytes)
|
|
51425
|
+
throw new Error("Raw discovery file byte limit exceeded");
|
|
51426
|
+
consume(budget, bytes);
|
|
51427
|
+
return createHash6("sha256").update(text2).digest("hex");
|
|
51428
|
+
}
|
|
51429
|
+
const initial2 = lstatSync8(path, { throwIfNoEntry: false });
|
|
51430
|
+
if (!initial2)
|
|
51431
|
+
return null;
|
|
51432
|
+
if (!initial2.isFile() || initial2.size > AGENT_POLICY_LIMITS.discoveryRawSourceBytes)
|
|
51433
|
+
throw new Error("Unsupported or oversized raw discovery input");
|
|
51434
|
+
if (initial2.size > budget.remaining)
|
|
51435
|
+
throw new Error("Raw discovery aggregate byte limit exceeded");
|
|
51436
|
+
const fd = openSync3(path, constants4.O_RDONLY | constants4.O_NOFOLLOW | constants4.O_NONBLOCK);
|
|
51437
|
+
try {
|
|
51438
|
+
const opened = fstatSync3(fd);
|
|
51439
|
+
if (!opened.isFile() || !same2(initial2, opened))
|
|
51440
|
+
throw new Error("Raw discovery input changed during open");
|
|
51441
|
+
const hash2 = createHash6("sha256"), buffer = Buffer.alloc(64 * 1024);
|
|
51442
|
+
let bytes = 0;
|
|
51443
|
+
while (true) {
|
|
51444
|
+
const count = readSync3(fd, buffer, 0, Math.min(buffer.length, AGENT_POLICY_LIMITS.discoveryRawSourceBytes - bytes + 1), null);
|
|
51445
|
+
if (!count)
|
|
51446
|
+
break;
|
|
51447
|
+
bytes += count;
|
|
51448
|
+
if (bytes > AGENT_POLICY_LIMITS.discoveryRawSourceBytes)
|
|
51449
|
+
throw new Error("Raw discovery file byte limit exceeded");
|
|
51450
|
+
consume(budget, count);
|
|
51451
|
+
hash2.update(buffer.subarray(0, count));
|
|
51452
|
+
}
|
|
51453
|
+
const final = fstatSync3(fd), current = lstatSync8(path, { throwIfNoEntry: false });
|
|
51454
|
+
safe2(path);
|
|
51455
|
+
if (!current?.isFile() || !same2(opened, final) || !same2(final, current) || bytes !== final.size)
|
|
51456
|
+
throw new Error("Raw discovery input changed during read");
|
|
51457
|
+
return hash2.digest("hex");
|
|
51458
|
+
} finally {
|
|
51459
|
+
closeSync3(fd);
|
|
51460
|
+
}
|
|
51461
|
+
}
|
|
51462
|
+
var init_agent_discovery_bytes = __esm(() => {
|
|
51463
|
+
init_agent_policy_limits();
|
|
51464
|
+
});
|
|
51465
|
+
|
|
51466
|
+
// src/lib/agent-discovery.ts
|
|
51467
|
+
import { createHash as createHash7 } from "crypto";
|
|
51468
|
+
import { lstatSync as lstatSync9, readFileSync as readFileSync11, readdirSync as readdirSync9, realpathSync as realpathSync3 } from "fs";
|
|
51469
|
+
import { dirname as dirname8, isAbsolute as isAbsolute6, join as join19, resolve as resolve8, sep as sep3 } from "path";
|
|
51313
51470
|
function parseConfig(text2, path, toml = false) {
|
|
51314
51471
|
try {
|
|
51315
51472
|
const value = toml ? Bun.TOML.parse(text2) : JSON.parse(text2);
|
|
@@ -51320,28 +51477,35 @@ function parseConfig(text2, path, toml = false) {
|
|
|
51320
51477
|
throw new Error(`Invalid native discovery configuration: ${path}`);
|
|
51321
51478
|
}
|
|
51322
51479
|
}
|
|
51323
|
-
function
|
|
51324
|
-
if (!
|
|
51480
|
+
function safe3(path) {
|
|
51481
|
+
if (!isAbsolute6(path) || path.includes("\x00"))
|
|
51325
51482
|
throw new Error("Expected an absolute native discovery path");
|
|
51326
|
-
for (let cursor = path;; cursor =
|
|
51327
|
-
if (
|
|
51483
|
+
for (let cursor = path;; cursor = dirname8(cursor)) {
|
|
51484
|
+
if (lstatSync9(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
51328
51485
|
throw new Error(`Refusing symlink native discovery input: ${cursor}`);
|
|
51329
|
-
if (
|
|
51486
|
+
if (dirname8(cursor) === cursor)
|
|
51330
51487
|
break;
|
|
51331
51488
|
}
|
|
51332
51489
|
}
|
|
51333
51490
|
function read2(path, changes) {
|
|
51334
|
-
|
|
51491
|
+
safe3(path);
|
|
51335
51492
|
if (changes?.has(path))
|
|
51336
51493
|
return changes.get(path);
|
|
51337
|
-
const stat =
|
|
51494
|
+
const stat = lstatSync9(path, { throwIfNoEntry: false });
|
|
51338
51495
|
if (!stat)
|
|
51339
51496
|
return null;
|
|
51340
51497
|
if (!stat.isFile() || stat.size > 16 * 1024 * 1024)
|
|
51341
51498
|
throw new Error(`Unsupported or oversized native discovery input: ${path}`);
|
|
51342
51499
|
return readFileSync11(path, "utf8");
|
|
51343
51500
|
}
|
|
51344
|
-
function projected(source, changes) {
|
|
51501
|
+
function projected(source, changes, budget = discoveryByteBudget()) {
|
|
51502
|
+
if (source.hashMode !== undefined) {
|
|
51503
|
+
if (source.hashMode !== "bytes")
|
|
51504
|
+
throw new Error("Invalid native discovery hash mode");
|
|
51505
|
+
if (source.format !== undefined || source.fields !== undefined)
|
|
51506
|
+
throw new Error("Raw discovery witnesses cannot project configuration fields");
|
|
51507
|
+
return hashRawDiscoveryFile(source.path, budget, changes);
|
|
51508
|
+
}
|
|
51345
51509
|
const text2 = read2(source.path, changes);
|
|
51346
51510
|
if (text2 === null)
|
|
51347
51511
|
return null;
|
|
@@ -51355,23 +51519,29 @@ function projected(source, changes) {
|
|
|
51355
51519
|
function verifyAgentDiscovery(binding) {
|
|
51356
51520
|
if (!binding || !Array.isArray(binding.sources) || !Array.isArray(binding.roots) || binding.sources.length > AGENT_POLICY_LIMITS.discoverySources || binding.roots.length > AGENT_POLICY_LIMITS.discoveryRoots)
|
|
51357
51521
|
throw new Error("Invalid native discovery binding");
|
|
51522
|
+
if (binding.agent === "hermes" && !binding.directories?.length)
|
|
51523
|
+
throw new Error("Hermes discovery requires directory membership coverage; run skills hook install with a fresh discovery review");
|
|
51524
|
+
if (binding.directories !== undefined)
|
|
51525
|
+
verifyDiscoveryDirectories(binding.directories);
|
|
51526
|
+
const budget = discoveryByteBudget();
|
|
51358
51527
|
for (const source of binding.sources) {
|
|
51359
51528
|
if (source.format !== undefined && (!["json", "toml", "yaml"].includes(source.format) || !Array.isArray(source.fields) || !source.fields.length || source.fields.length > 64 || source.fields.some((field) => typeof field !== "string" || !field)))
|
|
51360
51529
|
throw new Error("Invalid native discovery projection");
|
|
51361
51530
|
if (source.sha256 !== null && !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
51362
51531
|
throw new Error("Invalid native discovery digest");
|
|
51363
|
-
if (projected(source) !== source.sha256)
|
|
51532
|
+
if (projected(source, undefined, budget) !== source.sha256)
|
|
51364
51533
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
51365
51534
|
}
|
|
51366
51535
|
for (const root of binding.roots)
|
|
51367
|
-
|
|
51536
|
+
safe3(root);
|
|
51368
51537
|
}
|
|
51369
51538
|
function rebindAgentDiscovery(binding, changes) {
|
|
51370
|
-
|
|
51539
|
+
const budget = discoveryByteBudget();
|
|
51540
|
+
return { ...binding, sources: binding.sources.map((source) => ({ ...source, sha256: projected(source, changes, budget) })) };
|
|
51371
51541
|
}
|
|
51372
|
-
function assertProjectDiscovery(agent, directories, home, canonical =
|
|
51542
|
+
function assertProjectDiscovery(agent, directories, home, canonical = resolve8) {
|
|
51373
51543
|
for (const directory of directories) {
|
|
51374
|
-
const isHome =
|
|
51544
|
+
const isHome = resolve8(directory) === resolve8(home);
|
|
51375
51545
|
if (agent === "hermes") {
|
|
51376
51546
|
assertHermesEnvironment(home);
|
|
51377
51547
|
continue;
|
|
@@ -51380,7 +51550,7 @@ function assertProjectDiscovery(agent, directories, home, canonical = resolve6)
|
|
|
51380
51550
|
continue;
|
|
51381
51551
|
const paths = agent === "claude" ? [...isHome ? [] : [".claude/settings.json"], ".claude/settings.local.json"] : agent === "codex" ? [".codex/config.toml"] : agent === "gemini" ? [".gemini/settings.json"] : agent === "opencode" ? ["opencode.json", "opencode.jsonc", ".opencode/opencode.json", ".opencode/opencode.jsonc"] : [".cursor/hooks.json"];
|
|
51382
51552
|
for (const suffix of paths) {
|
|
51383
|
-
const path = canonical(
|
|
51553
|
+
const path = canonical(join19(directory, suffix)), raw = read2(path);
|
|
51384
51554
|
if (raw === null)
|
|
51385
51555
|
continue;
|
|
51386
51556
|
if (suffix.endsWith(".jsonc"))
|
|
@@ -51391,15 +51561,15 @@ function assertProjectDiscovery(agent, directories, home, canonical = resolve6)
|
|
|
51391
51561
|
throw new Error(`NATIVE_SKILL_DRIFT: higher-precedence project skill or hook configuration requires review: ${path}`);
|
|
51392
51562
|
}
|
|
51393
51563
|
if (agent === "claude") {
|
|
51394
|
-
const commands = canonical(
|
|
51395
|
-
|
|
51396
|
-
if (
|
|
51564
|
+
const commands = canonical(join19(directory, ".claude/commands"));
|
|
51565
|
+
safe3(commands);
|
|
51566
|
+
if (lstatSync9(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length)
|
|
51397
51567
|
throw new Error("NATIVE_SKILL_DRIFT: legacy project command discovery requires a dedicated format adapter");
|
|
51398
51568
|
}
|
|
51399
51569
|
}
|
|
51400
51570
|
}
|
|
51401
51571
|
function resolveAgentDiscovery(options) {
|
|
51402
|
-
const canonical = options.canonical ??
|
|
51572
|
+
const canonical = options.canonical ?? resolve8, home = resolve8(options.home), agent = options.agent;
|
|
51403
51573
|
const sources = [], roots = new Set, builtinNames = [];
|
|
51404
51574
|
const witness = (path, format, fields) => {
|
|
51405
51575
|
const source = { path: canonical(path), sha256: null, ...format ? { format, fields } : {} };
|
|
@@ -51409,14 +51579,14 @@ function resolveAgentDiscovery(options) {
|
|
|
51409
51579
|
};
|
|
51410
51580
|
if (agent === "hermes")
|
|
51411
51581
|
assertHermesEnvironment(home);
|
|
51412
|
-
const configPath =
|
|
51582
|
+
const configPath = join19(home, agent === "hermes" ? ".hermes/config.yaml" : agent === "opencode" ? ".config/opencode/opencode.json" : `.${agent}/${agent === "codex" ? "config.toml" : agent === "cursor" ? "hooks.json" : "settings.json"}`);
|
|
51413
51583
|
const configText = witness(configPath, agent === "hermes" ? "yaml" : agent === "codex" ? "toml" : "json", agent === "hermes" ? ["skills", "plugins", "hooks"] : agent === "claude" ? ["enabledPlugins", "extraKnownMarketplaces"] : agent === "codex" ? ["plugins", "marketplaces", "skills"] : agent === "gemini" ? ["skills", "extensions", "security"] : agent === "opencode" ? ["plugin", "skills"] : ["version"]);
|
|
51414
51584
|
const config = configText === null ? {} : agent === "hermes" ? parseHermesConfig(configText) : parseConfig(configText, configPath, agent === "codex");
|
|
51415
51585
|
const unresolved = (detail) => {
|
|
51416
51586
|
throw new Error(`Native discovery is unresolved (${agent}: ${detail}); provide a reviewed --discovery-inputs file`);
|
|
51417
51587
|
};
|
|
51418
51588
|
if (agent === "hermes") {
|
|
51419
|
-
const profile = witness(
|
|
51589
|
+
const profile = witness(join19(home, ".hermes/active_profile"));
|
|
51420
51590
|
if (profile?.trim() && profile.trim() !== "default")
|
|
51421
51591
|
unresolved("a non-default profile is active");
|
|
51422
51592
|
const declared = config.skills?.external_dirs ?? [], paths = typeof declared === "string" ? [declared] : declared;
|
|
@@ -51430,8 +51600,8 @@ function resolveAgentDiscovery(options) {
|
|
|
51430
51600
|
continue;
|
|
51431
51601
|
if (normalized.startsWith("~") && normalized !== "~" && !normalized.startsWith("~/"))
|
|
51432
51602
|
unresolved("user-specific tilde expansion requires a separate discovery adapter");
|
|
51433
|
-
const path = normalized === "~" ? home : normalized.startsWith("~/") ?
|
|
51434
|
-
|
|
51603
|
+
const path = normalized === "~" ? home : normalized.startsWith("~/") ? join19(home, normalized.slice(2)) : resolve8(home, ".hermes", normalized);
|
|
51604
|
+
safe3(path);
|
|
51435
51605
|
roots.add(path);
|
|
51436
51606
|
}
|
|
51437
51607
|
}
|
|
@@ -51439,24 +51609,24 @@ function resolveAgentDiscovery(options) {
|
|
|
51439
51609
|
const executable = Bun.which("gemini");
|
|
51440
51610
|
if (executable) {
|
|
51441
51611
|
let packageRoot;
|
|
51442
|
-
for (let directory =
|
|
51443
|
-
const path =
|
|
51612
|
+
for (let directory = dirname8(realpathSync3(executable)), depth = 0;depth < 8; directory = dirname8(directory), depth++) {
|
|
51613
|
+
const path = join19(directory, "package.json"), raw = read2(path);
|
|
51444
51614
|
if (raw !== null && parseConfig(raw, path).name === "@google/gemini-cli") {
|
|
51445
51615
|
packageRoot = directory;
|
|
51446
51616
|
witness(path);
|
|
51447
51617
|
break;
|
|
51448
51618
|
}
|
|
51449
|
-
if (
|
|
51619
|
+
if (dirname8(directory) === directory)
|
|
51450
51620
|
break;
|
|
51451
51621
|
}
|
|
51452
51622
|
if (!packageRoot)
|
|
51453
51623
|
unresolved("installed Gemini package layout is not recognized");
|
|
51454
|
-
const builtinRoot =
|
|
51455
|
-
|
|
51456
|
-
if (!
|
|
51624
|
+
const builtinRoot = join19(packageRoot, "bundle/builtin");
|
|
51625
|
+
safe3(builtinRoot);
|
|
51626
|
+
if (!lstatSync9(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
|
|
51457
51627
|
unresolved("installed Gemini builtin root is missing");
|
|
51458
51628
|
for (const name of readdirSync9(builtinRoot).sort()) {
|
|
51459
|
-
const text2 = witness(
|
|
51629
|
+
const text2 = witness(join19(builtinRoot, name, "SKILL.md"));
|
|
51460
51630
|
const match = text2?.match(/^---\r?\n[\s\S]*?^name:\s*([a-z0-9][a-z0-9-]*)\s*$/m);
|
|
51461
51631
|
if (!match?.[1] || builtinNames.includes(match[1]))
|
|
51462
51632
|
unresolved("installed Gemini builtin name is missing or ambiguous");
|
|
@@ -51470,7 +51640,7 @@ function resolveAgentDiscovery(options) {
|
|
|
51470
51640
|
if (review) {
|
|
51471
51641
|
if (review.pluginHooks !== "reviewed-no-skill-injection" || !Array.isArray(review.sources) || !review.sources.length || !Array.isArray(review.roots))
|
|
51472
51642
|
throw new Error("Discovery review must bind sources and confirm plugin hooks do not inject retired skills");
|
|
51473
|
-
const supplied = { agent, roots: review.roots, sources: review.sources, method: "reviewed" };
|
|
51643
|
+
const supplied = { agent, roots: review.roots, sources: review.sources, ...review.directories !== undefined ? { directories: review.directories } : {}, method: "reviewed" };
|
|
51474
51644
|
if (review.sources.some((source) => source.format !== undefined || source.fields !== undefined))
|
|
51475
51645
|
throw new Error("Explicit discovery reviews require full source-file hashes");
|
|
51476
51646
|
verifyAgentDiscovery(supplied);
|
|
@@ -51480,40 +51650,40 @@ function resolveAgentDiscovery(options) {
|
|
|
51480
51650
|
}
|
|
51481
51651
|
function plugin(root) {
|
|
51482
51652
|
root = canonical(root);
|
|
51483
|
-
|
|
51484
|
-
const manifestPath =
|
|
51653
|
+
safe3(root);
|
|
51654
|
+
const manifestPath = join19(root, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
|
|
51485
51655
|
const raw = witness(manifestPath);
|
|
51486
51656
|
if (raw === null)
|
|
51487
51657
|
unresolved("plugin manifest missing");
|
|
51488
51658
|
const manifest = parseConfig(raw, manifestPath);
|
|
51489
|
-
const hooks = witness(
|
|
51659
|
+
const hooks = witness(join19(root, "hooks/hooks.json"));
|
|
51490
51660
|
if (manifest.hooks !== undefined || hooks !== null)
|
|
51491
51661
|
unresolved("plugin hooks require a separate no-skill-injection review");
|
|
51492
|
-
const commands =
|
|
51493
|
-
|
|
51494
|
-
if (agent === "claude" && (manifest.commands !== undefined ||
|
|
51662
|
+
const commands = join19(root, "commands");
|
|
51663
|
+
safe3(commands);
|
|
51664
|
+
if (agent === "claude" && (manifest.commands !== undefined || lstatSync9(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length))
|
|
51495
51665
|
unresolved("legacy command discovery requires retirement or a dedicated format adapter");
|
|
51496
|
-
const rootSkill = witness(
|
|
51666
|
+
const rootSkill = witness(join19(root, "SKILL.md"));
|
|
51497
51667
|
if (rootSkill !== null)
|
|
51498
51668
|
roots.add(root);
|
|
51499
51669
|
const declared = manifest.skills === undefined ? ["./skills"] : typeof manifest.skills === "string" ? [manifest.skills] : manifest.skills;
|
|
51500
51670
|
if (!Array.isArray(declared) || declared.some((path) => typeof path !== "string"))
|
|
51501
51671
|
unresolved("unsupported plugin skill paths");
|
|
51502
51672
|
if (agent === "claude")
|
|
51503
|
-
roots.add(
|
|
51673
|
+
roots.add(join19(root, "skills"));
|
|
51504
51674
|
for (const value of declared) {
|
|
51505
|
-
const path =
|
|
51675
|
+
const path = resolve8(root, value);
|
|
51506
51676
|
if (path !== root && !path.startsWith(root + sep3))
|
|
51507
51677
|
unresolved("plugin skill path escapes its root");
|
|
51508
|
-
roots.add(path.endsWith(`${sep3}SKILL.md`) ?
|
|
51678
|
+
roots.add(path.endsWith(`${sep3}SKILL.md`) ? dirname8(path) : path);
|
|
51509
51679
|
}
|
|
51510
51680
|
}
|
|
51511
51681
|
if (agent === "claude") {
|
|
51512
|
-
const registrations = witness(
|
|
51513
|
-
const installed = registrations === null ? {} : parseConfig(registrations,
|
|
51514
|
-
const commands = canonical(
|
|
51515
|
-
|
|
51516
|
-
if (
|
|
51682
|
+
const registrations = witness(join19(home, ".claude/plugins/installed_plugins.json"));
|
|
51683
|
+
const installed = registrations === null ? {} : parseConfig(registrations, join19(home, ".claude/plugins/installed_plugins.json")).plugins;
|
|
51684
|
+
const commands = canonical(join19(home, ".claude/commands"));
|
|
51685
|
+
safe3(commands);
|
|
51686
|
+
if (lstatSync9(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length)
|
|
51517
51687
|
unresolved("legacy home command discovery requires a dedicated format adapter");
|
|
51518
51688
|
for (const [id, enabled] of Object.entries(config.enabledPlugins ?? {})) {
|
|
51519
51689
|
if (enabled === false)
|
|
@@ -51533,34 +51703,34 @@ function resolveAgentDiscovery(options) {
|
|
|
51533
51703
|
unresolved("unsupported plugin enablement");
|
|
51534
51704
|
const split2 = id.lastIndexOf("@"), name = id.slice(0, split2), marketplace = id.slice(split2 + 1);
|
|
51535
51705
|
const market = config.marketplaces?.[marketplace] ?? (marketplace === "personal" ? { source_type: "local", source: home } : undefined);
|
|
51536
|
-
if (split2 < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !
|
|
51706
|
+
if (split2 < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !isAbsolute6(market.source))
|
|
51537
51707
|
unresolved("enabled plugin marketplace is not an explicit local source");
|
|
51538
|
-
const catalogText = witness(
|
|
51708
|
+
const catalogText = witness(join19(market.source, ".agents/plugins/marketplace.json"));
|
|
51539
51709
|
if (catalogText === null)
|
|
51540
51710
|
unresolved("marketplace catalog missing");
|
|
51541
|
-
const catalog = parseConfig(catalogText,
|
|
51711
|
+
const catalog = parseConfig(catalogText, join19(market.source, ".agents/plugins/marketplace.json")), matches2 = Array.isArray(catalog.plugins) ? catalog.plugins.filter((item) => item.name === name) : [];
|
|
51542
51712
|
if (matches2.length !== 1 || matches2[0]?.source?.source !== "local" || typeof matches2[0]?.source?.path !== "string")
|
|
51543
51713
|
unresolved("plugin catalog source is missing or ambiguous");
|
|
51544
|
-
plugin(
|
|
51714
|
+
plugin(resolve8(market.source, matches2[0].source.path));
|
|
51545
51715
|
}
|
|
51546
51716
|
} else if (agent === "opencode") {
|
|
51547
|
-
if (witness(
|
|
51717
|
+
if (witness(join19(home, ".config/opencode/opencode.jsonc")) !== null || witness(join19(home, ".config/opencode/config.json")) !== null)
|
|
51548
51718
|
unresolved("additional config layers require review");
|
|
51549
51719
|
if ((config.plugin?.length ?? 0) > 0 || config.skills?.urls?.length)
|
|
51550
51720
|
unresolved("external plugin or remote skill source");
|
|
51551
51721
|
for (const path of config.skills?.paths ?? []) {
|
|
51552
|
-
if (typeof path !== "string" || !
|
|
51722
|
+
if (typeof path !== "string" || !isAbsolute6(path))
|
|
51553
51723
|
unresolved("relative or malformed added skill root");
|
|
51554
51724
|
roots.add(path);
|
|
51555
51725
|
}
|
|
51556
|
-
const localPlugins =
|
|
51557
|
-
|
|
51558
|
-
if (
|
|
51726
|
+
const localPlugins = join19(home, ".config/opencode/plugins");
|
|
51727
|
+
safe3(localPlugins);
|
|
51728
|
+
if (lstatSync9(localPlugins, { throwIfNoEntry: false }) && readdirSync9(localPlugins).some((name) => name !== "skills-cli.js"))
|
|
51559
51729
|
unresolved("additional local plugin hooks require review");
|
|
51560
51730
|
} else if (agent === "hermes") {
|
|
51561
|
-
for (const directory of [
|
|
51562
|
-
|
|
51563
|
-
if (
|
|
51731
|
+
for (const directory of [join19(home, ".hermes/plugins"), join19(home, ".hermes/hermes-agent")]) {
|
|
51732
|
+
safe3(directory);
|
|
51733
|
+
if (lstatSync9(directory, { throwIfNoEntry: false }))
|
|
51564
51734
|
unresolved("installed runtime/plugin discovery requires reviewed source bindings");
|
|
51565
51735
|
}
|
|
51566
51736
|
if (Bun.which("hermes") || Object.keys(config.plugins ?? {}).length)
|
|
@@ -51568,29 +51738,32 @@ function resolveAgentDiscovery(options) {
|
|
|
51568
51738
|
} else if (agent === "gemini") {
|
|
51569
51739
|
if (Object.keys(config.extensions ?? {}).length || config.skills?.paths?.length)
|
|
51570
51740
|
unresolved("custom extension or skill paths");
|
|
51571
|
-
const directory =
|
|
51572
|
-
|
|
51573
|
-
if (
|
|
51741
|
+
const directory = join19(home, ".gemini/extensions");
|
|
51742
|
+
safe3(directory);
|
|
51743
|
+
if (lstatSync9(directory, { throwIfNoEntry: false }))
|
|
51574
51744
|
for (const name of readdirSync9(directory)) {
|
|
51575
|
-
const root =
|
|
51576
|
-
|
|
51577
|
-
if (!
|
|
51745
|
+
const root = join19(directory, name);
|
|
51746
|
+
safe3(root);
|
|
51747
|
+
if (!lstatSync9(root)?.isDirectory())
|
|
51578
51748
|
continue;
|
|
51579
|
-
const raw = witness(
|
|
51749
|
+
const raw = witness(join19(root, "gemini-extension.json"));
|
|
51580
51750
|
if (raw === null)
|
|
51581
51751
|
unresolved("extension registration missing");
|
|
51582
|
-
const manifest = parseConfig(raw,
|
|
51583
|
-
if (manifest.hooks !== undefined || witness(
|
|
51752
|
+
const manifest = parseConfig(raw, join19(root, "gemini-extension.json"));
|
|
51753
|
+
if (manifest.hooks !== undefined || witness(join19(root, "hooks/hooks.json")) !== null || witness(join19(root, ".gemini-extension-install.json")) !== null)
|
|
51584
51754
|
unresolved("extension hooks or linked registration require review");
|
|
51585
|
-
roots.add(
|
|
51755
|
+
roots.add(join19(root, "skills"));
|
|
51586
51756
|
}
|
|
51587
51757
|
}
|
|
51588
|
-
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {} };
|
|
51758
|
+
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join19(home, ".hermes/plugins"), join19(home, ".hermes/hermes-agent")].map((path) => canonical(path))) } : {} };
|
|
51589
51759
|
}
|
|
51590
|
-
var digest = (text2) =>
|
|
51760
|
+
var digest = (text2) => createHash7("sha256").update(text2).digest("hex");
|
|
51591
51761
|
var init_agent_discovery = __esm(() => {
|
|
51592
51762
|
init_agent_policy_limits();
|
|
51593
51763
|
init_agent_hermes();
|
|
51764
|
+
init_agent_discovery_directories();
|
|
51765
|
+
init_agent_discovery_bytes();
|
|
51766
|
+
init_agent_discovery_directories();
|
|
51594
51767
|
});
|
|
51595
51768
|
|
|
51596
51769
|
// src/lib/agent-adapters.ts
|
|
@@ -51669,16 +51842,16 @@ var init_agent_adapters = __esm(() => {
|
|
|
51669
51842
|
});
|
|
51670
51843
|
|
|
51671
51844
|
// src/lib/agent-integration.ts
|
|
51672
|
-
import { createHash as
|
|
51673
|
-
import { existsSync as existsSync14, lstatSync as
|
|
51674
|
-
import { dirname as
|
|
51845
|
+
import { createHash as createHash8, randomUUID as randomUUID5 } from "crypto";
|
|
51846
|
+
import { existsSync as existsSync14, lstatSync as lstatSync10, statSync as statSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync12, readdirSync as readdirSync10, opendirSync as opendirSync3, readlinkSync, realpathSync as realpathSync4, renameSync as renameSync3, rmdirSync, writeFileSync as writeFileSync5, unlinkSync as unlinkSync2, chmodSync, openSync as openSync4, closeSync as closeSync4, fsyncSync, fstatSync as fstatSync4, readSync as readSync4, constants as constants5, linkSync } from "fs";
|
|
51847
|
+
import { dirname as dirname9, join as join20, resolve as resolve9, relative as relative4, isAbsolute as isAbsolute7, sep as sep4 } from "path";
|
|
51675
51848
|
import { homedir as homedir3 } from "os";
|
|
51676
51849
|
function assertSafePath(path) {
|
|
51677
|
-
let cursor =
|
|
51850
|
+
let cursor = resolve9(path);
|
|
51678
51851
|
while (true) {
|
|
51679
|
-
if (
|
|
51852
|
+
if (lstatSync10(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
51680
51853
|
throw new Error(`Refusing symlink path: ${cursor}`);
|
|
51681
|
-
const parent =
|
|
51854
|
+
const parent = dirname9(cursor);
|
|
51682
51855
|
if (parent === cursor)
|
|
51683
51856
|
return;
|
|
51684
51857
|
cursor = parent;
|
|
@@ -51686,17 +51859,17 @@ function assertSafePath(path) {
|
|
|
51686
51859
|
}
|
|
51687
51860
|
function readRootAlias(home, agent) {
|
|
51688
51861
|
assertSafePath(home);
|
|
51689
|
-
const realHome = realpathSync4(home), alias =
|
|
51690
|
-
const stat =
|
|
51862
|
+
const realHome = realpathSync4(home), alias = join20(realHome, `.${agent}`);
|
|
51863
|
+
const stat = lstatSync10(alias, { throwIfNoEntry: false, bigint: true });
|
|
51691
51864
|
if (!stat?.isSymbolicLink())
|
|
51692
51865
|
throw new Error(`Agent root alias changed after planning: ${alias}`);
|
|
51693
|
-
const link2 = readlinkSync(alias), targetPath =
|
|
51866
|
+
const link2 = readlinkSync(alias), targetPath = resolve9(dirname9(alias), link2);
|
|
51694
51867
|
assertSafePath(targetPath);
|
|
51695
|
-
const targetStat =
|
|
51868
|
+
const targetStat = lstatSync10(targetPath, { throwIfNoEntry: false });
|
|
51696
51869
|
if (!targetStat?.isDirectory())
|
|
51697
51870
|
throw new Error(`Agent root alias must target an existing directory: ${alias}`);
|
|
51698
51871
|
const target = realpathSync4(targetPath), inside = relative4(realHome, target);
|
|
51699
|
-
if (!inside || inside === ".." || inside.startsWith(`..${sep4}`) ||
|
|
51872
|
+
if (!inside || inside === ".." || inside.startsWith(`..${sep4}`) || isAbsolute7(inside))
|
|
51700
51873
|
throw new Error(`Agent root alias target must be inside the real home: ${alias}`);
|
|
51701
51874
|
return { agent, home: realHome, alias, target, link: link2, aliasIdentity: `${stat.dev}:${stat.ino}:${stat.ctimeNs}`, targetIdentity: `${targetStat.dev}:${targetStat.ino}` };
|
|
51702
51875
|
}
|
|
@@ -51705,19 +51878,19 @@ function rootAliases(home, allowed = false) {
|
|
|
51705
51878
|
return [];
|
|
51706
51879
|
const result2 = [];
|
|
51707
51880
|
for (const agent of ["claude", "codex"])
|
|
51708
|
-
if (
|
|
51881
|
+
if (lstatSync10(join20(home, `.${agent}`), { throwIfNoEntry: false })?.isSymbolicLink())
|
|
51709
51882
|
result2.push(readRootAlias(home, agent));
|
|
51710
51883
|
if (result2.some((item, index) => result2.slice(index + 1).some((other) => item.target === other.target || item.target.startsWith(other.target + sep4) || other.target.startsWith(item.target + sep4))))
|
|
51711
51884
|
throw new Error("Agent root alias targets must not overlap");
|
|
51712
51885
|
return result2;
|
|
51713
51886
|
}
|
|
51714
51887
|
function canonicalAgentPath(path, aliases) {
|
|
51715
|
-
const absolute =
|
|
51716
|
-
return binding ?
|
|
51888
|
+
const absolute = resolve9(path), binding = aliases.find((item) => absolute === item.alias || absolute.startsWith(item.alias + sep4));
|
|
51889
|
+
return binding ? join20(binding.target, relative4(binding.alias, absolute)) : absolute;
|
|
51717
51890
|
}
|
|
51718
51891
|
function recheckRootAliases(aliases) {
|
|
51719
51892
|
for (const binding of aliases) {
|
|
51720
|
-
if (!["claude", "codex"].includes(binding.agent) || binding.alias !==
|
|
51893
|
+
if (!["claude", "codex"].includes(binding.agent) || binding.alias !== join20(binding.home, `.${binding.agent}`))
|
|
51721
51894
|
throw new Error("Invalid agent root alias binding");
|
|
51722
51895
|
const current = readRootAlias(binding.home, binding.agent);
|
|
51723
51896
|
if (JSON.stringify(current) !== JSON.stringify(binding))
|
|
@@ -51726,42 +51899,42 @@ function recheckRootAliases(aliases) {
|
|
|
51726
51899
|
}
|
|
51727
51900
|
function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
|
|
51728
51901
|
assertSafePath(path);
|
|
51729
|
-
const before2 =
|
|
51902
|
+
const before2 = lstatSync10(path);
|
|
51730
51903
|
if (!before2.isFile() || before2.size > maximum)
|
|
51731
51904
|
throw new Error("Unsupported or oversized native skill file");
|
|
51732
|
-
const descriptor =
|
|
51905
|
+
const descriptor = openSync4(path, constants5.O_RDONLY | constants5.O_NOFOLLOW | constants5.O_NONBLOCK);
|
|
51733
51906
|
try {
|
|
51734
|
-
const opened =
|
|
51907
|
+
const opened = fstatSync4(descriptor);
|
|
51735
51908
|
if (!opened.isFile() || opened.dev !== before2.dev || opened.ino !== before2.ino || opened.size !== before2.size)
|
|
51736
51909
|
throw new Error("Native skill file changed while reading");
|
|
51737
51910
|
const bytes = Buffer.allocUnsafe(before2.size + 1);
|
|
51738
51911
|
let length = 0;
|
|
51739
51912
|
while (length < bytes.length) {
|
|
51740
|
-
const count =
|
|
51913
|
+
const count = readSync4(descriptor, bytes, length, bytes.length - length, null);
|
|
51741
51914
|
if (!count)
|
|
51742
51915
|
break;
|
|
51743
51916
|
length += count;
|
|
51744
51917
|
}
|
|
51745
|
-
const after2 =
|
|
51918
|
+
const after2 = fstatSync4(descriptor);
|
|
51746
51919
|
if (length !== before2.size || after2.size !== before2.size || after2.mtimeMs !== opened.mtimeMs || after2.ctimeMs !== opened.ctimeMs)
|
|
51747
51920
|
throw new Error("Native skill file changed while reading");
|
|
51748
51921
|
return bytes.subarray(0, length);
|
|
51749
51922
|
} finally {
|
|
51750
|
-
|
|
51923
|
+
closeSync4(descriptor);
|
|
51751
51924
|
}
|
|
51752
51925
|
}
|
|
51753
51926
|
function treeHash(root) {
|
|
51754
|
-
const hash2 =
|
|
51927
|
+
const hash2 = createHash8("sha256");
|
|
51755
51928
|
let bytes = 0, files = 0;
|
|
51756
51929
|
function visit2(path) {
|
|
51757
|
-
const stat =
|
|
51930
|
+
const stat = lstatSync10(path);
|
|
51758
51931
|
if (stat.isSymbolicLink())
|
|
51759
51932
|
throw new Error(`Refusing symlink in skill: ${path}`);
|
|
51760
51933
|
const rel = relative4(root, path);
|
|
51761
51934
|
if (stat.isDirectory()) {
|
|
51762
51935
|
hash2.update(`d\x00${rel}\x00`);
|
|
51763
51936
|
for (const name of readdirSync10(path).sort())
|
|
51764
|
-
visit2(
|
|
51937
|
+
visit2(join20(path, name));
|
|
51765
51938
|
return;
|
|
51766
51939
|
}
|
|
51767
51940
|
if (!stat.isFile())
|
|
@@ -51779,37 +51952,50 @@ function treeHash(root) {
|
|
|
51779
51952
|
}
|
|
51780
51953
|
function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
51781
51954
|
const aliases = rootAliases(home, options.allowRootAliases);
|
|
51782
|
-
const roots = ROOTS.map(([agent, path]) => [agent, canonicalAgentPath(
|
|
51783
|
-
const bridgePaths = Object.values(AGENT_ADAPTERS).map((adapter) => canonicalAgentPath(
|
|
51784
|
-
for (const project of new Set([...options.projectDirs ?? [], ...options.projectDir ? [options.projectDir] : []].map((path) =>
|
|
51955
|
+
const roots = ROOTS.map(([agent, path]) => [agent, canonicalAgentPath(join20(home, path), aliases)]);
|
|
51956
|
+
const bridgePaths = Object.values(AGENT_ADAPTERS).map((adapter) => canonicalAgentPath(join20(home, adapter.root, CLI_BRIDGE_NAME), aliases));
|
|
51957
|
+
for (const project of new Set([...options.projectDirs ?? [], ...options.projectDir ? [options.projectDir] : []].map((path) => resolve9(path)))) {
|
|
51785
51958
|
for (const [agent, path] of ROOTS)
|
|
51786
|
-
roots.push([agent, canonicalAgentPath(
|
|
51959
|
+
roots.push([agent, canonicalAgentPath(join20(project, path), aliases)]);
|
|
51787
51960
|
}
|
|
51788
51961
|
const entries = [], seen = new Set;
|
|
51789
51962
|
const cacheScans = new Map, maxAliasProofEntries = 1e4;
|
|
51963
|
+
let discoveryEntries = 0, discoveryPathBytes = 0;
|
|
51964
|
+
function admit(path) {
|
|
51965
|
+
if (++discoveryEntries > 20000)
|
|
51966
|
+
throw new Error("Native skill discovery entry limit exceeded");
|
|
51967
|
+
discoveryPathBytes += Buffer.byteLength(path, "utf8");
|
|
51968
|
+
if (discoveryPathBytes > 4 * 1024 * 1024)
|
|
51969
|
+
throw new Error("Native skill discovery metadata limit exceeded");
|
|
51970
|
+
}
|
|
51790
51971
|
function emptySiblingCacheAlias(path, parent) {
|
|
51791
|
-
const link2 = readlinkSync(path), target =
|
|
51792
|
-
if (
|
|
51972
|
+
const link2 = readlinkSync(path), target = resolve9(parent, link2);
|
|
51973
|
+
if (dirname9(target) !== parent || (isAbsolute7(link2) ? link2 !== target : dirname9(link2) !== "."))
|
|
51793
51974
|
return false;
|
|
51794
|
-
if (!
|
|
51975
|
+
if (!lstatSync10(target, { throwIfNoEntry: false })?.isDirectory())
|
|
51795
51976
|
return false;
|
|
51796
51977
|
const scan = cacheScans.get(target);
|
|
51797
51978
|
return Boolean(scan?.complete && !scan.hasSkills && scan.entries <= maxAliasProofEntries);
|
|
51798
51979
|
}
|
|
51799
|
-
function visit2(agent, path, vendor = false, depth = 0, pluginCache = false) {
|
|
51980
|
+
function visit2(agent, path, vendor = false, depth = 0, pluginCache = false, admitted = false) {
|
|
51981
|
+
if (!admitted)
|
|
51982
|
+
admit(path);
|
|
51800
51983
|
const scan = { complete: true, hasSkills: false, entries: 1 };
|
|
51801
51984
|
assertSafePath(path);
|
|
51802
51985
|
if (!existsSync14(path))
|
|
51803
51986
|
return scan;
|
|
51804
|
-
|
|
51987
|
+
const stat = lstatSync10(path);
|
|
51988
|
+
if (stat.isFile())
|
|
51805
51989
|
return scan;
|
|
51806
|
-
if (
|
|
51990
|
+
if (!stat.isDirectory())
|
|
51991
|
+
throw new Error(`Unsupported native discovery entry: ${path}`);
|
|
51992
|
+
if (existsSync14(join20(path, "SKILL.md"))) {
|
|
51807
51993
|
scan.hasSkills = true;
|
|
51808
51994
|
if (seen.has(path))
|
|
51809
51995
|
return scan;
|
|
51810
51996
|
seen.add(path);
|
|
51811
51997
|
let managed = false;
|
|
51812
|
-
const marker =
|
|
51998
|
+
const marker = join20(path, ".hasna-skills.json");
|
|
51813
51999
|
if (existsSync14(marker)) {
|
|
51814
52000
|
try {
|
|
51815
52001
|
managed = JSON.parse(readFileSync12(marker, "utf8")).managedBy === "@hasna/skills";
|
|
@@ -51817,12 +52003,22 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
51817
52003
|
}
|
|
51818
52004
|
const bridge = !vendor && isOwnedCliBridge(path, bridgePaths);
|
|
51819
52005
|
const rootAlias = aliases.find((item) => path === item.target || path.startsWith(item.target + sep4));
|
|
51820
|
-
entries.push({ agent, path, hash: treeHash(path), managed, vendor, ...agent === "codex" && path.startsWith(canonicalAgentPath(
|
|
52006
|
+
entries.push({ agent, path, hash: treeHash(path), managed, vendor, ...agent === "codex" && path.startsWith(canonicalAgentPath(join20(home, ".codex", "skills", ".system"), aliases) + sep4) ? { system: true } : {}, ...bridge ? { bridge: true, bridgeHome: resolve9(home) } : {}, ...rootAlias ? { rootAlias } : {} });
|
|
51821
52007
|
return scan;
|
|
51822
52008
|
}
|
|
51823
|
-
if (depth > (vendor ?
|
|
52009
|
+
if (depth > (vendor ? 32 : 3))
|
|
51824
52010
|
return { ...scan, complete: false };
|
|
51825
|
-
const children =
|
|
52011
|
+
const children = [], directory = opendirSync3(path);
|
|
52012
|
+
try {
|
|
52013
|
+
let child;
|
|
52014
|
+
while ((child = directory.readSync()) !== null) {
|
|
52015
|
+
admit(join20(path, child.name));
|
|
52016
|
+
children.push(child);
|
|
52017
|
+
}
|
|
52018
|
+
} finally {
|
|
52019
|
+
directory.closeSync();
|
|
52020
|
+
}
|
|
52021
|
+
children.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
51826
52022
|
if (pluginCache)
|
|
51827
52023
|
children.sort((a, b) => Number(a.isSymbolicLink()) - Number(b.isSymbolicLink()));
|
|
51828
52024
|
for (const { name } of children) {
|
|
@@ -51833,15 +52029,15 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
51833
52029
|
const isVendor = vendor || name === ".system";
|
|
51834
52030
|
if (isVendor && !options.includeVendor)
|
|
51835
52031
|
continue;
|
|
51836
|
-
const child =
|
|
51837
|
-
if (isVendor &&
|
|
52032
|
+
const child = join20(path, name);
|
|
52033
|
+
if (isVendor && lstatSync10(child, { throwIfNoEntry: false })?.isSymbolicLink()) {
|
|
51838
52034
|
const target = statSync8(child, { throwIfNoEntry: false });
|
|
51839
52035
|
if (target?.isFile() || pluginCache && target?.isDirectory() && emptySiblingCacheAlias(child, path)) {
|
|
51840
52036
|
scan.entries++;
|
|
51841
52037
|
continue;
|
|
51842
52038
|
}
|
|
51843
52039
|
}
|
|
51844
|
-
const childScan = visit2(agent, child, isVendor, depth + 1, pluginCache);
|
|
52040
|
+
const childScan = visit2(agent, child, isVendor, depth + 1, pluginCache, true);
|
|
51845
52041
|
scan.complete &&= childScan.complete;
|
|
51846
52042
|
scan.hasSkills ||= childScan.hasSkills;
|
|
51847
52043
|
scan.entries += childScan.entries;
|
|
@@ -51860,8 +52056,8 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
51860
52056
|
scanRoot(agent, path);
|
|
51861
52057
|
if (options.includeVendor) {
|
|
51862
52058
|
for (const agent of ["codex", "claude"])
|
|
51863
|
-
scanRoot(agent, canonicalAgentPath(
|
|
51864
|
-
scanRoot("gemini",
|
|
52059
|
+
scanRoot(agent, canonicalAgentPath(join20(home, `.${agent}`, "plugins", "cache"), aliases), true, true);
|
|
52060
|
+
scanRoot("gemini", join20(home, ".gemini", "extensions"), true);
|
|
51865
52061
|
}
|
|
51866
52062
|
const configured = options.configured ? INTEGRATION_AGENTS.flatMap((agent) => resolveAgentDiscovery({ home, agent, reviewed: options.discoveryInputs, canonical: (path) => canonicalAgentPath(path, aliases) }).roots.map((path) => ({ agent, path }))) : [];
|
|
51867
52063
|
for (const root of [...options.agentRoots ?? [], ...configured])
|
|
@@ -51959,12 +52155,12 @@ function disableCodexSkills(text2, skills, aliases, bridgePath) {
|
|
|
51959
52155
|
let result2 = text2;
|
|
51960
52156
|
const selections = [...skills.filter((entry) => entry.agent === "codex" && !entry.bridge).map((skill) => ({ path: skill.path, enabled: false })), { path: bridgePath, enabled: true }];
|
|
51961
52157
|
for (const skill of selections) {
|
|
51962
|
-
const path =
|
|
52158
|
+
const path = join20(skill.path, "SKILL.md");
|
|
51963
52159
|
let found = false;
|
|
51964
52160
|
result2 = result2.replace(/^\[\[skills\.config\]\][^\n]*(?:\n(?!\s*\[)[^\n]*)*/gm, (section) => {
|
|
51965
52161
|
const parsed = Bun.TOML.parse(section);
|
|
51966
52162
|
const declared = parsed.skills?.config?.[0]?.path;
|
|
51967
|
-
if (!declared || ![
|
|
52163
|
+
if (!declared || ![resolve9(path), resolve9(skill.path)].includes(canonicalAgentPath(declared, aliases)))
|
|
51968
52164
|
return section;
|
|
51969
52165
|
found = true;
|
|
51970
52166
|
return /^\s*enabled\s*=/m.test(section) ? section.replace(/^\s*enabled\s*=.*$/m, `enabled = ${skill.enabled}`) : `${section.trimEnd()}
|
|
@@ -51988,7 +52184,7 @@ function planAgentIntegration(options) {
|
|
|
51988
52184
|
if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(profileId) || profileId.includes(".."))
|
|
51989
52185
|
throw new Error("Invalid selection profile id");
|
|
51990
52186
|
const aliases = rootAliases(home, options.allowRootAliases);
|
|
51991
|
-
const policyPath =
|
|
52187
|
+
const policyPath = join20(dataDir3, "agent-policy.json");
|
|
51992
52188
|
assertSafePath(policyPath);
|
|
51993
52189
|
const priorSnapshot = readManagedSkillPolicySnapshot(dataDir3), previousPolicy = priorSnapshot?.text ?? null, policy = priorSnapshot?.value ?? {};
|
|
51994
52190
|
if (policy.bridge !== undefined && (!policy.bridge || typeof policy.bridge !== "object" || Array.isArray(policy.bridge)))
|
|
@@ -52005,19 +52201,19 @@ function planAgentIntegration(options) {
|
|
|
52005
52201
|
if (!INTEGRATION_AGENTS.includes(agent))
|
|
52006
52202
|
throw new Error(`Unsupported agent: ${agent}`);
|
|
52007
52203
|
const adapter = AGENT_ADAPTERS[agent];
|
|
52008
|
-
const bridgePath = canonicalAgentPath(
|
|
52204
|
+
const bridgePath = canonicalAgentPath(join20(home, adapter.root, CLI_BRIDGE_NAME), aliases);
|
|
52009
52205
|
assertSafePath(bridgePath);
|
|
52010
52206
|
if (existsSync14(bridgePath) && !isOwnedCliBridge(bridgePath, [bridgePath]))
|
|
52011
52207
|
throw new Error(`Refusing to overwrite an unrecognized or modified Skills bridge: ${bridgePath}`);
|
|
52012
52208
|
for (const [name, after3] of Object.entries(CLI_BRIDGE_FILES)) {
|
|
52013
|
-
const path2 =
|
|
52209
|
+
const path2 = join20(bridgePath, name), before3 = readOptional(path2);
|
|
52014
52210
|
if (before3 !== after3)
|
|
52015
52211
|
changes.push({ path: path2, before: before3, after: after3 });
|
|
52016
52212
|
}
|
|
52017
|
-
const path = canonicalAgentPath(
|
|
52213
|
+
const path = canonicalAgentPath(join20(home, adapter.config), aliases);
|
|
52018
52214
|
const before2 = readOptional(path);
|
|
52019
52215
|
if (agent === "hermes") {
|
|
52020
|
-
const supervisorPath =
|
|
52216
|
+
const supervisorPath = join20(dataDir3, "agent-hooks", "hermes.js"), supervisorBefore = readOptional(supervisorPath), supervisorAfter = renderHermesSupervisor(options.command ?? "skills", profileId);
|
|
52021
52217
|
const priorCommand = policy.bridge?.commands?.hermes, priorProfile = policy.bridge?.profiles?.hermes ?? policy.profileId;
|
|
52022
52218
|
const previous = policy.bridge?.supervisors?.hermes;
|
|
52023
52219
|
if (supervisorBefore !== null && supervisorBefore !== supervisorAfter && !(previous?.path === supervisorPath && typeof priorCommand === "string" && typeof priorProfile === "string" && supervisorBefore === renderHermesSupervisor(priorCommand, priorProfile)))
|
|
@@ -52028,7 +52224,7 @@ function planAgentIntegration(options) {
|
|
|
52028
52224
|
const after3 = configureHermesHooks(before2, supervisor, previous);
|
|
52029
52225
|
if (before2 !== after3)
|
|
52030
52226
|
changes.push({ path, before: before2, after: after3 });
|
|
52031
|
-
const optOut =
|
|
52227
|
+
const optOut = join20(home, ".hermes", HERMES_OPT_OUT), optOutBefore = readOptional(optOut);
|
|
52032
52228
|
if (optOutBefore === null)
|
|
52033
52229
|
changes.push({ path: optOut, before: null, after: `Managed by @hasna/skills: bundled native skill reseeding is disabled.
|
|
52034
52230
|
` });
|
|
@@ -52040,7 +52236,7 @@ function planAgentIntegration(options) {
|
|
|
52040
52236
|
if (!permission || typeof permission !== "object" || Array.isArray(permission))
|
|
52041
52237
|
throw new Error("Expected OpenCode permission object");
|
|
52042
52238
|
config.permission = { ...permission, skill: { "*": "deny", [CLI_BRIDGE_NAME]: "allow" } };
|
|
52043
|
-
const pluginPath =
|
|
52239
|
+
const pluginPath = join20(home, ".config", "opencode", "plugins", "skills-cli.js"), pluginBefore = readOptional(pluginPath);
|
|
52044
52240
|
const pluginAfter = renderOpenCodePlugin(options.command ?? "skills", profileId);
|
|
52045
52241
|
const priorCommand = policy.bridge?.commands?.opencode;
|
|
52046
52242
|
const ownedPrevious = typeof priorCommand === "string" && typeof policy.profileId === "string" && pluginBefore === renderOpenCodePlugin(priorCommand, policy.bridge?.profiles?.opencode ?? policy.profileId);
|
|
@@ -52057,7 +52253,7 @@ function planAgentIntegration(options) {
|
|
|
52057
52253
|
if (before2 !== after2)
|
|
52058
52254
|
changes.push({ path, before: before2, after: after2 });
|
|
52059
52255
|
if (agent === "codex") {
|
|
52060
|
-
const configPath = canonicalAgentPath(
|
|
52256
|
+
const configPath = canonicalAgentPath(join20(home, ".codex", "config.toml"), aliases), previous = readOptional(configPath);
|
|
52061
52257
|
const next = disableCodexSkills(previous ?? "", nativeSkills, aliases, bridgePath);
|
|
52062
52258
|
if (next !== (previous ?? ""))
|
|
52063
52259
|
changes.push({ path: configPath, before: previous, after: next });
|
|
@@ -52070,12 +52266,12 @@ function planAgentIntegration(options) {
|
|
|
52070
52266
|
version: CLI_BRIDGE_VERSION,
|
|
52071
52267
|
digest: CLI_BRIDGE_DIGEST,
|
|
52072
52268
|
agents: [...new Set([...priorAgents, ...options.agents])].sort(),
|
|
52073
|
-
home:
|
|
52269
|
+
home: resolve9(home),
|
|
52074
52270
|
includeVendor: true,
|
|
52075
|
-
...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path:
|
|
52271
|
+
...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join20(dataDir3, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256: sha(renderHermesSupervisor(options.command ?? "skills", profileId)) } } } : {},
|
|
52076
52272
|
commands: { ...policy.bridge?.commands, ...Object.fromEntries(options.agents.map((agent) => [agent, options.command ?? "skills"])) },
|
|
52077
52273
|
profiles: Object.fromEntries([...new Set([...priorAgents, ...options.agents])].sort().map((agent) => [agent, options.agents.includes(agent) ? profileId : policy.bridge?.profiles?.[agent] ?? policy.profileId])),
|
|
52078
|
-
disabledBuiltins: options.agents.includes("codex") ? nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor && entry.path.startsWith(canonicalAgentPath(
|
|
52274
|
+
disabledBuiltins: options.agents.includes("codex") ? nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor && entry.path.startsWith(canonicalAgentPath(join20(home, ".codex", "skills", ".system"), aliases) + sep4)).map((entry) => ({ path: entry.path, hash: entry.hash })) : policy.bridge?.disabledBuiltins ?? [],
|
|
52079
52275
|
rootAliases: aliases,
|
|
52080
52276
|
discovery: { ...policy.bridge?.discovery, ...Object.fromEntries(discoveryAfter.map((binding) => [binding.agent, binding])) }
|
|
52081
52277
|
} };
|
|
@@ -52087,7 +52283,7 @@ function planAgentIntegration(options) {
|
|
|
52087
52283
|
}
|
|
52088
52284
|
function atomicWrite2(path, content) {
|
|
52089
52285
|
assertSafePath(path);
|
|
52090
|
-
mkdirSync5(
|
|
52286
|
+
mkdirSync5(dirname9(path), { recursive: true, mode: 448 });
|
|
52091
52287
|
const temporary = `${path}.skills-${randomUUID5()}`;
|
|
52092
52288
|
try {
|
|
52093
52289
|
writeFileSync5(temporary, content, { mode: 384, flag: "wx" });
|
|
@@ -52098,12 +52294,12 @@ function atomicWrite2(path, content) {
|
|
|
52098
52294
|
}
|
|
52099
52295
|
}
|
|
52100
52296
|
function applyAgentIntegration(plan) {
|
|
52101
|
-
const policyPath =
|
|
52297
|
+
const policyPath = join20(plan.dataDir, "agent-policy.json");
|
|
52102
52298
|
assertSafePath(policyPath);
|
|
52103
|
-
const currentText = (path) =>
|
|
52299
|
+
const currentText = (path) => resolve9(path) === resolve9(policyPath) ? readManagedSkillPolicySnapshot(plan.dataDir)?.text ?? null : readOptional(path);
|
|
52104
52300
|
readManagedSkillPolicySnapshot(plan.dataDir);
|
|
52105
52301
|
for (const change of plan.changes)
|
|
52106
|
-
if (
|
|
52302
|
+
if (resolve9(change.path) === resolve9(policyPath))
|
|
52107
52303
|
parseManagedSkillPolicy(change.after);
|
|
52108
52304
|
const aliases = plan.rootAliases ?? [];
|
|
52109
52305
|
recheckRootAliases(aliases);
|
|
@@ -52114,7 +52310,7 @@ function applyAgentIntegration(plan) {
|
|
|
52114
52310
|
for (const change of plan.changes)
|
|
52115
52311
|
if (currentText(change.path) !== change.before)
|
|
52116
52312
|
throw new Error(`Configuration changed after planning: ${change.path}`);
|
|
52117
|
-
const backupRoot =
|
|
52313
|
+
const backupRoot = join20(plan.dataDir, "migration", randomUUID5()), backups = [], written = [], createdDirectories = new Set;
|
|
52118
52314
|
if (!plan.changes.length) {
|
|
52119
52315
|
recheckRootAliases(aliases);
|
|
52120
52316
|
return { changed: [], backups, ...aliases.length ? { rootAliases: aliases } : {} };
|
|
@@ -52124,7 +52320,7 @@ function applyAgentIntegration(plan) {
|
|
|
52124
52320
|
chmodSync(backupRoot, 448);
|
|
52125
52321
|
for (const [index, change] of plan.changes.entries())
|
|
52126
52322
|
if (change.before !== null) {
|
|
52127
|
-
const backup =
|
|
52323
|
+
const backup = join20(backupRoot, `${index}-${sha(change.path).slice(0, 12)}.backup`);
|
|
52128
52324
|
writeFileSync5(backup, change.before, { mode: 384, flag: "wx" });
|
|
52129
52325
|
backups.push(backup);
|
|
52130
52326
|
}
|
|
@@ -52133,7 +52329,7 @@ function applyAgentIntegration(plan) {
|
|
|
52133
52329
|
recheckRootAliases(aliases);
|
|
52134
52330
|
if (currentText(change.path) !== change.before)
|
|
52135
52331
|
throw new Error(`Configuration changed after planning: ${change.path}`);
|
|
52136
|
-
for (let directory =
|
|
52332
|
+
for (let directory = dirname9(change.path);!existsSync14(directory); directory = dirname9(directory))
|
|
52137
52333
|
createdDirectories.add(directory);
|
|
52138
52334
|
const after2 = change.after;
|
|
52139
52335
|
atomicWrite2(change.path, after2);
|
|
@@ -52142,7 +52338,7 @@ function applyAgentIntegration(plan) {
|
|
|
52142
52338
|
recheckRootAliases(aliases);
|
|
52143
52339
|
for (const binding of plan.discoveryAfter ?? [])
|
|
52144
52340
|
verifyAgentDiscovery(binding);
|
|
52145
|
-
atomicWrite2(
|
|
52341
|
+
atomicWrite2(join20(backupRoot, "receipt.json"), JSON.stringify({ version: 1, changes: written.map((change) => ({ path: change.path, beforeHash: change.before === null ? null : sha(change.before), afterHash: sha(change.after) })), backups, ...aliases.length ? { rootAliases: aliases } : {} }) + `
|
|
52146
52342
|
`);
|
|
52147
52343
|
} catch (error) {
|
|
52148
52344
|
for (const change of written.reverse()) {
|
|
@@ -52173,11 +52369,11 @@ function applyAgentIntegration(plan) {
|
|
|
52173
52369
|
}
|
|
52174
52370
|
function syncArchiveDirectory(path) {
|
|
52175
52371
|
assertSafePath(path);
|
|
52176
|
-
const descriptor =
|
|
52372
|
+
const descriptor = openSync4(path, constants5.O_RDONLY | constants5.O_DIRECTORY | constants5.O_NOFOLLOW | constants5.O_NONBLOCK);
|
|
52177
52373
|
try {
|
|
52178
52374
|
fsyncSync(descriptor);
|
|
52179
52375
|
} finally {
|
|
52180
|
-
|
|
52376
|
+
closeSync4(descriptor);
|
|
52181
52377
|
}
|
|
52182
52378
|
}
|
|
52183
52379
|
function writeArchiveJournal(path, value) {
|
|
@@ -52185,18 +52381,18 @@ function writeArchiveJournal(path, value) {
|
|
|
52185
52381
|
const temporary = `${path}.skills-${randomUUID5()}`;
|
|
52186
52382
|
let descriptor;
|
|
52187
52383
|
try {
|
|
52188
|
-
descriptor =
|
|
52384
|
+
descriptor = openSync4(temporary, constants5.O_WRONLY | constants5.O_CREAT | constants5.O_EXCL | constants5.O_NOFOLLOW, 384);
|
|
52189
52385
|
writeFileSync5(descriptor, `${JSON.stringify(value)}
|
|
52190
52386
|
`);
|
|
52191
52387
|
fsyncSync(descriptor);
|
|
52192
|
-
|
|
52388
|
+
closeSync4(descriptor);
|
|
52193
52389
|
descriptor = undefined;
|
|
52194
52390
|
renameSync3(temporary, path);
|
|
52195
|
-
syncArchiveDirectory(
|
|
52391
|
+
syncArchiveDirectory(dirname9(path));
|
|
52196
52392
|
} finally {
|
|
52197
52393
|
if (descriptor !== undefined)
|
|
52198
|
-
|
|
52199
|
-
if (
|
|
52394
|
+
closeSync4(descriptor);
|
|
52395
|
+
if (lstatSync10(temporary, { throwIfNoEntry: false }))
|
|
52200
52396
|
unlinkSync2(temporary);
|
|
52201
52397
|
}
|
|
52202
52398
|
}
|
|
@@ -52207,7 +52403,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
52207
52403
|
recheckRootAliases(aliases);
|
|
52208
52404
|
for (const entry of inventory.filter((entry2) => entry2.bridge)) {
|
|
52209
52405
|
const adapter = AGENT_ADAPTERS[entry.agent];
|
|
52210
|
-
const expected = adapter && entry.bridgeHome ? canonicalAgentPath(
|
|
52406
|
+
const expected = adapter && entry.bridgeHome ? canonicalAgentPath(join20(entry.bridgeHome, adapter.root, CLI_BRIDGE_NAME), aliases) : undefined;
|
|
52211
52407
|
if (!expected || treeHash(entry.path) !== entry.hash || !isOwnedCliBridge(entry.path, [expected]))
|
|
52212
52408
|
throw new Error(`Skills bridge changed after planning: ${entry.path}`);
|
|
52213
52409
|
}
|
|
@@ -52217,11 +52413,11 @@ function archiveNativeSkills(inventory, options) {
|
|
|
52217
52413
|
throw new Error(`Native skill changed after planning: ${entry.path}`);
|
|
52218
52414
|
if (!selected.length)
|
|
52219
52415
|
return { entries: [], ...aliases.length ? { rootAliases: aliases } : {} };
|
|
52220
|
-
const operationId = randomUUID5(), archiveRoot =
|
|
52416
|
+
const operationId = randomUUID5(), archiveRoot = join20(options.dataDir ?? getDataDir(), "migration", operationId, "native"), receiptPath = join20(archiveRoot, "receipt.json");
|
|
52221
52417
|
const entries = selected.map((entry, index) => ({
|
|
52222
|
-
source: entry.vendor ?
|
|
52223
|
-
archive:
|
|
52224
|
-
hash: entry.vendor ? sha(readNativeBytes(
|
|
52418
|
+
source: entry.vendor ? join20(entry.path, "SKILL.md") : entry.path,
|
|
52419
|
+
archive: join20(archiveRoot, `${index}-${sha(entry.path).slice(0, 12)}`),
|
|
52420
|
+
hash: entry.vendor ? sha(readNativeBytes(join20(entry.path, "SKILL.md"))) : entry.hash,
|
|
52225
52421
|
...entry.vendor ? { discoveryOnly: true } : {},
|
|
52226
52422
|
status: "planned"
|
|
52227
52423
|
}));
|
|
@@ -52229,7 +52425,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
52229
52425
|
const moved = [];
|
|
52230
52426
|
const verifyArchive = (entry) => {
|
|
52231
52427
|
assertSafePath(entry.archive);
|
|
52232
|
-
const stat =
|
|
52428
|
+
const stat = lstatSync10(entry.archive);
|
|
52233
52429
|
if (entry.discoveryOnly ? !stat.isFile() : !stat.isDirectory())
|
|
52234
52430
|
throw new Error("Archive type changed");
|
|
52235
52431
|
if ((entry.discoveryOnly ? sha(readNativeBytes(entry.archive)) : treeHash(entry.archive)) !== entry.hash)
|
|
@@ -52237,14 +52433,14 @@ function archiveNativeSkills(inventory, options) {
|
|
|
52237
52433
|
};
|
|
52238
52434
|
assertSafePath(archiveRoot);
|
|
52239
52435
|
const created = [];
|
|
52240
|
-
for (let path = archiveRoot;!existsSync14(path); path =
|
|
52436
|
+
for (let path = archiveRoot;!existsSync14(path); path = dirname9(path))
|
|
52241
52437
|
created.push(path);
|
|
52242
52438
|
mkdirSync5(archiveRoot, { recursive: true, mode: 448 });
|
|
52243
52439
|
try {
|
|
52244
52440
|
for (const directory of created)
|
|
52245
52441
|
syncArchiveDirectory(directory);
|
|
52246
52442
|
if (created.length)
|
|
52247
|
-
syncArchiveDirectory(
|
|
52443
|
+
syncArchiveDirectory(dirname9(created.at(-1)));
|
|
52248
52444
|
writeArchiveJournal(receiptPath, journal);
|
|
52249
52445
|
for (const [index, entry] of selected.entries()) {
|
|
52250
52446
|
recheckRootAliases(aliases);
|
|
@@ -52256,7 +52452,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
52256
52452
|
writeArchiveJournal(receiptPath, journal);
|
|
52257
52453
|
renameSync3(move.source, move.archive);
|
|
52258
52454
|
moved.push(move);
|
|
52259
|
-
syncArchiveDirectory(
|
|
52455
|
+
syncArchiveDirectory(dirname9(move.source));
|
|
52260
52456
|
syncArchiveDirectory(archiveRoot);
|
|
52261
52457
|
verifyArchive(move);
|
|
52262
52458
|
move.status = "archived";
|
|
@@ -52277,7 +52473,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
52277
52473
|
recheckRootAliases(aliases);
|
|
52278
52474
|
assertSafePath(entry.source);
|
|
52279
52475
|
assertSafePath(entry.archive);
|
|
52280
|
-
if (
|
|
52476
|
+
if (lstatSync10(entry.source, { throwIfNoEntry: false })) {
|
|
52281
52477
|
entry.status = "recovery-required";
|
|
52282
52478
|
entry.conflict = "source-occupied";
|
|
52283
52479
|
continue;
|
|
@@ -52291,10 +52487,10 @@ function archiveNativeSkills(inventory, options) {
|
|
|
52291
52487
|
}
|
|
52292
52488
|
if (entry.discoveryOnly) {
|
|
52293
52489
|
linkSync(entry.archive, entry.source);
|
|
52294
|
-
syncArchiveDirectory(
|
|
52490
|
+
syncArchiveDirectory(dirname9(entry.source));
|
|
52295
52491
|
unlinkSync2(entry.archive);
|
|
52296
52492
|
} else {
|
|
52297
|
-
if (
|
|
52493
|
+
if (lstatSync10(entry.source, { throwIfNoEntry: false })) {
|
|
52298
52494
|
entry.status = "recovery-required";
|
|
52299
52495
|
entry.conflict = "source-occupied";
|
|
52300
52496
|
continue;
|
|
@@ -52302,7 +52498,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
52302
52498
|
renameSync3(entry.archive, entry.source);
|
|
52303
52499
|
}
|
|
52304
52500
|
entry.status = "restored";
|
|
52305
|
-
syncArchiveDirectory(
|
|
52501
|
+
syncArchiveDirectory(dirname9(entry.source));
|
|
52306
52502
|
syncArchiveDirectory(archiveRoot);
|
|
52307
52503
|
} catch {
|
|
52308
52504
|
entry.status = "recovery-required";
|
|
@@ -52322,8 +52518,8 @@ function archiveNativeSkills(inventory, options) {
|
|
|
52322
52518
|
return { entries: entries.map(({ status, conflict, ...entry }) => entry), receiptPath, ...aliases.length ? { rootAliases: aliases } : {} };
|
|
52323
52519
|
}
|
|
52324
52520
|
function assertManagedAgentBridge(agent, options = {}) {
|
|
52325
|
-
const home =
|
|
52326
|
-
assertSafePath(
|
|
52521
|
+
const home = resolve9(options.home ?? homedir3()), dataDir3 = options.dataDir ?? getDataDirReadOnly();
|
|
52522
|
+
assertSafePath(join20(dataDir3, "agent-policy.json"));
|
|
52327
52523
|
const snapshot = readManagedSkillPolicySnapshot(dataDir3);
|
|
52328
52524
|
if (!snapshot)
|
|
52329
52525
|
throw new Error("NATIVE_SKILL_DRIFT: install the Skills bridge with skills hook install");
|
|
@@ -52334,16 +52530,16 @@ function assertManagedAgentBridge(agent, options = {}) {
|
|
|
52334
52530
|
if (!Array.isArray(aliases))
|
|
52335
52531
|
throw new Error("NATIVE_SKILL_DRIFT: invalid root alias binding");
|
|
52336
52532
|
recheckRootAliases(aliases);
|
|
52337
|
-
const expected = canonicalAgentPath(
|
|
52533
|
+
const expected = canonicalAgentPath(join20(home, AGENT_ADAPTERS[agent].root, CLI_BRIDGE_NAME), aliases);
|
|
52338
52534
|
if (!isOwnedCliBridge(expected, [expected]))
|
|
52339
52535
|
throw new Error("NATIVE_SKILL_DRIFT: the native Skills bridge is missing or modified; repair it before continuing");
|
|
52340
52536
|
const roots = new Set;
|
|
52341
52537
|
for (const project of [options.projectDir ?? process.cwd(), ...options.projectDirs ?? []]) {
|
|
52342
|
-
for (let path =
|
|
52538
|
+
for (let path = resolve9(project), depth = 0;; depth++) {
|
|
52343
52539
|
if (depth >= 100)
|
|
52344
52540
|
throw new Error("NATIVE_SKILL_DRIFT: project ancestor discovery limit exceeded");
|
|
52345
52541
|
roots.add(path);
|
|
52346
|
-
const parent =
|
|
52542
|
+
const parent = dirname9(path);
|
|
52347
52543
|
if (parent === path)
|
|
52348
52544
|
break;
|
|
52349
52545
|
path = parent;
|
|
@@ -52351,17 +52547,19 @@ function assertManagedAgentBridge(agent, options = {}) {
|
|
|
52351
52547
|
}
|
|
52352
52548
|
const visible = (entry) => entry.agent === agent || ["codex", "gemini", "opencode", "hermes"].includes(agent) && entry.path.includes(`${sep4}.agents${sep4}skills${sep4}`) || agent === "opencode" && entry.agent === "claude";
|
|
52353
52549
|
assertProjectDiscovery(agent, [...roots], home, (path) => canonicalAgentPath(path, aliases));
|
|
52354
|
-
const configPath = canonicalAgentPath(
|
|
52550
|
+
const configPath = canonicalAgentPath(join20(home, AGENT_ADAPTERS[agent].config), aliases), config = agent === "hermes" ? parseHermesConfig(readOptional(configPath)) : jsonObject(readOptional(configPath), configPath);
|
|
52355
52551
|
const command = binding.commands?.[agent], profile = binding.profiles?.[agent];
|
|
52356
52552
|
if (typeof command !== "string" || typeof profile !== "string")
|
|
52357
52553
|
throw new Error("NATIVE_SKILL_DRIFT: the native hook command/profile binding is missing");
|
|
52554
|
+
if (options.profileId !== undefined && options.profileId !== profile)
|
|
52555
|
+
throw new Error("NATIVE_SKILL_DRIFT: the hook selection profile differs from its managed binding; restart the native client after reviewing skills hook install");
|
|
52358
52556
|
if (agent === "hermes") {
|
|
52359
52557
|
const supervisor = binding.supervisors?.hermes;
|
|
52360
|
-
if (supervisor?.path !==
|
|
52558
|
+
if (supervisor?.path !== join20(dataDir3, "agent-hooks", "hermes.js") || supervisor?.sha256 !== sha(renderHermesSupervisor(command, profile)))
|
|
52361
52559
|
throw new Error("NATIVE_SKILL_DRIFT: Hermes supervisor binding changed; run skills hook install");
|
|
52362
52560
|
assertHermesProtection(home, config, command, profile, supervisor);
|
|
52363
52561
|
} else if (agent === "opencode") {
|
|
52364
|
-
if (JSON.stringify(config.permission?.skill) !== JSON.stringify({ "*": "deny", [CLI_BRIDGE_NAME]: "allow" }) || readOptional(
|
|
52562
|
+
if (JSON.stringify(config.permission?.skill) !== JSON.stringify({ "*": "deny", [CLI_BRIDGE_NAME]: "allow" }) || readOptional(join20(home, ".config", "opencode", "plugins", "skills-cli.js")) !== renderOpenCodePlugin(command, profile))
|
|
52365
52563
|
throw new Error("NATIVE_SKILL_DRIFT: OpenCode bridge protection changed; run skills hook install");
|
|
52366
52564
|
} else {
|
|
52367
52565
|
const required = {};
|
|
@@ -52376,13 +52574,13 @@ function assertManagedAgentBridge(agent, options = {}) {
|
|
|
52376
52574
|
if (agent === "gemini" && (config.hooksConfig?.enabled === false || config.skills?.enabled !== true || !["antigravity-support", "skill-creator"].every((name) => config.skills?.disabled?.includes(name)) || config.skills?.disabled?.includes(CLI_BRIDGE_NAME)))
|
|
52377
52575
|
throw new Error("NATIVE_SKILL_DRIFT: Gemini bridge or bundled-skill protection changed; run skills hook install");
|
|
52378
52576
|
}
|
|
52379
|
-
const codexPath = canonicalAgentPath(
|
|
52577
|
+
const codexPath = canonicalAgentPath(join20(home, ".codex", "config.toml"), aliases);
|
|
52380
52578
|
const codexConfig = agent === "codex" ? Bun.TOML.parse(readOptional(codexPath) ?? "") : {};
|
|
52381
|
-
const setting = (path) => (codexConfig.skills?.config ?? []).filter((entry) => typeof entry.path === "string" && [path,
|
|
52579
|
+
const setting = (path) => (codexConfig.skills?.config ?? []).filter((entry) => typeof entry.path === "string" && [path, join20(path, "SKILL.md")].includes(canonicalAgentPath(entry.path, aliases)));
|
|
52382
52580
|
if (agent === "codex" && setting(expected).some((entry) => entry.enabled === false))
|
|
52383
52581
|
throw new Error("NATIVE_SKILL_DRIFT: the Codex CLI bridge is disabled; run skills hook install");
|
|
52384
52582
|
const disabledBuiltin = (entry) => {
|
|
52385
|
-
if (agent !== "codex" || !entry.vendor || !entry.path.startsWith(canonicalAgentPath(
|
|
52583
|
+
if (agent !== "codex" || !entry.vendor || !entry.path.startsWith(canonicalAgentPath(join20(home, ".codex", "skills", ".system"), aliases) + sep4))
|
|
52386
52584
|
return false;
|
|
52387
52585
|
const matched = Array.isArray(binding.disabledBuiltins) && binding.disabledBuiltins.some((item) => item.path === entry.path && item.hash === entry.hash);
|
|
52388
52586
|
const settings = setting(entry.path);
|
|
@@ -52408,12 +52606,30 @@ function assertManagedAgentBridge(agent, options = {}) {
|
|
|
52408
52606
|
throw new Error("NATIVE_SKILL_DRIFT: unexpected native skill copies were found; review skills migrate native --include-unmanaged --include-vendor before continuing");
|
|
52409
52607
|
recheckRootAliases(aliases);
|
|
52410
52608
|
}
|
|
52609
|
+
function normalizeAgentHookPrompt(agent, event, prompt) {
|
|
52610
|
+
if (agent !== "gemini" || event !== "BeforeAgent")
|
|
52611
|
+
return prompt;
|
|
52612
|
+
const prefix = `<hook_context>${SKILLS_LOADING_POLICY}`;
|
|
52613
|
+
if (!prompt.startsWith(prefix))
|
|
52614
|
+
return prompt;
|
|
52615
|
+
const remainder = prompt.slice(prefix.length);
|
|
52616
|
+
const closing = `</hook_context>
|
|
52617
|
+
|
|
52618
|
+
`;
|
|
52619
|
+
if (remainder.startsWith(closing))
|
|
52620
|
+
return remainder.slice(closing.length);
|
|
52621
|
+
if (remainder.startsWith(`
|
|
52622
|
+
|
|
52623
|
+
`) && remainder.includes(closing))
|
|
52624
|
+
return `<hook_context>${remainder.slice(2)}`;
|
|
52625
|
+
return prompt;
|
|
52626
|
+
}
|
|
52411
52627
|
function hookContextOutput(event, result2) {
|
|
52412
52628
|
if (!HOOK_EVENTS.includes(event))
|
|
52413
52629
|
throw new Error(`Unsupported context hook event: ${event}`);
|
|
52414
52630
|
const omitted = result2.omitted?.slice(0, 10).map((entry) => `Additional selected skill ${entry.slug}@${entry.version}: ${entry.loadCommand}`).join(`
|
|
52415
52631
|
`);
|
|
52416
|
-
const policy = event === "SessionStart" || event === "SubagentStart" ?
|
|
52632
|
+
const policy = event === "SessionStart" || event === "SubagentStart" ? SKILLS_LOADING_POLICY : "";
|
|
52417
52633
|
const context = [policy, result2.context, omitted].filter(Boolean).join(`
|
|
52418
52634
|
|
|
52419
52635
|
`);
|
|
@@ -52425,7 +52641,7 @@ function assertNativeExportAllowed(dataDir3 = getDataDirReadOnly()) {
|
|
|
52425
52641
|
if (requiresCliSkillLoading(dataDir3))
|
|
52426
52642
|
throw new Error("NATIVE_SKILL_EXPORT_DISABLED: this station loads skills through the Skills CLI; use skills sync --selection-profile <id>");
|
|
52427
52643
|
}
|
|
52428
|
-
var sha = (data) =>
|
|
52644
|
+
var sha = (data) => createHash8("sha256").update(data).digest("hex"), HOOK_EVENTS, ROOTS, SKILLS_LOADING_POLICY = "Skills loading policy: discover skills with `skills list` or `skills search`, and read selected instructions with `skills load <slug>`. Use `skills sync` to refresh the shared profile. The only native skill is the owned skills-cli bridge. Create and edit payload skills in the Skills authoring workspace; do not copy payload instructions into native discovery folders. Context loading does not authorize execution; use `skills run` only when the task calls for running a skill.";
|
|
52429
52645
|
var init_agent_integration = __esm(() => {
|
|
52430
52646
|
init_config();
|
|
52431
52647
|
init_managed_policy();
|
|
@@ -52455,15 +52671,15 @@ var init_agent_integration = __esm(() => {
|
|
|
52455
52671
|
|
|
52456
52672
|
// src/lib/home-migration.ts
|
|
52457
52673
|
import { existsSync as existsSync15, mkdirSync as mkdirSync6, readdirSync as readdirSync11, renameSync as renameSync4, rmSync as rmSync2, statSync as statSync9, writeFileSync as writeFileSync6 } from "fs";
|
|
52458
|
-
import { join as
|
|
52674
|
+
import { join as join21 } from "path";
|
|
52459
52675
|
function layoutMigrationRecordPath(appDir) {
|
|
52460
|
-
return
|
|
52676
|
+
return join21(appDir, SKILLS_CACHE_DIRNAME, LAYOUT_MIGRATION_RECORD);
|
|
52461
52677
|
}
|
|
52462
52678
|
function resolveCorpusRoot(options = {}) {
|
|
52463
52679
|
return getPortableSkillsRoot(options);
|
|
52464
52680
|
}
|
|
52465
52681
|
function migrationAppDir(homeDir) {
|
|
52466
|
-
return homeDir ?
|
|
52682
|
+
return homeDir ? join21(homeDir, ".hasna", "skills") : getDataDir();
|
|
52467
52683
|
}
|
|
52468
52684
|
function looksLikeSkillDirectory2(path) {
|
|
52469
52685
|
try {
|
|
@@ -52472,7 +52688,7 @@ function looksLikeSkillDirectory2(path) {
|
|
|
52472
52688
|
} catch {
|
|
52473
52689
|
return false;
|
|
52474
52690
|
}
|
|
52475
|
-
return existsSync15(
|
|
52691
|
+
return existsSync15(join21(path, "SKILL.md")) || existsSync15(join21(path, "skill.json")) || existsSync15(join21(path, "package.json"));
|
|
52476
52692
|
}
|
|
52477
52693
|
function listLegacyFlatSkillDirs(appDir) {
|
|
52478
52694
|
const legacy = [];
|
|
@@ -52490,14 +52706,14 @@ function listLegacyFlatSkillDirs(appDir) {
|
|
|
52490
52706
|
if (entry === SKILLS_CACHE_DIRNAME || entry === INSTALLED_SKILLS_DIRNAME || entry === LEGACY_CUSTOM_DIRNAME2 || entry === LOGS_DIRNAME || entry === OUTPUTS_DIRNAME) {
|
|
52491
52707
|
continue;
|
|
52492
52708
|
}
|
|
52493
|
-
if (looksLikeSkillDirectory2(
|
|
52709
|
+
if (looksLikeSkillDirectory2(join21(appDir, entry)))
|
|
52494
52710
|
legacy.push(entry);
|
|
52495
52711
|
}
|
|
52496
52712
|
return legacy;
|
|
52497
52713
|
}
|
|
52498
52714
|
function createLazyDirs(appDir, created) {
|
|
52499
52715
|
for (const name of [LOGS_DIRNAME, OUTPUTS_DIRNAME]) {
|
|
52500
|
-
const dir =
|
|
52716
|
+
const dir = join21(appDir, name);
|
|
52501
52717
|
if (!existsSync15(dir)) {
|
|
52502
52718
|
mkdirSync6(dir, { recursive: true });
|
|
52503
52719
|
created.push(dir);
|
|
@@ -52506,8 +52722,8 @@ function createLazyDirs(appDir, created) {
|
|
|
52506
52722
|
}
|
|
52507
52723
|
function migrateOwnerLayout(options = {}) {
|
|
52508
52724
|
const appDir = migrationAppDir(options.homeDir);
|
|
52509
|
-
const cache3 =
|
|
52510
|
-
const installed =
|
|
52725
|
+
const cache3 = join21(appDir, SKILLS_CACHE_DIRNAME);
|
|
52726
|
+
const installed = join21(appDir, INSTALLED_SKILLS_DIRNAME);
|
|
52511
52727
|
const moved = [];
|
|
52512
52728
|
const created = [];
|
|
52513
52729
|
if (isOwnerLayoutMigrated(appDir)) {
|
|
@@ -52567,7 +52783,7 @@ function migrateOwnerLayout(options = {}) {
|
|
|
52567
52783
|
mkdirSync6(cache3, { recursive: true });
|
|
52568
52784
|
}
|
|
52569
52785
|
for (const name of legacy) {
|
|
52570
|
-
renameSync4(
|
|
52786
|
+
renameSync4(join21(appDir, name), join21(cache3, name));
|
|
52571
52787
|
moved.push(name);
|
|
52572
52788
|
}
|
|
52573
52789
|
createLazyDirs(appDir, created);
|
|
@@ -52592,7 +52808,7 @@ var init_home_migration = __esm(() => {
|
|
|
52592
52808
|
import {
|
|
52593
52809
|
cpSync as cpSync3,
|
|
52594
52810
|
existsSync as existsSync16,
|
|
52595
|
-
lstatSync as
|
|
52811
|
+
lstatSync as lstatSync11,
|
|
52596
52812
|
mkdirSync as mkdirSync7,
|
|
52597
52813
|
mkdtempSync as mkdtempSync2,
|
|
52598
52814
|
readFileSync as readFileSync13,
|
|
@@ -52603,14 +52819,14 @@ import {
|
|
|
52603
52819
|
writeFileSync as writeFileSync7
|
|
52604
52820
|
} from "fs";
|
|
52605
52821
|
import { homedir as homedir4 } from "os";
|
|
52606
|
-
import { basename as basename3, dirname as
|
|
52822
|
+
import { basename as basename3, dirname as dirname10, join as join22 } from "path";
|
|
52607
52823
|
function isSkillsOwnershipMarker(marker) {
|
|
52608
52824
|
return typeof marker === "object" && marker !== null && Object.hasOwn(marker, "managedBy") && marker.managedBy === SYNC_MARKER_MANAGED_BY;
|
|
52609
52825
|
}
|
|
52610
52826
|
function hasSkillsOwnershipMarker(dir) {
|
|
52611
|
-
const path =
|
|
52827
|
+
const path = join22(dir, SYNC_MARKER_FILE);
|
|
52612
52828
|
try {
|
|
52613
|
-
if (!
|
|
52829
|
+
if (!lstatSync11(path).isFile())
|
|
52614
52830
|
return false;
|
|
52615
52831
|
const marker = JSON.parse(readFileSync13(path, "utf8"));
|
|
52616
52832
|
return isSkillsOwnershipMarker(marker);
|
|
@@ -52632,9 +52848,9 @@ function resolveSyncAgents(arg) {
|
|
|
52632
52848
|
function agentGlobalSkillsDir(agent, homeDir = homedir4()) {
|
|
52633
52849
|
switch (agent) {
|
|
52634
52850
|
case "opencode":
|
|
52635
|
-
return
|
|
52851
|
+
return join22(homeDir, ".config", "opencode", "skills");
|
|
52636
52852
|
default:
|
|
52637
|
-
return
|
|
52853
|
+
return join22(homeDir, `.${agent}`, "skills");
|
|
52638
52854
|
}
|
|
52639
52855
|
}
|
|
52640
52856
|
function adaptSkillMdForAgent(skillMd, agent) {
|
|
@@ -52692,7 +52908,7 @@ function resolveSyncCorpus(options = {}) {
|
|
|
52692
52908
|
function packageSourceRoots(source) {
|
|
52693
52909
|
const roots = [];
|
|
52694
52910
|
for (const sub of ["skills"]) {
|
|
52695
|
-
const candidate =
|
|
52911
|
+
const candidate = join22(source, sub);
|
|
52696
52912
|
if (existsSync16(candidate) && isDirectory(candidate))
|
|
52697
52913
|
roots.push(candidate);
|
|
52698
52914
|
}
|
|
@@ -52708,10 +52924,10 @@ function containsSkillDirectories(path) {
|
|
|
52708
52924
|
return false;
|
|
52709
52925
|
}
|
|
52710
52926
|
return entries.some((entry) => {
|
|
52711
|
-
const candidate =
|
|
52927
|
+
const candidate = join22(path, entry);
|
|
52712
52928
|
if (!isDirectory(candidate))
|
|
52713
52929
|
return false;
|
|
52714
|
-
return existsSync16(
|
|
52930
|
+
return existsSync16(join22(candidate, "SKILL.md")) || existsSync16(join22(candidate, "skill.json")) || existsSync16(join22(candidate, "package.json"));
|
|
52715
52931
|
});
|
|
52716
52932
|
}
|
|
52717
52933
|
function isDirectory(path) {
|
|
@@ -52751,7 +52967,7 @@ function syncSkillsToAgents(options = {}) {
|
|
|
52751
52967
|
actions.push({
|
|
52752
52968
|
skill: name,
|
|
52753
52969
|
agent,
|
|
52754
|
-
path:
|
|
52970
|
+
path: join22(agentGlobalSkillsDir(agent, homeDir), name, "SKILL.md"),
|
|
52755
52971
|
action: "skip",
|
|
52756
52972
|
reason: "not found in this machine's corpus"
|
|
52757
52973
|
});
|
|
@@ -52781,7 +52997,7 @@ function syncSkillsToAgents(options = {}) {
|
|
|
52781
52997
|
}
|
|
52782
52998
|
function writeManagedAgentSkill(params) {
|
|
52783
52999
|
const homeDir = params.homeDir ?? homedir4();
|
|
52784
|
-
const dir =
|
|
53000
|
+
const dir = join22(agentGlobalSkillsDir(params.agent, homeDir), params.skill);
|
|
52785
53001
|
const result2 = writeManagedSkillDir(dir, params.skillMd, {
|
|
52786
53002
|
skill: params.skill,
|
|
52787
53003
|
source: params.source,
|
|
@@ -52798,8 +53014,8 @@ function writeManagedAgentSkill(params) {
|
|
|
52798
53014
|
};
|
|
52799
53015
|
}
|
|
52800
53016
|
function writeManagedSkillDir(dir, skillMd, options) {
|
|
52801
|
-
const skillMdPath =
|
|
52802
|
-
const markerPath =
|
|
53017
|
+
const skillMdPath = join22(dir, "SKILL.md");
|
|
53018
|
+
const markerPath = join22(dir, SYNC_MARKER_FILE);
|
|
52803
53019
|
const dirExists = existsSync16(dir);
|
|
52804
53020
|
const managed = hasSkillsOwnershipMarker(dir);
|
|
52805
53021
|
const hasSkillMd = existsSync16(skillMdPath);
|
|
@@ -52835,13 +53051,13 @@ function writeManagedSkillDir(dir, skillMd, options) {
|
|
|
52835
53051
|
const action = dirExists ? "update" : "create";
|
|
52836
53052
|
if (options.dryRun)
|
|
52837
53053
|
return { action, path: skillMdPath };
|
|
52838
|
-
const parentDir =
|
|
53054
|
+
const parentDir = dirname10(dir);
|
|
52839
53055
|
mkdirSync7(parentDir, { recursive: true });
|
|
52840
|
-
const transactionDir = mkdtempSync2(
|
|
52841
|
-
const candidateDir =
|
|
52842
|
-
const backupDir =
|
|
52843
|
-
const candidateSkillMdPath =
|
|
52844
|
-
const candidateMarkerPath =
|
|
53056
|
+
const transactionDir = mkdtempSync2(join22(parentDir, `.hasna-skills-write-${basename3(dir)}-`));
|
|
53057
|
+
const candidateDir = join22(transactionDir, "candidate");
|
|
53058
|
+
const backupDir = join22(transactionDir, "backup");
|
|
53059
|
+
const candidateSkillMdPath = join22(candidateDir, "SKILL.md");
|
|
53060
|
+
const candidateMarkerPath = join22(candidateDir, SYNC_MARKER_FILE);
|
|
52845
53061
|
const marker = {
|
|
52846
53062
|
managedBy: SYNC_MARKER_MANAGED_BY,
|
|
52847
53063
|
skill: options.skill,
|
|
@@ -52891,7 +53107,7 @@ function writeManagedSkillDir(dir, skillMd, options) {
|
|
|
52891
53107
|
}
|
|
52892
53108
|
function sourceSkillMd(skillPath, name, description, kind, preferBundledDocs = false) {
|
|
52893
53109
|
if (kind === undefined || kind === "instruction" || preferBundledDocs) {
|
|
52894
|
-
const skillMdPath =
|
|
53110
|
+
const skillMdPath = join22(skillPath, "SKILL.md");
|
|
52895
53111
|
if (existsSync16(skillMdPath))
|
|
52896
53112
|
return readFileSync13(skillMdPath, "utf-8");
|
|
52897
53113
|
}
|
|
@@ -52931,12 +53147,12 @@ function normalizeSkillName(name) {
|
|
|
52931
53147
|
|
|
52932
53148
|
// src/lib/project-state.ts
|
|
52933
53149
|
import { existsSync as existsSync17, mkdirSync as mkdirSync8, readFileSync as readFileSync14, writeFileSync as writeFileSync8 } from "fs";
|
|
52934
|
-
import { join as
|
|
53150
|
+
import { join as join23 } from "path";
|
|
52935
53151
|
function getProjectStateDir(targetDir = process.cwd()) {
|
|
52936
|
-
return
|
|
53152
|
+
return join23(targetDir, SKILLS_PROJECT_DIR);
|
|
52937
53153
|
}
|
|
52938
53154
|
function getProjectConfigPath(targetDir = process.cwd()) {
|
|
52939
|
-
return
|
|
53155
|
+
return join23(getProjectStateDir(targetDir), PROJECT_CONFIG_FILE);
|
|
52940
53156
|
}
|
|
52941
53157
|
function loadProjectConfig(targetDir = process.cwd()) {
|
|
52942
53158
|
const path = getProjectConfigPath(targetDir);
|
|
@@ -53098,31 +53314,31 @@ __export(exports_installer, {
|
|
|
53098
53314
|
AGENT_LABELS: () => AGENT_LABELS
|
|
53099
53315
|
});
|
|
53100
53316
|
import { existsSync as existsSync18, readFileSync as readFileSync15, rmSync as rmSync4 } from "fs";
|
|
53101
|
-
import { dirname as
|
|
53317
|
+
import { dirname as dirname11, join as join24 } from "path";
|
|
53102
53318
|
import { homedir as homedir5 } from "os";
|
|
53103
53319
|
import { fileURLToPath } from "url";
|
|
53104
53320
|
function findSkillsDir() {
|
|
53105
53321
|
let dir = __dirname2;
|
|
53106
53322
|
for (let i = 0;i < 5; i++) {
|
|
53107
|
-
const candidate =
|
|
53323
|
+
const candidate = join24(dir, "skills");
|
|
53108
53324
|
if (existsSync18(candidate) && !dir.includes(".skills"))
|
|
53109
53325
|
return candidate;
|
|
53110
|
-
dir =
|
|
53326
|
+
dir = dirname11(dir);
|
|
53111
53327
|
}
|
|
53112
|
-
return
|
|
53328
|
+
return join24(__dirname2, "..", "skills");
|
|
53113
53329
|
}
|
|
53114
53330
|
function getSkillPath(name) {
|
|
53115
53331
|
const skillName = normalizeSkillName(getCanonicalSkillName(name));
|
|
53116
53332
|
const portable = findPortableSkill(skillName);
|
|
53117
53333
|
if (portable)
|
|
53118
53334
|
return portable.path;
|
|
53119
|
-
const legacyCustomPath =
|
|
53335
|
+
const legacyCustomPath = join24(getDataDir(), "custom", skillName);
|
|
53120
53336
|
if (existsSync18(legacyCustomPath))
|
|
53121
53337
|
return legacyCustomPath;
|
|
53122
53338
|
const extensionPath = findExtensionSkillPath(skillName);
|
|
53123
53339
|
if (extensionPath)
|
|
53124
53340
|
return extensionPath;
|
|
53125
|
-
return
|
|
53341
|
+
return join24(SKILLS_DIR, skillName);
|
|
53126
53342
|
}
|
|
53127
53343
|
function getCanonicalSkillName(name) {
|
|
53128
53344
|
return getSkill(name)?.name ?? resolveSkillAlias(normalizeSkillSlug(name));
|
|
@@ -53208,7 +53424,7 @@ function createLocalSkillManifest(name, generateSkillMd) {
|
|
|
53208
53424
|
if (!existsSync18(sourcePath))
|
|
53209
53425
|
return null;
|
|
53210
53426
|
let skillMd = "";
|
|
53211
|
-
const skillMdPath =
|
|
53427
|
+
const skillMdPath = join24(sourcePath, "SKILL.md");
|
|
53212
53428
|
if (existsSync18(skillMdPath)) {
|
|
53213
53429
|
skillMd = readFileSync15(skillMdPath, "utf-8");
|
|
53214
53430
|
} else if (generateSkillMd) {
|
|
@@ -53290,16 +53506,16 @@ function getAgentSkillsDir(agent, scope = "global", projectDir) {
|
|
|
53290
53506
|
const base2 = projectDir || process.cwd();
|
|
53291
53507
|
switch (agent) {
|
|
53292
53508
|
case "pi":
|
|
53293
|
-
return scope === "project" ?
|
|
53509
|
+
return scope === "project" ? join24(base2, ".pi", "skills") : join24(homedir5(), ".pi", "agent", "skills");
|
|
53294
53510
|
case "opencode":
|
|
53295
|
-
return scope === "project" ?
|
|
53511
|
+
return scope === "project" ? join24(base2, ".opencode", "skills") : join24(homedir5(), ".config", "opencode", "skills");
|
|
53296
53512
|
default:
|
|
53297
|
-
return scope === "project" ?
|
|
53513
|
+
return scope === "project" ? join24(base2, `.${agent}`, "skills") : join24(homedir5(), `.${agent}`, "skills");
|
|
53298
53514
|
}
|
|
53299
53515
|
}
|
|
53300
53516
|
function getAgentSkillPath(name, agent, scope = "global", projectDir) {
|
|
53301
53517
|
const skillName = normalizeSkillName(getCanonicalSkillName(name));
|
|
53302
|
-
return
|
|
53518
|
+
return join24(getAgentSkillsDir(agent, scope, projectDir), skillName);
|
|
53303
53519
|
}
|
|
53304
53520
|
function installSkillForAgent(name, options, generateSkillMd) {
|
|
53305
53521
|
assertNativeExportAllowed();
|
|
@@ -53335,7 +53551,7 @@ function removeSkillForAgent(name, options) {
|
|
|
53335
53551
|
}
|
|
53336
53552
|
function resolveAgentSkillMd(name, generateSkillMd) {
|
|
53337
53553
|
const sourcePath = getSkillPath(name);
|
|
53338
|
-
const skillMdPath =
|
|
53554
|
+
const skillMdPath = join24(sourcePath, "SKILL.md");
|
|
53339
53555
|
if (existsSync18(skillMdPath))
|
|
53340
53556
|
return readFileSync15(skillMdPath, "utf-8");
|
|
53341
53557
|
if (generateSkillMd)
|
|
@@ -53370,7 +53586,7 @@ function generateMinimalSkillMd(name) {
|
|
|
53370
53586
|
"---",
|
|
53371
53587
|
""
|
|
53372
53588
|
].filter(Boolean);
|
|
53373
|
-
const fallbackDoc = readFileIfExists(
|
|
53589
|
+
const fallbackDoc = readFileIfExists(join24(sourcePath, "README.md")) || readFileIfExists(join24(sourcePath, "CLAUDE.md"));
|
|
53374
53590
|
if (fallbackDoc)
|
|
53375
53591
|
return `${frontmatter.join(`
|
|
53376
53592
|
`)}${fallbackDoc.trim()}
|
|
@@ -53389,7 +53605,7 @@ skills run ${canonicalName}
|
|
|
53389
53605
|
`;
|
|
53390
53606
|
}
|
|
53391
53607
|
function readBundledSkillVersion(name) {
|
|
53392
|
-
const pkgPath =
|
|
53608
|
+
const pkgPath = join24(getSkillPath(name), "package.json");
|
|
53393
53609
|
if (!existsSync18(pkgPath))
|
|
53394
53610
|
return "unknown";
|
|
53395
53611
|
try {
|
|
@@ -53414,7 +53630,7 @@ var init_installer = __esm(() => {
|
|
|
53414
53630
|
init_registry();
|
|
53415
53631
|
init_skill_aliases();
|
|
53416
53632
|
init_project_state();
|
|
53417
|
-
__dirname2 =
|
|
53633
|
+
__dirname2 = dirname11(fileURLToPath(import.meta.url));
|
|
53418
53634
|
SKILLS_DIR = findSkillsDir();
|
|
53419
53635
|
AGENT_TARGETS = ["claude", "codex", "gemini", "pi", "opencode", "cursor", "windsurf"];
|
|
53420
53636
|
AGENT_LABELS = {
|
|
@@ -53518,11 +53734,11 @@ var init_discovery = __esm(() => {
|
|
|
53518
53734
|
// ../contracts/dist/client/transport.js
|
|
53519
53735
|
import { isIP as isIP2 } from "net";
|
|
53520
53736
|
import { spawnSync } from "child_process";
|
|
53521
|
-
import { closeSync as
|
|
53737
|
+
import { closeSync as closeSync5, fstatSync as fstatSync5, openSync as openSync5, readFileSync as readFileSync16 } from "fs";
|
|
53522
53738
|
import { O_NOFOLLOW, O_NONBLOCK, O_RDONLY } from "constants";
|
|
53523
53739
|
import { createRequire as createRequire2 } from "module";
|
|
53524
53740
|
import { hostname as osHostname } from "os";
|
|
53525
|
-
import { isAbsolute as
|
|
53741
|
+
import { isAbsolute as isAbsolute8, join as join25 } from "path";
|
|
53526
53742
|
function envToken(name) {
|
|
53527
53743
|
return name.toUpperCase().replace(/-/g, "_");
|
|
53528
53744
|
}
|
|
@@ -53545,21 +53761,21 @@ function homeDir(env3) {
|
|
|
53545
53761
|
}
|
|
53546
53762
|
function absoluteOverride(env3, key) {
|
|
53547
53763
|
const value = env3[key]?.trim();
|
|
53548
|
-
return value &&
|
|
53764
|
+
return value && isAbsolute8(value) ? value : null;
|
|
53549
53765
|
}
|
|
53550
53766
|
function hasnaHomeDir(env3) {
|
|
53551
53767
|
const override = absoluteOverride(env3, HASNA_HOME_ENV_KEY);
|
|
53552
53768
|
if (override)
|
|
53553
53769
|
return override;
|
|
53554
53770
|
const home = homeDir(env3);
|
|
53555
|
-
return home ?
|
|
53771
|
+
return home ? join25(home, HASNA_HOME_DIR) : null;
|
|
53556
53772
|
}
|
|
53557
53773
|
function appConfigDir(name, env3) {
|
|
53558
53774
|
const configRoot = absoluteOverride(env3, HASNA_CONFIG_HOME_ENV_KEY);
|
|
53559
53775
|
if (configRoot)
|
|
53560
|
-
return
|
|
53776
|
+
return join25(configRoot, name);
|
|
53561
53777
|
const root = hasnaHomeDir(env3);
|
|
53562
|
-
return root ?
|
|
53778
|
+
return root ? join25(root, name, CONFIG_SUBDIR) : null;
|
|
53563
53779
|
}
|
|
53564
53780
|
function credentialDiskSourceList(name, env3, profile = null) {
|
|
53565
53781
|
if (!SAFE_APP_SLUG.test(name))
|
|
@@ -53568,7 +53784,7 @@ function credentialDiskSourceList(name, env3, profile = null) {
|
|
|
53568
53784
|
if (!directory)
|
|
53569
53785
|
return [];
|
|
53570
53786
|
const file = profile ? `${CREDENTIALS_FILE}-${profile}` : CREDENTIALS_FILE;
|
|
53571
|
-
return [{ path:
|
|
53787
|
+
return [{ path: join25(directory, file), tier: "disk" }];
|
|
53572
53788
|
}
|
|
53573
53789
|
function credentialDiskSources(name, env3) {
|
|
53574
53790
|
return credentialDiskSourceList(name, env3, null).map((s) => s.path);
|
|
@@ -53622,7 +53838,7 @@ function readAppConfigFile(path) {
|
|
|
53622
53838
|
};
|
|
53623
53839
|
let fd = -1;
|
|
53624
53840
|
try {
|
|
53625
|
-
fd =
|
|
53841
|
+
fd = openSync5(path, O_RDONLY | O_NOFOLLOW | O_NONBLOCK);
|
|
53626
53842
|
} catch (error) {
|
|
53627
53843
|
const code = error.code;
|
|
53628
53844
|
if (code === "ENOENT" || code === "ENOTDIR")
|
|
@@ -53632,7 +53848,7 @@ function readAppConfigFile(path) {
|
|
|
53632
53848
|
unsafe(`the path could not be opened (${code ?? "unknown error"})`);
|
|
53633
53849
|
}
|
|
53634
53850
|
try {
|
|
53635
|
-
const before2 =
|
|
53851
|
+
const before2 = fstatSync5(fd);
|
|
53636
53852
|
if (!before2.isFile())
|
|
53637
53853
|
unsafe("the path is not a regular file");
|
|
53638
53854
|
if (!configFileModeAllowed(before2.mode)) {
|
|
@@ -53644,14 +53860,14 @@ function readAppConfigFile(path) {
|
|
|
53644
53860
|
if (before2.size > MAX_CREDENTIAL_FILE_BYTES2)
|
|
53645
53861
|
unsafe("the file exceeds the size limit");
|
|
53646
53862
|
const bytes = readFileSync16(fd);
|
|
53647
|
-
const after2 =
|
|
53863
|
+
const after2 = fstatSync5(fd);
|
|
53648
53864
|
if (!configFileReadsCoherent(before2, after2)) {
|
|
53649
53865
|
unsafe("the file changed while being read");
|
|
53650
53866
|
}
|
|
53651
53867
|
return parseEnvFile(bytes.toString("utf8"));
|
|
53652
53868
|
} finally {
|
|
53653
53869
|
if (fd !== -1)
|
|
53654
|
-
|
|
53870
|
+
closeSync5(fd);
|
|
53655
53871
|
}
|
|
53656
53872
|
}
|
|
53657
53873
|
function readCredentialFile(path, apiKeyKeys) {
|
|
@@ -54191,7 +54407,7 @@ var init_transport = __esm(() => {
|
|
|
54191
54407
|
});
|
|
54192
54408
|
|
|
54193
54409
|
// src/lib/instance-credentials.ts
|
|
54194
|
-
import { closeSync as
|
|
54410
|
+
import { closeSync as closeSync6, constants as constants6, fstatSync as fstatSync6, lstatSync as lstatSync12, openSync as openSync6, readSync as readSync5 } from "fs";
|
|
54195
54411
|
function selectedSkillsProfile(env3, explicit) {
|
|
54196
54412
|
const selected = explicit ?? env3.HASNA_PROFILE;
|
|
54197
54413
|
if (selected === undefined)
|
|
@@ -54206,7 +54422,7 @@ function skillsProfileCredentialFiles(env3, explicit) {
|
|
|
54206
54422
|
}
|
|
54207
54423
|
function fileIdentity(file) {
|
|
54208
54424
|
try {
|
|
54209
|
-
return
|
|
54425
|
+
return lstatSync12(file);
|
|
54210
54426
|
} catch (error) {
|
|
54211
54427
|
if (["ENOENT", "ENOTDIR"].includes(error.code ?? ""))
|
|
54212
54428
|
return null;
|
|
@@ -54227,14 +54443,14 @@ function captureSkillsCredentialFiles(files) {
|
|
|
54227
54443
|
function readMetadataText(file) {
|
|
54228
54444
|
let fd;
|
|
54229
54445
|
try {
|
|
54230
|
-
fd =
|
|
54446
|
+
fd = openSync6(file, constants6.O_RDONLY | constants6.O_NOFOLLOW | constants6.O_NONBLOCK);
|
|
54231
54447
|
} catch (error) {
|
|
54232
54448
|
if (["ENOENT", "ENOTDIR"].includes(error.code ?? ""))
|
|
54233
54449
|
return null;
|
|
54234
54450
|
throw new Error("Cannot safely read Skills instance configuration");
|
|
54235
54451
|
}
|
|
54236
54452
|
try {
|
|
54237
|
-
const before2 =
|
|
54453
|
+
const before2 = fstatSync6(fd);
|
|
54238
54454
|
const uid = process.getuid?.() ?? process.geteuid?.();
|
|
54239
54455
|
if (!before2.isFile() || ![256, 384].includes(before2.mode & 4095) || uid !== undefined && before2.uid !== uid || before2.size > 64 * 1024) {
|
|
54240
54456
|
throw new Error("Unsafe Skills instance configuration; expected a bounded owner-only regular file");
|
|
@@ -54242,17 +54458,17 @@ function readMetadataText(file) {
|
|
|
54242
54458
|
const bytes = Buffer.alloc(64 * 1024 + 1);
|
|
54243
54459
|
let length = 0;
|
|
54244
54460
|
while (length < bytes.length) {
|
|
54245
|
-
const count =
|
|
54461
|
+
const count = readSync5(fd, bytes, length, bytes.length - length, null);
|
|
54246
54462
|
if (!count)
|
|
54247
54463
|
break;
|
|
54248
54464
|
length += count;
|
|
54249
54465
|
}
|
|
54250
|
-
if (length > 64 * 1024 || !unchanged(before2,
|
|
54466
|
+
if (length > 64 * 1024 || !unchanged(before2, fstatSync6(fd)) || !unchanged(before2, fileIdentity(file))) {
|
|
54251
54467
|
throw new Error("Skills instance configuration changed while reading");
|
|
54252
54468
|
}
|
|
54253
54469
|
return bytes.subarray(0, length).toString("utf8");
|
|
54254
54470
|
} finally {
|
|
54255
|
-
|
|
54471
|
+
closeSync6(fd);
|
|
54256
54472
|
}
|
|
54257
54473
|
}
|
|
54258
54474
|
function readSkillsInstanceMetadata(file) {
|
|
@@ -59215,13 +59431,13 @@ var init_remote_workspace_leave = __esm(() => {
|
|
|
59215
59431
|
|
|
59216
59432
|
// src/lib/auth-store.ts
|
|
59217
59433
|
import { chmodSync as chmodSync2, existsSync as existsSync19, mkdirSync as mkdirSync9, readFileSync as readFileSync17, renameSync as renameSync6, statSync as statSync11, unlinkSync as unlinkSync3, writeFileSync as writeFileSync9 } from "fs";
|
|
59218
|
-
import { basename as basename4, dirname as
|
|
59434
|
+
import { basename as basename4, dirname as dirname12, join as join26 } from "path";
|
|
59219
59435
|
function getAuthFilePath(env3 = process.env) {
|
|
59220
59436
|
return skillsCredentialFilePath(env3);
|
|
59221
59437
|
}
|
|
59222
59438
|
function getIdentityFilePath(env3 = process.env) {
|
|
59223
59439
|
const file = skillsCredentialFilePath(env3);
|
|
59224
|
-
return
|
|
59440
|
+
return join26(dirname12(file), basename4(file).replace(/^credentials/, "identity") + ".json");
|
|
59225
59441
|
}
|
|
59226
59442
|
function getAuthIdentity(env3 = process.env) {
|
|
59227
59443
|
return readIdentity(env3);
|
|
@@ -59255,7 +59471,7 @@ function getAuthConfig(env3 = process.env, options = {}) {
|
|
|
59255
59471
|
}
|
|
59256
59472
|
function writeCredentialValues(values2, env3 = process.env) {
|
|
59257
59473
|
const file = skillsCredentialFilePath(env3);
|
|
59258
|
-
mkdirSync9(
|
|
59474
|
+
mkdirSync9(dirname12(file), { recursive: true, mode: 448 });
|
|
59259
59475
|
const lines = [];
|
|
59260
59476
|
const written = new Set;
|
|
59261
59477
|
if (existsSync19(file)) {
|
|
@@ -59526,7 +59742,7 @@ __export(exports_remote_files, {
|
|
|
59526
59742
|
decodeRemoteFiles: () => decodeRemoteFiles,
|
|
59527
59743
|
MAX_REMOTE_FILE_BYTES: () => MAX_REMOTE_FILE_BYTES
|
|
59528
59744
|
});
|
|
59529
|
-
import { createHash as
|
|
59745
|
+
import { createHash as createHash9 } from "crypto";
|
|
59530
59746
|
function describeRemoteFiles(files) {
|
|
59531
59747
|
if (files.length > 10)
|
|
59532
59748
|
throw new Error("At most 10 input files are supported");
|
|
@@ -59543,7 +59759,7 @@ function describeRemoteFiles(files) {
|
|
|
59543
59759
|
});
|
|
59544
59760
|
}
|
|
59545
59761
|
function sha256(bytes) {
|
|
59546
|
-
return
|
|
59762
|
+
return createHash9("sha256").update(bytes).digest("hex");
|
|
59547
59763
|
}
|
|
59548
59764
|
async function readBoundedResponse(response, maximum) {
|
|
59549
59765
|
if (!Number.isSafeInteger(maximum) || maximum < 0 || maximum > MAX_REMOTE_FILE_BYTES)
|
|
@@ -59646,10 +59862,10 @@ async function readQuoteUnavailableCode(response) {
|
|
|
59646
59862
|
let timer;
|
|
59647
59863
|
let deadlineExceeded = false;
|
|
59648
59864
|
const expired = Symbol("quote body deadline");
|
|
59649
|
-
const deadline = new Promise((
|
|
59865
|
+
const deadline = new Promise((resolve10) => {
|
|
59650
59866
|
timer = setTimeout(() => {
|
|
59651
59867
|
deadlineExceeded = true;
|
|
59652
|
-
|
|
59868
|
+
resolve10(expired);
|
|
59653
59869
|
reader.cancel().catch(() => {});
|
|
59654
59870
|
}, 1500);
|
|
59655
59871
|
});
|
|
@@ -60497,7 +60713,7 @@ var init_remote_client = __esm(() => {
|
|
|
60497
60713
|
});
|
|
60498
60714
|
|
|
60499
60715
|
// src/lib/revision.ts
|
|
60500
|
-
import { createHash as
|
|
60716
|
+
import { createHash as createHash10 } from "crypto";
|
|
60501
60717
|
function revisionIdOf(content) {
|
|
60502
60718
|
const canonical = JSON.stringify({
|
|
60503
60719
|
slug: content.slug,
|
|
@@ -60512,7 +60728,7 @@ function revisionIdOf(content) {
|
|
|
60512
60728
|
bundleSha256: content.bundleSha256 ?? null,
|
|
60513
60729
|
bundleByteSize: content.bundleByteSize ?? null
|
|
60514
60730
|
});
|
|
60515
|
-
return
|
|
60731
|
+
return createHash10("sha256").update(canonical).digest("hex");
|
|
60516
60732
|
}
|
|
60517
60733
|
var REVISION_ID_PATTERN;
|
|
60518
60734
|
var init_revision = __esm(() => {
|
|
@@ -60542,7 +60758,7 @@ var init_skill_bundles = __esm(() => {
|
|
|
60542
60758
|
|
|
60543
60759
|
// src/lib/pull.ts
|
|
60544
60760
|
import { existsSync as existsSync20, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync3, readFileSync as readFileSync18, renameSync as renameSync7, rmSync as rmSync5, writeFileSync as writeFileSync10 } from "fs";
|
|
60545
|
-
import { dirname as
|
|
60761
|
+
import { dirname as dirname13, join as join27 } from "path";
|
|
60546
60762
|
async function pullSkills(options = {}) {
|
|
60547
60763
|
const client = options.client !== undefined ? options.client : await createRemoteSkillsClient();
|
|
60548
60764
|
if (!client) {
|
|
@@ -60598,7 +60814,7 @@ async function pullOne(client, rawName, corpusOptions, verify) {
|
|
|
60598
60814
|
return reconcileTombstone(slug, corpusOptions);
|
|
60599
60815
|
}
|
|
60600
60816
|
if (bundleResponse.status === 404) {
|
|
60601
|
-
const marker = readPullMarker(
|
|
60817
|
+
const marker = readPullMarker(join27(getPortableSkillsRoot(corpusOptions), slug));
|
|
60602
60818
|
if (isPublishedInstallMarker(marker)) {
|
|
60603
60819
|
return { name: slug, success: true, purged: true, removed: false };
|
|
60604
60820
|
}
|
|
@@ -60637,7 +60853,7 @@ async function pullOne(client, rawName, corpusOptions, verify) {
|
|
|
60637
60853
|
return { name: slug, success: false, error: `Skill '${slug}' was not found on the configured Skills instance.` };
|
|
60638
60854
|
}
|
|
60639
60855
|
if (!meta?.revisionId) {
|
|
60640
|
-
const marker = readPullMarker(
|
|
60856
|
+
const marker = readPullMarker(join27(getPortableSkillsRoot(corpusOptions), slug));
|
|
60641
60857
|
if (isPublishedInstallMarker(marker)) {
|
|
60642
60858
|
return { name: slug, success: true, purged: true, removed: false };
|
|
60643
60859
|
}
|
|
@@ -60694,7 +60910,7 @@ function provenRevision(meta, slug, bundle) {
|
|
|
60694
60910
|
return declared;
|
|
60695
60911
|
}
|
|
60696
60912
|
function reconcileTombstone(slug, corpusOptions) {
|
|
60697
|
-
const target =
|
|
60913
|
+
const target = join27(getPortableSkillsRoot(corpusOptions), slug);
|
|
60698
60914
|
if (!hasSkillsOwnershipMarker(target)) {
|
|
60699
60915
|
return { name: slug, success: true, tombstoned: true, removed: false, leftInPlace: true };
|
|
60700
60916
|
}
|
|
@@ -60703,7 +60919,7 @@ function reconcileTombstone(slug, corpusOptions) {
|
|
|
60703
60919
|
}
|
|
60704
60920
|
function readPullMarker(dir) {
|
|
60705
60921
|
try {
|
|
60706
|
-
return JSON.parse(readFileSync18(
|
|
60922
|
+
return JSON.parse(readFileSync18(join27(dir, PULL_MARKER_FILE), "utf-8"));
|
|
60707
60923
|
} catch {
|
|
60708
60924
|
return null;
|
|
60709
60925
|
}
|
|
@@ -60838,15 +61054,15 @@ function verifyBundleResponseBytes(buffer, response, verify = {}) {
|
|
|
60838
61054
|
function installBundleAtomically(name, entries, options = {}, marker = {}) {
|
|
60839
61055
|
const root = getPortableSkillsRoot(options);
|
|
60840
61056
|
mkdirSync10(root, { recursive: true });
|
|
60841
|
-
const target =
|
|
61057
|
+
const target = join27(root, name);
|
|
60842
61058
|
const created = !existsSync20(target);
|
|
60843
|
-
const staging = mkdtempSync3(
|
|
61059
|
+
const staging = mkdtempSync3(join27(root, `.pull-${name}-`));
|
|
60844
61060
|
let moved = false;
|
|
60845
61061
|
let backup = null;
|
|
60846
61062
|
try {
|
|
60847
61063
|
for (const entry of entries) {
|
|
60848
|
-
const destination =
|
|
60849
|
-
mkdirSync10(
|
|
61064
|
+
const destination = join27(staging, entry.path);
|
|
61065
|
+
mkdirSync10(dirname13(destination), { recursive: true });
|
|
60850
61066
|
writeFileSync10(destination, entry.bytes, { mode: entry.mode });
|
|
60851
61067
|
}
|
|
60852
61068
|
writePullMarker(staging, {
|
|
@@ -60858,8 +61074,8 @@ function installBundleAtomically(name, entries, options = {}, marker = {}) {
|
|
|
60858
61074
|
...marker.revisionId ? { revisionId: marker.revisionId } : {}
|
|
60859
61075
|
});
|
|
60860
61076
|
if (existsSync20(target)) {
|
|
60861
|
-
backup = mkdtempSync3(
|
|
60862
|
-
renameSync7(target,
|
|
61077
|
+
backup = mkdtempSync3(join27(root, `.pull-backup-${name}-`));
|
|
61078
|
+
renameSync7(target, join27(backup, name));
|
|
60863
61079
|
moved = true;
|
|
60864
61080
|
}
|
|
60865
61081
|
renameSync7(staging, target);
|
|
@@ -60867,9 +61083,9 @@ function installBundleAtomically(name, entries, options = {}, marker = {}) {
|
|
|
60867
61083
|
rmSync5(backup, { recursive: true, force: true });
|
|
60868
61084
|
} catch (error) {
|
|
60869
61085
|
rmSync5(staging, { recursive: true, force: true });
|
|
60870
|
-
if (moved && backup && existsSync20(
|
|
61086
|
+
if (moved && backup && existsSync20(join27(backup, name))) {
|
|
60871
61087
|
try {
|
|
60872
|
-
renameSync7(
|
|
61088
|
+
renameSync7(join27(backup, name), target);
|
|
60873
61089
|
} catch {}
|
|
60874
61090
|
}
|
|
60875
61091
|
throw error;
|
|
@@ -60888,7 +61104,7 @@ function writePullMarker(dir, record5) {
|
|
|
60888
61104
|
...record5.revisionId ? { revisionId: record5.revisionId } : {},
|
|
60889
61105
|
syncedAt: new Date().toISOString()
|
|
60890
61106
|
};
|
|
60891
|
-
writeFileSync10(
|
|
61107
|
+
writeFileSync10(join27(dir, PULL_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
|
|
60892
61108
|
`);
|
|
60893
61109
|
}
|
|
60894
61110
|
async function safeMeta(client, slug) {
|
|
@@ -61135,19 +61351,19 @@ function capturePreparationProcess(child, platform2 = process.platform, signalGr
|
|
|
61135
61351
|
}
|
|
61136
61352
|
|
|
61137
61353
|
// src/lib/dependency-preparation.ts
|
|
61138
|
-
import { constants as
|
|
61139
|
-
import { join as
|
|
61354
|
+
import { constants as constants7, closeSync as closeSync7, fstatSync as fstatSync7, lstatSync as lstatSync13, mkdirSync as mkdirSync11, openSync as openSync7, readFileSync as readFileSync19, readdirSync as readdirSync13, rmdirSync as rmdirSync2, unlinkSync as unlinkSync4, ftruncateSync, writeSync } from "fs";
|
|
61355
|
+
import { join as join28 } from "path";
|
|
61140
61356
|
function hasDependencyPreparationMarker(skillPath) {
|
|
61141
61357
|
try {
|
|
61142
|
-
|
|
61358
|
+
lstatSync13(join28(skillPath, DEPENDENCY_PREPARATION_MARKER));
|
|
61143
61359
|
return true;
|
|
61144
61360
|
} catch (error) {
|
|
61145
61361
|
return error.code !== "ENOENT";
|
|
61146
61362
|
}
|
|
61147
61363
|
}
|
|
61148
61364
|
function claimPreparation(skillPath) {
|
|
61149
|
-
const marker =
|
|
61150
|
-
const state =
|
|
61365
|
+
const marker = join28(skillPath, DEPENDENCY_PREPARATION_MARKER);
|
|
61366
|
+
const state = join28(marker, "state.json"), active = join28(marker, "active");
|
|
61151
61367
|
let created = false;
|
|
61152
61368
|
try {
|
|
61153
61369
|
mkdirSync11(marker, { mode: 448 });
|
|
@@ -61158,21 +61374,21 @@ function claimPreparation(skillPath) {
|
|
|
61158
61374
|
}
|
|
61159
61375
|
let fd;
|
|
61160
61376
|
try {
|
|
61161
|
-
if (!
|
|
61377
|
+
if (!lstatSync13(marker).isDirectory() || lstatSync13(marker).isSymbolicLink())
|
|
61162
61378
|
return;
|
|
61163
61379
|
if (!created) {
|
|
61164
61380
|
if (readdirSync13(marker).some((name) => name !== "state.json"))
|
|
61165
61381
|
return;
|
|
61166
|
-
if (!
|
|
61382
|
+
if (!lstatSync13(state).isFile() || lstatSync13(state).isSymbolicLink() || lstatSync13(state).size > 1024)
|
|
61167
61383
|
return;
|
|
61168
61384
|
const previous = JSON.parse(readFileSync19(state, "utf8"));
|
|
61169
61385
|
if (previous.version !== 1 || previous.status !== "failed" || Object.keys(previous).length !== 2)
|
|
61170
61386
|
return;
|
|
61171
61387
|
}
|
|
61172
61388
|
mkdirSync11(active, { mode: 448 });
|
|
61173
|
-
fd =
|
|
61174
|
-
if (!
|
|
61175
|
-
|
|
61389
|
+
fd = openSync7(state, constants7.O_RDWR | constants7.O_NOFOLLOW | (created ? constants7.O_CREAT | constants7.O_EXCL : 0), 384);
|
|
61390
|
+
if (!fstatSync7(fd).isFile()) {
|
|
61391
|
+
closeSync7(fd);
|
|
61176
61392
|
return;
|
|
61177
61393
|
}
|
|
61178
61394
|
const descriptor = fd;
|
|
@@ -61184,7 +61400,7 @@ function claimPreparation(skillPath) {
|
|
|
61184
61400
|
record5("pending");
|
|
61185
61401
|
return { abandon() {
|
|
61186
61402
|
try {
|
|
61187
|
-
|
|
61403
|
+
closeSync7(descriptor);
|
|
61188
61404
|
} catch {}
|
|
61189
61405
|
}, finish(success) {
|
|
61190
61406
|
try {
|
|
@@ -61192,7 +61408,7 @@ function claimPreparation(skillPath) {
|
|
|
61192
61408
|
unlinkSync4(state);
|
|
61193
61409
|
else
|
|
61194
61410
|
record5("failed");
|
|
61195
|
-
|
|
61411
|
+
closeSync7(descriptor);
|
|
61196
61412
|
fd = undefined;
|
|
61197
61413
|
rmdirSync2(active);
|
|
61198
61414
|
if (success)
|
|
@@ -61200,7 +61416,7 @@ function claimPreparation(skillPath) {
|
|
|
61200
61416
|
return true;
|
|
61201
61417
|
} catch {
|
|
61202
61418
|
try {
|
|
61203
|
-
|
|
61419
|
+
closeSync7(descriptor);
|
|
61204
61420
|
} catch {}
|
|
61205
61421
|
return false;
|
|
61206
61422
|
}
|
|
@@ -61208,7 +61424,7 @@ function claimPreparation(skillPath) {
|
|
|
61208
61424
|
} catch {
|
|
61209
61425
|
if (fd !== undefined)
|
|
61210
61426
|
try {
|
|
61211
|
-
|
|
61427
|
+
closeSync7(fd);
|
|
61212
61428
|
} catch {}
|
|
61213
61429
|
return;
|
|
61214
61430
|
}
|
|
@@ -61312,11 +61528,11 @@ __export(exports_skillinfo, {
|
|
|
61312
61528
|
detectProjectSkills: () => detectProjectSkills
|
|
61313
61529
|
});
|
|
61314
61530
|
import { existsSync as existsSync21, readFileSync as readFileSync20 } from "fs";
|
|
61315
|
-
import { join as
|
|
61531
|
+
import { join as join29 } from "path";
|
|
61316
61532
|
function isInstructionSkillDir(skillPath, meta) {
|
|
61317
61533
|
if (meta?.kind === "instruction")
|
|
61318
61534
|
return true;
|
|
61319
|
-
const skillMdPath =
|
|
61535
|
+
const skillMdPath = join29(skillPath, "SKILL.md");
|
|
61320
61536
|
if (!existsSync21(skillMdPath))
|
|
61321
61537
|
return false;
|
|
61322
61538
|
try {
|
|
@@ -61330,9 +61546,9 @@ function getSkillDocs(name) {
|
|
|
61330
61546
|
if (!existsSync21(skillPath))
|
|
61331
61547
|
return null;
|
|
61332
61548
|
return {
|
|
61333
|
-
skillMd: readIfExists(
|
|
61334
|
-
readme: readIfExists(
|
|
61335
|
-
claudeMd: readIfExists(
|
|
61549
|
+
skillMd: readIfExists(join29(skillPath, "SKILL.md")),
|
|
61550
|
+
readme: readIfExists(join29(skillPath, "README.md")),
|
|
61551
|
+
claudeMd: readIfExists(join29(skillPath, "CLAUDE.md"))
|
|
61336
61552
|
};
|
|
61337
61553
|
}
|
|
61338
61554
|
function getSkillBestDoc(name) {
|
|
@@ -61347,14 +61563,14 @@ function getSkillRequirements(name) {
|
|
|
61347
61563
|
return null;
|
|
61348
61564
|
const texts = [];
|
|
61349
61565
|
for (const file of ["SKILL.md", "README.md", "CLAUDE.md", ".env.example", ".env.local.example"]) {
|
|
61350
|
-
const content = readIfExists(
|
|
61566
|
+
const content = readIfExists(join29(skillPath, file));
|
|
61351
61567
|
if (content)
|
|
61352
61568
|
texts.push(content);
|
|
61353
61569
|
}
|
|
61354
61570
|
const meta = getSkill(name);
|
|
61355
61571
|
let dependencies = {};
|
|
61356
61572
|
try {
|
|
61357
|
-
dependencies = JSON.parse(readFileSync20(
|
|
61573
|
+
dependencies = JSON.parse(readFileSync20(join29(skillPath, "package.json"), "utf8")).dependencies || {};
|
|
61358
61574
|
} catch {}
|
|
61359
61575
|
return getSkillRequirementsFromContent(name, texts, dependencies, meta);
|
|
61360
61576
|
}
|
|
@@ -61406,9 +61622,9 @@ function isHostedPremiumSkill(skillName, meta) {
|
|
|
61406
61622
|
function isPackageResolvable(pkgName, fromDir) {
|
|
61407
61623
|
let dir = fromDir;
|
|
61408
61624
|
while (true) {
|
|
61409
|
-
if (existsSync21(
|
|
61625
|
+
if (existsSync21(join29(dir, "node_modules", pkgName, "package.json")))
|
|
61410
61626
|
return true;
|
|
61411
|
-
const parent =
|
|
61627
|
+
const parent = join29(dir, "..");
|
|
61412
61628
|
if (parent === dir)
|
|
61413
61629
|
return false;
|
|
61414
61630
|
dir = parent;
|
|
@@ -61437,7 +61653,7 @@ async function runSkill(name, args, options = {}) {
|
|
|
61437
61653
|
error: `Skill '${name}' is an instruction skill (kind: instruction) and is not runnable. Instruction skills are consumed by coding agents via SKILL.md, not executed with 'skills run'.`
|
|
61438
61654
|
};
|
|
61439
61655
|
}
|
|
61440
|
-
const pkgPath =
|
|
61656
|
+
const pkgPath = join29(skillPath, "package.json");
|
|
61441
61657
|
if (!existsSync21(pkgPath)) {
|
|
61442
61658
|
return { exitCode: 1, error: `No package.json in skill '${name}'` };
|
|
61443
61659
|
}
|
|
@@ -61457,12 +61673,12 @@ async function runSkill(name, args, options = {}) {
|
|
|
61457
61673
|
} catch {
|
|
61458
61674
|
return { exitCode: 1, error: `Failed to parse package.json for skill '${name}'` };
|
|
61459
61675
|
}
|
|
61460
|
-
const entryPath =
|
|
61676
|
+
const entryPath = join29(skillPath, entryPoint);
|
|
61461
61677
|
if (!existsSync21(entryPath)) {
|
|
61462
61678
|
return { exitCode: 1, error: `Entry point '${entryPoint}' not found in skill '${name}'` };
|
|
61463
61679
|
}
|
|
61464
61680
|
const env3 = { ...process.env, ...options.env };
|
|
61465
|
-
if (!existsSync21(
|
|
61681
|
+
if (!existsSync21(join29(skillPath, "node_modules")) || hasDependencyPreparationMarker(skillPath)) {
|
|
61466
61682
|
const failure = await prepareSkillDependencies(skillPath, env3, options.preparationTimeoutMs);
|
|
61467
61683
|
if (failure)
|
|
61468
61684
|
return failure;
|
|
@@ -61486,7 +61702,7 @@ async function runSkill(name, args, options = {}) {
|
|
|
61486
61702
|
return { exitCode };
|
|
61487
61703
|
}
|
|
61488
61704
|
function detectProjectSkills(cwd2 = process.cwd()) {
|
|
61489
|
-
const pkgPath =
|
|
61705
|
+
const pkgPath = join29(cwd2, "package.json");
|
|
61490
61706
|
if (!existsSync21(pkgPath)) {
|
|
61491
61707
|
const alwaysRecommend = ["market-research-report", "repo-onboarding-report", "blog-article"];
|
|
61492
61708
|
const recommended2 = alwaysRecommend.map((name) => loadRegistry().find((s) => s.name === name)).filter((s) => s !== undefined);
|
|
@@ -61623,10 +61839,10 @@ function generateSkillMd(name) {
|
|
|
61623
61839
|
"---"
|
|
61624
61840
|
].join(`
|
|
61625
61841
|
`);
|
|
61626
|
-
const readme = readIfExists(
|
|
61627
|
-
const claudeMd = readIfExists(
|
|
61842
|
+
const readme = readIfExists(join29(skillPath, "README.md"));
|
|
61843
|
+
const claudeMd = readIfExists(join29(skillPath, "CLAUDE.md"));
|
|
61628
61844
|
let cliCommand = null;
|
|
61629
|
-
const pkgPath =
|
|
61845
|
+
const pkgPath = join29(skillPath, "package.json");
|
|
61630
61846
|
if (existsSync21(pkgPath)) {
|
|
61631
61847
|
try {
|
|
61632
61848
|
const pkg = JSON.parse(readFileSync20(pkgPath, "utf-8"));
|
|
@@ -61899,8 +62115,8 @@ var init_selection_resolver = __esm(() => {
|
|
|
61899
62115
|
});
|
|
61900
62116
|
|
|
61901
62117
|
// src/lib/skill-context.ts
|
|
61902
|
-
import { createHash as
|
|
61903
|
-
import { resolve as
|
|
62118
|
+
import { createHash as createHash11 } from "crypto";
|
|
62119
|
+
import { resolve as resolve10 } from "path";
|
|
61904
62120
|
function words2(value) {
|
|
61905
62121
|
return new Set(value.toLowerCase().match(/[a-z0-9]+/g) ?? []);
|
|
61906
62122
|
}
|
|
@@ -61934,7 +62150,7 @@ async function buildSkillContext(input, options = {}) {
|
|
|
61934
62150
|
}
|
|
61935
62151
|
const promptWords = words2(prompt);
|
|
61936
62152
|
const loaded = new Set(resolved.session?.loaded ?? []);
|
|
61937
|
-
const paths = [...input.paths ?? [], ...input.cwd ? [input.cwd,
|
|
62153
|
+
const paths = [...input.paths ?? [], ...input.cwd ? [input.cwd, resolve10(input.cwd)] : []];
|
|
61938
62154
|
const candidates = profile.selections.map((selection) => {
|
|
61939
62155
|
const key = selectionKey(selection);
|
|
61940
62156
|
if (input.restore && loaded.has(key))
|
|
@@ -61986,7 +62202,7 @@ ${content}`;
|
|
|
61986
62202
|
`);
|
|
61987
62203
|
const receipt = {
|
|
61988
62204
|
schemaVersion: 1,
|
|
61989
|
-
id:
|
|
62205
|
+
id: createHash11("sha256").update(JSON.stringify({ profile: profile.profileRevision, sessionId, selections, omitted })).digest("hex"),
|
|
61990
62206
|
profileId: profile.profileId,
|
|
61991
62207
|
profileRevision: profile.profileRevision,
|
|
61992
62208
|
authority: profile.authority,
|
|
@@ -62016,7 +62232,7 @@ __export(exports_context, {
|
|
|
62016
62232
|
parseSkillContextInput: () => parseSkillContextInput,
|
|
62017
62233
|
contextResolverOptions: () => contextResolverOptions
|
|
62018
62234
|
});
|
|
62019
|
-
import { readSync as
|
|
62235
|
+
import { readSync as readSync6 } from "fs";
|
|
62020
62236
|
function selectedProfileId(explicit) {
|
|
62021
62237
|
return explicit ?? process.env.HASNA_SKILLS_SELECTION_PROFILE ?? readManagedSkillPolicy()?.profileId ?? "default";
|
|
62022
62238
|
}
|
|
@@ -62075,7 +62291,7 @@ async function readContextStdin() {
|
|
|
62075
62291
|
let size2 = 0;
|
|
62076
62292
|
while (true) {
|
|
62077
62293
|
const chunk2 = Buffer.allocUnsafe(8192);
|
|
62078
|
-
const count =
|
|
62294
|
+
const count = readSync6(0, chunk2, 0, chunk2.length, null);
|
|
62079
62295
|
if (count === 0)
|
|
62080
62296
|
break;
|
|
62081
62297
|
size2 += count;
|
|
@@ -62551,12 +62767,12 @@ function handleBrowseError(error) {
|
|
|
62551
62767
|
async function writeJson(value, space) {
|
|
62552
62768
|
const text3 = `${JSON.stringify(value, null, space)}
|
|
62553
62769
|
`;
|
|
62554
|
-
await new Promise((
|
|
62770
|
+
await new Promise((resolve11, reject2) => {
|
|
62555
62771
|
process.stdout.write(text3, (error) => {
|
|
62556
62772
|
if (error)
|
|
62557
62773
|
reject2(error);
|
|
62558
62774
|
else
|
|
62559
|
-
|
|
62775
|
+
resolve11();
|
|
62560
62776
|
});
|
|
62561
62777
|
});
|
|
62562
62778
|
}
|
|
@@ -62871,7 +63087,7 @@ __export(exports_introspect, {
|
|
|
62871
63087
|
registerIntrospect: () => registerIntrospect
|
|
62872
63088
|
});
|
|
62873
63089
|
import { existsSync as existsSync22, readFileSync as readFileSync21 } from "fs";
|
|
62874
|
-
import { join as
|
|
63090
|
+
import { join as join30 } from "path";
|
|
62875
63091
|
import { execSync } from "child_process";
|
|
62876
63092
|
function registerIntrospect(parent) {
|
|
62877
63093
|
parent.command("info").argument("<skill>", "Skill name").option("--json", "Output as JSON", false).option("--brief", "Single line: name \u2014 description [category] (tags: ...)", false).option("--remote", "Use the remote registry (the resolved Skills credential; HASNA_SKILLS_API_URL for your own instance)", false).description("Show details about a specific skill").action((name, options) => {
|
|
@@ -63104,8 +63320,8 @@ function handleDiff(name, options) {
|
|
|
63104
63320
|
const bare = name;
|
|
63105
63321
|
const normalized = normalizePortableSkillName(bare);
|
|
63106
63322
|
const sourcePath = getSkillPath(bare);
|
|
63107
|
-
const canonicalDir =
|
|
63108
|
-
const canonicalSkillMd =
|
|
63323
|
+
const canonicalDir = join30(resolveCorpusRoot(), normalized);
|
|
63324
|
+
const canonicalSkillMd = join30(canonicalDir, "SKILL.md");
|
|
63109
63325
|
const canonical = {
|
|
63110
63326
|
present: existsSync22(canonicalSkillMd),
|
|
63111
63327
|
path: canonicalDir,
|
|
@@ -63115,7 +63331,7 @@ function handleDiff(name, options) {
|
|
|
63115
63331
|
const pinned = getInstalledSkills().includes(bare);
|
|
63116
63332
|
const installMeta = getInstallMeta();
|
|
63117
63333
|
const installedVersion = installMeta.skills[bare]?.version ?? "unknown";
|
|
63118
|
-
const registryPkgPath =
|
|
63334
|
+
const registryPkgPath = join30(sourcePath, "package.json");
|
|
63119
63335
|
let registryVersion = "unknown";
|
|
63120
63336
|
if (existsSync22(registryPkgPath)) {
|
|
63121
63337
|
try {
|
|
@@ -63125,10 +63341,10 @@ function handleDiff(name, options) {
|
|
|
63125
63341
|
const upToDate = installedVersion === registryVersion;
|
|
63126
63342
|
const homes = [];
|
|
63127
63343
|
for (const agent of SYNC_AGENTS) {
|
|
63128
|
-
const dir =
|
|
63344
|
+
const dir = join30(agentGlobalSkillsDir(agent), normalized);
|
|
63129
63345
|
const present = existsSync22(dir);
|
|
63130
|
-
const managed = existsSync22(
|
|
63131
|
-
const skillMdPath =
|
|
63346
|
+
const managed = existsSync22(join30(dir, SYNC_MARKER_FILE));
|
|
63347
|
+
const skillMdPath = join30(dir, "SKILL.md");
|
|
63132
63348
|
const hash2 = present && existsSync22(skillMdPath) ? hashSkillMarkdownFile(skillMdPath) : undefined;
|
|
63133
63349
|
let stub;
|
|
63134
63350
|
if (present && existsSync22(skillMdPath)) {
|
|
@@ -63671,7 +63887,7 @@ __export(exports_init, {
|
|
|
63671
63887
|
registerSetup: () => registerSetup
|
|
63672
63888
|
});
|
|
63673
63889
|
import { existsSync as existsSync23, readFileSync as readFileSync22, writeFileSync as writeFileSync11, appendFileSync } from "fs";
|
|
63674
|
-
import { join as
|
|
63890
|
+
import { join as join31 } from "path";
|
|
63675
63891
|
function registerSetup(parent) {
|
|
63676
63892
|
parent.command("init").option("--json", "Output as JSON", false).option("--for <agent>", "Detect project type and show MCP registration guidance for agent").option("--scope <scope>", "Deprecated; agent skill-folder installs are disabled", "global").description("Initialize project for pinned skills (.env.example, .gitignore)").action((options) => handleInit(options));
|
|
63677
63893
|
parent.command("export").option("--json", "Output as JSON (default behavior)", false).description("Export pinned skills to JSON for sharing or backup").action((_options) => handleExport());
|
|
@@ -63755,7 +63971,7 @@ Use: skills render`));
|
|
|
63755
63971
|
lines.push(`# Used by: ${skills.join(", ")}`);
|
|
63756
63972
|
lines.push(`${envVar}=`);
|
|
63757
63973
|
}
|
|
63758
|
-
writeFileSync11(
|
|
63974
|
+
writeFileSync11(join31(cwd2, ".env.example"), lines.join(`
|
|
63759
63975
|
`) + `
|
|
63760
63976
|
`);
|
|
63761
63977
|
envVarCount = envMap.size;
|
|
@@ -63763,7 +63979,7 @@ Use: skills render`));
|
|
|
63763
63979
|
console.log(source_default.green(`\u2713 Generated .env.example (${envVarCount} variables from ${installed.length} skills)`));
|
|
63764
63980
|
} else if (!options.json)
|
|
63765
63981
|
console.log(source_default.dim(" No environment variables detected across pinned skills"));
|
|
63766
|
-
const gitignorePath =
|
|
63982
|
+
const gitignorePath = join31(cwd2, ".gitignore");
|
|
63767
63983
|
const gitignoreEntries = [".skills/runs/", ".skills/exports/", ".skills/tmp/"];
|
|
63768
63984
|
let gitignoreContent = existsSync23(gitignorePath) ? readFileSync22(gitignorePath, "utf-8") : "";
|
|
63769
63985
|
let gitignoreUpdated = false;
|
|
@@ -63917,9 +64133,9 @@ var init_init = __esm(() => {
|
|
|
63917
64133
|
});
|
|
63918
64134
|
|
|
63919
64135
|
// src/lib/home-adoption.ts
|
|
63920
|
-
import { constants as
|
|
64136
|
+
import { constants as constants8, closeSync as closeSync8, fstatSync as fstatSync8, lstatSync as lstatSync14, openSync as openSync8, readSync as readSync7, existsSync as existsSync24, mkdirSync as mkdirSync12, readdirSync as readdirSync14, readFileSync as readFileSync23, rmSync as rmSync6, statSync as statSync12, writeFileSync as writeFileSync12 } from "fs";
|
|
63921
64137
|
import { homedir as homedir6 } from "os";
|
|
63922
|
-
import { join as
|
|
64138
|
+
import { join as join32 } from "path";
|
|
63923
64139
|
function indexCanonicalCorpus(corpusRoot) {
|
|
63924
64140
|
const byName = new Map;
|
|
63925
64141
|
if (!existsSync24(corpusRoot))
|
|
@@ -63933,7 +64149,7 @@ function indexCanonicalCorpus(corpusRoot) {
|
|
|
63933
64149
|
for (const entry of entries.sort()) {
|
|
63934
64150
|
if (entry.startsWith("."))
|
|
63935
64151
|
continue;
|
|
63936
|
-
const skillMd =
|
|
64152
|
+
const skillMd = join32(corpusRoot, entry, "SKILL.md");
|
|
63937
64153
|
if (!existsSync24(skillMd))
|
|
63938
64154
|
continue;
|
|
63939
64155
|
try {
|
|
@@ -63953,7 +64169,7 @@ function selectedHomeNames(options, index, homeDir2, agents) {
|
|
|
63953
64169
|
continue;
|
|
63954
64170
|
const present = agents.some((agent) => {
|
|
63955
64171
|
try {
|
|
63956
|
-
return statSync12(
|
|
64172
|
+
return statSync12(join32(agentGlobalSkillsDir(agent, homeDir2), name)).isDirectory();
|
|
63957
64173
|
} catch {
|
|
63958
64174
|
return false;
|
|
63959
64175
|
}
|
|
@@ -63985,18 +64201,18 @@ function scanUnmarkedHomes(options = {}) {
|
|
|
63985
64201
|
continue;
|
|
63986
64202
|
if (names && !names.has(skill))
|
|
63987
64203
|
continue;
|
|
63988
|
-
const dir =
|
|
64204
|
+
const dir = join32(home, skill);
|
|
63989
64205
|
try {
|
|
63990
64206
|
if (!statSync12(dir).isDirectory())
|
|
63991
64207
|
continue;
|
|
63992
64208
|
} catch {
|
|
63993
64209
|
continue;
|
|
63994
64210
|
}
|
|
63995
|
-
if (existsSync24(
|
|
64211
|
+
if (existsSync24(join32(dir, SYNC_MARKER_FILE))) {
|
|
63996
64212
|
scan.managed += 1;
|
|
63997
64213
|
continue;
|
|
63998
64214
|
}
|
|
63999
|
-
const skillMdPath =
|
|
64215
|
+
const skillMdPath = join32(dir, "SKILL.md");
|
|
64000
64216
|
if (!existsSync24(skillMdPath))
|
|
64001
64217
|
continue;
|
|
64002
64218
|
const hash2 = hashSkillMarkdownFile(skillMdPath);
|
|
@@ -64017,7 +64233,7 @@ function scanUnmarkedHomes(options = {}) {
|
|
|
64017
64233
|
function appendConflictsLedger(appDir, conflicts) {
|
|
64018
64234
|
if (conflicts.length === 0)
|
|
64019
64235
|
return;
|
|
64020
|
-
const ledgerPath =
|
|
64236
|
+
const ledgerPath = join32(appDir, CONFLICTS_LEDGER_FILE);
|
|
64021
64237
|
let ledger = { version: 1, entries: [] };
|
|
64022
64238
|
if (existsSync24(ledgerPath)) {
|
|
64023
64239
|
try {
|
|
@@ -64037,9 +64253,9 @@ function appendConflictsLedger(appDir, conflicts) {
|
|
|
64037
64253
|
`);
|
|
64038
64254
|
}
|
|
64039
64255
|
function writeRollbackRecord(mode, entries, appDir = getDataDir()) {
|
|
64040
|
-
const dir =
|
|
64256
|
+
const dir = join32(appDir, ROLLBACK_DIRNAME);
|
|
64041
64257
|
mkdirSync12(dir, { recursive: true });
|
|
64042
|
-
const file =
|
|
64258
|
+
const file = join32(dir, `${mode}-${Date.now()}.json`);
|
|
64043
64259
|
const record5 = { version: 1, mode, timestamp: new Date().toISOString(), entries };
|
|
64044
64260
|
writeFileSync12(file, `${JSON.stringify(record5, null, 2)}
|
|
64045
64261
|
`);
|
|
@@ -64050,7 +64266,7 @@ function adoptUnmarkedHomes(options = {}) {
|
|
|
64050
64266
|
if (!options.apply) {
|
|
64051
64267
|
return { ...scan, applied: false };
|
|
64052
64268
|
}
|
|
64053
|
-
const appDir = options.homeDir ?
|
|
64269
|
+
const appDir = options.homeDir ? join32(options.homeDir, ".hasna", "skills") : getDataDir();
|
|
64054
64270
|
const markers = scan.adoptable.map((entry) => {
|
|
64055
64271
|
const marker = {
|
|
64056
64272
|
managedBy: SYNC_MARKER_MANAGED_BY,
|
|
@@ -64058,7 +64274,7 @@ function adoptUnmarkedHomes(options = {}) {
|
|
|
64058
64274
|
source: "adopted",
|
|
64059
64275
|
syncedAt: new Date().toISOString()
|
|
64060
64276
|
};
|
|
64061
|
-
writeFileSync12(
|
|
64277
|
+
writeFileSync12(join32(entry.path, SYNC_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
|
|
64062
64278
|
`);
|
|
64063
64279
|
return { agent: entry.agent, skill: entry.skill, path: entry.path, hash: entry.hash, marker };
|
|
64064
64280
|
});
|
|
@@ -64072,25 +64288,25 @@ function adoptUnmarkedHomes(options = {}) {
|
|
|
64072
64288
|
function pruneOwnership(dir) {
|
|
64073
64289
|
let descriptor;
|
|
64074
64290
|
try {
|
|
64075
|
-
const directory =
|
|
64291
|
+
const directory = lstatSync14(dir);
|
|
64076
64292
|
if (!directory.isDirectory())
|
|
64077
64293
|
return;
|
|
64078
|
-
const markerPath =
|
|
64294
|
+
const markerPath = join32(dir, SYNC_MARKER_FILE), markerPathBefore = lstatSync14(markerPath);
|
|
64079
64295
|
if (!markerPathBefore.isFile())
|
|
64080
64296
|
return;
|
|
64081
|
-
descriptor =
|
|
64082
|
-
const before2 =
|
|
64297
|
+
descriptor = openSync8(markerPath, constants8.O_RDONLY | constants8.O_NOFOLLOW | constants8.O_NONBLOCK);
|
|
64298
|
+
const before2 = fstatSync8(descriptor);
|
|
64083
64299
|
if (!before2.isFile() || before2.dev !== markerPathBefore.dev || before2.ino !== markerPathBefore.ino || before2.size !== markerPathBefore.size || before2.mtimeMs !== markerPathBefore.mtimeMs || before2.ctimeMs !== markerPathBefore.ctimeMs || before2.size < 1 || before2.size > 65536)
|
|
64084
64300
|
return;
|
|
64085
64301
|
const bytes = Buffer.alloc(before2.size + 1);
|
|
64086
64302
|
let length = 0;
|
|
64087
64303
|
while (length < bytes.length) {
|
|
64088
|
-
const count =
|
|
64304
|
+
const count = readSync7(descriptor, bytes, length, bytes.length - length, length);
|
|
64089
64305
|
if (!count)
|
|
64090
64306
|
break;
|
|
64091
64307
|
length += count;
|
|
64092
64308
|
}
|
|
64093
|
-
const after2 =
|
|
64309
|
+
const after2 = fstatSync8(descriptor), current = lstatSync14(dir), markerPathAfter = lstatSync14(markerPath);
|
|
64094
64310
|
if (!markerPathAfter.isFile() || markerPathAfter.dev !== before2.dev || markerPathAfter.ino !== before2.ino || markerPathAfter.size !== before2.size || markerPathAfter.mtimeMs !== before2.mtimeMs || markerPathAfter.ctimeMs !== before2.ctimeMs || length !== before2.size || after2.size !== before2.size || after2.mtimeMs !== before2.mtimeMs || after2.ctimeMs !== before2.ctimeMs || !current.isDirectory() || current.dev !== directory.dev || current.ino !== directory.ino)
|
|
64095
64311
|
return;
|
|
64096
64312
|
const text3 = bytes.subarray(0, length).toString("utf8"), marker = JSON.parse(text3);
|
|
@@ -64101,7 +64317,7 @@ function pruneOwnership(dir) {
|
|
|
64101
64317
|
return;
|
|
64102
64318
|
} finally {
|
|
64103
64319
|
if (descriptor !== undefined)
|
|
64104
|
-
|
|
64320
|
+
closeSync8(descriptor);
|
|
64105
64321
|
}
|
|
64106
64322
|
}
|
|
64107
64323
|
function pruneStrayHomes(options = {}) {
|
|
@@ -64127,7 +64343,7 @@ function pruneStrayHomes(options = {}) {
|
|
|
64127
64343
|
continue;
|
|
64128
64344
|
if (names && !names.has(skill))
|
|
64129
64345
|
continue;
|
|
64130
|
-
const dir =
|
|
64346
|
+
const dir = join32(home, skill);
|
|
64131
64347
|
try {
|
|
64132
64348
|
if (!statSync12(dir).isDirectory())
|
|
64133
64349
|
continue;
|
|
@@ -64141,7 +64357,7 @@ function pruneStrayHomes(options = {}) {
|
|
|
64141
64357
|
continue;
|
|
64142
64358
|
const marker = owned.marker;
|
|
64143
64359
|
ownership.set(dir, owned.identity);
|
|
64144
|
-
const skillMdPath =
|
|
64360
|
+
const skillMdPath = join32(dir, "SKILL.md");
|
|
64145
64361
|
const hash2 = existsSync24(skillMdPath) ? hashSkillMarkdownFile(skillMdPath) : "";
|
|
64146
64362
|
candidates.push({ agent, skill, home, path: dir, hash: hash2, marker });
|
|
64147
64363
|
}
|
|
@@ -64149,7 +64365,7 @@ function pruneStrayHomes(options = {}) {
|
|
|
64149
64365
|
if (!options.apply) {
|
|
64150
64366
|
return { candidates, pruned: 0, dryRun: true };
|
|
64151
64367
|
}
|
|
64152
|
-
const appDir = options.homeDir ?
|
|
64368
|
+
const appDir = options.homeDir ? join32(options.homeDir, ".hasna", "skills") : getDataDir();
|
|
64153
64369
|
const rollbackFile = writeRollbackRecord("prune", candidates.map(({ agent, skill, path, hash: hash2, marker }) => ({ agent, skill, path, hash: hash2, marker })), appDir);
|
|
64154
64370
|
let pruned = 0;
|
|
64155
64371
|
for (const candidate of candidates) {
|
|
@@ -64172,7 +64388,7 @@ var init_home_adoption = __esm(() => {
|
|
|
64172
64388
|
// src/lib/home-census.ts
|
|
64173
64389
|
import { existsSync as existsSync25, readFileSync as readFileSync24, readdirSync as readdirSync15, statSync as statSync13 } from "fs";
|
|
64174
64390
|
import { homedir as homedir7 } from "os";
|
|
64175
|
-
import { join as
|
|
64391
|
+
import { join as join33 } from "path";
|
|
64176
64392
|
function sortEntries(entries) {
|
|
64177
64393
|
return entries.sort((a, b) => {
|
|
64178
64394
|
const left = `${a.agent}/${a.skill}/${a.kind}`;
|
|
@@ -64213,7 +64429,7 @@ function censusHomeDrift(options = {}) {
|
|
|
64213
64429
|
continue;
|
|
64214
64430
|
if (requested && !requested.has(skill))
|
|
64215
64431
|
continue;
|
|
64216
|
-
const dir =
|
|
64432
|
+
const dir = join33(home, skill);
|
|
64217
64433
|
try {
|
|
64218
64434
|
if (!statSync13(dir).isDirectory())
|
|
64219
64435
|
continue;
|
|
@@ -64221,7 +64437,7 @@ function censusHomeDrift(options = {}) {
|
|
|
64221
64437
|
continue;
|
|
64222
64438
|
}
|
|
64223
64439
|
present.add(skill);
|
|
64224
|
-
const markerPath =
|
|
64440
|
+
const markerPath = join33(dir, SYNC_MARKER_FILE);
|
|
64225
64441
|
if (!existsSync25(markerPath)) {
|
|
64226
64442
|
unmarked += 1;
|
|
64227
64443
|
continue;
|
|
@@ -64232,7 +64448,7 @@ function censusHomeDrift(options = {}) {
|
|
|
64232
64448
|
entries.push({ agent, skill, kind: "stray-in-home", path: dir });
|
|
64233
64449
|
continue;
|
|
64234
64450
|
}
|
|
64235
|
-
const skillMdPath =
|
|
64451
|
+
const skillMdPath = join33(dir, "SKILL.md");
|
|
64236
64452
|
if (!existsSync25(skillMdPath)) {
|
|
64237
64453
|
entries.push({ agent, skill, kind: "diverged", path: dir, canonicalHash });
|
|
64238
64454
|
continue;
|
|
@@ -64246,7 +64462,7 @@ function censusHomeDrift(options = {}) {
|
|
|
64246
64462
|
homeStub = undefined;
|
|
64247
64463
|
}
|
|
64248
64464
|
let canonicalStub;
|
|
64249
|
-
const canonicalSkillMd =
|
|
64465
|
+
const canonicalSkillMd = join33(corpusRoot, skill, "SKILL.md");
|
|
64250
64466
|
try {
|
|
64251
64467
|
canonicalStub = isPointerSkillMd(readFileSync24(canonicalSkillMd, "utf-8"));
|
|
64252
64468
|
} catch {
|
|
@@ -64263,7 +64479,7 @@ function censusHomeDrift(options = {}) {
|
|
|
64263
64479
|
agent,
|
|
64264
64480
|
skill: name,
|
|
64265
64481
|
kind: "missing-from-home",
|
|
64266
|
-
path:
|
|
64482
|
+
path: join33(home, name),
|
|
64267
64483
|
canonicalHash
|
|
64268
64484
|
});
|
|
64269
64485
|
}
|
|
@@ -64286,7 +64502,7 @@ var init_home_census = __esm(() => {
|
|
|
64286
64502
|
});
|
|
64287
64503
|
|
|
64288
64504
|
// src/cli/env-assignment.ts
|
|
64289
|
-
import { closeSync as
|
|
64505
|
+
import { closeSync as closeSync9, constants as constants9, fstatSync as fstatSync9, ftruncateSync as ftruncateSync2, lstatSync as lstatSync15, openSync as openSync9, readFileSync as readFileSync25, writeSync as writeSync2 } from "fs";
|
|
64290
64506
|
function serializeValue(value) {
|
|
64291
64507
|
if (controls.test(value))
|
|
64292
64508
|
throw new EnvAssignmentError("Environment values cannot contain control characters or newlines.");
|
|
@@ -64365,7 +64581,7 @@ function setEnvAssignment(path, assignment) {
|
|
|
64365
64581
|
try {
|
|
64366
64582
|
const previous = (() => {
|
|
64367
64583
|
try {
|
|
64368
|
-
return
|
|
64584
|
+
return lstatSync15(path);
|
|
64369
64585
|
} catch (error) {
|
|
64370
64586
|
if (error.code === "ENOENT")
|
|
64371
64587
|
return;
|
|
@@ -64374,8 +64590,8 @@ function setEnvAssignment(path, assignment) {
|
|
|
64374
64590
|
})();
|
|
64375
64591
|
if (previous && !previous.isFile())
|
|
64376
64592
|
throw new EnvAssignmentError("The project .env must be a regular file, not a symlink or special file.");
|
|
64377
|
-
descriptor =
|
|
64378
|
-
const opened =
|
|
64593
|
+
descriptor = openSync9(path, previous ? constants9.O_RDWR | constants9.O_NOFOLLOW | constants9.O_NONBLOCK : constants9.O_WRONLY | constants9.O_CREAT | constants9.O_EXCL | constants9.O_NOFOLLOW, 384);
|
|
64594
|
+
const opened = fstatSync9(descriptor);
|
|
64379
64595
|
if (!opened.isFile() || previous && (opened.ino !== previous.ino || opened.dev !== previous.dev)) {
|
|
64380
64596
|
throw new EnvAssignmentError("The project .env changed while opening it; retry with a regular file.");
|
|
64381
64597
|
}
|
|
@@ -64402,7 +64618,7 @@ function setEnvAssignment(path, assignment) {
|
|
|
64402
64618
|
throw new EnvAssignmentError("Cannot safely read or write the project .env file.");
|
|
64403
64619
|
} finally {
|
|
64404
64620
|
if (descriptor !== undefined)
|
|
64405
|
-
|
|
64621
|
+
closeSync9(descriptor);
|
|
64406
64622
|
}
|
|
64407
64623
|
}
|
|
64408
64624
|
var INVALID_LAYOUT = "Cannot safely update .env with multiline or unsupported assignments. Use single-line KEY=VALUE entries or edit the file manually.", controls, EnvAssignmentError;
|
|
@@ -64469,7 +64685,7 @@ __export(exports_diagnostic, {
|
|
|
64469
64685
|
registerDiagnostic: () => registerDiagnostic
|
|
64470
64686
|
});
|
|
64471
64687
|
import { existsSync as existsSync26, readFileSync as readFileSync26, readdirSync as readdirSync16, statSync as statSync14 } from "fs";
|
|
64472
|
-
import { join as
|
|
64688
|
+
import { join as join34 } from "path";
|
|
64473
64689
|
import { execSync as execSync2 } from "child_process";
|
|
64474
64690
|
function registerDiagnostic(parent) {
|
|
64475
64691
|
parent.command("doctor").option("--json", "Output as JSON", false).description("Check env vars, system deps, and readiness for pinned skills").action((options) => handleDoctor(options));
|
|
@@ -64585,7 +64801,7 @@ Skills Test (${results.length} skill${results.length === 1 ? "" : "s"}):
|
|
|
64585
64801
|
}
|
|
64586
64802
|
function handleAuth(name, options) {
|
|
64587
64803
|
const cwd2 = process.cwd();
|
|
64588
|
-
const envFilePath =
|
|
64804
|
+
const envFilePath = join34(cwd2, ".env");
|
|
64589
64805
|
if (options.set !== undefined) {
|
|
64590
64806
|
let key;
|
|
64591
64807
|
try {
|
|
@@ -64661,7 +64877,7 @@ function handleWhoami(options) {
|
|
|
64661
64877
|
let skillCount = 0;
|
|
64662
64878
|
if (exists)
|
|
64663
64879
|
try {
|
|
64664
|
-
skillCount = readdirSync16(agentSkillsPath).filter((f) => !f.startsWith(".") && statSync14(
|
|
64880
|
+
skillCount = readdirSync16(agentSkillsPath).filter((f) => !f.startsWith(".") && statSync14(join34(agentSkillsPath, f)).isDirectory()).length;
|
|
64665
64881
|
} catch {}
|
|
64666
64882
|
agentConfigs.push({ agent, label: AGENT_LABELS[agent], path: agentSkillsPath, exists, skillCount });
|
|
64667
64883
|
}
|
|
@@ -64705,7 +64921,7 @@ function handleOutdated(options) {
|
|
|
64705
64921
|
for (const name of installed) {
|
|
64706
64922
|
const installedVersion = meta.skills[name]?.version ?? "unknown";
|
|
64707
64923
|
const registryPath = getSkillPath(name);
|
|
64708
|
-
const registryPkgPath =
|
|
64924
|
+
const registryPkgPath = join34(registryPath, "package.json");
|
|
64709
64925
|
let registryVersion = "unknown";
|
|
64710
64926
|
if (existsSync26(registryPkgPath))
|
|
64711
64927
|
try {
|
|
@@ -64914,10 +65130,10 @@ __export(exports_selected_run, {
|
|
|
64914
65130
|
resolveSelectedRun: () => resolveSelectedRun,
|
|
64915
65131
|
executeSelectedLocal: () => executeSelectedLocal
|
|
64916
65132
|
});
|
|
64917
|
-
import { createHash as
|
|
65133
|
+
import { createHash as createHash12 } from "crypto";
|
|
64918
65134
|
import { spawn as spawn2 } from "child_process";
|
|
64919
65135
|
import { mkdirSync as mkdirSync13, mkdtempSync as mkdtempSync4, writeFileSync as writeFileSync13 } from "fs";
|
|
64920
|
-
import { dirname as
|
|
65136
|
+
import { dirname as dirname14, join as join35, resolve as resolve11 } from "path";
|
|
64921
65137
|
import { tmpdir } from "os";
|
|
64922
65138
|
function jsonEntry(entries, path) {
|
|
64923
65139
|
const entry = entries.find((candidate) => candidate.path === path);
|
|
@@ -64995,7 +65211,7 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
64995
65211
|
throw new SkillSelectionError("LOCAL_ENV_REQUIRED", `The selected runtime requires an explicit value for ${name}; ambient credentials are not inherited.`);
|
|
64996
65212
|
env3[name] = value;
|
|
64997
65213
|
}
|
|
64998
|
-
const runDirectory = mkdtempSync4(
|
|
65214
|
+
const runDirectory = mkdtempSync4(join35(tmpdir(), "skills-execution-"));
|
|
64999
65215
|
const paths = new SkillEntryPaths;
|
|
65000
65216
|
for (const entry of entries) {
|
|
65001
65217
|
paths.add(entry.path, 100, () => {
|
|
@@ -65003,12 +65219,12 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
65003
65219
|
}, () => {
|
|
65004
65220
|
throw new SkillSelectionError("INVALID_BUNDLE_PATH", "The execution bundle path exceeds its limit.");
|
|
65005
65221
|
});
|
|
65006
|
-
const destination =
|
|
65007
|
-
mkdirSync13(
|
|
65222
|
+
const destination = join35(runDirectory, entry.path);
|
|
65223
|
+
mkdirSync13(dirname14(destination), { recursive: true, mode: 448 });
|
|
65008
65224
|
writeFileSync13(destination, entry.bytes, { flag: "wx", mode: entry.mode & 511 });
|
|
65009
65225
|
}
|
|
65010
65226
|
env3.SKILLS_INPUT_JSON = input;
|
|
65011
|
-
env3.SKILLS_WORKSPACE_DIR =
|
|
65227
|
+
env3.SKILLS_WORKSPACE_DIR = resolve11(options.cwd ?? process.cwd());
|
|
65012
65228
|
env3.SKILLS_RUN_DIR = runDirectory;
|
|
65013
65229
|
if (runtime.version) {
|
|
65014
65230
|
const version = await subprocess([executable, "--version"], runDirectory, env3, "", Math.min(timeoutMs, 5000));
|
|
@@ -65016,9 +65232,9 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
65016
65232
|
if (version.exitCode !== 0 || actual !== runtime.version)
|
|
65017
65233
|
throw new SkillSelectionError("LOCAL_RUNTIME_VERSION_MISMATCH", "The installed runtime version differs from the version selected by the skill.");
|
|
65018
65234
|
}
|
|
65019
|
-
const result2 = await subprocess([executable,
|
|
65020
|
-
const receipt = { selection: selected.selection, target: "local", runtime: runtimeName, inputDigest: `sha256:${
|
|
65021
|
-
writeFileSync13(
|
|
65235
|
+
const result2 = await subprocess([executable, join35(runDirectory, declaredEntry), ...args], runDirectory, env3, input, timeoutMs);
|
|
65236
|
+
const receipt = { selection: selected.selection, target: "local", runtime: runtimeName, inputDigest: `sha256:${createHash12("sha256").update(input).digest("hex")}`, runDirectory, ...result2 };
|
|
65237
|
+
writeFileSync13(join35(runDirectory, ".execution-receipt.json"), JSON.stringify({ ...receipt, stdout: undefined, stderr: undefined }), { mode: 384 });
|
|
65022
65238
|
return receipt;
|
|
65023
65239
|
}
|
|
65024
65240
|
async function subprocess(command, cwd2, env3, input, timeoutMs) {
|
|
@@ -65040,7 +65256,7 @@ async function subprocess(command, cwd2, env3, input, timeoutMs) {
|
|
|
65040
65256
|
error = "LOCAL_RUN_TIMEOUT";
|
|
65041
65257
|
kill();
|
|
65042
65258
|
}, timeoutMs);
|
|
65043
|
-
const
|
|
65259
|
+
const capture2 = (target) => (chunk2) => {
|
|
65044
65260
|
outputBytes += chunk2.length;
|
|
65045
65261
|
if (outputBytes > 1024 * 1024) {
|
|
65046
65262
|
error = "LOCAL_RUN_OUTPUT_LIMIT";
|
|
@@ -65049,8 +65265,8 @@ async function subprocess(command, cwd2, env3, input, timeoutMs) {
|
|
|
65049
65265
|
}
|
|
65050
65266
|
target.push(chunk2);
|
|
65051
65267
|
};
|
|
65052
|
-
child.stdout.on("data",
|
|
65053
|
-
child.stderr.on("data",
|
|
65268
|
+
child.stdout.on("data", capture2(stdout));
|
|
65269
|
+
child.stderr.on("data", capture2(stderr));
|
|
65054
65270
|
const finish = (code) => {
|
|
65055
65271
|
if (ended)
|
|
65056
65272
|
return;
|
|
@@ -65247,21 +65463,21 @@ var init_runs = __esm(() => {
|
|
|
65247
65463
|
});
|
|
65248
65464
|
|
|
65249
65465
|
// src/lib/run-state.ts
|
|
65250
|
-
import { createHash as
|
|
65466
|
+
import { createHash as createHash13, randomBytes } from "crypto";
|
|
65251
65467
|
import { existsSync as existsSync27, mkdirSync as mkdirSync14, readFileSync as readFileSync27, readdirSync as readdirSync17, statSync as statSync15, writeFileSync as writeFileSync14 } from "fs";
|
|
65252
|
-
import { extname, join as
|
|
65468
|
+
import { extname, join as join36, relative as relative5 } from "path";
|
|
65253
65469
|
function createSkillRun(params, targetDir = process.cwd()) {
|
|
65254
65470
|
const now3 = new Date;
|
|
65255
65471
|
const id = createRunId(now3);
|
|
65256
65472
|
const day = now3.toISOString().slice(0, 10);
|
|
65257
65473
|
const skillName = normalizeSkillName(params.skill);
|
|
65258
65474
|
const root = getProjectStateDir(targetDir);
|
|
65259
|
-
const runDir =
|
|
65260
|
-
const logsDir =
|
|
65261
|
-
const exportDir =
|
|
65475
|
+
const runDir = join36(root, "runs", day, id);
|
|
65476
|
+
const logsDir = join36(runDir, "logs");
|
|
65477
|
+
const exportDir = join36(root, "exports", skillName, id);
|
|
65262
65478
|
mkdirSync14(logsDir, { recursive: true });
|
|
65263
65479
|
mkdirSync14(exportDir, { recursive: true });
|
|
65264
|
-
mkdirSync14(
|
|
65480
|
+
mkdirSync14(join36(root, "tmp"), { recursive: true });
|
|
65265
65481
|
const record5 = {
|
|
65266
65482
|
id,
|
|
65267
65483
|
skill: skillName,
|
|
@@ -65313,27 +65529,27 @@ function updateSkillRun(context, patch) {
|
|
|
65313
65529
|
return context.record;
|
|
65314
65530
|
}
|
|
65315
65531
|
function writeRunLogs(context, stdout = "", stderr = "") {
|
|
65316
|
-
writeFileSync14(
|
|
65317
|
-
writeFileSync14(
|
|
65532
|
+
writeFileSync14(join36(context.logsDir, "stdout.log"), stdout);
|
|
65533
|
+
writeFileSync14(join36(context.logsDir, "stderr.log"), stderr);
|
|
65318
65534
|
}
|
|
65319
65535
|
function appendRunEvent(context, event, data = {}) {
|
|
65320
65536
|
const line = JSON.stringify({ ts: new Date().toISOString(), event, ...data }) + `
|
|
65321
65537
|
`;
|
|
65322
|
-
const path =
|
|
65538
|
+
const path = join36(context.runDir, "events.ndjson");
|
|
65323
65539
|
const previous = existsSync27(path) ? readFileSync27(path, "utf-8") : "";
|
|
65324
65540
|
writeFileSync14(path, previous + line);
|
|
65325
65541
|
}
|
|
65326
65542
|
function listSkillRuns(targetDir = process.cwd(), limit = 50) {
|
|
65327
|
-
const runsRoot =
|
|
65543
|
+
const runsRoot = join36(getProjectStateDir(targetDir), "runs");
|
|
65328
65544
|
if (!existsSync27(runsRoot))
|
|
65329
65545
|
return [];
|
|
65330
65546
|
const records = [];
|
|
65331
65547
|
for (const day of readdirSync17(runsRoot).sort().reverse()) {
|
|
65332
|
-
const dayDir =
|
|
65548
|
+
const dayDir = join36(runsRoot, day);
|
|
65333
65549
|
if (!statSync15(dayDir).isDirectory())
|
|
65334
65550
|
continue;
|
|
65335
65551
|
for (const runId2 of readdirSync17(dayDir).sort().reverse()) {
|
|
65336
|
-
const record5 = readRunRecord(
|
|
65552
|
+
const record5 = readRunRecord(join36(dayDir, runId2));
|
|
65337
65553
|
if (record5)
|
|
65338
65554
|
records.push(record5);
|
|
65339
65555
|
if (records.length >= limit)
|
|
@@ -65343,11 +65559,11 @@ function listSkillRuns(targetDir = process.cwd(), limit = 50) {
|
|
|
65343
65559
|
return records;
|
|
65344
65560
|
}
|
|
65345
65561
|
function findSkillRun(runId2, targetDir = process.cwd()) {
|
|
65346
|
-
const runsRoot =
|
|
65562
|
+
const runsRoot = join36(getProjectStateDir(targetDir), "runs");
|
|
65347
65563
|
if (!existsSync27(runsRoot))
|
|
65348
65564
|
return null;
|
|
65349
65565
|
for (const day of readdirSync17(runsRoot)) {
|
|
65350
|
-
const record5 = readRunRecord(
|
|
65566
|
+
const record5 = readRunRecord(join36(runsRoot, day, runId2));
|
|
65351
65567
|
if (record5)
|
|
65352
65568
|
return record5;
|
|
65353
65569
|
}
|
|
@@ -65364,14 +65580,14 @@ function skillRunEnv(context) {
|
|
|
65364
65580
|
};
|
|
65365
65581
|
}
|
|
65366
65582
|
function getRunExportDir(runId2, skill, targetDir = process.cwd()) {
|
|
65367
|
-
return
|
|
65583
|
+
return join36(getProjectStateDir(targetDir), "exports", normalizeSkillName(skill), runId2);
|
|
65368
65584
|
}
|
|
65369
65585
|
function writeRunRecord(context) {
|
|
65370
|
-
writeFileSync14(
|
|
65586
|
+
writeFileSync14(join36(context.runDir, "run.json"), JSON.stringify(context.record, null, 2) + `
|
|
65371
65587
|
`);
|
|
65372
65588
|
}
|
|
65373
65589
|
function writeArtifactsManifest(context, artifacts) {
|
|
65374
|
-
writeFileSync14(
|
|
65590
|
+
writeFileSync14(join36(context.runDir, "artifacts.json"), JSON.stringify({ runId: context.record.id, artifacts }, null, 2) + `
|
|
65375
65591
|
`);
|
|
65376
65592
|
}
|
|
65377
65593
|
function collectRunArtifacts(context) {
|
|
@@ -65384,14 +65600,14 @@ function collectRunArtifacts(context) {
|
|
|
65384
65600
|
artifacts.push({
|
|
65385
65601
|
path: toProjectRelative(context.targetDir, path),
|
|
65386
65602
|
mime: mimeForPath(path),
|
|
65387
|
-
sha256:
|
|
65603
|
+
sha256: createHash13("sha256").update(bytes).digest("hex"),
|
|
65388
65604
|
sizeBytes: stat.size
|
|
65389
65605
|
});
|
|
65390
65606
|
}
|
|
65391
65607
|
return artifacts.sort((a, b) => a.path.localeCompare(b.path));
|
|
65392
65608
|
}
|
|
65393
65609
|
function readRunRecord(runDir) {
|
|
65394
|
-
const path =
|
|
65610
|
+
const path = join36(runDir, "run.json");
|
|
65395
65611
|
if (!existsSync27(path))
|
|
65396
65612
|
return null;
|
|
65397
65613
|
try {
|
|
@@ -65403,7 +65619,7 @@ function readRunRecord(runDir) {
|
|
|
65403
65619
|
function walkFiles(dir) {
|
|
65404
65620
|
const files = [];
|
|
65405
65621
|
for (const entry of readdirSync17(dir)) {
|
|
65406
|
-
const full =
|
|
65622
|
+
const full = join36(dir, entry);
|
|
65407
65623
|
if (statSync15(full).isDirectory())
|
|
65408
65624
|
files.push(...walkFiles(full));
|
|
65409
65625
|
else
|
|
@@ -70973,12 +71189,12 @@ class StdioServerTransport {
|
|
|
70973
71189
|
this.onclose?.();
|
|
70974
71190
|
}
|
|
70975
71191
|
send(message) {
|
|
70976
|
-
return new Promise((
|
|
71192
|
+
return new Promise((resolve12) => {
|
|
70977
71193
|
const json = serializeMessage(message);
|
|
70978
71194
|
if (this._stdout.write(json)) {
|
|
70979
|
-
|
|
71195
|
+
resolve12();
|
|
70980
71196
|
} else {
|
|
70981
|
-
this._stdout.once("drain",
|
|
71197
|
+
this._stdout.once("drain", resolve12);
|
|
70982
71198
|
}
|
|
70983
71199
|
});
|
|
70984
71200
|
}
|
|
@@ -73148,7 +73364,7 @@ class Protocol {
|
|
|
73148
73364
|
return;
|
|
73149
73365
|
}
|
|
73150
73366
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1000;
|
|
73151
|
-
await new Promise((
|
|
73367
|
+
await new Promise((resolve12) => setTimeout(resolve12, pollInterval));
|
|
73152
73368
|
options?.signal?.throwIfAborted();
|
|
73153
73369
|
}
|
|
73154
73370
|
} catch (error2) {
|
|
@@ -73160,7 +73376,7 @@ class Protocol {
|
|
|
73160
73376
|
}
|
|
73161
73377
|
request(request, resultSchema, options) {
|
|
73162
73378
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
73163
|
-
return new Promise((
|
|
73379
|
+
return new Promise((resolve12, reject2) => {
|
|
73164
73380
|
const earlyReject = (error2) => {
|
|
73165
73381
|
reject2(error2);
|
|
73166
73382
|
};
|
|
@@ -73238,7 +73454,7 @@ class Protocol {
|
|
|
73238
73454
|
if (!parseResult.success) {
|
|
73239
73455
|
reject2(parseResult.error);
|
|
73240
73456
|
} else {
|
|
73241
|
-
|
|
73457
|
+
resolve12(parseResult.data);
|
|
73242
73458
|
}
|
|
73243
73459
|
} catch (error2) {
|
|
73244
73460
|
reject2(error2);
|
|
@@ -73429,12 +73645,12 @@ class Protocol {
|
|
|
73429
73645
|
interval = task.pollInterval;
|
|
73430
73646
|
}
|
|
73431
73647
|
} catch {}
|
|
73432
|
-
return new Promise((
|
|
73648
|
+
return new Promise((resolve12, reject2) => {
|
|
73433
73649
|
if (signal.aborted) {
|
|
73434
73650
|
reject2(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
73435
73651
|
return;
|
|
73436
73652
|
}
|
|
73437
|
-
const timeoutId = setTimeout(
|
|
73653
|
+
const timeoutId = setTimeout(resolve12, interval);
|
|
73438
73654
|
signal.addEventListener("abort", () => {
|
|
73439
73655
|
clearTimeout(timeoutId);
|
|
73440
73656
|
reject2(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -73911,11 +74127,11 @@ var require_codegen = __commonJS((exports) => {
|
|
|
73911
74127
|
const rhs = this.rhs === undefined ? "" : ` = ${this.rhs}`;
|
|
73912
74128
|
return `${varKind} ${this.name}${rhs};` + _n;
|
|
73913
74129
|
}
|
|
73914
|
-
optimizeNames(names,
|
|
74130
|
+
optimizeNames(names, constants10) {
|
|
73915
74131
|
if (!names[this.name.str])
|
|
73916
74132
|
return;
|
|
73917
74133
|
if (this.rhs)
|
|
73918
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
74134
|
+
this.rhs = optimizeExpr(this.rhs, names, constants10);
|
|
73919
74135
|
return this;
|
|
73920
74136
|
}
|
|
73921
74137
|
get names() {
|
|
@@ -73933,10 +74149,10 @@ var require_codegen = __commonJS((exports) => {
|
|
|
73933
74149
|
render({ _n }) {
|
|
73934
74150
|
return `${this.lhs} = ${this.rhs};` + _n;
|
|
73935
74151
|
}
|
|
73936
|
-
optimizeNames(names,
|
|
74152
|
+
optimizeNames(names, constants10) {
|
|
73937
74153
|
if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects)
|
|
73938
74154
|
return;
|
|
73939
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
74155
|
+
this.rhs = optimizeExpr(this.rhs, names, constants10);
|
|
73940
74156
|
return this;
|
|
73941
74157
|
}
|
|
73942
74158
|
get names() {
|
|
@@ -74002,8 +74218,8 @@ var require_codegen = __commonJS((exports) => {
|
|
|
74002
74218
|
optimizeNodes() {
|
|
74003
74219
|
return `${this.code}` ? this : undefined;
|
|
74004
74220
|
}
|
|
74005
|
-
optimizeNames(names,
|
|
74006
|
-
this.code = optimizeExpr(this.code, names,
|
|
74221
|
+
optimizeNames(names, constants10) {
|
|
74222
|
+
this.code = optimizeExpr(this.code, names, constants10);
|
|
74007
74223
|
return this;
|
|
74008
74224
|
}
|
|
74009
74225
|
get names() {
|
|
@@ -74033,12 +74249,12 @@ var require_codegen = __commonJS((exports) => {
|
|
|
74033
74249
|
}
|
|
74034
74250
|
return nodes.length > 0 ? this : undefined;
|
|
74035
74251
|
}
|
|
74036
|
-
optimizeNames(names,
|
|
74252
|
+
optimizeNames(names, constants10) {
|
|
74037
74253
|
const { nodes } = this;
|
|
74038
74254
|
let i = nodes.length;
|
|
74039
74255
|
while (i--) {
|
|
74040
74256
|
const n = nodes[i];
|
|
74041
|
-
if (n.optimizeNames(names,
|
|
74257
|
+
if (n.optimizeNames(names, constants10))
|
|
74042
74258
|
continue;
|
|
74043
74259
|
subtractNames(names, n.names);
|
|
74044
74260
|
nodes.splice(i, 1);
|
|
@@ -74095,12 +74311,12 @@ var require_codegen = __commonJS((exports) => {
|
|
|
74095
74311
|
return;
|
|
74096
74312
|
return this;
|
|
74097
74313
|
}
|
|
74098
|
-
optimizeNames(names,
|
|
74314
|
+
optimizeNames(names, constants10) {
|
|
74099
74315
|
var _a;
|
|
74100
|
-
this.else = (_a = this.else) === null || _a === undefined ? undefined : _a.optimizeNames(names,
|
|
74101
|
-
if (!(super.optimizeNames(names,
|
|
74316
|
+
this.else = (_a = this.else) === null || _a === undefined ? undefined : _a.optimizeNames(names, constants10);
|
|
74317
|
+
if (!(super.optimizeNames(names, constants10) || this.else))
|
|
74102
74318
|
return;
|
|
74103
|
-
this.condition = optimizeExpr(this.condition, names,
|
|
74319
|
+
this.condition = optimizeExpr(this.condition, names, constants10);
|
|
74104
74320
|
return this;
|
|
74105
74321
|
}
|
|
74106
74322
|
get names() {
|
|
@@ -74125,10 +74341,10 @@ var require_codegen = __commonJS((exports) => {
|
|
|
74125
74341
|
render(opts) {
|
|
74126
74342
|
return `for(${this.iteration})` + super.render(opts);
|
|
74127
74343
|
}
|
|
74128
|
-
optimizeNames(names,
|
|
74129
|
-
if (!super.optimizeNames(names,
|
|
74344
|
+
optimizeNames(names, constants10) {
|
|
74345
|
+
if (!super.optimizeNames(names, constants10))
|
|
74130
74346
|
return;
|
|
74131
|
-
this.iteration = optimizeExpr(this.iteration, names,
|
|
74347
|
+
this.iteration = optimizeExpr(this.iteration, names, constants10);
|
|
74132
74348
|
return this;
|
|
74133
74349
|
}
|
|
74134
74350
|
get names() {
|
|
@@ -74166,10 +74382,10 @@ var require_codegen = __commonJS((exports) => {
|
|
|
74166
74382
|
render(opts) {
|
|
74167
74383
|
return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
|
|
74168
74384
|
}
|
|
74169
|
-
optimizeNames(names,
|
|
74170
|
-
if (!super.optimizeNames(names,
|
|
74385
|
+
optimizeNames(names, constants10) {
|
|
74386
|
+
if (!super.optimizeNames(names, constants10))
|
|
74171
74387
|
return;
|
|
74172
|
-
this.iterable = optimizeExpr(this.iterable, names,
|
|
74388
|
+
this.iterable = optimizeExpr(this.iterable, names, constants10);
|
|
74173
74389
|
return this;
|
|
74174
74390
|
}
|
|
74175
74391
|
get names() {
|
|
@@ -74214,11 +74430,11 @@ var require_codegen = __commonJS((exports) => {
|
|
|
74214
74430
|
(_b = this.finally) === null || _b === undefined || _b.optimizeNodes();
|
|
74215
74431
|
return this;
|
|
74216
74432
|
}
|
|
74217
|
-
optimizeNames(names,
|
|
74433
|
+
optimizeNames(names, constants10) {
|
|
74218
74434
|
var _a, _b;
|
|
74219
|
-
super.optimizeNames(names,
|
|
74220
|
-
(_a = this.catch) === null || _a === undefined || _a.optimizeNames(names,
|
|
74221
|
-
(_b = this.finally) === null || _b === undefined || _b.optimizeNames(names,
|
|
74435
|
+
super.optimizeNames(names, constants10);
|
|
74436
|
+
(_a = this.catch) === null || _a === undefined || _a.optimizeNames(names, constants10);
|
|
74437
|
+
(_b = this.finally) === null || _b === undefined || _b.optimizeNames(names, constants10);
|
|
74222
74438
|
return this;
|
|
74223
74439
|
}
|
|
74224
74440
|
get names() {
|
|
@@ -74492,7 +74708,7 @@ var require_codegen = __commonJS((exports) => {
|
|
|
74492
74708
|
function addExprNames(names, from) {
|
|
74493
74709
|
return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
|
|
74494
74710
|
}
|
|
74495
|
-
function optimizeExpr(expr, names,
|
|
74711
|
+
function optimizeExpr(expr, names, constants10) {
|
|
74496
74712
|
if (expr instanceof code_1.Name)
|
|
74497
74713
|
return replaceName(expr);
|
|
74498
74714
|
if (!canOptimize(expr))
|
|
@@ -74507,14 +74723,14 @@ var require_codegen = __commonJS((exports) => {
|
|
|
74507
74723
|
return items;
|
|
74508
74724
|
}, []));
|
|
74509
74725
|
function replaceName(n) {
|
|
74510
|
-
const c =
|
|
74726
|
+
const c = constants10[n.str];
|
|
74511
74727
|
if (c === undefined || names[n.str] !== 1)
|
|
74512
74728
|
return n;
|
|
74513
74729
|
delete names[n.str];
|
|
74514
74730
|
return c;
|
|
74515
74731
|
}
|
|
74516
74732
|
function canOptimize(e) {
|
|
74517
|
-
return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 &&
|
|
74733
|
+
return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants10[c.str] !== undefined);
|
|
74518
74734
|
}
|
|
74519
74735
|
}
|
|
74520
74736
|
function subtractNames(names, from) {
|
|
@@ -76419,7 +76635,7 @@ var require_compile = __commonJS((exports) => {
|
|
|
76419
76635
|
const schOrFunc = root.refs[ref];
|
|
76420
76636
|
if (schOrFunc)
|
|
76421
76637
|
return schOrFunc;
|
|
76422
|
-
let _sch =
|
|
76638
|
+
let _sch = resolve12.call(this, root, ref);
|
|
76423
76639
|
if (_sch === undefined) {
|
|
76424
76640
|
const schema = (_a = root.localRefs) === null || _a === undefined ? undefined : _a[ref];
|
|
76425
76641
|
const { schemaId } = this.opts;
|
|
@@ -76446,7 +76662,7 @@ var require_compile = __commonJS((exports) => {
|
|
|
76446
76662
|
function sameSchemaEnv(s1, s2) {
|
|
76447
76663
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
76448
76664
|
}
|
|
76449
|
-
function
|
|
76665
|
+
function resolve12(root, ref) {
|
|
76450
76666
|
let sch;
|
|
76451
76667
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
76452
76668
|
ref = sch;
|
|
@@ -77248,7 +77464,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
77248
77464
|
}
|
|
77249
77465
|
return uri;
|
|
77250
77466
|
}
|
|
77251
|
-
function
|
|
77467
|
+
function resolve12(baseURI, relativeURI, options) {
|
|
77252
77468
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
77253
77469
|
const {
|
|
77254
77470
|
parsed: baseParsed,
|
|
@@ -77618,7 +77834,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
77618
77834
|
var fastUri = {
|
|
77619
77835
|
SCHEMES,
|
|
77620
77836
|
normalize: normalize3,
|
|
77621
|
-
resolve:
|
|
77837
|
+
resolve: resolve12,
|
|
77622
77838
|
resolveComponent,
|
|
77623
77839
|
equal,
|
|
77624
77840
|
serialize,
|
|
@@ -81404,7 +81620,7 @@ class McpServer {
|
|
|
81404
81620
|
let task = createTaskResult.task;
|
|
81405
81621
|
const pollInterval = task.pollInterval ?? 5000;
|
|
81406
81622
|
while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
|
|
81407
|
-
await new Promise((
|
|
81623
|
+
await new Promise((resolve12) => setTimeout(resolve12, pollInterval));
|
|
81408
81624
|
const updatedTask = await extra.taskStore.getTask(taskId);
|
|
81409
81625
|
if (!updatedTask) {
|
|
81410
81626
|
throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
|
|
@@ -83314,7 +83530,7 @@ var init_run_routing = __esm(() => {
|
|
|
83314
83530
|
|
|
83315
83531
|
// src/mcp/operation-tools.ts
|
|
83316
83532
|
import { existsSync as existsSync28, readdirSync as readdirSync18, statSync as statSync16 } from "fs";
|
|
83317
|
-
import { join as
|
|
83533
|
+
import { join as join37 } from "path";
|
|
83318
83534
|
function registerOperationTools(server) {
|
|
83319
83535
|
server.registerTool("scaffold_skill", {
|
|
83320
83536
|
title: "Scaffold Skill",
|
|
@@ -83779,7 +83995,7 @@ function registerOperationTools(server) {
|
|
|
83779
83995
|
if (exists) {
|
|
83780
83996
|
try {
|
|
83781
83997
|
skillCount = readdirSync18(agentSkillsPath).filter((f) => {
|
|
83782
|
-
const full =
|
|
83998
|
+
const full = join37(agentSkillsPath, f);
|
|
83783
83999
|
return !f.startsWith(".") && statSync16(full).isDirectory();
|
|
83784
84000
|
}).length;
|
|
83785
84001
|
} catch {}
|
|
@@ -83847,14 +84063,14 @@ var init_operation_tools = __esm(() => {
|
|
|
83847
84063
|
|
|
83848
84064
|
// src/lib/feedback.ts
|
|
83849
84065
|
import { appendFileSync as appendFileSync2, existsSync as existsSync29, mkdirSync as mkdirSync15 } from "fs";
|
|
83850
|
-
import { dirname as
|
|
84066
|
+
import { dirname as dirname15, join as join38 } from "path";
|
|
83851
84067
|
import { Database } from "bun:sqlite";
|
|
83852
84068
|
function getFeedbackDbPath() {
|
|
83853
|
-
return
|
|
84069
|
+
return join38(getDataDir(), "skills.db");
|
|
83854
84070
|
}
|
|
83855
84071
|
function getFeedbackDb() {
|
|
83856
84072
|
const dbPath = getFeedbackDbPath();
|
|
83857
|
-
const dir =
|
|
84073
|
+
const dir = dirname15(dbPath);
|
|
83858
84074
|
if (!existsSync29(dir))
|
|
83859
84075
|
mkdirSync15(dir, { recursive: true });
|
|
83860
84076
|
const db = new Database(dbPath);
|
|
@@ -83882,8 +84098,8 @@ function saveFeedback(input) {
|
|
|
83882
84098
|
throw new Error("Feedback message is required");
|
|
83883
84099
|
const category = input.category ?? "general";
|
|
83884
84100
|
if (isApiMode()) {
|
|
83885
|
-
const path =
|
|
83886
|
-
const dir =
|
|
84101
|
+
const path = join38(getDataDir(), "feedback.jsonl");
|
|
84102
|
+
const dir = dirname15(path);
|
|
83887
84103
|
if (!existsSync29(dir))
|
|
83888
84104
|
mkdirSync15(dir, { recursive: true });
|
|
83889
84105
|
appendFileSync2(path, JSON.stringify({ message, category, email: input.email ?? null, agent: input.agent ?? null, version: input.version ?? null, createdAt: new Date().toISOString() }) + `
|
|
@@ -84047,9 +84263,9 @@ var init_resource_meta_tools = __esm(() => {
|
|
|
84047
84263
|
|
|
84048
84264
|
// src/lib/scheduler.ts
|
|
84049
84265
|
import { existsSync as existsSync30, readFileSync as readFileSync28, writeFileSync as writeFileSync15, mkdirSync as mkdirSync16 } from "fs";
|
|
84050
|
-
import { join as
|
|
84266
|
+
import { join as join39 } from "path";
|
|
84051
84267
|
function getSchedulesPath(targetDir = process.cwd()) {
|
|
84052
|
-
return
|
|
84268
|
+
return join39(targetDir, ".skills", "schedules.json");
|
|
84053
84269
|
}
|
|
84054
84270
|
function loadSchedules(targetDir = process.cwd()) {
|
|
84055
84271
|
const path = getSchedulesPath(targetDir);
|
|
@@ -84062,7 +84278,7 @@ function loadSchedules(targetDir = process.cwd()) {
|
|
|
84062
84278
|
}
|
|
84063
84279
|
function saveSchedules(data, targetDir = process.cwd()) {
|
|
84064
84280
|
const path = getSchedulesPath(targetDir);
|
|
84065
|
-
const dir =
|
|
84281
|
+
const dir = join39(targetDir, ".skills");
|
|
84066
84282
|
if (!existsSync30(dir))
|
|
84067
84283
|
mkdirSync16(dir, { recursive: true });
|
|
84068
84284
|
writeFileSync15(path, JSON.stringify(data, null, 2));
|
|
@@ -84361,7 +84577,7 @@ var init_schedule_tools = __esm(() => {
|
|
|
84361
84577
|
});
|
|
84362
84578
|
|
|
84363
84579
|
// src/lib/native-storage.ts
|
|
84364
|
-
import { createHash as
|
|
84580
|
+
import { createHash as createHash14, createHmac as createHmac3 } from "crypto";
|
|
84365
84581
|
import {
|
|
84366
84582
|
existsSync as existsSync31,
|
|
84367
84583
|
mkdirSync as mkdirSync17,
|
|
@@ -84370,7 +84586,7 @@ import {
|
|
|
84370
84586
|
statSync as statSync17,
|
|
84371
84587
|
writeFileSync as writeFileSync16
|
|
84372
84588
|
} from "fs";
|
|
84373
|
-
import { dirname as
|
|
84589
|
+
import { dirname as dirname16, join as join40, normalize as normalize3, relative as relative6, sep as sep5 } from "path";
|
|
84374
84590
|
function resolveSkillsNativeStorageConfig(env3 = process.env) {
|
|
84375
84591
|
assertNoRetiredModeEnvVars(env3, {
|
|
84376
84592
|
app: SKILLS_ENV_NAMESPACE,
|
|
@@ -84411,7 +84627,7 @@ function getSkillsNativeStorageStatus(options = {}) {
|
|
|
84411
84627
|
local: {
|
|
84412
84628
|
dataDir: getDataDir(),
|
|
84413
84629
|
projectStateDir: getProjectStateDir(targetDir),
|
|
84414
|
-
feedbackDbPath:
|
|
84630
|
+
feedbackDbPath: join40(getDataDir(), "skills.db")
|
|
84415
84631
|
},
|
|
84416
84632
|
remote: {
|
|
84417
84633
|
databaseConfigured: Boolean(config2.databaseUrl),
|
|
@@ -84438,7 +84654,7 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
|
|
|
84438
84654
|
files.push({
|
|
84439
84655
|
path: relativePath,
|
|
84440
84656
|
sizeBytes: bytes.byteLength,
|
|
84441
|
-
sha256:
|
|
84657
|
+
sha256: createHash14("sha256").update(bytes).digest("hex"),
|
|
84442
84658
|
...options.includeFileContents ? { contentBase64: Buffer.from(bytes).toString("base64") } : {}
|
|
84443
84659
|
});
|
|
84444
84660
|
}
|
|
@@ -84492,7 +84708,7 @@ function parsePositiveInteger(value) {
|
|
|
84492
84708
|
function walkFiles2(dir) {
|
|
84493
84709
|
const files = [];
|
|
84494
84710
|
for (const entry of readdirSync19(dir)) {
|
|
84495
|
-
const full =
|
|
84711
|
+
const full = join40(dir, entry);
|
|
84496
84712
|
const stats = statSync17(full);
|
|
84497
84713
|
if (stats.isDirectory())
|
|
84498
84714
|
files.push(...walkFiles2(full));
|
|
@@ -84717,7 +84933,7 @@ var init_remote_invitation_recovery = __esm(() => {
|
|
|
84717
84933
|
});
|
|
84718
84934
|
|
|
84719
84935
|
// src/lib/remote-private-publications.ts
|
|
84720
|
-
import { createHash as
|
|
84936
|
+
import { createHash as createHash15 } from "crypto";
|
|
84721
84937
|
function checkedPublicationDeclaration(value) {
|
|
84722
84938
|
if (!exact(value, ["idempotencyKey", "version", "expectedCurrentVersionId", "manifestText", "archiveSha256", "archiveByteSize"]) || !publicationUuid(value.idempotencyKey) || !(value.expectedCurrentVersionId === null || publicationUuid(value.expectedCurrentVersionId)) || typeof value.version !== "string" || !value.version || value.version.length > 128 || /[\p{Cc}\p{Cs}]/u.test(value.version) || typeof value.manifestText !== "string" || Buffer.byteLength(value.manifestText) > 16384 || !hash2(value.archiveSha256) || !Number.isSafeInteger(value.archiveByteSize) || Number(value.archiveByteSize) < 1 || Number(value.archiveByteSize) > PRIVATE_PUBLICATION_MAX_BYTES)
|
|
84723
84939
|
return bad();
|
|
@@ -84962,12 +85178,12 @@ class RemotePrivatePublicationsClient {
|
|
|
84962
85178
|
previous = view;
|
|
84963
85179
|
if (!["queued", "verifying"].includes(view.state) || Date.now() >= until)
|
|
84964
85180
|
return view;
|
|
84965
|
-
await new Promise((
|
|
85181
|
+
await new Promise((resolve12) => {
|
|
84966
85182
|
const timer = setTimeout(done, Math.min(1000, until - Date.now()));
|
|
84967
85183
|
function done() {
|
|
84968
85184
|
clearTimeout(timer);
|
|
84969
85185
|
options.signal?.removeEventListener("abort", done);
|
|
84970
|
-
|
|
85186
|
+
resolve12();
|
|
84971
85187
|
}
|
|
84972
85188
|
options.signal?.addEventListener("abort", done, { once: true });
|
|
84973
85189
|
});
|
|
@@ -84978,7 +85194,7 @@ var PRIVATE_PUBLICATION_MAX_BYTES, failures, PrivatePublicationError, bad = () =
|
|
|
84978
85194
|
throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Invalid publication input or recovery data.");
|
|
84979
85195
|
}, invalid4 = () => {
|
|
84980
85196
|
throw new PrivatePublicationError("INVALID_PUBLICATION_RESPONSE", "The server returned an invalid publication result.");
|
|
84981
|
-
}, publicationUuid = (v) => typeof v === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(v), hash2 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v), record8 = (v) => !!v && typeof v === "object" && !Array.isArray(v), exact = (v, keys2) => record8(v) && Object.keys(v).sort().join(",") === keys2.sort().join(","), date4 = (v) => typeof v === "string" && /^\d{4}-\d\d-\d\dT[0-9:.]+(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.test(v) && Number.isFinite(Date.parse(v)), publicationSha256 = (bytes) =>
|
|
85197
|
+
}, publicationUuid = (v) => typeof v === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(v), hash2 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v), record8 = (v) => !!v && typeof v === "object" && !Array.isArray(v), exact = (v, keys2) => record8(v) && Object.keys(v).sort().join(",") === keys2.sort().join(","), date4 = (v) => typeof v === "string" && /^\d{4}-\d\d-\d\dT[0-9:.]+(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.test(v) && Number.isFinite(Date.parse(v)), publicationSha256 = (bytes) => createHash15("sha256").update(bytes).digest("hex");
|
|
84982
85198
|
var init_remote_private_publications = __esm(() => {
|
|
84983
85199
|
init_fleet_credentials();
|
|
84984
85200
|
init_remote_workspace_selection();
|
|
@@ -85255,11 +85471,11 @@ var init_remote_auth = __esm(() => {
|
|
|
85255
85471
|
});
|
|
85256
85472
|
|
|
85257
85473
|
// src/lib/workspace-profile.ts
|
|
85258
|
-
import { constants as
|
|
85259
|
-
import { dirname as
|
|
85474
|
+
import { constants as constants10, closeSync as closeSync10, fstatSync as fstatSync10, lstatSync as lstatSync16, mkdirSync as mkdirSync18, mkdtempSync as mkdtempSync5, openSync as openSync10, readFileSync as readFileSync30, renameSync as renameSync8, rmSync as rmSync7, writeFileSync as writeFileSync17 } from "fs";
|
|
85475
|
+
import { dirname as dirname17, join as join41 } from "path";
|
|
85260
85476
|
function stat(path) {
|
|
85261
85477
|
try {
|
|
85262
|
-
return
|
|
85478
|
+
return lstatSync16(path);
|
|
85263
85479
|
} catch (error2) {
|
|
85264
85480
|
if (error2.code === "ENOENT")
|
|
85265
85481
|
return null;
|
|
@@ -85269,14 +85485,14 @@ function stat(path) {
|
|
|
85269
85485
|
function safeText(file) {
|
|
85270
85486
|
if (stat(file) === null)
|
|
85271
85487
|
return null;
|
|
85272
|
-
const fd =
|
|
85488
|
+
const fd = openSync10(file, constants10.O_RDONLY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK);
|
|
85273
85489
|
try {
|
|
85274
|
-
const s =
|
|
85490
|
+
const s = fstatSync10(fd);
|
|
85275
85491
|
if (!s.isFile() || s.size > 65536 || ![256, 384].includes(s.mode & 4095) || process.getuid && s.uid !== process.getuid())
|
|
85276
85492
|
return fail2("The selected profile must use bounded owner-only regular files.");
|
|
85277
85493
|
return readFileSync30(fd, "utf8");
|
|
85278
85494
|
} finally {
|
|
85279
|
-
|
|
85495
|
+
closeSync10(fd);
|
|
85280
85496
|
}
|
|
85281
85497
|
}
|
|
85282
85498
|
function checkIdentityMetadata(file, identity3) {
|
|
@@ -85342,12 +85558,12 @@ async function prepareWorkspaceEnrollment(membershipId, source = process.env) {
|
|
|
85342
85558
|
if (Buffer.byteLength(credentialBody("x".repeat(8192)), "utf8") > 65536)
|
|
85343
85559
|
return fail2("The selected profile has insufficient space for a bounded credential. Reduce its unrelated configuration before signing in.");
|
|
85344
85560
|
const parents = [];
|
|
85345
|
-
for (let path =
|
|
85561
|
+
for (let path = dirname17(file);; path = dirname17(path)) {
|
|
85346
85562
|
const before2 = stat(path);
|
|
85347
85563
|
if (before2 && (!before2.isDirectory() || before2.isSymbolicLink()))
|
|
85348
85564
|
return fail2("The profile directory must not be a symbolic link.");
|
|
85349
85565
|
parents.push([path, before2]);
|
|
85350
|
-
if (path ===
|
|
85566
|
+
if (path === dirname17(path))
|
|
85351
85567
|
break;
|
|
85352
85568
|
}
|
|
85353
85569
|
const unchanged2 = () => {
|
|
@@ -85406,12 +85622,12 @@ async function prepareWorkspaceEnrollment(membershipId, source = process.env) {
|
|
|
85406
85622
|
return fail2("The new profile exceeds the credential reader size limit.");
|
|
85407
85623
|
const identity3 = JSON.stringify({ email: verified.user.email, userId: verified.user.id, orgId: verified.organization.id, orgSlug: verified.organization.slug, apiUrl: origin }, null, 2) + `
|
|
85408
85624
|
`;
|
|
85409
|
-
mkdirSync18(
|
|
85410
|
-
const temp = mkdtempSync5(
|
|
85625
|
+
mkdirSync18(dirname17(file), { recursive: true, mode: 448 });
|
|
85626
|
+
const temp = mkdtempSync5(join41(dirname17(file), ".workspace-login-"));
|
|
85411
85627
|
let identityInstalled = false;
|
|
85412
85628
|
try {
|
|
85413
|
-
writeFileSync17(
|
|
85414
|
-
writeFileSync17(
|
|
85629
|
+
writeFileSync17(join41(temp, "credentials"), body, { mode: 384, flag: "wx" });
|
|
85630
|
+
writeFileSync17(join41(temp, "identity"), identity3, { mode: 384, flag: "wx" });
|
|
85415
85631
|
unchangedFiles();
|
|
85416
85632
|
for (const [path, before2] of parents) {
|
|
85417
85633
|
const now3 = stat(path);
|
|
@@ -85420,16 +85636,16 @@ async function prepareWorkspaceEnrollment(membershipId, source = process.env) {
|
|
|
85420
85636
|
if (!before2 && now3 && ((now3.mode & 63) !== 0 || process.getuid && now3.uid !== process.getuid()))
|
|
85421
85637
|
changed();
|
|
85422
85638
|
}
|
|
85423
|
-
renameSync8(
|
|
85639
|
+
renameSync8(join41(temp, "identity"), identityFile);
|
|
85424
85640
|
identityInstalled = true;
|
|
85425
|
-
renameSync8(
|
|
85641
|
+
renameSync8(join41(temp, "credentials"), file);
|
|
85426
85642
|
} catch (error2) {
|
|
85427
85643
|
if (identityInstalled) {
|
|
85428
85644
|
if (oldIdentity === null)
|
|
85429
85645
|
rmSync7(identityFile, { force: true });
|
|
85430
85646
|
else {
|
|
85431
|
-
writeFileSync17(
|
|
85432
|
-
renameSync8(
|
|
85647
|
+
writeFileSync17(join41(temp, "restore"), oldIdentity, { mode: 384, flag: "wx" });
|
|
85648
|
+
renameSync8(join41(temp, "restore"), identityFile);
|
|
85433
85649
|
}
|
|
85434
85650
|
}
|
|
85435
85651
|
throw error2;
|
|
@@ -85587,20 +85803,20 @@ var init_private_publication_customer = __esm(() => {
|
|
|
85587
85803
|
});
|
|
85588
85804
|
|
|
85589
85805
|
// src/lib/private-publication-recovery.ts
|
|
85590
|
-
import { constants as
|
|
85591
|
-
import { dirname as
|
|
85806
|
+
import { constants as constants11, closeSync as closeSync11, fsyncSync as fsyncSync2, fstatSync as fstatSync11, lstatSync as lstatSync17, mkdirSync as mkdirSync19, openSync as openSync11, readSync as readSync8, realpathSync as realpathSync5, renameSync as renameSync9, unlinkSync as unlinkSync5, writeFileSync as writeFileSync18 } from "fs";
|
|
85807
|
+
import { dirname as dirname18, isAbsolute as isAbsolute9, join as join42, resolve as resolve12 } from "path";
|
|
85592
85808
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
85593
85809
|
function safeDirectory(directory) {
|
|
85594
|
-
if (!
|
|
85810
|
+
if (!isAbsolute9(directory) || directory !== resolve12(directory) || realpathSync5(directory) !== directory)
|
|
85595
85811
|
return fail3();
|
|
85596
|
-
for (let path = directory;; path =
|
|
85597
|
-
const stat2 =
|
|
85812
|
+
for (let path = directory;; path = dirname18(path)) {
|
|
85813
|
+
const stat2 = lstatSync17(path);
|
|
85598
85814
|
if (!stat2.isDirectory() || stat2.isSymbolicLink())
|
|
85599
85815
|
return fail3();
|
|
85600
|
-
if (path ===
|
|
85816
|
+
if (path === dirname18(path))
|
|
85601
85817
|
break;
|
|
85602
85818
|
}
|
|
85603
|
-
const own =
|
|
85819
|
+
const own = lstatSync17(directory);
|
|
85604
85820
|
if ((own.mode & 63) !== 0 || process.getuid && own.uid !== process.getuid())
|
|
85605
85821
|
return fail3();
|
|
85606
85822
|
return { dev: own.dev, ino: own.ino };
|
|
@@ -85611,36 +85827,36 @@ function unchangedDirectory(directory, identity3) {
|
|
|
85611
85827
|
return fail3();
|
|
85612
85828
|
}
|
|
85613
85829
|
function readOwned(directory, name, max2) {
|
|
85614
|
-
const identity3 = safeDirectory(directory), file =
|
|
85615
|
-
const fd =
|
|
85830
|
+
const identity3 = safeDirectory(directory), file = join42(directory, name);
|
|
85831
|
+
const fd = openSync11(file, constants11.O_RDONLY | constants11.O_NOFOLLOW);
|
|
85616
85832
|
try {
|
|
85617
|
-
const stat2 =
|
|
85833
|
+
const stat2 = fstatSync11(fd);
|
|
85618
85834
|
if (!stat2.isFile() || stat2.nlink !== 1 || stat2.size > max2 || stat2.size < 1 || (stat2.mode & 63) !== 0 || process.getuid && stat2.uid !== process.getuid())
|
|
85619
85835
|
return fail3();
|
|
85620
85836
|
const buffer = Buffer.alloc(Math.min(max2, stat2.size) + 1);
|
|
85621
85837
|
let length = 0;
|
|
85622
85838
|
while (length < buffer.length) {
|
|
85623
|
-
const count =
|
|
85839
|
+
const count = readSync8(fd, buffer, length, buffer.length - length, length);
|
|
85624
85840
|
if (count === 0)
|
|
85625
85841
|
break;
|
|
85626
85842
|
length += count;
|
|
85627
85843
|
}
|
|
85628
|
-
const bytes = buffer.subarray(0, length), after2 =
|
|
85844
|
+
const bytes = buffer.subarray(0, length), after2 = fstatSync11(fd);
|
|
85629
85845
|
unchangedDirectory(directory, identity3);
|
|
85630
85846
|
if (bytes.length !== stat2.size || stat2.size !== after2.size || stat2.mtimeMs !== after2.mtimeMs || stat2.ctimeMs !== after2.ctimeMs)
|
|
85631
85847
|
return fail3();
|
|
85632
85848
|
return bytes;
|
|
85633
85849
|
} finally {
|
|
85634
|
-
|
|
85850
|
+
closeSync11(fd);
|
|
85635
85851
|
}
|
|
85636
85852
|
}
|
|
85637
85853
|
function writeOwned(directory, name, bytes) {
|
|
85638
|
-
const fd =
|
|
85854
|
+
const fd = openSync11(join42(directory, name), constants11.O_WRONLY | constants11.O_CREAT | constants11.O_EXCL | constants11.O_NOFOLLOW, 384);
|
|
85639
85855
|
try {
|
|
85640
85856
|
writeFileSync18(fd, bytes);
|
|
85641
85857
|
fsyncSync2(fd);
|
|
85642
85858
|
} finally {
|
|
85643
|
-
|
|
85859
|
+
closeSync11(fd);
|
|
85644
85860
|
}
|
|
85645
85861
|
}
|
|
85646
85862
|
function save(directory, value) {
|
|
@@ -85648,12 +85864,12 @@ function save(directory, value) {
|
|
|
85648
85864
|
writeOwned(directory, temporary, JSON.stringify(value) + `
|
|
85649
85865
|
`);
|
|
85650
85866
|
unchangedDirectory(directory, identity3);
|
|
85651
|
-
renameSync9(
|
|
85652
|
-
const fd =
|
|
85867
|
+
renameSync9(join42(directory, temporary), join42(directory, "receipt.json"));
|
|
85868
|
+
const fd = openSync11(directory, constants11.O_RDONLY | constants11.O_NOFOLLOW);
|
|
85653
85869
|
try {
|
|
85654
85870
|
fsyncSync2(fd);
|
|
85655
85871
|
} finally {
|
|
85656
|
-
|
|
85872
|
+
closeSync11(fd);
|
|
85657
85873
|
}
|
|
85658
85874
|
}
|
|
85659
85875
|
function bind2(client, receipt) {
|
|
@@ -85661,23 +85877,23 @@ function bind2(client, receipt) {
|
|
|
85661
85877
|
throw new PrivatePublicationError("PUBLICATION_IDENTITY_CHANGED", "The fresh session does not match the recovery directory's server, account and membership.");
|
|
85662
85878
|
}
|
|
85663
85879
|
async function locked(directory, action) {
|
|
85664
|
-
const identity3 = safeDirectory(directory), file =
|
|
85880
|
+
const identity3 = safeDirectory(directory), file = join42(directory, "operation.lock");
|
|
85665
85881
|
let fd;
|
|
85666
85882
|
try {
|
|
85667
|
-
fd =
|
|
85883
|
+
fd = openSync11(file, constants11.O_WRONLY | constants11.O_CREAT | constants11.O_EXCL | constants11.O_NOFOLLOW, 384);
|
|
85668
85884
|
} catch {
|
|
85669
85885
|
throw new PrivatePublicationError("PUBLICATION_RECOVERY_BUSY", "Another operation holds this recovery directory. If it crashed, confirm that process has stopped before explicitly removing operation.lock and resuming.");
|
|
85670
85886
|
}
|
|
85671
|
-
const lock =
|
|
85887
|
+
const lock = fstatSync11(fd);
|
|
85672
85888
|
try {
|
|
85673
85889
|
writeFileSync18(fd, JSON.stringify({ pid: process.pid }) + `
|
|
85674
85890
|
`);
|
|
85675
85891
|
fsyncSync2(fd);
|
|
85676
85892
|
return await action();
|
|
85677
85893
|
} finally {
|
|
85678
|
-
|
|
85894
|
+
closeSync11(fd);
|
|
85679
85895
|
unchangedDirectory(directory, identity3);
|
|
85680
|
-
const now3 =
|
|
85896
|
+
const now3 = lstatSync17(file);
|
|
85681
85897
|
if (now3.dev !== lock.dev || now3.ino !== lock.ino || !now3.isFile() || now3.isSymbolicLink())
|
|
85682
85898
|
fail3();
|
|
85683
85899
|
unlinkSync5(file);
|
|
@@ -85729,15 +85945,15 @@ async function preparePrivatePublication(client, sourceDirectory, recoveryDirect
|
|
|
85729
85945
|
phase: "prepared",
|
|
85730
85946
|
intent: null
|
|
85731
85947
|
};
|
|
85732
|
-
if (!
|
|
85948
|
+
if (!isAbsolute9(recoveryDirectory) || resolve12(recoveryDirectory) !== recoveryDirectory || realpathSync5(dirname18(recoveryDirectory)) !== dirname18(recoveryDirectory))
|
|
85733
85949
|
return fail3();
|
|
85734
85950
|
mkdirSync19(recoveryDirectory, { mode: 448 });
|
|
85735
85951
|
safeDirectory(recoveryDirectory);
|
|
85736
|
-
const parent =
|
|
85952
|
+
const parent = openSync11(dirname18(recoveryDirectory), constants11.O_RDONLY | constants11.O_NOFOLLOW);
|
|
85737
85953
|
try {
|
|
85738
85954
|
fsyncSync2(parent);
|
|
85739
85955
|
} finally {
|
|
85740
|
-
|
|
85956
|
+
closeSync11(parent);
|
|
85741
85957
|
}
|
|
85742
85958
|
writeOwned(recoveryDirectory, "bundle.tgz", packed.bytes);
|
|
85743
85959
|
save(recoveryDirectory, receipt);
|
|
@@ -85830,10 +86046,10 @@ var init_private_publication_recovery = __esm(() => {
|
|
|
85830
86046
|
});
|
|
85831
86047
|
|
|
85832
86048
|
// src/mcp/private-publication-tools.ts
|
|
85833
|
-
import { isAbsolute as
|
|
86049
|
+
import { isAbsolute as isAbsolute10 } from "path";
|
|
85834
86050
|
function registerPrivatePublicationTools(server) {
|
|
85835
86051
|
const uuid6 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
|
|
85836
|
-
const directory = exports_external.string().max(4096).refine(
|
|
86052
|
+
const directory = exports_external.string().max(4096).refine(isAbsolute10, "Use an absolute local directory");
|
|
85837
86053
|
const verification = { email: exports_external.string().email().max(254), code: exports_external.string().regex(/^\d{6}$/), userId: uuid6, membershipId: uuid6, recoveryDirectory: directory };
|
|
85838
86054
|
const description = "Manage a private source publication using fresh workspace-bound verification and a host-local recovery directory. Publishing requires explicit UUID current-version comparison and upload consent. Resume reuses immutable saved bytes and intent; an uncertain PUT is finalized for server verification, never uploaded twice. Sessions and signed URLs are not returned or persisted. Private execution is unavailable. Host request history may contain the supplied verification code.";
|
|
85839
86055
|
const handler = (action) => async (value) => {
|
|
@@ -86143,7 +86359,7 @@ var init_mcp2 = __esm(() => {
|
|
|
86143
86359
|
// src/cli/commands/runtime-mcp.ts
|
|
86144
86360
|
import { existsSync as existsSync32, mkdirSync as mkdirSync20, readFileSync as readFileSync31, writeFileSync as writeFileSync19 } from "fs";
|
|
86145
86361
|
import { homedir as homedir8 } from "os";
|
|
86146
|
-
import { dirname as
|
|
86362
|
+
import { dirname as dirname19, join as join43 } from "path";
|
|
86147
86363
|
async function handleMcp(options) {
|
|
86148
86364
|
if (options.register) {
|
|
86149
86365
|
let agents;
|
|
@@ -86186,24 +86402,24 @@ async function registerMcpForAgent(agent, command) {
|
|
|
86186
86402
|
case "codex":
|
|
86187
86403
|
return registerCodexMcp(command);
|
|
86188
86404
|
case "gemini":
|
|
86189
|
-
return registerJsonMcpServer(agent,
|
|
86405
|
+
return registerJsonMcpServer(agent, join43(homedir8(), ".gemini", "settings.json"), "mcpServers", {
|
|
86190
86406
|
command,
|
|
86191
86407
|
args: []
|
|
86192
86408
|
});
|
|
86193
86409
|
case "pi":
|
|
86194
|
-
return registerJsonMcpServer(agent,
|
|
86410
|
+
return registerJsonMcpServer(agent, join43(homedir8(), ".pi", "agent", "mcp.json"), "mcpServers", {
|
|
86195
86411
|
command,
|
|
86196
86412
|
args: []
|
|
86197
86413
|
});
|
|
86198
86414
|
case "opencode":
|
|
86199
86415
|
return registerOpenCodeMcp(command);
|
|
86200
86416
|
case "cursor":
|
|
86201
|
-
return registerJsonMcpServer(agent,
|
|
86417
|
+
return registerJsonMcpServer(agent, join43(homedir8(), ".cursor", "mcp.json"), "mcpServers", {
|
|
86202
86418
|
command,
|
|
86203
86419
|
args: []
|
|
86204
86420
|
});
|
|
86205
86421
|
case "windsurf":
|
|
86206
|
-
return registerJsonMcpServer(agent,
|
|
86422
|
+
return registerJsonMcpServer(agent, join43(homedir8(), ".windsurf", "mcp.json"), "mcpServers", {
|
|
86207
86423
|
command,
|
|
86208
86424
|
args: []
|
|
86209
86425
|
});
|
|
@@ -86226,7 +86442,7 @@ async function registerClaudeMcp(command) {
|
|
|
86226
86442
|
if (exitCode === 0) {
|
|
86227
86443
|
return { agent: "claude", success: true, command: cliCommand };
|
|
86228
86444
|
}
|
|
86229
|
-
const fallback = registerJsonMcpServer("claude",
|
|
86445
|
+
const fallback = registerJsonMcpServer("claude", join43(homedir8(), ".claude", ".mcp.json"), "mcpServers", {
|
|
86230
86446
|
command,
|
|
86231
86447
|
args: []
|
|
86232
86448
|
});
|
|
@@ -86236,7 +86452,7 @@ async function registerClaudeMcp(command) {
|
|
|
86236
86452
|
error: fallback.success ? undefined : `claude exited with ${exitCode}: ${(stderr || stdout).trim()}`
|
|
86237
86453
|
};
|
|
86238
86454
|
} catch (err) {
|
|
86239
|
-
const fallback = registerJsonMcpServer("claude",
|
|
86455
|
+
const fallback = registerJsonMcpServer("claude", join43(homedir8(), ".claude", ".mcp.json"), "mcpServers", {
|
|
86240
86456
|
command,
|
|
86241
86457
|
args: []
|
|
86242
86458
|
});
|
|
@@ -86248,7 +86464,7 @@ async function registerClaudeMcp(command) {
|
|
|
86248
86464
|
}
|
|
86249
86465
|
}
|
|
86250
86466
|
function registerCodexMcp(command) {
|
|
86251
|
-
const path =
|
|
86467
|
+
const path = join43(homedir8(), ".codex", "config.toml");
|
|
86252
86468
|
const config2 = `[mcp_servers.${MCP_SERVER_NAME}]
|
|
86253
86469
|
command = ${JSON.stringify(command)}`;
|
|
86254
86470
|
try {
|
|
@@ -86260,7 +86476,7 @@ command = ${JSON.stringify(command)}`;
|
|
|
86260
86476
|
}
|
|
86261
86477
|
}
|
|
86262
86478
|
function registerOpenCodeMcp(command) {
|
|
86263
|
-
const path =
|
|
86479
|
+
const path = join43(homedir8(), ".config", "opencode", "opencode.json");
|
|
86264
86480
|
const config2 = JSON.stringify({
|
|
86265
86481
|
$schema: "https://opencode.ai/config.json",
|
|
86266
86482
|
mcp: {
|
|
@@ -86317,7 +86533,7 @@ function writeJsonObject(path, data) {
|
|
|
86317
86533
|
`);
|
|
86318
86534
|
}
|
|
86319
86535
|
function writeTextFile(path, content) {
|
|
86320
|
-
mkdirSync20(
|
|
86536
|
+
mkdirSync20(dirname19(path), { recursive: true });
|
|
86321
86537
|
writeFileSync19(path, content.endsWith(`
|
|
86322
86538
|
`) ? content : `${content}
|
|
86323
86539
|
`);
|
|
@@ -86348,7 +86564,7 @@ function findCommandOnPath(command) {
|
|
|
86348
86564
|
for (const dir of pathValue.split(":")) {
|
|
86349
86565
|
if (!dir)
|
|
86350
86566
|
continue;
|
|
86351
|
-
const candidate =
|
|
86567
|
+
const candidate = join43(dir, command);
|
|
86352
86568
|
if (existsSync32(candidate))
|
|
86353
86569
|
return candidate;
|
|
86354
86570
|
}
|
|
@@ -86410,9 +86626,9 @@ var exports_runtime = {};
|
|
|
86410
86626
|
__export(exports_runtime, {
|
|
86411
86627
|
registerRuntime: () => registerRuntime
|
|
86412
86628
|
});
|
|
86413
|
-
import { createHash as
|
|
86414
|
-
import { lstatSync as
|
|
86415
|
-
import { basename as basename5, isAbsolute as
|
|
86629
|
+
import { createHash as createHash16, randomUUID as randomUUID7 } from "crypto";
|
|
86630
|
+
import { lstatSync as lstatSync18, mkdirSync as mkdirSync21, readFileSync as readFileSync32, realpathSync as realpathSync6, writeFileSync as writeFileSync20 } from "fs";
|
|
86631
|
+
import { basename as basename5, isAbsolute as isAbsolute11, join as join44 } from "path";
|
|
86416
86632
|
import { createInterface } from "readline";
|
|
86417
86633
|
function registerRuntime(parent) {
|
|
86418
86634
|
parent.command("run").argument("<skill>", "Skill name").argument("[args...]", "Arguments to pass to the skill").allowUnknownOption(true).passThroughOptions(true).option("--json", "Output result as JSON", false).option("--remote", "Run on the configured server, using its catalog and quote", false).option("--target <target>", "Execution target: local or cloud").option("--input <json>", "Structured cloud execution input").option("--skill-version <version>", "Exact selected skill version").option("--selection-profile <id>", "Selected Skills profile").option("--session <id>", "Pinned Skills session").option("--cached", "Use the explicit verified selected cache", false).option("--yes", "Approve the server's quoted credit cost for this run", false).option("--idempotency-key <key>", "Reuse this key when retrying the same remote submission").option("--file <path>", "Attach a local input file to a remote run (repeatable)", (value, prior) => [...prior, value], []).option("--wait", "Poll remote runs until a terminal status", false).option("--poll-interval-ms <ms>", "Remote polling interval in milliseconds", "1000").option("--poll-timeout-ms <ms>", "Maximum time to wait for a remote run", "300000").description("Run a skill directly").action(async (name, args2, options) => handleRun(name, args2, options));
|
|
@@ -86437,7 +86653,7 @@ function registerRuntime(parent) {
|
|
|
86437
86653
|
if (!expected)
|
|
86438
86654
|
throw new Error("Cloud artifact not found");
|
|
86439
86655
|
const bytes = await client.download(id, name);
|
|
86440
|
-
if (bytes.length !== expected.byteSize ||
|
|
86656
|
+
if (bytes.length !== expected.byteSize || createHash16("sha256").update(bytes).digest("hex") !== expected.sha256)
|
|
86441
86657
|
throw new Error("Cloud artifact integrity verification failed");
|
|
86442
86658
|
writeFileSync20(options.output, bytes, { flag: "wx", mode: 384 });
|
|
86443
86659
|
console.log(JSON.stringify({ path: options.output, sha256: expected.sha256, byteSize: bytes.length }));
|
|
@@ -86525,7 +86741,7 @@ Updating ${name}...
|
|
|
86525
86741
|
async function readUpdatedVersion(bunExecutable) {
|
|
86526
86742
|
const output = await readUpdateCommand([bunExecutable, "pm", "bin", "-g"]);
|
|
86527
86743
|
const globalBin = output.replace(/\r?\n$/, "");
|
|
86528
|
-
if (!globalBin || !
|
|
86744
|
+
if (!globalBin || !isAbsolute11(globalBin) || /[\r\n\0]/.test(globalBin))
|
|
86529
86745
|
throw new Error("Update bin discovery failed");
|
|
86530
86746
|
const installed = Bun.which("skills", { PATH: globalBin, cwd: globalBin });
|
|
86531
86747
|
const selected = Bun.which("skills");
|
|
@@ -86661,14 +86877,14 @@ function requireHttpUrl(value) {
|
|
|
86661
86877
|
}
|
|
86662
86878
|
function promptLine(question) {
|
|
86663
86879
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
86664
|
-
return new Promise((
|
|
86880
|
+
return new Promise((resolve13) => {
|
|
86665
86881
|
let settled = false;
|
|
86666
86882
|
const finish = (answer) => {
|
|
86667
86883
|
if (settled)
|
|
86668
86884
|
return;
|
|
86669
86885
|
settled = true;
|
|
86670
86886
|
rl.close();
|
|
86671
|
-
|
|
86887
|
+
resolve13(answer);
|
|
86672
86888
|
};
|
|
86673
86889
|
rl.once("SIGINT", () => finish(null));
|
|
86674
86890
|
rl.once("close", () => finish(null));
|
|
@@ -86829,7 +87045,7 @@ async function handleRun(name, args2, options) {
|
|
|
86829
87045
|
try {
|
|
86830
87046
|
parsePollingOptions(options);
|
|
86831
87047
|
inputFiles = (options.file ?? []).map((path) => {
|
|
86832
|
-
const info =
|
|
87048
|
+
const info = lstatSync18(path);
|
|
86833
87049
|
if (!info.isFile() || info.size > 20 * 1024 * 1024)
|
|
86834
87050
|
throw new Error("Input must be a regular file no larger than 20 MiB");
|
|
86835
87051
|
return { name: basename5(path), bytes: new Uint8Array(readFileSync32(path)) };
|
|
@@ -87218,7 +87434,7 @@ async function handleExportsDownload(runId2, options) {
|
|
|
87218
87434
|
continue;
|
|
87219
87435
|
const verified = await client.getVerifiedRunArtifact(runId2, artifactId);
|
|
87220
87436
|
const relativePath = safeArtifactRelativePath(typeof artifact.relativePath === "string" ? artifact.relativePath : artifact.fileName, String(artifact.fileName || artifactId));
|
|
87221
|
-
const outputPath =
|
|
87437
|
+
const outputPath = join44(exportDir, relativePath);
|
|
87222
87438
|
ensureSafeExportParent(exportDir, relativePath);
|
|
87223
87439
|
writeFileSync20(outputPath, verified.bytes, { flag: "wx", mode: 384 });
|
|
87224
87440
|
downloaded.push({ id: artifactId, path: outputPath, byteSize: verified.byteSize });
|
|
@@ -87257,9 +87473,9 @@ function ensureSafeExportParent(root, relativePath) {
|
|
|
87257
87473
|
let parent = root;
|
|
87258
87474
|
for (const part of ["", ...parts]) {
|
|
87259
87475
|
if (part)
|
|
87260
|
-
parent =
|
|
87476
|
+
parent = join44(parent, part);
|
|
87261
87477
|
try {
|
|
87262
|
-
if (!
|
|
87478
|
+
if (!lstatSync18(parent).isDirectory() || lstatSync18(parent).isSymbolicLink())
|
|
87263
87479
|
throw new Error("Unsafe artifact directory");
|
|
87264
87480
|
} catch (error2) {
|
|
87265
87481
|
if (error2.code !== "ENOENT")
|
|
@@ -87297,7 +87513,7 @@ async function pollRemoteRun(client, runId2, options) {
|
|
|
87297
87513
|
const remaining = deadline - Date.now();
|
|
87298
87514
|
if (remaining <= 0)
|
|
87299
87515
|
break;
|
|
87300
|
-
await new Promise((
|
|
87516
|
+
await new Promise((resolve13) => setTimeout(resolve13, Math.min(options.intervalMs, remaining)));
|
|
87301
87517
|
}
|
|
87302
87518
|
return {
|
|
87303
87519
|
run: current ?? { id: runId2, status: "queued" },
|
|
@@ -87611,7 +87827,7 @@ var init_completion = __esm(() => {
|
|
|
87611
87827
|
// src/lib/portable-snapshot-filter.ts
|
|
87612
87828
|
import { readdirSync as readdirSync20, statSync as statSync18 } from "fs";
|
|
87613
87829
|
import { homedir as homedir9 } from "os";
|
|
87614
|
-
import { join as
|
|
87830
|
+
import { join as join45, sep as sep6 } from "path";
|
|
87615
87831
|
function isExcludedSkillFileName(fileName) {
|
|
87616
87832
|
if (EXCLUDE_FILE_NAMES.has(fileName)) {
|
|
87617
87833
|
return true;
|
|
@@ -87634,16 +87850,16 @@ function isPortableWithinSkill(relativeParts) {
|
|
|
87634
87850
|
function homePathFor(definition, homesRoot) {
|
|
87635
87851
|
const home = homesRoot ?? homedir9();
|
|
87636
87852
|
if (definition.subClass === "skills" || definition.subClass === "custom") {
|
|
87637
|
-
return
|
|
87853
|
+
return join45(skillsDataRootForHome(home), definition.name);
|
|
87638
87854
|
}
|
|
87639
87855
|
if (definition.agent === "opencode") {
|
|
87640
|
-
return
|
|
87856
|
+
return join45(home, ".config", "opencode", "skills");
|
|
87641
87857
|
}
|
|
87642
|
-
return
|
|
87858
|
+
return join45(home, `.${definition.agent}`, "skills");
|
|
87643
87859
|
}
|
|
87644
87860
|
function destinationFor(definition, stationId, relativePath) {
|
|
87645
|
-
const category = definition.subClass === "agent-homes" ?
|
|
87646
|
-
return
|
|
87861
|
+
const category = definition.subClass === "agent-homes" ? join45("agent-homes", definition.agent ?? "") : definition.name;
|
|
87862
|
+
return join45("resources", stationId, "skills", category, ...relativePath.split(sep6));
|
|
87647
87863
|
}
|
|
87648
87864
|
function walkEntries(absoluteRoot) {
|
|
87649
87865
|
let entries;
|
|
@@ -87654,7 +87870,7 @@ function walkEntries(absoluteRoot) {
|
|
|
87654
87870
|
}
|
|
87655
87871
|
const output = [];
|
|
87656
87872
|
for (const entry of entries) {
|
|
87657
|
-
const childFull =
|
|
87873
|
+
const childFull = join45(absoluteRoot, entry.name);
|
|
87658
87874
|
if (entry.isSymbolicLink()) {
|
|
87659
87875
|
output.push({ kind: "symlink", relativePath: entry.name, fullPath: childFull });
|
|
87660
87876
|
continue;
|
|
@@ -87665,7 +87881,7 @@ function walkEntries(absoluteRoot) {
|
|
|
87665
87881
|
}
|
|
87666
87882
|
const nested = walkEntries(childFull);
|
|
87667
87883
|
for (const item of nested) {
|
|
87668
|
-
output.push({ ...item, relativePath:
|
|
87884
|
+
output.push({ ...item, relativePath: join45(entry.name, item.relativePath) });
|
|
87669
87885
|
}
|
|
87670
87886
|
continue;
|
|
87671
87887
|
}
|
|
@@ -87758,7 +87974,7 @@ var init_portable_snapshot_filter = __esm(() => {
|
|
|
87758
87974
|
});
|
|
87759
87975
|
|
|
87760
87976
|
// src/lib/station-snapshot.ts
|
|
87761
|
-
import { createHash as
|
|
87977
|
+
import { createHash as createHash17 } from "crypto";
|
|
87762
87978
|
import {
|
|
87763
87979
|
copyFileSync as copyFileSync2,
|
|
87764
87980
|
mkdirSync as mkdirSync22,
|
|
@@ -87766,14 +87982,14 @@ import {
|
|
|
87766
87982
|
statSync as statSync19,
|
|
87767
87983
|
writeFileSync as writeFileSync21
|
|
87768
87984
|
} from "fs";
|
|
87769
|
-
import { dirname as
|
|
87985
|
+
import { dirname as dirname21, isAbsolute as isAbsolute12, relative as relative7, resolve as resolve13, sep as sep7 } from "path";
|
|
87770
87986
|
function validateStationId(stationId) {
|
|
87771
87987
|
if (!/^[a-z0-9-]+$/.test(stationId)) {
|
|
87772
87988
|
throw new StationSnapshotError("INVALID_STATION", `station id must be a slug, got: ${stationId}`);
|
|
87773
87989
|
}
|
|
87774
87990
|
}
|
|
87775
87991
|
function sha256File(filePath) {
|
|
87776
|
-
return
|
|
87992
|
+
return createHash17("sha256").update(readFileSync33(filePath)).digest("hex");
|
|
87777
87993
|
}
|
|
87778
87994
|
function scanHome(definition, homesRoot) {
|
|
87779
87995
|
const homePath = homePathFor(definition, homesRoot);
|
|
@@ -87844,7 +88060,7 @@ function humanHomes(scanned) {
|
|
|
87844
88060
|
}));
|
|
87845
88061
|
}
|
|
87846
88062
|
function writeStationSnapshot(options) {
|
|
87847
|
-
const repoRoot =
|
|
88063
|
+
const repoRoot = resolve13(options.repoRoot ?? process.cwd());
|
|
87848
88064
|
const { scanned, plans, totalBytes } = planStationSnapshot(options);
|
|
87849
88065
|
const manifestFiles = plans.map((plan) => ({
|
|
87850
88066
|
relativePath: plan.source.relativePath,
|
|
@@ -87870,9 +88086,9 @@ function writeStationSnapshot(options) {
|
|
|
87870
88086
|
const conflicts = [];
|
|
87871
88087
|
const untouched = [];
|
|
87872
88088
|
for (const plan of plans) {
|
|
87873
|
-
const destination =
|
|
88089
|
+
const destination = resolve13(repoRoot, plan.destination);
|
|
87874
88090
|
const destinationRelative = relative7(repoRoot, destination);
|
|
87875
|
-
if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep7) ||
|
|
88091
|
+
if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep7) || isAbsolute12(destinationRelative)) {
|
|
87876
88092
|
throw new StationSnapshotError("DESTINATION_ESCAPE", `destination escapes repo root: ${plan.destination}`);
|
|
87877
88093
|
}
|
|
87878
88094
|
let existingDigest = null;
|
|
@@ -87893,8 +88109,8 @@ function writeStationSnapshot(options) {
|
|
|
87893
88109
|
}
|
|
87894
88110
|
let written = 0;
|
|
87895
88111
|
for (const plan of untouched) {
|
|
87896
|
-
const destination =
|
|
87897
|
-
mkdirSync22(
|
|
88112
|
+
const destination = resolve13(repoRoot, plan.destination);
|
|
88113
|
+
mkdirSync22(dirname21(destination), { recursive: true });
|
|
87898
88114
|
copyFileSync2(plan.source.fullPath, destination);
|
|
87899
88115
|
written += 1;
|
|
87900
88116
|
}
|
|
@@ -87912,8 +88128,8 @@ function writeStationSnapshot(options) {
|
|
|
87912
88128
|
},
|
|
87913
88129
|
files: manifestFiles
|
|
87914
88130
|
};
|
|
87915
|
-
const manifestPath =
|
|
87916
|
-
mkdirSync22(
|
|
88131
|
+
const manifestPath = resolve13(repoRoot, "resources", options.stationId, "skills", "sync-manifest.json");
|
|
88132
|
+
mkdirSync22(dirname21(manifestPath), { recursive: true });
|
|
87917
88133
|
writeFileSync21(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
87918
88134
|
`);
|
|
87919
88135
|
return {
|
|
@@ -87946,7 +88162,7 @@ __export(exports_create_sync_config, {
|
|
|
87946
88162
|
registerCreateSync: () => registerCreateSync
|
|
87947
88163
|
});
|
|
87948
88164
|
import { existsSync as existsSync33 } from "fs";
|
|
87949
|
-
import { join as
|
|
88165
|
+
import { join as join46 } from "path";
|
|
87950
88166
|
function registerCreateSync(parent) {
|
|
87951
88167
|
const configCmd = parent.command("config").description("Manage skills configuration");
|
|
87952
88168
|
configCmd.command("show", { isDefault: true }).option("--json", "Output as JSON", false).description("Show current merged configuration").action((options) => {
|
|
@@ -88056,7 +88272,7 @@ function handleCreate(name, options) {
|
|
|
88056
88272
|
console.log(source_default.green(`\u2713 Created custom skill '${result2.name}' at ${result2.path}`));
|
|
88057
88273
|
console.log(source_default.dim(` Category: ${result2.manifest.category}`));
|
|
88058
88274
|
console.log(source_default.dim(` Tags: ${result2.manifest.tags?.join(", ")}`));
|
|
88059
|
-
console.log(` ${source_default.cyan("Edit:")} ${
|
|
88275
|
+
console.log(` ${source_default.cyan("Edit:")} ${join46(result2.path, options.kind === "instruction" ? "SKILL.md" : "src/index.ts")}`);
|
|
88060
88276
|
console.log(` ${source_default.cyan("Prepare:")} skills prepare ${result2.name} --version <new-semver>`);
|
|
88061
88277
|
}
|
|
88062
88278
|
} catch (error2) {
|
|
@@ -88350,7 +88566,7 @@ __export(exports_agent_integration, {
|
|
|
88350
88566
|
registerAgentIntegration: () => registerAgentIntegration
|
|
88351
88567
|
});
|
|
88352
88568
|
import { readFileSync as readFileSync34 } from "fs";
|
|
88353
|
-
import { isAbsolute as
|
|
88569
|
+
import { isAbsolute as isAbsolute13 } from "path";
|
|
88354
88570
|
function agents(value) {
|
|
88355
88571
|
if (value === "all")
|
|
88356
88572
|
return [...INTEGRATION_AGENTS];
|
|
@@ -88396,25 +88612,26 @@ function registerAgentIntegration(parent) {
|
|
|
88396
88612
|
input.hook_event_name = event;
|
|
88397
88613
|
const projects = [process.cwd()];
|
|
88398
88614
|
if (input.cwd !== undefined) {
|
|
88399
|
-
if (typeof input.cwd !== "string" || !
|
|
88615
|
+
if (typeof input.cwd !== "string" || !isAbsolute13(input.cwd) || input.cwd.includes("\x00"))
|
|
88400
88616
|
throw new Error("Invalid native hook working directory");
|
|
88401
88617
|
projects.push(input.cwd);
|
|
88402
88618
|
}
|
|
88403
88619
|
if (options.agent === "cursor") {
|
|
88404
|
-
if (!Array.isArray(input.workspace_roots) || input.workspace_roots.length > 32 || input.workspace_roots.some((path) => typeof path !== "string" || !
|
|
88620
|
+
if (!Array.isArray(input.workspace_roots) || input.workspace_roots.length > 32 || input.workspace_roots.some((path) => typeof path !== "string" || !isAbsolute13(path) || path.includes("\x00")))
|
|
88405
88621
|
throw new Error("Invalid Cursor workspace roots");
|
|
88406
88622
|
projects.push(...input.workspace_roots);
|
|
88407
88623
|
input.cwd ??= input.workspace_roots[0] ?? process.cwd();
|
|
88408
88624
|
input.session_id ??= input.conversation_id;
|
|
88409
88625
|
}
|
|
88626
|
+
const selectionProfile = selectedProfileId(options.selectionProfile);
|
|
88410
88627
|
if (options.agent === "hermes" && event === "pre_tool_call") {
|
|
88411
|
-
assertManagedAgentBridge("hermes", { projectDirs: projects });
|
|
88628
|
+
assertManagedAgentBridge("hermes", { projectDirs: projects, profileId: selectionProfile });
|
|
88412
88629
|
assertHermesTool(input);
|
|
88413
88630
|
await writeCliOutput(JSON.stringify({ action: "continue" }));
|
|
88414
88631
|
return;
|
|
88415
88632
|
}
|
|
88416
88633
|
if (options.agent === "claude" && event === "PreToolUse" || options.agent === "gemini" && event === "BeforeTool") {
|
|
88417
|
-
assertManagedAgentBridge(options.agent, { projectDirs: projects });
|
|
88634
|
+
assertManagedAgentBridge(options.agent, { projectDirs: projects, profileId: selectionProfile });
|
|
88418
88635
|
const skill = options.agent === "claude" ? input.tool_input?.skill : input.tool_input?.name;
|
|
88419
88636
|
if (skill !== "skills-cli")
|
|
88420
88637
|
throw new Error("NATIVE_SKILL_DRIFT: invoke only skills-cli; load selected payload instructions with skills load");
|
|
@@ -88422,9 +88639,11 @@ function registerAgentIntegration(parent) {
|
|
|
88422
88639
|
return;
|
|
88423
88640
|
}
|
|
88424
88641
|
hookContextOutput(event, { context: "" });
|
|
88425
|
-
assertManagedAgentBridge(options.agent, { projectDirs: projects });
|
|
88642
|
+
assertManagedAgentBridge(options.agent, { projectDirs: projects, profileId: selectionProfile });
|
|
88643
|
+
if (typeof input.prompt === "string")
|
|
88644
|
+
input.prompt = normalizeAgentHookPrompt(options.agent, nativeEvent, input.prompt);
|
|
88426
88645
|
if (event === "SessionStart") {
|
|
88427
|
-
const refresh = Bun.spawn([process.execPath, process.argv[1], "sync", "--selection-profile",
|
|
88646
|
+
const refresh = Bun.spawn([process.execPath, process.argv[1], "sync", "--selection-profile", selectionProfile, "--json"], { stdin: "ignore", stdout: "pipe", stderr: "pipe", env: { ...process.env, NO_COLOR: "1" } });
|
|
88428
88647
|
const timer2 = setTimeout(() => refresh.kill("SIGKILL"), 6500);
|
|
88429
88648
|
try {
|
|
88430
88649
|
const [, , status] = await Promise.all([new Response(refresh.stdout).text(), new Response(refresh.stderr).text(), refresh.exited]);
|
|
@@ -88434,9 +88653,7 @@ function registerAgentIntegration(parent) {
|
|
|
88434
88653
|
clearTimeout(timer2);
|
|
88435
88654
|
}
|
|
88436
88655
|
}
|
|
88437
|
-
const args2 = [process.execPath, process.argv[1], "context", "--stdin", "--json", "--cached"];
|
|
88438
|
-
if (options.selectionProfile)
|
|
88439
|
-
args2.push("--selection-profile", options.selectionProfile);
|
|
88656
|
+
const args2 = [process.execPath, process.argv[1], "context", "--stdin", "--json", "--cached", "--selection-profile", selectionProfile];
|
|
88440
88657
|
const child = Bun.spawn(args2, { stdin: new Blob([JSON.stringify(input)]), stdout: "pipe", stderr: "pipe", env: { ...process.env, NO_COLOR: "1" } });
|
|
88441
88658
|
const timer = setTimeout(() => child.kill("SIGKILL"), 6500);
|
|
88442
88659
|
try {
|
|
@@ -88578,17 +88795,17 @@ var exports_profiles = {};
|
|
|
88578
88795
|
__export(exports_profiles, {
|
|
88579
88796
|
registerProfiles: () => registerProfiles
|
|
88580
88797
|
});
|
|
88581
|
-
import { closeSync as
|
|
88798
|
+
import { closeSync as closeSync12, constants as constants12, fstatSync as fstatSync12, openSync as openSync12, readSync as readSync9, writeFileSync as writeFileSync22 } from "fs";
|
|
88582
88799
|
function readProfileInput(path) {
|
|
88583
|
-
const fd =
|
|
88800
|
+
const fd = openSync12(path, constants12.O_RDONLY | constants12.O_NONBLOCK);
|
|
88584
88801
|
try {
|
|
88585
|
-
const stat2 =
|
|
88802
|
+
const stat2 = fstatSync12(fd);
|
|
88586
88803
|
if (!stat2.isFile() || stat2.size > MAX_PROFILE_DOCUMENT_BYTES)
|
|
88587
88804
|
throw new Error("Profile input exceeds the size limit or is not a regular file");
|
|
88588
88805
|
const bytes = Buffer.alloc(MAX_PROFILE_DOCUMENT_BYTES + 1);
|
|
88589
88806
|
let size2 = 0;
|
|
88590
88807
|
while (size2 < bytes.length) {
|
|
88591
|
-
const read3 =
|
|
88808
|
+
const read3 = readSync9(fd, bytes, size2, bytes.length - size2, null);
|
|
88592
88809
|
if (!read3)
|
|
88593
88810
|
break;
|
|
88594
88811
|
size2 += read3;
|
|
@@ -88597,7 +88814,7 @@ function readProfileInput(path) {
|
|
|
88597
88814
|
throw new Error("Profile input exceeds the size limit");
|
|
88598
88815
|
return new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, size2));
|
|
88599
88816
|
} finally {
|
|
88600
|
-
|
|
88817
|
+
closeSync12(fd);
|
|
88601
88818
|
}
|
|
88602
88819
|
}
|
|
88603
88820
|
function registerProfiles(parent) {
|
|
@@ -88639,7 +88856,7 @@ var init_profiles = __esm(() => {
|
|
|
88639
88856
|
});
|
|
88640
88857
|
|
|
88641
88858
|
// src/lib/station-hydrate.ts
|
|
88642
|
-
import { createHash as
|
|
88859
|
+
import { createHash as createHash18 } from "crypto";
|
|
88643
88860
|
import {
|
|
88644
88861
|
copyFileSync as copyFileSync3,
|
|
88645
88862
|
mkdirSync as mkdirSync23,
|
|
@@ -88648,16 +88865,16 @@ import {
|
|
|
88648
88865
|
statSync as statSync20,
|
|
88649
88866
|
writeFileSync as writeFileSync23
|
|
88650
88867
|
} from "fs";
|
|
88651
|
-
import { dirname as
|
|
88868
|
+
import { dirname as dirname22, join as join47, resolve as resolve14, sep as sep8 } from "path";
|
|
88652
88869
|
function fail4(code, message, detail = []) {
|
|
88653
88870
|
throw new StationSnapshotError(code, message, detail);
|
|
88654
88871
|
}
|
|
88655
88872
|
function snapshotRootFor(repoRoot, stationId) {
|
|
88656
|
-
return
|
|
88873
|
+
return join47(repoRoot, "resources", stationId, "skills");
|
|
88657
88874
|
}
|
|
88658
88875
|
function readSnapshotManifest(repoRoot, stationId) {
|
|
88659
88876
|
const snapshotRoot = snapshotRootFor(repoRoot, stationId);
|
|
88660
|
-
const manifestPath =
|
|
88877
|
+
const manifestPath = join47(snapshotRoot, "sync-manifest.json");
|
|
88661
88878
|
let manifest;
|
|
88662
88879
|
try {
|
|
88663
88880
|
manifest = JSON.parse(readFileSync35(manifestPath, "utf8"));
|
|
@@ -88684,7 +88901,7 @@ function planStationHydration(stationId, repoRoot) {
|
|
|
88684
88901
|
const hashMismatches = [];
|
|
88685
88902
|
const skippedByRule = [];
|
|
88686
88903
|
for (const agent of SYNC_AGENTS) {
|
|
88687
|
-
const agentRoot =
|
|
88904
|
+
const agentRoot = join47(snapshotRoot, "agent-homes", agent);
|
|
88688
88905
|
let identEntries;
|
|
88689
88906
|
try {
|
|
88690
88907
|
identEntries = readdirSync21(agentRoot, { withFileTypes: true });
|
|
@@ -88695,7 +88912,7 @@ function planStationHydration(stationId, repoRoot) {
|
|
|
88695
88912
|
if (!identEntry.isDirectory() || identEntry.name.startsWith(".")) {
|
|
88696
88913
|
continue;
|
|
88697
88914
|
}
|
|
88698
|
-
const identRoot =
|
|
88915
|
+
const identRoot = join47(agentRoot, identEntry.name);
|
|
88699
88916
|
const entries = walkEntries(identRoot);
|
|
88700
88917
|
for (const entry of entries) {
|
|
88701
88918
|
const relativeParts = [identEntry.name, ...entry.relativePath.split(sep8)];
|
|
@@ -88842,12 +89059,12 @@ function skillSha256(skill) {
|
|
|
88842
89059
|
return sha256File(skill.files[0].winner.fullPath);
|
|
88843
89060
|
}
|
|
88844
89061
|
const joined = skill.files.map((file) => sha256File(file.winner.fullPath));
|
|
88845
|
-
return
|
|
89062
|
+
return createHash18("sha256").update(joined.sort().join(`
|
|
88846
89063
|
`)).digest("hex");
|
|
88847
89064
|
}
|
|
88848
89065
|
function writeStationHydration(options) {
|
|
88849
|
-
const repoRoot =
|
|
88850
|
-
const cacheRoot =
|
|
89066
|
+
const repoRoot = resolve14(options.repoRoot ?? process.cwd());
|
|
89067
|
+
const cacheRoot = resolve14(options.cacheRoot ?? resolveCorpusRoot());
|
|
88851
89068
|
const plan = planStationHydration(options.stationId, repoRoot);
|
|
88852
89069
|
const resultSkills = plan.winners.map((skill) => ({
|
|
88853
89070
|
ident: skill.ident,
|
|
@@ -88880,7 +89097,7 @@ function writeStationHydration(options) {
|
|
|
88880
89097
|
const toWrite = [];
|
|
88881
89098
|
for (const skill of plan.winners) {
|
|
88882
89099
|
for (const file of skill.files) {
|
|
88883
|
-
const destination =
|
|
89100
|
+
const destination = join47(cacheRoot, skill.ident, file.withinIdent);
|
|
88884
89101
|
const digest2 = sha256File(file.winner.fullPath);
|
|
88885
89102
|
let existingDigest = null;
|
|
88886
89103
|
try {
|
|
@@ -88901,7 +89118,7 @@ function writeStationHydration(options) {
|
|
|
88901
89118
|
}
|
|
88902
89119
|
let written = 0;
|
|
88903
89120
|
for (const entry of toWrite) {
|
|
88904
|
-
mkdirSync23(
|
|
89121
|
+
mkdirSync23(dirname22(entry.destination), { recursive: true });
|
|
88905
89122
|
copyFileSync3(entry.fullPath, entry.destination);
|
|
88906
89123
|
written += 1;
|
|
88907
89124
|
}
|
|
@@ -88922,8 +89139,8 @@ function writeStationHydration(options) {
|
|
|
88922
89139
|
},
|
|
88923
89140
|
skills: resultSkills
|
|
88924
89141
|
};
|
|
88925
|
-
const hydrationManifestPath =
|
|
88926
|
-
mkdirSync23(
|
|
89142
|
+
const hydrationManifestPath = join47(dirname22(cacheRoot), `hydration-${options.stationId}.json`);
|
|
89143
|
+
mkdirSync23(dirname22(hydrationManifestPath), { recursive: true });
|
|
88927
89144
|
writeFileSync23(hydrationManifestPath, `${JSON.stringify(hydration, null, 2)}
|
|
88928
89145
|
`);
|
|
88929
89146
|
return {
|
|
@@ -88999,15 +89216,15 @@ var init_hydrate = __esm(() => {
|
|
|
88999
89216
|
});
|
|
89000
89217
|
|
|
89001
89218
|
// src/lib/prepare-skill.ts
|
|
89002
|
-
import { createHash as
|
|
89003
|
-
import { chmodSync as chmodSync3, existsSync as existsSync34, lstatSync as
|
|
89219
|
+
import { createHash as createHash19, randomUUID as randomUUID8 } from "crypto";
|
|
89220
|
+
import { chmodSync as chmodSync3, existsSync as existsSync34, lstatSync as lstatSync19, mkdirSync as mkdirSync24, mkdtempSync as mkdtempSync6, readFileSync as readFileSync36, readdirSync as readdirSync22, renameSync as renameSync10, rmSync as rmSync8, writeFileSync as writeFileSync24 } from "fs";
|
|
89004
89221
|
import { tmpdir as tmpdir2 } from "os";
|
|
89005
|
-
import { dirname as
|
|
89222
|
+
import { dirname as dirname23, isAbsolute as isAbsolute14, join as join48, relative as relative8, resolve as resolve15, sep as sep9 } from "path";
|
|
89006
89223
|
function prepareSkill(name, options) {
|
|
89007
89224
|
const normalized = normalizePortableSkillName(name);
|
|
89008
89225
|
if (!new RegExp(SEMVER_PATTERN).test(options.version))
|
|
89009
89226
|
throw new Error("--version must be a semantic version, for example 0.2.0.");
|
|
89010
|
-
const path =
|
|
89227
|
+
const path = join48(getPortableSkillsRootReadOnly(options), normalized);
|
|
89011
89228
|
const before2 = snapshot(path);
|
|
89012
89229
|
const manifestFile = before2.files.find((file) => file.path === "skill.json");
|
|
89013
89230
|
if (!manifestFile)
|
|
@@ -89041,16 +89258,16 @@ function prepareSkill(name, options) {
|
|
|
89041
89258
|
throw new Error("skill.json provenance must be an object.");
|
|
89042
89259
|
const provenance = manifest.provenance;
|
|
89043
89260
|
const candidate = { ...manifest, version: options.version, kind, provenance: { ...provenance } };
|
|
89044
|
-
const staging = mkdtempSync6(
|
|
89261
|
+
const staging = mkdtempSync6(join48(tmpdir2(), "skills-prepare-"));
|
|
89045
89262
|
try {
|
|
89046
89263
|
for (const directory of before2.directories)
|
|
89047
|
-
mkdirSync24(
|
|
89264
|
+
mkdirSync24(join48(staging, directory), { recursive: true });
|
|
89048
89265
|
for (const file of before2.files) {
|
|
89049
|
-
const destination =
|
|
89050
|
-
mkdirSync24(
|
|
89266
|
+
const destination = join48(staging, file.path);
|
|
89267
|
+
mkdirSync24(dirname23(destination), { recursive: true });
|
|
89051
89268
|
writeFileSync24(destination, file.bytes, { mode: file.mode });
|
|
89052
89269
|
}
|
|
89053
|
-
const stagedManifest =
|
|
89270
|
+
const stagedManifest = join48(staging, "skill.json");
|
|
89054
89271
|
writeFileSync24(stagedManifest, `${JSON.stringify(candidate, null, 2)}
|
|
89055
89272
|
`);
|
|
89056
89273
|
const contentHash = computeContentHash(staging);
|
|
@@ -89073,11 +89290,11 @@ ${validation.issues.map((issue2) => `${issue2.code}: ${issue2.message}`).join(`
|
|
|
89073
89290
|
if (snapshot(path).identity !== before2.identity)
|
|
89074
89291
|
throw new Error("Skill changed during preparation; review the draft and run prepare again.");
|
|
89075
89292
|
if (changed2 && !options.dryRun) {
|
|
89076
|
-
const temporary =
|
|
89293
|
+
const temporary = join48(path, `.skill-prepare-${randomUUID8()}.tmp`);
|
|
89077
89294
|
try {
|
|
89078
89295
|
writeFileSync24(temporary, candidateBytes, { flag: "wx", mode: manifestFile.mode });
|
|
89079
89296
|
chmodSync3(temporary, manifestFile.mode);
|
|
89080
|
-
renameSync10(temporary,
|
|
89297
|
+
renameSync10(temporary, join48(path, "skill.json"));
|
|
89081
89298
|
} finally {
|
|
89082
89299
|
rmSync8(temporary, { force: true });
|
|
89083
89300
|
}
|
|
@@ -89107,8 +89324,8 @@ function validateRuntimeEntrypoint(candidate, root) {
|
|
|
89107
89324
|
const entry = candidate.runtime.entrypoint;
|
|
89108
89325
|
if (typeof entry !== "string")
|
|
89109
89326
|
return;
|
|
89110
|
-
const target =
|
|
89111
|
-
if (
|
|
89327
|
+
const target = resolve15(root, entry), rel = relative8(root, target);
|
|
89328
|
+
if (isAbsolute14(entry) || /^[a-zA-Z]:/.test(entry) || entry.includes("\\") || !rel || rel === ".." || rel.startsWith(`..${sep9}`) || isAbsolute14(rel) || !existsSync34(target) || !lstatSync19(target).isFile()) {
|
|
89112
89329
|
throw new Error("Executable runtime.entrypoint must name an existing regular file inside the skill directory.");
|
|
89113
89330
|
}
|
|
89114
89331
|
}
|
|
@@ -89180,20 +89397,20 @@ function compareVersions(left, right) {
|
|
|
89180
89397
|
return 0;
|
|
89181
89398
|
}
|
|
89182
89399
|
function snapshot(root) {
|
|
89183
|
-
const rootStat =
|
|
89400
|
+
const rootStat = lstatSync19(root);
|
|
89184
89401
|
if (rootStat.isSymbolicLink() || !rootStat.isDirectory())
|
|
89185
89402
|
throw new Error("Skill root must be a real directory, not a symlink.");
|
|
89186
89403
|
const files = [], directories = [];
|
|
89187
|
-
const hash3 =
|
|
89404
|
+
const hash3 = createHash19("sha256").update(`${rootStat.dev}:${rootStat.ino}\x00`);
|
|
89188
89405
|
let count = 0, bytes = 0;
|
|
89189
89406
|
const walk2 = (relative9) => {
|
|
89190
|
-
for (const name of readdirSync22(
|
|
89407
|
+
for (const name of readdirSync22(join48(root, relative9)).sort()) {
|
|
89191
89408
|
if (IGNORED.has(name.toLowerCase()) || !relative9 && ROOT_IGNORED.has(name.toLowerCase()))
|
|
89192
89409
|
continue;
|
|
89193
89410
|
const path = relative9 ? `${relative9}/${name}` : name;
|
|
89194
89411
|
if (++count > 20000)
|
|
89195
89412
|
throw new Error("Skill exceeds the preparation entry limit (20000).");
|
|
89196
|
-
const absolute =
|
|
89413
|
+
const absolute = join48(root, path), stat2 = lstatSync19(absolute);
|
|
89197
89414
|
if (stat2.isSymbolicLink())
|
|
89198
89415
|
throw new Error(`Skill contains a symlink: ${path}. No files were changed.`);
|
|
89199
89416
|
if (stat2.isDirectory() && name === "node_modules")
|
|
@@ -89608,7 +89825,7 @@ var init_schedule = __esm(() => {
|
|
|
89608
89825
|
|
|
89609
89826
|
// src/lib/registry-sync.ts
|
|
89610
89827
|
import { mkdirSync as mkdirSync25, writeFileSync as writeFileSync25 } from "fs";
|
|
89611
|
-
import { dirname as
|
|
89828
|
+
import { dirname as dirname24, relative as relative9 } from "path";
|
|
89612
89829
|
function createRegistrySyncArtifact(options = {}) {
|
|
89613
89830
|
const profile = options.profile ?? "all";
|
|
89614
89831
|
const includeDocs = options.includeDocs ?? true;
|
|
@@ -89665,7 +89882,7 @@ function createRegistrySyncArtifact(options = {}) {
|
|
|
89665
89882
|
};
|
|
89666
89883
|
}
|
|
89667
89884
|
function writeRegistrySyncArtifact(path, artifact) {
|
|
89668
|
-
mkdirSync25(
|
|
89885
|
+
mkdirSync25(dirname24(path), { recursive: true });
|
|
89669
89886
|
writeFileSync25(path, `${JSON.stringify(artifact, null, 2)}
|
|
89670
89887
|
`);
|
|
89671
89888
|
}
|
|
@@ -89698,12 +89915,12 @@ function registerRegistry(parent) {
|
|
|
89698
89915
|
async function writeJson2(value, space) {
|
|
89699
89916
|
const text3 = `${JSON.stringify(value, null, space)}
|
|
89700
89917
|
`;
|
|
89701
|
-
await new Promise((
|
|
89918
|
+
await new Promise((resolve16, reject2) => {
|
|
89702
89919
|
process.stdout.write(text3, (error2) => {
|
|
89703
89920
|
if (error2)
|
|
89704
89921
|
reject2(error2);
|
|
89705
89922
|
else
|
|
89706
|
-
|
|
89923
|
+
resolve16();
|
|
89707
89924
|
});
|
|
89708
89925
|
});
|
|
89709
89926
|
}
|
|
@@ -89869,7 +90086,7 @@ __export(exports_publish, {
|
|
|
89869
90086
|
import { execFileSync } from "child_process";
|
|
89870
90087
|
import { existsSync as existsSync35, readFileSync as readFileSync37 } from "fs";
|
|
89871
90088
|
import { hostname as hostname3 } from "os";
|
|
89872
|
-
import { join as
|
|
90089
|
+
import { join as join49 } from "path";
|
|
89873
90090
|
function registerPublish(parent) {
|
|
89874
90091
|
parent.command("push").argument("<name>", "Name of a skill in the local corpus (~/.hasna/skills/installed or the migrated ~/.hasna/skills/skills)").option("--version <version>", "Override the version recorded on the instance").option("--force-new-version", "If name@version already exists with different content, publish as the next patch version", false).option("--dry-run", "Pack and validate without uploading", false).option("--json", "Output result as JSON", false).description("Publish a local skill to the configured skills instance").action(async (name, options) => {
|
|
89875
90092
|
try {
|
|
@@ -89920,7 +90137,7 @@ async function pushSkill(name, options = {}) {
|
|
|
89920
90137
|
const packed = packSkillBundle(skill.path, { maxUnpackedBytes: MAX_UNPACKED_BYTES });
|
|
89921
90138
|
await verifyPackedCanonicalHash(skill.name, packed);
|
|
89922
90139
|
const versionManifest = buildVersionManifest(skill.path, packed);
|
|
89923
|
-
const skillMdPath =
|
|
90140
|
+
const skillMdPath = join49(skill.path, "SKILL.md");
|
|
89924
90141
|
const skillMd = existsSync35(skillMdPath) ? readFileSync37(skillMdPath, "utf-8") : undefined;
|
|
89925
90142
|
const base2 = {
|
|
89926
90143
|
slug: skill.name,
|
|
@@ -90172,7 +90389,7 @@ async function readCode() {
|
|
|
90172
90389
|
function promptCode() {
|
|
90173
90390
|
const { stdin, stderr: output } = process;
|
|
90174
90391
|
const { isRaw: wasRaw, readableFlowing: wasFlowing } = stdin;
|
|
90175
|
-
return new Promise((
|
|
90392
|
+
return new Promise((resolve16) => {
|
|
90176
90393
|
let value = "", settled = false;
|
|
90177
90394
|
const finish = (answer) => {
|
|
90178
90395
|
if (settled)
|
|
@@ -90189,7 +90406,7 @@ function promptCode() {
|
|
|
90189
90406
|
`);
|
|
90190
90407
|
if (answer === null)
|
|
90191
90408
|
process.exitCode = 130;
|
|
90192
|
-
|
|
90409
|
+
resolve16(answer);
|
|
90193
90410
|
};
|
|
90194
90411
|
const cancel = () => finish(null);
|
|
90195
90412
|
const keypress = (text3, key) => {
|
|
@@ -90234,7 +90451,7 @@ var exports_private_publications = {};
|
|
|
90234
90451
|
__export(exports_private_publications, {
|
|
90235
90452
|
registerPrivatePublications: () => registerPrivatePublications
|
|
90236
90453
|
});
|
|
90237
|
-
import { resolve as
|
|
90454
|
+
import { resolve as resolve16 } from "path";
|
|
90238
90455
|
function verifyOptions(options, action) {
|
|
90239
90456
|
if (options.userId === undefined !== (options.membershipId === undefined) || options.userId !== undefined && (!publicationUuid(options.userId) || !publicationUuid(options.membershipId)))
|
|
90240
90457
|
throw new PrivatePublicationError("PUBLICATION_CONTEXT_REQUIRED", "Provide both observed --user-id and --membership-id UUIDs.");
|
|
@@ -90279,9 +90496,9 @@ function registerPrivatePublications(parent) {
|
|
|
90279
90496
|
if (code === null)
|
|
90280
90497
|
return;
|
|
90281
90498
|
const context = options.userId ? { userId: options.userId, membershipId: options.membershipId } : undefined;
|
|
90282
|
-
const client = await privatePublicationSession(options.email, code, context), directory =
|
|
90499
|
+
const client = await privatePublicationSession(options.email, code, context), directory = resolve16(options.recoveryDir);
|
|
90283
90500
|
if (action === "publish")
|
|
90284
|
-
await preparePrivatePublication(client,
|
|
90501
|
+
await preparePrivatePublication(client, resolve16(args2[0]), directory, { skillId: options.skillId, expectedCurrentVersionId: options.expectedCurrentVersion ?? null, idempotencyKey: options.idempotencyKey });
|
|
90285
90502
|
const result2 = action === "publish" || action === "resume" ? await continuePrivatePublication(client, directory, { confirm: true, waitMs: Number(options.waitSeconds) * 1000 }) : await inspectPrivatePublication(client, directory, action === "cancel");
|
|
90286
90503
|
print2(result2, options.json);
|
|
90287
90504
|
} catch (error2) {
|
|
@@ -90382,7 +90599,7 @@ __export(exports_auth, {
|
|
|
90382
90599
|
import { createInterface as createInterface2 } from "readline";
|
|
90383
90600
|
function prompt(question) {
|
|
90384
90601
|
const rl = createInterface2({ input: process.stdin, output: process.stdout });
|
|
90385
|
-
return new Promise((
|
|
90602
|
+
return new Promise((resolve17) => {
|
|
90386
90603
|
let settled = false;
|
|
90387
90604
|
const finish = (answer) => {
|
|
90388
90605
|
if (settled)
|
|
@@ -90391,7 +90608,7 @@ function prompt(question) {
|
|
|
90391
90608
|
rl.close();
|
|
90392
90609
|
if (answer === null)
|
|
90393
90610
|
process.exitCode = 130;
|
|
90394
|
-
|
|
90611
|
+
resolve17(answer);
|
|
90395
90612
|
};
|
|
90396
90613
|
rl.once("SIGINT", () => finish(null));
|
|
90397
90614
|
rl.once("close", () => finish(null));
|
|
@@ -90493,7 +90710,7 @@ function printWhoami(payload) {
|
|
|
90493
90710
|
console.log(source_default.dim("(offline \u2014 showing cached info)"));
|
|
90494
90711
|
}
|
|
90495
90712
|
function sleep(ms) {
|
|
90496
|
-
return new Promise((
|
|
90713
|
+
return new Promise((resolve17) => setTimeout(resolve17, ms));
|
|
90497
90714
|
}
|
|
90498
90715
|
function browserCommand(url) {
|
|
90499
90716
|
if (process.platform === "darwin")
|
|
@@ -90986,7 +91203,7 @@ function promptInvitationProof(kind) {
|
|
|
90986
91203
|
const label = kind === "token" ? "invitation token" : "recovery code";
|
|
90987
91204
|
const character = kind === "token" ? /^[A-Za-z0-9_-]$/ : /^\d$/;
|
|
90988
91205
|
const { stdin, stderr: output } = process, wasRaw = stdin.isRaw, wasFlowing = stdin.readableFlowing;
|
|
90989
|
-
return new Promise((
|
|
91206
|
+
return new Promise((resolve17) => {
|
|
90990
91207
|
let value = "", settled = false, overflow = false;
|
|
90991
91208
|
const finish = (answer) => {
|
|
90992
91209
|
if (settled)
|
|
@@ -91003,7 +91220,7 @@ function promptInvitationProof(kind) {
|
|
|
91003
91220
|
`);
|
|
91004
91221
|
if (answer === null)
|
|
91005
91222
|
process.exitCode = 130;
|
|
91006
|
-
|
|
91223
|
+
resolve17(answer);
|
|
91007
91224
|
};
|
|
91008
91225
|
const cancel = () => finish(null);
|
|
91009
91226
|
const keypress = (text3, key) => {
|
|
@@ -91576,7 +91793,7 @@ var init_storage = __esm(() => {
|
|
|
91576
91793
|
|
|
91577
91794
|
// src/lib/registry-reconcile.ts
|
|
91578
91795
|
import { existsSync as existsSync36, readFileSync as readFileSync38, statSync as statSync21, writeFileSync as writeFileSync26 } from "fs";
|
|
91579
|
-
import { join as
|
|
91796
|
+
import { join as join50 } from "path";
|
|
91580
91797
|
function isDirectory2(path) {
|
|
91581
91798
|
try {
|
|
91582
91799
|
return statSync21(path).isDirectory();
|
|
@@ -91587,11 +91804,11 @@ function isDirectory2(path) {
|
|
|
91587
91804
|
function migrationNeeded(options) {
|
|
91588
91805
|
if (options.rootDir)
|
|
91589
91806
|
return false;
|
|
91590
|
-
const appDir = options.homeDir ?
|
|
91591
|
-
return !(isOwnerLayoutMigrated(appDir) && isDirectory2(
|
|
91807
|
+
const appDir = options.homeDir ? join50(options.homeDir, ".hasna", "skills") : getDataDir();
|
|
91808
|
+
return !(isOwnerLayoutMigrated(appDir) && isDirectory2(join50(appDir, SKILLS_CACHE_DIRNAME)));
|
|
91592
91809
|
}
|
|
91593
91810
|
function readBaseline(skillDir) {
|
|
91594
|
-
const markerPath =
|
|
91811
|
+
const markerPath = join50(skillDir, PULL_MARKER_FILE);
|
|
91595
91812
|
if (!existsSync36(markerPath))
|
|
91596
91813
|
return;
|
|
91597
91814
|
try {
|
|
@@ -91607,7 +91824,7 @@ function readBaseline(skillDir) {
|
|
|
91607
91824
|
}
|
|
91608
91825
|
}
|
|
91609
91826
|
function readCursor(root) {
|
|
91610
|
-
const path =
|
|
91827
|
+
const path = join50(root, SYNC_CURSOR_FILE);
|
|
91611
91828
|
if (!existsSync36(path))
|
|
91612
91829
|
return { runCount: 0 };
|
|
91613
91830
|
try {
|
|
@@ -91620,12 +91837,12 @@ function readCursor(root) {
|
|
|
91620
91837
|
function resolveCorpusRootReadOnly(options) {
|
|
91621
91838
|
if (options.rootDir)
|
|
91622
91839
|
return { root: options.rootDir, migrationPending: false };
|
|
91623
|
-
const appDir = options.homeDir ?
|
|
91624
|
-
const cache3 =
|
|
91840
|
+
const appDir = options.homeDir ? join50(options.homeDir, ".hasna", "skills") : getDataDirReadOnly();
|
|
91841
|
+
const cache3 = join50(appDir, SKILLS_CACHE_DIRNAME);
|
|
91625
91842
|
if (isOwnerLayoutMigrated(appDir) && isDirectory2(cache3)) {
|
|
91626
91843
|
return { root: cache3, migrationPending: false };
|
|
91627
91844
|
}
|
|
91628
|
-
return { root:
|
|
91845
|
+
return { root: join50(appDir, INSTALLED_SKILLS_DIRNAME), migrationPending: true };
|
|
91629
91846
|
}
|
|
91630
91847
|
function remoteRowToSkill(record9) {
|
|
91631
91848
|
const slug = typeof record9.slug === "string" ? record9.slug : typeof record9.name === "string" ? record9.name : undefined;
|
|
@@ -91759,7 +91976,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
91759
91976
|
for (const slug of allSlugs) {
|
|
91760
91977
|
const local = locals.get(slug);
|
|
91761
91978
|
const remote = remotes.get(slug);
|
|
91762
|
-
const baseline = local ? readBaseline(
|
|
91979
|
+
const baseline = local ? readBaseline(join50(root, slug)) : undefined;
|
|
91763
91980
|
const { state, reason } = classifySkill(local, remote, baseline);
|
|
91764
91981
|
let { action, reason: actionReason } = resolveAction(state, direction, conflict);
|
|
91765
91982
|
if (state === "remote-only" && isDigestless(remote)) {
|
|
@@ -91818,7 +92035,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
91818
92035
|
try {
|
|
91819
92036
|
await pushSkill(slug, { rootDir: root, client });
|
|
91820
92037
|
const pushed = locals.get(slug);
|
|
91821
|
-
writePullMarker(
|
|
92038
|
+
writePullMarker(join50(root, slug), {
|
|
91822
92039
|
skill: slug,
|
|
91823
92040
|
...pushed?.version ? { version: pushed.version } : {},
|
|
91824
92041
|
...pushed?.sha256 ? { contentHash: pushed.sha256 } : {},
|
|
@@ -91890,7 +92107,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
91890
92107
|
runCount: readCursor(root).runCount + 1,
|
|
91891
92108
|
summary
|
|
91892
92109
|
};
|
|
91893
|
-
writeFileSync26(
|
|
92110
|
+
writeFileSync26(join50(root, SYNC_CURSOR_FILE), `${JSON.stringify(cursor2, null, 2)}
|
|
91894
92111
|
`);
|
|
91895
92112
|
return {
|
|
91896
92113
|
corpusRoot: root,
|