[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M78G5D339N1KZPY1HKPW9DM9":3,"skill-same:01M78G5D339N1KZPY1HKPW9DM9":51},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":22,"frontMatter":23,"refName":25,"commitSha":26,"skillDirectory":27,"forksCount":14,"repositoryHtmlUrl":28,"repositoryHomepageUrl":6,"ownerHtmlUrl":29,"ownerBlogUrl":6,"ownerDescription":30,"updatedAt":31,"install":32,"resources":44},"01M78G5D339N1KZPY1HKPW9DM9","setup-ts-deep-modules",null,"Wire dependency-cruiser into a TypeScript repo so each package is a deep module — implementation hidden in subfolders, reachable only through its entry-point files. User-invoked.","nilox94\u002Fgh-agentic-workflow","nilox94","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F6260113?v=4","01M78G3FT2G2XB78G4CBP03BQ0","Danilo Gómez","01M78G3FTQYHF6HQAF6QT7ZGPA",0,"MIT","https:\u002F\u002Fgithub.com\u002Fnilox94\u002Fgh-agentic-workflow\u002Fblob\u002Fmain\u002Fskills\u002Fin-progress\u002Fsetup-ts-deep-modules\u002FSKILL.md",[],[],"2026-11-15 14:19:17",false,"---\nname: setup-ts-deep-modules\ndescription: Wire dependency-cruiser into a TypeScript repo so each package is a deep module — implementation hidden in subfolders, reachable only through its entry-point files. User-invoked.\ndisable-model-invocation: true\n---\n\n# Setup TS Deep Modules\n\nMake every package in this repo a **deep module**: a lot of behaviour behind a small interface. A package's public surface is its **entry points** — the files at the package root — and everything in its subfolders is hidden. This skill installs [dependency-cruiser](https:\u002F\u002Fgithub.com\u002Fsverweij\u002Fdependency-cruiser) and the rules that make the entry points the only way in, then proves the rules bite.\n\nFor the vocabulary (deep module, interface, seam, depth), run the `\u002Fcodebase-design` skill — use its language throughout.\n\n## The shape this enforces\n\n```\nsrc\u002Fpackages\u002F\n  \u003Cname>\u002F\n    index.ts        ← an entry point (public). Import this from outside.\n    client.ts       ← another entry point. Packages may expose SEVERAL.\n    lib\u002F            ← implementation: hidden from outside, free to import each other.\n    tests\u002F          ← co-located tests + fixtures (a subfolder, so private).\n```\n\nThe public surface is the package's **root files** — not one designated `index.ts`. By convention implementation lives in `lib\u002F` and tests in `tests\u002F`, giving every package the same two-folder shape. The rule itself is general, though: *anything* in *any* subfolder is private, so you never extend the config to add a folder.\n\nFour rules, all `error`:\n\n1. **Entry-point boundary** — code outside a package (app code or another package) may import only that package's entry points (its root files), never anything in its subfolders.\n2. **Intra-package freedom** — a package's own files import each other freely.\n3. **Tests through the entry points** — files under `\u003Cpkg>\u002Ftests\u002F` may import any package's entry points and their own `tests\u002F` fixtures, but never any package's subfolder internals (not even their own). Integration tests across packages are fine; deep imports are not.\n4. **No cycles** — no dependency cycles.\n\n**Entry points, not a barrel.** Because the public surface is *every* root file, a package can expose several small entry points (`index.ts`, `client.ts`, `server.ts`) instead of funnelling everything through one giant `index.ts`. Barrel files that re-export a whole subtree are discouraged — keep entry points small and hide implementation in subfolders.\n\nLayering (which packages may depend on which) is a *different* concern and is left as a commented stub in the config for this repo to fill in.\n\n## Steps\n\n### 1. Detect the environment\n\n- **Package manager** — `pnpm-lock.yaml` → pnpm, `yarn.lock` → yarn, `bun.lockb` → bun, else npm. Use it for every command below (`pnpm`\u002F`yarn`\u002F`npm run`\u002F`bunx`).\n- **Packages root** — if `src\u002F` exists use `src\u002Fpackages`, else `packages`. Confirm the choice with the user if the repo already has a different obvious convention.\n- **Existing config** — check for a `.dependency-cruiser.*` file. If one exists, do **not** overwrite it: merge the four rules and the options in, and tell the user what you added.\n\n**Done when:** package manager, packages root, and existing-config status are all known.\n\n### 2. Install dependency-cruiser\n\nInstall `dependency-cruiser` as a devDependency with the detected package manager.\n\n**Done when:** `dependency-cruiser` is in `devDependencies`.\n\n### 3. Write the config\n\nCopy [`dependency-cruiser.config.cjs`](.\u002Fdependency-cruiser.config.cjs) to the repo root as `.dependency-cruiser.cjs`. Set `PACKAGES_ROOT` to the root detected in step 1. The rules are path-depth based and extension-agnostic, so nothing else needs adapting.\n\n**Done when:** `.dependency-cruiser.cjs` exists with the correct `PACKAGES_ROOT`, and the four forbidden rules are present.\n\n### 4. Wire it into the checks\n\n- Add a `lint:boundaries` script: `depcruise \u003Cpackages-root>` (or `depcruise src`).\n- Fold it into the repo's umbrella check command — the one that already runs typecheck (e.g. a `check` \u002F `ci` \u002F `validate` script). Do **not** touch `tsconfig` or add path aliases.\n- If there is no umbrella script, add `lint:boundaries` and tell the user to include it in CI.\n\n**Done when:** `lint:boundaries` exists and runs as part of the same command as typecheck.\n\n### 5. Scaffold the example package\n\nCreate a committed `\u003Cpackages-root>\u002Fexample\u002F` as a copy-me template:\n\n- `index.ts` — an entry point. Export one function that delegates to an internal file (so the package is visibly *deep*, not a pass-through).\n- `lib\u002Fimpl.ts` — an internal file in a **subfolder**, imported by `index.ts`, not reachable from outside.\n- `tests\u002Fexample.test.ts` — imports **only** `..\u002Findex` (an entry point), and asserts against the public function.\n\nTell the user this is a starter template to copy or delete.\n\n**Done when:** the example package exists, exposes its behaviour through a root entry point, and hides `impl` in a subfolder.\n\n### 6. Prove the rules bite\n\nThis is the completion criterion for the whole skill — a config that doesn't fail on a violation is worthless.\n\n1. Run `lint:boundaries`. It must **pass** on the clean example.\n2. Temporarily add a deep import to `tests\u002Fexample.test.ts` (e.g. `import { thing } from \"..\u002Flib\u002Fimpl\"`). Run `lint:boundaries` again — it must **fail** with `tests-through-entrypoints`.\n3. Revert the deep import. Run once more — it must **pass**.\n\n**Done when:** you have observed a pass, then a fail on the deep import, then a pass again. If step 2 does not fail, the rules are not wired correctly — fix before finishing.\n\n### 7. Document the convention\n\nWrite a `README.md` **in the packages folder** (`\u003Cpackages-root>\u002FREADME.md`) — next to the packages it governs — covering: the `src\u002Fpackages\u002F\u003Cname>\u002F` layout (entry points at the root, `lib\u002F` for implementation, `tests\u002F` for tests), \"import only through a package's entry points (its root files)\", and how to run `lint:boundaries`. **Discourage barrel files** explicitly — expose several small entry points instead of re-exporting a whole subtree through one index. Keep it to the copy-me snippet plus the four rules in one paragraph each.\n\nThen add a **context pointer** to it from the repo's agent-instructions file — `CLAUDE.md` if present, else `AGENTS.md` (create `AGENTS.md` if neither exists). One line is enough, e.g. `Packages are deep modules — see [src\u002Fpackages\u002FREADME.md](.\u002Fsrc\u002Fpackages\u002FREADME.md) before adding or importing one.` This is what makes an agent discover the boundary rule instead of tripping over it.\n\n**Done when:** `\u003Cpackages-root>\u002FREADME.md` exists and discourages barrels, and the repo's `CLAUDE.md`\u002F`AGENTS.md` links to it.\n\n## Notes\n\n- The config's `$1` back-references (dependency-cruiser's group matching) are what let a package reach its own internals while outsiders can't — don't flatten them into separate per-package rules.\n- Public vs private is decided by **depth**: a package's root files are entry points; anything in a subfolder is private. The conventional subfolders are `lib\u002F` (implementation) and `tests\u002F`, but the rule doesn't hardcode them — any subfolder is private, so a new folder never needs a config change. Adding an entry point is just adding a root file — no barrel.\n- Packages are **flat**: one tier of immediate children under the root. A package's internals may nest as deep as you like; a package may not contain another package.\n- Use `.cjs` (not `.js`) so the config's `module.exports` works even in `\"type\": \"module\"` repos.\n","# Setup TS Deep Modules\n\nMake every package in this repo a **deep module**: a lot of behaviour behind a small interface. A package's public surface is its **entry points** — the files at the package root — and everything in its subfolders is hidden. This skill installs [dependency-cruiser](https:\u002F\u002Fgithub.com\u002Fsverweij\u002Fdependency-cruiser) and the rules that make the entry points the only way in, then proves the rules bite.\n\nFor the vocabulary (deep module, interface, seam, depth), run the `\u002Fcodebase-design` skill — use its language throughout.\n\n## The shape this enforces\n\n```\nsrc\u002Fpackages\u002F\n  \u003Cname>\u002F\n    index.ts        ← an entry point (public). Import this from outside.\n    client.ts       ← another entry point. Packages may expose SEVERAL.\n    lib\u002F            ← implementation: hidden from outside, free to import each other.\n    tests\u002F          ← co-located tests + fixtures (a subfolder, so private).\n```\n\nThe public surface is the package's **root files** — not one designated `index.ts`. By convention implementation lives in `lib\u002F` and tests in `tests\u002F`, giving every package the same two-folder shape. The rule itself is general, though: *anything* in *any* subfolder is private, so you never extend the config to add a folder.\n\nFour rules, all `error`:\n\n1. **Entry-point boundary** — code outside a package (app code or another package) may import only that package's entry points (its root files), never anything in its subfolders.\n2. **Intra-package freedom** — a package's own files import each other freely.\n3. **Tests through the entry points** — files under `\u003Cpkg>\u002Ftests\u002F` may import any package's entry points and their own `tests\u002F` fixtures, but never any package's subfolder internals (not even their own). Integration tests across packages are fine; deep imports are not.\n4. **No cycles** — no dependency cycles.\n\n**Entry points, not a barrel.** Because the public surface is *every* root file, a package can expose several small entry points (`index.ts`, `client.ts`, `server.ts`) instead of funnelling everything through one giant `index.ts`. Barrel files that re-export a whole subtree are discouraged — keep entry points small and hide implementation in subfolders.\n\nLayering (which packages may depend on which) is a *different* concern and is left as a commented stub in the config for this repo to fill in.\n\n## Steps\n\n### 1. Detect the environment\n\n- **Package manager** — `pnpm-lock.yaml` → pnpm, `yarn.lock` → yarn, `bun.lockb` → bun, else npm. Use it for every command below (`pnpm`\u002F`yarn`\u002F`npm run`\u002F`bunx`).\n- **Packages root** — if `src\u002F` exists use `src\u002Fpackages`, else `packages`. Confirm the choice with the user if the repo already has a different obvious convention.\n- **Existing config** — check for a `.dependency-cruiser.*` file. If one exists, do **not** overwrite it: merge the four rules and the options in, and tell the user what you added.\n\n**Done when:** package manager, packages root, and existing-config status are all known.\n\n### 2. Install dependency-cruiser\n\nInstall `dependency-cruiser` as a devDependency with the detected package manager.\n\n**Done when:** `dependency-cruiser` is in `devDependencies`.\n\n### 3. Write the config\n\nCopy [`dependency-cruiser.config.cjs`](.\u002Fdependency-cruiser.config.cjs) to the repo root as `.dependency-cruiser.cjs`. Set `PACKAGES_ROOT` to the root detected in step 1. The rules are path-depth based and extension-agnostic, so nothing else needs adapting.\n\n**Done when:** `.dependency-cruiser.cjs` exists with the correct `PACKAGES_ROOT`, and the four forbidden rules are present.\n\n### 4. Wire it into the checks\n\n- Add a `lint:boundaries` script: `depcruise \u003Cpackages-root>` (or `depcruise src`).\n- Fold it into the repo's umbrella check command — the one that already runs typecheck (e.g. a `check` \u002F `ci` \u002F `validate` script). Do **not** touch `tsconfig` or add path aliases.\n- If there is no umbrella script, add `lint:boundaries` and tell the user to include it in CI.\n\n**Done when:** `lint:boundaries` exists and runs as part of the same command as typecheck.\n\n### 5. Scaffold the example package\n\nCreate a committed `\u003Cpackages-root>\u002Fexample\u002F` as a copy-me template:\n\n- `index.ts` — an entry point. Export one function that delegates to an internal file (so the package is visibly *deep*, not a pass-through).\n- `lib\u002Fimpl.ts` — an internal file in a **subfolder**, imported by `index.ts`, not reachable from outside.\n- `tests\u002Fexample.test.ts` — imports **only** `..\u002Findex` (an entry point), and asserts against the public function.\n\nTell the user this is a starter template to copy or delete.\n\n**Done when:** the example package exists, exposes its behaviour through a root entry point, and hides `impl` in a subfolder.\n\n### 6. Prove the rules bite\n\nThis is the completion criterion for the whole skill — a config that doesn't fail on a violation is worthless.\n\n1. Run `lint:boundaries`. It must **pass** on the clean example.\n2. Temporarily add a deep import to `tests\u002Fexample.test.ts` (e.g. `import { thing } from \"..\u002Flib\u002Fimpl\"`). Run `lint:boundaries` again — it must **fail** with `tests-through-entrypoints`.\n3. Revert the deep import. Run once more — it must **pass**.\n\n**Done when:** you have observed a pass, then a fail on the deep import, then a pass again. If step 2 does not fail, the rules are not wired correctly — fix before finishing.\n\n### 7. Document the convention\n\nWrite a `README.md` **in the packages folder** (`\u003Cpackages-root>\u002FREADME.md`) — next to the packages it governs — covering: the `src\u002Fpackages\u002F\u003Cname>\u002F` layout (entry points at the root, `lib\u002F` for implementation, `tests\u002F` for tests), \"import only through a package's entry points (its root files)\", and how to run `lint:boundaries`. **Discourage barrel files** explicitly — expose several small entry points instead of re-exporting a whole subtree through one index. Keep it to the copy-me snippet plus the four rules in one paragraph each.\n\nThen add a **context pointer** to it from the repo's agent-instructions file — `CLAUDE.md` if present, else `AGENTS.md` (create `AGENTS.md` if neither exists). One line is enough, e.g. `Packages are deep modules — see [src\u002Fpackages\u002FREADME.md](.\u002Fsrc\u002Fpackages\u002FREADME.md) before adding or importing one.` This is what makes an agent discover the boundary rule instead of tripping over it.\n\n**Done when:** `\u003Cpackages-root>\u002FREADME.md` exists and discourages barrels, and the repo's `CLAUDE.md`\u002F`AGENTS.md` links to it.\n\n## Notes\n\n- The config's `$1` back-references (dependency-cruiser's group matching) are what let a package reach its own internals while outsiders can't — don't flatten them into separate per-package rules.\n- Public vs private is decided by **depth**: a package's root files are entry points; anything in a subfolder is private. The conventional subfolders are `lib\u002F` (implementation) and `tests\u002F`, but the rule doesn't hardcode them — any subfolder is private, so a new folder never needs a config change. Adding an entry point is just adding a root file — no barrel.\n- Packages are **flat**: one tier of immediate children under the root. A package's internals may nest as deep as you like; a package may not contain another package.\n- Use `.cjs` (not `.js`) so the config's `module.exports` works even in `\"type\": \"module\"` repos.\n",{"name":5,"description":7,"disable-model-invocation":24},true,"main","6011023b5dd9033c539a228f84241bfb4212ccdd","skills\u002Fin-progress\u002Fsetup-ts-deep-modules","https:\u002F\u002Fgithub.com\u002Fnilox94\u002Fgh-agentic-workflow","https:\u002F\u002Fgithub.com\u002Fnilox94","Engineer who reads EXPLAIN plans for fun. Observability nerd.","2026-07-15 12:41:12",{"source":8,"skillName":5,"commands":33,"prompt":43,"zipAvailable":24},[34,37,40],{"tool":35,"command":36},"npx","npx skills add nilox94\u002Fgh-agentic-workflow --skill setup-ts-deep-modules",{"tool":38,"command":39},"bunx","bunx skills add nilox94\u002Fgh-agentic-workflow --skill setup-ts-deep-modules",{"tool":41,"command":42},"pnpm","pnpm dlx skills add nilox94\u002Fgh-agentic-workflow --skill setup-ts-deep-modules","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fnilox94\u002Fgh-agentic-workflow\u002Fblob\u002Fmain\u002Fskills\u002Fin-progress\u002Fsetup-ts-deep-modules\u002FSKILL.md",[45],{"path":46,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":49,"sourceHtmlUrl":50},"dependency-cruiser.config.cjs","SCRIPT","脚本",3732,"https:\u002F\u002Fgithub.com\u002Fnilox94\u002Fgh-agentic-workflow\u002Fblob\u002Fmain\u002Fskills\u002Fin-progress\u002Fsetup-ts-deep-modules\u002Fdependency-cruiser.config.cjs",[52,59,66,73,80,87],{"skillNo":53,"name":54,"nameZh":6,"description":55,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":56,"categories":57,"keywords":58,"publishedAt":19},"01M78G6G5CKP4G3KKN8TEFGRHR","writing-great-skills","Reference for writing and editing skills well — the vocabulary and principles that make a skill predictable.","https:\u002F\u002Fgithub.com\u002Fnilox94\u002Fgh-agentic-workflow\u002Fblob\u002Fmain\u002Fskills\u002Fproductivity\u002Fwriting-great-skills\u002FSKILL.md",[],[],{"skillNo":60,"name":61,"nameZh":6,"description":62,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":63,"categories":64,"keywords":65,"publishedAt":19},"01M78G6D8H27EVVAMAH1T8MAFB","teach","Teach the user a new skill or concept, within this workspace.","https:\u002F\u002Fgithub.com\u002Fnilox94\u002Fgh-agentic-workflow\u002Fblob\u002Fmain\u002Fskills\u002Fproductivity\u002Fteach\u002FSKILL.md",[],[],{"skillNo":67,"name":68,"nameZh":6,"description":69,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":70,"categories":71,"keywords":72,"publishedAt":19},"01M78G6BN2CEFMMY7SCXHY4G78","handoff","Compact the current conversation into a handoff document for another agent to pick up.","https:\u002F\u002Fgithub.com\u002Fnilox94\u002Fgh-agentic-workflow\u002Fblob\u002Fmain\u002Fskills\u002Fproductivity\u002Fhandoff\u002FSKILL.md",[],[],{"skillNo":74,"name":75,"nameZh":6,"description":76,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":77,"categories":78,"keywords":79,"publishedAt":19},"01M78G69X6151TWAS2K6KY5YK6","grilling","Grill the user relentlessly about a plan or design. Use when the user wants to stress-test a plan before building, or uses any 'grill' trigger phrases.","https:\u002F\u002Fgithub.com\u002Fnilox94\u002Fgh-agentic-workflow\u002Fblob\u002Fmain\u002Fskills\u002Fproductivity\u002Fgrilling\u002FSKILL.md",[],[],{"skillNo":81,"name":82,"nameZh":6,"description":83,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":84,"categories":85,"keywords":86,"publishedAt":19},"01M78G68BMDBT2XSZZS3MEC6KK","grill-me","A relentless interview to sharpen a plan or design.","https:\u002F\u002Fgithub.com\u002Fnilox94\u002Fgh-agentic-workflow\u002Fblob\u002Fmain\u002Fskills\u002Fproductivity\u002Fgrill-me\u002FSKILL.md",[],[],{"skillNo":88,"name":89,"nameZh":6,"description":90,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":91,"categories":92,"keywords":93,"publishedAt":19},"01M78G66GMGBNWXGEQF26PW7Q6","obsidian-vault","Search, create, and manage notes in the Obsidian vault with wikilinks and index notes. Use when user wants to find, create, or organize notes in Obsidian.","https:\u002F\u002Fgithub.com\u002Fnilox94\u002Fgh-agentic-workflow\u002Fblob\u002Fmain\u002Fskills\u002Fpersonal\u002Fobsidian-vault\u002FSKILL.md",[],[]]