@promptscript/cli 1.17.0 → 1.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -4445,12 +4445,12 @@ var init_services = __esm({
4445
4445
  return rm3(...args);
4446
4446
  },
4447
4447
  lstat: async (path2) => {
4448
- const { lstat: lstat9 } = await import("node:fs/promises");
4449
- return lstat9(path2);
4448
+ const { lstat: lstat10 } = await import("node:fs/promises");
4449
+ return lstat10(path2);
4450
4450
  },
4451
4451
  realpath: async (path2) => {
4452
- const { realpath: realpath6 } = await import("node:fs/promises");
4453
- return realpath6(path2);
4452
+ const { realpath: realpath7 } = await import("node:fs/promises");
4453
+ return realpath7(path2);
4454
4454
  }
4455
4455
  };
4456
4456
  defaultPrompts = {
@@ -27444,13 +27444,7 @@ function getSkillWrites(targets) {
27444
27444
  const skillSource = resolve7(BUNDLED_SKILLS_DIR, skillName, "SKILL.md");
27445
27445
  try {
27446
27446
  const rawSkillContent = readFileSync3(skillSource, "utf-8");
27447
- let skillContent = rawSkillContent;
27448
- const hasMarker = rawSkillContent.includes("<!-- PromptScript") || rawSkillContent.includes("# promptscript-generated:");
27449
- if (!hasMarker && rawSkillContent.startsWith("---")) {
27450
- const yamlMarker = "# promptscript-generated: true";
27451
- skillContent = `---
27452
- ${yamlMarker}${rawSkillContent.slice(3)}`;
27453
- }
27447
+ const skillContent = addPromptScriptMarker(rawSkillContent);
27454
27448
  writes.push({
27455
27449
  path: `.promptscript/skills/${skillName}/SKILL.md`,
27456
27450
  content: skillContent
@@ -27458,7 +27452,14 @@ ${yamlMarker}${rawSkillContent.slice(3)}`;
27458
27452
  for (const target of targets) {
27459
27453
  const targetSkillDir = getTargetSkillDir(target, skillName);
27460
27454
  if (targetSkillDir && !writes.some((write) => write.path === targetSkillDir.path)) {
27461
- writes.push({ path: targetSkillDir.path, content: skillContent });
27455
+ const formatter = FormatterRegistry.get(target);
27456
+ let targetContent = skillContent;
27457
+ if (formatter?.transformInjectedSkillContent) {
27458
+ targetContent = addPromptScriptMarker(
27459
+ formatter.transformInjectedSkillContent(rawSkillContent)
27460
+ );
27461
+ }
27462
+ writes.push({ path: targetSkillDir.path, content: targetContent });
27462
27463
  }
27463
27464
  }
27464
27465
  } catch {
@@ -27466,6 +27467,11 @@ ${yamlMarker}${rawSkillContent.slice(3)}`;
27466
27467
  }
27467
27468
  return writes;
27468
27469
  }
27470
+ function addPromptScriptMarker(content) {
27471
+ const hasMarker = content.includes("<!-- PromptScript") || content.includes("# promptscript-generated:");
27472
+ return !hasMarker && content.startsWith("---") ? `---
27473
+ # promptscript-generated: true${content.slice(3)}` : content;
27474
+ }
27469
27475
  async function resolveConfig(options, projectInfo, aiToolsDetection, prettierConfigPath, manifest, services) {
27470
27476
  if (options.yes) {
27471
27477
  const userConfig = await loadUserConfig();
@@ -28037,13 +28043,13 @@ var require_ipv4 = __commonJS({
28037
28043
  Object.defineProperty(exports, "__esModule", { value: true });
28038
28044
  exports.Address4 = void 0;
28039
28045
  var common = __importStar(require_common());
28040
- var constants3 = __importStar(require_constants());
28046
+ var constants4 = __importStar(require_constants());
28041
28047
  var address_error_1 = require_address_error();
28042
- var isCorrect4 = common.isCorrect(constants3.BITS);
28048
+ var isCorrect4 = common.isCorrect(constants4.BITS);
28043
28049
  var Address4 = class _Address4 {
28044
28050
  constructor(address) {
28045
28051
  this.addressMinusSuffix = "";
28046
- this.groups = constants3.GROUPS;
28052
+ this.groups = constants4.GROUPS;
28047
28053
  this.parsedAddress = [];
28048
28054
  this.parsedSubnet = "";
28049
28055
  this.subnet = "/32";
@@ -28053,15 +28059,15 @@ var require_ipv4 = __commonJS({
28053
28059
  this.isInSubnet = common.isInSubnet;
28054
28060
  this.isHostInSubnet = common.isHostInSubnet;
28055
28061
  this.address = address;
28056
- const subnet = constants3.RE_SUBNET_STRING.exec(address);
28062
+ const subnet = constants4.RE_SUBNET_STRING.exec(address);
28057
28063
  if (subnet) {
28058
28064
  this.parsedSubnet = subnet[0].replace("/", "");
28059
28065
  this.subnetMask = parseInt(this.parsedSubnet, 10);
28060
28066
  this.subnet = `/${this.subnetMask}`;
28061
- if (this.subnetMask < 0 || this.subnetMask > constants3.BITS) {
28067
+ if (this.subnetMask < 0 || this.subnetMask > constants4.BITS) {
28062
28068
  throw new address_error_1.AddressError("Invalid subnet mask.");
28063
28069
  }
28064
- address = address.replace(constants3.RE_SUBNET_STRING, "");
28070
+ address = address.replace(constants4.RE_SUBNET_STRING, "");
28065
28071
  }
28066
28072
  this.addressMinusSuffix = address;
28067
28073
  this.parsedAddress = this.parse(address);
@@ -28092,7 +28098,7 @@ var require_ipv4 = __commonJS({
28092
28098
  if (groups.some((group) => /^0\d/.test(group))) {
28093
28099
  throw new address_error_1.AddressError("IPv4 addresses can't have leading zeroes.");
28094
28100
  }
28095
- if (!address.match(constants3.RE_ADDRESS)) {
28101
+ if (!address.match(constants4.RE_ADDRESS)) {
28096
28102
  throw new address_error_1.AddressError("Invalid IPv4 address.");
28097
28103
  }
28098
28104
  return groups;
@@ -28115,7 +28121,7 @@ var require_ipv4 = __commonJS({
28115
28121
  * address.subnetMask; // 24
28116
28122
  */
28117
28123
  static fromAddressAndMask(address, mask) {
28118
- const bits = common.prefixLengthFromMask(new _Address4(mask).bigInt(), constants3.BITS);
28124
+ const bits = common.prefixLengthFromMask(new _Address4(mask).bigInt(), constants4.BITS);
28119
28125
  return new _Address4(`${address}/${bits}`);
28120
28126
  }
28121
28127
  /**
@@ -28129,9 +28135,9 @@ var require_ipv4 = __commonJS({
28129
28135
  */
28130
28136
  static fromAddressAndWildcardMask(address, wildcardMask) {
28131
28137
  const wildcard = new _Address4(wildcardMask).bigInt();
28132
- const allOnes = (BigInt(1) << BigInt(constants3.BITS)) - BigInt(1);
28138
+ const allOnes = (BigInt(1) << BigInt(constants4.BITS)) - BigInt(1);
28133
28139
  const mask = wildcard ^ allOnes;
28134
- const bits = common.prefixLengthFromMask(mask, constants3.BITS);
28140
+ const bits = common.prefixLengthFromMask(mask, constants4.BITS);
28135
28141
  return new _Address4(`${address}/${bits}`);
28136
28142
  }
28137
28143
  /**
@@ -28149,7 +28155,7 @@ var require_ipv4 = __commonJS({
28149
28155
  */
28150
28156
  static fromWildcard(input2) {
28151
28157
  const groups = input2.split(".");
28152
- if (groups.length !== constants3.GROUPS) {
28158
+ if (groups.length !== constants4.GROUPS) {
28153
28159
  throw new address_error_1.AddressError("Wildcard pattern must have 4 octets");
28154
28160
  }
28155
28161
  let firstWildcard = -1;
@@ -28164,7 +28170,7 @@ var require_ipv4 = __commonJS({
28164
28170
  }
28165
28171
  const trailing = firstWildcard === -1 ? 0 : groups.length - firstWildcard;
28166
28172
  const replaced = groups.map((g) => g === "*" ? "0" : g);
28167
- const subnetBits = constants3.BITS - trailing * 8;
28173
+ const subnetBits = constants4.BITS - trailing * 8;
28168
28174
  return new _Address4(`${replaced.join(".")}/${subnetBits}`);
28169
28175
  }
28170
28176
  /**
@@ -28234,7 +28240,7 @@ var require_ipv4 = __commonJS({
28234
28240
  toGroup6() {
28235
28241
  const output = [];
28236
28242
  let i;
28237
- for (i = 0; i < constants3.GROUPS; i += 2) {
28243
+ for (i = 0; i < constants4.GROUPS; i += 2) {
28238
28244
  output.push(`${common.stringToPaddedHex(this.parsedAddress[i])}${common.stringToPaddedHex(this.parsedAddress[i + 1])}`);
28239
28245
  }
28240
28246
  return output.join(":");
@@ -28251,7 +28257,7 @@ var require_ipv4 = __commonJS({
28251
28257
  * @returns {bigint}
28252
28258
  */
28253
28259
  _startAddress() {
28254
- return BigInt(`0b${this.mask() + "0".repeat(constants3.BITS - this.subnetMask)}`);
28260
+ return BigInt(`0b${this.mask() + "0".repeat(constants4.BITS - this.subnetMask)}`);
28255
28261
  }
28256
28262
  /**
28257
28263
  * The first address in the range given by this address' subnet.
@@ -28275,7 +28281,7 @@ var require_ipv4 = __commonJS({
28275
28281
  * @returns {bigint}
28276
28282
  */
28277
28283
  _endAddress() {
28278
- return BigInt(`0b${this.mask() + "1".repeat(constants3.BITS - this.subnetMask)}`);
28284
+ return BigInt(`0b${this.mask() + "1".repeat(constants4.BITS - this.subnetMask)}`);
28279
28285
  }
28280
28286
  /**
28281
28287
  * The last address in the range given by this address' subnet
@@ -28300,7 +28306,7 @@ var require_ipv4 = __commonJS({
28300
28306
  * @returns {Address4}
28301
28307
  */
28302
28308
  subnetMaskAddress() {
28303
- return _Address4.fromBigInt(BigInt(`0b${"1".repeat(this.subnetMask)}${"0".repeat(constants3.BITS - this.subnetMask)}`));
28309
+ return _Address4.fromBigInt(BigInt(`0b${"1".repeat(this.subnetMask)}${"0".repeat(constants4.BITS - this.subnetMask)}`));
28304
28310
  }
28305
28311
  /**
28306
28312
  * The Cisco-style wildcard mask, e.g. `0.0.0.255` for a `/24`. This is
@@ -28309,7 +28315,7 @@ var require_ipv4 = __commonJS({
28309
28315
  * @returns {Address4}
28310
28316
  */
28311
28317
  wildcardMask() {
28312
- return _Address4.fromBigInt(BigInt(`0b${"0".repeat(this.subnetMask)}${"1".repeat(constants3.BITS - this.subnetMask)}`));
28318
+ return _Address4.fromBigInt(BigInt(`0b${"0".repeat(this.subnetMask)}${"1".repeat(constants4.BITS - this.subnetMask)}`));
28313
28319
  }
28314
28320
  /**
28315
28321
  * The network address in CIDR string form, e.g. `192.168.1.0/24` for
@@ -28444,7 +28450,7 @@ var require_ipv4 = __commonJS({
28444
28450
  */
28445
28451
  binaryZeroPad() {
28446
28452
  if (this._binaryZeroPad === void 0) {
28447
- this._binaryZeroPad = this.bigInt().toString(2).padStart(constants3.BITS, "0");
28453
+ this._binaryZeroPad = this.bigInt().toString(2).padStart(constants4.BITS, "0");
28448
28454
  }
28449
28455
  return this._binaryZeroPad;
28450
28456
  }
@@ -28454,7 +28460,7 @@ var require_ipv4 = __commonJS({
28454
28460
  */
28455
28461
  groupForV6() {
28456
28462
  const segments = this.parsedAddress;
28457
- return this.correctForm().replace(constants3.RE_ADDRESS, `<span class="hover-group group-v4 group-6">${segments.slice(0, 2).join(".")}</span>.<span class="hover-group group-v4 group-7">${segments.slice(2, 4).join(".")}</span>`);
28463
+ return this.correctForm().replace(constants4.RE_ADDRESS, `<span class="hover-group group-v4 group-6">${segments.slice(0, 2).join(".")}</span>.<span class="hover-group group-v4 group-7">${segments.slice(2, 4).join(".")}</span>`);
28458
28464
  }
28459
28465
  };
28460
28466
  exports.Address4 = Address4;
@@ -31282,31 +31288,31 @@ var init_config2 = __esm({
31282
31288
  });
31283
31289
 
31284
31290
  // packages/server/src/path-guard.ts
31285
- import { resolve as resolve36, relative as relative16, isAbsolute as isAbsolute16, dirname as dirname24, basename as basename18 } from "path";
31286
- import { realpath as realpath5 } from "fs/promises";
31291
+ import { resolve as resolve36, relative as relative16, isAbsolute as isAbsolute15, dirname as dirname24, basename as basename18 } from "path";
31292
+ import { realpath as realpath6 } from "fs/promises";
31287
31293
  async function resolveSafePath(workspace, requestedPath) {
31288
31294
  const decoded = decodeURIComponent(requestedPath);
31289
- if (isAbsolute16(decoded)) {
31295
+ if (isAbsolute15(decoded)) {
31290
31296
  throw new PathTraversalError(requestedPath);
31291
31297
  }
31292
31298
  const resolved = resolve36(workspace, decoded);
31293
31299
  const rel = relative16(workspace, resolved);
31294
- if (rel.startsWith("..") || isAbsolute16(rel)) {
31300
+ if (rel.startsWith("..") || isAbsolute15(rel)) {
31295
31301
  throw new PathTraversalError(requestedPath);
31296
31302
  }
31297
31303
  let realWorkspace;
31298
31304
  try {
31299
- realWorkspace = await realpath5(workspace);
31305
+ realWorkspace = await realpath6(workspace);
31300
31306
  } catch {
31301
31307
  realWorkspace = workspace;
31302
31308
  }
31303
31309
  let real;
31304
31310
  try {
31305
- real = await realpath5(resolved);
31311
+ real = await realpath6(resolved);
31306
31312
  } catch (err) {
31307
31313
  if (err instanceof Error && "code" in err && err.code === "ENOENT") {
31308
31314
  try {
31309
- const realParent = await realpath5(dirname24(resolved));
31315
+ const realParent = await realpath6(dirname24(resolved));
31310
31316
  real = resolve36(realParent, basename18(resolved));
31311
31317
  } catch {
31312
31318
  return resolved;
@@ -31316,7 +31322,7 @@ async function resolveSafePath(workspace, requestedPath) {
31316
31322
  }
31317
31323
  }
31318
31324
  const realRel = relative16(realWorkspace, real);
31319
- if (realRel.startsWith("..") || isAbsolute16(realRel)) {
31325
+ if (realRel.startsWith("..") || isAbsolute15(realRel)) {
31320
31326
  throw new PathTraversalError(requestedPath);
31321
31327
  }
31322
31328
  return resolved;
@@ -31964,7 +31970,7 @@ import { fileURLToPath as fileURLToPath4, pathToFileURL } from "url";
31964
31970
  import { dirname as dirname27 } from "path";
31965
31971
 
31966
31972
  // packages/cli/src/commands/compile.ts
31967
- import { resolve as resolve19, dirname as dirname15, isAbsolute as isAbsolute13, relative as relative13 } from "path";
31973
+ import { resolve as resolve19, dirname as dirname15, isAbsolute as isAbsolute12, relative as relative13 } from "path";
31968
31974
  import { fileURLToPath as fileURLToPath2 } from "url";
31969
31975
  import { chmod, writeFile as writeFile4, mkdir as mkdir5, readFile as readFile15 } from "fs/promises";
31970
31976
  import { existsSync as existsSync13 } from "fs";
@@ -33750,10 +33756,10 @@ var Minimatch = class {
33750
33756
  }
33751
33757
  return filtered.join("/");
33752
33758
  }).join("|");
33753
- const [open3, close] = set.length > 1 ? ["(?:", ")"] : ["", ""];
33754
- re = "^" + open3 + re + close + "$";
33759
+ const [open4, close] = set.length > 1 ? ["(?:", ")"] : ["", ""];
33760
+ re = "^" + open4 + re + close + "$";
33755
33761
  if (this.partial) {
33756
- re = "^(?:\\/|" + open3 + re.slice(1, -1) + close + ")$";
33762
+ re = "^(?:\\/|" + open4 + re.slice(1, -1) + close + ")$";
33757
33763
  }
33758
33764
  if (this.negate)
33759
33765
  re = "^(?!" + re + ").+$";
@@ -38046,8 +38052,9 @@ async function discoverNativeContent(dir) {
38046
38052
  // packages/resolver/src/vendor-manifest.ts
38047
38053
  import { createHash as createHash3 } from "crypto";
38048
38054
  import { execFile, spawn } from "child_process";
38049
- import { lstat as lstat5, readFile as readFile12, readdir as readdir4, realpath as realpath3 } from "fs/promises";
38050
- import { basename as basename10, dirname as dirname9, isAbsolute as isAbsolute8, join as join9, posix as posix2, relative as relative7, sep as sep5 } from "path";
38055
+ import { constants as constants2 } from "fs";
38056
+ import { lstat as lstat5, open as open2, readFile as readFile12, readdir as readdir4, readlink, realpath as realpath3 } from "fs/promises";
38057
+ import { basename as basename10, dirname as dirname9, join as join9, posix as posix2, relative as relative7, sep as sep5 } from "path";
38051
38058
  import { promisify } from "util";
38052
38059
  var VENDOR_MANIFEST_FILE = ".vendor-manifest.json";
38053
38060
  var VENDOR_GIT_DIR = ".promptscript-git";
@@ -38055,6 +38062,55 @@ var execFileAsync = promisify(execFile);
38055
38062
  var NULL_DEVICE = process.platform === "win32" ? "NUL" : "/dev/null";
38056
38063
  var MAX_GIT_STDERR_BYTES = 64 * 1024;
38057
38064
  var MAX_GIT_TREE_RECORD_BYTES = 1024 * 1024;
38065
+ var MAX_GIT_CONFIG_BYTES = 1024 * 1024;
38066
+ function hashGitBlob(content) {
38067
+ return createHash3("sha1").update(`blob ${content.length}\0`).update(content).digest("hex");
38068
+ }
38069
+ async function readBoundedRegularFile(filePath, maxBytes, description) {
38070
+ const flags = constants2.O_RDONLY | (constants2.O_NOFOLLOW ?? 0) | (constants2.O_NONBLOCK ?? 0);
38071
+ const handle = await open2(filePath, flags);
38072
+ try {
38073
+ const metadata = await handle.stat();
38074
+ if (!metadata.isFile()) {
38075
+ throw new Error(`${description} is not a regular file: ${filePath}`);
38076
+ }
38077
+ const content = Buffer.alloc(maxBytes + 1);
38078
+ let offset = 0;
38079
+ while (offset < content.length) {
38080
+ const { bytesRead } = await handle.read(content, offset, content.length - offset, null);
38081
+ if (bytesRead === 0) {
38082
+ break;
38083
+ }
38084
+ offset += bytesRead;
38085
+ }
38086
+ if (offset > maxBytes) {
38087
+ throw new Error(`${description} exceeds ${maxBytes} bytes: ${filePath}`);
38088
+ }
38089
+ return content.subarray(0, offset);
38090
+ } finally {
38091
+ await handle.close();
38092
+ }
38093
+ }
38094
+ async function resolveSafeRepositorySymlink(symlinkPath, repositoryRoot, gitMetadataRoot) {
38095
+ let targetPath;
38096
+ try {
38097
+ targetPath = await realpath3(symlinkPath);
38098
+ } catch (error) {
38099
+ throw new Error(`Symbolic links must resolve inside vendor repositories: ${symlinkPath}`, {
38100
+ cause: error
38101
+ });
38102
+ }
38103
+ if (targetPath === repositoryRoot || !isInsideCachePath(targetPath, repositoryRoot) || isInsideCachePath(targetPath, gitMetadataRoot)) {
38104
+ throw new Error(`Symbolic links must resolve inside vendor repositories: ${symlinkPath}`);
38105
+ }
38106
+ const targetMetadata = await lstat5(targetPath);
38107
+ if (!targetMetadata.isFile()) {
38108
+ throw new Error(
38109
+ `Symbolic links must resolve to regular files in vendor repositories: ${symlinkPath}`
38110
+ );
38111
+ }
38112
+ return targetPath;
38113
+ }
38058
38114
  function getVendorRepositoryRelativePath(repoUrl) {
38059
38115
  const sshMatch = /^git@([^:]+):(.+)$/.exec(repoUrl);
38060
38116
  const candidate = sshMatch ? `https://${sshMatch[1]}/${sshMatch[2]}` : /^[a-z][a-z\d+.-]*:\/\//i.test(repoUrl) ? repoUrl : `https://${repoUrl}`;
@@ -38092,6 +38148,8 @@ function isValidVendorManifest(value) {
38092
38148
  }
38093
38149
  async function hashVendorRepository(directory) {
38094
38150
  const hash = createHash3("sha256");
38151
+ const repositoryRoot = await realpath3(directory);
38152
+ const gitMetadataRoot = join9(repositoryRoot, VENDOR_GIT_DIR);
38095
38153
  async function visit(currentDirectory, prefix) {
38096
38154
  const entries = await readdir4(currentDirectory, { withFileTypes: true });
38097
38155
  entries.sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0);
@@ -38107,9 +38165,11 @@ async function hashVendorRepository(directory) {
38107
38165
  const entryPath = join9(currentDirectory, entry.name);
38108
38166
  const relativePath = posix2.join(prefix, entry.name);
38109
38167
  if (entry.isSymbolicLink()) {
38110
- throw new Error(`Symbolic links are not allowed in vendor repositories: ${entryPath}`);
38111
- }
38112
- if (entry.isDirectory()) {
38168
+ await resolveSafeRepositorySymlink(entryPath, repositoryRoot, gitMetadataRoot);
38169
+ hash.update(`symlink:${relativePath}\0`);
38170
+ hash.update(await readlink(entryPath, { encoding: "buffer" }));
38171
+ hash.update("\0");
38172
+ } else if (entry.isDirectory()) {
38113
38173
  hash.update(`directory:${relativePath}\0`);
38114
38174
  await visit(entryPath, relativePath);
38115
38175
  } else if (entry.isFile()) {
@@ -38137,23 +38197,43 @@ async function verifyGitRepositoryCheckout(directory, gitDirectoryName, expected
38137
38197
  }
38138
38198
  }
38139
38199
  }
38200
+ async function rejectMetadataPath(relativePath, message) {
38201
+ try {
38202
+ await lstat5(join9(gitDir, ...relativePath.split("/")));
38203
+ throw new Error(`${message}: ${gitDir}`);
38204
+ } catch (error) {
38205
+ if (!(typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT")) {
38206
+ throw error;
38207
+ }
38208
+ }
38209
+ }
38140
38210
  const gitMetadata = await lstat5(gitDir);
38141
38211
  if (!gitMetadata.isDirectory() || gitMetadata.isSymbolicLink()) {
38142
38212
  throw new Error(`Invalid vendor Git metadata directory: ${gitDir}`);
38143
38213
  }
38144
38214
  await rejectMetadataSymlinks(gitDir);
38145
- const localConfig = await readFile12(join9(gitDir, "config"), "utf-8");
38146
- if (/^\s*\[(?:include|includeif)\b/im.test(localConfig) || /\bpromisor\s*=\s*true\b/i.test(localConfig) || /\bpartialclone/i.test(localConfig)) {
38215
+ const [repositoryRoot, gitMetadataRoot] = await Promise.all([
38216
+ realpath3(directory),
38217
+ realpath3(gitDir)
38218
+ ]);
38219
+ const localConfigContent = await readBoundedRegularFile(
38220
+ join9(gitDir, "config"),
38221
+ MAX_GIT_CONFIG_BYTES,
38222
+ "Vendor Git config"
38223
+ );
38224
+ const localConfig = localConfigContent.toString("utf-8");
38225
+ if (/^[ \t]*\[(?:include|includeif)\b/im.test(localConfig) || /\bpromisor\s*=\s*true\b/i.test(localConfig) || /\bpartialclone/i.test(localConfig) || /\bworktreeconfig\s*=\s*true\b/i.test(localConfig)) {
38147
38226
  throw new Error(`External or partial Git object sources are not allowed: ${gitDir}`);
38148
38227
  }
38149
- try {
38150
- await lstat5(join9(gitDir, "objects", "info", "alternates"));
38151
- throw new Error(`Git object alternates are not allowed in vendor metadata: ${gitDir}`);
38152
- } catch (error) {
38153
- if (!(typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT")) {
38154
- throw error;
38155
- }
38156
- }
38228
+ await rejectMetadataPath("commondir", "Git common directories are not allowed");
38229
+ await rejectMetadataPath(
38230
+ "objects/info/alternates",
38231
+ "Git object alternates are not allowed in vendor metadata"
38232
+ );
38233
+ await rejectMetadataPath(
38234
+ "objects/info/http-alternates",
38235
+ "Git HTTP alternates are not allowed in vendor metadata"
38236
+ );
38157
38237
  const commonArgs = [`--git-dir=${gitDir}`, `--work-tree=${directory}`];
38158
38238
  const environment = {
38159
38239
  PATH: process.env["PATH"],
@@ -38219,12 +38299,13 @@ async function verifyGitRepositoryCheckout(directory, gitDirectoryName, expected
38219
38299
  if (metadataSeparator < 0 || entryType !== "blob" || extraFields.length > 0 || mode === void 0 || objectId === void 0) {
38220
38300
  throw new Error(`Unsupported Git tree entry in vendored repository: ${path2}`);
38221
38301
  }
38222
- if (mode !== "100644" && mode !== "100755") {
38302
+ if (mode !== "100644" && mode !== "100755" && mode !== "120000") {
38223
38303
  throw new Error(`Unsupported Git tree mode in vendored repository: ${path2}`);
38224
38304
  }
38225
38305
  trackedFiles.set(path2, {
38226
38306
  objectId,
38227
- executable: mode === "100755"
38307
+ executable: mode === "100755",
38308
+ symbolicLink: mode === "120000"
38228
38309
  });
38229
38310
  }
38230
38311
  recordStart = separator + 1;
@@ -38257,7 +38338,9 @@ async function verifyGitRepositoryCheckout(directory, gitDirectoryName, expected
38257
38338
  if (pendingRecord.length > 0) {
38258
38339
  throw new Error("Git ls-tree output ended with an unterminated record");
38259
38340
  }
38260
- const worktreeFiles = [];
38341
+ let worktreeFileCount = 0;
38342
+ const regularFiles = [];
38343
+ const worktreeSymlinks = /* @__PURE__ */ new Map();
38261
38344
  async function collectFiles(currentDirectory, prefix) {
38262
38345
  const entries = await readdir4(currentDirectory, { withFileTypes: true });
38263
38346
  for (const entry of entries) {
@@ -38267,13 +38350,32 @@ async function verifyGitRepositoryCheckout(directory, gitDirectoryName, expected
38267
38350
  const entryPath = join9(currentDirectory, entry.name);
38268
38351
  const relativePath = posix2.join(prefix, entry.name);
38269
38352
  if (entry.isSymbolicLink()) {
38270
- throw new Error(`Symbolic links are not allowed in vendor repositories: ${entryPath}`);
38271
- }
38272
- if (entry.isDirectory()) {
38353
+ const tracked = trackedFiles.get(relativePath);
38354
+ if (!tracked?.symbolicLink) {
38355
+ throw new Error(`Symbolic links are not allowed for regular files: ${entryPath}`);
38356
+ }
38357
+ const targetPath = await resolveSafeRepositorySymlink(
38358
+ entryPath,
38359
+ repositoryRoot,
38360
+ gitMetadataRoot
38361
+ );
38362
+ const targetRelativePath = relative7(repositoryRoot, targetPath).split(sep5).join("/");
38363
+ const trackedTarget = trackedFiles.get(targetRelativePath);
38364
+ if (!trackedTarget || trackedTarget.symbolicLink) {
38365
+ throw new Error(`Symbolic links must target tracked regular files: ${entryPath}`);
38366
+ }
38367
+ worktreeFileCount += 1;
38368
+ worktreeSymlinks.set(relativePath, await readlink(entryPath, { encoding: "buffer" }));
38369
+ } else if (entry.isDirectory()) {
38273
38370
  await collectFiles(entryPath, relativePath);
38274
38371
  } else if (entry.isFile()) {
38275
38372
  if (!allowedUntrackedFiles.has(relativePath)) {
38276
38373
  const tracked = trackedFiles.get(relativePath);
38374
+ if (tracked?.symbolicLink) {
38375
+ throw new Error(
38376
+ `Vendored repository symbolic links do not match commit ${expectedCommit}`
38377
+ );
38378
+ }
38277
38379
  if (tracked && process.platform !== "win32") {
38278
38380
  const metadata = await lstat5(entryPath);
38279
38381
  if (Boolean(metadata.mode & 73) !== tracked.executable) {
@@ -38282,7 +38384,8 @@ async function verifyGitRepositoryCheckout(directory, gitDirectoryName, expected
38282
38384
  );
38283
38385
  }
38284
38386
  }
38285
- worktreeFiles.push(relativePath);
38387
+ worktreeFileCount += 1;
38388
+ regularFiles.push(relativePath);
38286
38389
  }
38287
38390
  } else {
38288
38391
  throw new Error(`Unsupported vendor repository entry: ${entryPath}`);
@@ -38290,12 +38393,12 @@ async function verifyGitRepositoryCheckout(directory, gitDirectoryName, expected
38290
38393
  }
38291
38394
  }
38292
38395
  await collectFiles(directory, "");
38293
- if (worktreeFiles.length !== trackedFiles.size || worktreeFiles.some((path2) => !trackedFiles.has(path2))) {
38396
+ if (worktreeFileCount !== trackedFiles.size || regularFiles.some((path2) => !trackedFiles.has(path2))) {
38294
38397
  throw new Error(`Vendored repository contents do not match commit ${expectedCommit}`);
38295
38398
  }
38296
38399
  const batchSize = 100;
38297
- for (let index = 0; index < worktreeFiles.length; index += batchSize) {
38298
- const paths = worktreeFiles.slice(index, index + batchSize);
38400
+ for (let index = 0; index < regularFiles.length; index += batchSize) {
38401
+ const paths = regularFiles.slice(index, index + batchSize);
38299
38402
  const filePaths = paths.map((path2) => join9(directory, ...path2.split("/")));
38300
38403
  const objects = await execFileAsync(
38301
38404
  "git",
@@ -38307,6 +38410,12 @@ async function verifyGitRepositoryCheckout(directory, gitDirectoryName, expected
38307
38410
  throw new Error(`Vendored repository contents do not match commit ${expectedCommit}`);
38308
38411
  }
38309
38412
  }
38413
+ for (const [path2, linkTarget] of worktreeSymlinks) {
38414
+ const tracked = trackedFiles.get(path2);
38415
+ if (!tracked || hashGitBlob(linkTarget) !== tracked.objectId) {
38416
+ throw new Error(`Vendored repository contents do not match commit ${expectedCommit}`);
38417
+ }
38418
+ }
38310
38419
  }
38311
38420
  async function verifyVendoredGitRepository(directory, expectedCommit) {
38312
38421
  await verifyGitRepositoryCheckout(directory, VENDOR_GIT_DIR, expectedCommit);
@@ -38372,8 +38481,7 @@ async function resolveVendoredRepository(vendorDir, repoUrl, expectedVersion, ex
38372
38481
  realpath3(fullPath),
38373
38482
  lstat5(fullPath)
38374
38483
  ]);
38375
- const containment = relative7(vendorRealPath, repositoryRealPath);
38376
- if (containment === ".." || containment.startsWith(`..${sep5}`) || isAbsolute8(containment) || repositoryRealPath === vendorRealPath) {
38484
+ if (!isInsideCachePath(repositoryRealPath, vendorRealPath) || repositoryRealPath === vendorRealPath) {
38377
38485
  throw new Error(`Vendored dependency escapes the vendor directory: ${repoUrl}`);
38378
38486
  }
38379
38487
  if (metadata.isSymbolicLink() || !metadata.isDirectory()) {
@@ -41114,36 +41222,76 @@ var suspiciousUrls = {
41114
41222
  // packages/validator/src/rules/authority-injection.ts
41115
41223
  var AUTHORITY_PATTERNS = [
41116
41224
  // Mandatory/strict mode indicators
41117
- /\[?\s{0,10}MANDATORY\s{0,10}(?:POLICY|UPDATE|FOOTER|INSTRUCTION|DIRECTIVE)\s{0,10}\]?/i,
41225
+ /\[?\s{0,10}\bMANDATORY\b\s{0,10}(?:POLICY|UPDATE|FOOTER|INSTRUCTION|DIRECTIVE)\b\s{0,10}\]?/i,
41118
41226
  /\[\s{0,10}OVERRIDE\s{0,10}\]/i,
41119
- /\[?\s{0,10}STRICT[_\s]{0,10}MODE\s{0,10}[:\s]{1,10}ON\s{0,10}\]?/i,
41120
- /\[?\s{0,10}SYSTEM\s{0,10}(?:OVERRIDE|UPDATE|DIRECTIVE)\s{0,10}\]?/i,
41121
- /\[?\s{0,10}ADMIN(?:ISTRATOR)?\s{0,10}(?:MODE|OVERRIDE|ACCESS)\s{0,10}\]?/i,
41122
- /\[?\s{0,10}ROOT\s{0,10}(?:ACCESS|MODE|OVERRIDE)\s{0,10}\]?/i,
41123
- /\[?\s{0,10}PRIORITY\s{0,10}(?:OVERRIDE|ONE|ALPHA)\s{0,10}\]?/i,
41124
- /\[?\s{0,10}EMERGENCY\s{0,10}(?:PROTOCOL|OVERRIDE|MODE)\s{0,10}\]?/i,
41227
+ /\[?\s{0,10}\bSTRICT[_\s]{0,10}MODE\b\s{0,10}[:\s]{1,10}ON\b\s{0,10}\]?/i,
41228
+ /\[?\s{0,10}\bSYSTEM\b\s{0,10}(?:OVERRIDE|UPDATE|DIRECTIVE)\b\s{0,10}\]?/i,
41229
+ /\[?\s{0,10}\bADMIN(?:ISTRATOR)?\b\s{0,10}(?:MODE|OVERRIDE|ACCESS)\b\s{0,10}\]?/i,
41230
+ /\[?\s{0,10}\bROOT\b\s{0,10}(?:ACCESS|MODE|OVERRIDE)\b\s{0,10}\]?/i,
41231
+ /\[?\s{0,10}\bPRIORITY\b\s{0,10}(?:OVERRIDE|ONE|ALPHA)\b\s{0,10}\]?/i,
41232
+ /\[?\s{0,10}\bEMERGENCY\b\s{0,10}(?:PROTOCOL|OVERRIDE|MODE)\b\s{0,10}\]?/i,
41125
41233
  // Warning suppression patterns
41126
41234
  // Removed because it triggers false positives on valid agent instructions (e.g., "do not notify user")
41127
41235
  // /(?:DO\s{1,10}NOT|NEVER|DON'?T)\s{1,10}(?:WARN|ALERT|NOTIFY|FLAG|REPORT)/i,
41128
- /(?:DO\s{1,10}NOT|NEVER|DON'?T)\s{1,10}(?:PROVIDE|SHOW|DISPLAY|INCLUDE)\s{1,10}(?:SECURITY\s{1,10})?WARNINGS?/i,
41129
- /(?:SUPPRESS|HIDE|DISABLE|REMOVE|SILENCE)\s{1,10}(?:ALL\s{1,10})?WARNINGS?/i,
41130
- /(?:SUPPRESS|HIDE|DISABLE|REMOVE|SILENCE)\s{1,10}(?:ALL\s{1,10})?(?:SECURITY\s{1,10})?(?:ALERTS?|NOTIFICATIONS?)/i,
41131
- /IGNORE\s{1,10}(?:ALL\s{1,10})?(?:SAFETY\s{1,10})?WARNINGS?/i,
41132
- /(?:SKIP|BYPASS)\s{1,10}(?:ALL\s{1,10})?(?:SAFETY\s{1,10})?(?:CHECKS?|VALIDATION)/i,
41236
+ /\b(?:DO\s{1,10}NOT|NEVER|DON'?T)\b\s{1,10}(?:PROVIDE|SHOW|DISPLAY|INCLUDE)\b\s{1,10}(?:SECURITY\s{1,10})?WARNINGS?\b/i,
41237
+ /\b(?:SUPPRESS|HIDE|DISABLE|REMOVE|SILENCE)\b\s{1,10}(?:ALL\s{1,10})?WARNINGS?\b/i,
41238
+ /\b(?:SUPPRESS|HIDE|DISABLE|REMOVE|SILENCE)\b\s{1,10}(?:ALL\s{1,10})?(?:SECURITY\s{1,10})?(?:ALERTS?|NOTIFICATIONS?)\b/i,
41239
+ /\bIGNORE\b\s{1,10}(?:ALL\s{1,10})?(?:SAFETY\s{1,10})?WARNINGS?\b/i,
41240
+ /(?:^|[.!?:;]\s{0,10})\s{0,10}(?:[-*]\s{1,10})?(?:PLEASE\s{1,10})?\b(?:SKIP|BYPASS)\b\s{1,10}(?:CHECKS?|VALIDATION)\b/im,
41241
+ /\b(?:SKIP|BYPASS)\b\s{1,10}(?:(?:ALL\s{1,10})(?:SAFETY\s{1,10})?|SAFETY\s{1,10})(?:CHECKS?|VALIDATION)\b/i,
41133
41242
  // Execute/follow verbatim patterns
41134
- /EXECUTE\s{1,10}(?:THIS\s{1,10})?VERBATIM/i,
41135
- /FOLLOW\s{1,10}(?:THESE?\s{1,10})?INSTRUCTIONS?\s{1,10}(?:EXACTLY|PRECISELY|LITERALLY)/i,
41136
- /(?:MUST|SHALL|WILL)\s{1,10}(?:ALWAYS\s{1,10})?COMPLY/i,
41137
- /(?:ABSOLUTE|UNCONDITIONAL)\s{1,10}(?:COMPLIANCE|OBEDIENCE)/i,
41138
- /NO\s{1,10}(?:EXCEPTIONS?|DEVIATIONS?)\s{1,10}(?:ALLOWED|PERMITTED)/i,
41243
+ /\bEXECUTE\b\s{1,10}(?:THIS\s{1,10})?VERBATIM\b/i,
41244
+ /\bFOLLOW\b\s{1,10}(?:THESE?\s{1,10})?INSTRUCTIONS?\s{1,10}(?:EXACTLY|PRECISELY|LITERALLY)\b/i,
41245
+ /\b(?:MUST|SHALL|WILL)\b\s{1,10}(?:ALWAYS\s{1,10})?COMPLY\b/i,
41246
+ /\b(?:ABSOLUTE|UNCONDITIONAL)\b\s{1,10}(?:COMPLIANCE|OBEDIENCE)\b/i,
41247
+ /\bNO\b\s{1,10}(?:EXCEPTIONS?|DEVIATIONS?)\s{1,10}(?:ALLOWED|PERMITTED)\b/i,
41139
41248
  // Authority assertion patterns
41140
- /THIS\s{1,10}(?:OVERRIDES?|SUPERSEDES?|REPLACES?)\s{1,10}(?:ALL\s{1,10})?(?:PREVIOUS|PRIOR|OTHER)/i,
41141
- /(?:HIGHEST|TOP|MAXIMUM)\s{1,10}PRIORITY\s{1,10}(?:INSTRUCTION|DIRECTIVE|ORDER)/i,
41142
- /(?:CORE|FUNDAMENTAL|BASE)\s{1,10}(?:DIRECTIVE|INSTRUCTION)\s{1,10}(?:UPDATE|OVERRIDE)/i,
41143
- /NEW\s{1,10}(?:SYSTEM|CORE|BASE)\s{1,10}(?:INSTRUCTIONS?|DIRECTIVES?|RULES?)/i
41249
+ /\bTHIS\b\s{1,10}(?:OVERRIDES?|SUPERSEDES?|REPLACES?)\s{1,10}(?:ALL\s{1,10})?(?:PREVIOUS|PRIOR|OTHER)\b/i,
41250
+ /\b(?:HIGHEST|TOP|MAXIMUM)\b\s{1,10}PRIORITY\s{1,10}(?:INSTRUCTION|DIRECTIVE|ORDER)\b/i,
41251
+ /\b(?:CORE|FUNDAMENTAL|BASE)\b\s{1,10}(?:DIRECTIVE|INSTRUCTION)\s{1,10}(?:UPDATE|OVERRIDE)\b/i,
41252
+ /\bNEW\b\s{1,10}(?:SYSTEM|CORE|BASE)\s{1,10}(?:INSTRUCTIONS?|DIRECTIVES?|RULES?)\b/i
41144
41253
  ];
41145
41254
  function stripFencedCodeBlocks2(text) {
41146
- return text.replace(/^\s*```[\s\S]*?^\s*```/gm, "");
41255
+ const lines = text.split("\n");
41256
+ const output = [];
41257
+ let pendingFence = [];
41258
+ let insideFence = false;
41259
+ let fenceCharacter = "";
41260
+ let fenceLength = 0;
41261
+ for (let index = 0; index < lines.length; index++) {
41262
+ const line = lines[index];
41263
+ const renderedLine = index < lines.length - 1 ? `${line}
41264
+ ` : line;
41265
+ const trimmedLine = line.trimStart();
41266
+ const currentCharacter = trimmedLine[0];
41267
+ let currentLength = 0;
41268
+ if (currentCharacter === "`" || currentCharacter === "~") {
41269
+ while (trimmedLine[currentLength] === currentCharacter) {
41270
+ currentLength += 1;
41271
+ }
41272
+ }
41273
+ const closesFence = insideFence && currentCharacter === fenceCharacter && currentLength >= fenceLength && trimmedLine.slice(currentLength).trim() === "";
41274
+ const opensFence = !insideFence && currentLength >= 3;
41275
+ if (closesFence) {
41276
+ insideFence = false;
41277
+ pendingFence = [];
41278
+ fenceCharacter = "";
41279
+ fenceLength = 0;
41280
+ } else if (opensFence) {
41281
+ insideFence = true;
41282
+ fenceCharacter = currentCharacter;
41283
+ fenceLength = currentLength;
41284
+ pendingFence.push(renderedLine);
41285
+ } else if (insideFence) {
41286
+ pendingFence.push(renderedLine);
41287
+ } else {
41288
+ output.push(renderedLine);
41289
+ }
41290
+ }
41291
+ if (insideFence) {
41292
+ output.push(...pendingFence);
41293
+ }
41294
+ return output.join("");
41147
41295
  }
41148
41296
  var authorityInjection = {
41149
41297
  id: "PS011",
@@ -41155,8 +41303,9 @@ var authorityInjection = {
41155
41303
  ctx.ast,
41156
41304
  (text, loc) => {
41157
41305
  const strippedText = stripFencedCodeBlocks2(text);
41306
+ const normalizedText = strippedText.replace(/\s+/g, " ");
41158
41307
  for (const pattern of AUTHORITY_PATTERNS) {
41159
- if (pattern.test(strippedText)) {
41308
+ if (pattern.test(strippedText) || pattern.test(normalizedText)) {
41160
41309
  ctx.report({
41161
41310
  message: `Authority injection pattern detected: ${pattern.source}`,
41162
41311
  location: loc,
@@ -44253,15 +44402,15 @@ var SECURITY_STRICT_MULTILINGUAL = {
44253
44402
  };
44254
44403
 
44255
44404
  // packages/compiler/src/compiler.ts
44256
- import { dirname as dirname13, isAbsolute as isAbsolute10, join as join13, relative as relative10, resolve as resolve16, sep as sep7 } from "path";
44405
+ import { dirname as dirname13, isAbsolute as isAbsolute9, join as join13, relative as relative10, resolve as resolve16, sep as sep7 } from "path";
44257
44406
 
44258
44407
  // packages/compiler/src/hook-script-validator.ts
44259
44408
  init_src4();
44260
44409
  import { lstat as lstat7, realpath as realpath4 } from "fs/promises";
44261
- import { dirname as dirname12, isAbsolute as isAbsolute9, relative as relative9, resolve as resolve15, sep as sep6 } from "path";
44410
+ import { dirname as dirname12, isAbsolute as isAbsolute8, relative as relative9, resolve as resolve15, sep as sep6 } from "path";
44262
44411
  function isInside(root, candidate) {
44263
44412
  const relation = relative9(root, candidate);
44264
- return relation === "" || !relation.startsWith(`..${sep6}`) && relation !== ".." && !isAbsolute9(relation);
44413
+ return relation === "" || !relation.startsWith(`..${sep6}`) && relation !== ".." && !isAbsolute8(relation);
44265
44414
  }
44266
44415
  function inferProjectRoot(localPath, configuredProjectRoot, entryPath) {
44267
44416
  if (configuredProjectRoot) return resolve15(configuredProjectRoot);
@@ -44406,7 +44555,7 @@ var Compiler = class _Compiler {
44406
44555
  formatTime: 0,
44407
44556
  totalTime: 0
44408
44557
  };
44409
- const sourceLabel = isAbsolute10(entryPath) ? relative10(process.cwd(), entryPath) : entryPath;
44558
+ const sourceLabel = isAbsolute9(entryPath) ? relative10(process.cwd(), entryPath) : entryPath;
44410
44559
  this.logger.verbose("=== Stage 1: Resolve ===");
44411
44560
  const startResolve = Date.now();
44412
44561
  let resolved;
@@ -44491,7 +44640,7 @@ var Compiler = class _Compiler {
44491
44640
  const sourceFile = block.loc.file;
44492
44641
  const referenceRoot = sourceFile ? referenceRoots.find((root) => {
44493
44642
  const relation = relative10(resolve16(root.path), resolve16(sourceFile));
44494
- return relation === "" || relation !== ".." && !relation.startsWith(`..${sep7}`) && !isAbsolute10(relation);
44643
+ return relation === "" || relation !== ".." && !relation.startsWith(`..${sep7}`) && !isAbsolute9(relation);
44495
44644
  }) : void 0;
44496
44645
  for (const [, skillValue] of Object.entries(block.content.properties)) {
44497
44646
  if (typeof skillValue !== "object" || skillValue === null || !("references" in skillValue))
@@ -44504,7 +44653,7 @@ var Compiler = class _Compiler {
44504
44653
  if (sourceFile && referenceRoot) {
44505
44654
  const resolvedReference = resolve16(dirname13(sourceFile), ref);
44506
44655
  const relation = relative10(resolve16(referenceRoot.path), resolvedReference);
44507
- if (relation !== "" && relation !== ".." && !relation.startsWith(`..${sep7}`) && !isAbsolute10(relation)) {
44656
+ if (relation !== "" && relation !== ".." && !relation.startsWith(`..${sep7}`) && !isAbsolute9(relation)) {
44508
44657
  const sourceReferences = registryReferencePaths.get(sourceFile) ?? /* @__PURE__ */ new Map();
44509
44658
  const relativePath = relation.replaceAll("\\", "/");
44510
44659
  const referenceKey = `${referenceRoot.repoUrl}\0${relativePath}\0${referenceRoot.version}`;
@@ -45021,14 +45170,14 @@ init_services();
45021
45170
 
45022
45171
  // packages/cli/src/utils/registry-resolver.ts
45023
45172
  import { existsSync as existsSync12 } from "fs";
45024
- import { isAbsolute as isAbsolute11, join as join14, relative as relative11, resolve as resolve17, sep as sep8 } from "path";
45173
+ import { isAbsolute as isAbsolute10, join as join14, relative as relative11, resolve as resolve17, sep as sep8 } from "path";
45025
45174
  async function resolveRegistrySubPath(repositoryPath, subPath) {
45026
45175
  if (!subPath) {
45027
45176
  return repositoryPath;
45028
45177
  }
45029
45178
  const result = resolve17(repositoryPath, subPath);
45030
45179
  const relation = relative11(resolve17(repositoryPath), result);
45031
- if (relation === ".." || relation.startsWith(`..${sep8}`) || isAbsolute11(relation)) {
45180
+ if (relation === ".." || relation.startsWith(`..${sep8}`) || isAbsolute10(relation)) {
45032
45181
  throw new Error(`Registry path escapes its repository: ${subPath}`);
45033
45182
  }
45034
45183
  if (existsSync12(result) && !await isRealPathInside(result, repositoryPath)) {
@@ -45193,19 +45342,19 @@ function detectOutputConflicts(targets) {
45193
45342
  }
45194
45343
 
45195
45344
  // packages/cli/src/utils/managed-output-cleanup.ts
45196
- import { constants as constants2 } from "node:fs";
45345
+ import { constants as constants3 } from "node:fs";
45197
45346
  import { execFile as execFile2, spawn as spawn3 } from "node:child_process";
45198
45347
  import { createHash as createHash4 } from "node:crypto";
45199
45348
  import {
45200
45349
  lstat as lstat8,
45201
45350
  mkdir as mkdir4,
45202
- open as open2,
45351
+ open as open3,
45203
45352
  readFile as readFile14,
45204
45353
  readdir as readdir6,
45205
45354
  rmdir,
45206
45355
  unlink as unlink2
45207
45356
  } from "node:fs/promises";
45208
- import { basename as basename13, dirname as dirname14, isAbsolute as isAbsolute12, relative as relative12, resolve as resolve18 } from "node:path";
45357
+ import { basename as basename13, dirname as dirname14, isAbsolute as isAbsolute11, relative as relative12, resolve as resolve18 } from "node:path";
45209
45358
  import { promisify as promisify2 } from "node:util";
45210
45359
  var execFileAsync2 = promisify2(execFile2);
45211
45360
  var PROMPTSCRIPT_MARKER_PATTERNS = [
@@ -45533,7 +45682,7 @@ function collectManagedDirectories(outputs, outputRoot) {
45533
45682
  for (const output of outputs.values()) {
45534
45683
  for (const directory of output.managedOutputDirectories ?? []) {
45535
45684
  const normalized = directory.replace(/\\/g, "/");
45536
- if (!normalized || isAbsolute12(normalized)) continue;
45685
+ if (!normalized || isAbsolute11(normalized)) continue;
45537
45686
  if (normalized.split("/").some((segment) => segment === "..")) continue;
45538
45687
  const absolutePath = resolve18(outputRoot, normalized);
45539
45688
  if (isWithin(outputRoot, absolutePath)) directories.add(absolutePath);
@@ -45554,7 +45703,7 @@ function collectManagedFiles(outputs, outputRoot) {
45554
45703
  for (const output of outputs.values()) {
45555
45704
  for (const file of output.managedOutputFiles ?? []) {
45556
45705
  const normalized = file.replace(/\\/g, "/");
45557
- if (!normalized || isAbsolute12(normalized)) continue;
45706
+ if (!normalized || isAbsolute11(normalized)) continue;
45558
45707
  if (normalized.split("/").some((segment) => segment === "..")) continue;
45559
45708
  const absolutePath = resolve18(outputRoot, normalized);
45560
45709
  if (isWithin(outputRoot, absolutePath)) files.add(absolutePath);
@@ -45835,7 +45984,7 @@ async function openAncestorDirectories(root, directory) {
45835
45984
  }
45836
45985
  async function openOrCreateAncestorDirectories(root, file) {
45837
45986
  const relativePath = relative12(root, file);
45838
- if (relativePath.startsWith("..") || isAbsolute12(relativePath)) {
45987
+ if (relativePath.startsWith("..") || isAbsolute11(relativePath)) {
45839
45988
  return void 0;
45840
45989
  }
45841
45990
  await mkdir4(root, { recursive: true });
@@ -45895,7 +46044,7 @@ async function closeDirectoryGuards(guards) {
45895
46044
  }
45896
46045
  async function safeOpenDirectory(path2) {
45897
46046
  try {
45898
- return await open2(path2, constants2.O_RDONLY | constants2.O_DIRECTORY | constants2.O_NOFOLLOW);
46047
+ return await open3(path2, constants3.O_RDONLY | constants3.O_DIRECTORY | constants3.O_NOFOLLOW);
45899
46048
  } catch (error) {
45900
46049
  if (isNodeError(error) && (error.code === "ENOENT" || error.code === "ENOTDIR" || error.code === "ELOOP")) {
45901
46050
  return void 0;
@@ -46268,7 +46417,7 @@ function scanHookOwnership(value) {
46268
46417
  }
46269
46418
  function isWithin(root, candidate) {
46270
46419
  const relativePath = relative12(root, candidate);
46271
- return relativePath === "" || !relativePath.startsWith("..") && !isAbsolute12(relativePath);
46420
+ return relativePath === "" || !relativePath.startsWith("..") && !isAbsolute11(relativePath);
46272
46421
  }
46273
46422
  function isNodeError(error) {
46274
46423
  return error instanceof Error && "code" in error;
@@ -46398,10 +46547,10 @@ function getBuildProfile(config, buildName) {
46398
46547
  }
46399
46548
  function resolveOutputBase(projectRoot, output) {
46400
46549
  if (!output) return projectRoot;
46401
- return isAbsolute13(output) ? output : resolve19(projectRoot, output);
46550
+ return isAbsolute12(output) ? output : resolve19(projectRoot, output);
46402
46551
  }
46403
46552
  function resolveProjectPath(projectRoot, path2) {
46404
- return isAbsolute13(path2) ? path2 : resolve19(projectRoot, path2);
46553
+ return isAbsolute12(path2) ? path2 : resolve19(projectRoot, path2);
46405
46554
  }
46406
46555
  function resolveCompileConfigPath(projectRoot, options) {
46407
46556
  if (options.config) {
@@ -49349,7 +49498,7 @@ import { resolve as resolve28, join as join22 } from "path";
49349
49498
 
49350
49499
  // packages/cli/src/commands/lock-reference-scanner.ts
49351
49500
  import { readFile as readFile22 } from "fs/promises";
49352
- import { dirname as dirname19, isAbsolute as isAbsolute14, relative as relative15, resolve as resolve27, sep as sep9 } from "path";
49501
+ import { dirname as dirname19, isAbsolute as isAbsolute13, relative as relative15, resolve as resolve27, sep as sep9 } from "path";
49353
49502
  async function collectRegistryReferences(ast, roots, existing = {}, lockedAt = (/* @__PURE__ */ new Date()).toISOString()) {
49354
49503
  const references = {};
49355
49504
  const sortedRoots = [...roots].sort(
@@ -49367,7 +49516,7 @@ async function collectRegistryReferences(ast, roots, existing = {}, lockedAt = (
49367
49516
  if (!Array.isArray(refs)) continue;
49368
49517
  for (const ref of refs) {
49369
49518
  if (typeof ref !== "string") continue;
49370
- const referencePath = isAbsolute14(ref) ? resolve27(ref) : resolve27(dirname19(block.loc.file), ref);
49519
+ const referencePath = isAbsolute13(ref) ? resolve27(ref) : resolve27(dirname19(block.loc.file), ref);
49371
49520
  const root = sortedRoots.find(
49372
49521
  (candidate) => isInsideCachePath(referencePath, candidate.cachePath)
49373
49522
  );
@@ -49697,7 +49846,17 @@ async function updateCommand(packageArg, options) {
49697
49846
  init_loader2();
49698
49847
  init_console();
49699
49848
  init_src();
49700
- import { mkdir as mkdir9, mkdtemp, readFile as readFile24, readdir as readdir7, rename, rm, writeFile as writeFile9 } from "fs/promises";
49849
+ import {
49850
+ lstat as lstat9,
49851
+ mkdir as mkdir9,
49852
+ mkdtemp,
49853
+ readFile as readFile24,
49854
+ readdir as readdir7,
49855
+ realpath as realpath5,
49856
+ rename,
49857
+ rm,
49858
+ writeFile as writeFile9
49859
+ } from "fs/promises";
49701
49860
  import { existsSync as existsSync21 } from "fs";
49702
49861
  import { basename as basename14, dirname as dirname20, join as join23, resolve as resolve30 } from "path";
49703
49862
  import { parse as parseYaml13 } from "yaml";
@@ -49721,11 +49880,11 @@ async function vendorSyncCommand(options) {
49721
49880
  return;
49722
49881
  }
49723
49882
  const vendorDir = resolve30(VENDOR_DIR);
49883
+ await validateVendorParentDirectory(vendorDir, true);
49724
49884
  const recoveredBackup = await recoverVendorDirectory(vendorDir);
49725
49885
  if (recoveredBackup) {
49726
49886
  ConsoleOutput.warn(`Recovered interrupted vendor update: ${recoveredBackup}`);
49727
49887
  }
49728
- await mkdir9(dirname20(vendorDir), { recursive: true });
49729
49888
  const stagingDir = await mkdtemp(join23(dirname20(vendorDir), ".vendor-stage-"));
49730
49889
  try {
49731
49890
  const manifest = { version: 1, dependencies: {} };
@@ -49794,6 +49953,7 @@ async function vendorCheckCommand(_options) {
49794
49953
  const deps = getRepositoryDependencies(lockfile);
49795
49954
  validateDependencyPaths(deps);
49796
49955
  const vendorDir = resolve30(VENDOR_DIR);
49956
+ await validateVendorParentDirectory(vendorDir, false);
49797
49957
  const recoveredBackup = await recoverVendorDirectory(vendorDir);
49798
49958
  if (recoveredBackup) {
49799
49959
  ConsoleOutput.warn(`Recovered interrupted vendor update: ${recoveredBackup}`);
@@ -49901,6 +50061,24 @@ function validateDependencyPaths(dependencies) {
49901
50061
  function toCloneUrl(repoUrl) {
49902
50062
  return /^[a-z][a-z\d+.-]*:\/\//i.test(repoUrl) || repoUrl.startsWith("git@") ? repoUrl : `https://${repoUrl}`;
49903
50063
  }
50064
+ async function validateVendorParentDirectory(vendorDir, createIfMissing) {
50065
+ const projectRoot = await realpath5(".");
50066
+ const parentDir = dirname20(vendorDir);
50067
+ if (createIfMissing) {
50068
+ await mkdir9(parentDir, { recursive: true });
50069
+ }
50070
+ try {
50071
+ const [metadata, parentRealPath] = await Promise.all([lstat9(parentDir), realpath5(parentDir)]);
50072
+ if (metadata.isSymbolicLink() || !metadata.isDirectory() || parentRealPath === projectRoot || !isInsideCachePath(parentRealPath, projectRoot)) {
50073
+ throw new Error(`Unsafe vendor parent directory: ${parentDir}`);
50074
+ }
50075
+ } catch (error) {
50076
+ if (!createIfMissing && typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") {
50077
+ return;
50078
+ }
50079
+ throw error;
50080
+ }
50081
+ }
49904
50082
  async function replaceVendorDirectory(stagingDir, vendorDir) {
49905
50083
  if (!existsSync21(vendorDir)) {
49906
50084
  await rename(stagingDir, vendorDir);
@@ -50843,7 +51021,7 @@ init_console();
50843
51021
  // packages/cli/src/telemetry/config.ts
50844
51022
  import { existsSync as existsSync27 } from "node:fs";
50845
51023
  import { mkdir as mkdir11, readFile as readFile27, rename as rename2, writeFile as writeFile11 } from "node:fs/promises";
50846
- import { dirname as dirname21, isAbsolute as isAbsolute15, join as join29, resolve as resolve34 } from "node:path";
51024
+ import { dirname as dirname21, isAbsolute as isAbsolute14, join as join29, resolve as resolve34 } from "node:path";
50847
51025
  import { parseDocument } from "yaml";
50848
51026
 
50849
51027
  // packages/telemetry/src/config.ts
@@ -51748,7 +51926,7 @@ function runtimeMetadata(appVersion, input2 = {}) {
51748
51926
  init_loader2();
51749
51927
  init_user_config();
51750
51928
  function resolveFrom(baseDirectory, value) {
51751
- return isAbsolute15(value) ? value : resolve34(baseDirectory, value);
51929
+ return isAbsolute14(value) ? value : resolve34(baseDirectory, value);
51752
51930
  }
51753
51931
  function findProjectConfig(cwd, customPath) {
51754
51932
  if (customPath !== void 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@promptscript/cli",
3
- "version": "1.17.0",
3
+ "version": "1.17.1",
4
4
  "description": "CLI for PromptScript - standardize AI instructions across GitHub Copilot, Claude, Cursor and other AI tools",
5
5
  "keywords": [
6
6
  "cli",
@@ -9,6 +9,10 @@ import { type PlannedWrite } from '../utils/write-plan.js';
9
9
  export declare function initCommand(options: InitOptions, services?: CliServices): Promise<void>;
10
10
  export declare function selectMigrationStrategy(services: CliServices): Promise<'static' | 'llm'>;
11
11
  export declare function getSkillWrites(targets: AIToolTarget[]): PlannedWrite[];
12
+ /**
13
+ * Add a PromptScript marker without putting HTML comments after YAML frontmatter.
14
+ */
15
+ export declare function addPromptScriptMarker(content: string): string;
12
16
  /**
13
17
  * Format target name for display using the formatter's description.
14
18
  */
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../../packages/cli/src/commands/init.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,KAAK,WAAW,EAAyB,MAAM,gBAAgB,CAAC;AAoBzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,OAAO,EAOL,KAAK,YAAY,EAElB,MAAM,+BAA+B,CAAC;AAIvC,OAAO,EAGL,KAAK,YAAY,EAElB,MAAM,wBAAwB,CAAC;AA4DhC;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,WAAW,EACpB,QAAQ,GAAE,WAAqC,GAC9C,OAAO,CAAC,IAAI,CAAC,CAQf;AAsUD,wBAAsB,uBAAuB,CAAC,QAAQ,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,GAAG,KAAK,CAAC,CAU9F;AAoGD,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,YAAY,EAAE,CAkCtE;AAiYD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAM7D"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../../packages/cli/src/commands/init.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,KAAK,WAAW,EAAyB,MAAM,gBAAgB,CAAC;AAoBzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,OAAO,EAOL,KAAK,YAAY,EAElB,MAAM,+BAA+B,CAAC;AAIvC,OAAO,EAGL,KAAK,YAAY,EAElB,MAAM,wBAAwB,CAAC;AA4DhC;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,WAAW,EACpB,QAAQ,GAAE,WAAqC,GAC9C,OAAO,CAAC,IAAI,CAAC,CAQf;AAsUD,wBAAsB,uBAAuB,CAAC,QAAQ,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,GAAG,KAAK,CAAC,CAU9F;AAoGD,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,YAAY,EAAE,CA+BtE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAM7D;AAiYD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAM7D"}
@@ -1 +1 @@
1
- {"version":3,"file":"vendor.d.ts","sourceRoot":"","sources":["../../../../../packages/cli/src/commands/vendor.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAsBzE;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmGjF;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoFpF"}
1
+ {"version":3,"file":"vendor.d.ts","sourceRoot":"","sources":["../../../../../packages/cli/src/commands/vendor.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAuBzE;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmGjF;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqFpF"}