dlw-machine-setup 0.9.0 → 0.9.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 +39 -34
  2. package/package.json +1 -1
package/bin/installer.js CHANGED
@@ -3948,26 +3948,29 @@ function deleteDirIfExists(absPath) {
3948
3948
  return false;
3949
3949
  }
3950
3950
  }
3951
- function pruneEmptyParents(startPath, projectPath, maxLevels = 5) {
3952
- const removed = [];
3953
- let current = (0, import_path5.dirname)((0, import_path5.resolve)(startPath));
3951
+ function pruneEmptyAncestors(relPaths, projectPath) {
3954
3952
  const root = (0, import_path5.resolve)(projectPath);
3955
- for (let i = 0; i < maxLevels; i++) {
3956
- if (current === root) break;
3957
- if (!current.startsWith(root)) break;
3958
- if (!(0, import_fs5.existsSync)(current)) {
3959
- current = (0, import_path5.dirname)(current);
3960
- continue;
3953
+ const ancestors = /* @__PURE__ */ new Set();
3954
+ for (const rel of relPaths) {
3955
+ let cur = (0, import_path5.resolve)((0, import_path5.join)(root, rel));
3956
+ while (true) {
3957
+ cur = (0, import_path5.dirname)(cur);
3958
+ if (cur === root) break;
3959
+ if (!cur.startsWith(root + import_path5.sep)) break;
3960
+ ancestors.add(cur);
3961
3961
  }
3962
+ }
3963
+ const sorted = [...ancestors].sort((a, b) => b.length - a.length);
3964
+ const removed = [];
3965
+ for (const abs of sorted) {
3966
+ if (!(0, import_fs5.existsSync)(abs)) continue;
3962
3967
  try {
3963
- const entries = (0, import_fs5.readdirSync)(current);
3964
- if (entries.length > 0) break;
3965
- (0, import_fs5.rmSync)(current, { recursive: false });
3966
- removed.push(current);
3968
+ const entries = (0, import_fs5.readdirSync)(abs);
3969
+ if (entries.length > 0) continue;
3970
+ (0, import_fs5.rmdirSync)(abs);
3971
+ removed.push(abs);
3967
3972
  } catch {
3968
- break;
3969
3973
  }
3970
- current = (0, import_path5.dirname)(current);
3971
3974
  }
3972
3975
  return removed;
3973
3976
  }
@@ -4104,14 +4107,14 @@ var fetch_contexts_default = defineStep({
4104
4107
  const rec = raw ?? {};
4105
4108
  const domains = rec.domains ?? [];
4106
4109
  const removed = [];
4110
+ const relPaths = [];
4107
4111
  for (const domain of domains) {
4108
- const abs = resolveProjectPath((0, import_path6.join)("_ai-context", domain), ctx.config.projectPath);
4112
+ const rel = (0, import_path6.join)("_ai-context", domain);
4113
+ relPaths.push(rel);
4114
+ const abs = resolveProjectPath(rel, ctx.config.projectPath);
4109
4115
  if (deleteDirIfExists(abs)) removed.push(domain);
4110
4116
  }
4111
- if (rec.contextsDirCreated) {
4112
- const firstAbs = resolveProjectPath((0, import_path6.join)("_ai-context", domains[0] ?? "_"), ctx.config.projectPath);
4113
- pruneEmptyParents(firstAbs, ctx.config.projectPath, 1);
4114
- }
4117
+ pruneEmptyAncestors(relPaths, ctx.config.projectPath);
4115
4118
  return {
4116
4119
  status: "success",
4117
4120
  message: removed.length > 0 ? removed.join(", ") : "nothing to remove"
@@ -4704,9 +4707,8 @@ var fetch_factory_default = defineStep({
4704
4707
  removeMarkerBlock(abs, `<!-- ${bundle}:start -->`, `<!-- ${bundle}:end -->`);
4705
4708
  }
4706
4709
  }
4707
- const sortedCreated = [...rec.filesCreated ?? []].sort(
4708
- (a, b) => a.length - b.length
4709
- );
4710
+ const created = rec.filesCreated ?? [];
4711
+ const sortedCreated = [...created].sort((a, b) => a.length - b.length);
4710
4712
  for (const rel of sortedCreated) {
4711
4713
  const abs = resolveProjectPath(rel, projectPath);
4712
4714
  if (!(0, import_fs9.existsSync)(abs)) continue;
@@ -4718,6 +4720,8 @@ var fetch_factory_default = defineStep({
4718
4720
  summary.push(`removed ${rel}`);
4719
4721
  }
4720
4722
  }
4723
+ const pruned = pruneEmptyAncestors(created, projectPath);
4724
+ if (pruned.length > 0) summary.push(`pruned ${pruned.length} empty dir(s)`);
4721
4725
  return {
4722
4726
  status: "success",
4723
4727
  message: summary.length > 0 ? `${summary.length} action(s)` : "nothing to remove"
@@ -4892,16 +4896,13 @@ var fetch_abap_hooks_default = defineStep({
4892
4896
  removeMarkerBlock(abs, `<!-- ${bundle}:start -->`, `<!-- ${bundle}:end -->`);
4893
4897
  }
4894
4898
  }
4895
- for (const rel of rec.filesCreated ?? []) {
4899
+ const created = rec.filesCreated ?? [];
4900
+ for (const rel of created) {
4896
4901
  const abs = resolveProjectPath(rel, projectPath);
4897
4902
  if (isDirectorySafe(abs)) deleteDirIfExists(abs);
4898
4903
  else deleteFileIfExists(abs);
4899
4904
  }
4900
- const firstScript = (rec.filesCreated ?? [])[0];
4901
- if (firstScript) {
4902
- const abs = resolveProjectPath(firstScript, projectPath);
4903
- pruneEmptyParents(abs, projectPath, 1);
4904
- }
4905
+ pruneEmptyAncestors(created, projectPath);
4905
4906
  return { status: "success" };
4906
4907
  }
4907
4908
  }
@@ -5239,7 +5240,10 @@ var red2 = (text) => `\x1B[31m${text}\x1B[0m`;
5239
5240
  var write_mcp_config_default = defineStep({
5240
5241
  name: "write-mcp-config",
5241
5242
  label: "Writing MCP configuration",
5242
- when: (ctx) => Object.keys(ctx.config.mcpConfig).length > 0,
5243
+ /* Claude Code registers servers via `claude mcp add` (run-mcp-install-commands),
5244
+ * so the project-scoped `.mcp.json` is redundant there. Cursor and GitHub
5245
+ * Copilot have no equivalent CLI — they still need their config file. */
5246
+ when: (ctx) => ctx.config.agent !== "claude-code" && Object.keys(ctx.config.mcpConfig).length > 0,
5243
5247
  execute: async (ctx) => {
5244
5248
  const filteredMcpConfig = getFilteredMcpConfig(ctx);
5245
5249
  const target = getAgentTarget(ctx.config.agent);
@@ -5368,23 +5372,24 @@ var run_mcp_install_commands_default = defineStep({
5368
5372
  },
5369
5373
  inverse: {
5370
5374
  label: "Unregistering MCP servers from Claude Code",
5371
- execute: async (raw) => {
5375
+ execute: async (raw, ctx) => {
5372
5376
  const rec = raw ?? {};
5373
5377
  const servers = rec.registeredServers ?? [];
5374
5378
  if (servers.length === 0) return { status: "skipped", detail: "nothing was registered" };
5375
5379
  if (!isClaudeCliAvailable()) {
5376
5380
  return {
5377
5381
  status: "skipped",
5378
- detail: "`claude` CLI not found \u2014 leftover global registrations: " + servers.join(", ")
5382
+ detail: "`claude` CLI not found \u2014 leftover registrations: " + servers.join(", ")
5379
5383
  };
5380
5384
  }
5381
5385
  const removed = [];
5382
5386
  const failed = [];
5383
5387
  for (const name of servers) {
5384
- const r = (0, import_child_process3.spawnSync)(`claude mcp remove ${name}`, {
5388
+ const r = (0, import_child_process3.spawnSync)(`claude mcp remove ${name} --scope project`, {
5385
5389
  shell: true,
5386
5390
  stdio: "pipe",
5387
- encoding: "utf-8"
5391
+ encoding: "utf-8",
5392
+ cwd: ctx.config.projectPath
5388
5393
  });
5389
5394
  if (r.status === 0) removed.push(name);
5390
5395
  else failed.push(name);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dlw-machine-setup",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "description": "One-shot installer for The Machine toolchain",
5
5
  "bin": {
6
6
  "dlw-machine-setup": "bin/installer.js"