reposets 4.0.0 → 4.0.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/bin/reposets.js CHANGED
@@ -31,7 +31,7 @@ import { Command } from "effect/cli";
31
31
  * `0.0.0 (dev build)` from every build until the version was threaded down
32
32
  * from here through {@link Invocation}.
33
33
  */
34
- const VERSION = "4.0.0";
34
+ const VERSION = "4.0.1";
35
35
  /**
36
36
  * The application's directories: XDG resolution and the `reposets` namespace
37
37
  * under it.
@@ -96,24 +96,6 @@ const SECRET_IN_NAME = "That looks like a token, not a name. It was not stored."
96
96
  /** What `--env` names, and what the prompt accepts for it: a shell variable identifier. */
97
97
  const ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
98
98
  /**
99
- * Write credentials back to the file they were read from.
100
- *
101
- * @remarks
102
- * `ConfigFileShape.save` resolves its own default path — the XDG one — rather
103
- * than the path `discover` found. With a project-local
104
- * `reposets.credentials.toml` present, that splits reads from writes: `create`
105
- * lands in XDG while `list` keeps reading the local file, so a profile is
106
- * created that the user cannot see and that sync will not use. Writing back to
107
- * the discovered source keeps one file authoritative, and falls back to `save`
108
- * only when there is genuinely nothing to update.
109
- */
110
- const saveWhereRead = (file, value) => Effect.gen(function* () {
111
- const existing = (yield* file.discover.pipe(Effect.orElseSucceed(() => [])))[0];
112
- if (existing === void 0) return yield* file.save(value);
113
- yield* file.write(value, existing.path);
114
- return existing.path;
115
- });
116
- /**
117
99
  * Refuse an invocation the user got wrong.
118
100
  *
119
101
  * @remarks
@@ -284,7 +266,7 @@ const createHandler = (input) => Effect.gen(function* () {
284
266
  ...actsAs,
285
267
  github_token
286
268
  };
287
- const path = yield* saveWhereRead(credentialsFile, { profiles: {
269
+ const path = yield* credentialsFile.save({ profiles: {
288
270
  ...existing.profiles,
289
271
  [profile]: record
290
272
  } });
@@ -378,7 +360,7 @@ const deleteHandler = (profile) => Effect.gen(function* () {
378
360
  }), "Provide --profile <name>: the profile to delete."));
379
361
  if (credentials.profiles[name] === void 0) return yield* refuse(`Profile '${name}' not found.`);
380
362
  const { [name]: _removed, ...remaining } = credentials.profiles;
381
- const path = yield* saveWhereRead(credentialsFile, { profiles: remaining });
363
+ const path = yield* credentialsFile.save({ profiles: remaining });
382
364
  yield* CliMessage.success(`Deleted profile '${name}' from ${path}.`);
383
365
  });
384
366
  const deleteCommand = Command.make("delete", { profile: profileFlag }, ({ profile }) => deleteHandler(Option.getOrUndefined(profile))).pipe(Command.withDescription("Remove a credential profile"));
@@ -157,31 +157,15 @@ const REQUIRED_PERMISSIONS = [
157
157
  "resolve team slugs (org-owned repos only)"
158
158
  ]
159
159
  ];
160
- const levenshtein = (a, b) => {
161
- const matrix = [];
162
- for (let i = 0; i <= a.length; i++) matrix[i] = [i];
163
- for (let j = 0; j <= b.length; j++) matrix[0][j] = j;
164
- for (let i = 1; i <= a.length; i++) for (let j = 1; j <= b.length; j++) {
165
- const cost = a[i - 1] === b[j - 1] ? 0 : 1;
166
- const row = matrix[i];
167
- const prev = matrix[i - 1];
168
- row[j] = Math.min(prev[j] + 1, row[j - 1] + 1, prev[j - 1] + cost);
169
- }
170
- return matrix[a.length][b.length];
171
- };
172
- /** The nearest known key within edit distance 3, if any. */
173
- const findClosestMatch = (key, known) => {
174
- let best;
175
- let bestDist = Number.POSITIVE_INFINITY;
176
- for (const candidate of known) {
177
- const dist = levenshtein(key, candidate);
178
- if (dist < bestDist && dist <= 3) {
179
- bestDist = dist;
180
- best = candidate;
181
- }
182
- }
183
- return best;
184
- };
160
+ /**
161
+ * The nearest known key within edit distance 3, if any.
162
+ *
163
+ * @remarks
164
+ * Three edits, the threshold this check had before it moved onto the kit;
165
+ * `Fmt.suggest` defaults to two, `effect/cli`'s threshold. Ties keep the
166
+ * first known key, as before.
167
+ */
168
+ const findClosestMatch = (key, known) => Fmt.suggest(key, known, { maxDistance: 3 })[0];
185
169
  /**
186
170
  * The credential resolver `doctor`'s live token check runs through.
187
171
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reposets",
3
- "version": "4.0.0",
3
+ "version": "4.0.1",
4
4
  "private": false,
5
5
  "description": "CLI tool to sync GitHub repo settings, secrets and rulesets across personal repositories",
6
6
  "keywords": [
@@ -48,20 +48,22 @@
48
48
  },
49
49
  "dependencies": {
50
50
  "@1password/sdk": "^0.5.0",
51
- "@effect/platform-node": "^4.0.6",
52
- "@effected/app": "^0.28.0",
53
- "@effected/cli": "^0.23.0",
54
- "@effected/config-file": "^0.21.0",
55
- "@effected/env": "^0.6.0",
56
- "@effected/github": "^0.25.1",
57
- "@effected/glob": "^0.15.0",
58
- "@effected/schemastore": "^0.26.3",
59
- "@effected/store": "^0.20.0",
60
- "@effected/toml": "^0.16.0",
61
- "@effected/walker": "^0.21.0",
62
- "@effected/xdg": "^0.16.0",
51
+ "@effect/platform-node": "^4.0.7",
52
+ "@effected/app": "^0.29.0",
53
+ "@effected/cli": "^0.24.0",
54
+ "@effected/config-file": "^0.22.0",
55
+ "@effected/env": "^0.7.0",
56
+ "@effected/github": "^0.26.0",
57
+ "@effected/glob": "^0.16.0",
58
+ "@effected/jsonc": "^0.21.0",
59
+ "@effected/schemastore": "^0.27.0",
60
+ "@effected/store": "^0.21.0",
61
+ "@effected/toml": "^0.17.0",
62
+ "@effected/walker": "^0.22.0",
63
+ "@effected/xdg": "^0.17.0",
64
+ "@effected/yaml": "^0.26.0",
63
65
  "blakejs": "^1.2.1",
64
- "effect": "^4.0.6",
66
+ "effect": "^4.0.7",
65
67
  "ink": "^8.0.0",
66
68
  "react": "^19.3.1"
67
69
  },
@@ -78,6 +78,13 @@ const STRICT_KEYS = {
78
78
  * `upwardWalk` defaults to `process.cwd()` when given no `cwd`, which made
79
79
  * config discovery the one reader of `process` below the entrypoint.
80
80
  *
81
+ * **Writes go back to the file that was found.** `AppConfig` pins
82
+ * `saveTarget: "default"`, the XDG path, which would split reads from writes
83
+ * when a project-local `reposets.credentials.toml` exists: `credentials create`
84
+ * would land in XDG while `list` and `sync` keep reading the local file.
85
+ * `"source"` writes to the highest-priority file the chain found, and to XDG
86
+ * only when there is none.
87
+ *
81
88
  * @public
82
89
  */
