@alumbwe/anvil 1.0.42 → 1.0.49
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,217 +0,0 @@
|
|
|
1
|
-
import { describe, test, expect } from 'bun:test'
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
ANVIL_STREAK_INLINE_GAP,
|
|
5
|
-
fitsAnvilStreakOnHeadingRow,
|
|
6
|
-
getAnvilStreakBonusNote,
|
|
7
|
-
getAnvilStreakBonusNoteForLayout,
|
|
8
|
-
getAnvilStreakInlineWidth,
|
|
9
|
-
getAnvilStreakLine,
|
|
10
|
-
} from '../anvil-streak-line'
|
|
11
|
-
|
|
12
|
-
// The CLI draws the shared ●/○ pair: filled-vs-hollow is what makes a partial
|
|
13
|
-
// week distinguishable from a full one at a glance, which • and · (same shape,
|
|
14
|
-
// different size) never managed.
|
|
15
|
-
describe('getAnvilStreakLine', () => {
|
|
16
|
-
test('hides the row for new / lapsed users (streak <= 0)', () => {
|
|
17
|
-
expect(getAnvilStreakLine(0)).toBeNull()
|
|
18
|
-
expect(getAnvilStreakLine(-1)).toBeNull()
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
test('labels and fills dots for an active streak', () => {
|
|
22
|
-
expect(getAnvilStreakLine(2)).toEqual({
|
|
23
|
-
label: '2 day streak',
|
|
24
|
-
dots: '●●○○○○○',
|
|
25
|
-
progress: { filled: 2, total: 7, beyond: false },
|
|
26
|
-
})
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
test('"day" stays singular as a compound modifier', () => {
|
|
30
|
-
expect(getAnvilStreakLine(1)?.label).toBe('1 day streak')
|
|
31
|
-
expect(getAnvilStreakLine(5)?.label).toBe('5 day streak')
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
test('fills the whole week on a 7-day milestone', () => {
|
|
35
|
-
expect(getAnvilStreakLine(7)).toEqual({
|
|
36
|
-
label: '7 day streak',
|
|
37
|
-
dots: '●●●●●●●',
|
|
38
|
-
// filled === total is how a surface without the constant knows the
|
|
39
|
-
// milestone is earned (the desktop banner gates its perk line on it)
|
|
40
|
-
progress: { filled: 7, total: 7, beyond: false },
|
|
41
|
-
})
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
test('stays full and gains a "+" once the streak passes the week', () => {
|
|
45
|
-
expect(getAnvilStreakLine(9)).toEqual({
|
|
46
|
-
label: '9 day streak',
|
|
47
|
-
dots: '●●●●●●●+',
|
|
48
|
-
progress: { filled: 7, total: 7, beyond: true },
|
|
49
|
-
})
|
|
50
|
-
expect(getAnvilStreakLine(19)).toEqual({
|
|
51
|
-
label: '19 day streak',
|
|
52
|
-
dots: '●●●●●●●+',
|
|
53
|
-
progress: { filled: 7, total: 7, beyond: true },
|
|
54
|
-
})
|
|
55
|
-
})
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
describe('fitsAnvilStreakOnHeadingRow', () => {
|
|
59
|
-
const headingWidth = 'Start coding for free'.length
|
|
60
|
-
const line = getAnvilStreakLine(18)!
|
|
61
|
-
// "18 day streak" + 2 + "●●●●●●●+"
|
|
62
|
-
const inlineWidth = getAnvilStreakInlineWidth(line)
|
|
63
|
-
const exact = headingWidth + ANVIL_STREAK_INLINE_GAP + inlineWidth
|
|
64
|
-
|
|
65
|
-
test('measures the label and dots together', () => {
|
|
66
|
-
expect(inlineWidth).toBe(23)
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
test('shares the row only when the gap is fully clear', () => {
|
|
70
|
-
expect(
|
|
71
|
-
fitsAnvilStreakOnHeadingRow({
|
|
72
|
-
line,
|
|
73
|
-
headingWidth,
|
|
74
|
-
availableWidth: exact,
|
|
75
|
-
}),
|
|
76
|
-
).toBe(true)
|
|
77
|
-
expect(
|
|
78
|
-
fitsAnvilStreakOnHeadingRow({
|
|
79
|
-
line,
|
|
80
|
-
headingWidth,
|
|
81
|
-
availableWidth: exact - 1,
|
|
82
|
-
}),
|
|
83
|
-
).toBe(false)
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
test('measures an empty slot as the day-one streak it will become', () => {
|
|
87
|
-
const dayOne = getAnvilStreakLine(1)!
|
|
88
|
-
const width = headingWidth + ANVIL_STREAK_INLINE_GAP
|
|
89
|
-
expect(
|
|
90
|
-
fitsAnvilStreakOnHeadingRow({
|
|
91
|
-
line: null,
|
|
92
|
-
headingWidth,
|
|
93
|
-
availableWidth: width + getAnvilStreakInlineWidth(dayOne),
|
|
94
|
-
}),
|
|
95
|
-
).toBe(true)
|
|
96
|
-
expect(
|
|
97
|
-
fitsAnvilStreakOnHeadingRow({
|
|
98
|
-
line: null,
|
|
99
|
-
headingWidth,
|
|
100
|
-
availableWidth: width + getAnvilStreakInlineWidth(dayOne) - 1,
|
|
101
|
-
}),
|
|
102
|
-
).toBe(false)
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
// A three-digit streak widens its own label, so the cutoff has to follow the
|
|
106
|
-
// rendered strings rather than a fixed column count.
|
|
107
|
-
test('accounts for the label growing with the day count', () => {
|
|
108
|
-
const long = getAnvilStreakLine(365)!
|
|
109
|
-
expect(getAnvilStreakInlineWidth(long)).toBeGreaterThan(inlineWidth)
|
|
110
|
-
expect(
|
|
111
|
-
fitsAnvilStreakOnHeadingRow({
|
|
112
|
-
line: long,
|
|
113
|
-
headingWidth,
|
|
114
|
-
availableWidth: exact,
|
|
115
|
-
}),
|
|
116
|
-
).toBe(false)
|
|
117
|
-
})
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
describe('getAnvilStreakBonusNote', () => {
|
|
121
|
-
test('hidden with no streak at all', () => {
|
|
122
|
-
expect(
|
|
123
|
-
getAnvilStreakBonusNote({ streak: 0, accessTier: 'full' }),
|
|
124
|
-
).toBeNull()
|
|
125
|
-
expect(
|
|
126
|
-
getAnvilStreakBonusNote({ streak: -1, accessTier: 'limited' }),
|
|
127
|
-
).toBeNull()
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
test('teases the unlock countdown below the 7-day milestone', () => {
|
|
131
|
-
expect(getAnvilStreakBonusNote({ streak: 3, accessTier: 'full' })).toBe(
|
|
132
|
-
'🎁 4 more days to unlock +1 bonus session every day + 1 GLM 5.2 session each day',
|
|
133
|
-
)
|
|
134
|
-
expect(
|
|
135
|
-
getAnvilStreakBonusNote({ streak: 3, accessTier: 'limited' }),
|
|
136
|
-
).toBe('🎁 4 more days to unlock +1 bonus session every day')
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
test('"day" goes singular on the eve of the milestone', () => {
|
|
140
|
-
expect(
|
|
141
|
-
getAnvilStreakBonusNote({ streak: 6, accessTier: 'limited' }),
|
|
142
|
-
).toBe('🎁 1 more day to unlock +1 bonus session every day')
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
test('full access advertises the daily session + daily GLM perk at 7+', () => {
|
|
146
|
-
const note = getAnvilStreakBonusNote({ streak: 7, accessTier: 'full' })
|
|
147
|
-
expect(note).toBe(
|
|
148
|
-
'🎁 Streak perk: +1 bonus session every day + 1 GLM 5.2 session each day',
|
|
149
|
-
)
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
test('the GLM streak count grows per completed 7 days, capped at 4', () => {
|
|
153
|
-
expect(getAnvilStreakBonusNote({ streak: 14, accessTier: 'full' })).toBe(
|
|
154
|
-
'🎁 Streak perk: +1 bonus session every day + 2 GLM 5.2 sessions each day',
|
|
155
|
-
)
|
|
156
|
-
expect(getAnvilStreakBonusNote({ streak: 35, accessTier: 'full' })).toBe(
|
|
157
|
-
'🎁 Streak perk: +1 bonus session every day + 4 GLM 5.2 sessions each day',
|
|
158
|
-
)
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
test('limited access advertises only the daily session perk', () => {
|
|
162
|
-
const note = getAnvilStreakBonusNote({
|
|
163
|
-
streak: 14,
|
|
164
|
-
accessTier: 'limited',
|
|
165
|
-
})
|
|
166
|
-
expect(note).toBe('🎁 Streak perk: +1 bonus session every day')
|
|
167
|
-
})
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
describe('getAnvilStreakBonusNoteForLayout', () => {
|
|
171
|
-
const params = {
|
|
172
|
-
streak: 7,
|
|
173
|
-
accessTier: 'full' as const,
|
|
174
|
-
}
|
|
175
|
-
const note = getAnvilStreakBonusNote(params)!
|
|
176
|
-
|
|
177
|
-
test('hides the unlock countdown before the bonus is earned', () => {
|
|
178
|
-
expect(
|
|
179
|
-
getAnvilStreakBonusNoteForLayout({
|
|
180
|
-
...params,
|
|
181
|
-
streak: 6,
|
|
182
|
-
terminalHeight: 30,
|
|
183
|
-
availableWidth: 200,
|
|
184
|
-
}),
|
|
185
|
-
).toBeNull()
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
test('hides the earned note below 30 rows', () => {
|
|
189
|
-
expect(
|
|
190
|
-
getAnvilStreakBonusNoteForLayout({
|
|
191
|
-
...params,
|
|
192
|
-
terminalHeight: 29,
|
|
193
|
-
availableWidth: note.length,
|
|
194
|
-
}),
|
|
195
|
-
).toBeNull()
|
|
196
|
-
})
|
|
197
|
-
|
|
198
|
-
test('shows the earned note at 30 rows when it fits on one line', () => {
|
|
199
|
-
expect(
|
|
200
|
-
getAnvilStreakBonusNoteForLayout({
|
|
201
|
-
...params,
|
|
202
|
-
terminalHeight: 30,
|
|
203
|
-
availableWidth: note.length,
|
|
204
|
-
}),
|
|
205
|
-
).toBe(note)
|
|
206
|
-
})
|
|
207
|
-
|
|
208
|
-
test('hides the earned note when it would wrap', () => {
|
|
209
|
-
expect(
|
|
210
|
-
getAnvilStreakBonusNoteForLayout({
|
|
211
|
-
...params,
|
|
212
|
-
terminalHeight: 30,
|
|
213
|
-
availableWidth: note.length - 1,
|
|
214
|
-
}),
|
|
215
|
-
).toBeNull()
|
|
216
|
-
})
|
|
217
|
-
})
|
|
@@ -1,264 +0,0 @@
|
|
|
1
|
-
import { describe, test, expect, beforeEach } from 'bun:test'
|
|
2
|
-
|
|
3
|
-
import { Queue } from '../arrays'
|
|
4
|
-
|
|
5
|
-
describe('Queue', () => {
|
|
6
|
-
describe('constructor', () => {
|
|
7
|
-
test('creates empty queue', () => {
|
|
8
|
-
const q = new Queue<number>()
|
|
9
|
-
expect(q.length).toBe(0)
|
|
10
|
-
expect(q.peek()).toBeUndefined()
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
test('creates queue from array', () => {
|
|
14
|
-
const q = new Queue([1, 2, 3])
|
|
15
|
-
expect(q.length).toBe(3)
|
|
16
|
-
expect(q.peek()).toBe(1)
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
test('allocates extra capacity', () => {
|
|
20
|
-
const q = new Queue([1, 2, 3])
|
|
21
|
-
// Should have allocated double capacity (3 items + 3 extra)
|
|
22
|
-
q.enqueue(4, 5, 6)
|
|
23
|
-
expect(q.length).toBe(6)
|
|
24
|
-
})
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
describe('Queue.from', () => {
|
|
28
|
-
test('creates queue from iterable', () => {
|
|
29
|
-
const q = Queue.from([1, 2, 3])
|
|
30
|
-
expect(q.length).toBe(3)
|
|
31
|
-
expect(q.dequeue()).toBe(1)
|
|
32
|
-
expect(q.dequeue()).toBe(2)
|
|
33
|
-
expect(q.dequeue()).toBe(3)
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
test('creates queue from Set', () => {
|
|
37
|
-
const q = Queue.from(new Set([1, 2, 3]))
|
|
38
|
-
expect(q.length).toBe(3)
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
test('creates empty queue from empty iterable', () => {
|
|
42
|
-
const q = Queue.from([])
|
|
43
|
-
expect(q.length).toBe(0)
|
|
44
|
-
})
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
describe('enqueue', () => {
|
|
48
|
-
test('adds single item', () => {
|
|
49
|
-
const q = new Queue<number>()
|
|
50
|
-
q.enqueue(1)
|
|
51
|
-
expect(q.length).toBe(1)
|
|
52
|
-
expect(q.peek()).toBe(1)
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
test('adds multiple items', () => {
|
|
56
|
-
const q = new Queue<number>()
|
|
57
|
-
q.enqueue(1, 2, 3)
|
|
58
|
-
expect(q.length).toBe(3)
|
|
59
|
-
expect(q.dequeue()).toBe(1)
|
|
60
|
-
expect(q.dequeue()).toBe(2)
|
|
61
|
-
expect(q.dequeue()).toBe(3)
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
test('grows capacity when needed', () => {
|
|
65
|
-
const q = new Queue([1])
|
|
66
|
-
// Initial capacity is 2 (1 item + 1 extra)
|
|
67
|
-
q.enqueue(2, 3, 4)
|
|
68
|
-
expect(q.length).toBe(4)
|
|
69
|
-
expect(q.dequeue()).toBe(1)
|
|
70
|
-
expect(q.dequeue()).toBe(2)
|
|
71
|
-
expect(q.dequeue()).toBe(3)
|
|
72
|
-
expect(q.dequeue()).toBe(4)
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
test('handles wrap-around correctly', () => {
|
|
76
|
-
const q = new Queue([1, 2, 3])
|
|
77
|
-
q.dequeue() // Remove 1, head moves to index 1
|
|
78
|
-
q.dequeue() // Remove 2, head moves to index 2
|
|
79
|
-
q.enqueue(4, 5) // Should wrap around
|
|
80
|
-
expect(q.length).toBe(3)
|
|
81
|
-
expect(q.dequeue()).toBe(3)
|
|
82
|
-
expect(q.dequeue()).toBe(4)
|
|
83
|
-
expect(q.dequeue()).toBe(5)
|
|
84
|
-
})
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
describe('dequeue', () => {
|
|
88
|
-
test('removes and returns first item', () => {
|
|
89
|
-
const q = new Queue([1, 2, 3])
|
|
90
|
-
expect(q.dequeue()).toBe(1)
|
|
91
|
-
expect(q.length).toBe(2)
|
|
92
|
-
expect(q.peek()).toBe(2)
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
test('returns undefined when empty', () => {
|
|
96
|
-
const q = new Queue<number>()
|
|
97
|
-
expect(q.dequeue()).toBeUndefined()
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
test('maintains FIFO order', () => {
|
|
101
|
-
const q = new Queue<number>()
|
|
102
|
-
q.enqueue(1, 2, 3, 4, 5)
|
|
103
|
-
expect(q.dequeue()).toBe(1)
|
|
104
|
-
expect(q.dequeue()).toBe(2)
|
|
105
|
-
expect(q.dequeue()).toBe(3)
|
|
106
|
-
expect(q.dequeue()).toBe(4)
|
|
107
|
-
expect(q.dequeue()).toBe(5)
|
|
108
|
-
expect(q.dequeue()).toBeUndefined()
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
test('wraps head pointer correctly', () => {
|
|
112
|
-
const q = new Queue([1, 2])
|
|
113
|
-
q.dequeue()
|
|
114
|
-
q.dequeue()
|
|
115
|
-
q.enqueue(3, 4)
|
|
116
|
-
expect(q.dequeue()).toBe(3)
|
|
117
|
-
expect(q.dequeue()).toBe(4)
|
|
118
|
-
})
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
describe('peek', () => {
|
|
122
|
-
test('returns first item without removing', () => {
|
|
123
|
-
const q = new Queue([1, 2, 3])
|
|
124
|
-
expect(q.peek()).toBe(1)
|
|
125
|
-
expect(q.length).toBe(3)
|
|
126
|
-
expect(q.peek()).toBe(1)
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
test('returns undefined when empty', () => {
|
|
130
|
-
const q = new Queue<number>()
|
|
131
|
-
expect(q.peek()).toBeUndefined()
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
test('tracks changes after dequeue', () => {
|
|
135
|
-
const q = new Queue([1, 2, 3])
|
|
136
|
-
q.dequeue()
|
|
137
|
-
expect(q.peek()).toBe(2)
|
|
138
|
-
q.dequeue()
|
|
139
|
-
expect(q.peek()).toBe(3)
|
|
140
|
-
})
|
|
141
|
-
})
|
|
142
|
-
|
|
143
|
-
describe('at', () => {
|
|
144
|
-
let q: Queue<number>
|
|
145
|
-
|
|
146
|
-
beforeEach(() => {
|
|
147
|
-
q = new Queue([1, 2, 3, 4, 5])
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
test('returns element at positive index', () => {
|
|
151
|
-
expect(q.at(0)).toBe(1)
|
|
152
|
-
expect(q.at(1)).toBe(2)
|
|
153
|
-
expect(q.at(2)).toBe(3)
|
|
154
|
-
expect(q.at(4)).toBe(5)
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
test('returns element at negative index', () => {
|
|
158
|
-
expect(q.at(-1)).toBe(5)
|
|
159
|
-
expect(q.at(-2)).toBe(4)
|
|
160
|
-
expect(q.at(-5)).toBe(1)
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
test('returns undefined for out of bounds index', () => {
|
|
164
|
-
expect(q.at(5)).toBeUndefined()
|
|
165
|
-
expect(q.at(100)).toBeUndefined()
|
|
166
|
-
expect(q.at(-6)).toBeUndefined()
|
|
167
|
-
expect(q.at(-100)).toBeUndefined()
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
test('handles wrap-around correctly', () => {
|
|
171
|
-
q.dequeue() // Remove 1
|
|
172
|
-
q.dequeue() // Remove 2
|
|
173
|
-
q.enqueue(6, 7) // Add to wrapped positions
|
|
174
|
-
expect(q.at(0)).toBe(3)
|
|
175
|
-
expect(q.at(1)).toBe(4)
|
|
176
|
-
expect(q.at(2)).toBe(5)
|
|
177
|
-
expect(q.at(3)).toBe(6)
|
|
178
|
-
expect(q.at(4)).toBe(7)
|
|
179
|
-
expect(q.at(-1)).toBe(7)
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
test('returns undefined for empty queue', () => {
|
|
183
|
-
const emptyQ = new Queue<number>()
|
|
184
|
-
expect(emptyQ.at(0)).toBeUndefined()
|
|
185
|
-
expect(emptyQ.at(-1)).toBeUndefined()
|
|
186
|
-
})
|
|
187
|
-
})
|
|
188
|
-
|
|
189
|
-
describe('length', () => {
|
|
190
|
-
test('tracks queue size', () => {
|
|
191
|
-
const q = new Queue<number>()
|
|
192
|
-
expect(q.length).toBe(0)
|
|
193
|
-
q.enqueue(1)
|
|
194
|
-
expect(q.length).toBe(1)
|
|
195
|
-
q.enqueue(2, 3)
|
|
196
|
-
expect(q.length).toBe(3)
|
|
197
|
-
q.dequeue()
|
|
198
|
-
expect(q.length).toBe(2)
|
|
199
|
-
q.dequeue()
|
|
200
|
-
q.dequeue()
|
|
201
|
-
expect(q.length).toBe(0)
|
|
202
|
-
})
|
|
203
|
-
|
|
204
|
-
test('maintains correct length through wrap-around', () => {
|
|
205
|
-
const q = new Queue([1, 2])
|
|
206
|
-
q.dequeue()
|
|
207
|
-
q.enqueue(3)
|
|
208
|
-
expect(q.length).toBe(2)
|
|
209
|
-
q.dequeue()
|
|
210
|
-
expect(q.length).toBe(1)
|
|
211
|
-
})
|
|
212
|
-
})
|
|
213
|
-
|
|
214
|
-
describe('edge cases', () => {
|
|
215
|
-
test('handles alternating enqueue/dequeue', () => {
|
|
216
|
-
const q = new Queue<number>()
|
|
217
|
-
q.enqueue(1)
|
|
218
|
-
expect(q.dequeue()).toBe(1)
|
|
219
|
-
q.enqueue(2)
|
|
220
|
-
expect(q.dequeue()).toBe(2)
|
|
221
|
-
q.enqueue(3)
|
|
222
|
-
expect(q.dequeue()).toBe(3)
|
|
223
|
-
})
|
|
224
|
-
|
|
225
|
-
test('handles different data types', () => {
|
|
226
|
-
const stringQ = new Queue(['a', 'b', 'c'])
|
|
227
|
-
expect(stringQ.dequeue()).toBe('a')
|
|
228
|
-
|
|
229
|
-
const objectQ = new Queue([{ id: 1 }, { id: 2 }])
|
|
230
|
-
expect(objectQ.dequeue()).toEqual({ id: 1 })
|
|
231
|
-
|
|
232
|
-
const mixedQ = new Queue<string | number>([1, 'two', 3])
|
|
233
|
-
expect(mixedQ.dequeue()).toBe(1)
|
|
234
|
-
expect(mixedQ.dequeue()).toBe('two')
|
|
235
|
-
})
|
|
236
|
-
|
|
237
|
-
test('maintains integrity after capacity expansion', () => {
|
|
238
|
-
const q = new Queue([1, 2])
|
|
239
|
-
// Trigger expansion
|
|
240
|
-
q.enqueue(3, 4, 5, 6, 7, 8)
|
|
241
|
-
expect(q.length).toBe(8)
|
|
242
|
-
for (let i = 1; i <= 8; i++) {
|
|
243
|
-
expect(q.dequeue()).toBe(i)
|
|
244
|
-
}
|
|
245
|
-
})
|
|
246
|
-
|
|
247
|
-
test('handles large number of operations', () => {
|
|
248
|
-
const q = new Queue<number>()
|
|
249
|
-
const iterations = 1000
|
|
250
|
-
|
|
251
|
-
// Enqueue many items
|
|
252
|
-
for (let i = 0; i < iterations; i++) {
|
|
253
|
-
q.enqueue(i)
|
|
254
|
-
}
|
|
255
|
-
expect(q.length).toBe(iterations)
|
|
256
|
-
|
|
257
|
-
// Dequeue all items
|
|
258
|
-
for (let i = 0; i < iterations; i++) {
|
|
259
|
-
expect(q.dequeue()).toBe(i)
|
|
260
|
-
}
|
|
261
|
-
expect(q.length).toBe(0)
|
|
262
|
-
})
|
|
263
|
-
})
|
|
264
|
-
})
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from 'bun:test'
|
|
2
|
-
|
|
3
|
-
import { processBashContext } from '../bash-context-processor'
|
|
4
|
-
|
|
5
|
-
import type { PendingBashMessage } from '../../types/store'
|
|
6
|
-
|
|
7
|
-
const createPendingBash = (
|
|
8
|
-
overrides: Partial<PendingBashMessage> = {},
|
|
9
|
-
): PendingBashMessage => ({
|
|
10
|
-
id: overrides.id ?? crypto.randomUUID(),
|
|
11
|
-
command: overrides.command ?? 'echo "hi"',
|
|
12
|
-
stdout: overrides.stdout ?? 'hi',
|
|
13
|
-
stderr: overrides.stderr ?? '',
|
|
14
|
-
exitCode: overrides.exitCode ?? 0,
|
|
15
|
-
isRunning: overrides.isRunning ?? false,
|
|
16
|
-
cwd: overrides.cwd ?? '/tmp',
|
|
17
|
-
addedToHistory: overrides.addedToHistory,
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
describe('processBashContext', () => {
|
|
21
|
-
test('builds bash messages and context', () => {
|
|
22
|
-
const pending = [
|
|
23
|
-
createPendingBash({ id: '1', command: 'echo hi' }),
|
|
24
|
-
createPendingBash({
|
|
25
|
-
id: '2',
|
|
26
|
-
command: 'ls',
|
|
27
|
-
addedToHistory: true,
|
|
28
|
-
}),
|
|
29
|
-
]
|
|
30
|
-
|
|
31
|
-
const { bashMessages, bashContextForPrompt } = processBashContext(pending)
|
|
32
|
-
|
|
33
|
-
expect(bashMessages).toHaveLength(1)
|
|
34
|
-
expect(bashMessages[0].blocks?.[0].type).toBe('tool')
|
|
35
|
-
expect(bashContextForPrompt).toContain('Command: echo hi')
|
|
36
|
-
expect(bashContextForPrompt).toContain('Command: ls')
|
|
37
|
-
})
|
|
38
|
-
})
|