@hasna/skills 0.10.41 → 0.10.43
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 +20 -0
- package/bin/index.js +236 -87
- package/bin/maintenance.js +1 -0
- package/bin/mcp.js +138 -19
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +163 -31
- package/dist/lib/agent-discovery.d.ts +1 -1
- package/dist/lib/agent-integration.d.ts +1 -1
- package/dist/lib/codex-settings-witness.d.ts +13 -0
- package/dist/sdk/index.js +161 -31
- package/dist/server/maintenance.d.ts +1 -0
- 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.10.
|
|
36871
|
+
version: "0.10.43",
|
|
36872
36872
|
description: "Skills library for AI coding agents",
|
|
36873
36873
|
type: "module",
|
|
36874
36874
|
bin: {
|
|
@@ -40019,8 +40019,8 @@ function assertAgentPolicyCollections(policy) {
|
|
|
40019
40019
|
text(source.path);
|
|
40020
40020
|
requireBound(source.sha256 === null || typeof source.sha256 === "string" && /^[a-f0-9]{64}$/.test(source.sha256));
|
|
40021
40021
|
if (source.hashMode !== undefined)
|
|
40022
|
-
requireBound(["bytes", "path-bytes", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-marketplace-registry-v2", "codex-settings-v1", "codex-settings-v2", "codex-settings-v3"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
40023
|
-
if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || source.hashMode === "codex-settings-v3")
|
|
40022
|
+
requireBound(["bytes", "path-bytes", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-marketplace-registry-v2", "codex-settings-v1", "codex-settings-v2", "codex-settings-v3", "codex-settings-v4"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
40023
|
+
if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4"))
|
|
40024
40024
|
requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute2(source.path) && resolve3(source.path) === source.path && basename2(source.path) === "config.toml");
|
|
40025
40025
|
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3")
|
|
40026
40026
|
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute2(source.path) && resolve3(source.path) === source.path && basename2(source.path) === "settings.json");
|
|
@@ -52223,6 +52223,7 @@ var init_codex_mcp_discovery_projection = () => {};
|
|
|
52223
52223
|
|
|
52224
52224
|
// src/lib/codex-settings-witness.ts
|
|
52225
52225
|
import { createHash as createHash12 } from "crypto";
|
|
52226
|
+
import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
|
|
52226
52227
|
function need4(value) {
|
|
52227
52228
|
if (!value)
|
|
52228
52229
|
throw new Error("Invalid Codex settings witness");
|
|
@@ -52328,7 +52329,7 @@ function disablesOneSkill(entry) {
|
|
|
52328
52329
|
return selector.length === 1 && typeof entry[selector[0]] === "string" && entry[selector[0]].length > 0;
|
|
52329
52330
|
}
|
|
52330
52331
|
function inference(target, version) {
|
|
52331
|
-
const keys2 = version
|
|
52332
|
+
const keys2 = version >= 3 ? [...INFERENCE, "service_tier", "plan_mode_reasoning_effort", "personality"] : INFERENCE;
|
|
52332
52333
|
for (const key of keys2)
|
|
52333
52334
|
if (Object.hasOwn(target, key)) {
|
|
52334
52335
|
const value = target[key];
|
|
@@ -52336,7 +52337,7 @@ function inference(target, version) {
|
|
|
52336
52337
|
need4(typeof value === "string" && MODEL.test(value));
|
|
52337
52338
|
else if (key === "personality")
|
|
52338
52339
|
need4(typeof value === "string" && ["none", "friendly", "pragmatic"].includes(value));
|
|
52339
|
-
else if (version
|
|
52340
|
+
else if (version >= 3 && key !== "model_verbosity") {
|
|
52340
52341
|
need4(typeof value === "string" && value.length <= 128 && !/[\x00-\x1f\x7f]/.test(value));
|
|
52341
52342
|
if (key !== "service_tier")
|
|
52342
52343
|
need4(value.length > 0);
|
|
@@ -52345,6 +52346,115 @@ function inference(target, version) {
|
|
|
52345
52346
|
delete target[key];
|
|
52346
52347
|
}
|
|
52347
52348
|
}
|
|
52349
|
+
function projectModelAvailabilityNux(config, text2) {
|
|
52350
|
+
const tui = config.tui, counts = isRecord3(tui) ? tui.model_availability_nux : undefined;
|
|
52351
|
+
if (isRecord3(tui) && !Object.keys(tui).length) {
|
|
52352
|
+
delete config.tui;
|
|
52353
|
+
return { config, numericSource: text2 };
|
|
52354
|
+
}
|
|
52355
|
+
if (!isRecord3(counts) || Object.keys(counts).length > 256 || !Object.values(counts).every((value) => typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 4294967295))
|
|
52356
|
+
return { config, numericSource: text2 };
|
|
52357
|
+
const expected = structuredClone(config);
|
|
52358
|
+
delete expected.tui.model_availability_nux;
|
|
52359
|
+
const stripEmptyTui = (value) => {
|
|
52360
|
+
if (isRecord3(value.tui) && !Object.keys(value.tui).length)
|
|
52361
|
+
delete value.tui;
|
|
52362
|
+
};
|
|
52363
|
+
stripEmptyTui(expected);
|
|
52364
|
+
const headers = [];
|
|
52365
|
+
const spans = [];
|
|
52366
|
+
const integer = /^(?:\+?(?:0|[1-9](?:_?\d)*)|0x[0-9a-fA-F](?:_?[0-9a-fA-F])*|0o[0-7](?:_?[0-7])*|0b[01](?:_?[01])*)$/;
|
|
52367
|
+
const counterIntegers = (span) => {
|
|
52368
|
+
let values2 = 0;
|
|
52369
|
+
for (let at2 = 0;at2 < span.length; ) {
|
|
52370
|
+
const char = span[at2];
|
|
52371
|
+
if (char === "#") {
|
|
52372
|
+
while (at2 < span.length && span[at2] !== `
|
|
52373
|
+
`)
|
|
52374
|
+
at2++;
|
|
52375
|
+
continue;
|
|
52376
|
+
}
|
|
52377
|
+
if (char === '"' || char === "'") {
|
|
52378
|
+
const quote = char;
|
|
52379
|
+
at2++;
|
|
52380
|
+
while (at2 < span.length) {
|
|
52381
|
+
if (quote === '"' && span[at2] === "\\") {
|
|
52382
|
+
at2 += 2;
|
|
52383
|
+
continue;
|
|
52384
|
+
}
|
|
52385
|
+
if (span[at2++] === quote)
|
|
52386
|
+
break;
|
|
52387
|
+
}
|
|
52388
|
+
continue;
|
|
52389
|
+
}
|
|
52390
|
+
if (char !== "=") {
|
|
52391
|
+
at2++;
|
|
52392
|
+
continue;
|
|
52393
|
+
}
|
|
52394
|
+
at2++;
|
|
52395
|
+
while (at2 < span.length && /\s/.test(span[at2]))
|
|
52396
|
+
at2++;
|
|
52397
|
+
if (span[at2] === "{") {
|
|
52398
|
+
at2++;
|
|
52399
|
+
continue;
|
|
52400
|
+
}
|
|
52401
|
+
const start = at2;
|
|
52402
|
+
while (at2 < span.length && !/[\s,\]{}#]/.test(span[at2]))
|
|
52403
|
+
at2++;
|
|
52404
|
+
if (!integer.test(span.slice(start, at2)))
|
|
52405
|
+
return false;
|
|
52406
|
+
values2++;
|
|
52407
|
+
}
|
|
52408
|
+
return values2 === Object.keys(counts).length;
|
|
52409
|
+
};
|
|
52410
|
+
let attempts = 0;
|
|
52411
|
+
const realPrefix = (end) => {
|
|
52412
|
+
if (++attempts > 256)
|
|
52413
|
+
return false;
|
|
52414
|
+
try {
|
|
52415
|
+
Bun.TOML.parse(text2.slice(0, end));
|
|
52416
|
+
return true;
|
|
52417
|
+
} catch {
|
|
52418
|
+
return false;
|
|
52419
|
+
}
|
|
52420
|
+
};
|
|
52421
|
+
for (const match of text2.matchAll(/^[ \t]*\[[^\r\n]+\][ \t]*(?:#[^\r\n]*)?(?:\r?\n|$)/gm)) {
|
|
52422
|
+
const start = match.index, end = start + match[0].length;
|
|
52423
|
+
if (realPrefix(end))
|
|
52424
|
+
headers.push({ start, end });
|
|
52425
|
+
}
|
|
52426
|
+
for (let at2 = 0;at2 < headers.length; at2++) {
|
|
52427
|
+
const header = headers[at2];
|
|
52428
|
+
let parsed;
|
|
52429
|
+
try {
|
|
52430
|
+
parsed = Bun.TOML.parse(text2.slice(header.start, header.end));
|
|
52431
|
+
} catch {
|
|
52432
|
+
continue;
|
|
52433
|
+
}
|
|
52434
|
+
if (isRecord3(parsed.tui) && isRecord3(parsed.tui.model_availability_nux) && !Object.keys(parsed.tui.model_availability_nux).length && Object.keys(parsed).length === 1 && Object.keys(parsed.tui).length === 1)
|
|
52435
|
+
spans.push({ start: header.start, end: headers[at2 + 1]?.start ?? text2.length });
|
|
52436
|
+
}
|
|
52437
|
+
for (const match of text2.matchAll(/^[ \t]*(?:(?:tui|"tui"|'tui')[ \t]*\.[ \t]*)?(?:model_availability_nux|"model_availability_nux"|'model_availability_nux')[ \t]*=[ \t]*\{[^\r\n]*(?:\r?\n|$)/gm)) {
|
|
52438
|
+
const start = match.index, end = start + match[0].length;
|
|
52439
|
+
if (realPrefix(end))
|
|
52440
|
+
spans.push({ start, end });
|
|
52441
|
+
}
|
|
52442
|
+
for (const { start, end } of spans) {
|
|
52443
|
+
if (!counterIntegers(text2.slice(start, end)))
|
|
52444
|
+
continue;
|
|
52445
|
+
const remaining = text2.slice(0, start) + text2.slice(end);
|
|
52446
|
+
let parsed;
|
|
52447
|
+
try {
|
|
52448
|
+
parsed = Bun.TOML.parse(remaining);
|
|
52449
|
+
} catch {
|
|
52450
|
+
continue;
|
|
52451
|
+
}
|
|
52452
|
+
stripEmptyTui(parsed);
|
|
52453
|
+
if (isDeepStrictEqual4(parsed, expected))
|
|
52454
|
+
return { config: expected, numericSource: remaining };
|
|
52455
|
+
}
|
|
52456
|
+
return { config, numericSource: text2 };
|
|
52457
|
+
}
|
|
52348
52458
|
function settingsDigest2(text2, version = 2) {
|
|
52349
52459
|
let config;
|
|
52350
52460
|
try {
|
|
@@ -52353,7 +52463,8 @@ function settingsDigest2(text2, version = 2) {
|
|
|
52353
52463
|
throw new Error("Invalid Codex settings witness");
|
|
52354
52464
|
}
|
|
52355
52465
|
need4(isRecord3(config));
|
|
52356
|
-
const
|
|
52466
|
+
const mcp = version >= 3 ? projectRegularCodexMcp(config, text2) : { config, numericSource: text2 };
|
|
52467
|
+
const projected = version === 4 ? projectModelAvailabilityNux(mcp.config, mcp.numericSource) : mcp;
|
|
52357
52468
|
normalize3(projected.config, version);
|
|
52358
52469
|
return sha2(`hasna.skills.codex-settings.v${version}\x00${JSON.stringify([canonical4(projected.config), numericTokens2(projected.numericSource)])}`);
|
|
52359
52470
|
}
|
|
@@ -52398,6 +52509,25 @@ function upgradeCodexSettingsWitnessV3(previous, reviewedSettingsPath) {
|
|
|
52398
52509
|
throw new Error("Codex settings outside the reviewed V3 contract changed; explicit discovery review required");
|
|
52399
52510
|
return { path: previous.path, hashMode: "codex-settings-v3", sha256: sha2562 };
|
|
52400
52511
|
}
|
|
52512
|
+
function hashCodexSettingsReplacementV4(text2, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
52513
|
+
need4(Buffer.byteLength(text2) <= 1024 * 1024 && budget.remaining >= Buffer.byteLength(text2));
|
|
52514
|
+
budget.remaining -= Buffer.byteLength(text2);
|
|
52515
|
+
return settingsDigest2(text2, 4);
|
|
52516
|
+
}
|
|
52517
|
+
function captureCodexSettingsV4(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
52518
|
+
return { path, hashMode: "codex-settings-v4", sha256: settingsDigest2(readNativeSettingsWitnessFile(path, budget, "config.toml"), 4) };
|
|
52519
|
+
}
|
|
52520
|
+
function upgradeCodexSettingsWitnessV4(previous, reviewedSettingsPath) {
|
|
52521
|
+
need4(previous && Object.keys(previous).every((key) => ["path", "hashMode", "sha256"].includes(key)) && (previous.hashMode === undefined || ["bytes", "codex-settings-v1", "codex-settings-v2", "codex-settings-v3"].includes(previous.hashMode)) && /^[a-f0-9]{64}$/.test(previous.sha256));
|
|
52522
|
+
const budget = { remaining: 2 * 1024 * 1024 };
|
|
52523
|
+
const before2 = readNativeSettingsWitnessFile(reviewedSettingsPath, budget, "config.toml"), current = readNativeSettingsWitnessFile(previous.path, budget, "config.toml");
|
|
52524
|
+
const original = previous.hashMode === "codex-settings-v3" ? settingsDigest2(before2, 3) : previous.hashMode === "codex-settings-v2" ? settingsDigest2(before2, 2) : previous.hashMode === "codex-settings-v1" ? hashCodexSettingsReplacement(before2) : sha2(before2);
|
|
52525
|
+
need4(original === previous.sha256);
|
|
52526
|
+
const sha2562 = settingsDigest2(current, 4);
|
|
52527
|
+
if (settingsDigest2(before2, 4) !== sha2562)
|
|
52528
|
+
throw new Error("Codex settings outside the reviewed V4 contract changed; explicit discovery review required");
|
|
52529
|
+
return { path: previous.path, hashMode: "codex-settings-v4", sha256: sha2562 };
|
|
52530
|
+
}
|
|
52401
52531
|
var sha2 = (text2) => createHash12("sha256").update(text2).digest("hex"), EFFORT2, VERBOSITY2, MODEL, CODEX_DISCOVERY_PROJECTION_FIELDS, INFERENCE;
|
|
52402
52532
|
var init_codex_settings_witness = __esm(() => {
|
|
52403
52533
|
init_codex_settings_witness_v1();
|
|
@@ -52540,7 +52670,7 @@ var init_agent_bridge = __esm(() => {
|
|
|
52540
52670
|
});
|
|
52541
52671
|
|
|
52542
52672
|
// src/lib/agent-codex.ts
|
|
52543
|
-
import { isDeepStrictEqual as
|
|
52673
|
+
import { isDeepStrictEqual as isDeepStrictEqual5 } from "util";
|
|
52544
52674
|
function splitTopLevel(value, delimiter2) {
|
|
52545
52675
|
const result2 = [];
|
|
52546
52676
|
let start = 0, square = 0, curly = 0, quote = null, escaped = false;
|
|
@@ -52669,7 +52799,7 @@ function normalizeCodexInlinePathConfig(text2) {
|
|
|
52669
52799
|
const expectedWithoutConfig = structuredClone(before2);
|
|
52670
52800
|
delete expectedWithoutConfig.skills.config;
|
|
52671
52801
|
try {
|
|
52672
|
-
if (
|
|
52802
|
+
if (isDeepStrictEqual5(Bun.TOML.parse(text2.replace(CODEX_SKILL_CONFIG_SECTIONS, "")), expectedWithoutConfig))
|
|
52673
52803
|
return text2;
|
|
52674
52804
|
} catch {}
|
|
52675
52805
|
const matches2 = [];
|
|
@@ -52722,7 +52852,7 @@ function normalizeCodexInlinePathConfig(text2) {
|
|
|
52722
52852
|
try {
|
|
52723
52853
|
const after2 = Bun.TOML.parse(candidate);
|
|
52724
52854
|
const expected = structuredClone(before2);
|
|
52725
|
-
if (
|
|
52855
|
+
if (isDeepStrictEqual5(after2, expected))
|
|
52726
52856
|
matches2.push(candidate);
|
|
52727
52857
|
} catch {}
|
|
52728
52858
|
}
|
|
@@ -52738,11 +52868,11 @@ function assertCodexPathConfigEditable(text2) {
|
|
|
52738
52868
|
delete expected.skills.config;
|
|
52739
52869
|
try {
|
|
52740
52870
|
const withoutSections = Bun.TOML.parse(text2.replace(CODEX_SKILL_CONFIG_SECTIONS, ""));
|
|
52741
|
-
if (
|
|
52871
|
+
if (isDeepStrictEqual5(withoutSections, expected))
|
|
52742
52872
|
return;
|
|
52743
52873
|
const normalized = normalizeCodexInlinePathConfig(text2);
|
|
52744
52874
|
const withoutNormalizedSections = Bun.TOML.parse(normalized.replace(CODEX_SKILL_CONFIG_SECTIONS, ""));
|
|
52745
|
-
if (
|
|
52875
|
+
if (isDeepStrictEqual5(withoutNormalizedSections, expected))
|
|
52746
52876
|
return;
|
|
52747
52877
|
} catch {}
|
|
52748
52878
|
throw codexPathConfigRefusal();
|
|
@@ -52780,7 +52910,7 @@ function disableCodexBundledSkills(text2) {
|
|
|
52780
52910
|
const candidates = new Set;
|
|
52781
52911
|
const consider = (candidate) => {
|
|
52782
52912
|
try {
|
|
52783
|
-
if (
|
|
52913
|
+
if (isDeepStrictEqual5(Bun.TOML.parse(candidate), expected))
|
|
52784
52914
|
candidates.add(candidate);
|
|
52785
52915
|
} catch {}
|
|
52786
52916
|
};
|
|
@@ -52981,7 +53111,7 @@ var init_codex_hook_trust_files = () => {};
|
|
|
52981
53111
|
|
|
52982
53112
|
// src/lib/agent-integration.ts
|
|
52983
53113
|
import { createHash as createHash15, randomUUID as randomUUID5 } from "crypto";
|
|
52984
|
-
import { isDeepStrictEqual as
|
|
53114
|
+
import { isDeepStrictEqual as isDeepStrictEqual6 } from "util";
|
|
52985
53115
|
import { existsSync as existsSync13, lstatSync as lstatSync18, statSync as statSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync14, readdirSync as readdirSync8, opendirSync as opendirSync3, readlinkSync as readlinkSync4, realpathSync as realpathSync8, renameSync as renameSync2, rmdirSync as rmdirSync2, writeFileSync as writeFileSync5, unlinkSync as unlinkSync3, chmodSync, openSync as openSync9, closeSync as closeSync9, fsyncSync as fsyncSync3, fstatSync as fstatSync9, readSync as readSync7, constants as constants10, linkSync as linkSync2 } from "fs";
|
|
52986
53116
|
import { dirname as dirname13, join as join26, resolve as resolve13, relative as relative6, isAbsolute as isAbsolute12, sep as sep6 } from "path";
|
|
52987
53117
|
import { homedir as homedir3 } from "os";
|
|
@@ -53837,7 +53967,7 @@ function projectedHookExecutable(command, expectedResolved) {
|
|
|
53837
53967
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
53838
53968
|
const recheck = () => {
|
|
53839
53969
|
try {
|
|
53840
|
-
if (realpathSync8(command) !== resolved || linkIdentity(lstatSync18(command, { bigint: true })) !== linkIdentity(link2) || !
|
|
53970
|
+
if (realpathSync8(command) !== resolved || linkIdentity(lstatSync18(command, { bigint: true })) !== linkIdentity(link2) || !isDeepStrictEqual6(parents2(), parentIdentity) || !isDeepStrictEqual6(parents2(resolved), resolvedParentIdentity))
|
|
53841
53971
|
hookProjectionRefusal("EXECUTABLE_UNVERIFIED");
|
|
53842
53972
|
projectedHookAcl(cli.file, cli.stat);
|
|
53843
53973
|
projectedHookAcl(manifest.file, manifest.stat);
|
|
@@ -53977,7 +54107,7 @@ function atomicWrite2(path, content) {
|
|
|
53977
54107
|
}
|
|
53978
54108
|
}
|
|
53979
54109
|
function planAgentSettingsWitnessUpgrade(options) {
|
|
53980
|
-
if (options.targetCodexVersion !== undefined && (options.agent !== "codex" || ![2, 3].includes(options.targetCodexVersion)))
|
|
54110
|
+
if (options.targetCodexVersion !== undefined && (options.agent !== "codex" || ![2, 3, 4].includes(options.targetCodexVersion)))
|
|
53981
54111
|
throw new Error("Invalid Codex witness target version");
|
|
53982
54112
|
const home = resolve13(options.home ?? homedir3()), dataDir3 = options.dataDir ?? getDataDirReadOnly();
|
|
53983
54113
|
const snapshot2 = readManagedSkillPolicySnapshot(dataDir3);
|
|
@@ -54000,21 +54130,21 @@ function planAgentSettingsWitnessUpgrade(options) {
|
|
|
54000
54130
|
throw new Error("Settings witness upgrade requires a preserved settings preimage");
|
|
54001
54131
|
const replaced = [previous];
|
|
54002
54132
|
if (options.agent === "codex") {
|
|
54003
|
-
if (previous.hashMode !== undefined && previous.hashMode !== "bytes" && previous.hashMode !== "codex-settings-v1" && !(options.targetCodexVersion === 3 && previous.hashMode === "codex-settings-v2"))
|
|
54133
|
+
if (previous.hashMode !== undefined && previous.hashMode !== "bytes" && previous.hashMode !== "codex-settings-v1" && !((options.targetCodexVersion === 3 || options.targetCodexVersion === 4) && previous.hashMode === "codex-settings-v2") && !(options.targetCodexVersion === 4 && previous.hashMode === "codex-settings-v3"))
|
|
54004
54134
|
throw new Error("Codex settings witness upgrade requires an eligible preserved configuration witness");
|
|
54005
54135
|
const preimage = readCodexSettingsPreimage(options.reviewedPreimage);
|
|
54006
54136
|
for (const source of binding.sources) {
|
|
54007
54137
|
if (source === previous || source.path !== configPath)
|
|
54008
54138
|
continue;
|
|
54009
54139
|
const fields = source.fields;
|
|
54010
|
-
if (source.hashMode !== undefined || source.format !== "toml" || !Array.isArray(fields) || !
|
|
54140
|
+
if (source.hashMode !== undefined || source.format !== "toml" || !Array.isArray(fields) || !isDeepStrictEqual6(fields, [...CODEX_DISCOVERY_PROJECTION_FIELDS]) || typeof source.sha256 !== "string")
|
|
54011
54141
|
throw new Error("Codex settings witness upgrade found an unrecognized configuration witness");
|
|
54012
54142
|
if (projectNativeDiscoveryFields(preimage, "toml", fields, configPath) !== source.sha256)
|
|
54013
54143
|
throw new Error("Reviewed preimage does not explain the Codex discovery projection witness");
|
|
54014
54144
|
replaced.push(source);
|
|
54015
54145
|
}
|
|
54016
54146
|
}
|
|
54017
|
-
const next = options.agent === "claude" ? upgradeClaudeSettingsWitness(previous, options.reviewedPreimage) : options.targetCodexVersion === 3 ? upgradeCodexSettingsWitnessV3(previous, options.reviewedPreimage) : upgradeCodexSettingsWitness(previous, options.reviewedPreimage);
|
|
54147
|
+
const next = options.agent === "claude" ? upgradeClaudeSettingsWitness(previous, options.reviewedPreimage) : options.targetCodexVersion === 4 ? upgradeCodexSettingsWitnessV4(previous, options.reviewedPreimage) : options.targetCodexVersion === 3 ? upgradeCodexSettingsWitnessV3(previous, options.reviewedPreimage) : upgradeCodexSettingsWitness(previous, options.reviewedPreimage);
|
|
54018
54148
|
const rebound = [];
|
|
54019
54149
|
for (const source of binding.sources) {
|
|
54020
54150
|
if (!replaced.includes(source)) {
|
|
@@ -54060,7 +54190,7 @@ function applyAgentIntegrationUnlocked(plan, options = {}, assertCurrent) {
|
|
|
54060
54190
|
const upgrade = plan.settingsWitnessUpgrade;
|
|
54061
54191
|
if (!plan.managedAgentChecks || !plan.observedPolicy?.before)
|
|
54062
54192
|
throw new Error("Invalid settings witness upgrade plan");
|
|
54063
|
-
const verified = planAgentSettingsWitnessUpgrade({ agent: upgrade.agent, ...upgrade.agent === "codex" ? { targetCodexVersion: upgrade.toHashMode === "codex-settings-v3" ? 3 : 2 } : {}, reviewedPreimage: upgrade.reviewedPreimage, home: plan.managedAgentChecks.home, dataDir: plan.dataDir, expectedPolicySha256: sha3(plan.observedPolicy.before), expectedSettingsSha256: upgrade.currentSettingsSha256 });
|
|
54193
|
+
const verified = planAgentSettingsWitnessUpgrade({ agent: upgrade.agent, ...upgrade.agent === "codex" ? { targetCodexVersion: upgrade.toHashMode === "codex-settings-v4" ? 4 : upgrade.toHashMode === "codex-settings-v3" ? 3 : 2 } : {}, reviewedPreimage: upgrade.reviewedPreimage, home: plan.managedAgentChecks.home, dataDir: plan.dataDir, expectedPolicySha256: sha3(plan.observedPolicy.before), expectedSettingsSha256: upgrade.currentSettingsSha256 });
|
|
54064
54194
|
if (JSON.stringify(verified.changes) !== JSON.stringify(plan.changes) || JSON.stringify(verified.settingsWitnessUpgrade) !== JSON.stringify(upgrade))
|
|
54065
54195
|
throw new Error("Settings witness upgrade plan changed");
|
|
54066
54196
|
provenDiscovery = verified.discoveryBefore[0];
|
|
@@ -57400,7 +57530,7 @@ var init_claude_marketplace_registry = __esm(() => {
|
|
|
57400
57530
|
});
|
|
57401
57531
|
|
|
57402
57532
|
// src/lib/codex-hook-trust-layout.ts
|
|
57403
|
-
import { isDeepStrictEqual as
|
|
57533
|
+
import { isDeepStrictEqual as isDeepStrictEqual7 } from "util";
|
|
57404
57534
|
function codexTrustTextWitness(text2, keys2, canonicalize = true) {
|
|
57405
57535
|
const parsed = Bun.TOML.parse(text2), wanted = new Set(keys2);
|
|
57406
57536
|
const headers = [...text2.matchAll(/^[ \t]*(\[[^\r\n]+\])[ \t]*(#[^\r\n]*)?(?:\r?\n|$)/gm)];
|
|
@@ -57465,7 +57595,7 @@ function codexTrustTextWitness(text2, keys2, canonicalize = true) {
|
|
|
57465
57595
|
if (expected.hooks)
|
|
57466
57596
|
delete expected.hooks.state;
|
|
57467
57597
|
try {
|
|
57468
|
-
if (!
|
|
57598
|
+
if (!isDeepStrictEqual7(prune(Bun.TOML.parse(noState)), prune(expected)))
|
|
57469
57599
|
throw fail3();
|
|
57470
57600
|
} catch {
|
|
57471
57601
|
throw fail3();
|
|
@@ -57535,13 +57665,13 @@ var init_codex_hook_trust_layout = () => {};
|
|
|
57535
57665
|
|
|
57536
57666
|
// src/lib/codex-hook-additions-review.ts
|
|
57537
57667
|
import { isAbsolute as isAbsolute17 } from "path";
|
|
57538
|
-
import { isDeepStrictEqual as
|
|
57668
|
+
import { isDeepStrictEqual as isDeepStrictEqual8 } from "util";
|
|
57539
57669
|
function exactKeys2(value, keys2) {
|
|
57540
|
-
need5(value && typeof value === "object" && !Array.isArray(value) &&
|
|
57670
|
+
need5(value && typeof value === "object" && !Array.isArray(value) && isDeepStrictEqual8(Object.keys(value).sort(), [...keys2].sort()), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
|
|
57541
57671
|
}
|
|
57542
57672
|
function readReviewedAdditionTrustStates(proof, before2, current, journalHooks) {
|
|
57543
57673
|
const captured = proofs.get(proof);
|
|
57544
|
-
need5(!!captured && captured.before.file === before2.file && captured.before.sha256 === before2.sha256 && captured.current.file === current.file && captured.current.sha256 === current.sha256 &&
|
|
57674
|
+
need5(!!captured && captured.before.file === before2.file && captured.before.sha256 === before2.sha256 && captured.current.file === current.file && captured.current.sha256 === current.sha256 && isDeepStrictEqual8(captured.journalHooks, journalHooks.map(({ key, currentHash }) => ({ key, currentHash }))), "RECONCILE_ADDITIONS_PROOF_CHANGED");
|
|
57545
57675
|
captured.recheck();
|
|
57546
57676
|
unchanged2(before2);
|
|
57547
57677
|
unchanged2(current);
|
|
@@ -57564,7 +57694,7 @@ function reviewNativeHookAdditions(options) {
|
|
|
57564
57694
|
expectedProducer.hooks.state ??= {};
|
|
57565
57695
|
for (const hook of options.journalHooks)
|
|
57566
57696
|
expectedProducer.hooks.state[hook.key] = { ...expectedProducer.hooks.state[hook.key], enabled: true, trusted_hash: hook.currentHash };
|
|
57567
|
-
need5(
|
|
57697
|
+
need5(isDeepStrictEqual8(expectedProducer, producer) && codexTrustReconcileWitness(options.configBefore.text, originalKeys) === codexTrustReconcileWitness(producerConfig.text, originalKeys) && codexTrustUnmanagedSemantic(options.configBefore.text, originalKeys) === codexTrustUnmanagedSemantic(producerConfig.text, originalKeys), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
|
|
57568
57698
|
need5(Array.isArray(review.additions) && review.additions.length > 0 && review.additions.length <= 20, "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
|
|
57569
57699
|
const expectedHooks = JSON.parse(options.hooksBefore.text), currentHooks = JSON.parse(options.hooksCurrent.text), expectedConfig = structuredClone(producer);
|
|
57570
57700
|
need5(expectedHooks.hooks && typeof expectedHooks.hooks === "object" && !Array.isArray(expectedHooks.hooks), "RECONCILE_ADDITIONS_DECLARATIONS");
|
|
@@ -57593,9 +57723,9 @@ function reviewNativeHookAdditions(options) {
|
|
|
57593
57723
|
expectedHooks.hooks[event] = [...groups, { ...event === "PreToolUse" ? { matcher: hook.matcher } : {}, hooks: [{ type: "command", command: hook.command, timeout: hook.timeoutSec }] }];
|
|
57594
57724
|
expectedConfig.hooks.state[key] = trustState;
|
|
57595
57725
|
}
|
|
57596
|
-
need5(
|
|
57726
|
+
need5(isDeepStrictEqual8(expectedHooks, currentHooks), "RECONCILE_ADDITIONS_DECLARATIONS");
|
|
57597
57727
|
const keys2 = added.map((hook) => hook.key);
|
|
57598
|
-
need5(
|
|
57728
|
+
need5(isDeepStrictEqual8(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");
|
|
57599
57729
|
const inputs = [reviewFile, producerConfig, producerHooks, options.intent, options.policy, options.configBefore, options.configCurrent, options.hooksBefore, options.hooksCurrent];
|
|
57600
57730
|
const recheck = () => {
|
|
57601
57731
|
for (const input of inputs)
|
|
@@ -57618,7 +57748,7 @@ var init_codex_hook_additions_review = __esm(() => {
|
|
|
57618
57748
|
|
|
57619
57749
|
// src/lib/codex-hook-discovery-recovery.ts
|
|
57620
57750
|
import { createHash as createHash19 } from "crypto";
|
|
57621
|
-
import { isDeepStrictEqual as
|
|
57751
|
+
import { isDeepStrictEqual as isDeepStrictEqual9 } from "util";
|
|
57622
57752
|
function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, additions) {
|
|
57623
57753
|
const journalHooks = hooks.map(({ key, currentHash }) => ({ key, currentHash }));
|
|
57624
57754
|
const additionStates = additions ? readReviewedAdditionTrustStates(additions, before2, current, journalHooks) : [];
|
|
@@ -57632,11 +57762,11 @@ function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, addi
|
|
|
57632
57762
|
need5(binding.agent === "codex" && binding.method === "reviewed" && raw.length === 1 && raw[0].sha256 === before2.sha256 && before2.sha256 !== current.sha256, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
|
|
57633
57763
|
need5(raw[0].format === undefined && raw[0].fields === undefined && raw[0].managedPlugins === undefined, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
|
|
57634
57764
|
const typed = binding.sources.filter((source) => source.path === current.file && source.format === "toml");
|
|
57635
|
-
need5(typed.length === 1 && typed[0].hashMode === undefined &&
|
|
57765
|
+
need5(typed.length === 1 && typed[0].hashMode === undefined && isDeepStrictEqual9(typed[0].fields, fields), "RECONCILE_DISCOVERY_TYPED_WITNESS");
|
|
57636
57766
|
const original = structure2(before2.text), actual = structure2(current.text);
|
|
57637
57767
|
const project = (value) => Object.fromEntries(fields.map((field2) => [field2, value[field2] ?? null]));
|
|
57638
57768
|
const projection = sha4(JSON.stringify(project(original)));
|
|
57639
|
-
need5(typed[0].sha256 === projection && sha4(JSON.stringify(project(actual))) === projection &&
|
|
57769
|
+
need5(typed[0].sha256 === projection && sha4(JSON.stringify(project(actual))) === projection && isDeepStrictEqual9(project(original), project(actual)), "RECONCILE_DISCOVERY_TYPED_WITNESS");
|
|
57640
57770
|
const keys2 = [...journalHooks.map((hook) => hook.key), ...additionStates.map((hook) => hook.key)];
|
|
57641
57771
|
need5(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");
|
|
57642
57772
|
const expected = structuredClone(original);
|
|
@@ -57646,7 +57776,7 @@ function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, addi
|
|
|
57646
57776
|
expected.hooks.state[hook.key] = { ...expected.hooks.state[hook.key], enabled: true, trusted_hash: hook.currentHash };
|
|
57647
57777
|
for (const { key, state } of additionStates)
|
|
57648
57778
|
expected.hooks.state[key] = { ...state };
|
|
57649
|
-
need5(
|
|
57779
|
+
need5(isDeepStrictEqual9(expected, actual) && codexTrustReconcileWitness(before2.text, keys2) === codexTrustReconcileWitness(current.text, keys2) && codexTrustUnmanagedSemantic(before2.text, keys2) === codexTrustUnmanagedSemantic(current.text, keys2), "RECONCILE_DISCOVERY_TRUST_WITNESS");
|
|
57650
57780
|
unchanged2(before2);
|
|
57651
57781
|
unchanged2(current);
|
|
57652
57782
|
const witness = Object.freeze({ configPath: current.file, beforeSha256: before2.sha256, currentSha256: current.sha256, discoverySha256: sha4(JSON.stringify(binding)), typedProjectionSha256: projection });
|
|
@@ -57681,7 +57811,7 @@ var init_codex_hook_discovery_recovery = __esm(() => {
|
|
|
57681
57811
|
import { createHash as createHash20 } from "crypto";
|
|
57682
57812
|
import { lstatSync as lstatSync23, readFileSync as readFileSync19, readdirSync as readdirSync11, realpathSync as realpathSync9 } from "fs";
|
|
57683
57813
|
import { basename as basename10, dirname as dirname18, isAbsolute as isAbsolute18, join as join35, resolve as resolve18, sep as sep7 } from "path";
|
|
57684
|
-
import { isDeepStrictEqual as
|
|
57814
|
+
import { isDeepStrictEqual as isDeepStrictEqual10 } from "util";
|
|
57685
57815
|
function parseConfig(text3, path, toml = false) {
|
|
57686
57816
|
try {
|
|
57687
57817
|
const value = toml ? Bun.TOML.parse(text3) : JSON.parse(text3);
|
|
@@ -57720,19 +57850,19 @@ function projectNativeDiscoveryFields(text3, format, fields2, path) {
|
|
|
57720
57850
|
return digest(JSON.stringify(Object.fromEntries(fields2.map((field2) => [field2, object5[field2] ?? null]))));
|
|
57721
57851
|
}
|
|
57722
57852
|
function isSupersededCodexProjection(agent, configPath, source) {
|
|
57723
|
-
return agent === "codex" && source.path === configPath && source.format === "toml" &&
|
|
57853
|
+
return agent === "codex" && source.path === configPath && source.format === "toml" && isDeepStrictEqual10(source.fields, [...CODEX_DISCOVERY_PROJECTION_FIELDS]);
|
|
57724
57854
|
}
|
|
57725
57855
|
function supersedesCodexProjection(sources, configPath) {
|
|
57726
|
-
return sources.some((source) => source.path === configPath && (source.hashMode === "codex-settings-v2" || source.hashMode === "codex-settings-v3"));
|
|
57856
|
+
return sources.some((source) => source.path === configPath && (source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")));
|
|
57727
57857
|
}
|
|
57728
57858
|
function projected(source, changes, budget = discoveryByteBudget()) {
|
|
57729
|
-
if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || source.hashMode === "codex-settings-v3") {
|
|
57859
|
+
if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")) {
|
|
57730
57860
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
57731
57861
|
throw new Error("Codex settings witnesses require exact typed metadata");
|
|
57732
|
-
const current = (source.hashMode === "codex-settings-v3" ? captureCodexSettingsV3 : source.hashMode === "codex-settings-v2" ? captureCodexSettingsV2 : captureCodexSettings)(source.path, budget).sha256;
|
|
57862
|
+
const current = (source.hashMode === "codex-settings-v4" ? captureCodexSettingsV4 : source.hashMode === "codex-settings-v3" ? captureCodexSettingsV3 : source.hashMode === "codex-settings-v2" ? captureCodexSettingsV2 : captureCodexSettings)(source.path, budget).sha256;
|
|
57733
57863
|
if (current !== source.sha256)
|
|
57734
57864
|
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
57735
|
-
return changes?.has(source.path) ? (source.hashMode === "codex-settings-v3" ? hashCodexSettingsReplacementV3 : source.hashMode === "codex-settings-v2" ? hashCodexSettingsReplacementV2 : hashCodexSettingsReplacement)(changes.get(source.path), budget) : current;
|
|
57865
|
+
return changes?.has(source.path) ? (source.hashMode === "codex-settings-v4" ? hashCodexSettingsReplacementV4 : source.hashMode === "codex-settings-v3" ? hashCodexSettingsReplacementV3 : source.hashMode === "codex-settings-v2" ? hashCodexSettingsReplacementV2 : hashCodexSettingsReplacement)(changes.get(source.path), budget) : current;
|
|
57736
57866
|
}
|
|
57737
57867
|
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") {
|
|
57738
57868
|
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
@@ -57828,7 +57958,7 @@ function captureRetiredCodexDiscovery(binding, controls, rules) {
|
|
|
57828
57958
|
return current;
|
|
57829
57959
|
const installation = codexInstallationRoots(binding);
|
|
57830
57960
|
const directories = (binding.directories ?? []).filter((directory) => !installation.some((root2) => directory.path === root2 || directory.path.startsWith(root2 + sep7) || root2.startsWith(directory.path + sep7)));
|
|
57831
|
-
if (previous &&
|
|
57961
|
+
if (previous && isDeepStrictEqual10(previous.roots, roots) && isDeepStrictEqual10(previous.parents, parents3) && isDeepStrictEqual10(previous.directories.map((item) => item.path), directories.map((item) => item.path)))
|
|
57832
57962
|
return { ...current, codexRetiredMaterializations: previous };
|
|
57833
57963
|
return { ...current, codexRetiredMaterializations: { roots, parents: parents3, directories: captureDiscoveryDirectoryProjection(directories.map((item) => item.path), roots) } };
|
|
57834
57964
|
}
|
|
@@ -57904,7 +58034,7 @@ function verifyAgentDiscovery(binding, codexRecovery) {
|
|
|
57904
58034
|
if (omitted.some((root2) => !retiredRoots.includes(root2)))
|
|
57905
58035
|
throw new Error("Missing reviewed directory membership inventory; provide a fresh discovery review");
|
|
57906
58036
|
const current = captureDiscoveryDirectoryProjection(ordinary.map((item) => item.path), retiredRoots).map(({ entries, ...item }) => item);
|
|
57907
|
-
if (!
|
|
58037
|
+
if (!isDeepStrictEqual10(current, projection))
|
|
57908
58038
|
throw new Error("Native discovery directory membership changed outside retired Codex roots");
|
|
57909
58039
|
}
|
|
57910
58040
|
} else
|
|
@@ -57963,7 +58093,7 @@ function codexInstallationRoots(binding) {
|
|
|
57963
58093
|
});
|
|
57964
58094
|
}
|
|
57965
58095
|
function assertMarketplaceBinding(binding, source) {
|
|
57966
|
-
if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || source.hashMode === "codex-settings-v3") && (binding.agent !== "codex" || binding.method !== "reviewed" || basename10(source.path) !== "config.toml"))
|
|
58096
|
+
if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")) && (binding.agent !== "codex" || binding.method !== "reviewed" || basename10(source.path) !== "config.toml"))
|
|
57967
58097
|
throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
|
|
57968
58098
|
if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") && (binding.agent !== "claude" || binding.method !== "reviewed" || basename10(source.path) !== "settings.json"))
|
|
57969
58099
|
throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
|
|
@@ -58152,10 +58282,10 @@ function resolveAgentDiscovery(options) {
|
|
|
58152
58282
|
verifyAgentDiscovery(retained);
|
|
58153
58283
|
if (!retained.sources.some((source) => source.path === canonical6(configPath) && source.format === undefined && source.fields === undefined))
|
|
58154
58284
|
unresolved("retained review is missing the full agent configuration source");
|
|
58155
|
-
if (retained.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || source.hashMode === "codex-settings-v3"))) && source.path !== canonical6(configPath)))
|
|
58285
|
+
if (retained.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !== canonical6(configPath)))
|
|
58156
58286
|
unresolved("retained settings witness names another configuration source");
|
|
58157
58287
|
const covered = supersedesCodexProjection(retained.sources, canonical6(configPath)) ? sources.filter((source) => !isSupersededCodexProjection(agent, canonical6(configPath), source)) : sources;
|
|
58158
|
-
if (covered.some((source) => !retained.sources.some((saved) =>
|
|
58288
|
+
if (covered.some((source) => !retained.sources.some((saved) => isDeepStrictEqual10(saved, source))) || [...roots].some((root2) => !retained.roots.includes(root2)) || agent === "gemini" && JSON.stringify(retained.builtinNames) !== JSON.stringify(builtinNames))
|
|
58159
58289
|
unresolved("retained review is missing current runtime discovery coverage");
|
|
58160
58290
|
return retained;
|
|
58161
58291
|
}
|
|
@@ -58169,7 +58299,7 @@ function resolveAgentDiscovery(options) {
|
|
|
58169
58299
|
if (review.sources.some((source) => source.format !== undefined || source.fields !== undefined))
|
|
58170
58300
|
throw new Error("Explicit discovery reviews require full source-file hashes");
|
|
58171
58301
|
verifyAgentDiscovery(supplied);
|
|
58172
|
-
if (review.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || source.hashMode === "codex-settings-v3"))) && source.path !== canonical6(configPath)))
|
|
58302
|
+
if (review.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2" || (source.hashMode === "codex-settings-v3" || source.hashMode === "codex-settings-v4")))) && source.path !== canonical6(configPath)))
|
|
58173
58303
|
throw new Error("Semantic settings witnesses must name the configured Claude configuration source");
|
|
58174
58304
|
if (!review.sources.some((source) => source.path === canonical6(configPath)))
|
|
58175
58305
|
throw new Error("Discovery review must include the agent configuration source");
|
|
@@ -83098,7 +83228,7 @@ async function persistSignIn(result2, origin, env3 = process.env, issuedBy = "si
|
|
|
83098
83228
|
const created = await new RemoteSkillsAuthClient(origin).request("/api/auth/keys", {
|
|
83099
83229
|
method: "POST",
|
|
83100
83230
|
headers: { Authorization: `Bearer ${result2.token}` },
|
|
83101
|
-
body: JSON.stringify({ name: "cli" })
|
|
83231
|
+
body: JSON.stringify({ name: "cli", scopes: HOSTED_CLI_API_KEY_SCOPES })
|
|
83102
83232
|
});
|
|
83103
83233
|
apiKey = isRecord7(created) && typeof created.key === "string" && created.key.trim() ? created.key : undefined;
|
|
83104
83234
|
}
|
|
@@ -83311,13 +83441,22 @@ function openVerificationPage(url2, signInOrigin) {
|
|
|
83311
83441
|
return false;
|
|
83312
83442
|
}
|
|
83313
83443
|
}
|
|
83314
|
-
var SKILLS_CLI_DEVICE_CLIENT = "skills-cli", SLOW_DOWN_INCREMENT_MS = 5000, MIN_INTERVAL_MS = 1000, MAX_INTERVAL_MS = 60000, DEFAULT_INTERVAL_SECONDS = 5, DEFAULT_EXPIRES_IN_SECONDS = 900, LOOPBACK_HOSTS;
|
|
83444
|
+
var SKILLS_CLI_DEVICE_CLIENT = "skills-cli", HOSTED_CLI_API_KEY_SCOPES, SLOW_DOWN_INCREMENT_MS = 5000, MIN_INTERVAL_MS = 1000, MAX_INTERVAL_MS = 60000, DEFAULT_INTERVAL_SECONDS = 5, DEFAULT_EXPIRES_IN_SECONDS = 900, LOOPBACK_HOSTS;
|
|
83315
83445
|
var init_sign_in = __esm(() => {
|
|
83316
83446
|
init_transport();
|
|
83317
83447
|
init_auth_store();
|
|
83318
83448
|
init_fleet_credentials();
|
|
83319
83449
|
init_instance_credentials();
|
|
83320
83450
|
init_remote_auth();
|
|
83451
|
+
HOSTED_CLI_API_KEY_SCOPES = [
|
|
83452
|
+
"skills:read",
|
|
83453
|
+
"skills:run",
|
|
83454
|
+
"runs:read",
|
|
83455
|
+
"connectors:read",
|
|
83456
|
+
"connectors:write",
|
|
83457
|
+
"billing:read",
|
|
83458
|
+
"billing:write"
|
|
83459
|
+
];
|
|
83321
83460
|
LOOPBACK_HOSTS = new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
83322
83461
|
});
|
|
83323
83462
|
|
|
@@ -84267,7 +84406,7 @@ var init_skill_context = __esm(() => {
|
|
|
84267
84406
|
|
|
84268
84407
|
// src/lib/session-reconciliation.ts
|
|
84269
84408
|
import { createHash as createHash26 } from "crypto";
|
|
84270
|
-
import { isDeepStrictEqual as
|
|
84409
|
+
import { isDeepStrictEqual as isDeepStrictEqual11 } from "util";
|
|
84271
84410
|
function exactTimestamp(value) {
|
|
84272
84411
|
const parsed = value === undefined ? Number.NaN : Date.parse(value);
|
|
84273
84412
|
if (!Number.isFinite(parsed) || new Date(parsed).toISOString() !== value) {
|
|
@@ -84324,7 +84463,7 @@ async function reconcileSkillSessionIfSafe(sessionId, profileId, options = {}) {
|
|
|
84324
84463
|
for (const key of old.loaded) {
|
|
84325
84464
|
const previous = oldByKey.get(key);
|
|
84326
84465
|
const current = targetBySlug.get(previous.slug);
|
|
84327
|
-
if (!current || !
|
|
84466
|
+
if (!current || !isDeepStrictEqual11({ ...previous, profileRevision: target.profileRevision }, current)) {
|
|
84328
84467
|
throw new SkillSelectionError("SESSION_RECONCILIATION_REQUIRED", "A loaded Skills selection was removed or changed; review skills sessions reconcile before changing this session's pin.");
|
|
84329
84468
|
}
|
|
84330
84469
|
}
|
|
@@ -88966,7 +89105,7 @@ var init_execution_grants = __esm(() => {
|
|
|
88966
89105
|
});
|
|
88967
89106
|
|
|
88968
89107
|
// src/lib/execution-grant-client.ts
|
|
88969
|
-
import { isDeepStrictEqual as
|
|
89108
|
+
import { isDeepStrictEqual as isDeepStrictEqual12 } from "util";
|
|
88970
89109
|
function id(value) {
|
|
88971
89110
|
if (!grantIdentifier(value))
|
|
88972
89111
|
throw new Error("Invalid execution grant profile or revision identifier.");
|
|
@@ -89018,7 +89157,7 @@ async function saveExecutionGrantPolicy(profileId, grants, revision) {
|
|
|
89018
89157
|
headers: revision === undefined ? { "If-None-Match": "*" } : { "If-Match": `"${revision}"` },
|
|
89019
89158
|
body: JSON.stringify({ grants: snapshot2 })
|
|
89020
89159
|
}));
|
|
89021
|
-
if (policy.profileId !== profileId || policy.previousRevision !== (revision ?? null) || !
|
|
89160
|
+
if (policy.profileId !== profileId || policy.previousRevision !== (revision ?? null) || !isDeepStrictEqual12(policy.grants, snapshot2)) {
|
|
89022
89161
|
throw new Error("The API did not preserve the reviewed execution grant policy; read it before retrying.");
|
|
89023
89162
|
}
|
|
89024
89163
|
return policy;
|
|
@@ -89029,7 +89168,7 @@ async function resolveExecutionGrant(input2) {
|
|
|
89029
89168
|
if (!grantRecord(value) || Object.keys(value).length !== 3 || !grantIdentifier(value.policyRevision) || !grantIdentifier(value.grantId) || !grantRecord(value.bindings)) {
|
|
89030
89169
|
throw new SkillSelectionError("INVALID_EXECUTION_GRANT", "The Skills API returned an invalid execution grant.");
|
|
89031
89170
|
}
|
|
89032
|
-
if (!
|
|
89171
|
+
if (!isDeepStrictEqual12(value.bindings.selection, snapshot2.selection) || !isDeepStrictEqual12(value.bindings.consumer, snapshot2.consumer)) {
|
|
89033
89172
|
throw new SkillSelectionError("EXECUTION_GRANT_SCOPE_MISMATCH", "The Skills API returned a grant for a different selection or consumer.");
|
|
89034
89173
|
}
|
|
89035
89174
|
return value;
|
|
@@ -113727,7 +113866,7 @@ var init_create_sync_config = __esm(() => {
|
|
|
113727
113866
|
});
|
|
113728
113867
|
|
|
113729
113868
|
// src/lib/codex-native-config.ts
|
|
113730
|
-
import { isDeepStrictEqual as
|
|
113869
|
+
import { isDeepStrictEqual as isDeepStrictEqual13 } from "util";
|
|
113731
113870
|
function isRecord8(value) {
|
|
113732
113871
|
if (!value || typeof value !== "object")
|
|
113733
113872
|
return false;
|
|
@@ -113749,7 +113888,7 @@ function decimalIdentity(text4) {
|
|
|
113749
113888
|
return `${match[1]}${coefficient}e${exponent}`;
|
|
113750
113889
|
}
|
|
113751
113890
|
function codexNativeConfigEqual(native, expected) {
|
|
113752
|
-
if (
|
|
113891
|
+
if (isDeepStrictEqual13(native, expected))
|
|
113753
113892
|
return true;
|
|
113754
113893
|
if (typeof expected === "number") {
|
|
113755
113894
|
if (!Number.isFinite(expected) || !isRecord8(native))
|
|
@@ -113775,7 +113914,7 @@ var init_codex_native_config = () => {};
|
|
|
113775
113914
|
// src/lib/codex-hook-trust-identity.ts
|
|
113776
113915
|
import { realpathSync as realpathSync18 } from "fs";
|
|
113777
113916
|
import { dirname as dirname34, isAbsolute as isAbsolute28, join as join62 } from "path";
|
|
113778
|
-
import { isDeepStrictEqual as
|
|
113917
|
+
import { isDeepStrictEqual as isDeepStrictEqual14 } from "util";
|
|
113779
113918
|
function inspectRecordedSkillsCli(command, expected) {
|
|
113780
113919
|
need5(isAbsolute28(command) && !command.includes("\x00"), "RECONCILE_RECORDED_COMMAND_REQUIRED");
|
|
113781
113920
|
const resolved = realpathSync18(command);
|
|
@@ -113785,7 +113924,7 @@ function inspectRecordedSkillsCli(command, expected) {
|
|
|
113785
113924
|
need5(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join62(dirname34(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
|
|
113786
113925
|
need5((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
|
|
113787
113926
|
const receipt = { path: resolved, version: pkg.version, sha256: cli.sha256, manifestSha256: manifest.sha256 };
|
|
113788
|
-
need5(
|
|
113927
|
+
need5(isDeepStrictEqual14(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
|
|
113789
113928
|
return { receipt, recheck() {
|
|
113790
113929
|
need5(realpathSync18(command) === resolved, "SKILLS_COMMAND_CHANGED");
|
|
113791
113930
|
unchanged2(cli);
|
|
@@ -113821,19 +113960,19 @@ var init_codex_hook_trust_identity = __esm(() => {
|
|
|
113821
113960
|
});
|
|
113822
113961
|
|
|
113823
113962
|
// src/lib/codex-hook-policy-recovery.ts
|
|
113824
|
-
import { isDeepStrictEqual as
|
|
113963
|
+
import { isDeepStrictEqual as isDeepStrictEqual15 } from "util";
|
|
113825
113964
|
function reviewedClaudeDiscoveryChange(beforeText, currentText, options) {
|
|
113826
113965
|
need5(typeof options.reason === "string" && options.reason.trim().length > 0 && options.reason.length <= 512 && !/[\x00-\x1f\x7f]/.test(options.reason), "RECONCILE_RECOVERY_REASON_REQUIRED");
|
|
113827
113966
|
need5(options.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(options.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
|
|
113828
113967
|
const before2 = parseManagedSkillPolicy(beforeText), current = parseManagedSkillPolicy(currentText);
|
|
113829
113968
|
const oldDiscovery = before2.bridge?.discovery?.claude, newDiscovery = current.bridge?.discovery?.claude;
|
|
113830
113969
|
need5(oldDiscovery?.agent === "claude" && newDiscovery?.agent === "claude" && oldDiscovery.method === "reviewed" && newDiscovery.method === "reviewed", "RECONCILE_POLICY_CHANGED");
|
|
113831
|
-
const changes = ["roots", "sources"].filter((key) => !
|
|
113970
|
+
const changes = ["roots", "sources"].filter((key) => !isDeepStrictEqual15(oldDiscovery[key], newDiscovery[key])).map((key) => ({ path: `bridge.discovery.claude.${key}`, before: oldDiscovery[key], after: newDiscovery[key] }));
|
|
113832
113971
|
need5(changes.length > 0, "RECONCILE_POLICY_CHANGED");
|
|
113833
113972
|
const compared = structuredClone(current);
|
|
113834
113973
|
compared.bridge.discovery.claude.roots = oldDiscovery.roots;
|
|
113835
113974
|
compared.bridge.discovery.claude.sources = oldDiscovery.sources;
|
|
113836
|
-
need5(
|
|
113975
|
+
need5(isDeepStrictEqual15(before2, compared), "RECONCILE_POLICY_CHANGED");
|
|
113837
113976
|
verifyAgentDiscovery(newDiscovery);
|
|
113838
113977
|
return { reason: options.reason, changes };
|
|
113839
113978
|
}
|
|
@@ -113849,7 +113988,7 @@ import { createHash as createHash34, randomUUID as randomUUID11 } from "crypto";
|
|
|
113849
113988
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
113850
113989
|
import { dirname as dirname35, isAbsolute as isAbsolute29, join as join63, resolve as resolve27 } from "path";
|
|
113851
113990
|
import { homedir as homedir12 } from "os";
|
|
113852
|
-
import { isDeepStrictEqual as
|
|
113991
|
+
import { isDeepStrictEqual as isDeepStrictEqual16 } from "util";
|
|
113853
113992
|
function verifyReleaseArtifact(proof, skillsCli) {
|
|
113854
113993
|
need5(isAbsolute29(proof.packageTarPath) && !proof.packageTarPath.includes("\x00"), "RECONCILE_RELEASE_PROVENANCE_PATH");
|
|
113855
113994
|
const tarPath = realpathSync19(proof.packageTarPath);
|
|
@@ -113891,7 +114030,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
113891
114030
|
const configSha256 = intent.configSha256 ?? configBefore.sha256, configVersion = intent.configVersion ?? intent.expectedVersion;
|
|
113892
114031
|
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 };
|
|
113893
114032
|
need5(makePlanDigest(digestInput) === intent.planDigest, "RECONCILE_PLAN_CHANGED");
|
|
113894
|
-
need5(
|
|
114033
|
+
need5(isDeepStrictEqual16(intent.hooks, admitted.filter((hook) => !hook.enabled || hook.trustStatus !== "trusted")), "RECONCILE_INTENT_HOOKS_CHANGED");
|
|
113895
114034
|
need5(configBefore.sha256 === (intent.beforeSha256 ?? intent.configSha256) && hooksBefore.sha256 === intent.hooksSha256 && policyBefore.sha256 === intent.policySha256, "RECONCILE_JOURNAL_CHANGED");
|
|
113896
114035
|
const policyCurrent = snapshot(join63(dataDir3, "agent-policy.json"), true);
|
|
113897
114036
|
const { claudeDiscoveryRecovery: claudeRecovery, nativeHookAdditionsRecovery: additionsRecovery } = options;
|
|
@@ -113904,7 +114043,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
113904
114043
|
if (policyCurrent.sha256 !== policyBefore.sha256 && !claudeRecovery) {
|
|
113905
114044
|
need5(options.supersedeBinding === true, "RECONCILE_POLICY_CHANGED");
|
|
113906
114045
|
const oldPolicy = JSON.parse(policyBefore.text), currentPolicy = JSON.parse(policyCurrent.text);
|
|
113907
|
-
need5(
|
|
114046
|
+
need5(isDeepStrictEqual16(withoutCodexCommand(oldPolicy), withoutCodexCommand(currentPolicy)), "RECONCILE_POLICY_CHANGED");
|
|
113908
114047
|
supersededBinding = true;
|
|
113909
114048
|
}
|
|
113910
114049
|
if (supersededBinding || recovery) {
|
|
@@ -113940,7 +114079,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
113940
114079
|
need5(state?.enabled === true && typeof state.trusted_hash === "string" && /^sha256:[a-f0-9]{64}$/.test(state.trusted_hash), "RECONCILE_CONFIG_DRIFT");
|
|
113941
114080
|
}
|
|
113942
114081
|
} else
|
|
113943
|
-
need5(
|
|
114082
|
+
need5(isDeepStrictEqual16(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
|
|
113944
114083
|
const configDiscoveryRecovery = recovery && binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, configBefore, currentConfig, intent.hooks, additions?.trustProof) : undefined;
|
|
113945
114084
|
assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: configDiscoveryRecovery });
|
|
113946
114085
|
const recoveryCli = recovery ? bindSkillsCli("skills", options.reviewedSkillsCli) : undefined;
|
|
@@ -113949,14 +114088,14 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
113949
114088
|
const skillsCli = recovery ? inspectRecordedSkillsCli(binding.commands.codex, intent.skillsCli) : bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
|
|
113950
114089
|
if (supersededBinding)
|
|
113951
114090
|
verifyReleaseArtifact(options.releaseProof, skillsCli);
|
|
113952
|
-
const skillsBindingChanged = !
|
|
114091
|
+
const skillsBindingChanged = !isDeepStrictEqual16(skillsCli.receipt, intent.skillsCli);
|
|
113953
114092
|
need5(!skillsBindingChanged || supersededBinding, "RECONCILE_SKILLS_BINDING_CHANGED");
|
|
113954
114093
|
if (!additions && hooksCurrent.sha256 !== intent.hooksSha256 && hooksCurrent.sha256 !== hooksBefore.sha256) {
|
|
113955
114094
|
need5(supersededBinding, "RECONCILE_HOOKS_CHANGED");
|
|
113956
114095
|
const currentDeclarations = JSON.parse(hooksCurrent.text).hooks;
|
|
113957
114096
|
for (const [event, [nativeEvent]] of Object.entries(eventNames)) {
|
|
113958
114097
|
const command = renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, event);
|
|
113959
|
-
need5(
|
|
114098
|
+
need5(isDeepStrictEqual16(currentDeclarations?.[event], [{ hooks: [{ type: "command", command, timeout: 15 }] }]), "RECONCILE_BINDING_HOOK_CHANGED");
|
|
113960
114099
|
}
|
|
113961
114100
|
}
|
|
113962
114101
|
rpc = await connect({ command: options.codexCommand ?? "codex", home, codexHome });
|
|
@@ -113979,9 +114118,9 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
113979
114118
|
delete identity6.command;
|
|
113980
114119
|
return identity6;
|
|
113981
114120
|
};
|
|
113982
|
-
need5(
|
|
114121
|
+
need5(isDeepStrictEqual16(stable(actual), stable(expected)), "RECONCILE_NATIVE_IDENTITY_CHANGED");
|
|
113983
114122
|
if (!plannedKeys.has(expected.key))
|
|
113984
|
-
need5(
|
|
114123
|
+
need5(isDeepStrictEqual16(actual, expected), "RECONCILE_UNRELATED_HOOK_CHANGED");
|
|
113985
114124
|
}
|
|
113986
114125
|
for (const wanted of intent.hooks) {
|
|
113987
114126
|
const matches2 = nativeHooks.filter((h2) => h2.key === wanted.key || h2.key === wanted.key.replace(join63(home, ".codex/hooks.json"), hooksPath));
|
|
@@ -114000,7 +114139,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
114000
114139
|
const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
|
|
114001
114140
|
need5(layers?.length === 1 && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, current), "RECONCILE_NATIVE_CONFIG_MISMATCH");
|
|
114002
114141
|
const finalDiscovery = await rpc.request("hooks/list", { cwds: [home] });
|
|
114003
|
-
need5(Array.isArray(finalDiscovery?.data) && finalDiscovery.data.length === 1 && finalDiscovery.data[0].cwd === home && !finalDiscovery.data[0].errors?.length && !finalDiscovery.data[0].warnings?.length && (!recordedNativeHooks ||
|
|
114142
|
+
need5(Array.isArray(finalDiscovery?.data) && finalDiscovery.data.length === 1 && finalDiscovery.data[0].cwd === home && !finalDiscovery.data[0].errors?.length && !finalDiscovery.data[0].warnings?.length && (!recordedNativeHooks || isDeepStrictEqual16(finalDiscovery.data[0].hooks.map(safeNativeHook), nativeHooks.map(safeNativeHook))), "RECONCILE_NATIVE_STATE_CHANGED");
|
|
114004
114143
|
const finalConfig = await rpc.request("config/read", { includeLayers: true, cwd: home });
|
|
114005
114144
|
const finalLayers = finalConfig?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
|
|
114006
114145
|
need5(finalLayers?.length === 1 && !finalLayers[0].disabledReason && codexNativeConfigEqual(finalLayers[0].config, current), "RECONCILE_NATIVE_CONFIG_CHANGED");
|
|
@@ -114065,7 +114204,7 @@ async function enrollCodexNativeHooksUnlocked(options, connect) {
|
|
|
114065
114204
|
const groups = declarations[event];
|
|
114066
114205
|
need5(Array.isArray(groups), "DECLARATION_CHANGED");
|
|
114067
114206
|
const matches2 = groups.flatMap((group, gi) => (group.hooks ?? []).flatMap((entry, hi) => entry.command === command ? [{ group, entry, gi, hi }] : []));
|
|
114068
|
-
need5(matches2.length === 1 &&
|
|
114207
|
+
need5(matches2.length === 1 && isDeepStrictEqual16(matches2[0].group, { hooks: [{ type: "command", command, timeout: 15 }] }), "DECLARATION_CHANGED");
|
|
114069
114208
|
expected.push({ event: nativeEvent, key: `${join63(home, ".codex/hooks.json")}:${label}:${matches2[0].gi}:${matches2[0].hi}`, command });
|
|
114070
114209
|
}
|
|
114071
114210
|
codexTrustTextWitness(configFile.text, expected.map((h) => h.key));
|
|
@@ -114131,7 +114270,7 @@ async function enrollCodexNativeHooksUnlocked(options, connect) {
|
|
|
114131
114270
|
save(join63(journal, "hooks.before.json"), hooksFile.bytes);
|
|
114132
114271
|
save(join63(journal, "policy.before.json"), policyFile.bytes);
|
|
114133
114272
|
save(join63(journal, "intent.json"), json2({ ...digestInput, planDigest, hooks: planned, nativeHooks: discovered.map(safeNativeHook) }));
|
|
114134
|
-
need5(
|
|
114273
|
+
need5(isDeepStrictEqual16(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
|
|
114135
114274
|
checkInputs();
|
|
114136
114275
|
let result2;
|
|
114137
114276
|
try {
|
|
@@ -114145,7 +114284,7 @@ async function enrollCodexNativeHooksUnlocked(options, connect) {
|
|
|
114145
114284
|
expectedConfig.hooks.state ??= {};
|
|
114146
114285
|
for (const h of planned)
|
|
114147
114286
|
expectedConfig.hooks.state[h.key] = { ...expectedConfig.hooks.state[h.key], enabled: true, trusted_hash: h.currentHash };
|
|
114148
|
-
need5(
|
|
114287
|
+
need5(isDeepStrictEqual16(structure3(after2.text), expectedConfig) && codexTrustTextWitness(after2.text, keys3) === preservationText, "PRESERVATION_FAILED");
|
|
114149
114288
|
const savedConfig = snapshot(join63(journal, "config.before.toml"), true);
|
|
114150
114289
|
need5(savedConfig.sha256 === configFile.sha256, "JOURNAL_CHANGED");
|
|
114151
114290
|
const discoveryTransition = binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, savedConfig, after2, planned) : undefined;
|
|
@@ -114153,8 +114292,8 @@ async function enrollCodexNativeHooksUnlocked(options, connect) {
|
|
|
114153
114292
|
unchanged2(hooksFile);
|
|
114154
114293
|
assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: discoveryTransition });
|
|
114155
114294
|
const current = await list2(), confirmed = admit(current);
|
|
114156
|
-
need5(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") &&
|
|
114157
|
-
need5(
|
|
114295
|
+
need5(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") && isDeepStrictEqual16(confirmed.map((h) => [h.key, h.currentHash]), admitted.map((h) => [h.key, h.currentHash])), "NATIVE_NOT_ELIGIBLE");
|
|
114296
|
+
need5(isDeepStrictEqual16(current.filter((h) => !keys3.includes(h.key)), discovered.filter((h) => !keys3.includes(h.key))), "UNRELATED_HOOK_CHANGED");
|
|
114158
114297
|
unchanged2(after2);
|
|
114159
114298
|
unchanged2(savedConfig);
|
|
114160
114299
|
unchanged2(hooksFile);
|
|
@@ -114453,18 +114592,18 @@ function registerAgentIntegration(parent) {
|
|
|
114453
114592
|
process.exitCode = 1;
|
|
114454
114593
|
}
|
|
114455
114594
|
});
|
|
114456
|
-
hook.command("witness").requiredOption("--kind <kind>", "claude-settings-v3, claude-settings-v2, codex-settings-v3, codex-settings-v2, codex-settings-v1 or claude-marketplace-registry-v2").requiredOption("--path <path>", "Canonical absolute path to the reviewed settings or registry file").option("--json", "Output the discovery witness as JSON", false).description("Capture an explicit versioned review witness without installing it").action(async (options) => {
|
|
114457
|
-
const capture2 = options.kind === "codex-settings-v3" ? captureCodexSettingsV3 : options.kind === "codex-settings-v2" ? captureCodexSettingsV2 : options.kind === "codex-settings-v1" ? captureCodexSettings : options.kind === "claude-settings-v3" ? captureClaudeSettingsV3 : options.kind === "claude-settings-v2" ? captureClaudeSettingsV2 : options.kind === "claude-marketplace-registry-v2" ? captureClaudeMarketplaceRegistryV2 : null;
|
|
114595
|
+
hook.command("witness").requiredOption("--kind <kind>", "claude-settings-v3, claude-settings-v2, codex-settings-v4, codex-settings-v3, codex-settings-v2, codex-settings-v1 or claude-marketplace-registry-v2").requiredOption("--path <path>", "Canonical absolute path to the reviewed settings or registry file").option("--json", "Output the discovery witness as JSON", false).description("Capture an explicit versioned review witness without installing it").action(async (options) => {
|
|
114596
|
+
const capture2 = options.kind === "codex-settings-v4" ? captureCodexSettingsV4 : options.kind === "codex-settings-v3" ? captureCodexSettingsV3 : options.kind === "codex-settings-v2" ? captureCodexSettingsV2 : options.kind === "codex-settings-v1" ? captureCodexSettings : options.kind === "claude-settings-v3" ? captureClaudeSettingsV3 : options.kind === "claude-settings-v2" ? captureClaudeSettingsV2 : options.kind === "claude-marketplace-registry-v2" ? captureClaudeMarketplaceRegistryV2 : null;
|
|
114458
114597
|
if (!capture2)
|
|
114459
|
-
throw new Error("Unsupported witness kind; select claude-settings-v3, claude-settings-v2, codex-settings-v3, codex-settings-v2, codex-settings-v1 or claude-marketplace-registry-v2");
|
|
114598
|
+
throw new Error("Unsupported witness kind; select claude-settings-v3, claude-settings-v2, codex-settings-v4, codex-settings-v3, codex-settings-v2, codex-settings-v1 or claude-marketplace-registry-v2");
|
|
114460
114599
|
await writeCliOutput(JSON.stringify(capture2(options.path), null, 2));
|
|
114461
114600
|
});
|
|
114462
|
-
hook.command("rebind-settings").requiredOption("--agent <agent>", "claude or codex").requiredOption("--reviewed-preimage <path>", "Exact preserved legacy settings.json or config.toml").requiredOption("--expected-policy-sha256 <sha256>", "Exact current managed policy bytes").requiredOption("--expected-settings-sha256 <sha256>", "Exact current native settings bytes").option("--codex-witness-version <version>", "Explicit target: 2 (legacy default)
|
|
114601
|
+
hook.command("rebind-settings").requiredOption("--agent <agent>", "claude or codex").requiredOption("--reviewed-preimage <path>", "Exact preserved legacy settings.json or config.toml").requiredOption("--expected-policy-sha256 <sha256>", "Exact current managed policy bytes").requiredOption("--expected-settings-sha256 <sha256>", "Exact current native settings bytes").option("--codex-witness-version <version>", "Explicit target: 2 (legacy default) 3 (service tier and model-advertised effort), or 4 (native availability UI counts)").option("--apply", "Apply the explicit semantic witness upgrade with preservation and readback", false).option("--json", "Return the metadata-only plan or receipt", false).description("Explicitly migrate a legacy native settings witness after proving only known preferences changed").action(async (options) => {
|
|
114463
114602
|
try {
|
|
114464
114603
|
if (!["claude", "codex"].includes(options.agent))
|
|
114465
114604
|
throw new Error("Settings witness rebind accepts claude or codex");
|
|
114466
|
-
if (options.codexWitnessVersion !== undefined && !["2", "3"].includes(options.codexWitnessVersion))
|
|
114467
|
-
throw new Error("Codex witness version accepts 2 or
|
|
114605
|
+
if (options.codexWitnessVersion !== undefined && !["2", "3", "4"].includes(options.codexWitnessVersion))
|
|
114606
|
+
throw new Error("Codex witness version accepts 2, 3 or 4");
|
|
114468
114607
|
const plan = planAgentSettingsWitnessUpgrade({ ...options.codexWitnessVersion !== undefined ? { targetCodexVersion: Number(options.codexWitnessVersion) } : {}, agent: options.agent, reviewedPreimage: options.reviewedPreimage, expectedPolicySha256: options.expectedPolicySha256, expectedSettingsSha256: options.expectedSettingsSha256 });
|
|
114469
114608
|
const result2 = options.apply ? applyAgentIntegration(plan) : { changed: [], backups: [] };
|
|
114470
114609
|
const receipt = { applied: options.apply, settingsWitnessUpgrade: plan.settingsWitnessUpgrade, ...result2 };
|
|
@@ -117029,11 +117168,11 @@ async function doLogin(email5, code2, json3, target) {
|
|
|
117029
117168
|
}
|
|
117030
117169
|
if (!json3)
|
|
117031
117170
|
console.log(source_default.green("\u2713 Code sent to " + email5));
|
|
117032
|
-
if (json3 || !isTTY) {
|
|
117033
|
-
console.log(JSON.stringify({ status: "code_sent", email: email5, message: `
|
|
117171
|
+
if (json3 || !isTTY || !process.stderr.isTTY) {
|
|
117172
|
+
console.log(JSON.stringify({ status: "code_sent", email: email5, message: `Supply the fresh six-digit code on stdin to: skills login --email ${email5} --code-stdin${targetFlag(target)}` }));
|
|
117034
117173
|
return;
|
|
117035
117174
|
}
|
|
117036
|
-
const answer = await
|
|
117175
|
+
const answer = await promptCode();
|
|
117037
117176
|
if (answer === null)
|
|
117038
117177
|
return;
|
|
117039
117178
|
code2 = answer;
|
|
@@ -117224,6 +117363,10 @@ Waiting for authentication...`));
|
|
|
117224
117363
|
await finishSignIn(outcome.result, target, json3);
|
|
117225
117364
|
}
|
|
117226
117365
|
async function runLogin(options) {
|
|
117366
|
+
if (options.codeStdin && (!options.email || options.code !== undefined || options.apiKey !== undefined || options.device || options.poll)) {
|
|
117367
|
+
writeCommandError(new Error("--code-stdin requires --email and cannot be combined with --code, --api-key, --device or --poll"), "Invalid login options", options.json);
|
|
117368
|
+
return;
|
|
117369
|
+
}
|
|
117227
117370
|
if (options.apiKey !== undefined && (options.device || options.poll || options.email || options.code)) {
|
|
117228
117371
|
writeCommandError(new Error("--api-key cannot be combined with --device, --poll, --email or --code"), "Invalid login options", options.json);
|
|
117229
117372
|
return;
|
|
@@ -117264,7 +117407,16 @@ async function runLogin(options) {
|
|
|
117264
117407
|
writeCommandError(new Error("Email required. Use: skills login --email you@example.com"), "Email required", options.json);
|
|
117265
117408
|
return;
|
|
117266
117409
|
}
|
|
117267
|
-
|
|
117410
|
+
let code2 = options.code;
|
|
117411
|
+
if (options.codeStdin) {
|
|
117412
|
+
try {
|
|
117413
|
+
code2 = await readCode();
|
|
117414
|
+
} catch (error61) {
|
|
117415
|
+
writeCommandError(error61, "Could not read the verification code", options.json);
|
|
117416
|
+
return;
|
|
117417
|
+
}
|
|
117418
|
+
}
|
|
117419
|
+
await doLogin(email5, code2, options.json, target);
|
|
117268
117420
|
}
|
|
117269
117421
|
async function runLogout(options) {
|
|
117270
117422
|
const result2 = await signOut({ revoke: options.revoke, environmentProfile: getEnvironmentProfile() });
|
|
@@ -117343,7 +117495,7 @@ async function runWhoami(options) {
|
|
|
117343
117495
|
}
|
|
117344
117496
|
}
|
|
117345
117497
|
function withLoginOptions(command) {
|
|
117346
|
-
return command.option("--url <origin>", "Sign in to this Skills server instead of the default (your own instance)").option("--email <email>", "Sign in with an email code (non-interactive with --code)").option("--code <code>", "
|
|
117498
|
+
return command.option("--url <origin>", "Sign in to this Skills server instead of the default (your own instance)").option("--email <email>", "Sign in with an email code (non-interactive with --code-stdin)").option("--code <code>", "Legacy verification code argument; prefer --code-stdin to keep it out of shell history").option("--code-stdin", "Read a previously requested six-digit verification code from stdin").option("--api-key [key]", "Verify and store an API key; with no value, read it from stdin").option("--device", "Print a code to approve on another device; do not open a browser", false).option("--no-open", "Do not open a browser").option("--poll", "Wait for approval, resuming a pending `skills login --device` session", false).option("--poll-timeout-ms <ms>", "Maximum time to wait for approval").option("--json", "Output result as JSON", false);
|
|
117347
117499
|
}
|
|
117348
117500
|
function registerAccountCommands(parent) {
|
|
117349
117501
|
withLoginOptions(parent.command("login").description("Sign in (browser by default; --device, --email or --api-key; --url for your own server)")).action(async (options) => runLogin(options));
|
|
@@ -117401,7 +117553,7 @@ function registerAuth(parent) {
|
|
|
117401
117553
|
writeCommandError(error61, "Failed to add Skills publication scope", options.json);
|
|
117402
117554
|
}
|
|
117403
117555
|
});
|
|
117404
|
-
withLoginOptions(auth.command("login").description("Sign in with browser/device code, email code or an API key (same as `skills login`)").option("--membership-id <id>", "Enroll an exact workspace membership into an explicit HASNA_PROFILE")
|
|
117556
|
+
withLoginOptions(auth.command("login").description("Sign in with browser/device code, email code or an API key (same as `skills login`)").option("--membership-id <id>", "Enroll an exact workspace membership into an explicit HASNA_PROFILE")).action(async (options) => {
|
|
117405
117557
|
if (options.membershipId !== undefined) {
|
|
117406
117558
|
if (options.apiKey || options.device || options.code || options.poll || options.url) {
|
|
117407
117559
|
writeCommandError(new Error("Workspace login uses email and --code-stdin; do not combine it with device, API key, --url or --code login."), "Invalid login options", options.json);
|
|
@@ -117410,10 +117562,6 @@ function registerAuth(parent) {
|
|
|
117410
117562
|
await loginWorkspace({ email: options.email, codeStdin: options.codeStdin, json: options.json, membershipId: options.membershipId });
|
|
117411
117563
|
return;
|
|
117412
117564
|
}
|
|
117413
|
-
if (options.codeStdin) {
|
|
117414
|
-
writeCommandError(new Error("--code-stdin requires --membership-id for this login flow."), "Invalid login options", options.json);
|
|
117415
|
-
return;
|
|
117416
|
-
}
|
|
117417
117565
|
await runLogin(options);
|
|
117418
117566
|
});
|
|
117419
117567
|
auth.command("signup").description("Create or sign in with your email (passwordless)").option("--url <origin>", "Sign up on this Skills server instead of the default (your own instance)").option("--email <email>", "Email address (non-interactive)").option("--code <code>", "Verification code (non-interactive)").option("--json", "Output result as JSON without prompting", false).action(async (options) => {
|
|
@@ -117452,6 +117600,7 @@ function registerAuth(parent) {
|
|
|
117452
117600
|
var isTTY, DEFAULT_DEVICE_POLL_TIMEOUT_MS, CONFIG_HINT_STATUSES;
|
|
117453
117601
|
var init_auth = __esm(() => {
|
|
117454
117602
|
init_workspace_selection();
|
|
117603
|
+
init_customer_verification();
|
|
117455
117604
|
init_workspace_profile();
|
|
117456
117605
|
init_source();
|
|
117457
117606
|
init_auth_store();
|