Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
77a530b
hub/analytics: make analytics cookie optional
haraldschilly Jul 16, 2025
df31e7b
hub/analytics: configure if cookie is set or not
haraldschilly Jul 16, 2025
67608fa
next/abuse: use anonymous user ID from cookie or IP address
haraldschilly Jul 16, 2025
c1d826d
Merge remote-tracking branch 'origin/master' into rm-tracking-cookie
haraldschilly Jul 18, 2025
875e790
next+conat: come up with a universal client IP address extractor
haraldschilly Jul 18, 2025
bb20dc6
Merge remote-tracking branch 'origin/master' into rm-tracking-cookie
haraldschilly Jul 23, 2025
f5b99ca
Merge remote-tracking branch 'origin/master' into rm-tracking-cookie
haraldschilly Aug 8, 2025
dd0ea51
Merge remote-tracking branch 'origin/master' into rm-tracking-cookie
haraldschilly Aug 8, 2025
ea7cce9
Merge remote-tracking branch 'origin/master' into rm-tracking-cookie
haraldschilly Aug 18, 2025
c9a5dfc
Merge remote-tracking branch 'origin/master' into rm-tracking-cookie
haraldschilly Aug 18, 2025
f6bcdf0
Merge remote-tracking branch 'origin/master' into rm-tracking-cookie
haraldschilly Aug 29, 2025
1e9a156
util/get-client-ip: also normalize IPv6 with port numbers
haraldschilly Aug 29, 2025
689fecf
cocalc-api: fix docstring style, check with pyright as well, fix/igno…
haraldschilly Sep 27, 2025
ef6b05d
Merge remote-tracking branch 'origin/master' into cocalc-api-20250927
haraldschilly Sep 27, 2025
4cf7197
cocalc-api: add tests, using localhost instance and a given key
haraldschilly Sep 29, 2025
0772810
cocalc-api: implement project deletion in conat and support a full pr…
haraldschilly Sep 29, 2025
c652d60
cocalc-api: testing organization management
haraldschilly Sep 29, 2025
3eb7997
cocalc-api: coverage report, makefile help
haraldschilly Sep 29, 2025
b824e3f
cocalc-api: attempt to integrate into CI
haraldschilly Sep 30, 2025
d24ec9a
server/organizations logic: only allow site-admins to promote users t…
haraldschilly Sep 30, 2025
5faae38
cocalc-api: adjust org tests after changes to organization logic in s…
haraldschilly Sep 30, 2025
200810a
cocalc-api: fix the CI test
haraldschilly Sep 30, 2025
29dc582
cocalc-api: fix tests, creating accounts started many project servers…
haraldschilly Sep 30, 2025
7390989
Merge remote-tracking branch 'origin/master' into cocalc-api-20250927
haraldschilly Oct 1, 2025
1aed72c
cocalc-api: introduce a cleanup logic, of tracked accounts, orgs and …
haraldschilly Oct 1, 2025
95c7274
cocalc-api: jupyter tests, add endpoints to list/stop kernels
haraldschilly Oct 1, 2025
3f27741
Merge remote-tracking branch 'origin/master' into cocalc-api-20250927
haraldschilly Oct 2, 2025
fc0d26a
cocalc-api/tests: jupyterExecute increase timeout + retry logic
haraldschilly Oct 2, 2025
a31cedb
Merge branch 'master' into cocalc-api-20250927
haraldschilly Oct 3, 2025
cc24e1a
Merge remote-tracking branch 'origin/master' into cocalc-api-20250927
haraldschilly Oct 8, 2025
b9f1deb
Merge branch 'cocalc-api-20250927' of github.com:sagemathinc/cocalc i…
haraldschilly Oct 8, 2025
8dac10f
Merge remote-tracking branch 'origin/master' into cocalc-api-20250927
haraldschilly Oct 9, 2025
f5677b6
ci/cocalc-api: restart hub to enable jupyter api
haraldschilly Oct 9, 2025
057477c
Merge remote-tracking branch 'origin/master' into cocalc-api-20250927
haraldschilly Oct 10, 2025
f4a36b7
Merge remote-tracking branch 'origin/master' into cocalc-api-20250927
haraldschilly Oct 21, 2025
9f74c33
cocalc-api: MCP server stub
haraldschilly Oct 21, 2025
206f178
Merge remote-tracking branch 'origin/master' into cocalc-api-20250927
haraldschilly Oct 22, 2025
cf71ae9
cocalc-api/mcp: first sign of life
haraldschilly Oct 22, 2025
01cae0a
Merge remote-tracking branch 'origin/master' into cocalc-api-20250927
haraldschilly Oct 23, 2025
9756779
cocalc-api/mcp: refine authentication
haraldschilly Oct 23, 2025
e3b9acc
Merge remote-tracking branch 'origin/master' into cocalc-api-20250927
haraldschilly Nov 17, 2025
ccaf299
Merge remote-tracking branch 'origin/master' into cocalc-api-20250927
haraldschilly Nov 18, 2025
0d70752
cocalc-api: update, tweaks for jupyter testing, detecting older api key
haraldschilly Nov 18, 2025
5434d8d
cocalc-api: tweak test config
haraldschilly Nov 18, 2025
7d39dcb
cocalc-api/mcp: jupyter exec and more test fixes
haraldschilly Nov 19, 2025
f5b4f33
Merge remote-tracking branch 'origin/master' into cocalc-api-20250927
haraldschilly Nov 20, 2025
3d2ba2f
cocalc-api/mcp: dynamic tool and resource registration based on api k…
haraldschilly Nov 20, 2025
7bb53dc
frontend/project/disk warning: point to upgrades page instead of sett…
haraldschilly Nov 20, 2025
efdadad
cocalc-api/ci: increase timeout 30 → 90 secs
haraldschilly Nov 20, 2025
747a07d
cocalc-api: improve api key type discovery
haraldschilly Nov 21, 2025
157721b
cocalc-api/mcp: tool and resource descovery via api key or explicit p…
haraldschilly Nov 21, 2025
10646ee
cocalc-api/mcp: touch project when in use
haraldschilly Nov 21, 2025
a8c4ee2
cocalc-api/test: fix edgecases in api and improve testing
haraldschilly Nov 21, 2025
ab4ab26
cocalc-api/mcp: improve project.get (limit, filtering)
haraldschilly Nov 24, 2025
ef5d0ca
cocalc-api/test: fix edge cases in api and improve testing
haraldschilly Nov 24, 2025
80da9ee
Merge remote-tracking branch 'origin/master' into rm-tracking-cookie
haraldschilly Nov 24, 2025
7b6aec2
Merge branch 'master' into rm-tracking-cookie
haraldschilly Nov 24, 2025
8cdfc42
frontend/projects/starred: recalc layout only when really necessary
haraldschilly Nov 25, 2025
b754a26
frontend/settings: translate Dim file extensions and delete/update al…
haraldschilly Nov 25, 2025
e107d42
settings: accordion behavior: start closed, single open submenu
novoselt Nov 27, 2025
364938d
settings: create billing submenu similar to preferences
novoselt Nov 27, 2025
233a7fe
settings: unify and simplify treatment of preferences and billing
novoselt Nov 27, 2025
8557638
npm: update older node-forge 1.3.1 to 1.3.2
haraldschilly Nov 27, 2025
4f31396
frontend/x11: select wss vs ws for https vs http -- useful for local …
haraldschilly Nov 27, 2025
ccd1b33
npm: update js-yaml in non-dev dependencies and bump jest/ts-jest
haraldschilly Nov 27, 2025
4e8b146
frontend/account: add "Accessibility" setting (for now just boolean) …
haraldschilly Nov 27, 2025
55e2641
frontend/projects: fix icon of starred or recent directories
haraldschilly Nov 27, 2025
1b47cc8
settings: improve menu rendering especially in collapsed mode
novoselt Nov 27, 2025
9629cda
settings: add tiles for upgrades and payment methods
novoselt Nov 28, 2025
a17627d
settings: add new tiles to the list of valid pages
novoselt Nov 28, 2025
67a06b7
npm/server: update nodemailer (patch update) and also its @types package
haraldschilly Dec 2, 2025
e3d9f92
frotend/account: move css to sass file and update translations
haraldschilly Dec 2, 2025
a428547
build(deps): bump validator from 13.15.20 to 13.15.22 in /src/packages
dependabot[bot] Dec 2, 2025
4be65f6
accessibility: restructure the policy/statement page, link fresh VPAT
novoselt Dec 4, 2025
e91f843
accessibility: drop old VPAT
novoselt Dec 4, 2025
f4dd427
assignment: restructure header and notes with AntD layout
novoselt Dec 8, 2025
9561d97
Merge remote-tracking branch 'origin/rm-tracking-cookie' into pr-2025…
haraldschilly Dec 8, 2025
07679ec
Merge remote-tracking branch 'origin/cocalc-api-20250927' into pr-202…
haraldschilly Dec 8, 2025
28186c1
Merge remote-tracking branch 'origin/fix-full-disk-link' into pr-2025…
haraldschilly Dec 8, 2025
a1a91b9
Merge remote-tracking branch 'origin/fix-blinks-starred-projects' int…
haraldschilly Dec 8, 2025
751f4e7
Merge remote-tracking branch 'origin/i18n-after-PR-8654' into pr-2025…
haraldschilly Dec 8, 2025
31ded84
Merge remote-tracking branch 'origin/npm-node-forge-xpra' into pr-202…
haraldschilly Dec 8, 2025
f885701
Merge remote-tracking branch 'origin/npm-upd-20251127' into pr-20251208
haraldschilly Dec 8, 2025
74f0c57
Merge remote-tracking branch 'origin/frontent-accessibility-mode' int…
haraldschilly Dec 8, 2025
88d2681
Merge remote-tracking branch 'origin/fix-icon-files-starred-dropdown'…
haraldschilly Dec 8, 2025
501a23e
Merge remote-tracking branch 'origin/npm-nodemailer-20251202' into pr…
haraldschilly Dec 8, 2025
b2ed26a
Merge remote-tracking branch 'origin/dependabot/npm_and_yarn/src/pack…
haraldschilly Dec 8, 2025
19ca1d0
Merge branch 'novoselt-billing-preferences' into pr-20251208
haraldschilly Dec 8, 2025
392901f
Merge branch 'novoselt-vpat' into pr-20251208
haraldschilly Dec 8, 2025
36316e8
npm: update next -- https://github.com/sagemathinc/cocalc/pull/8672
haraldschilly Dec 8, 2025
10e4b59
frontend/course/assignmens: save assignment note on explicitly "done"…
haraldschilly Dec 9, 2025
4749f39
Merge branch 'novoselt-assignment_header' into pr-20251208
haraldschilly Dec 9, 2025
b27ee73
next/api/projects/delete: signed-in check inside try/catch + add test…
haraldschilly Dec 9, 2025
cd5cb8d
frontend/project/datastore: make sshfs port number configurable
haraldschilly Dec 9, 2025
1301533
datastore: validate port number (in a general way) in frontend and ba…
haraldschilly Dec 10, 2025
50c62ec
Merge remote-tracking branch 'origin/datastore-sshfs-port' into pr-20…
haraldschilly Dec 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 185 additions & 1 deletion .github/workflows/make-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ jobs:
pip install ipykernel
python -m ipykernel install --prefix=./jupyter-local --name python3-local --display-name "Python 3 (Local)"


