You are a coding assistant working on Twilio's Message Segment Calculator, a TypeScript library and browser tool that helps customers understand how SMS and RCS messages are segmented and encoded.
npm install # Install dependencies
npm test # Type-check (tsc) + run tests (jest)
npm run lint # ESLint on src/**/*.ts
npm run lint:fix # ESLint with auto-fix
npm run check # Lint + test (mirrors CI)
npm run release # Type-check + webpack build (outputs to docs/scripts/)
npm run build # Type-check only (tsc)
npm run test:e2e # Playwright e2e tests (serves docs/ locally)
npm run test:e2e:ui # Playwright interactive UI modesrc/
libs/ # Core library (encoding, segmentation)
SegmentedMessage.ts # SMS segmentation logic (GSM-7 / UCS-2)
RcsSegmentedMessage.ts # RCS segmentation logic (UTF-8)
EncodedChar.ts # Single character with encoding info (isGSM7, codeUnits)
Segment.ts # Segment container (extends Array)
UserDataHeader.ts # UDH for multi-segment messages
UnicodeToGSM.ts # GSM-7 character mapping table
SmartEncodingMap.ts # Twilio Smart Encoding replacements
textUtils.ts # Grapheme splitting utilities
browser/ # Browser UI modules
main.ts # Entry point, DOM wiring, event listeners
segmenter.ts # Analysis functions (analyzeSms, analyzeRcs)
renderer.ts # DOM rendering (segment tape, char detail, stats)
types.ts # Shared type definitions (SmsAnalysis, RcsAnalysis, etc.)
global.ts # Library exports for global scope
index.ts # NPM package entry point
docs/ # GitHub Pages site
index.html # Main page
scripts/ # Built JS bundles (from webpack)
styles/ # CSS (tokens.css, layout.css, components.css, animations.css)
pr-reviews/ # 3-agent + 1-human PR review docs
tests/ # Test suites
*.test.js # Jest unit tests
e2e/ # Playwright e2e tests (char-detail.spec.ts, etc.)
dist/ # Built library output (tsc)
- GSM-7: 7-bit encoding, 160 chars/segment (153 if multi-segment due to UDH)
- UCS-2: 16-bit Unicode, 70 chars/segment (67 if multi-segment)
- A single non-GSM character forces the entire message to UCS-2
EncodedChar.isGSM7identifies whether a character is in the GSM-7 setEncodedChar.codeUnitsgives the hex code units for any character
- Always UTF-8
- US: billed per 160-byte "Rich" segment
- International: "Basic" (<=160 bytes) or "Single" (>160 bytes), no segmentation
Data flows through three layers:
- segmenter.ts —
analyzeSms()/analyzeRcs()produce typed analysis objects - types.ts —
SmsAnalysis,RcsAnalysis,CharDetail,SegmentDatainterfaces - renderer.ts — Pure DOM rendering functions consume analysis objects and render to target elements
- Dark theme using CSS custom properties in
docs/styles/tokens.css - Font stack: Plus Jakarta Sans (display), DM Sans (body), JetBrains Mono (code)
- All colors must use CSS variables from tokens.css, never hard-coded hex values
- Segment palette:
--color-seg-N-bg/--color-seg-N-fg(5 rotating colors)
- TypeScript throughout
src/, compiled withtsc - ESLint with
eslint-config-twilio-ts(includes prettier) - Named exports preferred over default exports for browser modules
- Default exports used in core library (EncodedChar, Segment, etc.) — legacy pattern
npm run lintmust pass with zero errors before committing (warnings are OK for pre-existing issues)- Accessibility: interactive elements need
tabindex,role, andaria-label
GitHub Actions runs on every PR to main (.github/workflows/test.js.yml):
npm installnpm run lint— ESLint (prettier + twilio-ts rules)npm test— tsc + jest
Matrix: Node 20.x, 22.x
Run npm run check locally to mirror CI before pushing.
Husky + lint-staged runs eslint --fix on staged src/**/*.ts files at commit time.
- Project: DEVED on
twilio-productivity.atlassian.net - Component: "DevEd Internal" for docs projects
- Branch naming:
{type}/{TICKET-KEY}-{description}(e.g.,feat/DEVED-13514-restore-char-detail-view) - PR auto-close: Include JIRA ticket key in PR description
- Story points: 1 (1-4 hrs), 2 (1-2 days), 3 (2-3 days), 5 (3-5 days)
- JIRA tooling: Use
createJiraService()from the deved-agents repo for programmatic ticket creation
- Create branch from
mainwith JIRA ticket key - Implement, run
npm run checklocally - Push and create PR with JIRA link in description
- Follow 3-agent + 1-human review (see
docs/pr-reviews/README.md) - Address review feedback
- Squash and merge
Tests live in tests/e2e/ and run against the built docs/ site:
- Config:
playwright.config.ts— auto-servesdocs/on port 8080 - Results/reports:
tests/e2e/results/andtests/e2e/reports/(gitignored) tsconfig.jsonincludes onlysrc/;jestignorestests/e2e/— this prevents tsc and Jest from picking up Playwright files
Best practices:
- Use semantic selectors (
#sms-char-detail,.char-block) and Playwright's auto-waiting - Check attributes directly (
toHaveAttribute('hidden', '')) whentoBeHidden()doesn't work for elements inside open<details> - Run
npm run releasebefore e2e tests to ensuredocs/scripts/bundles are current - Always rebuild dist/docs artifacts before committing changes to
src/browser/
Run codex review --base main for automated code review. For re-reviews after changes:
codex review --base main --title "PR title here"Capture findings in docs/pr-reviews/<PR>/codex.md. Mark issues as [x] when fixed and note which commit resolved them.
SegmentextendsArray— iterating withfor...ofworks but items includeUserDataHeaderentries. Filter withisReservedCharto get only user characters.EncodedChar.codeUnitscontains GSM-7 septet values for GSM characters, even in UCS-2 messages. When displaying code units for UCS-2 messages, derive UTF-16 values fromraw.charCodeAt()instead.EncodedChar.isGSM7indicates whether a character is in the GSM-7 character set, NOT the message encoding. UseSegmentedMessage.encodingNamefor the actual message encoding.- The
docs/scripts/JS bundles are built artifacts from webpack — always runnpm run releaseafter changingsrc/browser/files. dist/contains tsc output for the NPM package — also rebuilt bynpm run release.- Both
docs/scripts/anddist/should be committed (they are deployed artifacts).