argsbarg 4.1.0 → 4.1.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.
Files changed (103) hide show
  1. package/CHANGELOG.md +48 -1
  2. package/README.md +90 -84
  3. package/docs/README.md +6 -6
  4. package/docs/bundled-docs.md +1 -1
  5. package/docs/cli-program.md +5 -3
  6. package/docs/config-schema.md +36 -9
  7. package/docs/developing.md +7 -7
  8. package/docs/distribution-homebrew.md +103 -0
  9. package/docs/install.md +105 -189
  10. package/docs/mcp.md +2 -3
  11. package/docs/output-schema.md +1 -1
  12. package/examples/full-example/Formula/.gitkeep +0 -0
  13. package/examples/full-example/README.md +98 -0
  14. package/examples/full-example/biome.json +22 -0
  15. package/examples/{consumer-app → full-example}/bun.lock +2 -0
  16. package/examples/full-example/justfile +134 -0
  17. package/examples/{consumer-app → full-example}/package.json +10 -3
  18. package/examples/{consumer-app → full-example}/schemas/generated/app-config.json +1 -1
  19. package/examples/{consumer-app → full-example}/schemas/generated/status.json +1 -1
  20. package/examples/full-example/scripts/create-identity.ts +11 -0
  21. package/examples/full-example/scripts/formula-shared.ts +73 -0
  22. package/examples/full-example/scripts/gen-dev-formula.ts +26 -0
  23. package/examples/full-example/scripts/print-identity.ts +27 -0
  24. package/examples/full-example/src/commands/echo/command.ts +21 -0
  25. package/examples/full-example/src/commands/status/command.test.ts +10 -0
  26. package/examples/full-example/src/commands/status/command.ts +36 -0
  27. package/examples/{consumer-app → full-example}/src/commands/status/types.ts +1 -1
  28. package/examples/full-example/src/index.ts +10 -0
  29. package/examples/full-example/src/program.ts +57 -0
  30. package/examples/{consumer-app → full-example}/src/types.ts +1 -1
  31. package/examples/nested.ts +1 -3
  32. package/index.d.ts +27 -66
  33. package/package.json +2 -2
  34. package/src/builtins/builtins.test.ts +22 -23
  35. package/src/builtins/completion-group.ts +17 -15
  36. package/src/builtins/dispatch.ts +25 -1
  37. package/src/builtins/install.ts +22 -52
  38. package/src/builtins/registry.ts +2 -0
  39. package/src/builtins/uninstall.ts +80 -0
  40. package/src/capabilities.ts +1 -3
  41. package/src/cli-tool/cli-smoke.test.ts +19 -0
  42. package/src/cli-tool/create.test.ts +119 -0
  43. package/src/cli-tool/create.ts +380 -0
  44. package/{examples/consumer-app/capabilities.test.ts → src/cli-tool/full-example-capabilities.test.ts} +15 -14
  45. package/src/cli-tool/main.ts +8 -0
  46. package/src/cli-tool/post-create.ts +111 -0
  47. package/src/cli-tool/program.ts +82 -0
  48. package/src/cli-tool/prompt.ts +28 -0
  49. package/src/cli-tool/run-create.ts +149 -0
  50. package/src/cli.ts +0 -2
  51. package/src/config/bootstrap.ts +16 -9
  52. package/src/config/resolve.test.ts +167 -0
  53. package/src/config/resolve.ts +50 -6
  54. package/src/docs/api-guide.test.ts +4 -5
  55. package/src/docs/docs.test.ts +2 -1
  56. package/src/docs/mcp-guide.ts +7 -8
  57. package/src/index.ts +3 -10
  58. package/src/install/binary-placement.test.ts +101 -0
  59. package/src/install/binary-placement.ts +47 -0
  60. package/src/install/index.ts +117 -123
  61. package/src/install/install.test.ts +89 -105
  62. package/src/install/normalize-uninstall.ts +11 -0
  63. package/src/install/normalize.ts +4 -19
  64. package/src/install/paths.ts +0 -22
  65. package/src/install/plan.ts +14 -6
  66. package/src/install/shell.ts +0 -14
  67. package/src/install/status.test.ts +6 -6
  68. package/src/install/status.ts +0 -6
  69. package/src/install/target-effective.ts +0 -2
  70. package/src/install/target-scope.ts +15 -28
  71. package/src/install/target-types.ts +0 -16
  72. package/src/install/targets/app.ts +19 -28
  73. package/src/install/targets/configure.ts +5 -1
  74. package/src/install/targets/index.ts +0 -3
  75. package/src/install/targets.test.ts +24 -42
  76. package/src/mcp/env.test.ts +92 -0
  77. package/src/mcp/env.ts +15 -14
  78. package/src/parse.test.ts +3 -2
  79. package/src/prompt.ts +10 -0
  80. package/src/schema.ts +9 -1
  81. package/src/types.ts +27 -9
  82. package/src/validate.ts +5 -11
  83. package/docs/templates/cursor/rules/cli-program.mdc +0 -31
  84. package/examples/config-app/main.ts +0 -20
  85. package/examples/config-app/program.ts +0 -78
  86. package/examples/config-app/schema.ts +0 -37
  87. package/examples/config-app/types.ts +0 -19
  88. package/examples/consumer-app/README.md +0 -56
  89. package/examples/consumer-app/src/main.ts +0 -15
  90. package/examples/consumer-app/src/program.ts +0 -108
  91. package/src/install/app.ts +0 -94
  92. package/src/install/bootstrap.ts +0 -22
  93. package/src/install/completions.ts +0 -56
  94. package/src/install/targets/completions.ts +0 -133
  95. package/src/install/update.test.ts +0 -123
  96. package/src/install/update.ts +0 -54
  97. /package/examples/{consumer-app → full-example}/schemas/configSchemas.ts +0 -0
  98. /package/examples/{consumer-app → full-example}/schemas/outputSchemas.ts +0 -0
  99. /package/examples/{consumer-app → full-example}/scripts/schemagen/discover-schema-roots.test.ts +0 -0
  100. /package/examples/{consumer-app → full-example}/scripts/schemagen/discover-schema-roots.ts +0 -0
  101. /package/examples/{consumer-app → full-example}/scripts/schemagen/naming.ts +0 -0
  102. /package/examples/{consumer-app → full-example}/scripts/schemagen.ts +0 -0
  103. /package/examples/{consumer-app → full-example}/tsconfig.json +0 -0
