argsbarg 5.1.15 → 5.1.16

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
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [5.1.16] - 2026-07-07
11
+
12
+
10
13
  ## [5.1.15] - 2026-07-06
11
14
 
12
15
 
@@ -20,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
20
23
  - **`configure --remove-all`** — skill uninstall actions no longer reinstall skills after printing "Removing …".
21
24
  - **Interactive `configure`** — choosing `n` on an installed skill now removes the skill directory (same bug as `--remove-all`, different code path).
22
25
  - **Configure closing summary** — counts artifacts (not per-file paths) and uses Removed/Installed/Synced instead of always "Updated N file(s)."
26
+ - **Interactive `configure` app config** — re-prompts every config entry; Enter keeps the current value.
23
27
 
24
28
  ### Changed
25
29
 
@@ -681,7 +685,8 @@ const cli = { ... } satisfies CliProgram; // or : CliProgram
681
685
  - Migrate schemas: rename every `children` property to **`commands`**; move positional definitions to **`CliPositional`** objects on `positionals` and strip `positional` / `argMin` / `argMax` from flag definitions under `options` (flags only carry `name`, `description`, `kind`, and optional `shortName`).
682
686
  - Imports: use `CliPositional` where needed; replace `CliOptionDef` with `CliOption` or `CliPositional` as appropriate.
683
687
 
