dlw-machine-setup 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/bin/installer.js +67 -84
  2. package/package.json +1 -1
package/bin/installer.js CHANGED
@@ -3295,9 +3295,9 @@ ${page}${helpTipBottom}${choiceDescription}${import_ansi_escapes4.default.cursor
3295
3295
  });
3296
3296
 
3297
3297
  // src/index.ts
3298
- var import_fs18 = require("fs");
3298
+ var import_fs17 = require("fs");
3299
3299
  var import_readline2 = require("readline");
3300
- var import_path18 = require("path");
3300
+ var import_path17 = require("path");
3301
3301
 
3302
3302
  // src/utils/fetch.ts
3303
3303
  var DEFAULT_TIMEOUT_MS = 3e4;
@@ -3956,7 +3956,6 @@ __export(steps_exports, {
3956
3956
  fetchFactory: () => fetch_factory_default,
3957
3957
  runMcpInstallCommands: () => run_mcp_install_commands_default,
3958
3958
  setupCodeIndex: () => build_code_index_default,
3959
- setupProjectInput: () => create_project_input_default,
3960
3959
  updateGitignore: () => update_gitignore_default,
3961
3960
  writeInstructions: () => write_instructions_default,
3962
3961
  writeMcpConfig: () => write_mcp_config_default,
@@ -4293,6 +4292,10 @@ var claudeCodeProfile = {
4293
4292
  // Claude exposes a top-level `statusLine` setting in settings.json.
4294
4293
  // Bundles gate statusline-related ops with `when: 'statusline-supported'`.
4295
4294
  statusLineSupported: true,
4295
+ // Claude Code is the only runtime with agent teams. Bundles gate
4296
+ // team-only ops with `when: 'agent-teams-opted-in'`, which also requires
4297
+ // the user's install-time opt-in (ctx.optIns.agentTeams).
4298
+ agentTeamsSupported: true,
4296
4299
  handlers: {
4297
4300
  agent: {
4298
4301
  supported: true,
@@ -4475,6 +4478,7 @@ function runBundleV2(manifest, ctx) {
4475
4478
  for (const op of manifest.ops ?? []) {
4476
4479
  if (op.when === "hooks-supported" && !profile.handlers.hook.supported) continue;
4477
4480
  if (op.when === "statusline-supported" && !profile.statusLineSupported) continue;
4481
+ if (op.when === "agent-teams-opted-in" && !(profile.agentTeamsSupported && ctx.optIns?.agentTeams)) continue;
4478
4482
  const substituted = substituteHookDir(op, profile);
4479
4483
  if (substituted.op === "merge-json") {
4480
4484
  const existing = mergePatches.get(substituted.file);
@@ -4733,7 +4737,7 @@ var fetch_factory_default = defineStep({
4733
4737
  label: "Installing Factory framework",
4734
4738
  when: (ctx) => ctx.config.installFactory && !!ctx.factoryRepo,
4735
4739
  execute: async (ctx) => {
4736
- const result = await fetchFactory(ctx.token, ctx.factoryRepo, ctx.config.projectPath, ctx.config.agent);
4740
+ const result = await fetchFactory(ctx.token, ctx.factoryRepo, ctx.config.projectPath, ctx.config.agent, ctx.config.agentTeams);
4737
4741
  ctx.installed.factoryInstalled = result.success;
4738
4742
  if (result.instructionsSnippet) {
4739
4743
  ctx.installed.factoryInstructionsSnippet = result.instructionsSnippet;
@@ -4791,7 +4795,7 @@ var fetch_factory_default = defineStep({
4791
4795
  }
4792
4796
  }
4793
4797
  });
4794
- async function fetchFactory(token, repo, targetDir, agent) {
4798
+ async function fetchFactory(token, repo, targetDir, agent, agentTeams) {
4795
4799
  const result = {
4796
4800
  success: false,
4797
4801
  filesInstalled: [],
@@ -4826,7 +4830,7 @@ async function fetchFactory(token, repo, targetDir, agent) {
4826
4830
  result.failureReason = "Factory archive has no install.json \u2014 upgrade Factory or downgrade installer";
4827
4831
  return result;
4828
4832
  }
4829
- await installViaBundle(manifestPath, extractedPath, targetDir, agent, result);
4833
+ await installViaBundle(manifestPath, extractedPath, targetDir, agent, agentTeams, result);
4830
4834
  result.success = true;
4831
4835
  } catch (error) {
4832
4836
  result.failureReason = error instanceof Error ? error.message : String(error);
@@ -4835,7 +4839,7 @@ async function fetchFactory(token, repo, targetDir, agent) {
4835
4839
  }
4836
4840
  return result;
4837
4841
  }
4838
- async function installViaBundle(manifestPath, extractedPath, targetDir, agent, result) {
4842
+ async function installViaBundle(manifestPath, extractedPath, targetDir, agent, agentTeams, result) {
4839
4843
  let manifest;
4840
4844
  try {
4841
4845
  manifest = JSON.parse((0, import_fs9.readFileSync)(manifestPath, "utf-8"));
@@ -4848,8 +4852,10 @@ async function installViaBundle(manifestPath, extractedPath, targetDir, agent, r
4848
4852
  projectPath: targetDir,
4849
4853
  agent,
4850
4854
  instructionsFile: target.instructions,
4851
- skipInstructions: true
4855
+ skipInstructions: true,
4852
4856
  // write-instructions.ts commits the snippet for correct ordering
4857
+ optIns: { agentTeams }
4858
+ // gates the experimental agent-teams env-var op
4853
4859
  });
4854
4860
  result.instructionsSnippet = runResult.instructionsSnippet;
4855
4861
  result.filesInstalled = runResult.filesTouched;
@@ -5572,47 +5578,9 @@ function isNodeAvailable() {
5572
5578
  return probeResult.status === 0;
5573
5579
  }
5574
5580
 
5575
- // src/steps/setup/create-project-input.ts
5581
+ // src/steps/setup/update-gitignore.ts
5576
5582
  var import_fs14 = require("fs");
5577
5583
  var import_path14 = require("path");
5578
- var INPUT_DIR = ".project/input";
5579
- var KEEP_FILE = `${INPUT_DIR}/.gitkeep`;
5580
- var create_project_input_default = defineStep({
5581
- name: "create-project-input",
5582
- label: "Creating .project/input folder",
5583
- execute: async (ctx) => {
5584
- const dirAbs = (0, import_path14.join)(ctx.config.projectPath, INPUT_DIR);
5585
- const keepAbs = (0, import_path14.join)(ctx.config.projectPath, KEEP_FILE);
5586
- const dirExistedBefore = (0, import_fs14.existsSync)(dirAbs);
5587
- if (!dirExistedBefore) (0, import_fs14.mkdirSync)(dirAbs, { recursive: true });
5588
- const keepFileCreated = !(0, import_fs14.existsSync)(keepAbs);
5589
- if (keepFileCreated) (0, import_fs14.writeFileSync)(keepAbs, "", "utf-8");
5590
- const record = {
5591
- keepFile: KEEP_FILE,
5592
- dirExistedBefore,
5593
- keepFileCreated
5594
- };
5595
- return { status: "success", message: INPUT_DIR, record };
5596
- },
5597
- inverse: {
5598
- label: "Removing .project/input folder",
5599
- execute: async (raw, ctx) => {
5600
- const rec = raw ?? {};
5601
- if (rec.keepFileCreated && rec.keepFile) {
5602
- const keepAbs = resolveProjectPath(rec.keepFile, ctx.config.projectPath);
5603
- deleteFileIfExists(keepAbs);
5604
- }
5605
- if (!rec.dirExistedBefore && rec.keepFile) {
5606
- pruneEmptyAncestors([rec.keepFile], ctx.config.projectPath);
5607
- }
5608
- return { status: "success", message: INPUT_DIR };
5609
- }
5610
- }
5611
- });
5612
-
5613
- // src/steps/setup/update-gitignore.ts
5614
- var import_fs15 = require("fs");
5615
- var import_path15 = require("path");
5616
5584
  var MARKER_START2 = "# one-shot-installer:start";
5617
5585
  var MARKER_END2 = "# one-shot-installer:end";
5618
5586
  var CORE_GITIGNORE_ENTRIES = [
@@ -5633,8 +5601,8 @@ var update_gitignore_default = defineStep({
5633
5601
  name: "update-gitignore",
5634
5602
  label: "Updating .gitignore",
5635
5603
  execute: async (ctx) => {
5636
- const gitignorePath = (0, import_path15.join)(ctx.config.projectPath, ".gitignore");
5637
- const fileExistedBefore = (0, import_fs15.existsSync)(gitignorePath);
5604
+ const gitignorePath = (0, import_path14.join)(ctx.config.projectPath, ".gitignore");
5605
+ const fileExistedBefore = (0, import_fs14.existsSync)(gitignorePath);
5638
5606
  upsertMarkerBlock(gitignorePath, MARKER_START2, MARKER_END2, CORE_GITIGNORE_ENTRIES.join("\n"));
5639
5607
  const record = {
5640
5608
  filePath: ".gitignore",
@@ -5662,8 +5630,8 @@ var update_gitignore_default = defineStep({
5662
5630
  });
5663
5631
 
5664
5632
  // src/steps/setup/write-state.ts
5665
- var import_fs16 = require("fs");
5666
- var import_path16 = require("path");
5633
+ var import_fs15 = require("fs");
5634
+ var import_path15 = require("path");
5667
5635
  var import_os2 = require("os");
5668
5636
 
5669
5637
  // package.json
@@ -5697,7 +5665,7 @@ var write_state_default = defineStep({
5697
5665
  name: "write-state",
5698
5666
  label: "Saving installation state",
5699
5667
  execute: async (ctx) => {
5700
- const statePath = (0, import_path16.join)(ctx.config.projectPath, ".one-shot-state.json");
5668
+ const statePath = (0, import_path15.join)(ctx.config.projectPath, ".one-shot-state.json");
5701
5669
  const mcpServersAdded = ctx.installed.mcpServersAdded ?? [];
5702
5670
  const filteredMcpConfig = Object.fromEntries(
5703
5671
  Object.entries(ctx.config.mcpConfig).filter(([name]) => mcpServersAdded.includes(name))
@@ -5728,13 +5696,13 @@ var write_state_default = defineStep({
5728
5696
  * mislead the uninstall preview which reads this field. */
5729
5697
  factory: ctx.installed.factoryInstalled ? ".claude/" : null,
5730
5698
  abapHooks: ctx.installed.abapHooksInstalled ? ".claude/hooks/" : null,
5731
- globalConfig: (0, import_path16.join)((0, import_os2.homedir)(), ".one-shot-installer")
5699
+ globalConfig: (0, import_path15.join)((0, import_os2.homedir)(), ".one-shot-installer")
5732
5700
  }
5733
5701
  };
5734
5702
  if (ctx.journal) {
5735
5703
  ctx.journal.setSummary(state);
5736
5704
  } else {
5737
- (0, import_fs16.writeFileSync)(statePath, JSON.stringify(state, null, 2), "utf-8");
5705
+ (0, import_fs15.writeFileSync)(statePath, JSON.stringify(state, null, 2), "utf-8");
5738
5706
  }
5739
5707
  return { status: "success" };
5740
5708
  },
@@ -5749,9 +5717,9 @@ var write_state_default = defineStep({
5749
5717
  });
5750
5718
 
5751
5719
  // src/uninstall.ts
5752
- var import_fs17 = require("fs");
5720
+ var import_fs16 = require("fs");
5753
5721
  var import_readline = require("readline");
5754
- var import_path17 = require("path");
5722
+ var import_path16 = require("path");
5755
5723
  var dim = (text) => `\x1B[2m${text}\x1B[0m`;
5756
5724
  var yellow = (text) => `\x1B[33m${text}\x1B[0m`;
5757
5725
  var red3 = (text) => `\x1B[31m${text}\x1B[0m`;
@@ -5771,11 +5739,11 @@ async function uninstall() {
5771
5739
  try {
5772
5740
  const projectInput = await esm_default4({
5773
5741
  message: "Project directory to uninstall from:",
5774
- default: (0, import_path17.resolve)(process.cwd())
5742
+ default: (0, import_path16.resolve)(process.cwd())
5775
5743
  });
5776
- const projectPath = (0, import_path17.resolve)(projectInput);
5777
- const statePath = (0, import_path17.join)(projectPath, ".one-shot-state.json");
5778
- if (!(0, import_fs17.existsSync)(statePath)) {
5744
+ const projectPath = (0, import_path16.resolve)(projectInput);
5745
+ const statePath = (0, import_path16.join)(projectPath, ".one-shot-state.json");
5746
+ if (!(0, import_fs16.existsSync)(statePath)) {
5779
5747
  console.log("");
5780
5748
  console.log(red3(" No .one-shot-state.json found at:"));
5781
5749
  console.log(` ${statePath}`);
@@ -5800,7 +5768,7 @@ async function uninstall() {
5800
5768
  default: false
5801
5769
  });
5802
5770
  if (proceed2) {
5803
- (0, import_fs17.unlinkSync)(statePath);
5771
+ (0, import_fs16.unlinkSync)(statePath);
5804
5772
  console.log(" Removed .one-shot-state.json");
5805
5773
  }
5806
5774
  await waitForEnter();
@@ -5827,7 +5795,8 @@ async function uninstall() {
5827
5795
  mcpConfig: {},
5828
5796
  releaseVersion: "",
5829
5797
  installFactory: false,
5830
- installAbapHooks: false
5798
+ installAbapHooks: false,
5799
+ agentTeams: false
5831
5800
  },
5832
5801
  token: "",
5833
5802
  repo: "",
@@ -5841,7 +5810,7 @@ async function uninstall() {
5841
5810
  console.log("");
5842
5811
  const result = await runRollback(stepList, ctx);
5843
5812
  try {
5844
- if ((0, import_fs17.existsSync)(statePath)) (0, import_fs17.unlinkSync)(statePath);
5813
+ if ((0, import_fs16.existsSync)(statePath)) (0, import_fs16.unlinkSync)(statePath);
5845
5814
  } catch {
5846
5815
  }
5847
5816
  printSummary(result);
@@ -5853,7 +5822,7 @@ async function uninstall() {
5853
5822
  }
5854
5823
  function readSummary(statePath) {
5855
5824
  try {
5856
- const raw = JSON.parse((0, import_fs17.readFileSync)(statePath, "utf-8"));
5825
+ const raw = JSON.parse((0, import_fs16.readFileSync)(statePath, "utf-8"));
5857
5826
  return raw;
5858
5827
  } catch {
5859
5828
  return {};
@@ -5934,19 +5903,19 @@ var dim2 = (text) => `\x1B[2m${text}\x1B[0m`;
5934
5903
  var yellow2 = (text) => `\x1B[33m${text}\x1B[0m`;
5935
5904
  var green2 = (text) => `\x1B[32m${text}\x1B[0m`;
5936
5905
  function detectMarkerFileMode(filePath, markerStart) {
5937
- if (!(0, import_fs18.existsSync)(filePath)) return green2("create");
5938
- const content = (0, import_fs18.readFileSync)(filePath, "utf-8");
5906
+ if (!(0, import_fs17.existsSync)(filePath)) return green2("create");
5907
+ const content = (0, import_fs17.readFileSync)(filePath, "utf-8");
5939
5908
  if (content.includes(markerStart)) return yellow2("update");
5940
5909
  return yellow2("append");
5941
5910
  }
5942
5911
  function detectMCPFileMode(filePath) {
5943
- if (!(0, import_fs18.existsSync)(filePath)) return green2("create");
5912
+ if (!(0, import_fs17.existsSync)(filePath)) return green2("create");
5944
5913
  return yellow2("merge");
5945
5914
  }
5946
5915
  function detectContextMode(projectPath, domain) {
5947
- const contextDir = (0, import_path18.join)(projectPath, "_ai-context", domain.toUpperCase());
5948
- const contextDirLower = (0, import_path18.join)(projectPath, "_ai-context", domain);
5949
- if ((0, import_fs18.existsSync)(contextDir) || (0, import_fs18.existsSync)(contextDirLower)) return yellow2("overwrite");
5916
+ const contextDir = (0, import_path17.join)(projectPath, "_ai-context", domain.toUpperCase());
5917
+ const contextDirLower = (0, import_path17.join)(projectPath, "_ai-context", domain);
5918
+ if ((0, import_fs17.existsSync)(contextDir) || (0, import_fs17.existsSync)(contextDirLower)) return yellow2("overwrite");
5950
5919
  return green2("create");
5951
5920
  }
5952
5921
  function waitForEnter2() {
@@ -5992,7 +5961,7 @@ async function main() {
5992
5961
  await waitForEnter2();
5993
5962
  return;
5994
5963
  }
5995
- const statePath = (0, import_path18.join)(config.projectPath, ".one-shot-state.json");
5964
+ const statePath = (0, import_path17.join)(config.projectPath, ".one-shot-state.json");
5996
5965
  const journal = new Journal(statePath);
5997
5966
  journal.startFresh();
5998
5967
  const ctx = {
@@ -6035,6 +6004,19 @@ async function collectInputs(options, releaseVersion, factoryAvailable = false,
6035
6004
  choices: options.agents,
6036
6005
  loop: false
6037
6006
  });
6007
+ let agentTeams = false;
6008
+ if (factoryAvailable && agent === "claude-code") {
6009
+ const brainstormer = await esm_default6({
6010
+ message: "Brainstorming mode:",
6011
+ default: "solo",
6012
+ choices: [
6013
+ { name: "Default \u2014 solo facilitator (works everywhere, normal cost)", value: "solo" },
6014
+ { name: "Experimental \u2014 agent-team brainstormer (Claude Code only, higher token use)", value: "team" }
6015
+ ],
6016
+ loop: false
6017
+ });
6018
+ agentTeams = brainstormer === "team";
6019
+ }
6038
6020
  const mcpConfig = buildMCPConfiguration(selectedTechnologies, options.baseMcpServers, options.mcpServers);
6039
6021
  let azureDevOpsOrg = "";
6040
6022
  if (mcpConfig["azure-devops"]) {
@@ -6076,7 +6058,7 @@ async function collectInputs(options, releaseVersion, factoryAvailable = false,
6076
6058
  }
6077
6059
  const projectInput = await esm_default4({
6078
6060
  message: "Project directory:",
6079
- default: (0, import_path18.resolve)(process.cwd())
6061
+ default: (0, import_path17.resolve)(process.cwd())
6080
6062
  });
6081
6063
  const isAbapSelected = selectedTechnologies.some((t) => t.domains.includes("ABAP"));
6082
6064
  const installAbapHooks = abapHooksAvailable && agent === "claude-code" && isAbapSelected;
@@ -6084,12 +6066,13 @@ async function collectInputs(options, releaseVersion, factoryAvailable = false,
6084
6066
  technologies: selectedTechnologies,
6085
6067
  agent,
6086
6068
  azureDevOpsOrg,
6087
- projectPath: (0, import_path18.resolve)(projectInput),
6069
+ projectPath: (0, import_path17.resolve)(projectInput),
6088
6070
  baseMcpServers: options.baseMcpServers,
6089
6071
  mcpConfig,
6090
6072
  releaseVersion,
6091
6073
  installFactory: factoryAvailable,
6092
- installAbapHooks
6074
+ installAbapHooks,
6075
+ agentTeams
6093
6076
  };
6094
6077
  }
6095
6078
  async function previewAndConfirm(config, options) {
@@ -6099,9 +6082,9 @@ async function previewAndConfirm(config, options) {
6099
6082
  const instructionFile = target.instructions;
6100
6083
  const mcpConfigFile = target.mcpConfig;
6101
6084
  const serverEntries = Object.entries(config.mcpConfig);
6102
- const instructionFilePath = (0, import_path18.join)(config.projectPath, instructionFile);
6103
- const mcpConfigFilePath = (0, import_path18.join)(config.projectPath, mcpConfigFile);
6104
- const gitignorePath = (0, import_path18.join)(config.projectPath, ".gitignore");
6085
+ const instructionFilePath = (0, import_path17.join)(config.projectPath, instructionFile);
6086
+ const mcpConfigFilePath = (0, import_path17.join)(config.projectPath, mcpConfigFile);
6087
+ const gitignorePath = (0, import_path17.join)(config.projectPath, ".gitignore");
6105
6088
  const instructionMode = detectMarkerFileMode(instructionFilePath, "<!-- one-shot-installer:start -->");
6106
6089
  const mcpMode = detectMCPFileMode(mcpConfigFilePath);
6107
6090
  const gitignoreMode = detectMarkerFileMode(gitignorePath, "# one-shot-installer:start");
@@ -6117,6 +6100,9 @@ async function previewAndConfirm(config, options) {
6117
6100
  console.log(` Tool ${agentDisplay}`);
6118
6101
  console.log(` Factory ${config.installFactory ? "yes" : "no"}`);
6119
6102
  console.log(` ABAP hooks ${config.installAbapHooks ? "yes" : "no"}`);
6103
+ if (config.installFactory && config.agent === "claude-code") {
6104
+ console.log(` Brainstormer ${config.agentTeams ? "experimental (agent teams)" : "default (solo)"}`);
6105
+ }
6120
6106
  console.log(` Directory ${config.projectPath}`);
6121
6107
  console.log("");
6122
6108
  console.log(` ${dim2("File actions:")}`);
@@ -6127,15 +6113,12 @@ async function previewAndConfirm(config, options) {
6127
6113
  console.log(` ${instructionFile.padEnd(domainColWidth + 14)}${instructionMode}`);
6128
6114
  console.log(` ${mcpConfigFile.padEnd(domainColWidth + 14)}${mcpMode}`);
6129
6115
  console.log(` ${".gitignore".padEnd(domainColWidth + 14)}${gitignoreMode}`);
6130
- const projectInputDir = (0, import_path18.join)(config.projectPath, ".project", "input");
6131
- const projectInputMode = (0, import_fs18.existsSync)(projectInputDir) ? yellow2("exists") : green2("create");
6132
- console.log(` ${".project/input/".padEnd(domainColWidth + 14)}${projectInputMode}`);
6133
6116
  if (config.installFactory || config.installAbapHooks) {
6134
- const claudeDir = (0, import_path18.join)(config.projectPath, ".claude");
6135
- const claudeMode = (0, import_fs18.existsSync)(claudeDir) ? yellow2("merge") : green2("create");
6117
+ const claudeDir = (0, import_path17.join)(config.projectPath, ".claude");
6118
+ const claudeMode = (0, import_fs17.existsSync)(claudeDir) ? yellow2("merge") : green2("create");
6136
6119
  console.log(` ${".claude/".padEnd(domainColWidth + 14)}${claudeMode}`);
6137
- const settingsPath = (0, import_path18.join)(config.projectPath, ".claude", "settings.json");
6138
- const settingsMode = (0, import_fs18.existsSync)(settingsPath) ? yellow2("merge") : green2("create");
6120
+ const settingsPath = (0, import_path17.join)(config.projectPath, ".claude", "settings.json");
6121
+ const settingsMode = (0, import_fs17.existsSync)(settingsPath) ? yellow2("merge") : green2("create");
6139
6122
  console.log(` ${".claude/settings.json".padEnd(domainColWidth + 14)}${settingsMode}`);
6140
6123
  }
6141
6124
  if (serverEntries.length > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dlw-machine-setup",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "One-shot installer for The Machine toolchain",
5
5
  "bin": {
6
6
  "dlw-machine-setup": "bin/installer.js"