dlw-machine-setup 0.9.4 → 0.9.6

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 +154 -41
  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_fs16 = require("fs");
3298
+ var import_fs17 = require("fs");
3299
3299
  var import_readline2 = require("readline");
3300
- var import_path16 = require("path");
3300
+ var import_path17 = require("path");
3301
3301
 
3302
3302
  // src/utils/fetch.ts
3303
3303
  var DEFAULT_TIMEOUT_MS = 3e4;
@@ -3951,6 +3951,7 @@ var Journal = class {
3951
3951
  // src/steps/index.ts
3952
3952
  var steps_exports = {};
3953
3953
  __export(steps_exports, {
3954
+ buildCodeIndex: () => build_code_index_default,
3954
3955
  fetchAbapHooks: () => fetch_abap_hooks_default,
3955
3956
  fetchContexts: () => fetch_contexts_default,
3956
3957
  fetchFactory: () => fetch_factory_default,
@@ -4465,20 +4466,29 @@ function runBundleV2(manifest, ctx) {
4465
4466
  filesPatched: [],
4466
4467
  markerBlockFiles: []
4467
4468
  };
4468
- const hookPatches = /* @__PURE__ */ new Map();
4469
+ const mergePatches = /* @__PURE__ */ new Map();
4469
4470
  for (const asset of manifest.assets ?? []) {
4470
- runAsset(asset, profile, hookPatches, ctx, result);
4471
+ runAsset(asset, profile, mergePatches, ctx, result);
4471
4472
  result.opsExecuted++;
4472
4473
  }
4473
- for (const [file, patch] of hookPatches) {
4474
- runMergeJson({ op: "merge-json", file, patch }, manifest.name, ctx, result);
4475
- }
4476
4474
  for (const op of manifest.ops ?? []) {
4477
4475
  if (op.when === "hooks-supported" && !profile.handlers.hook.supported) continue;
4478
4476
  if (op.when === "statusline-supported" && !profile.statusLineSupported) continue;
4479
- executeOp(substituteHookDir(op, profile), manifest.name, ctx, result);
4477
+ const substituted = substituteHookDir(op, profile);
4478
+ if (substituted.op === "merge-json") {
4479
+ const existing = mergePatches.get(substituted.file);
4480
+ mergePatches.set(
4481
+ substituted.file,
4482
+ deepMerge2(existing ?? {}, substituted.patch)
4483
+ );
4484
+ } else {
4485
+ executeOp(substituted, manifest.name, ctx, result);
4486
+ }
4480
4487
  result.opsExecuted++;
4481
4488
  }
4489
+ for (const [file, patch] of mergePatches) {
4490
+ runMergeJson({ op: "merge-json", file, patch }, manifest.name, ctx, result);
4491
+ }
4482
4492
  writeGitignoreBlock(manifest, ctx, result);
4483
4493
  const snippet = result.instructionsSnippet;
4484
4494
  if (snippet) {
@@ -5458,9 +5468,112 @@ function isClaudeCliAvailable() {
5458
5468
  return check2.status === 0;
5459
5469
  }
5460
5470
 
5461
- // src/steps/setup/update-gitignore.ts
5471
+ // src/steps/setup/build-code-index.ts
5472
+ var import_child_process4 = require("child_process");
5462
5473
  var import_fs13 = require("fs");
5463
5474
  var import_path13 = require("path");
5475
+ var CODE_INDEX_RELATIVE_PATH = ".claude/factory/utils/code-index";
5476
+ var INDEX_OUTPUT_RELATIVE_PATH = ".claude/factory/repo-index.json";
5477
+ var INDEX_STAMP_RELATIVE_PATH = ".claude/factory/index.stamp";
5478
+ var build_code_index_default = defineStep({
5479
+ name: "build-code-index",
5480
+ label: "Building code index",
5481
+ when: (ctx) => ctx.installed.factoryInstalled === true,
5482
+ execute: async (ctx) => {
5483
+ const codeIndexDirectory = (0, import_path13.join)(ctx.config.projectPath, CODE_INDEX_RELATIVE_PATH);
5484
+ if (!(0, import_fs13.existsSync)(codeIndexDirectory)) {
5485
+ return {
5486
+ status: "skipped",
5487
+ detail: `code-index not found at ${CODE_INDEX_RELATIVE_PATH} \u2014 older Factory release?`,
5488
+ record: { depsInstalled: false, indexBuilt: false }
5489
+ };
5490
+ }
5491
+ if (!isNodeAvailable()) {
5492
+ return {
5493
+ status: "skipped",
5494
+ detail: "`node` not found on PATH \u2014 run the indexer manually once node is available",
5495
+ record: { depsInstalled: false, indexBuilt: false }
5496
+ };
5497
+ }
5498
+ const npmResult = (0, import_child_process4.spawnSync)("npm install --silent --no-audit --no-fund --omit=dev", {
5499
+ shell: true,
5500
+ stdio: "pipe",
5501
+ encoding: "utf-8",
5502
+ cwd: codeIndexDirectory
5503
+ });
5504
+ const depsInstalled = npmResult.status === 0;
5505
+ if (!depsInstalled) {
5506
+ const stderrFirstLine = (npmResult.stderr ?? "").trim().split("\n")[0] || `exit ${npmResult.status}`;
5507
+ return {
5508
+ status: "failed",
5509
+ detail: `npm install failed: ${stderrFirstLine}`,
5510
+ record: { depsInstalled: false, indexBuilt: false }
5511
+ };
5512
+ }
5513
+ const indexerScriptPath = (0, import_path13.join)(codeIndexDirectory, "index.cjs");
5514
+ const indexerResult = (0, import_child_process4.spawnSync)(`node "${indexerScriptPath}" "${ctx.config.projectPath}"`, {
5515
+ shell: true,
5516
+ stdio: "pipe",
5517
+ encoding: "utf-8",
5518
+ cwd: ctx.config.projectPath
5519
+ });
5520
+ const indexBuilt = indexerResult.status === 0;
5521
+ if (!indexBuilt) {
5522
+ const stderrFirstLine = (indexerResult.stderr ?? "").trim().split("\n")[0] || `exit ${indexerResult.status}`;
5523
+ return {
5524
+ status: "success",
5525
+ message: "deps installed; initial index build failed (run manually)",
5526
+ detail: `indexer error: ${stderrFirstLine}`,
5527
+ record: { depsInstalled: true, indexBuilt: false }
5528
+ };
5529
+ }
5530
+ const lastStdoutLines = (indexerResult.stdout ?? "").trim().split("\n").slice(-5).join(" | ");
5531
+ return {
5532
+ status: "success",
5533
+ message: lastStdoutLines || "index built",
5534
+ record: { depsInstalled: true, indexBuilt: true }
5535
+ };
5536
+ },
5537
+ inverse: {
5538
+ label: "Removing code index",
5539
+ execute: async (raw, ctx) => {
5540
+ const record = raw ?? {};
5541
+ const projectPath = ctx.config.projectPath;
5542
+ const summaryActions = [];
5543
+ if (record.indexBuilt) {
5544
+ const indexFilePath = (0, import_path13.join)(projectPath, INDEX_OUTPUT_RELATIVE_PATH);
5545
+ if ((0, import_fs13.existsSync)(indexFilePath)) {
5546
+ (0, import_fs13.unlinkSync)(indexFilePath);
5547
+ summaryActions.push(`removed ${INDEX_OUTPUT_RELATIVE_PATH}`);
5548
+ }
5549
+ const stampFilePath = (0, import_path13.join)(projectPath, INDEX_STAMP_RELATIVE_PATH);
5550
+ if ((0, import_fs13.existsSync)(stampFilePath)) {
5551
+ (0, import_fs13.unlinkSync)(stampFilePath);
5552
+ summaryActions.push(`removed ${INDEX_STAMP_RELATIVE_PATH}`);
5553
+ }
5554
+ }
5555
+ if (record.depsInstalled) {
5556
+ const nodeModulesPath = (0, import_path13.join)(projectPath, CODE_INDEX_RELATIVE_PATH, "node_modules");
5557
+ if ((0, import_fs13.existsSync)(nodeModulesPath)) {
5558
+ (0, import_fs13.rmSync)(nodeModulesPath, { recursive: true, force: true });
5559
+ summaryActions.push("removed code-index node_modules");
5560
+ }
5561
+ }
5562
+ return {
5563
+ status: "success",
5564
+ message: summaryActions.length > 0 ? summaryActions.join(", ") : "nothing to remove"
5565
+ };
5566
+ }
5567
+ }
5568
+ });
5569
+ function isNodeAvailable() {
5570
+ const probeResult = (0, import_child_process4.spawnSync)("node --version", { shell: true, stdio: "ignore" });
5571
+ return probeResult.status === 0;
5572
+ }
5573
+
5574
+ // src/steps/setup/update-gitignore.ts
5575
+ var import_fs14 = require("fs");
5576
+ var import_path14 = require("path");
5464
5577
  var MARKER_START2 = "# one-shot-installer:start";
5465
5578
  var MARKER_END2 = "# one-shot-installer:end";
5466
5579
  var CORE_GITIGNORE_ENTRIES = [
@@ -5481,8 +5594,8 @@ var update_gitignore_default = defineStep({
5481
5594
  name: "update-gitignore",
5482
5595
  label: "Updating .gitignore",
5483
5596
  execute: async (ctx) => {
5484
- const gitignorePath = (0, import_path13.join)(ctx.config.projectPath, ".gitignore");
5485
- const fileExistedBefore = (0, import_fs13.existsSync)(gitignorePath);
5597
+ const gitignorePath = (0, import_path14.join)(ctx.config.projectPath, ".gitignore");
5598
+ const fileExistedBefore = (0, import_fs14.existsSync)(gitignorePath);
5486
5599
  upsertMarkerBlock(gitignorePath, MARKER_START2, MARKER_END2, CORE_GITIGNORE_ENTRIES.join("\n"));
5487
5600
  const record = {
5488
5601
  filePath: ".gitignore",
@@ -5510,8 +5623,8 @@ var update_gitignore_default = defineStep({
5510
5623
  });
5511
5624
 
5512
5625
  // src/steps/setup/write-state.ts
5513
- var import_fs14 = require("fs");
5514
- var import_path14 = require("path");
5626
+ var import_fs15 = require("fs");
5627
+ var import_path15 = require("path");
5515
5628
  var import_os2 = require("os");
5516
5629
 
5517
5630
  // package.json
@@ -5545,7 +5658,7 @@ var write_state_default = defineStep({
5545
5658
  name: "write-state",
5546
5659
  label: "Saving installation state",
5547
5660
  execute: async (ctx) => {
5548
- const statePath = (0, import_path14.join)(ctx.config.projectPath, ".one-shot-state.json");
5661
+ const statePath = (0, import_path15.join)(ctx.config.projectPath, ".one-shot-state.json");
5549
5662
  const mcpServersAdded = ctx.installed.mcpServersAdded ?? [];
5550
5663
  const filteredMcpConfig = Object.fromEntries(
5551
5664
  Object.entries(ctx.config.mcpConfig).filter(([name]) => mcpServersAdded.includes(name))
@@ -5576,13 +5689,13 @@ var write_state_default = defineStep({
5576
5689
  * mislead the uninstall preview which reads this field. */
5577
5690
  factory: ctx.installed.factoryInstalled ? ".claude/" : null,
5578
5691
  abapHooks: ctx.installed.abapHooksInstalled ? ".claude/hooks/" : null,
5579
- globalConfig: (0, import_path14.join)((0, import_os2.homedir)(), ".one-shot-installer")
5692
+ globalConfig: (0, import_path15.join)((0, import_os2.homedir)(), ".one-shot-installer")
5580
5693
  }
5581
5694
  };
5582
5695
  if (ctx.journal) {
5583
5696
  ctx.journal.setSummary(state);
5584
5697
  } else {
5585
- (0, import_fs14.writeFileSync)(statePath, JSON.stringify(state, null, 2), "utf-8");
5698
+ (0, import_fs15.writeFileSync)(statePath, JSON.stringify(state, null, 2), "utf-8");
5586
5699
  }
5587
5700
  return { status: "success" };
5588
5701
  },
@@ -5597,9 +5710,9 @@ var write_state_default = defineStep({
5597
5710
  });
5598
5711
 
5599
5712
  // src/uninstall.ts
5600
- var import_fs15 = require("fs");
5713
+ var import_fs16 = require("fs");
5601
5714
  var import_readline = require("readline");
5602
- var import_path15 = require("path");
5715
+ var import_path16 = require("path");
5603
5716
  var dim = (text) => `\x1B[2m${text}\x1B[0m`;
5604
5717
  var yellow = (text) => `\x1B[33m${text}\x1B[0m`;
5605
5718
  var red3 = (text) => `\x1B[31m${text}\x1B[0m`;
@@ -5619,11 +5732,11 @@ async function uninstall() {
5619
5732
  try {
5620
5733
  const projectInput = await esm_default4({
5621
5734
  message: "Project directory to uninstall from:",
5622
- default: (0, import_path15.resolve)(process.cwd())
5735
+ default: (0, import_path16.resolve)(process.cwd())
5623
5736
  });
5624
- const projectPath = (0, import_path15.resolve)(projectInput);
5625
- const statePath = (0, import_path15.join)(projectPath, ".one-shot-state.json");
5626
- if (!(0, import_fs15.existsSync)(statePath)) {
5737
+ const projectPath = (0, import_path16.resolve)(projectInput);
5738
+ const statePath = (0, import_path16.join)(projectPath, ".one-shot-state.json");
5739
+ if (!(0, import_fs16.existsSync)(statePath)) {
5627
5740
  console.log("");
5628
5741
  console.log(red3(" No .one-shot-state.json found at:"));
5629
5742
  console.log(` ${statePath}`);
@@ -5648,7 +5761,7 @@ async function uninstall() {
5648
5761
  default: false
5649
5762
  });
5650
5763
  if (proceed2) {
5651
- (0, import_fs15.unlinkSync)(statePath);
5764
+ (0, import_fs16.unlinkSync)(statePath);
5652
5765
  console.log(" Removed .one-shot-state.json");
5653
5766
  }
5654
5767
  await waitForEnter();
@@ -5689,7 +5802,7 @@ async function uninstall() {
5689
5802
  console.log("");
5690
5803
  const result = await runRollback(stepList, ctx);
5691
5804
  try {
5692
- if ((0, import_fs15.existsSync)(statePath)) (0, import_fs15.unlinkSync)(statePath);
5805
+ if ((0, import_fs16.existsSync)(statePath)) (0, import_fs16.unlinkSync)(statePath);
5693
5806
  } catch {
5694
5807
  }
5695
5808
  printSummary(result);
@@ -5701,7 +5814,7 @@ async function uninstall() {
5701
5814
  }
5702
5815
  function readSummary(statePath) {
5703
5816
  try {
5704
- const raw = JSON.parse((0, import_fs15.readFileSync)(statePath, "utf-8"));
5817
+ const raw = JSON.parse((0, import_fs16.readFileSync)(statePath, "utf-8"));
5705
5818
  return raw;
5706
5819
  } catch {
5707
5820
  return {};
@@ -5782,19 +5895,19 @@ var dim2 = (text) => `\x1B[2m${text}\x1B[0m`;
5782
5895
  var yellow2 = (text) => `\x1B[33m${text}\x1B[0m`;
5783
5896
  var green2 = (text) => `\x1B[32m${text}\x1B[0m`;
5784
5897
  function detectMarkerFileMode(filePath, markerStart) {
5785
- if (!(0, import_fs16.existsSync)(filePath)) return green2("create");
5786
- const content = (0, import_fs16.readFileSync)(filePath, "utf-8");
5898
+ if (!(0, import_fs17.existsSync)(filePath)) return green2("create");
5899
+ const content = (0, import_fs17.readFileSync)(filePath, "utf-8");
5787
5900
  if (content.includes(markerStart)) return yellow2("update");
5788
5901
  return yellow2("append");
5789
5902
  }
5790
5903
  function detectMCPFileMode(filePath) {
5791
- if (!(0, import_fs16.existsSync)(filePath)) return green2("create");
5904
+ if (!(0, import_fs17.existsSync)(filePath)) return green2("create");
5792
5905
  return yellow2("merge");
5793
5906
  }
5794
5907
  function detectContextMode(projectPath, domain) {
5795
- const contextDir = (0, import_path16.join)(projectPath, "_ai-context", domain.toUpperCase());
5796
- const contextDirLower = (0, import_path16.join)(projectPath, "_ai-context", domain);
5797
- if ((0, import_fs16.existsSync)(contextDir) || (0, import_fs16.existsSync)(contextDirLower)) return yellow2("overwrite");
5908
+ const contextDir = (0, import_path17.join)(projectPath, "_ai-context", domain.toUpperCase());
5909
+ const contextDirLower = (0, import_path17.join)(projectPath, "_ai-context", domain);
5910
+ if ((0, import_fs17.existsSync)(contextDir) || (0, import_fs17.existsSync)(contextDirLower)) return yellow2("overwrite");
5798
5911
  return green2("create");
5799
5912
  }
5800
5913
  function waitForEnter2() {
@@ -5840,7 +5953,7 @@ async function main() {
5840
5953
  await waitForEnter2();
5841
5954
  return;
5842
5955
  }
5843
- const statePath = (0, import_path16.join)(config.projectPath, ".one-shot-state.json");
5956
+ const statePath = (0, import_path17.join)(config.projectPath, ".one-shot-state.json");
5844
5957
  const journal = new Journal(statePath);
5845
5958
  journal.startFresh();
5846
5959
  const ctx = {
@@ -5924,7 +6037,7 @@ async function collectInputs(options, releaseVersion, factoryAvailable = false,
5924
6037
  }
5925
6038
  const projectInput = await esm_default4({
5926
6039
  message: "Project directory:",
5927
- default: (0, import_path16.resolve)(process.cwd())
6040
+ default: (0, import_path17.resolve)(process.cwd())
5928
6041
  });
5929
6042
  const isAbapSelected = selectedTechnologies.some((t) => t.domains.includes("ABAP"));
5930
6043
  const installAbapHooks = abapHooksAvailable && agent === "claude-code" && isAbapSelected;
@@ -5932,7 +6045,7 @@ async function collectInputs(options, releaseVersion, factoryAvailable = false,
5932
6045
  technologies: selectedTechnologies,
5933
6046
  agent,
5934
6047
  azureDevOpsOrg,
5935
- projectPath: (0, import_path16.resolve)(projectInput),
6048
+ projectPath: (0, import_path17.resolve)(projectInput),
5936
6049
  baseMcpServers: options.baseMcpServers,
5937
6050
  mcpConfig,
5938
6051
  releaseVersion,
@@ -5947,9 +6060,9 @@ async function previewAndConfirm(config, options) {
5947
6060
  const instructionFile = target.instructions;
5948
6061
  const mcpConfigFile = target.mcpConfig;
5949
6062
  const serverEntries = Object.entries(config.mcpConfig);
5950
- const instructionFilePath = (0, import_path16.join)(config.projectPath, instructionFile);
5951
- const mcpConfigFilePath = (0, import_path16.join)(config.projectPath, mcpConfigFile);
5952
- const gitignorePath = (0, import_path16.join)(config.projectPath, ".gitignore");
6063
+ const instructionFilePath = (0, import_path17.join)(config.projectPath, instructionFile);
6064
+ const mcpConfigFilePath = (0, import_path17.join)(config.projectPath, mcpConfigFile);
6065
+ const gitignorePath = (0, import_path17.join)(config.projectPath, ".gitignore");
5953
6066
  const instructionMode = detectMarkerFileMode(instructionFilePath, "<!-- one-shot-installer:start -->");
5954
6067
  const mcpMode = detectMCPFileMode(mcpConfigFilePath);
5955
6068
  const gitignoreMode = detectMarkerFileMode(gitignorePath, "# one-shot-installer:start");
@@ -5976,11 +6089,11 @@ async function previewAndConfirm(config, options) {
5976
6089
  console.log(` ${mcpConfigFile.padEnd(domainColWidth + 14)}${mcpMode}`);
5977
6090
  console.log(` ${".gitignore".padEnd(domainColWidth + 14)}${gitignoreMode}`);
5978
6091
  if (config.installFactory || config.installAbapHooks) {
5979
- const claudeDir = (0, import_path16.join)(config.projectPath, ".claude");
5980
- const claudeMode = (0, import_fs16.existsSync)(claudeDir) ? yellow2("merge") : green2("create");
6092
+ const claudeDir = (0, import_path17.join)(config.projectPath, ".claude");
6093
+ const claudeMode = (0, import_fs17.existsSync)(claudeDir) ? yellow2("merge") : green2("create");
5981
6094
  console.log(` ${".claude/".padEnd(domainColWidth + 14)}${claudeMode}`);
5982
- const settingsPath = (0, import_path16.join)(config.projectPath, ".claude", "settings.json");
5983
- const settingsMode = (0, import_fs16.existsSync)(settingsPath) ? yellow2("merge") : green2("create");
6095
+ const settingsPath = (0, import_path17.join)(config.projectPath, ".claude", "settings.json");
6096
+ const settingsMode = (0, import_fs17.existsSync)(settingsPath) ? yellow2("merge") : green2("create");
5984
6097
  console.log(` ${".claude/settings.json".padEnd(domainColWidth + 14)}${settingsMode}`);
5985
6098
  }
5986
6099
  if (serverEntries.length > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dlw-machine-setup",
3
- "version": "0.9.4",
3
+ "version": "0.9.6",
4
4
  "description": "One-shot installer for The Machine toolchain",
5
5
  "bin": {
6
6
  "dlw-machine-setup": "bin/installer.js"