@catladder/cli 0.0.0-new-cli-81ed6546 → 0.0.0-new-cli-a65ec262

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 (93) hide show
  1. package/README.md +2 -2
  2. package/dist/bundles/catenv/index.js +1 -1
  3. package/dist/bundles/cli/index.js +113 -81
  4. package/dist/cli/src/cli.js +24 -5
  5. package/dist/cli/src/cli.js.map +1 -1
  6. package/dist/cli/src/commands/cloudSQL/commandRestoreDb.js +1 -1
  7. package/dist/cli/src/commands/cloudSQL/commandRestoreDb.js.map +1 -1
  8. package/dist/cli/src/commands/fun/commandDadjoke.js +1 -1
  9. package/dist/cli/src/commands/fun/commandDadjoke.js.map +1 -1
  10. package/dist/cli/src/commands/fun/commandStarwars.js +1 -1
  11. package/dist/cli/src/commands/fun/commandStarwars.js.map +1 -1
  12. package/dist/cli/src/commands/general/commandKubeCurrentContext.js +1 -1
  13. package/dist/cli/src/commands/general/commandKubeGetShell.js +1 -1
  14. package/dist/cli/src/commands/general/commandKubeListNamespaces.js +1 -1
  15. package/dist/cli/src/commands/general/commandKubeListPods.js +1 -1
  16. package/dist/cli/src/commands/general/commandKubeListSecrets.js +1 -1
  17. package/dist/cli/src/commands/general/commandKubePortForward.js +1 -1
  18. package/dist/cli/src/commands/general/commandKubeStopPortforward.js +1 -1
  19. package/dist/cli/src/commands/mongodb/commandMongoDestroyMember.js +1 -1
  20. package/dist/cli/src/commands/mongodb/commandMongoGetShell.js +1 -1
  21. package/dist/cli/src/commands/mongodb/commandMongoPortForward.js +1 -1
  22. package/dist/cli/src/commands/project/commandCloudSqlProxy.js +1 -1
  23. package/dist/cli/src/commands/project/commandCloudSqlProxy.js.map +1 -1
  24. package/dist/cli/src/commands/project/commandConfigSecrets.js +1 -1
  25. package/dist/cli/src/commands/project/commandDeletePods.js +1 -1
  26. package/dist/cli/src/commands/project/commandDeleteProject.js +1 -1
  27. package/dist/cli/src/commands/project/commandEnvVars.js +1 -1
  28. package/dist/cli/src/commands/project/commandGetMyTotalWorktime.js +1 -1
  29. package/dist/cli/src/commands/project/commandGetMyTotalWorktime.js.map +1 -1
  30. package/dist/cli/src/commands/project/commandGetShell.js +1 -1
  31. package/dist/cli/src/commands/project/commandGitlabCi.js +2 -2
  32. package/dist/cli/src/commands/project/commandListPods.js +1 -1
  33. package/dist/cli/src/commands/project/commandNamespace.js +1 -1
  34. package/dist/cli/src/commands/project/commandOpenEnv.js +1 -1
  35. package/dist/cli/src/commands/project/commandOpenGit.js +1 -1
  36. package/dist/cli/src/commands/project/commandOpenLogs.js +1 -1
  37. package/dist/cli/src/commands/project/commandPauseProject.js +1 -1
  38. package/dist/cli/src/commands/project/commandPortForward.js +1 -1
  39. package/dist/cli/src/commands/project/commandProjectRestoreDb.js +1 -1
  40. package/dist/cli/src/commands/project/commandProjectRestoreDb.js.map +1 -1
  41. package/dist/cli/src/commands/project/commandRenewToken.js +1 -1
  42. package/dist/cli/src/commands/project/commandSecretsClearBackups.js +1 -1
  43. package/dist/cli/src/commands/project/commandSecurityEvaluate.js +1 -1
  44. package/dist/cli/src/commands/project/commandSetup.js +1 -1
  45. package/dist/cli/src/commands/project/commandTriggerCronjob.js +2 -2
  46. package/dist/cli/src/commands/project/commandTriggerCronjob.js.map +1 -1
  47. package/dist/cli/src/commands/security/commandSecurityAuditCiJob.js +1 -1
  48. package/dist/cli/src/commands/security/commandSecurityAuditCreate.js +1 -1
  49. package/dist/cli/src/commands/security/commandSecurityAuditEvaluate.js +1 -1
  50. package/dist/cli/src/completion.js +49 -36
  51. package/dist/cli/src/completion.js.map +1 -1
  52. package/dist/pipeline/src/constants.js +1 -1
  53. package/dist/tsconfig.tsbuildinfo +1 -1
  54. package/package.json +1 -1
  55. package/src/cli.ts +29 -5
  56. package/src/commands/cloudSQL/commandRestoreDb.ts +1 -1
  57. package/src/commands/fun/commandDadjoke.ts +1 -1
  58. package/src/commands/fun/commandStarwars.ts +1 -1
  59. package/src/commands/general/commandKubeCurrentContext.ts +1 -1
  60. package/src/commands/general/commandKubeGetShell.ts +1 -1
  61. package/src/commands/general/commandKubeListNamespaces.ts +1 -1
  62. package/src/commands/general/commandKubeListPods.ts +1 -1
  63. package/src/commands/general/commandKubeListSecrets.ts +1 -1
  64. package/src/commands/general/commandKubePortForward.ts +1 -1
  65. package/src/commands/general/commandKubeStopPortforward.ts +1 -1
  66. package/src/commands/mongodb/commandMongoDestroyMember.ts +1 -1
  67. package/src/commands/mongodb/commandMongoGetShell.ts +1 -1
  68. package/src/commands/mongodb/commandMongoPortForward.ts +1 -1
  69. package/src/commands/project/commandCloudSqlProxy.ts +1 -1
  70. package/src/commands/project/commandConfigSecrets.ts +1 -1
  71. package/src/commands/project/commandDeletePods.ts +1 -1
  72. package/src/commands/project/commandDeleteProject.ts +1 -1
  73. package/src/commands/project/commandEnvVars.ts +1 -1
  74. package/src/commands/project/commandGetMyTotalWorktime.ts +1 -1
  75. package/src/commands/project/commandGetShell.ts +1 -1
  76. package/src/commands/project/commandGitlabCi.ts +2 -2
  77. package/src/commands/project/commandListPods.ts +1 -1
  78. package/src/commands/project/commandNamespace.ts +1 -1
  79. package/src/commands/project/commandOpenEnv.ts +1 -1
  80. package/src/commands/project/commandOpenGit.ts +1 -1
  81. package/src/commands/project/commandOpenLogs.ts +1 -1
  82. package/src/commands/project/commandPauseProject.ts +1 -1
  83. package/src/commands/project/commandPortForward.ts +1 -1
  84. package/src/commands/project/commandProjectRestoreDb.ts +1 -1
  85. package/src/commands/project/commandRenewToken.ts +1 -1
  86. package/src/commands/project/commandSecretsClearBackups.ts +1 -1
  87. package/src/commands/project/commandSecurityEvaluate.ts +1 -1
  88. package/src/commands/project/commandSetup.ts +1 -1
  89. package/src/commands/project/commandTriggerCronjob.ts +2 -2
  90. package/src/commands/security/commandSecurityAuditCiJob.ts +1 -1
  91. package/src/commands/security/commandSecurityAuditCreate.ts +1 -1
  92. package/src/commands/security/commandSecurityAuditEvaluate.ts +1 -1
  93. package/src/completion.ts +53 -45
