dlw-machine-setup 0.11.1 → 0.12.0-canary.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/bin/installer.js +138 -103
  2. package/package.json +3 -2
package/bin/installer.js CHANGED
@@ -3123,9 +3123,9 @@ ${page}${helpTipBottom}${choiceDescription}${import_ansi_escapes3.default.cursor
3123
3123
  });
3124
3124
 
3125
3125
  // src/index.ts
3126
- var import_fs17 = require("fs");
3126
+ var import_fs18 = require("fs");
3127
3127
  var import_readline2 = require("readline");
3128
- var import_path17 = require("path");
3128
+ var import_path18 = require("path");
3129
3129
 
3130
3130
  // src/utils/fetch.ts
3131
3131
  var DEFAULT_TIMEOUT_MS = 3e4;
@@ -4043,8 +4043,8 @@ async function fetchContexts(domains, token, repo, targetDir) {
4043
4043
  }
4044
4044
 
4045
4045
  // src/steps/resources/fetch-factory.ts
4046
- var import_fs9 = require("fs");
4047
- var import_path9 = require("path");
4046
+ var import_fs10 = require("fs");
4047
+ var import_path10 = require("path");
4048
4048
 
4049
4049
  // src/bundles/run-bundle.ts
4050
4050
  var import_fs8 = require("fs");
@@ -4557,6 +4557,40 @@ function assertBundleRootExists(ctx) {
4557
4557
  }
4558
4558
  }
4559
4559
 
4560
+ // src/utils/channel.ts
4561
+ var import_fs9 = require("fs");
4562
+ var import_path9 = require("path");
4563
+ function getChannel() {
4564
+ try {
4565
+ const pkgPath = (0, import_path9.join)(__dirname, "..", "package.json");
4566
+ const { version } = JSON.parse((0, import_fs9.readFileSync)(pkgPath, "utf-8"));
4567
+ if (typeof version === "string" && version.includes("-")) return "test";
4568
+ } catch {
4569
+ }
4570
+ return "prod";
4571
+ }
4572
+
4573
+ // src/utils/resolve-release.ts
4574
+ async function fetchLatestPrerelease(token, repo) {
4575
+ const headers = {
4576
+ "Accept": "application/vnd.github+json",
4577
+ "Authorization": `Bearer ${token}`
4578
+ };
4579
+ const res = await fetchWithRetry(`https://api.github.com/repos/${repo}/releases?per_page=100`, { headers });
4580
+ if (!res.ok) {
4581
+ throw new Error(`GitHub API error (${res.status}): ${getReadableError(res.status)}`);
4582
+ }
4583
+ const releases = await res.json();
4584
+ const match = releases.find((r) => r.prerelease === true);
4585
+ if (!match) {
4586
+ throw new Error(`No pre-release found in ${repo} (test channel)`);
4587
+ }
4588
+ return { tagName: match.tag_name ?? "unknown", assets: match.assets ?? [] };
4589
+ }
4590
+ async function resolveReleaseForChannel(token, repo) {
4591
+ return getChannel() === "test" ? fetchLatestPrerelease(token, repo) : fetchLatestRelease(token, repo);
4592
+ }
4593
+
4560
4594
  // src/steps/resources/fetch-factory.ts
4561
4595
  var FACTORY_ASSET_NAME = "factory.tar.gz";
4562
4596
  var FACTORY_ROOT_FOLDER = "factory";
