code-squad-cli 1.2.3 → 1.2.4

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.
@@ -2,42 +2,130 @@ import { Router } from 'express';
2
2
  import fs from 'fs';
3
3
  import path from 'path';
4
4
  const router = Router();
5
+ // Extension to language mapping
6
+ const extensionMap = {
7
+ // JavaScript/TypeScript
8
+ js: 'javascript',
9
+ mjs: 'javascript',
10
+ cjs: 'javascript',
11
+ ts: 'typescript',
12
+ mts: 'typescript',
13
+ cts: 'typescript',
14
+ tsx: 'tsx',
15
+ jsx: 'jsx',
16
+ // Systems languages
17
+ rs: 'rust',
18
+ go: 'go',
19
+ c: 'c',
20
+ cpp: 'cpp',
21
+ cc: 'cpp',
22
+ cxx: 'cpp',
23
+ h: 'cpp',
24
+ hpp: 'cpp',
25
+ hxx: 'cpp',
26
+ // JVM languages
27
+ java: 'java',
28
+ kt: 'kotlin',
29
+ kts: 'kotlin',
30
+ scala: 'scala',
31
+ groovy: 'groovy',
32
+ // Scripting languages
33
+ py: 'python',
34
+ rb: 'ruby',
35
+ php: 'php',
36
+ pl: 'perl',
37
+ lua: 'lua',
38
+ // Mobile
39
+ swift: 'swift',
40
+ m: 'objective-c',
41
+ mm: 'objective-cpp',
42
+ dart: 'dart',
43
+ // Web
44
+ html: 'html',
45
+ htm: 'html',
46
+ css: 'css',
47
+ scss: 'scss',
48
+ sass: 'sass',
49
+ less: 'less',
50
+ vue: 'vue',
51
+ svelte: 'svelte',
52
+ astro: 'astro',
53
+ // Data formats
54
+ json: 'json',
55
+ jsonc: 'jsonc',
56
+ yaml: 'yaml',
57
+ yml: 'yaml',
58
+ toml: 'toml',
59
+ xml: 'xml',
60
+ csv: 'csv',
61
+ // Documentation
62
+ md: 'markdown',
63
+ mdx: 'mdx',
64
+ rst: 'rst',
65
+ tex: 'latex',
66
+ // Shell
67
+ sh: 'bash',
68
+ bash: 'bash',
69
+ zsh: 'bash',
70
+ fish: 'fish',
71
+ ps1: 'powershell',
72
+ bat: 'batch',
73
+ cmd: 'batch',
74
+ // Database
75
+ sql: 'sql',
76
+ prisma: 'prisma',
77
+ graphql: 'graphql',
78
+ gql: 'graphql',
79
+ // Config
80
+ ini: 'ini',
81
+ conf: 'ini',
82
+ cfg: 'ini',
83
+ env: 'dotenv',
84
+ // Other
85
+ dockerfile: 'dockerfile',
86
+ makefile: 'makefile',
87
+ cmake: 'cmake',
88
+ diff: 'diff',
89
+ patch: 'diff',
90
+ };
91
+ // Filename to language mapping (for files without extensions)
92
+ const filenameMap = {
93
+ 'Makefile': 'makefile',
94
+ 'makefile': 'makefile',
95
+ 'GNUmakefile': 'makefile',
96
+ 'Dockerfile': 'dockerfile',
97
+ 'dockerfile': 'dockerfile',
98
+ 'Containerfile': 'dockerfile',
99
+ 'Jenkinsfile': 'groovy',
100
+ 'Vagrantfile': 'ruby',
101
+ 'Gemfile': 'ruby',
102
+ 'Rakefile': 'ruby',
103
+ 'Brewfile': 'ruby',
104
+ 'Podfile': 'ruby',
105
+ 'Fastfile': 'ruby',
106
+ 'Guardfile': 'ruby',
107
+ '.gitignore': 'gitignore',
108
+ '.gitattributes': 'gitattributes',
109
+ '.editorconfig': 'editorconfig',
110
+ '.bashrc': 'bash',
111
+ '.zshrc': 'bash',
112
+ '.bash_profile': 'bash',
113
+ '.profile': 'bash',
114
+ 'CMakeLists.txt': 'cmake',
115
+ 'CODEOWNERS': 'gitignore',
116
+ };
5
117
  function detectLanguage(filePath) {
118
+ const basename = path.basename(filePath);
119
+ // Check filename first (for files like Makefile, Dockerfile)
120
+ if (filenameMap[basename]) {
121
+ return filenameMap[basename];
122
+ }
123
+ // Then check extension
6
124
  const ext = path.extname(filePath).slice(1).toLowerCase();
7
- const languageMap = {
8
- rs: 'rust',
9
- js: 'javascript',
10
- ts: 'typescript',
11
- tsx: 'tsx',
12
- jsx: 'jsx',
13
- py: 'python',
14
- go: 'go',
15
- java: 'java',
16
- c: 'c',
17
- cpp: 'cpp',
18
- cc: 'cpp',
19
- cxx: 'cpp',
20
- h: 'cpp',
21
- hpp: 'cpp',
22
- md: 'markdown',
23
- json: 'json',
24
- yaml: 'yaml',
25
- yml: 'yaml',
26
- toml: 'toml',
27
- html: 'html',
28
- css: 'css',
29
- scss: 'scss',
30
- sh: 'bash',
31
- bash: 'bash',
32
- sql: 'sql',
33
- rb: 'ruby',
34
- swift: 'swift',
35
- kt: 'kotlin',
36
- kts: 'kotlin',
37
- xml: 'xml',
38
- vue: 'vue',
39
- };
40
- return languageMap[ext] || 'plaintext';
125
+ if (extensionMap[ext]) {
126
+ return extensionMap[ext];
127
+ }
128
+ return 'text';
41
129
  }