package/package.json CHANGED
@@ -53,7 +53,7 @@
53
53
  }
54
54
  ],
55
55
  "license": "MIT",
56
- "version": "0.0.0-new-cli-81ed6546",
56
+ "version": "0.0.0-new-cli-a65ec262",
57
57
  "scripts": {
58
58
  "lint": "eslint \"src/**/*.ts\"",
59
59
  "lint:fix": "eslint \"src/**/*.ts\" --fix",
package/src/cli.ts CHANGED
@@ -24,8 +24,28 @@ program
24
24
  // Collect all command defs for completion
25
25
  const allCommandDefs: CommandDef[] = [];
26
26
 
27
+ // Cache for intermediate subcommand groups (e.g., "project", "project cloudsql")
28
+ const subcommandCache = new Map<string, Command>();
29
+
30
+ /**
31
+ * Get or create a chain of nested subcommands.
32
+ * E.g., for ["project", "cloudsql"], ensures program.command("project").command("cloudsql") exists.
33
+ */
34
+ function getOrCreateParent(parts: string[]): Command {
35
+ if (parts.length === 0) return program;
36
+
37
+ const key = parts.join(" ");
38
+ if (subcommandCache.has(key)) return subcommandCache.get(key)!;
39
+
40
+ const parent = getOrCreateParent(parts.slice(0, -1));
41
+ const cmd = parent.command(parts[parts.length - 1]);
42
+ subcommandCache.set(key, cmd);
43
+ return cmd;
44
+ }
45
+
27
46
  /**
28
47
  * Register a CommandDef with Commander.js.
48
+ * - Command name can contain spaces for nesting (e.g., "project cloudsql proxy")
29
49
  * - Inputs with `positional: true` become Commander positional args
30
50
  * - Other inputs become optional --flags
31
51
  * - --inputs accepts JSON for programmatic use
@@ -45,15 +65,19 @@ function registerCommand(def: CommandDef): void {
45
65
  }
46
66
  }
47
67
 
48
- // Build the command string with positional args.
49
- // All positionals are registered as optional in Commander so that
50
- // ctx.get() can prompt for them interactively when missing.
51
- let cmdStr = def.name;
68
+ // Split name into parent groups + leaf command
69
+ const nameParts = def.name.split(" ");
70
+ const parentParts = nameParts.slice(0, -1);
71
+ const leafName = nameParts[nameParts.length - 1];
72
+
73
+ // Build leaf command string with positional args
74
+ let cmdStr = leafName;
52
75
  for (const [name] of positionalInputs) {
53
76
  cmdStr += ` [${name}]`;
54
77
  }
55
78
 
56
- const cmd = program.command(cmdStr).description(def.description);
79
+ const parent = getOrCreateParent(parentParts);
80
+ const cmd = parent.command(cmdStr).description(def.description);
57
81
 
58
82
  // Add --flag for each non-positional input
59
83
  for (const [name, inputDef] of flagInputs) {
@@ -4,7 +4,7 @@ import type { CloudSqlBackgroundProxy } from "../../gcloud/cloudSql/startProxy";
4
4
  import { startCloudSqlProxyInBackground } from "../../gcloud/cloudSql/startProxy";
5
5
 
6
6
  export const commandRestoreDb = defineCommand({
7
- name: "cloud-sql-restore-db",
7
+ name: "cloudsql restore-db",
8
8
  description: "restore a db from one source to another target",
9
9
  group: "cloudSQL",
10
10
  inputs: {
@@ -2,7 +2,7 @@ import fetch from "node-fetch";
2
2
  import { defineCommand } from "../../core/defineCommand";
3
3
 
4
4
  export const commandDadjoke = defineCommand({
5
- name: "dadjoke",
5
+ name: "fun dadjoke",
6
6
  description: "something for jonas.",
7
7
  group: "fun",
8
8
  inputs: {},
@@ -2,7 +2,7 @@ import { spawn } from "child-process-promise";
2
2
  import { defineCommand } from "../../core/defineCommand";
3
3
 
4
4
  export const commandStarwars = defineCommand({
5
- name: "starwars",
5
+ name: "fun starwars",
6
6
  description: "Long time ago... in a galaxy far far away...",
7
7
  group: "fun",
8
8
  inputs: {},
@@ -2,7 +2,7 @@ import { defineCommand } from "../../core/defineCommand";
2
2
  import { getCurrentContext } from "../../utils/cluster";
3
3
 
4
4
  export const commandKubeCurrentContext = defineCommand({
5
- name: "kube-current-context",
5
+ name: "kube current-context",
6
6
  description: "show current kubernetes context",
7
7
  group: "general",
8
8
  inputs: {},
@@ -4,7 +4,7 @@ import { getk8sApi } from "../../k8sApi";
4
4
  import { getShell } from "../../utils/shell";
5
5
 
6
6
  export const commandKubeGetShell = defineCommand({
7
- name: "kube-get-shell",
7
+ name: "kube get-shell",
8
8
  description: "get a shell to a pod in the environment",
9
9
  group: "general",
10
10
  inputs: {
@@ -2,7 +2,7 @@ import { defineCommand } from "../../core/defineCommand";
2
2
  import { getk8sApi } from "../../k8sApi";
3
3
 
4
4
  export const commandKubeListNamespaces = defineCommand({
5
- name: "kube-list-namespaces",
5
+ name: "kube list-namespaces",
6
6
  description: "list all namespaces",
7
7
  group: "general",
8
8
  inputs: {},
@@ -2,7 +2,7 @@ import { defineCommand } from "../../core/defineCommand";
2
2
  import { getk8sApi } from "../../k8sApi";
3
3
 
4
4
  export const commandKubeListPods = defineCommand({
5
- name: "kube-list-pods",
5
+ name: "kube list-pods",
6
6
  description: "list all pods of namespace",
7
7
  group: "general",
8
8
  inputs: {
@@ -2,7 +2,7 @@ import { defineCommand } from "../../core/defineCommand";
2
2
  import { getk8sApi } from "../../k8sApi";
3
3
 
4
4
  export const commandKubeListSecrets = defineCommand({
5
- name: "kube-list-secrets",
5
+ name: "kube list-secrets",
6
6
  description: "show secrets",
7
7
  group: "general",
8
8
  inputs: {
@@ -3,7 +3,7 @@ import { getk8sApi } from "../../k8sApi";
3
3
  import { startKubePortForward } from "../../kubernetes/portForward";
4
4
 
5
5
  export const commandKubePortForward = defineCommand({
6
- name: "kube-port-forward",
6
+ name: "kube port-forward",
7
7
  description: "start port-forwarding",
8
8
  group: "general",
9
9
  inputs: {
@@ -2,7 +2,7 @@ import { defineCommand } from "../../core/defineCommand";
2
2
  import { stopPortForward } from "../../utils/portForwards";
3
3
 
4
4
  export const commandKubeStopPortforward = defineCommand({
5
- name: "kube-stop-portforward",
5
+ name: "kube stop-portforward",
6
6
  description: "stop a running port forward",
7
7
  group: "general",
8
8
  inputs: {
@@ -34,7 +34,7 @@ const removeFinalizerAndDelete = async (
34
34
  };
35
35
 
36
36
  export const commandMongoDestroyMember = defineCommand({
37
- name: "project-mongo-destroy-member",
37
+ name: "project mongo destroy-member",
38
38
  description: "DESTROY a member of a replicaset in order to reinitialize it",
39
39
  group: "mongodb",
40
40
  inputs: {
@@ -9,7 +9,7 @@ import {
9
9
  import { envAndComponents } from "../../apps/cli/commands/project/utils/autocompletions";
10
10
 
11
11
  export const commandMongoGetShell = defineCommand({
12
- name: "project-mongo-get-shell",
12
+ name: "project mongo get-shell",
13
13
  description: "get a shell to a mongodb in the environment",
14
14
  group: "mongodb",
15
15
  inputs: {
@@ -9,7 +9,7 @@ import clipboard from "clipboardy";
9
9
  import { envAndComponents } from "../../apps/cli/commands/project/utils/autocompletions";
10
10
 
11
11
  export const commandMongoPortForward = defineCommand({
12
- name: "project-mongo-port-forward",
12
+ name: "project mongo port-forward",
13
13
  description: "port forward to a mongodb",
14
14
  group: "mongodb",
15
15
  inputs: {
@@ -91,7 +91,7 @@ const getJdbcUrl = (
91
91
  `DATABASE_JDBC_URL="jdbc:postgresql://localhost:${localPort}/${DB_NAME}?schema=public&user=${DB_USER}&password=${DB_PASSWORD}"`;
92
92
 
93
93
  export const commandCloudSqlProxy = defineCommand({
94
- name: "project-cloud-sql-proxy",
94
+ name: "project cloudsql proxy",
95
95
  description: "proxy to cloud sql db",
96
96
  group: "project",
97
97
  inputs: {
@@ -7,7 +7,7 @@ import { envAndComponents } from "../../apps/cli/commands/project/utils/autocomp
7
7
  // Full migration to CommandIO would require reworking the editor flow,
8
8
  // so for now we bridge it.
9
9
  export const commandConfigSecrets = defineCommand({
10
- name: "project-config-secrets",
10
+ name: "project config-secrets",
11
11
  description: "setup/update secrets stored in pass",
12
12
  group: "project",
13
13
  inputs: {
@@ -7,7 +7,7 @@ import { ensureCluster } from "../../apps/cli/commands/project/utils/ensureClust
7
7
  import { envAndComponents } from "../../apps/cli/commands/project/utils/autocompletions";
8
8
 
9
9
  export const commandDeletePods = defineCommand({
10
- name: "project-delete-pods",
10
+ name: "project delete-pods",
11
11
  description: "delete / restart pods",
12
12
  group: "project",
13
13
 
@@ -4,7 +4,7 @@ import { getProjectNamespace } from "../../utils/projects";
4
4
  import { envAndComponents } from "../../apps/cli/commands/project/utils/autocompletions";
5
5
 
6
6
  export const commandDeleteProject = defineCommand({
7
- name: "project-delete",
7
+ name: "project delete",
8
8
  description: "deletes a environment of a project (it deletes the namespace)",
9
9
  group: "project",
10
10
  inputs: {
@@ -3,7 +3,7 @@ import { getEnvVarsResolved, parseChoice } from "../../config/getProjectConfig";
3
3
  import { envAndComponents } from "../../apps/cli/commands/project/utils/autocompletions";
4
4
 
5
5
  export const commandEnvVars = defineCommand({
6
- name: "project-env-vars",
6
+ name: "project env-vars",
7
7
  description: "list env vars",
8
8
  group: "project",
9
9
  inputs: {
@@ -2,7 +2,7 @@ import { spawn } from "child-process-promise";
2
2
  import { defineCommand } from "../../core/defineCommand";
3
3
 
4
4
  export const commandGetMyTotalWorktime = defineCommand({
5
- name: "project-get-my-total-worktime",
5
+ name: "project worktime",
6
6
  description: "show the total worktime that you spent on a project",
7
7
  group: "project",
8
8
  inputs: {},
@@ -7,7 +7,7 @@ import { ensureCluster } from "../../apps/cli/commands/project/utils/ensureClust
7
7
  import { envAndComponents } from "../../apps/cli/commands/project/utils/autocompletions";
8
8
 
9
9
  export const commandGetShell = defineCommand({
10
- name: "project-get-shell",
10
+ name: "project get-shell",
11
11
  description: "get a shell to a pod in the environment",
12
12
  group: "project",
13
13
  inputs: {
@@ -61,7 +61,7 @@ const findJobById = async (io: any, jobName: string) => {
61
61
  };
62
62
 
63
63
  export const commandCiJobOpen = defineCommand({
64
- name: "project-ci-job-open",
64
+ name: "project ci job-open",
65
65
  description: "Open a Job",
66
66
  group: "project",
67
67
  inputs: {
@@ -79,7 +79,7 @@ export const commandCiJobOpen = defineCommand({
79
79
  });
80
80
 
81
81
  export const commandCiJobLog = defineCommand({
82
- name: "project-ci-job-log",
82
+ name: "project ci job-log",
83
83
  description: "Show a job's log",
84
84
  group: "project",
85
85
  inputs: {
@@ -6,7 +6,7 @@ import { ensureCluster } from "../../apps/cli/commands/project/utils/ensureClust
6
6
  import { envAndComponents } from "../../apps/cli/commands/project/utils/autocompletions";
7
7
 
8
8
  export const commandListPods = defineCommand({
9
- name: "project-list-pods",
9
+ name: "project list-pods",
10
10
  description: "list pods of local project",
11
11
  group: "project",
12
12
  inputs: {
@@ -3,7 +3,7 @@ import { getProjectNamespace } from "../../utils/projects";
3
3
  import { envAndComponents } from "../../apps/cli/commands/project/utils/autocompletions";
4
4
 
5
5
  export const commandNamespace = defineCommand({
6
- name: "project-namespace",
6
+ name: "project namespace",
7
7
  description: "show namespace of local project",
8
8
  group: "project",
9
9
  inputs: {
@@ -5,7 +5,7 @@ import { ensureCluster } from "../../apps/cli/commands/project/utils/ensureClust
5
5
  import { envAndComponents } from "../../apps/cli/commands/project/utils/autocompletions";
6
6
 
7
7
  export const commandOpenEnv = defineCommand({
8
- name: "project-open-env",
8
+ name: "project open env",
9
9
  description: "open the live environment",
10
10
  group: "project",
11
11
  inputs: {
@@ -2,7 +2,7 @@ import { exec } from "child-process-promise";
2
2
  import { defineCommand } from "../../core/defineCommand";
3
3
 
4
4
  export const commandOpenGit = defineCommand({
5
- name: "project-open-git",
5
+ name: "project open git",
6
6
  description: "open the repo on gitlab / github in your browser",
7
7
  group: "project",
8
8
  inputs: {},
@@ -7,7 +7,7 @@ import { openGoogleCloudLogs } from "../../kubernetes/openKubernetesDashboards";
7
7
  import { envAndComponents } from "../../apps/cli/commands/project/utils/autocompletions";
8
8
 
9
9
  export const commandOpenLogs = defineCommand({
10
- name: "project-open-logs",
10
+ name: "project open logs",
11
11
  description: "open google cloud logs (stackdriver logs)",
12
12
  group: "project",
13
13
  inputs: {
@@ -4,7 +4,7 @@ import { getProjectNamespace } from "../../utils/projects";
4
4
  import { envAndComponents } from "../../apps/cli/commands/project/utils/autocompletions";
5
5
 
6
6
  export const commandPauseProject = defineCommand({
7
- name: "project-pause",
7
+ name: "project pause",
8
8
  description: "halts all running pods (scales to 0)",
9
9
  group: "project",
10
10
  inputs: {
@@ -12,7 +12,7 @@ import open from "open";
12
12
  import { envAndComponents } from "../../apps/cli/commands/project/utils/autocompletions";
13
13
 
14
14
  export const commandPortForward = defineCommand({
15
- name: "project-port-forward",
15
+ name: "project port-forward",
16
16
  description: "start port-forwarding",
17
17
  group: "project",
18
18
  inputs: {
@@ -23,7 +23,7 @@ const hasCloudSql = (context: ComponentContext) => {
23
23
  };
24
24
 
25
25
  export const commandProjectRestoreDb = defineCommand({
26
- name: "project-cloud-sql-restore-db",
26
+ name: "project cloudsql restore-db",
27
27
  description: "restores a project db from one source to another target",
28
28
  group: "project",
29
29
  inputs: {
@@ -2,7 +2,7 @@ import { defineCommand } from "../../core/defineCommand";
2
2
  import { setupAccessTokens } from "../../apps/cli/commands/project/setup/setupAccessTokens";
3
3
 
4
4
  export const commandRenewToken = defineCommand({
5
- name: "project-renew-token",
5
+ name: "project renew-token",
6
6
  description: "Configures the project access token for semantic release.",
7
7
  group: "project",
8
8
  inputs: {},
@@ -2,7 +2,7 @@ import { defineCommand } from "../../core/defineCommand";
2
2
  import { clearBackups } from "../../utils/gitlab";
3
3
 
4
4
  export const commandSecretsClearBackups = defineCommand({
5
- name: "project-secrets-clear-backups",
5
+ name: "project secrets-clear-backups",
6
6
  description: "clears all backups",
7
7
  group: "project",
8
8
  inputs: {
@@ -6,7 +6,7 @@ import {
6
6
  import { getGitRoot } from "../../utils/projects";
7
7
 
8
8
  export const commandSecurityEvaluate = defineCommand({
9
- name: "project-security-evaluate",
9
+ name: "project security-evaluate",
10
10
  description: "evaluate project's security audit document",
11
11
  group: "project",
12
12
  inputs: {},
@@ -2,7 +2,7 @@ import { defineCommand } from "../../core/defineCommand";
2
2
  import { setupProject } from "../../apps/cli/commands/project/setup";
3
3
 
4
4
  export const commandSetup = defineCommand({
5
- name: "project-setup",
5
+ name: "project setup",
6
6
  description:
7
7
  "Initializes all environments and creates required resources, service accounts, etc.",
8
8
  group: "project",
@@ -46,7 +46,7 @@ const runCronjob = async (
46
46
  };
47
47
 
48
48
  export const commandTriggerCronjobGeneral = defineCommand({
49
- name: "trigger-cronjob",
49
+ name: "kube trigger-cronjob",
50
50
  description: "trigger cronjob",
51
51
  group: "general",
52
52
  inputs: {
@@ -69,7 +69,7 @@ export const commandTriggerCronjobGeneral = defineCommand({
69
69
  });
70
70
 
71
71
  export const commandTriggerCronjobProject = defineCommand({
72
- name: "project-trigger-cronjob",
72
+ name: "project trigger-cronjob",
73
73
  description: "trigger cronjob",
74
74
  group: "project",
75
75
  inputs: {
@@ -12,7 +12,7 @@ import {
12
12
  const GITLAB_HOST = "https://git.panter.ch";
13
13
 
14
14
  export const commandSecurityAuditCiJob = defineCommand({
15
- name: "security-audit-ci-job",
15
+ name: "security audit ci-job",
16
16
  description:
17
17
  "Evaluates security audit document. Creates MR with template if missing.",
18
18
  group: "security",
@@ -5,7 +5,7 @@ import { createSecurityAuditMergeRequest } from "../../security/createSecurityAu
5
5
  const GITLAB_HOST = "https://git.panter.ch";
6
6
 
7
7
  export const commandSecurityAuditCreate = defineCommand({
8
- name: "security-audit-create",
8
+ name: "security audit create",
9
9
  description: "Creates a MR with the latest security audit template document",
10
10
  group: "security",
11
11
  inputs: {
@@ -6,7 +6,7 @@ import {
6
6
  import { SECURITY_AUDIT_FILE_NAME } from "../../security/createSecurityAuditMergeRequest";
7
7
 
8
8
  export const commandSecurityAuditEvaluate = defineCommand({
9
- name: "security-audit-evaluate",
9
+ name: "security audit evaluate",
10
10
  description: "Evaluates security audit document in given path",
11
11
  group: "security",
12
12
  inputs: {
package/src/completion.ts CHANGED
@@ -16,60 +16,68 @@ export async function getCompletions(
16
16
  words: string[],
17
17
  cursorWord: string,
18
18
  ): Promise<string[]> {
19
- // If no command yet, complete command names
20
- if (words.length === 0) {
21
- return allCommands
22
- .map((c) => c.name)
23
- .filter((name) => name.startsWith(cursorWord));
24
- }
25
-
26
- const commandName = words[0];
27
- const command = allCommands.find((c) => c.name === commandName);
19
+ // Try to match words against command names (which can be multi-word)
20
+ // Walk through words, consuming them as command name parts until we find
21
+ // an exact command match or need to suggest the next subcommand level.
22
+
23
+ // Find all commands whose name starts with the words typed so far
24
+ const typed = words.join(" ");
25
+
26
+ // Exact match: we've typed a full command name, now complete its inputs
27
+ const exactCommand = allCommands.find((c) => c.name === typed);
28
+ if (exactCommand) {
29
+ // Check if cursor is a --flag
30
+ if (cursorWord.startsWith("--")) {
31
+ return getFlagCompletions(exactCommand, cursorWord);
32
+ }
28
33
 
29
- // If the first word doesn't match a command, complete command names
30
- if (!command) {
31
- return allCommands
32
- .map((c) => c.name)
33
- .filter((name) => name.startsWith(commandName));
34
- }
34
+ // Check if previous word was a --flag (complete its value)
35
+ const prevWord = words[words.length - 1];
36
+ if (prevWord?.startsWith("--")) {
37
+ const flagName = prevWord.replace(/^--/, "");
38
+ const inputName = flagNameToInputName(flagName);
39
+ const inputDef = exactCommand.inputs[inputName];
40
+ if (inputDef && "choices" in inputDef && inputDef.choices) {
41
+ return resolveChoicesForCompletion(inputDef, cursorWord);
42
+ }
43
+ return [];
44
+ }
35
45
 
36
- // We have a valid command. Figure out what to complete.
37
- const argsAfterCommand = words.slice(1);
38
-
39
- // Check if we're completing a --flag value
40
- const prevWord = argsAfterCommand[argsAfterCommand.length - 1];
41
- if (prevWord?.startsWith("--")) {
42
- // Previous word is a flag, complete its values
43
- const flagName = prevWord.replace(/^--/, "");
44
- const inputName = flagNameToInputName(flagName);
45
- const inputDef = command.inputs[inputName];
46
- if (inputDef && "choices" in inputDef && inputDef.choices) {
47
- return resolveChoicesForCompletion(inputDef, cursorWord);
46
+ // Complete positional inputs
47
+ const positionalInputs = getPositionalInputs(exactCommand);
48
+ // Count non-flag args after the command name
49
+ const argsAfterCommand = words.slice(exactCommand.name.split(" ").length);
50
+ const positionalArgs = argsAfterCommand.filter((w) => !w.startsWith("--"));
51
+ const positionalIndex = positionalArgs.length;
52
+ const targetInput = positionalInputs[positionalIndex];
53
+
54
+ if (targetInput) {
55
+ const [, inputDef] = targetInput;
56
+ if ("choices" in inputDef && inputDef.choices) {
57
+ return resolveChoicesForCompletion(inputDef, cursorWord);
58
+ }
48
59
  }
49
60
  return [];
50
61
  }
51
62
 
52
- // Check if we're typing a --flag name
53
- if (cursorWord.startsWith("--")) {
54
- return getFlagCompletions(command, cursorWord);
55
- }
56
-
57
- // Otherwise, complete positional inputs
58
- const positionalInputs = getPositionalInputs(command);
59
- const positionalArgs = argsAfterCommand.filter((w) => !w.startsWith("--"));
60
-
61
- // Which positional index are we on?
62
- const positionalIndex = positionalArgs.length;
63
- const targetInput = positionalInputs[positionalIndex];
64
-
65
- if (targetInput) {
66
- const [, inputDef] = targetInput;
67
- if ("choices" in inputDef && inputDef.choices) {
68
- return resolveChoicesForCompletion(inputDef, cursorWord);
63
+ // No exact match. Complete the next level of subcommand names.
64
+ // The prefix is what's been typed so far (words joined with space).
65
+ const prefix = typed ? typed + " " : "";
66
+
67
+ // Find unique next-level subcommand names
68
+ const nextParts = new Set<string>();
69
+ for (const cmd of allCommands) {
70
+ if (cmd.name.startsWith(prefix)) {
71
+ // Get the next word after the prefix
72
+ const rest = cmd.name.slice(prefix.length);
73
+ const nextPart = rest.split(" ")[0];
74
+ if (nextPart && nextPart.startsWith(cursorWord)) {
75
+ nextParts.add(nextPart);
76
+ }
69
77
  }
70
78
  }
71
79
 
72
- return [];
80
+ return [...nextParts].sort();
73
81
  }
74
82
 
75
83
  function getPositionalInputs(command: CommandDef): [string, InputDef][] {