@@ -4605,7 +4639,7 @@ var fetch_factory_default = defineStep({
4605
4639
  const sortedCreated = [...created].sort((a, b) => a.length - b.length);
4606
4640
  for (const rel of sortedCreated) {
4607
4641
  const abs = resolveProjectPath(rel, projectPath);
4608
- if (!(0, import_fs9.existsSync)(abs)) continue;
4642
+ if (!(0, import_fs10.existsSync)(abs)) continue;
4609
4643
  if (isDirectorySafe(abs)) {
4610
4644
  deleteDirIfExists(abs);
4611
4645
  summary.push(`removed ${rel}`);
@@ -4633,7 +4667,7 @@ async function fetchFactory(token, repo, targetDir, agent, agentTeams) {
4633
4667
  };
4634
4668
  let release;
4635
4669
  try {
4636
- release = await fetchLatestRelease(token, repo);
4670
+ release = await resolveReleaseForChannel(token, repo);
4637
4671
  } catch (err) {
4638
4672
  result.failureReason = err instanceof Error ? err.message : String(err);
4639
4673
  return result;
@@ -4646,15 +4680,15 @@ async function fetchFactory(token, repo, targetDir, agent, agentTeams) {
4646
4680
  let archive = null;
4647
4681
  try {
4648
4682
  archive = await downloadAndExtractAsset(token, asset, targetDir, ".temp-factory-download");
4649
- const extractedEntries = (0, import_fs9.readdirSync)(archive.extractedRoot);
4683
+ const extractedEntries = (0, import_fs10.readdirSync)(archive.extractedRoot);
4650
4684
  const extractedFolder = extractedEntries.find((e) => e.toLowerCase() === FACTORY_ROOT_FOLDER.toLowerCase());
4651
4685
  if (!extractedFolder) {
4652
4686
  result.failureReason = `No ${FACTORY_ROOT_FOLDER}/ folder in archive`;
4653
4687
  return result;
4654
4688
  }
4655
- const extractedPath = (0, import_path9.join)(archive.extractedRoot, extractedFolder);
4656
- const manifestPath = (0, import_path9.join)(extractedPath, "install.json");
4657
- if (!(0, import_fs9.existsSync)(manifestPath)) {
4689
+ const extractedPath = (0, import_path10.join)(archive.extractedRoot, extractedFolder);
4690
+ const manifestPath = (0, import_path10.join)(extractedPath, "install.json");
4691
+ if (!(0, import_fs10.existsSync)(manifestPath)) {
4658
4692
  result.failureReason = "Factory archive has no install.json \u2014 upgrade Factory or downgrade installer";
4659
4693
  return result;
4660
4694
  }
@@ -4670,7 +4704,7 @@ async function fetchFactory(token, repo, targetDir, agent, agentTeams) {
4670
4704
  async function installViaBundle(manifestPath, extractedPath, targetDir, agent, agentTeams, result) {
4671
4705
  let manifest;
4672
4706
  try {
4673
- manifest = JSON.parse((0, import_fs9.readFileSync)(manifestPath, "utf-8"));
4707
+ manifest = JSON.parse((0, import_fs10.readFileSync)(manifestPath, "utf-8"));
4674
4708
  } catch (e) {
4675
4709
  throw new Error(`install.json is not valid JSON: ${e instanceof Error ? e.message : String(e)}`);
4676
4710
  }
@@ -4693,8 +4727,8 @@ async function installViaBundle(manifestPath, extractedPath, targetDir, agent, a
4693
4727
  }
4694
4728
 
4695
4729
  // src/steps/resources/fetch-abap-hooks.ts
4696
- var import_fs10 = require("fs");
4697
- var import_path10 = require("path");
4730
+ var import_fs11 = require("fs");
4731
+ var import_path11 = require("path");
4698
4732
  var HOOKS_ASSET_NAME = "sap-hooks.tar.gz";
4699
4733
  var HOOKS_TAG_PREFIX = "hooks-v";
4700
4734
  var HOOKS_ROOT_FOLDER = "hooks";
@@ -4826,7 +4860,7 @@ async function fetchAbapHooks(token, repo, targetDir, agent) {
4826
4860
  let archive = null;
4827
4861
  try {
4828
4862
  archive = await downloadAndExtractAsset(token, asset, targetDir, ".temp-abap-hooks-download");
4829
- const extractedEntries = (0, import_fs10.readdirSync)(archive.extractedRoot);
4863
+ const extractedEntries = (0, import_fs11.readdirSync)(archive.extractedRoot);
4830
4864
  const innerFolder = extractedEntries.find(
4831
4865
  (e) => e.toLowerCase() === HOOKS_ROOT_FOLDER.toLowerCase()
4832
4866
  );
@@ -4834,12 +4868,12 @@ async function fetchAbapHooks(token, repo, targetDir, agent) {
4834
4868
  result.failureReason = `No ${HOOKS_ROOT_FOLDER}/ folder in archive`;
4835
4869
  return result;
4836
4870
  }
4837
- const bundleRoot = (0, import_path10.join)(archive.extractedRoot, innerFolder);
4838
- if (!(0, import_fs10.statSync)(bundleRoot).isDirectory()) {
4871
+ const bundleRoot = (0, import_path11.join)(archive.extractedRoot, innerFolder);
4872
+ if (!(0, import_fs11.statSync)(bundleRoot).isDirectory()) {
4839
4873
  result.failureReason = `${HOOKS_ROOT_FOLDER}/ entry is not a directory`;
4840
4874
  return result;
4841
4875
  }
4842
- const presentDefs = HOOK_DEFINITIONS.filter((d) => (0, import_fs10.existsSync)((0, import_path10.join)(bundleRoot, d.script)));
4876
+ const presentDefs = HOOK_DEFINITIONS.filter((d) => (0, import_fs11.existsSync)((0, import_path11.join)(bundleRoot, d.script)));
4843
4877
  if (presentDefs.length === 0) {
4844
4878
  result.failureReason = "Archive contains no recognized hook scripts";
4845
4879
  return result;
@@ -4893,8 +4927,8 @@ async function fetchAbapHooks(token, repo, targetDir, agent) {
4893
4927
  }
4894
4928
 
4895
4929
  // src/steps/setup/write-instructions.ts
4896
- var import_fs11 = require("fs");
4897
- var import_path11 = require("path");
4930
+ var import_fs12 = require("fs");
4931
+ var import_path12 = require("path");
4898
4932
 
4899
4933
  // src/steps/shared.ts
4900
4934
  var cached = null;
@@ -4929,13 +4963,13 @@ var write_instructions_default = defineStep({
4929
4963
  const projectPath = ctx.config.projectPath;
4930
4964
  const content = buildCombinedInstructions(domains, filteredMcpConfig, agent, projectPath);
4931
4965
  const target = getAgentTarget(agent);
4932
- const filePath = (0, import_path11.join)(projectPath, target.instructions);
4933
- const fileDir = (0, import_path11.dirname)(filePath);
4934
- if (!(0, import_fs11.existsSync)(fileDir)) (0, import_fs11.mkdirSync)(fileDir, { recursive: true });
4935
- const fileExistedBefore = (0, import_fs11.existsSync)(filePath);
4966
+ const filePath = (0, import_path12.join)(projectPath, target.instructions);
4967
+ const fileDir = (0, import_path12.dirname)(filePath);
4968
+ if (!(0, import_fs12.existsSync)(fileDir)) (0, import_fs12.mkdirSync)(fileDir, { recursive: true });
4969
+ const fileExistedBefore = (0, import_fs12.existsSync)(filePath);
4936
4970
  let cursorFrontmatterWritten = false;
4937
4971
  if (agent === "cursor" && !fileExistedBefore) {
4938
- (0, import_fs11.writeFileSync)(filePath, `---
4972
+ (0, import_fs12.writeFileSync)(filePath, `---
4939
4973
  description: AI development instructions from One-Shot Installer
4940
4974
  alwaysApply: true
4941
4975
  ---
@@ -5016,16 +5050,16 @@ alwaysApply: true
5016
5050
  }
5017
5051
  });
5018
5052
  function collectMdFiles(dir) {
5019
- if (!(0, import_fs11.existsSync)(dir)) return [];
5020
- const entries = (0, import_fs11.readdirSync)(dir, { recursive: true });
5053
+ if (!(0, import_fs12.existsSync)(dir)) return [];
5054
+ const entries = (0, import_fs12.readdirSync)(dir, { recursive: true });
5021
5055
  return entries.filter((entry) => {
5022
- const fullPath = (0, import_path11.join)(dir, entry);
5023
- return entry.endsWith(".md") && (0, import_fs11.statSync)(fullPath).isFile();
5056
+ const fullPath = (0, import_path12.join)(dir, entry);
5057
+ return entry.endsWith(".md") && (0, import_fs12.statSync)(fullPath).isFile();
5024
5058
  }).map((entry) => entry.replace(/\\/g, "/")).sort();
5025
5059
  }
5026
5060
  function extractFirstHeading(filePath) {
5027
5061
  try {
5028
- const content = (0, import_fs11.readFileSync)(filePath, "utf-8");
5062
+ const content = (0, import_fs12.readFileSync)(filePath, "utf-8");
5029
5063
  const withoutFrontmatter = content.replace(/^---[\s\S]*?---\s*/, "");
5030
5064
  const match = withoutFrontmatter.match(/^#\s+(.+)/m);
5031
5065
  if (match) {
@@ -5043,16 +5077,16 @@ function formatPathRef(contextPath, description, agent) {
5043
5077
  return `- \`${contextPath}\` \u2014 ${description}`;
5044
5078
  }
5045
5079
  function resolveDomainFolder(domain, contextsDir) {
5046
- if ((0, import_fs11.existsSync)(contextsDir)) {
5080
+ if ((0, import_fs12.existsSync)(contextsDir)) {
5047
5081
  try {
5048
- const entries = (0, import_fs11.readdirSync)(contextsDir);
5082
+ const entries = (0, import_fs12.readdirSync)(contextsDir);
5049
5083
  const match = entries.find((e) => e.toLowerCase() === domain.toLowerCase());
5050
- if (match) return { folderName: match, folderPath: (0, import_path11.join)(contextsDir, match) };
5084
+ if (match) return { folderName: match, folderPath: (0, import_path12.join)(contextsDir, match) };
5051
5085
  } catch {
5052
5086
  }
5053
5087
  }
5054
5088
  const fallback = domain.toUpperCase();
5055
- return { folderName: fallback, folderPath: (0, import_path11.join)(contextsDir, fallback) };
5089
+ return { folderName: fallback, folderPath: (0, import_path12.join)(contextsDir, fallback) };
5056
5090
  }
5057
5091
  function buildContextRefsSection(domains, agent, contextsDir) {
5058
5092
  const lines2 = [
@@ -5064,34 +5098,34 @@ function buildContextRefsSection(domains, agent, contextsDir) {
5064
5098
  let hasAnyFiles = false;
5065
5099
  for (const domain of domains) {
5066
5100
  const { folderName, folderPath: domainPath } = resolveDomainFolder(domain, contextsDir);
5067
- if (!(0, import_fs11.existsSync)(domainPath)) continue;
5101
+ if (!(0, import_fs12.existsSync)(domainPath)) continue;
5068
5102
  const domainFiles = [];
5069
- const ctxInstructions = (0, import_path11.join)(domainPath, "context-instructions.md");
5070
- if ((0, import_fs11.existsSync)(ctxInstructions)) {
5103
+ const ctxInstructions = (0, import_path12.join)(domainPath, "context-instructions.md");
5104
+ if ((0, import_fs12.existsSync)(ctxInstructions)) {
5071
5105
  const desc = extractFirstHeading(ctxInstructions);
5072
5106
  domainFiles.push(formatPathRef(`_ai-context/${folderName}/context-instructions.md`, desc, agent));
5073
5107
  }
5074
- const instructionsMd = (0, import_path11.join)(domainPath, "core", "instructions.md");
5075
- if ((0, import_fs11.existsSync)(instructionsMd)) {
5108
+ const instructionsMd = (0, import_path12.join)(domainPath, "core", "instructions.md");
5109
+ if ((0, import_fs12.existsSync)(instructionsMd)) {
5076
5110
  const desc = extractFirstHeading(instructionsMd);
5077
5111
  domainFiles.push(formatPathRef(`_ai-context/${folderName}/core/instructions.md`, `${desc} (start here)`, agent));
5078
5112
  }
5079
- const coreDir = (0, import_path11.join)(domainPath, "core");
5080
- if ((0, import_fs11.existsSync)(coreDir)) {
5113
+ const coreDir = (0, import_path12.join)(domainPath, "core");
5114
+ if ((0, import_fs12.existsSync)(coreDir)) {
5081
5115
  const coreFiles = collectMdFiles(coreDir).filter((f) => f !== "instructions.md" && !f.startsWith("instructions/"));
5082
5116
  for (const file of coreFiles) {
5083
- const desc = extractFirstHeading((0, import_path11.join)(coreDir, file));
5117
+ const desc = extractFirstHeading((0, import_path12.join)(coreDir, file));
5084
5118
  domainFiles.push(formatPathRef(`_ai-context/${folderName}/core/${file}`, desc, agent));
5085
5119
  }
5086
5120
  }
5087
- const refDir = (0, import_path11.join)(domainPath, "reference");
5088
- if ((0, import_fs11.existsSync)(refDir)) {
5121
+ const refDir = (0, import_path12.join)(domainPath, "reference");
5122
+ if ((0, import_fs12.existsSync)(refDir)) {
5089
5123
  const refFiles = collectMdFiles(refDir);
5090
5124
  if (refFiles.length > 0) {
5091
5125
  domainFiles.push(``);
5092
5126
  domainFiles.push(`**Reference & cheat sheets:**`);
5093
5127
  for (const file of refFiles) {
5094
- const desc = extractFirstHeading((0, import_path11.join)(refDir, file));
5128
+ const desc = extractFirstHeading((0, import_path12.join)(refDir, file));
5095
5129
  domainFiles.push(formatPathRef(`_ai-context/${folderName}/reference/${file}`, desc, agent));
5096
5130
  }
5097
5131
  }
@@ -5122,7 +5156,7 @@ function buildMCPSection(mcpConfig) {
5122
5156
  return lines2.join("\n");
5123
5157
  }
5124
5158
  function buildCombinedInstructions(domains, mcpConfig, agent, projectPath) {
5125
- const contextsDir = (0, import_path11.join)(projectPath, "_ai-context");
5159
+ const contextsDir = (0, import_path12.join)(projectPath, "_ai-context");
5126
5160
  const lines2 = [`# AI Development Instructions`, ``, `> Generated by One-Shot Installer`, ``];
5127
5161
  lines2.push(buildContextRefsSection(domains, agent, contextsDir));
5128
5162
  if (Object.keys(mcpConfig).length > 0) lines2.push(buildMCPSection(mcpConfig));
@@ -5130,8 +5164,8 @@ function buildCombinedInstructions(domains, mcpConfig, agent, projectPath) {
5130
5164
  }
5131
5165
 
5132
5166
  // src/steps/setup/write-mcp-config.ts
5133
- var import_fs12 = require("fs");
5134
- var import_path12 = require("path");
5167
+ var import_fs13 = require("fs");
5168
+ var import_path13 = require("path");
5135
5169
  var red2 = (text) => `\x1B[31m${text}\x1B[0m`;
5136
5170
  var write_mcp_config_default = defineStep({
5137
5171
  name: "write-mcp-config",
@@ -5143,16 +5177,16 @@ var write_mcp_config_default = defineStep({
5143
5177
  execute: async (ctx) => {
5144
5178
  const filteredMcpConfig = getFilteredMcpConfig(ctx);
5145
5179
  const target = getAgentTarget(ctx.config.agent);
5146
- const mcpJsonPath = (0, import_path12.join)(ctx.config.projectPath, target.mcpConfig);
5147
- const fileExistedBefore = (0, import_fs12.existsSync)(mcpJsonPath);
5180
+ const mcpJsonPath = (0, import_path13.join)(ctx.config.projectPath, target.mcpConfig);
5181
+ const fileExistedBefore = (0, import_fs13.existsSync)(mcpJsonPath);
5148
5182
  if (target.mcpDir) {
5149
- const dir = (0, import_path12.join)(ctx.config.projectPath, target.mcpDir);
5150
- if (!(0, import_fs12.existsSync)(dir)) (0, import_fs12.mkdirSync)(dir, { recursive: true });
5183
+ const dir = (0, import_path13.join)(ctx.config.projectPath, target.mcpDir);
5184
+ if (!(0, import_fs13.existsSync)(dir)) (0, import_fs13.mkdirSync)(dir, { recursive: true });
5151
5185
  }
5152
5186
  let existingFile = {};
5153
- if ((0, import_fs12.existsSync)(mcpJsonPath)) {
5187
+ if ((0, import_fs13.existsSync)(mcpJsonPath)) {
5154
5188
  try {
5155
- existingFile = JSON.parse((0, import_fs12.readFileSync)(mcpJsonPath, "utf-8"));
5189
+ existingFile = JSON.parse((0, import_fs13.readFileSync)(mcpJsonPath, "utf-8"));
5156
5190
  } catch {
5157
5191
  const box = [
5158
5192
  "",
@@ -5178,7 +5212,7 @@ var write_mcp_config_default = defineStep({
5178
5212
  }
5179
5213
  const mergedServers = { ...existingServers, ...newServers };
5180
5214
  const outputFile = { ...existingFile, [target.mcpRootKey]: mergedServers };
5181
- (0, import_fs12.writeFileSync)(mcpJsonPath, JSON.stringify(outputFile, null, 2), "utf-8");
5215
+ (0, import_fs13.writeFileSync)(mcpJsonPath, JSON.stringify(outputFile, null, 2), "utf-8");
5182
5216
  ctx.installed.mcpServersAdded = addedServers;
5183
5217
  const record = {
5184
5218
  filePath: target.mcpConfig,
@@ -5305,8 +5339,8 @@ function isClaudeCliAvailable() {
5305
5339
 
5306
5340
  // src/steps/setup/build-code-index.ts
5307
5341
  var import_child_process4 = require("child_process");
5308
- var import_fs13 = require("fs");
5309
- var import_path13 = require("path");
5342
+ var import_fs14 = require("fs");
5343
+ var import_path14 = require("path");
5310
5344
  var CODE_INDEX_RELATIVE_PATH = ".claude/factory/utils/code-index";
5311
5345
  var INDEX_OUTPUT_RELATIVE_PATH = ".claude/factory/repo-index.json";
5312
5346
  var INDEX_STAMP_RELATIVE_PATH = ".claude/factory/index.stamp";
@@ -5315,8 +5349,8 @@ var build_code_index_default = defineStep({
5315
5349
  label: "Building code index",
5316
5350
  when: (ctx) => ctx.installed.factoryInstalled === true,
5317
5351
  execute: async (ctx) => {
5318
- const codeIndexDirectory = (0, import_path13.join)(ctx.config.projectPath, CODE_INDEX_RELATIVE_PATH);
5319
- if (!(0, import_fs13.existsSync)(codeIndexDirectory)) {
5352
+ const codeIndexDirectory = (0, import_path14.join)(ctx.config.projectPath, CODE_INDEX_RELATIVE_PATH);
5353
+ if (!(0, import_fs14.existsSync)(codeIndexDirectory)) {
5320
5354
  return {
5321
5355
  status: "skipped",
5322
5356
  detail: `code-index not found at ${CODE_INDEX_RELATIVE_PATH} \u2014 older Factory release?`,
@@ -5345,7 +5379,7 @@ var build_code_index_default = defineStep({
5345
5379
  record: { depsInstalled: false, indexBuilt: false }
5346
5380
  };
5347
5381
  }
5348
- const indexerScriptPath = (0, import_path13.join)(codeIndexDirectory, "index.cjs");
5382
+ const indexerScriptPath = (0, import_path14.join)(codeIndexDirectory, "index.cjs");
5349
5383
  const indexerResult = (0, import_child_process4.spawnSync)(`node "${indexerScriptPath}" "${ctx.config.projectPath}"`, {
5350
5384
  shell: true,
5351
5385
  stdio: "pipe",
@@ -5376,21 +5410,21 @@ var build_code_index_default = defineStep({
5376
5410
  const projectPath = ctx.config.projectPath;
5377
5411
  const summaryActions = [];
5378
5412
  if (record.indexBuilt) {
5379
- const indexFilePath = (0, import_path13.join)(projectPath, INDEX_OUTPUT_RELATIVE_PATH);
5380
- if ((0, import_fs13.existsSync)(indexFilePath)) {
5381
- (0, import_fs13.unlinkSync)(indexFilePath);
5413
+ const indexFilePath = (0, import_path14.join)(projectPath, INDEX_OUTPUT_RELATIVE_PATH);
5414
+ if ((0, import_fs14.existsSync)(indexFilePath)) {
5415
+ (0, import_fs14.unlinkSync)(indexFilePath);
5382
5416
  summaryActions.push(`removed ${INDEX_OUTPUT_RELATIVE_PATH}`);
5383
5417
  }
5384
- const stampFilePath = (0, import_path13.join)(projectPath, INDEX_STAMP_RELATIVE_PATH);
5385
- if ((0, import_fs13.existsSync)(stampFilePath)) {
5386
- (0, import_fs13.unlinkSync)(stampFilePath);
5418
+ const stampFilePath = (0, import_path14.join)(projectPath, INDEX_STAMP_RELATIVE_PATH);
5419
+ if ((0, import_fs14.existsSync)(stampFilePath)) {
5420
+ (0, import_fs14.unlinkSync)(stampFilePath);
5387
5421
  summaryActions.push(`removed ${INDEX_STAMP_RELATIVE_PATH}`);
5388
5422
  }
5389
5423
  }
5390
5424
  if (record.depsInstalled) {
5391
- const nodeModulesPath = (0, import_path13.join)(projectPath, CODE_INDEX_RELATIVE_PATH, "node_modules");
5392
- if ((0, import_fs13.existsSync)(nodeModulesPath)) {
5393
- (0, import_fs13.rmSync)(nodeModulesPath, { recursive: true, force: true });
5425
+ const nodeModulesPath = (0, import_path14.join)(projectPath, CODE_INDEX_RELATIVE_PATH, "node_modules");
5426
+ if ((0, import_fs14.existsSync)(nodeModulesPath)) {
5427
+ (0, import_fs14.rmSync)(nodeModulesPath, { recursive: true, force: true });
5394
5428
  summaryActions.push("removed code-index node_modules");
5395
5429
  }
5396
5430
  }
@@ -5407,8 +5441,8 @@ function isNodeAvailable() {
5407
5441
  }
5408
5442
 
5409
5443
  // src/steps/setup/update-gitignore.ts
5410
- var import_fs14 = require("fs");
5411
- var import_path14 = require("path");
5444
+ var import_fs15 = require("fs");
5445
+ var import_path15 = require("path");
5412
5446
  var MARKER_START2 = "# one-shot-installer:start";
5413
5447
  var MARKER_END2 = "# one-shot-installer:end";
5414
5448
  var CORE_GITIGNORE_ENTRIES = [
@@ -5429,8 +5463,8 @@ var update_gitignore_default = defineStep({
5429
5463
  name: "update-gitignore",
5430
5464
  label: "Updating .gitignore",
5431
5465
  execute: async (ctx) => {
5432
- const gitignorePath = (0, import_path14.join)(ctx.config.projectPath, ".gitignore");
5433
- const fileExistedBefore = (0, import_fs14.existsSync)(gitignorePath);
5466
+ const gitignorePath = (0, import_path15.join)(ctx.config.projectPath, ".gitignore");
5467
+ const fileExistedBefore = (0, import_fs15.existsSync)(gitignorePath);
5434
5468
  upsertMarkerBlock(gitignorePath, MARKER_START2, MARKER_END2, CORE_GITIGNORE_ENTRIES.join("\n"));
5435
5469
  const record = {
5436
5470
  filePath: ".gitignore",
@@ -5458,8 +5492,8 @@ var update_gitignore_default = defineStep({
5458
5492
  });
5459
5493
 
5460
5494
  // src/steps/setup/write-state.ts
5461
- var import_fs15 = require("fs");
5462
- var import_path15 = require("path");
5495
+ var import_fs16 = require("fs");
5496
+ var import_path16 = require("path");
5463
5497
  var import_os2 = require("os");
5464
5498
 
5465
5499
  // package.json
@@ -5473,7 +5507,8 @@ var package_default = {
5473
5507
  dev: "tsx src/index.ts",
5474
5508
  build: 'esbuild src/index.ts --bundle --platform=node --banner:js="#!/usr/bin/env node" --outfile=wrapper/bin/installer.js',
5475
5509
  "build:all": "npm run build",
5476
- "publish:wrapper": "cd wrapper && npm publish"
5510
+ "publish:test": "cd wrapper && npm publish --tag canary",
5511
+ "publish:prod": "cd wrapper && npm publish --tag latest"
5477
5512
  },
5478
5513
  dependencies: {
5479
5514
  "@inquirer/prompts": "^5.0.0"
@@ -5493,7 +5528,7 @@ var write_state_default = defineStep({
5493
5528
  name: "write-state",
5494
5529
  label: "Saving installation state",
5495
5530
  execute: async (ctx) => {
5496
- const statePath = (0, import_path15.join)(ctx.config.projectPath, ".one-shot-state.json");
5531
+ const statePath = (0, import_path16.join)(ctx.config.projectPath, ".one-shot-state.json");
5497
5532
  const mcpServersAdded = ctx.installed.mcpServersAdded ?? [];
5498
5533
  const filteredMcpConfig = Object.fromEntries(
5499
5534
  Object.entries(ctx.config.mcpConfig).filter(([name]) => mcpServersAdded.includes(name))
@@ -5524,13 +5559,13 @@ var write_state_default = defineStep({
5524
5559
  * mislead the uninstall preview which reads this field. */
5525
5560
  factory: ctx.installed.factoryInstalled ? ".claude/" : null,
5526
5561
  abapHooks: ctx.installed.abapHooksInstalled ? ".claude/hooks/" : null,
5527
- globalConfig: (0, import_path15.join)((0, import_os2.homedir)(), ".one-shot-installer")
5562
+ globalConfig: (0, import_path16.join)((0, import_os2.homedir)(), ".one-shot-installer")
5528
5563
  }
5529
5564
  };
5530
5565
  if (ctx.journal) {
5531
5566
  ctx.journal.setSummary(state);
5532
5567
  } else {
5533
- (0, import_fs15.writeFileSync)(statePath, JSON.stringify(state, null, 2), "utf-8");
5568
+ (0, import_fs16.writeFileSync)(statePath, JSON.stringify(state, null, 2), "utf-8");
5534
5569
  }
5535
5570
  return { status: "success" };
5536
5571
  },
@@ -5545,9 +5580,9 @@ var write_state_default = defineStep({
5545
5580
  });
5546
5581
 
5547
5582
  // src/uninstall.ts
5548
- var import_fs16 = require("fs");
5583
+ var import_fs17 = require("fs");
5549
5584
  var import_readline = require("readline");
5550
- var import_path16 = require("path");
5585
+ var import_path17 = require("path");
5551
5586
  var dim = (text) => `\x1B[2m${text}\x1B[0m`;
5552
5587
  var yellow = (text) => `\x1B[33m${text}\x1B[0m`;
5553
5588
  var red3 = (text) => `\x1B[31m${text}\x1B[0m`;
@@ -5567,11 +5602,11 @@ async function uninstall() {
5567
5602
  try {
5568
5603
  const projectInput = await esm_default3({
5569
5604
  message: "Project directory to uninstall from:",
5570
- default: (0, import_path16.resolve)(process.cwd())
5605
+ default: (0, import_path17.resolve)(process.cwd())
5571
5606
  });
5572
- const projectPath = (0, import_path16.resolve)(projectInput);
5573
- const statePath = (0, import_path16.join)(projectPath, ".one-shot-state.json");
5574
- if (!(0, import_fs16.existsSync)(statePath)) {
5607
+ const projectPath = (0, import_path17.resolve)(projectInput);
5608
+ const statePath = (0, import_path17.join)(projectPath, ".one-shot-state.json");
5609
+ if (!(0, import_fs17.existsSync)(statePath)) {
5575
5610
  console.log("");
5576
5611
  console.log(red3(" No .one-shot-state.json found at:"));
5577
5612
  console.log(` ${statePath}`);
@@ -5596,7 +5631,7 @@ async function uninstall() {
5596
5631
  default: false
5597
5632
  });
5598
5633
  if (proceed2) {
5599
- (0, import_fs16.unlinkSync)(statePath);
5634
+ (0, import_fs17.unlinkSync)(statePath);
5600
5635
  console.log(" Removed .one-shot-state.json");
5601
5636
  }
5602
5637
  await waitForEnter();
@@ -5638,7 +5673,7 @@ async function uninstall() {
5638
5673
  console.log("");
5639
5674
  const result = await runRollback(stepList, ctx);
5640
5675
  try {
5641
- if ((0, import_fs16.existsSync)(statePath)) (0, import_fs16.unlinkSync)(statePath);
5676
+ if ((0, import_fs17.existsSync)(statePath)) (0, import_fs17.unlinkSync)(statePath);
5642
5677
  } catch {
5643
5678
  }
5644
5679
  printSummary(result);
@@ -5650,7 +5685,7 @@ async function uninstall() {
5650
5685
  }
5651
5686
  function readSummary(statePath) {
5652
5687
  try {
5653
- const raw = JSON.parse((0, import_fs16.readFileSync)(statePath, "utf-8"));
5688
+ const raw = JSON.parse((0, import_fs17.readFileSync)(statePath, "utf-8"));
5654
5689
  return raw;
5655
5690
  } catch {
5656
5691
  return {};
@@ -5731,19 +5766,19 @@ var dim2 = (text) => `\x1B[2m${text}\x1B[0m`;
5731
5766
  var yellow2 = (text) => `\x1B[33m${text}\x1B[0m`;
5732
5767
  var green2 = (text) => `\x1B[32m${text}\x1B[0m`;
5733
5768
  function detectMarkerFileMode(filePath, markerStart) {
5734
- if (!(0, import_fs17.existsSync)(filePath)) return green2("create");
5735
- const content = (0, import_fs17.readFileSync)(filePath, "utf-8");
5769
+ if (!(0, import_fs18.existsSync)(filePath)) return green2("create");
5770
+ const content = (0, import_fs18.readFileSync)(filePath, "utf-8");
5736
5771
  if (content.includes(markerStart)) return yellow2("update");
5737
5772
  return yellow2("append");
5738
5773
  }
5739
5774
  function detectMCPFileMode(filePath) {
5740
- if (!(0, import_fs17.existsSync)(filePath)) return green2("create");
5775
+ if (!(0, import_fs18.existsSync)(filePath)) return green2("create");
5741
5776
  return yellow2("merge");
5742
5777
  }
5743
5778
  function detectContextMode(projectPath, domain) {
5744
- const contextDir = (0, import_path17.join)(projectPath, "_ai-context", domain.toUpperCase());
5745
- const contextDirLower = (0, import_path17.join)(projectPath, "_ai-context", domain);
5746
- if ((0, import_fs17.existsSync)(contextDir) || (0, import_fs17.existsSync)(contextDirLower)) return yellow2("overwrite");
5779
+ const contextDir = (0, import_path18.join)(projectPath, "_ai-context", domain.toUpperCase());
5780
+ const contextDirLower = (0, import_path18.join)(projectPath, "_ai-context", domain);
5781
+ if ((0, import_fs18.existsSync)(contextDir) || (0, import_fs18.existsSync)(contextDirLower)) return yellow2("overwrite");
5747
5782
  return green2("create");
5748
5783
  }
5749
5784
  function waitForEnter2() {
@@ -5789,7 +5824,7 @@ async function main() {
5789
5824
  await waitForEnter2();
5790
5825
  return;
5791
5826
  }
5792
- const statePath = (0, import_path17.join)(config.projectPath, ".one-shot-state.json");
5827
+ const statePath = (0, import_path18.join)(config.projectPath, ".one-shot-state.json");
5793
5828
  const journal = new Journal(statePath);
5794
5829
  journal.startFresh();
5795
5830
  const ctx = {
@@ -5873,7 +5908,7 @@ async function collectInputs(options, releaseVersion, factoryAvailable = false,
5873
5908
  }
5874
5909
  const projectInput = await esm_default3({
5875
5910
  message: "Project directory:",
5876
- default: (0, import_path17.resolve)(process.cwd())
5911
+ default: (0, import_path18.resolve)(process.cwd())
5877
5912
  });
5878
5913
  const isAbapSelected = selectedTechnologies.some((t) => t.domains.includes("ABAP"));
5879
5914
  const installAbapHooks = abapHooksAvailable && agent === "claude-code" && isAbapSelected;
@@ -5881,7 +5916,7 @@ async function collectInputs(options, releaseVersion, factoryAvailable = false,
5881
5916
  technologies: selectedTechnologies,
5882
5917
  agent,
5883
5918
  azureDevOpsOrg,
5884
- projectPath: (0, import_path17.resolve)(projectInput),
5919
+ projectPath: (0, import_path18.resolve)(projectInput),
5885
5920
  baseMcpServers: options.baseMcpServers,
5886
5921
  mcpConfig,
5887
5922
  releaseVersion,
@@ -5897,9 +5932,9 @@ async function previewAndConfirm(config, options) {
5897
5932
  const instructionFile = target.instructions;
5898
5933
  const mcpConfigFile = target.mcpConfig;
5899
5934
  const serverEntries = Object.entries(config.mcpConfig);
5900
- const instructionFilePath = (0, import_path17.join)(config.projectPath, instructionFile);
5901
- const mcpConfigFilePath = (0, import_path17.join)(config.projectPath, mcpConfigFile);
5902
- const gitignorePath = (0, import_path17.join)(config.projectPath, ".gitignore");
5935
+ const instructionFilePath = (0, import_path18.join)(config.projectPath, instructionFile);
5936
+ const mcpConfigFilePath = (0, import_path18.join)(config.projectPath, mcpConfigFile);
5937
+ const gitignorePath = (0, import_path18.join)(config.projectPath, ".gitignore");
5903
5938
  const instructionMode = detectMarkerFileMode(instructionFilePath, "<!-- one-shot-installer:start -->");
5904
5939
  const mcpMode = detectMCPFileMode(mcpConfigFilePath);
5905
5940
  const gitignoreMode = detectMarkerFileMode(gitignorePath, "# one-shot-installer:start");
@@ -5929,11 +5964,11 @@ async function previewAndConfirm(config, options) {
5929
5964
  console.log(` ${mcpConfigFile.padEnd(domainColWidth + 14)}${mcpMode}`);
5930
5965
  console.log(` ${".gitignore".padEnd(domainColWidth + 14)}${gitignoreMode}`);
5931
5966
  if (config.installFactory || config.installAbapHooks) {
5932
- const claudeDir = (0, import_path17.join)(config.projectPath, ".claude");
5933
- const claudeMode = (0, import_fs17.existsSync)(claudeDir) ? yellow2("merge") : green2("create");
5967
+ const claudeDir = (0, import_path18.join)(config.projectPath, ".claude");
5968
+ const claudeMode = (0, import_fs18.existsSync)(claudeDir) ? yellow2("merge") : green2("create");
5934
5969
  console.log(` ${".claude/".padEnd(domainColWidth + 14)}${claudeMode}`);
5935
- const settingsPath = (0, import_path17.join)(config.projectPath, ".claude", "settings.json");
5936
- const settingsMode = (0, import_fs17.existsSync)(settingsPath) ? yellow2("merge") : green2("create");
5970
+ const settingsPath = (0, import_path18.join)(config.projectPath, ".claude", "settings.json");
5971
+ const settingsMode = (0, import_fs18.existsSync)(settingsPath) ? yellow2("merge") : green2("create");
5937
5972
  console.log(` ${".claude/settings.json".padEnd(domainColWidth + 14)}${settingsMode}`);
5938
5973
  }
5939
5974
  if (serverEntries.length > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dlw-machine-setup",
3
- "version": "0.11.1",
3
+ "version": "0.12.0-canary.2",
4
4
  "description": "One-shot installer for The Machine toolchain",
5
5
  "bin": {
6
6
  "dlw-machine-setup": "bin/installer.js"
@@ -16,7 +16,8 @@
16
16
  "license": "UNLICENSED",
17
17
  "publishConfig": {
18
18
  "access": "public",
19
- "registry": "https://registry.npmjs.org"
19
+ "registry": "https://registry.npmjs.org",
20
+ "tag": "canary"
20
21
  },
21
22
  "engines": {
22
23
  "node": ">=18.0.0"