@alumbwe/anvil 1.0.42 → 1.0.50
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/bin/anvil.js +18 -0
- package/package.json +13 -6
- package/src/agents/bundled-agents.generated.ts +1 -1
- package/src/index.tsx +27 -4
- package/src/login/plain-login.ts +60 -0
- package/src/login/supabase-auth.ts +346 -0
- package/src/utils/anvil-client.ts +4 -0
- package/src/utils/auth.ts +16 -4
- package/src/utils/config-dir.ts +1 -1
- package/vendor/@anvil/common/src/constants/deepseek-direct.ts +30 -1
- package/vendor/@anvil/common/src/util/project-ignore.ts +4 -3
- package/vendor/@anvil/sdk/dist/index.cjs +46 -10
- package/vendor/@anvil/sdk/dist/index.mjs +46 -10
- package/src/commands/__tests__/anvil-command-aliases.test.ts +0 -56
- package/src/commands/__tests__/bash-command.test.ts +0 -445
- package/src/commands/__tests__/command-args.test.ts +0 -349
- package/src/commands/__tests__/copy-conversation-clipboard.test.ts +0 -108
- package/src/commands/__tests__/copy-conversation.test.ts +0 -226
- package/src/commands/__tests__/diagnostics-command.test.ts +0 -35
- package/src/commands/__tests__/image.test.ts +0 -99
- package/src/commands/__tests__/init.test.ts +0 -456
- package/src/commands/__tests__/new-command-rotates-chat.test.ts +0 -91
- package/src/commands/__tests__/process-diagnostics.test.ts +0 -54
- package/src/commands/__tests__/prompt-builders.test.ts +0 -28
- package/src/commands/__tests__/router-input.test.ts +0 -298
- package/src/components/__tests__/ad-banner.test.tsx +0 -83
- package/src/components/__tests__/anvil-landing-heading-row.test.tsx +0 -91
- package/src/components/__tests__/anvil-model-selector.test.tsx +0 -519
- package/src/components/__tests__/anvil-offer-invariants.test.ts +0 -54
- package/src/components/__tests__/anvil-takeover-prompt.test.tsx +0 -212
- package/src/components/__tests__/chat-input-bar.test.tsx +0 -130
- package/src/components/__tests__/grid-layout.integration.test.tsx +0 -304
- package/src/components/__tests__/grid-layout.test.tsx +0 -1051
- package/src/components/__tests__/message-block.completion.test.tsx +0 -104
- package/src/components/__tests__/message-block.streaming.test.tsx +0 -78
- package/src/components/__tests__/message-with-agents.test.tsx +0 -579
- package/src/components/__tests__/multiline-input.test.tsx +0 -1132
- package/src/components/__tests__/queue-panel.test.tsx +0 -398
- package/src/components/__tests__/selectable-list.test.ts +0 -232
- package/src/components/__tests__/status-bar.test.tsx +0 -44
- package/src/components/__tests__/status-indicator.test.tsx +0 -204
- package/src/components/__tests__/terminal-thinking-orb.test.tsx +0 -111
- package/src/components/__tests__/user-error-banner.test.tsx +0 -102
- package/src/components/ask-user/__tests__/multiple-choice-form.test.ts +0 -432
- package/src/components/ask-user/__tests__/validation.test.ts +0 -213
- package/src/components/tools/__tests__/apply-patch.test.tsx +0 -84
- package/src/components/tools/__tests__/code-search.test.tsx +0 -45
- package/src/components/tools/__tests__/gravity-index.test.ts +0 -76
- package/src/components/tools/__tests__/render-ui.test.tsx +0 -92
- package/src/components/tools/__tests__/run-terminal-command.test.ts +0 -233
- package/src/contexts/__tests__/chat-runtime-context.test.tsx +0 -149
- package/src/data/slash-commands.test.ts +0 -24
- package/src/hooks/__tests__/holds-live-anvil-slot.test.ts +0 -49
- package/src/hooks/__tests__/session-fetch-signal.test.ts +0 -63
- package/src/hooks/__tests__/use-activity-query.test.ts +0 -1000
- package/src/hooks/__tests__/use-ask-user-bridge.test.ts +0 -176
- package/src/hooks/__tests__/use-auth-query.test.ts +0 -21
- package/src/hooks/__tests__/use-chat-input-remount.test.tsx +0 -66
- package/src/hooks/__tests__/use-clipboard.test.tsx +0 -73
- package/src/hooks/__tests__/use-connection-status.test.ts +0 -112
- package/src/hooks/__tests__/use-directory-browser.test.ts +0 -203
- package/src/hooks/__tests__/use-gravity-ad.test.ts +0 -73
- package/src/hooks/__tests__/use-grid-layout.test.ts +0 -349
- package/src/hooks/__tests__/use-input-history.test.ts +0 -699
- package/src/hooks/__tests__/use-message-queue-editing.test.tsx +0 -209
- package/src/hooks/__tests__/use-message-queue.test.tsx +0 -71
- package/src/hooks/__tests__/use-path-tab-completion.test.ts +0 -315
- package/src/hooks/__tests__/use-queue-controls.test.ts +0 -68
- package/src/hooks/__tests__/use-queue-ui.test.tsx +0 -83
- package/src/hooks/__tests__/use-searchable-list.test.ts +0 -359
- package/src/hooks/__tests__/use-send-message-timer.test.ts +0 -146
- package/src/hooks/__tests__/use-suggestion-engine-mention.test.ts +0 -361
- package/src/hooks/__tests__/use-suggestion-engine.test.ts +0 -485
- package/src/hooks/__tests__/use-terminal-focus.test.ts +0 -66
- package/src/hooks/__tests__/use-terminal-layout.test.ts +0 -675
- package/src/hooks/__tests__/use-timeout.test.ts +0 -330
- package/src/hooks/__tests__/use-usage-query.test.ts +0 -502
- package/src/hooks/__tests__/use-user-details-query.test.ts +0 -195
- package/src/hooks/helpers/__tests__/send-message.test.ts +0 -1918
- package/src/init/__tests__/init-direnv.test.ts +0 -526
- package/src/state/__tests__/chat-store-focus.test.ts +0 -22
- package/src/state/__tests__/feedback-store.test.ts +0 -257
- package/src/utils/__tests__/active-run.test.ts +0 -140
- package/src/utils/__tests__/activity-tracker.test.ts +0 -440
- package/src/utils/__tests__/agent-display.test.ts +0 -139
- package/src/utils/__tests__/analytics-client.test.ts +0 -262
- package/src/utils/__tests__/anonymous-id.test.ts +0 -74
- package/src/utils/__tests__/anvil-api.test.ts +0 -578
- package/src/utils/__tests__/anvil-instance-owner.test.ts +0 -69
- package/src/utils/__tests__/anvil-model-navigation.test.ts +0 -102
- package/src/utils/__tests__/anvil-premium-reset.test.ts +0 -79
- package/src/utils/__tests__/anvil-referral-cache.test.ts +0 -116
- package/src/utils/__tests__/anvil-session-api.test.ts +0 -215
- package/src/utils/__tests__/anvil-session-display.test.ts +0 -23
- package/src/utils/__tests__/anvil-streak-line.test.ts +0 -217
- package/src/utils/__tests__/arrays.test.ts +0 -264
- package/src/utils/__tests__/bash-context-processor.test.ts +0 -38
- package/src/utils/__tests__/block-processor.test.ts +0 -810
- package/src/utils/__tests__/chat-history.test.ts +0 -203
- package/src/utils/__tests__/chat-input-key-intercept.test.ts +0 -40
- package/src/utils/__tests__/chat-meta.test.ts +0 -130
- package/src/utils/__tests__/clipboard-linux.test.ts +0 -359
- package/src/utils/__tests__/clipboard.test.ts +0 -910
- package/src/utils/__tests__/code-search-summary.test.ts +0 -84
- package/src/utils/__tests__/collapse-helpers.test.ts +0 -1109
- package/src/utils/__tests__/error-handling.test.ts +0 -658
- package/src/utils/__tests__/exit-cleanly.test.ts +0 -110
- package/src/utils/__tests__/feedback-helpers.test.ts +0 -444
- package/src/utils/__tests__/feedback-submission.test.ts +0 -26
- package/src/utils/__tests__/fetch-usage.test.ts +0 -355
- package/src/utils/__tests__/fingerprint.test.ts +0 -144
- package/src/utils/__tests__/fixtures/terminal-command-broker-child.ts +0 -7
- package/src/utils/__tests__/fixtures/terminal-command-broker-entry.ts +0 -3
- package/src/utils/__tests__/fixtures/terminal-command-broker-owner.ts +0 -33
- package/src/utils/__tests__/format-elapsed-time.test.ts +0 -103
- package/src/utils/__tests__/format-timeout.test.ts +0 -87
- package/src/utils/__tests__/image-dimensions.test.ts +0 -249
- package/src/utils/__tests__/image-processor.test.ts +0 -209
- package/src/utils/__tests__/implementor-helpers.test.ts +0 -1458
- package/src/utils/__tests__/keyboard-actions.test.ts +0 -660
- package/src/utils/__tests__/layout-helpers.test.ts +0 -36
- package/src/utils/__tests__/lazy-response-ads.test.ts +0 -167
- package/src/utils/__tests__/log-shipper.test.ts +0 -53
- package/src/utils/__tests__/markdown-renderer.test.tsx +0 -421
- package/src/utils/__tests__/message-block-helpers.test.ts +0 -1263
- package/src/utils/__tests__/message-updater.test.ts +0 -645
- package/src/utils/__tests__/osc-timeout-scenarios.test.ts +0 -172
- package/src/utils/__tests__/pending-attachments.test.ts +0 -277
- package/src/utils/__tests__/polling-backoff.test.ts +0 -51
- package/src/utils/__tests__/queue-panel-actions.test.ts +0 -148
- package/src/utils/__tests__/run-state-storage.test.ts +0 -919
- package/src/utils/__tests__/safe-json.test.ts +0 -77
- package/src/utils/__tests__/sdk-event-handlers.test.ts +0 -685
- package/src/utils/__tests__/send-message-helpers.test.ts +0 -1898
- package/src/utils/__tests__/send-message-timer.test.ts +0 -64
- package/src/utils/__tests__/settings.test.ts +0 -99
- package/src/utils/__tests__/strings.test.ts +0 -192
- package/src/utils/__tests__/terminal-color-detection.test.ts +0 -425
- package/src/utils/__tests__/terminal-command-broker.test.ts +0 -528
- package/src/utils/__tests__/terminal-enter-detection.test.ts +0 -77
- package/src/utils/__tests__/terminal-io.test.ts +0 -137
- package/src/utils/__tests__/terminal-protocol-controller.test.ts +0 -119
- package/src/utils/__tests__/text-layout.test.ts +0 -82
- package/src/utils/__tests__/theme-platform-detection.test.ts +0 -125
- package/src/utils/__tests__/think-tag-parser.test.ts +0 -159
- package/src/utils/__tests__/trace-writer.test.ts +0 -223
- package/src/utils/__tests__/trim-chat-logs.test.ts +0 -78
- package/src/utils/__tests__/usage-banner-state.test.ts +0 -298
- package/src/utils/__tests__/validation-error-formatting.test.ts +0 -126
- package/src/utils/__tests__/windows-terminal-health.test.ts +0 -101
- package/src/utils/__tests__/write-file-atomic.test.ts +0 -127
- package/vendor/@anvil/common/src/__tests__/agent-validation.test.ts +0 -846
- package/vendor/@anvil/common/src/__tests__/anvil-model-availability.test.ts +0 -101
- package/vendor/@anvil/common/src/__tests__/anvil-models.test.ts +0 -1408
- package/vendor/@anvil/common/src/__tests__/anvil-public-data-use-copy.test.ts +0 -258
- package/vendor/@anvil/common/src/__tests__/anvil-referral-tiers.test.ts +0 -48
- package/vendor/@anvil/common/src/__tests__/anvil-spend-ceilings.test.ts +0 -282
- package/vendor/@anvil/common/src/__tests__/anvil-trust.test.ts +0 -526
- package/vendor/@anvil/common/src/__tests__/deepseek-direct.test.ts +0 -68
- package/vendor/@anvil/common/src/__tests__/disposable-email.test.ts +0 -132
- package/vendor/@anvil/common/src/__tests__/dynamic-agent-template-schema.test.ts +0 -422
- package/vendor/@anvil/common/src/__tests__/env-ci.test.ts +0 -167
- package/vendor/@anvil/common/src/__tests__/env-process.test.ts +0 -145
- package/vendor/@anvil/common/src/__tests__/foreign-client-shipped-agents.test.ts +0 -234
- package/vendor/@anvil/common/src/__tests__/foreign-client-signals.test.ts +0 -379
- package/vendor/@anvil/common/src/__tests__/free-agents.test.ts +0 -807
- package/vendor/@anvil/common/src/__tests__/gravity-capi.test.ts +0 -154
- package/vendor/@anvil/common/src/__tests__/handlesteps-parsing.test.ts +0 -246
- package/vendor/@anvil/common/src/__tests__/kimi-k3-god-only.test.ts +0 -77
- package/vendor/@anvil/common/src/__tests__/model-config.test.ts +0 -89
- package/vendor/@anvil/common/src/__tests__/project-file-tree.test.ts +0 -298
- package/vendor/@anvil/common/src/__tests__/provisioned-model-tiers.test.ts +0 -116
- package/vendor/@anvil/common/src/__tests__/reasoning-effort.test.ts +0 -167
- package/vendor/@anvil/common/src/__tests__/reddit-capi.test.ts +0 -132
- package/vendor/@anvil/common/src/__tests__/response-ad-positions.test.ts +0 -72
- package/vendor/@anvil/common/src/__tests__/user-state.test.ts +0 -30
- package/vendor/@anvil/common/src/constants/__tests__/anvil-onboarding-gate.test.ts +0 -63
- package/vendor/@anvil/common/src/constants/__tests__/anvil-onboarding.test.ts +0 -246
- package/vendor/@anvil/common/src/constants/__tests__/cf-worker-signals.test.ts +0 -106
- package/vendor/@anvil/common/src/testing/TESTING_PATTERNS.md +0 -351
- package/vendor/@anvil/common/src/testing/anvil-offer-invariants.ts +0 -169
- package/vendor/@anvil/common/src/testing/errors.ts +0 -33
- package/vendor/@anvil/common/src/testing/fixtures/agent-runtime.ts +0 -334
- package/vendor/@anvil/common/src/testing/impl/agent-runtime.ts +0 -6
- package/vendor/@anvil/common/src/testing/index.ts +0 -84
- package/vendor/@anvil/common/src/testing/mock-modules.ts +0 -53
- package/vendor/@anvil/common/src/testing/mock-types.ts +0 -123
- package/vendor/@anvil/common/src/testing/mocks/analytics.ts +0 -261
- package/vendor/@anvil/common/src/testing/mocks/child-process.ts +0 -93
- package/vendor/@anvil/common/src/testing/mocks/crypto.ts +0 -218
- package/vendor/@anvil/common/src/testing/mocks/database.ts +0 -337
- package/vendor/@anvil/common/src/testing/mocks/fetch.ts +0 -219
- package/vendor/@anvil/common/src/testing/mocks/filesystem.ts +0 -166
- package/vendor/@anvil/common/src/testing/mocks/index.ts +0 -101
- package/vendor/@anvil/common/src/testing/mocks/logger.ts +0 -135
- package/vendor/@anvil/common/src/testing/mocks/stream.ts +0 -313
- package/vendor/@anvil/common/src/testing/mocks/timers.ts +0 -132
- package/vendor/@anvil/common/src/testing/mocks/tree-sitter.ts +0 -127
- package/vendor/@anvil/common/src/testing/setup.ts +0 -282
- package/vendor/@anvil/common/src/tools/__tests__/compile-tool-definitions.test.ts +0 -34
- package/vendor/@anvil/common/src/tools/params/__tests__/coerce-to-array.test.ts +0 -213
- package/vendor/@anvil/common/src/tools/params/__tests__/read-docs.test.ts +0 -47
- package/vendor/@anvil/common/src/tools/params/__tests__/render-ui.test.ts +0 -65
- package/vendor/@anvil/common/src/tools/params/tool/__tests__/run-terminal-command-timeout.test.ts +0 -49
- package/vendor/@anvil/common/src/types/__tests__/dynamic-agent-template.test.ts +0 -20
- package/vendor/@anvil/common/src/util/__tests__/ad-user-agent.test.ts +0 -26
- package/vendor/@anvil/common/src/util/__tests__/analytics-dispatcher.test.ts +0 -122
- package/vendor/@anvil/common/src/util/__tests__/analytics-log.test.ts +0 -102
- package/vendor/@anvil/common/src/util/__tests__/analytics-sampling.test.ts +0 -143
- package/vendor/@anvil/common/src/util/__tests__/anvil-streak.test.ts +0 -202
- package/vendor/@anvil/common/src/util/__tests__/anvil-usage-summary.test.ts +0 -193
- package/vendor/@anvil/common/src/util/__tests__/axiom-only-log.test.ts +0 -140
- package/vendor/@anvil/common/src/util/__tests__/client-user-agent.test.ts +0 -148
- package/vendor/@anvil/common/src/util/__tests__/engagement-tracker.test.ts +0 -115
- package/vendor/@anvil/common/src/util/__tests__/env-file-path.test.ts +0 -57
- package/vendor/@anvil/common/src/util/__tests__/error-abort.test.ts +0 -774
- package/vendor/@anvil/common/src/util/__tests__/error-api-details.test.ts +0 -206
- package/vendor/@anvil/common/src/util/__tests__/file-read-limits.test.ts +0 -173
- package/vendor/@anvil/common/src/util/__tests__/format-code-search.test.ts +0 -60
- package/vendor/@anvil/common/src/util/__tests__/log-mirror.test.ts +0 -31
- package/vendor/@anvil/common/src/util/__tests__/messages.test.ts +0 -1252
- package/vendor/@anvil/common/src/util/__tests__/partial-json-delta.test.ts +0 -505
- package/vendor/@anvil/common/src/util/__tests__/path.test.ts +0 -22
- package/vendor/@anvil/common/src/util/__tests__/project-ignore.test.ts +0 -90
- package/vendor/@anvil/common/src/util/__tests__/promise.test.ts +0 -325
- package/vendor/@anvil/common/src/util/__tests__/rate-limit.test.ts +0 -28
- package/vendor/@anvil/common/src/util/__tests__/reddit-anvil-retention.test.ts +0 -130
- package/vendor/@anvil/common/src/util/__tests__/saxy.test.ts +0 -1008
- package/vendor/@anvil/common/src/util/__tests__/split-data.test.ts +0 -289
- package/vendor/@anvil/common/src/util/__tests__/string.test.ts +0 -239
- package/vendor/@anvil/common/src/util/__tests__/thread-title.test.ts +0 -70
- package/vendor/@anvil/common/src/util/__tests__/tool-result-media-order.test.ts +0 -108
- package/vendor/@anvil/common/src/util/__tests__/ttft-histogram.test.ts +0 -180
- package/vendor/@anvil/common/src/util/__tests__/with-timeout.test.ts +0 -24
- package/vendor/@anvil/common/src/util/__tests__/zoned-time.test.ts +0 -88
- package/vendor/@anvil/common/src/util/skills.test.ts +0 -44
- package/vendor/@anvil/sdk/dist/index.cjs.map +0 -440
- package/vendor/@anvil/sdk/dist/index.mjs.map +0 -440
|
@@ -1,440 +0,0 @@
|
|
|
1
|
-
import { describe, test, expect, beforeEach, afterEach, mock } from 'bun:test'
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
reportActivity,
|
|
5
|
-
getLastActivityTime,
|
|
6
|
-
isUserActive,
|
|
7
|
-
getIdleTime,
|
|
8
|
-
subscribeToActivity,
|
|
9
|
-
resetActivityTracker,
|
|
10
|
-
} from '../activity-tracker'
|
|
11
|
-
|
|
12
|
-
describe('activity-tracker', () => {
|
|
13
|
-
let originalDateNow: typeof Date.now
|
|
14
|
-
let mockNow: number
|
|
15
|
-
|
|
16
|
-
beforeEach(() => {
|
|
17
|
-
originalDateNow = Date.now
|
|
18
|
-
mockNow = 1000000
|
|
19
|
-
Date.now = () => mockNow
|
|
20
|
-
resetActivityTracker()
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
afterEach(() => {
|
|
24
|
-
Date.now = originalDateNow
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
describe('reportActivity', () => {
|
|
28
|
-
test('updates lastActivityTime to current time', () => {
|
|
29
|
-
mockNow = 2000000
|
|
30
|
-
reportActivity()
|
|
31
|
-
expect(getLastActivityTime()).toBe(2000000)
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
test('notifies all subscribers when activity is reported', () => {
|
|
35
|
-
const listener1 = mock(() => {})
|
|
36
|
-
const listener2 = mock(() => {})
|
|
37
|
-
|
|
38
|
-
subscribeToActivity(listener1)
|
|
39
|
-
subscribeToActivity(listener2)
|
|
40
|
-
|
|
41
|
-
mockNow = 3000000
|
|
42
|
-
reportActivity()
|
|
43
|
-
|
|
44
|
-
expect(listener1).toHaveBeenCalledTimes(1)
|
|
45
|
-
expect(listener1).toHaveBeenCalledWith(3000000)
|
|
46
|
-
expect(listener2).toHaveBeenCalledTimes(1)
|
|
47
|
-
expect(listener2).toHaveBeenCalledWith(3000000)
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
test('multiple calls update the timestamp each time', () => {
|
|
51
|
-
mockNow = 1000
|
|
52
|
-
reportActivity()
|
|
53
|
-
expect(getLastActivityTime()).toBe(1000)
|
|
54
|
-
|
|
55
|
-
mockNow = 2000
|
|
56
|
-
reportActivity()
|
|
57
|
-
expect(getLastActivityTime()).toBe(2000)
|
|
58
|
-
|
|
59
|
-
mockNow = 3000
|
|
60
|
-
reportActivity()
|
|
61
|
-
expect(getLastActivityTime()).toBe(3000)
|
|
62
|
-
})
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
describe('getLastActivityTime', () => {
|
|
66
|
-
test('returns the initial time after reset', () => {
|
|
67
|
-
// After reset, lastActivityTime is set to Date.now()
|
|
68
|
-
expect(getLastActivityTime()).toBe(mockNow)
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
test('returns the time of the last activity', () => {
|
|
72
|
-
mockNow = 5000000
|
|
73
|
-
reportActivity()
|
|
74
|
-
expect(getLastActivityTime()).toBe(5000000)
|
|
75
|
-
})
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
describe('isUserActive', () => {
|
|
79
|
-
test('returns true when user activity is within threshold', () => {
|
|
80
|
-
reportActivity()
|
|
81
|
-
mockNow += 10000 // 10 seconds later
|
|
82
|
-
expect(isUserActive(30000)).toBe(true)
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
test('returns false when user has been idle longer than threshold', () => {
|
|
86
|
-
reportActivity()
|
|
87
|
-
mockNow += 35000 // 35 seconds later
|
|
88
|
-
expect(isUserActive(30000)).toBe(false)
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
test('uses default threshold of 30 seconds', () => {
|
|
92
|
-
reportActivity()
|
|
93
|
-
mockNow += 29000 // 29 seconds later
|
|
94
|
-
expect(isUserActive()).toBe(true)
|
|
95
|
-
|
|
96
|
-
mockNow += 2000 // 31 seconds total
|
|
97
|
-
expect(isUserActive()).toBe(false)
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
test('returns true at exactly the threshold boundary', () => {
|
|
101
|
-
reportActivity()
|
|
102
|
-
mockNow += 29999 // Just under 30 seconds
|
|
103
|
-
expect(isUserActive(30000)).toBe(true)
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
test('returns false at exactly the threshold', () => {
|
|
107
|
-
reportActivity()
|
|
108
|
-
mockNow += 30000 // Exactly 30 seconds
|
|
109
|
-
expect(isUserActive(30000)).toBe(false)
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
test('works with custom thresholds', () => {
|
|
113
|
-
reportActivity()
|
|
114
|
-
mockNow += 5000
|
|
115
|
-
expect(isUserActive(10000)).toBe(true)
|
|
116
|
-
expect(isUserActive(3000)).toBe(false)
|
|
117
|
-
})
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
describe('getIdleTime', () => {
|
|
121
|
-
test('returns 0 immediately after activity', () => {
|
|
122
|
-
reportActivity()
|
|
123
|
-
expect(getIdleTime()).toBe(0)
|
|
124
|
-
})
|
|
125
|
-
|
|
126
|
-
test('returns correct idle time', () => {
|
|
127
|
-
reportActivity()
|
|
128
|
-
mockNow += 15000
|
|
129
|
-
expect(getIdleTime()).toBe(15000)
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
test('increases as time passes', () => {
|
|
133
|
-
reportActivity()
|
|
134
|
-
|
|
135
|
-
mockNow += 1000
|
|
136
|
-
expect(getIdleTime()).toBe(1000)
|
|
137
|
-
|
|
138
|
-
mockNow += 4000
|
|
139
|
-
expect(getIdleTime()).toBe(5000)
|
|
140
|
-
|
|
141
|
-
mockNow += 10000
|
|
142
|
-
expect(getIdleTime()).toBe(15000)
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
test('resets after new activity', () => {
|
|
146
|
-
reportActivity()
|
|
147
|
-
mockNow += 10000
|
|
148
|
-
expect(getIdleTime()).toBe(10000)
|
|
149
|
-
|
|
150
|
-
reportActivity()
|
|
151
|
-
expect(getIdleTime()).toBe(0)
|
|
152
|
-
})
|
|
153
|
-
})
|
|
154
|
-
|
|
155
|
-
describe('subscribeToActivity', () => {
|
|
156
|
-
test('returns an unsubscribe function', () => {
|
|
157
|
-
const listener = mock(() => {})
|
|
158
|
-
const unsubscribe = subscribeToActivity(listener)
|
|
159
|
-
|
|
160
|
-
expect(typeof unsubscribe).toBe('function')
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
test('unsubscribe stops notifications', () => {
|
|
164
|
-
const listener = mock(() => {})
|
|
165
|
-
const unsubscribe = subscribeToActivity(listener)
|
|
166
|
-
|
|
167
|
-
reportActivity()
|
|
168
|
-
expect(listener).toHaveBeenCalledTimes(1)
|
|
169
|
-
|
|
170
|
-
unsubscribe()
|
|
171
|
-
|
|
172
|
-
reportActivity()
|
|
173
|
-
expect(listener).toHaveBeenCalledTimes(1) // Still 1, not called again
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
test('multiple subscribers work independently', () => {
|
|
177
|
-
const listener1 = mock(() => {})
|
|
178
|
-
const listener2 = mock(() => {})
|
|
179
|
-
const listener3 = mock(() => {})
|
|
180
|
-
|
|
181
|
-
const unsub1 = subscribeToActivity(listener1)
|
|
182
|
-
subscribeToActivity(listener2)
|
|
183
|
-
subscribeToActivity(listener3)
|
|
184
|
-
|
|
185
|
-
reportActivity()
|
|
186
|
-
expect(listener1).toHaveBeenCalledTimes(1)
|
|
187
|
-
expect(listener2).toHaveBeenCalledTimes(1)
|
|
188
|
-
expect(listener3).toHaveBeenCalledTimes(1)
|
|
189
|
-
|
|
190
|
-
unsub1()
|
|
191
|
-
|
|
192
|
-
reportActivity()
|
|
193
|
-
expect(listener1).toHaveBeenCalledTimes(1) // Unsubscribed
|
|
194
|
-
expect(listener2).toHaveBeenCalledTimes(2)
|
|
195
|
-
expect(listener3).toHaveBeenCalledTimes(2)
|
|
196
|
-
})
|
|
197
|
-
|
|
198
|
-
test('same listener can be subscribed multiple times', () => {
|
|
199
|
-
const listener = mock(() => {})
|
|
200
|
-
|
|
201
|
-
subscribeToActivity(listener)
|
|
202
|
-
subscribeToActivity(listener)
|
|
203
|
-
|
|
204
|
-
reportActivity()
|
|
205
|
-
// Set only stores unique values, so it's called once
|
|
206
|
-
expect(listener).toHaveBeenCalledTimes(1)
|
|
207
|
-
})
|
|
208
|
-
|
|
209
|
-
test('unsubscribing non-existent listener does nothing', () => {
|
|
210
|
-
const listener1 = mock(() => {})
|
|
211
|
-
const listener2 = mock(() => {})
|
|
212
|
-
|
|
213
|
-
const unsub1 = subscribeToActivity(listener1)
|
|
214
|
-
unsub1()
|
|
215
|
-
unsub1() // Double unsubscribe should not throw
|
|
216
|
-
|
|
217
|
-
reportActivity()
|
|
218
|
-
expect(listener1).not.toHaveBeenCalled()
|
|
219
|
-
})
|
|
220
|
-
})
|
|
221
|
-
|
|
222
|
-
describe('resetActivityTracker', () => {
|
|
223
|
-
test('resets lastActivityTime to current time', () => {
|
|
224
|
-
reportActivity()
|
|
225
|
-
mockNow = 9999999
|
|
226
|
-
resetActivityTracker()
|
|
227
|
-
expect(getLastActivityTime()).toBe(9999999)
|
|
228
|
-
})
|
|
229
|
-
|
|
230
|
-
test('clears all listeners', () => {
|
|
231
|
-
const listener1 = mock(() => {})
|
|
232
|
-
const listener2 = mock(() => {})
|
|
233
|
-
|
|
234
|
-
subscribeToActivity(listener1)
|
|
235
|
-
subscribeToActivity(listener2)
|
|
236
|
-
|
|
237
|
-
resetActivityTracker()
|
|
238
|
-
|
|
239
|
-
reportActivity()
|
|
240
|
-
expect(listener1).not.toHaveBeenCalled()
|
|
241
|
-
expect(listener2).not.toHaveBeenCalled()
|
|
242
|
-
})
|
|
243
|
-
})
|
|
244
|
-
})
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Tests for activity tracker integration with useActivityQuery.
|
|
248
|
-
* These verify the behavior that affects polling and refetching in hooks.
|
|
249
|
-
*/
|
|
250
|
-
describe('activity-tracker integration scenarios', () => {
|
|
251
|
-
let originalDateNow: typeof Date.now
|
|
252
|
-
let mockNow: number
|
|
253
|
-
|
|
254
|
-
beforeEach(() => {
|
|
255
|
-
originalDateNow = Date.now
|
|
256
|
-
mockNow = 1000000
|
|
257
|
-
Date.now = () => mockNow
|
|
258
|
-
resetActivityTracker()
|
|
259
|
-
})
|
|
260
|
-
|
|
261
|
-
afterEach(() => {
|
|
262
|
-
Date.now = originalDateNow
|
|
263
|
-
})
|
|
264
|
-
|
|
265
|
-
describe('pauseWhenIdle behavior', () => {
|
|
266
|
-
test('isUserActive returns true immediately after reportActivity', () => {
|
|
267
|
-
reportActivity()
|
|
268
|
-
expect(isUserActive(30000)).toBe(true)
|
|
269
|
-
})
|
|
270
|
-
|
|
271
|
-
test('isUserActive returns false after idle threshold passes', () => {
|
|
272
|
-
reportActivity()
|
|
273
|
-
mockNow += 35000 // 35 seconds
|
|
274
|
-
expect(isUserActive(30000)).toBe(false)
|
|
275
|
-
})
|
|
276
|
-
|
|
277
|
-
test('activity tracking prevents polling pause', () => {
|
|
278
|
-
// Simulate user typing every 10 seconds
|
|
279
|
-
reportActivity()
|
|
280
|
-
expect(isUserActive(30000)).toBe(true)
|
|
281
|
-
|
|
282
|
-
mockNow += 10000
|
|
283
|
-
reportActivity()
|
|
284
|
-
expect(isUserActive(30000)).toBe(true)
|
|
285
|
-
|
|
286
|
-
mockNow += 10000
|
|
287
|
-
reportActivity()
|
|
288
|
-
expect(isUserActive(30000)).toBe(true)
|
|
289
|
-
|
|
290
|
-
// User is continuously active - polling should continue
|
|
291
|
-
})
|
|
292
|
-
|
|
293
|
-
test('prolonged inactivity should trigger idle state', () => {
|
|
294
|
-
reportActivity()
|
|
295
|
-
|
|
296
|
-
// Simulate no activity for 60 seconds
|
|
297
|
-
mockNow += 60000
|
|
298
|
-
|
|
299
|
-
expect(isUserActive(30000)).toBe(false)
|
|
300
|
-
expect(getIdleTime()).toBe(60000)
|
|
301
|
-
})
|
|
302
|
-
})
|
|
303
|
-
|
|
304
|
-
describe('refetchOnActivity behavior', () => {
|
|
305
|
-
test('activity notification triggers listeners for refetch', () => {
|
|
306
|
-
const refetchCallback = mock(() => {})
|
|
307
|
-
subscribeToActivity(refetchCallback)
|
|
308
|
-
|
|
309
|
-
// User was idle
|
|
310
|
-
mockNow += 35000
|
|
311
|
-
expect(isUserActive(30000)).toBe(false)
|
|
312
|
-
|
|
313
|
-
// User becomes active - should notify listeners
|
|
314
|
-
reportActivity()
|
|
315
|
-
|
|
316
|
-
expect(refetchCallback).toHaveBeenCalledTimes(1)
|
|
317
|
-
expect(refetchCallback).toHaveBeenCalledWith(mockNow)
|
|
318
|
-
})
|
|
319
|
-
|
|
320
|
-
test('multiple listeners all receive activity notifications', () => {
|
|
321
|
-
const callback1 = mock(() => {})
|
|
322
|
-
const callback2 = mock(() => {})
|
|
323
|
-
const callback3 = mock(() => {})
|
|
324
|
-
|
|
325
|
-
subscribeToActivity(callback1)
|
|
326
|
-
subscribeToActivity(callback2)
|
|
327
|
-
subscribeToActivity(callback3)
|
|
328
|
-
|
|
329
|
-
reportActivity()
|
|
330
|
-
|
|
331
|
-
expect(callback1).toHaveBeenCalledTimes(1)
|
|
332
|
-
expect(callback2).toHaveBeenCalledTimes(1)
|
|
333
|
-
expect(callback3).toHaveBeenCalledTimes(1)
|
|
334
|
-
})
|
|
335
|
-
|
|
336
|
-
test('unsubscribed listeners do not receive notifications', () => {
|
|
337
|
-
const activeCallback = mock(() => {})
|
|
338
|
-
const unsubscribedCallback = mock(() => {})
|
|
339
|
-
|
|
340
|
-
subscribeToActivity(activeCallback)
|
|
341
|
-
const unsub = subscribeToActivity(unsubscribedCallback)
|
|
342
|
-
|
|
343
|
-
// Unsubscribe one listener
|
|
344
|
-
unsub()
|
|
345
|
-
|
|
346
|
-
reportActivity()
|
|
347
|
-
|
|
348
|
-
expect(activeCallback).toHaveBeenCalledTimes(1)
|
|
349
|
-
expect(unsubscribedCallback).not.toHaveBeenCalled()
|
|
350
|
-
})
|
|
351
|
-
})
|
|
352
|
-
|
|
353
|
-
describe('Claude quota polling scenarios', () => {
|
|
354
|
-
test('idle user should not trigger quota polling', () => {
|
|
355
|
-
const idleThreshold = 30000
|
|
356
|
-
|
|
357
|
-
// User was active
|
|
358
|
-
reportActivity()
|
|
359
|
-
|
|
360
|
-
// 60 seconds pass with no activity
|
|
361
|
-
mockNow += 60000
|
|
362
|
-
|
|
363
|
-
// User is idle
|
|
364
|
-
expect(isUserActive(idleThreshold)).toBe(false)
|
|
365
|
-
|
|
366
|
-
// When pauseWhenIdle is true, polling tick should skip refetch
|
|
367
|
-
// (tested in use-activity-query: if (pauseWhenIdle && !isUserActive(idleThreshold)) return)
|
|
368
|
-
})
|
|
369
|
-
|
|
370
|
-
test('returning user after idle should trigger stale data refetch', () => {
|
|
371
|
-
const idleThreshold = 30000
|
|
372
|
-
const wasIdleCallback = mock(() => {})
|
|
373
|
-
|
|
374
|
-
// Simulate wasIdleRef pattern from useActivityQuery
|
|
375
|
-
let wasIdle = false
|
|
376
|
-
|
|
377
|
-
subscribeToActivity(() => {
|
|
378
|
-
if (wasIdle) {
|
|
379
|
-
wasIdleCallback()
|
|
380
|
-
wasIdle = false
|
|
381
|
-
}
|
|
382
|
-
})
|
|
383
|
-
|
|
384
|
-
// User is initially active
|
|
385
|
-
reportActivity()
|
|
386
|
-
|
|
387
|
-
// User goes idle
|
|
388
|
-
mockNow += 35000
|
|
389
|
-
wasIdle = !isUserActive(idleThreshold)
|
|
390
|
-
expect(wasIdle).toBe(true)
|
|
391
|
-
|
|
392
|
-
// User returns
|
|
393
|
-
reportActivity()
|
|
394
|
-
|
|
395
|
-
// Should have triggered the "returning from idle" callback
|
|
396
|
-
expect(wasIdleCallback).toHaveBeenCalledTimes(1)
|
|
397
|
-
})
|
|
398
|
-
|
|
399
|
-
test('continuous activity should not set wasIdle flag', () => {
|
|
400
|
-
const idleThreshold = 30000
|
|
401
|
-
|
|
402
|
-
// User types every 10 seconds
|
|
403
|
-
for (let i = 0; i < 10; i++) {
|
|
404
|
-
reportActivity()
|
|
405
|
-
mockNow += 10000
|
|
406
|
-
|
|
407
|
-
// User never goes idle
|
|
408
|
-
expect(isUserActive(idleThreshold)).toBe(true)
|
|
409
|
-
}
|
|
410
|
-
})
|
|
411
|
-
})
|
|
412
|
-
|
|
413
|
-
describe('edge cases', () => {
|
|
414
|
-
test('very short idle threshold', () => {
|
|
415
|
-
reportActivity()
|
|
416
|
-
mockNow += 100 // 0.1 seconds
|
|
417
|
-
expect(isUserActive(100)).toBe(false)
|
|
418
|
-
})
|
|
419
|
-
|
|
420
|
-
test('very long idle threshold', () => {
|
|
421
|
-
reportActivity()
|
|
422
|
-
mockNow += 3600000 // 1 hour
|
|
423
|
-
expect(isUserActive(7200000)).toBe(true) // 2 hour threshold
|
|
424
|
-
})
|
|
425
|
-
|
|
426
|
-
test('activity reported multiple times in quick succession', () => {
|
|
427
|
-
const callback = mock(() => {})
|
|
428
|
-
subscribeToActivity(callback)
|
|
429
|
-
|
|
430
|
-
// Rapid activity reporting (e.g., typing fast)
|
|
431
|
-
for (let i = 0; i < 100; i++) {
|
|
432
|
-
mockNow += 10 // 10ms between keystrokes
|
|
433
|
-
reportActivity()
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
expect(callback).toHaveBeenCalledTimes(100)
|
|
437
|
-
expect(getLastActivityTime()).toBe(mockNow)
|
|
438
|
-
})
|
|
439
|
-
})
|
|
440
|
-
})
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from 'bun:test'
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
getAgentDisplayPrompt,
|
|
5
|
-
getBasherFinishedOutputPreview,
|
|
6
|
-
truncateToSingleLinePreview,
|
|
7
|
-
} from '../agent-display'
|
|
8
|
-
|
|
9
|
-
import type { AgentContentBlock } from '../../types/chat'
|
|
10
|
-
|
|
11
|
-
const createAgentBlock = (
|
|
12
|
-
overrides: Partial<AgentContentBlock>,
|
|
13
|
-
): AgentContentBlock => ({
|
|
14
|
-
type: 'agent',
|
|
15
|
-
agentId: 'agent-1',
|
|
16
|
-
agentName: 'Basher',
|
|
17
|
-
agentType: 'basher',
|
|
18
|
-
content: '',
|
|
19
|
-
status: 'running',
|
|
20
|
-
blocks: [],
|
|
21
|
-
initialPrompt: '',
|
|
22
|
-
...overrides,
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
describe('getAgentDisplayPrompt', () => {
|
|
26
|
-
test('uses initial prompt when present', () => {
|
|
27
|
-
const block = createAgentBlock({
|
|
28
|
-
initialPrompt: 'Run tests',
|
|
29
|
-
params: {
|
|
30
|
-
what_to_summarize: 'Summarize failures',
|
|
31
|
-
},
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
expect(getAgentDisplayPrompt(block)).toBe('Run tests')
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
test('uses basher what_to_summarize when prompt is omitted', () => {
|
|
38
|
-
const block = createAgentBlock({
|
|
39
|
-
params: {
|
|
40
|
-
command: 'bun test',
|
|
41
|
-
what_to_summarize: 'Summarize failing tests only',
|
|
42
|
-
},
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
expect(getAgentDisplayPrompt(block)).toBe('Summarize failing tests only')
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
test('normalizes scoped and versioned basher agent ids', () => {
|
|
49
|
-
const block = createAgentBlock({
|
|
50
|
-
agentType: 'anvil/basher@1.0.0',
|
|
51
|
-
params: {
|
|
52
|
-
what_to_summarize: 'Summarize command output',
|
|
53
|
-
},
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
expect(getAgentDisplayPrompt(block)).toBe('Summarize command output')
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
test('ignores non-basher what_to_summarize params', () => {
|
|
60
|
-
const block = createAgentBlock({
|
|
61
|
-
agentName: 'code-searcher',
|
|
62
|
-
agentType: 'code-searcher',
|
|
63
|
-
params: {
|
|
64
|
-
what_to_summarize: 'This is not a basher prompt',
|
|
65
|
-
},
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
expect(getAgentDisplayPrompt(block)).toBeUndefined()
|
|
69
|
-
})
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
describe('getBasherFinishedOutputPreview', () => {
|
|
73
|
-
test('returns undefined while basher is still running', () => {
|
|
74
|
-
const block = createAgentBlock({
|
|
75
|
-
status: 'running',
|
|
76
|
-
params: {
|
|
77
|
-
what_to_summarize: 'Report the test result',
|
|
78
|
-
},
|
|
79
|
-
blocks: [{ type: 'text', content: 'Tests passed' }],
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
expect(getBasherFinishedOutputPreview(block)).toBeUndefined()
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
test('uses finished basher text output before what_to_summarize', () => {
|
|
86
|
-
const block = createAgentBlock({
|
|
87
|
-
status: 'complete',
|
|
88
|
-
params: {
|
|
89
|
-
what_to_summarize: 'Report the test result',
|
|
90
|
-
},
|
|
91
|
-
blocks: [
|
|
92
|
-
{
|
|
93
|
-
type: 'text',
|
|
94
|
-
content: 'Tests passed\n42 assertions completed',
|
|
95
|
-
textType: 'text',
|
|
96
|
-
},
|
|
97
|
-
],
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
expect(getBasherFinishedOutputPreview(block)).toBe(
|
|
101
|
-
'Tests passed 42 assertions completed',
|
|
102
|
-
)
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
test('falls back to command output when no text block exists', () => {
|
|
106
|
-
const block = createAgentBlock({
|
|
107
|
-
status: 'complete',
|
|
108
|
-
blocks: [
|
|
109
|
-
{
|
|
110
|
-
type: 'tool',
|
|
111
|
-
toolCallId: 'tool-1',
|
|
112
|
-
toolName: 'run_terminal_command',
|
|
113
|
-
input: { command: 'git status --short' },
|
|
114
|
-
output: ' M cli/src/app.tsx\n',
|
|
115
|
-
},
|
|
116
|
-
],
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
expect(getBasherFinishedOutputPreview(block)).toBe('M cli/src/app.tsx')
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
test('ignores non-basher output', () => {
|
|
123
|
-
const block = createAgentBlock({
|
|
124
|
-
agentType: 'code-searcher',
|
|
125
|
-
status: 'complete',
|
|
126
|
-
blocks: [{ type: 'text', content: 'Search results' }],
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
expect(getBasherFinishedOutputPreview(block)).toBeUndefined()
|
|
130
|
-
})
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
describe('truncateToSingleLinePreview', () => {
|
|
134
|
-
test('collapses whitespace and truncates to the requested length', () => {
|
|
135
|
-
expect(truncateToSingleLinePreview('one\ntwo three four', 13)).toBe(
|
|
136
|
-
'one two th...',
|
|
137
|
-
)
|
|
138
|
-
})
|
|
139
|
-
})
|