- name: install pnpm
uses: pnpm/action-setup@v4
with:
Expand All @@ -128,6 +127,191 @@ jobs:
name: "test-results-node-${{ matrix.node-version }}-pg-${{ matrix.pg-version }}"
path: 'src/packages/*/junit.xml'

- name: Start CoCalc Hub
run: |
# Create conat password for hub internal authentication
mkdir -p src/data/secrets
echo "test-conat-password-$(date +%s)" > src/data/secrets/conat-password
chmod 600 src/data/secrets/conat-password

cd src/packages/hub
pnpm run hub-project-dev-nobuild > hub.log 2>&1 &
HUB_PID=$!
echo $HUB_PID > hub.pid
echo "Hub started with PID $HUB_PID"
# Check if process is still running after a moment
sleep 2
if ! kill -0 $HUB_PID 2>/dev/null; then
echo "Error: Hub process died immediately after starting"
echo "Hub log:"
cat hub.log
exit 1
fi
env:
PGDATABASE: smc
PGUSER: smc
PGHOST: localhost
COCALC_MODE: single-user
COCALC_TEST_MODE: yes
DEBUG: 'cocalc:*,-cocalc:silly:*,hub:*,project:*'

- name: Wait for hub readiness
run: |
MAX_ATTEMPTS=30
READY=false
for i in $(seq 1 $MAX_ATTEMPTS); do
if curl -sf --max-time 3 http://localhost:5000/healthcheck > /dev/null; then
echo "Hub is ready"
READY=true
break
fi
echo "Waiting for hub... ($i/$MAX_ATTEMPTS)"
sleep 3
done
if [ "$READY" = "false" ]; then
echo "Hub failed to become ready after $MAX_ATTEMPTS attempts"
echo "Hub log:"
cat src/packages/hub/hub.log || echo "No log file found"
exit 1
fi

