argsbarg 4.1.0 → 5.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/CHANGELOG.md +74 -1
- package/README.md +91 -85
- package/docs/README.md +8 -8
- package/docs/ai-skills.md +9 -9
- package/docs/bundled-docs.md +5 -5
- package/docs/cli-program.md +13 -11
- package/docs/config-schema.md +36 -9
- package/docs/configure.md +177 -0
- package/docs/developing.md +7 -7
- package/docs/distribution-homebrew.md +104 -0
- package/docs/mcp.md +11 -12
- package/docs/output-schema.md +1 -1
- package/examples/full-example/Formula/.gitkeep +0 -0
- package/examples/full-example/README.md +98 -0
- package/examples/full-example/biome.json +22 -0
- package/examples/{consumer-app → full-example}/bun.lock +2 -0
- package/examples/full-example/justfile +134 -0
- package/examples/{consumer-app → full-example}/package.json +10 -3
- package/examples/{consumer-app → full-example}/schemas/generated/app-config.json +1 -1
- package/examples/{consumer-app → full-example}/schemas/generated/status.json +1 -1
- package/examples/full-example/scripts/create-identity.ts +11 -0
- package/examples/full-example/scripts/formula-shared.ts +73 -0
- package/examples/full-example/scripts/gen-dev-formula.ts +26 -0
- package/examples/full-example/scripts/print-identity.ts +27 -0
- package/examples/full-example/src/commands/echo/command.ts +21 -0
- package/examples/full-example/src/commands/status/command.test.ts +10 -0
- package/examples/full-example/src/commands/status/command.ts +36 -0
- package/examples/{consumer-app → full-example}/src/commands/status/types.ts +1 -1
- package/examples/full-example/src/index.ts +10 -0
- package/examples/full-example/src/program.ts +57 -0
- package/examples/{consumer-app → full-example}/src/types.ts +1 -1
- package/examples/nested.ts +1 -3
- package/index.d.ts +49 -81
- package/package.json +2 -2
- package/src/builtins/builtins.test.ts +84 -64
- package/src/builtins/completion-group.ts +17 -17
- package/src/builtins/configure-copy.ts +86 -0
- package/src/builtins/configure.ts +70 -0
- package/src/builtins/dispatch.ts +13 -9
- package/src/builtins/index.ts +1 -1
- package/src/builtins/mcp.ts +2 -2
- package/src/builtins/registry.ts +6 -4
- package/src/capabilities.ts +22 -15
- package/src/cli-tool/cli-smoke.test.ts +29 -0
- package/src/cli-tool/create.test.ts +141 -0
- package/src/cli-tool/create.ts +402 -0
- package/{examples/consumer-app/capabilities.test.ts → src/cli-tool/full-example-capabilities.test.ts} +16 -15
- package/src/cli-tool/main.ts +8 -0
- package/src/cli-tool/post-create.ts +111 -0
- package/src/cli-tool/program.ts +97 -0
- package/src/cli-tool/prompt.ts +28 -0
- package/src/cli-tool/run-create.ts +138 -0
- package/src/cli.ts +0 -2
- package/src/config/bootstrap.ts +27 -18
- package/src/config/file.test.ts +1 -1
- package/src/config/resolve.test.ts +167 -0
- package/src/config/resolve.ts +52 -8
- package/src/configure/configure.test.ts +148 -0
- package/src/configure/index.ts +284 -0
- package/src/configure/prompt.ts +40 -0
- package/src/docs/api-guide.test.ts +4 -5
- package/src/docs/builtin.ts +3 -5
- package/src/docs/docs.test.ts +6 -5
- package/src/docs/mcp-guide.ts +11 -12
- package/src/index.ts +5 -12
- package/src/install/binary-placement.test.ts +101 -0
- package/src/install/binary-placement.ts +47 -0
- package/src/install/install-validate.test.ts +5 -5
- package/src/install/normalize-uninstall.ts +11 -0
- package/src/install/normalize.ts +4 -19
- package/src/install/opts.ts +17 -0
- package/src/install/paths.ts +0 -22
- package/src/install/plan.ts +14 -6
- package/src/install/shell.ts +0 -14
- package/src/install/status.test.ts +6 -6
- package/src/install/status.ts +0 -6
- package/src/install/target-effective.ts +8 -10
- package/src/install/target-scope.ts +26 -36
- package/src/install/target-types.ts +0 -16
- package/src/install/targets/app.ts +19 -28
- package/src/install/targets/configure.ts +6 -2
- package/src/install/targets/index.ts +0 -3
- package/src/install/targets.test.ts +26 -44
- package/src/invoke.test.ts +1 -1
- package/src/mcp/env.test.ts +92 -0
- package/src/mcp/env.ts +15 -14
- package/src/mcp/tools.ts +1 -1
- package/src/mcp.integration.test.ts +4 -4
- package/src/parse.test.ts +13 -14
- package/src/prompt.ts +10 -0
- package/src/schema.ts +1 -1
- package/src/skill/hint.ts +2 -2
- package/src/types.ts +48 -22
- package/src/validate.ts +22 -28
- package/docs/install.md +0 -290
- package/docs/templates/cursor/rules/cli-program.mdc +0 -31
- package/examples/config-app/main.ts +0 -20
- package/examples/config-app/program.ts +0 -78
- package/examples/config-app/schema.ts +0 -37
- package/examples/config-app/types.ts +0 -19
- package/examples/consumer-app/README.md +0 -56
- package/examples/consumer-app/src/main.ts +0 -15
- package/examples/consumer-app/src/program.ts +0 -108
- package/src/builtins/install.ts +0 -136
- package/src/install/app.ts +0 -94
- package/src/install/bootstrap.ts +0 -22
- package/src/install/completions.ts +0 -56
- package/src/install/index.ts +0 -415
- package/src/install/install.test.ts +0 -333
- package/src/install/targets/completions.ts +0 -133
- package/src/install/update.test.ts +0 -123
- package/src/install/update.ts +0 -54
- /package/examples/{consumer-app → full-example}/schemas/configSchemas.ts +0 -0
- /package/examples/{consumer-app → full-example}/schemas/outputSchemas.ts +0 -0
- /package/examples/{consumer-app → full-example}/scripts/schemagen/discover-schema-roots.test.ts +0 -0
- /package/examples/{consumer-app → full-example}/scripts/schemagen/discover-schema-roots.ts +0 -0
- /package/examples/{consumer-app → full-example}/scripts/schemagen/naming.ts +0 -0
- /package/examples/{consumer-app → full-example}/scripts/schemagen.ts +0 -0
- /package/examples/{consumer-app → full-example}/tsconfig.json +0 -0
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Inline draft-07 JSON Schema for AppConfig.
|
|
3
|
-
Production apps commit generated JSON and import via configSchemas.ts — see docs/config-schema.md.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { AppConfig } from "./types.ts";
|
|
7
|
-
|
|
8
|
-
/** JSON Schema root for program.appConfig.jsonSchema (hand-written stand-in for schemagen). */
|
|
9
|
-
export const APP_CONFIG_JSON_SCHEMA = {
|
|
10
|
-
$schema: "http://json-schema.org/draft-07/schema#",
|
|
11
|
-
type: "object",
|
|
12
|
-
additionalProperties: false,
|
|
13
|
-
required: ["apiToken", "maxRetries"],
|
|
14
|
-
properties: {
|
|
15
|
-
apiToken: { type: "string", minLength: 1 },
|
|
16
|
-
defaultRegion: { type: "string", default: "us-east-1" },
|
|
17
|
-
maxRetries: { type: "integer", minimum: 0, maximum: 10, default: 3 },
|
|
18
|
-
prefs: {
|
|
19
|
-
type: "object",
|
|
20
|
-
additionalProperties: false,
|
|
21
|
-
required: ["ttl"],
|
|
22
|
-
properties: {
|
|
23
|
-
ttl: { type: "integer", minimum: 1 },
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
} as const satisfies Record<string, unknown>;
|
|
28
|
-
|
|
29
|
-
/** Compile-time check that schema keys align with AppConfig (documentation only). */
|
|
30
|
-
type _SchemaKeys = keyof typeof APP_CONFIG_JSON_SCHEMA.properties;
|
|
31
|
-
type _ConfigKeys = keyof AppConfig;
|
|
32
|
-
const _assertKeysAlign: _SchemaKeys extends _ConfigKeys
|
|
33
|
-
? _ConfigKeys extends _SchemaKeys
|
|
34
|
-
? true
|
|
35
|
-
: never
|
|
36
|
-
: never = true;
|
|
37
|
-
void _assertKeysAlign;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Config schema
|
|
3
|
-
*
|
|
4
|
-
* Application settings persisted in a flat JSON file (`program.appConfig`).
|
|
5
|
-
* In a production app, generate `APP_CONFIG_JSON_SCHEMA` from this interface
|
|
6
|
-
* with ts-json-schema-generator — see docs/config-schema.md.
|
|
7
|
-
*/
|
|
8
|
-
export interface AppConfig {
|
|
9
|
-
/** API token from the provider dashboard. */
|
|
10
|
-
apiToken: string;
|
|
11
|
-
/** AWS region (default us-east-1). */
|
|
12
|
-
defaultRegion?: string;
|
|
13
|
-
/** HTTP retry count (default 3). */
|
|
14
|
-
maxRetries: number;
|
|
15
|
-
/** Local preferences (file-only; not mapped to process.env). */
|
|
16
|
-
prefs?: {
|
|
17
|
-
ttl: number;
|
|
18
|
-
};
|
|
19
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
# consumer-app
|
|
2
|
-
|
|
3
|
-
**Kitchen-sink argsbarg reference** — copy this layout when bootstrapping a production CLI. For a minimal `program.appConfig` intro, see [`../config-app/`](../config-app/).
|
|
4
|
-
|
|
5
|
-
## What this demonstrates
|
|
6
|
-
|
|
7
|
-
| Area | Files / wiring |
|
|
8
|
-
| --- | --- |
|
|
9
|
-
| All builtins | `completion`, `version`, `install` (+ `--update`), `docs`, `mcp`, `config get`/`set` |
|
|
10
|
-
| `program.appConfig` | `src/types.ts` (`AppConfig`) → `schemas/configSchemas.ts` |
|
|
11
|
-
| `outputSchema` | `src/commands/status/types.ts` (`StatusJsonOutput`) → `schemas/outputSchemas.ts` |
|
|
12
|
-
| Schemagen | `scripts/schemagen.ts` + `scripts/schemagen/discover-schema-roots.ts` |
|
|
13
|
-
| Handler access | `ctx.appConfig` in `src/program.ts` |
|
|
14
|
-
| MCP doc topics | `docs.topics` auto-exposed as `<key>://docs/<topic>` resources when docs + MCP enabled |
|
|
15
|
-
| Package import | `from "argsbarg"` (not relative to argsbarg `src/`) |
|
|
16
|
-
|
|
17
|
-
## Quick start (in this repo)
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
cd examples/consumer-app
|
|
21
|
-
bun install
|
|
22
|
-
bun run schemagen # after changing src/**/types.ts
|
|
23
|
-
CONSUMER_APP_API_TOKEN=dev bun run start status --json
|
|
24
|
-
CONSUMER_APP_API_TOKEN=dev bun run start config get apiToken --json
|
|
25
|
-
CONSUMER_APP_API_TOKEN=dev bun run start docs readme
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Copy into a new app
|
|
29
|
-
|
|
30
|
-
1. Copy this directory into your repo (e.g. `apps/my-cli/`).
|
|
31
|
-
2. Set `"argsbarg": "^<version>"` in `package.json` (replace `file:../..`).
|
|
32
|
-
3. Run `bun run schemagen` and commit `schemas/generated/` + bridge `.ts` files.
|
|
33
|
-
4. Copy [`node_modules/argsbarg/docs/templates/cursor/rules/cli-program.mdc`](../../docs/templates/cursor/rules/cli-program.mdc) to `.cursor/rules/`.
|
|
34
|
-
|
|
35
|
-
## Schemagen markers
|
|
36
|
-
|
|
37
|
-
| Marker in interface JSDoc | Artifact |
|
|
38
|
-
| --- | --- |
|
|
39
|
-
| `Config schema` | `schemas/configSchemas.ts` + `schemas/generated/*-config.json` |
|
|
40
|
-
| `JSON payload` | `schemas/outputSchemas.ts` + `schemas/generated/*.json` |
|
|
41
|
-
|
|
42
|
-
Discovery walks `src/**/types.ts` only.
|
|
43
|
-
|
|
44
|
-
## Environment
|
|
45
|
-
|
|
46
|
-
| Variable | Purpose |
|
|
47
|
-
| --- | --- |
|
|
48
|
-
| `CONSUMER_APP_API_TOKEN` | Overrides `apiToken` via `program.appConfig` env mapping |
|
|
49
|
-
|
|
50
|
-
## Maintainers (argsbarg repo)
|
|
51
|
-
|
|
52
|
-
When adding or changing builtins, update this example and run:
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
just consumer-app-schemagen
|
|
56
|
-
```
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
/*
|
|
3
|
-
Kitchen-sink argsbarg consumer reference.
|
|
4
|
-
|
|
5
|
-
cd examples/consumer-app && bun install && bun run schemagen
|
|
6
|
-
CONSUMER_APP_API_TOKEN=dev bun run start status --json
|
|
7
|
-
CONSUMER_APP_API_TOKEN=dev bun run start config get
|
|
8
|
-
CONSUMER_APP_API_TOKEN=dev bun run start docs readme
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { Cli } from "argsbarg";
|
|
12
|
-
import { program } from "./program.ts";
|
|
13
|
-
|
|
14
|
-
const cli = new Cli(program);
|
|
15
|
-
await cli.run();
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Kitchen-sink CliProgram — every argsbarg builtin enabled.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
type CliAppConfig,
|
|
7
|
-
type CliAppConfigEntry,
|
|
8
|
-
CliOptionKind,
|
|
9
|
-
type CliProgram,
|
|
10
|
-
} from "argsbarg";
|
|
11
|
-
import readmeText from "../README.md" with { type: "text" };
|
|
12
|
-
import { APP_CONFIG_JSON_SCHEMA } from "../schemas/configSchemas.ts";
|
|
13
|
-
import { STATUS_JSON_OUTPUT_SCHEMA } from "../schemas/outputSchemas.ts";
|
|
14
|
-
import type { StatusJsonOutput } from "./commands/status/types.ts";
|
|
15
|
-
|
|
16
|
-
const configSchema = {
|
|
17
|
-
apiToken: {
|
|
18
|
-
description: "Create at https://example.com/settings/tokens",
|
|
19
|
-
env: "CONSUMER_APP_API_TOKEN",
|
|
20
|
-
sensitive: true,
|
|
21
|
-
},
|
|
22
|
-
defaultRegion: {
|
|
23
|
-
description: "AWS region for API calls.",
|
|
24
|
-
required: false,
|
|
25
|
-
},
|
|
26
|
-
maxRetries: {
|
|
27
|
-
description: "HTTP retry count (0–10).",
|
|
28
|
-
},
|
|
29
|
-
prefs: {
|
|
30
|
-
description: "Local cache preferences (not exported to env).",
|
|
31
|
-
required: false,
|
|
32
|
-
},
|
|
33
|
-
} as const satisfies Record<string, CliAppConfigEntry>;
|
|
34
|
-
|
|
35
|
-
export const program = {
|
|
36
|
-
key: "consumer-app",
|
|
37
|
-
version: "1.0.0",
|
|
38
|
-
description: "Argsbarg kitchen-sink reference — all builtins, schemagen, ctx.appConfig.",
|
|
39
|
-
appConfig: {
|
|
40
|
-
jsonSchema: APP_CONFIG_JSON_SCHEMA,
|
|
41
|
-
entries: configSchema,
|
|
42
|
-
} satisfies CliAppConfig,
|
|
43
|
-
docs: {
|
|
44
|
-
enabled: true,
|
|
45
|
-
topics: {
|
|
46
|
-
readme: {
|
|
47
|
-
text: readmeText,
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
},
|
|
51
|
-
mcpServer: {
|
|
52
|
-
enabled: true,
|
|
53
|
-
mcpd: true,
|
|
54
|
-
claudePlugin: true,
|
|
55
|
-
},
|
|
56
|
-
install: {
|
|
57
|
-
// Defaults: app + completions + configure; agentIntegration picks skill vs MCP for --all.
|
|
58
|
-
updateGetLatest: async () => ({
|
|
59
|
-
path: process.execPath,
|
|
60
|
-
version: "1.0.0",
|
|
61
|
-
}),
|
|
62
|
-
},
|
|
63
|
-
commands: [
|
|
64
|
-
{
|
|
65
|
-
key: "status",
|
|
66
|
-
description: "Show resolved config and app version.",
|
|
67
|
-
options: [
|
|
68
|
-
{
|
|
69
|
-
name: "json",
|
|
70
|
-
description: "Emit JSON.",
|
|
71
|
-
kind: CliOptionKind.Presence,
|
|
72
|
-
},
|
|
73
|
-
],
|
|
74
|
-
outputSchema: STATUS_JSON_OUTPUT_SCHEMA,
|
|
75
|
-
handler: (ctx) => {
|
|
76
|
-
const out: StatusJsonOutput = {
|
|
77
|
-
defaultRegion: ctx.appConfig.get("defaultRegion") as string | undefined,
|
|
78
|
-
maxRetries: ctx.appConfig.get("maxRetries") as number | undefined,
|
|
79
|
-
apiTokenSet: ctx.appConfig.get("apiToken") !== undefined,
|
|
80
|
-
version: ctx.program.version,
|
|
81
|
-
};
|
|
82
|
-
if (ctx.hasFlag("json")) {
|
|
83
|
-
console.log(JSON.stringify(out, null, 2));
|
|
84
|
-
} else {
|
|
85
|
-
console.log(`version=${out.version}`);
|
|
86
|
-
console.log(`region=${out.defaultRegion ?? "(not set)"}`);
|
|
87
|
-
console.log(`maxRetries=${out.maxRetries ?? "(not set)"}`);
|
|
88
|
-
console.log(`apiToken=${out.apiTokenSet ? "set" : "missing"}`);
|
|
89
|
-
}
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
key: "echo",
|
|
94
|
-
description: "Echo a message (MCP-friendly leaf).",
|
|
95
|
-
options: [
|
|
96
|
-
{
|
|
97
|
-
name: "message",
|
|
98
|
-
description: "Text to print.",
|
|
99
|
-
kind: CliOptionKind.String,
|
|
100
|
-
required: true,
|
|
101
|
-
},
|
|
102
|
-
],
|
|
103
|
-
handler: (ctx) => {
|
|
104
|
-
console.log(ctx.stringOpt("message") ?? "");
|
|
105
|
-
},
|
|
106
|
-
},
|
|
107
|
-
],
|
|
108
|
-
} satisfies CliProgram;
|
package/src/builtins/install.ts
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import { resolveCapabilities } from "../capabilities.ts";
|
|
2
|
-
import { type CliLeaf, type CliOption, CliOptionKind, type CliProgram } from "../types.ts";
|
|
3
|
-
|
|
4
|
-
/** Install command options (dynamic: `--mcp` only when MCP is enabled). */
|
|
5
|
-
export function installBuiltinOptions(root: CliProgram): CliOption[] {
|
|
6
|
-
const opts: CliOption[] = [
|
|
7
|
-
{
|
|
8
|
-
name: "all",
|
|
9
|
-
description:
|
|
10
|
-
"Install the default set (app, shell completions, and configuration when supported).",
|
|
11
|
-
kind: CliOptionKind.Presence,
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
name: "app",
|
|
15
|
-
description: "Copy this app to your install directory (default ~/.local/bin).",
|
|
16
|
-
kind: CliOptionKind.Presence,
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
name: "completions",
|
|
20
|
-
description:
|
|
21
|
-
"Install bash, zsh, and fish tab-completion scripts (each skipped silently if that shell is not on PATH).",
|
|
22
|
-
kind: CliOptionKind.Presence,
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
name: "skill",
|
|
26
|
-
description:
|
|
27
|
-
"Install agent skills for Cursor, Claude, and other supported AI tools on this machine.",
|
|
28
|
-
kind: CliOptionKind.Presence,
|
|
29
|
-
},
|
|
30
|
-
];
|
|
31
|
-
|
|
32
|
-
if (resolveCapabilities(root).mcp) {
|
|
33
|
-
opts.push({
|
|
34
|
-
name: "mcp",
|
|
35
|
-
description:
|
|
36
|
-
"Add MCP server configuration for Cursor, Claude Code, and other supported agents.",
|
|
37
|
-
kind: CliOptionKind.Presence,
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (root.appConfig) {
|
|
42
|
-
opts.push({
|
|
43
|
-
name: "configure",
|
|
44
|
-
description:
|
|
45
|
-
"Run the configuration wizard (install), or remove the config file (--uninstall).",
|
|
46
|
-
kind: CliOptionKind.Presence,
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
opts.push(
|
|
51
|
-
{
|
|
52
|
-
name: "status",
|
|
53
|
-
description: "Print what is currently installed (read-only).",
|
|
54
|
-
kind: CliOptionKind.Presence,
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
name: "reinstall",
|
|
58
|
-
description: "Refresh everything already installed for this app.",
|
|
59
|
-
kind: CliOptionKind.Presence,
|
|
60
|
-
},
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
if (resolveCapabilities(root).update) {
|
|
64
|
-
opts.push({
|
|
65
|
-
name: "update",
|
|
66
|
-
description: "Download the latest release and refresh installed files.",
|
|
67
|
-
kind: CliOptionKind.Presence,
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
opts.push(
|
|
72
|
-
{
|
|
73
|
-
name: "uninstall",
|
|
74
|
-
description:
|
|
75
|
-
"Remove installed files (--all removes everything; use individual flags to remove one category).",
|
|
76
|
-
kind: CliOptionKind.Presence,
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
name: "from",
|
|
80
|
-
description: "App executable to copy (default: running executable). Used with --reinstall.",
|
|
81
|
-
kind: CliOptionKind.String,
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
name: "yes",
|
|
85
|
-
description: "Skip the confirmation prompt.",
|
|
86
|
-
kind: CliOptionKind.Presence,
|
|
87
|
-
shortName: "y",
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
name: "dry",
|
|
91
|
-
description: "Show what would change without writing files.",
|
|
92
|
-
kind: CliOptionKind.Presence,
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
name: "json",
|
|
96
|
-
description: "Print changed paths (install/update/uninstall) or status JSON on stdout.",
|
|
97
|
-
kind: CliOptionKind.Presence,
|
|
98
|
-
},
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
return opts;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/** Builds the `install` built-in command. */
|
|
105
|
-
export function cliBuiltinInstallCommand(root: CliProgram): CliLeaf {
|
|
106
|
-
const app = root.key;
|
|
107
|
-
const notesLines = [
|
|
108
|
-
"First-time setup:",
|
|
109
|
-
` ${app} install --yes`,
|
|
110
|
-
"",
|
|
111
|
-
"Refresh after upgrading:",
|
|
112
|
-
` ${app} install --reinstall`,
|
|
113
|
-
];
|
|
114
|
-
if (resolveCapabilities(root).update) {
|
|
115
|
-
notesLines.push("", "Upgrade to latest release:", ` ${app} install --update`);
|
|
116
|
-
}
|
|
117
|
-
notesLines.push(
|
|
118
|
-
"",
|
|
119
|
-
"See what is installed:",
|
|
120
|
-
` ${app} install --status`,
|
|
121
|
-
"",
|
|
122
|
-
"Remove everything installed with --all:",
|
|
123
|
-
` ${app} install --uninstall --all --yes`,
|
|
124
|
-
"",
|
|
125
|
-
"Use --dry to preview changes without writing files.",
|
|
126
|
-
"Use --json for machine-readable output.",
|
|
127
|
-
);
|
|
128
|
-
return {
|
|
129
|
-
key: "install",
|
|
130
|
-
description:
|
|
131
|
-
"Install this app, shell completions, agent skills, and MCP config on your machine.",
|
|
132
|
-
options: installBuiltinOptions(root),
|
|
133
|
-
notes: notesLines.join("\n"),
|
|
134
|
-
handler: () => {},
|
|
135
|
-
};
|
|
136
|
-
}
|
package/src/install/app.ts
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
copyFileSync,
|
|
3
|
-
existsSync,
|
|
4
|
-
mkdirSync,
|
|
5
|
-
readFileSync,
|
|
6
|
-
unlinkSync,
|
|
7
|
-
writeFileSync,
|
|
8
|
-
} from "node:fs";
|
|
9
|
-
import { dirname, join } from "node:path";
|
|
10
|
-
import type { CliProgram } from "../types.ts";
|
|
11
|
-
import type { InstallPaths } from "./paths.ts";
|
|
12
|
-
import {
|
|
13
|
-
buildPathRcBlock,
|
|
14
|
-
buildZshFpathRcBlock,
|
|
15
|
-
detectShells,
|
|
16
|
-
hasRcBlock,
|
|
17
|
-
removeRcBlock,
|
|
18
|
-
} from "./shell.ts";
|
|
19
|
-
|
|
20
|
-
export interface AppInstallResult {
|
|
21
|
-
changedFiles: string[];
|
|
22
|
-
patchedBashRc: boolean;
|
|
23
|
-
patchedZshRc: boolean;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/** Copies the app executable to the install path and patches rc files when shells are detected. */
|
|
27
|
-
export function installApp(
|
|
28
|
-
root: CliProgram,
|
|
29
|
-
paths: InstallPaths,
|
|
30
|
-
dry: boolean,
|
|
31
|
-
sourcePath: string = process.execPath,
|
|
32
|
-
): AppInstallResult {
|
|
33
|
-
const changed: string[] = [];
|
|
34
|
-
const shells = detectShells();
|
|
35
|
-
let patchedBashRc = false;
|
|
36
|
-
let patchedZshRc = false;
|
|
37
|
-
|
|
38
|
-
if (!dry) {
|
|
39
|
-
mkdirSync(paths.appDir, { recursive: true });
|
|
40
|
-
copyFileSync(sourcePath, paths.appPath);
|
|
41
|
-
}
|
|
42
|
-
changed.push(paths.appPath);
|
|
43
|
-
|
|
44
|
-
if (shells.bash && existsSync(dirname(paths.bashRc))) {
|
|
45
|
-
const block = buildPathRcBlock(root.key, paths.appDir);
|
|
46
|
-
let content = existsSync(paths.bashRc) ? readFileSync(paths.bashRc, "utf8") : "";
|
|
47
|
-
if (!hasRcBlock(content, root.key, "path")) {
|
|
48
|
-
if (!content.endsWith("\n") && content.length > 0) content += "\n";
|
|
49
|
-
content += `${block}\n`;
|
|
50
|
-
if (!dry) writeFileSync(paths.bashRc, content, "utf8");
|
|
51
|
-
changed.push(paths.bashRc);
|
|
52
|
-
patchedBashRc = true;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (shells.zsh) {
|
|
57
|
-
const completionsDir = join(dirname(paths.zshCompletion));
|
|
58
|
-
const block = buildZshFpathRcBlock(root.key, completionsDir);
|
|
59
|
-
let content = existsSync(paths.zshRc) ? readFileSync(paths.zshRc, "utf8") : "";
|
|
60
|
-
if (!hasRcBlock(content, root.key, "fpath")) {
|
|
61
|
-
if (!content.endsWith("\n") && content.length > 0) content += "\n";
|
|
62
|
-
content += `${block}\n`;
|
|
63
|
-
if (!dry) writeFileSync(paths.zshRc, content, "utf8");
|
|
64
|
-
changed.push(paths.zshRc);
|
|
65
|
-
patchedZshRc = true;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return { changedFiles: changed, patchedBashRc, patchedZshRc };
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/** Removes the installed app and rc marker blocks. */
|
|
73
|
-
export function uninstallApp(root: CliProgram, paths: InstallPaths, dry: boolean): string[] {
|
|
74
|
-
const changed: string[] = [];
|
|
75
|
-
if (existsSync(paths.appPath)) {
|
|
76
|
-
if (!dry) unlinkSync(paths.appPath);
|
|
77
|
-
changed.push(paths.appPath);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
for (const [rcPath, tag] of [
|
|
81
|
-
[paths.bashRc, "path"],
|
|
82
|
-
[paths.zshRc, "fpath"],
|
|
83
|
-
] as const) {
|
|
84
|
-
if (!existsSync(rcPath)) continue;
|
|
85
|
-
const content = readFileSync(rcPath, "utf8");
|
|
86
|
-
if (hasRcBlock(content, root.key, tag)) {
|
|
87
|
-
const next = removeRcBlock(content, root.key, tag);
|
|
88
|
-
if (!dry) writeFileSync(rcPath, next, "utf8");
|
|
89
|
-
changed.push(rcPath);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return changed;
|
|
94
|
-
}
|
package/src/install/bootstrap.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
|
-
import type { CliProgram } from "../types.ts";
|
|
3
|
-
import { resolveAppDir } from "./paths.ts";
|
|
4
|
-
|
|
5
|
-
/** Rewrites empty argv to `install` when the app is not yet installed (TTY only). */
|
|
6
|
-
export function maybeBootstrapInstallArgv(argv: string[], program: CliProgram): string[] {
|
|
7
|
-
if (argv.length !== 0) {
|
|
8
|
-
return argv;
|
|
9
|
-
}
|
|
10
|
-
if (program.install?.enabled === false) {
|
|
11
|
-
return argv;
|
|
12
|
-
}
|
|
13
|
-
if (!process.stdin.isTTY) {
|
|
14
|
-
return argv;
|
|
15
|
-
}
|
|
16
|
-
const appDir = resolveAppDir();
|
|
17
|
-
const appPath = `${appDir}/${program.key}`;
|
|
18
|
-
if (existsSync(appPath)) {
|
|
19
|
-
return argv;
|
|
20
|
-
}
|
|
21
|
-
return ["install"];
|
|
22
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, unlinkSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { dirname } from "node:path";
|
|
3
|
-
import {
|
|
4
|
-
completionBashScript,
|
|
5
|
-
completionFishScript,
|
|
6
|
-
completionZshScript,
|
|
7
|
-
} from "../builtins/index.ts";
|
|
8
|
-
import { cliPresentationRoot } from "../builtins/presentation.ts";
|
|
9
|
-
import type { CliProgram } from "../types.ts";
|
|
10
|
-
import type { InstallPaths } from "./paths.ts";
|
|
11
|
-
import { detectShells } from "./shell.ts";
|
|
12
|
-
|
|
13
|
-
/** Writes shell completion scripts for detected shells. */
|
|
14
|
-
export function installCompletions(root: CliProgram, paths: InstallPaths, dry: boolean): string[] {
|
|
15
|
-
const changed: string[] = [];
|
|
16
|
-
const shells = detectShells();
|
|
17
|
-
const schema = cliPresentationRoot(root);
|
|
18
|
-
|
|
19
|
-
if (shells.bash) {
|
|
20
|
-
if (!dry) {
|
|
21
|
-
mkdirSync(dirname(paths.bashCompletion), { recursive: true });
|
|
22
|
-
writeFileSync(paths.bashCompletion, completionBashScript(schema), "utf8");
|
|
23
|
-
}
|
|
24
|
-
changed.push(paths.bashCompletion);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
if (shells.zsh) {
|
|
28
|
-
if (!dry) {
|
|
29
|
-
mkdirSync(dirname(paths.zshCompletion), { recursive: true });
|
|
30
|
-
writeFileSync(paths.zshCompletion, completionZshScript(schema), "utf8");
|
|
31
|
-
}
|
|
32
|
-
changed.push(paths.zshCompletion);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (shells.fish) {
|
|
36
|
-
if (!dry) {
|
|
37
|
-
mkdirSync(dirname(paths.fishCompletion), { recursive: true });
|
|
38
|
-
writeFileSync(paths.fishCompletion, completionFishScript(schema), "utf8");
|
|
39
|
-
}
|
|
40
|
-
changed.push(paths.fishCompletion);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return changed;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/** Removes shell completion files. */
|
|
47
|
-
export function uninstallCompletions(paths: InstallPaths, dry: boolean): string[] {
|
|
48
|
-
const changed: string[] = [];
|
|
49
|
-
for (const p of [paths.bashCompletion, paths.zshCompletion, paths.fishCompletion]) {
|
|
50
|
-
if (existsSync(p)) {
|
|
51
|
-
if (!dry) unlinkSync(p);
|
|
52
|
-
changed.push(p);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return changed;
|
|
56
|
-
}
|