crawd 0.9.4 → 0.9.5
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 -1
- package/skills/crawd/SKILL.md +2 -0
- package/src/backend/coordinator.ts +0 -115
- package/src/backend/server.ts +0 -4
package/package.json
CHANGED
package/skills/crawd/SKILL.md
CHANGED
|
@@ -9,8 +9,10 @@ metadata: {"emoji": "🟠", "requires.env": ["OPENCLAW_GATEWAY_TOKEN"], "require
|
|
|
9
9
|
Viewers see your screen in real time. Every click, every page, every tab — it's all on stream. Act like someone is watching, because they are.
|
|
10
10
|
|
|
11
11
|
**Screen awareness:**
|
|
12
|
+
- **Take screenshots constantly.** If your model supports vision, screenshot is your best friend. Take one before responding to chat, after navigating to a new page, after scrolling, when you wake up, when something changes on screen. You cannot see what viewers see unless you screenshot. This is how you stay aware of your own stream.
|
|
12
13
|
- **Check your screen when you wake up.** Take a screenshot before doing anything — you may have gone to sleep with tabs open, notifications visible, or pages loaded. Viewers can see all of this and will reference it in chat. If you don't look at your screen first, you won't understand what they're talking about.
|
|
13
14
|
- **Check your screen before responding to chat.** Viewers are looking at the same screen you are. Their messages often reference what's visible — a notification count, a tweet on screen, a video playing. Screenshot first so you have the same context they do.
|
|
15
|
+
- **Screenshot after actions.** After clicking, scrolling, or navigating — screenshot to see the result. Don't blindly chain actions. Look at what happened.
|
|
14
16
|
- Keep your browser tidy. Close tabs you're not using — empty tabs, old searches, finished pages. Viewers see clutter.
|
|
15
17
|
- When you finish with something, close it. Don't leave 15 tabs open.
|
|
16
18
|
- Think of your screen as your stage. What's on it matters.
|
|
@@ -507,101 +507,6 @@ export class OneShotGateway {
|
|
|
507
507
|
})
|
|
508
508
|
}
|
|
509
509
|
|
|
510
|
-
/** Compact a session via the gateway's sessions.compact method */
|
|
511
|
-
async compactSession(maxLines = 400): Promise<{ compacted: boolean }> {
|
|
512
|
-
return new Promise((resolve, reject) => {
|
|
513
|
-
const ws = new WebSocket(this.url)
|
|
514
|
-
const authId = randomUUID()
|
|
515
|
-
const reqId = randomUUID()
|
|
516
|
-
let settled = false
|
|
517
|
-
|
|
518
|
-
const timeout = setTimeout(() => {
|
|
519
|
-
if (!settled) {
|
|
520
|
-
settled = true
|
|
521
|
-
ws.close()
|
|
522
|
-
reject(new Error('One-shot compact request timed out (30s)'))
|
|
523
|
-
}
|
|
524
|
-
}, 30_000)
|
|
525
|
-
|
|
526
|
-
const finish = (result?: { compacted: boolean }, error?: Error) => {
|
|
527
|
-
if (settled) return
|
|
528
|
-
settled = true
|
|
529
|
-
clearTimeout(timeout)
|
|
530
|
-
ws.close()
|
|
531
|
-
if (error) {
|
|
532
|
-
console.error(`[OneShotGateway] compact error: ${error.message}`)
|
|
533
|
-
reject(error)
|
|
534
|
-
} else {
|
|
535
|
-
resolve(result ?? { compacted: false })
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
const sendConnect = () => {
|
|
540
|
-
ws.send(JSON.stringify({
|
|
541
|
-
type: 'req',
|
|
542
|
-
id: authId,
|
|
543
|
-
method: 'connect',
|
|
544
|
-
params: {
|
|
545
|
-
minProtocol: 3,
|
|
546
|
-
maxProtocol: 3,
|
|
547
|
-
client: {
|
|
548
|
-
id: 'gateway-client',
|
|
549
|
-
version: '1.0.0',
|
|
550
|
-
platform: 'node',
|
|
551
|
-
mode: 'backend',
|
|
552
|
-
},
|
|
553
|
-
auth: this.token ? { token: this.token } : {},
|
|
554
|
-
},
|
|
555
|
-
}))
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
ws.on('message', (data) => {
|
|
559
|
-
try {
|
|
560
|
-
const frame = JSON.parse(data.toString()) as GatewayFrame
|
|
561
|
-
|
|
562
|
-
if (frame.type === 'event' && (frame as any).event === 'connect.challenge') {
|
|
563
|
-
sendConnect()
|
|
564
|
-
return
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
if (frame.type === 'res' && frame.id === authId) {
|
|
568
|
-
if (frame.error) {
|
|
569
|
-
finish(undefined, new Error(`Gateway auth failed: ${frame.error.message}`))
|
|
570
|
-
return
|
|
571
|
-
}
|
|
572
|
-
ws.send(JSON.stringify({
|
|
573
|
-
type: 'req',
|
|
574
|
-
id: reqId,
|
|
575
|
-
method: 'sessions.compact',
|
|
576
|
-
params: {
|
|
577
|
-
key: this.sessionKey,
|
|
578
|
-
maxLines,
|
|
579
|
-
},
|
|
580
|
-
}))
|
|
581
|
-
} else if (frame.type === 'res' && frame.id === reqId) {
|
|
582
|
-
if (frame.error) {
|
|
583
|
-
finish(undefined, new Error(`sessions.compact failed: ${frame.error.message}`))
|
|
584
|
-
return
|
|
585
|
-
}
|
|
586
|
-
const payload = frame.payload as any
|
|
587
|
-
finish({ compacted: payload?.compacted === true })
|
|
588
|
-
}
|
|
589
|
-
} catch {
|
|
590
|
-
// Parse error — ignore
|
|
591
|
-
}
|
|
592
|
-
})
|
|
593
|
-
|
|
594
|
-
ws.on('error', (err) => {
|
|
595
|
-
finish(undefined, err instanceof Error ? err : new Error(String(err)))
|
|
596
|
-
})
|
|
597
|
-
|
|
598
|
-
ws.on('close', () => {
|
|
599
|
-
if (!settled) {
|
|
600
|
-
finish(undefined, new Error('WebSocket closed unexpectedly'))
|
|
601
|
-
}
|
|
602
|
-
})
|
|
603
|
-
})
|
|
604
|
-
}
|
|
605
510
|
}
|
|
606
511
|
|
|
607
512
|
/**
|
|
@@ -637,7 +542,6 @@ export class Coordinator {
|
|
|
637
542
|
private buffer: ChatMessage[] = []
|
|
638
543
|
private timer: NodeJS.Timeout | null = null
|
|
639
544
|
private triggerFn: TriggerAgentFn
|
|
640
|
-
private compactFn?: () => Promise<void>
|
|
641
545
|
private onEvent?: (event: CoordinatorEvent) => void
|
|
642
546
|
/** Timestamp when coordinator was created (used to filter old messages on restart) */
|
|
643
547
|
private readonly startedAt: number
|
|
@@ -717,11 +621,6 @@ export class Coordinator {
|
|
|
717
621
|
this.onEvent = callback
|
|
718
622
|
}
|
|
719
623
|
|
|
720
|
-
/** Set the compact function (uses gateway sessions.compact instead of sending /compact as agent message) */
|
|
721
|
-
setCompactFn(fn: () => Promise<void>): void {
|
|
722
|
-
this.compactFn = fn
|
|
723
|
-
}
|
|
724
|
-
|
|
725
624
|
private emit(event: CoordinatorEvent): void {
|
|
726
625
|
this.onEvent?.(event)
|
|
727
626
|
}
|
|
@@ -792,20 +691,6 @@ export class Coordinator {
|
|
|
792
691
|
|
|
793
692
|
this.stopVibeLoop()
|
|
794
693
|
this.cancelPlanNudge()
|
|
795
|
-
this.compactSession()
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
/** Compact the agent's session context before sleeping to free stale history */
|
|
799
|
-
private compactSession(): void {
|
|
800
|
-
if (!this.compactFn) return
|
|
801
|
-
this._gatewayQueue = this._gatewayQueue.then(async () => {
|
|
802
|
-
try {
|
|
803
|
-
await this.compactFn!()
|
|
804
|
-
this.logger.log('[Coordinator] Session compacted before sleep')
|
|
805
|
-
} catch (err) {
|
|
806
|
-
this.logger.error('[Coordinator] Failed to compact session:', err)
|
|
807
|
-
}
|
|
808
|
-
}).catch(() => {})
|
|
809
694
|
}
|
|
810
695
|
|
|
811
696
|
/** Signal that the agent is speaking (via tool call) — keeps coordinator awake */
|
package/src/backend/server.ts
CHANGED
|
@@ -272,10 +272,6 @@ export class CrawdBackend {
|
|
|
272
272
|
coordConfig,
|
|
273
273
|
)
|
|
274
274
|
|
|
275
|
-
this.coordinator.setCompactFn(async () => {
|
|
276
|
-
await gateway.compactSession()
|
|
277
|
-
})
|
|
278
|
-
|
|
279
275
|
this.coordinator.setOnEvent((event: CoordinatorEvent) => {
|
|
280
276
|
if (event.type === 'stateChange') {
|
|
281
277
|
this.io.emit('crawd:status', { status: event.to })
|