- name: Create CI admin user and API key
run: |
cd src/packages/hub
OUTPUT=$(node dist/run/test-create-admin.js)
# Split output into account_id and API key (format: UUID;api-key)
ACCOUNT_ID=$(echo "$OUTPUT" | cut -d';' -f1)
API_KEY=$(echo "$OUTPUT" | cut -d';' -f2)

# Store in separate files
echo "$ACCOUNT_ID" > ../../account_id.txt
echo "$API_KEY" > ../../api_key.txt

# Validate account ID (UUID format)
if ! echo "$ACCOUNT_ID" | grep -qE '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'; then
echo "Error: Invalid account ID format: $ACCOUNT_ID"
exit 1
fi

# Validate API key was created
if [ ! -s ../../api_key.txt ]; then
echo "Error: API key file is empty or missing"
exit 1
fi
if ! echo "$API_KEY" | grep -qE '^sk-[A-Za-z0-9]+$'; then
echo "Error: Invalid API key format: $API_KEY"
exit 1
fi

echo "Account ID: $ACCOUNT_ID"
echo "API key created successfully"
env:
PGDATABASE: smc
PGUSER: smc
PGHOST: localhost

- name: Restart CoCalc Hub
run: |
HUB_PID=$(cat src/packages/hub/hub.pid)
echo "Stopping hub with PID $HUB_PID"
kill $HUB_PID || true
# Wait a bit for graceful shutdown
sleep 5
# Force kill if still running
kill -9 $HUB_PID 2>/dev/null || true

