argsbarg 5.0.1 → 5.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 +15 -1
- package/docs/distribution-homebrew.md +2 -0
- package/examples/full-example/scripts/formula-shared.ts +1 -0
- package/index.d.ts +10 -5
- package/package.json +1 -1
- package/src/builtins/builtins.test.ts +12 -0
- package/src/builtins/config.test.ts +8 -0
- package/src/cli-tool/cli-smoke.test.ts +5 -0
- package/src/cli-tool/create.test.ts +10 -0
- package/src/cli-tool/full-example-capabilities.test.ts +6 -0
- package/src/cli-tool/main.ts +0 -0
- package/src/config/context.test.ts +7 -0
- package/src/config/file.test.ts +7 -0
- package/src/config/resolve.test.ts +11 -0
- package/src/config/validate.test.ts +5 -0
- package/src/config.integration.test.ts +5 -0
- package/src/configure/configure.test.ts +11 -0
- package/src/configure/index.ts +14 -0
- package/src/configure/prompt.ts +7 -0
- package/src/docs/api-guide.test.ts +6 -0
- package/src/docs/docs.test.ts +7 -0
- package/src/docs/mcp-resources.test.ts +4 -0
- package/src/formats.test.ts +4 -0
- package/src/headless.test.ts +6 -0
- package/src/headless.ts +5 -4
- package/src/hidden-mcpb.test.ts +10 -0
- package/src/install/binary-placement.test.ts +9 -0
- package/src/install/gh-release-update.test.ts +4 -0
- package/src/install/install-validate.test.ts +5 -0
- package/src/install/mcp-codex.test.ts +7 -0
- package/src/install/mcp-openclaw.test.ts +6 -0
- package/src/install/mcp-opencode.test.ts +6 -0
- package/src/install/status.test.ts +9 -0
- package/src/install/targets.test.ts +9 -0
- package/src/invoke.test.ts +7 -0
- package/src/mcp/claude.test.ts +6 -0
- package/src/mcp/env.test.ts +7 -0
- package/src/mcp/zip.test.ts +4 -0
- package/src/mcp.integration.test.ts +17 -0
- package/src/parse.test.ts +43 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [5.0.3] - 2026-07-04
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- **JSDoc style** — short `test()` callbacks no longer carry redundant one-liners; `describe` blocks still documented. `requireYesInNonTty` uses per-parameter JSDoc instead of `@param`. Pure re-export barrels stay comment-free.
|
|
15
|
+
|
|
16
|
+
## [5.0.2] - 2026-07-04
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- **JSDoc style** — every `describe` block in `src/**/*.test.ts` now has a human-readable JSDoc; `configure` modules brought in line with file headers and symbol docs.
|
|
21
|
+
|
|
10
22
|
## [5.0.1] - 2026-07-04
|
|
11
23
|
|
|
12
24
|
|
|
@@ -567,7 +579,9 @@ const cli = { ... } satisfies CliProgram; // or : CliProgram
|
|
|
567
579
|
- 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`).
|
|
568
580
|
- Imports: use `CliPositional` where needed; replace `CliOptionDef` with `CliOption` or `CliPositional` as appropriate.
|
|
569
581
|
|
|
570
|
-
[Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v5.0.
|
|
582
|
+
[Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v5.0.3...HEAD
|
|
583
|
+
[5.0.3]: https://github.com/bdombro/bun-argsbarg/releases/tag/v5.0.3
|
|
584
|
+
[5.0.2]: https://github.com/bdombro/bun-argsbarg/releases/tag/v5.0.2
|
|
571
585
|
[5.0.1]: https://github.com/bdombro/bun-argsbarg/releases/tag/v5.0.1
|
|
572
586
|
[5.0.0]: https://github.com/bdombro/bun-argsbarg/releases/tag/v5.0.0
|
|
573
587
|
[4.1.1]: https://github.com/bdombro/bun-argsbarg/releases/tag/v4.1.1
|
|
@@ -60,6 +60,8 @@ Completions require users to configure their shell per [Homebrew Shell Completio
|
|
|
60
60
|
|
|
61
61
|
**Why configure is separate from `post_install`:** the wizard is interactive (TTY + prompts for secrets). Formula `post_install` runs non-interactively during `brew install` and in CI (`brew test`). Apps with `appConfig` print a one-line configure hint in formula `caveats` instead.
|
|
62
62
|
|
|
63
|
+
**MCP hosts:** when `mcpServer.enabled` is true, add a caveats line that chat apps (Cursor, Claude Desktop, etc.) must be **restarted** after `brew install` / `brew upgrade` — `post_install` updates MCP config on disk, but hosts typically load it only at startup.
|
|
64
|
+
|
|
63
65
|
## Bootstrap CLI (`argsbarg create`)
|
|
64
66
|
|
|
65
67
|
Copy the shipped `examples/full-example` template into a new directory with identity substitutions, then run install, schemagen, tests, and git init (when appropriate):
|
|
@@ -17,6 +17,7 @@ export const formulaPostInstallRuby = `def post_install
|
|
|
17
17
|
export const formulaCaveatsRuby = `def caveats
|
|
18
18
|
<<~EOS
|
|
19
19
|
Run \`${key} configure\` to set up agent artifacts and app config (interactive).
|
|
20
|
+
Restart MCP chat apps (Cursor, Claude Desktop, etc.) after install or upgrade so they load the updated server.
|
|
20
21
|
EOS
|
|
21
22
|
end`;
|
|
22
23
|
|
package/index.d.ts
CHANGED
|
@@ -551,11 +551,16 @@ export declare function shouldRunHeadlessWithYes(ctx: HeadlessContext, opts: {
|
|
|
551
551
|
hasRequiredArgs: boolean;
|
|
552
552
|
dryRun?: boolean;
|
|
553
553
|
}, interactive?: boolean): boolean;
|
|
554
|
-
/**
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
554
|
+
/** Exits when non-interactive mode is used without `--yes`. */
|
|
555
|
+
export declare function requireYesInNonTty(
|
|
556
|
+
/** True when `--yes` was passed on the command line. */
|
|
557
|
+
yes: boolean,
|
|
558
|
+
/** Command-specific guidance appended to the error message. */
|
|
559
|
+
hint: string,
|
|
560
|
+
/** When true, skip the check (dry-run preview). */
|
|
561
|
+
dryRun?: boolean,
|
|
562
|
+
/** Injectable TTY probe for tests. */
|
|
563
|
+
interactive?: boolean): void;
|
|
559
564
|
/** Prefixes a success message when running in dry-run mode. */
|
|
560
565
|
export declare function formatDryRunMessage(message: string, dryRun: boolean): string;
|
|
561
566
|
/** Resolved paths for `mcp bundle`. */
|
package/package.json
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Tests for builtins/builtins module behavior.
|
|
3
|
+
*/
|
|
4
|
+
|
|
1
5
|
import { describe, expect, test } from "bun:test";
|
|
2
6
|
import { resolveCapabilities } from "../capabilities.ts";
|
|
3
7
|
import { cliBuiltinDocsGroup } from "../docs/builtin.ts";
|
|
@@ -31,6 +35,7 @@ const noMcp: CliProgram = {
|
|
|
31
35
|
commands: [{ key: "ping", description: "Ping.", handler: () => {} }],
|
|
32
36
|
};
|
|
33
37
|
|
|
38
|
+
/** Tests for builtins help copy. */
|
|
34
39
|
describe("builtins help copy", () => {
|
|
35
40
|
test("configure command includes Homebrew-oriented description", () => {
|
|
36
41
|
const configure = cliBuiltinConfigureCommand(fixture);
|
|
@@ -56,6 +61,7 @@ describe("builtins help copy", () => {
|
|
|
56
61
|
expect(configure.description).not.toContain("MCP");
|
|
57
62
|
});
|
|
58
63
|
|
|
64
|
+
/** Configure notes mention brew upgrade and interactive configure. */
|
|
59
65
|
test("configure notes mention brew upgrade and interactive configure", () => {
|
|
60
66
|
const configure = cliBuiltinConfigureCommand(fixture);
|
|
61
67
|
expect(configure.notes).toContain("brew upgrade");
|
|
@@ -93,6 +99,7 @@ describe("builtins help copy", () => {
|
|
|
93
99
|
});
|
|
94
100
|
});
|
|
95
101
|
|
|
102
|
+
/** Tests for presentation root. */
|
|
96
103
|
describe("presentation root", () => {
|
|
97
104
|
test("includes mcp and configure when enabled", () => {
|
|
98
105
|
const root = cliPresentationRoot(fixture);
|
|
@@ -115,6 +122,7 @@ describe("presentation root", () => {
|
|
|
115
122
|
});
|
|
116
123
|
});
|
|
117
124
|
|
|
125
|
+
/** Tests for completion emitters. */
|
|
118
126
|
describe("completion emitters", () => {
|
|
119
127
|
test("fish script references app key and subcommands", () => {
|
|
120
128
|
const schema = cliPresentationRoot(fixture);
|
|
@@ -144,7 +152,9 @@ describe("completion emitters", () => {
|
|
|
144
152
|
});
|
|
145
153
|
});
|
|
146
154
|
|
|
155
|
+
/** Tests for schema export builtins. */
|
|
147
156
|
describe("schema export builtins", () => {
|
|
157
|
+
/** ExportPresentationBuiltins includes config when appConfig set. */
|
|
148
158
|
test("exportPresentationBuiltins includes config when appConfig set", () => {
|
|
149
159
|
const withConfig: CliProgram = {
|
|
150
160
|
...fixture,
|
|
@@ -165,7 +175,9 @@ describe("schema export builtins", () => {
|
|
|
165
175
|
});
|
|
166
176
|
});
|
|
167
177
|
|
|
178
|
+
/** Tests for docs skill topic copy. */
|
|
168
179
|
describe("docs skill topic copy", () => {
|
|
180
|
+
/** Tests that mentions configure when configure is enabled. */
|
|
169
181
|
test("mentions configure when configure is enabled", () => {
|
|
170
182
|
const withDocs: CliProgram = {
|
|
171
183
|
...noMcp,
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Tests for builtins/config module behavior.
|
|
3
|
+
*/
|
|
4
|
+
|
|
1
5
|
import { describe, expect, test } from "bun:test";
|
|
2
6
|
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
3
7
|
import { tmpdir } from "node:os";
|
|
@@ -20,7 +24,9 @@ function configFixture(): CliProgram {
|
|
|
20
24
|
};
|
|
21
25
|
}
|
|
22
26
|
|
|
27
|
+
/** Tests for builtins/config. */
|
|
23
28
|
describe("builtins/config", () => {
|
|
29
|
+
/** Tests that config get redacts sensitive values. */
|
|
24
30
|
test("config get redacts sensitive values", async () => {
|
|
25
31
|
const dir = mkdtempSync(join(tmpdir(), "cfg-builtin-"));
|
|
26
32
|
const prevHome = process.env.HOME;
|
|
@@ -43,6 +49,7 @@ describe("builtins/config", () => {
|
|
|
43
49
|
}
|
|
44
50
|
});
|
|
45
51
|
|
|
52
|
+
/** Tests that config get --json redacts sensitive as { set: true }. */
|
|
46
53
|
test("config get --json redacts sensitive as { set: true }", async () => {
|
|
47
54
|
const dir = mkdtempSync(join(tmpdir(), "cfg-builtin-"));
|
|
48
55
|
const prevHome = process.env.HOME;
|
|
@@ -65,6 +72,7 @@ describe("builtins/config", () => {
|
|
|
65
72
|
}
|
|
66
73
|
});
|
|
67
74
|
|
|
75
|
+
/** Tests that config set writes and resolves without required exit. */
|
|
68
76
|
test("config set writes and resolves without required exit", async () => {
|
|
69
77
|
const dir = mkdtempSync(join(tmpdir(), "cfg-builtin-"));
|
|
70
78
|
const prevHome = process.env.HOME;
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Tests for cli-tool/cli-smoke module behavior.
|
|
3
|
+
*/
|
|
4
|
+
|
|
1
5
|
import { describe, expect, test } from "bun:test";
|
|
2
6
|
import { spawnSync } from "node:child_process";
|
|
3
7
|
import { join } from "node:path";
|
|
4
8
|
|
|
5
9
|
const main = join(import.meta.dir, "main.ts");
|
|
6
10
|
|
|
11
|
+
/** Tests for argsbarg cli-tool. */
|
|
7
12
|
describe("argsbarg cli-tool", () => {
|
|
8
13
|
test("version subcommand prints version", () => {
|
|
9
14
|
const proc = spawnSync("bun", [main, "version"], { encoding: "utf8" });
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Tests for cli-tool/create module behavior.
|
|
3
|
+
*/
|
|
4
|
+
|
|
1
5
|
import { describe, expect, test } from "bun:test";
|
|
2
6
|
import { mkdtempSync, rmSync } from "node:fs";
|
|
3
7
|
import { tmpdir } from "node:os";
|
|
@@ -12,7 +16,9 @@ import {
|
|
|
12
16
|
substituteTemplateContent,
|
|
13
17
|
} from "./create.ts";
|
|
14
18
|
|
|
19
|
+
/** Tests for argsbarg create. */
|
|
15
20
|
describe("argsbarg create", () => {
|
|
21
|
+
/** Tests that substitutes {key} tokens. */
|
|
16
22
|
test("substitutes {key} tokens", () => {
|
|
17
23
|
const out = substituteTemplateContent(
|
|
18
24
|
"key={key} class={className} env={envPrefix}_API_TOKEN tap={tap} org={tapOrg}",
|
|
@@ -44,6 +50,7 @@ describe("argsbarg create", () => {
|
|
|
44
50
|
expect(classNameFromKey("1password")).toBe("App1password");
|
|
45
51
|
});
|
|
46
52
|
|
|
53
|
+
/** ResolveCreateOptions derives identity defaults from key. */
|
|
47
54
|
test("resolveCreateOptions derives identity defaults from key", () => {
|
|
48
55
|
expect(resolveCreateOptions({ key: "1password", releaseRepo: "org/1password" }).className).toBe(
|
|
49
56
|
"App1password",
|
|
@@ -63,6 +70,7 @@ describe("argsbarg create", () => {
|
|
|
63
70
|
expect(() => resolveCreateOptions({ key: "at1" })).toThrow(/release repo/i);
|
|
64
71
|
});
|
|
65
72
|
|
|
73
|
+
/** Tests that renderCreateTree includes justfile and create-identity. */
|
|
66
74
|
test("renderCreateTree includes justfile and create-identity", () => {
|
|
67
75
|
const tree = renderCreateTree({
|
|
68
76
|
key: "testapp",
|
|
@@ -88,6 +96,7 @@ describe("argsbarg create", () => {
|
|
|
88
96
|
expect(formula).toContain("create-identity.ts");
|
|
89
97
|
});
|
|
90
98
|
|
|
99
|
+
/** Tests that --check detects drift. */
|
|
91
100
|
test("--check detects drift", () => {
|
|
92
101
|
const dir = mkdtempSync(join(tmpdir(), "argsbarg-create-"));
|
|
93
102
|
try {
|
|
@@ -111,6 +120,7 @@ describe("argsbarg create", () => {
|
|
|
111
120
|
}
|
|
112
121
|
});
|
|
113
122
|
|
|
123
|
+
/** Tests that --check infers options from create-identity.ts. */
|
|
114
124
|
test("--check infers options from create-identity.ts", () => {
|
|
115
125
|
const dir = mkdtempSync(join(tmpdir(), "argsbarg-create-"));
|
|
116
126
|
try {
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Tests for cli-tool/full-example-capabilities module behavior.
|
|
3
|
+
*/
|
|
4
|
+
|
|
1
5
|
import { describe, expect, test } from "bun:test";
|
|
2
6
|
import { readFileSync } from "node:fs";
|
|
3
7
|
import { join } from "node:path";
|
|
@@ -45,7 +49,9 @@ const sinkProgram = {
|
|
|
45
49
|
],
|
|
46
50
|
} satisfies CliProgram;
|
|
47
51
|
|
|
52
|
+
/** Tests for full-example template. */
|
|
48
53
|
describe("full-example template", () => {
|
|
54
|
+
/** Tests that program source enables every builtin flag. */
|
|
49
55
|
test("program source enables every builtin flag", () => {
|
|
50
56
|
expect(programSource).toContain("mcpServer: {");
|
|
51
57
|
expect(programSource).toContain("enabled: true");
|
package/src/cli-tool/main.ts
CHANGED
|
File without changes
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Tests for config/context module behavior.
|
|
3
|
+
*/
|
|
4
|
+
|
|
1
5
|
import { describe, expect, test } from "bun:test";
|
|
2
6
|
import { mkdtempSync, rmSync } from "node:fs";
|
|
3
7
|
import { tmpdir } from "node:os";
|
|
@@ -20,7 +24,9 @@ const program: CliProgram = {
|
|
|
20
24
|
handler: () => {},
|
|
21
25
|
};
|
|
22
26
|
|
|
27
|
+
/** Tests for config/context. */
|
|
23
28
|
describe("config/context", () => {
|
|
29
|
+
/** Tests that AppConfigSnapshot get, require, read, set. */
|
|
24
30
|
test("AppConfigSnapshot get, require, read, set", () => {
|
|
25
31
|
const dir = mkdtempSync(join(tmpdir(), "ctx-test-"));
|
|
26
32
|
const prevHome = process.env.HOME;
|
|
@@ -50,6 +56,7 @@ describe("config/context", () => {
|
|
|
50
56
|
}
|
|
51
57
|
});
|
|
52
58
|
|
|
59
|
+
/** Tests that EmptyAppConfigSnapshot when program.appConfig unset. */
|
|
53
60
|
test("EmptyAppConfigSnapshot when program.appConfig unset", () => {
|
|
54
61
|
const programWithoutConfig: CliProgram = {
|
|
55
62
|
key: "x",
|
package/src/config/file.test.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Tests for config/file module behavior.
|
|
3
|
+
*/
|
|
4
|
+
|
|
1
5
|
import { describe, expect, test } from "bun:test";
|
|
2
6
|
import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
3
7
|
import { tmpdir } from "node:os";
|
|
@@ -40,6 +44,7 @@ function withHome<T>(fn: (home: string) => T): T {
|
|
|
40
44
|
}
|
|
41
45
|
}
|
|
42
46
|
|
|
47
|
+
/** Tests for config/file. */
|
|
43
48
|
describe("config/file", () => {
|
|
44
49
|
test("buildProgramUserConfig from program.appConfig env entries", () => {
|
|
45
50
|
const cfg = buildProgramUserConfig(program);
|
|
@@ -59,6 +64,7 @@ describe("config/file", () => {
|
|
|
59
64
|
});
|
|
60
65
|
});
|
|
61
66
|
|
|
67
|
+
/** ResolveAppConfig prefers host env over file. */
|
|
62
68
|
test("resolveAppConfig prefers host env over file", () => {
|
|
63
69
|
withHome((_home) => {
|
|
64
70
|
const prevToken = process.env.API_TOKEN;
|
|
@@ -76,6 +82,7 @@ describe("config/file", () => {
|
|
|
76
82
|
});
|
|
77
83
|
});
|
|
78
84
|
|
|
85
|
+
/** MissingRequiredConfig and formatMissingConfigMessage. */
|
|
79
86
|
test("missingRequiredConfig and formatMissingConfigMessage", () => {
|
|
80
87
|
const prev = process.env.API_TOKEN;
|
|
81
88
|
delete process.env.API_TOKEN;
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Tests for config/resolve module behavior.
|
|
3
|
+
*/
|
|
4
|
+
|
|
1
5
|
import { describe, expect, test } from "bun:test";
|
|
2
6
|
import type { CliProgram } from "../types.ts";
|
|
3
7
|
import { captureMappedHostEnv, exportConfigToEnv, resolveAppConfig } from "./resolve.ts";
|
|
@@ -25,6 +29,7 @@ const program: CliProgram = {
|
|
|
25
29
|
handler: () => {},
|
|
26
30
|
};
|
|
27
31
|
|
|
32
|
+
/** Tests for config/resolve. */
|
|
28
33
|
describe("config/resolve", () => {
|
|
29
34
|
test("prefers env over file for mapped keys", () => {
|
|
30
35
|
const prev = process.env.API_TOKEN;
|
|
@@ -110,6 +115,7 @@ describe("config/resolve", () => {
|
|
|
110
115
|
}
|
|
111
116
|
});
|
|
112
117
|
|
|
118
|
+
/** Resolve callback supplies value when env and file are absent. */
|
|
113
119
|
test("resolve callback supplies value when env and file are absent", () => {
|
|
114
120
|
const resolveProgram: CliProgram = {
|
|
115
121
|
...program,
|
|
@@ -135,6 +141,7 @@ describe("config/resolve", () => {
|
|
|
135
141
|
}
|
|
136
142
|
});
|
|
137
143
|
|
|
144
|
+
/** Env overrides resolve callback. */
|
|
138
145
|
test("env overrides resolve callback", () => {
|
|
139
146
|
const resolveProgram: CliProgram = {
|
|
140
147
|
...program,
|
|
@@ -161,6 +168,7 @@ describe("config/resolve", () => {
|
|
|
161
168
|
}
|
|
162
169
|
});
|
|
163
170
|
|
|
171
|
+
/** File overrides resolve callback. */
|
|
164
172
|
test("file overrides resolve callback", () => {
|
|
165
173
|
const resolveProgram: CliProgram = {
|
|
166
174
|
...program,
|
|
@@ -186,6 +194,7 @@ describe("config/resolve", () => {
|
|
|
186
194
|
}
|
|
187
195
|
});
|
|
188
196
|
|
|
197
|
+
/** Tests that falls back to env when resolve returns undefined. */
|
|
189
198
|
test("falls back to env when resolve returns undefined", () => {
|
|
190
199
|
const resolveProgram: CliProgram = {
|
|
191
200
|
...program,
|
|
@@ -212,6 +221,7 @@ describe("config/resolve", () => {
|
|
|
212
221
|
}
|
|
213
222
|
});
|
|
214
223
|
|
|
224
|
+
/** Resolve callback is skipped when env is set. */
|
|
215
225
|
test("resolve callback is skipped when env is set", () => {
|
|
216
226
|
let resolveCalled = false;
|
|
217
227
|
const resolveProgram: CliProgram = {
|
|
@@ -243,6 +253,7 @@ describe("config/resolve", () => {
|
|
|
243
253
|
}
|
|
244
254
|
});
|
|
245
255
|
|
|
256
|
+
/** Tests that async resolve is ignored with stderr warning. */
|
|
246
257
|
test("async resolve is ignored with stderr warning", () => {
|
|
247
258
|
const resolveProgram: CliProgram = {
|
|
248
259
|
...program,
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Tests for config/validate module behavior.
|
|
3
|
+
*/
|
|
4
|
+
|
|
1
5
|
import { describe, expect, test } from "bun:test";
|
|
2
6
|
import { parseConfigSetValue, validateConfigDocument } from "./validate.ts";
|
|
3
7
|
|
|
@@ -17,6 +21,7 @@ const rootSchema = {
|
|
|
17
21
|
},
|
|
18
22
|
};
|
|
19
23
|
|
|
24
|
+
/** Tests for config/validate. */
|
|
20
25
|
describe("config/validate", () => {
|
|
21
26
|
test("accepts valid document", () => {
|
|
22
27
|
const result = validateConfigDocument(
|
|
@@ -10,6 +10,7 @@ import { bootstrapAppConfig } from "./config/bootstrap.ts";
|
|
|
10
10
|
import { resolveAppConfigPath } from "./config/file.ts";
|
|
11
11
|
import { mcpRequest, testProgram } from "./test-fixtures.ts";
|
|
12
12
|
|
|
13
|
+
/** Tests that bootstrapAppConfig prefers host env over config file. */
|
|
13
14
|
test("bootstrapAppConfig prefers host env over config file", () => {
|
|
14
15
|
const dir = mkdtempSync(join(tmpdir(), "argsbarg-env-"));
|
|
15
16
|
const prevHome = process.env.HOME;
|
|
@@ -43,6 +44,7 @@ test("bootstrapAppConfig prefers host env over config file", () => {
|
|
|
43
44
|
}
|
|
44
45
|
});
|
|
45
46
|
|
|
47
|
+
/** MCP program.appConfig fails when required config missing. */
|
|
46
48
|
test("MCP program.appConfig fails when required config missing", async () => {
|
|
47
49
|
const responses = await mcpRequest(
|
|
48
50
|
[
|
|
@@ -60,6 +62,7 @@ test("MCP program.appConfig fails when required config missing", async () => {
|
|
|
60
62
|
expect(res.result.content[0]?.text).toContain("argsTestSecret");
|
|
61
63
|
});
|
|
62
64
|
|
|
65
|
+
/** MCP program.appConfig succeeds when env present. */
|
|
63
66
|
test("MCP program.appConfig succeeds when env present", async () => {
|
|
64
67
|
const responses = await mcpRequest(
|
|
65
68
|
[
|
|
@@ -77,6 +80,7 @@ test("MCP program.appConfig succeeds when env present", async () => {
|
|
|
77
80
|
expect(res.result.content[0]?.text.trim()).toBe("sekrit");
|
|
78
81
|
});
|
|
79
82
|
|
|
83
|
+
/** MCP config file loads and exports vars for tool handlers. */
|
|
80
84
|
test("MCP config file loads and exports vars for tool handlers", async () => {
|
|
81
85
|
const dir = mkdtempSync(join(tmpdir(), "argsbarg-mcp-"));
|
|
82
86
|
const configFile = join(dir, ".local", "lib", "mcp_test", "config");
|
|
@@ -106,6 +110,7 @@ test("MCP config file loads and exports vars for tool handlers", async () => {
|
|
|
106
110
|
rmSync(dir, { recursive: true, force: true });
|
|
107
111
|
});
|
|
108
112
|
|
|
113
|
+
/** Cli.run docs api skips required appConfig exit. */
|
|
109
114
|
test("Cli.run docs api skips required appConfig exit", async () => {
|
|
110
115
|
const dir = mkdtempSync(join(tmpdir(), "argsbarg-docs-skip-"));
|
|
111
116
|
const configFile = join(dir, ".local", "lib", "docs_skip_test", "config");
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Tests for configure/configure module behavior.
|
|
3
|
+
*/
|
|
4
|
+
|
|
1
5
|
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
6
|
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
3
7
|
import { tmpdir } from "node:os";
|
|
@@ -42,6 +46,7 @@ afterEach(() => {
|
|
|
42
46
|
rmSync(home, { recursive: true, force: true });
|
|
43
47
|
});
|
|
44
48
|
|
|
49
|
+
/** Tests for configure opts. */
|
|
45
50
|
describe("configure opts", () => {
|
|
46
51
|
test("validate rejects multiple modes", () => {
|
|
47
52
|
const opts = parseConfigureOpts({ sync: "1", status: "1" });
|
|
@@ -59,6 +64,7 @@ describe("configure opts", () => {
|
|
|
59
64
|
});
|
|
60
65
|
});
|
|
61
66
|
|
|
67
|
+
/** Tests for install paths. */
|
|
62
68
|
describe("install paths", () => {
|
|
63
69
|
test("resolveInstallPaths includes skill and mcp paths", () => {
|
|
64
70
|
const paths = resolveInstallPaths(fixture);
|
|
@@ -79,7 +85,9 @@ describe("install paths", () => {
|
|
|
79
85
|
});
|
|
80
86
|
});
|
|
81
87
|
|
|
88
|
+
/** Tests for detect installed. */
|
|
82
89
|
describe("detect installed", () => {
|
|
90
|
+
/** Detects cursor mcp when configured. */
|
|
83
91
|
test("detects cursor mcp when configured", () => {
|
|
84
92
|
const paths = resolveInstallPaths(fixture);
|
|
85
93
|
mkdirSync(join(home, ".cursor"), { recursive: true });
|
|
@@ -95,6 +103,7 @@ describe("detect installed", () => {
|
|
|
95
103
|
});
|
|
96
104
|
});
|
|
97
105
|
|
|
106
|
+
/** Tests for sync plan. */
|
|
98
107
|
describe("sync plan", () => {
|
|
99
108
|
test("buildUpdatePlan greenfield includes agent targets", () => {
|
|
100
109
|
const paths = resolveInstallPaths(fixture);
|
|
@@ -123,6 +132,7 @@ describe("sync plan", () => {
|
|
|
123
132
|
});
|
|
124
133
|
});
|
|
125
134
|
|
|
135
|
+
/** Tests for remove plan. */
|
|
126
136
|
describe("remove plan", () => {
|
|
127
137
|
test("buildUninstallPlan --all with nothing installed is empty", () => {
|
|
128
138
|
const paths = resolveInstallPaths(fixture);
|
|
@@ -131,6 +141,7 @@ describe("remove plan", () => {
|
|
|
131
141
|
});
|
|
132
142
|
});
|
|
133
143
|
|
|
144
|
+
/** Tests for app config wizard. */
|
|
134
145
|
describe("app config wizard", () => {
|
|
135
146
|
test("appConfigHasEntries when entries exist", () => {
|
|
136
147
|
expect(
|
package/src/configure/index.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Interactive and automated `configure` command orchestration (agent artifacts and app config).
|
|
3
|
+
*/
|
|
4
|
+
|
|
1
5
|
import { resolveCapabilities } from "../capabilities.ts";
|
|
2
6
|
import { displayAppConfigPath, runConfigure } from "../config/bootstrap.ts";
|
|
3
7
|
import { resolveInstallPaths } from "../install/paths.ts";
|
|
@@ -36,6 +40,7 @@ export function appConfigHasEntries(program: CliProgram): boolean {
|
|
|
36
40
|
return !!entries && Object.keys(entries).length > 0;
|
|
37
41
|
}
|
|
38
42
|
|
|
43
|
+
/** Parsed flags for the top-level `configure` built-in. */
|
|
39
44
|
export interface ConfigureOpts {
|
|
40
45
|
sync?: boolean;
|
|
41
46
|
removeAll?: boolean;
|
|
@@ -46,6 +51,7 @@ export interface ConfigureOpts {
|
|
|
46
51
|
json?: boolean;
|
|
47
52
|
}
|
|
48
53
|
|
|
54
|
+
/** Maps raw argv flags into {@link ConfigureOpts}. */
|
|
49
55
|
export function parseConfigureOpts(raw: Record<string, string>): ConfigureOpts {
|
|
50
56
|
const flag = (name: string) => raw[name] === "1";
|
|
51
57
|
return {
|
|
@@ -59,6 +65,7 @@ export function parseConfigureOpts(raw: Record<string, string>): ConfigureOpts {
|
|
|
59
65
|
};
|
|
60
66
|
}
|
|
61
67
|
|
|
68
|
+
/** Returns an error message when configure flags are inconsistent; otherwise null. */
|
|
62
69
|
export function validateConfigureOpts(opts: ConfigureOpts): string | null {
|
|
63
70
|
const flags = [opts.sync, opts.removeAll, opts.removeConfig, opts.status].filter(Boolean);
|
|
64
71
|
if (flags.length > 1) {
|
|
@@ -73,6 +80,7 @@ export function validateConfigureOpts(opts: ConfigureOpts): string | null {
|
|
|
73
80
|
return null;
|
|
74
81
|
}
|
|
75
82
|
|
|
83
|
+
/** Adapts configure flags to internal install-plan option shape. */
|
|
76
84
|
function configureToInstallOpts(opts: ConfigureOpts): InstallOpts {
|
|
77
85
|
if (opts.status) {
|
|
78
86
|
return { status: true, yes: opts.yes, dry: opts.dry, json: opts.json };
|
|
@@ -89,6 +97,7 @@ function configureToInstallOpts(opts: ConfigureOpts): InstallOpts {
|
|
|
89
97
|
return { dry: opts.dry, json: opts.json };
|
|
90
98
|
}
|
|
91
99
|
|
|
100
|
+
/** Installs a skill target and returns changed paths. */
|
|
92
101
|
function runSkillAction(root: CliProgram, kind: InstallActionKind, opts: InstallOpts): string[] {
|
|
93
102
|
const target = skillTargetFromActionKind(kind);
|
|
94
103
|
if (!target) return [];
|
|
@@ -99,6 +108,7 @@ function runSkillAction(root: CliProgram, kind: InstallActionKind, opts: Install
|
|
|
99
108
|
});
|
|
100
109
|
}
|
|
101
110
|
|
|
111
|
+
/** Runs install or uninstall actions and collects changed paths. */
|
|
102
112
|
function executePlan(
|
|
103
113
|
root: CliProgram,
|
|
104
114
|
actions: Array<InstallAction | UninstallAction>,
|
|
@@ -130,6 +140,7 @@ function executePlan(
|
|
|
130
140
|
return changed;
|
|
131
141
|
}
|
|
132
142
|
|
|
143
|
+
/** Builds plan context limited to a single artifact key. */
|
|
133
144
|
function buildSingleTargetContext(
|
|
134
145
|
root: CliProgram,
|
|
135
146
|
paths: ReturnType<typeof resolveInstallPaths>,
|
|
@@ -147,6 +158,7 @@ function buildSingleTargetContext(
|
|
|
147
158
|
};
|
|
148
159
|
}
|
|
149
160
|
|
|
161
|
+
/** Resolves install or uninstall actions for one artifact target. */
|
|
150
162
|
function actionsForTarget(
|
|
151
163
|
root: CliProgram,
|
|
152
164
|
paths: ReturnType<typeof resolveInstallPaths>,
|
|
@@ -164,6 +176,7 @@ function actionsForTarget(
|
|
|
164
176
|
return target.planUninstall(ctx);
|
|
165
177
|
}
|
|
166
178
|
|
|
179
|
+
/** Walks enabled targets with per-target prompts (TTY required). */
|
|
167
180
|
async function runInteractiveConfigure(root: CliProgram, opts: ConfigureOpts): Promise<string[]> {
|
|
168
181
|
if (!process.stdin.isTTY) {
|
|
169
182
|
throw new Error("Interactive configure requires a TTY. Use flags such as --sync --yes.");
|
|
@@ -218,6 +231,7 @@ async function runInteractiveConfigure(root: CliProgram, opts: ConfigureOpts): P
|
|
|
218
231
|
return changed;
|
|
219
232
|
}
|
|
220
233
|
|
|
234
|
+
/** Runs sync, remove, or status modes without per-target prompts. */
|
|
221
235
|
async function runAutomatedConfigure(root: CliProgram, opts: ConfigureOpts): Promise<string[]> {
|
|
222
236
|
const installOpts = configureToInstallOpts(opts);
|
|
223
237
|
const paths = resolveInstallPaths(root);
|
package/src/configure/prompt.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
TTY prompts for per-target install, skip, or uninstall during interactive `configure`.
|
|
3
|
+
*/
|
|
4
|
+
|
|
1
5
|
import { readSync } from "node:fs";
|
|
2
6
|
import type { CliInstallArtifactKey } from "../install/target-types.ts";
|
|
3
7
|
|
|
8
|
+
/** Human-readable labels for each install artifact key in interactive prompts. */
|
|
4
9
|
const LABELS: Record<CliInstallArtifactKey, string> = {
|
|
5
10
|
app: "App binary",
|
|
6
11
|
cursorSkill: "Cursor skill",
|
|
@@ -18,10 +23,12 @@ const LABELS: Record<CliInstallArtifactKey, string> = {
|
|
|
18
23
|
configure: "App config",
|
|
19
24
|
};
|
|
20
25
|
|
|
26
|
+
/** Returns the prompt label for an install artifact key. */
|
|
21
27
|
export function artifactPromptLabel(key: CliInstallArtifactKey): string {
|
|
22
28
|
return LABELS[key];
|
|
23
29
|
}
|
|
24
30
|
|
|
31
|
+
/** User choice from a per-target Y/n or y/N prompt. */
|
|
25
32
|
export type TargetPromptAction = "install" | "skip" | "uninstall";
|
|
26
33
|
|
|
27
34
|
/** Prompt per target: Y/n when not installed, y/N when installed. */
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Tests for docs/api-guide module behavior.
|
|
3
|
+
*/
|
|
4
|
+
|
|
1
5
|
import { expect, test } from "bun:test";
|
|
2
6
|
import { cliSchemaExport } from "../schema.ts";
|
|
3
7
|
import type { CliProgram } from "../types.ts";
|
|
@@ -87,6 +91,7 @@ test("generateApiGuide mentions Homebrew upgrade", () => {
|
|
|
87
91
|
expect(md).not.toContain("install --update");
|
|
88
92
|
});
|
|
89
93
|
|
|
94
|
+
/** Tests that generateApiGuide resolves {argsbarg:program} in consumer notes. */
|
|
90
95
|
test("generateApiGuide resolves {argsbarg:program} in consumer notes", () => {
|
|
91
96
|
const fixture: CliProgram = {
|
|
92
97
|
key: "myapp",
|
|
@@ -105,6 +110,7 @@ test("generateApiGuide resolves {argsbarg:program} in consumer notes", () => {
|
|
|
105
110
|
expect(md).toContain("Invoke `myapp run`.");
|
|
106
111
|
});
|
|
107
112
|
|
|
113
|
+
/** Tests that generateApiGuide and cliSchemaExport include leaf outputSchema. */
|
|
108
114
|
test("generateApiGuide and cliSchemaExport include leaf outputSchema", () => {
|
|
109
115
|
const fixture: CliProgram = {
|
|
110
116
|
key: "myapp",
|
package/src/docs/docs.test.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Tests for docs/docs module behavior.
|
|
3
|
+
*/
|
|
4
|
+
|
|
1
5
|
import { afterEach, beforeEach, expect, test } from "bun:test";
|
|
2
6
|
import { mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
3
7
|
import { tmpdir } from "node:os";
|
|
@@ -49,6 +53,7 @@ function docsFixture(mcp = true): CliProgram {
|
|
|
49
53
|
};
|
|
50
54
|
}
|
|
51
55
|
|
|
56
|
+
/** Docs reserved when enabled. */
|
|
52
57
|
test("docs reserved when enabled", () => {
|
|
53
58
|
const root: CliProgram = {
|
|
54
59
|
...docsFixture(),
|
|
@@ -63,6 +68,7 @@ test("docs reserved when enabled", () => {
|
|
|
63
68
|
expect(() => cliValidateProgram(root)).toThrow(/Reserved command name: docs/);
|
|
64
69
|
});
|
|
65
70
|
|
|
71
|
+
/** Docs rejects reserved topic keys. */
|
|
66
72
|
test("docs rejects reserved topic keys", () => {
|
|
67
73
|
const root = docsFixture();
|
|
68
74
|
const docs = root.docs;
|
|
@@ -176,6 +182,7 @@ test("docs skill prints Cursor SKILL.md", async () => {
|
|
|
176
182
|
expect(result.stdout).not.toContain("mcp.json");
|
|
177
183
|
});
|
|
178
184
|
|
|
185
|
+
/** Docs skill help recommends configure. */
|
|
179
186
|
test("docs skill help recommends configure", async () => {
|
|
180
187
|
const presentation = cliPresentationRoot(docsFixture());
|
|
181
188
|
const docsNode = presentation.commands.find((c) => c.key === "docs");
|