Skip to content

Commit 5dd2ca4

Browse files
authored
Merge pull request #894 from bitsocialhq/development
Development
2 parents 11b713c + 6271d15 commit 5dd2ca4

File tree

27 files changed

+260
-207
lines changed

27 files changed

+260
-207
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,4 +165,5 @@ yarn-debug.log*
165165
yarn-error.log*
166166

167167
.vscode
168-
.cursor
168+
.cursor
169+
.claude

AGENTS.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,26 @@ Discover and install skills from the open agent skills ecosystem.
107107
npx skills add https://github.com/vercel-labs/skills --skill find-skills
108108
```
109109

110+
### playwright-cli (browser automation)
111+
112+
Use **playwright-cli** for browser automation—navigation, form filling, screenshots, testing, and data extraction. The CLI + skill approach is token-efficient: it avoids loading large MCP tool schemas and verbose accessibility trees into context.
113+
114+
**Do NOT use browser MCPs** (cursor-ide-browser, playwright-mcp, chrome MCP, etc.) for this project. MCP servers inject heavy tool definitions and page snapshots into the context window, degrading quality and response speed.
115+
116+
**Install** (globally, once per machine). Agents working on this project without playwright-cli should run:
117+
118+
```bash
119+
npm install -g @playwright/cli@latest
120+
```
121+
122+
Then from the project root, install the skill so the agent can use it:
123+
124+
```bash
125+
playwright-cli install --skills
126+
```
127+
128+
The skill installs to `.cursor/skills/playwright-cli/` (or `.claude/skills/` for Claude Code). Agents invoke commands via Bash (e.g. `playwright-cli open`, `playwright-cli snapshot`, `playwright-cli click e1`).
129+
110130
## AI Agent Hooks (Recommended)
111131

112132
If you're using an AI coding assistant (Cursor, Claude Code, Codex, etc.), set up hooks to automatically enforce code quality. Most modern AI agents support lifecycle hooks.
@@ -192,6 +212,10 @@ For Dependabot security alerts, GitHub Actions logs, issue/PR searches, or cross
192212

193213
If not available, suggest the user install it.
194214

215+
### Browser MCPs — Do NOT Use
216+
217+
**Avoid browser-related MCP servers** for this project (cursor-ide-browser, playwright-mcp, chrome MCP, etc.). Use **playwright-cli** (skill) instead—see [playwright-cli (browser automation)](#playwright-cli-browser-automation) above. Browser MCPs bloat the context window with tool schemas and page snapshots; the CLI + skill workflow is more token-efficient for coding agents.
218+
195219
### Context Window Warning
196220

197221
Each MCP server injects its tool definitions into the context window, consuming tokens even when the tools aren't being used. Too many servers will:

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"@capacitor/status-bar": "7.0.1",
1212
"@capawesome/capacitor-android-edge-to-edge-support": "7.2.2",
1313
"@floating-ui/react": "0.26.1",
14-
"@plebbit/plebbit-react-hooks": "https://github.com/plebbit/plebbit-react-hooks.git#df3cb6901f63054870dc127cd7565c98617c2a4f",
14+
"@plebbit/plebbit-react-hooks": "https://github.com/plebbit/plebbit-react-hooks.git#e197af2381ad651e5b74a93bcb705de78f94742c",
1515
"@react-spring/web": "9.7.5",
1616
"@types/node": "20.8.2",
1717
"@types/react": "18.2.25",
@@ -138,6 +138,7 @@
138138
"wait-on": "9.0.3"
139139
},
140140
"resolutions": {
141+
"axios": "1.13.5",
141142
"js-yaml": "4.1.1",
142143
"baseline-browser-mapping": "^2.9.11",
143144
"vite": "npm:rolldown-vite@7.3.1",

scripts/release-body.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,7 @@ const htmlSection = section('Static HTML build', [htmlZip && `- 5chan-html (zip)
102102
const downloads = [macSection, winSection, linuxSection, androidSection, htmlSection].filter(Boolean).join('\n\n');
103103

104104
// One-liner summary of what changed in this release. Update before each release.
105-
const oneLinerDescription =
106-
'This version adds multiple-replying support, 4chan-like user anonymity with or without user IDs depending on the board, and several bug fixes.';
105+
const oneLinerDescription = 'This version adds backlinks for quoted posts, improves reply functionality with proper quote references, and includes several bug fixes.';
107106

