@hasna/skills 0.9.9 → 0.9.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -0
- package/bin/index.js +801 -667
- package/bin/mcp.js +21 -6
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/index.js +268 -197
- package/dist/lib/agent-codex-trust.d.ts +42 -0
- package/dist/lib/agent-discovery.d.ts +2 -1
- package/dist/lib/agent-integration.d.ts +2 -0
- package/dist/lib/codex-hook-discovery-recovery.d.ts +25 -0
- package/dist/lib/codex-hook-policy-recovery.d.ts +16 -0
- package/dist/lib/codex-hook-trust-identity.d.ts +11 -0
- package/dist/sdk/index.js +290 -219
- package/package.json +1 -1
package/bin/index.js
CHANGED
|
@@ -36868,7 +36868,7 @@ var package_default;
|
|
|
36868
36868
|
var init_package = __esm(() => {
|
|
36869
36869
|
package_default = {
|
|
36870
36870
|
name: "@hasna/skills",
|
|
36871
|
-
version: "0.9.
|
|
36871
|
+
version: "0.9.11",
|
|
36872
36872
|
description: "Skills library for AI coding agents",
|
|
36873
36873
|
type: "module",
|
|
36874
36874
|
bin: {
|
|
@@ -54737,10 +54737,252 @@ var init_claude_settings_witness = __esm(() => {
|
|
|
54737
54737
|
]);
|
|
54738
54738
|
});
|
|
54739
54739
|
|
|
54740
|
-
// src/lib/
|
|
54740
|
+
// src/lib/codex-hook-trust-files.ts
|
|
54741
|
+
import { closeSync as closeSync11, constants as constants11, fstatSync as fstatSync11, fsyncSync as fsyncSync3, lstatSync as lstatSync17, openSync as openSync11, readSync as readSync9, writeFileSync as writeFileSync5 } from "fs";
|
|
54741
54742
|
import { createHash as createHash13 } from "crypto";
|
|
54742
|
-
import {
|
|
54743
|
-
|
|
54743
|
+
import { dirname as dirname14 } from "path";
|
|
54744
|
+
function need4(value, code) {
|
|
54745
|
+
if (!value)
|
|
54746
|
+
throw new Error(`CODEX_HOOK_TRUST_${code}`);
|
|
54747
|
+
}
|
|
54748
|
+
function safeParents(file) {
|
|
54749
|
+
for (let p = dirname14(file);; p = dirname14(p)) {
|
|
54750
|
+
const s = lstatSync17(p);
|
|
54751
|
+
need4(s.isDirectory() && !s.isSymbolicLink(), "UNSAFE_PARENT");
|
|
54752
|
+
need4((s.mode & 18) === 0 || s.uid === 0 && (s.mode & 512) !== 0, "UNSAFE_PARENT");
|
|
54753
|
+
if (dirname14(p) === p)
|
|
54754
|
+
break;
|
|
54755
|
+
}
|
|
54756
|
+
}
|
|
54757
|
+
function snapshot(file, privateFile = false, options = {}) {
|
|
54758
|
+
const readOnlyPackage = options.readOnlyPackage === true && !privateFile;
|
|
54759
|
+
safeParents(file);
|
|
54760
|
+
const initial2 = lstatSync17(file, { bigint: true });
|
|
54761
|
+
need4(initial2.isFile() && initial2.uid === BigInt(process.getuid()) && (initial2.nlink === 1n || readOnlyPackage && initial2.nlink > 1n) && (initial2.mode & 0o022n) === 0n && (!privateFile || (initial2.mode & 0o777n) === 0o600n), "UNSAFE_FILE");
|
|
54762
|
+
need4(initial2.size <= 8n * 1024n * 1024n, "FILE_BOUND");
|
|
54763
|
+
const fd = openSync11(file, constants11.O_RDONLY | constants11.O_NOFOLLOW | constants11.O_NONBLOCK);
|
|
54764
|
+
try {
|
|
54765
|
+
const before2 = fstatSync11(fd, { bigint: true });
|
|
54766
|
+
need4(sameStat(initial2, before2), "INPUT_CHANGED");
|
|
54767
|
+
const bytes = Buffer.alloc(Number(before2.size) + 1);
|
|
54768
|
+
let length = 0;
|
|
54769
|
+
while (length < bytes.length) {
|
|
54770
|
+
const n2 = readSync9(fd, bytes, length, bytes.length - length, null);
|
|
54771
|
+
if (!n2)
|
|
54772
|
+
break;
|
|
54773
|
+
length += n2;
|
|
54774
|
+
}
|
|
54775
|
+
need4(length === Number(before2.size) && sameStat(before2, fstatSync11(fd, { bigint: true })) && sameStat(before2, lstatSync17(file, { bigint: true })), "INPUT_CHANGED");
|
|
54776
|
+
const content = bytes.subarray(0, length), text2 = new TextDecoder("utf-8", { fatal: true }).decode(content);
|
|
54777
|
+
return { file, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before2, sha256: createHash13("sha256").update(content).digest("hex") };
|
|
54778
|
+
} finally {
|
|
54779
|
+
closeSync11(fd);
|
|
54780
|
+
}
|
|
54781
|
+
}
|
|
54782
|
+
function unchanged2(before2) {
|
|
54783
|
+
const after2 = snapshot(before2.file, before2.privateFile, before2.readOnlyPackage ? { readOnlyPackage: true } : {});
|
|
54784
|
+
need4(sameStat(before2.stat, after2.stat) && after2.sha256 === before2.sha256, "INPUT_CHANGED");
|
|
54785
|
+
}
|
|
54786
|
+
function save(file, content) {
|
|
54787
|
+
safeParents(file);
|
|
54788
|
+
const fd = openSync11(file, constants11.O_WRONLY | constants11.O_CREAT | constants11.O_EXCL | constants11.O_NOFOLLOW, 384);
|
|
54789
|
+
try {
|
|
54790
|
+
writeFileSync5(fd, content);
|
|
54791
|
+
fsyncSync3(fd);
|
|
54792
|
+
} finally {
|
|
54793
|
+
closeSync11(fd);
|
|
54794
|
+
}
|
|
54795
|
+
}
|
|
54796
|
+
var sameStat = (a, b) => ["dev", "ino", "uid", "nlink", "mode", "size", "mtimeNs", "ctimeNs"].every((key) => a[key] === b[key]);
|
|
54797
|
+
var init_codex_hook_trust_files = () => {};
|
|
54798
|
+
|
|
54799
|
+
// src/lib/codex-hook-trust-layout.ts
|
|
54800
|
+
import { isDeepStrictEqual as isDeepStrictEqual3 } from "util";
|
|
54801
|
+
function codexTrustTextWitness(text2, keys2, canonicalize = true) {
|
|
54802
|
+
const parsed = Bun.TOML.parse(text2), wanted = new Set(keys2);
|
|
54803
|
+
const headers = [...text2.matchAll(/^[ \t]*(\[[^\r\n]+\])[ \t]*(#[^\r\n]*)?(?:\r?\n|$)/gm)];
|
|
54804
|
+
if (headers.length > 512)
|
|
54805
|
+
throw fail2();
|
|
54806
|
+
let root2 = parsed;
|
|
54807
|
+
for (const header of headers) {
|
|
54808
|
+
try {
|
|
54809
|
+
root2 = Bun.TOML.parse(text2.slice(0, header.index));
|
|
54810
|
+
break;
|
|
54811
|
+
} catch {}
|
|
54812
|
+
}
|
|
54813
|
+
if (root2.hooks !== undefined)
|
|
54814
|
+
throw fail2();
|
|
54815
|
+
const replacements2 = [];
|
|
54816
|
+
const stateSections = [];
|
|
54817
|
+
for (const [index, header] of headers.entries()) {
|
|
54818
|
+
let shape;
|
|
54819
|
+
try {
|
|
54820
|
+
shape = Bun.TOML.parse(header[1]);
|
|
54821
|
+
} catch {
|
|
54822
|
+
continue;
|
|
54823
|
+
}
|
|
54824
|
+
const state = shape.hooks?.state;
|
|
54825
|
+
if (!state || Object.keys(shape).length !== 1 || Object.keys(shape.hooks).length !== 1)
|
|
54826
|
+
continue;
|
|
54827
|
+
const names = Object.keys(state), start = header.index, end = headers[index + 1]?.index ?? text2.length;
|
|
54828
|
+
if (names.length === 0) {
|
|
54829
|
+
replacements2.push({ start, end: start + header[0].length, comments: header[2] ? header[2] + `
|
|
54830
|
+
` : "" });
|
|
54831
|
+
stateSections.push({ start, end: start + header[0].length });
|
|
54832
|
+
} else if (names.length === 1 && !Object.keys(state[names[0]]).length) {
|
|
54833
|
+
stateSections.push({ start, end });
|
|
54834
|
+
if (!wanted.has(names[0])) {
|
|
54835
|
+
replacements2.push({ start, end: start + header[0].length, comments: `[hooks.state.${JSON.stringify(names[0])}]${header[2] ? " " + header[2] : ""}
|
|
54836
|
+
` });
|
|
54837
|
+
continue;
|
|
54838
|
+
}
|
|
54839
|
+
const comments = header[2] ? [header[2]] : [];
|
|
54840
|
+
for (const line of text2.slice(start + header[0].length, end).split(/\r?\n/)) {
|
|
54841
|
+
if (!line.trim())
|
|
54842
|
+
continue;
|
|
54843
|
+
if (/^[ \t]*#/.test(line)) {
|
|
54844
|
+
comments.push(line);
|
|
54845
|
+
continue;
|
|
54846
|
+
}
|
|
54847
|
+
const field2 = /^[ \t]*(?:enabled|trusted_hash)[ \t]*=[ \t]*(?:true|false|"(?:[^"\\]|\\.)*"|'[^']*')[ \t]*(#[^\r\n]*)?$/.exec(line);
|
|
54848
|
+
if (!field2)
|
|
54849
|
+
throw fail2();
|
|
54850
|
+
if (field2[1])
|
|
54851
|
+
comments.push(field2[1]);
|
|
54852
|
+
}
|
|
54853
|
+
replacements2.push({ start, end, comments: comments.join(`
|
|
54854
|
+
`) + `
|
|
54855
|
+
` });
|
|
54856
|
+
}
|
|
54857
|
+
}
|
|
54858
|
+
let noState = text2;
|
|
54859
|
+
for (const span of [...stateSections].reverse())
|
|
54860
|
+
noState = noState.slice(0, span.start) + noState.slice(span.end);
|
|
54861
|
+
const expected = structuredClone(parsed);
|
|
54862
|
+
if (expected.hooks)
|
|
54863
|
+
delete expected.hooks.state;
|
|
54864
|
+
try {
|
|
54865
|
+
if (!isDeepStrictEqual3(prune(Bun.TOML.parse(noState)), prune(expected)))
|
|
54866
|
+
throw fail2();
|
|
54867
|
+
} catch {
|
|
54868
|
+
throw fail2();
|
|
54869
|
+
}
|
|
54870
|
+
let result2 = text2;
|
|
54871
|
+
for (const span of replacements2.reverse())
|
|
54872
|
+
result2 = result2.slice(0, span.start) + span.comments + result2.slice(span.end);
|
|
54873
|
+
return (canonicalize ? canonicalizeTableOrder(result2) : result2).split(/\r?\n/).filter((line) => line.trim()).join(`
|
|
54874
|
+
`);
|
|
54875
|
+
}
|
|
54876
|
+
function codexTrustReconcileWitness(text2, keys2) {
|
|
54877
|
+
return codexTrustTextWitness(text2, keys2, false).replace(/[ \t]+$/gm, "");
|
|
54878
|
+
}
|
|
54879
|
+
function codexTrustUnmanagedSemantic(text2, keys2) {
|
|
54880
|
+
const parsed = structuredClone(Bun.TOML.parse(text2));
|
|
54881
|
+
for (const key of keys2)
|
|
54882
|
+
if (parsed.hooks?.state?.[key] !== undefined)
|
|
54883
|
+
delete parsed.hooks.state[key];
|
|
54884
|
+
return JSON.stringify(stableSemantic(prune(parsed)));
|
|
54885
|
+
}
|
|
54886
|
+
var fail2 = () => new Error('CODEX_HOOK_TRUST_UNSUPPORTED_LAYOUT: preserve and convert hook trust to ordinary [hooks.state."<key>"] tables before enrollment'), prune = (value) => {
|
|
54887
|
+
if (value.hooks?.state && !Object.keys(value.hooks.state).length)
|
|
54888
|
+
delete value.hooks.state;
|
|
54889
|
+
if (value.hooks && !Object.keys(value.hooks).length)
|
|
54890
|
+
delete value.hooks;
|
|
54891
|
+
return value;
|
|
54892
|
+
}, canonicalizeTableOrder = (text2) => {
|
|
54893
|
+
const headers = [...text2.matchAll(/^[ \t]*(\[\[?[^\r\n]+\]\]?)[ \t]*(#[^\r\n]*)?(?:\r?\n|$)/gm)];
|
|
54894
|
+
if (!headers.length)
|
|
54895
|
+
return text2;
|
|
54896
|
+
const keys2 = headers.map((header) => header[1].trim());
|
|
54897
|
+
const repeated = keys2.filter((key) => !key.startsWith("[[")).filter((key, index, simple2) => simple2.indexOf(key) !== index);
|
|
54898
|
+
const arrayKeys = keys2.filter((key) => key.startsWith("[["));
|
|
54899
|
+
const plain = keys2.map((key) => key.replace(/^\[\[?/, "").replace(/\]\]?$/, "").trim());
|
|
54900
|
+
const parentChild = plain.some((key, index) => plain.some((other, otherIndex) => index !== otherIndex && (other.startsWith(`${key}.`) || key.startsWith(`${other}.`))));
|
|
54901
|
+
if (repeated.length || parentChild)
|
|
54902
|
+
return text2;
|
|
54903
|
+
if (!arrayKeys.length) {
|
|
54904
|
+
const first2 = headers[0].index;
|
|
54905
|
+
const prefix2 = text2.slice(0, first2);
|
|
54906
|
+
const blocks2 = headers.map((header, index) => ({
|
|
54907
|
+
key: header[1],
|
|
54908
|
+
order: index,
|
|
54909
|
+
text: text2.slice(header.index, headers[index + 1]?.index ?? text2.length)
|
|
54910
|
+
}));
|
|
54911
|
+
blocks2.sort((a, b) => a.key.localeCompare(b.key) || a.order - b.order);
|
|
54912
|
+
return prefix2 + blocks2.map((block) => block.text).join("");
|
|
54913
|
+
}
|
|
54914
|
+
const first = headers[0].index;
|
|
54915
|
+
const prefix = text2.slice(0, first);
|
|
54916
|
+
const blocks = headers.map((header, index) => ({
|
|
54917
|
+
key: header[1],
|
|
54918
|
+
order: index,
|
|
54919
|
+
text: text2.slice(header.index, headers[index + 1]?.index ?? text2.length)
|
|
54920
|
+
}));
|
|
54921
|
+
const simple = blocks.filter((block) => !block.key.startsWith("[["));
|
|
54922
|
+
const arrays = blocks.filter((block) => block.key.startsWith("[["));
|
|
54923
|
+
return prefix + [...simple, ...arrays].map((block) => block.text).join("");
|
|
54924
|
+
}, stableSemantic = (value) => {
|
|
54925
|
+
if (Array.isArray(value))
|
|
54926
|
+
return value.map(stableSemantic);
|
|
54927
|
+
if (value && typeof value === "object")
|
|
54928
|
+
return Object.fromEntries(Object.keys(value).sort().map((key) => [key, stableSemantic(value[key])]));
|
|
54929
|
+
return value;
|
|
54930
|
+
};
|
|
54931
|
+
var init_codex_hook_trust_layout = () => {};
|
|
54932
|
+
|
|
54933
|
+
// src/lib/codex-hook-discovery-recovery.ts
|
|
54934
|
+
import { createHash as createHash14 } from "crypto";
|
|
54935
|
+
import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
|
|
54936
|
+
function createCodexHookDiscoveryRecovery(binding, before2, current, hooks) {
|
|
54937
|
+
const raw = binding.sources.filter((source) => source.path === current.file && source.hashMode === "bytes");
|
|
54938
|
+
if (!raw.some((source) => source.sha256 !== current.sha256))
|
|
54939
|
+
return;
|
|
54940
|
+
need4(binding.agent === "codex" && binding.method === "reviewed" && raw.length === 1 && raw[0].sha256 === before2.sha256 && before2.sha256 !== current.sha256, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
|
|
54941
|
+
need4(raw[0].format === undefined && raw[0].fields === undefined && raw[0].managedPlugins === undefined, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
|
|
54942
|
+
const typed = binding.sources.filter((source) => source.path === current.file && source.format === "toml");
|
|
54943
|
+
need4(typed.length === 1 && typed[0].hashMode === undefined && isDeepStrictEqual4(typed[0].fields, fields), "RECONCILE_DISCOVERY_TYPED_WITNESS");
|
|
54944
|
+
const original = structure(before2.text), actual = structure(current.text);
|
|
54945
|
+
const project = (value) => Object.fromEntries(fields.map((field2) => [field2, value[field2] ?? null]));
|
|
54946
|
+
const projection = sha(JSON.stringify(project(original)));
|
|
54947
|
+
need4(typed[0].sha256 === projection && sha(JSON.stringify(project(actual))) === projection && isDeepStrictEqual4(project(original), project(actual)), "RECONCILE_DISCOVERY_TYPED_WITNESS");
|
|
54948
|
+
need4(hooks.length > 0 && hooks.length <= 100 && new Set(hooks.map((hook) => hook.key)).size === hooks.length && hooks.every((hook) => typeof hook.key === "string" && /^sha256:[a-f0-9]{64}$/.test(hook.currentHash)), "RECONCILE_DISCOVERY_TRUST_WITNESS");
|
|
54949
|
+
const keys2 = hooks.map((hook) => hook.key), expected = structuredClone(original);
|
|
54950
|
+
expected.hooks ??= {};
|
|
54951
|
+
expected.hooks.state ??= {};
|
|
54952
|
+
for (const hook of hooks)
|
|
54953
|
+
expected.hooks.state[hook.key] = { ...expected.hooks.state[hook.key], enabled: true, trusted_hash: hook.currentHash };
|
|
54954
|
+
need4(isDeepStrictEqual4(expected, actual) && codexTrustReconcileWitness(before2.text, keys2) === codexTrustReconcileWitness(current.text, keys2) && codexTrustUnmanagedSemantic(before2.text, keys2) === codexTrustUnmanagedSemantic(current.text, keys2), "RECONCILE_DISCOVERY_TRUST_WITNESS");
|
|
54955
|
+
unchanged2(before2);
|
|
54956
|
+
unchanged2(current);
|
|
54957
|
+
const witness = Object.freeze({ configPath: current.file, beforeSha256: before2.sha256, currentSha256: current.sha256, discoverySha256: sha(JSON.stringify(binding)), typedProjectionSha256: projection });
|
|
54958
|
+
proofs.set(witness, { before: before2, current });
|
|
54959
|
+
return witness;
|
|
54960
|
+
}
|
|
54961
|
+
function assertCodexHookDiscoveryRecovery(binding, witness) {
|
|
54962
|
+
const proof = proofs.get(witness);
|
|
54963
|
+
need4(!!proof && binding.agent === "codex" && witness.discoverySha256 === sha(JSON.stringify(binding)), "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
|
|
54964
|
+
unchanged2(proof.before);
|
|
54965
|
+
unchanged2(proof.current);
|
|
54966
|
+
}
|
|
54967
|
+
function verifiesCodexHookDiscoverySource(binding, source, currentDigest, witness) {
|
|
54968
|
+
if (!witness || source.path !== witness.configPath || source.hashMode !== "bytes")
|
|
54969
|
+
return false;
|
|
54970
|
+
assertCodexHookDiscoveryRecovery(binding, witness);
|
|
54971
|
+
need4(source.sha256 === witness.beforeSha256 && currentDigest === witness.currentSha256, "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
|
|
54972
|
+
return true;
|
|
54973
|
+
}
|
|
54974
|
+
var sha = (text2) => createHash14("sha256").update(text2).digest("hex"), fields, structure = (text2) => JSON.parse(JSON.stringify(Bun.TOML.parse(text2))), proofs;
|
|
54975
|
+
var init_codex_hook_discovery_recovery = __esm(() => {
|
|
54976
|
+
init_codex_hook_trust_files();
|
|
54977
|
+
init_codex_hook_trust_layout();
|
|
54978
|
+
fields = ["plugins", "marketplaces", "skills"];
|
|
54979
|
+
proofs = new WeakMap;
|
|
54980
|
+
});
|
|
54981
|
+
|
|
54982
|
+
// src/lib/agent-discovery.ts
|
|
54983
|
+
import { createHash as createHash15 } from "crypto";
|
|
54984
|
+
import { lstatSync as lstatSync18, readFileSync as readFileSync14, readdirSync as readdirSync9, realpathSync as realpathSync4 } from "fs";
|
|
54985
|
+
import { basename as basename8, dirname as dirname15, isAbsolute as isAbsolute14, join as join28, resolve as resolve15, sep as sep5 } from "path";
|
|
54744
54986
|
function parseConfig(text2, path, toml = false) {
|
|
54745
54987
|
try {
|
|
54746
54988
|
const value = toml ? Bun.TOML.parse(text2) : JSON.parse(text2);
|
|
@@ -54754,10 +54996,10 @@ function parseConfig(text2, path, toml = false) {
|
|
|
54754
54996
|
function safe4(path) {
|
|
54755
54997
|
if (!isAbsolute14(path) || path.includes("\x00"))
|
|
54756
54998
|
throw new Error("Expected an absolute native discovery path");
|
|
54757
|
-
for (let cursor = path;; cursor =
|
|
54758
|
-
if (
|
|
54999
|
+
for (let cursor = path;; cursor = dirname15(cursor)) {
|
|
55000
|
+
if (lstatSync18(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
54759
55001
|
throw new Error(`Refusing symlink native discovery input: ${cursor}`);
|
|
54760
|
-
if (
|
|
55002
|
+
if (dirname15(cursor) === cursor)
|
|
54761
55003
|
break;
|
|
54762
55004
|
}
|
|
54763
55005
|
}
|
|
@@ -54765,7 +55007,7 @@ function read2(path, changes) {
|
|
|
54765
55007
|
safe4(path);
|
|
54766
55008
|
if (changes?.has(path))
|
|
54767
55009
|
return changes.get(path);
|
|
54768
|
-
const stat2 =
|
|
55010
|
+
const stat2 = lstatSync18(path, { throwIfNoEntry: false });
|
|
54769
55011
|
if (!stat2)
|
|
54770
55012
|
return null;
|
|
54771
55013
|
if (!stat2.isFile() || stat2.size > 16 * 1024 * 1024)
|
|
@@ -54815,7 +55057,9 @@ function projected(source, changes, budget = discoveryByteBudget()) {
|
|
|
54815
55057
|
throw new Error("Expected native discovery configuration object");
|
|
54816
55058
|
return digest(JSON.stringify(Object.fromEntries((source.fields ?? []).map((field2) => [field2, object4[field2] ?? null]))));
|
|
54817
55059
|
}
|
|
54818
|
-
function verifyAgentDiscovery(binding) {
|
|
55060
|
+
function verifyAgentDiscovery(binding, codexRecovery) {
|
|
55061
|
+
if (codexRecovery)
|
|
55062
|
+
assertCodexHookDiscoveryRecovery(binding, codexRecovery);
|
|
54819
55063
|
if (!binding || !Array.isArray(binding.sources) || !Array.isArray(binding.roots) || binding.sources.length > AGENT_POLICY_LIMITS.discoverySources || binding.roots.length > AGENT_POLICY_LIMITS.discoveryRoots)
|
|
54820
55064
|
throw new Error("Invalid native discovery binding");
|
|
54821
55065
|
if (binding.agent === "hermes" && !binding.directories?.length)
|
|
@@ -54831,7 +55075,8 @@ function verifyAgentDiscovery(binding) {
|
|
|
54831
55075
|
throw new Error("Invalid native discovery projection");
|
|
54832
55076
|
if (source.sha256 !== null && !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
54833
55077
|
throw new Error("Invalid native discovery digest");
|
|
54834
|
-
|
|
55078
|
+
const current = projected(source, undefined, budget);
|
|
55079
|
+
if (current !== source.sha256 && !verifiesCodexHookDiscoverySource(binding, source, current, codexRecovery))
|
|
54835
55080
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
54836
55081
|
}
|
|
54837
55082
|
for (const root2 of binding.roots)
|
|
@@ -54883,7 +55128,7 @@ function assertProjectDiscovery(agent, directories, home, canonical4 = resolve15
|
|
|
54883
55128
|
if (agent === "claude") {
|
|
54884
55129
|
const commands = canonical4(join28(directory, ".claude/commands"));
|
|
54885
55130
|
safe4(commands);
|
|
54886
|
-
if (
|
|
55131
|
+
if (lstatSync18(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length)
|
|
54887
55132
|
throw new Error("NATIVE_SKILL_DRIFT: legacy project command discovery requires a dedicated format adapter");
|
|
54888
55133
|
}
|
|
54889
55134
|
}
|
|
@@ -54891,8 +55136,8 @@ function assertProjectDiscovery(agent, directories, home, canonical4 = resolve15
|
|
|
54891
55136
|
function resolveAgentDiscovery(options) {
|
|
54892
55137
|
const canonical4 = options.canonical ?? resolve15, home = resolve15(options.home), agent = options.agent;
|
|
54893
55138
|
const sources = [], roots = new Set, builtinNames = [];
|
|
54894
|
-
const witness = (path, format,
|
|
54895
|
-
const source = { path: canonical4(path), sha256: null, ...format ? { format, fields } : {} };
|
|
55139
|
+
const witness = (path, format, fields2) => {
|
|
55140
|
+
const source = { path: canonical4(path), sha256: null, ...format ? { format, fields: fields2 } : {} };
|
|
54896
55141
|
source.sha256 = projected(source);
|
|
54897
55142
|
sources.push(source);
|
|
54898
55143
|
return read2(source.path);
|
|
@@ -54929,21 +55174,21 @@ function resolveAgentDiscovery(options) {
|
|
|
54929
55174
|
const executable = Bun.which("gemini");
|
|
54930
55175
|
if (executable) {
|
|
54931
55176
|
let packageRoot;
|
|
54932
|
-
for (let directory =
|
|
55177
|
+
for (let directory = dirname15(realpathSync4(executable)), depth = 0;depth < 8; directory = dirname15(directory), depth++) {
|
|
54933
55178
|
const path = join28(directory, "package.json"), raw = read2(path);
|
|
54934
55179
|
if (raw !== null && parseConfig(raw, path).name === "@google/gemini-cli") {
|
|
54935
55180
|
packageRoot = directory;
|
|
54936
55181
|
witness(path);
|
|
54937
55182
|
break;
|
|
54938
55183
|
}
|
|
54939
|
-
if (
|
|
55184
|
+
if (dirname15(directory) === directory)
|
|
54940
55185
|
break;
|
|
54941
55186
|
}
|
|
54942
55187
|
if (!packageRoot)
|
|
54943
55188
|
unresolved("installed Gemini package layout is not recognized");
|
|
54944
55189
|
const builtinRoot = join28(packageRoot, "bundle/builtin");
|
|
54945
55190
|
safe4(builtinRoot);
|
|
54946
|
-
if (!
|
|
55191
|
+
if (!lstatSync18(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
|
|
54947
55192
|
unresolved("installed Gemini builtin root is missing");
|
|
54948
55193
|
for (const name of readdirSync9(builtinRoot).sort()) {
|
|
54949
55194
|
const text2 = witness(join28(builtinRoot, name, "SKILL.md"));
|
|
@@ -54983,7 +55228,7 @@ function resolveAgentDiscovery(options) {
|
|
|
54983
55228
|
unresolved("plugin hooks require a separate no-skill-injection review");
|
|
54984
55229
|
const commands = join28(root2, "commands");
|
|
54985
55230
|
safe4(commands);
|
|
54986
|
-
if (agent === "claude" && (manifest.commands !== undefined ||
|
|
55231
|
+
if (agent === "claude" && (manifest.commands !== undefined || lstatSync18(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length))
|
|
54987
55232
|
unresolved("legacy command discovery requires retirement or a dedicated format adapter");
|
|
54988
55233
|
const rootSkill = witness(join28(root2, "SKILL.md"));
|
|
54989
55234
|
if (rootSkill !== null)
|
|
@@ -54997,7 +55242,7 @@ function resolveAgentDiscovery(options) {
|
|
|
54997
55242
|
const path = resolve15(root2, value);
|
|
54998
55243
|
if (path !== root2 && !path.startsWith(root2 + sep5))
|
|
54999
55244
|
unresolved("plugin skill path escapes its root");
|
|
55000
|
-
roots.add(path.endsWith(`${sep5}SKILL.md`) ?
|
|
55245
|
+
roots.add(path.endsWith(`${sep5}SKILL.md`) ? dirname15(path) : path);
|
|
55001
55246
|
}
|
|
55002
55247
|
}
|
|
55003
55248
|
if (agent === "claude") {
|
|
@@ -55005,7 +55250,7 @@ function resolveAgentDiscovery(options) {
|
|
|
55005
55250
|
const installed = registrations === null ? {} : parseConfig(registrations, join28(home, ".claude/plugins/installed_plugins.json")).plugins;
|
|
55006
55251
|
const commands = canonical4(join28(home, ".claude/commands"));
|
|
55007
55252
|
safe4(commands);
|
|
55008
|
-
if (
|
|
55253
|
+
if (lstatSync18(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length)
|
|
55009
55254
|
unresolved("legacy home command discovery requires a dedicated format adapter");
|
|
55010
55255
|
for (const [id, enabled] of Object.entries(config.enabledPlugins ?? {})) {
|
|
55011
55256
|
if (enabled === false)
|
|
@@ -55047,12 +55292,12 @@ function resolveAgentDiscovery(options) {
|
|
|
55047
55292
|
}
|
|
55048
55293
|
const localPlugins = join28(home, ".config/opencode/plugins");
|
|
55049
55294
|
safe4(localPlugins);
|
|
55050
|
-
if (
|
|
55295
|
+
if (lstatSync18(localPlugins, { throwIfNoEntry: false }) && readdirSync9(localPlugins).some((name) => name !== "skills-cli.js"))
|
|
55051
55296
|
unresolved("additional local plugin hooks require review");
|
|
55052
55297
|
} else if (agent === "hermes") {
|
|
55053
55298
|
for (const directory of [join28(home, ".hermes/plugins"), join28(home, ".hermes/hermes-agent")]) {
|
|
55054
55299
|
safe4(directory);
|
|
55055
|
-
if (
|
|
55300
|
+
if (lstatSync18(directory, { throwIfNoEntry: false }))
|
|
55056
55301
|
unresolved("installed runtime/plugin discovery requires reviewed source bindings");
|
|
55057
55302
|
}
|
|
55058
55303
|
if (Bun.which("hermes") || Object.keys(config.plugins ?? {}).length)
|
|
@@ -55062,11 +55307,11 @@ function resolveAgentDiscovery(options) {
|
|
|
55062
55307
|
unresolved("custom extension or skill paths");
|
|
55063
55308
|
const directory = join28(home, ".gemini/extensions");
|
|
55064
55309
|
safe4(directory);
|
|
55065
|
-
if (
|
|
55310
|
+
if (lstatSync18(directory, { throwIfNoEntry: false }))
|
|
55066
55311
|
for (const name of readdirSync9(directory)) {
|
|
55067
55312
|
const root2 = join28(directory, name);
|
|
55068
55313
|
safe4(root2);
|
|
55069
|
-
if (!
|
|
55314
|
+
if (!lstatSync18(root2)?.isDirectory())
|
|
55070
55315
|
continue;
|
|
55071
55316
|
const raw = witness(join28(root2, "gemini-extension.json"));
|
|
55072
55317
|
if (raw === null)
|
|
@@ -55079,7 +55324,7 @@ function resolveAgentDiscovery(options) {
|
|
|
55079
55324
|
}
|
|
55080
55325
|
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join28(home, ".hermes/plugins"), join28(home, ".hermes/hermes-agent")].map((path) => canonical4(path))) } : {} };
|
|
55081
55326
|
}
|
|
55082
|
-
var digest = (text2) =>
|
|
55327
|
+
var digest = (text2) => createHash15("sha256").update(text2).digest("hex");
|
|
55083
55328
|
var init_agent_discovery = __esm(() => {
|
|
55084
55329
|
init_agent_policy_limits();
|
|
55085
55330
|
init_agent_hermes();
|
|
@@ -55090,6 +55335,7 @@ var init_agent_discovery = __esm(() => {
|
|
|
55090
55335
|
init_plugin_admission();
|
|
55091
55336
|
init_claude_marketplace_registry();
|
|
55092
55337
|
init_claude_settings_witness();
|
|
55338
|
+
init_codex_hook_discovery_recovery();
|
|
55093
55339
|
init_agent_discovery_directories();
|
|
55094
55340
|
});
|
|
55095
55341
|
|
|
@@ -55174,7 +55420,7 @@ var init_agent_adapters = __esm(() => {
|
|
|
55174
55420
|
});
|
|
55175
55421
|
|
|
55176
55422
|
// src/lib/agent-codex.ts
|
|
55177
|
-
import { isDeepStrictEqual as
|
|
55423
|
+
import { isDeepStrictEqual as isDeepStrictEqual5 } from "util";
|
|
55178
55424
|
function assertCodexPathConfigEditable(text2) {
|
|
55179
55425
|
const before2 = Bun.TOML.parse(text2);
|
|
55180
55426
|
if (before2.skills?.config === undefined)
|
|
@@ -55183,7 +55429,7 @@ function assertCodexPathConfigEditable(text2) {
|
|
|
55183
55429
|
delete expected.skills.config;
|
|
55184
55430
|
try {
|
|
55185
55431
|
const withoutSections = Bun.TOML.parse(text2.replace(CODEX_SKILL_CONFIG_SECTIONS, ""));
|
|
55186
|
-
if (
|
|
55432
|
+
if (isDeepStrictEqual5(withoutSections, expected))
|
|
55187
55433
|
return;
|
|
55188
55434
|
} catch {}
|
|
55189
55435
|
throw new Error("Codex skill path controls require ordinary [[skills.config]] TOML tables; preserve and convert inline or dotted config arrays before running skills hook install");
|
|
@@ -55221,7 +55467,7 @@ function disableCodexBundledSkills(text2) {
|
|
|
55221
55467
|
const candidates = new Set;
|
|
55222
55468
|
const consider = (candidate2) => {
|
|
55223
55469
|
try {
|
|
55224
|
-
if (
|
|
55470
|
+
if (isDeepStrictEqual5(Bun.TOML.parse(candidate2), expected))
|
|
55225
55471
|
candidates.add(candidate2);
|
|
55226
55472
|
} catch {}
|
|
55227
55473
|
};
|
|
@@ -55251,16 +55497,16 @@ var init_agent_codex = __esm(() => {
|
|
|
55251
55497
|
});
|
|
55252
55498
|
|
|
55253
55499
|
// src/lib/agent-integration.ts
|
|
55254
|
-
import { createHash as
|
|
55255
|
-
import { existsSync as existsSync15, lstatSync as
|
|
55256
|
-
import { dirname as
|
|
55500
|
+
import { createHash as createHash16, randomUUID as randomUUID6 } from "crypto";
|
|
55501
|
+
import { existsSync as existsSync15, lstatSync as lstatSync19, statSync as statSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync15, readdirSync as readdirSync10, opendirSync as opendirSync5, readlinkSync as readlinkSync2, realpathSync as realpathSync5, renameSync as renameSync4, rmdirSync as rmdirSync3, writeFileSync as writeFileSync6, unlinkSync as unlinkSync4, chmodSync, openSync as openSync12, closeSync as closeSync12, fsyncSync as fsyncSync4, fstatSync as fstatSync12, readSync as readSync10, constants as constants12, linkSync as linkSync2 } from "fs";
|
|
55502
|
+
import { dirname as dirname16, join as join29, resolve as resolve16, relative as relative5, isAbsolute as isAbsolute15, sep as sep6 } from "path";
|
|
55257
55503
|
import { homedir as homedir4 } from "os";
|
|
55258
55504
|
function assertSafePath(path) {
|
|
55259
55505
|
let cursor = resolve16(path);
|
|
55260
55506
|
while (true) {
|
|
55261
|
-
if (
|
|
55507
|
+
if (lstatSync19(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
55262
55508
|
throw new Error(`Refusing symlink path: ${cursor}`);
|
|
55263
|
-
const parent =
|
|
55509
|
+
const parent = dirname16(cursor);
|
|
55264
55510
|
if (parent === cursor)
|
|
55265
55511
|
return;
|
|
55266
55512
|
cursor = parent;
|
|
@@ -55269,12 +55515,12 @@ function assertSafePath(path) {
|
|
|
55269
55515
|
function readRootAlias(home, agent) {
|
|
55270
55516
|
assertSafePath(home);
|
|
55271
55517
|
const realHome = realpathSync5(home), alias = join29(realHome, `.${agent}`);
|
|
55272
|
-
const stat2 =
|
|
55518
|
+
const stat2 = lstatSync19(alias, { throwIfNoEntry: false, bigint: true });
|
|
55273
55519
|
if (!stat2?.isSymbolicLink())
|
|
55274
55520
|
throw new Error(`Agent root alias changed after planning: ${alias}`);
|
|
55275
|
-
const link2 = readlinkSync2(alias), targetPath = resolve16(
|
|
55521
|
+
const link2 = readlinkSync2(alias), targetPath = resolve16(dirname16(alias), link2);
|
|
55276
55522
|
assertSafePath(targetPath);
|
|
55277
|
-
const targetStat =
|
|
55523
|
+
const targetStat = lstatSync19(targetPath, { throwIfNoEntry: false });
|
|
55278
55524
|
if (!targetStat?.isDirectory())
|
|
55279
55525
|
throw new Error(`Agent root alias must target an existing directory: ${alias}`);
|
|
55280
55526
|
const target = realpathSync5(targetPath), inside = relative5(realHome, target);
|
|
@@ -55287,7 +55533,7 @@ function rootAliases(home, allowed = false) {
|
|
|
55287
55533
|
return [];
|
|
55288
55534
|
const result2 = [];
|
|
55289
55535
|
for (const agent of ["claude", "codex"])
|
|
55290
|
-
if (
|
|
55536
|
+
if (lstatSync19(join29(home, `.${agent}`), { throwIfNoEntry: false })?.isSymbolicLink())
|
|
55291
55537
|
result2.push(readRootAlias(home, agent));
|
|
55292
55538
|
if (result2.some((item, index) => result2.slice(index + 1).some((other) => item.target === other.target || item.target.startsWith(other.target + sep6) || other.target.startsWith(item.target + sep6))))
|
|
55293
55539
|
throw new Error("Agent root alias targets must not overlap");
|
|
@@ -55308,35 +55554,35 @@ function recheckRootAliases(aliases) {
|
|
|
55308
55554
|
}
|
|
55309
55555
|
function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
|
|
55310
55556
|
assertSafePath(path);
|
|
55311
|
-
const before2 =
|
|
55557
|
+
const before2 = lstatSync19(path);
|
|
55312
55558
|
if (!before2.isFile() || before2.size > maximum)
|
|
55313
55559
|
throw new Error("Unsupported or oversized native skill file");
|
|
55314
|
-
const descriptor =
|
|
55560
|
+
const descriptor = openSync12(path, constants12.O_RDONLY | constants12.O_NOFOLLOW | constants12.O_NONBLOCK);
|
|
55315
55561
|
try {
|
|
55316
|
-
const opened =
|
|
55562
|
+
const opened = fstatSync12(descriptor);
|
|
55317
55563
|
if (!opened.isFile() || opened.dev !== before2.dev || opened.ino !== before2.ino || opened.size !== before2.size)
|
|
55318
55564
|
throw new Error("Native skill file changed while reading");
|
|
55319
55565
|
const bytes = Buffer.allocUnsafe(before2.size + 1);
|
|
55320
55566
|
let length = 0;
|
|
55321
55567
|
while (length < bytes.length) {
|
|
55322
|
-
const count =
|
|
55568
|
+
const count = readSync10(descriptor, bytes, length, bytes.length - length, null);
|
|
55323
55569
|
if (!count)
|
|
55324
55570
|
break;
|
|
55325
55571
|
length += count;
|
|
55326
55572
|
}
|
|
55327
|
-
const after2 =
|
|
55573
|
+
const after2 = fstatSync12(descriptor);
|
|
55328
55574
|
if (length !== before2.size || after2.size !== before2.size || after2.mtimeMs !== opened.mtimeMs || after2.ctimeMs !== opened.ctimeMs)
|
|
55329
55575
|
throw new Error("Native skill file changed while reading");
|
|
55330
55576
|
return bytes.subarray(0, length);
|
|
55331
55577
|
} finally {
|
|
55332
|
-
|
|
55578
|
+
closeSync12(descriptor);
|
|
55333
55579
|
}
|
|
55334
55580
|
}
|
|
55335
55581
|
function treeHash(root2) {
|
|
55336
|
-
const hash2 =
|
|
55582
|
+
const hash2 = createHash16("sha256");
|
|
55337
55583
|
let bytes = 0, files = 0;
|
|
55338
55584
|
function visit2(path) {
|
|
55339
|
-
const stat2 =
|
|
55585
|
+
const stat2 = lstatSync19(path);
|
|
55340
55586
|
if (stat2.isSymbolicLink())
|
|
55341
55587
|
throw new Error(`Refusing symlink in skill: ${path}`);
|
|
55342
55588
|
const rel = relative5(root2, path);
|
|
@@ -55360,7 +55606,7 @@ function treeHash(root2) {
|
|
|
55360
55606
|
return hash2.digest("hex");
|
|
55361
55607
|
}
|
|
55362
55608
|
function parseNativeMigrationTargetManifest(input) {
|
|
55363
|
-
const digest2 =
|
|
55609
|
+
const digest2 = sha2(input);
|
|
55364
55610
|
let value;
|
|
55365
55611
|
try {
|
|
55366
55612
|
value = JSON.parse(input.toString());
|
|
@@ -55385,7 +55631,7 @@ function parseNativeMigrationTargetManifest(input) {
|
|
|
55385
55631
|
if (!INTEGRATION_AGENTS.includes(item.agent))
|
|
55386
55632
|
throw new Error(`Unsupported native migration target agent: ${item.agent}`);
|
|
55387
55633
|
const projectRoot = resolve16(item.projectRoot);
|
|
55388
|
-
if (!isAbsolute15(item.projectRoot) || projectRoot !== item.projectRoot || !existsSync15(projectRoot) || !
|
|
55634
|
+
if (!isAbsolute15(item.projectRoot) || projectRoot !== item.projectRoot || !existsSync15(projectRoot) || !lstatSync19(projectRoot).isDirectory())
|
|
55389
55635
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${item.projectRoot}`);
|
|
55390
55636
|
assertSafePath(projectRoot);
|
|
55391
55637
|
if (isAbsolute15(item.path) || item.path.includes("\\") || item.path.length === 0 || item.path.includes("\x00"))
|
|
@@ -55413,7 +55659,7 @@ function selectNativeMigrationTargets(inventory, manifest) {
|
|
|
55413
55659
|
const selected = [];
|
|
55414
55660
|
for (const target of manifest.targets) {
|
|
55415
55661
|
const projectRoot = resolve16(target.projectRoot), normalized = relative5(projectRoot, resolve16(projectRoot, target.path));
|
|
55416
|
-
if (!isAbsolute15(target.projectRoot) || projectRoot !== target.projectRoot || !existsSync15(projectRoot) || !
|
|
55662
|
+
if (!isAbsolute15(target.projectRoot) || projectRoot !== target.projectRoot || !existsSync15(projectRoot) || !lstatSync19(projectRoot).isDirectory())
|
|
55417
55663
|
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
55418
55664
|
assertSafePath(projectRoot);
|
|
55419
55665
|
if (isAbsolute15(target.path) || target.path.includes("\\") || target.path.includes("\x00") || !normalized || normalized === ".." || normalized.startsWith(`..${sep6}`) || normalized !== target.path || !/^[0-9a-f]{64}$/.test(target.treeSha256))
|
|
@@ -55442,7 +55688,7 @@ function projectAncestorDirectories(projects) {
|
|
|
55442
55688
|
if (depth >= 100)
|
|
55443
55689
|
throw new Error("NATIVE_SKILL_DRIFT: project ancestor discovery limit exceeded");
|
|
55444
55690
|
directories.add(path);
|
|
55445
|
-
const parent =
|
|
55691
|
+
const parent = dirname16(path);
|
|
55446
55692
|
if (parent === path)
|
|
55447
55693
|
break;
|
|
55448
55694
|
path = parent;
|
|
@@ -55473,9 +55719,9 @@ function inventoryNativeSkills(home = homedir4(), options = {}) {
|
|
|
55473
55719
|
}
|
|
55474
55720
|
function emptySiblingCacheAlias(path, parent) {
|
|
55475
55721
|
const link2 = readlinkSync2(path), target = resolve16(parent, link2);
|
|
55476
|
-
if (
|
|
55722
|
+
if (dirname16(target) !== parent || (isAbsolute15(link2) ? link2 !== target : dirname16(link2) !== "."))
|
|
55477
55723
|
return false;
|
|
55478
|
-
if (!
|
|
55724
|
+
if (!lstatSync19(target, { throwIfNoEntry: false })?.isDirectory())
|
|
55479
55725
|
return false;
|
|
55480
55726
|
const scan = cacheScans.get(target);
|
|
55481
55727
|
return Boolean(scan?.complete && !scan.hasSkills && scan.entries <= maxAliasProofEntries);
|
|
@@ -55487,7 +55733,7 @@ function inventoryNativeSkills(home = homedir4(), options = {}) {
|
|
|
55487
55733
|
assertSafePath(path);
|
|
55488
55734
|
if (!existsSync15(path))
|
|
55489
55735
|
return scan;
|
|
55490
|
-
const stat2 =
|
|
55736
|
+
const stat2 = lstatSync19(path);
|
|
55491
55737
|
if (stat2.isFile())
|
|
55492
55738
|
return scan;
|
|
55493
55739
|
if (!stat2.isDirectory())
|
|
@@ -55533,7 +55779,7 @@ function inventoryNativeSkills(home = homedir4(), options = {}) {
|
|
|
55533
55779
|
if (isVendor && !options.includeVendor)
|
|
55534
55780
|
continue;
|
|
55535
55781
|
const child = join29(path, name);
|
|
55536
|
-
if (isVendor &&
|
|
55782
|
+
if (isVendor && lstatSync19(child, { throwIfNoEntry: false })?.isSymbolicLink()) {
|
|
55537
55783
|
const target = statSync8(child, { throwIfNoEntry: false });
|
|
55538
55784
|
if (target?.isFile() || pluginCache && target?.isDirectory() && emptySiblingCacheAlias(child, path)) {
|
|
55539
55785
|
scan.entries++;
|
|
@@ -55743,7 +55989,7 @@ function planAgentIntegration(options) {
|
|
|
55743
55989
|
throw new Error("Refusing to overwrite an unrecognized Hermes supervisor");
|
|
55744
55990
|
if (supervisorBefore !== supervisorAfter)
|
|
55745
55991
|
changes.push({ path: supervisorPath, before: supervisorBefore, after: supervisorAfter });
|
|
55746
|
-
const supervisor = { path: supervisorPath, runtime: process.execPath, sha256:
|
|
55992
|
+
const supervisor = { path: supervisorPath, runtime: process.execPath, sha256: sha2(supervisorAfter) };
|
|
55747
55993
|
const after3 = configureHermesHooks(before2, supervisor, previous);
|
|
55748
55994
|
if (before2 !== after3)
|
|
55749
55995
|
changes.push({ path, before: before2, after: after3 });
|
|
@@ -55790,7 +56036,7 @@ function planAgentIntegration(options) {
|
|
|
55790
56036
|
agents: [...new Set([...priorAgents, ...options.agents])].sort(),
|
|
55791
56037
|
home: resolve16(home),
|
|
55792
56038
|
includeVendor: true,
|
|
55793
|
-
...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join29(dataDir3, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256:
|
|
56039
|
+
...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join29(dataDir3, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256: sha2(renderHermesSupervisor(bindings.get("hermes").command, bindings.get("hermes").profileId)) } } } : {},
|
|
55794
56040
|
commands: { ...policy.bridge?.commands, ...Object.fromEntries([...bindings].map(([agent, binding]) => [agent, binding.command])) },
|
|
55795
56041
|
profiles: Object.fromEntries([...new Set([...priorAgents, ...options.agents])].sort().map((agent) => [agent, bindings.get(agent)?.profileId ?? policy.bridge?.profiles?.[agent] ?? policy.profileId])),
|
|
55796
56042
|
disabledBuiltins: options.agents.includes("codex") ? nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor && entry.path.startsWith(canonicalAgentPath(join29(home, ".codex", "skills", ".system"), aliases) + sep6)).map((entry) => ({ path: entry.path, hash: entry.hash })) : policy.bridge?.disabledBuiltins ?? [],
|
|
@@ -55805,10 +56051,10 @@ function planAgentIntegration(options) {
|
|
|
55805
56051
|
}
|
|
55806
56052
|
function atomicWrite2(path, content) {
|
|
55807
56053
|
assertSafePath(path);
|
|
55808
|
-
mkdirSync7(
|
|
56054
|
+
mkdirSync7(dirname16(path), { recursive: true, mode: 448 });
|
|
55809
56055
|
const temporary = `${path}.skills-${randomUUID6()}`;
|
|
55810
56056
|
try {
|
|
55811
|
-
|
|
56057
|
+
writeFileSync6(temporary, content, { mode: 384, flag: "wx" });
|
|
55812
56058
|
renameSync4(temporary, path);
|
|
55813
56059
|
} finally {
|
|
55814
56060
|
if (existsSync15(temporary))
|
|
@@ -55842,8 +56088,8 @@ function applyAgentIntegration(plan) {
|
|
|
55842
56088
|
chmodSync(backupRoot, 448);
|
|
55843
56089
|
for (const [index, change] of plan.changes.entries())
|
|
55844
56090
|
if (change.before !== null) {
|
|
55845
|
-
const backup = join29(backupRoot, `${index}-${
|
|
55846
|
-
|
|
56091
|
+
const backup = join29(backupRoot, `${index}-${sha2(change.path).slice(0, 12)}.backup`);
|
|
56092
|
+
writeFileSync6(backup, change.before, { mode: 384, flag: "wx" });
|
|
55847
56093
|
backups.push(backup);
|
|
55848
56094
|
}
|
|
55849
56095
|
try {
|
|
@@ -55851,7 +56097,7 @@ function applyAgentIntegration(plan) {
|
|
|
55851
56097
|
recheckRootAliases(aliases);
|
|
55852
56098
|
if (currentText(change.path) !== change.before)
|
|
55853
56099
|
throw new Error(`Configuration changed after planning: ${change.path}`);
|
|
55854
|
-
for (let directory =
|
|
56100
|
+
for (let directory = dirname16(change.path);!existsSync15(directory); directory = dirname16(directory))
|
|
55855
56101
|
createdDirectories.add(directory);
|
|
55856
56102
|
const after2 = change.after;
|
|
55857
56103
|
atomicWrite2(change.path, after2);
|
|
@@ -55860,7 +56106,7 @@ function applyAgentIntegration(plan) {
|
|
|
55860
56106
|
recheckRootAliases(aliases);
|
|
55861
56107
|
for (const binding of plan.discoveryAfter ?? [])
|
|
55862
56108
|
verifyAgentDiscovery(binding);
|
|
55863
|
-
atomicWrite2(join29(backupRoot, "receipt.json"), JSON.stringify({ version: 1, changes: written.map((change) => ({ path: change.path, beforeHash: change.before === null ? null :
|
|
56109
|
+
atomicWrite2(join29(backupRoot, "receipt.json"), JSON.stringify({ version: 1, changes: written.map((change) => ({ path: change.path, beforeHash: change.before === null ? null : sha2(change.before), afterHash: sha2(change.after) })), backups, ...aliases.length ? { rootAliases: aliases } : {} }) + `
|
|
55864
56110
|
`);
|
|
55865
56111
|
} catch (error) {
|
|
55866
56112
|
for (const change of written.reverse()) {
|
|
@@ -55891,11 +56137,11 @@ function applyAgentIntegration(plan) {
|
|
|
55891
56137
|
}
|
|
55892
56138
|
function syncArchiveDirectory(path) {
|
|
55893
56139
|
assertSafePath(path);
|
|
55894
|
-
const descriptor =
|
|
56140
|
+
const descriptor = openSync12(path, constants12.O_RDONLY | constants12.O_DIRECTORY | constants12.O_NOFOLLOW | constants12.O_NONBLOCK);
|
|
55895
56141
|
try {
|
|
55896
|
-
|
|
56142
|
+
fsyncSync4(descriptor);
|
|
55897
56143
|
} finally {
|
|
55898
|
-
|
|
56144
|
+
closeSync12(descriptor);
|
|
55899
56145
|
}
|
|
55900
56146
|
}
|
|
55901
56147
|
function writeArchiveJournal(path, value) {
|
|
@@ -55903,18 +56149,18 @@ function writeArchiveJournal(path, value) {
|
|
|
55903
56149
|
const temporary = `${path}.skills-${randomUUID6()}`;
|
|
55904
56150
|
let descriptor;
|
|
55905
56151
|
try {
|
|
55906
|
-
descriptor =
|
|
55907
|
-
|
|
56152
|
+
descriptor = openSync12(temporary, constants12.O_WRONLY | constants12.O_CREAT | constants12.O_EXCL | constants12.O_NOFOLLOW, 384);
|
|
56153
|
+
writeFileSync6(descriptor, `${JSON.stringify(value)}
|
|
55908
56154
|
`);
|
|
55909
|
-
|
|
55910
|
-
|
|
56155
|
+
fsyncSync4(descriptor);
|
|
56156
|
+
closeSync12(descriptor);
|
|
55911
56157
|
descriptor = undefined;
|
|
55912
56158
|
renameSync4(temporary, path);
|
|
55913
|
-
syncArchiveDirectory(
|
|
56159
|
+
syncArchiveDirectory(dirname16(path));
|
|
55914
56160
|
} finally {
|
|
55915
56161
|
if (descriptor !== undefined)
|
|
55916
|
-
|
|
55917
|
-
if (
|
|
56162
|
+
closeSync12(descriptor);
|
|
56163
|
+
if (lstatSync19(temporary, { throwIfNoEntry: false }))
|
|
55918
56164
|
unlinkSync4(temporary);
|
|
55919
56165
|
}
|
|
55920
56166
|
}
|
|
@@ -55939,8 +56185,8 @@ function archiveNativeSkills(inventory, options) {
|
|
|
55939
56185
|
const operationId = randomUUID6(), archiveRoot = join29(options.dataDir ?? getDataDir(), "migration", operationId, "native"), receiptPath = join29(archiveRoot, "receipt.json");
|
|
55940
56186
|
const entries = selected.map((entry, index) => ({
|
|
55941
56187
|
source: entry.vendor ? join29(entry.path, "SKILL.md") : entry.path,
|
|
55942
|
-
archive: join29(archiveRoot, `${index}-${
|
|
55943
|
-
hash: entry.vendor ?
|
|
56188
|
+
archive: join29(archiveRoot, `${index}-${sha2(entry.path).slice(0, 12)}`),
|
|
56189
|
+
hash: entry.vendor ? sha2(readNativeBytes(join29(entry.path, "SKILL.md"))) : entry.hash,
|
|
55944
56190
|
...entry.vendor ? { discoveryOnly: true } : {},
|
|
55945
56191
|
status: "planned"
|
|
55946
56192
|
}));
|
|
@@ -55948,22 +56194,22 @@ function archiveNativeSkills(inventory, options) {
|
|
|
55948
56194
|
const moved = [];
|
|
55949
56195
|
const verifyArchive = (entry) => {
|
|
55950
56196
|
assertSafePath(entry.archive);
|
|
55951
|
-
const stat2 =
|
|
56197
|
+
const stat2 = lstatSync19(entry.archive);
|
|
55952
56198
|
if (entry.discoveryOnly ? !stat2.isFile() : !stat2.isDirectory())
|
|
55953
56199
|
throw new Error("Archive type changed");
|
|
55954
|
-
if ((entry.discoveryOnly ?
|
|
56200
|
+
if ((entry.discoveryOnly ? sha2(readNativeBytes(entry.archive)) : treeHash(entry.archive)) !== entry.hash)
|
|
55955
56201
|
throw new Error("Archive bytes changed");
|
|
55956
56202
|
};
|
|
55957
56203
|
assertSafePath(archiveRoot);
|
|
55958
56204
|
const created = [];
|
|
55959
|
-
for (let path = archiveRoot;!existsSync15(path); path =
|
|
56205
|
+
for (let path = archiveRoot;!existsSync15(path); path = dirname16(path))
|
|
55960
56206
|
created.push(path);
|
|
55961
56207
|
mkdirSync7(archiveRoot, { recursive: true, mode: 448 });
|
|
55962
56208
|
try {
|
|
55963
56209
|
for (const directory of created)
|
|
55964
56210
|
syncArchiveDirectory(directory);
|
|
55965
56211
|
if (created.length)
|
|
55966
|
-
syncArchiveDirectory(
|
|
56212
|
+
syncArchiveDirectory(dirname16(created.at(-1)));
|
|
55967
56213
|
writeArchiveJournal(receiptPath, journal);
|
|
55968
56214
|
for (const [index, entry] of selected.entries()) {
|
|
55969
56215
|
recheckRootAliases(aliases);
|
|
@@ -55975,7 +56221,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
55975
56221
|
writeArchiveJournal(receiptPath, journal);
|
|
55976
56222
|
renameSync4(move.source, move.archive);
|
|
55977
56223
|
moved.push(move);
|
|
55978
|
-
syncArchiveDirectory(
|
|
56224
|
+
syncArchiveDirectory(dirname16(move.source));
|
|
55979
56225
|
syncArchiveDirectory(archiveRoot);
|
|
55980
56226
|
verifyArchive(move);
|
|
55981
56227
|
move.status = "archived";
|
|
@@ -55996,7 +56242,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
55996
56242
|
recheckRootAliases(aliases);
|
|
55997
56243
|
assertSafePath(entry.source);
|
|
55998
56244
|
assertSafePath(entry.archive);
|
|
55999
|
-
if (
|
|
56245
|
+
if (lstatSync19(entry.source, { throwIfNoEntry: false })) {
|
|
56000
56246
|
entry.status = "recovery-required";
|
|
56001
56247
|
entry.conflict = "source-occupied";
|
|
56002
56248
|
continue;
|
|
@@ -56010,10 +56256,10 @@ function archiveNativeSkills(inventory, options) {
|
|
|
56010
56256
|
}
|
|
56011
56257
|
if (entry.discoveryOnly) {
|
|
56012
56258
|
linkSync2(entry.archive, entry.source);
|
|
56013
|
-
syncArchiveDirectory(
|
|
56259
|
+
syncArchiveDirectory(dirname16(entry.source));
|
|
56014
56260
|
unlinkSync4(entry.archive);
|
|
56015
56261
|
} else {
|
|
56016
|
-
if (
|
|
56262
|
+
if (lstatSync19(entry.source, { throwIfNoEntry: false })) {
|
|
56017
56263
|
entry.status = "recovery-required";
|
|
56018
56264
|
entry.conflict = "source-occupied";
|
|
56019
56265
|
continue;
|
|
@@ -56021,7 +56267,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
56021
56267
|
renameSync4(entry.archive, entry.source);
|
|
56022
56268
|
}
|
|
56023
56269
|
entry.status = "restored";
|
|
56024
|
-
syncArchiveDirectory(
|
|
56270
|
+
syncArchiveDirectory(dirname16(entry.source));
|
|
56025
56271
|
syncArchiveDirectory(archiveRoot);
|
|
56026
56272
|
} catch {
|
|
56027
56273
|
entry.status = "recovery-required";
|
|
@@ -56043,10 +56289,10 @@ function archiveNativeSkills(inventory, options) {
|
|
|
56043
56289
|
function assertManagedAgentBridge(agent, options = {}) {
|
|
56044
56290
|
const home = resolve16(options.home ?? homedir4()), dataDir3 = options.dataDir ?? getDataDirReadOnly();
|
|
56045
56291
|
assertSafePath(join29(dataDir3, "agent-policy.json"));
|
|
56046
|
-
const
|
|
56047
|
-
if (!
|
|
56292
|
+
const snapshot2 = readManagedSkillPolicySnapshot(dataDir3);
|
|
56293
|
+
if (!snapshot2)
|
|
56048
56294
|
throw new Error("NATIVE_SKILL_DRIFT: install the Skills bridge with skills hook install");
|
|
56049
|
-
const binding =
|
|
56295
|
+
const binding = snapshot2.value.bridge;
|
|
56050
56296
|
if (!binding || binding.version !== CLI_BRIDGE_VERSION || binding.digest !== CLI_BRIDGE_DIGEST || binding.home !== home || !Array.isArray(binding.agents) || !binding.agents.includes(agent))
|
|
56051
56297
|
throw new Error("NATIVE_SKILL_DRIFT: the managed Skills bridge binding is missing or incompatible; run skills hook install");
|
|
56052
56298
|
const aliases = binding.rootAliases ?? [];
|
|
@@ -56068,7 +56314,7 @@ function assertManagedAgentBridge(agent, options = {}) {
|
|
|
56068
56314
|
throw new Error("NATIVE_SKILL_DRIFT: the hook selection profile differs from its managed binding; restart the native client after reviewing skills hook install");
|
|
56069
56315
|
if (agent === "hermes") {
|
|
56070
56316
|
const supervisor = binding.supervisors?.hermes;
|
|
56071
|
-
if (supervisor?.path !== join29(dataDir3, "agent-hooks", "hermes.js") || supervisor?.sha256 !==
|
|
56317
|
+
if (supervisor?.path !== join29(dataDir3, "agent-hooks", "hermes.js") || supervisor?.sha256 !== sha2(renderHermesSupervisor(command, profile)))
|
|
56072
56318
|
throw new Error("NATIVE_SKILL_DRIFT: Hermes supervisor binding changed; run skills hook install");
|
|
56073
56319
|
assertHermesProtection(home, config, command, profile, supervisor);
|
|
56074
56320
|
} else if (agent === "opencode") {
|
|
@@ -56090,6 +56336,8 @@ function assertManagedAgentBridge(agent, options = {}) {
|
|
|
56090
56336
|
throw new Error("NATIVE_SKILL_DRIFT: Gemini bridge or bundled-skill protection changed; run skills hook install");
|
|
56091
56337
|
}
|
|
56092
56338
|
const codexPath = canonicalAgentPath(join29(home, ".codex", "config.toml"), aliases);
|
|
56339
|
+
if (options.codexDiscoveryRecovery && (agent !== "codex" || options.codexDiscoveryRecovery.configPath !== codexPath))
|
|
56340
|
+
throw new Error("NATIVE_SKILL_DRIFT: Codex trust recovery names a different configuration root");
|
|
56093
56341
|
const codexConfig = agent === "codex" ? Bun.TOML.parse(readOptional(codexPath) ?? "") : {};
|
|
56094
56342
|
if (agent === "codex" && codexConfig.skills?.bundled?.enabled !== false)
|
|
56095
56343
|
throw new Error("NATIVE_SKILL_DRIFT: Codex bundled skill reseeding is not disabled (skills.bundled.enabled); run skills hook install");
|
|
@@ -56108,7 +56356,7 @@ function assertManagedAgentBridge(agent, options = {}) {
|
|
|
56108
56356
|
if (agent === "gemini" && !discovery.builtinNames?.every((name) => config.skills.disabled.includes(name)))
|
|
56109
56357
|
throw new Error("NATIVE_SKILL_DRIFT: an installed Gemini builtin is not disabled");
|
|
56110
56358
|
try {
|
|
56111
|
-
verifyAgentDiscovery(discovery);
|
|
56359
|
+
verifyAgentDiscovery(discovery, options.codexDiscoveryRecovery);
|
|
56112
56360
|
if (discovery.method === "automatic") {
|
|
56113
56361
|
const current = resolveAgentDiscovery({ home, agent, canonical: (path) => canonicalAgentPath(path, aliases) });
|
|
56114
56362
|
if (JSON.stringify(current) !== JSON.stringify(discovery))
|
|
@@ -56164,7 +56412,7 @@ function assertNativeExportAllowed(dataDir3 = getDataDirReadOnly()) {
|
|
|
56164
56412
|
if (requiresCliSkillLoading(dataDir3))
|
|
56165
56413
|
throw new Error("NATIVE_SKILL_EXPORT_DISABLED: this station loads skills through the Skills CLI; use skills sync --selection-profile <id>");
|
|
56166
56414
|
}
|
|
56167
|
-
var
|
|
56415
|
+
var sha2 = (data) => createHash16("sha256").update(data).digest("hex"), HOOK_EVENTS, ROOTS, SKILLS_LOADING_POLICY = "Skills loading policy: discover skills with `skills list` or `skills search`, and read selected instructions with `skills load <slug>`. Use `skills sync` to refresh the shared profile. The only native skill is the owned skills-cli bridge. Create and edit payload skills in the Skills authoring workspace; do not copy payload instructions into native discovery folders. Context loading does not authorize execution; use `skills run` only when the task calls for running a skill.";
|
|
56168
56416
|
var init_agent_integration = __esm(() => {
|
|
56169
56417
|
init_config();
|
|
56170
56418
|
init_managed_policy();
|
|
@@ -56194,7 +56442,7 @@ var init_agent_integration = __esm(() => {
|
|
|
56194
56442
|
});
|
|
56195
56443
|
|
|
56196
56444
|
// src/lib/home-migration.ts
|
|
56197
|
-
import { existsSync as existsSync16, mkdirSync as mkdirSync8, readdirSync as readdirSync11, renameSync as renameSync5, rmSync as rmSync3, statSync as statSync9, writeFileSync as
|
|
56445
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync8, readdirSync as readdirSync11, renameSync as renameSync5, rmSync as rmSync3, statSync as statSync9, writeFileSync as writeFileSync7 } from "fs";
|
|
56198
56446
|
import { join as join30 } from "path";
|
|
56199
56447
|
function layoutMigrationRecordPath(appDir) {
|
|
56200
56448
|
return join30(appDir, SKILLS_CACHE_DIRNAME, LAYOUT_MIGRATION_RECORD);
|
|
@@ -56317,7 +56565,7 @@ function migrateOwnerLayout(options = {}) {
|
|
|
56317
56565
|
moved,
|
|
56318
56566
|
note: "installed/ and legacy flat skill dirs moved into skills/; custom/ retained"
|
|
56319
56567
|
};
|
|
56320
|
-
|
|
56568
|
+
writeFileSync7(layoutMigrationRecordPath(appDir), `${JSON.stringify(record2, null, 2)}
|
|
56321
56569
|
`);
|
|
56322
56570
|
return { status: "migrated", moved, created, record: record2 };
|
|
56323
56571
|
}
|
|
@@ -56332,7 +56580,7 @@ var init_home_migration = __esm(() => {
|
|
|
56332
56580
|
import {
|
|
56333
56581
|
cpSync as cpSync2,
|
|
56334
56582
|
existsSync as existsSync17,
|
|
56335
|
-
lstatSync as
|
|
56583
|
+
lstatSync as lstatSync20,
|
|
56336
56584
|
mkdirSync as mkdirSync9,
|
|
56337
56585
|
mkdtempSync as mkdtempSync2,
|
|
56338
56586
|
readFileSync as readFileSync16,
|
|
@@ -56340,17 +56588,17 @@ import {
|
|
|
56340
56588
|
renameSync as renameSync6,
|
|
56341
56589
|
rmSync as rmSync4,
|
|
56342
56590
|
statSync as statSync10,
|
|
56343
|
-
writeFileSync as
|
|
56591
|
+
writeFileSync as writeFileSync8
|
|
56344
56592
|
} from "fs";
|
|
56345
56593
|
import { homedir as homedir5 } from "os";
|
|
56346
|
-
import { basename as basename9, dirname as
|
|
56594
|
+
import { basename as basename9, dirname as dirname17, join as join31 } from "path";
|
|
56347
56595
|
function isSkillsOwnershipMarker(marker) {
|
|
56348
56596
|
return typeof marker === "object" && marker !== null && Object.hasOwn(marker, "managedBy") && marker.managedBy === SYNC_MARKER_MANAGED_BY;
|
|
56349
56597
|
}
|
|
56350
56598
|
function hasSkillsOwnershipMarker(dir) {
|
|
56351
56599
|
const path = join31(dir, SYNC_MARKER_FILE);
|
|
56352
56600
|
try {
|
|
56353
|
-
if (!
|
|
56601
|
+
if (!lstatSync20(path).isFile())
|
|
56354
56602
|
return false;
|
|
56355
56603
|
const marker = JSON.parse(readFileSync16(path, "utf8"));
|
|
56356
56604
|
return isSkillsOwnershipMarker(marker);
|
|
@@ -56575,7 +56823,7 @@ function writeManagedSkillDir(dir, skillMd, options) {
|
|
|
56575
56823
|
const action = dirExists ? "update" : "create";
|
|
56576
56824
|
if (options.dryRun)
|
|
56577
56825
|
return { action, path: skillMdPath };
|
|
56578
|
-
const parentDir =
|
|
56826
|
+
const parentDir = dirname17(dir);
|
|
56579
56827
|
mkdirSync9(parentDir, { recursive: true });
|
|
56580
56828
|
const transactionDir = mkdtempSync2(join31(parentDir, `.hasna-skills-write-${basename9(dir)}-`));
|
|
56581
56829
|
const candidateDir = join31(transactionDir, "candidate");
|
|
@@ -56597,10 +56845,10 @@ function writeManagedSkillDir(dir, skillMd, options) {
|
|
|
56597
56845
|
} else {
|
|
56598
56846
|
mkdirSync9(candidateDir, { recursive: true });
|
|
56599
56847
|
}
|
|
56600
|
-
|
|
56848
|
+
writeFileSync8(candidateSkillMdPath, skillMd.endsWith(`
|
|
56601
56849
|
`) ? skillMd : `${skillMd}
|
|
56602
56850
|
`);
|
|
56603
|
-
|
|
56851
|
+
writeFileSync8(candidateMarkerPath, `${JSON.stringify(marker, null, 2)}
|
|
56604
56852
|
`);
|
|
56605
56853
|
if (dirExists) {
|
|
56606
56854
|
originalMoved = true;
|
|
@@ -56665,7 +56913,7 @@ var init_agent_sync = __esm(() => {
|
|
|
56665
56913
|
});
|
|
56666
56914
|
|
|
56667
56915
|
// src/lib/project-state.ts
|
|
56668
|
-
import { existsSync as existsSync18, mkdirSync as mkdirSync10, readFileSync as readFileSync17, writeFileSync as
|
|
56916
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync10, readFileSync as readFileSync17, writeFileSync as writeFileSync9 } from "fs";
|
|
56669
56917
|
import { join as join32 } from "path";
|
|
56670
56918
|
function getProjectStateDir(targetDir = process.cwd()) {
|
|
56671
56919
|
return join32(targetDir, SKILLS_PROJECT_DIR);
|
|
@@ -56701,7 +56949,7 @@ function saveProjectConfig(config, targetDir = process.cwd()) {
|
|
|
56701
56949
|
const dir = getProjectStateDir(targetDir);
|
|
56702
56950
|
mkdirSync10(dir, { recursive: true });
|
|
56703
56951
|
const normalized = normalizeProjectConfig({ ...config, updatedAt: new Date().toISOString() });
|
|
56704
|
-
|
|
56952
|
+
writeFileSync9(getProjectConfigPath(targetDir), JSON.stringify(normalized, null, 2) + `
|
|
56705
56953
|
`);
|
|
56706
56954
|
}
|
|
56707
56955
|
function pinProjectSkill(name, details = {}, targetDir = process.cwd()) {
|
|
@@ -76515,7 +76763,7 @@ var init_v4 = __esm(() => {
|
|
|
76515
76763
|
});
|
|
76516
76764
|
|
|
76517
76765
|
// src/lib/canonical-json.ts
|
|
76518
|
-
import { createHash as
|
|
76766
|
+
import { createHash as createHash17 } from "crypto";
|
|
76519
76767
|
function canonicalJson2(value, maximumBytes = 2 * 1024 * 1024) {
|
|
76520
76768
|
return canonicalJsonAtDepth(value, maximumBytes, 64);
|
|
76521
76769
|
}
|
|
@@ -76559,7 +76807,7 @@ function canonicalJsonAtDepth(value, maximumBytes, maximumDepth) {
|
|
|
76559
76807
|
return visit3(value, 0);
|
|
76560
76808
|
}
|
|
76561
76809
|
function canonicalJsonSha256(value, maximumBytes) {
|
|
76562
|
-
return
|
|
76810
|
+
return createHash17("sha256").update(canonicalJson2(value, maximumBytes)).digest("hex");
|
|
76563
76811
|
}
|
|
76564
76812
|
var init_canonical_json = () => {};
|
|
76565
76813
|
|
|
@@ -76630,8 +76878,8 @@ function recurringFailure(value, status) {
|
|
|
76630
76878
|
}
|
|
76631
76879
|
function recurringInput(action, raw) {
|
|
76632
76880
|
try {
|
|
76633
|
-
const
|
|
76634
|
-
return inputs[action].parse(
|
|
76881
|
+
const snapshot2 = JSON.parse(canonicalJson2(raw, action === "preview" ? 1048576 : 4096));
|
|
76882
|
+
return inputs[action].parse(snapshot2);
|
|
76635
76883
|
} catch {
|
|
76636
76884
|
throw new RecurringInputError;
|
|
76637
76885
|
}
|
|
@@ -77159,9 +77407,9 @@ function timestamp2(value) {
|
|
|
77159
77407
|
const time3 = Date.parse(value);
|
|
77160
77408
|
return Number.isFinite(time3) && new Date(time3).toISOString().slice(0, 23) === value.slice(0, 23);
|
|
77161
77409
|
}
|
|
77162
|
-
function parseMember(row,
|
|
77410
|
+
function parseMember(row, fail3) {
|
|
77163
77411
|
if (!record5(row) || !uuid10(row.membershipId) || !uuid10(row.userId) || typeof row.email !== "string" || !row.email || !(row.displayName === null || typeof row.displayName === "string") || !isRole(row.role) || !timestamp2(row.createdAt))
|
|
77164
|
-
return
|
|
77412
|
+
return fail3();
|
|
77165
77413
|
return {
|
|
77166
77414
|
membershipId: row.membershipId,
|
|
77167
77415
|
userId: row.userId,
|
|
@@ -77188,14 +77436,14 @@ function workspaceMemberRemovalInput(membershipId, input2) {
|
|
|
77188
77436
|
return { membershipId: value.membershipId, body: { expectedRole: value.expectedRole } };
|
|
77189
77437
|
}
|
|
77190
77438
|
function parseWorkspaceMemberRoleResult(value, membershipId, role3) {
|
|
77191
|
-
const
|
|
77439
|
+
const fail3 = () => {
|
|
77192
77440
|
throw new Error(invalidMemberResult);
|
|
77193
77441
|
};
|
|
77194
77442
|
if (!record5(value) || !uuid10(value.organizationId) || typeof value.changed !== "boolean")
|
|
77195
|
-
return
|
|
77196
|
-
const member = parseMember(value.member,
|
|
77443
|
+
return fail3();
|
|
77444
|
+
const member = parseMember(value.member, fail3);
|
|
77197
77445
|
if (member.membershipId !== membershipId || member.role !== role3)
|
|
77198
|
-
return
|
|
77446
|
+
return fail3();
|
|
77199
77447
|
return { organizationId: value.organizationId, member, changed: value.changed };
|
|
77200
77448
|
}
|
|
77201
77449
|
function parseWorkspaceMemberRemovalResult(value, membershipId) {
|
|
@@ -77210,14 +77458,14 @@ function workspaceMemberFailure(value, status) {
|
|
|
77210
77458
|
return workspaceMemberFailures[code][0] === status ? code : null;
|
|
77211
77459
|
}
|
|
77212
77460
|
function parseWorkspaceMembersPage(value) {
|
|
77213
|
-
const
|
|
77461
|
+
const fail3 = () => {
|
|
77214
77462
|
throw new Error("The server returned an invalid workspace roster.");
|
|
77215
77463
|
};
|
|
77216
77464
|
if (!record5(value) || !uuid10(value.organizationId) || !Array.isArray(value.members) || value.members.length > 100 || !(value.nextCursor === null || cursor(value.nextCursor)) || !value.members.length && value.nextCursor !== null)
|
|
77217
|
-
return
|
|
77218
|
-
const members2 = value.members.map((row) => parseMember(row,
|
|
77465
|
+
return fail3();
|
|
77466
|
+
const members2 = value.members.map((row) => parseMember(row, fail3));
|
|
77219
77467
|
if (new Set(members2.map((row) => row.membershipId)).size !== members2.length)
|
|
77220
|
-
return
|
|
77468
|
+
return fail3();
|
|
77221
77469
|
return { organizationId: value.organizationId, members: members2, nextCursor: value.nextCursor };
|
|
77222
77470
|
}
|
|
77223
77471
|
var record5 = (value) => !!value && typeof value === "object" && !Array.isArray(value), cursor = (value) => typeof value === "string" && /^[A-Za-z0-9_-]{1,512}$/.test(value), uuid10 = (value) => typeof value === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i.test(value), isRole = (value) => typeof value === "string" && ["owner", "admin", "member", "viewer"].includes(value), WorkspaceMemberInputError, invalidMemberResult = "The server returned an invalid workspace member result. Refresh the roster before another action.", workspaceMemberFailures;
|
|
@@ -77312,14 +77560,14 @@ var init_remote_workspace_leave = __esm(() => {
|
|
|
77312
77560
|
});
|
|
77313
77561
|
|
|
77314
77562
|
// src/lib/auth-store.ts
|
|
77315
|
-
import { chmodSync as chmodSync2, existsSync as existsSync20, mkdirSync as mkdirSync11, readFileSync as readFileSync19, renameSync as renameSync7, statSync as statSync11, unlinkSync as unlinkSync5, writeFileSync as
|
|
77316
|
-
import { basename as basename10, dirname as
|
|
77563
|
+
import { chmodSync as chmodSync2, existsSync as existsSync20, mkdirSync as mkdirSync11, readFileSync as readFileSync19, renameSync as renameSync7, statSync as statSync11, unlinkSync as unlinkSync5, writeFileSync as writeFileSync10 } from "fs";
|
|
77564
|
+
import { basename as basename10, dirname as dirname18, join as join34 } from "path";
|
|
77317
77565
|
function getAuthFilePath(env3 = process.env) {
|
|
77318
77566
|
return skillsCredentialFilePath(env3);
|
|
77319
77567
|
}
|
|
77320
77568
|
function getIdentityFilePath(env3 = process.env) {
|
|
77321
77569
|
const file2 = skillsCredentialFilePath(env3);
|
|
77322
|
-
return join34(
|
|
77570
|
+
return join34(dirname18(file2), basename10(file2).replace(/^credentials/, "identity") + ".json");
|
|
77323
77571
|
}
|
|
77324
77572
|
function getAuthIdentity(env3 = process.env) {
|
|
77325
77573
|
return readIdentity(env3);
|
|
@@ -77353,7 +77601,7 @@ function getAuthConfig(env3 = process.env, options = {}) {
|
|
|
77353
77601
|
}
|
|
77354
77602
|
function writeCredentialValues(values2, env3 = process.env) {
|
|
77355
77603
|
const file2 = skillsCredentialFilePath(env3);
|
|
77356
|
-
mkdirSync11(
|
|
77604
|
+
mkdirSync11(dirname18(file2), { recursive: true, mode: 448 });
|
|
77357
77605
|
const lines = [];
|
|
77358
77606
|
const written = new Set;
|
|
77359
77607
|
if (existsSync20(file2)) {
|
|
@@ -77380,7 +77628,7 @@ function writeCredentialValues(values2, env3 = process.env) {
|
|
|
77380
77628
|
`) + `
|
|
77381
77629
|
`;
|
|
77382
77630
|
const temp = `${file2}.tmp-${process.pid}`;
|
|
77383
|
-
|
|
77631
|
+
writeFileSync10(temp, body, { mode: 384 });
|
|
77384
77632
|
chmodSync2(temp, 384);
|
|
77385
77633
|
renameSync7(temp, file2);
|
|
77386
77634
|
return file2;
|
|
@@ -77428,7 +77676,7 @@ function saveAuthConfig(config2, env3 = process.env, authenticatedOrigin) {
|
|
|
77428
77676
|
}
|
|
77429
77677
|
const identityFile = getIdentityFilePath(env3);
|
|
77430
77678
|
if (Object.keys(identity4).length > 0) {
|
|
77431
|
-
|
|
77679
|
+
writeFileSync10(identityFile, JSON.stringify({ ...identity4, apiUrl }, null, 2) + `
|
|
77432
77680
|
`, { mode: 384 });
|
|
77433
77681
|
chmodSync2(identityFile, 384);
|
|
77434
77682
|
} else {
|
|
@@ -78818,7 +79066,7 @@ var init_remote_client = __esm(() => {
|
|
|
78818
79066
|
});
|
|
78819
79067
|
|
|
78820
79068
|
// src/lib/revision.ts
|
|
78821
|
-
import { createHash as
|
|
79069
|
+
import { createHash as createHash18 } from "crypto";
|
|
78822
79070
|
function revisionIdOf(content) {
|
|
78823
79071
|
const canonicalContent = {
|
|
78824
79072
|
slug: content.slug,
|
|
@@ -78839,7 +79087,7 @@ function revisionIdOf(content) {
|
|
|
78839
79087
|
canonicalContent.replacementSlug = content.replacementSlug ?? null;
|
|
78840
79088
|
}
|
|
78841
79089
|
const canonical4 = JSON.stringify(canonicalContent);
|
|
78842
|
-
return
|
|
79090
|
+
return createHash18("sha256").update(canonical4).digest("hex");
|
|
78843
79091
|
}
|
|
78844
79092
|
var REVISION_ID_PATTERN;
|
|
78845
79093
|
var init_revision = __esm(() => {
|
|
@@ -78868,8 +79116,8 @@ var init_skill_bundles = __esm(() => {
|
|
|
78868
79116
|
});
|
|
78869
79117
|
|
|
78870
79118
|
// src/lib/pull.ts
|
|
78871
|
-
import { existsSync as existsSync21, mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync3, readFileSync as readFileSync20, renameSync as renameSync8, rmSync as rmSync6, writeFileSync as
|
|
78872
|
-
import { dirname as
|
|
79119
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync3, readFileSync as readFileSync20, renameSync as renameSync8, rmSync as rmSync6, writeFileSync as writeFileSync11 } from "fs";
|
|
79120
|
+
import { dirname as dirname19, join as join35 } from "path";
|
|
78873
79121
|
async function pullSkills(options = {}) {
|
|
78874
79122
|
const client2 = options.client !== undefined ? options.client : await createRemoteSkillsClient();
|
|
78875
79123
|
if (!client2) {
|
|
@@ -79173,8 +79421,8 @@ function installBundleAtomically(name, entries, options = {}, marker = {}) {
|
|
|
79173
79421
|
try {
|
|
79174
79422
|
for (const entry of entries) {
|
|
79175
79423
|
const destination = join35(staging, entry.path);
|
|
79176
|
-
mkdirSync12(
|
|
79177
|
-
|
|
79424
|
+
mkdirSync12(dirname19(destination), { recursive: true });
|
|
79425
|
+
writeFileSync11(destination, entry.bytes, { mode: entry.mode });
|
|
79178
79426
|
}
|
|
79179
79427
|
writePullMarker(staging, {
|
|
79180
79428
|
skill: name,
|
|
@@ -79215,7 +79463,7 @@ function writePullMarker(dir, record7) {
|
|
|
79215
79463
|
...record7.revisionId ? { revisionId: record7.revisionId } : {},
|
|
79216
79464
|
syncedAt: new Date().toISOString()
|
|
79217
79465
|
};
|
|
79218
|
-
|
|
79466
|
+
writeFileSync11(join35(dir, PULL_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
|
|
79219
79467
|
`);
|
|
79220
79468
|
}
|
|
79221
79469
|
async function safeMeta(client2, slug2) {
|
|
@@ -79288,7 +79536,7 @@ var init_pull = __esm(() => {
|
|
|
79288
79536
|
});
|
|
79289
79537
|
|
|
79290
79538
|
// src/lib/skill-context.ts
|
|
79291
|
-
import { createHash as
|
|
79539
|
+
import { createHash as createHash19 } from "crypto";
|
|
79292
79540
|
import { resolve as resolve17 } from "path";
|
|
79293
79541
|
function words2(value) {
|
|
79294
79542
|
return new Set(value.toLowerCase().match(/[a-z0-9]+/g) ?? []);
|
|
@@ -79377,7 +79625,7 @@ ${content}`;
|
|
|
79377
79625
|
`);
|
|
79378
79626
|
const receipt = {
|
|
79379
79627
|
schemaVersion: 1,
|
|
79380
|
-
id:
|
|
79628
|
+
id: createHash19("sha256").update(JSON.stringify({ profile: profile.profileRevision, sessionId, selections, omitted })).digest("hex"),
|
|
79381
79629
|
profileId: profile.profileId,
|
|
79382
79630
|
profileRevision: profile.profileRevision,
|
|
79383
79631
|
authority: profile.authority,
|
|
@@ -79399,7 +79647,7 @@ var init_skill_context = __esm(() => {
|
|
|
79399
79647
|
});
|
|
79400
79648
|
|
|
79401
79649
|
// src/lib/session-reconciliation.ts
|
|
79402
|
-
import { createHash as
|
|
79650
|
+
import { createHash as createHash20 } from "crypto";
|
|
79403
79651
|
function exactTimestamp(value) {
|
|
79404
79652
|
const parsed = value === undefined ? Number.NaN : Date.parse(value);
|
|
79405
79653
|
if (!Number.isFinite(parsed) || new Date(parsed).toISOString() !== value) {
|
|
@@ -79417,12 +79665,12 @@ function assertPlanWindow(issuedAt, expiresAt, now3) {
|
|
|
79417
79665
|
}
|
|
79418
79666
|
}
|
|
79419
79667
|
function inspectSkillSession(sessionId, options = {}) {
|
|
79420
|
-
const
|
|
79668
|
+
const snapshot2 = readSkillSessionSnapshot(sessionId, options), { receipt } = snapshot2;
|
|
79421
79669
|
return {
|
|
79422
79670
|
sessionId,
|
|
79423
|
-
path:
|
|
79424
|
-
receiptSha256:
|
|
79425
|
-
generation:
|
|
79671
|
+
path: snapshot2.path,
|
|
79672
|
+
receiptSha256: snapshot2.sha256,
|
|
79673
|
+
generation: snapshot2.generation,
|
|
79426
79674
|
verifiedAt: receipt.verifiedAt,
|
|
79427
79675
|
authority: receipt.profile.authority,
|
|
79428
79676
|
workspaceId: receipt.profile.workspaceId,
|
|
@@ -79447,8 +79695,8 @@ async function reconcileSkillSession(input2, options = {}) {
|
|
|
79447
79695
|
const expiresAt = input2.apply ? input2.planExpiresAt : new Date(now3 + SESSION_RECONCILIATION_PLAN_TTL_MS).toISOString();
|
|
79448
79696
|
if (input2.apply)
|
|
79449
79697
|
assertPlanWindow(issuedAt, expiresAt, now3);
|
|
79450
|
-
const
|
|
79451
|
-
if (
|
|
79698
|
+
const snapshot2 = readSkillSessionSnapshot(input2.sessionId, options), old = snapshot2.receipt;
|
|
79699
|
+
if (snapshot2.sha256 !== input2.receiptSha256 || old.profile.profileId !== input2.fromProfile || old.profile.profileRevision !== input2.fromRevision) {
|
|
79452
79700
|
throw new SkillSelectionError("SESSION_RECEIPT_CHANGED", "The current session receipt does not match the reviewed old bytes, profile and revision.");
|
|
79453
79701
|
}
|
|
79454
79702
|
const client2 = options.client ?? await createProfileClient();
|
|
@@ -79462,14 +79710,14 @@ async function reconcileSkillSession(input2, options = {}) {
|
|
|
79462
79710
|
}
|
|
79463
79711
|
const targetKeys = new Set(target.selections.map(selectionKey));
|
|
79464
79712
|
const loaded = old.loaded.filter((key) => targetKeys.has(key));
|
|
79465
|
-
const replacementGeneration = nextSkillSessionGeneration(
|
|
79713
|
+
const replacementGeneration = nextSkillSessionGeneration(snapshot2.generation);
|
|
79466
79714
|
const plan = {
|
|
79467
79715
|
schemaVersion: 1,
|
|
79468
79716
|
issuedAt,
|
|
79469
79717
|
expiresAt,
|
|
79470
79718
|
sessionId: input2.sessionId,
|
|
79471
|
-
sessionPath:
|
|
79472
|
-
before: { receiptSha256:
|
|
79719
|
+
sessionPath: snapshot2.path,
|
|
79720
|
+
before: { receiptSha256: snapshot2.sha256, generation: snapshot2.generation, profileId: old.profile.profileId, profileRevision: old.profile.profileRevision, selectionCount: old.profile.selections.length },
|
|
79473
79721
|
target: { authority: target.authority, workspaceId: target.workspaceId, profileId: target.profileId, profileRevision: target.profileRevision, profileSha256: digest3(target), selectionCount: target.selections.length },
|
|
79474
79722
|
replacementGeneration,
|
|
79475
79723
|
retainedLoadedCount: loaded.length,
|
|
@@ -79480,7 +79728,7 @@ async function reconcileSkillSession(input2, options = {}) {
|
|
|
79480
79728
|
if (input2.planDigest !== undefined && input2.planDigest !== planDigest)
|
|
79481
79729
|
throw new SkillSelectionError("SESSION_PLAN_CHANGED", "The session reconciliation plan differs from the reviewed plan.");
|
|
79482
79730
|
if (!input2.apply)
|
|
79483
|
-
return { applied: false, plan, planDigest, archivePath: undefined, receiptPath: undefined, beforeSha256:
|
|
79731
|
+
return { applied: false, plan, planDigest, archivePath: undefined, receiptPath: undefined, beforeSha256: snapshot2.sha256, afterSha256: undefined };
|
|
79484
79732
|
assertPlanWindow(issuedAt, expiresAt, (options.now ?? Date.now)());
|
|
79485
79733
|
const replacement = {
|
|
79486
79734
|
...old,
|
|
@@ -79489,10 +79737,10 @@ async function reconcileSkillSession(input2, options = {}) {
|
|
|
79489
79737
|
profile: target,
|
|
79490
79738
|
loaded
|
|
79491
79739
|
};
|
|
79492
|
-
const result2 = replaceSkillSession(skillSessionSnapshotBinding(
|
|
79740
|
+
const result2 = replaceSkillSession(skillSessionSnapshotBinding(snapshot2), replacement, { ...plan, planDigest }, options, () => assertPlanWindow(issuedAt, expiresAt, (options.now ?? Date.now)()));
|
|
79493
79741
|
return { applied: true, plan, planDigest, ...result2 };
|
|
79494
79742
|
}
|
|
79495
|
-
var SESSION_RECONCILIATION_PLAN_TTL_MS, digest3 = (value) =>
|
|
79743
|
+
var SESSION_RECONCILIATION_PLAN_TTL_MS, digest3 = (value) => createHash20("sha256").update(JSON.stringify(value)).digest("hex");
|
|
79496
79744
|
var init_session_reconciliation = __esm(() => {
|
|
79497
79745
|
init_profile_client();
|
|
79498
79746
|
init_selection_cache();
|
|
@@ -79508,7 +79756,7 @@ __export(exports_context, {
|
|
|
79508
79756
|
parseSkillContextInput: () => parseSkillContextInput,
|
|
79509
79757
|
contextResolverOptions: () => contextResolverOptions
|
|
79510
79758
|
});
|
|
79511
|
-
import { readSync as
|
|
79759
|
+
import { readSync as readSync11 } from "fs";
|
|
79512
79760
|
function selectedProfileId(explicit) {
|
|
79513
79761
|
return explicit ?? process.env.HASNA_SKILLS_SELECTION_PROFILE ?? readManagedSkillPolicy()?.profileId ?? "default";
|
|
79514
79762
|
}
|
|
@@ -79586,7 +79834,7 @@ async function readContextStdin() {
|
|
|
79586
79834
|
let size2 = 0;
|
|
79587
79835
|
while (true) {
|
|
79588
79836
|
const chunk2 = Buffer.allocUnsafe(8192);
|
|
79589
|
-
const count =
|
|
79837
|
+
const count = readSync11(0, chunk2, 0, chunk2.length, null);
|
|
79590
79838
|
if (count === 0)
|
|
79591
79839
|
break;
|
|
79592
79840
|
size2 += count;
|
|
@@ -81165,7 +81413,7 @@ var exports_init = {};
|
|
|
81165
81413
|
__export(exports_init, {
|
|
81166
81414
|
registerSetup: () => registerSetup
|
|
81167
81415
|
});
|
|
81168
|
-
import { existsSync as existsSync23, readFileSync as readFileSync23, writeFileSync as
|
|
81416
|
+
import { existsSync as existsSync23, readFileSync as readFileSync23, writeFileSync as writeFileSync12, appendFileSync } from "fs";
|
|
81169
81417
|
import { join as join37 } from "path";
|
|
81170
81418
|
function registerSetup(parent) {
|
|
81171
81419
|
parent.command("init").option("--json", "Output as JSON", false).option("--for <agent>", "Detect project type and show MCP registration guidance for agent").option("--scope <scope>", "Deprecated; agent skill-folder installs are disabled", "global").description("Initialize project for pinned skills (.env.example, .gitignore)").action((options) => handleInit(options));
|
|
@@ -81250,7 +81498,7 @@ Use: skills render`));
|
|
|
81250
81498
|
lines.push(`# Used by: ${skills.join(", ")}`);
|
|
81251
81499
|
lines.push(`${envVar}=`);
|
|
81252
81500
|
}
|
|
81253
|
-
|
|
81501
|
+
writeFileSync12(join37(cwd2, ".env.example"), lines.join(`
|
|
81254
81502
|
`) + `
|
|
81255
81503
|
`);
|
|
81256
81504
|
envVarCount = envMap.size;
|
|
@@ -81412,7 +81660,7 @@ var init_init = __esm(() => {
|
|
|
81412
81660
|
});
|
|
81413
81661
|
|
|
81414
81662
|
// src/lib/home-adoption.ts
|
|
81415
|
-
import { constants as
|
|
81663
|
+
import { constants as constants13, closeSync as closeSync13, fstatSync as fstatSync13, lstatSync as lstatSync21, openSync as openSync13, readSync as readSync12, existsSync as existsSync24, mkdirSync as mkdirSync13, readdirSync as readdirSync13, readFileSync as readFileSync25, rmSync as rmSync7, statSync as statSync12, writeFileSync as writeFileSync13 } from "fs";
|
|
81416
81664
|
import { homedir as homedir7 } from "os";
|
|
81417
81665
|
import { join as join38 } from "path";
|
|
81418
81666
|
function indexCanonicalCorpus(corpusRoot) {
|
|
@@ -81528,7 +81776,7 @@ function appendConflictsLedger(appDir, conflicts) {
|
|
|
81528
81776
|
for (const conflict of conflicts)
|
|
81529
81777
|
byKey.set(`${conflict.agent}/${conflict.skill}`, conflict);
|
|
81530
81778
|
ledger.entries = [...byKey.values()].sort((a, b) => `${a.agent}/${a.skill}`.localeCompare(`${b.agent}/${b.skill}`));
|
|
81531
|
-
|
|
81779
|
+
writeFileSync13(ledgerPath, `${JSON.stringify(ledger, null, 2)}
|
|
81532
81780
|
`);
|
|
81533
81781
|
}
|
|
81534
81782
|
function writeRollbackRecord(mode, entries, appDir = getDataDir()) {
|
|
@@ -81536,7 +81784,7 @@ function writeRollbackRecord(mode, entries, appDir = getDataDir()) {
|
|
|
81536
81784
|
mkdirSync13(dir, { recursive: true });
|
|
81537
81785
|
const file2 = join38(dir, `${mode}-${Date.now()}.json`);
|
|
81538
81786
|
const record7 = { version: 1, mode, timestamp: new Date().toISOString(), entries };
|
|
81539
|
-
|
|
81787
|
+
writeFileSync13(file2, `${JSON.stringify(record7, null, 2)}
|
|
81540
81788
|
`);
|
|
81541
81789
|
return file2;
|
|
81542
81790
|
}
|
|
@@ -81553,7 +81801,7 @@ function adoptUnmarkedHomes(options = {}) {
|
|
|
81553
81801
|
source: "adopted",
|
|
81554
81802
|
syncedAt: new Date().toISOString()
|
|
81555
81803
|
};
|
|
81556
|
-
|
|
81804
|
+
writeFileSync13(join38(entry.path, SYNC_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
|
|
81557
81805
|
`);
|
|
81558
81806
|
return { agent: entry.agent, skill: entry.skill, path: entry.path, hash: entry.hash, marker };
|
|
81559
81807
|
});
|
|
@@ -81567,25 +81815,25 @@ function adoptUnmarkedHomes(options = {}) {
|
|
|
81567
81815
|
function pruneOwnership(dir) {
|
|
81568
81816
|
let descriptor;
|
|
81569
81817
|
try {
|
|
81570
|
-
const directory =
|
|
81818
|
+
const directory = lstatSync21(dir);
|
|
81571
81819
|
if (!directory.isDirectory())
|
|
81572
81820
|
return;
|
|
81573
|
-
const markerPath = join38(dir, SYNC_MARKER_FILE), markerPathBefore =
|
|
81821
|
+
const markerPath = join38(dir, SYNC_MARKER_FILE), markerPathBefore = lstatSync21(markerPath);
|
|
81574
81822
|
if (!markerPathBefore.isFile())
|
|
81575
81823
|
return;
|
|
81576
|
-
descriptor =
|
|
81577
|
-
const before2 =
|
|
81824
|
+
descriptor = openSync13(markerPath, constants13.O_RDONLY | constants13.O_NOFOLLOW | constants13.O_NONBLOCK);
|
|
81825
|
+
const before2 = fstatSync13(descriptor);
|
|
81578
81826
|
if (!before2.isFile() || before2.dev !== markerPathBefore.dev || before2.ino !== markerPathBefore.ino || before2.size !== markerPathBefore.size || before2.mtimeMs !== markerPathBefore.mtimeMs || before2.ctimeMs !== markerPathBefore.ctimeMs || before2.size < 1 || before2.size > 65536)
|
|
81579
81827
|
return;
|
|
81580
81828
|
const bytes = Buffer.alloc(before2.size + 1);
|
|
81581
81829
|
let length = 0;
|
|
81582
81830
|
while (length < bytes.length) {
|
|
81583
|
-
const count =
|
|
81831
|
+
const count = readSync12(descriptor, bytes, length, bytes.length - length, length);
|
|
81584
81832
|
if (!count)
|
|
81585
81833
|
break;
|
|
81586
81834
|
length += count;
|
|
81587
81835
|
}
|
|
81588
|
-
const after2 =
|
|
81836
|
+
const after2 = fstatSync13(descriptor), current = lstatSync21(dir), markerPathAfter = lstatSync21(markerPath);
|
|
81589
81837
|
if (!markerPathAfter.isFile() || markerPathAfter.dev !== before2.dev || markerPathAfter.ino !== before2.ino || markerPathAfter.size !== before2.size || markerPathAfter.mtimeMs !== before2.mtimeMs || markerPathAfter.ctimeMs !== before2.ctimeMs || length !== before2.size || after2.size !== before2.size || after2.mtimeMs !== before2.mtimeMs || after2.ctimeMs !== before2.ctimeMs || !current.isDirectory() || current.dev !== directory.dev || current.ino !== directory.ino)
|
|
81590
81838
|
return;
|
|
81591
81839
|
const text3 = bytes.subarray(0, length).toString("utf8"), marker = JSON.parse(text3);
|
|
@@ -81596,7 +81844,7 @@ function pruneOwnership(dir) {
|
|
|
81596
81844
|
return;
|
|
81597
81845
|
} finally {
|
|
81598
81846
|
if (descriptor !== undefined)
|
|
81599
|
-
|
|
81847
|
+
closeSync13(descriptor);
|
|
81600
81848
|
}
|
|
81601
81849
|
}
|
|
81602
81850
|
function pruneStrayHomes(options = {}) {
|
|
@@ -81781,7 +82029,7 @@ var init_home_census = __esm(() => {
|
|
|
81781
82029
|
});
|
|
81782
82030
|
|
|
81783
82031
|
// src/cli/env-assignment.ts
|
|
81784
|
-
import { closeSync as
|
|
82032
|
+
import { closeSync as closeSync14, constants as constants14, fstatSync as fstatSync14, ftruncateSync as ftruncateSync2, lstatSync as lstatSync22, openSync as openSync14, readFileSync as readFileSync27, writeSync as writeSync3 } from "fs";
|
|
81785
82033
|
function serializeValue(value) {
|
|
81786
82034
|
if (controls.test(value))
|
|
81787
82035
|
throw new EnvAssignmentError("Environment values cannot contain control characters or newlines.");
|
|
@@ -81860,7 +82108,7 @@ function setEnvAssignment(path, assignment) {
|
|
|
81860
82108
|
try {
|
|
81861
82109
|
const previous = (() => {
|
|
81862
82110
|
try {
|
|
81863
|
-
return
|
|
82111
|
+
return lstatSync22(path);
|
|
81864
82112
|
} catch (error61) {
|
|
81865
82113
|
if (error61.code === "ENOENT")
|
|
81866
82114
|
return;
|
|
@@ -81869,8 +82117,8 @@ function setEnvAssignment(path, assignment) {
|
|
|
81869
82117
|
})();
|
|
81870
82118
|
if (previous && !previous.isFile())
|
|
81871
82119
|
throw new EnvAssignmentError("The project .env must be a regular file, not a symlink or special file.");
|
|
81872
|
-
descriptor =
|
|
81873
|
-
const opened =
|
|
82120
|
+
descriptor = openSync14(path, previous ? constants14.O_RDWR | constants14.O_NOFOLLOW | constants14.O_NONBLOCK : constants14.O_WRONLY | constants14.O_CREAT | constants14.O_EXCL | constants14.O_NOFOLLOW, 384);
|
|
82121
|
+
const opened = fstatSync14(descriptor);
|
|
81874
82122
|
if (!opened.isFile() || previous && (opened.ino !== previous.ino || opened.dev !== previous.dev)) {
|
|
81875
82123
|
throw new EnvAssignmentError("The project .env changed while opening it; retry with a regular file.");
|
|
81876
82124
|
}
|
|
@@ -81897,7 +82145,7 @@ function setEnvAssignment(path, assignment) {
|
|
|
81897
82145
|
throw new EnvAssignmentError("Cannot safely read or write the project .env file.");
|
|
81898
82146
|
} finally {
|
|
81899
82147
|
if (descriptor !== undefined)
|
|
81900
|
-
|
|
82148
|
+
closeSync14(descriptor);
|
|
81901
82149
|
}
|
|
81902
82150
|
}
|
|
81903
82151
|
var INVALID_LAYOUT = "Cannot safely update .env with multiline or unsupported assignments. Use single-line KEY=VALUE entries or edit the file manually.", controls, EnvAssignmentError;
|
|
@@ -82415,7 +82663,7 @@ var init_cloud_executions = __esm(() => {
|
|
|
82415
82663
|
// node_modules/@hasna/secrets/dist/sdk.js
|
|
82416
82664
|
import { isIP as isIP3 } from "net";
|
|
82417
82665
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
82418
|
-
import { closeSync as
|
|
82666
|
+
import { closeSync as closeSync15, fstatSync as fstatSync15, openSync as openSync15, readFileSync as readFileSync29 } from "fs";
|
|
82419
82667
|
import { O_NOFOLLOW as O_NOFOLLOW3, O_NONBLOCK as O_NONBLOCK3, O_RDONLY as O_RDONLY3 } from "constants";
|
|
82420
82668
|
import { createRequire as createRequire2 } from "module";
|
|
82421
82669
|
import { hostname as osHostname2 } from "os";
|
|
@@ -82520,7 +82768,7 @@ function readAppConfigFile2(path) {
|
|
|
82520
82768
|
};
|
|
82521
82769
|
let fd = -1;
|
|
82522
82770
|
try {
|
|
82523
|
-
fd =
|
|
82771
|
+
fd = openSync15(path, O_RDONLY3 | O_NOFOLLOW3 | O_NONBLOCK3);
|
|
82524
82772
|
} catch (error61) {
|
|
82525
82773
|
const code = error61.code;
|
|
82526
82774
|
if (code === "ENOENT" || code === "ENOTDIR")
|
|
@@ -82530,7 +82778,7 @@ function readAppConfigFile2(path) {
|
|
|
82530
82778
|
unsafe(`the path could not be opened (${code ?? "unknown error"})`);
|
|
82531
82779
|
}
|
|
82532
82780
|
try {
|
|
82533
|
-
const before2 =
|
|
82781
|
+
const before2 = fstatSync15(fd);
|
|
82534
82782
|
if (!before2.isFile())
|
|
82535
82783
|
unsafe("the path is not a regular file");
|
|
82536
82784
|
if (!configFileModeAllowed2(before2.mode)) {
|
|
@@ -82542,14 +82790,14 @@ function readAppConfigFile2(path) {
|
|
|
82542
82790
|
if (before2.size > MAX_CREDENTIAL_FILE_BYTES2)
|
|
82543
82791
|
unsafe("the file exceeds the size limit");
|
|
82544
82792
|
const bytes = readFileSync29(fd);
|
|
82545
|
-
const after2 =
|
|
82793
|
+
const after2 = fstatSync15(fd);
|
|
82546
82794
|
if (!configFileReadsCoherent2(before2, after2)) {
|
|
82547
82795
|
unsafe("the file changed while being read");
|
|
82548
82796
|
}
|
|
82549
82797
|
return parseEnvFile2(bytes.toString("utf8"));
|
|
82550
82798
|
} finally {
|
|
82551
82799
|
if (fd !== -1)
|
|
82552
|
-
|
|
82800
|
+
closeSync15(fd);
|
|
82553
82801
|
}
|
|
82554
82802
|
}
|
|
82555
82803
|
function readCredentialFile2(path, apiKeyKeys) {
|
|
@@ -82599,14 +82847,14 @@ function assertUsableCredential2(appName, source, value) {
|
|
|
82599
82847
|
return;
|
|
82600
82848
|
throw new CredentialResolutionError2(appName, `The credential from ${source} contains characters that cannot be sent in an HTTP header ` + `(a control character or non-ASCII byte). A file written with CR-only line endings is the usual ` + `cause. Rewrite that credential file with one LF-terminated KEY=value line. ` + `The value is not shown here, and is deliberately never logged.`, [source]);
|
|
82601
82849
|
}
|
|
82602
|
-
function sealCredential2(
|
|
82603
|
-
const { apiKey } =
|
|
82850
|
+
function sealCredential2(fields2) {
|
|
82851
|
+
const { apiKey } = fields2;
|
|
82604
82852
|
const visible = {
|
|
82605
|
-
tier:
|
|
82606
|
-
source:
|
|
82607
|
-
deliberate:
|
|
82608
|
-
diskCandidates: Object.freeze([...
|
|
82609
|
-
warning:
|
|
82853
|
+
tier: fields2.tier,
|
|
82854
|
+
source: fields2.source,
|
|
82855
|
+
deliberate: fields2.deliberate,
|
|
82856
|
+
diskCandidates: Object.freeze([...fields2.diskCandidates]),
|
|
82857
|
+
warning: fields2.warning
|
|
82610
82858
|
};
|
|
82611
82859
|
const sealed = { ...visible };
|
|
82612
82860
|
Object.defineProperty(sealed, "apiKey", {
|
|
@@ -82615,9 +82863,9 @@ function sealCredential2(fields) {
|
|
|
82615
82863
|
writable: false,
|
|
82616
82864
|
configurable: false
|
|
82617
82865
|
});
|
|
82618
|
-
if (
|
|
82866
|
+
if (fields2.pointerVaultKey !== undefined) {
|
|
82619
82867
|
Object.defineProperty(sealed, "pointerVaultKey", {
|
|
82620
|
-
value:
|
|
82868
|
+
value: fields2.pointerVaultKey,
|
|
82621
82869
|
enumerable: false,
|
|
82622
82870
|
writable: false,
|
|
82623
82871
|
configurable: false
|
|
@@ -82755,7 +83003,7 @@ function keychainConfigValue2(name, env3, options = {}) {
|
|
|
82755
83003
|
function snapshotClientEnvironment2(name, env3) {
|
|
82756
83004
|
const keys2 = clientTransportEnvKeys2(name);
|
|
82757
83005
|
const ambient = isAmbientEnvironment2(env3);
|
|
82758
|
-
const
|
|
83006
|
+
const snapshot2 = Object.create(null);
|
|
82759
83007
|
for (const key of [
|
|
82760
83008
|
...keys2.apiUrlKeys,
|
|
82761
83009
|
...keys2.apiKeyKeys,
|
|
@@ -82777,17 +83025,17 @@ function snapshotClientEnvironment2(name, env3) {
|
|
|
82777
83025
|
if (descriptor.value !== undefined && typeof descriptor.value !== "string") {
|
|
82778
83026
|
throw new CredentialResolutionError2(name, `${key} must be a string data property.`, [key]);
|
|
82779
83027
|
}
|
|
82780
|
-
|
|
83028
|
+
snapshot2[key] = descriptor.value;
|
|
82781
83029
|
}
|
|
82782
83030
|
if (ambient) {
|
|
82783
|
-
Object.defineProperty(
|
|
83031
|
+
Object.defineProperty(snapshot2, AMBIENT_ENVIRONMENT2, {
|
|
82784
83032
|
value: true,
|
|
82785
83033
|
enumerable: false,
|
|
82786
83034
|
writable: false,
|
|
82787
83035
|
configurable: false
|
|
82788
83036
|
});
|
|
82789
83037
|
}
|
|
82790
|
-
return Object.freeze(
|
|
83038
|
+
return Object.freeze(snapshot2);
|
|
82791
83039
|
}
|
|
82792
83040
|
function resolveCredential2(name, env3, options = {}) {
|
|
82793
83041
|
env3 = snapshotClientEnvironment2(name, env3);
|
|
@@ -83715,7 +83963,7 @@ var init_sdk = __esm(() => {
|
|
|
83715
83963
|
});
|
|
83716
83964
|
|
|
83717
83965
|
// src/lib/execution-secrets.ts
|
|
83718
|
-
import { constants as
|
|
83966
|
+
import { constants as constants15, closeSync as closeSync16, fstatSync as fstatSync16, openSync as openSync16, readSync as readSync13, realpathSync as realpathSync6 } from "fs";
|
|
83719
83967
|
import { hostname as stationHostname } from "os";
|
|
83720
83968
|
function selectedSecretBindingsTemplate(scope, names, createClient2 = createSecretsClientFromEnv) {
|
|
83721
83969
|
let secretsAuthority;
|
|
@@ -83759,13 +84007,13 @@ function declaredSecretNames(value) {
|
|
|
83759
84007
|
function readSelectedSecretBindings(path) {
|
|
83760
84008
|
let fd;
|
|
83761
84009
|
try {
|
|
83762
|
-
fd =
|
|
83763
|
-
const stat2 =
|
|
84010
|
+
fd = openSync16(path, constants15.O_RDONLY | constants15.O_NOFOLLOW | constants15.O_NONBLOCK);
|
|
84011
|
+
const stat2 = fstatSync16(fd);
|
|
83764
84012
|
if (!stat2.isFile() || stat2.size > 65536)
|
|
83765
84013
|
throw new Error;
|
|
83766
84014
|
const bytes = Buffer.alloc(65537);
|
|
83767
84015
|
let size2 = 0, count;
|
|
83768
|
-
while ((count =
|
|
84016
|
+
while ((count = readSync13(fd, bytes, size2, bytes.length - size2, null)) > 0) {
|
|
83769
84017
|
size2 += count;
|
|
83770
84018
|
if (size2 > 65536)
|
|
83771
84019
|
throw new Error;
|
|
@@ -83775,7 +84023,7 @@ function readSelectedSecretBindings(path) {
|
|
|
83775
84023
|
return refuse("INVALID_SECRET_BINDINGS", "Secret bindings must be a regular JSON file of at most 64 KiB, containing reference names only.");
|
|
83776
84024
|
} finally {
|
|
83777
84025
|
if (fd !== undefined)
|
|
83778
|
-
|
|
84026
|
+
closeSync16(fd);
|
|
83779
84027
|
}
|
|
83780
84028
|
}
|
|
83781
84029
|
function validateSelectedSecretBindings(value, scope, names) {
|
|
@@ -83982,7 +84230,7 @@ var init_execution_grants = __esm(() => {
|
|
|
83982
84230
|
});
|
|
83983
84231
|
|
|
83984
84232
|
// src/lib/execution-grant-client.ts
|
|
83985
|
-
import { isDeepStrictEqual as
|
|
84233
|
+
import { isDeepStrictEqual as isDeepStrictEqual6 } from "util";
|
|
83986
84234
|
function id(value) {
|
|
83987
84235
|
if (!grantIdentifier(value))
|
|
83988
84236
|
throw new Error("Invalid execution grant profile or revision identifier.");
|
|
@@ -84026,26 +84274,26 @@ async function readExecutionGrantPolicy(profileId, revision) {
|
|
|
84026
84274
|
return policy;
|
|
84027
84275
|
}
|
|
84028
84276
|
async function saveExecutionGrantPolicy(profileId, grants, revision) {
|
|
84029
|
-
const
|
|
84277
|
+
const snapshot2 = validateExecutionGrants(grants);
|
|
84030
84278
|
if (revision !== undefined)
|
|
84031
84279
|
id(revision);
|
|
84032
84280
|
const policy = validateExecutionGrantPolicy(await request(`/execution-grants/${id(profileId)}`, {
|
|
84033
84281
|
method: "PUT",
|
|
84034
84282
|
headers: revision === undefined ? { "If-None-Match": "*" } : { "If-Match": `"${revision}"` },
|
|
84035
|
-
body: JSON.stringify({ grants:
|
|
84283
|
+
body: JSON.stringify({ grants: snapshot2 })
|
|
84036
84284
|
}));
|
|
84037
|
-
if (policy.profileId !== profileId || policy.previousRevision !== (revision ?? null) || !
|
|
84285
|
+
if (policy.profileId !== profileId || policy.previousRevision !== (revision ?? null) || !isDeepStrictEqual6(policy.grants, snapshot2)) {
|
|
84038
84286
|
throw new Error("The API did not preserve the reviewed execution grant policy; read it before retrying.");
|
|
84039
84287
|
}
|
|
84040
84288
|
return policy;
|
|
84041
84289
|
}
|
|
84042
84290
|
async function resolveExecutionGrant(input2) {
|
|
84043
|
-
const
|
|
84044
|
-
const value = await request(`/execution-grants/${id(
|
|
84291
|
+
const snapshot2 = validateExecutionGrantRequest(input2);
|
|
84292
|
+
const value = await request(`/execution-grants/${id(snapshot2.selection.profileId)}/resolve`, { method: "POST", body: JSON.stringify(snapshot2) }, snapshot2.selection.authority);
|
|
84045
84293
|
if (!grantRecord(value) || Object.keys(value).length !== 3 || !grantIdentifier(value.policyRevision) || !grantIdentifier(value.grantId) || !grantRecord(value.bindings)) {
|
|
84046
84294
|
throw new SkillSelectionError("INVALID_EXECUTION_GRANT", "The Skills API returned an invalid execution grant.");
|
|
84047
84295
|
}
|
|
84048
|
-
if (!
|
|
84296
|
+
if (!isDeepStrictEqual6(value.bindings.selection, snapshot2.selection) || !isDeepStrictEqual6(value.bindings.consumer, snapshot2.consumer)) {
|
|
84049
84297
|
throw new SkillSelectionError("EXECUTION_GRANT_SCOPE_MISMATCH", "The Skills API returned a grant for a different selection or consumer.");
|
|
84050
84298
|
}
|
|
84051
84299
|
return value;
|
|
@@ -84064,10 +84312,10 @@ __export(exports_selected_run, {
|
|
|
84064
84312
|
prepareSelectedSecretBindings: () => prepareSelectedSecretBindings,
|
|
84065
84313
|
executeSelectedLocal: () => executeSelectedLocal
|
|
84066
84314
|
});
|
|
84067
|
-
import { createHash as
|
|
84315
|
+
import { createHash as createHash21 } from "crypto";
|
|
84068
84316
|
import { spawn as spawn2 } from "child_process";
|
|
84069
|
-
import { mkdirSync as mkdirSync14, mkdtempSync as mkdtempSync4, writeFileSync as
|
|
84070
|
-
import { dirname as
|
|
84317
|
+
import { mkdirSync as mkdirSync14, mkdtempSync as mkdtempSync4, writeFileSync as writeFileSync14, realpathSync as realpathSync7 } from "fs";
|
|
84318
|
+
import { dirname as dirname20, join as join42, resolve as resolve18 } from "path";
|
|
84071
84319
|
import { tmpdir, hostname as stationHostname2 } from "os";
|
|
84072
84320
|
async function resolveSelectedRun(spec, profileId, options = {}) {
|
|
84073
84321
|
const context = await resolveSelectionContext(profileId, options);
|
|
@@ -84156,8 +84404,8 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
84156
84404
|
throw new SkillSelectionError("INVALID_BUNDLE_PATH", "The execution bundle path exceeds its limit.");
|
|
84157
84405
|
});
|
|
84158
84406
|
const destination = join42(runDirectory, entry.path);
|
|
84159
|
-
mkdirSync14(
|
|
84160
|
-
|
|
84407
|
+
mkdirSync14(dirname20(destination), { recursive: true, mode: 448 });
|
|
84408
|
+
writeFileSync14(destination, entry.bytes, { flag: "wx", mode: entry.mode & 511 });
|
|
84161
84409
|
}
|
|
84162
84410
|
env3.SKILLS_INPUT_JSON = input2;
|
|
84163
84411
|
env3.SKILLS_WORKSPACE_DIR = resolve18(options.cwd ?? process.cwd());
|
|
@@ -84190,13 +84438,13 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
84190
84438
|
selection: selection2,
|
|
84191
84439
|
target: "local",
|
|
84192
84440
|
runtime: runtimeName,
|
|
84193
|
-
inputDigest: `sha256:${
|
|
84441
|
+
inputDigest: `sha256:${createHash21("sha256").update(input2).digest("hex")}`,
|
|
84194
84442
|
runDirectory,
|
|
84195
84443
|
...executionGrant ? { executionGrant } : {},
|
|
84196
84444
|
...bindings ? { secretBinding: { schema: bindings.schema, selection: bindings.selection, consumer: bindings.consumer, secretsAuthority: bindings.secretsAuthority, bindings: bindings.bindings } } : {},
|
|
84197
84445
|
...result2
|
|
84198
84446
|
};
|
|
84199
|
-
|
|
84447
|
+
writeFileSync14(join42(runDirectory, ".execution-receipt.json"), JSON.stringify({ ...receipt, stdout: undefined, stderr: undefined }), { mode: 384 });
|
|
84200
84448
|
return receipt;
|
|
84201
84449
|
}
|
|
84202
84450
|
async function subprocess(command, cwd2, env3, input2, timeoutMs) {
|
|
@@ -88407,8 +88655,8 @@ var init_runs = __esm(() => {
|
|
|
88407
88655
|
});
|
|
88408
88656
|
|
|
88409
88657
|
// src/lib/run-state.ts
|
|
88410
|
-
import { createHash as
|
|
88411
|
-
import { existsSync as existsSync27, mkdirSync as mkdirSync15, readFileSync as readFileSync30, readdirSync as readdirSync16, statSync as statSync15, writeFileSync as
|
|
88658
|
+
import { createHash as createHash22, randomBytes } from "crypto";
|
|
88659
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync15, readFileSync as readFileSync30, readdirSync as readdirSync16, statSync as statSync15, writeFileSync as writeFileSync15 } from "fs";
|
|
88412
88660
|
import { extname, join as join43, relative as relative6 } from "path";
|
|
88413
88661
|
function createSkillRun(params, targetDir = process.cwd()) {
|
|
88414
88662
|
const now3 = new Date;
|
|
@@ -88473,15 +88721,15 @@ function updateSkillRun(context, patch) {
|
|
|
88473
88721
|
return context.record;
|
|
88474
88722
|
}
|
|
88475
88723
|
function writeRunLogs(context, stdout = "", stderr = "") {
|
|
88476
|
-
|
|
88477
|
-
|
|
88724
|
+
writeFileSync15(join43(context.logsDir, "stdout.log"), stdout);
|
|
88725
|
+
writeFileSync15(join43(context.logsDir, "stderr.log"), stderr);
|
|
88478
88726
|
}
|
|
88479
88727
|
function appendRunEvent(context, event, data = {}) {
|
|
88480
88728
|
const line = JSON.stringify({ ts: new Date().toISOString(), event, ...data }) + `
|
|
88481
88729
|
`;
|
|
88482
88730
|
const path = join43(context.runDir, "events.ndjson");
|
|
88483
88731
|
const previous = existsSync27(path) ? readFileSync30(path, "utf-8") : "";
|
|
88484
|
-
|
|
88732
|
+
writeFileSync15(path, previous + line);
|
|
88485
88733
|
}
|
|
88486
88734
|
function listSkillRuns(targetDir = process.cwd(), limit = 50) {
|
|
88487
88735
|
const runsRoot = join43(getProjectStateDir(targetDir), "runs");
|
|
@@ -88527,11 +88775,11 @@ function getRunExportDir(runId2, skill, targetDir = process.cwd()) {
|
|
|
88527
88775
|
return join43(getProjectStateDir(targetDir), "exports", normalizeSkillName(skill), runId2);
|
|
88528
88776
|
}
|
|
88529
88777
|
function writeRunRecord(context) {
|
|
88530
|
-
|
|
88778
|
+
writeFileSync15(join43(context.runDir, "run.json"), JSON.stringify(context.record, null, 2) + `
|
|
88531
88779
|
`);
|
|
88532
88780
|
}
|
|
88533
88781
|
function writeArtifactsManifest(context, artifacts) {
|
|
88534
|
-
|
|
88782
|
+
writeFileSync15(join43(context.runDir, "artifacts.json"), JSON.stringify({ runId: context.record.id, artifacts }, null, 2) + `
|
|
88535
88783
|
`);
|
|
88536
88784
|
}
|
|
88537
88785
|
function collectRunArtifacts(context) {
|
|
@@ -88544,7 +88792,7 @@ function collectRunArtifacts(context) {
|
|
|
88544
88792
|
artifacts.push({
|
|
88545
88793
|
path: toProjectRelative(context.targetDir, path),
|
|
88546
88794
|
mime: mimeForPath(path),
|
|
88547
|
-
sha256:
|
|
88795
|
+
sha256: createHash22("sha256").update(bytes).digest("hex"),
|
|
88548
88796
|
sizeBytes: stat2.size
|
|
88549
88797
|
});
|
|
88550
88798
|
}
|
|
@@ -92501,11 +92749,11 @@ var require_codegen = __commonJS((exports) => {
|
|
|
92501
92749
|
const rhs = this.rhs === undefined ? "" : ` = ${this.rhs}`;
|
|
92502
92750
|
return `${varKind} ${this.name}${rhs};` + _n;
|
|
92503
92751
|
}
|
|
92504
|
-
optimizeNames(names,
|
|
92752
|
+
optimizeNames(names, constants16) {
|
|
92505
92753
|
if (!names[this.name.str])
|
|
92506
92754
|
return;
|
|
92507
92755
|
if (this.rhs)
|
|
92508
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
92756
|
+
this.rhs = optimizeExpr(this.rhs, names, constants16);
|
|
92509
92757
|
return this;
|
|
92510
92758
|
}
|
|
92511
92759
|
get names() {
|
|
@@ -92523,10 +92771,10 @@ var require_codegen = __commonJS((exports) => {
|
|
|
92523
92771
|
render({ _n }) {
|
|
92524
92772
|
return `${this.lhs} = ${this.rhs};` + _n;
|
|
92525
92773
|
}
|
|
92526
|
-
optimizeNames(names,
|
|
92774
|
+
optimizeNames(names, constants16) {
|
|
92527
92775
|
if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects)
|
|
92528
92776
|
return;
|
|
92529
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
92777
|
+
this.rhs = optimizeExpr(this.rhs, names, constants16);
|
|
92530
92778
|
return this;
|
|
92531
92779
|
}
|
|
92532
92780
|
get names() {
|
|
@@ -92592,8 +92840,8 @@ var require_codegen = __commonJS((exports) => {
|
|
|
92592
92840
|
optimizeNodes() {
|
|
92593
92841
|
return `${this.code}` ? this : undefined;
|
|
92594
92842
|
}
|
|
92595
|
-
optimizeNames(names,
|
|
92596
|
-
this.code = optimizeExpr(this.code, names,
|
|
92843
|
+
optimizeNames(names, constants16) {
|
|
92844
|
+
this.code = optimizeExpr(this.code, names, constants16);
|
|
92597
92845
|
return this;
|
|
92598
92846
|
}
|
|
92599
92847
|
get names() {
|
|
@@ -92623,12 +92871,12 @@ var require_codegen = __commonJS((exports) => {
|
|
|
92623
92871
|
}
|
|
92624
92872
|
return nodes.length > 0 ? this : undefined;
|
|
92625
92873
|
}
|
|
92626
|
-
optimizeNames(names,
|
|
92874
|
+
optimizeNames(names, constants16) {
|
|
92627
92875
|
const { nodes } = this;
|
|
92628
92876
|
let i = nodes.length;
|
|
92629
92877
|
while (i--) {
|
|
92630
92878
|
const n2 = nodes[i];
|
|
92631
|
-
if (n2.optimizeNames(names,
|
|
92879
|
+
if (n2.optimizeNames(names, constants16))
|
|
92632
92880
|
continue;
|
|
92633
92881
|
subtractNames(names, n2.names);
|
|
92634
92882
|
nodes.splice(i, 1);
|
|
@@ -92685,12 +92933,12 @@ var require_codegen = __commonJS((exports) => {
|
|
|
92685
92933
|
return;
|
|
92686
92934
|
return this;
|
|
92687
92935
|
}
|
|
92688
|
-
optimizeNames(names,
|
|
92936
|
+
optimizeNames(names, constants16) {
|
|
92689
92937
|
var _a3;
|
|
92690
|
-
this.else = (_a3 = this.else) === null || _a3 === undefined ? undefined : _a3.optimizeNames(names,
|
|
92691
|
-
if (!(super.optimizeNames(names,
|
|
92938
|
+
this.else = (_a3 = this.else) === null || _a3 === undefined ? undefined : _a3.optimizeNames(names, constants16);
|
|
92939
|
+
if (!(super.optimizeNames(names, constants16) || this.else))
|
|
92692
92940
|
return;
|
|
92693
|
-
this.condition = optimizeExpr(this.condition, names,
|
|
92941
|
+
this.condition = optimizeExpr(this.condition, names, constants16);
|
|
92694
92942
|
return this;
|
|
92695
92943
|
}
|
|
92696
92944
|
get names() {
|
|
@@ -92715,10 +92963,10 @@ var require_codegen = __commonJS((exports) => {
|
|
|
92715
92963
|
render(opts) {
|
|
92716
92964
|
return `for(${this.iteration})` + super.render(opts);
|
|
92717
92965
|
}
|
|
92718
|
-
optimizeNames(names,
|
|
92719
|
-
if (!super.optimizeNames(names,
|
|
92966
|
+
optimizeNames(names, constants16) {
|
|
92967
|
+
if (!super.optimizeNames(names, constants16))
|
|
92720
92968
|
return;
|
|
92721
|
-
this.iteration = optimizeExpr(this.iteration, names,
|
|
92969
|
+
this.iteration = optimizeExpr(this.iteration, names, constants16);
|
|
92722
92970
|
return this;
|
|
92723
92971
|
}
|
|
92724
92972
|
get names() {
|
|
@@ -92756,10 +93004,10 @@ var require_codegen = __commonJS((exports) => {
|
|
|
92756
93004
|
render(opts) {
|
|
92757
93005
|
return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
|
|
92758
93006
|
}
|
|
92759
|
-
optimizeNames(names,
|
|
92760
|
-
if (!super.optimizeNames(names,
|
|
93007
|
+
optimizeNames(names, constants16) {
|
|
93008
|
+
if (!super.optimizeNames(names, constants16))
|
|
92761
93009
|
return;
|
|
92762
|
-
this.iterable = optimizeExpr(this.iterable, names,
|
|
93010
|
+
this.iterable = optimizeExpr(this.iterable, names, constants16);
|
|
92763
93011
|
return this;
|
|
92764
93012
|
}
|
|
92765
93013
|
get names() {
|
|
@@ -92804,11 +93052,11 @@ var require_codegen = __commonJS((exports) => {
|
|
|
92804
93052
|
(_b = this.finally) === null || _b === undefined || _b.optimizeNodes();
|
|
92805
93053
|
return this;
|
|
92806
93054
|
}
|
|
92807
|
-
optimizeNames(names,
|
|
93055
|
+
optimizeNames(names, constants16) {
|
|
92808
93056
|
var _a3, _b;
|
|
92809
|
-
super.optimizeNames(names,
|
|
92810
|
-
(_a3 = this.catch) === null || _a3 === undefined || _a3.optimizeNames(names,
|
|
92811
|
-
(_b = this.finally) === null || _b === undefined || _b.optimizeNames(names,
|
|
93057
|
+
super.optimizeNames(names, constants16);
|
|
93058
|
+
(_a3 = this.catch) === null || _a3 === undefined || _a3.optimizeNames(names, constants16);
|
|
93059
|
+
(_b = this.finally) === null || _b === undefined || _b.optimizeNames(names, constants16);
|
|
92812
93060
|
return this;
|
|
92813
93061
|
}
|
|
92814
93062
|
get names() {
|
|
@@ -93082,7 +93330,7 @@ var require_codegen = __commonJS((exports) => {
|
|
|
93082
93330
|
function addExprNames(names, from) {
|
|
93083
93331
|
return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
|
|
93084
93332
|
}
|
|
93085
|
-
function optimizeExpr(expr, names,
|
|
93333
|
+
function optimizeExpr(expr, names, constants16) {
|
|
93086
93334
|
if (expr instanceof code_1.Name)
|
|
93087
93335
|
return replaceName(expr);
|
|
93088
93336
|
if (!canOptimize(expr))
|
|
@@ -93097,14 +93345,14 @@ var require_codegen = __commonJS((exports) => {
|
|
|
93097
93345
|
return items;
|
|
93098
93346
|
}, []));
|
|
93099
93347
|
function replaceName(n2) {
|
|
93100
|
-
const c =
|
|
93348
|
+
const c = constants16[n2.str];
|
|
93101
93349
|
if (c === undefined || names[n2.str] !== 1)
|
|
93102
93350
|
return n2;
|
|
93103
93351
|
delete names[n2.str];
|
|
93104
93352
|
return c;
|
|
93105
93353
|
}
|
|
93106
93354
|
function canOptimize(e2) {
|
|
93107
|
-
return e2 instanceof code_1._Code && e2._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 &&
|
|
93355
|
+
return e2 instanceof code_1._Code && e2._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants16[c.str] !== undefined);
|
|
93108
93356
|
}
|
|
93109
93357
|
}
|
|
93110
93358
|
function subtractNames(names, from) {
|
|
@@ -100681,7 +100929,7 @@ var init_remote_invitation_recovery = __esm(() => {
|
|
|
100681
100929
|
});
|
|
100682
100930
|
|
|
100683
100931
|
// src/lib/remote-private-publications.ts
|
|
100684
|
-
import { createHash as
|
|
100932
|
+
import { createHash as createHash23 } from "crypto";
|
|
100685
100933
|
function checkedPublicationDeclaration(value) {
|
|
100686
100934
|
if (!exact(value, ["idempotencyKey", "version", "expectedCurrentVersionId", "manifestText", "archiveSha256", "archiveByteSize"]) || !publicationUuid(value.idempotencyKey) || !(value.expectedCurrentVersionId === null || publicationUuid(value.expectedCurrentVersionId)) || typeof value.version !== "string" || !value.version || value.version.length > 128 || /[\p{Cc}\p{Cs}]/u.test(value.version) || typeof value.manifestText !== "string" || Buffer.byteLength(value.manifestText) > 16384 || !hash3(value.archiveSha256) || !Number.isSafeInteger(value.archiveByteSize) || Number(value.archiveByteSize) < 1 || Number(value.archiveByteSize) > PRIVATE_PUBLICATION_MAX_BYTES)
|
|
100687
100935
|
return bad();
|
|
@@ -100942,7 +101190,7 @@ var PRIVATE_PUBLICATION_MAX_BYTES, failures2, PrivatePublicationError, bad = ()
|
|
|
100942
101190
|
throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Invalid publication input or recovery data.");
|
|
100943
101191
|
}, invalid5 = () => {
|
|
100944
101192
|
throw new PrivatePublicationError("INVALID_PUBLICATION_RESPONSE", "The server returned an invalid publication result.");
|
|
100945
|
-
}, publicationUuid = (v) => typeof v === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(v), hash3 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v), record10 = (v) => !!v && typeof v === "object" && !Array.isArray(v), exact = (v, keys3) => record10(v) && Object.keys(v).sort().join(",") === keys3.sort().join(","), date6 = (v) => typeof v === "string" && /^\d{4}-\d\d-\d\dT[0-9:.]+(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.test(v) && Number.isFinite(Date.parse(v)), publicationSha256 = (bytes) =>
|
|
101193
|
+
}, publicationUuid = (v) => typeof v === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(v), hash3 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v), record10 = (v) => !!v && typeof v === "object" && !Array.isArray(v), exact = (v, keys3) => record10(v) && Object.keys(v).sort().join(",") === keys3.sort().join(","), date6 = (v) => typeof v === "string" && /^\d{4}-\d\d-\d\dT[0-9:.]+(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.test(v) && Number.isFinite(Date.parse(v)), publicationSha256 = (bytes) => createHash23("sha256").update(bytes).digest("hex");
|
|
100946
101194
|
var init_remote_private_publications = __esm(() => {
|
|
100947
101195
|
init_fleet_credentials();
|
|
100948
101196
|
init_remote_workspace_selection();
|
|
@@ -101219,11 +101467,11 @@ var init_remote_auth = __esm(() => {
|
|
|
101219
101467
|
});
|
|
101220
101468
|
|
|
101221
101469
|
// src/lib/workspace-profile.ts
|
|
101222
|
-
import { constants as
|
|
101223
|
-
import { dirname as
|
|
101470
|
+
import { constants as constants16, closeSync as closeSync17, fstatSync as fstatSync17, lstatSync as lstatSync23, mkdirSync as mkdirSync16, mkdtempSync as mkdtempSync5, openSync as openSync17, readFileSync as readFileSync31, renameSync as renameSync9, rmSync as rmSync8, writeFileSync as writeFileSync16 } from "fs";
|
|
101471
|
+
import { dirname as dirname21, join as join44 } from "path";
|
|
101224
101472
|
function stat2(path) {
|
|
101225
101473
|
try {
|
|
101226
|
-
return
|
|
101474
|
+
return lstatSync23(path);
|
|
101227
101475
|
} catch (error61) {
|
|
101228
101476
|
if (error61.code === "ENOENT")
|
|
101229
101477
|
return null;
|
|
@@ -101233,14 +101481,14 @@ function stat2(path) {
|
|
|
101233
101481
|
function safeText(file2) {
|
|
101234
101482
|
if (stat2(file2) === null)
|
|
101235
101483
|
return null;
|
|
101236
|
-
const fd =
|
|
101484
|
+
const fd = openSync17(file2, constants16.O_RDONLY | constants16.O_NOFOLLOW | constants16.O_NONBLOCK);
|
|
101237
101485
|
try {
|
|
101238
|
-
const s =
|
|
101486
|
+
const s = fstatSync17(fd);
|
|
101239
101487
|
if (!s.isFile() || s.size > 65536 || ![256, 384].includes(s.mode & 4095) || process.getuid && s.uid !== process.getuid())
|
|
101240
|
-
return
|
|
101488
|
+
return fail3("The selected profile must use bounded owner-only regular files.");
|
|
101241
101489
|
return readFileSync31(fd, "utf8");
|
|
101242
101490
|
} finally {
|
|
101243
|
-
|
|
101491
|
+
closeSync17(fd);
|
|
101244
101492
|
}
|
|
101245
101493
|
}
|
|
101246
101494
|
function checkIdentityMetadata(file2, identity4) {
|
|
@@ -101251,37 +101499,37 @@ function checkIdentityMetadata(file2, identity4) {
|
|
|
101251
101499
|
try {
|
|
101252
101500
|
value = JSON.parse(text3);
|
|
101253
101501
|
} catch {
|
|
101254
|
-
return
|
|
101502
|
+
return fail3("The profile identity metadata is invalid. Sign in again before managing this workspace.");
|
|
101255
101503
|
}
|
|
101256
101504
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
101257
|
-
return
|
|
101505
|
+
return fail3("The profile identity metadata is invalid.");
|
|
101258
101506
|
for (const [key, expected] of Object.entries({ userId: identity4.user.id, orgId: identity4.organization.id })) {
|
|
101259
101507
|
if (value[key] !== undefined && value[key] !== expected)
|
|
101260
|
-
return
|
|
101508
|
+
return fail3("The profile identity metadata does not match its authenticated key. Sign in again before managing this workspace.");
|
|
101261
101509
|
}
|
|
101262
101510
|
}
|
|
101263
101511
|
async function keyIdentity(key, origin) {
|
|
101264
101512
|
const value = await new RemoteSkillsClient(key, origin).getIdentity();
|
|
101265
101513
|
if (value.authMethod !== "api_key")
|
|
101266
|
-
return
|
|
101514
|
+
return fail3("The selected credential is not a workspace API key.");
|
|
101267
101515
|
const user = value.user;
|
|
101268
101516
|
return parseWorkspaceIdentity(value, workspaceExpectedUserId(user?.id));
|
|
101269
101517
|
}
|
|
101270
101518
|
function prepareProfileWorkspace(action, source = process.env) {
|
|
101271
101519
|
const env3 = { ...source }, origin = getApiUrl(action, env3), profile = selectedSkillsProfile(env3);
|
|
101272
|
-
const
|
|
101520
|
+
const unchanged3 = captureSkillsCredentialFiles(skillsProfileCredentialFiles(env3));
|
|
101273
101521
|
return { origin, async resolve() {
|
|
101274
|
-
|
|
101522
|
+
unchanged3();
|
|
101275
101523
|
if (!profile)
|
|
101276
|
-
return { origin, context: undefined, unchanged:
|
|
101524
|
+
return { origin, context: undefined, unchanged: unchanged3 };
|
|
101277
101525
|
const connection = await resolveSkillsConnection(env3);
|
|
101278
101526
|
if (!connection || connection.apiOrigin !== origin)
|
|
101279
|
-
return
|
|
101527
|
+
return fail3("The selected profile has no usable credential for this server.");
|
|
101280
101528
|
const identity4 = await keyIdentity(connection.apiKey, origin);
|
|
101281
101529
|
checkIdentityMetadata(getIdentityFilePath(env3), identity4);
|
|
101282
|
-
|
|
101530
|
+
unchanged3();
|
|
101283
101531
|
const context = { userId: identity4.user.id, membershipId: identity4.user.membershipId };
|
|
101284
|
-
return { origin, context, unchanged:
|
|
101532
|
+
return { origin, context, unchanged: unchanged3 };
|
|
101285
101533
|
} };
|
|
101286
101534
|
}
|
|
101287
101535
|
async function captureProfileWorkspace(action, source = process.env) {
|
|
@@ -101291,9 +101539,9 @@ async function prepareWorkspaceEnrollment(membershipId, source = process.env) {
|
|
|
101291
101539
|
workspaceExpectedUserId(membershipId);
|
|
101292
101540
|
const env3 = { ...source }, profile = selectedSkillsProfile(env3);
|
|
101293
101541
|
if (!profile)
|
|
101294
|
-
return
|
|
101542
|
+
return fail3("Workspace login requires an explicit HASNA_PROFILE name.");
|
|
101295
101543
|
if (["HASNA_SKILLS_API_KEY_OVERRIDE", "HASNA_SKILLS_API_KEY_REF", "HASNA_SKILLS_API_KEY", "SKILLS_API_KEY"].some((name) => env3[name]?.trim()))
|
|
101296
|
-
return
|
|
101544
|
+
return fail3("Clear injected API keys before enrolling a named workspace profile.");
|
|
101297
101545
|
const origin = getApiUrl("Sign in to a workspace", env3);
|
|
101298
101546
|
const file2 = getAuthFilePath(env3), identityFile = getIdentityFilePath(env3);
|
|
101299
101547
|
const paths = [...new Set([...skillsProfileCredentialFiles(env3), file2, identityFile])];
|
|
@@ -101304,17 +101552,17 @@ async function prepareWorkspaceEnrollment(membershipId, source = process.env) {
|
|
|
101304
101552
|
const credentialBody = (key) => [...lines.filter(Boolean), `HASNA_SKILLS_API_KEY=${key}`, `HASNA_SKILLS_API_URL=${origin}`, `HASNA_SKILLS_BOUND_API_URL=${origin}`, ""].join(`
|
|
101305
101553
|
`);
|
|
101306
101554
|
if (Buffer.byteLength(credentialBody("x".repeat(8192)), "utf8") > 65536)
|
|
101307
|
-
return
|
|
101555
|
+
return fail3("The selected profile has insufficient space for a bounded credential. Reduce its unrelated configuration before signing in.");
|
|
101308
101556
|
const parents3 = [];
|
|
101309
|
-
for (let path =
|
|
101557
|
+
for (let path = dirname21(file2);; path = dirname21(path)) {
|
|
101310
101558
|
const before2 = stat2(path);
|
|
101311
101559
|
if (before2 && (!before2.isDirectory() || before2.isSymbolicLink()))
|
|
101312
|
-
return
|
|
101560
|
+
return fail3("The profile directory must not be a symbolic link.");
|
|
101313
101561
|
parents3.push([path, before2]);
|
|
101314
|
-
if (path ===
|
|
101562
|
+
if (path === dirname21(path))
|
|
101315
101563
|
break;
|
|
101316
101564
|
}
|
|
101317
|
-
const
|
|
101565
|
+
const unchanged3 = () => {
|
|
101318
101566
|
unchangedFiles();
|
|
101319
101567
|
for (const [path, before2] of parents3) {
|
|
101320
101568
|
const now3 = stat2(path);
|
|
@@ -101327,7 +101575,7 @@ async function prepareWorkspaceEnrollment(membershipId, source = process.env) {
|
|
|
101327
101575
|
const connection = await resolveSkillsConnection(env3);
|
|
101328
101576
|
if (connection) {
|
|
101329
101577
|
if (connection.apiKeyTier !== "profile" || connection.apiOrigin !== origin)
|
|
101330
|
-
return
|
|
101578
|
+
return fail3("Workspace login must resolve only the explicitly named profile.");
|
|
101331
101579
|
expected = await keyIdentity(connection.apiKey, origin);
|
|
101332
101580
|
checkIdentityMetadata(identityFile, expected);
|
|
101333
101581
|
}
|
|
@@ -101335,47 +101583,47 @@ async function prepareWorkspaceEnrollment(membershipId, source = process.env) {
|
|
|
101335
101583
|
if (!(error61 instanceof SkillsFleetCredentialError && error61.code === "MISSING_API_CREDENTIAL" && (old === null || !/^\s*(?:export\s+)?(?:HASNA_SKILLS_API_KEY|SKILLS_API_KEY)\s*=/m.test(old))))
|
|
101336
101584
|
throw error61;
|
|
101337
101585
|
}
|
|
101338
|
-
|
|
101586
|
+
unchanged3();
|
|
101339
101587
|
return {
|
|
101340
101588
|
profile,
|
|
101341
101589
|
origin,
|
|
101342
101590
|
async complete(email4, code) {
|
|
101343
|
-
|
|
101591
|
+
unchanged3();
|
|
101344
101592
|
if (!email4.includes("@") || !/^\d{6}$/.test(code))
|
|
101345
|
-
return
|
|
101593
|
+
return fail3("A fresh email and six-digit verification code are required.");
|
|
101346
101594
|
if (expected && expected.user.email.toLowerCase() !== email4.toLowerCase())
|
|
101347
|
-
return
|
|
101595
|
+
return fail3("This profile belongs to another account. Use a different profile or ordinary replacement login.");
|
|
101348
101596
|
let issued = false;
|
|
101349
101597
|
try {
|
|
101350
101598
|
const result2 = await new RemoteSkillsAuthClient(origin).verifyCode(email4, code);
|
|
101351
101599
|
const login = parseWorkspaceLogin(result2, expected?.user.id);
|
|
101352
101600
|
if (result2.firstLogin === true)
|
|
101353
|
-
return
|
|
101601
|
+
return fail3("This sign-in created a new account using the server signup policy. Finish ordinary account login before enrolling a workspace profile.");
|
|
101354
101602
|
const session = await new RemoteSkillsClient(login.token, origin).switchWorkspace({ userId: login.userId, membershipId });
|
|
101355
101603
|
if (session.user.email.toLowerCase() !== email4.toLowerCase())
|
|
101356
|
-
return
|
|
101604
|
+
return fail3("The verified account does not match the requested email.");
|
|
101357
101605
|
if (session.user.role === "viewer")
|
|
101358
|
-
return
|
|
101359
|
-
|
|
101606
|
+
return fail3("Viewer memberships cannot enroll API keys.");
|
|
101607
|
+
unchanged3();
|
|
101360
101608
|
issued = true;
|
|
101361
101609
|
const created = await new RemoteSkillsClient(session.token, origin).createApiKey("cli");
|
|
101362
101610
|
const verified = await keyIdentity(created.key, origin);
|
|
101363
101611
|
if (verified.user.id !== session.user.id || verified.user.membershipId !== membershipId || verified.organization.id !== session.organization.id)
|
|
101364
|
-
return
|
|
101365
|
-
|
|
101612
|
+
return fail3("The issued key does not match the selected workspace.");
|
|
101613
|
+
unchanged3();
|
|
101366
101614
|
if (!created.key.trim() || /[^\x21-\x7e]/.test(created.key) || created.key.length > 8192)
|
|
101367
|
-
return
|
|
101615
|
+
return fail3("The server returned an invalid API key.");
|
|
101368
101616
|
const body = credentialBody(created.key);
|
|
101369
101617
|
if (Buffer.byteLength(body, "utf8") > 65536)
|
|
101370
|
-
return
|
|
101618
|
+
return fail3("The new profile exceeds the credential reader size limit.");
|
|
101371
101619
|
const identity4 = JSON.stringify({ email: verified.user.email, userId: verified.user.id, orgId: verified.organization.id, orgSlug: verified.organization.slug, apiUrl: origin }, null, 2) + `
|
|
101372
101620
|
`;
|
|
101373
|
-
mkdirSync16(
|
|
101374
|
-
const temp = mkdtempSync5(join44(
|
|
101621
|
+
mkdirSync16(dirname21(file2), { recursive: true, mode: 448 });
|
|
101622
|
+
const temp = mkdtempSync5(join44(dirname21(file2), ".workspace-login-"));
|
|
101375
101623
|
let identityInstalled = false;
|
|
101376
101624
|
try {
|
|
101377
|
-
|
|
101378
|
-
|
|
101625
|
+
writeFileSync16(join44(temp, "credentials"), body, { mode: 384, flag: "wx" });
|
|
101626
|
+
writeFileSync16(join44(temp, "identity"), identity4, { mode: 384, flag: "wx" });
|
|
101379
101627
|
unchangedFiles();
|
|
101380
101628
|
for (const [path, before2] of parents3) {
|
|
101381
101629
|
const now3 = stat2(path);
|
|
@@ -101392,7 +101640,7 @@ async function prepareWorkspaceEnrollment(membershipId, source = process.env) {
|
|
|
101392
101640
|
if (oldIdentity === null)
|
|
101393
101641
|
rmSync8(identityFile, { force: true });
|
|
101394
101642
|
else {
|
|
101395
|
-
|
|
101643
|
+
writeFileSync16(join44(temp, "restore"), oldIdentity, { mode: 384, flag: "wx" });
|
|
101396
101644
|
renameSync9(join44(temp, "restore"), identityFile);
|
|
101397
101645
|
}
|
|
101398
101646
|
}
|
|
@@ -101414,17 +101662,17 @@ async function prepareWorkspaceEnrollment(membershipId, source = process.env) {
|
|
|
101414
101662
|
};
|
|
101415
101663
|
} catch (error61) {
|
|
101416
101664
|
if (issued)
|
|
101417
|
-
return
|
|
101665
|
+
return fail3("Workspace key issuance was attempted, but enrollment could not be confirmed. Inspect the selected profile and workspace keys before retrying; do not retry automatically.");
|
|
101418
101666
|
if (error61 instanceof WorkspaceProfileError)
|
|
101419
101667
|
throw error61;
|
|
101420
|
-
return
|
|
101668
|
+
return fail3("Unable to verify and select the workspace. Check the account, membership, selected server and fresh code. No enrollment key was requested.");
|
|
101421
101669
|
}
|
|
101422
101670
|
}
|
|
101423
101671
|
};
|
|
101424
101672
|
}
|
|
101425
|
-
var WorkspaceProfileError,
|
|
101673
|
+
var WorkspaceProfileError, fail3 = (message) => {
|
|
101426
101674
|
throw new WorkspaceProfileError(message);
|
|
101427
|
-
}, changed = () =>
|
|
101675
|
+
}, changed = () => fail3("The selected profile changed during sign-in. No credential was saved; retry with a stable profile.");
|
|
101428
101676
|
var init_workspace_profile = __esm(() => {
|
|
101429
101677
|
init_auth_store();
|
|
101430
101678
|
init_fleet_credentials();
|
|
@@ -101587,8 +101835,8 @@ var init_recurring_customer = __esm(() => {
|
|
|
101587
101835
|
});
|
|
101588
101836
|
|
|
101589
101837
|
// src/lib/recurring-recovery.ts
|
|
101590
|
-
import { constants as
|
|
101591
|
-
import { dirname as
|
|
101838
|
+
import { constants as constants17, closeSync as closeSync18, fsyncSync as fsyncSync5, fstatSync as fstatSync18, lstatSync as lstatSync24, mkdirSync as mkdirSync17, openSync as openSync18, readSync as readSync14, realpathSync as realpathSync8, renameSync as renameSync10, unlinkSync as unlinkSync6, writeFileSync as writeFileSync17 } from "fs";
|
|
101839
|
+
import { dirname as dirname22, isAbsolute as isAbsolute17, join as join45, resolve as resolve19 } from "path";
|
|
101592
101840
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
101593
101841
|
|
|
101594
101842
|
class RecoveryOwner {
|
|
@@ -101598,12 +101846,12 @@ class RecoveryOwner {
|
|
|
101598
101846
|
this.directory = directory;
|
|
101599
101847
|
if (!isAbsolute17(directory) || resolve19(directory) !== directory || realpathSync8(directory) !== directory)
|
|
101600
101848
|
invalid6();
|
|
101601
|
-
for (let path = directory;; path =
|
|
101602
|
-
const stat3 =
|
|
101849
|
+
for (let path = directory;; path = dirname22(path)) {
|
|
101850
|
+
const stat3 = lstatSync24(path);
|
|
101603
101851
|
if (!stat3.isDirectory() || stat3.isSymbolicLink())
|
|
101604
101852
|
invalid6();
|
|
101605
101853
|
this.parents.push({ path, dev: stat3.dev, ino: stat3.ino });
|
|
101606
|
-
if (path ===
|
|
101854
|
+
if (path === dirname22(path))
|
|
101607
101855
|
break;
|
|
101608
101856
|
}
|
|
101609
101857
|
this.assert();
|
|
@@ -101612,59 +101860,59 @@ class RecoveryOwner {
|
|
|
101612
101860
|
if (realpathSync8(this.directory) !== this.directory)
|
|
101613
101861
|
invalid6();
|
|
101614
101862
|
for (const prior of this.parents) {
|
|
101615
|
-
const now3 =
|
|
101863
|
+
const now3 = lstatSync24(prior.path);
|
|
101616
101864
|
if (!now3.isDirectory() || now3.isSymbolicLink() || now3.dev !== prior.dev || now3.ino !== prior.ino)
|
|
101617
101865
|
invalid6();
|
|
101618
101866
|
}
|
|
101619
|
-
const own2 =
|
|
101867
|
+
const own2 = lstatSync24(this.directory);
|
|
101620
101868
|
if ((own2.mode & 511) !== 448 || (own2.mode & 3584) !== 0 || process.getuid && own2.uid !== process.getuid())
|
|
101621
101869
|
invalid6();
|
|
101622
101870
|
}
|
|
101623
101871
|
read(name) {
|
|
101624
101872
|
this.assert();
|
|
101625
|
-
const fd =
|
|
101873
|
+
const fd = openSync18(join45(this.directory, name), constants17.O_RDONLY | constants17.O_NOFOLLOW | constants17.O_NONBLOCK);
|
|
101626
101874
|
try {
|
|
101627
|
-
const before2 =
|
|
101875
|
+
const before2 = fstatSync18(fd);
|
|
101628
101876
|
if (!before2.isFile() || before2.nlink !== 1 || (before2.mode & 4095) !== 384 || before2.size < 1 || before2.size > 8192 || process.getuid && before2.uid !== process.getuid())
|
|
101629
101877
|
invalid6();
|
|
101630
101878
|
const bytes = Buffer.alloc(before2.size + 1);
|
|
101631
101879
|
let size2 = 0;
|
|
101632
101880
|
while (size2 < bytes.length) {
|
|
101633
|
-
const n2 =
|
|
101881
|
+
const n2 = readSync14(fd, bytes, size2, bytes.length - size2, size2);
|
|
101634
101882
|
if (!n2)
|
|
101635
101883
|
break;
|
|
101636
101884
|
size2 += n2;
|
|
101637
101885
|
}
|
|
101638
|
-
const after2 =
|
|
101886
|
+
const after2 = fstatSync18(fd), path = lstatSync24(join45(this.directory, name));
|
|
101639
101887
|
if (size2 !== before2.size || after2.size !== before2.size || before2.mtimeMs !== after2.mtimeMs || before2.ctimeMs !== after2.ctimeMs || path.dev !== before2.dev || path.ino !== before2.ino || !path.isFile() || path.isSymbolicLink())
|
|
101640
101888
|
invalid6();
|
|
101641
101889
|
this.assert();
|
|
101642
101890
|
return new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, size2));
|
|
101643
101891
|
} finally {
|
|
101644
|
-
|
|
101892
|
+
closeSync18(fd);
|
|
101645
101893
|
}
|
|
101646
101894
|
}
|
|
101647
101895
|
write(name, value) {
|
|
101648
101896
|
this.assert();
|
|
101649
101897
|
const bytes = canonicalJson2(value, 8192) + `
|
|
101650
101898
|
`;
|
|
101651
|
-
const fd =
|
|
101899
|
+
const fd = openSync18(join45(this.directory, name), constants17.O_WRONLY | constants17.O_CREAT | constants17.O_EXCL | constants17.O_NOFOLLOW, 384);
|
|
101652
101900
|
try {
|
|
101653
|
-
|
|
101654
|
-
|
|
101901
|
+
writeFileSync17(fd, bytes);
|
|
101902
|
+
fsyncSync5(fd);
|
|
101655
101903
|
} finally {
|
|
101656
|
-
|
|
101904
|
+
closeSync18(fd);
|
|
101657
101905
|
}
|
|
101658
101906
|
this.assert();
|
|
101659
101907
|
this.sync();
|
|
101660
101908
|
}
|
|
101661
101909
|
sync() {
|
|
101662
101910
|
this.assert();
|
|
101663
|
-
const fd =
|
|
101911
|
+
const fd = openSync18(this.directory, constants17.O_RDONLY | constants17.O_NOFOLLOW);
|
|
101664
101912
|
try {
|
|
101665
|
-
|
|
101913
|
+
fsyncSync5(fd);
|
|
101666
101914
|
} finally {
|
|
101667
|
-
|
|
101915
|
+
closeSync18(fd);
|
|
101668
101916
|
}
|
|
101669
101917
|
}
|
|
101670
101918
|
saveState(state, expected) {
|
|
@@ -101682,20 +101930,20 @@ class RecoveryOwner {
|
|
|
101682
101930
|
this.assert();
|
|
101683
101931
|
let fd;
|
|
101684
101932
|
try {
|
|
101685
|
-
fd =
|
|
101933
|
+
fd = openSync18(join45(this.directory, "operation.lock"), constants17.O_WRONLY | constants17.O_CREAT | constants17.O_EXCL | constants17.O_NOFOLLOW, 384);
|
|
101686
101934
|
} catch {
|
|
101687
101935
|
throw new RecurringCustomerError("RECURRING_RECOVERY_BUSY", "Recovery is locked. Confirm the original process has stopped before explicitly reconciling the retained lock; no request was retried.");
|
|
101688
101936
|
}
|
|
101689
|
-
const owner2 =
|
|
101937
|
+
const owner2 = fstatSync18(fd);
|
|
101690
101938
|
try {
|
|
101691
|
-
|
|
101692
|
-
|
|
101939
|
+
writeFileSync17(fd, JSON.stringify({ pid: process.pid }));
|
|
101940
|
+
fsyncSync5(fd);
|
|
101693
101941
|
this.sync();
|
|
101694
101942
|
return await action();
|
|
101695
101943
|
} finally {
|
|
101696
|
-
|
|
101944
|
+
closeSync18(fd);
|
|
101697
101945
|
this.assert();
|
|
101698
|
-
const now3 =
|
|
101946
|
+
const now3 = lstatSync24(join45(this.directory, "operation.lock"));
|
|
101699
101947
|
if (owner2.dev !== now3.dev || owner2.ino !== now3.ino || !now3.isFile() || now3.isSymbolicLink())
|
|
101700
101948
|
invalid6();
|
|
101701
101949
|
unlinkSync6(join45(this.directory, "operation.lock"));
|
|
@@ -101731,7 +101979,7 @@ function base2(customer, organizationId) {
|
|
|
101731
101979
|
};
|
|
101732
101980
|
}
|
|
101733
101981
|
function create3(directory, intent) {
|
|
101734
|
-
if (!isAbsolute17(directory) || resolve19(directory) !== directory || realpathSync8(
|
|
101982
|
+
if (!isAbsolute17(directory) || resolve19(directory) !== directory || realpathSync8(dirname22(directory)) !== dirname22(directory))
|
|
101735
101983
|
invalid6();
|
|
101736
101984
|
mkdirSync17(directory, { mode: 448 });
|
|
101737
101985
|
const owner2 = new RecoveryOwner(directory), checked = intentSchema.parse(intent), intentSha256 = canonicalJsonSha256(checked);
|
|
@@ -101790,7 +102038,7 @@ async function continueRecurringRecovery(customer, directory, options) {
|
|
|
101790
102038
|
pending = state.phase === "pending";
|
|
101791
102039
|
bindRecurringRecovery(customer, intent);
|
|
101792
102040
|
await customer.assertCurrent();
|
|
101793
|
-
const
|
|
102041
|
+
const save2 = (next) => {
|
|
101794
102042
|
owner2.saveState(next, stateText);
|
|
101795
102043
|
state = next;
|
|
101796
102044
|
stateText = owner2.read("state.json");
|
|
@@ -101814,7 +102062,7 @@ async function continueRecurringRecovery(customer, directory, options) {
|
|
|
101814
102062
|
} else {
|
|
101815
102063
|
const consent2 = consentMatches(await customer.call("get", { consentId: intent.consentId }), intent);
|
|
101816
102064
|
if (consent2.revokedAt !== null) {
|
|
101817
|
-
|
|
102065
|
+
save2({ ...state, phase: "observed", consentId: consent2.consentId });
|
|
101818
102066
|
return result2(consent2);
|
|
101819
102067
|
}
|
|
101820
102068
|
if (!captured.confirm)
|
|
@@ -101832,20 +102080,20 @@ async function continueRecurringRecovery(customer, directory, options) {
|
|
|
101832
102080
|
owner2.assert();
|
|
101833
102081
|
await active.assertCurrent();
|
|
101834
102082
|
const previousUnknown = pending;
|
|
101835
|
-
|
|
102083
|
+
save2({ ...state, phase: "pending", consentId: null });
|
|
101836
102084
|
pending = true;
|
|
101837
102085
|
let response;
|
|
101838
102086
|
try {
|
|
101839
102087
|
response = intent.operation === "activate" ? await active.call("activate", { draftId: intent.draftId, approval: intent.approval }) : await active.call("revoke", { consentId: intent.consentId });
|
|
101840
102088
|
} catch (error61) {
|
|
101841
102089
|
if (!previousUnknown && (error61 instanceof RemoteRecurringError || error61 instanceof RemoteRecurringReadError || error61 instanceof RemoteRecurringUnavailableError || error61 instanceof RecurringInputError)) {
|
|
101842
|
-
|
|
102090
|
+
save2({ ...state, phase: "prepared", consentId: null });
|
|
101843
102091
|
pending = false;
|
|
101844
102092
|
}
|
|
101845
102093
|
throw error61;
|
|
101846
102094
|
}
|
|
101847
102095
|
const consentId = "consent" in response ? response.consent.consentId : response.consentId;
|
|
101848
|
-
|
|
102096
|
+
save2({ ...state, phase: "observed", consentId });
|
|
101849
102097
|
return result2(response);
|
|
101850
102098
|
});
|
|
101851
102099
|
pending = false;
|
|
@@ -101856,7 +102104,7 @@ async function continueRecurringRecovery(customer, directory, options) {
|
|
|
101856
102104
|
throw error61;
|
|
101857
102105
|
}
|
|
101858
102106
|
}
|
|
101859
|
-
var uuid12,
|
|
102107
|
+
var uuid12, sha3, common2, intentSchema, stateSchema, invalid6 = () => {
|
|
101860
102108
|
throw new RecurringCustomerError("RECURRING_RECOVERY_INVALID", "The original recovery directory or record is invalid or changed. Preserve it; do not create a replacement activation automatically.");
|
|
101861
102109
|
};
|
|
101862
102110
|
var init_recurring_recovery = __esm(() => {
|
|
@@ -101866,7 +102114,7 @@ var init_recurring_recovery = __esm(() => {
|
|
|
101866
102114
|
init_remote_recurring();
|
|
101867
102115
|
init_recurring_customer();
|
|
101868
102116
|
uuid12 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
|
|
101869
|
-
|
|
102117
|
+
sha3 = exports_external.string().regex(/^[a-f0-9]{64}$/);
|
|
101870
102118
|
common2 = exports_external.object({
|
|
101871
102119
|
contractVersion: exports_external.literal(1),
|
|
101872
102120
|
apiOrigin: exports_external.string().min(1).max(4096),
|
|
@@ -101879,7 +102127,7 @@ var init_recurring_recovery = __esm(() => {
|
|
|
101879
102127
|
common2.extend({
|
|
101880
102128
|
operation: exports_external.literal("activate"),
|
|
101881
102129
|
draftId: uuid12,
|
|
101882
|
-
termsSha256:
|
|
102130
|
+
termsSha256: sha3,
|
|
101883
102131
|
approvalDeadline: exports_external.string().datetime(),
|
|
101884
102132
|
approval: recurringActivationSchema
|
|
101885
102133
|
}).strict(),
|
|
@@ -101887,7 +102135,7 @@ var init_recurring_recovery = __esm(() => {
|
|
|
101887
102135
|
]);
|
|
101888
102136
|
stateSchema = exports_external.object({
|
|
101889
102137
|
contractVersion: exports_external.literal(1),
|
|
101890
|
-
intentSha256:
|
|
102138
|
+
intentSha256: sha3,
|
|
101891
102139
|
phase: exports_external.enum(["prepared", "pending", "observed"]),
|
|
101892
102140
|
consentId: uuid12.nullable()
|
|
101893
102141
|
}).strict();
|
|
@@ -103917,14 +104165,14 @@ var init_operation_tools = __esm(() => {
|
|
|
103917
104165
|
|
|
103918
104166
|
// src/lib/feedback.ts
|
|
103919
104167
|
import { appendFileSync as appendFileSync2, existsSync as existsSync29, mkdirSync as mkdirSync18 } from "fs";
|
|
103920
|
-
import { dirname as
|
|
104168
|
+
import { dirname as dirname23, join as join47 } from "path";
|
|
103921
104169
|
import { Database } from "bun:sqlite";
|
|
103922
104170
|
function getFeedbackDbPath() {
|
|
103923
104171
|
return join47(getDataDir(), "skills.db");
|
|
103924
104172
|
}
|
|
103925
104173
|
function getFeedbackDb() {
|
|
103926
104174
|
const dbPath = getFeedbackDbPath();
|
|
103927
|
-
const dir =
|
|
104175
|
+
const dir = dirname23(dbPath);
|
|
103928
104176
|
if (!existsSync29(dir))
|
|
103929
104177
|
mkdirSync18(dir, { recursive: true });
|
|
103930
104178
|
const db = new Database(dbPath);
|
|
@@ -103953,7 +104201,7 @@ function saveFeedback(input2) {
|
|
|
103953
104201
|
const category = input2.category ?? "general";
|
|
103954
104202
|
if (isApiMode()) {
|
|
103955
104203
|
const path = join47(getDataDir(), "feedback.jsonl");
|
|
103956
|
-
const dir =
|
|
104204
|
+
const dir = dirname23(path);
|
|
103957
104205
|
if (!existsSync29(dir))
|
|
103958
104206
|
mkdirSync18(dir, { recursive: true });
|
|
103959
104207
|
appendFileSync2(path, JSON.stringify({ message, category, email: input2.email ?? null, agent: input2.agent ?? null, version: input2.version ?? null, createdAt: new Date().toISOString() }) + `
|
|
@@ -104116,7 +104364,7 @@ var init_resource_meta_tools = __esm(() => {
|
|
|
104116
104364
|
});
|
|
104117
104365
|
|
|
104118
104366
|
// src/lib/scheduler.ts
|
|
104119
|
-
import { existsSync as existsSync30, readFileSync as readFileSync32, writeFileSync as
|
|
104367
|
+
import { existsSync as existsSync30, readFileSync as readFileSync32, writeFileSync as writeFileSync18, mkdirSync as mkdirSync19 } from "fs";
|
|
104120
104368
|
import { join as join48 } from "path";
|
|
104121
104369
|
function getSchedulesPath(targetDir = process.cwd()) {
|
|
104122
104370
|
return join48(targetDir, ".skills", "schedules.json");
|
|
@@ -104135,7 +104383,7 @@ function saveSchedules(data, targetDir = process.cwd()) {
|
|
|
104135
104383
|
const dir = join48(targetDir, ".skills");
|
|
104136
104384
|
if (!existsSync30(dir))
|
|
104137
104385
|
mkdirSync19(dir, { recursive: true });
|
|
104138
|
-
|
|
104386
|
+
writeFileSync18(path, JSON.stringify(data, null, 2));
|
|
104139
104387
|
}
|
|
104140
104388
|
function validateCronField(expr, min2, max2, label) {
|
|
104141
104389
|
for (const part of expr.split(",")) {
|
|
@@ -104175,11 +104423,11 @@ function validateCronField(expr, min2, max2, label) {
|
|
|
104175
104423
|
return { valid: true };
|
|
104176
104424
|
}
|
|
104177
104425
|
function validateCron(expr) {
|
|
104178
|
-
const
|
|
104179
|
-
if (
|
|
104180
|
-
return { valid: false, error: `Expected 5 fields, got ${
|
|
104426
|
+
const fields2 = expr.trim().split(/\s+/);
|
|
104427
|
+
if (fields2.length !== 5) {
|
|
104428
|
+
return { valid: false, error: `Expected 5 fields, got ${fields2.length}. Format: "minute hour day-of-month month day-of-week"` };
|
|
104181
104429
|
}
|
|
104182
|
-
const [minuteF, hourF, domF, monthF, dowF] =
|
|
104430
|
+
const [minuteF, hourF, domF, monthF, dowF] = fields2;
|
|
104183
104431
|
const checks4 = [
|
|
104184
104432
|
{ expr: minuteF, min: 0, max: 59, label: "minute" },
|
|
104185
104433
|
{ expr: hourF, min: 0, max: 23, label: "hour" },
|
|
@@ -104431,16 +104679,16 @@ var init_schedule_tools = __esm(() => {
|
|
|
104431
104679
|
});
|
|
104432
104680
|
|
|
104433
104681
|
// src/lib/native-storage.ts
|
|
104434
|
-
import { createHash as
|
|
104682
|
+
import { createHash as createHash24, createHmac as createHmac3 } from "crypto";
|
|
104435
104683
|
import {
|
|
104436
104684
|
existsSync as existsSync31,
|
|
104437
104685
|
mkdirSync as mkdirSync20,
|
|
104438
104686
|
readFileSync as readFileSync33,
|
|
104439
104687
|
readdirSync as readdirSync18,
|
|
104440
104688
|
statSync as statSync17,
|
|
104441
|
-
writeFileSync as
|
|
104689
|
+
writeFileSync as writeFileSync19
|
|
104442
104690
|
} from "fs";
|
|
104443
|
-
import { dirname as
|
|
104691
|
+
import { dirname as dirname24, join as join49, normalize as normalize3, relative as relative7, sep as sep7 } from "path";
|
|
104444
104692
|
function resolveSkillsNativeStorageConfig(env3 = process.env) {
|
|
104445
104693
|
assertNoRetiredModeEnvVars(env3, {
|
|
104446
104694
|
app: SKILLS_ENV_NAMESPACE,
|
|
@@ -104508,7 +104756,7 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
|
|
|
104508
104756
|
files.push({
|
|
104509
104757
|
path: relativePath,
|
|
104510
104758
|
sizeBytes: bytes.byteLength,
|
|
104511
|
-
sha256:
|
|
104759
|
+
sha256: createHash24("sha256").update(bytes).digest("hex"),
|
|
104512
104760
|
...options.includeFileContents ? { contentBase64: Buffer.from(bytes).toString("base64") } : {}
|
|
104513
104761
|
});
|
|
104514
104762
|
}
|
|
@@ -104519,9 +104767,9 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
|
|
|
104519
104767
|
files: files.sort((a, b) => a.path.localeCompare(b.path))
|
|
104520
104768
|
};
|
|
104521
104769
|
}
|
|
104522
|
-
function planSkillsS3SnapshotUpload(
|
|
104770
|
+
function planSkillsS3SnapshotUpload(snapshot2, options = {}) {
|
|
104523
104771
|
const prefix = normalizeS3Prefix(options.prefix);
|
|
104524
|
-
return
|
|
104772
|
+
return snapshot2.files.map((file2) => ({
|
|
104525
104773
|
path: file2.path,
|
|
104526
104774
|
key: [prefix, file2.path.replace(/^\.?\//, "")].filter(Boolean).join("/"),
|
|
104527
104775
|
sizeBytes: file2.sizeBytes,
|
|
@@ -104662,14 +104910,14 @@ function registerStorageTools(server) {
|
|
|
104662
104910
|
}, async ({ directory: directory2, includeSchemaSql }) => {
|
|
104663
104911
|
const targetDir = directory2 || process.cwd();
|
|
104664
104912
|
const config2 = resolveStorageConfig();
|
|
104665
|
-
const
|
|
104666
|
-
const s3Plan = config2.s3Bucket ? planSkillsS3SnapshotUpload(
|
|
104913
|
+
const snapshot2 = exportSkillsLocalSnapshot(targetDir, { includeFileContents: false });
|
|
104914
|
+
const s3Plan = config2.s3Bucket ? planSkillsS3SnapshotUpload(snapshot2, { prefix: config2.s3Prefix }) : [];
|
|
104667
104915
|
return mcpJson({
|
|
104668
104916
|
package: "skills",
|
|
104669
104917
|
noNetwork: true,
|
|
104670
104918
|
databaseConfigured: Boolean(config2.databaseUrl),
|
|
104671
104919
|
s3Configured: Boolean(config2.s3Bucket),
|
|
104672
|
-
snapshotFileCount:
|
|
104920
|
+
snapshotFileCount: snapshot2.files.length,
|
|
104673
104921
|
s3ObjectCount: s3Plan.length,
|
|
104674
104922
|
env: {
|
|
104675
104923
|
databaseUrl: SKILLS_NATIVE_STORAGE_ENV.databaseUrl,
|
|
@@ -104800,73 +105048,73 @@ var init_private_publication_customer = __esm(() => {
|
|
|
104800
105048
|
});
|
|
104801
105049
|
|
|
104802
105050
|
// src/lib/private-publication-recovery.ts
|
|
104803
|
-
import { constants as
|
|
104804
|
-
import { dirname as
|
|
105051
|
+
import { constants as constants18, closeSync as closeSync19, fsyncSync as fsyncSync6, fstatSync as fstatSync19, lstatSync as lstatSync25, mkdirSync as mkdirSync21, openSync as openSync19, readSync as readSync15, realpathSync as realpathSync9, renameSync as renameSync11, unlinkSync as unlinkSync7, writeFileSync as writeFileSync20 } from "fs";
|
|
105052
|
+
import { dirname as dirname25, isAbsolute as isAbsolute19, join as join50, resolve as resolve20 } from "path";
|
|
104805
105053
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
104806
105054
|
function safeDirectory(directory2) {
|
|
104807
105055
|
if (!isAbsolute19(directory2) || directory2 !== resolve20(directory2) || realpathSync9(directory2) !== directory2)
|
|
104808
|
-
return
|
|
104809
|
-
for (let path = directory2;; path =
|
|
104810
|
-
const stat3 =
|
|
105056
|
+
return fail4();
|
|
105057
|
+
for (let path = directory2;; path = dirname25(path)) {
|
|
105058
|
+
const stat3 = lstatSync25(path);
|
|
104811
105059
|
if (!stat3.isDirectory() || stat3.isSymbolicLink())
|
|
104812
|
-
return
|
|
104813
|
-
if (path ===
|
|
105060
|
+
return fail4();
|
|
105061
|
+
if (path === dirname25(path))
|
|
104814
105062
|
break;
|
|
104815
105063
|
}
|
|
104816
|
-
const own2 =
|
|
105064
|
+
const own2 = lstatSync25(directory2);
|
|
104817
105065
|
if ((own2.mode & 63) !== 0 || process.getuid && own2.uid !== process.getuid())
|
|
104818
|
-
return
|
|
105066
|
+
return fail4();
|
|
104819
105067
|
return { dev: own2.dev, ino: own2.ino };
|
|
104820
105068
|
}
|
|
104821
105069
|
function unchangedDirectory(directory2, identity4) {
|
|
104822
105070
|
const now3 = safeDirectory(directory2);
|
|
104823
105071
|
if (now3.dev !== identity4.dev || now3.ino !== identity4.ino)
|
|
104824
|
-
return
|
|
105072
|
+
return fail4();
|
|
104825
105073
|
}
|
|
104826
105074
|
function readOwned(directory2, name, max2) {
|
|
104827
105075
|
const identity4 = safeDirectory(directory2), file2 = join50(directory2, name);
|
|
104828
|
-
const fd =
|
|
105076
|
+
const fd = openSync19(file2, constants18.O_RDONLY | constants18.O_NOFOLLOW);
|
|
104829
105077
|
try {
|
|
104830
|
-
const stat3 =
|
|
105078
|
+
const stat3 = fstatSync19(fd);
|
|
104831
105079
|
if (!stat3.isFile() || stat3.nlink !== 1 || stat3.size > max2 || stat3.size < 1 || (stat3.mode & 63) !== 0 || process.getuid && stat3.uid !== process.getuid())
|
|
104832
|
-
return
|
|
105080
|
+
return fail4();
|
|
104833
105081
|
const buffer = Buffer.alloc(Math.min(max2, stat3.size) + 1);
|
|
104834
105082
|
let length = 0;
|
|
104835
105083
|
while (length < buffer.length) {
|
|
104836
|
-
const count =
|
|
105084
|
+
const count = readSync15(fd, buffer, length, buffer.length - length, length);
|
|
104837
105085
|
if (count === 0)
|
|
104838
105086
|
break;
|
|
104839
105087
|
length += count;
|
|
104840
105088
|
}
|
|
104841
|
-
const bytes = buffer.subarray(0, length), after2 =
|
|
105089
|
+
const bytes = buffer.subarray(0, length), after2 = fstatSync19(fd);
|
|
104842
105090
|
unchangedDirectory(directory2, identity4);
|
|
104843
105091
|
if (bytes.length !== stat3.size || stat3.size !== after2.size || stat3.mtimeMs !== after2.mtimeMs || stat3.ctimeMs !== after2.ctimeMs)
|
|
104844
|
-
return
|
|
105092
|
+
return fail4();
|
|
104845
105093
|
return bytes;
|
|
104846
105094
|
} finally {
|
|
104847
|
-
|
|
105095
|
+
closeSync19(fd);
|
|
104848
105096
|
}
|
|
104849
105097
|
}
|
|
104850
105098
|
function writeOwned(directory2, name, bytes) {
|
|
104851
|
-
const fd =
|
|
105099
|
+
const fd = openSync19(join50(directory2, name), constants18.O_WRONLY | constants18.O_CREAT | constants18.O_EXCL | constants18.O_NOFOLLOW, 384);
|
|
104852
105100
|
try {
|
|
104853
|
-
|
|
104854
|
-
|
|
105101
|
+
writeFileSync20(fd, bytes);
|
|
105102
|
+
fsyncSync6(fd);
|
|
104855
105103
|
} finally {
|
|
104856
|
-
|
|
105104
|
+
closeSync19(fd);
|
|
104857
105105
|
}
|
|
104858
105106
|
}
|
|
104859
|
-
function
|
|
105107
|
+
function save2(directory2, value) {
|
|
104860
105108
|
const identity4 = safeDirectory(directory2), temporary = `.receipt-${randomUUID8()}.json`;
|
|
104861
105109
|
writeOwned(directory2, temporary, JSON.stringify(value) + `
|
|
104862
105110
|
`);
|
|
104863
105111
|
unchangedDirectory(directory2, identity4);
|
|
104864
105112
|
renameSync11(join50(directory2, temporary), join50(directory2, "receipt.json"));
|
|
104865
|
-
const fd =
|
|
105113
|
+
const fd = openSync19(directory2, constants18.O_RDONLY | constants18.O_NOFOLLOW);
|
|
104866
105114
|
try {
|
|
104867
|
-
|
|
105115
|
+
fsyncSync6(fd);
|
|
104868
105116
|
} finally {
|
|
104869
|
-
|
|
105117
|
+
closeSync19(fd);
|
|
104870
105118
|
}
|
|
104871
105119
|
}
|
|
104872
105120
|
function bind2(client2, receipt) {
|
|
@@ -104877,22 +105125,22 @@ async function locked(directory2, action) {
|
|
|
104877
105125
|
const identity4 = safeDirectory(directory2), file2 = join50(directory2, "operation.lock");
|
|
104878
105126
|
let fd;
|
|
104879
105127
|
try {
|
|
104880
|
-
fd =
|
|
105128
|
+
fd = openSync19(file2, constants18.O_WRONLY | constants18.O_CREAT | constants18.O_EXCL | constants18.O_NOFOLLOW, 384);
|
|
104881
105129
|
} catch {
|
|
104882
105130
|
throw new PrivatePublicationError("PUBLICATION_RECOVERY_BUSY", "Another operation holds this recovery directory. If it crashed, confirm that process has stopped before explicitly removing operation.lock and resuming.");
|
|
104883
105131
|
}
|
|
104884
|
-
const lock =
|
|
105132
|
+
const lock = fstatSync19(fd);
|
|
104885
105133
|
try {
|
|
104886
|
-
|
|
105134
|
+
writeFileSync20(fd, JSON.stringify({ pid: process.pid }) + `
|
|
104887
105135
|
`);
|
|
104888
|
-
|
|
105136
|
+
fsyncSync6(fd);
|
|
104889
105137
|
return await action();
|
|
104890
105138
|
} finally {
|
|
104891
|
-
|
|
105139
|
+
closeSync19(fd);
|
|
104892
105140
|
unchangedDirectory(directory2, identity4);
|
|
104893
|
-
const now3 =
|
|
105141
|
+
const now3 = lstatSync25(file2);
|
|
104894
105142
|
if (now3.dev !== lock.dev || now3.ino !== lock.ino || !now3.isFile() || now3.isSymbolicLink())
|
|
104895
|
-
|
|
105143
|
+
fail4();
|
|
104896
105144
|
unlinkSync7(file2);
|
|
104897
105145
|
}
|
|
104898
105146
|
}
|
|
@@ -104900,23 +105148,23 @@ function readPrivatePublicationRecovery(directory2) {
|
|
|
104900
105148
|
try {
|
|
104901
105149
|
const value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(readOwned(directory2, "receipt.json", 65536)));
|
|
104902
105150
|
if (!value || typeof value !== "object" || Array.isArray(value) || Object.keys(value).sort().join(",") !== ["contractVersion", "apiOrigin", "organizationId", "userId", "membershipId", "skillId", "declaration", "phase", "intent"].sort().join(",") || value.contractVersion !== 1 || ![value.organizationId, value.userId, value.membershipId, value.skillId].every(publicationUuid) || typeof value.apiOrigin !== "string" || normalizeSkillsApiOrigin(value.apiOrigin) !== value.apiOrigin || !["prepared", "begin_uncertain", "awaiting_upload", "upload_uncertain", "uploaded", "finalize_uncertain", "observed"].includes(value.phase))
|
|
104903
|
-
return
|
|
105151
|
+
return fail4();
|
|
104904
105152
|
value.declaration = checkedPublicationDeclaration(value.declaration);
|
|
104905
105153
|
if (value.intent !== null)
|
|
104906
105154
|
value.intent = checkedPublicationView(value.intent, value.skillId, undefined, value.declaration);
|
|
104907
105155
|
if (value.intent === null && !["prepared", "begin_uncertain"].includes(value.phase))
|
|
104908
|
-
return
|
|
105156
|
+
return fail4();
|
|
104909
105157
|
const bytes = readOwned(directory2, "bundle.tgz", PRIVATE_PUBLICATION_MAX_BYTES);
|
|
104910
105158
|
if (bytes.length !== value.declaration.archiveByteSize || publicationSha256(bytes) !== value.declaration.archiveSha256)
|
|
104911
|
-
return
|
|
105159
|
+
return fail4();
|
|
104912
105160
|
return { receipt: value, bytes };
|
|
104913
105161
|
} catch {
|
|
104914
|
-
return
|
|
105162
|
+
return fail4();
|
|
104915
105163
|
}
|
|
104916
105164
|
}
|
|
104917
105165
|
async function preparePrivatePublication(client2, sourceDirectory, recoveryDirectory, input2) {
|
|
104918
105166
|
if (!publicationUuid(input2.skillId) || !(input2.expectedCurrentVersionId === null || publicationUuid(input2.expectedCurrentVersionId)) || input2.idempotencyKey !== undefined && !publicationUuid(input2.idempotencyKey))
|
|
104919
|
-
return
|
|
105167
|
+
return fail4();
|
|
104920
105168
|
const packed = packSkillBundle(sourceDirectory, { maxUnpackedBytes: 32 * 1024 * 1024 });
|
|
104921
105169
|
const inspected = await inspectSkillBundle(packed.bytes, { limits: { compressedBytes: PRIVATE_PUBLICATION_MAX_BYTES } });
|
|
104922
105170
|
const manifest = inspected.entries.find((entry) => entry.path === "skill.json");
|
|
@@ -104942,18 +105190,18 @@ async function preparePrivatePublication(client2, sourceDirectory, recoveryDirec
|
|
|
104942
105190
|
phase: "prepared",
|
|
104943
105191
|
intent: null
|
|
104944
105192
|
};
|
|
104945
|
-
if (!isAbsolute19(recoveryDirectory) || resolve20(recoveryDirectory) !== recoveryDirectory || realpathSync9(
|
|
104946
|
-
return
|
|
105193
|
+
if (!isAbsolute19(recoveryDirectory) || resolve20(recoveryDirectory) !== recoveryDirectory || realpathSync9(dirname25(recoveryDirectory)) !== dirname25(recoveryDirectory))
|
|
105194
|
+
return fail4();
|
|
104947
105195
|
mkdirSync21(recoveryDirectory, { mode: 448 });
|
|
104948
105196
|
safeDirectory(recoveryDirectory);
|
|
104949
|
-
const parent =
|
|
105197
|
+
const parent = openSync19(dirname25(recoveryDirectory), constants18.O_RDONLY | constants18.O_NOFOLLOW);
|
|
104950
105198
|
try {
|
|
104951
|
-
|
|
105199
|
+
fsyncSync6(parent);
|
|
104952
105200
|
} finally {
|
|
104953
|
-
|
|
105201
|
+
closeSync19(parent);
|
|
104954
105202
|
}
|
|
104955
105203
|
writeOwned(recoveryDirectory, "bundle.tgz", packed.bytes);
|
|
104956
|
-
|
|
105204
|
+
save2(recoveryDirectory, receipt);
|
|
104957
105205
|
return receipt;
|
|
104958
105206
|
}
|
|
104959
105207
|
function privatePublicationResult(directory2, receipt) {
|
|
@@ -104974,7 +105222,7 @@ async function continuePrivatePublication(client2, directory2, options) {
|
|
|
104974
105222
|
if (options.confirm !== true)
|
|
104975
105223
|
throw new PrivatePublicationError("PUBLICATION_CONFIRM_REQUIRED", "Explicit upload confirmation is required.");
|
|
104976
105224
|
if (options.waitMs !== undefined && (!Number.isSafeInteger(options.waitMs) || options.waitMs < 0 || options.waitMs > 300000))
|
|
104977
|
-
return
|
|
105225
|
+
return fail4();
|
|
104978
105226
|
return locked(directory2, () => continueLocked(client2, directory2, options));
|
|
104979
105227
|
}
|
|
104980
105228
|
async function continueLocked(client2, directory2, options) {
|
|
@@ -104982,40 +105230,40 @@ async function continueLocked(client2, directory2, options) {
|
|
|
104982
105230
|
bind2(client2, receipt);
|
|
104983
105231
|
if (!receipt.intent) {
|
|
104984
105232
|
receipt.phase = "begin_uncertain";
|
|
104985
|
-
|
|
105233
|
+
save2(directory2, receipt);
|
|
104986
105234
|
receipt.intent = await client2.begin(receipt.skillId, receipt.declaration);
|
|
104987
105235
|
receipt.phase = "awaiting_upload";
|
|
104988
|
-
|
|
105236
|
+
save2(directory2, receipt);
|
|
104989
105237
|
} else {
|
|
104990
105238
|
receipt.intent = checkedPublicationView(await client2.get(receipt.skillId, receipt.intent.id), receipt.skillId, receipt.intent.id, receipt.declaration);
|
|
104991
|
-
|
|
105239
|
+
save2(directory2, receipt);
|
|
104992
105240
|
}
|
|
104993
105241
|
if (receipt.intent.state === "awaiting_upload") {
|
|
104994
105242
|
if (receipt.phase === "awaiting_upload") {
|
|
104995
105243
|
receipt.phase = "upload_uncertain";
|
|
104996
|
-
|
|
105244
|
+
save2(directory2, receipt);
|
|
104997
105245
|
try {
|
|
104998
105246
|
await client2.upload(receipt.skillId, receipt.intent, bytes);
|
|
104999
105247
|
} catch (error61) {
|
|
105000
105248
|
if (error61 instanceof PrivatePublicationError && !error61.uncertain) {
|
|
105001
105249
|
receipt.phase = "awaiting_upload";
|
|
105002
|
-
|
|
105250
|
+
save2(directory2, receipt);
|
|
105003
105251
|
}
|
|
105004
105252
|
throw error61;
|
|
105005
105253
|
}
|
|
105006
105254
|
receipt.phase = "uploaded";
|
|
105007
|
-
|
|
105255
|
+
save2(directory2, receipt);
|
|
105008
105256
|
}
|
|
105009
105257
|
receipt.phase = "finalize_uncertain";
|
|
105010
|
-
|
|
105258
|
+
save2(directory2, receipt);
|
|
105011
105259
|
receipt.intent = checkedPublicationView(await client2.finalize(receipt.skillId, receipt.intent.id), receipt.skillId, receipt.intent.id, receipt.declaration);
|
|
105012
105260
|
receipt.phase = "observed";
|
|
105013
|
-
|
|
105261
|
+
save2(directory2, receipt);
|
|
105014
105262
|
}
|
|
105015
105263
|
if (options.waitMs !== undefined && options.waitMs > 0 && ["queued", "verifying"].includes(receipt.intent.state)) {
|
|
105016
105264
|
receipt.intent = checkedPublicationView(await client2.wait(receipt.skillId, receipt.intent.id, { timeoutMs: options.waitMs }), receipt.skillId, receipt.intent.id, receipt.declaration);
|
|
105017
105265
|
receipt.phase = "observed";
|
|
105018
|
-
|
|
105266
|
+
save2(directory2, receipt);
|
|
105019
105267
|
}
|
|
105020
105268
|
return privatePublicationResult(directory2, receipt);
|
|
105021
105269
|
}
|
|
@@ -105027,12 +105275,12 @@ async function inspectLocked(client2, directory2, cancel) {
|
|
|
105027
105275
|
bind2(client2, receipt);
|
|
105028
105276
|
if (receipt.intent) {
|
|
105029
105277
|
receipt.intent = checkedPublicationView(await (cancel ? client2.cancel(receipt.skillId, receipt.intent.id) : client2.get(receipt.skillId, receipt.intent.id)), receipt.skillId, receipt.intent.id, receipt.declaration);
|
|
105030
|
-
|
|
105278
|
+
save2(directory2, receipt);
|
|
105031
105279
|
} else if (cancel)
|
|
105032
105280
|
throw new PrivatePublicationError("PUBLICATION_INTENT_UNKNOWN", "Reconcile the saved begin request with publication resume before cancelling its intent.");
|
|
105033
105281
|
return privatePublicationResult(directory2, receipt);
|
|
105034
105282
|
}
|
|
105035
|
-
var
|
|
105283
|
+
var fail4 = () => {
|
|
105036
105284
|
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.");
|
|
105037
105285
|
};
|
|
105038
105286
|
var init_private_publication_recovery = __esm(() => {
|
|
@@ -105404,9 +105652,9 @@ var init_mcp2 = __esm(() => {
|
|
|
105404
105652
|
});
|
|
105405
105653
|
|
|
105406
105654
|
// src/cli/commands/runtime-mcp.ts
|
|
105407
|
-
import { existsSync as existsSync32, mkdirSync as mkdirSync22, readFileSync as readFileSync34, writeFileSync as
|
|
105655
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync22, readFileSync as readFileSync34, writeFileSync as writeFileSync21 } from "fs";
|
|
105408
105656
|
import { homedir as homedir9 } from "os";
|
|
105409
|
-
import { dirname as
|
|
105657
|
+
import { dirname as dirname26, join as join51 } from "path";
|
|
105410
105658
|
async function handleMcp(options) {
|
|
105411
105659
|
if (options.register) {
|
|
105412
105660
|
let agents;
|
|
@@ -105580,8 +105828,8 @@ function writeJsonObject(path, data) {
|
|
|
105580
105828
|
`);
|
|
105581
105829
|
}
|
|
105582
105830
|
function writeTextFile(path, content) {
|
|
105583
|
-
mkdirSync22(
|
|
105584
|
-
|
|
105831
|
+
mkdirSync22(dirname26(path), { recursive: true });
|
|
105832
|
+
writeFileSync21(path, content.endsWith(`
|
|
105585
105833
|
`) ? content : `${content}
|
|
105586
105834
|
`);
|
|
105587
105835
|
}
|
|
@@ -105690,8 +105938,8 @@ var exports_runtime = {};
|
|
|
105690
105938
|
__export(exports_runtime, {
|
|
105691
105939
|
registerRuntime: () => registerRuntime
|
|
105692
105940
|
});
|
|
105693
|
-
import { createHash as
|
|
105694
|
-
import { lstatSync as
|
|
105941
|
+
import { createHash as createHash25, randomUUID as randomUUID9 } from "crypto";
|
|
105942
|
+
import { lstatSync as lstatSync26, mkdirSync as mkdirSync23, readFileSync as readFileSync35, realpathSync as realpathSync10, writeFileSync as writeFileSync22 } from "fs";
|
|
105695
105943
|
import { basename as basename11, isAbsolute as isAbsolute21, join as join52 } from "path";
|
|
105696
105944
|
import { createInterface } from "readline";
|
|
105697
105945
|
function registerRuntime(parent) {
|
|
@@ -105731,9 +105979,9 @@ function registerRuntime(parent) {
|
|
|
105731
105979
|
if (!expected)
|
|
105732
105980
|
throw new Error("Cloud artifact not found");
|
|
105733
105981
|
const bytes = await client2.download(id2, name);
|
|
105734
|
-
if (bytes.length !== expected.byteSize ||
|
|
105982
|
+
if (bytes.length !== expected.byteSize || createHash25("sha256").update(bytes).digest("hex") !== expected.sha256)
|
|
105735
105983
|
throw new Error("Cloud artifact integrity verification failed");
|
|
105736
|
-
|
|
105984
|
+
writeFileSync22(options.output, bytes, { flag: "wx", mode: 384 });
|
|
105737
105985
|
console.log(JSON.stringify({ path: options.output, sha256: expected.sha256, byteSize: bytes.length }));
|
|
105738
105986
|
} catch (error61) {
|
|
105739
105987
|
console.error(JSON.stringify({ error: error61.message }));
|
|
@@ -106139,7 +106387,7 @@ async function handleRun(name, args2, options, separatorBeforeSkill) {
|
|
|
106139
106387
|
try {
|
|
106140
106388
|
parsePollingOptions(options);
|
|
106141
106389
|
inputFiles = (options.file ?? []).map((path) => {
|
|
106142
|
-
const info =
|
|
106390
|
+
const info = lstatSync26(path);
|
|
106143
106391
|
if (!info.isFile() || info.size > 20 * 1024 * 1024)
|
|
106144
106392
|
throw new Error("Input must be a regular file no larger than 20 MiB");
|
|
106145
106393
|
return { name: basename11(path), bytes: new Uint8Array(readFileSync35(path)) };
|
|
@@ -106530,7 +106778,7 @@ async function handleExportsDownload(runId2, options) {
|
|
|
106530
106778
|
const relativePath = safeArtifactRelativePath(typeof artifact.relativePath === "string" ? artifact.relativePath : artifact.fileName, String(artifact.fileName || artifactId));
|
|
106531
106779
|
const outputPath = join52(exportDir, relativePath);
|
|
106532
106780
|
ensureSafeExportParent(exportDir, relativePath);
|
|
106533
|
-
|
|
106781
|
+
writeFileSync22(outputPath, verified.bytes, { flag: "wx", mode: 384 });
|
|
106534
106782
|
downloaded.push({ id: artifactId, path: outputPath, byteSize: verified.byteSize });
|
|
106535
106783
|
}
|
|
106536
106784
|
const payload = {
|
|
@@ -106569,7 +106817,7 @@ function ensureSafeExportParent(root2, relativePath) {
|
|
|
106569
106817
|
if (part)
|
|
106570
106818
|
parent = join52(parent, part);
|
|
106571
106819
|
try {
|
|
106572
|
-
if (!
|
|
106820
|
+
if (!lstatSync26(parent).isDirectory() || lstatSync26(parent).isSymbolicLink())
|
|
106573
106821
|
throw new Error("Unsafe artifact directory");
|
|
106574
106822
|
} catch (error61) {
|
|
106575
106823
|
if (error61.code !== "ENOENT")
|
|
@@ -106861,30 +107109,30 @@ var exports_recurring = {};
|
|
|
106861
107109
|
__export(exports_recurring, {
|
|
106862
107110
|
registerRecurringCommands: () => registerRecurringCommands
|
|
106863
107111
|
});
|
|
106864
|
-
import { constants as
|
|
107112
|
+
import { constants as constants19, closeSync as closeSync20, fstatSync as fstatSync20, lstatSync as lstatSync27, openSync as openSync20, readSync as readSync16 } from "fs";
|
|
106865
107113
|
import { createInterface as createInterface2 } from "readline";
|
|
106866
107114
|
function readRequest(path) {
|
|
106867
|
-
const fd =
|
|
107115
|
+
const fd = openSync20(path, constants19.O_RDONLY | constants19.O_NOFOLLOW | constants19.O_NONBLOCK);
|
|
106868
107116
|
try {
|
|
106869
|
-
const before2 =
|
|
107117
|
+
const before2 = fstatSync20(fd);
|
|
106870
107118
|
if (!before2.isFile() || before2.size > 1048576 || before2.size < 1)
|
|
106871
107119
|
throw new RecurringInputError;
|
|
106872
107120
|
const bytes = Buffer.alloc(before2.size + 1);
|
|
106873
107121
|
let length = 0;
|
|
106874
107122
|
while (length < bytes.length) {
|
|
106875
|
-
const n2 =
|
|
107123
|
+
const n2 = readSync16(fd, bytes, length, bytes.length - length, length);
|
|
106876
107124
|
if (!n2)
|
|
106877
107125
|
break;
|
|
106878
107126
|
length += n2;
|
|
106879
107127
|
}
|
|
106880
|
-
const after2 =
|
|
107128
|
+
const after2 = fstatSync20(fd), current = lstatSync27(path);
|
|
106881
107129
|
if (length !== before2.size || after2.size !== before2.size || before2.mtimeMs !== after2.mtimeMs || before2.ctimeMs !== after2.ctimeMs || current.dev !== before2.dev || current.ino !== before2.ino || !current.isFile() || current.isSymbolicLink())
|
|
106882
107130
|
throw new RecurringInputError;
|
|
106883
107131
|
return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, length)));
|
|
106884
107132
|
} catch {
|
|
106885
107133
|
throw new RecurringInputError;
|
|
106886
107134
|
} finally {
|
|
106887
|
-
|
|
107135
|
+
closeSync20(fd);
|
|
106888
107136
|
}
|
|
106889
107137
|
}
|
|
106890
107138
|
async function acceptAtTerminal(draft) {
|
|
@@ -107310,22 +107558,22 @@ var init_portable_snapshot_filter = __esm(() => {
|
|
|
107310
107558
|
});
|
|
107311
107559
|
|
|
107312
107560
|
// src/lib/station-snapshot.ts
|
|
107313
|
-
import { createHash as
|
|
107561
|
+
import { createHash as createHash26 } from "crypto";
|
|
107314
107562
|
import {
|
|
107315
107563
|
copyFileSync,
|
|
107316
107564
|
mkdirSync as mkdirSync24,
|
|
107317
107565
|
readFileSync as readFileSync36,
|
|
107318
107566
|
statSync as statSync19,
|
|
107319
|
-
writeFileSync as
|
|
107567
|
+
writeFileSync as writeFileSync23
|
|
107320
107568
|
} from "fs";
|
|
107321
|
-
import { dirname as
|
|
107569
|
+
import { dirname as dirname28, isAbsolute as isAbsolute22, relative as relative8, resolve as resolve21, sep as sep9 } from "path";
|
|
107322
107570
|
function validateStationId(stationId) {
|
|
107323
107571
|
if (!/^[a-z0-9-]+$/.test(stationId)) {
|
|
107324
107572
|
throw new StationSnapshotError("INVALID_STATION", `station id must be a slug, got: ${stationId}`);
|
|
107325
107573
|
}
|
|
107326
107574
|
}
|
|
107327
107575
|
function sha256File(filePath) {
|
|
107328
|
-
return
|
|
107576
|
+
return createHash26("sha256").update(readFileSync36(filePath)).digest("hex");
|
|
107329
107577
|
}
|
|
107330
107578
|
function scanHome(definition, homesRoot) {
|
|
107331
107579
|
const homePath = homePathFor(definition, homesRoot);
|
|
@@ -107446,11 +107694,11 @@ function writeStationSnapshot(options) {
|
|
|
107446
107694
|
let written = 0;
|
|
107447
107695
|
for (const plan of untouched) {
|
|
107448
107696
|
const destination = resolve21(repoRoot, plan.destination);
|
|
107449
|
-
mkdirSync24(
|
|
107697
|
+
mkdirSync24(dirname28(destination), { recursive: true });
|
|
107450
107698
|
copyFileSync(plan.source.fullPath, destination);
|
|
107451
107699
|
written += 1;
|
|
107452
107700
|
}
|
|
107453
|
-
const
|
|
107701
|
+
const unchanged3 = plans.length - untouched.length;
|
|
107454
107702
|
const manifest = {
|
|
107455
107703
|
schema: STATION_SYNC_MANIFEST_SCHEMA,
|
|
107456
107704
|
stationId: options.stationId,
|
|
@@ -107458,20 +107706,20 @@ function writeStationSnapshot(options) {
|
|
|
107458
107706
|
producer: STATION_SNAPSHOT_PRODUCER,
|
|
107459
107707
|
stats: {
|
|
107460
107708
|
written,
|
|
107461
|
-
unchanged:
|
|
107709
|
+
unchanged: unchanged3,
|
|
107462
107710
|
files: plans.length,
|
|
107463
107711
|
bytes: totalBytes
|
|
107464
107712
|
},
|
|
107465
107713
|
files: manifestFiles
|
|
107466
107714
|
};
|
|
107467
107715
|
const manifestPath = resolve21(repoRoot, "resources", options.stationId, "skills", "sync-manifest.json");
|
|
107468
|
-
mkdirSync24(
|
|
107469
|
-
|
|
107716
|
+
mkdirSync24(dirname28(manifestPath), { recursive: true });
|
|
107717
|
+
writeFileSync23(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
107470
107718
|
`);
|
|
107471
107719
|
return {
|
|
107472
107720
|
...base3,
|
|
107473
107721
|
mode: "populate",
|
|
107474
|
-
stats: { files: plans.length, bytes: totalBytes, written, unchanged:
|
|
107722
|
+
stats: { files: plans.length, bytes: totalBytes, written, unchanged: unchanged3 },
|
|
107475
107723
|
manifestPath
|
|
107476
107724
|
};
|
|
107477
107725
|
}
|
|
@@ -107932,7 +108180,7 @@ async function connectCodexHookRpc(options) {
|
|
|
107932
108180
|
});
|
|
107933
108181
|
const pending = new Map;
|
|
107934
108182
|
let nextId = 1, buffer = Buffer.alloc(0), stopped = false, diagnosticBytes = 0;
|
|
107935
|
-
const
|
|
108183
|
+
const fail5 = () => {
|
|
107936
108184
|
stopped = true;
|
|
107937
108185
|
for (const value of pending.values()) {
|
|
107938
108186
|
clearTimeout(value.timer);
|
|
@@ -107940,19 +108188,19 @@ async function connectCodexHookRpc(options) {
|
|
|
107940
108188
|
}
|
|
107941
108189
|
pending.clear();
|
|
107942
108190
|
};
|
|
107943
|
-
child.on("error",
|
|
107944
|
-
child.on("exit",
|
|
107945
|
-
child.stdin.on("error",
|
|
108191
|
+
child.on("error", fail5);
|
|
108192
|
+
child.on("exit", fail5);
|
|
108193
|
+
child.stdin.on("error", fail5);
|
|
107946
108194
|
child.stderr.on("data", (bytes) => {
|
|
107947
108195
|
diagnosticBytes += bytes.length;
|
|
107948
108196
|
if (diagnosticBytes > 2 * 1024 * 1024) {
|
|
107949
|
-
|
|
108197
|
+
fail5();
|
|
107950
108198
|
child.kill();
|
|
107951
108199
|
}
|
|
107952
108200
|
});
|
|
107953
108201
|
child.stdout.on("data", (bytes) => {
|
|
107954
108202
|
if (buffer.length + bytes.length > 8 * 1024 * 1024) {
|
|
107955
|
-
|
|
108203
|
+
fail5();
|
|
107956
108204
|
child.kill();
|
|
107957
108205
|
return;
|
|
107958
108206
|
}
|
|
@@ -107967,12 +108215,12 @@ async function connectCodexHookRpc(options) {
|
|
|
107967
108215
|
try {
|
|
107968
108216
|
value = JSON.parse(line.toString("utf8"));
|
|
107969
108217
|
} catch {
|
|
107970
|
-
|
|
108218
|
+
fail5();
|
|
107971
108219
|
child.kill();
|
|
107972
108220
|
return;
|
|
107973
108221
|
}
|
|
107974
108222
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
107975
|
-
|
|
108223
|
+
fail5();
|
|
107976
108224
|
child.kill();
|
|
107977
108225
|
return;
|
|
107978
108226
|
}
|
|
@@ -107996,7 +108244,7 @@ async function connectCodexHookRpc(options) {
|
|
|
107996
108244
|
return new Promise((resolve22, reject2) => {
|
|
107997
108245
|
const id2 = nextId++;
|
|
107998
108246
|
const timer = setTimeout(() => {
|
|
107999
|
-
|
|
108247
|
+
fail5();
|
|
108000
108248
|
child.kill();
|
|
108001
108249
|
}, 20000);
|
|
108002
108250
|
pending.set(id2, { resolve: resolve22, reject: reject2, timer });
|
|
@@ -108005,7 +108253,7 @@ async function connectCodexHookRpc(options) {
|
|
|
108005
108253
|
});
|
|
108006
108254
|
},
|
|
108007
108255
|
async close() {
|
|
108008
|
-
|
|
108256
|
+
fail5();
|
|
108009
108257
|
child.stdin.end();
|
|
108010
108258
|
if (child.exitCode !== null || child.signalCode !== null)
|
|
108011
108259
|
return;
|
|
@@ -108036,202 +108284,26 @@ var init_codex_hook_rpc = __esm(() => {
|
|
|
108036
108284
|
SUPPORTED_CODEX_HOOK_VERSIONS = ["codex-cli 0.153.0", "codex-cli 0.154.0", "codex-cli 0.155.0", "codex-cli 0.155.1"];
|
|
108037
108285
|
});
|
|
108038
108286
|
|
|
108039
|
-
// src/lib/codex-hook-trust-layout.ts
|
|
108040
|
-
import { isDeepStrictEqual as isDeepStrictEqual5 } from "util";
|
|
108041
|
-
function codexTrustTextWitness(text3, keys3, canonicalize = true) {
|
|
108042
|
-
const parsed = Bun.TOML.parse(text3), wanted = new Set(keys3);
|
|
108043
|
-
const headers = [...text3.matchAll(/^[ \t]*(\[[^\r\n]+\])[ \t]*(#[^\r\n]*)?(?:\r?\n|$)/gm)];
|
|
108044
|
-
if (headers.length > 512)
|
|
108045
|
-
throw fail4();
|
|
108046
|
-
let root2 = parsed;
|
|
108047
|
-
for (const header of headers) {
|
|
108048
|
-
try {
|
|
108049
|
-
root2 = Bun.TOML.parse(text3.slice(0, header.index));
|
|
108050
|
-
break;
|
|
108051
|
-
} catch {}
|
|
108052
|
-
}
|
|
108053
|
-
if (root2.hooks !== undefined)
|
|
108054
|
-
throw fail4();
|
|
108055
|
-
const replacements2 = [];
|
|
108056
|
-
const stateSections = [];
|
|
108057
|
-
for (const [index, header] of headers.entries()) {
|
|
108058
|
-
let shape;
|
|
108059
|
-
try {
|
|
108060
|
-
shape = Bun.TOML.parse(header[1]);
|
|
108061
|
-
} catch {
|
|
108062
|
-
continue;
|
|
108063
|
-
}
|
|
108064
|
-
const state = shape.hooks?.state;
|
|
108065
|
-
if (!state || Object.keys(shape).length !== 1 || Object.keys(shape.hooks).length !== 1)
|
|
108066
|
-
continue;
|
|
108067
|
-
const names = Object.keys(state), start = header.index, end = headers[index + 1]?.index ?? text3.length;
|
|
108068
|
-
if (names.length === 0) {
|
|
108069
|
-
replacements2.push({ start, end: start + header[0].length, comments: header[2] ? header[2] + `
|
|
108070
|
-
` : "" });
|
|
108071
|
-
stateSections.push({ start, end: start + header[0].length });
|
|
108072
|
-
} else if (names.length === 1 && !Object.keys(state[names[0]]).length) {
|
|
108073
|
-
stateSections.push({ start, end });
|
|
108074
|
-
if (!wanted.has(names[0])) {
|
|
108075
|
-
replacements2.push({ start, end: start + header[0].length, comments: `[hooks.state.${JSON.stringify(names[0])}]${header[2] ? " " + header[2] : ""}
|
|
108076
|
-
` });
|
|
108077
|
-
continue;
|
|
108078
|
-
}
|
|
108079
|
-
const comments = header[2] ? [header[2]] : [];
|
|
108080
|
-
for (const line of text3.slice(start + header[0].length, end).split(/\r?\n/)) {
|
|
108081
|
-
if (!line.trim())
|
|
108082
|
-
continue;
|
|
108083
|
-
if (/^[ \t]*#/.test(line)) {
|
|
108084
|
-
comments.push(line);
|
|
108085
|
-
continue;
|
|
108086
|
-
}
|
|
108087
|
-
const field2 = /^[ \t]*(?:enabled|trusted_hash)[ \t]*=[ \t]*(?:true|false|"(?:[^"\\]|\\.)*"|'[^']*')[ \t]*(#[^\r\n]*)?$/.exec(line);
|
|
108088
|
-
if (!field2)
|
|
108089
|
-
throw fail4();
|
|
108090
|
-
if (field2[1])
|
|
108091
|
-
comments.push(field2[1]);
|
|
108092
|
-
}
|
|
108093
|
-
replacements2.push({ start, end, comments: comments.join(`
|
|
108094
|
-
`) + `
|
|
108095
|
-
` });
|
|
108096
|
-
}
|
|
108097
|
-
}
|
|
108098
|
-
let noState = text3;
|
|
108099
|
-
for (const span of [...stateSections].reverse())
|
|
108100
|
-
noState = noState.slice(0, span.start) + noState.slice(span.end);
|
|
108101
|
-
const expected = structuredClone(parsed);
|
|
108102
|
-
if (expected.hooks)
|
|
108103
|
-
delete expected.hooks.state;
|
|
108104
|
-
try {
|
|
108105
|
-
if (!isDeepStrictEqual5(prune(Bun.TOML.parse(noState)), prune(expected)))
|
|
108106
|
-
throw fail4();
|
|
108107
|
-
} catch {
|
|
108108
|
-
throw fail4();
|
|
108109
|
-
}
|
|
108110
|
-
let result2 = text3;
|
|
108111
|
-
for (const span of replacements2.reverse())
|
|
108112
|
-
result2 = result2.slice(0, span.start) + span.comments + result2.slice(span.end);
|
|
108113
|
-
return (canonicalize ? canonicalizeTableOrder(result2) : result2).split(/\r?\n/).filter((line) => line.trim()).join(`
|
|
108114
|
-
`);
|
|
108115
|
-
}
|
|
108116
|
-
function codexTrustReconcileWitness(text3, keys3) {
|
|
108117
|
-
return codexTrustTextWitness(text3, keys3, false).replace(/[ \t]+$/gm, "");
|
|
108118
|
-
}
|
|
108119
|
-
function codexTrustUnmanagedSemantic(text3, keys3) {
|
|
108120
|
-
const parsed = structuredClone(Bun.TOML.parse(text3));
|
|
108121
|
-
for (const key of keys3)
|
|
108122
|
-
if (parsed.hooks?.state?.[key] !== undefined)
|
|
108123
|
-
delete parsed.hooks.state[key];
|
|
108124
|
-
return JSON.stringify(stableSemantic(prune(parsed)));
|
|
108125
|
-
}
|
|
108126
|
-
var fail4 = () => new Error('CODEX_HOOK_TRUST_UNSUPPORTED_LAYOUT: preserve and convert hook trust to ordinary [hooks.state."<key>"] tables before enrollment'), prune = (value) => {
|
|
108127
|
-
if (value.hooks?.state && !Object.keys(value.hooks.state).length)
|
|
108128
|
-
delete value.hooks.state;
|
|
108129
|
-
if (value.hooks && !Object.keys(value.hooks).length)
|
|
108130
|
-
delete value.hooks;
|
|
108131
|
-
return value;
|
|
108132
|
-
}, canonicalizeTableOrder = (text3) => {
|
|
108133
|
-
const headers = [...text3.matchAll(/^[ \t]*(\[\[?[^\r\n]+\]\]?)[ \t]*(#[^\r\n]*)?(?:\r?\n|$)/gm)];
|
|
108134
|
-
if (!headers.length)
|
|
108135
|
-
return text3;
|
|
108136
|
-
const keys3 = headers.map((header) => header[1].trim());
|
|
108137
|
-
const repeated = keys3.filter((key) => !key.startsWith("[[")).filter((key, index, simple2) => simple2.indexOf(key) !== index);
|
|
108138
|
-
const arrayKeys = keys3.filter((key) => key.startsWith("[["));
|
|
108139
|
-
const plain = keys3.map((key) => key.replace(/^\[\[?/, "").replace(/\]\]?$/, "").trim());
|
|
108140
|
-
const parentChild = plain.some((key, index) => plain.some((other, otherIndex) => index !== otherIndex && (other.startsWith(`${key}.`) || key.startsWith(`${other}.`))));
|
|
108141
|
-
if (repeated.length || parentChild)
|
|
108142
|
-
return text3;
|
|
108143
|
-
if (!arrayKeys.length) {
|
|
108144
|
-
const first2 = headers[0].index;
|
|
108145
|
-
const prefix2 = text3.slice(0, first2);
|
|
108146
|
-
const blocks2 = headers.map((header, index) => ({
|
|
108147
|
-
key: header[1],
|
|
108148
|
-
order: index,
|
|
108149
|
-
text: text3.slice(header.index, headers[index + 1]?.index ?? text3.length)
|
|
108150
|
-
}));
|
|
108151
|
-
blocks2.sort((a, b) => a.key.localeCompare(b.key) || a.order - b.order);
|
|
108152
|
-
return prefix2 + blocks2.map((block) => block.text).join("");
|
|
108153
|
-
}
|
|
108154
|
-
const first = headers[0].index;
|
|
108155
|
-
const prefix = text3.slice(0, first);
|
|
108156
|
-
const blocks = headers.map((header, index) => ({
|
|
108157
|
-
key: header[1],
|
|
108158
|
-
order: index,
|
|
108159
|
-
text: text3.slice(header.index, headers[index + 1]?.index ?? text3.length)
|
|
108160
|
-
}));
|
|
108161
|
-
const simple = blocks.filter((block) => !block.key.startsWith("[["));
|
|
108162
|
-
const arrays = blocks.filter((block) => block.key.startsWith("[["));
|
|
108163
|
-
return prefix + [...simple, ...arrays].map((block) => block.text).join("");
|
|
108164
|
-
}, stableSemantic = (value) => {
|
|
108165
|
-
if (Array.isArray(value))
|
|
108166
|
-
return value.map(stableSemantic);
|
|
108167
|
-
if (value && typeof value === "object")
|
|
108168
|
-
return Object.fromEntries(Object.keys(value).sort().map((key) => [key, stableSemantic(value[key])]));
|
|
108169
|
-
return value;
|
|
108170
|
-
};
|
|
108171
|
-
var init_codex_hook_trust_layout = () => {};
|
|
108172
|
-
|
|
108173
|
-
// src/lib/codex-hook-trust-files.ts
|
|
108174
|
-
import { closeSync as closeSync20, constants as constants19, fstatSync as fstatSync20, fsyncSync as fsyncSync6, lstatSync as lstatSync27, openSync as openSync20, readSync as readSync16, writeFileSync as writeFileSync23 } from "fs";
|
|
108175
|
-
import { createHash as createHash25 } from "crypto";
|
|
108176
|
-
import { dirname as dirname28 } from "path";
|
|
108177
|
-
function need4(value, code2) {
|
|
108178
|
-
if (!value)
|
|
108179
|
-
throw new Error(`CODEX_HOOK_TRUST_${code2}`);
|
|
108180
|
-
}
|
|
108181
|
-
function safeParents(file2) {
|
|
108182
|
-
for (let p = dirname28(file2);; p = dirname28(p)) {
|
|
108183
|
-
const s = lstatSync27(p);
|
|
108184
|
-
need4(s.isDirectory() && !s.isSymbolicLink(), "UNSAFE_PARENT");
|
|
108185
|
-
need4((s.mode & 18) === 0 || s.uid === 0 && (s.mode & 512) !== 0, "UNSAFE_PARENT");
|
|
108186
|
-
if (dirname28(p) === p)
|
|
108187
|
-
break;
|
|
108188
|
-
}
|
|
108189
|
-
}
|
|
108190
|
-
function snapshot(file2, privateFile = false, options = {}) {
|
|
108191
|
-
const readOnlyPackage = options.readOnlyPackage === true && !privateFile;
|
|
108192
|
-
safeParents(file2);
|
|
108193
|
-
const initial2 = lstatSync27(file2, { bigint: true });
|
|
108194
|
-
need4(initial2.isFile() && initial2.uid === BigInt(process.getuid()) && (initial2.nlink === 1n || readOnlyPackage && initial2.nlink > 1n) && (initial2.mode & 0o022n) === 0n && (!privateFile || (initial2.mode & 0o777n) === 0o600n), "UNSAFE_FILE");
|
|
108195
|
-
need4(initial2.size <= 8n * 1024n * 1024n, "FILE_BOUND");
|
|
108196
|
-
const fd = openSync20(file2, constants19.O_RDONLY | constants19.O_NOFOLLOW | constants19.O_NONBLOCK);
|
|
108197
|
-
try {
|
|
108198
|
-
const before2 = fstatSync20(fd, { bigint: true });
|
|
108199
|
-
need4(sameStat(initial2, before2), "INPUT_CHANGED");
|
|
108200
|
-
const bytes = Buffer.alloc(Number(before2.size) + 1);
|
|
108201
|
-
let length = 0;
|
|
108202
|
-
while (length < bytes.length) {
|
|
108203
|
-
const n2 = readSync16(fd, bytes, length, bytes.length - length, null);
|
|
108204
|
-
if (!n2)
|
|
108205
|
-
break;
|
|
108206
|
-
length += n2;
|
|
108207
|
-
}
|
|
108208
|
-
need4(length === Number(before2.size) && sameStat(before2, fstatSync20(fd, { bigint: true })) && sameStat(before2, lstatSync27(file2, { bigint: true })), "INPUT_CHANGED");
|
|
108209
|
-
const content = bytes.subarray(0, length), text3 = new TextDecoder("utf-8", { fatal: true }).decode(content);
|
|
108210
|
-
return { file: file2, privateFile, readOnlyPackage, text: text3, bytes: content, stat: before2, sha256: createHash25("sha256").update(content).digest("hex") };
|
|
108211
|
-
} finally {
|
|
108212
|
-
closeSync20(fd);
|
|
108213
|
-
}
|
|
108214
|
-
}
|
|
108215
|
-
function unchanged2(before2) {
|
|
108216
|
-
const after2 = snapshot(before2.file, before2.privateFile, before2.readOnlyPackage ? { readOnlyPackage: true } : {});
|
|
108217
|
-
need4(sameStat(before2.stat, after2.stat) && after2.sha256 === before2.sha256, "INPUT_CHANGED");
|
|
108218
|
-
}
|
|
108219
|
-
function save2(file2, content) {
|
|
108220
|
-
safeParents(file2);
|
|
108221
|
-
const fd = openSync20(file2, constants19.O_WRONLY | constants19.O_CREAT | constants19.O_EXCL | constants19.O_NOFOLLOW, 384);
|
|
108222
|
-
try {
|
|
108223
|
-
writeFileSync23(fd, content);
|
|
108224
|
-
fsyncSync6(fd);
|
|
108225
|
-
} finally {
|
|
108226
|
-
closeSync20(fd);
|
|
108227
|
-
}
|
|
108228
|
-
}
|
|
108229
|
-
var sameStat = (a, b) => ["dev", "ino", "uid", "nlink", "mode", "size", "mtimeNs", "ctimeNs"].every((key) => a[key] === b[key]);
|
|
108230
|
-
var init_codex_hook_trust_files = () => {};
|
|
108231
|
-
|
|
108232
108287
|
// src/lib/codex-hook-trust-identity.ts
|
|
108233
108288
|
import { realpathSync as realpathSync12 } from "fs";
|
|
108234
108289
|
import { dirname as dirname29, isAbsolute as isAbsolute24, join as join55 } from "path";
|
|
108290
|
+
import { isDeepStrictEqual as isDeepStrictEqual7 } from "util";
|
|
108291
|
+
function inspectRecordedSkillsCli(command, expected) {
|
|
108292
|
+
need4(isAbsolute24(command) && !command.includes("\x00"), "RECONCILE_RECORDED_COMMAND_REQUIRED");
|
|
108293
|
+
const resolved = realpathSync12(command);
|
|
108294
|
+
const cli = snapshot(resolved, false, { readOnlyPackage: true });
|
|
108295
|
+
const manifest = snapshot(join55(dirname29(dirname29(resolved)), "package.json"), false, { readOnlyPackage: true });
|
|
108296
|
+
const pkg = JSON.parse(manifest.text);
|
|
108297
|
+
need4(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join55(dirname29(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
|
|
108298
|
+
need4((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
|
|
108299
|
+
const receipt = { path: resolved, version: pkg.version, sha256: cli.sha256, manifestSha256: manifest.sha256 };
|
|
108300
|
+
need4(isDeepStrictEqual7(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
|
|
108301
|
+
return { receipt, recheck() {
|
|
108302
|
+
need4(realpathSync12(command) === resolved, "SKILLS_COMMAND_CHANGED");
|
|
108303
|
+
unchanged2(cli);
|
|
108304
|
+
unchanged2(manifest);
|
|
108305
|
+
} };
|
|
108306
|
+
}
|
|
108235
108307
|
function bindSkillsCli(command, reviewed) {
|
|
108236
108308
|
const normal = Bun.which("skills", { PATH: process.env.PATH });
|
|
108237
108309
|
need4(normal, "SKILLS_COMMAND_UNAVAILABLE");
|
|
@@ -108260,23 +108332,46 @@ var init_codex_hook_trust_identity = __esm(() => {
|
|
|
108260
108332
|
init_codex_hook_trust_files();
|
|
108261
108333
|
});
|
|
108262
108334
|
|
|
108335
|
+
// src/lib/codex-hook-policy-recovery.ts
|
|
108336
|
+
import { isDeepStrictEqual as isDeepStrictEqual8 } from "util";
|
|
108337
|
+
function reviewedClaudeDiscoveryChange(beforeText, currentText, options) {
|
|
108338
|
+
need4(typeof options.reason === "string" && options.reason.trim().length > 0 && options.reason.length <= 512 && !/[\x00-\x1f\x7f]/.test(options.reason), "RECONCILE_RECOVERY_REASON_REQUIRED");
|
|
108339
|
+
need4(options.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(options.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
|
|
108340
|
+
const before2 = parseManagedSkillPolicy(beforeText), current = parseManagedSkillPolicy(currentText);
|
|
108341
|
+
const oldDiscovery = before2.bridge?.discovery?.claude, newDiscovery = current.bridge?.discovery?.claude;
|
|
108342
|
+
need4(oldDiscovery?.agent === "claude" && newDiscovery?.agent === "claude" && oldDiscovery.method === "reviewed" && newDiscovery.method === "reviewed", "RECONCILE_POLICY_CHANGED");
|
|
108343
|
+
const changes = ["roots", "sources"].filter((key) => !isDeepStrictEqual8(oldDiscovery[key], newDiscovery[key])).map((key) => ({ path: `bridge.discovery.claude.${key}`, before: oldDiscovery[key], after: newDiscovery[key] }));
|
|
108344
|
+
need4(changes.length > 0, "RECONCILE_POLICY_CHANGED");
|
|
108345
|
+
const compared = structuredClone(current);
|
|
108346
|
+
compared.bridge.discovery.claude.roots = oldDiscovery.roots;
|
|
108347
|
+
compared.bridge.discovery.claude.sources = oldDiscovery.sources;
|
|
108348
|
+
need4(isDeepStrictEqual8(before2, compared), "RECONCILE_POLICY_CHANGED");
|
|
108349
|
+
verifyAgentDiscovery(newDiscovery);
|
|
108350
|
+
return { reason: options.reason, changes };
|
|
108351
|
+
}
|
|
108352
|
+
var init_codex_hook_policy_recovery = __esm(() => {
|
|
108353
|
+
init_codex_hook_trust_files();
|
|
108354
|
+
init_managed_policy();
|
|
108355
|
+
init_agent_discovery();
|
|
108356
|
+
});
|
|
108357
|
+
|
|
108263
108358
|
// src/lib/agent-codex-trust.ts
|
|
108264
108359
|
import { lstatSync as lstatSync28, mkdirSync as mkdirSync25, readdirSync as readdirSync20, readFileSync as readFileSync37, realpathSync as realpathSync13, statSync as statSync21 } from "fs";
|
|
108265
|
-
import { createHash as
|
|
108360
|
+
import { createHash as createHash27, randomUUID as randomUUID10 } from "crypto";
|
|
108266
108361
|
import { execFileSync } from "child_process";
|
|
108267
108362
|
import { dirname as dirname30, isAbsolute as isAbsolute25, join as join56, resolve as resolve22 } from "path";
|
|
108268
108363
|
import { homedir as homedir11 } from "os";
|
|
108269
|
-
import { isDeepStrictEqual as
|
|
108364
|
+
import { isDeepStrictEqual as isDeepStrictEqual9 } from "util";
|
|
108270
108365
|
function verifyReleaseArtifact(proof, skillsCli) {
|
|
108271
108366
|
need4(isAbsolute25(proof.packageTarPath) && !proof.packageTarPath.includes("\x00"), "RECONCILE_RELEASE_PROVENANCE_PATH");
|
|
108272
108367
|
const tarPath = realpathSync13(proof.packageTarPath);
|
|
108273
108368
|
need4(statSync21(tarPath).isFile(), "RECONCILE_RELEASE_PROVENANCE_PATH");
|
|
108274
108369
|
const tarBytes = readFileSync37(tarPath);
|
|
108275
|
-
need4(tarBytes.byteLength === proof.packageTarBytes &&
|
|
108370
|
+
need4(tarBytes.byteLength === proof.packageTarBytes && createHash27("sha256").update(tarBytes).digest("hex") === proof.packageTarSha256, "RECONCILE_RELEASE_ARTIFACT_CHANGED");
|
|
108276
108371
|
const packageRoot = dirname30(dirname30(realpathSync13(skillsCli.receipt.path)));
|
|
108277
108372
|
const manifest = readFileSync37(join56(packageRoot, "package.json"));
|
|
108278
|
-
need4(
|
|
108279
|
-
need4(
|
|
108373
|
+
need4(createHash27("sha256").update(manifest).digest("hex") === skillsCli.receipt.manifestSha256 && skillsCli.receipt.manifestSha256 === proof.manifestSha256, "RECONCILE_RELEASE_MANIFEST_CHANGED");
|
|
108374
|
+
need4(createHash27("sha256").update(readFileSync37(skillsCli.receipt.path)).digest("hex") === proof.executableSha256 && skillsCli.receipt.sha256 === proof.executableSha256, "RECONCILE_RELEASE_EXECUTABLE_CHANGED");
|
|
108280
108375
|
const members2 = [["package/package.json", manifest], ["package/bin/index.js", readFileSync37(skillsCli.receipt.path)]];
|
|
108281
108376
|
for (const [member, expected] of members2) {
|
|
108282
108377
|
let actual;
|
|
@@ -108308,17 +108403,20 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
108308
108403
|
const configSha256 = intent.configSha256 ?? configBefore.sha256, configVersion = intent.configVersion ?? intent.expectedVersion;
|
|
108309
108404
|
const digestInput = { version: 1, home: intent.home ?? home, configPath: intent.configPath, ...intent.nativeConfigPath !== undefined ? { nativeConfigPath: intent.nativeConfigPath } : {}, configSha256, configVersion, policySha256: intent.policySha256, hooksSha256: intent.hooksSha256, skillsCli: intent.skillsCli, nativeVersion: intent.nativeVersion, declarations, admitted };
|
|
108310
108405
|
need4(makePlanDigest(digestInput) === intent.planDigest, "RECONCILE_PLAN_CHANGED");
|
|
108311
|
-
need4(
|
|
108406
|
+
need4(isDeepStrictEqual9(intent.hooks, admitted.filter((hook) => !hook.enabled || hook.trustStatus !== "trusted")), "RECONCILE_INTENT_HOOKS_CHANGED");
|
|
108312
108407
|
need4(configBefore.sha256 === (intent.beforeSha256 ?? intent.configSha256) && hooksBefore.sha256 === intent.hooksSha256 && policyBefore.sha256 === intent.policySha256, "RECONCILE_JOURNAL_CHANGED");
|
|
108313
108408
|
const policyCurrent = snapshot(join56(dataDir3, "agent-policy.json"), true);
|
|
108409
|
+
const recovery = options.claudeDiscoveryRecovery;
|
|
108410
|
+
need4(!recovery || !options.supersedeBinding, "RECONCILE_RECOVERY_MODE_CONFLICT");
|
|
108411
|
+
const policyChange = recovery ? reviewedClaudeDiscoveryChange(policyBefore.text, policyCurrent.text, recovery) : undefined;
|
|
108314
108412
|
let supersededBinding = false;
|
|
108315
|
-
if (policyCurrent.sha256 !== policyBefore.sha256) {
|
|
108413
|
+
if (policyCurrent.sha256 !== policyBefore.sha256 && !recovery) {
|
|
108316
108414
|
need4(options.supersedeBinding === true, "RECONCILE_POLICY_CHANGED");
|
|
108317
108415
|
const oldPolicy = JSON.parse(policyBefore.text), currentPolicy = JSON.parse(policyCurrent.text);
|
|
108318
|
-
need4(
|
|
108416
|
+
need4(isDeepStrictEqual9(withoutCodexCommand(oldPolicy), withoutCodexCommand(currentPolicy)), "RECONCILE_POLICY_CHANGED");
|
|
108319
108417
|
supersededBinding = true;
|
|
108320
108418
|
}
|
|
108321
|
-
if (supersededBinding) {
|
|
108419
|
+
if (supersededBinding || recovery) {
|
|
108322
108420
|
need4(Array.isArray(intent.nativeHooks) && intent.nativeHooks.length > 0, "RECONCILE_NATIVE_INVENTORY_REQUIRED");
|
|
108323
108421
|
const proof = options.releaseProof;
|
|
108324
108422
|
need4(!!proof && isAbsolute25(proof.packageTarPath) && /^[a-f0-9]{64}$/.test(proof.packageTarSha256) && Number.isInteger(proof.packageTarBytes) && proof.packageTarBytes > 0 && /^[a-f0-9]{64}$/.test(proof.manifestSha256) && /^[a-f0-9]{64}$/.test(proof.executableSha256), "RECONCILE_RELEASE_PROVENANCE_REQUIRED");
|
|
@@ -108328,7 +108426,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
108328
108426
|
const witnessSame = codexTrustReconcileWitness(configBefore.text, managedKeys) === codexTrustReconcileWitness(currentConfig.text, managedKeys);
|
|
108329
108427
|
const unmanagedSame = codexTrustUnmanagedSemantic(configBefore.text, managedKeys) === codexTrustUnmanagedSemantic(currentConfig.text, managedKeys);
|
|
108330
108428
|
need4(unmanagedSame && (witnessSame || supersededBinding), "RECONCILE_UNRELATED_CONFIG_CHANGED");
|
|
108331
|
-
const before2 =
|
|
108429
|
+
const before2 = structure2(configBefore.text), current = structure2(currentConfig.text), expectedConfig = structuredClone(before2);
|
|
108332
108430
|
expectedConfig.hooks ??= {};
|
|
108333
108431
|
expectedConfig.hooks.state ??= {};
|
|
108334
108432
|
for (const hook of intent.hooks)
|
|
@@ -108339,13 +108437,17 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
108339
108437
|
need4(state?.enabled === true && typeof state.trusted_hash === "string" && /^sha256:[a-f0-9]{64}$/.test(state.trusted_hash), "RECONCILE_CONFIG_DRIFT");
|
|
108340
108438
|
}
|
|
108341
108439
|
} else
|
|
108342
|
-
need4(
|
|
108440
|
+
need4(isDeepStrictEqual9(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
|
|
108343
108441
|
const policy = parseManagedSkillPolicy(policyCurrent.text), binding = policy.bridge;
|
|
108344
|
-
|
|
108345
|
-
|
|
108442
|
+
const configDiscoveryRecovery = recovery && binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, configBefore, currentConfig, intent.hooks) : undefined;
|
|
108443
|
+
assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: configDiscoveryRecovery });
|
|
108444
|
+
const recoveryCli = recovery ? bindSkillsCli("skills", options.reviewedSkillsCli) : undefined;
|
|
108445
|
+
if (recoveryCli)
|
|
108446
|
+
verifyReleaseArtifact(options.releaseProof, recoveryCli);
|
|
108447
|
+
const skillsCli = recovery ? inspectRecordedSkillsCli(binding.commands.codex, intent.skillsCli) : bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
|
|
108346
108448
|
if (supersededBinding)
|
|
108347
108449
|
verifyReleaseArtifact(options.releaseProof, skillsCli);
|
|
108348
|
-
const skillsBindingChanged = !
|
|
108450
|
+
const skillsBindingChanged = !isDeepStrictEqual9(skillsCli.receipt, intent.skillsCli);
|
|
108349
108451
|
need4(!skillsBindingChanged || supersededBinding, "RECONCILE_SKILLS_BINDING_CHANGED");
|
|
108350
108452
|
const alias = binding.rootAliases?.find((item) => item.agent === "codex"), physicalRoot = alias?.target ?? join56(home, ".codex"), hooksPath = join56(physicalRoot, "hooks.json");
|
|
108351
108453
|
need4(resolve22(intent.configPath) === resolve22(join56(physicalRoot, "config.toml")), "RECONCILE_CONFIG_PATH_CHANGED");
|
|
@@ -108358,7 +108460,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
108358
108460
|
const currentDeclarations = JSON.parse(hooksCurrent.text).hooks;
|
|
108359
108461
|
for (const [event, [nativeEvent]] of Object.entries(eventNames)) {
|
|
108360
108462
|
const command = renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, event);
|
|
108361
|
-
need4(
|
|
108463
|
+
need4(isDeepStrictEqual9(currentDeclarations?.[event], [{ hooks: [{ type: "command", command, timeout: 15 }] }]), "RECONCILE_BINDING_HOOK_CHANGED");
|
|
108362
108464
|
}
|
|
108363
108465
|
}
|
|
108364
108466
|
rpc = await connect({ command: options.codexCommand ?? "codex", home, codexHome });
|
|
@@ -108381,9 +108483,9 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
108381
108483
|
delete identity4.command;
|
|
108382
108484
|
return identity4;
|
|
108383
108485
|
};
|
|
108384
|
-
need4(
|
|
108486
|
+
need4(isDeepStrictEqual9(stable(actual), stable(expected)), "RECONCILE_NATIVE_IDENTITY_CHANGED");
|
|
108385
108487
|
if (!plannedKeys.has(expected.key))
|
|
108386
|
-
need4(
|
|
108488
|
+
need4(isDeepStrictEqual9(actual, expected), "RECONCILE_UNRELATED_HOOK_CHANGED");
|
|
108387
108489
|
}
|
|
108388
108490
|
for (const wanted of intent.hooks) {
|
|
108389
108491
|
const matches2 = nativeHooks.filter((h2) => h2.key === wanted.key || h2.key === wanted.key.replace(join56(home, ".codex/hooks.json"), hooksPath));
|
|
@@ -108400,12 +108502,21 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
108400
108502
|
}
|
|
108401
108503
|
const config2 = await rpc.request("config/read", { includeLayers: true, cwd: home });
|
|
108402
108504
|
const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
|
|
108403
|
-
need4(layers?.length === 1 && !layers[0].disabledReason &&
|
|
108505
|
+
need4(layers?.length === 1 && !layers[0].disabledReason && isDeepStrictEqual9(layers[0].config, current), "RECONCILE_NATIVE_CONFIG_MISMATCH");
|
|
108404
108506
|
const finalDiscovery = await rpc.request("hooks/list", { cwds: [home] });
|
|
108405
|
-
need4(Array.isArray(finalDiscovery?.data) && finalDiscovery.data.length === 1 && finalDiscovery.data[0].cwd === home && !finalDiscovery.data[0].errors?.length && !finalDiscovery.data[0].warnings?.length && (!recordedNativeHooks ||
|
|
108507
|
+
need4(Array.isArray(finalDiscovery?.data) && finalDiscovery.data.length === 1 && finalDiscovery.data[0].cwd === home && !finalDiscovery.data[0].errors?.length && !finalDiscovery.data[0].warnings?.length && (!recordedNativeHooks || isDeepStrictEqual9(finalDiscovery.data[0].hooks.map(safeNativeHook), nativeHooks.map(safeNativeHook))), "RECONCILE_NATIVE_STATE_CHANGED");
|
|
108406
108508
|
const finalConfig = await rpc.request("config/read", { includeLayers: true, cwd: home });
|
|
108407
108509
|
const finalLayers = finalConfig?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
|
|
108408
|
-
need4(finalLayers?.length === 1 &&
|
|
108510
|
+
need4(finalLayers?.length === 1 && !finalLayers[0].disabledReason && isDeepStrictEqual9(finalLayers[0].config, current), "RECONCILE_NATIVE_CONFIG_CHANGED");
|
|
108511
|
+
if (recovery) {
|
|
108512
|
+
for (const response of [config2, finalConfig]) {
|
|
108513
|
+
const layerIndex = response.layers.findIndex((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
|
|
108514
|
+
need4(response.config && response.config.features?.hooks !== false && response.layers.slice(0, layerIndex).every((layer) => layer.config?.hooks === undefined && layer.config?.features?.hooks === undefined), "RECONCILE_NATIVE_CONFIG_OVERRIDDEN");
|
|
108515
|
+
}
|
|
108516
|
+
recoveryCli.recheck();
|
|
108517
|
+
verifyReleaseArtifact(options.releaseProof, recoveryCli);
|
|
108518
|
+
reviewedClaudeDiscoveryChange(policyBefore.text, policyCurrent.text, recovery);
|
|
108519
|
+
}
|
|
108409
108520
|
unchanged2(stoppedFile);
|
|
108410
108521
|
unchanged2(intentFile);
|
|
108411
108522
|
unchanged2(configBefore);
|
|
@@ -108415,9 +108526,16 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
108415
108526
|
unchanged2(hooksCurrent);
|
|
108416
108527
|
unchanged2(currentConfig);
|
|
108417
108528
|
skillsCli.recheck();
|
|
108418
|
-
assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home });
|
|
108419
|
-
const
|
|
108420
|
-
|
|
108529
|
+
assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: configDiscoveryRecovery });
|
|
108530
|
+
const recoveryPlan = recovery ? { version: 1, kind: "claude-discovery-only", journal, journalIntentSha256: intentFile.sha256, stoppedSha256: stoppedFile.sha256, originalPlanDigest: intent.planDigest, policyBeforeSha256: policyBefore.sha256, policyCurrentSha256: policyCurrent.sha256, configBeforeSha256: configBefore.sha256, configCurrentSha256: currentConfig.sha256, ...configDiscoveryRecovery ? { configDiscoveryRecovery } : {}, hooksSha256: hooksCurrent.sha256, nativeConfigPath, nativeVersion: rpc.version, nativeInventorySha256: makePlanDigest(nativeHooks.map(safeNativeHook)), recordedNativeInventorySha256: makePlanDigest(recordedNativeHooks), boundSkillsCli: skillsCli.receipt, recoveryCli: recoveryCli.receipt, releaseProof: options.releaseProof, ...policyChange } : undefined;
|
|
108531
|
+
const recoveryPlanDigest = recoveryPlan ? makePlanDigest(recoveryPlan) : undefined;
|
|
108532
|
+
if (recovery?.reviewedPlanDigest !== undefined)
|
|
108533
|
+
need4(recovery.reviewedPlanDigest === recoveryPlanDigest, "RECONCILE_RECOVERY_PLAN_CHANGED");
|
|
108534
|
+
const preview2 = !!recovery && recovery.reviewedPlanDigest === undefined;
|
|
108535
|
+
const receipt = { version: 1, status: preview2 ? "recovery-review-required" : supersededBinding ? "superseded" : "reconciled", reconciled: !preview2, supersededBinding, automaticRollback: false, journal, planDigest: intent.planDigest, nativeVersion: rpc.version, nativeStateVerified: !nativeTrustPending, nativeTrustPending, bindingRefreshRequired: !!configDiscoveryRecovery, nativeExecutionVerified: false, configSha256: currentConfig.sha256, hooksSha256: hooksCurrent.sha256, policySha256: policyBefore.sha256, policyBeforeSha256: policyBefore.sha256, policyCurrentSha256: policyCurrent.sha256, previousSkillsCli: intent.skillsCli, skillsCli: skillsCli.receipt, releaseProof: options.releaseProof, nativeInventoryScope: recordedNativeHooks ? "complete" : "declared-managed-hooks-only", unrelatedNativeHooksPreserved: !!recordedNativeHooks, unrelatedSettingsAndCommentsPreserved: true, ...recoveryPlan ? { recoveryPlan, recoveryPlanDigest } : {} };
|
|
108536
|
+
if (preview2)
|
|
108537
|
+
return receipt;
|
|
108538
|
+
save(join56(journal, "receipt.json"), json2(receipt));
|
|
108421
108539
|
return receipt;
|
|
108422
108540
|
} catch (error61) {
|
|
108423
108541
|
const message = error61 instanceof Error && error61.message.startsWith("CODEX_HOOK_TRUST_") ? error61.message : "CODEX_HOOK_TRUST_RECONCILE_REFUSED";
|
|
@@ -108438,14 +108556,14 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
|
|
|
108438
108556
|
need4(options.codexHome === undefined || isAbsolute25(options.codexHome) && [join56(home, ".codex"), physicalRoot].includes(options.codexHome), "NATIVE_HOME_NOT_ADMITTED");
|
|
108439
108557
|
const codexHome = options.codexHome === undefined ? undefined : physicalRoot;
|
|
108440
108558
|
const nativeConfigPath = join56(codexHome ?? join56(home, ".codex"), "config.toml");
|
|
108441
|
-
const hooksFile = snapshot(hooksPath), configFile = snapshot(configPath, true), original =
|
|
108559
|
+
const hooksFile = snapshot(hooksPath), configFile = snapshot(configPath, true), original = structure2(configFile.text);
|
|
108442
108560
|
const declarations = JSON.parse(hooksFile.text).hooks, expected = [];
|
|
108443
108561
|
for (const [event, [nativeEvent, label]] of Object.entries(eventNames)) {
|
|
108444
108562
|
const command = renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, event);
|
|
108445
108563
|
const groups = declarations[event];
|
|
108446
108564
|
need4(Array.isArray(groups), "DECLARATION_CHANGED");
|
|
108447
108565
|
const matches2 = groups.flatMap((group, gi) => (group.hooks ?? []).flatMap((entry, hi) => entry.command === command ? [{ group, entry, gi, hi }] : []));
|
|
108448
|
-
need4(matches2.length === 1 &&
|
|
108566
|
+
need4(matches2.length === 1 && isDeepStrictEqual9(matches2[0].group, { hooks: [{ type: "command", command, timeout: 15 }] }), "DECLARATION_CHANGED");
|
|
108449
108567
|
expected.push({ event: nativeEvent, key: `${join56(home, ".codex/hooks.json")}:${label}:${matches2[0].gi}:${matches2[0].hi}`, command });
|
|
108450
108568
|
}
|
|
108451
108569
|
codexTrustTextWitness(configFile.text, expected.map((h) => h.key));
|
|
@@ -108469,7 +108587,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
|
|
|
108469
108587
|
const discovered = await list2(), admitted = admit(discovered);
|
|
108470
108588
|
const config2 = await rpc.request("config/read", { includeLayers: true, cwd: home });
|
|
108471
108589
|
const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
|
|
108472
|
-
need4(layers?.length === 1 && /^sha256:[a-f0-9]{64}$/.test(layers[0].version) && !layers[0].disabledReason &&
|
|
108590
|
+
need4(layers?.length === 1 && /^sha256:[a-f0-9]{64}$/.test(layers[0].version) && !layers[0].disabledReason && isDeepStrictEqual9(layers[0].config, original), "NATIVE_CONFIG_MISMATCH");
|
|
108473
108591
|
need4(config2.config && config2.config.features?.hooks !== false, "NATIVE_HOOKS_DISABLED");
|
|
108474
108592
|
need4(config2.layers.slice(0, config2.layers.indexOf(layers[0])).every((layer) => layer.config?.hooks === undefined && layer.config?.features?.hooks === undefined), "NATIVE_CONFIG_OVERRIDDEN");
|
|
108475
108593
|
const keys3 = admitted.map((h) => h.key), planned = admitted.filter((h) => !h.enabled || h.trustStatus !== "trusted");
|
|
@@ -108484,7 +108602,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
|
|
|
108484
108602
|
checkInputs();
|
|
108485
108603
|
const digestInput = { version: 1, home, configPath, ...nativeConfigPath !== configPath ? { nativeConfigPath } : {}, configSha256: configFile.sha256, configVersion: layers[0].version, policySha256: policyFile.sha256, hooksSha256: hooksFile.sha256, skillsCli: skillsCli.receipt, nativeVersion: rpc.version, declarations: expected, admitted };
|
|
108486
108604
|
const planDigest = makePlanDigest(digestInput);
|
|
108487
|
-
const baseReceipt = { planDigest, skillsCli: skillsCli.receipt, nativeVersion: rpc.version, nativeConfigPath, ownedNativeProcessId: rpc.processId, agent: "codex", applied: false, planned, nativeEligible: planned.length === 0, transport: "owned-stdio-process", existingSessionsReloaded: false, nativeExecutionVerified: false };
|
|
108605
|
+
const baseReceipt = { planDigest, skillsCli: skillsCli.receipt, nativeVersion: rpc.version, nativeConfigPath, ownedNativeProcessId: rpc.processId, agent: "codex", applied: false, planned, nativeEligible: planned.length === 0, bindingRefreshRequired: false, transport: "owned-stdio-process", existingSessionsReloaded: false, nativeExecutionVerified: false };
|
|
108488
108606
|
if (options.apply)
|
|
108489
108607
|
need4(options.reviewedPlanDigest === planDigest, "PLAN_CHANGED: run the dry-run again and pass its reviewed --plan-digest with --apply");
|
|
108490
108608
|
const parent = join56(dataDir3, "native-hook-trust");
|
|
@@ -108504,11 +108622,11 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
|
|
|
108504
108622
|
mkdirSync25(parent, { mode: 448 });
|
|
108505
108623
|
journal = join56(parent, randomUUID10());
|
|
108506
108624
|
mkdirSync25(journal, { mode: 448 });
|
|
108507
|
-
|
|
108508
|
-
|
|
108509
|
-
|
|
108510
|
-
|
|
108511
|
-
need4(
|
|
108625
|
+
save(join56(journal, "config.before.toml"), configFile.bytes);
|
|
108626
|
+
save(join56(journal, "hooks.before.json"), hooksFile.bytes);
|
|
108627
|
+
save(join56(journal, "policy.before.json"), policyFile.bytes);
|
|
108628
|
+
save(join56(journal, "intent.json"), json2({ ...digestInput, planDigest, hooks: planned, nativeHooks: discovered.map(safeNativeHook) }));
|
|
108629
|
+
need4(isDeepStrictEqual9(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
|
|
108512
108630
|
checkInputs();
|
|
108513
108631
|
let result2;
|
|
108514
108632
|
try {
|
|
@@ -108522,25 +108640,30 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
|
|
|
108522
108640
|
expectedConfig.hooks.state ??= {};
|
|
108523
108641
|
for (const h of planned)
|
|
108524
108642
|
expectedConfig.hooks.state[h.key] = { ...expectedConfig.hooks.state[h.key], enabled: true, trusted_hash: h.currentHash };
|
|
108525
|
-
need4(
|
|
108643
|
+
need4(isDeepStrictEqual9(structure2(after2.text), expectedConfig) && codexTrustTextWitness(after2.text, keys3) === preservationText, "PRESERVATION_FAILED");
|
|
108644
|
+
const savedConfig = snapshot(join56(journal, "config.before.toml"), true);
|
|
108645
|
+
need4(savedConfig.sha256 === configFile.sha256, "JOURNAL_CHANGED");
|
|
108646
|
+
const discoveryTransition = binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, savedConfig, after2, planned) : undefined;
|
|
108526
108647
|
unchanged2(policyFile);
|
|
108527
108648
|
unchanged2(hooksFile);
|
|
108528
|
-
assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home });
|
|
108649
|
+
assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: discoveryTransition });
|
|
108529
108650
|
const current = await list2(), confirmed = admit(current);
|
|
108530
|
-
need4(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") &&
|
|
108531
|
-
need4(
|
|
108651
|
+
need4(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") && isDeepStrictEqual9(confirmed.map((h) => [h.key, h.currentHash]), admitted.map((h) => [h.key, h.currentHash])), "NATIVE_NOT_ELIGIBLE");
|
|
108652
|
+
need4(isDeepStrictEqual9(current.filter((h) => !keys3.includes(h.key)), discovered.filter((h) => !keys3.includes(h.key))), "UNRELATED_HOOK_CHANGED");
|
|
108532
108653
|
unchanged2(after2);
|
|
108654
|
+
unchanged2(savedConfig);
|
|
108533
108655
|
unchanged2(hooksFile);
|
|
108534
108656
|
unchanged2(policyFile);
|
|
108535
108657
|
skillsCli.recheck();
|
|
108536
|
-
|
|
108537
|
-
|
|
108658
|
+
assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: discoveryTransition });
|
|
108659
|
+
const receipt = { ...baseReceipt, applied: true, nativeEligible: true, bindingRefreshRequired: !!discoveryTransition, ...discoveryTransition ? { discoveryTransition } : {}, nativeConfigVersion: result2.version, journal, beforeSha256: configFile.sha256, afterSha256: after2.sha256, unrelatedSettingsAndCommentsPreserved: true };
|
|
108660
|
+
save(join56(journal, "receipt.json"), json2(receipt));
|
|
108538
108661
|
return receipt;
|
|
108539
108662
|
} catch (error61) {
|
|
108540
108663
|
const message = error61 instanceof Error && error61.message.startsWith("CODEX_HOOK_TRUST_") ? error61.message : "CODEX_HOOK_TRUST_REFUSED: verify managed bridge installation and native Codex support";
|
|
108541
108664
|
if (journal) {
|
|
108542
108665
|
try {
|
|
108543
|
-
|
|
108666
|
+
save(join56(journal, "stopped.json"), json2({ error: message.split(":")[0], automaticRollback: false, reconcileBeforeRetry: true }));
|
|
108544
108667
|
} catch {}
|
|
108545
108668
|
}
|
|
108546
108669
|
throw new Error(message);
|
|
@@ -108549,7 +108672,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
|
|
|
108549
108672
|
}
|
|
108550
108673
|
}
|
|
108551
108674
|
var json2 = (value) => JSON.stringify(value, null, 2) + `
|
|
108552
|
-
`,
|
|
108675
|
+
`, structure2 = (text3) => JSON.parse(JSON.stringify(Bun.TOML.parse(text3))), eventNames, makePlanDigest = (value) => createHash27("sha256").update(json2(value)).digest("hex"), safeNativeHook = (hook) => ({ key: hook.key, eventName: hook.eventName, handlerType: hook.handlerType, command: hook.command, matcher: hook.matcher, timeoutSec: hook.timeoutSec, async: hook.async, statusMessage: hook.statusMessage, additionalContextLimit: hook.additionalContextLimit, sourcePath: hook.sourcePath, source: hook.source, pluginId: hook.pluginId, isManaged: hook.isManaged, currentHash: hook.currentHash, enabled: hook.enabled, trustStatus: hook.trustStatus }), withoutCodexCommand = (value) => {
|
|
108553
108676
|
const copy = structuredClone(value);
|
|
108554
108677
|
if (copy?.bridge?.commands && Object.hasOwn(copy.bridge.commands, "codex"))
|
|
108555
108678
|
copy.bridge.commands.codex = "<reviewed-codex-binding>";
|
|
@@ -108559,11 +108682,13 @@ var init_agent_codex_trust = __esm(() => {
|
|
|
108559
108682
|
init_config();
|
|
108560
108683
|
init_managed_policy();
|
|
108561
108684
|
init_agent_integration();
|
|
108685
|
+
init_codex_hook_discovery_recovery();
|
|
108562
108686
|
init_agent_adapters();
|
|
108563
108687
|
init_codex_hook_rpc();
|
|
108564
108688
|
init_codex_hook_trust_layout();
|
|
108565
108689
|
init_codex_hook_trust_files();
|
|
108566
108690
|
init_codex_hook_trust_identity();
|
|
108691
|
+
init_codex_hook_policy_recovery();
|
|
108567
108692
|
eventNames = { UserPromptSubmit: ["userPromptSubmit", "user_prompt_submit"], SessionStart: ["sessionStart", "session_start"], SubagentStart: ["subagentStart", "subagent_start"] };
|
|
108568
108693
|
});
|
|
108569
108694
|
|
|
@@ -108742,25 +108867,28 @@ function registerAgentIntegration(parent) {
|
|
|
108742
108867
|
if (options.json)
|
|
108743
108868
|
await writeCliOutput(JSON.stringify(result2));
|
|
108744
108869
|
else
|
|
108745
|
-
await writeCliOutput(result2.applied ? `Enrolled ${result2.planned.length} Skills hook(s) for new Codex processes. Existing sessions were not reloaded; use their native hook controls.` : result2.planned.length ? `Planned ${result2.planned.length} native hook trust change(s). Review the --json plan, then use --apply --plan-digest ${result2.planDigest}.` : "The managed Skills hooks are enabled and trusted for new Codex processes. Existing session dispatch was not checked.");
|
|
108870
|
+
await writeCliOutput(result2.applied ? result2.bindingRefreshRequired ? `Enrolled ${result2.planned.length} native Skills hook trust state(s). Managed context remains blocked: review the current configuration and run skills hook install with fresh --discovery-inputs and the same --command. Policy was not changed. Existing sessions were not reloaded.` : `Enrolled ${result2.planned.length} Skills hook(s) for new Codex processes. Existing sessions were not reloaded; use their native hook controls.` : result2.planned.length ? `Planned ${result2.planned.length} native hook trust change(s). Review the --json plan, then use --apply --plan-digest ${result2.planDigest}.` : "The managed Skills hooks are enabled and trusted for new Codex processes. Existing session dispatch was not checked.");
|
|
108746
108871
|
} catch (error61) {
|
|
108747
108872
|
console.error(error61.message);
|
|
108748
108873
|
process.exitCode = 1;
|
|
108749
108874
|
}
|
|
108750
108875
|
});
|
|
108751
|
-
trust.command("reconcile").requiredOption("--agent <agent>", "Native trust adapter (codex)").requiredOption("--journal <path>", "Private incomplete native trust journal to inspect").option("--codex-command <path>", "Installed Codex executable used for its native configuration API", "codex").option("--supersede-binding", "Resolve a stale journal only when current policy differs solely by the reviewed Codex CLI binding", false).option("--skills-package-tar <path>", "Exact package tarball consumed by the reviewed executable").option("--skills-package-tar-sha256 <sha256>", "SHA-256 of the reviewed Skills package tarball").option("--skills-package-tar-bytes <bytes>", "Byte length of the reviewed Skills package tarball").option("--skills-package-manifest-sha256 <sha256>", "SHA-256 of the reviewed Skills package manifest").option("--skills-executable-sha256 <sha256>", "SHA-256 of the reviewed running Skills executable").option("--json", "Output the reconciliation receipt", false).description("Verify an interrupted Codex native trust write and resolve its private journal").action(async (options) => {
|
|
108876
|
+
trust.command("reconcile").requiredOption("--agent <agent>", "Native trust adapter (codex)").requiredOption("--journal <path>", "Private incomplete native trust journal to inspect").option("--codex-command <path>", "Installed Codex executable used for its native configuration API", "codex").option("--supersede-binding", "Resolve a stale journal only when current policy differs solely by the reviewed Codex CLI binding", false).option("--review-claude-discovery <reason>", "Preview recovery for exact unrelated Claude discovery roots/sources; provide an authoritative evidence reference").option("--recovery-plan-digest <sha256>", "Record recovery only for the exact reviewed --review-claude-discovery preview").option("--skills-package-tar <path>", "Exact package tarball consumed by the reviewed executable").option("--skills-package-tar-sha256 <sha256>", "SHA-256 of the reviewed Skills package tarball").option("--skills-package-tar-bytes <bytes>", "Byte length of the reviewed Skills package tarball").option("--skills-package-manifest-sha256 <sha256>", "SHA-256 of the reviewed Skills package manifest").option("--skills-executable-sha256 <sha256>", "SHA-256 of the reviewed running Skills executable").option("--json", "Output the reconciliation receipt", false).description("Verify an interrupted Codex native trust write and resolve its private journal").action(async (options) => {
|
|
108752
108877
|
try {
|
|
108753
108878
|
if (options.agent !== "codex")
|
|
108754
108879
|
throw new Error("Native trust reconciliation currently supports --agent codex only");
|
|
108880
|
+
if (options.recoveryPlanDigest !== undefined && options.reviewClaudeDiscovery === undefined)
|
|
108881
|
+
throw new Error("--recovery-plan-digest requires --review-claude-discovery");
|
|
108755
108882
|
const proofFields = [options.skillsPackageTar, options.skillsPackageTarSha256, options.skillsPackageTarBytes, options.skillsPackageManifestSha256, options.skillsExecutableSha256];
|
|
108756
108883
|
if (proofFields.some((value) => value !== undefined) && proofFields.some((value) => value === undefined))
|
|
108757
108884
|
throw new Error("Release provenance requires package tar path, tar hash/bytes, manifest hash, and executable hash together");
|
|
108758
108885
|
const releaseProof = proofFields.every((value) => value !== undefined) ? { packageTarPath: options.skillsPackageTar, packageTarSha256: options.skillsPackageTarSha256, packageTarBytes: Number(options.skillsPackageTarBytes), manifestSha256: options.skillsPackageManifestSha256, executableSha256: options.skillsExecutableSha256 } : undefined;
|
|
108759
|
-
const
|
|
108886
|
+
const claudeDiscoveryRecovery = options.reviewClaudeDiscovery === undefined ? undefined : { reason: options.reviewClaudeDiscovery, reviewedPlanDigest: options.recoveryPlanDigest };
|
|
108887
|
+
const result2 = await reconcileCodexNativeHooks({ journal: options.journal, codexCommand: options.codexCommand, supersedeBinding: options.supersedeBinding, releaseProof, claudeDiscoveryRecovery });
|
|
108760
108888
|
if (options.json)
|
|
108761
108889
|
await writeCliOutput(JSON.stringify(result2));
|
|
108762
108890
|
else
|
|
108763
|
-
await writeCliOutput(`Reconciled native Codex trust journal ${result2.journal}. No native configuration was written.`);
|
|
108891
|
+
await writeCliOutput(result2.reconciled ? result2.bindingRefreshRequired ? `Reconciled native Codex trust journal ${result2.journal}. Managed context remains blocked: install the reviewed binding with fresh --discovery-inputs before using ordinary hooks. Policy was not changed. No native configuration was written.` : `Reconciled native Codex trust journal ${result2.journal}. No native configuration was written.` : `Recovery remains pending. Review the private --json plan, then repeat with --recovery-plan-digest ${result2.recoveryPlanDigest}.`);
|
|
108764
108892
|
} catch (error61) {
|
|
108765
108893
|
console.error(error61.message);
|
|
108766
108894
|
process.exitCode = 1;
|
|
@@ -109169,7 +109297,7 @@ var init_grants = __esm(() => {
|
|
|
109169
109297
|
});
|
|
109170
109298
|
|
|
109171
109299
|
// src/lib/station-hydrate.ts
|
|
109172
|
-
import { createHash as
|
|
109300
|
+
import { createHash as createHash28 } from "crypto";
|
|
109173
109301
|
import {
|
|
109174
109302
|
copyFileSync as copyFileSync2,
|
|
109175
109303
|
mkdirSync as mkdirSync26,
|
|
@@ -109372,7 +109500,7 @@ function skillSha256(skill) {
|
|
|
109372
109500
|
return sha256File(skill.files[0].winner.fullPath);
|
|
109373
109501
|
}
|
|
109374
109502
|
const joined = skill.files.map((file2) => sha256File(file2.winner.fullPath));
|
|
109375
|
-
return
|
|
109503
|
+
return createHash28("sha256").update(joined.sort().join(`
|
|
109376
109504
|
`)).digest("hex");
|
|
109377
109505
|
}
|
|
109378
109506
|
function writeStationHydration(options) {
|
|
@@ -109529,7 +109657,7 @@ var init_hydrate = __esm(() => {
|
|
|
109529
109657
|
});
|
|
109530
109658
|
|
|
109531
109659
|
// src/lib/prepare-skill.ts
|
|
109532
|
-
import { createHash as
|
|
109660
|
+
import { createHash as createHash29, randomUUID as randomUUID11 } from "crypto";
|
|
109533
109661
|
import { chmodSync as chmodSync3, existsSync as existsSync34, lstatSync as lstatSync29, mkdirSync as mkdirSync27, mkdtempSync as mkdtempSync6, readFileSync as readFileSync40, readdirSync as readdirSync22, renameSync as renameSync12, rmSync as rmSync9, writeFileSync as writeFileSync27 } from "fs";
|
|
109534
109662
|
import { tmpdir as tmpdir2 } from "os";
|
|
109535
109663
|
import { dirname as dirname32, isAbsolute as isAbsolute27, join as join58, relative as relative9, resolve as resolve24, sep as sep11 } from "path";
|
|
@@ -109727,7 +109855,7 @@ function snapshot2(root2) {
|
|
|
109727
109855
|
if (rootStat.isSymbolicLink() || !rootStat.isDirectory())
|
|
109728
109856
|
throw new Error("Skill root must be a real directory, not a symlink.");
|
|
109729
109857
|
const files = [], directories = [];
|
|
109730
|
-
const hash4 =
|
|
109858
|
+
const hash4 = createHash29("sha256").update(`${rootStat.dev}:${rootStat.ino}\x00`);
|
|
109731
109859
|
let count = 0, bytes = 0;
|
|
109732
109860
|
const walk2 = (relative10) => {
|
|
109733
109861
|
for (const name of readdirSync22(join58(root2, relative10)).sort()) {
|
|
@@ -110944,6 +111072,10 @@ function stringField2(value) {
|
|
|
110944
111072
|
function recordField(value) {
|
|
110945
111073
|
return isRecord7(value) ? value : undefined;
|
|
110946
111074
|
}
|
|
111075
|
+
function identityApiKey(live) {
|
|
111076
|
+
const root2 = recordField(live);
|
|
111077
|
+
return root2 && Object.hasOwn(root2, "apiKey") ? root2.apiKey : recordField(root2?.data)?.apiKey;
|
|
111078
|
+
}
|
|
110947
111079
|
function authIdentityPayload(authSource, live, cached2, offline = false) {
|
|
110948
111080
|
const root2 = recordField(live) ?? {};
|
|
110949
111081
|
const data = recordField(root2.data);
|
|
@@ -110955,11 +111087,11 @@ function authIdentityPayload(authSource, live, cached2, offline = false) {
|
|
|
110955
111087
|
const userId = stringField2(user?.id) ?? cached2?.userId;
|
|
110956
111088
|
const orgId = stringField2(organization2?.id) ?? cached2?.orgId;
|
|
110957
111089
|
const role3 = stringField2(user?.role);
|
|
110958
|
-
const apiKey = recordField(
|
|
111090
|
+
const apiKey = recordField(identityApiKey(live));
|
|
110959
111091
|
const apiKeyId = stringField2(apiKey?.id);
|
|
110960
111092
|
const apiKeyScopes = apiKey?.scopes;
|
|
110961
111093
|
const safeApiKeyId = apiKeyId && /^[A-Za-z0-9_-]{1,256}$/.test(apiKeyId) ? apiKeyId : undefined;
|
|
110962
|
-
const safeApiKeyScopes = Array.isArray(apiKeyScopes) && apiKeyScopes.length <= 32 && apiKeyScopes.every((scope) => typeof scope === "string" && scope.length <= 128 && /^(?:\*|[a-z][a-z0-9_-]*:(?:\*|[a-z][a-z0-9_-]*))$/.test(scope)) ? [...
|
|
111094
|
+
const safeApiKeyScopes = Array.isArray(apiKeyScopes) && apiKeyScopes.length <= 32 && apiKeyScopes.every((scope) => typeof scope === "string" && scope.length <= 128 && /^(?:\*|[a-z][a-z0-9_-]*:(?:\*|[a-z][a-z0-9_-]*))$/.test(scope)) ? [...apiKeyScopes] : undefined;
|
|
110963
111095
|
return {
|
|
110964
111096
|
status: "authenticated",
|
|
110965
111097
|
authSource,
|
|
@@ -111427,8 +111559,10 @@ function registerAuth(parent) {
|
|
|
111427
111559
|
access = await new RemoteSkillsClient(fleet.apiKey, fleet.apiOrigin).getCapabilities();
|
|
111428
111560
|
} catch {}
|
|
111429
111561
|
payload.permissions = { publish: access?.permissions?.publish ?? null, profilesWrite: access?.permissions?.profilesWrite ?? null };
|
|
111430
|
-
|
|
111562
|
+
const apiKey = identityApiKey(res);
|
|
111563
|
+
if (access?.scopes && (apiKey === undefined || isRecord7(apiKey) && !Object.hasOwn(apiKey, "scopes"))) {
|
|
111431
111564
|
payload.scopes = access.scopes;
|
|
111565
|
+
}
|
|
111432
111566
|
if (options.json) {
|
|
111433
111567
|
console.log(JSON.stringify(payload, null, 2));
|
|
111434
111568
|
} else {
|