hatch3r 1.6.0 → 1.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -14,7 +14,7 @@ var HATCH3R_VERSION;
14
14
  var init_version = __esm({
15
15
  "src/version.ts"() {
16
16
  "use strict";
17
- HATCH3R_VERSION = "1.6.0";
17
+ HATCH3R_VERSION = "1.6.2";
18
18
  }
19
19
  });
20
20
 
@@ -2181,7 +2181,9 @@ function createManifest(options) {
2181
2181
  if (options.defaultBranch) {
2182
2182
  manifest.board = createMinimalBoardConfig(owner, repo, options.defaultBranch);
2183
2183
  }
2184
- if (options.tools.some((t) => WORKTREE_CAPABLE_TOOLS.has(t))) {
2184
+ const autoEnable = options.tools.some((t) => WORKTREE_CAPABLE_TOOLS.has(t));
2185
+ const shouldEnable = options.worktreeEnabled ?? autoEnable;
2186
+ if (shouldEnable) {
2185
2187
  manifest.worktree = { enabled: true };
2186
2188
  }
2187
2189
  return manifest;
@@ -2399,7 +2401,7 @@ var init_resolve2 = __esm({
2399
2401
 
2400
2402
  // src/adapters/canonical.ts
2401
2403
  import { readFile as readFile9, readdir as readdir6, lstat as lstat2 } from "fs/promises";
2402
- import { join as join12 } from "path";
2404
+ import { join as join12, relative as relative3 } from "path";
2403
2405
  import { parse as parseYaml2 } from "yaml";
2404
2406
  function precedenceRank(value) {
2405
2407
  if (value && RULE_PRECEDENCE_VALUES.includes(value)) {
@@ -2414,6 +2416,16 @@ function sortByPrecedence(items) {
2414
2416
  return a.id.localeCompare(b.id);
2415
2417
  });
2416
2418
  }
2419
+ function filterUserFacing(files, expectedFrontmatterType, baseDir) {
2420
+ return files.filter((file) => {
2421
+ const rel = relative3(baseDir, file.sourcePath);
2422
+ if (rel === "" || rel.startsWith("..")) return true;
2423
+ if (/^[A-Za-z]:[\\/]/.test(rel)) return true;
2424
+ if (rel.includes("/") || rel.includes("\\")) return false;
2425
+ if (file.frontmatterType && file.frontmatterType !== expectedFrontmatterType) return false;
2426
+ return true;
2427
+ });
2428
+ }
2417
2429
  function classifyFsError(err) {
2418
2430
  const code = err?.code;
2419
2431
  if (code === "ENOENT") return "NOT_FOUND";
@@ -2460,6 +2472,7 @@ function parseFrontmatter(rawContent, typeMismatches) {
2460
2472
  type: "rule",
2461
2473
  description: ""
2462
2474
  };
2475
+ let rawType;
2463
2476
  if (parsed && typeof parsed === "object") {
2464
2477
  const scalarFields = ["id", "type", "description"];
2465
2478
  for (const field of scalarFields) {
@@ -2467,6 +2480,7 @@ function parseFrontmatter(rawContent, typeMismatches) {
2467
2480
  if (raw === void 0) continue;
2468
2481
  if (typeof raw === "string") {
2469
2482
  metadata[field] = raw;
2483
+ if (field === "type") rawType = raw;
2470
2484
  } else if (typeMismatches) {
2471
2485
  typeMismatches.push(
2472
2486
  `${field} field must be a string, got ${describeYamlType(raw)} (value: ${JSON.stringify(raw)})`
@@ -2502,7 +2516,7 @@ function parseFrontmatter(rawContent, typeMismatches) {
2502
2516
  }
2503
2517
  metadata.type = metadata.type ?? "rule";
2504
2518
  metadata.description = metadata.description ?? "";
2505
- return { metadata, content: content ?? "" };
2519
+ return { metadata, content: content ?? "", rawType };
2506
2520
  }
2507
2521
  async function readSingleMd(fullPath, fileType, fallbackId) {
2508
2522
  let stats;
@@ -2533,11 +2547,19 @@ async function readSingleMd(fullPath, fileType, fallbackId) {
2533
2547
  const errorResult = makeErrorResult(fullPath, err, "YAML_PARSE_ERROR");
2534
2548
  return errorResult;
2535
2549
  }
2536
- const { metadata, content } = parsed;
2550
+ const { metadata, content, rawType } = parsed;
2537
2551
  const id = metadata.id || metadata.name || fallbackId;
2538
2552
  const canonical = {
2539
2553
  id,
2540
2554
  type: fileType,
2555
+ // Preserve the author-declared frontmatter `type` alongside the reader
2556
+ // bucket so downstream filters (see `filterUserFacing`) can distinguish
2557
+ // user-invocable commands/agents from companion content
2558
+ // (`shared-context`, `reference`, `mode`) within the same directory.
2559
+ // `rawType` is undefined when the author omitted `type:`, so files
2560
+ // without an explicit declaration fall through the filter's
2561
+ // back-compat path and are kept.
2562
+ frontmatterType: rawType,
2541
2563
  description: metadata.description ?? "",
2542
2564
  scope: metadata.scope,
2543
2565
  model: metadata.model,
@@ -2959,7 +2981,7 @@ function resolveSelection(preset, projectType, teamSize, index, customSelections
2959
2981
  (item) => item.protected || !item.tags.includes("greenfield") || item.tags.some((t) => t !== "greenfield" && t !== "team" && t !== "solo")
2960
2982
  );
2961
2983
  }
2962
- if (teamSize === "solo") {
2984
+ if (teamSize === "solo" && preset.id !== "full") {
2963
2985
  selected = selected.filter((item) => {
2964
2986
  if (item.protected) return true;
2965
2987
  if (!item.tags.includes("team") && !item.tags.includes("board")) return true;
@@ -4231,7 +4253,7 @@ var init_hooks = __esm({
4231
4253
  });
4232
4254
 
4233
4255
  // src/adapters/base.ts
4234
- import { dirname as dirname7 } from "path";
4256
+ import { dirname as dirname7, join as join17 } from "path";
4235
4257
  function output(path, content, managedContent) {
4236
4258
  return { path, content, managedContent, action: "create" };
4237
4259
  }
@@ -4345,6 +4367,27 @@ var init_base = __esm({
4345
4367
  }
4346
4368
  return files;
4347
4369
  }
4370
+ /**
4371
+ * Read canonical commands or agents and filter to only those that should
4372
+ * appear in a tool's user-facing command/agent picker. Wraps
4373
+ * {@link readCanonicalFiles} + {@link filterUserFacing} and applies
4374
+ * provenance tracking only to the surviving files, so filtered-out
4375
+ * companion content does not pollute the adapter's source-file manifest.
4376
+ *
4377
+ * Filter rules are documented on {@link filterUserFacing}: files in
4378
+ * support subdirectories (`commands/board/`, `agents/modes/`, etc.) and
4379
+ * top-level files with a non-primary frontmatter `type:` (e.g.
4380
+ * `shared-context`, `reference`, `mode`) are excluded.
4381
+ */
4382
+ async readUserFacingCanonicalFiles(agentsDir, type) {
4383
+ const files = await readCanonicalFiles(agentsDir, type, this.warnings);
4384
+ const expectedType = type === "commands" ? "command" : "agent";
4385
+ const filtered = filterUserFacing(files, expectedType, join17(agentsDir, type));
4386
+ for (const f of filtered) {
4387
+ if (f.sourcePath) this._trackedSourceFiles.add(f.sourcePath);
4388
+ }
4389
+ return filtered;
4390
+ }
4348
4391
  /**
4349
4392
  * Returns the raw bridge orchestration content (no surrounding headers).
4350
4393
  * Use this when the adapter needs custom formatting around the bridge content.
@@ -4401,7 +4444,7 @@ var init_base = __esm({
4401
4444
  async inlineAgents(ctx, formatModel) {
4402
4445
  if (!ctx.features.agents) return [];
4403
4446
  const lines = [];
4404
- const agents = await this.readTrackedCanonicalFiles(ctx.agentsDir, "agents");
4447
+ const agents = await this.readUserFacingCanonicalFiles(ctx.agentsDir, "agents");
4405
4448
  const minimal = this.isMinimal(ctx);
4406
4449
  for (const agent of agents) {
4407
4450
  const { content, skip, overrides, warnings } = await applyCustomization(ctx.projectRoot, agent);
@@ -4459,7 +4502,7 @@ ${wrapInManagedBlock(content)}`, content));
4459
4502
  async processCommandsRaw(ctx, pathFn) {
4460
4503
  if (!ctx.features.commands) return [];
4461
4504
  const results = [];
4462
- const commands = await this.readTrackedCanonicalFiles(ctx.agentsDir, "commands");
4505
+ const commands = await this.readUserFacingCanonicalFiles(ctx.agentsDir, "commands");
4463
4506
  for (const cmd of commands) {
4464
4507
  const { content, skip, warnings } = await applyCustomizationRaw(ctx.projectRoot, cmd);
4465
4508
  this.warnings.push(...warnings);
@@ -4561,7 +4604,7 @@ var init_agentsmd = __esm({
4561
4604
  sections.push("");
4562
4605
  }
4563
4606
  if (ctx.features.agents) {
4564
- const agents = await readCanonicalFiles(ctx.agentsDir, "agents", this.warnings);
4607
+ const agents = await this.readUserFacingCanonicalFiles(ctx.agentsDir, "agents");
4565
4608
  for (const agent of agents) {
4566
4609
  const { content, skip, overrides, warnings } = await applyCustomization(ctx.projectRoot, agent);
4567
4610
  this.warnings.push(...warnings);
@@ -4695,7 +4738,6 @@ var init_amazonq = __esm({
4695
4738
  init_types();
4696
4739
  init_managedBlocks();
4697
4740
  init_base();
4698
- init_canonical();
4699
4741
  init_customization();
4700
4742
  AmazonQAdapter = class extends BaseAdapter {
4701
4743
  name = "amazon-q";
@@ -4720,7 +4762,7 @@ var init_amazonq = __esm({
4720
4762
  const hooks = await this.readHooks(ctx);
4721
4763
  const descriptorHooks = this.buildDescriptorHooks(hooks);
4722
4764
  if (ctx.features.agents) {
4723
- const agents = await readCanonicalFiles(ctx.agentsDir, "agents", this.warnings);
4765
+ const agents = await this.readUserFacingCanonicalFiles(ctx.agentsDir, "agents");
4724
4766
  for (const agent of agents) {
4725
4767
  const { content, skip, overrides, warnings } = await applyCustomization(ctx.projectRoot, agent);
4726
4768
  this.warnings.push(...warnings);
@@ -5358,7 +5400,7 @@ ${content}`;
5358
5400
  }
5359
5401
  }
5360
5402
  if (ctx.features.agents) {
5361
- const agents = await readCanonicalFiles(ctx.agentsDir, "agents", this.warnings);
5403
+ const agents = await this.readUserFacingCanonicalFiles(ctx.agentsDir, "agents");
5362
5404
  for (const agent of agents) {
5363
5405
  const { content, skip, overrides, warnings } = await applyCustomization(ctx.projectRoot, agent);
5364
5406
  this.warnings.push(...warnings);
@@ -5509,7 +5551,7 @@ var init_cline = __esm({
5509
5551
  const results = [];
5510
5552
  const customModes = [];
5511
5553
  if (ctx.features.agents) {
5512
- const agents = await readCanonicalFiles(ctx.agentsDir, "agents", this.warnings);
5554
+ const agents = await this.readUserFacingCanonicalFiles(ctx.agentsDir, "agents");
5513
5555
  for (const agent of agents) {
5514
5556
  const { content, skip, overrides, warnings } = await applyCustomization(ctx.projectRoot, agent);
5515
5557
  this.warnings.push(...warnings);
@@ -5710,7 +5752,7 @@ var init_codex = __esm({
5710
5752
  }
5711
5753
  }
5712
5754
  if (ctx.features.agents) {
5713
- const agents = await readCanonicalFiles(ctx.agentsDir, "agents", this.warnings);
5755
+ const agents = await this.readUserFacingCanonicalFiles(ctx.agentsDir, "agents");
5714
5756
  for (const agent of agents) {
5715
5757
  const { content, skip, overrides, warnings } = await applyCustomization(ctx.projectRoot, agent);
5716
5758
  this.warnings.push(...warnings);
@@ -5791,11 +5833,11 @@ var init_codex = __esm({
5791
5833
 
5792
5834
  // src/detect/packageManager.ts
5793
5835
  import { access as access6 } from "fs/promises";
5794
- import { join as join17 } from "path";
5836
+ import { join as join18 } from "path";
5795
5837
  async function detectPackageManager(rootDir) {
5796
5838
  for (const { file, name } of LOCK_FILE_MAP) {
5797
5839
  try {
5798
- await access6(join17(rootDir, file));
5840
+ await access6(join18(rootDir, file));
5799
5841
  return { name, ...PM_INFO[name] };
5800
5842
  } catch (err) {
5801
5843
  if (err.code !== "ENOENT") throw err;
@@ -5927,7 +5969,7 @@ ${wrapInManagedBlock(body)}`,
5927
5969
  );
5928
5970
  }
5929
5971
  if (ctx.features.agents) {
5930
- const agents = await readCanonicalFiles(ctx.agentsDir, "agents", this.warnings);
5972
+ const agents = await this.readUserFacingCanonicalFiles(ctx.agentsDir, "agents");
5931
5973
  for (const agent of agents) {
5932
5974
  const { content, skip, overrides, warnings } = await applyCustomization(ctx.projectRoot, agent);
5933
5975
  this.warnings.push(...warnings);
@@ -6032,7 +6074,7 @@ var init_cursor = __esm({
6032
6074
  }
6033
6075
  }
6034
6076
  if (ctx.features.agents) {
6035
- const agents = await readCanonicalFiles(ctx.agentsDir, "agents", this.warnings);
6077
+ const agents = await this.readUserFacingCanonicalFiles(ctx.agentsDir, "agents");
6036
6078
  for (const agent of agents) {
6037
6079
  const { content, skip, overrides, warnings } = await applyCustomization(ctx.projectRoot, agent);
6038
6080
  this.warnings.push(...warnings);
@@ -6138,6 +6180,7 @@ New to this project's agent setup? Progress through these stages:
6138
6180
  });
6139
6181
 
6140
6182
  // src/adapters/gemini.ts
6183
+ import { join as join19 } from "path";
6141
6184
  function mapToGeminiEvent(event) {
6142
6185
  const mapping = {
6143
6186
  "pre-commit": "BeforeTool",
@@ -6208,7 +6251,8 @@ var init_gemini = __esm({
6208
6251
  ...await this.processSkillsRaw(ctx, (id) => `.gemini/skills/${toPrefixedId(id)}/SKILL.md`)
6209
6252
  );
6210
6253
  if (ctx.features.commands) {
6211
- const commands = await readCanonicalFiles(ctx.agentsDir, "commands", this.warnings);
6254
+ const commandsRaw = await readCanonicalFiles(ctx.agentsDir, "commands", this.warnings);
6255
+ const commands = filterUserFacing(commandsRaw, "command", join19(ctx.agentsDir, "commands"));
6212
6256
  for (const cmd of commands) {
6213
6257
  const { content, skip, overrides, warnings } = await applyCustomization(ctx.projectRoot, cmd);
6214
6258
  this.warnings.push(...warnings);
@@ -6242,7 +6286,7 @@ var init_goose = __esm({
6242
6286
  GooseAdapter = class extends BaseAdapter {
6243
6287
  name = "goose";
6244
6288
  async doGenerate(ctx) {
6245
- const agents = ctx.features.agents ? await readCanonicalFiles(ctx.agentsDir, "agents", this.warnings) : [];
6289
+ const agents = ctx.features.agents ? await this.readUserFacingCanonicalFiles(ctx.agentsDir, "agents") : [];
6246
6290
  const lines = [
6247
6291
  ...await this.bridgeHeader(ctx),
6248
6292
  ...await this.inlineRules(ctx),
@@ -6521,7 +6565,7 @@ var init_opencode = __esm({
6521
6565
  }
6522
6566
  results.push(output("opencode.json", JSON.stringify(opencodeConfig, null, 2)));
6523
6567
  if (ctx.features.agents) {
6524
- const agents = await readCanonicalFiles(ctx.agentsDir, "agents", this.warnings);
6568
+ const agents = await this.readUserFacingCanonicalFiles(ctx.agentsDir, "agents");
6525
6569
  for (const agent of agents) {
6526
6570
  const { content, skip, overrides, warnings } = await applyCustomization(ctx.projectRoot, agent);
6527
6571
  this.warnings.push(...warnings);
@@ -6600,7 +6644,7 @@ var init_windsurf = __esm({
6600
6644
  */
6601
6645
  async windsurfAgentToolPolicies(ctx) {
6602
6646
  if (!ctx.features.agents) return [];
6603
- const agents = await readCanonicalFiles(ctx.agentsDir, "agents", this.warnings);
6647
+ const agents = await this.readUserFacingCanonicalFiles(ctx.agentsDir, "agents");
6604
6648
  const rows = [];
6605
6649
  for (const agent of agents) {
6606
6650
  const { skip } = await applyCustomization(ctx.projectRoot, agent);
@@ -6892,7 +6936,7 @@ var init_adapters = __esm({
6892
6936
  // src/env/mcpEnv.ts
6893
6937
  import { readFile as readFile15 } from "fs/promises";
6894
6938
  import { existsSync } from "fs";
6895
- import { join as join19 } from "path";
6939
+ import { join as join21 } from "path";
6896
6940
  function getSourceEnvMcpCommand() {
6897
6941
  return process.platform === "win32" ? SOURCE_POWERSHELL : SOURCE_POSIX;
6898
6942
  }
@@ -6962,7 +7006,7 @@ function parseEnvFile(content) {
6962
7006
  return result;
6963
7007
  }
6964
7008
  async function ensureGitignoreEntry(rootDir) {
6965
- const gitignorePath = join19(rootDir, ".gitignore");
7009
+ const gitignorePath = join21(rootDir, ".gitignore");
6966
7010
  let content = "";
6967
7011
  try {
6968
7012
  content = await readFile15(gitignorePath, "utf-8");
@@ -6978,7 +7022,7 @@ async function ensureGitignoreEntry(rootDir) {
6978
7022
  `);
6979
7023
  }
6980
7024
  async function ensureEnvMcp(rootDir, servers) {
6981
- const envPath = join19(rootDir, ENV_MCP_FILE);
7025
+ const envPath = join21(rootDir, ENV_MCP_FILE);
6982
7026
  const vars = collectRequiredEnvVars(servers);
6983
7027
  if (vars.length === 0) {
6984
7028
  return { action: "skipped", path: ENV_MCP_FILE, newVars: [] };
@@ -7016,11 +7060,11 @@ var init_mcpEnv = __esm({
7016
7060
 
7017
7061
  // src/cli/shared/paths.ts
7018
7062
  import { existsSync as existsSync2 } from "fs";
7019
- import { dirname as dirname8, join as join20 } from "path";
7063
+ import { dirname as dirname8, join as join22 } from "path";
7020
7064
  function findPackageRoot(startDir) {
7021
7065
  let dir = startDir;
7022
7066
  while (dir !== dirname8(dir)) {
7023
- if (existsSync2(join20(dir, "package.json"))) return dir;
7067
+ if (existsSync2(join22(dir, "package.json"))) return dir;
7024
7068
  dir = dirname8(dir);
7025
7069
  }
7026
7070
  return startDir;
@@ -7079,7 +7123,7 @@ var init_checkpoints = __esm({
7079
7123
 
7080
7124
  // src/merge/orphanCleanup.ts
7081
7125
  import { access as access10, readFile as readFile19, unlink as unlink3 } from "fs/promises";
7082
- import { basename as basename3, dirname as dirname11, relative as relative4, resolve as resolve3 } from "path";
7126
+ import { basename as basename3, dirname as dirname11, relative as relative5, resolve as resolve3 } from "path";
7083
7127
  function isManagedOutputBasename(fileName) {
7084
7128
  return fileName.startsWith(HATCH3R_PREFIX) || NN_HATCH3R_PREFIX_RE2.test(fileName);
7085
7129
  }
@@ -7094,7 +7138,7 @@ function diffOrphanCandidates(previousPaths, currentPaths) {
7094
7138
  }
7095
7139
  function isPathInKnownAdapterRoot(relPath, rootDir) {
7096
7140
  const abs = resolve3(rootDir, relPath);
7097
- const rel = relative4(rootDir, abs);
7141
+ const rel = relative5(rootDir, abs);
7098
7142
  if (rel.startsWith("..") || resolve3(rootDir, rel) !== abs) return false;
7099
7143
  if (rel === "" || rel === ".") return false;
7100
7144
  const posix4 = rel.split(/[\\/]/).join("/");
@@ -7814,7 +7858,7 @@ __export(update_exports, {
7814
7858
  import { appendFile, cp as cp4, mkdir as mkdir8, readFile as readFile20, readdir as readdir11, stat as stat6 } from "fs/promises";
7815
7859
  import { execFileSync as execFileSync4 } from "child_process";
7816
7860
  import { fileURLToPath as fileURLToPath3 } from "url";
7817
- import { dirname as dirname12, join as join24 } from "path";
7861
+ import { dirname as dirname12, join as join26 } from "path";
7818
7862
  import chalk7 from "chalk";
7819
7863
  import inquirer5 from "inquirer";
7820
7864
  async function readFileOrNull(filePath) {
@@ -7826,7 +7870,7 @@ async function readFileOrNull(filePath) {
7826
7870
  }
7827
7871
  async function appendFailure(agentsDir, phase, error2, tool) {
7828
7872
  try {
7829
- const logPath = join24(agentsDir, FAILURE_LOG_FILE);
7873
+ const logPath = join26(agentsDir, FAILURE_LOG_FILE);
7830
7874
  const entry = createFailureLogEntry(phase, error2, {
7831
7875
  tool,
7832
7876
  version: HATCH3R_VERSION
@@ -7855,8 +7899,8 @@ async function copyHatch3rFiles(srcDir, destDir, insideHatch3rDir = false, selec
7855
7899
  throw err;
7856
7900
  }
7857
7901
  for (const entry of entries) {
7858
- const srcPath = join24(srcDir, entry.name);
7859
- const destPath = join24(destDir, entry.name);
7902
+ const srcPath = join26(srcDir, entry.name);
7903
+ const destPath = join26(destDir, entry.name);
7860
7904
  if (entry.isDirectory()) {
7861
7905
  if (selectedIds && entry.name.startsWith(HATCH3R_PREFIX)) {
7862
7906
  if (!selectedIds.has(entry.name)) continue;
@@ -7868,7 +7912,7 @@ async function copyHatch3rFiles(srcDir, destDir, insideHatch3rDir = false, selec
7868
7912
  insideHatch3rDir || !entry.name.startsWith(HATCH3R_PREFIX),
7869
7913
  selectedIds
7870
7914
  );
7871
- copied.push(...subCopied.map((p) => join24(entry.name, p)));
7915
+ copied.push(...subCopied.map((p) => join26(entry.name, p)));
7872
7916
  } else if (entry.name.startsWith(HATCH3R_PREFIX) || insideHatch3rDir || ALWAYS_COPY_FILES.has(entry.name)) {
7873
7917
  if (selectedIds && entry.name.startsWith(HATCH3R_PREFIX)) {
7874
7918
  const baseId = entry.name.replace(/\.(md|mdc)$/, "");
@@ -7919,7 +7963,7 @@ async function runPackageUpdate(rootDir, options = {}) {
7919
7963
  async function runRegenerate(rootDir, manifest, options = {}) {
7920
7964
  const offset = options.stepOffset ?? 0;
7921
7965
  const total = options.totalSteps ?? 3;
7922
- const agentsDir = join24(rootDir, AGENTS_DIR);
7966
+ const agentsDir = join26(rootDir, AGENTS_DIR);
7923
7967
  const contentRoot = findPackageRoot(__dirname3);
7924
7968
  const s1 = createSpinner(step(offset + 1, total, "Updating canonical files..."));
7925
7969
  s1.start();
@@ -7932,18 +7976,18 @@ async function runRegenerate(rootDir, manifest, options = {}) {
7932
7976
  }
7933
7977
  const copied = [];
7934
7978
  for (const dir of CONTENT_DIRS) {
7935
- const srcDir = join24(contentRoot, dir);
7979
+ const srcDir = join26(contentRoot, dir);
7936
7980
  try {
7937
- const dirCopied = await copyHatch3rFiles(srcDir, join24(agentsDir, dir), false, selectedIds);
7938
- copied.push(...dirCopied.map((p) => join24(dir, p)));
7981
+ const dirCopied = await copyHatch3rFiles(srcDir, join26(agentsDir, dir), false, selectedIds);
7982
+ copied.push(...dirCopied.map((p) => join26(dir, p)));
7939
7983
  } catch (err) {
7940
7984
  if (err.code !== "ENOENT") throw err;
7941
7985
  }
7942
7986
  }
7943
7987
  const canonicalAgentsMd = await generateCanonicalAgentsMd(agentsDir);
7944
- await safeWriteFile(join24(agentsDir, "AGENTS.md"), canonicalAgentsMd);
7988
+ await safeWriteFile(join26(agentsDir, "AGENTS.md"), canonicalAgentsMd);
7945
7989
  const rootAgentsMd = await generateRootAgentsMd(agentsDir);
7946
- await safeWriteFile(join24(rootDir, "AGENTS.md"), rootAgentsMd.full, {
7990
+ await safeWriteFile(join26(rootDir, "AGENTS.md"), rootAgentsMd.full, {
7947
7991
  managedContent: rootAgentsMd.inner
7948
7992
  });
7949
7993
  s1.succeed(step(offset + 1, total, `Updated ${copied.length} canonical files`));
@@ -7991,9 +8035,9 @@ async function runRegenerate(rootDir, manifest, options = {}) {
7991
8035
  const toolPaths = [];
7992
8036
  for (const out of outputs) {
7993
8037
  if (options.diff) {
7994
- diffBefore.set(out.path, await readFileOrNull(join24(rootDir, out.path)));
8038
+ diffBefore.set(out.path, await readFileOrNull(join26(rootDir, out.path)));
7995
8039
  }
7996
- const fullPath = join24(rootDir, out.path);
8040
+ const fullPath = join26(rootDir, out.path);
7997
8041
  if (out.managedContent) {
7998
8042
  await safeWriteFile(fullPath, out.content, {
7999
8043
  managedContent: out.managedContent
@@ -8004,7 +8048,7 @@ async function runRegenerate(rootDir, manifest, options = {}) {
8004
8048
  addManagedFile(manifest, out.path);
8005
8049
  toolPaths.push(out.path);
8006
8050
  if (options.diff) {
8007
- diffAfter.set(out.path, await readFileOrNull(join24(rootDir, out.path)));
8051
+ diffAfter.set(out.path, await readFileOrNull(join26(rootDir, out.path)));
8008
8052
  }
8009
8053
  }
8010
8054
  newManagedByAdapter[tool] = toolPaths;
@@ -8065,7 +8109,7 @@ async function runRegenerate(rootDir, manifest, options = {}) {
8065
8109
  const wtContent = await generateWorktreeInclude(manifest, rootDir);
8066
8110
  const wtManaged = extractManagedContent(wtContent);
8067
8111
  await safeWriteFile(
8068
- join24(rootDir, WORKTREE_INCLUDE_FILE),
8112
+ join26(rootDir, WORKTREE_INCLUDE_FILE),
8069
8113
  wtContent,
8070
8114
  { managedContent: wtManaged }
8071
8115
  );
@@ -8101,7 +8145,7 @@ async function runRegenerate(rootDir, manifest, options = {}) {
8101
8145
  };
8102
8146
  }
8103
8147
  async function runUpdateDryRun(rootDir, manifest, options = {}) {
8104
- const agentsDir = join24(rootDir, AGENTS_DIR);
8148
+ const agentsDir = join26(rootDir, AGENTS_DIR);
8105
8149
  const contentRoot = findPackageRoot(__dirname3);
8106
8150
  let selectedIds;
8107
8151
  if (manifest.content) {
@@ -8112,9 +8156,9 @@ async function runUpdateDryRun(rootDir, manifest, options = {}) {
8112
8156
  }
8113
8157
  const canonicalCandidates = [];
8114
8158
  for (const dir of CONTENT_DIRS) {
8115
- const srcDir = join24(contentRoot, dir);
8159
+ const srcDir = join26(contentRoot, dir);
8116
8160
  const entries = await enumerateHatch3rFiles(srcDir, false, selectedIds);
8117
- for (const rel of entries) canonicalCandidates.push(join24(dir, rel));
8161
+ for (const rel of entries) canonicalCandidates.push(join26(dir, rel));
8118
8162
  }
8119
8163
  const adapterChanges = /* @__PURE__ */ new Map();
8120
8164
  for (const tool of manifest.tools) {
@@ -8128,7 +8172,7 @@ async function runUpdateDryRun(rootDir, manifest, options = {}) {
8128
8172
  }
8129
8173
  const outputs = generationResult.outputs ?? [];
8130
8174
  for (const out of outputs) {
8131
- const existing = await readFileOrNull(join24(rootDir, out.path));
8175
+ const existing = await readFileOrNull(join26(rootDir, out.path));
8132
8176
  if (existing === null) bucket.added.push(out.path);
8133
8177
  else if (existing !== out.content) bucket.modified.push(out.path);
8134
8178
  else bucket.unchanged.push(out.path);
@@ -8168,7 +8212,7 @@ async function enumerateHatch3rFiles(srcDir, insideHatch3rDir, selectedIds) {
8168
8212
  }
8169
8213
  const out = [];
8170
8214
  for (const entry of entries) {
8171
- const srcPath = join24(srcDir, entry.name);
8215
+ const srcPath = join26(srcDir, entry.name);
8172
8216
  if (entry.isDirectory()) {
8173
8217
  if (selectedIds && entry.name.startsWith(HATCH3R_PREFIX)) {
8174
8218
  if (!selectedIds.has(entry.name)) continue;
@@ -8178,7 +8222,7 @@ async function enumerateHatch3rFiles(srcDir, insideHatch3rDir, selectedIds) {
8178
8222
  insideHatch3rDir || !entry.name.startsWith(HATCH3R_PREFIX),
8179
8223
  selectedIds
8180
8224
  );
8181
- out.push(...sub.map((p) => join24(entry.name, p)));
8225
+ out.push(...sub.map((p) => join26(entry.name, p)));
8182
8226
  } else if (entry.name.startsWith(HATCH3R_PREFIX) || insideHatch3rDir || ALWAYS_COPY_FILES.has(entry.name)) {
8183
8227
  if (selectedIds && entry.name.startsWith(HATCH3R_PREFIX)) {
8184
8228
  const baseId = entry.name.replace(/\.(md|mdc)$/, "");
@@ -8230,7 +8274,7 @@ async function updateCommand(_opts) {
8230
8274
  for (const notice of allNotices) {
8231
8275
  warn(notice);
8232
8276
  }
8233
- const agentsDir = join24(rootDir, AGENTS_DIR);
8277
+ const agentsDir = join26(rootDir, AGENTS_DIR);
8234
8278
  const integrityResults = await verifyIntegrity(agentsDir);
8235
8279
  const modified = integrityResults.filter((r) => r.status === "modified");
8236
8280
  const missing = integrityResults.filter((r) => r.status === "missing");
@@ -8375,7 +8419,7 @@ var init_update = __esm({
8375
8419
  id: "content-selections-init",
8376
8420
  condition: async (manifest) => manifest.content === void 0,
8377
8421
  execute: async (manifest, rootDir, headless) => {
8378
- const agentsDir = join24(rootDir, AGENTS_DIR);
8422
+ const agentsDir = join26(rootDir, AGENTS_DIR);
8379
8423
  const content = await buildSelectionsFromDisk(agentsDir);
8380
8424
  if (headless) {
8381
8425
  content.projectType = "brownfield";
@@ -8464,12 +8508,12 @@ var init_update = __esm({
8464
8508
  {
8465
8509
  id: "customize-yaml-size",
8466
8510
  condition: async (_manifest, rootDir) => {
8467
- const agentsDir = join24(rootDir, AGENTS_DIR);
8511
+ const agentsDir = join26(rootDir, AGENTS_DIR);
8468
8512
  try {
8469
8513
  const entries = await readdir11(agentsDir, { recursive: true });
8470
8514
  for (const entry of entries) {
8471
8515
  if (typeof entry === "string" && entry.endsWith(".customize.yaml")) {
8472
- const s = await stat6(join24(agentsDir, entry));
8516
+ const s = await stat6(join26(agentsDir, entry));
8473
8517
  if (s.size > 10240) return true;
8474
8518
  }
8475
8519
  }
@@ -8480,12 +8524,12 @@ var init_update = __esm({
8480
8524
  },
8481
8525
  execute: async (manifest, rootDir, _headless) => {
8482
8526
  const notices = [];
8483
- const agentsDir = join24(rootDir, AGENTS_DIR);
8527
+ const agentsDir = join26(rootDir, AGENTS_DIR);
8484
8528
  try {
8485
8529
  const entries = await readdir11(agentsDir, { recursive: true });
8486
8530
  for (const entry of entries) {
8487
8531
  if (typeof entry === "string" && entry.endsWith(".customize.yaml")) {
8488
- const s = await stat6(join24(agentsDir, entry));
8532
+ const s = await stat6(join26(agentsDir, entry));
8489
8533
  if (s.size > 10240) {
8490
8534
  notices.push(`Large customize file detected: ${entry} (${Math.round(s.size / 1024)}KB) \u2014 consider splitting`);
8491
8535
  }
@@ -8520,7 +8564,7 @@ var init_update = __esm({
8520
8564
  const notices = [];
8521
8565
  if (enabled) {
8522
8566
  const wtContent = await generateWorktreeInclude(updated, rootDir);
8523
- await safeWriteFile(join24(rootDir, WORKTREE_INCLUDE_FILE), wtContent, {
8567
+ await safeWriteFile(join26(rootDir, WORKTREE_INCLUDE_FILE), wtContent, {
8524
8568
  appendIfNoBlock: true
8525
8569
  });
8526
8570
  notices.push("Worktree isolation enabled \u2014 .worktreeinclude generated");
@@ -9036,14 +9080,14 @@ init_worktree();
9036
9080
  init_types();
9037
9081
  import { access as access9, mkdir as mkdir7, readFile as readFile18 } from "fs/promises";
9038
9082
  import { fileURLToPath as fileURLToPath2 } from "url";
9039
- import { basename as basename2, dirname as dirname10, join as join23 } from "path";
9083
+ import { basename as basename2, dirname as dirname10, join as join25 } from "path";
9040
9084
  import chalk5 from "chalk";
9041
9085
  import inquirer3 from "inquirer";
9042
9086
 
9043
9087
  // src/detect/repoAnalyzer.ts
9044
9088
  init_packageManager();
9045
9089
  import { access as access7, readFile as readFile14, readdir as readdir10 } from "fs/promises";
9046
- import { join as join18 } from "path";
9090
+ import { join as join20 } from "path";
9047
9091
  async function analyzeRepo(rootDir) {
9048
9092
  const [languages, pm, isMonorepo, hasExistingAgents, existingTools, frameworks, linters, testFrameworks, ciProviders] = await Promise.all([
9049
9093
  detectLanguages(rootDir),
@@ -9094,7 +9138,7 @@ async function detectLanguages(rootDir) {
9094
9138
  };
9095
9139
  for (const [lang, files] of Object.entries(indicators)) {
9096
9140
  for (const file of files) {
9097
- if (await pathExists(join18(rootDir, file))) {
9141
+ if (await pathExists(join20(rootDir, file))) {
9098
9142
  languages.push(lang);
9099
9143
  break;
9100
9144
  }
@@ -9114,13 +9158,13 @@ async function detectLanguages(rootDir) {
9114
9158
  return languages;
9115
9159
  }
9116
9160
  async function detectMonorepo(rootDir) {
9117
- if (await pathExists(join18(rootDir, "pnpm-workspace.yaml"))) return true;
9118
- if (await pathExists(join18(rootDir, "lerna.json"))) return true;
9119
- if (await pathExists(join18(rootDir, "nx.json"))) return true;
9120
- if (await pathExists(join18(rootDir, "turbo.json"))) return true;
9121
- if (await pathExists(join18(rootDir, "pants.toml"))) return true;
9161
+ if (await pathExists(join20(rootDir, "pnpm-workspace.yaml"))) return true;
9162
+ if (await pathExists(join20(rootDir, "lerna.json"))) return true;
9163
+ if (await pathExists(join20(rootDir, "nx.json"))) return true;
9164
+ if (await pathExists(join20(rootDir, "turbo.json"))) return true;
9165
+ if (await pathExists(join20(rootDir, "pants.toml"))) return true;
9122
9166
  try {
9123
- const pkgJson = await readFile14(join18(rootDir, "package.json"), "utf-8");
9167
+ const pkgJson = await readFile14(join20(rootDir, "package.json"), "utf-8");
9124
9168
  const pkg = JSON.parse(pkgJson);
9125
9169
  if (pkg.workspaces) return true;
9126
9170
  } catch (err) {
@@ -9130,11 +9174,11 @@ async function detectMonorepo(rootDir) {
9130
9174
  return false;
9131
9175
  }
9132
9176
  async function detectExistingAgents(rootDir) {
9133
- return pathExists(join18(rootDir, ".agents"));
9177
+ return pathExists(join20(rootDir, ".agents"));
9134
9178
  }
9135
9179
  var TOOL_INDICATORS = [
9136
9180
  { tool: "cursor", paths: [".cursor"] },
9137
- { tool: "copilot", paths: [join18(".github", "copilot-instructions.md")] },
9181
+ { tool: "copilot", paths: [join20(".github", "copilot-instructions.md")] },
9138
9182
  { tool: "claude", paths: ["CLAUDE.md", ".claude"] },
9139
9183
  { tool: "opencode", paths: ["opencode.json", "opencode.jsonc"] },
9140
9184
  { tool: "windsurf", paths: [".windsurfrules"] },
@@ -9153,7 +9197,7 @@ async function detectExistingTools(rootDir) {
9153
9197
  const results = await Promise.allSettled(
9154
9198
  TOOL_INDICATORS.map(async ({ tool, paths }) => {
9155
9199
  for (const p of paths) {
9156
- if (await pathExists(join18(rootDir, p))) return tool;
9200
+ if (await pathExists(join20(rootDir, p))) return tool;
9157
9201
  }
9158
9202
  return null;
9159
9203
  })
@@ -9203,7 +9247,7 @@ async function detectFrameworks(rootDir) {
9203
9247
  const configResults = await Promise.allSettled(
9204
9248
  FRAMEWORK_CONFIG_INDICATORS.map(async ({ framework, configs }) => {
9205
9249
  for (const cfg of configs) {
9206
- if (await pathExists(join18(rootDir, cfg))) return framework;
9250
+ if (await pathExists(join20(rootDir, cfg))) return framework;
9207
9251
  }
9208
9252
  return null;
9209
9253
  })
@@ -9214,7 +9258,7 @@ async function detectFrameworks(rootDir) {
9214
9258
  }
9215
9259
  }
9216
9260
  try {
9217
- const raw = await readFile14(join18(rootDir, "package.json"), "utf-8");
9261
+ const raw = await readFile14(join20(rootDir, "package.json"), "utf-8");
9218
9262
  const pkg = JSON.parse(raw);
9219
9263
  const allDeps = {
9220
9264
  ...pkg.dependencies,
@@ -9232,7 +9276,7 @@ async function detectFrameworks(rootDir) {
9232
9276
  const nonJsResults = await Promise.allSettled(
9233
9277
  NON_JS_FRAMEWORK_INDICATORS.map(async ({ framework, configs }) => {
9234
9278
  for (const cfg of configs) {
9235
- if (await pathExists(join18(rootDir, cfg))) return framework;
9279
+ if (await pathExists(join20(rootDir, cfg))) return framework;
9236
9280
  }
9237
9281
  return null;
9238
9282
  })
@@ -9268,7 +9312,7 @@ async function detectLinters(rootDir) {
9268
9312
  const results = await Promise.allSettled(
9269
9313
  LINTER_INDICATORS.map(async ({ name, configs }) => {
9270
9314
  for (const cfg of configs) {
9271
- if (await pathExists(join18(rootDir, cfg))) return name;
9315
+ if (await pathExists(join20(rootDir, cfg))) return name;
9272
9316
  }
9273
9317
  return null;
9274
9318
  })
@@ -9300,7 +9344,7 @@ async function detectTestFrameworks(rootDir) {
9300
9344
  const results = await Promise.allSettled(
9301
9345
  TEST_FRAMEWORK_INDICATORS.map(async ({ name, configs }) => {
9302
9346
  for (const cfg of configs) {
9303
- if (await pathExists(join18(rootDir, cfg))) return name;
9347
+ if (await pathExists(join20(rootDir, cfg))) return name;
9304
9348
  }
9305
9349
  return null;
9306
9350
  })
@@ -9329,7 +9373,7 @@ async function detectCIProviders(rootDir) {
9329
9373
  const results = await Promise.allSettled(
9330
9374
  CI_PROVIDER_INDICATORS.map(async ({ name, configs }) => {
9331
9375
  for (const cfg of configs) {
9332
- if (await pathExists(join18(rootDir, cfg))) return name;
9376
+ if (await pathExists(join20(rootDir, cfg))) return name;
9333
9377
  }
9334
9378
  return null;
9335
9379
  })
@@ -9545,7 +9589,7 @@ init_types();
9545
9589
  init_version();
9546
9590
  init_safeWrite();
9547
9591
  import { readFile as readFile16 } from "fs/promises";
9548
- import { join as join21, normalize as normalize2, isAbsolute as isAbsolute2 } from "path";
9592
+ import { join as join23, normalize as normalize2, isAbsolute as isAbsolute2 } from "path";
9549
9593
  function isUnsafeRepoPath(repoPath) {
9550
9594
  if (repoPath.includes("\0")) return true;
9551
9595
  if (isAbsolute2(repoPath)) return true;
@@ -9591,7 +9635,7 @@ function validateWorkspaceManifest(data) {
9591
9635
  return true;
9592
9636
  }
9593
9637
  async function readWorkspaceManifest(rootDir) {
9594
- const manifestPath = join21(rootDir, AGENTS_DIR, WORKSPACE_MANIFEST_FILE);
9638
+ const manifestPath = join23(rootDir, AGENTS_DIR, WORKSPACE_MANIFEST_FILE);
9595
9639
  let raw;
9596
9640
  try {
9597
9641
  raw = await readFile16(manifestPath, "utf-8");
@@ -9621,7 +9665,7 @@ async function readWorkspaceManifest(rootDir) {
9621
9665
  return parsed;
9622
9666
  }
9623
9667
  async function writeWorkspaceManifest(rootDir, manifest) {
9624
- const manifestPath = join21(rootDir, AGENTS_DIR, WORKSPACE_MANIFEST_FILE);
9668
+ const manifestPath = join23(rootDir, AGENTS_DIR, WORKSPACE_MANIFEST_FILE);
9625
9669
  await atomicWriteFile(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
9626
9670
  }
9627
9671
  function createWorkspaceManifest(name, defaults, repos, syncStrategy = "manual") {
@@ -9647,7 +9691,7 @@ init_agentsContent();
9647
9691
  init_paths();
9648
9692
  import { createHash as createHash4 } from "crypto";
9649
9693
  import { mkdir as mkdir6, access as access8, readFile as readFile17 } from "fs/promises";
9650
- import { join as join22, relative as relative3 } from "path";
9694
+ import { join as join24, relative as relative4 } from "path";
9651
9695
  import { fileURLToPath } from "url";
9652
9696
  import { dirname as dirname9 } from "path";
9653
9697
  init_mcpEnv();
@@ -9780,11 +9824,11 @@ async function estimateTokensForContent(contentIds, index) {
9780
9824
  for (const item of items) {
9781
9825
  try {
9782
9826
  if (item.type === "skill") {
9783
- const skillPath = join22(CONTENT_ROOT, item.relativePath, "SKILL.md");
9827
+ const skillPath = join24(CONTENT_ROOT, item.relativePath, "SKILL.md");
9784
9828
  const content = await readFile17(skillPath, "utf-8");
9785
9829
  totalChars += content.length;
9786
9830
  } else {
9787
- const filePath = join22(CONTENT_ROOT, item.relativePath);
9831
+ const filePath = join24(CONTENT_ROOT, item.relativePath);
9788
9832
  const content = await readFile17(filePath, "utf-8");
9789
9833
  totalChars += content.length;
9790
9834
  }
@@ -9804,7 +9848,7 @@ async function syncWorkspaceRepos(workspaceRoot, options = {}) {
9804
9848
  const protectedIds = new Set(
9805
9849
  index.items.filter((item) => item.protected).map((item) => item.id)
9806
9850
  );
9807
- const wsAgentsDir = join22(workspaceRoot, AGENTS_DIR);
9851
+ const wsAgentsDir = join24(workspaceRoot, AGENTS_DIR);
9808
9852
  const integrityResults = await verifyIntegrity(wsAgentsDir);
9809
9853
  const tampered = integrityResults.filter(
9810
9854
  (r) => r.status === "modified" || r.status === "tampered"
@@ -9857,8 +9901,8 @@ async function syncWorkspaceRepos(workspaceRoot, options = {}) {
9857
9901
  return { repos: results };
9858
9902
  }
9859
9903
  async function syncSingleRepo(workspaceRoot, wsManifest, wsChecksum, repoEntry, index, protectedIds, options) {
9860
- const repoDir = join22(workspaceRoot, repoEntry.path);
9861
- const repoAgentsDir = join22(repoDir, AGENTS_DIR);
9904
+ const repoDir = join24(workspaceRoot, repoEntry.path);
9905
+ const repoAgentsDir = join24(repoDir, AGENTS_DIR);
9862
9906
  try {
9863
9907
  await access8(repoDir);
9864
9908
  } catch {
@@ -9900,7 +9944,7 @@ async function syncSingleRepo(workspaceRoot, wsManifest, wsChecksum, repoEntry,
9900
9944
  }
9901
9945
  }
9902
9946
  const canonicalAgentsMd = await generateCanonicalAgentsMd(repoAgentsDir);
9903
- await safeWriteFile(join22(repoAgentsDir, "AGENTS.md"), canonicalAgentsMd, { force: true });
9947
+ await safeWriteFile(join24(repoAgentsDir, "AGENTS.md"), canonicalAgentsMd, { force: true });
9904
9948
  const repoInfo = await analyzeRepo(repoDir);
9905
9949
  let gitOwner = repoEntry.owner ?? "";
9906
9950
  let gitRepo = repoEntry.repo ?? "";
@@ -9932,7 +9976,7 @@ async function syncSingleRepo(workspaceRoot, wsManifest, wsChecksum, repoEntry,
9932
9976
  languages: repoInfo.languages
9933
9977
  });
9934
9978
  manifest.workspace = {
9935
- rootPath: relative3(repoDir, workspaceRoot),
9979
+ rootPath: relative4(repoDir, workspaceRoot),
9936
9980
  lastSync: (/* @__PURE__ */ new Date()).toISOString(),
9937
9981
  syncVersion: HATCH3R_VERSION,
9938
9982
  workspaceChecksum: wsChecksum,
@@ -9944,7 +9988,7 @@ async function syncSingleRepo(workspaceRoot, wsManifest, wsChecksum, repoEntry,
9944
9988
  }
9945
9989
  await writeManifest(repoDir, manifest);
9946
9990
  const rootAgentsMd = await generateRootAgentsMd(repoAgentsDir);
9947
- await safeWriteFile(join22(repoDir, "AGENTS.md"), rootAgentsMd.full, {
9991
+ await safeWriteFile(join24(repoDir, "AGENTS.md"), rootAgentsMd.full, {
9948
9992
  managedContent: rootAgentsMd.inner,
9949
9993
  appendIfNoBlock: true
9950
9994
  });
@@ -9958,7 +10002,7 @@ async function syncSingleRepo(workspaceRoot, wsManifest, wsChecksum, repoEntry,
9958
10002
  options.onWarn?.(w);
9959
10003
  }
9960
10004
  for (const out of outputs) {
9961
- await safeWriteFile(join22(repoDir, out.path), out.content, {
10005
+ await safeWriteFile(join24(repoDir, out.path), out.content, {
9962
10006
  managedContent: out.managedContent,
9963
10007
  appendIfNoBlock: true
9964
10008
  });
@@ -10095,8 +10139,8 @@ async function runInit(options) {
10095
10139
  }
10096
10140
  }
10097
10141
  async function runInitInner(options) {
10098
- const { rootDir, platform, owner, repo, namespace, project, defaultBranch, tools, features, mcpServers, repoInfo, contentSelection } = options;
10099
- const agentsDir = join23(rootDir, AGENTS_DIR);
10142
+ const { rootDir, platform, owner, repo, namespace, project, defaultBranch, tools, features, mcpServers, repoInfo, contentSelection, worktreeEnabled } = options;
10143
+ const agentsDir = join25(rootDir, AGENTS_DIR);
10100
10144
  const totalSteps = 4;
10101
10145
  const s1 = createSpinner(step(1, totalSteps, "Creating canonical files..."));
10102
10146
  s1.start();
@@ -10114,8 +10158,8 @@ async function runInitInner(options) {
10114
10158
  }
10115
10159
  }
10116
10160
  }
10117
- await mkdir7(join23(agentsDir, "learnings"), { recursive: true });
10118
- const learningsReadmePath = join23(agentsDir, "learnings", "README.md");
10161
+ await mkdir7(join25(agentsDir, "learnings"), { recursive: true });
10162
+ const learningsReadmePath = join25(agentsDir, "learnings", "README.md");
10119
10163
  try {
10120
10164
  await access9(learningsReadmePath);
10121
10165
  } catch (err) {
@@ -10125,7 +10169,7 @@ async function runInitInner(options) {
10125
10169
  throw err;
10126
10170
  }
10127
10171
  }
10128
- const mcpPath = join23(agentsDir, "mcp", "mcp.json");
10172
+ const mcpPath = join25(agentsDir, "mcp", "mcp.json");
10129
10173
  try {
10130
10174
  const mcpRaw = await readFile18(mcpPath, "utf-8");
10131
10175
  const mcpParsed = JSON.parse(mcpRaw);
@@ -10149,18 +10193,18 @@ async function runInitInner(options) {
10149
10193
  if (!isExpected) throw err;
10150
10194
  }
10151
10195
  const canonicalAgentsMd = await generateCanonicalAgentsMd(agentsDir);
10152
- await safeWriteFile(join23(agentsDir, "AGENTS.md"), canonicalAgentsMd, { force: true });
10196
+ await safeWriteFile(join25(agentsDir, "AGENTS.md"), canonicalAgentsMd, { force: true });
10153
10197
  s1.succeed(step(1, totalSteps, `Canonical files created (${countSelectionItems(contentSelection)} items)`));
10154
10198
  const s2 = createSpinner(step(2, totalSteps, "Preparing manifest..."));
10155
10199
  s2.start();
10156
- const manifest = createManifest({ platform, owner, repo, namespace, project, defaultBranch, tools, features, mcpServers, content: contentSelection, languages: repoInfo.languages });
10200
+ const manifest = createManifest({ platform, owner, repo, namespace, project, defaultBranch, tools, features, mcpServers, content: contentSelection, languages: repoInfo.languages, worktreeEnabled });
10157
10201
  s2.succeed(step(2, totalSteps, "Manifest prepared"));
10158
10202
  const s3 = createSpinner(
10159
10203
  step(3, totalSteps, `Generating ${tools.map((t) => TOOL_DISPLAY_NAMES[t] ?? t).join(", ")} output...`)
10160
10204
  );
10161
10205
  s3.start();
10162
10206
  const rootAgentsMd = await generateRootAgentsMd(agentsDir);
10163
- await safeWriteFile(join23(rootDir, "AGENTS.md"), rootAgentsMd.full, {
10207
+ await safeWriteFile(join25(rootDir, "AGENTS.md"), rootAgentsMd.full, {
10164
10208
  managedContent: rootAgentsMd.inner,
10165
10209
  appendIfNoBlock: true
10166
10210
  });
@@ -10176,7 +10220,7 @@ async function runInitInner(options) {
10176
10220
  }
10177
10221
  const toolPaths = [];
10178
10222
  for (const out of outputs) {
10179
- await safeWriteFile(join23(rootDir, out.path), out.content, {
10223
+ await safeWriteFile(join25(rootDir, out.path), out.content, {
10180
10224
  managedContent: out.managedContent,
10181
10225
  appendIfNoBlock: true
10182
10226
  });
@@ -10207,14 +10251,10 @@ async function runInitInner(options) {
10207
10251
  warn(w);
10208
10252
  }
10209
10253
  }
10210
- const hasWorktreeTool = tools.some((t) => WORKTREE_CAPABLE_TOOLS.has(t));
10211
- if (hasWorktreeTool) {
10212
- manifest.worktree = manifest.worktree ?? { enabled: true };
10213
- }
10214
10254
  if (manifest.worktree?.enabled) {
10215
10255
  const wtContent = await generateWorktreeInclude(manifest, rootDir);
10216
10256
  const wtManaged = extractManagedContent(wtContent);
10217
- await safeWriteFile(join23(rootDir, WORKTREE_INCLUDE_FILE), wtContent, {
10257
+ await safeWriteFile(join25(rootDir, WORKTREE_INCLUDE_FILE), wtContent, {
10218
10258
  managedContent: wtManaged,
10219
10259
  appendIfNoBlock: true
10220
10260
  });
@@ -10274,7 +10314,7 @@ async function runInitInner(options) {
10274
10314
  printBox("Hatch complete", summaryLines, "success");
10275
10315
  }
10276
10316
  async function checkExisting(rootDir, skipPrompt, newSelection) {
10277
- const hatchJsonPath = join23(rootDir, AGENTS_DIR, "hatch.json");
10317
+ const hatchJsonPath = join25(rootDir, AGENTS_DIR, "hatch.json");
10278
10318
  try {
10279
10319
  await access9(hatchJsonPath);
10280
10320
  if (!skipPrompt) {
@@ -10400,6 +10440,7 @@ async function initCommand(opts = {}) {
10400
10440
  } else {
10401
10441
  tools2 = DEFAULT_TOOLS;
10402
10442
  }
10443
+ const worktreeEnabled2 = opts.worktree ?? tools2.some((t) => WORKTREE_CAPABLE_TOOLS.has(t));
10403
10444
  const features2 = { ...DEFAULT_FEATURES };
10404
10445
  const platformMcp = PLATFORM_MCP_SERVER[platform2];
10405
10446
  const mcpServers2 = features2.mcp ? Array.from(/* @__PURE__ */ new Set([platformMcp, ...DEFAULT_MCP.filter((s) => s !== "github")])) : [];
@@ -10418,7 +10459,7 @@ async function initCommand(opts = {}) {
10418
10459
  }
10419
10460
  warnBoardPrerequisites(contentSelection2);
10420
10461
  await checkExisting(rootDir, true, contentSelection2);
10421
- await runInit({ rootDir, platform: platform2, owner: owner2, repo: repo2, namespace: namespace2, project: project2, defaultBranch: defaultBranch2, tools: tools2, features: features2, mcpServers: mcpServers2, repoInfo, contentSelection: contentSelection2 });
10462
+ await runInit({ rootDir, platform: platform2, owner: owner2, repo: repo2, namespace: namespace2, project: project2, defaultBranch: defaultBranch2, tools: tools2, features: features2, mcpServers: mcpServers2, repoInfo, contentSelection: contentSelection2, worktreeEnabled: worktreeEnabled2 });
10422
10463
  return;
10423
10464
  }
10424
10465
  console.log();
@@ -10571,6 +10612,21 @@ async function initCommand(opts = {}) {
10571
10612
  }
10572
10613
  ]);
10573
10614
  const tools = toolAnswers.tools.length > 0 ? toolAnswers.tools : DEFAULT_TOOLS;
10615
+ const hasWorktreeTool = tools.some((t) => WORKTREE_CAPABLE_TOOLS.has(t));
10616
+ let worktreeEnabled;
10617
+ if (opts.worktree !== void 0) {
10618
+ worktreeEnabled = opts.worktree;
10619
+ } else if (hasWorktreeTool) {
10620
+ const wtAnswer = await inquirer3.prompt([{
10621
+ type: "confirm",
10622
+ name: "enabled",
10623
+ message: "Enable worktree file isolation (for parallel agent sessions)?",
10624
+ default: true
10625
+ }]);
10626
+ worktreeEnabled = wtAnswer.enabled;
10627
+ } else {
10628
+ worktreeEnabled = false;
10629
+ }
10574
10630
  const secretNotes = tools.map((t) => TOOL_SECRET_NOTES[t]).filter(Boolean);
10575
10631
  if (secretNotes.length > 0) {
10576
10632
  info(chalk5.dim("MCP secret loading by tool:"));
@@ -10621,7 +10677,7 @@ async function initCommand(opts = {}) {
10621
10677
  }
10622
10678
  warnBoardPrerequisites(contentSelection);
10623
10679
  await checkExisting(rootDir, false, contentSelection);
10624
- await runInit({ rootDir, platform, owner, repo, namespace, project, defaultBranch, tools, features, mcpServers, repoInfo, contentSelection });
10680
+ await runInit({ rootDir, platform, owner, repo, namespace, project, defaultBranch, tools, features, mcpServers, repoInfo, contentSelection, worktreeEnabled });
10625
10681
  }
10626
10682
  async function runWorkspaceInit(rootDir, detectedRepos, repoInfo, opts) {
10627
10683
  const headless = !!opts.yes;
@@ -10649,7 +10705,7 @@ async function runWorkspaceInit(rootDir, detectedRepos, repoInfo, opts) {
10649
10705
  }
10650
10706
  const enriched = detectedRepos.map((r) => ({
10651
10707
  ...r,
10652
- ...detectRepoGitIdentity(join23(rootDir, r.path))
10708
+ ...detectRepoGitIdentity(join25(rootDir, r.path))
10653
10709
  }));
10654
10710
  wsSpinner.succeed(`Workspace: ${detectedRepos.length} repo(s) detected`);
10655
10711
  console.log();
@@ -10706,8 +10762,10 @@ async function runWorkspaceInit(rootDir, detectedRepos, repoInfo, opts) {
10706
10762
  let features;
10707
10763
  let mcpServers;
10708
10764
  let contentSelection;
10765
+ let worktreeEnabled;
10709
10766
  if (headless) {
10710
10767
  tools = resolveToolsFromOpts(opts.tools, repoInfo);
10768
+ worktreeEnabled = opts.worktree ?? tools.some((t) => WORKTREE_CAPABLE_TOOLS.has(t));
10711
10769
  features = { ...DEFAULT_FEATURES };
10712
10770
  const platformMcp = PLATFORM_MCP_SERVER[platform];
10713
10771
  mcpServers = features.mcp ? Array.from(/* @__PURE__ */ new Set([platformMcp, ...DEFAULT_MCP.filter((s) => s !== "github")])) : [];
@@ -10803,6 +10861,20 @@ async function runWorkspaceInit(rootDir, detectedRepos, repoInfo, opts) {
10803
10861
  }
10804
10862
  ]);
10805
10863
  tools = toolAnswers.tools.length > 0 ? toolAnswers.tools : DEFAULT_TOOLS;
10864
+ const wsHasWorktreeTool = tools.some((t) => WORKTREE_CAPABLE_TOOLS.has(t));
10865
+ if (opts.worktree !== void 0) {
10866
+ worktreeEnabled = opts.worktree;
10867
+ } else if (wsHasWorktreeTool) {
10868
+ const wsWtAnswer = await inquirer3.prompt([{
10869
+ type: "confirm",
10870
+ name: "enabled",
10871
+ message: "Enable worktree file isolation (for parallel agent sessions)?",
10872
+ default: true
10873
+ }]);
10874
+ worktreeEnabled = wsWtAnswer.enabled;
10875
+ } else {
10876
+ worktreeEnabled = false;
10877
+ }
10806
10878
  const wsSecretNotes = tools.map((t) => TOOL_SECRET_NOTES[t]).filter(Boolean);
10807
10879
  if (wsSecretNotes.length > 0) {
10808
10880
  info(chalk5.dim("MCP secret loading by tool:"));
@@ -10866,7 +10938,8 @@ async function runWorkspaceInit(rootDir, detectedRepos, repoInfo, opts) {
10866
10938
  features,
10867
10939
  mcpServers,
10868
10940
  repoInfo,
10869
- contentSelection
10941
+ contentSelection,
10942
+ worktreeEnabled
10870
10943
  });
10871
10944
  let repoEntries;
10872
10945
  if (headless) {
@@ -10995,7 +11068,8 @@ function captureConfig(manifest) {
10995
11068
  projectType: "brownfield",
10996
11069
  teamSize: "solo",
10997
11070
  items: { agents: [], skills: [], rules: [], commands: [], prompts: [], hooks: [], githubAgents: [] }
10998
- }
11071
+ },
11072
+ worktreeEnabled: manifest.worktree?.enabled ?? false
10999
11073
  };
11000
11074
  }
11001
11075
  function printInventory(inventory) {
@@ -11130,7 +11204,8 @@ async function cleanCommand(opts = {}) {
11130
11204
  features: config.features,
11131
11205
  mcpServers: config.mcpServers,
11132
11206
  repoInfo,
11133
- contentSelection: config.contentSelection
11207
+ contentSelection: config.contentSelection,
11208
+ worktreeEnabled: config.worktreeEnabled
11134
11209
  };
11135
11210
  await runInit(initOpts);
11136
11211
  if (learningsBackup) {
@@ -11191,7 +11266,7 @@ init_archive();
11191
11266
  init_paths();
11192
11267
  import { fileURLToPath as fileURLToPath4 } from "url";
11193
11268
  import { readFile as readFile21 } from "fs/promises";
11194
- import { dirname as dirname13, join as join25 } from "path";
11269
+ import { dirname as dirname13, join as join27 } from "path";
11195
11270
  import chalk8 from "chalk";
11196
11271
  import inquirer6 from "inquirer";
11197
11272
  init_content();
@@ -11426,7 +11501,7 @@ async function configCommand() {
11426
11501
  );
11427
11502
  console.log();
11428
11503
  const contentRoot = findPackageRoot(__dirname4);
11429
- const agentsDir = join25(rootDir, AGENTS_DIR);
11504
+ const agentsDir = join27(rootDir, AGENTS_DIR);
11430
11505
  const index = await buildContentIndex(contentRoot);
11431
11506
  const previousContent = manifest.content;
11432
11507
  const { projectType, teamSize } = manifest.content;
@@ -11480,7 +11555,7 @@ async function configCommand() {
11480
11555
  const keepItem = index.byId.get(keepId);
11481
11556
  if (!keepItem) continue;
11482
11557
  try {
11483
- const filePath = keepItem.type === "skill" ? join25(agentsDir, keepItem.relativePath, "SKILL.md") : join25(agentsDir, keepItem.relativePath);
11558
+ const filePath = keepItem.type === "skill" ? join27(agentsDir, keepItem.relativePath, "SKILL.md") : join27(agentsDir, keepItem.relativePath);
11484
11559
  const content = await readFile21(filePath, "utf-8");
11485
11560
  const refs = extractContentReferences(content);
11486
11561
  if (refs.includes(removedId)) {
@@ -11528,9 +11603,9 @@ async function configCommand() {
11528
11603
  contentMetadataChanged = previousContent.preset !== newSelection.preset || previousContent.projectType !== newSelection.projectType || previousContent.teamSize !== newSelection.teamSize;
11529
11604
  if (contentChanges.added.length > 0 || contentChanges.removed.length > 0) {
11530
11605
  const canonicalAgentsMd = await generateCanonicalAgentsMd(agentsDir);
11531
- await safeWriteFile(join25(agentsDir, "AGENTS.md"), canonicalAgentsMd);
11606
+ await safeWriteFile(join27(agentsDir, "AGENTS.md"), canonicalAgentsMd);
11532
11607
  const rootAgentsMd = await generateRootAgentsMd(agentsDir);
11533
- await safeWriteFile(join25(rootDir, "AGENTS.md"), rootAgentsMd.full, {
11608
+ await safeWriteFile(join27(rootDir, "AGENTS.md"), rootAgentsMd.full, {
11534
11609
  managedContent: rootAgentsMd.inner
11535
11610
  });
11536
11611
  }
@@ -11598,7 +11673,7 @@ async function configCommand() {
11598
11673
  if (manifest.worktree?.enabled) {
11599
11674
  const wtContent = await generateWorktreeInclude(manifest, rootDir);
11600
11675
  const wtManaged = extractManagedContent(wtContent);
11601
- await safeWriteFile(join25(rootDir, WORKTREE_INCLUDE_FILE), wtContent, {
11676
+ await safeWriteFile(join27(rootDir, WORKTREE_INCLUDE_FILE), wtContent, {
11602
11677
  managedContent: wtManaged
11603
11678
  });
11604
11679
  }
@@ -11764,7 +11839,7 @@ async function configCommand() {
11764
11839
  ]);
11765
11840
  if (editIdentity === "detect") {
11766
11841
  for (const repo2 of wsManifestFinal.repos) {
11767
- const identity = detectRepoGitIdentity(join25(rootDir, repo2.path));
11842
+ const identity = detectRepoGitIdentity(join27(rootDir, repo2.path));
11768
11843
  repo2.owner = identity.owner || void 0;
11769
11844
  repo2.repo = identity.repo || void 0;
11770
11845
  repo2.defaultBranch = identity.defaultBranch || void 0;
@@ -11863,7 +11938,7 @@ async function configCommand() {
11863
11938
  init_hatchJson();
11864
11939
  init_adapters();
11865
11940
  import { appendFile as appendFile2, readFile as readFile23, stat as stat7, readdir as readdir12 } from "fs/promises";
11866
- import { join as join27 } from "path";
11941
+ import { join as join29 } from "path";
11867
11942
  import { execFileSync as execFileSync5 } from "child_process";
11868
11943
  import chalk9 from "chalk";
11869
11944
 
@@ -11925,10 +12000,10 @@ init_integrity();
11925
12000
  // src/integrity/provenance.ts
11926
12001
  init_safeWrite();
11927
12002
  import { readFile as readFile22 } from "fs/promises";
11928
- import { join as join26, relative as relative5, posix as posix2, sep as sep2 } from "path";
12003
+ import { join as join28, relative as relative6, posix as posix2, sep as sep2 } from "path";
11929
12004
  var PROVENANCE_FILE = ".provenance.json";
11930
12005
  function normalizeToRepoPath(absPath, rootDir) {
11931
- const rel = relative5(rootDir, absPath);
12006
+ const rel = relative6(rootDir, absPath);
11932
12007
  return sep2 === "/" ? rel : rel.split(sep2).join(posix2.sep);
11933
12008
  }
11934
12009
  function buildProvenanceManifest(hatchVersion, rootDir, perAdapterOutputs) {
@@ -11956,7 +12031,7 @@ function buildProvenanceManifest(hatchVersion, rootDir, perAdapterOutputs) {
11956
12031
  };
11957
12032
  }
11958
12033
  async function writeProvenanceManifest(agentsDir, manifest) {
11959
- const filePath = join26(agentsDir, PROVENANCE_FILE);
12034
+ const filePath = join28(agentsDir, PROVENANCE_FILE);
11960
12035
  await atomicWriteFile(filePath, JSON.stringify(manifest, null, 2) + "\n");
11961
12036
  }
11962
12037
 
@@ -11972,7 +12047,7 @@ init_phaseOutputSchema();
11972
12047
  init_retryWithBackoff();
11973
12048
  init_ui();
11974
12049
  async function checkSpecFreshness(rootDir) {
11975
- const specsDir = join27(rootDir, "docs", "specs");
12050
+ const specsDir = join29(rootDir, "docs", "specs");
11976
12051
  try {
11977
12052
  await stat7(specsDir);
11978
12053
  } catch {
@@ -11984,7 +12059,7 @@ async function checkSpecFreshness(rootDir) {
11984
12059
  for (const entry of entries) {
11985
12060
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
11986
12061
  const parentPath = entry.parentPath ?? entry.path ?? specsDir;
11987
- const fileStat = await stat7(join27(parentPath, entry.name));
12062
+ const fileStat = await stat7(join29(parentPath, entry.name));
11988
12063
  if (fileStat.mtimeMs < oldestSpecMtime) {
11989
12064
  oldestSpecMtime = fileStat.mtimeMs;
11990
12065
  }
@@ -12008,7 +12083,7 @@ async function checkSpecFreshness(rootDir) {
12008
12083
  }
12009
12084
  async function appendFailure2(agentsDir, phase, error2, tool) {
12010
12085
  try {
12011
- const logPath = join27(agentsDir, FAILURE_LOG_FILE);
12086
+ const logPath = join29(agentsDir, FAILURE_LOG_FILE);
12012
12087
  const entry = createFailureLogEntry(phase, error2, {
12013
12088
  tool,
12014
12089
  version: HATCH3R_VERSION
@@ -12048,7 +12123,7 @@ async function syncCommand(opts = {}) {
12048
12123
  `This repository appears to be managed by a workspace at ${wsContext.workspaceRoot ?? ".."}. Run ${chalk9.cyan("hatch3r sync")} from the workspace root to sync all repos.`
12049
12124
  );
12050
12125
  }
12051
- const agentsDir = join27(rootDir, AGENTS_DIR);
12126
+ const agentsDir = join29(rootDir, AGENTS_DIR);
12052
12127
  const manifest = await readManifest(rootDir);
12053
12128
  if (!manifest) {
12054
12129
  error("No .agents/hatch.json found.");
@@ -12092,8 +12167,8 @@ async function syncCommand(opts = {}) {
12092
12167
  const diffBefore = /* @__PURE__ */ new Map();
12093
12168
  const diffAfter = /* @__PURE__ */ new Map();
12094
12169
  if (opts.diff) {
12095
- diffBefore.set("AGENTS.md", await readFileOrNull2(join27(rootDir, "AGENTS.md")));
12096
- diffBefore.set(`${AGENTS_DIR}/AGENTS.md`, await readFileOrNull2(join27(agentsDir, "AGENTS.md")));
12170
+ diffBefore.set("AGENTS.md", await readFileOrNull2(join29(rootDir, "AGENTS.md")));
12171
+ diffBefore.set(`${AGENTS_DIR}/AGENTS.md`, await readFileOrNull2(join29(agentsDir, "AGENTS.md")));
12097
12172
  }
12098
12173
  const s1 = createSpinner(step(++currentStep, totalSteps, "Syncing AGENTS.md..."));
12099
12174
  s1.start();
@@ -12107,18 +12182,18 @@ async function syncCommand(opts = {}) {
12107
12182
  diffAfter.set(`${AGENTS_DIR}/AGENTS.md`, canonicalAgentsMd);
12108
12183
  }
12109
12184
  } else {
12110
- const agentsMdResult = await safeWriteFile(join27(rootDir, "AGENTS.md"), rootAgentsMd.full, {
12185
+ const agentsMdResult = await safeWriteFile(join29(rootDir, "AGENTS.md"), rootAgentsMd.full, {
12111
12186
  managedContent: rootAgentsMd.inner
12112
12187
  });
12113
12188
  if (agentsMdResult.warning) warn(agentsMdResult.warning);
12114
12189
  results.push({ path: "AGENTS.md", action: agentsMdResult.action });
12115
12190
  const canonicalAgentsMd = await generateCanonicalAgentsMd(agentsDir);
12116
- const canonicalResult = await safeWriteFile(join27(agentsDir, "AGENTS.md"), canonicalAgentsMd);
12191
+ const canonicalResult = await safeWriteFile(join29(agentsDir, "AGENTS.md"), canonicalAgentsMd);
12117
12192
  if (canonicalResult.warning) warn(canonicalResult.warning);
12118
12193
  results.push({ path: `${AGENTS_DIR}/AGENTS.md`, action: canonicalResult.action });
12119
12194
  if (opts.diff) {
12120
- diffAfter.set("AGENTS.md", await readFileOrNull2(join27(rootDir, "AGENTS.md")));
12121
- diffAfter.set(`${AGENTS_DIR}/AGENTS.md`, await readFileOrNull2(join27(agentsDir, "AGENTS.md")));
12195
+ diffAfter.set("AGENTS.md", await readFileOrNull2(join29(rootDir, "AGENTS.md")));
12196
+ diffAfter.set(`${AGENTS_DIR}/AGENTS.md`, await readFileOrNull2(join29(agentsDir, "AGENTS.md")));
12122
12197
  }
12123
12198
  }
12124
12199
  s1.succeed(step(currentStep, totalSteps, opts.dryRun ? "AGENTS.md (dry run)" : "AGENTS.md synced"));
@@ -12199,16 +12274,16 @@ async function syncCommand(opts = {}) {
12199
12274
  for (const out of outputs) {
12200
12275
  results.push({ path: out.path, action: "dry-run" });
12201
12276
  if (opts.diff) {
12202
- diffBefore.set(out.path, await readFileOrNull2(join27(rootDir, out.path)));
12277
+ diffBefore.set(out.path, await readFileOrNull2(join29(rootDir, out.path)));
12203
12278
  diffAfter.set(out.path, out.content);
12204
12279
  }
12205
12280
  }
12206
12281
  } else {
12207
12282
  for (const out of outputs) {
12208
12283
  if (opts.diff) {
12209
- diffBefore.set(out.path, await readFileOrNull2(join27(rootDir, out.path)));
12284
+ diffBefore.set(out.path, await readFileOrNull2(join29(rootDir, out.path)));
12210
12285
  }
12211
- const fullPath = join27(rootDir, out.path);
12286
+ const fullPath = join29(rootDir, out.path);
12212
12287
  if (out.managedContent) {
12213
12288
  const result = await safeWriteFile(fullPath, out.content, {
12214
12289
  managedContent: out.managedContent
@@ -12223,7 +12298,7 @@ async function syncCommand(opts = {}) {
12223
12298
  results.push({ path: out.path, action: result.action });
12224
12299
  }
12225
12300
  if (opts.diff) {
12226
- diffAfter.set(out.path, await readFileOrNull2(join27(rootDir, out.path)));
12301
+ diffAfter.set(out.path, await readFileOrNull2(join29(rootDir, out.path)));
12227
12302
  }
12228
12303
  }
12229
12304
  }
@@ -12285,7 +12360,7 @@ async function syncCommand(opts = {}) {
12285
12360
  const wtContent = await generateWorktreeInclude(m, rootDir);
12286
12361
  const wtManaged = extractManagedContent(wtContent);
12287
12362
  const wtResult = await safeWriteFile(
12288
- join27(rootDir, WORKTREE_INCLUDE_FILE),
12363
+ join29(rootDir, WORKTREE_INCLUDE_FILE),
12289
12364
  wtContent,
12290
12365
  { managedContent: wtManaged }
12291
12366
  );
@@ -12346,7 +12421,7 @@ async function syncCommand(opts = {}) {
12346
12421
  const CUSTOMIZE_DIRS = ["agents", "commands", "skills", "rules"];
12347
12422
  for (const dir of CUSTOMIZE_DIRS) {
12348
12423
  try {
12349
- const files = await readdir12(join27(rootDir, ".hatch3r", dir));
12424
+ const files = await readdir12(join29(rootDir, ".hatch3r", dir));
12350
12425
  for (const f of files.filter((f2) => f2.endsWith(".customize.yaml") || f2.endsWith(".customize.md"))) {
12351
12426
  const itemId = f.replace(/\.customize\.(yaml|md)$/, "");
12352
12427
  const prefixed = `hatch3r-${itemId}`;
@@ -12460,7 +12535,7 @@ init_content();
12460
12535
  init_paths();
12461
12536
  import { readdir as readdir15, readFile as readFile26, access as access11 } from "fs/promises";
12462
12537
  import { existsSync as existsSync3 } from "fs";
12463
- import { dirname as dirname15, join as join30, posix as posix3 } from "path";
12538
+ import { dirname as dirname15, join as join32, posix as posix3 } from "path";
12464
12539
  import { fileURLToPath as fileURLToPath6 } from "url";
12465
12540
  import chalk10 from "chalk";
12466
12541
  import { parse as parseYaml4 } from "yaml";
@@ -12468,7 +12543,7 @@ import { parse as parseYaml4 } from "yaml";
12468
12543
  // src/content/learningsValidation.ts
12469
12544
  init_customization();
12470
12545
  import { readFile as readFile24, readdir as readdir13 } from "fs/promises";
12471
- import { join as join28 } from "path";
12546
+ import { join as join30 } from "path";
12472
12547
  var MAX_LEARNING_FILE_BYTES = 65536;
12473
12548
  var MAX_LEARNINGS_TOTAL_BYTES = 524288;
12474
12549
  var MAX_LEARNING_FILE_COUNT = 50;
@@ -12572,7 +12647,7 @@ async function validateLearningsDirectory(learningsDir) {
12572
12647
  const nameErrors = validateLearningFileName(file);
12573
12648
  errors.push(...nameErrors);
12574
12649
  try {
12575
- const content = await readFile24(join28(learningsDir, file), "utf-8");
12650
+ const content = await readFile24(join30(learningsDir, file), "utf-8");
12576
12651
  const byteLength = Buffer.byteLength(content, "utf-8");
12577
12652
  totalBytes += byteLength;
12578
12653
  const result = validateLearningContent(content, file);
@@ -12743,7 +12818,7 @@ function detectSecrets(envVars) {
12743
12818
  // src/pipeline/complianceVerification.ts
12744
12819
  init_agentToolAllowlist();
12745
12820
  import { readFile as readFile25, readdir as readdir14 } from "fs/promises";
12746
- import { dirname as dirname14, join as join29 } from "path";
12821
+ import { dirname as dirname14, join as join31 } from "path";
12747
12822
  import { fileURLToPath as fileURLToPath5 } from "url";
12748
12823
 
12749
12824
  // src/pipeline/reviewLoop.ts
@@ -12782,9 +12857,9 @@ var RESILIENCE_MODULES = [
12782
12857
  var __dirname5 = dirname14(fileURLToPath5(import.meta.url));
12783
12858
  async function resolveCommandsDir() {
12784
12859
  const candidates = [
12785
- join29(__dirname5, "..", "cli", "commands"),
12786
- join29(__dirname5, "..", "..", "src", "cli", "commands"),
12787
- join29(__dirname5, "..", "cli")
12860
+ join31(__dirname5, "..", "cli", "commands"),
12861
+ join31(__dirname5, "..", "..", "src", "cli", "commands"),
12862
+ join31(__dirname5, "..", "cli")
12788
12863
  ];
12789
12864
  for (const candidate of candidates) {
12790
12865
  try {
@@ -12805,7 +12880,7 @@ async function detectResilienceInvocations() {
12805
12880
  } catch {
12806
12881
  return invoked;
12807
12882
  }
12808
- const files = entries.filter((e) => typeof e === "string" && (e.endsWith(".ts") || e.endsWith(".js"))).map((e) => join29(commandsDir, e));
12883
+ const files = entries.filter((e) => typeof e === "string" && (e.endsWith(".ts") || e.endsWith(".js"))).map((e) => join31(commandsDir, e));
12809
12884
  const patterns = {};
12810
12885
  for (const mod of RESILIENCE_MODULES) {
12811
12886
  patterns[mod] = new RegExp(`pipeline/${mod}(?:\\.js)?["']`);
@@ -12998,7 +13073,7 @@ async function validateManifest2(rootDir, manifest, result) {
12998
13073
  if (!manifest.tools || manifest.tools.length === 0) result.warnings.push("hatch.json: no tools configured");
12999
13074
  for (const managedFile of manifest.managedFiles ?? []) {
13000
13075
  try {
13001
- await access11(join30(rootDir, managedFile));
13076
+ await access11(join32(rootDir, managedFile));
13002
13077
  } catch (err) {
13003
13078
  if (err.code !== "ENOENT") throw err;
13004
13079
  result.warnings.push(`Managed file missing from disk: ${managedFile}`);
@@ -13010,7 +13085,7 @@ async function validateDirectories(agentsDir, result) {
13010
13085
  const optionalDirs = ["commands", "prompts", "mcp", "policy", "github-agents"];
13011
13086
  for (const dir of requiredDirs) {
13012
13087
  try {
13013
- await access11(join30(agentsDir, dir));
13088
+ await access11(join32(agentsDir, dir));
13014
13089
  } catch (err) {
13015
13090
  if (err.code !== "ENOENT") throw err;
13016
13091
  result.errors.push(`Required directory missing: .agents/${dir}/`);
@@ -13018,7 +13093,7 @@ async function validateDirectories(agentsDir, result) {
13018
13093
  }
13019
13094
  for (const dir of optionalDirs) {
13020
13095
  try {
13021
- await access11(join30(agentsDir, dir));
13096
+ await access11(join32(agentsDir, dir));
13022
13097
  } catch (err) {
13023
13098
  if (err.code !== "ENOENT") throw err;
13024
13099
  result.warnings.push(`Optional directory missing: .agents/${dir}/`);
@@ -13029,12 +13104,12 @@ async function validateFrontmatter(agentsDir, result) {
13029
13104
  const requiredDirs = ["agents", "skills", "rules"];
13030
13105
  const optionalDirs = ["commands", "prompts", "mcp", "policy", "github-agents"];
13031
13106
  for (const dir of [...requiredDirs, ...optionalDirs]) {
13032
- const dirPath = join30(agentsDir, dir);
13107
+ const dirPath = join32(agentsDir, dir);
13033
13108
  try {
13034
13109
  const entries = await readdir15(dirPath, { withFileTypes: true });
13035
13110
  for (const entry of entries) {
13036
13111
  if (entry.isFile() && entry.name.endsWith(".md")) {
13037
- const filePath = join30(dirPath, entry.name);
13112
+ const filePath = join32(dirPath, entry.name);
13038
13113
  const content = await readFile26(filePath, "utf-8");
13039
13114
  if (!content.startsWith("---")) {
13040
13115
  result.warnings.push(`Missing frontmatter: .agents/${dir}/${entry.name}`);
@@ -13057,7 +13132,7 @@ async function validateFrontmatter(agentsDir, result) {
13057
13132
  }
13058
13133
  }
13059
13134
  } else if (entry.isDirectory()) {
13060
- const skillPath = join30(dirPath, entry.name, "SKILL.md");
13135
+ const skillPath = join32(dirPath, entry.name, "SKILL.md");
13061
13136
  try {
13062
13137
  await access11(skillPath);
13063
13138
  } catch (err) {
@@ -13071,7 +13146,7 @@ async function validateFrontmatter(agentsDir, result) {
13071
13146
  }
13072
13147
  }
13073
13148
  try {
13074
- await access11(join30(agentsDir, "AGENTS.md"));
13149
+ await access11(join32(agentsDir, "AGENTS.md"));
13075
13150
  } catch (err) {
13076
13151
  if (err.code !== "ENOENT") throw err;
13077
13152
  result.warnings.push("Missing .agents/AGENTS.md");
@@ -13138,7 +13213,7 @@ async function validateManagedFilePrefixes(manifest, result) {
13138
13213
  }
13139
13214
  async function validateHooks(agentsDir, manifest, result) {
13140
13215
  if (!manifest.features.hooks) return;
13141
- const hooksDir = join30(agentsDir, "hooks");
13216
+ const hooksDir = join32(agentsDir, "hooks");
13142
13217
  try {
13143
13218
  const hookFiles = await readdir15(hooksDir);
13144
13219
  const mdHooks = hookFiles.filter((f) => f.endsWith(".md"));
@@ -13147,13 +13222,13 @@ async function validateHooks(agentsDir, manifest, result) {
13147
13222
  }
13148
13223
  let agentFiles;
13149
13224
  try {
13150
- const agentEntries = await readdir15(join30(agentsDir, "agents"));
13225
+ const agentEntries = await readdir15(join32(agentsDir, "agents"));
13151
13226
  agentFiles = new Set(agentEntries.filter((f) => f.endsWith(".md")));
13152
13227
  } catch (err) {
13153
13228
  if (err.code !== "ENOENT") throw err;
13154
13229
  }
13155
13230
  for (const hookFile of mdHooks) {
13156
- const hookContent = await readFile26(join30(hooksDir, hookFile), "utf-8");
13231
+ const hookContent = await readFile26(join32(hooksDir, hookFile), "utf-8");
13157
13232
  if (!hookContent.startsWith("---")) {
13158
13233
  result.warnings.push(`Hook missing frontmatter: .agents/hooks/${hookFile}`);
13159
13234
  continue;
@@ -13185,7 +13260,7 @@ async function validateHooks(agentsDir, manifest, result) {
13185
13260
  }
13186
13261
  async function validateMcp(agentsDir, manifest, result) {
13187
13262
  if (!manifest.features.mcp || manifest.mcp.servers.length === 0) return;
13188
- const mcpPath = join30(agentsDir, "mcp", "mcp.json");
13263
+ const mcpPath = join32(agentsDir, "mcp", "mcp.json");
13189
13264
  try {
13190
13265
  const mcpContent = await readFile26(mcpPath, "utf-8");
13191
13266
  const mcpParsed = JSON.parse(mcpContent);
@@ -13242,7 +13317,7 @@ async function validateCustomizeYaml(rootDir, result) {
13242
13317
  enabled: "boolean"
13243
13318
  };
13244
13319
  for (const { dir } of CUSTOMIZATION_TYPES) {
13245
- const customDir = join30(rootDir, ".hatch3r", dir);
13320
+ const customDir = join32(rootDir, ".hatch3r", dir);
13246
13321
  let files;
13247
13322
  try {
13248
13323
  files = await readdir15(customDir);
@@ -13252,7 +13327,7 @@ async function validateCustomizeYaml(rootDir, result) {
13252
13327
  }
13253
13328
  const yamlFiles = files.filter((f) => f.endsWith(".customize.yaml"));
13254
13329
  for (const file of yamlFiles) {
13255
- const filePath = join30(customDir, file);
13330
+ const filePath = join32(customDir, file);
13256
13331
  const itemId = file.replace(".customize.yaml", "");
13257
13332
  let raw;
13258
13333
  try {
@@ -13319,13 +13394,13 @@ async function validateCustomizeYaml(rootDir, result) {
13319
13394
  }
13320
13395
  async function validateCustomizations(rootDir, agentsDir, manifest, result) {
13321
13396
  for (const { dir, canonical } of CUSTOMIZATION_TYPES) {
13322
- const customDir = join30(rootDir, ".hatch3r", dir);
13397
+ const customDir = join32(rootDir, ".hatch3r", dir);
13323
13398
  try {
13324
13399
  const customFiles = await readdir15(customDir);
13325
13400
  for (const file of customFiles) {
13326
13401
  if (file.endsWith(".customize.yaml")) {
13327
13402
  const itemId = file.replace(".customize.yaml", "");
13328
- const canonicalPath = canonical === "skills" ? join30(agentsDir, canonical, itemId) : join30(agentsDir, canonical, `${itemId}.md`);
13403
+ const canonicalPath = canonical === "skills" ? join32(agentsDir, canonical, itemId) : join32(agentsDir, canonical, `${itemId}.md`);
13329
13404
  try {
13330
13405
  await access11(canonicalPath);
13331
13406
  } catch (err) {
@@ -13353,7 +13428,7 @@ async function validateContentConsistency(rootDir, agentsDir, manifest, result)
13353
13428
  for (const [key, cfg] of Object.entries(contentDirs)) {
13354
13429
  const ids = manifest.content.items[key];
13355
13430
  for (const id of ids) {
13356
- const checkPath = cfg.strategy === "subdir" ? join30(agentsDir, cfg.dir, id, "SKILL.md") : join30(agentsDir, cfg.dir, `${id}.md`);
13431
+ const checkPath = cfg.strategy === "subdir" ? join32(agentsDir, cfg.dir, id, "SKILL.md") : join32(agentsDir, cfg.dir, `${id}.md`);
13357
13432
  try {
13358
13433
  await access11(checkPath);
13359
13434
  } catch {
@@ -13366,7 +13441,7 @@ async function validateContentConsistency(rootDir, agentsDir, manifest, result)
13366
13441
  for (const id of ids) allContentIds.add(id);
13367
13442
  }
13368
13443
  for (const { dir } of CUSTOMIZATION_TYPES) {
13369
- const customDir = join30(rootDir, ".hatch3r", dir);
13444
+ const customDir = join32(rootDir, ".hatch3r", dir);
13370
13445
  try {
13371
13446
  const files = await readdir15(customDir);
13372
13447
  for (const f of files.filter((f2) => f2.endsWith(".customize.yaml") || f2.endsWith(".customize.md"))) {
@@ -13380,7 +13455,7 @@ async function validateContentConsistency(rootDir, agentsDir, manifest, result)
13380
13455
  }
13381
13456
  }
13382
13457
  }
13383
- const learningsDir = join30(agentsDir, "learnings");
13458
+ const learningsDir = join32(agentsDir, "learnings");
13384
13459
  const learningsResult = await validateLearningsDirectory(learningsDir);
13385
13460
  for (const e of learningsResult.errors) {
13386
13461
  result.errors.push(e);
@@ -13500,12 +13575,12 @@ async function validateDocsCounts(rootDir) {
13500
13575
  let checked = 0;
13501
13576
  const actual = {};
13502
13577
  const dirs = [
13503
- ["adapters", join30(rootDir, "src/adapters"), (e) => e.endsWith(".ts") && !["base.ts", "index.ts", "canonical.ts", "customization.ts", "types.ts", "mcp-utils.ts", "toml-utils.ts", "contextBudget.ts", "agentsmd.ts"].includes(e)],
13504
- ["commands", join30(rootDir, "src/cli/commands"), (e) => e.endsWith(".ts")],
13505
- ["agents", join30(rootDir, "agents"), (e) => e.endsWith(".md")],
13506
- ["skills", join30(rootDir, "skills"), (e) => true],
13507
- ["rules", join30(rootDir, "rules"), (e) => e.endsWith(".md")],
13508
- ["hooks", join30(rootDir, "hooks"), (e) => e.endsWith(".md")]
13578
+ ["adapters", join32(rootDir, "src/adapters"), (e) => e.endsWith(".ts") && !["base.ts", "index.ts", "canonical.ts", "customization.ts", "types.ts", "mcp-utils.ts", "toml-utils.ts", "contextBudget.ts", "agentsmd.ts"].includes(e)],
13579
+ ["commands", join32(rootDir, "src/cli/commands"), (e) => e.endsWith(".ts")],
13580
+ ["agents", join32(rootDir, "agents"), (e) => e.endsWith(".md")],
13581
+ ["skills", join32(rootDir, "skills"), (e) => true],
13582
+ ["rules", join32(rootDir, "rules"), (e) => e.endsWith(".md")],
13583
+ ["hooks", join32(rootDir, "hooks"), (e) => e.endsWith(".md")]
13509
13584
  ];
13510
13585
  for (const [name, dir, filter] of dirs) {
13511
13586
  try {
@@ -13519,7 +13594,7 @@ async function validateDocsCounts(rootDir) {
13519
13594
  actual[name] = 0;
13520
13595
  }
13521
13596
  }
13522
- const readmePath = join30(rootDir, "README.md");
13597
+ const readmePath = join32(rootDir, "README.md");
13523
13598
  try {
13524
13599
  const readme = await readFile26(readmePath, "utf-8");
13525
13600
  const countPatterns = [
@@ -13593,11 +13668,11 @@ async function validateCommand(opts) {
13593
13668
  }
13594
13669
  return;
13595
13670
  }
13596
- const agentsDir = join30(rootDir, AGENTS_DIR);
13671
+ const agentsDir = join32(rootDir, AGENTS_DIR);
13597
13672
  const result = { errors: [], warnings: [] };
13598
13673
  const spinner = jsonMode ? null : createSpinner("Validating .agents/ structure...");
13599
13674
  spinner?.start();
13600
- const cwdIsFrameworkSource = existsSync3(join30(rootDir, "agents")) && existsSync3(join30(rootDir, "skills")) && existsSync3(join30(rootDir, "rules")) && existsSync3(join30(rootDir, "commands"));
13675
+ const cwdIsFrameworkSource = existsSync3(join32(rootDir, "agents")) && existsSync3(join32(rootDir, "skills")) && existsSync3(join32(rootDir, "rules")) && existsSync3(join32(rootDir, "commands"));
13601
13676
  try {
13602
13677
  await access11(agentsDir);
13603
13678
  } catch (err) {
@@ -13752,7 +13827,7 @@ async function validateCommand(opts) {
13752
13827
  let hasCustomizations = false;
13753
13828
  for (const { dir } of CUSTOMIZATION_TYPES) {
13754
13829
  try {
13755
- const files = await readdir15(join30(rootDir, ".hatch3r", dir));
13830
+ const files = await readdir15(join32(rootDir, ".hatch3r", dir));
13756
13831
  if (files.some((f) => f.endsWith(".customize.yaml") || f.endsWith(".customize.md"))) {
13757
13832
  hasCustomizations = true;
13758
13833
  break;
@@ -13818,7 +13893,7 @@ async function validateCommand(opts) {
13818
13893
  }
13819
13894
  }
13820
13895
  async function validateEnvMcpSecrets(rootDir, result) {
13821
- const envMcpPath = join30(rootDir, ".env.mcp");
13896
+ const envMcpPath = join32(rootDir, ".env.mcp");
13822
13897
  if (!existsSync3(envMcpPath)) return;
13823
13898
  try {
13824
13899
  const raw = await readFile26(envMcpPath, "utf-8");
@@ -13838,7 +13913,7 @@ async function validateEnvMcpSecrets(rootDir, result) {
13838
13913
  async function validateCanonicalDescriptionQuality(rootDir, result) {
13839
13914
  const __filename = fileURLToPath6(import.meta.url);
13840
13915
  const packageRoot = findPackageRoot(dirname15(__filename));
13841
- const canonicalRoot = existsSync3(join30(rootDir, "agents")) && existsSync3(join30(rootDir, "skills")) && existsSync3(join30(rootDir, "rules")) && existsSync3(join30(rootDir, "commands")) ? rootDir : packageRoot;
13916
+ const canonicalRoot = existsSync3(join32(rootDir, "agents")) && existsSync3(join32(rootDir, "skills")) && existsSync3(join32(rootDir, "rules")) && existsSync3(join32(rootDir, "commands")) ? rootDir : packageRoot;
13842
13917
  try {
13843
13918
  const index = await buildContentIndex(canonicalRoot);
13844
13919
  if (index.items.length === 0) return;
@@ -13884,7 +13959,7 @@ init_pipelineTimeout();
13884
13959
  init_phaseOutputSchema();
13885
13960
  init_retryWithBackoff();
13886
13961
  init_ui();
13887
- import { join as join31 } from "path";
13962
+ import { join as join33 } from "path";
13888
13963
  import chalk11 from "chalk";
13889
13964
  async function runVerifyPass(agentsDir) {
13890
13965
  const results = await verifyIntegrity(agentsDir);
@@ -13938,7 +14013,7 @@ async function verifyCommand(options = {}) {
13938
14013
  DEFAULT_PIPELINE_TIMEOUT_MS
13939
14014
  );
13940
14015
  const rootDir = process.cwd();
13941
- const agentsDir = join31(rootDir, AGENTS_DIR);
14016
+ const agentsDir = join33(rootDir, AGENTS_DIR);
13942
14017
  const spinner = createSpinner("Verifying file integrity...");
13943
14018
  spinner.start();
13944
14019
  const manifest = await readIntegrityManifest(agentsDir);
@@ -14075,7 +14150,7 @@ init_managedBlocks();
14075
14150
  init_integrity();
14076
14151
  init_ui();
14077
14152
  import { access as access12, readFile as readFile27, readdir as readdir16, stat as stat8 } from "fs/promises";
14078
- import { join as join32 } from "path";
14153
+ import { join as join34 } from "path";
14079
14154
  import chalk12 from "chalk";
14080
14155
  async function dirCharCount(dir) {
14081
14156
  let total = 0;
@@ -14086,7 +14161,7 @@ async function dirCharCount(dir) {
14086
14161
  return 0;
14087
14162
  }
14088
14163
  for (const entry of entries) {
14089
- const fullPath = join32(dir, entry.name);
14164
+ const fullPath = join34(dir, entry.name);
14090
14165
  if (entry.isDirectory()) {
14091
14166
  total += await dirCharCount(fullPath);
14092
14167
  } else if (entry.isFile()) {
@@ -14122,7 +14197,7 @@ async function runFastStatusCheck(rootDir, agentsDir, manifest) {
14122
14197
  verbose(`${tool}: ${paths.length} output path(s) to check (fast path)`);
14123
14198
  fileLines.push(chalk12.bold(`${tool}:`));
14124
14199
  for (const p of paths) {
14125
- const destPath = join32(rootDir, p);
14200
+ const destPath = join34(rootDir, p);
14126
14201
  try {
14127
14202
  const fileStat = await stat8(destPath);
14128
14203
  if (fileStat.mtimeMs > sealMs) {
@@ -14150,7 +14225,7 @@ async function runDeepStatusCheck(rootDir, agentsDir, manifest) {
14150
14225
  verbose(`${tool}: ${outputs.length} output file(s) to check`);
14151
14226
  fileLines.push(chalk12.bold(`${tool}:`));
14152
14227
  for (const out of outputs) {
14153
- const destPath = join32(rootDir, out.path);
14228
+ const destPath = join34(rootDir, out.path);
14154
14229
  try {
14155
14230
  const existing = await readFile27(destPath, "utf-8");
14156
14231
  const existingBlock = extractManagedBlock(existing);
@@ -14175,7 +14250,7 @@ async function statusCommand(opts) {
14175
14250
  setVerbose(!!opts?.verbose);
14176
14251
  printBanner(true);
14177
14252
  const rootDir = process.cwd();
14178
- const agentsDir = join32(rootDir, AGENTS_DIR);
14253
+ const agentsDir = join34(rootDir, AGENTS_DIR);
14179
14254
  const manifest = await readManifest(rootDir);
14180
14255
  if (!manifest) {
14181
14256
  error("No .agents/hatch.json found.");
@@ -14228,7 +14303,7 @@ async function statusCommand(opts) {
14228
14303
  console.log();
14229
14304
  }
14230
14305
  if (manifest.tools.includes("codex")) {
14231
- const overridePath = join32(rootDir, "AGENTS.override.md");
14306
+ const overridePath = join34(rootDir, "AGENTS.override.md");
14232
14307
  try {
14233
14308
  await access12(overridePath);
14234
14309
  warn(
@@ -14319,7 +14394,7 @@ function createProgram() {
14319
14394
  program2.command("init").description("Install a complete agent setup into the current repo (first-run: creates .agents/ directory)").option(
14320
14395
  "--tools <tools>",
14321
14396
  `Comma-separated tools (${TOOL_CHOICES})`
14322
- ).option("--yes", "Skip interactive prompts, use defaults").option("--quick", "Skip all prompts and use smart defaults (alias for --yes)").option("--default", "Skip all prompts and use smart defaults (alias for --yes)").option("--preset <preset>", "Content preset: minimal, standard, full (default: full)").option("--project-type <type>", "Project type: greenfield, brownfield").option("--team-size <size>", "Team size: solo, team").option("--workspace", "Initialize as a multi-repo workspace").action(initCommand);
14397
+ ).option("--yes", "Skip interactive prompts, use defaults").option("--quick", "Skip all prompts and use smart defaults (alias for --yes)").option("--default", "Skip all prompts and use smart defaults (alias for --yes)").option("--preset <preset>", "Content preset: minimal, standard, full (default: full)").option("--project-type <type>", "Project type: greenfield, brownfield").option("--team-size <size>", "Team size: solo, team").option("--worktree", "Enable git worktree file isolation (overrides tool auto-detect)").option("--no-worktree", "Disable git worktree file isolation").option("--workspace", "Initialize as a multi-repo workspace").action(initCommand);
14323
14398
  program2.command("sync").description("Re-generate tool outputs from canonical .agents/ state (run after editing .agents/)").option("--repos [paths...]", "Sync workspace content to sub-repos (all opted-in if no paths given)").option("--dry-run", "Show what would change without modifying files").option("--diff", "Show a before/after diff summary for each generated file").option("--force", "Overwrite locally modified files in sub-repos").option("--minimal", "Generate stripped-down output (no comments, minimal formatting) to reduce token usage").option("--strict-budget", "Fail sync if any adapter's generated output exceeds its context budget (default: warn)").option("--verbose", "Show detailed output for each file processed").action(syncCommand);
14324
14399
  program2.command("status").description("Check sync status between canonical .agents/ and generated files").option("--verbose", "Show detailed per-file status information").option("--deep", "Regenerate every adapter's output in-memory to compare byte-for-byte (slower; default uses integrity-manifest fast path)").action(statusCommand);
14325
14400
  program2.command("update").description("Pull latest hatch3r templates with safe merge (preserves customizations)").option("--yes", "Skip interactive prompts, use defaults").option("--diff", "Show a before/after diff summary for each generated file").option("--force", "Override the preflight integrity check and proceed despite drift").option("--offline, --skip-fetch", "Skip the package fetch step; regenerate only from already-installed canonical content").option("--dry-run", "Preview what would change (added/modified/unchanged per adapter) without writing files").action(updateCommand);