# Read the admin account ID created in the previous step
cd src/packages/hub
ADMIN_ACCOUNT_ID=$(cat ../../account_id.txt)
echo "Using admin account ID: $ADMIN_ACCOUNT_ID"

# Export env vars for the hub process
export COCALC_SETTING_JUPYTER_API_ENABLED=yes
export COCALC_SETTING_JUPYTER_ACCOUNT_ID=$ADMIN_ACCOUNT_ID
export COCALC_SETTING_JUPYTER_PROJECT_POOL_SIZE=1

# Start hub with new configuration
pnpm run hub-project-dev-nobuild > hub.log 2>&1 &
HUB_PID=$!
echo $HUB_PID > hub.pid
echo "Hub restarted with PID $HUB_PID"

# Check if process is still running after a moment
sleep 2
if ! kill -0 $HUB_PID 2>/dev/null; then
echo "Error: Hub process died immediately after restarting"
echo "Hub log:"
cat hub.log
exit 1
fi

# Wait for hub to be ready
MAX_ATTEMPTS=30
READY=false
for i in $(seq 1 $MAX_ATTEMPTS); do
if curl -sf --max-time 3 http://localhost:5000/healthcheck > /dev/null; then
echo "Hub is ready after restart"
READY=true
break
fi
echo "Waiting for hub to be ready... ($i/$MAX_ATTEMPTS)"
sleep 3
done
if [ "$READY" = "false" ]; then
echo "Hub failed to become ready after restart"
echo "Hub log:"
cat hub.log
exit 1
fi
env:
PGDATABASE: smc
PGUSER: smc
PGHOST: localhost
COCALC_MODE: single-user
COCALC_TEST_MODE: yes
DEBUG: 'cocalc:*,-cocalc:silly:*,hub:*,project:*'

