René's URL Explorer Experiment


Title: Add a live word / character count indicator to the chat composer by DragonnZhang · Pull Request #61 · modelstudioai/openwork · GitHub

Open Graph Title: Add a live word / character count indicator to the chat composer by DragonnZhang · Pull Request #61 · modelstudioai/openwork

X Title: Add a live word / character count indicator to the chat composer by DragonnZhang · Pull Request #61 · modelstudioai/openwork

Description: Closes #60 What & why OpenWork's chat composer (FreeFormInput) gave no feedback about how much you've written. The toolbar already surfaces a context-usage indicator, a model picker, a thinking-level picker and an attach control — but there was no length feedback for the draft itself, which comparable desktop composers/editors (Codex desktop, VS Code / Google Docs status bars, the Claude/ChatGPT message boxes) all provide. This adds a small, unobtrusive draft count indicator to the composer toolbar: shows the word count inline (e.g. Words: 12), only while the composer has non-whitespace text — so the empty composer stays clean; a hover tooltip breaks down the full stats: Words, Characters, and Lines; counts update live per keystroke, derived from the existing controlled input text (no new state, no persistence); hidden in compactMode (mirroring the context / thinking / model controls) and hidden entirely when the draft is empty. Frontend-only. No qwen-code backend change — the composer already stores the draft as a plain-text string, so the indicator is pure derived state. Changes lib/composer-count.ts — pure computeComposerCounts / shouldShowComposerCount helpers (Unicode-aware character count via code points, whitespace-collapsing word count, newline-based line count), DOM-free and unit-tested. components/app-shell/input/ComposerCountIndicator.tsx — the indicator: renders null for an empty draft, shows the word count inline with the full breakdown in a tooltip, and exposes data-word-count / data-char-count / data-line-count for e2e. components/app-shell/input/FreeFormInput.tsx — slots the indicator into the toolbar bottom row (between the left badge group and the flex spacer, !compactMode). i18n — three new keys (chat.composerWords, chat.composerCharacters, chat.composerLines) added to all 7 locales, using a plural-neutral label form ("Words: {{count}}") so no per-locale plural categories are needed. e2e/assertions/composer-count.assert.ts — new CDP assertion (below). Verification (DoD) bun run typecheck:all — zero new errors. packages/{core,shared,server-core,server,session-tools-core,ui} all pass clean; apps/electron shows only its 11 pre-existing baseline errors (auto-update.ts owner/repo ×4, a settings-default-thinking test tuple ×5, two test files importing vitest) — none in the files this PR touches. Unit tests — composer-count.test.ts 10/10 pass (empty / whitespace-only, single vs. multiple words, collapsed internal whitespace, multi-line, emoji/Unicode character counting). Touched-area suites (renderer/lib) 141/141 pass; the one unrelated SAFE_MODE_CONFIG failure pre-dates this change. bun run lint:i18n:parity — OK (6 locales, 1545 keys each — +3, all present in every locale). ESLint — clean on the new/changed files. Renderer build (bun run electron:build:renderer) — ✅ builds cleanly. CDP assertion transpiles (bun build e2e/assertions/composer-count.assert.ts) — ✅. CDP e2e assertion (composer-count.assert.ts) Drives the real built app over CDP entirely in the draft (no-session) state — no seeded conversation and no backend: While the composer is empty, the count indicator ([data-testid="composer-count"]) is absent. Real typing (CDP Input.insertText) of hello world makes it appear with data-word-count="2" and data-char-count="11". Appending again updates the counts live to data-word-count="3" / data-char-count="17" — proving per-keystroke reactivity. Selecting-all and deleting the draft makes the indicator disappear again. ⚠️ Local CDP run was blocked by this sandbox's egress policy, not by the feature — the e2e build fails before launch because the Electron binary download (GitHub release host) returns 403 and the libsignal WhatsApp-worker dependency can't be fetched, the same limitation noted on the other open loop-bot PRs. The assertion transpiles and is included so CI / a reviewer can run bun run e2e in an environment with normal network access. Everything that doesn't require launching Electron (typecheck, unit tests, i18n parity, renderer build) passes. Part of the autonomous desktop-feature loop (loop-bot). Generated by Claude Code

Open Graph Description: Closes #60 What & why OpenWork's chat composer (FreeFormInput) gave no feedback about how much you've written. The toolbar already surfaces a context-usage indicator, a model picker, a ...

X Description: Closes #60 What & why OpenWork's chat composer (FreeFormInput) gave no feedback about how much you've written. The toolbar already surfaces a context-usage indicator, a mode...

