argsbarg 4.0.2 → 4.0.3

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
+ ## [4.0.3] - 2026-06-24
11
+
12
+
10
13
  ## [4.0.2] - 2026-06-24
11
14
 
12
15
 
@@ -455,7 +458,8 @@ const cli = { ... } satisfies CliProgram; // or : CliProgram
455
458
  - 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`).
456
459
  - Imports: use `CliPositional` where needed; replace `CliOptionDef` with `CliOption` or `CliPositional` as appropriate.
457
460
 
458
- [Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v4.0.2...HEAD
461
+ [Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v4.0.3...HEAD
462
+ [4.0.3]: https://github.com/bdombro/bun-argsbarg/releases/tag/v4.0.3
459
463
  [4.0.2]: https://github.com/bdombro/bun-argsbarg/releases/tag/v4.0.2
460
464
  [4.0.1]: https://github.com/bdombro/bun-argsbarg/releases/tag/v4.0.1
461
465
  [4.0.0]: https://github.com/bdombro/bun-argsbarg/releases/tag/v4.0.0
@@ -431,7 +431,7 @@ await cli.run();
431
431
 
432
432
  See [config-schema.md](config-schema.md) for codegen, [install.md](install.md), and [mcp.md](mcp.md).
433
433
 
434
- **Handler access (`ctx.appConfig`):** `get`, `require`, `set`, `read`, `path` — prefer over `process.env` in handlers; env export remains for subprocess inheritance. `path` is the resolved absolute config file path (`program.appConfig.path` when set, otherwise the OS default from `program.key`).
434
+ **Handler access (`ctx.appConfig`):** `get`, `require`, `set`, `read`, `path`, `dir` — prefer over `process.env` in handlers; env export remains for subprocess inheritance. `path` is the resolved absolute config file path; `dir` is its parent directory (both honor `program.appConfig.path` when set, otherwise the OS default from `program.key`).
435
435
 
436
436
  ## Reserved names
437
437
 
@@ -42,7 +42,7 @@ await cli.run();
42
42
  | `install --configure` / `--status` | Interactive setup and status |
43
43
  | Built-in `config get` / `config set` | Read/write resolved values (opt-out via `commands: false`) |
44
44
  | MCP bundle / Claude plugin | `userConfig` for entries with `env` set |
45
- | `ctx.appConfig` in handlers | `get`, `require`, `set`, `read`, `path` — prefer over `process.env` |
45
+ | `ctx.appConfig` in handlers | `get`, `require`, `set`, `read`, `path`, `dir` — prefer over `process.env` |
46
46
 
47
47
  **Validation at runtime** — argsbarg validates the config file and `config set` / `ctx.appConfig.set` against the effective JSON Schema (block `jsonSchema` or synthesized all-string schema).
48
48
 
package/index.d.ts CHANGED
@@ -10,6 +10,8 @@ declare class EmptyAppConfigSnapshot {
10
10
  read(): ResolvedConfig;
11
11
  /** Resolved absolute path to the app JSON config file (OS default from `program.key`). */
12
12
  get path(): string;
13
+ /** Resolved absolute directory containing the config file. */
14
+ get dir(): string;
13
15
  }
14
16
  declare class AppConfigSnapshot {
15
17
  private readonly program;
@@ -22,6 +24,8 @@ declare class AppConfigSnapshot {
22
24
  read(): ResolvedConfig;
23
25
  /** Resolved absolute path to the app JSON config file (honors `program.appConfig.path` or OS default). */
24
26
  get path(): string;
27
+ /** Resolved absolute directory containing the config file. */
28
+ get dir(): string;
25
29
  /** Replace snapshot after external bootstrap (internal). */
26
30
  refresh(fileData: Record<string, unknown>, resolved: ResolvedConfig): void;
27
31
  private assertEntryKey;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "argsbarg",
3
- "version": "4.0.2",
3
+ "version": "4.0.3",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "bun": ">=1.3"
@@ -1,9 +1,10 @@
1
1
  import { describe, expect, test } from "bun:test";
2
2
  import { mkdtempSync, rmSync } from "node:fs";
3
3
  import { tmpdir } from "node:os";
4
- import { join } from "node:path";
4
+ import { dirname, join } from "node:path";
5
5
  import type { CliProgram } from "../types.ts";
6
6
  import { createAppConfigSnapshot } from "./context.ts";
7
+ import { resolveAppConfigDir } from "./file.ts";
7
8
  import { resolveAppConfig } from "./resolve.ts";
8
9
 
9
10
  function configProgram(configPath: string): CliProgram {
@@ -37,6 +38,7 @@ describe("config/context", () => {
37
38
  expect(ctx.get("note")).toBe("hello");
38
39
  expect(ctx.require("apiToken")).toBe("tok");
39
40
  expect(ctx.path).toBe(path);
41
+ expect(ctx.dir).toBe(dirname(path));
40
42
 
41
43
  ctx.set("note", "updated");
42
44
  expect(ctx.get("note")).toBe("updated");
@@ -60,6 +62,7 @@ describe("config/context", () => {
60
62
  expect(() => empty.set("any", "v")).toThrow(/program.appConfig is not set/);
61
63
  expect(empty.path).toContain("x");
62
64
  expect(empty.path.endsWith("/config") || empty.path.endsWith("\\config")).toBe(true);
65
+ expect(empty.dir).toBe(dirname(empty.path));
63
66
  });
64
67
 
65
68
  test("AppConfigSnapshot path uses OS default when program.appConfig.path omitted", () => {
@@ -75,5 +78,12 @@ describe("config/context", () => {
75
78
  const ctx = createAppConfigSnapshot(program, {}, {});
76
79
  expect(ctx.path).toContain("ctx_test");
77
80
  expect(ctx.path.endsWith("/config") || ctx.path.endsWith("\\config")).toBe(true);
81
+ expect(ctx.dir).toBe(resolveAppConfigDir(program));
82
+ expect(ctx.dir).toBe(dirname(ctx.path));
83
+ });
84
+
85
+ test("resolveAppConfigDir honors custom program.appConfig.path", () => {
86
+ const program = configProgram("/tmp/custom/settings.json");
87
+ expect(resolveAppConfigDir(program)).toBe("/tmp/custom");
78
88
  });
79
89
  });
@@ -3,7 +3,7 @@ Handler-facing resolved app config snapshot (ctx.appConfig).
3
3
  */
4
4
 
5
5
  import type { CliProgram } from "../types.ts";
6
- import { resolveAppConfigPath, writeAppConfigFile } from "./file.ts";
6
+ import { resolveAppConfigDir, resolveAppConfigPath, writeAppConfigFile } from "./file.ts";
7
7
  import type { ResolvedConfig } from "./resolve.ts";
8
8
  import { exportConfigToEnv, resolveAppConfig } from "./resolve.ts";
9
9
 
@@ -31,6 +31,11 @@ export class EmptyAppConfigSnapshot {
31
31
  get path(): string {
32
32
  return resolveAppConfigPath(this.program);
33
33
  }
34
+
35
+ /** Resolved absolute directory containing the config file. */
36
+ get dir(): string {
37
+ return resolveAppConfigDir(this.program);
38
+ }
34
39
  }
35
40
 
36
41
  /** Resolved config for handlers with program.appConfig set. */
@@ -82,6 +87,11 @@ export class AppConfigSnapshot {
82
87
  return resolveAppConfigPath(this.program);
83
88
  }
84
89
 
90
+ /** Resolved absolute directory containing the config file. */
91
+ get dir(): string {
92
+ return resolveAppConfigDir(this.program);
93
+ }
94
+
85
95
  /** Replace snapshot after external bootstrap (internal). */
86
96
  refresh(fileData: Record<string, unknown>, resolved: ResolvedConfig): void {
87
97
  this.fileData = { ...fileData };
@@ -22,6 +22,11 @@ export function resolveAppConfigPath(program: CliProgram): string {
22
22
  return join(appConfigHome(), dirName, "config");
23
23
  }
24
24
 
25
+ /** Resolved absolute directory containing the app JSON config file. */
26
+ export function resolveAppConfigDir(program: CliProgram): string {
27
+ return dirname(resolveAppConfigPath(program));
28
+ }
29
+
25
30
  /** Human-readable config path for error messages (`~` when under home). */
26
31
  export function displayAppConfigPath(program: CliProgram): string {
27
32
  const resolved = resolveAppConfigPath(program);