- name: Install uv for cocalc-api tests
run: curl -LsSf https://astral.sh/uv/install.sh | sh && echo "$HOME/.local/bin" >> $GITHUB_PATH

- name: Run cocalc-api tests
run: |
export COCALC_API_KEY=$(cat src/api_key.txt)
export COCALC_HOST=http://localhost:5000
export CI=true
cd src/python/cocalc-api && make ci
env:
PGDATABASE: smc
PGUSER: smc
PGHOST: localhost

- name: Stop CoCalc Hub
if: always()
run: |
if [ -f src/packages/hub/hub.pid ]; then
HUB_PID=$(cat src/packages/hub/hub.pid)
echo "Stopping hub with PID $HUB_PID"
kill $HUB_PID || true
# Wait a bit for graceful shutdown
sleep 5
# Force kill if still running
kill -9 $HUB_PID 2>/dev/null || true
fi

- name: Upload hub logs
uses: actions/upload-artifact@v4
if: always()
with:
name: "hub-logs-node-${{ matrix.node-version }}-pg-${{ matrix.pg-version }}"
path: 'src/packages/hub/hub.log'

- name: Upload cocalc-api test results
uses: actions/upload-artifact@v4
if: always()
with:
name: "cocalc-api-test-results-node-${{ matrix.node-version }}-pg-${{ matrix.pg-version }}"
path: 'src/python/cocalc-api/test-results.xml'

report:
runs-on: ubuntu-latest

Expand Down
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ src/conf/tinc_hosts/
# mocha: banket coverage report
src/coverage
src/*/coverage

# Python coverage files
.coverage
.coverage.*
htmlcov/
**/htmlcov/
# comes up when testing in that directory
src/rethinkdb_data/
src/dev/project/rethinkdb_data/
Expand Down Expand Up @@ -169,3 +175,5 @@ junit.xml

