@bpmnkit/cli 0.0.9

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/README.md ADDED
@@ -0,0 +1,113 @@
1
+ # casen
2
+
3
+ CLI for the [Camunda 8 Orchestration Cluster REST API (v2)](https://docs.camunda.io/docs/apis-tools/orchestration-cluster-api-rest/orchestration-cluster-api-rest-overview/).
4
+
5
+ Commands are auto-generated from the official OpenAPI specs — every resource and operation stays in sync automatically. See [DOCUMENTATION.md](./DOCUMENTATION.md) for the full command reference.
6
+
7
+ ## Features
8
+
9
+ - **All API resources** — process instances, jobs, user tasks, decisions, users, groups, tenants, and more
10
+ - **Multiple profiles** — store named connection configs and switch between them instantly
11
+ - **Three output formats** — human-readable table (default), `--output json`, `--output yaml`
12
+ - **Shell completions** — bash, zsh, and fish
13
+ - **Zero dependencies** — no runtime requirements beyond Node.js
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ # From the monorepo root
19
+ pnpm build
20
+
21
+ # Then link globally (optional)
22
+ npm link ./apps/cli
23
+ ```
24
+
25
+ ## Quick start
26
+
27
+ **1. Create a profile**
28
+
29
+ ```bash
30
+ # Bearer token (local / self-managed)
31
+ casen profile create local \
32
+ --base-url http://localhost:8080/v2 \
33
+ --auth-type bearer \
34
+ --token my-token
35
+
36
+ # OAuth2 (Camunda SaaS)
37
+ casen profile create prod \
38
+ --base-url https://<cluster-id>.camunda.io/v2 \
39
+ --auth-type oauth2 \
40
+ --client-id <client-id> \
41
+ --client-secret <client-secret> \
42
+ --token-url https://login.cloud.camunda.io/oauth/token
43
+ ```
44
+
45
+ The first profile created becomes the active profile automatically.
46
+
47
+ **Import from a Camunda Cloud credentials file**
48
+
49
+ When you create a client in Camunda Cloud, you can download a credentials file containing `export KEY='VALUE'` declarations. Import it directly:
50
+
51
+ ```bash
52
+ casen profile import prod ./camunda-credentials.sh
53
+
54
+ # or pipe via stdin
55
+ cat camunda-credentials.sh | casen profile import prod -
56
+ ```
57
+
58
+ The file must contain at least:
59
+
60
+ | Variable | Fallback |
61
+ |----------|----------|
62
+ | `ZEEBE_REST_ADDRESS` | _(required)_ |
63
+ | `CAMUNDA_CLIENT_ID` | `ZEEBE_CLIENT_ID` |
64
+ | `CAMUNDA_CLIENT_SECRET` | `ZEEBE_CLIENT_SECRET` |
65
+ | `CAMUNDA_OAUTH_URL` | `ZEEBE_AUTHORIZATION_SERVER_URL` |
66
+
67
+ **2. Run a command**
68
+
69
+ ```bash
70
+ casen process-instance list --filter '{"state":"ACTIVE"}'
71
+ casen user-task list --filter '{"assignee":"alice"}'
72
+ casen process-instance create --data '{"processDefinitionId":"order-process"}'
73
+ ```
74
+
75
+ ## Profiles
76
+
77
+ Profiles store connection configuration in the OS config directory:
78
+
79
+ | Platform | Location |
80
+ |----------|----------|
81
+ | Linux | `$XDG_CONFIG_HOME/casen/config.json` or `~/.config/casen/config.json` |
82
+ | macOS | `~/Library/Application Support/casen/config.json` |
83
+ | Windows | `%APPDATA%\casen\config.json` |
84
+
85
+ Use `--profile <name>` on any command to temporarily override the active profile.
86
+
87
+ ## Output formats
88
+
89
+ Results can be printed as a table (default), JSON, or YAML via `--output json` / `--output yaml`. Colors and table formatting are automatically disabled when stdout is not a TTY or when `NO_COLOR` is set.
90
+
91
+ ## Shell completions
92
+
93
+ ```bash
94
+ # zsh
95
+ mkdir -p ~/.zfunc && casen completion zsh > ~/.zfunc/_casen
96
+ # add to ~/.zshrc: fpath=(~/.zfunc $fpath) && autoload -Uz compinit && compinit
97
+
98
+ # bash
99
+ casen completion bash >> ~/.bash_completion
100
+
101
+ # fish
102
+ casen completion fish > ~/.config/fish/completions/casen.fish
103
+ ```
104
+
105
+ ## Help
106
+
107
+ ```bash
108
+ casen --help # Global help
109
+ casen <resource> --help # Resource-level help
110
+ casen <resource> <command> --help # Command-level help
111
+ ```
112
+
113
+ For all available resources and commands see [DOCUMENTATION.md](./DOCUMENTATION.md).
package/dist/args.js ADDED
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Parse argv tokens into positional arguments and flags.
3
+ *
4
+ * Supports:
5
+ * --flag value string / number flag
6
+ * --flag=value alternative syntax
7
+ * --flag boolean flag (true)
8
+ * --no-flag boolean flag negation (false)
9
+ * -f value short flag
10
+ * -f=value short flag with equals
11
+ * -- stop flag parsing; everything after is positional
12
+ */
13
+ export function parseArgs(argv) {
14
+ const positional = [];
15
+ const flags = {};
16
+ let i = 0;
17
+ let stopFlags = false;
18
+ while (i < argv.length) {
19
+ const arg = argv[i] ?? "";
20
+ if (stopFlags || arg === "") {
21
+ positional.push(arg);
22
+ i++;
23
+ continue;
24
+ }
25
+ if (arg === "--") {
26
+ stopFlags = true;
27
+ i++;
28
+ continue;
29
+ }
30
+ if (arg.startsWith("--")) {
31
+ const raw = arg.slice(2);
32
+ const eqIdx = raw.indexOf("=");
33
+ if (eqIdx >= 0) {
34
+ // --flag=value
35
+ const name = raw.slice(0, eqIdx);
36
+ const value = raw.slice(eqIdx + 1);
37
+ flags[name] = coerce(value);
38
+ }
39
+ else if (raw.startsWith("no-")) {
40
+ // --no-flag → false
41
+ flags[raw.slice(3)] = false;
42
+ }
43
+ else {
44
+ // --flag [value?]
45
+ const next = argv[i + 1];
46
+ if (next !== undefined && !next.startsWith("-")) {
47
+ flags[raw] = coerce(next);
48
+ i++;
49
+ }
50
+ else {
51
+ flags[raw] = true;
52
+ }
53
+ }
54
+ }
55
+ else if (arg.startsWith("-") && arg.length === 2) {
56
+ // -f [value?]
57
+ const short = arg.slice(1);
58
+ const next = argv[i + 1];
59
+ if (next !== undefined && !next.startsWith("-")) {
60
+ flags[short] = coerce(next);
61
+ i++;
62
+ }
63
+ else {
64
+ flags[short] = true;
65
+ }
66
+ }
67
+ else if (arg.startsWith("-") && arg.length > 2 && arg[2] !== "-") {
68
+ // -fVALUE or -f=VALUE
69
+ const short = arg[1] ?? "";
70
+ const rest = arg.slice(2).replace(/^=/, "");
71
+ flags[short] = coerce(rest);
72
+ }
73
+ else {
74
+ positional.push(arg);
75
+ }
76
+ i++;
77
+ }
78
+ return { positional, flags };
79
+ }
80
+ /** Coerce string to number or boolean if it looks like one. */
81
+ function coerce(value) {
82
+ if (value === "true")
83
+ return true;
84
+ if (value === "false")
85
+ return false;
86
+ const n = Number(value);
87
+ if (!Number.isNaN(n) && value.trim() !== "")
88
+ return n;
89
+ return value;
90
+ }
91
+ /** Resolve a flag value with a fallback, returning it as a string. */
92
+ export function flagStr(flags, name, short) {
93
+ const v = flags[name] ?? (short ? flags[short] : undefined);
94
+ return v !== undefined ? String(v) : undefined;
95
+ }
96
+ /** Resolve a flag value as a boolean. */
97
+ export function flagBool(flags, name, short) {
98
+ const v = flags[name] ?? (short ? flags[short] : undefined);
99
+ return v === true || v === "true" || v === 1;
100
+ }
101
+ //# sourceMappingURL=args.js.map
package/dist/client.js ADDED
@@ -0,0 +1,19 @@
1
+ import { AdminApiClient, CamundaClient } from "@bpmn-sdk/api";
2
+ import { getActiveProfile, getProfile } from "./profile.js";
3
+ function requireProfile(profileName) {
4
+ const profile = profileName ? getProfile(profileName) : getActiveProfile();
5
+ if (!profile) {
6
+ if (profileName) {
7
+ throw new Error(`Profile "${profileName}" not found. Run \`casen profile list\` to see available profiles.`);
8
+ }
9
+ throw new Error("No active profile. Create one with:\n\n casen profile create <name> --base-url <url> --auth-type bearer --token <token>\n");
10
+ }
11
+ return profile;
12
+ }
13
+ export function createClientFromProfile(profileName) {
14
+ return new CamundaClient(requireProfile(profileName).config);
15
+ }
16
+ export function createAdminClientFromProfile(profileName) {
17
+ return new AdminApiClient(requireProfile(profileName).config);
18
+ }
19
+ //# sourceMappingURL=client.js.map
package/dist/color.js ADDED
@@ -0,0 +1,50 @@
1
+ /**
2
+ * ANSI color helpers. Auto-disabled when:
3
+ * - NO_COLOR env var is set
4
+ * - stdout is not a TTY (piped output)
5
+ * - --no-color flag is passed (checked externally via isEnabled)
6
+ */
7
+ const ESC = "\x1b[";
8
+ function wrap(code, reset) {
9
+ return (text, enabled) => enabled ? `${ESC}${code}m${text}${ESC}${reset}m` : text;
10
+ }
11
+ export const bold = wrap("1", "22");
12
+ export const dim = wrap("2", "22");
13
+ export const italic = wrap("3", "23");
14
+ export const red = wrap("31", "39");
15
+ export const green = wrap("32", "39");
16
+ export const yellow = wrap("33", "39");
17
+ export const blue = wrap("34", "39");
18
+ export const magenta = wrap("35", "39");
19
+ export const cyan = wrap("36", "39");
20
+ export const white = wrap("37", "39");
21
+ /** Check if colors should be enabled given env + TTY state. */
22
+ export function shouldUseColor(noColorFlag) {
23
+ if (noColorFlag)
24
+ return false;
25
+ if (process.env.NO_COLOR !== undefined)
26
+ return false;
27
+ if (process.env.FORCE_COLOR !== undefined)
28
+ return true;
29
+ return process.stdout.isTTY === true;
30
+ }
31
+ /** Produce a state-colored string for Camunda entity states. */
32
+ export function stateColor(state, enabled) {
33
+ switch (state.toUpperCase()) {
34
+ case "ACTIVE":
35
+ case "EVALUATED":
36
+ case "COMPLETED":
37
+ return green(state, enabled);
38
+ case "TERMINATED":
39
+ case "FAILED":
40
+ case "CANCELED":
41
+ case "REJECTED":
42
+ return red(state, enabled);
43
+ case "SUSPENDED":
44
+ case "INCIDENT":
45
+ return yellow(state, enabled);
46
+ default:
47
+ return state;
48
+ }
49
+ }
50
+ //# sourceMappingURL=color.js.map
@@ -0,0 +1,180 @@
1
+ // ─── Shared flag specs ────────────────────────────────────────────────────────
2
+ export const FILTER_FLAG = {
3
+ name: "filter",
4
+ short: "f",
5
+ description: "Filter as JSON object",
6
+ type: "string",
7
+ placeholder: "JSON",
8
+ };
9
+ export const DATA_FLAG = {
10
+ name: "data",
11
+ short: "d",
12
+ description: "Request body as JSON",
13
+ type: "string",
14
+ required: true,
15
+ placeholder: "JSON",
16
+ };
17
+ export const DATA_OPT_FLAG = {
18
+ name: "data",
19
+ short: "d",
20
+ description: "Request body as JSON",
21
+ type: "string",
22
+ placeholder: "JSON",
23
+ };
24
+ export const LIMIT_FLAG = {
25
+ name: "limit",
26
+ short: "l",
27
+ description: "Maximum number of results",
28
+ type: "number",
29
+ default: 20,
30
+ };
31
+ export const SORT_FLAG = {
32
+ name: "sort-by",
33
+ description: "Sort field",
34
+ type: "string",
35
+ placeholder: "FIELD",
36
+ };
37
+ export const SORT_ORDER_FLAG = {
38
+ name: "sort-order",
39
+ description: "Sort order: asc|desc",
40
+ type: "string",
41
+ default: "asc",
42
+ };
43
+ // ─── JSON helpers ─────────────────────────────────────────────────────────────
44
+ export function parseJson(value, flagName) {
45
+ if (!value)
46
+ return undefined;
47
+ try {
48
+ return JSON.parse(value);
49
+ }
50
+ catch (err) {
51
+ throw new Error(`Invalid JSON for --${flagName}: ${err instanceof Error ? err.message : String(err)}\n\nGot: ${value}`);
52
+ }
53
+ }
54
+ function buildSearchBody(ctx) {
55
+ const filter = parseJson(ctx.flags.filter, "filter");
56
+ const limit = ctx.flags.limit;
57
+ const sortBy = ctx.flags["sort-by"];
58
+ const sortOrder = ctx.flags["sort-order"];
59
+ const body = {};
60
+ if (filter)
61
+ body.filter = filter;
62
+ if (limit !== undefined)
63
+ body.page = { limit };
64
+ if (sortBy)
65
+ body.sort = [{ field: sortBy, order: sortOrder ?? "asc" }];
66
+ return Object.keys(body).length > 0 ? body : undefined;
67
+ }
68
+ // ─── Command factories ────────────────────────────────────────────────────────
69
+ export function makeListCmd(opts) {
70
+ const filterFlag = opts.filterFields
71
+ ? { ...FILTER_FLAG, fields: opts.filterFields }
72
+ : FILTER_FLAG;
73
+ return {
74
+ name: opts.name ?? "list",
75
+ aliases: opts.aliases,
76
+ description: opts.description,
77
+ flags: [filterFlag, LIMIT_FLAG, SORT_FLAG, SORT_ORDER_FLAG, ...(opts.extraFlags ?? [])],
78
+ examples: opts.examples,
79
+ async run(ctx) {
80
+ const client = await ctx.getAdminClient();
81
+ const body = buildSearchBody(ctx);
82
+ const result = await opts.search(client, body);
83
+ ctx.output.printList(result, opts.columns);
84
+ },
85
+ };
86
+ }
87
+ export function makeGetCmd(opts) {
88
+ return {
89
+ name: opts.name ?? "get",
90
+ aliases: opts.aliases,
91
+ description: opts.description,
92
+ args: [
93
+ {
94
+ name: opts.argName,
95
+ description: opts.argDesc ?? `${opts.argName} to retrieve`,
96
+ required: true,
97
+ },
98
+ ],
99
+ examples: opts.examples,
100
+ async run(ctx) {
101
+ const key = ctx.positional[0];
102
+ if (!key)
103
+ throw new Error(`Missing required argument: <${opts.argName}>`);
104
+ const client = await ctx.getAdminClient();
105
+ const result = await opts.get(client, key);
106
+ ctx.output.printItem(result);
107
+ },
108
+ };
109
+ }
110
+ export function makeDeleteCmd(opts) {
111
+ return {
112
+ name: opts.name ?? "delete",
113
+ aliases: opts.aliases,
114
+ description: opts.description,
115
+ args: [{ name: opts.argName, description: `${opts.argName} to delete`, required: true }],
116
+ flags: opts.extraFlags ? [DATA_OPT_FLAG, ...opts.extraFlags] : undefined,
117
+ examples: opts.examples,
118
+ async run(ctx) {
119
+ const key = ctx.positional[0];
120
+ if (!key)
121
+ throw new Error(`Missing required argument: <${opts.argName}>`);
122
+ const body = opts.extraFlags
123
+ ? parseJson(ctx.flags.data, "data")
124
+ : undefined;
125
+ const client = await ctx.getAdminClient();
126
+ await opts.delete(client, key, body);
127
+ const msg = opts.successMsg ? opts.successMsg(key) : `Deleted ${key}`;
128
+ ctx.output.ok(msg);
129
+ },
130
+ };
131
+ }
132
+ export function makeCreateCmd(opts) {
133
+ const dataFlag = opts.bodyFields ? { ...DATA_FLAG, fields: opts.bodyFields } : DATA_FLAG;
134
+ return {
135
+ name: opts.name ?? "create",
136
+ aliases: opts.aliases,
137
+ description: opts.description,
138
+ flags: [dataFlag, ...(opts.extraFlags ?? [])],
139
+ examples: opts.examples,
140
+ async run(ctx) {
141
+ const raw = ctx.flags.data;
142
+ const body = parseJson(raw, "data") ?? {};
143
+ const client = await ctx.getAdminClient();
144
+ const result = await opts.create(client, body);
145
+ if (result !== undefined && result !== null) {
146
+ ctx.output.printItem(result);
147
+ }
148
+ else {
149
+ ctx.output.ok(opts.successMsg ?? "Created successfully.");
150
+ }
151
+ },
152
+ };
153
+ }
154
+ export function makeUpdateCmd(opts) {
155
+ const dataFlag = opts.bodyFields ? { ...DATA_FLAG, fields: opts.bodyFields } : DATA_FLAG;
156
+ return {
157
+ name: opts.name ?? "update",
158
+ aliases: opts.aliases,
159
+ description: opts.description,
160
+ args: [{ name: opts.argName, description: `${opts.argName} to update`, required: true }],
161
+ flags: [dataFlag, ...(opts.extraFlags ?? [])],
162
+ examples: opts.examples,
163
+ async run(ctx) {
164
+ const key = ctx.positional[0];
165
+ if (!key)
166
+ throw new Error(`Missing required argument: <${opts.argName}>`);
167
+ const raw = ctx.flags.data;
168
+ const body = parseJson(raw, "data") ?? {};
169
+ const client = await ctx.getAdminClient();
170
+ const result = await opts.update(client, key, body);
171
+ if (result !== undefined && result !== null) {
172
+ ctx.output.printItem(result);
173
+ }
174
+ else {
175
+ ctx.output.ok(`Updated ${key}.`);
176
+ }
177
+ },
178
+ };
179
+ }
180
+ //# sourceMappingURL=admin-shared.js.map
@@ -0,0 +1,143 @@
1
+ import { renderBpmnAscii, renderDmnAscii, renderFormAscii } from "@bpmnkit/ascii";
2
+ /**
3
+ * Replaces the generated `get-x-m-l` command. The endpoint returns text/xml,
4
+ * so we must set Accept: text/xml and parse the body as text, not JSON.
5
+ * The XML is then rendered as ASCII art via @bpmnkit/ascii.
6
+ */
7
+ export const getXmlCmd = {
8
+ name: "get-xml",
9
+ description: "Get process definition XML and render as ASCII art",
10
+ args: [{ name: "processDefinitionKey", description: "Process definition key", required: true }],
11
+ async run(ctx) {
12
+ const key = ctx.positional[0];
13
+ if (!key)
14
+ throw new Error("Missing required argument: <processDefinitionKey>");
15
+ const client = await ctx.getClient();
16
+ const xml = await client.http.request({
17
+ method: "GET",
18
+ path: `/process-definitions/${key}/xml`,
19
+ accept: "text/xml",
20
+ responseType: "text",
21
+ cacheable: true,
22
+ });
23
+ if (!xml)
24
+ throw new Error("No XML returned for this process definition");
25
+ const art = renderBpmnAscii(xml);
26
+ ctx.output.print(art);
27
+ },
28
+ };
29
+ /**
30
+ * Fetches a process definition's BPMN XML and renders it as ASCII art.
31
+ * Injected into the generated process-definition command group.
32
+ */
33
+ export const renderBpmnCmd = {
34
+ name: "render",
35
+ description: "Render process definition as ASCII art in the terminal",
36
+ args: [{ name: "processDefinitionKey", description: "Process definition key", required: true }],
37
+ async run(ctx) {
38
+ const key = ctx.positional[0];
39
+ if (!key)
40
+ throw new Error("Missing required argument: <processDefinitionKey>");
41
+ // Reuse the XML fetch + render logic
42
+ await getXmlCmd.run(ctx);
43
+ },
44
+ };
45
+ // ── DMN ───────────────────────────────────────────────────────────────────────
46
+ /**
47
+ * Replaces the generated `get-x-m-l` command on decision-definition.
48
+ * Fetches DMN XML and renders it as ASCII art.
49
+ */
50
+ export const getDmnXmlCmd = {
51
+ name: "get-xml",
52
+ description: "Get decision definition XML and render as ASCII art",
53
+ args: [{ name: "decisionDefinitionKey", description: "Decision definition key", required: true }],
54
+ async run(ctx) {
55
+ const key = ctx.positional[0];
56
+ if (!key)
57
+ throw new Error("Missing required argument: <decisionDefinitionKey>");
58
+ const client = await ctx.getClient();
59
+ const xml = await client.http.request({
60
+ method: "GET",
61
+ path: `/decision-definitions/${key}/xml`,
62
+ accept: "text/xml",
63
+ responseType: "text",
64
+ cacheable: true,
65
+ });
66
+ if (!xml)
67
+ throw new Error("No XML returned for this decision definition");
68
+ ctx.output.print(renderDmnAscii(xml));
69
+ },
70
+ };
71
+ /**
72
+ * Replaces the generated `get-x-m-l` command on decision-requirements.
73
+ * Fetches DMN requirements XML and renders it as ASCII art.
74
+ */
75
+ export const getDmnReqsXmlCmd = {
76
+ name: "get-xml",
77
+ description: "Get decision requirements XML and render as ASCII art",
78
+ args: [
79
+ { name: "decisionRequirementsKey", description: "Decision requirements key", required: true },
80
+ ],
81
+ async run(ctx) {
82
+ const key = ctx.positional[0];
83
+ if (!key)
84
+ throw new Error("Missing required argument: <decisionRequirementsKey>");
85
+ const client = await ctx.getClient();
86
+ const xml = await client.http.request({
87
+ method: "GET",
88
+ path: `/decision-requirements/${key}/xml`,
89
+ accept: "text/xml",
90
+ responseType: "text",
91
+ cacheable: true,
92
+ });
93
+ if (!xml)
94
+ throw new Error("No XML returned for this decision requirements");
95
+ ctx.output.print(renderDmnAscii(xml));
96
+ },
97
+ };
98
+ function renderFormResult(result, ctx) {
99
+ const schema = result.schema;
100
+ if (!schema) {
101
+ ctx.output.print("(no form schema)");
102
+ return;
103
+ }
104
+ // The Camunda API returns `schema` as a JSON-encoded string even though the
105
+ // generated TypeScript type says Record<string, unknown>. Handle both cases.
106
+ const json = typeof schema === "string" ? schema : JSON.stringify(schema);
107
+ ctx.output.print(renderFormAscii(json));
108
+ }
109
+ /**
110
+ * Replaces the generated `getstart-form` command on process-definition.
111
+ * Fetches the start form schema and renders it as ASCII art.
112
+ */
113
+ export const getStartFormCmd = {
114
+ name: "get-start-form",
115
+ description: "Get process start form and render as ASCII art",
116
+ args: [{ name: "processDefinitionKey", description: "Process definition key", required: true }],
117
+ async run(ctx) {
118
+ const key = ctx.positional[0];
119
+ if (!key)
120
+ throw new Error("Missing required argument: <processDefinitionKey>");
121
+ const client = await ctx.getClient();
122
+ const result = await client.processDefinition.getStartProcessForm(key);
123
+ renderFormResult(result, ctx);
124
+ },
125
+ };
126
+ /**
127
+ * Replaces the generated `get-form` command on user-task.
128
+ * Fetches the user task form schema and renders it as ASCII art.
129
+ */
130
+ export const getUserTaskFormCmd = {
131
+ name: "get-form",
132
+ description: "Get user task form and render as ASCII art",
133
+ args: [{ name: "userTaskKey", description: "User task key", required: true }],
134
+ async run(ctx) {
135
+ const key = ctx.positional[0];
136
+ if (!key)
137
+ throw new Error("Missing required argument: <userTaskKey>");
138
+ const client = await ctx.getClient();
139
+ const result = await client.userTask.getUserTaskForm(key);
140
+ renderFormResult(result, ctx);
141
+ },
142
+ };
143
+ //# sourceMappingURL=bpmn.js.map
@@ -0,0 +1,52 @@
1
+ import { getBashScript, getFishScript, getZshScript } from "../completion.js";
2
+ export const completionGroup = {
3
+ name: "completion",
4
+ description: "Generate shell completion scripts",
5
+ commands: [
6
+ {
7
+ name: "bash",
8
+ description: "Generate bash completion script",
9
+ examples: [
10
+ { description: "Install bash completion", command: 'eval "$(casen completion bash)"' },
11
+ {
12
+ description: "Persist bash completion",
13
+ command: "casen completion bash >> ~/.bash_completion",
14
+ },
15
+ ],
16
+ async run(ctx) {
17
+ ctx.output.print(getBashScript());
18
+ },
19
+ },
20
+ {
21
+ name: "zsh",
22
+ description: "Generate zsh completion script",
23
+ examples: [
24
+ {
25
+ description: "Install zsh completion",
26
+ command: "mkdir -p ~/.zfunc && casen completion zsh > ~/.zfunc/_casen",
27
+ },
28
+ {
29
+ description: "Then add to ~/.zshrc",
30
+ command: "# fpath=(~/.zfunc $fpath); autoload -Uz compinit && compinit",
31
+ },
32
+ ],
33
+ async run(ctx) {
34
+ ctx.output.print(getZshScript());
35
+ },
36
+ },
37
+ {
38
+ name: "fish",
39
+ description: "Generate fish completion script",
40
+ examples: [
41
+ {
42
+ description: "Install fish completion",
43
+ command: "casen completion fish > ~/.config/fish/completions/casen.fish",
44
+ },
45
+ ],
46
+ async run(ctx) {
47
+ ctx.output.print(getFishScript());
48
+ },
49
+ },
50
+ ],
51
+ };
52
+ //# sourceMappingURL=completion.js.map