@hasna/skills 0.8.11 → 0.8.12
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 +10 -0
- package/bin/index.js +672 -435
- package/bin/mcp.js +62 -2
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +412 -177
- package/dist/lib/agent-discovery.d.ts +1 -1
- package/dist/lib/claude-settings-witness.d.ts +19 -0
- package/dist/sdk/index.js +499 -265
- package/docs/plugin-admission.md +67 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9650,7 +9650,7 @@ import { homedir as homedir5 } from "os";
|
|
|
9650
9650
|
import {
|
|
9651
9651
|
cpSync as cpSync2,
|
|
9652
9652
|
existsSync as existsSync12,
|
|
9653
|
-
lstatSync as
|
|
9653
|
+
lstatSync as lstatSync19,
|
|
9654
9654
|
mkdirSync as mkdirSync8,
|
|
9655
9655
|
mkdtempSync as mkdtempSync2,
|
|
9656
9656
|
readFileSync as readFileSync15,
|
|
@@ -9661,12 +9661,12 @@ import {
|
|
|
9661
9661
|
writeFileSync as writeFileSync6
|
|
9662
9662
|
} from "fs";
|
|
9663
9663
|
import { homedir as homedir4 } from "os";
|
|
9664
|
-
import { basename as
|
|
9664
|
+
import { basename as basename9, dirname as dirname16, join as join26 } from "path";
|
|
9665
9665
|
|
|
9666
9666
|
// src/lib/agent-integration.ts
|
|
9667
|
-
import { createHash as
|
|
9668
|
-
import { existsSync as existsSync11, lstatSync as
|
|
9669
|
-
import { dirname as
|
|
9667
|
+
import { createHash as createHash14, randomUUID as randomUUID3 } from "crypto";
|
|
9668
|
+
import { existsSync as existsSync11, lstatSync as lstatSync18, statSync as statSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync14, readdirSync as readdirSync10, opendirSync as opendirSync5, readlinkSync as readlinkSync2, realpathSync as realpathSync5, renameSync as renameSync4, rmdirSync as rmdirSync3, writeFileSync as writeFileSync5, unlinkSync as unlinkSync4, chmodSync, openSync as openSync11, closeSync as closeSync11, fsyncSync as fsyncSync3, fstatSync as fstatSync11, readSync as readSync9, constants as constants10, linkSync as linkSync2 } from "fs";
|
|
9669
|
+
import { dirname as dirname15, join as join25, resolve as resolve15, relative as relative5, isAbsolute as isAbsolute15, sep as sep6 } from "path";
|
|
9670
9670
|
import { homedir as homedir3 } from "os";
|
|
9671
9671
|
|
|
9672
9672
|
// src/lib/managed-policy.ts
|
|
@@ -10807,7 +10807,9 @@ function assertAgentPolicyCollections(policy) {
|
|
|
10807
10807
|
text(source.path);
|
|
10808
10808
|
requireBound(source.sha256 === null || typeof source.sha256 === "string" && /^[a-f0-9]{64}$/.test(source.sha256));
|
|
10809
10809
|
if (source.hashMode !== undefined)
|
|
10810
|
-
requireBound(["bytes", "path-bytes", "claude-plugin-registry", "claude-marketplace-registry"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
10810
|
+
requireBound(["bytes", "path-bytes", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
10811
|
+
if (source.hashMode === "claude-settings-v1")
|
|
10812
|
+
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute3(source.path) && resolve4(source.path) === source.path && basename3(source.path) === "settings.json");
|
|
10811
10813
|
if (source.hashMode === "claude-marketplace-registry")
|
|
10812
10814
|
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute3(source.path) && resolve4(source.path) === source.path && basename3(source.path) === "known_marketplaces.json");
|
|
10813
10815
|
if (source.hashMode === "claude-plugin-registry") {
|
|
@@ -10961,9 +10963,9 @@ function isOwnedCliBridge(path, expectedPaths) {
|
|
|
10961
10963
|
}
|
|
10962
10964
|
|
|
10963
10965
|
// src/lib/agent-discovery.ts
|
|
10964
|
-
import { createHash as
|
|
10965
|
-
import { lstatSync as
|
|
10966
|
-
import { dirname as
|
|
10966
|
+
import { createHash as createHash13 } from "crypto";
|
|
10967
|
+
import { lstatSync as lstatSync17, readFileSync as readFileSync13, readdirSync as readdirSync9, realpathSync as realpathSync4 } from "fs";
|
|
10968
|
+
import { basename as basename8, dirname as dirname14, isAbsolute as isAbsolute14, join as join23, resolve as resolve14, sep as sep5 } from "path";
|
|
10967
10969
|
|
|
10968
10970
|
// node_modules/yaml/dist/index.js
|
|
10969
10971
|
var composer = require_composer();
|
|
@@ -11439,7 +11441,7 @@ import { isAbsolute as isAbsolute10, join as join20, resolve as resolve10 } from
|
|
|
11439
11441
|
// package.json
|
|
11440
11442
|
var package_default = {
|
|
11441
11443
|
name: "@hasna/skills",
|
|
11442
|
-
version: "0.8.
|
|
11444
|
+
version: "0.8.12",
|
|
11443
11445
|
description: "Skills library for AI coding agents",
|
|
11444
11446
|
type: "module",
|
|
11445
11447
|
bin: {
|
|
@@ -14931,8 +14933,228 @@ function captureClaudeMarketplaceRegistry(path, budget = { remaining: 256 * 1024
|
|
|
14931
14933
|
return { path, hashMode: "claude-marketplace-registry", sha256: sha2562 };
|
|
14932
14934
|
}
|
|
14933
14935
|
|
|
14936
|
+
// src/lib/claude-settings-witness.ts
|
|
14937
|
+
import { createHash as createHash12 } from "crypto";
|
|
14938
|
+
import { closeSync as closeSync10, constants as constants9, fstatSync as fstatSync10, lstatSync as lstatSync16, openSync as openSync10, readSync as readSync8 } from "fs";
|
|
14939
|
+
import { basename as basename7, dirname as dirname13, isAbsolute as isAbsolute13, resolve as resolve13 } from "path";
|
|
14940
|
+
var CLAUDE_SETTINGS_WITNESS_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
|
|
14941
|
+
function need3(value, reason) {
|
|
14942
|
+
if (!value)
|
|
14943
|
+
throw new Error(`Claude settings witness ${reason}`);
|
|
14944
|
+
}
|
|
14945
|
+
function absolutePath2(value) {
|
|
14946
|
+
need3(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_SETTINGS_WITNESS_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute13(value) && resolve13(value) === value, "requires a normalized absolute path");
|
|
14947
|
+
}
|
|
14948
|
+
var sameFile2 = (a, b) => a.dev === b.dev && a.ino === b.ino && a.mode === b.mode && a.uid === b.uid && a.gid === b.gid && a.nlink === b.nlink && a.size === b.size && a.mtimeNs === b.mtimeNs && a.ctimeNs === b.ctimeNs;
|
|
14949
|
+
function parents2(path) {
|
|
14950
|
+
const result = [];
|
|
14951
|
+
for (let at = dirname13(path);; at = dirname13(at)) {
|
|
14952
|
+
const stat2 = lstatSync16(at, { bigint: true });
|
|
14953
|
+
need3(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
|
|
14954
|
+
result.push([at, stat2]);
|
|
14955
|
+
if (at === dirname13(at))
|
|
14956
|
+
return result;
|
|
14957
|
+
}
|
|
14958
|
+
}
|
|
14959
|
+
function readSettings(path, budget) {
|
|
14960
|
+
absolutePath2(path);
|
|
14961
|
+
need3(basename7(path) === "settings.json", "requires settings.json");
|
|
14962
|
+
need3(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
|
|
14963
|
+
const ancestors2 = parents2(path), initial = lstatSync16(path, { bigint: true });
|
|
14964
|
+
need3(initial.isFile() && !initial.isSymbolicLink() && initial.size <= BigInt(CLAUDE_SETTINGS_WITNESS_LIMITS.bytes), "is not a bounded regular file");
|
|
14965
|
+
need3(initial.size <= BigInt(budget.remaining), "exceeds its aggregate byte limit");
|
|
14966
|
+
const fd = openSync10(path, constants9.O_RDONLY | constants9.O_NOFOLLOW | constants9.O_NONBLOCK);
|
|
14967
|
+
try {
|
|
14968
|
+
const opened = fstatSync10(fd, { bigint: true });
|
|
14969
|
+
need3(opened.isFile() && sameFile2(initial, opened), "changed during open");
|
|
14970
|
+
const bytes = Buffer.alloc(Number(opened.size) + 1);
|
|
14971
|
+
let length = 0;
|
|
14972
|
+
while (length < bytes.length) {
|
|
14973
|
+
const count = readSync8(fd, bytes, length, bytes.length - length, null);
|
|
14974
|
+
if (!count)
|
|
14975
|
+
break;
|
|
14976
|
+
length += count;
|
|
14977
|
+
}
|
|
14978
|
+
const after = fstatSync10(fd, { bigint: true }), current = lstatSync16(path, { bigint: true });
|
|
14979
|
+
need3(current.isFile() && sameFile2(opened, after) && sameFile2(after, current) && BigInt(length) === opened.size, "changed during read");
|
|
14980
|
+
for (const [ancestor, before] of ancestors2) {
|
|
14981
|
+
const now = lstatSync16(ancestor, { bigint: true });
|
|
14982
|
+
need3(now.isDirectory() && before.dev === now.dev && before.ino === now.ino && before.mode === now.mode, "parent changed during read");
|
|
14983
|
+
}
|
|
14984
|
+
budget.remaining -= length;
|
|
14985
|
+
try {
|
|
14986
|
+
return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes.subarray(0, length));
|
|
14987
|
+
} catch {
|
|
14988
|
+
throw new Error("Claude settings witness is not strict UTF-8");
|
|
14989
|
+
}
|
|
14990
|
+
} finally {
|
|
14991
|
+
closeSync10(fd);
|
|
14992
|
+
}
|
|
14993
|
+
}
|
|
14994
|
+
function parse6(text2) {
|
|
14995
|
+
let at = 0, nodes = 0;
|
|
14996
|
+
const numberPattern = /-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?/y;
|
|
14997
|
+
const space = () => {
|
|
14998
|
+
while (at < text2.length && /[\x20\t\r\n]/.test(text2[at]))
|
|
14999
|
+
at++;
|
|
15000
|
+
};
|
|
15001
|
+
function string() {
|
|
15002
|
+
need3(text2[at] === '"', "contains invalid JSON");
|
|
15003
|
+
const start = at++;
|
|
15004
|
+
while (at < text2.length) {
|
|
15005
|
+
const character = text2[at++];
|
|
15006
|
+
if (character === '"') {
|
|
15007
|
+
let value2;
|
|
15008
|
+
try {
|
|
15009
|
+
value2 = JSON.parse(text2.slice(start, at));
|
|
15010
|
+
} catch {
|
|
15011
|
+
throw new Error("Claude settings witness contains invalid JSON string");
|
|
15012
|
+
}
|
|
15013
|
+
need3(value2.length <= CLAUDE_SETTINGS_WITNESS_LIMITS.stringCharacters, "exceeds its string limit");
|
|
15014
|
+
return value2;
|
|
15015
|
+
}
|
|
15016
|
+
if (character === "\\")
|
|
15017
|
+
at++;
|
|
15018
|
+
}
|
|
15019
|
+
throw new Error("Claude settings witness contains an unterminated JSON string");
|
|
15020
|
+
}
|
|
15021
|
+
function value(depth) {
|
|
15022
|
+
need3(depth <= CLAUDE_SETTINGS_WITNESS_LIMITS.depth && ++nodes <= CLAUDE_SETTINGS_WITNESS_LIMITS.nodes, "exceeds its nesting or node limit");
|
|
15023
|
+
space();
|
|
15024
|
+
const character = text2[at];
|
|
15025
|
+
if (character === '"')
|
|
15026
|
+
return { kind: "string", value: string() };
|
|
15027
|
+
if (character === "{" || character === "[") {
|
|
15028
|
+
at++;
|
|
15029
|
+
space();
|
|
15030
|
+
const object4 = character === "{", end = object4 ? "}" : "]", entries = [], items = [], keys = new Set;
|
|
15031
|
+
if (text2[at] !== end)
|
|
15032
|
+
while (true) {
|
|
15033
|
+
if (object4) {
|
|
15034
|
+
space();
|
|
15035
|
+
const key = string();
|
|
15036
|
+
need3(!keys.has(key), "contains a duplicate JSON key");
|
|
15037
|
+
keys.add(key);
|
|
15038
|
+
space();
|
|
15039
|
+
need3(text2[at++] === ":", "contains invalid JSON");
|
|
15040
|
+
entries.push([key, value(depth + 1)]);
|
|
15041
|
+
} else
|
|
15042
|
+
items.push(value(depth + 1));
|
|
15043
|
+
space();
|
|
15044
|
+
if (text2[at] === end)
|
|
15045
|
+
break;
|
|
15046
|
+
need3(text2[at++] === ",", "contains invalid JSON");
|
|
15047
|
+
}
|
|
15048
|
+
at++;
|
|
15049
|
+
return object4 ? { kind: "object", entries } : { kind: "array", items };
|
|
15050
|
+
}
|
|
15051
|
+
for (const literal of ["true", "false", "null"])
|
|
15052
|
+
if (text2.startsWith(literal, at)) {
|
|
15053
|
+
at += literal.length;
|
|
15054
|
+
return { kind: "literal", value: literal };
|
|
15055
|
+
}
|
|
15056
|
+
numberPattern.lastIndex = at;
|
|
15057
|
+
const number = numberPattern.exec(text2);
|
|
15058
|
+
need3(number, "contains invalid JSON");
|
|
15059
|
+
at += number[0].length;
|
|
15060
|
+
return { kind: "number", value: number[0] };
|
|
15061
|
+
}
|
|
15062
|
+
const root2 = value(0);
|
|
15063
|
+
space();
|
|
15064
|
+
need3(at === text2.length && root2.kind === "object", "requires a JSON object without trailing content");
|
|
15065
|
+
need3(root2.entries.length <= CLAUDE_SETTINGS_WITNESS_LIMITS.rows, "exceeds its settings field limit");
|
|
15066
|
+
return root2;
|
|
15067
|
+
}
|
|
15068
|
+
var BOOLEAN_PREFERENCES = new Set([
|
|
15069
|
+
"autoScrollEnabled",
|
|
15070
|
+
"axScreenReader",
|
|
15071
|
+
"emojiCompletionEnabled",
|
|
15072
|
+
"prefersReducedMotion",
|
|
15073
|
+
"showTurnDuration",
|
|
15074
|
+
"spinnerTipsEnabled",
|
|
15075
|
+
"syntaxHighlightingDisabled",
|
|
15076
|
+
"terminalProgressBarEnabled",
|
|
15077
|
+
"terminalTitleFromRename",
|
|
15078
|
+
"verbose",
|
|
15079
|
+
"wheelScrollAccelerationEnabled"
|
|
15080
|
+
]);
|
|
15081
|
+
var ENUM_PREFERENCES = Object.freeze({
|
|
15082
|
+
editorMode: ["normal", "vim"],
|
|
15083
|
+
tui: ["default", "fullscreen"],
|
|
15084
|
+
viewMode: ["default", "verbose", "focus"]
|
|
15085
|
+
});
|
|
15086
|
+
var BUILTIN_MODEL_SELECTIONS = new Set([
|
|
15087
|
+
"default",
|
|
15088
|
+
"best",
|
|
15089
|
+
"fable",
|
|
15090
|
+
"fable[1m]",
|
|
15091
|
+
"sonnet",
|
|
15092
|
+
"sonnet[1m]",
|
|
15093
|
+
"opus",
|
|
15094
|
+
"opus[1m]",
|
|
15095
|
+
"haiku",
|
|
15096
|
+
"opusplan",
|
|
15097
|
+
"claude-fable-5-1",
|
|
15098
|
+
"claude-fable-5",
|
|
15099
|
+
"claude-fable-5[1m]",
|
|
15100
|
+
"claude-opus-5",
|
|
15101
|
+
"claude-sonnet-5",
|
|
15102
|
+
"claude-haiku-4-5-20251001",
|
|
15103
|
+
"claude-opus-4-6",
|
|
15104
|
+
"claude-sonnet-4-5",
|
|
15105
|
+
"claude-sonnet-4-5-20250929",
|
|
15106
|
+
"claude-opus-4-8",
|
|
15107
|
+
"claude-opus-4-8[1m]",
|
|
15108
|
+
"claude-opus-4-7",
|
|
15109
|
+
"claude-sonnet-4-6",
|
|
15110
|
+
"claude-opus-4-5-20251101",
|
|
15111
|
+
"claude-opus-4-5",
|
|
15112
|
+
"claude-haiku-4-5",
|
|
15113
|
+
"claude-fable-5-1[1m]",
|
|
15114
|
+
"claude-opus-5[1m]",
|
|
15115
|
+
"claude-opus-4-7[1m]",
|
|
15116
|
+
"claude-opus-4-6[1m]",
|
|
15117
|
+
"claude-sonnet-4-6[1m]"
|
|
15118
|
+
]);
|
|
15119
|
+
function canonical3(value) {
|
|
15120
|
+
if (value.kind === "object")
|
|
15121
|
+
return { kind: "object", entries: value.entries.map(([key, child]) => [key, canonical3(child)]).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0) };
|
|
15122
|
+
if (value.kind === "array")
|
|
15123
|
+
return { kind: "array", items: value.items.map(canonical3) };
|
|
15124
|
+
return value;
|
|
15125
|
+
}
|
|
15126
|
+
function settingsDigest(text2) {
|
|
15127
|
+
const value = parse6(text2);
|
|
15128
|
+
value.entries = value.entries.filter(([key, child]) => {
|
|
15129
|
+
if (key === "model") {
|
|
15130
|
+
need3(child.kind === "string", "contains an invalid model selection");
|
|
15131
|
+
return !BUILTIN_MODEL_SELECTIONS.has(child.value);
|
|
15132
|
+
}
|
|
15133
|
+
if (BOOLEAN_PREFERENCES.has(key)) {
|
|
15134
|
+
need3(child.kind === "literal" && (child.value === "true" || child.value === "false"), "contains an invalid display preference");
|
|
15135
|
+
return false;
|
|
15136
|
+
}
|
|
15137
|
+
if (Object.hasOwn(ENUM_PREFERENCES, key)) {
|
|
15138
|
+
need3(child.kind === "string" && ENUM_PREFERENCES[key].includes(child.value), "contains an invalid display preference");
|
|
15139
|
+
return false;
|
|
15140
|
+
}
|
|
15141
|
+
return true;
|
|
15142
|
+
});
|
|
15143
|
+
return createHash12("sha256").update("hasna.skills.claude-settings.v1\x00").update(JSON.stringify(canonical3(value))).digest("hex");
|
|
15144
|
+
}
|
|
15145
|
+
function hashClaudeSettingsReplacement(text2, budget) {
|
|
15146
|
+
need3(typeof text2 === "string", "requires settings text");
|
|
15147
|
+
const bytes = Buffer.byteLength(text2);
|
|
15148
|
+
need3(bytes <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes && Number.isSafeInteger(budget.remaining) && budget.remaining >= bytes, "exceeds its byte limit");
|
|
15149
|
+
budget.remaining -= bytes;
|
|
15150
|
+
return settingsDigest(text2);
|
|
15151
|
+
}
|
|
15152
|
+
function captureClaudeSettings(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
15153
|
+
return { path, hashMode: "claude-settings-v1", sha256: settingsDigest(readSettings(path, budget)) };
|
|
15154
|
+
}
|
|
15155
|
+
|
|
14934
15156
|
// src/lib/agent-discovery.ts
|
|
14935
|
-
var digest = (text2) =>
|
|
15157
|
+
var digest = (text2) => createHash13("sha256").update(text2).digest("hex");
|
|
14936
15158
|
function parseConfig(text2, path, toml = false) {
|
|
14937
15159
|
try {
|
|
14938
15160
|
const value = toml ? Bun.TOML.parse(text2) : JSON.parse(text2);
|
|
@@ -14944,12 +15166,12 @@ function parseConfig(text2, path, toml = false) {
|
|
|
14944
15166
|
}
|
|
14945
15167
|
}
|
|
14946
15168
|
function safe4(path) {
|
|
14947
|
-
if (!
|
|
15169
|
+
if (!isAbsolute14(path) || path.includes("\x00"))
|
|
14948
15170
|
throw new Error("Expected an absolute native discovery path");
|
|
14949
|
-
for (let cursor = path;; cursor =
|
|
14950
|
-
if (
|
|
15171
|
+
for (let cursor = path;; cursor = dirname14(cursor)) {
|
|
15172
|
+
if (lstatSync17(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
14951
15173
|
throw new Error(`Refusing symlink native discovery input: ${cursor}`);
|
|
14952
|
-
if (
|
|
15174
|
+
if (dirname14(cursor) === cursor)
|
|
14953
15175
|
break;
|
|
14954
15176
|
}
|
|
14955
15177
|
}
|
|
@@ -14957,7 +15179,7 @@ function read(path, changes) {
|
|
|
14957
15179
|
safe4(path);
|
|
14958
15180
|
if (changes?.has(path))
|
|
14959
15181
|
return changes.get(path);
|
|
14960
|
-
const stat2 =
|
|
15182
|
+
const stat2 = lstatSync17(path, { throwIfNoEntry: false });
|
|
14961
15183
|
if (!stat2)
|
|
14962
15184
|
return null;
|
|
14963
15185
|
if (!stat2.isFile() || stat2.size > 16 * 1024 * 1024)
|
|
@@ -14965,6 +15187,14 @@ function read(path, changes) {
|
|
|
14965
15187
|
return readFileSync13(path, "utf8");
|
|
14966
15188
|
}
|
|
14967
15189
|
function projected(source, changes, budget = discoveryByteBudget()) {
|
|
15190
|
+
if (source.hashMode === "claude-settings-v1") {
|
|
15191
|
+
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
15192
|
+
throw new Error("Claude settings witnesses require exact typed metadata");
|
|
15193
|
+
const current = captureClaudeSettings(source.path, budget).sha256;
|
|
15194
|
+
if (current !== source.sha256)
|
|
15195
|
+
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
15196
|
+
return changes?.has(source.path) ? hashClaudeSettingsReplacement(changes.get(source.path), budget) : current;
|
|
15197
|
+
}
|
|
14968
15198
|
if (source.hashMode === "claude-marketplace-registry") {
|
|
14969
15199
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256) || changes?.has(source.path))
|
|
14970
15200
|
throw new Error("Claude marketplace witnesses require an exact reviewed registry without synthetic changes");
|
|
@@ -15022,6 +15252,8 @@ function verifyAgentDiscovery(binding) {
|
|
|
15022
15252
|
safe4(root2);
|
|
15023
15253
|
}
|
|
15024
15254
|
function assertMarketplaceBinding(binding, source) {
|
|
15255
|
+
if (source.hashMode === "claude-settings-v1" && (binding.agent !== "claude" || binding.method !== "reviewed" || basename8(source.path) !== "settings.json"))
|
|
15256
|
+
throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
|
|
15025
15257
|
if (source.hashMode === "claude-marketplace-registry" && (binding.agent !== "claude" || binding.method !== "reviewed"))
|
|
15026
15258
|
throw new Error("Claude marketplace witnesses require explicit reviewed Claude discovery");
|
|
15027
15259
|
}
|
|
@@ -15045,10 +15277,10 @@ function captureDiscoveryPathSources(paths) {
|
|
|
15045
15277
|
return paths.map((path) => ({ path, hashMode: "path-bytes", sha256: hashDiscoveryPathFile(path, budget) }));
|
|
15046
15278
|
}
|
|
15047
15279
|
function resolveAgentDiscovery(options) {
|
|
15048
|
-
const
|
|
15280
|
+
const canonical4 = options.canonical ?? resolve14, home = resolve14(options.home), agent = options.agent;
|
|
15049
15281
|
const sources = [], roots = new Set, builtinNames = [];
|
|
15050
15282
|
const witness = (path, format, fields) => {
|
|
15051
|
-
const source = { path:
|
|
15283
|
+
const source = { path: canonical4(path), sha256: null, ...format ? { format, fields } : {} };
|
|
15052
15284
|
source.sha256 = projected(source);
|
|
15053
15285
|
sources.push(source);
|
|
15054
15286
|
return read(source.path);
|
|
@@ -15076,7 +15308,7 @@ function resolveAgentDiscovery(options) {
|
|
|
15076
15308
|
continue;
|
|
15077
15309
|
if (normalized.startsWith("~") && normalized !== "~" && !normalized.startsWith("~/"))
|
|
15078
15310
|
unresolved("user-specific tilde expansion requires a separate discovery adapter");
|
|
15079
|
-
const path = normalized === "~" ? home : normalized.startsWith("~/") ? join23(home, normalized.slice(2)) :
|
|
15311
|
+
const path = normalized === "~" ? home : normalized.startsWith("~/") ? join23(home, normalized.slice(2)) : resolve14(home, ".hermes", normalized);
|
|
15080
15312
|
safe4(path);
|
|
15081
15313
|
roots.add(path);
|
|
15082
15314
|
}
|
|
@@ -15085,21 +15317,21 @@ function resolveAgentDiscovery(options) {
|
|
|
15085
15317
|
const executable = Bun.which("gemini");
|
|
15086
15318
|
if (executable) {
|
|
15087
15319
|
let packageRoot;
|
|
15088
|
-
for (let directory =
|
|
15320
|
+
for (let directory = dirname14(realpathSync4(executable)), depth = 0;depth < 8; directory = dirname14(directory), depth++) {
|
|
15089
15321
|
const path = join23(directory, "package.json"), raw = read(path);
|
|
15090
15322
|
if (raw !== null && parseConfig(raw, path).name === "@google/gemini-cli") {
|
|
15091
15323
|
packageRoot = directory;
|
|
15092
15324
|
witness(path);
|
|
15093
15325
|
break;
|
|
15094
15326
|
}
|
|
15095
|
-
if (
|
|
15327
|
+
if (dirname14(directory) === directory)
|
|
15096
15328
|
break;
|
|
15097
15329
|
}
|
|
15098
15330
|
if (!packageRoot)
|
|
15099
15331
|
unresolved("installed Gemini package layout is not recognized");
|
|
15100
15332
|
const builtinRoot = join23(packageRoot, "bundle/builtin");
|
|
15101
15333
|
safe4(builtinRoot);
|
|
15102
|
-
if (!
|
|
15334
|
+
if (!lstatSync17(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
|
|
15103
15335
|
unresolved("installed Gemini builtin root is missing");
|
|
15104
15336
|
for (const name of readdirSync9(builtinRoot).sort()) {
|
|
15105
15337
|
const text2 = witness(join23(builtinRoot, name, "SKILL.md"));
|
|
@@ -15120,12 +15352,14 @@ function resolveAgentDiscovery(options) {
|
|
|
15120
15352
|
if (review.sources.some((source) => source.format !== undefined || source.fields !== undefined))
|
|
15121
15353
|
throw new Error("Explicit discovery reviews require full source-file hashes");
|
|
15122
15354
|
verifyAgentDiscovery(supplied);
|
|
15123
|
-
if (
|
|
15355
|
+
if (review.sources.some((source) => source.hashMode === "claude-settings-v1" && source.path !== canonical4(configPath)))
|
|
15356
|
+
throw new Error("Semantic settings witnesses must name the configured Claude configuration source");
|
|
15357
|
+
if (!review.sources.some((source) => source.path === canonical4(configPath)))
|
|
15124
15358
|
throw new Error("Discovery review must include the agent configuration source");
|
|
15125
15359
|
return { ...supplied, roots: [...new Set([...roots, ...supplied.roots])].sort(), sources: [...sources, ...review.sources], ...agent === "gemini" ? { builtinNames } : {} };
|
|
15126
15360
|
}
|
|
15127
15361
|
function plugin(root2) {
|
|
15128
|
-
root2 =
|
|
15362
|
+
root2 = canonical4(root2);
|
|
15129
15363
|
safe4(root2);
|
|
15130
15364
|
const manifestPath = join23(root2, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
|
|
15131
15365
|
const raw = witness(manifestPath);
|
|
@@ -15137,7 +15371,7 @@ function resolveAgentDiscovery(options) {
|
|
|
15137
15371
|
unresolved("plugin hooks require a separate no-skill-injection review");
|
|
15138
15372
|
const commands = join23(root2, "commands");
|
|
15139
15373
|
safe4(commands);
|
|
15140
|
-
if (agent === "claude" && (manifest.commands !== undefined ||
|
|
15374
|
+
if (agent === "claude" && (manifest.commands !== undefined || lstatSync17(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length))
|
|
15141
15375
|
unresolved("legacy command discovery requires retirement or a dedicated format adapter");
|
|
15142
15376
|
const rootSkill = witness(join23(root2, "SKILL.md"));
|
|
15143
15377
|
if (rootSkill !== null)
|
|
@@ -15148,18 +15382,18 @@ function resolveAgentDiscovery(options) {
|
|
|
15148
15382
|
if (agent === "claude")
|
|
15149
15383
|
roots.add(join23(root2, "skills"));
|
|
15150
15384
|
for (const value of declared) {
|
|
15151
|
-
const path =
|
|
15385
|
+
const path = resolve14(root2, value);
|
|
15152
15386
|
if (path !== root2 && !path.startsWith(root2 + sep5))
|
|
15153
15387
|
unresolved("plugin skill path escapes its root");
|
|
15154
|
-
roots.add(path.endsWith(`${sep5}SKILL.md`) ?
|
|
15388
|
+
roots.add(path.endsWith(`${sep5}SKILL.md`) ? dirname14(path) : path);
|
|
15155
15389
|
}
|
|
15156
15390
|
}
|
|
15157
15391
|
if (agent === "claude") {
|
|
15158
15392
|
const registrations = witness(join23(home, ".claude/plugins/installed_plugins.json"));
|
|
15159
15393
|
const installed = registrations === null ? {} : parseConfig(registrations, join23(home, ".claude/plugins/installed_plugins.json")).plugins;
|
|
15160
|
-
const commands =
|
|
15394
|
+
const commands = canonical4(join23(home, ".claude/commands"));
|
|
15161
15395
|
safe4(commands);
|
|
15162
|
-
if (
|
|
15396
|
+
if (lstatSync17(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length)
|
|
15163
15397
|
unresolved("legacy home command discovery requires a dedicated format adapter");
|
|
15164
15398
|
for (const [id, enabled] of Object.entries(config.enabledPlugins ?? {})) {
|
|
15165
15399
|
if (enabled === false)
|
|
@@ -15179,7 +15413,7 @@ function resolveAgentDiscovery(options) {
|
|
|
15179
15413
|
unresolved("unsupported plugin enablement");
|
|
15180
15414
|
const split = id.lastIndexOf("@"), name = id.slice(0, split), marketplace = id.slice(split + 1);
|
|
15181
15415
|
const market = config.marketplaces?.[marketplace] ?? (marketplace === "personal" ? { source_type: "local", source: home } : undefined);
|
|
15182
|
-
if (split < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !
|
|
15416
|
+
if (split < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !isAbsolute14(market.source))
|
|
15183
15417
|
unresolved("enabled plugin marketplace is not an explicit local source");
|
|
15184
15418
|
const catalogText = witness(join23(market.source, ".agents/plugins/marketplace.json"));
|
|
15185
15419
|
if (catalogText === null)
|
|
@@ -15187,7 +15421,7 @@ function resolveAgentDiscovery(options) {
|
|
|
15187
15421
|
const catalog = parseConfig(catalogText, join23(market.source, ".agents/plugins/marketplace.json")), matches = Array.isArray(catalog.plugins) ? catalog.plugins.filter((item) => item.name === name) : [];
|
|
15188
15422
|
if (matches.length !== 1 || matches[0]?.source?.source !== "local" || typeof matches[0]?.source?.path !== "string")
|
|
15189
15423
|
unresolved("plugin catalog source is missing or ambiguous");
|
|
15190
|
-
plugin(
|
|
15424
|
+
plugin(resolve14(market.source, matches[0].source.path));
|
|
15191
15425
|
}
|
|
15192
15426
|
} else if (agent === "opencode") {
|
|
15193
15427
|
if (witness(join23(home, ".config/opencode/opencode.jsonc")) !== null || witness(join23(home, ".config/opencode/config.json")) !== null)
|
|
@@ -15195,18 +15429,18 @@ function resolveAgentDiscovery(options) {
|
|
|
15195
15429
|
if ((config.plugin?.length ?? 0) > 0 || config.skills?.urls?.length)
|
|
15196
15430
|
unresolved("external plugin or remote skill source");
|
|
15197
15431
|
for (const path of config.skills?.paths ?? []) {
|
|
15198
|
-
if (typeof path !== "string" || !
|
|
15432
|
+
if (typeof path !== "string" || !isAbsolute14(path))
|
|
15199
15433
|
unresolved("relative or malformed added skill root");
|
|
15200
15434
|
roots.add(path);
|
|
15201
15435
|
}
|
|
15202
15436
|
const localPlugins = join23(home, ".config/opencode/plugins");
|
|
15203
15437
|
safe4(localPlugins);
|
|
15204
|
-
if (
|
|
15438
|
+
if (lstatSync17(localPlugins, { throwIfNoEntry: false }) && readdirSync9(localPlugins).some((name) => name !== "skills-cli.js"))
|
|
15205
15439
|
unresolved("additional local plugin hooks require review");
|
|
15206
15440
|
} else if (agent === "hermes") {
|
|
15207
15441
|
for (const directory of [join23(home, ".hermes/plugins"), join23(home, ".hermes/hermes-agent")]) {
|
|
15208
15442
|
safe4(directory);
|
|
15209
|
-
if (
|
|
15443
|
+
if (lstatSync17(directory, { throwIfNoEntry: false }))
|
|
15210
15444
|
unresolved("installed runtime/plugin discovery requires reviewed source bindings");
|
|
15211
15445
|
}
|
|
15212
15446
|
if (Bun.which("hermes") || Object.keys(config.plugins ?? {}).length)
|
|
@@ -15216,11 +15450,11 @@ function resolveAgentDiscovery(options) {
|
|
|
15216
15450
|
unresolved("custom extension or skill paths");
|
|
15217
15451
|
const directory = join23(home, ".gemini/extensions");
|
|
15218
15452
|
safe4(directory);
|
|
15219
|
-
if (
|
|
15453
|
+
if (lstatSync17(directory, { throwIfNoEntry: false }))
|
|
15220
15454
|
for (const name of readdirSync9(directory)) {
|
|
15221
15455
|
const root2 = join23(directory, name);
|
|
15222
15456
|
safe4(root2);
|
|
15223
|
-
if (!
|
|
15457
|
+
if (!lstatSync17(root2)?.isDirectory())
|
|
15224
15458
|
continue;
|
|
15225
15459
|
const raw = witness(join23(root2, "gemini-extension.json"));
|
|
15226
15460
|
if (raw === null)
|
|
@@ -15231,7 +15465,7 @@ function resolveAgentDiscovery(options) {
|
|
|
15231
15465
|
roots.add(join23(root2, "skills"));
|
|
15232
15466
|
}
|
|
15233
15467
|
}
|
|
15234
|
-
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join23(home, ".hermes/plugins"), join23(home, ".hermes/hermes-agent")].map((path) =>
|
|
15468
|
+
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join23(home, ".hermes/plugins"), join23(home, ".hermes/hermes-agent")].map((path) => canonical4(path))) } : {} };
|
|
15235
15469
|
}
|
|
15236
15470
|
|
|
15237
15471
|
// src/lib/agent-adapters.ts
|
|
@@ -15375,7 +15609,7 @@ function disableCodexBundledSkills(text2) {
|
|
|
15375
15609
|
}
|
|
15376
15610
|
|
|
15377
15611
|
// src/lib/agent-integration.ts
|
|
15378
|
-
var sha = (data) =>
|
|
15612
|
+
var sha = (data) => createHash14("sha256").update(data).digest("hex");
|
|
15379
15613
|
var ROOTS = [
|
|
15380
15614
|
["claude", ".claude/skills"],
|
|
15381
15615
|
["codex", ".codex/skills"],
|
|
@@ -15394,11 +15628,11 @@ var ROOTS = [
|
|
|
15394
15628
|
["copilot", ".github/skills"]
|
|
15395
15629
|
];
|
|
15396
15630
|
function assertSafePath(path) {
|
|
15397
|
-
let cursor =
|
|
15631
|
+
let cursor = resolve15(path);
|
|
15398
15632
|
while (true) {
|
|
15399
|
-
if (
|
|
15633
|
+
if (lstatSync18(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
15400
15634
|
throw new Error(`Refusing symlink path: ${cursor}`);
|
|
15401
|
-
const parent =
|
|
15635
|
+
const parent = dirname15(cursor);
|
|
15402
15636
|
if (parent === cursor)
|
|
15403
15637
|
return;
|
|
15404
15638
|
cursor = parent;
|
|
@@ -15407,16 +15641,16 @@ function assertSafePath(path) {
|
|
|
15407
15641
|
function readRootAlias(home, agent) {
|
|
15408
15642
|
assertSafePath(home);
|
|
15409
15643
|
const realHome = realpathSync5(home), alias = join25(realHome, `.${agent}`);
|
|
15410
|
-
const stat2 =
|
|
15644
|
+
const stat2 = lstatSync18(alias, { throwIfNoEntry: false, bigint: true });
|
|
15411
15645
|
if (!stat2?.isSymbolicLink())
|
|
15412
15646
|
throw new Error(`Agent root alias changed after planning: ${alias}`);
|
|
15413
|
-
const link = readlinkSync2(alias), targetPath =
|
|
15647
|
+
const link = readlinkSync2(alias), targetPath = resolve15(dirname15(alias), link);
|
|
15414
15648
|
assertSafePath(targetPath);
|
|
15415
|
-
const targetStat =
|
|
15649
|
+
const targetStat = lstatSync18(targetPath, { throwIfNoEntry: false });
|
|
15416
15650
|
if (!targetStat?.isDirectory())
|
|
15417
15651
|
throw new Error(`Agent root alias must target an existing directory: ${alias}`);
|
|
15418
15652
|
const target = realpathSync5(targetPath), inside = relative5(realHome, target);
|
|
15419
|
-
if (!inside || inside === ".." || inside.startsWith(`..${sep6}`) ||
|
|
15653
|
+
if (!inside || inside === ".." || inside.startsWith(`..${sep6}`) || isAbsolute15(inside))
|
|
15420
15654
|
throw new Error(`Agent root alias target must be inside the real home: ${alias}`);
|
|
15421
15655
|
return { agent, home: realHome, alias, target, link, aliasIdentity: `${stat2.dev}:${stat2.ino}:${stat2.ctimeNs}`, targetIdentity: `${targetStat.dev}:${targetStat.ino}` };
|
|
15422
15656
|
}
|
|
@@ -15425,14 +15659,14 @@ function rootAliases(home, allowed = false) {
|
|
|
15425
15659
|
return [];
|
|
15426
15660
|
const result = [];
|
|
15427
15661
|
for (const agent of ["claude", "codex"])
|
|
15428
|
-
if (
|
|
15662
|
+
if (lstatSync18(join25(home, `.${agent}`), { throwIfNoEntry: false })?.isSymbolicLink())
|
|
15429
15663
|
result.push(readRootAlias(home, agent));
|
|
15430
15664
|
if (result.some((item, index) => result.slice(index + 1).some((other) => item.target === other.target || item.target.startsWith(other.target + sep6) || other.target.startsWith(item.target + sep6))))
|
|
15431
15665
|
throw new Error("Agent root alias targets must not overlap");
|
|
15432
15666
|
return result;
|
|
15433
15667
|
}
|
|
15434
15668
|
function canonicalAgentPath(path, aliases) {
|
|
15435
|
-
const absolute =
|
|
15669
|
+
const absolute = resolve15(path), binding = aliases.find((item) => absolute === item.alias || absolute.startsWith(item.alias + sep6));
|
|
15436
15670
|
return binding ? join25(binding.target, relative5(binding.alias, absolute)) : absolute;
|
|
15437
15671
|
}
|
|
15438
15672
|
function recheckRootAliases(aliases) {
|
|
@@ -15446,35 +15680,35 @@ function recheckRootAliases(aliases) {
|
|
|
15446
15680
|
}
|
|
15447
15681
|
function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
|
|
15448
15682
|
assertSafePath(path);
|
|
15449
|
-
const before =
|
|
15683
|
+
const before = lstatSync18(path);
|
|
15450
15684
|
if (!before.isFile() || before.size > maximum)
|
|
15451
15685
|
throw new Error("Unsupported or oversized native skill file");
|
|
15452
|
-
const descriptor =
|
|
15686
|
+
const descriptor = openSync11(path, constants10.O_RDONLY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK);
|
|
15453
15687
|
try {
|
|
15454
|
-
const opened =
|
|
15688
|
+
const opened = fstatSync11(descriptor);
|
|
15455
15689
|
if (!opened.isFile() || opened.dev !== before.dev || opened.ino !== before.ino || opened.size !== before.size)
|
|
15456
15690
|
throw new Error("Native skill file changed while reading");
|
|
15457
15691
|
const bytes = Buffer.allocUnsafe(before.size + 1);
|
|
15458
15692
|
let length = 0;
|
|
15459
15693
|
while (length < bytes.length) {
|
|
15460
|
-
const count =
|
|
15694
|
+
const count = readSync9(descriptor, bytes, length, bytes.length - length, null);
|
|
15461
15695
|
if (!count)
|
|
15462
15696
|
break;
|
|
15463
15697
|
length += count;
|
|
15464
15698
|
}
|
|
15465
|
-
const after =
|
|
15699
|
+
const after = fstatSync11(descriptor);
|
|
15466
15700
|
if (length !== before.size || after.size !== before.size || after.mtimeMs !== opened.mtimeMs || after.ctimeMs !== opened.ctimeMs)
|
|
15467
15701
|
throw new Error("Native skill file changed while reading");
|
|
15468
15702
|
return bytes.subarray(0, length);
|
|
15469
15703
|
} finally {
|
|
15470
|
-
|
|
15704
|
+
closeSync11(descriptor);
|
|
15471
15705
|
}
|
|
15472
15706
|
}
|
|
15473
15707
|
function treeHash(root2) {
|
|
15474
|
-
const hash2 =
|
|
15708
|
+
const hash2 = createHash14("sha256");
|
|
15475
15709
|
let bytes = 0, files = 0;
|
|
15476
15710
|
function visit2(path) {
|
|
15477
|
-
const stat2 =
|
|
15711
|
+
const stat2 = lstatSync18(path);
|
|
15478
15712
|
if (stat2.isSymbolicLink())
|
|
15479
15713
|
throw new Error(`Refusing symlink in skill: ${path}`);
|
|
15480
15714
|
const rel = relative5(root2, path);
|
|
@@ -15500,11 +15734,11 @@ function treeHash(root2) {
|
|
|
15500
15734
|
function projectAncestorDirectories(projects) {
|
|
15501
15735
|
const directories = new Set;
|
|
15502
15736
|
for (const project of projects) {
|
|
15503
|
-
for (let path =
|
|
15737
|
+
for (let path = resolve15(project), depth = 0;; depth++) {
|
|
15504
15738
|
if (depth >= 100)
|
|
15505
15739
|
throw new Error("NATIVE_SKILL_DRIFT: project ancestor discovery limit exceeded");
|
|
15506
15740
|
directories.add(path);
|
|
15507
|
-
const parent =
|
|
15741
|
+
const parent = dirname15(path);
|
|
15508
15742
|
if (parent === path)
|
|
15509
15743
|
break;
|
|
15510
15744
|
path = parent;
|
|
@@ -15531,10 +15765,10 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
15531
15765
|
throw new Error("Native skill discovery metadata limit exceeded");
|
|
15532
15766
|
}
|
|
15533
15767
|
function emptySiblingCacheAlias(path, parent) {
|
|
15534
|
-
const link = readlinkSync2(path), target =
|
|
15535
|
-
if (
|
|
15768
|
+
const link = readlinkSync2(path), target = resolve15(parent, link);
|
|
15769
|
+
if (dirname15(target) !== parent || (isAbsolute15(link) ? link !== target : dirname15(link) !== "."))
|
|
15536
15770
|
return false;
|
|
15537
|
-
if (!
|
|
15771
|
+
if (!lstatSync18(target, { throwIfNoEntry: false })?.isDirectory())
|
|
15538
15772
|
return false;
|
|
15539
15773
|
const scan = cacheScans.get(target);
|
|
15540
15774
|
return Boolean(scan?.complete && !scan.hasSkills && scan.entries <= maxAliasProofEntries);
|
|
@@ -15546,7 +15780,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
15546
15780
|
assertSafePath(path);
|
|
15547
15781
|
if (!existsSync11(path))
|
|
15548
15782
|
return scan;
|
|
15549
|
-
const stat2 =
|
|
15783
|
+
const stat2 = lstatSync18(path);
|
|
15550
15784
|
if (stat2.isFile())
|
|
15551
15785
|
return scan;
|
|
15552
15786
|
if (!stat2.isDirectory())
|
|
@@ -15565,7 +15799,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
15565
15799
|
}
|
|
15566
15800
|
const bridge = !vendor && isOwnedCliBridge(path, bridgePaths);
|
|
15567
15801
|
const rootAlias = aliases.find((item) => path === item.target || path.startsWith(item.target + sep6));
|
|
15568
|
-
entries.push({ agent, path, hash: treeHash(path), managed, vendor, ...agent === "codex" && path.startsWith(canonicalAgentPath(join25(home, ".codex", "skills", ".system"), aliases) + sep6) ? { system: true } : {}, ...bridge ? { bridge: true, bridgeHome:
|
|
15802
|
+
entries.push({ agent, path, hash: treeHash(path), managed, vendor, ...agent === "codex" && path.startsWith(canonicalAgentPath(join25(home, ".codex", "skills", ".system"), aliases) + sep6) ? { system: true } : {}, ...bridge ? { bridge: true, bridgeHome: resolve15(home) } : {}, ...rootAlias ? { rootAlias } : {} });
|
|
15569
15803
|
return scan;
|
|
15570
15804
|
}
|
|
15571
15805
|
if (depth > (vendor ? 32 : 3))
|
|
@@ -15592,7 +15826,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
15592
15826
|
if (isVendor && !options.includeVendor)
|
|
15593
15827
|
continue;
|
|
15594
15828
|
const child = join25(path, name);
|
|
15595
|
-
if (isVendor &&
|
|
15829
|
+
if (isVendor && lstatSync18(child, { throwIfNoEntry: false })?.isSymbolicLink()) {
|
|
15596
15830
|
const target = statSync8(child, { throwIfNoEntry: false });
|
|
15597
15831
|
if (target?.isFile() || pluginCache && target?.isDirectory() && emptySiblingCacheAlias(child, path)) {
|
|
15598
15832
|
scan.entries++;
|
|
@@ -15714,7 +15948,7 @@ function configureHooks(config, agent, command, profileId, nativeReady) {
|
|
|
15714
15948
|
function disableCodexSkills(text2, skills, aliases, bridgePath) {
|
|
15715
15949
|
const bundled = disableCodexBundledSkills(text2);
|
|
15716
15950
|
let result = bundled;
|
|
15717
|
-
const bridgeSelector = (entry) => typeof entry.name === "string" && entry.name.trim() === CLI_BRIDGE_NAME || typeof entry.path === "string" && [
|
|
15951
|
+
const bridgeSelector = (entry) => typeof entry.name === "string" && entry.name.trim() === CLI_BRIDGE_NAME || typeof entry.path === "string" && [resolve15(bridgePath), resolve15(join25(bridgePath, "SKILL.md"))].includes(canonicalAgentPath(entry.path, aliases));
|
|
15718
15952
|
const previousConfig = Bun.TOML.parse(bundled).skills?.config;
|
|
15719
15953
|
if (previousConfig !== undefined && (!Array.isArray(previousConfig) || previousConfig.some((entry) => !entry || typeof entry !== "object" || entry.path !== undefined && entry.name !== undefined)))
|
|
15720
15954
|
throw new Error("Codex skill controls require one path or name selector per [[skills.config]] entry; review ambiguous entries before running skills hook install");
|
|
@@ -15726,7 +15960,7 @@ function disableCodexSkills(text2, skills, aliases, bridgePath) {
|
|
|
15726
15960
|
result = result.replace(CODEX_SKILL_CONFIG_SECTIONS, (section) => {
|
|
15727
15961
|
const parsed = Bun.TOML.parse(section);
|
|
15728
15962
|
const declared = parsed.skills?.config?.[0];
|
|
15729
|
-
if (!declared || !(skill.enabled && bridgeSelector(declared)) && !(typeof declared.path === "string" && [
|
|
15963
|
+
if (!declared || !(skill.enabled && bridgeSelector(declared)) && !(typeof declared.path === "string" && [resolve15(path), resolve15(skill.path)].includes(canonicalAgentPath(declared.path, aliases))))
|
|
15730
15964
|
return section;
|
|
15731
15965
|
found = true;
|
|
15732
15966
|
return /^\s*enabled\s*=/m.test(section) ? section.replace(/^\s*enabled\s*=.*$/m, `enabled = ${skill.enabled}`) : `${section.trimEnd()}
|
|
@@ -15844,7 +16078,7 @@ function planAgentIntegration(options) {
|
|
|
15844
16078
|
version: CLI_BRIDGE_VERSION,
|
|
15845
16079
|
digest: CLI_BRIDGE_DIGEST,
|
|
15846
16080
|
agents: [...new Set([...priorAgents, ...options.agents])].sort(),
|
|
15847
|
-
home:
|
|
16081
|
+
home: resolve15(home),
|
|
15848
16082
|
includeVendor: true,
|
|
15849
16083
|
...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join25(dataDir2, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256: sha(renderHermesSupervisor(bindings.get("hermes").command, bindings.get("hermes").profileId)) } } } : {},
|
|
15850
16084
|
commands: { ...policy.bridge?.commands, ...Object.fromEntries([...bindings].map(([agent, binding]) => [agent, binding.command])) },
|
|
@@ -15861,7 +16095,7 @@ function planAgentIntegration(options) {
|
|
|
15861
16095
|
}
|
|
15862
16096
|
function atomicWrite2(path, content) {
|
|
15863
16097
|
assertSafePath(path);
|
|
15864
|
-
mkdirSync7(
|
|
16098
|
+
mkdirSync7(dirname15(path), { recursive: true, mode: 448 });
|
|
15865
16099
|
const temporary = `${path}.skills-${randomUUID3()}`;
|
|
15866
16100
|
try {
|
|
15867
16101
|
writeFileSync5(temporary, content, { mode: 384, flag: "wx" });
|
|
@@ -15874,10 +16108,10 @@ function atomicWrite2(path, content) {
|
|
|
15874
16108
|
function applyAgentIntegration(plan) {
|
|
15875
16109
|
const policyPath = join25(plan.dataDir, "agent-policy.json");
|
|
15876
16110
|
assertSafePath(policyPath);
|
|
15877
|
-
const currentText = (path) =>
|
|
16111
|
+
const currentText = (path) => resolve15(path) === resolve15(policyPath) ? readManagedSkillPolicySnapshot(plan.dataDir)?.text ?? null : readOptional(path);
|
|
15878
16112
|
readManagedSkillPolicySnapshot(plan.dataDir);
|
|
15879
16113
|
for (const change of plan.changes)
|
|
15880
|
-
if (
|
|
16114
|
+
if (resolve15(change.path) === resolve15(policyPath))
|
|
15881
16115
|
parseManagedSkillPolicy(change.after);
|
|
15882
16116
|
const aliases = plan.rootAliases ?? [];
|
|
15883
16117
|
recheckRootAliases(aliases);
|
|
@@ -15907,7 +16141,7 @@ function applyAgentIntegration(plan) {
|
|
|
15907
16141
|
recheckRootAliases(aliases);
|
|
15908
16142
|
if (currentText(change.path) !== change.before)
|
|
15909
16143
|
throw new Error(`Configuration changed after planning: ${change.path}`);
|
|
15910
|
-
for (let directory =
|
|
16144
|
+
for (let directory = dirname15(change.path);!existsSync11(directory); directory = dirname15(directory))
|
|
15911
16145
|
createdDirectories.add(directory);
|
|
15912
16146
|
const after = change.after;
|
|
15913
16147
|
atomicWrite2(change.path, after);
|
|
@@ -15947,11 +16181,11 @@ function applyAgentIntegration(plan) {
|
|
|
15947
16181
|
}
|
|
15948
16182
|
function syncArchiveDirectory(path) {
|
|
15949
16183
|
assertSafePath(path);
|
|
15950
|
-
const descriptor =
|
|
16184
|
+
const descriptor = openSync11(path, constants10.O_RDONLY | constants10.O_DIRECTORY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK);
|
|
15951
16185
|
try {
|
|
15952
16186
|
fsyncSync3(descriptor);
|
|
15953
16187
|
} finally {
|
|
15954
|
-
|
|
16188
|
+
closeSync11(descriptor);
|
|
15955
16189
|
}
|
|
15956
16190
|
}
|
|
15957
16191
|
function writeArchiveJournal(path, value) {
|
|
@@ -15959,18 +16193,18 @@ function writeArchiveJournal(path, value) {
|
|
|
15959
16193
|
const temporary = `${path}.skills-${randomUUID3()}`;
|
|
15960
16194
|
let descriptor;
|
|
15961
16195
|
try {
|
|
15962
|
-
descriptor =
|
|
16196
|
+
descriptor = openSync11(temporary, constants10.O_WRONLY | constants10.O_CREAT | constants10.O_EXCL | constants10.O_NOFOLLOW, 384);
|
|
15963
16197
|
writeFileSync5(descriptor, `${JSON.stringify(value)}
|
|
15964
16198
|
`);
|
|
15965
16199
|
fsyncSync3(descriptor);
|
|
15966
|
-
|
|
16200
|
+
closeSync11(descriptor);
|
|
15967
16201
|
descriptor = undefined;
|
|
15968
16202
|
renameSync4(temporary, path);
|
|
15969
|
-
syncArchiveDirectory(
|
|
16203
|
+
syncArchiveDirectory(dirname15(path));
|
|
15970
16204
|
} finally {
|
|
15971
16205
|
if (descriptor !== undefined)
|
|
15972
|
-
|
|
15973
|
-
if (
|
|
16206
|
+
closeSync11(descriptor);
|
|
16207
|
+
if (lstatSync18(temporary, { throwIfNoEntry: false }))
|
|
15974
16208
|
unlinkSync4(temporary);
|
|
15975
16209
|
}
|
|
15976
16210
|
}
|
|
@@ -16003,7 +16237,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
16003
16237
|
const moved = [];
|
|
16004
16238
|
const verifyArchive = (entry) => {
|
|
16005
16239
|
assertSafePath(entry.archive);
|
|
16006
|
-
const stat2 =
|
|
16240
|
+
const stat2 = lstatSync18(entry.archive);
|
|
16007
16241
|
if (entry.discoveryOnly ? !stat2.isFile() : !stat2.isDirectory())
|
|
16008
16242
|
throw new Error("Archive type changed");
|
|
16009
16243
|
if ((entry.discoveryOnly ? sha(readNativeBytes(entry.archive)) : treeHash(entry.archive)) !== entry.hash)
|
|
@@ -16011,14 +16245,14 @@ function archiveNativeSkills(inventory, options) {
|
|
|
16011
16245
|
};
|
|
16012
16246
|
assertSafePath(archiveRoot);
|
|
16013
16247
|
const created = [];
|
|
16014
|
-
for (let path = archiveRoot;!existsSync11(path); path =
|
|
16248
|
+
for (let path = archiveRoot;!existsSync11(path); path = dirname15(path))
|
|
16015
16249
|
created.push(path);
|
|
16016
16250
|
mkdirSync7(archiveRoot, { recursive: true, mode: 448 });
|
|
16017
16251
|
try {
|
|
16018
16252
|
for (const directory of created)
|
|
16019
16253
|
syncArchiveDirectory(directory);
|
|
16020
16254
|
if (created.length)
|
|
16021
|
-
syncArchiveDirectory(
|
|
16255
|
+
syncArchiveDirectory(dirname15(created.at(-1)));
|
|
16022
16256
|
writeArchiveJournal(receiptPath, journal);
|
|
16023
16257
|
for (const [index, entry] of selected.entries()) {
|
|
16024
16258
|
recheckRootAliases(aliases);
|
|
@@ -16030,7 +16264,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
16030
16264
|
writeArchiveJournal(receiptPath, journal);
|
|
16031
16265
|
renameSync4(move.source, move.archive);
|
|
16032
16266
|
moved.push(move);
|
|
16033
|
-
syncArchiveDirectory(
|
|
16267
|
+
syncArchiveDirectory(dirname15(move.source));
|
|
16034
16268
|
syncArchiveDirectory(archiveRoot);
|
|
16035
16269
|
verifyArchive(move);
|
|
16036
16270
|
move.status = "archived";
|
|
@@ -16051,7 +16285,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
16051
16285
|
recheckRootAliases(aliases);
|
|
16052
16286
|
assertSafePath(entry.source);
|
|
16053
16287
|
assertSafePath(entry.archive);
|
|
16054
|
-
if (
|
|
16288
|
+
if (lstatSync18(entry.source, { throwIfNoEntry: false })) {
|
|
16055
16289
|
entry.status = "recovery-required";
|
|
16056
16290
|
entry.conflict = "source-occupied";
|
|
16057
16291
|
continue;
|
|
@@ -16065,10 +16299,10 @@ function archiveNativeSkills(inventory, options) {
|
|
|
16065
16299
|
}
|
|
16066
16300
|
if (entry.discoveryOnly) {
|
|
16067
16301
|
linkSync2(entry.archive, entry.source);
|
|
16068
|
-
syncArchiveDirectory(
|
|
16302
|
+
syncArchiveDirectory(dirname15(entry.source));
|
|
16069
16303
|
unlinkSync4(entry.archive);
|
|
16070
16304
|
} else {
|
|
16071
|
-
if (
|
|
16305
|
+
if (lstatSync18(entry.source, { throwIfNoEntry: false })) {
|
|
16072
16306
|
entry.status = "recovery-required";
|
|
16073
16307
|
entry.conflict = "source-occupied";
|
|
16074
16308
|
continue;
|
|
@@ -16076,7 +16310,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
16076
16310
|
renameSync4(entry.archive, entry.source);
|
|
16077
16311
|
}
|
|
16078
16312
|
entry.status = "restored";
|
|
16079
|
-
syncArchiveDirectory(
|
|
16313
|
+
syncArchiveDirectory(dirname15(entry.source));
|
|
16080
16314
|
syncArchiveDirectory(archiveRoot);
|
|
16081
16315
|
} catch {
|
|
16082
16316
|
entry.status = "recovery-required";
|
|
@@ -16115,7 +16349,7 @@ function isSkillsOwnershipMarker(marker) {
|
|
|
16115
16349
|
function hasSkillsOwnershipMarker(dir) {
|
|
16116
16350
|
const path = join26(dir, SYNC_MARKER_FILE);
|
|
16117
16351
|
try {
|
|
16118
|
-
if (!
|
|
16352
|
+
if (!lstatSync19(path).isFile())
|
|
16119
16353
|
return false;
|
|
16120
16354
|
const marker = JSON.parse(readFileSync15(path, "utf8"));
|
|
16121
16355
|
return isSkillsOwnershipMarker(marker);
|
|
@@ -16341,9 +16575,9 @@ function writeManagedSkillDir(dir, skillMd, options) {
|
|
|
16341
16575
|
const action = dirExists ? "update" : "create";
|
|
16342
16576
|
if (options.dryRun)
|
|
16343
16577
|
return { action, path: skillMdPath };
|
|
16344
|
-
const parentDir =
|
|
16578
|
+
const parentDir = dirname16(dir);
|
|
16345
16579
|
mkdirSync8(parentDir, { recursive: true });
|
|
16346
|
-
const transactionDir = mkdtempSync2(join26(parentDir, `.hasna-skills-write-${
|
|
16580
|
+
const transactionDir = mkdtempSync2(join26(parentDir, `.hasna-skills-write-${basename9(dir)}-`));
|
|
16347
16581
|
const candidateDir = join26(transactionDir, "candidate");
|
|
16348
16582
|
const backupDir = join26(transactionDir, "backup");
|
|
16349
16583
|
const candidateSkillMdPath = join26(candidateDir, "SKILL.md");
|
|
@@ -16832,7 +17066,7 @@ function loadProjectConfigCompat(targetDir) {
|
|
|
16832
17066
|
return loadProjectConfig(targetDir);
|
|
16833
17067
|
}
|
|
16834
17068
|
// src/lib/run-state.ts
|
|
16835
|
-
import { createHash as
|
|
17069
|
+
import { createHash as createHash15, randomBytes } from "crypto";
|
|
16836
17070
|
import { existsSync as existsSync15, mkdirSync as mkdirSync10, readFileSync as readFileSync18, readdirSync as readdirSync12, statSync as statSync10, writeFileSync as writeFileSync8 } from "fs";
|
|
16837
17071
|
import { extname, join as join29, relative as relative6 } from "path";
|
|
16838
17072
|
function createSkillRun(params, targetDir = process.cwd()) {
|
|
@@ -16959,7 +17193,7 @@ function collectRunArtifacts(context) {
|
|
|
16959
17193
|
artifacts.push({
|
|
16960
17194
|
path: toProjectRelative(context.targetDir, path),
|
|
16961
17195
|
mime: mimeForPath(path),
|
|
16962
|
-
sha256:
|
|
17196
|
+
sha256: createHash15("sha256").update(bytes).digest("hex"),
|
|
16963
17197
|
sizeBytes: stat2.size
|
|
16964
17198
|
});
|
|
16965
17199
|
}
|
|
@@ -17087,7 +17321,7 @@ __export(exports_external, {
|
|
|
17087
17321
|
pipe: () => pipe,
|
|
17088
17322
|
partialRecord: () => partialRecord,
|
|
17089
17323
|
parseAsync: () => parseAsync2,
|
|
17090
|
-
parse: () =>
|
|
17324
|
+
parse: () => parse9,
|
|
17091
17325
|
overwrite: () => _overwrite,
|
|
17092
17326
|
output: () => output,
|
|
17093
17327
|
optional: () => optional,
|
|
@@ -17307,7 +17541,7 @@ __export(exports_core2, {
|
|
|
17307
17541
|
prettifyError: () => prettifyError,
|
|
17308
17542
|
parseURLObject: () => parseURLObject,
|
|
17309
17543
|
parseAsync: () => parseAsync,
|
|
17310
|
-
parse: () =>
|
|
17544
|
+
parse: () => parse7,
|
|
17311
17545
|
meta: () => meta,
|
|
17312
17546
|
mergeValues: () => mergeValues,
|
|
17313
17547
|
memoizer: () => memoizer,
|
|
@@ -18761,7 +18995,7 @@ var _parse = (_Err) => {
|
|
|
18761
18995
|
};
|
|
18762
18996
|
return fn;
|
|
18763
18997
|
};
|
|
18764
|
-
var
|
|
18998
|
+
var parse7 = /* @__PURE__ */ _parse($ZodRealError);
|
|
18765
18999
|
var _parseAsync = (_Err) => {
|
|
18766
19000
|
const fn = async (schema, value, _ctx, params) => {
|
|
18767
19001
|
const ctx = _ctx ? { ..._ctx, async: true } : { async: true };
|
|
@@ -18832,18 +19066,18 @@ var validateAsync = async (schema, value, _ctx) => {
|
|
|
18832
19066
|
return result.issues.length === 0;
|
|
18833
19067
|
};
|
|
18834
19068
|
var _encode = (_Err) => {
|
|
18835
|
-
const
|
|
19069
|
+
const parse8 = _parse(_Err);
|
|
18836
19070
|
const fn = (schema, value, _ctx, _params) => {
|
|
18837
19071
|
const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" };
|
|
18838
|
-
return
|
|
19072
|
+
return parse8(schema, value, ctx, finalizeParams(fn, _params));
|
|
18839
19073
|
};
|
|
18840
19074
|
return fn;
|
|
18841
19075
|
};
|
|
18842
19076
|
var encode = /* @__PURE__ */ _encode($ZodRealError);
|
|
18843
19077
|
var _decode = (_Err) => {
|
|
18844
|
-
const
|
|
19078
|
+
const parse8 = _parse(_Err);
|
|
18845
19079
|
const fn = (schema, value, _ctx, _params) => {
|
|
18846
|
-
return
|
|
19080
|
+
return parse8(schema, value, _ctx, finalizeParams(fn, _params));
|
|
18847
19081
|
};
|
|
18848
19082
|
return fn;
|
|
18849
19083
|
};
|
|
@@ -21766,10 +22000,10 @@ var $ZodFunction = /* @__PURE__ */ $constructor("$ZodFunction", (inst, def) => {
|
|
|
21766
22000
|
throw new Error("implement() must be called with a function");
|
|
21767
22001
|
}
|
|
21768
22002
|
return Object.defineProperty(function(...args) {
|
|
21769
|
-
const parsedArgs = inst._def.input ?
|
|
22003
|
+
const parsedArgs = inst._def.input ? parse7(inst._def.input, args) : args;
|
|
21770
22004
|
const result = Reflect.apply(func, this, parsedArgs);
|
|
21771
22005
|
if (inst._def.output) {
|
|
21772
|
-
return
|
|
22006
|
+
return parse7(inst._def.output, result);
|
|
21773
22007
|
}
|
|
21774
22008
|
return result;
|
|
21775
22009
|
}, "_zod", { value: inst._zod, enumerable: false });
|
|
@@ -33407,7 +33641,7 @@ var ZodRealError = /* @__PURE__ */ $constructor("ZodError", initializer2, undefi
|
|
|
33407
33641
|
});
|
|
33408
33642
|
|
|
33409
33643
|
// node_modules/zod/v4/classic/parse.js
|
|
33410
|
-
var
|
|
33644
|
+
var parse9 = /* @__PURE__ */ _parse(ZodRealError);
|
|
33411
33645
|
var parseAsync2 = /* @__PURE__ */ _parseAsync(ZodRealError);
|
|
33412
33646
|
var safeParse2 = /* @__PURE__ */ _safeParse(ZodRealError);
|
|
33413
33647
|
var safeParseAsync2 = /* @__PURE__ */ _safeParseAsync(ZodRealError);
|
|
@@ -33543,7 +33777,7 @@ var ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
|
|
|
33543
33777
|
exports_util.own(this, "~standard", value);
|
|
33544
33778
|
},
|
|
33545
33779
|
parse: function _parse2(data, params) {
|
|
33546
|
-
return
|
|
33780
|
+
return parse9(this, data, params, { callee: _parse2 });
|
|
33547
33781
|
},
|
|
33548
33782
|
parseAsync: async function _parseAsync2(data, params) {
|
|
33549
33783
|
return await parseAsync2(this, data, params, { callee: _parseAsync2 });
|
|
@@ -36374,7 +36608,7 @@ function clone2(value) {
|
|
|
36374
36608
|
return value === undefined ? undefined : JSON.parse(JSON.stringify(value));
|
|
36375
36609
|
}
|
|
36376
36610
|
// src/lib/canonical-json.ts
|
|
36377
|
-
import { createHash as
|
|
36611
|
+
import { createHash as createHash16 } from "crypto";
|
|
36378
36612
|
function canonicalJson2(value, maximumBytes = 2 * 1024 * 1024) {
|
|
36379
36613
|
return canonicalJsonAtDepth(value, maximumBytes, 64);
|
|
36380
36614
|
}
|
|
@@ -36418,7 +36652,7 @@ function canonicalJsonAtDepth(value, maximumBytes, maximumDepth) {
|
|
|
36418
36652
|
return visit3(value, 0);
|
|
36419
36653
|
}
|
|
36420
36654
|
function canonicalJsonSha256(value, maximumBytes) {
|
|
36421
|
-
return
|
|
36655
|
+
return createHash16("sha256").update(canonicalJson2(value, maximumBytes)).digest("hex");
|
|
36422
36656
|
}
|
|
36423
36657
|
|
|
36424
36658
|
// src/lib/remote-recurring-contract.ts
|
|
@@ -37379,10 +37613,10 @@ async function readQuoteUnavailableCode(response) {
|
|
|
37379
37613
|
let timer;
|
|
37380
37614
|
let deadlineExceeded = false;
|
|
37381
37615
|
const expired = Symbol("quote body deadline");
|
|
37382
|
-
const deadline = new Promise((
|
|
37616
|
+
const deadline = new Promise((resolve16) => {
|
|
37383
37617
|
timer = setTimeout(() => {
|
|
37384
37618
|
deadlineExceeded = true;
|
|
37385
|
-
|
|
37619
|
+
resolve16(expired);
|
|
37386
37620
|
reader.cancel().catch(() => {});
|
|
37387
37621
|
}, 1500);
|
|
37388
37622
|
});
|
|
@@ -38610,10 +38844,10 @@ function recordScheduleRun(id, status, targetDir) {
|
|
|
38610
38844
|
saveSchedules(data, targetDir);
|
|
38611
38845
|
}
|
|
38612
38846
|
// src/lib/revision.ts
|
|
38613
|
-
import { createHash as
|
|
38847
|
+
import { createHash as createHash17 } from "crypto";
|
|
38614
38848
|
var REVISION_ID_PATTERN = /^[0-9a-f]{64}$/;
|
|
38615
38849
|
function revisionIdOf(content) {
|
|
38616
|
-
const
|
|
38850
|
+
const canonical4 = JSON.stringify({
|
|
38617
38851
|
slug: content.slug,
|
|
38618
38852
|
displayName: content.displayName,
|
|
38619
38853
|
description: content.description,
|
|
@@ -38626,14 +38860,14 @@ function revisionIdOf(content) {
|
|
|
38626
38860
|
bundleSha256: content.bundleSha256 ?? null,
|
|
38627
38861
|
bundleByteSize: content.bundleByteSize ?? null
|
|
38628
38862
|
});
|
|
38629
|
-
return
|
|
38863
|
+
return createHash17("sha256").update(canonical4).digest("hex");
|
|
38630
38864
|
}
|
|
38631
38865
|
function revisionIdOfRecord(record7) {
|
|
38632
38866
|
return revisionIdOf(record7);
|
|
38633
38867
|
}
|
|
38634
38868
|
// src/lib/pull.ts
|
|
38635
38869
|
import { existsSync as existsSync17, mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync3, readFileSync as readFileSync20, renameSync as renameSync6, rmSync as rmSync5, writeFileSync as writeFileSync10 } from "fs";
|
|
38636
|
-
import { dirname as
|
|
38870
|
+
import { dirname as dirname17, join as join31 } from "path";
|
|
38637
38871
|
|
|
38638
38872
|
// src/lib/skill-bundles.ts
|
|
38639
38873
|
import { createHmac, timingSafeEqual } from "crypto";
|
|
@@ -38975,7 +39209,7 @@ function installBundleAtomically(name, entries, options = {}, marker = {}) {
|
|
|
38975
39209
|
try {
|
|
38976
39210
|
for (const entry of entries) {
|
|
38977
39211
|
const destination = join31(staging, entry.path);
|
|
38978
|
-
mkdirSync12(
|
|
39212
|
+
mkdirSync12(dirname17(destination), { recursive: true });
|
|
38979
39213
|
writeFileSync10(destination, entry.bytes, { mode: entry.mode });
|
|
38980
39214
|
}
|
|
38981
39215
|
writePullMarker(staging, {
|
|
@@ -39069,7 +39303,7 @@ function splitNameVersion(raw) {
|
|
|
39069
39303
|
return version2 ? { name, version: version2 } : { name };
|
|
39070
39304
|
}
|
|
39071
39305
|
// src/lib/recurring-surface.ts
|
|
39072
|
-
import { isAbsolute as
|
|
39306
|
+
import { isAbsolute as isAbsolute16 } from "path";
|
|
39073
39307
|
|
|
39074
39308
|
// src/lib/remote-invitation-recovery.ts
|
|
39075
39309
|
class InvitationEmailInputError extends Error {
|
|
@@ -39167,7 +39401,7 @@ async function requestInvitationEmail(origin, action, input2) {
|
|
|
39167
39401
|
}
|
|
39168
39402
|
|
|
39169
39403
|
// src/lib/remote-private-publications.ts
|
|
39170
|
-
import { createHash as
|
|
39404
|
+
import { createHash as createHash18 } from "crypto";
|
|
39171
39405
|
var PRIVATE_PUBLICATION_MAX_BYTES = 16 * 1024 * 1024;
|
|
39172
39406
|
var failures2 = {
|
|
39173
39407
|
INVALID_REQUEST: [400, "The publication request is invalid."],
|
|
@@ -39214,7 +39448,7 @@ var hash3 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v);
|
|
|
39214
39448
|
var record8 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
39215
39449
|
var exact = (v, keys) => record8(v) && Object.keys(v).sort().join(",") === keys.sort().join(",");
|
|
39216
39450
|
var date5 = (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));
|
|
39217
|
-
var publicationSha256 = (bytes) =>
|
|
39451
|
+
var publicationSha256 = (bytes) => createHash18("sha256").update(bytes).digest("hex");
|
|
39218
39452
|
function checkedPublicationDeclaration(value) {
|
|
39219
39453
|
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 || !hash3(value.archiveSha256) || !Number.isSafeInteger(value.archiveByteSize) || Number(value.archiveByteSize) < 1 || Number(value.archiveByteSize) > PRIVATE_PUBLICATION_MAX_BYTES)
|
|
39220
39454
|
return bad();
|
|
@@ -39459,12 +39693,12 @@ class RemotePrivatePublicationsClient {
|
|
|
39459
39693
|
previous = view;
|
|
39460
39694
|
if (!["queued", "verifying"].includes(view.state) || Date.now() >= until)
|
|
39461
39695
|
return view;
|
|
39462
|
-
await new Promise((
|
|
39696
|
+
await new Promise((resolve16) => {
|
|
39463
39697
|
const timer = setTimeout(done, Math.min(1000, until - Date.now()));
|
|
39464
39698
|
function done() {
|
|
39465
39699
|
clearTimeout(timer);
|
|
39466
39700
|
options.signal?.removeEventListener("abort", done);
|
|
39467
|
-
|
|
39701
|
+
resolve16();
|
|
39468
39702
|
}
|
|
39469
39703
|
options.signal?.addEventListener("abort", done, { once: true });
|
|
39470
39704
|
});
|
|
@@ -39728,7 +39962,7 @@ var stateSchema = exports_external.object({
|
|
|
39728
39962
|
var uuid13 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
|
|
39729
39963
|
var context = { userId: uuid13.optional(), membershipId: uuid13.optional() };
|
|
39730
39964
|
var page2 = { limit: exports_external.number().int().min(1).max(100).optional(), cursor: exports_external.string().min(1).max(2048).optional() };
|
|
39731
|
-
var directory = exports_external.string().max(4096).refine(
|
|
39965
|
+
var directory = exports_external.string().max(4096).refine(isAbsolute16, "Use an absolute recovery directory");
|
|
39732
39966
|
var email4 = exports_external.string().trim().toLowerCase().email().max(254);
|
|
39733
39967
|
var code = exports_external.string().regex(/^\d{6}$/);
|
|
39734
39968
|
var recurringSurfaceSchemas = {
|
|
@@ -39879,7 +40113,7 @@ function findSkillsParityForMcpTool(tool) {
|
|
|
39879
40113
|
}
|
|
39880
40114
|
// src/lib/registry-sync.ts
|
|
39881
40115
|
import { mkdirSync as mkdirSync13, writeFileSync as writeFileSync11 } from "fs";
|
|
39882
|
-
import { dirname as
|
|
40116
|
+
import { dirname as dirname18, relative as relative7 } from "path";
|
|
39883
40117
|
function createRegistrySyncArtifact(options = {}) {
|
|
39884
40118
|
const profile = options.profile ?? "all";
|
|
39885
40119
|
const includeDocs = options.includeDocs ?? true;
|
|
@@ -39936,7 +40170,7 @@ function createRegistrySyncArtifact(options = {}) {
|
|
|
39936
40170
|
};
|
|
39937
40171
|
}
|
|
39938
40172
|
function writeRegistrySyncArtifact(path, artifact) {
|
|
39939
|
-
mkdirSync13(
|
|
40173
|
+
mkdirSync13(dirname18(path), { recursive: true });
|
|
39940
40174
|
writeFileSync11(path, `${JSON.stringify(artifact, null, 2)}
|
|
39941
40175
|
`);
|
|
39942
40176
|
}
|
|
@@ -41021,14 +41255,14 @@ function clone3(value) {
|
|
|
41021
41255
|
}
|
|
41022
41256
|
// src/lib/feedback.ts
|
|
41023
41257
|
import { appendFileSync, existsSync as existsSync18, mkdirSync as mkdirSync14 } from "fs";
|
|
41024
|
-
import { dirname as
|
|
41258
|
+
import { dirname as dirname19, join as join32 } from "path";
|
|
41025
41259
|
import { Database } from "bun:sqlite";
|
|
41026
41260
|
function getFeedbackDbPath() {
|
|
41027
41261
|
return join32(getDataDir(), "skills.db");
|
|
41028
41262
|
}
|
|
41029
41263
|
function getFeedbackDb() {
|
|
41030
41264
|
const dbPath = getFeedbackDbPath();
|
|
41031
|
-
const dir =
|
|
41265
|
+
const dir = dirname19(dbPath);
|
|
41032
41266
|
if (!existsSync18(dir))
|
|
41033
41267
|
mkdirSync14(dir, { recursive: true });
|
|
41034
41268
|
const db = new Database(dbPath);
|
|
@@ -41057,7 +41291,7 @@ function saveFeedback(input2) {
|
|
|
41057
41291
|
const category = input2.category ?? "general";
|
|
41058
41292
|
if (isApiMode()) {
|
|
41059
41293
|
const path = join32(getDataDir(), "feedback.jsonl");
|
|
41060
|
-
const dir =
|
|
41294
|
+
const dir = dirname19(path);
|
|
41061
41295
|
if (!existsSync18(dir))
|
|
41062
41296
|
mkdirSync14(dir, { recursive: true });
|
|
41063
41297
|
appendFileSync(path, JSON.stringify({ message, category, email: input2.email ?? null, agent: input2.agent ?? null, version: input2.version ?? null, createdAt: new Date().toISOString() }) + `
|
|
@@ -41080,7 +41314,7 @@ function isApiMode(env = process.env) {
|
|
|
41080
41314
|
}
|
|
41081
41315
|
}
|
|
41082
41316
|
// src/lib/native-storage.ts
|
|
41083
|
-
import { createHash as
|
|
41317
|
+
import { createHash as createHash19, createHmac as createHmac2 } from "crypto";
|
|
41084
41318
|
import {
|
|
41085
41319
|
existsSync as existsSync19,
|
|
41086
41320
|
mkdirSync as mkdirSync15,
|
|
@@ -41089,7 +41323,7 @@ import {
|
|
|
41089
41323
|
statSync as statSync11,
|
|
41090
41324
|
writeFileSync as writeFileSync12
|
|
41091
41325
|
} from "fs";
|
|
41092
|
-
import { dirname as
|
|
41326
|
+
import { dirname as dirname20, join as join33, normalize as normalize3, relative as relative8, sep as sep7 } from "path";
|
|
41093
41327
|
var SKILLS_STORAGE_TABLES = [
|
|
41094
41328
|
"skills_sync_records",
|
|
41095
41329
|
"skills_sync_cursors"
|
|
@@ -41256,7 +41490,7 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
|
|
|
41256
41490
|
files.push({
|
|
41257
41491
|
path: relativePath,
|
|
41258
41492
|
sizeBytes: bytes.byteLength,
|
|
41259
|
-
sha256:
|
|
41493
|
+
sha256: createHash19("sha256").update(bytes).digest("hex"),
|
|
41260
41494
|
...options.includeFileContents ? { contentBase64: Buffer.from(bytes).toString("base64") } : {}
|
|
41261
41495
|
});
|
|
41262
41496
|
}
|
|
@@ -41275,18 +41509,18 @@ function importSkillsLocalSnapshot(snapshot, targetDir = process.cwd(), options
|
|
|
41275
41509
|
skipped += 1;
|
|
41276
41510
|
continue;
|
|
41277
41511
|
}
|
|
41278
|
-
const
|
|
41279
|
-
if (existsSync19(
|
|
41512
|
+
const absolutePath3 = resolveSnapshotPath(targetDir, file2.path);
|
|
41513
|
+
if (existsSync19(absolutePath3) && !options.overwrite) {
|
|
41280
41514
|
skipped += 1;
|
|
41281
41515
|
continue;
|
|
41282
41516
|
}
|
|
41283
41517
|
const bytes = Buffer.from(file2.contentBase64, "base64");
|
|
41284
|
-
const hash4 =
|
|
41518
|
+
const hash4 = createHash19("sha256").update(bytes).digest("hex");
|
|
41285
41519
|
if (hash4 !== file2.sha256) {
|
|
41286
41520
|
throw new Error(`Snapshot file checksum mismatch: ${file2.path}`);
|
|
41287
41521
|
}
|
|
41288
|
-
mkdirSync15(
|
|
41289
|
-
writeFileSync12(
|
|
41522
|
+
mkdirSync15(dirname20(absolutePath3), { recursive: true });
|
|
41523
|
+
writeFileSync12(absolutePath3, bytes);
|
|
41290
41524
|
written += 1;
|
|
41291
41525
|
}
|
|
41292
41526
|
return { written, skipped };
|
|
@@ -41613,7 +41847,7 @@ function toIsoString(value) {
|
|
|
41613
41847
|
return Number.isNaN(date6.getTime()) ? value : date6.toISOString();
|
|
41614
41848
|
}
|
|
41615
41849
|
function sha256Hex2(value) {
|
|
41616
|
-
return
|
|
41850
|
+
return createHash19("sha256").update(value).digest("hex");
|
|
41617
41851
|
}
|
|
41618
41852
|
function normalizeHeaders(headers) {
|
|
41619
41853
|
const result = {};
|
|
@@ -41665,7 +41899,7 @@ function toArrayBuffer(bytes) {
|
|
|
41665
41899
|
return buffer;
|
|
41666
41900
|
}
|
|
41667
41901
|
// src/lib/station-snapshot.ts
|
|
41668
|
-
import { createHash as
|
|
41902
|
+
import { createHash as createHash20 } from "crypto";
|
|
41669
41903
|
import {
|
|
41670
41904
|
copyFileSync,
|
|
41671
41905
|
mkdirSync as mkdirSync16,
|
|
@@ -41673,7 +41907,7 @@ import {
|
|
|
41673
41907
|
statSync as statSync13,
|
|
41674
41908
|
writeFileSync as writeFileSync13
|
|
41675
41909
|
} from "fs";
|
|
41676
|
-
import { dirname as
|
|
41910
|
+
import { dirname as dirname21, isAbsolute as isAbsolute17, relative as relative9, resolve as resolve16, sep as sep9 } from "path";
|
|
41677
41911
|
|
|
41678
41912
|
// src/lib/portable-snapshot-filter.ts
|
|
41679
41913
|
import { readdirSync as readdirSync14, statSync as statSync12 } from "fs";
|
|
@@ -41840,7 +42074,7 @@ function validateStationId(stationId) {
|
|
|
41840
42074
|
}
|
|
41841
42075
|
}
|
|
41842
42076
|
function sha256File(filePath) {
|
|
41843
|
-
return
|
|
42077
|
+
return createHash20("sha256").update(readFileSync23(filePath)).digest("hex");
|
|
41844
42078
|
}
|
|
41845
42079
|
function scanHome(definition, homesRoot) {
|
|
41846
42080
|
const homePath = homePathFor(definition, homesRoot);
|
|
@@ -41911,7 +42145,7 @@ function humanHomes(scanned) {
|
|
|
41911
42145
|
}));
|
|
41912
42146
|
}
|
|
41913
42147
|
function writeStationSnapshot(options) {
|
|
41914
|
-
const repoRoot =
|
|
42148
|
+
const repoRoot = resolve16(options.repoRoot ?? process.cwd());
|
|
41915
42149
|
const { scanned, plans, totalBytes } = planStationSnapshot(options);
|
|
41916
42150
|
const manifestFiles = plans.map((plan) => ({
|
|
41917
42151
|
relativePath: plan.source.relativePath,
|
|
@@ -41937,9 +42171,9 @@ function writeStationSnapshot(options) {
|
|
|
41937
42171
|
const conflicts = [];
|
|
41938
42172
|
const untouched = [];
|
|
41939
42173
|
for (const plan of plans) {
|
|
41940
|
-
const destination =
|
|
42174
|
+
const destination = resolve16(repoRoot, plan.destination);
|
|
41941
42175
|
const destinationRelative = relative9(repoRoot, destination);
|
|
41942
|
-
if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep9) ||
|
|
42176
|
+
if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep9) || isAbsolute17(destinationRelative)) {
|
|
41943
42177
|
throw new StationSnapshotError("DESTINATION_ESCAPE", `destination escapes repo root: ${plan.destination}`);
|
|
41944
42178
|
}
|
|
41945
42179
|
let existingDigest = null;
|
|
@@ -41960,8 +42194,8 @@ function writeStationSnapshot(options) {
|
|
|
41960
42194
|
}
|
|
41961
42195
|
let written = 0;
|
|
41962
42196
|
for (const plan of untouched) {
|
|
41963
|
-
const destination =
|
|
41964
|
-
mkdirSync16(
|
|
42197
|
+
const destination = resolve16(repoRoot, plan.destination);
|
|
42198
|
+
mkdirSync16(dirname21(destination), { recursive: true });
|
|
41965
42199
|
copyFileSync(plan.source.fullPath, destination);
|
|
41966
42200
|
written += 1;
|
|
41967
42201
|
}
|
|
@@ -41979,8 +42213,8 @@ function writeStationSnapshot(options) {
|
|
|
41979
42213
|
},
|
|
41980
42214
|
files: manifestFiles
|
|
41981
42215
|
};
|
|
41982
|
-
const manifestPath =
|
|
41983
|
-
mkdirSync16(
|
|
42216
|
+
const manifestPath = resolve16(repoRoot, "resources", options.stationId, "skills", "sync-manifest.json");
|
|
42217
|
+
mkdirSync16(dirname21(manifestPath), { recursive: true });
|
|
41984
42218
|
writeFileSync13(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
41985
42219
|
`);
|
|
41986
42220
|
return {
|
|
@@ -41991,7 +42225,7 @@ function writeStationSnapshot(options) {
|
|
|
41991
42225
|
};
|
|
41992
42226
|
}
|
|
41993
42227
|
// src/lib/station-hydrate.ts
|
|
41994
|
-
import { createHash as
|
|
42228
|
+
import { createHash as createHash21 } from "crypto";
|
|
41995
42229
|
import {
|
|
41996
42230
|
copyFileSync as copyFileSync2,
|
|
41997
42231
|
mkdirSync as mkdirSync17,
|
|
@@ -42000,7 +42234,7 @@ import {
|
|
|
42000
42234
|
statSync as statSync14,
|
|
42001
42235
|
writeFileSync as writeFileSync14
|
|
42002
42236
|
} from "fs";
|
|
42003
|
-
import { dirname as
|
|
42237
|
+
import { dirname as dirname22, join as join35, resolve as resolve17, sep as sep10 } from "path";
|
|
42004
42238
|
var STATION_HYDRATION_MANIFEST_SCHEMA = "hasna.fleet-resources.skills-hydration-manifest/v1";
|
|
42005
42239
|
var STATION_HYDRATION_PRODUCER = { name: "@hasna/skills", version: package_default.version };
|
|
42006
42240
|
var MANIFEST_HASH_KEY_SEP = String.fromCharCode(0);
|
|
@@ -42197,12 +42431,12 @@ function skillSha256(skill) {
|
|
|
42197
42431
|
return sha256File(skill.files[0].winner.fullPath);
|
|
42198
42432
|
}
|
|
42199
42433
|
const joined = skill.files.map((file2) => sha256File(file2.winner.fullPath));
|
|
42200
|
-
return
|
|
42434
|
+
return createHash21("sha256").update(joined.sort().join(`
|
|
42201
42435
|
`)).digest("hex");
|
|
42202
42436
|
}
|
|
42203
42437
|
function writeStationHydration(options) {
|
|
42204
|
-
const repoRoot =
|
|
42205
|
-
const cacheRoot =
|
|
42438
|
+
const repoRoot = resolve17(options.repoRoot ?? process.cwd());
|
|
42439
|
+
const cacheRoot = resolve17(options.cacheRoot ?? resolveCorpusRoot());
|
|
42206
42440
|
const plan = planStationHydration(options.stationId, repoRoot);
|
|
42207
42441
|
const resultSkills = plan.winners.map((skill) => ({
|
|
42208
42442
|
ident: skill.ident,
|
|
@@ -42256,7 +42490,7 @@ function writeStationHydration(options) {
|
|
|
42256
42490
|
}
|
|
42257
42491
|
let written = 0;
|
|
42258
42492
|
for (const entry of toWrite) {
|
|
42259
|
-
mkdirSync17(
|
|
42493
|
+
mkdirSync17(dirname22(entry.destination), { recursive: true });
|
|
42260
42494
|
copyFileSync2(entry.fullPath, entry.destination);
|
|
42261
42495
|
written += 1;
|
|
42262
42496
|
}
|
|
@@ -42277,8 +42511,8 @@ function writeStationHydration(options) {
|
|
|
42277
42511
|
},
|
|
42278
42512
|
skills: resultSkills
|
|
42279
42513
|
};
|
|
42280
|
-
const hydrationManifestPath = join35(
|
|
42281
|
-
mkdirSync17(
|
|
42514
|
+
const hydrationManifestPath = join35(dirname22(cacheRoot), `hydration-${options.stationId}.json`);
|
|
42515
|
+
mkdirSync17(dirname22(hydrationManifestPath), { recursive: true });
|
|
42282
42516
|
writeFileSync14(hydrationManifestPath, `${JSON.stringify(hydration, null, 2)}
|
|
42283
42517
|
`);
|
|
42284
42518
|
return {
|
|
@@ -42289,23 +42523,23 @@ function writeStationHydration(options) {
|
|
|
42289
42523
|
};
|
|
42290
42524
|
}
|
|
42291
42525
|
// src/lib/private-publication-recovery.ts
|
|
42292
|
-
import { constants as
|
|
42293
|
-
import { dirname as
|
|
42526
|
+
import { constants as constants11, closeSync as closeSync12, fsyncSync as fsyncSync4, fstatSync as fstatSync12, lstatSync as lstatSync20, mkdirSync as mkdirSync18, openSync as openSync12, readSync as readSync10, realpathSync as realpathSync6, renameSync as renameSync7, unlinkSync as unlinkSync5, writeFileSync as writeFileSync15 } from "fs";
|
|
42527
|
+
import { dirname as dirname23, isAbsolute as isAbsolute18, join as join36, resolve as resolve18 } from "path";
|
|
42294
42528
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
42295
42529
|
var fail2 = () => {
|
|
42296
42530
|
throw new PrivatePublicationError("PUBLICATION_RECOVERY_INVALID", "The recovery directory is invalid or changed. Preserve it and inspect the existing intent; do not start a replacement automatically.");
|
|
42297
42531
|
};
|
|
42298
42532
|
function safeDirectory(directory2) {
|
|
42299
|
-
if (!
|
|
42533
|
+
if (!isAbsolute18(directory2) || directory2 !== resolve18(directory2) || realpathSync6(directory2) !== directory2)
|
|
42300
42534
|
return fail2();
|
|
42301
|
-
for (let path = directory2;; path =
|
|
42302
|
-
const stat2 =
|
|
42535
|
+
for (let path = directory2;; path = dirname23(path)) {
|
|
42536
|
+
const stat2 = lstatSync20(path);
|
|
42303
42537
|
if (!stat2.isDirectory() || stat2.isSymbolicLink())
|
|
42304
42538
|
return fail2();
|
|
42305
|
-
if (path ===
|
|
42539
|
+
if (path === dirname23(path))
|
|
42306
42540
|
break;
|
|
42307
42541
|
}
|
|
42308
|
-
const own2 =
|
|
42542
|
+
const own2 = lstatSync20(directory2);
|
|
42309
42543
|
if ((own2.mode & 63) !== 0 || process.getuid && own2.uid !== process.getuid())
|
|
42310
42544
|
return fail2();
|
|
42311
42545
|
return { dev: own2.dev, ino: own2.ino };
|
|
@@ -42317,35 +42551,35 @@ function unchangedDirectory(directory2, identity3) {
|
|
|
42317
42551
|
}
|
|
42318
42552
|
function readOwned(directory2, name, max) {
|
|
42319
42553
|
const identity3 = safeDirectory(directory2), file2 = join36(directory2, name);
|
|
42320
|
-
const fd =
|
|
42554
|
+
const fd = openSync12(file2, constants11.O_RDONLY | constants11.O_NOFOLLOW);
|
|
42321
42555
|
try {
|
|
42322
|
-
const stat2 =
|
|
42556
|
+
const stat2 = fstatSync12(fd);
|
|
42323
42557
|
if (!stat2.isFile() || stat2.nlink !== 1 || stat2.size > max || stat2.size < 1 || (stat2.mode & 63) !== 0 || process.getuid && stat2.uid !== process.getuid())
|
|
42324
42558
|
return fail2();
|
|
42325
42559
|
const buffer = Buffer.alloc(Math.min(max, stat2.size) + 1);
|
|
42326
42560
|
let length = 0;
|
|
42327
42561
|
while (length < buffer.length) {
|
|
42328
|
-
const count =
|
|
42562
|
+
const count = readSync10(fd, buffer, length, buffer.length - length, length);
|
|
42329
42563
|
if (count === 0)
|
|
42330
42564
|
break;
|
|
42331
42565
|
length += count;
|
|
42332
42566
|
}
|
|
42333
|
-
const bytes = buffer.subarray(0, length), after =
|
|
42567
|
+
const bytes = buffer.subarray(0, length), after = fstatSync12(fd);
|
|
42334
42568
|
unchangedDirectory(directory2, identity3);
|
|
42335
42569
|
if (bytes.length !== stat2.size || stat2.size !== after.size || stat2.mtimeMs !== after.mtimeMs || stat2.ctimeMs !== after.ctimeMs)
|
|
42336
42570
|
return fail2();
|
|
42337
42571
|
return bytes;
|
|
42338
42572
|
} finally {
|
|
42339
|
-
|
|
42573
|
+
closeSync12(fd);
|
|
42340
42574
|
}
|
|
42341
42575
|
}
|
|
42342
42576
|
function writeOwned(directory2, name, bytes) {
|
|
42343
|
-
const fd =
|
|
42577
|
+
const fd = openSync12(join36(directory2, name), constants11.O_WRONLY | constants11.O_CREAT | constants11.O_EXCL | constants11.O_NOFOLLOW, 384);
|
|
42344
42578
|
try {
|
|
42345
42579
|
writeFileSync15(fd, bytes);
|
|
42346
42580
|
fsyncSync4(fd);
|
|
42347
42581
|
} finally {
|
|
42348
|
-
|
|
42582
|
+
closeSync12(fd);
|
|
42349
42583
|
}
|
|
42350
42584
|
}
|
|
42351
42585
|
function save(directory2, value) {
|
|
@@ -42354,11 +42588,11 @@ function save(directory2, value) {
|
|
|
42354
42588
|
`);
|
|
42355
42589
|
unchangedDirectory(directory2, identity3);
|
|
42356
42590
|
renameSync7(join36(directory2, temporary), join36(directory2, "receipt.json"));
|
|
42357
|
-
const fd =
|
|
42591
|
+
const fd = openSync12(directory2, constants11.O_RDONLY | constants11.O_NOFOLLOW);
|
|
42358
42592
|
try {
|
|
42359
42593
|
fsyncSync4(fd);
|
|
42360
42594
|
} finally {
|
|
42361
|
-
|
|
42595
|
+
closeSync12(fd);
|
|
42362
42596
|
}
|
|
42363
42597
|
}
|
|
42364
42598
|
function bind(client2, receipt) {
|
|
@@ -42369,20 +42603,20 @@ async function locked(directory2, action) {
|
|
|
42369
42603
|
const identity3 = safeDirectory(directory2), file2 = join36(directory2, "operation.lock");
|
|
42370
42604
|
let fd;
|
|
42371
42605
|
try {
|
|
42372
|
-
fd =
|
|
42606
|
+
fd = openSync12(file2, constants11.O_WRONLY | constants11.O_CREAT | constants11.O_EXCL | constants11.O_NOFOLLOW, 384);
|
|
42373
42607
|
} catch {
|
|
42374
42608
|
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.");
|
|
42375
42609
|
}
|
|
42376
|
-
const lock =
|
|
42610
|
+
const lock = fstatSync12(fd);
|
|
42377
42611
|
try {
|
|
42378
42612
|
writeFileSync15(fd, JSON.stringify({ pid: process.pid }) + `
|
|
42379
42613
|
`);
|
|
42380
42614
|
fsyncSync4(fd);
|
|
42381
42615
|
return await action();
|
|
42382
42616
|
} finally {
|
|
42383
|
-
|
|
42617
|
+
closeSync12(fd);
|
|
42384
42618
|
unchangedDirectory(directory2, identity3);
|
|
42385
|
-
const now =
|
|
42619
|
+
const now = lstatSync20(file2);
|
|
42386
42620
|
if (now.dev !== lock.dev || now.ino !== lock.ino || !now.isFile() || now.isSymbolicLink())
|
|
42387
42621
|
fail2();
|
|
42388
42622
|
unlinkSync5(file2);
|
|
@@ -42434,15 +42668,15 @@ async function preparePrivatePublication(client2, sourceDirectory, recoveryDirec
|
|
|
42434
42668
|
phase: "prepared",
|
|
42435
42669
|
intent: null
|
|
42436
42670
|
};
|
|
42437
|
-
if (!
|
|
42671
|
+
if (!isAbsolute18(recoveryDirectory) || resolve18(recoveryDirectory) !== recoveryDirectory || realpathSync6(dirname23(recoveryDirectory)) !== dirname23(recoveryDirectory))
|
|
42438
42672
|
return fail2();
|
|
42439
42673
|
mkdirSync18(recoveryDirectory, { mode: 448 });
|
|
42440
42674
|
safeDirectory(recoveryDirectory);
|
|
42441
|
-
const parent =
|
|
42675
|
+
const parent = openSync12(dirname23(recoveryDirectory), constants11.O_RDONLY | constants11.O_NOFOLLOW);
|
|
42442
42676
|
try {
|
|
42443
42677
|
fsyncSync4(parent);
|
|
42444
42678
|
} finally {
|
|
42445
|
-
|
|
42679
|
+
closeSync12(parent);
|
|
42446
42680
|
}
|
|
42447
42681
|
writeOwned(recoveryDirectory, "bundle.tgz", packed.bytes);
|
|
42448
42682
|
save(recoveryDirectory, receipt);
|
|
@@ -42525,8 +42759,8 @@ async function inspectLocked(client2, directory2, cancel) {
|
|
|
42525
42759
|
return privatePublicationResult(directory2, receipt);
|
|
42526
42760
|
}
|
|
42527
42761
|
// src/lib/skill-context.ts
|
|
42528
|
-
import { createHash as
|
|
42529
|
-
import { resolve as
|
|
42762
|
+
import { createHash as createHash22 } from "crypto";
|
|
42763
|
+
import { resolve as resolve19 } from "path";
|
|
42530
42764
|
function words(value) {
|
|
42531
42765
|
return new Set(value.toLowerCase().match(/[a-z0-9]+/g) ?? []);
|
|
42532
42766
|
}
|
|
@@ -42561,7 +42795,7 @@ async function buildSkillContext(input2, options = {}) {
|
|
|
42561
42795
|
const promptWords = words(prompt);
|
|
42562
42796
|
const promptNames = new Set(prompt.toLowerCase().match(/[a-z0-9]+(?:-[a-z0-9]+)*/g) ?? []);
|
|
42563
42797
|
const loaded = new Set(resolved.session?.loaded ?? []);
|
|
42564
|
-
const paths = [...input2.paths ?? [], ...input2.cwd ? [input2.cwd,
|
|
42798
|
+
const paths = [...input2.paths ?? [], ...input2.cwd ? [input2.cwd, resolve19(input2.cwd)] : []];
|
|
42565
42799
|
const candidates = profile.selections.map((selection) => {
|
|
42566
42800
|
const key = selectionKey(selection);
|
|
42567
42801
|
if (input2.restore && loaded.has(key))
|
|
@@ -42614,7 +42848,7 @@ ${content}`;
|
|
|
42614
42848
|
`);
|
|
42615
42849
|
const receipt = {
|
|
42616
42850
|
schemaVersion: 1,
|
|
42617
|
-
id:
|
|
42851
|
+
id: createHash22("sha256").update(JSON.stringify({ profile: profile.profileRevision, sessionId, selections, omitted })).digest("hex"),
|
|
42618
42852
|
profileId: profile.profileId,
|
|
42619
42853
|
profileRevision: profile.profileRevision,
|
|
42620
42854
|
authority: profile.authority,
|
|
@@ -42630,9 +42864,9 @@ ${content}`;
|
|
|
42630
42864
|
return { context: context2, selections, omitted, receipt };
|
|
42631
42865
|
}
|
|
42632
42866
|
// src/lib/session-reconciliation.ts
|
|
42633
|
-
import { createHash as
|
|
42867
|
+
import { createHash as createHash23 } from "crypto";
|
|
42634
42868
|
var SESSION_RECONCILIATION_PLAN_TTL_MS = 5 * 60 * 1000;
|
|
42635
|
-
var digest3 = (value) =>
|
|
42869
|
+
var digest3 = (value) => createHash23("sha256").update(JSON.stringify(value)).digest("hex");
|
|
42636
42870
|
function exactTimestamp(value) {
|
|
42637
42871
|
const parsed = value === undefined ? Number.NaN : Date.parse(value);
|
|
42638
42872
|
if (!Number.isFinite(parsed) || new Date(parsed).toISOString() !== value) {
|
|
@@ -42921,6 +43155,7 @@ export {
|
|
|
42921
43155
|
captureDiscoveryPathSources,
|
|
42922
43156
|
captureDiscoveryDirectories,
|
|
42923
43157
|
captureDiscoveryByteSources,
|
|
43158
|
+
captureClaudeSettings,
|
|
42924
43159
|
captureClaudeMarketplaceRegistry,
|
|
42925
43160
|
canonicalizeManifest,
|
|
42926
43161
|
buildSkillsS3ObjectUrl,
|