# autogenerated docs
**/cocalc-api/site/**

!src/packages/next/public/documents/*.pdf
7 changes: 7 additions & 0 deletions src/.claude/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
"Bash(pnpm exec tsc:*)",
"Bash(pnpm i18n:*)",
"Bash(pnpm i18n:*:*)",
"Bash(pnpm i18n:compile:*)",
"Bash(pnpm i18n:download:*)",
"Bash(pnpm i18n:extract:*)",
"Bash(pnpm i18n:upload:*)",
"Bash(pnpm i18n:update:*)",
"Bash(pnpm info:*)",
"Bash(pnpm list:*)",
Expand All @@ -49,9 +53,12 @@
"Bash(prettier -w:*)",
"Bash(psql:*)",
"Bash(python3:*)",
"Bash(uv:*)",
"Bash(timeout:*)",
"Bash(uv sync:*)",
"WebFetch",
"WebSearch",
"mcp__cocalc__*",
"mcp__cclsp__find_definition",
"mcp__cclsp__find_references",
"mcp__github__get_issue",
Expand Down
64 changes: 55 additions & 9 deletions src/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,22 @@ CoCalc is organized as a monorepo with key packages:
5. **Authentication**: Each conat request includes account_id and is subject to permission checks at the hub level
6. **Subjects**: Messages are routed using hierarchical subjects like `hub.account.{uuid}.{service}` or `project.{uuid}.{compute_server_id}.{service}`

#### CoCalc Conat Hub API Architecture

**API Method Registration Pattern:**

- **Registry**: `packages/conat/hub/api/projects.ts` contains `export const projects = { methodName: authFirstRequireAccount }`
- **Implementation**: `packages/server/conat/api/projects.ts` contains `export async function methodName() { ... }`
- **Flow**: Python client `@api_method("projects.methodName")` → POST `/api/conat/hub` → `hubBridge()` → conat subject `hub.account.{account_id}.api` → registry lookup → implementation

**Example - projects.createProject:**

1. **Python**: `@api_method("projects.createProject")` decorator
2. **HTTP**: `POST /api/conat/hub {"name": "projects.createProject", "args": [...]}`
3. **Bridge**: `hubBridge()` routes to conat subject
4. **Registry**: `packages/conat/hub/api/projects.ts: createProject: authFirstRequireAccount`
5. **Implementation**: `packages/server/conat/api/projects.ts: export { createProject }` → `@cocalc/server/projects/create`

### Key Technologies

- **TypeScript**: Primary language for all new code
Expand Down Expand Up @@ -158,7 +174,6 @@ CoCalc is organized as a monorepo with key packages:
- Prefix git commits with the package and general area. e.g. 'frontend/latex: ...' if it concerns latex editor changes in the packages/frontend/... code.
- When pushing a new branch to Github, track it upstream. e.g. `git push --set-upstream origin feature-foo` for branch "feature-foo".


## React-intl / Internationalization (i18n)

CoCalc uses react-intl for internationalization with SimpleLocalize as the translation platform.
Expand All @@ -176,7 +191,7 @@ Translation IDs follow a hierarchical pattern: `[directory].[subdir].[filename].

Examples:

- `labels.masked_files` - for common UI labels
- `labels.account` - for common UI labels
- `account.sign-out.button.title` - for account sign-out dialog
- `command.generic.force_build.label` - for command labels

Expand Down Expand Up @@ -216,11 +231,42 @@ Same flow as above, but **before 3. i18n:upload**, delete the key. Only new keys
- Ignore everything in `node_modules` or `dist` directories
- Ignore all files not tracked by Git, unless they are newly created files

# Important Instruction Reminders
# CoCalc Python API Client Investigation

## Overview

The `python/cocalc-api/` directory contains a uv-based Python client library for the CoCalc API, published as the `cocalc-api` package on PyPI.

It also contains a test framework (`python/cocalc-api/tests/README.md`) and an MCP client (`python/cocalc-api/src/cocalc_api/mcp/README.md`).
For convenience, a `python/cocalc-api/Makefile` exists.

## Client-Server Architecture Investigation

### API Call Flow

1. **cocalc-api Client** (Python) → HTTP POST requests
2. **Next.js API Routes** (`/api/conat/{hub,project}`) → Bridge to conat messaging
3. **ConatClient** (server-side) → NATS-like messaging protocol
4. **Hub API Implementation** (`packages/conat/hub/api/`) → Actual business logic

### Endpoints Discovered

#### Hub API: `POST /api/conat/hub`

- **Bridge**: `packages/next/pages/api/conat/hub.ts` → `hubBridge()` → conat subject `hub.account.{account_id}.api`
- **Implementation**: `packages/conat/hub/api/projects.ts`
- **Available Methods**: `createProject`, `start`, `stop`, `setQuotas`, `addCollaborator`, `removeCollaborator`, etc.

#### Project API: `POST /api/conat/project`

- **Bridge**: `packages/next/pages/api/conat/project.ts` → `projectBridge()` → conat project subjects
- **Implementation**: `packages/conat/project/api/` (system.ping, system.exec, system.jupyterExecute)

# important-instruction-reminders

- Do what has been asked; nothing more, nothing less
- NEVER create files unless they're absolutely necessary for achieving your goal
- ALWAYS prefer editing an existing file to creating a new one
- REFUSE to modify files when the git repository is on the `master` or `main` branch
- NEVER proactively create documentation files (`*.md`) or README files. Only create documentation files if explicitly requested by the User
- when modifying a file with a copyright banner at the top, make sure to fix/add the current year to indicate the copyright year
- Do what has been asked; nothing more, nothing less.
- NEVER create files unless they're absolutely necessary for achieving your goal.
- ALWAYS prefer editing an existing file to creating a new one.
- NEVER proactively create documentation files (\*.md) or README files. Only create documentation files if explicitly requested by the User.
- ALWAYS ask questions if something is unclear. Only proceed to the implementation step if you have no questions left.
- When modifying a file with a copyright banner at the top, make sure to fix/add the current year to indicate the copyright year.
3 changes: 3 additions & 0 deletions src/cocalc.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
{
"name": "cocalc",
"path": "."
},
{
"path": "../.github"
}
],
"settings": {
Expand Down
Loading