forgedock 1.0.12 → 1.0.13

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/forgedock.mjs +36 -8
  2. package/package.json +1 -1
package/bin/forgedock.mjs CHANGED
@@ -9,6 +9,7 @@ import {
9
9
  readFileSync,
10
10
  writeFileSync,
11
11
  renameSync,
12
+ copyFileSync,
12
13
  } from "fs";
13
14
  import { execSync } from "child_process";
14
15
  import readline from "readline";
@@ -169,10 +170,17 @@ async function install() {
169
170
  updated++;
170
171
  }
171
172
  } else {
172
- console.log(
173
- ` ${YELLOW}WARNING${RESET}: ${rel} is a regular file — skipping (remove it manually to let ForgeDock manage it)`,
174
- );
175
- skipped++;
173
+ // Existing regular file — a ForgeDock-shipped command copied by a prior
174
+ // install (common on Windows, where symlinks aren't permitted). It is
175
+ // ForgeDock-managed (we only iterate shipped command names), so refresh
176
+ // it: skip if already current, otherwise overwrite with a fresh copy.
177
+ if (readFileSync(file, "utf-8") === readFileSync(target, "utf-8")) {
178
+ skipped++;
179
+ } else {
180
+ copyFileSync(file, target);
181
+ console.log(` ${YELLOW}Updated${RESET}: ${rel}`);
182
+ updated++;
183
+ }
176
184
  }
177
185
  } catch (err) {
178
186
  if (err.code !== "ENOENT") {
@@ -181,9 +189,20 @@ async function install() {
181
189
  );
182
190
  throw err;
183
191
  }
184
- // Doesn't exist — create symlink
185
- await symlink(file, target);
186
- console.log(` ${GREEN}Installed${RESET}: ${rel}`);
192
+ // Doesn't exist — create it. Prefer a symlink; fall back to a copy on
193
+ // systems where symlink creation is not permitted (e.g. Windows without
194
+ // Developer Mode / admin), which would otherwise throw EPERM. See #587.
195
+ try {
196
+ await symlink(file, target);
197
+ console.log(` ${GREEN}Installed${RESET}: ${rel}`);
198
+ } catch (linkErr) {
199
+ if (linkErr.code === "EPERM" || linkErr.code === "EACCES") {
200
+ copyFileSync(file, target);
201
+ console.log(` ${GREEN}Installed${RESET} (copy): ${rel}`);
202
+ } else {
203
+ throw linkErr;
204
+ }
205
+ }
187
206
  installed++;
188
207
  }
189
208
  }
@@ -253,14 +272,23 @@ async function uninstall() {
253
272
 
254
273
  try {
255
274
  const stats = await lstat(target);
275
+ const { unlink } = await import("fs/promises");
256
276
  if (stats.isSymbolicLink()) {
257
277
  const current = await readlink(target);
258
278
  if (current === file) {
259
- const { unlink } = await import("fs/promises");
260
279
  await unlink(target);
261
280
  console.log(` ${RED}Removed${RESET}: ${rel}`);
262
281
  removed++;
263
282
  }
283
+ } else if (
284
+ readFileSync(file, "utf-8") === readFileSync(target, "utf-8")
285
+ ) {
286
+ // Regular file installed by ForgeDock in copy mode (content matches the
287
+ // shipped command). Safe to remove. Content-differing files are left
288
+ // in place in case the user edited them.
289
+ await unlink(target);
290
+ console.log(` ${RED}Removed${RESET}: ${rel}`);
291
+ removed++;
264
292
  }
265
293
  } catch (err) {
266
294
  if (err.code !== "ENOENT") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forgedock",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "description": "GitHub as a knowledge graph for AI agents. Autonomous dev pipeline for Claude Code.",
5
5
  "bin": {
6
6
  "forgedock": "bin/forgedock.mjs"