@hasna/skills 0.10.77 → 0.10.78
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 +39 -1
- package/bin/index.js +547 -283
- package/bin/mcp.js +93 -17
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/cli/commands/runtime-mcp.d.ts +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +56 -8
- package/dist/lib/mcp-registration-environment.d.ts +2 -0
- package/dist/lib/private-publication-customer.d.ts +6 -2
- package/dist/lib/registry-types.d.ts +2 -0
- package/dist/lib/remote-private-publications.d.ts +22 -0
- package/dist/runtime-prerequisites.js +3 -2
- package/dist/sdk/index.d.ts +1 -1
- package/dist/sdk/index.js +53 -7
- package/package.json +1 -1
package/bin/index.js
CHANGED
|
@@ -36888,7 +36888,7 @@ var package_default;
|
|
|
36888
36888
|
var init_package = __esm(() => {
|
|
36889
36889
|
package_default = {
|
|
36890
36890
|
name: "@hasna/skills",
|
|
36891
|
-
version: "0.10.
|
|
36891
|
+
version: "0.10.78",
|
|
36892
36892
|
description: "Skills library for AI coding agents",
|
|
36893
36893
|
type: "module",
|
|
36894
36894
|
bin: {
|
|
@@ -40398,7 +40398,8 @@ var init_codex_native_compatibility = __esm(() => {
|
|
|
40398
40398
|
"codex-cli 0.160.1": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
40399
40399
|
"codex-cli 0.161.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
40400
40400
|
"codex-cli 0.162.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
40401
|
-
"codex-cli 0.162.1": ["hooks", "qualified-skill-catalog", "installed-plugin-review"]
|
|
40401
|
+
"codex-cli 0.162.1": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
|
|
40402
|
+
"codex-cli 0.163.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"]
|
|
40402
40403
|
};
|
|
40403
40404
|
SUPPORTED_CODEX_HOOK_VERSIONS = Object.freeze(Object.keys(MEASURED_CODEX_CAPABILITIES).filter((version) => supportsCodexNativeCapability(version, "hooks")));
|
|
40404
40405
|
});
|
|
@@ -66746,6 +66747,24 @@ var init_remote_workspace_selection = __esm(() => {
|
|
|
66746
66747
|
|
|
66747
66748
|
// src/lib/remote-private-publications.ts
|
|
66748
66749
|
import { createHash as createHash30 } from "crypto";
|
|
66750
|
+
function checkedPrivateSkillCreate(value) {
|
|
66751
|
+
const refuse6 = (field3, accepted) => {
|
|
66752
|
+
throw new PrivatePublicationError("INVALID_SKILL_CREATE_INPUT", `Invalid ${field3}. ${accepted}`);
|
|
66753
|
+
};
|
|
66754
|
+
if (!record7(value) || !Object.keys(value).every((key2) => ["slug", "displayName", "description", "visibility", "confirm"].includes(key2)))
|
|
66755
|
+
return refuse6("create input", "Provide only slug, displayName, description, visibility and confirm.");
|
|
66756
|
+
if (value.confirm !== true)
|
|
66757
|
+
throw new PrivatePublicationError("SKILL_CREATE_CONFIRM_REQUIRED", "Explicit confirmation is required to create this skill.");
|
|
66758
|
+
if (typeof value.slug !== "string" || value.slug.length > 128 || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(value.slug))
|
|
66759
|
+
return refuse6("slug", "Use lowercase kebab-case, at most 128 characters.");
|
|
66760
|
+
if (typeof value.displayName !== "string" || !value.displayName.trim() || value.displayName.length > 256 || /[\p{Cc}\p{Cs}\u2028\u2029]/u.test(value.displayName))
|
|
66761
|
+
return refuse6("displayName", "Use nonempty text, at most 256 characters, without control characters.");
|
|
66762
|
+
if (value.description !== undefined && (typeof value.description !== "string" || Buffer.byteLength(value.description) > 8192 || /[\p{Cc}\p{Cs}]/u.test(value.description.replace(/[\r\n\t]/g, ""))))
|
|
66763
|
+
return refuse6("description", "Use text of at most 8192 UTF-8 bytes, without control characters other than tabs and newlines.");
|
|
66764
|
+
if (value.visibility !== undefined && value.visibility !== "private" && value.visibility !== "team")
|
|
66765
|
+
return refuse6("visibility", "Use private or team.");
|
|
66766
|
+
return Object.freeze({ slug: value.slug, displayName: value.displayName.trim(), description: value.description ?? "", visibility: value.visibility ?? "private" });
|
|
66767
|
+
}
|
|
66749
66768
|
function checkedPublicationDeclaration(value) {
|
|
66750
66769
|
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)
|
|
66751
66770
|
return bad();
|
|
@@ -66765,11 +66784,11 @@ function checkedPublicationView(value, skillId, intentId, declaration) {
|
|
|
66765
66784
|
return invalid3();
|
|
66766
66785
|
return Object.freeze({ ...value });
|
|
66767
66786
|
}
|
|
66768
|
-
async function boundedJson(url, init, token, mutation, budget2 = 15000, signal) {
|
|
66787
|
+
async function boundedJson(url, init, token, mutation, budget2 = 15000, signal, create3 = false) {
|
|
66769
66788
|
const controller = new AbortController;
|
|
66770
66789
|
let reader;
|
|
66771
66790
|
let response;
|
|
66772
|
-
const timeout = new PrivatePublicationError("PUBLICATION_UNCONFIRMED", "No confirmed publication result. Inspect the saved intent before retrying.", mutation);
|
|
66791
|
+
const timeout = new PrivatePublicationError(create3 ? "SKILL_CREATE_UNCONFIRMED" : "PUBLICATION_UNCONFIRMED", create3 ? "Skill creation could not be confirmed. Inspect the workspace for this slug before another create; do not retry automatically." : "No confirmed publication result. Inspect the saved intent before retrying.", mutation);
|
|
66773
66792
|
let timer;
|
|
66774
66793
|
let abort;
|
|
66775
66794
|
try {
|
|
@@ -66809,11 +66828,19 @@ async function boundedJson(url, init, token, mutation, budget2 = 15000, signal)
|
|
|
66809
66828
|
return invalid3();
|
|
66810
66829
|
}
|
|
66811
66830
|
if (!response.ok) {
|
|
66812
|
-
const
|
|
66813
|
-
|
|
66814
|
-
|
|
66831
|
+
const known = create3 ? skillCreateFailures : failures;
|
|
66832
|
+
const code = record7(body) && typeof body.code === "string" && Object.hasOwn(known, body.code) ? body.code : null;
|
|
66833
|
+
if (code && known[code][0] === response.status)
|
|
66834
|
+
throw new PrivatePublicationError(code, known[code][1], mutation && code === "PUBLICATION_UNCERTAIN", response.status);
|
|
66835
|
+
if (create3) {
|
|
66836
|
+
if (response.status >= 500)
|
|
66837
|
+
throw timeout;
|
|
66838
|
+
throw new PrivatePublicationError("SKILL_CREATE_REQUEST_FAILED", "The server refused skill creation.", false, response.status);
|
|
66839
|
+
}
|
|
66815
66840
|
throw new PrivatePublicationError("PUBLICATION_REQUEST_FAILED", "The publication request was refused. Inspect its status before retrying.", mutation && response.status >= 500, response.status);
|
|
66816
66841
|
}
|
|
66842
|
+
if (create3 && response.status !== 201)
|
|
66843
|
+
return invalid3();
|
|
66817
66844
|
return body;
|
|
66818
66845
|
})(), new Promise((_, reject2) => {
|
|
66819
66846
|
abort = () => {
|
|
@@ -66860,6 +66887,15 @@ class RemotePrivatePublicationsClient {
|
|
|
66860
66887
|
this.membershipId = checked.user.membershipId;
|
|
66861
66888
|
Object.freeze(this);
|
|
66862
66889
|
}
|
|
66890
|
+
async createSkill(input, options = {}) {
|
|
66891
|
+
const body = checkedPrivateSkillCreate(input);
|
|
66892
|
+
if (options.timeoutMs !== undefined && (!Number.isSafeInteger(options.timeoutMs) || options.timeoutMs < 1 || options.timeoutMs > 15000))
|
|
66893
|
+
throw new PrivatePublicationError("INVALID_SKILL_CREATE_INPUT", "Invalid timeoutMs. Use an integer from 1 to 15000.");
|
|
66894
|
+
const value = await boundedJson(skillsApiRequestUrl(this.apiOrigin, "/api/v1/skills"), { method: "POST", body: JSON.stringify(body) }, this.#token, true, options.timeoutMs, options.signal, true);
|
|
66895
|
+
if (!record7(value) || !publicationUuid(value.id) || value.slug !== body.slug || value.displayName !== body.displayName || value.description !== body.description || value.visibility !== body.visibility || value.sourceType !== "private_hosted" || !record7(value.metadata) || value.metadata.ownerOrganizationId !== this.organizationId)
|
|
66896
|
+
throw new PrivatePublicationError("SKILL_CREATE_UNCONFIRMED", "Skill creation returned an unbound result. Inspect the workspace for this slug before another create; do not retry automatically.", true);
|
|
66897
|
+
return Object.freeze({ id: value.id, slug: body.slug, visibility: body.visibility, sourceType: "private_hosted", ownerOrganizationId: this.organizationId });
|
|
66898
|
+
}
|
|
66863
66899
|
async getCapability(options = {}) {
|
|
66864
66900
|
if (options.timeoutMs !== undefined && (!Number.isSafeInteger(options.timeoutMs) || options.timeoutMs < 1 || options.timeoutMs > 15000))
|
|
66865
66901
|
return bad();
|
|
@@ -67002,7 +67038,7 @@ class RemotePrivatePublicationsClient {
|
|
|
67002
67038
|
}
|
|
67003
67039
|
}
|
|
67004
67040
|
}
|
|
67005
|
-
var PRIVATE_PUBLICATION_MAX_BYTES, failures, PrivatePublicationError, bad = () => {
|
|
67041
|
+
var PRIVATE_PUBLICATION_MAX_BYTES, skillCreateFailures, failures, PrivatePublicationError, bad = () => {
|
|
67006
67042
|
throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Invalid publication input or recovery data.");
|
|
67007
67043
|
}, invalid3 = () => {
|
|
67008
67044
|
throw new PrivatePublicationError("INVALID_PUBLICATION_RESPONSE", "The server returned an invalid publication result.");
|
|
@@ -67012,6 +67048,16 @@ var init_remote_private_publications = __esm(() => {
|
|
|
67012
67048
|
init_remote_workspace_selection();
|
|
67013
67049
|
init_skill_contract();
|
|
67014
67050
|
PRIVATE_PUBLICATION_MAX_BYTES = 16 * 1024 * 1024;
|
|
67051
|
+
skillCreateFailures = {
|
|
67052
|
+
INVALID_SLUG: [400, "Provide a lowercase kebab-case skill slug."],
|
|
67053
|
+
INVALID_DISPLAY_NAME: [400, "Provide a nonempty skill display name."],
|
|
67054
|
+
INVALID_VISIBILITY: [400, "Use private or team visibility for source publication."],
|
|
67055
|
+
SESSION_EXPIRED: [401, "Sign in again before creating a private skill."],
|
|
67056
|
+
INTERACTIVE_SESSION_REQUIRED: [403, "An interactive account session is required to create a private skill."],
|
|
67057
|
+
ACCOUNT_UNAVAILABLE: [403, "The current account membership cannot create a private skill."],
|
|
67058
|
+
PLAN_REQUIRED: [403, "Private and team skills require the Pro plan."],
|
|
67059
|
+
SLUG_CONFLICT: [409, "This skill slug already exists. Inspect the existing skill before publishing."]
|
|
67060
|
+
};
|
|
67015
67061
|
failures = {
|
|
67016
67062
|
INVALID_REQUEST: [400, "The publication request is invalid."],
|
|
67017
67063
|
SESSION_EXPIRED: [401, "Sign in again to manage this publication."],
|
|
@@ -88997,6 +89043,7 @@ function normalizeRemoteSkill(skill) {
|
|
|
88997
89043
|
if (!name)
|
|
88998
89044
|
throw new Error("Remote skill requires name or slug");
|
|
88999
89045
|
return {
|
|
89046
|
+
...skill.id !== undefined ? { id: skill.id } : {},
|
|
89000
89047
|
name,
|
|
89001
89048
|
displayName: skill.displayName || titleize(name),
|
|
89002
89049
|
description: skill.description || "",
|
|
@@ -89115,11 +89162,12 @@ var init_remote_registry = __esm(() => {
|
|
|
89115
89162
|
details: exports_external.array(exports_external.string()).optional()
|
|
89116
89163
|
}).passthrough();
|
|
89117
89164
|
remoteSkillSchema = exports_external.object({
|
|
89165
|
+
id: exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/).optional(),
|
|
89118
89166
|
name: exports_external.string().min(1).optional(),
|
|
89119
89167
|
slug: exports_external.string().min(1).optional(),
|
|
89120
89168
|
displayName: exports_external.string().optional(),
|
|
89121
89169
|
description: exports_external.string().optional(),
|
|
89122
|
-
category: exports_external.string().optional(),
|
|
89170
|
+
category: exports_external.string().nullable().optional(),
|
|
89123
89171
|
tags: exports_external.array(exports_external.string()).optional(),
|
|
89124
89172
|
dependencies: exports_external.array(exports_external.string()).optional(),
|
|
89125
89173
|
version: exports_external.string().optional(),
|
|
@@ -99568,6 +99616,43 @@ var init_run_state = __esm(() => {
|
|
|
99568
99616
|
init_project_state();
|
|
99569
99617
|
});
|
|
99570
99618
|
|
|
99619
|
+
// src/lib/mcp-registration-environment.ts
|
|
99620
|
+
import { isAbsolute as isAbsolute33 } from "path";
|
|
99621
|
+
function skillsMcpRegistrationEnvironment(env3 = process.env, origin) {
|
|
99622
|
+
const result2 = {};
|
|
99623
|
+
const profile = selectedSkillsProfile(env3);
|
|
99624
|
+
if (profile)
|
|
99625
|
+
result2[CREDENTIAL_PROFILE_ENV_KEY] = profile;
|
|
99626
|
+
for (const key2 of ["HASNA_HOME", "HASNA_CONFIG_HOME"]) {
|
|
99627
|
+
const value = env3[key2];
|
|
99628
|
+
if (value === undefined)
|
|
99629
|
+
continue;
|
|
99630
|
+
if (!isAbsolute33(value) || /[\x00-\x1f\x7f]/.test(value))
|
|
99631
|
+
throw new Error(`Invalid ${key2}; expected an absolute configuration path`);
|
|
99632
|
+
result2[key2] = value;
|
|
99633
|
+
}
|
|
99634
|
+
if (origin !== undefined || urlKeys2.some((key2) => env3[key2] !== undefined)) {
|
|
99635
|
+
try {
|
|
99636
|
+
const source = origin === undefined ? env3 : { ...env3, ...Object.fromEntries(urlKeys2.map((key2) => [key2, origin])) };
|
|
99637
|
+
const configured = configuredSkillsApiUrl(source);
|
|
99638
|
+
if (!configured)
|
|
99639
|
+
throw new Error;
|
|
99640
|
+
for (const key2 of urlKeys2)
|
|
99641
|
+
result2[key2] = configured.value;
|
|
99642
|
+
} catch {
|
|
99643
|
+
throw new Error("Invalid Skills MCP API URL; expected matching HTTPS or loopback HTTP origins without credentials, query or fragment");
|
|
99644
|
+
}
|
|
99645
|
+
}
|
|
99646
|
+
return Object.freeze(result2);
|
|
99647
|
+
}
|
|
99648
|
+
var urlKeys2;
|
|
99649
|
+
var init_mcp_registration_environment = __esm(() => {
|
|
99650
|
+
init_transport();
|
|
99651
|
+
init_instance_credentials();
|
|
99652
|
+
init_fleet_credentials();
|
|
99653
|
+
urlKeys2 = clientTransportEnvKeys("skills").apiUrlKeys;
|
|
99654
|
+
});
|
|
99655
|
+
|
|
99571
99656
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
|
|
99572
99657
|
function assertCompleteRequestPrompt(request2) {
|
|
99573
99658
|
if (request2.params.ref.type !== "ref/prompt") {
|
|
@@ -111906,7 +111991,7 @@ var init_recurring_customer = __esm(() => {
|
|
|
111906
111991
|
|
|
111907
111992
|
// src/lib/recurring-recovery.ts
|
|
111908
111993
|
import { constants as constants26, closeSync as closeSync27, fsyncSync as fsyncSync8, fstatSync as fstatSync27, lstatSync as lstatSync37, mkdirSync as mkdirSync21, openSync as openSync27, readSync as readSync19, realpathSync as realpathSync17, renameSync as renameSync12, unlinkSync as unlinkSync8, writeFileSync as writeFileSync19 } from "fs";
|
|
111909
|
-
import { dirname as dirname35, isAbsolute as
|
|
111994
|
+
import { dirname as dirname35, isAbsolute as isAbsolute34, join as join59, resolve as resolve34 } from "path";
|
|
111910
111995
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
111911
111996
|
|
|
111912
111997
|
class RecoveryOwner {
|
|
@@ -111914,7 +111999,7 @@ class RecoveryOwner {
|
|
|
111914
111999
|
parents = [];
|
|
111915
112000
|
constructor(directory2) {
|
|
111916
112001
|
this.directory = directory2;
|
|
111917
|
-
if (!
|
|
112002
|
+
if (!isAbsolute34(directory2) || resolve34(directory2) !== directory2 || realpathSync17(directory2) !== directory2)
|
|
111918
112003
|
invalid6();
|
|
111919
112004
|
for (let path = directory2;; path = dirname35(path)) {
|
|
111920
112005
|
const stat3 = lstatSync37(path);
|
|
@@ -112049,7 +112134,7 @@ function base2(customer, organizationId) {
|
|
|
112049
112134
|
};
|
|
112050
112135
|
}
|
|
112051
112136
|
function create3(directory2, intent) {
|
|
112052
|
-
if (!
|
|
112137
|
+
if (!isAbsolute34(directory2) || resolve34(directory2) !== directory2 || realpathSync17(dirname35(directory2)) !== dirname35(directory2))
|
|
112053
112138
|
invalid6();
|
|
112054
112139
|
mkdirSync21(directory2, { mode: 448 });
|
|
112055
112140
|
const owner2 = new RecoveryOwner(directory2), checked = intentSchema.parse(intent), intentSha256 = canonicalJsonSha256(checked);
|
|
@@ -112212,7 +112297,7 @@ var init_recurring_recovery = __esm(() => {
|
|
|
112212
112297
|
});
|
|
112213
112298
|
|
|
112214
112299
|
// src/lib/recurring-surface.ts
|
|
112215
|
-
import { isAbsolute as
|
|
112300
|
+
import { isAbsolute as isAbsolute35 } from "path";
|
|
112216
112301
|
function recurringMcpSchema(action) {
|
|
112217
112302
|
return action === "activate" ? recurringSurfaceSchemas.activate.extend({ code, confirm: exports_external.literal(true) }) : recurringSurfaceSchemas[action];
|
|
112218
112303
|
}
|
|
@@ -112317,7 +112402,7 @@ var init_recurring_surface = __esm(() => {
|
|
|
112317
112402
|
uuid12 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
|
|
112318
112403
|
context = { userId: uuid12.optional(), membershipId: uuid12.optional() };
|
|
112319
112404
|
page2 = { limit: exports_external.number().int().min(1).max(100).optional(), cursor: exports_external.string().min(1).max(2048).optional() };
|
|
112320
|
-
directory2 = exports_external.string().max(4096).refine(
|
|
112405
|
+
directory2 = exports_external.string().max(4096).refine(isAbsolute35, "Use an absolute recovery directory");
|
|
112321
112406
|
email4 = exports_external.string().trim().toLowerCase().email().max(254);
|
|
112322
112407
|
code = exports_external.string().regex(/^\d{6}$/);
|
|
112323
112408
|
recurringSurfaceSchemas = {
|
|
@@ -115103,15 +115188,42 @@ var init_remote_invitation_tools = __esm(() => {
|
|
|
115103
115188
|
});
|
|
115104
115189
|
|
|
115105
115190
|
// src/lib/private-publication-customer.ts
|
|
115191
|
+
function preparePrivatePublicationSession(requested) {
|
|
115192
|
+
const selectors = [
|
|
115193
|
+
"HASNA_PROFILE",
|
|
115194
|
+
"HASNA_HOME",
|
|
115195
|
+
"HASNA_CONFIG_HOME",
|
|
115196
|
+
"HASNA_STATION",
|
|
115197
|
+
"HASNA_SKILLS_API_URL",
|
|
115198
|
+
"SKILLS_API_URL",
|
|
115199
|
+
"HASNA_SKILLS_API_KEY_OVERRIDE",
|
|
115200
|
+
"HASNA_SKILLS_API_KEY_REF",
|
|
115201
|
+
"HASNA_SKILLS_API_KEY",
|
|
115202
|
+
"SKILLS_API_KEY"
|
|
115203
|
+
];
|
|
115204
|
+
const before2 = new Map(selectors.map((key2) => [key2, process.env[key2]]));
|
|
115205
|
+
const profile = selectedSkillsProfile(process.env), pending = prepareProfileWorkspace("Manage private publications");
|
|
115206
|
+
const captured = requested ? { ...requested } : undefined;
|
|
115207
|
+
const unchanged3 = () => {
|
|
115208
|
+
if (selectors.some((key2) => process.env[key2] !== before2.get(key2)) || selectedSkillsProfile(process.env) !== profile)
|
|
115209
|
+
throw new PrivatePublicationError("PUBLICATION_TARGET_CHANGED", "The selected profile or server changed during verification. Start again with a stable target; no skill action was sent.");
|
|
115210
|
+
};
|
|
115211
|
+
return { origin: pending.origin, async verify(email5, code2) {
|
|
115212
|
+
unchanged3();
|
|
115213
|
+
const target = await pending.resolve();
|
|
115214
|
+
const context2 = captured ?? target.context;
|
|
115215
|
+
if (!context2 || !publicationUuid(context2.userId) || !publicationUuid(context2.membershipId) || target.context && (context2.userId !== target.context.userId || context2.membershipId !== target.context.membershipId))
|
|
115216
|
+
throw new PrivatePublicationError("PUBLICATION_CONTEXT_REQUIRED", "Provide the observed user and membership IDs, or select an enrolled workspace profile.");
|
|
115217
|
+
unchanged3();
|
|
115218
|
+
target.unchanged();
|
|
115219
|
+
const client2 = await new RemoteSkillsAuthClient(target.origin).openPrivatePublications(email5, code2, context2);
|
|
115220
|
+
unchanged3();
|
|
115221
|
+
target.unchanged();
|
|
115222
|
+
return client2;
|
|
115223
|
+
} };
|
|
115224
|
+
}
|
|
115106
115225
|
async function privatePublicationSession(email5, code2, requested) {
|
|
115107
|
-
|
|
115108
|
-
const context2 = requested ?? target.context;
|
|
115109
|
-
if (!context2 || !publicationUuid(context2.userId) || !publicationUuid(context2.membershipId) || target.context && (context2.userId !== target.context.userId || context2.membershipId !== target.context.membershipId))
|
|
115110
|
-
throw new PrivatePublicationError("PUBLICATION_CONTEXT_REQUIRED", "Provide the observed user and membership IDs, or select an enrolled workspace profile.");
|
|
115111
|
-
target.unchanged();
|
|
115112
|
-
const client2 = await new RemoteSkillsAuthClient(target.origin).openPrivatePublications(email5, code2, context2);
|
|
115113
|
-
target.unchanged();
|
|
115114
|
-
return client2;
|
|
115226
|
+
return preparePrivatePublicationSession(requested).verify(email5, code2);
|
|
115115
115227
|
}
|
|
115116
115228
|
function privatePublicationCustomerError(error61) {
|
|
115117
115229
|
return error61 instanceof PrivatePublicationError ? { error: error61.message, code: error61.code, uncertain: error61.uncertain } : { error: "The publication action could not be confirmed. Preserve the recovery directory and inspect the same intent; credentials were not changed.", code: "PUBLICATION_ACTION_UNCONFIRMED", uncertain: true };
|
|
@@ -115120,14 +115232,15 @@ var init_private_publication_customer = __esm(() => {
|
|
|
115120
115232
|
init_remote_auth();
|
|
115121
115233
|
init_remote_private_publications();
|
|
115122
115234
|
init_workspace_profile();
|
|
115235
|
+
init_instance_credentials();
|
|
115123
115236
|
});
|
|
115124
115237
|
|
|
115125
115238
|
// src/lib/private-publication-recovery.ts
|
|
115126
115239
|
import { constants as constants27, closeSync as closeSync28, fsyncSync as fsyncSync9, fstatSync as fstatSync28, lstatSync as lstatSync38, mkdirSync as mkdirSync25, openSync as openSync28, readSync as readSync20, realpathSync as realpathSync18, renameSync as renameSync13, unlinkSync as unlinkSync9, writeFileSync as writeFileSync22 } from "fs";
|
|
115127
|
-
import { dirname as dirname38, isAbsolute as
|
|
115240
|
+
import { dirname as dirname38, isAbsolute as isAbsolute36, join as join64, resolve as resolve35 } from "path";
|
|
115128
115241
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
115129
115242
|
function safeDirectory(directory3) {
|
|
115130
|
-
if (!
|
|
115243
|
+
if (!isAbsolute36(directory3) || directory3 !== resolve35(directory3) || realpathSync18(directory3) !== directory3)
|
|
115131
115244
|
return fail5();
|
|
115132
115245
|
for (let path = directory3;; path = dirname38(path)) {
|
|
115133
115246
|
const stat3 = lstatSync38(path);
|
|
@@ -115265,7 +115378,7 @@ async function preparePrivatePublication(client2, sourceDirectory, recoveryDirec
|
|
|
115265
115378
|
phase: "prepared",
|
|
115266
115379
|
intent: null
|
|
115267
115380
|
};
|
|
115268
|
-
if (!
|
|
115381
|
+
if (!isAbsolute36(recoveryDirectory) || resolve35(recoveryDirectory) !== recoveryDirectory || realpathSync18(dirname38(recoveryDirectory)) !== dirname38(recoveryDirectory))
|
|
115269
115382
|
return fail5();
|
|
115270
115383
|
mkdirSync25(recoveryDirectory, { mode: 448 });
|
|
115271
115384
|
safeDirectory(recoveryDirectory);
|
|
@@ -115366,10 +115479,10 @@ var init_private_publication_recovery = __esm(() => {
|
|
|
115366
115479
|
});
|
|
115367
115480
|
|
|
115368
115481
|
// src/mcp/private-publication-tools.ts
|
|
115369
|
-
import { isAbsolute as
|
|
115482
|
+
import { isAbsolute as isAbsolute37 } from "path";
|
|
115370
115483
|
function registerPrivatePublicationTools(server) {
|
|
115371
115484
|
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}$/);
|
|
115372
|
-
const directory3 = exports_external.string().max(4096).refine(
|
|
115485
|
+
const directory3 = exports_external.string().max(4096).refine(isAbsolute37, "Use an absolute local directory");
|
|
115373
115486
|
const verification2 = { email: exports_external.string().email().max(254), code: exports_external.string().regex(/^\d{6}$/), userId: uuid9, membershipId: uuid9, recoveryDirectory: directory3 };
|
|
115374
115487
|
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.";
|
|
115375
115488
|
const handler = (action) => async (value) => {
|
|
@@ -115830,14 +115943,18 @@ var exports_runtime_mcp = {};
|
|
|
115830
115943
|
__export(exports_runtime_mcp, {
|
|
115831
115944
|
handleMcp: () => handleMcp
|
|
115832
115945
|
});
|
|
115833
|
-
import { existsSync as existsSync33, mkdirSync as mkdirSync26, readFileSync as readFileSync42, writeFileSync as writeFileSync23 } from "fs";
|
|
115946
|
+
import { existsSync as existsSync33, lstatSync as lstatSync39, mkdirSync as mkdirSync26, readFileSync as readFileSync42, renameSync as renameSync14, rmdirSync as rmdirSync4, statSync as statSync22, writeFileSync as writeFileSync23 } from "fs";
|
|
115947
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
115834
115948
|
import { homedir as homedir10 } from "os";
|
|
115835
|
-
import { dirname as dirname39, join as join65 } from "path";
|
|
115949
|
+
import { dirname as dirname39, isAbsolute as isAbsolute38, join as join65 } from "path";
|
|
115950
|
+
import { isDeepStrictEqual as isDeepStrictEqual16, stripVTControlCharacters } from "util";
|
|
115836
115951
|
async function handleMcp(options) {
|
|
115837
115952
|
if (options.register) {
|
|
115838
115953
|
let agents;
|
|
115954
|
+
let environment;
|
|
115839
115955
|
try {
|
|
115840
115956
|
agents = resolveAgents(options.register);
|
|
115957
|
+
environment = skillsMcpRegistrationEnvironment(process.env, options.apiUrl);
|
|
115841
115958
|
} catch (err) {
|
|
115842
115959
|
const error61 = err.message;
|
|
115843
115960
|
if (options.json) {
|
|
@@ -115851,7 +115968,7 @@ async function handleMcp(options) {
|
|
|
115851
115968
|
const command = findCommandOnPath(MCP_COMMAND_NAME);
|
|
115852
115969
|
const results2 = [];
|
|
115853
115970
|
for (const agent of agents) {
|
|
115854
|
-
const result2 = await registerMcpForAgent(agent, command);
|
|
115971
|
+
const result2 = await registerMcpForAgent(agent, command, environment);
|
|
115855
115972
|
results2.push(result2);
|
|
115856
115973
|
if (!options.json) {
|
|
115857
115974
|
const label = result2.path ? `${agent} (${result2.path})` : agent;
|
|
@@ -115868,96 +115985,193 @@ async function handleMcp(options) {
|
|
|
115868
115985
|
const { startMcpStdio: startMcpStdio2 } = await Promise.resolve().then(() => (init_mcp2(), exports_mcp));
|
|
115869
115986
|
await startMcpStdio2();
|
|
115870
115987
|
}
|
|
115871
|
-
async function registerMcpForAgent(agent, command) {
|
|
115988
|
+
async function registerMcpForAgent(agent, command, environment) {
|
|
115989
|
+
const server2 = { command, args: ["--stdio"], ...Object.keys(environment).length ? { env: environment } : {} };
|
|
115872
115990
|
switch (agent) {
|
|
115873
115991
|
case "claude":
|
|
115874
|
-
return registerClaudeMcp(command);
|
|
115992
|
+
return registerClaudeMcp(command, server2, environment);
|
|
115875
115993
|
case "codex":
|
|
115876
|
-
return registerCodexMcp(command);
|
|
115994
|
+
return registerCodexMcp(command, environment);
|
|
115877
115995
|
case "gemini":
|
|
115878
|
-
return registerJsonMcpServer(agent, join65(homedir10(), ".gemini", "settings.json"), "mcpServers",
|
|
115879
|
-
command,
|
|
115880
|
-
args: []
|
|
115881
|
-
});
|
|
115996
|
+
return registerJsonMcpServer(agent, join65(homedir10(), ".gemini", "settings.json"), "mcpServers", server2);
|
|
115882
115997
|
case "pi":
|
|
115883
|
-
return registerJsonMcpServer(agent, join65(homedir10(), ".pi", "agent", "mcp.json"), "mcpServers",
|
|
115884
|
-
command,
|
|
115885
|
-
args: []
|
|
115886
|
-
});
|
|
115998
|
+
return registerJsonMcpServer(agent, join65(homedir10(), ".pi", "agent", "mcp.json"), "mcpServers", server2);
|
|
115887
115999
|
case "opencode":
|
|
115888
|
-
return registerOpenCodeMcp(command);
|
|
116000
|
+
return registerOpenCodeMcp(command, environment);
|
|
115889
116001
|
case "cursor":
|
|
115890
|
-
return registerJsonMcpServer(agent, join65(homedir10(), ".cursor", "mcp.json"), "mcpServers",
|
|
115891
|
-
command,
|
|
115892
|
-
args: []
|
|
115893
|
-
});
|
|
116002
|
+
return registerJsonMcpServer(agent, join65(homedir10(), ".cursor", "mcp.json"), "mcpServers", server2);
|
|
115894
116003
|
case "windsurf":
|
|
115895
|
-
return registerJsonMcpServer(agent, join65(homedir10(), ".windsurf", "mcp.json"), "mcpServers",
|
|
115896
|
-
command,
|
|
115897
|
-
args: []
|
|
115898
|
-
});
|
|
116004
|
+
return registerJsonMcpServer(agent, join65(homedir10(), ".windsurf", "mcp.json"), "mcpServers", server2);
|
|
115899
116005
|
default:
|
|
115900
116006
|
return { agent, success: false, error: `Unknown agent: ${agent}. Available: ${AGENT_TARGETS.join(", ")}, all` };
|
|
115901
116007
|
}
|
|
115902
116008
|
}
|
|
115903
|
-
async function registerClaudeMcp(command) {
|
|
115904
|
-
const
|
|
116009
|
+
async function registerClaudeMcp(command, server2, environment) {
|
|
116010
|
+
const args2 = ["claude", "mcp", "add", "-s", "user", ...Object.entries(environment).flatMap(([key2, value]) => ["--env", `${key2}=${value}`]), "--transport", "stdio", MCP_SERVER_NAME, "--", command, "--stdio"];
|
|
116011
|
+
const cliCommand = args2.map(skillsShellArgument).join(" ");
|
|
116012
|
+
const desired = { type: "stdio", ...server2, env: environment };
|
|
115905
116013
|
try {
|
|
115906
|
-
const
|
|
115907
|
-
|
|
115908
|
-
|
|
116014
|
+
const path = claudeUserConfigPath();
|
|
116015
|
+
const before2 = withClaudeConfigLock(path, () => {
|
|
116016
|
+
if (claudeUserConfigPath() !== path)
|
|
116017
|
+
throw new Error;
|
|
116018
|
+
const bytes = readClaudeConfig(path);
|
|
116019
|
+
if (bytes !== null) {
|
|
116020
|
+
const backup = `${path}.skills-mcp-${randomUUID10()}.backup`;
|
|
116021
|
+
writeFileSync23(backup, bytes, { flag: "wx", mode: 384 });
|
|
116022
|
+
if (!readFileSync42(backup).equals(bytes))
|
|
116023
|
+
throw new Error;
|
|
116024
|
+
}
|
|
116025
|
+
return bytes;
|
|
115909
116026
|
});
|
|
115910
|
-
|
|
115911
|
-
|
|
115912
|
-
|
|
115913
|
-
|
|
115914
|
-
|
|
115915
|
-
|
|
115916
|
-
|
|
116027
|
+
let exitCode, duplicateAccepted = false, cliUnavailable = false;
|
|
116028
|
+
const proc = (() => {
|
|
116029
|
+
try {
|
|
116030
|
+
return Bun.spawn(args2, { stdout: "pipe", stderr: "pipe" });
|
|
116031
|
+
} catch (error61) {
|
|
116032
|
+
if (!isPlainObject4(error61) || error61.code !== "ENOENT")
|
|
116033
|
+
throw new Error;
|
|
116034
|
+
cliUnavailable = true;
|
|
116035
|
+
return;
|
|
116036
|
+
}
|
|
116037
|
+
})();
|
|
116038
|
+
if (proc) {
|
|
116039
|
+
const [stdout, stderr, status] = await Promise.all([
|
|
116040
|
+
new Response(proc.stdout).text(),
|
|
116041
|
+
new Response(proc.stderr).text(),
|
|
116042
|
+
proc.exited
|
|
116043
|
+
]);
|
|
116044
|
+
exitCode = status;
|
|
116045
|
+
const diagnostic = stripVTControlCharacters(stderr).trim();
|
|
116046
|
+
duplicateAccepted = exitCode === 1 && stdout.trim() === "" && (diagnostic === `MCP server ${MCP_SERVER_NAME} already exists in user config` || diagnostic === `Error: MCP server ${MCP_SERVER_NAME} already exists in user config`);
|
|
116047
|
+
if (exitCode !== 0 && !duplicateAccepted)
|
|
116048
|
+
throw new Error;
|
|
115917
116049
|
}
|
|
115918
|
-
|
|
115919
|
-
|
|
115920
|
-
|
|
115921
|
-
|
|
115922
|
-
|
|
115923
|
-
|
|
115924
|
-
|
|
115925
|
-
|
|
115926
|
-
|
|
115927
|
-
|
|
115928
|
-
|
|
115929
|
-
|
|
115930
|
-
|
|
116050
|
+
return withClaudeConfigLock(path, () => {
|
|
116051
|
+
if (claudeUserConfigPath() !== path)
|
|
116052
|
+
throw new Error;
|
|
116053
|
+
const current = readClaudeConfig(path);
|
|
116054
|
+
const previous = parseClaudeConfig(before2), data = parseClaudeConfig(current);
|
|
116055
|
+
if (exitCode === 0) {
|
|
116056
|
+
const actual = isPlainObject4(data.mcpServers) ? data.mcpServers[MCP_SERVER_NAME] : undefined;
|
|
116057
|
+
if (!isDeepStrictEqual16(withoutClaudeSkills(previous), withoutClaudeSkills(data)) || !isPlainObject4(actual) || !isDeepStrictEqual16({ ...actual, env: actual.env ?? {} }, desired))
|
|
116058
|
+
throw new Error;
|
|
116059
|
+
} else {
|
|
116060
|
+
if (!cliUnavailable && (!duplicateAccepted || !isPlainObject4(previous.mcpServers) || !previous.mcpServers[MCP_SERVER_NAME]))
|
|
116061
|
+
throw new Error;
|
|
116062
|
+
if (before2 === null ? current !== null : current === null || !current.equals(before2))
|
|
116063
|
+
throw new Error;
|
|
116064
|
+
data.mcpServers = { ...data.mcpServers, [MCP_SERVER_NAME]: desired };
|
|
116065
|
+
const next = Buffer.from(`${JSON.stringify(data, null, 2)}
|
|
116066
|
+
`);
|
|
116067
|
+
const temporary = `${path}.skills-mcp-${randomUUID10()}.tmp`;
|
|
116068
|
+
writeFileSync23(temporary, next, { flag: "wx", mode: 384 });
|
|
116069
|
+
if (!readFileSync42(temporary).equals(next))
|
|
116070
|
+
throw new Error;
|
|
116071
|
+
const latest = readClaudeConfig(path);
|
|
116072
|
+
if (claudeUserConfigPath() !== path || (before2 === null ? latest !== null : latest === null || !latest.equals(before2)))
|
|
116073
|
+
throw new Error;
|
|
116074
|
+
renameSync14(temporary, path);
|
|
116075
|
+
if (!readFileSync42(path).equals(next))
|
|
116076
|
+
throw new Error;
|
|
116077
|
+
}
|
|
116078
|
+
return { agent: "claude", success: true, path, command: cliCommand };
|
|
115931
116079
|
});
|
|
116080
|
+
} catch {
|
|
115932
116081
|
return {
|
|
115933
|
-
|
|
116082
|
+
agent: "claude",
|
|
116083
|
+
success: false,
|
|
115934
116084
|
command: cliCommand,
|
|
115935
|
-
error:
|
|
116085
|
+
error: "Could not safely update the Claude user MCP configuration; native admission or config checks refused the update"
|
|
115936
116086
|
};
|
|
115937
116087
|
}
|
|
115938
116088
|
}
|
|
115939
|
-
function
|
|
116089
|
+
function claudeUserConfigPath() {
|
|
116090
|
+
const override = process.env.CLAUDE_CONFIG_DIR;
|
|
116091
|
+
if (override !== undefined && (!override || !isAbsolute38(override) || /[\x00-\x1f\x7f]/.test(override)))
|
|
116092
|
+
throw new Error;
|
|
116093
|
+
const modern = join65(override || homedir10(), process.env.CLAUDE_CODE_CUSTOM_OAUTH_URL ? ".claude-custom-oauth.json" : ".claude.json");
|
|
116094
|
+
const legacy = join65(override ?? join65(homedir10(), ".claude"), ".config.json");
|
|
116095
|
+
if (existsSync33(legacy)) {
|
|
116096
|
+
const info = lstatSync39(legacy);
|
|
116097
|
+
if (!info.isFile())
|
|
116098
|
+
throw new Error;
|
|
116099
|
+
if (info.size > 0 || (info.mode & 146) !== 0 && !existsSync33(modern))
|
|
116100
|
+
return legacy;
|
|
116101
|
+
}
|
|
116102
|
+
return modern;
|
|
116103
|
+
}
|
|
116104
|
+
function readClaudeConfig(path) {
|
|
116105
|
+
if (!existsSync33(path))
|
|
116106
|
+
return null;
|
|
116107
|
+
const info = lstatSync39(path);
|
|
116108
|
+
if (!info.isFile() || info.size > 16777216)
|
|
116109
|
+
throw new Error;
|
|
116110
|
+
const bytes = readFileSync42(path);
|
|
116111
|
+
parseClaudeConfig(bytes);
|
|
116112
|
+
return bytes;
|
|
116113
|
+
}
|
|
116114
|
+
function parseClaudeConfig(bytes) {
|
|
116115
|
+
const data = bytes === null ? {} : JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
116116
|
+
if (!isPlainObject4(data) || data.mcpServers !== undefined && !isPlainObject4(data.mcpServers))
|
|
116117
|
+
throw new Error;
|
|
116118
|
+
return data;
|
|
116119
|
+
}
|
|
116120
|
+
function withoutClaudeSkills(data) {
|
|
116121
|
+
const rest2 = { ...data }, servers = { ...data.mcpServers };
|
|
116122
|
+
delete servers[MCP_SERVER_NAME];
|
|
116123
|
+
if (Object.keys(servers).length)
|
|
116124
|
+
rest2.mcpServers = servers;
|
|
116125
|
+
else
|
|
116126
|
+
delete rest2.mcpServers;
|
|
116127
|
+
return rest2;
|
|
116128
|
+
}
|
|
116129
|
+
function withClaudeConfigLock(path, action) {
|
|
116130
|
+
mkdirSync26(dirname39(path), { recursive: true });
|
|
116131
|
+
const lock = `${path}.lock`;
|
|
116132
|
+
mkdirSync26(lock, { mode: 448 });
|
|
116133
|
+
const owned = statSync22(lock);
|
|
116134
|
+
try {
|
|
116135
|
+
return action();
|
|
116136
|
+
} finally {
|
|
116137
|
+
const current = lstatSync39(lock);
|
|
116138
|
+
if (current.isDirectory() && current.dev === owned.dev && current.ino === owned.ino) {
|
|
116139
|
+
rmdirSync4(lock);
|
|
116140
|
+
}
|
|
116141
|
+
}
|
|
116142
|
+
}
|
|
116143
|
+
function registerCodexMcp(command, environment) {
|
|
115940
116144
|
const path = join65(homedir10(), ".codex", "config.toml");
|
|
116145
|
+
const body = `command = ${JSON.stringify(command)}
|
|
116146
|
+
args = ["--stdio"]${Object.keys(environment).length ? `
|
|
116147
|
+
env = { ${Object.entries(environment).map(([key2, value]) => `${JSON.stringify(key2)} = ${JSON.stringify(value)}`).join(", ")} }` : ""}`;
|
|
115941
116148
|
const config2 = `[mcp_servers.${MCP_SERVER_NAME}]
|
|
115942
|
-
|
|
116149
|
+
${body}`;
|
|
115943
116150
|
try {
|
|
115944
116151
|
const current = existsSync33(path) ? readFileSync42(path, "utf-8") : "";
|
|
115945
|
-
|
|
116152
|
+
const before2 = Bun.TOML.parse(current);
|
|
116153
|
+
const next = upsertTomlSection(current, `[mcp_servers.${MCP_SERVER_NAME}]`, body);
|
|
116154
|
+
const after2 = Bun.TOML.parse(next);
|
|
116155
|
+
if (!isDeepStrictEqual16(withoutSkillsMcp(before2), withoutSkillsMcp(after2)))
|
|
116156
|
+
throw new Error;
|
|
116157
|
+
writeTextFile(path, next);
|
|
115946
116158
|
return { agent: "codex", success: true, path, config: config2 };
|
|
115947
116159
|
} catch (err) {
|
|
115948
|
-
return { agent: "codex", success: false, path, config: config2, error:
|
|
116160
|
+
return { agent: "codex", success: false, path, config: config2, error: "Could not update the Codex MCP configuration" };
|
|
115949
116161
|
}
|
|
115950
116162
|
}
|
|
115951
|
-
function registerOpenCodeMcp(command) {
|
|
116163
|
+
function registerOpenCodeMcp(command, environment) {
|
|
115952
116164
|
const path = join65(homedir10(), ".config", "opencode", "opencode.json");
|
|
116165
|
+
const server2 = {
|
|
116166
|
+
type: "local",
|
|
116167
|
+
command: [command, "--stdio"],
|
|
116168
|
+
enabled: true,
|
|
116169
|
+
...Object.keys(environment).length ? { environment } : {}
|
|
116170
|
+
};
|
|
115953
116171
|
const config2 = JSON.stringify({
|
|
115954
116172
|
$schema: "https://opencode.ai/config.json",
|
|
115955
116173
|
mcp: {
|
|
115956
|
-
[MCP_SERVER_NAME]:
|
|
115957
|
-
type: "local",
|
|
115958
|
-
command: [command],
|
|
115959
|
-
enabled: true
|
|
115960
|
-
}
|
|
116174
|
+
[MCP_SERVER_NAME]: server2
|
|
115961
116175
|
}
|
|
115962
116176
|
}, null, 2);
|
|
115963
116177
|
try {
|
|
@@ -115965,16 +116179,12 @@ function registerOpenCodeMcp(command) {
|
|
|
115965
116179
|
if (!data.$schema)
|
|
115966
116180
|
data.$schema = "https://opencode.ai/config.json";
|
|
115967
116181
|
const mcp = isPlainObject4(data.mcp) ? data.mcp : {};
|
|
115968
|
-
mcp[MCP_SERVER_NAME] =
|
|
115969
|
-
type: "local",
|
|
115970
|
-
command: [command],
|
|
115971
|
-
enabled: true
|
|
115972
|
-
};
|
|
116182
|
+
mcp[MCP_SERVER_NAME] = server2;
|
|
115973
116183
|
data.mcp = mcp;
|
|
115974
116184
|
writeJsonObject(path, data);
|
|
115975
116185
|
return { agent: "opencode", success: true, path, config: config2 };
|
|
115976
116186
|
} catch (err) {
|
|
115977
|
-
return { agent: "opencode", success: false, path, config: config2, error:
|
|
116187
|
+
return { agent: "opencode", success: false, path, config: config2, error: "Could not update the OpenCode MCP configuration" };
|
|
115978
116188
|
}
|
|
115979
116189
|
}
|
|
115980
116190
|
function registerJsonMcpServer(agent, path, containerKey, server2) {
|
|
@@ -115987,7 +116197,7 @@ function registerJsonMcpServer(agent, path, containerKey, server2) {
|
|
|
115987
116197
|
writeJsonObject(path, data);
|
|
115988
116198
|
return { agent, success: true, path, config: config2 };
|
|
115989
116199
|
} catch (err) {
|
|
115990
|
-
return { agent, success: false, path, config: config2, error:
|
|
116200
|
+
return { agent, success: false, path, config: config2, error: "Could not update the agent MCP configuration" };
|
|
115991
116201
|
}
|
|
115992
116202
|
}
|
|
115993
116203
|
function readJsonObject2(path) {
|
|
@@ -116014,24 +116224,37 @@ function writeTextFile(path, content) {
|
|
|
116014
116224
|
function upsertTomlSection(content, header, body) {
|
|
116015
116225
|
const sectionLines = [header, ...body.trim().split(/\r?\n/)];
|
|
116016
116226
|
const lines = content.trimEnd() ? content.trimEnd().split(/\r?\n/) : [];
|
|
116017
|
-
const
|
|
116018
|
-
|
|
116019
|
-
|
|
116020
|
-
|
|
116021
|
-
|
|
116022
|
-
|
|
116023
|
-
|
|
116024
|
-
|
|
116025
|
-
|
|
116026
|
-
end = i;
|
|
116027
|
-
break;
|
|
116227
|
+
const result2 = [];
|
|
116228
|
+
let owned = false, inserted = false;
|
|
116229
|
+
for (const line of lines) {
|
|
116230
|
+
if (/^\s*\[/.test(line)) {
|
|
116231
|
+
owned = /^\s*\[\s*(?:mcp_servers|"mcp_servers"|'mcp_servers')\s*\.\s*(?:skills|"skills"|'skills')\s*(?:\.|\])/.test(line);
|
|
116232
|
+
if (owned && !inserted) {
|
|
116233
|
+
result2.push(...sectionLines, "");
|
|
116234
|
+
inserted = true;
|
|
116235
|
+
}
|
|
116028
116236
|
}
|
|
116237
|
+
if (!owned)
|
|
116238
|
+
result2.push(line);
|
|
116029
116239
|
}
|
|
116030
|
-
|
|
116031
|
-
|
|
116240
|
+
if (!inserted)
|
|
116241
|
+
result2.push(...result2.length ? [""] : [], ...sectionLines);
|
|
116242
|
+
return `${result2.join(`
|
|
116032
116243
|
`)}
|
|
116033
116244
|
`;
|
|
116034
116245
|
}
|
|
116246
|
+
function withoutSkillsMcp(config2) {
|
|
116247
|
+
const preserved = { ...config2 };
|
|
116248
|
+
if (isPlainObject4(preserved.mcp_servers)) {
|
|
116249
|
+
const servers = { ...preserved.mcp_servers };
|
|
116250
|
+
delete servers[MCP_SERVER_NAME];
|
|
116251
|
+
if (Object.keys(servers).length)
|
|
116252
|
+
preserved.mcp_servers = servers;
|
|
116253
|
+
else
|
|
116254
|
+
delete preserved.mcp_servers;
|
|
116255
|
+
}
|
|
116256
|
+
return preserved;
|
|
116257
|
+
}
|
|
116035
116258
|
function findCommandOnPath(command) {
|
|
116036
116259
|
const pathValue = process.env.PATH || "";
|
|
116037
116260
|
for (const dir of pathValue.split(":")) {
|
|
@@ -116050,6 +116273,8 @@ var MCP_SERVER_NAME = "skills", MCP_COMMAND_NAME = "skills-mcp";
|
|
|
116050
116273
|
var init_runtime_mcp = __esm(() => {
|
|
116051
116274
|
init_source();
|
|
116052
116275
|
init_installer();
|
|
116276
|
+
init_credential_profile_command();
|
|
116277
|
+
init_mcp_registration_environment();
|
|
116053
116278
|
});
|
|
116054
116279
|
|
|
116055
116280
|
// src/cli/commands/remote-account.ts
|
|
@@ -116243,7 +116468,7 @@ var init_reviewed_runtime_lock = __esm(() => {
|
|
|
116243
116468
|
});
|
|
116244
116469
|
|
|
116245
116470
|
// src/cli/commands/runtime-copyfile.ts
|
|
116246
|
-
import { createHash as createHash40, randomUUID as
|
|
116471
|
+
import { createHash as createHash40, randomUUID as randomUUID11 } from "crypto";
|
|
116247
116472
|
import { Readable } from "stream";
|
|
116248
116473
|
import { createGunzip as createGunzip2 } from "zlib";
|
|
116249
116474
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
@@ -116251,16 +116476,16 @@ import {
|
|
|
116251
116476
|
chmodSync as chmodSync4,
|
|
116252
116477
|
copyFileSync,
|
|
116253
116478
|
existsSync as existsSync34,
|
|
116254
|
-
lstatSync as
|
|
116479
|
+
lstatSync as lstatSync40,
|
|
116255
116480
|
mkdirSync as mkdirSync27,
|
|
116256
116481
|
readFileSync as readFileSync43,
|
|
116257
116482
|
readdirSync as readdirSync24,
|
|
116258
116483
|
readlinkSync as readlinkSync8,
|
|
116259
116484
|
realpathSync as realpathSync19,
|
|
116260
|
-
renameSync as
|
|
116485
|
+
renameSync as renameSync15,
|
|
116261
116486
|
writeFileSync as writeFileSync24
|
|
116262
116487
|
} from "fs";
|
|
116263
|
-
import { basename as basename21, delimiter as delimiter3, dirname as dirname40, isAbsolute as
|
|
116488
|
+
import { basename as basename21, delimiter as delimiter3, dirname as dirname40, isAbsolute as isAbsolute39, join as join66, relative as relative13, resolve as resolve36, sep as sep18 } from "path";
|
|
116264
116489
|
function oldLauncherState(item) {
|
|
116265
116490
|
if (item.oldShape === "pinned")
|
|
116266
116491
|
return { shape: "pinned", runtime: item.oldRuntime, cwd: item.oldCwd, target: item.oldTarget, sha256: item.oldSha256, format: item.oldFormat, profile: item.oldProfile };
|
|
@@ -116286,7 +116511,7 @@ function assertLauncherRecordShapes(item, expectedProfile) {
|
|
|
116286
116511
|
throw new Error("RECEIPT_LAUNCHER_SHAPE_INVALID");
|
|
116287
116512
|
continue;
|
|
116288
116513
|
}
|
|
116289
|
-
if (shape !== "pinned" || typeof runtime !== "string" || !
|
|
116514
|
+
if (shape !== "pinned" || typeof runtime !== "string" || !isAbsolute39(runtime) || typeof cwd2 !== "string" || !isAbsolute39(cwd2) || typeof sha7 !== "string" || !hex4.test(sha7)) {
|
|
116290
116515
|
throw new Error("RECEIPT_LAUNCHER_SHAPE_INVALID");
|
|
116291
116516
|
}
|
|
116292
116517
|
const target = side === "old" ? item.oldTarget : item.newTarget;
|
|
@@ -116314,7 +116539,7 @@ function verifyTargetPrerequisites(manifest, packageRoot, home, cwd2, pathValue)
|
|
|
116314
116539
|
throw new Error("RUNTIME_PREREQUISITE_CONTRACT_INVALID");
|
|
116315
116540
|
}
|
|
116316
116541
|
const entry = join66(packageRoot, contract.entry);
|
|
116317
|
-
if (!entryExists(entry) || !
|
|
116542
|
+
if (!entryExists(entry) || !lstatSync40(entry).isFile() || lstatSync40(entry).isSymbolicLink())
|
|
116318
116543
|
throw new Error("RUNTIME_PREREQUISITE_ENTRY_MISSING");
|
|
116319
116544
|
const entrySha256 = hash6(readFileSync43(entry));
|
|
116320
116545
|
const env3 = { HOME: home, PATH: pathValue, BUN_RUNTIME_TRANSPILER_CACHE_PATH: "0" };
|
|
@@ -116373,11 +116598,11 @@ function hash6(bytes) {
|
|
|
116373
116598
|
}
|
|
116374
116599
|
function isWithin(parent, child2) {
|
|
116375
116600
|
const rel = relative13(parent, child2);
|
|
116376
|
-
return rel === "" || !rel.startsWith(`..${sep18}`) && rel !== ".." && !
|
|
116601
|
+
return rel === "" || !rel.startsWith(`..${sep18}`) && rel !== ".." && !isAbsolute39(rel);
|
|
116377
116602
|
}
|
|
116378
116603
|
function entryExists(path) {
|
|
116379
116604
|
try {
|
|
116380
|
-
|
|
116605
|
+
lstatSync40(path);
|
|
116381
116606
|
return true;
|
|
116382
116607
|
} catch {
|
|
116383
116608
|
return false;
|
|
@@ -116389,7 +116614,7 @@ function assertNoSymlinkAncestors(path) {
|
|
|
116389
116614
|
let current = sep18;
|
|
116390
116615
|
for (const part of parts) {
|
|
116391
116616
|
current = join66(current, part);
|
|
116392
|
-
const stat3 =
|
|
116617
|
+
const stat3 = lstatSync40(current);
|
|
116393
116618
|
if (stat3.isSymbolicLink())
|
|
116394
116619
|
throw new Error("PATH_ANCESTOR_SYMLINK_UNSUPPORTED");
|
|
116395
116620
|
if (!stat3.isDirectory())
|
|
@@ -116404,17 +116629,17 @@ function acquireRuntimeLock(runtimeRoot) {
|
|
|
116404
116629
|
throw new Error("RUNTIME_UPDATE_LOCKED");
|
|
116405
116630
|
}
|
|
116406
116631
|
try {
|
|
116407
|
-
writeJsonPrivate(join66(lockPath, "lock.json"), { operationId:
|
|
116632
|
+
writeJsonPrivate(join66(lockPath, "lock.json"), { operationId: randomUUID11(), pid: process.pid, startedAt: new Date().toISOString() });
|
|
116408
116633
|
} catch {
|
|
116409
116634
|
try {
|
|
116410
|
-
|
|
116635
|
+
renameSync15(lockPath, join66(runtimeRoot, `.copyfile-update-lock-incomplete-${randomUUID11()}`));
|
|
116411
116636
|
} catch {}
|
|
116412
116637
|
throw new Error("RUNTIME_LOCK_INITIALIZATION_FAILED");
|
|
116413
116638
|
}
|
|
116414
116639
|
return () => {
|
|
116415
|
-
const released = join66(runtimeRoot, `.copyfile-update-lock-released-${
|
|
116640
|
+
const released = join66(runtimeRoot, `.copyfile-update-lock-released-${randomUUID11()}`);
|
|
116416
116641
|
writeJsonPrivate(join66(lockPath, "released.json"), { completedAt: new Date().toISOString() });
|
|
116417
|
-
|
|
116642
|
+
renameSync15(lockPath, released);
|
|
116418
116643
|
};
|
|
116419
116644
|
}
|
|
116420
116645
|
function packageBins(pkg) {
|
|
@@ -116422,7 +116647,7 @@ function packageBins(pkg) {
|
|
|
116422
116647
|
const entries = typeof raw === "string" ? [[PACKAGE_NAME.slice(PACKAGE_NAME.lastIndexOf("/") + 1), raw]] : raw && typeof raw === "object" && !Array.isArray(raw) ? Object.entries(raw) : [];
|
|
116423
116648
|
const output2 = {};
|
|
116424
116649
|
for (const [name, value] of entries) {
|
|
116425
|
-
if (!/^[a-zA-Z0-9._-]+$/.test(name) || typeof value !== "string" || !value ||
|
|
116650
|
+
if (!/^[a-zA-Z0-9._-]+$/.test(name) || typeof value !== "string" || !value || isAbsolute39(value)) {
|
|
116426
116651
|
throw new Error("PACKAGE_BIN_INVALID");
|
|
116427
116652
|
}
|
|
116428
116653
|
const normalized2 = value.replaceAll("\\", "/");
|
|
@@ -116450,7 +116675,7 @@ function resolveRuntimeLayout(homeInput, pathInput) {
|
|
|
116450
116675
|
const home = realpathSync19(homeInput);
|
|
116451
116676
|
const runtimeRoot = join66(home, ".hasna", "skills", "runtime");
|
|
116452
116677
|
assertNoSymlinkAncestors(runtimeRoot);
|
|
116453
|
-
const runtimeRootStat =
|
|
116678
|
+
const runtimeRootStat = lstatSync40(runtimeRoot);
|
|
116454
116679
|
if (!runtimeRootStat.isDirectory() || runtimeRootStat.isSymbolicLink() || (runtimeRootStat.mode & 63) !== 0) {
|
|
116455
116680
|
throw new Error("RUNTIME_ROOT_NOT_PRIVATE");
|
|
116456
116681
|
}
|
|
@@ -116509,7 +116734,7 @@ function resolveRuntimeLayout(homeInput, pathInput) {
|
|
|
116509
116734
|
if (actual !== join66(currentPackageRoot, target))
|
|
116510
116735
|
continue;
|
|
116511
116736
|
const newTarget = join66(runtimeRoot, "__target__", "node_modules", "@hasna", "skills", target);
|
|
116512
|
-
const backupPath = `${path}.skills-prev-${
|
|
116737
|
+
const backupPath = `${path}.skills-prev-${randomUUID11()}`;
|
|
116513
116738
|
if (launcher.kind === "symlink") {
|
|
116514
116739
|
if (resolve36(dirname40(path), launcher.linkTarget) !== actual)
|
|
116515
116740
|
throw new Error("LAUNCHER_SYMLINK_CHAIN_UNSUPPORTED");
|
|
@@ -116722,7 +116947,7 @@ function readTree(root2, includeModes, excludeNpmDependencies = false) {
|
|
|
116722
116947
|
for (const item of readdirSync24(dir).sort()) {
|
|
116723
116948
|
const path = join66(dir, item);
|
|
116724
116949
|
const rel = prefix ? `${prefix}/${item}` : item;
|
|
116725
|
-
const stat3 =
|
|
116950
|
+
const stat3 = lstatSync40(path);
|
|
116726
116951
|
if (excludeNpmDependencies && !prefix && item === "node_modules") {
|
|
116727
116952
|
if (!stat3.isDirectory() || stat3.isSymbolicLink())
|
|
116728
116953
|
throw new Error("INSTALLED_DEPENDENCY_DIRECTORY_UNSAFE");
|
|
@@ -116758,14 +116983,14 @@ function readTree(root2, includeModes, excludeNpmDependencies = false) {
|
|
|
116758
116983
|
return { entries, digest: hash6(new TextEncoder().encode(JSON.stringify(entries))) };
|
|
116759
116984
|
}
|
|
116760
116985
|
function normalizeModes(root2) {
|
|
116761
|
-
const rootStat =
|
|
116986
|
+
const rootStat = lstatSync40(root2);
|
|
116762
116987
|
if (!rootStat.isDirectory() || rootStat.isSymbolicLink())
|
|
116763
116988
|
throw new Error("RUNTIME_ENTRY_TYPE_UNSUPPORTED");
|
|
116764
116989
|
chmodSync4(root2, rootStat.mode & 493);
|
|
116765
116990
|
const walk2 = (dir) => {
|
|
116766
116991
|
for (const item of readdirSync24(dir)) {
|
|
116767
116992
|
const path = join66(dir, item);
|
|
116768
|
-
const stat3 =
|
|
116993
|
+
const stat3 = lstatSync40(path);
|
|
116769
116994
|
if (stat3.isSymbolicLink())
|
|
116770
116995
|
continue;
|
|
116771
116996
|
if (stat3.isDirectory()) {
|
|
@@ -116815,7 +117040,7 @@ function verifyPreimageManifest(runtimePath, receipt, home) {
|
|
|
116815
117040
|
throw new Error("PREIMAGE_CONFIG_BINDING_INVALID");
|
|
116816
117041
|
if (config2.present) {
|
|
116817
117042
|
const backup = join66(runtimePath, "preimage", "configs", relativePath);
|
|
116818
|
-
const stat3 =
|
|
117043
|
+
const stat3 = lstatSync40(backup);
|
|
116819
117044
|
const saved = readFileSync43(backup);
|
|
116820
117045
|
if (!stat3.isFile() || stat3.isSymbolicLink() || hash6(saved) !== config2.sha256 || saved.byteLength !== config2.byteSize)
|
|
116821
117046
|
throw new Error("PREIMAGE_CONFIG_DRIFT");
|
|
@@ -116829,7 +117054,7 @@ function captureConfigPreimages(home, stage) {
|
|
|
116829
117054
|
const sourcePath = join66(home, relativePath);
|
|
116830
117055
|
if (!entryExists(sourcePath))
|
|
116831
117056
|
return { sourcePath, relativePath, present: false };
|
|
116832
|
-
const stat3 =
|
|
117057
|
+
const stat3 = lstatSync40(sourcePath);
|
|
116833
117058
|
if (!stat3.isFile() || stat3.isSymbolicLink())
|
|
116834
117059
|
throw new Error("CONFIG_PREIMAGE_NOT_REGULAR_FILE");
|
|
116835
117060
|
const bytes = readFileSync43(sourcePath);
|
|
@@ -116849,7 +117074,7 @@ function assertConfigUnchanged(configs) {
|
|
|
116849
117074
|
if (present2 !== config2.present)
|
|
116850
117075
|
throw new Error("CONFIG_DRIFT_DURING_UPDATE");
|
|
116851
117076
|
if (present2) {
|
|
116852
|
-
const stat3 =
|
|
117077
|
+
const stat3 = lstatSync40(config2.sourcePath);
|
|
116853
117078
|
if (!stat3.isFile() || stat3.isSymbolicLink() || hash6(readFileSync43(config2.sourcePath)) !== config2.sha256) {
|
|
116854
117079
|
throw new Error("CONFIG_DRIFT_DURING_UPDATE");
|
|
116855
117080
|
}
|
|
@@ -116948,7 +117173,7 @@ function replaceLauncher(item) {
|
|
|
116948
117173
|
const oldState = oldLauncherState(item), newState = newLauncherState(item);
|
|
116949
117174
|
if (!launcherIs(item.path, oldState) || entryExists(item.backupPath))
|
|
116950
117175
|
throw new Error("LAUNCHER_PREIMAGE_DRIFT");
|
|
116951
|
-
const temp = `${item.path}.skills-next-${
|
|
117176
|
+
const temp = `${item.path}.skills-next-${randomUUID11()}`;
|
|
116952
117177
|
try {
|
|
116953
117178
|
materializeLauncher(item.backupPath, oldState);
|
|
116954
117179
|
} catch {
|
|
@@ -116963,15 +117188,15 @@ function replaceLauncher(item) {
|
|
|
116963
117188
|
}
|
|
116964
117189
|
if (!launcherIs(temp, newState))
|
|
116965
117190
|
throw new Error("LAUNCHER_NEW_LINK_READBACK_MISMATCH");
|
|
116966
|
-
|
|
117191
|
+
renameSync15(temp, item.path);
|
|
116967
117192
|
}
|
|
116968
117193
|
function atomicJson(path, value) {
|
|
116969
|
-
const temp = `${path}.next-${
|
|
117194
|
+
const temp = `${path}.next-${randomUUID11()}`;
|
|
116970
117195
|
const bytes = Buffer.from(`${JSON.stringify(value, null, 2)}
|
|
116971
117196
|
`);
|
|
116972
117197
|
writeFileSync24(temp, bytes, { flag: "wx", mode: 384 });
|
|
116973
117198
|
chmodSync4(temp, 384);
|
|
116974
|
-
|
|
117199
|
+
renameSync15(temp, path);
|
|
116975
117200
|
if (!readFileSync43(path).equals(bytes))
|
|
116976
117201
|
throw new Error("RECEIPT_READBACK_MISMATCH");
|
|
116977
117202
|
}
|
|
@@ -116988,10 +117213,10 @@ function persistReceipt(path, value) {
|
|
|
116988
117213
|
const historyRoot = join66(dirname40(path), "receipt-history");
|
|
116989
117214
|
if (!entryExists(historyRoot))
|
|
116990
117215
|
mkdirSync27(historyRoot, { mode: 448 });
|
|
116991
|
-
const historyStat =
|
|
117216
|
+
const historyStat = lstatSync40(historyRoot);
|
|
116992
117217
|
if (!historyStat.isDirectory() || historyStat.isSymbolicLink() || (historyStat.mode & 63) !== 0)
|
|
116993
117218
|
throw new Error("RECEIPT_HISTORY_NOT_PRIVATE");
|
|
116994
|
-
const historyPath = join66(historyRoot, `${value.id}-${String(prior.state)}-${
|
|
117219
|
+
const historyPath = join66(historyRoot, `${value.id}-${String(prior.state)}-${randomUUID11()}.json`);
|
|
116995
117220
|
writeFileSync24(historyPath, priorBytes, { flag: "wx", mode: 256 });
|
|
116996
117221
|
chmodSync4(historyPath, 256);
|
|
116997
117222
|
if (!readFileSync43(historyPath).equals(priorBytes))
|
|
@@ -117012,10 +117237,10 @@ function persistAliasReceipt(path, value) {
|
|
|
117012
117237
|
const history = join66(dirname40(path), "history");
|
|
117013
117238
|
if (!entryExists(history))
|
|
117014
117239
|
mkdirSync27(history, { mode: 448 });
|
|
117015
|
-
const historyStat =
|
|
117240
|
+
const historyStat = lstatSync40(history);
|
|
117016
117241
|
if (!historyStat.isDirectory() || historyStat.isSymbolicLink() || (historyStat.mode & 63) !== 0)
|
|
117017
117242
|
throw new Error("ALIAS_RECEIPT_HISTORY_UNSAFE");
|
|
117018
|
-
const saved = join66(history, `${value.id}-${String(prior.state)}-${
|
|
117243
|
+
const saved = join66(history, `${value.id}-${String(prior.state)}-${randomUUID11()}.json`);
|
|
117019
117244
|
writeFileSync24(saved, priorBytes, { flag: "wx", mode: 256 });
|
|
117020
117245
|
chmodSync4(saved, 256);
|
|
117021
117246
|
if (!readFileSync43(saved).equals(priorBytes))
|
|
@@ -117026,7 +117251,7 @@ function persistAliasReceipt(path, value) {
|
|
|
117026
117251
|
function assertOwnedSafePath(path, home, requireWritable = false) {
|
|
117027
117252
|
assertNoSymlinkAncestors(path);
|
|
117028
117253
|
for (let current = path;; current = dirname40(current)) {
|
|
117029
|
-
const stat3 =
|
|
117254
|
+
const stat3 = lstatSync40(current);
|
|
117030
117255
|
if (!stat3.isDirectory() || ![0, process.getuid?.() ?? -1].includes(stat3.uid) || stat3.mode & 18)
|
|
117031
117256
|
throw new Error("ALIAS_PATH_UNSAFE");
|
|
117032
117257
|
if (current === path && requireWritable && (stat3.uid !== (process.getuid?.() ?? -1) || (stat3.mode & 128) === 0))
|
|
@@ -117074,7 +117299,7 @@ function inspectAliasPackageChain(home, aliasPath, oldLinkTarget, oldTarget, bin
|
|
|
117074
117299
|
assertOwnedSafePath(dirname40(packageLinkPath), home);
|
|
117075
117300
|
let stat3, packageLinkTarget, resolved;
|
|
117076
117301
|
try {
|
|
117077
|
-
stat3 =
|
|
117302
|
+
stat3 = lstatSync40(packageLinkPath);
|
|
117078
117303
|
packageLinkTarget = readlinkSync8(packageLinkPath);
|
|
117079
117304
|
resolved = realpathSync19(packageLinkPath);
|
|
117080
117305
|
} catch {
|
|
@@ -117097,7 +117322,7 @@ function validateAliasSource(home, name, actual) {
|
|
|
117097
117322
|
}
|
|
117098
117323
|
assertOwnedSafePath(packageRoot, home);
|
|
117099
117324
|
const manifestPath = join66(packageRoot, "package.json");
|
|
117100
|
-
const manifestStat =
|
|
117325
|
+
const manifestStat = lstatSync40(manifestPath), binaryStat = lstatSync40(actual);
|
|
117101
117326
|
if (!manifestStat.isFile() || manifestStat.isSymbolicLink() || !binaryStat.isFile() || binaryStat.isSymbolicLink() || ![0, process.getuid?.() ?? -1].includes(manifestStat.uid) || ![0, process.getuid?.() ?? -1].includes(binaryStat.uid) || manifestStat.mode & 18)
|
|
117102
117327
|
throw new Error("ALIAS_SOURCE_UNSAFE");
|
|
117103
117328
|
const pkg = readPackage(manifestPath);
|
|
@@ -117113,7 +117338,7 @@ function adoptCopyfileAliases(options = {}) {
|
|
|
117113
117338
|
const launcherRuntime = pinnedLauncherRuntime();
|
|
117114
117339
|
pinnedLauncherState(launcherRuntime, currentRuntime, join66(layout.currentPackageRoot, layout.bin.skills ?? "bin/index.js"));
|
|
117115
117340
|
const releaseLock = acquireRuntimeLock(layout.runtimeRoot);
|
|
117116
|
-
const id2 =
|
|
117341
|
+
const id2 = randomUUID11();
|
|
117117
117342
|
const aliases = [];
|
|
117118
117343
|
const receiptDir = join66(currentRuntime, "alias-adoptions");
|
|
117119
117344
|
const receiptPath = join66(receiptDir, `${id2}.json`);
|
|
@@ -117130,7 +117355,7 @@ function adoptCopyfileAliases(options = {}) {
|
|
|
117130
117355
|
if (!entryExists(path))
|
|
117131
117356
|
continue;
|
|
117132
117357
|
assertOwnedSafePath(dir, home, true);
|
|
117133
|
-
const stat3 =
|
|
117358
|
+
const stat3 = lstatSync40(path);
|
|
117134
117359
|
if (stat3.uid !== (process.getuid?.() ?? -1))
|
|
117135
117360
|
throw new Error("ALIAS_LINK_NOT_OWNED");
|
|
117136
117361
|
let launcher;
|
|
@@ -117169,7 +117394,7 @@ function adoptCopyfileAliases(options = {}) {
|
|
|
117169
117394
|
if (!aliases.length)
|
|
117170
117395
|
return { adopted: true, version: layout.currentVersion, aliasCount: 0 };
|
|
117171
117396
|
mkdirSync27(receiptDir, { recursive: true, mode: 448 });
|
|
117172
|
-
const receiptDirStat =
|
|
117397
|
+
const receiptDirStat = lstatSync40(receiptDir);
|
|
117173
117398
|
if (!receiptDirStat.isDirectory() || receiptDirStat.isSymbolicLink() || receiptDirStat.mode & 63)
|
|
117174
117399
|
throw new Error("ALIAS_RECEIPT_DIRECTORY_UNSAFE");
|
|
117175
117400
|
receipt = {
|
|
@@ -117234,9 +117459,9 @@ function adoptCopyfileAliases(options = {}) {
|
|
|
117234
117459
|
if (entryExists(after2))
|
|
117235
117460
|
throw new Error("ALIAS_AFTER_COLLISION");
|
|
117236
117461
|
materializeLauncher(after2, newLauncherState(item));
|
|
117237
|
-
const temp = `${item.path}.skills-alias-rollback-${
|
|
117462
|
+
const temp = `${item.path}.skills-alias-rollback-${randomUUID11()}`;
|
|
117238
117463
|
materializeLauncher(temp, oldLauncherState(item));
|
|
117239
|
-
|
|
117464
|
+
renameSync15(temp, item.path);
|
|
117240
117465
|
if (!launcherIs(item.path, oldLauncherState(item)))
|
|
117241
117466
|
throw new Error("ALIAS_ROLLBACK_READBACK_MISMATCH");
|
|
117242
117467
|
receipt.rollbackCompletedAliases = [...receipt.rollbackCompletedAliases, item.path];
|
|
@@ -117287,7 +117512,7 @@ function rollbackCopyfileAliases(receiptId, options = {}) {
|
|
|
117287
117512
|
const source = validateAliasSource(home, name, item.oldTarget);
|
|
117288
117513
|
if (source.version !== item.oldVersion || source.binarySha256 !== item.oldBinarySha256)
|
|
117289
117514
|
throw new Error("ALIAS_PREIMAGE_DRIFT");
|
|
117290
|
-
const stat3 =
|
|
117515
|
+
const stat3 = lstatSync40(item.path);
|
|
117291
117516
|
if (stat3.uid !== (process.getuid?.() ?? -1))
|
|
117292
117517
|
throw new Error("ALIAS_LINK_DRIFT");
|
|
117293
117518
|
let current;
|
|
@@ -117322,9 +117547,9 @@ function rollbackCopyfileAliases(receiptId, options = {}) {
|
|
|
117322
117547
|
throw new Error("ALIAS_AFTER_DRIFT");
|
|
117323
117548
|
if (launcherTarget(item.path) !== item.newTarget)
|
|
117324
117549
|
throw new Error("ALIAS_TARGET_DRIFT");
|
|
117325
|
-
const temp = `${item.path}.skills-alias-rollback-${
|
|
117550
|
+
const temp = `${item.path}.skills-alias-rollback-${randomUUID11()}`;
|
|
117326
117551
|
materializeLauncher(temp, oldLauncherState(item));
|
|
117327
|
-
|
|
117552
|
+
renameSync15(temp, item.path);
|
|
117328
117553
|
if (!launcherIs(item.path, oldLauncherState(item)))
|
|
117329
117554
|
throw new Error("ALIAS_ROLLBACK_READBACK_MISMATCH");
|
|
117330
117555
|
receipt.rollbackCompletedAliases = [...new Set([...receipt.rollbackCompletedAliases, item.path])];
|
|
@@ -117353,10 +117578,10 @@ async function updateCopyfileRuntime(version2, options = {}) {
|
|
|
117353
117578
|
throw new Error("REVIEWED_LOCK_INPUT_PAIR_REQUIRED");
|
|
117354
117579
|
if (!policy)
|
|
117355
117580
|
throw new Error("REVIEWED_LOCK_RELEASE_AGE_REQUIRED");
|
|
117356
|
-
if (!
|
|
117581
|
+
if (!isAbsolute39(options.reviewedLock))
|
|
117357
117582
|
throw new Error("REVIEWED_LOCK_ABSOLUTE_PATH_REQUIRED");
|
|
117358
117583
|
assertNoSymlinkAncestors(dirname40(options.reviewedLock));
|
|
117359
|
-
const stat3 =
|
|
117584
|
+
const stat3 = lstatSync40(options.reviewedLock);
|
|
117360
117585
|
if (!stat3.isFile() || stat3.isSymbolicLink() || stat3.nlink !== 1 || stat3.uid !== process.getuid?.() || stat3.mode & 63 || stat3.size > 8 * 1024 * 1024)
|
|
117361
117586
|
throw new Error("REVIEWED_LOCK_FILE_UNSAFE");
|
|
117362
117587
|
reviewedLockBytes = readFileSync43(options.reviewedLock);
|
|
@@ -117377,10 +117602,10 @@ async function updateCopyfileRuntime(version2, options = {}) {
|
|
|
117377
117602
|
throw new Error("REGISTRY_ORIGIN_INVALID");
|
|
117378
117603
|
if (origin.username || origin.password || origin.search || origin.hash)
|
|
117379
117604
|
throw new Error("REGISTRY_ORIGIN_INVALID");
|
|
117380
|
-
const runtimeRootStat =
|
|
117605
|
+
const runtimeRootStat = lstatSync40(layout.runtimeRoot);
|
|
117381
117606
|
if ((runtimeRootStat.mode & 63) !== 0)
|
|
117382
117607
|
throw new Error("RUNTIME_ROOT_NOT_PRIVATE");
|
|
117383
|
-
const id2 =
|
|
117608
|
+
const id2 = randomUUID11();
|
|
117384
117609
|
const stagePath = join66(layout.runtimeRoot, `.stage-${version2}-${id2}`);
|
|
117385
117610
|
const finalPath = join66(layout.runtimeRoot, `${version2}-copyfile`);
|
|
117386
117611
|
const launcherRuntime = pinnedLauncherRuntime();
|
|
@@ -117493,7 +117718,7 @@ async function updateCopyfileRuntime(version2, options = {}) {
|
|
|
117493
117718
|
persistReceipt(join66(stagePath, "rollout-receipt.json"), receipt);
|
|
117494
117719
|
const finalNodeModules = join66(stagePackage, "node_modules");
|
|
117495
117720
|
const stagedNodeModules = join66(stagePath, "node_modules");
|
|
117496
|
-
|
|
117721
|
+
renameSync15(finalNodeModules, stagedNodeModules);
|
|
117497
117722
|
copyFileSync(join66(stagePackage, "package-lock.json"), join66(stagePath, "install-lock.json"));
|
|
117498
117723
|
chmodSync4(join66(stagePath, "install-lock.json"), 384);
|
|
117499
117724
|
const stagedTree = readTree(stagedNodeModules, true);
|
|
@@ -117502,7 +117727,7 @@ async function updateCopyfileRuntime(version2, options = {}) {
|
|
|
117502
117727
|
receipt.targetPackageRoot = join66(finalPath, "node_modules", "@hasna", "skills");
|
|
117503
117728
|
receipt.runtimeTreeSha256 = stagedTree.digest;
|
|
117504
117729
|
persistReceipt(join66(stagePath, "rollout-receipt.json"), receipt);
|
|
117505
|
-
|
|
117730
|
+
renameSync15(stagePath, finalPath);
|
|
117506
117731
|
moved = true;
|
|
117507
117732
|
const finalReceiptBytes = Buffer.from(`${JSON.stringify(receipt, null, 2)}
|
|
117508
117733
|
`);
|
|
@@ -117540,7 +117765,7 @@ async function updateCopyfileRuntime(version2, options = {}) {
|
|
|
117540
117765
|
throw new Error("ROLLBACK_PRESERVATION_PATH_EXISTS");
|
|
117541
117766
|
materializeLauncher(afterPath, newLauncherState(item));
|
|
117542
117767
|
materializeLauncher(temp, oldLauncherState(item));
|
|
117543
|
-
|
|
117768
|
+
renameSync15(temp, item.path);
|
|
117544
117769
|
} catch {
|
|
117545
117770
|
rollbackFailed = true;
|
|
117546
117771
|
}
|
|
@@ -117568,7 +117793,7 @@ function rollbackCopyfileRuntime(receiptId, options = {}) {
|
|
|
117568
117793
|
throw new Error("HOME_NOT_FOUND");
|
|
117569
117794
|
const runtimeRoot = join66(realpathSync19(home), ".hasna", "skills", "runtime");
|
|
117570
117795
|
assertNoSymlinkAncestors(runtimeRoot);
|
|
117571
|
-
const rootStat =
|
|
117796
|
+
const rootStat = lstatSync40(runtimeRoot);
|
|
117572
117797
|
if (!rootStat.isDirectory() || rootStat.isSymbolicLink() || (rootStat.mode & 63) !== 0)
|
|
117573
117798
|
throw new Error("RUNTIME_ROOT_NOT_PRIVATE");
|
|
117574
117799
|
const releaseLock = acquireRuntimeLock(runtimeRoot);
|
|
@@ -117609,7 +117834,7 @@ function rollbackCopyfileRuntime(receiptId, options = {}) {
|
|
|
117609
117834
|
const seen = new Set;
|
|
117610
117835
|
for (const item of receipt.launchers) {
|
|
117611
117836
|
const bin = oldBins[basename21(item.path)];
|
|
117612
|
-
if (!bin || !
|
|
117837
|
+
if (!bin || !isAbsolute39(item.path) || seen.has(item.path) || item.oldTarget !== join66(receipt.currentPackageRoot, bin) || item.newTarget !== join66(receipt.targetPackageRoot, bin) || !/^.+\.skills-prev-[0-9a-f-]{36}$/.test(item.backupPath) || !item.backupPath.startsWith(`${item.path}.skills-prev-`) || typeof item.oldLinkTarget !== "string" || resolve36(dirname40(item.path), item.oldLinkTarget) !== item.oldTarget)
|
|
117613
117838
|
throw new Error("RECEIPT_LAUNCHER_BINDING_INVALID");
|
|
117614
117839
|
assertNoSymlinkAncestors(dirname40(item.path));
|
|
117615
117840
|
assertLauncherRecordShapes(item, launcherProfileForBin(basename21(item.path), bin));
|
|
@@ -117641,9 +117866,9 @@ function rollbackCopyfileRuntime(receiptId, options = {}) {
|
|
|
117641
117866
|
const afterPath = `${item.path}.skills-after-${receiptId}`;
|
|
117642
117867
|
if (!entryExists(afterPath))
|
|
117643
117868
|
materializeLauncher(afterPath, newLauncherState(item));
|
|
117644
|
-
const temp = `${item.path}.skills-rollback-${receiptId}-${
|
|
117869
|
+
const temp = `${item.path}.skills-rollback-${receiptId}-${randomUUID11()}`;
|
|
117645
117870
|
materializeLauncher(temp, oldLauncherState(item));
|
|
117646
|
-
|
|
117871
|
+
renameSync15(temp, item.path);
|
|
117647
117872
|
receipt.rollbackCompletedLaunchers = [...new Set([...receipt.rollbackCompletedLaunchers, item.path])];
|
|
117648
117873
|
persistReceipt(receiptPath, receipt);
|
|
117649
117874
|
}
|
|
@@ -117676,9 +117901,9 @@ __export(exports_runtime, {
|
|
|
117676
117901
|
selectedSkillsCommand: () => selectedSkillsCommand,
|
|
117677
117902
|
registerRuntime: () => registerRuntime
|
|
117678
117903
|
});
|
|
117679
|
-
import { createHash as createHash41, randomUUID as
|
|
117680
|
-
import { lstatSync as
|
|
117681
|
-
import { basename as basename22, isAbsolute as
|
|
117904
|
+
import { createHash as createHash41, randomUUID as randomUUID12 } from "crypto";
|
|
117905
|
+
import { lstatSync as lstatSync41, mkdirSync as mkdirSync28, readFileSync as readFileSync44, writeFileSync as writeFileSync25 } from "fs";
|
|
117906
|
+
import { basename as basename22, isAbsolute as isAbsolute40, join as join67 } from "path";
|
|
117682
117907
|
import { createInterface } from "readline";
|
|
117683
117908
|
function registerRuntime(parent) {
|
|
117684
117909
|
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) => {
|
|
@@ -117746,7 +117971,11 @@ function registerRuntime(parent) {
|
|
|
117746
117971
|
await handleMcp(options);
|
|
117747
117972
|
}));
|
|
117748
117973
|
const setup = parent.command("setup").description("Point this CLI at a Skills API server, or register agent integrations").option("--api-url <url>", "Skills API origin to send remote work to").option("--global", "Accepted for compatibility; the API origin is always per-user", false).option("--json", "Output setup result as JSON", false).action(async (options) => handleSetup(options));
|
|
117749
|
-
setup.command("agents").option("--json", "Output registration result as JSON", false).description("Register the Skills MCP server with all supported agents").action(async (options) => handleMcp({
|
|
117974
|
+
setup.command("agents").option("--json", "Output registration result as JSON", false).description("Register the Skills MCP server with all supported agents").action(async (options, command) => handleMcp({
|
|
117975
|
+
register: "all",
|
|
117976
|
+
json: options.json,
|
|
117977
|
+
apiUrl: command.parent?.opts().apiUrl
|
|
117978
|
+
}));
|
|
117750
117979
|
parent.command("self-update").description("Update @hasna/skills to the latest version").option("--json", "Output result as JSON", false).option("--version <version>", "Install this exact @hasna/skills version as a staged copyfile runtime").option("--min-release-age <days>", "Require a positive integer dependency release age in days for an exact-version update").option("--min-release-age-exclude <pattern>", "Exclude matching package identities from the release-age policy (repeatable)", (pattern, prior) => [...prior, pattern], []).option("--reviewed-lock <path>", "Install from this private absolute package-lock.json path without resolving dependency ranges").option("--reviewed-lock-sha256 <sha256>", "Exact reviewed SHA-256 of the supplied package-lock.json").option("--rollback <receipt-id>", "Restore launcher links from an exact copyfile rollout receipt").option("--adopt-aliases", "Switch verified legacy @hasna/skills aliases to the active copyfile runtime").option("--rollback-aliases <receipt-id>", "Restore aliases from an exact adoption receipt").action(async (options) => {
|
|
117751
117980
|
if ((options.reviewedLock !== undefined || options.reviewedLockSha256 !== undefined) && (!options.version || options.rollback || options.adoptAliases || options.rollbackAliases)) {
|
|
117752
117981
|
console.error(JSON.stringify({ error: "REVIEWED_LOCK_REQUIRES_EXACT_VERSION" }));
|
|
@@ -117877,7 +118106,7 @@ Updating ${name}...
|
|
|
117877
118106
|
async function readUpdatedVersion(bunExecutable) {
|
|
117878
118107
|
const output2 = await readUpdateCommand([bunExecutable, "pm", "bin", "-g"]);
|
|
117879
118108
|
const globalBin = output2.replace(/\r?\n$/, "");
|
|
117880
|
-
if (!globalBin || !
|
|
118109
|
+
if (!globalBin || !isAbsolute40(globalBin) || /[\r\n\0]/.test(globalBin))
|
|
117881
118110
|
throw new Error("Update bin discovery failed");
|
|
117882
118111
|
const installed = Bun.which("skills", { PATH: globalBin, cwd: globalBin });
|
|
117883
118112
|
const selected = Bun.which("skills");
|
|
@@ -118156,7 +118385,7 @@ async function handleRun(name, args2, options, separatorBeforeSkill) {
|
|
|
118156
118385
|
if (!Number.isFinite(timeoutMs) || timeoutMs < 1 || timeoutMs > 1200000 || !Number.isFinite(intervalMs) || intervalMs < 100 || intervalMs > 60000)
|
|
118157
118386
|
throw new Error("Invalid cloud polling bounds");
|
|
118158
118387
|
const client3 = await CloudExecutionClient.configured();
|
|
118159
|
-
const admitted = await client3.submit(slug2, version2, input2, options.idempotencyKey ??
|
|
118388
|
+
const admitted = await client3.submit(slug2, version2, input2, options.idempotencyKey ?? randomUUID12(), selected?.selection);
|
|
118160
118389
|
if (options.wait)
|
|
118161
118390
|
console.error(JSON.stringify({ executionId: admitted.id, status: admitted.status }));
|
|
118162
118391
|
const result3 = options.wait ? await client3.wait(admitted.id, { timeoutMs, intervalMs }) : admitted;
|
|
@@ -118213,7 +118442,7 @@ async function handleRun(name, args2, options, separatorBeforeSkill) {
|
|
|
118213
118442
|
try {
|
|
118214
118443
|
parsePollingOptions(options);
|
|
118215
118444
|
inputFiles = (options.file ?? []).map((path) => {
|
|
118216
|
-
const info =
|
|
118445
|
+
const info = lstatSync41(path);
|
|
118217
118446
|
if (!info.isFile() || info.size > 20 * 1024 * 1024)
|
|
118218
118447
|
throw new Error("Input must be a regular file no larger than 20 MiB");
|
|
118219
118448
|
return { name: basename22(path), bytes: new Uint8Array(readFileSync44(path)) };
|
|
@@ -118643,7 +118872,7 @@ function ensureSafeExportParent(root2, relativePath) {
|
|
|
118643
118872
|
if (part)
|
|
118644
118873
|
parent = join67(parent, part);
|
|
118645
118874
|
try {
|
|
118646
|
-
if (!
|
|
118875
|
+
if (!lstatSync41(parent).isDirectory() || lstatSync41(parent).isSymbolicLink())
|
|
118647
118876
|
throw new Error("Unsafe artifact directory");
|
|
118648
118877
|
} catch (error61) {
|
|
118649
118878
|
if (error61.code !== "ENOENT")
|
|
@@ -118938,7 +119167,7 @@ var exports_recurring = {};
|
|
|
118938
119167
|
__export(exports_recurring, {
|
|
118939
119168
|
registerRecurringCommands: () => registerRecurringCommands
|
|
118940
119169
|
});
|
|
118941
|
-
import { constants as constants28, closeSync as closeSync29, fstatSync as fstatSync29, lstatSync as
|
|
119170
|
+
import { constants as constants28, closeSync as closeSync29, fstatSync as fstatSync29, lstatSync as lstatSync42, openSync as openSync29, readSync as readSync21 } from "fs";
|
|
118942
119171
|
import { createInterface as createInterface2 } from "readline";
|
|
118943
119172
|
function readRequest(path) {
|
|
118944
119173
|
const fd = openSync29(path, constants28.O_RDONLY | constants28.O_NOFOLLOW | constants28.O_NONBLOCK);
|
|
@@ -118954,7 +119183,7 @@ function readRequest(path) {
|
|
|
118954
119183
|
break;
|
|
118955
119184
|
length += n2;
|
|
118956
119185
|
}
|
|
118957
|
-
const after2 = fstatSync29(fd), current =
|
|
119186
|
+
const after2 = fstatSync29(fd), current = lstatSync42(path);
|
|
118958
119187
|
if (length !== before2.size || after2.size !== before2.size || before2.mtimeMs !== after2.mtimeMs || before2.ctimeMs !== after2.ctimeMs || current.dev !== before2.dev || current.ino !== before2.ino || !current.isFile() || current.isSymbolicLink())
|
|
118959
119188
|
throw new RecurringInputError;
|
|
118960
119189
|
return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, length)));
|
|
@@ -119238,7 +119467,7 @@ var init_completion = __esm(() => {
|
|
|
119238
119467
|
});
|
|
119239
119468
|
|
|
119240
119469
|
// src/lib/portable-snapshot-filter.ts
|
|
119241
|
-
import { readdirSync as readdirSync25, statSync as
|
|
119470
|
+
import { readdirSync as readdirSync25, statSync as statSync23 } from "fs";
|
|
119242
119471
|
import { homedir as homedir11 } from "os";
|
|
119243
119472
|
import { join as join68, sep as sep19 } from "path";
|
|
119244
119473
|
function isExcludedSkillFileName(fileName) {
|
|
@@ -119306,7 +119535,7 @@ function walkEntries(absoluteRoot) {
|
|
|
119306
119535
|
}
|
|
119307
119536
|
function isRegularFile(filePath) {
|
|
119308
119537
|
try {
|
|
119309
|
-
return
|
|
119538
|
+
return statSync23(filePath).isFile();
|
|
119310
119539
|
} catch {
|
|
119311
119540
|
return false;
|
|
119312
119541
|
}
|
|
@@ -119392,10 +119621,10 @@ import {
|
|
|
119392
119621
|
copyFileSync as copyFileSync2,
|
|
119393
119622
|
mkdirSync as mkdirSync29,
|
|
119394
119623
|
readFileSync as readFileSync45,
|
|
119395
|
-
statSync as
|
|
119624
|
+
statSync as statSync24,
|
|
119396
119625
|
writeFileSync as writeFileSync26
|
|
119397
119626
|
} from "fs";
|
|
119398
|
-
import { dirname as dirname42, isAbsolute as
|
|
119627
|
+
import { dirname as dirname42, isAbsolute as isAbsolute41, relative as relative14, resolve as resolve37, sep as sep20 } from "path";
|
|
119399
119628
|
function validateStationId(stationId) {
|
|
119400
119629
|
if (!/^[a-z0-9-]+$/.test(stationId)) {
|
|
119401
119630
|
throw new StationSnapshotError("INVALID_STATION", `station id must be a slug, got: ${stationId}`);
|
|
@@ -119432,7 +119661,7 @@ function scanHome(definition, homesRoot) {
|
|
|
119432
119661
|
skipped.push({ relativePath: entry.relativePath, reason: "not-regular-file" });
|
|
119433
119662
|
continue;
|
|
119434
119663
|
}
|
|
119435
|
-
const info =
|
|
119664
|
+
const info = statSync24(entry.fullPath);
|
|
119436
119665
|
portable.push({
|
|
119437
119666
|
relativePath: entry.relativePath,
|
|
119438
119667
|
fullPath: entry.fullPath,
|
|
@@ -119501,7 +119730,7 @@ function writeStationSnapshot(options) {
|
|
|
119501
119730
|
for (const plan of plans) {
|
|
119502
119731
|
const destination = resolve37(repoRoot, plan.destination);
|
|
119503
119732
|
const destinationRelative = relative14(repoRoot, destination);
|
|
119504
|
-
if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep20) ||
|
|
119733
|
+
if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep20) || isAbsolute41(destinationRelative)) {
|
|
119505
119734
|
throw new StationSnapshotError("DESTINATION_ESCAPE", `destination escapes repo root: ${plan.destination}`);
|
|
119506
119735
|
}
|
|
119507
119736
|
let existingDigest = null;
|
|
@@ -119974,7 +120203,7 @@ var init_create_sync_config = __esm(() => {
|
|
|
119974
120203
|
});
|
|
119975
120204
|
|
|
119976
120205
|
// src/lib/agent-install-selection.ts
|
|
119977
|
-
import { lstatSync as
|
|
120206
|
+
import { lstatSync as lstatSync43 } from "fs";
|
|
119978
120207
|
import { dirname as dirname43, join as join70, resolve as resolve38 } from "path";
|
|
119979
120208
|
import { homedir as homedir12 } from "os";
|
|
119980
120209
|
function detectedIntegrationAgents(options = {}) {
|
|
@@ -119988,7 +120217,7 @@ function detectedIntegrationAgents(options = {}) {
|
|
|
119988
120217
|
throw new Error("Invalid existing bridge agent inventory");
|
|
119989
120218
|
const present2 = (path) => {
|
|
119990
120219
|
try {
|
|
119991
|
-
return
|
|
120220
|
+
return lstatSync43(path, { throwIfNoEntry: false }) !== undefined;
|
|
119992
120221
|
} catch {
|
|
119993
120222
|
throw new Error("Agent presence cannot be inspected; review native configuration before hook installation");
|
|
119994
120223
|
}
|
|
@@ -120018,7 +120247,7 @@ var init_agent_install_selection = __esm(() => {
|
|
|
120018
120247
|
});
|
|
120019
120248
|
|
|
120020
120249
|
// src/lib/codex-native-config.ts
|
|
120021
|
-
import { isDeepStrictEqual as
|
|
120250
|
+
import { isDeepStrictEqual as isDeepStrictEqual17 } from "util";
|
|
120022
120251
|
function isRecord8(value) {
|
|
120023
120252
|
if (!value || typeof value !== "object")
|
|
120024
120253
|
return false;
|
|
@@ -120040,7 +120269,7 @@ function decimalIdentity(text4) {
|
|
|
120040
120269
|
return `${match[1]}${coefficient}e${exponent}`;
|
|
120041
120270
|
}
|
|
120042
120271
|
function codexNativeConfigEqual(native, expected) {
|
|
120043
|
-
if (
|
|
120272
|
+
if (isDeepStrictEqual17(native, expected))
|
|
120044
120273
|
return true;
|
|
120045
120274
|
if (typeof expected === "number") {
|
|
120046
120275
|
if (!Number.isFinite(expected) || !isRecord8(native))
|
|
@@ -120064,11 +120293,11 @@ var NUMBER_TAG = "$serde_json::private::Number";
|
|
|
120064
120293
|
var init_codex_native_config = () => {};
|
|
120065
120294
|
|
|
120066
120295
|
// src/lib/codex-hook-trust-identity.ts
|
|
120067
|
-
import { lstatSync as
|
|
120068
|
-
import { dirname as dirname44, isAbsolute as
|
|
120069
|
-
import { isDeepStrictEqual as
|
|
120296
|
+
import { lstatSync as lstatSync44, realpathSync as realpathSync20 } from "fs";
|
|
120297
|
+
import { dirname as dirname44, isAbsolute as isAbsolute42, join as join71, resolve as resolve39 } from "path";
|
|
120298
|
+
import { isDeepStrictEqual as isDeepStrictEqual18 } from "util";
|
|
120070
120299
|
function commandPhysical(command) {
|
|
120071
|
-
need8(typeof command === "string" &&
|
|
120300
|
+
need8(typeof command === "string" && isAbsolute42(command) && !command.includes("\x00") && resolve39(command) === command, COMMAND_NOT_CANONICAL);
|
|
120072
120301
|
const physical = realpathSync20(command);
|
|
120073
120302
|
let spelled;
|
|
120074
120303
|
try {
|
|
@@ -120079,7 +120308,7 @@ function commandPhysical(command) {
|
|
|
120079
120308
|
safeParents(spelled);
|
|
120080
120309
|
let direct = false;
|
|
120081
120310
|
try {
|
|
120082
|
-
const leaf =
|
|
120311
|
+
const leaf = lstatSync44(spelled);
|
|
120083
120312
|
direct = leaf.isSymbolicLink() ? trustedAncestorOwner(leaf.uid) && directAliasTarget(spelled) === physical : spelled === physical;
|
|
120084
120313
|
} catch {}
|
|
120085
120314
|
need8(direct, COMMAND_ALIAS_UNSAFE);
|
|
@@ -120123,7 +120352,7 @@ function targetUnchanged(command, target) {
|
|
|
120123
120352
|
assertPinnedRuntime(target.runtime);
|
|
120124
120353
|
}
|
|
120125
120354
|
function inspectRecordedSkillsCli(command, expected) {
|
|
120126
|
-
need8(
|
|
120355
|
+
need8(isAbsolute42(command) && !command.includes("\x00"), "RECONCILE_RECORDED_COMMAND_REQUIRED");
|
|
120127
120356
|
const target = skillsCommandTarget(command), resolved = target.entry;
|
|
120128
120357
|
const cli = snapshot(resolved, false, { readOnlyPackage: true });
|
|
120129
120358
|
const manifest = snapshot(join71(dirname44(dirname44(resolved)), "package.json"), false, { readOnlyPackage: true });
|
|
@@ -120131,7 +120360,7 @@ function inspectRecordedSkillsCli(command, expected) {
|
|
|
120131
120360
|
need8(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join71(dirname44(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
|
|
120132
120361
|
need8((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
|
|
120133
120362
|
const receipt = { path: resolved, version: pkg.version, sha256: cli.sha256, manifestSha256: manifest.sha256 };
|
|
120134
|
-
need8(
|
|
120363
|
+
need8(isDeepStrictEqual18(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
|
|
120135
120364
|
return { receipt, recheck() {
|
|
120136
120365
|
targetUnchanged(command, target);
|
|
120137
120366
|
unchanged2(cli);
|
|
@@ -120142,7 +120371,7 @@ function bindSkillsCli(command, reviewed) {
|
|
|
120142
120371
|
const normal = Bun.which("skills", { PATH: process.env.PATH });
|
|
120143
120372
|
need8(normal, "SKILLS_COMMAND_UNAVAILABLE");
|
|
120144
120373
|
const normalTarget = skillsCommandTarget(normal), resolved = normalTarget.entry;
|
|
120145
|
-
const bound =
|
|
120374
|
+
const bound = isAbsolute42(command) ? command : command === "skills" ? normal : undefined;
|
|
120146
120375
|
need8(bound, "SKILLS_COMMAND_MISMATCH");
|
|
120147
120376
|
const boundTarget = skillsCommandTarget(bound);
|
|
120148
120377
|
need8(boundTarget.entry === resolved, "SKILLS_COMMAND_MISMATCH");
|
|
@@ -120201,19 +120430,19 @@ var init_codex_hook_trust_identity = __esm(() => {
|
|
|
120201
120430
|
});
|
|
120202
120431
|
|
|
120203
120432
|
// src/lib/codex-hook-policy-recovery.ts
|
|
120204
|
-
import { isDeepStrictEqual as
|
|
120433
|
+
import { isDeepStrictEqual as isDeepStrictEqual19 } from "util";
|
|
120205
120434
|
function reviewedClaudeDiscoveryChange(beforeText, currentText, options) {
|
|
120206
120435
|
need8(typeof options.reason === "string" && options.reason.trim().length > 0 && options.reason.length <= 512 && !/[\x00-\x1f\x7f]/.test(options.reason), "RECONCILE_RECOVERY_REASON_REQUIRED");
|
|
120207
120436
|
need8(options.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(options.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
|
|
120208
120437
|
const before2 = parseManagedSkillPolicy(beforeText), current = parseManagedSkillPolicy(currentText);
|
|
120209
120438
|
const oldDiscovery = before2.bridge?.discovery?.claude, newDiscovery = current.bridge?.discovery?.claude;
|
|
120210
120439
|
need8(oldDiscovery?.agent === "claude" && newDiscovery?.agent === "claude" && oldDiscovery.method === "reviewed" && newDiscovery.method === "reviewed", "RECONCILE_POLICY_CHANGED");
|
|
120211
|
-
const changes = ["roots", "sources"].filter((key2) => !
|
|
120440
|
+
const changes = ["roots", "sources"].filter((key2) => !isDeepStrictEqual19(oldDiscovery[key2], newDiscovery[key2])).map((key2) => ({ path: `bridge.discovery.claude.${key2}`, before: oldDiscovery[key2], after: newDiscovery[key2] }));
|
|
120212
120441
|
need8(changes.length > 0, "RECONCILE_POLICY_CHANGED");
|
|
120213
120442
|
const compared = structuredClone(current);
|
|
120214
120443
|
compared.bridge.discovery.claude.roots = oldDiscovery.roots;
|
|
120215
120444
|
compared.bridge.discovery.claude.sources = oldDiscovery.sources;
|
|
120216
|
-
need8(
|
|
120445
|
+
need8(isDeepStrictEqual19(before2, compared), "RECONCILE_POLICY_CHANGED");
|
|
120217
120446
|
verifyAgentDiscovery(newDiscovery);
|
|
120218
120447
|
return { reason: options.reason, changes };
|
|
120219
120448
|
}
|
|
@@ -120224,16 +120453,16 @@ var init_codex_hook_policy_recovery = __esm(() => {
|
|
|
120224
120453
|
});
|
|
120225
120454
|
|
|
120226
120455
|
// src/lib/agent-codex-trust.ts
|
|
120227
|
-
import { lstatSync as
|
|
120228
|
-
import { createHash as createHash43, randomUUID as
|
|
120456
|
+
import { lstatSync as lstatSync45, mkdirSync as mkdirSync30, readdirSync as readdirSync26, readFileSync as readFileSync46, realpathSync as realpathSync21, statSync as statSync25 } from "fs";
|
|
120457
|
+
import { createHash as createHash43, randomUUID as randomUUID13 } from "crypto";
|
|
120229
120458
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
120230
|
-
import { dirname as dirname45, isAbsolute as
|
|
120459
|
+
import { dirname as dirname45, isAbsolute as isAbsolute43, join as join72, resolve as resolve40 } from "path";
|
|
120231
120460
|
import { homedir as homedir13 } from "os";
|
|
120232
|
-
import { isDeepStrictEqual as
|
|
120461
|
+
import { isDeepStrictEqual as isDeepStrictEqual20 } from "util";
|
|
120233
120462
|
function verifyReleaseArtifact(proof, skillsCli) {
|
|
120234
|
-
need8(
|
|
120463
|
+
need8(isAbsolute43(proof.packageTarPath) && !proof.packageTarPath.includes("\x00"), "RECONCILE_RELEASE_PROVENANCE_PATH");
|
|
120235
120464
|
const tarPath = realpathSync21(proof.packageTarPath);
|
|
120236
|
-
need8(
|
|
120465
|
+
need8(statSync25(tarPath).isFile(), "RECONCILE_RELEASE_PROVENANCE_PATH");
|
|
120237
120466
|
const tarBytes = readFileSync46(tarPath);
|
|
120238
120467
|
need8(tarBytes.byteLength === proof.packageTarBytes && createHash43("sha256").update(tarBytes).digest("hex") === proof.packageTarSha256, "RECONCILE_RELEASE_ARTIFACT_CHANGED");
|
|
120239
120468
|
const packageRoot = dirname45(dirname45(realpathSync21(skillsCli.receipt.path)));
|
|
@@ -120257,10 +120486,10 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
120257
120486
|
const home = resolve40(options.home ?? homedir13()), dataDir3 = resolve40(options.dataDir ?? getDataDirReadOnly());
|
|
120258
120487
|
const parent = resolve40(join72(dataDir3, "native-hook-trust")), journal = resolve40(options.journal);
|
|
120259
120488
|
need8(journal.startsWith(parent + "/") && /^[a-f0-9-]{36}$/.test(journal.slice(parent.length + 1)), "RECONCILE_JOURNAL_PATH");
|
|
120260
|
-
const dir =
|
|
120489
|
+
const dir = lstatSync45(journal, { throwIfNoEntry: false });
|
|
120261
120490
|
need8(!!dir && dir.isDirectory() && !dir.isSymbolicLink() && dir.uid === process.getuid() && (dir.mode & 511) === 448, "UNSAFE_JOURNAL");
|
|
120262
|
-
need8(!
|
|
120263
|
-
need8(
|
|
120491
|
+
need8(!lstatSync45(join72(journal, "receipt.json"), { throwIfNoEntry: false }), "RECONCILE_ALREADY_COMPLETE");
|
|
120492
|
+
need8(lstatSync45(join72(journal, "stopped.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_JOURNAL_INCOMPLETE");
|
|
120264
120493
|
const stoppedFile = snapshot(join72(journal, "stopped.json"), true);
|
|
120265
120494
|
const intentFile = snapshot(join72(journal, "intent.json"), true), intent = JSON.parse(intentFile.text);
|
|
120266
120495
|
const configBefore = snapshot(join72(journal, "config.before.toml"), true), hooksBefore = snapshot(join72(journal, "hooks.before.json"), true), policyBefore = snapshot(join72(journal, "policy.before.json"), true);
|
|
@@ -120271,7 +120500,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
120271
120500
|
const configSha256 = intent.configSha256 ?? configBefore.sha256, configVersion = intent.configVersion ?? intent.expectedVersion;
|
|
120272
120501
|
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 };
|
|
120273
120502
|
need8(makePlanDigest(digestInput) === intent.planDigest, "RECONCILE_PLAN_CHANGED");
|
|
120274
|
-
need8(
|
|
120503
|
+
need8(isDeepStrictEqual20(intent.hooks, admitted.filter((hook) => !hook.enabled || hook.trustStatus !== "trusted")), "RECONCILE_INTENT_HOOKS_CHANGED");
|
|
120275
120504
|
need8(configBefore.sha256 === (intent.beforeSha256 ?? intent.configSha256) && hooksBefore.sha256 === intent.hooksSha256 && policyBefore.sha256 === intent.policySha256, "RECONCILE_JOURNAL_CHANGED");
|
|
120276
120505
|
const policyCurrent = snapshot(join72(dataDir3, "agent-policy.json"), true);
|
|
120277
120506
|
const { claudeDiscoveryRecovery: claudeRecovery, nativeHookAdditionsRecovery: additionsRecovery } = options;
|
|
@@ -120284,13 +120513,13 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
120284
120513
|
if (policyCurrent.sha256 !== policyBefore.sha256 && !claudeRecovery) {
|
|
120285
120514
|
need8(options.supersedeBinding === true, "RECONCILE_POLICY_CHANGED");
|
|
120286
120515
|
const oldPolicy = JSON.parse(policyBefore.text), currentPolicy = JSON.parse(policyCurrent.text);
|
|
120287
|
-
need8(
|
|
120516
|
+
need8(isDeepStrictEqual20(withoutCodexCommand(oldPolicy), withoutCodexCommand(currentPolicy)), "RECONCILE_POLICY_CHANGED");
|
|
120288
120517
|
supersededBinding = true;
|
|
120289
120518
|
}
|
|
120290
120519
|
if (supersededBinding || recovery) {
|
|
120291
120520
|
need8(Array.isArray(intent.nativeHooks) && intent.nativeHooks.length > 0, "RECONCILE_NATIVE_INVENTORY_REQUIRED");
|
|
120292
120521
|
const proof = options.releaseProof;
|
|
120293
|
-
need8(!!proof &&
|
|
120522
|
+
need8(!!proof && isAbsolute43(proof.packageTarPath) && /^[a-f0-9]{64}$/.test(proof.packageTarSha256) && Number.isInteger(proof.packageTarBytes) && proof.packageTarBytes > 0 && /^[a-f0-9]{64}$/.test(proof.manifestSha256) && /^[a-f0-9]{64}$/.test(proof.executableSha256), "RECONCILE_RELEASE_PROVENANCE_REQUIRED");
|
|
120294
120523
|
}
|
|
120295
120524
|
const currentConfig = snapshot(intent.configPath, true);
|
|
120296
120525
|
const policy = parseManagedSkillPolicy(policyCurrent.text), binding = policy.bridge;
|
|
@@ -120320,7 +120549,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
120320
120549
|
need8(state?.enabled === true && typeof state.trusted_hash === "string" && /^sha256:[a-f0-9]{64}$/.test(state.trusted_hash), "RECONCILE_CONFIG_DRIFT");
|
|
120321
120550
|
}
|
|
120322
120551
|
} else
|
|
120323
|
-
need8(
|
|
120552
|
+
need8(isDeepStrictEqual20(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
|
|
120324
120553
|
const configDiscoveryRecovery = recovery && binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, configBefore, currentConfig, intent.hooks, additions?.trustProof) : undefined;
|
|
120325
120554
|
assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: configDiscoveryRecovery });
|
|
120326
120555
|
const recoveryCli = recovery ? bindSkillsCli("skills", options.reviewedSkillsCli) : undefined;
|
|
@@ -120329,14 +120558,14 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
120329
120558
|
const skillsCli = recovery ? inspectRecordedSkillsCli(binding.commands.codex, intent.skillsCli) : bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
|
|
120330
120559
|
if (supersededBinding)
|
|
120331
120560
|
verifyReleaseArtifact(options.releaseProof, skillsCli);
|
|
120332
|
-
const skillsBindingChanged = !
|
|
120561
|
+
const skillsBindingChanged = !isDeepStrictEqual20(skillsCli.receipt, intent.skillsCli);
|
|
120333
120562
|
need8(!skillsBindingChanged || supersededBinding, "RECONCILE_SKILLS_BINDING_CHANGED");
|
|
120334
120563
|
if (!additions && hooksCurrent.sha256 !== intent.hooksSha256 && hooksCurrent.sha256 !== hooksBefore.sha256) {
|
|
120335
120564
|
need8(supersededBinding, "RECONCILE_HOOKS_CHANGED");
|
|
120336
120565
|
const currentDeclarations = JSON.parse(hooksCurrent.text).hooks;
|
|
120337
120566
|
for (const [event, [nativeEvent]] of Object.entries(eventNames)) {
|
|
120338
120567
|
const command = renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, event);
|
|
120339
|
-
need8(
|
|
120568
|
+
need8(isDeepStrictEqual20(currentDeclarations?.[event], [{ hooks: [{ type: "command", command, timeout: 15 }] }]), "RECONCILE_BINDING_HOOK_CHANGED");
|
|
120340
120569
|
}
|
|
120341
120570
|
}
|
|
120342
120571
|
rpc = await connect({ command: options.codexCommand ?? "codex", home, codexHome });
|
|
@@ -120359,9 +120588,9 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
120359
120588
|
delete identity6.command;
|
|
120360
120589
|
return identity6;
|
|
120361
120590
|
};
|
|
120362
|
-
need8(
|
|
120591
|
+
need8(isDeepStrictEqual20(stable(actual), stable(expected)), "RECONCILE_NATIVE_IDENTITY_CHANGED");
|
|
120363
120592
|
if (!plannedKeys.has(expected.key))
|
|
120364
|
-
need8(
|
|
120593
|
+
need8(isDeepStrictEqual20(actual, expected), "RECONCILE_UNRELATED_HOOK_CHANGED");
|
|
120365
120594
|
}
|
|
120366
120595
|
for (const wanted of intent.hooks) {
|
|
120367
120596
|
const matches2 = nativeHooks.filter((h2) => h2.key === wanted.key || h2.key === wanted.key.replace(join72(home, ".codex/hooks.json"), hooksPath));
|
|
@@ -120380,7 +120609,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
120380
120609
|
const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
|
|
120381
120610
|
need8(layers?.length === 1 && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, current), "RECONCILE_NATIVE_CONFIG_MISMATCH");
|
|
120382
120611
|
const finalDiscovery = await rpc.request("hooks/list", { cwds: [home] });
|
|
120383
|
-
need8(Array.isArray(finalDiscovery?.data) && finalDiscovery.data.length === 1 && finalDiscovery.data[0].cwd === home && !finalDiscovery.data[0].errors?.length && !finalDiscovery.data[0].warnings?.length && (!recordedNativeHooks ||
|
|
120612
|
+
need8(Array.isArray(finalDiscovery?.data) && finalDiscovery.data.length === 1 && finalDiscovery.data[0].cwd === home && !finalDiscovery.data[0].errors?.length && !finalDiscovery.data[0].warnings?.length && (!recordedNativeHooks || isDeepStrictEqual20(finalDiscovery.data[0].hooks.map(safeNativeHook), nativeHooks.map(safeNativeHook))), "RECONCILE_NATIVE_STATE_CHANGED");
|
|
120384
120613
|
const finalConfig = await rpc.request("config/read", { includeLayers: true, cwd: home });
|
|
120385
120614
|
const finalLayers = finalConfig?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
|
|
120386
120615
|
need8(finalLayers?.length === 1 && !finalLayers[0].disabledReason && codexNativeConfigEqual(finalLayers[0].config, current), "RECONCILE_NATIVE_CONFIG_CHANGED");
|
|
@@ -120435,7 +120664,7 @@ async function enrollCodexNativeHooksUnlocked(options, connect, admission) {
|
|
|
120435
120664
|
const binding = policy.bridge, alias = binding.rootAliases?.find((item) => item.agent === "codex");
|
|
120436
120665
|
const skillsCli = bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
|
|
120437
120666
|
const physicalRoot = alias?.target ?? join72(home, ".codex"), hooksPath = join72(physicalRoot, "hooks.json"), configPath = join72(physicalRoot, "config.toml");
|
|
120438
|
-
need8(options.codexHome === undefined ||
|
|
120667
|
+
need8(options.codexHome === undefined || isAbsolute43(options.codexHome) && [join72(home, ".codex"), physicalRoot].includes(options.codexHome), "NATIVE_HOME_NOT_ADMITTED");
|
|
120439
120668
|
const codexHome = options.codexHome === undefined ? undefined : physicalRoot;
|
|
120440
120669
|
const nativeConfigPath = join72(codexHome ?? join72(home, ".codex"), "config.toml");
|
|
120441
120670
|
const hooksFile = snapshot(hooksPath), configFile = snapshot(configPath, true), original = structure3(configFile.text);
|
|
@@ -120445,7 +120674,7 @@ async function enrollCodexNativeHooksUnlocked(options, connect, admission) {
|
|
|
120445
120674
|
const groups = declarations[event];
|
|
120446
120675
|
need8(Array.isArray(groups), "DECLARATION_CHANGED");
|
|
120447
120676
|
const matches2 = groups.flatMap((group, gi) => (group.hooks ?? []).flatMap((entry, hi) => entry.command === command ? [{ group, entry, gi, hi }] : []));
|
|
120448
|
-
need8(matches2.length === 1 &&
|
|
120677
|
+
need8(matches2.length === 1 && isDeepStrictEqual20(matches2[0].group, { hooks: [{ type: "command", command, timeout: 15 }] }), "DECLARATION_CHANGED");
|
|
120449
120678
|
expected.push({ event: nativeEvent, key: `${join72(home, ".codex/hooks.json")}:${label}:${matches2[0].gi}:${matches2[0].hi}`, command });
|
|
120450
120679
|
}
|
|
120451
120680
|
codexTrustTextWitness(configFile.text, expected.map((h) => h.key));
|
|
@@ -120491,27 +120720,27 @@ async function enrollCodexNativeHooksUnlocked(options, connect, admission) {
|
|
|
120491
120720
|
if (options.apply)
|
|
120492
120721
|
need8(options.reviewedPlanDigest === planDigest, "PLAN_CHANGED: run the dry-run again and pass its reviewed --plan-digest with --apply");
|
|
120493
120722
|
const parent = join72(dataDir3, "native-hook-trust");
|
|
120494
|
-
const st =
|
|
120723
|
+
const st = lstatSync45(parent, { throwIfNoEntry: false });
|
|
120495
120724
|
if (st) {
|
|
120496
120725
|
need8(st.isDirectory() && !st.isSymbolicLink() && st.uid === process.getuid() && (st.mode & 511) === 448, "UNSAFE_JOURNAL");
|
|
120497
120726
|
const priorJournals = readdirSync26(parent);
|
|
120498
120727
|
need8(priorJournals.length < 1000, "JOURNAL_BOUND");
|
|
120499
120728
|
for (const name of priorJournals) {
|
|
120500
120729
|
need8(/^[a-f0-9-]{36}$/.test(name), "UNSAFE_JOURNAL");
|
|
120501
|
-
need8(
|
|
120730
|
+
need8(lstatSync45(join72(parent, name, "receipt.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_REQUIRED: inspect the incomplete private journal before applying again");
|
|
120502
120731
|
}
|
|
120503
120732
|
}
|
|
120504
120733
|
if (!options.apply || !planned.length)
|
|
120505
120734
|
return baseReceipt;
|
|
120506
120735
|
if (!st)
|
|
120507
120736
|
mkdirSync30(parent, { mode: 448 });
|
|
120508
|
-
journal = join72(parent,
|
|
120737
|
+
journal = join72(parent, randomUUID13());
|
|
120509
120738
|
mkdirSync30(journal, { mode: 448 });
|
|
120510
120739
|
save(join72(journal, "config.before.toml"), configFile.bytes);
|
|
120511
120740
|
save(join72(journal, "hooks.before.json"), hooksFile.bytes);
|
|
120512
120741
|
save(join72(journal, "policy.before.json"), policyFile.bytes);
|
|
120513
120742
|
save(join72(journal, "intent.json"), json2({ ...digestInput, planDigest, hooks: planned, nativeHooks: discovered.map(safeNativeHook), ...codexAdmissionReceipt(admission) }));
|
|
120514
|
-
need8(
|
|
120743
|
+
need8(isDeepStrictEqual20(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
|
|
120515
120744
|
checkInputs();
|
|
120516
120745
|
let result2;
|
|
120517
120746
|
try {
|
|
@@ -120525,7 +120754,7 @@ async function enrollCodexNativeHooksUnlocked(options, connect, admission) {
|
|
|
120525
120754
|
expectedConfig.hooks.state ??= {};
|
|
120526
120755
|
for (const h of planned)
|
|
120527
120756
|
expectedConfig.hooks.state[h.key] = { ...expectedConfig.hooks.state[h.key], enabled: true, trusted_hash: h.currentHash };
|
|
120528
|
-
need8(
|
|
120757
|
+
need8(isDeepStrictEqual20(structure3(after2.text), expectedConfig) && codexTrustTextWitness(after2.text, keys4) === preservationText, "PRESERVATION_FAILED");
|
|
120529
120758
|
const savedConfig = snapshot(join72(journal, "config.before.toml"), true);
|
|
120530
120759
|
need8(savedConfig.sha256 === configFile.sha256, "JOURNAL_CHANGED");
|
|
120531
120760
|
const discoveryTransition = binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, savedConfig, after2, planned) : undefined;
|
|
@@ -120533,8 +120762,8 @@ async function enrollCodexNativeHooksUnlocked(options, connect, admission) {
|
|
|
120533
120762
|
unchanged2(hooksFile);
|
|
120534
120763
|
assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: discoveryTransition });
|
|
120535
120764
|
const current = await list2(), confirmed = admit(current);
|
|
120536
|
-
need8(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") &&
|
|
120537
|
-
need8(
|
|
120765
|
+
need8(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") && isDeepStrictEqual20(confirmed.map((h) => [h.key, h.currentHash]), admitted.map((h) => [h.key, h.currentHash])), "NATIVE_NOT_ELIGIBLE");
|
|
120766
|
+
need8(isDeepStrictEqual20(current.filter((h) => !keys4.includes(h.key)), discovered.filter((h) => !keys4.includes(h.key))), "UNRELATED_HOOK_CHANGED");
|
|
120538
120767
|
unchanged2(after2);
|
|
120539
120768
|
unchanged2(savedConfig);
|
|
120540
120769
|
unchanged2(hooksFile);
|
|
@@ -120667,9 +120896,9 @@ var init_codex_native_trust = __esm(() => {
|
|
|
120667
120896
|
|
|
120668
120897
|
// src/lib/claude-prospective-review.ts
|
|
120669
120898
|
import { createHash as createHash45 } from "crypto";
|
|
120670
|
-
import { lstatSync as
|
|
120671
|
-
import { basename as basename23, dirname as dirname46, isAbsolute as
|
|
120672
|
-
import { isDeepStrictEqual as
|
|
120899
|
+
import { lstatSync as lstatSync46, readFileSync as readFileSync48, readdirSync as readdirSync27, realpathSync as realpathSync22 } from "fs";
|
|
120900
|
+
import { basename as basename23, dirname as dirname46, isAbsolute as isAbsolute44, join as join74, relative as relative15, resolve as resolve42, sep as sep21 } from "path";
|
|
120901
|
+
import { isDeepStrictEqual as isDeepStrictEqual21 } from "util";
|
|
120673
120902
|
function hashClaudeDiscoveryBinding(binding) {
|
|
120674
120903
|
return sha8(JSON.stringify(binding));
|
|
120675
120904
|
}
|
|
@@ -120719,7 +120948,7 @@ function keys4(value, expected, name) {
|
|
|
120719
120948
|
refuse8(`${name} has an unsupported shape`);
|
|
120720
120949
|
}
|
|
120721
120950
|
function abs(path, name) {
|
|
120722
|
-
if (typeof path !== "string" || !path || path.length > 4096 || /[\x00-\x1f\x7f]/.test(path) || !
|
|
120951
|
+
if (typeof path !== "string" || !path || path.length > 4096 || /[\x00-\x1f\x7f]/.test(path) || !isAbsolute44(path) || resolve42(path) !== path)
|
|
120723
120952
|
refuse8(`${name} must be a normalized absolute path`);
|
|
120724
120953
|
}
|
|
120725
120954
|
function validUtcTimestamp(value) {
|
|
@@ -120728,23 +120957,23 @@ function validUtcTimestamp(value) {
|
|
|
120728
120957
|
function safeFile(path, name) {
|
|
120729
120958
|
abs(path, name);
|
|
120730
120959
|
for (let at2 = dirname46(path);; at2 = dirname46(at2)) {
|
|
120731
|
-
const stat4 =
|
|
120960
|
+
const stat4 = lstatSync46(at2, { throwIfNoEntry: false });
|
|
120732
120961
|
if (!stat4?.isDirectory() || stat4.isSymbolicLink())
|
|
120733
120962
|
refuse8(`${name} traverses a symlink or non-directory`);
|
|
120734
120963
|
if (at2 === dirname46(at2))
|
|
120735
120964
|
break;
|
|
120736
120965
|
}
|
|
120737
|
-
const stat3 =
|
|
120966
|
+
const stat3 = lstatSync46(path, { throwIfNoEntry: false });
|
|
120738
120967
|
if (!stat3?.isFile() || stat3.isSymbolicLink() || stat3.size > MAX_CANDIDATE_BYTES)
|
|
120739
120968
|
refuse8(`${name} is not a bounded regular file`);
|
|
120740
120969
|
return readFileSync48(path);
|
|
120741
120970
|
}
|
|
120742
120971
|
function canonicalDir(path, name) {
|
|
120743
120972
|
abs(path, name);
|
|
120744
|
-
if (realpathSync22(path) !== path || !
|
|
120973
|
+
if (realpathSync22(path) !== path || !lstatSync46(path).isDirectory())
|
|
120745
120974
|
refuse8(`${name} is not a canonical directory`);
|
|
120746
120975
|
for (let at2 = path;; at2 = dirname46(at2)) {
|
|
120747
|
-
const stat3 =
|
|
120976
|
+
const stat3 = lstatSync46(at2);
|
|
120748
120977
|
if (!stat3.isDirectory() || stat3.isSymbolicLink())
|
|
120749
120978
|
refuse8(`${name} traverses a symlink`);
|
|
120750
120979
|
if (at2 === dirname46(at2))
|
|
@@ -120756,7 +120985,7 @@ function captureClaudeProspectiveCandidateClosure(root2) {
|
|
|
120756
120985
|
const entries = [];
|
|
120757
120986
|
let bytes = 0;
|
|
120758
120987
|
const walk2 = (directory3) => {
|
|
120759
|
-
const beforeDirectory =
|
|
120988
|
+
const beforeDirectory = lstatSync46(directory3);
|
|
120760
120989
|
const names = readdirSync27(directory3).sort();
|
|
120761
120990
|
if (new Set(names).size !== names.length)
|
|
120762
120991
|
refuse8("candidate contains ambiguous directory entries");
|
|
@@ -120766,7 +120995,7 @@ function captureClaudeProspectiveCandidateClosure(root2) {
|
|
|
120766
120995
|
const path = join74(directory3, name), rel = relative15(root2, path).split(sep21).join("/");
|
|
120767
120996
|
if (entries.length >= MAX_CANDIDATE_FILES)
|
|
120768
120997
|
refuse8("candidate closure exceeds its member limit");
|
|
120769
|
-
const stat3 =
|
|
120998
|
+
const stat3 = lstatSync46(path);
|
|
120770
120999
|
if (stat3.isSymbolicLink())
|
|
120771
121000
|
refuse8("candidate closure contains a symlink");
|
|
120772
121001
|
if (stat3.isDirectory()) {
|
|
@@ -120776,14 +121005,14 @@ function captureClaudeProspectiveCandidateClosure(root2) {
|
|
|
120776
121005
|
bytes += stat3.size;
|
|
120777
121006
|
if (bytes > MAX_CANDIDATE_BYTES)
|
|
120778
121007
|
refuse8("candidate closure exceeds its byte limit");
|
|
120779
|
-
const content = safeFile(path, "candidate member"), after2 =
|
|
121008
|
+
const content = safeFile(path, "candidate member"), after2 = lstatSync46(path);
|
|
120780
121009
|
if (!after2.isFile() || after2.dev !== stat3.dev || after2.ino !== stat3.ino || after2.size !== stat3.size || after2.mtimeMs !== stat3.mtimeMs || after2.ctimeMs !== stat3.ctimeMs)
|
|
120781
121010
|
refuse8("candidate member changed while being read");
|
|
120782
121011
|
entries.push([rel, "file", sha8(content)]);
|
|
120783
121012
|
} else
|
|
120784
121013
|
refuse8("candidate closure contains a special file");
|
|
120785
121014
|
}
|
|
120786
|
-
const afterDirectory =
|
|
121015
|
+
const afterDirectory = lstatSync46(directory3);
|
|
120787
121016
|
if (!afterDirectory.isDirectory() || afterDirectory.dev !== beforeDirectory.dev || afterDirectory.ino !== beforeDirectory.ino || afterDirectory.mtimeMs !== beforeDirectory.mtimeMs || afterDirectory.ctimeMs !== beforeDirectory.ctimeMs)
|
|
120788
121017
|
refuse8("candidate directory changed while being read");
|
|
120789
121018
|
};
|
|
@@ -120807,11 +121036,11 @@ function captureClaudeInstallerCandidate(root2, policyPath) {
|
|
|
120807
121036
|
if (names.has(row2.name))
|
|
120808
121037
|
refuse8("candidate catalog repeats a plugin name");
|
|
120809
121038
|
names.add(row2.name);
|
|
120810
|
-
if (typeof row2.source !== "string" ||
|
|
121039
|
+
if (typeof row2.source !== "string" || isAbsolute44(row2.source) || /[\\\x00-\x1f\x7f]/.test(row2.source))
|
|
120811
121040
|
refuse8("candidate catalog plugin source is invalid");
|
|
120812
121041
|
const pluginRoot = resolve42(root2, row2.source);
|
|
120813
121042
|
const relativeRoot = relative15(root2, pluginRoot);
|
|
120814
|
-
if (!relativeRoot || relativeRoot === "." || relativeRoot === ".." || relativeRoot.startsWith(`..${sep21}`) ||
|
|
121043
|
+
if (!relativeRoot || relativeRoot === "." || relativeRoot === ".." || relativeRoot.startsWith(`..${sep21}`) || isAbsolute44(relativeRoot))
|
|
120815
121044
|
refuse8("candidate plugin source escapes the candidate root");
|
|
120816
121045
|
const path = join74(pluginRoot, ".claude-plugin/plugin.json");
|
|
120817
121046
|
return { plugin: row2.name, ...captureClaudePluginManifestFile(path) };
|
|
@@ -120830,7 +121059,7 @@ function captureClaudeInstallerCandidate(root2, policyPath) {
|
|
|
120830
121059
|
}
|
|
120831
121060
|
function readWitness(path, expected, name) {
|
|
120832
121061
|
abs(path, `${name} path`);
|
|
120833
|
-
const stat3 =
|
|
121062
|
+
const stat3 = lstatSync46(path, { throwIfNoEntry: false });
|
|
120834
121063
|
if (expected === null) {
|
|
120835
121064
|
if (stat3)
|
|
120836
121065
|
refuse8(`${name} was absent at review but is now present`);
|
|
@@ -120882,7 +121111,7 @@ function unreviewedProjectSettingsRefusal(path, expected, name) {
|
|
|
120882
121111
|
return null;
|
|
120883
121112
|
}
|
|
120884
121113
|
function jsonFile(path, name) {
|
|
120885
|
-
const stat3 =
|
|
121114
|
+
const stat3 = lstatSync46(path, { throwIfNoEntry: false });
|
|
120886
121115
|
if (!stat3)
|
|
120887
121116
|
return null;
|
|
120888
121117
|
let value;
|
|
@@ -120914,7 +121143,7 @@ function assertNoUnprojectedSkillPayload(root2, catalogPath, marketplace, plugin
|
|
|
120914
121143
|
const walk2 = (directory3) => {
|
|
120915
121144
|
for (const name of readdirSync27(directory3).sort()) {
|
|
120916
121145
|
const path = join74(directory3, name), rel = relative15(root2, path).split(sep21).join("/");
|
|
120917
|
-
const stat3 =
|
|
121146
|
+
const stat3 = lstatSync46(path);
|
|
120918
121147
|
if (stat3.isDirectory())
|
|
120919
121148
|
walk2(path);
|
|
120920
121149
|
else if (stat3.isFile()) {
|
|
@@ -120980,7 +121209,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
120980
121209
|
refuse8("CLAUDE_CODE_PLUGIN_CACHE_DIR overrides are unsupported by this prospective schema; bind and review the actual cache root first");
|
|
120981
121210
|
if (request2.native.pluginRoot !== pluginRoot)
|
|
120982
121211
|
refuse8("Claude plugin root differs from the supported standard plugins directory; Cowork and custom cache roots require a separately bound schema");
|
|
120983
|
-
const pluginRootStat =
|
|
121212
|
+
const pluginRootStat = lstatSync46(pluginRoot, { throwIfNoEntry: false });
|
|
120984
121213
|
if (pluginRootStat && (!pluginRootStat.isDirectory() || pluginRootStat.isSymbolicLink()))
|
|
120985
121214
|
refuse8("Claude plugin root is not a regular directory");
|
|
120986
121215
|
keys4(request2.candidate, ["marketplace", "root", "catalogPath", "catalogSha256", "closureSha256", "plugins", ...hasOwn2(request2.candidate, "releaseManifest") ? ["releaseManifest"] : [], ...hasOwn2(request2.candidate, "functionHooksEnv") ? ["functionHooksEnv"] : [], ...hasOwn2(request2.candidate, "settingsMarketplaceSource") ? ["settingsMarketplaceSource"] : []], "candidate");
|
|
@@ -121046,7 +121275,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
121046
121275
|
refuse8("plugin manifest must be under a plugin root inside the frozen marketplace closure");
|
|
121047
121276
|
const pluginRoot2 = dirname46(dirname46(selected.manifestPath));
|
|
121048
121277
|
const relativePluginRoot = relative15(candidate2.root, pluginRoot2);
|
|
121049
|
-
if (!relativePluginRoot || relativePluginRoot === "." || relativePluginRoot === ".." || relativePluginRoot.startsWith(`..${sep21}`) ||
|
|
121278
|
+
if (!relativePluginRoot || relativePluginRoot === "." || relativePluginRoot === ".." || relativePluginRoot.startsWith(`..${sep21}`) || isAbsolute44(relativePluginRoot))
|
|
121050
121279
|
refuse8("plugin root must be a child of the frozen marketplace root");
|
|
121051
121280
|
canonicalDir(pluginRoot2, "candidate plugin root");
|
|
121052
121281
|
if (!SHA256.test(selected.manifestSha256))
|
|
@@ -121080,7 +121309,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
121080
121309
|
const sourcePath = selectedEntry.source;
|
|
121081
121310
|
const sourceRelativePath = relative15(candidate2.root, pluginRoot2).split(sep21).join("/");
|
|
121082
121311
|
const expectedSourcePath = sourceRelativePath === "." ? "./" : `./${sourceRelativePath}`;
|
|
121083
|
-
if (typeof sourcePath !== "string" ||
|
|
121312
|
+
if (typeof sourcePath !== "string" || isAbsolute44(sourcePath) || sourcePath !== expectedSourcePath || resolve42(dirname46(dirname46(candidate2.catalogPath)), sourcePath) !== pluginRoot2)
|
|
121084
121313
|
refuse8("marketplace source does not resolve to the frozen plugin closure; external source mapping is not supported by this schema");
|
|
121085
121314
|
const entry = captureClaudeMarketplaceEntry(candidate2.catalogPath, candidate2.marketplace, selected.plugin);
|
|
121086
121315
|
if (entry.sha256.length !== 64)
|
|
@@ -121141,7 +121370,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
121141
121370
|
refuse8("Skills discovery preimage differs from its reviewed binding");
|
|
121142
121371
|
assertProjectDiscovery("claude", [request2.scope.projectPath], request2.native.home, canonical9, binding);
|
|
121143
121372
|
const stored = snapshot2.value.bridge?.discovery?.claude;
|
|
121144
|
-
if (!stored || !
|
|
121373
|
+
if (!stored || !isDeepStrictEqual21(stored, binding) || snapshot2.value.bridge?.home !== request2.native.home)
|
|
121145
121374
|
refuse8("Skills policy does not bind the reviewed current Claude discovery");
|
|
121146
121375
|
assertExemptUnchanged();
|
|
121147
121376
|
const delta = request2.delta;
|
|
@@ -121299,7 +121528,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
121299
121528
|
refuse8("current known marketplace autoUpdate is not a boolean");
|
|
121300
121529
|
}
|
|
121301
121530
|
}
|
|
121302
|
-
if (!
|
|
121531
|
+
if (!isDeepStrictEqual21(delta.settingsAfter, settingsAfter))
|
|
121303
121532
|
refuse8("complete settings document differs from the exact selected plugin/options/environment/marketplace operations");
|
|
121304
121533
|
const marketplaceRowBefore = marketplaces?.[candidate2.marketplace];
|
|
121305
121534
|
if (marketplaceRowBefore !== undefined && !object11(marketplaceRowBefore))
|
|
@@ -121311,7 +121540,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
121311
121540
|
if (marketplaceRowBefore?.lastUpdated !== undefined && !validUtcTimestamp(marketplaceRowBefore.lastUpdated))
|
|
121312
121541
|
refuse8("current marketplace update timestamp is invalid");
|
|
121313
121542
|
const targetMarketplaceLocation = candidate2.root;
|
|
121314
|
-
const sameMarketplaceSource =
|
|
121543
|
+
const sameMarketplaceSource = isDeepStrictEqual21(marketplaceRowBefore?.source, { source: "directory", path: candidate2.root }) && marketplaceRowBefore?.installLocation === targetMarketplaceLocation;
|
|
121315
121544
|
const afterMarketplace = {
|
|
121316
121545
|
source: { source: "directory", path: candidate2.root },
|
|
121317
121546
|
installLocation: targetMarketplaceLocation,
|
|
@@ -121320,7 +121549,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
121320
121549
|
};
|
|
121321
121550
|
const marketplacesAfter = marketplaces ? structuredClone(marketplaces) : {};
|
|
121322
121551
|
marketplacesAfter[candidate2.marketplace] = afterMarketplace;
|
|
121323
|
-
if (!
|
|
121552
|
+
if (!isDeepStrictEqual21(delta.knownMarketplacesAfter, marketplacesAfter))
|
|
121324
121553
|
refuse8("complete marketplace document differs from the exact selected-directory marketplace operation");
|
|
121325
121554
|
const installedAfter = registrations ? structuredClone(registrations) : { version: 2, plugins: {} };
|
|
121326
121555
|
if (installedAfter.plugins === undefined)
|
|
@@ -121340,7 +121569,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
|
|
|
121340
121569
|
nextRows[index] = targetRegistration;
|
|
121341
121570
|
installedAfter.plugins[pluginId2] = nextRows;
|
|
121342
121571
|
}
|
|
121343
|
-
if (!
|
|
121572
|
+
if (!isDeepStrictEqual21(delta.installedPluginsAfter, installedAfter))
|
|
121344
121573
|
refuse8("complete installed plugin document changes an unrelated registration or has target rows not derived from every selected candidate");
|
|
121345
121574
|
assertExemptUnchanged();
|
|
121346
121575
|
const semanticDocumentsSha256 = sha8(canonicalJson3({ settings: settingsAfter, knownMarketplaces: marketplacesAfter, installedPlugins: installedAfter }));
|
|
@@ -121419,7 +121648,7 @@ var init_claude_prospective_review = __esm(() => {
|
|
|
121419
121648
|
|
|
121420
121649
|
// src/lib/self-spawn.ts
|
|
121421
121650
|
import { realpathSync as realpathSync23 } from "fs";
|
|
121422
|
-
import { dirname as dirname47, isAbsolute as
|
|
121651
|
+
import { dirname as dirname47, isAbsolute as isAbsolute45, sep as sep22 } from "path";
|
|
121423
121652
|
function selfSpawnRoot(entry) {
|
|
121424
121653
|
const index = entry.indexOf(INSTALLED_PACKAGE);
|
|
121425
121654
|
const root2 = index > 0 ? entry.slice(0, index) : dirname47(entry);
|
|
@@ -121432,7 +121661,7 @@ function selfSpawnRoot(entry) {
|
|
|
121432
121661
|
function selfSpawnCommand(args2, options = {}) {
|
|
121433
121662
|
const runtime = options.runtime ?? process.execPath;
|
|
121434
121663
|
const entry = options.entry ?? process.argv[1];
|
|
121435
|
-
if (!runtime || !
|
|
121664
|
+
if (!runtime || !isAbsolute45(runtime) || !entry || !isAbsolute45(entry))
|
|
121436
121665
|
throw new Error("SKILLS_SELF_SPAWN_ENTRY_UNRESOLVED");
|
|
121437
121666
|
const root2 = selfSpawnRoot(entry);
|
|
121438
121667
|
const env3 = pinnedLauncherEnvironment(options.env ?? process.env);
|
|
@@ -121538,8 +121767,8 @@ var init_claude_installer_binding = __esm(() => {
|
|
|
121538
121767
|
});
|
|
121539
121768
|
|
|
121540
121769
|
// src/cli/commands/claude-installer-capture.ts
|
|
121541
|
-
import { closeSync as closeSync30, constants as constants29, fstatSync as fstatSync30, lstatSync as
|
|
121542
|
-
import { isAbsolute as
|
|
121770
|
+
import { closeSync as closeSync30, constants as constants29, fstatSync as fstatSync30, lstatSync as lstatSync47, openSync as openSync30, readSync as readSync22 } from "fs";
|
|
121771
|
+
import { isAbsolute as isAbsolute46, resolve as resolve43 } from "path";
|
|
121543
121772
|
function need11(condition, code2) {
|
|
121544
121773
|
if (!condition)
|
|
121545
121774
|
throw new CaptureRefusal(code2);
|
|
@@ -121553,11 +121782,11 @@ function exactKeys5(value, expected, operation) {
|
|
|
121553
121782
|
}
|
|
121554
121783
|
}
|
|
121555
121784
|
function canonicalPath2(value) {
|
|
121556
|
-
need11(typeof value === "string" &&
|
|
121785
|
+
need11(typeof value === "string" && isAbsolute46(value) && resolve43(value) === value && !/[\x00-\x1f\x7f]/.test(value), "INVALID_PATH: path fields must be normalized absolute paths without control characters");
|
|
121557
121786
|
}
|
|
121558
121787
|
function readRequest2(path) {
|
|
121559
121788
|
canonicalPath2(path);
|
|
121560
|
-
const before2 =
|
|
121789
|
+
const before2 = lstatSync47(path, { throwIfNoEntry: false });
|
|
121561
121790
|
if (!before2?.isFile() || before2.isSymbolicLink() || before2.size > MAX_REQUEST_BYTES)
|
|
121562
121791
|
throw new CaptureRefusal("INVALID_REQUEST_FILE: --request must name a regular non-symlink JSON file no larger than 64 KiB");
|
|
121563
121792
|
const fd = openSync30(path, constants29.O_RDONLY | (constants29.O_NOFOLLOW ?? 0) | constants29.O_NONBLOCK);
|
|
@@ -121572,7 +121801,7 @@ function readRequest2(path) {
|
|
|
121572
121801
|
break;
|
|
121573
121802
|
length += count;
|
|
121574
121803
|
}
|
|
121575
|
-
const after2 = fstatSync30(fd), current =
|
|
121804
|
+
const after2 = fstatSync30(fd), current = lstatSync47(path);
|
|
121576
121805
|
need11(length <= MAX_REQUEST_BYTES && length === opened.size && after2.size === opened.size && after2.mtimeMs === opened.mtimeMs && after2.ctimeMs === opened.ctimeMs && current.dev === opened.dev && current.ino === opened.ino && current.mtimeMs === opened.mtimeMs && current.ctimeMs === opened.ctimeMs, "INVALID_REQUEST_FILE: --request must remain unchanged while read");
|
|
121577
121806
|
try {
|
|
121578
121807
|
return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, length)));
|
|
@@ -121724,10 +121953,10 @@ var exports_agent_integration = {};
|
|
|
121724
121953
|
__export(exports_agent_integration, {
|
|
121725
121954
|
registerAgentIntegration: () => registerAgentIntegration
|
|
121726
121955
|
});
|
|
121727
|
-
import { existsSync as existsSync36, lstatSync as
|
|
121956
|
+
import { existsSync as existsSync36, lstatSync as lstatSync48, readFileSync as readFileSync49, readSync as readSync23, writeFileSync as writeFileSync27 } from "fs";
|
|
121728
121957
|
import { createHash as createHash47 } from "crypto";
|
|
121729
121958
|
import { homedir as homedir14 } from "os";
|
|
121730
|
-
import { basename as basename24, isAbsolute as
|
|
121959
|
+
import { basename as basename24, isAbsolute as isAbsolute47, resolve as resolve44 } from "path";
|
|
121731
121960
|
function pinnedHookProfile(input3, configuredProfile) {
|
|
121732
121961
|
try {
|
|
121733
121962
|
const parsed = parseSkillContextInput(JSON.stringify(input3));
|
|
@@ -121862,7 +122091,7 @@ function registerAgentIntegration(parent) {
|
|
|
121862
122091
|
});
|
|
121863
122092
|
hook.command("native-catalog").requiredOption("--cwd <path>", "Absolute project directory observed by native Codex skills/list").requiredOption("--output <file>", "New private file for the projected native catalog").option("--codex-command <path>", "Installed Codex executable used by the native client", "codex").option("--json", "Output bounded capture metadata as JSON", false).description("Capture a reviewed Codex native skill catalog for exact hook enrollment").action(async (options) => {
|
|
121864
122093
|
try {
|
|
121865
|
-
if (!
|
|
122094
|
+
if (!isAbsolute47(options.cwd) || !isAbsolute47(options.output))
|
|
121866
122095
|
throw new Error("CODEX_NATIVE_SKILL_CATALOG_ABSOLUTE_PATH_REQUIRED");
|
|
121867
122096
|
if (existsSync36(options.output))
|
|
121868
122097
|
throw new Error("CODEX_NATIVE_SKILL_CATALOG_OUTPUT_EXISTS");
|
|
@@ -121886,7 +122115,7 @@ function registerAgentIntegration(parent) {
|
|
|
121886
122115
|
throw new Error("CODEX_NATIVE_SKILL_CATALOG_OUTPUT_EXISTS");
|
|
121887
122116
|
throw error61;
|
|
121888
122117
|
}
|
|
121889
|
-
const written =
|
|
122118
|
+
const written = lstatSync48(options.output);
|
|
121890
122119
|
if (!written.isFile() || written.isSymbolicLink() || (written.mode & 63) !== 0 || readFileSync49(options.output, "utf8") !== bytes)
|
|
121891
122120
|
throw new Error("CODEX_NATIVE_SKILL_CATALOG_READBACK_FAILED");
|
|
121892
122121
|
const receipt = {
|
|
@@ -121953,9 +122182,9 @@ function registerAgentIntegration(parent) {
|
|
|
121953
122182
|
});
|
|
121954
122183
|
hook.command("review-claude-candidate").requiredOption("--request <file>", "Frozen skills.claude-plugin-prospective-review/v1 JSON request").option("--json", "Return the validation-only receipt as JSON", false).description("Validate a prospective Claude plugin candidate and current preimages without changing native state; Harnesses must compare native and Skills paths against installed package-owned resolvers before trusting the receipt").action(async (options) => {
|
|
121955
122184
|
try {
|
|
121956
|
-
if (!
|
|
122185
|
+
if (!isAbsolute47(options.request))
|
|
121957
122186
|
throw new Error("CLAUDE_CANDIDATE_REVIEW_REFUSED: --request must be an absolute path");
|
|
121958
|
-
const stat3 =
|
|
122187
|
+
const stat3 = lstatSync48(options.request);
|
|
121959
122188
|
if (!stat3.isFile() || stat3.isSymbolicLink() || stat3.size > 1024 * 1024)
|
|
121960
122189
|
throw new Error("CLAUDE_CANDIDATE_REVIEW_REFUSED: request must be a regular file no larger than 1 MiB");
|
|
121961
122190
|
const requestBytes = readFileSync49(options.request);
|
|
@@ -122091,12 +122320,12 @@ function registerAgentIntegration(parent) {
|
|
|
122091
122320
|
input3.hook_event_name = event;
|
|
122092
122321
|
const projects = [process.cwd()];
|
|
122093
122322
|
if (input3.cwd !== undefined) {
|
|
122094
|
-
if (typeof input3.cwd !== "string" || !
|
|
122323
|
+
if (typeof input3.cwd !== "string" || !isAbsolute47(input3.cwd) || input3.cwd.includes("\x00"))
|
|
122095
122324
|
throw new Error("Invalid native hook working directory");
|
|
122096
122325
|
projects.push(input3.cwd);
|
|
122097
122326
|
}
|
|
122098
122327
|
if (options.agent === "cursor") {
|
|
122099
|
-
if (!Array.isArray(input3.workspace_roots) || input3.workspace_roots.length > 32 || input3.workspace_roots.some((path) => typeof path !== "string" || !
|
|
122328
|
+
if (!Array.isArray(input3.workspace_roots) || input3.workspace_roots.length > 32 || input3.workspace_roots.some((path) => typeof path !== "string" || !isAbsolute47(path) || path.includes("\x00")))
|
|
122100
122329
|
throw new Error("Invalid Cursor workspace roots");
|
|
122101
122330
|
projects.push(...input3.workspace_roots);
|
|
122102
122331
|
input3.cwd ??= input3.workspace_roots[0] ?? process.cwd();
|
|
@@ -122887,7 +123116,7 @@ import {
|
|
|
122887
123116
|
mkdirSync as mkdirSync31,
|
|
122888
123117
|
readdirSync as readdirSync28,
|
|
122889
123118
|
readFileSync as readFileSync50,
|
|
122890
|
-
statSync as
|
|
123119
|
+
statSync as statSync26,
|
|
122891
123120
|
writeFileSync as writeFileSync30
|
|
122892
123121
|
} from "fs";
|
|
122893
123122
|
import { dirname as dirname48, join as join76, resolve as resolve45, sep as sep23 } from "path";
|
|
@@ -122984,7 +123213,7 @@ function planStationHydration(stationId, repoRoot) {
|
|
|
122984
123213
|
});
|
|
122985
123214
|
continue;
|
|
122986
123215
|
}
|
|
122987
|
-
const info =
|
|
123216
|
+
const info = statSync26(entry.fullPath);
|
|
122988
123217
|
const manifestHash = manifestHashes.get(`${agent}${MANIFEST_HASH_KEY_SEP}${homeRelative}`) ?? null;
|
|
122989
123218
|
let verified = false;
|
|
122990
123219
|
if (manifestHash !== null) {
|
|
@@ -123241,10 +123470,10 @@ var init_hydrate = __esm(() => {
|
|
|
123241
123470
|
});
|
|
123242
123471
|
|
|
123243
123472
|
// src/lib/prepare-skill.ts
|
|
123244
|
-
import { createHash as createHash49, randomUUID as
|
|
123245
|
-
import { chmodSync as chmodSync5, existsSync as existsSync37, lstatSync as
|
|
123473
|
+
import { createHash as createHash49, randomUUID as randomUUID14 } from "crypto";
|
|
123474
|
+
import { chmodSync as chmodSync5, existsSync as existsSync37, lstatSync as lstatSync49, mkdirSync as mkdirSync32, mkdtempSync as mkdtempSync7, readFileSync as readFileSync51, readdirSync as readdirSync29, renameSync as renameSync16, rmSync as rmSync10, writeFileSync as writeFileSync31 } from "fs";
|
|
123246
123475
|
import { tmpdir as tmpdir2 } from "os";
|
|
123247
|
-
import { dirname as dirname49, isAbsolute as
|
|
123476
|
+
import { dirname as dirname49, isAbsolute as isAbsolute48, join as join77, relative as relative16, resolve as resolve46, sep as sep24 } from "path";
|
|
123248
123477
|
function prepareSkill(name, options) {
|
|
123249
123478
|
const normalized2 = normalizePortableSkillName(name);
|
|
123250
123479
|
if (!new RegExp(SEMVER_PATTERN).test(options.version))
|
|
@@ -123316,11 +123545,11 @@ ${validation.issues.map((issue2) => `${issue2.code}: ${issue2.message}`).join(`
|
|
|
123316
123545
|
if (snapshot2(path).identity !== before2.identity)
|
|
123317
123546
|
throw new Error("Skill changed during preparation; review the draft and run prepare again.");
|
|
123318
123547
|
if (changed3 && !options.dryRun) {
|
|
123319
|
-
const temporary = join77(path, `.skill-prepare-${
|
|
123548
|
+
const temporary = join77(path, `.skill-prepare-${randomUUID14()}.tmp`);
|
|
123320
123549
|
try {
|
|
123321
123550
|
writeFileSync31(temporary, candidateBytes, { flag: "wx", mode: manifestFile.mode });
|
|
123322
123551
|
chmodSync5(temporary, manifestFile.mode);
|
|
123323
|
-
|
|
123552
|
+
renameSync16(temporary, join77(path, "skill.json"));
|
|
123324
123553
|
} finally {
|
|
123325
123554
|
rmSync10(temporary, { force: true });
|
|
123326
123555
|
}
|
|
@@ -123351,7 +123580,7 @@ function validateRuntimeEntrypoint(candidate2, root2) {
|
|
|
123351
123580
|
if (typeof entry !== "string")
|
|
123352
123581
|
return;
|
|
123353
123582
|
const target = resolve46(root2, entry), rel = relative16(root2, target);
|
|
123354
|
-
if (
|
|
123583
|
+
if (isAbsolute48(entry) || /^[a-zA-Z]:/.test(entry) || entry.includes("\\") || !rel || rel === ".." || rel.startsWith(`..${sep24}`) || isAbsolute48(rel) || !existsSync37(target) || !lstatSync49(target).isFile()) {
|
|
123355
123584
|
throw new Error("Executable runtime.entrypoint must name an existing regular file inside the skill directory.");
|
|
123356
123585
|
}
|
|
123357
123586
|
}
|
|
@@ -123436,7 +123665,7 @@ function compareVersions(left, right) {
|
|
|
123436
123665
|
return 0;
|
|
123437
123666
|
}
|
|
123438
123667
|
function snapshot2(root2) {
|
|
123439
|
-
const rootStat =
|
|
123668
|
+
const rootStat = lstatSync49(root2);
|
|
123440
123669
|
if (rootStat.isSymbolicLink() || !rootStat.isDirectory())
|
|
123441
123670
|
throw new Error("Skill root must be a real directory, not a symlink.");
|
|
123442
123671
|
const files = [], directories = [];
|
|
@@ -123449,7 +123678,7 @@ function snapshot2(root2) {
|
|
|
123449
123678
|
const path = relative17 ? `${relative17}/${name}` : name;
|
|
123450
123679
|
if (++count > 20000)
|
|
123451
123680
|
throw new Error("Skill exceeds the preparation entry limit (20000).");
|
|
123452
|
-
const absolute = join77(root2, path), stat3 =
|
|
123681
|
+
const absolute = join77(root2, path), stat3 = lstatSync49(absolute);
|
|
123453
123682
|
if (stat3.isSymbolicLink())
|
|
123454
123683
|
throw new Error(`Skill contains a symlink: ${path}. No files were changed.`);
|
|
123455
123684
|
if (stat3.isDirectory() && name === "node_modules")
|
|
@@ -123942,8 +124171,8 @@ var init_registry_sync = __esm(() => {
|
|
|
123942
124171
|
});
|
|
123943
124172
|
|
|
123944
124173
|
// src/lib/review-export.ts
|
|
123945
|
-
import { constants as constants32, closeSync as closeSync33, existsSync as existsSync38, fstatSync as fstatSync33, fsyncSync as fsyncSync10, lstatSync as
|
|
123946
|
-
import { basename as basename25, dirname as dirname51, isAbsolute as
|
|
124174
|
+
import { constants as constants32, closeSync as closeSync33, existsSync as existsSync38, fstatSync as fstatSync33, fsyncSync as fsyncSync10, lstatSync as lstatSync50, openSync as openSync33, realpathSync as realpathSync24, statSync as statSync27, writeFileSync as writeFileSync33 } from "fs";
|
|
124175
|
+
import { basename as basename25, dirname as dirname51, isAbsolute as isAbsolute49, join as join78, parse as parse13, resolve as resolve47, sep as sep25 } from "path";
|
|
123947
124176
|
function exactVersion(spec) {
|
|
123948
124177
|
const at2 = spec.indexOf("@");
|
|
123949
124178
|
const slug2 = spec.slice(0, at2);
|
|
@@ -123954,14 +124183,14 @@ function exactVersion(spec) {
|
|
|
123954
124183
|
return { slug: slug2, version: version2 };
|
|
123955
124184
|
}
|
|
123956
124185
|
function assertPrivateDestination(output2) {
|
|
123957
|
-
if (!
|
|
124186
|
+
if (!isAbsolute49(output2) || resolve47(output2) !== output2 || !basename25(output2).endsWith(".tar.gz")) {
|
|
123958
124187
|
throw new Error("Review output must be an absolute, normalized .tar.gz path.");
|
|
123959
124188
|
}
|
|
123960
124189
|
const parent = dirname51(output2);
|
|
123961
|
-
if (realpathSync24(parent) !== parent ||
|
|
124190
|
+
if (realpathSync24(parent) !== parent || lstatSync50(parent).isSymbolicLink()) {
|
|
123962
124191
|
throw new Error("Review output parent must be a real directory, not a symlink.");
|
|
123963
124192
|
}
|
|
123964
|
-
const parentStat =
|
|
124193
|
+
const parentStat = statSync27(parent);
|
|
123965
124194
|
if (!parentStat.isDirectory() || (parentStat.mode & 63) !== 0 || process.getuid && parentStat.uid !== process.getuid()) {
|
|
123966
124195
|
throw new Error("Review output parent must be an owner-only directory (mode 0700).");
|
|
123967
124196
|
}
|
|
@@ -124549,17 +124778,20 @@ __export(exports_private_publications, {
|
|
|
124549
124778
|
registerPrivatePublications: () => registerPrivatePublications
|
|
124550
124779
|
});
|
|
124551
124780
|
import { resolve as resolve48 } from "path";
|
|
124552
|
-
function
|
|
124781
|
+
function verifySessionOptions(options) {
|
|
124553
124782
|
if (options.userId === undefined !== (options.membershipId === undefined) || options.userId !== undefined && (!publicationUuid(options.userId) || !publicationUuid(options.membershipId)))
|
|
124554
124783
|
throw new PrivatePublicationError("PUBLICATION_CONTEXT_REQUIRED", "Provide both observed --user-id and --membership-id UUIDs.");
|
|
124784
|
+
if (!options.codeStdin && (options.json || !process.stdin.isTTY || !process.stderr.isTTY))
|
|
124785
|
+
throw new PrivatePublicationError("PUBLICATION_CODE_REQUIRED", "Use --code-stdin with a fresh code for noninteractive publishing.");
|
|
124786
|
+
}
|
|
124787
|
+
function verifyOptions(options, action) {
|
|
124788
|
+
verifySessionOptions(options);
|
|
124555
124789
|
if ((action === "publish" || action === "resume" || action === "cancel") && options.confirm !== true)
|
|
124556
124790
|
throw new PrivatePublicationError("PUBLICATION_CONFIRM_REQUIRED", "Use --confirm to approve this publication action.");
|
|
124557
124791
|
if (action === "publish" && (!publicationUuid(options.skillId) || Boolean(options.expectEmpty) === (options.expectedCurrentVersion !== undefined) || options.expectedCurrentVersion !== undefined && !publicationUuid(options.expectedCurrentVersion) || options.idempotencyKey !== undefined && !publicationUuid(options.idempotencyKey)))
|
|
124558
124792
|
throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Provide --skill-id and exactly one of --expect-empty or --expected-current-version; optional --idempotency-key must be a UUID.");
|
|
124559
124793
|
if (options.waitSeconds !== undefined && (!/^(?:0|[1-9]\d{0,2})$/.test(options.waitSeconds) || Number(options.waitSeconds) > 300))
|
|
124560
124794
|
throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Use --wait-seconds from 0 to 300.");
|
|
124561
|
-
if (!options.codeStdin && (options.json || !process.stdin.isTTY || !process.stderr.isTTY))
|
|
124562
|
-
throw new PrivatePublicationError("PUBLICATION_CODE_REQUIRED", "Use --code-stdin with a fresh code for noninteractive publishing.");
|
|
124563
124795
|
}
|
|
124564
124796
|
function print2(result2, json3) {
|
|
124565
124797
|
if (json3)
|
|
@@ -124573,7 +124805,39 @@ function print2(result2, json3) {
|
|
|
124573
124805
|
process.exitCode = 2;
|
|
124574
124806
|
}
|
|
124575
124807
|
function registerPrivatePublications(parent) {
|
|
124576
|
-
const group = parent.command("publication").description("
|
|
124808
|
+
const group = parent.command("publication").description("Create private skills, publish and reconcile source versions on a compatible hosted server; execution is separate");
|
|
124809
|
+
group.command("create").allowExcessArguments(false).description("Create a private or team skill using fresh session verification (requires Pro)").argument("<slug>", "Lowercase kebab-case skill slug").requiredOption("--display-name <name>", "Skill display name").option("--description <text>", "Skill description", "").option("--visibility <visibility>", "private or team", "private").requiredOption("--email <email>", "Account email for fresh interactive verification").option("--user-id <uuid>", "Observed account UUID (required without an enrolled named profile)").option("--membership-id <uuid>", "Observed workspace membership UUID").option("--code-stdin", "Read a fresh six-digit verification code from stdin").option("--confirm", "Explicitly approve skill creation").option("--json", "Output validated skill identifiers without credentials or server free text").action(async (slug2, options) => {
|
|
124810
|
+
try {
|
|
124811
|
+
const body = checkedPrivateSkillCreate({ slug: slug2, displayName: options.displayName, description: options.description, visibility: options.visibility, confirm: options.confirm });
|
|
124812
|
+
verifySessionOptions(options);
|
|
124813
|
+
const context2 = options.userId ? { userId: options.userId, membershipId: options.membershipId } : undefined;
|
|
124814
|
+
const pending = preparePrivatePublicationSession(context2);
|
|
124815
|
+
let code2;
|
|
124816
|
+
if (options.codeStdin)
|
|
124817
|
+
code2 = await readCode();
|
|
124818
|
+
else {
|
|
124819
|
+
await new RemoteSkillsAuthClient(pending.origin).requestCode(options.email);
|
|
124820
|
+
code2 = await promptCode();
|
|
124821
|
+
}
|
|
124822
|
+
if (code2 === null)
|
|
124823
|
+
return;
|
|
124824
|
+
const client2 = await pending.verify(options.email, code2);
|
|
124825
|
+
const result2 = await client2.createSkill({ ...body, confirm: true });
|
|
124826
|
+
if (options.json)
|
|
124827
|
+
console.log(JSON.stringify(result2));
|
|
124828
|
+
else {
|
|
124829
|
+
console.log(`Created ${result2.visibility} skill: ${result2.slug}`);
|
|
124830
|
+
console.log(`Skill ID: ${result2.id}`);
|
|
124831
|
+
}
|
|
124832
|
+
} catch (error61) {
|
|
124833
|
+
const result2 = error61 instanceof PrivatePublicationError ? privatePublicationCustomerError(error61) : { error: "Unable to verify the selected account and workspace for skill creation. Check the server, membership and fresh code; no credential was saved.", code: "SKILL_CREATE_SESSION_UNAVAILABLE", uncertain: false };
|
|
124834
|
+
if (options.json)
|
|
124835
|
+
console.log(JSON.stringify(result2));
|
|
124836
|
+
else
|
|
124837
|
+
console.error(result2.error);
|
|
124838
|
+
process.exitCode = 1;
|
|
124839
|
+
}
|
|
124840
|
+
});
|
|
124577
124841
|
const publishCommand = group.command("publish").allowExcessArguments(false).description("Publish private source with explicit current-version comparison").requiredOption("--recovery-dir <directory>", "New recovery directory for publish; existing directory for other actions").requiredOption("--email <email>", "Account email for fresh interactive verification").option("--user-id <uuid>", "Observed account UUID (required without an enrolled named profile)").option("--membership-id <uuid>", "Observed workspace membership UUID").option("--code-stdin", "Read a fresh six-digit verification code from stdin").option("--json", "Output a safe result without session credentials or upload URLs").option("--confirm", "Explicitly approve this action").argument("<directory>", "Validated local skill directory").requiredOption("--skill-id <uuid>", "Existing private/team skill UUID").option("--expected-current-version <uuid>", "Compare against the observed current version UUID").option("--expect-empty", "Require the skill to have no current version").option("--idempotency-key <uuid>", "Stable intent key; generated and saved before begin when omitted").option("--wait-seconds <seconds>", "Bounded status wait from 0 to 300", "60");
|
|
124578
124842
|
const statusCommand = group.command("status").allowExcessArguments(false).description("Inspect the exact saved publication").requiredOption("--recovery-dir <directory>", "New recovery directory for publish; existing directory for other actions").requiredOption("--email <email>", "Account email for fresh interactive verification").option("--user-id <uuid>", "Observed account UUID (required without an enrolled named profile)").option("--membership-id <uuid>", "Observed workspace membership UUID").option("--code-stdin", "Read a fresh six-digit verification code from stdin").option("--json", "Output a safe result without session credentials or upload URLs");
|
|
124579
124843
|
const resumeCommand = group.command("resume").allowExcessArguments(false).description("Reconcile the saved intent without creating a replacement").requiredOption("--recovery-dir <directory>", "New recovery directory for publish; existing directory for other actions").requiredOption("--email <email>", "Account email for fresh interactive verification").option("--user-id <uuid>", "Observed account UUID (required without an enrolled named profile)").option("--membership-id <uuid>", "Observed workspace membership UUID").option("--code-stdin", "Read a fresh six-digit verification code from stdin").option("--json", "Output a safe result without session credentials or upload URLs").option("--confirm", "Explicitly approve this action").option("--wait-seconds <seconds>", "Bounded status wait from 0 to 300", "60");
|
|
@@ -124583,17 +124847,18 @@ function registerPrivatePublications(parent) {
|
|
|
124583
124847
|
const options = action === "publish" ? args2[1] : args2[0];
|
|
124584
124848
|
try {
|
|
124585
124849
|
verifyOptions(options, action);
|
|
124850
|
+
const context2 = options.userId ? { userId: options.userId, membershipId: options.membershipId } : undefined;
|
|
124851
|
+
const pending = preparePrivatePublicationSession(context2);
|
|
124586
124852
|
let code2;
|
|
124587
124853
|
if (options.codeStdin)
|
|
124588
124854
|
code2 = await readCode();
|
|
124589
124855
|
else {
|
|
124590
|
-
await new RemoteSkillsAuthClient(
|
|
124856
|
+
await new RemoteSkillsAuthClient(pending.origin).requestCode(options.email);
|
|
124591
124857
|
code2 = await promptCode();
|
|
124592
124858
|
}
|
|
124593
124859
|
if (code2 === null)
|
|
124594
124860
|
return;
|
|
124595
|
-
const
|
|
124596
|
-
const client2 = await privatePublicationSession(options.email, code2, context2), directory3 = resolve48(options.recoveryDir);
|
|
124861
|
+
const client2 = await pending.verify(options.email, code2), directory3 = resolve48(options.recoveryDir);
|
|
124597
124862
|
if (action === "publish")
|
|
124598
124863
|
await preparePrivatePublication(client2, resolve48(args2[0]), directory3, { skillId: options.skillId, expectedCurrentVersionId: options.expectedCurrentVersion ?? null, idempotencyKey: options.idempotencyKey });
|
|
124599
124864
|
const result2 = action === "publish" || action === "resume" ? await continuePrivatePublication(client2, directory3, { confirm: true, waitMs: Number(options.waitSeconds) * 1000 }) : await inspectPrivatePublication(client2, directory3, action === "cancel");
|
|
@@ -124611,7 +124876,6 @@ function registerPrivatePublications(parent) {
|
|
|
124611
124876
|
}
|
|
124612
124877
|
var init_private_publications = __esm(() => {
|
|
124613
124878
|
init_remote_auth();
|
|
124614
|
-
init_auth_store();
|
|
124615
124879
|
init_private_publication_customer();
|
|
124616
124880
|
init_private_publication_recovery();
|
|
124617
124881
|
init_remote_private_publications();
|
|
@@ -124890,7 +125154,7 @@ Skipped. Run it any time: ${skillsCommand("setup agents", target)}`));
|
|
|
124890
125154
|
return;
|
|
124891
125155
|
}
|
|
124892
125156
|
const { handleMcp: handleMcp2 } = await Promise.resolve().then(() => (init_runtime_mcp(), exports_runtime_mcp));
|
|
124893
|
-
await handleMcp2({ register: "all", json: false });
|
|
125157
|
+
await handleMcp2({ register: "all", json: false, apiUrl: target.origin });
|
|
124894
125158
|
process.exitCode = before2 ?? 0;
|
|
124895
125159
|
}
|
|
124896
125160
|
function promptHidden(question) {
|
|
@@ -126062,11 +126326,11 @@ var init_storage2 = __esm(() => {
|
|
|
126062
126326
|
});
|
|
126063
126327
|
|
|
126064
126328
|
// src/lib/registry-reconcile.ts
|
|
126065
|
-
import { existsSync as existsSync40, readFileSync as readFileSync53, statSync as
|
|
126329
|
+
import { existsSync as existsSync40, readFileSync as readFileSync53, statSync as statSync28, writeFileSync as writeFileSync34 } from "fs";
|
|
126066
126330
|
import { join as join80 } from "path";
|
|
126067
126331
|
function isDirectory2(path) {
|
|
126068
126332
|
try {
|
|
126069
|
-
return
|
|
126333
|
+
return statSync28(path).isDirectory();
|
|
126070
126334
|
} catch {
|
|
126071
126335
|
return false;
|
|
126072
126336
|
}
|