diff --git a/.gitignore b/.gitignore index 60ef949c1e..1779ca803a 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,8 @@ notebooks tmp/appmap packages/*/tmp/ packages/cli/tests/unit/fixtures/malformedParentId/parent_id_49_does_not_exist/ +# Gradle test fixtures regenerate their build/ trees on every run. +packages/cli/tests/unit/fixtures/java/**/build/ *.appmap.json .navie .run-stats diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000..ad1b28229a --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,39 @@ +# Verifying changes + +This is a Yarn 3 monorepo (`packages/*`). CI rejects pushes for both lint errors and tsc errors, with several-minute round-trip costs per CI run. Verify locally before committing. + +## When to run verify + +After any **substantial batch of changes** — multiple files touched, new functions added, tests added, refactors — run `yarn verify` from the repo root before reporting work complete or asking to commit. A one-line typo fix doesn't need it; a multi-file change does. + +## How to run verify + +```sh +yarn verify # check working-tree changes (staged + unstaged + untracked) +yarn verify:staged # check only staged changes +``` + +`scripts/verify.mjs`: + +1. Reads modified files from git. +2. Groups them by `packages//`. +3. For each affected package: runs ESLint (`--quiet`, errors only) on the changed lintable files, then `tsc --noEmit` on the whole package (since TS is project-wide, you can't typecheck a single file). + +Typical run on one package: ~5–7s. CI's full lint+typecheck takes ~30s; scoped is ~3× faster. + +## Adding verify to a package + +If you touch a package that doesn't yet participate, add a `typecheck` script (`tsc --noEmit`) to its `package.json` so `verify.mjs` includes it. The existing `lint` script is enough for ESLint coverage. + +## What verify catches + +- ESLint errors that CI rejects: `array-type` (use `T[]` not `Array`), `no-unnecessary-type-assertion`, `prefer-function-type`, `prefer-optional-chain`, etc. Warnings (e.g. `no-unsafe-*`, `prefer-nullish-coalescing`) are suppressed by `--quiet`. +- Type errors that `tsc --noEmit` finds, including yargs `CommandModule` assignability issues that require widening exported handler argv types. + +# Driving the MCP after MCP-side changes + +The `appmap query mcp` server lives in `built/cli.js`. If you change anything under `packages/cli/src/cmds/query/queries/mcp.ts` (or anywhere it transitively imports), you must run `npx tsc` (or `yarn build`) inside `packages/cli` before launching `mcp` for ad-hoc testing. A stale binary will respond to `tools/list` with the old surface — symptom is usually `unknown tool: …` from a client driving a tool the source defines. + +# Recording with appmap-node from a monorepo + +`npx appmap-node@latest npx jest …` invoked from the repo root can fail to parse `.ts` test files with a babel SyntaxError, because the inner jest doesn't pick up `packages//jest.config.js`'s `ts-jest` preset. Run from the package directory whose preset matters — e.g. `cd packages/cli && npx appmap-node@latest npx jest …`. diff --git a/package.json b/package.json index 8b0e76759d..92d534e07b 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,8 @@ ], "scripts": { "lint": "yarn workspaces foreach --exclude root -v run lint", + "verify": "node scripts/verify.mjs", + "verify:staged": "node scripts/verify.mjs --staged", "test": "yarn workspaces foreach --exclude '{root}' -v run test", "build": "yarn workspaces foreach -t --exclude root -v run build", "build-native": "yarn workspaces foreach -t --exclude root -v run build-native", diff --git a/packages/cli/.eslintrc.cjs b/packages/cli/.eslintrc.cjs index cbaab0be01..1ee54c49e9 100644 --- a/packages/cli/.eslintrc.cjs +++ b/packages/cli/.eslintrc.cjs @@ -22,7 +22,13 @@ const FIXME = [ module.exports = { root: true, ignorePatterns: [ - 'src/telemetry.ts', // symlink to a separate "package" + '.eslintrc.cjs', // self — type-aware parser doesn't include this file in tsconfig.lint + 'src/telemetry.ts', // symlink to a separate "package" + // The query-ui React app has its own toolchain (esbuild + tailwind); + // the main cli ESLint/TS setup doesn't ship React types and treats + // src/html as build-only, matching how src/html/{appmap,navie}.js are + // already handled. + 'src/html/query-ui/**', ], env: { browser: true, diff --git a/packages/cli/esbuild.html.ts b/packages/cli/esbuild.html.ts index 0dc15236c2..4aa981ba52 100644 --- a/packages/cli/esbuild.html.ts +++ b/packages/cli/esbuild.html.ts @@ -110,3 +110,123 @@ esbuild console.warn(err); process.exit(1); }); + +// Query UI React SPA — main app shell. +// +// Output goes under `built/html/query-ui/` so the cli's `query ui` verb +// can serve it (`packages/cli/src/cmds/query/lib/uiServer.ts` looks +// there). Tailwind CSS is built separately by `build:ui:css` and lands +// at `built/html/query-ui/tailwind.css`, referenced from the inline +// HTML template below. +esbuild + .build({ + minify: true, + sourcemap: true, + target: 'es2021', + metafile: true, + outdir: 'built/html/query-ui', + bundle: true, + logLevel: 'info', + define: { + 'process.env': '{}', + 'process.env.NODE_ENV': '"production"', + global: 'window', + }, + loader: { '.ts': 'tsx', '.tsx': 'tsx' }, + entryPoints: ['src/html/query-ui/src/main.tsx'], + plugins: [ + htmlPlugin({ + files: [ + { + entryPoints: ['src/html/query-ui/src/main.tsx'], + filename: 'index.html', + htmlTemplate: ` + + + + + AppMap Query UI + + + +
+ +`, + }, + ], + }), + ], + }) + .catch((err) => { + console.warn(err); + process.exit(1); + }); + +// Query UI — embedded AppMap viewer. +// +// Vue 2 + @appland/components mount that the React detail page loads +// via