@hasna/skills 0.9.13 → 0.9.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/index.js +271 -215
- package/bin/mcp.js +26 -14
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +88 -27
- package/dist/lib/agent-codex-trust.d.ts +2 -1
- package/dist/lib/agent-integration.d.ts +9 -1
- package/dist/lib/claude-settings-witness.d.ts +5 -1
- package/dist/lib/codex-hook-additions-review.d.ts +22 -1
- package/dist/lib/codex-hook-discovery-recovery.d.ts +2 -1
- package/dist/sdk/index.js +107 -49
- package/docs/plugin-admission.md +27 -3
- 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.15",
|
|
36872
36872
|
description: "Skills library for AI coding agents",
|
|
36873
36873
|
type: "module",
|
|
36874
36874
|
bin: {
|
|
@@ -50548,7 +50548,7 @@ function canonical2(value) {
|
|
|
50548
50548
|
function inferencePreference(key, child) {
|
|
50549
50549
|
if (key === "skipDangerousModePermissionPrompt") {
|
|
50550
50550
|
need2(child.kind === "literal" && (child.value === "true" || child.value === "false"), "contains an invalid dialog acknowledgment");
|
|
50551
|
-
return
|
|
50551
|
+
return false;
|
|
50552
50552
|
}
|
|
50553
50553
|
if (key === "effortLevel") {
|
|
50554
50554
|
need2(child.kind === "string" && PERSISTED_EFFORT_LEVELS.has(child.value), "contains an invalid persisted effort level");
|
|
@@ -51233,6 +51233,20 @@ function planAgentIntegration(options) {
|
|
|
51233
51233
|
recheckRootAliases(aliases);
|
|
51234
51234
|
return { dataDir: dataDir3, profileId, changes, nativeSkills, observedPolicy: { path: policyPath, before: previousPolicy }, discoveryBefore: discoveries, discoveryAfter, ...aliases.length ? { rootAliases: aliases } : {} };
|
|
51235
51235
|
}
|
|
51236
|
+
function verifyCoordinatedDiscovery(binding, home, aliases) {
|
|
51237
|
+
try {
|
|
51238
|
+
if (binding.method !== "automatic" && binding.method !== "reviewed")
|
|
51239
|
+
throw new Error("Invalid managed discovery method");
|
|
51240
|
+
verifyAgentDiscovery(binding);
|
|
51241
|
+
if (binding.method === "automatic") {
|
|
51242
|
+
const current = resolveAgentDiscovery({ home, agent: binding.agent, canonical: (path) => canonicalAgentPath(path, aliases) });
|
|
51243
|
+
if (JSON.stringify(current) !== JSON.stringify(binding))
|
|
51244
|
+
throw new Error("Configured native discovery roots changed during Claude update");
|
|
51245
|
+
}
|
|
51246
|
+
} catch (error) {
|
|
51247
|
+
throw new Error(`NATIVE_SKILL_DRIFT: ${error.message}`);
|
|
51248
|
+
}
|
|
51249
|
+
}
|
|
51236
51250
|
function atomicWrite2(path, content) {
|
|
51237
51251
|
assertSafePath(path);
|
|
51238
51252
|
mkdirSync5(dirname10(path), { recursive: true, mode: 448 });
|
|
@@ -51257,8 +51271,12 @@ function applyAgentIntegration(plan) {
|
|
|
51257
51271
|
recheckRootAliases(aliases);
|
|
51258
51272
|
for (const agent of plan.managedAgentChecks?.agents ?? [])
|
|
51259
51273
|
assertManagedAgentBridge(agent, { home: plan.managedAgentChecks.home, dataDir: plan.dataDir, projectDir: plan.managedAgentChecks.home });
|
|
51260
|
-
for (const binding of plan.discoveryBefore ?? [])
|
|
51261
|
-
|
|
51274
|
+
for (const binding of plan.discoveryBefore ?? []) {
|
|
51275
|
+
if (plan.managedAgentChecks)
|
|
51276
|
+
verifyCoordinatedDiscovery(binding, plan.managedAgentChecks.home, aliases);
|
|
51277
|
+
else
|
|
51278
|
+
verifyAgentDiscovery(binding);
|
|
51279
|
+
}
|
|
51262
51280
|
if (plan.observedPolicy && currentText(plan.observedPolicy.path) !== plan.observedPolicy.before)
|
|
51263
51281
|
throw new Error("Agent policy changed after planning");
|
|
51264
51282
|
for (const change of plan.changes)
|
|
@@ -51290,8 +51308,12 @@ function applyAgentIntegration(plan) {
|
|
|
51290
51308
|
written.push({ path: change.path, before: change.before, after: after2 });
|
|
51291
51309
|
}
|
|
51292
51310
|
recheckRootAliases(aliases);
|
|
51293
|
-
for (const binding of plan.discoveryAfter ?? [])
|
|
51294
|
-
|
|
51311
|
+
for (const binding of plan.discoveryAfter ?? []) {
|
|
51312
|
+
if (plan.managedAgentChecks)
|
|
51313
|
+
verifyCoordinatedDiscovery(binding, plan.managedAgentChecks.home, aliases);
|
|
51314
|
+
else
|
|
51315
|
+
verifyAgentDiscovery(binding);
|
|
51316
|
+
}
|
|
51295
51317
|
for (const agent of plan.managedAgentChecks?.agents ?? [])
|
|
51296
51318
|
assertManagedAgentBridge(agent, { home: plan.managedAgentChecks.home, dataDir: plan.dataDir, projectDir: plan.managedAgentChecks.home });
|
|
51297
51319
|
atomicWrite2(join20(backupRoot, "receipt.json"), JSON.stringify({ version: 1, changes: written.map((change) => ({ path: change.path, beforeHash: change.before === null ? null : sha(change.before), afterHash: sha(change.after) })), backups, ...aliases.length ? { rootAliases: aliases } : {} }) + `
|
|
@@ -54674,39 +54696,132 @@ var fail2 = () => new Error('CODEX_HOOK_TRUST_UNSUPPORTED_LAYOUT: preserve and c
|
|
|
54674
54696
|
};
|
|
54675
54697
|
var init_codex_hook_trust_layout = () => {};
|
|
54676
54698
|
|
|
54699
|
+
// src/lib/codex-hook-additions-review.ts
|
|
54700
|
+
import { isAbsolute as isAbsolute14 } from "path";
|
|
54701
|
+
import { isDeepStrictEqual as isDeepStrictEqual5 } from "util";
|
|
54702
|
+
function exactKeys2(value, keys2) {
|
|
54703
|
+
need4(value && typeof value === "object" && !Array.isArray(value) && isDeepStrictEqual5(Object.keys(value).sort(), [...keys2].sort()), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
|
|
54704
|
+
}
|
|
54705
|
+
function readReviewedAdditionTrustStates(proof, before2, current, journalHooks) {
|
|
54706
|
+
const captured = proofs.get(proof);
|
|
54707
|
+
need4(!!captured && captured.before.file === before2.file && captured.before.sha256 === before2.sha256 && captured.current.file === current.file && captured.current.sha256 === current.sha256 && isDeepStrictEqual5(captured.journalHooks, journalHooks.map(({ key, currentHash }) => ({ key, currentHash }))), "RECONCILE_ADDITIONS_PROOF_CHANGED");
|
|
54708
|
+
captured.recheck();
|
|
54709
|
+
unchanged2(before2);
|
|
54710
|
+
unchanged2(current);
|
|
54711
|
+
return captured.states;
|
|
54712
|
+
}
|
|
54713
|
+
function reviewNativeHookAdditions(options) {
|
|
54714
|
+
need4(isAbsolute14(options.path), "RECONCILE_ADDITIONS_REVIEW_PATH");
|
|
54715
|
+
const reviewFile = snapshot(options.path, true), review = JSON.parse(reviewFile.text);
|
|
54716
|
+
exactKeys2(review, ["version", "kind", "reason", "producerEvidence", "journalIntentSha256", "policySha256", "configCurrentSha256", "hooksCurrentSha256", "producerBefore", "additions"]);
|
|
54717
|
+
need4((review.version === 1 || review.version === 2) && review.kind === "native-hook-additions" && text2(review.reason) && text2(review.producerEvidence), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
|
|
54718
|
+
for (const [name, expected] of [["journalIntentSha256", options.intent.sha256], ["policySha256", options.policy.sha256], ["configCurrentSha256", options.configCurrent.sha256], ["hooksCurrentSha256", options.hooksCurrent.sha256]])
|
|
54719
|
+
need4(hash2(review[name]) && review[name] === expected, "RECONCILE_ADDITIONS_REVIEW_CHANGED");
|
|
54720
|
+
exactKeys2(review.producerBefore, ["configPath", "configSha256", "hooksPath", "hooksSha256"]);
|
|
54721
|
+
const before2 = review.producerBefore;
|
|
54722
|
+
need4(isAbsolute14(before2.configPath) && isAbsolute14(before2.hooksPath) && hash2(before2.configSha256) && hash2(before2.hooksSha256), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
|
|
54723
|
+
const producerConfig = snapshot(before2.configPath, true), producerHooks = snapshot(before2.hooksPath, true);
|
|
54724
|
+
need4(producerConfig.sha256 === before2.configSha256 && producerHooks.sha256 === before2.hooksSha256 && producerHooks.sha256 === options.hooksBefore.sha256, "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
|
|
54725
|
+
const original = structure(options.configBefore.text), producer = structure(producerConfig.text), expectedProducer = structuredClone(original), originalKeys = options.journalHooks.map((hook) => hook.key);
|
|
54726
|
+
expectedProducer.hooks ??= {};
|
|
54727
|
+
expectedProducer.hooks.state ??= {};
|
|
54728
|
+
for (const hook of options.journalHooks)
|
|
54729
|
+
expectedProducer.hooks.state[hook.key] = { ...expectedProducer.hooks.state[hook.key], enabled: true, trusted_hash: hook.currentHash };
|
|
54730
|
+
need4(isDeepStrictEqual5(expectedProducer, producer) && codexTrustReconcileWitness(options.configBefore.text, originalKeys) === codexTrustReconcileWitness(producerConfig.text, originalKeys) && codexTrustUnmanagedSemantic(options.configBefore.text, originalKeys) === codexTrustUnmanagedSemantic(producerConfig.text, originalKeys), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
|
|
54731
|
+
need4(Array.isArray(review.additions) && review.additions.length > 0 && review.additions.length <= 20, "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
|
|
54732
|
+
const expectedHooks = JSON.parse(options.hooksBefore.text), currentHooks = JSON.parse(options.hooksCurrent.text), expectedConfig = structuredClone(producer);
|
|
54733
|
+
need4(expectedHooks.hooks && typeof expectedHooks.hooks === "object" && !Array.isArray(expectedHooks.hooks), "RECONCILE_ADDITIONS_DECLARATIONS");
|
|
54734
|
+
const added = [], states = [], seen = new Set, commands = new Set(options.recordedNativeHooks.map((hook) => hook.command));
|
|
54735
|
+
for (const addition of review.additions) {
|
|
54736
|
+
exactKeys2(addition, review.version === 1 ? ["event", "nativeHook"] : ["event", "nativeHook", "trustState"]);
|
|
54737
|
+
need4(Object.hasOwn(review.version === 1 ? events : matchedEvents, addition.event), "RECONCILE_ADDITIONS_DECLARATIONS");
|
|
54738
|
+
const { event, nativeHook: hook } = addition;
|
|
54739
|
+
exactKeys2(hook, nativeKeys);
|
|
54740
|
+
const groups = expectedHooks.hooks[event] ?? [];
|
|
54741
|
+
need4(Array.isArray(groups), "RECONCILE_ADDITIONS_DECLARATIONS");
|
|
54742
|
+
const key = `${options.nativeHooksPath}:${matchedEvents[event][1]}:${groups.length}:0`;
|
|
54743
|
+
need4(hook.key === key && !seen.has(key) && !options.recordedNativeHooks.some((originalHook) => originalHook.key === key) && !Object.hasOwn(expectedConfig.hooks.state, key), "RECONCILE_ADDITIONS_IDENTITY");
|
|
54744
|
+
need4(hook.eventName === matchedEvents[event][0] && hook.handlerType === "command" && text2(hook.command, 16384) && !commands.has(hook.command) && Number.isInteger(hook.timeoutSec) && hook.timeoutSec > 0 && hook.timeoutSec <= 60 && (event === "PreToolUse" ? text2(hook.matcher) : hook.matcher === null) && hook.async === false && hook.statusMessage === null && hook.additionalContextLimit === null && hook.sourcePath === options.nativeHooksPath && hook.source === "user" && hook.pluginId === null && hook.isManaged === false && /^sha256:[a-f0-9]{64}$/.test(hook.currentHash) && hook.enabled === true && hook.trustStatus === "trusted", "RECONCILE_ADDITIONS_IDENTITY");
|
|
54745
|
+
let trustState = { enabled: true, trusted_hash: hook.currentHash };
|
|
54746
|
+
if (review.version === 2) {
|
|
54747
|
+
const state = addition.trustState;
|
|
54748
|
+
exactKeys2(state, state && Object.hasOwn(state, "enabled") ? ["enabled", "trusted_hash"] : ["trusted_hash"]);
|
|
54749
|
+
need4(state.trusted_hash === hook.currentHash && (!Object.hasOwn(state, "enabled") || state.enabled === true), "RECONCILE_ADDITIONS_TRUST_STATE");
|
|
54750
|
+
trustState = { ...state };
|
|
54751
|
+
}
|
|
54752
|
+
seen.add(key);
|
|
54753
|
+
commands.add(hook.command);
|
|
54754
|
+
added.push(hook);
|
|
54755
|
+
states.push(Object.freeze({ key, state: Object.freeze(trustState) }));
|
|
54756
|
+
expectedHooks.hooks[event] = [...groups, { ...event === "PreToolUse" ? { matcher: hook.matcher } : {}, hooks: [{ type: "command", command: hook.command, timeout: hook.timeoutSec }] }];
|
|
54757
|
+
expectedConfig.hooks.state[key] = trustState;
|
|
54758
|
+
}
|
|
54759
|
+
need4(isDeepStrictEqual5(expectedHooks, currentHooks), "RECONCILE_ADDITIONS_DECLARATIONS");
|
|
54760
|
+
const keys2 = added.map((hook) => hook.key);
|
|
54761
|
+
need4(isDeepStrictEqual5(expectedConfig, structure(options.configCurrent.text)) && codexTrustReconcileWitness(producerConfig.text, keys2) === codexTrustReconcileWitness(options.configCurrent.text, keys2) && codexTrustUnmanagedSemantic(producerConfig.text, keys2) === codexTrustUnmanagedSemantic(options.configCurrent.text, keys2), "RECONCILE_ADDITIONS_CONFIG");
|
|
54762
|
+
const inputs = [reviewFile, producerConfig, producerHooks, options.intent, options.policy, options.configBefore, options.configCurrent, options.hooksBefore, options.hooksCurrent];
|
|
54763
|
+
const recheck = () => {
|
|
54764
|
+
for (const input of inputs)
|
|
54765
|
+
unchanged2(input);
|
|
54766
|
+
};
|
|
54767
|
+
recheck();
|
|
54768
|
+
const trustProof = Object.freeze({ reviewSha256: reviewFile.sha256 });
|
|
54769
|
+
proofs.set(trustProof, { before: options.configBefore, current: options.configCurrent, journalHooks: options.journalHooks.map(({ key, currentHash }) => ({ key, currentHash })), states: Object.freeze(states), recheck });
|
|
54770
|
+
return { hooks: added, recheck, trustProof, receipt: { ...review.version === 2 ? { version: 2 } : {}, reviewPath: reviewFile.file, reviewSha256: reviewFile.sha256, reason: review.reason, producerEvidence: review.producerEvidence, producerBefore: { configPath: producerConfig.file, configSha256: producerConfig.sha256, hooksPath: producerHooks.file, hooksSha256: producerHooks.sha256 }, additions: review.version === 1 ? added : review.additions } };
|
|
54771
|
+
}
|
|
54772
|
+
var events, matchedEvents, hash2 = (value) => typeof value === "string" && /^[a-f0-9]{64}$/.test(value), text2 = (value, max2 = 2048) => typeof value === "string" && value.trim().length > 0 && value.length <= max2 && !/[\0\r\n]/.test(value), structure = (value) => JSON.parse(JSON.stringify(Bun.TOML.parse(value))), nativeKeys, proofs;
|
|
54773
|
+
var init_codex_hook_additions_review = __esm(() => {
|
|
54774
|
+
init_codex_hook_trust_files();
|
|
54775
|
+
init_codex_hook_trust_layout();
|
|
54776
|
+
events = { UserPromptSubmit: ["userPromptSubmit", "user_prompt_submit"], SessionStart: ["sessionStart", "session_start"], SubagentStart: ["subagentStart", "subagent_start"] };
|
|
54777
|
+
matchedEvents = { ...events, PreToolUse: ["preToolUse", "pre_tool_use"] };
|
|
54778
|
+
nativeKeys = ["key", "eventName", "handlerType", "command", "matcher", "timeoutSec", "async", "statusMessage", "additionalContextLimit", "sourcePath", "source", "pluginId", "isManaged", "currentHash", "enabled", "trustStatus"];
|
|
54779
|
+
proofs = new WeakMap;
|
|
54780
|
+
});
|
|
54781
|
+
|
|
54677
54782
|
// src/lib/codex-hook-discovery-recovery.ts
|
|
54678
54783
|
import { createHash as createHash15 } from "crypto";
|
|
54679
|
-
import { isDeepStrictEqual as
|
|
54680
|
-
function createCodexHookDiscoveryRecovery(binding, before2, current, hooks) {
|
|
54784
|
+
import { isDeepStrictEqual as isDeepStrictEqual6 } from "util";
|
|
54785
|
+
function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, additions) {
|
|
54786
|
+
const journalHooks = hooks.map(({ key, currentHash }) => ({ key, currentHash }));
|
|
54787
|
+
const additionStates = additions ? readReviewedAdditionTrustStates(additions, before2, current, journalHooks) : [];
|
|
54788
|
+
const recheckAdditions = () => {
|
|
54789
|
+
if (additions)
|
|
54790
|
+
readReviewedAdditionTrustStates(additions, before2, current, journalHooks);
|
|
54791
|
+
};
|
|
54681
54792
|
const raw = binding.sources.filter((source) => source.path === current.file && source.hashMode === "bytes");
|
|
54682
54793
|
if (!raw.some((source) => source.sha256 !== current.sha256))
|
|
54683
54794
|
return;
|
|
54684
54795
|
need4(binding.agent === "codex" && binding.method === "reviewed" && raw.length === 1 && raw[0].sha256 === before2.sha256 && before2.sha256 !== current.sha256, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
|
|
54685
54796
|
need4(raw[0].format === undefined && raw[0].fields === undefined && raw[0].managedPlugins === undefined, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
|
|
54686
54797
|
const typed = binding.sources.filter((source) => source.path === current.file && source.format === "toml");
|
|
54687
|
-
need4(typed.length === 1 && typed[0].hashMode === undefined &&
|
|
54688
|
-
const original =
|
|
54798
|
+
need4(typed.length === 1 && typed[0].hashMode === undefined && isDeepStrictEqual6(typed[0].fields, fields), "RECONCILE_DISCOVERY_TYPED_WITNESS");
|
|
54799
|
+
const original = structure2(before2.text), actual = structure2(current.text);
|
|
54689
54800
|
const project = (value) => Object.fromEntries(fields.map((field2) => [field2, value[field2] ?? null]));
|
|
54690
54801
|
const projection = sha2(JSON.stringify(project(original)));
|
|
54691
|
-
need4(typed[0].sha256 === projection && sha2(JSON.stringify(project(actual))) === projection &&
|
|
54692
|
-
|
|
54693
|
-
|
|
54802
|
+
need4(typed[0].sha256 === projection && sha2(JSON.stringify(project(actual))) === projection && isDeepStrictEqual6(project(original), project(actual)), "RECONCILE_DISCOVERY_TYPED_WITNESS");
|
|
54803
|
+
const keys2 = [...journalHooks.map((hook) => hook.key), ...additionStates.map((hook) => hook.key)];
|
|
54804
|
+
need4(journalHooks.length > 0 && keys2.length <= 100 && new Set(keys2).size === keys2.length && journalHooks.every((hook) => typeof hook.key === "string" && /^sha256:[a-f0-9]{64}$/.test(hook.currentHash)), "RECONCILE_DISCOVERY_TRUST_WITNESS");
|
|
54805
|
+
const expected = structuredClone(original);
|
|
54694
54806
|
expected.hooks ??= {};
|
|
54695
54807
|
expected.hooks.state ??= {};
|
|
54696
|
-
for (const hook of
|
|
54808
|
+
for (const hook of journalHooks)
|
|
54697
54809
|
expected.hooks.state[hook.key] = { ...expected.hooks.state[hook.key], enabled: true, trusted_hash: hook.currentHash };
|
|
54698
|
-
|
|
54810
|
+
for (const { key, state } of additionStates)
|
|
54811
|
+
expected.hooks.state[key] = { ...state };
|
|
54812
|
+
need4(isDeepStrictEqual6(expected, actual) && codexTrustReconcileWitness(before2.text, keys2) === codexTrustReconcileWitness(current.text, keys2) && codexTrustUnmanagedSemantic(before2.text, keys2) === codexTrustUnmanagedSemantic(current.text, keys2), "RECONCILE_DISCOVERY_TRUST_WITNESS");
|
|
54699
54813
|
unchanged2(before2);
|
|
54700
54814
|
unchanged2(current);
|
|
54701
54815
|
const witness = Object.freeze({ configPath: current.file, beforeSha256: before2.sha256, currentSha256: current.sha256, discoverySha256: sha2(JSON.stringify(binding)), typedProjectionSha256: projection });
|
|
54702
|
-
|
|
54816
|
+
proofs2.set(witness, { before: before2, current, recheckAdditions });
|
|
54703
54817
|
return witness;
|
|
54704
54818
|
}
|
|
54705
54819
|
function assertCodexHookDiscoveryRecovery(binding, witness) {
|
|
54706
|
-
const proof =
|
|
54820
|
+
const proof = proofs2.get(witness);
|
|
54707
54821
|
need4(!!proof && binding.agent === "codex" && witness.discoverySha256 === sha2(JSON.stringify(binding)), "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
|
|
54708
54822
|
unchanged2(proof.before);
|
|
54709
54823
|
unchanged2(proof.current);
|
|
54824
|
+
proof.recheckAdditions();
|
|
54710
54825
|
}
|
|
54711
54826
|
function verifiesCodexHookDiscoverySource(binding, source, currentDigest, witness) {
|
|
54712
54827
|
if (!witness || source.path !== witness.configPath || source.hashMode !== "bytes")
|
|
@@ -54715,21 +54830,22 @@ function verifiesCodexHookDiscoverySource(binding, source, currentDigest, witnes
|
|
|
54715
54830
|
need4(source.sha256 === witness.beforeSha256 && currentDigest === witness.currentSha256, "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
|
|
54716
54831
|
return true;
|
|
54717
54832
|
}
|
|
54718
|
-
var sha2 = (
|
|
54833
|
+
var sha2 = (text3) => createHash15("sha256").update(text3).digest("hex"), fields, structure2 = (text3) => JSON.parse(JSON.stringify(Bun.TOML.parse(text3))), proofs2;
|
|
54719
54834
|
var init_codex_hook_discovery_recovery = __esm(() => {
|
|
54720
54835
|
init_codex_hook_trust_files();
|
|
54721
54836
|
init_codex_hook_trust_layout();
|
|
54837
|
+
init_codex_hook_additions_review();
|
|
54722
54838
|
fields = ["plugins", "marketplaces", "skills"];
|
|
54723
|
-
|
|
54839
|
+
proofs2 = new WeakMap;
|
|
54724
54840
|
});
|
|
54725
54841
|
|
|
54726
54842
|
// src/lib/agent-discovery.ts
|
|
54727
54843
|
import { createHash as createHash16 } from "crypto";
|
|
54728
54844
|
import { lstatSync as lstatSync20, readFileSync as readFileSync17, readdirSync as readdirSync10, realpathSync as realpathSync4 } from "fs";
|
|
54729
|
-
import { basename as basename8, dirname as dirname16, isAbsolute as
|
|
54730
|
-
function parseConfig(
|
|
54845
|
+
import { basename as basename8, dirname as dirname16, isAbsolute as isAbsolute15, join as join31, resolve as resolve15, sep as sep5 } from "path";
|
|
54846
|
+
function parseConfig(text3, path, toml = false) {
|
|
54731
54847
|
try {
|
|
54732
|
-
const value = toml ? Bun.TOML.parse(
|
|
54848
|
+
const value = toml ? Bun.TOML.parse(text3) : JSON.parse(text3);
|
|
54733
54849
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
54734
54850
|
throw new Error;
|
|
54735
54851
|
return value;
|
|
@@ -54738,7 +54854,7 @@ function parseConfig(text2, path, toml = false) {
|
|
|
54738
54854
|
}
|
|
54739
54855
|
}
|
|
54740
54856
|
function safe4(path) {
|
|
54741
|
-
if (!
|
|
54857
|
+
if (!isAbsolute15(path) || path.includes("\x00"))
|
|
54742
54858
|
throw new Error("Expected an absolute native discovery path");
|
|
54743
54859
|
for (let cursor = path;; cursor = dirname16(cursor)) {
|
|
54744
54860
|
if (lstatSync20(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
@@ -54791,12 +54907,12 @@ function projected(source, changes, budget = discoveryByteBudget()) {
|
|
|
54791
54907
|
return hashDiscoveryPathFile(source.path, budget, changes);
|
|
54792
54908
|
return hashRawDiscoveryFile(source.path, budget, changes);
|
|
54793
54909
|
}
|
|
54794
|
-
const
|
|
54795
|
-
if (
|
|
54910
|
+
const text3 = read2(source.path, changes);
|
|
54911
|
+
if (text3 === null)
|
|
54796
54912
|
return null;
|
|
54797
54913
|
if (!source.format)
|
|
54798
|
-
return digest(
|
|
54799
|
-
const object4 = source.format === "yaml" ? parseHermesConfig(
|
|
54914
|
+
return digest(text3);
|
|
54915
|
+
const object4 = source.format === "yaml" ? parseHermesConfig(text3) : parseConfig(text3, source.path, source.format === "toml");
|
|
54800
54916
|
if (!object4 || typeof object4 !== "object" || Array.isArray(object4))
|
|
54801
54917
|
throw new Error("Expected native discovery configuration object");
|
|
54802
54918
|
return digest(JSON.stringify(Object.fromEntries((source.fields ?? []).map((field2) => [field2, object4[field2] ?? null]))));
|
|
@@ -54940,8 +55056,8 @@ function resolveAgentDiscovery(options) {
|
|
|
54940
55056
|
if (!lstatSync20(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
|
|
54941
55057
|
unresolved("installed Gemini builtin root is missing");
|
|
54942
55058
|
for (const name of readdirSync10(builtinRoot).sort()) {
|
|
54943
|
-
const
|
|
54944
|
-
const match =
|
|
55059
|
+
const text3 = witness(join31(builtinRoot, name, "SKILL.md"));
|
|
55060
|
+
const match = text3?.match(/^---\r?\n[\s\S]*?^name:\s*([a-z0-9][a-z0-9-]*)\s*$/m);
|
|
54945
55061
|
if (!match?.[1] || builtinNames.includes(match[1]))
|
|
54946
55062
|
unresolved("installed Gemini builtin name is missing or ambiguous");
|
|
54947
55063
|
builtinNames.push(match[1]);
|
|
@@ -55019,7 +55135,7 @@ function resolveAgentDiscovery(options) {
|
|
|
55019
55135
|
unresolved("unsupported plugin enablement");
|
|
55020
55136
|
const split2 = id.lastIndexOf("@"), name = id.slice(0, split2), marketplace = id.slice(split2 + 1);
|
|
55021
55137
|
const market = config.marketplaces?.[marketplace] ?? (marketplace === "personal" ? { source_type: "local", source: home } : undefined);
|
|
55022
|
-
if (split2 < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !
|
|
55138
|
+
if (split2 < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !isAbsolute15(market.source))
|
|
55023
55139
|
unresolved("enabled plugin marketplace is not an explicit local source");
|
|
55024
55140
|
const catalogText = witness(join31(market.source, ".agents/plugins/marketplace.json"));
|
|
55025
55141
|
if (catalogText === null)
|
|
@@ -55035,7 +55151,7 @@ function resolveAgentDiscovery(options) {
|
|
|
55035
55151
|
if ((config.plugin?.length ?? 0) > 0 || config.skills?.urls?.length)
|
|
55036
55152
|
unresolved("external plugin or remote skill source");
|
|
55037
55153
|
for (const path of config.skills?.paths ?? []) {
|
|
55038
|
-
if (typeof path !== "string" || !
|
|
55154
|
+
if (typeof path !== "string" || !isAbsolute15(path))
|
|
55039
55155
|
unresolved("relative or malformed added skill root");
|
|
55040
55156
|
roots.add(path);
|
|
55041
55157
|
}
|
|
@@ -55073,7 +55189,7 @@ function resolveAgentDiscovery(options) {
|
|
|
55073
55189
|
}
|
|
55074
55190
|
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join31(home, ".hermes/plugins"), join31(home, ".hermes/hermes-agent")].map((path) => canonical4(path))) } : {} };
|
|
55075
55191
|
}
|
|
55076
|
-
var digest = (
|
|
55192
|
+
var digest = (text3) => createHash16("sha256").update(text3).digest("hex");
|
|
55077
55193
|
var init_agent_discovery = __esm(() => {
|
|
55078
55194
|
init_agent_policy_limits();
|
|
55079
55195
|
init_agent_hermes();
|
|
@@ -55205,7 +55321,7 @@ import {
|
|
|
55205
55321
|
statSync as statSync10,
|
|
55206
55322
|
writeFileSync as writeFileSync9
|
|
55207
55323
|
} from "fs";
|
|
55208
|
-
import { basename as basename10, dirname as dirname18, isAbsolute as
|
|
55324
|
+
import { basename as basename10, dirname as dirname18, isAbsolute as isAbsolute16, join as join33, normalize as normalize2, relative as relative5, resolve as resolve17, sep as sep7 } from "path";
|
|
55209
55325
|
function getPortableSkillsRoot(options = {}) {
|
|
55210
55326
|
return resolvePortableSkillsRoot(options, true);
|
|
55211
55327
|
}
|
|
@@ -55363,7 +55479,7 @@ function assertDisjointImportPaths(source, destination) {
|
|
|
55363
55479
|
const destinationPath = physicalImportPath(destination);
|
|
55364
55480
|
const contains2 = (parent, child) => {
|
|
55365
55481
|
const path = relative5(parent, child);
|
|
55366
|
-
return path === "" || !
|
|
55482
|
+
return path === "" || !isAbsolute16(path) && path !== ".." && !path.startsWith(`..${sep7}`);
|
|
55367
55483
|
};
|
|
55368
55484
|
if (contains2(sourcePath, destinationPath) || contains2(destinationPath, sourcePath)) {
|
|
55369
55485
|
throw new Error("Source and destination skill directories must not overlap");
|
|
@@ -55580,7 +55696,7 @@ function safeIsDirectory(path) {
|
|
|
55580
55696
|
}
|
|
55581
55697
|
}
|
|
55582
55698
|
function isSafeRelativePath2(value) {
|
|
55583
|
-
if (!value.trim() ||
|
|
55699
|
+
if (!value.trim() || isAbsolute16(value))
|
|
55584
55700
|
return false;
|
|
55585
55701
|
const normalized = normalize2(value).replace(/\\/g, "/");
|
|
55586
55702
|
return normalized !== ".." && !normalized.startsWith("../") && !normalized.includes("/../");
|
|
@@ -57604,8 +57720,8 @@ function getPublicSkillDiscovery(skill) {
|
|
|
57604
57720
|
function publicDiscoveryTags(tags) {
|
|
57605
57721
|
return tags.filter((tag) => !VENDOR_TAGS.has(tag.toLowerCase()));
|
|
57606
57722
|
}
|
|
57607
|
-
function sanitizePublicDiscoveryText(
|
|
57608
|
-
let sanitized =
|
|
57723
|
+
function sanitizePublicDiscoveryText(text3) {
|
|
57724
|
+
let sanitized = text3.replace(vendorPattern, "hosted AI").replace(/\bLLM\b/g, "AI").replace(/\s{2,}/g, " ");
|
|
57609
57725
|
let previous;
|
|
57610
57726
|
do {
|
|
57611
57727
|
previous = sanitized;
|
|
@@ -66225,8 +66341,8 @@ function lt_default() {
|
|
|
66225
66341
|
localeError: error33()
|
|
66226
66342
|
};
|
|
66227
66343
|
}
|
|
66228
|
-
var capitalizeFirstCharacter = (
|
|
66229
|
-
return
|
|
66344
|
+
var capitalizeFirstCharacter = (text3) => {
|
|
66345
|
+
return text3.charAt(0).toUpperCase() + text3.slice(1);
|
|
66230
66346
|
}, error33 = () => {
|
|
66231
66347
|
const Sizable = {
|
|
66232
66348
|
string: {
|
|
@@ -74059,7 +74175,7 @@ __export(exports_schemas2, {
|
|
|
74059
74175
|
httpUrl: () => httpUrl,
|
|
74060
74176
|
hostname: () => hostname2,
|
|
74061
74177
|
hex: () => hex2,
|
|
74062
|
-
hash: () =>
|
|
74178
|
+
hash: () => hash3,
|
|
74063
74179
|
guid: () => guid2,
|
|
74064
74180
|
function: () => _function,
|
|
74065
74181
|
float64: () => float64,
|
|
@@ -74265,7 +74381,7 @@ function hostname2(_params) {
|
|
|
74265
74381
|
function hex2(_params) {
|
|
74266
74382
|
return _stringFormat(ZodCustomStringFormat, "hex", exports_regexes.hex, _params);
|
|
74267
74383
|
}
|
|
74268
|
-
function
|
|
74384
|
+
function hash3(alg, params) {
|
|
74269
74385
|
const enc = params?.enc ?? "hex";
|
|
74270
74386
|
const format = `${alg}_${enc}`;
|
|
74271
74387
|
const regex2 = exports_regexes[format];
|
|
@@ -76525,7 +76641,7 @@ __export(exports_external, {
|
|
|
76525
76641
|
httpUrl: () => httpUrl,
|
|
76526
76642
|
hostname: () => hostname2,
|
|
76527
76643
|
hex: () => hex2,
|
|
76528
|
-
hash: () =>
|
|
76644
|
+
hash: () => hash3,
|
|
76529
76645
|
guid: () => guid2,
|
|
76530
76646
|
gte: () => _gte,
|
|
76531
76647
|
gt: () => _gt,
|
|
@@ -76760,8 +76876,8 @@ function safeAvailabilityCode(code) {
|
|
|
76760
76876
|
return;
|
|
76761
76877
|
return /^[A-Z0-9_]+$/.test(code) ? code : undefined;
|
|
76762
76878
|
}
|
|
76763
|
-
function sanitizeAvailabilityText(
|
|
76764
|
-
return secretValuePatterns.reduce((value, pattern) => value.replace(pattern, "credential"), sanitizePublicDiscoveryText(
|
|
76879
|
+
function sanitizeAvailabilityText(text3) {
|
|
76880
|
+
return secretValuePatterns.reduce((value, pattern) => value.replace(pattern, "credential"), sanitizePublicDiscoveryText(text3).replace(/\b[A-Z0-9_]*(?:API_KEY|SECRET|TOKEN|CREDENTIAL)[A-Z0-9_]*\b/g, "credential")).replace(/\s{2,}/g, " ").trim();
|
|
76765
76881
|
}
|
|
76766
76882
|
function parseRemoteRegistryPayload(payload) {
|
|
76767
76883
|
const parsed = parseRemoteContract(remoteRegistrySchema, payload, "Remote registry payload did not match the expected skills contract");
|
|
@@ -76966,11 +77082,11 @@ function canonicalJsonAtDepth(value, maximumBytes, maximumDepth) {
|
|
|
76966
77082
|
throw new Error("Invalid canonical JSON depth bound");
|
|
76967
77083
|
let bytes = 0;
|
|
76968
77084
|
const active = new Set;
|
|
76969
|
-
const piece = (
|
|
76970
|
-
bytes += Buffer.byteLength(
|
|
77085
|
+
const piece = (text3) => {
|
|
77086
|
+
bytes += Buffer.byteLength(text3);
|
|
76971
77087
|
if (bytes > maximumBytes)
|
|
76972
77088
|
throw new Error("Canonical JSON exceeds its bound");
|
|
76973
|
-
return
|
|
77089
|
+
return text3;
|
|
76974
77090
|
};
|
|
76975
77091
|
const visit3 = (v, depth) => {
|
|
76976
77092
|
if (depth > maximumDepth)
|
|
@@ -77109,9 +77225,9 @@ function requireResult(value) {
|
|
|
77109
77225
|
if (!value)
|
|
77110
77226
|
throw new RemoteRecurringReadError;
|
|
77111
77227
|
}
|
|
77112
|
-
function termsIntegrity(terms,
|
|
77228
|
+
function termsIntegrity(terms, hash4, identity4, own2) {
|
|
77113
77229
|
requireResult(terms.organizationId === identity4.organization.id && (!own2 || terms.approvedByUserId === identity4.user.id && terms.approvedMembershipId === identity4.user.membershipId));
|
|
77114
|
-
requireResult(canonicalJsonSha256(terms) ===
|
|
77230
|
+
requireResult(canonicalJsonSha256(terms) === hash4);
|
|
77115
77231
|
requireResult(canonicalJsonSha256({ skill: terms.skill, input: terms.input, args: terms.args, runtime: terms.runtime }) === terms.payloadSha256);
|
|
77116
77232
|
requireResult(Date.parse(terms.expiresAt) > Date.parse(terms.startsAt));
|
|
77117
77233
|
}
|
|
@@ -77507,7 +77623,7 @@ function invalid3() {
|
|
|
77507
77623
|
throw new Error(invalidWorkspaceResult);
|
|
77508
77624
|
}
|
|
77509
77625
|
function organization(v) {
|
|
77510
|
-
if (!record4(v) || !uuid8(v.id) || !
|
|
77626
|
+
if (!record4(v) || !uuid8(v.id) || !text3(v.slug) || !text3(v.name))
|
|
77511
77627
|
return invalid3();
|
|
77512
77628
|
return { id: v.id, slug: v.slug, name: v.name };
|
|
77513
77629
|
}
|
|
@@ -77527,7 +77643,7 @@ function parseWorkspaceIdentity(value, expectedUserId) {
|
|
|
77527
77643
|
if (!record4(value))
|
|
77528
77644
|
return invalid3();
|
|
77529
77645
|
const user = value.user;
|
|
77530
|
-
if (!record4(user) || !uuid8(user.id) || !uuid8(user.membershipId) || !
|
|
77646
|
+
if (!record4(user) || !uuid8(user.id) || !uuid8(user.membershipId) || !text3(user.email, 320) || !(user.displayName === null || text3(user.displayName)) || !role2(user.role))
|
|
77531
77647
|
return invalid3();
|
|
77532
77648
|
if (user.id !== expectedUserId)
|
|
77533
77649
|
throw new WorkspaceIdentityMismatchError;
|
|
@@ -77558,7 +77674,7 @@ function workspaceSelectionFailure(value, status) {
|
|
|
77558
77674
|
const code = value.code;
|
|
77559
77675
|
return workspaceSelectionFailures[code][0] === status ? code : null;
|
|
77560
77676
|
}
|
|
77561
|
-
var record4 = (v) => !!v && typeof v === "object" && !Array.isArray(v), uuid8 = (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),
|
|
77677
|
+
var record4 = (v) => !!v && typeof v === "object" && !Array.isArray(v), uuid8 = (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), text3 = (v, max2 = 1024) => typeof v === "string" && !!v.trim() && v.length <= max2 && !/[\p{Cc}\p{Cs}\u2028\u2029]/u.test(v), role2 = (v) => typeof v === "string" && ["owner", "admin", "member", "viewer"].includes(v), invalidWorkspaceResult = "The server returned an invalid workspace selection result.", WorkspaceContextInputError, WorkspaceIdentityMismatchError, workspaceSelectionFailures;
|
|
77562
77678
|
var init_remote_workspace_selection = __esm(() => {
|
|
77563
77679
|
WorkspaceContextInputError = class WorkspaceContextInputError extends Error {
|
|
77564
77680
|
constructor() {
|
|
@@ -80372,17 +80488,17 @@ var init_install = __esm(() => {
|
|
|
80372
80488
|
|
|
80373
80489
|
// src/lib/compact-output.ts
|
|
80374
80490
|
function truncateText(value, maxChars = 96) {
|
|
80375
|
-
const
|
|
80376
|
-
if (
|
|
80377
|
-
return
|
|
80378
|
-
return `${
|
|
80491
|
+
const text4 = String(value ?? "").replace(/\s+/g, " ").trim();
|
|
80492
|
+
if (text4.length <= maxChars)
|
|
80493
|
+
return text4;
|
|
80494
|
+
return `${text4.slice(0, Math.max(0, maxChars - 3)).trimEnd()}...`;
|
|
80379
80495
|
}
|
|
80380
80496
|
function previewText(value, maxChars = DEFAULT_PREVIEW_CHARS) {
|
|
80381
|
-
const
|
|
80497
|
+
const text4 = String(value ?? "");
|
|
80382
80498
|
return {
|
|
80383
|
-
text:
|
|
80384
|
-
length:
|
|
80385
|
-
truncated:
|
|
80499
|
+
text: text4.length > maxChars ? `${text4.slice(0, Math.max(0, maxChars - 3))}...` : text4,
|
|
80500
|
+
length: text4.length,
|
|
80501
|
+
truncated: text4.length > maxChars
|
|
80386
80502
|
};
|
|
80387
80503
|
}
|
|
80388
80504
|
function parsePageLimit(value, fallback, options = {}) {
|
|
@@ -80501,10 +80617,10 @@ function handleBrowseError(error61) {
|
|
|
80501
80617
|
process.exitCode = 1;
|
|
80502
80618
|
}
|
|
80503
80619
|
async function writeJson(value, space) {
|
|
80504
|
-
const
|
|
80620
|
+
const text4 = `${JSON.stringify(value, null, space)}
|
|
80505
80621
|
`;
|
|
80506
80622
|
await new Promise((resolve19, reject2) => {
|
|
80507
|
-
process.stdout.write(
|
|
80623
|
+
process.stdout.write(text4, (error61) => {
|
|
80508
80624
|
if (error61)
|
|
80509
80625
|
reject2(error61);
|
|
80510
80626
|
else
|
|
@@ -81063,7 +81179,7 @@ function handleDiff(name, options) {
|
|
|
81063
81179
|
const present = existsSync22(dir);
|
|
81064
81180
|
const managed = existsSync22(join37(dir, SYNC_MARKER_FILE));
|
|
81065
81181
|
const skillMdPath = join37(dir, "SKILL.md");
|
|
81066
|
-
const
|
|
81182
|
+
const hash4 = present && existsSync22(skillMdPath) ? hashSkillMarkdownFile(skillMdPath) : undefined;
|
|
81067
81183
|
let stub;
|
|
81068
81184
|
if (present && existsSync22(skillMdPath)) {
|
|
81069
81185
|
try {
|
|
@@ -81072,13 +81188,13 @@ function handleDiff(name, options) {
|
|
|
81072
81188
|
stub = undefined;
|
|
81073
81189
|
}
|
|
81074
81190
|
}
|
|
81075
|
-
const diverged = present && canonical4.present && managed &&
|
|
81191
|
+
const diverged = present && canonical4.present && managed && hash4 !== canonical4.hash;
|
|
81076
81192
|
homes.push({
|
|
81077
81193
|
agent,
|
|
81078
81194
|
path: dir,
|
|
81079
81195
|
present,
|
|
81080
81196
|
managed,
|
|
81081
|
-
...
|
|
81197
|
+
...hash4 ? { hash: hash4 } : {},
|
|
81082
81198
|
...stub !== undefined ? { stub } : {},
|
|
81083
81199
|
...diverged !== undefined ? { diverged } : {}
|
|
81084
81200
|
});
|
|
@@ -81934,13 +82050,13 @@ function scanUnmarkedHomes(options = {}) {
|
|
|
81934
82050
|
const skillMdPath = join39(dir, "SKILL.md");
|
|
81935
82051
|
if (!existsSync24(skillMdPath))
|
|
81936
82052
|
continue;
|
|
81937
|
-
const
|
|
82053
|
+
const hash4 = hashSkillMarkdownFile(skillMdPath);
|
|
81938
82054
|
const mtime = statSync12(skillMdPath).mtime.toISOString();
|
|
81939
|
-
const entry = { agent, skill, home, path: dir, hash:
|
|
82055
|
+
const entry = { agent, skill, home, path: dir, hash: hash4, mtime };
|
|
81940
82056
|
const canonicalHash = index.get(skill);
|
|
81941
82057
|
if (canonicalHash === undefined) {
|
|
81942
82058
|
scan.unknown.push({ ...entry });
|
|
81943
|
-
} else if (canonicalHash ===
|
|
82059
|
+
} else if (canonicalHash === hash4) {
|
|
81944
82060
|
scan.adoptable.push(entry);
|
|
81945
82061
|
} else {
|
|
81946
82062
|
scan.conflicts.push({ ...entry, canonicalHash });
|
|
@@ -82028,10 +82144,10 @@ function pruneOwnership(dir) {
|
|
|
82028
82144
|
const after2 = fstatSync15(descriptor), current = lstatSync22(dir), markerPathAfter = lstatSync22(markerPath);
|
|
82029
82145
|
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)
|
|
82030
82146
|
return;
|
|
82031
|
-
const
|
|
82147
|
+
const text4 = bytes.subarray(0, length).toString("utf8"), marker = JSON.parse(text4);
|
|
82032
82148
|
if (!isSkillsOwnershipMarker(marker))
|
|
82033
82149
|
return;
|
|
82034
|
-
return { marker, identity: JSON.stringify([directory.dev, directory.ino, before2.dev, before2.ino, before2.mtimeMs, before2.ctimeMs,
|
|
82150
|
+
return { marker, identity: JSON.stringify([directory.dev, directory.ino, before2.dev, before2.ino, before2.mtimeMs, before2.ctimeMs, text4]) };
|
|
82035
82151
|
} catch {
|
|
82036
82152
|
return;
|
|
82037
82153
|
} finally {
|
|
@@ -82077,15 +82193,15 @@ function pruneStrayHomes(options = {}) {
|
|
|
82077
82193
|
const marker = owned.marker;
|
|
82078
82194
|
ownership.set(dir, owned.identity);
|
|
82079
82195
|
const skillMdPath = join39(dir, "SKILL.md");
|
|
82080
|
-
const
|
|
82081
|
-
candidates.push({ agent, skill, home, path: dir, hash:
|
|
82196
|
+
const hash4 = existsSync24(skillMdPath) ? hashSkillMarkdownFile(skillMdPath) : "";
|
|
82197
|
+
candidates.push({ agent, skill, home, path: dir, hash: hash4, marker });
|
|
82082
82198
|
}
|
|
82083
82199
|
}
|
|
82084
82200
|
if (!options.apply) {
|
|
82085
82201
|
return { candidates, pruned: 0, dryRun: true };
|
|
82086
82202
|
}
|
|
82087
82203
|
const appDir = options.homeDir ? join39(options.homeDir, ".hasna", "skills") : getDataDir();
|
|
82088
|
-
const rollbackFile = writeRollbackRecord("prune", candidates.map(({ agent, skill, path, hash:
|
|
82204
|
+
const rollbackFile = writeRollbackRecord("prune", candidates.map(({ agent, skill, path, hash: hash4, marker }) => ({ agent, skill, path, hash: hash4, marker })), appDir);
|
|
82089
82205
|
let pruned = 0;
|
|
82090
82206
|
for (const candidate2 of candidates) {
|
|
82091
82207
|
if (pruneOwnership(candidate2.path)?.identity !== ownership.get(candidate2.path))
|
|
@@ -82316,10 +82432,10 @@ function setEnvAssignment(path, assignment) {
|
|
|
82316
82432
|
}
|
|
82317
82433
|
let prepared = initial2;
|
|
82318
82434
|
if (previous) {
|
|
82319
|
-
const original = readFileSync27(descriptor),
|
|
82320
|
-
if (!Buffer.from(
|
|
82435
|
+
const original = readFileSync27(descriptor), text4 = original.toString("utf8");
|
|
82436
|
+
if (!Buffer.from(text4, "utf8").equals(original))
|
|
82321
82437
|
throw new EnvAssignmentError(INVALID_LAYOUT);
|
|
82322
|
-
prepared = prepareEnvAssignment(assignment,
|
|
82438
|
+
prepared = prepareEnvAssignment(assignment, text4);
|
|
82323
82439
|
}
|
|
82324
82440
|
const bytes = Buffer.from(prepared.content, "utf8");
|
|
82325
82441
|
let written = 0;
|
|
@@ -82859,7 +82975,7 @@ import { closeSync as closeSync17, fstatSync as fstatSync17, openSync as openSyn
|
|
|
82859
82975
|
import { O_NOFOLLOW as O_NOFOLLOW3, O_NONBLOCK as O_NONBLOCK3, O_RDONLY as O_RDONLY3 } from "constants";
|
|
82860
82976
|
import { createRequire as createRequire2 } from "module";
|
|
82861
82977
|
import { hostname as osHostname2 } from "os";
|
|
82862
|
-
import { isAbsolute as
|
|
82978
|
+
import { isAbsolute as isAbsolute17, join as join42 } from "path";
|
|
82863
82979
|
import { createRequire as createRequire22 } from "module";
|
|
82864
82980
|
function envToken2(name) {
|
|
82865
82981
|
return name.toUpperCase().replace(/-/g, "_");
|
|
@@ -82883,7 +82999,7 @@ function homeDir2(env3) {
|
|
|
82883
82999
|
}
|
|
82884
83000
|
function absoluteOverride2(env3, key) {
|
|
82885
83001
|
const value = env3[key]?.trim();
|
|
82886
|
-
return value &&
|
|
83002
|
+
return value && isAbsolute17(value) ? value : null;
|
|
82887
83003
|
}
|
|
82888
83004
|
function hasnaHomeDir2(env3) {
|
|
82889
83005
|
const override = absoluteOverride2(env3, HASNA_HOME_ENV_KEY2);
|
|
@@ -82914,10 +83030,10 @@ function credentialDiskSources2(name, env3) {
|
|
|
82914
83030
|
function profileDiskSources2(name, env3, profile) {
|
|
82915
83031
|
return credentialDiskSourceList2(name, env3, profile).map((s) => s.path);
|
|
82916
83032
|
}
|
|
82917
|
-
function parseEnvFile2(
|
|
83033
|
+
function parseEnvFile2(text4) {
|
|
82918
83034
|
const values2 = new Map;
|
|
82919
83035
|
const unusable = new Set;
|
|
82920
|
-
for (const rawLine of
|
|
83036
|
+
for (const rawLine of text4.split(/\r?\n/)) {
|
|
82921
83037
|
const line = rawLine.trim();
|
|
82922
83038
|
if (line.length === 0 || line.startsWith("#"))
|
|
82923
83039
|
continue;
|
|
@@ -83157,8 +83273,8 @@ function keychainAccount2(env3, options) {
|
|
|
83157
83273
|
const user = env3.USER?.trim();
|
|
83158
83274
|
return user || null;
|
|
83159
83275
|
}
|
|
83160
|
-
function keychainFailureHint2(
|
|
83161
|
-
const line =
|
|
83276
|
+
function keychainFailureHint2(text4) {
|
|
83277
|
+
const line = text4.split(/\r?\n/).find((entry) => entry.trim().length > 0)?.trim() ?? "";
|
|
83162
83278
|
const clean = line.replace(/[\u0000-\u001f\u007f]/g, "").slice(0, 200);
|
|
83163
83279
|
return clean ? `: ${clean}` : "";
|
|
83164
83280
|
}
|
|
@@ -83736,12 +83852,12 @@ function createHasnaHttpTransportInternal(options, requestBindingProvider) {
|
|
|
83736
83852
|
await response.body?.cancel();
|
|
83737
83853
|
} catch {}
|
|
83738
83854
|
} else {
|
|
83739
|
-
const
|
|
83740
|
-
if (
|
|
83855
|
+
const text4 = await response.text();
|
|
83856
|
+
if (text4.length > 0) {
|
|
83741
83857
|
try {
|
|
83742
|
-
parsed = JSON.parse(
|
|
83858
|
+
parsed = JSON.parse(text4);
|
|
83743
83859
|
} catch {
|
|
83744
|
-
parsed =
|
|
83860
|
+
parsed = text4;
|
|
83745
83861
|
}
|
|
83746
83862
|
}
|
|
83747
83863
|
}
|
|
@@ -83844,13 +83960,13 @@ class SecretsClient {
|
|
|
83844
83960
|
headers,
|
|
83845
83961
|
redirect: "manual"
|
|
83846
83962
|
});
|
|
83847
|
-
const
|
|
83963
|
+
const text4 = await response.text();
|
|
83848
83964
|
let body = undefined;
|
|
83849
|
-
if (
|
|
83965
|
+
if (text4) {
|
|
83850
83966
|
try {
|
|
83851
|
-
body = JSON.parse(
|
|
83967
|
+
body = JSON.parse(text4);
|
|
83852
83968
|
} catch {
|
|
83853
|
-
body =
|
|
83969
|
+
body = text4;
|
|
83854
83970
|
}
|
|
83855
83971
|
}
|
|
83856
83972
|
if (!response.ok) {
|
|
@@ -84179,7 +84295,7 @@ function refuse(code, message) {
|
|
|
84179
84295
|
function record7(value) {
|
|
84180
84296
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
84181
84297
|
}
|
|
84182
|
-
function
|
|
84298
|
+
function exactKeys3(value, keys2) {
|
|
84183
84299
|
return Object.keys(value).length === keys2.length && keys2.every((key) => Object.hasOwn(value, key));
|
|
84184
84300
|
}
|
|
84185
84301
|
function identifier2(value) {
|
|
@@ -84219,7 +84335,7 @@ function readSelectedSecretBindings(path) {
|
|
|
84219
84335
|
}
|
|
84220
84336
|
}
|
|
84221
84337
|
function validateSelectedSecretBindings(value, scope, names) {
|
|
84222
|
-
if (!record7(value) || !
|
|
84338
|
+
if (!record7(value) || !exactKeys3(value, ["schema", "selection", "consumer", "secretsAuthority", "bindings"]) || value.schema !== "hasna.skills-secret-bindings.v1" || !record7(value.selection) || !exactKeys3(value.selection, ["authority", "workspaceId", "profileId", "profileRevision", "slug", "version", "bundleDigest"]) || !record7(value.consumer) || !exactKeys3(value.consumer, ["stationId", "workspaceDirectory"]) || !record7(value.bindings)) {
|
|
84223
84339
|
return refuse("INVALID_SECRET_BINDINGS", "Secret bindings do not match the hasna.skills-secret-bindings.v1 contract.");
|
|
84224
84340
|
}
|
|
84225
84341
|
for (const [key, expected] of Object.entries({ authority: scope.selection.authority, workspaceId: scope.selection.workspaceId, profileId: scope.profileId, profileRevision: scope.selection.profileRevision, slug: scope.selection.slug, version: scope.selection.version, bundleDigest: scope.selection.bundleDigest })) {
|
|
@@ -84244,7 +84360,7 @@ function validateSelectedSecretBindings(value, scope, names) {
|
|
|
84244
84360
|
} catch {
|
|
84245
84361
|
return refuse("INVALID_SECRET_BINDINGS", "Secret bindings require a canonical HTTPS Secrets /v1 authority (loopback HTTP is allowed).");
|
|
84246
84362
|
}
|
|
84247
|
-
if (!
|
|
84363
|
+
if (!exactKeys3(value.bindings, names) || Object.values(value.bindings).some((key) => !identifier2(key) || !/^[A-Za-z0-9][A-Za-z0-9._/-]*$/.test(key) || key.split("/").some((part) => !part || part === "." || part === ".."))) {
|
|
84248
84364
|
return refuse("INVALID_SECRET_BINDINGS", "Bind every declared environment name exactly once to a vault key; undeclared bindings and values are refused.");
|
|
84249
84365
|
}
|
|
84250
84366
|
return structuredClone(value);
|
|
@@ -84274,7 +84390,7 @@ async function resolveSelectedSecrets(bindings, createClient2 = createSecretsCli
|
|
|
84274
84390
|
return refuse("LOCAL_SECRET_UNAVAILABLE", "A declared secret could not be resolved, was invalid, or has expired. The skill was not started; no fallback was attempted.");
|
|
84275
84391
|
}
|
|
84276
84392
|
}
|
|
84277
|
-
function redactExecutionSecrets(
|
|
84393
|
+
function redactExecutionSecrets(text4, env3) {
|
|
84278
84394
|
const values2 = new Set(Object.values(env3).flatMap((value) => {
|
|
84279
84395
|
let encoded = "";
|
|
84280
84396
|
try {
|
|
@@ -84283,8 +84399,8 @@ function redactExecutionSecrets(text3, env3) {
|
|
|
84283
84399
|
return [value, JSON.stringify(value).slice(1, -1), Buffer.from(value).toString("base64"), encoded];
|
|
84284
84400
|
}));
|
|
84285
84401
|
for (const value of [...values2].filter(Boolean).sort((a, b) => b.length - a.length))
|
|
84286
|
-
|
|
84287
|
-
return
|
|
84402
|
+
text4 = text4.split(value).join("[REDACTED]");
|
|
84403
|
+
return text4;
|
|
84288
84404
|
}
|
|
84289
84405
|
var init_execution_secrets = __esm(() => {
|
|
84290
84406
|
init_sdk();
|
|
@@ -84422,7 +84538,7 @@ var init_execution_grants = __esm(() => {
|
|
|
84422
84538
|
});
|
|
84423
84539
|
|
|
84424
84540
|
// src/lib/execution-grant-client.ts
|
|
84425
|
-
import { isDeepStrictEqual as
|
|
84541
|
+
import { isDeepStrictEqual as isDeepStrictEqual7 } from "util";
|
|
84426
84542
|
function id(value) {
|
|
84427
84543
|
if (!grantIdentifier(value))
|
|
84428
84544
|
throw new Error("Invalid execution grant profile or revision identifier.");
|
|
@@ -84474,7 +84590,7 @@ async function saveExecutionGrantPolicy(profileId, grants, revision) {
|
|
|
84474
84590
|
headers: revision === undefined ? { "If-None-Match": "*" } : { "If-Match": `"${revision}"` },
|
|
84475
84591
|
body: JSON.stringify({ grants: snapshot2 })
|
|
84476
84592
|
}));
|
|
84477
|
-
if (policy.profileId !== profileId || policy.previousRevision !== (revision ?? null) || !
|
|
84593
|
+
if (policy.profileId !== profileId || policy.previousRevision !== (revision ?? null) || !isDeepStrictEqual7(policy.grants, snapshot2)) {
|
|
84478
84594
|
throw new Error("The API did not preserve the reviewed execution grant policy; read it before retrying.");
|
|
84479
84595
|
}
|
|
84480
84596
|
return policy;
|
|
@@ -84485,7 +84601,7 @@ async function resolveExecutionGrant(input2) {
|
|
|
84485
84601
|
if (!grantRecord(value) || Object.keys(value).length !== 3 || !grantIdentifier(value.policyRevision) || !grantIdentifier(value.grantId) || !grantRecord(value.bindings)) {
|
|
84486
84602
|
throw new SkillSelectionError("INVALID_EXECUTION_GRANT", "The Skills API returned an invalid execution grant.");
|
|
84487
84603
|
}
|
|
84488
|
-
if (!
|
|
84604
|
+
if (!isDeepStrictEqual7(value.bindings.selection, snapshot2.selection) || !isDeepStrictEqual7(value.bindings.consumer, snapshot2.consumer)) {
|
|
84489
84605
|
throw new SkillSelectionError("EXECUTION_GRANT_SCOPE_MISMATCH", "The Skills API returned a grant for a different selection or consumer.");
|
|
84490
84606
|
}
|
|
84491
84607
|
return value;
|
|
@@ -93580,10 +93696,10 @@ var require_util = __commonJS((exports) => {
|
|
|
93580
93696
|
var codegen_1 = require_codegen();
|
|
93581
93697
|
var code_1 = require_code();
|
|
93582
93698
|
function toHash(arr) {
|
|
93583
|
-
const
|
|
93699
|
+
const hash4 = {};
|
|
93584
93700
|
for (const item of arr)
|
|
93585
|
-
|
|
93586
|
-
return
|
|
93701
|
+
hash4[item] = true;
|
|
93702
|
+
return hash4;
|
|
93587
93703
|
}
|
|
93588
93704
|
exports.toHash = toHash;
|
|
93589
93705
|
function alwaysValidSchema(it, schema) {
|
|
@@ -97045,7 +97161,7 @@ var require_core = __commonJS((exports) => {
|
|
|
97045
97161
|
errorsText(errors5 = this.errors, { separator = ", ", dataVar = "data" } = {}) {
|
|
97046
97162
|
if (!errors5 || errors5.length === 0)
|
|
97047
97163
|
return "No errors";
|
|
97048
|
-
return errors5.map((e2) => `${dataVar}${e2.instancePath} ${e2.message}`).reduce((
|
|
97164
|
+
return errors5.map((e2) => `${dataVar}${e2.instancePath} ${e2.message}`).reduce((text4, msg) => text4 + separator + msg);
|
|
97049
97165
|
}
|
|
97050
97166
|
$dataMetaSchema(metaSchema, keywordsJsonPointers) {
|
|
97051
97167
|
const rules = this.RULES.all;
|
|
@@ -101123,11 +101239,11 @@ var init_remote_invitation_recovery = __esm(() => {
|
|
|
101123
101239
|
// src/lib/remote-private-publications.ts
|
|
101124
101240
|
import { createHash as createHash23 } from "crypto";
|
|
101125
101241
|
function checkedPublicationDeclaration(value) {
|
|
101126
|
-
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 || !
|
|
101242
|
+
if (!exact(value, ["idempotencyKey", "version", "expectedCurrentVersionId", "manifestText", "archiveSha256", "archiveByteSize"]) || !publicationUuid(value.idempotencyKey) || !(value.expectedCurrentVersionId === null || publicationUuid(value.expectedCurrentVersionId)) || typeof value.version !== "string" || !value.version || value.version.length > 128 || /[\p{Cc}\p{Cs}]/u.test(value.version) || typeof value.manifestText !== "string" || Buffer.byteLength(value.manifestText) > 16384 || !hash4(value.archiveSha256) || !Number.isSafeInteger(value.archiveByteSize) || Number(value.archiveByteSize) < 1 || Number(value.archiveByteSize) > PRIVATE_PUBLICATION_MAX_BYTES)
|
|
101127
101243
|
return bad();
|
|
101128
101244
|
try {
|
|
101129
101245
|
const manifest = JSON.parse(value.manifestText);
|
|
101130
|
-
if (!record10(manifest) || manifest.version !== value.version || validatePortableManifestContract(manifest, { strict: true }).length || !
|
|
101246
|
+
if (!record10(manifest) || manifest.version !== value.version || validatePortableManifestContract(manifest, { strict: true }).length || !hash4(manifest.provenance?.content_hash))
|
|
101131
101247
|
return bad();
|
|
101132
101248
|
} catch {
|
|
101133
101249
|
return bad();
|
|
@@ -101135,7 +101251,7 @@ function checkedPublicationDeclaration(value) {
|
|
|
101135
101251
|
return Object.freeze({ ...value });
|
|
101136
101252
|
}
|
|
101137
101253
|
function checkedPublicationView(value, skillId, intentId, declaration) {
|
|
101138
|
-
if (!exact(value, ["id", "skillId", "version", "expectedCurrentVersionId", "archiveSha256", "archiveByteSize", "state", "expiresAt", "createdAt", "versionId"]) || !publicationUuid(value.id) || value.skillId !== skillId || intentId !== undefined && value.id !== intentId || typeof value.version !== "string" || !value.version || value.version.length > 128 || /[\p{Cc}\p{Cs}]/u.test(value.version) || !(value.expectedCurrentVersionId === null || publicationUuid(value.expectedCurrentVersionId)) || !
|
|
101254
|
+
if (!exact(value, ["id", "skillId", "version", "expectedCurrentVersionId", "archiveSha256", "archiveByteSize", "state", "expiresAt", "createdAt", "versionId"]) || !publicationUuid(value.id) || value.skillId !== skillId || intentId !== undefined && value.id !== intentId || typeof value.version !== "string" || !value.version || value.version.length > 128 || /[\p{Cc}\p{Cs}]/u.test(value.version) || !(value.expectedCurrentVersionId === null || publicationUuid(value.expectedCurrentVersionId)) || !hash4(value.archiveSha256) || !Number.isSafeInteger(value.archiveByteSize) || Number(value.archiveByteSize) < 1 || Number(value.archiveByteSize) > PRIVATE_PUBLICATION_MAX_BYTES || typeof value.state !== "string" || !["awaiting_upload", "queued", "verifying", "needs_attention", "committed", "rejected", "cancelled", "expired"].includes(value.state) || !date6(value.expiresAt) || !date6(value.createdAt) || !(value.versionId === null || publicationUuid(value.versionId)) || value.state === "committed" && value.versionId === null)
|
|
101139
101255
|
return invalid5();
|
|
101140
101256
|
if (declaration && ["version", "expectedCurrentVersionId", "archiveSha256", "archiveByteSize"].some((k) => value[k] !== declaration[k]))
|
|
101141
101257
|
return invalid5();
|
|
@@ -101382,7 +101498,7 @@ var PRIVATE_PUBLICATION_MAX_BYTES, failures2, PrivatePublicationError, bad = ()
|
|
|
101382
101498
|
throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Invalid publication input or recovery data.");
|
|
101383
101499
|
}, invalid5 = () => {
|
|
101384
101500
|
throw new PrivatePublicationError("INVALID_PUBLICATION_RESPONSE", "The server returned an invalid publication result.");
|
|
101385
|
-
}, 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),
|
|
101501
|
+
}, 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), hash4 = (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");
|
|
101386
101502
|
var init_remote_private_publications = __esm(() => {
|
|
101387
101503
|
init_fleet_credentials();
|
|
101388
101504
|
init_remote_workspace_selection();
|
|
@@ -101443,8 +101559,8 @@ async function requestAuthApi(instance, path, options) {
|
|
|
101443
101559
|
apiUrl: safeUrl
|
|
101444
101560
|
});
|
|
101445
101561
|
}
|
|
101446
|
-
const
|
|
101447
|
-
const body =
|
|
101562
|
+
const text4 = await res.text();
|
|
101563
|
+
const body = text4 ? parseJsonBody(text4) : {};
|
|
101448
101564
|
if (!res.ok) {
|
|
101449
101565
|
const record11 = isRecord5(body) ? body : {};
|
|
101450
101566
|
const detail = typeof record11.detail === "string" ? record11.detail : undefined;
|
|
@@ -101460,15 +101576,15 @@ async function requestAuthApi(instance, path, options) {
|
|
|
101460
101576
|
}
|
|
101461
101577
|
return body;
|
|
101462
101578
|
}
|
|
101463
|
-
function parseJsonBody(
|
|
101579
|
+
function parseJsonBody(text4) {
|
|
101464
101580
|
try {
|
|
101465
|
-
return JSON.parse(
|
|
101581
|
+
return JSON.parse(text4);
|
|
101466
101582
|
} catch {
|
|
101467
|
-
return { detail: condenseErrorBody(
|
|
101583
|
+
return { detail: condenseErrorBody(text4) };
|
|
101468
101584
|
}
|
|
101469
101585
|
}
|
|
101470
|
-
function condenseErrorBody(
|
|
101471
|
-
const stripped = /<[a-z!/]/i.test(
|
|
101586
|
+
function condenseErrorBody(text4) {
|
|
101587
|
+
const stripped = /<[a-z!/]/i.test(text4) ? text4.replace(/<(script|style)[\s\S]*?<\/\1>/gi, " ").replace(/<[^>]*>/g, " ") : text4;
|
|
101472
101588
|
const collapsed = stripped.replace(/\s+/g, " ").trim();
|
|
101473
101589
|
if (collapsed.length <= MAX_ERROR_DETAIL_LENGTH)
|
|
101474
101590
|
return collapsed;
|
|
@@ -101684,12 +101800,12 @@ function safeText(file2) {
|
|
|
101684
101800
|
}
|
|
101685
101801
|
}
|
|
101686
101802
|
function checkIdentityMetadata(file2, identity4) {
|
|
101687
|
-
const
|
|
101688
|
-
if (
|
|
101803
|
+
const text4 = safeText(file2);
|
|
101804
|
+
if (text4 === null)
|
|
101689
101805
|
return;
|
|
101690
101806
|
let value;
|
|
101691
101807
|
try {
|
|
101692
|
-
value = JSON.parse(
|
|
101808
|
+
value = JSON.parse(text4);
|
|
101693
101809
|
} catch {
|
|
101694
101810
|
return fail3("The profile identity metadata is invalid. Sign in again before managing this workspace.");
|
|
101695
101811
|
}
|
|
@@ -102028,7 +102144,7 @@ var init_recurring_customer = __esm(() => {
|
|
|
102028
102144
|
|
|
102029
102145
|
// src/lib/recurring-recovery.ts
|
|
102030
102146
|
import { constants as constants17, closeSync as closeSync20, fsyncSync as fsyncSync5, fstatSync as fstatSync20, lstatSync as lstatSync25, mkdirSync as mkdirSync17, openSync as openSync20, readSync as readSync14, realpathSync as realpathSync9, renameSync as renameSync10, unlinkSync as unlinkSync6, writeFileSync as writeFileSync17 } from "fs";
|
|
102031
|
-
import { dirname as dirname23, isAbsolute as
|
|
102147
|
+
import { dirname as dirname23, isAbsolute as isAbsolute18, join as join46, resolve as resolve20 } from "path";
|
|
102032
102148
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
102033
102149
|
|
|
102034
102150
|
class RecoveryOwner {
|
|
@@ -102036,7 +102152,7 @@ class RecoveryOwner {
|
|
|
102036
102152
|
parents = [];
|
|
102037
102153
|
constructor(directory) {
|
|
102038
102154
|
this.directory = directory;
|
|
102039
|
-
if (!
|
|
102155
|
+
if (!isAbsolute18(directory) || resolve20(directory) !== directory || realpathSync9(directory) !== directory)
|
|
102040
102156
|
invalid6();
|
|
102041
102157
|
for (let path = directory;; path = dirname23(path)) {
|
|
102042
102158
|
const stat3 = lstatSync25(path);
|
|
@@ -102171,7 +102287,7 @@ function base2(customer, organizationId) {
|
|
|
102171
102287
|
};
|
|
102172
102288
|
}
|
|
102173
102289
|
function create3(directory, intent) {
|
|
102174
|
-
if (!
|
|
102290
|
+
if (!isAbsolute18(directory) || resolve20(directory) !== directory || realpathSync9(dirname23(directory)) !== dirname23(directory))
|
|
102175
102291
|
invalid6();
|
|
102176
102292
|
mkdirSync17(directory, { mode: 448 });
|
|
102177
102293
|
const owner2 = new RecoveryOwner(directory), checked = intentSchema.parse(intent), intentSha256 = canonicalJsonSha256(checked);
|
|
@@ -102334,12 +102450,12 @@ var init_recurring_recovery = __esm(() => {
|
|
|
102334
102450
|
});
|
|
102335
102451
|
|
|
102336
102452
|
// src/lib/recurring-surface.ts
|
|
102337
|
-
import { isAbsolute as
|
|
102453
|
+
import { isAbsolute as isAbsolute19 } from "path";
|
|
102338
102454
|
function recurringMcpSchema(action) {
|
|
102339
102455
|
return action === "activate" ? recurringSurfaceSchemas.activate.extend({ code, confirm: exports_external.literal(true) }) : recurringSurfaceSchemas[action];
|
|
102340
102456
|
}
|
|
102341
|
-
function expectedDraft(draft,
|
|
102342
|
-
if (!draft || draft.termsSha256 !==
|
|
102457
|
+
function expectedDraft(draft, hash5) {
|
|
102458
|
+
if (!draft || draft.termsSha256 !== hash5)
|
|
102343
102459
|
throw new RemoteRecurringError("RECURRING_TERMS_UNAVAILABLE");
|
|
102344
102460
|
return draft;
|
|
102345
102461
|
}
|
|
@@ -102439,7 +102555,7 @@ var init_recurring_surface = __esm(() => {
|
|
|
102439
102555
|
uuid13 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
|
|
102440
102556
|
context = { userId: uuid13.optional(), membershipId: uuid13.optional() };
|
|
102441
102557
|
page2 = { limit: exports_external.number().int().min(1).max(100).optional(), cursor: exports_external.string().min(1).max(2048).optional() };
|
|
102442
|
-
directory = exports_external.string().max(4096).refine(
|
|
102558
|
+
directory = exports_external.string().max(4096).refine(isAbsolute19, "Use an absolute recovery directory");
|
|
102443
102559
|
email4 = exports_external.string().trim().toLowerCase().email().max(254);
|
|
102444
102560
|
code = exports_external.string().regex(/^\d{6}$/);
|
|
102445
102561
|
recurringSurfaceSchemas = {
|
|
@@ -105241,10 +105357,10 @@ var init_private_publication_customer = __esm(() => {
|
|
|
105241
105357
|
|
|
105242
105358
|
// src/lib/private-publication-recovery.ts
|
|
105243
105359
|
import { constants as constants18, closeSync as closeSync21, fsyncSync as fsyncSync6, fstatSync as fstatSync21, lstatSync as lstatSync26, mkdirSync as mkdirSync21, openSync as openSync21, readSync as readSync15, realpathSync as realpathSync10, renameSync as renameSync11, unlinkSync as unlinkSync7, writeFileSync as writeFileSync20 } from "fs";
|
|
105244
|
-
import { dirname as dirname26, isAbsolute as
|
|
105360
|
+
import { dirname as dirname26, isAbsolute as isAbsolute20, join as join51, resolve as resolve21 } from "path";
|
|
105245
105361
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
105246
105362
|
function safeDirectory(directory2) {
|
|
105247
|
-
if (!
|
|
105363
|
+
if (!isAbsolute20(directory2) || directory2 !== resolve21(directory2) || realpathSync10(directory2) !== directory2)
|
|
105248
105364
|
return fail4();
|
|
105249
105365
|
for (let path = directory2;; path = dirname26(path)) {
|
|
105250
105366
|
const stat3 = lstatSync26(path);
|
|
@@ -105382,7 +105498,7 @@ async function preparePrivatePublication(client2, sourceDirectory, recoveryDirec
|
|
|
105382
105498
|
phase: "prepared",
|
|
105383
105499
|
intent: null
|
|
105384
105500
|
};
|
|
105385
|
-
if (!
|
|
105501
|
+
if (!isAbsolute20(recoveryDirectory) || resolve21(recoveryDirectory) !== recoveryDirectory || realpathSync10(dirname26(recoveryDirectory)) !== dirname26(recoveryDirectory))
|
|
105386
105502
|
return fail4();
|
|
105387
105503
|
mkdirSync21(recoveryDirectory, { mode: 448 });
|
|
105388
105504
|
safeDirectory(recoveryDirectory);
|
|
@@ -105483,10 +105599,10 @@ var init_private_publication_recovery = __esm(() => {
|
|
|
105483
105599
|
});
|
|
105484
105600
|
|
|
105485
105601
|
// src/mcp/private-publication-tools.ts
|
|
105486
|
-
import { isAbsolute as
|
|
105602
|
+
import { isAbsolute as isAbsolute21 } from "path";
|
|
105487
105603
|
function registerPrivatePublicationTools(server) {
|
|
105488
105604
|
const uuid9 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
|
|
105489
|
-
const directory2 = exports_external.string().max(4096).refine(
|
|
105605
|
+
const directory2 = exports_external.string().max(4096).refine(isAbsolute21, "Use an absolute local directory");
|
|
105490
105606
|
const verification2 = { email: exports_external.string().email().max(254), code: exports_external.string().regex(/^\d{6}$/), userId: uuid9, membershipId: uuid9, recoveryDirectory: directory2 };
|
|
105491
105607
|
const description = "Manage a private source publication using fresh workspace-bound verification and a host-local recovery directory. Publishing requires explicit UUID current-version comparison and upload consent. Resume reuses immutable saved bytes and intent; an uncertain PUT is finalized for server verification, never uploaded twice. Sessions and signed URLs are not returned or persisted. Private execution is unavailable. Host request history may contain the supplied verification code.";
|
|
105492
105608
|
const handler = (action) => async (value) => {
|
|
@@ -106132,7 +106248,7 @@ __export(exports_runtime, {
|
|
|
106132
106248
|
});
|
|
106133
106249
|
import { createHash as createHash25, randomUUID as randomUUID9 } from "crypto";
|
|
106134
106250
|
import { lstatSync as lstatSync27, mkdirSync as mkdirSync23, readFileSync as readFileSync35, realpathSync as realpathSync11, writeFileSync as writeFileSync22 } from "fs";
|
|
106135
|
-
import { basename as basename12, isAbsolute as
|
|
106251
|
+
import { basename as basename12, isAbsolute as isAbsolute22, join as join53 } from "path";
|
|
106136
106252
|
import { createInterface } from "readline";
|
|
106137
106253
|
function registerRuntime(parent) {
|
|
106138
106254
|
parent.command("run").argument("<skill>", "Skill name").argument("[args...]", "Arguments to pass to the skill; use -- to end Skills options").allowUnknownOption(true).passThroughOptions(true).option("--json", "Output result as JSON", false).option("--remote", "Run on the configured server, using its catalog and quote", false).option("--target <target>", "Execution target: local or cloud").option("--secret-bindings <path>", "Reviewed, exact-selection local execution vault bindings (JSON file)").option("--secret-bindings-template", "Print a scoped bindings template without resolving secrets or running the skill", false).option("--input <json>", "Structured cloud execution input").option("--skill-version <version>", "Exact selected skill version").option("--selection-profile <id>", "Selected Skills profile").option("--session <id>", "Pinned Skills session").option("--cached", "Use the explicit verified selected cache", false).option("--yes", "Approve the server's quoted credit cost for this run", false).option("--idempotency-key <key>", "Reuse this key when retrying the same remote submission").option("--file <path>", "Attach a local input file to a remote run (repeatable)", (value, prior) => [...prior, value], []).option("--wait", "Poll remote runs until a terminal status", false).option("--poll-interval-ms <ms>", "Remote polling interval in milliseconds", "1000").option("--poll-timeout-ms <ms>", "Maximum time to wait for a remote run", "300000").description("Run a skill directly").action(async (name, args2, options, command) => {
|
|
@@ -106259,7 +106375,7 @@ Updating ${name}...
|
|
|
106259
106375
|
async function readUpdatedVersion(bunExecutable) {
|
|
106260
106376
|
const output2 = await readUpdateCommand([bunExecutable, "pm", "bin", "-g"]);
|
|
106261
106377
|
const globalBin = output2.replace(/\r?\n$/, "");
|
|
106262
|
-
if (!globalBin || !
|
|
106378
|
+
if (!globalBin || !isAbsolute22(globalBin) || /[\r\n\0]/.test(globalBin))
|
|
106263
106379
|
throw new Error("Update bin discovery failed");
|
|
106264
106380
|
const installed = Bun.which("skills", { PATH: globalBin, cwd: globalBin });
|
|
106265
106381
|
const selected = Bun.which("skills");
|
|
@@ -107225,13 +107341,13 @@ import { emitKeypressEvents } from "readline";
|
|
|
107225
107341
|
async function readCode() {
|
|
107226
107342
|
if (process.stdin.isTTY)
|
|
107227
107343
|
throw new NameInputError("Pipe a fresh six-digit verification code when using --code-stdin.");
|
|
107228
|
-
let
|
|
107344
|
+
let text4 = "";
|
|
107229
107345
|
for await (const chunk2 of process.stdin) {
|
|
107230
|
-
|
|
107231
|
-
if (
|
|
107346
|
+
text4 += chunk2.toString();
|
|
107347
|
+
if (text4.length > 32)
|
|
107232
107348
|
throw new NameInputError("Supply only a six-digit verification code on stdin.");
|
|
107233
107349
|
}
|
|
107234
|
-
const code2 =
|
|
107350
|
+
const code2 = text4.trim();
|
|
107235
107351
|
if (!/^\d{6}$/.test(code2))
|
|
107236
107352
|
throw new NameInputError("Supply only a six-digit verification code on stdin.");
|
|
107237
107353
|
return code2;
|
|
@@ -107259,7 +107375,7 @@ function promptCode() {
|
|
|
107259
107375
|
resolve22(answer);
|
|
107260
107376
|
};
|
|
107261
107377
|
const cancel = () => finish(null);
|
|
107262
|
-
const keypress = (
|
|
107378
|
+
const keypress = (text4, key) => {
|
|
107263
107379
|
if (key.ctrl && ["c", "d"].includes(key.name ?? "") || key.name === "escape")
|
|
107264
107380
|
return cancel();
|
|
107265
107381
|
if (key.name === "return" || key.name === "enter") {
|
|
@@ -107275,8 +107391,8 @@ Enter all six digits: `);
|
|
|
107275
107391
|
value = value.slice(0, -1);
|
|
107276
107392
|
output2.write("\b \b");
|
|
107277
107393
|
}
|
|
107278
|
-
} else if (/^[0-9]$/.test(
|
|
107279
|
-
value +=
|
|
107394
|
+
} else if (/^[0-9]$/.test(text4) && value.length < 6) {
|
|
107395
|
+
value += text4;
|
|
107280
107396
|
output2.write("*");
|
|
107281
107397
|
}
|
|
107282
107398
|
};
|
|
@@ -107758,7 +107874,7 @@ import {
|
|
|
107758
107874
|
statSync as statSync19,
|
|
107759
107875
|
writeFileSync as writeFileSync23
|
|
107760
107876
|
} from "fs";
|
|
107761
|
-
import { dirname as dirname29, isAbsolute as
|
|
107877
|
+
import { dirname as dirname29, isAbsolute as isAbsolute23, relative as relative8, resolve as resolve22, sep as sep10 } from "path";
|
|
107762
107878
|
function validateStationId(stationId) {
|
|
107763
107879
|
if (!/^[a-z0-9-]+$/.test(stationId)) {
|
|
107764
107880
|
throw new StationSnapshotError("INVALID_STATION", `station id must be a slug, got: ${stationId}`);
|
|
@@ -107864,7 +107980,7 @@ function writeStationSnapshot(options) {
|
|
|
107864
107980
|
for (const plan of plans) {
|
|
107865
107981
|
const destination = resolve22(repoRoot, plan.destination);
|
|
107866
107982
|
const destinationRelative = relative8(repoRoot, destination);
|
|
107867
|
-
if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep10) ||
|
|
107983
|
+
if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep10) || isAbsolute23(destinationRelative)) {
|
|
107868
107984
|
throw new StationSnapshotError("DESTINATION_ESCAPE", `destination escapes repo root: ${plan.destination}`);
|
|
107869
107985
|
}
|
|
107870
107986
|
let existingDigest = null;
|
|
@@ -108339,10 +108455,10 @@ var init_create_sync_config = __esm(() => {
|
|
|
108339
108455
|
// src/lib/codex-hook-rpc.ts
|
|
108340
108456
|
import { execFile, spawn as spawn3 } from "child_process";
|
|
108341
108457
|
import { realpathSync as realpathSync12, statSync as statSync20 } from "fs";
|
|
108342
|
-
import { isAbsolute as
|
|
108458
|
+
import { isAbsolute as isAbsolute24 } from "path";
|
|
108343
108459
|
import { promisify } from "util";
|
|
108344
108460
|
async function connectCodexHookRpc(options) {
|
|
108345
|
-
const found =
|
|
108461
|
+
const found = isAbsolute24(options.command) ? options.command : Bun.which(options.command, { PATH: process.env.PATH });
|
|
108346
108462
|
if (!found)
|
|
108347
108463
|
throw new Error("CODEX_HOOK_TRUST_NATIVE_UNAVAILABLE: install Codex or pass --codex-command");
|
|
108348
108464
|
const binary = realpathSync12(found), stat3 = statSync20(binary);
|
|
@@ -108478,10 +108594,10 @@ var init_codex_hook_rpc = __esm(() => {
|
|
|
108478
108594
|
|
|
108479
108595
|
// src/lib/codex-hook-trust-identity.ts
|
|
108480
108596
|
import { realpathSync as realpathSync13 } from "fs";
|
|
108481
|
-
import { dirname as dirname30, isAbsolute as
|
|
108482
|
-
import { isDeepStrictEqual as
|
|
108597
|
+
import { dirname as dirname30, isAbsolute as isAbsolute25, join as join56 } from "path";
|
|
108598
|
+
import { isDeepStrictEqual as isDeepStrictEqual8 } from "util";
|
|
108483
108599
|
function inspectRecordedSkillsCli(command, expected) {
|
|
108484
|
-
need4(
|
|
108600
|
+
need4(isAbsolute25(command) && !command.includes("\x00"), "RECONCILE_RECORDED_COMMAND_REQUIRED");
|
|
108485
108601
|
const resolved = realpathSync13(command);
|
|
108486
108602
|
const cli = snapshot(resolved, false, { readOnlyPackage: true });
|
|
108487
108603
|
const manifest = snapshot(join56(dirname30(dirname30(resolved)), "package.json"), false, { readOnlyPackage: true });
|
|
@@ -108489,7 +108605,7 @@ function inspectRecordedSkillsCli(command, expected) {
|
|
|
108489
108605
|
need4(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join56(dirname30(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
|
|
108490
108606
|
need4((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
|
|
108491
108607
|
const receipt = { path: resolved, version: pkg.version, sha256: cli.sha256, manifestSha256: manifest.sha256 };
|
|
108492
|
-
need4(
|
|
108608
|
+
need4(isDeepStrictEqual8(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
|
|
108493
108609
|
return { receipt, recheck() {
|
|
108494
108610
|
need4(realpathSync13(command) === resolved, "SKILLS_COMMAND_CHANGED");
|
|
108495
108611
|
unchanged2(cli);
|
|
@@ -108500,7 +108616,7 @@ function bindSkillsCli(command, reviewed) {
|
|
|
108500
108616
|
const normal = Bun.which("skills", { PATH: process.env.PATH });
|
|
108501
108617
|
need4(normal, "SKILLS_COMMAND_UNAVAILABLE");
|
|
108502
108618
|
const resolved = realpathSync13(normal);
|
|
108503
|
-
const bound =
|
|
108619
|
+
const bound = isAbsolute25(command) ? command : command === "skills" ? normal : undefined;
|
|
108504
108620
|
need4(bound && realpathSync13(bound) === resolved, "SKILLS_COMMAND_MISMATCH");
|
|
108505
108621
|
const entrypoint = reviewed?.path ?? process.argv[1];
|
|
108506
108622
|
need4(entrypoint && realpathSync13(entrypoint) === resolved, "SKILLS_ENTRYPOINT_MISMATCH");
|
|
@@ -108525,19 +108641,19 @@ var init_codex_hook_trust_identity = __esm(() => {
|
|
|
108525
108641
|
});
|
|
108526
108642
|
|
|
108527
108643
|
// src/lib/codex-hook-policy-recovery.ts
|
|
108528
|
-
import { isDeepStrictEqual as
|
|
108644
|
+
import { isDeepStrictEqual as isDeepStrictEqual9 } from "util";
|
|
108529
108645
|
function reviewedClaudeDiscoveryChange(beforeText, currentText, options) {
|
|
108530
108646
|
need4(typeof options.reason === "string" && options.reason.trim().length > 0 && options.reason.length <= 512 && !/[\x00-\x1f\x7f]/.test(options.reason), "RECONCILE_RECOVERY_REASON_REQUIRED");
|
|
108531
108647
|
need4(options.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(options.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
|
|
108532
108648
|
const before2 = parseManagedSkillPolicy(beforeText), current = parseManagedSkillPolicy(currentText);
|
|
108533
108649
|
const oldDiscovery = before2.bridge?.discovery?.claude, newDiscovery = current.bridge?.discovery?.claude;
|
|
108534
108650
|
need4(oldDiscovery?.agent === "claude" && newDiscovery?.agent === "claude" && oldDiscovery.method === "reviewed" && newDiscovery.method === "reviewed", "RECONCILE_POLICY_CHANGED");
|
|
108535
|
-
const changes = ["roots", "sources"].filter((key) => !
|
|
108651
|
+
const changes = ["roots", "sources"].filter((key) => !isDeepStrictEqual9(oldDiscovery[key], newDiscovery[key])).map((key) => ({ path: `bridge.discovery.claude.${key}`, before: oldDiscovery[key], after: newDiscovery[key] }));
|
|
108536
108652
|
need4(changes.length > 0, "RECONCILE_POLICY_CHANGED");
|
|
108537
108653
|
const compared = structuredClone(current);
|
|
108538
108654
|
compared.bridge.discovery.claude.roots = oldDiscovery.roots;
|
|
108539
108655
|
compared.bridge.discovery.claude.sources = oldDiscovery.sources;
|
|
108540
|
-
need4(
|
|
108656
|
+
need4(isDeepStrictEqual9(before2, compared), "RECONCILE_POLICY_CHANGED");
|
|
108541
108657
|
verifyAgentDiscovery(newDiscovery);
|
|
108542
108658
|
return { reason: options.reason, changes };
|
|
108543
108659
|
}
|
|
@@ -108547,69 +108663,6 @@ var init_codex_hook_policy_recovery = __esm(() => {
|
|
|
108547
108663
|
init_agent_discovery();
|
|
108548
108664
|
});
|
|
108549
108665
|
|
|
108550
|
-
// src/lib/codex-hook-additions-review.ts
|
|
108551
|
-
import { isAbsolute as isAbsolute25 } from "path";
|
|
108552
|
-
import { isDeepStrictEqual as isDeepStrictEqual9 } from "util";
|
|
108553
|
-
function exactKeys3(value, keys3) {
|
|
108554
|
-
need4(value && typeof value === "object" && !Array.isArray(value) && isDeepStrictEqual9(Object.keys(value).sort(), [...keys3].sort()), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
|
|
108555
|
-
}
|
|
108556
|
-
function reviewNativeHookAdditions(options) {
|
|
108557
|
-
need4(isAbsolute25(options.path), "RECONCILE_ADDITIONS_REVIEW_PATH");
|
|
108558
|
-
const reviewFile = snapshot(options.path, true), review = JSON.parse(reviewFile.text);
|
|
108559
|
-
exactKeys3(review, ["version", "kind", "reason", "producerEvidence", "journalIntentSha256", "policySha256", "configCurrentSha256", "hooksCurrentSha256", "producerBefore", "additions"]);
|
|
108560
|
-
need4(review.version === 1 && review.kind === "native-hook-additions" && text3(review.reason) && text3(review.producerEvidence), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
|
|
108561
|
-
for (const [name, expected] of [["journalIntentSha256", options.intent.sha256], ["policySha256", options.policy.sha256], ["configCurrentSha256", options.configCurrent.sha256], ["hooksCurrentSha256", options.hooksCurrent.sha256]])
|
|
108562
|
-
need4(hash4(review[name]) && review[name] === expected, "RECONCILE_ADDITIONS_REVIEW_CHANGED");
|
|
108563
|
-
exactKeys3(review.producerBefore, ["configPath", "configSha256", "hooksPath", "hooksSha256"]);
|
|
108564
|
-
const before2 = review.producerBefore;
|
|
108565
|
-
need4(isAbsolute25(before2.configPath) && isAbsolute25(before2.hooksPath) && hash4(before2.configSha256) && hash4(before2.hooksSha256), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
|
|
108566
|
-
const producerConfig = snapshot(before2.configPath, true), producerHooks = snapshot(before2.hooksPath, true);
|
|
108567
|
-
need4(producerConfig.sha256 === before2.configSha256 && producerHooks.sha256 === before2.hooksSha256 && producerHooks.sha256 === options.hooksBefore.sha256, "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
|
|
108568
|
-
const original = structure2(options.configBefore.text), producer = structure2(producerConfig.text), expectedProducer = structuredClone(original), originalKeys = options.journalHooks.map((hook) => hook.key);
|
|
108569
|
-
expectedProducer.hooks ??= {};
|
|
108570
|
-
expectedProducer.hooks.state ??= {};
|
|
108571
|
-
for (const hook of options.journalHooks)
|
|
108572
|
-
expectedProducer.hooks.state[hook.key] = { ...expectedProducer.hooks.state[hook.key], enabled: true, trusted_hash: hook.currentHash };
|
|
108573
|
-
need4(isDeepStrictEqual9(expectedProducer, producer) && codexTrustReconcileWitness(options.configBefore.text, originalKeys) === codexTrustReconcileWitness(producerConfig.text, originalKeys) && codexTrustUnmanagedSemantic(options.configBefore.text, originalKeys) === codexTrustUnmanagedSemantic(producerConfig.text, originalKeys), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
|
|
108574
|
-
need4(Array.isArray(review.additions) && review.additions.length > 0 && review.additions.length <= 20, "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
|
|
108575
|
-
const expectedHooks = JSON.parse(options.hooksBefore.text), currentHooks = JSON.parse(options.hooksCurrent.text), expectedConfig = structuredClone(producer);
|
|
108576
|
-
need4(expectedHooks.hooks && typeof expectedHooks.hooks === "object" && !Array.isArray(expectedHooks.hooks), "RECONCILE_ADDITIONS_DECLARATIONS");
|
|
108577
|
-
const added = [], seen = new Set, commands = new Set(options.recordedNativeHooks.map((hook) => hook.command));
|
|
108578
|
-
for (const addition of review.additions) {
|
|
108579
|
-
exactKeys3(addition, ["event", "nativeHook"]);
|
|
108580
|
-
need4(Object.hasOwn(events, addition.event), "RECONCILE_ADDITIONS_DECLARATIONS");
|
|
108581
|
-
const { event, nativeHook: hook } = addition;
|
|
108582
|
-
exactKeys3(hook, nativeKeys);
|
|
108583
|
-
const groups = expectedHooks.hooks[event] ?? [];
|
|
108584
|
-
need4(Array.isArray(groups), "RECONCILE_ADDITIONS_DECLARATIONS");
|
|
108585
|
-
const key = `${options.nativeHooksPath}:${events[event][1]}:${groups.length}:0`;
|
|
108586
|
-
need4(hook.key === key && !seen.has(key) && !options.recordedNativeHooks.some((originalHook) => originalHook.key === key) && !Object.hasOwn(expectedConfig.hooks.state, key), "RECONCILE_ADDITIONS_IDENTITY");
|
|
108587
|
-
need4(hook.eventName === events[event][0] && hook.handlerType === "command" && text3(hook.command, 16384) && !commands.has(hook.command) && Number.isInteger(hook.timeoutSec) && hook.timeoutSec > 0 && hook.timeoutSec <= 60 && hook.matcher === null && hook.async === false && hook.statusMessage === null && hook.additionalContextLimit === null && hook.sourcePath === options.nativeHooksPath && hook.source === "user" && hook.pluginId === null && hook.isManaged === false && /^sha256:[a-f0-9]{64}$/.test(hook.currentHash) && hook.enabled === true && hook.trustStatus === "trusted", "RECONCILE_ADDITIONS_IDENTITY");
|
|
108588
|
-
seen.add(key);
|
|
108589
|
-
commands.add(hook.command);
|
|
108590
|
-
added.push(hook);
|
|
108591
|
-
expectedHooks.hooks[event] = [...groups, { hooks: [{ type: "command", command: hook.command, timeout: hook.timeoutSec }] }];
|
|
108592
|
-
expectedConfig.hooks.state[key] = { enabled: true, trusted_hash: hook.currentHash };
|
|
108593
|
-
}
|
|
108594
|
-
need4(isDeepStrictEqual9(expectedHooks, currentHooks), "RECONCILE_ADDITIONS_DECLARATIONS");
|
|
108595
|
-
const keys3 = added.map((hook) => hook.key);
|
|
108596
|
-
need4(isDeepStrictEqual9(expectedConfig, structure2(options.configCurrent.text)) && codexTrustReconcileWitness(producerConfig.text, keys3) === codexTrustReconcileWitness(options.configCurrent.text, keys3) && codexTrustUnmanagedSemantic(producerConfig.text, keys3) === codexTrustUnmanagedSemantic(options.configCurrent.text, keys3), "RECONCILE_ADDITIONS_CONFIG");
|
|
108597
|
-
const recheck = () => {
|
|
108598
|
-
unchanged2(reviewFile);
|
|
108599
|
-
unchanged2(producerConfig);
|
|
108600
|
-
unchanged2(producerHooks);
|
|
108601
|
-
};
|
|
108602
|
-
recheck();
|
|
108603
|
-
return { hooks: added, recheck, receipt: { reviewPath: reviewFile.file, reviewSha256: reviewFile.sha256, reason: review.reason, producerEvidence: review.producerEvidence, producerBefore: { configPath: producerConfig.file, configSha256: producerConfig.sha256, hooksPath: producerHooks.file, hooksSha256: producerHooks.sha256 }, additions: added } };
|
|
108604
|
-
}
|
|
108605
|
-
var events, hash4 = (value) => typeof value === "string" && /^[a-f0-9]{64}$/.test(value), text3 = (value, max2 = 2048) => typeof value === "string" && value.trim().length > 0 && value.length <= max2 && !/[\0\r\n]/.test(value), structure2 = (value) => JSON.parse(JSON.stringify(Bun.TOML.parse(value))), nativeKeys;
|
|
108606
|
-
var init_codex_hook_additions_review = __esm(() => {
|
|
108607
|
-
init_codex_hook_trust_files();
|
|
108608
|
-
init_codex_hook_trust_layout();
|
|
108609
|
-
events = { UserPromptSubmit: ["userPromptSubmit", "user_prompt_submit"], SessionStart: ["sessionStart", "session_start"], SubagentStart: ["subagentStart", "subagent_start"] };
|
|
108610
|
-
nativeKeys = ["key", "eventName", "handlerType", "command", "matcher", "timeoutSec", "async", "statusMessage", "additionalContextLimit", "sourcePath", "source", "pluginId", "isManaged", "currentHash", "enabled", "trustStatus"];
|
|
108611
|
-
});
|
|
108612
|
-
|
|
108613
108666
|
// src/lib/agent-codex-trust.ts
|
|
108614
108667
|
import { lstatSync as lstatSync29, mkdirSync as mkdirSync25, readdirSync as readdirSync20, readFileSync as readFileSync37, realpathSync as realpathSync14, statSync as statSync21 } from "fs";
|
|
108615
108668
|
import { createHash as createHash27, randomUUID as randomUUID10 } from "crypto";
|
|
@@ -108696,8 +108749,11 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
108696
108749
|
const before2 = structure3(configBefore.text), current = structure3(currentConfig.text), expectedConfig = structuredClone(before2);
|
|
108697
108750
|
expectedConfig.hooks ??= {};
|
|
108698
108751
|
expectedConfig.hooks.state ??= {};
|
|
108699
|
-
for (const hook of
|
|
108752
|
+
for (const hook of intent.hooks)
|
|
108700
108753
|
expectedConfig.hooks.state[hook.key] = { ...expectedConfig.hooks.state[hook.key], enabled: true, trusted_hash: hook.currentHash };
|
|
108754
|
+
if (additions)
|
|
108755
|
+
for (const { key, state } of readReviewedAdditionTrustStates(additions.trustProof, configBefore, currentConfig, intent.hooks))
|
|
108756
|
+
expectedConfig.hooks.state[key] = { ...state };
|
|
108701
108757
|
if (supersededBinding) {
|
|
108702
108758
|
for (const hook of intent.hooks) {
|
|
108703
108759
|
const state = current.hooks?.state?.[hook.key];
|
|
@@ -108705,7 +108761,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
108705
108761
|
}
|
|
108706
108762
|
} else
|
|
108707
108763
|
need4(isDeepStrictEqual10(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
|
|
108708
|
-
const configDiscoveryRecovery = recovery && binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, configBefore, currentConfig,
|
|
108764
|
+
const configDiscoveryRecovery = recovery && binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, configBefore, currentConfig, intent.hooks, additions?.trustProof) : undefined;
|
|
108709
108765
|
assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: configDiscoveryRecovery });
|
|
108710
108766
|
const recoveryCli = recovery ? bindSkillsCli("skills", options.reviewedSkillsCli) : undefined;
|
|
108711
108767
|
if (recoveryCli)
|