@lousy-agents/cli 5.14.9 → 5.15.0

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 (33) hide show
  1. package/api/copilot-with-fastify/.agents/skills/feature-to-plan/SKILL.md +164 -0
  2. package/api/copilot-with-fastify/.agents/skills/feature-to-plan/references/interactive-flow.md +122 -0
  3. package/api/copilot-with-fastify/.agents/skills/feature-to-plan/references/spec-format.md +434 -0
  4. package/api/copilot-with-fastify/.devcontainer/devcontainer.json +2 -2
  5. package/api/copilot-with-fastify/.github/ISSUE_TEMPLATE/feature-to-spec.yml +18 -10
  6. package/api/copilot-with-fastify/.github/instructions/spec.instructions.md +5 -2
  7. package/api/copilot-with-fastify/.nvmrc +1 -1
  8. package/api/copilot-with-fastify/biome.template.json +1 -1
  9. package/api/copilot-with-fastify/package-lock.json +340 -285
  10. package/api/copilot-with-fastify/package.json +7 -7
  11. package/cli/copilot-with-citty/.agents/skills/feature-to-plan/SKILL.md +164 -0
  12. package/cli/copilot-with-citty/.agents/skills/feature-to-plan/references/interactive-flow.md +122 -0
  13. package/cli/copilot-with-citty/.agents/skills/feature-to-plan/references/spec-format.md +434 -0
  14. package/cli/copilot-with-citty/.devcontainer/devcontainer.json +2 -2
  15. package/cli/copilot-with-citty/.github/ISSUE_TEMPLATE/feature-to-spec.yml +18 -10
  16. package/cli/copilot-with-citty/.nvmrc +1 -1
  17. package/cli/copilot-with-citty/biome.template.json +1 -1
  18. package/cli/copilot-with-citty/package.json +5 -5
  19. package/dist/116.js +4 -3
  20. package/dist/316.js +4 -3
  21. package/dist/475.js +2 -2
  22. package/dist/653.js +13 -10
  23. package/dist/index.js +604 -360
  24. package/package.json +1 -1
  25. package/ui/copilot-with-react/.agents/skills/feature-to-plan/SKILL.md +164 -0
  26. package/ui/copilot-with-react/.agents/skills/feature-to-plan/references/interactive-flow.md +122 -0
  27. package/ui/copilot-with-react/.agents/skills/feature-to-plan/references/spec-format.md +434 -0
  28. package/ui/copilot-with-react/.devcontainer/devcontainer.json +2 -2
  29. package/ui/copilot-with-react/.github/ISSUE_TEMPLATE/feature-to-spec.yml +18 -10
  30. package/ui/copilot-with-react/.github/instructions/spec.instructions.md +5 -2
  31. package/ui/copilot-with-react/.nvmrc +1 -1
  32. package/ui/copilot-with-react/biome.template.json +1 -1
  33. package/ui/copilot-with-react/package.json +11 -11
package/dist/index.js CHANGED
@@ -2990,7 +2990,7 @@ exports.basename = (path, { windows } = {}) => {
2990
2990
 
2991
2991
 
2992
2992
  },