@@ -8,6 +8,8 @@
8
8
  "argsbarg": "file:../..",
9
9
  },
10
10
  "devDependencies": {
11
+ "@biomejs/biome": "^2.5.0",
12
+ "@types/bun": "^1.3.12",
11
13
  "ts-json-schema-generator": "^2.3.0",
12
14
  "typescript": "^5.9.3",
13
15
  },
@@ -0,0 +1,134 @@
1
+ set shell := ["bash", "-eu", "-o", "pipefail", "-c"]
2
+
3
+ HOMEBREW_NO_AUTO_UPDATE := "1"
4
+ HOMEBREW_NO_INSTALL_CLEANUP := "1"
5
+ HOMEBREW_NO_ENV_HINTS := "1"
6
+
7
+ cli_key := `bun scripts/print-identity.ts key`
8
+ tap_org := `bun scripts/print-identity.ts tapOrg`
9
+ tap_repo := `bun scripts/print-identity.ts tapRepo`
10
+ tap := `bun scripts/print-identity.ts tap`
11
+ brew_prefix := `brew --prefix`
12
+ tap_parent := brew_prefix + "/Library/Taps/" + tap_org
13
+ tap_path := tap_parent + "/homebrew-" + tap_repo
14
+
15
+ # List available recipes (default)
16
+ _:
17
+ @just --list
18
+
19
+ # Compile the CLI binary to dist/full-example
20
+ build:
21
+ bun build ./src/index.ts --compile --outfile=dist/{{cli_key}}
22
+ @rm -f .*.bun-build
23
+
24
+ # Run schemagen, git diff check, typecheck, and format
25
+ check: schemagen
26
+ git diff --exit-code schemas/
27
+ just typecheck
28
+ just format
29
+
30
+ # Run the CLI from source with optional args; restarts on file changes
31
+ dev *ARGS:
32
+ bun --watch ./src/index.ts {{ARGS}}
33
+
34
+ # Regenerate docs/schema.json and docs/skill.md
35
+ docgen: schemagen
36
+ @just run docs schema --save
37
+ @just run docs skill --save
38
+
39
+ alias fmt := format
40
+
41
+ # Format and lint sources (auto-fix)
42
+ format:
43
+ bun run biome check ./src ./scripts --write
44
+
45
+ # Alias for backward compatibility
46
+ install: install-local
47
+
48
+ # Refresh skills and MCP without reinstalling the formula
49
+ install-artifacts:
50
+ {{cli_key}} install --reinstall --yes
51
+
52
+ # Dev install: build, write dev formula, symlink tap, brew install
53
+ install-local: build
54
+ @bun scripts/gen-dev-formula.ts
55
+ @brew untap {{tap}} 2>/dev/null || true
56
+ mkdir -p {{tap_parent}}
57
+ ln -sfn '{{justfile_directory()}}' {{tap_path}}
58
+ brew install --formula {{tap}}/{{cli_key}}
59
+ @echo ""
60
+ @echo "Next: {{cli_key}} install --configure"
61
+
62
+ # Remove local dev install, then install from GitHub tap
63
+ install-production: uninstall
64
+ brew tap {{tap}}
65
+ brew install --formula {{tap}}/{{cli_key}}
66
+ @echo ""
67
+ @echo "Next: {{cli_key}} install --configure"
68
+
69
+ # Alias for backward compatibility
70
+ reinstall: reinstall-local
71
+
72
+ # Rebuild binary and swap into Cellar (run install-local first)
73
+ reinstall-local: build
74
+ install -m 755 dist/{{cli_key}} "$(brew --prefix {{cli_key}})/bin/{{cli_key}}"
75
+
76
+ # Lint sources without writing
77
+ lint:
78
+ bun run biome check ./src ./scripts
79
+
80
+ # Run the CLI from source once
81
+ run *ARGS:
82
+ bun ./src/index.ts {{ARGS}}
83
+
84
+ # Generate JSON Schema artifacts from TypeScript types
85
+ schemagen:
86
+ bun run schemagen
87
+ just format
88
+
89
+ # Install bun/npm dependencies
90
+ setup:
91
+ bun install
92
+
93
+ # Run unit tests (after check)
94
+ test: check
95
+ bun test .
96
+
97
+ # Install release formula from tap and run formula test
98
+ test-release:
99
+ @brew untap {{tap}} 2>/dev/null || true
100
+ mkdir -p {{tap_parent}}
101
+ ln -sfn '{{justfile_directory()}}' {{tap_path}}
102
+ @brew uninstall --formula {{tap}}/{{cli_key}} 2>/dev/null || true
103
+ brew install --formula {{tap}}/{{cli_key}}
104
+ brew test {{cli_key}}
105
+
106
+ # Typecheck without emitting build artifacts
107
+ typecheck:
108
+ bun run tsc --noEmit
109
+
110
+ # Undo just install-local: agent artifacts first, then formula
111
+ uninstall: uninstall-artifacts uninstall-formula
112
+
113
+ # Remove agent artifacts only (skills, MCP)
114
+ uninstall-artifacts:
115
+ {{cli_key}} uninstall --yes
116
+
117
+ # Remove app config file only
118
+ uninstall-config:
119
+ {{cli_key}} uninstall --configure --yes
120
+
121
+ # Remove formula and untap
122
+ uninstall-formula:
123
+ @brew uninstall --formula {{tap}}/{{cli_key}} 2>/dev/null || true
124
+ @brew uninstall --formula {{tap}}/{{cli_key}}-local 2>/dev/null || true
125
+ @brew untap {{tap}} 2>/dev/null || true
126
+
127
+ # Remove release formula (does not untap)
128
+ uninstall-release:
129
+ @brew uninstall --formula {{tap}}/{{cli_key}} 2>/dev/null || true
130
+
131
+ # Remove release formula and untap
132
+ uninstall-release-tap:
133
+ @brew uninstall --formula {{tap}}/{{cli_key}} 2>/dev/null || true
134
+ @brew untap {{tap}} 2>/dev/null || true
@@ -1,16 +1,23 @@
1
1
  {
2
- "name": "consumer-app-example",
2
+ "name": "full-example",
3
3
  "private": true,
4
4
  "type": "module",
5
- "description": "Argsbarg kitchen-sink reference app (copy template; not published to npm).",
5
+ "module": "src/index.ts",
6
+ "description": "Argsbarg full example reference app (copy template; not published to npm).",
7
+ "engines": {
8
+ "bun": ">=1.3"
9
+ },
6
10
  "scripts": {
11
+ "biome": "biome",
7
12
  "schemagen": "bun run scripts/schemagen.ts",
8
- "start": "bun run src/main.ts"
13
+ "start": "bun run src/index.ts"
9
14
  },
10
15
  "dependencies": {
11
16
  "argsbarg": "file:../.."
12
17
  },
13
18
  "devDependencies": {
19
+ "@biomejs/biome": "^2.5.0",
20
+ "@types/bun": "^1.3.12",
14
21
  "ts-json-schema-generator": "^2.3.0",
15
22
  "typescript": "^5.9.3"
16
23
  }
@@ -35,6 +35,6 @@
35
35
  "maxRetries"
36
36
  ],