108107
const releaseBody = `${oneLinerDescription}
109108

src/components/board-buttons/board-buttons.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import CatalogSearch from '../catalog-search';
2020
import Tooltip from '../tooltip';
2121
import { ModQueueButton } from '../../views/mod-queue/mod-queue';
2222
import styles from './board-buttons.module.css';
23-
import _ from 'lodash';
23+
import { capitalize } from 'lodash';
2424

2525
interface BoardButtonsProps {
2626
address?: string | undefined;
@@ -510,13 +510,13 @@ const PostPageStats = () => {
510510
const linkCount = useCountLinksInReplies(comment);
511511

512512
const displayReplyCount = replyCount !== undefined ? replyCount.toString() : '?';
513-
const replyCountTooltip = replyCount !== undefined ? _.capitalize(t('replies')) : t('loading');
513+
const replyCountTooltip = replyCount !== undefined ? capitalize(t('replies')) : t('loading');
514514

515515
return (
516516
<span>
517-
{pinned && `${_.capitalize(t('sticky'))} / `}
518-
{closed && `${_.capitalize(t('closed'))} / `}
519-
<Tooltip children={displayReplyCount} content={replyCountTooltip} /> / <Tooltip children={linkCount?.toString()} content={_.capitalize(t('links'))} />
517+
{pinned && `${capitalize(t('sticky'))} / `}
518+
{closed && `${capitalize(t('closed'))} / `}
519+
<Tooltip children={displayReplyCount} content={replyCountTooltip} /> / <Tooltip children={linkCount?.toString()} content={capitalize(t('links'))} />
520520
</span>
521521
);
522522
};

src/components/board-header/board-header.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import useIsMobile from '../../hooks/use-is-mobile';
1414
import useIsSubplebbitOffline from '../../hooks/use-is-subplebbit-offline';
1515
import { shouldShowSnow } from '../../lib/snow';
1616
import Tooltip from '../tooltip';
17-
import _ from 'lodash';
17+
import { startCase } from 'lodash';
1818
import { BANNERS } from '../../generated/asset-manifest';
1919

2020
const ImageBanner = () => {
@@ -78,7 +78,7 @@ const BoardHeader = () => {
7878
: isInSubscriptionsView
7979
? '/subs/ - Subscriptions'
8080
: isInModView
81-
? _.startCase(t('boards_you_moderate'))
81+
? startCase(t('boards_you_moderate'))
8282
: defaultSubplebbit?.title || stableSubplebbit?.title;
8383
const subtitle = isInAllView ? '' : isInSubscriptionsView ? subscriptionsSubtitle : isInModView ? '/mod/' : `${address || subplebbitAddress || ''}`;
8484

src/components/catalog-row/catalog-row.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import useWindowWidth from '../../hooks/use-window-width';
2222
import { ContentPreview } from '../../views/home/popular-threads-box';
2323
import PostMenuDesktop from '../post-desktop/post-menu-desktop';
2424
import styles from './catalog-row.module.css';
25-
import _ from 'lodash';
25+
import { capitalize } from 'lodash';
2626
import { selectPostMenuProps } from '../../lib/utils/post-menu-props';
2727

2828
interface CatalogPostMediaProps {
@@ -286,7 +286,7 @@ const CatalogPost = memo(
286286
t('posted_by')
287287
)}{' '}
288288
<span className={`${styles.postAuthor} ${isCatalogPostAuthorMod && styles.capcode}`}>
289-
{author?.displayName || _.capitalize(t('anonymous'))}
289+
{author?.displayName || capitalize(t('anonymous'))}
290290
{isCatalogPostAuthorMod && <span className='capitalize'>{` ## Board ${catalogPostAuthorRole}`}</span>}
291291
</span>
292292
{(isInAllView || isInSubscriptionsView) && subplebbitAddress && ` to p/${Plebbit.getShortAddress({ address: subplebbitAddress })}`}
@@ -295,7 +295,7 @@ const CatalogPost = memo(
295295
<div className={styles.postLast}>
296296
{t('last_reply_by')}{' '}
297297
<span className={`${styles.postAuthor} ${isLastReplyAuthorMod && styles.capcode}`}>
298-
{lastReply?.author?.displayName || _.capitalize(t('anonymous'))}
298+
{lastReply?.author?.displayName || capitalize(t('anonymous'))}
299299
{isLastReplyAuthorMod && ` ## Board ${lastReplyAuthorRole}`}
300300
</span>
301301
<span className={styles.postAgo}> {getFormattedTimeAgo(lastReply?.timestamp)}</span>

src/components/catalog-search/catalog-search.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { useLocation, useNavigate } from 'react-router-dom';
44
import styles from './catalog-search.module.css';
55
import useIsMobile from '../../hooks/use-is-mobile';
66
import useCatalogFiltersStore from '../../stores/use-catalog-filters-store';
7-
import _ from 'lodash';
7+
import { debounce } from 'lodash';
88

99
const CatalogSearch = () => {
1010
const { t } = useTranslation();
@@ -44,7 +44,7 @@ const CatalogSearch = () => {
4444
// Create a debounced version of setSearchFilter and URL update
4545
// eslint-disable-next-line react-hooks/exhaustive-deps
4646
const debouncedSetSearchFilter = useCallback(
47-
_.debounce((text: string) => {
47+
debounce((text: string) => {
4848
if (text.trim()) {
4949
setSearchFilter(text);
5050
updateURL(text);

src/components/challenge-modal/challenge-modal.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import useIsMobile from '../../hooks/use-is-mobile';
66
import useChallengesStore from '../../stores/use-challenges-store';
77
import useTheme from '../../hooks/use-theme';
88
import styles from './challenge-modal.module.css';
9-
import _ from 'lodash';
9+
import { capitalize } from 'lodash';
1010
import { useSpring, animated } from '@react-spring/web';
1111
import { useDrag } from '@use-gesture/react';
1212

@@ -269,7 +269,7 @@ const Challenge = ({ challenge, closeModal }: ChallengeProps) => {
269269
{isIframeChallenge && !showIframeConfirmation ? null : (
270270
<>
271271
<div className={styles.name}>
272-
<input type='text' value={displayName || _.capitalize(t('anonymous'))} disabled />
272+
<input type='text' value={displayName || capitalize(t('anonymous'))} disabled />
273273
</div>
274274
{title && (
275275
<div className={styles.subject}>

src/components/comment-content/comment-content.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import ReplyQuotePreview from '../../components/reply-quote-preview';
1414
import Markdown from '../../components/markdown';
1515
import Tooltip from '../../components/tooltip';
1616
import styles from '../../views/post/post.module.css';
17-
import _ from 'lodash';
17+
import { capitalize } from 'lodash';
1818

1919
const QuotedCidLink = ({ cid, postCid }: { cid: string; postCid: string }) => {
2020
const commentFromStore = useSubplebbitsPagesStore((state) => state.comments[cid]);
@@ -88,16 +88,16 @@ const CommentContent = ({ comment: post }: { comment: Comment }) => {
8888
<span className={styles.redEditMessage}>({t('this_post_was_removed')})</span>
8989
<br />
9090
<br />
91-
<span className={styles.grayEditMessage}>{`${_.capitalize(t('reason'))}: "${reason}"`}</span>
91+
<span className={styles.grayEditMessage}>{`${capitalize(t('reason'))}: "${reason}"`}</span>
9292
</>
9393
) : (
94-
<span className={styles.grayEditMessage}>{_.capitalize(t('this_post_was_removed'))}.</span>
94+
<span className={styles.grayEditMessage}>{capitalize(t('this_post_was_removed'))}.</span>
9595
)
9696
) : deleted ? (
9797
reason ? (
9898
<>
9999
<span className={styles.grayEditMessage}>{t('user_deleted_this_post')}</span>{' '}
100-
<span className={styles.grayEditMessage}>{`${_.capitalize(t('reason'))}: "${reason}"`}</span>
100+
<span className={styles.grayEditMessage}>{`${capitalize(t('reason'))}: "${reason}"`}</span>
101101
</>
102102
) : (
103103
<span className={styles.grayEditMessage}>{t('user_deleted_this_post')}</span>
@@ -159,7 +159,7 @@ const CommentContent = ({ comment: post }: { comment: Comment }) => {
159159
address: subplebbitAddress && Plebbit.getShortAddress({ address: subplebbitAddress }),
160160
timestamp: getFormattedDate(post?.author?.subplebbit?.banExpiresAt),
161161
interpolation: { escapeValue: false },
162-
})}${reason ? `. ${_.capitalize(t('reason'))}: "${reason}"` : ''}`}
162+
})}${reason ? `. ${capitalize(t('reason'))}: "${reason}"` : ''}`}
163163
/>
164164
</span>
165165
)}

0 commit comments

Comments
 (0)