flagrm 0.2.0 → 0.2.1

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/CHANGELOG.md CHANGED
@@ -5,6 +5,15 @@ All notable changes to this project are documented here. The format follows
5
5
  [Semantic Versioning](https://semver.org/). Before 1.0, a minor version may
6
6
  contain breaking changes.
7
7
 
8
+ ## [0.2.1] - 2026-10-04
9
+
10
+ ### Fixed
11
+
12
+ - `flagrm scope` on Windows: `--json` printed the solution path with forward
13
+ slashes, and `--write` showed a wrong `.git/info/exclude` path (and could
14
+ write a wrong line to it) when the path held a short name such as
15
+ `RUNNER~1`.
16
+
8
17
  ## [0.2.0] - 2026-10-04
9
18
 
10
19
  ### Changed
@@ -135,6 +144,7 @@ removes the flag through the `flagrm-remove` skill, and flagrm checks the result
135
144
  `doctor` warns about an incremental `dotnet build`, which hides existing
136
145
  warnings from the dead-code comparison.
137
146
 
147
+ [0.2.1]: https://github.com/dino-cosic/flagrm/releases/tag/v0.2.1
138
148
  [0.2.0]: https://github.com/dino-cosic/flagrm/releases/tag/v0.2.0
139
149
  [0.1.1]: https://github.com/dino-cosic/flagrm/releases/tag/v0.1.1
140
150
  [0.1.0]: https://github.com/dino-cosic/flagrm/releases/tag/v0.1.0
@@ -82,8 +82,9 @@ function solutionFor(ctx, commands) {
82
82
  }
83
83
  }
84
84
  const found = fg.sync("*.{sln,slnx}", { cwd: ctx.root, absolute: true });
85
+ // fast-glob returns forward slashes, also on Windows.
85
86
  if (found.length === 1)
86
- return { solution: found[0] };
87
+ return { solution: path.normalize(found[0]) };
87
88
  return { note: found.length ? "several solutions: name one in build/test" : "no solution file found" };
88
89
  }
89
90
  /**
@@ -139,6 +140,20 @@ export function pointAt(command, slnf) {
139
140
  return command;
140
141
  return command.replace(/\bdotnet\s+(build|test)\b/, `dotnet $1 ${slnf}`);
141
142
  }
143
+ /**
144
+ * `file` with symlinks resolved and, on Windows, 8.3 short names expanded
145
+ * (`RUNNER~1`): git prints long names, `os.tmpdir()` may give short ones. A
146
+ * file that doesn't exist yet resolves through its directory.
147
+ */
148
+ function realPath(file) {
149
+ try {
150
+ return fs.realpathSync.native(file);
151
+ }
152
+ catch {
153
+ const dir = path.dirname(file);
154
+ return dir === file ? file : path.join(realPath(dir), path.basename(file));
155
+ }
156
+ }
142
157
  function excludeFromGit(root, file) {
143
158
  const git = (...args) => spawnSync("git", args, { cwd: root, encoding: "utf8" });
144
159
  const top = git("rev-parse", "--show-toplevel");
@@ -146,9 +161,9 @@ function excludeFromGit(root, file) {
146
161
  if (top.status !== 0 || exclude.status !== 0)
147
162
  return { path: ".git/info/exclude", status: "skipped", note: "not a git repository" };
148
163
  const excludeFile = exclude.stdout.trim();
149
- const line = `/${relativePath(fs.realpathSync(top.stdout.trim()), fs.realpathSync(file))}`;
164
+ const line = `/${relativePath(realPath(top.stdout.trim()), realPath(file))}`;
150
165
  const text = fs.existsSync(excludeFile) ? fs.readFileSync(excludeFile, "utf8") : "";
151
- const shown = relativePath(root, excludeFile);
166
+ const shown = relativePath(realPath(root), realPath(excludeFile));
152
167
  if (text.split(/\r?\n/).includes(line))
153
168
  return { path: shown, status: "unchanged" };
154
169
  fs.mkdirSync(path.dirname(excludeFile), { recursive: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flagrm",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Guardrails for removing feature flags with AI coding agents (Claude Code, Copilot, Codex): skills, a baseline, a verify gate and a Stop hook.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",