@notiamo/runner 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +38 -0
  2. package/dist/cli.js +395 -254
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1045,8 +1045,8 @@ var require_safePathNames = __commonJS({
1045
1045
  })();
1046
1046
  Object.defineProperty(exports, "__esModule", { value: true });
1047
1047
  exports.isSafePathName = isSafePathName;
1048
- var path13 = __importStar(__require("path"));
1049
- function isSafePathName(name, localPath = path13) {
1048
+ var path14 = __importStar(__require("path"));
1049
+ function isSafePathName(name, localPath = path14) {
1050
1050
  if (!name || name === "." || name === ".." || name.includes("/")) {
1051
1051
  return false;
1052
1052
  }
@@ -1704,8 +1704,8 @@ var require_Client = __commonJS({
1704
1704
  /**
1705
1705
  * Set the working directory.
1706
1706
  */
1707
- async cd(path13) {
1708
- const validPath = await this.protectWhitespace(path13);
1707
+ async cd(path14) {
1708
+ const validPath = await this.protectWhitespace(path14);
1709
1709
  return this.send("CWD " + validPath);
1710
1710
  }
1711
1711
  /**
@@ -1718,8 +1718,8 @@ var require_Client = __commonJS({
1718
1718
  * Get the last modified time of a file. This is not supported by every FTP server, in which case
1719
1719
  * calling this method will throw an exception.
1720
1720
  */
1721
- async lastMod(path13) {
1722
- const validPath = await this.protectWhitespace(path13);
1721
+ async lastMod(path14) {
1722
+ const validPath = await this.protectWhitespace(path14);
1723
1723
  const res = await this.send(`MDTM ${validPath}`);
1724
1724
  const date5 = res.message.slice(4);
1725
1725
  return (0, parseListMLSD_1.parseMLSxDate)(date5);
@@ -1727,8 +1727,8 @@ var require_Client = __commonJS({
1727
1727
  /**
1728
1728
  * Get the size of a file.
1729
1729
  */
1730
- async size(path13) {
1731
- const validPath = await this.protectWhitespace(path13);
1730
+ async size(path14) {
1731
+ const validPath = await this.protectWhitespace(path14);
1732
1732
  const command = `SIZE ${validPath}`;
1733
1733
  const res = await this.send(command);
1734
1734
  const size = parseInt(res.message.slice(4), 10);
@@ -1755,8 +1755,8 @@ var require_Client = __commonJS({
1755
1755
  * You can ignore FTP error return codes which won't throw an exception if e.g.
1756
1756
  * the file doesn't exist.
1757
1757
  */
1758
- async remove(path13, ignoreErrorCodes = false) {
1759
- const validPath = await this.protectWhitespace(path13);
1758
+ async remove(path14, ignoreErrorCodes = false) {
1759
+ const validPath = await this.protectWhitespace(path14);
1760
1760
  if (ignoreErrorCodes) {
1761
1761
  return this.sendIgnoringError(`DELE ${validPath}`);
1762
1762
  }
@@ -1915,8 +1915,8 @@ var require_Client = __commonJS({
1915
1915
  *
1916
1916
  * @param [path] Path to remote file or directory.
1917
1917
  */
1918
- async list(path13 = "") {
1919
- const validPath = await this.protectWhitespace(path13);
1918
+ async list(path14 = "") {
1919
+ const validPath = await this.protectWhitespace(path14);
1920
1920
  let lastError;
1921
1921
  for (const candidate of this.availableListCommands) {
1922
1922
  const command = validPath === "" ? candidate : `${candidate} ${validPath}`;
@@ -2085,21 +2085,21 @@ var require_Client = __commonJS({
2085
2085
  /**
2086
2086
  * Remove an empty directory, will fail if not empty.
2087
2087
  */
2088
- async removeEmptyDir(path13) {
2089
- const validPath = await this.protectWhitespace(path13);
2088
+ async removeEmptyDir(path14) {
2089
+ const validPath = await this.protectWhitespace(path14);
2090
2090
  return this.send(`RMD ${validPath}`);
2091
2091
  }
2092
2092
  /**
2093
2093
  * FTP servers can't handle filenames that have leading whitespace. This method transforms
2094
2094
  * a given path to fix that issue for most cases.
2095
2095
  */
2096
- async protectWhitespace(path13) {
2097
- if (!path13.startsWith(" ")) {
2098
- return path13;
2096
+ async protectWhitespace(path14) {
2097
+ if (!path14.startsWith(" ")) {
2098
+ return path14;
2099
2099
  }
2100
2100
  const pwd = await this.pwd();
2101
2101
  const absolutePathPrefix = pwd.endsWith("/") ? pwd : pwd + "/";
2102
- return absolutePathPrefix + path13;
2102
+ return absolutePathPrefix + path14;
2103
2103
  }
2104
2104
  async _exitAtCurrentDirectory(func) {
2105
2105
  const userDir = await this.pwd();
@@ -2176,11 +2176,11 @@ var require_Client = __commonJS({
2176
2176
  }
2177
2177
  };
2178
2178
  exports.Client = Client3;
2179
- async function ensureLocalDirectory(path13) {
2179
+ async function ensureLocalDirectory(path14) {
2180
2180
  try {
2181
- await fsStat(path13);
2181
+ await fsStat(path14);
2182
2182
  } catch (_a3) {
2183
- await fsMkDir(path13, { recursive: true });
2183
+ await fsMkDir(path14, { recursive: true });
2184
2184
  }
2185
2185
  }
2186
2186
  async function expectedBytesFromLocalFile(fd, options) {
@@ -5088,20 +5088,20 @@ var require_compile = __commonJS({
5088
5088
  var util_1 = require_util();
5089
5089
  var validate_1 = require_validate();
5090
5090
  var SchemaEnv = class {
5091
- constructor(env) {
5091
+ constructor(env2) {
5092
5092
  var _a3;
5093
5093
  this.refs = {};
5094
5094
  this.dynamicAnchors = {};
5095
5095
  let schema;
5096
- if (typeof env.schema == "object")
5097
- schema = env.schema;
5098
- this.schema = env.schema;
5099
- this.schemaId = env.schemaId;
5100
- this.root = env.root || this;
5101
- this.baseId = (_a3 = env.baseId) !== null && _a3 !== void 0 ? _a3 : (0, resolve_1.normalizeId)(schema === null || schema === void 0 ? void 0 : schema[env.schemaId || "$id"]);
5102
- this.schemaPath = env.schemaPath;
5103
- this.localRefs = env.localRefs;
5104
- this.meta = env.meta;
5096
+ if (typeof env2.schema == "object")
5097
+ schema = env2.schema;
5098
+ this.schema = env2.schema;
5099
+ this.schemaId = env2.schemaId;
5100
+ this.root = env2.root || this;
5101
+ this.baseId = (_a3 = env2.baseId) !== null && _a3 !== void 0 ? _a3 : (0, resolve_1.normalizeId)(schema === null || schema === void 0 ? void 0 : schema[env2.schemaId || "$id"]);
5102
+ this.schemaPath = env2.schemaPath;
5103
+ this.localRefs = env2.localRefs;
5104
+ this.meta = env2.meta;
5105
5105
  this.$async = schema === null || schema === void 0 ? void 0 : schema.$async;
5106
5106
  this.refs = {};
5107
5107
  }
@@ -5285,15 +5285,15 @@ var require_compile = __commonJS({
5285
5285
  baseId = (0, resolve_1.resolveUrl)(this.opts.uriResolver, baseId, schId);
5286
5286
  }
5287
5287
  }
5288
- let env;
5288
+ let env2;
5289
5289
  if (typeof schema != "boolean" && schema.$ref && !(0, util_1.schemaHasRulesButRef)(schema, this.RULES)) {
5290
5290
  const $ref = (0, resolve_1.resolveUrl)(this.opts.uriResolver, baseId, schema.$ref);
5291
- env = resolveSchema.call(this, root, $ref);
5291
+ env2 = resolveSchema.call(this, root, $ref);
5292
5292
  }
5293
5293
  const { schemaId } = this.opts;
5294
- env = env || new SchemaEnv({ schema, schemaId, root, baseId });
5295
- if (env.schema !== env.root.schema)
5296
- return env;
5294
+ env2 = env2 || new SchemaEnv({ schema, schemaId, root, baseId });
5295
+ if (env2.schema !== env2.root.schema)
5296
+ return env2;
5297
5297
  return void 0;
5298
5298
  }
5299
5299
  }
@@ -5477,8 +5477,8 @@ var require_utils = __commonJS({
5477
5477
  }
5478
5478
  return ind;
5479
5479
  }
5480
- function removeDotSegments(path13) {
5481
- let input2 = path13;
5480
+ function removeDotSegments(path14) {
5481
+ let input2 = path14;
5482
5482
  const output2 = [];
5483
5483
  let nextSlash = -1;
5484
5484
  let len = 0;
@@ -5887,8 +5887,8 @@ var require_schemes = __commonJS({
5887
5887
  }
5888
5888
  if (wsComponent.resourceName) {
5889
5889
  const queryIndex = wsComponent.resourceName.indexOf("?");
5890
- const path13 = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
5891
- wsComponent.path = path13 && path13 !== "/" ? path13 : void 0;
5890
+ const path14 = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
5891
+ wsComponent.path = path14 && path14 !== "/" ? path14 : void 0;
5892
5892
  wsComponent.query = queryIndex === -1 ? void 0 : wsComponent.resourceName.slice(queryIndex + 1);
5893
5893
  wsComponent.resourceName = void 0;
5894
5894
  }
@@ -7091,8 +7091,8 @@ var require_ref = __commonJS({
7091
7091
  schemaType: "string",
7092
7092
  code(cxt) {
7093
7093
  const { gen, schema: $ref, it } = cxt;
7094
- const { baseId, schemaEnv: env, validateName, opts, self: self2 } = it;
7095
- const { root } = env;
7094
+ const { baseId, schemaEnv: env2, validateName, opts, self: self2 } = it;
7095
+ const { root } = env2;
7096
7096
  if (($ref === "#" || $ref === "#/") && baseId === root.baseId)
7097
7097
  return callRootRef();
7098
7098
  const schOrEnv = compile_1.resolveRef.call(self2, root, baseId, $ref);
@@ -7102,8 +7102,8 @@ var require_ref = __commonJS({
7102
7102
  return callValidate(schOrEnv);
7103
7103
  return inlineRefSchema(schOrEnv);
7104
7104
  function callRootRef() {
7105
- if (env === root)
7106
- return callRef(cxt, validateName, env, env.$async);
7105
+ if (env2 === root)
7106
+ return callRef(cxt, validateName, env2, env2.$async);
7107
7107
  const rootName = gen.scopeValue("root", { ref: root });
7108
7108
  return callRef(cxt, (0, codegen_1._)`${rootName}.validate`, root, root.$async);
7109
7109
  }
@@ -7133,14 +7133,14 @@ var require_ref = __commonJS({
7133
7133
  exports.getValidate = getValidate;
7134
7134
  function callRef(cxt, v, sch, $async) {
7135
7135
  const { gen, it } = cxt;
7136
- const { allErrors, schemaEnv: env, opts } = it;
7136
+ const { allErrors, schemaEnv: env2, opts } = it;
7137
7137
  const passCxt = opts.passContext ? names_1.default.this : codegen_1.nil;
7138
7138
  if ($async)
7139
7139
  callAsyncRef();
7140
7140
  else
7141
7141
  callSyncRef();
7142
7142
  function callAsyncRef() {
7143
- if (!env.$async)
7143
+ if (!env2.$async)
7144
7144
  throw new Error("async schema referenced by sync schema");
7145
7145
  const valid = gen.let("valid");
7146
7146
  gen.try(() => {
@@ -17567,11 +17567,11 @@ var require_agent = __commonJS({
17567
17567
  };
17568
17568
  })();
17569
17569
  var WINDOWS_PIPE_REGEX = /^[/\\][/\\]\.[/\\]pipe[/\\].+/;
17570
- function createAgent(path13) {
17571
- if (process.platform === "win32" && !WINDOWS_PIPE_REGEX.test(path13)) {
17572
- return path13 === "pageant" ? new PageantAgent() : new CygwinAgent(path13);
17570
+ function createAgent(path14) {
17571
+ if (process.platform === "win32" && !WINDOWS_PIPE_REGEX.test(path14)) {
17572
+ return path14 === "pageant" ? new PageantAgent() : new CygwinAgent(path14);
17573
17573
  }
17574
- return new OpenSSHAgent(path13);
17574
+ return new OpenSSHAgent(path14);
17575
17575
  }
17576
17576
  var AgentProtocol = (() => {
17577
17577
  const SSH_AGENTC_REQUEST_IDENTITIES = 11;
@@ -22815,17 +22815,17 @@ var require_SFTP = __commonJS({
22815
22815
  // ===========================================================================
22816
22816
  // Client-specific ===========================================================
22817
22817
  // ===========================================================================
22818
- createReadStream(path13, options) {
22818
+ createReadStream(path14, options) {
22819
22819
  if (this.server)
22820
22820
  throw new Error("Client-only method called in server mode");
22821
- return new ReadStream(this, path13, options);
22821
+ return new ReadStream(this, path14, options);
22822
22822
  }
22823
- createWriteStream(path13, options) {
22823
+ createWriteStream(path14, options) {
22824
22824
  if (this.server)
22825
22825
  throw new Error("Client-only method called in server mode");
22826
- return new WriteStream(this, path13, options);
22826
+ return new WriteStream(this, path14, options);
22827
22827
  }
22828
- open(path13, flags_, attrs, cb) {
22828
+ open(path14, flags_, attrs, cb) {
22829
22829
  if (this.server)
22830
22830
  throw new Error("Client-only method called in server mode");
22831
22831
  if (typeof attrs === "function") {
@@ -22844,7 +22844,7 @@ var require_SFTP = __commonJS({
22844
22844
  attrsFlags = attrs.flags;
22845
22845
  attrsLen = attrs.nb;
22846
22846
  }
22847
- const pathLen = Buffer.byteLength(path13);
22847
+ const pathLen = Buffer.byteLength(path14);
22848
22848
  let p = 9;
22849
22849
  const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen + 4 + 4 + attrsLen);
22850
22850
  writeUInt32BE(buf, buf.length - 4, 0);
@@ -22852,7 +22852,7 @@ var require_SFTP = __commonJS({
22852
22852
  const reqid = this._writeReqid = this._writeReqid + 1 & MAX_REQID;
22853
22853
  writeUInt32BE(buf, reqid, 5);
22854
22854
  writeUInt32BE(buf, pathLen, p);
22855
- buf.utf8Write(path13, p += 4, pathLen);
22855
+ buf.utf8Write(path14, p += 4, pathLen);
22856
22856
  writeUInt32BE(buf, flags, p += pathLen);
22857
22857
  writeUInt32BE(buf, attrsFlags, p += 4);
22858
22858
  if (attrsLen) {
@@ -22983,7 +22983,7 @@ var require_SFTP = __commonJS({
22983
22983
  throw new Error("Client-only method called in server mode");
22984
22984
  fastXfer(fs, this, localPath, remotePath, opts, cb);
22985
22985
  }
22986
- readFile(path13, options, callback_) {
22986
+ readFile(path14, options, callback_) {
22987
22987
  if (this.server)
22988
22988
  throw new Error("Client-only method called in server mode");
22989
22989
  let callback;
@@ -23056,13 +23056,13 @@ var require_SFTP = __commonJS({
23056
23056
  return callback && callback(er, buffer);
23057
23057
  });
23058
23058
  };
23059
- this.open(path13, flag, 438, (er, handle_) => {
23059
+ this.open(path14, flag, 438, (er, handle_) => {
23060
23060
  if (er)
23061
23061
  return callback && callback(er);
23062
23062
  handle = handle_;
23063
23063
  const tryStat = (er2, st) => {
23064
23064
  if (er2) {
23065
- this.stat(path13, (er_, st_) => {
23065
+ this.stat(path14, (er_, st_) => {
23066
23066
  if (er_) {
23067
23067
  return this.close(handle, () => {
23068
23068
  callback && callback(er2);
@@ -23083,7 +23083,7 @@ var require_SFTP = __commonJS({
23083
23083
  this.fstat(handle, tryStat);
23084
23084
  });
23085
23085
  }
23086
- writeFile(path13, data, options, callback_) {
23086
+ writeFile(path14, data, options, callback_) {
23087
23087
  if (this.server)
23088
23088
  throw new Error("Client-only method called in server mode");
23089
23089
  let callback;
@@ -23102,7 +23102,7 @@ var require_SFTP = __commonJS({
23102
23102
  if (options.encoding && !Buffer.isEncoding(options.encoding))
23103
23103
  throw new Error(`Unknown encoding: ${options.encoding}`);
23104
23104
  const flag = options.flag || "w";
23105
- this.open(path13, flag, options.mode, (openErr, handle) => {
23105
+ this.open(path14, flag, options.mode, (openErr, handle) => {
23106
23106
  if (openErr) {
23107
23107
  callback && callback(openErr);
23108
23108
  } else {
@@ -23111,7 +23111,7 @@ var require_SFTP = __commonJS({
23111
23111
  if (position === null) {
23112
23112
  const tryStat = (er, st) => {
23113
23113
  if (er) {
23114
- this.stat(path13, (er_, st_) => {
23114
+ this.stat(path14, (er_, st_) => {
23115
23115
  if (er_) {
23116
23116
  return this.close(handle, () => {
23117
23117
  callback && callback(er);
@@ -23130,7 +23130,7 @@ var require_SFTP = __commonJS({
23130
23130
  }
23131
23131
  });
23132
23132
  }
23133
- appendFile(path13, data, options, callback_) {
23133
+ appendFile(path14, data, options, callback_) {
23134
23134
  if (this.server)
23135
23135
  throw new Error("Client-only method called in server mode");
23136
23136
  let callback;
@@ -23148,12 +23148,12 @@ var require_SFTP = __commonJS({
23148
23148
  throw new TypeError("Bad arguments");
23149
23149
  if (!options.flag)
23150
23150
  options = Object.assign({ flag: "a" }, options);
23151
- this.writeFile(path13, data, options, callback);
23151
+ this.writeFile(path14, data, options, callback);
23152
23152
  }
23153
- exists(path13, cb) {
23153
+ exists(path14, cb) {
23154
23154
  if (this.server)
23155
23155
  throw new Error("Client-only method called in server mode");
23156
- this.stat(path13, (err) => {
23156
+ this.stat(path14, (err) => {
23157
23157
  cb && cb(err ? false : true);
23158
23158
  });
23159
23159
  }
@@ -23196,7 +23196,7 @@ var require_SFTP = __commonJS({
23196
23196
  `SFTP: Outbound: ${isBuffered ? "Buffered" : "Sending"} RENAME`
23197
23197
  );
23198
23198
  }
23199
- mkdir(path13, attrs, cb) {
23199
+ mkdir(path14, attrs, cb) {
23200
23200
  if (this.server)
23201
23201
  throw new Error("Client-only method called in server mode");
23202
23202
  let flags = 0;
@@ -23210,7 +23210,7 @@ var require_SFTP = __commonJS({
23210
23210
  flags = attrs.flags;
23211
23211
  attrsLen = attrs.nb;
23212
23212
  }
23213
- const pathLen = Buffer.byteLength(path13);
23213
+ const pathLen = Buffer.byteLength(path14);
23214
23214
  let p = 9;
23215
23215
  const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen + 4 + attrsLen);
23216
23216
  writeUInt32BE(buf, buf.length - 4, 0);
@@ -23218,7 +23218,7 @@ var require_SFTP = __commonJS({
23218
23218
  const reqid = this._writeReqid = this._writeReqid + 1 & MAX_REQID;
23219
23219
  writeUInt32BE(buf, reqid, 5);
23220
23220
  writeUInt32BE(buf, pathLen, p);
23221
- buf.utf8Write(path13, p += 4, pathLen);
23221
+ buf.utf8Write(path14, p += 4, pathLen);
23222
23222
  writeUInt32BE(buf, flags, p += pathLen);
23223
23223
  if (attrsLen) {
23224
23224
  p += 4;
@@ -23234,10 +23234,10 @@ var require_SFTP = __commonJS({
23234
23234
  `SFTP: Outbound: ${isBuffered ? "Buffered" : "Sending"} MKDIR`
23235
23235
  );
23236
23236
  }
23237
- rmdir(path13, cb) {
23237
+ rmdir(path14, cb) {
23238
23238
  if (this.server)
23239
23239
  throw new Error("Client-only method called in server mode");
23240
- const pathLen = Buffer.byteLength(path13);
23240
+ const pathLen = Buffer.byteLength(path14);
23241
23241
  let p = 9;
23242
23242
  const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen);
23243
23243
  writeUInt32BE(buf, buf.length - 4, 0);
@@ -23245,7 +23245,7 @@ var require_SFTP = __commonJS({
23245
23245
  const reqid = this._writeReqid = this._writeReqid + 1 & MAX_REQID;
23246
23246
  writeUInt32BE(buf, reqid, 5);
23247
23247
  writeUInt32BE(buf, pathLen, p);
23248
- buf.utf8Write(path13, p += 4, pathLen);
23248
+ buf.utf8Write(path14, p += 4, pathLen);
23249
23249
  this._requests[reqid] = { cb };
23250
23250
  const isBuffered = sendOrBuffer(this, buf);
23251
23251
  this._debug && this._debug(
@@ -23335,10 +23335,10 @@ var require_SFTP = __commonJS({
23335
23335
  `SFTP: Outbound: ${isBuffered ? "Buffered" : "Sending"} FSTAT`
23336
23336
  );
23337
23337
  }
23338
- stat(path13, cb) {
23338
+ stat(path14, cb) {
23339
23339
  if (this.server)
23340
23340
  throw new Error("Client-only method called in server mode");
23341
- const pathLen = Buffer.byteLength(path13);
23341
+ const pathLen = Buffer.byteLength(path14);
23342
23342
  let p = 9;
23343
23343
  const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen);
23344
23344
  writeUInt32BE(buf, buf.length - 4, 0);
@@ -23346,17 +23346,17 @@ var require_SFTP = __commonJS({
23346
23346
  const reqid = this._writeReqid = this._writeReqid + 1 & MAX_REQID;
23347
23347
  writeUInt32BE(buf, reqid, 5);
23348
23348
  writeUInt32BE(buf, pathLen, p);
23349
- buf.utf8Write(path13, p += 4, pathLen);
23349
+ buf.utf8Write(path14, p += 4, pathLen);
23350
23350
  this._requests[reqid] = { cb };
23351
23351
  const isBuffered = sendOrBuffer(this, buf);
23352
23352
  this._debug && this._debug(
23353
23353
  `SFTP: Outbound: ${isBuffered ? "Buffered" : "Sending"} STAT`
23354
23354
  );
23355
23355
  }
23356
- lstat(path13, cb) {
23356
+ lstat(path14, cb) {
23357
23357
  if (this.server)
23358
23358
  throw new Error("Client-only method called in server mode");
23359
- const pathLen = Buffer.byteLength(path13);
23359
+ const pathLen = Buffer.byteLength(path14);
23360
23360
  let p = 9;
23361
23361
  const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen);
23362
23362
  writeUInt32BE(buf, buf.length - 4, 0);
@@ -23364,17 +23364,17 @@ var require_SFTP = __commonJS({
23364
23364
  const reqid = this._writeReqid = this._writeReqid + 1 & MAX_REQID;
23365
23365
  writeUInt32BE(buf, reqid, 5);
23366
23366
  writeUInt32BE(buf, pathLen, p);
23367
- buf.utf8Write(path13, p += 4, pathLen);
23367
+ buf.utf8Write(path14, p += 4, pathLen);
23368
23368
  this._requests[reqid] = { cb };
23369
23369
  const isBuffered = sendOrBuffer(this, buf);
23370
23370
  this._debug && this._debug(
23371
23371
  `SFTP: Outbound: ${isBuffered ? "Buffered" : "Sending"} LSTAT`
23372
23372
  );
23373
23373
  }
23374
- opendir(path13, cb) {
23374
+ opendir(path14, cb) {
23375
23375
  if (this.server)
23376
23376
  throw new Error("Client-only method called in server mode");
23377
- const pathLen = Buffer.byteLength(path13);
23377
+ const pathLen = Buffer.byteLength(path14);
23378
23378
  let p = 9;
23379
23379
  const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen);
23380
23380
  writeUInt32BE(buf, buf.length - 4, 0);
@@ -23382,14 +23382,14 @@ var require_SFTP = __commonJS({
23382
23382
  const reqid = this._writeReqid = this._writeReqid + 1 & MAX_REQID;
23383
23383
  writeUInt32BE(buf, reqid, 5);
23384
23384
  writeUInt32BE(buf, pathLen, p);
23385
- buf.utf8Write(path13, p += 4, pathLen);
23385
+ buf.utf8Write(path14, p += 4, pathLen);
23386
23386
  this._requests[reqid] = { cb };
23387
23387
  const isBuffered = sendOrBuffer(this, buf);
23388
23388
  this._debug && this._debug(
23389
23389
  `SFTP: Outbound: ${isBuffered ? "Buffered" : "Sending"} OPENDIR`
23390
23390
  );
23391
23391
  }
23392
- setstat(path13, attrs, cb) {
23392
+ setstat(path14, attrs, cb) {
23393
23393
  if (this.server)
23394
23394
  throw new Error("Client-only method called in server mode");
23395
23395
  let flags = 0;
@@ -23401,7 +23401,7 @@ var require_SFTP = __commonJS({
23401
23401
  } else if (typeof attrs === "function") {
23402
23402
  cb = attrs;
23403
23403
  }
23404
- const pathLen = Buffer.byteLength(path13);
23404
+ const pathLen = Buffer.byteLength(path14);
23405
23405
  let p = 9;
23406
23406
  const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen + 4 + attrsLen);
23407
23407
  writeUInt32BE(buf, buf.length - 4, 0);
@@ -23409,7 +23409,7 @@ var require_SFTP = __commonJS({
23409
23409
  const reqid = this._writeReqid = this._writeReqid + 1 & MAX_REQID;
23410
23410
  writeUInt32BE(buf, reqid, 5);
23411
23411
  writeUInt32BE(buf, pathLen, p);
23412
- buf.utf8Write(path13, p += 4, pathLen);
23412
+ buf.utf8Write(path14, p += 4, pathLen);
23413
23413
  writeUInt32BE(buf, flags, p += pathLen);
23414
23414
  if (attrsLen) {
23415
23415
  p += 4;
@@ -23469,8 +23469,8 @@ var require_SFTP = __commonJS({
23469
23469
  mtime: toUnixTimestamp(mtime)
23470
23470
  }, cb);
23471
23471
  }
23472
- utimes(path13, atime, mtime, cb) {
23473
- return this.setstat(path13, {
23472
+ utimes(path14, atime, mtime, cb) {
23473
+ return this.setstat(path14, {
23474
23474
  atime: toUnixTimestamp(atime),
23475
23475
  mtime: toUnixTimestamp(mtime)
23476
23476
  }, cb);
@@ -23481,8 +23481,8 @@ var require_SFTP = __commonJS({
23481
23481
  gid
23482
23482
  }, cb);
23483
23483
  }
23484
- chown(path13, uid, gid, cb) {
23485
- return this.setstat(path13, {
23484
+ chown(path14, uid, gid, cb) {
23485
+ return this.setstat(path14, {
23486
23486
  uid,
23487
23487
  gid
23488
23488
  }, cb);
@@ -23492,15 +23492,15 @@ var require_SFTP = __commonJS({
23492
23492
  mode
23493
23493
  }, cb);
23494
23494
  }
23495
- chmod(path13, mode, cb) {
23496
- return this.setstat(path13, {
23495
+ chmod(path14, mode, cb) {
23496
+ return this.setstat(path14, {
23497
23497
  mode
23498
23498
  }, cb);
23499
23499
  }
23500
- readlink(path13, cb) {
23500
+ readlink(path14, cb) {
23501
23501
  if (this.server)
23502
23502
  throw new Error("Client-only method called in server mode");
23503
- const pathLen = Buffer.byteLength(path13);
23503
+ const pathLen = Buffer.byteLength(path14);
23504
23504
  let p = 9;
23505
23505
  const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen);
23506
23506
  writeUInt32BE(buf, buf.length - 4, 0);
@@ -23508,7 +23508,7 @@ var require_SFTP = __commonJS({
23508
23508
  const reqid = this._writeReqid = this._writeReqid + 1 & MAX_REQID;
23509
23509
  writeUInt32BE(buf, reqid, 5);
23510
23510
  writeUInt32BE(buf, pathLen, p);
23511
- buf.utf8Write(path13, p += 4, pathLen);
23511
+ buf.utf8Write(path14, p += 4, pathLen);
23512
23512
  this._requests[reqid] = {
23513
23513
  cb: (err, names) => {
23514
23514
  if (typeof cb !== "function")
@@ -23553,10 +23553,10 @@ var require_SFTP = __commonJS({
23553
23553
  `SFTP: Outbound: ${isBuffered ? "Buffered" : "Sending"} SYMLINK`
23554
23554
  );
23555
23555
  }
23556
- realpath(path13, cb) {
23556
+ realpath(path14, cb) {
23557
23557
  if (this.server)
23558
23558
  throw new Error("Client-only method called in server mode");
23559
- const pathLen = Buffer.byteLength(path13);
23559
+ const pathLen = Buffer.byteLength(path14);
23560
23560
  let p = 9;
23561
23561
  const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen);
23562
23562
  writeUInt32BE(buf, buf.length - 4, 0);
@@ -23564,7 +23564,7 @@ var require_SFTP = __commonJS({
23564
23564
  const reqid = this._writeReqid = this._writeReqid + 1 & MAX_REQID;
23565
23565
  writeUInt32BE(buf, reqid, 5);
23566
23566
  writeUInt32BE(buf, pathLen, p);
23567
- buf.utf8Write(path13, p += 4, pathLen);
23567
+ buf.utf8Write(path14, p += 4, pathLen);
23568
23568
  this._requests[reqid] = {
23569
23569
  cb: (err, names) => {
23570
23570
  if (typeof cb !== "function")
@@ -23609,13 +23609,13 @@ var require_SFTP = __commonJS({
23609
23609
  this._debug(`SFTP: Outbound: ${which} posix-rename@openssh.com`);
23610
23610
  }
23611
23611
  }
23612
- ext_openssh_statvfs(path13, cb) {
23612
+ ext_openssh_statvfs(path14, cb) {
23613
23613
  if (this.server)
23614
23614
  throw new Error("Client-only method called in server mode");
23615
23615
  const ext = this._extensions["statvfs@openssh.com"];
23616
23616
  if (!ext || ext !== "2")
23617
23617
  throw new Error("Server does not support this extended request");
23618
- const pathLen = Buffer.byteLength(path13);
23618
+ const pathLen = Buffer.byteLength(path14);
23619
23619
  let p = 9;
23620
23620
  const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + 19 + 4 + pathLen);
23621
23621
  writeUInt32BE(buf, buf.length - 4, 0);
@@ -23625,7 +23625,7 @@ var require_SFTP = __commonJS({
23625
23625
  writeUInt32BE(buf, 19, p);
23626
23626
  buf.utf8Write("statvfs@openssh.com", p += 4, 19);
23627
23627
  writeUInt32BE(buf, pathLen, p += 19);
23628
- buf.utf8Write(path13, p += 4, pathLen);
23628
+ buf.utf8Write(path14, p += 4, pathLen);
23629
23629
  this._requests[reqid] = { extended: "statvfs@openssh.com", cb };
23630
23630
  const isBuffered = sendOrBuffer(this, buf);
23631
23631
  if (this._debug) {
@@ -23711,7 +23711,7 @@ var require_SFTP = __commonJS({
23711
23711
  `SFTP: Outbound: ${isBuffered ? "Buffered" : "Sending"} fsync@openssh.com`
23712
23712
  );
23713
23713
  }
23714
- ext_openssh_lsetstat(path13, attrs, cb) {
23714
+ ext_openssh_lsetstat(path14, attrs, cb) {
23715
23715
  if (this.server)
23716
23716
  throw new Error("Client-only method called in server mode");
23717
23717
  const ext = this._extensions["lsetstat@openssh.com"];
@@ -23726,7 +23726,7 @@ var require_SFTP = __commonJS({
23726
23726
  } else if (typeof attrs === "function") {
23727
23727
  cb = attrs;
23728
23728
  }
23729
- const pathLen = Buffer.byteLength(path13);
23729
+ const pathLen = Buffer.byteLength(path14);
23730
23730
  let p = 9;
23731
23731
  const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + 20 + 4 + pathLen + 4 + attrsLen);
23732
23732
  writeUInt32BE(buf, buf.length - 4, 0);
@@ -23736,7 +23736,7 @@ var require_SFTP = __commonJS({
23736
23736
  writeUInt32BE(buf, 20, p);
23737
23737
  buf.utf8Write("lsetstat@openssh.com", p += 4, 20);
23738
23738
  writeUInt32BE(buf, pathLen, p += 20);
23739
- buf.utf8Write(path13, p += 4, pathLen);
23739
+ buf.utf8Write(path14, p += 4, pathLen);
23740
23740
  writeUInt32BE(buf, flags, p += pathLen);
23741
23741
  if (attrsLen) {
23742
23742
  p += 4;
@@ -23753,13 +23753,13 @@ var require_SFTP = __commonJS({
23753
23753
  this._debug(`SFTP: Outbound: ${status5} lsetstat@openssh.com`);
23754
23754
  }
23755
23755
  }
23756
- ext_openssh_expandPath(path13, cb) {
23756
+ ext_openssh_expandPath(path14, cb) {
23757
23757
  if (this.server)
23758
23758
  throw new Error("Client-only method called in server mode");
23759
23759
  const ext = this._extensions["expand-path@openssh.com"];
23760
23760
  if (ext !== "1")
23761
23761
  throw new Error("Server does not support this extended request");
23762
- const pathLen = Buffer.byteLength(path13);
23762
+ const pathLen = Buffer.byteLength(path14);
23763
23763
  let p = 9;
23764
23764
  const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + 23 + 4 + pathLen);
23765
23765
  writeUInt32BE(buf, buf.length - 4, 0);
@@ -23769,7 +23769,7 @@ var require_SFTP = __commonJS({
23769
23769
  writeUInt32BE(buf, 23, p);
23770
23770
  buf.utf8Write("expand-path@openssh.com", p += 4, 23);
23771
23771
  writeUInt32BE(buf, pathLen, p += 20);
23772
- buf.utf8Write(path13, p += 4, pathLen);
23772
+ buf.utf8Write(path14, p += 4, pathLen);
23773
23773
  this._requests[reqid] = {
23774
23774
  cb: (err, names) => {
23775
23775
  if (typeof cb !== "function")
@@ -25047,12 +25047,12 @@ var require_SFTP = __commonJS({
25047
25047
  [REQUEST.LSTAT]: (sftp, payload) => {
25048
25048
  bufferParser.init(payload, 1);
25049
25049
  const reqID = bufferParser.readUInt32BE();
25050
- const path13 = bufferParser.readString(true);
25050
+ const path14 = bufferParser.readString(true);
25051
25051
  bufferParser.clear();
25052
- if (path13 === void 0)
25052
+ if (path14 === void 0)
25053
25053
  return doFatalSFTPError(sftp, "Malformed LSTAT packet");
25054
25054
  sftp._debug && sftp._debug(`SFTP: Inbound: Received LSTAT (id:${reqID})`);
25055
- if (!sftp.emit("LSTAT", reqID, path13)) {
25055
+ if (!sftp.emit("LSTAT", reqID, path14)) {
25056
25056
  sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED);
25057
25057
  }
25058
25058
  },
@@ -25071,13 +25071,13 @@ var require_SFTP = __commonJS({
25071
25071
  [REQUEST.SETSTAT]: (sftp, payload) => {
25072
25072
  bufferParser.init(payload, 1);
25073
25073
  const reqID = bufferParser.readUInt32BE();
25074
- const path13 = bufferParser.readString(true);
25074
+ const path14 = bufferParser.readString(true);
25075
25075
  const attrs = readAttrs(sftp._biOpt);
25076
25076
  bufferParser.clear();
25077
25077
  if (attrs === void 0)
25078
25078
  return doFatalSFTPError(sftp, "Malformed SETSTAT packet");
25079
25079
  sftp._debug && sftp._debug(`SFTP: Inbound: Received SETSTAT (id:${reqID})`);
25080
- if (!sftp.emit("SETSTAT", reqID, path13, attrs)) {
25080
+ if (!sftp.emit("SETSTAT", reqID, path14, attrs)) {
25081
25081
  sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED);
25082
25082
  }
25083
25083
  },
@@ -25099,12 +25099,12 @@ var require_SFTP = __commonJS({
25099
25099
  [REQUEST.OPENDIR]: (sftp, payload) => {
25100
25100
  bufferParser.init(payload, 1);
25101
25101
  const reqID = bufferParser.readUInt32BE();
25102
- const path13 = bufferParser.readString(true);
25102
+ const path14 = bufferParser.readString(true);
25103
25103
  bufferParser.clear();
25104
- if (path13 === void 0)
25104
+ if (path14 === void 0)
25105
25105
  return doFatalSFTPError(sftp, "Malformed OPENDIR packet");
25106
25106
  sftp._debug && sftp._debug(`SFTP: Inbound: Received OPENDIR (id:${reqID})`);
25107
- if (!sftp.emit("OPENDIR", reqID, path13)) {
25107
+ if (!sftp.emit("OPENDIR", reqID, path14)) {
25108
25108
  sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED);
25109
25109
  }
25110
25110
  },
@@ -25123,63 +25123,63 @@ var require_SFTP = __commonJS({
25123
25123
  [REQUEST.REMOVE]: (sftp, payload) => {
25124
25124
  bufferParser.init(payload, 1);
25125
25125
  const reqID = bufferParser.readUInt32BE();
25126
- const path13 = bufferParser.readString(true);
25126
+ const path14 = bufferParser.readString(true);
25127
25127
  bufferParser.clear();
25128
- if (path13 === void 0)
25128
+ if (path14 === void 0)
25129
25129
  return doFatalSFTPError(sftp, "Malformed REMOVE packet");
25130
25130
  sftp._debug && sftp._debug(`SFTP: Inbound: Received REMOVE (id:${reqID})`);
25131
- if (!sftp.emit("REMOVE", reqID, path13)) {
25131
+ if (!sftp.emit("REMOVE", reqID, path14)) {
25132
25132
  sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED);
25133
25133
  }
25134
25134
  },
25135
25135
  [REQUEST.MKDIR]: (sftp, payload) => {
25136
25136
  bufferParser.init(payload, 1);
25137
25137
  const reqID = bufferParser.readUInt32BE();
25138
- const path13 = bufferParser.readString(true);
25138
+ const path14 = bufferParser.readString(true);
25139
25139
  const attrs = readAttrs(sftp._biOpt);
25140
25140
  bufferParser.clear();
25141
25141
  if (attrs === void 0)
25142
25142
  return doFatalSFTPError(sftp, "Malformed MKDIR packet");
25143
25143
  sftp._debug && sftp._debug(`SFTP: Inbound: Received MKDIR (id:${reqID})`);
25144
- if (!sftp.emit("MKDIR", reqID, path13, attrs)) {
25144
+ if (!sftp.emit("MKDIR", reqID, path14, attrs)) {
25145
25145
  sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED);
25146
25146
  }
25147
25147
  },
25148
25148
  [REQUEST.RMDIR]: (sftp, payload) => {
25149
25149
  bufferParser.init(payload, 1);
25150
25150
  const reqID = bufferParser.readUInt32BE();
25151
- const path13 = bufferParser.readString(true);
25151
+ const path14 = bufferParser.readString(true);
25152
25152
  bufferParser.clear();
25153
- if (path13 === void 0)
25153
+ if (path14 === void 0)
25154
25154
  return doFatalSFTPError(sftp, "Malformed RMDIR packet");
25155
25155
  sftp._debug && sftp._debug(`SFTP: Inbound: Received RMDIR (id:${reqID})`);
25156
- if (!sftp.emit("RMDIR", reqID, path13)) {
25156
+ if (!sftp.emit("RMDIR", reqID, path14)) {
25157
25157
  sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED);
25158
25158
  }
25159
25159
  },
25160
25160
  [REQUEST.REALPATH]: (sftp, payload) => {
25161
25161
  bufferParser.init(payload, 1);
25162
25162
  const reqID = bufferParser.readUInt32BE();
25163
- const path13 = bufferParser.readString(true);
25163
+ const path14 = bufferParser.readString(true);
25164
25164
  bufferParser.clear();
25165
- if (path13 === void 0)
25165
+ if (path14 === void 0)
25166
25166
  return doFatalSFTPError(sftp, "Malformed REALPATH packet");
25167
25167
  sftp._debug && sftp._debug(
25168
25168
  `SFTP: Inbound: Received REALPATH (id:${reqID})`
25169
25169
  );
25170
- if (!sftp.emit("REALPATH", reqID, path13)) {
25170
+ if (!sftp.emit("REALPATH", reqID, path14)) {
25171
25171
  sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED);
25172
25172
  }
25173
25173
  },
25174
25174
  [REQUEST.STAT]: (sftp, payload) => {
25175
25175
  bufferParser.init(payload, 1);
25176
25176
  const reqID = bufferParser.readUInt32BE();
25177
- const path13 = bufferParser.readString(true);
25177
+ const path14 = bufferParser.readString(true);
25178
25178
  bufferParser.clear();
25179
- if (path13 === void 0)
25179
+ if (path14 === void 0)
25180
25180
  return doFatalSFTPError(sftp, "Malformed STAT packet");
25181
25181
  sftp._debug && sftp._debug(`SFTP: Inbound: Received STAT (id:${reqID})`);
25182
- if (!sftp.emit("STAT", reqID, path13)) {
25182
+ if (!sftp.emit("STAT", reqID, path14)) {
25183
25183
  sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED);
25184
25184
  }
25185
25185
  },
@@ -25199,14 +25199,14 @@ var require_SFTP = __commonJS({
25199
25199
  [REQUEST.READLINK]: (sftp, payload) => {
25200
25200
  bufferParser.init(payload, 1);
25201
25201
  const reqID = bufferParser.readUInt32BE();
25202
- const path13 = bufferParser.readString(true);
25202
+ const path14 = bufferParser.readString(true);
25203
25203
  bufferParser.clear();
25204
- if (path13 === void 0)
25204
+ if (path14 === void 0)
25205
25205
  return doFatalSFTPError(sftp, "Malformed READLINK packet");
25206
25206
  sftp._debug && sftp._debug(
25207
25207
  `SFTP: Inbound: Received READLINK (id:${reqID})`
25208
25208
  );
25209
- if (!sftp.emit("READLINK", reqID, path13)) {
25209
+ if (!sftp.emit("READLINK", reqID, path14)) {
25210
25210
  sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED);
25211
25211
  }
25212
25212
  },
@@ -25277,7 +25277,7 @@ var require_SFTP = __commonJS({
25277
25277
  function roundUpToMultipleOf8(n) {
25278
25278
  return n + 7 & ~7;
25279
25279
  }
25280
- function ReadStream(sftp, path13, options) {
25280
+ function ReadStream(sftp, path14, options) {
25281
25281
  if (options === void 0)
25282
25282
  options = {};
25283
25283
  else if (typeof options === "string")
@@ -25291,7 +25291,7 @@ var require_SFTP = __commonJS({
25291
25291
  options.emitClose = false;
25292
25292
  options.autoDestroy = false;
25293
25293
  ReadableStream2.call(this, options);
25294
- this.path = path13;
25294
+ this.path = path14;
25295
25295
  this.flags = options.flags === void 0 ? "r" : options.flags;
25296
25296
  this.mode = options.mode === void 0 ? 438 : options.mode;
25297
25297
  this.start = options.start;
@@ -25422,7 +25422,7 @@ var require_SFTP = __commonJS({
25422
25422
  },
25423
25423
  configurable: true
25424
25424
  });
25425
- function WriteStream(sftp, path13, options) {
25425
+ function WriteStream(sftp, path14, options) {
25426
25426
  if (options === void 0)
25427
25427
  options = {};
25428
25428
  else if (typeof options === "string")
@@ -25434,7 +25434,7 @@ var require_SFTP = __commonJS({
25434
25434
  options.emitClose = false;
25435
25435
  options.autoDestroy = false;
25436
25436
  WritableStream.call(this, options);
25437
- this.path = path13;
25437
+ this.path = path14;
25438
25438
  this.flags = options.flags === void 0 ? "w" : options.flags;
25439
25439
  this.mode = options.mode === void 0 ? 438 : options.mode;
25440
25440
  this.start = options.start;
@@ -27403,12 +27403,12 @@ var require_client = __commonJS({
27403
27403
  );
27404
27404
  return this;
27405
27405
  }
27406
- sftp(env, cb) {
27406
+ sftp(env2, cb) {
27407
27407
  if (!this._sock || !isWritable(this._sock))
27408
27408
  throw new Error("Not connected");
27409
- if (typeof env === "function") {
27410
- cb = env;
27411
- env = void 0;
27409
+ if (typeof env2 === "function") {
27410
+ cb = env2;
27411
+ env2 = void 0;
27412
27412
  }
27413
27413
  openChannel(this, "sftp", (err, sftp) => {
27414
27414
  if (err) {
@@ -27451,8 +27451,8 @@ var require_client = __commonJS({
27451
27451
  sftp.on("ready", onReady).on("error", onError).on("exit", onExit).on("close", onExit);
27452
27452
  sftp._init();
27453
27453
  };
27454
- if (typeof env === "object" && env !== null) {
27455
- reqEnv(sftp, env, (err2) => {
27454
+ if (typeof env2 === "object" && env2 !== null) {
27455
+ reqEnv(sftp, env2, (err2) => {
27456
27456
  if (err2) {
27457
27457
  cb(err2);
27458
27458
  return;
@@ -27657,7 +27657,7 @@ var require_client = __commonJS({
27657
27657
  });
27658
27658
  chan._client._protocol.exec(chan.outgoing.id, cmd, true);
27659
27659
  }
27660
- function reqEnv(chan, env, cb) {
27660
+ function reqEnv(chan, env2, cb) {
27661
27661
  const wantReply = typeof cb === "function";
27662
27662
  if (chan.outgoing.state !== "open") {
27663
27663
  if (wantReply)
@@ -27673,10 +27673,10 @@ var require_client = __commonJS({
27673
27673
  cb();
27674
27674
  });
27675
27675
  }
27676
- const keys = Object.keys(env || {});
27676
+ const keys = Object.keys(env2 || {});
27677
27677
  for (let i = 0; i < keys.length; ++i) {
27678
27678
  const key = keys[i];
27679
- const val = env[key];
27679
+ const val = env2[key];
27680
27680
  chan._client._protocol.env(chan.outgoing.id, key, val, wantReply);
27681
27681
  }
27682
27682
  }
@@ -29659,7 +29659,9 @@ function paths(dir) {
29659
29659
  /** Each run's Claude Code settings file, `<runId>.json`, there only while the run lasts. */
29660
29660
  runsDir: path.join(dir, "runs"),
29661
29661
  /** The runner's bare mirrors of the projects' repositories: the only ones that talk to GitHub. */
29662
- gitDir: path.join(dir, "git")
29662
+ gitDir: path.join(dir, "git"),
29663
+ /** One `<projectId>.env` per project the machine's owner gives variables to (see project-env.ts). */
29664
+ envDir: path.join(dir, "env")
29663
29665
  };
29664
29666
  }
29665
29667
  function loadConfig(dir = defaultDir()) {
@@ -29682,6 +29684,7 @@ function saveConfig(cfg, dir = defaultDir()) {
29682
29684
  }
29683
29685
 
29684
29686
  // src/args.ts
29687
+ var WITH_ARG = /* @__PURE__ */ new Set(["env"]);
29685
29688
  function parseArgs(argv) {
29686
29689
  const out = {};
29687
29690
  for (let i = 0; i < argv.length; i++) {
@@ -29691,13 +29694,14 @@ function parseArgs(argv) {
29691
29694
  if (!v || !PROFILE_RE.test(v)) return { error: `--profile needs a name of letters, digits and dashes (1 to 32), not "${v ?? ""}".` };
29692
29695
  out.profile = v;
29693
29696
  } else if (out.cmd === void 0) out.cmd = a;
29697
+ else if (out.arg === void 0 && WITH_ARG.has(out.cmd)) out.arg = a;
29694
29698
  else return { error: `Unexpected argument: ${a}` };
29695
29699
  }
29696
29700
  return out;
29697
29701
  }
29698
29702
 
29699
29703
  // src/commands.ts
29700
- import { readFileSync as readFileSync4 } from "node:fs";
29704
+ import { readFileSync as readFileSync5 } from "node:fs";
29701
29705
  import os6 from "node:os";
29702
29706
  import { createInterface } from "node:readline/promises";
29703
29707
  import { Writable as Writable2 } from "node:stream";
@@ -29813,9 +29817,9 @@ var ENV_ALLOW_WINDOWS = [
29813
29817
  "TEMP",
29814
29818
  "TMP"
29815
29819
  ];
29816
- function baseEnv(env, windows) {
29820
+ function baseEnv(env2, windows) {
29817
29821
  const out = {};
29818
- for (const [k, v] of Object.entries(env)) {
29822
+ for (const [k, v] of Object.entries(env2)) {
29819
29823
  if (v === void 0) continue;
29820
29824
  const key = windows ? k.toUpperCase() : k;
29821
29825
  if (!(ENV_ALLOW.includes(key) || ENV_ALLOW_PREFIX.some((p) => key.startsWith(p)) || windows && ENV_ALLOW_WINDOWS.includes(key))) continue;
@@ -29884,8 +29888,9 @@ function claudeEngine(deps = {}) {
29884
29888
  "user"
29885
29889
  ];
29886
29890
  const engineEnv = (o) => ({
29887
- ...baseEnv(deps.env ?? process.env, windows),
29891
+ // The project's own variables first: the runner's environment (PATH, proxies, CA files…) and its tokens win.
29888
29892
  ...o.env,
29893
+ ...baseEnv(deps.env ?? process.env, windows),
29889
29894
  ...AGENT_GIT_ENV,
29890
29895
  CLAUDE_CONFIG_DIR: o.claudeConfigDir,
29891
29896
  NOTIAMO_RUN_TOKEN: o.mcp.token,
@@ -30156,11 +30161,11 @@ var realExec = async (file2, args, opts) => {
30156
30161
  if (r.code === 127 && process.platform === "win32") return run(file2, args.map(quoteForCmd), opts?.env, true, opts?.timeout);
30157
30162
  return r;
30158
30163
  };
30159
- function run(file2, args, env, shell, timeout) {
30164
+ function run(file2, args, env2, shell, timeout) {
30160
30165
  return new Promise((resolve) => {
30161
30166
  let stdout = "";
30162
30167
  let stderr = "";
30163
- const child = spawn2(file2, args, { env: env ?? process.env, shell, stdio: ["ignore", "pipe", "pipe"], windowsHide: true, ...timeout ? { timeout, killSignal: "SIGKILL" } : {} });
30168
+ const child = spawn2(file2, args, { env: env2 ?? process.env, shell, stdio: ["ignore", "pipe", "pipe"], windowsHide: true, ...timeout ? { timeout, killSignal: "SIGKILL" } : {} });
30164
30169
  child.stdout.on("data", (d) => {
30165
30170
  stdout += d.toString();
30166
30171
  });
@@ -30267,8 +30272,8 @@ function findOnPath(name, dirs, platform) {
30267
30272
  }
30268
30273
  return null;
30269
30274
  }
30270
- function machineToolDirs(env = process.env, argv1 = process.argv[1], execPath = process.execPath, platform = process.platform) {
30271
- const pathDirs = (env.PATH ?? env.Path ?? "").split(path2.delimiter).filter((d) => d && path2.isAbsolute(d));
30275
+ function machineToolDirs(env2 = process.env, argv1 = process.argv[1], execPath = process.execPath, platform = process.platform) {
30276
+ const pathDirs = (env2.PATH ?? env2.Path ?? "").split(path2.delimiter).filter((d) => d && path2.isAbsolute(d));
30272
30277
  const dirs = pathDirs.map(realPath);
30273
30278
  for (const bin of ["git", "claude"]) {
30274
30279
  const found = findOnPath(bin, pathDirs, platform);
@@ -30422,8 +30427,9 @@ function sandboxSettings(o) {
30422
30427
  },
30423
30428
  network: {
30424
30429
  allowedDomains: [...new Set(domains)],
30425
- // macOS: lets the engine's shell commands reach the run's local helper on 127.0.0.1 (no effect on Linux).
30426
- ...o.wordpressHost ? { allowLocalBinding: true } : {}
30430
+ // macOS: lets the engine's shell commands reach 127.0.0.1: the run's local helper on a WordPress run, the
30431
+ // owner's own services (Postgres, MinIO…) on a project with an env file (no effect on Linux).
30432
+ ...o.wordpressHost || o.localServices ? { allowLocalBinding: true } : {}
30427
30433
  }
30428
30434
  }
30429
30435
  };
@@ -30444,9 +30450,9 @@ import path3 from "node:path";
30444
30450
 
30445
30451
  // src/service/common.ts
30446
30452
  var startArgs = (profile) => profile ? ["start", "--profile", profile] : ["start"];
30447
- function serviceEnv(env = {}) {
30453
+ function serviceEnv(env2 = {}) {
30448
30454
  const out = {};
30449
- for (const k of ["PATH", "NOTIAMO_RUNNER_HOME"]) if (env[k]) out[k] = env[k];
30455
+ for (const k of ["PATH", "NOTIAMO_RUNNER_HOME"]) if (env2[k]) out[k] = env2[k];
30450
30456
  return out;
30451
30457
  }
30452
30458
  function must(what, r) {
@@ -30461,7 +30467,7 @@ var BOOTSTRAP_TRIES = 5;
30461
30467
  var BOOTSTRAP_RETRY_MS = 500;
30462
30468
  var esc = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
30463
30469
  function renderPlist(o) {
30464
- const env = Object.entries(serviceEnv(o.env)).map(([k, v]) => ` <key>${esc(k)}</key>
30470
+ const env2 = Object.entries(serviceEnv(o.env)).map(([k, v]) => ` <key>${esc(k)}</key>
30465
30471
  <string>${esc(v)}</string>`).join("\n");
30466
30472
  return `<?xml version="1.0" encoding="UTF-8"?>
30467
30473
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -30487,7 +30493,7 @@ ${startArgs(o.profile).map((a) => ` <string>${esc(a)}</string>`).join("\n")}
30487
30493
  <string>${esc(o.log)}</string>
30488
30494
  <key>EnvironmentVariables</key>
30489
30495
  <dict>
30490
- ${env}
30496
+ ${env2}
30491
30497
  </dict>
30492
30498
  </dict>
30493
30499
  </plist>
@@ -30536,7 +30542,7 @@ var unit = (profile) => profile ? `notiamo-runner-${profile}` : "notiamo-runner"
30536
30542
  var unitPath = (home, profile) => path4.join(home, ".config", "systemd", "user", `${unit(profile)}.service`);
30537
30543
  var q = (s) => `"${s.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
30538
30544
  function renderUnit(o) {
30539
- const env = Object.entries(serviceEnv(o.env)).map(([k, v]) => `Environment=${q(`${k}=${v}`)}`).join("\n");
30545
+ const env2 = Object.entries(serviceEnv(o.env)).map(([k, v]) => `Environment=${q(`${k}=${v}`)}`).join("\n");
30540
30546
  return `[Unit]
30541
30547
  Description=Notiamo runner${o.profile ? ` (${o.profile})` : ""}
30542
30548
  After=network-online.target
@@ -30547,7 +30553,7 @@ Restart=always
30547
30553
  RestartSec=5
30548
30554
  StandardOutput=append:${o.log}
30549
30555
  StandardError=append:${o.log}
30550
- ${env}
30556
+ ${env2}
30551
30557
 
30552
30558
  [Install]
30553
30559
  WantedBy=default.target
@@ -30623,8 +30629,8 @@ var serviceStatus = async (o) => impl(o).status(withUid(o));
30623
30629
  // src/init.ts
30624
30630
  var DEFAULT_HOST = "https://my.notiamo.com";
30625
30631
  var KEYCHAIN_WARNING = "Warning: this user's keychain holds a GitHub login. A run on this machine could reach it. Remove it (Keychain Access, search github.com) or install the runner under a separate macOS user. The runner itself does not need it.";
30626
- var runInteractive = (file2, args, env) => new Promise((resolve, reject) => {
30627
- const child = spawn3(file2, args, { stdio: "inherit", env, shell: process.platform === "win32" });
30632
+ var runInteractive = (file2, args, env2) => new Promise((resolve, reject) => {
30633
+ const child = spawn3(file2, args, { stdio: "inherit", env: env2, shell: process.platform === "win32" });
30628
30634
  child.on("error", reject);
30629
30635
  child.on("exit", (code) => resolve(code ?? 1));
30630
30636
  });
@@ -30636,7 +30642,7 @@ async function runInit(deps) {
30636
30642
  const dir = deps.dir ?? profileDir(deps.profile);
30637
30643
  const platform = deps.platform ?? process.platform;
30638
30644
  const p = paths(dir);
30639
- const env = deps.env ?? process.env;
30645
+ const env2 = deps.env ?? process.env;
30640
30646
  const print = deps.print ?? ((s) => console.log(s));
30641
30647
  const ask = async (q2, def) => (await deps.prompt(q2, { default: def })).trim() || def;
30642
30648
  const token = (await deps.prompt("Runner token (made in Notiamo under Settings \u203A Agent runs \u203A Runners; nothing shows while you paste it): ", { hidden: true })).trim();
@@ -30644,21 +30650,21 @@ async function runInit(deps) {
30644
30650
  const host = normalizeHost(await ask("Notiamo address: ", DEFAULT_HOST));
30645
30651
  const hostname3 = deps.hostname ?? os4.hostname();
30646
30652
  const name = await ask("Name of this runner: ", hostname3);
30647
- const engineVersion = await checkMachine(deps, env, platform, print);
30653
+ const engineVersion = await checkMachine(deps, env2, platform, print);
30648
30654
  try {
30649
30655
  await new NotiamoApi({ host, token }, deps.fetch).hello({ version: VERSION, os: platform, engine: "claude", engineVersion });
30650
30656
  } catch (e) {
30651
30657
  if (e instanceof ApiError && e.status === 401) throw new Error("The runner token was not accepted.");
30652
30658
  throw new Error(`Notiamo at ${host} did not answer: ${e instanceof Error ? e.message : String(e)}`);
30653
30659
  }
30654
- const claudeEnv = { ...env, CLAUDE_CONFIG_DIR: p.claudeConfigDir };
30660
+ const claudeEnv = { ...env2, CLAUDE_CONFIG_DIR: p.claudeConfigDir };
30655
30661
  if (!deps.skipLogin) {
30656
30662
  print("Sign Claude Code in for the runner (its own sign-in, kept apart from yours):");
30657
30663
  await (deps.interactive ?? runInteractive)("claude", ["auth", "login"], claudeEnv);
30658
30664
  }
30659
30665
  const check2 = await deps.exec("claude", ["-p", "say ok"], { env: claudeEnv });
30660
30666
  if (check2.code !== 0) throw new Error("Claude Code is not signed in for the runner.");
30661
- await warnKeychain(deps, env, platform, print);
30667
+ await warnKeychain(deps, env2, platform, print);
30662
30668
  saveConfig({ host, token, name, dataDir: dir, engine: "claude" }, dir);
30663
30669
  await installService({
30664
30670
  platform,
@@ -30666,26 +30672,26 @@ async function runInit(deps) {
30666
30672
  paths: p,
30667
30673
  exec: deps.exec,
30668
30674
  home: deps.home ?? os4.homedir(),
30669
- env,
30675
+ env: env2,
30670
30676
  nodePath: deps.nodePath ?? process.execPath,
30671
30677
  cliPath: deps.cliPath ?? process.argv[1]
30672
30678
  });
30673
30679
  print(`Runner ${name}${deps.profile ? ` (profile ${deps.profile})` : ""} is installed and running. Logs: ${p.log}`);
30674
30680
  }
30675
- async function checkMachine(deps, env, platform, print) {
30676
- const version2 = await deps.exec("claude", ["--version"], { env });
30681
+ async function checkMachine(deps, env2, platform, print) {
30682
+ const version2 = await deps.exec("claude", ["--version"], { env: env2 });
30677
30683
  if (version2.code !== 0) throw new Error("Claude Code is not installed. Install it first: https://claude.com/claude-code");
30678
30684
  const engineVersion = version2.stdout.trim().slice(0, 100) || "unknown";
30679
30685
  if (engineTooOld(engineVersion)) throw new Error(`Claude Code 2.1.314 or newer is needed (yours: ${engineVersion}). Update it: claude update`);
30680
- const git = await deps.exec("git", ["--version"], { env });
30686
+ const git = await deps.exec("git", ["--version"], { env: env2 });
30681
30687
  const gitVersion = git.code === 0 ? /git version (\d+)\.(\d+)/.exec(git.stdout) ?? null : null;
30682
30688
  if (!gitVersion || Number(gitVersion[1]) < 2 || Number(gitVersion[1]) === 2 && Number(gitVersion[2]) < 31) {
30683
30689
  const yours = git.code === 0 ? git.stdout.trim().replace(/^git version /, "").slice(0, 60) || "unknown" : "not installed";
30684
30690
  throw new Error(`git 2.31 or newer is needed (yours: ${yours}). Update git.`);
30685
30691
  }
30686
30692
  if (platform === "linux") {
30687
- const bwrap = await deps.exec("which", ["bwrap"], { env });
30688
- const socat = await deps.exec("which", ["socat"], { env });
30693
+ const bwrap = await deps.exec("which", ["bwrap"], { env: env2 });
30694
+ const socat = await deps.exec("which", ["socat"], { env: env2 });
30689
30695
  if (bwrap.code !== 0 || socat.code !== 0) {
30690
30696
  throw new Error("The sandbox needs bubblewrap and socat. Install them (Debian/Ubuntu: sudo apt install bubblewrap socat), then run init again.");
30691
30697
  }
@@ -30694,36 +30700,36 @@ async function checkMachine(deps, env, platform, print) {
30694
30700
  }
30695
30701
  return engineVersion;
30696
30702
  }
30697
- async function warnKeychain(deps, env, platform, print) {
30703
+ async function warnKeychain(deps, env2, platform, print) {
30698
30704
  if (platform !== "darwin") return;
30699
- const git = await deps.exec("security", ["find-internet-password", "-s", "github.com"], { env, timeout: 1e4 });
30700
- const gh = await deps.exec("security", ["find-generic-password", "-s", "gh:github.com"], { env, timeout: 1e4 });
30705
+ const git = await deps.exec("security", ["find-internet-password", "-s", "github.com"], { env: env2, timeout: 1e4 });
30706
+ const gh = await deps.exec("security", ["find-generic-password", "-s", "gh:github.com"], { env: env2, timeout: 1e4 });
30701
30707
  if (git.code === 0 || gh.code === 0) print(KEYCHAIN_WARNING);
30702
30708
  }
30703
30709
  async function runUpdate(deps) {
30704
30710
  const dir = deps.dir ?? profileDir(deps.profile);
30705
30711
  const platform = deps.platform ?? process.platform;
30706
30712
  const p = paths(dir);
30707
- const env = deps.env ?? process.env;
30713
+ const env2 = deps.env ?? process.env;
30708
30714
  const print = deps.print ?? ((s) => console.log(s));
30709
30715
  const cfg = loadConfig(dir);
30710
- const engineVersion = await checkMachine(deps, env, platform, print);
30716
+ const engineVersion = await checkMachine(deps, env2, platform, print);
30711
30717
  try {
30712
30718
  await new NotiamoApi({ host: cfg.host, token: cfg.token }, deps.fetch).hello({ version: VERSION, os: platform, engine: "claude", engineVersion });
30713
30719
  } catch (e) {
30714
30720
  if (e instanceof ApiError && e.status === 401) throw new Error("The saved runner token is not accepted any more (revoked or deleted). Make a new runner in Notiamo and run init.");
30715
30721
  throw new Error(`Notiamo at ${cfg.host} did not answer: ${e instanceof Error ? e.message : String(e)}`);
30716
30722
  }
30717
- const check2 = await deps.exec("claude", ["-p", "say ok"], { env: { ...env, CLAUDE_CONFIG_DIR: p.claudeConfigDir } });
30723
+ const check2 = await deps.exec("claude", ["-p", "say ok"], { env: { ...env2, CLAUDE_CONFIG_DIR: p.claudeConfigDir } });
30718
30724
  if (check2.code !== 0) throw new Error("Claude Code is not signed in for the runner. Run: notiamo-runner init");
30719
- await warnKeychain(deps, env, platform, print);
30725
+ await warnKeychain(deps, env2, platform, print);
30720
30726
  await installService({
30721
30727
  platform,
30722
30728
  profile: deps.profile,
30723
30729
  paths: p,
30724
30730
  exec: deps.exec,
30725
30731
  home: deps.home ?? os4.homedir(),
30726
- env,
30732
+ env: env2,
30727
30733
  nodePath: deps.nodePath ?? process.execPath,
30728
30734
  cliPath: deps.cliPath ?? process.argv[1]
30729
30735
  });
@@ -30748,8 +30754,8 @@ function createLogger(file2) {
30748
30754
  }
30749
30755
 
30750
30756
  // src/loop.ts
30751
- import { mkdirSync as mkdirSync8, readFileSync as readFileSync3, renameSync as renameSync2, rmSync as rmSync6, writeFileSync as writeFileSync7 } from "node:fs";
30752
- import path12 from "node:path";
30757
+ import { mkdirSync as mkdirSync9, readFileSync as readFileSync4, renameSync as renameSync2, rmSync as rmSync6, writeFileSync as writeFileSync8 } from "node:fs";
30758
+ import path13 from "node:path";
30753
30759
  import { setTimeout as delay2 } from "node:timers/promises";
30754
30760
 
30755
30761
  // src/clones.ts
@@ -30843,8 +30849,8 @@ function removeStaleClones(projectsDir, gitDir, keepDays, busyProjectIds, now, l
30843
30849
  var errorText = (e) => e instanceof Error ? e.message : String(e);
30844
30850
 
30845
30851
  // src/run.ts
30846
- import { chmodSync as chmodSync2, mkdirSync as mkdirSync7, mkdtempSync, rmSync as rmSync5, writeFileSync as writeFileSync6 } from "node:fs";
30847
- import path11 from "node:path";
30852
+ import { chmodSync as chmodSync3, mkdirSync as mkdirSync8, mkdtempSync, rmSync as rmSync5, writeFileSync as writeFileSync7 } from "node:fs";
30853
+ import path12 from "node:path";
30848
30854
 
30849
30855
  // src/project-folder.ts
30850
30856
  import { execFile } from "node:child_process";
@@ -30865,9 +30871,9 @@ var execFileAsync = async (file2, args, opts) => {
30865
30871
  };
30866
30872
  var SAFE_GIT = ["-c", "core.hooksPath=/dev/null", "-c", "core.fsmonitor=false"];
30867
30873
  function gitEnv() {
30868
- const env = { ...process.env, GIT_TERMINAL_PROMPT: "0", GIT_CONFIG_NOSYSTEM: "1", GIT_CONFIG_GLOBAL: os5.devNull };
30869
- for (const k of Object.keys(env)) if (/^GIT_CONFIG_(COUNT|KEY_\d+|VALUE_\d+|PARAMETERS)$/.test(k) || k === "GIT_ASKPASS") delete env[k];
30870
- return env;
30874
+ const env2 = { ...process.env, GIT_TERMINAL_PROMPT: "0", GIT_CONFIG_NOSYSTEM: "1", GIT_CONFIG_GLOBAL: os5.devNull };
30875
+ for (const k of Object.keys(env2)) if (/^GIT_CONFIG_(COUNT|KEY_\d+|VALUE_\d+|PARAMETERS)$/.test(k) || k === "GIT_ASKPASS") delete env2[k];
30876
+ return env2;
30871
30877
  }
30872
30878
  function githubAuthEnv(token) {
30873
30879
  return {
@@ -30890,8 +30896,8 @@ async function prepareGithubFolder(dirs, projectId, g, token, exec = execFileAsy
30890
30896
  const folder = projectFolder(dirs.projectsDir, slot, projectId);
30891
30897
  const bare = barePath(dirs.gitDir, projectId);
30892
30898
  const saved = savedSnapshotPath(dirs.gitDir, projectId, slot);
30893
- const env = gitEnv();
30894
- const gitIn = (dir, args, timeout = GIT_TIMEOUT_MS) => exec("git", [...SAFE_GIT, "-C", dir, ...args], { env, timeout });
30899
+ const env2 = gitEnv();
30900
+ const gitIn = (dir, args, timeout = GIT_TIMEOUT_MS) => exec("git", [...SAFE_GIT, "-C", dir, ...args], { env: env2, timeout });
30895
30901
  if (existsSync4(path7.join(bare, "HEAD"))) {
30896
30902
  await gitIn(bare, ["remote", "set-url", "--", "origin", g.cloneUrl]);
30897
30903
  await exec("git", [...SAFE_GIT, "-C", bare, "fetch", "origin", "--prune", "+refs/heads/*:refs/heads/*"], { env: githubAuthEnv(await token()), timeout: CLONE_TIMEOUT_MS });
@@ -30915,7 +30921,7 @@ async function prepareGithubFolder(dirs, projectId, g, token, exec = execFileAsy
30915
30921
  await gitIn(folder, ["fetch", "origin", "--prune"]);
30916
30922
  } else {
30917
30923
  mkdirSync6(slotDir, { recursive: true, mode: 448 });
30918
- await exec("git", [...SAFE_GIT, "clone", "--no-hardlinks", "--", bare, folder], { cwd: slotDir, env, timeout: CLONE_TIMEOUT_MS });
30924
+ await exec("git", [...SAFE_GIT, "clone", "--no-hardlinks", "--", bare, folder], { cwd: slotDir, env: env2, timeout: CLONE_TIMEOUT_MS });
30919
30925
  }
30920
30926
  const { stdout } = await gitIn(folder, ["rev-parse", "--abbrev-ref", "HEAD"]);
30921
30927
  if (stdout.trim() !== g.branch) {
@@ -30947,8 +30953,8 @@ function readSavedSnapshot(file2) {
30947
30953
  }
30948
30954
  }
30949
30955
  async function pushBranch(folder, bare, branch, token, exec = execFileAsync) {
30950
- const env = gitEnv();
30951
- await exec("git", [...SAFE_GIT, "-C", bare, "fetch", folder, `+refs/heads/${branch}:refs/heads/${branch}`], { env, timeout: GIT_TIMEOUT_MS }).catch(gitError);
30956
+ const env2 = gitEnv();
30957
+ await exec("git", [...SAFE_GIT, "-C", bare, "fetch", folder, `+refs/heads/${branch}:refs/heads/${branch}`], { env: env2, timeout: GIT_TIMEOUT_MS }).catch(gitError);
30952
30958
  const auth = githubAuthEnv(await token());
30953
30959
  await exec("git", [...SAFE_GIT, "-C", bare, "push", "--no-verify", "origin", branch], { env: auth, timeout: GIT_TIMEOUT_MS }).catch(gitError);
30954
30960
  }
@@ -31041,6 +31047,110 @@ function exists(p) {
31041
31047
  }
31042
31048
  }
31043
31049
 
31050
+ // src/project-env.ts
31051
+ import { chmodSync as chmodSync2, existsSync as existsSync5, mkdirSync as mkdirSync7, readFileSync as readFileSync3, writeFileSync as writeFileSync6 } from "node:fs";
31052
+ import path8 from "node:path";
31053
+ var PROTECTED_KEYS = /* @__PURE__ */ new Set([
31054
+ "PATH",
31055
+ "HOME",
31056
+ "USER",
31057
+ "LOGNAME",
31058
+ "SHELL",
31059
+ "TMPDIR",
31060
+ "TERM",
31061
+ "LANG",
31062
+ "TZ",
31063
+ "CLAUDE_CONFIG_DIR",
31064
+ "HTTP_PROXY",
31065
+ "HTTPS_PROXY",
31066
+ "NO_PROXY",
31067
+ "NODE_EXTRA_CA_CERTS",
31068
+ "SSL_CERT_FILE",
31069
+ "SSL_CERT_DIR",
31070
+ "NODE_OPTIONS",
31071
+ "NODE_TLS_REJECT_UNAUTHORIZED",
31072
+ "PATHEXT",
31073
+ "SYSTEMROOT",
31074
+ "SYSTEMDRIVE",
31075
+ "WINDIR",
31076
+ "COMSPEC",
31077
+ "USERPROFILE",
31078
+ "USERNAME",
31079
+ "HOMEDRIVE",
31080
+ "HOMEPATH",
31081
+ "APPDATA",
31082
+ "LOCALAPPDATA",
31083
+ "PROGRAMDATA",
31084
+ "PROGRAMFILES",
31085
+ "PROGRAMFILES(X86)",
31086
+ "TEMP",
31087
+ "TMP"
31088
+ ]);
31089
+ var PROTECTED_PREFIXES = ["NOTIAMO_", "GIT_", "CLAUDE_", "ANTHROPIC_", "LC_", "XDG_"];
31090
+ var KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
31091
+ var PROJECT_ID_RE = /^[\w-]+$/;
31092
+ var isProtectedKey = (key) => PROTECTED_KEYS.has(key.toUpperCase()) || PROTECTED_PREFIXES.some((p) => key.toUpperCase().startsWith(p));
31093
+ var unescape2 = (s) => s.replace(/\\([ntr\\"])/g, (_, c) => ({ n: "\n", t: " ", r: "\r", "\\": "\\", '"': '"' })[c]);
31094
+ function parseEnvFile(text) {
31095
+ const env2 = {};
31096
+ const skipped = [];
31097
+ const lines2 = text.split(/\r?\n/);
31098
+ for (let i = 0; i < lines2.length; i++) {
31099
+ const raw = lines2[i].trim();
31100
+ if (raw === "" || raw.startsWith("#")) continue;
31101
+ const line = raw.startsWith("export ") ? raw.slice(7).trimStart() : raw;
31102
+ const eq = line.indexOf("=");
31103
+ const key = eq < 0 ? "" : line.slice(0, eq).trim();
31104
+ if (eq < 0 || !KEY_RE.test(key)) {
31105
+ skipped.push({ line: i + 1, key: KEY_RE.test(key) ? key : key.split(/\s/)[0] ?? "", reason: "bad_line" });
31106
+ continue;
31107
+ }
31108
+ if (isProtectedKey(key)) {
31109
+ skipped.push({ line: i + 1, key, reason: "protected" });
31110
+ continue;
31111
+ }
31112
+ let value = line.slice(eq + 1).trim();
31113
+ if (value.length >= 2 && value.startsWith('"') && value.endsWith('"')) value = unescape2(value.slice(1, -1));
31114
+ else if (value.length >= 2 && value.startsWith("'") && value.endsWith("'")) value = value.slice(1, -1);
31115
+ env2[key] = value;
31116
+ }
31117
+ return { env: env2, skipped };
31118
+ }
31119
+ function projectEnvPath(envDir, projectId) {
31120
+ if (!PROJECT_ID_RE.test(projectId)) throw new Error(`Not a project id: ${JSON.stringify(projectId)}. It is the last part of the project page's address.`);
31121
+ return path8.join(envDir, `${projectId}.env`);
31122
+ }
31123
+ function loadProjectEnv(envDir, projectId, log) {
31124
+ const file2 = projectEnvPath(envDir, projectId);
31125
+ if (!existsSync5(file2)) return null;
31126
+ const { env: env2, skipped } = parseEnvFile(readFileSync3(file2, "utf8"));
31127
+ for (const s of skipped) {
31128
+ log.warn(s.reason === "protected" ? `env file ${file2}: line ${s.line} sets ${s.key}, a protected variable: skipped` : `env file ${file2}: line ${s.line} is not KEY=VALUE: skipped`);
31129
+ }
31130
+ return { env: env2, names: Object.keys(env2).sort() };
31131
+ }
31132
+ var HEADER = `# Environment for the runs of this project on this machine (notiamo-runner).
31133
+ # One KEY=VALUE per line. Dev and test values only: the agent can read every variable. Never production keys.
31134
+ # With this file present, the run's shell may reach services on 127.0.0.1 (your Postgres, MinIO, Mailpit...) on macOS.
31135
+ # PATH, HOME, proxy and certificate variables, NODE_OPTIONS, NOTIAMO_*, GIT_*, CLAUDE_* and ANTHROPIC_* are ignored here.
31136
+ `;
31137
+ function ensureProjectEnv(envDir, projectId) {
31138
+ const file2 = projectEnvPath(envDir, projectId);
31139
+ mkdirSync7(envDir, { recursive: true, mode: 448 });
31140
+ try {
31141
+ chmodSync2(envDir, 448);
31142
+ } catch {
31143
+ }
31144
+ if (!existsSync5(file2)) {
31145
+ writeFileSync6(file2, HEADER, { mode: 384 });
31146
+ try {
31147
+ chmodSync2(file2, 384);
31148
+ } catch {
31149
+ }
31150
+ }
31151
+ return file2;
31152
+ }
31153
+
31044
31154
  // src/scrub.ts
31045
31155
  function scrub(line, secrets) {
31046
31156
  const forms = /* @__PURE__ */ new Set();
@@ -31110,12 +31220,12 @@ function resolveRoute(siteUrl, route) {
31110
31220
  return { error: "route is not a valid URL path" };
31111
31221
  }
31112
31222
  if (url2.origin !== site.origin || !url2.pathname.startsWith(prefix + "/wp/v2/")) return { error: "route must stay under /wp/v2/" };
31113
- const path13 = url2.pathname.slice(prefix.length);
31114
- return { path: path13, route: path13 + url2.search, query: url2.searchParams };
31223
+ const path14 = url2.pathname.slice(prefix.length);
31224
+ return { path: path14, route: path14 + url2.search, query: url2.searchParams };
31115
31225
  }
31116
31226
 
31117
31227
  // src/wp/backup.ts
31118
- import path8 from "node:path";
31228
+ import path9 from "node:path";
31119
31229
 
31120
31230
  // src/wp/transport.ts
31121
31231
  var shellQuote = (a) => /^[A-Za-z0-9_\-.,/:=@%+]+$/.test(a) ? a : `'${a.replace(/'/g, `'\\''`)}'`;
@@ -31134,7 +31244,7 @@ async function backupBefore(t, root) {
31134
31244
  const wp = await dump(`{ wp db export - --path=${shellQuote(root)} || echo ${FAILED} >&2; } | gzip`);
31135
31245
  if (wp === "overflow") throw new Error("backup_failed: the database dump is over 200 MB");
31136
31246
  if (wp) return { dump: wp, how: "wp-cli" };
31137
- const config2 = await t.getFile(path8.posix.join(root, "wp-config.php")).catch(() => null);
31247
+ const config2 = await t.getFile(path9.posix.join(root, "wp-config.php")).catch(() => null);
31138
31248
  const db = config2 ? dbCredentials(config2) : null;
31139
31249
  if (!db) throw new Error("backup_failed: no wp-cli export and no database credentials in wp-config.php");
31140
31250
  const [host, port] = splitHost(db.host);
@@ -31266,7 +31376,7 @@ async function ftpTransport(conn) {
31266
31376
  // src/wp/helper.ts
31267
31377
  import { randomBytes, timingSafeEqual } from "node:crypto";
31268
31378
  import http from "node:http";
31269
- import path9 from "node:path";
31379
+ import path10 from "node:path";
31270
31380
 
31271
31381
  // ../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v3/helpers/util.js
31272
31382
  var util;
@@ -31642,8 +31752,8 @@ function getErrorMap() {
31642
31752
 
31643
31753
  // ../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v3/helpers/parseUtil.js
31644
31754
  var makeIssue = (params) => {
31645
- const { data, path: path13, errorMaps, issueData } = params;
31646
- const fullPath = [...path13, ...issueData.path || []];
31755
+ const { data, path: path14, errorMaps, issueData } = params;
31756
+ const fullPath = [...path14, ...issueData.path || []];
31647
31757
  const fullIssue = {
31648
31758
  ...issueData,
31649
31759
  path: fullPath
@@ -31758,11 +31868,11 @@ var errorUtil;
31758
31868
 
31759
31869
  // ../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v3/types.js
31760
31870
  var ParseInputLazyPath = class {
31761
- constructor(parent, value, path13, key) {
31871
+ constructor(parent, value, path14, key) {
31762
31872
  this._cachedPath = [];
31763
31873
  this.parent = parent;
31764
31874
  this.data = value;
31765
- this._path = path13;
31875
+ this._path = path14;
31766
31876
  this._key = key;
31767
31877
  }
31768
31878
  get path() {
@@ -35717,10 +35827,10 @@ function mergeDefs(...defs) {
35717
35827
  function cloneDef(schema) {
35718
35828
  return mergeDefs(schema._zod.def);
35719
35829
  }
35720
- function getElementAtPath(obj, path13) {
35721
- if (!path13)
35830
+ function getElementAtPath(obj, path14) {
35831
+ if (!path14)
35722
35832
  return obj;
35723
- return path13.reduce((acc, key) => acc?.[key], obj);
35833
+ return path14.reduce((acc, key) => acc?.[key], obj);
35724
35834
  }
35725
35835
  function promiseAllObject(promisesObj) {
35726
35836
  const keys = Object.keys(promisesObj);
@@ -36060,11 +36170,11 @@ function explicitlyAborted(x, startIndex = 0) {
36060
36170
  }
36061
36171
  return false;
36062
36172
  }
36063
- function prefixIssues(path13, issues) {
36173
+ function prefixIssues(path14, issues) {
36064
36174
  return issues.map((iss) => {
36065
36175
  var _a3;
36066
36176
  (_a3 = iss).path ?? (_a3.path = []);
36067
- iss.path.unshift(path13);
36177
+ iss.path.unshift(path14);
36068
36178
  return iss;
36069
36179
  });
36070
36180
  }
@@ -36526,16 +36636,16 @@ function flattenError(error62, mapper = (issue2) => issue2.message) {
36526
36636
  }
36527
36637
  function formatError(error62, mapper = (issue2) => issue2.message) {
36528
36638
  const fieldErrors = { _errors: [] };
36529
- const processError = (error63, path13 = []) => {
36639
+ const processError = (error63, path14 = []) => {
36530
36640
  for (const issue2 of error63.issues) {
36531
36641
  if (issue2.code === "invalid_union" && issue2.errors.length) {
36532
- issue2.errors.map((issues) => processError({ issues }, [...path13, ...issue2.path]));
36642
+ issue2.errors.map((issues) => processError({ issues }, [...path14, ...issue2.path]));
36533
36643
  } else if (issue2.code === "invalid_key") {
36534
- processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
36644
+ processError({ issues: issue2.issues }, [...path14, ...issue2.path]);
36535
36645
  } else if (issue2.code === "invalid_element") {
36536
- processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
36646
+ processError({ issues: issue2.issues }, [...path14, ...issue2.path]);
36537
36647
  } else {
36538
- const fullpath = [...path13, ...issue2.path];
36648
+ const fullpath = [...path14, ...issue2.path];
36539
36649
  if (fullpath.length === 0) {
36540
36650
  fieldErrors._errors.push(mapper(issue2));
36541
36651
  } else {
@@ -36574,17 +36684,17 @@ function formatError(error62, mapper = (issue2) => issue2.message) {
36574
36684
  }
36575
36685
  function treeifyError(error62, mapper = (issue2) => issue2.message) {
36576
36686
  const result = { errors: [] };
36577
- const processError = (error63, path13 = []) => {
36687
+ const processError = (error63, path14 = []) => {
36578
36688
  var _a3;
36579
36689
  for (const issue2 of error63.issues) {
36580
36690
  if (issue2.code === "invalid_union" && issue2.errors.length) {
36581
- issue2.errors.map((issues) => processError({ issues }, [...path13, ...issue2.path]));
36691
+ issue2.errors.map((issues) => processError({ issues }, [...path14, ...issue2.path]));
36582
36692
  } else if (issue2.code === "invalid_key") {
36583
- processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
36693
+ processError({ issues: issue2.issues }, [...path14, ...issue2.path]);
36584
36694
  } else if (issue2.code === "invalid_element") {
36585
- processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
36695
+ processError({ issues: issue2.issues }, [...path14, ...issue2.path]);
36586
36696
  } else {
36587
- const fullpath = [...path13, ...issue2.path];
36697
+ const fullpath = [...path14, ...issue2.path];
36588
36698
  if (fullpath.length === 0) {
36589
36699
  result.errors.push(mapper(issue2));
36590
36700
  continue;
@@ -36623,8 +36733,8 @@ function treeifyError(error62, mapper = (issue2) => issue2.message) {
36623
36733
  }
36624
36734
  function toDotPath(_path) {
36625
36735
  const segs = [];
36626
- const path13 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
36627
- for (const seg of path13) {
36736
+ const path14 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
36737
+ for (const seg of path14) {
36628
36738
  if (typeof seg === "number")
36629
36739
  segs.push(`[${seg}]`);
36630
36740
  else if (typeof seg === "symbol")
@@ -52175,11 +52285,11 @@ function normalizeObjectSchema(schema) {
52175
52285
  }
52176
52286
  return void 0;
52177
52287
  }
52178
- function getDotPath(path13) {
52179
- if (path13.length === 0) {
52288
+ function getDotPath(path14) {
52289
+ if (path14.length === 0) {
52180
52290
  return "object root";
52181
52291
  }
52182
- return path13.reduce((acc, seg, index) => {
52292
+ return path14.reduce((acc, seg, index) => {
52183
52293
  if (index === 0) {
52184
52294
  return String(seg);
52185
52295
  }
@@ -54406,13 +54516,13 @@ function resolveRef(ref, ctx) {
54406
54516
  if (!ref.startsWith("#")) {
54407
54517
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
54408
54518
  }
54409
- const path13 = ref.slice(1).split("/").filter(Boolean);
54410
- if (path13.length === 0) {
54519
+ const path14 = ref.slice(1).split("/").filter(Boolean);
54520
+ if (path14.length === 0) {
54411
54521
  return ctx.rootSchema;
54412
54522
  }
54413
54523
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
54414
- if (path13[0] === defsKey) {
54415
- const key = path13[1] === void 0 ? void 0 : decodeJSONPointerSegment(path13[1]);
54524
+ if (path14[0] === defsKey) {
54525
+ const key = path14[1] === void 0 ? void 0 : decodeJSONPointerSegment(path14[1]);
54416
54526
  if (!key || !ctx.defs[key]) {
54417
54527
  throw new Error(`Reference not found: ${ref}`);
54418
54528
  }
@@ -61678,15 +61788,15 @@ var CONNECTION_SYMBOL_KEY = /* @__PURE__ */ Symbol("CONNECTION_SYMBOL_KEY");
61678
61788
  var WAIT_FOR_WEBSOCKET_SYMBOL = /* @__PURE__ */ Symbol("WAIT_FOR_WEBSOCKET_SYMBOL");
61679
61789
  var upgradeWebSocket = defineWebSocketHelper(async (c, events, options) => {
61680
61790
  if (c.req.header("upgrade")?.toLowerCase() !== "websocket") return;
61681
- const env = c.env;
61682
- const waitForWebSocket = env[WAIT_FOR_WEBSOCKET_SYMBOL];
61683
- if (!waitForWebSocket || !env.incoming) return new Response(null, { status: 500 });
61791
+ const env2 = c.env;
61792
+ const waitForWebSocket = env2[WAIT_FOR_WEBSOCKET_SYMBOL];
61793
+ if (!waitForWebSocket || !env2.incoming) return new Response(null, { status: 500 });
61684
61794
  const connectionSymbol = generateConnectionSymbol();
61685
- env[CONNECTION_SYMBOL_KEY] = connectionSymbol;
61795
+ env2[CONNECTION_SYMBOL_KEY] = connectionSymbol;
61686
61796
  (async () => {
61687
61797
  let ws;
61688
61798
  try {
61689
- ws = await waitForWebSocket(env.incoming, connectionSymbol);
61799
+ ws = await waitForWebSocket(env2.incoming, connectionSymbol);
61690
61800
  } catch {
61691
61801
  return;
61692
61802
  }
@@ -62860,7 +62970,7 @@ function buildServer(t) {
62860
62970
  if (!t.allow.files && !t.allow.all) return fail("the files group is off for this project");
62861
62971
  if (t.root === null) return fail("wordpress_root_not_found: the WordPress folder was not found on the server");
62862
62972
  const bad = pathRefusal(p, t.allow.all);
62863
- return bad ? fail(bad) : path9.posix.join(t.root, p);
62973
+ return bad ? fail(bad) : path10.posix.join(t.root, p);
62864
62974
  };
62865
62975
  server.registerTool("wp_get_file", {
62866
62976
  description: "Reads a file of the WordPress site, by its path relative to the WordPress folder (e.g. wp-content/themes/x/style.css).",
@@ -62932,9 +63042,9 @@ function apiRefusal(route, query, method, body, allow) {
62932
63042
  }
62933
63043
  function pathRefusal(p, all) {
62934
63044
  if (p.startsWith("/") || p.includes("\\") || p.includes("\0")) return "path must be relative to the WordPress folder";
62935
- const norm = path9.posix.normalize(p);
63045
+ const norm = path10.posix.normalize(p);
62936
63046
  if (norm === ".." || norm.startsWith("../") || p.split("/").includes("..")) return "path must stay inside the WordPress folder";
62937
- if (!all && PROTECTED_FILES.has(path9.posix.basename(norm))) return `refused: ${path9.posix.basename(norm)} is never changed unless "Allow everything" is on`;
63047
+ if (!all && PROTECTED_FILES.has(path10.posix.basename(norm))) return `refused: ${path10.posix.basename(norm)} is never changed unless "Allow everything" is on`;
62938
63048
  return null;
62939
63049
  }
62940
63050
  function publishedLink(json3) {
@@ -62946,7 +63056,7 @@ var cut2 = (s) => s.length > MAX_OUTPUT ? `${s.slice(0, MAX_OUTPUT)}
62946
63056
  [cut at ${MAX_OUTPUT} characters]` : s;
62947
63057
 
62948
63058
  // src/wp/root.ts
62949
- import path10 from "node:path";
63059
+ import path11 from "node:path";
62950
63060
  var FTP_CANDIDATES = [".", "public_html", "www", "htdocs", "httpdocs", "html", "web"];
62951
63061
  async function findRoot(t) {
62952
63062
  if (t.run) {
@@ -62954,10 +63064,10 @@ async function findRoot(t) {
62954
63064
  if (home?.code === 0) return ".";
62955
63065
  const found = await t.run(["find", ".", "-maxdepth", "3", "-name", "wp-config.php"]).catch(() => null);
62956
63066
  const first = found?.stdout.toString("utf8").split("\n").map((l) => l.trim()).filter(Boolean).sort((a, b) => a.split("/").length - b.split("/").length)[0];
62957
- return first ? path10.posix.normalize(path10.posix.dirname(first)) : null;
63067
+ return first ? path11.posix.normalize(path11.posix.dirname(first)) : null;
62958
63068
  }
62959
63069
  for (const dir of FTP_CANDIDATES) {
62960
- if (await t.getFile(path10.posix.join(dir, "wp-config.php")).catch(() => null) !== null) return dir;
63070
+ if (await t.getFile(path11.posix.join(dir, "wp-config.php")).catch(() => null) !== null) return dir;
62961
63071
  }
62962
63072
  return null;
62963
63073
  }
@@ -63090,17 +63200,23 @@ async function runOne(spec, deps) {
63090
63200
  } else {
63091
63201
  started = true;
63092
63202
  const parent = projectFolder(deps.paths.projectsDir, slot, spec.projectId);
63093
- mkdirSync7(parent, { recursive: true, mode: 448 });
63094
- cwd = tempDir = mkdtempSync(path11.join(parent, "run-"));
63203
+ mkdirSync8(parent, { recursive: true, mode: 448 });
63204
+ cwd = tempDir = mkdtempSync(path12.join(parent, "run-"));
63095
63205
  if (deps.helperFactory) helper = await deps.helperFactory(spec);
63096
63206
  }
63097
- settingsFile = writeSettings(spec, deps, cwd);
63207
+ const projectEnv = loadProjectEnv(deps.paths.envDir, spec.projectId, log);
63208
+ settingsFile = writeSettings(spec, deps, cwd, projectEnv !== null);
63209
+ if (projectEnv) {
63210
+ secrets.push(...Object.values(projectEnv.env));
63211
+ log.info(`run ${spec.runId}: env file with ${projectEnv.names.length} variable(s)`);
63212
+ }
63098
63213
  const base = {
63214
+ // 127.0.0.1 is the machine's only on macOS: Linux's sandbox gives the shell its own network namespace.
63099
63215
  cwd,
63100
- systemPrompt: spec.systemPrompt,
63216
+ systemPrompt: projectEnv ? withEnvNote(spec.systemPrompt, projectEnv.names, deps.sandbox.platform === "darwin") : spec.systemPrompt,
63101
63217
  mcp: { url: spec.mcp.url, token: spec.mcp.accessToken },
63102
63218
  helper: helper ? { url: helper.url, token: helper.token } : void 0,
63103
- env: {},
63219
+ env: projectEnv?.env ?? {},
63104
63220
  maxMinutes: spec.maxRunMinutes,
63105
63221
  claudeConfigDir: deps.paths.claudeConfigDir,
63106
63222
  settingsFile
@@ -63224,7 +63340,14 @@ function githubToken(runId, g, api, secrets, now) {
63224
63340
  return token;
63225
63341
  };
63226
63342
  }
63227
- function writeSettings(spec, deps, cwd) {
63343
+ function withEnvNote(systemPrompt, names, localServices) {
63344
+ const list = names.length > 0 ? `these environment variables for the project: ${names.join(", ")}` : "an environment file for the project (empty)";
63345
+ const local = localServices ? " Services they point to run on 127.0.0.1 and are reachable from your shell." : "";
63346
+ return `${systemPrompt}
63347
+
63348
+ This machine sets ${list}.${local} Use them for tests; do not print their values.`;
63349
+ }
63350
+ function writeSettings(spec, deps, cwd, localServices) {
63228
63351
  const { sandbox } = deps;
63229
63352
  let wordpressHost;
63230
63353
  if (spec.wordpress) {
@@ -63234,8 +63357,8 @@ function writeSettings(spec, deps, cwd) {
63234
63357
  }
63235
63358
  }
63236
63359
  if (!/^[\w-]+$/.test(spec.runId)) throw new Error("bad run id");
63237
- const dir = path11.resolve(deps.paths.runsDir);
63238
- mkdirSync7(dir, { recursive: true, mode: 448 });
63360
+ const dir = path12.resolve(deps.paths.runsDir);
63361
+ mkdirSync8(dir, { recursive: true, mode: 448 });
63239
63362
  const settings = sandboxSettings({
63240
63363
  platform: sandbox.platform,
63241
63364
  runnerRoot: sandbox.runnerRoot,
@@ -63244,13 +63367,14 @@ function writeSettings(spec, deps, cwd) {
63244
63367
  notiamoHost: sandbox.notiamoHost,
63245
63368
  extraDomains: sandbox.allowedDomains(),
63246
63369
  wordpressHost,
63370
+ localServices,
63247
63371
  gitExecPath: sandbox.gitExecPath,
63248
63372
  ghPath: sandbox.ghPath
63249
63373
  });
63250
- const file2 = path11.join(dir, `${spec.runId}.json`);
63251
- writeFileSync6(file2, JSON.stringify(settings, null, 2) + "\n", { mode: 384 });
63374
+ const file2 = path12.join(dir, `${spec.runId}.json`);
63375
+ writeFileSync7(file2, JSON.stringify(settings, null, 2) + "\n", { mode: 384 });
63252
63376
  try {
63253
- chmodSync2(file2, 384);
63377
+ chmodSync3(file2, 384);
63254
63378
  } catch {
63255
63379
  }
63256
63380
  return file2;
@@ -63411,7 +63535,7 @@ async function startLoop(deps) {
63411
63535
  const running = /* @__PURE__ */ new Map();
63412
63536
  for (let i = 0; i < SLOT_FOLDERS; i++) {
63413
63537
  try {
63414
- mkdirSync8(path12.join(deps.paths.projectsDir, String(i)), { recursive: true, mode: 448 });
63538
+ mkdirSync9(path13.join(deps.paths.projectsDir, String(i)), { recursive: true, mode: 448 });
63415
63539
  } catch (e) {
63416
63540
  log.warn(`slot folder ${i} not made: ${errorText3(e)}`);
63417
63541
  }
@@ -63511,7 +63635,7 @@ async function startLoop(deps) {
63511
63635
  var errorText3 = (e) => e instanceof Error ? e.message : String(e);
63512
63636
  function readState(file2) {
63513
63637
  try {
63514
- const s = JSON.parse(readFileSync3(file2, "utf8"));
63638
+ const s = JSON.parse(readFileSync4(file2, "utf8"));
63515
63639
  if (Array.isArray(s.busyRunIds)) return s.busyRunIds.filter((x) => typeof x === "string");
63516
63640
  return typeof s.busyRunId === "string" ? [s.busyRunId] : [];
63517
63641
  } catch {
@@ -63523,9 +63647,9 @@ function writeState(file2, busyRunIds) {
63523
63647
  rmSync6(file2, { force: true });
63524
63648
  return;
63525
63649
  }
63526
- mkdirSync8(path12.dirname(file2), { recursive: true, mode: 448 });
63650
+ mkdirSync9(path13.dirname(file2), { recursive: true, mode: 448 });
63527
63651
  const tmp = `${file2}.tmp`;
63528
- writeFileSync7(tmp, JSON.stringify({ busyRunIds }) + "\n", { mode: 384 });
63652
+ writeFileSync8(tmp, JSON.stringify({ busyRunIds }) + "\n", { mode: 384 });
63529
63653
  renameSync2(tmp, file2);
63530
63654
  }
63531
63655
 
@@ -63631,6 +63755,13 @@ async function uninstall4({ profile } = {}) {
63631
63755
  await uninstallService(serviceOptions(profile));
63632
63756
  console.log(`The runner service is removed. Its folder ${profileDir(profile)} (config, sign-in, projects) stays; delete it to remove everything.`);
63633
63757
  }
63758
+ async function env({ profile, projectId }) {
63759
+ const file2 = ensureProjectEnv(paths(profileDir(profile)).envDir, projectId);
63760
+ console.log(`Env file for project ${projectId}${profile ? ` (profile ${profile})` : ""}: ${file2}`);
63761
+ console.log("One KEY=VALUE per line. Dev and test values only: the agent can read every variable, never production keys.");
63762
+ console.log("With this file present, the runs of this project may reach services on 127.0.0.1 (Postgres, MinIO, Mailpit...) on macOS; on Linux the sandbox keeps 127.0.0.1 apart, use the machine's LAN address.");
63763
+ console.log("The next run of the project reads it; the runner needs no restart. Remove the file to take the variables away.");
63764
+ }
63634
63765
  async function status4({ profile } = {}) {
63635
63766
  const st = await serviceStatus(serviceOptions(profile));
63636
63767
  let cfg = null;
@@ -63659,7 +63790,7 @@ function hostOf(url2) {
63659
63790
  function tail(file2, n) {
63660
63791
  let text;
63661
63792
  try {
63662
- text = readFileSync4(file2, "utf8");
63793
+ text = readFileSync5(file2, "utf8");
63663
63794
  } catch {
63664
63795
  return [];
63665
63796
  }
@@ -63678,12 +63809,13 @@ Usage: notiamo-runner <command> [--profile <name>]
63678
63809
  status Whether the service is installed and running, and the last log line
63679
63810
  logs The last 50 lines of the log
63680
63811
  uninstall Remove the service (the runner's folder stays)
63812
+ env <projectId> Make or show the env file this machine gives the runs of one project (dev/test values)
63681
63813
  --version Print the version
63682
63814
 
63683
63815
  --profile <name> A second runner on this machine (say "staging"): its own folder, sign-in and service.
63684
63816
  Give it to every command of that runner.`;
63685
63817
  async function main(argv) {
63686
- const { cmd, profile, error: error62 } = parseArgs(argv);
63818
+ const { cmd, arg, profile, error: error62 } = parseArgs(argv);
63687
63819
  if (error62) {
63688
63820
  console.error(`${error62}
63689
63821
 
@@ -63692,6 +63824,13 @@ ${HELP}`);
63692
63824
  return;
63693
63825
  }
63694
63826
  const o = { profile };
63827
+ if (cmd === "env" && !arg) {
63828
+ console.error(`env needs the project id: the last part of the project page's address.
63829
+
63830
+ ${HELP}`);
63831
+ process.exitCode = 1;
63832
+ return;
63833
+ }
63695
63834
  switch (cmd) {
63696
63835
  case "init":
63697
63836
  return init(o);
@@ -63707,6 +63846,8 @@ ${HELP}`);
63707
63846
  return logs(o);
63708
63847
  case "uninstall":
63709
63848
  return uninstall4(o);
63849
+ case "env":
63850
+ return env({ ...o, projectId: arg });
63710
63851
  case "--version":
63711
63852
  case "-v":
63712
63853
  console.log(`notiamo-runner ${VERSION}`);