83
90
  const CredentialsFilesLive = Layer.unwrap(Effect.map(Invocation, ({ cwd }) => AppConfig.layer(ReposetsCredentialsFile, {
@@ -88,7 +95,8 @@ const CredentialsFilesLive = Layer.unwrap(Effect.map(Invocation, ({ cwd }) => Ap
88
95
  filename: CREDENTIALS_FILENAME,
89
96
  cwd
90
97
  })],
91
- parseOptions: STRICT_KEYS
98
+ parseOptions: STRICT_KEYS,
99
+ saveTarget: "source"
92
100
  })));
93
101
  /**
94
102
  * Raised when `--config` names a path that does not exist.
@@ -237,7 +237,7 @@ const settingsPhase = Effect.gen(function* () {
237
237
  };
238
238
  let sent;
239
239
  if (!ctx.dryRun) {
240
- const outcome = yield* read(settingsClient.applySettings(desired));
240
+ const outcome = yield* read(settingsClient.applySettings(desired, { unknownKeys: "send" }));
241
241
  if ("failed" in outcome) return {
242
242
  changes: [],
243
243
  errors: [...errors, {
@@ -245,6 +245,7 @@ const settingsPhase = Effect.gen(function* () {
245
245
  message: outcome.failed
246
246
  }]
247
247
  };
248
+ for (const key of outcome.value.unverified) yield* logger.syncOperation("apply", "setting", key, "(unconfirmed: GitHub does not describe this field)");
248
249
  sent = [...outcome.value.rest, ...outcome.value.graphql];
249
250
  yield* applied.record({
250
251
  repo: ctx.slug,
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.59.4"
8
+ "packageVersion": "7.60.0"
9
9
  }
10
10
  ]
11
11
  }