Opengraph URL: https://github.com/modelstudioai/openwork/pull/61

X: @github

direct link

Domain: github.com

route-pattern/:user_id/:repository/pull/:id/files(.:format)
route-controllerpull_requests
route-actionfiles
fetch-noncev2:007773f4-e1c1-c4bc-b70c-fb0c8cfbb1de
current-catalog-service-hashae870bc5e265a340912cde392f23dad3671a0a881730ffdadd82f2f57d81641b
request-idDE96:190D34:3E32D7:53E0B7:6A5291EA
html-safe-nonce33a20e563b1de1a3ed0c4d377e324e09e388e7333a54dc89e3521f35aa24d05a
visitor-payloadeyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJERTk2OjE5MEQzNDozRTMyRDc6NTNFMEI3OjZBNTI5MUVBIiwidmlzaXRvcl9pZCI6IjkwNDU3MDc5NDE4OTA2NTg3OTQiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ==
visitor-hmac6ed0991eb0a4c80cfe66243ac3bd5895b19d8ccefdd64197e2b414eaf3ccd0ce
hovercard-subject-tagpull_request:3995472797
github-keyboard-shortcutsrepository,pull-request-list,pull-request-conversation,pull-request-files-changed,copilot
google-site-verificationApib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I
octolytics-urlhttps://collector.github.com/github/collect
analytics-location///pull_requests/show/files
fb:app_id1401488693436528
apple-itunes-appapp-id=1477376905, app-argument=https://github.com/modelstudioai/openwork/pull/61/files
twitter:imagehttps://avatars.githubusercontent.com/u/52599892?s=400&v=4
twitter:cardsummary_large_image
og:imagehttps://avatars.githubusercontent.com/u/52599892?s=400&v=4
og:image:altCloses #60 What & why OpenWork's chat composer (FreeFormInput) gave no feedback about how much you've written. The toolbar already surfaces a context-usage indicator, a model picker, a ...
og:site_nameGitHub
og:typeobject
hostnamegithub.com
expected-hostnamegithub.com
Noneb9a586c06a05a7a86fc7e3f4dbd03e42f6869085879aa184aa6369456dbd50fb
turbo-cache-controlno-preview
diff-viewunified
go-importgithub.com/modelstudioai/openwork git https://github.com/modelstudioai/openwork.git
octolytics-dimension-user_id283556804
octolytics-dimension-user_loginmodelstudioai
octolytics-dimension-repository_id1256697754
octolytics-dimension-repository_nwomodelstudioai/openwork
octolytics-dimension-repository_publictrue
octolytics-dimension-repository_is_forkfalse
octolytics-dimension-repository_network_root_id1256697754
octolytics-dimension-repository_network_root_nwomodelstudioai/openwork
turbo-body-classeslogged-out env-production page-responsive full-width
disable-turbotrue
browser-stats-urlhttps://api.github.com/_private/browser/stats
browser-errors-urlhttps://api.github.com/_private/browser/errors
release07a982c1d40157c619b364352b704c3ce66bb332
ui-targetfull
theme-color#1e2327
color-schemelight dark

Links:

