@poe-platform/safe-bash 0.1.540 → 0.1.541

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 (87) hide show
  1. package/dist/safe-bash/chunks/{chunk-GZKLXMBM.js → chunk-5VBLSPNM.js} +6 -1
  2. package/dist/safe-bash/chunks/{chunk-GZKLXMBM.js.map → chunk-5VBLSPNM.js.map} +2 -2
  3. package/dist/safe-bash/chunks/{chunk-DJHZJAB7.js → chunk-66VSWIUC.js} +3 -3
  4. package/dist/safe-bash/chunks/{chunk-PPPN3OME.js → chunk-6PSMEBVP.js} +2 -2
  5. package/dist/safe-bash/chunks/{chunk-32GGX4AS.js → chunk-AZNI263O.js} +3 -3
  6. package/dist/safe-bash/chunks/{chunk-LRVRQIG5.js → chunk-EZLQA6ON.js} +3 -3
  7. package/dist/safe-bash/chunks/{chunk-ZQEL7DYC.js → chunk-HFEU5SBQ.js} +4 -4
  8. package/dist/safe-bash/chunks/{chunk-EYJTLUBJ.js → chunk-PZMJ4EC3.js} +2 -2
  9. package/dist/safe-bash/chunks/chunk-R3QJL5HH.js +698 -0
  10. package/dist/safe-bash/chunks/chunk-R3QJL5HH.js.map +7 -0
  11. package/dist/safe-bash/chunks/{chunk-J4CKSMJV.js → chunk-T5BV7HPD.js} +2 -2
  12. package/dist/safe-bash/chunks/{chunk-IIWXPQB3.js → chunk-TPD45VUZ.js} +5 -5
  13. package/dist/safe-bash/chunks/{chunk-UGMO7OO5.js → chunk-VNDFKT6F.js} +3 -3
  14. package/dist/safe-bash/chunks/{chunk-LZUOZVGJ.js → chunk-WF4P7XKI.js} +3 -3
  15. package/dist/safe-bash/chunks/{chunk-Z75O7XWR.js → chunk-WODV2DVM.js} +3 -3
  16. package/dist/safe-bash/chunks/{chunk-QKQNBJOU.js → chunk-YEJBZLE5.js} +5 -5
  17. package/dist/safe-bash/commands/bytes/compression/file-operation.d.ts +16 -0
  18. package/dist/safe-bash/commands/bytes/compression/file-operation.d.ts.map +1 -0
  19. package/dist/safe-bash/commands/bytes/compression/file-operation.js +134 -0
  20. package/dist/safe-bash/commands/bytes/compression/file-operation.js.map +1 -0
  21. package/dist/safe-bash/commands/bytes/compression/files.d.ts.map +1 -1
  22. package/dist/safe-bash/commands/bytes/compression/files.js +126 -67
  23. package/dist/safe-bash/commands/bytes/compression/files.js.map +1 -1
  24. package/dist/safe-bash/commands/bytes/compression/stream.d.ts.map +1 -1
  25. package/dist/safe-bash/commands/bytes/compression/stream.js +2 -1
  26. package/dist/safe-bash/commands/bytes/compression/stream.js.map +1 -1
  27. package/dist/safe-bash/commands/csplit/index.browser.js +4 -4
  28. package/dist/safe-bash/commands/factor/index.browser.js +3 -3
  29. package/dist/safe-bash/commands/getopt/index.browser.js +3 -3
  30. package/dist/safe-bash/commands/hexdump/command.d.ts +5 -0
  31. package/dist/safe-bash/commands/hexdump/command.d.ts.map +1 -0
  32. package/dist/safe-bash/commands/hexdump/command.js +174 -0
  33. package/dist/safe-bash/commands/hexdump/command.js.map +1 -0
  34. package/dist/safe-bash/commands/hexdump/format.d.ts +2 -0
  35. package/dist/safe-bash/commands/hexdump/format.d.ts.map +1 -0
  36. package/dist/safe-bash/commands/hexdump/format.js +25 -0
  37. package/dist/safe-bash/commands/hexdump/format.js.map +1 -0
  38. package/dist/safe-bash/commands/hexdump/index.browser.js +17 -0
  39. package/dist/safe-bash/commands/hexdump/index.browser.js.map +7 -0
  40. package/dist/safe-bash/commands/hexdump/index.d.ts +7 -0
  41. package/dist/safe-bash/commands/hexdump/index.d.ts.map +1 -0
  42. package/dist/safe-bash/commands/hexdump/index.js +17 -0
  43. package/dist/safe-bash/commands/hexdump/index.js.map +1 -0
  44. package/dist/safe-bash/commands/hexdump/internal.d.ts +52 -0
  45. package/dist/safe-bash/commands/hexdump/internal.d.ts.map +1 -0
  46. package/dist/safe-bash/commands/hexdump/internal.js +150 -0
  47. package/dist/safe-bash/commands/hexdump/internal.js.map +1 -0
  48. package/dist/safe-bash/commands/hexdump/io.d.ts +41 -0
  49. package/dist/safe-bash/commands/hexdump/io.d.ts.map +1 -0
  50. package/dist/safe-bash/commands/hexdump/io.js +288 -0
  51. package/dist/safe-bash/commands/hexdump/io.js.map +1 -0
  52. package/dist/safe-bash/commands/hexdump/options.d.ts +10 -0
  53. package/dist/safe-bash/commands/hexdump/options.d.ts.map +1 -0
  54. package/dist/safe-bash/commands/hexdump/options.js +80 -0
  55. package/dist/safe-bash/commands/hexdump/options.js.map +1 -0
  56. package/dist/safe-bash/commands/network/index.browser.js +5 -5
  57. package/dist/safe-bash/commands/pr/index.browser.js +3 -3
  58. package/dist/safe-bash/commands/tsort/index.browser.js +3 -3
  59. package/dist/safe-bash/commands/xml/index.browser.js +4 -4
  60. package/dist/safe-bash/commands/yq/index.browser.js +5 -5
  61. package/dist/safe-bash/contracts/yield.d.ts +1 -0
  62. package/dist/safe-bash/contracts/yield.d.ts.map +1 -1
  63. package/dist/safe-bash/contracts/yield.js +5 -0
  64. package/dist/safe-bash/contracts/yield.js.map +1 -1
  65. package/dist/safe-bash/core.browser.js +287 -79
  66. package/dist/safe-bash/core.browser.js.map +4 -4
  67. package/dist/safe-bash/core.d.ts +1 -0
  68. package/dist/safe-bash/core.d.ts.map +1 -1
  69. package/dist/safe-bash/core.js +1 -0
  70. package/dist/safe-bash/core.js.map +1 -1
  71. package/dist/safe-bash/plugins/composition.d.ts +2 -0
  72. package/dist/safe-bash/plugins/composition.d.ts.map +1 -1
  73. package/dist/safe-bash/plugins/composition.js +3 -1
  74. package/dist/safe-bash/plugins/composition.js.map +1 -1
  75. package/package.json +8 -2
  76. /package/dist/safe-bash/chunks/{chunk-DJHZJAB7.js.map → chunk-66VSWIUC.js.map} +0 -0
  77. /package/dist/safe-bash/chunks/{chunk-PPPN3OME.js.map → chunk-6PSMEBVP.js.map} +0 -0
  78. /package/dist/safe-bash/chunks/{chunk-32GGX4AS.js.map → chunk-AZNI263O.js.map} +0 -0
  79. /package/dist/safe-bash/chunks/{chunk-LRVRQIG5.js.map → chunk-EZLQA6ON.js.map} +0 -0
  80. /package/dist/safe-bash/chunks/{chunk-ZQEL7DYC.js.map → chunk-HFEU5SBQ.js.map} +0 -0
  81. /package/dist/safe-bash/chunks/{chunk-EYJTLUBJ.js.map → chunk-PZMJ4EC3.js.map} +0 -0
  82. /package/dist/safe-bash/chunks/{chunk-J4CKSMJV.js.map → chunk-T5BV7HPD.js.map} +0 -0
  83. /package/dist/safe-bash/chunks/{chunk-IIWXPQB3.js.map → chunk-TPD45VUZ.js.map} +0 -0
  84. /package/dist/safe-bash/chunks/{chunk-UGMO7OO5.js.map → chunk-VNDFKT6F.js.map} +0 -0
  85. /package/dist/safe-bash/chunks/{chunk-LZUOZVGJ.js.map → chunk-WF4P7XKI.js.map} +0 -0
  86. /package/dist/safe-bash/chunks/{chunk-Z75O7XWR.js.map → chunk-WODV2DVM.js.map} +0 -0
  87. /package/dist/safe-bash/chunks/{chunk-QKQNBJOU.js.map → chunk-YEJBZLE5.js.map} +0 -0
