bingocode 1.0.5 → 1.0.6
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
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Command } from '../../commands.js'
|
|
2
|
+
|
|
3
|
+
const releaseNotes: Command = {
|
|
4
|
+
description: 'View release notes',
|
|
5
|
+
name: 'release-notes',
|
|
6
|
+
type: 'local',
|
|
7
|
+
supportsNonInteractive: true,
|
|
8
|
+
load: () => import('./release-notes.js'),
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default releaseNotes
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { LocalCommandResult } from '../../types/command.js'
|
|
2
|
+
import {
|
|
3
|
+
CHANGELOG_URL,
|
|
4
|
+
fetchAndStoreChangelog,
|
|
5
|
+
getAllReleaseNotes,
|
|
6
|
+
getStoredChangelog,
|
|
7
|
+
} from '../../utils/releaseNotes.js'
|
|
8
|
+
|
|
9
|
+
function formatReleaseNotes(notes: Array<[string, string[]]>): string {
|
|
10
|
+
return notes
|
|
11
|
+
.map(([version, notes]) => {
|
|
12
|
+
const header = `Version ${version}:`
|
|
13
|
+
const bulletPoints = notes.map(note => `· ${note}`).join('\n')
|
|
14
|
+
return `${header}\n${bulletPoints}`
|
|
15
|
+
})
|
|
16
|
+
.join('\n\n')
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function call(): Promise<LocalCommandResult> {
|
|
20
|
+
// Try to fetch the latest changelog with a 500ms timeout
|
|
21
|
+
let freshNotes: Array<[string, string[]]> = []
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
const timeoutPromise = new Promise<void>((_, reject) => {
|
|
25
|
+
setTimeout(rej => rej(new Error('Timeout')), 500, reject)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
await Promise.race([fetchAndStoreChangelog(), timeoutPromise])
|
|
29
|
+
freshNotes = getAllReleaseNotes(await getStoredChangelog())
|
|
30
|
+
} catch {
|
|
31
|
+
// Either fetch failed or timed out - just use cached notes
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// If we have fresh notes from the quick fetch, use those
|
|
35
|
+
if (freshNotes.length > 0) {
|
|
36
|
+
return { type: 'text', value: formatReleaseNotes(freshNotes) }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Otherwise check cached notes
|
|
40
|
+
const cachedNotes = getAllReleaseNotes(await getStoredChangelog())
|
|
41
|
+
if (cachedNotes.length > 0) {
|
|
42
|
+
return { type: 'text', value: formatReleaseNotes(cachedNotes) }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Nothing available, show link
|
|
46
|
+
return {
|
|
47
|
+
type: 'text',
|
|
48
|
+
value: `See the full changelog at: ${CHANGELOG_URL}`,
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
const args = process.argv.slice(2)
|
|
2
|
+
|
|
3
|
+
function getArg(name: string): string | undefined {
|
|
4
|
+
const index = args.indexOf(name)
|
|
5
|
+
return index >= 0 ? args[index + 1] : undefined
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function emit(ws: WebSocket, payload: Record<string, unknown>) {
|
|
9
|
+
ws.send(JSON.stringify(payload) + '\n')
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function extractUserText(message: any): string {
|
|
13
|
+
const content = message?.message?.content
|
|
14
|
+
if (!Array.isArray(content)) return ''
|
|
15
|
+
return content
|
|
16
|
+
.filter((block: any) => block?.type === 'text' && typeof block.text === 'string')
|
|
17
|
+
.map((block: any) => block.text)
|
|
18
|
+
.join(' ')
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const sdkUrl = getArg('--sdk-url')
|
|
22
|
+
const sessionId = getArg('--session-id') || crypto.randomUUID()
|
|
23
|
+
const initMode = process.env.MOCK_SDK_INIT_MODE || 'on_open'
|
|
24
|
+
let initSent = false
|
|
25
|
+
|
|
26
|
+
if (!sdkUrl) {
|
|
27
|
+
console.error('Missing --sdk-url')
|
|
28
|
+
process.exit(1)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const ws = new WebSocket(sdkUrl)
|
|
32
|
+
|
|
33
|
+
function sendInit() {
|
|
34
|
+
if (initSent) return
|
|
35
|
+
initSent = true
|
|
36
|
+
emit(ws, {
|
|
37
|
+
type: 'system',
|
|
38
|
+
subtype: 'init',
|
|
39
|
+
model: 'mock-opus',
|
|
40
|
+
slash_commands: [{ name: 'help', description: 'Show help' }],
|
|
41
|
+
session_id: sessionId,
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
ws.addEventListener('open', () => {
|
|
46
|
+
if (initMode !== 'on_first_user') {
|
|
47
|
+
sendInit()
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
ws.addEventListener('message', (event) => {
|
|
52
|
+
const payload = typeof event.data === 'string' ? event.data : String(event.data)
|
|
53
|
+
const lines = payload.split('\n').map(line => line.trim()).filter(Boolean)
|
|
54
|
+
|
|
55
|
+
for (const line of lines) {
|
|
56
|
+
const parsed = JSON.parse(line)
|
|
57
|
+
|
|
58
|
+
if (parsed.type === 'user') {
|
|
59
|
+
sendInit()
|
|
60
|
+
const text = extractUserText(parsed)
|
|
61
|
+
emit(ws, {
|
|
62
|
+
type: 'stream_event',
|
|
63
|
+
event: { type: 'message_start' },
|
|
64
|
+
session_id: sessionId,
|
|
65
|
+
})
|
|
66
|
+
emit(ws, {
|
|
67
|
+
type: 'stream_event',
|
|
68
|
+
event: {
|
|
69
|
+
type: 'content_block_start',
|
|
70
|
+
index: 0,
|
|
71
|
+
content_block: { type: 'text', text: '' },
|
|
72
|
+
},
|
|
73
|
+
session_id: sessionId,
|
|
74
|
+
})
|
|
75
|
+
emit(ws, {
|
|
76
|
+
type: 'stream_event',
|
|
77
|
+
event: {
|
|
78
|
+
type: 'content_block_delta',
|
|
79
|
+
index: 0,
|
|
80
|
+
delta: { type: 'thinking_delta', thinking: 'Mock thinking...' },
|
|
81
|
+
},
|
|
82
|
+
session_id: sessionId,
|
|
83
|
+
})
|
|
84
|
+
emit(ws, {
|
|
85
|
+
type: 'stream_event',
|
|
86
|
+
event: {
|
|
87
|
+
type: 'content_block_delta',
|
|
88
|
+
index: 0,
|
|
89
|
+
delta: { type: 'text_delta', text: `Echo: ${text}` },
|
|
90
|
+
},
|
|
91
|
+
session_id: sessionId,
|
|
92
|
+
})
|
|
93
|
+
emit(ws, {
|
|
94
|
+
type: 'stream_event',
|
|
95
|
+
event: { type: 'content_block_stop', index: 0 },
|
|
96
|
+
session_id: sessionId,
|
|
97
|
+
})
|
|
98
|
+
emit(ws, {
|
|
99
|
+
type: 'result',
|
|
100
|
+
subtype: 'success',
|
|
101
|
+
is_error: false,
|
|
102
|
+
result: `Echo: ${text}`,
|
|
103
|
+
usage: { input_tokens: 3, output_tokens: 2 },
|
|
104
|
+
session_id: sessionId,
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (parsed.type === 'control_request' && parsed.request?.subtype === 'interrupt') {
|
|
109
|
+
emit(ws, {
|
|
110
|
+
type: 'result',
|
|
111
|
+
subtype: 'success',
|
|
112
|
+
is_error: false,
|
|
113
|
+
result: 'Interrupted',
|
|
114
|
+
usage: { input_tokens: 0, output_tokens: 0 },
|
|
115
|
+
session_id: sessionId,
|
|
116
|
+
})
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
ws.addEventListener('close', () => {
|
|
122
|
+
process.exit(0)
|
|
123
|
+
})
|