@jarel/myskills 0.1.0-beta.19 → 0.1.0-beta.20

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.
Files changed (3) hide show
  1. package/README.md +42 -4
  2. package/dist/index.js +845 -583
  3. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -269,10 +269,10 @@ function mergeDefs(...defs) {
269
269
  function cloneDef(schema) {
270
270
  return mergeDefs(schema._zod.def);
271
271
  }
272
- function getElementAtPath(obj, path18) {
273
- if (!path18)
272
+ function getElementAtPath(obj, path19) {
273
+ if (!path19)
274
274
  return obj;
275
- return path18.reduce((acc, key) => acc?.[key], obj);
275
+ return path19.reduce((acc, key) => acc?.[key], obj);
276
276
  }
277
277
  function promiseAllObject(promisesObj) {
278
278
  const keys = Object.keys(promisesObj);
@@ -531,11 +531,11 @@ function explicitlyAborted(x, startIndex = 0) {
531
531
  }
532
532
  return false;
533
533
  }
534
- function prefixIssues(path18, issues) {
534
+ function prefixIssues(path19, issues) {
535
535
  return issues.map((iss) => {
536
536
  var _a3;
537
537
  (_a3 = iss).path ?? (_a3.path = []);
538
- iss.path.unshift(path18);
538
+ iss.path.unshift(path19);
539
539
  return iss;
540
540
  });
541
541
  }
@@ -1056,16 +1056,16 @@ function flattenError(error62, mapper = (issue4) => issue4.message) {
1056
1056
  }
1057
1057
  function formatError(error62, mapper = (issue4) => issue4.message) {
1058
1058
  const fieldErrors = { _errors: [] };
1059
- const processError = (error63, path18 = []) => {
1059
+ const processError = (error63, path19 = []) => {
1060
1060
  for (const issue4 of error63.issues) {
1061
1061
  if (issue4.code === "invalid_union" && issue4.errors.length) {
1062
- issue4.errors.map((issues) => processError({ issues }, [...path18, ...issue4.path]));
1062
+ issue4.errors.map((issues) => processError({ issues }, [...path19, ...issue4.path]));
1063
1063
  } else if (issue4.code === "invalid_key") {
1064
- processError({ issues: issue4.issues }, [...path18, ...issue4.path]);
1064
+ processError({ issues: issue4.issues }, [...path19, ...issue4.path]);
1065
1065
  } else if (issue4.code === "invalid_element") {
1066
- processError({ issues: issue4.issues }, [...path18, ...issue4.path]);
1066
+ processError({ issues: issue4.issues }, [...path19, ...issue4.path]);
1067
1067
  } else {
1068
- const fullpath = [...path18, ...issue4.path];
1068
+ const fullpath = [...path19, ...issue4.path];
1069
1069
  if (fullpath.length === 0) {
1070
1070
  fieldErrors._errors.push(mapper(issue4));
1071
1071
  } else {
@@ -1104,17 +1104,17 @@ function formatError(error62, mapper = (issue4) => issue4.message) {
1104
1104
  }
1105
1105
  function treeifyError(error62, mapper = (issue4) => issue4.message) {
1106
1106
  const result = { errors: [] };
1107
- const processError = (error63, path18 = []) => {
1107
+ const processError = (error63, path19 = []) => {
1108
1108
  var _a3;
1109
1109
  for (const issue4 of error63.issues) {
1110
1110
  if (issue4.code === "invalid_union" && issue4.errors.length) {
1111
- issue4.errors.map((issues) => processError({ issues }, [...path18, ...issue4.path]));
1111
+ issue4.errors.map((issues) => processError({ issues }, [...path19, ...issue4.path]));
1112
1112
  } else if (issue4.code === "invalid_key") {
1113
- processError({ issues: issue4.issues }, [...path18, ...issue4.path]);
1113
+ processError({ issues: issue4.issues }, [...path19, ...issue4.path]);
1114
1114
  } else if (issue4.code === "invalid_element") {
1115
- processError({ issues: issue4.issues }, [...path18, ...issue4.path]);
1115
+ processError({ issues: issue4.issues }, [...path19, ...issue4.path]);
1116
1116
  } else {
1117
- const fullpath = [...path18, ...issue4.path];
1117
+ const fullpath = [...path19, ...issue4.path];
1118
1118
  if (fullpath.length === 0) {
1119
1119
  result.errors.push(mapper(issue4));
1120
1120
  continue;
@@ -1153,8 +1153,8 @@ function treeifyError(error62, mapper = (issue4) => issue4.message) {
1153
1153
  }
1154
1154
  function toDotPath(_path) {
1155
1155
  const segs = [];
1156
- const path18 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1157
- for (const seg of path18) {
1156
+ const path19 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1157
+ for (const seg of path19) {
1158
1158
  if (typeof seg === "number")
1159
1159
  segs.push(`[${seg}]`);
1160
1160
  else if (typeof seg === "symbol")
@@ -19150,13 +19150,13 @@ function resolveRef(ref, ctx) {
19150
19150
  if (!ref.startsWith("#")) {
19151
19151
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
19152
19152
  }
19153
- const path18 = ref.slice(1).split("/").filter(Boolean);
19154
- if (path18.length === 0) {
19153
+ const path19 = ref.slice(1).split("/").filter(Boolean);
19154
+ if (path19.length === 0) {
19155
19155
  return ctx.rootSchema;
19156
19156
  }
19157
19157
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
19158
- if (path18[0] === defsKey) {
19159
- const key = path18[1] === void 0 ? void 0 : decodeJSONPointerSegment(path18[1]);
19158
+ if (path19[0] === defsKey) {
19159
+ const key = path19[1] === void 0 ? void 0 : decodeJSONPointerSegment(path19[1]);
19160
19160
  if (!key || !ctx.defs[key]) {
19161
19161
  throw new Error(`Reference not found: ${ref}`);
19162
19162
  }
@@ -21082,27 +21082,27 @@ function unknownKeys(value, allowed) {
21082
21082
  const allowedSet = new Set(allowed);
21083
21083
  return Object.keys(value).filter((key) => !allowedSet.has(key)).sort();
21084
21084
  }
21085
- function issue2(errors, code, message, path18) {
21086
- errors.push(path18 ? { code, message, path: path18 } : { code, message });
21085
+ function issue2(errors, code, message, path19) {
21086
+ errors.push(path19 ? { code, message, path: path19 } : { code, message });
21087
21087
  }
21088
- function checkUnknownKeys(value, allowed, path18, errors) {
21088
+ function checkUnknownKeys(value, allowed, path19, errors) {
21089
21089
  for (const key of unknownKeys(value, allowed)) {
21090
- issue2(errors, "ARCHITECTURE_TARGET_UNKNOWN_FIELD", `Field '${key}' is not accepted.`, `${path18}.${key}`);
21090
+ issue2(errors, "ARCHITECTURE_TARGET_UNKNOWN_FIELD", `Field '${key}' is not accepted.`, `${path19}.${key}`);
21091
21091
  }
21092
21092
  }
21093
- function checkSensitiveKeys(value, path18, errors) {
21093
+ function checkSensitiveKeys(value, path19, errors) {
21094
21094
  if (Array.isArray(value)) {
21095
21095
  for (const [index, item] of value.entries())
21096
- checkSensitiveKeys(item, `${path18}[${index}]`, errors);
21096
+ checkSensitiveKeys(item, `${path19}[${index}]`, errors);
21097
21097
  return;
21098
21098
  }
21099
21099
  if (!isRecord2(value))
21100
21100
  return;
21101
21101
  for (const [key, item] of Object.entries(value)) {
21102
21102
  if (isSensitiveMetadataKey(key) && !safeKnownKeys.has(key)) {
21103
- issue2(errors, "ARCHITECTURE_TARGET_SENSITIVE_FIELD", `Field '${key}' is not permitted in metadata-only target records.`, `${path18}.${key}`);
21103
+ issue2(errors, "ARCHITECTURE_TARGET_SENSITIVE_FIELD", `Field '${key}' is not permitted in metadata-only target records.`, `${path19}.${key}`);
21104
21104
  }
21105
- checkSensitiveKeys(item, `${path18}.${key}`, errors);
21105
+ checkSensitiveKeys(item, `${path19}.${key}`, errors);
21106
21106
  }
21107
21107
  }
21108
21108
  function validIdentifier(value, maximum = architectureTargetLimits.identifierLength) {
@@ -21130,40 +21130,40 @@ function normalizeMetadata(value) {
21130
21130
  normalized[key] = value[key];
21131
21131
  return normalized;
21132
21132
  }
21133
- function validateMetadata2(value, path18, errors) {
21133
+ function validateMetadata2(value, path19, errors) {
21134
21134
  if (value === void 0)
21135
21135
  return void 0;
21136
21136
  if (!isRecord2(value)) {
21137
- issue2(errors, "ARCHITECTURE_TARGET_METADATA_INVALID", "Metadata must be a bounded object of scalar values.", path18);
21137
+ issue2(errors, "ARCHITECTURE_TARGET_METADATA_INVALID", "Metadata must be a bounded object of scalar values.", path19);
21138
21138
  return void 0;
21139
21139
  }
21140
21140
  const entries = Object.entries(value);
21141
21141
  if (entries.length > architectureTargetLimits.metadataKeys) {
21142
- issue2(errors, "ARCHITECTURE_TARGET_LIMIT_EXCEEDED", `Metadata may contain at most ${architectureTargetLimits.metadataKeys} fields.`, path18);
21142
+ issue2(errors, "ARCHITECTURE_TARGET_LIMIT_EXCEEDED", `Metadata may contain at most ${architectureTargetLimits.metadataKeys} fields.`, path19);
21143
21143
  }
21144
21144
  const normalized = {};
21145
21145
  for (const [key, item] of entries) {
21146
21146
  if (key.length === 0 || key.length > architectureTargetLimits.metadataKeyLength || isSensitiveMetadataKey(key)) {
21147
- issue2(errors, "ARCHITECTURE_TARGET_SENSITIVE_FIELD", `Metadata field '${key}' is not allowed.`, `${path18}.${key}`);
21147
+ issue2(errors, "ARCHITECTURE_TARGET_SENSITIVE_FIELD", `Metadata field '${key}' is not allowed.`, `${path19}.${key}`);
21148
21148
  }
21149
21149
  if (!metadataKeyPattern.test(key)) {
21150
- issue2(errors, "ARCHITECTURE_TARGET_METADATA_INVALID", `Metadata field '${key}' must use a safe identifier shape.`, `${path18}.${key}`);
21150
+ issue2(errors, "ARCHITECTURE_TARGET_METADATA_INVALID", `Metadata field '${key}' must use a safe identifier shape.`, `${path19}.${key}`);
21151
21151
  }
21152
21152
  if (item !== null && typeof item !== "string" && typeof item !== "number" && typeof item !== "boolean") {
21153
- issue2(errors, "ARCHITECTURE_TARGET_METADATA_INVALID", "Metadata values must be scalar.", `${path18}.${key}`);
21153
+ issue2(errors, "ARCHITECTURE_TARGET_METADATA_INVALID", "Metadata values must be scalar.", `${path19}.${key}`);
21154
21154
  continue;
21155
21155
  }
21156
21156
  if (typeof item === "number" && !Number.isFinite(item)) {
21157
- issue2(errors, "ARCHITECTURE_TARGET_METADATA_INVALID", "Metadata numbers must be finite.", `${path18}.${key}`);
21157
+ issue2(errors, "ARCHITECTURE_TARGET_METADATA_INVALID", "Metadata numbers must be finite.", `${path19}.${key}`);
21158
21158
  continue;
21159
21159
  }
21160
21160
  if (typeof item === "string") {
21161
21161
  if (item.length > architectureTargetLimits.metadataStringLength) {
21162
- issue2(errors, "ARCHITECTURE_TARGET_LIMIT_EXCEEDED", `Metadata strings must contain at most ${architectureTargetLimits.metadataStringLength} printable characters.`, `${path18}.${key}`);
21162
+ issue2(errors, "ARCHITECTURE_TARGET_LIMIT_EXCEEDED", `Metadata strings must contain at most ${architectureTargetLimits.metadataStringLength} printable characters.`, `${path19}.${key}`);
21163
21163
  continue;
21164
21164
  }
21165
21165
  if (!textPattern.test(item) || unsafeMetadataValuePattern.test(item)) {
21166
- issue2(errors, "ARCHITECTURE_TARGET_SENSITIVE_FIELD", `Metadata value '${key}' contains unsafe or private content.`, `${path18}.${key}`);
21166
+ issue2(errors, "ARCHITECTURE_TARGET_SENSITIVE_FIELD", `Metadata value '${key}' contains unsafe or private content.`, `${path19}.${key}`);
21167
21167
  continue;
21168
21168
  }
21169
21169
  }
@@ -21175,81 +21175,81 @@ function isSensitiveMetadataKey(key) {
21175
21175
  const normalized = key.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
21176
21176
  return sensitiveMetadataKeyPattern.test(normalized);
21177
21177
  }
21178
- function validateOwner(value, path18, errors) {
21178
+ function validateOwner(value, path19, errors) {
21179
21179
  if (!isRecord2(value)) {
21180
- issue2(errors, "ARCHITECTURE_TARGET_OWNER_INVALID", "Target owner must be an object.", path18);
21180
+ issue2(errors, "ARCHITECTURE_TARGET_OWNER_INVALID", "Target owner must be an object.", path19);
21181
21181
  return void 0;
21182
21182
  }
21183
- checkUnknownKeys(value, ["type", "id"], path18, errors);
21183
+ checkUnknownKeys(value, ["type", "id"], path19, errors);
21184
21184
  if (!isOneOf(value.type, architectureTargetOwnerReferenceTypes)) {
21185
- issue2(errors, "ARCHITECTURE_TARGET_OWNER_TYPE_INVALID", "Target owner type must be user, team, or organization.", `${path18}.type`);
21185
+ issue2(errors, "ARCHITECTURE_TARGET_OWNER_TYPE_INVALID", "Target owner type must be user, team, or organization.", `${path19}.type`);
21186
21186
  }
21187
21187
  if (!validIdentifier(value.id))
21188
- issue2(errors, "ARCHITECTURE_TARGET_OWNER_ID_INVALID", "Target owner id must be a bounded identifier.", `${path18}.id`);
21188
+ issue2(errors, "ARCHITECTURE_TARGET_OWNER_ID_INVALID", "Target owner id must be a bounded identifier.", `${path19}.id`);
21189
21189
  if (!isOneOf(value.type, architectureTargetOwnerReferenceTypes) || !validIdentifier(value.id))
21190
21190
  return void 0;
21191
21191
  return { type: value.type, id: value.id };
21192
21192
  }
21193
- function validateAdapterDescriptor(value, path18, errors) {
21193
+ function validateAdapterDescriptor(value, path19, errors) {
21194
21194
  if (!isRecord2(value)) {
21195
- issue2(errors, "ARCHITECTURE_TARGET_ADAPTER_INVALID", "Target adapter descriptor must be an object.", path18);
21195
+ issue2(errors, "ARCHITECTURE_TARGET_ADAPTER_INVALID", "Target adapter descriptor must be an object.", path19);
21196
21196
  return void 0;
21197
21197
  }
21198
- checkUnknownKeys(value, ["kind", "version", "contractVersion"], path18, errors);
21198
+ checkUnknownKeys(value, ["kind", "version", "contractVersion"], path19, errors);
21199
21199
  if (typeof value.kind !== "string" || !adapterKindPattern.test(value.kind)) {
21200
- issue2(errors, "ARCHITECTURE_TARGET_ADAPTER_KIND_INVALID", "Adapter kind must be a lowercase bounded identifier.", `${path18}.kind`);
21200
+ issue2(errors, "ARCHITECTURE_TARGET_ADAPTER_KIND_INVALID", "Adapter kind must be a lowercase bounded identifier.", `${path19}.kind`);
21201
21201
  }
21202
21202
  if (!validText(value.version, architectureTargetLimits.adapterVersionLength)) {
21203
- issue2(errors, "ARCHITECTURE_TARGET_ADAPTER_VERSION_INVALID", "Adapter version must be a bounded string.", `${path18}.version`);
21203
+ issue2(errors, "ARCHITECTURE_TARGET_ADAPTER_VERSION_INVALID", "Adapter version must be a bounded string.", `${path19}.version`);
21204
21204
  }
21205
21205
  if (!architectureTargetAdapterContractVersions.includes(value.contractVersion)) {
21206
- issue2(errors, "ARCHITECTURE_TARGET_ADAPTER_CONTRACT_VERSION_INVALID", "Adapter contract version must be 1 or 2.", `${path18}.contractVersion`);
21206
+ issue2(errors, "ARCHITECTURE_TARGET_ADAPTER_CONTRACT_VERSION_INVALID", "Adapter contract version must be 1 or 2.", `${path19}.contractVersion`);
21207
21207
  }
21208
21208
  if (typeof value.kind !== "string" || !adapterKindPattern.test(value.kind) || !validText(value.version, architectureTargetLimits.adapterVersionLength) || value.contractVersion !== 1 && value.contractVersion !== 2)
21209
21209
  return void 0;
21210
21210
  return { kind: value.kind, version: value.version, contractVersion: value.contractVersion };
21211
21211
  }
21212
- function validateCapabilities(value, path18, errors, contractVersion = 1) {
21212
+ function validateCapabilities(value, path19, errors, contractVersion = 1) {
21213
21213
  if (!isRecord2(value)) {
21214
- issue2(errors, "ARCHITECTURE_TARGET_CAPABILITIES_INVALID", "Target capabilities must be an object.", path18);
21214
+ issue2(errors, "ARCHITECTURE_TARGET_CAPABILITIES_INVALID", "Target capabilities must be an object.", path19);
21215
21215
  return void 0;
21216
21216
  }
21217
- checkUnknownKeys(value, architectureTargetCapabilityNames, path18, errors);
21217
+ checkUnknownKeys(value, architectureTargetCapabilityNames, path19, errors);
21218
21218
  const normalized = {};
21219
21219
  const knownNames = new Set(architectureTargetCapabilityNames);
21220
21220
  for (const [key, item] of Object.entries(value)) {
21221
21221
  if (!knownNames.has(key))
21222
21222
  continue;
21223
21223
  if (typeof item !== "boolean") {
21224
- issue2(errors, "ARCHITECTURE_TARGET_CAPABILITY_INVALID", "Capability values must be boolean.", `${path18}.${key}`);
21224
+ issue2(errors, "ARCHITECTURE_TARGET_CAPABILITY_INVALID", "Capability values must be boolean.", `${path19}.${key}`);
21225
21225
  continue;
21226
21226
  }
21227
21227
  if (contractVersion === 1 && architectureTargetMutationCapabilities.includes(key) && item === true) {
21228
- issue2(errors, "ARCHITECTURE_TARGET_MUTATION_CAPABILITY_ENABLED", "Mutation capabilities must be absent or explicitly false in contract version 1.", `${path18}.${key}`);
21228
+ issue2(errors, "ARCHITECTURE_TARGET_MUTATION_CAPABILITY_ENABLED", "Mutation capabilities must be absent or explicitly false in contract version 1.", `${path19}.${key}`);
21229
21229
  continue;
21230
21230
  }
21231
21231
  normalized[key] = item;
21232
21232
  }
21233
21233
  if (contractVersion === 2 && (normalized.apply === true || normalized.rollback === true) && normalized["sync.write"] !== true) {
21234
- issue2(errors, "ARCHITECTURE_TARGET_MUTATION_CAPABILITY_ENABLED", "Contract version 2 requires sync.write when apply or rollback is enabled.", `${path18}.sync.write`);
21234
+ issue2(errors, "ARCHITECTURE_TARGET_MUTATION_CAPABILITY_ENABLED", "Contract version 2 requires sync.write when apply or rollback is enabled.", `${path19}.sync.write`);
21235
21235
  }
21236
21236
  return normalized;
21237
21237
  }
21238
- function validateConsent(value, path18, errors) {
21238
+ function validateConsent(value, path19, errors) {
21239
21239
  if (!isRecord2(value)) {
21240
- issue2(errors, "ARCHITECTURE_TARGET_CONSENT_INVALID", "Target consent must be an object.", path18);
21240
+ issue2(errors, "ARCHITECTURE_TARGET_CONSENT_INVALID", "Target consent must be an object.", path19);
21241
21241
  return void 0;
21242
21242
  }
21243
- checkUnknownKeys(value, ["status", "requestedAt", "grantedAt", "deniedAt", "revokedAt"], path18, errors);
21243
+ checkUnknownKeys(value, ["status", "requestedAt", "grantedAt", "deniedAt", "revokedAt"], path19, errors);
21244
21244
  if (!isOneOf(value.status, architectureTargetConsentStatuses))
21245
- issue2(errors, "ARCHITECTURE_TARGET_CONSENT_STATUS_INVALID", "Target consent status is invalid.", `${path18}.status`);
21245
+ issue2(errors, "ARCHITECTURE_TARGET_CONSENT_STATUS_INVALID", "Target consent status is invalid.", `${path19}.status`);
21246
21246
  if (!validIsoTimestamp(value.requestedAt))
21247
- issue2(errors, "ARCHITECTURE_TARGET_CONSENT_TIMESTAMP_REQUIRED", "Consent requestedAt must be an ISO-8601 UTC timestamp.", `${path18}.requestedAt`);
21247
+ issue2(errors, "ARCHITECTURE_TARGET_CONSENT_TIMESTAMP_REQUIRED", "Consent requestedAt must be an ISO-8601 UTC timestamp.", `${path19}.requestedAt`);
21248
21248
  const timestamps = ["grantedAt", "deniedAt", "revokedAt"];
21249
21249
  for (const timestamp of timestamps) {
21250
21250
  const item = value[timestamp];
21251
21251
  if (item !== void 0 && item !== null && !validIsoTimestamp(item)) {
21252
- issue2(errors, "ARCHITECTURE_TARGET_TIMESTAMP_INVALID", `${timestamp} must be an ISO-8601 UTC timestamp or null.`, `${path18}.${timestamp}`);
21252
+ issue2(errors, "ARCHITECTURE_TARGET_TIMESTAMP_INVALID", `${timestamp} must be an ISO-8601 UTC timestamp or null.`, `${path19}.${timestamp}`);
21253
21253
  }
21254
21254
  }
21255
21255
  const requiredTimestamp = {
@@ -21260,7 +21260,7 @@ function validateConsent(value, path18, errors) {
21260
21260
  };
21261
21261
  const required2 = isOneOf(value.status, architectureTargetConsentStatuses) ? requiredTimestamp[value.status] : null;
21262
21262
  if (required2 && !validIsoTimestamp(value[required2])) {
21263
- issue2(errors, "ARCHITECTURE_TARGET_CONSENT_TIMESTAMP_REQUIRED", `Consent ${required2} is required for status '${value.status}'.`, `${path18}.${required2}`);
21263
+ issue2(errors, "ARCHITECTURE_TARGET_CONSENT_TIMESTAMP_REQUIRED", `Consent ${required2} is required for status '${value.status}'.`, `${path19}.${required2}`);
21264
21264
  }
21265
21265
  if (!isOneOf(value.status, architectureTargetConsentStatuses) || !validIsoTimestamp(value.requestedAt))
21266
21266
  return void 0;
@@ -21272,11 +21272,11 @@ function validateConsent(value, path18, errors) {
21272
21272
  ...value.revokedAt === void 0 ? {} : { revokedAt: value.revokedAt }
21273
21273
  };
21274
21274
  }
21275
- function validateOptionalTimestamp(value, path18, errors) {
21275
+ function validateOptionalTimestamp(value, path19, errors) {
21276
21276
  if (value === void 0)
21277
21277
  return void 0;
21278
21278
  if (!validIsoTimestamp(value)) {
21279
- issue2(errors, "ARCHITECTURE_TARGET_TIMESTAMP_INVALID", "Timestamp must be an ISO-8601 UTC timestamp.", path18);
21279
+ issue2(errors, "ARCHITECTURE_TARGET_TIMESTAMP_INVALID", "Timestamp must be an ISO-8601 UTC timestamp.", path19);
21280
21280
  return void 0;
21281
21281
  }
21282
21282
  return value;
@@ -21494,34 +21494,34 @@ function architectureTargetCapabilitiesDigest(input2, contractVersion = 1) {
21494
21494
  throw new ArchitectureTargetValidationError(errors.length > 0 ? errors : [{ code: "ARCHITECTURE_TARGET_CAPABILITIES_INVALID", message: "Capabilities are invalid." }]);
21495
21495
  return sha256Hex(canonicalizeJson(normalizeCapabilities(normalized)));
21496
21496
  }
21497
- function validateObservedSkill(value, path18, errors) {
21497
+ function validateObservedSkill(value, path19, errors) {
21498
21498
  if (!isRecord2(value)) {
21499
- issue2(errors, "ARCHITECTURE_TARGET_SKILL_INVALID", "Observed skill must be an object.", path18);
21499
+ issue2(errors, "ARCHITECTURE_TARGET_SKILL_INVALID", "Observed skill must be an object.", path19);
21500
21500
  return void 0;
21501
21501
  }
21502
- checkUnknownKeys(value, ["skillRefId", "slug", "version", "digest", "kind", "enabled", "runtimeExposure", "configurationDigest", "configured", "managed", "supported", "metadata"], path18, errors);
21502
+ checkUnknownKeys(value, ["skillRefId", "slug", "version", "digest", "kind", "enabled", "runtimeExposure", "configurationDigest", "configured", "managed", "supported", "metadata"], path19, errors);
21503
21503
  if (value.skillRefId !== void 0 && !validIdentifier(value.skillRefId))
21504
- issue2(errors, "ARCHITECTURE_TARGET_SKILL_INVALID", "Observed skill skillRefId must be a bounded identifier.", `${path18}.skillRefId`);
21504
+ issue2(errors, "ARCHITECTURE_TARGET_SKILL_INVALID", "Observed skill skillRefId must be a bounded identifier.", `${path19}.skillRefId`);
21505
21505
  if (!validText(value.slug, architectureTargetLimits.identifierLength) || !identifierPattern.test(value.slug))
21506
- issue2(errors, "ARCHITECTURE_TARGET_SKILL_INVALID", "Observed skill slug must be a bounded identifier.", `${path18}.slug`);
21506
+ issue2(errors, "ARCHITECTURE_TARGET_SKILL_INVALID", "Observed skill slug must be a bounded identifier.", `${path19}.slug`);
21507
21507
  if (value.version !== void 0 && !validText(value.version, architectureTargetLimits.versionLength))
21508
- issue2(errors, "ARCHITECTURE_TARGET_SKILL_INVALID", "Observed skill version must be a bounded string.", `${path18}.version`);
21508
+ issue2(errors, "ARCHITECTURE_TARGET_SKILL_INVALID", "Observed skill version must be a bounded string.", `${path19}.version`);
21509
21509
  if (value.digest !== void 0 && !validDigest(value.digest))
21510
- issue2(errors, "ARCHITECTURE_TARGET_SKILL_INVALID", "Observed skill digest must be a lowercase SHA-256 digest.", `${path18}.digest`);
21510
+ issue2(errors, "ARCHITECTURE_TARGET_SKILL_INVALID", "Observed skill digest must be a lowercase SHA-256 digest.", `${path19}.digest`);
21511
21511
  if (value.kind !== void 0 && value.kind !== "router" && value.kind !== "leaf")
21512
- issue2(errors, "ARCHITECTURE_TARGET_SKILL_INVALID", "Observed skill kind must be router or leaf.", `${path18}.kind`);
21512
+ issue2(errors, "ARCHITECTURE_TARGET_SKILL_INVALID", "Observed skill kind must be router or leaf.", `${path19}.kind`);
21513
21513
  if (value.enabled !== void 0 && typeof value.enabled !== "boolean")
21514
- issue2(errors, "ARCHITECTURE_TARGET_SKILL_INVALID", "Observed skill enabled must be boolean.", `${path18}.enabled`);
21514
+ issue2(errors, "ARCHITECTURE_TARGET_SKILL_INVALID", "Observed skill enabled must be boolean.", `${path19}.enabled`);
21515
21515
  if (value.runtimeExposure !== void 0 && !isOneOf(value.runtimeExposure, runtimeExposureModes))
21516
- issue2(errors, "ARCHITECTURE_TARGET_SKILL_INVALID", "Observed skill runtimeExposure is invalid.", `${path18}.runtimeExposure`);
21516
+ issue2(errors, "ARCHITECTURE_TARGET_SKILL_INVALID", "Observed skill runtimeExposure is invalid.", `${path19}.runtimeExposure`);
21517
21517
  if (value.configurationDigest !== void 0 && !validDigest(value.configurationDigest))
21518
- issue2(errors, "ARCHITECTURE_TARGET_SKILL_INVALID", "Observed skill configurationDigest must be a lowercase SHA-256 digest.", `${path18}.configurationDigest`);
21518
+ issue2(errors, "ARCHITECTURE_TARGET_SKILL_INVALID", "Observed skill configurationDigest must be a lowercase SHA-256 digest.", `${path19}.configurationDigest`);
21519
21519
  for (const key of ["configured", "managed", "supported"]) {
21520
21520
  if (value[key] !== void 0 && typeof value[key] !== "boolean")
21521
- issue2(errors, "ARCHITECTURE_TARGET_SKILL_INVALID", `Observed skill ${key} must be boolean.`, `${path18}.${key}`);
21521
+ issue2(errors, "ARCHITECTURE_TARGET_SKILL_INVALID", `Observed skill ${key} must be boolean.`, `${path19}.${key}`);
21522
21522
  }
21523
- const metadata = validateMetadata2(value.metadata, `${path18}.metadata`, errors);
21524
- if (errors.some((error62) => error62.path?.startsWith(path18)))
21523
+ const metadata = validateMetadata2(value.metadata, `${path19}.metadata`, errors);
21524
+ if (errors.some((error62) => error62.path?.startsWith(path19)))
21525
21525
  return void 0;
21526
21526
  return {
21527
21527
  ...value.skillRefId === void 0 ? {} : { skillRefId: value.skillRefId },
@@ -21538,34 +21538,34 @@ function validateObservedSkill(value, path18, errors) {
21538
21538
  ...metadata && Object.keys(metadata).length > 0 ? { metadata } : {}
21539
21539
  };
21540
21540
  }
21541
- function validateConfigFinding(value, path18, errors) {
21541
+ function validateConfigFinding(value, path19, errors) {
21542
21542
  if (!isRecord2(value)) {
21543
- issue2(errors, "ARCHITECTURE_TARGET_CONFIG_FINDING_INVALID", "Configuration finding must be an object.", path18);
21543
+ issue2(errors, "ARCHITECTURE_TARGET_CONFIG_FINDING_INVALID", "Configuration finding must be an object.", path19);
21544
21544
  return void 0;
21545
21545
  }
21546
- checkUnknownKeys(value, ["code", "severity", "count"], path18, errors);
21546
+ checkUnknownKeys(value, ["code", "severity", "count"], path19, errors);
21547
21547
  if (typeof value.code !== "string" || !findingCodePattern.test(value.code))
21548
- issue2(errors, "ARCHITECTURE_TARGET_CONFIG_FINDING_INVALID", "Configuration finding code must be a bounded identifier.", `${path18}.code`);
21548
+ issue2(errors, "ARCHITECTURE_TARGET_CONFIG_FINDING_INVALID", "Configuration finding code must be a bounded identifier.", `${path19}.code`);
21549
21549
  if (!isOneOf(value.severity, architectureTargetConfigFindingSeverities))
21550
- issue2(errors, "ARCHITECTURE_TARGET_CONFIG_FINDING_INVALID", "Configuration finding severity is invalid.", `${path18}.severity`);
21550
+ issue2(errors, "ARCHITECTURE_TARGET_CONFIG_FINDING_INVALID", "Configuration finding severity is invalid.", `${path19}.severity`);
21551
21551
  if (typeof value.count !== "number" || !Number.isInteger(value.count) || value.count < 0 || value.count > architectureTargetLimits.counterMaximum)
21552
- issue2(errors, "ARCHITECTURE_TARGET_CONFIG_FINDING_INVALID", "Configuration finding count must be a bounded non-negative integer.", `${path18}.count`);
21552
+ issue2(errors, "ARCHITECTURE_TARGET_CONFIG_FINDING_INVALID", "Configuration finding count must be a bounded non-negative integer.", `${path19}.count`);
21553
21553
  if (typeof value.code !== "string" || !findingCodePattern.test(value.code) || !isOneOf(value.severity, architectureTargetConfigFindingSeverities) || typeof value.count !== "number" || !Number.isInteger(value.count) || value.count < 0)
21554
21554
  return void 0;
21555
21555
  return { code: value.code, severity: value.severity, count: value.count };
21556
21556
  }
21557
- function validatePromptAwareness(value, path18, errors) {
21557
+ function validatePromptAwareness(value, path19, errors) {
21558
21558
  if (!isRecord2(value)) {
21559
- issue2(errors, "ARCHITECTURE_TARGET_PROMPT_AWARENESS_INVALID", "Prompt awareness must be an object.", path18);
21559
+ issue2(errors, "ARCHITECTURE_TARGET_PROMPT_AWARENESS_INVALID", "Prompt awareness must be an object.", path19);
21560
21560
  return void 0;
21561
21561
  }
21562
- checkUnknownKeys(value, ["detected", "count", "redacted"], path18, errors);
21562
+ checkUnknownKeys(value, ["detected", "count", "redacted"], path19, errors);
21563
21563
  if (typeof value.detected !== "boolean")
21564
- issue2(errors, "ARCHITECTURE_TARGET_PROMPT_AWARENESS_INVALID", "Prompt awareness detected must be boolean.", `${path18}.detected`);
21564
+ issue2(errors, "ARCHITECTURE_TARGET_PROMPT_AWARENESS_INVALID", "Prompt awareness detected must be boolean.", `${path19}.detected`);
21565
21565
  if (typeof value.count !== "number" || !Number.isInteger(value.count) || value.count < 0 || value.count > architectureTargetLimits.counterMaximum)
21566
- issue2(errors, "ARCHITECTURE_TARGET_PROMPT_AWARENESS_INVALID", "Prompt awareness count must be a bounded non-negative integer.", `${path18}.count`);
21566
+ issue2(errors, "ARCHITECTURE_TARGET_PROMPT_AWARENESS_INVALID", "Prompt awareness count must be a bounded non-negative integer.", `${path19}.count`);
21567
21567
  if (value.redacted !== void 0 && typeof value.redacted !== "boolean")
21568
- issue2(errors, "ARCHITECTURE_TARGET_PROMPT_AWARENESS_INVALID", "Prompt awareness redacted must be boolean.", `${path18}.redacted`);
21568
+ issue2(errors, "ARCHITECTURE_TARGET_PROMPT_AWARENESS_INVALID", "Prompt awareness redacted must be boolean.", `${path19}.redacted`);
21569
21569
  if (typeof value.detected !== "boolean" || typeof value.count !== "number" || !Number.isInteger(value.count) || value.count < 0 || value.redacted !== void 0 && typeof value.redacted !== "boolean")
21570
21570
  return void 0;
21571
21571
  return {
@@ -23216,9 +23216,9 @@ var require_yauzl = __commonJS({
23216
23216
  exports.Entry = Entry;
23217
23217
  exports.LocalFileHeader = LocalFileHeader;
23218
23218
  exports.RandomAccessReader = RandomAccessReader;
23219
- function openPromise(path18, options2) {
23219
+ function openPromise(path19, options2) {
23220
23220
  return new Promise((resolve, reject) => {
23221
- open10(path18, { ...options2, lazyEntries: true }, function(err, zipfile) {
23221
+ open10(path19, { ...options2, lazyEntries: true }, function(err, zipfile) {
23222
23222
  if (err) return reject(err);
23223
23223
  resolve(zipfile);
23224
23224
  });
@@ -23248,7 +23248,7 @@ var require_yauzl = __commonJS({
23248
23248
  });
23249
23249
  });
23250
23250
  }
23251
- function open10(path18, options2, callback) {
23251
+ function open10(path19, options2, callback) {
23252
23252
  if (typeof options2 === "function") {
23253
23253
  callback = options2;
23254
23254
  options2 = null;
@@ -23260,7 +23260,7 @@ var require_yauzl = __commonJS({
23260
23260
  if (options2.validateEntrySizes == null) options2.validateEntrySizes = true;
23261
23261
  if (options2.strictFileNames == null) options2.strictFileNames = false;
23262
23262
  if (callback == null) callback = defaultCallback;
23263
- fs.open(path18, "r", function(err, fd) {
23263
+ fs.open(path19, "r", function(err, fd) {
23264
23264
  if (err) return callback(err);
23265
23265
  fromFd(fd, options2, function(err2, zipfile) {
23266
23266
  if (err2) fs.close(fd, defaultCallback);
@@ -25041,10 +25041,10 @@ function comparisonResult(input2, baseFiles, targetFiles, baseBytes, targetBytes
25041
25041
  remaining -= preview.length;
25042
25042
  return { sha256: digest2(content), byteSize: Buffer.byteLength(content), preview, previewTruncated: preview.length < content.length, previewOmitted: binary ? "binary" : unchanged ? "unchanged" : null };
25043
25043
  };
25044
- const changes = [.../* @__PURE__ */ new Set([...before.keys(), ...after.keys()])].sort().map((path18) => {
25045
- const status = !before.has(path18) ? "added" : !after.has(path18) ? "removed" : before.get(path18) === after.get(path18) ? "unchanged" : "modified";
25044
+ const changes = [.../* @__PURE__ */ new Set([...before.keys(), ...after.keys()])].sort().map((path19) => {
25045
+ const status = !before.has(path19) ? "added" : !after.has(path19) ? "removed" : before.get(path19) === after.get(path19) ? "unchanged" : "modified";
25046
25046
  totals[status]++;
25047
- return { path: path18, status, base: side(before.get(path18), status === "unchanged"), target: side(after.get(path18), status === "unchanged") };
25047
+ return { path: path19, status, base: side(before.get(path19), status === "unchanged"), target: side(after.get(path19), status === "unchanged") };
25048
25048
  });
25049
25049
  return { schemaVersion: 1, base: { ...input2.base, byteSize: baseBytes }, target: { ...input2.target, byteSize: targetBytes }, totals, changes, previewLimitCharacters: 32768, notice: "Compared complete content. Previews are bounded and may be omitted or truncated. No package code was executed." };
25050
25050
  }
@@ -25407,17 +25407,17 @@ var require_visit = __commonJS({
25407
25407
  visit2.BREAK = BREAK;
25408
25408
  visit2.SKIP = SKIP;
25409
25409
  visit2.REMOVE = REMOVE;
25410
- function visit_(key, node2, visitor, path18) {
25411
- const ctrl = callVisitor(key, node2, visitor, path18);
25410
+ function visit_(key, node2, visitor, path19) {
25411
+ const ctrl = callVisitor(key, node2, visitor, path19);
25412
25412
  if (identity2.isNode(ctrl) || identity2.isPair(ctrl)) {
25413
- replaceNode(key, path18, ctrl);
25414
- return visit_(key, ctrl, visitor, path18);
25413
+ replaceNode(key, path19, ctrl);
25414
+ return visit_(key, ctrl, visitor, path19);
25415
25415
  }
25416
25416
  if (typeof ctrl !== "symbol") {
25417
25417
  if (identity2.isCollection(node2)) {
25418
- path18 = Object.freeze(path18.concat(node2));
25418
+ path19 = Object.freeze(path19.concat(node2));
25419
25419
  for (let i = 0; i < node2.items.length; ++i) {
25420
- const ci = visit_(i, node2.items[i], visitor, path18);
25420
+ const ci = visit_(i, node2.items[i], visitor, path19);
25421
25421
  if (typeof ci === "number")
25422
25422
  i = ci - 1;
25423
25423
  else if (ci === BREAK)
@@ -25428,13 +25428,13 @@ var require_visit = __commonJS({
25428
25428
  }
25429
25429
  }
25430
25430
  } else if (identity2.isPair(node2)) {
25431
- path18 = Object.freeze(path18.concat(node2));
25432
- const ck = visit_("key", node2.key, visitor, path18);
25431
+ path19 = Object.freeze(path19.concat(node2));
25432
+ const ck = visit_("key", node2.key, visitor, path19);
25433
25433
  if (ck === BREAK)
25434
25434
  return BREAK;
25435
25435
  else if (ck === REMOVE)
25436
25436
  node2.key = null;
25437
- const cv = visit_("value", node2.value, visitor, path18);
25437
+ const cv = visit_("value", node2.value, visitor, path19);
25438
25438
  if (cv === BREAK)
25439
25439
  return BREAK;
25440
25440
  else if (cv === REMOVE)
@@ -25455,17 +25455,17 @@ var require_visit = __commonJS({
25455
25455
  visitAsync.BREAK = BREAK;
25456
25456
  visitAsync.SKIP = SKIP;
25457
25457
  visitAsync.REMOVE = REMOVE;
25458
- async function visitAsync_(key, node2, visitor, path18) {
25459
- const ctrl = await callVisitor(key, node2, visitor, path18);
25458
+ async function visitAsync_(key, node2, visitor, path19) {
25459
+ const ctrl = await callVisitor(key, node2, visitor, path19);
25460
25460
  if (identity2.isNode(ctrl) || identity2.isPair(ctrl)) {
25461
- replaceNode(key, path18, ctrl);
25462
- return visitAsync_(key, ctrl, visitor, path18);
25461
+ replaceNode(key, path19, ctrl);
25462
+ return visitAsync_(key, ctrl, visitor, path19);
25463
25463
  }
25464
25464
  if (typeof ctrl !== "symbol") {
25465
25465
  if (identity2.isCollection(node2)) {
25466
- path18 = Object.freeze(path18.concat(node2));
25466
+ path19 = Object.freeze(path19.concat(node2));
25467
25467
  for (let i = 0; i < node2.items.length; ++i) {
25468
- const ci = await visitAsync_(i, node2.items[i], visitor, path18);
25468
+ const ci = await visitAsync_(i, node2.items[i], visitor, path19);
25469
25469
  if (typeof ci === "number")
25470
25470
  i = ci - 1;
25471
25471
  else if (ci === BREAK)
@@ -25476,13 +25476,13 @@ var require_visit = __commonJS({
25476
25476
  }
25477
25477
  }
25478
25478
  } else if (identity2.isPair(node2)) {
25479
- path18 = Object.freeze(path18.concat(node2));
25480
- const ck = await visitAsync_("key", node2.key, visitor, path18);
25479
+ path19 = Object.freeze(path19.concat(node2));
25480
+ const ck = await visitAsync_("key", node2.key, visitor, path19);
25481
25481
  if (ck === BREAK)
25482
25482
  return BREAK;
25483
25483
  else if (ck === REMOVE)
25484
25484
  node2.key = null;
25485
- const cv = await visitAsync_("value", node2.value, visitor, path18);
25485
+ const cv = await visitAsync_("value", node2.value, visitor, path19);
25486
25486
  if (cv === BREAK)
25487
25487
  return BREAK;
25488
25488
  else if (cv === REMOVE)
@@ -25509,23 +25509,23 @@ var require_visit = __commonJS({
25509
25509
  }
25510
25510
  return visitor;
25511
25511
  }
25512
- function callVisitor(key, node2, visitor, path18) {
25512
+ function callVisitor(key, node2, visitor, path19) {
25513
25513
  if (typeof visitor === "function")
25514
- return visitor(key, node2, path18);
25514
+ return visitor(key, node2, path19);
25515
25515
  if (identity2.isMap(node2))
25516
- return visitor.Map?.(key, node2, path18);
25516
+ return visitor.Map?.(key, node2, path19);
25517
25517
  if (identity2.isSeq(node2))
25518
- return visitor.Seq?.(key, node2, path18);
25518
+ return visitor.Seq?.(key, node2, path19);
25519
25519
  if (identity2.isPair(node2))
25520
- return visitor.Pair?.(key, node2, path18);
25520
+ return visitor.Pair?.(key, node2, path19);
25521
25521
  if (identity2.isScalar(node2))
25522
- return visitor.Scalar?.(key, node2, path18);
25522
+ return visitor.Scalar?.(key, node2, path19);
25523
25523
  if (identity2.isAlias(node2))
25524
- return visitor.Alias?.(key, node2, path18);
25524
+ return visitor.Alias?.(key, node2, path19);
25525
25525
  return void 0;
25526
25526
  }
25527
- function replaceNode(key, path18, node2) {
25528
- const parent = path18[path18.length - 1];
25527
+ function replaceNode(key, path19, node2) {
25528
+ const parent = path19[path19.length - 1];
25529
25529
  if (identity2.isCollection(parent)) {
25530
25530
  parent.items[key] = node2;
25531
25531
  } else if (identity2.isPair(parent)) {
@@ -26137,10 +26137,10 @@ var require_Collection = __commonJS({
26137
26137
  var createNode = require_createNode();
26138
26138
  var identity2 = require_identity();
26139
26139
  var Node = require_Node();
26140
- function collectionFromPath(schema, path18, value) {
26140
+ function collectionFromPath(schema, path19, value) {
26141
26141
  let v = value;
26142
- for (let i = path18.length - 1; i >= 0; --i) {
26143
- const k = path18[i];
26142
+ for (let i = path19.length - 1; i >= 0; --i) {
26143
+ const k = path19[i];
26144
26144
  if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
26145
26145
  const a = [];
26146
26146
  a[k] = v;
@@ -26159,7 +26159,7 @@ var require_Collection = __commonJS({
26159
26159
  sourceObjects: /* @__PURE__ */ new Map()
26160
26160
  });
26161
26161
  }
26162
- var isEmptyPath = (path18) => path18 == null || typeof path18 === "object" && !!path18[Symbol.iterator]().next().done;
26162
+ var isEmptyPath = (path19) => path19 == null || typeof path19 === "object" && !!path19[Symbol.iterator]().next().done;
26163
26163
  var Collection = class extends Node.NodeBase {
26164
26164
  constructor(type, schema) {
26165
26165
  super(type);
@@ -26189,11 +26189,11 @@ var require_Collection = __commonJS({
26189
26189
  * be a Pair instance or a `{ key, value }` object, which may not have a key
26190
26190
  * that already exists in the map.
26191
26191
  */
26192
- addIn(path18, value) {
26193
- if (isEmptyPath(path18))
26192
+ addIn(path19, value) {
26193
+ if (isEmptyPath(path19))
26194
26194
  this.add(value);
26195
26195
  else {
26196
- const [key, ...rest] = path18;
26196
+ const [key, ...rest] = path19;
26197
26197
  const node2 = this.get(key, true);
26198
26198
  if (identity2.isCollection(node2))
26199
26199
  node2.addIn(rest, value);
@@ -26207,8 +26207,8 @@ var require_Collection = __commonJS({
26207
26207
  * Removes a value from the collection.
26208
26208
  * @returns `true` if the item was found and removed.
26209
26209
  */
26210
- deleteIn(path18) {
26211
- const [key, ...rest] = path18;
26210
+ deleteIn(path19) {
26211
+ const [key, ...rest] = path19;
26212
26212
  if (rest.length === 0)
26213
26213
  return this.delete(key);
26214
26214
  const node2 = this.get(key, true);
@@ -26222,8 +26222,8 @@ var require_Collection = __commonJS({
26222
26222
  * scalar values from their surrounding node; to disable set `keepScalar` to
26223
26223
  * `true` (collections are always returned intact).
26224
26224
  */
26225
- getIn(path18, keepScalar) {
26226
- const [key, ...rest] = path18;
26225
+ getIn(path19, keepScalar) {
26226
+ const [key, ...rest] = path19;
26227
26227
  const node2 = this.get(key, true);
26228
26228
  if (rest.length === 0)
26229
26229
  return !keepScalar && identity2.isScalar(node2) ? node2.value : node2;
@@ -26241,8 +26241,8 @@ var require_Collection = __commonJS({
26241
26241
  /**
26242
26242
  * Checks if the collection includes a value with the key `key`.
26243
26243
  */
26244
- hasIn(path18) {
26245
- const [key, ...rest] = path18;
26244
+ hasIn(path19) {
26245
+ const [key, ...rest] = path19;
26246
26246
  if (rest.length === 0)
26247
26247
  return this.has(key);
26248
26248
  const node2 = this.get(key, true);
@@ -26252,8 +26252,8 @@ var require_Collection = __commonJS({
26252
26252
  * Sets a value in this collection. For `!!set`, `value` needs to be a
26253
26253
  * boolean to add/remove the item from the set.
26254
26254
  */
26255
- setIn(path18, value) {
26256
- const [key, ...rest] = path18;
26255
+ setIn(path19, value) {
26256
+ const [key, ...rest] = path19;
26257
26257
  if (rest.length === 0) {
26258
26258
  this.set(key, value);
26259
26259
  } else {
@@ -28768,9 +28768,9 @@ var require_Document = __commonJS({
28768
28768
  this.contents.add(value);
28769
28769
  }
28770
28770
  /** Adds a value to the document. */
28771
- addIn(path18, value) {
28771
+ addIn(path19, value) {
28772
28772
  if (assertCollection(this.contents))
28773
- this.contents.addIn(path18, value);
28773
+ this.contents.addIn(path19, value);
28774
28774
  }
28775
28775
  /**
28776
28776
  * Create a new `Alias` node, ensuring that the target `node` has the required anchor.
@@ -28845,14 +28845,14 @@ var require_Document = __commonJS({
28845
28845
  * Removes a value from the document.
28846
28846
  * @returns `true` if the item was found and removed.
28847
28847
  */
28848
- deleteIn(path18) {
28849
- if (Collection.isEmptyPath(path18)) {
28848
+ deleteIn(path19) {
28849
+ if (Collection.isEmptyPath(path19)) {
28850
28850
  if (this.contents == null)
28851
28851
  return false;
28852
28852
  this.contents = null;
28853
28853
  return true;
28854
28854
  }
28855
- return assertCollection(this.contents) ? this.contents.deleteIn(path18) : false;
28855
+ return assertCollection(this.contents) ? this.contents.deleteIn(path19) : false;
28856
28856
  }
28857
28857
  /**
28858
28858
  * Returns item at `key`, or `undefined` if not found. By default unwraps
@@ -28867,10 +28867,10 @@ var require_Document = __commonJS({
28867
28867
  * scalar values from their surrounding node; to disable set `keepScalar` to
28868
28868
  * `true` (collections are always returned intact).
28869
28869
  */
28870
- getIn(path18, keepScalar) {
28871
- if (Collection.isEmptyPath(path18))
28870
+ getIn(path19, keepScalar) {
28871
+ if (Collection.isEmptyPath(path19))
28872
28872
  return !keepScalar && identity2.isScalar(this.contents) ? this.contents.value : this.contents;
28873
- return identity2.isCollection(this.contents) ? this.contents.getIn(path18, keepScalar) : void 0;
28873
+ return identity2.isCollection(this.contents) ? this.contents.getIn(path19, keepScalar) : void 0;
28874
28874
  }
28875
28875
  /**
28876
28876
  * Checks if the document includes a value with the key `key`.
@@ -28881,10 +28881,10 @@ var require_Document = __commonJS({
28881
28881
  /**
28882
28882
  * Checks if the document includes a value at `path`.
28883
28883
  */
28884
- hasIn(path18) {
28885
- if (Collection.isEmptyPath(path18))
28884
+ hasIn(path19) {
28885
+ if (Collection.isEmptyPath(path19))
28886
28886
  return this.contents !== void 0;
28887
- return identity2.isCollection(this.contents) ? this.contents.hasIn(path18) : false;
28887
+ return identity2.isCollection(this.contents) ? this.contents.hasIn(path19) : false;
28888
28888
  }
28889
28889
  /**
28890
28890
  * Sets a value in this document. For `!!set`, `value` needs to be a
@@ -28901,13 +28901,13 @@ var require_Document = __commonJS({
28901
28901
  * Sets a value in this document. For `!!set`, `value` needs to be a
28902
28902
  * boolean to add/remove the item from the set.
28903
28903
  */
28904
- setIn(path18, value) {
28905
- if (Collection.isEmptyPath(path18)) {
28904
+ setIn(path19, value) {
28905
+ if (Collection.isEmptyPath(path19)) {
28906
28906
  this.contents = value;
28907
28907
  } else if (this.contents == null) {
28908
- this.contents = Collection.collectionFromPath(this.schema, Array.from(path18), value);
28908
+ this.contents = Collection.collectionFromPath(this.schema, Array.from(path19), value);
28909
28909
  } else if (assertCollection(this.contents)) {
28910
- this.contents.setIn(path18, value);
28910
+ this.contents.setIn(path19, value);
28911
28911
  }
28912
28912
  }
28913
28913
  /**
@@ -30868,9 +30868,9 @@ var require_cst_visit = __commonJS({
30868
30868
  visit2.BREAK = BREAK;
30869
30869
  visit2.SKIP = SKIP;
30870
30870
  visit2.REMOVE = REMOVE;
30871
- visit2.itemAtPath = (cst, path18) => {
30871
+ visit2.itemAtPath = (cst, path19) => {
30872
30872
  let item = cst;
30873
- for (const [field, index] of path18) {
30873
+ for (const [field, index] of path19) {
30874
30874
  const tok = item?.[field];
30875
30875
  if (tok && "items" in tok) {
30876
30876
  item = tok.items[index];
@@ -30879,23 +30879,23 @@ var require_cst_visit = __commonJS({
30879
30879
  }
30880
30880
  return item;
30881
30881
  };
30882
- visit2.parentCollection = (cst, path18) => {
30883
- const parent = visit2.itemAtPath(cst, path18.slice(0, -1));
30884
- const field = path18[path18.length - 1][0];
30882
+ visit2.parentCollection = (cst, path19) => {
30883
+ const parent = visit2.itemAtPath(cst, path19.slice(0, -1));
30884
+ const field = path19[path19.length - 1][0];
30885
30885
  const coll = parent?.[field];
30886
30886
  if (coll && "items" in coll)
30887
30887
  return coll;
30888
30888
  throw new Error("Parent collection not found");
30889
30889
  };
30890
- function _visit(path18, item, visitor) {
30891
- let ctrl = visitor(item, path18);
30890
+ function _visit(path19, item, visitor) {
30891
+ let ctrl = visitor(item, path19);
30892
30892
  if (typeof ctrl === "symbol")
30893
30893
  return ctrl;
30894
30894
  for (const field of ["key", "value"]) {
30895
30895
  const token = item[field];
30896
30896
  if (token && "items" in token) {
30897
30897
  for (let i = 0; i < token.items.length; ++i) {
30898
- const ci = _visit(Object.freeze(path18.concat([[field, i]])), token.items[i], visitor);
30898
+ const ci = _visit(Object.freeze(path19.concat([[field, i]])), token.items[i], visitor);
30899
30899
  if (typeof ci === "number")
30900
30900
  i = ci - 1;
30901
30901
  else if (ci === BREAK)
@@ -30906,10 +30906,10 @@ var require_cst_visit = __commonJS({
30906
30906
  }
30907
30907
  }
30908
30908
  if (typeof ctrl === "function" && field === "key")
30909
- ctrl = ctrl(item, path18);
30909
+ ctrl = ctrl(item, path19);
30910
30910
  }
30911
30911
  }
30912
- return typeof ctrl === "function" ? ctrl(item, path18) : ctrl;
30912
+ return typeof ctrl === "function" ? ctrl(item, path19) : ctrl;
30913
30913
  }
30914
30914
  exports.visit = visit2;
30915
30915
  }
@@ -33725,13 +33725,13 @@ __export(skill_improvement_exports, {
33725
33725
  readImprovementReport: () => readImprovementReport,
33726
33726
  runImprovementJob: () => runImprovementJob
33727
33727
  });
33728
- import { createHash as createHash6 } from "node:crypto";
33728
+ import { createHash as createHash8 } from "node:crypto";
33729
33729
  import { execFile, spawn } from "node:child_process";
33730
33730
  import { promisify } from "node:util";
33731
- import { access, lstat as lstat13, mkdir as mkdir2, open as open9, readFile as readFile2, realpath as realpath9, rm as rm2 } from "node:fs/promises";
33731
+ import { access, lstat as lstat13, mkdir as mkdir3, open as open9, readFile as readFile3, realpath as realpath9, rm as rm3 } from "node:fs/promises";
33732
33732
  import { constants as constants5 } from "node:fs";
33733
- import os4 from "node:os";
33734
- import path13 from "node:path";
33733
+ import os6 from "node:os";
33734
+ import path15 from "node:path";
33735
33735
  import { StringDecoder } from "node:string_decoder";
33736
33736
  async function createImprovementJob(options2) {
33737
33737
  requireSupportedImprovementHost();
@@ -33778,7 +33778,7 @@ async function createImprovementJob(options2) {
33778
33778
  ...suite ? { suite } : {},
33779
33779
  executable,
33780
33780
  executableDigest: await executableDigest(executable),
33781
- runnerPin: (await readFile2(executable)).subarray(0, 2).toString() === "#!" ? "launcher-only" : "native-binary",
33781
+ runnerPin: (await readFile3(executable)).subarray(0, 2).toString() === "#!" ? "launcher-only" : "native-binary",
33782
33782
  runnerVersion,
33783
33783
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
33784
33784
  maxWallMinutes,
@@ -33786,8 +33786,8 @@ async function createImprovementJob(options2) {
33786
33786
  ...options2.registry ? { registry: options2.registry } : {}
33787
33787
  };
33788
33788
  const planDigest = digest4(plan);
33789
- await mkdir2(output2, { mode: 448 });
33790
- await atomicPrivateWrite(output2, path13.join(output2, "plan.json"), JSON.stringify({ plan, planDigest }, null, 2));
33789
+ await mkdir3(output2, { mode: 448 });
33790
+ await atomicPrivateWrite(output2, path15.join(output2, "plan.json"), JSON.stringify({ plan, planDigest }, null, 2));
33791
33791
  return { plan, planDigest };
33792
33792
  }
33793
33793
  async function runImprovementJob(options2) {
@@ -33807,7 +33807,7 @@ async function runImprovementJob(options2) {
33807
33807
  return snapshot.files;
33808
33808
  }));
33809
33809
  if (await executableDigest(plan.executable) !== plan.executableDigest) throw new ImprovementError("Runner executable changed after planning.");
33810
- const lock = path13.join(job, "started");
33810
+ const lock = path15.join(job, "started");
33811
33811
  try {
33812
33812
  const file2 = await open9(lock, "wx", 384);
33813
33813
  await file2.close();
@@ -33819,7 +33819,7 @@ async function runImprovementJob(options2) {
33819
33819
  const startedAt = Date.now();
33820
33820
  const wallLimit = AbortSignal.timeout(plan.maxWallMinutes * 6e4);
33821
33821
  const signal = options2.signal ? AbortSignal.any([options2.signal, wallLimit]) : wallLimit;
33822
- const save = () => atomicPrivateWrite(job, path13.join(job, "report.json"), JSON.stringify(report, null, 2));
33822
+ const save = () => atomicPrivateWrite(job, path15.join(job, "report.json"), JSON.stringify(report, null, 2));
33823
33823
  await save();
33824
33824
  const invoke = async (payload, stage) => {
33825
33825
  if (signal.aborted) throw new ImprovementError(wallLimit.aborted ? "Wall time budget exhausted." : "Run cancelled.");
@@ -33872,7 +33872,7 @@ async function runImprovementJob(options2) {
33872
33872
  loadSkillManifestFromPackageFiles(files2);
33873
33873
  validateCodexSkill(files2, source2.manifest.name);
33874
33874
  if (hasBlockingFindings(scanPackageFiles(files2).findings)) throw new ImprovementError("Candidate failed the package safety scan; evaluation was not started.");
33875
- await writeNewPackageTree(job, path13.join(job, "candidate"), files2);
33875
+ await writeNewPackageTree(job, path15.join(job, "candidate"), files2);
33876
33876
  report.candidateDigest = treeDigest(files2);
33877
33877
  await options2.lifecycle?.candidate(report.candidateDigest, files2);
33878
33878
  await options2.lifecycle?.stage("propose", "completed", analysis.findings.length);
@@ -33920,7 +33920,7 @@ async function runImprovementJob(options2) {
33920
33920
  async function readImprovementReport(jobPath) {
33921
33921
  jobPath = systemAlias(jobPath);
33922
33922
  const { planDigest } = await readPlan(jobPath);
33923
- const report = JSON.parse(await readRegularText(path13.join(jobPath, "report.json"), MAX_STATE));
33923
+ const report = JSON.parse(await readRegularText(path15.join(jobPath, "report.json"), MAX_STATE));
33924
33924
  if (report.schemaVersion !== 1 || report.provenance !== "local-report" || report.planDigest !== planDigest) throw new ImprovementError("Report does not match the accepted plan.");
33925
33925
  return report;
33926
33926
  }
@@ -33928,7 +33928,7 @@ async function exportImprovementCandidate(options2) {
33928
33928
  const { plan } = await readPlan(options2.jobPath);
33929
33929
  const report = await readImprovementReport(options2.jobPath);
33930
33930
  if (report.state !== "completed" || !report.candidateDigest) throw new ImprovementError("Only a completed candidate can be exported for review.");
33931
- const snapshot = await checkedPackage(path13.join(options2.jobPath, "candidate"));
33931
+ const snapshot = await checkedPackage(path15.join(options2.jobPath, "candidate"));
33932
33932
  if (treeDigest(snapshot.files) !== report.candidateDigest) throw new ImprovementError("Candidate digest changed since evaluation.");
33933
33933
  if (snapshot.manifest.version !== plan.targetVersion) throw new ImprovementError("Candidate identity does not match the plan.");
33934
33934
  const output2 = await destination(options2.outputPath);
@@ -33938,7 +33938,7 @@ async function exportImprovementCandidate(options2) {
33938
33938
  }
33939
33939
  async function readImprovementPlan(job) {
33940
33940
  job = systemAlias(job);
33941
- const value = JSON.parse(await readRegularText(path13.join(job, "plan.json"), MAX_STATE));
33941
+ const value = JSON.parse(await readRegularText(path15.join(job, "plan.json"), MAX_STATE));
33942
33942
  if (isRecord7(value) && isRecord7(value.plan) && value.plan.adapter === "codex-text-v1") throw new ImprovementError("This job was planned for the retired codex-text-v1 adapter. Codex execution is disabled until it passes a future isolation gate; create a new plan for Claude Code. No fallback runner is used.");
33943
33943
  if (!isRecord7(value) || !isRecord7(value.plan) || value.plan.schemaVersion !== 1 || value.plan.adapter !== "claude-code-text-v1" || digest4(value.plan) !== value.planDigest) throw new ImprovementError("Plan digest is invalid or the plan changed.");
33944
33944
  return value;
@@ -33985,21 +33985,21 @@ function validateAnalysis(value) {
33985
33985
  return { disposition: value.disposition, findings: value.findings.map((f) => ({ id: f.id, severity: f.severity, summary: f.summary })), changes: value.changes.map((f) => ({ path: f.path, content: f.content })), rationale: value.rationale };
33986
33986
  }
33987
33987
  async function destination(input2) {
33988
- const absolute2 = path13.resolve(input2);
33989
- const parent = await realpath9(path13.dirname(absolute2));
33988
+ const absolute2 = path15.resolve(input2);
33989
+ const parent = await realpath9(path15.dirname(absolute2));
33990
33990
  await assertRegularDirectory(parent);
33991
- return path13.join(parent, path13.basename(absolute2));
33991
+ return path15.join(parent, path15.basename(absolute2));
33992
33992
  }
33993
33993
  function systemAlias(input2) {
33994
- const absolute2 = path13.resolve(input2);
33994
+ const absolute2 = path15.resolve(input2);
33995
33995
  if (process.platform === "darwin" && ["/tmp", "/var", "/etc"].some((prefix) => absolute2 === prefix || absolute2.startsWith(prefix + "/"))) return "/private" + absolute2;
33996
33996
  return absolute2;
33997
33997
  }
33998
33998
  function assertSeparate(a, b) {
33999
- if (a === b || a.startsWith(b + path13.sep) || b.startsWith(a + path13.sep)) throw new ImprovementError("Job and export paths must not overlap source, reviewer, or job directories.");
33999
+ if (a === b || a.startsWith(b + path15.sep) || b.startsWith(a + path15.sep)) throw new ImprovementError("Job and export paths must not overlap source, reviewer, or job directories.");
34000
34000
  }
34001
34001
  async function resolveExecutable(input2) {
34002
- const candidates = input2.includes(path13.sep) ? [path13.resolve(input2)] : (process.env.PATH ?? "").split(path13.delimiter).filter(Boolean).map((p) => path13.join(p, input2));
34002
+ const candidates = input2.includes(path15.sep) ? [path15.resolve(input2)] : (process.env.PATH ?? "").split(path15.delimiter).filter(Boolean).map((p) => path15.join(p, input2));
34003
34003
  for (const candidate of candidates) {
34004
34004
  try {
34005
34005
  const resolved = await realpath9(candidate);
@@ -34012,10 +34012,10 @@ async function resolveExecutable(input2) {
34012
34012
  throw new ImprovementError("Claude Code executable is unavailable. Install Claude Code and sign in with your existing account before planning a run.");
34013
34013
  }
34014
34014
  async function executableDigest(executable) {
34015
- return createHash6("sha256").update(await readFile2(executable)).digest("hex");
34015
+ return createHash8("sha256").update(await readFile3(executable)).digest("hex");
34016
34016
  }
34017
34017
  function claudeEnvironment(tmp) {
34018
- const env = { PATH: process.env.PATH, HOME: os4.homedir(), TMPDIR: tmp, LANG: "en_US.UTF-8" };
34018
+ const env = { PATH: process.env.PATH, HOME: os6.homedir(), TMPDIR: tmp, LANG: "en_US.UTF-8" };
34019
34019
  for (const name of ["USER", "LOGNAME", "SHELL", "CLAUDE_CONFIG_DIR"]) if (process.env[name]) env[name] = process.env[name];
34020
34020
  return env;
34021
34021
  }
@@ -34027,7 +34027,7 @@ async function inspectImprovementRunner(input2) {
34027
34027
  const executable = await resolveExecutable(input2 ?? "claude");
34028
34028
  let version2;
34029
34029
  try {
34030
- const { stdout: stdout2 } = await promisify(execFile)(executable, ["--version"], { timeout: 1e4, maxBuffer: 4096, encoding: "utf8", env: claudeEnvironment(os4.tmpdir()) });
34030
+ const { stdout: stdout2 } = await promisify(execFile)(executable, ["--version"], { timeout: 1e4, maxBuffer: 4096, encoding: "utf8", env: claudeEnvironment(os6.tmpdir()) });
34031
34031
  version2 = /^([0-9]+\.[0-9]+\.[0-9]+) \(Claude Code\)\s*$/.exec(stdout2)?.[1];
34032
34032
  } catch {
34033
34033
  }
@@ -34087,8 +34087,8 @@ function claudeEventViolation(state, event, model, runnerVersion) {
34087
34087
  return claudeFailure.invalid;
34088
34088
  }
34089
34089
  async function invokeClaude(plan, job, call, payload, stage, signal) {
34090
- const scratch = path13.join(job, `call-${call}`);
34091
- await mkdir2(scratch, { mode: 448 });
34090
+ const scratch = path15.join(job, `call-${call}`);
34091
+ await mkdir3(scratch, { mode: 448 });
34092
34092
  const string4 = { type: "string" };
34093
34093
  const schema = stage === "evaluate" ? { type: "object", additionalProperties: false, properties: { response: string4 }, required: ["response"] } : {
34094
34094
  type: "object",
@@ -34217,7 +34217,7 @@ async function invokeClaude(plan, job, call, payload, stage, signal) {
34217
34217
  if (JSON.stringify(state.value).length > MAX_OUTPUT) throw new ImprovementError("Runner output limit exceeded.");
34218
34218
  return { value: state.value, observedModel: plan.model };
34219
34219
  } finally {
34220
- await rm2(scratch, { recursive: true, force: true });
34220
+ await rm3(scratch, { recursive: true, force: true });
34221
34221
  }
34222
34222
  }
34223
34223
  var ImprovementError, MAX_OUTPUT, MAX_STATE, MAX_STREAM, MAX_EVENT, digest4, treeDigest, readPlan, MINIMUM_CLAUDE_VERSION, CLAUDE_SYSTEM_PROMPT, allowedClaudePlugins, claudeFailure;
@@ -34233,7 +34233,7 @@ var init_skill_improvement = __esm({
34233
34233
  MAX_STATE = 8 * 1024 * 1024;
34234
34234
  MAX_STREAM = 16 * 1024 * 1024;
34235
34235
  MAX_EVENT = 4 * 1024 * 1024;
34236
- digest4 = (value) => createHash6("sha256").update(JSON.stringify(value)).digest("hex");
34236
+ digest4 = (value) => createHash8("sha256").update(JSON.stringify(value)).digest("hex");
34237
34237
  treeDigest = (files2) => digest4({ files: [...files2].sort((a, b) => a.path.localeCompare(b.path)) });
34238
34238
  readPlan = readImprovementPlan;
34239
34239
  MINIMUM_CLAUDE_VERSION = [2, 1, 283];
@@ -34260,9 +34260,9 @@ __export(skill_improvement_registry_exports, {
34260
34260
  shareImprovementEvidence: () => shareImprovementEvidence,
34261
34261
  shareRecordedImprovementEvidence: () => shareRecordedImprovementEvidence
34262
34262
  });
34263
- import { createHash as createHash7 } from "node:crypto";
34264
- import { mkdir as mkdir3, realpath as realpath10 } from "node:fs/promises";
34265
- import path14 from "node:path";
34263
+ import { createHash as createHash9 } from "node:crypto";
34264
+ import { mkdir as mkdir4, realpath as realpath10 } from "node:fs/promises";
34265
+ import path16 from "node:path";
34266
34266
  async function fetchImprovementJob(api, input2) {
34267
34267
  const response = await api.get(`${base2}/plans/${encodeURIComponent(input2.planId)}`);
34268
34268
  const record5 = checkedRecord(response.plan, input2.planId);
@@ -34297,14 +34297,14 @@ async function fetchImprovementJob(api, input2) {
34297
34297
  if (snapshot.artifact.sha256 !== pin.artifactSha256) throw new Error("A downloaded release differs from the prepared artifact digest.");
34298
34298
  return snapshot;
34299
34299
  }));
34300
- const output2 = path14.join(await realpath10(path14.dirname(path14.resolve(input2.outputPath))), path14.basename(input2.outputPath));
34300
+ const output2 = path16.join(await realpath10(path16.dirname(path16.resolve(input2.outputPath))), path16.basename(input2.outputPath));
34301
34301
  const inputs = `${output2}.inputs`;
34302
- await mkdir3(inputs, { mode: 448 });
34303
- const sourcePath = path14.join(inputs, "source");
34302
+ await mkdir4(inputs, { mode: 448 });
34303
+ const sourcePath = path16.join(inputs, "source");
34304
34304
  await writeNewPackageTree(inputs, sourcePath, snapshots[0].files);
34305
34305
  const reviewerPaths = [];
34306
34306
  for (let i = 1; i < snapshots.length; i += 1) {
34307
- const dir = path14.join(inputs, `reviewer-${i}`);
34307
+ const dir = path16.join(inputs, `reviewer-${i}`);
34308
34308
  await writeNewPackageTree(inputs, dir, snapshots[i].files);
34309
34309
  reviewerPaths.push(dir);
34310
34310
  }
@@ -34340,7 +34340,7 @@ async function registryLifecycle(api, jobPath, coordinatorVersion) {
34340
34340
  let runId;
34341
34341
  let sequence = 0;
34342
34342
  const jobRoot = await realpath10(jobPath);
34343
- const statePath = path14.join(jobRoot, "registry-run.json");
34343
+ const statePath = path16.join(jobRoot, "registry-run.json");
34344
34344
  const save = async (reportSha256) => atomicPrivateWrite(jobRoot, statePath, JSON.stringify({ planDigest, planId: binding.planId, runId, sequence, reportSha256: reportSha256 ?? null }, null, 2));
34345
34345
  const event = async (value) => {
34346
34346
  if (!runId) throw new Error("The registry run has not started.");
@@ -34443,7 +34443,7 @@ async function shareImprovementEvidence(api, input2) {
34443
34443
  if (!plan.registry || plan.registry.apiUrl !== api.apiUrl) throw new Error("Evidence sharing requires the original registry endpoint and plan.");
34444
34444
  if (plan.registry.record.plan.resultSharing === "local-only") throw new Error("This plan is local-only; evidence sharing was not authorized.");
34445
34445
  if (input2.disclosure !== "summary") throw new Error("This adapter shares summary evidence only. Raw findings stay local.");
34446
- const state = JSON.parse(await readRegularText(path14.join(await realpath10(input2.jobPath), "registry-run.json"), 64e3));
34446
+ const state = JSON.parse(await readRegularText(path16.join(await realpath10(input2.jobPath), "registry-run.json"), 64e3));
34447
34447
  if (!state || state.planDigest !== planDigest || typeof state.runId !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._:@+-]{0,127}$/.test(state.runId) || typeof state.reportSha256 !== "string" || !/^[0-9a-f]{64}$/.test(state.reportSha256)) throw new Error("No confirmed registry completion is available to share.");
34448
34448
  return postImprovementEvidence(api, state.runId, state.reportSha256, input2.disclosure, input2.proposals);
34449
34449
  }
@@ -34460,7 +34460,7 @@ var init_skill_improvement_registry = __esm({
34460
34460
  init_dist();
34461
34461
  init_install_filesystem();
34462
34462
  init_skill_improvement();
34463
- hash2 = (value) => createHash7("sha256").update(canonicalizeJson(value)).digest("hex");
34463
+ hash2 = (value) => createHash9("sha256").update(canonicalizeJson(value)).digest("hex");
34464
34464
  base2 = "/v1/improvements";
34465
34465
  }
34466
34466
  });
@@ -34531,9 +34531,9 @@ function option(input2, key) {
34531
34531
  if (typeof value !== "string" || !value) throw new Error(`--${key} requires a file.`);
34532
34532
  return value;
34533
34533
  }
34534
- async function readInput(context, path18) {
34534
+ async function readInput(context, path19) {
34535
34535
  try {
34536
- return await context.readInput(path18);
34536
+ return await context.readInput(path19);
34537
34537
  } catch {
34538
34538
  throw new Error("Evaluation input must be a bounded valid JSON object.");
34539
34539
  }
@@ -35045,52 +35045,466 @@ function decodeResponseUtf8(bytes2) {
35045
35045
  }
35046
35046
  }
35047
35047
 
35048
+ // src/device-login-store.ts
35049
+ init_install_filesystem();
35050
+ import { createHash as createHash5 } from "node:crypto";
35051
+ import os5 from "node:os";
35052
+ import path9 from "node:path";
35053
+
35054
+ // src/token-store.ts
35055
+ import { createHash as createHash4 } from "node:crypto";
35056
+ import { chmod, mkdir as mkdir2, readFile, rm as rm2, writeFile } from "node:fs/promises";
35057
+ import os4 from "node:os";
35058
+ import path8 from "node:path";
35059
+ var KEYRING_SERVICE = "ai.jarel.myskills.cli";
35060
+ function createTokenStore(env = process.env, namespace) {
35061
+ const fileStore = createFileTokenStore(env);
35062
+ if (env.MYSKILLS_TOKEN_STORE === "file" || env.MYSKILLS_TOKEN_FILE) {
35063
+ return fileStore;
35064
+ }
35065
+ return createKeyringTokenStore(fileStore, void 0, namespace);
35066
+ }
35067
+ function createFileTokenStore(env = process.env) {
35068
+ const filePath = tokenFilePath(env);
35069
+ return {
35070
+ async get(apiUrl) {
35071
+ return (await readPayload(filePath)).tokens[normalizeApiUrl(apiUrl)] ?? null;
35072
+ },
35073
+ async set(apiUrl, token) {
35074
+ const payload = await readPayload(filePath);
35075
+ payload.tokens[normalizeApiUrl(apiUrl)] = token;
35076
+ await writePayload(filePath, payload);
35077
+ },
35078
+ async delete(apiUrl) {
35079
+ const payload = await readPayload(filePath);
35080
+ delete payload.tokens[normalizeApiUrl(apiUrl)];
35081
+ if (Object.keys(payload.tokens).length === 0) {
35082
+ await rm2(filePath, { force: true });
35083
+ return;
35084
+ }
35085
+ await writePayload(filePath, payload);
35086
+ },
35087
+ describe() {
35088
+ return {
35089
+ backend: "file",
35090
+ filePath
35091
+ };
35092
+ }
35093
+ };
35094
+ }
35095
+ function createKeyringTokenStore(fallback, backend = nativeKeyringBackend, namespace) {
35096
+ const credentialKey = (apiUrl) => keyringCredentialKey(apiUrl, namespace);
35097
+ let usedFallback = false;
35098
+ return {
35099
+ async get(apiUrl) {
35100
+ let raw;
35101
+ try {
35102
+ raw = await backend.get(credentialKey(apiUrl));
35103
+ } catch {
35104
+ throw new Error("Cannot read the OS keyring. Unlock or restore keyring access, or explicitly select MYSKILLS_TOKEN_STORE=file.");
35105
+ }
35106
+ if (raw === null) {
35107
+ const token2 = await fallback.get(apiUrl);
35108
+ usedFallback = token2 !== null;
35109
+ return token2;
35110
+ }
35111
+ let token;
35112
+ try {
35113
+ token = parseStoredToken(JSON.parse(raw));
35114
+ } catch {
35115
+ token = null;
35116
+ }
35117
+ if (!token) {
35118
+ throw new Error("The OS keyring credential has an invalid format. Remove it with myskills logout, then log in again.");
35119
+ }
35120
+ usedFallback = false;
35121
+ return token;
35122
+ },
35123
+ async set(apiUrl, token) {
35124
+ try {
35125
+ await backend.set(credentialKey(apiUrl), JSON.stringify(token));
35126
+ } catch {
35127
+ throw new Error("Cannot save the token in the OS keyring. Unlock or restore keyring access, or explicitly select MYSKILLS_TOKEN_STORE=file.");
35128
+ }
35129
+ usedFallback = false;
35130
+ try {
35131
+ await fallback.delete(apiUrl);
35132
+ } catch {
35133
+ throw new Error("The token was saved in the OS keyring, but the older file credential could not be removed. Token storage cleanup is incomplete.");
35134
+ }
35135
+ },
35136
+ async delete(apiUrl) {
35137
+ const results = await Promise.allSettled([backend.delete(credentialKey(apiUrl)), fallback.delete(apiUrl)]);
35138
+ const failed = results.flatMap((result, index) => result.status === "rejected" ? [index === 0 ? "OS keyring" : "file"] : []);
35139
+ if (failed.length > 0) {
35140
+ throw new Error(`Logout cleanup is incomplete: could not remove the ${failed.join(" and ")} credential. Restore storage access and retry logout.`);
35141
+ }
35142
+ usedFallback = false;
35143
+ },
35144
+ async describe() {
35145
+ const fallbackInfo = await fallback.describe?.();
35146
+ if (usedFallback && fallbackInfo) {
35147
+ return fallbackInfo;
35148
+ }
35149
+ return {
35150
+ backend: "keyring",
35151
+ fallbackFilePath: fallbackInfo?.filePath
35152
+ };
35153
+ }
35154
+ };
35155
+ }
35156
+ var nativeKeyringBackend = {
35157
+ async get(apiUrl) {
35158
+ const { Entry } = await import("@napi-rs/keyring");
35159
+ return new Entry(KEYRING_SERVICE, keyringAccount(apiUrl)).getPassword();
35160
+ },
35161
+ async set(apiUrl, raw) {
35162
+ const { Entry } = await import("@napi-rs/keyring");
35163
+ new Entry(KEYRING_SERVICE, keyringAccount(apiUrl)).setPassword(raw);
35164
+ },
35165
+ async delete(apiUrl) {
35166
+ const { Entry } = await import("@napi-rs/keyring");
35167
+ new Entry(KEYRING_SERVICE, keyringAccount(apiUrl)).deletePassword();
35168
+ }
35169
+ };
35170
+ function keyringCredentialKey(apiUrl, namespace) {
35171
+ const prefix = namespace === void 0 ? "" : `config-profile:${createHash4("sha256").update(namespace).digest("hex")}:`;
35172
+ return `${prefix}${normalizeApiUrl(apiUrl)}`;
35173
+ }
35174
+ function tokenFilePath(env) {
35175
+ if (env.MYSKILLS_TOKEN_FILE) {
35176
+ return path8.resolve(env.MYSKILLS_TOKEN_FILE);
35177
+ }
35178
+ if (env.MYSKILLS_CONFIG_DIR) {
35179
+ return path8.join(path8.resolve(env.MYSKILLS_CONFIG_DIR), "tokens.json");
35180
+ }
35181
+ const baseDir = env.XDG_CONFIG_HOME ? path8.join(env.XDG_CONFIG_HOME, "myskills-app") : path8.join(os4.homedir(), ".config", "myskills-app");
35182
+ return path8.join(baseDir, "tokens.json");
35183
+ }
35184
+ async function readPayload(filePath) {
35185
+ try {
35186
+ const raw = await readFile(filePath, "utf8");
35187
+ return parsePayload(raw);
35188
+ } catch (error62) {
35189
+ if (isNodeError(error62) && error62.code === "ENOENT") {
35190
+ return { version: 1, tokens: {} };
35191
+ }
35192
+ throw error62;
35193
+ }
35194
+ }
35195
+ async function writePayload(filePath, payload) {
35196
+ await mkdir2(path8.dirname(filePath), { recursive: true, mode: 448 });
35197
+ await writeFile(filePath, `${JSON.stringify(payload, null, 2)}
35198
+ `, { mode: 384 });
35199
+ await chmod(filePath, 384);
35200
+ }
35201
+ function parsePayload(raw) {
35202
+ let parsed;
35203
+ try {
35204
+ parsed = JSON.parse(raw);
35205
+ } catch {
35206
+ throw new Error("Token store file contains invalid JSON. Repair or remove the file before logging in again.");
35207
+ }
35208
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
35209
+ throw new Error("Token store file must contain a JSON object.");
35210
+ }
35211
+ const record5 = parsed;
35212
+ if (record5.version !== 1 || !record5.tokens || typeof record5.tokens !== "object" || Array.isArray(record5.tokens)) {
35213
+ throw new Error("Token store file has an unsupported format.");
35214
+ }
35215
+ const tokens = {};
35216
+ for (const [apiUrl, token] of Object.entries(record5.tokens)) {
35217
+ const parsedToken = parseStoredToken(token);
35218
+ if (parsedToken) {
35219
+ tokens[normalizeApiUrl(apiUrl)] = parsedToken;
35220
+ }
35221
+ }
35222
+ return { version: 1, tokens };
35223
+ }
35224
+ function parseStoredToken(input2) {
35225
+ if (!input2 || typeof input2 !== "object" || Array.isArray(input2)) {
35226
+ return null;
35227
+ }
35228
+ const record5 = input2;
35229
+ if (record5.kind !== "session" && record5.kind !== "api" || typeof record5.token !== "string" || !record5.token) {
35230
+ return null;
35231
+ }
35232
+ return {
35233
+ kind: record5.kind,
35234
+ token: record5.token,
35235
+ email: typeof record5.email === "string" ? record5.email : void 0,
35236
+ expiresAt: typeof record5.expiresAt === "string" ? record5.expiresAt : void 0
35237
+ };
35238
+ }
35239
+ function normalizeApiUrl(apiUrl) {
35240
+ return apiUrl.replace(/\/+$/, "");
35241
+ }
35242
+ function keyringAccount(apiUrl) {
35243
+ return `api-url:${Buffer.from(normalizeApiUrl(apiUrl)).toString("base64url")}`;
35244
+ }
35245
+ function isNodeError(error62) {
35246
+ return error62 instanceof Error && "code" in error62;
35247
+ }
35248
+
35249
+ // src/device-login-store.ts
35250
+ var DeviceLoginError = class extends Error {
35251
+ constructor(message, code) {
35252
+ super(message);
35253
+ this.code = code;
35254
+ }
35255
+ code;
35256
+ };
35257
+ function createDeviceLoginStore(namespace, backend = nativeKeyringBackend, lockDirectory) {
35258
+ const key = (apiUrl) => `device-login:${keyringCredentialKey(apiUrl, namespace)}`;
35259
+ return {
35260
+ async get(apiUrl) {
35261
+ let raw;
35262
+ try {
35263
+ raw = await backend.get(key(apiUrl));
35264
+ } catch {
35265
+ throw unavailable();
35266
+ }
35267
+ if (raw === null) return null;
35268
+ try {
35269
+ if (raw.length > 16384) throw new Error();
35270
+ const value = JSON.parse(raw);
35271
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error();
35272
+ return value;
35273
+ } catch {
35274
+ throw new DeviceLoginError("The pending browser login is invalid. Run myskills logout for this API and configuration profile, then log in again.", "DEVICE_LOGIN_STATE_INVALID");
35275
+ }
35276
+ },
35277
+ async set(apiUrl, request) {
35278
+ try {
35279
+ await backend.set(key(apiUrl), JSON.stringify(request));
35280
+ } catch {
35281
+ throw unavailable();
35282
+ }
35283
+ },
35284
+ async delete(apiUrl) {
35285
+ try {
35286
+ await backend.delete(key(apiUrl));
35287
+ } catch {
35288
+ throw new DeviceLoginError("Pending browser login cleanup failed. Restore OS keyring access and retry logout for this API and configuration profile.", "DEVICE_LOGIN_CLEANUP_FAILED");
35289
+ }
35290
+ },
35291
+ async withLock(apiUrl, work) {
35292
+ const directory = path9.join(lockDirectory ?? deviceLoginLockDirectory(), createHash5("sha256").update(key(apiUrl)).digest("hex"));
35293
+ let acquired = false;
35294
+ try {
35295
+ return await withInstallRootLock(directory, async () => {
35296
+ acquired = true;
35297
+ return work();
35298
+ });
35299
+ } catch (error62) {
35300
+ if (acquired) throw error62;
35301
+ throw new DeviceLoginError("Browser login is busy or its process lock could not be acquired. Wait for the other command to exit and retry; preserve an ambiguous lock for operator recovery.", "DEVICE_LOGIN_BUSY");
35302
+ }
35303
+ }
35304
+ };
35305
+ }
35306
+ function deviceLoginLockDirectory() {
35307
+ try {
35308
+ const home = os5.userInfo().homedir;
35309
+ if (!path9.isAbsolute(home)) throw new Error();
35310
+ return path9.join(home, ".config", "myskills-app", "device-login-locks");
35311
+ } catch {
35312
+ throw new DeviceLoginError("Cannot determine the OS-account home for secure browser-login locking. Configure a valid OS account before browser login or logout; HOME overrides are not used.", "DEVICE_LOGIN_LOCK_UNAVAILABLE");
35313
+ }
35314
+ }
35315
+ function unavailable() {
35316
+ return new DeviceLoginError("Cannot access secure pending-login storage in the OS keyring. Unlock or restore keyring access, or explicitly use login --method browser --no-resume for an in-memory request.", "DEVICE_LOGIN_STORE_UNAVAILABLE");
35317
+ }
35318
+
35048
35319
  // src/device-login.ts
35049
- async function browserDeviceLogin(apiUrl, scopes, runtime) {
35050
- const api = new URL(apiUrl);
35051
- if (api.protocol !== "https:" && !(api.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(api.hostname))) throw new Error("Browser login requires HTTPS, except on loopback.");
35052
- async function post(path18, body) {
35053
- const signal = AbortSignal.timeout(15e3);
35054
- const response = await runtime.fetch(`${apiUrl}/v1/auth/device/${path18}`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body), signal, redirect: "error" });
35055
- const text = decodeResponseUtf8(await readBoundedResponse(response, 16384, signal));
35056
- const result = JSON.parse(text);
35057
- if (!result || typeof result !== "object" || Array.isArray(result)) throw new Error("Invalid device login response.");
35058
- if (!response.ok) throw new Error(`Browser login request failed (HTTP ${response.status}).`);
35059
- return result;
35320
+ async function browserDeviceLogin(apiUrl, scopes, runtime, noResume = false) {
35321
+ apiUrl = apiUrl.replace(/\/+$/, "");
35322
+ const api = safeUrl(apiUrl);
35323
+ if (api.username || api.password || api.search || api.hash) throw invalidResponse();
35324
+ if (!noResume && !runtime.deviceLoginStore) throw new DeviceLoginError("No secure pending-login store is configured. Use login --method browser --no-resume explicitly for an in-memory request.", "DEVICE_LOGIN_STORE_UNAVAILABLE");
35325
+ const controller = new AbortController();
35326
+ const interrupt = () => controller.abort();
35327
+ process.once("SIGINT", interrupt);
35328
+ process.once("SIGTERM", interrupt);
35329
+ const signal = runtime.deviceLogin?.signal ? AbortSignal.any([controller.signal, runtime.deviceLogin.signal]) : controller.signal;
35330
+ const now = runtime.deviceLogin?.now ?? Date.now;
35331
+ const sleep = runtime.deviceLogin?.sleep ?? ((milliseconds, abort) => delay(milliseconds, void 0, { signal: abort }));
35332
+ const store = noResume ? void 0 : runtime.deviceLoginStore;
35333
+ const requestedScopes = scopes ? [...new Set(scopes)].sort() : null;
35334
+ let request;
35335
+ async function post(path19, body, deadline) {
35336
+ const budget = deadline === void 0 ? 15e3 : Math.min(15e3, deadline - now());
35337
+ if (budget <= 0) throw expired();
35338
+ const abort = AbortSignal.any([signal, AbortSignal.timeout(Math.max(1, Math.floor(budget)))]);
35339
+ try {
35340
+ const response = await runtime.fetch(`${apiUrl}/v1/auth/device/${path19}`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body), signal: abort, redirect: "error" });
35341
+ if (!response.ok) throw new DeviceLoginError(`Browser login request failed (HTTP ${response.status}). Retry before the original deadline if a pending request exists.`, "DEVICE_LOGIN_REQUEST_FAILED");
35342
+ const text = decodeResponseUtf8(await readBoundedResponse(response, 16384, abort));
35343
+ let result;
35344
+ try {
35345
+ result = JSON.parse(text);
35346
+ } catch {
35347
+ throw invalidResponse();
35348
+ }
35349
+ if (!result || typeof result !== "object" || Array.isArray(result)) throw invalidResponse();
35350
+ return result;
35351
+ } catch (error62) {
35352
+ if (error62 instanceof DeviceLoginError) throw error62;
35353
+ if (deadline !== void 0 && now() >= deadline) throw expired();
35354
+ throw interrupted();
35355
+ }
35060
35356
  }
35061
- const request = await post("start", scopes ? { scopes } : {});
35062
- if (typeof request.deviceCode !== "string" || !/^[A-Za-z0-9_-]{43}$/.test(request.deviceCode) || typeof request.userCode !== "string" || !/^[23456789ABCDEFGHJKLMNPQRSTUVWXYZ]{5}-[23456789ABCDEFGHJKLMNPQRSTUVWXYZ]{5}$/.test(request.userCode) || typeof request.verificationUri !== "string" || typeof request.expiresIn !== "number" || request.expiresIn < 1 || request.expiresIn > 600) throw new Error("Invalid device login response.");
35063
- const verification = new URL(request.verificationUri);
35064
- if (verification.protocol !== "https:" && !(verification.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(verification.hostname)) || verification.username || verification.password || verification.search || verification.hash || verification.pathname !== "/auth/device") throw new Error("Invalid device verification URL.");
35065
- let interval = pollInterval(request.interval);
35066
- const deadline = Date.now() + request.expiresIn * 1e3;
35067
- runtime.io.stdout(`Open ${verification.href} and enter device code ${request.userCode}.`);
35068
- runtime.io.stdout("Review the permissions in your browser. Waiting for your decision\u2026");
35069
- while (Date.now() < deadline) {
35070
- await delay(Math.min(interval * 1e3, Math.max(1, deadline - Date.now())));
35071
- if (Date.now() >= deadline) break;
35072
- const result = await post("poll", { deviceCode: request.deviceCode });
35073
- if (result.status === "pending" || result.status === "slow_down") {
35074
- interval = pollInterval(result.interval);
35075
- continue;
35357
+ async function clearPending(outcome) {
35358
+ try {
35359
+ await store?.delete(apiUrl);
35360
+ } catch {
35361
+ throw new DeviceLoginError(`${outcome?.message ?? "The credential was saved."} Pending browser login cleanup failed; restore OS keyring access and retry logout.`, outcome?.code ?? "DEVICE_LOGIN_CLEANUP_FAILED");
35076
35362
  }
35077
- if (result.status === "authorized") {
35078
- if (typeof result.token !== "string" || !/^aiss_[A-Za-z0-9_-]{43}$/.test(result.token) || typeof result.email !== "string" || typeof result.expiresAt !== "string" || !Number.isFinite(Date.parse(result.expiresAt)) || Date.parse(result.expiresAt) <= Date.now()) throw new Error("Invalid device credential response.");
35079
- if (!runtime.tokenStore) throw new Error("No credential store is configured.");
35080
- await runtime.tokenStore.set(apiUrl, { kind: "api", token: result.token, email: result.email, expiresAt: result.expiresAt });
35081
- await runtime.configStore?.setApiUrl(apiUrl);
35082
- runtime.io.stdout(`${result.email.replace(/[\u0000-\u001F\u007F-\u009F]/gu, " ")} logged-in expires=${result.expiresAt}`);
35083
- return;
35363
+ }
35364
+ async function run() {
35365
+ if (signal.aborted) throw interrupted();
35366
+ if (noResume && runtime.deviceLoginStore) {
35367
+ let previous2;
35368
+ try {
35369
+ previous2 = await runtime.deviceLoginStore.get(apiUrl);
35370
+ } catch (error63) {
35371
+ if (!(error63 instanceof DeviceLoginError) || error63.code !== "DEVICE_LOGIN_STORE_UNAVAILABLE") throw error63;
35372
+ previous2 = null;
35373
+ runtime.io.stdout("Secure pending state could not be checked. Run logout after keyring access returns before using resumable login again.");
35374
+ }
35375
+ if (previous2 !== null) throw new DeviceLoginError("A pending browser login already exists. Run myskills logout for this API and configuration profile before starting an independent --no-resume request.", "DEVICE_LOGIN_PENDING_EXISTS");
35376
+ }
35377
+ const previous = await store?.get(apiUrl);
35378
+ if (previous !== null && previous !== void 0) {
35379
+ request = pendingRequest(previous);
35380
+ if (Math.min(Date.parse(request.expiresAt), request.deadline) <= now()) {
35381
+ const error63 = expired();
35382
+ await clearPending(error63);
35383
+ throw error63;
35384
+ }
35385
+ if (Date.parse(request.expiresAt) > now() + 6e5) throw invalidState();
35386
+ if (JSON.stringify(request.scopes) !== JSON.stringify(requestedScopes)) throw new DeviceLoginError("A pending browser login requests different scopes. Repeat the same --scopes choice, or run myskills logout for this API and configuration profile before starting a new request.", "DEVICE_LOGIN_SCOPES_MISMATCH");
35387
+ runtime.io.stdout("Resuming the pending browser login.");
35388
+ } else {
35389
+ if (noResume) runtime.io.stdout("Browser login resume is disabled. Interruption requires a new code.");
35390
+ const startedAt = now();
35391
+ const result = await post("start", scopes ? { scopes } : {});
35392
+ if (typeof result.expiresIn !== "number" || !Number.isFinite(result.expiresIn) || result.expiresIn < 1 || result.expiresIn > 600) throw invalidResponse();
35393
+ request = pendingRequest({ ...result, version: 1, scopes: requestedScopes, deadline: Math.min(Date.parse(String(result.expiresAt)), startedAt + result.expiresIn * 1e3), nextPollAt: now() + pollInterval(result.interval) * 1e3 });
35394
+ if (Date.parse(request.expiresAt) > now() + 6e5) throw invalidResponse();
35395
+ if (request.deadline <= now()) throw expired();
35396
+ await store?.set(apiUrl, request);
35397
+ }
35398
+ const deadline = Math.min(Date.parse(request.expiresAt), request.deadline);
35399
+ runtime.io.stdout(`Open ${request.verificationUri} and enter device code ${request.userCode}.`);
35400
+ runtime.io.stdout(`Browser login expires at ${new Date(deadline).toISOString()}. Review the permissions in your browser. Waiting for your decision\u2026`);
35401
+ while (now() < deadline) {
35402
+ if (signal.aborted) throw interrupted();
35403
+ try {
35404
+ await sleep(Math.max(0, Math.min(request.nextPollAt, deadline) - now()), signal);
35405
+ } catch {
35406
+ throw interrupted();
35407
+ }
35408
+ if (signal.aborted) throw interrupted();
35409
+ if (now() >= deadline) break;
35410
+ request.nextPollAt = now() + request.interval * 1e3;
35411
+ await store?.set(apiUrl, request);
35412
+ let result;
35413
+ try {
35414
+ result = await post("poll", { deviceCode: request.deviceCode }, deadline);
35415
+ } catch (error64) {
35416
+ if (error64 instanceof DeviceLoginError && error64.code === "DEVICE_LOGIN_EXPIRED") await clearPending(error64);
35417
+ throw error64;
35418
+ }
35419
+ if (result.status === "pending" || result.status === "slow_down") {
35420
+ request.interval = pollInterval(result.interval);
35421
+ request.nextPollAt = now() + request.interval * 1e3;
35422
+ await store?.set(apiUrl, request);
35423
+ continue;
35424
+ }
35425
+ if (result.status === "authorized") {
35426
+ if (typeof result.token !== "string" || !/^aiss_[A-Za-z0-9_-]{43}$/.test(result.token) || typeof result.email !== "string" || typeof result.expiresAt !== "string" || !Number.isFinite(Date.parse(result.expiresAt)) || Date.parse(result.expiresAt) <= now()) {
35427
+ const error64 = invalidResponse();
35428
+ await clearPending(error64);
35429
+ throw error64;
35430
+ }
35431
+ try {
35432
+ if (!runtime.tokenStore) throw new Error();
35433
+ await runtime.tokenStore.set(apiUrl, { kind: "api", token: result.token, email: result.email, expiresAt: result.expiresAt });
35434
+ } catch {
35435
+ const error64 = new DeviceLoginError("Browser authorization completed, but credential saving was not confirmed. This one-time code cannot be redeemed again. Check myskills auth status; if necessary revoke the CLI browser login token in account settings and start a new login.", "DEVICE_LOGIN_TOKEN_SAVE_FAILED");
35436
+ await clearPending(error64);
35437
+ throw error64;
35438
+ }
35439
+ await clearPending();
35440
+ try {
35441
+ await runtime.configStore?.setApiUrl(apiUrl);
35442
+ } catch {
35443
+ throw new DeviceLoginError("The browser login credential was saved, but saving the selected API URL failed. Use --api-url for this registry and repair the configuration store.", "DEVICE_LOGIN_CONFIG_SAVE_FAILED");
35444
+ }
35445
+ runtime.io.stdout(`${result.email.replace(/[\u0000-\u001F\u007F-\u009F]/gu, " ")} logged-in expires=${result.expiresAt}`);
35446
+ return;
35447
+ }
35448
+ const error63 = result.status === "denied" ? new DeviceLoginError("Browser login denied. Start again to request a new code.", "DEVICE_LOGIN_DENIED") : result.status === "expired" ? expired() : result.status === "invalid" ? new DeviceLoginError("Browser login is invalid or already redeemed. A lost response after one-time redemption cannot be recovered. Check myskills auth status or revoke the CLI browser login token in account settings, then start again.", "DEVICE_LOGIN_INVALID") : invalidResponse();
35449
+ await clearPending(error63);
35450
+ throw error63;
35084
35451
  }
35085
- if (["denied", "expired", "invalid"].includes(String(result.status))) throw new Error(`Browser login ${result.status}.`);
35086
- throw new Error("Invalid device login response.");
35452
+ const error62 = expired();
35453
+ await clearPending(error62);
35454
+ throw error62;
35455
+ }
35456
+ try {
35457
+ if (runtime.deviceLoginStore) await runtime.deviceLoginStore.withLock(apiUrl, run);
35458
+ else await run();
35459
+ } finally {
35460
+ process.removeListener("SIGINT", interrupt);
35461
+ process.removeListener("SIGTERM", interrupt);
35462
+ }
35463
+ function interrupted() {
35464
+ return new DeviceLoginError(request && store ? `Browser login interrupted. Repeat the same login command before ${new Date(request.deadline).toISOString()} to resume. A response lost after one-time redemption cannot be recovered.` : "Browser login interrupted. Start again to request a new code.", "DEVICE_LOGIN_INTERRUPTED");
35465
+ }
35466
+ }
35467
+ function pendingRequest(input2) {
35468
+ if (!input2 || typeof input2 !== "object" || Array.isArray(input2)) throw invalidState();
35469
+ const value = input2;
35470
+ if (value.version !== 1 || typeof value.deviceCode !== "string" || !/^[A-Za-z0-9_-]{43}$/.test(value.deviceCode) || typeof value.userCode !== "string" || !/^[23456789ABCDEFGHJKLMNPQRSTUVWXYZ]{5}-[23456789ABCDEFGHJKLMNPQRSTUVWXYZ]{5}$/.test(value.userCode) || typeof value.verificationUri !== "string" || typeof value.expiresAt !== "string" || !Number.isFinite(Date.parse(value.expiresAt)) || !(value.scopes === null || Array.isArray(value.scopes) && value.scopes.length > 0 && value.scopes.length <= 100 && value.scopes.every((scope) => typeof scope === "string" && /^[a-z][a-z-]*:[a-z][a-z-]*$/.test(scope))) || typeof value.deadline !== "number" || !Number.isFinite(value.deadline) || value.deadline > Date.parse(value.expiresAt) || typeof value.nextPollAt !== "number" || !Number.isFinite(value.nextPollAt)) throw invalidState();
35471
+ const verification = safeUrl(value.verificationUri);
35472
+ if (verification.username || verification.password || verification.search || verification.hash || verification.pathname !== "/auth/device") throw invalidState();
35473
+ return {
35474
+ version: 1,
35475
+ deviceCode: value.deviceCode,
35476
+ userCode: value.userCode,
35477
+ verificationUri: verification.href,
35478
+ expiresAt: value.expiresAt,
35479
+ deadline: value.deadline,
35480
+ scopes: value.scopes === null ? null : [...new Set(value.scopes)].sort(),
35481
+ interval: pollInterval(value.interval),
35482
+ nextPollAt: value.nextPollAt
35483
+ };
35484
+ }
35485
+ function safeUrl(value) {
35486
+ let url3;
35487
+ try {
35488
+ url3 = new URL(value);
35489
+ } catch {
35490
+ throw invalidResponse();
35087
35491
  }
35088
- throw new Error("Browser login expired. Start again to request a new code.");
35492
+ if (url3.protocol !== "https:" && !(url3.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url3.hostname))) throw new DeviceLoginError("Browser login requires HTTPS, except on loopback.", "DEVICE_LOGIN_URL_INVALID");
35493
+ return url3;
35089
35494
  }
35090
35495
  function pollInterval(value) {
35091
- if (typeof value !== "number" || !Number.isInteger(value) || value < 5 || value > 60) throw new Error("Invalid device polling interval.");
35496
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 5 || value > 60) throw invalidResponse();
35092
35497
  return value;
35093
35498
  }
35499
+ function expired() {
35500
+ return new DeviceLoginError("Browser login expired. Start again to request a new code.", "DEVICE_LOGIN_EXPIRED");
35501
+ }
35502
+ function invalidResponse() {
35503
+ return new DeviceLoginError("Invalid browser login response.", "DEVICE_LOGIN_RESPONSE_INVALID");
35504
+ }
35505
+ function invalidState() {
35506
+ return new DeviceLoginError("The pending browser login is invalid. Run myskills logout for this API and configuration profile, then log in again.", "DEVICE_LOGIN_STATE_INVALID");
35507
+ }
35094
35508
 
35095
35509
  // src/cli.ts
35096
35510
  init_dist();
@@ -35485,8 +35899,8 @@ var organizationReadPaths = {
35485
35899
  };
35486
35900
  async function runRegistryCollaborationCommand(input2, context) {
35487
35901
  const [action, ...args] = input2.args;
35488
- const send = async (method, path18, body) => {
35489
- context.output(await context.request(method, path18, body));
35902
+ const send = async (method, path19, body) => {
35903
+ context.output(await context.request(method, path19, body));
35490
35904
  };
35491
35905
  if (input2.command === "skills" && action === "managed") {
35492
35906
  if (args.length) {
@@ -35634,7 +36048,7 @@ function role(input2, allowed) {
35634
36048
 
35635
36049
  // src/account-admin-commands.ts
35636
36050
  import { lstat as lstat8, open as open5, unlink } from "node:fs/promises";
35637
- import path8 from "node:path";
36051
+ import path10 from "node:path";
35638
36052
  var accountAdminHelp = [
35639
36053
  " account register --email <email> [--name <name>] (prompts for a password and an optional invitation token)",
35640
36054
  " account verify-email-request|password-reset-request --email <email>",
@@ -35938,7 +36352,7 @@ async function requiredSecret(context, label, trim = false) {
35938
36352
  return value;
35939
36353
  }
35940
36354
  async function withReservedOutput(output2, action, lostMessage) {
35941
- const file2 = path8.resolve(output2);
36355
+ const file2 = path10.resolve(output2);
35942
36356
  let handle;
35943
36357
  try {
35944
36358
  handle = await open5(file2, "wx", 384);
@@ -36117,16 +36531,16 @@ async function runArchitectureTargetCommand(input2, context) {
36117
36531
  // src/cli.ts
36118
36532
  init_dist2();
36119
36533
  init_dist();
36120
- import { createHash as createHash8, randomUUID as randomUUID3 } from "node:crypto";
36121
- import { lstat as lstat14, mkdir as mkdir4, readFile as readFile3, readdir as readdir6, realpath as realpath11, rename as rename3, rm as rm3, stat as stat3, writeFile } from "node:fs/promises";
36122
- import os5 from "node:os";
36123
- import path15 from "node:path";
36534
+ import { createHash as createHash10, randomUUID as randomUUID3 } from "node:crypto";
36535
+ import { lstat as lstat14, mkdir as mkdir5, readFile as readFile4, readdir as readdir6, realpath as realpath11, rename as rename3, rm as rm4, stat as stat3, writeFile as writeFile2 } from "node:fs/promises";
36536
+ import os7 from "node:os";
36537
+ import path17 from "node:path";
36124
36538
 
36125
36539
  // src/codex-readonly-adapter.ts
36126
36540
  init_dist();
36127
36541
  import { constants as fsConstants } from "node:fs";
36128
36542
  import { open as open6, lstat as lstat9, readdir as readdir5 } from "node:fs/promises";
36129
- import path9 from "node:path";
36543
+ import path11 from "node:path";
36130
36544
  var codexAdapterProfiles = ["personal", "work", "shared"];
36131
36545
  var codexAdapterDescriptor = Object.freeze({
36132
36546
  kind: "codex",
@@ -36253,7 +36667,7 @@ var CodexReadOnlyArchitectureTargetAdapter = class {
36253
36667
  #clock;
36254
36668
  constructor(optionsOrRoot, profile, clock) {
36255
36669
  const options2 = typeof optionsOrRoot === "string" ? { root: optionsOrRoot, profile, clock } : optionsOrRoot;
36256
- if (typeof options2.root !== "string" || !options2.root || !path9.isAbsolute(options2.root)) {
36670
+ if (typeof options2.root !== "string" || !options2.root || !path11.isAbsolute(options2.root)) {
36257
36671
  throw new TypeError("A consented absolute target root is required.");
36258
36672
  }
36259
36673
  if (!isCodexAdapterProfile(options2.profile)) {
@@ -36262,7 +36676,7 @@ var CodexReadOnlyArchitectureTargetAdapter = class {
36262
36676
  if (options2.clock !== void 0 && typeof options2.clock !== "function") {
36263
36677
  throw new TypeError("The adapter clock must be a function.");
36264
36678
  }
36265
- this.#root = path9.resolve(options2.root);
36679
+ this.#root = path11.resolve(options2.root);
36266
36680
  this.#profile = options2.profile;
36267
36681
  this.#clock = options2.clock ?? (() => /* @__PURE__ */ new Date());
36268
36682
  }
@@ -36393,7 +36807,7 @@ var CodexReadOnlyArchitectureTargetAdapter = class {
36393
36807
  return result;
36394
36808
  }
36395
36809
  async #readMetadataFile(relativeName) {
36396
- const filePath = path9.join(this.#root, relativeName);
36810
+ const filePath = path11.join(this.#root, relativeName);
36397
36811
  let handle;
36398
36812
  try {
36399
36813
  handle = await open6(filePath, fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW | fsConstants.O_NONBLOCK);
@@ -36417,7 +36831,7 @@ var CodexReadOnlyArchitectureTargetAdapter = class {
36417
36831
  }
36418
36832
  }
36419
36833
  async #readSkills(profileResolutions, routerPolicy, findings) {
36420
- const skillsDirectory = path9.join(this.#root, SKILLS_DIRECTORY);
36834
+ const skillsDirectory = path11.join(this.#root, SKILLS_DIRECTORY);
36421
36835
  let entries;
36422
36836
  try {
36423
36837
  const directory = await lstat9(skillsDirectory);
@@ -36450,7 +36864,7 @@ var CodexReadOnlyArchitectureTargetAdapter = class {
36450
36864
  return skills.sort(compareSkills);
36451
36865
  }
36452
36866
  async #readSkill(directorySlug, profileResolutions, routerPolicy, findings) {
36453
- const skillPath = path9.join(this.#root, SKILLS_DIRECTORY, directorySlug, "SKILL.md");
36867
+ const skillPath = path11.join(this.#root, SKILLS_DIRECTORY, directorySlug, "SKILL.md");
36454
36868
  const frontmatter = await readFrontmatter(skillPath);
36455
36869
  if (frontmatter.status === "missing") findings.add("skill-frontmatter-missing");
36456
36870
  if (frontmatter.status === "invalid") findings.add("skill-frontmatter-invalid");
@@ -36817,10 +37231,10 @@ var CompanionLease = class {
36817
37231
 
36818
37232
  // src/codex-bootstrap.ts
36819
37233
  init_dist2();
36820
- import { createHash as createHash4 } from "node:crypto";
37234
+ import { createHash as createHash6 } from "node:crypto";
36821
37235
  import { constants as fsConstants2 } from "node:fs";
36822
- import { lstat as lstat10, open as open7, opendir as opendir3, readFile, realpath as realpath6, stat as stat2, unlink as unlink2 } from "node:fs/promises";
36823
- import path10 from "node:path";
37236
+ import { lstat as lstat10, open as open7, opendir as opendir3, readFile as readFile2, realpath as realpath6, stat as stat2, unlink as unlink2 } from "node:fs/promises";
37237
+ import path12 from "node:path";
36824
37238
  import { TextDecoder as TextDecoder3 } from "node:util";
36825
37239
  var CODEX_BOOTSTRAP_REPORT_SCHEMA = "myskills.codex-bootstrap-dry-run.v3";
36826
37240
  var CODEX_BOOTSTRAP_CONTRACT_VERSIONS = Object.freeze({
@@ -36961,7 +37375,7 @@ async function readCodexBootstrapContextFile(contextPath) {
36961
37375
  }
36962
37376
  let text;
36963
37377
  try {
36964
- text = await readFile(path10.resolve(contextPath), "utf8");
37378
+ text = await readFile2(path12.resolve(contextPath), "utf8");
36965
37379
  } catch {
36966
37380
  throw new CodexBootstrapError("BOOTSTRAP_CONTEXT_INVALID", "The work context file could not be read.");
36967
37381
  }
@@ -37211,14 +37625,14 @@ async function normalizePaths(input2) {
37211
37625
  if (sourceRoots.length === 0) {
37212
37626
  throw new CodexBootstrapError("BOOTSTRAP_SOURCE_ROOT_REQUIRED", "At least one typed work or shared source root is required.");
37213
37627
  }
37214
- const liveSkillsRoot = path10.resolve(input2.liveSkillsRoot);
37628
+ const liveSkillsRoot = path12.resolve(input2.liveSkillsRoot);
37215
37629
  const realLiveRoot = await existingDirectoryRealpath(liveSkillsRoot, "BOOTSTRAP_ROOT_INVALID");
37216
37630
  const normalizedSourceRoots = [];
37217
37631
  for (const source2 of sourceRoots) {
37218
37632
  if (!SOURCE_TYPES.includes(source2.type) || !isAbsolutePath(source2.root)) {
37219
37633
  throw new CodexBootstrapError("BOOTSTRAP_SOURCE_ROOT_INVALID", "Every source root must be an absolute, typed work or shared directory.");
37220
37634
  }
37221
- const root = path10.resolve(source2.root);
37635
+ const root = path12.resolve(source2.root);
37222
37636
  const realRoot = await existingDirectoryRealpath(root, "BOOTSTRAP_SOURCE_ROOT_INVALID");
37223
37637
  if (pathsOverlap2(realRoot, realLiveRoot) || normalizedSourceRoots.some((existing) => pathsOverlap2(existing.realRoot, realRoot))) {
37224
37638
  throw new CodexBootstrapError("BOOTSTRAP_ROOT_OVERLAP", "Source and target roots must be separate trust compartments.");
@@ -37226,8 +37640,8 @@ async function normalizePaths(input2) {
37226
37640
  normalizedSourceRoots.push({ type: source2.type, root, realRoot });
37227
37641
  }
37228
37642
  const requestedReportPath = await resolveReportPath(input2);
37229
- const reportParent = await secureReportParent(path10.dirname(requestedReportPath));
37230
- const reportPath = path10.join(reportParent, path10.basename(requestedReportPath));
37643
+ const reportParent = await secureReportParent(path12.dirname(requestedReportPath));
37644
+ const reportPath = path12.join(reportParent, path12.basename(requestedReportPath));
37231
37645
  if (isContained(realLiveRoot, reportParent) || normalizedSourceRoots.some((source2) => isContained(source2.realRoot, reportParent))) {
37232
37646
  throw new CodexBootstrapError("BOOTSTRAP_OUTPUT_UNSAFE", "The report location must be outside source and target roots.");
37233
37647
  }
@@ -37267,7 +37681,7 @@ function rawSourceRoots(input2) {
37267
37681
  if (input2.sharedSourceRoot !== void 0) roots.push({ type: "shared", root: input2.sharedSourceRoot });
37268
37682
  const unique = /* @__PURE__ */ new Map();
37269
37683
  for (const source2 of roots) {
37270
- const normalizedRoot = typeof source2.root === "string" ? path10.resolve(source2.root) : String(source2.root);
37684
+ const normalizedRoot = typeof source2.root === "string" ? path12.resolve(source2.root) : String(source2.root);
37271
37685
  unique.set(`${String(source2.type)}\0${normalizedRoot}`, source2);
37272
37686
  }
37273
37687
  return [...unique.values()];
@@ -37277,7 +37691,7 @@ async function resolveReportPath(input2) {
37277
37691
  if (!isAbsolutePath(requested)) {
37278
37692
  throw new CodexBootstrapError("BOOTSTRAP_OUTPUT_REQUIRED", "An absolute report path is required.");
37279
37693
  }
37280
- const absolute2 = path10.resolve(requested);
37694
+ const absolute2 = path12.resolve(requested);
37281
37695
  let requestedStat;
37282
37696
  try {
37283
37697
  requestedStat = await lstat10(absolute2);
@@ -37287,14 +37701,14 @@ async function resolveReportPath(input2) {
37287
37701
  if (requestedStat?.isSymbolicLink()) {
37288
37702
  throw new CodexBootstrapError("BOOTSTRAP_OUTPUT_UNSAFE", "The report location must not be a symlink.");
37289
37703
  }
37290
- if (requestedStat?.isDirectory() || requested.endsWith(path10.sep)) return path10.join(absolute2, "dry-run-report.json");
37704
+ if (requestedStat?.isDirectory() || requested.endsWith(path12.sep)) return path12.join(absolute2, "dry-run-report.json");
37291
37705
  if (requestedStat && !requestedStat.isFile()) {
37292
37706
  throw new CodexBootstrapError("BOOTSTRAP_OUTPUT_INVALID", "The report location must be a regular file.");
37293
37707
  }
37294
37708
  return absolute2;
37295
37709
  }
37296
37710
  async function secureReportParent(parentPath) {
37297
- const lexicalParent = path10.resolve(parentPath);
37711
+ const lexicalParent = path12.resolve(parentPath);
37298
37712
  const realParent = await existingDirectoryRealpath(lexicalParent, "BOOTSTRAP_OUTPUT_INVALID");
37299
37713
  let parentStats;
37300
37714
  try {
@@ -37335,13 +37749,13 @@ async function selectSources(paths, selectors, exclusions) {
37335
37749
  const roots = paths.sourceRoots.filter((source2) => selector.sourceType === void 0 || source2.type === selector.sourceType);
37336
37750
  const matches = [];
37337
37751
  for (const source2 of roots) {
37338
- const sourceDir = path10.join(source2.realRoot, selector.slug);
37752
+ const sourceDir = path12.join(source2.realRoot, selector.slug);
37339
37753
  try {
37340
37754
  const entry = await lstat10(sourceDir);
37341
37755
  if (entry.isSymbolicLink() || !entry.isDirectory()) continue;
37342
37756
  const realSourceDir = await realpath6(sourceDir);
37343
37757
  if (!isContained(source2.realRoot, realSourceDir)) throw new Error("source path escape");
37344
- const liveDir = path10.join(paths.realLiveRoot, selector.slug);
37758
+ const liveDir = path12.join(paths.realLiveRoot, selector.slug);
37345
37759
  matches.push({
37346
37760
  slug: selector.slug,
37347
37761
  sourceType: source2.type,
@@ -37572,8 +37986,8 @@ function safeFinding(finding) {
37572
37986
  return { category: finding.category, severity: finding.severity, ...finding.path ? { path: finding.path } : {} };
37573
37987
  }
37574
37988
  async function captureTargetAbsence(targetPath, boundaryRoot) {
37575
- const absoluteTargetPath = path10.resolve(targetPath);
37576
- const parentPath = path10.dirname(absoluteTargetPath);
37989
+ const absoluteTargetPath = path12.resolve(targetPath);
37990
+ const parentPath = path12.dirname(absoluteTargetPath);
37577
37991
  const parentStats = await lstat10(parentPath, { bigint: true });
37578
37992
  if (parentStats.isSymbolicLink() || !parentStats.isDirectory()) throw new Error("target absence parent is not regular");
37579
37993
  const parentRealPath = await realpath6(parentPath);
@@ -37584,7 +37998,7 @@ async function captureTargetAbsence(targetPath, boundaryRoot) {
37584
37998
  if (nodeErrorCode(error62) === "ENOENT") {
37585
37999
  return {
37586
38000
  targetPath: absoluteTargetPath,
37587
- boundaryRoot: path10.resolve(boundaryRoot),
38001
+ boundaryRoot: path12.resolve(boundaryRoot),
37588
38002
  parentPath,
37589
38003
  parentRealPath,
37590
38004
  parentStats
@@ -37620,8 +38034,8 @@ async function readBootstrapSnapshot(rootPath, boundaryRoot, testHooks) {
37620
38034
  if (typeof NO_FOLLOW_FLAG !== "number" || NO_FOLLOW_FLAG === 0 || typeof DIRECTORY_FLAG !== "number" || DIRECTORY_FLAG === 0) {
37621
38035
  throw new Error("secure filesystem flags unavailable");
37622
38036
  }
37623
- const absoluteRoot = path10.resolve(rootPath);
37624
- const absoluteBoundaryRoot = path10.resolve(boundaryRoot);
38037
+ const absoluteRoot = path12.resolve(rootPath);
38038
+ const absoluteBoundaryRoot = path12.resolve(boundaryRoot);
37625
38039
  const state = { directories: [], files: [], identities: [], entries: 0, totalBytes: 0 };
37626
38040
  await readBootstrapDirectory(absoluteRoot, absoluteBoundaryRoot, "", 0, state, testHooks);
37627
38041
  if (!state.rootPath || !state.rootRealPath || !state.rootStats || state.directories.length === 0 || state.files.length !== state.identities.length) {
@@ -37670,7 +38084,7 @@ async function readBootstrapDirectory(directoryPath, boundaryRoot, relativePrefi
37670
38084
  entryNames: entries.map((entry) => entry.name)
37671
38085
  });
37672
38086
  for (const entry of entries) {
37673
- const entryPath = path10.join(directoryPath, entry.name);
38087
+ const entryPath = path12.join(directoryPath, entry.name);
37674
38088
  const relativePath = relativePrefix ? `${relativePrefix}/${entry.name}` : entry.name;
37675
38089
  if (entry.isSymbolicLink()) throw new Error("snapshot symlink is not allowed");
37676
38090
  if (isSensitiveSnapshotPath(relativePath)) throw new Error("snapshot sensitive path is not allowed");
@@ -37819,7 +38233,7 @@ function snapshotToPackageFiles(snapshot) {
37819
38233
  return Object.freeze(snapshot.files.map((file2) => Object.freeze({ path: file2.path, content: file2.content })));
37820
38234
  }
37821
38235
  function snapshotArtifactIdentity(snapshot) {
37822
- const hash3 = createHash4("sha256");
38236
+ const hash3 = createHash6("sha256");
37823
38237
  for (const file2 of snapshot.files) {
37824
38238
  const pathBytes = Buffer.from(file2.path, "utf8");
37825
38239
  const contentBytes = Buffer.from(file2.content, "utf8");
@@ -37988,7 +38402,7 @@ function compareOrdinal2(left, right) {
37988
38402
  return left === right ? 0 : left < right ? -1 : 1;
37989
38403
  }
37990
38404
  function sha256(value) {
37991
- return createHash4("sha256").update(value, "utf8").digest("hex");
38405
+ return createHash6("sha256").update(value, "utf8").digest("hex");
37992
38406
  }
37993
38407
  function normalizeTimestamp(value) {
37994
38408
  const timestamp = value ?? (/* @__PURE__ */ new Date()).toISOString();
@@ -38074,7 +38488,7 @@ async function verifyReportPathAfterWrite(paths, reportHandle, parentBefore, ope
38074
38488
  async function cleanupReportDestination(reportPath, openedIdentity) {
38075
38489
  if (!openedIdentity) return;
38076
38490
  try {
38077
- const parentPath = path10.dirname(reportPath);
38491
+ const parentPath = path12.dirname(reportPath);
38078
38492
  const parentReal = await realpath6(parentPath);
38079
38493
  const reportReal = await realpath6(reportPath);
38080
38494
  if (parentReal !== parentPath || reportReal !== reportPath) return;
@@ -38084,7 +38498,7 @@ async function cleanupReportDestination(reportPath, openedIdentity) {
38084
38498
  }
38085
38499
  }
38086
38500
  function isAbsolutePath(value) {
38087
- return typeof value === "string" && value.length > 0 && path10.isAbsolute(value) && !value.includes("\0");
38501
+ return typeof value === "string" && value.length > 0 && path12.isAbsolute(value) && !value.includes("\0");
38088
38502
  }
38089
38503
  function isSensitiveSnapshotPath(relativePath) {
38090
38504
  const segments = relativePath.split("/");
@@ -38097,8 +38511,8 @@ function isRecord6(value) {
38097
38511
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
38098
38512
  }
38099
38513
  function isContained(root, target) {
38100
- const relative = path10.relative(path10.resolve(root), path10.resolve(target));
38101
- return relative === "" || !relative.startsWith("..") && !path10.isAbsolute(relative);
38514
+ const relative = path12.relative(path12.resolve(root), path12.resolve(target));
38515
+ return relative === "" || !relative.startsWith("..") && !path12.isAbsolute(relative);
38102
38516
  }
38103
38517
  function pathsOverlap2(left, right) {
38104
38518
  return isContained(left, right) || isContained(right, left);
@@ -38111,7 +38525,7 @@ function nodeErrorCode(error62) {
38111
38525
  init_dist2();
38112
38526
  init_install_filesystem();
38113
38527
  import { lstat as lstat11, realpath as realpath7 } from "node:fs/promises";
38114
- import path11 from "node:path";
38528
+ import path13 from "node:path";
38115
38529
  var DEFAULT_VERSION = "0.1.0";
38116
38530
  var DEFAULT_LICENSE = "UNLICENSED";
38117
38531
  var DEFAULT_SUMMARY = "Describe what this skill does.";
@@ -38138,11 +38552,11 @@ async function initSkillPackage(options2) {
38138
38552
  ` },
38139
38553
  { path: "SKILL.md", content: skillDocument(manifest.name, manifest.summary) }
38140
38554
  ];
38141
- const requestedOutput = path11.resolve(options2.output ?? path11.join(process.cwd(), options2.name));
38555
+ const requestedOutput = path13.resolve(options2.output ?? path13.join(process.cwd(), options2.name));
38142
38556
  if (CONTROL_CHARACTER_PATTERN3.test(requestedOutput)) {
38143
38557
  throw new SkillInitInputError("Output path must not contain control characters.");
38144
38558
  }
38145
- const requestedParent = path11.dirname(requestedOutput);
38559
+ const requestedParent = path13.dirname(requestedOutput);
38146
38560
  try {
38147
38561
  await assertRegularDirectory(requestedParent);
38148
38562
  } catch {
@@ -38155,7 +38569,7 @@ async function initSkillPackage(options2) {
38155
38569
  } catch {
38156
38570
  throw new SkillInitDestinationError(`Output parent must be an existing regular directory: ${requestedParent}.`);
38157
38571
  }
38158
- const outputPath = path11.join(parent, path11.basename(requestedOutput));
38572
+ const outputPath = path13.join(parent, path13.basename(requestedOutput));
38159
38573
  let destinationExists = false;
38160
38574
  try {
38161
38575
  await lstat11(outputPath);
@@ -38224,10 +38638,10 @@ function isNonBlankText(value) {
38224
38638
  // src/author-package.ts
38225
38639
  init_dist2();
38226
38640
  init_install_filesystem();
38227
- import { createHash as createHash5 } from "node:crypto";
38641
+ import { createHash as createHash7 } from "node:crypto";
38228
38642
  import { constants as constants4 } from "node:fs";
38229
38643
  import { lstat as lstat12, open as open8, realpath as realpath8 } from "node:fs/promises";
38230
- import path12 from "node:path";
38644
+ import path14 from "node:path";
38231
38645
  var SkillPackageDestinationError = class extends Error {
38232
38646
  constructor(message) {
38233
38647
  super(message);
@@ -38236,14 +38650,14 @@ var SkillPackageDestinationError = class extends Error {
38236
38650
  };
38237
38651
  async function packageSkill(options2, fault) {
38238
38652
  if (process.platform !== "darwin" && process.platform !== "linux") throw new Error("Local skill packaging requires macOS or Linux.");
38239
- const inputPath = await systemAliasPath(path12.resolve(options2.path));
38240
- const outputPath = await systemAliasPath(path12.resolve(options2.output));
38653
+ const inputPath = await systemAliasPath(path14.resolve(options2.path));
38654
+ const outputPath = await systemAliasPath(path14.resolve(options2.output));
38241
38655
  if (/[\u0000-\u001f\u007f-\u009f]/u.test(inputPath + outputPath)) throw new Error("Package paths must not contain control characters.");
38242
- if (path12.extname(outputPath).toLowerCase() !== ".zip") throw new SkillPackageDestinationError("Output must name a .zip file.");
38656
+ if (path14.extname(outputPath).toLowerCase() !== ".zip") throw new SkillPackageDestinationError("Output must name a .zip file.");
38243
38657
  const source2 = await lstat12(inputPath, { bigint: true });
38244
38658
  if (!source2.isDirectory() || source2.isSymbolicLink()) throw new Error("Package input must be a regular directory.");
38245
38659
  const sourcePath = await realpath8(inputPath);
38246
- const parentPath = path12.dirname(outputPath);
38660
+ const parentPath = path14.dirname(outputPath);
38247
38661
  assertOutsideSource(sourcePath, parentPath);
38248
38662
  const parent = await openDirectoryWithoutSymlinks(parentPath);
38249
38663
  try {
@@ -38255,7 +38669,7 @@ async function packageSkill(options2, fault) {
38255
38669
  await fault?.("checked");
38256
38670
  assertIdentity(source2, await lstat12(inputPath, { bigint: true }));
38257
38671
  await assertDestinationParent(parentPath, parent, parentIdentity, sourcePath);
38258
- const destination2 = process.platform === "linux" ? `/proc/self/fd/${parent.fd}/${path12.basename(outputPath)}` : outputPath;
38672
+ const destination2 = process.platform === "linux" ? `/proc/self/fd/${parent.fd}/${path14.basename(outputPath)}` : outputPath;
38259
38673
  const noFollow = process.platform === "darwin" ? 536870912 : constants4.O_NOFOLLOW;
38260
38674
  let output2;
38261
38675
  try {
@@ -38279,7 +38693,7 @@ async function packageSkill(options2, fault) {
38279
38693
  }
38280
38694
  return {
38281
38695
  output: outputPath,
38282
- sha256: createHash5("sha256").update(bytes2).digest("hex"),
38696
+ sha256: createHash7("sha256").update(bytes2).digest("hex"),
38283
38697
  size: bytes2.byteLength,
38284
38698
  manifest: snapshot.manifest,
38285
38699
  scan: snapshot.scan
@@ -38289,8 +38703,8 @@ async function packageSkill(options2, fault) {
38289
38703
  }
38290
38704
  }
38291
38705
  function assertOutsideSource(sourcePath, directory) {
38292
- const relative = path12.relative(sourcePath, directory);
38293
- if (relative === "" || !relative.startsWith(`..${path12.sep}`) && relative !== ".." && !path12.isAbsolute(relative)) {
38706
+ const relative = path14.relative(sourcePath, directory);
38707
+ if (relative === "" || !relative.startsWith(`..${path14.sep}`) && relative !== ".." && !path14.isAbsolute(relative)) {
38294
38708
  throw new SkillPackageDestinationError("Output parent must be outside the source package directory.");
38295
38709
  }
38296
38710
  }
@@ -38329,13 +38743,13 @@ async function systemAliasPath(requested) {
38329
38743
  if (!alias) return requested;
38330
38744
  const resolved = await realpath8(alias);
38331
38745
  if (resolved !== `/private${alias}`) throw new Error("Package system path alias has an unexpected destination.");
38332
- return path12.join(resolved, path12.relative(alias, requested));
38746
+ return path14.join(resolved, path14.relative(alias, requested));
38333
38747
  }
38334
38748
 
38335
38749
  // src/cli.ts
38336
38750
  var DEFAULT_API_URL = "http://localhost:3001";
38337
38751
  var SCOPE_TARGET_LIST_LIMIT = 500;
38338
- var CLI_VERSION = "0.1.0-beta.19";
38752
+ var CLI_VERSION = "0.1.0-beta.20";
38339
38753
  var CLI_VISIBILITY_SCOPES = ["public", "authenticated", "organization", "team", "private", "explicit-users"];
38340
38754
  var LOGIN_AUTH_METHODS = ["password", "api-key", "browser"];
38341
38755
  var OBSERVED_IDENTIFIER_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
@@ -38374,8 +38788,7 @@ var CODEX_OBSERVATION_OPTIONS = /* @__PURE__ */ new Set([
38374
38788
  async function runCli(argv, runtime) {
38375
38789
  let parsed;
38376
38790
  let namespace;
38377
- const enrollmentDirectory = runtime.workspaceEnrollmentStateDirectory ?? workspaceEnrollmentDirectory(runtime.env);
38378
- const legacyEnrollmentDirectory = runtime.workspaceEnrollmentStateDirectory ? void 0 : legacyWorkspaceEnrollmentDirectory(runtime.env);
38791
+ const enrollmentEnv = runtime.env;
38379
38792
  try {
38380
38793
  const selected = selectConfigurationProfile(argv, runtime.env);
38381
38794
  parsed = parseArgs(selected.argv);
@@ -38400,15 +38813,15 @@ async function runCli(argv, runtime) {
38400
38813
  if (parsed.options.workspace && parsed.options.dir) throw new CliError("Choose --workspace or --dir, not both.", 2);
38401
38814
  const workspace = optionalStringOption(parsed, "workspace");
38402
38815
  if (workspace) {
38403
- if (!path15.isAbsolute(workspace)) throw new CliError("Workspace must be an absolute directory.", 2);
38816
+ if (!path17.isAbsolute(workspace)) throw new CliError("Workspace must be an absolute directory.", 2);
38404
38817
  if (parsed.options.platform && parsed.options.platform !== "codex") throw new CliError("Workspace installation supports the Codex platform.", 2);
38405
38818
  await assertRegularDirectory(workspace);
38406
38819
  const canonicalWorkspace = await realpath11(workspace);
38407
- if (canonicalWorkspace === os5.homedir() || [".codex", ".agents"].some((directory) => {
38408
- const relative = path15.relative(path15.join(os5.homedir(), directory), canonicalWorkspace);
38409
- return relative === "" || !relative.startsWith("..") && !path15.isAbsolute(relative);
38820
+ if (canonicalWorkspace === os7.homedir() || [".codex", ".agents"].some((directory) => {
38821
+ const relative = path17.relative(path17.join(os7.homedir(), directory), canonicalWorkspace);
38822
+ return relative === "" || !relative.startsWith("..") && !path17.isAbsolute(relative);
38410
38823
  })) throw new CliError("Choose a project workspace, not global configuration.", 2);
38411
- await ensureSafeDirectory(canonicalWorkspace, path15.join(canonicalWorkspace, ".agents", "skills"));
38824
+ await ensureSafeDirectory(canonicalWorkspace, path17.join(canonicalWorkspace, ".agents", "skills"));
38412
38825
  parsed.options.workspace = canonicalWorkspace;
38413
38826
  }
38414
38827
  const root = installRoot(parsed, runtime);
@@ -38419,11 +38832,15 @@ async function runCli(argv, runtime) {
38419
38832
  await lstat14(workspaceBindingPath(canonicalRoot));
38420
38833
  throw new CliError("This installation root belongs to an enrolled Codex workspace. Use --workspace for workspace mutations.", 2);
38421
38834
  } catch (error62) {
38422
- if (!isNodeError(error62) || error62.code !== "ENOENT") throw error62;
38835
+ if (!isNodeError2(error62) || error62.code !== "ENOENT") throw error62;
38423
38836
  }
38424
38837
  }
38425
38838
  const managedMutation = parsed.command === "architecture-artifacts" || parsed.command === "codex" && parsed.args[0] === "enroll" || ["install", "update", "rollback", "companion"].includes(parsed.command);
38426
- if (workspace && managedMutation) return withWorkspaceEnrollment(String(parsed.options.workspace), enrollmentDirectory, parsed.command === "codex" && parsed.args[0] === "enroll", () => dispatchCli(parsed, runtime), { legacyDirectory: legacyEnrollmentDirectory, onAuthorityWait: runtime.workspaceEnrollmentWait });
38839
+ if (workspace && managedMutation) {
38840
+ const enrollmentDirectory = runtime.workspaceEnrollmentStateDirectory ?? workspaceEnrollmentDirectory(enrollmentEnv);
38841
+ const legacyEnrollmentDirectory = runtime.workspaceEnrollmentStateDirectory ? void 0 : legacyWorkspaceEnrollmentDirectory(enrollmentEnv);
38842
+ return withWorkspaceEnrollment(String(parsed.options.workspace), enrollmentDirectory, parsed.command === "codex" && parsed.args[0] === "enroll", () => dispatchCli(parsed, runtime), { legacyDirectory: legacyEnrollmentDirectory, onAuthorityWait: runtime.workspaceEnrollmentWait });
38843
+ }
38427
38844
  return dispatchCli(parsed, runtime);
38428
38845
  });
38429
38846
  }
@@ -38599,9 +39016,9 @@ function parityCommandContext(parsed, runtime) {
38599
39016
  },
38600
39017
  async writeOutput(outputPath, contents) {
38601
39018
  try {
38602
- await writeFile(path15.resolve(outputPath), contents, { mode: 384, flag: "wx" });
39019
+ await writeFile2(path17.resolve(outputPath), contents, { mode: 384, flag: "wx" });
38603
39020
  } catch (error62) {
38604
- if (isNodeError(error62) && error62.code === "EEXIST") throw new CliError("The output path already exists. Choose a new file; existing files are not replaced.", 1, "OUTPUT_EXISTS");
39021
+ if (isNodeError2(error62) && error62.code === "EEXIST") throw new CliError("The output path already exists. Choose a new file; existing files are not replaced.", 1, "OUTPUT_EXISTS");
38605
39022
  throw error62;
38606
39023
  }
38607
39024
  }
@@ -38800,7 +39217,7 @@ async function initCommand(parsed, runtime) {
38800
39217
  }
38801
39218
  const quotedPath = displayCliPath(result.outputPath);
38802
39219
  const next = {
38803
- edit: displayCliPath(path15.join(result.outputPath, "SKILL.md")),
39220
+ edit: displayCliPath(path17.join(result.outputPath, "SKILL.md")),
38804
39221
  validate: `myskills validate --path ${quotedPath}`,
38805
39222
  scan: `myskills scan --path ${quotedPath}`,
38806
39223
  submit: `myskills submit --path ${quotedPath}`
@@ -38936,9 +39353,9 @@ async function loginCommand(parsed, runtime) {
38936
39353
  const method = await loginAuthMethod(parsed, runtime);
38937
39354
  if (method === "browser") {
38938
39355
  try {
38939
- await browserDeviceLogin(apiUrl, optionalStringOption(parsed, "scopes")?.split(",").map((scope) => scope.trim()), runtime);
39356
+ await browserDeviceLogin(apiUrl, optionalStringOption(parsed, "scopes")?.split(",").map((scope) => scope.trim()), runtime, parsed.options["no-resume"] === true);
38940
39357
  } catch (error62) {
38941
- throw new CliError(error62 instanceof Error ? error62.message : "Browser login failed.", 1);
39358
+ throw new CliError(error62 instanceof DeviceLoginError ? error62.message : "Browser login failed.", 1, error62 instanceof DeviceLoginError ? error62.code : "DEVICE_LOGIN_FAILED");
38942
39359
  }
38943
39360
  return 0;
38944
39361
  }
@@ -38990,6 +39407,39 @@ async function completeMfaLogin(loginResponse, parsed, runtime) {
38990
39407
  return authSessionFromResponse(verifyResponse);
38991
39408
  }
38992
39409
  async function logoutCommand(parsed, runtime) {
39410
+ const apiUrl = apiBaseUrl(parsed, runtime);
39411
+ if (runtime.deviceLoginStore) {
39412
+ try {
39413
+ return await runtime.deviceLoginStore.withLock(apiUrl, async () => {
39414
+ let pending = null;
39415
+ let cleanupFailed = false;
39416
+ try {
39417
+ pending = await runtime.deviceLoginStore.get(apiUrl).catch((error62) => {
39418
+ if (error62 instanceof DeviceLoginError && error62.code === "DEVICE_LOGIN_STATE_INVALID") return true;
39419
+ throw error62;
39420
+ });
39421
+ await runtime.deviceLoginStore.delete(apiUrl);
39422
+ } catch {
39423
+ cleanupFailed = true;
39424
+ }
39425
+ let result;
39426
+ try {
39427
+ result = await logoutCredential(parsed, runtime, pending !== null);
39428
+ } catch (error62) {
39429
+ if (cleanupFailed) throw new CliError("Credential logout was attempted, but pending browser login cleanup could not be confirmed. Restore OS keyring access and retry logout; check account settings for remote revocation.", 1, "DEVICE_LOGIN_CLEANUP_FAILED");
39430
+ throw error62;
39431
+ }
39432
+ if (cleanupFailed) throw new CliError("Credential logout completed, but pending browser login cleanup could not be confirmed. Restore OS keyring access and retry logout before resuming browser login.", 1, "DEVICE_LOGIN_CLEANUP_FAILED");
39433
+ return result;
39434
+ });
39435
+ } catch (error62) {
39436
+ if (error62 instanceof DeviceLoginError) throw new CliError(error62.message, 1, error62.code);
39437
+ throw error62;
39438
+ }
39439
+ }
39440
+ return logoutCredential(parsed, runtime, false);
39441
+ }
39442
+ async function logoutCredential(parsed, runtime, removedPending) {
38993
39443
  const apiUrl = apiBaseUrl(parsed, runtime);
38994
39444
  let resolved;
38995
39445
  try {
@@ -39005,6 +39455,10 @@ async function logoutCommand(parsed, runtime) {
39005
39455
  throw new CliError("Stored credentials were unreadable. Local cleanup succeeded, but remote revocation could not be confirmed. Revoke the session or API token through the account settings.", 1, "LOGOUT_REMOTE_UNCONFIRMED");
39006
39456
  }
39007
39457
  if (!resolved) {
39458
+ if (removedPending) {
39459
+ runtime.io.stdout("pending browser login removed local-only");
39460
+ return 0;
39461
+ }
39008
39462
  throw new CliError("Not logged in. Run myskills login, set MYSKILLS_TOKEN, or pass --token.", 1);
39009
39463
  }
39010
39464
  if (resolved.source === "store" && resolved.stored.kind === "api") {
@@ -39299,17 +39753,17 @@ async function reviewCommand(parsed, runtime) {
39299
39753
  }
39300
39754
  const outputPath = optionalStringOption(parsed, "output");
39301
39755
  if (outputPath) {
39302
- await mkdir4(path15.dirname(path15.resolve(outputPath)), { recursive: true });
39303
- await writeFile(path15.resolve(outputPath), response.text, { encoding: "utf8", mode: 384 });
39756
+ await mkdir5(path17.dirname(path17.resolve(outputPath)), { recursive: true });
39757
+ await writeFile2(path17.resolve(outputPath), response.text, { encoding: "utf8", mode: 384 });
39304
39758
  }
39305
39759
  if (parsed.options.json) {
39306
39760
  runtime.io.stdout(JSON.stringify({
39307
39761
  artifactSha256,
39308
- ...outputPath ? { output: path15.resolve(outputPath) } : {},
39762
+ ...outputPath ? { output: path17.resolve(outputPath) } : {},
39309
39763
  payload: parseJsonResponse(`/v1/review/submissions/${submissionId}/bundle`, apiBaseUrl(parsed, runtime), response.text)
39310
39764
  }, null, 2));
39311
39765
  } else {
39312
- runtime.io.stdout([`artifactSha256=${artifactSha256}`, ...outputPath ? [`output=${path15.resolve(outputPath)}`] : []].map((field) => terminalSafeText(field)).join(" "));
39766
+ runtime.io.stdout([`artifactSha256=${artifactSha256}`, ...outputPath ? [`output=${path17.resolve(outputPath)}`] : []].map((field) => terminalSafeText(field)).join(" "));
39313
39767
  }
39314
39768
  return 0;
39315
39769
  }
@@ -39716,7 +40170,7 @@ function assertCodexObservationOptions(parsed, healthOnly) {
39716
40170
  }
39717
40171
  function requiredCodexRoot(parsed) {
39718
40172
  const root = parsed.options.root;
39719
- if (typeof root !== "string" || !root || hasControlCharacter(root) || !path15.isAbsolute(root)) {
40173
+ if (typeof root !== "string" || !root || hasControlCharacter(root) || !path17.isAbsolute(root)) {
39720
40174
  throw new CliError("An explicit absolute --root is required; the CLI does not discover a Codex home or profile.", 2, "CODEX_TARGET_ROOT_INVALID");
39721
40175
  }
39722
40176
  return root;
@@ -39768,7 +40222,7 @@ async function readCodexAdapterContext(parsed) {
39768
40222
  }
39769
40223
  let text;
39770
40224
  try {
39771
- text = await readFile3(path15.resolve(contextPath), "utf8");
40225
+ text = await readFile4(path17.resolve(contextPath), "utf8");
39772
40226
  } catch {
39773
40227
  throw new CliError("The context JSON file could not be read.", 2, "CODEX_TARGET_CONTEXT_INVALID");
39774
40228
  }
@@ -40029,7 +40483,7 @@ async function releaseMetadataOptions(parsed) {
40029
40483
  const releaseNotesFile = optionalStringOption(parsed, "release-notes-file");
40030
40484
  const adapterContractVersion = optionalStringOption(parsed, "minimum-adapter-contract-version");
40031
40485
  const raw = {
40032
- ...releaseNotesFile ? { releaseNotes: await readFile3(path15.resolve(releaseNotesFile), "utf8") } : {},
40486
+ ...releaseNotesFile ? { releaseNotes: await readFile4(path17.resolve(releaseNotesFile), "utf8") } : {},
40033
40487
  ...optionalStringOption(parsed, "change-kind") ? { changeKind: optionalStringOption(parsed, "change-kind") } : {},
40034
40488
  ...parsed.options["requires-user-action"] === true ? { requiresUserAction: true } : {},
40035
40489
  compatibility: {
@@ -40054,7 +40508,7 @@ async function exportCommand(parsed, runtime) {
40054
40508
  const outputDir = stringOption(parsed, "output");
40055
40509
  const token = await tokenOption(parsed, runtime) ?? void 0;
40056
40510
  const bundle = await downloadVerifiedBundle({ slug, version: version2, platform }, parsed, runtime, token);
40057
- const outputRoot = path15.resolve(outputDir);
40511
+ const outputRoot = path17.resolve(outputDir);
40058
40512
  await exportPackageTree(bundle.files, outputRoot);
40059
40513
  runtime.io.stdout(terminalText`${slug}@${version2}\texported\tfiles=${bundle.files.length}\t${outputRoot}`);
40060
40514
  return 0;
@@ -40117,18 +40571,18 @@ async function verifiedLibraryReviewBundle(pathname, parsed, runtime, token) {
40117
40571
  throw new CliError("The review bundle response has no valid artifact digest. Nothing was printed or written.", 1, "ARTIFACT_HASH_MISSING");
40118
40572
  }
40119
40573
  const bytes2 = Buffer.from(response.text, "utf8");
40120
- if (createHash8("sha256").update(bytes2).digest("hex") !== artifactSha256 || expectedDigest !== void 0 && artifactSha256 !== expectedDigest) {
40574
+ if (createHash10("sha256").update(bytes2).digest("hex") !== artifactSha256 || expectedDigest !== void 0 && artifactSha256 !== expectedDigest) {
40121
40575
  throw new CliError("The review bundle does not match its artifact digest. Nothing was printed or written; do not elevate this release.", 1, "ARTIFACT_HASH_MISMATCH");
40122
40576
  }
40123
40577
  const payload = parseJsonResponse(pathname, apiBaseUrl(parsed, runtime), response.text);
40124
40578
  if (!Array.isArray(payload.files)) throw new CliError("The review bundle is not an inspectable package.", 1, "ARTIFACT_INVALID");
40125
40579
  const outputPath = optionalStringOption(parsed, "output");
40126
- const output2 = outputPath ? path15.resolve(outputPath) : null;
40580
+ const output2 = outputPath ? path17.resolve(outputPath) : null;
40127
40581
  if (output2) {
40128
40582
  try {
40129
- await writeFile(output2, bytes2, { mode: 384, flag: "wx" });
40583
+ await writeFile2(output2, bytes2, { mode: 384, flag: "wx" });
40130
40584
  } catch (error62) {
40131
- if (isNodeError(error62) && error62.code === "EEXIST") throw new CliError("The output path already exists. Choose a new file; existing files are not replaced.", 1, "OUTPUT_EXISTS");
40585
+ if (isNodeError2(error62) && error62.code === "EEXIST") throw new CliError("The output path already exists. Choose a new file; existing files are not replaced.", 1, "OUTPUT_EXISTS");
40132
40586
  throw error62;
40133
40587
  }
40134
40588
  }
@@ -40431,8 +40885,8 @@ async function rollbackCommand(parsed, runtime) {
40431
40885
  assertMatchingProvenance(existing, provenance);
40432
40886
  }
40433
40887
  const outputRoot = skillInstallPath(root, slug);
40434
- const sourceSnapshotPath = path15.resolve(previous.snapshotPath);
40435
- assertChildPath(path15.join(root, ".myskills-app", "history"), sourceSnapshotPath);
40888
+ const sourceSnapshotPath = path17.resolve(previous.snapshotPath);
40889
+ assertChildPath(path17.join(root, ".myskills-app", "history"), sourceSnapshotPath);
40436
40890
  if (!await pathExists(outputRoot) || !await pathExists(sourceSnapshotPath)) {
40437
40891
  throw new CliError(`${slug} cannot roll back because its active install or snapshot is missing.`, 1);
40438
40892
  }
@@ -40468,7 +40922,7 @@ async function rollbackCommand(parsed, runtime) {
40468
40922
  await runtime.installFault?.("prepared");
40469
40923
  await runtime.beforeInstallPromotion?.();
40470
40924
  await assertInstalledBytes(existing);
40471
- await ensureSafeDirectory(root, path15.dirname(recoverySnapshotPath));
40925
+ await ensureSafeDirectory(root, path17.dirname(recoverySnapshotPath));
40472
40926
  await rename3(outputRoot, recoverySnapshotPath);
40473
40927
  transaction2 = { ...transaction2, state: "previous-staged" };
40474
40928
  await writeInstallTransaction(root, transaction2);
@@ -40496,14 +40950,14 @@ async function rollbackCommand(parsed, runtime) {
40496
40950
  transaction2 = { ...transaction2, state: "registry-committed" };
40497
40951
  await writeInstallTransaction(root, transaction2);
40498
40952
  await runtime.installFault?.("registry-committed");
40499
- await rm3(recoverySnapshotPath, { recursive: true, force: true });
40500
- await rm3(sourceSnapshotPath, { recursive: true, force: true });
40501
- await rm3(installTransactionPath(root, transactionId), { force: true });
40953
+ await rm4(recoverySnapshotPath, { recursive: true, force: true });
40954
+ await rm4(sourceSnapshotPath, { recursive: true, force: true });
40955
+ await rm4(installTransactionPath(root, transactionId), { force: true });
40502
40956
  runtime.io.stdout(terminalText`${slug}@${previous.version}\trolled-back\tplatform=${previous.platform}\t${outputRoot}`);
40503
40957
  return 0;
40504
40958
  }
40505
40959
  function workspaceBindingPath(root) {
40506
- return path15.join(root, ".myskills-app", "codex-workspace.json");
40960
+ return path17.join(root, ".myskills-app", "codex-workspace.json");
40507
40961
  }
40508
40962
  async function readWorkspaceBinding(root) {
40509
40963
  let input2;
@@ -40575,7 +41029,7 @@ async function codexWorkspaceCommand(parsed, runtime) {
40575
41029
  await lstat14(workspaceBindingPath(root));
40576
41030
  binding = await readWorkspaceBinding(root);
40577
41031
  } catch (error62) {
40578
- if (!isNodeError(error62) || error62.code !== "ENOENT") throw error62;
41032
+ if (!isNodeError2(error62) || error62.code !== "ENOENT") throw error62;
40579
41033
  }
40580
41034
  if (binding) assertMatchingProvenance(binding, provenance);
40581
41035
  const requestedTarget = optionalStringOption(parsed, "target-id");
@@ -40594,7 +41048,7 @@ async function codexWorkspaceCommand(parsed, runtime) {
40594
41048
  profileId: parseArchitectureReference(stringOption(parsed, "profile-id"), "profile"),
40595
41049
  adapter: codexWorkspaceDescriptor,
40596
41050
  capabilities: codexWorkspaceCapabilities,
40597
- identityDigest: createHash8("sha256").update(randomUUID3()).digest("hex")
41051
+ identityDigest: createHash10("sha256").update(randomUUID3()).digest("hex")
40598
41052
  }, parsed, runtime, token)).target);
40599
41053
  }
40600
41054
  binding = { schemaVersion: 1, rootDigest: workspaceRootDigest(root), provenance, target };
@@ -40812,7 +41266,7 @@ async function storedProjectRoot(parsed) {
40812
41266
  try {
40813
41267
  return (await canonicalScopeDirectory(value, { allowBroad: true, label: "The project directory" })).path;
40814
41268
  } catch (error62) {
40815
- if (typeof value === "string" && path15.isAbsolute(value)) return path15.resolve(value);
41269
+ if (typeof value === "string" && path17.isAbsolute(value)) return path17.resolve(value);
40816
41270
  throw error62;
40817
41271
  }
40818
41272
  }
@@ -40951,7 +41405,7 @@ async function scopesEnroll(parsed, runtime) {
40951
41405
  const upgraded = record5.rootIdentity.dev === null;
40952
41406
  let backupName = null;
40953
41407
  if (upgraded) {
40954
- backupName = await backup(`workspace-scopes.root-identity.${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.${createHash8("sha256").update(snapshot.bytes).digest("hex").slice(0, 12)}.json`, snapshot.bytes);
41408
+ backupName = await backup(`workspace-scopes.root-identity.${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.${createHash10("sha256").update(snapshot.bytes).digest("hex").slice(0, 12)}.json`, snapshot.bytes);
40955
41409
  await assertScopeRootUnchanged(location.path, current.identity);
40956
41410
  record5.rootIdentity = current.identity;
40957
41411
  await write(state);
@@ -41589,7 +42043,7 @@ async function installSkillVersion(input2) {
41589
42043
  if (existing) await assertInstalledBytes(existing);
41590
42044
  else if (await pathExists(outputRoot)) throw new CliError("Installation appeared after planning.", 1);
41591
42045
  if (snapshotPath && existing) {
41592
- await ensureSafeDirectory(input2.root, path15.dirname(snapshotPath));
42046
+ await ensureSafeDirectory(input2.root, path17.dirname(snapshotPath));
41593
42047
  await rename3(outputRoot, snapshotPath);
41594
42048
  history.push({
41595
42049
  version: existing.version,
@@ -41606,7 +42060,7 @@ async function installSkillVersion(input2) {
41606
42060
  await input2.runtime.installFault?.("previous-staged");
41607
42061
  }
41608
42062
  await checkpointInstallPromotion(input2.root, input2.runtime);
41609
- await ensureSafeDirectory(input2.root, path15.dirname(outputRoot));
42063
+ await ensureSafeDirectory(input2.root, path17.dirname(outputRoot));
41610
42064
  await rename3(stageRoot, outputRoot);
41611
42065
  transaction2 = { ...transaction2, state: "installed" };
41612
42066
  await writeInstallTransaction(input2.root, transaction2);
@@ -41630,7 +42084,7 @@ async function installSkillVersion(input2) {
41630
42084
  transaction2 = { ...transaction2, state: "registry-committed" };
41631
42085
  await writeInstallTransaction(input2.root, transaction2);
41632
42086
  await input2.runtime.installFault?.("registry-committed");
41633
- await rm3(installTransactionPath(input2.root, transactionId), { force: true });
42087
+ await rm4(installTransactionPath(input2.root, transactionId), { force: true });
41634
42088
  return installed;
41635
42089
  }
41636
42090
  async function downloadVerifiedBundle(input2, parsed, runtime, token) {
@@ -41731,9 +42185,9 @@ function selectReleasePlatform(release, requestedPlatform) {
41731
42185
  function installRoot(parsed, runtime) {
41732
42186
  if (parsed.command === "codex" && !optionalStringOption(parsed, "workspace")) throw new CliError("Codex commands require an explicit --workspace <absolute-dir>.", 2);
41733
42187
  const workspace = optionalStringOption(parsed, "workspace");
41734
- if (workspace && (!path15.isAbsolute(workspace) || path15.resolve(workspace) === os5.homedir() || path15.resolve(workspace) === path15.join(os5.homedir(), ".codex"))) throw new CliError("Choose an absolute project workspace, not the home or global Codex directory.", 2);
41735
- const configured = optionalStringOption(parsed, "dir") ?? (workspace ? path15.join(workspace, ".agents", "skills") : void 0) ?? runtime.env.MYSKILLS_INSTALL_DIR ?? (runtime.env.XDG_DATA_HOME ? path15.join(runtime.env.XDG_DATA_HOME, "myskills-app", "skills") : void 0) ?? (runtime.env.HOME ? path15.join(runtime.env.HOME, ".local", "share", "myskills-app", "skills") : void 0) ?? path15.join(process.cwd(), ".myskills-app", "skills");
41736
- return path15.resolve(configured);
42188
+ if (workspace && (!path17.isAbsolute(workspace) || path17.resolve(workspace) === os7.homedir() || path17.resolve(workspace) === path17.join(os7.homedir(), ".codex"))) throw new CliError("Choose an absolute project workspace, not the home or global Codex directory.", 2);
42189
+ const configured = optionalStringOption(parsed, "dir") ?? (workspace ? path17.join(workspace, ".agents", "skills") : void 0) ?? runtime.env.MYSKILLS_INSTALL_DIR ?? (runtime.env.XDG_DATA_HOME ? path17.join(runtime.env.XDG_DATA_HOME, "myskills-app", "skills") : void 0) ?? (runtime.env.HOME ? path17.join(runtime.env.HOME, ".local", "share", "myskills-app", "skills") : void 0) ?? path17.join(process.cwd(), ".myskills-app", "skills");
42190
+ return path17.resolve(configured);
41737
42191
  }
41738
42192
  async function readInstallRegistry(root) {
41739
42193
  assertInstallRootLocked(root);
@@ -41744,7 +42198,7 @@ async function readInstallRegistryFile(root) {
41744
42198
  try {
41745
42199
  return parseInstallRegistry(await readRegularText(installRegistryPath(root)), root);
41746
42200
  } catch (error62) {
41747
- if (isNodeError(error62) && error62.code === "ENOENT") {
42201
+ if (isNodeError2(error62) && error62.code === "ENOENT") {
41748
42202
  return { version: 1, installations: {} };
41749
42203
  }
41750
42204
  throw error62;
@@ -41810,8 +42264,8 @@ function parseInstallHistory(input2, root) {
41810
42264
  if (typeof record5.version !== "string" || !parseSemanticVersion(record5.version) || typeof record5.platform !== "string" || typeof record5.snapshotPath !== "string") {
41811
42265
  return [];
41812
42266
  }
41813
- const snapshotPath = path15.resolve(record5.snapshotPath);
41814
- assertChildPath(path15.join(root, ".myskills-app", "history"), snapshotPath);
42267
+ const snapshotPath = path17.resolve(record5.snapshotPath);
42268
+ assertChildPath(path17.join(root, ".myskills-app", "history"), snapshotPath);
41815
42269
  return [{
41816
42270
  version: record5.version,
41817
42271
  platform: record5.platform,
@@ -42423,10 +42877,10 @@ async function readObservedStateFixture(inputPath) {
42423
42877
  if (hasControlCharacter(inputPath)) {
42424
42878
  throw new CliError("Observed-state fixture path contains control characters.", 2, "OBSERVED_STATE_INVALID");
42425
42879
  }
42426
- const resolvedPath = path15.resolve(inputPath);
42880
+ const resolvedPath = path17.resolve(inputPath);
42427
42881
  let text;
42428
42882
  try {
42429
- text = await readFile3(resolvedPath, "utf8");
42883
+ text = await readFile4(resolvedPath, "utf8");
42430
42884
  } catch {
42431
42885
  throw new CliError("Observed-state fixture could not be read.", 2, "OBSERVED_STATE_INVALID");
42432
42886
  }
@@ -42795,22 +43249,22 @@ function optionalRecordBoolean(record5, key) {
42795
43249
  return typeof value === "boolean" ? value : void 0;
42796
43250
  }
42797
43251
  function installRegistryPath(root) {
42798
- return path15.join(root, ".myskills-app", "installed.json");
43252
+ return path17.join(root, ".myskills-app", "installed.json");
42799
43253
  }
42800
43254
  function installTransactionsRoot(root) {
42801
- return path15.join(root, ".myskills-app", "transactions");
43255
+ return path17.join(root, ".myskills-app", "transactions");
42802
43256
  }
42803
43257
  function installTransactionPath(root, transactionId) {
42804
- return path15.join(installTransactionsRoot(root), `${transactionId}.json`);
43258
+ return path17.join(installTransactionsRoot(root), `${transactionId}.json`);
42805
43259
  }
42806
43260
  function installStagePath(root, transactionId) {
42807
- return path15.join(root, ".myskills-app", "staging", transactionId);
43261
+ return path17.join(root, ".myskills-app", "staging", transactionId);
42808
43262
  }
42809
43263
  function skillInstallPath(root, slug) {
42810
- return path15.join(root, parseInstallSlug(slug));
43264
+ return path17.join(root, parseInstallSlug(slug));
42811
43265
  }
42812
43266
  function historySnapshotPath(root, slug, version2, transactionId = randomUUID3()) {
42813
- return path15.join(root, ".myskills-app", "history", parseInstallSlug(slug), `${transactionId}-${version2}`);
43267
+ return path17.join(root, ".myskills-app", "history", parseInstallSlug(slug), `${transactionId}-${version2}`);
42814
43268
  }
42815
43269
  async function writeInstallTransaction(root, transaction2) {
42816
43270
  assertInstallRootLocked(root);
@@ -42840,33 +43294,33 @@ async function recoverInstallTransactions(root) {
42840
43294
  await assertRegularDirectory(installTransactionsRoot(root));
42841
43295
  entries = await readdir6(installTransactionsRoot(root), { withFileTypes: true });
42842
43296
  } catch (error62) {
42843
- if (isNodeError(error62) && error62.code === "ENOENT") return;
43297
+ if (isNodeError2(error62) && error62.code === "ENOENT") return;
42844
43298
  throw error62;
42845
43299
  }
42846
43300
  const files2 = entries.filter((entry) => entry.isFile() && /^[0-9a-f-]{36}\.json$/.test(entry.name)).map((entry) => entry.name).sort();
42847
43301
  if (files2.length === 0) return;
42848
43302
  const registry2 = await readInstallRegistryFile(root);
42849
43303
  for (const filename of files2) {
42850
- const journalPath2 = path15.join(installTransactionsRoot(root), filename);
43304
+ const journalPath2 = path17.join(installTransactionsRoot(root), filename);
42851
43305
  const transaction2 = parseInstallTransaction(await readRegularText(journalPath2), filename, root);
42852
43306
  const outputRoot = skillInstallPath(root, transaction2.slug);
42853
43307
  const stageRoot = installStagePath(root, transaction2.id);
42854
43308
  const snapshotPath = transaction2.previous && transaction2.snapshotCreated ? historySnapshotPath(root, transaction2.slug, transaction2.previous.version, transaction2.id) : null;
42855
- if (snapshotPath) await ensureSafeDirectory(root, path15.dirname(snapshotPath));
42856
- await ensureSafeDirectory(root, path15.dirname(stageRoot));
43309
+ if (snapshotPath) await ensureSafeDirectory(root, path17.dirname(snapshotPath));
43310
+ await ensureSafeDirectory(root, path17.dirname(stageRoot));
42857
43311
  const installed = registry2.installations[transaction2.slug];
42858
43312
  const candidateCommitted = Boolean(
42859
43313
  installed && installed.version === transaction2.targetVersion && installed.platform === transaction2.targetPlatform && installed.artifact.sha256 === transaction2.targetArtifact.sha256 && installed.contentDigest === transaction2.targetContentDigest && installed.contentDigestAlgorithm === transaction2.targetContentDigestAlgorithm && await pathExists(outputRoot) && await directoryMatchesDigest(outputRoot, transaction2.targetContentDigest, transaction2.targetContentDigestAlgorithm)
42860
43314
  );
42861
43315
  if (candidateCommitted) {
42862
- await rm3(stageRoot, { recursive: true, force: true });
43316
+ await rm4(stageRoot, { recursive: true, force: true });
42863
43317
  if (transaction2.operation === "rollback") {
42864
- if (snapshotPath) await rm3(snapshotPath, { recursive: true, force: true });
43318
+ if (snapshotPath) await rm4(snapshotPath, { recursive: true, force: true });
42865
43319
  if (transaction2.sourceSnapshotPath) {
42866
- await rm3(transaction2.sourceSnapshotPath, { recursive: true, force: true });
43320
+ await rm4(transaction2.sourceSnapshotPath, { recursive: true, force: true });
42867
43321
  }
42868
43322
  }
42869
- await rm3(journalPath2, { force: true });
43323
+ await rm4(journalPath2, { force: true });
42870
43324
  continue;
42871
43325
  }
42872
43326
  const previousAtOutput = Boolean(transaction2.previous?.contentDigest && await directoryMatchesDigest(outputRoot, transaction2.previous.contentDigest, transaction2.previous.contentDigestAlgorithm));
@@ -42881,8 +43335,8 @@ async function recoverInstallTransactions(root) {
42881
43335
  throw new CliError("Recovery snapshot does not match its verified bytes. Preserve both copies for operator recovery.", 1);
42882
43336
  }
42883
43337
  if (!previousAtOutput) {
42884
- await rm3(outputRoot, { recursive: true, force: true });
42885
- await ensureSafeDirectory(root, path15.dirname(outputRoot));
43338
+ await rm4(outputRoot, { recursive: true, force: true });
43339
+ await ensureSafeDirectory(root, path17.dirname(outputRoot));
42886
43340
  await rename3(snapshotPath, outputRoot);
42887
43341
  }
42888
43342
  } else if (transaction2.snapshotCreated) {
@@ -42890,17 +43344,17 @@ async function recoverInstallTransactions(root) {
42890
43344
  throw new CliError(`Install recovery for ${transaction2.slug} requires manual intervention; its rollback snapshot is missing.`, 1);
42891
43345
  }
42892
43346
  } else if (!transaction2.previous || transaction2.state !== "prepared") {
42893
- await rm3(outputRoot, { recursive: true, force: true });
43347
+ await rm4(outputRoot, { recursive: true, force: true });
42894
43348
  }
42895
- await rm3(stageRoot, { recursive: true, force: true });
43349
+ await rm4(stageRoot, { recursive: true, force: true });
42896
43350
  if (transaction2.previous) {
42897
43351
  registry2.installations[transaction2.slug] = transaction2.previous;
42898
43352
  } else {
42899
43353
  delete registry2.installations[transaction2.slug];
42900
43354
  }
42901
43355
  await writeInstallRegistry(root, registry2);
42902
- if (previousAtOutput && snapshotPath) await rm3(snapshotPath, { recursive: true, force: true });
42903
- await rm3(journalPath2, { force: true });
43356
+ if (previousAtOutput && snapshotPath) await rm4(snapshotPath, { recursive: true, force: true });
43357
+ await rm4(journalPath2, { force: true });
42904
43358
  }
42905
43359
  }
42906
43360
  function parseInstallTransaction(raw, filename, root) {
@@ -42933,8 +43387,8 @@ function parseInstallTransaction(raw, filename, root) {
42933
43387
  if (typeof record5.sourceSnapshotPath !== "string") {
42934
43388
  throw new CliError("Install rollback transaction is missing its source snapshot.", 1);
42935
43389
  }
42936
- sourceSnapshotPath = path15.resolve(record5.sourceSnapshotPath);
42937
- assertChildPath(path15.join(root, ".myskills-app", "history"), sourceSnapshotPath);
43390
+ sourceSnapshotPath = path17.resolve(record5.sourceSnapshotPath);
43391
+ assertChildPath(path17.join(root, ".myskills-app", "history"), sourceSnapshotPath);
42938
43392
  } else if (record5.sourceSnapshotPath !== void 0) {
42939
43393
  throw new CliError("Install transaction journal is invalid.", 1);
42940
43394
  }
@@ -42961,7 +43415,7 @@ function parseContentDigestAlgorithm(input2) {
42961
43415
  }
42962
43416
  function contentDigestForFiles(files2, algorithm) {
42963
43417
  const normalized = files2.map((file2) => ({ path: safeBundlePath(file2.path), content: file2.content })).sort((left, right) => algorithm === CONTENT_DIGEST_ALGORITHM ? left.path < right.path ? -1 : left.path > right.path ? 1 : 0 : left.path.localeCompare(right.path));
42964
- return createHash8("sha256").update(JSON.stringify(normalized)).digest("hex");
43418
+ return createHash10("sha256").update(JSON.stringify(normalized)).digest("hex");
42965
43419
  }
42966
43420
  async function readStoredPackageSnapshot(inputPath) {
42967
43421
  const files2 = await readPackageFilesFromPath(inputPath);
@@ -43014,15 +43468,15 @@ async function pathExists(filePath) {
43014
43468
  await stat3(filePath);
43015
43469
  return true;
43016
43470
  } catch (error62) {
43017
- if (isNodeError(error62) && error62.code === "ENOENT") {
43471
+ if (isNodeError2(error62) && error62.code === "ENOENT") {
43018
43472
  return false;
43019
43473
  }
43020
43474
  throw error62;
43021
43475
  }
43022
43476
  }
43023
43477
  function assertChildPath(root, target) {
43024
- const relative = path15.relative(path15.resolve(root), path15.resolve(target));
43025
- if (relative.startsWith("..") || path15.isAbsolute(relative)) {
43478
+ const relative = path17.relative(path17.resolve(root), path17.resolve(target));
43479
+ if (relative.startsWith("..") || path17.isAbsolute(relative)) {
43026
43480
  throw new CliError("Install registry contains an unsafe path.", 1);
43027
43481
  }
43028
43482
  }
@@ -43120,7 +43574,7 @@ async function apiFetch(pathname, parsed, runtime, init, artifact) {
43120
43574
  let text;
43121
43575
  try {
43122
43576
  const bytes2 = await readBoundedResponse(response, response.ok && artifact ? artifact.byteSize : MAX_PACKAGE_RESPONSE_BYTES, signal);
43123
- if (response.ok && artifact && (bytes2.length !== artifact.byteSize || createHash8("sha256").update(bytes2).digest("hex") !== artifact.sha256)) {
43577
+ if (response.ok && artifact && (bytes2.length !== artifact.byteSize || createHash10("sha256").update(bytes2).digest("hex") !== artifact.sha256)) {
43124
43578
  throw new Error("Downloaded bundle did not match release metadata.");
43125
43579
  }
43126
43580
  text = decodeResponseUtf8(bytes2);
@@ -43332,11 +43786,11 @@ async function doctorTokenStoreCheck(runtime) {
43332
43786
  }
43333
43787
  async function doctorInstallDirCheck(parsed, runtime) {
43334
43788
  const root = installRoot(parsed, runtime);
43335
- const testFile = path15.join(root, ".myskills-app", `doctor-write-test-${randomUUID3()}`);
43789
+ const testFile = path17.join(root, ".myskills-app", `doctor-write-test-${randomUUID3()}`);
43336
43790
  try {
43337
43791
  assertInstallRootLocked(root);
43338
43792
  await atomicPrivateWrite(root, testFile, "ok\n");
43339
- await rm3(testFile, { force: true });
43793
+ await rm4(testFile, { force: true });
43340
43794
  return {
43341
43795
  name: "install_dir",
43342
43796
  ok: true,
@@ -43379,7 +43833,7 @@ async function filePermissions(filePath) {
43379
43833
  try {
43380
43834
  return ((await stat3(filePath)).mode & 511).toString(8).padStart(3, "0");
43381
43835
  } catch (error62) {
43382
- if (isNodeError(error62) && error62.code === "ENOENT") {
43836
+ if (isNodeError2(error62) && error62.code === "ENOENT") {
43383
43837
  return null;
43384
43838
  }
43385
43839
  throw error62;
@@ -43605,7 +44059,7 @@ function releaseArtifact(response) {
43605
44059
  byteSize: record5.byteSize
43606
44060
  };
43607
44061
  }
43608
- function isNodeError(error62) {
44062
+ function isNodeError2(error62) {
43609
44063
  return error62 instanceof Error && "code" in error62;
43610
44064
  }
43611
44065
  function parseBundlePayload(text) {
@@ -43654,7 +44108,7 @@ function parseArgs(argv) {
43654
44108
  continue;
43655
44109
  }
43656
44110
  const key = value.slice(2);
43657
- if (key === "json" || key === "api-key" || key === "health" || key === "clear-organizations" || key === "dry-run" || key === "allow-loopback-http" || key === "upload" || key === "include-prerelease" || key === "requires-user-action" || key === "accept-user-action" || key === "allow-cloud" || key === "accept-current-root") {
44111
+ if (key === "json" || key === "api-key" || key === "no-resume" || key === "health" || key === "clear-organizations" || key === "dry-run" || key === "allow-loopback-http" || key === "upload" || key === "include-prerelease" || key === "requires-user-action" || key === "accept-user-action" || key === "allow-cloud" || key === "accept-current-root") {
43658
44112
  options2[key] = true;
43659
44113
  continue;
43660
44114
  }
@@ -43711,7 +44165,7 @@ function helpText(runtime) {
43711
44165
  " search [query] [--limit <1-100>] [--cursor <cursor>] [--api-url <url>]",
43712
44166
  " info <skill-slug> [--version <exact-version>] [--api-url <url>]",
43713
44167
  " login [--api-url <url>] [--method <password|api-key|browser>] [--email <email>]",
43714
- " login --method browser [--scopes profile:read,skills:read] (trusted browser consent)",
44168
+ " login --method browser [--scopes <comma-separated-scopes>] [--no-resume] (repeat to resume before the displayed deadline)",
43715
44169
  " login --api-key [--api-url <url>]",
43716
44170
  " logout [--api-url <url>] [--token <token>]",
43717
44171
  " whoami [--api-url <url>] [--token <token>]",
@@ -43811,11 +44265,11 @@ var LibraryCurationUnavailableError = class extends CliError {
43811
44265
 
43812
44266
  // src/config-store.ts
43813
44267
  import { chmodSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
43814
- import os6 from "node:os";
43815
- import path16 from "node:path";
44268
+ import os8 from "node:os";
44269
+ import path18 from "node:path";
43816
44270
  function createFileConfigStore(env = process.env) {
43817
44271
  const filePath = configFilePath(env);
43818
- let payload = readPayload(filePath);
44272
+ let payload = readPayload2(filePath);
43819
44273
  return {
43820
44274
  getApiUrl() {
43821
44275
  return payload.apiUrl;
@@ -43825,7 +44279,7 @@ function createFileConfigStore(env = process.env) {
43825
44279
  ...payload,
43826
44280
  apiUrl: apiUrl.replace(/\/+$/, "")
43827
44281
  };
43828
- writePayload(filePath, payload);
44282
+ writePayload2(filePath, payload);
43829
44283
  },
43830
44284
  async resetApiUrl() {
43831
44285
  payload = { version: 1 };
@@ -43835,31 +44289,31 @@ function createFileConfigStore(env = process.env) {
43835
44289
  }
43836
44290
  function configFilePath(env) {
43837
44291
  if (env.MYSKILLS_CONFIG_FILE) {
43838
- return path16.resolve(env.MYSKILLS_CONFIG_FILE);
44292
+ return path18.resolve(env.MYSKILLS_CONFIG_FILE);
43839
44293
  }
43840
44294
  if (env.MYSKILLS_CONFIG_DIR) {
43841
- return path16.join(path16.resolve(env.MYSKILLS_CONFIG_DIR), "config.json");
44295
+ return path18.join(path18.resolve(env.MYSKILLS_CONFIG_DIR), "config.json");
43842
44296
  }
43843
- const baseDir = env.XDG_CONFIG_HOME ? path16.join(env.XDG_CONFIG_HOME, "myskills-app") : path16.join(os6.homedir(), ".config", "myskills-app");
43844
- return path16.join(baseDir, "config.json");
44297
+ const baseDir = env.XDG_CONFIG_HOME ? path18.join(env.XDG_CONFIG_HOME, "myskills-app") : path18.join(os8.homedir(), ".config", "myskills-app");
44298
+ return path18.join(baseDir, "config.json");
43845
44299
  }
43846
- function readPayload(filePath) {
44300
+ function readPayload2(filePath) {
43847
44301
  try {
43848
- return parsePayload(readFileSync(filePath, "utf8"));
44302
+ return parsePayload2(readFileSync(filePath, "utf8"));
43849
44303
  } catch (error62) {
43850
- if (isNodeError2(error62) && error62.code === "ENOENT") {
44304
+ if (isNodeError3(error62) && error62.code === "ENOENT") {
43851
44305
  return { version: 1 };
43852
44306
  }
43853
44307
  throw error62;
43854
44308
  }
43855
44309
  }
43856
- function writePayload(filePath, payload) {
43857
- mkdirSync(path16.dirname(filePath), { recursive: true, mode: 448 });
44310
+ function writePayload2(filePath, payload) {
44311
+ mkdirSync(path18.dirname(filePath), { recursive: true, mode: 448 });
43858
44312
  writeFileSync(filePath, `${JSON.stringify(payload, null, 2)}
43859
44313
  `, { mode: 384 });
43860
44314
  chmodSync(filePath, 384);
43861
44315
  }
43862
- function parsePayload(raw) {
44316
+ function parsePayload2(raw) {
43863
44317
  const parsed = JSON.parse(raw);
43864
44318
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
43865
44319
  throw new Error("Config file must contain a JSON object.");
@@ -43873,198 +44327,6 @@ function parsePayload(raw) {
43873
44327
  apiUrl: typeof record5.apiUrl === "string" && record5.apiUrl ? record5.apiUrl.replace(/\/+$/, "") : void 0
43874
44328
  };
43875
44329
  }
43876
- function isNodeError2(error62) {
43877
- return error62 instanceof Error && "code" in error62;
43878
- }
43879
-
43880
- // src/token-store.ts
43881
- import { createHash as createHash9 } from "node:crypto";
43882
- import { chmod, mkdir as mkdir5, readFile as readFile4, rm as rm4, writeFile as writeFile2 } from "node:fs/promises";
43883
- import os7 from "node:os";
43884
- import path17 from "node:path";
43885
- var KEYRING_SERVICE = "ai.jarel.myskills.cli";
43886
- function createTokenStore(env = process.env, namespace) {
43887
- const fileStore = createFileTokenStore(env);
43888
- if (env.MYSKILLS_TOKEN_STORE === "file" || env.MYSKILLS_TOKEN_FILE) {
43889
- return fileStore;
43890
- }
43891
- return createKeyringTokenStore(fileStore, void 0, namespace);
43892
- }
43893
- function createFileTokenStore(env = process.env) {
43894
- const filePath = tokenFilePath(env);
43895
- return {
43896
- async get(apiUrl) {
43897
- return (await readPayload2(filePath)).tokens[normalizeApiUrl(apiUrl)] ?? null;
43898
- },
43899
- async set(apiUrl, token) {
43900
- const payload = await readPayload2(filePath);
43901
- payload.tokens[normalizeApiUrl(apiUrl)] = token;
43902
- await writePayload2(filePath, payload);
43903
- },
43904
- async delete(apiUrl) {
43905
- const payload = await readPayload2(filePath);
43906
- delete payload.tokens[normalizeApiUrl(apiUrl)];
43907
- if (Object.keys(payload.tokens).length === 0) {
43908
- await rm4(filePath, { force: true });
43909
- return;
43910
- }
43911
- await writePayload2(filePath, payload);
43912
- },
43913
- describe() {
43914
- return {
43915
- backend: "file",
43916
- filePath
43917
- };
43918
- }
43919
- };
43920
- }
43921
- function createKeyringTokenStore(fallback, backend = nativeKeyringBackend, namespace) {
43922
- const prefix = namespace === void 0 ? void 0 : `config-profile:${createHash9("sha256").update(namespace).digest("hex")}:`;
43923
- const credentialKey = (apiUrl) => prefix === void 0 ? apiUrl : `${prefix}${normalizeApiUrl(apiUrl)}`;
43924
- let usedFallback = false;
43925
- return {
43926
- async get(apiUrl) {
43927
- let raw;
43928
- try {
43929
- raw = await backend.get(credentialKey(apiUrl));
43930
- } catch {
43931
- throw new Error("Cannot read the OS keyring. Unlock or restore keyring access, or explicitly select MYSKILLS_TOKEN_STORE=file.");
43932
- }
43933
- if (raw === null) {
43934
- const token2 = await fallback.get(apiUrl);
43935
- usedFallback = token2 !== null;
43936
- return token2;
43937
- }
43938
- let token;
43939
- try {
43940
- token = parseStoredToken(JSON.parse(raw));
43941
- } catch {
43942
- token = null;
43943
- }
43944
- if (!token) {
43945
- throw new Error("The OS keyring credential has an invalid format. Remove it with myskills logout, then log in again.");
43946
- }
43947
- usedFallback = false;
43948
- return token;
43949
- },
43950
- async set(apiUrl, token) {
43951
- try {
43952
- await backend.set(credentialKey(apiUrl), JSON.stringify(token));
43953
- } catch {
43954
- throw new Error("Cannot save the token in the OS keyring. Unlock or restore keyring access, or explicitly select MYSKILLS_TOKEN_STORE=file.");
43955
- }
43956
- usedFallback = false;
43957
- try {
43958
- await fallback.delete(apiUrl);
43959
- } catch {
43960
- throw new Error("The token was saved in the OS keyring, but the older file credential could not be removed. Token storage cleanup is incomplete.");
43961
- }
43962
- },
43963
- async delete(apiUrl) {
43964
- const results = await Promise.allSettled([backend.delete(credentialKey(apiUrl)), fallback.delete(apiUrl)]);
43965
- const failed = results.flatMap((result, index) => result.status === "rejected" ? [index === 0 ? "OS keyring" : "file"] : []);
43966
- if (failed.length > 0) {
43967
- throw new Error(`Logout cleanup is incomplete: could not remove the ${failed.join(" and ")} credential. Restore storage access and retry logout.`);
43968
- }
43969
- usedFallback = false;
43970
- },
43971
- async describe() {
43972
- const fallbackInfo = await fallback.describe?.();
43973
- if (usedFallback && fallbackInfo) {
43974
- return fallbackInfo;
43975
- }
43976
- return {
43977
- backend: "keyring",
43978
- fallbackFilePath: fallbackInfo?.filePath
43979
- };
43980
- }
43981
- };
43982
- }
43983
- var nativeKeyringBackend = {
43984
- async get(apiUrl) {
43985
- const { Entry } = await import("@napi-rs/keyring");
43986
- return new Entry(KEYRING_SERVICE, keyringAccount(apiUrl)).getPassword();
43987
- },
43988
- async set(apiUrl, raw) {
43989
- const { Entry } = await import("@napi-rs/keyring");
43990
- new Entry(KEYRING_SERVICE, keyringAccount(apiUrl)).setPassword(raw);
43991
- },
43992
- async delete(apiUrl) {
43993
- const { Entry } = await import("@napi-rs/keyring");
43994
- new Entry(KEYRING_SERVICE, keyringAccount(apiUrl)).deletePassword();
43995
- }
43996
- };
43997
- function tokenFilePath(env) {
43998
- if (env.MYSKILLS_TOKEN_FILE) {
43999
- return path17.resolve(env.MYSKILLS_TOKEN_FILE);
44000
- }
44001
- if (env.MYSKILLS_CONFIG_DIR) {
44002
- return path17.join(path17.resolve(env.MYSKILLS_CONFIG_DIR), "tokens.json");
44003
- }
44004
- const baseDir = env.XDG_CONFIG_HOME ? path17.join(env.XDG_CONFIG_HOME, "myskills-app") : path17.join(os7.homedir(), ".config", "myskills-app");
44005
- return path17.join(baseDir, "tokens.json");
44006
- }
44007
- async function readPayload2(filePath) {
44008
- try {
44009
- const raw = await readFile4(filePath, "utf8");
44010
- return parsePayload2(raw);
44011
- } catch (error62) {
44012
- if (isNodeError3(error62) && error62.code === "ENOENT") {
44013
- return { version: 1, tokens: {} };
44014
- }
44015
- throw error62;
44016
- }
44017
- }
44018
- async function writePayload2(filePath, payload) {
44019
- await mkdir5(path17.dirname(filePath), { recursive: true, mode: 448 });
44020
- await writeFile2(filePath, `${JSON.stringify(payload, null, 2)}
44021
- `, { mode: 384 });
44022
- await chmod(filePath, 384);
44023
- }
44024
- function parsePayload2(raw) {
44025
- let parsed;
44026
- try {
44027
- parsed = JSON.parse(raw);
44028
- } catch {
44029
- throw new Error("Token store file contains invalid JSON. Repair or remove the file before logging in again.");
44030
- }
44031
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
44032
- throw new Error("Token store file must contain a JSON object.");
44033
- }
44034
- const record5 = parsed;
44035
- if (record5.version !== 1 || !record5.tokens || typeof record5.tokens !== "object" || Array.isArray(record5.tokens)) {
44036
- throw new Error("Token store file has an unsupported format.");
44037
- }
44038
- const tokens = {};
44039
- for (const [apiUrl, token] of Object.entries(record5.tokens)) {
44040
- const parsedToken = parseStoredToken(token);
44041
- if (parsedToken) {
44042
- tokens[normalizeApiUrl(apiUrl)] = parsedToken;
44043
- }
44044
- }
44045
- return { version: 1, tokens };
44046
- }
44047
- function parseStoredToken(input2) {
44048
- if (!input2 || typeof input2 !== "object" || Array.isArray(input2)) {
44049
- return null;
44050
- }
44051
- const record5 = input2;
44052
- if (record5.kind !== "session" && record5.kind !== "api" || typeof record5.token !== "string" || !record5.token) {
44053
- return null;
44054
- }
44055
- return {
44056
- kind: record5.kind,
44057
- token: record5.token,
44058
- email: typeof record5.email === "string" ? record5.email : void 0,
44059
- expiresAt: typeof record5.expiresAt === "string" ? record5.expiresAt : void 0
44060
- };
44061
- }
44062
- function normalizeApiUrl(apiUrl) {
44063
- return apiUrl.replace(/\/+$/, "");
44064
- }
44065
- function keyringAccount(apiUrl) {
44066
- return `api-url:${Buffer.from(normalizeApiUrl(apiUrl)).toString("base64url")}`;
44067
- }
44068
44330
  function isNodeError3(error62) {
44069
44331
  return error62 instanceof Error && "code" in error62;
44070
44332
  }
@@ -44185,7 +44447,7 @@ try {
44185
44447
  const exitCode = await runCli(process.argv.slice(2), {
44186
44448
  env: process.env,
44187
44449
  fetch: fetchImpl,
44188
- createStores: (env, namespace) => ({ configStore: createFileConfigStore(env), tokenStore: createTokenStore(env, namespace) }),
44450
+ createStores: (env, namespace) => ({ configStore: createFileConfigStore(env), tokenStore: createTokenStore(env, namespace), deviceLoginStore: createDeviceLoginStore(namespace) }),
44189
44451
  prompt,
44190
44452
  io: {
44191
44453
  stdout: (line) => console.log(line),