@@ -2,12 +2,18 @@ import {
2
2
  createGetoptCommand,
3
3
  createGetoptCommands,
4
4
  getoptCommands
5
- } from "./chunks/chunk-LRVRQIG5.js";
5
+ } from "./chunks/chunk-EZLQA6ON.js";
6
+ import {
7
+ createHdCommand,
8
+ createHexdumpCommand,
9
+ createHexdumpCommands,
10
+ hexdumpCommands
11
+ } from "./chunks/chunk-R3QJL5HH.js";
6
12
  import {
7
13
  createXmlCommands,
8
14
  defaultXmlQueryLimits,
9
15
  xmlCommands
10
- } from "./chunks/chunk-ZQEL7DYC.js";
16
+ } from "./chunks/chunk-HFEU5SBQ.js";
11
17
  import {
12
18
  Interpreter,
13
19
  createYqCommand,
@@ -18,7 +24,7 @@ import {
18
24
  rawValues,
19
25
  stringify,
20
26
  yqCommands
21
- } from "./chunks/chunk-QKQNBJOU.js";
27
+ } from "./chunks/chunk-YEJBZLE5.js";
22
28
  import {
23
29
  Budget,
24
30
  JqError,
@@ -31,7 +37,7 @@ import {
31
37
  resolveJqLimits,
32
38
  truth,
33
39
  wellFormed
34
- } from "./chunks/chunk-PPPN3OME.js";
40
+ } from "./chunks/chunk-6PSMEBVP.js";
35
41
  import {
36
42
  CurlError,
37
43
  cloudflareWorkerNetworkLimits,
@@ -44,7 +50,7 @@ import {
44
50
  curlCommands,
45
51
  defaultNetworkLimits,
46
52
  networkCommands
47
- } from "./chunks/chunk-IIWXPQB3.js";
53
+ } from "./chunks/chunk-TPD45VUZ.js";
48
54
  import {
49
55
  RecordBuffer,
50
56
  UsageError,
@@ -76,7 +82,7 @@ import {
76
82
  textOutputRequirements,
77
83
  value,
78
84
  writeDiagnostic
79
- } from "./chunks/chunk-J4CKSMJV.js";
85
+ } from "./chunks/chunk-T5BV7HPD.js";
80
86
  import {
81
87
  AvailableRecords,
82
88
  EreLedger,
@@ -96,22 +102,22 @@ import {
96
102
  exprMatchCeilings,
97
103
  matchEre,
98
104
  withRegexSession
99
- } from "./chunks/chunk-Z75O7XWR.js";
105
+ } from "./chunks/chunk-WODV2DVM.js";
100
106
  import {
101
107
  bindFileOutputBudget,
102
108
  openFileOutput,
103
109
  writeFileOutput
104
- } from "./chunks/chunk-32GGX4AS.js";
110
+ } from "./chunks/chunk-AZNI263O.js";
105
111
  import {
106
112
  createPrCommand,
107
113
  createPrCommands,
108
114
  prCommands
109
- } from "./chunks/chunk-UGMO7OO5.js";
115
+ } from "./chunks/chunk-VNDFKT6F.js";
110
116
  import {
111
117
  createTsortCommand,
112
118
  createTsortCommands,
113
119
  tsortCommands
114
- } from "./chunks/chunk-LZUOZVGJ.js";
120
+ } from "./chunks/chunk-WF4P7XKI.js";
115
121
  import {
116
122
  basename,
117
123
  dirname,
@@ -126,10 +132,10 @@ import {
126
132
  createFactorCommand,
127
133
  createFactorCommands,
128
134
  factorCommands
129
- } from "./chunks/chunk-DJHZJAB7.js";
135
+ } from "./chunks/chunk-66VSWIUC.js";
130
136
  import {
131
137
  createOutputOperation
132
- } from "./chunks/chunk-EYJTLUBJ.js";
138
+ } from "./chunks/chunk-PZMJ4EC3.js";
133
139
  import {
134
140
  CommandArgumentIdentityError,
135
141
  CommandRegistry,
@@ -142,6 +148,7 @@ import {
142
148
  createBytePipe,
143
149
  createCommandArguments,
144
150
  getCommandArguments,
151
+ inheritYieldCheckpoint,
145
152
  isErrnoCode,
146
153
  isFsError,
147
154
  monotonicNow,
@@ -162,7 +169,7 @@ import {
162
169
  writeBytes,
163
170
  writeText,
164
171
  yieldTurn
165
- } from "./chunks/chunk-GZKLXMBM.js";
172
+ } from "./chunks/chunk-5VBLSPNM.js";
166
173
  import {
167
174
  import_buffer,
168
175
  init_platform
@@ -17254,6 +17261,7 @@ init_platform();
17254
17261
 
17255
17262
  // packages/safe-bash/src/commands/bytes/compression/files.ts
17256
17263
  init_platform();
17264
+ import { retainFileSystemCleanup } from "@poe-platform/safe-fs/core";
17257
17265
 
17258
17266
  // packages/safe-bash/src/commands/bytes/compression/options.ts
17259
17267
  init_platform();
@@ -20871,6 +20879,7 @@ async function* split2(source2, signal, fail4) {
20871
20879
  async function transform(source2, consume, options2, parentSignal, maxOutput = Infinity) {
20872
20880
  const controller = new AbortController();
20873
20881
  const signal = AbortSignal.any([parentSignal, controller.signal]);
20882
+ inheritYieldCheckpoint(parentSignal, signal);
20874
20883
  let failure;
20875
20884
  let hasFailure = false;
20876
20885
  const fail4 = (error) => {
@@ -20926,15 +20935,153 @@ async function transform(source2, consume, options2, parentSignal, maxOutput = I
20926
20935
  return warned2;
20927
20936
  }
20928
20937
 
20938
+ // packages/safe-bash/src/commands/bytes/compression/file-operation.ts
20939
+ init_platform();
20940
+ var FileOperation = class {
20941
+ signal;
20942
+ fs;
20943
+ controller = new AbortController();
20944
+ pending = /* @__PURE__ */ new Set();
20945
+ sources = [];
20946
+ closing;
20947
+ caller;
20948
+ constructor(context2, cleanup) {
20949
+ this.caller = context2.signal;
20950
+ this.signal = this.controller.signal;
20951
+ this.caller.throwIfAborted();
20952
+ inheritYieldCheckpoint(this.caller, this.signal);
20953
+ const filesystem = context2.fs;
20954
+ this.caller.throwIfAborted();
20955
+ this.fs = new Proxy(filesystem, {
20956
+ get: (target, key) => {
20957
+ this.check();
20958
+ const value2 = Reflect.get(target, key, target);
20959
+ this.check();
20960
+ return typeof value2 === "function" ? (...args) => {
20961
+ this.check();
20962
+ const result2 = Reflect.apply(value2, target, args);
20963
+ return key === "readStream" ? this.ownSource(result2) : result2;
20964
+ } : value2;
20965
+ }
20966
+ });
20967
+ let outcomeClaimed = false;
20968
+ let registeredClosing;
20969
+ const abort = () => {
20970
+ void retire().catch(() => {
20971
+ });
20972
+ };
20973
+ const retire = () => {
20974
+ if (!this.closing) {
20975
+ this.closing = Promise.resolve().then(async () => {
20976
+ try {
20977
+ const sources2 = Promise.allSettled(this.sources.map((close) => close()));
20978
+ await Promise.allSettled([...this.pending]);
20979
+ const outcomes = await sources2;
20980
+ await cleanup?.();
20981
+ const failures = outcomes.filter((outcome) => outcome.status === "rejected").map((outcome) => outcome.reason);
20982
+ if (failures.length === 1) throw failures[0];
20983
+ if (failures.length) throw new AggregateError(failures, "Compression source cleanup failed");
20984
+ } finally {
20985
+ this.caller.removeEventListener("abort", abort);
20986
+ }
20987
+ });
20988
+ void this.closing.catch(() => {
20989
+ });
20990
+ this.controller.abort(this.caller.aborted ? this.caller.reason : new Error("Compression file operation is closed"));
20991
+ }
20992
+ return this.closing;
20993
+ };
20994
+ this.close = () => {
20995
+ outcomeClaimed = true;
20996
+ return retire();
20997
+ };
20998
+ const register = context2.registerCleanup;
20999
+ this.check();
21000
+ if (register) Reflect.apply(register, context2, [() => {
21001
+ registeredClosing ??= retire().catch((error) => {
21002
+ if (!outcomeClaimed) throw error;
21003
+ });
21004
+ void registeredClosing.catch(() => {
21005
+ });
21006
+ return registeredClosing;
21007
+ }]);
21008
+ this.check();
21009
+ this.caller.addEventListener("abort", abort, { once: true });
21010
+ if (this.caller.aborted) abort();
21011
+ }
21012
+ close;
21013
+ check() {
21014
+ this.caller.throwIfAborted();
21015
+ this.signal.throwIfAborted();
21016
+ }
21017
+ async run(start) {
21018
+ this.check();
21019
+ const pending = Promise.resolve().then(() => {
21020
+ this.check();
21021
+ return start();
21022
+ });
21023
+ this.pending.add(pending);
21024
+ try {
21025
+ return await pending;
21026
+ } finally {
21027
+ this.pending.delete(pending);
21028
+ }
21029
+ }
21030
+ ownSource(source2) {
21031
+ let iterator = void 0;
21032
+ let closing;
21033
+ const close = () => {
21034
+ closing ??= Promise.resolve().then(async () => {
21035
+ const method = iterator?.return;
21036
+ return method ? await Reflect.apply(method, iterator, []) : { done: true, value: void 0 };
21037
+ });
21038
+ void closing.catch(() => {
21039
+ });
21040
+ return closing;
21041
+ };
21042
+ this.sources.push(close);
21043
+ const factory = source2[Symbol.asyncIterator];
21044
+ iterator = Reflect.apply(factory, source2, []);
21045
+ this.check();
21046
+ let claimed = false;
21047
+ return {
21048
+ [Symbol.asyncIterator]: () => {
21049
+ this.check();
21050
+ if (claimed) throw new Error("Compression input was already acquired");
21051
+ claimed = true;
21052
+ return {
21053
+ next: async () => {
21054
+ this.check();
21055
+ if (closing) throw new Error("Compression input is closed");
21056
+ const method = iterator.next;
21057
+ this.check();
21058
+ const result2 = await Reflect.apply(method, iterator, []);
21059
+ this.check();
21060
+ const done = result2.done;
21061
+ this.check();
21062
+ const value2 = result2.value;
21063
+ this.check();
21064
+ return done ? { done: true, value: value2 } : { done: false, value: value2 };
21065
+ },
21066
+ return: close
21067
+ };
21068
+ }
21069
+ };
21070
+ }
21071
+ };
21072
+
20929
21073
  // packages/safe-bash/src/commands/bytes/compression/files.ts
21074
+ function identified(stat) {
21075
+ return stat.identityScope !== void 0 && Number.isSafeInteger(stat.ino) && Number.isSafeInteger(stat.dev);
21076
+ }
20930
21077
  function sameIdentity(first, second) {
20931
- return first.ino !== void 0 && second.ino !== void 0 && first.ino === second.ino && first.dev === second.dev;
21078
+ return identified(first) && identified(second) && first.identityScope === second.identityScope && first.ino === second.ino && first.dev === second.dev;
20932
21079
  }
20933
21080
  function sameSnapshot(first, second) {
20934
- return first.type === second.type && first.size === second.size && first.mode === second.mode && first.mtimeMs === second.mtimeMs && first.ctimeMs === second.ctimeMs && first.ino === second.ino && first.dev === second.dev && first.nlink === second.nlink && first.birthtimeMs === second.birthtimeMs && first.uid === second.uid && first.gid === second.gid;
21081
+ return first.type === second.type && first.size === second.size && first.mode === second.mode && first.mtimeMs === second.mtimeMs && first.ctimeMs === second.ctimeMs && first.ino === second.ino && first.dev === second.dev && first.nlink === second.nlink && first.birthtimeMs === second.birthtimeMs && first.uid === second.uid && first.gid === second.gid && first.identityScope === second.identityScope;
20935
21082
  }
20936
21083
  function sameEntry(first, second) {
20937
- return first.type === second.type && first.ino === second.ino && first.dev === second.dev && first.birthtimeMs === second.birthtimeMs;
21084
+ return sameIdentity(first, second) && first.type === second.type && first.birthtimeMs === second.birthtimeMs;
20938
21085
  }
20939
21086
  async function existing(context2, path) {
20940
21087
  try {
@@ -20970,6 +21117,15 @@ function outputPath(source2, options2) {
20970
21117
  return source2 + ".gz";
20971
21118
  }
20972
21119
  async function planOperands(context2, options2) {
21120
+ const operation2 = new FileOperation(context2);
21121
+ try {
21122
+ return await operation2.run(() => collectOperands({ ...context2, fs: operation2.fs, signal: operation2.signal }, options2));
21123
+ } finally {
21124
+ await operation2.close();
21125
+ context2.signal.throwIfAborted();
21126
+ }
21127
+ }
21128
+ async function collectOperands(context2, options2) {
20973
21129
  const plans = [];
20974
21130
  for (const name2 of options2.operands) {
20975
21131
  context2.signal.throwIfAborted();
@@ -21003,6 +21159,13 @@ async function planOperands(context2, options2) {
21003
21159
  throw new FsError("ENOTSUP", { message: "file output requires VFS streaming writes (use -c for stdout)" });
21004
21160
  }
21005
21161
  const destinationStat = await existing(context2, destination2);
21162
+ if (!identified(sourceStat) || destinationStat && !identified(destinationStat)) {
21163
+ throw new FsError("ENOTSUP", { path: source2, message: "file output requires stable scoped entry identities" });
21164
+ }
21165
+ if (!context2.fs.rmdir || capabilities.exclusiveCreate !== true || (destinationStat ? capabilities.atomicRename : capabilities.atomicRenameNoReplace) !== true) {
21166
+ throw new FsError("ENOTSUP", { path: destination2, message: "file output requires exclusive staging, safe rmdir and atomic publication (use -c for stdout)" });
21167
+ }
21168
+ context2.signal.throwIfAborted();
21006
21169
  if (destinationStat) {
21007
21170
  if (destinationStat.type !== "file" || sameIdentity(sourceStat, destinationStat) || realSource === await context2.fs.realpath(destination2, { signal: context2.signal })) {
21008
21171
  throw new FsError("EINVAL", { path: destination2, message: "destination is not a distinct regular file" });
@@ -21033,23 +21196,10 @@ async function unchangedSource(context2, plan) {
21033
21196
  throw new FsError("EBUSY", { path: plan.source, message: "input identity or metadata changed; input retained" });
21034
21197
  }
21035
21198
  }
21036
- async function temporaryDirectory(context2, destination2) {
21037
- for (let attempt = 0; attempt < 16; attempt++) {
21038
- const path = joinPath(dirname(destination2), `.virtual-bash-gzip-${globalThis.crypto.randomUUID()}`);
21039
- try {
21040
- await context2.fs.mkdir(path, { mode: 448, signal: context2.signal });
21041
- return path;
21042
- } catch (error) {
21043
- if (codeOf(error) !== "EEXIST") throw error;
21044
- }
21045
- }
21046
- throw new FsError("EEXIST", { message: "unable to allocate a private gzip staging directory" });
21047
- }
21048
21199
  async function writeFileOperand(context2, plan, options2) {
21049
21200
  const destination2 = plan.destination;
21050
- await unchangedSource(context2, plan);
21051
- const directory2 = await temporaryDirectory(context2, destination2);
21052
- const staged = joinPath(directory2, "data");
21201
+ let directory2;
21202
+ let staged;
21053
21203
  let directoryStat;
21054
21204
  let stageStat;
21055
21205
  let stageOwned = false;
@@ -21057,69 +21207,121 @@ async function writeFileOperand(context2, plan, options2) {
21057
21207
  let failure;
21058
21208
  let failed = false;
21059
21209
  let warned2 = false;
21210
+ let cleanupFailed = false;
21211
+ let retainedCleanup;
21212
+ const operation2 = new FileOperation(context2, async () => {
21213
+ await retainedCleanup?.();
21214
+ });
21215
+ const active = { ...context2, fs: operation2.fs, signal: operation2.signal };
21216
+ const { fs, signal } = active;
21217
+ const snapshot = (stat) => {
21218
+ const result2 = {};
21219
+ for (const key of ["type", "size", "mode", "mtimeMs", "atimeMs", "ctimeMs", "birthtimeMs", "identityScope", "ino", "dev", "nlink", "uid", "gid"]) {
21220
+ result2[key] = stat[key];
21221
+ operation2.check();
21222
+ }
21223
+ return Object.freeze(result2);
21224
+ };
21060
21225
  try {
21061
- directoryStat = await context2.fs.lstat(directory2, { signal: context2.signal });
21062
- if (directoryStat.type !== "directory") throw new FsError("EBUSY", { path: directory2 });
21063
- await context2.fs.writeFile(staged, new Uint8Array(), { flag: "wx", mode: 384, signal: context2.signal });
21064
- stageOwned = true;
21065
- stageStat = await context2.fs.lstat(staged, { signal: context2.signal });
21066
- if (stageStat.type !== "file" || stageStat.size !== 0) throw new FsError("EBUSY", { path: staged });
21067
- warned2 = await transform((signal) => context2.fs.readStream(plan.source, { signal, chunkSize: chunkBytes }), async (output2, signal) => {
21068
- await context2.fs.writeStream(staged, output2, { flag: "w", mode: 384, signal });
21069
- }, { ...options2, force: false }, context2.signal, stagingLimit);
21070
- await unchangedSource(context2, plan);
21071
- const target = await existing(context2, destination2);
21226
+ retainedCleanup = retainFileSystemCleanup(context2.fs, async (cleanup) => {
21227
+ if (directory2 === void 0) return;
21228
+ const cleanupSignal = AbortSignal.timeout(5e3);
21229
+ const currentDirectory = await cleanup.lstat(directory2, { signal: cleanupSignal });
21230
+ if (!directoryStat || !sameEntry(directoryStat, currentDirectory)) {
21231
+ throw new FsError("EBUSY", { path: directory2, message: "staging directory identity is unknown or changed; refusing cleanup" });
21232
+ }
21233
+ if (stageOwned && !moved && staged !== void 0) {
21234
+ let currentStage;
21235
+ try {
21236
+ currentStage = await cleanup.lstat(staged, { signal: cleanupSignal });
21237
+ } catch (error) {
21238
+ if (codeOf(error) !== "ENOENT") throw error;
21239
+ }
21240
+ if (currentStage) {
21241
+ if (!stageStat || !sameEntry(stageStat, currentStage)) throw new FsError("EBUSY", { path: staged, message: "staging file identity changed; refusing cleanup" });
21242
+ await cleanup.rm(staged, { signal: cleanupSignal });
21243
+ }
21244
+ }
21245
+ if (!cleanup.rmdir) throw new FsError("ENOTSUP", { path: directory2, message: "safe directory removal unavailable" });
21246
+ try {
21247
+ await cleanup.rmdir(directory2, { signal: cleanupSignal });
21248
+ } catch (error) {
21249
+ if (codeOf(error) === "ENOTEMPTY") throw new FsError("ENOTEMPTY", { path: directory2, message: "unexpected staging entries; refusing cleanup" });
21250
+ throw error;
21251
+ }
21252
+ }, { maxOperations: 8 });
21253
+ operation2.check();
21254
+ await operation2.run(() => unchangedSource(active, plan));
21255
+ for (let attempt = 0; directory2 === void 0 && attempt < 16; attempt++) {
21256
+ const path = joinPath(dirname(destination2), `.virtual-bash-gzip-${globalThis.crypto.randomUUID()}`);
21257
+ const capabilities = await operation2.run(async () => await fs.capabilitiesFor?.(path, { signal, create: true, allowDirectory: true }) ?? fs.capabilities);
21258
+ operation2.check();
21259
+ const snapshotRmdir = capabilities.snapshotRmdir;
21260
+ operation2.check();
21261
+ if (snapshotRmdir === true) throw new FsError("ENOTSUP", { path, message: "strong staging directory cleanup unavailable; snapshot-only rmdir is unsupported" });
21262
+ try {
21263
+ await operation2.run(async () => {
21264
+ await fs.mkdir(path, { mode: 448, signal });
21265
+ directory2 = path;
21266
+ });
21267
+ } catch (error) {
21268
+ operation2.check();
21269
+ if (codeOf(error) !== "EEXIST") throw error;
21270
+ }
21271
+ }
21272
+ if (directory2 === void 0) throw new FsError("EEXIST", { message: "unable to allocate a private gzip staging directory" });
21273
+ staged = joinPath(directory2, "data");
21274
+ directoryStat = snapshot(await operation2.run(() => fs.lstat(directory2, { signal })));
21275
+ if (directoryStat.type !== "directory" || !identified(directoryStat)) throw new FsError("EBUSY", { path: directory2 });
21276
+ await operation2.run(async () => {
21277
+ await fs.writeFile(staged, new Uint8Array(), { flag: "wx", mode: 384, signal });
21278
+ stageOwned = true;
21279
+ });
21280
+ stageStat = snapshot(await operation2.run(() => fs.lstat(staged, { signal })));
21281
+ if (stageStat.type !== "file" || stageStat.size !== 0 || !identified(stageStat)) throw new FsError("EBUSY", { path: staged });
21282
+ warned2 = await operation2.run(() => transform((signal2) => fs.readStream(plan.source, { signal: signal2, chunkSize: chunkBytes }), async (output2, signal2) => {
21283
+ await fs.writeStream(staged, output2, { flag: "w", mode: 384, signal: signal2 });
21284
+ }, { ...options2, force: false }, signal, stagingLimit));
21285
+ await operation2.run(() => unchangedSource(active, plan));
21286
+ const target = await operation2.run(() => existing(active, destination2));
21072
21287
  if (plan.destinationStat ? !target || !sameSnapshot(plan.destinationStat, target) : target !== void 0) {
21073
21288
  throw new FsError("EBUSY", { path: destination2, message: "destination changed during compression" });
21074
21289
  }
21075
- if (!sameEntry(stageStat, await context2.fs.lstat(staged, { signal: context2.signal }))) {
21290
+ if (!sameEntry(stageStat, snapshot(await operation2.run(() => fs.lstat(staged, { signal }))))) {
21076
21291
  throw new FsError("EBUSY", { path: staged, message: "staging identity changed" });
21077
21292
  }
21078
- if (plan.destinationStat) {
21079
- await context2.fs.rename(staged, destination2, { signal: context2.signal });
21293
+ await operation2.run(async () => {
21294
+ await fs.rename(staged, destination2, { signal, noReplace: !plan.destinationStat });
21080
21295
  moved = true;
21081
- } else await context2.fs.copyFile(staged, destination2, { exclusive: true, signal: context2.signal });
21082
- context2.signal.throwIfAborted();
21296
+ });
21297
+ operation2.check();
21298
+ try {
21299
+ await retainedCleanup();
21300
+ } catch (error) {
21301
+ cleanupFailed = true;
21302
+ throw error;
21303
+ }
21304
+ operation2.check();
21305
+ if (!options2.keep) {
21306
+ await operation2.run(() => unchangedSource(active, plan));
21307
+ await operation2.run(() => fs.rm(plan.source, { signal }));
21308
+ }
21083
21309
  } catch (error) {
21084
21310
  failed = true;
21085
21311
  failure = error;
21086
21312
  }
21087
21313
  try {
21088
- const signal = AbortSignal.timeout(5e3);
21089
- const currentDirectory = await context2.fs.lstat(directory2, { signal });
21090
- if (directoryStat && !sameEntry(directoryStat, currentDirectory)) {
21091
- throw new FsError("EBUSY", { path: directory2, message: "staging directory identity changed; refusing cleanup" });
21092
- }
21093
- if (stageOwned && !moved) {
21094
- let currentStage;
21095
- try {
21096
- currentStage = await context2.fs.lstat(staged, { signal });
21097
- } catch (error) {
21098
- if (codeOf(error) !== "ENOENT") throw error;
21099
- }
21100
- if (currentStage) {
21101
- if (!stageStat || !sameEntry(stageStat, currentStage)) {
21102
- throw new FsError("EBUSY", { path: staged, message: "staging file identity changed; refusing cleanup" });
21103
- }
21104
- await context2.fs.rm(staged, { signal });
21105
- }
21106
- }
21107
- if ((await context2.fs.readdir(directory2, { signal })).length) {
21108
- throw new FsError("ENOTEMPTY", { path: directory2, message: "unexpected staging entries; refusing recursive cleanup" });
21109
- }
21110
- await context2.fs.rm(directory2, { recursive: true, signal });
21314
+ await operation2.close();
21111
21315
  } catch (error) {
21316
+ if (cleanupFailed && error === failure) throw error;
21112
21317
  if (failed) {
21113
21318
  const aggregate = new AggregateError([failure, error], "compression failed and staging cleanup failed; input retained");
21114
21319
  throw new PublicDiagnostic(aggregate.message, { cause: aggregate });
21115
21320
  }
21116
21321
  throw error;
21117
21322
  }
21323
+ context2.signal.throwIfAborted();
21118
21324
  if (failed) throw failure;
21119
- if (!options2.keep) {
21120
- await unchangedSource(context2, plan);
21121
- await context2.fs.rm(plan.source, { signal: context2.signal });
21122
- }
21123
21325
  return warned2;
21124
21326
  }
21125
21327
 
@@ -26822,7 +27024,7 @@ async function writeZipArchive(archive, limits, signal) {
26822
27024
 
26823
27025
  // packages/safe-bash/src/commands/archive/zip/safety.ts
26824
27026
  init_platform();
26825
- import { retainFileSystemCleanup } from "@poe-platform/safe-fs/core";
27027
+ import { retainFileSystemCleanup as retainFileSystemCleanup2 } from "@poe-platform/safe-fs/core";
26826
27028
  var ZipScope = class {
26827
27029
  constructor(original, limits) {
26828
27030
  this.original = original;
@@ -26930,7 +27132,7 @@ async function publishZip(scope, prepared) {
26930
27132
  const owner = directory2 && await scope.stat(directory2.path);
26931
27133
  if (parent !== prepared.parent || !owner || owner.type !== "directory" || !sameIdentity2(owner, directory2.stat)) fail("ZIP temporary ownership changed before mutation");
26932
27134
  };
26933
- const close = retainFileSystemCleanup(fs, async (cleanup) => {
27135
+ const close = retainFileSystemCleanup2(fs, async (cleanup) => {
26934
27136
  if (!directory2 || !hasIdentity(directory2.stat)) return;
26935
27137
  const parent = await cleanup.realpath(prepared.parentName);
26936
27138
  const owner = await cleanup.lstat(directory2.path);
@@ -27435,7 +27637,7 @@ var Answers = class {
27435
27637
 
27436
27638
  // packages/safe-bash/src/commands/archive/unzip/safety.ts
27437
27639
  init_platform();
27438
- import { retainFileSystemCleanup as retainFileSystemCleanup2 } from "@poe-platform/safe-fs/core";
27640
+ import { retainFileSystemCleanup as retainFileSystemCleanup3 } from "@poe-platform/safe-fs/core";
27439
27641
  var Extraction = class {
27440
27642
  constructor(context2, limits) {
27441
27643
  this.context = context2;
@@ -27622,7 +27824,7 @@ var Extraction = class {
27622
27824
  let identity2;
27623
27825
  let created = false;
27624
27826
  let failure;
27625
- const cleanup = retainFileSystemCleanup2(fs, async (view) => {
27827
+ const cleanup = retainFileSystemCleanup3(fs, async (view) => {
27626
27828
  if (!created || !identity2) return;
27627
27829
  try {
27628
27830
  let parent = "/";
@@ -36599,6 +36801,7 @@ function composeAgentCommands(options2, executors) {
36599
36801
  const tsortLimits = options2.tsort?.limits;
36600
36802
  const factorLimits = options2.factor?.limits;
36601
36803
  const getoptLimits = options2.getopt?.limits;
36804
+ const hexdumpLimits = options2.hexdump?.limits;
36602
36805
  const whichLimits = options2.which?.limits;
36603
36806
  const timeoutOptions = options2.timeout;
36604
36807
  const applyPatchLimits = options2.applyPatch?.limits;
@@ -36636,7 +36839,8 @@ function composeAgentCommands(options2, executors) {
36636
36839
  ...createPrCommands({ ...prLimits === void 0 ? {} : { limits: prLimits }, ...prClock === void 0 ? {} : { clock: prClock } }),
36637
36840
  ...createTsortCommands(tsortLimits === void 0 ? {} : { limits: tsortLimits }),
36638
36841
  ...createFactorCommands(factorLimits === void 0 ? {} : { limits: factorLimits }),
36639
- ...createGetoptCommands(getoptLimits === void 0 ? {} : { limits: getoptLimits })
36842
+ ...createGetoptCommands(getoptLimits === void 0 ? {} : { limits: getoptLimits }),
36843
+ ...createHexdumpCommands(hexdumpLimits === void 0 ? {} : { limits: hexdumpLimits })
36640
36844
  );
36641
36845
  return new CommandRegistry(commands).list();
36642
36846
  }
@@ -53020,6 +53224,9 @@ export {
53020
53224
  createGetoptCommand,
53021
53225
  createGetoptCommands,
53022
53226
  createGrepAliasCommands,
53227
+ createHdCommand,
53228
+ createHexdumpCommand,
53229
+ createHexdumpCommands,
53023
53230
  createHtmlToMarkdownCommand,
53024
53231
  createHtmlToMarkdownCommands,
53025
53232
  createMemoryFileSystem2 as createMemoryFileSystem,
@@ -53077,6 +53284,7 @@ export {
53077
53284
  getCommandArguments,
53078
53285
  getoptCommands,
53079
53286
  grepAliasCommands,
53287
+ hexdumpCommands,
53080
53288
  htmlToMarkdownCommands,
53081
53289
  isAbsolutePath3 as isAbsolutePath,
53082
53290
  isErrnoCode,