37
37
  "additionalProperties": false,
38
- "description": "Config schema\n\nApplication settings for `consumer-app` (`program.appConfig`).",
38
+ "description": "Config schema\n\nApplication settings for `full-example` (`program.appConfig`).",
39
39
  "definitions": {}
40
40
  }
@@ -23,6 +23,6 @@
23
23
  "apiTokenSet",
24
24
  "version"
25
25
  ],
26
- "description": "JSON payload for `consumer-app status --json`.",
26
+ "description": "JSON payload for `full-example status --json`.",
27
27
  "definitions": {}
28
28
  }
@@ -0,0 +1,11 @@
1
+ /** CLI identity — substituted by `argsbarg create`. */
2
+
3
+ export const createIdentity = {
4
+ key: "full-example",
5
+ className: "FullExample",
6
+ tap: "local/full-example",
7
+ homepage: "https://github.com/bdombro/bun-argsbarg",
8
+ releaseRepo: "bdombro/bun-argsbarg",
9
+ desc: "Argsbarg full example reference app",
10
+ envPrefix: "FULL_EXAMPLE",
11
+ } as const;
@@ -0,0 +1,73 @@
1
+ /** Shared Ruby fragments embedded in Homebrew formulae. */
2
+
3
+ import { createIdentity } from "./create-identity.ts";
4
+
5
+ const { key, className, desc, homepage, releaseRepo } = createIdentity;
6
+
7
+ export const formulaInstallRuby = `def install
8
+ bin.install "${key}"
9
+ chmod 0755, bin/"${key}"
10
+ generate_completions_from_executable(bin/"${key}", "completion", base_name: "${key}")
11
+ end`;
12
+
13
+ export const formulaPostInstallRuby = `def post_install
14
+ system bin/"${key}", "install", "--reinstall", "--yes"
15
+ end`;
16
+
17
+ export const formulaCaveatsRuby = `def caveats
18
+ <<~EOS
19
+ Run \`${key} install --configure\` to set up app config (interactive).
20
+ EOS
21
+ end`;
22
+
23
+ export const formulaTestRuby = `test do
24
+ assert_match version.to_s, shell_output("#{bin}/${key} version")
25
+ assert_predicate bash_completion/"${key}", :exist?
26
+ assert_predicate zsh_completion/"_${key}", :exist?
27
+ assert_predicate fish_completion/"${key}.fish", :exist?
28
+ end`;
29
+
30
+ export interface FormulaCoords {
31
+ url: string;
32
+ version: string;
33
+ sha256: string;
34
+ }
35
+
36
+ export function releaseFormulaUrl(version: string): string {
37
+ return `https://github.com/${releaseRepo}/releases/download/v${version}/${key}`;
38
+ }
39
+
40
+ export function renderFormula(coords: FormulaCoords): string {
41
+ return `class ${className} < Formula
42
+ desc "${desc}"
43
+ homepage "${homepage}"
44
+ url "${coords.url}"
45
+ version "${coords.version}"
46
+ sha256 "${coords.sha256}"
47
+ {dependsOnBlock}
48
+ ${formulaInstallRuby}
49
+
50
+ ${formulaPostInstallRuby}
51
+
52
+ ${formulaCaveatsRuby}
53
+
54
+ ${formulaTestRuby}
55
+ end
56
+ `;
57
+ }
58
+
59
+ export function renderReleaseFormula(version: string, sha256: string): string {
60
+ return renderFormula({
61
+ url: releaseFormulaUrl(version),
62
+ version,
63
+ sha256,
64
+ });
65
+ }
66
+
67
+ export function renderDevFormula(stagingPath: string, version: string, sha256: string): string {
68
+ return renderFormula({
69
+ url: `file://${stagingPath}`,
70
+ version,
71
+ sha256,
72
+ });
73
+ }
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env bun
2
+ /** Generate Formula/full-example.rb for local dev install (same formula as release; file:// URL only). */
3
+
4
+ import { createHash } from "node:crypto";
5
+ import { chmodSync, copyFileSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
6
+ import { join } from "node:path";
7
+ import { createIdentity } from "./create-identity.ts";
8
+ import { renderDevFormula } from "./formula-shared.ts";
9
+
10
+ const { key } = createIdentity;
11
+ const root = join(import.meta.dir, "..");
12
+ const distPath = join(root, "dist", key);
13
+ const stagingDir = join(root, "Formula", ".staging");
14
+ const stagingPath = join(stagingDir, key);
15
+
16
+ mkdirSync(stagingDir, { recursive: true });
17
+ copyFileSync(distPath, stagingPath);
18
+ chmodSync(stagingPath, 0o755);
19
+
20
+ const binary = readFileSync(stagingPath);
21
+ const sha256 = createHash("sha256").update(binary).digest("hex");
22
+ const version = JSON.parse(readFileSync(join(root, "package.json"), "utf8")).version as string;
23
+
24
+ const out = join(root, "Formula", `${key}.rb`);
25
+ writeFileSync(out, renderDevFormula(stagingPath, version, sha256), "utf8");
26
+ console.log(`Wrote ${out}`);
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env bun
2
+ /** Print a field from scripts/create-identity.ts for justfile backticks. */
3
+
4
+ import { createIdentity } from "./create-identity.ts";
5
+
6
+ const field = process.argv[2];
7
+ if (!field) {
8
+ console.error("Usage: bun scripts/print-identity.ts <key|className|tap|tapOrg|tapRepo|envPrefix>");
9
+ process.exit(1);
10
+ }
11
+
12
+ const [tapOrg, tapRepo] = createIdentity.tap.split("/");
13
+ const values: Record<string, string> = {
14
+ key: createIdentity.key,
15
+ className: createIdentity.className,
16
+ tap: createIdentity.tap,
17
+ tapOrg: tapOrg ?? "",
18
+ tapRepo: tapRepo ?? "",
19
+ envPrefix: createIdentity.envPrefix,
20
+ };
21
+
22
+ const value = values[field];
23
+ if (value === undefined) {
24
+ console.error(`Unknown field: ${field}`);
25
+ process.exit(1);
26
+ }
27
+ process.stdout.write(value);
@@ -0,0 +1,21 @@
1
+ /*
2
+ Echo leaf — minimal MCP-friendly command.
3
+ */
4
+
5
+ import { type CliLeaf, CliOptionKind } from "argsbarg";
6
+
7
+ export const echoCommand = {
8
+ key: "echo",
9
+ description: "Echo a message (MCP-friendly leaf).",
10
+ options: [
11
+ {
12
+ name: "message",
13
+ description: "Text to print.",
14
+ kind: CliOptionKind.String,
15
+ required: true,
16
+ },
17
+ ],
18
+ handler: (ctx) => {
19
+ console.log(ctx.stringOpt("message") ?? "");
20
+ },
21
+ } satisfies CliLeaf;
@@ -0,0 +1,10 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { statusCommand } from "./command.ts";
3
+
4
+ describe("status command", () => {
5
+ test("exports outputSchema and json option", () => {
6
+ expect(statusCommand.key).toBe("status");
7
+ expect(statusCommand.outputSchema).toBeDefined();
8
+ expect(statusCommand.options?.some((o) => o.name === "json")).toBe(true);
9
+ });
10
+ });
@@ -0,0 +1,36 @@
1
+ /*
2
+ Status leaf — demonstrates outputSchema and ctx.appConfig.
3
+ */
4
+
5
+ import { type CliLeaf, CliOptionKind } from "argsbarg";
6
+ import { STATUS_JSON_OUTPUT_SCHEMA } from "../../../schemas/outputSchemas.ts";
7
+ import type { StatusJsonOutput } from "./types.ts";
8
+
9
+ export const statusCommand = {
10
+ key: "status",
11
+ description: "Show resolved config and app version.",
12
+ options: [
13
+ {
14
+ name: "json",
15
+ description: "Emit JSON.",
16
+ kind: CliOptionKind.Presence,
17
+ },
18
+ ],
19
+ outputSchema: STATUS_JSON_OUTPUT_SCHEMA,
20
+ handler: (ctx) => {
21
+ const out: StatusJsonOutput = {
22
+ defaultRegion: ctx.appConfig.get("defaultRegion") as string | undefined,
23
+ maxRetries: ctx.appConfig.get("maxRetries") as number | undefined,
24
+ apiTokenSet: ctx.appConfig.get("apiToken") !== undefined,
25
+ version: ctx.program.version,
26
+ };
27
+ if (ctx.hasFlag("json")) {
28
+ console.log(JSON.stringify(out, null, 2));
29
+ } else {
30
+ console.log(`version=${out.version}`);
31
+ console.log(`region=${out.defaultRegion ?? "(not set)"}`);
32
+ console.log(`maxRetries=${out.maxRetries ?? "(not set)"}`);
33
+ console.log(`apiToken=${out.apiTokenSet ? "set" : "missing"}`);
34
+ }
35
+ },
36
+ } satisfies CliLeaf;
@@ -1,4 +1,4 @@
1
- /** JSON payload for `consumer-app status --json`. */
1
+ /** JSON payload for `full-example status --json`. */
2
2
  export interface StatusJsonOutput {
3
3
  /** Resolved AWS region. */
4
4
  defaultRegion?: string;
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env bun
2
+ /*
3
+ Thin CLI entry — delegates to argsbarg runtime.
4
+ */
5
+
6
+ import { Cli } from "argsbarg";
7
+ import { program } from "./program.ts";
8
+
9
+ const cli = new Cli(program);
10
+ await cli.run();
@@ -0,0 +1,57 @@
1
+ /*
2
+ Kitchen-sink CliProgram — every argsbarg builtin enabled; command registration only.
3
+ */
4
+
5
+ import type { CliAppConfig, CliAppConfigEntry, CliProgram } from "argsbarg";
6
+ import readmeText from "../README.md" with { type: "text" };
7
+ import { APP_CONFIG_JSON_SCHEMA } from "../schemas/configSchemas.ts";
8
+ import { createIdentity } from "../scripts/create-identity.ts";
9
+ import { echoCommand } from "./commands/echo/command.ts";
10
+ import { statusCommand } from "./commands/status/command.ts";
11
+
12
+ const configSchema = {
13
+ apiToken: {
14
+ description: "Create at https://example.com/settings/tokens",
15
+ env: `${createIdentity.envPrefix}_API_TOKEN`,
16
+ sensitive: true,
17
+ },
18
+ defaultRegion: {
19
+ description: "AWS region for API calls.",
20
+ required: false,
21
+ },
22
+ maxRetries: {
23
+ description: "HTTP retry count (0–10).",
24
+ required: false,
25
+ },
26
+ prefs: {
27
+ description: "Local cache preferences (not exported to env).",
28
+ required: false,
29
+ },
30
+ } as const satisfies Record<string, CliAppConfigEntry>;
31
+
32
+ export const program = {
33
+ key: createIdentity.key,
34
+ version: "1.0.0",
35
+ description: "Argsbarg full example — all builtins, schemagen, ctx.appConfig.",
36
+ appConfig: {
37
+ jsonSchema: APP_CONFIG_JSON_SCHEMA,
38
+ entries: configSchema,
39
+ } satisfies CliAppConfig,
40
+ docs: {
41
+ enabled: true,
42
+ topics: {
43
+ readme: {
44
+ text: readmeText,
45
+ },
46
+ },
47
+ },
48
+ mcpServer: {
49
+ enabled: true,
50
+ mcpd: true,
51
+ claudePlugin: true,
52
+ },
53
+ install: {
54
+ // Defaults: agentIntegration picks skill vs MCP for --all; configure is opt-in.
55
+ },
56
+ commands: [echoCommand, statusCommand],
57
+ } satisfies CliProgram;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Config schema
3
3
  *
4
- * Application settings for `consumer-app` (`program.appConfig`).
4
+ * Application settings for `full-example` (`program.appConfig`).
5
5
  */
6
6
  export interface AppConfig {
7
7
  /** API token from the provider dashboard. */
@@ -21,9 +21,7 @@ const program = {
21
21
  readme: { text: "# nested.ts\n\nNested groups demo.\n" },
22
22
  },
23
23
  },
24
- install: {
25
- updateGetLatest: async () => ({ path: process.execPath, version: pkg.version }),
26
- },
24
+ install: {},
27
25
  commands: [
28
26
  {
29
27
  key: "stat",
package/index.d.ts CHANGED
@@ -1,5 +1,9 @@
1
1
  // Generated by dts-bundle-generator v9.5.1
2
2
 
3
+ /** Resolved absolute path to the app JSON config file (`~/.local/lib/<key>/config.json`). */
4
+ export declare function resolveAppConfigPath(program: CliProgram): string;
5
+ /** Human-readable config path for error messages (`~/…` when under home). */
6
+ export declare function displayAppConfigPath(program: CliProgram): string;
3
7
  export type ResolvedConfig = Record<string, unknown>;
4
8
  declare class EmptyAppConfigSnapshot {
5
9
  private readonly program;
@@ -245,21 +249,24 @@ export interface CliMcpToolConfig {
245
249
  */
246
250
  outputSchema?: Record<string, unknown>;
247
251
  }
252
+ /** Context passed to {@link CliAppConfigEntry.resolve} for one config key. */
253
+ export interface CliAppConfigResolveContext {
254
+ /** Schema key being resolved. */
255
+ key: string;
256
+ /** Entry metadata for this key. */
257
+ entry: CliAppConfigEntry;
258
+ /** Program root (read-only). */
259
+ program: CliProgram;
260
+ /** Raw value from the config file, if any. */
261
+ fileValue: unknown;
262
+ /** Non-empty host env string when `entry.env` is set; otherwise `undefined`. */
263
+ envValue: string | undefined;
264
+ }
248
265
  /**
249
- * Opt-out and defaults for the `install` built-in (program root only).
266
+ * Optional fallback resolver for one config key (e.g. `gh auth token` when `GH_TOKEN` is unset).
267
+ * Return `undefined` to continue resolution (env, then default).
250
268
  */
251
- export interface CliUpdateArtifact {
252
- /** Path to an executable binary to copy into the install location. */
253
- path: string;
254
- /** Release version of `path` (used for already-current checks and success messages). */
255
- version?: string;
256
- /** Called after reinstall completes (e.g. remove a temp download directory). */
257
- cleanup?: () => void | Promise<void>;
258
- }
259
- /** Fetches the latest release binary for `install --update`. */
260
- export type CliUpdateGetLatest = (ctx: {
261
- version: string;
262
- }) => Promise<CliUpdateArtifact>;
269
+ export type CliAppConfigResolveFn = (ctx: CliAppConfigResolveContext) => unknown;
263
270
  /**
264
271
  * Metadata overlay for one key in {@link CliAppConfig.entries}.
265
272
  * Types and validation come from {@link CliAppConfig.jsonSchema} when set; otherwise all values are strings.
@@ -280,6 +287,11 @@ export interface CliAppConfigEntry {
280
287
  sensitive?: boolean;
281
288
  /** When set: non-empty `process.env[env]` overrides file; value exported after resolve. */
282
289
  env?: string;
290
+ /**
291
+ * Optional fallback after file when env is empty.
292
+ * Return `undefined` to fall back to `env` (if set) and schema defaults.
293
+ */
294
+ resolve?: CliAppConfigResolveFn;
283
295
  }
284
296
  /**
285
297
  * App configuration block on the program root ({@link CliProgram.appConfig}).
@@ -307,11 +319,6 @@ export interface CliInstallConfig {
307
319
  agentIntegration?: InstallAgentIntegration;
308
320
  /** Per-artifact gates for full install/uninstall. See {@link resolveEffectiveInstallTargets}. */
309
321
  targets?: CliInstallTargets;
310
- /**
311
- * When set, enables `install --update` on the program root.
312
- * Should download or locate the latest release binary and return its path.
313
- */
314
- updateGetLatest?: CliUpdateGetLatest;
315
322
  }
316
323
  /** Agent integration mode for install — MCP vs shell skill per host. */
317
324
  export type InstallAgentIntegration = "mcp" | "skill" | "both";
@@ -328,7 +335,7 @@ export interface ResolvedInstallTarget {
328
335
  }
329
336
  /** Per-artifact gates for full install/uninstall. See {@link resolveEffectiveInstallTargets}. */
330
337
  export interface CliInstallTargets {
331
- /** Copy app to `~/.local/bin/<key>`. Default includedInAll true (opt-out). */
338
+ /** App binary status only (Homebrew PATH); no self-install. */
332
339
  app?: InstallTargetSpec;
333
340
  /** ChatGPT desktop MCP. Default false. */
334
341
  chatgptMcp?: InstallTargetSpec;
@@ -342,9 +349,7 @@ export interface CliInstallTargets {
342
349
  codexMcp?: InstallTargetSpec;
343
350
  /** Codex skill. Default false. */
344
351
  codexSkill?: InstallTargetSpec;
345
- /** Shell completions for detected shells. Default includedInAll true (opt-out). */
346
- completions?: InstallTargetSpec;
347
- /** App config: wizard on install, file removal on uninstall. Default includedInAll true. */
352
+ /** App config: wizard via install --configure only. Default not in --all. */
348
353
  configure?: InstallTargetSpec;
349
354
  /** Cursor MCP. Default false. */
350
355
  cursorMcp?: InstallTargetSpec;
@@ -465,7 +470,6 @@ export interface CliCapabilities {
465
470
  mcp: boolean;
466
471
  install: boolean;
467
472
  docs: boolean;
468
- update: boolean;
469
473
  configCommands: boolean;
470
474
  }
471
475
  /** JSON-safe command node (no handlers). */
@@ -547,49 +551,6 @@ export declare function shouldRunHeadlessWithYes(ctx: HeadlessContext, opts: {
547
551
  export declare function requireYesInNonTty(yes: boolean, hint: string, dryRun?: boolean, interactive?: boolean): void;
548
552
  /** Prefixes a success message when running in dry-run mode. */
549
553
  export declare function formatDryRunMessage(message: string, dryRun: boolean): string;
550
- /** Config for {@link ghReleaseUpdateGetLatest}. */
551
- export interface GhReleaseUpdateConfig {
552
- /** GitHub `owner/repo` slug. */
553
- repo: string;
554
- /** Release asset filename (e.g. `myapp`). */
555
- asset: string;
556
- /** Temp directory name prefix for downloads. */
557
- tempPrefix: string;
558
- /** Path to the on-disk version-check cache JSON file. */
559
- cachePath: string;
560
- /** Optional hint when `gh auth` fails or no releases exist. */
561
- repoEnvHint?: string;
562
- }
563
- /** Config for {@link createGhVersionCheck}. */
564
- export interface GhVersionCheckConfig {
565
- /** Installed semver string. */
566
- currentVersion: string;
567
- /** CLI command name for update notices (e.g. `qa`). */
568
- commandName: string;
569
- /** Path to the on-disk version-check cache JSON file. */
570
- cachePath: string;
571
- /** Cache TTL in milliseconds (default 24h). */
572
- ttlMs?: number;
573
- /** When true, skip background refresh (e.g. test subprocess). */
574
- skipRefresh?: () => boolean;
575
- /** When true, skip refresh because `gh` is unavailable. */
576
- ghAvailable?: () => boolean;
577
- /** Fetches latest release version via `gh`. */
578
- fetchLatest: () => Promise<string>;
579
- }
580
- /** Returns whether the installed version matches the latest release. */
581
- export declare function isAlreadyCurrent(current: string, latest: string): boolean;
582
- /** Strips a leading `v` from a release tag. */
583
- export declare function parseReleaseTag(tag: string): string;
584
- /** Builds a `CliUpdateGetLatest` hook that downloads a release via `gh`. */
585
- export declare function ghReleaseUpdateGetLatest(config: GhReleaseUpdateConfig): CliUpdateGetLatest;
586
- /** Version-check cache helpers for summary notices and background refresh. */
587
- export declare function createGhVersionCheck(config: GhVersionCheckConfig): {
588
- getUpdateNotice: () => string | null;
589
- refreshIfStale: () => void;
590
- };
591
- /** Shared `gh release view` fetcher for hooks and version-check refresh. */
592
- export declare function createGhFetchLatest(config: Pick<GhReleaseUpdateConfig, "repo" | "repoEnvHint">): () => Promise<string>;
593
554
  /** Resolved paths for `mcp bundle`. */
594
555
  export interface McpBundlePaths {
595
556
  binaryPath: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "argsbarg",
3
- "version": "4.1.0",
3
+ "version": "4.1.1",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "bun": ">=1.3"
@@ -12,7 +12,7 @@
12
12
  "module": "./src/index.ts",
13
13
  "types": "./index.d.ts",
14
14
  "bin": {
15
- "argsbarg": "src/index.ts"
15
+ "argsbarg": "src/cli-tool/main.ts"
16
16
  },
17
17
  "exports": {
18
18
  ".": {