Skip to contenthttps://github.com/modelstudioai/openwork/pull/61/files#start-of-content
https://github.com/
Sign in https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fmodelstudioai%2Fopenwork%2Fpull%2F61%2Ffiles
GitHub CopilotWrite better code with AIhttps://github.com/features/copilot
GitHub Copilot appDirect agents from issue to mergehttps://github.com/features/ai/github-app
MCP RegistryNewIntegrate external toolshttps://github.com/mcp
ActionsAutomate any workflowhttps://github.com/features/actions
CodespacesInstant dev environmentshttps://github.com/features/codespaces
IssuesPlan and track workhttps://github.com/features/issues
Code ReviewManage code changeshttps://github.com/features/code-review
GitHub Advanced SecurityFind and fix vulnerabilitieshttps://github.com/security/advanced-security
Code securitySecure your code as you buildhttps://github.com/security/advanced-security/code-security
Secret protectionStop leaks before they starthttps://github.com/security/advanced-security/secret-protection
Why GitHubhttps://github.com/why-github
Documentationhttps://docs.github.com
Bloghttps://github.blog
Changeloghttps://github.blog/changelog
Marketplacehttps://github.com/marketplace
View all featureshttps://github.com/features
Enterpriseshttps://github.com/enterprise
Small and medium teamshttps://github.com/team
Startupshttps://github.com/enterprise/startups
Nonprofitshttps://github.com/solutions/industry/nonprofits
App Modernizationhttps://github.com/solutions/use-case/app-modernization
DevSecOpshttps://github.com/solutions/use-case/devsecops
DevOpshttps://github.com/solutions/use-case/devops
CI/CDhttps://github.com/solutions/use-case/ci-cd
View all use caseshttps://github.com/solutions/use-case
Healthcarehttps://github.com/solutions/industry/healthcare
Financial serviceshttps://github.com/solutions/industry/financial-services
Manufacturinghttps://github.com/solutions/industry/manufacturing
Governmenthttps://github.com/solutions/industry/government
View all industrieshttps://github.com/solutions/industry
View all solutionshttps://github.com/solutions
AIhttps://github.com/resources/articles?topic=ai
Software Developmenthttps://github.com/resources/articles?topic=software-development
DevOpshttps://github.com/resources/articles?topic=devops
Securityhttps://github.com/resources/articles?topic=security
View all topicshttps://github.com/resources/articles
Customer storieshttps://github.com/customer-stories
Events & webinarshttps://github.com/resources/events
Ebooks & reportshttps://github.com/resources/whitepapers
Business insightshttps://github.com/solutions/executive-insights
GitHub Skillshttps://skills.github.com
Documentationhttps://docs.github.com
Customer supporthttps://support.github.com
Community forumhttps://github.com/orgs/community/discussions
Trust centerhttps://github.com/trust-center
Partnershttps://github.com/partners
View all resourceshttps://github.com/resources
GitHub SponsorsFund open source developershttps://github.com/open-source/sponsors
Security Labhttps://securitylab.github.com
Maintainer Communityhttps://maintainers.github.com
Acceleratorhttps://github.com/open-source/accelerator
GitHub Starshttps://stars.github.com
Archive Programhttps://archiveprogram.github.com
Topicshttps://github.com/topics
Trendinghttps://github.com/trending
Collectionshttps://github.com/collections
Enterprise platformAI-powered developer platformhttps://github.com/enterprise
GitHub Advanced SecurityEnterprise-grade security featureshttps://github.com/security/advanced-security
Copilot for BusinessEnterprise-grade AI featureshttps://github.com/features/copilot/copilot-business
Premium SupportEnterprise-grade 24/7 supporthttps://github.com/enterprise/premium-support
Pricinghttps://github.com/pricing
Search syntax tipshttps://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax
documentationhttps://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax
Sign in https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fmodelstudioai%2Fopenwork%2Fpull%2F61%2Ffiles
Sign up https://github.com/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E%2Fpull_requests%2Fshow%2Ffiles&source=header-repo&source_repo=modelstudioai%2Fopenwork
Reloadhttps://github.com/modelstudioai/openwork/pull/61/files
Reloadhttps://github.com/modelstudioai/openwork/pull/61/files
Reloadhttps://github.com/modelstudioai/openwork/pull/61/files
Please reload this pagehttps://github.com/modelstudioai/openwork/pull/61/files
modelstudioai https://github.com/modelstudioai
openworkhttps://github.com/modelstudioai/openwork
Notifications https://github.com/login?return_to=%2Fmodelstudioai%2Fopenwork
Fork 3 https://github.com/login?return_to=%2Fmodelstudioai%2Fopenwork
Star 11 https://github.com/login?return_to=%2Fmodelstudioai%2Fopenwork
Code https://github.com/modelstudioai/openwork
Issues 14 https://github.com/modelstudioai/openwork/issues
Pull requests 12 https://github.com/modelstudioai/openwork/pulls
Actions https://github.com/modelstudioai/openwork/actions
Projects https://github.com/modelstudioai/openwork/projects
Security and quality 0 https://github.com/modelstudioai/openwork/security
Insights https://github.com/modelstudioai/openwork/pulse
Code https://github.com/modelstudioai/openwork
Issues https://github.com/modelstudioai/openwork/issues
Pull requests https://github.com/modelstudioai/openwork/pulls
Actions https://github.com/modelstudioai/openwork/actions
Projects https://github.com/modelstudioai/openwork/projects
Security and quality https://github.com/modelstudioai/openwork/security
Insights https://github.com/modelstudioai/openwork/pulse
Sign up for GitHub https://github.com/signup?return_to=%2Fmodelstudioai%2Fopenwork%2Fissues%2Fnew%2Fchoose
terms of servicehttps://docs.github.com/terms
privacy statementhttps://docs.github.com/privacy
Sign inhttps://github.com/login?return_to=%2Fmodelstudioai%2Fopenwork%2Fissues%2Fnew%2Fchoose
DragonnZhanghttps://github.com/DragonnZhang
mainhttps://github.com/modelstudioai/openwork/tree/main
loop/composer-word-counthttps://github.com/modelstudioai/openwork/tree/loop/composer-word-count
Conversation 0 https://github.com/modelstudioai/openwork/pull/61
Commits 2 https://github.com/modelstudioai/openwork/pull/61/commits
Checks 0 https://github.com/modelstudioai/openwork/pull/61/checks
Files changed https://github.com/modelstudioai/openwork/pull/61/files
Please reload this pagehttps://github.com/modelstudioai/openwork/pull/61/files
Add a live word / character count indicator to the chat composer https://github.com/modelstudioai/openwork/pull/61/files#top
Show all changes 2 commits https://github.com/modelstudioai/openwork/pull/61/files
c098c3f Add live word/character count indicator to the chat composer claude Jul 6, 2026 https://github.com/modelstudioai/openwork/pull/61/commits/c098c3f5f63afbe28f748915bc6039b98d1abe04
0ddec0c chore: merge main into loop/composer-word-count claude Jul 6, 2026 https://github.com/modelstudioai/openwork/pull/61/commits/0ddec0c4a29f5cd820bd628d2e5abc22f99a3995
Clear filters https://github.com/modelstudioai/openwork/pull/61/files
Please reload this pagehttps://github.com/modelstudioai/openwork/pull/61/files
Please reload this pagehttps://github.com/modelstudioai/openwork/pull/61/files
ComposerCountIndicator.tsx https://github.com/modelstudioai/openwork/pull/61/files#diff-887e018b7e943903fd3db803d1a49f3e16c1678fe4f0c7bc5723f07dc0eb8ee4
FreeFormInput.tsx https://github.com/modelstudioai/openwork/pull/61/files#diff-8f45fdb3e5ebbc0360a53553f9b16be05400782b73a4596dd93949d08fdf1dee
composer-count.test.ts https://github.com/modelstudioai/openwork/pull/61/files#diff-2815b033ffec2e1fe5bb87d6cb581740e2c93cb81ecd7f7b68059465048db390
composer-count.ts https://github.com/modelstudioai/openwork/pull/61/files#diff-4f4fba117c7681cb9bc8a277653ac2fa22342faa24f03ab80f0bf8528794f98b
feature-ledger.md https://github.com/modelstudioai/openwork/pull/61/files#diff-2ae33a5d5ac052f40e2dfa56a7c3a17353f66baa0e674a59cc228e165b47c1af
composer-count.assert.ts https://github.com/modelstudioai/openwork/pull/61/files#diff-3797f4da9c50eb82b8e2a02116b9bb6602f859804dd4977fb415aa5e37286d7c
de.json https://github.com/modelstudioai/openwork/pull/61/files#diff-a07701a4bc4176fccd6c7f3e46bf998f5837c2b31a637c3368b7e2bd4945196f
en.json https://github.com/modelstudioai/openwork/pull/61/files#diff-650c08c76762dcf05df7a125fe3b6ddae49ec33728cbe9faa1cdb21d7a685fbd
es.json https://github.com/modelstudioai/openwork/pull/61/files#diff-17b9af294bafe3747f72d5e451d5bfca9e55f81e78c2cc4eaf8990c9144cf70b
hu.json https://github.com/modelstudioai/openwork/pull/61/files#diff-6214170c87d0d435f797d6f51294f090b12c8e0da8444c00e4cfed01fd0010ef
ja.json https://github.com/modelstudioai/openwork/pull/61/files#diff-249ff4abe047742db0ebfebd9afa8f6caa0fb2f3c2f471323f7f399b845b8933
pl.json https://github.com/modelstudioai/openwork/pull/61/files#diff-c1520578547c50e85365472656e70246092c4844b0010e599a5b4c2b315818ad
zh-Hans.json https://github.com/modelstudioai/openwork/pull/61/files#diff-f6d1257160b49bb15b0c0d38bd31c98febbbbe1eb1475f4c0be0e9d99d24c954
apps/electron/src/renderer/components/app-shell/input/ComposerCountIndicator.tsxhttps://github.com/modelstudioai/openwork/pull/61/files#diff-887e018b7e943903fd3db803d1a49f3e16c1678fe4f0c7bc5723f07dc0eb8ee4
View file https://github.com/modelstudioai/openwork/blob/0ddec0c4a29f5cd820bd628d2e5abc22f99a3995/apps/electron/src/renderer/components/app-shell/input/ComposerCountIndicator.tsx
Open in desktop https://desktop.github.com
https://github.co/hiddenchars
https://github.com/modelstudioai/openwork/pull/61/{{ revealButtonHref }}
apps/electron/src/renderer/components/app-shell/input/FreeFormInput.tsxhttps://github.com/modelstudioai/openwork/pull/61/files#diff-8f45fdb3e5ebbc0360a53553f9b16be05400782b73a4596dd93949d08fdf1dee
View file https://github.com/modelstudioai/openwork/blob/0ddec0c4a29f5cd820bd628d2e5abc22f99a3995/apps/electron/src/renderer/components/app-shell/input/FreeFormInput.tsx
Open in desktop https://desktop.github.com
https://github.co/hiddenchars
https://github.com/modelstudioai/openwork/pull/61/{{ revealButtonHref }}
https://github.com/modelstudioai/openwork/pull/61/files#diff-8f45fdb3e5ebbc0360a53553f9b16be05400782b73a4596dd93949d08fdf1dee
https://github.com/modelstudioai/openwork/pull/61/files#diff-8f45fdb3e5ebbc0360a53553f9b16be05400782b73a4596dd93949d08fdf1dee
https://github.com/modelstudioai/openwork/pull/61/files#diff-8f45fdb3e5ebbc0360a53553f9b16be05400782b73a4596dd93949d08fdf1dee
https://github.com/modelstudioai/openwork/pull/61/files#diff-8f45fdb3e5ebbc0360a53553f9b16be05400782b73a4596dd93949d08fdf1dee
apps/electron/src/renderer/lib/__tests__/composer-count.test.tshttps://github.com/modelstudioai/openwork/pull/61/files#diff-2815b033ffec2e1fe5bb87d6cb581740e2c93cb81ecd7f7b68059465048db390
View file https://github.com/modelstudioai/openwork/blob/0ddec0c4a29f5cd820bd628d2e5abc22f99a3995/apps/electron/src/renderer/lib/__tests__/composer-count.test.ts
Open in desktop https://desktop.github.com
https://github.co/hiddenchars
https://github.com/modelstudioai/openwork/pull/61/{{ revealButtonHref }}
apps/electron/src/renderer/lib/composer-count.tshttps://github.com/modelstudioai/openwork/pull/61/files#diff-4f4fba117c7681cb9bc8a277653ac2fa22342faa24f03ab80f0bf8528794f98b
View file https://github.com/modelstudioai/openwork/blob/0ddec0c4a29f5cd820bd628d2e5abc22f99a3995/apps/electron/src/renderer/lib/composer-count.ts
Open in desktop https://desktop.github.com
https://github.co/hiddenchars
https://github.com/modelstudioai/openwork/pull/61/{{ revealButtonHref }}
docs/loop/feature-ledger.mdhttps://github.com/modelstudioai/openwork/pull/61/files#diff-2ae33a5d5ac052f40e2dfa56a7c3a17353f66baa0e674a59cc228e165b47c1af
View file https://github.com/modelstudioai/openwork/blob/0ddec0c4a29f5cd820bd628d2e5abc22f99a3995/docs/loop/feature-ledger.md
Open in desktop https://desktop.github.com
https://github.co/hiddenchars
https://github.com/modelstudioai/openwork/pull/61/{{ revealButtonHref }}
https://github.com/modelstudioai/openwork/pull/61/files#diff-2ae33a5d5ac052f40e2dfa56a7c3a17353f66baa0e674a59cc228e165b47c1af
e2e/assertions/composer-count.assert.tshttps://github.com/modelstudioai/openwork/pull/61/files#diff-3797f4da9c50eb82b8e2a02116b9bb6602f859804dd4977fb415aa5e37286d7c
View file https://github.com/modelstudioai/openwork/blob/0ddec0c4a29f5cd820bd628d2e5abc22f99a3995/e2e/assertions/composer-count.assert.ts
Open in desktop https://desktop.github.com
https://github.co/hiddenchars
https://github.com/modelstudioai/openwork/pull/61/{{ revealButtonHref }}
Please reload this pagehttps://github.com/modelstudioai/openwork/pull/61/files
https://github.com
Termshttps://docs.github.com/site-policy/github-terms/github-terms-of-service
Privacyhttps://docs.github.com/site-policy/privacy-policies/github-privacy-statement
Securityhttps://github.com/security
Statushttps://www.githubstatus.com/
Communityhttps://github.community/
Docshttps://docs.github.com/
Contacthttps://support.github.com?tags=dotcom-footer

Viewport: width=device-width


URLs of crawlers that visited me.