42
130
  // GET /api/file?path=<path>
43
131
  router.get('/', (req, res) => {
@@ -24,9 +24,36 @@ const DEFAULT_IGNORES = [
24
24
  'yarn.lock',
25
25
  '.DS_Store',
26
26
  ];
27
+ // Dotfiles that should be visible in the file tree
28
+ const VISIBLE_DOTFILES = new Set([
29
+ '.gitignore',
30
+ '.gitattributes',
31
+ '.env.example',
32
+ '.env.local.example',
33
+ '.eslintrc',
34
+ '.eslintrc.js',
35
+ '.eslintrc.cjs',
36
+ '.eslintrc.json',
37
+ '.eslintrc.yml',
38
+ '.prettierrc',
39
+ '.prettierrc.js',
40
+ '.prettierrc.cjs',
41
+ '.prettierrc.json',
42
+ '.prettierrc.yml',
43
+ '.editorconfig',
44
+ '.npmrc',
45
+ '.nvmrc',
46
+ '.node-version',
47
+ '.dockerignore',
48
+ '.browserslistrc',
49
+ '.babelrc',
50
+ '.babelrc.js',
51
+ '.babelrc.json',
52
+ ]);
27
53
  function shouldIgnore(name) {
28
- if (name.startsWith('.') && name !== '.gitignore' && name !== '.env.example') {
29
- return true;
54
+ if (name.startsWith('.')) {
55
+ // Allow specific dotfiles
56
+ return !VISIBLE_DOTFILES.has(name);
30
57
  }
31
58
  return DEFAULT_IGNORES.includes(name);
32
59
  }
@@ -0,0 +1 @@
1
+ *{box-sizing:border-box;margin:0;padding:0}:root{--bg-primary: #0d1117;--bg-secondary: #161b22;--bg-tertiary: #21262d;--bg-hover: #30363d;--bg-selected: #1f6feb26;--text-primary: #e6edf3;--text-secondary: #8b949e;--text-muted: #6e7681;--border-color: #30363d;--border-subtle: #21262d;--accent-primary: #238636;--accent-primary-hover: #2ea043;--accent-secondary: #1f6feb;--git-modified: #d29922;--git-untracked: #3fb950;--git-deleted: #f85149;--git-added: #3fb950;--line-number-color: #6e7681;--selection-bg: #264f78;--diff-add-bg: rgba(46, 160, 67, .15);--diff-add-text: #7ee787;--diff-add-border: rgba(46, 160, 67, .4);--diff-delete-bg: rgba(248, 81, 73, .15);--diff-delete-text: #ffa198;--diff-delete-border: rgba(248, 81, 73, .4);--diff-hunk-bg: rgba(56, 139, 253, .1);--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif;--font-mono: "SF Mono", "Menlo", "Monaco", "Consolas", monospace;--space-1: 4px;--space-2: 8px;--space-3: 12px;--space-4: 16px;--space-5: 24px;--transition-fast: .15s ease;--transition-normal: .2s ease}body{font-family:var(--font-sans);font-size:14px;background-color:var(--bg-primary);color:var(--text-primary);height:100vh;overflow:hidden}#root{height:100%}.app{display:flex;flex-direction:column;height:100%}.main-content{display:flex;flex:1;overflow:hidden}.toolbar{display:flex;align-items:center;justify-content:space-between;height:40px;padding:0 var(--space-3);background-color:var(--bg-secondary);border-bottom:1px solid var(--border-subtle)}.toolbar-left,.toolbar-center,.toolbar-right{display:flex;align-items:center;gap:var(--space-2)}.toolbar-btn{display:flex;align-items:center;justify-content:center;gap:var(--space-1);height:28px;padding:0 var(--space-2);border:none;background:transparent;border-radius:6px;color:var(--text-secondary);cursor:pointer;transition:all var(--transition-fast)}.toolbar-btn:hover{background-color:var(--bg-hover);color:var(--text-primary)}.toolbar-btn.active{background-color:var(--bg-tertiary);color:var(--text-primary)}.toolbar-btn svg{flex-shrink:0}.diff-toggle{min-width:100px}.diff-mode-label{font-size:12px}.sidebar{width:280px;background-color:var(--bg-secondary);border-right:1px solid var(--border-subtle);overflow:hidden;display:flex;flex-direction:column;transition:width var(--transition-normal),opacity var(--transition-fast)}.sidebar.collapsed{width:0;opacity:0;border-right:none}.content{flex:1;overflow:hidden;display:flex;flex-direction:column;min-width:0}.staging-panel{width:320px;background-color:var(--bg-secondary);border-left:1px solid var(--border-subtle);overflow:hidden;display:flex;flex-direction:column;transition:width var(--transition-normal),opacity var(--transition-fast)}.staging-panel.collapsed{width:0;opacity:0;border-left:none}.footer{display:flex;align-items:center;justify-content:space-between;padding:var(--space-2) var(--space-4);background-color:var(--bg-secondary);border-top:1px solid var(--border-subtle);gap:var(--space-4)}.footer-actions{display:flex;gap:var(--space-2)}.file-tree{display:flex;flex-direction:column;height:100%}.file-tree-header{display:flex;align-items:center;justify-content:space-between;padding:var(--space-3) var(--space-4);font-weight:600;font-size:11px;text-transform:uppercase;letter-spacing:.5px;color:var(--text-secondary);border-bottom:1px solid var(--border-subtle)}.file-tree-header-actions{display:flex;gap:var(--space-1)}.filter-btn{display:flex;align-items:center;gap:var(--space-1);padding:2px 8px;border:none;background:transparent;border-radius:4px;color:var(--text-muted);font-size:10px;font-weight:600;cursor:pointer;transition:all var(--transition-fast)}.filter-btn:hover{background-color:var(--bg-hover);color:var(--text-secondary)}.filter-btn.active{background-color:var(--accent-secondary);color:#fff}.filter-btn .count{background-color:var(--bg-hover);padding:0 4px;border-radius:3px;font-size:9px}.filter-btn.active .count{background-color:#fff3}.file-tree-content{flex:1;overflow-y:auto;padding:var(--space-1) 0}.tree-item{display:flex;align-items:center;padding:var(--space-1) var(--space-2);cursor:pointer;-webkit-user-select:none;user-select:none;gap:6px}.tree-item:hover{background-color:var(--bg-hover)}.tree-icon{display:flex;align-items:center;justify-content:center;width:14px;color:var(--text-secondary);flex-shrink:0}.tree-folder-icon{display:flex;align-items:center;justify-content:center;width:14px;color:var(--git-modified);flex-shrink:0}.tree-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.git-badge{font-size:10px;font-weight:600;padding:1px 4px;border-radius:3px}.git-badge-modified{color:var(--git-modified);background-color:#d2992226}.git-badge-untracked{color:var(--git-untracked);background-color:#3fb95026}.git-badge-deleted{color:var(--git-deleted);background-color:#f8514926}.git-badge-added{color:var(--git-added);background-color:#3fb95026}.code-viewer{display:flex;flex-direction:column;height:100%;overflow:hidden}.code-viewer-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;color:var(--text-secondary);gap:var(--space-3)}.code-viewer-empty .hint{display:flex;align-items:center;gap:var(--space-1);font-size:12px;color:var(--text-muted)}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:var(--space-5);gap:var(--space-3)}.empty-state-icon{color:var(--text-muted);opacity:.5}.code-viewer-header{display:flex;align-items:center;justify-content:space-between;padding:var(--space-2) var(--space-4);background-color:var(--bg-secondary);border-bottom:1px solid var(--border-subtle)}.file-path{font-size:13px;font-family:var(--font-mono)}.file-language{font-size:11px;color:var(--text-secondary);text-transform:uppercase}.code-viewer-content{flex:1;overflow:auto;font-family:var(--font-mono);font-size:13px;line-height:1.5}.code-line{display:flex;min-height:20px;cursor:pointer}.code-line:hover{background-color:var(--bg-hover)}.code-line-selected{background-color:var(--selection-bg)!important}.code-line-added{background-color:var(--diff-add-bg)!important}.code-line-added:hover{background-color:#2ea04340!important}.code-line-deleted{background-color:var(--diff-delete-bg)!important}.code-line-deleted:hover{background-color:#f8514940!important}.line-number{display:inline-block;min-width:50px;padding:0 var(--space-3);text-align:right;color:var(--line-number-color);-webkit-user-select:none;user-select:none;background-color:var(--bg-tertiary);border-right:1px solid var(--border-subtle)}.code-line code{flex:1;padding:0 var(--space-3);white-space:pre;background:transparent}.code-line code.hljs{background:transparent;padding:0 var(--space-3)}.code-content{flex:1;padding:0 var(--space-3);white-space:pre}.staging-list{display:flex;flex-direction:column;height:100%}.staging-list-empty{padding:var(--space-4)}.staging-header{display:flex;align-items:center;justify-content:space-between;padding:var(--space-3) var(--space-4);font-weight:600;font-size:11px;text-transform:uppercase;letter-spacing:.5px;color:var(--text-secondary);border-bottom:1px solid var(--border-subtle)}.staging-hint{font-size:12px;color:var(--text-muted);line-height:1.5}.staging-items{flex:1;overflow-y:auto;padding:var(--space-2)}.staging-item{background-color:var(--bg-tertiary);border-radius:6px;padding:var(--space-2) var(--space-3);margin-bottom:var(--space-2)}.staging-item-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--space-1)}.staging-location{font-family:var(--font-mono);font-size:12px;color:var(--text-secondary)}.staging-comment{font-size:13px;line-height:1.4}.comment-input{display:flex;align-items:center;gap:var(--space-3);flex:1}.comment-selection{font-family:var(--font-mono);font-size:12px;color:var(--accent-secondary);white-space:nowrap}.comment-field{flex:1;padding:var(--space-2) var(--space-3);background-color:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:6px;color:var(--text-primary);font-size:14px;transition:border-color var(--transition-fast)}.comment-field:focus{outline:none;border-color:var(--accent-secondary)}.comment-hint{color:var(--text-muted);font-size:13px}.fuzzy-finder-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background-color:#0009;display:flex;justify-content:center;padding-top:80px;z-index:100}.fuzzy-finder{background-color:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px;box-shadow:0 16px 48px #00000080;width:600px;max-height:400px;display:flex;flex-direction:column;overflow:hidden}.fuzzy-finder-input{padding:var(--space-4);background-color:var(--bg-tertiary);border:none;border-bottom:1px solid var(--border-subtle);color:var(--text-primary);font-size:16px}.fuzzy-finder-input:focus{outline:none}.fuzzy-finder-results{flex:1;overflow-y:auto}.fuzzy-finder-item{padding:var(--space-3) var(--space-4);cursor:pointer;font-family:var(--font-mono);font-size:13px}.fuzzy-finder-item:hover,.fuzzy-finder-item-selected{background-color:var(--bg-selected)}.fuzzy-finder-empty{padding:var(--space-4);color:var(--text-muted);text-align:center}.btn{padding:var(--space-2) var(--space-4);border:none;border-radius:6px;font-size:13px;font-weight:500;cursor:pointer;transition:background-color var(--transition-fast)}.btn:disabled{opacity:.5;cursor:not-allowed}.btn-primary{background-color:var(--accent-primary);color:#fff}.btn-primary:hover:not(:disabled){background-color:var(--accent-primary-hover)}.btn-secondary{background-color:var(--bg-tertiary);color:var(--text-primary)}.btn-secondary:hover:not(:disabled){background-color:var(--bg-hover)}.btn-small{padding:var(--space-1) var(--space-3)}.btn-link{background:none;border:none;color:var(--accent-secondary);cursor:pointer;font-size:11px}.btn-link:hover{text-decoration:underline}.btn-icon{background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:14px;padding:2px 6px}.btn-icon:hover{color:var(--text-primary)}.diff-side-by-side{display:flex;height:100%;overflow:hidden}.diff-pane{flex:1;overflow:auto;font-family:var(--font-mono);font-size:13px;line-height:1.5}.diff-pane-left{border-right:1px solid var(--border-color)}.diff-pane-header{padding:var(--space-2) var(--space-3);background-color:var(--bg-tertiary);border-bottom:1px solid var(--border-subtle);font-size:11px;color:var(--text-secondary);text-transform:uppercase;letter-spacing:.5px}.code-viewer-loading{display:flex;align-items:center;justify-content:center;height:100%;color:var(--text-muted)}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--bg-hover);border-radius:4px}::-webkit-scrollbar-thumb:hover{background:#484f58}::-webkit-scrollbar-corner{background:transparent}