@hasna/skills 0.10.46 → 0.10.48
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/bin/index.js +1211 -926
- package/bin/maintenance.js +7 -2
- package/bin/mcp.js +577 -360
- package/bin/migrate.js +7 -5
- package/bin/server.js +29 -10
- package/bin/worker.js +12 -7
- package/dist/index.js +826 -613
- package/dist/lib/agent-discovery.d.ts +1 -1
- package/dist/lib/claude-plugin-manifest-witness.d.ts +9 -0
- package/dist/lib/profile-client.d.ts +6 -2
- package/dist/lib/remote-files.d.ts +1 -1
- package/dist/lib/selection-cache.d.ts +5 -0
- package/dist/lib/selection-resolver.d.ts +1 -0
- package/dist/lib/session-reconciliation.d.ts +6 -3
- package/dist/sdk/index.js +796 -564
- package/dist/server/skills-api.d.ts +1 -0
- package/dist/server/types.d.ts +3 -1
- package/dist/types/skill-selection.d.ts +2 -0
- package/migrations/postgres/0011_skill_authorization_epoch.sql +22 -0
- package/migrations/sqlite/0011_skill_authorization_epoch.sql +17 -0
- package/package.json +1 -1
package/dist/sdk/index.js
CHANGED
|
@@ -3724,10 +3724,10 @@ var require_resolve_block_map = __commonJS((exports) => {
|
|
|
3724
3724
|
let offset = bm.offset;
|
|
3725
3725
|
let commentEnd = null;
|
|
3726
3726
|
for (const collItem of bm.items) {
|
|
3727
|
-
const { start, key, sep:
|
|
3727
|
+
const { start, key, sep: sep5, value } = collItem;
|
|
3728
3728
|
const keyProps = resolveProps.resolveProps(start, {
|
|
3729
3729
|
indicator: "explicit-key-ind",
|
|
3730
|
-
next: key ??
|
|
3730
|
+
next: key ?? sep5?.[0],
|
|
3731
3731
|
offset,
|
|
3732
3732
|
onError,
|
|
3733
3733
|
parentIndent: bm.indent,
|
|
@@ -3741,7 +3741,7 @@ var require_resolve_block_map = __commonJS((exports) => {
|
|
|
3741
3741
|
else if ("indent" in key && key.indent !== bm.indent)
|
|
3742
3742
|
onError(offset, "BAD_INDENT", startColMsg);
|
|
3743
3743
|
}
|
|
3744
|
-
if (!keyProps.anchor && !keyProps.tag && !
|
|
3744
|
+
if (!keyProps.anchor && !keyProps.tag && !sep5) {
|
|
3745
3745
|
commentEnd = keyProps.end;
|
|
3746
3746
|
if (keyProps.comment) {
|
|
3747
3747
|
if (map.comment)
|
|
@@ -3766,7 +3766,7 @@ var require_resolve_block_map = __commonJS((exports) => {
|
|
|
3766
3766
|
ctx.atKey = false;
|
|
3767
3767
|
if (utilMapIncludes.mapIncludes(ctx, map.items, keyNode))
|
|
3768
3768
|
onError(keyStart, "DUPLICATE_KEY", "Map keys must be unique");
|
|
3769
|
-
const valueProps = resolveProps.resolveProps(
|
|
3769
|
+
const valueProps = resolveProps.resolveProps(sep5 ?? [], {
|
|
3770
3770
|
indicator: "map-value-ind",
|
|
3771
3771
|
next: value,
|
|
3772
3772
|
offset: keyNode.range[2],
|
|
@@ -3782,7 +3782,7 @@ var require_resolve_block_map = __commonJS((exports) => {
|
|
|
3782
3782
|
if (ctx.options.strict && keyProps.start < valueProps.found.offset - 1024)
|
|
3783
3783
|
onError(keyNode.range, "KEY_OVER_1024_CHARS", "The : indicator must be at most 1024 chars after the start of an implicit block mapping key");
|
|
3784
3784
|
}
|
|
3785
|
-
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset,
|
|
3785
|
+
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset, sep5, null, valueProps, onError);
|
|
3786
3786
|
if (ctx.schema.compat)
|
|
3787
3787
|
utilFlowIndentCheck.flowIndentCheck(bm.indent, value, onError);
|
|
3788
3788
|
offset = valueNode.range[2];
|
|
@@ -3868,7 +3868,7 @@ var require_resolve_end = __commonJS((exports) => {
|
|
|
3868
3868
|
let comment = "";
|
|
3869
3869
|
if (end) {
|
|
3870
3870
|
let hasSpace = false;
|
|
3871
|
-
let
|
|
3871
|
+
let sep5 = "";
|
|
3872
3872
|
for (const token of end) {
|
|
3873
3873
|
const { source, type } = token;
|
|
3874
3874
|
switch (type) {
|
|
@@ -3882,13 +3882,13 @@ var require_resolve_end = __commonJS((exports) => {
|
|
|
3882
3882
|
if (!comment)
|
|
3883
3883
|
comment = cb;
|
|
3884
3884
|
else
|
|
3885
|
-
comment +=
|
|
3886
|
-
|
|
3885
|
+
comment += sep5 + cb;
|
|
3886
|
+
sep5 = "";
|
|
3887
3887
|
break;
|
|
3888
3888
|
}
|
|
3889
3889
|
case "newline":
|
|
3890
3890
|
if (comment)
|
|
3891
|
-
|
|
3891
|
+
sep5 += source;
|
|
3892
3892
|
hasSpace = true;
|
|
3893
3893
|
break;
|
|
3894
3894
|
default:
|
|
@@ -3928,18 +3928,18 @@ var require_resolve_flow_collection = __commonJS((exports) => {
|
|
|
3928
3928
|
let offset = fc.offset + fc.start.source.length;
|
|
3929
3929
|
for (let i = 0;i < fc.items.length; ++i) {
|
|
3930
3930
|
const collItem = fc.items[i];
|
|
3931
|
-
const { start, key, sep:
|
|
3931
|
+
const { start, key, sep: sep5, value } = collItem;
|
|
3932
3932
|
const props = resolveProps.resolveProps(start, {
|
|
3933
3933
|
flow: fcName,
|
|
3934
3934
|
indicator: "explicit-key-ind",
|
|
3935
|
-
next: key ??
|
|
3935
|
+
next: key ?? sep5?.[0],
|
|
3936
3936
|
offset,
|
|
3937
3937
|
onError,
|
|
3938
3938
|
parentIndent: fc.indent,
|
|
3939
3939
|
startOnNewline: false
|
|
3940
3940
|
});
|
|
3941
3941
|
if (!props.found) {
|
|
3942
|
-
if (!props.anchor && !props.tag && !
|
|
3942
|
+
if (!props.anchor && !props.tag && !sep5 && !value) {
|
|
3943
3943
|
if (i === 0 && props.comma)
|
|
3944
3944
|
onError(props.comma, "UNEXPECTED_TOKEN", `Unexpected , in ${fcName}`);
|
|
3945
3945
|
else if (i < fc.items.length - 1)
|
|
@@ -3991,8 +3991,8 @@ var require_resolve_flow_collection = __commonJS((exports) => {
|
|
|
3991
3991
|
}
|
|
3992
3992
|
}
|
|
3993
3993
|
}
|
|
3994
|
-
if (!isMap && !
|
|
3995
|
-
const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end,
|
|
3994
|
+
if (!isMap && !sep5 && !props.found) {
|
|
3995
|
+
const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end, sep5, null, props, onError);
|
|
3996
3996
|
coll.items.push(valueNode);
|
|
3997
3997
|
offset = valueNode.range[2];
|
|
3998
3998
|
if (isBlock(value))
|
|
@@ -4004,7 +4004,7 @@ var require_resolve_flow_collection = __commonJS((exports) => {
|
|
|
4004
4004
|
if (isBlock(key))
|
|
4005
4005
|
onError(keyNode.range, "BLOCK_IN_FLOW", blockMsg);
|
|
4006
4006
|
ctx.atKey = false;
|
|
4007
|
-
const valueProps = resolveProps.resolveProps(
|
|
4007
|
+
const valueProps = resolveProps.resolveProps(sep5 ?? [], {
|
|
4008
4008
|
flow: fcName,
|
|
4009
4009
|
indicator: "map-value-ind",
|
|
4010
4010
|
next: value,
|
|
@@ -4015,8 +4015,8 @@ var require_resolve_flow_collection = __commonJS((exports) => {
|
|
|
4015
4015
|
});
|
|
4016
4016
|
if (valueProps.found) {
|
|
4017
4017
|
if (!isMap && !props.found && ctx.options.strict) {
|
|
4018
|
-
if (
|
|
4019
|
-
for (const st of
|
|
4018
|
+
if (sep5)
|
|
4019
|
+
for (const st of sep5) {
|
|
4020
4020
|
if (st === valueProps.found)
|
|
4021
4021
|
break;
|
|
4022
4022
|
if (st.type === "newline") {
|
|
@@ -4033,7 +4033,7 @@ var require_resolve_flow_collection = __commonJS((exports) => {
|
|
|
4033
4033
|
else
|
|
4034
4034
|
onError(valueProps.start, "MISSING_CHAR", `Missing , or : between ${fcName} items`);
|
|
4035
4035
|
}
|
|
4036
|
-
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end,
|
|
4036
|
+
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end, sep5, null, valueProps, onError) : null;
|
|
4037
4037
|
if (valueNode) {
|
|
4038
4038
|
if (isBlock(value))
|
|
4039
4039
|
onError(valueNode.range, "BLOCK_IN_FLOW", blockMsg);
|
|
@@ -4210,7 +4210,7 @@ var require_resolve_block_scalar = __commonJS((exports) => {
|
|
|
4210
4210
|
chompStart = i + 1;
|
|
4211
4211
|
}
|
|
4212
4212
|
let value = "";
|
|
4213
|
-
let
|
|
4213
|
+
let sep5 = "";
|
|
4214
4214
|
let prevMoreIndented = false;
|
|
4215
4215
|
for (let i = 0;i < contentStart; ++i)
|
|
4216
4216
|
value += lines[i][0].slice(trimIndent) + `
|
|
@@ -4228,33 +4228,33 @@ var require_resolve_block_scalar = __commonJS((exports) => {
|
|
|
4228
4228
|
indent = "";
|
|
4229
4229
|
}
|
|
4230
4230
|
if (type === Scalar.Scalar.BLOCK_LITERAL) {
|
|
4231
|
-
value +=
|
|
4232
|
-
|
|
4231
|
+
value += sep5 + indent.slice(trimIndent) + content;
|
|
4232
|
+
sep5 = `
|
|
4233
4233
|
`;
|
|
4234
4234
|
} else if (indent.length > trimIndent || content[0] === "\t") {
|
|
4235
|
-
if (
|
|
4236
|
-
|
|
4235
|
+
if (sep5 === " ")
|
|
4236
|
+
sep5 = `
|
|
4237
4237
|
`;
|
|
4238
|
-
else if (!prevMoreIndented &&
|
|
4238
|
+
else if (!prevMoreIndented && sep5 === `
|
|
4239
4239
|
`)
|
|
4240
|
-
|
|
4240
|
+
sep5 = `
|
|
4241
4241
|
|
|
4242
4242
|
`;
|
|
4243
|
-
value +=
|
|
4244
|
-
|
|
4243
|
+
value += sep5 + indent.slice(trimIndent) + content;
|
|
4244
|
+
sep5 = `
|
|
4245
4245
|
`;
|
|
4246
4246
|
prevMoreIndented = true;
|
|
4247
4247
|
} else if (content === "") {
|
|
4248
|
-
if (
|
|
4248
|
+
if (sep5 === `
|
|
4249
4249
|
`)
|
|
4250
4250
|
value += `
|
|
4251
4251
|
`;
|
|
4252
4252
|
else
|
|
4253
|
-
|
|
4253
|
+
sep5 = `
|
|
4254
4254
|
`;
|
|
4255
4255
|
} else {
|
|
4256
|
-
value +=
|
|
4257
|
-
|
|
4256
|
+
value += sep5 + content;
|
|
4257
|
+
sep5 = " ";
|
|
4258
4258
|
prevMoreIndented = false;
|
|
4259
4259
|
}
|
|
4260
4260
|
}
|
|
@@ -4435,27 +4435,27 @@ var require_resolve_flow_scalar = __commonJS((exports) => {
|
|
|
4435
4435
|
if (!match)
|
|
4436
4436
|
return source;
|
|
4437
4437
|
let res = match[1];
|
|
4438
|
-
let
|
|
4438
|
+
let sep5 = " ";
|
|
4439
4439
|
let pos = first.lastIndex;
|
|
4440
4440
|
line.lastIndex = pos;
|
|
4441
4441
|
while (match = line.exec(source)) {
|
|
4442
4442
|
if (match[1] === "") {
|
|
4443
|
-
if (
|
|
4443
|
+
if (sep5 === `
|
|
4444
4444
|
`)
|
|
4445
|
-
res +=
|
|
4445
|
+
res += sep5;
|
|
4446
4446
|
else
|
|
4447
|
-
|
|
4447
|
+
sep5 = `
|
|
4448
4448
|
`;
|
|
4449
4449
|
} else {
|
|
4450
|
-
res +=
|
|
4451
|
-
|
|
4450
|
+
res += sep5 + match[1];
|
|
4451
|
+
sep5 = " ";
|
|
4452
4452
|
}
|
|
4453
4453
|
pos = line.lastIndex;
|
|
4454
4454
|
}
|
|
4455
4455
|
const last = /[ \t]*(.*)/sy;
|
|
4456
4456
|
last.lastIndex = pos;
|
|
4457
4457
|
match = last.exec(source);
|
|
4458
|
-
return res +
|
|
4458
|
+
return res + sep5 + (match?.[1] ?? "");
|
|
4459
4459
|
}
|
|
4460
4460
|
function doubleQuotedValue(source, onError) {
|
|
4461
4461
|
let res = "";
|
|
@@ -5236,14 +5236,14 @@ var require_cst_stringify = __commonJS((exports) => {
|
|
|
5236
5236
|
}
|
|
5237
5237
|
}
|
|
5238
5238
|
}
|
|
5239
|
-
function stringifyItem({ start, key, sep:
|
|
5239
|
+
function stringifyItem({ start, key, sep: sep5, value }) {
|
|
5240
5240
|
let res = "";
|
|
5241
5241
|
for (const st of start)
|
|
5242
5242
|
res += st.source;
|
|
5243
5243
|
if (key)
|
|
5244
5244
|
res += stringifyToken(key);
|
|
5245
|
-
if (
|
|
5246
|
-
for (const st of
|
|
5245
|
+
if (sep5)
|
|
5246
|
+
for (const st of sep5)
|
|
5247
5247
|
res += st.source;
|
|
5248
5248
|
if (value)
|
|
5249
5249
|
res += stringifyToken(value);
|
|
@@ -6391,18 +6391,18 @@ var require_parser = __commonJS((exports) => {
|
|
|
6391
6391
|
if (this.type === "map-value-ind") {
|
|
6392
6392
|
const prev = getPrevProps(this.peek(2));
|
|
6393
6393
|
const start = getFirstKeyStartProps(prev);
|
|
6394
|
-
let
|
|
6394
|
+
let sep5;
|
|
6395
6395
|
if (scalar2.end) {
|
|
6396
|
-
|
|
6397
|
-
|
|
6396
|
+
sep5 = scalar2.end;
|
|
6397
|
+
sep5.push(this.sourceToken);
|
|
6398
6398
|
delete scalar2.end;
|
|
6399
6399
|
} else
|
|
6400
|
-
|
|
6400
|
+
sep5 = [this.sourceToken];
|
|
6401
6401
|
const map = {
|
|
6402
6402
|
type: "block-map",
|
|
6403
6403
|
offset: scalar2.offset,
|
|
6404
6404
|
indent: scalar2.indent,
|
|
6405
|
-
items: [{ start, key: scalar2, sep:
|
|
6405
|
+
items: [{ start, key: scalar2, sep: sep5 }]
|
|
6406
6406
|
};
|
|
6407
6407
|
this.onKeyLine = true;
|
|
6408
6408
|
this.stack[this.stack.length - 1] = map;
|
|
@@ -6556,15 +6556,15 @@ var require_parser = __commonJS((exports) => {
|
|
|
6556
6556
|
} else if (isFlowToken(it.key) && !includesToken(it.sep, "newline")) {
|
|
6557
6557
|
const start2 = getFirstKeyStartProps(it.start);
|
|
6558
6558
|
const key = it.key;
|
|
6559
|
-
const
|
|
6560
|
-
|
|
6559
|
+
const sep5 = it.sep;
|
|
6560
|
+
sep5.push(this.sourceToken);
|
|
6561
6561
|
delete it.key;
|
|
6562
6562
|
delete it.sep;
|
|
6563
6563
|
this.stack.push({
|
|
6564
6564
|
type: "block-map",
|
|
6565
6565
|
offset: this.offset,
|
|
6566
6566
|
indent: this.indent,
|
|
6567
|
-
items: [{ start: start2, key, sep:
|
|
6567
|
+
items: [{ start: start2, key, sep: sep5 }]
|
|
6568
6568
|
});
|
|
6569
6569
|
} else if (start.length > 0) {
|
|
6570
6570
|
it.sep = it.sep.concat(start, this.sourceToken);
|
|
@@ -6758,13 +6758,13 @@ var require_parser = __commonJS((exports) => {
|
|
|
6758
6758
|
const prev = getPrevProps(parent);
|
|
6759
6759
|
const start = getFirstKeyStartProps(prev);
|
|
6760
6760
|
fixFlowSeqItems(fc);
|
|
6761
|
-
const
|
|
6762
|
-
|
|
6761
|
+
const sep5 = fc.end.splice(1, fc.end.length);
|
|
6762
|
+
sep5.push(this.sourceToken);
|
|
6763
6763
|
const map = {
|
|
6764
6764
|
type: "block-map",
|
|
6765
6765
|
offset: fc.offset,
|
|
6766
6766
|
indent: fc.indent,
|
|
6767
|
-
items: [{ start, key: fc, sep:
|
|
6767
|
+
items: [{ start, key: fc, sep: sep5 }]
|
|
6768
6768
|
};
|
|
6769
6769
|
this.onKeyLine = true;
|
|
6770
6770
|
this.stack[this.stack.length - 1] = map;
|
|
@@ -9003,8 +9003,8 @@ var require_client = __commonJS((exports) => {
|
|
|
9003
9003
|
// node_modules/@smithy/core/dist-cjs/submodules/config/index.js
|
|
9004
9004
|
var require_config = __commonJS((exports) => {
|
|
9005
9005
|
var { homedir: homedir7 } = __require("os");
|
|
9006
|
-
var { sep:
|
|
9007
|
-
var { createHash:
|
|
9006
|
+
var { sep: sep11, join: join4 } = __require("path");
|
|
9007
|
+
var { createHash: createHash26 } = __require("crypto");
|
|
9008
9008
|
var { readFile: readFile$1 } = __require("fs/promises");
|
|
9009
9009
|
var { IniSectionType } = require_dist_cjs();
|
|
9010
9010
|
var { normalizeProvider } = require_client();
|
|
@@ -9143,7 +9143,7 @@ var require_config = __commonJS((exports) => {
|
|
|
9143
9143
|
return "DEFAULT";
|
|
9144
9144
|
};
|
|
9145
9145
|
var getHomeDir = () => {
|
|
9146
|
-
const { HOME, USERPROFILE, HOMEPATH, HOMEDRIVE = `C:${
|
|
9146
|
+
const { HOME, USERPROFILE, HOMEPATH, HOMEDRIVE = `C:${sep11}` } = process.env;
|
|
9147
9147
|
if (HOME)
|
|
9148
9148
|
return HOME;
|
|
9149
9149
|
if (USERPROFILE)
|
|
@@ -9159,7 +9159,7 @@ var require_config = __commonJS((exports) => {
|
|
|
9159
9159
|
var DEFAULT_PROFILE = "default";
|
|
9160
9160
|
var getProfileName = (init) => init.profile || process.env[ENV_PROFILE] || DEFAULT_PROFILE;
|
|
9161
9161
|
var getSSOTokenFilepath = (id2) => {
|
|
9162
|
-
const hasher =
|
|
9162
|
+
const hasher = createHash26("sha1");
|
|
9163
9163
|
const cacheName = hasher.update(id2).digest("hex");
|
|
9164
9164
|
return join4(getHomeDir(), ".aws", "sso", "cache", `${cacheName}.json`);
|
|
9165
9165
|
};
|
|
@@ -10511,7 +10511,7 @@ var require_endpoints = __commonJS((exports) => {
|
|
|
10511
10511
|
|
|
10512
10512
|
// node_modules/@smithy/core/dist-cjs/submodules/serde/index.js
|
|
10513
10513
|
var require_serde = __commonJS((exports) => {
|
|
10514
|
-
var { createHmac: createHmac2, createHash:
|
|
10514
|
+
var { createHmac: createHmac2, createHash: createHash26, getRandomValues } = __require("crypto");
|
|
10515
10515
|
var { hasOwn: hasOwn2, HttpResponse } = require_transport();
|
|
10516
10516
|
exports.hasOwn = hasOwn2;
|
|
10517
10517
|
var { ReadStream, lstatSync: lstatSync26, fstatSync: fstatSync4 } = __require("fs");
|
|
@@ -11416,7 +11416,7 @@ var require_serde = __commonJS((exports) => {
|
|
|
11416
11416
|
return Promise.resolve(this.hash.digest());
|
|
11417
11417
|
}
|
|
11418
11418
|
reset() {
|
|
11419
|
-
this.hash = this.secret ? createHmac2(this.algorithmIdentifier, castSourceData(this.secret)) :
|
|
11419
|
+
this.hash = this.secret ? createHmac2(this.algorithmIdentifier, castSourceData(this.secret)) : createHash26(this.algorithmIdentifier);
|
|
11420
11420
|
}
|
|
11421
11421
|
}
|
|
11422
11422
|
function castSourceData(toCast, encoding) {
|
|
@@ -12155,7 +12155,7 @@ var require_checksum = __commonJS((exports) => {
|
|
|
12155
12155
|
var { createReadStream } = __require("fs");
|
|
12156
12156
|
var { Writable } = __require("stream");
|
|
12157
12157
|
var { toUint8Array, concatBytes } = require_serde();
|
|
12158
|
-
var { createHash:
|
|
12158
|
+
var { createHash: createHash26, createHmac: createHmac2 } = __require("crypto");
|
|
12159
12159
|
var zlib = __require("zlib");
|
|
12160
12160
|
async function blobReader(blob, onChunk, chunkSize = 1024 * 1024) {
|
|
12161
12161
|
const size = blob.size;
|
|
@@ -12320,7 +12320,7 @@ var require_checksum = __commonJS((exports) => {
|
|
|
12320
12320
|
}
|
|
12321
12321
|
var hasNativeCrypto$1 = (() => {
|
|
12322
12322
|
try {
|
|
12323
|
-
|
|
12323
|
+
createHash26("md5");
|
|
12324
12324
|
return true;
|
|
12325
12325
|
} catch {
|
|
12326
12326
|
return false;
|
|
@@ -12330,7 +12330,7 @@ var require_checksum = __commonJS((exports) => {
|
|
|
12330
12330
|
function buildNativeClass$2() {
|
|
12331
12331
|
return class Md5Node2 {
|
|
12332
12332
|
digestLength = 16;
|
|
12333
|
-
hash =
|
|
12333
|
+
hash = createHash26("md5");
|
|
12334
12334
|
update(data) {
|
|
12335
12335
|
this.hash.update(toUint8Array(data));
|
|
12336
12336
|
}
|
|
@@ -12339,7 +12339,7 @@ var require_checksum = __commonJS((exports) => {
|
|
|
12339
12339
|
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
12340
12340
|
}
|
|
12341
12341
|
reset() {
|
|
12342
|
-
this.hash =
|
|
12342
|
+
this.hash = createHash26("md5");
|
|
12343
12343
|
}
|
|
12344
12344
|
};
|
|
12345
12345
|
}
|
|
@@ -12629,7 +12629,7 @@ var require_checksum = __commonJS((exports) => {
|
|
|
12629
12629
|
]);
|
|
12630
12630
|
var hasNativeCrypto = (() => {
|
|
12631
12631
|
try {
|
|
12632
|
-
|
|
12632
|
+
createHash26("sha256");
|
|
12633
12633
|
return true;
|
|
12634
12634
|
} catch {
|
|
12635
12635
|
return false;
|
|
@@ -12669,7 +12669,7 @@ var require_checksum = __commonJS((exports) => {
|
|
|
12669
12669
|
this.finished = false;
|
|
12670
12670
|
}
|
|
12671
12671
|
createHash() {
|
|
12672
|
-
return this.secret ? createHmac2("sha256", toBuffer(this.secret)) :
|
|
12672
|
+
return this.secret ? createHmac2("sha256", toBuffer(this.secret)) : createHash26("sha256");
|
|
12673
12673
|
}
|
|
12674
12674
|
};
|
|
12675
12675
|
}
|
|
@@ -17515,8 +17515,8 @@ More information can be found at: https://a.co/c895JFp`);
|
|
|
17515
17515
|
};
|
|
17516
17516
|
var createUserAgentStringParsingProvider = ({ serviceId, clientVersion }) => async (config) => {
|
|
17517
17517
|
const module2 = require_es5();
|
|
17518
|
-
const
|
|
17519
|
-
const parsedUA = typeof window !== "undefined" && window?.navigator?.userAgent ?
|
|
17518
|
+
const parse8 = module2.parse ?? module2.default.parse ?? (() => "");
|
|
17519
|
+
const parsedUA = typeof window !== "undefined" && window?.navigator?.userAgent ? parse8(window.navigator.userAgent) : undefined;
|
|
17520
17520
|
const sections = [
|
|
17521
17521
|
["aws-sdk-js", clientVersion],
|
|
17522
17522
|
["ua", "2.1"],
|
|
@@ -18166,7 +18166,7 @@ ${toHex(hashedRequest)}`;
|
|
|
18166
18166
|
return hash2.digest();
|
|
18167
18167
|
};
|
|
18168
18168
|
var getCanonicalHeaders = ({ headers }, unsignableHeaders, signableHeaders) => {
|
|
18169
|
-
const
|
|
18169
|
+
const canonical7 = {};
|
|
18170
18170
|
for (const headerName of Object.keys(headers).sort()) {
|
|
18171
18171
|
if (headers[headerName] == undefined) {
|
|
18172
18172
|
continue;
|
|
@@ -18177,9 +18177,9 @@ ${toHex(hashedRequest)}`;
|
|
|
18177
18177
|
continue;
|
|
18178
18178
|
}
|
|
18179
18179
|
}
|
|
18180
|
-
|
|
18180
|
+
canonical7[canonicalHeaderName] = headers[headerName].trim().replace(/\s+/g, " ");
|
|
18181
18181
|
}
|
|
18182
|
-
return
|
|
18182
|
+
return canonical7;
|
|
18183
18183
|
};
|
|
18184
18184
|
var getPayloadHash = async ({ headers, body }, hashConstructor) => {
|
|
18185
18185
|
for (const headerName in headers) {
|
|
@@ -18542,7 +18542,7 @@ var require_dist_cjs4 = __commonJS((exports) => {
|
|
|
18542
18542
|
var require_util = __commonJS((exports) => {
|
|
18543
18543
|
var { buildQueryString } = require_protocols();
|
|
18544
18544
|
var validate = (str) => typeof str === "string" && str.indexOf("arn:") === 0 && str.split(":").length >= 6;
|
|
18545
|
-
var
|
|
18545
|
+
var parse8 = (arn) => {
|
|
18546
18546
|
const segments = arn.split(":");
|
|
18547
18547
|
if (segments.length < 6 || segments[0] !== "arn")
|
|
18548
18548
|
throw new Error("Malformed ARN");
|
|
@@ -18592,7 +18592,7 @@ var require_util = __commonJS((exports) => {
|
|
|
18592
18592
|
}
|
|
18593
18593
|
exports.build = build;
|
|
18594
18594
|
exports.formatUrl = formatUrl;
|
|
18595
|
-
exports.parse =
|
|
18595
|
+
exports.parse = parse8;
|
|
18596
18596
|
exports.validate = validate;
|
|
18597
18597
|
});
|
|
18598
18598
|
|
|
@@ -21700,12 +21700,12 @@ var require_protocols2 = __commonJS((exports) => {
|
|
|
21700
21700
|
return expandToDecimal(numericString) === expandToDecimal(String(value));
|
|
21701
21701
|
}
|
|
21702
21702
|
const normalized = numericString.replace(/(\.\d*?)0+$/, "$1").replace(/\.$/, "");
|
|
21703
|
-
const
|
|
21704
|
-
if (normalized ===
|
|
21703
|
+
const canonical7 = String(value);
|
|
21704
|
+
if (normalized === canonical7) {
|
|
21705
21705
|
return true;
|
|
21706
21706
|
}
|
|
21707
|
-
if (/[eE]/.test(
|
|
21708
|
-
return normalized === expandToDecimal(
|
|
21707
|
+
if (/[eE]/.test(canonical7)) {
|
|
21708
|
+
return normalized === expandToDecimal(canonical7);
|
|
21709
21709
|
}
|
|
21710
21710
|
return false;
|
|
21711
21711
|
}
|
|
@@ -29443,10 +29443,10 @@ var require_signin = __commonJS((exports) => {
|
|
|
29443
29443
|
});
|
|
29444
29444
|
|
|
29445
29445
|
// node_modules/@aws-sdk/credential-provider-ini/node_modules/@aws-sdk/credential-provider-login/dist-es/LoginCredentialsFetcher.js
|
|
29446
|
-
import { createHash as
|
|
29446
|
+
import { createHash as createHash26, createPrivateKey, createPublicKey, sign } from "crypto";
|
|
29447
29447
|
import { promises as fs2 } from "fs";
|
|
29448
29448
|
import { homedir as homedir7 } from "os";
|
|
29449
|
-
import { dirname as dirname23, join as
|
|
29449
|
+
import { dirname as dirname23, join as join38 } from "path";
|
|
29450
29450
|
var import_config28, import_protocols3, LoginCredentialsFetcher;
|
|
29451
29451
|
var init_LoginCredentialsFetcher = __esm(() => {
|
|
29452
29452
|
import_config28 = __toESM(require_config(), 1);
|
|
@@ -29613,10 +29613,10 @@ var init_LoginCredentialsFetcher = __esm(() => {
|
|
|
29613
29613
|
await fs2.writeFile(tokenFilePath, JSON.stringify(token, null, 2), "utf8");
|
|
29614
29614
|
}
|
|
29615
29615
|
getTokenFilePath() {
|
|
29616
|
-
const directory = process.env.AWS_LOGIN_CACHE_DIRECTORY ??
|
|
29616
|
+
const directory = process.env.AWS_LOGIN_CACHE_DIRECTORY ?? join38(homedir7(), ".aws", "login", "cache");
|
|
29617
29617
|
const loginSessionBytes = Buffer.from(this.loginSession, "utf8");
|
|
29618
|
-
const loginSessionSha256 =
|
|
29619
|
-
return
|
|
29618
|
+
const loginSessionSha256 = createHash26("sha256").update(loginSessionBytes).digest("hex");
|
|
29619
|
+
return join38(directory, `${loginSessionSha256}.json`);
|
|
29620
29620
|
}
|
|
29621
29621
|
derToRawSignature(derSignature) {
|
|
29622
29622
|
let offset = 2;
|
|
@@ -31067,7 +31067,7 @@ import { existsSync as existsSync22 } from "fs";
|
|
|
31067
31067
|
import { join as join210 } from "path";
|
|
31068
31068
|
import { existsSync as existsSync17 } from "fs";
|
|
31069
31069
|
import { homedir as homedir8 } from "os";
|
|
31070
|
-
import { join as
|
|
31070
|
+
import { join as join42, resolve as resolve22 } from "path";
|
|
31071
31071
|
import { homedir as pathsResolverHomedir2 } from "os";
|
|
31072
31072
|
import { join as pathsResolverJoin2 } from "path";
|
|
31073
31073
|
import { createHmac as createHmac4, timingSafeEqual as timingSafeEqual3 } from "crypto";
|
|
@@ -31228,7 +31228,7 @@ function effectiveHome2() {
|
|
|
31228
31228
|
return process.env["HOME"] || process.env["USERPROFILE"] || homedir8();
|
|
31229
31229
|
}
|
|
31230
31230
|
function legacyHomeDir() {
|
|
31231
|
-
return
|
|
31231
|
+
return join42(effectiveHome2(), ".hasna", "events");
|
|
31232
31232
|
}
|
|
31233
31233
|
function resolverHome() {
|
|
31234
31234
|
return dataDir2({ app: "events", home: effectiveHome2() || undefined });
|
|
@@ -31237,7 +31237,7 @@ function adoptResolverHome(resolved, env = process.env) {
|
|
|
31237
31237
|
const dataOverride = env.HASNA_DATA_HOME;
|
|
31238
31238
|
if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
|
|
31239
31239
|
return true;
|
|
31240
|
-
return existsSync17(
|
|
31240
|
+
return existsSync17(join42(resolved, EVENTS_STORE_SENTINEL_FILE));
|
|
31241
31241
|
}
|
|
31242
31242
|
function exactEventsHome() {
|
|
31243
31243
|
const dir = process.env[HASNA_EVENTS_DIR_ENV];
|
|
@@ -32373,7 +32373,7 @@ var init_event_sink = __esm(() => {
|
|
|
32373
32373
|
// package.json
|
|
32374
32374
|
var package_default = {
|
|
32375
32375
|
name: "@hasna/skills",
|
|
32376
|
-
version: "0.10.
|
|
32376
|
+
version: "0.10.48",
|
|
32377
32377
|
description: "Skills library for AI coding agents",
|
|
32378
32378
|
type: "module",
|
|
32379
32379
|
bin: {
|
|
@@ -32525,7 +32525,7 @@ function describeRemoteFiles(files) {
|
|
|
32525
32525
|
function sha256(bytes) {
|
|
32526
32526
|
return createHash("sha256").update(bytes).digest("hex");
|
|
32527
32527
|
}
|
|
32528
|
-
async function readBoundedResponse(response, maximum) {
|
|
32528
|
+
async function readBoundedResponse(response, maximum, signal) {
|
|
32529
32529
|
if (!Number.isSafeInteger(maximum) || maximum < 0 || maximum > MAX_REMOTE_FILE_BYTES)
|
|
32530
32530
|
throw new Error("Invalid artifact size limit");
|
|
32531
32531
|
const length = response.headers.get("content-length");
|
|
@@ -32536,11 +32536,18 @@ async function readBoundedResponse(response, maximum) {
|
|
|
32536
32536
|
const reader = response.body?.getReader();
|
|
32537
32537
|
if (!reader)
|
|
32538
32538
|
return new Uint8Array;
|
|
32539
|
+
signal?.throwIfAborted();
|
|
32540
|
+
const abort = () => {
|
|
32541
|
+
reader.cancel().catch(() => {});
|
|
32542
|
+
};
|
|
32543
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
32539
32544
|
const chunks = [];
|
|
32540
32545
|
let size = 0;
|
|
32541
32546
|
try {
|
|
32542
32547
|
while (true) {
|
|
32548
|
+
signal?.throwIfAborted();
|
|
32543
32549
|
const next = await reader.read();
|
|
32550
|
+
signal?.throwIfAborted();
|
|
32544
32551
|
if (next.done)
|
|
32545
32552
|
break;
|
|
32546
32553
|
size += next.value.byteLength;
|
|
@@ -32552,6 +32559,7 @@ async function readBoundedResponse(response, maximum) {
|
|
|
32552
32559
|
await reader.cancel().catch(() => {});
|
|
32553
32560
|
throw error;
|
|
32554
32561
|
} finally {
|
|
32562
|
+
signal?.removeEventListener("abort", abort);
|
|
32555
32563
|
reader.releaseLock();
|
|
32556
32564
|
}
|
|
32557
32565
|
const bytes = new Uint8Array(size);
|
|
@@ -34927,7 +34935,7 @@ function hash(value) {
|
|
|
34927
34935
|
return createHash3("sha256").update(JSON.stringify(value)).digest("hex");
|
|
34928
34936
|
}
|
|
34929
34937
|
function validateSelection(selection) {
|
|
34930
|
-
if (!selection || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(selection.slug) || !isValidSkillVersion(selection.version) || !/^sha256:[a-f0-9]{64}$/.test(selection.bundleDigest) || typeof selection.workspaceId !== "string" || !selection.workspaceId.trim() || typeof selection.profileRevision !== "string" || !selection.profileRevision.trim()) {
|
|
34938
|
+
if (!selection || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(selection.slug) || !isValidSkillVersion(selection.version) || !/^sha256:[a-f0-9]{64}$/.test(selection.bundleDigest) || typeof selection.workspaceId !== "string" || !selection.workspaceId.trim() || selection.authorizationEpoch !== undefined && (typeof selection.authorizationEpoch !== "string" || !/^[a-f0-9]{32}$/.test(selection.authorizationEpoch)) || typeof selection.profileRevision !== "string" || !selection.profileRevision.trim()) {
|
|
34931
34939
|
throw new SkillSelectionError("INVALID_SELECTION", "A skill selection must carry an exact version, digest, workspace and profile revision.");
|
|
34932
34940
|
}
|
|
34933
34941
|
const aliasError = selectionAliasError([selection]);
|
|
@@ -35053,17 +35061,21 @@ function readSelectionJson(path) {
|
|
|
35053
35061
|
throw new SkillSelectionError("INVALID_RECEIPT", "The Skills selection receipt is unreadable; sync the profile again.");
|
|
35054
35062
|
}
|
|
35055
35063
|
}
|
|
35056
|
-
async function verifiedEntries(selection, bytes) {
|
|
35064
|
+
async function verifiedEntries(selection, bytes, signal, deadline) {
|
|
35057
35065
|
if (`sha256:${sha256Hex(bytes)}` !== selection.bundleDigest)
|
|
35058
35066
|
throw new SkillSelectionError("BUNDLE_DIGEST_MISMATCH", "The skill bundle does not match its selected digest.");
|
|
35059
|
-
const
|
|
35067
|
+
const remaining = deadline === undefined ? undefined : Math.floor(deadline - performance.now());
|
|
35068
|
+
signal?.throwIfAborted();
|
|
35069
|
+
if (remaining !== undefined && remaining <= 0)
|
|
35070
|
+
throw new SkillSelectionError("SKILLS_API_UNAVAILABLE", "Skills session authorization deadline exceeded.");
|
|
35071
|
+
const bundle = await inspectSkillBundle(bytes, { signal, ...remaining === undefined ? {} : { limits: { timeoutMs: remaining } } });
|
|
35060
35072
|
return bundle.entries;
|
|
35061
35073
|
}
|
|
35062
35074
|
async function readCachedSelection(selection, options = {}) {
|
|
35063
35075
|
const bytes = readRegularFile(selectionBundlePath(selection, options), SKILL_BUNDLE_INSPECTION_LIMITS.compressedBytes);
|
|
35064
35076
|
return bytes ? verifiedEntries(selection, bytes) : null;
|
|
35065
35077
|
}
|
|
35066
|
-
async function
|
|
35078
|
+
async function verifySelectionBundleResponse(selection, response, signal, deadline) {
|
|
35067
35079
|
validateSelection(selection);
|
|
35068
35080
|
if (!response?.ok)
|
|
35069
35081
|
throw new SkillSelectionError("BUNDLE_UNAVAILABLE", `The selected skill bundle is unavailable${response ? ` (HTTP ${response.status})` : ""}.`);
|
|
@@ -35073,15 +35085,27 @@ async function cacheSelectionBundle(selection, response, options = {}) {
|
|
|
35073
35085
|
await response.body?.cancel();
|
|
35074
35086
|
throw new SkillSelectionError("BUNDLE_IDENTITY_MISMATCH", "The returned bundle does not match the selected version and digest.");
|
|
35075
35087
|
}
|
|
35088
|
+
const epoch = response.headers.get("X-Skill-Authorization-Epoch");
|
|
35089
|
+
if (selection.authorizationEpoch !== undefined && epoch !== selection.authorizationEpoch) {
|
|
35090
|
+
response.body?.cancel().catch(() => {});
|
|
35091
|
+
throw new SkillSelectionError("SESSION_RECONCILIATION_REQUIRED", "The selected bundle lifecycle authorization changed or is unavailable.");
|
|
35092
|
+
}
|
|
35076
35093
|
const maximum = SKILL_BUNDLE_INSPECTION_LIMITS.compressedBytes;
|
|
35077
35094
|
const reader = response.body?.getReader();
|
|
35078
35095
|
if (!reader)
|
|
35079
35096
|
throw new SkillSelectionError("BUNDLE_UNAVAILABLE", "The selected bundle response has no body.");
|
|
35097
|
+
signal?.throwIfAborted();
|
|
35098
|
+
const abort = () => {
|
|
35099
|
+
reader.cancel().catch(() => {});
|
|
35100
|
+
};
|
|
35101
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
35080
35102
|
const chunks = [];
|
|
35081
35103
|
let length = 0;
|
|
35082
35104
|
try {
|
|
35083
35105
|
while (true) {
|
|
35106
|
+
signal?.throwIfAborted();
|
|
35084
35107
|
const next = await reader.read();
|
|
35108
|
+
signal?.throwIfAborted();
|
|
35085
35109
|
if (next.done)
|
|
35086
35110
|
break;
|
|
35087
35111
|
length += next.value.byteLength;
|
|
@@ -35090,9 +35114,10 @@ async function cacheSelectionBundle(selection, response, options = {}) {
|
|
|
35090
35114
|
chunks.push(next.value);
|
|
35091
35115
|
}
|
|
35092
35116
|
} catch (error) {
|
|
35093
|
-
|
|
35117
|
+
reader.cancel().catch(() => {});
|
|
35094
35118
|
throw error;
|
|
35095
35119
|
} finally {
|
|
35120
|
+
signal?.removeEventListener("abort", abort);
|
|
35096
35121
|
reader.releaseLock();
|
|
35097
35122
|
}
|
|
35098
35123
|
const bytes = new Uint8Array(length);
|
|
@@ -35101,7 +35126,12 @@ async function cacheSelectionBundle(selection, response, options = {}) {
|
|
|
35101
35126
|
bytes.set(chunk, offset);
|
|
35102
35127
|
offset += chunk.byteLength;
|
|
35103
35128
|
}
|
|
35104
|
-
const entries = await verifiedEntries(selection, bytes);
|
|
35129
|
+
const entries = await verifiedEntries(selection, bytes, signal, deadline);
|
|
35130
|
+
return { bytes, entries };
|
|
35131
|
+
}
|
|
35132
|
+
async function cacheSelectionBundle(selection, response, options = {}) {
|
|
35133
|
+
const { bytes, entries } = await verifySelectionBundleResponse(selection, response);
|
|
35134
|
+
const maximum = SKILL_BUNDLE_INSPECTION_LIMITS.compressedBytes;
|
|
35105
35135
|
const path = selectionBundlePath(selection, options);
|
|
35106
35136
|
const existing = readRegularFile(path, maximum);
|
|
35107
35137
|
if (existing)
|
|
@@ -37301,10 +37331,12 @@ function validateSelection2(value) {
|
|
|
37301
37331
|
|
|
37302
37332
|
class HttpProfileClient {
|
|
37303
37333
|
key;
|
|
37334
|
+
signal;
|
|
37304
37335
|
authority;
|
|
37305
37336
|
origin;
|
|
37306
|
-
constructor(key, origin) {
|
|
37337
|
+
constructor(key, origin, signal) {
|
|
37307
37338
|
this.key = key;
|
|
37339
|
+
this.signal = signal;
|
|
37308
37340
|
if (!key.trim())
|
|
37309
37341
|
throw new Error("A Skills credential is required");
|
|
37310
37342
|
this.origin = normalizeSkillsApiOrigin(origin);
|
|
@@ -37318,7 +37350,7 @@ class HttpProfileClient {
|
|
|
37318
37350
|
...init,
|
|
37319
37351
|
redirect: "error",
|
|
37320
37352
|
credentials: "omit",
|
|
37321
|
-
signal: AbortSignal.timeout(15000),
|
|
37353
|
+
signal: this.signal ? AbortSignal.any([this.signal, AbortSignal.timeout(15000)]) : AbortSignal.timeout(15000),
|
|
37322
37354
|
headers: {
|
|
37323
37355
|
"Content-Type": "application/json",
|
|
37324
37356
|
"User-Agent": `hasna-skills/${package_default.version}`,
|
|
@@ -37343,22 +37375,28 @@ class HttpProfileClient {
|
|
|
37343
37375
|
}
|
|
37344
37376
|
async read(response, limit = MAX_PROFILE_DOCUMENT_BYTES) {
|
|
37345
37377
|
try {
|
|
37346
|
-
return JSON.parse(new TextDecoder().decode(await readBoundedResponse(response, limit)));
|
|
37378
|
+
return JSON.parse(new TextDecoder().decode(await readBoundedResponse(response, limit, this.signal)));
|
|
37347
37379
|
} catch {
|
|
37348
37380
|
invalid2();
|
|
37349
37381
|
}
|
|
37350
37382
|
}
|
|
37383
|
+
async supportsPinRenewal() {
|
|
37384
|
+
const result = await this.read(await this.request("/capabilities"));
|
|
37385
|
+
if (!object(result) || !Array.isArray(result.capabilities))
|
|
37386
|
+
invalid2();
|
|
37387
|
+
return result.capabilities.includes("skills.session-pin-renewal");
|
|
37388
|
+
}
|
|
37351
37389
|
async resolveProfile(id2) {
|
|
37352
37390
|
if (!identifier2(id2))
|
|
37353
37391
|
throw new Error("Invalid selection profile id");
|
|
37354
|
-
const result = await this.read(await this.request(`/profiles/${encodeURIComponent(id2)}/resolve`), MAX_RESOLVED_PROFILE_BYTES);
|
|
37392
|
+
const result = await this.read(await this.request(`/profiles/${encodeURIComponent(id2)}/resolve?pinAuthorization=epoch-v1`), MAX_RESOLVED_PROFILE_BYTES);
|
|
37355
37393
|
if (!object(result) || result.profileId !== id2 || result.authority !== this.authority || !identifier2(result.workspaceId) || !identifier2(result.profileRevision) || !Array.isArray(result.selections) || result.selections.length > MAX_PROFILE_SELECTIONS)
|
|
37356
37394
|
invalid2();
|
|
37357
37395
|
const seen = new Set;
|
|
37358
37396
|
for (const entry of result.selections) {
|
|
37359
37397
|
validateSelection2(entry);
|
|
37360
37398
|
const item = entry;
|
|
37361
|
-
if (seen.has(item.slug) || item.authority !== this.authority || item.workspaceId !== result.workspaceId || item.profileRevision !== result.profileRevision)
|
|
37399
|
+
if (item.authorizationEpoch !== undefined && (typeof item.authorizationEpoch !== "string" || !/^[a-f0-9]{32}$/.test(item.authorizationEpoch)) || seen.has(item.slug) || item.authority !== this.authority || item.workspaceId !== result.workspaceId || item.profileRevision !== result.profileRevision)
|
|
37362
37400
|
invalid2();
|
|
37363
37401
|
seen.add(item.slug);
|
|
37364
37402
|
}
|
|
@@ -37405,7 +37443,7 @@ class HttpProfileClient {
|
|
|
37405
37443
|
return this.request(`/skills/${encodeURIComponent(slug)}/versions/${encodeURIComponent(version)}/bundle`);
|
|
37406
37444
|
}
|
|
37407
37445
|
}
|
|
37408
|
-
async function createProfileClient() {
|
|
37446
|
+
async function createProfileClient(signal) {
|
|
37409
37447
|
let connection;
|
|
37410
37448
|
try {
|
|
37411
37449
|
connection = await resolveSkillsConnection();
|
|
@@ -37417,7 +37455,7 @@ async function createProfileClient() {
|
|
|
37417
37455
|
}
|
|
37418
37456
|
if (!connection)
|
|
37419
37457
|
throw new Error("Selection profiles require a configured Skills API");
|
|
37420
|
-
return new HttpProfileClient(connection.apiKey, connection.apiOrigin);
|
|
37458
|
+
return new HttpProfileClient(connection.apiKey, connection.apiOrigin, signal);
|
|
37421
37459
|
}
|
|
37422
37460
|
// src/lib/session-reconciliation.ts
|
|
37423
37461
|
import { createHash as createHash4 } from "crypto";
|
|
@@ -37516,10 +37554,10 @@ async function reconcileSkillSession(input, options = {}) {
|
|
|
37516
37554
|
return { applied: true, plan, planDigest, ...result };
|
|
37517
37555
|
}
|
|
37518
37556
|
// src/lib/selected-run.ts
|
|
37519
|
-
import { createHash as
|
|
37557
|
+
import { createHash as createHash25 } from "crypto";
|
|
37520
37558
|
import { spawn as spawn2 } from "child_process";
|
|
37521
37559
|
import { mkdirSync as mkdirSync11, mkdtempSync as mkdtempSync3, writeFileSync as writeFileSync10, realpathSync as realpathSync14 } from "fs";
|
|
37522
|
-
import { dirname as dirname22, join as
|
|
37560
|
+
import { dirname as dirname22, join as join37, resolve as resolve21 } from "path";
|
|
37523
37561
|
import { tmpdir, hostname as stationHostname2 } from "os";
|
|
37524
37562
|
|
|
37525
37563
|
// src/lib/dependency-preparation.ts
|
|
@@ -37731,7 +37769,7 @@ async function prepareSkillDependencies(skillPath, env, timeoutMs = DEFAULT_PREP
|
|
|
37731
37769
|
|
|
37732
37770
|
// src/lib/skillinfo.ts
|
|
37733
37771
|
import { existsSync as existsSync15, readFileSync as readFileSync23 } from "fs";
|
|
37734
|
-
import { join as
|
|
37772
|
+
import { join as join36 } from "path";
|
|
37735
37773
|
|
|
37736
37774
|
// src/lib/codex-corpus-write.ts
|
|
37737
37775
|
import { KernelLock } from "@hasna/contracts/kernel-lock";
|
|
@@ -37896,7 +37934,7 @@ function withCodexCorpusWrite(roots, run, options = {}) {
|
|
|
37896
37934
|
|
|
37897
37935
|
// src/lib/installer.ts
|
|
37898
37936
|
import { existsSync as existsSync14, readFileSync as readFileSync22, rmSync as rmSync4 } from "fs";
|
|
37899
|
-
import { join as
|
|
37937
|
+
import { join as join35 } from "path";
|
|
37900
37938
|
import { homedir as homedir6 } from "os";
|
|
37901
37939
|
|
|
37902
37940
|
// src/lib/agent-sync.ts
|
|
@@ -37914,7 +37952,7 @@ import {
|
|
|
37914
37952
|
writeFileSync as writeFileSync8
|
|
37915
37953
|
} from "fs";
|
|
37916
37954
|
import { homedir as homedir5 } from "os";
|
|
37917
|
-
import { basename as basename12, dirname as dirname21, join as
|
|
37955
|
+
import { basename as basename12, dirname as dirname21, join as join32 } from "path";
|
|
37918
37956
|
|
|
37919
37957
|
// src/lib/sumi-settings-witness.ts
|
|
37920
37958
|
import { createHash as createHash7 } from "crypto";
|
|
@@ -40214,18 +40252,18 @@ var NATIVE_SKILL_ROOTS = [
|
|
|
40214
40252
|
];
|
|
40215
40253
|
|
|
40216
40254
|
// src/lib/agent-integration.ts
|
|
40217
|
-
import { createHash as
|
|
40255
|
+
import { createHash as createHash23, randomUUID as randomUUID4 } from "crypto";
|
|
40218
40256
|
import { isDeepStrictEqual as isDeepStrictEqual8 } from "util";
|
|
40219
40257
|
import { existsSync as existsSync7, lstatSync as lstatSync22, statSync as statSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync16, readdirSync as readdirSync8, opendirSync as opendirSync5, readlinkSync as readlinkSync5, realpathSync as realpathSync10, renameSync as renameSync4, rmdirSync as rmdirSync3, writeFileSync as writeFileSync5, unlinkSync as unlinkSync5, chmodSync, openSync as openSync17, closeSync as closeSync17, fsyncSync as fsyncSync5, fstatSync as fstatSync17, readSync as readSync12, constants as constants14, linkSync as linkSync3 } from "fs";
|
|
40220
|
-
import { dirname as dirname17, join as
|
|
40258
|
+
import { dirname as dirname17, join as join27, resolve as resolve18, relative as relative5, isAbsolute as isAbsolute19, sep as sep7 } from "path";
|
|
40221
40259
|
import { homedir as homedir3 } from "os";
|
|
40222
40260
|
|
|
40223
40261
|
// src/lib/managed-policy.ts
|
|
40224
40262
|
import { closeSync as closeSync11, constants as constants8, fstatSync as fstatSync11, lstatSync as lstatSync9, openSync as openSync11, readSync as readSync6 } from "fs";
|
|
40225
|
-
import { join as
|
|
40263
|
+
import { join as join15 } from "path";
|
|
40226
40264
|
|
|
40227
40265
|
// src/lib/agent-policy-limits.ts
|
|
40228
|
-
import { basename as basename5, isAbsolute as isAbsolute8, resolve as resolve7 } from "path";
|
|
40266
|
+
import { basename as basename5, isAbsolute as isAbsolute8, join as join14, resolve as resolve7, sep as sep4 } from "path";
|
|
40229
40267
|
var AGENT_POLICY_LIMITS = Object.freeze({ bytes: 1024 * 1024, agents: 16, discoverySources: 2048, discoveryRawSourceBytes: 64 * 1024 * 1024, discoveryRawTotalBytes: 256 * 1024 * 1024, discoveryPathLinks: 40, discoveryPathSteps: 256, discoveryPathSourceMetadataBytes: 64 * 1024, discoveryPathTotalMetadataBytes: 8 * 1024 * 1024, discoveryRoots: 512, discoveryDirectories: 64, discoveryDirectoryEntries: 20000, discoveryDirectoryBytes: 8 * 1024 * 1024, builtinNames: 2048, rootAliases: 2, fields: 64, pathCharacters: 4096 });
|
|
40230
40268
|
function object4(value) {
|
|
40231
40269
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
@@ -40367,7 +40405,9 @@ function assertAgentPolicyCollections(policy) {
|
|
|
40367
40405
|
text(source.path);
|
|
40368
40406
|
requireBound(source.sha256 === null || typeof source.sha256 === "string" && /^[a-f0-9]{64}$/.test(source.sha256));
|
|
40369
40407
|
if (source.hashMode !== undefined)
|
|
40370
|
-
requireBound(["bytes", "path-bytes", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-marketplace-registry-v2", "codex-settings-v1", "codex-settings-v2", "codex-settings-v3", "codex-settings-v4", "sumi-settings-v1"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
40408
|
+
requireBound(["bytes", "path-bytes", "claude-plugin-manifest-v1", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-marketplace-registry-v2", "codex-settings-v1", "codex-settings-v2", "codex-settings-v3", "codex-settings-v4", "sumi-settings-v1"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
40409
|
+
if (source.hashMode === "claude-plugin-manifest-v1")
|
|
40410
|
+
requireBound(agent === "claude" && value.agent === "claude" && ["automatic", "reviewed"].includes(value.method) && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute8(source.path) && resolve7(source.path) === source.path && source.path.endsWith(join14(sep4, ".claude-plugin", "plugin.json")) && source.managedPlugins === undefined);
|
|
40371
40411
|
if (source.hashMode === "sumi-settings-v1")
|
|
40372
40412
|
requireBound(agent === "sumi" && value.agent === "sumi" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute8(source.path) && resolve7(source.path) === source.path && basename5(source.path) === "sumi.json");
|
|
40373
40413
|
if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4"))
|
|
@@ -40436,7 +40476,7 @@ function serializeManagedSkillPolicy(value) {
|
|
|
40436
40476
|
return text2;
|
|
40437
40477
|
}
|
|
40438
40478
|
function readManagedSkillPolicySnapshot(dataDir2 = getDataDirReadOnly()) {
|
|
40439
|
-
const path =
|
|
40479
|
+
const path = join15(dataDir2, "agent-policy.json");
|
|
40440
40480
|
let descriptor, observed = false;
|
|
40441
40481
|
try {
|
|
40442
40482
|
const stat = lstatSync9(path);
|
|
@@ -40486,7 +40526,7 @@ function requiresCliSkillLoading(dataDir2 = getDataDirReadOnly()) {
|
|
|
40486
40526
|
// src/lib/agent-bridge.ts
|
|
40487
40527
|
import { createHash as createHash12 } from "crypto";
|
|
40488
40528
|
import { lstatSync as lstatSync10, readFileSync as readFileSync11, readdirSync as readdirSync4 } from "fs";
|
|
40489
|
-
import { join as
|
|
40529
|
+
import { join as join16 } from "path";
|
|
40490
40530
|
var CLI_BRIDGE_NAME = "skills-cli";
|
|
40491
40531
|
var CLI_BRIDGE_VERSION = 1;
|
|
40492
40532
|
var markdown = `---
|
|
@@ -40518,7 +40558,7 @@ function isOwnedCliBridge(path, expectedPaths) {
|
|
|
40518
40558
|
if (JSON.stringify(readdirSync4(path).sort()) !== JSON.stringify(Object.keys(CLI_BRIDGE_FILES).sort()))
|
|
40519
40559
|
return false;
|
|
40520
40560
|
return Object.entries(CLI_BRIDGE_FILES).every(([name, content]) => {
|
|
40521
|
-
const file =
|
|
40561
|
+
const file = join16(path, name), stat = lstatSync10(file);
|
|
40522
40562
|
return stat.isFile() && !stat.isSymbolicLink() && stat.size === Buffer.byteLength(content) && readFileSync11(file, "utf8") === content;
|
|
40523
40563
|
});
|
|
40524
40564
|
} catch {
|
|
@@ -40527,9 +40567,9 @@ function isOwnedCliBridge(path, expectedPaths) {
|
|
|
40527
40567
|
}
|
|
40528
40568
|
|
|
40529
40569
|
// src/lib/agent-discovery.ts
|
|
40530
|
-
import { createHash as
|
|
40570
|
+
import { createHash as createHash22 } from "crypto";
|
|
40531
40571
|
import { lstatSync as lstatSync21, readFileSync as readFileSync15, readdirSync as readdirSync7, realpathSync as realpathSync9 } from "fs";
|
|
40532
|
-
import { basename as basename8, dirname as dirname16, isAbsolute as isAbsolute18, join as
|
|
40572
|
+
import { basename as basename8, dirname as dirname16, isAbsolute as isAbsolute18, join as join26, resolve as resolve17, sep as sep6 } from "path";
|
|
40533
40573
|
import { isDeepStrictEqual as isDeepStrictEqual6 } from "util";
|
|
40534
40574
|
|
|
40535
40575
|
// node_modules/yaml/dist/index.js
|
|
@@ -40579,7 +40619,7 @@ var $visit = visit.visit;
|
|
|
40579
40619
|
var $visitAsync = visit.visitAsync;
|
|
40580
40620
|
|
|
40581
40621
|
// src/lib/agent-hermes.ts
|
|
40582
|
-
import { dirname as dirname8, isAbsolute as isAbsolute9, join as
|
|
40622
|
+
import { dirname as dirname8, isAbsolute as isAbsolute9, join as join17, resolve as resolve8 } from "path";
|
|
40583
40623
|
import { lstatSync as lstatSync11, readFileSync as readFileSync12, opendirSync } from "fs";
|
|
40584
40624
|
var HERMES_OPT_OUT = ".no-bundled-skills";
|
|
40585
40625
|
var EVENTS = ["pre_llm_call", "pre_tool_call"];
|
|
@@ -40653,7 +40693,7 @@ function assertHermesEnvironment(home) {
|
|
|
40653
40693
|
throw new Error(`NATIVE_SKILL_DRIFT: Hermes ${variable} requires a dedicated discovery adapter; unset it before using this adapter`);
|
|
40654
40694
|
}
|
|
40655
40695
|
const selected = process.env.HERMES_HOME?.trim();
|
|
40656
|
-
if (selected && (!isAbsolute9(selected) || resolve8(selected) !==
|
|
40696
|
+
if (selected && (!isAbsolute9(selected) || resolve8(selected) !== join17(resolve8(home), ".hermes")))
|
|
40657
40697
|
throw new Error("NATIVE_SKILL_DRIFT: custom Hermes homes/profiles require their own reviewed bridge");
|
|
40658
40698
|
if (process.env.HERMES_ENABLE_PROJECT_PLUGINS?.trim() && !["0", "false", "no", "off"].includes(process.env.HERMES_ENABLE_PROJECT_PLUGINS.trim().toLowerCase()))
|
|
40659
40699
|
throw new Error("NATIVE_SKILL_DRIFT: Hermes project plugins require a dedicated discovery review");
|
|
@@ -40674,11 +40714,11 @@ function read(path) {
|
|
|
40674
40714
|
}
|
|
40675
40715
|
function assertHermesProtection(home, config, command, profile, supervisor) {
|
|
40676
40716
|
assertHermesEnvironment(home);
|
|
40677
|
-
if (read(
|
|
40717
|
+
if (read(join17(home, ".hermes", HERMES_OPT_OUT)) === null)
|
|
40678
40718
|
throw new Error("NATIVE_SKILL_DRIFT: Hermes bundled skill reseeding is not disabled; run skills hook install");
|
|
40679
40719
|
if (!supervisor || !isAbsolute9(supervisor.path) || supervisor.runtime !== process.execPath || read(supervisor.path) !== renderHermesSupervisor(command, profile))
|
|
40680
40720
|
throw new Error("NATIVE_SKILL_DRIFT: Hermes owned supervisor changed; run skills hook install");
|
|
40681
|
-
const raw = read(
|
|
40721
|
+
const raw = read(join17(home, ".hermes/shell-hooks-allowlist.json"));
|
|
40682
40722
|
let trust;
|
|
40683
40723
|
try {
|
|
40684
40724
|
trust = raw === null ? undefined : JSON.parse(raw);
|
|
@@ -40721,15 +40761,15 @@ function assertNoHermesLegacyShadow(root) {
|
|
|
40721
40761
|
throw new Error("NATIVE_SKILL_DRIFT: unsupported Hermes legacy discovery input");
|
|
40722
40762
|
return;
|
|
40723
40763
|
}
|
|
40724
|
-
if (lstatSync11(
|
|
40764
|
+
if (lstatSync11(join17(path, "skills-cli.md"), { throwIfNoEntry: false }))
|
|
40725
40765
|
throw new Error("NATIVE_SKILL_DRIFT: legacy Hermes skills-cli.md can shadow the owned bridge; preserve and retire it before continuing");
|
|
40726
|
-
const hasDescriptor = Boolean(lstatSync11(
|
|
40766
|
+
const hasDescriptor = Boolean(lstatSync11(join17(path, "SKILL.md"), { throwIfNoEntry: false }));
|
|
40727
40767
|
const directory = opendirSync(path);
|
|
40728
40768
|
try {
|
|
40729
40769
|
for (let child = directory.readSync();child; child = directory.readSync()) {
|
|
40730
40770
|
if (hasDescriptor && ["references", "templates", "assets", "scripts"].includes(child.name))
|
|
40731
40771
|
continue;
|
|
40732
|
-
scan(
|
|
40772
|
+
scan(join17(path, child.name), depth + 1);
|
|
40733
40773
|
}
|
|
40734
40774
|
} finally {
|
|
40735
40775
|
directory.closeSync();
|
|
@@ -40788,7 +40828,7 @@ if (failed) process.exitCode = 2;
|
|
|
40788
40828
|
// src/lib/agent-discovery-directories.ts
|
|
40789
40829
|
import { createHash as createHash13 } from "crypto";
|
|
40790
40830
|
import { lstatSync as lstatSync12, opendirSync as opendirSync2 } from "fs";
|
|
40791
|
-
import { dirname as dirname9, isAbsolute as isAbsolute10, join as
|
|
40831
|
+
import { dirname as dirname9, isAbsolute as isAbsolute10, join as join18, resolve as resolve9 } from "path";
|
|
40792
40832
|
function need4(value, message) {
|
|
40793
40833
|
if (!value)
|
|
40794
40834
|
throw new Error(message);
|
|
@@ -40826,7 +40866,7 @@ function capture(path, budget2, excludedRoots, omittedRoots = [], rows) {
|
|
|
40826
40866
|
}
|
|
40827
40867
|
need4(new Set(names).size === names.length, "Ambiguous native discovery directory names");
|
|
40828
40868
|
for (const name of names.sort()) {
|
|
40829
|
-
const child =
|
|
40869
|
+
const child = join18(current, name), childRelative = relative5 ? `${relative5}/${name}` : name;
|
|
40830
40870
|
if (omittedRoots.includes(child))
|
|
40831
40871
|
continue;
|
|
40832
40872
|
need4(child.length <= AGENT_POLICY_LIMITS.pathCharacters, "Native discovery directory path limit exceeded");
|
|
@@ -40874,7 +40914,7 @@ function verifyDiscoveryDirectoryProjection(directories, omittedRoots) {
|
|
|
40874
40914
|
need4(Array.isArray(value) && value.length === 2 && typeof value[0] === "string" && value[0] && !isAbsolute10(value[0]) && !value[0].split("/").some((part) => !part || part === "." || part === "..") && ["file", "directory"].includes(value[1]) && row === JSON.stringify(value) + `
|
|
40875
40915
|
`, "Invalid reviewed directory member");
|
|
40876
40916
|
hash2.update(row);
|
|
40877
|
-
const path =
|
|
40917
|
+
const path = join18(directory.path, value[0]);
|
|
40878
40918
|
if (!omittedRoots.some((root) => path === root || path.startsWith(root + "/")))
|
|
40879
40919
|
kept.push(row);
|
|
40880
40920
|
}
|
|
@@ -40972,7 +41012,7 @@ function hashRawDiscoveryFile(path, budget2, changes) {
|
|
|
40972
41012
|
// src/lib/agent-discovery-path-bytes.ts
|
|
40973
41013
|
import { createHash as createHash15 } from "crypto";
|
|
40974
41014
|
import { lstatSync as lstatSync14, readlinkSync as readlinkSync4 } from "fs";
|
|
40975
|
-
import { dirname as dirname11, isAbsolute as isAbsolute12, join as
|
|
41015
|
+
import { dirname as dirname11, isAbsolute as isAbsolute12, join as join19, parse as parse3, resolve as resolve11, sep as sep5 } from "path";
|
|
40976
41016
|
function identity4(stat, mutable = false) {
|
|
40977
41017
|
return {
|
|
40978
41018
|
dev: String(stat.dev),
|
|
@@ -40990,7 +41030,7 @@ function canonical4(path) {
|
|
|
40990
41030
|
function trace(path) {
|
|
40991
41031
|
canonical4(path);
|
|
40992
41032
|
const rows = [], paths = [];
|
|
40993
|
-
let metadataBytes = 0, steps = 0, links = 0, cursor = parse3(path).root, pending = path.slice(cursor.length).split(
|
|
41033
|
+
let metadataBytes = 0, steps = 0, links = 0, cursor = parse3(path).root, pending = path.slice(cursor.length).split(sep5);
|
|
40994
41034
|
function record4(path2, row) {
|
|
40995
41035
|
const value = { path: path2, ...row };
|
|
40996
41036
|
metadataBytes += Buffer.byteLength(JSON.stringify(value));
|
|
@@ -41016,7 +41056,7 @@ function trace(path) {
|
|
|
41016
41056
|
cursor = dirname11(cursor);
|
|
41017
41057
|
continue;
|
|
41018
41058
|
}
|
|
41019
|
-
const candidate =
|
|
41059
|
+
const candidate = join19(cursor, component);
|
|
41020
41060
|
if (candidate.length > AGENT_POLICY_LIMITS.pathCharacters)
|
|
41021
41061
|
throw new Error("Discovery resolved path length limit exceeded");
|
|
41022
41062
|
const stat = lstatSync14(candidate, { bigint: true, throwIfNoEntry: false });
|
|
@@ -41038,7 +41078,7 @@ function trace(path) {
|
|
|
41038
41078
|
root();
|
|
41039
41079
|
}
|
|
41040
41080
|
const remainder = isAbsolute12(target) ? target.slice(parse3(target).root.length) : target;
|
|
41041
|
-
pending = [...remainder.split(
|
|
41081
|
+
pending = [...remainder.split(sep5), ...pending];
|
|
41042
41082
|
if (pending.length + steps > AGENT_POLICY_LIMITS.discoveryPathSteps)
|
|
41043
41083
|
throw new Error("Discovery path step limit exceeded");
|
|
41044
41084
|
continue;
|
|
@@ -41062,7 +41102,7 @@ function hashDiscoveryPathFile(path, budget2, changes) {
|
|
|
41062
41102
|
let createsMissingPath = false;
|
|
41063
41103
|
if (before.missing !== null && changes) {
|
|
41064
41104
|
for (const target of changes.keys()) {
|
|
41065
|
-
if (target === before.missing || target.startsWith(before.missing +
|
|
41105
|
+
if (target === before.missing || target.startsWith(before.missing + sep5)) {
|
|
41066
41106
|
createsMissingPath = true;
|
|
41067
41107
|
break;
|
|
41068
41108
|
}
|
|
@@ -41083,16 +41123,151 @@ function hashDiscoveryPathFile(path, budget2, changes) {
|
|
|
41083
41123
|
return createHash15("sha256").update(JSON.stringify({ version: 1, path, rows: before.rows, content })).digest("hex");
|
|
41084
41124
|
}
|
|
41085
41125
|
|
|
41126
|
+
// src/lib/claude-plugin-manifest-witness.ts
|
|
41127
|
+
import { createHash as createHash16 } from "crypto";
|
|
41128
|
+
var CLAUDE_PLUGIN_MANIFEST_LIMITS = Object.freeze({ bytes: 1024 * 1024, depth: 32, nodes: 65536, stringCharacters: 16384 });
|
|
41129
|
+
function requireValue(value, reason) {
|
|
41130
|
+
if (!value)
|
|
41131
|
+
throw new Error("Claude plugin manifest " + reason);
|
|
41132
|
+
}
|
|
41133
|
+
function parse4(text2) {
|
|
41134
|
+
requireValue(Buffer.byteLength(text2, "utf8") <= CLAUDE_PLUGIN_MANIFEST_LIMITS.bytes, "exceeds its byte limit");
|
|
41135
|
+
let at = 0, nodes = 0;
|
|
41136
|
+
const numberPattern = /-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?/y;
|
|
41137
|
+
const space = () => {
|
|
41138
|
+
while (at < text2.length && /[\x20\t\r\n]/.test(text2[at]))
|
|
41139
|
+
at++;
|
|
41140
|
+
};
|
|
41141
|
+
function string() {
|
|
41142
|
+
requireValue(text2[at] === '"', "contains invalid JSON");
|
|
41143
|
+
const start = at++;
|
|
41144
|
+
while (at < text2.length) {
|
|
41145
|
+
const character = text2[at++];
|
|
41146
|
+
if (character === '"') {
|
|
41147
|
+
let value2;
|
|
41148
|
+
try {
|
|
41149
|
+
value2 = JSON.parse(text2.slice(start, at));
|
|
41150
|
+
} catch {
|
|
41151
|
+
throw new Error("Claude plugin manifest contains invalid JSON string");
|
|
41152
|
+
}
|
|
41153
|
+
requireValue(value2.length <= CLAUDE_PLUGIN_MANIFEST_LIMITS.stringCharacters, "exceeds its string limit");
|
|
41154
|
+
return value2;
|
|
41155
|
+
}
|
|
41156
|
+
if (character === "\\")
|
|
41157
|
+
at++;
|
|
41158
|
+
}
|
|
41159
|
+
throw new Error("Claude plugin manifest contains an unterminated JSON string");
|
|
41160
|
+
}
|
|
41161
|
+
function value(depth) {
|
|
41162
|
+
requireValue(depth <= CLAUDE_PLUGIN_MANIFEST_LIMITS.depth && ++nodes <= CLAUDE_PLUGIN_MANIFEST_LIMITS.nodes, "exceeds its nesting or node limit");
|
|
41163
|
+
space();
|
|
41164
|
+
const character = text2[at];
|
|
41165
|
+
if (character === '"')
|
|
41166
|
+
return { kind: "string", value: string() };
|
|
41167
|
+
if (character === "{" || character === "[") {
|
|
41168
|
+
at++;
|
|
41169
|
+
space();
|
|
41170
|
+
const object6 = character === "{", end = object6 ? "}" : "]", entries = [], items = [], keys2 = new Set;
|
|
41171
|
+
if (text2[at] !== end)
|
|
41172
|
+
while (true) {
|
|
41173
|
+
if (object6) {
|
|
41174
|
+
space();
|
|
41175
|
+
const key = string();
|
|
41176
|
+
requireValue(!keys2.has(key), "contains a duplicate JSON key");
|
|
41177
|
+
keys2.add(key);
|
|
41178
|
+
space();
|
|
41179
|
+
requireValue(text2[at++] === ":", "contains invalid JSON");
|
|
41180
|
+
entries.push([key, value(depth + 1)]);
|
|
41181
|
+
} else
|
|
41182
|
+
items.push(value(depth + 1));
|
|
41183
|
+
space();
|
|
41184
|
+
if (text2[at] === end)
|
|
41185
|
+
break;
|
|
41186
|
+
requireValue(text2[at++] === ",", "contains invalid JSON");
|
|
41187
|
+
}
|
|
41188
|
+
at++;
|
|
41189
|
+
return object6 ? { kind: "object", entries } : { kind: "array", items };
|
|
41190
|
+
}
|
|
41191
|
+
for (const literal of ["true", "false", "null"])
|
|
41192
|
+
if (text2.startsWith(literal, at)) {
|
|
41193
|
+
at += literal.length;
|
|
41194
|
+
return { kind: "literal", value: literal };
|
|
41195
|
+
}
|
|
41196
|
+
numberPattern.lastIndex = at;
|
|
41197
|
+
const number = numberPattern.exec(text2);
|
|
41198
|
+
requireValue(number, "contains invalid JSON");
|
|
41199
|
+
at += number[0].length;
|
|
41200
|
+
return { kind: "number", value: number[0] };
|
|
41201
|
+
}
|
|
41202
|
+
const root = value(0);
|
|
41203
|
+
space();
|
|
41204
|
+
requireValue(at === text2.length && root.kind === "object", "requires a JSON object without trailing content");
|
|
41205
|
+
return root;
|
|
41206
|
+
}
|
|
41207
|
+
function canonical5(value) {
|
|
41208
|
+
if (value.kind === "string")
|
|
41209
|
+
return JSON.stringify(value.value);
|
|
41210
|
+
if (value.kind === "number")
|
|
41211
|
+
return value.value;
|
|
41212
|
+
if (value.kind === "literal")
|
|
41213
|
+
return value.value;
|
|
41214
|
+
if (value.kind === "array")
|
|
41215
|
+
return "[" + value.items.map(canonical5).join(",") + "]";
|
|
41216
|
+
return "{" + value.entries.map(([key, item]) => JSON.stringify(key) + ":" + canonical5(item)).join(",") + "}";
|
|
41217
|
+
}
|
|
41218
|
+
var DESCRIPTIVE_FIELDS = new Set(["description", "version", "author", "homepage", "repository", "license", "keywords"]);
|
|
41219
|
+
function validateText(value, field) {
|
|
41220
|
+
requireValue(value?.kind === "string" && value.value.length <= CLAUDE_PLUGIN_MANIFEST_LIMITS.stringCharacters, "has an invalid " + field + " field");
|
|
41221
|
+
}
|
|
41222
|
+
function validateDescriptiveFields(manifest) {
|
|
41223
|
+
const values = new Map(manifest.entries);
|
|
41224
|
+
for (const field of ["description", "version", "homepage", "license"]) {
|
|
41225
|
+
const value = values.get(field);
|
|
41226
|
+
if (value !== undefined)
|
|
41227
|
+
validateText(value, field);
|
|
41228
|
+
}
|
|
41229
|
+
const author = values.get("author");
|
|
41230
|
+
if (author !== undefined) {
|
|
41231
|
+
if (author.kind === "string")
|
|
41232
|
+
validateText(author, "author");
|
|
41233
|
+
else {
|
|
41234
|
+
requireValue(author.kind === "object" && author.entries.every(([key, value]) => ["name", "email", "url"].includes(key) && value.kind === "string" && value.value.length <= CLAUDE_PLUGIN_MANIFEST_LIMITS.stringCharacters), "has an invalid author field");
|
|
41235
|
+
}
|
|
41236
|
+
}
|
|
41237
|
+
const repository = values.get("repository");
|
|
41238
|
+
if (repository !== undefined) {
|
|
41239
|
+
if (repository.kind === "string")
|
|
41240
|
+
validateText(repository, "repository");
|
|
41241
|
+
else
|
|
41242
|
+
requireValue(repository.kind === "object" && repository.entries.every(([key, value]) => ["type", "url", "directory"].includes(key) && value.kind === "string" && value.value.length <= CLAUDE_PLUGIN_MANIFEST_LIMITS.stringCharacters), "has an invalid repository field");
|
|
41243
|
+
}
|
|
41244
|
+
const keywords = values.get("keywords");
|
|
41245
|
+
if (keywords !== undefined)
|
|
41246
|
+
requireValue(keywords.kind === "array" && keywords.items.every((value) => value.kind === "string" && value.value.length <= CLAUDE_PLUGIN_MANIFEST_LIMITS.stringCharacters), "has an invalid keywords field");
|
|
41247
|
+
}
|
|
41248
|
+
function hashClaudePluginManifest(text2) {
|
|
41249
|
+
const manifest = parse4(text2);
|
|
41250
|
+
validateDescriptiveFields(manifest);
|
|
41251
|
+
const discovery = { kind: "object", entries: manifest.entries.filter(([key]) => !DESCRIPTIVE_FIELDS.has(key)) };
|
|
41252
|
+
return createHash16("sha256").update(canonical5(discovery)).digest("hex");
|
|
41253
|
+
}
|
|
41254
|
+
function projectReviewedClaudePluginManifest(text2, reviewedSha256) {
|
|
41255
|
+
if (!/^[a-f0-9]{64}$/.test(reviewedSha256) || createHash16("sha256").update(text2).digest("hex") !== reviewedSha256) {
|
|
41256
|
+
throw new Error("Reviewed Claude plugin manifest changed before semantic projection");
|
|
41257
|
+
}
|
|
41258
|
+
return hashClaudePluginManifest(text2);
|
|
41259
|
+
}
|
|
41260
|
+
|
|
41086
41261
|
// src/lib/plugin-discovery.ts
|
|
41087
41262
|
import { closeSync as closeSync14, constants as constants11, fstatSync as fstatSync14, lstatSync as lstatSync17, openSync as openSync14, opendirSync as opendirSync4, readSync as readSync9 } from "fs";
|
|
41088
|
-
import { basename as basename6, dirname as dirname13, isAbsolute as isAbsolute16, join as
|
|
41263
|
+
import { basename as basename6, dirname as dirname13, isAbsolute as isAbsolute16, join as join24, resolve as resolve14 } from "path";
|
|
41089
41264
|
|
|
41090
41265
|
// src/lib/plugin-admission.ts
|
|
41091
41266
|
import { homedir as homedir2 } from "os";
|
|
41092
|
-
import { isAbsolute as isAbsolute15, join as
|
|
41267
|
+
import { isAbsolute as isAbsolute15, join as join23, resolve as resolve13 } from "path";
|
|
41093
41268
|
|
|
41094
41269
|
// src/lib/plugin-projection.ts
|
|
41095
|
-
import { createHash as
|
|
41270
|
+
import { createHash as createHash17 } from "crypto";
|
|
41096
41271
|
import { posix as posix2 } from "path";
|
|
41097
41272
|
var PLUGIN_PROJECTION_MANIFEST = "plugin-projection.json";
|
|
41098
41273
|
var PLUGIN_PROJECTION_LIMITS = Object.freeze({ files: 1024, bytes: 64 * 1024 * 1024, fileBytes: 16 * 1024 * 1024, metadataBytes: 512 * 1024, registrations: 64, history: 128 });
|
|
@@ -41103,7 +41278,7 @@ function pluginNeed(value, message) {
|
|
|
41103
41278
|
if (!value)
|
|
41104
41279
|
pluginRefusal(message);
|
|
41105
41280
|
}
|
|
41106
|
-
var pluginHash = (bytes) =>
|
|
41281
|
+
var pluginHash = (bytes) => createHash17("sha256").update(bytes).digest("hex");
|
|
41107
41282
|
function pluginObject(value) {
|
|
41108
41283
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
41109
41284
|
}
|
|
@@ -41119,7 +41294,7 @@ function pluginId(value) {
|
|
|
41119
41294
|
function pluginDigest(value) {
|
|
41120
41295
|
pluginNeed(typeof value === "string" && /^sha256:[a-f0-9]{64}$/.test(value), "Invalid plugin tree digest");
|
|
41121
41296
|
}
|
|
41122
|
-
function
|
|
41297
|
+
function parse5(bytes) {
|
|
41123
41298
|
pluginNeed(bytes.byteLength <= PLUGIN_PROJECTION_LIMITS.metadataBytes, "Plugin metadata exceeds its limit");
|
|
41124
41299
|
try {
|
|
41125
41300
|
return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
@@ -41210,7 +41385,7 @@ function buildPluginProjection(entries) {
|
|
|
41210
41385
|
pluginFileWitnesses(entries);
|
|
41211
41386
|
const contract = entries.filter((item) => item.path === PLUGIN_PROJECTION_MANIFEST);
|
|
41212
41387
|
pluginNeed(contract.length === 1, "The selected bundle has no unique plugin projection manifest");
|
|
41213
|
-
const manifest =
|
|
41388
|
+
const manifest = parse5(contract[0].bytes);
|
|
41214
41389
|
validatePluginManifest(manifest);
|
|
41215
41390
|
const original = entries.filter((item) => item.path.startsWith("original/")).map((item) => ({ ...item, path: item.path.slice(9) }));
|
|
41216
41391
|
pluginNeed(!original.some((item) => [".in_use", ".orphaned_at", ".gcs-sha", ".links_materialized"].some((path) => within(item.path, path))), "Original plugin packages cannot supply native runtime metadata");
|
|
@@ -41218,7 +41393,7 @@ function buildPluginProjection(entries) {
|
|
|
41218
41393
|
pluginNeed(originalTreeDigest === manifest.upstream.treeDigest, "The original plugin package differs from its immutable provenance");
|
|
41219
41394
|
const native = original.find((item) => item.path === ".claude-plugin/plugin.json");
|
|
41220
41395
|
pluginNeed(native, "The original plugin manifest is missing");
|
|
41221
|
-
const config =
|
|
41396
|
+
const config = parse5(native.bytes);
|
|
41222
41397
|
pluginKeys(config, MANIFEST_FIELDS);
|
|
41223
41398
|
pluginNeed(config.name === manifest.pluginId.split("@")[0] && (manifest.upstream.version === null ? !Object.hasOwn(config, "version") : config.version === manifest.upstream.version), "Original plugin identity differs from its contract");
|
|
41224
41399
|
const skillRoots = ["skills", ...declaredPaths(config.skills)], commandRoots = ["commands", ...declaredPaths(config.commands)];
|
|
@@ -41262,7 +41437,7 @@ function buildPluginProjection(entries) {
|
|
|
41262
41437
|
if (item.path === native.path)
|
|
41263
41438
|
continue;
|
|
41264
41439
|
if (item.path.toLowerCase() === "package.json") {
|
|
41265
|
-
const pkg =
|
|
41440
|
+
const pkg = parse5(item.bytes);
|
|
41266
41441
|
pluginNeed(pluginObject(pkg), "Invalid plugin package metadata");
|
|
41267
41442
|
for (const key of ["scripts", "dependencies", "optionalDependencies", "devDependencies", "peerDependencies", "workspaces", "bundledDependencies", "bundleDependencies", "packageManager"])
|
|
41268
41443
|
pluginNeed(pkg[key] === undefined, "Upstream package installation is outside plugin admission");
|
|
@@ -41291,9 +41466,9 @@ function buildPluginProjection(entries) {
|
|
|
41291
41466
|
}
|
|
41292
41467
|
|
|
41293
41468
|
// src/lib/plugin-projection-store.ts
|
|
41294
|
-
import { createHash as
|
|
41469
|
+
import { createHash as createHash18, randomUUID as randomUUID3 } from "crypto";
|
|
41295
41470
|
import { constants as constants10, closeSync as closeSync13, fchmodSync, fstatSync as fstatSync13, fsyncSync as fsyncSync3, linkSync as linkSync2, lstatSync as lstatSync15, mkdirSync as mkdirSync5, openSync as openSync13, opendirSync as opendirSync3, readSync as readSync8, renameSync as renameSync3, rmdirSync as rmdirSync2, rmSync, unlinkSync as unlinkSync4, writeSync as writeSync2 } from "fs";
|
|
41296
|
-
import { dirname as dirname12, isAbsolute as isAbsolute13, join as
|
|
41471
|
+
import { dirname as dirname12, isAbsolute as isAbsolute13, join as join20, parse as parse6, resolve as resolve12 } from "path";
|
|
41297
41472
|
var READ_FLAGS = constants10.O_RDONLY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK;
|
|
41298
41473
|
var WRITE_FLAGS = constants10.O_WRONLY | constants10.O_CREAT | constants10.O_EXCL | constants10.O_NOFOLLOW | constants10.O_NONBLOCK;
|
|
41299
41474
|
var uid = () => typeof process.getuid === "function" ? BigInt(process.getuid()) : undefined;
|
|
@@ -41307,7 +41482,7 @@ function stat(path) {
|
|
|
41307
41482
|
return pluginRefusal("Cannot inspect plugin filesystem entry");
|
|
41308
41483
|
}
|
|
41309
41484
|
}
|
|
41310
|
-
function
|
|
41485
|
+
function canonical6(path) {
|
|
41311
41486
|
pluginNeed(typeof path === "string" && path.length <= 8192 && isAbsolute13(path) && resolve12(path) === path && !/[\x00-\x1f\x7f]/.test(path), "Plugin storage paths must be canonical absolute paths");
|
|
41312
41487
|
}
|
|
41313
41488
|
function owner(stats, system = false) {
|
|
@@ -41318,12 +41493,12 @@ function same3(left, right, identityOnly = false) {
|
|
|
41318
41493
|
pluginNeed(right && left.dev === right.dev && left.ino === right.ino && left.mode === right.mode && left.uid === right.uid && left.gid === right.gid && (identityOnly || left.size === right.size && left.nlink === right.nlink && left.mtimeNs === right.mtimeNs && left.ctimeNs === right.ctimeNs), "Plugin filesystem entry changed during access");
|
|
41319
41494
|
}
|
|
41320
41495
|
function ancestors(path, create = false) {
|
|
41321
|
-
|
|
41322
|
-
const result = [], parent = dirname12(path), filesystemRoot =
|
|
41496
|
+
canonical6(path);
|
|
41497
|
+
const result = [], parent = dirname12(path), filesystemRoot = parse6(parent).root;
|
|
41323
41498
|
let current = filesystemRoot;
|
|
41324
41499
|
for (const segment of ["", ...parent.slice(filesystemRoot.length).split("/").filter(Boolean)]) {
|
|
41325
41500
|
if (segment)
|
|
41326
|
-
current =
|
|
41501
|
+
current = join20(current, segment);
|
|
41327
41502
|
let currentStat = stat(current);
|
|
41328
41503
|
if (!currentStat && create) {
|
|
41329
41504
|
try {
|
|
@@ -41438,7 +41613,7 @@ function snapshotPluginTree(root, options = {}) {
|
|
|
41438
41613
|
pluginNeed(++visited <= PLUGIN_PROJECTION_LIMITS.files * 50, "Plugin tree membership exceeds its limit");
|
|
41439
41614
|
const path = relative5 ? `${relative5}/${name}` : name;
|
|
41440
41615
|
pluginNeed(new TextEncoder().encode(path).byteLength <= 100 && !/[\\:\x00-\x1f\x7f]/u.test(path), "Plugin entry path exceeds its limit or is unsafe");
|
|
41441
|
-
const absolute =
|
|
41616
|
+
const absolute = join20(directory, name), entryStat = stat(absolute);
|
|
41442
41617
|
pluginNeed(entryStat, "Plugin tree member disappeared");
|
|
41443
41618
|
if (relative5 === "" && name === ".orphaned_at" && (options.nativeRuntime === "claude-2.1.274" || options.nativeRuntime === "claude-2.1.276")) {
|
|
41444
41619
|
const bytes2 = readBytes(absolute, 32, "native-pin");
|
|
@@ -41455,7 +41630,7 @@ function snapshotPluginTree(root, options = {}) {
|
|
|
41455
41630
|
directories.push({ path: absolute, stat: entryStat, names: pins });
|
|
41456
41631
|
for (const pin of pins) {
|
|
41457
41632
|
pluginNeed(/^[1-9][0-9]{0,9}$/.test(pin) && Number(pin) <= 2147483647, "Unrecognized native plugin pin name");
|
|
41458
|
-
const pinPath =
|
|
41633
|
+
const pinPath = join20(absolute, pin), pinStat = stat(pinPath);
|
|
41459
41634
|
pluginNeed(pinStat, "Native plugin pin disappeared");
|
|
41460
41635
|
const bytes2 = readBytes(pinPath, 4096, "native-pin");
|
|
41461
41636
|
let value;
|
|
@@ -41553,7 +41728,7 @@ function materializePluginTree(root, entries) {
|
|
|
41553
41728
|
mkdirSync5(staging, { mode: 448 });
|
|
41554
41729
|
staged = stat(staging);
|
|
41555
41730
|
for (const entry of entries) {
|
|
41556
|
-
const path =
|
|
41731
|
+
const path = join20(staging, entry.path);
|
|
41557
41732
|
ancestors(path, true);
|
|
41558
41733
|
writeExclusive(path, entry.bytes, entry.mode);
|
|
41559
41734
|
}
|
|
@@ -41633,7 +41808,7 @@ function pluginExecutableDigest(path) {
|
|
|
41633
41808
|
const opened = fstatSync13(fd, { bigint: true });
|
|
41634
41809
|
same3(before, opened);
|
|
41635
41810
|
fileShape(opened, maximum, "executable");
|
|
41636
|
-
const hash2 =
|
|
41811
|
+
const hash2 = createHash18("sha256"), buffer = new Uint8Array(64 * 1024);
|
|
41637
41812
|
let remaining = Number(opened.size);
|
|
41638
41813
|
while (remaining > 0) {
|
|
41639
41814
|
const count = readSync8(fd, buffer, 0, Math.min(buffer.byteLength, remaining), null);
|
|
@@ -41658,11 +41833,11 @@ function pluginExecutableDigest(path) {
|
|
|
41658
41833
|
|
|
41659
41834
|
// src/lib/skill-validation.ts
|
|
41660
41835
|
import { existsSync as existsSync5, lstatSync as lstatSync16, readFileSync as readFileSync14, readdirSync as readdirSync6, statSync as statSync6 } from "fs";
|
|
41661
|
-
import { isAbsolute as isAbsolute14, join as
|
|
41836
|
+
import { isAbsolute as isAbsolute14, join as join22, normalize as normalize3 } from "path";
|
|
41662
41837
|
|
|
41663
41838
|
// src/lib/hosted-skill-set.ts
|
|
41664
41839
|
import { existsSync as existsSync4, readFileSync as readFileSync13, readdirSync as readdirSync5, statSync as statSync5 } from "fs";
|
|
41665
|
-
import { join as
|
|
41840
|
+
import { join as join21 } from "path";
|
|
41666
41841
|
var HOSTED_RUNTIMES = new Set(["hosted"]);
|
|
41667
41842
|
var HOSTED_SOURCES = new Set(["remote", "private-hosted"]);
|
|
41668
41843
|
function normalizeMarker(value) {
|
|
@@ -41675,7 +41850,7 @@ function isHostedMetadataPackage(pkg) {
|
|
|
41675
41850
|
return HOSTED_RUNTIMES.has(normalizeMarker(skills.runtime)) || HOSTED_SOURCES.has(normalizeMarker(skills.source));
|
|
41676
41851
|
}
|
|
41677
41852
|
function isHostedMetadataSkillDir(skillDir) {
|
|
41678
|
-
const pkgPath =
|
|
41853
|
+
const pkgPath = join21(skillDir, "package.json");
|
|
41679
41854
|
if (!existsSync4(pkgPath))
|
|
41680
41855
|
return false;
|
|
41681
41856
|
try {
|
|
@@ -41775,7 +41950,7 @@ function validateRuntimeEntry(skillPath, entrypoint, issues, warnings) {
|
|
|
41775
41950
|
const parts = entrypoint.split("/");
|
|
41776
41951
|
let current = skillPath;
|
|
41777
41952
|
for (let index = 0;index < parts.length; index++) {
|
|
41778
|
-
current =
|
|
41953
|
+
current = join22(current, parts[index]);
|
|
41779
41954
|
let info;
|
|
41780
41955
|
try {
|
|
41781
41956
|
info = lstatSync16(current);
|
|
@@ -41891,7 +42066,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
41891
42066
|
add(issues, "skill.name_invalid", `Skill name '${bareName}' must use lowercase letters, numbers, dots, underscores, or hyphens`);
|
|
41892
42067
|
}
|
|
41893
42068
|
for (const entry of readdirSync6(skillPath).sort()) {
|
|
41894
|
-
const entryPath =
|
|
42069
|
+
const entryPath = join22(skillPath, entry);
|
|
41895
42070
|
if (RESERVED_SKILL_ENTRIES.has(entry)) {
|
|
41896
42071
|
add(issues, "skill.reserved_file", `Reserved file '${entry}' is not allowed in skill packages`);
|
|
41897
42072
|
}
|
|
@@ -41903,13 +42078,13 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
41903
42078
|
}
|
|
41904
42079
|
}
|
|
41905
42080
|
for (const docFile of DOC_FILES) {
|
|
41906
|
-
if (existsSync5(
|
|
42081
|
+
if (existsSync5(join22(skillPath, docFile)))
|
|
41907
42082
|
metadata.docFiles.push(docFile);
|
|
41908
42083
|
}
|
|
41909
42084
|
if (metadata.docFiles.length === 0) {
|
|
41910
42085
|
add(issues, "skill.docs_missing", "Missing documentation file: expected SKILL.md, README.md, or CLAUDE.md");
|
|
41911
42086
|
}
|
|
41912
|
-
const skillMdPath =
|
|
42087
|
+
const skillMdPath = join22(skillPath, "SKILL.md");
|
|
41913
42088
|
if (existsSync5(skillMdPath)) {
|
|
41914
42089
|
const frontmatter = parseSkillFrontmatter(readFileSync14(skillMdPath, "utf-8"));
|
|
41915
42090
|
if (!frontmatter) {
|
|
@@ -41953,7 +42128,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
41953
42128
|
}
|
|
41954
42129
|
metadata.kind = resolvedKind;
|
|
41955
42130
|
const isInstruction = resolvedKind === "instruction";
|
|
41956
|
-
const pkgPath =
|
|
42131
|
+
const pkgPath = join22(skillPath, "package.json");
|
|
41957
42132
|
if (!existsSync5(pkgPath)) {
|
|
41958
42133
|
if (!isInstruction)
|
|
41959
42134
|
add(issues, "package.missing", "Missing package.json");
|
|
@@ -42012,7 +42187,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
42012
42187
|
add(issues, "package.bin_target_unsafe", `package.json bin '${command}' target '${target}' must stay inside the skill directory`);
|
|
42013
42188
|
continue;
|
|
42014
42189
|
}
|
|
42015
|
-
const targetPath =
|
|
42190
|
+
const targetPath = join22(skillPath, target);
|
|
42016
42191
|
if (!existsSync5(targetPath)) {
|
|
42017
42192
|
add(warnings, "package.bin_target_missing", `package.json bin '${command}' target '${target}' is not present before build`);
|
|
42018
42193
|
} else if (statSync6(targetPath).isDirectory()) {
|
|
@@ -42030,9 +42205,9 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
42030
42205
|
metadata.runtime = "none";
|
|
42031
42206
|
} else {
|
|
42032
42207
|
metadata.runtime = hostedMetadata ? "hosted" : "local";
|
|
42033
|
-
const srcDir =
|
|
42208
|
+
const srcDir = join22(skillPath, "src");
|
|
42034
42209
|
let declaredEntrypoint;
|
|
42035
|
-
const manifestPath =
|
|
42210
|
+
const manifestPath = join22(skillPath, "skill.json");
|
|
42036
42211
|
if (!hostedMetadata && existsSync5(manifestPath)) {
|
|
42037
42212
|
try {
|
|
42038
42213
|
const manifest = asRecord(readJsonFile(manifestPath));
|
|
@@ -42049,10 +42224,10 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
42049
42224
|
validateRuntimeEntry(skillPath, declaredEntrypoint, issues, warnings);
|
|
42050
42225
|
} else if (!existsSync5(srcDir)) {
|
|
42051
42226
|
add(issues, "skill.src_missing", "Missing src/ directory");
|
|
42052
|
-
} else if (!existsSync5(
|
|
42227
|
+
} else if (!existsSync5(join22(srcDir, "index.ts")) && !existsSync5(join22(srcDir, "index.js"))) {
|
|
42053
42228
|
add(issues, "skill.src_index_missing", "Missing src/index.ts or src/index.js");
|
|
42054
42229
|
} else {
|
|
42055
|
-
const indexPath = existsSync5(
|
|
42230
|
+
const indexPath = existsSync5(join22(srcDir, "index.ts")) ? join22(srcDir, "index.ts") : join22(srcDir, "index.js");
|
|
42056
42231
|
const size = statSync6(indexPath).size;
|
|
42057
42232
|
if (size < 50)
|
|
42058
42233
|
add(warnings, "skill.src_index_minimal", `Source entry point is very small (${size}B)`);
|
|
@@ -42077,7 +42252,7 @@ function validateRegistryConsistency(registry, skillsDir) {
|
|
|
42077
42252
|
return false;
|
|
42078
42253
|
})));
|
|
42079
42254
|
const skillDirs = existsSync5(skillsDir) ? readdirSync6(skillsDir).filter((entry) => {
|
|
42080
|
-
const fullPath =
|
|
42255
|
+
const fullPath = join22(skillsDir, entry);
|
|
42081
42256
|
return !entry.startsWith(".") && entry !== "_common" && statSync6(fullPath).isDirectory();
|
|
42082
42257
|
}) : [];
|
|
42083
42258
|
const directoryNames2 = new Set(skillDirs);
|
|
@@ -42116,7 +42291,7 @@ function describeEntries(entries) {
|
|
|
42116
42291
|
|
|
42117
42292
|
// src/lib/plugin-admission.ts
|
|
42118
42293
|
function pluginAdmissionRoot() {
|
|
42119
|
-
return
|
|
42294
|
+
return join23(homedir2(), ".hasna", "skills", "plugin-admission");
|
|
42120
42295
|
}
|
|
42121
42296
|
function validatePluginTarget(value) {
|
|
42122
42297
|
pluginKeys(value, ["schemaVersion", "pluginId", "registrations", "native", "resolver"]);
|
|
@@ -42292,12 +42467,12 @@ function root(options) {
|
|
|
42292
42467
|
}
|
|
42293
42468
|
function pluginBindingPath(storeRoot, id2) {
|
|
42294
42469
|
pluginNeed(/^[a-f0-9]{64}$/.test(id2), "Invalid plugin binding identifier");
|
|
42295
|
-
return
|
|
42470
|
+
return join23(storeRoot, "bindings", `${id2}.json`);
|
|
42296
42471
|
}
|
|
42297
42472
|
function pluginReceiptPath(storeRoot, id2, digest2) {
|
|
42298
42473
|
pluginNeed(/^[a-f0-9]{64}$/.test(id2), "Invalid plugin binding identifier");
|
|
42299
42474
|
pluginDigest(digest2);
|
|
42300
|
-
return
|
|
42475
|
+
return join23(storeRoot, "receipts", id2, `${digest2.slice(7)}.json`);
|
|
42301
42476
|
}
|
|
42302
42477
|
function readPluginBinding(storeRoot, id2) {
|
|
42303
42478
|
const value = readPluginJson(pluginBindingPath(storeRoot, id2));
|
|
@@ -42317,7 +42492,7 @@ function readPluginAdmissionReceipt(storeRoot, id2, digest2) {
|
|
|
42317
42492
|
pluginNeed(receipt.plan.bindingId === id2 && receipt.plan.planDigest === digest2, "Plugin receipt identity differs from its filename");
|
|
42318
42493
|
const binding = readPluginBinding(storeRoot, id2);
|
|
42319
42494
|
pluginNeed(canonicalJson(binding) === canonicalJson(receipt.plan.binding) && receipt.plan.sourceCommand === pluginResolverCommand(binding), "Plugin receipt binding changed");
|
|
42320
|
-
pluginNeed(receipt.materializedPath ===
|
|
42495
|
+
pluginNeed(receipt.materializedPath === join23(storeRoot, "objects", id2, digest2.slice(7)), "Plugin receipt points outside its immutable materialization");
|
|
42321
42496
|
pluginText(receipt.admittedAt, 64);
|
|
42322
42497
|
pluginNeed(Number.isFinite(Date.parse(receipt.admittedAt)), "Invalid plugin admission time");
|
|
42323
42498
|
return receipt;
|
|
@@ -42458,7 +42633,7 @@ async function admitPlugin(spec, profileId, target, approvedDigest, approvedEvid
|
|
|
42458
42633
|
const { plan, projection } = await candidate(spec, profileId, target, options);
|
|
42459
42634
|
pluginNeed(plan.planDigest === approvedDigest, "The plugin plan changed since review; obtain and review a new plan");
|
|
42460
42635
|
pluginNeed(plan.evidenceDigest === approvedEvidenceDigest, "The plugin routing evidence changed since review; obtain and review a new plan");
|
|
42461
|
-
const store = root(options), materializedPath =
|
|
42636
|
+
const store = root(options), materializedPath = join23(store, "objects", plan.bindingId, plan.planDigest.slice(7));
|
|
42462
42637
|
materializePluginTree(materializedPath, projection.files);
|
|
42463
42638
|
writePluginJsonImmutable(pluginBindingPath(store, plan.bindingId), plan.binding);
|
|
42464
42639
|
const path = pluginReceiptPath(store, plan.bindingId, plan.planDigest), existing = readPluginJson(path);
|
|
@@ -42550,7 +42725,7 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
42550
42725
|
seen.add(target.pluginId);
|
|
42551
42726
|
const rows = plugins[target.pluginId];
|
|
42552
42727
|
pluginNeed(Array.isArray(rows) && rows.length === target.registrations.length, "Managed plugin registration membership changed");
|
|
42553
|
-
const [name, market] = target.pluginId.split("@"), cacheRoot =
|
|
42728
|
+
const [name, market] = target.pluginId.split("@"), cacheRoot = join24(dirname13(path), "cache", market, name);
|
|
42554
42729
|
const scopes = new Set, approvals = new Map, currentFiles = new Map;
|
|
42555
42730
|
plugins[target.pluginId] = rows.map((row) => {
|
|
42556
42731
|
pluginNeed(pluginObject(row), "Invalid managed plugin registration");
|
|
@@ -42563,7 +42738,7 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
42563
42738
|
pluginText(row.sourceProducerPath);
|
|
42564
42739
|
pluginText(row.lastUpdated, 64);
|
|
42565
42740
|
pluginNeed(Number.isFinite(Date.parse(row.lastUpdated)), "Invalid managed plugin update timestamp");
|
|
42566
|
-
pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath ===
|
|
42741
|
+
pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath === join24(cacheRoot, row.version), "Managed plugin cache path or version is outside its registration");
|
|
42567
42742
|
const approval = (producer) => {
|
|
42568
42743
|
pluginText(producer);
|
|
42569
42744
|
const digest2 = `sha256:${basename6(producer)}`;
|
|
@@ -42606,11 +42781,11 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
42606
42781
|
directory.closeSync();
|
|
42607
42782
|
}
|
|
42608
42783
|
for (const version of names.sort()) {
|
|
42609
|
-
const files = pluginFileWitnesses(snapshotPluginTree(
|
|
42784
|
+
const files = pluginFileWitnesses(snapshotPluginTree(join24(cacheRoot, version), { nativeRuntime: `claude-${target.native.version}` }));
|
|
42610
42785
|
verifiedBytes += files.reduce((total, file) => total + file.size, 0);
|
|
42611
42786
|
pluginNeed(verifiedBytes <= 256 * 1024 * 1024, "Managed plugin verification exceeds its aggregate byte budget");
|
|
42612
42787
|
const serialized = JSON.stringify(files);
|
|
42613
|
-
const expected = currentFiles.get(
|
|
42788
|
+
const expected = currentFiles.get(join24(cacheRoot, version));
|
|
42614
42789
|
pluginNeed(expected === undefined || serialized === expected, "Current native cache differs from its exact registered producer receipt");
|
|
42615
42790
|
pluginNeed([...approvals.values()].some((receipt) => nativeVersionMatches(version, receipt) && JSON.stringify(receipt.plan.files) === serialized), "A retained native plugin cache version differs from every approved projection");
|
|
42616
42791
|
}
|
|
@@ -42628,7 +42803,7 @@ function captureManagedPluginRegistry(path, managedPlugins) {
|
|
|
42628
42803
|
}
|
|
42629
42804
|
|
|
42630
42805
|
// src/lib/claude-marketplace-registry.ts
|
|
42631
|
-
import { createHash as
|
|
42806
|
+
import { createHash as createHash19 } from "crypto";
|
|
42632
42807
|
import { closeSync as closeSync15, constants as constants12, fstatSync as fstatSync15, lstatSync as lstatSync18, openSync as openSync15, readSync as readSync10 } from "fs";
|
|
42633
42808
|
import { basename as basename7, dirname as dirname14, isAbsolute as isAbsolute17, resolve as resolve15 } from "path";
|
|
42634
42809
|
var CLAUDE_MARKETPLACE_REGISTRY_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
|
|
@@ -42685,7 +42860,7 @@ function readRegistry2(path, budget2) {
|
|
|
42685
42860
|
closeSync15(fd);
|
|
42686
42861
|
}
|
|
42687
42862
|
}
|
|
42688
|
-
function
|
|
42863
|
+
function parse7(text2) {
|
|
42689
42864
|
let at = 0, nodes = 0;
|
|
42690
42865
|
const numberPattern = /-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?/y;
|
|
42691
42866
|
const space = () => {
|
|
@@ -42794,26 +42969,26 @@ function normalizeRow(row, version = 1) {
|
|
|
42794
42969
|
row.entries = row.entries.map(([key, value]) => [key, key === "lastUpdated" ? { kind: "validated-update-time" } : value]);
|
|
42795
42970
|
}
|
|
42796
42971
|
function captureClaudeMarketplaceRegistry(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
42797
|
-
const value =
|
|
42972
|
+
const value = parse7(readRegistry2(path, budget2));
|
|
42798
42973
|
for (const [, row] of value.entries)
|
|
42799
42974
|
normalizeRow(row);
|
|
42800
|
-
const sha2562 =
|
|
42975
|
+
const sha2562 = createHash19("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
|
|
42801
42976
|
return { path, hashMode: "claude-marketplace-registry", sha256: sha2562 };
|
|
42802
42977
|
}
|
|
42803
42978
|
function captureClaudeMarketplaceRegistryV2(path, budget2 = { remaining: 256 * 1024 * 1024 }) {
|
|
42804
|
-
const value =
|
|
42979
|
+
const value = parse7(readRegistry2(path, budget2));
|
|
42805
42980
|
for (const [, row] of value.entries)
|
|
42806
42981
|
normalizeRow(row, 2);
|
|
42807
|
-
const sha2562 =
|
|
42982
|
+
const sha2562 = createHash19("sha256").update("hasna.skills.claude-marketplace-registry.v2\x00").update(JSON.stringify(value)).digest("hex");
|
|
42808
42983
|
return { path, hashMode: "claude-marketplace-registry-v2", sha256: sha2562 };
|
|
42809
42984
|
}
|
|
42810
42985
|
|
|
42811
42986
|
// src/lib/codex-hook-discovery-recovery.ts
|
|
42812
|
-
import { createHash as
|
|
42987
|
+
import { createHash as createHash21 } from "crypto";
|
|
42813
42988
|
|
|
42814
42989
|
// src/lib/codex-hook-trust-files.ts
|
|
42815
42990
|
import { closeSync as closeSync16, constants as constants13, fstatSync as fstatSync16, fsyncSync as fsyncSync4, lstatSync as lstatSync19, openSync as openSync16, readSync as readSync11, writeFileSync as writeFileSync4 } from "fs";
|
|
42816
|
-
import { createHash as
|
|
42991
|
+
import { createHash as createHash20 } from "crypto";
|
|
42817
42992
|
import { dirname as dirname15 } from "path";
|
|
42818
42993
|
function need6(value, code) {
|
|
42819
42994
|
if (!value)
|
|
@@ -42849,7 +43024,7 @@ function snapshot(file, privateFile = false, options = {}) {
|
|
|
42849
43024
|
}
|
|
42850
43025
|
need6(length === Number(before.size) && sameStat(before, fstatSync16(fd, { bigint: true })) && sameStat(before, lstatSync19(file, { bigint: true })), "INPUT_CHANGED");
|
|
42851
43026
|
const content = bytes.subarray(0, length), text2 = new TextDecoder("utf-8", { fatal: true }).decode(content);
|
|
42852
|
-
return { file, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before, sha256:
|
|
43027
|
+
return { file, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before, sha256: createHash20("sha256").update(content).digest("hex") };
|
|
42853
43028
|
} finally {
|
|
42854
43029
|
closeSync16(fd);
|
|
42855
43030
|
}
|
|
@@ -42865,7 +43040,7 @@ var matchedEvents = { ...events, PreToolUse: ["preToolUse", "pre_tool_use"] };
|
|
|
42865
43040
|
var proofs = new WeakMap;
|
|
42866
43041
|
|
|
42867
43042
|
// src/lib/codex-hook-discovery-recovery.ts
|
|
42868
|
-
var sha3 = (text2) =>
|
|
43043
|
+
var sha3 = (text2) => createHash21("sha256").update(text2).digest("hex");
|
|
42869
43044
|
var fields = [...CODEX_DISCOVERY_PROJECTION_FIELDS];
|
|
42870
43045
|
var proofs2 = new WeakMap;
|
|
42871
43046
|
function assertCodexHookDiscoveryRecovery(binding, witness) {
|
|
@@ -42885,36 +43060,36 @@ function verifiesCodexHookDiscoverySource(binding, source, currentDigest, witnes
|
|
|
42885
43060
|
|
|
42886
43061
|
// src/lib/agent-sumi.ts
|
|
42887
43062
|
import { existsSync as existsSync6, lstatSync as lstatSync20, realpathSync as realpathSync8 } from "fs";
|
|
42888
|
-
import { join as
|
|
43063
|
+
import { join as join25, resolve as resolve16 } from "path";
|
|
42889
43064
|
function sumiConfigDirectory(home, env = process.env) {
|
|
42890
43065
|
for (const key of ["SUMI_CONFIG", "SUMI_CONFIG_CONTENT"])
|
|
42891
43066
|
if (env[key] !== undefined)
|
|
42892
43067
|
throw new Error(`Sumi ${key} requires a dedicated discovery adapter; unset it before Skills integration`);
|
|
42893
43068
|
const selected = (key) => env[key]?.trim() ? env[key] : undefined;
|
|
42894
|
-
const expand = (value) => resolve16(value === "~" ? home : value.startsWith("~/") ?
|
|
43069
|
+
const expand = (value) => resolve16(value === "~" ? home : value.startsWith("~/") ? join25(home, value.slice(2)) : value);
|
|
42895
43070
|
const explicit = selected("SUMI_CONFIG_DIR");
|
|
42896
43071
|
const xdg = selected("XDG_CONFIG_HOME");
|
|
42897
43072
|
const custom = selected("SUMI_HOME");
|
|
42898
|
-
const
|
|
43073
|
+
const canonical7 = explicit ? expand(explicit) : xdg ? join25(expand(xdg), "sumi") : join25(custom ? expand(custom) : join25(home, ".hasna-internal/sumi"), "config");
|
|
42899
43074
|
if (explicit || xdg || custom)
|
|
42900
|
-
return
|
|
42901
|
-
const legacy =
|
|
42902
|
-
const a = lstatSync20(
|
|
42903
|
-
if (a && b && realpathSync8(
|
|
43075
|
+
return canonical7;
|
|
43076
|
+
const legacy = join25(home, ".config/sumi");
|
|
43077
|
+
const a = lstatSync20(canonical7, { throwIfNoEntry: false }), b = lstatSync20(legacy, { throwIfNoEntry: false });
|
|
43078
|
+
if (a && b && realpathSync8(canonical7) !== realpathSync8(legacy))
|
|
42904
43079
|
throw new Error("Sumi config roots conflict; complete native home adoption before Skills integration");
|
|
42905
|
-
const path = a ?
|
|
43080
|
+
const path = a ? canonical7 : b ? legacy : canonical7;
|
|
42906
43081
|
if (!existsSync6(path))
|
|
42907
43082
|
return path;
|
|
42908
43083
|
const physical = realpathSync8(path);
|
|
42909
|
-
if ((a?.isSymbolicLink() || b?.isSymbolicLink()) && ![
|
|
43084
|
+
if ((a?.isSymbolicLink() || b?.isSymbolicLink()) && ![canonical7, legacy].includes(physical))
|
|
42910
43085
|
throw new Error("Sumi config alias must resolve to its canonical or legacy root");
|
|
42911
43086
|
return physical;
|
|
42912
43087
|
}
|
|
42913
43088
|
function sumiBridgeRoot(home) {
|
|
42914
|
-
return
|
|
43089
|
+
return join25(sumiConfigDirectory(home), "skills");
|
|
42915
43090
|
}
|
|
42916
43091
|
function sumiConfigPath(home) {
|
|
42917
|
-
return
|
|
43092
|
+
return join25(sumiConfigDirectory(home), "sumi.json");
|
|
42918
43093
|
}
|
|
42919
43094
|
function renderSumiPlugin(command, profile) {
|
|
42920
43095
|
return renderSumiPluginVersion(command, profile, false);
|
|
@@ -43006,7 +43181,7 @@ var SUMI_SKILL_PERMISSIONS = [
|
|
|
43006
43181
|
];
|
|
43007
43182
|
|
|
43008
43183
|
// src/lib/agent-discovery.ts
|
|
43009
|
-
var digest2 = (text2) =>
|
|
43184
|
+
var digest2 = (text2) => createHash22("sha256").update(text2).digest("hex");
|
|
43010
43185
|
function parseConfig(text2, path, toml = false) {
|
|
43011
43186
|
try {
|
|
43012
43187
|
const value = toml ? Bun.TOML.parse(text2) : JSON.parse(text2);
|
|
@@ -43092,6 +43267,12 @@ function projected(source, changes, budget2 = discoveryByteBudget()) {
|
|
|
43092
43267
|
throw new Error("Managed plugin registry witnesses require verified native registrations");
|
|
43093
43268
|
return hashManagedPluginRegistry(source.path, source.managedPlugins);
|
|
43094
43269
|
}
|
|
43270
|
+
if (source.hashMode === "claude-plugin-manifest-v1") {
|
|
43271
|
+
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || changes?.has(source.path))
|
|
43272
|
+
throw new Error("Claude plugin manifest witnesses require a native discovery source without synthetic changes");
|
|
43273
|
+
const text3 = read2(source.path);
|
|
43274
|
+
return text3 === null ? null : hashClaudePluginManifest(text3);
|
|
43275
|
+
}
|
|
43095
43276
|
if (source.managedPlugins !== undefined)
|
|
43096
43277
|
throw new Error("Managed plugin rules require a typed registry witness");
|
|
43097
43278
|
if (source.hashMode !== undefined) {
|
|
@@ -43118,7 +43299,7 @@ function absentCodexSkillRoots(binding) {
|
|
|
43118
43299
|
throw new Error("Invalid disabled Codex discovery proof");
|
|
43119
43300
|
if (binding.method !== "reviewed" || controls.every((control) => lstatSync21(control.pluginParent, { throwIfNoEntry: false })))
|
|
43120
43301
|
return [];
|
|
43121
|
-
const cache = dirname16(dirname16(controls[0].pluginParent)), config =
|
|
43302
|
+
const cache = dirname16(dirname16(controls[0].pluginParent)), config = join26(dirname16(dirname16(cache)), "config.toml");
|
|
43122
43303
|
const source = binding.sources.find((source2) => source2.path === config && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined);
|
|
43123
43304
|
if (!source || projected(source) !== source.sha256)
|
|
43124
43305
|
throw new Error("Missing current disabled Codex configuration witness");
|
|
@@ -43126,8 +43307,8 @@ function absentCodexSkillRoots(binding) {
|
|
|
43126
43307
|
return [...new Set(controls.map((control) => control.pluginParent))].filter((parent) => !codexDirectHookSelects(cache, parent) && absentDisabledCodexPluginParent(cache, parent, controls, rules));
|
|
43127
43308
|
}
|
|
43128
43309
|
function codexDirectHookSelects(cache, root2) {
|
|
43129
|
-
const codex = dirname16(dirname16(cache)), config = Bun.TOML.parse(read2(
|
|
43130
|
-
const hooks = read2(
|
|
43310
|
+
const codex = dirname16(dirname16(cache)), config = Bun.TOML.parse(read2(join26(codex, "config.toml")) ?? "");
|
|
43311
|
+
const hooks = read2(join26(codex, "hooks.json"));
|
|
43131
43312
|
if (hooks !== null)
|
|
43132
43313
|
hashNativeJsonControls(hooks);
|
|
43133
43314
|
return JSON.stringify(config.hooks ?? {}).includes(root2) || hooks !== null && JSON.stringify(JSON.parse(hooks)).includes(root2);
|
|
@@ -43139,7 +43320,7 @@ function retiredCodexRoots(binding) {
|
|
|
43139
43320
|
const controls = binding.codexDisabledPluginSkills;
|
|
43140
43321
|
if (binding.agent !== "codex" || binding.method !== "reviewed" || !Array.isArray(controls) || !controls.length || !Array.isArray(proof.roots) || proof.roots.length > AGENT_POLICY_LIMITS.discoveryRoots || new Set(proof.roots).size !== proof.roots.length || !Array.isArray(proof.directories) || proof.parents !== undefined && (!Array.isArray(proof.parents) || proof.parents.length > AGENT_POLICY_LIMITS.discoveryRoots || new Set(proof.parents).size !== proof.parents.length) || !proof.roots.length && !proof.parents?.length)
|
|
43141
43322
|
throw new Error("Invalid retired Codex materialization proof");
|
|
43142
|
-
const cache = dirname16(dirname16(controls[0].pluginParent)), config =
|
|
43323
|
+
const cache = dirname16(dirname16(controls[0].pluginParent)), config = join26(dirname16(dirname16(cache)), "config.toml");
|
|
43143
43324
|
const source = binding.sources.find((source2) => source2.path === config && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined);
|
|
43144
43325
|
if (!source || projected(source) !== source.sha256)
|
|
43145
43326
|
throw new Error("Missing current retired Codex configuration witness");
|
|
@@ -43147,7 +43328,7 @@ function retiredCodexRoots(binding) {
|
|
|
43147
43328
|
if ((proof.parents ?? []).some((parent) => codexDirectHookSelects(cache, parent) || !reviewedDisabledCodexPluginParent(cache, parent, controls, rules)) || !reviewedCodexPluginCapabilitiesUnchanged(cache, controls, (path) => read2(path), rules))
|
|
43148
43329
|
throw new Error("Retired Codex parent capabilities changed");
|
|
43149
43330
|
for (const root2 of proof.roots) {
|
|
43150
|
-
const manifest = binding.sources.find((source2) => source2.path ===
|
|
43331
|
+
const manifest = binding.sources.find((source2) => source2.path === join26(root2, ".codex-plugin/plugin.json") && source2.sha256 !== null && source2.format === undefined && source2.fields === undefined && [undefined, "bytes"].includes(source2.hashMode));
|
|
43151
43332
|
if (!manifest || codexDirectHookSelects(cache, root2) || !reviewedRetiredCodexRoot(cache, root2, controls, rules, (path) => read2(path), true))
|
|
43152
43333
|
throw new Error("Retired Codex materialization changed");
|
|
43153
43334
|
}
|
|
@@ -43157,14 +43338,14 @@ function captureRetiredCodexDiscovery(binding, controls, rules) {
|
|
|
43157
43338
|
if (binding.agent !== "codex" || binding.method !== "reviewed" || !controls.length)
|
|
43158
43339
|
return binding;
|
|
43159
43340
|
const cache = dirname16(dirname16(controls[0].pluginParent));
|
|
43160
|
-
const candidates = binding.sources.filter((source) => source.path.endsWith(
|
|
43341
|
+
const candidates = binding.sources.filter((source) => source.path.endsWith(sep6 + ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined && [undefined, "bytes"].includes(source.hashMode)).map((source) => dirname16(dirname16(source.path)));
|
|
43161
43342
|
const roots = [...new Set(candidates)].filter((root2) => !codexDirectHookSelects(cache, root2) && reviewedRetiredCodexRoot(cache, root2, controls, rules, (path) => read2(path), binding.codexRetiredMaterializations?.roots.includes(root2) ?? false)).sort();
|
|
43162
43343
|
const parents3 = reviewedCodexPluginCapabilitiesUnchanged(cache, controls, (path) => read2(path), rules) ? [...new Set(controls.map((control) => control.pluginParent))].filter((parent) => !codexDirectHookSelects(cache, parent) && reviewedDisabledCodexPluginParent(cache, parent, controls, rules)).sort() : [];
|
|
43163
43344
|
const { codexRetiredMaterializations: previous, ...current } = binding;
|
|
43164
43345
|
if (!roots.length && !parents3.length)
|
|
43165
43346
|
return current;
|
|
43166
43347
|
const installation = codexInstallationRoots(binding);
|
|
43167
|
-
const directories = (binding.directories ?? []).filter((directory) => !installation.some((root2) => directory.path === root2 || directory.path.startsWith(root2 +
|
|
43348
|
+
const directories = (binding.directories ?? []).filter((directory) => !installation.some((root2) => directory.path === root2 || directory.path.startsWith(root2 + sep6) || root2.startsWith(directory.path + sep6)));
|
|
43168
43349
|
if (previous && isDeepStrictEqual6(previous.roots, roots) && isDeepStrictEqual6(previous.parents, parents3) && isDeepStrictEqual6(previous.directories.map((item) => item.path), directories.map((item) => item.path)))
|
|
43169
43350
|
return { ...current, codexRetiredMaterializations: previous };
|
|
43170
43351
|
return { ...current, codexRetiredMaterializations: { roots, parents: parents3, directories: captureDiscoveryDirectoryProjection(directories.map((item) => item.path), roots) } };
|
|
@@ -43176,17 +43357,17 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
43176
43357
|
for (const source of binding.sources) {
|
|
43177
43358
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || ![undefined, "bytes"].includes(source.hashMode) || source.sha256 === null)
|
|
43178
43359
|
continue;
|
|
43179
|
-
const marker =
|
|
43360
|
+
const marker = sep6 + ".claude" + sep6 + "plugins" + sep6 + "cache" + sep6, at = source.path.indexOf(marker);
|
|
43180
43361
|
if (at < 0 || source.path.indexOf(marker, at + 1) >= 0)
|
|
43181
43362
|
continue;
|
|
43182
|
-
const cache = source.path.slice(0, at + marker.length - 1), parts = source.path.slice(at + marker.length).split(
|
|
43363
|
+
const cache = source.path.slice(0, at + marker.length - 1), parts = source.path.slice(at + marker.length).split(sep6);
|
|
43183
43364
|
if (parts.length < 4 || parts.slice(0, 3).some((part) => !part || part === "." || part === ".."))
|
|
43184
43365
|
continue;
|
|
43185
|
-
const root2 =
|
|
43366
|
+
const root2 = join26(cache, ...parts.slice(0, 3));
|
|
43186
43367
|
safe4(root2);
|
|
43187
43368
|
if (lstatSync21(root2, { throwIfNoEntry: false }))
|
|
43188
43369
|
continue;
|
|
43189
|
-
const claude = dirname16(dirname16(cache)), settings =
|
|
43370
|
+
const claude = dirname16(dirname16(cache)), settings = join26(claude, "settings.json"), registry = join26(claude, "plugins/installed_plugins.json");
|
|
43190
43371
|
const full = (path) => binding.sources.find((item) => item.path === path && item.sha256 !== null && item.format === undefined && item.fields === undefined);
|
|
43191
43372
|
const configSource = full(settings), registrySource = full(registry);
|
|
43192
43373
|
if (!configSource || !registrySource || projected(configSource) !== configSource.sha256 || projected(registrySource) !== registrySource.sha256)
|
|
@@ -43205,10 +43386,10 @@ function absentRetiredClaudeRoots(binding) {
|
|
|
43205
43386
|
const active = rows[0].installPath;
|
|
43206
43387
|
if (rows[0].version !== basename8(active) || resolve17(active) !== active || dirname16(active) !== dirname16(root2) || active === root2 || !lstatSync21(active, { throwIfNoEntry: false })?.isDirectory() || realpathSync9(active) !== active)
|
|
43207
43388
|
continue;
|
|
43208
|
-
const activeManifest = full(
|
|
43389
|
+
const activeManifest = full(join26(active, ".claude-plugin/plugin.json"));
|
|
43209
43390
|
if (!activeManifest || projected(activeManifest) !== activeManifest.sha256)
|
|
43210
43391
|
continue;
|
|
43211
|
-
if (Object.values(installed.plugins).some((value) => !Array.isArray(value) || value.some((row) => !row || typeof row.installPath !== "string" || row.installPath === root2 || row.installPath.startsWith(root2 +
|
|
43392
|
+
if (Object.values(installed.plugins).some((value) => !Array.isArray(value) || value.some((row) => !row || typeof row.installPath !== "string" || row.installPath === root2 || row.installPath.startsWith(root2 + sep6) || root2.startsWith(row.installPath + sep6))))
|
|
43212
43393
|
continue;
|
|
43213
43394
|
result.add(root2);
|
|
43214
43395
|
}
|
|
@@ -43223,10 +43404,10 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
43223
43404
|
throw new Error("Hermes discovery requires directory membership coverage; run skills hook install with a fresh discovery review");
|
|
43224
43405
|
const installationRoots = codexInstallationRoots(binding);
|
|
43225
43406
|
const retiredRoots = retiredCodexRoots(binding);
|
|
43226
|
-
const installationInput = (path) => installationRoots.some((root2) => path === root2 || path.startsWith(root2 +
|
|
43407
|
+
const installationInput = (path) => installationRoots.some((root2) => path === root2 || path.startsWith(root2 + sep6));
|
|
43227
43408
|
if (binding.directories !== undefined) {
|
|
43228
43409
|
const projected2 = binding.codexInstallationInputs?.directories ?? [];
|
|
43229
|
-
const ancestors2 = binding.directories.filter((directory) => installationRoots.some((root2) => root2.startsWith(directory.path +
|
|
43410
|
+
const ancestors2 = binding.directories.filter((directory) => installationRoots.some((root2) => root2.startsWith(directory.path + sep6)));
|
|
43230
43411
|
if (projected2.length !== ancestors2.length || projected2.some((directory) => !ancestors2.some((original) => original.path === directory.path)))
|
|
43231
43412
|
throw new Error("Missing installation input directory projection");
|
|
43232
43413
|
const ordinary = binding.directories.filter((directory) => !installationInput(directory.path) && !ancestors2.includes(directory));
|
|
@@ -43262,7 +43443,7 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
43262
43443
|
safe4(source.path);
|
|
43263
43444
|
continue;
|
|
43264
43445
|
}
|
|
43265
|
-
if (absentRoots.some((root2) => source.path.startsWith(root2 +
|
|
43446
|
+
if (absentRoots.some((root2) => source.path.startsWith(root2 + sep6)) && source.format === undefined && source.fields === undefined && source.managedPlugins === undefined && [undefined, "bytes"].includes(source.hashMode)) {
|
|
43266
43447
|
safe4(source.path);
|
|
43267
43448
|
continue;
|
|
43268
43449
|
}
|
|
@@ -43285,12 +43466,12 @@ function codexInstallationRoots(binding) {
|
|
|
43285
43466
|
if (binding.agent !== "codex" || binding.method !== "reviewed" || proof.version !== "codex-cli 0.160.0" || !/^[a-f0-9]{64}$/.test(proof.catalogSha256) || !Array.isArray(proof.plugins) || !proof.plugins.length)
|
|
43286
43467
|
throw new Error("Invalid native installation input proof");
|
|
43287
43468
|
const cache = dirname16(dirname16(proof.plugins[0].pluginParent));
|
|
43288
|
-
const config =
|
|
43469
|
+
const config = join26(dirname16(dirname16(cache)), "config.toml"), home = dirname16(dirname16(dirname16(cache)));
|
|
43289
43470
|
const configSource = binding.sources.find((source) => source.path === config && source.sha256 !== null && (!source.format || source.format === "toml" && source.fields?.includes("plugins")));
|
|
43290
|
-
const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) =>
|
|
43291
|
-
if (!configSource || proof.plugins.some((input) => nativeRoots.some((root2) => root2 === input.sourceRoot || root2.startsWith(input.sourceRoot +
|
|
43471
|
+
const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => join26(home, path));
|
|
43472
|
+
if (!configSource || proof.plugins.some((input) => nativeRoots.some((root2) => root2 === input.sourceRoot || root2.startsWith(input.sourceRoot + sep6) || input.sourceRoot.startsWith(root2 + sep6)) || binding.sources.some((source) => basename8(source.path) === "config.toml" && (source.path === input.sourceRoot || source.path.startsWith(input.sourceRoot + sep6)))))
|
|
43292
43473
|
throw new Error("Native installation input overlaps configuration or loading roots");
|
|
43293
|
-
if (proof.plugins.some((input) => dirname16(dirname16(input.pluginParent)) !== cache || !binding.sources.some((source) => source.path ===
|
|
43474
|
+
if (proof.plugins.some((input) => dirname16(dirname16(input.pluginParent)) !== cache || !binding.sources.some((source) => source.path === join26(input.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined)))
|
|
43294
43475
|
throw new Error("Missing native installation input source witness");
|
|
43295
43476
|
return reviewedCodexPluginSourceRoots(cache, proof.plugins, (path) => {
|
|
43296
43477
|
const text2 = read2(path);
|
|
@@ -43300,6 +43481,8 @@ function codexInstallationRoots(binding) {
|
|
|
43300
43481
|
});
|
|
43301
43482
|
}
|
|
43302
43483
|
function assertMarketplaceBinding(binding, source) {
|
|
43484
|
+
if (source.hashMode === "claude-plugin-manifest-v1" && (binding.agent !== "claude" || basename8(source.path) !== "plugin.json" || !source.path.endsWith(join26(sep6, ".claude-plugin", "plugin.json"))))
|
|
43485
|
+
throw new Error("Claude plugin manifest witnesses require Claude plugin discovery");
|
|
43303
43486
|
if (source.hashMode === "sumi-settings-v1" && (binding.agent !== "sumi" || binding.method !== "reviewed" || basename8(source.path) !== "sumi.json"))
|
|
43304
43487
|
throw new Error("Sumi settings witnesses require explicit reviewed Sumi configuration");
|
|
43305
43488
|
if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")) && (binding.agent !== "codex" || binding.method !== "reviewed" || basename8(source.path) !== "config.toml"))
|
|
@@ -43314,7 +43497,7 @@ function rebindAgentDiscovery(binding, changes) {
|
|
|
43314
43497
|
const installationRoots = codexInstallationRoots(binding), absentRoots = [...absentCodexSkillRoots(binding), ...absentRetiredClaudeRoots(binding), ...retiredCodexRoots(binding).filter((root2) => !lstatSync21(root2, { throwIfNoEntry: false }))];
|
|
43315
43498
|
const rebound = { ...binding, sources: binding.sources.map((source) => {
|
|
43316
43499
|
assertMarketplaceBinding(binding, source);
|
|
43317
|
-
if (!changes.has(source.path) && (installationRoots.some((root2) => source.path.startsWith(root2 +
|
|
43500
|
+
if (!changes.has(source.path) && (installationRoots.some((root2) => source.path.startsWith(root2 + sep6)) || absentRoots.some((root2) => source.path.startsWith(root2 + sep6)) && source.format === undefined && source.fields === undefined && source.managedPlugins === undefined && [undefined, "bytes"].includes(source.hashMode)))
|
|
43318
43501
|
return source;
|
|
43319
43502
|
const sha2562 = projected(source, changes, budget2);
|
|
43320
43503
|
if (!changes.has(source.path) && sha2562 !== source.sha256)
|
|
@@ -43340,8 +43523,8 @@ function captureDiscoveryPathSources(paths) {
|
|
|
43340
43523
|
const budget2 = discoveryByteBudget();
|
|
43341
43524
|
return paths.map((path) => ({ path, hashMode: "path-bytes", sha256: hashDiscoveryPathFile(path, budget2) }));
|
|
43342
43525
|
}
|
|
43343
|
-
function assertProjectDiscovery(agent, directories, home,
|
|
43344
|
-
const homeConfigPath =
|
|
43526
|
+
function assertProjectDiscovery(agent, directories, home, canonical7 = resolve17, reviewed) {
|
|
43527
|
+
const homeConfigPath = canonical7(agentDiscoveryConfigPath(home, agent));
|
|
43345
43528
|
for (const directory of directories) {
|
|
43346
43529
|
const isHome = resolve17(directory) === resolve17(home);
|
|
43347
43530
|
if (agent === "hermes") {
|
|
@@ -43352,7 +43535,7 @@ function assertProjectDiscovery(agent, directories, home, canonical6 = resolve17
|
|
|
43352
43535
|
continue;
|
|
43353
43536
|
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"] : agent === "sumi" ? ["sumi.json", "sumi.jsonc", ".sumi/sumi.json", ".sumi/sumi.jsonc"] : [".cursor/hooks.json"];
|
|
43354
43537
|
for (const suffix of paths) {
|
|
43355
|
-
const path =
|
|
43538
|
+
const path = canonical7(join26(directory, suffix)), raw = read2(path);
|
|
43356
43539
|
if (raw === null)
|
|
43357
43540
|
continue;
|
|
43358
43541
|
const isRootAliasedHomeConfig = agent === "claude" && suffix === ".claude/settings.json" || agent === "codex" && suffix === ".codex/config.toml";
|
|
@@ -43368,7 +43551,7 @@ function assertProjectDiscovery(agent, directories, home, canonical6 = resolve17
|
|
|
43368
43551
|
const managed = reviewed.sources.flatMap((source) => source.hashMode === "claude-plugin-registry" ? source.managedPlugins ?? [] : []);
|
|
43369
43552
|
if (exact && projected(exact) === exact.sha256 && managed.length) {
|
|
43370
43553
|
const bindings = managed.map((item) => readPluginBinding(item.storeRoot, item.bindingId));
|
|
43371
|
-
admittedPlugins = Object.entries(config.enabledPlugins).every(([id2, enabled]) => typeof enabled === "boolean" && bindings.some((binding) => binding.target.pluginId === id2 && binding.target.registrations.some((scope) => scope.scope === "project" && scope.projectPath ===
|
|
43554
|
+
admittedPlugins = Object.entries(config.enabledPlugins).every(([id2, enabled]) => typeof enabled === "boolean" && bindings.some((binding) => binding.target.pluginId === id2 && binding.target.registrations.some((scope) => scope.scope === "project" && scope.projectPath === canonical7(directory))));
|
|
43372
43555
|
}
|
|
43373
43556
|
}
|
|
43374
43557
|
if (keys2.some((key) => config[key] !== undefined && !(key === "enabledPlugins" && admittedPlugins)) || config.disableAllHooks === true || config.disableBundledSkills === false || config.hooksConfig?.enabled === false || config.permission?.skill !== undefined || config.permissions?.deny?.some((rule) => typeof rule === "string" && /^Skill(?:\(|$)/.test(rule)))
|
|
@@ -43376,13 +43559,13 @@ function assertProjectDiscovery(agent, directories, home, canonical6 = resolve17
|
|
|
43376
43559
|
}
|
|
43377
43560
|
if (agent === "sumi")
|
|
43378
43561
|
for (const name of ["plugin", "plugins"]) {
|
|
43379
|
-
const path =
|
|
43562
|
+
const path = canonical7(join26(directory, ".sumi", name));
|
|
43380
43563
|
safe4(path);
|
|
43381
43564
|
if (lstatSync21(path, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(path).length)
|
|
43382
43565
|
throw new Error(`NATIVE_SKILL_DRIFT: project Sumi plugins require a dedicated discovery review: ${path}`);
|
|
43383
43566
|
}
|
|
43384
43567
|
if (agent === "claude") {
|
|
43385
|
-
const commands =
|
|
43568
|
+
const commands = canonical7(join26(directory, ".claude/commands"));
|
|
43386
43569
|
safe4(commands);
|
|
43387
43570
|
if (lstatSync21(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(commands).length)
|
|
43388
43571
|
throw new Error("NATIVE_SKILL_DRIFT: legacy project command discovery requires a dedicated format adapter");
|
|
@@ -43392,13 +43575,13 @@ function assertProjectDiscovery(agent, directories, home, canonical6 = resolve17
|
|
|
43392
43575
|
function agentDiscoveryConfigPath(home, agent) {
|
|
43393
43576
|
if (agent === "sumi")
|
|
43394
43577
|
return sumiConfigPath(home);
|
|
43395
|
-
return
|
|
43578
|
+
return join26(home, agent === "hermes" ? ".hermes/config.yaml" : agent === "opencode" ? ".config/opencode/opencode.json" : `.${agent}/${agent === "codex" ? "config.toml" : agent === "cursor" ? "hooks.json" : "settings.json"}`);
|
|
43396
43579
|
}
|
|
43397
43580
|
function resolveAgentDiscovery(options) {
|
|
43398
|
-
const
|
|
43581
|
+
const canonical7 = options.canonical ?? resolve17, home = resolve17(options.home), agent = options.agent;
|
|
43399
43582
|
const sources = [], roots = new Set, builtinNames = [];
|
|
43400
|
-
const witness = (path, format, fields2) => {
|
|
43401
|
-
const source = { path:
|
|
43583
|
+
const witness = (path, format, fields2, hashMode) => {
|
|
43584
|
+
const source = { path: canonical7(path), sha256: null, ...format ? { format, fields: fields2 } : {}, ...hashMode ? { hashMode } : {} };
|
|
43402
43585
|
source.sha256 = projected(source);
|
|
43403
43586
|
sources.push(source);
|
|
43404
43587
|
return read2(source.path);
|
|
@@ -43411,31 +43594,34 @@ function resolveAgentDiscovery(options) {
|
|
|
43411
43594
|
const unresolved = (detail) => {
|
|
43412
43595
|
throw new Error(`Native discovery is unresolved (${agent}: ${detail}); provide a reviewed --discovery-inputs file`);
|
|
43413
43596
|
};
|
|
43597
|
+
if (options.reviewed && (options.reviewed.version !== 1 || !Array.isArray(options.reviewed.agents) || options.reviewed.agents.some((item) => !item || typeof item !== "object") || new Set(options.reviewed.agents.map((item) => item.agent)).size !== options.reviewed.agents.length))
|
|
43598
|
+
throw new Error("Invalid --discovery-inputs version or agents");
|
|
43599
|
+
const review = options.reviewed?.agents.find((item) => item.agent === agent);
|
|
43414
43600
|
if (agent === "sumi") {
|
|
43415
43601
|
const directory = sumiConfigDirectory(home);
|
|
43416
|
-
if (witness(
|
|
43602
|
+
if (witness(join26(directory, "sumi.jsonc")) !== null)
|
|
43417
43603
|
unresolved("JSONC configuration requires a supported format adapter");
|
|
43418
|
-
for (const root2 of [directory,
|
|
43604
|
+
for (const root2 of [directory, join26(home, ".claude"), join26(home, ".agents")])
|
|
43419
43605
|
for (const name of ["skill", "skills"])
|
|
43420
|
-
roots.add(
|
|
43606
|
+
roots.add(canonical7(join26(root2, name)));
|
|
43421
43607
|
if (config.skills !== undefined && (!Array.isArray(config.skills) || config.skills.some((path) => typeof path !== "string")))
|
|
43422
43608
|
unresolved("skills must be a string array");
|
|
43423
43609
|
for (const value of config.skills ?? []) {
|
|
43424
43610
|
if (typeof value !== "string" || /[\0$]/.test(value) || !value || !(isAbsolute18(value) || value.startsWith("~/")))
|
|
43425
43611
|
unresolved("remote or relative skill sources need a dedicated discovery adapter");
|
|
43426
|
-
roots.add(
|
|
43612
|
+
roots.add(canonical7(value.startsWith("~/") ? join26(home, value.slice(2)) : value));
|
|
43427
43613
|
}
|
|
43428
43614
|
for (const key of ["plugin", "plugins"])
|
|
43429
43615
|
if (config[key] !== undefined && !Array.isArray(config[key]))
|
|
43430
43616
|
unresolved(`${key} must be an array`);
|
|
43431
|
-
const plugins = [
|
|
43617
|
+
const plugins = [join26(directory, "plugin"), join26(directory, "plugins")];
|
|
43432
43618
|
for (const path of plugins) {
|
|
43433
43619
|
safe4(path);
|
|
43434
43620
|
if (lstatSync21(path, { throwIfNoEntry: false })?.isDirectory())
|
|
43435
43621
|
for (const name of readdirSync7(path).sort()) {
|
|
43436
43622
|
if (name === "skills-cli.js" && path === plugins[1])
|
|
43437
43623
|
continue;
|
|
43438
|
-
const target =
|
|
43624
|
+
const target = join26(path, name);
|
|
43439
43625
|
if (!lstatSync21(target).isFile())
|
|
43440
43626
|
unresolved("local plugin packages need a dedicated discovery adapter");
|
|
43441
43627
|
witness(target);
|
|
@@ -43448,7 +43634,7 @@ function resolveAgentDiscovery(options) {
|
|
|
43448
43634
|
}
|
|
43449
43635
|
}
|
|
43450
43636
|
if (agent === "hermes") {
|
|
43451
|
-
const profile = witness(
|
|
43637
|
+
const profile = witness(join26(home, ".hermes/active_profile"));
|
|
43452
43638
|
if (profile?.trim() && profile.trim() !== "default")
|
|
43453
43639
|
unresolved("a non-default profile is active");
|
|
43454
43640
|
const declared = config.skills?.external_dirs ?? [], paths = typeof declared === "string" ? [declared] : declared;
|
|
@@ -43462,7 +43648,7 @@ function resolveAgentDiscovery(options) {
|
|
|
43462
43648
|
continue;
|
|
43463
43649
|
if (normalized.startsWith("~") && normalized !== "~" && !normalized.startsWith("~/"))
|
|
43464
43650
|
unresolved("user-specific tilde expansion requires a separate discovery adapter");
|
|
43465
|
-
const path = normalized === "~" ? home : normalized.startsWith("~/") ?
|
|
43651
|
+
const path = normalized === "~" ? home : normalized.startsWith("~/") ? join26(home, normalized.slice(2)) : resolve17(home, ".hermes", normalized);
|
|
43466
43652
|
safe4(path);
|
|
43467
43653
|
roots.add(path);
|
|
43468
43654
|
}
|
|
@@ -43472,7 +43658,7 @@ function resolveAgentDiscovery(options) {
|
|
|
43472
43658
|
if (executable2) {
|
|
43473
43659
|
let packageRoot;
|
|
43474
43660
|
for (let directory = dirname16(realpathSync9(executable2)), depth = 0;depth < 8; directory = dirname16(directory), depth++) {
|
|
43475
|
-
const path =
|
|
43661
|
+
const path = join26(directory, "package.json"), raw = read2(path);
|
|
43476
43662
|
if (raw !== null && parseConfig(raw, path).name === "@google/gemini-cli") {
|
|
43477
43663
|
packageRoot = directory;
|
|
43478
43664
|
witness(path);
|
|
@@ -43483,12 +43669,12 @@ function resolveAgentDiscovery(options) {
|
|
|
43483
43669
|
}
|
|
43484
43670
|
if (!packageRoot)
|
|
43485
43671
|
unresolved("installed Gemini package layout is not recognized");
|
|
43486
|
-
const builtinRoot =
|
|
43672
|
+
const builtinRoot = join26(packageRoot, "bundle/builtin");
|
|
43487
43673
|
safe4(builtinRoot);
|
|
43488
43674
|
if (!lstatSync21(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
|
|
43489
43675
|
unresolved("installed Gemini builtin root is missing");
|
|
43490
43676
|
for (const name of readdirSync7(builtinRoot).sort()) {
|
|
43491
|
-
const text2 = witness(
|
|
43677
|
+
const text2 = witness(join26(builtinRoot, name, "SKILL.md"));
|
|
43492
43678
|
const match = text2?.match(/^---\r?\n[\s\S]*?^name:\s*([a-z0-9][a-z0-9-]*)\s*$/m);
|
|
43493
43679
|
if (!match?.[1] || builtinNames.includes(match[1]))
|
|
43494
43680
|
unresolved("installed Gemini builtin name is missing or ambiguous");
|
|
@@ -43501,18 +43687,15 @@ function resolveAgentDiscovery(options) {
|
|
|
43501
43687
|
if (retained.agent !== agent || retained.method !== "reviewed")
|
|
43502
43688
|
unresolved("invalid retained review");
|
|
43503
43689
|
verifyAgentDiscovery(retained);
|
|
43504
|
-
if (!retained.sources.some((source) => source.path ===
|
|
43690
|
+
if (!retained.sources.some((source) => source.path === canonical7(configPath) && source.format === undefined && source.fields === undefined))
|
|
43505
43691
|
unresolved("retained review is missing the full agent configuration source");
|
|
43506
|
-
if (retained.sources.some((source) => (source.hashMode === "sumi-settings-v1" || source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !==
|
|
43692
|
+
if (retained.sources.some((source) => (source.hashMode === "sumi-settings-v1" || source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !== canonical7(configPath)))
|
|
43507
43693
|
unresolved("retained settings witness names another configuration source");
|
|
43508
|
-
const covered = supersedesSettingsProjection(agent, retained.sources,
|
|
43694
|
+
const covered = supersedesSettingsProjection(agent, retained.sources, canonical7(configPath)) ? sources.filter((source) => !isSupersededSettingsProjection(agent, canonical7(configPath), source)) : sources;
|
|
43509
43695
|
if (covered.some((source) => !retained.sources.some((saved) => isDeepStrictEqual6(saved, source))) || [...roots].some((root2) => !retained.roots.includes(root2)) || agent === "gemini" && JSON.stringify(retained.builtinNames) !== JSON.stringify(builtinNames))
|
|
43510
43696
|
unresolved("retained review is missing current runtime discovery coverage");
|
|
43511
43697
|
return retained;
|
|
43512
43698
|
}
|
|
43513
|
-
if (options.reviewed && (options.reviewed.version !== 1 || !Array.isArray(options.reviewed.agents) || options.reviewed.agents.some((item) => !item || typeof item !== "object") || new Set(options.reviewed.agents.map((item) => item.agent)).size !== options.reviewed.agents.length))
|
|
43514
|
-
throw new Error("Invalid --discovery-inputs version or agents");
|
|
43515
|
-
const review = options.reviewed?.agents.find((item) => item.agent === agent);
|
|
43516
43699
|
if (review) {
|
|
43517
43700
|
if (review.pluginHooks !== "reviewed-no-skill-injection" || !Array.isArray(review.sources) || !review.sources.length || !Array.isArray(review.roots))
|
|
43518
43701
|
throw new Error("Discovery review must bind sources and confirm plugin hooks do not inject retired skills");
|
|
@@ -43520,47 +43703,77 @@ function resolveAgentDiscovery(options) {
|
|
|
43520
43703
|
if (review.sources.some((source) => source.format !== undefined || source.fields !== undefined))
|
|
43521
43704
|
throw new Error("Explicit discovery reviews require full source-file hashes");
|
|
43522
43705
|
verifyAgentDiscovery(supplied);
|
|
43523
|
-
if (review.sources.some((source) => (source.hashMode === "sumi-settings-v1" || source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !==
|
|
43706
|
+
if (review.sources.some((source) => (source.hashMode === "sumi-settings-v1" || source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !== canonical7(configPath)))
|
|
43524
43707
|
throw new Error("Semantic settings witnesses must name the configured agent configuration source");
|
|
43525
|
-
if (!review.sources.some((source) => source.path ===
|
|
43708
|
+
if (!review.sources.some((source) => source.path === canonical7(configPath)))
|
|
43526
43709
|
throw new Error("Discovery review must include the agent configuration source");
|
|
43527
|
-
const reviewedSources = supersedesSettingsProjection(agent, review.sources,
|
|
43528
|
-
|
|
43710
|
+
const reviewedSources = supersedesSettingsProjection(agent, review.sources, canonical7(configPath)) ? sources.filter((source) => !isSupersededSettingsProjection(agent, canonical7(configPath), source)) : sources;
|
|
43711
|
+
const reviewedSourcesWithManifestProjection = review.sources.map((source) => {
|
|
43712
|
+
if (agent !== "claude" || source.sha256 === null || source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || source.hashMode !== undefined && source.hashMode !== "bytes" || basename8(source.path) !== "plugin.json" || !source.path.endsWith(join26(sep6, ".claude-plugin", "plugin.json")))
|
|
43713
|
+
return source;
|
|
43714
|
+
const pluginRoot = dirname16(dirname16(source.path)), hooksPath = join26(pluginRoot, "hooks/hooks.json");
|
|
43715
|
+
const hookStat = lstatSync21(hooksPath, { throwIfNoEntry: false });
|
|
43716
|
+
const text2 = read2(source.path);
|
|
43717
|
+
if (text2 === null)
|
|
43718
|
+
throw new Error("Reviewed Claude plugin manifest is missing");
|
|
43719
|
+
const manifestSha256 = projectReviewedClaudePluginManifest(text2, source.sha256 ?? "");
|
|
43720
|
+
const manifest = JSON.parse(text2);
|
|
43721
|
+
if (!manifest || typeof manifest !== "object" || Array.isArray(manifest))
|
|
43722
|
+
throw new Error("Reviewed Claude plugin manifest must be an object");
|
|
43723
|
+
const reviewedHookPaths = new Set;
|
|
43724
|
+
if (hookStat)
|
|
43725
|
+
reviewedHookPaths.add(hooksPath);
|
|
43726
|
+
if (manifest.hooks !== undefined) {
|
|
43727
|
+
if (typeof manifest.hooks !== "string")
|
|
43728
|
+
throw new Error("Reviewed Claude plugin manifest has an unsupported hooks target");
|
|
43729
|
+
const declaredHookPath = resolve17(pluginRoot, manifest.hooks);
|
|
43730
|
+
if (!declaredHookPath.startsWith(pluginRoot + sep6))
|
|
43731
|
+
throw new Error("Reviewed Claude plugin hooks target escapes its root");
|
|
43732
|
+
reviewedHookPaths.add(declaredHookPath);
|
|
43733
|
+
}
|
|
43734
|
+
for (const hooksFile of reviewedHookPaths)
|
|
43735
|
+
if (!review.sources.some((hook) => hook.path === canonical7(hooksFile) && hook.sha256 !== null && hook.format === undefined && hook.fields === undefined && hook.managedPlugins === undefined && (hook.hashMode === undefined || hook.hashMode === "bytes")))
|
|
43736
|
+
throw new Error("Reviewed Claude plugin manifest requires separately reviewed exact hook file sources");
|
|
43737
|
+
return { path: source.path, sha256: manifestSha256, hashMode: "claude-plugin-manifest-v1" };
|
|
43738
|
+
});
|
|
43739
|
+
const combined = [...reviewedSources, ...reviewedSourcesWithManifestProjection];
|
|
43740
|
+
const unique = combined.filter((source, index) => combined.findIndex((candidate2) => isDeepStrictEqual6(candidate2, source)) === index);
|
|
43741
|
+
return { ...supplied, roots: [...new Set([...roots, ...supplied.roots])].sort(), sources: unique, ...agent === "gemini" ? { builtinNames } : {} };
|
|
43529
43742
|
}
|
|
43530
43743
|
function plugin(root2) {
|
|
43531
|
-
root2 =
|
|
43744
|
+
root2 = canonical7(root2);
|
|
43532
43745
|
safe4(root2);
|
|
43533
|
-
const manifestPath =
|
|
43534
|
-
const raw = witness(manifestPath);
|
|
43746
|
+
const manifestPath = join26(root2, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
|
|
43747
|
+
const raw = witness(manifestPath, undefined, undefined, agent === "claude" ? "claude-plugin-manifest-v1" : undefined);
|
|
43535
43748
|
if (raw === null)
|
|
43536
43749
|
unresolved("plugin manifest missing");
|
|
43537
43750
|
const manifest = parseConfig(raw, manifestPath);
|
|
43538
|
-
const hooks = witness(
|
|
43751
|
+
const hooks = witness(join26(root2, "hooks/hooks.json"));
|
|
43539
43752
|
if (manifest.hooks !== undefined || hooks !== null)
|
|
43540
43753
|
unresolved("plugin hooks require a separate no-skill-injection review");
|
|
43541
|
-
const commands =
|
|
43754
|
+
const commands = join26(root2, "commands");
|
|
43542
43755
|
safe4(commands);
|
|
43543
43756
|
if (agent === "claude" && (manifest.commands !== undefined || lstatSync21(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(commands).length))
|
|
43544
43757
|
unresolved("legacy command discovery requires retirement or a dedicated format adapter");
|
|
43545
|
-
const rootSkill = witness(
|
|
43758
|
+
const rootSkill = witness(join26(root2, "SKILL.md"));
|
|
43546
43759
|
if (rootSkill !== null)
|
|
43547
43760
|
roots.add(root2);
|
|
43548
43761
|
const declared = manifest.skills === undefined ? ["./skills"] : typeof manifest.skills === "string" ? [manifest.skills] : manifest.skills;
|
|
43549
43762
|
if (!Array.isArray(declared) || declared.some((path) => typeof path !== "string"))
|
|
43550
43763
|
unresolved("unsupported plugin skill paths");
|
|
43551
43764
|
if (agent === "claude")
|
|
43552
|
-
roots.add(
|
|
43765
|
+
roots.add(join26(root2, "skills"));
|
|
43553
43766
|
for (const value of declared) {
|
|
43554
43767
|
const path = resolve17(root2, value);
|
|
43555
|
-
if (path !== root2 && !path.startsWith(root2 +
|
|
43768
|
+
if (path !== root2 && !path.startsWith(root2 + sep6))
|
|
43556
43769
|
unresolved("plugin skill path escapes its root");
|
|
43557
|
-
roots.add(path.endsWith(`${
|
|
43770
|
+
roots.add(path.endsWith(`${sep6}SKILL.md`) ? dirname16(path) : path);
|
|
43558
43771
|
}
|
|
43559
43772
|
}
|
|
43560
43773
|
if (agent === "claude") {
|
|
43561
|
-
const registrations = witness(
|
|
43562
|
-
const installed = registrations === null ? {} : parseConfig(registrations,
|
|
43563
|
-
const commands =
|
|
43774
|
+
const registrations = witness(join26(home, ".claude/plugins/installed_plugins.json"));
|
|
43775
|
+
const installed = registrations === null ? {} : parseConfig(registrations, join26(home, ".claude/plugins/installed_plugins.json")).plugins;
|
|
43776
|
+
const commands = canonical7(join26(home, ".claude/commands"));
|
|
43564
43777
|
safe4(commands);
|
|
43565
43778
|
if (lstatSync21(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(commands).length)
|
|
43566
43779
|
unresolved("legacy home command discovery requires a dedicated format adapter");
|
|
@@ -43584,16 +43797,16 @@ function resolveAgentDiscovery(options) {
|
|
|
43584
43797
|
const market = config.marketplaces?.[marketplace] ?? (marketplace === "personal" ? { source_type: "local", source: home } : undefined);
|
|
43585
43798
|
if (split < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !isAbsolute18(market.source))
|
|
43586
43799
|
unresolved("enabled plugin marketplace is not an explicit local source");
|
|
43587
|
-
const catalogText = witness(
|
|
43800
|
+
const catalogText = witness(join26(market.source, ".agents/plugins/marketplace.json"));
|
|
43588
43801
|
if (catalogText === null)
|
|
43589
43802
|
unresolved("marketplace catalog missing");
|
|
43590
|
-
const catalog = parseConfig(catalogText,
|
|
43803
|
+
const catalog = parseConfig(catalogText, join26(market.source, ".agents/plugins/marketplace.json")), matches = Array.isArray(catalog.plugins) ? catalog.plugins.filter((item) => item.name === name) : [];
|
|
43591
43804
|
if (matches.length !== 1 || matches[0]?.source?.source !== "local" || typeof matches[0]?.source?.path !== "string")
|
|
43592
43805
|
unresolved("plugin catalog source is missing or ambiguous");
|
|
43593
43806
|
plugin(resolve17(market.source, matches[0].source.path));
|
|
43594
43807
|
}
|
|
43595
43808
|
} else if (agent === "opencode") {
|
|
43596
|
-
if (witness(
|
|
43809
|
+
if (witness(join26(home, ".config/opencode/opencode.jsonc")) !== null || witness(join26(home, ".config/opencode/config.json")) !== null)
|
|
43597
43810
|
unresolved("additional config layers require review");
|
|
43598
43811
|
if ((config.plugin?.length ?? 0) > 0 || config.skills?.urls?.length)
|
|
43599
43812
|
unresolved("external plugin or remote skill source");
|
|
@@ -43602,15 +43815,15 @@ function resolveAgentDiscovery(options) {
|
|
|
43602
43815
|
unresolved("relative or malformed added skill root");
|
|
43603
43816
|
roots.add(path);
|
|
43604
43817
|
}
|
|
43605
|
-
const localPlugins =
|
|
43818
|
+
const localPlugins = join26(home, ".config/opencode/plugins");
|
|
43606
43819
|
safe4(localPlugins);
|
|
43607
43820
|
if (lstatSync21(localPlugins, { throwIfNoEntry: false }) && readdirSync7(localPlugins).some((name) => name !== "skills-cli.js"))
|
|
43608
43821
|
unresolved("additional local plugin hooks require review");
|
|
43609
43822
|
} else if (agent === "sumi") {
|
|
43610
|
-
if ((config.plugin?.length ?? 0) > 0 || (config.plugins?.length ?? 0) > 0 || sources.some((source) => source.path !==
|
|
43823
|
+
if ((config.plugin?.length ?? 0) > 0 || (config.plugins?.length ?? 0) > 0 || sources.some((source) => source.path !== canonical7(configPath) && source.path !== canonical7(join26(sumiConfigDirectory(home), "sumi.jsonc")) && source.sha256 !== null))
|
|
43611
43824
|
unresolved("external or foreign local plugins require review");
|
|
43612
43825
|
} else if (agent === "hermes") {
|
|
43613
|
-
for (const directory of [
|
|
43826
|
+
for (const directory of [join26(home, ".hermes/plugins"), join26(home, ".hermes/hermes-agent")]) {
|
|
43614
43827
|
safe4(directory);
|
|
43615
43828
|
if (lstatSync21(directory, { throwIfNoEntry: false }))
|
|
43616
43829
|
unresolved("installed runtime/plugin discovery requires reviewed source bindings");
|
|
@@ -43620,24 +43833,24 @@ function resolveAgentDiscovery(options) {
|
|
|
43620
43833
|
} else if (agent === "gemini") {
|
|
43621
43834
|
if (Object.keys(config.extensions ?? {}).length || config.skills?.paths?.length)
|
|
43622
43835
|
unresolved("custom extension or skill paths");
|
|
43623
|
-
const directory =
|
|
43836
|
+
const directory = join26(home, ".gemini/extensions");
|
|
43624
43837
|
safe4(directory);
|
|
43625
43838
|
if (lstatSync21(directory, { throwIfNoEntry: false }))
|
|
43626
43839
|
for (const name of readdirSync7(directory)) {
|
|
43627
|
-
const root2 =
|
|
43840
|
+
const root2 = join26(directory, name);
|
|
43628
43841
|
safe4(root2);
|
|
43629
43842
|
if (!lstatSync21(root2)?.isDirectory())
|
|
43630
43843
|
continue;
|
|
43631
|
-
const raw = witness(
|
|
43844
|
+
const raw = witness(join26(root2, "gemini-extension.json"));
|
|
43632
43845
|
if (raw === null)
|
|
43633
43846
|
unresolved("extension registration missing");
|
|
43634
|
-
const manifest = parseConfig(raw,
|
|
43635
|
-
if (manifest.hooks !== undefined || witness(
|
|
43847
|
+
const manifest = parseConfig(raw, join26(root2, "gemini-extension.json"));
|
|
43848
|
+
if (manifest.hooks !== undefined || witness(join26(root2, "hooks/hooks.json")) !== null || witness(join26(root2, ".gemini-extension-install.json")) !== null)
|
|
43636
43849
|
unresolved("extension hooks or linked registration require review");
|
|
43637
|
-
roots.add(
|
|
43850
|
+
roots.add(join26(root2, "skills"));
|
|
43638
43851
|
}
|
|
43639
43852
|
}
|
|
43640
|
-
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([
|
|
43853
|
+
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join26(home, ".hermes/plugins"), join26(home, ".hermes/hermes-agent")].map((path) => canonical7(path))) } : {} };
|
|
43641
43854
|
}
|
|
43642
43855
|
|
|
43643
43856
|
// src/lib/agent-adapters.ts
|
|
@@ -43976,7 +44189,7 @@ function disableCodexBundledSkills(text2) {
|
|
|
43976
44189
|
}
|
|
43977
44190
|
|
|
43978
44191
|
// src/lib/agent-integration.ts
|
|
43979
|
-
var sha4 = (data) =>
|
|
44192
|
+
var sha4 = (data) => createHash23("sha256").update(data).digest("hex");
|
|
43980
44193
|
var ROOTS = NATIVE_SKILL_ROOTS;
|
|
43981
44194
|
function hasTrustedDarwinAcl(fd, allowDenyOnly = false) {
|
|
43982
44195
|
try {
|
|
@@ -44054,7 +44267,7 @@ function isSystemRootAlias(path) {
|
|
|
44054
44267
|
}
|
|
44055
44268
|
}
|
|
44056
44269
|
function canonicalSystemPath(path) {
|
|
44057
|
-
const absolute = resolve18(path), root2 = `/${absolute.split(
|
|
44270
|
+
const absolute = resolve18(path), root2 = `/${absolute.split(sep7)[1]}`;
|
|
44058
44271
|
if (process.platform !== "darwin" || !["/var", "/tmp", "/etc"].includes(root2) || !lstatSync22(root2, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
44059
44272
|
return absolute;
|
|
44060
44273
|
if (!isSystemRootAlias(root2))
|
|
@@ -44074,7 +44287,7 @@ function assertSafePath(path) {
|
|
|
44074
44287
|
}
|
|
44075
44288
|
function readRootAlias(home, agent) {
|
|
44076
44289
|
assertSafePath(home);
|
|
44077
|
-
const realHome = realpathSync10(home), alias =
|
|
44290
|
+
const realHome = realpathSync10(home), alias = join27(realHome, `.${agent}`);
|
|
44078
44291
|
const stat2 = lstatSync22(alias, { throwIfNoEntry: false, bigint: true });
|
|
44079
44292
|
if (!stat2?.isSymbolicLink())
|
|
44080
44293
|
throw new Error(`Agent root alias changed after planning: ${alias}`);
|
|
@@ -44084,7 +44297,7 @@ function readRootAlias(home, agent) {
|
|
|
44084
44297
|
if (!targetStat?.isDirectory())
|
|
44085
44298
|
throw new Error(`Agent root alias must target an existing directory: ${alias}`);
|
|
44086
44299
|
const target = realpathSync10(targetPath), inside = relative5(realHome, target);
|
|
44087
|
-
if (!inside || inside === ".." || inside.startsWith(`..${
|
|
44300
|
+
if (!inside || inside === ".." || inside.startsWith(`..${sep7}`) || isAbsolute19(inside))
|
|
44088
44301
|
throw new Error(`Agent root alias target must be inside the real home: ${alias}`);
|
|
44089
44302
|
return { agent, home: realHome, alias, target, link, aliasIdentity: `${stat2.dev}:${stat2.ino}:${stat2.ctimeNs}`, targetIdentity: `${targetStat.dev}:${targetStat.ino}` };
|
|
44090
44303
|
}
|
|
@@ -44093,15 +44306,15 @@ function rootAliases(home, allowed = false) {
|
|
|
44093
44306
|
return [];
|
|
44094
44307
|
const result = [];
|
|
44095
44308
|
for (const agent of ["claude", "codex"])
|
|
44096
|
-
if (lstatSync22(
|
|
44309
|
+
if (lstatSync22(join27(home, `.${agent}`), { throwIfNoEntry: false })?.isSymbolicLink())
|
|
44097
44310
|
result.push(readRootAlias(home, agent));
|
|
44098
|
-
if (result.some((item, index) => result.slice(index + 1).some((other) => item.target === other.target || item.target.startsWith(other.target +
|
|
44311
|
+
if (result.some((item, index) => result.slice(index + 1).some((other) => item.target === other.target || item.target.startsWith(other.target + sep7) || other.target.startsWith(item.target + sep7))))
|
|
44099
44312
|
throw new Error("Agent root alias targets must not overlap");
|
|
44100
44313
|
return result;
|
|
44101
44314
|
}
|
|
44102
44315
|
function canonicalAgentPath(path, aliases) {
|
|
44103
|
-
const absolute = canonicalSystemPath(path), binding = aliases.find((item) => absolute === item.alias || absolute.startsWith(item.alias +
|
|
44104
|
-
return binding ?
|
|
44316
|
+
const absolute = canonicalSystemPath(path), binding = aliases.find((item) => absolute === item.alias || absolute.startsWith(item.alias + sep7));
|
|
44317
|
+
return binding ? join27(binding.target, relative5(binding.alias, absolute)) : absolute;
|
|
44105
44318
|
}
|
|
44106
44319
|
function disabledCodexSkillPaths(config, aliases) {
|
|
44107
44320
|
const skills = config.skills;
|
|
@@ -44124,7 +44337,7 @@ function disabledCodexSkillPaths(config, aliases) {
|
|
|
44124
44337
|
} catch {
|
|
44125
44338
|
continue;
|
|
44126
44339
|
}
|
|
44127
|
-
if (!document2.endsWith(`${
|
|
44340
|
+
if (!document2.endsWith(`${sep7}SKILL.md`))
|
|
44128
44341
|
continue;
|
|
44129
44342
|
settings.set(document2, [...settings.get(document2) ?? [], entry.enabled === false]);
|
|
44130
44343
|
}
|
|
@@ -44132,7 +44345,7 @@ function disabledCodexSkillPaths(config, aliases) {
|
|
|
44132
44345
|
}
|
|
44133
44346
|
function recheckRootAliases(aliases) {
|
|
44134
44347
|
for (const binding of aliases) {
|
|
44135
|
-
if (!["claude", "codex"].includes(binding.agent) || binding.alias !==
|
|
44348
|
+
if (!["claude", "codex"].includes(binding.agent) || binding.alias !== join27(binding.home, `.${binding.agent}`))
|
|
44136
44349
|
throw new Error("Invalid agent root alias binding");
|
|
44137
44350
|
const current = readRootAlias(binding.home, binding.agent);
|
|
44138
44351
|
if (JSON.stringify(current) !== JSON.stringify(binding))
|
|
@@ -44170,7 +44383,7 @@ function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
|
|
|
44170
44383
|
}
|
|
44171
44384
|
}
|
|
44172
44385
|
function treeHash(root2) {
|
|
44173
|
-
const hash2 =
|
|
44386
|
+
const hash2 = createHash23("sha256");
|
|
44174
44387
|
let bytes = 0, files = 0;
|
|
44175
44388
|
function visit2(path) {
|
|
44176
44389
|
const stat2 = lstatSync22(path);
|
|
@@ -44180,7 +44393,7 @@ function treeHash(root2) {
|
|
|
44180
44393
|
if (stat2.isDirectory()) {
|
|
44181
44394
|
hash2.update(`d\x00${rel}\x00`);
|
|
44182
44395
|
for (const name of readdirSync8(path).sort())
|
|
44183
|
-
visit2(
|
|
44396
|
+
visit2(join27(path, name));
|
|
44184
44397
|
return;
|
|
44185
44398
|
}
|
|
44186
44399
|
if (!stat2.isFile())
|
|
@@ -44208,7 +44421,7 @@ function selectNativeMigrationTargets(inventory, manifest) {
|
|
|
44208
44421
|
if (!existsSync7(projectRoot) || !lstatSync22(projectRoot).isDirectory())
|
|
44209
44422
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
44210
44423
|
assertSafePath(projectRoot);
|
|
44211
|
-
if (isAbsolute19(target.path) || target.path.includes("\\") || target.path.includes("\x00") || !normalized || normalized === ".." || normalized.startsWith(`..${
|
|
44424
|
+
if (isAbsolute19(target.path) || target.path.includes("\\") || target.path.includes("\x00") || !normalized || normalized === ".." || normalized.startsWith(`..${sep7}`) || normalized !== target.path || !/^[0-9a-f]{64}$/.test(target.treeSha256))
|
|
44212
44425
|
throw new Error(`Invalid native migration target: ${target.path}`);
|
|
44213
44426
|
const identity5 = `${target.agent}\x00${canonicalSystemPath(projectRoot)}\x00${normalized}`;
|
|
44214
44427
|
if (identities.has(identity5))
|
|
@@ -44244,7 +44457,7 @@ function projectAncestorDirectories(projects) {
|
|
|
44244
44457
|
}
|
|
44245
44458
|
function isCodexSkillDiscoveryInput(path) {
|
|
44246
44459
|
for (let cursor = canonicalSystemPath(path);cursor !== dirname17(cursor); cursor = dirname17(cursor)) {
|
|
44247
|
-
if (ROOTS.some(([agent, root2]) => agent === "codex" && cursor.endsWith(
|
|
44460
|
+
if (ROOTS.some(([agent, root2]) => agent === "codex" && cursor.endsWith(join27(sep7, root2))))
|
|
44248
44461
|
return true;
|
|
44249
44462
|
}
|
|
44250
44463
|
return false;
|
|
@@ -44261,18 +44474,18 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
44261
44474
|
const selectedAgents = options.agents ? new Set(options.agents) : undefined;
|
|
44262
44475
|
const includesAgent = (agent) => !selectedAgents || selectedAgents.has(agent);
|
|
44263
44476
|
const rootDefinitions = selectedAgents ? ROOTS.filter(([agent, path]) => selectedAgents.has(agent) || selectedAgents.has("hermes") && agent === "codex" && path === ".agents/skills") : ROOTS;
|
|
44264
|
-
const roots = rootDefinitions.map(([agent, path]) => [agent, canonicalAgentPath(
|
|
44265
|
-
const bridgePaths = Object.entries(AGENT_ADAPTERS).filter(([agent]) => agent !== "sumi" || includesAgent("sumi")).map(([agent, adapter]) => canonicalAgentPath(
|
|
44477
|
+
const roots = rootDefinitions.map(([agent, path]) => [agent, canonicalAgentPath(join27(home, path), aliases)]);
|
|
44478
|
+
const bridgePaths = Object.entries(AGENT_ADAPTERS).filter(([agent]) => agent !== "sumi" || includesAgent("sumi")).map(([agent, adapter]) => canonicalAgentPath(join27(agent === "sumi" ? sumiBridgeRoot(home) : join27(home, adapter.root), CLI_BRIDGE_NAME), aliases));
|
|
44266
44479
|
for (const project of projectAncestorDirectories([...options.projectDirs ?? [], ...options.projectDir ? [options.projectDir] : []])) {
|
|
44267
44480
|
for (const [agent, path] of rootDefinitions)
|
|
44268
|
-
roots.push([agent, canonicalAgentPath(
|
|
44481
|
+
roots.push([agent, canonicalAgentPath(join27(project, path), aliases)]);
|
|
44269
44482
|
if (selectedAgents?.has("sumi"))
|
|
44270
44483
|
for (const directory of [".claude", ".agents"])
|
|
44271
44484
|
for (const name of ["skill", "skills"])
|
|
44272
|
-
roots.push(["sumi", canonicalAgentPath(
|
|
44485
|
+
roots.push(["sumi", canonicalAgentPath(join27(project, directory, name), aliases)]);
|
|
44273
44486
|
}
|
|
44274
44487
|
const installationInputs = options.codexInstallationInputRoots ?? [];
|
|
44275
|
-
if (installationInputs.some((input) => resolve18(input) !== input || realpathSync10(input) !== input || roots.some(([agent, path]) => agent === "codex" && (path === input || path.startsWith(input +
|
|
44488
|
+
if (installationInputs.some((input) => resolve18(input) !== input || realpathSync10(input) !== input || roots.some(([agent, path]) => agent === "codex" && (path === input || path.startsWith(input + sep7) || input.startsWith(path + sep7)))))
|
|
44276
44489
|
throw new Error("Native installation input overlaps an unconditional skill-loading root");
|
|
44277
44490
|
const entries = [], seen = new Set;
|
|
44278
44491
|
const cacheScans = new Map, maxAliasProofEntries = 1e4;
|
|
@@ -44298,7 +44511,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
44298
44511
|
if (!scan?.complete || scan.entries > maxAliasProofEntries)
|
|
44299
44512
|
return false;
|
|
44300
44513
|
if (scan.hasSkills) {
|
|
44301
|
-
const targetSkills = entries.filter((entry) => entry.agent === agent && entry.vendor && (entry.path === target || entry.path.startsWith(target +
|
|
44514
|
+
const targetSkills = entries.filter((entry) => entry.agent === agent && entry.vendor && (entry.path === target || entry.path.startsWith(target + sep7)));
|
|
44302
44515
|
if (path === reviewedCacheAlias && targetSkills.length > 0)
|
|
44303
44516
|
reviewedCacheAliasFound = true;
|
|
44304
44517
|
if (agent === "codex" && targetSkills.length > 0 && targetSkills.every((entry) => disabledVendorPaths.has(entry.path) || options.disabledVendorSkill?.(entry) === true))
|
|
@@ -44313,7 +44526,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
44313
44526
|
admit(path);
|
|
44314
44527
|
const scan = { complete: true, hasSkills: false, entries: 1 };
|
|
44315
44528
|
assertSafePath(path);
|
|
44316
|
-
if (configuredRoot && agent === "codex" && installationInputs.some((root2) => path === root2 || path.startsWith(`${root2}${
|
|
44529
|
+
if (configuredRoot && agent === "codex" && installationInputs.some((root2) => path === root2 || path.startsWith(`${root2}${sep7}`)))
|
|
44317
44530
|
return scan;
|
|
44318
44531
|
if (!existsSync7(path))
|
|
44319
44532
|
return scan;
|
|
@@ -44325,21 +44538,21 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
44325
44538
|
}
|
|
44326
44539
|
if (!stat2.isDirectory())
|
|
44327
44540
|
throw new Error(`Unsupported native discovery entry: ${path}`);
|
|
44328
|
-
if (existsSync7(
|
|
44541
|
+
if (existsSync7(join27(path, "SKILL.md"))) {
|
|
44329
44542
|
scan.hasSkills = true;
|
|
44330
44543
|
if (seen.has(path))
|
|
44331
44544
|
return scan;
|
|
44332
44545
|
seen.add(path);
|
|
44333
44546
|
let managed = false;
|
|
44334
|
-
const marker =
|
|
44547
|
+
const marker = join27(path, ".hasna-skills.json");
|
|
44335
44548
|
if (existsSync7(marker)) {
|
|
44336
44549
|
try {
|
|
44337
44550
|
managed = JSON.parse(readFileSync16(marker, "utf8")).managedBy === "@hasna/skills";
|
|
44338
44551
|
} catch {}
|
|
44339
44552
|
}
|
|
44340
44553
|
const bridge = (!vendor || agent === "sumi") && isOwnedCliBridge(path, bridgePaths);
|
|
44341
|
-
const rootAlias = aliases.find((item) => path === item.target || path.startsWith(item.target +
|
|
44342
|
-
entries.push({ agent, path, hash: treeHash(path), managed, vendor, ...agent === "codex" || isCodexSkillDiscoveryInput(path) ? { codexHome: process.env.CODEX_HOME ??
|
|
44554
|
+
const rootAlias = aliases.find((item) => path === item.target || path.startsWith(item.target + sep7));
|
|
44555
|
+
entries.push({ agent, path, hash: treeHash(path), managed, vendor, ...agent === "codex" || isCodexSkillDiscoveryInput(path) ? { codexHome: process.env.CODEX_HOME ?? join27(home, ".codex") } : {}, ...agent === "codex" && path.startsWith(canonicalAgentPath(join27(home, ".codex", "skills", ".system"), aliases) + sep7) ? { system: true } : {}, ...bridge ? { bridge: true, bridgeHome: resolve18(home) } : {}, ...rootAlias ? { rootAlias } : {} });
|
|
44343
44556
|
return scan;
|
|
44344
44557
|
}
|
|
44345
44558
|
if (depth > (agent === "sumi" ? 32 : vendor ? 32 : 3))
|
|
@@ -44348,7 +44561,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
44348
44561
|
try {
|
|
44349
44562
|
let child;
|
|
44350
44563
|
while ((child = directory.readSync()) !== null) {
|
|
44351
|
-
admit(
|
|
44564
|
+
admit(join27(path, child.name));
|
|
44352
44565
|
children.push(child);
|
|
44353
44566
|
}
|
|
44354
44567
|
} finally {
|
|
@@ -44360,12 +44573,12 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
44360
44573
|
for (const { name } of children) {
|
|
44361
44574
|
if (name === "node_modules")
|
|
44362
44575
|
continue;
|
|
44363
|
-
if (name.startsWith(".") && name !== ".system" && agent !== "hermes" && agent !== "sumi" && !(options.guardHermes && `${path}${
|
|
44576
|
+
if (name.startsWith(".") && name !== ".system" && agent !== "hermes" && agent !== "sumi" && !(options.guardHermes && `${path}${sep7}`.includes(`${sep7}.agents${sep7}skills${sep7}`)))
|
|
44364
44577
|
continue;
|
|
44365
44578
|
const isVendor = vendor || name === ".system";
|
|
44366
44579
|
if (isVendor && !options.includeVendor)
|
|
44367
44580
|
continue;
|
|
44368
|
-
const child =
|
|
44581
|
+
const child = join27(path, name);
|
|
44369
44582
|
if (isVendor && lstatSync22(child, { throwIfNoEntry: false })?.isSymbolicLink()) {
|
|
44370
44583
|
const target = statSync7(child, { throwIfNoEntry: false });
|
|
44371
44584
|
if (target?.isFile() || pluginCache && target?.isDirectory() && verifiedSiblingCacheAlias(agent, child, path)) {
|
|
@@ -44383,7 +44596,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
44383
44596
|
return scan;
|
|
44384
44597
|
}
|
|
44385
44598
|
function scanRoot(agent, path, vendor = false, pluginCache = false, configuredRoot = false) {
|
|
44386
|
-
if (agent === "hermes" || options.guardHermes && `${path}${
|
|
44599
|
+
if (agent === "hermes" || options.guardHermes && `${path}${sep7}`.includes(`${sep7}.agents${sep7}skills${sep7}`))
|
|
44387
44600
|
assertNoHermesLegacyShadow(path);
|
|
44388
44601
|
if (!visit2(agent, path, vendor, 0, pluginCache, false, configuredRoot).complete)
|
|
44389
44602
|
throw new Error(`Native skill discovery limit exceeded; review this root before continuing: ${path}`);
|
|
@@ -44392,11 +44605,11 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
44392
44605
|
scanRoot(agent, path);
|
|
44393
44606
|
if (options.includeVendor) {
|
|
44394
44607
|
for (const agent of ["codex", "claude"].filter(includesAgent))
|
|
44395
|
-
scanRoot(agent, canonicalAgentPath(
|
|
44608
|
+
scanRoot(agent, canonicalAgentPath(join27(home, `.${agent}`, "plugins", "cache"), aliases), true, true);
|
|
44396
44609
|
if (includesAgent("claude"))
|
|
44397
|
-
scanRoot("claude", canonicalAgentPath(
|
|
44610
|
+
scanRoot("claude", canonicalAgentPath(join27(home, ".claude", "plugins", "synced"), aliases), true);
|
|
44398
44611
|
if (includesAgent("gemini"))
|
|
44399
|
-
scanRoot("gemini",
|
|
44612
|
+
scanRoot("gemini", join27(home, ".gemini", "extensions"), true);
|
|
44400
44613
|
}
|
|
44401
44614
|
const configured = options.configured ? INTEGRATION_AGENTS.filter(includesAgent).flatMap((agent) => resolveAgentDiscovery({ home, agent, reviewed: options.discoveryInputs, canonical: (path) => canonicalAgentPath(path, aliases) }).roots.map((path) => ({ agent, path }))) : [];
|
|
44402
44615
|
for (const root2 of [...options.agentRoots ?? [], ...configured])
|
|
@@ -44509,14 +44722,14 @@ function configureHooks(config, agent, command, profileId, nativeReady) {
|
|
|
44509
44722
|
function disableCodexSkills(text2, skills, aliases, bridgePath) {
|
|
44510
44723
|
const bundled = disableCodexBundledSkills(text2);
|
|
44511
44724
|
let result = normalizeCodexInlinePathConfig(bundled);
|
|
44512
|
-
const bridgeSelector = (entry) => typeof entry.name === "string" && entry.name.trim() === CLI_BRIDGE_NAME || typeof entry.path === "string" && [resolve18(bridgePath), resolve18(
|
|
44725
|
+
const bridgeSelector = (entry) => typeof entry.name === "string" && entry.name.trim() === CLI_BRIDGE_NAME || typeof entry.path === "string" && [resolve18(bridgePath), resolve18(join27(bridgePath, "SKILL.md"))].includes(canonicalAgentPath(entry.path, aliases));
|
|
44513
44726
|
const previousConfig = Bun.TOML.parse(bundled).skills?.config;
|
|
44514
44727
|
if (previousConfig !== undefined && (!Array.isArray(previousConfig) || previousConfig.some((entry) => !entry || typeof entry !== "object" || entry.path !== undefined && entry.name !== undefined)))
|
|
44515
44728
|
throw new Error("Codex skill controls require one path or name selector per [[skills.config]] entry; review ambiguous entries before running skills hook install");
|
|
44516
44729
|
const bridgeNeedsRepair = previousConfig?.some((entry) => entry.enabled === false && bridgeSelector(entry));
|
|
44517
44730
|
const selections = [...skills.filter((entry) => entry.agent === "codex" && !entry.bridge).map((skill) => ({ path: skill.path, enabled: false })), { path: bridgePath, enabled: true }];
|
|
44518
44731
|
for (const skill of selections) {
|
|
44519
|
-
const path =
|
|
44732
|
+
const path = join27(skill.path, "SKILL.md");
|
|
44520
44733
|
let found = false;
|
|
44521
44734
|
result = result.replace(CODEX_SKILL_CONFIG_SECTIONS, (section) => {
|
|
44522
44735
|
const parsed = Bun.TOML.parse(section);
|
|
@@ -44543,7 +44756,7 @@ enabled = false
|
|
|
44543
44756
|
}
|
|
44544
44757
|
function assertCodexInstallationInputs(home, projectDirs, inputs) {
|
|
44545
44758
|
const nativeRoots = [home, ...projectAncestorDirectories(projectDirs)].flatMap((directory) => ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => resolve18(directory, path)));
|
|
44546
|
-
if (inputs.some((input) => nativeRoots.some((root2) => root2 === input || root2.startsWith(input +
|
|
44759
|
+
if (inputs.some((input) => nativeRoots.some((root2) => root2 === input || root2.startsWith(input + sep7) || input.startsWith(root2 + sep7))))
|
|
44547
44760
|
throw new Error("Native installation input overlaps an unconditional skill-loading root");
|
|
44548
44761
|
}
|
|
44549
44762
|
function planAgentIntegration(options) {
|
|
@@ -44551,7 +44764,7 @@ function planAgentIntegration(options) {
|
|
|
44551
44764
|
throw new Error("Explicit Codex skill denials require a fresh native catalog and discovery review");
|
|
44552
44765
|
const home = options.home ?? homedir3(), dataDir2 = options.dataDir ?? getDataDirReadOnly();
|
|
44553
44766
|
const aliases = rootAliases(home, options.allowRootAliases);
|
|
44554
|
-
const policyPath =
|
|
44767
|
+
const policyPath = join27(dataDir2, "agent-policy.json");
|
|
44555
44768
|
assertSafePath(policyPath);
|
|
44556
44769
|
const priorSnapshot = readManagedSkillPolicySnapshot(dataDir2), previousPolicy = priorSnapshot?.text ?? null, policy = priorSnapshot?.value ?? {};
|
|
44557
44770
|
if (policy.bridge !== undefined && (!policy.bridge || typeof policy.bridge !== "object" || Array.isArray(policy.bridge)))
|
|
@@ -44583,28 +44796,28 @@ function planAgentIntegration(options) {
|
|
|
44583
44796
|
}
|
|
44584
44797
|
return resolveAgentDiscovery({ home, agent, reviewed: options.discoveryInputs, retainedReview, canonical: (path) => canonicalAgentPath(path, aliases) });
|
|
44585
44798
|
});
|
|
44586
|
-
const codexConfigBefore = options.agents.includes("codex") ? readOptional(canonicalAgentPath(
|
|
44799
|
+
const codexConfigBefore = options.agents.includes("codex") ? readOptional(canonicalAgentPath(join27(home, ".codex", "config.toml"), aliases)) : null;
|
|
44587
44800
|
const codexConfig = Bun.TOML.parse(codexConfigBefore ?? "");
|
|
44588
44801
|
const nativeSkills = inventoryNativeSkills(home, { includeVendor: true, guardHermes: options.agents.includes("hermes"), agents: options.agents, projectDir: options.projectDir, agentRoots: discoveries.flatMap((binding) => binding.roots.map((path) => ({ agent: binding.agent, path }))), allowRootAliases: options.allowRootAliases, reviewedCacheAlias: options.reviewedCacheAlias, disabledVendorPaths: disabledCodexSkillPaths(codexConfig, aliases) });
|
|
44589
|
-
const codexPathConfig = options.agents.includes("codex") ? disableCodexSkills(codexConfigBefore ?? "", nativeSkills, aliases, canonicalAgentPath(
|
|
44802
|
+
const codexPathConfig = options.agents.includes("codex") ? disableCodexSkills(codexConfigBefore ?? "", nativeSkills, aliases, canonicalAgentPath(join27(home, ".codex/skills", CLI_BRIDGE_NAME), aliases)) : undefined;
|
|
44590
44803
|
const plannedCodexRules = codexPathConfig === undefined ? undefined : Bun.TOML.parse(codexPathConfig).skills?.config ?? [];
|
|
44591
44804
|
const observedNativeSources = [];
|
|
44592
|
-
const codexPluginControls = options.codexNativeCatalog ? reviewCodexPluginControls(options.codexNativeCatalog, nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor).map((entry) =>
|
|
44805
|
+
const codexPluginControls = options.codexNativeCatalog ? reviewCodexPluginControls(options.codexNativeCatalog, nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor).map((entry) => join27(entry.path, "SKILL.md")), canonicalAgentPath(join27(home, ".codex/plugins/cache"), aliases), resolve18(options.projectDir ?? home), (path) => {
|
|
44593
44806
|
const bytes = readNativeBytes(path, 1024 * 1024);
|
|
44594
44807
|
observedNativeSources.push({ path, sha256: sha4(bytes) });
|
|
44595
44808
|
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
44596
44809
|
}, codexConfig.skills?.config ?? [], codexConfig.plugins, plannedCodexRules, options.codexSkillDenials) : { skills: policy.bridge?.codexPluginSkills ?? [], inactivePlugins: policy.bridge?.codexInactivePlugins ?? [], sourceInputs: policy.bridge?.discovery?.codex?.codexInstallationInputs?.plugins ?? [] };
|
|
44597
|
-
const cache = canonicalAgentPath(
|
|
44810
|
+
const cache = canonicalAgentPath(join27(home, ".codex/plugins/cache"), aliases);
|
|
44598
44811
|
const retired = (policy.bridge?.codexPluginSkills ?? []).filter((control) => absentDisabledCodexPluginParent(cache, control.pluginParent, policy.bridge.codexPluginSkills, codexConfig.skills?.config ?? []));
|
|
44599
44812
|
for (const denial of options.codexSkillDenials ?? []) {
|
|
44600
44813
|
const control = codexPluginControls.skills.find((item) => item.name === denial.name);
|
|
44601
44814
|
if (!control)
|
|
44602
44815
|
throw new Error("Explicit Codex denial did not resolve a reviewed identity");
|
|
44603
|
-
const root2 =
|
|
44816
|
+
const root2 = join27(control.pluginParent, relative5(control.pluginParent, denial.path).split(sep7)[0]);
|
|
44604
44817
|
const review = options.discoveryInputs.agents.find((item) => item.agent === "codex");
|
|
44605
|
-
for (const path of [
|
|
44818
|
+
for (const path of [join27(root2, ".app.json"), join27(root2, ".mcp.json"), join27(root2, "hooks")])
|
|
44606
44819
|
observedNativeSources.push({ path, sha256: nativeSourceDigest(path) });
|
|
44607
|
-
const files = [
|
|
44820
|
+
const files = [join27(root2, ".codex-plugin/plugin.json"), ...control.appSha256 ? [join27(root2, ".app.json")] : [], ...control.mcpSha256 ? [join27(root2, ".mcp.json")] : []];
|
|
44608
44821
|
for (const path of files)
|
|
44609
44822
|
if (!review?.sources.some((source) => source.path === path && source.format === undefined && source.fields === undefined && [undefined, "bytes"].includes(source.hashMode) && source.sha256 === sha4(readNativeBytes(path, 1024 * 1024))))
|
|
44610
44823
|
throw new Error("Explicit Codex denial requires current full manifest and capability discovery witnesses");
|
|
@@ -44613,12 +44826,12 @@ function planAgentIntegration(options) {
|
|
|
44613
44826
|
for (const discovery of discoveries)
|
|
44614
44827
|
if (discovery.agent === "codex" && discovery.method === "reviewed")
|
|
44615
44828
|
discovery.codexDisabledPluginSkills = codexPluginSkills;
|
|
44616
|
-
if (options.agents.includes("codex") && !options.codexNativeCatalog && codexPluginSkills.length && !reviewedCodexPluginCapabilitiesUnchanged(canonicalAgentPath(
|
|
44829
|
+
if (options.agents.includes("codex") && !options.codexNativeCatalog && codexPluginSkills.length && !reviewedCodexPluginCapabilitiesUnchanged(canonicalAgentPath(join27(home, ".codex/plugins/cache"), aliases), codexPluginSkills, (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024)), codexConfig.skills?.config ?? [])) {
|
|
44617
44830
|
throw new Error("NATIVE_SKILL_DRIFT: reviewed native plugin capability controls changed; provide a fresh native catalog and discovery review");
|
|
44618
44831
|
}
|
|
44619
44832
|
const codexInactivePlugins = codexPluginControls.inactivePlugins;
|
|
44620
44833
|
const codexDiscovery = discoveries.find((binding) => binding.agent === "codex");
|
|
44621
|
-
const codexPluginSourceInputs = codexPluginControls.sourceInputs.filter((input) => codexDiscovery?.method === "reviewed" && codexDiscovery.roots.some((root2) => root2 === input.sourceRoot || root2.startsWith(input.sourceRoot +
|
|
44834
|
+
const codexPluginSourceInputs = codexPluginControls.sourceInputs.filter((input) => codexDiscovery?.method === "reviewed" && codexDiscovery.roots.some((root2) => root2 === input.sourceRoot || root2.startsWith(input.sourceRoot + sep7) || input.sourceRoot.startsWith(root2 + sep7)) && codexDiscovery.sources.some((source) => source.path === join27(input.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined));
|
|
44622
44835
|
assertCodexInstallationInputs(home, [options.projectDir ?? home], codexPluginSourceInputs.map((input) => input.sourceRoot));
|
|
44623
44836
|
const changes = [];
|
|
44624
44837
|
let observedSettings;
|
|
@@ -44627,19 +44840,19 @@ function planAgentIntegration(options) {
|
|
|
44627
44840
|
throw new Error(`Unsupported agent: ${agent}`);
|
|
44628
44841
|
const { command, profileId: profileId2 } = bindings.get(agent);
|
|
44629
44842
|
const adapter = AGENT_ADAPTERS[agent];
|
|
44630
|
-
const bridgePath = canonicalAgentPath(
|
|
44843
|
+
const bridgePath = canonicalAgentPath(join27(agent === "sumi" ? sumiBridgeRoot(home) : join27(home, adapter.root), CLI_BRIDGE_NAME), aliases);
|
|
44631
44844
|
assertSafePath(bridgePath);
|
|
44632
44845
|
if (existsSync7(bridgePath) && !isOwnedCliBridge(bridgePath, [bridgePath]))
|
|
44633
44846
|
throw new Error(`Refusing to overwrite an unrecognized or modified Skills bridge: ${bridgePath}`);
|
|
44634
44847
|
for (const [name, after2] of Object.entries(CLI_BRIDGE_FILES)) {
|
|
44635
|
-
const path2 =
|
|
44848
|
+
const path2 = join27(bridgePath, name), before2 = readOptional(path2);
|
|
44636
44849
|
if (before2 !== after2)
|
|
44637
44850
|
changes.push({ path: path2, before: before2, after: after2 });
|
|
44638
44851
|
}
|
|
44639
|
-
const path = canonicalAgentPath(agent === "sumi" ? sumiConfigPath(home) :
|
|
44852
|
+
const path = canonicalAgentPath(agent === "sumi" ? sumiConfigPath(home) : join27(home, adapter.config), aliases);
|
|
44640
44853
|
const before = readOptional(path);
|
|
44641
44854
|
if (agent === "hermes") {
|
|
44642
|
-
const supervisorPath =
|
|
44855
|
+
const supervisorPath = join27(dataDir2, "agent-hooks", "hermes.js"), supervisorBefore = readOptional(supervisorPath), supervisorAfter = renderHermesSupervisor(command, profileId2);
|
|
44643
44856
|
const priorCommand = policy.bridge?.commands?.hermes, priorProfile = policy.bridge?.profiles?.hermes ?? policy.profileId;
|
|
44644
44857
|
const previous = policy.bridge?.supervisors?.hermes;
|
|
44645
44858
|
if (supervisorBefore !== null && supervisorBefore !== supervisorAfter && !(previous?.path === supervisorPath && typeof priorCommand === "string" && typeof priorProfile === "string" && supervisorBefore === renderHermesSupervisor(priorCommand, priorProfile)))
|
|
@@ -44650,7 +44863,7 @@ function planAgentIntegration(options) {
|
|
|
44650
44863
|
const after2 = configureHermesHooks(before, supervisor, previous);
|
|
44651
44864
|
if (before !== after2)
|
|
44652
44865
|
changes.push({ path, before, after: after2 });
|
|
44653
|
-
const optOut =
|
|
44866
|
+
const optOut = join27(home, ".hermes", HERMES_OPT_OUT), optOutBefore = readOptional(optOut);
|
|
44654
44867
|
if (optOutBefore === null)
|
|
44655
44868
|
changes.push({ path: optOut, before: null, after: `Managed by @hasna/skills: bundled native skill reseeding is disabled.
|
|
44656
44869
|
` });
|
|
@@ -44661,7 +44874,7 @@ function planAgentIntegration(options) {
|
|
|
44661
44874
|
if (config.permissions !== undefined && (!Array.isArray(config.permissions) || config.permissions.some((rule) => !rule || typeof rule.action !== "string" || typeof rule.resource !== "string" || !["allow", "deny", "ask"].includes(rule.effect))))
|
|
44662
44875
|
throw new Error("Expected Sumi native permission rules");
|
|
44663
44876
|
config.permissions = [...(config.permissions ?? []).filter((rule) => rule.action !== "skill"), ...SUMI_SKILL_PERMISSIONS];
|
|
44664
|
-
const pluginPath =
|
|
44877
|
+
const pluginPath = join27(sumiConfigDirectory(home), "plugins", "skills-cli.js"), pluginBefore = readOptional(pluginPath);
|
|
44665
44878
|
const pluginAfter = renderSumiPlugin(command, profileId2);
|
|
44666
44879
|
const priorCommand = policy.bridge?.commands?.sumi, priorProfile = policy.bridge?.profiles?.sumi ?? policy.profileId;
|
|
44667
44880
|
if (pluginBefore !== null && pluginBefore !== pluginAfter && !(typeof priorCommand === "string" && typeof priorProfile === "string" && isManagedSumiPlugin(pluginBefore, priorCommand, priorProfile)))
|
|
@@ -44673,7 +44886,7 @@ function planAgentIntegration(options) {
|
|
|
44673
44886
|
if (!permission || typeof permission !== "object" || Array.isArray(permission))
|
|
44674
44887
|
throw new Error("Expected OpenCode permission object");
|
|
44675
44888
|
config.permission = { ...permission, skill: { "*": "deny", [CLI_BRIDGE_NAME]: "allow" } };
|
|
44676
|
-
const pluginPath =
|
|
44889
|
+
const pluginPath = join27(home, ".config", "opencode", "plugins", "skills-cli.js"), pluginBefore = readOptional(pluginPath);
|
|
44677
44890
|
const pluginAfter = renderOpenCodePlugin(command, profileId2);
|
|
44678
44891
|
const priorCommand = policy.bridge?.commands?.opencode;
|
|
44679
44892
|
const ownedPrevious = typeof priorCommand === "string" && typeof policy.profileId === "string" && pluginBefore === renderOpenCodePlugin(priorCommand, policy.bridge?.profiles?.opencode ?? policy.profileId);
|
|
@@ -44690,7 +44903,7 @@ function planAgentIntegration(options) {
|
|
|
44690
44903
|
if (before !== after)
|
|
44691
44904
|
changes.push({ path, before, after });
|
|
44692
44905
|
if (agent === "codex") {
|
|
44693
|
-
const configPath = canonicalAgentPath(
|
|
44906
|
+
const configPath = canonicalAgentPath(join27(home, ".codex", "config.toml"), aliases), previous = readOptional(configPath);
|
|
44694
44907
|
if (previous !== codexConfigBefore)
|
|
44695
44908
|
throw new Error(`Configuration changed during planning: ${configPath}`);
|
|
44696
44909
|
const next = disableReviewedCodexPluginNames(codexPathConfig, codexPluginSkills);
|
|
@@ -44702,16 +44915,16 @@ function planAgentIntegration(options) {
|
|
|
44702
44915
|
}
|
|
44703
44916
|
}
|
|
44704
44917
|
}
|
|
44705
|
-
const codexPluginSkillReview = options.codexNativeCatalog ? { version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, catalogSha256: sha4(JSON.stringify({ version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, skills: projectCodexNativeSkillCatalog({ data: [{ cwd: options.codexNativeCatalog.cwd, errors: [], skills: options.codexNativeCatalog.skills }] }, options.codexNativeCatalog.cwd), ...options.codexNativeCatalog.plugins === undefined ? {} : { plugins: projectCodexInstalledPluginEntries(options.codexNativeCatalog.plugins) } })), configSha256: changes.find((change) => change.path === canonicalAgentPath(
|
|
44918
|
+
const codexPluginSkillReview = options.codexNativeCatalog ? { version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, catalogSha256: sha4(JSON.stringify({ version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, skills: projectCodexNativeSkillCatalog({ data: [{ cwd: options.codexNativeCatalog.cwd, errors: [], skills: options.codexNativeCatalog.skills }] }, options.codexNativeCatalog.cwd), ...options.codexNativeCatalog.plugins === undefined ? {} : { plugins: projectCodexInstalledPluginEntries(options.codexNativeCatalog.plugins) } })), configSha256: changes.find((change) => change.path === canonicalAgentPath(join27(home, ".codex/config.toml"), aliases))?.before === null ? null : sha4(readOptional(canonicalAgentPath(join27(home, ".codex/config.toml"), aliases)) ?? "") } : policy.bridge?.codexPluginSkillReview;
|
|
44706
44919
|
const discoveryAfter = discoveries.map((binding) => {
|
|
44707
44920
|
const rebound = rebindAgentDiscovery(binding, new Map(changes.map((change) => [change.path, change.after])));
|
|
44708
44921
|
if (binding.agent !== "codex")
|
|
44709
44922
|
return rebound;
|
|
44710
44923
|
const { codexInstallationInputs: previousInputs, ...current } = rebound;
|
|
44711
44924
|
const inputs = codexPluginSourceInputs.map((input) => input.sourceRoot);
|
|
44712
|
-
const directories = options.codexNativeCatalog || !previousInputs ? captureDiscoveryDirectories((binding.directories ?? []).filter((directory) => inputs.some((root2) => root2.startsWith(directory.path +
|
|
44925
|
+
const directories = options.codexNativeCatalog || !previousInputs ? captureDiscoveryDirectories((binding.directories ?? []).filter((directory) => inputs.some((root2) => root2.startsWith(directory.path + sep7))).map((directory) => directory.path), inputs) : previousInputs.directories;
|
|
44713
44926
|
const installed = codexPluginSourceInputs.length ? { ...current, codexInstallationInputs: { version: "codex-cli 0.160.0", catalogSha256: codexPluginSkillReview.catalogSha256, plugins: codexPluginSourceInputs, ...directories?.length ? { directories } : {} } } : current;
|
|
44714
|
-
return captureRetiredCodexDiscovery(installed, codexPluginSkills, Bun.TOML.parse(changes.find((change) => change.path === canonicalAgentPath(
|
|
44927
|
+
return captureRetiredCodexDiscovery(installed, codexPluginSkills, Bun.TOML.parse(changes.find((change) => change.path === canonicalAgentPath(join27(home, ".codex/config.toml"), aliases))?.after ?? codexConfigBefore ?? "").skills?.config ?? []);
|
|
44715
44928
|
});
|
|
44716
44929
|
const nextPolicy = { ...policy, version: 1, loading: "cli", profileId, bridge: {
|
|
44717
44930
|
...policy.bridge,
|
|
@@ -44720,10 +44933,10 @@ function planAgentIntegration(options) {
|
|
|
44720
44933
|
agents: [...new Set([...priorAgents, ...options.agents])].sort(),
|
|
44721
44934
|
home: resolve18(home),
|
|
44722
44935
|
includeVendor: true,
|
|
44723
|
-
...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path:
|
|
44936
|
+
...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join27(dataDir2, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256: sha4(renderHermesSupervisor(bindings.get("hermes").command, bindings.get("hermes").profileId)) } } } : {},
|
|
44724
44937
|
commands: { ...policy.bridge?.commands, ...Object.fromEntries([...bindings].map(([agent, binding]) => [agent, binding.command])) },
|
|
44725
44938
|
profiles: Object.fromEntries([...new Set([...priorAgents, ...options.agents])].sort().map((agent) => [agent, bindings.get(agent)?.profileId ?? policy.bridge?.profiles?.[agent] ?? policy.profileId])),
|
|
44726
|
-
disabledBuiltins: options.agents.includes("codex") ? nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor && entry.path.startsWith(canonicalAgentPath(
|
|
44939
|
+
disabledBuiltins: options.agents.includes("codex") ? nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor && entry.path.startsWith(canonicalAgentPath(join27(home, ".codex", "skills", ".system"), aliases) + sep7)).map((entry) => ({ path: entry.path, hash: entry.hash })) : policy.bridge?.disabledBuiltins ?? [],
|
|
44727
44940
|
rootAliases: aliases,
|
|
44728
44941
|
...options.codexNativeCatalog || codexPluginSkills.length || codexInactivePlugins.length || codexPluginSourceInputs.length ? { codexPluginSkills, codexInactivePlugins, codexPluginSkillReview } : {},
|
|
44729
44942
|
discovery: { ...policy.bridge?.discovery, ...Object.fromEntries(discoveryAfter.map((binding) => [binding.agent, binding])) }
|
|
@@ -44775,10 +44988,10 @@ function projectedHookExecutable(command, expectedResolved) {
|
|
|
44775
44988
|
if (expectedResolved !== undefined && resolved !== expectedResolved)
|
|
44776
44989
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
44777
44990
|
const resolvedParentIdentity = parents3(resolved);
|
|
44778
|
-
const manifest = snapshot(
|
|
44991
|
+
const manifest = snapshot(join27(dirname17(dirname17(resolved)), "package.json"), false, { readOnlyPackage: true });
|
|
44779
44992
|
projectedHookAcl(manifest.file, manifest.stat);
|
|
44780
44993
|
const pkg = JSON.parse(manifest.text);
|
|
44781
|
-
if (pkg.name !== "@hasna/skills" || !/^\d+\.\d+\.\d+$/.test(pkg.version) || pkg.bin?.skills !== "bin/index.js" || resolved !==
|
|
44994
|
+
if (pkg.name !== "@hasna/skills" || !/^\d+\.\d+\.\d+$/.test(pkg.version) || pkg.bin?.skills !== "bin/index.js" || resolved !== join27(dirname17(manifest.file), "bin/index.js"))
|
|
44782
44995
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
44783
44996
|
const cli = snapshot(resolved, false, { readOnlyPackage: true });
|
|
44784
44997
|
projectedHookAcl(cli.file, cli.stat);
|
|
@@ -44815,7 +45028,7 @@ function planClaudeManagedHookProjection(options) {
|
|
|
44815
45028
|
hookProjectionRefusal("TARGET_INVALID");
|
|
44816
45029
|
}
|
|
44817
45030
|
const home = resolve18(options.home ?? homedir3()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
|
|
44818
|
-
const policyPath =
|
|
45031
|
+
const policyPath = join27(dataDir2, "agent-policy.json");
|
|
44819
45032
|
let policyBytes, settingsBytes, settingsPath, command, profile;
|
|
44820
45033
|
try {
|
|
44821
45034
|
policyBytes = readNativeBytes(policyPath, 1024 * 1024);
|
|
@@ -44823,7 +45036,7 @@ function planClaudeManagedHookProjection(options) {
|
|
|
44823
45036
|
if (!snapshot2 || snapshot2.text !== policyBytes.toString("utf8"))
|
|
44824
45037
|
hookProjectionRefusal("SOURCE_UNVERIFIED");
|
|
44825
45038
|
const binding = snapshot2.value.bridge;
|
|
44826
|
-
settingsPath = canonicalAgentPath(
|
|
45039
|
+
settingsPath = canonicalAgentPath(join27(home, AGENT_ADAPTERS.claude.config), binding?.rootAliases ?? []);
|
|
44827
45040
|
settingsBytes = readNativeBytes(settingsPath, 1024 * 1024);
|
|
44828
45041
|
command = binding?.commands?.claude;
|
|
44829
45042
|
profile = binding?.profiles?.claude;
|
|
@@ -44906,12 +45119,12 @@ function planClaudePreToolUseHookUpdate(options) {
|
|
|
44906
45119
|
return planClaudeHookEventsUpdate({ ...options, events: ["PreToolUse"] });
|
|
44907
45120
|
}
|
|
44908
45121
|
function claudeSettingsConsumers(home, path, discoveries, aliases) {
|
|
44909
|
-
const
|
|
45122
|
+
const canonical7 = (value) => canonicalAgentPath(value, aliases);
|
|
44910
45123
|
const containsSettings = (root2) => {
|
|
44911
|
-
const distance = relative5(
|
|
44912
|
-
return distance === "" || distance !== ".." && !distance.startsWith(`..${
|
|
45124
|
+
const distance = relative5(canonical7(root2), path);
|
|
45125
|
+
return distance === "" || distance !== ".." && !distance.startsWith(`..${sep7}`) && !isAbsolute19(distance);
|
|
44913
45126
|
};
|
|
44914
|
-
return discoveries.filter((binding) => binding.agent === "claude" || binding.agent === "opencode" ||
|
|
45127
|
+
return discoveries.filter((binding) => binding.agent === "claude" || binding.agent === "opencode" || canonical7(join27(home, AGENT_ADAPTERS[binding.agent].config)) === path || binding.sources.some((source) => canonical7(source.path) === path) || binding.roots.some(containsSettings) || binding.directories?.some((directory) => containsSettings(directory.path))).map((binding) => binding.agent);
|
|
44915
45128
|
}
|
|
44916
45129
|
function verifyCoordinatedDiscovery(binding, home, aliases) {
|
|
44917
45130
|
try {
|
|
@@ -44929,7 +45142,7 @@ function verifyCoordinatedDiscovery(binding, home, aliases) {
|
|
|
44929
45142
|
}
|
|
44930
45143
|
function planClaudeHookEventsUpdate(options) {
|
|
44931
45144
|
const home = resolve18(options.home ?? homedir3()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
|
|
44932
|
-
const policyPath =
|
|
45145
|
+
const policyPath = join27(dataDir2, "agent-policy.json");
|
|
44933
45146
|
assertSafePath(policyPath);
|
|
44934
45147
|
const snapshot2 = readManagedSkillPolicySnapshot(dataDir2);
|
|
44935
45148
|
if (!snapshot2)
|
|
@@ -44940,7 +45153,7 @@ function planClaudeHookEventsUpdate(options) {
|
|
|
44940
45153
|
}
|
|
44941
45154
|
const aliases = bridge.rootAliases ?? [];
|
|
44942
45155
|
recheckRootAliases(aliases);
|
|
44943
|
-
const path = canonicalAgentPath(
|
|
45156
|
+
const path = canonicalAgentPath(join27(home, ".claude", "settings.json"), aliases);
|
|
44944
45157
|
assertSafePath(path);
|
|
44945
45158
|
const before = lstatSync22(path, { throwIfNoEntry: false }) ? new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(readNativeBytes(path, 1024 * 1024)) : null;
|
|
44946
45159
|
if ((before === null ? "absent" : sha4(before)) !== options.expectedSettingsSha256)
|
|
@@ -45018,7 +45231,7 @@ function planAgentSettingsWitnessUpgrade(options) {
|
|
|
45018
45231
|
const binding = policy.bridge?.discovery?.[options.agent];
|
|
45019
45232
|
if (!binding || binding.agent !== options.agent || binding.method !== "reviewed")
|
|
45020
45233
|
throw new Error("Settings witness upgrade requires an existing reviewed native binding");
|
|
45021
|
-
const configPath = canonicalAgentPath(options.agent === "sumi" ? sumiConfigPath(home) :
|
|
45234
|
+
const configPath = canonicalAgentPath(options.agent === "sumi" ? sumiConfigPath(home) : join27(home, options.agent === "claude" ? ".claude/settings.json" : ".codex/config.toml"), aliases);
|
|
45022
45235
|
const settings = readOptional(configPath);
|
|
45023
45236
|
if (settings === null || sha4(settings) !== options.expectedSettingsSha256)
|
|
45024
45237
|
throw new Error("Native settings preimage changed");
|
|
@@ -45069,7 +45282,7 @@ function planAgentSettingsWitnessUpgrade(options) {
|
|
|
45069
45282
|
const replacement = { ...binding, sources: rebound };
|
|
45070
45283
|
verifyAgentDiscovery(replacement);
|
|
45071
45284
|
const after = serializeManagedSkillPolicy({ ...policy, bridge: { ...policy.bridge, discovery: { ...policy.bridge.discovery, [options.agent]: replacement } } });
|
|
45072
|
-
return { dataDir: dataDir2, profileId: policy.profileId, changes: [{ path:
|
|
45285
|
+
return { dataDir: dataDir2, profileId: policy.profileId, changes: [{ path: join27(dataDir2, "agent-policy.json"), before: snapshot2.text, after }], nativeSkills: [], observedPolicy: { path: join27(dataDir2, "agent-policy.json"), before: snapshot2.text }, observedSettings: { path: configPath, before: settings }, discoveryBefore: [replacement], discoveryAfter: [replacement], rootAliases: aliases, managedAgentChecks: { home, agents: [options.agent] }, settingsWitnessUpgrade: { agent: options.agent, path: configPath, fromHashMode: previous.hashMode ?? "bytes", fromSha256: previous.sha256, toHashMode: next.hashMode, toSha256: next.sha256, reviewedPreimage: options.reviewedPreimage, currentSettingsSha256: options.expectedSettingsSha256, replacedWitnesses: replaced.map((source) => ({ hashMode: source.hashMode ?? "bytes", sha256: source.sha256 })) } };
|
|
45073
45286
|
}
|
|
45074
45287
|
function applyAgentIntegration(plan, options = {}) {
|
|
45075
45288
|
const roots = plan.changes.flatMap((change) => {
|
|
@@ -45085,7 +45298,7 @@ function applyAgentIntegrationUnlocked(plan, options = {}, assertCurrent) {
|
|
|
45085
45298
|
throw new Error("Native identity source changed after planning");
|
|
45086
45299
|
if (plan.observedSettings && readOptional(plan.observedSettings.path) !== plan.observedSettings.before)
|
|
45087
45300
|
throw new Error("Native settings changed after witness planning");
|
|
45088
|
-
const policyPath =
|
|
45301
|
+
const policyPath = join27(plan.dataDir, "agent-policy.json");
|
|
45089
45302
|
assertSafePath(policyPath);
|
|
45090
45303
|
const currentText = (path) => resolve18(path) === resolve18(policyPath) ? readManagedSkillPolicySnapshot(plan.dataDir)?.text ?? null : readOptional(path);
|
|
45091
45304
|
readManagedSkillPolicySnapshot(plan.dataDir);
|
|
@@ -45120,7 +45333,7 @@ function applyAgentIntegrationUnlocked(plan, options = {}, assertCurrent) {
|
|
|
45120
45333
|
for (const change of plan.changes)
|
|
45121
45334
|
if (currentText(change.path) !== change.before)
|
|
45122
45335
|
throw new Error(`Configuration changed after planning: ${change.path}`);
|
|
45123
|
-
const backupRoot =
|
|
45336
|
+
const backupRoot = join27(plan.dataDir, "migration", randomUUID4()), backups = [], written = [], createdDirectories = new Set;
|
|
45124
45337
|
if (!plan.changes.length) {
|
|
45125
45338
|
assertCurrent();
|
|
45126
45339
|
recheckRootAliases(aliases);
|
|
@@ -45131,7 +45344,7 @@ function applyAgentIntegrationUnlocked(plan, options = {}, assertCurrent) {
|
|
|
45131
45344
|
chmodSync(backupRoot, 448);
|
|
45132
45345
|
for (const [index, change] of plan.changes.entries())
|
|
45133
45346
|
if (change.before !== null) {
|
|
45134
|
-
const backup =
|
|
45347
|
+
const backup = join27(backupRoot, `${index}-${sha4(change.path).slice(0, 12)}.backup`);
|
|
45135
45348
|
writeFileSync5(backup, change.before, { mode: 384, flag: "wx" });
|
|
45136
45349
|
if (readFileSync16(backup, "utf8") !== change.before)
|
|
45137
45350
|
throw new Error("Native configuration preservation readback failed");
|
|
@@ -45164,7 +45377,7 @@ function applyAgentIntegrationUnlocked(plan, options = {}, assertCurrent) {
|
|
|
45164
45377
|
}
|
|
45165
45378
|
for (const agent of plan.managedAgentChecks?.agents ?? [])
|
|
45166
45379
|
assertManagedAgentBridge(agent, { home: plan.managedAgentChecks.home, dataDir: plan.dataDir, projectDir: plan.managedAgentChecks.home });
|
|
45167
|
-
atomicWrite2(
|
|
45380
|
+
atomicWrite2(join27(backupRoot, "receipt.json"), JSON.stringify({ version: 1, changes: written.map((change) => ({ path: change.path, beforeHash: change.before === null ? null : sha4(change.before), afterHash: sha4(change.after) })), backups, ...aliases.length ? { rootAliases: aliases } : {} }) + `
|
|
45168
45381
|
`);
|
|
45169
45382
|
} catch (error) {
|
|
45170
45383
|
assertCurrent();
|
|
@@ -45227,7 +45440,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
45227
45440
|
const selected = options.targetManifest ? selectNativeMigrationTargets(inventory, options.targetManifest) : inventory.filter((entry) => !entry.bridge && !entry.system && (entry.vendor ? options.includeVendor : entry.managed || options.includeUnmanaged));
|
|
45228
45441
|
const roots = selected.flatMap((entry) => {
|
|
45229
45442
|
const root2 = (entry.rootAlias?.agent === "codex" ? entry.rootAlias.alias : undefined) ?? codexCorpusRootForPath(entry.path);
|
|
45230
|
-
const owner2 = entry.codexHome ?? (entry.agent === "codex" && entry.bridgeHome ?
|
|
45443
|
+
const owner2 = entry.codexHome ?? (entry.agent === "codex" && entry.bridgeHome ? join27(entry.bridgeHome, ".codex") : undefined);
|
|
45231
45444
|
if (!root2 && !owner2 && (entry.agent === "codex" || isCodexSkillDiscoveryInput(entry.path)))
|
|
45232
45445
|
throw new Error("CODEX_CORPUS_ROOT_UNVERIFIED");
|
|
45233
45446
|
return [...new Set([root2, owner2].filter((value) => value !== undefined))];
|
|
@@ -45242,7 +45455,7 @@ function archiveNativeSkillsUnlocked(inventory, options, assertCurrent) {
|
|
|
45242
45455
|
recheckRootAliases(aliases);
|
|
45243
45456
|
for (const entry of inventory.filter((entry2) => entry2.bridge)) {
|
|
45244
45457
|
const adapter = AGENT_ADAPTERS[entry.agent];
|
|
45245
|
-
const expected = adapter && entry.bridgeHome ? canonicalAgentPath(
|
|
45458
|
+
const expected = adapter && entry.bridgeHome ? canonicalAgentPath(join27(entry.agent === "sumi" ? sumiBridgeRoot(entry.bridgeHome) : join27(entry.bridgeHome, adapter.root), CLI_BRIDGE_NAME), aliases) : undefined;
|
|
45246
45459
|
if (!expected || treeHash(entry.path) !== entry.hash || !isOwnedCliBridge(entry.path, [expected]))
|
|
45247
45460
|
throw new Error(`Skills bridge changed after planning: ${entry.path}`);
|
|
45248
45461
|
}
|
|
@@ -45253,11 +45466,11 @@ function archiveNativeSkillsUnlocked(inventory, options, assertCurrent) {
|
|
|
45253
45466
|
const targetManifest = options.targetManifest ? { schema: options.targetManifest.schema, digest: options.targetManifest.digest, targetCount: options.targetManifest.targets.length } : undefined;
|
|
45254
45467
|
if (!selected.length)
|
|
45255
45468
|
return { entries: [], ...targetManifest ? { targetManifest } : {}, ...aliases.length ? { rootAliases: aliases } : {} };
|
|
45256
|
-
const operationId = randomUUID4(), archiveRoot =
|
|
45469
|
+
const operationId = randomUUID4(), archiveRoot = join27(options.dataDir ?? getDataDir(), "migration", operationId, "native"), receiptPath = join27(archiveRoot, "receipt.json");
|
|
45257
45470
|
const entries = selected.map((entry, index) => ({
|
|
45258
|
-
source: entry.vendor ?
|
|
45259
|
-
archive:
|
|
45260
|
-
hash: entry.vendor ? sha4(readNativeBytes(
|
|
45471
|
+
source: entry.vendor ? join27(entry.path, "SKILL.md") : entry.path,
|
|
45472
|
+
archive: join27(archiveRoot, `${index}-${sha4(entry.path).slice(0, 12)}`),
|
|
45473
|
+
hash: entry.vendor ? sha4(readNativeBytes(join27(entry.path, "SKILL.md"))) : entry.hash,
|
|
45261
45474
|
...entry.vendor ? { discoveryOnly: true } : {},
|
|
45262
45475
|
status: "planned"
|
|
45263
45476
|
}));
|
|
@@ -45364,9 +45577,9 @@ function isInertCodexPluginCacheCopy(entry, cache, allowedHostPaths, read3) {
|
|
|
45364
45577
|
try {
|
|
45365
45578
|
if (entry.agent !== "codex" || !entry.vendor || entry.bridge || entry.system)
|
|
45366
45579
|
return false;
|
|
45367
|
-
const document2 =
|
|
45580
|
+
const document2 = join27(entry.path, "SKILL.md");
|
|
45368
45581
|
const inside = relative5(cache, entry.path);
|
|
45369
|
-
if (!inside || isAbsolute19(inside) || inside.split(
|
|
45582
|
+
if (!inside || isAbsolute19(inside) || inside.split(sep7).some((segment) => segment === ".."))
|
|
45370
45583
|
return false;
|
|
45371
45584
|
assertSafePath(entry.path);
|
|
45372
45585
|
if (!lstatSync22(cache).isDirectory() || !lstatSync22(entry.path).isDirectory() || !lstatSync22(document2).isFile())
|
|
@@ -45387,7 +45600,7 @@ function assertManagedAgentBridge(agent, options = {}) {
|
|
|
45387
45600
|
}
|
|
45388
45601
|
function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscovery) {
|
|
45389
45602
|
const home = resolve18(options.home ?? homedir3()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
|
|
45390
|
-
assertSafePath(
|
|
45603
|
+
assertSafePath(join27(dataDir2, "agent-policy.json"));
|
|
45391
45604
|
const snapshot2 = readManagedSkillPolicySnapshot(dataDir2);
|
|
45392
45605
|
if (!snapshot2)
|
|
45393
45606
|
throw new Error("NATIVE_SKILL_DRIFT: install the Skills bridge with skills hook install");
|
|
@@ -45398,14 +45611,14 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
|
|
|
45398
45611
|
if (!Array.isArray(aliases))
|
|
45399
45612
|
throw new Error("NATIVE_SKILL_DRIFT: invalid root alias binding");
|
|
45400
45613
|
recheckRootAliases(aliases);
|
|
45401
|
-
const expected = canonicalAgentPath(
|
|
45614
|
+
const expected = canonicalAgentPath(join27(agent === "sumi" ? sumiBridgeRoot(home) : join27(home, AGENT_ADAPTERS[agent].root), CLI_BRIDGE_NAME), aliases);
|
|
45402
45615
|
if (!isOwnedCliBridge(expected, [expected]))
|
|
45403
45616
|
throw new Error("NATIVE_SKILL_DRIFT: the native Skills bridge is missing or modified; repair it before continuing");
|
|
45404
45617
|
const roots = projectAncestorDirectories([options.projectDir ?? process.cwd(), ...options.projectDirs ?? [], ...agent === "hermes" && process.env.TERMINAL_CWD ? [process.cwd()] : []]);
|
|
45405
|
-
const visible = (entry) => entry.agent === agent || ["codex", "gemini", "opencode", "hermes", "sumi"].includes(agent) && entry.path.includes(`${
|
|
45618
|
+
const visible = (entry) => entry.agent === agent || ["codex", "gemini", "opencode", "hermes", "sumi"].includes(agent) && entry.path.includes(`${sep7}.agents${sep7}skills${sep7}`) || ["opencode", "sumi"].includes(agent) && entry.agent === "claude";
|
|
45406
45619
|
const discovery = provenDiscovery ?? binding.discovery?.[agent];
|
|
45407
45620
|
assertProjectDiscovery(agent, [...roots], home, (path) => canonicalAgentPath(path, aliases), discovery);
|
|
45408
|
-
const configPath = canonicalAgentPath(agent === "sumi" ? sumiConfigPath(home) :
|
|
45621
|
+
const configPath = canonicalAgentPath(agent === "sumi" ? sumiConfigPath(home) : join27(home, AGENT_ADAPTERS[agent].config), aliases), config = agent === "hermes" ? parseHermesConfig(readOptional(configPath)) : jsonObject(readOptional(configPath), configPath);
|
|
45409
45622
|
const command = binding.commands?.[agent], profile = binding.profiles?.[agent];
|
|
45410
45623
|
if (typeof command !== "string" || typeof profile !== "string")
|
|
45411
45624
|
throw new Error("NATIVE_SKILL_DRIFT: the native hook command/profile binding is missing");
|
|
@@ -45413,14 +45626,14 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
|
|
|
45413
45626
|
throw new Error("NATIVE_SKILL_DRIFT: the hook selection profile differs from its managed binding; restart the native client after reviewing skills hook install");
|
|
45414
45627
|
if (agent === "hermes") {
|
|
45415
45628
|
const supervisor = binding.supervisors?.hermes;
|
|
45416
|
-
if (supervisor?.path !==
|
|
45629
|
+
if (supervisor?.path !== join27(dataDir2, "agent-hooks", "hermes.js") || supervisor?.sha256 !== sha4(renderHermesSupervisor(command, profile)))
|
|
45417
45630
|
throw new Error("NATIVE_SKILL_DRIFT: Hermes supervisor binding changed; run skills hook install");
|
|
45418
45631
|
assertHermesProtection(home, config, command, profile, supervisor);
|
|
45419
45632
|
} else if (agent === "sumi") {
|
|
45420
|
-
if (JSON.stringify(config.permissions?.filter((rule) => rule.action === "skill")) !== JSON.stringify(SUMI_SKILL_PERMISSIONS) || !isManagedSumiPlugin(readOptional(
|
|
45633
|
+
if (JSON.stringify(config.permissions?.filter((rule) => rule.action === "skill")) !== JSON.stringify(SUMI_SKILL_PERMISSIONS) || !isManagedSumiPlugin(readOptional(join27(sumiConfigDirectory(home), "plugins", "skills-cli.js")), command, profile))
|
|
45421
45634
|
throw new Error("NATIVE_SKILL_DRIFT: Sumi bridge protection changed; run skills hook install");
|
|
45422
45635
|
} else if (agent === "opencode") {
|
|
45423
|
-
if (JSON.stringify(config.permission?.skill) !== JSON.stringify({ "*": "deny", [CLI_BRIDGE_NAME]: "allow" }) || readOptional(
|
|
45636
|
+
if (JSON.stringify(config.permission?.skill) !== JSON.stringify({ "*": "deny", [CLI_BRIDGE_NAME]: "allow" }) || readOptional(join27(home, ".config", "opencode", "plugins", "skills-cli.js")) !== renderOpenCodePlugin(command, profile))
|
|
45424
45637
|
throw new Error("NATIVE_SKILL_DRIFT: OpenCode bridge protection changed; run skills hook install");
|
|
45425
45638
|
} else {
|
|
45426
45639
|
const required = {};
|
|
@@ -45437,42 +45650,42 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
|
|
|
45437
45650
|
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)))
|
|
45438
45651
|
throw new Error("NATIVE_SKILL_DRIFT: Gemini bridge or bundled-skill protection changed; run skills hook install");
|
|
45439
45652
|
}
|
|
45440
|
-
const codexPath = canonicalAgentPath(
|
|
45653
|
+
const codexPath = canonicalAgentPath(join27(home, ".codex", "config.toml"), aliases);
|
|
45441
45654
|
if (options.codexDiscoveryRecovery && (agent !== "codex" || options.codexDiscoveryRecovery.configPath !== codexPath))
|
|
45442
45655
|
throw new Error("NATIVE_SKILL_DRIFT: Codex trust recovery names a different configuration root");
|
|
45443
45656
|
const codexConfig = agent === "codex" ? Bun.TOML.parse(readOptional(codexPath) ?? "") : {};
|
|
45444
45657
|
if (agent === "codex" && codexConfig.skills?.bundled?.enabled !== false)
|
|
45445
45658
|
throw new Error("NATIVE_SKILL_DRIFT: Codex bundled skill reseeding is not disabled (skills.bundled.enabled); run skills hook install");
|
|
45446
|
-
const setting = (path) => (codexConfig.skills?.config ?? []).filter((entry) => typeof entry.path === "string" && [path,
|
|
45659
|
+
const setting = (path) => (codexConfig.skills?.config ?? []).filter((entry) => typeof entry.path === "string" && [path, join27(path, "SKILL.md")].includes(canonicalAgentPath(entry.path, aliases)));
|
|
45447
45660
|
if (agent === "codex" && [...setting(expected), ...(codexConfig.skills?.config ?? []).filter((entry) => typeof entry.name === "string" && entry.name.trim() === CLI_BRIDGE_NAME)].some((entry) => entry.enabled === false))
|
|
45448
45661
|
throw new Error("NATIVE_SKILL_DRIFT: the Codex CLI bridge is disabled; run skills hook install");
|
|
45449
|
-
if (agent === "codex" && !reviewedCodexPluginCapabilitiesUnchanged(canonicalAgentPath(
|
|
45662
|
+
if (agent === "codex" && !reviewedCodexPluginCapabilitiesUnchanged(canonicalAgentPath(join27(home, ".codex/plugins/cache"), aliases), binding.codexPluginSkills ?? [], (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024)), codexConfig.skills?.config ?? []))
|
|
45450
45663
|
throw new Error("NATIVE_SKILL_DRIFT: reviewed native plugin capability controls changed; run skills hook install with a fresh discovery review");
|
|
45451
45664
|
const disabledPlugin = (entry) => {
|
|
45452
45665
|
if (agent !== "codex" || !entry.vendor)
|
|
45453
45666
|
return false;
|
|
45454
|
-
const document2 =
|
|
45667
|
+
const document2 = join27(entry.path, "SKILL.md"), cache = canonicalAgentPath(join27(home, ".codex/plugins/cache"), aliases), read3 = (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024));
|
|
45455
45668
|
return isReviewedCodexPluginInactive(document2, cache, binding.codexInactivePlugins ?? [], codexConfig.plugins, codexConfig.skills?.config ?? [], read3) || isReviewedCodexPluginSkillDisabled(document2, cache, binding.codexPluginSkills ?? [], codexConfig.skills?.config, read3);
|
|
45456
45669
|
};
|
|
45457
45670
|
const disabledPaths = new Set(disabledCodexSkillPaths(codexConfig, aliases));
|
|
45458
45671
|
const disabledVendorSkill = (entry) => {
|
|
45459
45672
|
if (agent !== "codex" || !entry.vendor)
|
|
45460
45673
|
return false;
|
|
45461
|
-
if ((binding.codexPluginSkills ?? []).some((control) => entry.path.startsWith(control.pluginParent +
|
|
45674
|
+
if ((binding.codexPluginSkills ?? []).some((control) => entry.path.startsWith(control.pluginParent + sep7)))
|
|
45462
45675
|
return disabledPlugin(entry);
|
|
45463
45676
|
if (disabledPlugin(entry))
|
|
45464
45677
|
return true;
|
|
45465
45678
|
if (!disabledPaths.has(entry.path))
|
|
45466
45679
|
return false;
|
|
45467
|
-
if (entry.path.startsWith(canonicalAgentPath(
|
|
45680
|
+
if (entry.path.startsWith(canonicalAgentPath(join27(home, ".codex", "plugins", "cache"), aliases) + sep7))
|
|
45468
45681
|
return true;
|
|
45469
|
-
const runtimeCache = canonicalAgentPath(
|
|
45470
|
-
if (entry.path.startsWith(runtimeCache +
|
|
45682
|
+
const runtimeCache = canonicalAgentPath(join27(home, ".cache", "codex-runtimes"), aliases);
|
|
45683
|
+
if (entry.path.startsWith(runtimeCache + sep7) && discovery?.method === "automatic" && discovery.roots.some((root2) => entry.path.startsWith(root2 + sep7)))
|
|
45471
45684
|
return true;
|
|
45472
|
-
const bundledMarketplaces = canonicalAgentPath(
|
|
45473
|
-
if (entry.path.startsWith(bundledMarketplaces +
|
|
45685
|
+
const bundledMarketplaces = canonicalAgentPath(join27(home, ".codex", ".tmp", "bundled-marketplaces"), aliases);
|
|
45686
|
+
if (entry.path.startsWith(bundledMarketplaces + sep7) && discovery?.method === "automatic" && discovery.roots.some((root2) => entry.path.startsWith(root2 + sep7)))
|
|
45474
45687
|
return true;
|
|
45475
|
-
if (!entry.path.startsWith(canonicalAgentPath(
|
|
45688
|
+
if (!entry.path.startsWith(canonicalAgentPath(join27(home, ".codex", "skills", ".system"), aliases) + sep7))
|
|
45476
45689
|
return false;
|
|
45477
45690
|
return Array.isArray(binding.disabledBuiltins) && binding.disabledBuiltins.some((item) => item.path === entry.path && item.hash === entry.hash);
|
|
45478
45691
|
};
|
|
@@ -45495,7 +45708,7 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
|
|
|
45495
45708
|
let installationInputRoots = [];
|
|
45496
45709
|
if (agent === "codex") {
|
|
45497
45710
|
try {
|
|
45498
|
-
installationInputRoots = reviewedCodexPluginSourceRoots(canonicalAgentPath(
|
|
45711
|
+
installationInputRoots = reviewedCodexPluginSourceRoots(canonicalAgentPath(join27(home, ".codex/plugins/cache"), aliases), discovery.codexInstallationInputs?.plugins ?? [], (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024)));
|
|
45499
45712
|
} catch {
|
|
45500
45713
|
throw new Error("NATIVE_SKILL_DRIFT: native installation input identity changed; review discovery and catalog");
|
|
45501
45714
|
}
|
|
@@ -45505,7 +45718,7 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
|
|
|
45505
45718
|
let adapterRefusal, inert = [];
|
|
45506
45719
|
if (agent === "codex" && unexpected.length && options.codexNativePolicy) {
|
|
45507
45720
|
const { inspector, helperRunner, deadlineMs, ...envelope } = options.codexNativePolicy;
|
|
45508
|
-
const cache = canonicalAgentPath(
|
|
45721
|
+
const cache = canonicalAgentPath(join27(home, ".codex", "plugins", "cache"), aliases), read3 = (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024)), bridgeDocument = join27(expected, "SKILL.md");
|
|
45509
45722
|
try {
|
|
45510
45723
|
const claimed = parseCodexNativeHookEnvelope(envelope, bridgeDocument).policy;
|
|
45511
45724
|
inert = unexpected.filter((entry) => isInertCodexPluginCacheCopy(entry, cache, claimed.allowedHostPaths, read3));
|
|
@@ -45545,15 +45758,15 @@ import {
|
|
|
45545
45758
|
statSync as statSync10,
|
|
45546
45759
|
writeFileSync as writeFileSync7
|
|
45547
45760
|
} from "fs";
|
|
45548
|
-
import { basename as basename11, dirname as dirname20, isAbsolute as isAbsolute20, join as
|
|
45761
|
+
import { basename as basename11, dirname as dirname20, isAbsolute as isAbsolute20, join as join31, normalize as normalize4, relative as relative7, resolve as resolve20, sep as sep10 } from "path";
|
|
45549
45762
|
|
|
45550
45763
|
// src/lib/registry-data/index.ts
|
|
45551
45764
|
var SKILLS = [];
|
|
45552
45765
|
|
|
45553
45766
|
// src/lib/skill-hash.ts
|
|
45554
|
-
import { createHash as
|
|
45767
|
+
import { createHash as createHash24 } from "crypto";
|
|
45555
45768
|
import { existsSync as existsSync8, readdirSync as readdirSync9, readFileSync as readFileSync17, statSync as statSync8 } from "fs";
|
|
45556
|
-
import { join as
|
|
45769
|
+
import { join as join28, sep as sep8 } from "path";
|
|
45557
45770
|
var CONTENT_HASH_ALGORITHM = "sha256";
|
|
45558
45771
|
var HASH_EXCLUDE_DIRS = new Set([".git", "node_modules", "dist", "build", ".turbo"]);
|
|
45559
45772
|
function excludedHashEntry(name, directory) {
|
|
@@ -45615,7 +45828,7 @@ function collectBundleFiles(skillPath) {
|
|
|
45615
45828
|
if (seen.has(entry))
|
|
45616
45829
|
continue;
|
|
45617
45830
|
seen.add(entry);
|
|
45618
|
-
const absolute =
|
|
45831
|
+
const absolute = join28(skillPath, entry);
|
|
45619
45832
|
if (!existsSync8(absolute))
|
|
45620
45833
|
continue;
|
|
45621
45834
|
if (statSync8(absolute).isDirectory())
|
|
@@ -45629,7 +45842,7 @@ function collectDirectory(files, dir, rel) {
|
|
|
45629
45842
|
for (const entry of readdirSync9(dir).sort()) {
|
|
45630
45843
|
if (entry.startsWith("."))
|
|
45631
45844
|
continue;
|
|
45632
|
-
const absolute =
|
|
45845
|
+
const absolute = join28(dir, entry);
|
|
45633
45846
|
const childRel = `${rel}/${entry}`;
|
|
45634
45847
|
let stats;
|
|
45635
45848
|
try {
|
|
@@ -45650,7 +45863,7 @@ function collectDirectory(files, dir, rel) {
|
|
|
45650
45863
|
}
|
|
45651
45864
|
function collectFile(files, absolute, rel) {
|
|
45652
45865
|
const buffer = readFileSync17(absolute);
|
|
45653
|
-
files.push(normalizeBundleFile(rel.split(
|
|
45866
|
+
files.push(normalizeBundleFile(rel.split(sep8).join("/"), buffer));
|
|
45654
45867
|
}
|
|
45655
45868
|
function normalizeBundleFile(rel, buffer) {
|
|
45656
45869
|
if (rel === "skill.json") {
|
|
@@ -45675,13 +45888,13 @@ function* bundleHashParts(files) {
|
|
|
45675
45888
|
yield new TextEncoder().encode("\x00");
|
|
45676
45889
|
}
|
|
45677
45890
|
function hashBundleFiles(files) {
|
|
45678
|
-
const hash2 =
|
|
45891
|
+
const hash2 = createHash24(CONTENT_HASH_ALGORITHM);
|
|
45679
45892
|
for (const part of bundleHashParts(files))
|
|
45680
45893
|
hash2.update(part);
|
|
45681
45894
|
return hash2.digest("hex");
|
|
45682
45895
|
}
|
|
45683
45896
|
async function hashBundleFilesCooperatively(files, check) {
|
|
45684
|
-
const hash2 =
|
|
45897
|
+
const hash2 = createHash24(CONTENT_HASH_ALGORITHM);
|
|
45685
45898
|
let bytesSinceYield = 0;
|
|
45686
45899
|
for (const part of bundleHashParts(files)) {
|
|
45687
45900
|
for (let offset = 0;offset < part.byteLength; offset += 64 * 1024) {
|
|
@@ -46070,7 +46283,7 @@ import {
|
|
|
46070
46283
|
realpathSync as realpathSync11,
|
|
46071
46284
|
writeFileSync as writeFileSync6
|
|
46072
46285
|
} from "fs";
|
|
46073
|
-
import { basename as basename9, dirname as dirname18, join as
|
|
46286
|
+
import { basename as basename9, dirname as dirname18, join as join29, relative as relative6 } from "path";
|
|
46074
46287
|
var ANY_SEGMENT_COPY_EXCLUDES = new Set([
|
|
46075
46288
|
".git",
|
|
46076
46289
|
".DS_Store",
|
|
@@ -46127,9 +46340,9 @@ function readPortableSkillManifestForImport(skillPath) {
|
|
|
46127
46340
|
return readManifest(skillPath, basename9(skillPath), normalizeNewPortableSkillName);
|
|
46128
46341
|
}
|
|
46129
46342
|
function readManifest(skillPath, fallbackName, normalizeName) {
|
|
46130
|
-
const skillJsonPath =
|
|
46131
|
-
const skillMdPath =
|
|
46132
|
-
const pkgPath =
|
|
46343
|
+
const skillJsonPath = join29(skillPath, "skill.json");
|
|
46344
|
+
const skillMdPath = join29(skillPath, "SKILL.md");
|
|
46345
|
+
const pkgPath = join29(skillPath, "package.json");
|
|
46133
46346
|
const jsonManifest = existsSync9(skillJsonPath) ? readJsonObject(skillJsonPath) : undefined;
|
|
46134
46347
|
const frontmatter = existsSync9(skillMdPath) ? parseSkillFrontmatter(readFileSync18(skillMdPath, "utf-8")) ?? undefined : undefined;
|
|
46135
46348
|
const pkg = existsSync9(pkgPath) ? readJsonObject(pkgPath) : undefined;
|
|
@@ -46161,9 +46374,9 @@ function parseSkillKind(value) {
|
|
|
46161
46374
|
return;
|
|
46162
46375
|
}
|
|
46163
46376
|
function readDeclaredSkillVersion(skillPath) {
|
|
46164
|
-
const skillJsonPath =
|
|
46165
|
-
const skillMdPath =
|
|
46166
|
-
const pkgPath =
|
|
46377
|
+
const skillJsonPath = join29(skillPath, "skill.json");
|
|
46378
|
+
const skillMdPath = join29(skillPath, "SKILL.md");
|
|
46379
|
+
const pkgPath = join29(skillPath, "package.json");
|
|
46167
46380
|
const jsonManifest = existsSync9(skillJsonPath) ? readJsonObject(skillJsonPath) : undefined;
|
|
46168
46381
|
const frontmatter = existsSync9(skillMdPath) ? parseSkillFrontmatter(readFileSync18(skillMdPath, "utf-8")) ?? undefined : undefined;
|
|
46169
46382
|
const pkg = existsSync9(pkgPath) ? readJsonObject(pkgPath) : undefined;
|
|
@@ -46187,7 +46400,7 @@ function createInstructionManifest(name, options) {
|
|
|
46187
46400
|
}
|
|
46188
46401
|
function writeInstructionSkillTemplate(skillPath, manifest) {
|
|
46189
46402
|
mkdirSync7(skillPath, { recursive: true });
|
|
46190
|
-
writeFileSync6(
|
|
46403
|
+
writeFileSync6(join29(skillPath, "SKILL.md"), renderInstructionSkillMd(manifest));
|
|
46191
46404
|
writeSkillJsonWithHash(skillPath, manifest);
|
|
46192
46405
|
}
|
|
46193
46406
|
function renderInstructionSkillMd(manifest) {
|
|
@@ -46237,12 +46450,12 @@ function createPortableManifest(name, options) {
|
|
|
46237
46450
|
};
|
|
46238
46451
|
}
|
|
46239
46452
|
function writePortableSkillTemplate(skillPath, manifest) {
|
|
46240
|
-
mkdirSync7(
|
|
46241
|
-
writeFileSync6(
|
|
46242
|
-
writeFileSync6(
|
|
46243
|
-
writeFileSync6(
|
|
46244
|
-
writeFileSync6(
|
|
46245
|
-
writeFileSync6(
|
|
46453
|
+
mkdirSync7(join29(skillPath, "src"), { recursive: true });
|
|
46454
|
+
writeFileSync6(join29(skillPath, "SKILL.md"), renderSkillMd(manifest));
|
|
46455
|
+
writeFileSync6(join29(skillPath, "AGENTS.md"), renderAgentsMd(manifest));
|
|
46456
|
+
writeFileSync6(join29(skillPath, "package.json"), renderPackageJson(manifest));
|
|
46457
|
+
writeFileSync6(join29(skillPath, "tsconfig.json"), renderTsconfig());
|
|
46458
|
+
writeFileSync6(join29(skillPath, "src", "index.ts"), renderEntrypoint(manifest));
|
|
46246
46459
|
writeSkillJsonWithHash(skillPath, manifest);
|
|
46247
46460
|
}
|
|
46248
46461
|
function fillContractDefaults(manifest, entrypoint) {
|
|
@@ -46267,7 +46480,7 @@ function writeSkillJsonWithHash(skillPath, manifest) {
|
|
|
46267
46480
|
content_hash: undefined
|
|
46268
46481
|
}
|
|
46269
46482
|
};
|
|
46270
|
-
writeFileSync6(
|
|
46483
|
+
writeFileSync6(join29(skillPath, "skill.json"), `${JSON.stringify({ ...existing, ...renderSkillJsonObject(withoutHash) }, null, 2)}
|
|
46271
46484
|
`);
|
|
46272
46485
|
const hash2 = computeContentHash(skillPath);
|
|
46273
46486
|
const withHash = {
|
|
@@ -46277,12 +46490,12 @@ function writeSkillJsonWithHash(skillPath, manifest) {
|
|
|
46277
46490
|
content_hash: hash2
|
|
46278
46491
|
}
|
|
46279
46492
|
};
|
|
46280
|
-
writeFileSync6(
|
|
46493
|
+
writeFileSync6(join29(skillPath, "skill.json"), `${JSON.stringify({ ...existing, ...renderSkillJsonObject(withHash) }, null, 2)}
|
|
46281
46494
|
`);
|
|
46282
46495
|
return withHash;
|
|
46283
46496
|
}
|
|
46284
46497
|
function readExistingSkillJson(skillPath) {
|
|
46285
|
-
const path =
|
|
46498
|
+
const path = join29(skillPath, "skill.json");
|
|
46286
46499
|
if (!existsSync9(path))
|
|
46287
46500
|
return {};
|
|
46288
46501
|
try {
|
|
@@ -46316,24 +46529,24 @@ function ensurePortableSkillFiles(skillPath, manifest) {
|
|
|
46316
46529
|
tags: next.tags?.length ? next.tags : ["custom", next.name]
|
|
46317
46530
|
};
|
|
46318
46531
|
const entry = next.commands[0]?.entry ?? "src/index.ts";
|
|
46319
|
-
if (entry && !existsSync9(
|
|
46320
|
-
mkdirSync7(dirname18(
|
|
46321
|
-
writeFileSync6(
|
|
46532
|
+
if (entry && !existsSync9(join29(skillPath, entry))) {
|
|
46533
|
+
mkdirSync7(dirname18(join29(skillPath, entry)), { recursive: true });
|
|
46534
|
+
writeFileSync6(join29(skillPath, entry), renderEntrypoint(next));
|
|
46322
46535
|
}
|
|
46323
|
-
if (!existsSync9(
|
|
46324
|
-
writeFileSync6(
|
|
46536
|
+
if (!existsSync9(join29(skillPath, "SKILL.md")))
|
|
46537
|
+
writeFileSync6(join29(skillPath, "SKILL.md"), renderSkillMd(next));
|
|
46325
46538
|
else
|
|
46326
|
-
writeFileSync6(
|
|
46327
|
-
if (!existsSync9(
|
|
46328
|
-
writeFileSync6(
|
|
46539
|
+
writeFileSync6(join29(skillPath, "SKILL.md"), ensureSkillMdFrontmatter(readFileSync18(join29(skillPath, "SKILL.md"), "utf-8"), next));
|
|
46540
|
+
if (!existsSync9(join29(skillPath, "AGENTS.md")))
|
|
46541
|
+
writeFileSync6(join29(skillPath, "AGENTS.md"), renderAgentsMd(next));
|
|
46329
46542
|
ensurePackageJson(skillPath, next);
|
|
46330
|
-
if (!existsSync9(
|
|
46331
|
-
writeFileSync6(
|
|
46543
|
+
if (!existsSync9(join29(skillPath, "tsconfig.json")))
|
|
46544
|
+
writeFileSync6(join29(skillPath, "tsconfig.json"), renderTsconfig());
|
|
46332
46545
|
writeSkillJsonWithHash(skillPath, next);
|
|
46333
46546
|
return readPortableSkillManifest(skillPath, next.name);
|
|
46334
46547
|
}
|
|
46335
46548
|
function ensurePackageJson(skillPath, manifest) {
|
|
46336
|
-
const pkgPath =
|
|
46549
|
+
const pkgPath = join29(skillPath, "package.json");
|
|
46337
46550
|
const first = manifest.commands[0] ?? { name: manifest.name, entry: "src/index.ts" };
|
|
46338
46551
|
const commandName = normalizePortableSkillName(first.name || manifest.name);
|
|
46339
46552
|
const entry = (first.entry ?? "src/index.ts").replace(/^\.\//, "");
|
|
@@ -46380,17 +46593,17 @@ function ensureInstructionSkillFiles(skillPath, manifest) {
|
|
|
46380
46593
|
inputs: [],
|
|
46381
46594
|
commands: []
|
|
46382
46595
|
};
|
|
46383
|
-
if (!existsSync9(
|
|
46384
|
-
writeFileSync6(
|
|
46596
|
+
if (!existsSync9(join29(skillPath, "SKILL.md"))) {
|
|
46597
|
+
writeFileSync6(join29(skillPath, "SKILL.md"), renderSkillMd(next));
|
|
46385
46598
|
} else {
|
|
46386
|
-
const path =
|
|
46599
|
+
const path = join29(skillPath, "SKILL.md");
|
|
46387
46600
|
const content = readFileSync18(path, "utf8");
|
|
46388
46601
|
const declaredName = parseSkillFrontmatter(content)?.name;
|
|
46389
46602
|
if (declaredName && declaredName !== next.name) {
|
|
46390
46603
|
writeFileSync6(path, renameInstructionFrontmatter(content, next.name));
|
|
46391
46604
|
}
|
|
46392
46605
|
}
|
|
46393
|
-
const packagePath =
|
|
46606
|
+
const packagePath = join29(skillPath, "package.json");
|
|
46394
46607
|
if (existsSync9(packagePath)) {
|
|
46395
46608
|
const pkg = readJsonObject(packagePath);
|
|
46396
46609
|
if (typeof pkg.name === "string" && pkg.name !== next.name) {
|
|
@@ -46716,10 +46929,10 @@ function escapeJsString(value) {
|
|
|
46716
46929
|
// src/lib/authoring-path.ts
|
|
46717
46930
|
import { lstatSync as lstatSync24, realpathSync as realpathSync12 } from "fs";
|
|
46718
46931
|
import { homedir as homedir4 } from "os";
|
|
46719
|
-
import { basename as basename10, dirname as dirname19, join as
|
|
46932
|
+
import { basename as basename10, dirname as dirname19, join as join30, resolve as resolve19, sep as sep9 } from "path";
|
|
46720
46933
|
var NATIVE_DISCOVERY_ROOTS = NATIVE_SKILL_ROOTS.map(([, path]) => path.split("/"));
|
|
46721
46934
|
function pathParts(path) {
|
|
46722
|
-
return resolve19(path).split(
|
|
46935
|
+
return resolve19(path).split(sep9).filter(Boolean);
|
|
46723
46936
|
}
|
|
46724
46937
|
function nativeRootMatch(path) {
|
|
46725
46938
|
const parts = pathParts(path);
|
|
@@ -46745,10 +46958,10 @@ function physicalPath(path) {
|
|
|
46745
46958
|
return resolve19(realpathSync12(cursor), ...suffix);
|
|
46746
46959
|
}
|
|
46747
46960
|
function contains(root2, path) {
|
|
46748
|
-
return path === root2 || path.startsWith(root2 +
|
|
46961
|
+
return path === root2 || path.startsWith(root2 + sep9);
|
|
46749
46962
|
}
|
|
46750
46963
|
function configuredRoots(home, explicitHome) {
|
|
46751
|
-
const homeData =
|
|
46964
|
+
const homeData = join30(home, ".hasna", "skills");
|
|
46752
46965
|
const homePolicy = readManagedSkillPolicySnapshot(homeData);
|
|
46753
46966
|
const configuredPolicy = !explicitHome && resolve19(getDataDirReadOnly()) !== resolve19(homeData) ? readManagedSkillPolicySnapshot(getDataDirReadOnly()) : null;
|
|
46754
46967
|
const policy = homePolicy ?? configuredPolicy;
|
|
@@ -46779,7 +46992,7 @@ function configuredRoots(home, explicitHome) {
|
|
|
46779
46992
|
admitBinding(binding);
|
|
46780
46993
|
continue;
|
|
46781
46994
|
}
|
|
46782
|
-
const nativeHome =
|
|
46995
|
+
const nativeHome = join30(home, agent === "opencode" ? ".config/opencode" : `.${agent}`);
|
|
46783
46996
|
if (!lstatSync24(nativeHome, { throwIfNoEntry: false }))
|
|
46784
46997
|
continue;
|
|
46785
46998
|
roots.push(...resolveAgentDiscovery({ home, agent, canonical: physicalPath }).roots);
|
|
@@ -46794,8 +47007,8 @@ function assertPortableAuthoringPath(path, options = {}) {
|
|
|
46794
47007
|
const candidates = [lexical, physical];
|
|
46795
47008
|
let native = candidates.map(nativeRootMatch).find(Boolean);
|
|
46796
47009
|
const home = resolve19(options.homeDir ?? homedir4());
|
|
46797
|
-
const defaults = NATIVE_DISCOVERY_ROOTS.map((parts) =>
|
|
46798
|
-
defaults.push(
|
|
47010
|
+
const defaults = NATIVE_DISCOVERY_ROOTS.map((parts) => join30(home, ...parts));
|
|
47011
|
+
defaults.push(join30(home, ".codex/plugins/cache"), join30(home, ".claude/plugins/cache"), join30(home, ".claude/plugins/synced"), join30(home, ".gemini/extensions"));
|
|
46799
47012
|
for (const root2 of defaults) {
|
|
46800
47013
|
if (candidates.some((candidate2) => contains(resolve19(root2), candidate2) || contains(physicalPath(root2), candidate2)))
|
|
46801
47014
|
native ??= root2;
|
|
@@ -46816,15 +47029,15 @@ function getPortableSkillsRoot(options = {}) {
|
|
|
46816
47029
|
function resolvePortableSkillsRoot(options, migrate) {
|
|
46817
47030
|
if (options.rootDir)
|
|
46818
47031
|
return options.rootDir;
|
|
46819
|
-
const appDir = options.homeDir ?
|
|
46820
|
-
const cache =
|
|
47032
|
+
const appDir = options.homeDir ? join31(options.homeDir, ".hasna", "skills") : migrate ? getDataDir() : getDataDirReadOnly();
|
|
47033
|
+
const cache = join31(appDir, SKILLS_CACHE_DIRNAME);
|
|
46821
47034
|
if (isOwnerLayoutMigrated(appDir) && safeIsDirectory(cache))
|
|
46822
47035
|
return cache;
|
|
46823
|
-
const installed =
|
|
47036
|
+
const installed = join31(appDir, INSTALLED_SKILLS_DIRNAME);
|
|
46824
47037
|
return installed;
|
|
46825
47038
|
}
|
|
46826
47039
|
function getPortableSkillPath(name, options = {}) {
|
|
46827
|
-
return
|
|
47040
|
+
return join31(getPortableSkillsRoot(options), normalizePortableSkillName(name));
|
|
46828
47041
|
}
|
|
46829
47042
|
function findPortableSkill(name, options = {}) {
|
|
46830
47043
|
let normalized;
|
|
@@ -46850,7 +47063,7 @@ function listPortableSkills(options = {}) {
|
|
|
46850
47063
|
for (const entry of readdirSync10(root2).sort()) {
|
|
46851
47064
|
if (entry.startsWith("."))
|
|
46852
47065
|
continue;
|
|
46853
|
-
const path =
|
|
47066
|
+
const path = join31(root2, entry);
|
|
46854
47067
|
if (!safeIsDirectory(path))
|
|
46855
47068
|
continue;
|
|
46856
47069
|
try {
|
|
@@ -46884,9 +47097,9 @@ function isOfficialSkillName(name) {
|
|
|
46884
47097
|
function scaffoldPortableSkill(name, options = {}) {
|
|
46885
47098
|
const skillName = normalizeNewPortableSkillName(name);
|
|
46886
47099
|
const readOnlyRoot = resolvePortableSkillsRoot(options, false);
|
|
46887
|
-
assertPortableAuthoringPath(
|
|
47100
|
+
assertPortableAuthoringPath(join31(readOnlyRoot, skillName), options);
|
|
46888
47101
|
const root2 = getPortableSkillsRoot(options);
|
|
46889
|
-
const skillPath =
|
|
47102
|
+
const skillPath = join31(root2, skillName);
|
|
46890
47103
|
assertPortableAuthoringPath(skillPath, options);
|
|
46891
47104
|
if (existsSync10(skillPath)) {
|
|
46892
47105
|
if (!options.overwrite)
|
|
@@ -46920,7 +47133,7 @@ function portPortableSkillDirectory(sourceDir, options = {}) {
|
|
|
46920
47133
|
const skipped = [];
|
|
46921
47134
|
const entries = readdirSync10(absoluteSource, { withFileTypes: true }).map((entry) => entry.name).filter((entryName) => !entryName.startsWith(".")).sort();
|
|
46922
47135
|
for (const entryName of entries) {
|
|
46923
|
-
const childPath =
|
|
47136
|
+
const childPath = join31(absoluteSource, entryName);
|
|
46924
47137
|
if (!safeIsDirectory(childPath))
|
|
46925
47138
|
continue;
|
|
46926
47139
|
if (!isSkillCandidate(childPath)) {
|
|
@@ -46949,7 +47162,7 @@ function portPortableSkillDirectory(sourceDir, options = {}) {
|
|
|
46949
47162
|
};
|
|
46950
47163
|
}
|
|
46951
47164
|
function isSkillCandidate(dir) {
|
|
46952
|
-
return existsSync10(
|
|
47165
|
+
return existsSync10(join31(dir, "SKILL.md")) || existsSync10(join31(dir, "skill.json")) || existsSync10(join31(dir, "package.json"));
|
|
46953
47166
|
}
|
|
46954
47167
|
function physicalImportPath(path) {
|
|
46955
47168
|
let ancestor = resolve20(path);
|
|
@@ -46958,14 +47171,14 @@ function physicalImportPath(path) {
|
|
|
46958
47171
|
suffix.unshift(basename11(ancestor));
|
|
46959
47172
|
ancestor = dirname20(ancestor);
|
|
46960
47173
|
}
|
|
46961
|
-
return
|
|
47174
|
+
return join31(realpathSync13(ancestor), ...suffix);
|
|
46962
47175
|
}
|
|
46963
47176
|
function assertDisjointImportPaths(source, destination) {
|
|
46964
47177
|
const sourcePath = realpathSync13(source);
|
|
46965
47178
|
const destinationPath = physicalImportPath(destination);
|
|
46966
47179
|
const contains2 = (parent, child) => {
|
|
46967
47180
|
const path = relative7(parent, child);
|
|
46968
|
-
return path === "" || !isAbsolute20(path) && path !== ".." && !path.startsWith(`..${
|
|
47181
|
+
return path === "" || !isAbsolute20(path) && path !== ".." && !path.startsWith(`..${sep10}`);
|
|
46969
47182
|
};
|
|
46970
47183
|
if (contains2(sourcePath, destinationPath) || contains2(destinationPath, sourcePath)) {
|
|
46971
47184
|
throw new Error("Source and destination skill directories must not overlap");
|
|
@@ -46984,11 +47197,11 @@ function portPortableSkill(sourcePath, options = {}) {
|
|
|
46984
47197
|
const via = explicitName ? `Name '${skillName}' matches a bundled official skill.` : `Inferred name '${skillName}'${sourceSlug && sourceSlug !== skillName ? ` (from source folder '${basename11(absoluteSource)}')` : ""} matches a bundled official skill.`;
|
|
46985
47198
|
throw new Error(`${via} Importing it would shadow the official '${skillName}'. ` + `Pass --name to choose a different name, or --allow-shadow to override deliberately.`);
|
|
46986
47199
|
}
|
|
46987
|
-
const readOnlyDestination =
|
|
47200
|
+
const readOnlyDestination = join31(resolvePortableSkillsRoot(options, false), skillName);
|
|
46988
47201
|
assertPortableAuthoringPath(readOnlyDestination, options);
|
|
46989
47202
|
assertDisjointImportPaths(absoluteSource, readOnlyDestination);
|
|
46990
47203
|
const root2 = getPortableSkillsRoot(options);
|
|
46991
|
-
const destination =
|
|
47204
|
+
const destination = join31(root2, skillName);
|
|
46992
47205
|
assertPortableAuthoringPath(destination, options);
|
|
46993
47206
|
assertDisjointImportPaths(absoluteSource, destination);
|
|
46994
47207
|
if (existsSync10(destination)) {
|
|
@@ -47033,13 +47246,13 @@ function buildCorpusManifest(input, name) {
|
|
|
47033
47246
|
function writeCorpusSkill(input, options = {}) {
|
|
47034
47247
|
const name = normalizePortableSkillName(input.name);
|
|
47035
47248
|
const readOnlyRoot = resolvePortableSkillsRoot(options, false);
|
|
47036
|
-
assertPortableAuthoringPath(
|
|
47249
|
+
assertPortableAuthoringPath(join31(readOnlyRoot, name), options);
|
|
47037
47250
|
const root2 = getPortableSkillsRoot(options);
|
|
47038
|
-
const skillPath =
|
|
47251
|
+
const skillPath = join31(root2, name);
|
|
47039
47252
|
assertPortableAuthoringPath(skillPath, options);
|
|
47040
47253
|
const created = !existsSync10(skillPath);
|
|
47041
47254
|
mkdirSync8(skillPath, { recursive: true });
|
|
47042
|
-
writeFileSync7(
|
|
47255
|
+
writeFileSync7(join31(skillPath, "SKILL.md"), input.skillMd);
|
|
47043
47256
|
const manifest = buildCorpusManifest(input, name);
|
|
47044
47257
|
writeSkillJsonWithHash(skillPath, manifest);
|
|
47045
47258
|
return { name, path: skillPath, manifest, created };
|
|
@@ -47047,22 +47260,22 @@ function writeCorpusSkill(input, options = {}) {
|
|
|
47047
47260
|
function installCorpusSkillAtomically(input, options = {}) {
|
|
47048
47261
|
const name = normalizePortableSkillName(input.name);
|
|
47049
47262
|
const readOnlyRoot = resolvePortableSkillsRoot(options, false);
|
|
47050
|
-
assertPortableAuthoringPath(
|
|
47263
|
+
assertPortableAuthoringPath(join31(readOnlyRoot, name), options);
|
|
47051
47264
|
const root2 = getPortableSkillsRoot(options);
|
|
47052
|
-
const target =
|
|
47265
|
+
const target = join31(root2, name);
|
|
47053
47266
|
assertPortableAuthoringPath(target, options);
|
|
47054
47267
|
const created = !existsSync10(target);
|
|
47055
47268
|
mkdirSync8(root2, { recursive: true });
|
|
47056
|
-
const staging = mkdtempSync(
|
|
47269
|
+
const staging = mkdtempSync(join31(root2, `.pull-${name}-`));
|
|
47057
47270
|
let moved = false;
|
|
47058
47271
|
let backup = null;
|
|
47059
47272
|
try {
|
|
47060
|
-
writeFileSync7(
|
|
47273
|
+
writeFileSync7(join31(staging, "SKILL.md"), input.skillMd);
|
|
47061
47274
|
const manifest = buildCorpusManifest(input, name);
|
|
47062
47275
|
writeSkillJsonWithHash(staging, manifest);
|
|
47063
47276
|
if (existsSync10(target)) {
|
|
47064
|
-
backup = mkdtempSync(
|
|
47065
|
-
renameSync5(target,
|
|
47277
|
+
backup = mkdtempSync(join31(root2, `.pull-backup-${name}-`));
|
|
47278
|
+
renameSync5(target, join31(backup, name));
|
|
47066
47279
|
moved = true;
|
|
47067
47280
|
}
|
|
47068
47281
|
renameSync5(staging, target);
|
|
@@ -47071,9 +47284,9 @@ function installCorpusSkillAtomically(input, options = {}) {
|
|
|
47071
47284
|
return { name, path: target, manifest, created };
|
|
47072
47285
|
} catch (error) {
|
|
47073
47286
|
rmSync2(staging, { recursive: true, force: true });
|
|
47074
|
-
if (moved && backup && existsSync10(
|
|
47287
|
+
if (moved && backup && existsSync10(join31(backup, name))) {
|
|
47075
47288
|
try {
|
|
47076
|
-
renameSync5(
|
|
47289
|
+
renameSync5(join31(backup, name), target);
|
|
47077
47290
|
} catch {}
|
|
47078
47291
|
}
|
|
47079
47292
|
throw error;
|
|
@@ -47086,8 +47299,8 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
47086
47299
|
const warnings = [...base.warnings];
|
|
47087
47300
|
let manifest;
|
|
47088
47301
|
if (existsSync10(skillPath)) {
|
|
47089
|
-
const skillJsonPath =
|
|
47090
|
-
const skillMdPath =
|
|
47302
|
+
const skillJsonPath = join31(skillPath, "skill.json");
|
|
47303
|
+
const skillMdPath = join31(skillPath, "SKILL.md");
|
|
47091
47304
|
if (!existsSync10(skillJsonPath) && !existsSync10(skillMdPath)) {
|
|
47092
47305
|
add3(issues, "portable.manifest_missing", "Missing portable manifest: expected SKILL.md frontmatter and/or skill.json");
|
|
47093
47306
|
}
|
|
@@ -47107,7 +47320,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
47107
47320
|
add3(issues, "portable.version_missing", "Portable manifest missing version");
|
|
47108
47321
|
}
|
|
47109
47322
|
const contractIssues = validatePortableManifestContract(manifest, {
|
|
47110
|
-
strict: existsSync10(
|
|
47323
|
+
strict: existsSync10(join31(skillPath, "skill.json")),
|
|
47111
47324
|
skillPath
|
|
47112
47325
|
});
|
|
47113
47326
|
for (const issue of contractIssues)
|
|
@@ -47147,7 +47360,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
47147
47360
|
add3(issues, "portable.command_entry_unsafe", `Command '${command.name}' entry '${command.entry}' must stay inside the skill directory`);
|
|
47148
47361
|
continue;
|
|
47149
47362
|
}
|
|
47150
|
-
const entryPath =
|
|
47363
|
+
const entryPath = join31(skillPath, command.entry);
|
|
47151
47364
|
if (!existsSync10(entryPath))
|
|
47152
47365
|
add3(issues, "portable.command_entry_missing", `Command '${command.name}' entry '${command.entry}' is missing`);
|
|
47153
47366
|
else if (statSync10(entryPath).isDirectory())
|
|
@@ -47158,7 +47371,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
47158
47371
|
} catch (error) {
|
|
47159
47372
|
add3(issues, "portable.manifest_invalid", error.message);
|
|
47160
47373
|
}
|
|
47161
|
-
if (manifest?.kind !== "instruction" && !existsSync10(
|
|
47374
|
+
if (manifest?.kind !== "instruction" && !existsSync10(join31(skillPath, "AGENTS.md"))) {
|
|
47162
47375
|
add3(issues, "portable.agents_missing", "Missing AGENTS.md with build-out instructions for coding agents");
|
|
47163
47376
|
}
|
|
47164
47377
|
}
|
|
@@ -47194,12 +47407,12 @@ async function runPortableSkill(name, args, options = {}) {
|
|
|
47194
47407
|
if (!isSafeRelativePath2(command.entry)) {
|
|
47195
47408
|
return { exitCode: 1, error: `Portable skill '${name}' command entry is unsafe` };
|
|
47196
47409
|
}
|
|
47197
|
-
const entryPath =
|
|
47410
|
+
const entryPath = join31(skill.path, command.entry);
|
|
47198
47411
|
if (!existsSync10(entryPath)) {
|
|
47199
47412
|
return { exitCode: 1, error: `Entry point '${command.entry}' not found in portable skill '${name}'` };
|
|
47200
47413
|
}
|
|
47201
|
-
const pkgPath =
|
|
47202
|
-
const nodeModules =
|
|
47414
|
+
const pkgPath = join31(skill.path, "package.json");
|
|
47415
|
+
const nodeModules = join31(skill.path, "node_modules");
|
|
47203
47416
|
if (existsSync10(pkgPath) && !existsSync10(nodeModules) && hasPackageDependencies(pkgPath)) {
|
|
47204
47417
|
const install = Bun.spawn(["bun", "install", "--no-save"], {
|
|
47205
47418
|
cwd: skill.path,
|
|
@@ -47271,7 +47484,7 @@ function isSkillsOwnershipMarker(marker) {
|
|
|
47271
47484
|
return typeof marker === "object" && marker !== null && Object.hasOwn(marker, "managedBy") && marker.managedBy === SYNC_MARKER_MANAGED_BY;
|
|
47272
47485
|
}
|
|
47273
47486
|
function hasSkillsOwnershipMarker(dir) {
|
|
47274
|
-
const path =
|
|
47487
|
+
const path = join32(dir, SYNC_MARKER_FILE);
|
|
47275
47488
|
try {
|
|
47276
47489
|
if (!lstatSync25(path).isFile())
|
|
47277
47490
|
return false;
|
|
@@ -47295,9 +47508,9 @@ function resolveSyncAgents(arg) {
|
|
|
47295
47508
|
function agentGlobalSkillsDir(agent, homeDir3 = homedir5()) {
|
|
47296
47509
|
switch (agent) {
|
|
47297
47510
|
case "opencode":
|
|
47298
|
-
return
|
|
47511
|
+
return join32(homeDir3, ".config", "opencode", "skills");
|
|
47299
47512
|
default:
|
|
47300
|
-
return
|
|
47513
|
+
return join32(homeDir3, `.${agent}`, "skills");
|
|
47301
47514
|
}
|
|
47302
47515
|
}
|
|
47303
47516
|
function adaptSkillMdForAgent(skillMd, agent) {
|
|
@@ -47356,7 +47569,7 @@ function resolveSyncCorpus(options = {}) {
|
|
|
47356
47569
|
function packageSourceRoots(source) {
|
|
47357
47570
|
const roots = [];
|
|
47358
47571
|
for (const sub of ["skills"]) {
|
|
47359
|
-
const candidate2 =
|
|
47572
|
+
const candidate2 = join32(source, sub);
|
|
47360
47573
|
if (existsSync11(candidate2) && isDirectory(candidate2))
|
|
47361
47574
|
roots.push(candidate2);
|
|
47362
47575
|
}
|
|
@@ -47372,10 +47585,10 @@ function containsSkillDirectories(path) {
|
|
|
47372
47585
|
return false;
|
|
47373
47586
|
}
|
|
47374
47587
|
return entries.some((entry) => {
|
|
47375
|
-
const candidate2 =
|
|
47588
|
+
const candidate2 = join32(path, entry);
|
|
47376
47589
|
if (!isDirectory(candidate2))
|
|
47377
47590
|
return false;
|
|
47378
|
-
return existsSync11(
|
|
47591
|
+
return existsSync11(join32(candidate2, "SKILL.md")) || existsSync11(join32(candidate2, "skill.json")) || existsSync11(join32(candidate2, "package.json"));
|
|
47379
47592
|
});
|
|
47380
47593
|
}
|
|
47381
47594
|
function isDirectory(path) {
|
|
@@ -47415,7 +47628,7 @@ function syncSkillsToAgents(options = {}) {
|
|
|
47415
47628
|
actions.push({
|
|
47416
47629
|
skill: name,
|
|
47417
47630
|
agent,
|
|
47418
|
-
path:
|
|
47631
|
+
path: join32(agentGlobalSkillsDir(agent, homeDir3), name, "SKILL.md"),
|
|
47419
47632
|
action: "skip",
|
|
47420
47633
|
reason: "not found in this machine's corpus"
|
|
47421
47634
|
});
|
|
@@ -47447,7 +47660,7 @@ function syncSkillsToAgents(options = {}) {
|
|
|
47447
47660
|
}
|
|
47448
47661
|
function writeManagedAgentSkill(params) {
|
|
47449
47662
|
const homeDir3 = params.homeDir ?? homedir5();
|
|
47450
|
-
const dir =
|
|
47663
|
+
const dir = join32(agentGlobalSkillsDir(params.agent, homeDir3), params.skill);
|
|
47451
47664
|
const result = writeManagedSkillDir(dir, params.skillMd, {
|
|
47452
47665
|
skill: params.skill,
|
|
47453
47666
|
source: params.source,
|
|
@@ -47470,8 +47683,8 @@ function writeManagedSkillDir(dir, skillMd, options) {
|
|
|
47470
47683
|
return withCodexCorpusWrite(root2 ? [root2] : [], (assertCurrent) => writeManagedSkillDirUnlocked(dir, skillMd, options, assertCurrent), options);
|
|
47471
47684
|
}
|
|
47472
47685
|
function writeManagedSkillDirUnlocked(dir, skillMd, options, assertCurrent) {
|
|
47473
|
-
const skillMdPath =
|
|
47474
|
-
const markerPath =
|
|
47686
|
+
const skillMdPath = join32(dir, "SKILL.md");
|
|
47687
|
+
const markerPath = join32(dir, SYNC_MARKER_FILE);
|
|
47475
47688
|
const dirExists = existsSync11(dir);
|
|
47476
47689
|
const managed = hasSkillsOwnershipMarker(dir);
|
|
47477
47690
|
const hasSkillMd = existsSync11(skillMdPath);
|
|
@@ -47509,11 +47722,11 @@ function writeManagedSkillDirUnlocked(dir, skillMd, options, assertCurrent) {
|
|
|
47509
47722
|
return { action, path: skillMdPath };
|
|
47510
47723
|
const parentDir = dirname21(dir);
|
|
47511
47724
|
mkdirSync9(parentDir, { recursive: true });
|
|
47512
|
-
const transactionDir = mkdtempSync2(
|
|
47513
|
-
const candidateDir =
|
|
47514
|
-
const backupDir =
|
|
47515
|
-
const candidateSkillMdPath =
|
|
47516
|
-
const candidateMarkerPath =
|
|
47725
|
+
const transactionDir = mkdtempSync2(join32(parentDir, `.hasna-skills-write-${basename12(dir)}-`));
|
|
47726
|
+
const candidateDir = join32(transactionDir, "candidate");
|
|
47727
|
+
const backupDir = join32(transactionDir, "backup");
|
|
47728
|
+
const candidateSkillMdPath = join32(candidateDir, "SKILL.md");
|
|
47729
|
+
const candidateMarkerPath = join32(candidateDir, SYNC_MARKER_FILE);
|
|
47517
47730
|
const marker = {
|
|
47518
47731
|
managedBy: SYNC_MARKER_MANAGED_BY,
|
|
47519
47732
|
skill: options.skill,
|
|
@@ -47571,12 +47784,12 @@ function writeManagedSkillDirUnlocked(dir, skillMd, options, assertCurrent) {
|
|
|
47571
47784
|
return { action, path: skillMdPath };
|
|
47572
47785
|
}
|
|
47573
47786
|
function removeManagedAgentSkill(skill, agent, homeDir3 = homedir5(), options = {}) {
|
|
47574
|
-
const dir =
|
|
47787
|
+
const dir = join32(agentGlobalSkillsDir(agent, homeDir3), skill);
|
|
47575
47788
|
const root2 = codexCorpusRootForPath(dir);
|
|
47576
47789
|
return withCodexCorpusWrite(root2 ? [root2] : [], () => removeManagedAgentSkillUnlocked(skill, agent, homeDir3, options), options);
|
|
47577
47790
|
}
|
|
47578
47791
|
function removeManagedAgentSkillUnlocked(skill, agent, homeDir3 = homedir5(), options = {}) {
|
|
47579
|
-
const dir =
|
|
47792
|
+
const dir = join32(agentGlobalSkillsDir(agent, homeDir3), skill);
|
|
47580
47793
|
if (!hasSkillsOwnershipMarker(dir))
|
|
47581
47794
|
return false;
|
|
47582
47795
|
rmSync3(dir, { recursive: true, force: true });
|
|
@@ -47584,7 +47797,7 @@ function removeManagedAgentSkillUnlocked(skill, agent, homeDir3 = homedir5(), op
|
|
|
47584
47797
|
}
|
|
47585
47798
|
function sourceSkillMd(skillPath, name, description, kind, preferBundledDocs = false) {
|
|
47586
47799
|
if (kind === undefined || kind === "instruction" || preferBundledDocs) {
|
|
47587
|
-
const skillMdPath =
|
|
47800
|
+
const skillMdPath = join32(skillPath, "SKILL.md");
|
|
47588
47801
|
if (existsSync11(skillMdPath))
|
|
47589
47802
|
return readFileSync19(skillMdPath, "utf-8");
|
|
47590
47803
|
}
|
|
@@ -47617,7 +47830,7 @@ function normalizeSkillName(name) {
|
|
|
47617
47830
|
|
|
47618
47831
|
// src/lib/registry.ts
|
|
47619
47832
|
import { existsSync as existsSync12, readFileSync as readFileSync20, readdirSync as readdirSync12 } from "fs";
|
|
47620
|
-
import { join as
|
|
47833
|
+
import { join as join33 } from "path";
|
|
47621
47834
|
|
|
47622
47835
|
// src/lib/registry-merge.ts
|
|
47623
47836
|
var SKILL_SOURCE_PRECEDENCE = {
|
|
@@ -47827,7 +48040,7 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
47827
48040
|
for (const entry of entries) {
|
|
47828
48041
|
if (!entry.isDirectory())
|
|
47829
48042
|
continue;
|
|
47830
|
-
const skillMdPath =
|
|
48043
|
+
const skillMdPath = join33(dir, entry.name, "SKILL.md");
|
|
47831
48044
|
if (!existsSync12(skillMdPath))
|
|
47832
48045
|
continue;
|
|
47833
48046
|
let content;
|
|
@@ -47847,7 +48060,7 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
47847
48060
|
category: fm.category || "Development Tools",
|
|
47848
48061
|
tags: fm.tags || [],
|
|
47849
48062
|
...fm.kind ? { kind: fm.kind } : {},
|
|
47850
|
-
...isHostedMetadataSkillDir(
|
|
48063
|
+
...isHostedMetadataSkillDir(join33(dir, entry.name)) ? { serverOwned: true } : {},
|
|
47851
48064
|
source
|
|
47852
48065
|
});
|
|
47853
48066
|
}
|
|
@@ -47863,8 +48076,8 @@ function findExtensionSkillPath(name) {
|
|
|
47863
48076
|
for (const entry of entries) {
|
|
47864
48077
|
if (!entry.isDirectory())
|
|
47865
48078
|
continue;
|
|
47866
|
-
const skillDir =
|
|
47867
|
-
const skillMdPath =
|
|
48079
|
+
const skillDir = join33(config.extensionsDir, entry.name);
|
|
48080
|
+
const skillMdPath = join33(skillDir, "SKILL.md");
|
|
47868
48081
|
if (!existsSync12(skillMdPath))
|
|
47869
48082
|
continue;
|
|
47870
48083
|
let content;
|
|
@@ -47935,7 +48148,7 @@ function getAllTags(catalog) {
|
|
|
47935
48148
|
|
|
47936
48149
|
// src/lib/project-state.ts
|
|
47937
48150
|
import { existsSync as existsSync13, mkdirSync as mkdirSync10, readFileSync as readFileSync21, writeFileSync as writeFileSync9 } from "fs";
|
|
47938
|
-
import { join as
|
|
48151
|
+
import { join as join34 } from "path";
|
|
47939
48152
|
var VALID_PIN_SOURCES = [
|
|
47940
48153
|
"official",
|
|
47941
48154
|
"custom",
|
|
@@ -47950,10 +48163,10 @@ var SKILLS_PROJECT_DIR = ".skills";
|
|
|
47950
48163
|
var PROJECT_CONFIG_FILE = "project.json";
|
|
47951
48164
|
var DEFAULT_EXPORT_DIR = ".skills/exports";
|
|
47952
48165
|
function getProjectStateDir(targetDir = process.cwd()) {
|
|
47953
|
-
return
|
|
48166
|
+
return join34(targetDir, SKILLS_PROJECT_DIR);
|
|
47954
48167
|
}
|
|
47955
48168
|
function getProjectConfigPath(targetDir = process.cwd()) {
|
|
47956
|
-
return
|
|
48169
|
+
return join34(getProjectStateDir(targetDir), PROJECT_CONFIG_FILE);
|
|
47957
48170
|
}
|
|
47958
48171
|
function loadProjectConfig(targetDir = process.cwd()) {
|
|
47959
48172
|
const path = getProjectConfigPath(targetDir);
|
|
@@ -48082,7 +48295,7 @@ function getSkillPath(name) {
|
|
|
48082
48295
|
const extensionPath = findExtensionSkillPath(skillName);
|
|
48083
48296
|
if (extensionPath)
|
|
48084
48297
|
return extensionPath;
|
|
48085
|
-
return
|
|
48298
|
+
return join35(getPortableSkillsRoot(), skillName);
|
|
48086
48299
|
}
|
|
48087
48300
|
function getCanonicalSkillName(name) {
|
|
48088
48301
|
return getSkill(name)?.name ?? resolveSkillAlias(normalizeSkillSlug(name));
|
|
@@ -48145,7 +48358,7 @@ function createLocalSkillManifest(name, generateSkillMd) {
|
|
|
48145
48358
|
if (!existsSync14(sourcePath))
|
|
48146
48359
|
return null;
|
|
48147
48360
|
let skillMd = "";
|
|
48148
|
-
const skillMdPath =
|
|
48361
|
+
const skillMdPath = join35(sourcePath, "SKILL.md");
|
|
48149
48362
|
if (existsSync14(skillMdPath)) {
|
|
48150
48363
|
skillMd = readFileSync22(skillMdPath, "utf-8");
|
|
48151
48364
|
} else if (generateSkillMd) {
|
|
@@ -48219,16 +48432,16 @@ function getAgentSkillsDir(agent, scope = "global", projectDir) {
|
|
|
48219
48432
|
const base = projectDir || process.cwd();
|
|
48220
48433
|
switch (agent) {
|
|
48221
48434
|
case "pi":
|
|
48222
|
-
return scope === "project" ?
|
|
48435
|
+
return scope === "project" ? join35(base, ".pi", "skills") : join35(homedir6(), ".pi", "agent", "skills");
|
|
48223
48436
|
case "opencode":
|
|
48224
|
-
return scope === "project" ?
|
|
48437
|
+
return scope === "project" ? join35(base, ".opencode", "skills") : join35(homedir6(), ".config", "opencode", "skills");
|
|
48225
48438
|
default:
|
|
48226
|
-
return scope === "project" ?
|
|
48439
|
+
return scope === "project" ? join35(base, `.${agent}`, "skills") : join35(homedir6(), `.${agent}`, "skills");
|
|
48227
48440
|
}
|
|
48228
48441
|
}
|
|
48229
48442
|
function getAgentSkillPath(name, agent, scope = "global", projectDir) {
|
|
48230
48443
|
const skillName = normalizeSkillName(getCanonicalSkillName(name));
|
|
48231
|
-
return
|
|
48444
|
+
return join35(getAgentSkillsDir(agent, scope, projectDir), skillName);
|
|
48232
48445
|
}
|
|
48233
48446
|
function installSkillForAgent(name, options, generateSkillMd) {
|
|
48234
48447
|
assertNativeExportAllowed();
|
|
@@ -48271,7 +48484,7 @@ function removeSkillForAgentUnlocked(name, options) {
|
|
|
48271
48484
|
}
|
|
48272
48485
|
function resolveAgentSkillMd(name, generateSkillMd) {
|
|
48273
48486
|
const sourcePath = getSkillPath(name);
|
|
48274
|
-
const skillMdPath =
|
|
48487
|
+
const skillMdPath = join35(sourcePath, "SKILL.md");
|
|
48275
48488
|
if (existsSync14(skillMdPath))
|
|
48276
48489
|
return readFileSync22(skillMdPath, "utf-8");
|
|
48277
48490
|
if (generateSkillMd)
|
|
@@ -48306,7 +48519,7 @@ function generateMinimalSkillMd(name) {
|
|
|
48306
48519
|
"---",
|
|
48307
48520
|
""
|
|
48308
48521
|
].filter(Boolean);
|
|
48309
|
-
const fallbackDoc = readFileIfExists(
|
|
48522
|
+
const fallbackDoc = readFileIfExists(join35(sourcePath, "README.md")) || readFileIfExists(join35(sourcePath, "CLAUDE.md"));
|
|
48310
48523
|
if (fallbackDoc)
|
|
48311
48524
|
return `${frontmatter.join(`
|
|
48312
48525
|
`)}${fallbackDoc.trim()}
|
|
@@ -48325,7 +48538,7 @@ skills run ${canonicalName}
|
|
|
48325
48538
|
`;
|
|
48326
48539
|
}
|
|
48327
48540
|
function readBundledSkillVersion(name) {
|
|
48328
|
-
const pkgPath =
|
|
48541
|
+
const pkgPath = join35(getSkillPath(name), "package.json");
|
|
48329
48542
|
if (!existsSync14(pkgPath))
|
|
48330
48543
|
return "unknown";
|
|
48331
48544
|
try {
|
|
@@ -48380,7 +48593,7 @@ function selectSkillDoc(docs, file) {
|
|
|
48380
48593
|
function isInstructionSkillDir(skillPath, meta) {
|
|
48381
48594
|
if (meta?.kind === "instruction")
|
|
48382
48595
|
return true;
|
|
48383
|
-
const skillMdPath =
|
|
48596
|
+
const skillMdPath = join36(skillPath, "SKILL.md");
|
|
48384
48597
|
if (!existsSync15(skillMdPath))
|
|
48385
48598
|
return false;
|
|
48386
48599
|
try {
|
|
@@ -48410,9 +48623,9 @@ function getSkillDocs(name) {
|
|
|
48410
48623
|
if (!existsSync15(skillPath))
|
|
48411
48624
|
return null;
|
|
48412
48625
|
return {
|
|
48413
|
-
skillMd: readIfExists(
|
|
48414
|
-
readme: readIfExists(
|
|
48415
|
-
claudeMd: readIfExists(
|
|
48626
|
+
skillMd: readIfExists(join36(skillPath, "SKILL.md")),
|
|
48627
|
+
readme: readIfExists(join36(skillPath, "README.md")),
|
|
48628
|
+
claudeMd: readIfExists(join36(skillPath, "CLAUDE.md"))
|
|
48416
48629
|
};
|
|
48417
48630
|
}
|
|
48418
48631
|
function getSkillBestDoc(name, file) {
|
|
@@ -48428,14 +48641,14 @@ function getSkillRequirements(name) {
|
|
|
48428
48641
|
return null;
|
|
48429
48642
|
const texts = [];
|
|
48430
48643
|
for (const file of ["SKILL.md", "README.md", "CLAUDE.md", ".env.example", ".env.local.example"]) {
|
|
48431
|
-
const content = readIfExists(
|
|
48644
|
+
const content = readIfExists(join36(skillPath, file));
|
|
48432
48645
|
if (content)
|
|
48433
48646
|
texts.push(content);
|
|
48434
48647
|
}
|
|
48435
48648
|
const meta = getSkill(name);
|
|
48436
48649
|
let dependencies = {};
|
|
48437
48650
|
try {
|
|
48438
|
-
dependencies = JSON.parse(readFileSync23(
|
|
48651
|
+
dependencies = JSON.parse(readFileSync23(join36(skillPath, "package.json"), "utf8")).dependencies || {};
|
|
48439
48652
|
} catch {}
|
|
48440
48653
|
return getSkillRequirementsFromContent(name, texts, dependencies, meta);
|
|
48441
48654
|
}
|
|
@@ -48497,7 +48710,7 @@ async function runSkill(name, args, options = {}) {
|
|
|
48497
48710
|
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'.`
|
|
48498
48711
|
};
|
|
48499
48712
|
}
|
|
48500
|
-
const pkgPath =
|
|
48713
|
+
const pkgPath = join36(skillPath, "package.json");
|
|
48501
48714
|
if (!existsSync15(pkgPath)) {
|
|
48502
48715
|
return { exitCode: 1, error: `No package.json in skill '${name}'` };
|
|
48503
48716
|
}
|
|
@@ -48517,12 +48730,12 @@ async function runSkill(name, args, options = {}) {
|
|
|
48517
48730
|
} catch {
|
|
48518
48731
|
return { exitCode: 1, error: `Failed to parse package.json for skill '${name}'` };
|
|
48519
48732
|
}
|
|
48520
|
-
const entryPath =
|
|
48733
|
+
const entryPath = join36(skillPath, entryPoint2);
|
|
48521
48734
|
if (!existsSync15(entryPath)) {
|
|
48522
48735
|
return { exitCode: 1, error: `Entry point '${entryPoint2}' not found in skill '${name}'` };
|
|
48523
48736
|
}
|
|
48524
48737
|
const env = { ...process.env, ...options.env };
|
|
48525
|
-
if (!existsSync15(
|
|
48738
|
+
if (!existsSync15(join36(skillPath, "node_modules")) || hasDependencyPreparationMarker(skillPath)) {
|
|
48526
48739
|
const failure = await prepareSkillDependencies(skillPath, env, options.preparationTimeoutMs);
|
|
48527
48740
|
if (failure)
|
|
48528
48741
|
return failure;
|
|
@@ -48600,10 +48813,10 @@ function generateSkillMd(name) {
|
|
|
48600
48813
|
"---"
|
|
48601
48814
|
].join(`
|
|
48602
48815
|
`);
|
|
48603
|
-
const readme = readIfExists(
|
|
48604
|
-
const claudeMd = readIfExists(
|
|
48816
|
+
const readme = readIfExists(join36(skillPath, "README.md"));
|
|
48817
|
+
const claudeMd = readIfExists(join36(skillPath, "CLAUDE.md"));
|
|
48605
48818
|
let cliCommand = null;
|
|
48606
|
-
const pkgPath =
|
|
48819
|
+
const pkgPath = join36(skillPath, "package.json");
|
|
48607
48820
|
if (existsSync15(pkgPath)) {
|
|
48608
48821
|
try {
|
|
48609
48822
|
const pkg = JSON.parse(readFileSync23(pkgPath, "utf-8"));
|
|
@@ -48887,7 +49100,7 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
48887
49100
|
throw new SkillSelectionError("INVALID_SECRET_BINDINGS", "Explicit environment values must be bounded strings without NUL bytes.");
|
|
48888
49101
|
secretEnv[name] = value;
|
|
48889
49102
|
}
|
|
48890
|
-
const runDirectory = mkdtempSync3(
|
|
49103
|
+
const runDirectory = mkdtempSync3(join37(tmpdir(), "skills-execution-"));
|
|
48891
49104
|
const paths = new SkillEntryPaths;
|
|
48892
49105
|
for (const entry of entries) {
|
|
48893
49106
|
paths.add(entry.path, 100, () => {
|
|
@@ -48895,7 +49108,7 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
48895
49108
|
}, () => {
|
|
48896
49109
|
throw new SkillSelectionError("INVALID_BUNDLE_PATH", "The execution bundle path exceeds its limit.");
|
|
48897
49110
|
});
|
|
48898
|
-
const destination =
|
|
49111
|
+
const destination = join37(runDirectory, entry.path);
|
|
48899
49112
|
mkdirSync11(dirname22(destination), { recursive: true, mode: 448 });
|
|
48900
49113
|
writeFileSync10(destination, entry.bytes, { flag: "wx", mode: entry.mode & 511 });
|
|
48901
49114
|
}
|
|
@@ -48923,20 +49136,20 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
48923
49136
|
}
|
|
48924
49137
|
if (bindings)
|
|
48925
49138
|
secretEnv = await resolveSelectedSecrets(bindings, options.createSecretsClient);
|
|
48926
|
-
const result = await subprocess([executable2, ...runtimeName === "bun" ? ["--no-env-file"] : [],
|
|
49139
|
+
const result = await subprocess([executable2, ...runtimeName === "bun" ? ["--no-env-file"] : [], join37(runDirectory, declaredEntry), ...args], runDirectory, { ...env, ...secretEnv }, input, timeoutMs);
|
|
48927
49140
|
result.stdout = redactExecutionSecrets(result.stdout, secretEnv);
|
|
48928
49141
|
result.stderr = redactExecutionSecrets(result.stderr, secretEnv);
|
|
48929
49142
|
const receipt = {
|
|
48930
49143
|
selection: selection2,
|
|
48931
49144
|
target: "local",
|
|
48932
49145
|
runtime: runtimeName,
|
|
48933
|
-
inputDigest: `sha256:${
|
|
49146
|
+
inputDigest: `sha256:${createHash25("sha256").update(input).digest("hex")}`,
|
|
48934
49147
|
runDirectory,
|
|
48935
49148
|
...executionGrant ? { executionGrant } : {},
|
|
48936
49149
|
...bindings ? { secretBinding: { schema: bindings.schema, selection: bindings.selection, consumer: bindings.consumer, secretsAuthority: bindings.secretsAuthority, bindings: bindings.bindings } } : {},
|
|
48937
49150
|
...result
|
|
48938
49151
|
};
|
|
48939
|
-
writeFileSync10(
|
|
49152
|
+
writeFileSync10(join37(runDirectory, ".execution-receipt.json"), JSON.stringify({ ...receipt, stdout: undefined, stderr: undefined }), { mode: 384 });
|
|
48940
49153
|
return receipt;
|
|
48941
49154
|
}
|
|
48942
49155
|
async function subprocess(command, cwd, env, input, timeoutMs) {
|
|
@@ -49456,7 +49669,7 @@ var { booleanSelector, SelectorType: SelectorType2 } = require_config();
|
|
|
49456
49669
|
var { setFeature: setFeature2 } = require_client2();
|
|
49457
49670
|
var { httpSigningMiddlewareOptions } = require_dist_cjs2();
|
|
49458
49671
|
var { Readable } = __require("stream");
|
|
49459
|
-
var { validate, parse:
|
|
49672
|
+
var { validate, parse: parse8 } = require_util();
|
|
49460
49673
|
var { AwsRestXmlProtocol } = require_protocols2();
|
|
49461
49674
|
var { NormalizedSchema } = require_schema4();
|
|
49462
49675
|
var CONTENT_LENGTH_HEADER = "content-length";
|
|
@@ -58220,7 +58433,7 @@ var import_node_http_handler2 = __toESM(require_dist_cjs6(), 1);
|
|
|
58220
58433
|
|
|
58221
58434
|
// node_modules/@aws-sdk/checksums/dist-cjs/submodules/sha/index.js
|
|
58222
58435
|
var { toUint8Array: toUint8Array2, concatBytes } = require_serde();
|
|
58223
|
-
var { createHmac: createHmac2, createHash:
|
|
58436
|
+
var { createHmac: createHmac2, createHash: createHash27 } = __require("crypto");
|
|
58224
58437
|
var { Sha256: Sha2562, Sha256Js, Sha256Node } = require_checksum();
|
|
58225
58438
|
var BLOCK2 = 64;
|
|
58226
58439
|
var DIGEST_LENGTH = 20;
|
|
@@ -58389,7 +58602,7 @@ class Sha1Js {
|
|
|
58389
58602
|
}
|
|
58390
58603
|
var hasNativeCrypto = (() => {
|
|
58391
58604
|
try {
|
|
58392
|
-
|
|
58605
|
+
createHash27("sha1");
|
|
58393
58606
|
return true;
|
|
58394
58607
|
} catch {
|
|
58395
58608
|
return false;
|
|
@@ -58429,7 +58642,7 @@ function buildNativeClass() {
|
|
|
58429
58642
|
this.finished = false;
|
|
58430
58643
|
}
|
|
58431
58644
|
createHash() {
|
|
58432
|
-
return this.secret ? createHmac2("sha1", toBuffer(this.secret)) :
|
|
58645
|
+
return this.secret ? createHmac2("sha1", toBuffer(this.secret)) : createHash27("sha1");
|
|
58433
58646
|
}
|
|
58434
58647
|
};
|
|
58435
58648
|
}
|
|
@@ -59001,7 +59214,7 @@ import { mkdirSync as mkdirSync13 } from "fs";
|
|
|
59001
59214
|
import { dirname as dirname26 } from "path";
|
|
59002
59215
|
|
|
59003
59216
|
// src/server/database-url.ts
|
|
59004
|
-
import { isAbsolute as isAbsolute21, join as
|
|
59217
|
+
import { isAbsolute as isAbsolute21, join as join39 } from "path";
|
|
59005
59218
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
59006
59219
|
var DEFAULT_SQLITE_FILENAME2 = "server.db";
|
|
59007
59220
|
var SQLITE_MEMORY_PATH = ":memory:";
|
|
@@ -59010,7 +59223,7 @@ var SQLITE_SCHEMES = new Set(["sqlite", "sqlite3", "file"]);
|
|
|
59010
59223
|
var MEMORY_SCHEMES = new Set(["memory"]);
|
|
59011
59224
|
var SQLITE_EXTENSIONS = [".db", ".sqlite", ".sqlite3", ".db3"];
|
|
59012
59225
|
function defaultSqlitePath() {
|
|
59013
|
-
return
|
|
59226
|
+
return join39(getDataDir(), DEFAULT_SQLITE_FILENAME2);
|
|
59014
59227
|
}
|
|
59015
59228
|
function resolveDatabaseTarget(raw) {
|
|
59016
59229
|
const value = raw?.trim();
|
|
@@ -59037,7 +59250,7 @@ function resolveDatabaseTarget(raw) {
|
|
|
59037
59250
|
throw new Error(`unsupported database scheme "${scheme}:". Supported: postgres://, postgresql://, sqlite:, file:, ` + `an absolute or relative path to a .db/.sqlite file, ":memory:", or "memory:" (non-durable, tests only). ` + `Leave the setting empty to use the default SQLite database at ${defaultSqlitePath()}.`);
|
|
59038
59251
|
}
|
|
59039
59252
|
if (looksLikeSqlitePath(value)) {
|
|
59040
|
-
const path = isAbsolute21(value) ? value :
|
|
59253
|
+
const path = isAbsolute21(value) ? value : join39(process.cwd(), value);
|
|
59041
59254
|
return { kind: "sqlite", path, durable: true, label: `sqlite (${path})` };
|
|
59042
59255
|
}
|
|
59043
59256
|
throw new Error(`could not resolve a database backend from "${value}". Use postgres://\u2026, sqlite:\u2026, an absolute or ` + `relative path ending in ${SQLITE_EXTENSIONS.join("/")}, ":memory:", or leave it empty for the ` + `default SQLite database at ${defaultSqlitePath()}.`);
|
|
@@ -59061,7 +59274,7 @@ function sqlitePathFromUrl(value, scheme) {
|
|
|
59061
59274
|
}
|
|
59062
59275
|
return rest.slice(2).replace(/^\/\/+/, "/");
|
|
59063
59276
|
}
|
|
59064
|
-
return isAbsolute21(rest) ? rest :
|
|
59277
|
+
return isAbsolute21(rest) ? rest : join39(process.cwd(), rest);
|
|
59065
59278
|
}
|
|
59066
59279
|
function looksLikeSqlitePath(value) {
|
|
59067
59280
|
if (value.includes("/"))
|
|
@@ -59294,12 +59507,12 @@ class PostgresSkillSelectionStore {
|
|
|
59294
59507
|
// src/server/sqlite-store.ts
|
|
59295
59508
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
59296
59509
|
import { mkdirSync as mkdirSync12, readFileSync as readFileSync25, readdirSync as readdirSync13 } from "fs";
|
|
59297
|
-
import { dirname as dirname25, join as
|
|
59510
|
+
import { dirname as dirname25, join as join41 } from "path";
|
|
59298
59511
|
|
|
59299
59512
|
// src/server/auth.ts
|
|
59300
|
-
import { createHash as
|
|
59513
|
+
import { createHash as createHash28 } from "crypto";
|
|
59301
59514
|
function hashApiKey(token) {
|
|
59302
|
-
return
|
|
59515
|
+
return createHash28("sha256").update(token).digest("hex");
|
|
59303
59516
|
}
|
|
59304
59517
|
function bearerToken(request2) {
|
|
59305
59518
|
const header = request2.headers.get("authorization") || "";
|
|
@@ -59353,15 +59566,15 @@ function permitsSkillsRoute(principal, method, resource) {
|
|
|
59353
59566
|
|
|
59354
59567
|
// src/server/migrations-dir.ts
|
|
59355
59568
|
import { existsSync as existsSync16 } from "fs";
|
|
59356
|
-
import { dirname as dirname24, join as
|
|
59569
|
+
import { dirname as dirname24, join as join40 } from "path";
|
|
59357
59570
|
var MIGRATION_DIALECTS = ["postgres", "sqlite"];
|
|
59358
59571
|
var MAX_WALK_UP = 6;
|
|
59359
59572
|
function findMigrationsRoot(startDirs = defaultStartDirs()) {
|
|
59360
59573
|
for (const start of startDirs) {
|
|
59361
59574
|
let dir = start;
|
|
59362
59575
|
for (let level = 0;level < MAX_WALK_UP; level += 1) {
|
|
59363
|
-
const candidate2 =
|
|
59364
|
-
if (MIGRATION_DIALECTS.some((dialect) => existsSync16(
|
|
59576
|
+
const candidate2 = join40(dir, "migrations");
|
|
59577
|
+
if (MIGRATION_DIALECTS.some((dialect) => existsSync16(join40(candidate2, dialect))))
|
|
59365
59578
|
return candidate2;
|
|
59366
59579
|
const parent = dirname24(dir);
|
|
59367
59580
|
if (parent === dir)
|
|
@@ -59375,7 +59588,7 @@ function resolveMigrationsDir(dialect, root4 = findMigrationsRoot()) {
|
|
|
59375
59588
|
if (!root4) {
|
|
59376
59589
|
throw new Error(`could not locate the migrations directory for dialect "${dialect}". ` + `Expected a migrations/${dialect}/ folder alongside the package root.`);
|
|
59377
59590
|
}
|
|
59378
|
-
const dir =
|
|
59591
|
+
const dir = join40(root4, dialect);
|
|
59379
59592
|
if (!existsSync16(dir)) {
|
|
59380
59593
|
throw new Error(`migrations directory not found: ${dir}`);
|
|
59381
59594
|
}
|
|
@@ -59471,6 +59684,7 @@ function rowToSkill(row) {
|
|
|
59471
59684
|
revisionNumber: Number(row.revision_number ?? 0),
|
|
59472
59685
|
...row.tombstoned_at ? { tombstonedAt: dateString(row.tombstoned_at) } : {},
|
|
59473
59686
|
...row.tombstone_purge_after ? { tombstonePurgeAfter: dateString(row.tombstone_purge_after) } : {},
|
|
59687
|
+
...typeof row.authorization_epoch === "string" ? { authorizationEpoch: row.authorization_epoch } : {},
|
|
59474
59688
|
lifecycle: row.lifecycle === "archived" ? "archived" : "active",
|
|
59475
59689
|
...row.archived_at ? { archivedAt: dateString(row.archived_at) } : {},
|
|
59476
59690
|
...row.archive_reason ? { archiveReason: String(row.archive_reason) } : {},
|
|
@@ -59482,6 +59696,7 @@ function rowToPublishedSelectionState(row) {
|
|
|
59482
59696
|
slug: String(row.slug),
|
|
59483
59697
|
version: String(row.version),
|
|
59484
59698
|
current: row.skill_exists ? {
|
|
59699
|
+
...typeof row.authorization_epoch === "string" ? { authorizationEpoch: row.authorization_epoch } : {},
|
|
59485
59700
|
lifecycle: row.lifecycle === "archived" ? "archived" : "active",
|
|
59486
59701
|
...row.tombstoned_at ? { tombstonedAt: dateString(row.tombstoned_at) } : {}
|
|
59487
59702
|
} : null,
|
|
@@ -59621,7 +59836,7 @@ function validOperatorScopeEnrollmentInput(input) {
|
|
|
59621
59836
|
}
|
|
59622
59837
|
|
|
59623
59838
|
// src/lib/revision.ts
|
|
59624
|
-
import { createHash as
|
|
59839
|
+
import { createHash as createHash29 } from "crypto";
|
|
59625
59840
|
var REVISION_ID_PATTERN = /^[0-9a-f]{64}$/;
|
|
59626
59841
|
function revisionIdOf(content) {
|
|
59627
59842
|
const canonicalContent = {
|
|
@@ -59642,8 +59857,8 @@ function revisionIdOf(content) {
|
|
|
59642
59857
|
canonicalContent.archiveReason = content.archiveReason ?? null;
|
|
59643
59858
|
canonicalContent.replacementSlug = content.replacementSlug ?? null;
|
|
59644
59859
|
}
|
|
59645
|
-
const
|
|
59646
|
-
return
|
|
59860
|
+
const canonical7 = JSON.stringify(canonicalContent);
|
|
59861
|
+
return createHash29("sha256").update(canonical7).digest("hex");
|
|
59647
59862
|
}
|
|
59648
59863
|
function revisionIdOfRecord(record4) {
|
|
59649
59864
|
return revisionIdOf(record4);
|
|
@@ -60125,7 +60340,7 @@ class SqliteSkillsStore {
|
|
|
60125
60340
|
continue;
|
|
60126
60341
|
insertTag.run(orgId, input.slug, tag);
|
|
60127
60342
|
}
|
|
60128
|
-
return
|
|
60343
|
+
return this.getSkillSync(input.principal, input.slug);
|
|
60129
60344
|
})();
|
|
60130
60345
|
}
|
|
60131
60346
|
async listSkills(principal) {
|
|
@@ -60162,7 +60377,7 @@ class SqliteSkillsStore {
|
|
|
60162
60377
|
const row = this.get("UPDATE skills_registry SET lifecycle=?, archived_at=?, archive_reason=?, replacement_slug=?, revision_id=?, revision_number=revision_number+1, updated_at=? WHERE org_id=? AND slug=? AND tombstoned_at IS NULL AND revision_id=? RETURNING *", [next2.lifecycle, next2.archivedAt ?? null, next2.archiveReason ?? null, next2.replacementSlug ?? null, revisionIdOfRecord(next2), next2.updatedAt, principal.orgId, slug, current.revisionId]);
|
|
60163
60378
|
if (!row)
|
|
60164
60379
|
throw new SkillRevisionConflictError(slug, expectedRevisionId, this.getSkillSync(principal, slug)?.revisionId ?? null);
|
|
60165
|
-
return
|
|
60380
|
+
return this.getSkillSync(principal, slug);
|
|
60166
60381
|
}).immediate();
|
|
60167
60382
|
}
|
|
60168
60383
|
getSkillSync(principal, slug) {
|
|
@@ -60233,7 +60448,7 @@ class SqliteSkillsStore {
|
|
|
60233
60448
|
SET tombstoned_at = ?, tombstone_purge_after = ?, updated_at = ?
|
|
60234
60449
|
WHERE org_id = ? AND slug = ?
|
|
60235
60450
|
RETURNING *`, [tombstonedAt, purgeAfter, tombstonedAt, principal.orgId, slug]);
|
|
60236
|
-
return
|
|
60451
|
+
return this.getSkillSync(principal, slug);
|
|
60237
60452
|
})();
|
|
60238
60453
|
}
|
|
60239
60454
|
async purgeExpiredTombstones(principal) {
|
|
@@ -60270,7 +60485,7 @@ class SqliteSkillsStore {
|
|
|
60270
60485
|
return [];
|
|
60271
60486
|
const requested = JSON.stringify(selections2.map(({ slug, version: version2 }) => ({ slug, version: version2 })));
|
|
60272
60487
|
return this.all(`SELECT json_extract(q.value, '$.slug') AS slug, json_extract(q.value, '$.version') AS version,
|
|
60273
|
-
r.slug IS NOT NULL AS skill_exists, r.lifecycle, r.tombstoned_at,
|
|
60488
|
+
r.slug IS NOT NULL AS skill_exists, r.lifecycle, r.tombstoned_at, r.authorization_epoch,
|
|
60274
60489
|
v.bundle_sha256, b.sha256 IS NOT NULL AS bundle_available
|
|
60275
60490
|
FROM json_each(?) q
|
|
60276
60491
|
LEFT JOIN skills_registry r ON r.org_id = ? AND r.slug = json_extract(q.value, '$.slug')
|
|
@@ -60347,7 +60562,7 @@ function applySqliteMigrations(db, migrationsDir = resolveMigrationsDir("sqlite"
|
|
|
60347
60562
|
const appliedNow = [];
|
|
60348
60563
|
for (const file of files) {
|
|
60349
60564
|
const version2 = file.replace(/\.sql$/, "");
|
|
60350
|
-
const text2 = readFileSync25(
|
|
60565
|
+
const text2 = readFileSync25(join41(migrationsDir, file), "utf8");
|
|
60351
60566
|
const apply = db.transaction(() => {
|
|
60352
60567
|
const already = db.query("SELECT 1 AS present FROM schema_migrations WHERE version = ? LIMIT 1").get(version2);
|
|
60353
60568
|
if (already)
|
|
@@ -60727,7 +60942,7 @@ function nextMonthPrefix(monthPrefix) {
|
|
|
60727
60942
|
}
|
|
60728
60943
|
|
|
60729
60944
|
// src/server/skills-api.ts
|
|
60730
|
-
import { createHash as
|
|
60945
|
+
import { createHash as createHash30 } from "crypto";
|
|
60731
60946
|
var SLUG_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
|
|
60732
60947
|
var SHA256_HEX2 = /^[0-9a-f]{64}$/;
|
|
60733
60948
|
var MAX_SLUG_LENGTH = 128;
|
|
@@ -60917,7 +61132,7 @@ async function parsePublishRequest(request2, config) {
|
|
|
60917
61132
|
if (bundleBytes.byteLength === 0) {
|
|
60918
61133
|
throw new SkillRequestError(400, "BUNDLE_EMPTY", "the uploaded bundle is empty");
|
|
60919
61134
|
}
|
|
60920
|
-
const sha2562 =
|
|
61135
|
+
const sha2562 = createHash30("sha256").update(bundleBytes).digest("hex");
|
|
60921
61136
|
const claimed = optionalString(manifest.bundleSha256);
|
|
60922
61137
|
if (claimed)
|
|
60923
61138
|
assertSha2562(claimed);
|
|
@@ -61032,7 +61247,7 @@ async function readPublishedBundle(store, artifactStorage, principal, slug) {
|
|
|
61032
61247
|
if (!bytes) {
|
|
61033
61248
|
throw new SkillRequestError(503, "BUNDLE_BACKEND_UNAVAILABLE", "bundle storage backend unavailable");
|
|
61034
61249
|
}
|
|
61035
|
-
const actual =
|
|
61250
|
+
const actual = createHash30("sha256").update(bytes).digest("hex");
|
|
61036
61251
|
if (actual !== record4.bundleSha256) {
|
|
61037
61252
|
throw new SkillRequestError(500, "BUNDLE_DIGEST_DRIFT", `stored bundle for '${slug}' hashes to ${actual} but was published as ${record4.bundleSha256}`);
|
|
61038
61253
|
}
|
|
@@ -61180,11 +61395,11 @@ async function readSkillVersionBundle(store, artifactStorage, principal, slug, v
|
|
|
61180
61395
|
const bytes = await artifactStorage.readBundle(bundle2);
|
|
61181
61396
|
if (!bytes)
|
|
61182
61397
|
throw new SkillRequestError(503, "BUNDLE_BACKEND_UNAVAILABLE", "bundle storage backend unavailable");
|
|
61183
|
-
const actual =
|
|
61398
|
+
const actual = createHash30("sha256").update(bytes).digest("hex");
|
|
61184
61399
|
if (actual !== found.bundleSha256) {
|
|
61185
61400
|
throw new SkillRequestError(500, "BUNDLE_DIGEST_DRIFT", `stored bundle for '${slug}@${version2}' hashes to ${actual} but was published as ${found.bundleSha256}`);
|
|
61186
61401
|
}
|
|
61187
|
-
return { version: found, bytes };
|
|
61402
|
+
return { version: found, bytes, authorizationEpoch: resolved.record.authorizationEpoch };
|
|
61188
61403
|
}
|
|
61189
61404
|
function publishVersionOf(manifest) {
|
|
61190
61405
|
const version2 = optionalString(manifest.version);
|
|
@@ -61424,6 +61639,7 @@ async function validatePublished(store, principal, selections2) {
|
|
|
61424
61639
|
if (!state2.bundleAvailable)
|
|
61425
61640
|
throw new SkillRequestError(503, "SELECTION_BUNDLE_UNAVAILABLE", "Selected bundle is unavailable");
|
|
61426
61641
|
}
|
|
61642
|
+
return states;
|
|
61427
61643
|
}
|
|
61428
61644
|
async function body2(request2, limit) {
|
|
61429
61645
|
if (!request2.body)
|
|
@@ -61484,6 +61700,7 @@ async function handleProfileApi(store, principal, request2, parts, config) {
|
|
|
61484
61700
|
capabilities: [
|
|
61485
61701
|
"skills.registry",
|
|
61486
61702
|
"skills.versions",
|
|
61703
|
+
"skills.session-pin-renewal",
|
|
61487
61704
|
...store.selectionStore && store.executionGrantStore ? ["skills.execution-grants"] : [],
|
|
61488
61705
|
...store.selectionStore ? ["skills.profiles", "skills.station-state"] : []
|
|
61489
61706
|
],
|
|
@@ -61529,6 +61746,7 @@ async function handleProfileApi(store, principal, request2, parts, config) {
|
|
|
61529
61746
|
const authority2 = skillsApiRequestUrl(normalizeSkillsApiOrigin(config.publicBaseUrl), "/api/v1/").replace(/\/+$/, "");
|
|
61530
61747
|
const revision = "x".repeat(128);
|
|
61531
61748
|
const projected2 = resolvedProfileSnapshot({ id: id2, workspaceId: principal.orgId, revision, selections: selections2 }, authority2);
|
|
61749
|
+
projected2.selections = projected2.selections.map((selection2) => ({ ...selection2, authorizationEpoch: "0".repeat(32) }));
|
|
61532
61750
|
if (profileDocumentBytes(projected2) > MAX_RESOLVED_PROFILE_BYTES || profileDocumentBytes({ profileId: id2, profileRevision: revision, selections: selections2 }) > Math.min(config.requestBodyLimitBytes, MAX_PROFILE_DOCUMENT_BYTES)) {
|
|
61533
61751
|
throw new SkillRequestError(413, "PROFILE_TOO_LARGE", "The complete resolved profile and station/session receipts must fit the advertised profile limits");
|
|
61534
61752
|
}
|
|
@@ -61550,7 +61768,17 @@ async function handleProfileApi(store, principal, request2, parts, config) {
|
|
|
61550
61768
|
const result = resolvedProfileSnapshot(profile2, authority2);
|
|
61551
61769
|
if (result.selections.length > MAX_PROFILE_SELECTIONS || profileDocumentBytes(result) > MAX_RESOLVED_PROFILE_BYTES)
|
|
61552
61770
|
throw new SkillRequestError(413, "PROFILE_TOO_LARGE", "Resolved profile exceeds the advertised profile limits");
|
|
61553
|
-
await validatePublished(store, principal, profile2.selections);
|
|
61771
|
+
const states = await validatePublished(store, principal, profile2.selections);
|
|
61772
|
+
if (new URL(request2.url).searchParams.get("pinAuthorization") === "epoch-v1") {
|
|
61773
|
+
result.selections = result.selections.map((selection2, index) => {
|
|
61774
|
+
const epoch = states[index].current?.authorizationEpoch;
|
|
61775
|
+
if (!epoch || !/^[a-f0-9]{32}$/.test(epoch))
|
|
61776
|
+
throw new SkillRequestError(503, "PIN_AUTHORIZATION_UNAVAILABLE", "The selection lifecycle fence is unavailable");
|
|
61777
|
+
return { ...selection2, authorizationEpoch: epoch };
|
|
61778
|
+
});
|
|
61779
|
+
}
|
|
61780
|
+
if (profileDocumentBytes(result) > MAX_RESOLVED_PROFILE_BYTES)
|
|
61781
|
+
throw new SkillRequestError(413, "PROFILE_TOO_LARGE", "Resolved profile exceeds the advertised profile limits");
|
|
61554
61782
|
return json2(result, 200, profile2.revision);
|
|
61555
61783
|
}
|
|
61556
61784
|
if (resource === "stations" && parts.length === 3 && child === "state") {
|
|
@@ -61883,7 +62111,7 @@ class RuntimeExecutionStore {
|
|
|
61883
62111
|
}
|
|
61884
62112
|
|
|
61885
62113
|
// src/sdk/execution/admission.ts
|
|
61886
|
-
import { createHash as
|
|
62114
|
+
import { createHash as createHash32 } from "crypto";
|
|
61887
62115
|
|
|
61888
62116
|
// src/sdk/execution/image-profile.ts
|
|
61889
62117
|
class ImageProfileResolutionError extends Error {
|
|
@@ -62495,11 +62723,11 @@ function ownedAdmission(admission) {
|
|
|
62495
62723
|
};
|
|
62496
62724
|
}
|
|
62497
62725
|
function digestInput(input) {
|
|
62498
|
-
return
|
|
62726
|
+
return createHash32("sha256").update(canonicalJson2(input)).digest("hex");
|
|
62499
62727
|
}
|
|
62500
62728
|
|
|
62501
62729
|
// src/sdk/execution/dispatchers/ecs.ts
|
|
62502
|
-
import { createHash as
|
|
62730
|
+
import { createHash as createHash33 } from "crypto";
|
|
62503
62731
|
|
|
62504
62732
|
// src/sdk/execution/state-machine.ts
|
|
62505
62733
|
var LEGAL_TRANSITIONS = {
|
|
@@ -65899,13 +66127,13 @@ function observedTask(states, taskArn) {
|
|
|
65899
66127
|
return state2.lastStatus === "STOPPED" || LIVE_TASK_STATUSES.has(state2.lastStatus) ? state2 : undefined;
|
|
65900
66128
|
}
|
|
65901
66129
|
function clientTokenFor(runId3, attemptId) {
|
|
65902
|
-
return
|
|
66130
|
+
return createHash33("sha256").update(`${runId3}\x00${attemptId}`).digest("hex").slice(0, CLIENT_TOKEN_BYTES * 2);
|
|
65903
66131
|
}
|
|
65904
66132
|
function startedByFor(runId3, attemptNumber) {
|
|
65905
66133
|
return `skills-exec/${runId3}/a${attemptNumber}`;
|
|
65906
66134
|
}
|
|
65907
66135
|
function requestDigestFor(admission, attemptId) {
|
|
65908
|
-
return
|
|
66136
|
+
return createHash33("sha256").update(canonicalJson2({ admission, attemptId })).digest("hex");
|
|
65909
66137
|
}
|
|
65910
66138
|
|
|
65911
66139
|
class EcsDispatcher {
|
|
@@ -66201,10 +66429,10 @@ function validText(value) {
|
|
|
66201
66429
|
}
|
|
66202
66430
|
|
|
66203
66431
|
// src/server/runtime-policy.ts
|
|
66204
|
-
import { createHash as
|
|
66432
|
+
import { createHash as createHash35, createHmac as createHmac3, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
66205
66433
|
|
|
66206
66434
|
// src/server/runtime-pure-contract.ts
|
|
66207
|
-
import { createHash as
|
|
66435
|
+
import { createHash as createHash34 } from "crypto";
|
|
66208
66436
|
var PURE_DESCRIPTOR = Object.freeze({
|
|
66209
66437
|
id: "regex-test.v1",
|
|
66210
66438
|
runtime: "bun",
|
|
@@ -66228,7 +66456,7 @@ var PURE_LIMITS = Object.freeze({
|
|
|
66228
66456
|
maxArtifactsBytes: 0,
|
|
66229
66457
|
maxConcurrency: 1
|
|
66230
66458
|
});
|
|
66231
|
-
var hash2 = (bytes) =>
|
|
66459
|
+
var hash2 = (bytes) => createHash34("sha256").update(bytes).digest("hex");
|
|
66232
66460
|
var object7 = (v2) => {
|
|
66233
66461
|
if (!v2 || typeof v2 !== "object" || Array.isArray(v2))
|
|
66234
66462
|
throw Error("Pure contract requires an object");
|
|
@@ -66457,7 +66685,7 @@ function verifyRuntimeToken(token, key, admission, attempt, now = Date.now()) {
|
|
|
66457
66685
|
const actual = Buffer.from(token);
|
|
66458
66686
|
return actual.length === expected.length && timingSafeEqual2(actual, expected);
|
|
66459
66687
|
}
|
|
66460
|
-
var hashBytes = (bytes) =>
|
|
66688
|
+
var hashBytes = (bytes) => createHash35("sha256").update(bytes).digest("hex");
|
|
66461
66689
|
|
|
66462
66690
|
// src/server/runtime-api.ts
|
|
66463
66691
|
async function createRuntimeService(options) {
|
|
@@ -67274,6 +67502,7 @@ class MemorySkillsStore {
|
|
|
67274
67502
|
updatedAt: now,
|
|
67275
67503
|
revisionId: revisionIdOfRecord(recordFieldsOf(input, carriedBundle, carriedSkillMd)),
|
|
67276
67504
|
revisionNumber: (previous?.revisionNumber ?? 0) + 1,
|
|
67505
|
+
authorizationEpoch: previous?.authorizationEpoch ?? randomUUID10().replaceAll("-", ""),
|
|
67277
67506
|
lifecycle: previous?.lifecycle ?? "active",
|
|
67278
67507
|
...previous?.archivedAt ? { archivedAt: previous.archivedAt } : {},
|
|
67279
67508
|
...previous?.archiveReason ? { archiveReason: previous.archiveReason } : {},
|
|
@@ -67317,6 +67546,7 @@ class MemorySkillsStore {
|
|
|
67317
67546
|
slug,
|
|
67318
67547
|
version: version2,
|
|
67319
67548
|
current: current?.orgId === principal.orgId ? {
|
|
67549
|
+
authorizationEpoch: current.authorizationEpoch,
|
|
67320
67550
|
lifecycle: current.lifecycle,
|
|
67321
67551
|
...current.tombstonedAt ? { tombstonedAt: current.tombstonedAt } : {}
|
|
67322
67552
|
} : null,
|
|
@@ -67345,6 +67575,7 @@ class MemorySkillsStore {
|
|
|
67345
67575
|
}
|
|
67346
67576
|
const next2 = {
|
|
67347
67577
|
...current,
|
|
67578
|
+
authorizationEpoch: current.lifecycle === patch.lifecycle ? current.authorizationEpoch : randomUUID10().replaceAll("-", ""),
|
|
67348
67579
|
lifecycle: patch.lifecycle,
|
|
67349
67580
|
updatedAt: nowIso(),
|
|
67350
67581
|
revisionId: revisionIdOfRecord({ ...current, lifecycle: patch.lifecycle, archiveReason: patch.reason, replacementSlug: patch.replacementSlug }),
|
|
@@ -67389,7 +67620,7 @@ class MemorySkillsStore {
|
|
|
67389
67620
|
if (!current.tombstonedAt) {
|
|
67390
67621
|
const tombstoned = nowIso();
|
|
67391
67622
|
const purgeAfter = new Date(Date.now() + tombstoneWindowMs).toISOString();
|
|
67392
|
-
const next2 = { ...current, tombstonedAt: tombstoned, tombstonePurgeAfter: purgeAfter, updatedAt: tombstoned };
|
|
67623
|
+
const next2 = { ...current, authorizationEpoch: randomUUID10().replaceAll("-", ""), tombstonedAt: tombstoned, tombstonePurgeAfter: purgeAfter, updatedAt: tombstoned };
|
|
67393
67624
|
this.skills.set(skillKey(principal.orgId, slug), next2);
|
|
67394
67625
|
return next2;
|
|
67395
67626
|
}
|
|
@@ -68143,7 +68374,7 @@ class PostgresSkillsStore {
|
|
|
68143
68374
|
const requested = JSON.stringify(selections2.map(({ slug, version: version2 }) => ({ slug, version: version2 })));
|
|
68144
68375
|
const rows = await this.sql`
|
|
68145
68376
|
SELECT q.value->>'slug' AS slug, q.value->>'version' AS version,
|
|
68146
|
-
r.slug IS NOT NULL AS skill_exists, r.lifecycle, r.tombstoned_at,
|
|
68377
|
+
r.slug IS NOT NULL AS skill_exists, r.lifecycle, r.tombstoned_at, r.authorization_epoch,
|
|
68147
68378
|
v.bundle_sha256, b.sha256 IS NOT NULL AS bundle_available
|
|
68148
68379
|
FROM jsonb_array_elements(${requested}::text::jsonb) WITH ORDINALITY AS q(value, ordinal)
|
|
68149
68380
|
LEFT JOIN skills_registry r ON r.org_id = ${principal.orgId} AND r.slug = q.value->>'slug'
|
|
@@ -68439,13 +68670,14 @@ async function handleApiV1(store, governanceStore, principal, request2, parts, c
|
|
|
68439
68670
|
return json4(skillVersionPayload(version2, current));
|
|
68440
68671
|
}
|
|
68441
68672
|
if (request2.method === "GET" && id2 && subresource === "versions" && childId && parts[4] === "bundle" && !parts[5]) {
|
|
68442
|
-
const { version: version2, bytes } = await readSkillVersionBundle(store, artifactStorage, principal, id2, childId);
|
|
68673
|
+
const { version: version2, bytes, authorizationEpoch } = await readSkillVersionBundle(store, artifactStorage, principal, id2, childId);
|
|
68443
68674
|
const headers = {
|
|
68444
68675
|
"Content-Type": "application/gzip",
|
|
68445
68676
|
"Content-Length": String(bytes.byteLength),
|
|
68446
68677
|
"Content-Disposition": `attachment; filename="${version2.slug}-${version2.version}.tar.gz"`,
|
|
68447
68678
|
"X-Skill-Bundle-Sha256": version2.bundleSha256,
|
|
68448
68679
|
"X-Skill-Version": version2.version,
|
|
68680
|
+
...authorizationEpoch ? { "X-Skill-Authorization-Epoch": authorizationEpoch } : {},
|
|
68449
68681
|
ETag: `"${version2.bundleSha256}"`,
|
|
68450
68682
|
"Cache-Control": "no-store"
|
|
68451
68683
|
};
|
|
@@ -72829,7 +73061,7 @@ var localRunExecutor = {
|
|
|
72829
73061
|
// src/sdk/storage.ts
|
|
72830
73062
|
var artifactStorageSeam = ArtifactStorage;
|
|
72831
73063
|
// src/sdk/outputs.ts
|
|
72832
|
-
import { createHash as
|
|
73064
|
+
import { createHash as createHash36 } from "crypto";
|
|
72833
73065
|
class DatabaseOnlyObjectStore {
|
|
72834
73066
|
usesS3 = false;
|
|
72835
73067
|
async materialize(run, artifact, body4) {
|
|
@@ -72876,7 +73108,7 @@ function createGovernedArtifactWriter(options) {
|
|
|
72876
73108
|
const stamped = {
|
|
72877
73109
|
...meta,
|
|
72878
73110
|
byteSize: outputBytes,
|
|
72879
|
-
sha256:
|
|
73111
|
+
sha256: createHash36("sha256").update(persistedBytes).digest("hex"),
|
|
72880
73112
|
visibility: options.visibility ?? config.defaultVisibility,
|
|
72881
73113
|
...config.artifactTtlSeconds !== undefined ? { expiresAt: expiresAtFor(createdAt, config.artifactTtlSeconds) } : {}
|
|
72882
73114
|
};
|
|
@@ -73117,7 +73349,7 @@ __export(exports_external2, {
|
|
|
73117
73349
|
pipe: () => pipe,
|
|
73118
73350
|
partialRecord: () => partialRecord,
|
|
73119
73351
|
parseAsync: () => parseAsync2,
|
|
73120
|
-
parse: () =>
|
|
73352
|
+
parse: () => parse11,
|
|
73121
73353
|
overwrite: () => _overwrite,
|
|
73122
73354
|
output: () => output,
|
|
73123
73355
|
optional: () => optional,
|
|
@@ -73337,7 +73569,7 @@ __export(exports_core2, {
|
|
|
73337
73569
|
prettifyError: () => prettifyError,
|
|
73338
73570
|
parseURLObject: () => parseURLObject,
|
|
73339
73571
|
parseAsync: () => parseAsync,
|
|
73340
|
-
parse: () =>
|
|
73572
|
+
parse: () => parse9,
|
|
73341
73573
|
meta: () => meta,
|
|
73342
73574
|
mergeValues: () => mergeValues2,
|
|
73343
73575
|
memoizer: () => memoizer,
|
|
@@ -74791,7 +75023,7 @@ var _parse = (_Err) => {
|
|
|
74791
75023
|
};
|
|
74792
75024
|
return fn;
|
|
74793
75025
|
};
|
|
74794
|
-
var
|
|
75026
|
+
var parse9 = /* @__PURE__ */ _parse($ZodRealError);
|
|
74795
75027
|
var _parseAsync = (_Err) => {
|
|
74796
75028
|
const fn = async (schema, value, _ctx, params) => {
|
|
74797
75029
|
const ctx = _ctx ? { ..._ctx, async: true } : { async: true };
|
|
@@ -74862,18 +75094,18 @@ var validateAsync = async (schema, value, _ctx) => {
|
|
|
74862
75094
|
return result.issues.length === 0;
|
|
74863
75095
|
};
|
|
74864
75096
|
var _encode = (_Err) => {
|
|
74865
|
-
const
|
|
75097
|
+
const parse10 = _parse(_Err);
|
|
74866
75098
|
const fn = (schema, value, _ctx, _params) => {
|
|
74867
75099
|
const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" };
|
|
74868
|
-
return
|
|
75100
|
+
return parse10(schema, value, ctx, finalizeParams(fn, _params));
|
|
74869
75101
|
};
|
|
74870
75102
|
return fn;
|
|
74871
75103
|
};
|
|
74872
75104
|
var encode = /* @__PURE__ */ _encode($ZodRealError);
|
|
74873
75105
|
var _decode = (_Err) => {
|
|
74874
|
-
const
|
|
75106
|
+
const parse10 = _parse(_Err);
|
|
74875
75107
|
const fn = (schema, value, _ctx, _params) => {
|
|
74876
|
-
return
|
|
75108
|
+
return parse10(schema, value, _ctx, finalizeParams(fn, _params));
|
|
74877
75109
|
};
|
|
74878
75110
|
return fn;
|
|
74879
75111
|
};
|
|
@@ -77796,10 +78028,10 @@ var $ZodFunction = /* @__PURE__ */ $constructor("$ZodFunction", (inst, def) => {
|
|
|
77796
78028
|
throw new Error("implement() must be called with a function");
|
|
77797
78029
|
}
|
|
77798
78030
|
return Object.defineProperty(function(...args) {
|
|
77799
|
-
const parsedArgs = inst._def.input ?
|
|
78031
|
+
const parsedArgs = inst._def.input ? parse9(inst._def.input, args) : args;
|
|
77800
78032
|
const result = Reflect.apply(func, this, parsedArgs);
|
|
77801
78033
|
if (inst._def.output) {
|
|
77802
|
-
return
|
|
78034
|
+
return parse9(inst._def.output, result);
|
|
77803
78035
|
}
|
|
77804
78036
|
return result;
|
|
77805
78037
|
}, "_zod", { value: inst._zod, enumerable: false });
|
|
@@ -89437,7 +89669,7 @@ var ZodRealError = /* @__PURE__ */ $constructor("ZodError", initializer2, undefi
|
|
|
89437
89669
|
});
|
|
89438
89670
|
|
|
89439
89671
|
// node_modules/zod/v4/classic/parse.js
|
|
89440
|
-
var
|
|
89672
|
+
var parse11 = /* @__PURE__ */ _parse(ZodRealError);
|
|
89441
89673
|
var parseAsync2 = /* @__PURE__ */ _parseAsync(ZodRealError);
|
|
89442
89674
|
var safeParse3 = /* @__PURE__ */ _safeParse(ZodRealError);
|
|
89443
89675
|
var safeParseAsync2 = /* @__PURE__ */ _safeParseAsync(ZodRealError);
|
|
@@ -89573,7 +89805,7 @@ var ZodType2 = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
|
|
|
89573
89805
|
exports_util.own(this, "~standard", value);
|
|
89574
89806
|
},
|
|
89575
89807
|
parse: function _parse2(data, params) {
|
|
89576
|
-
return
|
|
89808
|
+
return parse11(this, data, params, { callee: _parse2 });
|
|
89577
89809
|
},
|
|
89578
89810
|
parseAsync: async function _parseAsync2(data, params) {
|
|
89579
89811
|
return await parseAsync2(this, data, params, { callee: _parseAsync2 });
|
|
@@ -91643,7 +91875,7 @@ function date4(params) {
|
|
|
91643
91875
|
return _coercedDate(ZodDate2, params);
|
|
91644
91876
|
}
|
|
91645
91877
|
// src/lib/canonical-json.ts
|
|
91646
|
-
import { createHash as
|
|
91878
|
+
import { createHash as createHash37 } from "crypto";
|
|
91647
91879
|
function canonicalJson3(value, maximumBytes = 2 * 1024 * 1024) {
|
|
91648
91880
|
return canonicalJsonAtDepth(value, maximumBytes, 64);
|
|
91649
91881
|
}
|
|
@@ -91687,7 +91919,7 @@ function canonicalJsonAtDepth(value, maximumBytes, maximumDepth) {
|
|
|
91687
91919
|
return visit3(value, 0);
|
|
91688
91920
|
}
|
|
91689
91921
|
function canonicalJsonSha256(value, maximumBytes) {
|
|
91690
|
-
return
|
|
91922
|
+
return createHash37("sha256").update(canonicalJson3(value, maximumBytes)).digest("hex");
|
|
91691
91923
|
}
|
|
91692
91924
|
|
|
91693
91925
|
// src/lib/remote-recurring-contract.ts
|
|
@@ -93801,7 +94033,7 @@ async function requestInvitationEmail(origin, action, input2) {
|
|
|
93801
94033
|
}
|
|
93802
94034
|
|
|
93803
94035
|
// src/lib/remote-private-publications.ts
|
|
93804
|
-
import { createHash as
|
|
94036
|
+
import { createHash as createHash38 } from "crypto";
|
|
93805
94037
|
var PRIVATE_PUBLICATION_MAX_BYTES = 16 * 1024 * 1024;
|
|
93806
94038
|
var failures2 = {
|
|
93807
94039
|
INVALID_REQUEST: [400, "The publication request is invalid."],
|
|
@@ -93848,7 +94080,7 @@ var hash4 = (v2) => typeof v2 === "string" && /^[a-f0-9]{64}$/.test(v2);
|
|
|
93848
94080
|
var record10 = (v2) => !!v2 && typeof v2 === "object" && !Array.isArray(v2);
|
|
93849
94081
|
var exact = (v2, keys3) => record10(v2) && Object.keys(v2).sort().join(",") === keys3.sort().join(",");
|
|
93850
94082
|
var date5 = (v2) => typeof v2 === "string" && /^\d{4}-\d\d-\d\dT[0-9:.]+(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.test(v2) && Number.isFinite(Date.parse(v2));
|
|
93851
|
-
var publicationSha256 = (bytes) =>
|
|
94083
|
+
var publicationSha256 = (bytes) => createHash38("sha256").update(bytes).digest("hex");
|
|
93852
94084
|
function checkedPublicationDeclaration(value) {
|
|
93853
94085
|
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 || !hash4(value.archiveSha256) || !Number.isSafeInteger(value.archiveByteSize) || Number(value.archiveByteSize) < 1 || Number(value.archiveByteSize) > PRIVATE_PUBLICATION_MAX_BYTES)
|
|
93854
94086
|
return bad();
|
|
@@ -94331,7 +94563,7 @@ class RemoteSkillsAuthClient {
|
|
|
94331
94563
|
}
|
|
94332
94564
|
// src/lib/private-publication-recovery.ts
|
|
94333
94565
|
import { constants as constants15, closeSync as closeSync18, fsyncSync as fsyncSync6, fstatSync as fstatSync18, lstatSync as lstatSync26, mkdirSync as mkdirSync15, openSync as openSync18, readSync as readSync13, realpathSync as realpathSync15, renameSync as renameSync7, unlinkSync as unlinkSync6, writeFileSync as writeFileSync11 } from "fs";
|
|
94334
|
-
import { dirname as dirname28, isAbsolute as isAbsolute22, join as
|
|
94566
|
+
import { dirname as dirname28, isAbsolute as isAbsolute22, join as join43, resolve as resolve23 } from "path";
|
|
94335
94567
|
import { randomUUID as randomUUID12 } from "crypto";
|
|
94336
94568
|
var fail2 = () => {
|
|
94337
94569
|
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.");
|
|
@@ -94357,7 +94589,7 @@ function unchangedDirectory(directory, identity5) {
|
|
|
94357
94589
|
return fail2();
|
|
94358
94590
|
}
|
|
94359
94591
|
function readOwned(directory, name, max) {
|
|
94360
|
-
const identity5 = safeDirectory(directory), file2 =
|
|
94592
|
+
const identity5 = safeDirectory(directory), file2 = join43(directory, name);
|
|
94361
94593
|
const fd = openSync18(file2, constants15.O_RDONLY | constants15.O_NOFOLLOW);
|
|
94362
94594
|
try {
|
|
94363
94595
|
const stat2 = fstatSync18(fd);
|
|
@@ -94381,7 +94613,7 @@ function readOwned(directory, name, max) {
|
|
|
94381
94613
|
}
|
|
94382
94614
|
}
|
|
94383
94615
|
function writeOwned(directory, name, bytes) {
|
|
94384
|
-
const fd = openSync18(
|
|
94616
|
+
const fd = openSync18(join43(directory, name), constants15.O_WRONLY | constants15.O_CREAT | constants15.O_EXCL | constants15.O_NOFOLLOW, 384);
|
|
94385
94617
|
try {
|
|
94386
94618
|
writeFileSync11(fd, bytes);
|
|
94387
94619
|
fsyncSync6(fd);
|
|
@@ -94394,7 +94626,7 @@ function save(directory, value) {
|
|
|
94394
94626
|
writeOwned(directory, temporary, JSON.stringify(value) + `
|
|
94395
94627
|
`);
|
|
94396
94628
|
unchangedDirectory(directory, identity5);
|
|
94397
|
-
renameSync7(
|
|
94629
|
+
renameSync7(join43(directory, temporary), join43(directory, "receipt.json"));
|
|
94398
94630
|
const fd = openSync18(directory, constants15.O_RDONLY | constants15.O_NOFOLLOW);
|
|
94399
94631
|
try {
|
|
94400
94632
|
fsyncSync6(fd);
|
|
@@ -94407,7 +94639,7 @@ function bind(client2, receipt) {
|
|
|
94407
94639
|
throw new PrivatePublicationError("PUBLICATION_IDENTITY_CHANGED", "The fresh session does not match the recovery directory's server, account and membership.");
|
|
94408
94640
|
}
|
|
94409
94641
|
async function locked(directory, action) {
|
|
94410
|
-
const identity5 = safeDirectory(directory), file2 =
|
|
94642
|
+
const identity5 = safeDirectory(directory), file2 = join43(directory, "operation.lock");
|
|
94411
94643
|
let fd;
|
|
94412
94644
|
try {
|
|
94413
94645
|
fd = openSync18(file2, constants15.O_WRONLY | constants15.O_CREAT | constants15.O_EXCL | constants15.O_NOFOLLOW, 384);
|