bingocode 1.0.27 → 1.0.28
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 +1 -2
- package/.github/FUNDING.yml +0 -1
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -44
- package/.github/ISSUE_TEMPLATE/config.yml +0 -1
- package/.github/ISSUE_TEMPLATE/question.md +0 -40
- package/.github/workflows/build-desktop-dev.yml +0 -210
- package/.github/workflows/deploy-docs.yml +0 -59
- package/.github/workflows/release-desktop.yml +0 -162
- package/.spine/user.yaml +0 -5
- package/.spine/workspace.yaml +0 -1
- package/adapters/common/__tests__/chat-queue.test.ts +0 -61
- package/adapters/common/__tests__/format.test.ts +0 -148
- package/adapters/common/__tests__/http-client.test.ts +0 -105
- package/adapters/common/__tests__/message-buffer.test.ts +0 -84
- package/adapters/common/__tests__/message-dedup.test.ts +0 -57
- package/adapters/common/__tests__/session-store.test.ts +0 -62
- package/adapters/common/__tests__/ws-bridge.test.ts +0 -177
- package/adapters/common/attachment/__tests__/attachment-limits.test.ts +0 -52
- package/adapters/common/attachment/__tests__/attachment-store.test.ts +0 -108
- package/adapters/common/attachment/__tests__/image-block-watcher.test.ts +0 -115
- package/adapters/feishu/__tests__/card-errors.test.ts +0 -194
- package/adapters/feishu/__tests__/cardkit.test.ts +0 -295
- package/adapters/feishu/__tests__/extract-payload.test.ts +0 -77
- package/adapters/feishu/__tests__/feishu.test.ts +0 -907
- package/adapters/feishu/__tests__/flush-controller.test.ts +0 -290
- package/adapters/feishu/__tests__/markdown-style.test.ts +0 -353
- package/adapters/feishu/__tests__/media.test.ts +0 -120
- package/adapters/feishu/__tests__/streaming-card.test.ts +0 -914
- package/adapters/telegram/__tests__/media.test.ts +0 -86
- package/adapters/telegram/__tests__/telegram.test.ts +0 -115
- package/adapters/tsconfig.json +0 -18
- package/bunfig.toml +0 -1
- package/preload.ts +0 -30
- package/scripts/count-app-loc.ts +0 -256
- package/scripts/release.ts +0 -130
- package/src/server/__tests__/conversation-service.test.ts +0 -173
- package/src/server/__tests__/conversations.test.ts +0 -458
- package/src/server/__tests__/cron-scheduler.test.ts +0 -575
- package/src/server/__tests__/e2e/business-flow.test.ts +0 -841
- package/src/server/__tests__/e2e/full-flow.test.ts +0 -357
- package/src/server/__tests__/fixtures/mock-sdk-cli.ts +0 -123
- package/src/server/__tests__/haha-oauth-api.test.ts +0 -146
- package/src/server/__tests__/haha-oauth-service.test.ts +0 -185
- package/src/server/__tests__/providers-real.test.ts +0 -244
- package/src/server/__tests__/providers.test.ts +0 -579
- package/src/server/__tests__/proxy-streaming.test.ts +0 -317
- package/src/server/__tests__/proxy-transform.test.ts +0 -469
- package/src/server/__tests__/real-llm-test.ts +0 -526
- package/src/server/__tests__/scheduled-tasks.test.ts +0 -371
- package/src/server/__tests__/sessions.test.ts +0 -786
- package/src/server/__tests__/settings.test.ts +0 -376
- package/src/server/__tests__/skills.test.ts +0 -125
- package/src/server/__tests__/tasks.test.ts +0 -171
- package/src/server/__tests__/team-watcher.test.ts +0 -400
- package/src/server/__tests__/teams.test.ts +0 -627
- package/src/server/middleware/cors.test.ts +0 -27
- package/src/utils/__tests__/cronFrequency.test.ts +0 -153
- package/src/utils/__tests__/cronTasks.test.ts +0 -204
- package/src/utils/computerUse/permissions.test.ts +0 -44
- package/stubs/ant-claude-for-chrome-mcp.ts +0 -24
- package/stubs/color-diff-napi.ts +0 -45
- package/tsconfig.json +0 -24
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from 'bun:test'
|
|
2
|
-
import {
|
|
3
|
-
frequencyToCron,
|
|
4
|
-
cronToFrequency,
|
|
5
|
-
FREQUENCY_OPTIONS,
|
|
6
|
-
} from '../cronFrequency.js'
|
|
7
|
-
|
|
8
|
-
describe('frequencyToCron', () => {
|
|
9
|
-
test('manual returns empty string', () => {
|
|
10
|
-
expect(frequencyToCron('manual')).toBe('')
|
|
11
|
-
expect(frequencyToCron('manual', '09:00')).toBe('')
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
test('hourly returns minute-only cron', () => {
|
|
15
|
-
expect(frequencyToCron('hourly')).toBe('0 * * * *')
|
|
16
|
-
expect(frequencyToCron('hourly', '15')).toBe('') // malformed: must be HH:MM
|
|
17
|
-
expect(frequencyToCron('hourly', '0 * * * *')).toBe('') // malformed time
|
|
18
|
-
expect(frequencyToCron('hourly', ':15')).toBe('') // malformed
|
|
19
|
-
expect(frequencyToCron('hourly', '00:15')).toBe('15 * * * *')
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
test('daily returns correct cron', () => {
|
|
23
|
-
expect(frequencyToCron('daily', '09:00')).toBe('0 9 * * *')
|
|
24
|
-
expect(frequencyToCron('daily', '14:30')).toBe('30 14 * * *')
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
test('weekdays returns cron with 1-5 dow', () => {
|
|
28
|
-
expect(frequencyToCron('weekdays', '09:00')).toBe('0 9 * * 1-5')
|
|
29
|
-
expect(frequencyToCron('weekdays', '08:30')).toBe('30 8 * * 1-5')
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
test('weekly returns cron with dow=1', () => {
|
|
33
|
-
expect(frequencyToCron('weekly', '09:00')).toBe('0 9 * * 1')
|
|
34
|
-
expect(frequencyToCron('weekly', '17:00')).toBe('0 17 * * 1')
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
test('rejects invalid time formats', () => {
|
|
38
|
-
expect(frequencyToCron('daily', '')).toBe('')
|
|
39
|
-
expect(frequencyToCron('daily', '25:00')).toBe('')
|
|
40
|
-
expect(frequencyToCron('daily', '09:60')).toBe('')
|
|
41
|
-
expect(frequencyToCron('daily', 'abc')).toBe('')
|
|
42
|
-
expect(frequencyToCron('daily', '9')).toBe('')
|
|
43
|
-
expect(frequencyToCron('daily', ':30')).toBe('')
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
test('defaults to 09:00 for missing time', () => {
|
|
47
|
-
expect(frequencyToCron('daily')).toBe('0 9 * * *')
|
|
48
|
-
expect(frequencyToCron('weekdays')).toBe('0 9 * * 1-5')
|
|
49
|
-
expect(frequencyToCron('weekly')).toBe('0 9 * * 1')
|
|
50
|
-
})
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
describe('cronToFrequency', () => {
|
|
54
|
-
test('empty cron returns manual', () => {
|
|
55
|
-
expect(cronToFrequency('')).toEqual({ frequency: 'manual' })
|
|
56
|
-
expect(cronToFrequency(' ')).toEqual({ frequency: 'manual' })
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
test('invalid cron returns manual', () => {
|
|
60
|
-
expect(cronToFrequency('not a cron')).toEqual({ frequency: 'manual' })
|
|
61
|
-
expect(cronToFrequency('*')).toEqual({ frequency: 'manual' })
|
|
62
|
-
expect(cronToFrequency('* *')).toEqual({ frequency: 'manual' })
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
test('hourly pattern detected', () => {
|
|
66
|
-
expect(cronToFrequency('7 * * * *')).toEqual({ frequency: 'hourly' })
|
|
67
|
-
expect(cronToFrequency('0 * * * *')).toEqual({ frequency: 'hourly' })
|
|
68
|
-
expect(cronToFrequency('30 * * * *')).toEqual({ frequency: 'hourly' })
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
test('daily pattern detected', () => {
|
|
72
|
-
expect(cronToFrequency('0 9 * * *')).toEqual({ frequency: 'daily', time: '09:00' })
|
|
73
|
-
expect(cronToFrequency('30 14 * * *')).toEqual({ frequency: 'daily', time: '14:30' })
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
test('weekdays pattern detected', () => {
|
|
77
|
-
expect(cronToFrequency('0 9 * * 1-5')).toEqual({ frequency: 'weekdays', time: '09:00' })
|
|
78
|
-
expect(cronToFrequency('30 8 * * 1-5')).toEqual({ frequency: 'weekdays', time: '08:30' })
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
test('weekly pattern detected', () => {
|
|
82
|
-
expect(cronToFrequency('0 9 * * 1')).toEqual({ frequency: 'weekly', time: '09:00' })
|
|
83
|
-
expect(cronToFrequency('0 17 * * 1')).toEqual({ frequency: 'weekly', time: '17:00' })
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
test('complex crons return manual', () => {
|
|
87
|
-
expect(cronToFrequency('0 9 1-15 * *')).toEqual({ frequency: 'manual' })
|
|
88
|
-
expect(cronToFrequency('0 9 * * 0,6')).toEqual({ frequency: 'manual' })
|
|
89
|
-
expect(cronToFrequency('0 9 * 1,2 *')).toEqual({ frequency: 'manual' })
|
|
90
|
-
expect(cronToFrequency('0 */2 * * *')).toEqual({ frequency: 'manual' })
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
test('hourly when minute is step but hour is wildcard', () => {
|
|
94
|
-
// */5 in minute + * in hour matches the first branch: hour === '*' && all wildcards
|
|
95
|
-
expect(cronToFrequency('*/5 * * * *')).toEqual({ frequency: 'hourly' })
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
test('out-of-range values return manual', () => {
|
|
99
|
-
expect(cronToFrequency('60 25 * * *')).toEqual({ frequency: 'manual' })
|
|
100
|
-
expect(cronToFrequency('99 99 * * *')).toEqual({ frequency: 'manual' })
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
test('pads hour and minute correctly', () => {
|
|
104
|
-
expect(cronToFrequency('5 9 * * *')).toEqual({ frequency: 'daily', time: '09:05' })
|
|
105
|
-
expect(cronToFrequency('30 0 * * *')).toEqual({ frequency: 'daily', time: '00:30' })
|
|
106
|
-
})
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
describe('FREQUENCY_OPTIONS', () => {
|
|
110
|
-
test('contains all expected frequencies', () => {
|
|
111
|
-
const values = FREQUENCY_OPTIONS.map(o => o.value)
|
|
112
|
-
expect(values).toContain('manual')
|
|
113
|
-
expect(values).toContain('hourly')
|
|
114
|
-
expect(values).toContain('daily')
|
|
115
|
-
expect(values).toContain('weekdays')
|
|
116
|
-
expect(values).toContain('weekly')
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
test('all have labels', () => {
|
|
120
|
-
for (const opt of FREQUENCY_OPTIONS) {
|
|
121
|
-
expect(typeof opt.label).toBe('string')
|
|
122
|
-
expect(opt.label.length).toBeGreaterThan(0)
|
|
123
|
-
}
|
|
124
|
-
})
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
describe('round-trip: frequency → cron → frequency', () => {
|
|
128
|
-
test('daily round-trip preserves data', () => {
|
|
129
|
-
const cron = frequencyToCron('daily', '09:00')
|
|
130
|
-
const result = cronToFrequency(cron)
|
|
131
|
-
expect(result).toEqual({ frequency: 'daily', time: '09:00' })
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
test('weekdays round-trip preserves data', () => {
|
|
135
|
-
const cron = frequencyToCron('weekdays', '08:30')
|
|
136
|
-
const result = cronToFrequency(cron)
|
|
137
|
-
expect(result).toEqual({ frequency: 'weekdays', time: '08:30' })
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
test('weekly round-trip preserves data', () => {
|
|
141
|
-
const cron = frequencyToCron('weekly', '17:00')
|
|
142
|
-
const result = cronToFrequency(cron)
|
|
143
|
-
expect(result).toEqual({ frequency: 'weekly', time: '17:00' })
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
test('hourly round-trip preserves minute', () => {
|
|
147
|
-
// frequencyToCron('hourly', '00:15') produces "15 * * * *"
|
|
148
|
-
// cronToFrequency('15 * * * *') returns 'hourly' (minute is numeric, hour is '*')
|
|
149
|
-
const cron = frequencyToCron('hourly', '00:15')
|
|
150
|
-
const result = cronToFrequency(cron)
|
|
151
|
-
expect(result).toEqual({ frequency: 'hourly' })
|
|
152
|
-
})
|
|
153
|
-
})
|
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test, beforeEach, afterEach } from 'bun:test'
|
|
2
|
-
import { mkdir, writeFile, rm } from 'fs/promises'
|
|
3
|
-
import { join } from 'path'
|
|
4
|
-
import { randomUUID } from 'crypto'
|
|
5
|
-
|
|
6
|
-
// We'll test the updateCronTask by directly exercising the exported functions
|
|
7
|
-
// through a temporary directory approach.
|
|
8
|
-
// Note: These are integration tests that use actual filesystem operations.
|
|
9
|
-
|
|
10
|
-
describe('updateCronTask integration', () => {
|
|
11
|
-
const tmpDir = join('/tmp', `cron-test-${randomUUID().slice(0, 8)}`)
|
|
12
|
-
|
|
13
|
-
beforeEach(async () => {
|
|
14
|
-
// Create temp project structure
|
|
15
|
-
await mkdir(join(tmpDir, '.claude'), { recursive: true })
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
afterEach(async () => {
|
|
19
|
-
await rm(tmpDir, { recursive: true, force: true })
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
test('CRON_FILE_REL constant is correct', async () => {
|
|
23
|
-
// Import and verify the file relative path
|
|
24
|
-
const { getCronFilePath } = await import('../cronTasks.js')
|
|
25
|
-
const filePath = getCronFilePath(tmpDir)
|
|
26
|
-
expect(filePath).toContain('.claude')
|
|
27
|
-
expect(filePath).toContain('scheduled_tasks.json')
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
test('getCronFilePath returns correct path', async () => {
|
|
31
|
-
const { getCronFilePath } = await import('../cronTasks.js')
|
|
32
|
-
const filePath = getCronFilePath(tmpDir)
|
|
33
|
-
expect(filePath).toBe(join(tmpDir, '.claude', 'scheduled_tasks.json'))
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
test('getCronFilePath uses project root when no dir provided', async () => {
|
|
37
|
-
const { getCronFilePath } = await import('../cronTasks.js')
|
|
38
|
-
// Without dir, should use getProjectRoot() which is process.cwd()
|
|
39
|
-
// Just verify it returns a valid-looking path
|
|
40
|
-
const filePath = getCronFilePath()
|
|
41
|
-
expect(filePath).toContain('scheduled_tasks.json')
|
|
42
|
-
})
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
describe('CronTaskMeta type coverage', () => {
|
|
46
|
-
test('all UI fields are optional on CronTask', async () => {
|
|
47
|
-
// Verify all new fields exist on the type by creating tasks with them
|
|
48
|
-
const { addCronTask } = await import('../cronTasks.js')
|
|
49
|
-
|
|
50
|
-
// Create a task with all metadata fields (durable=true writes to disk in test dir)
|
|
51
|
-
const tmpDir = join('/tmp', `cron-meta-test-${randomUUID().slice(0, 8)}`)
|
|
52
|
-
await mkdir(join(tmpDir, '.claude'), { recursive: true })
|
|
53
|
-
|
|
54
|
-
const id = await addCronTask(
|
|
55
|
-
'0 9 * * *',
|
|
56
|
-
'test prompt',
|
|
57
|
-
true, // recurring
|
|
58
|
-
true, // durable (writes to disk)
|
|
59
|
-
undefined, // agentId
|
|
60
|
-
{
|
|
61
|
-
name: 'test-name',
|
|
62
|
-
description: 'test description',
|
|
63
|
-
folder: '/test/folder',
|
|
64
|
-
model: 'claude-opus-4-7',
|
|
65
|
-
permissionMode: 'ask',
|
|
66
|
-
worktree: false,
|
|
67
|
-
frequency: 'daily',
|
|
68
|
-
scheduledTime: '09:00',
|
|
69
|
-
},
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
expect(typeof id).toBe('string')
|
|
73
|
-
expect(id.length).toBe(8) // Short ID
|
|
74
|
-
|
|
75
|
-
// Clean up
|
|
76
|
-
await rm(tmpDir, { recursive: true, force: true })
|
|
77
|
-
})
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
describe('readCronTasks backward compatibility', () => {
|
|
81
|
-
test('handles empty file', async () => {
|
|
82
|
-
const { readCronTasks } = await import('../cronTasks.js')
|
|
83
|
-
const tmpDir = join('/tmp', `cron-empty-${randomUUID().slice(0, 8)}`)
|
|
84
|
-
await mkdir(join(tmpDir, '.claude'), { recursive: true })
|
|
85
|
-
|
|
86
|
-
const tasks = await readCronTasks(tmpDir)
|
|
87
|
-
expect(Array.isArray(tasks)).toBe(true)
|
|
88
|
-
expect(tasks.length).toBe(0)
|
|
89
|
-
|
|
90
|
-
await rm(tmpDir, { recursive: true, force: true })
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
test('skips malformed JSON', async () => {
|
|
94
|
-
const { readCronTasks } = await import('../cronTasks.js')
|
|
95
|
-
const tmpDir = join('/tmp', `cron-malformed-${randomUUID().slice(0, 8)}`)
|
|
96
|
-
await mkdir(join(tmpDir, '.claude'), { recursive: true })
|
|
97
|
-
|
|
98
|
-
// Write malformed JSON
|
|
99
|
-
const filePath = join(tmpDir, '.claude', 'scheduled_tasks.json')
|
|
100
|
-
await writeFile(filePath, 'not valid json{{{')
|
|
101
|
-
|
|
102
|
-
const tasks = await readCronTasks(tmpDir)
|
|
103
|
-
expect(tasks.length).toBe(0) // Malformed entries skipped
|
|
104
|
-
|
|
105
|
-
await rm(tmpDir, { recursive: true, force: true })
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
test('skips tasks with invalid cron strings', async () => {
|
|
109
|
-
const { readCronTasks } = await import('../cronTasks.js')
|
|
110
|
-
const tmpDir = join('/tmp', `cron-invalid-${randomUUID().slice(0, 8)}`)
|
|
111
|
-
await mkdir(join(tmpDir, '.claude'), { recursive: true })
|
|
112
|
-
|
|
113
|
-
// Write task with invalid cron
|
|
114
|
-
const filePath = join(tmpDir, '.claude', 'scheduled_tasks.json')
|
|
115
|
-
await writeFile(
|
|
116
|
-
filePath,
|
|
117
|
-
JSON.stringify({
|
|
118
|
-
tasks: [
|
|
119
|
-
{
|
|
120
|
-
id: 'abcd1234',
|
|
121
|
-
cron: 'invalid-cron',
|
|
122
|
-
prompt: 'test',
|
|
123
|
-
createdAt: Date.now(),
|
|
124
|
-
},
|
|
125
|
-
],
|
|
126
|
-
}),
|
|
127
|
-
)
|
|
128
|
-
|
|
129
|
-
const tasks = await readCronTasks(tmpDir)
|
|
130
|
-
expect(tasks.length).toBe(0) // Invalid cron skipped
|
|
131
|
-
|
|
132
|
-
await rm(tmpDir, { recursive: true, force: true })
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
test('preserves new fields when reading', async () => {
|
|
136
|
-
const { readCronTasks } = await import('../cronTasks.js')
|
|
137
|
-
const tmpDir = join('/tmp', `cron-preserve-${randomUUID().slice(0, 8)}`)
|
|
138
|
-
await mkdir(join(tmpDir, '.claude'), { recursive: true })
|
|
139
|
-
|
|
140
|
-
const filePath = join(tmpDir, '.claude', 'scheduled_tasks.json')
|
|
141
|
-
const task = {
|
|
142
|
-
id: 'abcd1234',
|
|
143
|
-
cron: '0 9 * * *',
|
|
144
|
-
prompt: 'test prompt',
|
|
145
|
-
createdAt: Date.now(),
|
|
146
|
-
recurring: true,
|
|
147
|
-
name: 'my-task',
|
|
148
|
-
description: 'A test task',
|
|
149
|
-
folder: '/project',
|
|
150
|
-
model: 'claude-sonnet-4-6',
|
|
151
|
-
permissionMode: 'bypass',
|
|
152
|
-
worktree: true,
|
|
153
|
-
frequency: 'daily',
|
|
154
|
-
scheduledTime: '09:00',
|
|
155
|
-
}
|
|
156
|
-
await writeFile(filePath, JSON.stringify({ tasks: [task] }))
|
|
157
|
-
|
|
158
|
-
const tasks = await readCronTasks(tmpDir)
|
|
159
|
-
expect(tasks.length).toBe(1)
|
|
160
|
-
expect(tasks[0].name).toBe('my-task')
|
|
161
|
-
expect(tasks[0].description).toBe('A test task')
|
|
162
|
-
expect(tasks[0].folder).toBe('/project')
|
|
163
|
-
expect(tasks[0].model).toBe('claude-sonnet-4-6')
|
|
164
|
-
expect(tasks[0].permissionMode).toBe('bypass')
|
|
165
|
-
expect(tasks[0].worktree).toBe(true)
|
|
166
|
-
expect(tasks[0].frequency).toBe('daily')
|
|
167
|
-
expect(tasks[0].scheduledTime).toBe('09:00')
|
|
168
|
-
|
|
169
|
-
await rm(tmpDir, { recursive: true, force: true })
|
|
170
|
-
})
|
|
171
|
-
})
|
|
172
|
-
|
|
173
|
-
describe('writeCronTasks strips runtime fields', () => {
|
|
174
|
-
test('strips durable and agentId on write', async () => {
|
|
175
|
-
const { readCronTasks, writeCronTasks } = await import('../cronTasks.js')
|
|
176
|
-
const tmpDir = join('/tmp', `cron-strip-${randomUUID().slice(0, 8)}`)
|
|
177
|
-
await mkdir(join(tmpDir, '.claude'), { recursive: true })
|
|
178
|
-
|
|
179
|
-
const taskWithRuntimeFields = {
|
|
180
|
-
id: 'abcd1234',
|
|
181
|
-
cron: '0 9 * * *',
|
|
182
|
-
prompt: 'test',
|
|
183
|
-
createdAt: Date.now(),
|
|
184
|
-
recurring: true,
|
|
185
|
-
durable: true, // runtime-only, should be stripped
|
|
186
|
-
agentId: 'agent-123', // runtime-only, should be stripped
|
|
187
|
-
name: 'test-task', // new field, should be preserved
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
await writeCronTasks([taskWithRuntimeFields as any], tmpDir)
|
|
191
|
-
|
|
192
|
-
// Read back and verify runtime fields are stripped
|
|
193
|
-
const filePath = join(tmpDir, '.claude', 'scheduled_tasks.json')
|
|
194
|
-
const { readFileSync } = await import('fs')
|
|
195
|
-
const raw = readFileSync(filePath, 'utf-8')
|
|
196
|
-
const parsed = JSON.parse(raw)
|
|
197
|
-
|
|
198
|
-
expect(parsed.tasks[0].durable).toBeUndefined()
|
|
199
|
-
expect(parsed.tasks[0].agentId).toBeUndefined()
|
|
200
|
-
expect(parsed.tasks[0].name).toBe('test-task')
|
|
201
|
-
|
|
202
|
-
await rm(tmpDir, { recursive: true, force: true })
|
|
203
|
-
})
|
|
204
|
-
})
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'bun:test'
|
|
2
|
-
import { normalizeOsPermissions } from './permissions.js'
|
|
3
|
-
|
|
4
|
-
describe('normalizeOsPermissions', () => {
|
|
5
|
-
it('treats explicit grants as granted', () => {
|
|
6
|
-
expect(
|
|
7
|
-
normalizeOsPermissions({ accessibility: true, screenRecording: true }),
|
|
8
|
-
).toEqual({
|
|
9
|
-
granted: true,
|
|
10
|
-
accessibility: true,
|
|
11
|
-
screenRecording: true,
|
|
12
|
-
})
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
it('treats screen recording unknown as non-blocking when accessibility is granted', () => {
|
|
16
|
-
expect(
|
|
17
|
-
normalizeOsPermissions({ accessibility: true, screenRecording: null }),
|
|
18
|
-
).toEqual({
|
|
19
|
-
granted: true,
|
|
20
|
-
accessibility: true,
|
|
21
|
-
screenRecording: true,
|
|
22
|
-
})
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
it('still blocks when accessibility is missing', () => {
|
|
26
|
-
expect(
|
|
27
|
-
normalizeOsPermissions({ accessibility: false, screenRecording: null }),
|
|
28
|
-
).toEqual({
|
|
29
|
-
granted: false,
|
|
30
|
-
accessibility: false,
|
|
31
|
-
screenRecording: true,
|
|
32
|
-
})
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
it('blocks when screen recording is explicitly denied', () => {
|
|
36
|
-
expect(
|
|
37
|
-
normalizeOsPermissions({ accessibility: true, screenRecording: false }),
|
|
38
|
-
).toEqual({
|
|
39
|
-
granted: false,
|
|
40
|
-
accessibility: true,
|
|
41
|
-
screenRecording: false,
|
|
42
|
-
})
|
|
43
|
-
})
|
|
44
|
-
})
|
|
@@ -1,24 +0,0 @@
|
|
|
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
|
-
}
|
package/stubs/color-diff-napi.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
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
|
-
}
|