2993
- 1809(__unused_rspack_module, __unused_rspack___webpack_exports__, __webpack_require__) {
2993
+ 8634(__unused_rspack_module, __unused_rspack___webpack_exports__, __webpack_require__) {
2994
2994
  // NAMESPACE OBJECT: ../../node_modules/micromark/lib/constructs.js
2995
2995
  var constructs_namespaceObject = {};
2996
2996
  __webpack_require__.r(constructs_namespaceObject);
@@ -3210,6 +3210,9 @@ function path_isPathInside(root, target) {
3210
3210
  const firstSegment = relative.split(external_node_path_.posix.sep)[0];
3211
3211
  return relative === "" || (firstSegment !== ".." && !external_node_path_.isAbsolute(relative));
3212
3212
  }
3213
+ function isPathRelativeEscape(relativePath) {
3214
+ return relativePath === ".." || relativePath.startsWith(`..${external_node_path_.sep}`) || external_node_path_.isAbsolute(relativePath);
3215
+ }
3213
3216
  function resolveSafeBaseDir(rootDir) {
3214
3217
  const resolved = path.resolve(rootDir);
3215
3218
  return resolved.endsWith(path.sep) ? resolved : `${resolved}${path.sep}`;
@@ -3358,17 +3361,17 @@ function directory_guard_createNearestExistingSyncDirectoryGuard(rootReal, targe
3358
3361
 
3359
3362
 
3360
3363
 
3364
+
3361
3365
  function isSameOrChildPath(candidate, parent) {
3362
- return candidate === parent || candidate.startsWith(`${parent}${external_node_path_.sep}`);
3363
- }
3364
- function isPathEscape(relativePath) {
3365
- return relativePath === ".." || relativePath.startsWith(`..${external_node_path_.sep}`) || external_node_path_.isAbsolute(relativePath);
3366
+ const parentPrefix = parent.endsWith(external_node_path_.sep) ? parent : `${parent}${external_node_path_.sep}`;
3367
+ return candidate === parent || candidate.startsWith(parentPrefix);
3366
3368
  }
3367
3369
  async function mkdirPathComponentsWithGuards(params) {
3368
3370
  const root = external_node_path_.resolve(params.rootReal);
3371
+ const rootCanonical = external_node_path_.resolve(await promises_.realpath(root));
3369
3372
  const target = external_node_path_.resolve(params.targetPath);
3370
3373
  const relative = external_node_path_.relative(root, target);
3371
- if (isPathEscape(relative)) {
3374
+ if (isPathRelativeEscape(relative)) {
3372
3375
  throw new errors_FsSafeError("outside-workspace", "directory is outside workspace root");
3373
3376
  }
3374
3377
  let current = root;
@@ -3391,7 +3394,7 @@ async function mkdirPathComponentsWithGuards(params) {
3391
3394
  }
3392
3395
  // Node's recursive mkdir follows symlinks in missing components. Build one
3393
3396
  // segment at a time and realpath-check each segment before descending.
3394
- if (!isSameOrChildPath(external_node_path_.resolve(await promises_.realpath(next)), root)) {
3397
+ if (!isSameOrChildPath(external_node_path_.resolve(await promises_.realpath(next)), rootCanonical)) {
3395
3398
  throw new errors_FsSafeError("outside-workspace", "directory escaped workspace root");
3396
3399
  }
3397
3400
  await directory_guard_createAsyncDirectoryGuard(next);
@@ -3478,6 +3481,191 @@ function guardedRmSync(params) {
3478
3481
  }), { verifyAfter: params.verifyAfter });
3479
3482
  }
3480
3483
 
3484
+ ;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/deny-mutations.js
3485
+
3486
+
3487
+
3488
+
3489
+ async function pathExists(filePath) {
3490
+ try {
3491
+ await promises_.lstat(filePath);
3492
+ return true;
3493
+ }
3494
+ catch (err) {
3495
+ if (!path_isNotFoundPathError(err)) {
3496
+ throw err;
3497
+ }
3498
+ return false;
3499
+ }
3500
+ }
3501
+ async function resolvePathViaExistingAncestor(targetPath) {
3502
+ const normalized = external_node_path_.resolve(targetPath);
3503
+ let cursor = normalized;
3504
+ const missingSuffix = [];
3505
+ while (external_node_path_.dirname(cursor) !== cursor && !(await pathExists(cursor))) {
3506
+ missingSuffix.unshift(external_node_path_.basename(cursor));
3507
+ cursor = external_node_path_.dirname(cursor);
3508
+ }
3509
+ if (!(await pathExists(cursor))) {
3510
+ return normalized;
3511
+ }
3512
+ try {
3513
+ const resolvedAncestor = external_node_path_.resolve(await promises_.realpath(cursor));
3514
+ return missingSuffix.length === 0
3515
+ ? resolvedAncestor
3516
+ : external_node_path_.resolve(resolvedAncestor, ...missingSuffix);
3517
+ }
3518
+ catch {
3519
+ return normalized;
3520
+ }
3521
+ }
3522
+ async function comparablePaths(rawPath) {
3523
+ path_assertNoNulPathInput(rawPath, "path contains a NUL byte");
3524
+ const resolved = external_node_path_.resolve(rawPath);
3525
+ return new Set([resolved, await resolvePathViaExistingAncestor(resolved)]);
3526
+ }
3527
+ function isSamePath(left, right) {
3528
+ return path_isPathInside(left, right) && path_isPathInside(right, left);
3529
+ }
3530
+ function hasPolicyEntries(policy) {
3531
+ return Boolean(policy?.paths?.length || policy?.prefixes?.length);
3532
+ }
3533
+ function policyPathEntries(entries) {
3534
+ const paths = [];
3535
+ for (const entry of entries ?? []) {
3536
+ if (entry.length === 0) {
3537
+ throw new errors_FsSafeError("invalid-path", "deny mutation paths must be non-empty");
3538
+ }
3539
+ path_assertNoNulPathInput(entry, "deny mutation path contains a NUL byte");
3540
+ if (!external_node_path_.isAbsolute(entry)) {
3541
+ throw new errors_FsSafeError("invalid-path", "deny mutation paths must be absolute");
3542
+ }
3543
+ paths.push(entry);
3544
+ }
3545
+ return paths;
3546
+ }
3547
+ async function assertMutationNotDenied(filePath, policy, options = {}) {
3548
+ if (!hasPolicyEntries(policy)) {
3549
+ return;
3550
+ }
3551
+ const targetPaths = await comparablePaths(filePath);
3552
+ for (const deniedPath of policyPathEntries(policy.paths)) {
3553
+ const deniedPaths = await comparablePaths(deniedPath);
3554
+ for (const target of targetPaths) {
3555
+ for (const denied of deniedPaths) {
3556
+ if (isSamePath(denied, target) ||
3557
+ (options.protectAncestors === true && path_isPathInside(target, denied))) {
3558
+ throw new errors_FsSafeError("denied-path", "path is denied by denyMutations policy");
3559
+ }
3560
+ }
3561
+ }
3562
+ }
3563
+ for (const deniedPrefix of policyPathEntries(policy.prefixes)) {
3564
+ const deniedPaths = await comparablePaths(deniedPrefix);
3565
+ for (const target of targetPaths) {
3566
+ for (const denied of deniedPaths) {
3567
+ if (path_isPathInside(denied, target) ||
3568
+ (options.protectAncestors === true && path_isPathInside(target, denied))) {
3569
+ throw new errors_FsSafeError("denied-path", "path is denied by denyMutations policy");
3570
+ }
3571
+ }
3572
+ }
3573
+ }
3574
+ }
3575
+ function mergeDenyMutationPolicies(defaultPolicy, callPolicy) {
3576
+ if (!defaultPolicy) {
3577
+ return callPolicy;
3578
+ }
3579
+ if (!callPolicy) {
3580
+ return defaultPolicy;
3581
+ }
3582
+ return {
3583
+ paths: [...(defaultPolicy.paths ?? []), ...(callPolicy.paths ?? [])],
3584
+ prefixes: [...(defaultPolicy.prefixes ?? []), ...(callPolicy.prefixes ?? [])],
3585
+ };
3586
+ }
3587
+
3588
+ ;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/opened-realpath.js
3589
+
3590
+
3591
+
3592
+
3593
+
3594
+ async function resolveOpenedFileRealPathForHandle(handle, ioPath) {
3595
+ const handleStat = await handle.stat();
3596
+ const fdCandidates = process.platform === "linux"
3597
+ ? [`/proc/self/fd/${handle.fd}`, `/dev/fd/${handle.fd}`]
3598
+ : process.platform === "win32"
3599
+ ? []
3600
+ : [`/dev/fd/${handle.fd}`];
3601
+ for (const fdPath of fdCandidates) {
3602
+ try {
3603
+ const fdRealPath = await promises_.realpath(fdPath);
3604
+ const fdRealStat = await promises_.stat(fdRealPath);
3605
+ if (file_identity_sameFileIdentity(handleStat, fdRealStat)) {
3606
+ return fdRealPath;
3607
+ }
3608
+ }
3609
+ catch {
3610
+ // try next fd path
3611
+ }
3612
+ }
3613
+ try {
3614
+ const ioRealPath = await promises_.realpath(ioPath);
3615
+ const ioRealStat = await promises_.stat(ioRealPath);
3616
+ if (file_identity_sameFileIdentity(handleStat, ioRealStat)) {
3617
+ return ioRealPath;
3618
+ }
3619
+ }
3620
+ catch (err) {
3621
+ if (!path_isNotFoundPathError(err)) {
3622
+ throw err;
3623
+ }
3624
+ }
3625
+ const parentResolved = await resolveOpenedFileRealPathFromParent(handleStat, ioPath);
3626
+ if (parentResolved) {
3627
+ return parentResolved;
3628
+ }
3629
+ throw new errors_FsSafeError("path-mismatch", "unable to resolve opened file path");
3630
+ }
3631
+ async function resolveOpenedFileRealPathFromParent(handleStat, ioPath) {
3632
+ let parentReal;
3633
+ try {
3634
+ parentReal = await promises_.realpath(external_node_path_.dirname(ioPath));
3635
+ }
3636
+ catch (err) {
3637
+ if (path_isNotFoundPathError(err)) {
3638
+ return null;
3639
+ }
3640
+ throw err;
3641
+ }
3642
+ let entries;
3643
+ try {
3644
+ entries = await promises_.readdir(parentReal);
3645
+ }
3646
+ catch (err) {
3647
+ if (path_isNotFoundPathError(err)) {
3648
+ return null;
3649
+ }
3650
+ throw err;
3651
+ }
3652
+ for (const entry of entries.toSorted()) {
3653
+ const candidatePath = external_node_path_.join(parentReal, entry);
3654
+ try {
3655
+ const candidateStat = await promises_.lstat(candidatePath);
3656
+ if (candidateStat.isFile() && file_identity_sameFileIdentity(handleStat, candidateStat)) {
3657
+ return await promises_.realpath(candidatePath);
3658
+ }
3659
+ }
3660
+ catch (err) {
3661
+ if (!path_isNotFoundPathError(err)) {
3662
+ throw err;
3663
+ }
3664
+ }
3665
+ }
3666
+ return null;
3667
+ }
3668
+
3481
3669
  ;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/pinned-python-config.js
3482
3670
  let overrideConfig = {};
3483
3671
  function parseMode(value) {
@@ -3526,26 +3714,20 @@ var external_node_child_process_ = __webpack_require__(1421);
3526
3714
 
3527
3715
 
3528
3716
  const PINNED_PYTHON_WORKER_SOURCE = String.raw `
3529
- import base64
3530
- import errno
3531
- import json
3532
- import os
3533
- import secrets
3534
- import stat
3535
- import sys
3536
-
3717
+ import base64, errno, json, os, secrets, stat, sys
3537
3718
  DIR_FLAGS = os.O_RDONLY
3538
3719
  if hasattr(os, "O_DIRECTORY"):
3539
3720
  DIR_FLAGS |= os.O_DIRECTORY
3540
3721
  if hasattr(os, "O_NOFOLLOW"):
3541
3722
  DIR_FLAGS |= os.O_NOFOLLOW
3542
3723
  READ_FLAGS = os.O_RDONLY
3724
+ if hasattr(os, "O_NONBLOCK"):
3725
+ READ_FLAGS |= os.O_NONBLOCK
3543
3726
  if hasattr(os, "O_NOFOLLOW"):
3544
3727
  READ_FLAGS |= os.O_NOFOLLOW
3545
3728
  WRITE_FLAGS = os.O_WRONLY | os.O_CREAT | os.O_EXCL
3546
3729
  if hasattr(os, "O_NOFOLLOW"):
3547
3730
  WRITE_FLAGS |= os.O_NOFOLLOW
3548
-
3549
3731
  def split_relative(value):
3550
3732
  if value in ("", "."):
3551
3733
  return []
@@ -3558,10 +3740,8 @@ def split_relative(value):
3558
3740
  if part == "..":
3559
3741
  raise OSError(errno.EPERM, "path traversal is not allowed")
3560
3742
  return parts
3561
-
3562
3743
  def open_dir(path_value, dir_fd=None):
3563
3744
  return os.open(path_value, DIR_FLAGS, dir_fd=dir_fd)
3564
-
3565
3745
  def walk_dir(root_fd, segments, mkdir_enabled=False):
3566
3746
  current_fd = os.dup(root_fd)
3567
3747
  try:
@@ -3579,14 +3759,12 @@ def walk_dir(root_fd, segments, mkdir_enabled=False):
3579
3759
  except Exception:
3580
3760
  os.close(current_fd)
3581
3761
  raise
3582
-
3583
3762
  def parent_and_basename(root_fd, relative):
3584
3763
  segments = split_relative(relative)
3585
3764
  if not segments:
3586
3765
  raise OSError(errno.EPERM, "operation requires a non-root path")
3587
3766
  parent_fd = walk_dir(root_fd, segments[:-1])
3588
3767
  return parent_fd, segments[-1]
3589
-
3590
3768
  def encode_stat(st):
3591
3769
  mode = st.st_mode
3592
3770
  return {
@@ -3602,14 +3780,12 @@ def encode_stat(st):
3602
3780
  "size": st.st_size,
3603
3781
  "uid": st.st_uid,
3604
3782
  }
3605
-
3606
3783
  def reject_unsafe_endpoint(st):
3607
3784
  mode = st.st_mode
3608
3785
  if stat.S_ISLNK(mode):
3609
3786
  raise OSError(errno.ELOOP, "symlink endpoint is not allowed")
3610
3787
  if stat.S_ISREG(mode) and st.st_nlink > 1:
3611
3788
  raise OSError(errno.EPERM, "hardlinked file endpoint is not allowed")
3612
-
3613
3789
  def copy_bytes(source_fd, dest_fd):
3614
3790
  while True:
3615
3791
  chunk = os.read(source_fd, 65536)
@@ -3621,7 +3797,6 @@ def copy_bytes(source_fd, dest_fd):
3621
3797
  if written <= 0:
3622
3798
  raise OSError(errno.EIO, "short write")
3623
3799
  view = view[written:]
3624
-
3625
3800
  def write_all(fd, data):
3626
3801
  view = memoryview(data)
3627
3802
  while view:
@@ -3629,11 +3804,9 @@ def write_all(fd, data):
3629
3804
  if written <= 0:
3630
3805
  raise OSError(errno.EIO, "short write")
3631
3806
  view = view[written:]
3632
-
3633
3807
  def link_unsupported(exc):
3634
3808
  unsupported = (errno.EPERM, errno.EOPNOTSUPP, getattr(errno, "ENOTSUP", errno.EOPNOTSUPP))
3635
3809
  return getattr(exc, "errno", None) in unsupported
3636
-
3637
3810
  def link_no_replace(name, new_name, source_fd, target_fd):
3638
3811
  linked = False
3639
3812
  try:
@@ -3648,11 +3821,9 @@ def link_no_replace(name, new_name, source_fd, target_fd):
3648
3821
  os.fsync(source_fd)
3649
3822
  if source_fd != target_fd:
3650
3823
  os.fsync(target_fd)
3651
-
3652
3824
  def copy_file_no_replace(source_parent_fd, source_name, target_parent_fd, basename, mode, expected=None, unlink_source=False):
3653
3825
  source_fd = os.open(source_name, READ_FLAGS, dir_fd=source_parent_fd)
3654
- dest_fd = None
3655
- success = False
3826
+ dest_fd = None; success = False; dest_stat = None
3656
3827
  try:
3657
3828
  if expected is not None:
3658
3829
  source_stat = os.fstat(source_fd)
@@ -3661,6 +3832,7 @@ def copy_file_no_replace(source_parent_fd, source_name, target_parent_fd, basena
3661
3832
  dest_fd = os.open(basename, WRITE_FLAGS, mode, dir_fd=target_parent_fd)
3662
3833
  copy_bytes(source_fd, dest_fd)
3663
3834
  os.fsync(dest_fd)
3835
+ dest_stat = os.fstat(dest_fd)
3664
3836
  success = True
3665
3837
  finally:
3666
3838
  os.close(source_fd)
@@ -3676,19 +3848,40 @@ def copy_file_no_replace(source_parent_fd, source_name, target_parent_fd, basena
3676
3848
  try: os.unlink(basename, dir_fd=target_parent_fd)
3677
3849
  except FileNotFoundError: pass
3678
3850
  raise
3679
-
3680
- def commit_temp_file(parent_fd, temp_name, basename, overwrite, mode):
3851
+ return dest_stat
3852
+ def same_identity(left, right):
3853
+ return left.st_dev == right.st_dev and left.st_ino == right.st_ino
3854
+ def verify_temp_name(parent_fd, temp_name, expected_stat):
3855
+ current_stat = os.lstat(temp_name, dir_fd=parent_fd)
3856
+ if stat.S_ISLNK(current_stat.st_mode) or not same_identity(current_stat, expected_stat):
3857
+ raise RuntimeError("fs-safe-temp-mismatch")
3858
+ def verify_committed_temp(parent_fd, basename, expected_stat):
3859
+ final_stat = os.lstat(basename, dir_fd=parent_fd)
3860
+ if not stat.S_ISLNK(final_stat.st_mode) and same_identity(final_stat, expected_stat):
3861
+ return final_stat
3862
+ try: os.unlink(basename, dir_fd=parent_fd)
3863
+ except FileNotFoundError: pass
3864
+ raise RuntimeError("fs-safe-temp-mismatch")
3865
+ def commit_temp_file(parent_fd, temp_name, basename, overwrite, mode, expected_stat):
3866
+ verify_temp_name(parent_fd, temp_name, expected_stat)
3681
3867
  if overwrite:
3682
3868
  os.replace(temp_name, basename, src_dir_fd=parent_fd, dst_dir_fd=parent_fd)
3869
+ return verify_committed_temp(parent_fd, basename, expected_stat)
3683
3870
  else:
3684
3871
  try:
3685
3872
  os.link(temp_name, basename, src_dir_fd=parent_fd, dst_dir_fd=parent_fd, follow_symlinks=False)
3873
+ final_stat = verify_committed_temp(parent_fd, basename, expected_stat)
3686
3874
  os.unlink(temp_name, dir_fd=parent_fd)
3875
+ return final_stat
3687
3876
  except OSError as exc:
3688
3877
  if not link_unsupported(exc):
3689
3878
  raise
3690
- copy_file_no_replace(parent_fd, temp_name, parent_fd, basename, mode, unlink_source=True)
3691
-
3879
+ return copy_file_no_replace(parent_fd, temp_name, parent_fd, basename, mode, expected_stat, True)
3880
+ def assert_expected_root(root_fd, payload):
3881
+ if "rootDev" in payload or "rootIno" in payload:
3882
+ root_stat = os.fstat(root_fd)
3883
+ if root_stat.st_dev != int(payload["rootDev"]) or root_stat.st_ino != int(payload["rootIno"]):
3884
+ raise RuntimeError("fs-safe-root-mismatch")
3692
3885
  def stat_path(root_fd, payload):
3693
3886
  relative = payload.get("relativePath", "")
3694
3887
  segments = split_relative(relative)
@@ -3702,7 +3895,6 @@ def stat_path(root_fd, payload):
3702
3895
  return encode_stat(st)
3703
3896
  finally:
3704
3897
  os.close(parent_fd)
3705
-
3706
3898
  def readdir_path(root_fd, payload):
3707
3899
  dir_fd = walk_dir(root_fd, split_relative(payload.get("relativePath", "")))
3708
3900
  try:
@@ -3718,12 +3910,9 @@ def readdir_path(root_fd, payload):
3718
3910
  return entries
3719
3911
  finally:
3720
3912
  os.close(dir_fd)
3721
-
3722
3913
  def mkdirp_path(root_fd, payload):
3723
3914
  dir_fd = walk_dir(root_fd, split_relative(payload.get("relativePath", "")), mkdir_enabled=True)
3724
- os.close(dir_fd)
3725
- return None
3726
-
3915
+ os.close(dir_fd); return None
3727
3916
  def remove_tree(parent_fd, basename):
3728
3917
  st = os.lstat(basename, dir_fd=parent_fd)
3729
3918
  if stat.S_ISDIR(st.st_mode) and not stat.S_ISLNK(st.st_mode):
@@ -3736,7 +3925,6 @@ def remove_tree(parent_fd, basename):
3736
3925
  os.rmdir(basename, dir_fd=parent_fd)
3737
3926
  else:
3738
3927
  os.unlink(basename, dir_fd=parent_fd)
3739
-
3740
3928
  def remove_path(root_fd, payload):
3741
3929
  parent_fd, basename = parent_and_basename(root_fd, payload.get("relativePath", ""))
3742
3930
  try:
@@ -3819,14 +4007,15 @@ def write_path(root_fd, payload):
3819
4007
  except FileNotFoundError:
3820
4008
  pass
3821
4009
  temp_name, temp_fd = create_temp_file(parent_fd, basename, mode)
4010
+ os.fchmod(temp_fd, mode)
3822
4011
  write_all(temp_fd, data)
3823
4012
  os.fsync(temp_fd)
4013
+ temp_stat = os.fstat(temp_fd)
3824
4014
  os.close(temp_fd)
3825
4015
  temp_fd = None
3826
- commit_temp_file(parent_fd, temp_name, basename, overwrite, mode)
4016
+ result_stat = commit_temp_file(parent_fd, temp_name, basename, overwrite, mode, temp_stat)
3827
4017
  temp_name = None
3828
4018
  os.fsync(parent_fd)
3829
- result_stat = os.stat(basename, dir_fd=parent_fd, follow_symlinks=False)
3830
4019
  return {"dev": result_stat.st_dev, "ino": result_stat.st_ino}
3831
4020
  finally:
3832
4021
  if temp_fd is not None:
@@ -3857,6 +4046,7 @@ def copy_path(root_fd, payload):
3857
4046
  raise RuntimeError("fs-safe-too-large:%d:%d" % (max_bytes, source_stat.st_size))
3858
4047
  parent_fd = walk_dir(root_fd, split_relative(payload.get("relativeParentPath", "")), bool(payload.get("mkdir", True)))
3859
4048
  temp_name, temp_fd = create_temp_file(parent_fd, basename, mode)
4049
+ os.fchmod(temp_fd, mode)
3860
4050
  written_bytes = 0
3861
4051
  while True:
3862
4052
  chunk = os.read(source_fd, 65536)
@@ -3872,12 +4062,12 @@ def copy_path(root_fd, payload):
3872
4062
  raise OSError(errno.EIO, "short write")
3873
4063
  view = view[written:]
3874
4064
  os.fsync(temp_fd)
4065
+ temp_stat = os.fstat(temp_fd)
3875
4066
  os.close(temp_fd)
3876
4067
  temp_fd = None
3877
- commit_temp_file(parent_fd, temp_name, basename, overwrite, mode)
4068
+ result_stat = commit_temp_file(parent_fd, temp_name, basename, overwrite, mode, temp_stat)
3878
4069
  temp_name = None
3879
4070
  os.fsync(parent_fd)
3880
- result_stat = os.stat(basename, dir_fd=parent_fd, follow_symlinks=False)
3881
4071
  return {"dev": result_stat.st_dev, "ino": result_stat.st_ino}
3882
4072
  finally:
3883
4073
  os.close(source_fd)
@@ -3894,6 +4084,7 @@ def copy_path(root_fd, payload):
3894
4084
  def run_operation(operation, root_path, payload):
3895
4085
  root_fd = open_dir(root_path)
3896
4086
  try:
4087
+ assert_expected_root(root_fd, payload)
3897
4088
  if operation == "stat":
3898
4089
  return stat_path(root_fd, payload)
3899
4090
  if operation == "readdir":
@@ -3998,6 +4189,12 @@ function mapWorkerError(response) {
3998
4189
  if (message.includes("fs-safe-source-mismatch")) {
3999
4190
  return new errors_FsSafeError("path-mismatch", "source path changed during copy");
4000
4191
  }
4192
+ if (message.includes("fs-safe-temp-mismatch")) {
4193
+ return new errors_FsSafeError("path-mismatch", "temp path changed during write");
4194
+ }
4195
+ if (message.includes("fs-safe-root-mismatch")) {
4196
+ return new errors_FsSafeError("path-mismatch", "root path changed during operation");
4197
+ }
4001
4198
  if (message.includes("fs-safe-directory-noreplace-unsupported")) {
4002
4199
  return new errors_FsSafeError("invalid-path", "directory moves require overwrite: true");
4003
4200
  }
@@ -4178,9 +4375,7 @@ function validatePinnedOperationPayload(payload) {
4178
4375
  }
4179
4376
  }
4180
4377
  function isPinnedHelperUnavailable(error) {
4181
- return error instanceof Error &&
4182
- "code" in error &&
4183
- error.code === "helper-unavailable";
4378
+ return error instanceof Error && "code" in error && error.code === "helper-unavailable";
4184
4379
  }
4185
4380
  function validatePinnedRelativePath(relativePath) {
4186
4381
  if (relativePath.length === 0 || relativePath === ".") {
@@ -4278,29 +4473,21 @@ function assertWithinMaxBytes(bytes, maxBytes) {
4278
4473
  throw new errors_FsSafeError("too-large", `file exceeds limit of ${maxBytes} bytes (got at least ${bytes})`);
4279
4474
  }
4280
4475
  }
4281
- function pinned_write_createMaxBytesTransform(maxBytes) {
4282
- if (maxBytes === undefined) {
4283
- return undefined;
4284
- }
4476
+ async function writeStreamToHandle(stream, handle, maxBytes) {
4285
4477
  let bytes = 0;
4286
- return new external_node_stream_.Transform({
4287
- transform(chunk, _encoding, callback) {
4288
- bytes += chunk.byteLength;
4289
- if (bytes > maxBytes) {
4290
- callback(new errors_FsSafeError("too-large", `file exceeds limit of ${maxBytes} bytes (got at least ${bytes})`));
4291
- return;
4478
+ for await (const chunk of stream) {
4479
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
4480
+ bytes += buffer.byteLength;
4481
+ assertWithinMaxBytes(bytes, maxBytes);
4482
+ let offset = 0;
4483
+ while (offset < buffer.byteLength) {
4484
+ const { bytesWritten } = await handle.write(buffer, offset, buffer.byteLength - offset);
4485
+ if (bytesWritten <= 0) {
4486
+ throw new errors_FsSafeError("helper-failed", "fallback stream write made no progress");
4292
4487
  }
4293
- callback(null, chunk);
4294
- },
4295
- });
4296
- }
4297
- async function pipelineWithMaxBytes(stream, destination, maxBytes) {
4298
- const limiter = pinned_write_createMaxBytesTransform(maxBytes);
4299
- if (limiter) {
4300
- await (0,external_node_stream_promises_.pipeline)(stream, limiter, destination);
4301
- return;
4488
+ offset += bytesWritten;
4489
+ }
4302
4490
  }
4303
- await (0,external_node_stream_promises_.pipeline)(stream, destination);
4304
4491
  }
4305
4492
  async function inputToBase64(input, maxBytes) {
4306
4493
  if (input.kind === "buffer") {
@@ -4346,6 +4533,7 @@ async function runPinnedWriteHelper(params) {
4346
4533
  mode: params.mode || 0o600,
4347
4534
  overwrite: params.overwrite !== false,
4348
4535
  relativeParentPath: params.relativeParentPath,
4536
+ ...(params.rootIdentity ? { rootDev: params.rootIdentity.dev, rootIno: params.rootIdentity.ino } : {}),
4349
4537
  };
4350
4538
  try {
4351
4539
  return await runPinnedPythonOperation({
@@ -4376,6 +4564,7 @@ async function runPinnedCopyHelper(params) {
4376
4564
  mode: params.mode || 0o600,
4377
4565
  overwrite: params.overwrite !== false,
4378
4566
  relativeParentPath: params.relativeParentPath,
4567
+ ...(params.rootIdentity ? { rootDev: params.rootIdentity.dev, rootIno: params.rootIdentity.ino } : {}),
4379
4568
  sourceDev: params.sourceIdentity.dev,
4380
4569
  sourceIno: params.sourceIdentity.ino,
4381
4570
  sourcePath: params.sourcePath,
@@ -4386,12 +4575,12 @@ async function runPinnedWriteFallback(params) {
4386
4575
  const parentPath = params.relativeParentPath
4387
4576
  ? external_node_path_.join(params.rootPath, ...params.relativeParentPath.split("/"))
4388
4577
  : params.rootPath;
4389
- const parentGuard = await directory_guard_createNearestExistingDirectoryGuard(params.rootPath, parentPath);
4390
4578
  if (params.mkdir) {
4391
- await withAsyncDirectoryGuards([parentGuard], async () => {
4392
- await promises_.mkdir(parentPath, { recursive: true });
4393
- });
4579
+ await mkdirPathComponentsWithGuards({ rootReal: params.rootPath, targetPath: parentPath });
4394
4580
  }
4581
+ const parentGuard = params.mkdir
4582
+ ? await directory_guard_createAsyncDirectoryGuard(parentPath)
4583
+ : await directory_guard_createNearestExistingDirectoryGuard(params.rootPath, parentPath);
4395
4584
  const targetPath = external_node_path_.join(parentPath, params.basename);
4396
4585
  if (params.overwrite === false) {
4397
4586
  let handle = await withAsyncDirectoryGuards([parentGuard], async () => await promises_.open(targetPath, external_node_fs_.constants.O_WRONLY | external_node_fs_.constants.O_CREAT | external_node_fs_.constants.O_EXCL, params.mode), {
@@ -4413,7 +4602,7 @@ async function runPinnedWriteFallback(params) {
4413
4602
  }
4414
4603
  }
4415
4604
  else {
4416
- await pipelineWithMaxBytes(params.input.stream, handle.createWriteStream(), params.maxBytes);
4605
+ await writeStreamToHandle(params.input.stream, handle, params.maxBytes);
4417
4606
  }
4418
4607
  const stat = await handle.stat();
4419
4608
  created = false;
@@ -4434,7 +4623,9 @@ async function runPinnedWriteFallback(params) {
4434
4623
  ? external_node_fs_.constants.O_NOFOLLOW
4435
4624
  : 0);
4436
4625
  let handle;
4437
- let handleClosedByStream = false;
4626
+ let tempStat;
4627
+ let targetStat;
4628
+ let renamed = false;
4438
4629
  try {
4439
4630
  handle = await promises_.open(tempPath, tempFlags, params.mode);
4440
4631
  if (params.input.kind === "buffer") {
@@ -4447,29 +4638,36 @@ async function runPinnedWriteFallback(params) {
4447
4638
  }
4448
4639
  }
4449
4640
  else {
4450
- const writable = handle.createWriteStream();
4451
- writable.once("close", () => {
4452
- handleClosedByStream = true;
4453
- });
4454
- await pipelineWithMaxBytes(params.input.stream, writable, params.maxBytes);
4641
+ await writeStreamToHandle(params.input.stream, handle, params.maxBytes);
4455
4642
  }
4456
- if (!handleClosedByStream) {
4457
- await handle.close().catch(() => undefined);
4458
- handle = undefined;
4643
+ tempStat = await handle.stat();
4644
+ const tempPathStat = await promises_.lstat(tempPath);
4645
+ if (tempPathStat.isSymbolicLink() || !file_identity_sameFileIdentity(tempPathStat, tempStat)) {
4646
+ throw new errors_FsSafeError("path-mismatch", "fallback temp path changed during write");
4459
4647
  }
4648
+ const expectedTempStat = tempStat;
4649
+ await handle.close().catch(() => undefined);
4650
+ handle = undefined;
4460
4651
  await withAsyncDirectoryGuards([parentGuard], async () => {
4461
4652
  await promises_.rename(tempPath, targetPath);
4653
+ renamed = true;
4654
+ targetStat = await promises_.lstat(targetPath);
4655
+ if (targetStat.isSymbolicLink() || !file_identity_sameFileIdentity(targetStat, expectedTempStat)) {
4656
+ throw new errors_FsSafeError("path-mismatch", "fallback target changed during write");
4657
+ }
4462
4658
  });
4463
4659
  }
4464
4660
  catch (error) {
4465
- if (handle && !handleClosedByStream) {
4466
- await handle.close().catch(() => undefined);
4661
+ await handle?.close().catch(() => undefined);
4662
+ if (!renamed) {
4663
+ await promises_.rm(tempPath, { force: true }).catch(() => undefined);
4467
4664
  }
4468
- await promises_.rm(tempPath, { force: true }).catch(() => undefined);
4469
4665
  throw error;
4470
4666
  }
4471
- const stat = await promises_.stat(targetPath);
4472
- return { dev: stat.dev, ino: stat.ino };
4667
+ if (!targetStat) {
4668
+ throw new errors_FsSafeError("path-mismatch", "fallback target was not verified");
4669
+ }
4670
+ return { dev: targetStat.dev, ino: targetStat.ino };
4473
4671
  }
4474
4672
 
4475
4673
  // EXTERNAL MODULE: external "node:os"
@@ -4495,7 +4693,7 @@ async function resolveRootPath(params) {
4495
4693
  const absolutePath = external_node_path_.resolve(params.absolutePath);
4496
4694
  const rootCanonicalPath = params.rootCanonicalPath
4497
4695
  ? external_node_path_.resolve(params.rootCanonicalPath)
4498
- : await resolvePathViaExistingAncestor(rootPath);
4696
+ : await root_path_resolvePathViaExistingAncestor(rootPath);
4499
4697
  const context = createBoundaryResolutionContext({
4500
4698
  resolveParams: params,
4501
4699
  rootPath,
@@ -4864,7 +5062,7 @@ async function resolveOutsideLexicalCanonicalPathAsync(params) {
4864
5062
  if (path_isPathInside(params.rootPath, params.absolutePath)) {
4865
5063
  return undefined;
4866
5064
  }
4867
- return await resolvePathViaExistingAncestor(params.absolutePath);
5065
+ return await root_path_resolvePathViaExistingAncestor(params.absolutePath);
4868
5066
  }
4869
5067
  function resolveOutsideLexicalCanonicalPathSync(params) {
4870
5068
  if (isPathInside(params.rootPath, params.absolutePath)) {
@@ -4911,11 +5109,11 @@ function buildResolvedRootPath(params) {
4911
5109
  kind: params.kind.kind,
4912
5110
  };
4913
5111
  }
4914
- async function resolvePathViaExistingAncestor(targetPath) {
5112
+ async function root_path_resolvePathViaExistingAncestor(targetPath) {
4915
5113
  const normalized = external_node_path_.resolve(targetPath);
4916
5114
  let cursor = normalized;
4917
5115
  const missingSuffix = [];
4918
- while (!isFilesystemRoot(cursor) && !(await pathExists(cursor))) {
5116
+ while (!isFilesystemRoot(cursor) && !(await root_path_pathExists(cursor))) {
4919
5117
  missingSuffix.unshift(external_node_path_.basename(cursor));
4920
5118
  const parent = external_node_path_.dirname(cursor);
4921
5119
  if (parent === cursor) {
@@ -4923,7 +5121,7 @@ async function resolvePathViaExistingAncestor(targetPath) {
4923
5121
  }
4924
5122
  cursor = parent;
4925
5123
  }
4926
- if (!(await pathExists(cursor))) {
5124
+ if (!(await root_path_pathExists(cursor))) {
4927
5125
  return normalized;
4928
5126
  }
4929
5127
  try {
@@ -5008,7 +5206,7 @@ function relativeInsideRoot(rootPath, targetPath) {
5008
5206
  if (!relative || relative === ".") {
5009
5207
  return "";
5010
5208
  }
5011
- if (relative.startsWith("..") || external_node_path_.isAbsolute(relative)) {
5209
+ if (isPathRelativeEscape(relative)) {
5012
5210
  return "";
5013
5211
  }
5014
5212
  return relative;
@@ -5035,7 +5233,7 @@ function shortPath(value) {
5035
5233
  function isFilesystemRoot(candidate) {
5036
5234
  return external_node_path_.parse(candidate).root === candidate;
5037
5235
  }
5038
- async function pathExists(targetPath) {
5236
+ async function root_path_pathExists(targetPath) {
5039
5237
  try {
5040
5238
  await promises_.lstat(targetPath);
5041
5239
  return true;
@@ -5057,7 +5255,7 @@ async function resolveSymlinkHopPath(symlinkPath) {
5057
5255
  }
5058
5256
  const linkTarget = await promises_.readlink(symlinkPath);
5059
5257
  const linkAbsolute = external_node_path_.resolve(external_node_path_.dirname(symlinkPath), linkTarget);
5060
- return resolvePathViaExistingAncestor(linkAbsolute);
5258
+ return root_path_resolvePathViaExistingAncestor(linkAbsolute);
5061
5259
  }
5062
5260
  }
5063
5261
  function resolveSymlinkHopPathSync(symlinkPath) {
@@ -5126,6 +5324,23 @@ function path_policy_shortPath(value) {
5126
5324
  return value;
5127
5325
  }
5128
5326
 
5327
+ ;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/read-opened-file.js
5328
+
5329
+ async function read_opened_file_readOpenedFileSafely(params) {
5330
+ if (params.maxBytes !== undefined && params.opened.stat.size > params.maxBytes) {
5331
+ throw new errors_FsSafeError("too-large", `file exceeds limit of ${params.maxBytes} bytes (got ${params.opened.stat.size})`);
5332
+ }
5333
+ const buffer = await params.opened.handle.readFile();
5334
+ if (params.maxBytes !== undefined && buffer.byteLength > params.maxBytes) {
5335
+ throw new errors_FsSafeError("too-large", `file exceeds limit of ${params.maxBytes} bytes (got ${buffer.byteLength})`);
5336
+ }
5337
+ return {
5338
+ buffer,
5339
+ realPath: params.opened.realPath,
5340
+ stat: params.opened.stat,
5341
+ };
5342
+ }
5343
+
5129
5344
  ;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/path-stat.js
5130
5345
  function pathStatFromStats(stat) {
5131
5346
  return {
@@ -5453,6 +5668,10 @@ async function serializePathWrite(key, run) {
5453
5668
 
5454
5669
 
5455
5670
 
5671
+
5672
+
5673
+
5674
+
5456
5675
 
5457
5676
 
5458
5677
 
@@ -5651,6 +5870,7 @@ class RootHandle {
5651
5870
  mkdir: this.defaults.mkdir,
5652
5871
  mode: this.defaults.mode,
5653
5872
  ...options,
5873
+ denyMutations: mergeDenyMutationPolicies(this.defaults.denyMutations, options.denyMutations),
5654
5874
  append: writeMode === "append",
5655
5875
  truncateExisting: writeMode === "replace",
5656
5876
  });
@@ -5662,18 +5882,29 @@ class RootHandle {
5662
5882
  mkdir: this.defaults.mkdir,
5663
5883
  mode: this.defaults.mode,
5664
5884
  ...options,
5885
+ denyMutations: mergeDenyMutationPolicies(this.defaults.denyMutations, options.denyMutations),
5665
5886
  });
5666
5887
  }
5667
- async remove(relativePath) {
5888
+ async remove(relativePath, options = {}) {
5668
5889
  assertValidRootRelativePath(relativePath);
5669
- await removePathInRoot(this.context, relativePath);
5890
+ await removePathInRoot(this.context, {
5891
+ relativePath,
5892
+ denyMutations: mergeDenyMutationPolicies(this.defaults.denyMutations, options.denyMutations),
5893
+ });
5670
5894
  }
5671
- async mkdir(relativePath) {
5895
+ async mkdir(relativePath, options = {}) {
5672
5896
  assertValidRootRelativePath(relativePath);
5673
- await mkdirPathInRoot(this.context, { relativePath });
5897
+ await mkdirPathInRoot(this.context, {
5898
+ relativePath,
5899
+ denyMutations: mergeDenyMutationPolicies(this.defaults.denyMutations, options.denyMutations),
5900
+ });
5674
5901
  }
5675
- async ensureRoot() {
5676
- await mkdirPathInRoot(this.context, { relativePath: "", allowRoot: true });
5902
+ async ensureRoot(options = {}) {
5903
+ await mkdirPathInRoot(this.context, {
5904
+ relativePath: "",
5905
+ allowRoot: true,
5906
+ denyMutations: mergeDenyMutationPolicies(this.defaults.denyMutations, options.denyMutations),
5907
+ });
5677
5908
  }
5678
5909
  async write(relativePath, data, options = {}) {
5679
5910
  await writeFileInRoot(this.context, {
@@ -5682,6 +5913,7 @@ class RootHandle {
5682
5913
  mkdir: this.defaults.mkdir,
5683
5914
  mode: this.defaults.mode,
5684
5915
  ...options,
5916
+ denyMutations: mergeDenyMutationPolicies(this.defaults.denyMutations, options.denyMutations),
5685
5917
  });
5686
5918
  }
5687
5919
  async create(relativePath, data, options = {}) {
@@ -5691,6 +5923,7 @@ class RootHandle {
5691
5923
  mkdir: this.defaults.mkdir,
5692
5924
  mode: this.defaults.mode,
5693
5925
  ...options,
5926
+ denyMutations: mergeDenyMutationPolicies(this.defaults.denyMutations, options.denyMutations),
5694
5927
  overwrite: false,
5695
5928
  });
5696
5929
  }
@@ -5713,6 +5946,7 @@ class RootHandle {
5713
5946
  mkdir: this.defaults.mkdir,
5714
5947
  mode: this.defaults.mode,
5715
5948
  ...options,
5949
+ denyMutations: mergeDenyMutationPolicies(this.defaults.denyMutations, options.denyMutations),
5716
5950
  });
5717
5951
  }
5718
5952
  async exists(relativePath) {
@@ -5756,6 +5990,12 @@ class RootHandle {
5756
5990
  async move(fromRelative, toRelative, options = {}) {
5757
5991
  assertValidRootRelativePath(fromRelative);
5758
5992
  assertValidRootRelativePath(toRelative);
5993
+ const denyMutations = mergeDenyMutationPolicies(this.defaults.denyMutations, options.denyMutations);
5994
+ await assertMoveMutationAllowed(this.context, {
5995
+ fromRelative,
5996
+ toRelative,
5997
+ denyMutations,
5998
+ });
5759
5999
  try {
5760
6000
  await runPinnedHelper("rename", this.rootReal, {
5761
6001
  from: fromRelative,
@@ -5767,6 +6007,7 @@ class RootHandle {
5767
6007
  if (canFallbackFromPythonError(error)) {
5768
6008
  await movePathFallback(this.context, {
5769
6009
  fromRelative,
6010
+ denyMutations,
5770
6011
  overwrite: options.overwrite ?? false,
5771
6012
  toRelative,
5772
6013
  });
@@ -5815,7 +6056,7 @@ async function openFileInRoot(root, params) {
5815
6056
  async function readFileInRoot(root, params) {
5816
6057
  const opened = await openFileInRoot(root, params);
5817
6058
  try {
5818
- return await readOpenedFileSafely({ opened, maxBytes: params.maxBytes });
6059
+ return await read_opened_file_readOpenedFileSafely({ opened, maxBytes: params.maxBytes });
5819
6060
  }
5820
6061
  finally {
5821
6062
  await opened.handle.close().catch(() => { });
@@ -5848,20 +6089,6 @@ async function openLocalFileSafely(params) {
5848
6089
  assertNoNulPathInput(params.filePath, "file path contains a NUL byte");
5849
6090
  return await openVerifiedLocalFile(params.filePath);
5850
6091
  }
5851
- async function readOpenedFileSafely(params) {
5852
- if (params.maxBytes !== undefined && params.opened.stat.size > params.maxBytes) {
5853
- throw new errors_FsSafeError("too-large", `file exceeds limit of ${params.maxBytes} bytes (got ${params.opened.stat.size})`);
5854
- }
5855
- const buffer = await params.opened.handle.readFile();
5856
- if (params.maxBytes !== undefined && buffer.byteLength > params.maxBytes) {
5857
- throw new errors_FsSafeError("too-large", `file exceeds limit of ${params.maxBytes} bytes (got ${buffer.byteLength})`);
5858
- }
5859
- return {
5860
- buffer,
5861
- realPath: params.opened.realPath,
5862
- stat: params.opened.stat,
5863
- };
5864
- }
5865
6092
  function emitWriteBoundaryWarning(reason) {
5866
6093
  logWarn(`security: fs-safe write boundary warning (${reason})`);
5867
6094
  }
@@ -5902,82 +6129,9 @@ async function verifyAtomicWriteResult(params) {
5902
6129
  await opened.handle.close().catch(() => { });
5903
6130
  }
5904
6131
  }
5905
- async function resolveOpenedFileRealPathForHandle(handle, ioPath) {
5906
- const handleStat = await handle.stat();
5907
- const fdCandidates = process.platform === "linux"
5908
- ? [`/proc/self/fd/${handle.fd}`, `/dev/fd/${handle.fd}`]
5909
- : process.platform === "win32"
5910
- ? []
5911
- : [`/dev/fd/${handle.fd}`];
5912
- for (const fdPath of fdCandidates) {
5913
- try {
5914
- const fdRealPath = await promises_.realpath(fdPath);
5915
- const fdRealStat = await promises_.stat(fdRealPath);
5916
- if (file_identity_sameFileIdentity(handleStat, fdRealStat)) {
5917
- return fdRealPath;
5918
- }
5919
- }
5920
- catch {
5921
- // try next fd path
5922
- }
5923
- }
5924
- try {
5925
- const ioRealPath = await promises_.realpath(ioPath);
5926
- const ioRealStat = await promises_.stat(ioRealPath);
5927
- if (file_identity_sameFileIdentity(handleStat, ioRealStat)) {
5928
- return ioRealPath;
5929
- }
5930
- }
5931
- catch (err) {
5932
- if (!path_isNotFoundPathError(err)) {
5933
- throw err;
5934
- }
5935
- }
5936
- const parentResolved = await resolveOpenedFileRealPathFromParent(handleStat, ioPath);
5937
- if (parentResolved) {
5938
- return parentResolved;
5939
- }
5940
- throw new errors_FsSafeError("path-mismatch", "unable to resolve opened file path");
5941
- }
5942
- async function resolveOpenedFileRealPathFromParent(handleStat, ioPath) {
5943
- let parentReal;
5944
- try {
5945
- parentReal = await promises_.realpath(external_node_path_.dirname(ioPath));
5946
- }
5947
- catch (err) {
5948
- if (path_isNotFoundPathError(err)) {
5949
- return null;
5950
- }
5951
- throw err;
5952
- }
5953
- let entries;
5954
- try {
5955
- entries = await promises_.readdir(parentReal);
5956
- }
5957
- catch (err) {
5958
- if (path_isNotFoundPathError(err)) {
5959
- return null;
5960
- }
5961
- throw err;
5962
- }
5963
- for (const entry of entries.toSorted()) {
5964
- const candidatePath = external_node_path_.join(parentReal, entry);
5965
- try {
5966
- const candidateStat = await promises_.lstat(candidatePath);
5967
- if (candidateStat.isFile() && file_identity_sameFileIdentity(handleStat, candidateStat)) {
5968
- return await promises_.realpath(candidatePath);
5969
- }
5970
- }
5971
- catch (err) {
5972
- if (!path_isNotFoundPathError(err)) {
5973
- throw err;
5974
- }
5975
- }
5976
- }
5977
- return null;
5978
- }
5979
6132
  async function openWritableFileInRoot(root, params) {
5980
6133
  const { rootReal, rootWithSep, resolved } = await resolvePathInRoot(root, params.relativePath);
6134
+ await assertMutationNotDenied(resolved, params.denyMutations);
5981
6135
  try {
5982
6136
  await assertNoPathAliasEscape({
5983
6137
  absolutePath: resolved,
@@ -6104,6 +6258,7 @@ async function appendFileInRoot(root, params) {
6104
6258
  relativePath: params.relativePath,
6105
6259
  mkdir: params.mkdir,
6106
6260
  mode: params.mode,
6261
+ denyMutations: params.denyMutations,
6107
6262
  truncateExisting: false,
6108
6263
  append: true,
6109
6264
  });
@@ -6131,8 +6286,8 @@ async function appendFileInRoot(root, params) {
6131
6286
  await target.handle.close().catch(() => { });
6132
6287
  }
6133
6288
  }
6134
- async function removePathInRoot(root, relativePath) {
6135
- const resolved = await resolvePinnedRemovePathInRoot(root, relativePath);
6289
+ async function removePathInRoot(root, params) {
6290
+ const resolved = await resolvePinnedRemovePathInRoot(root, params.relativePath, params.denyMutations);
6136
6291
  if (process.platform === "win32") {
6137
6292
  await removePathFallback(resolved);
6138
6293
  return;
@@ -6180,7 +6335,7 @@ async function writeFileInRoot(root, params) {
6180
6335
  });
6181
6336
  return;
6182
6337
  }
6183
- const pinned = await resolvePinnedWriteTargetInRoot(root, params.relativePath, params.mode);
6338
+ const pinned = await resolvePinnedWriteTargetInRoot(root, params.relativePath, params.mode, params.denyMutations);
6184
6339
  await serializePathWrite(pinned.targetPath, async () => {
6185
6340
  let identity;
6186
6341
  try {
@@ -6236,7 +6391,7 @@ async function copyFileInRoot(root, params) {
6236
6391
  });
6237
6392
  return;
6238
6393
  }
6239
- const pinned = await resolvePinnedWriteTargetInRoot(root, params.relativePath, params.mode);
6394
+ const pinned = await resolvePinnedWriteTargetInRoot(root, params.relativePath, params.mode, params.denyMutations);
6240
6395
  await serializePathWrite(pinned.targetPath, async () => {
6241
6396
  let identity;
6242
6397
  try {
@@ -6280,8 +6435,9 @@ async function copyFileInRoot(root, params) {
6280
6435
  await source.handle.close().catch(() => { });
6281
6436
  }
6282
6437
  }
6283
- async function resolvePinnedWriteTargetInRoot(root, relativePath, requestedMode) {
6438
+ async function resolvePinnedWriteTargetInRoot(root, relativePath, requestedMode, denyMutations) {
6284
6439
  const { rootReal, rootWithSep, resolved } = await resolvePathInRoot(root, relativePath);
6440
+ await assertMutationNotDenied(resolved, denyMutations);
6285
6441
  try {
6286
6442
  await assertNoPathAliasEscape({
6287
6443
  absolutePath: resolved,
@@ -6338,12 +6494,16 @@ async function resolvePinnedWriteTargetInRoot(root, relativePath, requestedMode)
6338
6494
  async function resolvePinnedPathInRoot(root, params) {
6339
6495
  return await resolvePinnedOperationPathInRoot(root, {
6340
6496
  allowRoot: params.allowRoot,
6497
+ denyMutations: params.denyMutations,
6498
+ protectDenyMutationAncestors: false,
6341
6499
  relativePath: params.relativePath,
6342
6500
  policy: PATH_ALIAS_POLICIES.strict,
6343
6501
  });
6344
6502
  }
6345
- async function resolvePinnedRemovePathInRoot(root, relativePath) {
6503
+ async function resolvePinnedRemovePathInRoot(root, relativePath, denyMutations) {
6346
6504
  return await resolvePinnedOperationPathInRoot(root, {
6505
+ denyMutations,
6506
+ protectDenyMutationAncestors: true,
6347
6507
  relativePath,
6348
6508
  policy: PATH_ALIAS_POLICIES.unlinkTarget,
6349
6509
  });
@@ -6355,6 +6515,7 @@ async function resolvePinnedOperationPathInRoot(root, params) {
6355
6515
  });
6356
6516
  const relativeResolved = external_node_path_.relative(resolved.rootReal, resolved.canonicalPath);
6357
6517
  if ((relativeResolved === "" || relativeResolved === ".") && params.allowRoot === true) {
6518
+ await assertMutationNotDenied(resolved.canonicalPath, params.denyMutations);
6358
6519
  return { rootReal: resolved.rootReal, resolved: resolved.canonicalPath, relativePosix: "" };
6359
6520
  }
6360
6521
  const firstSegment = relativeResolved.split(external_node_path_.sep)[0];
@@ -6368,6 +6529,9 @@ async function resolvePinnedOperationPathInRoot(root, params) {
6368
6529
  if (!path_isPathInside(resolved.rootWithSep, resolved.canonicalPath)) {
6369
6530
  throw new errors_FsSafeError("outside-workspace", "file is outside workspace root");
6370
6531
  }
6532
+ await assertMutationNotDenied(resolved.canonicalPath, params.denyMutations, {
6533
+ protectAncestors: params.protectDenyMutationAncestors,
6534
+ });
6371
6535
  return { rootReal: resolved.rootReal, resolved: resolved.canonicalPath, relativePosix };
6372
6536
  }
6373
6537
  async function resolvePinnedRootPathInRoot(root, params) {
@@ -6445,13 +6609,21 @@ async function listPathFallback(root, relativePath, withFileTypes) {
6445
6609
  throw error;
6446
6610
  }
6447
6611
  }
6612
+ async function assertMoveMutationAllowed(root, params) {
6613
+ const source = await resolvePathInRoot(root, params.fromRelative);
6614
+ await assertMutationNotDenied(source.resolved, params.denyMutations, { protectAncestors: true });
6615
+ const target = await resolvePathInRoot(root, params.toRelative);
6616
+ await assertMutationNotDenied(target.resolved, params.denyMutations, { protectAncestors: true });
6617
+ }
6448
6618
  async function movePathFallback(root, params) {
6449
6619
  const source = await resolvePathInRoot(root, params.fromRelative);
6620
+ await assertMutationNotDenied(source.resolved, params.denyMutations, { protectAncestors: true });
6450
6621
  await resolvePinnedRootPathInRoot(root, {
6451
6622
  relativePath: params.fromRelative,
6452
6623
  policy: PATH_ALIAS_POLICIES.strict,
6453
6624
  });
6454
6625
  const target = await resolvePathInRoot(root, params.toRelative);
6626
+ await assertMutationNotDenied(target.resolved, params.denyMutations, { protectAncestors: true });
6455
6627
  await resolvePinnedRootPathInRoot(root, {
6456
6628
  relativePath: params.toRelative,
6457
6629
  policy: PATH_ALIAS_POLICIES.unlinkTarget,
@@ -6535,6 +6707,7 @@ async function writeFileFallback(root, params) {
6535
6707
  relativePath: params.relativePath,
6536
6708
  mkdir: params.mkdir,
6537
6709
  mode: params.mode,
6710
+ denyMutations: params.denyMutations,
6538
6711
  truncateExisting: false,
6539
6712
  });
6540
6713
  const destinationPath = target.realPath;
@@ -6580,6 +6753,7 @@ async function writeFileFallback(root, params) {
6580
6753
  }
6581
6754
  async function writeMissingFileFallback(root, params) {
6582
6755
  const { rootReal, resolved } = await resolvePathInRoot(root, params.relativePath);
6756
+ await assertMutationNotDenied(resolved, params.denyMutations);
6583
6757
  try {
6584
6758
  await assertNoPathAliasEscape({
6585
6759
  absolutePath: resolved,
@@ -6653,6 +6827,7 @@ async function copyFileFallback(root, params, source) {
6653
6827
  relativePath: params.relativePath,
6654
6828
  mkdir: params.mkdir,
6655
6829
  mode: params.mode,
6830
+ denyMutations: params.denyMutations,
6656
6831
  truncateExisting: false,
6657
6832
  });
6658
6833
  const destinationPath = target.realPath;
@@ -21535,8 +21710,8 @@ function dist_bundle_withDefaults(oldDefaults, newDefaults) {
21535
21710
  var dist_bundle_endpoint = dist_bundle_withDefaults(null, DEFAULTS);
21536
21711
 
21537
21712
 
21538
- // EXTERNAL MODULE: ../../node_modules/fast-content-type-parse/index.js
21539
- var fast_content_type_parse = __webpack_require__(2592);
21713
+ // EXTERNAL MODULE: ../../node_modules/@octokit/request/node_modules/content-type/dist/index.js
21714
+ var content_type_dist = __webpack_require__(9703);
21540
21715
  ;// CONCATENATED MODULE: ../../node_modules/json-with-bigint/json-with-bigint.js
21541
21716
  const intRegex = /^-?\d+$/;
21542
21717
  const noiseValue = /^-?\d+n+$/; // Noise - strings that match the custom format before being converted to it
@@ -21803,7 +21978,7 @@ class RequestError extends Error {
21803
21978
 
21804
21979
 
21805
21980
  // pkg/dist-src/version.js
21806
- var dist_bundle_VERSION = "10.0.8";
21981
+ var dist_bundle_VERSION = "10.0.10";
21807
21982
 
21808
21983
  // pkg/dist-src/defaults.js
21809
21984
  var defaults_default = {
@@ -21932,7 +22107,7 @@ async function getResponseData(response) {
21932
22107
  if (!contentType) {
21933
22108
  return response.text().catch(noop);
21934
22109
  }
21935
- const mimetype = (0,fast_content_type_parse/* .safeParse */.xL)(contentType);
22110
+ const mimetype = (0,content_type_dist/* .parse */.qg)(contentType);
21936
22111
  if (isJSONResponse(mimetype)) {
21937
22112
  let text = "";
21938
22113
  try {
@@ -25781,6 +25956,7 @@ const PackageJsonSchema = schemas_object({
25781
25956
  */
25782
25957
 
25783
25958
 
25959
+
25784
25960
  /** Maximum skill file size: 1 MB */ const MAX_SKILL_FILE_BYTES = 1_048_576;
25785
25961
  /**
25786
25962
  * Skill directory locations to search for SKILL.md files.
@@ -25789,6 +25965,33 @@ const PackageJsonSchema = schemas_object({
25789
25965
  (0,external_node_path_.join)(".claude", "skills"),
25790
25966
  (0,external_node_path_.join)(".agents", "skills")
25791
25967
  ];
25968
+ /** Maximum lock file size: 256 KB */ const MAX_LOCK_FILE_BYTES = 262_144;
25969
+ /** Relative path to the skills lock file. */ const SKILLS_LOCK_PATH = "skills-lock.json";
25970
+ /** Zod schema for skills-lock.json structure */ const SkillsLockSchema = schemas_object({
25971
+ skills: record(schemas_string(), unknown()).optional()
25972
+ });
25973
+ /**
25974
+ * Reads the skills-lock.json file and returns the set of locked skill names.
25975
+ * Returns an empty set if the file does not exist or cannot be parsed.
25976
+ */ async function readLockedSkillNames(targetDir) {
25977
+ try {
25978
+ const exists = await file_system_utils_pathExistsWithinRoot(targetDir, SKILLS_LOCK_PATH);
25979
+ if (!exists) {
25980
+ return new Set();
25981
+ }
25982
+ const content = await file_system_utils_readTextWithinRoot(targetDir, SKILLS_LOCK_PATH, MAX_LOCK_FILE_BYTES);
25983
+ const result = SkillsLockSchema.safeParse(JSON.parse(content));
25984
+ if (result.success && Object.hasOwn(result.data, "skills") && result.data.skills != null) {
25985
+ return new Set(Object.keys(result.data.skills));
25986
+ }
25987
+ return new Set();
25988
+ } catch (error) {
25989
+ if (file_system_utils_isFsSafeViolation(error)) {
25990
+ throw error;
25991
+ }
25992
+ return new Set();
25993
+ }
25994
+ }
25792
25995
  /**
25793
25996
  * File system implementation of the skill lint gateway.
25794
25997
  */ class FileSystemSkillLintGateway {
@@ -25798,7 +26001,11 @@ const PackageJsonSchema = schemas_object({
25798
26001
  const discovered = await this.discoverSkillsInDir(targetDir, relativeDir);
25799
26002
  skills.push(...discovered);
25800
26003
  }
25801
- return skills;
26004
+ const lockedNames = await readLockedSkillNames(targetDir);
26005
+ if (lockedNames.size === 0) {
26006
+ return skills;
26007
+ }
26008
+ return skills.filter((skill)=>!lockedNames.has(skill.skillName));
25802
26009
  }
25803
26010
  async discoverSkillsInDir(targetDir, skillsDir) {
25804
26011
  try {
@@ -27677,6 +27884,38 @@ const CLI_TEMPLATE_DIR = (0,external_node_path_.join)(PROJECT_ROOT, "cli", "copi
27677
27884
  type: "file",
27678
27885
  path: ".devcontainer/devcontainer.json",
27679
27886
  content: reader(".devcontainer/devcontainer.json")
27887
+ },
27888
+ // Agent skills — required by the feature-to-plan skill invocation in the issue template
27889
+ {
27890
+ type: "directory",
27891
+ path: ".agents"
27892
+ },
27893
+ {
27894
+ type: "directory",
27895
+ path: ".agents/skills"
27896
+ },
27897
+ {
27898
+ type: "directory",
27899
+ path: ".agents/skills/feature-to-plan"
27900
+ },
27901
+ {
27902
+ type: "file",
27903
+ path: ".agents/skills/feature-to-plan/SKILL.md",
27904
+ content: reader(".agents/skills/feature-to-plan/SKILL.md")
27905
+ },
27906
+ {
27907
+ type: "directory",
27908
+ path: ".agents/skills/feature-to-plan/references"
27909
+ },
27910
+ {
27911
+ type: "file",
27912
+ path: ".agents/skills/feature-to-plan/references/interactive-flow.md",
27913
+ content: reader(".agents/skills/feature-to-plan/references/interactive-flow.md")
27914
+ },
27915
+ {
27916
+ type: "file",
27917
+ path: ".agents/skills/feature-to-plan/references/spec-format.md",
27918
+ content: reader(".agents/skills/feature-to-plan/references/spec-format.md")
27680
27919
  }
27681
27920
  ];
27682
27921
  }
@@ -43301,7 +43540,7 @@ function formatHeadingAsSetext(node, state) {
43301
43540
  node.type === 'break'
43302
43541
  ) {
43303
43542
  literalWithBreak = true
43304
- return EXIT
43543
+ return (/* inlined export .EXIT */false)
43305
43544
  }
43306
43545
  })
43307
43546
 
@@ -50403,178 +50642,178 @@ module.exports = __rspack_createRequire_require("process");
50403
50642
  module.exports = __rspack_createRequire_require("zlib");
50404
50643
 
50405
50644
  },
50406
- 2592(module) {
50645
+ 9703(__unused_rspack_module, exports) {
50407
50646
  var __webpack_unused_export__;
50408
50647
 
50409
-
50410
- const NullObject = function NullObject () { }
50411
- NullObject.prototype = Object.create(null)
50412
-
50413
- /**
50414
- * RegExp to match *( ";" parameter ) in RFC 7231 sec 3.1.1.1
50415
- *
50416
- * parameter = token "=" ( token / quoted-string )
50417
- * token = 1*tchar
50418
- * tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
50419
- * / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
50420
- * / DIGIT / ALPHA
50421
- * ; any VCHAR, except delimiters
50422
- * quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE
50423
- * qdtext = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text
50424
- * obs-text = %x80-FF
50425
- * quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
50648
+ /*!
50649
+ * content-type
50650
+ * Copyright(c) 2015 Douglas Christopher Wilson
50651
+ * MIT Licensed
50426
50652
  */
50427
- const paramRE = /; *([!#$%&'*+.^\w`|~-]+)=("(?:[\v\u0020\u0021\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\v\u0020-\u00ff])*"|[!#$%&'*+.^\w`|~-]+) */gu
50428
-
50653
+ __webpack_unused_export__ = ({ value: true });
50654
+ __webpack_unused_export__ = format;
50655
+ exports.qg = parse;
50656
+ const TEXT_REGEXP = /^[\u0009\u0020-\u007e\u0080-\u00ff]*$/;
50657
+ const TOKEN_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
50429
50658
  /**
50430
- * RegExp to match quoted-pair in RFC 7230 sec 3.2.6
50431
- *
50432
- * quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
50433
- * obs-text = %x80-FF
50659
+ * RegExp to match chars that must be quoted-pair in RFC 9110 sec 5.6.4
50434
50660
  */
50435
- const quotedPairRE = /\\([\v\u0020-\u00ff])/gu
50436
-
50661
+ const QUOTE_REGEXP = /[\\"]/g;
50437
50662
  /**
50438
- * RegExp to match type in RFC 7231 sec 3.1.1.1
50663
+ * RegExp to match type in RFC 9110 sec 8.3.1
50439
50664
  *
50440
50665
  * media-type = type "/" subtype
50441
50666
  * type = token
50442
50667
  * subtype = token
50443
50668
  */
50444
- const mediaTypeRE = /^[!#$%&'*+.^\w|~-]+\/[!#$%&'*+.^\w|~-]+$/u
50445
-
50446
- // default ContentType to prevent repeated object creation
50447
- const defaultContentType = { type: '', parameters: new NullObject() }
50448
- Object.freeze(defaultContentType.parameters)
50449
- Object.freeze(defaultContentType)
50450
-
50669
+ const TYPE_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+\/[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
50451
50670
  /**
50452
- * Parse media type to object.
50453
- *
50454
- * @param {string|object} header
50455
- * @return {Object}
50456
- * @public
50671
+ * Null object perf optimization. Faster than `Object.create(null)` and `{ __proto__: null }`.
50457
50672
  */
50458
-
50459
- function parse (header) {
50460
- if (typeof header !== 'string') {
50461
- throw new TypeError('argument header is required and must be a string')
50462
- }
50463
-
50464
- let index = header.indexOf(';')
50465
- const type = index !== -1
50466
- ? header.slice(0, index).trim()
50467
- : header.trim()
50468
-
50469
- if (mediaTypeRE.test(type) === false) {
50470
- throw new TypeError('invalid media type')
50471
- }
50472
-
50473
- const result = {
50474
- type: type.toLowerCase(),
50475
- parameters: new NullObject()
50476
- }
50477
-
50478
- // parse parameters
50479
- if (index === -1) {
50480
- return result
50481
- }
50482
-
50483
- let key
50484
- let match
50485
- let value
50486
-
50487
- paramRE.lastIndex = index
50488
-
50489
- while ((match = paramRE.exec(header))) {
50490
- if (match.index !== index) {
50491
- throw new TypeError('invalid parameter format')
50673
+ const NullObject = /* @__PURE__ */ (() => {
50674
+ const C = function () { };
50675
+ C.prototype = Object.create(null);
50676
+ return C;
50677
+ })();
50678
+ /**
50679
+ * Format an object into a `Content-Type` header.
50680
+ */
50681
+ function format(obj) {
50682
+ const { type, parameters } = obj;
50683
+ if (!type || !TYPE_REGEXP.test(type)) {
50684
+ throw new TypeError(`Invalid type: ${type}`);
50492
50685
  }
50493
-
50494
- index += match[0].length
50495
- key = match[1].toLowerCase()
50496
- value = match[2]
50497
-
50498
- if (value[0] === '"') {
50499
- // remove quotes and escapes
50500
- value = value
50501
- .slice(1, value.length - 1)
50502
-
50503
- quotedPairRE.test(value) && (value = value.replace(quotedPairRE, '$1'))
50686
+ let result = type;
50687
+ if (parameters) {
50688
+ for (const param of Object.keys(parameters)) {
50689
+ if (!TOKEN_REGEXP.test(param)) {
50690
+ throw new TypeError(`Invalid parameter name: ${param}`);
50691
+ }
50692
+ result += `; ${param}=${qstring(parameters[param])}`;
50693
+ }
50504
50694
  }
50505
-
50506
- result.parameters[key] = value
50507
- }
50508
-
50509
- if (index !== header.length) {
50510
- throw new TypeError('invalid parameter format')
50511
- }
50512
-
50513
- return result
50695
+ return result;
50514
50696
  }
50515
-
50516
- function safeParse (header) {
50517
- if (typeof header !== 'string') {
50518
- return defaultContentType
50519
- }
50520
-
50521
- let index = header.indexOf(';')
50522
- const type = index !== -1
50523
- ? header.slice(0, index).trim()
50524
- : header.trim()
50525
-
50526
- if (mediaTypeRE.test(type) === false) {
50527
- return defaultContentType
50528
- }
50529
-
50530
- const result = {
50531
- type: type.toLowerCase(),
50532
- parameters: new NullObject()
50533
- }
50534
-
50535
- // parse parameters
50536
- if (index === -1) {
50537
- return result
50538
- }
50539
-
50540
- let key
50541
- let match
50542
- let value
50543
-
50544
- paramRE.lastIndex = index
50545
-
50546
- while ((match = paramRE.exec(header))) {
50547
- if (match.index !== index) {
50548
- return defaultContentType
50697
+ /**
50698
+ * Parse a `Content-Type` header.
50699
+ */
50700
+ function parse(header, options) {
50701
+ const len = header.length;
50702
+ let index = skipOWS(header, 0, len);
50703
+ const valueStart = index;
50704
+ index = skipValue(header, index, len);
50705
+ const valueEnd = trailingOWS(header, valueStart, index);
50706
+ const type = header.slice(valueStart, valueEnd).toLowerCase();
50707
+ const parameters = options?.parameters === false
50708
+ ? new NullObject()
50709
+ : parseParameters(header, index, len);
50710
+ return { type, parameters };
50711
+ }
50712
+ const SP = 32; // " "
50713
+ const HTAB = 9; // "\t"
50714
+ const SEMI = 59; // ";"
50715
+ const EQ = 61; // "="
50716
+ const DQUOTE = 34; // '"'
50717
+ const BSLASH = 92; // "\\"
50718
+ /**
50719
+ * Parses the parameters of a `Content-Type` header starting at the given index.
50720
+ */
50721
+ function parseParameters(header, index, len) {
50722
+ const parameters = new NullObject();
50723
+ parameter: while (index < len) {
50724
+ index = skipOWS(header, index + 1 /* Skip over ; */, len);
50725
+ const keyStart = index;
50726
+ while (index < len) {
50727
+ const code = header.charCodeAt(index);
50728
+ if (code === SEMI)
50729
+ continue parameter;
50730
+ if (code === EQ) {
50731
+ const keyEnd = trailingOWS(header, keyStart, index);
50732
+ const key = header.slice(keyStart, keyEnd).toLowerCase();
50733
+ index = skipOWS(header, index + 1, len);
50734
+ if (index < len && header.charCodeAt(index) === DQUOTE) {
50735
+ index++;
50736
+ let value = "";
50737
+ while (index < len) {
50738
+ const code = header.charCodeAt(index++);
50739
+ if (code === DQUOTE) {
50740
+ index = skipValue(header, index, len);
50741
+ if (parameters[key] === undefined)
50742
+ parameters[key] = value;
50743
+ break;
50744
+ }
50745
+ if (code === BSLASH && index < len) {
50746
+ value += header[index++];
50747
+ continue;
50748
+ }
50749
+ value += String.fromCharCode(code);
50750
+ }
50751
+ continue parameter;
50752
+ }
50753
+ const valueStart = index;
50754
+ index = skipValue(header, index, len);
50755
+ if (parameters[key] === undefined) {
50756
+ const valueEnd = trailingOWS(header, valueStart, index);
50757
+ parameters[key] = header.slice(valueStart, valueEnd);
50758
+ }
50759
+ continue parameter;
50760
+ }
50761
+ index++;
50762
+ }
50549
50763
  }
50550
-
50551
- index += match[0].length
50552
- key = match[1].toLowerCase()
50553
- value = match[2]
50554
-
50555
- if (value[0] === '"') {
50556
- // remove quotes and escapes
50557
- value = value
50558
- .slice(1, value.length - 1)
50559
-
50560
- quotedPairRE.test(value) && (value = value.replace(quotedPairRE, '$1'))
50764
+ return parameters;
50765
+ }
50766
+ /**
50767
+ * Skip over characters until a semicolon.
50768
+ */
50769
+ function skipValue(str, index, len) {
50770
+ while (index < len) {
50771
+ const char = str.charCodeAt(index);
50772
+ if (char === SEMI)
50773
+ break;
50774
+ index++;
50561
50775
  }
50562
-
50563
- result.parameters[key] = value
50564
- }
50565
-
50566
- if (index !== header.length) {
50567
- return defaultContentType
50568
- }
50569
-
50570
- return result
50776
+ return index;
50571
50777
  }
50572
-
50573
- __webpack_unused_export__ = { parse, safeParse }
50574
- __webpack_unused_export__ = parse
50575
- module.exports.xL = safeParse
50576
- __webpack_unused_export__ = defaultContentType
50577
-
50778
+ /**
50779
+ * Skip optional whitespace (OWS) in an HTTP header value.
50780
+ *
50781
+ * OWS is defined in RFC 9110 sec 5.6.3 as SP (" ") or HTAB ("\t").
50782
+ */
50783
+ function skipOWS(header, index, len) {
50784
+ while (index < len) {
50785
+ const char = header.charCodeAt(index);
50786
+ if (char !== SP && char !== HTAB)
50787
+ break;
50788
+ index++;
50789
+ }
50790
+ return index;
50791
+ }
50792
+ /**
50793
+ * Trim optional whitespace (OWS) from the end of a substring.
50794
+ *
50795
+ * OWS is defined in RFC 9110 sec 5.6.3 as SP (" ") or HTAB ("\t").
50796
+ */
50797
+ function trailingOWS(header, start, end) {
50798
+ while (end > start) {
50799
+ const char = header.charCodeAt(end - 1);
50800
+ if (char !== SP && char !== HTAB)
50801
+ break;
50802
+ end--;
50803
+ }
50804
+ return end;
50805
+ }
50806
+ /**
50807
+ * Serialize a parameter value.
50808
+ */
50809
+ function qstring(str) {
50810
+ if (TOKEN_REGEXP.test(str))
50811
+ return str;
50812
+ if (TEXT_REGEXP.test(str))
50813
+ return `"${str.replace(QUOTE_REGEXP, "\\$&")}"`;
50814
+ throw new TypeError(`Invalid parameter value: ${str}`);
50815
+ }
50816
+ //# sourceMappingURL=index.js.map
50578
50817
 
50579
50818
  },
50580
50819
  3273(module, __unused_rspack_exports, __webpack_require__) {
@@ -58930,10 +59169,11 @@ exports.visitAsync = visitAsync;
58930
59169
 
58931
59170
  },
58932
59171
  5492(__unused_rspack___webpack_module__, __webpack_exports__, __webpack_require__) {
59172
+ const t=Symbol.for(`__confbox_fmt__`),n=/^(\s+)/,r=/(\s+)$/;function i(e,t={}){return{sample:t.indent===void 0&&t.preserveIndentation!==!1&&e.slice(0,t?.sampleSize||1024),whiteSpace:t.preserveWhitespace===!1?void 0:{start:n.exec(e)?.[0]||``,end:r.exec(e)?.[0]||``}}}function a(e,n,r){!n||typeof n!=`object`||Object.defineProperty(n,t,{enumerable:!1,configurable:!0,writable:!0,value:i(e,r)})}function o(n,r){if(!n||typeof n!=`object`||!(t in n))return{indent:r?.indent??2,whitespace:{start:``,end:``}};let i=n[t];return{indent:r?.indent||e(i.sample||``).indent,whitespace:i.whiteSpace||{start:``,end:``}}}
58933
59173
  __webpack_require__.d(__webpack_exports__, {
58934
59174
  n: () => (a)
58935
59175
  });
58936
- const t=Symbol.for(`__confbox_fmt__`),n=/^(\s+)/,r=/(\s+)$/;function i(e,t={}){return{sample:t.indent===void 0&&t.preserveIndentation!==!1&&e.slice(0,t?.sampleSize||1024),whiteSpace:t.preserveWhitespace===!1?void 0:{start:n.exec(e)?.[0]||``,end:r.exec(e)?.[0]||``}}}function a(e,n,r){!n||typeof n!=`object`||Object.defineProperty(n,t,{enumerable:!1,configurable:!0,writable:!0,value:i(e,r)})}function o(n,r){if(!n||typeof n!=`object`||!(t in n))return{indent:r?.indent??2,whitespace:{start:``,end:``}};let i=n[t];return{indent:r?.indent||e(i.sample||``).indent,whitespace:i.whiteSpace||{start:``,end:``}}}
59176
+
58937
59177
 
58938
59178
  },
58939
59179
  5975(__unused_rspack___webpack_module__, __webpack_exports__, __webpack_require__) {
@@ -59030,12 +59270,16 @@ __webpack_require__.t = function(value, mode) {
59030
59270
  })();
59031
59271
  // webpack/runtime/define_property_getters
59032
59272
  (() => {
59033
- __webpack_require__.d = (exports, definition) => {
59034
- for(var key in definition) {
59035
- if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
59036
- Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
59037
- }
59038
- }
59273
+ __webpack_require__.d = (exports, getters, values) => {
59274
+ var define = (defs, kind) => {
59275
+ for(var key in defs) {
59276
+ if(__webpack_require__.o(defs, key) && !__webpack_require__.o(exports, key)) {
59277
+ Object.defineProperty(exports, key, { enumerable: true, [kind]: defs[key] });
59278
+ }
59279
+ }
59280
+ };
59281
+ define(getters, "get");
59282
+ define(values, "value");
59039
59283
  };
59040
59284
  })();
59041
59285
  // webpack/runtime/ensure_chunk
@@ -59137,4 +59381,4 @@ if (installedChunkData !== 0) { // 0 means "already installed".'
59137
59381
  // module factories are used so entry inlining is disabled
59138
59382
  // startup
59139
59383
  // Load entry module and return exports
59140
- var __webpack_exports__ = __webpack_require__(1809);
59384
+ var __webpack_exports__ = __webpack_require__(8634);