From 15fe4811813d58d90bc4f687173bd502acca227f Mon Sep 17 00:00:00 2001 From: Danny Kim Date: Fri, 16 Oct 2026 23:41:04 +0900 Subject: [PATCH] Prune migration notes and align the notes with the current lint setup --- .agents/memory/app-repo-specific-decisions.md | 4 +- .agents/memory/bot-agents-lint-opt-outs.md | 15 ++-- .agents/memory/deno-to-node-migration.md | 45 ----------- .agents/memory/imports-aliases-barrels.md | 7 +- .agents/memory/lint-config-shape.md | 9 +-- .agents/memory/lit-analyzer-ts6.md | 7 +- .agents/memory/package-json-shape.md | 31 ++------ .agents/memory/project-lint-plugin.md | 8 +- .agents/memory/publishing-ci-only.md | 2 +- .agents/memory/toolchain-node-vite-plus.md | 4 +- .agents/memory/ts-only-files-and-imports.md | 15 ++-- .agents/skills/migrate-deno-repo/SKILL.md | 74 ------------------- 12 files changed, 47 insertions(+), 174 deletions(-) delete mode 100644 .agents/memory/deno-to-node-migration.md delete mode 100644 .agents/skills/migrate-deno-repo/SKILL.md diff --git a/.agents/memory/app-repo-specific-decisions.md b/.agents/memory/app-repo-specific-decisions.md index 188bad5..0c693d2 100644 --- a/.agents/memory/app-repo-specific-decisions.md +++ b/.agents/memory/app-repo-specific-decisions.md @@ -12,7 +12,9 @@ Node + Vite+ migration (PR #20, `node-migration`, 2026-10-15/16): consumer (`uses: .../commons/bot-agents@`) on a throwaway PR. - **Profiles are JSON.** `profiles.yml` became `profiles.json` with the same content (encrypted `v1:` values unchanged), read with `JSON.parse`. That - removed the only runtime dependency (`@std/yaml`); keep it dependency-free. + removed the only runtime dependency (`@std/yaml`); keep it free of runtime + dependencies (`@eslint/core` and the other devDependencies serve only the + tooling). - **Node 24.2+**, not 22: `src/post.ts` uses `import.meta.main`. `engines.node` is `>=24.2`, which the user accepted for this repo ([[bot-agents-runtime-no-build]]). diff --git a/.agents/memory/bot-agents-lint-opt-outs.md b/.agents/memory/bot-agents-lint-opt-outs.md index 96f3186..7145c6d 100644 --- a/.agents/memory/bot-agents-lint-opt-outs.md +++ b/.agents/memory/bot-agents-lint-opt-outs.md @@ -1,17 +1,18 @@ --- -description: bot-agents lint has prefer-readonly-parameter-types off (Node/web types can't satisfy it) and one scripts/** override for no-unsafe-enum-comparison; nothing else +description: bot-agents lint has prefer-readonly-parameter-types off (Node/web types can't satisfy it) and no overrides; nothing else --- -The repo follows [[lint-config-shape]] with two recorded exceptions, both -present when the migration PR was approved: +The repo follows [[lint-config-shape]] with one recorded exception, present +when the migration PR was approved: - `typescript/prefer-readonly-parameter-types` is `"off"` in `scripts/project-lint.ts`, as in the explicit-types template, because Node/web types (`Response`, `Stats`, `RequestInit`) can never satisfy it. -- `vite.config.ts` has one `overrides` entry, for `scripts/**` only: - `typescript/no-unsafe-enum-comparison` off, because the lint plugin compares - AST node `type`s, which the AST types declare as an enum. This is the - tooling exception [[lint-overrides-policy]] allows. +- `vite.config.ts` has no `overrides`. The `scripts/**` override for + `typescript/no-unsafe-enum-comparison` was removed (2026-10-16): + `scripts/project-lint.ts` compares node types with `AST_NODE_TYPES` members + from `@typescript-eslint/types` instead of string literals + ([[lint-overrides-policy]]). Oxlint's default size limits apply to `src/`; the migration split `run.ts` into `run-context.ts`, `agents.ts`, and `agent-{claude,codex,opencode}.ts`, diff --git a/.agents/memory/deno-to-node-migration.md b/.agents/memory/deno-to-node-migration.md deleted file mode 100644 index c40fdf2..0000000 --- a/.agents/memory/deno-to-node-migration.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -description: Every repo moved from Deno to Node + Vite+ in Oct 2026 because Cloudflare bought Deno; nothing goes back to Deno ---- - -On 2026-10-12 the user moved every project from Deno to Node.js + Vite+ -(`vp`). Cloudflare bought Deno on 2026-10-09; the runtime gets roughly 12 -months of maintenance and Deno Deploy shuts down around April 2027. None of the -repos used Deploy or KV, so the move is about the toolchain, not hosting. - -Do not reintroduce `deno.json`, `deno.lock`, `Deno.*` APIs, `jsr:` or `npm:` -specifiers, `mod.ts` entries, or `deno task` anywhere, docs and scripts -included. - -## Order the migration followed - -1. The custom Deno lint plugins were ported to npm first, as - `@cunarist/eslint-plugin-explicit-types`, `-import-check`, and `-lit`. - `cunarist/eslint-plugin-explicit-types` is the template every other repo - copies (config shape, `scripts/project-lint.ts`, AGENTS.md, notes). -2. Then `commons/bot-agents` (six repos use it as an action), then the apps: - home, eximium, stockvibe, brain, memona, memona-home. -3. deno-practice, interview-practice, web-landing, and vemium were left out - (archivable). Old `cunarist/deno-*` repos are archived one at a time, and - only after their `eslint-plugin-*` replacement is published to npm. - -## What "migrated" means - -- Same behavior. A migration PR changes tooling, not features. -- Lint coverage is at least what Deno enforced: [[lint-parity-never-shrinks]]. -- Only three config files and only `.ts`: [[toolchain-node-vite-plus]], - [[ts-only-files-and-imports]]. -- Deno.test suites became Vitest: [[tests-layout-vitest]]. - -The custom plugins' Deno names map like this: - -| Deno | npm | -| ----------------------------------------------- | ---------------------------------------- | -| `jsr:@cunarist/deno-lint-plugin-explicit-types` | `@cunarist/eslint-plugin-explicit-types` | -| `jsr:@cunarist/deno-import-check` (`./lint`) | `@cunarist/eslint-plugin-import-check` | -| `jsr:@cunarist/deno-lint-plugin-lit` | `@cunarist/eslint-plugin-lit` | -| `scripts/deno-lint-plugin.ts` (per app) | `scripts/project-lint.ts` (per app) | - -Until those packages are on npm, a repo that depends on them fails `npm ci` in -CI; that is expected and stated in the PR, never worked around by committing -tarballs or `file:` dependencies. diff --git a/.agents/memory/imports-aliases-barrels.md b/.agents/memory/imports-aliases-barrels.md index 3655159..787a253 100644 --- a/.agents/memory/imports-aliases-barrels.md +++ b/.agents/memory/imports-aliases-barrels.md @@ -1,5 +1,5 @@ --- -description: Shared code comes through # aliases in package.json imports, each directory's entry is index.ts, barrels keep imports few; never ../ out of a directory +description: Shared code comes through # aliases in package.json imports, each src/ subfolder's entry is index.ts, barrels keep imports few; never ../ out of a directory --- ## `#` aliases @@ -44,8 +44,9 @@ so they never reach package consumers. ## `index.ts` entries and barrels -- Every directory's entry file is `index.ts`, never `mod.ts` (decided - 2026-10-12; import-check's `enforce-mod-file` now requires `index.ts`). +- Every `src/` subfolder's entry file is `index.ts`, never `mod.ts` (decided + 2026-10-12; import-check's `enforce-mod-file` requires it only in folders a + `#` alias owns). Folders outside `src/`, such as `scripts/`, have none. - A directory used from outside exposes its API through its `index.ts` barrel, and callers import the barrel (`#ui`), not files inside it (`no-barrel-bypass`). diff --git a/.agents/memory/lint-config-shape.md b/.agents/memory/lint-config-shape.md index 5b1172c..84c6fb5 100644 --- a/.agents/memory/lint-config-shape.md +++ b/.agents/memory/lint-config-shape.md @@ -22,11 +22,10 @@ lint: { - **Default limits stay** (2026-10-16): pedantic's `max-lines` 300, `max-lines-per-function` 50, `max-classes-per-file` 1, `max-dependencies` 10, `max-params` 3, `complexity` 20. Don't raise them to - make code pass; refactor (see [[lint-overrides-policy]]). Apps follow this - strictly. The plugin template already turns off `max-lines`, - `max-lines-per-function`, `typescript/prefer-readonly-parameter-types`, and - `typescript/no-unsafe-enum-comparison` because AST visitors fight them; do - not add new opt-outs anywhere without asking the user. + make code pass; refactor (see [[lint-overrides-policy]]). `max-lines` stays + at 300 everywhere, `scripts/` included, with no override (2026-10-16): split + a long file by theme instead. Do not add new opt-outs anywhere without + asking the user. - **`vite.config.ts` names no rule.** Every rule id, built-in ones included, lives in `configs.project` of `scripts/project-lint.ts` ([[project-lint-plugin]]). `vite.config.ts` only spreads configs. diff --git a/.agents/memory/lit-analyzer-ts6.md b/.agents/memory/lit-analyzer-ts6.md index 4e972d3..ebbb795 100644 --- a/.agents/memory/lit-analyzer-ts6.md +++ b/.agents/memory/lit-analyzer-ts6.md @@ -29,9 +29,10 @@ registerHooks({ ``` - Node runs the `.ts` script directly (type stripping), so no build step. -- **Gotcha:** the obvious `await import("lit-analyzer/cli.js")` fails - `project/no-non-ts-imports` (a `.js` subpath). Import the package entry, or - spawn the package's bin with `node:child_process`, instead. +- Import the package entry, or spawn the package's bin with + `node:child_process`, rather than `await import("lit-analyzer/cli.js")`. + `project/no-asset-imports` allows `.js` subpaths, but the CLI file runs on + import and bypasses the package's public entry. - CI runs `npm run lit-check` as its own step. - It is tooling under `scripts/`: no tests; a narrow `overrides` entry for it (e.g. `no-console`) is allowed if truly needed. diff --git a/.agents/memory/package-json-shape.md b/.agents/memory/package-json-shape.md index 9c56212..714bbed 100644 --- a/.agents/memory/package-json-shape.md +++ b/.agents/memory/package-json-shape.md @@ -1,32 +1,13 @@ --- -description: package.json key order is metadata, scripts, exports, imports, devDependencies, dependencies; standard fields only; no peerDependencies or packageManager +description: package.json keys follow Oxfmt's standard order (vp check --fix); standard fields only; no peerDependencies or packageManager --- -## Key order (2026-10-14) +## Key order (2026-10-16) -Metadata first, then `scripts`, `exports`, `imports`, `devDependencies`, -`dependencies`. Oxfmt would re-sort the file, so `vite.config.ts` sets -`fmt: { sortPackageJson: false }`; keep it, and keep the order by hand. - -```jsonc -{ - "name": "@cunarist/eslint-plugin-x", - "version": "0.1.0", - "description": "...", - "keywords": ["eslint", "eslint-plugin", "eslintplugin", "oxlint"], - "license": "MIT", - "repository": { "type": "git", "url": "git+https://github.com/..." }, - "type": "module", - "files": ["dist"], - "engines": { "node": ">=22" }, - "eslint-doc-generator": {/* tool options that can only live here */}, - "scripts": { "docs": "eslint-doc-generator" }, - "exports": { ".": "./dist/index.js" }, - "imports": { "#helpers": "./src/helpers/index.ts" }, - "devDependencies": { "vite-plus": "^1.1.0" }, - "dependencies": {}, -} -``` +Oxfmt's standard `package.json` sorting is accepted: there is no +`fmt: { sortPackageJson: false }`, and `vp check --fix` sets the order. This +replaces the earlier hand-written order (metadata, `scripts`, `exports`, +`imports`, `devDependencies`, `dependencies`). The `imports` key order can carry meaning: import-check's `enforce-layer-order` reads it as the layer order. Never reorder it casually. diff --git a/.agents/memory/project-lint-plugin.md b/.agents/memory/project-lint-plugin.md index 1d24338..14df71c 100644 --- a/.agents/memory/project-lint-plugin.md +++ b/.agents/memory/project-lint-plugin.md @@ -11,11 +11,15 @@ Oxlint plugin with `meta.name` `"project"`, loaded through `jsPlugins` in plugin configs: Deno parity rules, extras, per-rule options, and opt-outs, built-in Oxlint ids included (`curly`, `id-match`, `import/no-cycle`, ...). - **Custom rules**, enabled as `project/`. Every repo has - `no-disable-comments` and `no-non-ts-imports`. Apps also port the rules of + `no-disable-comments` and `no-asset-imports`. Apps also port the rules of their old `scripts/deno-lint-plugin.ts` here under the same names and behavior (`no-self-sync`, `app-module-conventions`, `restricted-types`, ...). -Rules and plugin stay in this one file; don't add `scripts/rules/`. +`scripts/` stays flat; don't add `scripts/rules/`. A file that would pass +`max-lines` (300) splits into flat themed files sharing the prefix: +`scripts/project-lint.ts` keeps the plugin object and the rule list and +imports the others (`project-lint-modules.ts`, `project-lint-types.ts`, +`project-lint-lit.ts`, ...). ```ts import type { DummyRuleMap } from "vite-plus/lint"; diff --git a/.agents/memory/publishing-ci-only.md b/.agents/memory/publishing-ci-only.md index 35b07e8..0c2541d 100644 --- a/.agents/memory/publishing-ci-only.md +++ b/.agents/memory/publishing-ci-only.md @@ -23,7 +23,7 @@ Standing convention (2026-10-12), applied to every package: (`--generate-notes`, edited there). There is no `CHANGELOG.md`; never add one. - **The version lives in two places in plugin packages:** `package.json` and - `meta.version` in `src/index.ts`; `tests/package-meta.test.ts` fails if they + `meta.version` in `src/plugin/index.ts`; `tests/package-meta.test.ts` fails if they differ. - **Before 1.0**, a change that breaks users (renamed rule id, a rule that fires on more code, removed behavior) is a minor bump. diff --git a/.agents/memory/toolchain-node-vite-plus.md b/.agents/memory/toolchain-node-vite-plus.md index bce938e..86cff76 100644 --- a/.agents/memory/toolchain-node-vite-plus.md +++ b/.agents/memory/toolchain-node-vite-plus.md @@ -44,8 +44,8 @@ before any push. CI installs the toolchain with `voidzero-dev/setup-vp`. - `vp check` does **not** report `isolatedDeclarations` errors (TS9010); only `vp pack` does, so packages run `vp pack` in CI on every PR. -- Oxfmt sorts `package.json` keys by default, which destroys the required key - order. Set `fmt: { sortPackageJson: false }` ([[package-json-shape]]). +- Oxfmt sorts `package.json` keys by default; that order is accepted, so + there is no `fmt` option for it ([[package-json-shape]]). - Oxlint and Oxfmt skip what `.gitignore` lists; that is the only reason `dist/` and `node_modules/` are not linted. Keep build output gitignored. - Vite+ bundles `vite.config.ts` itself and resolves `#` imports in it. diff --git a/.agents/memory/ts-only-files-and-imports.md b/.agents/memory/ts-only-files-and-imports.md index e365a93..8ac48f8 100644 --- a/.agents/memory/ts-only-files-and-imports.md +++ b/.agents/memory/ts-only-files-and-imports.md @@ -1,5 +1,5 @@ --- -description: Every file is .ts (no js/mjs/cjs/jsx/tsx, configs included) and source imports only .ts; CSS comes from HTML, JSON/SVG become .ts modules +description: Every file is .ts (no js/mjs/cjs/jsx/tsx, configs included); imports name only .ts files or .js package subpaths; CSS comes from HTML, JSON/SVG become .ts modules --- The user's rule, from the Deno days and restated for Node (2026-10-12): "No @@ -12,12 +12,14 @@ plain `.ts`. Build output in a gitignored folder is the only JS. `noUncheckedIndexedAccess`). If a tool or framework seems to need a JS or TSX file, stop and flag it instead of adding one. -## Only `.ts` imports (2026-10-14) +## No asset imports (2026-10-14, widened 2026-10-16) -`project/no-non-ts-imports` (in `scripts/project-lint.ts`) fails: +`.ts` and `.js` imports are allowed: our own files stay `.ts`, and `.js` +covers package subpaths such as `lit/decorators.js`. +`project/no-asset-imports` (in `scripts/project-lint.ts`) fails: - a relative, absolute, `#`, or package-subpath specifier whose last segment - has a non-`.ts` extension: `.css`, `.json`, `.svg`, `.js`, `.mjs`, `.tsx`; + has any other extension: `.css`, `.json`, `.svg`, `.mjs`, `.tsx`; - any `?query` suffix (`?raw`, `?url`, `?inline`); - any import attributes (`with { type: "json" }`, `with { type: "text" }`). @@ -44,5 +46,6 @@ import { scenes } from "#data/scenes"; // yes: scenes.ts and fails on drift (the plugin repos do this for `meta.name`/`meta.version`). - **Reading a file is not importing it.** `readFileSync` + `JSON.parse` is fine in tooling and tests. -- **A tool's `.js` entry:** don't `import("pkg/cli.js")`; use the package - entry or spawn the package's bin ([[lit-analyzer-ts6]]). +- **A tool's CLI file:** prefer the package entry or spawning the package's + bin over importing `pkg/cli.js`, which runs the CLI as a side effect + ([[lit-analyzer-ts6]]). diff --git a/.agents/skills/migrate-deno-repo/SKILL.md b/.agents/skills/migrate-deno-repo/SKILL.md deleted file mode 100644 index 36e4373..0000000 --- a/.agents/skills/migrate-deno-repo/SKILL.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -name: migrate-deno-repo -description: Checklist for moving a Deno repo (or a leftover Deno part of one) to Node 22+ + Vite+ with npm, same behavior, full lint parity, one PR ---- - -Template: `cunarist/eslint-plugin-explicit-types` on `main`. Read its -`AGENTS.md`, `vite.config.ts`, `scripts/project-lint.ts`, `package.json`, and -CI before starting, and copy their shape. Never ask the user mid-way when -they're away: decide by the memories, record the choice in the PR. - -Branch `node-migration` (apps) or `initial-port` (new plugin repos); one PR -with everything. - -**Inventory first** - -- [ ] List every `deno.json` task, import-map entry, lint rule (tags, - includes, `@hugoalh`, custom plugins), test, `Deno.*` call, JSON/CSS/SVG - import, and every place the output is consumed (Rust, HTML, - Containerfile, CI). - -**Toolchain** - -- [ ] `package.json` in the required key order, `engines.node ">=22"`, no - `packageManager`, no `peerDependencies`; `npm install`; commit - `package-lock.json`. -- [ ] `tsconfig.json` from the template; `vite.config.ts` with `fmt: - { sortPackageJson: false }` and the category-based `lint` block. -- [ ] Delete `deno.json`, `deno.lock`, and Deno-only files. `mod.ts` → - `index.ts`; `deno.json` imports → `package.json` `imports` (`#x/*` - patterns for trailing-slash mappings; aliases may target only direct - subfolders of `src/`, anything else becomes a relative import); - `jsr:`/`npm:` → npm packages. - -**Code** - -- [ ] Only `.ts` files; no non-`.ts` imports: CSS via ``, JSON and SVG - as `.ts` modules, icons in memona's style. -- [ ] `Deno.*` → `node:*` / `process`. Generated JS written as `.ts`, built, - gitignored. -- [ ] Decorators stay standard with `accessor`; add `scripts/decorators.ts` - if the repo has any. Lit repos: `scripts/lit-check.ts` + `npm run - lit-check`. -- [ ] `scripts/` is flat: no subfolders, no `index.ts` (barrels live only in - `src/`); `vite.config.ts` imports `./scripts/.ts` directly. A - scripts subfolder that is really an app moves under `src/`. - -**Lint** - -- [ ] `scripts/project-lint.ts` copied; old local Deno lint rules ported into - it; parity mapping for every former rule; `id-match`; no disable - comments; no source `overrides`; refactor size-rule hits. - -**Tests** - -- [ ] `Deno.test` → Vitest (codemod, then finish TODOs); unit tests next to - code, integration in `tests/`; no case dropped. - -**Build, ship, CI** - -- [ ] `vp build` in app mode with the same output paths, or `vp pack` for - packages. Containerfile node stage on `node:24-alpine`. CI with - `setup-vp`: `vp check`, build, `vp test` (+ lit-check). Packages: - release-triggered `publish.yml`. -- [ ] `AGENTS.md` with the damem header, `.agents/` notes from the damem kit, - README updated (Node.js 22+, no Deno instructions). `damem doctor` - clean. - -**Finish** - -- [ ] `vp check`, `vp test`, build all pass locally; the app runs. -- [ ] Commit in plain imperative sentences; open the PR (summary, changes, - parity mapping, deviations/risks, "CI fails until @cunarist/eslint-plugin-* - are published" if relevant, verification, footer line). -- [ ] Run `review-cycle`. Never merge, publish, or archive.