bingocode 1.1.46 → 1.1.51

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bingocode",
3
- "version": "1.1.46",
3
+ "version": "1.1.51",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "claude": "bin/claude-win.cjs",
@@ -20,10 +20,14 @@
20
20
  "files": [
21
21
  "bin/",
22
22
  "src/",
23
+ "scripts/",
24
+ "stubs/",
23
25
  "config/",
24
- ".claude/",
25
26
  "preload.ts",
26
27
  "package.json",
28
+ "package-lock.json",
29
+ ".env.example",
30
+ "tsconfig.json",
27
31
  "README.md",
28
32
  "bun.lock",
29
33
  "bunfig.toml"
@@ -0,0 +1,256 @@
1
+ import { readdirSync, readFileSync, statSync } from 'node:fs'
2
+ import { extname, join, relative, sep } from 'node:path'
3
+
4
+ type Bucket = {
5
+ files: number
6
+ lines: number
7
+ nonBlankLines: number
8
+ }
9
+
10
+ type FileStat = Bucket & {
11
+ path: string
12
+ extension: string
13
+ }
14
+
15
+ const root = process.cwd()
16
+
17
+ const targetRoots = ['adapters', 'desktop', 'runtime', 'src/server']
18
+
19
+ const codeExtensions = new Set([
20
+ '.css',
21
+ '.cjs',
22
+ '.html',
23
+ '.js',
24
+ '.jsx',
25
+ '.mjs',
26
+ '.nsh',
27
+ '.ps1',
28
+ '.py',
29
+ '.rs',
30
+ '.sh',
31
+ '.ts',
32
+ '.tsx',
33
+ ])
34
+
35
+ const excludedDirectoryNames = new Set([
36
+ '.cache',
37
+ '.git',
38
+ '.next',
39
+ '.nuxt',
40
+ '.omx',
41
+ '.parcel-cache',
42
+ '.svelte-kit',
43
+ '.tauri',
44
+ '.turbo',
45
+ '.vite',
46
+ '.vite-temp',
47
+ '__pycache__',
48
+ 'build',
49
+ 'build-artifacts',
50
+ 'coverage',
51
+ 'dist',
52
+ 'node_modules',
53
+ 'out',
54
+ 'target',
55
+ ])
56
+
57
+ const excludedRelativePaths = new Set([
58
+ 'desktop/src-tauri/binaries',
59
+ 'desktop/src-tauri/icons',
60
+ ])
61
+
62
+ const files: FileStat[] = []
63
+
64
+ function emptyBucket(): Bucket {
65
+ return {
66
+ files: 0,
67
+ lines: 0,
68
+ nonBlankLines: 0,
69
+ }
70
+ }
71
+
72
+ function addToBucket(bucket: Bucket, file: FileStat) {
73
+ bucket.files += file.files
74
+ bucket.lines += file.lines
75
+ bucket.nonBlankLines += file.nonBlankLines
76
+ }
77
+
78
+ function shouldSkipDirectory(path: string) {
79
+ const name = path.split(sep).at(-1)
80
+ const normalized = relative(root, path).split(sep).join('/')
81
+
82
+ return (
83
+ Boolean(name && excludedDirectoryNames.has(name)) ||
84
+ excludedRelativePaths.has(normalized)
85
+ )
86
+ }
87
+
88
+ function countFile(path: string): FileStat | null {
89
+ const extension = extname(path)
90
+
91
+ if (!codeExtensions.has(extension)) {
92
+ return null
93
+ }
94
+
95
+ const content = readFileSync(path, 'utf8')
96
+ const newlineCount = content.match(/\r\n|\r|\n/g)?.length ?? 0
97
+ const lines =
98
+ content.length === 0 || content.endsWith('\n') || content.endsWith('\r')
99
+ ? newlineCount
100
+ : newlineCount + 1
101
+ const nonBlankLines = content
102
+ .split(/\r\n|\r|\n/)
103
+ .filter((line) => line.trim().length > 0).length
104
+
105
+ return {
106
+ files: 1,
107
+ lines,
108
+ nonBlankLines,
109
+ path: relative(root, path).split(sep).join('/'),
110
+ extension,
111
+ }
112
+ }
113
+
114
+ function walk(path: string) {
115
+ const stat = statSync(path)
116
+
117
+ if (stat.isDirectory()) {
118
+ if (shouldSkipDirectory(path)) {
119
+ return
120
+ }
121
+
122
+ for (const entry of readdirSync(path)) {
123
+ walk(join(path, entry))
124
+ }
125
+
126
+ return
127
+ }
128
+
129
+ if (!stat.isFile()) {
130
+ return
131
+ }
132
+
133
+ const result = countFile(path)
134
+ if (result) {
135
+ files.push(result)
136
+ }
137
+ }
138
+
139
+ function formatNumber(value: number) {
140
+ return value.toLocaleString('en-US')
141
+ }
142
+
143
+ function printTable(
144
+ title: string,
145
+ rows: Array<{ name: string } & Bucket>,
146
+ nameHeader = 'Group',
147
+ ) {
148
+ console.log(`\n${title}`)
149
+ console.log(`${nameHeader.padEnd(28)} ${'Files'.padStart(7)} ${'Lines'.padStart(9)} ${'Nonblank'.padStart(9)}`)
150
+ console.log(`${'-'.repeat(28)} ${'-'.repeat(7)} ${'-'.repeat(9)} ${'-'.repeat(9)}`)
151
+
152
+ for (const row of rows) {
153
+ console.log(
154
+ `${row.name.padEnd(28)} ${formatNumber(row.files).padStart(7)} ${formatNumber(row.lines).padStart(9)} ${formatNumber(row.nonBlankLines).padStart(9)}`,
155
+ )
156
+ }
157
+ }
158
+
159
+ function groupBy<T extends string>(getKey: (file: FileStat) => T) {
160
+ const result = new Map<T, Bucket>()
161
+
162
+ for (const file of files) {
163
+ const key = getKey(file)
164
+ const bucket = result.get(key) ?? emptyBucket()
165
+ addToBucket(bucket, file)
166
+ result.set(key, bucket)
167
+ }
168
+
169
+ return [...result.entries()]
170
+ .map(([name, bucket]) => ({ name, ...bucket }))
171
+ .sort((left, right) => right.lines - left.lines)
172
+ }
173
+
174
+ function areaForPath(path: string) {
175
+ if (path.startsWith('src/server/')) {
176
+ return 'server'
177
+ }
178
+
179
+ if (path.startsWith('desktop/src/')) {
180
+ return 'desktop frontend'
181
+ }
182
+
183
+ if (path.startsWith('desktop/src-tauri/')) {
184
+ return 'desktop tauri'
185
+ }
186
+
187
+ if (path.startsWith('desktop/')) {
188
+ return 'desktop support'
189
+ }
190
+
191
+ if (path.startsWith('adapters/')) {
192
+ return 'adapters'
193
+ }
194
+
195
+ if (path.startsWith('runtime/')) {
196
+ return 'runtime'
197
+ }
198
+
199
+ return 'other'
200
+ }
201
+
202
+ function purposeForPath(path: string) {
203
+ const fileName = path.split('/').at(-1) ?? ''
204
+
205
+ if (
206
+ path.includes('/__tests__/') ||
207
+ path.includes('/fixtures/') ||
208
+ fileName.startsWith('test_') ||
209
+ /\.test\.[cm]?[jt]sx?$/.test(path) ||
210
+ /\.spec\.[cm]?[jt]sx?$/.test(path)
211
+ ) {
212
+ return 'tests and fixtures'
213
+ }
214
+
215
+ return 'product source'
216
+ }
217
+
218
+ for (const targetRoot of targetRoots) {
219
+ walk(join(root, targetRoot))
220
+ }
221
+
222
+ const total = emptyBucket()
223
+ for (const file of files) {
224
+ addToBucket(total, file)
225
+ }
226
+
227
+ const sortedByPath = [...files].sort((left, right) =>
228
+ left.path.localeCompare(right.path),
229
+ )
230
+
231
+ console.log('Desktop app source line count')
232
+ console.log('')
233
+ console.log(`Targets: ${targetRoots.join(', ')}`)
234
+ console.log(`Included extensions: ${[...codeExtensions].sort().join(', ')}`)
235
+ console.log(
236
+ `Excluded directories: ${[...excludedDirectoryNames].sort().join(', ')}`,
237
+ )
238
+ console.log(`Excluded paths: ${[...excludedRelativePaths].sort().join(', ')}`)
239
+
240
+ printTable('By area', groupBy((file) => areaForPath(file.path)))
241
+ printTable('By purpose', groupBy((file) => purposeForPath(file.path)))
242
+ printTable('By top-level target', groupBy((file) => file.path.split('/')[0]))
243
+ printTable('By extension', groupBy((file) => file.extension), 'Extension')
244
+
245
+ console.log('\nTotal')
246
+ console.log(`Files: ${formatNumber(total.files)}`)
247
+ console.log(`Lines: ${formatNumber(total.lines)}`)
248
+ console.log(`Nonblank lines: ${formatNumber(total.nonBlankLines)}`)
249
+
250
+ if (process.argv.includes('--files')) {
251
+ printTable(
252
+ 'By file',
253
+ sortedByPath.map((file) => ({ name: file.path, ...file })),
254
+ 'File',
255
+ )
256
+ }
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Release script for Claude Code Haha Desktop
4
+ *
5
+ * Usage:
6
+ * bun run scripts/release.ts patch # 0.1.0 → 0.1.1
7
+ * bun run scripts/release.ts minor # 0.1.0 → 0.2.0
8
+ * bun run scripts/release.ts major # 0.1.0 → 1.0.0
9
+ * bun run scripts/release.ts 2.0.0 # explicit version
10
+ * bun run scripts/release.ts patch --dry # preview without changes
11
+ */
12
+
13
+ import { readFileSync, writeFileSync } from 'node:fs'
14
+ import path from 'node:path'
15
+
16
+ const root = path.resolve(import.meta.dir, '..')
17
+
18
+ const VERSION_FILES = [
19
+ {
20
+ path: path.join(root, 'desktop/package.json'),
21
+ update(content: string, version: string) {
22
+ return content.replace(/"version":\s*"[^"]*"/, `"version": "${version}"`)
23
+ },
24
+ },
25
+ {
26
+ path: path.join(root, 'desktop/src-tauri/tauri.conf.json'),
27
+ update(content: string, version: string) {
28
+ return content.replace(/"version":\s*"[^"]*"/, `"version": "${version}"`)
29
+ },
30
+ },
31
+ {
32
+ path: path.join(root, 'desktop/src-tauri/Cargo.toml'),
33
+ update(content: string, version: string) {
34
+ return content.replace(/^version\s*=\s*"[^"]*"/m, `version = "${version}"`)
35
+ },
36
+ },
37
+ ]
38
+
39
+ function getCurrentVersion(): string {
40
+ const tauriConf = JSON.parse(
41
+ readFileSync(path.join(root, 'desktop/src-tauri/tauri.conf.json'), 'utf-8'),
42
+ )
43
+ return tauriConf.version
44
+ }
45
+
46
+ function bumpVersion(current: string, bump: string): string {
47
+ if (/^\d+\.\d+\.\d+$/.test(bump)) {
48
+ return bump
49
+ }
50
+
51
+ const [major, minor, patch] = current.split('.').map(Number)
52
+
53
+ switch (bump) {
54
+ case 'patch':
55
+ return `${major}.${minor}.${patch + 1}`
56
+ case 'minor':
57
+ return `${major}.${minor + 1}.0`
58
+ case 'major':
59
+ return `${major + 1}.0.0`
60
+ default:
61
+ console.error(`Invalid bump type: ${bump}`)
62
+ console.error('Usage: bun run scripts/release.ts <patch|minor|major|x.y.z> [--dry]')
63
+ process.exit(1)
64
+ }
65
+ }
66
+
67
+ async function run(cmd: string[], cwd = root) {
68
+ const proc = Bun.spawn(cmd, { cwd, stdout: 'pipe', stderr: 'pipe' })
69
+ const stdout = await new Response(proc.stdout).text()
70
+ const stderr = await new Response(proc.stderr).text()
71
+ const code = await proc.exited
72
+ if (code !== 0) {
73
+ throw new Error(`Command failed: ${cmd.join(' ')}\n${stderr || stdout}`)
74
+ }
75
+ return stdout.trim()
76
+ }
77
+
78
+ // ── Main ──────────────────────────────────────────────
79
+
80
+ const args = process.argv.slice(2)
81
+ const dryRun = args.includes('--dry')
82
+ const bumpArg = args.find((a) => a !== '--dry')
83
+
84
+ if (!bumpArg) {
85
+ console.error('Usage: bun run scripts/release.ts <patch|minor|major|x.y.z> [--dry]')
86
+ process.exit(1)
87
+ }
88
+
89
+ const current = getCurrentVersion()
90
+ const next = bumpVersion(current, bumpArg)
91
+
92
+ console.log(`\n Version: ${current} → ${next}`)
93
+ console.log(` Tag: v${next}`)
94
+ console.log(` Dry run: ${dryRun}\n`)
95
+
96
+ if (dryRun) {
97
+ console.log('Files that would be updated:')
98
+ for (const file of VERSION_FILES) {
99
+ console.log(` - ${path.relative(root, file.path)}`)
100
+ }
101
+ process.exit(0)
102
+ }
103
+
104
+ // Update version in all files
105
+ for (const file of VERSION_FILES) {
106
+ const content = readFileSync(file.path, 'utf-8')
107
+ const updated = file.update(content, next)
108
+ writeFileSync(file.path, updated)
109
+ console.log(` Updated: ${path.relative(root, file.path)}`)
110
+ }
111
+
112
+ // Regenerate Cargo.lock
113
+ console.log('\n Updating Cargo.lock...')
114
+ await run(['cargo', 'generate-lockfile'], path.join(root, 'desktop/src-tauri'))
115
+
116
+ // Git commit + tag
117
+ console.log(' Creating git commit...')
118
+ await run([
119
+ 'git',
120
+ 'add',
121
+ 'desktop/package.json',
122
+ 'desktop/src-tauri/tauri.conf.json',
123
+ 'desktop/src-tauri/Cargo.toml',
124
+ 'desktop/src-tauri/Cargo.lock',
125
+ ])
126
+ await run(['git', 'commit', '-m', `release: v${next}`])
127
+ await run(['git', 'tag', '-a', `v${next}`, '-m', `Release v${next}`])
128
+
129
+ console.log(`\n Done! Created commit and tag v${next}`)
130
+ console.log(`\n To trigger the build:\n git push origin main --tags\n`)
@@ -0,0 +1,24 @@
1
+ export type PermissionMode =
2
+ | 'ask'
3
+ | 'skip_all_permission_checks'
4
+ | 'follow_a_plan';
5
+
6
+ export type Logger = {
7
+ silly?: (...args: unknown[]) => void;
8
+ debug?: (...args: unknown[]) => void;
9
+ info?: (...args: unknown[]) => void;
10
+ warn?: (...args: unknown[]) => void;
11
+ error?: (...args: unknown[]) => void;
12
+ };
13
+
14
+ export type ClaudeForChromeContext = Record<string, unknown>;
15
+
16
+ export const BROWSER_TOOLS: Array<{ name: string }> = [];
17
+
18
+ export function createClaudeForChromeMcpServer(
19
+ _context: ClaudeForChromeContext,
20
+ ) {
21
+ return {
22
+ async connect(_transport: unknown): Promise<void> {},
23
+ };
24
+ }
@@ -0,0 +1,45 @@
1
+ export type SyntaxTheme = {
2
+ theme: string;
3
+ source: string | null;
4
+ };
5
+
6
+ export class ColorDiff {
7
+ private hunk: { oldStart: number; oldLines: number; newStart: number; newLines: number; lines: string[] };
8
+ private filePath: string;
9
+ private firstLine: string | null;
10
+ private prefixContent: string | null;
11
+
12
+ constructor(
13
+ hunk: { oldStart: number; oldLines: number; newStart: number; newLines: number; lines: string[] },
14
+ firstLine: string | null,
15
+ filePath: string,
16
+ prefixContent?: string | null,
17
+ ) {
18
+ this.hunk = hunk;
19
+ this.filePath = filePath;
20
+ this.firstLine = firstLine;
21
+ this.prefixContent = prefixContent ?? null;
22
+ }
23
+
24
+ render(themeName: string, width: number, dim: boolean): string[] | null {
25
+ return null;
26
+ }
27
+ }
28
+
29
+ export class ColorFile {
30
+ private code: string;
31
+ private filePath: string;
32
+
33
+ constructor(code: string, filePath: string) {
34
+ this.code = code;
35
+ this.filePath = filePath;
36
+ }
37
+
38
+ render(themeName: string, width: number, dim: boolean): string[] | null {
39
+ return null;
40
+ }
41
+ }
42
+
43
+ export function getSyntaxTheme(themeName: string): SyntaxTheme {
44
+ return { theme: themeName, source: null };
45
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "allowJs": true,
7
+ "jsx": "react-jsx",
8
+ "baseUrl": ".",
9
+ "paths": {
10
+ "@ant/claude-for-chrome-mcp": [
11
+ "./stubs/ant-claude-for-chrome-mcp.ts"
12
+ ],
13
+ "color-diff-napi": [
14
+ "./stubs/color-diff-napi.ts"
15
+ ],
16
+ "src/*": [
17
+ "./src/*"
18
+ ]
19
+ },
20
+ "types": [
21
+ "bun-types"
22
+ ]
23
+ }
24
+ }
@@ -1,48 +0,0 @@
1
- ---
2
- name: claude-native-adapter
3
- description: 核心协议适配器,强制 LLM 模仿 Claude Code 的原生输出结构、工具调用逻辑和极致简练的沟通风格。
4
- user-invocable: true
5
- ---
6
-
7
- # Claude Native Protocol v7.0 (Core Adapter)
8
-
9
- 当你(LLM)作为 Claude Code 的引擎运行时,必须严格遵守以下协议。这不仅是风格问题,更是确保工具调用(Tool Use)成功的技术要求。
10
-
11
- ## 1. 响应结构 (The Structure)
12
-
13
- **严禁**任何开场白(如 "Sure", "I can help with that")或结尾总结。你的输出应直接进入分析或行动。
14
-
15
- **标准的输出流程:**
16
- 1. `<thought>`: 内部推理。分析用户意图,规划工具链调用。
17
- 2. `[Tool Calls]`: 发送工具调用命令。
18
- 3. `[Text Response]`: 仅在工具执行完毕、报错或需要询问用户时,输出极简的文字。
19
-
20
- ## 2. 工具调用规范 (Tool Execution)
21
-
22
- - **原子性**:除非任务是并行的,否则优先按逻辑顺序执行工具。
23
- - **参数精度**:
24
- - `Read`: 总是先 Read 再 Edit。
25
- - `Edit`: `old_string` 必须从最近的 `Read` 输出中**完全一致(包括空格、制表符、换行符)**地复制。不要自作聪明修复缩进。
26
- - `Bash`: 涉及路径时务必使用双引号。
27
-
28
- ## 3. 极简主义风格 (Terse Style)
29
-
30
- - **严禁废话**:不要解释你为什么要调用这个工具,除非步骤极其复杂且不直观。
31
- - **引用格式**:提及代码时,始终使用 `file_path:line_number` 格式。
32
- - **状态报告**:如果工具成功且结果直观,不要重复描述结果。
33
-
34
- ## 4. 容错逻辑 (Error Handling)
35
-
36
- - 如果 `Edit` 报错 `old_string` 未找到:
37
- 1. 立即重新 `Read` 该文件。
38
- 2. 对比最新的内容,检查是否有其他进程或之前的工具调用改变了代码。
39
- 3. 重新提取 `old_string`。
40
- - 不要尝试多次重复完全相同的失败命令。
41
-
42
- ## 5. 任务管理 (Task Management)
43
-
44
- - 对于多步骤任务,必须优先调用 `TaskCreate` 创建任务清单。
45
- - 每完成一个关键步骤,立即 `TaskUpdate` 标记 `completed`。这样可以帮助你自己(LLM)维持长程上下文。
46
-
47
- ---
48
- *此协议由 Claude Code 强制执行。一旦激活,你必须表现得像是一个直接嵌入在终端中的高效编译器,而非聊天机器人。*