@kaitranntt/ccs 5.9.0 → 5.10.0

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 (96) hide show
  1. package/README.md +30 -2
  2. package/VERSION +1 -1
  3. package/dist/ccs.js +12 -0
  4. package/dist/ccs.js.map +1 -1
  5. package/dist/cliproxy/binary-manager.d.ts +2 -2
  6. package/dist/cliproxy/binary-manager.js +2 -2
  7. package/dist/cliproxy/model-catalog.d.ts +12 -0
  8. package/dist/cliproxy/model-catalog.d.ts.map +1 -1
  9. package/dist/cliproxy/model-catalog.js +31 -11
  10. package/dist/cliproxy/model-catalog.js.map +1 -1
  11. package/dist/cliproxy/model-config.d.ts.map +1 -1
  12. package/dist/cliproxy/model-config.js +14 -2
  13. package/dist/cliproxy/model-config.js.map +1 -1
  14. package/dist/cliproxy/platform-detector.d.ts +2 -2
  15. package/dist/cliproxy/platform-detector.js +1 -1
  16. package/dist/commands/cliproxy-command.d.ts.map +1 -1
  17. package/dist/commands/cliproxy-command.js +92 -54
  18. package/dist/commands/cliproxy-command.js.map +1 -1
  19. package/dist/commands/config-command.d.ts +11 -0
  20. package/dist/commands/config-command.d.ts.map +1 -0
  21. package/dist/commands/config-command.js +111 -0
  22. package/dist/commands/config-command.js.map +1 -0
  23. package/dist/commands/help-command.d.ts.map +1 -1
  24. package/dist/commands/help-command.js +4 -1
  25. package/dist/commands/help-command.js.map +1 -1
  26. package/dist/glmt/glmt-proxy.d.ts +6 -0
  27. package/dist/glmt/glmt-proxy.d.ts.map +1 -1
  28. package/dist/glmt/glmt-proxy.js +23 -2
  29. package/dist/glmt/glmt-proxy.js.map +1 -1
  30. package/dist/management/doctor.d.ts.map +1 -1
  31. package/dist/management/doctor.js +19 -7
  32. package/dist/management/doctor.js.map +1 -1
  33. package/dist/ui/assets/form-utils-CE1K85pW.js +20 -0
  34. package/dist/ui/assets/icons-DJoMkiyK.js +1 -0
  35. package/dist/ui/assets/index-BxRTPSHw.js +9 -0
  36. package/dist/ui/assets/index-ks0hk5dc.css +1 -0
  37. package/dist/ui/assets/radix-ui-Ba6LUgyw.js +51 -0
  38. package/dist/ui/assets/react-vendor-CW-MU7-e.js +3 -0
  39. package/dist/ui/assets/tanstack-MD0629v8.js +4 -0
  40. package/dist/ui/favicon.ico +0 -0
  41. package/dist/ui/favicons/android-chrome-192x192.png +0 -0
  42. package/dist/ui/favicons/android-chrome-512x512.png +0 -0
  43. package/dist/ui/favicons/android-chrome-512x512.webp +0 -0
  44. package/dist/ui/favicons/apple-touch-icon.png +0 -0
  45. package/dist/ui/favicons/favicon-16x16.png +0 -0
  46. package/dist/ui/favicons/favicon-32x32.png +0 -0
  47. package/dist/ui/favicons/favicon.ico +0 -0
  48. package/dist/ui/index.html +30 -0
  49. package/dist/ui/logo/ccs-logo-256.png +0 -0
  50. package/dist/ui/logo/ccs-logo-zoomed-web.png +0 -0
  51. package/dist/ui/logo/ccs-social-media.png +0 -0
  52. package/dist/ui/logo/ccs-social-media.webp +0 -0
  53. package/dist/utils/port-utils.d.ts +19 -0
  54. package/dist/utils/port-utils.d.ts.map +1 -0
  55. package/dist/utils/port-utils.js +113 -0
  56. package/dist/utils/port-utils.js.map +1 -0
  57. package/dist/web-server/file-watcher.d.ts +15 -0
  58. package/dist/web-server/file-watcher.d.ts.map +1 -0
  59. package/dist/web-server/file-watcher.js +88 -0
  60. package/dist/web-server/file-watcher.js.map +1 -0
  61. package/dist/web-server/health-service.d.ts +35 -0
  62. package/dist/web-server/health-service.d.ts.map +1 -0
  63. package/dist/web-server/health-service.js +223 -0
  64. package/dist/web-server/health-service.js.map +1 -0
  65. package/dist/web-server/index.d.ts +25 -0
  66. package/dist/web-server/index.d.ts.map +1 -0
  67. package/dist/web-server/index.js +89 -0
  68. package/dist/web-server/index.js.map +1 -0
  69. package/dist/web-server/overview-routes.d.ts +7 -0
  70. package/dist/web-server/overview-routes.d.ts.map +1 -0
  71. package/dist/web-server/overview-routes.js +80 -0
  72. package/dist/web-server/overview-routes.js.map +1 -0
  73. package/dist/web-server/routes.d.ts +7 -0
  74. package/dist/web-server/routes.d.ts.map +1 -0
  75. package/dist/web-server/routes.js +444 -0
  76. package/dist/web-server/routes.js.map +1 -0
  77. package/dist/web-server/shared-routes.d.ts +7 -0
  78. package/dist/web-server/shared-routes.d.ts.map +1 -0
  79. package/dist/web-server/shared-routes.js +167 -0
  80. package/dist/web-server/shared-routes.js.map +1 -0
  81. package/dist/web-server/shutdown.d.ts +14 -0
  82. package/dist/web-server/shutdown.d.ts.map +1 -0
  83. package/dist/web-server/shutdown.js +36 -0
  84. package/dist/web-server/shutdown.js.map +1 -0
  85. package/dist/web-server/websocket.d.ts +14 -0
  86. package/dist/web-server/websocket.d.ts.map +1 -0
  87. package/dist/web-server/websocket.js +82 -0
  88. package/dist/web-server/websocket.js.map +1 -0
  89. package/package.json +26 -6
  90. package/scripts/clean-dist.js +46 -0
  91. package/scripts/completion/ccs.bash +69 -10
  92. package/scripts/completion/ccs.fish +128 -47
  93. package/scripts/completion/ccs.ps1 +179 -14
  94. package/scripts/completion/ccs.zsh +107 -28
  95. package/scripts/pre-release.sh +39 -0
  96. package/scripts/verify-bundle.js +49 -0
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ /**
3
+ * Graceful Shutdown Handler
4
+ *
5
+ * Handles SIGINT/SIGTERM signals to gracefully close WebSocket connections
6
+ * and HTTP server before process exit.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.setupGracefulShutdown = void 0;
10
+ const SHUTDOWN_TIMEOUT = 10000; // 10 seconds
11
+ /**
12
+ * Setup graceful shutdown handlers for SIGINT and SIGTERM
13
+ */
14
+ function setupGracefulShutdown(server, _wss, cleanup) {
15
+ const shutdown = () => {
16
+ console.log('\n[i] Shutting down gracefully...');
17
+ // Run cleanup first (closes file watchers + WebSocket clients)
18
+ if (cleanup) {
19
+ cleanup();
20
+ }
21
+ // Close HTTP server
22
+ server.close(() => {
23
+ console.log('[OK] Server closed');
24
+ process.exit(0);
25
+ });
26
+ // Force shutdown if graceful shutdown takes too long
27
+ setTimeout(() => {
28
+ console.log('[!] Force shutdown (timeout exceeded)');
29
+ process.exit(1);
30
+ }, SHUTDOWN_TIMEOUT);
31
+ };
32
+ process.on('SIGINT', shutdown);
33
+ process.on('SIGTERM', shutdown);
34
+ }
35
+ exports.setupGracefulShutdown = setupGracefulShutdown;
36
+ //# sourceMappingURL=shutdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shutdown.js","sourceRoot":"","sources":["../../src/web-server/shutdown.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAKH,MAAM,gBAAgB,GAAG,KAAM,CAAC,CAAC,aAAa;AAE9C;;GAEG;AACH,SAAgB,qBAAqB,CACnC,MAAkB,EAClB,IAAqB,EACrB,OAAoB;IAEpB,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;QAEjD,+DAA+D;QAC/D,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,oBAAoB;QACpB,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE;YAChB,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;YAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;QAEH,qDAAqD;QACrD,UAAU,CAAC,GAAG,EAAE;YACd,OAAO,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;YACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,EAAE,gBAAgB,CAAC,CAAC;IACvB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAClC,CAAC;AA5BD,sDA4BC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * WebSocket Handler (Phase 04)
3
+ *
4
+ * Manages WebSocket connections, broadcasts file changes, and handles client messages.
5
+ */
6
+ import { WebSocketServer } from 'ws';
7
+ export interface WSMessage {
8
+ type: string;
9
+ [key: string]: unknown;
10
+ }
11
+ export declare function setupWebSocket(wss: WebSocketServer): {
12
+ cleanup: () => void;
13
+ };
14
+ //# sourceMappingURL=websocket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../../src/web-server/websocket.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,eAAe,EAAa,MAAM,IAAI,CAAC;AAGhD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,eAAe,GAAG;IAAE,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,CA8E5E"}
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ /**
3
+ * WebSocket Handler (Phase 04)
4
+ *
5
+ * Manages WebSocket connections, broadcasts file changes, and handles client messages.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.setupWebSocket = void 0;
9
+ const ws_1 = require("ws");
10
+ const file_watcher_1 = require("./file-watcher");
11
+ function setupWebSocket(wss) {
12
+ // Track connected clients
13
+ const clients = new Set();
14
+ // Broadcast message to all clients
15
+ function broadcast(message) {
16
+ const data = JSON.stringify(message);
17
+ clients.forEach((client) => {
18
+ if (client.readyState === ws_1.WebSocket.OPEN) {
19
+ client.send(data);
20
+ }
21
+ });
22
+ }
23
+ // Handle new connections
24
+ wss.on('connection', (ws) => {
25
+ clients.add(ws);
26
+ console.log(`[WS] Client connected (${clients.size} total)`);
27
+ // Send welcome message
28
+ ws.send(JSON.stringify({ type: 'connected', timestamp: Date.now() }));
29
+ // Handle client messages
30
+ ws.on('message', (data) => {
31
+ try {
32
+ const message = JSON.parse(data.toString());
33
+ handleClientMessage(ws, message);
34
+ }
35
+ catch {
36
+ console.log('[WS] Invalid message format');
37
+ }
38
+ });
39
+ // Handle disconnect
40
+ ws.on('close', () => {
41
+ clients.delete(ws);
42
+ console.log(`[WS] Client disconnected (${clients.size} remaining)`);
43
+ });
44
+ ws.on('error', (err) => {
45
+ console.log(`[WS] Error: ${err.message}`);
46
+ clients.delete(ws);
47
+ });
48
+ });
49
+ // Handle incoming client messages
50
+ function handleClientMessage(ws, message) {
51
+ switch (message.type) {
52
+ case 'ping':
53
+ ws.send(JSON.stringify({ type: 'pong', timestamp: Date.now() }));
54
+ break;
55
+ case 'subscribe':
56
+ // Future: selective subscriptions
57
+ break;
58
+ default:
59
+ console.log(`[WS] Unknown message type: ${message.type}`);
60
+ }
61
+ }
62
+ // Setup file watcher
63
+ const watcher = (0, file_watcher_1.createFileWatcher)((event) => {
64
+ console.log(`[FS] ${event.type}: ${event.path}`);
65
+ broadcast({
66
+ type: event.type,
67
+ path: event.path,
68
+ timestamp: event.timestamp,
69
+ });
70
+ });
71
+ // Cleanup function
72
+ const cleanup = () => {
73
+ watcher.close();
74
+ clients.forEach((client) => {
75
+ client.close(1001, 'Server shutting down');
76
+ });
77
+ clients.clear();
78
+ };
79
+ return { cleanup };
80
+ }
81
+ exports.setupWebSocket = setupWebSocket;
82
+ //# sourceMappingURL=websocket.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket.js","sourceRoot":"","sources":["../../src/web-server/websocket.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaitranntt/ccs",
3
- "version": "5.9.0",
3
+ "version": "5.10.0",
4
4
  "description": "Claude Code Switch - Instant profile switching between Claude Sonnet 4.5 and GLM 4.6",
5
5
  "keywords": [
6
6
  "cli",
@@ -52,45 +52,65 @@
52
52
  "scripts": {
53
53
  "build": "tsc && node scripts/add-shebang.js",
54
54
  "build:watch": "tsc --watch",
55
- "prebuild": "rm -rf dist tsconfig.tsbuildinfo",
55
+ "build:server": "tsc && node scripts/add-shebang.js",
56
+ "build:all": "bun run ui:build && bun run build:server",
57
+ "prebuild": "node scripts/clean-dist.js",
58
+ "prebuild:all": "rm -rf dist tsconfig.tsbuildinfo",
59
+ "postbuild:all": "node scripts/verify-bundle.js",
56
60
  "typecheck": "tsc --noEmit",
57
61
  "lint": "eslint src/",
58
62
  "lint:fix": "eslint src/ --fix",
59
63
  "format": "prettier --write src/",
60
64
  "format:check": "prettier --check src/",
61
65
  "validate": "bun run typecheck && bun run lint:fix && bun run format:check && bun run test",
66
+ "verify:bundle": "node scripts/verify-bundle.js",
62
67
  "test": "bun run build && bun run test:all",
63
68
  "test:all": "bun test",
64
69
  "test:unit": "bun test tests/unit/",
65
70
  "test:npm": "bun test tests/npm/",
66
71
  "test:native": "bash tests/native/unix/edge-cases.sh",
67
- "prepublishOnly": "npm run validate && node scripts/sync-version.js",
68
- "prepack": "npm run validate && node scripts/sync-version.js",
72
+ "dev": "bun run build:server && bun dist/ccs.js config --dev",
73
+ "ui:build": "cd ui && bun run build",
74
+ "ui:preview": "cd ui && bun run preview",
75
+ "ui:validate": "cd ui && bun run validate",
76
+ "prepublishOnly": "bun run build:all && bun run validate && node scripts/sync-version.js",
77
+ "prepack": "bun run build:all && bun run validate && node scripts/sync-version.js",
69
78
  "prepare": "husky",
70
79
  "postinstall": "node scripts/postinstall.js"
71
80
  },
72
81
  "dependencies": {
73
82
  "boxen": "^8.0.1",
74
83
  "chalk": "^5.6.2",
84
+ "chokidar": "^5.0.0",
75
85
  "cli-table3": "^0.6.5",
86
+ "express": "^4.18.2",
87
+ "get-port": "^7.0.0",
76
88
  "gradient-string": "^3.0.0",
77
89
  "listr2": "^9.0.5",
78
- "ora": "^9.0.0"
90
+ "open": "^10.1.0",
91
+ "ora": "^9.0.0",
92
+ "ws": "^8.16.0"
79
93
  },
80
94
  "devDependencies": {
81
95
  "@commitlint/cli": "^20.1.0",
82
96
  "@commitlint/config-conventional": "^20.0.0",
83
97
  "@semantic-release/changelog": "^6.0.3",
84
98
  "@semantic-release/git": "^10.0.1",
99
+ "@tailwindcss/vite": "^4.1.17",
100
+ "@types/chokidar": "^2.1.7",
101
+ "@types/express": "^4.17.21",
85
102
  "@types/node": "^20.19.25",
103
+ "@types/ws": "^8.5.10",
86
104
  "@typescript-eslint/eslint-plugin": "^8.48.0",
87
105
  "@typescript-eslint/parser": "^8.48.0",
106
+ "@vitejs/plugin-react": "^5.1.1",
88
107
  "eslint": "^9.39.1",
89
108
  "eslint-config-prettier": "^10.1.8",
90
109
  "husky": "^9.1.7",
91
110
  "mocha": "^11.7.5",
92
111
  "prettier": "^3.6.2",
93
112
  "semantic-release": "^25.0.2",
94
- "typescript": "5.3"
113
+ "typescript": "5.3",
114
+ "vite": "^7.2.4"
95
115
  }
96
116
  }
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Clean dist directory while preserving UI bundle
5
+ * The UI bundle is built separately and should not be deleted during regular builds
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+
11
+ const DIST_DIR = path.join(__dirname, '../dist');
12
+ const TSCONFIG_BUILDINFO = path.join(__dirname, '../tsconfig.tsbuildinfo');
13
+
14
+ // Directories to preserve (from UI build)
15
+ const PRESERVE = new Set(['ui']);
16
+
17
+ function cleanDist() {
18
+ // Remove tsconfig.tsbuildinfo
19
+ if (fs.existsSync(TSCONFIG_BUILDINFO)) {
20
+ fs.unlinkSync(TSCONFIG_BUILDINFO);
21
+ }
22
+
23
+ // If dist doesn't exist, nothing to clean
24
+ if (!fs.existsSync(DIST_DIR)) {
25
+ return;
26
+ }
27
+
28
+ const entries = fs.readdirSync(DIST_DIR, { withFileTypes: true });
29
+
30
+ for (const entry of entries) {
31
+ // Skip preserved directories
32
+ if (PRESERVE.has(entry.name)) {
33
+ continue;
34
+ }
35
+
36
+ const fullPath = path.join(DIST_DIR, entry.name);
37
+
38
+ if (entry.isDirectory()) {
39
+ fs.rmSync(fullPath, { recursive: true, force: true });
40
+ } else {
41
+ fs.unlinkSync(fullPath);
42
+ }
43
+ }
44
+ }
45
+
46
+ cleanDist();
@@ -18,8 +18,9 @@ _ccs_completion() {
18
18
 
19
19
  # Top-level completion (first argument)
20
20
  if [[ ${COMP_CWORD} -eq 1 ]]; then
21
- local commands="auth profile doctor sync update"
21
+ local commands="auth api cliproxy doctor sync update"
22
22
  local flags="--help --version --shell-completion -h -v -sc"
23
+ local cliproxy_profiles="gemini codex agy qwen"
23
24
  local profiles=""
24
25
 
25
26
  # Add profiles from config.json (settings-based profiles)
@@ -32,12 +33,24 @@ _ccs_completion() {
32
33
  profiles="$profiles $(jq -r '.profiles | keys[]' ~/.ccs/profiles.json 2>/dev/null || true)"
33
34
  fi
34
35
 
36
+ # Add cliproxy variants from config.json
37
+ if [[ -f ~/.ccs/config.json ]]; then
38
+ profiles="$profiles $(jq -r '.cliproxy | keys[]' ~/.ccs/config.json 2>/dev/null || true)"
39
+ fi
40
+
35
41
  # Combine all options
36
- local opts="$commands $flags $profiles"
42
+ local opts="$commands $flags $cliproxy_profiles $profiles"
37
43
  COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
38
44
  return 0
39
45
  fi
40
46
 
47
+ # CLIProxy provider flags (gemini, codex, agy, qwen)
48
+ if [[ ${COMP_WORDS[1]} =~ ^(gemini|codex|agy|qwen)$ ]]; then
49
+ local provider_flags="--auth --config --logout --headless --help -h"
50
+ COMPREPLY=( $(compgen -W "${provider_flags}" -- ${cur}) )
51
+ return 0
52
+ fi
53
+
41
54
  # auth subcommands
42
55
  if [[ ${prev} == "auth" ]]; then
43
56
  local auth_commands="create list show remove default --help -h"
@@ -45,15 +58,54 @@ _ccs_completion() {
45
58
  return 0
46
59
  fi
47
60
 
48
- # profile subcommands
49
- if [[ ${prev} == "profile" ]]; then
50
- local profile_commands="create list remove --help -h"
51
- COMPREPLY=( $(compgen -W "${profile_commands}" -- ${cur}) )
61
+ # api subcommands
62
+ if [[ ${prev} == "api" ]]; then
63
+ local api_commands="create list remove --help -h"
64
+ COMPREPLY=( $(compgen -W "${api_commands}" -- ${cur}) )
65
+ return 0
66
+ fi
67
+
68
+ # cliproxy subcommands
69
+ if [[ ${prev} == "cliproxy" ]]; then
70
+ local cliproxy_commands="create list remove --install --latest --help -h"
71
+ COMPREPLY=( $(compgen -W "${cliproxy_commands}" -- ${cur}) )
52
72
  return 0
53
73
  fi
54
74
 
55
- # Completion for profile subcommands
56
- if [[ ${COMP_WORDS[1]} == "profile" ]]; then
75
+ # Completion for cliproxy subcommands
76
+ if [[ ${COMP_WORDS[1]} == "cliproxy" ]]; then
77
+ case "${prev}" in
78
+ remove|delete|rm)
79
+ # Complete with cliproxy variant names
80
+ if [[ -f ~/.ccs/config.json ]]; then
81
+ local variants=$(jq -r '.cliproxy | keys[]' ~/.ccs/config.json 2>/dev/null || true)
82
+ COMPREPLY=( $(compgen -W "${variants}" -- ${cur}) )
83
+ fi
84
+ return 0
85
+ ;;
86
+ create)
87
+ # Complete with create flags
88
+ COMPREPLY=( $(compgen -W "--provider --model --force --yes -y" -- ${cur}) )
89
+ return 0
90
+ ;;
91
+ --provider)
92
+ # Complete with provider names
93
+ COMPREPLY=( $(compgen -W "gemini codex agy qwen" -- ${cur}) )
94
+ return 0
95
+ ;;
96
+ list|ls)
97
+ # No flags for list
98
+ return 0
99
+ ;;
100
+ --install)
101
+ # User enters version number
102
+ return 0
103
+ ;;
104
+ esac
105
+ fi
106
+
107
+ # Completion for api subcommands
108
+ if [[ ${COMP_WORDS[1]} == "api" ]]; then
57
109
  case "${prev}" in
58
110
  remove|delete|rm)
59
111
  # Complete with settings profile names
@@ -87,7 +139,8 @@ _ccs_completion() {
87
139
  return 0
88
140
  ;;
89
141
  create)
90
- # No completion for create (user enters new name)
142
+ # Complete with create flags
143
+ COMPREPLY=( $(compgen -W "--force" -- ${cur}) )
91
144
  return 0
92
145
  ;;
93
146
  list)
@@ -104,8 +157,14 @@ _ccs_completion() {
104
157
  return 0
105
158
  fi
106
159
 
160
+ # Flags for update command
161
+ if [[ ${COMP_WORDS[1]} == "update" ]]; then
162
+ COMPREPLY=( $(compgen -W "--force --beta --dev --help -h" -- ${cur}) )
163
+ return 0
164
+ fi
165
+
107
166
  # Flags for shell-completion command
108
- if [[ ${prev} == "--shell-completion" ]]; then
167
+ if [[ ${prev} == "--shell-completion" || ${prev} == "-sc" ]]; then
109
168
  COMPREPLY=( $(compgen -W "--bash --zsh --fish --powershell" -- ${cur}) )
110
169
  return 0
111
170
  fi