diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 82dbaa20..81eb403b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,13 @@ jobs: with: node-version: ${{ matrix.node-version }} cache: "npm" + # dfx is still needed for `dfx generate` (decl:cli) and the + # production deploy paths (deploy-staging/deploy-ic, release.yml). + # Local network + deploy now go through icp-cli (see deploy-local + # and replica scripts in package.json). - uses: dfinity/setup-dfx@e50c04f104ee4285ec010f10609483cf41e4d365 # main + - name: Install icp-cli + run: npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm - uses: ./.github/actions/cache-rust-wasm @@ -68,6 +74,9 @@ jobs: - name: Deploy backend run: npm run deploy-local + - name: Generate declarations + run: npm run decl + - name: Build frontend run: npm run build-frontend diff --git a/.gitignore b/.gitignore index f7764cfa..b14bcc98 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ node_modules/ target/ dist/ .dfx/ +.icp/cache/ .mops/ .migrations-*/ mops.lock diff --git a/AGENTS.md b/AGENTS.md index 3b0b2edf..cf38b510 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -30,7 +30,7 @@ npm run lint # ESLint npm run fix # Prettier + ESLint fix npm run check # TypeScript check for CLI + Frontend (parallel) npm test # mops test (Motoko) + CLI Jest tests -npm start # Start local dfx replica + deploy + all frontends +npm start # Start local icp replica + deploy + all frontends ``` ### CLI (`cd cli/`) @@ -70,6 +70,7 @@ Svelte 5 + Vite 8, queries the main canister. Staging canister: `ogp6e-diaaa-aaa ## Key constraints +- **Local pipeline uses icp-cli**: `npm run replica` and `npm run deploy-local` use `icp` (config in `icp.yaml`). `dfx.json` is still kept around — production deploys (`deploy-staging`, `deploy-ic`, `release.yml`) and `npm run decl:cli` (`dfx generate`) still go through dfx. - **dfx version**: pinned in `dfx.json` via `dfxvm`. Do not run `dfxvm update/install/default` to change it. -- **Declarations must be regenerated** after backend changes: `npm run decl` (requires local dfx running). +- **Declarations must be regenerated** after backend changes: `npm run decl` (uses `dfx generate`, no replica needed). - **API version** in `cli/mops.ts` (`apiVersion`) and `backend/main/main-canister.mo` (`API_VERSION`) must match. diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 4a919abc..0059dd49 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -15,17 +15,33 @@ interface CanisterIds { let canisterIds: CanisterIds = {}; try { - canisterIds = JSON.parse( - fs - .readFileSync( - network === "local" - ? "../.dfx/local/canister_ids.json" - : "../canister_ids.json", - ) - .toString(), - ); + if (network === "local") { + // icp-cli writes a flat { name: id } map per environment; dfx writes + // { name: { network: id } }. Try icp first, fall back to dfx. + try { + const icpIds = JSON.parse( + fs.readFileSync("../.icp/cache/mappings/local.ids.json").toString(), + ) as Record; + canisterIds = Object.fromEntries( + Object.entries(icpIds).map(([name, id]) => [ + name, + { local: id } as { [k in Network]: string }, + ]), + ); + } catch { + canisterIds = JSON.parse( + fs.readFileSync("../.dfx/local/canister_ids.json").toString(), + ); + } + } else { + canisterIds = JSON.parse( + fs.readFileSync("../canister_ids.json").toString(), + ); + } } catch (e) { - console.error("\n⚠️ Before starting the dev server run: dfx deploy\n\n"); + console.error( + "\n⚠️ Before starting the dev server run: npm run deploy-local\n\n", + ); } // Generate canister ids, required by the generated canister code in .dfx/local/declarations/* diff --git a/icp.yaml b/icp.yaml new file mode 100644 index 00000000..7ae78032 --- /dev/null +++ b/icp.yaml @@ -0,0 +1,81 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/dfinity/icp-cli/main/docs/schemas/icp-yaml-schema.json +# +# Mirrors dfx.json. dfx.json is still kept around for the production deploy +# path (release.yml, deploy-staging, deploy-ic) and for mops users who haven't +# migrated yet. + +canisters: + - name: main + recipe: + type: "@dfinity/motoko@v4.1.0" + configuration: + main: backend/main/main-canister.mo + compress: true + shrink: true + - name: bench + recipe: + type: "@dfinity/motoko@v4.1.0" + configuration: + main: cli/commands/bench/bench-canister.mo + - name: assets + recipe: + type: "@dfinity/asset-canister@v2.1.0" + configuration: + version: "0.29.1" + dir: frontend/dist + build: + - npm run build-frontend + - name: docs + recipe: + type: "@dfinity/asset-canister@v2.1.0" + configuration: + version: "0.29.1" + dir: docs/build + build: + - npm run build-docs + - name: blog + recipe: + type: "@dfinity/asset-canister@v2.1.0" + configuration: + version: "0.29.1" + dir: blog/build + build: + - npm run build-blog + # Raw build/sync (not the recipe) because the asset-canister recipe template + # only supports a single `dir`, but dfx.json ships two sources for `cli`: + # `cli-releases/` (install.sh, releases.json, tags/, versions/ — served at + # cli.mops.one) and `cli-releases/frontend/dist/` (the SPA). + - name: cli + build: + steps: + - type: script + commands: + - npm run build-cli-releases + - type: pre-built + url: https://github.com/dfinity/sdk/releases/download/0.29.1/assetstorage.wasm.gz + sync: + steps: + - type: assets + dirs: + - cli-releases + - cli-releases/frontend/dist + # Static-only canister: no build step, just serves + # play-frontend/.well-known/ic-domains. + - name: play-frontend + build: + steps: + - type: pre-built + url: https://github.com/dfinity/sdk/releases/download/0.29.1/assetstorage.wasm.gz + sync: + steps: + - type: assets + dir: play-frontend + +# Override the default local network port (8000) to bind on dfx's 4943 so +# vite's /api proxy keeps working without changes to the proxy config. +networks: + - name: local + mode: managed + gateway: + bind: 127.0.0.1 + port: 4943 diff --git a/package.json b/package.json index 48a812ed..5a79f270 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "start-docs": "cd docs && npm run start", "start-blog": "cd blog && npm run start", "start-cli-releases": "cd cli-releases && npm run start", - "replica": "dfx stop && dfx start --clean --background", + "replica": "icp network stop -e local 2>/dev/null; rm -rf .icp/cache/networks && icp network start --background -e local", "decl": "npm run decl:cli && npm run decl:frontend", "lint": "eslint .", "fix": "prettier --write . && eslint --fix .", @@ -17,7 +17,7 @@ "format": "prettier --write .", "format:check": "prettier --check .", "deploy": "dfx deploy --no-wallet --identity ${IDENTITY:-default} --network ${DFX_NETWORK:-local}", - "deploy-local": "NODE_ENV=development dfx deploy --identity default --no-wallet main", + "deploy-local": "NODE_ENV=development icp deploy -y -e local main", "deploy-staging": "NODE_ENV=production IDENTITY=mops DFX_NETWORK=staging npm run deploy", "deploy-ic": "NODE_ENV=production IDENTITY=mops DFX_NETWORK=ic npm run deploy", "deploy:main": "NODE_ENV=development IDENTITY=default DFX_NETWORK=local npm run deploy main",