684
- [Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v5.1.15...HEAD
688
+ [Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v5.1.16...HEAD
689
+ [5.1.16]: https://github.com/bdombro/bun-argsbarg/releases/tag/v5.1.16
685
690
  [5.1.15]: https://github.com/bdombro/bun-argsbarg/releases/tag/v5.1.15
686
691
  [5.1.14]: https://github.com/bdombro/bun-argsbarg/releases/tag/v5.1.14
687
692
  [5.1.13]: https://github.com/bdombro/bun-argsbarg/releases/tag/v5.1.13
package/docs/configure.md CHANGED
@@ -118,12 +118,12 @@ When `program.appConfig` is set, ArgsBarg manages schema-driven values in that f
118
118
  | Mode | Description |
119
119
  | --- | --- |
120
120
  | `configure --sync` | Bootstraps `config.json` as `{}` when missing |
121
- | Interactive `configure` | Config wizard when `entries` is non-empty; writes only when values or `_bindings` change |
121
+ | Interactive `configure` | Config wizard when `entries` is non-empty; re-prompts every entry (Enter keeps current); writes only when values or `_bindings` change |
122
122
  | `--status` | Shows config path, required keys (`set` / `missing`), and binding hints (`env`, `file`, `skip`) |
123
123
  | `--remove-config --yes` | Removes the config directory |
124
124
  | `configure set --from-env` | Bind a key to its mapped env var (stores `_bindings`, no literal secret) |
125
125
 
126
- Per-key intent is stored under the reserved `_bindings` object (e.g. `"apiToken": "env"`). Env still wins at resolve time when set; bindings record user choice and suppress re-prompts.
126
+ Per-key intent is stored under the reserved `_bindings` object (e.g. `"apiToken": "env"`). Env still wins at resolve time when set; bindings record user choice. CLI startup only prompts for missing required keys; interactive `configure` re-prompts all entries.
127
127
 
128
128
  Export helpers from `argsbarg`: `resolveAppConfigPath`, `displayAppConfigPath`.
129
129
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "argsbarg",
3
- "version": "5.1.15",
3
+ "version": "5.1.16",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "bun": ">=1.3"
@@ -0,0 +1,46 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import type { CliAppConfigEntry } from "../types.ts";
3
+ import { shouldWizardPromptConfigKey } from "./bootstrap.ts";
4
+
5
+ const requiredEntry: CliAppConfigEntry = {
6
+ description: "API token.",
7
+ required: true,
8
+ };
9
+
10
+ describe("shouldWizardPromptConfigKey", () => {
11
+ test("skips addressed keys by default", () => {
12
+ expect(
13
+ shouldWizardPromptConfigKey(
14
+ "apiToken",
15
+ { apiToken: "tok", _bindings: { apiToken: "file" } },
16
+ requiredEntry,
17
+ { apiToken: "tok" },
18
+ {},
19
+ ),
20
+ ).toBe(false);
21
+ });
22
+
23
+ test("rePromptAll prompts addressed keys", () => {
24
+ expect(
25
+ shouldWizardPromptConfigKey(
26
+ "apiToken",
27
+ { apiToken: "tok", _bindings: { apiToken: "file" } },
28
+ requiredEntry,
29
+ { apiToken: "tok" },
30
+ { rePromptAll: true },
31
+ ),
32
+ ).toBe(true);
33
+ });
34
+
35
+ test("prompts when env binding is broken", () => {
36
+ expect(
37
+ shouldWizardPromptConfigKey(
38
+ "apiToken",
39
+ { _bindings: { apiToken: "env" } },
40
+ { ...requiredEntry, env: "API_TOKEN" },
41
+ {},
42
+ {},
43
+ ),
44
+ ).toBe(true);
45
+ });
46
+ });
@@ -176,6 +176,8 @@ export interface RunInstallConfigureOpts {
176
176
  context?: "standalone" | "after-install";
177
177
  /** When false, omit the "Configuration Setup" banner (e.g. inside interactive `configure`). */
178
178
  showHeading?: boolean;
179
+ /** When true, prompt every entry (Enter keeps the current value). */
180
+ rePromptAll?: boolean;
179
181
  }
180
182
 
181
183
  /** Print the "Configuration Setup" heading before the configure prompts. */
@@ -199,6 +201,24 @@ function bindingsDiffer(a: Record<string, unknown>, b: Record<string, unknown>):
199
201
  return JSON.stringify(readBindings(a)) !== JSON.stringify(readBindings(b));
200
202
  }
201
203
 
204
+ /** Whether the configure wizard should prompt for a config key. */
205
+ export function shouldWizardPromptConfigKey(
206
+ key: string,
207
+ fileData: Record<string, unknown>,
208
+ entry: CliAppConfigEntry,
209
+ resolved: Record<string, unknown>,
210
+ opts: Pick<RunInstallConfigureOpts, "rePromptAll">,
211
+ ): boolean {
212
+ const bindings = readBindings(fileData);
213
+ if (bindings[key] === "env" && !isPresent(resolved[key])) {
214
+ return true;
215
+ }
216
+ if (opts.rePromptAll) {
217
+ return true;
218
+ }
219
+ return !isKeyAddressed(key, fileData, entry);
220
+ }
221
+
202
222
  /** Ask the user for each required setting that is still empty; returns updates to save to the config file. */
203
223
  function promptMissingRequired(program: CliProgram): Record<string, unknown> {
204
224
  const appConfig = program.appConfig;
@@ -270,10 +290,7 @@ export function runConfigure(
270
290
  }
271
291
 
272
292
  for (const [key, entry] of Object.entries(program.appConfig.entries)) {
273
- const bindings = readBindings(existing);
274
- if (bindings[key] === "env" && !isPresent(resolved[key])) {
275
- // Re-prompt when env binding is broken.
276
- } else if (isKeyAddressed(key, existing, entry)) {
293
+ if (!shouldWizardPromptConfigKey(key, existing, entry, resolved, opts)) {
277
294
  continue;
278
295
  }
279
296
 
@@ -383,7 +400,7 @@ export function ensureAppConfig(program: CliProgram, opts: EnsureAppConfigOpts):
383
400
 
384
401
  if (opts.interactive && process.stdin.isTTY) {
385
402
  if (opts.configure) {
386
- runConfigure(program, { context: "standalone" });
403
+ runConfigure(program, { context: "standalone", rePromptAll: true });
387
404
  fileData = readAppConfigFileRaw(resolveAppConfigPath(program));
388
405
  resolved = resolveAppConfig(program, fileData, hostEnv);
389
406
  exportConfigToEnv(program, resolved, hostEnv);
@@ -272,7 +272,7 @@ async function runInteractiveConfigure(root: CliProgram, opts: ConfigureOpts): P
272
272
  if (target.key === "configure") {
273
273
  if (!appConfigHasEntries(root)) continue;
274
274
 
275
- const result = runConfigure(root, { context: "standalone", showHeading: false });
275
+ const result = runConfigure(root, { context: "standalone", showHeading: false, rePromptAll: true });
276
276
  if (result.changed) {
277
277
  installOut(`Wrote config: ${displayAppConfigPath(root)}`, mutationOpts);
278
278
  recordArtifactMutation(summary, [displayAppConfigPath(root)], "configured");