From b0697a6700aef609cece33607e216a27cc2bdbbb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 9 Aug 2025 09:03:53 +0000 Subject: [PATCH 1/5] Initial plan From 29d63dc227b015bacea7f5aafab5a7280d3e819f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 9 Aug 2025 09:25:23 +0000 Subject: [PATCH 2/5] Create comprehensive .github/copilot-instructions.md with validated commands and timing Co-authored-by: RichDom2185 <34370238+RichDom2185@users.noreply.github.com> --- .github/copilot-instructions.md | 146 +++++++++++++++++++++++ package.json.backup | 201 ++++++++++++++++++++++++++++++++ yarn.lock | 83 ++++++++++++- 3 files changed, 424 insertions(+), 6 deletions(-) create mode 100644 .github/copilot-instructions.md create mode 100644 package.json.backup diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000000..3cc398afeb --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,146 @@ +# Source Academy Frontend + +The Source Academy Frontend is a React.js TypeScript web application for an immersive online programming education platform. It features a coding playground, SICP JS textbook integration, assessment system, grading tools, collaborative sessions, and game elements. The application is built with React 18, Redux, TypeScript, and modern tooling. + +**ALWAYS reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here.** + +## Working Effectively + +### Environment Setup +- Node.js version: 20.9.0+ (as specified in `.node-version`) +- Package manager: Yarn 4.6.0 (managed via corepack) +- Enable corepack: `corepack enable` + +### Bootstrap and Build Process +1. **Install dependencies** (25 seconds): + ```bash + corepack enable + yarn install + ``` + **NOTE**: Installation may fail due to network restrictions accessing `cdn.sheetjs.com` for the xlsx package. If this occurs, temporarily modify `package.json` to use `"xlsx": "^0.18.5"` instead of the CDN URL, run `yarn install --mode update-lockfile`, then `yarn install`. + +2. **TypeScript compilation** (20 seconds): + ```bash + yarn run tsc --noEmit + ``` + +3. **Linting** (7 seconds): + ```bash + yarn run eslint + ``` + +4. **Format checks** (10 seconds): + ```bash + yarn run format:ci + ``` + +5. **Production build** (40 seconds, **NEVER CANCEL**): + ```bash + yarn run build + ``` + **CRITICAL**: Set timeout to 60+ minutes. Build completes in ~40 seconds but may take longer on slower systems. + +6. **Test suite** (1 minute 45 seconds, **NEVER CANCEL**): + ```bash + yarn run test + ``` + **CRITICAL**: Set timeout to 30+ minutes. One test may fail due to network restrictions accessing `sicp.sourceacademy.org`. + +### Development Server +- **Start development server** (16 seconds build + server startup): + ```bash + yarn run start + ``` +- **Access**: http://localhost:8000 +- **Hot reload**: Enabled with live updates + +## Validation + +### Manual Testing Requirements +**ALWAYS run through at least one complete end-to-end scenario after making changes:** + +1. **Basic Playground Functionality**: + - Navigate to http://localhost:8000 (redirects to /playground) + - Verify the editor loads with syntax highlighting + - Write test code: `function factorial(n) { return n <= 1 ? 1 : n * factorial(n - 1); } factorial(5);` + - Click "Run" button + - Verify output "120" appears in the result panel + - Test REPL by typing expressions in the bottom panel + +2. **Navigation and UI**: + - Verify navigation bar with "Playground" and "SICP JS" links + - Test language selector (Source §1 through §4) + - Verify all toolbar buttons are functional (Run, Share, Session, Folder, Google Drive, GitHub) + - Check welcome message and documentation links work + +3. **Build Validation**: + - **ALWAYS** run `yarn run format` and `yarn run eslint` before committing + - The CI workflow (`.github/workflows/ci.yml`) runs: `tsc`, `format:ci`, `eslint`, `build`, `test --bail=1`, `test-coveralls` + +## Network Limitations + +**Important**: Several external services are not accessible in sandboxed environments: +- `cdn.sheetjs.com` - xlsx package installation fails +- `sicp.sourceacademy.org` - SICP JS content fails to load +- `fonts.googleapis.com`, `apis.google.com` - Google services blocked +- These failures are expected and should be documented as "fails due to network limitations" + +## Common Tasks + +### Repository Structure +``` +/home/runner/work/frontend/frontend/ +├── .github/workflows/ # CI/CD pipelines +├── .node-version # Node.js 20.9.0 +├── package.json # Dependencies and scripts +├── tsconfig.json # TypeScript configuration +├── rsbuild.config.ts # Build configuration (replaces webpack) +├── vitest.config.ts # Test configuration +├── src/ +│ ├── assets/ # Static assets +│ ├── commons/ # Shared components and utilities +│ ├── features/ # Redux features (actions, reducers, sagas) +│ ├── pages/ # Page components matching routes +│ └── styles/ # SCSS stylesheets +├── public/ # Public static files +└── scripts/ # Utility scripts +``` + +### Key npm Scripts +- `yarn start` - Development server (http://localhost:8000) +- `yarn build` - Production build (40s, outputs to `build/`) +- `yarn test` - Test suite (1m45s, may have 1 network-related failure) +- `yarn format` - Auto-fix code formatting (ESLint + Prettier) +- `yarn format:ci` - Check formatting without changes +- `yarn eslint` - Lint TypeScript/JavaScript code +- `yarn tsc` - TypeScript compilation check + +### Environment Configuration +Copy `.env.example` to `.env` and configure: +- `REACT_APP_BACKEND_URL` - Backend API endpoint +- `REACT_APP_USE_BACKEND` - Enable/disable backend integration +- `REACT_APP_PLAYGROUND_ONLY` - Playground-only mode for GitHub Pages +- Authentication providers, Google Drive, GitHub integration settings + +### Memory Requirements +The build process requires significant memory: +- Set `NODE_OPTIONS=--max_old_space_size=8192` for CI/CD +- Local development typically works with default Node.js memory limits + +### Technology Stack +- **Frontend**: React 18.3.1 with TypeScript 5.8.2 +- **State Management**: Redux Toolkit with Redux Saga +- **Build Tool**: rsbuild (modern webpack replacement) +- **Testing**: Vitest with jsdom environment +- **Styling**: SCSS with Blueprint UI components +- **Linting**: ESLint 9 with TypeScript rules +- **Code Editor**: ACE editor with Source language support + +### Debugging Tips +- Check browser console for React DevTools and HMR connection messages +- Build warnings about missing Node.js modules (perf_hooks) are expected in browser builds +- ESLint warnings about React hooks dependencies are common and generally safe +- Use `yarn run test:watch` for interactive test development +- Use `yarn run test:ui` for browser-based test UI + +**Remember**: Always validate functionality manually by running the application and testing user scenarios. The playground must be able to execute code and display results correctly. \ No newline at end of file diff --git a/package.json.backup b/package.json.backup new file mode 100644 index 0000000000..bc70762390 --- /dev/null +++ b/package.json.backup @@ -0,0 +1,201 @@ +{ + "private": true, + "type": "module", + "name": "frontend", + "packageManager": "yarn@4.6.0", + "version": "1.4.3", + "scripts-info": { + "analyze": "Analyze bundle size breakdown", + "format": "Format source code", + "start": "Start the Webpack development server", + "build": "Build production bundle", + "test": "Run unit tests", + "update-ui-snapshots": "Update UI test snapshots" + }, + "scripts": { + "analyze": "yarn build --stats; webpack-bundle-analyzer build/bundle-stats.json", + "build": "tsc -b && rsbuild build", + "coverage": "./scripts/coverage-fix.sh do && yarn test --coverage && ./scripts/coverage-fix.sh undo", + "format": "eslint --fix src && prettier --write \"src/**/*.{js,jsx,ts,tsx}\" && prettier --write --parser scss \"src/**/*.scss\"", + "format:tsx": "prettier --list-different \"src/**/*.{js,jsx,ts,tsx}\"", + "format:scss": "prettier --list-different --parser scss \"src/**/*.scss\"", + "format:ci": "yarn run format:tsx && yarn run format:scss", + "start": "rsbuild dev", + "test": "cross-env TZ=Asia/Singapore vitest run", + "test:watch": "cross-env TZ=Asia/Singapore vitest", + "test:ui": "cross-env TZ=Asia/Singapore vitest --ui --no-open", + "test-coveralls": "./scripts/test-coveralls.sh", + "update-ui-snapshots": "vitest run --update", + "eslint": "eslint src", + "prepare": "husky", + "preview": "rsbuild preview" + }, + "dependencies": { + "@blueprintjs/core": "^5.10.1", + "@blueprintjs/datetime2": "^2.3.3", + "@blueprintjs/icons": "^6.0.0", + "@blueprintjs/select": "^5.1.3", + "@convergencelabs/ace-collab-ext": "^0.6.0", + "@mantine/hooks": "^7.11.2", + "@octokit/rest": "^22.0.0", + "@reduxjs/toolkit": "^1.9.7", + "@sentry/browser": "^8.33.0", + "@sourceacademy/c-slang": "^1.0.21", + "@sourceacademy/sharedb-ace": "^2.1.1", + "@sourceacademy/sling-client": "^0.1.0", + "@szhsin/react-menu": "^4.0.0", + "@tanstack/react-table": "^8.9.3", + "@tremor/react": "^1.8.2", + "ace-builds": "^1.42.1", + "acorn": "^8.9.0", + "ag-grid-community": "^32.3.1", + "ag-grid-react": "^32.3.1", + "array-move": "^4.0.0", + "browserfs": "^1.4.3", + "classnames": "^2.3.2", + "conductor": "https://github.com/source-academy/conductor.git#0.2.1", + "dayjs": "^1.11.13", + "dompurify": "^3.2.4", + "flexboxgrid": "^6.3.1", + "flexboxgrid-helpers": "^1.1.3", + "hastscript": "^9.0.0", + "i18next": "^25.0.0", + "i18next-browser-languagedetector": "^8.0.0", + "immer": "^9.0.21", + "java-slang": "^1.0.13", + "js-cookie": "^3.0.5", + "js-slang": "^1.0.84", + "js-yaml": "^4.1.0", + "konva": "^9.2.0", + "language-directory": "https://github.com/source-academy/language-directory.git", + "lodash": "^4.17.21", + "lz-string": "^1.4.4", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-hast": "^13.0.0", + "normalize.css": "^8.0.1", + "phaser": "~3.90.0", + "query-string": "^9.0.0", + "re-resizable": "^6.9.9", + "react": "^18.3.1", + "react-ace": "^14.0.0", + "react-copy-to-clipboard": "^5.1.0", + "react-debounce-render": "^8.0.2", + "react-dom": "^18.3.1", + "react-drag-drop-files": "^3.0.0", + "react-draggable": "^4.4.5", + "react-dropzone": "^14.2.3", + "react-i18next": "^15.0.0", + "react-konva": "^18.2.10", + "react-latex-next": "^3.0.0", + "react-mde": "^11.5.0", + "react-papaparse": "^4.0.2", + "react-qr-reader": "^3.0.0-beta-1", + "react-redux": "^8.1.1", + "react-router": "^7.6.2", + "react-select": "^5.7.3", + "react-simple-keyboard": "^3.6.27", + "react-sortable-hoc": "^2.0.0", + "react-syntax-highlighter": "^15.5.0", + "react-textarea-autosize": "^8.5.2", + "redux-mock-store": "^1.5.4", + "redux-saga": "^1.2.3", + "rehype-react": "^8.0.0", + "showdown": "^2.1.0", + "sourceror": "^0.8.5", + "unified": "^11.0.0", + "uuid": "^11.0.2", + "workbox-core": "^7.3.0", + "workbox-precaching": "^7.3.0", + "workbox-routing": "^7.3.0", + "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz", + "xml2js": "^0.6.0", + "yareco": "^0.1.5" + }, + "devDependencies": { + "@aaroon/workbox-rspack-plugin": "^0.3.2", + "@babel/core": "^7.24.5", + "@babel/plugin-proposal-private-property-in-object": "^7.21.11", + "@babel/preset-typescript": "^7.24.1", + "@babel/runtime": "^7.24.5", + "@rsbuild/core": "^1.3.12", + "@rsbuild/plugin-eslint": "^1.1.1", + "@rsbuild/plugin-node-polyfill": "^1.3.0", + "@rsbuild/plugin-react": "^1.3.0", + "@rsbuild/plugin-sass": "^1.3.1", + "@rsbuild/plugin-svgr": "^1.2.0", + "@svgr/webpack": "^8.0.0", + "@swc/core": "^1.11.22", + "@testing-library/dom": "^10.4.0", + "@testing-library/jest-dom": "^6.0.0", + "@testing-library/react": "^16.0.0", + "@testing-library/user-event": "^14.6.0", + "@types/estree": "^1.0.5", + "@types/gapi": "^0.0.47", + "@types/gapi.auth2": "^0.0.61", + "@types/gapi.client": "^1.0.5", + "@types/gapi.client.drive-v3": "^0.0.5", + "@types/google.picker": "^0.0.51", + "@types/identity-obj-proxy": "^3", + "@types/js-cookie": "^3.0.6", + "@types/js-yaml": "^4.0.5", + "@types/lodash": "^4.14.195", + "@types/react": "^18.3.3", + "@types/react-copy-to-clipboard": "^5.0.4", + "@types/react-dom": "^18.3.0", + "@types/react-redux": "^7.1.24", + "@types/react-syntax-highlighter": "^15.5.7", + "@types/react-test-renderer": "^18.0.0", + "@types/redux-mock-store": "^1.0.3", + "@types/showdown": "^2.0.1", + "@types/xml2js": "^0.4.11", + "@vitejs/plugin-react-swc": "^3.11.0", + "@vitest/coverage-v8": "3.2.4", + "@vitest/ui": "^3.2.4", + "buffer": "^6.0.3", + "canvas": "^3.1.0", + "constants-browserify": "^1.0.0", + "coveralls": "^3.1.1", + "cross-env": "^10.0.0", + "eslint": "^9.9.0", + "eslint-plugin-react": "^7.35.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.9", + "eslint-plugin-simple-import-sort": "^12.1.1", + "https-browserify": "^1.0.0", + "husky": "^9.0.0", + "identity-obj-proxy": "^3.0.0", + "jsdom": "^26.0.0", + "npm-run-all2": "^8.0.0", + "os-browserify": "^0.3.0", + "path": "^0.12.7", + "path-browserify": "^1.0.1", + "phaser3spectorjs": "^0.0.8", + "prettier": "^3.3.3", + "process": "^0.11.10", + "react-error-overlay": "^6.0.11", + "react-test-renderer": "^18.2.0", + "redux-saga-test-plan": "^4.0.6", + "resize-observer-polyfill": "^1.5.1", + "sass": "^1.63.6", + "stream-browserify": "^3.0.0", + "stream-http": "^3.2.0", + "timers-browserify": "^2.0.12", + "typescript": "^5.8.2", + "typescript-eslint": "^8.1.0", + "url": "^0.11.1", + "vitest": "^3.2.4", + "webpack-bundle-analyzer": "^4.9.0" + }, + "browserslist": { + "production": [ + "Firefox ESR", + "last 2 chrome versions", + "last 2 safari versions" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/yarn.lock b/yarn.lock index 77457e5a88..526f573d03 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4613,6 +4613,13 @@ __metadata: languageName: node linkType: hard +"adler-32@npm:~1.3.0": + version: 1.3.1 + resolution: "adler-32@npm:1.3.1" + checksum: 10c0/c1b7185526ee1bbe0eac8ed414d5226af4cd02a0540449a72ec1a75f198c5e93352ba4d7b9327231eea31fd83c2d080d13baf16d8ed5710fb183677beb85f612 + languageName: node + linkType: hard + "ag-charts-types@npm:10.3.8": version: 10.3.8 resolution: "ag-charts-types@npm:10.3.8" @@ -5428,6 +5435,16 @@ __metadata: languageName: node linkType: hard +"cfb@npm:~1.2.1": + version: 1.2.2 + resolution: "cfb@npm:1.2.2" + dependencies: + adler-32: "npm:~1.3.0" + crc-32: "npm:~1.2.0" + checksum: 10c0/87f6d9c3878268896ed6ca29dfe32a2aa078b12d0f21d8405c95911b74ab6296823d7312bbf5e18326d00b16cc697f587e07a17018c5edf7a1ba31dd5bc6da36 + languageName: node + linkType: hard + "chai@npm:^5.2.0": version: 5.2.1 resolution: "chai@npm:5.2.1" @@ -5596,6 +5613,13 @@ __metadata: languageName: node linkType: hard +"codepage@npm:~1.15.0": + version: 1.15.0 + resolution: "codepage@npm:1.15.0" + checksum: 10c0/2455b482302cb784b46dea60a8ee83f0c23e794bdd979556bdb107abe681bba722af62a37f5c955ff4efd68fdb9688c3986e719b4fd536c0e06bb25bc82abea3 + languageName: node + linkType: hard + "color-convert@npm:^1.9.0": version: 1.9.3 resolution: "color-convert@npm:1.9.3" @@ -5873,6 +5897,15 @@ __metadata: languageName: node linkType: hard +"crc-32@npm:~1.2.0, crc-32@npm:~1.2.1": + version: 1.2.2 + resolution: "crc-32@npm:1.2.2" + bin: + crc32: bin/crc32.njs + checksum: 10c0/11dcf4a2e77ee793835d49f2c028838eae58b44f50d1ff08394a610bfd817523f105d6ae4d9b5bef0aad45510f633eb23c903e9902e4409bed1ce70cb82b9bf0 + languageName: node + linkType: hard + "create-ecdh@npm:^4.0.4": version: 4.0.4 resolution: "create-ecdh@npm:4.0.4" @@ -7471,6 +7504,13 @@ __metadata: languageName: node linkType: hard +"frac@npm:~1.1.2": + version: 1.1.2 + resolution: "frac@npm:1.1.2" + checksum: 10c0/640740eb58b590eb38c78c676955bee91cd22d854f5876241a15c49d4495fa53a84898779dcf7eca30aabfe1c1a4a705752b5f224934257c5dda55c545413ba7 + languageName: node + linkType: hard + "frontend@workspace:.": version: 0.0.0-use.local resolution: "frontend@workspace:." @@ -7624,7 +7664,7 @@ __metadata: workbox-core: "npm:^7.3.0" workbox-precaching: "npm:^7.3.0" workbox-routing: "npm:^7.3.0" - xlsx: "https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz" + xlsx: "npm:^0.18.5" xml2js: "npm:^0.6.0" yareco: "npm:^0.1.5" languageName: unknown @@ -12856,6 +12896,15 @@ __metadata: languageName: node linkType: hard +"ssf@npm:~0.11.2": + version: 0.11.2 + resolution: "ssf@npm:0.11.2" + dependencies: + frac: "npm:~1.1.2" + checksum: 10c0/c3fd24a90dc37a9dc5c4154cb4121e27507c33ebfeee3532aaf03625756b2c006cf79c0a23db0ba16c4a6e88e1349455327867e03453fc9d54b32c546bc18ca6 + languageName: node + linkType: hard + "sshpk@npm:^1.7.0": version: 1.17.0 resolution: "sshpk@npm:1.17.0" @@ -14388,6 +14437,20 @@ __metadata: languageName: node linkType: hard +"wmf@npm:~1.0.1": + version: 1.0.2 + resolution: "wmf@npm:1.0.2" + checksum: 10c0/3fa5806f382632cadfe65d4ef24f7a583b0c0720171edb00e645af5248ad0bb6784e8fcee1ccd9f475a1a12a7523e2512e9c063731fbbdae14dc469e1c033d93 + languageName: node + linkType: hard + +"word@npm:~0.3.0": + version: 0.3.0 + resolution: "word@npm:0.3.0" + checksum: 10c0/c6da2a9f7a0d81a32fa6768a638d21b153da2be04f94f3964889c7cc1365d74b6ecb43b42256c3f926cd59512d8258206991c78c21000c3da96d42ff1238b840 + languageName: node + linkType: hard + "workbox-background-sync@npm:7.3.0": version: 7.3.0 resolution: "workbox-background-sync@npm:7.3.0" @@ -14637,12 +14700,20 @@ __metadata: languageName: node linkType: hard -"xlsx@https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz": - version: 0.20.2 - resolution: "xlsx@https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz" +"xlsx@npm:^0.18.5": + version: 0.18.5 + resolution: "xlsx@npm:0.18.5" + dependencies: + adler-32: "npm:~1.3.0" + cfb: "npm:~1.2.1" + codepage: "npm:~1.15.0" + crc-32: "npm:~1.2.1" + ssf: "npm:~0.11.2" + wmf: "npm:~1.0.1" + word: "npm:~0.3.0" bin: - xlsx: ./bin/xlsx.njs - checksum: 10c0/664dff22e5ecd83d595f34e00ac90ee852d16e45b72385ada54291551b808c6848b166fb395f5e35249ca976a5b5d514e793ccbcc0a611b87a600ae4024d605a + xlsx: bin/xlsx.njs + checksum: 10c0/787cfa77034a3e86fdcde21572f1011c8976f87823a5e0ee5057f13b2f6e48f17a1710732a91b8ae15d7794945c7cba8a3ca904ea7150e028260b0ab8e1158c8 languageName: node linkType: hard From 6126b602fad1d6e58fca5b59b596961ac371a27a Mon Sep 17 00:00:00 2001 From: Richard Dominick <34370238+RichDom2185@users.noreply.github.com> Date: Sat, 9 Aug 2025 17:30:16 +0800 Subject: [PATCH 3/5] Revert dependency changes --- package.json.backup | 201 -------------------------------------------- yarn.lock | 83 ++---------------- 2 files changed, 6 insertions(+), 278 deletions(-) delete mode 100644 package.json.backup diff --git a/package.json.backup b/package.json.backup deleted file mode 100644 index bc70762390..0000000000 --- a/package.json.backup +++ /dev/null @@ -1,201 +0,0 @@ -{ - "private": true, - "type": "module", - "name": "frontend", - "packageManager": "yarn@4.6.0", - "version": "1.4.3", - "scripts-info": { - "analyze": "Analyze bundle size breakdown", - "format": "Format source code", - "start": "Start the Webpack development server", - "build": "Build production bundle", - "test": "Run unit tests", - "update-ui-snapshots": "Update UI test snapshots" - }, - "scripts": { - "analyze": "yarn build --stats; webpack-bundle-analyzer build/bundle-stats.json", - "build": "tsc -b && rsbuild build", - "coverage": "./scripts/coverage-fix.sh do && yarn test --coverage && ./scripts/coverage-fix.sh undo", - "format": "eslint --fix src && prettier --write \"src/**/*.{js,jsx,ts,tsx}\" && prettier --write --parser scss \"src/**/*.scss\"", - "format:tsx": "prettier --list-different \"src/**/*.{js,jsx,ts,tsx}\"", - "format:scss": "prettier --list-different --parser scss \"src/**/*.scss\"", - "format:ci": "yarn run format:tsx && yarn run format:scss", - "start": "rsbuild dev", - "test": "cross-env TZ=Asia/Singapore vitest run", - "test:watch": "cross-env TZ=Asia/Singapore vitest", - "test:ui": "cross-env TZ=Asia/Singapore vitest --ui --no-open", - "test-coveralls": "./scripts/test-coveralls.sh", - "update-ui-snapshots": "vitest run --update", - "eslint": "eslint src", - "prepare": "husky", - "preview": "rsbuild preview" - }, - "dependencies": { - "@blueprintjs/core": "^5.10.1", - "@blueprintjs/datetime2": "^2.3.3", - "@blueprintjs/icons": "^6.0.0", - "@blueprintjs/select": "^5.1.3", - "@convergencelabs/ace-collab-ext": "^0.6.0", - "@mantine/hooks": "^7.11.2", - "@octokit/rest": "^22.0.0", - "@reduxjs/toolkit": "^1.9.7", - "@sentry/browser": "^8.33.0", - "@sourceacademy/c-slang": "^1.0.21", - "@sourceacademy/sharedb-ace": "^2.1.1", - "@sourceacademy/sling-client": "^0.1.0", - "@szhsin/react-menu": "^4.0.0", - "@tanstack/react-table": "^8.9.3", - "@tremor/react": "^1.8.2", - "ace-builds": "^1.42.1", - "acorn": "^8.9.0", - "ag-grid-community": "^32.3.1", - "ag-grid-react": "^32.3.1", - "array-move": "^4.0.0", - "browserfs": "^1.4.3", - "classnames": "^2.3.2", - "conductor": "https://github.com/source-academy/conductor.git#0.2.1", - "dayjs": "^1.11.13", - "dompurify": "^3.2.4", - "flexboxgrid": "^6.3.1", - "flexboxgrid-helpers": "^1.1.3", - "hastscript": "^9.0.0", - "i18next": "^25.0.0", - "i18next-browser-languagedetector": "^8.0.0", - "immer": "^9.0.21", - "java-slang": "^1.0.13", - "js-cookie": "^3.0.5", - "js-slang": "^1.0.84", - "js-yaml": "^4.1.0", - "konva": "^9.2.0", - "language-directory": "https://github.com/source-academy/language-directory.git", - "lodash": "^4.17.21", - "lz-string": "^1.4.4", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-hast": "^13.0.0", - "normalize.css": "^8.0.1", - "phaser": "~3.90.0", - "query-string": "^9.0.0", - "re-resizable": "^6.9.9", - "react": "^18.3.1", - "react-ace": "^14.0.0", - "react-copy-to-clipboard": "^5.1.0", - "react-debounce-render": "^8.0.2", - "react-dom": "^18.3.1", - "react-drag-drop-files": "^3.0.0", - "react-draggable": "^4.4.5", - "react-dropzone": "^14.2.3", - "react-i18next": "^15.0.0", - "react-konva": "^18.2.10", - "react-latex-next": "^3.0.0", - "react-mde": "^11.5.0", - "react-papaparse": "^4.0.2", - "react-qr-reader": "^3.0.0-beta-1", - "react-redux": "^8.1.1", - "react-router": "^7.6.2", - "react-select": "^5.7.3", - "react-simple-keyboard": "^3.6.27", - "react-sortable-hoc": "^2.0.0", - "react-syntax-highlighter": "^15.5.0", - "react-textarea-autosize": "^8.5.2", - "redux-mock-store": "^1.5.4", - "redux-saga": "^1.2.3", - "rehype-react": "^8.0.0", - "showdown": "^2.1.0", - "sourceror": "^0.8.5", - "unified": "^11.0.0", - "uuid": "^11.0.2", - "workbox-core": "^7.3.0", - "workbox-precaching": "^7.3.0", - "workbox-routing": "^7.3.0", - "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz", - "xml2js": "^0.6.0", - "yareco": "^0.1.5" - }, - "devDependencies": { - "@aaroon/workbox-rspack-plugin": "^0.3.2", - "@babel/core": "^7.24.5", - "@babel/plugin-proposal-private-property-in-object": "^7.21.11", - "@babel/preset-typescript": "^7.24.1", - "@babel/runtime": "^7.24.5", - "@rsbuild/core": "^1.3.12", - "@rsbuild/plugin-eslint": "^1.1.1", - "@rsbuild/plugin-node-polyfill": "^1.3.0", - "@rsbuild/plugin-react": "^1.3.0", - "@rsbuild/plugin-sass": "^1.3.1", - "@rsbuild/plugin-svgr": "^1.2.0", - "@svgr/webpack": "^8.0.0", - "@swc/core": "^1.11.22", - "@testing-library/dom": "^10.4.0", - "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^16.0.0", - "@testing-library/user-event": "^14.6.0", - "@types/estree": "^1.0.5", - "@types/gapi": "^0.0.47", - "@types/gapi.auth2": "^0.0.61", - "@types/gapi.client": "^1.0.5", - "@types/gapi.client.drive-v3": "^0.0.5", - "@types/google.picker": "^0.0.51", - "@types/identity-obj-proxy": "^3", - "@types/js-cookie": "^3.0.6", - "@types/js-yaml": "^4.0.5", - "@types/lodash": "^4.14.195", - "@types/react": "^18.3.3", - "@types/react-copy-to-clipboard": "^5.0.4", - "@types/react-dom": "^18.3.0", - "@types/react-redux": "^7.1.24", - "@types/react-syntax-highlighter": "^15.5.7", - "@types/react-test-renderer": "^18.0.0", - "@types/redux-mock-store": "^1.0.3", - "@types/showdown": "^2.0.1", - "@types/xml2js": "^0.4.11", - "@vitejs/plugin-react-swc": "^3.11.0", - "@vitest/coverage-v8": "3.2.4", - "@vitest/ui": "^3.2.4", - "buffer": "^6.0.3", - "canvas": "^3.1.0", - "constants-browserify": "^1.0.0", - "coveralls": "^3.1.1", - "cross-env": "^10.0.0", - "eslint": "^9.9.0", - "eslint-plugin-react": "^7.35.0", - "eslint-plugin-react-hooks": "^5.2.0", - "eslint-plugin-react-refresh": "^0.4.9", - "eslint-plugin-simple-import-sort": "^12.1.1", - "https-browserify": "^1.0.0", - "husky": "^9.0.0", - "identity-obj-proxy": "^3.0.0", - "jsdom": "^26.0.0", - "npm-run-all2": "^8.0.0", - "os-browserify": "^0.3.0", - "path": "^0.12.7", - "path-browserify": "^1.0.1", - "phaser3spectorjs": "^0.0.8", - "prettier": "^3.3.3", - "process": "^0.11.10", - "react-error-overlay": "^6.0.11", - "react-test-renderer": "^18.2.0", - "redux-saga-test-plan": "^4.0.6", - "resize-observer-polyfill": "^1.5.1", - "sass": "^1.63.6", - "stream-browserify": "^3.0.0", - "stream-http": "^3.2.0", - "timers-browserify": "^2.0.12", - "typescript": "^5.8.2", - "typescript-eslint": "^8.1.0", - "url": "^0.11.1", - "vitest": "^3.2.4", - "webpack-bundle-analyzer": "^4.9.0" - }, - "browserslist": { - "production": [ - "Firefox ESR", - "last 2 chrome versions", - "last 2 safari versions" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } -} diff --git a/yarn.lock b/yarn.lock index 526f573d03..77457e5a88 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4613,13 +4613,6 @@ __metadata: languageName: node linkType: hard -"adler-32@npm:~1.3.0": - version: 1.3.1 - resolution: "adler-32@npm:1.3.1" - checksum: 10c0/c1b7185526ee1bbe0eac8ed414d5226af4cd02a0540449a72ec1a75f198c5e93352ba4d7b9327231eea31fd83c2d080d13baf16d8ed5710fb183677beb85f612 - languageName: node - linkType: hard - "ag-charts-types@npm:10.3.8": version: 10.3.8 resolution: "ag-charts-types@npm:10.3.8" @@ -5435,16 +5428,6 @@ __metadata: languageName: node linkType: hard -"cfb@npm:~1.2.1": - version: 1.2.2 - resolution: "cfb@npm:1.2.2" - dependencies: - adler-32: "npm:~1.3.0" - crc-32: "npm:~1.2.0" - checksum: 10c0/87f6d9c3878268896ed6ca29dfe32a2aa078b12d0f21d8405c95911b74ab6296823d7312bbf5e18326d00b16cc697f587e07a17018c5edf7a1ba31dd5bc6da36 - languageName: node - linkType: hard - "chai@npm:^5.2.0": version: 5.2.1 resolution: "chai@npm:5.2.1" @@ -5613,13 +5596,6 @@ __metadata: languageName: node linkType: hard -"codepage@npm:~1.15.0": - version: 1.15.0 - resolution: "codepage@npm:1.15.0" - checksum: 10c0/2455b482302cb784b46dea60a8ee83f0c23e794bdd979556bdb107abe681bba722af62a37f5c955ff4efd68fdb9688c3986e719b4fd536c0e06bb25bc82abea3 - languageName: node - linkType: hard - "color-convert@npm:^1.9.0": version: 1.9.3 resolution: "color-convert@npm:1.9.3" @@ -5897,15 +5873,6 @@ __metadata: languageName: node linkType: hard -"crc-32@npm:~1.2.0, crc-32@npm:~1.2.1": - version: 1.2.2 - resolution: "crc-32@npm:1.2.2" - bin: - crc32: bin/crc32.njs - checksum: 10c0/11dcf4a2e77ee793835d49f2c028838eae58b44f50d1ff08394a610bfd817523f105d6ae4d9b5bef0aad45510f633eb23c903e9902e4409bed1ce70cb82b9bf0 - languageName: node - linkType: hard - "create-ecdh@npm:^4.0.4": version: 4.0.4 resolution: "create-ecdh@npm:4.0.4" @@ -7504,13 +7471,6 @@ __metadata: languageName: node linkType: hard -"frac@npm:~1.1.2": - version: 1.1.2 - resolution: "frac@npm:1.1.2" - checksum: 10c0/640740eb58b590eb38c78c676955bee91cd22d854f5876241a15c49d4495fa53a84898779dcf7eca30aabfe1c1a4a705752b5f224934257c5dda55c545413ba7 - languageName: node - linkType: hard - "frontend@workspace:.": version: 0.0.0-use.local resolution: "frontend@workspace:." @@ -7664,7 +7624,7 @@ __metadata: workbox-core: "npm:^7.3.0" workbox-precaching: "npm:^7.3.0" workbox-routing: "npm:^7.3.0" - xlsx: "npm:^0.18.5" + xlsx: "https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz" xml2js: "npm:^0.6.0" yareco: "npm:^0.1.5" languageName: unknown @@ -12896,15 +12856,6 @@ __metadata: languageName: node linkType: hard -"ssf@npm:~0.11.2": - version: 0.11.2 - resolution: "ssf@npm:0.11.2" - dependencies: - frac: "npm:~1.1.2" - checksum: 10c0/c3fd24a90dc37a9dc5c4154cb4121e27507c33ebfeee3532aaf03625756b2c006cf79c0a23db0ba16c4a6e88e1349455327867e03453fc9d54b32c546bc18ca6 - languageName: node - linkType: hard - "sshpk@npm:^1.7.0": version: 1.17.0 resolution: "sshpk@npm:1.17.0" @@ -14437,20 +14388,6 @@ __metadata: languageName: node linkType: hard -"wmf@npm:~1.0.1": - version: 1.0.2 - resolution: "wmf@npm:1.0.2" - checksum: 10c0/3fa5806f382632cadfe65d4ef24f7a583b0c0720171edb00e645af5248ad0bb6784e8fcee1ccd9f475a1a12a7523e2512e9c063731fbbdae14dc469e1c033d93 - languageName: node - linkType: hard - -"word@npm:~0.3.0": - version: 0.3.0 - resolution: "word@npm:0.3.0" - checksum: 10c0/c6da2a9f7a0d81a32fa6768a638d21b153da2be04f94f3964889c7cc1365d74b6ecb43b42256c3f926cd59512d8258206991c78c21000c3da96d42ff1238b840 - languageName: node - linkType: hard - "workbox-background-sync@npm:7.3.0": version: 7.3.0 resolution: "workbox-background-sync@npm:7.3.0" @@ -14700,20 +14637,12 @@ __metadata: languageName: node linkType: hard -"xlsx@npm:^0.18.5": - version: 0.18.5 - resolution: "xlsx@npm:0.18.5" - dependencies: - adler-32: "npm:~1.3.0" - cfb: "npm:~1.2.1" - codepage: "npm:~1.15.0" - crc-32: "npm:~1.2.1" - ssf: "npm:~0.11.2" - wmf: "npm:~1.0.1" - word: "npm:~0.3.0" +"xlsx@https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz": + version: 0.20.2 + resolution: "xlsx@https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz" bin: - xlsx: bin/xlsx.njs - checksum: 10c0/787cfa77034a3e86fdcde21572f1011c8976f87823a5e0ee5057f13b2f6e48f17a1710732a91b8ae15d7794945c7cba8a3ca904ea7150e028260b0ab8e1158c8 + xlsx: ./bin/xlsx.njs + checksum: 10c0/664dff22e5ecd83d595f34e00ac90ee852d16e45b72385ada54291551b808c6848b166fb395f5e35249ca976a5b5d514e793ccbcc0a611b87a600ae4024d605a languageName: node linkType: hard From d5c74d38ca43b5948878f3f019e12fcdea249621 Mon Sep 17 00:00:00 2001 From: Richard Dominick <34370238+RichDom2185@users.noreply.github.com> Date: Sat, 9 Aug 2025 17:33:14 +0800 Subject: [PATCH 4/5] Add markdownlint config --- .markdownlint.jsonc | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .markdownlint.jsonc diff --git a/.markdownlint.jsonc b/.markdownlint.jsonc new file mode 100644 index 0000000000..feec355226 --- /dev/null +++ b/.markdownlint.jsonc @@ -0,0 +1,3 @@ +{ + "line-length": false +} From 25d3e428aaf7785951dc40a4cfe971cfbcf9d058 Mon Sep 17 00:00:00 2001 From: Richard Dominick <34370238+RichDom2185@users.noreply.github.com> Date: Sat, 9 Aug 2025 17:33:40 +0800 Subject: [PATCH 5/5] Reformat instructions with markdownlint --- .github/copilot-instructions.md | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 3cc398afeb..f92aa050be 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -7,60 +7,75 @@ The Source Academy Frontend is a React.js TypeScript web application for an imme ## Working Effectively ### Environment Setup + - Node.js version: 20.9.0+ (as specified in `.node-version`) - Package manager: Yarn 4.6.0 (managed via corepack) - Enable corepack: `corepack enable` ### Bootstrap and Build Process + 1. **Install dependencies** (25 seconds): + ```bash corepack enable yarn install ``` + **NOTE**: Installation may fail due to network restrictions accessing `cdn.sheetjs.com` for the xlsx package. If this occurs, temporarily modify `package.json` to use `"xlsx": "^0.18.5"` instead of the CDN URL, run `yarn install --mode update-lockfile`, then `yarn install`. 2. **TypeScript compilation** (20 seconds): + ```bash yarn run tsc --noEmit ``` 3. **Linting** (7 seconds): + ```bash yarn run eslint ``` 4. **Format checks** (10 seconds): + ```bash yarn run format:ci ``` 5. **Production build** (40 seconds, **NEVER CANCEL**): + ```bash yarn run build ``` + **CRITICAL**: Set timeout to 60+ minutes. Build completes in ~40 seconds but may take longer on slower systems. 6. **Test suite** (1 minute 45 seconds, **NEVER CANCEL**): + ```bash yarn run test ``` + **CRITICAL**: Set timeout to 30+ minutes. One test may fail due to network restrictions accessing `sicp.sourceacademy.org`. ### Development Server + - **Start development server** (16 seconds build + server startup): + ```bash yarn run start ``` -- **Access**: http://localhost:8000 + +- **Access**: - **Hot reload**: Enabled with live updates ## Validation ### Manual Testing Requirements + **ALWAYS run through at least one complete end-to-end scenario after making changes:** 1. **Basic Playground Functionality**: - - Navigate to http://localhost:8000 (redirects to /playground) + - Navigate to (redirects to /playground) - Verify the editor loads with syntax highlighting - Write test code: `function factorial(n) { return n <= 1 ? 1 : n * factorial(n - 1); } factorial(5);` - Click "Run" button @@ -80,6 +95,7 @@ The Source Academy Frontend is a React.js TypeScript web application for an imme ## Network Limitations **Important**: Several external services are not accessible in sandboxed environments: + - `cdn.sheetjs.com` - xlsx package installation fails - `sicp.sourceacademy.org` - SICP JS content fails to load - `fonts.googleapis.com`, `apis.google.com` - Google services blocked @@ -88,6 +104,7 @@ The Source Academy Frontend is a React.js TypeScript web application for an imme ## Common Tasks ### Repository Structure + ``` /home/runner/work/frontend/frontend/ ├── .github/workflows/ # CI/CD pipelines @@ -107,7 +124,8 @@ The Source Academy Frontend is a React.js TypeScript web application for an imme ``` ### Key npm Scripts -- `yarn start` - Development server (http://localhost:8000) + +- `yarn start` - Development server () - `yarn build` - Production build (40s, outputs to `build/`) - `yarn test` - Test suite (1m45s, may have 1 network-related failure) - `yarn format` - Auto-fix code formatting (ESLint + Prettier) @@ -116,18 +134,23 @@ The Source Academy Frontend is a React.js TypeScript web application for an imme - `yarn tsc` - TypeScript compilation check ### Environment Configuration + Copy `.env.example` to `.env` and configure: + - `REACT_APP_BACKEND_URL` - Backend API endpoint - `REACT_APP_USE_BACKEND` - Enable/disable backend integration - `REACT_APP_PLAYGROUND_ONLY` - Playground-only mode for GitHub Pages - Authentication providers, Google Drive, GitHub integration settings ### Memory Requirements + The build process requires significant memory: + - Set `NODE_OPTIONS=--max_old_space_size=8192` for CI/CD - Local development typically works with default Node.js memory limits ### Technology Stack + - **Frontend**: React 18.3.1 with TypeScript 5.8.2 - **State Management**: Redux Toolkit with Redux Saga - **Build Tool**: rsbuild (modern webpack replacement) @@ -137,10 +160,11 @@ The build process requires significant memory: - **Code Editor**: ACE editor with Source language support ### Debugging Tips + - Check browser console for React DevTools and HMR connection messages - Build warnings about missing Node.js modules (perf_hooks) are expected in browser builds - ESLint warnings about React hooks dependencies are common and generally safe - Use `yarn run test:watch` for interactive test development - Use `yarn run test:ui` for browser-based test UI -**Remember**: Always validate functionality manually by running the application and testing user scenarios. The playground must be able to execute code and display results correctly. \ No newline at end of file +**Remember**: Always validate functionality manually by running the application and testing user scenarios. The playground must be able to execute code and display results correctly.