crawd 0.9.4 → 0.9.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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "crawd",
3
- "version": "0.9.4",
3
+ "version": "0.9.6",
4
4
  "description": "CLI for crawd.bot - AI agent livestreaming platform",
5
5
  "type": "module",
6
6
  "types": "./dist/types.d.ts",
@@ -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.
@@ -330,24 +330,24 @@ describe('Coordinator — Plan Mode', () => {
330
330
  })
331
331
  })
332
332
 
333
- describe('chat batch in plan mode', () => {
334
- it('appends plan instruction to chat batch when no active plan', () => {
333
+ describe('chat batch format', () => {
334
+ it('includes END OF CHAT delimiter', () => {
335
335
  const coord = createCoordinator()
336
- // No plan set
337
336
 
338
- const batch = coord.formatBatch([makeChatMessage('do something cool')])
339
- expect(batch).toContain('plan mode')
340
- expect(batch).toContain('plan_set')
337
+ const batch = coord.formatBatch([makeChatMessage('hello')])
338
+ expect(batch).toContain('[END OF CHAT]')
339
+ expect(batch).not.toContain('plan_set')
341
340
 
342
341
  coord.stop()
343
342
  })
344
343
 
345
- it('does not append plan instruction when plan is active', () => {
344
+ it('does not include plan instruction in chat batch', () => {
346
345
  const coord = createCoordinator()
347
- coord.setPlan('Active plan', ['Working on it'])
346
+ // No plan set, but chat batch should NOT include plan instruction
348
347
 
349
- const batch = coord.formatBatch([makeChatMessage('hello')])
348
+ const batch = coord.formatBatch([makeChatMessage('do something cool')])
350
349
  expect(batch).not.toContain('plan mode')
350
+ expect(batch).not.toContain('plan_set')
351
351
 
352
352
  coord.stop()
353
353
  })
@@ -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 */
@@ -1288,12 +1173,6 @@ export class Coordinator {
1288
1173
  ? '\n(To reply to a specific message, prefix with its ID: [msgId] your reply)'
1289
1174
  : ''
1290
1175
 
1291
- // In plan mode with no active plan, instruct agent to create one
1292
- let planInstruction = ''
1293
- if (this.config.autonomyMode === 'plan' && !this.hasPendingPlanSteps()) {
1294
- planInstruction = '\n\nCreate a plan using plan_set. Be creative and proactive — come up with something YOU want to do, not just "reply to chat". Browse the web, go down rabbit holes, check X/HN/YouTube, find weird stuff, have opinions. Each step should be a concrete action. Think aloud on stream about what you\'re doing. Never mention plans or steps to viewers.'
1295
- }
1296
-
1297
- return `${header}\n${lines.join('\n')}${instruction}${planInstruction}`
1176
+ return `${header}\n${lines.join('\n')}\n[END OF CHAT]${instruction}`
1298
1177
  }
1299
1178
  }
@@ -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 })