theforge-cli 0.2.2 → 0.2.3

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/CHANGELOG.md +11 -0
  2. package/dist/index.js +482 -414
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -95,7 +95,7 @@ var require_windows = __commonJS({
95
95
  module.exports = isexe;
96
96
  isexe.sync = sync;
97
97
  var fs2 = __require("fs");
98
- function checkPathExt(path52, options) {
98
+ function checkPathExt(path53, options) {
99
99
  var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
100
100
  if (!pathext) {
101
101
  return true;
@@ -106,25 +106,25 @@ var require_windows = __commonJS({
106
106
  }
107
107
  for (var i3 = 0; i3 < pathext.length; i3++) {
108
108
  var p = pathext[i3].toLowerCase();
109
- if (p && path52.substr(-p.length).toLowerCase() === p) {
109
+ if (p && path53.substr(-p.length).toLowerCase() === p) {
110
110
  return true;
111
111
  }
112
112
  }
113
113
  return false;
114
114
  }
115
- function checkStat(stat, path52, options) {
115
+ function checkStat(stat, path53, options) {
116
116
  if (!stat.isSymbolicLink() && !stat.isFile()) {
117
117
  return false;
118
118
  }
119
- return checkPathExt(path52, options);
119
+ return checkPathExt(path53, options);
120
120
  }
121
- function isexe(path52, options, cb) {
122
- fs2.stat(path52, function(er, stat) {
123
- cb(er, er ? false : checkStat(stat, path52, options));
121
+ function isexe(path53, options, cb) {
122
+ fs2.stat(path53, function(er, stat) {
123
+ cb(er, er ? false : checkStat(stat, path53, options));
124
124
  });
125
125
  }
126
- function sync(path52, options) {
127
- return checkStat(fs2.statSync(path52), path52, options);
126
+ function sync(path53, options) {
127
+ return checkStat(fs2.statSync(path53), path53, options);
128
128
  }
129
129
  }
130
130
  });
@@ -136,13 +136,13 @@ var require_mode = __commonJS({
136
136
  module.exports = isexe;
137
137
  isexe.sync = sync;
138
138
  var fs2 = __require("fs");
139
- function isexe(path52, options, cb) {
140
- fs2.stat(path52, function(er, stat) {
139
+ function isexe(path53, options, cb) {
140
+ fs2.stat(path53, function(er, stat) {
141
141
  cb(er, er ? false : checkStat(stat, options));
142
142
  });
143
143
  }
144
- function sync(path52, options) {
145
- return checkStat(fs2.statSync(path52), options);
144
+ function sync(path53, options) {
145
+ return checkStat(fs2.statSync(path53), options);
146
146
  }
147
147
  function checkStat(stat, options) {
148
148
  return stat.isFile() && checkMode(stat, options);
@@ -176,7 +176,7 @@ var require_isexe = __commonJS({
176
176
  }
177
177
  module.exports = isexe;
178
178
  isexe.sync = sync;
179
- function isexe(path52, options, cb) {
179
+ function isexe(path53, options, cb) {
180
180
  if (typeof options === "function") {
181
181
  cb = options;
182
182
  options = {};
@@ -186,7 +186,7 @@ var require_isexe = __commonJS({
186
186
  throw new TypeError("callback not provided");
187
187
  }
188
188
  return new Promise(function(resolve, reject) {
189
- isexe(path52, options || {}, function(er, is) {
189
+ isexe(path53, options || {}, function(er, is) {
190
190
  if (er) {
191
191
  reject(er);
192
192
  } else {
@@ -195,7 +195,7 @@ var require_isexe = __commonJS({
195
195
  });
196
196
  });
197
197
  }
198
- core(path52, options || {}, function(er, is) {
198
+ core(path53, options || {}, function(er, is) {
199
199
  if (er) {
200
200
  if (er.code === "EACCES" || options && options.ignoreErrors) {
201
201
  er = null;
@@ -205,9 +205,9 @@ var require_isexe = __commonJS({
205
205
  cb(er, is);
206
206
  });
207
207
  }
208
- function sync(path52, options) {
208
+ function sync(path53, options) {
209
209
  try {
210
- return core.sync(path52, options || {});
210
+ return core.sync(path53, options || {});
211
211
  } catch (er) {
212
212
  if (options && options.ignoreErrors || er.code === "EACCES") {
213
213
  return false;
@@ -224,7 +224,7 @@ var require_which = __commonJS({
224
224
  "node_modules/which/which.js"(exports, module) {
225
225
  "use strict";
226
226
  var isWindows = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
227
- var path52 = __require("path");
227
+ var path53 = __require("path");
228
228
  var COLON = isWindows ? ";" : ":";
229
229
  var isexe = require_isexe();
230
230
  var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
@@ -262,7 +262,7 @@ var require_which = __commonJS({
262
262
  return opt.all && found.length ? resolve(found) : reject(getNotFoundError(cmd));
263
263
  const ppRaw = pathEnv[i3];
264
264
  const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
265
- const pCmd = path52.join(pathPart, cmd);
265
+ const pCmd = path53.join(pathPart, cmd);
266
266
  const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
267
267
  resolve(subStep(p, i3, 0));
268
268
  });
@@ -289,7 +289,7 @@ var require_which = __commonJS({
289
289
  for (let i3 = 0; i3 < pathEnv.length; i3++) {
290
290
  const ppRaw = pathEnv[i3];
291
291
  const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
292
- const pCmd = path52.join(pathPart, cmd);
292
+ const pCmd = path53.join(pathPart, cmd);
293
293
  const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
294
294
  for (let j = 0; j < pathExt.length; j++) {
295
295
  const cur = p + pathExt[j];
@@ -337,7 +337,7 @@ var require_path_key = __commonJS({
337
337
  var require_resolveCommand = __commonJS({
338
338
  "node_modules/cross-spawn/lib/util/resolveCommand.js"(exports, module) {
339
339
  "use strict";
340
- var path52 = __require("path");
340
+ var path53 = __require("path");
341
341
  var which = require_which();
342
342
  var getPathKey = require_path_key();
343
343
  function resolveCommandAttempt(parsed, withoutPathExt) {
@@ -355,7 +355,7 @@ var require_resolveCommand = __commonJS({
355
355
  try {
356
356
  resolved = which.sync(parsed.command, {
357
357
  path: env[getPathKey({ env })],
358
- pathExt: withoutPathExt ? path52.delimiter : void 0
358
+ pathExt: withoutPathExt ? path53.delimiter : void 0
359
359
  });
360
360
  } catch (e) {
361
361
  } finally {
@@ -364,7 +364,7 @@ var require_resolveCommand = __commonJS({
364
364
  }
365
365
  }
366
366
  if (resolved) {
367
- resolved = path52.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
367
+ resolved = path53.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
368
368
  }
369
369
  return resolved;
370
370
  }
@@ -418,8 +418,8 @@ var require_shebang_command = __commonJS({
418
418
  if (!match) {
419
419
  return null;
420
420
  }
421
- const [path52, argument] = match[0].replace(/#! ?/, "").split(" ");
422
- const binary = path52.split("/").pop();
421
+ const [path53, argument] = match[0].replace(/#! ?/, "").split(" ");
422
+ const binary = path53.split("/").pop();
423
423
  if (binary === "env") {
424
424
  return argument;
425
425
  }
@@ -454,7 +454,7 @@ var require_readShebang = __commonJS({
454
454
  var require_parse = __commonJS({
455
455
  "node_modules/cross-spawn/lib/parse.js"(exports, module) {
456
456
  "use strict";
457
- var path52 = __require("path");
457
+ var path53 = __require("path");
458
458
  var resolveCommand2 = require_resolveCommand();
459
459
  var escape = require_escape();
460
460
  var readShebang = require_readShebang();
@@ -479,7 +479,7 @@ var require_parse = __commonJS({
479
479
  const needsShell = !isExecutableRegExp.test(commandFile);
480
480
  if (parsed.options.forceShell || needsShell) {
481
481
  const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
482
- parsed.command = path52.normalize(parsed.command);
482
+ parsed.command = path53.normalize(parsed.command);
483
483
  parsed.command = escape.command(parsed.command);
484
484
  parsed.args = parsed.args.map((arg) => escape.argument(arg, needsDoubleEscapeMetaChars));
485
485
  const shellCommand = [parsed.command].concat(parsed.args).join(" ");
@@ -7069,13 +7069,13 @@ var logOutputSync = ({ serializedResult, fdNumber, state, verboseInfo, encoding,
7069
7069
  }
7070
7070
  };
7071
7071
  var writeToFiles = (serializedResult, stdioItems, outputFiles) => {
7072
- for (const { path: path52, append } of stdioItems.filter(({ type }) => FILE_TYPES.has(type))) {
7073
- const pathString = typeof path52 === "string" ? path52 : path52.toString();
7072
+ for (const { path: path53, append } of stdioItems.filter(({ type }) => FILE_TYPES.has(type))) {
7073
+ const pathString = typeof path53 === "string" ? path53 : path53.toString();
7074
7074
  if (append || outputFiles.has(pathString)) {
7075
- appendFileSync2(path52, serializedResult);
7075
+ appendFileSync2(path53, serializedResult);
7076
7076
  } else {
7077
7077
  outputFiles.add(pathString);
7078
- writeFileSync2(path52, serializedResult);
7078
+ writeFileSync2(path53, serializedResult);
7079
7079
  }
7080
7080
  }
7081
7081
  };
@@ -10380,7 +10380,7 @@ function isNonInteractive(cli) {
10380
10380
  return cli.all || (cli.only?.length ?? 0) > 0 || cli.retryFailed;
10381
10381
  }
10382
10382
  var COMMAND_USAGE = {
10383
- install: "\ninstall <forjas> \u2014 git clone + setup (default) ou PyPI+venv (--method registry).\n --plan s\xF3 mostra o plano; --ref/--version fixa UMA Forja; --all/--only selecionam.",
10383
+ install: "\ninstall <forjas> \u2014 PyPI+venv (default) ou git clone + setup (--method git).\n --plan s\xF3 mostra o plano; --ref/--version fixa UMA Forja; --all/--only selecionam.",
10384
10384
  update: "\nupdate [forjas] \u2014 pull + setup. --check s\xF3 verifica; --method registry usa o receipt.\n Sem nomes no interativo: oferece as Forjas presentes; --yes exige sele\xE7\xE3o.",
10385
10385
  registry: "\nregistry [list|install|lock] \u2014 cat\xE1logo PyPI + receipts.\n registry install <f> --offline --lock <arquivo>: instala\xE7\xE3o travada (--no-index).\n registry lock <f> [--out <arq|dir>]: gera <forja>.offline-lock.json (online, pip>=23).",
10386
10386
  mcp: "\nmcp [forja\u2026] \u2014 argv MCP por Forja (clone ou venv registry).\n --verify: handshake real \u2014 n\xEDveis INSTALLED\u2192EXECUTABLE\u2192INITIALIZED\u2192\n TOOLS_DISCOVERED\u2192SAFE_TOOL_CALLED\u2192HOST_VERIFIED. tools/call s\xF3 na allowlist do cat\xE1logo.",
@@ -14528,26 +14528,26 @@ var ContractValidator = class {
14528
14528
  }
14529
14529
  return this.validate(declared, document);
14530
14530
  }
14531
- check(value, schema, path52, errs) {
14531
+ check(value, schema, path53, errs) {
14532
14532
  if (typeof schema.$ref === "string") {
14533
14533
  const target = schema.$ref;
14534
14534
  if (!target.startsWith("forge/")) {
14535
- errs.push({ code: "CONTRACT-REF", message: `external ref refused: ${target}`, path: path52 });
14535
+ errs.push({ code: "CONTRACT-REF", message: `external ref refused: ${target}`, path: path53 });
14536
14536
  return;
14537
14537
  }
14538
14538
  const resolved = this.schemas[target];
14539
14539
  if (!resolved) {
14540
- errs.push({ code: "CONTRACT-UNKNOWN", message: `unknown contract: ${target}`, path: path52 });
14540
+ errs.push({ code: "CONTRACT-UNKNOWN", message: `unknown contract: ${target}`, path: path53 });
14541
14541
  return;
14542
14542
  }
14543
- this.check(value, resolved, path52, errs);
14543
+ this.check(value, resolved, path53, errs);
14544
14544
  return;
14545
14545
  }
14546
14546
  if ("const" in schema && value !== schema.const) {
14547
14547
  errs.push({
14548
14548
  code: "CONTRACT-CONST",
14549
14549
  message: `expected ${JSON.stringify(schema.const)}`,
14550
- path: path52
14550
+ path: path53
14551
14551
  });
14552
14552
  return;
14553
14553
  }
@@ -14555,7 +14555,7 @@ var ContractValidator = class {
14555
14555
  errs.push({
14556
14556
  code: "CONTRACT-TYPE",
14557
14557
  message: `expected type ${JSON.stringify(schema.type)}`,
14558
- path: path52
14558
+ path: path53
14559
14559
  });
14560
14560
  return;
14561
14561
  }
@@ -14563,27 +14563,27 @@ var ContractValidator = class {
14563
14563
  errs.push({
14564
14564
  code: "CONTRACT-ENUM",
14565
14565
  message: `value not in ${JSON.stringify(schema.enum)}`,
14566
- path: path52
14566
+ path: path53
14567
14567
  });
14568
14568
  return;
14569
14569
  }
14570
14570
  if (typeof value === "string") {
14571
14571
  if (typeof schema.pattern === "string" && !new RegExp(schema.pattern).test(value)) {
14572
- errs.push({ code: "CONTRACT-PATTERN", message: `does not match ${schema.pattern}`, path: path52 });
14572
+ errs.push({ code: "CONTRACT-PATTERN", message: `does not match ${schema.pattern}`, path: path53 });
14573
14573
  }
14574
14574
  if (typeof schema.minLength === "number" && value.length < schema.minLength) {
14575
- errs.push({ code: "CONTRACT-LENGTH", message: "string too short", path: path52 });
14575
+ errs.push({ code: "CONTRACT-LENGTH", message: "string too short", path: path53 });
14576
14576
  }
14577
14577
  if (typeof schema.maxLength === "number" && value.length > schema.maxLength) {
14578
- errs.push({ code: "CONTRACT-LENGTH", message: "string too long", path: path52 });
14578
+ errs.push({ code: "CONTRACT-LENGTH", message: "string too long", path: path53 });
14579
14579
  }
14580
14580
  }
14581
14581
  if (typeof value === "number") {
14582
14582
  if (typeof schema.min === "number" && value < schema.min) {
14583
- errs.push({ code: "CONTRACT-RANGE", message: `< ${schema.min}`, path: path52 });
14583
+ errs.push({ code: "CONTRACT-RANGE", message: `< ${schema.min}`, path: path53 });
14584
14584
  }
14585
14585
  if (typeof schema.max === "number" && value > schema.max) {
14586
- errs.push({ code: "CONTRACT-RANGE", message: `> ${schema.max}`, path: path52 });
14586
+ errs.push({ code: "CONTRACT-RANGE", message: `> ${schema.max}`, path: path53 });
14587
14587
  }
14588
14588
  }
14589
14589
  if (typeof value === "object" && value !== null && !Array.isArray(value)) {
@@ -14593,7 +14593,7 @@ var ContractValidator = class {
14593
14593
  errs.push({
14594
14594
  code: "CONTRACT-REQUIRED",
14595
14595
  message: `missing '${req}'`,
14596
- path: `${path52}/${req}`
14596
+ path: `${path53}/${req}`
14597
14597
  });
14598
14598
  }
14599
14599
  }
@@ -14601,25 +14601,25 @@ var ContractValidator = class {
14601
14601
  const additional = schema.additionalProperties;
14602
14602
  for (const [key, val] of Object.entries(obj)) {
14603
14603
  if (key in props) {
14604
- this.check(val, props[key], `${path52}/${key}`, errs);
14604
+ this.check(val, props[key], `${path53}/${key}`, errs);
14605
14605
  } else if (additional === false) {
14606
14606
  errs.push({
14607
14607
  code: "CONTRACT-UNKNOWN-FIELD",
14608
14608
  message: `unexpected '${key}'`,
14609
- path: `${path52}/${key}`
14609
+ path: `${path53}/${key}`
14610
14610
  });
14611
14611
  } else if (typeof additional === "object" && additional !== null) {
14612
- this.check(val, additional, `${path52}/${key}`, errs);
14612
+ this.check(val, additional, `${path53}/${key}`, errs);
14613
14613
  }
14614
14614
  }
14615
14615
  }
14616
14616
  if (Array.isArray(value)) {
14617
14617
  if (typeof schema.minItems === "number" && value.length < schema.minItems) {
14618
- errs.push({ code: "CONTRACT-SIZE", message: "too few items", path: path52 });
14618
+ errs.push({ code: "CONTRACT-SIZE", message: "too few items", path: path53 });
14619
14619
  }
14620
14620
  const itemSchema = schema.items;
14621
14621
  if (typeof itemSchema === "object" && itemSchema !== null) {
14622
- value.forEach((item, i3) => this.check(item, itemSchema, `${path52}/${i3}`, errs));
14622
+ value.forEach((item, i3) => this.check(item, itemSchema, `${path53}/${i3}`, errs));
14623
14623
  }
14624
14624
  }
14625
14625
  }
@@ -15609,22 +15609,22 @@ async function uninstall(opts = {}) {
15609
15609
  }
15610
15610
 
15611
15611
  // src/cmd/query.ts
15612
- import { existsSync as existsSync14 } from "fs";
15612
+ import { existsSync as existsSync15 } from "fs";
15613
15613
 
15614
15614
  // src/registry/install.ts
15615
15615
  import { createHash as createHash2 } from "crypto";
15616
15616
  import {
15617
- chmodSync as chmodSync2,
15618
- existsSync as existsSync12,
15619
- mkdirSync as mkdirSync4,
15617
+ chmodSync as chmodSync3,
15618
+ existsSync as existsSync13,
15619
+ mkdirSync as mkdirSync5,
15620
15620
  readdirSync as readdirSync6,
15621
15621
  readFileSync as readFileSync11,
15622
15622
  renameSync as renameSync2,
15623
- rmSync as rmSync3,
15623
+ rmSync as rmSync4,
15624
15624
  statSync as statSync3,
15625
- writeFileSync as writeFileSync4
15625
+ writeFileSync as writeFileSync5
15626
15626
  } from "fs";
15627
- import path20 from "path";
15627
+ import path21 from "path";
15628
15628
 
15629
15629
  // src/registry/lock.ts
15630
15630
  import { createHash } from "crypto";
@@ -15919,9 +15919,58 @@ async function lockTransitiveCheck(lock, wheels, run, pythonExe) {
15919
15919
  return null;
15920
15920
  }
15921
15921
 
15922
- // src/registry/pypi.ts
15923
- import { mkdirSync as mkdirSync3, readFileSync as readFileSync10 } from "fs";
15922
+ // src/registry/shims.ts
15923
+ import { chmodSync as chmodSync2, existsSync as existsSync12, mkdirSync as mkdirSync3, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "fs";
15924
15924
  import path19 from "path";
15925
+ function shimsDir(home) {
15926
+ return path19.join(home, ".forge-cli", "bin");
15927
+ }
15928
+ function shimName(bin, platform2) {
15929
+ const base = path19.basename(bin).replace(/\.(exe|cmd|bat)$/i, "");
15930
+ return platform2 === "win32" ? `${base}.cmd` : base;
15931
+ }
15932
+ function shQuote(bin) {
15933
+ if (bin.includes("\n") || bin.includes("\r")) {
15934
+ throw new Error(`bin com newline n\xE3o pode virar shim: ${JSON.stringify(bin)}`);
15935
+ }
15936
+ return bin.replace(/(["\\$`])/g, "\\$1");
15937
+ }
15938
+ function emitForgeShim(home, bin, platform2) {
15939
+ const dir = shimsDir(home);
15940
+ const target = resolveInside(dir, shimName(bin, platform2));
15941
+ if (!target || !isSafeRepoName(path19.basename(target).replace(/\.cmd$/i, ""))) {
15942
+ throw new Error(`nome de shim inseguro: ${path19.basename(bin)}`);
15943
+ }
15944
+ mkdirSync3(dir, { recursive: true });
15945
+ if (platform2 === "win32") {
15946
+ if (bin.includes('"') || bin.includes("\n") || bin.includes("\r")) {
15947
+ throw new Error(`bin n\xE3o express\xE1vel em .cmd: ${JSON.stringify(bin)}`);
15948
+ }
15949
+ writeFileSync4(target, `@echo off\r
15950
+ "${bin}" %*\r
15951
+ `, "utf8");
15952
+ } else {
15953
+ writeFileSync4(target, `#!/bin/sh
15954
+ exec "${shQuote(bin)}" "$@"
15955
+ `, {
15956
+ encoding: "utf8",
15957
+ mode: 493
15958
+ });
15959
+ chmodSync2(target, 493);
15960
+ }
15961
+ return target;
15962
+ }
15963
+ function removeForgeShim(home, bin, platform2) {
15964
+ if (!bin) return false;
15965
+ const target = resolveInside(shimsDir(home), shimName(bin, platform2));
15966
+ if (!target || !existsSync12(target)) return false;
15967
+ rmSync3(target, { force: true });
15968
+ return true;
15969
+ }
15970
+
15971
+ // src/registry/pypi.ts
15972
+ import { mkdirSync as mkdirSync4, readFileSync as readFileSync10 } from "fs";
15973
+ import path20 from "path";
15925
15974
 
15926
15975
  // src/registry/versions.ts
15927
15976
  var VERSION_RE = /^(\d+(?:\.\d+)*)(?:(a|b|rc)(\d+))?(?:\.post(\d+))?(?:\.dev(\d+))?$/i;
@@ -16051,7 +16100,7 @@ function latestStable(versions) {
16051
16100
  var PYPI_JSON = "https://pypi.org/pypi";
16052
16101
  var CACHE_TTL_MS = 60 * 60 * 1e3;
16053
16102
  function pypiCacheFile(cacheDir, dist) {
16054
- return path19.join(cacheDir, `${dist}.json`);
16103
+ return path20.join(cacheDir, `${dist}.json`);
16055
16104
  }
16056
16105
  function asString(v) {
16057
16106
  return typeof v === "string" && v.length ? v : void 0;
@@ -16090,7 +16139,7 @@ function readCache(cacheDir, dist) {
16090
16139
  }
16091
16140
  function writeCache(cacheDir, dist, payload) {
16092
16141
  try {
16093
- mkdirSync3(cacheDir, { recursive: true });
16142
+ mkdirSync4(cacheDir, { recursive: true });
16094
16143
  writeFileAtomic(
16095
16144
  pypiCacheFile(cacheDir, dist),
16096
16145
  JSON.stringify({ fetchedAt: Date.now(), payload })
@@ -16247,20 +16296,20 @@ async function resolveRelease(dist, opts) {
16247
16296
 
16248
16297
  // src/registry/install.ts
16249
16298
  function forgesRoot(home) {
16250
- return path20.join(home, ".forge-cli", "forges");
16299
+ return path21.join(home, ".forge-cli", "forges");
16251
16300
  }
16252
16301
  function forgeStatePath(home) {
16253
- return path20.join(forgesRoot(home), "state.json");
16302
+ return path21.join(forgesRoot(home), "state.json");
16254
16303
  }
16255
16304
  function forgeVenv(home, name) {
16256
- return path20.join(forgesRoot(home), name, "venv");
16305
+ return path21.join(forgesRoot(home), name, "venv");
16257
16306
  }
16258
16307
  function receiptPath(home, name) {
16259
- return path20.join(forgesRoot(home), name, "install.json");
16308
+ return path21.join(forgesRoot(home), name, "install.json");
16260
16309
  }
16261
16310
  function loadForgeState(home) {
16262
16311
  const file = forgeStatePath(home);
16263
- if (!existsSync12(file)) return { forges: {} };
16312
+ if (!existsSync13(file)) return { forges: {} };
16264
16313
  try {
16265
16314
  const raw = JSON.parse(readFileSync11(file, "utf8"));
16266
16315
  if (typeof raw.forges !== "object" || !raw.forges || Array.isArray(raw.forges)) {
@@ -16279,7 +16328,7 @@ function ghostEntry(name, receipt) {
16279
16328
  return {
16280
16329
  name,
16281
16330
  dist: receipt.dist,
16282
- bin: path20.basename(receipt.bin).replace(/\.exe$/i, ""),
16331
+ bin: path21.basename(receipt.bin).replace(/\.exe$/i, ""),
16283
16332
  minPython: receipt.python.split(".").slice(0, 2).join("."),
16284
16333
  origin: "official",
16285
16334
  // Extras instalados junto — reinstall/update/rollback do ghost pedem o
@@ -16288,22 +16337,22 @@ function ghostEntry(name, receipt) {
16288
16337
  };
16289
16338
  }
16290
16339
  function quarantineCorruptState(file) {
16291
- if (!existsSync12(file)) return;
16340
+ if (!existsSync13(file)) return;
16292
16341
  try {
16293
16342
  JSON.parse(readFileSync11(file, "utf8"));
16294
16343
  } catch {
16295
16344
  try {
16296
- writeFileSync4(`${file}.corrupt`, readFileSync11(file), { flag: "wx" });
16345
+ writeFileSync5(`${file}.corrupt`, readFileSync11(file), { flag: "wx" });
16297
16346
  } catch {
16298
16347
  }
16299
16348
  }
16300
16349
  }
16301
16350
  function saveForgeState(home, state) {
16302
- mkdirSync4(forgesRoot(home), { recursive: true });
16351
+ mkdirSync5(forgesRoot(home), { recursive: true });
16303
16352
  if (process.platform !== "win32") {
16304
16353
  try {
16305
- chmodSync2(forgesRoot(home), 448);
16306
- chmodSync2(path20.dirname(forgesRoot(home)), 448);
16354
+ chmodSync3(forgesRoot(home), 448);
16355
+ chmodSync3(path21.dirname(forgesRoot(home)), 448);
16307
16356
  } catch {
16308
16357
  }
16309
16358
  }
@@ -16313,7 +16362,7 @@ function saveForgeState(home, state) {
16313
16362
  `);
16314
16363
  }
16315
16364
  function wheelCacheDir(cacheDir, dist) {
16316
- return path20.join(path20.dirname(cacheDir), "wheels", dist);
16365
+ return path21.join(path21.dirname(cacheDir), "wheels", dist);
16317
16366
  }
16318
16367
  function entryExtras(entry2) {
16319
16368
  return [...new Set(entry2.extras ?? [])].sort();
@@ -16326,13 +16375,13 @@ function pipSpec(entry2, version) {
16326
16375
  return `${entry2.dist}${extrasSuffix(entry2)}==${version}`;
16327
16376
  }
16328
16377
  function venvBin(venvDir, platform2 = process.platform) {
16329
- return platform2 === "win32" ? path20.join(venvDir, "Scripts") : path20.join(venvDir, "bin");
16378
+ return platform2 === "win32" ? path21.join(venvDir, "Scripts") : path21.join(venvDir, "bin");
16330
16379
  }
16331
16380
  function venvPython(venvDir, platform2 = process.platform) {
16332
- return path20.join(venvBin(venvDir, platform2), platform2 === "win32" ? "python.exe" : "python");
16381
+ return path21.join(venvBin(venvDir, platform2), platform2 === "win32" ? "python.exe" : "python");
16333
16382
  }
16334
16383
  function forgeLockDir(home) {
16335
- return path20.join(forgesRoot(home), ".forge-lifecycle.lock");
16384
+ return path21.join(forgesRoot(home), ".forge-lifecycle.lock");
16336
16385
  }
16337
16386
  function pidAliveDefault(pid) {
16338
16387
  try {
@@ -16349,12 +16398,12 @@ async function acquireForgeLock(home, opts = {}) {
16349
16398
  const now = opts.now ?? Date.now;
16350
16399
  const alive = opts.pidAlive ?? pidAliveDefault;
16351
16400
  const dir = forgeLockDir(home);
16352
- const info = path20.join(dir, "info.json");
16401
+ const info = path21.join(dir, "info.json");
16353
16402
  const deadline = now() + timeoutMs;
16354
16403
  for (; ; ) {
16355
16404
  try {
16356
- mkdirSync4(forgesRoot(home), { recursive: true });
16357
- mkdirSync4(dir);
16405
+ mkdirSync5(forgesRoot(home), { recursive: true });
16406
+ mkdirSync5(dir);
16358
16407
  } catch (error) {
16359
16408
  if (error.code !== "EEXIST") {
16360
16409
  return { ok: false, reason: "error", detail: `lifecycle lock: ${String(error)}` };
@@ -16375,7 +16424,7 @@ async function acquireForgeLock(home, opts = {}) {
16375
16424
  })();
16376
16425
  if (stale || broken) {
16377
16426
  try {
16378
- rmSync3(dir, { recursive: true, force: true });
16427
+ rmSync4(dir, { recursive: true, force: true });
16379
16428
  } catch {
16380
16429
  }
16381
16430
  continue;
@@ -16391,7 +16440,7 @@ async function acquireForgeLock(home, opts = {}) {
16391
16440
  continue;
16392
16441
  }
16393
16442
  try {
16394
- writeFileSync4(info, JSON.stringify({ pid: process.pid, at: new Date(now()).toISOString() }));
16443
+ writeFileSync5(info, JSON.stringify({ pid: process.pid, at: new Date(now()).toISOString() }));
16395
16444
  } catch {
16396
16445
  }
16397
16446
  return {
@@ -16400,7 +16449,7 @@ async function acquireForgeLock(home, opts = {}) {
16400
16449
  dir,
16401
16450
  release: () => {
16402
16451
  try {
16403
- rmSync3(dir, { recursive: true, force: true });
16452
+ rmSync4(dir, { recursive: true, force: true });
16404
16453
  } catch {
16405
16454
  }
16406
16455
  }
@@ -16414,7 +16463,7 @@ function installConsistency(home, name) {
16414
16463
  const dir = resolveInside(forgesRoot(home), name);
16415
16464
  const venv = forgeVenv(home, name);
16416
16465
  if (!entry2) {
16417
- const leftover = dir !== null && existsSync12(dir) || existsSync12(venv);
16466
+ const leftover = dir !== null && existsSync13(dir) || existsSync13(venv);
16418
16467
  return leftover ? {
16419
16468
  ok: false,
16420
16469
  status: "orphaned",
@@ -16422,7 +16471,7 @@ function installConsistency(home, name) {
16422
16471
  } : { ok: false, status: "not-installed", detail: `${name}: n\xE3o instalado via registry` };
16423
16472
  }
16424
16473
  const rfile = receiptPath(home, name);
16425
- if (!existsSync12(rfile)) {
16474
+ if (!existsSync13(rfile)) {
16426
16475
  return {
16427
16476
  ok: false,
16428
16477
  status: "missing-receipt",
@@ -16455,7 +16504,7 @@ function installConsistency(home, name) {
16455
16504
  detail: `${name}: state=${entry2.version} mas receipt=${receipt.version} \u2014 escrita interrompida no meio; ${REPAIR_HINT}`
16456
16505
  };
16457
16506
  }
16458
- if (!existsSync12(entry2.venv ?? venv)) {
16507
+ if (!existsSync13(entry2.venv ?? venv)) {
16459
16508
  return {
16460
16509
  ok: false,
16461
16510
  status: "missing-venv",
@@ -16511,16 +16560,16 @@ function selectInterpreter(entry2, resolved, pythons) {
16511
16560
  return { python: candidates[0] };
16512
16561
  }
16513
16562
  function checkDistHashes(distFiles, wheels) {
16514
- const have = existsSync12(wheels) ? readdirSync6(wheels) : [];
16563
+ const have = existsSync13(wheels) ? readdirSync6(wheels) : [];
16515
16564
  let verifiedHash;
16516
16565
  let verifiedFile;
16517
16566
  for (const f of distFiles) {
16518
16567
  if (!have.includes(f.filename) || !f.sha256) continue;
16519
- const digest = createHash2("sha256").update(readFileSync11(path20.join(wheels, f.filename))).digest("hex");
16568
+ const digest = createHash2("sha256").update(readFileSync11(path21.join(wheels, f.filename))).digest("hex");
16520
16569
  if (digest !== f.sha256) {
16521
- const culprit = path20.join(wheels, f.filename);
16570
+ const culprit = path21.join(wheels, f.filename);
16522
16571
  try {
16523
- rmSync3(`${culprit}.rejected`, { force: true });
16572
+ rmSync4(`${culprit}.rejected`, { force: true });
16524
16573
  renameSync2(culprit, `${culprit}.rejected`);
16525
16574
  } catch {
16526
16575
  }
@@ -16557,7 +16606,7 @@ async function registryInstall(entry2, pin, deps) {
16557
16606
  }
16558
16607
  return { stage: "incomplete", detail: c5.detail };
16559
16608
  };
16560
- if (!deps.clean && existsSync12(venvDir)) return consistencyGate();
16609
+ if (!deps.clean && existsSync13(venvDir)) return consistencyGate();
16561
16610
  const resolved = await resolveRelease(entry2.dist, {
16562
16611
  pin,
16563
16612
  offline: deps.offline,
@@ -16615,20 +16664,20 @@ async function registryInstall(entry2, pin, deps) {
16615
16664
  return { stage: "busy", detail: `${entry2.name}: ${lockRes.detail}` };
16616
16665
  }
16617
16666
  try {
16618
- if (!deps.clean && existsSync12(venvDir)) return consistencyGate();
16619
- const forgeDir = path20.join(forgesRoot(deps.home), entry2.name);
16667
+ if (!deps.clean && existsSync13(venvDir)) return consistencyGate();
16668
+ const forgeDir = path21.join(forgesRoot(deps.home), entry2.name);
16620
16669
  let backupDir = null;
16621
- if (deps.clean && existsSync12(forgeDir)) {
16670
+ if (deps.clean && existsSync13(forgeDir)) {
16622
16671
  backupDir = `${forgeDir}.restore-${process.pid}`;
16623
16672
  renameSync2(forgeDir, backupDir);
16624
16673
  }
16625
16674
  const cleanup = () => {
16626
- rmSync3(venvDir, { recursive: true, force: true });
16627
- if (existsSync12(forgeDir) && !readdirSync6(forgeDir).length) {
16628
- rmSync3(forgeDir, { recursive: true, force: true });
16675
+ rmSync4(venvDir, { recursive: true, force: true });
16676
+ if (existsSync13(forgeDir) && !readdirSync6(forgeDir).length) {
16677
+ rmSync4(forgeDir, { recursive: true, force: true });
16629
16678
  }
16630
16679
  if (backupDir) {
16631
- rmSync3(forgeDir, { recursive: true, force: true });
16680
+ rmSync4(forgeDir, { recursive: true, force: true });
16632
16681
  renameSync2(backupDir, forgeDir);
16633
16682
  backupDir = null;
16634
16683
  }
@@ -16643,7 +16692,7 @@ async function registryInstall(entry2, pin, deps) {
16643
16692
  }
16644
16693
  const vpy = venvPython(venvDir, platform2);
16645
16694
  const spec = pipSpec(entry2, resolved.version);
16646
- mkdirSync4(wheels, { recursive: true });
16695
+ mkdirSync5(wheels, { recursive: true });
16647
16696
  const distFiles = distArtifactFiles(resolved.files, entry2.dist);
16648
16697
  let verifiedHash;
16649
16698
  let verifiedFile;
@@ -16671,7 +16720,7 @@ async function registryInstall(entry2, pin, deps) {
16671
16720
  return { stage: "lock", error: depErr };
16672
16721
  }
16673
16722
  } else if (deps.offline) {
16674
- const have = existsSync12(wheels) ? readdirSync6(wheels) : [];
16723
+ const have = existsSync13(wheels) ? readdirSync6(wheels) : [];
16675
16724
  if (!distFiles.length || !distFiles.some((f) => have.includes(f.filename))) {
16676
16725
  cleanup();
16677
16726
  return {
@@ -16739,11 +16788,11 @@ async function registryInstall(entry2, pin, deps) {
16739
16788
  ...lock ? (
16740
16789
  // Lock já enumera o fecho inteiro — inclusive as deps dos extras
16741
16790
  // declarados — então os artefatos entram por caminho puro.
16742
- lock.artifacts.map((a3) => path20.join(wheels, a3.filename))
16791
+ lock.artifacts.map((a3) => path21.join(wheels, a3.filename))
16743
16792
  ) : (
16744
16793
  // `[extras]` no caminho do artefato: pip instala a wheel verificada
16745
16794
  // E resolve as deps do extra no índice/--find-links (PEP 508).
16746
- [`${path20.join(wheels, verifiedFile)}${extrasSuffix(entry2)}`]
16795
+ [`${path21.join(wheels, verifiedFile)}${extrasSuffix(entry2)}`]
16747
16796
  )
16748
16797
  ];
16749
16798
  const pip = await run(vpy, pipArgs);
@@ -16756,7 +16805,7 @@ async function registryInstall(entry2, pin, deps) {
16756
16805
  }
16757
16806
  const commitBackup = backupDir;
16758
16807
  backupDir = null;
16759
- const binPath = path20.join(
16808
+ const binPath = path21.join(
16760
16809
  venvBin(venvDir, platform2),
16761
16810
  platform2 === "win32" ? `${entry2.bin}.exe` : entry2.bin
16762
16811
  );
@@ -16793,15 +16842,24 @@ async function registryInstall(entry2, pin, deps) {
16793
16842
  };
16794
16843
  deps.receiptPatch?.(receipt);
16795
16844
  try {
16796
- mkdirSync4(path20.dirname(receiptPath(deps.home, entry2.name)), { recursive: true });
16845
+ mkdirSync5(path21.dirname(receiptPath(deps.home, entry2.name)), { recursive: true });
16797
16846
  writeFileAtomic(receiptPath(deps.home, entry2.name), `${JSON.stringify(receipt, null, 2)}
16798
16847
  `);
16799
16848
  const state = loadForgeState(deps.home);
16800
16849
  state.forges[entry2.name] = receipt;
16801
16850
  saveForgeState(deps.home, state);
16851
+ try {
16852
+ receipt.shim = emitForgeShim(deps.home, binPath, platform2);
16853
+ } catch (shimError) {
16854
+ receipt.shimRefused = shimError instanceof Error ? shimError.message : String(shimError);
16855
+ }
16856
+ writeFileAtomic(receiptPath(deps.home, entry2.name), `${JSON.stringify(receipt, null, 2)}
16857
+ `);
16858
+ state.forges[entry2.name] = receipt;
16859
+ saveForgeState(deps.home, state);
16802
16860
  } catch (error) {
16803
16861
  if (commitBackup) {
16804
- rmSync3(forgeDir, { recursive: true, force: true });
16862
+ rmSync4(forgeDir, { recursive: true, force: true });
16805
16863
  try {
16806
16864
  renameSync2(commitBackup, forgeDir);
16807
16865
  } catch {
@@ -16814,7 +16872,7 @@ async function registryInstall(entry2, pin, deps) {
16814
16872
  detail: `${entry2.name}: pip instalou mas o receipt/state falhou (${why}) \u2014 instala\xE7\xE3o INCOMPLETA (${consistency.status}): ${consistency.detail || "reexecute install"}`
16815
16873
  };
16816
16874
  }
16817
- if (commitBackup) rmSync3(commitBackup, { recursive: true, force: true });
16875
+ if (commitBackup) rmSync4(commitBackup, { recursive: true, force: true });
16818
16876
  if (verify.exitCode !== 0) {
16819
16877
  return { stage: "verify", detail: `${entry2.bin} --help saiu com c\xF3digo ${verify.exitCode}` };
16820
16878
  }
@@ -16827,22 +16885,27 @@ function registryUninstall(target, deps) {
16827
16885
  const dir = resolveInside(forgesRoot(deps.home), target.name);
16828
16886
  if (!dir)
16829
16887
  return { removed: false, receiptRemoved: false, cacheRemoved: false, refused: "unsafe-name" };
16830
- const removed = existsSync12(dir);
16831
- if (removed) rmSync3(dir, { recursive: true, force: true });
16832
- const wheels = target.dist && isSafeRepoName(target.dist) ? resolveInside(path20.join(deps.home, ".forge-cli", "cache", "wheels"), target.dist) : null;
16833
- const cacheRemoved = wheels !== null && existsSync12(wheels);
16834
- if (wheels) rmSync3(wheels, { recursive: true, force: true });
16888
+ const removed = existsSync13(dir);
16889
+ if (removed) rmSync4(dir, { recursive: true, force: true });
16890
+ const wheels = target.dist && isSafeRepoName(target.dist) ? resolveInside(path21.join(deps.home, ".forge-cli", "cache", "wheels"), target.dist) : null;
16891
+ const cacheRemoved = wheels !== null && existsSync13(wheels);
16892
+ if (wheels) rmSync4(wheels, { recursive: true, force: true });
16835
16893
  const state = loadForgeState(deps.home);
16836
16894
  const hadReceipt = Object.hasOwn(state.forges, target.name);
16895
+ const shimRemoved = removeForgeShim(
16896
+ deps.home,
16897
+ hadReceipt ? state.forges[target.name].shim ?? state.forges[target.name].bin : void 0,
16898
+ deps.platform ?? process.platform
16899
+ );
16837
16900
  if (hadReceipt) delete state.forges[target.name];
16838
16901
  saveForgeState(deps.home, state);
16839
- return { removed, receiptRemoved: hadReceipt, cacheRemoved };
16902
+ return { removed, receiptRemoved: hadReceipt, cacheRemoved, shimRemoved };
16840
16903
  }
16841
16904
 
16842
16905
  // src/compat.ts
16843
16906
  import { createHash as createHash3 } from "crypto";
16844
- import { existsSync as existsSync13, readFileSync as readFileSync12 } from "fs";
16845
- import path21 from "path";
16907
+ import { existsSync as existsSync14, readFileSync as readFileSync12 } from "fs";
16908
+ import path22 from "path";
16846
16909
  var ECOSYSTEM_SCHEMA = "forge/EcosystemCompatibility/v1";
16847
16910
  function isRecord(v) {
16848
16911
  return typeof v === "object" && v !== null && !Array.isArray(v);
@@ -16929,7 +16992,7 @@ function manifestProblems(doc) {
16929
16992
  return problems;
16930
16993
  }
16931
16994
  function loadCompatManifest(manifestPath) {
16932
- if (!existsSync13(manifestPath)) return null;
16995
+ if (!existsSync14(manifestPath)) return null;
16933
16996
  let raw;
16934
16997
  try {
16935
16998
  raw = readFileSync12(manifestPath, "utf-8");
@@ -16954,7 +17017,7 @@ function loadCompatManifest(manifestPath) {
16954
17017
  };
16955
17018
  }
16956
17019
  function defaultManifestPath(workspaceDir) {
16957
- return path21.join(workspaceDir, "the-forge", "ecosystem-compatibility.json");
17020
+ return path22.join(workspaceDir, "the-forge", "ecosystem-compatibility.json");
16958
17021
  }
16959
17022
  function compatVerdict(manifest, component, version) {
16960
17023
  const entry2 = manifest.components.find((c5) => c5.component === component);
@@ -16962,8 +17025,8 @@ function compatVerdict(manifest, component, version) {
16962
17025
  return entry2.version === version ? "certified" : "incompatible";
16963
17026
  }
16964
17027
  function readDeclaredVersion(repoDir) {
16965
- const pkg = path21.join(repoDir, "package.json");
16966
- if (existsSync13(pkg)) {
17028
+ const pkg = path22.join(repoDir, "package.json");
17029
+ if (existsSync14(pkg)) {
16967
17030
  try {
16968
17031
  const parsed = JSON.parse(readFileSync12(pkg, "utf-8"));
16969
17032
  if (isRecord(parsed) && typeof parsed.version === "string" && parsed.version) {
@@ -16972,8 +17035,8 @@ function readDeclaredVersion(repoDir) {
16972
17035
  } catch {
16973
17036
  }
16974
17037
  }
16975
- const pyproject = path21.join(repoDir, "pyproject.toml");
16976
- if (existsSync13(pyproject)) {
17038
+ const pyproject = path22.join(repoDir, "pyproject.toml");
17039
+ if (existsSync14(pyproject)) {
16977
17040
  try {
16978
17041
  const table = /^\[project\][^\n]*\n((?:(?!\[)[^\n]*(?:\n|$))*)/m.exec(
16979
17042
  readFileSync12(pyproject, "utf-8")
@@ -17015,7 +17078,7 @@ function mergeRegistryPhase(infos, registry) {
17015
17078
  const reg = Object.hasOwn(registry, i3.name) ? registry[i3.name] : void 0;
17016
17079
  if (!reg || typeof reg !== "object") continue;
17017
17080
  const tag2 = `pypi ${reg.dist ?? "?"}==${reg.version ?? "?"}`;
17018
- const binMissing = typeof reg.bin !== "string" || !existsSync14(reg.bin);
17081
+ const binMissing = typeof reg.bin !== "string" || !existsSync15(reg.bin);
17019
17082
  if (binMissing) {
17020
17083
  if (i3.phase === "not-installed" || i3.phase === "installed") i3.phase = "drifted";
17021
17084
  i3.describe = [i3.describe, `${tag2} (bin ausente)`].filter(Boolean).join(" + ");
@@ -17154,15 +17217,15 @@ async function runVersionsCommand(cli, names) {
17154
17217
 
17155
17218
  // src/doctor2/index.ts
17156
17219
  import os4 from "os";
17157
- import path32 from "path";
17220
+ import path33 from "path";
17158
17221
 
17159
17222
  // src/hosts/claude.ts
17160
- import path23 from "path";
17223
+ import path24 from "path";
17161
17224
 
17162
17225
  // src/hosts/types.ts
17163
- import { copyFileSync as copyFileSync2, existsSync as existsSync15, mkdirSync as mkdirSync5, readFileSync as readFileSync13, readdirSync as readdirSync7, rmSync as rmSync4 } from "fs";
17226
+ import { copyFileSync as copyFileSync2, existsSync as existsSync16, mkdirSync as mkdirSync6, readFileSync as readFileSync13, readdirSync as readdirSync7, rmSync as rmSync5 } from "fs";
17164
17227
  import os2 from "os";
17165
- import path22 from "path";
17228
+ import path23 from "path";
17166
17229
  var defaultProbe = {
17167
17230
  output: (command, args) => commandOutput(command, args),
17168
17231
  detailed: async (command, args) => {
@@ -17181,7 +17244,7 @@ function parseVersionOutput(out) {
17181
17244
  return first && first !== "ok" ? first : null;
17182
17245
  }
17183
17246
  function existingConfigPaths(home, rels) {
17184
- return rels.map((rel2) => path22.join(home, rel2)).filter((p) => existsSync15(p));
17247
+ return rels.map((rel2) => path23.join(home, rel2)).filter((p) => existsSync16(p));
17185
17248
  }
17186
17249
  async function detectHost(home, spec) {
17187
17250
  const runProbe = async (argv) => spec.probe.detailed ? spec.probe.detailed(argv[0], argv.slice(1)) : { out: await spec.probe.output(argv[0], argv.slice(1)), timedOut: false };
@@ -17237,7 +17300,7 @@ async function detectHost(home, spec) {
17237
17300
  };
17238
17301
  }
17239
17302
  function readJsonObject(file) {
17240
- if (!existsSync15(file)) return null;
17303
+ if (!existsSync16(file)) return null;
17241
17304
  try {
17242
17305
  const parsed = JSON.parse(readFileSync13(file, "utf8"));
17243
17306
  return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : "invalid";
@@ -17275,22 +17338,22 @@ function backupTimestamp(d = /* @__PURE__ */ new Date()) {
17275
17338
  return `${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}-${p(d.getHours())}${p(d.getMinutes())}${p(d.getSeconds())}${p(d.getMilliseconds(), 3)}`;
17276
17339
  }
17277
17340
  function backupsRoot(home) {
17278
- return path22.join(artifactsRoot(home), "backups");
17341
+ return path23.join(artifactsRoot(home), "backups");
17279
17342
  }
17280
17343
  function backupDirFor(home, hostId) {
17281
- return path22.join(backupsRoot(home), `hosts-${hostId}-${backupTimestamp()}`);
17344
+ return path23.join(backupsRoot(home), `hosts-${hostId}-${backupTimestamp()}`);
17282
17345
  }
17283
17346
  function backupTargets(dir, hostId, targets) {
17284
- mkdirSync5(dir, { recursive: true });
17347
+ mkdirSync6(dir, { recursive: true });
17285
17348
  const files = targets.map((target) => {
17286
- const name = path22.basename(target);
17287
- const absent = !existsSync15(target);
17288
- if (absent) writeFileAtomic(path22.join(dir, `${name}.absent`), "");
17289
- else copyFileSync2(target, path22.join(dir, name));
17349
+ const name = path23.basename(target);
17350
+ const absent = !existsSync16(target);
17351
+ if (absent) writeFileAtomic(path23.join(dir, `${name}.absent`), "");
17352
+ else copyFileSync2(target, path23.join(dir, name));
17290
17353
  return { backup: name, target, absent };
17291
17354
  });
17292
17355
  writeFileAtomic(
17293
- path22.join(dir, "manifest.json"),
17356
+ path23.join(dir, "manifest.json"),
17294
17357
  `${JSON.stringify({ host: hostId, files }, null, 2)}
17295
17358
  `
17296
17359
  );
@@ -17303,18 +17366,18 @@ function latestBackupDir(home, hostId) {
17303
17366
  return null;
17304
17367
  }
17305
17368
  const hit = names.filter((n4) => n4.startsWith(`hosts-${hostId}-`)).sort().reverse()[0];
17306
- return hit ? path22.join(backupsRoot(home), hit) : null;
17369
+ return hit ? path23.join(backupsRoot(home), hit) : null;
17307
17370
  }
17308
17371
  function restoreBackupDir(dir) {
17309
- const manifest = JSON.parse(readFileSync13(path22.join(dir, "manifest.json"), "utf8"));
17372
+ const manifest = JSON.parse(readFileSync13(path23.join(dir, "manifest.json"), "utf8"));
17310
17373
  const restored = [];
17311
17374
  const removed = [];
17312
17375
  for (const entry2 of manifest.files ?? []) {
17313
17376
  if (entry2.absent) {
17314
- rmSync4(entry2.target, { force: true });
17377
+ rmSync5(entry2.target, { force: true });
17315
17378
  removed.push(entry2.target);
17316
17379
  } else {
17317
- writeFileAtomic(entry2.target, readFileSync13(path22.join(dir, entry2.backup), "utf8"));
17380
+ writeFileAtomic(entry2.target, readFileSync13(path23.join(dir, entry2.backup), "utf8"));
17318
17381
  restored.push(entry2.target);
17319
17382
  }
17320
17383
  }
@@ -17363,7 +17426,7 @@ async function applyHostPlan(home, plan, resolveWrite, opts = {}) {
17363
17426
  );
17364
17427
  for (const w of writes) {
17365
17428
  try {
17366
- mkdirSync5(path22.dirname(w.target), { recursive: true });
17429
+ mkdirSync6(path23.dirname(w.target), { recursive: true });
17367
17430
  writeFileAtomic(w.target, w.content);
17368
17431
  applied.push(w.target);
17369
17432
  } catch (error) {
@@ -17410,9 +17473,9 @@ async function rollbackHostPlan(home, plan, backup) {
17410
17473
 
17411
17474
  // src/hosts/claude.ts
17412
17475
  var CONFIG_FILE = ".claude.json";
17413
- var CONFIG_REL = [CONFIG_FILE, ".claude", path23.join(".claude", "settings.json")];
17476
+ var CONFIG_REL = [CONFIG_FILE, ".claude", path24.join(".claude", "settings.json")];
17414
17477
  function targetFor(home) {
17415
- return path23.join(home, CONFIG_FILE);
17478
+ return path24.join(home, CONFIG_FILE);
17416
17479
  }
17417
17480
  function createClaudeAdapter(probe = defaultProbe) {
17418
17481
  return {
@@ -17480,12 +17543,12 @@ function createClaudeAdapter(probe = defaultProbe) {
17480
17543
  var claudeAdapter = createClaudeAdapter();
17481
17544
 
17482
17545
  // src/hosts/codex.ts
17483
- import { existsSync as existsSync16, readFileSync as readFileSync14 } from "fs";
17484
- import path24 from "path";
17485
- var CONFIG_FILE2 = path24.join(".codex", "config.toml");
17546
+ import { existsSync as existsSync17, readFileSync as readFileSync14 } from "fs";
17547
+ import path25 from "path";
17548
+ var CONFIG_FILE2 = path25.join(".codex", "config.toml");
17486
17549
  var CONFIG_REL2 = [CONFIG_FILE2, ".codex"];
17487
17550
  function targetFor2(home) {
17488
- return path24.join(home, CONFIG_FILE2);
17551
+ return path25.join(home, CONFIG_FILE2);
17489
17552
  }
17490
17553
  function escapeRe(s) {
17491
17554
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -17551,7 +17614,7 @@ function createCodexAdapter(probe = defaultProbe) {
17551
17614
  authArgv: ["codex", "login", "status"],
17552
17615
  hasIntegration: (dir) => {
17553
17616
  const file = targetFor2(dir);
17554
- return existsSync16(file) && hasAnyCodexMcpSection(readFileSync14(file, "utf8"));
17617
+ return existsSync17(file) && hasAnyCodexMcpSection(readFileSync14(file, "utf8"));
17555
17618
  }
17556
17619
  });
17557
17620
  },
@@ -17560,7 +17623,7 @@ function createCodexAdapter(probe = defaultProbe) {
17560
17623
  if (!argv?.length) return null;
17561
17624
  const h3 = hostHome(home);
17562
17625
  const target = targetFor2(h3);
17563
- const existing = existsSync16(target) ? readFileSync14(target, "utf8") : null;
17626
+ const existing = existsSync17(target) ? readFileSync14(target, "utf8") : null;
17564
17627
  if (existing !== null && hasCodexMcpSection(existing, forge.forge_id)) {
17565
17628
  return {
17566
17629
  host: "codex",
@@ -17591,7 +17654,7 @@ function createCodexAdapter(probe = defaultProbe) {
17591
17654
  plan,
17592
17655
  (action) => {
17593
17656
  if (!action.target || !action.argv?.length) return "skip";
17594
- const existing = existsSync16(action.target) ? readFileSync14(action.target, "utf8") : null;
17657
+ const existing = existsSync17(action.target) ? readFileSync14(action.target, "utf8") : null;
17595
17658
  if (existing !== null && hasCodexMcpSection(existing, plan.forge_id)) {
17596
17659
  return "duplicate";
17597
17660
  }
@@ -17608,7 +17671,7 @@ ${block2}
17608
17671
  validateIntegration: async (forge_id, home) => {
17609
17672
  const file = targetFor2(hostHome(home));
17610
17673
  const checks = [];
17611
- if (!existsSync16(file)) {
17674
+ if (!existsSync17(file)) {
17612
17675
  checks.push({ id: "config-file", result: "fail", detail: "absent" });
17613
17676
  checks.push({ id: "mcp-section", result: "fail", detail: forge_id });
17614
17677
  return { ok: false, checks };
@@ -17635,12 +17698,12 @@ ${block2}
17635
17698
  var codexAdapter = createCodexAdapter();
17636
17699
 
17637
17700
  // src/hosts/copilot.ts
17638
- import path25 from "path";
17639
- import { existsSync as existsSync17 } from "fs";
17640
- var CONFIG_FILE3 = path25.join(".copilot", "mcp-config.json");
17641
- var CONFIG_REL3 = [".copilot", CONFIG_FILE3, path25.join(".config", "gh")];
17701
+ import path26 from "path";
17702
+ import { existsSync as existsSync18 } from "fs";
17703
+ var CONFIG_FILE3 = path26.join(".copilot", "mcp-config.json");
17704
+ var CONFIG_REL3 = [".copilot", CONFIG_FILE3, path26.join(".config", "gh")];
17642
17705
  function targetFor3(home) {
17643
- return path25.join(home, CONFIG_FILE3);
17706
+ return path26.join(home, CONFIG_FILE3);
17644
17707
  }
17645
17708
  function createCopilotAdapter(probe = defaultProbe) {
17646
17709
  return {
@@ -17664,7 +17727,7 @@ function createCopilotAdapter(probe = defaultProbe) {
17664
17727
  if (!argv?.length) return null;
17665
17728
  const h3 = hostHome(home);
17666
17729
  const target = targetFor3(h3);
17667
- if (!existsSync17(target)) return null;
17730
+ if (!existsSync18(target)) return null;
17668
17731
  if (hasMcpEntry(target, forge.forge_id)) {
17669
17732
  return {
17670
17733
  host: "copilot",
@@ -17710,11 +17773,11 @@ function createCopilotAdapter(probe = defaultProbe) {
17710
17773
  var copilotAdapter = createCopilotAdapter();
17711
17774
 
17712
17775
  // src/hosts/cursor.ts
17713
- import path26 from "path";
17714
- var CONFIG_FILE4 = path26.join(".cursor", "mcp.json");
17776
+ import path27 from "path";
17777
+ var CONFIG_FILE4 = path27.join(".cursor", "mcp.json");
17715
17778
  var CONFIG_REL4 = [CONFIG_FILE4, ".cursor"];
17716
17779
  function targetFor4(home) {
17717
- return path26.join(home, CONFIG_FILE4);
17780
+ return path27.join(home, CONFIG_FILE4);
17718
17781
  }
17719
17782
  function createCursorAdapter(probe = defaultProbe) {
17720
17783
  return {
@@ -17780,8 +17843,8 @@ function createCursorAdapter(probe = defaultProbe) {
17780
17843
  var cursorAdapter = createCursorAdapter();
17781
17844
 
17782
17845
  // src/hosts/devin.ts
17783
- import path27 from "path";
17784
- var CONFIG_REL5 = [".devin", path27.join(".config", "devin")];
17846
+ import path28 from "path";
17847
+ var CONFIG_REL5 = [".devin", path28.join(".config", "devin")];
17785
17848
  function createDevinAdapter(probe = defaultProbe) {
17786
17849
  return {
17787
17850
  id: "devin",
@@ -17862,13 +17925,13 @@ function errMsg(error) {
17862
17925
  }
17863
17926
 
17864
17927
  // src/doctor2/domains.ts
17865
- import { existsSync as existsSync21, readdirSync as readdirSync10, rmSync as rmSync5, statSync as statSync4, writeFileSync as writeFileSync5 } from "fs";
17928
+ import { existsSync as existsSync22, readdirSync as readdirSync10, rmSync as rmSync6, statSync as statSync4, writeFileSync as writeFileSync6 } from "fs";
17866
17929
  import os3 from "os";
17867
- import path31 from "path";
17930
+ import path32 from "path";
17868
17931
 
17869
17932
  // src/envintel/validate.ts
17870
- import { existsSync as existsSync19, readFileSync as readFileSync17 } from "fs";
17871
- import path29 from "path";
17933
+ import { existsSync as existsSync20, readFileSync as readFileSync17 } from "fs";
17934
+ import path30 from "path";
17872
17935
 
17873
17936
  // src/envintel/parse.ts
17874
17937
  var ENV_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
@@ -17957,8 +18020,8 @@ function formatEntry(key, value) {
17957
18020
  }
17958
18021
 
17959
18022
  // src/envintel/schema.ts
17960
- import { existsSync as existsSync18, readFileSync as readFileSync16 } from "fs";
17961
- import path28 from "path";
18023
+ import { existsSync as existsSync19, readFileSync as readFileSync16 } from "fs";
18024
+ import path29 from "path";
17962
18025
  var SECRET_RE = /KEY|SECRET|TOKEN|PASSWORD|CREDENTIAL/;
17963
18026
  var KIND_RULES = [
17964
18027
  { kind: "port", re: /(^|_)PORT($|_)/ },
@@ -18005,8 +18068,8 @@ function validPattern(p) {
18005
18068
  }
18006
18069
  }
18007
18070
  function readSchemaFile(repoDir) {
18008
- const file = path28.join(repoDir, "forge.env.schema.json");
18009
- if (!existsSync18(file)) return [];
18071
+ const file = path29.join(repoDir, "forge.env.schema.json");
18072
+ if (!existsSync19(file)) return [];
18010
18073
  try {
18011
18074
  const parsed = JSON.parse(readFileSync16(file, "utf8"));
18012
18075
  const list = Array.isArray(parsed) ? parsed : parsed && typeof parsed === "object" && Array.isArray(parsed.vars) ? parsed.vars : parsed && typeof parsed === "object" ? Object.entries(parsed).map(([key, v]) => ({
@@ -18020,8 +18083,8 @@ function readSchemaFile(repoDir) {
18020
18083
  }
18021
18084
  function deriveSchema(repoDir, envKeys) {
18022
18085
  const specs = /* @__PURE__ */ new Map();
18023
- const exampleFile = path28.join(repoDir, ".env.example");
18024
- if (existsSync18(exampleFile)) {
18086
+ const exampleFile = path29.join(repoDir, ".env.example");
18087
+ if (existsSync19(exampleFile)) {
18025
18088
  for (const entry2 of parseEnv(readFileSync16(exampleFile, "utf8")).entries) {
18026
18089
  if (specs.has(entry2.key)) continue;
18027
18090
  const kind = inferKind(entry2.key, entry2.value || void 0);
@@ -18085,8 +18148,8 @@ function checkValue(spec, value, opts = {}) {
18085
18148
  case "path": {
18086
18149
  if (!value.trim()) return false;
18087
18150
  if (!opts.checkPaths) return true;
18088
- const p = path29.isAbsolute(value) ? value : path29.resolve(opts.baseDir ?? ".", value);
18089
- return existsSync19(p);
18151
+ const p = path30.isAbsolute(value) ? value : path30.resolve(opts.baseDir ?? ".", value);
18152
+ return existsSync20(p);
18090
18153
  }
18091
18154
  case "bool":
18092
18155
  return /^(true|false|0|1|yes|no)$/i.test(value.trim());
@@ -18137,9 +18200,9 @@ function analyzeKey(key, spec, entries, opts) {
18137
18200
  }
18138
18201
  function analyzeEnv(repoDir, envKeys, opts = {}) {
18139
18202
  const schema = deriveSchema(repoDir, envKeys);
18140
- const envPath = path29.join(repoDir, ".env");
18203
+ const envPath = path30.join(repoDir, ".env");
18141
18204
  const specByKey = new Map(schema.vars.map((v) => [v.key, v]));
18142
- const envFile = existsSync19(envPath) ? parseEnv(readFileSync17(envPath, "utf8")) : null;
18205
+ const envFile = existsSync20(envPath) ? parseEnv(readFileSync17(envPath, "utf8")) : null;
18143
18206
  const findings = [];
18144
18207
  const vars = [];
18145
18208
  const byKey = /* @__PURE__ */ new Map();
@@ -18220,9 +18283,9 @@ function inspectEnv(repoDir, envKeys) {
18220
18283
  }
18221
18284
 
18222
18285
  // src/maintenance.ts
18223
- import { existsSync as existsSync20, mkdirSync as mkdirSync6, readFileSync as readFileSync18, readdirSync as readdirSync9 } from "fs";
18286
+ import { existsSync as existsSync21, mkdirSync as mkdirSync7, readFileSync as readFileSync18, readdirSync as readdirSync9 } from "fs";
18224
18287
  import { createHash as createHash4 } from "crypto";
18225
- import path30 from "path";
18288
+ import path31 from "path";
18226
18289
  function envLockDigest(repoDir) {
18227
18290
  const names = [
18228
18291
  ".env.example",
@@ -18234,8 +18297,8 @@ function envLockDigest(repoDir) {
18234
18297
  const files = [];
18235
18298
  const hash = createHash4("sha256");
18236
18299
  for (const name of names) {
18237
- const file = path30.join(repoDir, name);
18238
- if (!existsSync20(file)) continue;
18300
+ const file = path31.join(repoDir, name);
18301
+ if (!existsSync21(file)) continue;
18239
18302
  files.push(name);
18240
18303
  const content = readFileSync18(file);
18241
18304
  hash.update(name).update("\0").update(content).update("\0");
@@ -18249,8 +18312,8 @@ function buildEnvLock(targetDir, repos) {
18249
18312
  forges: {}
18250
18313
  };
18251
18314
  for (const repo of repos) {
18252
- const dir = path30.join(targetDir, repo.name);
18253
- if (!existsSync20(dir)) continue;
18315
+ const dir = path31.join(targetDir, repo.name);
18316
+ if (!existsSync21(dir)) continue;
18254
18317
  const { files, digest } = envLockDigest(dir);
18255
18318
  const head = loadState(targetDir)?.repos[repo.name]?.head;
18256
18319
  lock.forges[repo.name] = { env_files: files, digest, ...head ? { head } : {} };
@@ -18259,14 +18322,14 @@ function buildEnvLock(targetDir, repos) {
18259
18322
  }
18260
18323
  function writeEnvLock(targetDir, repos) {
18261
18324
  const lock = buildEnvLock(targetDir, repos);
18262
- const file = path30.join(artifactsRoot(targetDir), "env.lock.json");
18263
- mkdirSync6(path30.dirname(file), { recursive: true });
18325
+ const file = path31.join(artifactsRoot(targetDir), "env.lock.json");
18326
+ mkdirSync7(path31.dirname(file), { recursive: true });
18264
18327
  writeFileAtomic(file, JSON.stringify(lock, null, 2));
18265
18328
  return lock;
18266
18329
  }
18267
18330
  function checkEnvLock(targetDir, repos) {
18268
- const file = path30.join(artifactsRoot(targetDir), "env.lock.json");
18269
- if (!existsSync20(file)) return repos.map((r2) => ({ forge: r2.name, state: "untracked" }));
18331
+ const file = path31.join(artifactsRoot(targetDir), "env.lock.json");
18332
+ if (!existsSync21(file)) return repos.map((r2) => ({ forge: r2.name, state: "untracked" }));
18270
18333
  let lock;
18271
18334
  try {
18272
18335
  lock = JSON.parse(readFileSync18(file, "utf8"));
@@ -18276,8 +18339,8 @@ function checkEnvLock(targetDir, repos) {
18276
18339
  return repos.map((repo) => {
18277
18340
  const entry2 = lock.forges?.[repo.name];
18278
18341
  if (!entry2) return { forge: repo.name, state: "untracked" };
18279
- const dir = path30.join(targetDir, repo.name);
18280
- if (!existsSync20(dir)) return { forge: repo.name, state: "absent" };
18342
+ const dir = path31.join(targetDir, repo.name);
18343
+ if (!existsSync21(dir)) return { forge: repo.name, state: "absent" };
18281
18344
  const { digest } = envLockDigest(dir);
18282
18345
  return { forge: repo.name, state: digest === entry2.digest ? "match" : "drifted" };
18283
18346
  });
@@ -18298,7 +18361,7 @@ function buildProfile(targetDir) {
18298
18361
  }
18299
18362
  function exportProfile(targetDir, dest) {
18300
18363
  const profile = buildProfile(targetDir);
18301
- mkdirSync6(path30.dirname(path30.resolve(dest)), { recursive: true });
18364
+ mkdirSync7(path31.dirname(path31.resolve(dest)), { recursive: true });
18302
18365
  writeFileAtomic(dest, JSON.stringify(profile, null, 2));
18303
18366
  return profile;
18304
18367
  }
@@ -18399,16 +18462,16 @@ function systemChecks(ctx) {
18399
18462
  readEvidence = `read=falha (${errMsg(error)})`;
18400
18463
  }
18401
18464
  if (readable2) {
18402
- const probe = path31.join(dir, `.forge-doctor2-probe-${process.pid}`);
18465
+ const probe = path32.join(dir, `.forge-doctor2-probe-${process.pid}`);
18403
18466
  try {
18404
- writeFileSync5(probe, "probe\n", "utf8");
18405
- rmSync5(probe, { force: true });
18467
+ writeFileSync6(probe, "probe\n", "utf8");
18468
+ rmSync6(probe, { force: true });
18406
18469
  writable2 = true;
18407
18470
  writeEvidence = "write=ok";
18408
18471
  } catch (error) {
18409
18472
  writeEvidence = `write=falha (${errMsg(error)})`;
18410
18473
  try {
18411
- rmSync5(probe, { force: true });
18474
+ rmSync6(probe, { force: true });
18412
18475
  } catch {
18413
18476
  }
18414
18477
  }
@@ -18434,7 +18497,7 @@ function systemChecks(ctx) {
18434
18497
  const dirEvidence = [];
18435
18498
  let dirFailed = 0;
18436
18499
  for (const { label, dir: d } of required) {
18437
- if (!existsSync21(d)) {
18500
+ if (!existsSync22(d)) {
18438
18501
  dirFailed += 1;
18439
18502
  dirEvidence.push(`${label}=${d}: ausente`);
18440
18503
  continue;
@@ -18492,7 +18555,7 @@ function backupScan(ctx) {
18492
18555
  over = true;
18493
18556
  break;
18494
18557
  }
18495
- const full = path31.join(dir, name);
18558
+ const full = path32.join(dir, name);
18496
18559
  try {
18497
18560
  if (!statSync4(full).isDirectory()) continue;
18498
18561
  } catch {
@@ -18501,16 +18564,16 @@ function backupScan(ctx) {
18501
18564
  if (restorableIf(full)) restorable.push(`${kind}: ${full}`);
18502
18565
  }
18503
18566
  };
18504
- scan(path31.join(artifactsRoot(ctx.root), "backups"), "workspace-backup", dirHasFiles);
18567
+ scan(path32.join(artifactsRoot(ctx.root), "backups"), "workspace-backup", dirHasFiles);
18505
18568
  scan(
18506
- path31.join(ctx.home, ".forge-cli", "backups"),
18569
+ path32.join(ctx.home, ".forge-cli", "backups"),
18507
18570
  "host-backup",
18508
- (full) => existsSync21(path31.join(full, "manifest.json"))
18571
+ (full) => existsSync22(path32.join(full, "manifest.json"))
18509
18572
  );
18510
18573
  for (const repo of ctx.catalog) {
18511
18574
  const dir = resolveInside(ctx.root, repo.name);
18512
18575
  if (!dir || over) continue;
18513
- scan(path31.join(dir, ".forge-cli", "backups"), `env-backup(${repo.name})`, dirHasFiles);
18576
+ scan(path32.join(dir, ".forge-cli", "backups"), `env-backup(${repo.name})`, dirHasFiles);
18514
18577
  }
18515
18578
  if (over) ctx.truncated.value = true;
18516
18579
  return { restorable, scanned };
@@ -18518,7 +18581,7 @@ function backupScan(ctx) {
18518
18581
  function installationChecks(ctx) {
18519
18582
  const checks = [];
18520
18583
  const forgeDir = artifactsRoot(ctx.root);
18521
- const forgeDirPresent = existsSync21(forgeDir);
18584
+ const forgeDirPresent = existsSync22(forgeDir);
18522
18585
  const stateFile = stateFileFor(ctx.root);
18523
18586
  checks.push(
18524
18587
  mkCheck(
@@ -18531,7 +18594,7 @@ function installationChecks(ctx) {
18531
18594
  diagnosis: "diret\xF3rio de estado .forge-cli presente",
18532
18595
  evidence: [
18533
18596
  `${forgeDir} presente`,
18534
- existsSync21(stateFile) ? "state.json presente" : "state.json ausente"
18597
+ existsSync22(stateFile) ? "state.json presente" : "state.json ausente"
18535
18598
  ],
18536
18599
  reversible: null
18537
18600
  } : {
@@ -18546,8 +18609,8 @@ function installationChecks(ctx) {
18546
18609
  }
18547
18610
  )
18548
18611
  );
18549
- const forgeJson = path31.join(ctx.root, "forge.json");
18550
- if (!existsSync21(forgeJson)) {
18612
+ const forgeJson = path32.join(ctx.root, "forge.json");
18613
+ if (!existsSync22(forgeJson)) {
18551
18614
  checks.push(
18552
18615
  mkCheck(ctx.now, {
18553
18616
  id: "installation.forge-json.present",
@@ -18596,10 +18659,10 @@ function installationChecks(ctx) {
18596
18659
  );
18597
18660
  }
18598
18661
  }
18599
- const lockFile = path31.join(forgeDir, "env.lock.json");
18600
- const lockParsed = existsSync21(lockFile) ? readJson(lockFile) : null;
18662
+ const lockFile = path32.join(forgeDir, "env.lock.json");
18663
+ const lockParsed = existsSync22(lockFile) ? readJson(lockFile) : null;
18601
18664
  const lockObj = lockParsed?.ok && lockParsed.value !== null && typeof lockParsed.value === "object" ? lockParsed.value : null;
18602
- if (!forgeDirPresent || !existsSync21(lockFile)) {
18665
+ if (!forgeDirPresent || !existsSync22(lockFile)) {
18603
18666
  checks.push(
18604
18667
  mkCheck(ctx.now, {
18605
18668
  id: "installation.lockfile.present",
@@ -18644,7 +18707,7 @@ function installationChecks(ctx) {
18644
18707
  );
18645
18708
  }
18646
18709
  const trackedForges = lockObj ? Object.keys(lockObj.forges ?? {}) : [];
18647
- if (!existsSync21(lockFile) || !lockObj || !trackedForges.length) {
18710
+ if (!existsSync22(lockFile) || !lockObj || !trackedForges.length) {
18648
18711
  checks.push(
18649
18712
  mkCheck(ctx.now, {
18650
18713
  id: "installation.lockfile.drift",
@@ -18653,7 +18716,7 @@ function installationChecks(ctx) {
18653
18716
  severity: "info",
18654
18717
  diagnosis: "deriva do lockfile n\xE3o verific\xE1vel",
18655
18718
  evidence: [
18656
- !existsSync21(lockFile) ? "sem lockfile para recomputar (.forge-cli/env.lock.json ausente)" : !lockObj ? "lockfile ileg\xEDvel \u2014 digest n\xE3o pode ser recomputado" : "lockfile n\xE3o cobre nenhuma Forja \u2014 nada para recomputar"
18719
+ !existsSync22(lockFile) ? "sem lockfile para recomputar (.forge-cli/env.lock.json ausente)" : !lockObj ? "lockfile ileg\xEDvel \u2014 digest n\xE3o pode ser recomputado" : "lockfile n\xE3o cobre nenhuma Forja \u2014 nada para recomputar"
18657
18720
  ],
18658
18721
  reversible: null
18659
18722
  })
@@ -18675,17 +18738,17 @@ function installationChecks(ctx) {
18675
18738
  })
18676
18739
  );
18677
18740
  }
18678
- const ledgerDir = path31.join(ctx.home, ".forge", "installations");
18741
+ const ledgerDir = path32.join(ctx.home, ".forge", "installations");
18679
18742
  const ledgerNames = listDir(ledgerDir);
18680
18743
  if (ledgerNames === null) {
18681
18744
  checks.push(
18682
18745
  mkCheck(ctx.now, {
18683
18746
  id: "installation.ledger.readable",
18684
18747
  domain: "installation",
18685
- result: existsSync21(ledgerDir) ? "warn" : "skip",
18686
- severity: existsSync21(ledgerDir) ? "medium" : "info",
18687
- diagnosis: existsSync21(ledgerDir) ? "ledger de instala\xE7\xF5es existe mas n\xE3o p\xF4de ser lido" : "sem ledger de instala\xE7\xF5es (~/.forge/installations ausente)",
18688
- evidence: [`${ledgerDir} ${existsSync21(ledgerDir) ? "ileg\xEDvel" : "ausente"}`],
18748
+ result: existsSync22(ledgerDir) ? "warn" : "skip",
18749
+ severity: existsSync22(ledgerDir) ? "medium" : "info",
18750
+ diagnosis: existsSync22(ledgerDir) ? "ledger de instala\xE7\xF5es existe mas n\xE3o p\xF4de ser lido" : "sem ledger de instala\xE7\xF5es (~/.forge/installations ausente)",
18751
+ evidence: [`${ledgerDir} ${existsSync22(ledgerDir) ? "ileg\xEDvel" : "ausente"}`],
18689
18752
  reversible: null
18690
18753
  })
18691
18754
  );
@@ -18813,7 +18876,7 @@ function environmentChecks(ctx) {
18813
18876
  const targets = [{ label: "<workspace>", dir: ctx.root }];
18814
18877
  for (const repo of ctx.catalog) {
18815
18878
  const dir = resolveInside(ctx.root, repo.name);
18816
- if (dir && existsSync21(dir)) targets.push({ label: repo.name, dir, envKeys: repo.envKeys });
18879
+ if (dir && existsSync22(dir)) targets.push({ label: repo.name, dir, envKeys: repo.envKeys });
18817
18880
  }
18818
18881
  const inspected = targets.map((t2) => ({
18819
18882
  ...t2,
@@ -19026,16 +19089,16 @@ async function hostsChecks(ctx) {
19026
19089
  }
19027
19090
  function operationsChecks(ctx) {
19028
19091
  const checks = [];
19029
- const reportsDir = path31.join(artifactsRoot(ctx.root), "reports");
19092
+ const reportsDir = path32.join(artifactsRoot(ctx.root), "reports");
19030
19093
  const allReports = (listDir(reportsDir) ?? []).filter((n4) => n4.endsWith(".json"));
19031
19094
  const capped = allReports.length > ctx.maxReceipts;
19032
19095
  if (capped) ctx.truncated.value = true;
19033
19096
  const scannedNames = [...allReports].sort().reverse().slice(0, ctx.maxReceipts);
19034
- const parsedReports = scannedNames.map((n4) => readJson(path31.join(reportsDir, n4))).filter((r2) => r2.ok).map((r2) => r2.value);
19097
+ const parsedReports = scannedNames.map((n4) => readJson(path32.join(reportsDir, n4))).filter((r2) => r2.ok).map((r2) => r2.value);
19035
19098
  checks.push(
19036
19099
  mkCheck(
19037
19100
  ctx.now,
19038
- !existsSync21(reportsDir) ? {
19101
+ !existsSync22(reportsDir) ? {
19039
19102
  id: "operations.receipts.recent",
19040
19103
  domain: "operations",
19041
19104
  result: "skip",
@@ -19071,7 +19134,7 @@ function operationsChecks(ctx) {
19071
19134
  if (entry2.status === "error") failures.set(name, (failures.get(name) ?? 0) + 1);
19072
19135
  }
19073
19136
  const recurring = [...failures.entries()].filter(([, n4]) => n4 >= 2);
19074
- const scannedAnything = existsSync21(reportsDir) || ctx.state !== null;
19137
+ const scannedAnything = existsSync22(reportsDir) || ctx.state !== null;
19075
19138
  if (!scannedAnything) {
19076
19139
  checks.push(
19077
19140
  mkCheck(ctx.now, {
@@ -19107,7 +19170,7 @@ function operationsChecks(ctx) {
19107
19170
  );
19108
19171
  const recFiles = boundEntries(ctx, allRecFiles).shown;
19109
19172
  const recEvidence = recFiles.map((f) => {
19110
- const parsed = readJson(path31.join(artifactsRoot(ctx.root), f));
19173
+ const parsed = readJson(path32.join(artifactsRoot(ctx.root), f));
19111
19174
  return `recovery file: ${f}${parsed.ok ? "" : " (ileg\xEDvel)"}`;
19112
19175
  });
19113
19176
  checks.push(
@@ -19287,7 +19350,7 @@ function defaultCatalog(root) {
19287
19350
  }
19288
19351
  async function runDoctor2(root, opts = {}) {
19289
19352
  const now = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
19290
- const resolved = path32.resolve(root);
19353
+ const resolved = path33.resolve(root);
19291
19354
  const ctx = {
19292
19355
  root: resolved,
19293
19356
  home: opts.home ?? os4.homedir(),
@@ -19347,9 +19410,9 @@ async function runDoctor2(root, opts = {}) {
19347
19410
  }
19348
19411
 
19349
19412
  // src/heal/fixes.ts
19350
- import { existsSync as existsSync22, mkdirSync as mkdirSync7, readdirSync as readdirSync11, readFileSync as readFileSync19, statSync as statSync5 } from "fs";
19351
- import path33 from "path";
19352
- var rel = (root, abs) => path33.relative(root, abs) || ".";
19413
+ import { existsSync as existsSync23, mkdirSync as mkdirSync8, readdirSync as readdirSync11, readFileSync as readFileSync19, statSync as statSync5 } from "fs";
19414
+ import path34 from "path";
19415
+ var rel = (root, abs) => path34.relative(root, abs) || ".";
19353
19416
  function stampOf(iso) {
19354
19417
  const m3 = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})/.exec(iso);
19355
19418
  return m3 ? `${m3[1]}${m3[2]}${m3[3]}-${m3[4]}${m3[5]}${m3[6]}` : iso.replace(/[^\d]/g, "").slice(0, 14);
@@ -19364,9 +19427,9 @@ var forgeDirRepair = {
19364
19427
  plan(ctx) {
19365
19428
  const base = artifactsRoot(ctx.root);
19366
19429
  return ["", ...FORGE_DIR_SUBDIRS].map((sub) => {
19367
- const dir = sub ? path33.join(base, sub) : base;
19430
+ const dir = sub ? path34.join(base, sub) : base;
19368
19431
  return {
19369
- description: `create directory ${rel(ctx.root, dir)}${existsSync22(dir) ? " (already present)" : ""}`,
19432
+ description: `create directory ${rel(ctx.root, dir)}${existsSync23(dir) ? " (already present)" : ""}`,
19370
19433
  touches: [rel(ctx.root, dir)]
19371
19434
  };
19372
19435
  });
@@ -19376,9 +19439,9 @@ var forgeDirRepair = {
19376
19439
  const base = artifactsRoot(ctx.root);
19377
19440
  const created = [];
19378
19441
  for (const sub of ["", ...FORGE_DIR_SUBDIRS]) {
19379
- const dir = sub ? path33.join(base, sub) : base;
19380
- if (existsSync22(dir)) continue;
19381
- mkdirSync7(dir, { recursive: true });
19442
+ const dir = sub ? path34.join(base, sub) : base;
19443
+ if (existsSync23(dir)) continue;
19444
+ mkdirSync8(dir, { recursive: true });
19382
19445
  created.push(rel(ctx.root, dir));
19383
19446
  }
19384
19447
  return created.length ? `created ${created.length} directorie(s): ${created.join(", ")}` : "all directories already present";
@@ -19386,7 +19449,7 @@ var forgeDirRepair = {
19386
19449
  async verify(ctx) {
19387
19450
  const base = artifactsRoot(ctx.root);
19388
19451
  return ["", ...FORGE_DIR_SUBDIRS].every((sub) => {
19389
- const dir = sub ? path33.join(base, sub) : base;
19452
+ const dir = sub ? path34.join(base, sub) : base;
19390
19453
  try {
19391
19454
  return statSync5(dir).isDirectory();
19392
19455
  } catch {
@@ -19397,11 +19460,11 @@ var forgeDirRepair = {
19397
19460
  };
19398
19461
  var EVIDENCE_KEY_RE = /^[A-Z_][A-Z0-9_]*$/;
19399
19462
  function envPathOf(root) {
19400
- return path33.join(root, ".env");
19463
+ return path34.join(root, ".env");
19401
19464
  }
19402
19465
  function presentKeys(root) {
19403
19466
  const file = envPathOf(root);
19404
- if (!existsSync22(file)) return /* @__PURE__ */ new Set();
19467
+ if (!existsSync23(file)) return /* @__PURE__ */ new Set();
19405
19468
  return new Set(parseEnv(readFileSync19(file, "utf8")).entries.map((e) => e.key));
19406
19469
  }
19407
19470
  function missingEnvKeys(root, check) {
@@ -19422,9 +19485,9 @@ function keysToAppend(root, check) {
19422
19485
  }
19423
19486
  function backupEnvFile(ctx, current) {
19424
19487
  const stamp = stampOf(ctx.now?.() ?? (/* @__PURE__ */ new Date()).toISOString());
19425
- const dir = path33.join(artifactsRoot(ctx.root), "backups", `env-${stamp}`);
19426
- mkdirSync7(dir, { recursive: true });
19427
- writeFileAtomic(path33.join(dir, ".env"), current);
19488
+ const dir = path34.join(artifactsRoot(ctx.root), "backups", `env-${stamp}`);
19489
+ mkdirSync8(dir, { recursive: true });
19490
+ writeFileAtomic(path34.join(dir, ".env"), current);
19428
19491
  return dir;
19429
19492
  }
19430
19493
  var envMissingKeyRepair = {
@@ -19437,9 +19500,9 @@ var envMissingKeyRepair = {
19437
19500
  const root = ctx.root;
19438
19501
  const toAppend = keysToAppend(root, ctx.check);
19439
19502
  const steps = [];
19440
- if (existsSync22(envPathOf(root))) {
19503
+ if (existsSync23(envPathOf(root))) {
19441
19504
  steps.push({
19442
- description: `backup .env to ${rel(root, path33.join(artifactsRoot(root), "backups"))}/env-<ts>/.env`,
19505
+ description: `backup .env to ${rel(root, path34.join(artifactsRoot(root), "backups"))}/env-<ts>/.env`,
19443
19506
  touches: [".env", `${rel(root, artifactsRoot(root))}/backups/`]
19444
19507
  });
19445
19508
  }
@@ -19456,7 +19519,7 @@ var envMissingKeyRepair = {
19456
19519
  const root = ctx.root;
19457
19520
  if (ctx.dryRun) return "dry-run \u2014 not applied";
19458
19521
  const file = envPathOf(root);
19459
- const exists = existsSync22(file);
19522
+ const exists = existsSync23(file);
19460
19523
  const current = exists ? readFileSync19(file, "utf8") : "";
19461
19524
  const env = parseEnv(current);
19462
19525
  const present = new Set(env.entries.map((e) => e.key));
@@ -19474,7 +19537,7 @@ var envMissingKeyRepair = {
19474
19537
  },
19475
19538
  async verify(ctx) {
19476
19539
  const file = envPathOf(ctx.root);
19477
- if (!existsSync22(file)) return false;
19540
+ if (!existsSync23(file)) return false;
19478
19541
  const present = new Set(parseEnv(readFileSync19(file, "utf8")).entries.map((e) => e.key));
19479
19542
  return missingEnvKeys(ctx.root, ctx.check).every((k) => present.has(k));
19480
19543
  }
@@ -19491,7 +19554,7 @@ var lockfileDriftRepair = {
19491
19554
  return [
19492
19555
  {
19493
19556
  description: `run \`${LOCKFILE_REGEN_COMMAND}\` to regenerate .forge-cli/env.lock.json`,
19494
- touches: [path33.join(".forge-cli", "env.lock.json")]
19557
+ touches: [path34.join(".forge-cli", "env.lock.json")]
19495
19558
  },
19496
19559
  {
19497
19560
  description: `run \`${LOCKFILE_CHECK_COMMAND}\` to confirm the drift cleared`,
@@ -19511,12 +19574,12 @@ var lockfileDriftRepair = {
19511
19574
  var ENV_BACKUP_RE = /^env-\d{8}-\d{6}$/;
19512
19575
  var REPO_BACKUP_RE = /^([a-z0-9][a-z0-9._-]*)-\d{10,}$/i;
19513
19576
  function listBackups(root) {
19514
- const base = path33.join(artifactsRoot(root), "backups");
19515
- if (!existsSync22(base)) return [];
19577
+ const base = path34.join(artifactsRoot(root), "backups");
19578
+ if (!existsSync23(base)) return [];
19516
19579
  const out = [];
19517
19580
  for (const entry2 of readdirSync11(base, { withFileTypes: true })) {
19518
19581
  if (!entry2.isDirectory()) continue;
19519
- const dir = path33.join(base, entry2.name);
19582
+ const dir = path34.join(base, entry2.name);
19520
19583
  try {
19521
19584
  const files = readdirSync11(dir, { withFileTypes: true }).filter((f) => f.isFile()).map((f) => f.name).sort();
19522
19585
  if (!files.length) continue;
@@ -19534,18 +19597,18 @@ function restoreTargetFor(backupDirName, fileName) {
19534
19597
  return fileName;
19535
19598
  }
19536
19599
  function pickBackupFile(ctx) {
19537
- const backupsBase = path33.join(artifactsRoot(ctx.root), "backups");
19600
+ const backupsBase = path34.join(artifactsRoot(ctx.root), "backups");
19538
19601
  if (ctx.backup) {
19539
- const abs = path33.resolve(ctx.root, ctx.backup);
19540
- const inside = path33.relative(backupsBase, abs);
19541
- if (inside.startsWith("..") || path33.isAbsolute(inside)) {
19602
+ const abs = path34.resolve(ctx.root, ctx.backup);
19603
+ const inside = path34.relative(backupsBase, abs);
19604
+ if (inside.startsWith("..") || path34.isAbsolute(inside)) {
19542
19605
  throw new Error(`selected backup escapes .forge-cli/backups: ${ctx.backup}`);
19543
19606
  }
19544
- if (!existsSync22(abs) || !statSync5(abs).isFile()) {
19607
+ if (!existsSync23(abs) || !statSync5(abs).isFile()) {
19545
19608
  throw new Error(`selected backup not found: ${ctx.backup}`);
19546
19609
  }
19547
- const dirName = inside.split(path33.sep)[0] ?? "";
19548
- const fileName2 = path33.basename(abs);
19610
+ const dirName = inside.split(path34.sep)[0] ?? "";
19611
+ const fileName2 = path34.basename(abs);
19549
19612
  return { src: abs, rel: inside, dest: restoreTargetFor(dirName, fileName2) };
19550
19613
  }
19551
19614
  const candidates = listBackups(ctx.root);
@@ -19554,7 +19617,7 @@ function pickBackupFile(ctx) {
19554
19617
  if (!cand) throw new Error("no backups available under .forge-cli/backups");
19555
19618
  const fileName = cand.files.includes(".env") ? ".env" : cand.files[0];
19556
19619
  return {
19557
- src: path33.join(cand.dir, fileName),
19620
+ src: path34.join(cand.dir, fileName),
19558
19621
  rel: `${cand.name}/${fileName}`,
19559
19622
  dest: restoreTargetFor(cand.name, fileName)
19560
19623
  };
@@ -19570,7 +19633,7 @@ var backupRestoreRepair = {
19570
19633
  if (!candidates.length) {
19571
19634
  return [
19572
19635
  {
19573
- description: `no backups found under ${rel(ctx.root, path33.join(artifactsRoot(ctx.root), "backups"))}/`,
19636
+ description: `no backups found under ${rel(ctx.root, path34.join(artifactsRoot(ctx.root), "backups"))}/`,
19574
19637
  touches: []
19575
19638
  }
19576
19639
  ];
@@ -19596,20 +19659,20 @@ var backupRestoreRepair = {
19596
19659
  async apply(ctx) {
19597
19660
  if (ctx.dryRun) return "dry-run \u2014 not applied";
19598
19661
  const picked = pickBackupFile(ctx);
19599
- const dest = path33.resolve(ctx.root, picked.dest);
19600
- const relDest = path33.relative(ctx.root, dest);
19601
- if (relDest.startsWith("..") || path33.isAbsolute(relDest)) {
19662
+ const dest = path34.resolve(ctx.root, picked.dest);
19663
+ const relDest = path34.relative(ctx.root, dest);
19664
+ if (relDest.startsWith("..") || path34.isAbsolute(relDest)) {
19602
19665
  throw new Error(`restore target escapes root: ${picked.dest}`);
19603
19666
  }
19604
- mkdirSync7(path33.dirname(dest), { recursive: true });
19667
+ mkdirSync8(path34.dirname(dest), { recursive: true });
19605
19668
  writeFileAtomic(dest, readFileSync19(picked.src, "utf8"));
19606
19669
  return `restored ${picked.rel} \u2192 ${relDest}`;
19607
19670
  },
19608
19671
  async verify(ctx) {
19609
19672
  try {
19610
19673
  const picked = pickBackupFile(ctx);
19611
- const dest = path33.resolve(ctx.root, picked.dest);
19612
- return existsSync22(dest) && readFileSync19(dest, "utf8") === readFileSync19(picked.src, "utf8");
19674
+ const dest = path34.resolve(ctx.root, picked.dest);
19675
+ return existsSync23(dest) && readFileSync19(dest, "utf8") === readFileSync19(picked.src, "utf8");
19613
19676
  } catch {
19614
19677
  return false;
19615
19678
  }
@@ -19639,11 +19702,11 @@ function classifyFindings(checks) {
19639
19702
  }
19640
19703
 
19641
19704
  // src/heal/flow.ts
19642
- import { mkdirSync as mkdirSync8 } from "fs";
19643
- import path34 from "path";
19705
+ import { mkdirSync as mkdirSync9 } from "fs";
19706
+ import path35 from "path";
19644
19707
  function healReceiptPath(root, generatedAt) {
19645
19708
  const stamp = generatedAt.replace(/[:.]/g, "-");
19646
- return path34.join(artifactsRoot(root), "receipts", `heal-${stamp}.json`);
19709
+ return path35.join(artifactsRoot(root), "receipts", `heal-${stamp}.json`);
19647
19710
  }
19648
19711
  async function planRepairs(checks, opts) {
19649
19712
  const classified = classifyFindings(checks);
@@ -19778,7 +19841,7 @@ async function runHealFlow(checks, opts) {
19778
19841
  };
19779
19842
  if (!dryRun) {
19780
19843
  const file = healReceiptPath(opts.root, generatedAt);
19781
- mkdirSync8(path34.dirname(file), { recursive: true });
19844
+ mkdirSync9(path35.dirname(file), { recursive: true });
19782
19845
  writeFileAtomic(file, redactSecrets(JSON.stringify(receipt, null, 2)));
19783
19846
  }
19784
19847
  return receipt;
@@ -19863,8 +19926,8 @@ async function runDoctor2Command(cli) {
19863
19926
  }
19864
19927
 
19865
19928
  // src/cmd/registry.ts
19866
- import path35 from "path";
19867
- import { existsSync as existsSync23, mkdirSync as mkdirSync9 } from "fs";
19929
+ import path36 from "path";
19930
+ import { existsSync as existsSync24, mkdirSync as mkdirSync10 } from "fs";
19868
19931
 
19869
19932
  // src/registry/catalog.ts
19870
19933
  var REGISTRY_PACKAGES = [
@@ -19998,7 +20061,7 @@ function describeInstallError(e) {
19998
20061
  return `${e.stage}: ${e.detail}`;
19999
20062
  }
20000
20063
  function registryCacheDir(home = cliHome()) {
20001
- return path35.join(home, ".forge-cli", "cache", "pypi");
20064
+ return path36.join(home, ".forge-cli", "cache", "pypi");
20002
20065
  }
20003
20066
  var REGISTRY_IGNORED_FLAGS = [
20004
20067
  ["dir", "--dir"],
@@ -20092,8 +20155,8 @@ async function persistReceipt(home, receipt) {
20092
20155
  }
20093
20156
  }
20094
20157
  function writeRegistryReport(reportPath, doc) {
20095
- const file = path35.resolve(reportPath);
20096
- mkdirSync9(path35.dirname(file), { recursive: true });
20158
+ const file = path36.resolve(reportPath);
20159
+ mkdirSync10(path36.dirname(file), { recursive: true });
20097
20160
  writeFileAtomic(file, redactSecrets(JSON.stringify(doc, null, 2)));
20098
20161
  }
20099
20162
  async function runRegistryInstall(cli, names, deps = {}) {
@@ -20272,7 +20335,7 @@ async function runRegistryInstall(cli, names, deps = {}) {
20272
20335
  const doc = { method: "pypi", results, warnings };
20273
20336
  reportTo(doc);
20274
20337
  if (cli.reportPath !== void 0) {
20275
- log.info(`${S.reportSaved}: ${theme.dim(path35.resolve(cli.reportPath))}`);
20338
+ log.info(`${S.reportSaved}: ${theme.dim(path36.resolve(cli.reportPath))}`);
20276
20339
  }
20277
20340
  if (quiet) {
20278
20341
  emitJson(doc, results.every((r2) => r2.ok) ? 0 : 1);
@@ -20283,9 +20346,13 @@ async function runRegistryInstall(cli, names, deps = {}) {
20283
20346
  if (results.some((r2) => !r2.ok)) process.exit(1);
20284
20347
  const bins = results.map((r2) => {
20285
20348
  const inst = loadForgeState(home).forges[r2.forge];
20286
- return inst ? `${r2.forge} \u2192 ${inst.bin}` : "";
20349
+ if (!inst) return "";
20350
+ return inst.shim ? `${r2.forge} \u2192 ${path36.basename(inst.shim)} (em ${path36.dirname(inst.shim)})` : `${r2.forge} \u2192 ${inst.bin}`;
20287
20351
  });
20288
- note(bins.filter(Boolean).join("\n"), "Para usar, adicione ao PATH ou invoque o caminho");
20352
+ note(
20353
+ bins.filter(Boolean).join("\n"),
20354
+ "Launchers em ~/.forge-cli/bin (no PATH do forge-cli); sem shim, invoque o caminho da venv"
20355
+ );
20289
20356
  outro(`${icons.ok} instala\xE7\xE3o registry-first conclu\xEDda`);
20290
20357
  return results;
20291
20358
  }
@@ -20347,7 +20414,7 @@ async function runRegistryLock(cli, names, deps = {}) {
20347
20414
  results.push({ forge: e.name, ok: false, detail: describeResolveError(picked.error) });
20348
20415
  continue;
20349
20416
  }
20350
- const out = cli.out ? entries.length === 1 ? path35.resolve(cli.out) : path35.join(path35.resolve(cli.out), `${e.name}.offline-lock.json`) : path35.resolve(`${e.name}.offline-lock.json`);
20417
+ const out = cli.out ? entries.length === 1 ? path36.resolve(cli.out) : path36.join(path36.resolve(cli.out), `${e.name}.offline-lock.json`) : path36.resolve(`${e.name}.offline-lock.json`);
20351
20418
  if (isPlan) {
20352
20419
  results.push({
20353
20420
  forge: e.name,
@@ -20366,7 +20433,7 @@ async function runRegistryLock(cli, names, deps = {}) {
20366
20433
  results.push({ forge: e.name, ok: false, detail: `${lock.kind}: ${lock.detail}` });
20367
20434
  continue;
20368
20435
  }
20369
- mkdirSync9(path35.dirname(out), { recursive: true });
20436
+ mkdirSync10(path36.dirname(out), { recursive: true });
20370
20437
  writeFileAtomic(out, `${JSON.stringify(lock, null, 2)}
20371
20438
  `);
20372
20439
  locks.push({ forge: e.name, lock, file: out });
@@ -20407,7 +20474,7 @@ function runRegistryList(cli, deps = {}) {
20407
20474
  }
20408
20475
  const rows = REGISTRY_PACKAGES.filter((e) => !wanted || wanted.has(e.name)).map((e) => {
20409
20476
  const inst = state.forges[e.name];
20410
- const binOk = inst ? typeof inst.bin === "string" && existsSync23(inst.bin) : null;
20477
+ const binOk = inst ? typeof inst.bin === "string" && existsSync24(inst.bin) : null;
20411
20478
  const consistency = installConsistency(home, e.name);
20412
20479
  const relevant = consistency.status !== "not-installed";
20413
20480
  return {
@@ -21132,24 +21199,24 @@ async function runRegistryPin(cli, names, pin, deps = {}) {
21132
21199
  }
21133
21200
 
21134
21201
  // src/lifecycle.ts
21135
- import { copyFileSync as copyFileSync3, existsSync as existsSync24, mkdirSync as mkdirSync10, readdirSync as readdirSync12, rmSync as rmSync6 } from "fs";
21136
- import path36 from "path";
21202
+ import { copyFileSync as copyFileSync3, existsSync as existsSync25, mkdirSync as mkdirSync11, readdirSync as readdirSync12, rmSync as rmSync7 } from "fs";
21203
+ import path37 from "path";
21137
21204
  function configFilesToBackup(repoDir) {
21138
21205
  const out = /* @__PURE__ */ new Set();
21139
- if (existsSync24(path36.join(repoDir, ".env"))) out.add(".env");
21206
+ if (existsSync25(path37.join(repoDir, ".env"))) out.add(".env");
21140
21207
  for (const file of readdirSync12(repoDir)) {
21141
21208
  if (file === ".env.example" || !file.includes(".example.")) continue;
21142
21209
  const real = file.replace(".example.", ".");
21143
- if (existsSync24(path36.join(repoDir, real))) out.add(real);
21210
+ if (existsSync25(path37.join(repoDir, real))) out.add(real);
21144
21211
  }
21145
21212
  return [...out];
21146
21213
  }
21147
21214
  async function planUninstall(targetDir, repo) {
21148
21215
  const dir = resolveInside(targetDir, repo.name);
21149
21216
  if (!dir)
21150
- return { kind: "refused", dir: path36.join(targetDir, repo.name), reason: "invalid-name" };
21217
+ return { kind: "refused", dir: path37.join(targetDir, repo.name), reason: "invalid-name" };
21151
21218
  if (isLinkOrJunction(dir)) return { kind: "refused", dir, reason: "symlink" };
21152
- if (!existsSync24(dir)) return { kind: "absent", dir };
21219
+ if (!existsSync25(dir)) return { kind: "absent", dir };
21153
21220
  if (!hasGitRepo(dir)) return { kind: "refused", dir, reason: "non-git" };
21154
21221
  const remote = await commandOutput("git", ["-C", dir, "remote", "get-url", "origin"]);
21155
21222
  if (remote && remote !== "ok" && !sameRemote(remote, repo.url)) {
@@ -21163,14 +21230,14 @@ function executeUninstall(targetDir, repo, plan) {
21163
21230
  if (!expected || expected !== plan.dir) throw new Error("plano de remo\xE7\xE3o inconsistente");
21164
21231
  let backupDir = null;
21165
21232
  if (plan.backups.length) {
21166
- backupDir = path36.join(artifactsRoot(targetDir), "backups", `${repo.name}-${Date.now()}`);
21233
+ backupDir = path37.join(artifactsRoot(targetDir), "backups", `${repo.name}-${Date.now()}`);
21167
21234
  for (const file of plan.backups) {
21168
- const dest = path36.join(backupDir, file);
21169
- mkdirSync10(path36.dirname(dest), { recursive: true });
21170
- copyFileSync3(path36.join(plan.dir, file), dest);
21235
+ const dest = path37.join(backupDir, file);
21236
+ mkdirSync11(path37.dirname(dest), { recursive: true });
21237
+ copyFileSync3(path37.join(plan.dir, file), dest);
21171
21238
  }
21172
21239
  }
21173
- rmSync6(plan.dir, { recursive: true, force: true });
21240
+ rmSync7(plan.dir, { recursive: true, force: true });
21174
21241
  forgetRepo(targetDir, repo.name);
21175
21242
  return backupDir;
21176
21243
  }
@@ -21199,13 +21266,13 @@ async function rollbackRepo(targetDir, repo) {
21199
21266
  }
21200
21267
 
21201
21268
  // src/self.ts
21202
- import path37 from "path";
21269
+ import path38 from "path";
21203
21270
  function norm(p) {
21204
- return path37.resolve(p).replace(/\\/g, "/").toLowerCase();
21271
+ return path38.resolve(p).replace(/\\/g, "/").toLowerCase();
21205
21272
  }
21206
21273
  function detectInstallMethod(scriptPath, home) {
21207
21274
  const script = norm(scriptPath);
21208
- if (script.startsWith(`${norm(path37.join(home, ".forge-cli", "bin"))}/`)) return "shim";
21275
+ if (script.startsWith(`${norm(path38.join(home, ".forge-cli", "bin"))}/`)) return "shim";
21209
21276
  if (script.includes("/node_modules/")) return "npm-global";
21210
21277
  return "source";
21211
21278
  }
@@ -21500,11 +21567,11 @@ async function runUninstallCommand(cli) {
21500
21567
  }
21501
21568
 
21502
21569
  // src/config.ts
21503
- import { existsSync as existsSync25, readFileSync as readFileSync20 } from "fs";
21504
- import path38 from "path";
21570
+ import { existsSync as existsSync26, readFileSync as readFileSync20 } from "fs";
21571
+ import path39 from "path";
21505
21572
  function loadConfig(targetDir) {
21506
- const file = path38.join(targetDir, "forge-cli.config.json");
21507
- if (!existsSync25(file)) return null;
21573
+ const file = path39.join(targetDir, "forge-cli.config.json");
21574
+ if (!existsSync26(file)) return null;
21508
21575
  let parsed;
21509
21576
  try {
21510
21577
  parsed = JSON.parse(readFileSync20(file, "utf8"));
@@ -21550,12 +21617,12 @@ function loadConfig(targetDir) {
21550
21617
  }
21551
21618
 
21552
21619
  // src/plan.ts
21553
- import { existsSync as existsSync26, readdirSync as readdirSync13 } from "fs";
21554
- import path39 from "path";
21620
+ import { existsSync as existsSync27, readdirSync as readdirSync13 } from "fs";
21621
+ import path40 from "path";
21555
21622
  function planLines(repo, targetDir) {
21556
- const repoDir = path39.join(targetDir, repo.name);
21623
+ const repoDir = path40.join(targetDir, repo.name);
21557
21624
  const lines = [];
21558
- if (!existsSync26(repoDir)) {
21625
+ if (!existsSync27(repoDir)) {
21559
21626
  lines.push(`${S.planSync}: git clone (${S.planDetectAfter})`);
21560
21627
  for (const step of [
21561
21628
  S.phaseEnv,
@@ -21594,11 +21661,11 @@ function planLines(repo, targetDir) {
21594
21661
  return lines;
21595
21662
  }
21596
21663
  async function executionSummary(repo, targetDir, native, platform2 = process.platform) {
21597
- const repoDir = path39.join(targetDir, repo.name);
21664
+ const repoDir = path40.join(targetDir, repo.name);
21598
21665
  const trust = repo.origin === "custom" ? "custom" : "builtin";
21599
21666
  const commands = [];
21600
21667
  let revision;
21601
- if (!existsSync26(repoDir) || !hasGitRepo(repoDir)) {
21668
+ if (!existsSync27(repoDir) || !hasGitRepo(repoDir)) {
21602
21669
  commands.push(`git clone -- ${repo.url}`, S.planScriptsAfterClone);
21603
21670
  } else {
21604
21671
  revision = (await currentHead(repoDir))?.slice(0, 7);
@@ -21833,8 +21900,8 @@ ${planLines(repo, targetDir).map((line) => ` ${theme.dim(line)}`).join("\n")}`
21833
21900
  }
21834
21901
 
21835
21902
  // src/cmd/env.ts
21836
- import { copyFileSync as copyFileSync4, existsSync as existsSync28, readFileSync as readFileSync22, readdirSync as readdirSync15 } from "fs";
21837
- import path41 from "path";
21903
+ import { copyFileSync as copyFileSync4, existsSync as existsSync29, readFileSync as readFileSync22, readdirSync as readdirSync15 } from "fs";
21904
+ import path42 from "path";
21838
21905
 
21839
21906
  // src/envintel/doctor.ts
21840
21907
  function envDoctor(repoDir, envKeys) {
@@ -21883,8 +21950,8 @@ function envDoctor(repoDir, envKeys) {
21883
21950
 
21884
21951
  // src/envintel/migrate.ts
21885
21952
  import { randomBytes } from "crypto";
21886
- import { existsSync as existsSync27, mkdirSync as mkdirSync11, readdirSync as readdirSync14, readFileSync as readFileSync21 } from "fs";
21887
- import path40 from "path";
21953
+ import { existsSync as existsSync28, mkdirSync as mkdirSync12, readdirSync as readdirSync14, readFileSync as readFileSync21 } from "fs";
21954
+ import path41 from "path";
21888
21955
  function timestamp2(d = /* @__PURE__ */ new Date()) {
21889
21956
  const p = (n4) => String(n4).padStart(2, "0");
21890
21957
  return `${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}-${p(d.getHours())}${p(d.getMinutes())}${p(d.getSeconds())}`;
@@ -21898,12 +21965,12 @@ function addValue(spec, exampleEmpty) {
21898
21965
  }
21899
21966
  function planMigration(repoDir, targetSchema) {
21900
21967
  const schema = targetSchema ?? deriveSchema(repoDir);
21901
- const envPath = path40.join(repoDir, ".env");
21902
- const env = existsSync27(envPath) ? parseEnv(readFileSync21(envPath, "utf8")) : null;
21968
+ const envPath = path41.join(repoDir, ".env");
21969
+ const env = existsSync28(envPath) ? parseEnv(readFileSync21(envPath, "utf8")) : null;
21903
21970
  const present = new Set(env?.entries.map((e) => e.key) ?? []);
21904
- const examplePath = path40.join(repoDir, ".env.example");
21971
+ const examplePath = path41.join(repoDir, ".env.example");
21905
21972
  const exampleEmpty = /* @__PURE__ */ new Set();
21906
- if (existsSync27(examplePath)) {
21973
+ if (existsSync28(examplePath)) {
21907
21974
  for (const e of parseEnv(readFileSync21(examplePath, "utf8")).entries) {
21908
21975
  if (e.value === "") exampleEmpty.add(e.key);
21909
21976
  }
@@ -21932,18 +21999,18 @@ function planMigration(repoDir, targetSchema) {
21932
21999
  return { actions, removesRequireApproval: true };
21933
22000
  }
21934
22001
  function backupDirFor2(repoDir, ts) {
21935
- return path40.join(artifactsRoot(repoDir), "backups", `env-${ts}`);
22002
+ return path41.join(artifactsRoot(repoDir), "backups", `env-${ts}`);
21936
22003
  }
21937
22004
  function backupEnv(repoDir, content) {
21938
22005
  const dir = backupDirFor2(repoDir, timestamp2());
21939
- mkdirSync11(dir, { recursive: true });
21940
- const file = path40.join(dir, ".env");
22006
+ mkdirSync12(dir, { recursive: true });
22007
+ const file = path41.join(dir, ".env");
21941
22008
  writeFileAtomic(file, content);
21942
22009
  return dir;
21943
22010
  }
21944
22011
  function applyMigration(repoDir, plan, opts = {}) {
21945
- const envPath = path40.join(repoDir, ".env");
21946
- const exists = existsSync27(envPath);
22012
+ const envPath = path41.join(repoDir, ".env");
22013
+ const exists = existsSync28(envPath);
21947
22014
  const current = exists ? readFileSync21(envPath, "utf8") : "";
21948
22015
  const env = parseEnv(current);
21949
22016
  const present = new Set(env.entries.map((e) => e.key));
@@ -21974,16 +22041,16 @@ function applyMigration(repoDir, plan, opts = {}) {
21974
22041
  };
21975
22042
  }
21976
22043
  function latestEnvBackup(repoDir) {
21977
- const root = path40.join(artifactsRoot(repoDir), "backups");
21978
- if (!existsSync27(root)) return null;
22044
+ const root = path41.join(artifactsRoot(repoDir), "backups");
22045
+ if (!existsSync28(root)) return null;
21979
22046
  const candidates = readdirSync14(root, { withFileTypes: true }).filter((d) => d.isDirectory() && /^env-\d{8}-\d{6}$/.test(d.name)).map((d) => d.name).sort();
21980
22047
  const last = candidates.at(-1);
21981
- return last ? path40.join(root, last) : null;
22048
+ return last ? path41.join(root, last) : null;
21982
22049
  }
21983
22050
  function rollbackEnv(repoDir, backupDir) {
21984
- const src = path40.join(backupDir, ".env");
21985
- if (!existsSync27(src)) return false;
21986
- writeFileAtomic(path40.join(repoDir, ".env"), readFileSync21(src, "utf8"));
22051
+ const src = path41.join(backupDir, ".env");
22052
+ if (!existsSync28(src)) return false;
22053
+ writeFileAtomic(path41.join(repoDir, ".env"), readFileSync21(src, "utf8"));
21987
22054
  return true;
21988
22055
  }
21989
22056
 
@@ -21993,7 +22060,7 @@ function envCandidates(dir) {
21993
22060
  try {
21994
22061
  return readdirSync15(dir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).filter((name) => {
21995
22062
  const r2 = resolveInside(dir, name);
21996
- return r2 !== null && (existsSync28(path41.join(r2, ".env")) || existsSync28(path41.join(r2, ".env.example")));
22063
+ return r2 !== null && (existsSync29(path42.join(r2, ".env")) || existsSync29(path42.join(r2, ".env.example")));
21997
22064
  }).sort();
21998
22065
  } catch {
21999
22066
  return [];
@@ -22040,7 +22107,7 @@ async function runEnvCommand(cli, args) {
22040
22107
  envKeys = catalogFor(targetDir).find((r2) => r2.name === name)?.envKeys;
22041
22108
  } else {
22042
22109
  const cwd = process.cwd();
22043
- if (existsSync28(path41.join(cwd, ".env")) || existsSync28(path41.join(cwd, ".env.example"))) {
22110
+ if (existsSync29(path42.join(cwd, ".env")) || existsSync29(path42.join(cwd, ".env.example"))) {
22044
22111
  repoDir = cwd;
22045
22112
  }
22046
22113
  }
@@ -22050,7 +22117,7 @@ async function runEnvCommand(cli, args) {
22050
22117
  if (found.length) note(found.join("\n"), S.envTitle);
22051
22118
  return 2;
22052
22119
  }
22053
- const repo = name ?? path41.basename(repoDir);
22120
+ const repo = name ?? path42.basename(repoDir);
22054
22121
  if (verb === "inspect") {
22055
22122
  const res2 = inspectEnv(repoDir, envKeys);
22056
22123
  if (json) {
@@ -22092,13 +22159,13 @@ async function runEnvCommand(cli, args) {
22092
22159
  note(lines.join("\n"), `${S.envDoctorTitle} \u2014 ${repo}`);
22093
22160
  return res2.checks.some((c5) => c5.result === "fail") ? 1 : 0;
22094
22161
  }
22095
- if (!existsSync28(repoDir)) {
22162
+ if (!existsSync29(repoDir)) {
22096
22163
  log.error(`${repo}: ${S.statusNotInstalled}`);
22097
22164
  return 2;
22098
22165
  }
22099
22166
  const schema = deriveSchema(repoDir, envKeys);
22100
22167
  const secretKeys = new Set(schema.vars.filter((v) => v.secret).map((v) => v.key));
22101
- const envPath = path41.join(repoDir, ".env");
22168
+ const envPath = path42.join(repoDir, ".env");
22102
22169
  if (verb === "wizard") {
22103
22170
  if (dryRun) {
22104
22171
  log.error(S.errPlanUnsupported);
@@ -22108,7 +22175,7 @@ async function runEnvCommand(cli, args) {
22108
22175
  log.error(S.envWizardNonInteractive);
22109
22176
  return 2;
22110
22177
  }
22111
- const env = parseEnv(existsSync28(envPath) ? readFileSync22(envPath, "utf8") : "");
22178
+ const env = parseEnv(existsSync29(envPath) ? readFileSync22(envPath, "utf8") : "");
22112
22179
  const current = new Map(env.entries.map((e) => [e.key, e]));
22113
22180
  const updates = /* @__PURE__ */ new Map();
22114
22181
  for (const spec of schema.vars) {
@@ -22151,7 +22218,7 @@ async function runEnvCommand(cli, args) {
22151
22218
  }
22152
22219
  for (const [k, v] of updates) lines.push(formatEntry(k, v));
22153
22220
  const out = serializeEnv({ ...env, lines });
22154
- if (existsSync28(envPath)) copyFileSync4(envPath, `${envPath}.bak`);
22221
+ if (existsSync29(envPath)) copyFileSync4(envPath, `${envPath}.bak`);
22155
22222
  writeFileAtomic(envPath, out.endsWith("\n") ? out : `${out}
22156
22223
  `);
22157
22224
  log.success(`${icons.ok} ${S.envWizardDone} ${theme.dim(`(${envPath}.bak)`)}`);
@@ -22179,7 +22246,7 @@ async function runEnvCommand(cli, args) {
22179
22246
  return 0;
22180
22247
  }
22181
22248
  if (verb === "init") {
22182
- if (existsSync28(envPath)) {
22249
+ if (existsSync29(envPath)) {
22183
22250
  if (json) console.log(JSON.stringify({ command: "env init", repo, created: false }));
22184
22251
  else log.info(S.envInitExists);
22185
22252
  return 0;
@@ -22293,13 +22360,13 @@ async function runEnvCommand(cli, args) {
22293
22360
  }
22294
22361
 
22295
22362
  // src/cmd/hosts.ts
22296
- import path43 from "path";
22297
- import { existsSync as existsSync30, readdirSync as readdirSync16 } from "fs";
22363
+ import path44 from "path";
22364
+ import { existsSync as existsSync31, readdirSync as readdirSync16 } from "fs";
22298
22365
 
22299
22366
  // src/mcp/handshake.ts
22300
22367
  import { spawn as spawn2 } from "child_process";
22301
- import { existsSync as existsSync29 } from "fs";
22302
- import path42 from "path";
22368
+ import { existsSync as existsSync30 } from "fs";
22369
+ import path43 from "path";
22303
22370
  import { createInterface as createInterface2 } from "readline";
22304
22371
  var PROTOCOL_VERSION = "2024-11-05";
22305
22372
  var STEP_MS = 8e3;
@@ -22388,8 +22455,8 @@ function probeMcpServer(argv, opts = {}) {
22388
22455
  }
22389
22456
  const stepMs = opts.timeoutMs ?? STEP_MS;
22390
22457
  const levels = [];
22391
- if (path42.isAbsolute(argv[0])) {
22392
- if (!existsSync29(argv[0])) {
22458
+ if (path43.isAbsolute(argv[0])) {
22459
+ if (!existsSync30(argv[0])) {
22393
22460
  resolve(err("bin-missing", `bin\xE1rio MCP ausente: ${argv[0]}`));
22394
22461
  return;
22395
22462
  }
@@ -22678,12 +22745,12 @@ function forgeDescriptor(targetDir, name, home = cliHome()) {
22678
22745
  const receipt = loadForgeState(home).forges[name];
22679
22746
  const entry2 = registryEntry(name);
22680
22747
  if (receipt?.bin && entry2?.mcp?.length) {
22681
- const binDir = path43.dirname(receipt.bin);
22748
+ const binDir = path44.dirname(receipt.bin);
22682
22749
  const mcp_command = entry2.mcp.map((tok) => {
22683
22750
  if (tok === "{bin}") return receipt.bin;
22684
22751
  if (tok.startsWith("{binDir}/")) {
22685
22752
  const script = tok.slice("{binDir}/".length);
22686
- return path43.join(binDir, process.platform === "win32" ? `${script}.exe` : script);
22753
+ return path44.join(binDir, process.platform === "win32" ? `${script}.exe` : script);
22687
22754
  }
22688
22755
  return tok;
22689
22756
  });
@@ -22818,7 +22885,7 @@ async function runMcpCommand(cli, args, home = cliHome()) {
22818
22885
  const candidates = names.length > 0 ? names : [
22819
22886
  .../* @__PURE__ */ new Set([
22820
22887
  ...Object.keys(loadForgeState(home).forges),
22821
- ...existsSync30(targetDir) ? readdirSync16(targetDir, { withFileTypes: true }).filter((d) => d.isDirectory() && isSafeRepoName(d.name)).map((d) => d.name) : []
22888
+ ...existsSync31(targetDir) ? readdirSync16(targetDir, { withFileTypes: true }).filter((d) => d.isDirectory() && isSafeRepoName(d.name)).map((d) => d.name) : []
22822
22889
  ])
22823
22890
  ].sort();
22824
22891
  if (candidates.length === 0) {
@@ -22839,7 +22906,7 @@ async function runMcpCommand(cli, args, home = cliHome()) {
22839
22906
  results.push({ forge: name, ok: false, detail: "sem mcp_command" });
22840
22907
  continue;
22841
22908
  }
22842
- const binPresent = path43.isAbsolute(argv[0]) ? existsSync30(argv[0]) : true;
22909
+ const binPresent = path44.isAbsolute(argv[0]) ? existsSync31(argv[0]) : true;
22843
22910
  const item = {
22844
22911
  forge: name,
22845
22912
  forge_id: forge.forge_id,
@@ -22848,7 +22915,7 @@ async function runMcpCommand(cli, args, home = cliHome()) {
22848
22915
  ok: binPresent
22849
22916
  };
22850
22917
  if (!binPresent) item.detail = "bin\xE1rio MCP ausente na venv";
22851
- if (verify && binPresent && path43.isAbsolute(argv[0])) {
22918
+ if (verify && binPresent && path44.isAbsolute(argv[0])) {
22852
22919
  const safeTools = registryEntry(name)?.mcp_safe_tools;
22853
22920
  const probe = await probeMcpServer(argv, { safeTools });
22854
22921
  let levels = probe.levels;
@@ -22887,9 +22954,9 @@ async function runMcpCommand(cli, args, home = cliHome()) {
22887
22954
  }
22888
22955
 
22889
22956
  // src/discovery.ts
22890
- import { existsSync as existsSync31, readdirSync as readdirSync17, readFileSync as readFileSync23, statSync as statSync6 } from "fs";
22957
+ import { existsSync as existsSync32, readdirSync as readdirSync17, readFileSync as readFileSync23, statSync as statSync6 } from "fs";
22891
22958
  import os5 from "os";
22892
- import path44 from "path";
22959
+ import path45 from "path";
22893
22960
  var DEFAULT_LIMITS = {
22894
22961
  maxDepth: 3,
22895
22962
  maxEntriesPerDir: 500,
@@ -23054,7 +23121,7 @@ function walkWorkspace(root, limits, budgetLeft) {
23054
23121
  return { markers, envFiles, topDirs, signals: signals2, truncated };
23055
23122
  }
23056
23123
  const lower = entry2.name.toLowerCase();
23057
- const full = path44.join(dir, entry2.name);
23124
+ const full = path45.join(dir, entry2.name);
23058
23125
  const relPath = rel2 ? `${rel2}/${entry2.name}` : entry2.name;
23059
23126
  if (entry2.isDirectory()) {
23060
23127
  if (skip.has(lower) || isLinkOrJunction(full)) continue;
@@ -23177,10 +23244,10 @@ function registryState(entry2) {
23177
23244
  function discoverForge(name, dir, state) {
23178
23245
  const sources = [];
23179
23246
  const git = !!dir && hasGitRepo(dir);
23180
- const manifest = dir && existsSync31(dir) ? readForgeManifest(dir) : null;
23247
+ const manifest = dir && existsSync32(dir) ? readForgeManifest(dir) : null;
23181
23248
  const entry2 = state?.repos[name];
23182
23249
  if (entry2 && entry2.phase !== "not-installed") {
23183
- const dirExists = !!dir && existsSync31(dir);
23250
+ const dirExists = !!dir && existsSync32(dir);
23184
23251
  sources.push({
23185
23252
  origin: "manifest",
23186
23253
  // registro diz instalada mas o checkout sumiu → evidência falhando
@@ -23223,7 +23290,7 @@ async function discoverEnvironment(targetDir, opts) {
23223
23290
  const start = now();
23224
23291
  const limits = { ...DEFAULT_LIMITS, ...opts?.limits };
23225
23292
  const budgetLeft = () => limits.timeoutMs - (now() - start);
23226
- const root = path44.resolve(targetDir);
23293
+ const root = path45.resolve(targetDir);
23227
23294
  const walk = walkWorkspace(root, limits, budgetLeft);
23228
23295
  const tools = await probeTools(process.platform, budgetLeft);
23229
23296
  const hosts = await probeHosts(budgetLeft);
@@ -23240,7 +23307,7 @@ async function discoverEnvironment(targetDir, opts) {
23240
23307
  const dir = resolveInside(root, dirName);
23241
23308
  if (!dir) continue;
23242
23309
  const git = hasGitRepo(dir);
23243
- const manifest = existsSync31(path44.join(dir, "forge.json"));
23310
+ const manifest = existsSync32(path45.join(dir, "forge.json"));
23244
23311
  if (!git && !manifest) continue;
23245
23312
  presence.push({ name: dirName, path: dirName, git, manifest });
23246
23313
  if (!catalogNames.has(dirName) && manifest) {
@@ -23909,8 +23976,8 @@ async function answerRepair(targetDir, repos, opts = {}) {
23909
23976
  }
23910
23977
 
23911
23978
  // src/intel/context.ts
23912
- import { existsSync as existsSync32, readdirSync as readdirSync18, readFileSync as readFileSync24, statSync as statSync7 } from "fs";
23913
- import path45 from "path";
23979
+ import { existsSync as existsSync33, readdirSync as readdirSync18, readFileSync as readFileSync24, statSync as statSync7 } from "fs";
23980
+ import path46 from "path";
23914
23981
 
23915
23982
  // src/planner.ts
23916
23983
  import { createHash as createHash5 } from "crypto";
@@ -24008,7 +24075,7 @@ function safeScalar(value) {
24008
24075
  return redactSecrets(value) === value ? value : null;
24009
24076
  }
24010
24077
  function safeConfig(targetDir) {
24011
- const file = path45.join(targetDir, "forge-cli.config.json");
24078
+ const file = path46.join(targetDir, "forge-cli.config.json");
24012
24079
  let raw;
24013
24080
  try {
24014
24081
  raw = JSON.parse(readFileSync24(file, "utf8"));
@@ -24025,9 +24092,9 @@ function safeConfig(targetDir) {
24025
24092
  return out;
24026
24093
  }
24027
24094
  function readManifestObject(repoDir) {
24028
- const file = path45.join(repoDir, "forge.json");
24095
+ const file = path46.join(repoDir, "forge.json");
24029
24096
  try {
24030
- if (!existsSync32(file) || statSync7(file).size > MAX_MANIFEST_BYTES) return null;
24097
+ if (!existsSync33(file) || statSync7(file).size > MAX_MANIFEST_BYTES) return null;
24031
24098
  const raw = JSON.parse(readFileSync24(file, "utf8"));
24032
24099
  return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : null;
24033
24100
  } catch {
@@ -24061,7 +24128,7 @@ function manifestCapabilities(repoDir, repoName, out) {
24061
24128
  }
24062
24129
  }
24063
24130
  function activePlans(targetDir, nowIso) {
24064
- const dir = path45.join(artifactsRoot(targetDir), "plans");
24131
+ const dir = path46.join(artifactsRoot(targetDir), "plans");
24065
24132
  let names;
24066
24133
  try {
24067
24134
  names = readdirSync18(dir).filter((n4) => n4.endsWith(".json")).sort();
@@ -24072,7 +24139,7 @@ function activePlans(targetDir, nowIso) {
24072
24139
  const out = [];
24073
24140
  for (const name of names.slice(0, MAX_PLAN_FILES)) {
24074
24141
  try {
24075
- const doc = JSON.parse(readFileSync24(path45.join(dir, name), "utf8"));
24142
+ const doc = JSON.parse(readFileSync24(path46.join(dir, name), "utf8"));
24076
24143
  if (!doc || typeof doc !== "object" || Array.isArray(doc)) continue;
24077
24144
  const plan = doc;
24078
24145
  if (typeof plan.plan_id !== "string" || !plan.plan_id) continue;
@@ -24143,7 +24210,7 @@ async function buildForgeContext(targetDir, repos, opts = {}) {
24143
24210
  const byName = new Map(report.forges.map((f) => [f.name, f]));
24144
24211
  const capabilities = {};
24145
24212
  const forjas = [...repos].sort((a3, b) => cmp2(a3.name, b.name)).map((repo) => {
24146
- const dir = path45.join(targetDir, repo.name);
24213
+ const dir = path46.join(targetDir, repo.name);
24147
24214
  manifestCapabilities(dir, repo.name, capabilities);
24148
24215
  const discovered = byName.get(repo.name);
24149
24216
  return {
@@ -24197,8 +24264,8 @@ async function buildForgeContext(targetDir, repos, opts = {}) {
24197
24264
  }
24198
24265
 
24199
24266
  // src/intel/predict.ts
24200
- import { existsSync as existsSync33, readFileSync as readFileSync25, statSync as statSync8 } from "fs";
24201
- import path46 from "path";
24267
+ import { existsSync as existsSync34, readFileSync as readFileSync25, statSync as statSync8 } from "fs";
24268
+ import path47 from "path";
24202
24269
  var MAX_MANIFEST_BYTES2 = 64 * 1024;
24203
24270
  var SEMVERISH = /^v?\d+\.\d+\.\d+/;
24204
24271
  var ev2 = (source, fact) => ({
@@ -24208,9 +24275,9 @@ var ev2 = (source, fact) => ({
24208
24275
  var cmp3 = (a3, b) => a3 < b ? -1 : a3 > b ? 1 : 0;
24209
24276
  var mk2 = (id, kind, subject, certainty, version, evidence, explanation) => ({ id, kind, subject, certainty, version, evidence, explanation });
24210
24277
  function readManifest(repoDir) {
24211
- const file = path46.join(repoDir, "forge.json");
24278
+ const file = path47.join(repoDir, "forge.json");
24212
24279
  try {
24213
- if (!existsSync33(file) || statSync8(file).size > MAX_MANIFEST_BYTES2) return null;
24280
+ if (!existsSync34(file) || statSync8(file).size > MAX_MANIFEST_BYTES2) return null;
24214
24281
  const raw = JSON.parse(readFileSync25(file, "utf8"));
24215
24282
  return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : null;
24216
24283
  } catch {
@@ -24260,7 +24327,7 @@ function declaredRefs(targetDir, repoName, m3) {
24260
24327
  }
24261
24328
  try {
24262
24329
  const lock = JSON.parse(
24263
- readFileSync25(path46.join(artifactsRoot(targetDir), "env.lock.json"), "utf8")
24330
+ readFileSync25(path47.join(artifactsRoot(targetDir), "env.lock.json"), "utf8")
24264
24331
  );
24265
24332
  const head = lock?.forges?.[repoName]?.head;
24266
24333
  if (typeof head === "string" && SEMVERISH.test(head)) {
@@ -24527,7 +24594,7 @@ async function predictCompatibility(targetDir, repos, opts = {}) {
24527
24594
  const allClaims = [];
24528
24595
  for (const repo of sorted) {
24529
24596
  const dir = resolveInside(targetDir, repo.name);
24530
- if (!dir || !existsSync33(dir)) continue;
24597
+ if (!dir || !existsSync34(dir)) continue;
24531
24598
  const m3 = readManifest(dir);
24532
24599
  manifests.set(repo.name, m3);
24533
24600
  if (m3) out.push(...schemaChange(repo.name, m3));
@@ -24539,7 +24606,7 @@ async function predictCompatibility(targetDir, repos, opts = {}) {
24539
24606
  out.push(...envVarFindings("<workspace>", targetDir));
24540
24607
  for (const repo of sorted) {
24541
24608
  const dir = resolveInside(targetDir, repo.name);
24542
- if (!dir || !existsSync33(dir)) continue;
24609
+ if (!dir || !existsSync34(dir)) continue;
24543
24610
  out.push(...envVarFindings(repo.name, dir, repo.envKeys));
24544
24611
  }
24545
24612
  out.push(...installConflict(allClaims));
@@ -24547,13 +24614,13 @@ async function predictCompatibility(targetDir, repos, opts = {}) {
24547
24614
  }
24548
24615
 
24549
24616
  // src/ai/bridge.ts
24550
- import { mkdirSync as mkdirSync13 } from "fs";
24551
- import path48 from "path";
24617
+ import { mkdirSync as mkdirSync14 } from "fs";
24618
+ import path49 from "path";
24552
24619
 
24553
24620
  // src/ai/cache.ts
24554
24621
  import { createHash as createHash6 } from "crypto";
24555
- import { existsSync as existsSync34, mkdirSync as mkdirSync12, readFileSync as readFileSync26, readdirSync as readdirSync19, rmSync as rmSync7 } from "fs";
24556
- import path47 from "path";
24622
+ import { existsSync as existsSync35, mkdirSync as mkdirSync13, readFileSync as readFileSync26, readdirSync as readdirSync19, rmSync as rmSync8 } from "fs";
24623
+ import path48 from "path";
24557
24624
 
24558
24625
  // src/ai/types.ts
24559
24626
  var AI_PROPOSAL_SCHEMA = "forge/AiProposal/v1";
@@ -24636,7 +24703,7 @@ function validateProposal(proposal, catalog) {
24636
24703
  var AI_CACHE_MAX_ENTRIES = 32;
24637
24704
  var KEY_RE = /^[a-f0-9]{64}$/;
24638
24705
  function aiCacheDir(rootDir) {
24639
- return path47.join(artifactsRoot(rootDir), "ai", "cache");
24706
+ return path48.join(artifactsRoot(rootDir), "ai", "cache");
24640
24707
  }
24641
24708
  function canonical(value) {
24642
24709
  if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
@@ -24651,12 +24718,12 @@ function aiCacheKey(payload) {
24651
24718
  }
24652
24719
  function entryFile(rootDir, key) {
24653
24720
  if (!KEY_RE.test(key)) return null;
24654
- return path47.join(aiCacheDir(rootDir), `${key}.json`);
24721
+ return path48.join(aiCacheDir(rootDir), `${key}.json`);
24655
24722
  }
24656
24723
  function aiCacheGet(rootDir, key, opts) {
24657
24724
  if (opts.ttlMs <= 0) return null;
24658
24725
  const file = entryFile(rootDir, key);
24659
- if (!file || !existsSync34(file)) return null;
24726
+ if (!file || !existsSync35(file)) return null;
24660
24727
  try {
24661
24728
  const entry2 = JSON.parse(readFileSync26(file, "utf8"));
24662
24729
  const now = opts.now ?? Date.now();
@@ -24672,7 +24739,7 @@ function aiCacheSet(rootDir, key, proposal, opts = {}) {
24672
24739
  const file = entryFile(rootDir, key);
24673
24740
  if (!file) return;
24674
24741
  const dir = aiCacheDir(rootDir);
24675
- mkdirSync12(dir, { recursive: true });
24742
+ mkdirSync13(dir, { recursive: true });
24676
24743
  const entry2 = { at: opts.now ?? Date.now(), proposal };
24677
24744
  writeFileAtomic(file, JSON.stringify(entry2));
24678
24745
  evictOldest(dir, opts.maxEntries ?? AI_CACHE_MAX_ENTRIES);
@@ -24681,14 +24748,14 @@ function evictOldest(dir, maxEntries) {
24681
24748
  if (maxEntries < 1) return;
24682
24749
  let files;
24683
24750
  try {
24684
- files = readdirSync19(dir).filter((f) => KEY_RE.test(path47.basename(f, ".json")));
24751
+ files = readdirSync19(dir).filter((f) => KEY_RE.test(path48.basename(f, ".json")));
24685
24752
  } catch {
24686
24753
  return;
24687
24754
  }
24688
24755
  if (files.length <= maxEntries) return;
24689
- const aged = files.map((file) => ({ file, at: entryAge(path47.join(dir, file)) })).sort((a3, b) => a3.at - b.at || a3.file.localeCompare(b.file));
24756
+ const aged = files.map((file) => ({ file, at: entryAge(path48.join(dir, file)) })).sort((a3, b) => a3.at - b.at || a3.file.localeCompare(b.file));
24690
24757
  for (const { file } of aged.slice(0, aged.length - maxEntries)) {
24691
- rmSync7(path47.join(dir, file), { force: true });
24758
+ rmSync8(path48.join(dir, file), { force: true });
24692
24759
  }
24693
24760
  }
24694
24761
  function entryAge(file) {
@@ -24745,18 +24812,18 @@ function sanitizeForAi(input) {
24745
24812
  }
24746
24813
  function assertNoSecrets(input) {
24747
24814
  const hits = /* @__PURE__ */ new Set();
24748
- const visit = (value, path52) => {
24815
+ const visit = (value, path53) => {
24749
24816
  if (typeof value === "string") {
24750
- if (redactSecrets(value) !== value) hits.add(path52 || "<root>");
24817
+ if (redactSecrets(value) !== value) hits.add(path53 || "<root>");
24751
24818
  return;
24752
24819
  }
24753
24820
  if (Array.isArray(value)) {
24754
- value.forEach((item, index) => visit(item, `${path52}[${index}]`));
24821
+ value.forEach((item, index) => visit(item, `${path53}[${index}]`));
24755
24822
  return;
24756
24823
  }
24757
24824
  if (value && typeof value === "object") {
24758
24825
  for (const [key, child] of Object.entries(value)) {
24759
- const childPath = path52 ? `${path52}.${key}` : key;
24826
+ const childPath = path53 ? `${path53}.${key}` : key;
24760
24827
  if (isDeniedKey(key)) {
24761
24828
  hits.add(childPath);
24762
24829
  continue;
@@ -24813,9 +24880,9 @@ async function runAiBridge(req, cfg, deps) {
24813
24880
  if (Buffer.byteLength(body, "utf8") > cfg.maxContextBytes) {
24814
24881
  return { ok: false, reason: "bridge-error", detail: "context-too-large" };
24815
24882
  }
24816
- const aiDir = path48.join(artifactsRoot(rootDir), "ai");
24817
- mkdirSync13(aiDir, { recursive: true });
24818
- const contextFile = path48.join(aiDir, `context-${digest}.json`);
24883
+ const aiDir = path49.join(artifactsRoot(rootDir), "ai");
24884
+ mkdirSync14(aiDir, { recursive: true });
24885
+ const contextFile = path49.join(aiDir, `context-${digest}.json`);
24819
24886
  writeFileAtomic(contextFile, body);
24820
24887
  const argv = command.map((part) => part === "{context}" ? contextFile : part);
24821
24888
  if (!command.includes("{context}")) argv.push(contextFile);
@@ -24856,8 +24923,8 @@ async function runAiBridge(req, cfg, deps) {
24856
24923
  }
24857
24924
 
24858
24925
  // src/portability/bundle.ts
24859
- import { existsSync as existsSync35, mkdirSync as mkdirSync14, readFileSync as readFileSync27 } from "fs";
24860
- import path49 from "path";
24926
+ import { existsSync as existsSync36, mkdirSync as mkdirSync15, readFileSync as readFileSync27 } from "fs";
24927
+ import path50 from "path";
24861
24928
 
24862
24929
  // src/portability/manifest.ts
24863
24930
  import { createHash as createHash7 } from "crypto";
@@ -24944,19 +25011,19 @@ var SecretKeysRefusedError = class extends Error {
24944
25011
  function writeJson(dest, doc) {
24945
25012
  const content = JSON.stringify(doc, null, 2);
24946
25013
  writeFileAtomic(dest, content);
24947
- return { path: path49.basename(dest), content };
25014
+ return { path: path50.basename(dest), content };
24948
25015
  }
24949
25016
  function pinVersion(repoDir) {
24950
25017
  for (const file of ["forge.json", "package.json"]) {
24951
25018
  try {
24952
- const parsed = JSON.parse(readFileSync27(path49.join(repoDir, file), "utf8"));
25019
+ const parsed = JSON.parse(readFileSync27(path50.join(repoDir, file), "utf8"));
24953
25020
  const v = parsed?.version;
24954
25021
  if (typeof v === "string" && v) return v;
24955
25022
  } catch {
24956
25023
  }
24957
25024
  }
24958
25025
  try {
24959
- const pyproject = readFileSync27(path49.join(repoDir, "pyproject.toml"), "utf8");
25026
+ const pyproject = readFileSync27(path50.join(repoDir, "pyproject.toml"), "utf8");
24960
25027
  const m3 = /^version\s*=\s*"([^"]+)"/m.exec(pyproject);
24961
25028
  if (m3) return m3[1];
24962
25029
  } catch {
@@ -24967,8 +25034,8 @@ function collectPins(targetDir, repos) {
24967
25034
  const state = loadState(targetDir);
24968
25035
  const pins = /* @__PURE__ */ new Map();
24969
25036
  for (const repo of repos) {
24970
- const repoDir = path49.join(targetDir, repo.name);
24971
- const version = existsSync35(repoDir) ? pinVersion(repoDir) : void 0;
25037
+ const repoDir = path50.join(targetDir, repo.name);
25038
+ const version = existsSync36(repoDir) ? pinVersion(repoDir) : void 0;
24972
25039
  const head = state?.repos[repo.name]?.head;
24973
25040
  const ref = state?.pins?.[repo.name] ?? head;
24974
25041
  pins.set(repo.name, {
@@ -24994,15 +25061,15 @@ async function exportBundle(targetDir, repos, dest, opts) {
24994
25061
  }
24995
25062
  const schemaByRepo = /* @__PURE__ */ new Map();
24996
25063
  for (const repo of repos) {
24997
- const repoDir = path49.join(targetDir, repo.name);
24998
- const schema = existsSync35(repoDir) ? deriveSchema(repoDir, repo.envKeys) : { vars: [] };
25064
+ const repoDir = path50.join(targetDir, repo.name);
25065
+ const schema = existsSync36(repoDir) ? deriveSchema(repoDir, repo.envKeys) : { vars: [] };
24999
25066
  schemaByRepo.set(repo.name, schema);
25000
25067
  for (const v of schema.vars) {
25001
25068
  if (v.secret && whitelist.includes(v.key)) refused.add(v.key);
25002
25069
  }
25003
25070
  }
25004
25071
  if (refused.size) throw new SecretKeysRefusedError([...refused]);
25005
- mkdirSync14(dest, { recursive: true });
25072
+ mkdirSync15(dest, { recursive: true });
25006
25073
  const inputs = [];
25007
25074
  const produced = [
25008
25075
  BUNDLE_FILES.envelope,
@@ -25015,29 +25082,29 @@ async function exportBundle(targetDir, repos, dest, opts) {
25015
25082
  BUNDLE_FILES.integrity
25016
25083
  ].sort();
25017
25084
  inputs.push(
25018
- writeJson(path49.join(dest, BUNDLE_FILES.envelope), {
25085
+ writeJson(path50.join(dest, BUNDLE_FILES.envelope), {
25019
25086
  schema: BUNDLE_SCHEMA,
25020
25087
  generatedAt: now,
25021
25088
  files: produced
25022
25089
  })
25023
25090
  );
25024
- const profile = { ...exportProfile(targetDir, path49.join(dest, BUNDLE_FILES.profile)) };
25091
+ const profile = { ...exportProfile(targetDir, path50.join(dest, BUNDLE_FILES.profile)) };
25025
25092
  const normalizedProfile = { ...profile, exported_at: now };
25026
- inputs.push(writeJson(path49.join(dest, BUNDLE_FILES.profile), normalizedProfile));
25093
+ inputs.push(writeJson(path50.join(dest, BUNDLE_FILES.profile), normalizedProfile));
25027
25094
  const lock = { ...writeEnvLock(targetDir, repos), generated_at: now };
25028
- inputs.push(writeJson(path49.join(dest, BUNDLE_FILES.lock), lock));
25029
- inputs.push(writeJson(path49.join(dest, BUNDLE_FILES.lockCheck), checkEnvLock(targetDir, repos)));
25095
+ inputs.push(writeJson(path50.join(dest, BUNDLE_FILES.lock), lock));
25096
+ inputs.push(writeJson(path50.join(dest, BUNDLE_FILES.lockCheck), checkEnvLock(targetDir, repos)));
25030
25097
  const envKeys = {};
25031
25098
  for (const repo of repos) {
25032
25099
  const keys = [...new Set((schemaByRepo.get(repo.name)?.vars ?? []).map((v) => v.key))].sort();
25033
25100
  envKeys[repo.name] = keys;
25034
25101
  }
25035
- inputs.push(writeJson(path49.join(dest, BUNDLE_FILES.envKeys), envKeys));
25102
+ inputs.push(writeJson(path50.join(dest, BUNDLE_FILES.envKeys), envKeys));
25036
25103
  if (whitelist.length) {
25037
25104
  const values = {};
25038
25105
  for (const repo of repos) {
25039
- const envFile = path49.join(targetDir, repo.name, ".env");
25040
- if (!existsSync35(envFile)) continue;
25106
+ const envFile = path50.join(targetDir, repo.name, ".env");
25107
+ if (!existsSync36(envFile)) continue;
25041
25108
  const entries = parseEnv(readFileSync27(envFile, "utf8")).entries;
25042
25109
  const found = {};
25043
25110
  for (const key of whitelist) {
@@ -25046,11 +25113,11 @@ async function exportBundle(targetDir, repos, dest, opts) {
25046
25113
  }
25047
25114
  if (Object.keys(found).length) values[repo.name] = found;
25048
25115
  }
25049
- inputs.push(writeJson(path49.join(dest, BUNDLE_FILES.envValues), values));
25116
+ inputs.push(writeJson(path50.join(dest, BUNDLE_FILES.envValues), values));
25050
25117
  }
25051
- inputs.push(writeJson(path49.join(dest, BUNDLE_FILES.pins), collectPins(targetDir, repos)));
25118
+ inputs.push(writeJson(path50.join(dest, BUNDLE_FILES.pins), collectPins(targetDir, repos)));
25052
25119
  const manifest = buildIntegrityManifest(inputs, { now });
25053
- inputs.push(writeJson(path49.join(dest, BUNDLE_FILES.integrity), manifest));
25120
+ inputs.push(writeJson(path50.join(dest, BUNDLE_FILES.integrity), manifest));
25054
25121
  return { ok: true, dir: dest, files: produced, manifest };
25055
25122
  }
25056
25123
  function readJsonFile(file) {
@@ -25104,38 +25171,38 @@ function readPins(file) {
25104
25171
  function importBundle(src, opts) {
25105
25172
  const read = (p) => {
25106
25173
  try {
25107
- return readFileSync27(path49.join(src, p));
25174
+ return readFileSync27(path50.join(src, p));
25108
25175
  } catch {
25109
25176
  return null;
25110
25177
  }
25111
25178
  };
25112
- const manifestRaw = readJsonFile(path49.join(src, BUNDLE_FILES.integrity));
25179
+ const manifestRaw = readJsonFile(path50.join(src, BUNDLE_FILES.integrity));
25113
25180
  const manifest = manifestRaw && typeof manifestRaw === "object" && manifestRaw.schema === "forge/IntegrityManifest/v1" ? manifestRaw : null;
25114
25181
  const verify = opts?.verifyIntegrity === false ? { ok: true } : verifyIntegrityManifest(manifest, read);
25115
- const profile = importProfile(path49.join(src, BUNDLE_FILES.profile));
25182
+ const profile = importProfile(path50.join(src, BUNDLE_FILES.profile));
25116
25183
  return {
25117
25184
  dir: src,
25118
25185
  verify,
25119
25186
  manifest,
25120
25187
  profile: "error" in profile ? null : profile,
25121
- lockfile: readLockfile(path49.join(src, BUNDLE_FILES.lock)),
25122
- lockCheck: readLockCheck(path49.join(src, BUNDLE_FILES.lockCheck)),
25123
- envKeys: readStringMap(path49.join(src, BUNDLE_FILES.envKeys)),
25124
- envValues: readValueMap(path49.join(src, BUNDLE_FILES.envValues)),
25125
- pins: readPins(path49.join(src, BUNDLE_FILES.pins))
25188
+ lockfile: readLockfile(path50.join(src, BUNDLE_FILES.lock)),
25189
+ lockCheck: readLockCheck(path50.join(src, BUNDLE_FILES.lockCheck)),
25190
+ envKeys: readStringMap(path50.join(src, BUNDLE_FILES.envKeys)),
25191
+ envValues: readValueMap(path50.join(src, BUNDLE_FILES.envValues)),
25192
+ pins: readPins(path50.join(src, BUNDLE_FILES.pins))
25126
25193
  };
25127
25194
  }
25128
25195
 
25129
25196
  // src/intel/learning.ts
25130
- import { existsSync as existsSync36, mkdirSync as mkdirSync15, readFileSync as readFileSync28 } from "fs";
25131
- import path50 from "path";
25197
+ import { existsSync as existsSync37, mkdirSync as mkdirSync16, readFileSync as readFileSync28 } from "fs";
25198
+ import path51 from "path";
25132
25199
  var LEARNING_SCHEMA = "forge-cli/LearningStore/v1";
25133
25200
  function learningFile(targetDir) {
25134
- return path50.join(artifactsRoot(targetDir), "learning.json");
25201
+ return path51.join(artifactsRoot(targetDir), "learning.json");
25135
25202
  }
25136
25203
  function readStore(targetDir) {
25137
25204
  const file = learningFile(targetDir);
25138
- if (!existsSync36(file)) return { schema: LEARNING_SCHEMA, enabled: false, observations: [] };
25205
+ if (!existsSync37(file)) return { schema: LEARNING_SCHEMA, enabled: false, observations: [] };
25139
25206
  try {
25140
25207
  const parsed = JSON.parse(readFileSync28(file, "utf8"));
25141
25208
  if (parsed?.schema !== LEARNING_SCHEMA || !Array.isArray(parsed.observations)) {
@@ -25154,7 +25221,7 @@ function readStore(targetDir) {
25154
25221
  }
25155
25222
  function writeStore(targetDir, store) {
25156
25223
  const file = learningFile(targetDir);
25157
- mkdirSync15(path50.dirname(file), { recursive: true });
25224
+ mkdirSync16(path51.dirname(file), { recursive: true });
25158
25225
  writeFileAtomic(file, JSON.stringify(store, null, 2));
25159
25226
  }
25160
25227
  function learningStatus(targetDir) {
@@ -25395,8 +25462,8 @@ async function runLearningCommand(cli) {
25395
25462
  }
25396
25463
 
25397
25464
  // src/wizard.ts
25398
- import { existsSync as existsSync37 } from "fs";
25399
- import path51 from "path";
25465
+ import { existsSync as existsSync38 } from "fs";
25466
+ import path52 from "path";
25400
25467
  var STEP_LABELS = [
25401
25468
  S.wizardStepDetect,
25402
25469
  S.wizardStepRecommend,
@@ -25435,8 +25502,8 @@ function renderOperationPlan(plan) {
25435
25502
  return lines.join("\n");
25436
25503
  }
25437
25504
  function planActionsFor(repo, targetDir, steps) {
25438
- const repoDir = path51.join(targetDir, repo.name);
25439
- const cloned = existsSync37(repoDir) && hasGitRepo(repoDir);
25505
+ const repoDir = path52.join(targetDir, repo.name);
25506
+ const cloned = existsSync38(repoDir) && hasGitRepo(repoDir);
25440
25507
  const actions = [
25441
25508
  {
25442
25509
  kind: "clone",
@@ -25456,7 +25523,7 @@ function planActionsFor(repo, targetDir, steps) {
25456
25523
  actions.push({
25457
25524
  kind: "env",
25458
25525
  label: "provisionar .env (nunca sobrescreve)",
25459
- paths: [path51.join(repo.name, ".env")],
25526
+ paths: [path52.join(repo.name, ".env")],
25460
25527
  reversible: false
25461
25528
  });
25462
25529
  if (steps.includes("skills")) {
@@ -25606,7 +25673,7 @@ async function runWizard(cli) {
25606
25673
  const planForges = repos.map((repo) => ({
25607
25674
  forge_id: repo.name,
25608
25675
  repo: repo.name,
25609
- target_dir: path51.join(targetDir, repo.name),
25676
+ target_dir: path52.join(targetDir, repo.name),
25610
25677
  actions: filterSteps(planActionsFor(repo, targetDir, steps), steps)
25611
25678
  }));
25612
25679
  const plan = buildPlan({
@@ -26000,7 +26067,8 @@ async function main() {
26000
26067
  log.error(S.errReinstallNeedsNames);
26001
26068
  process.exit(2);
26002
26069
  }
26003
- if (resolved.command === "install" && cli.method === "registry") {
26070
+ const installWantsRegistry = resolved.command === "install" && cli.method !== "git" && (cli.method === "registry" || resolved.names.length > 0 || cli.all === true || (cli.only?.length ?? 0) > 0 || isNonInteractive(cli));
26071
+ if (installWantsRegistry) {
26004
26072
  const names = resolved.names.length ? resolved.names : cli.all ? registryNames() : cli.only ?? [];
26005
26073
  if (!names.length) {
26006
26074
  log.error(S.errRegistryNeedsNames);