adamantite 0.38.0 → 0.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # adamantite
2
2
 
3
+ ## 0.39.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#398](https://github.com/adelrodriguez/adamantite/pull/398) [`ee97933`](https://github.com/adelrodriguez/adamantite/commit/ee97933d7d9f642cb68f97993dd5c2a91a7362a9) Thanks [@adelrodriguez](https://github.com/adelrodriguez)! - Update the vendored anti-slop plugin to upstream v0.1.2 (`e8c4880`)
8
+
9
+ The bundled build moves from `446268e` to `e8c4880`, picking up the v0.1.1 and v0.1.2 releases. The rule set is unchanged, so no preset configuration changes are needed. **Some rules are stricter than before, so source that passed `adamantite check` on 0.38.0 can start reporting `anti-slop` errors after this update.** The tightenings:
10
+
11
+ - `no-unknown-parameters` and `no-unknown-type-aliases` now also report union types that contain `unknown`, such as `input: string | unknown` or `type T = string | unknown`.
12
+ - `no-object-parameters`, `no-unknown-returns`, `no-unknown-type-aliases`, and `no-known-value-widening` now resolve block-scoped, forward-referenced, and transparent generic type aliases, so an alias declared inside a function body is no longer overlooked.
13
+ - `no-known-value-widening` also flags known values passed into local `unknown` type predicates.
14
+
15
+ The relaxations, where previously reported code is now accepted:
16
+
17
+ - `no-runtime-typeof` now allows every `typeof x === "undefined"` comparison, not only existence probes such as `typeof document === "undefined"`. Comparisons against any other type string are still reported.
18
+ - `no-unknown-parameters` allows `unknown` on the exact subject of a type predicate.
19
+ - `no-known-value-widening` no longer flags finite-key `Record` targets such as `Record<"a" | "b", T>`.
20
+ - `no-shape-in-symbol-names` allows static member reads such as Zod's `schema.shape`.
21
+ - `no-unsafe-dictionary-type` allows generic constraints such as `T extends Record<string, unknown>`.
22
+ - `require-safety-comment-for-type-assertion` recognizes comments above exported declarations and accepts a `markers` option for alternative prefixes.
23
+
24
+ Upstream also added a separate opt-in `anti-slop-effect` plugin with one rule, `no-service-constructor-imports`. It is not vendored here because it lives behind its own entry point and encodes Effect service-layer architecture policy rather than generic lint rules.
25
+
26
+ ### Patch Changes
27
+
28
+ - [#409](https://github.com/adelrodriguez/adamantite/pull/409) [`d476141`](https://github.com/adelrodriguez/adamantite/commit/d4761411e4d35a21eee345a0126a49141922c485) Thanks [@adelrodriguez](https://github.com/adelrodriguez)! - Update Effect packages to 4.0.0-rc.115 to align runtime dependencies in fresh package installs.
29
+
3
30
  ## 0.38.0
4
31
 
5
32
  ### Minor Changes
package/dist/index.js CHANGED
@@ -5,10 +5,10 @@ import*as e from"@effect/platform-node/NodeRuntime";import*as t from"@effect/pla
5
5
  `,`\n${n}`):i}const Fe=(e,t)=>n.try({catch:e=>new be({cause:e}),try:()=>ne(e,t)}),Ie=/^workspace:/,Le=/^[\^~]/;function Re(e){return e.trim().replace(Ie,``).replace(Le,``)}const z=(e=S.cwd())=>n.gen(function*(){let t=(yield*x.Path).join(e,`package.json`),n=yield*N(t);return yield*L(n,t)}),ze=(e,t)=>n.gen(function*(){let n=yield*x.Path;yield*I(n.join(e,`package.json`),t)});function Be(e){return e===`bun`||e===`deno`||e===`npm`||e===`pnpm`||e===`yarn`}const B={analyze:`adamantite analyze`,check:`adamantite check`,"check:monorepo":`adamantite monorepo`,fix:`adamantite fix`,"fix:monorepo":`adamantite monorepo --fix`,format:`adamantite format`};function Ve(e){let t=e.scripts??{};return h(te.keys(B),c.filter(e=>t[e]===B[e]))}function He(e,t){let n=e.scripts??{};return c.filterMap(t,e=>{let t=n[e];return t!==void 0&&t!==``&&t!==B[e]?C.succeed({command:t,script:e}):C.failVoid})}function Ue(e){return e.endsWith(`.jsonc`)?`jsonc`:e.endsWith(`.json`)?`json`:`ts`}function We(e,t){return c.findFirst(e.legacyConfigs,e=>Ue(e)===t)}function Ge(e){let t=We(e,`json`),n=We(e,`jsonc`);return h(g.zipWith(t,n,e=>`${e}(c)`),g.orElse(()=>n),g.orElse(()=>t),g.getOrElse(()=>``))}function Ke(e,t,n,r){return n===null||r.length===0?[]:n.format===`ts`?[`Found both \`${t.config}\` and \`${Ge(t)}\`. Adamantite will use \`${t.config}\`.`]:h(g.zipWith(We(t,`json`),We(t,`jsonc`),(t,n)=>`Found both \`${t}\` and \`${n}\`. Multiple legacy ${e} configs exist; Adamantite will treat \`${n}\` as the source of truth in its findings.`),g.toArray)}const qe=n.fn(`detectToolingConfig`)(function*(e,t,r){let i=yield*b.FileSystem,a=yield*x.Path,o=[r.config,...r.legacyConfigs].map(t=>({file:t,format:Ue(t),path:a.join(e,t)})),s=yield*n.forEach(o,e=>i.exists(e.path),{concurrency:`unbounded`}),l=o.filter((e,t)=>s[t]),u=h(c.findFirst(l,e=>e.format===`ts`),g.orElse(()=>c.findFirst(l,e=>e.format===`jsonc`)),g.orElse(()=>c.findFirst(l,e=>e.format===`json`)),g.getOrNull),d=l.filter(e=>e!==u&&e.format!==`ts`);return{active:u,legacy:d,warnings:Ke(t,r,u,d)}});function Je(e,t,n){let r=e.devDependencies?.[t.name]??e.dependencies?.[t.name];return r?Re(r)===t.version?[]:[{currentVersion:r,description:`Update \`${t.name}\` from \`${r}\` to \`${t.version}\`.`,package:t.name,targetVersion:t.version,type:`update_package`}]:[{description:`Install \`${t.name}@${t.version}\` for ${n}.`,package:t.name,targetVersion:t.version,type:`install_package`}]}function Ye(e,t){return e.map(e=>({currentState:e.type===`install_package`?`The required package \`${e.package}\` is not installed.`:`The installed \`${e.package}\` version is \`${e.currentVersion}\`, but Adamantite requires \`${e.targetVersion}\`.`,goal:[`Run \`adamantite update\` so \`${e.package}@${e.targetVersion}\` is installed.`],id:`${e.type===`install_package`?`missing`:`outdated`}-${e.package}`,integration:t,title:e.type===`install_package`?`Missing ${e.package}`:`Outdated ${e.package}`}))}function Xe(e,t){if(e.active===null)return[{currentState:`The managed \`${t.configFile}\` file is missing.`,goal:[`Create \`${t.configFile}\` with the reference content.`,`Do not create a legacy JSON or JSONC ${t.toolName} config.`],id:`missing-${t.toolName}-config`,integration:t.toolName,reference:{content:t.configContent,language:`ts`},title:`Missing ${t.toolName} configuration`}];if(e.active.format!==`ts`)return[{currentState:`Legacy \`${e.active.file}\` is the active ${t.toolName} configuration.`,goal:[`Port the project settings into \`${t.configFile}\` using the reference content as the base.`,`Delete every legacy ${t.toolName} JSON or JSONC config after its settings are preserved.`],id:`legacy-${t.toolName}-config`,integration:t.toolName,notes:[`Preserve project-specific settings. Do not replace them with the reference defaults.`],reference:{content:t.configContent,language:`ts`},title:`Legacy ${t.toolName} configuration`}];let n=[];return e.legacy.length>0&&n.push({currentState:`Legacy ${t.toolName} config files remain next to \`${t.configFile}\`: ${e.legacy.map(({file:e})=>`\`${e}\``).join(`, `)}.`,goal:[`Delete the legacy files after you confirm that \`${t.configFile}\` preserves their project-specific settings.`],id:`shadowed-legacy-${t.toolName}-config`,integration:t.toolName,title:`Legacy ${t.toolName} files remain`}),t.inspection?.kind===`invalid`&&n.push({currentState:`\`${t.configFile}\` does not meet Adamantite's required shape. ${t.inspection.reason}`,goal:[t.invalidGoal??`Update \`${t.configFile}\` so it includes the required Adamantite preset while preserving project-specific settings.`],id:`invalid-${t.toolName}-config`,integration:t.toolName,notes:[`Treat the reference as a known-good example, not an exact replacement.`],reference:{content:t.configContent,language:`ts`},title:`Invalid ${t.toolName} configuration`}),n}function Ze(e,t){let n=Ve(e);return t.some(e=>n.includes(e))}function Qe(e){return M({assess:(t,r)=>n.sync(()=>{if(!Ze(r,e.scripts))return{applicable:!1,warnings:[]};let t=Je(r,e,e.purpose);return{applicable:!0,findings:Ye(t,e.name),packageActions:t,warnings:[]}}),kind:`tooling`,name:e.name,version:e.version})}function $e(e){let t=[{path:e.configFiles.config,type:`config`},...e.configFiles.legacyConfigs.map(e=>({path:e,type:`legacy_config`}))],r=t=>qe(t,e.name,e.configFiles);return M({assess:(t,i)=>n.gen(function*(){if(!Ze(i,e.scripts))return{applicable:!1,warnings:[]};let n=yield*r(t),a=Je(i,e,e.purpose),o=e.configContent(),s=n.active?.format===`ts`?e.inspectConfig(yield*N(n.active.path)):void 0;return{applicable:!0,findings:[...Ye(a,e.name),...Xe(n,{configContent:o,configFile:e.configFiles.config,inspection:s,toolName:e.name})],packageActions:a,warnings:n.warnings}}),config:e.configFiles.config,create:t=>n.gen(function*(){let n=yield*x.Path;yield*F(n.join(t,e.configFiles.config),e.configContent())}),detect:r,files:t,kind:`tooling`,name:e.name,version:e.version})}function et(e,t){for(let n of e.body)if(n.type===`ImportDeclaration`&&n.source.value===t){for(let e of n.specifiers)if(e.type===`ImportDefaultSpecifier`)return e.local.name}return null}function tt(e,t){for(let n of e.body)if(n.type===`VariableDeclaration`){for(let e of n.declarations)if(e.id.type===`Identifier`&&e.id.name===t)return e.init}return null}function nt(e,t,n){let r=!1;return new re({Identifier:e=>{e.start>=n.start&&e.end<=n.end&&e.name===t&&(r=!0)}}).visit(e),r}function rt(e,t){let n=e.body.filter(e=>e.type===`ExportDefaultDeclaration`);if(n.length!==1)return!1;let r=n[0]?.declaration;if(!r)return!1;if(r.type!==`Identifier`)return nt(e,t,r);if(r.name===t)return!0;let i=tt(e,r.name);return i!==null&&nt(e,t,i)}function it(e,t){let n=ie(`config.ts`,e,{astType:`ts`,lang:`ts`,sourceType:`module`});if(n.errors.length>0)return{kind:`invalid`,reason:`The file is not valid TypeScript.`};let r=et(n.program,t.moduleName);return r?rt(n.program,r)?{kind:`configured`}:{kind:`invalid`,reason:`The imported ${t.presetName} preset is not used by the exported configuration.`}:{kind:`invalid`,reason:`The file must import the ${t.presetName} preset from \`${t.moduleName}\`.`}}function at(e){return it(e,{moduleName:`adamantite/analyze`,presetName:`Adamantite analyze`})}function ot(e={}){let t=Object.entries(e).map(([e,t])=>e===`rules`&&R(t)?[` rules: {`,` ...analyze.rules,`,...Object.entries(t).map(([e,t])=>` ${Ne(e)}: ${Pe(t,{continuationIndent:` `,indentation:` `})},`),` },`].join(`
6
6
  `):` ${Ne(e)}: ${Pe(t)},`);return t.length===0?[`import type { KnipConfig } from "knip"`,`import analyze from "adamantite/analyze"`,``,`const config: KnipConfig = analyze`,``,`export default config`,``].join(`
7
7
  `):[`import type { KnipConfig } from "knip"`,`import analyze from "adamantite/analyze"`,``,`const config: KnipConfig = {`,` ...analyze,`,...t,`}`,``,`export default config`,``].join(`
8
- `)}var V=$e({configContent:()=>ot(),configFiles:{config:`knip.config.ts`,legacyConfigs:[`knip.json`,`knip.jsonc`]},inspectConfig:at,name:`knip`,purpose:"the managed `analyze` script",scripts:[`analyze`],version:`6.32.2`});const st=u.boolean(`fix`).pipe(u.withDefault(!1),u.withDescription(`Automatically fix issues`)),ct=u.boolean(`strict`).pipe(u.withDefault(!1),u.withDescription(`Enable strict mode`));var lt=l.make(`analyze`,{fix:st,strict:ct}).pipe(l.withDescription(`Find unused dependencies, exports, and files using knip`),l.withExamples([{command:`adamantite analyze -- --directory packages/app`,description:`Run knip from a specific directory`}]),l.withHandler(({fix:e,strict:t})=>n.gen(function*(){let n=yield*j,r=yield*A,i=[];e&&i.push(`--fix`,`--allow-remove-files`),t&&i.push(`--production`,`--strict`),i.push(...n);let a=yield*r.run({args:i,command:V.name});a!==s.ExitCode(0)&&(yield*new O({command:V.name,exitCode:a}))})));const ut=`**/node_modules,**/.yarn,**/.git,**/dist,**/build,**/out,**/.next,**/.open-next,**/.nuxt,**/.output,**/.svelte-kit,**/.vitepress/cache,**/.turbo,**/.vercel,**/.netlify,**/.wrangler,**/.docusaurus,**/.cache,**/.parcel-cache,**/.vite,**/.astro,**/_astro,**/storybook-static,**/_generated,**/__generated__,**/*.gen.*,**/*.generated.*,**/generated,**/codegen,**/graphql-types.*,**/*.d.ts.map,**/coverage,**/.nyc_output,**/.expo,**/.expo-shared,**/next-env.d.ts,**/worker-configuration.d.ts`.split(`,`),dt=[`respectEslintDisableDirectives`,`typeAware`,`typeCheck`],ft="`oxlint.config.ts` must export an object literal directly, with or without `defineConfig(...)`, for Adamantite to patch `options` safely.",pt="`oxlint.config.ts` has an `options` property, but it is not an object literal that Adamantite can patch safely.",mt="`oxlint.config.ts` has an `options` object Adamantite cannot patch safely. Make sure each required option is a plain `key: true | false` property—avoid spreads (`...rest`), computed keys (`[name]: ...`), duplicate keys, methods/getters/setters, and non-boolean-literal values.";function ht(e=[]){return e.includes(`core`)?e:[`core`,...e]}function gt(e){return e.replaceAll(/-([a-z])/g,(e,t)=>t.toUpperCase())}const _t=ae.mapInput(ae.String,e=>e[0]);function vt(e){let t=(c.isArray(e)?e:[]).filter(e=>_.isString(e)).filter(e=>!ut.includes(e));return t.length===0?`core.ignorePatterns`:`[...core.ignorePatterns, ${t.map(e=>JSON.stringify(e)).join(`, `)}]`}function yt(e,t,n=[]){let{ignorePatterns:r,options:i,...a}=e,o=[`import { defineConfig } from "oxlint"`,...t.map(e=>`import ${gt(e)} from "${e===`core`?`adamantite/lint`:`adamantite/lint/${e}`}"`)],s=[...t.map(e=>gt(e)),...n.map(e=>JSON.stringify(e))],l=_.isObject(i)?{...i}:{};l.respectEslintDisableDirectives=!0,l.typeAware=!0,l.typeCheck=!0;let u=JSON.stringify(Object.fromEntries(c.sort(Object.entries(l),_t)),null,2),d=Object.entries(a).map(([e,t])=>[e,JSON.stringify(t,null,2)]),f=[[`extends`,`[${s.join(`, `)}]`],[`ignorePatterns`,vt(r)],[`options`,u],...d],p=c.sort(f,_t).map(([e,t])=>` ${e}: ${t},`).join(`
8
+ `)}var V=$e({configContent:()=>ot(),configFiles:{config:`knip.config.ts`,legacyConfigs:[`knip.json`,`knip.jsonc`]},inspectConfig:at,name:`knip`,purpose:"the managed `analyze` script",scripts:[`analyze`],version:`6.32.2`});const st=u.Boolean(`fix`).pipe(u.withDefault(!1),u.withDescription(`Automatically fix issues`)),ct=u.Boolean(`strict`).pipe(u.withDefault(!1),u.withDescription(`Enable strict mode`));var lt=l.make(`analyze`,{fix:st,strict:ct}).pipe(l.withDescription(`Find unused dependencies, exports, and files using knip`),l.withExamples([{command:`adamantite analyze -- --directory packages/app`,description:`Run knip from a specific directory`}]),l.withHandler(({fix:e,strict:t})=>n.gen(function*(){let n=yield*j,r=yield*A,i=[];e&&i.push(`--fix`,`--allow-remove-files`),t&&i.push(`--production`,`--strict`),i.push(...n);let a=yield*r.run({args:i,command:V.name});a!==s.ExitCode(0)&&(yield*new O({command:V.name,exitCode:a}))})));const ut=`**/node_modules,**/.yarn,**/.git,**/dist,**/build,**/out,**/.next,**/.open-next,**/.nuxt,**/.output,**/.svelte-kit,**/.vitepress/cache,**/.turbo,**/.vercel,**/.netlify,**/.wrangler,**/.docusaurus,**/.cache,**/.parcel-cache,**/.vite,**/.astro,**/_astro,**/storybook-static,**/_generated,**/__generated__,**/*.gen.*,**/*.generated.*,**/generated,**/codegen,**/graphql-types.*,**/*.d.ts.map,**/coverage,**/.nyc_output,**/.expo,**/.expo-shared,**/next-env.d.ts,**/worker-configuration.d.ts`.split(`,`),dt=[`respectEslintDisableDirectives`,`typeAware`,`typeCheck`],ft="`oxlint.config.ts` must export an object literal directly, with or without `defineConfig(...)`, for Adamantite to patch `options` safely.",pt="`oxlint.config.ts` has an `options` property, but it is not an object literal that Adamantite can patch safely.",mt="`oxlint.config.ts` has an `options` object Adamantite cannot patch safely. Make sure each required option is a plain `key: true | false` property—avoid spreads (`...rest`), computed keys (`[name]: ...`), duplicate keys, methods/getters/setters, and non-boolean-literal values.";function ht(e=[]){return e.includes(`core`)?e:[`core`,...e]}function gt(e){return e.replaceAll(/-([a-z])/g,(e,t)=>t.toUpperCase())}const _t=ae.mapInput(ae.String,e=>e[0]);function vt(e){let t=(c.isArray(e)?e:[]).filter(e=>_.isString(e)).filter(e=>!ut.includes(e));return t.length===0?`core.ignorePatterns`:`[...core.ignorePatterns, ${t.map(e=>JSON.stringify(e)).join(`, `)}]`}function yt(e,t,n=[]){let{ignorePatterns:r,options:i,...a}=e,o=[`import { defineConfig } from "oxlint"`,...t.map(e=>`import ${gt(e)} from "${e===`core`?`adamantite/lint`:`adamantite/lint/${e}`}"`)],s=[...t.map(e=>gt(e)),...n.map(e=>JSON.stringify(e))],l=_.isObject(i)?{...i}:{};l.respectEslintDisableDirectives=!0,l.typeAware=!0,l.typeCheck=!0;let u=JSON.stringify(Object.fromEntries(c.sort(Object.entries(l),_t)),null,2),d=Object.entries(a).map(([e,t])=>[e,JSON.stringify(t,null,2)]),f=[[`extends`,`[${s.join(`, `)}]`],[`ignorePatterns`,vt(r)],[`options`,u],...d],p=c.sort(f,_t).map(([e,t])=>` ${e}: ${t},`).join(`
9
9
  `);return[...o,``,`export default defineConfig({`,p,`})`,``].join(`
10
10
  `)}const bt=g.liftThrowable(e=>ie(`oxlint.config.ts`,e,{astType:`ts`,lang:`ts`,sourceType:`module`}));function xt(e){return bt(e).pipe(g.flatMap(e=>e.errors.length===0?g.fromNullishOr(e.program):g.none()))}function St(e){let{code:t}=oe(e,se({quotes:`double`}));return t.endsWith(`
11
- `)?t:`${t}\n`}function Ct(e){return e.type===`Identifier`?h(e.name,g.some):e.type===`Literal`&&_.isString(e.value)?h(e.value,g.some):g.none()}function wt(e){return e.type===`ObjectExpression`?h(e,g.some):e.type!==`CallExpression`||e.callee.type!==`Identifier`||e.callee.name!==`defineConfig`?g.none():h(e.arguments.length===1?c.head(e.arguments):g.none(),g.filter(e=>e.type===`ObjectExpression`))}function Tt(e){return h(e.body,c.filter(e=>e.type===`ExportDefaultDeclaration`),e=>e.length===1?c.head(e):g.none(),g.flatMap(e=>wt(e.declaration)))}function Et(e,t){let n=null;for(let r of e.properties){if(r.type===`SpreadElement`||r.computed)return{status:`manual`};let e=g.contains(Ct(r.key),t);if(r.method||r.kind!==`init`){if(e)return{status:`manual`};continue}if(e){if(n)return{status:`manual`};n=r}}return n?{property:n,status:`found`}:{status:`missing`}}function Dt(e){return{computed:!1,end:0,key:{end:0,name:e,start:0,type:`Identifier`},kind:`init`,method:!1,shorthand:!1,start:0,type:`Property`,value:{end:0,raw:`true`,start:0,type:`Literal`,value:!0}}}function Ot(){return{computed:!1,end:0,key:{end:0,name:`options`,start:0,type:`Identifier`},kind:`init`,method:!1,shorthand:!1,start:0,type:`Property`,value:{end:0,properties:dt.map(e=>Dt(e)),start:0,type:`ObjectExpression`}}}function kt(e,t){let n=[],r=!1;for(let e of dt){let i=Et(t,e);if(i.status===`manual`)return{kind:`manual`,reason:mt};if(i.status===`missing`){n.push(e);continue}let a=i.property.value;if(a.type!==`Literal`||!_.isBoolean(a.value))return{kind:`manual`,reason:mt};a.value||(a.raw=`true`,a.value=!0,r=!0)}return n.length>0&&(t.properties.unshift(...n.map(e=>Dt(e))),r=!0),r?{kind:`patchable`,updatedContent:St(e)}:{kind:`configured`}}function At(e){let t=xt(e);if(g.isNone(t))return{kind:`manual`,reason:ft};let n=Tt(t.value);if(g.isNone(n))return{kind:`manual`,reason:ft};let r=Et(n.value,`options`);return r.status===`manual`?{kind:`manual`,reason:pt}:r.status===`missing`?(n.value.properties.unshift(Ot()),{kind:`patchable`,updatedContent:St(t.value)}):r.property.value.type===`ObjectExpression`?kt(t.value,r.property.value):{kind:`manual`,reason:pt}}const H=`oxlint.config.ts`,jt=`.oxlintrc.json`,Mt=[{path:H,type:`config`},{path:jt,type:`legacy_config`}],Nt={config:H,legacyConfigs:[jt]},Pt=`1.79.0`,Ft=e=>qe(e,`oxlint`,Nt);var U=M({assess:(e,t)=>n.gen(function*(){let n=Ve(t);if(!n.includes(`check`)&&!n.includes(`fix`))return{applicable:!1,warnings:[]};let r=yield*Ft(e),i=Je(t,{name:`oxlint`,version:Pt},`the managed lint scripts`),a=r.active,o;if(a?.format===`ts`){let e=At(yield*N(a.path));o=e.kind===`configured`?{kind:`configured`}:{kind:`invalid`,reason:e.kind===`manual`?e.reason:`The required Oxlint options are missing or set to false.`}}let s=yt({},ht());return{applicable:!0,findings:[...Ye(i,`oxlint`),...Xe(r,{configContent:s,configFile:H,inspection:o,invalidGoal:"Set `respectEslintDisableDirectives`, `typeAware`, and `typeCheck` to `true` in the `options` object. Preserve every other project setting.",toolName:`oxlint`})],packageActions:i,warnings:r.warnings}}),config:H,create:(e,t=[])=>n.gen(function*(){let n=yield*x.Path,r=yt({},ht(t));yield*F(n.join(e,H),r)}),detect:Ft,files:Mt,kind:`tooling`,name:`oxlint`,update:e=>n.gen(function*(){let t=yield*b.FileSystem,n=(yield*x.Path).join(e,H);if(!(yield*t.exists(n)))return yield*new we({path:H});let r=At(yield*N(n));if(r.kind!==`configured`){if(r.kind===`manual`)return yield*new Ee({path:H,reason:r.reason});yield*F(n,r.updatedContent)}}),version:Pt});const It=w.file(`files`,{mustExist:!0}).pipe(w.withDescription(`Specific files to lint (optional)`),w.variadic());var Lt=l.make(`check`,{files:It}).pipe(l.withDescription(`Find issues and type errors in code using oxlint`),l.withHandler(({files:e})=>n.gen(function*(){let t=yield*j,n=yield*(yield*A).run({args:[...e,...t],command:U.name});n!==s.ExitCode(0)&&(yield*new O({command:U.name,exitCode:n}))})));const Rt=[{command:`claude`,name:`Claude Code`,seedArguments:e=>[e]},{command:`codex`,name:`Codex`,seedArguments:e=>[e]},{command:`cursor-agent`,name:`Cursor`,seedArguments:e=>[e]},{command:`gemini`,name:`Gemini CLI`,seedArguments:e=>[`-i`,e]},{command:`grok`,name:`Grok Build`,probeArguments:[`version`],seedArguments:e=>[e]},{command:`opencode`,name:`OpenCode`,seedArguments:e=>[`--prompt`,e]}],zt=e=>n.gen(function*(){let t=yield*A;return(yield*n.forEach(Rt,r=>t.run({args:[...r.probeArguments??[`--version`]],command:r.command,cwd:e,stderr:`ignore`,stdout:`ignore`}).pipe(n.timeout(`10 seconds`),n.as(r),n.catch(()=>n.succeed(null))),{concurrency:Rt.length})).filter(e=>e!==null)});var Bt=class extends m.TaggedError(`AgentSessionFailed`){};const Vt=()=>{},Ht=e=>n.acquireUseRelease(n.sync(()=>{let e=S.listeners(`SIGINT`);return S.removeAllListeners(`SIGINT`),S.on(`SIGINT`,Vt),e}),()=>e,e=>n.sync(()=>{S.removeAllListeners(`SIGINT`);for(let t of e)S.on(`SIGINT`,t)})),Ut=({agent:e,cwd:t})=>n.gen(function*(){let n=yield*A;yield*Ht(n.run({args:e.seedArguments("Run `adamantite doctor` — through your package runner, such as `npx` or `pnpm exec`, if it is not on PATH — and resolve every finding it reports. Rerun `adamantite doctor` until it exits 0."),command:e.command,cwd:t,detached:!1,stderr:`inherit`,stdin:`inherit`,stdout:`inherit`}))}).pipe(n.asVoid,n.mapError(e=>new Bt({cause:e,reason:e._tag===`CliNotFound`?`not-found`:`spawn-failed`}))),Wt=e=>n.gen(function*(){let t=yield*(yield*A).run({args:[`diff`,`--quiet`,`HEAD`],command:`git`,cwd:e,stderr:`ignore`,stdout:`ignore`});return t===s.ExitCode(0)?`clean`:t===s.ExitCode(1)?`dirty`:`unknown`}).pipe(n.catch(()=>n.succeed(`unknown`))),Gt=[{name:`check`,script:`check`},{args:[`--check`],name:`format`,script:`format`},{name:`monorepo`,script:`check:monorepo`},{name:`analyze`,script:`analyze`}];function Kt(e,t){let n=[];for(let r of Gt)t.includes(r.script)&&n.push({command:ue(e,r.script,{args:r.args}),name:r.name});return n}function qt(e){return Gt.some(t=>e.includes(t.script))}var W=class extends d.Service()(`DependencyInstaller`){static layer=i.succeed(this)({addDevDependencies:n.fn(`DependencyInstaller.addDevDependencies`)((e,t,r)=>n.tryPromise({catch:t=>new ve({cause:t,packages:e}),try:()=>ce(e,{...r,cwd:t})}).pipe(n.asVoid)),detectPackageManager:n.fn(`DependencyInstaller.detectPackageManager`)(e=>n.tryPromise({catch:e=>new De({cause:e}),try:()=>le(e)}).pipe(n.map(e=>e??null)))})};function Jt(e){return{_tag:`File`,path:e}}function Yt(e){return{_tag:`Version`,value:e}}const Xt=[`.node-version`,`.nvmrc`],Zt=T.Struct({volta:T.Struct({node:T.NonEmptyString})}),Qt=T.Struct({engines:T.Struct({node:T.NonEmptyString})}),$t=T.Struct({name:T.NonEmptyString,version:T.NonEmptyString});function en(e){return e.split(`
11
+ `)?t:`${t}\n`}function Ct(e){return e.type===`Identifier`?h(e.name,g.some):e.type===`Literal`&&_.isString(e.value)?h(e.value,g.some):g.none()}function wt(e){return e.type===`ObjectExpression`?h(e,g.some):e.type!==`CallExpression`||e.callee.type!==`Identifier`||e.callee.name!==`defineConfig`?g.none():h(e.arguments.length===1?c.head(e.arguments):g.none(),g.filter(e=>e.type===`ObjectExpression`))}function Tt(e){return h(e.body,c.filter(e=>e.type===`ExportDefaultDeclaration`),e=>e.length===1?c.head(e):g.none(),g.flatMap(e=>wt(e.declaration)))}function Et(e,t){let n=null;for(let r of e.properties){if(r.type===`SpreadElement`||r.computed)return{status:`manual`};let e=g.contains(Ct(r.key),t);if(r.method||r.kind!==`init`){if(e)return{status:`manual`};continue}if(e){if(n)return{status:`manual`};n=r}}return n?{property:n,status:`found`}:{status:`missing`}}function Dt(e){return{computed:!1,end:0,key:{end:0,name:e,start:0,type:`Identifier`},kind:`init`,method:!1,shorthand:!1,start:0,type:`Property`,value:{end:0,raw:`true`,start:0,type:`Literal`,value:!0}}}function Ot(){return{computed:!1,end:0,key:{end:0,name:`options`,start:0,type:`Identifier`},kind:`init`,method:!1,shorthand:!1,start:0,type:`Property`,value:{end:0,properties:dt.map(e=>Dt(e)),start:0,type:`ObjectExpression`}}}function kt(e,t){let n=[],r=!1;for(let e of dt){let i=Et(t,e);if(i.status===`manual`)return{kind:`manual`,reason:mt};if(i.status===`missing`){n.push(e);continue}let a=i.property.value;if(a.type!==`Literal`||!_.isBoolean(a.value))return{kind:`manual`,reason:mt};a.value||(a.raw=`true`,a.value=!0,r=!0)}return n.length>0&&(t.properties.unshift(...n.map(e=>Dt(e))),r=!0),r?{kind:`patchable`,updatedContent:St(e)}:{kind:`configured`}}function At(e){let t=xt(e);if(g.isNone(t))return{kind:`manual`,reason:ft};let n=Tt(t.value);if(g.isNone(n))return{kind:`manual`,reason:ft};let r=Et(n.value,`options`);return r.status===`manual`?{kind:`manual`,reason:pt}:r.status===`missing`?(n.value.properties.unshift(Ot()),{kind:`patchable`,updatedContent:St(t.value)}):r.property.value.type===`ObjectExpression`?kt(t.value,r.property.value):{kind:`manual`,reason:pt}}const H=`oxlint.config.ts`,jt=`.oxlintrc.json`,Mt=[{path:H,type:`config`},{path:jt,type:`legacy_config`}],Nt={config:H,legacyConfigs:[jt]},Pt=`1.79.0`,Ft=e=>qe(e,`oxlint`,Nt);var U=M({assess:(e,t)=>n.gen(function*(){let n=Ve(t);if(!n.includes(`check`)&&!n.includes(`fix`))return{applicable:!1,warnings:[]};let r=yield*Ft(e),i=Je(t,{name:`oxlint`,version:Pt},`the managed lint scripts`),a=r.active,o;if(a?.format===`ts`){let e=At(yield*N(a.path));o=e.kind===`configured`?{kind:`configured`}:{kind:`invalid`,reason:e.kind===`manual`?e.reason:`The required Oxlint options are missing or set to false.`}}let s=yt({},ht());return{applicable:!0,findings:[...Ye(i,`oxlint`),...Xe(r,{configContent:s,configFile:H,inspection:o,invalidGoal:"Set `respectEslintDisableDirectives`, `typeAware`, and `typeCheck` to `true` in the `options` object. Preserve every other project setting.",toolName:`oxlint`})],packageActions:i,warnings:r.warnings}}),config:H,create:(e,t=[])=>n.gen(function*(){let n=yield*x.Path,r=yt({},ht(t));yield*F(n.join(e,H),r)}),detect:Ft,files:Mt,kind:`tooling`,name:`oxlint`,update:e=>n.gen(function*(){let t=yield*b.FileSystem,n=(yield*x.Path).join(e,H);if(!(yield*t.exists(n)))return yield*new we({path:H});let r=At(yield*N(n));if(r.kind!==`configured`){if(r.kind===`manual`)return yield*new Ee({path:H,reason:r.reason});yield*F(n,r.updatedContent)}}),version:Pt});const It=w.File(`files`,{mustExist:!0}).pipe(w.withDescription(`Specific files to lint (optional)`),w.variadic());var Lt=l.make(`check`,{files:It}).pipe(l.withDescription(`Find issues and type errors in code using oxlint`),l.withHandler(({files:e})=>n.gen(function*(){let t=yield*j,n=yield*(yield*A).run({args:[...e,...t],command:U.name});n!==s.ExitCode(0)&&(yield*new O({command:U.name,exitCode:n}))})));const Rt=[{command:`claude`,name:`Claude Code`,seedArguments:e=>[e]},{command:`codex`,name:`Codex`,seedArguments:e=>[e]},{command:`cursor-agent`,name:`Cursor`,seedArguments:e=>[e]},{command:`gemini`,name:`Gemini CLI`,seedArguments:e=>[`-i`,e]},{command:`grok`,name:`Grok Build`,probeArguments:[`version`],seedArguments:e=>[e]},{command:`opencode`,name:`OpenCode`,seedArguments:e=>[`--prompt`,e]}],zt=e=>n.gen(function*(){let t=yield*A;return(yield*n.forEach(Rt,r=>t.run({args:[...r.probeArguments??[`--version`]],command:r.command,cwd:e,stderr:`ignore`,stdout:`ignore`}).pipe(n.timeout(`10 seconds`),n.as(r),n.catch(()=>n.succeed(null))),{concurrency:Rt.length})).filter(e=>e!==null)});var Bt=class extends m.TaggedError(`AgentSessionFailed`){};const Vt=()=>{},Ht=e=>n.acquireUseRelease(n.sync(()=>{let e=S.listeners(`SIGINT`);return S.removeAllListeners(`SIGINT`),S.on(`SIGINT`,Vt),e}),()=>e,e=>n.sync(()=>{S.removeAllListeners(`SIGINT`);for(let t of e)S.on(`SIGINT`,t)})),Ut=({agent:e,cwd:t})=>n.gen(function*(){let n=yield*A;yield*Ht(n.run({args:e.seedArguments("Run `adamantite doctor` — through your package runner, such as `npx` or `pnpm exec`, if it is not on PATH — and resolve every finding it reports. Rerun `adamantite doctor` until it exits 0."),command:e.command,cwd:t,detached:!1,stderr:`inherit`,stdin:`inherit`,stdout:`inherit`}))}).pipe(n.asVoid,n.mapError(e=>new Bt({cause:e,reason:e._tag===`CliNotFound`?`not-found`:`spawn-failed`}))),Wt=e=>n.gen(function*(){let t=yield*(yield*A).run({args:[`diff`,`--quiet`,`HEAD`],command:`git`,cwd:e,stderr:`ignore`,stdout:`ignore`});return t===s.ExitCode(0)?`clean`:t===s.ExitCode(1)?`dirty`:`unknown`}).pipe(n.catch(()=>n.succeed(`unknown`))),Gt=[{name:`check`,script:`check`},{args:[`--check`],name:`format`,script:`format`},{name:`monorepo`,script:`check:monorepo`},{name:`analyze`,script:`analyze`}];function Kt(e,t){let n=[];for(let r of Gt)t.includes(r.script)&&n.push({command:ue(e,r.script,{args:r.args}),name:r.name});return n}function qt(e){return Gt.some(t=>e.includes(t.script))}var W=class extends d.Service()(`DependencyInstaller`){static layer=i.succeed(this)({addDevDependencies:n.fn(`DependencyInstaller.addDevDependencies`)((e,t,r)=>n.tryPromise({catch:t=>new ve({cause:t,packages:e}),try:()=>ce(e,{...r,cwd:t})}).pipe(n.asVoid)),detectPackageManager:n.fn(`DependencyInstaller.detectPackageManager`)(e=>n.tryPromise({catch:e=>new De({cause:e}),try:()=>le(e)}).pipe(n.map(e=>e??null)))})};function Jt(e){return{_tag:`File`,path:e}}function Yt(e){return{_tag:`Version`,value:e}}const Xt=[`.node-version`,`.nvmrc`],Zt=T.Struct({volta:T.Struct({node:T.NonEmptyString})}),Qt=T.Struct({engines:T.Struct({node:T.NonEmptyString})}),$t=T.Struct({name:T.NonEmptyString,version:T.NonEmptyString});function en(e){return e.split(`
12
12
  `).map(e=>e.split(`#`)[0]?.trim()??``).some(e=>/^node(?:js)?\s+\S/.test(e))}function tn(e){return T.is($t)(e)&&e.name.toLowerCase()===`node`}function nn(e){if(T.is(Zt)(e))return!0;if(_.isObject(e)&&_.isObject(e.devEngines)){let t=e.devEngines.runtime;if((Array.isArray(t)?t:[t]).some(e=>tn(e)))return!0}return T.is(Qt)(e)}var rn=class extends d.Service()(`NodeVersionResolver`){static layer=i.effect(this,n.gen(function*(){let e=yield*b.FileSystem,t=yield*x.Path,r=(r,i)=>P(t.join(r,i)).pipe(n.provideService(b.FileSystem,e));return{resolve:n.fn(`NodeVersionResolver.resolve`)(function*(e){for(let t of Xt){let n=yield*r(e,t);if(g.exists(n,e=>v.isNonEmpty(e.trim())))return Jt(t)}let n=yield*r(e,`.tool-versions`);if(g.exists(n,e=>en(e)))return Jt(`.tool-versions`);let i=yield*r(e,`package.json`);return g.isSome(i)&&nn(yield*L(i.value,t.join(e,`package.json`)))?Jt(`package.json`):Yt(`lts/*`)})}}))};const an=/^\s*node-version:\s*"?\d/m,on=/^[>|](?:[1-9][+-]?|[+-][1-9]?)?(?:\s+#.*)?$/,sn=/\b(?:(?:bun|npm|pnpm|yarn)(?:\s+(?!run\b)\S+)*\s+run\s+check|deno(?:\s+(?!task\b)\S+)*\s+task\s+check)\b/,cn=/^(\s*)(?:-\s*)?(?:command|run):\s*(.*)$/;function ln(e){let t=e.split(`
13
13
  `);for(let[e,n]of t.entries()){let r=cn.exec(n);if(!r)continue;let i=r[1]?.length??0,a=(r[2]??``).trim();if(sn.test(a))return!0;if(on.test(a))for(let n of t.slice(e+1)){let e=n.trim();if(e.length!==0){if(n.length-n.trimStart().length<=i)break;if(sn.test(e))return!0}}}return!1}function un(e){return` - name: Setup Node.js
14
14
  uses: actions/setup-node@v7
@@ -99,7 +99,7 @@ ${dn(n)[e]}
99
99
  `)}`),t.join(`
100
100
 
101
101
  `)}const Un=n.fn(`printFindings`)(function*(e){let t=yield*Q;for(let[n,r]of e.entries())yield*t.note(Hn(r),`${n+1}. ${r.title}`)}),Wn=' .o8 . o8o . \n "888 .o8 `"\' .o8 \n .oooo. .oooo888 .oooo. ooo. .oo. .oo. .oooo. ooo. .oo. .o888oo oooo .o888oo .ooooo. \n`P )88b d88\' `888 `P )88b `888P"Y88bP"Y88b `P )88b `888P"Y88b 888 `888 888 d88\' `88b \n .oP"888 888 888 .oP"888 888 888 888 .oP"888 888 888 888 888 888 888ooo888 \nd8( 888 888 888 d8( 888 888 888 888 d8( 888 888 888 888 . 888 888 . 888 .o \n`Y888""8o `Y8bod88P" `Y888""8o o888o o888o o888o `Y888""8o o888o o888o "888" o888o "888" `Y8bod8P\' \n \n \n ',Gn=()=>n.gen(function*(){let e=yield*(yield*fe.Terminal).columns,t=Wn.split(`
102
- `).reduce((e,t)=>Math.max(e,t.trim().length),0);!e||e<t||(yield*de.info(Wn))}),Kn=u.boolean(`fix`).pipe(u.withDefault(!1),u.withDescription(`Removed. Run doctor and follow its findings`)),qn=`0.38.0`;var Jn=l.make(`doctor`,{fix:Kn}).pipe(l.withDescription(`Assess Adamantite-managed integrations in the current project`),l.withHandler(({fix:e})=>n.gen(function*(){let t=S.cwd(),r=yield*Q,i=yield*Vn,a=yield*i.isInteractive;a&&(yield*Gn(),yield*r.intro(`💠 adamantite doctor`));let o=n.gen(function*(){return yield*r.outro(`⚠️ Doctor found issues.`),yield*new O({command:`doctor`,exitCode:s.ExitCode(1)})});if(e){let e="`doctor --fix` has been removed. Run `adamantite doctor` and follow the reported goal criteria.";return a?(yield*r.log.error(e),yield*r.outro(`❌ Doctor did not run`)):yield*r.message(e),yield*new O({command:`doctor`,exitCode:s.ExitCode(1)})}let c=yield*z(t);if(!c.devDependencies?.adamantite&&!c.dependencies?.adamantite){let e="`adamantite` is not installed in this project. Install it before running `adamantite doctor`.";return a?(yield*r.log.warning(e),yield*r.outro(`⚠️ Doctor found issues.`)):yield*r.message(e),yield*new O({command:`doctor`,exitCode:s.ExitCode(1)})}let l=yield*Ln(t);if(a)for(let e of l.warnings)yield*r.log.warning(e);if(l.applicableIntegrations.length===0){a&&(yield*r.log.success(`No applicable integrations found.`),yield*r.outro(`✅ Doctor completed successfully!`));return}if(l.findings.length===0){a?(yield*r.log.success(`No issues found.`),yield*r.outro(`✅ Doctor completed successfully!`)):l.warnings.length>0&&(yield*r.message(Rn(l,qn)));return}if(!a)return yield*r.message(Rn(l,qn)),yield*new O({command:`doctor`,exitCode:s.ExitCode(1)});let u=e=>n.gen(function*(){(yield*r.confirm({initialValue:!0,message:`Copy the Markdown prompt for a coding agent?`}))&&(yield*r.message(e),yield*i.copyToClipboard(e),yield*r.log.success(`The Markdown prompt was printed and sent to the terminal clipboard.`))});yield*Un(l.findings);let d=yield*r.withSpinner(()=>zt(t),{start:`Checking for installed coding agents...`,success:e=>e.length===0?`No supported coding agent CLI was found on PATH.`:`Found ${e.map(e=>e.name).join(`, `)}.`});d.length===0&&(yield*r.log.info(`Doctor can hand findings off when one of these CLIs is installed: ${Rt.map(e=>`\`${e.command}\``).join(`, `)}.`));let f=Rn(l,qn),p=yield*r.select({message:`How do you want to resolve these findings?`,options:[...d.map(e=>({label:`Hand off to ${e.name}`,value:e})),{label:`Copy the Markdown prompt for a coding agent`,value:`copy`},{label:`Do nothing`,value:`done`}]});if(p===`done`)return yield*o;if(p===`copy`)return yield*r.message(f),yield*i.copyToClipboard(f),yield*r.log.success(`The Markdown prompt was printed and sent to the terminal clipboard.`),yield*o;let m=p,h=yield*Wt(t);if(h!==`clean`&&(yield*r.log.warning(h===`dirty`?`The Git working tree has uncommitted changes. The agent will edit files on top of them.`:`Doctor could not confirm a clean Git working tree. The agent will edit files without a checkpoint to return to.`),!(yield*r.confirm({initialValue:!1,message:`Hand off to ${m.name} anyway?`})))||(yield*r.log.info(`Handing the terminal to ${m.name}. Exit the agent to return to Doctor.`),!(yield*Ut({agent:m,cwd:t}).pipe(n.as(!0),n.catchTag(`AgentSessionFailed`,e=>r.log.error(e.reason===`not-found`?`\`${m.command}\` was not found on PATH. Install ${m.name} or copy the prompt instead.`:`Failed to start ${m.name}: ${e.cause.message}`).pipe(n.as(!1)))))))return yield*u(f),yield*o;let g=yield*Ln(t);if(g.findings.length===0){yield*r.log.success(`All findings were resolved by ${m.name}.`),yield*r.outro(`✅ Doctor completed successfully!`);return}return yield*r.log.warning(`${g.findings.length} of ${l.findings.length} findings remain after the ${m.name} session.`),yield*Un(g.findings),yield*u(Rn(g,qn)),yield*o}).pipe(n.catchTag(`OperationCancelled`,()=>n.gen(function*(){return yield*(yield*Q).cancel(`Doctor was cancelled. The findings remain.`),yield*new O({command:`doctor`,exitCode:s.ExitCode(1)})})))));const Yn=w.file(`files`,{mustExist:!0}).pipe(w.withDescription(`Specific files to fix (optional)`),w.variadic()),Xn=u.boolean(`suggested`).pipe(u.withDefault(!1),u.withDescription(`Apply suggested fixes`)),Zn=u.boolean(`dangerous`).pipe(u.withDefault(!1),u.withDescription(`Apply dangerous fixes`)),Qn=u.boolean(`all`).pipe(u.withDefault(!1),u.withDescription(`Apply all fixes, including suggested and dangerous fixes`));var $n=l.make(`fix`,{all:Qn,dangerous:Zn,files:Yn,suggested:Xn}).pipe(l.withDescription(`Fix issues in code using oxlint`),l.withHandler(({all:e,dangerous:t,files:r,suggested:i})=>n.gen(function*(){let n=yield*j,a=yield*A,o=c.dedupe([`--fix`,...i||e?[`--fix-suggestions`]:[],...t||e?[`--fix-dangerously`]:[],...r]),l=yield*a.run({args:[...o,...n],command:U.name});l!==s.ExitCode(0)&&(yield*new O({command:U.name,exitCode:l}))})));const er=w.file(`files`,{mustExist:!0}).pipe(w.withDescription(`Specific files to format (optional)`),w.variadic()),tr=u.boolean(`check`).pipe(u.withDefault(!1),u.withDescription(`Check if files are formatted without writing`));var nr=l.make(`format`,{check:tr,files:er}).pipe(l.withDescription(`Format files using oxfmt`),l.withHandler(({check:e,files:t})=>n.gen(function*(){let n=yield*j,r=yield*A,i=[];e&&i.push(`--check`),i.push(...t,...n);let a=yield*r.run({args:i,command:q.name});a!==s.ExitCode(0)&&(yield*new O({command:q.name,exitCode:a}))})));const rr=[{path:`.vscode/settings.json`,type:`config`}],ir={"[css]":{"editor.defaultFormatter":`oxc.oxc-vscode`},"[graphql]":{"editor.defaultFormatter":`oxc.oxc-vscode`},"[javascript]":{"editor.defaultFormatter":`oxc.oxc-vscode`},"[javascriptreact]":{"editor.defaultFormatter":`oxc.oxc-vscode`},"[json]":{"editor.defaultFormatter":`oxc.oxc-vscode`},"[jsonc]":{"editor.defaultFormatter":`oxc.oxc-vscode`},"[typescript]":{"editor.defaultFormatter":`oxc.oxc-vscode`},"[typescriptreact]":{"editor.defaultFormatter":`oxc.oxc-vscode`},"editor.codeActionsOnSave":{"source.fixAll.oxc":`explicit`},"editor.defaultFormatter":`oxc.oxc-vscode`,"editor.formatOnPaste":!0,"editor.formatOnSave":!0,"oxc.typeAware":!0};var $=M({config:rr[0].path,create:e=>n.gen(function*(){let t=yield*x.Path,n=t.join(e,rr[0].path);yield*je(t.dirname(n)),yield*I(n,ir)}),detect:e=>n.gen(function*(){let t=yield*b.FileSystem,n=yield*x.Path;return yield*t.exists(n.join(e,rr[0].path))}),extension:(e=[])=>n.gen(function*(){let t=[];(e.includes(`check`)||e.includes(`fix`)||e.includes(`format`))&&t.push(`oxc.oxc-vscode`),e.includes(`analyze`)&&t.push(`webpro.vscode-knip`);for(let e of t){let t=yield*(yield*A).run({args:[`--install-extension`,e],command:`code`}).pipe(n.mapError(t=>t._tag===`CliNotFound`&&t.command===`code`?new Ae({cause:t}):new ye({cause:t,extension:e})));if(t!==s.ExitCode(0))return yield*new ye({cause:t,extension:e})}}),files:rr,kind:`editor`,name:`vscode`,update:e=>n.gen(function*(){let t=(yield*x.Path).join(e,rr[0].path),n=yield*N(t),r=yield*L(n,t);if(!_.isObject(r))return yield*new Te({path:t});let i=yield*Fe(ir,r);yield*I(t,i)})});const ar=`<!-- ADAMANTITE:START -->`,or=`<!-- ADAMANTITE:END -->`;function sr(e,t){let n=ue(e,t),r=B[t];switch(t){case`analyze`:return`- Run \`${n}\` after changing dependencies, imports, or exports. Direct command: \`${r}\`.`;case`check`:return`- Run \`${n}\` to catch lint and type issues. Direct command: \`${r}\`.`;case`check:monorepo`:return`- Run \`${n}\` to check monorepo package consistency. Direct command: \`${r}\`.`;case`fix`:return`- Run \`${n}\` to apply safe lint fixes. Direct command: \`${r}\`.`;case`fix:monorepo`:return`- Run \`${n}\` to fix monorepo package consistency. Direct command: \`${r}\`.`;case`format`:return`- Run \`${n}\` after editing files. Direct command: \`${r}\`.`}}function cr({packageManager:e,scripts:t}){let n=[`format`,`check`,`fix`,`analyze`,`check:monorepo`,`fix:monorepo`].filter(e=>t.includes(e)).map(t=>sr(e,t)),r=[`## Adamantite`,``,`This project uses Adamantite for its managed formatting, linting, type checking, and dependency-analysis setup.`,``,...n.length>0?[`- Prefer the package scripts Adamantite added for this workspace.`,...n]:[],"- Run `adamantite doctor` and follow its findings to repair managed setup."].join(`
102
+ `).reduce((e,t)=>Math.max(e,t.trim().length),0);!e||e<t||(yield*de.info(Wn))}),Kn=u.Boolean(`fix`).pipe(u.withDefault(!1),u.withDescription(`Removed. Run doctor and follow its findings`)),qn=`0.39.0`;var Jn=l.make(`doctor`,{fix:Kn}).pipe(l.withDescription(`Assess Adamantite-managed integrations in the current project`),l.withHandler(({fix:e})=>n.gen(function*(){let t=S.cwd(),r=yield*Q,i=yield*Vn,a=yield*i.isInteractive;a&&(yield*Gn(),yield*r.intro(`💠 adamantite doctor`));let o=n.gen(function*(){return yield*r.outro(`⚠️ Doctor found issues.`),yield*new O({command:`doctor`,exitCode:s.ExitCode(1)})});if(e){let e="`doctor --fix` has been removed. Run `adamantite doctor` and follow the reported goal criteria.";return a?(yield*r.log.error(e),yield*r.outro(`❌ Doctor did not run`)):yield*r.message(e),yield*new O({command:`doctor`,exitCode:s.ExitCode(1)})}let c=yield*z(t);if(!c.devDependencies?.adamantite&&!c.dependencies?.adamantite){let e="`adamantite` is not installed in this project. Install it before running `adamantite doctor`.";return a?(yield*r.log.warning(e),yield*r.outro(`⚠️ Doctor found issues.`)):yield*r.message(e),yield*new O({command:`doctor`,exitCode:s.ExitCode(1)})}let l=yield*Ln(t);if(a)for(let e of l.warnings)yield*r.log.warning(e);if(l.applicableIntegrations.length===0){a&&(yield*r.log.success(`No applicable integrations found.`),yield*r.outro(`✅ Doctor completed successfully!`));return}if(l.findings.length===0){a?(yield*r.log.success(`No issues found.`),yield*r.outro(`✅ Doctor completed successfully!`)):l.warnings.length>0&&(yield*r.message(Rn(l,qn)));return}if(!a)return yield*r.message(Rn(l,qn)),yield*new O({command:`doctor`,exitCode:s.ExitCode(1)});let u=e=>n.gen(function*(){(yield*r.confirm({initialValue:!0,message:`Copy the Markdown prompt for a coding agent?`}))&&(yield*r.message(e),yield*i.copyToClipboard(e),yield*r.log.success(`The Markdown prompt was printed and sent to the terminal clipboard.`))});yield*Un(l.findings);let d=yield*r.withSpinner(()=>zt(t),{start:`Checking for installed coding agents...`,success:e=>e.length===0?`No supported coding agent CLI was found on PATH.`:`Found ${e.map(e=>e.name).join(`, `)}.`});d.length===0&&(yield*r.log.info(`Doctor can hand findings off when one of these CLIs is installed: ${Rt.map(e=>`\`${e.command}\``).join(`, `)}.`));let f=Rn(l,qn),p=yield*r.select({message:`How do you want to resolve these findings?`,options:[...d.map(e=>({label:`Hand off to ${e.name}`,value:e})),{label:`Copy the Markdown prompt for a coding agent`,value:`copy`},{label:`Do nothing`,value:`done`}]});if(p===`done`)return yield*o;if(p===`copy`)return yield*r.message(f),yield*i.copyToClipboard(f),yield*r.log.success(`The Markdown prompt was printed and sent to the terminal clipboard.`),yield*o;let m=p,h=yield*Wt(t);if(h!==`clean`&&(yield*r.log.warning(h===`dirty`?`The Git working tree has uncommitted changes. The agent will edit files on top of them.`:`Doctor could not confirm a clean Git working tree. The agent will edit files without a checkpoint to return to.`),!(yield*r.confirm({initialValue:!1,message:`Hand off to ${m.name} anyway?`})))||(yield*r.log.info(`Handing the terminal to ${m.name}. Exit the agent to return to Doctor.`),!(yield*Ut({agent:m,cwd:t}).pipe(n.as(!0),n.catchTag(`AgentSessionFailed`,e=>r.log.error(e.reason===`not-found`?`\`${m.command}\` was not found on PATH. Install ${m.name} or copy the prompt instead.`:`Failed to start ${m.name}: ${e.cause.message}`).pipe(n.as(!1)))))))return yield*u(f),yield*o;let g=yield*Ln(t);if(g.findings.length===0){yield*r.log.success(`All findings were resolved by ${m.name}.`),yield*r.outro(`✅ Doctor completed successfully!`);return}return yield*r.log.warning(`${g.findings.length} of ${l.findings.length} findings remain after the ${m.name} session.`),yield*Un(g.findings),yield*u(Rn(g,qn)),yield*o}).pipe(n.catchTag(`OperationCancelled`,()=>n.gen(function*(){return yield*(yield*Q).cancel(`Doctor was cancelled. The findings remain.`),yield*new O({command:`doctor`,exitCode:s.ExitCode(1)})})))));const Yn=w.File(`files`,{mustExist:!0}).pipe(w.withDescription(`Specific files to fix (optional)`),w.variadic()),Xn=u.Boolean(`suggested`).pipe(u.withDefault(!1),u.withDescription(`Apply suggested fixes`)),Zn=u.Boolean(`dangerous`).pipe(u.withDefault(!1),u.withDescription(`Apply dangerous fixes`)),Qn=u.Boolean(`all`).pipe(u.withDefault(!1),u.withDescription(`Apply all fixes, including suggested and dangerous fixes`));var $n=l.make(`fix`,{all:Qn,dangerous:Zn,files:Yn,suggested:Xn}).pipe(l.withDescription(`Fix issues in code using oxlint`),l.withHandler(({all:e,dangerous:t,files:r,suggested:i})=>n.gen(function*(){let n=yield*j,a=yield*A,o=c.dedupe([`--fix`,...i||e?[`--fix-suggestions`]:[],...t||e?[`--fix-dangerously`]:[],...r]),l=yield*a.run({args:[...o,...n],command:U.name});l!==s.ExitCode(0)&&(yield*new O({command:U.name,exitCode:l}))})));const er=w.File(`files`,{mustExist:!0}).pipe(w.withDescription(`Specific files to format (optional)`),w.variadic()),tr=u.Boolean(`check`).pipe(u.withDefault(!1),u.withDescription(`Check if files are formatted without writing`));var nr=l.make(`format`,{check:tr,files:er}).pipe(l.withDescription(`Format files using oxfmt`),l.withHandler(({check:e,files:t})=>n.gen(function*(){let n=yield*j,r=yield*A,i=[];e&&i.push(`--check`),i.push(...t,...n);let a=yield*r.run({args:i,command:q.name});a!==s.ExitCode(0)&&(yield*new O({command:q.name,exitCode:a}))})));const rr=[{path:`.vscode/settings.json`,type:`config`}],ir={"[css]":{"editor.defaultFormatter":`oxc.oxc-vscode`},"[graphql]":{"editor.defaultFormatter":`oxc.oxc-vscode`},"[javascript]":{"editor.defaultFormatter":`oxc.oxc-vscode`},"[javascriptreact]":{"editor.defaultFormatter":`oxc.oxc-vscode`},"[json]":{"editor.defaultFormatter":`oxc.oxc-vscode`},"[jsonc]":{"editor.defaultFormatter":`oxc.oxc-vscode`},"[typescript]":{"editor.defaultFormatter":`oxc.oxc-vscode`},"[typescriptreact]":{"editor.defaultFormatter":`oxc.oxc-vscode`},"editor.codeActionsOnSave":{"source.fixAll.oxc":`explicit`},"editor.defaultFormatter":`oxc.oxc-vscode`,"editor.formatOnPaste":!0,"editor.formatOnSave":!0,"oxc.typeAware":!0};var $=M({config:rr[0].path,create:e=>n.gen(function*(){let t=yield*x.Path,n=t.join(e,rr[0].path);yield*je(t.dirname(n)),yield*I(n,ir)}),detect:e=>n.gen(function*(){let t=yield*b.FileSystem,n=yield*x.Path;return yield*t.exists(n.join(e,rr[0].path))}),extension:(e=[])=>n.gen(function*(){let t=[];(e.includes(`check`)||e.includes(`fix`)||e.includes(`format`))&&t.push(`oxc.oxc-vscode`),e.includes(`analyze`)&&t.push(`webpro.vscode-knip`);for(let e of t){let t=yield*(yield*A).run({args:[`--install-extension`,e],command:`code`}).pipe(n.mapError(t=>t._tag===`CliNotFound`&&t.command===`code`?new Ae({cause:t}):new ye({cause:t,extension:e})));if(t!==s.ExitCode(0))return yield*new ye({cause:t,extension:e})}}),files:rr,kind:`editor`,name:`vscode`,update:e=>n.gen(function*(){let t=(yield*x.Path).join(e,rr[0].path),n=yield*N(t),r=yield*L(n,t);if(!_.isObject(r))return yield*new Te({path:t});let i=yield*Fe(ir,r);yield*I(t,i)})});const ar=`<!-- ADAMANTITE:START -->`,or=`<!-- ADAMANTITE:END -->`;function sr(e,t){let n=ue(e,t),r=B[t];switch(t){case`analyze`:return`- Run \`${n}\` after changing dependencies, imports, or exports. Direct command: \`${r}\`.`;case`check`:return`- Run \`${n}\` to catch lint and type issues. Direct command: \`${r}\`.`;case`check:monorepo`:return`- Run \`${n}\` to check monorepo package consistency. Direct command: \`${r}\`.`;case`fix`:return`- Run \`${n}\` to apply safe lint fixes. Direct command: \`${r}\`.`;case`fix:monorepo`:return`- Run \`${n}\` to fix monorepo package consistency. Direct command: \`${r}\`.`;case`format`:return`- Run \`${n}\` after editing files. Direct command: \`${r}\`.`}}function cr({packageManager:e,scripts:t}){let n=[`format`,`check`,`fix`,`analyze`,`check:monorepo`,`fix:monorepo`].filter(e=>t.includes(e)).map(t=>sr(e,t)),r=[`## Adamantite`,``,`This project uses Adamantite for its managed formatting, linting, type checking, and dependency-analysis setup.`,``,...n.length>0?[`- Prefer the package scripts Adamantite added for this workspace.`,...n]:[],"- Run `adamantite doctor` and follow its findings to repair managed setup."].join(`
103
103
  `);return[ar,``,r,``,or,``].join(`
104
104
  `)}const lr=(e,t)=>n.gen(function*(){let n=(yield*x.Path).join(e,`AGENTS.md`),r=h(yield*P(n),g.getOrElse(()=>``)),i=h(r,v.indexOf(ar)),a=h(r,v.indexOf(or)),o=h(g.all({end:a,start:i}),g.filter(({end:e,start:t})=>t<e)),s=cr(t);if(g.isSome(o)){let{end:e,start:t}=o.value,i=e+23,a=`${r.slice(0,t)}${s.trimEnd()}${r.slice(i)}`;return yield*F(n,a.endsWith(`
105
105
  `)?a:`${a}\n`),`updated`}if(g.isSome(i)||g.isSome(a))return`malformed`;let c=r.length===0||r.endsWith(`
@@ -108,4 +108,4 @@ ${dn(n)[e]}
108
108
  `)?`
109
109
  `:`
110
110
 
111
- `;return yield*F(n,`${r}${c}${s}`),`updated`}),ur=(e,t)=>n.gen(function*(){let r=yield*W;yield*(yield*Q).withSpinner(()=>n.gen(function*(){let n=yield*An(e);yield*r.addDevDependencies(t,e,{silent:!0,workspace:n})}),{failure:`Failed to install dependencies.`,start:`Installing dependencies...`,success:`Dependencies installed.`})});function dr(e,t,r){return n.gen(function*(){let i=yield*Q,a=yield*i.withSpinner(a=>n.gen(function*(){let n=yield*t.detect(e);for(let e of n.warnings)yield*i.log.warning(e);return n.active===null?(yield*a.message(`\`${t.config}\` not found, creating...`),yield*r,{created:!0,legacyConfig:null}):n.active.format===`ts`?(yield*a.message(`Found \`${t.config}\`, keeping existing config.`),{created:!1,legacyConfig:null}):(yield*a.message(`Found \`${n.active.file}\`, keeping existing config.`),{created:!1,legacyConfig:n.active.file})}),{failure:`Failed to set up ${t.name} config.`,start:`Setting up ${t.name} config...`,success:e=>e.created?`${t.name} config created successfully.`:`${t.name} config is ready.`});a.legacyConfig&&(yield*i.log.info(`Legacy \`${a.legacyConfig}\` was preserved during \`adamantite init\`. Run \`adamantite doctor\` and follow its findings to migrate it to the latest ${t.name} config.`))})}const fr=e=>`\`${e.script}\` is currently \`${e.command}\`; Adamantite would replace it with \`${B[e.script]}\`.`,pr=(e,t,r)=>n.gen(function*(){let i=yield*Q,a=yield*z(e),o=r.overwriteScripts?[]:He(a,t),s=new Set(o.map(e=>e.script)),c=t.filter(e=>!s.has(e));yield*i.withSpinner(()=>n.gen(function*(){if(c.length!==0){a.scripts??={};for(let e of c)a.scripts[e]=B[e];yield*ze(e,a)}}),{failure:"Failed to add scripts to `package.json`.",start:"Adding scripts to your `package.json`...",success:o.length===0?"Scripts added to your `package.json`":c.length===0?"Kept your existing `package.json` scripts.":"Scripts added to your `package.json`; conflicting scripts were kept."});let l=r.nonInteractive?"Use `--overwrite-scripts` to replace it.":"Re-run `adamantite init` and confirm overwriting to replace it.";for(let e of o)yield*i.log.warning(`Kept existing \`${e.script}\` script (\`${e.command}\`) instead of \`${B[e.script]}\`. ${l}`);return o.length>0&&(yield*i.log.info("Adamantite commands forward extra arguments after `--`, so custom flags can be kept, e.g. `adamantite monorepo -- --ignore-dependency tailwindcss`.")),c}),mr=(e,t)=>n.gen(function*(){let r=yield*Q;if(t){yield*h(Mn,n.forEach(e=>r.log.info(e)));return}yield*r.withSpinner(t=>n.gen(function*(){return(yield*Z.detect(e))?(yield*t.message(`\`${Z.config}\` found, updating...`),yield*Z.update(e),!1):(yield*t.message(`\`${Z.config}\` not found, creating...`),yield*Z.create(e),!0)}),{failure:`Failed to set up TypeScript config.`,start:`Setting up TypeScript config...`,success:e=>e?`\`${Z.config}\` created successfully`:`\`${Z.config}\` updated successfully`})}),hr=(e,t)=>n.gen(function*(){let r=yield*Q;t.includes(`vscode`)&&(yield*r.withSpinner(t=>n.gen(function*(){let n=yield*$.detect(e);return yield*t.message(`\`${$.config}\` ${n?`found, updating`:`not found, creating`}...`),yield*n?$.update(e):$.create(e),!n}),{failure:`Failed to set up VS Code config.`,start:`Checking for \`${$.config}\`...`,success:e=>`\`${$.config}\` ${e?`created`:`updated`} with Adamantite preset.`})),t.includes(`zed`)&&(yield*r.withSpinner(t=>n.gen(function*(){let n=yield*K.detect(e);return yield*t.message(`\`${K.config}\` ${n?`found, updating`:`not found, creating`}...`),yield*n?K.update(e):K.create(e),!n}),{failure:`Failed to set up Zed config.`,start:`Checking for \`${K.config}\`...`,success:e=>`\`${K.config}\` ${e?`created`:`updated`} with Adamantite preset.`}))}),gr=(e,t)=>n.gen(function*(){let r=yield*Q,i=e.includes(`zed`),a=e.includes(`vscode`);yield*r.withSpinner(e=>n.gen(function*(){return a&&(yield*e.message(`Installing VS Code extension...`),yield*$.extension(t)),!0}),{start:`Installing editor extensions...`,success:i&&!a?`Zed extensions require manual install.`:`Editor extensions installed successfully.`}).pipe(n.catchTag(`FailedToInstallExtension`,e=>n.gen(function*(){return yield*r.log.warning(`⚠️ ${e.message}`),yield*r.log.warning(`Please install it manually after setup completes.`),!1})),n.catchTag(`VscodeCliNotFound`,()=>n.gen(function*(){return yield*r.log.error(`VSCode CLI ('code' command) not found.`),yield*r.log.info(`To install it:`),yield*r.log.info(` 1. Open VS Code`),yield*r.log.info(` 2. Press Cmd+Shift+P (macOS) or Ctrl+Shift+P (Windows/Linux)`),yield*r.log.info(` 3. Run 'Shell Command: Install "code" command in PATH'`),!1}))),i&&(yield*r.log.info("Install the Zed `oxc` extension: zed://extension/oxc"))}),_r=(e,t,r)=>n.gen(function*(){let i=yield*Q,a=hn.files[0].path;yield*i.withSpinner(i=>n.gen(function*(){let n=yield*hn.detect(e);return yield*i.message(n?`\`${a}\` found, updating...`:`Creating \`${a}\`...`),yield*n?hn.update(e,{packageManager:t,scripts:r}):hn.create(e,{packageManager:t,scripts:r}),!n}),{failure:`Failed to set up GitHub Actions workflow.`,start:`Setting up GitHub Actions workflow...`,success:e=>`GitHub Actions workflow ${e?`created`:`updated`} successfully.`})}).pipe(n.catchTag([`FailedToCreateDirectory`,`FailedToParseFile`,`FailedToReadFile`,`FailedToWriteFile`,`PlatformError`],e=>n.gen(function*(){let t=yield*Q;yield*t.log.warning(`Could not set up the GitHub Actions workflow. ${e.message}`),yield*t.log.warning("Fix the reported problem and run `adamantite init` again, or create the workflow manually.")}))),vr=(e,t,r)=>n.gen(function*(){let i=yield*Q,a=yield*i.withSpinner(()=>lr(e,{packageManager:t,scripts:r}),{failure:`Failed to update AGENTS.md.`,start:`Updating AGENTS.md...`,success:`AGENTS.md check complete.`}).pipe(n.catchTag([`FailedToReadFile`,`FailedToWriteFile`],e=>n.gen(function*(){return yield*i.log.warning(`Could not update AGENTS.md. ${e.message} Adamantite will continue initialization.`),`failed`})));a!==`failed`&&a===`malformed`&&(yield*i.log.warning(`Could not update AGENTS.md because Adamantite markers are incomplete. Remove the stale ADAMANTITE marker and run adamantite init again.`))}),yr=[`check`,`fix`,`format`,`check:monorepo`,`fix:monorepo`,`analyze`],br=[`react`,`nextjs`,`vue`,`jest`,`vitest`,`node`,`antislop`],xr=[`vscode`,`zed`],Sr=n.fn(`validateInitOptions`)(function*(e,t){let n={agents:e.agents,editors:c.dedupe(e.editors),githubActions:e.githubActions,installExtensions:e.installExtensions,overwriteScripts:e.overwriteScripts,presets:c.dedupe(e.presets),scripts:c.dedupe(e.scripts),typescript:e.typescript};if(n.scripts.length===0)return yield*new k({reason:"Select at least one script with `--script <name>`."});let r=n.scripts.includes(`check`)||n.scripts.includes(`fix`);return(n.scripts.includes(`check:monorepo`)||n.scripts.includes(`fix:monorepo`))&&!t.isMonorepo?yield*new k({reason:`Monorepo scripts can only be selected in a detected monorepo.`}):n.presets.length>0&&!r?yield*new k({reason:"`--preset` requires the `check` or `fix` script."}):n.typescript&&!r?yield*new k({reason:"`--typescript` requires the `check` or `fix` script."}):n.installExtensions&&n.editors.length===0?yield*new k({reason:"`--install-extensions` requires at least one `--editor`."}):n.githubActions&&!qt(n.scripts)?yield*new k({reason:"`--github-actions` requires a CI-compatible script."}):n.githubActions&&t.nonInteractive&&!Be(t.packageManager)?yield*new k({reason:`\`--github-actions\` does not support the detected package manager \`${t.packageManager}\`. Use bun, deno, npm, pnpm, or yarn.`}):n}),Cr=u.boolean(`non-interactive`).pipe(u.withDefault(!1),u.withDescription(`Configure without prompts; requires at least one --script`)),wr=u.choice(`script`,yr).pipe(u.atMost(yr.length),u.withDescription(`Package script to configure; repeatable and required in non-interactive mode. Monorepo scripts require a detected monorepo`)),Tr=u.choice(`preset`,br).pipe(u.atMost(br.length),u.withDescription(`Oxlint preset to configure; repeatable and requires --script check or fix`)),Er=u.choice(`editor`,xr).pipe(u.atMost(xr.length),u.withDescription(`Editor to configure; may be specified multiple times`)),Dr=u.boolean(`typescript`).pipe(u.withDefault(!1),u.withDescription(`Configure the TypeScript preset; requires --script check or fix`)),Or=u.boolean(`install-extensions`).pipe(u.withDefault(!1),u.withDescription(`Install recommended extensions; requires at least one --editor`)),kr=u.boolean(`github-actions`).pipe(u.withDefault(!1),u.withDescription(`Configure CI; requires a compatible script and bun, deno, npm, pnpm, or yarn`)),Ar=u.boolean(`agents`).pipe(u.withDefault(!1),u.withDescription(`Add Adamantite guidance to AGENTS.md`)),jr=u.boolean(`overwrite-scripts`).pipe(u.withDefault(!1),u.withDescription(`Replace existing package scripts that conflict with Adamantite's managed commands`)),Mr=n.fn(`collectInteractiveInitOptions`)(function*(e,t){let n=yield*Q,r=yield*n.multiselect({message:"Which scripts do you want to add to your `package.json`?",options:[{hint:`recommended`,label:`check - find issues and type errors using oxlint`,value:`check`},{hint:`recommended`,label:`fix - fix code issues using oxlint`,value:`fix`},{hint:`recommended`,label:`format - code formatting using oxfmt`,value:`format`},{disabled:!t,hint:t?void 0:`available for monorepo projects`,label:`check:monorepo - check for monorepo-specific issues using Sherif`,value:`check:monorepo`},{disabled:!t,hint:t?void 0:`available for monorepo projects`,label:`fix:monorepo - fix monorepo-specific issues using Sherif`,value:`fix:monorepo`},{label:`analyze - find unused dependencies, exports, and files using knip`,value:`analyze`}]}),i=He(yield*z(e),r),a=!1;if(i.length>0){for(let e of i)yield*n.log.warning(fr(e));a=yield*n.confirm({initialValue:!1,message:i.length===1?`Overwrite this existing script with Adamantite's command?`:`Overwrite these existing scripts with Adamantite's commands?`})}let o=r.includes(`check`)||r.includes(`fix`),s=[];o&&(s=yield*n.multiselect({message:`Which presets do you want to install? (core is always included)`,options:[{hint:`React correctness, JSX accessibility, and render performance rules`,label:`react`,value:`react`},{hint:`Next.js pitfalls around scripts, fonts, images, and document/head usage`,label:`next.js`,value:`nextjs`},{hint:`Vue 3 correctness rules and deprecated API detection`,label:`vue`,value:`vue`},{hint:`Jest test hygiene: focused/disabled tests, matcher and snapshot discipline`,label:`jest`,value:`jest`},{hint:`Vitest test hygiene: focused/disabled tests, matcher and snapshot discipline`,label:`vitest`,value:`vitest`},{hint:`Node.js callback and CommonJS pitfalls`,label:`node`,value:`node`},{hint:`Rejects low-signal escape hatches: unjustified assertions, unknown leaks, module mocks`,label:`antislop`,value:`antislop`}],required:!1}));let c=o?yield*n.confirm({initialValue:!0,message:t?"Adamantite provides a TypeScript preset to enforce strict type-safety. In a monorepo, each package's `tsconfig.json` must extend it. Would you like instructions on how to set it up?":`Adamantite provides a TypeScript preset to enforce strict type-safety. Would you like to use it?`}):!1,l=yield*n.multiselect({message:`Which editors do you want to configure? (optional)`,options:[{label:`VSCode / Cursor / Windsurf`,value:`vscode`},{label:`Zed`,value:`zed`}],required:!1}),u=l.length>0?yield*n.confirm({initialValue:!0,message:`Do you want to install the recommended editor extensions?`}):!1,d=qt(r)?yield*n.confirm({message:`Do you want to add a GitHub Actions workflow to run checks in CI?`}):!1;return{agents:yield*n.confirm({initialValue:!0,message:`Add Adamantite guidance to AGENTS.md so coding agents know how to run project checks?`}),editors:l,githubActions:d,installExtensions:u,overwriteScripts:a,presets:s,scripts:r,typescript:c}});var Nr=l.make(`init`,{agents:Ar,editors:Er,githubActions:kr,installExtensions:Or,nonInteractive:Cr,overwriteScripts:jr,presets:Tr,scripts:wr,typescript:Dr}).pipe(l.withDescription(`Initialize Adamantite in the current directory. Setup flags require --non-interactive; omitted boolean setup flags are disabled`),l.withExamples([{command:`adamantite init --non-interactive --script check`,description:`Configure linting without prompts`},{command:`adamantite init --non-interactive --script check --script format --preset react --editor vscode --typescript --install-extensions --github-actions --agents`,description:`Configure a React project with VS Code, TypeScript, CI, and agent guidance`},{command:`adamantite init --non-interactive --script check:monorepo`,description:`Configure monorepo checks in a detected monorepo`}]),l.withHandler(e=>n.gen(function*(){let t=S.cwd(),n=yield*Q;yield*Gn(),yield*n.intro(`💠 adamantite init`);let r=yield*(yield*W).detectPackageManager(t);if(!r)return yield*new De({});if(r.warnings?.length)for(let e of r.warnings)yield*n.log.warning(e);yield*n.log.info(`Detected package manager: ${r.name}`);let i=yield*An(t);if(i&&(yield*n.log.info(`We've detected a monorepo setup in your project.`)),!e.nonInteractive&&c.some([e.scripts.length>0,e.presets.length>0,e.editors.length>0,e.typescript,e.installExtensions,e.githubActions,e.agents,e.overwriteScripts],_.isTruthy))return yield*new k({reason:"Setup flags require `--non-interactive`."});let a=e.nonInteractive?e:yield*Mr(t,i),o=yield*Sr(a,{isMonorepo:i,nonInteractive:e.nonInteractive,packageManager:r.name}),s=o.scripts,l=o.presets,u=o.editors,d=o.typescript,f=o.installExtensions,p=o.githubActions,m=o.agents,h=s.includes(`check`)||s.includes(`fix`),g=s.includes(`format`),v=s.includes(`check:monorepo`)||s.includes(`fix:monorepo`),ee=s.includes(`analyze`),y=[`adamantite`];h&&y.push(`${U.name}@${U.version}`,`${En.name}@${En.version}`),g&&y.push(`${q.name}@${q.version}`),v&&y.push(`${J.name}@${J.version}`),ee&&y.push(`${V.name}@${V.version}`),yield*ur(t,y),g&&(yield*dr(t,q,q.create(t))),h&&(yield*dr(t,U,U.create(t,l))),ee&&(yield*dr(t,V,V.create(t)));let b=yield*pr(t,s,{nonInteractive:e.nonInteractive,overwriteScripts:o.overwriteScripts});if(m&&(yield*vr(t,r.name,b)),d&&(yield*mr(t,i)),yield*hr(t,u),f&&(yield*gr(u,s)),p){let e=r.name;Be(e)?yield*_r(t,e,s):yield*n.log.warning(`Skipping GitHub Actions setup: \`${e}\` is not a supported package manager for CI workflow generation.`)}yield*n.log.success(`Your project is now configured`),yield*n.outro(`💠 Adamantite initialized successfully!`)}).pipe(n.catchTags({OperationCancelled:()=>n.gen(function*(){yield*(yield*Q).cancel(`You've cancelled the initialization process.`)})}))));const Pr=u.boolean(`fix`).pipe(u.withDefault(!1),u.withDescription(`Automatically fix issues`));var Fr=l.make(`monorepo`,{fix:Pr}).pipe(l.withDescription(`Find and fix monorepo-specific issues using Sherif`),l.withHandler(({fix:e})=>n.gen(function*(){let t=yield*j,n=yield*A,r=e?[`--fix`,...t]:[...t],i=yield*n.run({args:r,command:J.name,stdin:`inherit`});i!==s.ExitCode(0)&&(yield*new O({command:J.name,exitCode:i}))})));const Ir=[U,En,q,J,V];function Lr(e,t){return c.filterMap(Ir,n=>{if(t.has(n.name))return C.failVoid;let r=e.devDependencies?.[n.name]??e.dependencies?.[n.name];return r&&Re(r)!==n.version?C.succeed({currentVersion:r,name:n.name,targetVersion:n.version}):C.failVoid})}var Rr=l.make(`update`).pipe(l.withDescription(`Update Adamantite-managed dependencies and report setup findings`),l.withHandler(()=>n.gen(function*(){let e=S.cwd(),t=yield*Q,n=yield*W;yield*Gn(),yield*t.intro(`💠 adamantite update`);let r=yield*z(e),i=yield*Ln(e,r),a=i.packageActions,o=new Set(a.map(e=>e.package)),s=[...a.map(e=>({currentVersion:e.type===`install_package`?`not installed`:e.currentVersion,name:e.package,targetVersion:e.targetVersion})),...Lr(r,o)];if(s.length>0){yield*t.log.info(`The following dependencies will be updated:`);for(let e of s)yield*t.log.info(` ${e.name}: ${e.currentVersion} → ${e.targetVersion}`);yield*t.withSpinner(()=>n.addDevDependencies(s.map(e=>`${e.name}@${e.targetVersion}`),e,{silent:!0}),{failure:`Failed to update dependencies`,start:`Updating dependencies...`,success:`Dependencies updated successfully`}),yield*t.log.success(`Dependencies updated successfully.`)}let c=s.length===0?i:yield*Ln(e);for(let e of c.warnings)yield*t.log.warning(e);let l=c.findings;return l.length>0&&(yield*Un(l),yield*t.log.info("Run `adamantite doctor` to get the combined Markdown repair prompt.")),s.length===0&&l.length===0?(yield*t.log.success(`No changes needed.`),`no-changes`):`success`}).pipe(n.tapError(()=>n.gen(function*(){yield*(yield*Q).outro(`❌ Update failed`)})),n.tap(e=>n.gen(function*(){yield*(yield*Q).outro(e===`no-changes`?`✅ Adamantite is already up to date.`:`✅ Update completed successfully!`)})))));const zr=[lt,Lt,$n,nr,Fr],Br=[lt,Lt,Jn,$n,nr,Nr,Fr,Rr],Vr=new Set(Br.map(e=>e.name)),Hr=new Set(zr.map(e=>e.name)),Ur=l.make(`adamantite`).pipe(l.withDescription(`Opinionated preset package for modern TypeScript applications`),l.withSubcommands(Br)),Wr=n.fn(`runCli`)(function*(e,t){let[r,i]=c.splitWhere(e,e=>e===`--`),a=c.drop(i,1),o=r.find(e=>Vr.has(e));if(a.length>0&&o!==void 0&&!Hr.has(o))return yield*new ke({command:o});yield*l.runWith(Ur,{version:t})(r).pipe(n.provideService(j,a))}),Gr=n.gen(function*(){let e=yield*(yield*o.Stdio).args;yield*Wr(e,`0.38.0`)}).pipe(n.as(0),n.catchTag(`CommandFailed`,e=>n.succeed(e.exitCode)),n.catch(e=>n.service(Q).pipe(n.flatMap(t=>t.log.error(e.message)),n.as(s.ExitCode(1)))),n.provide(i.mergeAll(t.layer,rn.layer.pipe(i.provide(t.layer)),Q.layer,A.layer,W.layer,Vn.layer)));e.runMain(Gr,{teardown:(e,t)=>{if(r.isSuccess(e)){t(Number(e.value));return}a.defaultTeardown(e,t)}});export{};
111
+ `;return yield*F(n,`${r}${c}${s}`),`updated`}),ur=(e,t)=>n.gen(function*(){let r=yield*W;yield*(yield*Q).withSpinner(()=>n.gen(function*(){let n=yield*An(e);yield*r.addDevDependencies(t,e,{silent:!0,workspace:n})}),{failure:`Failed to install dependencies.`,start:`Installing dependencies...`,success:`Dependencies installed.`})});function dr(e,t,r){return n.gen(function*(){let i=yield*Q,a=yield*i.withSpinner(a=>n.gen(function*(){let n=yield*t.detect(e);for(let e of n.warnings)yield*i.log.warning(e);return n.active===null?(yield*a.message(`\`${t.config}\` not found, creating...`),yield*r,{created:!0,legacyConfig:null}):n.active.format===`ts`?(yield*a.message(`Found \`${t.config}\`, keeping existing config.`),{created:!1,legacyConfig:null}):(yield*a.message(`Found \`${n.active.file}\`, keeping existing config.`),{created:!1,legacyConfig:n.active.file})}),{failure:`Failed to set up ${t.name} config.`,start:`Setting up ${t.name} config...`,success:e=>e.created?`${t.name} config created successfully.`:`${t.name} config is ready.`});a.legacyConfig&&(yield*i.log.info(`Legacy \`${a.legacyConfig}\` was preserved during \`adamantite init\`. Run \`adamantite doctor\` and follow its findings to migrate it to the latest ${t.name} config.`))})}const fr=e=>`\`${e.script}\` is currently \`${e.command}\`; Adamantite would replace it with \`${B[e.script]}\`.`,pr=(e,t,r)=>n.gen(function*(){let i=yield*Q,a=yield*z(e),o=r.overwriteScripts?[]:He(a,t),s=new Set(o.map(e=>e.script)),c=t.filter(e=>!s.has(e));yield*i.withSpinner(()=>n.gen(function*(){if(c.length!==0){a.scripts??={};for(let e of c)a.scripts[e]=B[e];yield*ze(e,a)}}),{failure:"Failed to add scripts to `package.json`.",start:"Adding scripts to your `package.json`...",success:o.length===0?"Scripts added to your `package.json`":c.length===0?"Kept your existing `package.json` scripts.":"Scripts added to your `package.json`; conflicting scripts were kept."});let l=r.nonInteractive?"Use `--overwrite-scripts` to replace it.":"Re-run `adamantite init` and confirm overwriting to replace it.";for(let e of o)yield*i.log.warning(`Kept existing \`${e.script}\` script (\`${e.command}\`) instead of \`${B[e.script]}\`. ${l}`);return o.length>0&&(yield*i.log.info("Adamantite commands forward extra arguments after `--`, so custom flags can be kept, e.g. `adamantite monorepo -- --ignore-dependency tailwindcss`.")),c}),mr=(e,t)=>n.gen(function*(){let r=yield*Q;if(t){yield*h(Mn,n.forEach(e=>r.log.info(e)));return}yield*r.withSpinner(t=>n.gen(function*(){return(yield*Z.detect(e))?(yield*t.message(`\`${Z.config}\` found, updating...`),yield*Z.update(e),!1):(yield*t.message(`\`${Z.config}\` not found, creating...`),yield*Z.create(e),!0)}),{failure:`Failed to set up TypeScript config.`,start:`Setting up TypeScript config...`,success:e=>e?`\`${Z.config}\` created successfully`:`\`${Z.config}\` updated successfully`})}),hr=(e,t)=>n.gen(function*(){let r=yield*Q;t.includes(`vscode`)&&(yield*r.withSpinner(t=>n.gen(function*(){let n=yield*$.detect(e);return yield*t.message(`\`${$.config}\` ${n?`found, updating`:`not found, creating`}...`),yield*n?$.update(e):$.create(e),!n}),{failure:`Failed to set up VS Code config.`,start:`Checking for \`${$.config}\`...`,success:e=>`\`${$.config}\` ${e?`created`:`updated`} with Adamantite preset.`})),t.includes(`zed`)&&(yield*r.withSpinner(t=>n.gen(function*(){let n=yield*K.detect(e);return yield*t.message(`\`${K.config}\` ${n?`found, updating`:`not found, creating`}...`),yield*n?K.update(e):K.create(e),!n}),{failure:`Failed to set up Zed config.`,start:`Checking for \`${K.config}\`...`,success:e=>`\`${K.config}\` ${e?`created`:`updated`} with Adamantite preset.`}))}),gr=(e,t)=>n.gen(function*(){let r=yield*Q,i=e.includes(`zed`),a=e.includes(`vscode`);yield*r.withSpinner(e=>n.gen(function*(){return a&&(yield*e.message(`Installing VS Code extension...`),yield*$.extension(t)),!0}),{start:`Installing editor extensions...`,success:i&&!a?`Zed extensions require manual install.`:`Editor extensions installed successfully.`}).pipe(n.catchTag(`FailedToInstallExtension`,e=>n.gen(function*(){return yield*r.log.warning(`⚠️ ${e.message}`),yield*r.log.warning(`Please install it manually after setup completes.`),!1})),n.catchTag(`VscodeCliNotFound`,()=>n.gen(function*(){return yield*r.log.error(`VSCode CLI ('code' command) not found.`),yield*r.log.info(`To install it:`),yield*r.log.info(` 1. Open VS Code`),yield*r.log.info(` 2. Press Cmd+Shift+P (macOS) or Ctrl+Shift+P (Windows/Linux)`),yield*r.log.info(` 3. Run 'Shell Command: Install "code" command in PATH'`),!1}))),i&&(yield*r.log.info("Install the Zed `oxc` extension: zed://extension/oxc"))}),_r=(e,t,r)=>n.gen(function*(){let i=yield*Q,a=hn.files[0].path;yield*i.withSpinner(i=>n.gen(function*(){let n=yield*hn.detect(e);return yield*i.message(n?`\`${a}\` found, updating...`:`Creating \`${a}\`...`),yield*n?hn.update(e,{packageManager:t,scripts:r}):hn.create(e,{packageManager:t,scripts:r}),!n}),{failure:`Failed to set up GitHub Actions workflow.`,start:`Setting up GitHub Actions workflow...`,success:e=>`GitHub Actions workflow ${e?`created`:`updated`} successfully.`})}).pipe(n.catchTag([`FailedToCreateDirectory`,`FailedToParseFile`,`FailedToReadFile`,`FailedToWriteFile`,`PlatformError`],e=>n.gen(function*(){let t=yield*Q;yield*t.log.warning(`Could not set up the GitHub Actions workflow. ${e.message}`),yield*t.log.warning("Fix the reported problem and run `adamantite init` again, or create the workflow manually.")}))),vr=(e,t,r)=>n.gen(function*(){let i=yield*Q,a=yield*i.withSpinner(()=>lr(e,{packageManager:t,scripts:r}),{failure:`Failed to update AGENTS.md.`,start:`Updating AGENTS.md...`,success:`AGENTS.md check complete.`}).pipe(n.catchTag([`FailedToReadFile`,`FailedToWriteFile`],e=>n.gen(function*(){return yield*i.log.warning(`Could not update AGENTS.md. ${e.message} Adamantite will continue initialization.`),`failed`})));a!==`failed`&&a===`malformed`&&(yield*i.log.warning(`Could not update AGENTS.md because Adamantite markers are incomplete. Remove the stale ADAMANTITE marker and run adamantite init again.`))}),yr=[`check`,`fix`,`format`,`check:monorepo`,`fix:monorepo`,`analyze`],br=[`react`,`nextjs`,`vue`,`jest`,`vitest`,`node`,`antislop`],xr=[`vscode`,`zed`],Sr=n.fn(`validateInitOptions`)(function*(e,t){let n={agents:e.agents,editors:c.dedupe(e.editors),githubActions:e.githubActions,installExtensions:e.installExtensions,overwriteScripts:e.overwriteScripts,presets:c.dedupe(e.presets),scripts:c.dedupe(e.scripts),typescript:e.typescript};if(n.scripts.length===0)return yield*new k({reason:"Select at least one script with `--script <name>`."});let r=n.scripts.includes(`check`)||n.scripts.includes(`fix`);return(n.scripts.includes(`check:monorepo`)||n.scripts.includes(`fix:monorepo`))&&!t.isMonorepo?yield*new k({reason:`Monorepo scripts can only be selected in a detected monorepo.`}):n.presets.length>0&&!r?yield*new k({reason:"`--preset` requires the `check` or `fix` script."}):n.typescript&&!r?yield*new k({reason:"`--typescript` requires the `check` or `fix` script."}):n.installExtensions&&n.editors.length===0?yield*new k({reason:"`--install-extensions` requires at least one `--editor`."}):n.githubActions&&!qt(n.scripts)?yield*new k({reason:"`--github-actions` requires a CI-compatible script."}):n.githubActions&&t.nonInteractive&&!Be(t.packageManager)?yield*new k({reason:`\`--github-actions\` does not support the detected package manager \`${t.packageManager}\`. Use bun, deno, npm, pnpm, or yarn.`}):n}),Cr=u.Boolean(`non-interactive`).pipe(u.withDefault(!1),u.withDescription(`Configure without prompts; requires at least one --script`)),wr=u.Literals(`script`,yr).pipe(u.atMost(yr.length),u.withDescription(`Package script to configure; repeatable and required in non-interactive mode. Monorepo scripts require a detected monorepo`)),Tr=u.Literals(`preset`,br).pipe(u.atMost(br.length),u.withDescription(`Oxlint preset to configure; repeatable and requires --script check or fix`)),Er=u.Literals(`editor`,xr).pipe(u.atMost(xr.length),u.withDescription(`Editor to configure; may be specified multiple times`)),Dr=u.Boolean(`typescript`).pipe(u.withDefault(!1),u.withDescription(`Configure the TypeScript preset; requires --script check or fix`)),Or=u.Boolean(`install-extensions`).pipe(u.withDefault(!1),u.withDescription(`Install recommended extensions; requires at least one --editor`)),kr=u.Boolean(`github-actions`).pipe(u.withDefault(!1),u.withDescription(`Configure CI; requires a compatible script and bun, deno, npm, pnpm, or yarn`)),Ar=u.Boolean(`agents`).pipe(u.withDefault(!1),u.withDescription(`Add Adamantite guidance to AGENTS.md`)),jr=u.Boolean(`overwrite-scripts`).pipe(u.withDefault(!1),u.withDescription(`Replace existing package scripts that conflict with Adamantite's managed commands`)),Mr=n.fn(`collectInteractiveInitOptions`)(function*(e,t){let n=yield*Q,r=yield*n.multiselect({message:"Which scripts do you want to add to your `package.json`?",options:[{hint:`recommended`,label:`check - find issues and type errors using oxlint`,value:`check`},{hint:`recommended`,label:`fix - fix code issues using oxlint`,value:`fix`},{hint:`recommended`,label:`format - code formatting using oxfmt`,value:`format`},{disabled:!t,hint:t?void 0:`available for monorepo projects`,label:`check:monorepo - check for monorepo-specific issues using Sherif`,value:`check:monorepo`},{disabled:!t,hint:t?void 0:`available for monorepo projects`,label:`fix:monorepo - fix monorepo-specific issues using Sherif`,value:`fix:monorepo`},{label:`analyze - find unused dependencies, exports, and files using knip`,value:`analyze`}]}),i=He(yield*z(e),r),a=!1;if(i.length>0){for(let e of i)yield*n.log.warning(fr(e));a=yield*n.confirm({initialValue:!1,message:i.length===1?`Overwrite this existing script with Adamantite's command?`:`Overwrite these existing scripts with Adamantite's commands?`})}let o=r.includes(`check`)||r.includes(`fix`),s=[];o&&(s=yield*n.multiselect({message:`Which presets do you want to install? (core is always included)`,options:[{hint:`React correctness, JSX accessibility, and render performance rules`,label:`react`,value:`react`},{hint:`Next.js pitfalls around scripts, fonts, images, and document/head usage`,label:`next.js`,value:`nextjs`},{hint:`Vue 3 correctness rules and deprecated API detection`,label:`vue`,value:`vue`},{hint:`Jest test hygiene: focused/disabled tests, matcher and snapshot discipline`,label:`jest`,value:`jest`},{hint:`Vitest test hygiene: focused/disabled tests, matcher and snapshot discipline`,label:`vitest`,value:`vitest`},{hint:`Node.js callback and CommonJS pitfalls`,label:`node`,value:`node`},{hint:`Rejects low-signal escape hatches: unjustified assertions, unknown leaks, module mocks`,label:`antislop`,value:`antislop`}],required:!1}));let c=o?yield*n.confirm({initialValue:!0,message:t?"Adamantite provides a TypeScript preset to enforce strict type-safety. In a monorepo, each package's `tsconfig.json` must extend it. Would you like instructions on how to set it up?":`Adamantite provides a TypeScript preset to enforce strict type-safety. Would you like to use it?`}):!1,l=yield*n.multiselect({message:`Which editors do you want to configure? (optional)`,options:[{label:`VSCode / Cursor / Windsurf`,value:`vscode`},{label:`Zed`,value:`zed`}],required:!1}),u=l.length>0?yield*n.confirm({initialValue:!0,message:`Do you want to install the recommended editor extensions?`}):!1,d=qt(r)?yield*n.confirm({message:`Do you want to add a GitHub Actions workflow to run checks in CI?`}):!1;return{agents:yield*n.confirm({initialValue:!0,message:`Add Adamantite guidance to AGENTS.md so coding agents know how to run project checks?`}),editors:l,githubActions:d,installExtensions:u,overwriteScripts:a,presets:s,scripts:r,typescript:c}});var Nr=l.make(`init`,{agents:Ar,editors:Er,githubActions:kr,installExtensions:Or,nonInteractive:Cr,overwriteScripts:jr,presets:Tr,scripts:wr,typescript:Dr}).pipe(l.withDescription(`Initialize Adamantite in the current directory. Setup flags require --non-interactive; omitted boolean setup flags are disabled`),l.withExamples([{command:`adamantite init --non-interactive --script check`,description:`Configure linting without prompts`},{command:`adamantite init --non-interactive --script check --script format --preset react --editor vscode --typescript --install-extensions --github-actions --agents`,description:`Configure a React project with VS Code, TypeScript, CI, and agent guidance`},{command:`adamantite init --non-interactive --script check:monorepo`,description:`Configure monorepo checks in a detected monorepo`}]),l.withHandler(e=>n.gen(function*(){let t=S.cwd(),n=yield*Q;yield*Gn(),yield*n.intro(`💠 adamantite init`);let r=yield*(yield*W).detectPackageManager(t);if(!r)return yield*new De({});if(r.warnings?.length)for(let e of r.warnings)yield*n.log.warning(e);yield*n.log.info(`Detected package manager: ${r.name}`);let i=yield*An(t);if(i&&(yield*n.log.info(`We've detected a monorepo setup in your project.`)),!e.nonInteractive&&c.some([e.scripts.length>0,e.presets.length>0,e.editors.length>0,e.typescript,e.installExtensions,e.githubActions,e.agents,e.overwriteScripts],_.isTruthy))return yield*new k({reason:"Setup flags require `--non-interactive`."});let a=e.nonInteractive?e:yield*Mr(t,i),o=yield*Sr(a,{isMonorepo:i,nonInteractive:e.nonInteractive,packageManager:r.name}),s=o.scripts,l=o.presets,u=o.editors,d=o.typescript,f=o.installExtensions,p=o.githubActions,m=o.agents,h=s.includes(`check`)||s.includes(`fix`),g=s.includes(`format`),v=s.includes(`check:monorepo`)||s.includes(`fix:monorepo`),ee=s.includes(`analyze`),y=[`adamantite`];h&&y.push(`${U.name}@${U.version}`,`${En.name}@${En.version}`),g&&y.push(`${q.name}@${q.version}`),v&&y.push(`${J.name}@${J.version}`),ee&&y.push(`${V.name}@${V.version}`),yield*ur(t,y),g&&(yield*dr(t,q,q.create(t))),h&&(yield*dr(t,U,U.create(t,l))),ee&&(yield*dr(t,V,V.create(t)));let b=yield*pr(t,s,{nonInteractive:e.nonInteractive,overwriteScripts:o.overwriteScripts});if(m&&(yield*vr(t,r.name,b)),d&&(yield*mr(t,i)),yield*hr(t,u),f&&(yield*gr(u,s)),p){let e=r.name;Be(e)?yield*_r(t,e,s):yield*n.log.warning(`Skipping GitHub Actions setup: \`${e}\` is not a supported package manager for CI workflow generation.`)}yield*n.log.success(`Your project is now configured`),yield*n.outro(`💠 Adamantite initialized successfully!`)}).pipe(n.catchTags({OperationCancelled:()=>n.gen(function*(){yield*(yield*Q).cancel(`You've cancelled the initialization process.`)})}))));const Pr=u.Boolean(`fix`).pipe(u.withDefault(!1),u.withDescription(`Automatically fix issues`));var Fr=l.make(`monorepo`,{fix:Pr}).pipe(l.withDescription(`Find and fix monorepo-specific issues using Sherif`),l.withHandler(({fix:e})=>n.gen(function*(){let t=yield*j,n=yield*A,r=e?[`--fix`,...t]:[...t],i=yield*n.run({args:r,command:J.name,stdin:`inherit`});i!==s.ExitCode(0)&&(yield*new O({command:J.name,exitCode:i}))})));const Ir=[U,En,q,J,V];function Lr(e,t){return c.filterMap(Ir,n=>{if(t.has(n.name))return C.failVoid;let r=e.devDependencies?.[n.name]??e.dependencies?.[n.name];return r&&Re(r)!==n.version?C.succeed({currentVersion:r,name:n.name,targetVersion:n.version}):C.failVoid})}var Rr=l.make(`update`).pipe(l.withDescription(`Update Adamantite-managed dependencies and report setup findings`),l.withHandler(()=>n.gen(function*(){let e=S.cwd(),t=yield*Q,n=yield*W;yield*Gn(),yield*t.intro(`💠 adamantite update`);let r=yield*z(e),i=yield*Ln(e,r),a=i.packageActions,o=new Set(a.map(e=>e.package)),s=[...a.map(e=>({currentVersion:e.type===`install_package`?`not installed`:e.currentVersion,name:e.package,targetVersion:e.targetVersion})),...Lr(r,o)];if(s.length>0){yield*t.log.info(`The following dependencies will be updated:`);for(let e of s)yield*t.log.info(` ${e.name}: ${e.currentVersion} → ${e.targetVersion}`);yield*t.withSpinner(()=>n.addDevDependencies(s.map(e=>`${e.name}@${e.targetVersion}`),e,{silent:!0}),{failure:`Failed to update dependencies`,start:`Updating dependencies...`,success:`Dependencies updated successfully`}),yield*t.log.success(`Dependencies updated successfully.`)}let c=s.length===0?i:yield*Ln(e);for(let e of c.warnings)yield*t.log.warning(e);let l=c.findings;return l.length>0&&(yield*Un(l),yield*t.log.info("Run `adamantite doctor` to get the combined Markdown repair prompt.")),s.length===0&&l.length===0?(yield*t.log.success(`No changes needed.`),`no-changes`):`success`}).pipe(n.tapError(()=>n.gen(function*(){yield*(yield*Q).outro(`❌ Update failed`)})),n.tap(e=>n.gen(function*(){yield*(yield*Q).outro(e===`no-changes`?`✅ Adamantite is already up to date.`:`✅ Update completed successfully!`)})))));const zr=[lt,Lt,$n,nr,Fr],Br=[lt,Lt,Jn,$n,nr,Nr,Fr,Rr],Vr=new Set(Br.map(e=>e.name)),Hr=new Set(zr.map(e=>e.name)),Ur=l.make(`adamantite`).pipe(l.withDescription(`Opinionated preset package for modern TypeScript applications`),l.withSubcommands(Br)),Wr=n.fn(`runCli`)(function*(e,t){let[r,i]=c.splitWhere(e,e=>e===`--`),a=c.drop(i,1),o=r.find(e=>Vr.has(e));if(a.length>0&&o!==void 0&&!Hr.has(o))return yield*new ke({command:o});yield*l.runWith(Ur,{version:t})(r).pipe(n.provideService(j,a))}),Gr=n.gen(function*(){let e=yield*(yield*o.Stdio).args;yield*Wr(e,`0.39.0`)}).pipe(n.as(0),n.catchTag(`CommandFailed`,e=>n.succeed(e.exitCode)),n.catch(e=>n.service(Q).pipe(n.flatMap(t=>t.log.error(e.message)),n.as(s.ExitCode(1)))),n.provide(i.mergeAll(t.layer,rn.layer.pipe(i.provide(t.layer)),Q.layer,A.layer,W.layer,Vn.layer)));e.runMain(Gr,{teardown:(e,t)=>{if(r.isSuccess(e)){t(Number(e.value));return}a.defaultTeardown(e,t)}});export{};
@@ -1,7 +1,7 @@
1
1
  # anti-slop license
2
2
 
3
3
  The bundled `plugin.mjs` is a build of
4
- [anti-slop](https://github.com/dmmulroy/anti-slop) at commit 446268e5d15baa968eaec669ff65358d36ae6259,
4
+ [anti-slop](https://github.com/dmmulroy/anti-slop) at commit e8c4880471b23ab7f216fba7b27d173a6ef07d4c,
5
5
  with its dependencies (MIT) inlined.
6
6
 
7
7
  MIT License
@@ -1,5 +1,5 @@
1
1
  // Vendored build of the anti-slop oxlint plugin.
2
- // Source: https://github.com/dmmulroy/anti-slop (MIT) at commit 446268e5d15baa968eaec669ff65358d36ae6259.
2
+ // Source: https://github.com/dmmulroy/anti-slop (MIT) at commit e8c4880471b23ab7f216fba7b27d173a6ef07d4c.
3
3
  // Its dependencies (MIT) are inlined so this file is self-contained.
4
4
  // See license.md for the full license text.
5
5
  //
@@ -433,6 +433,182 @@ const noConditionalEmptyObjectSpreadRule = defineRule({
433
433
  }
434
434
  });
435
435
  //#endregion
436
+ //#region src/shared/lexical-type-parameters.ts
437
+ function isNode$1(value) {
438
+ return typeof value === "object" && value !== null && "type" in value && typeof value.type === "string";
439
+ }
440
+ function collectInferTypeParameterNames(node, visitorKeys, names) {
441
+ if (node.type === "TSInferType") names.add(node.typeParameter.name.name);
442
+ const record = node;
443
+ for (const key of visitorKeys[node.type] ?? []) {
444
+ const value = record[key];
445
+ if (isNode$1(value)) {
446
+ collectInferTypeParameterNames(value, visitorKeys, names);
447
+ continue;
448
+ }
449
+ if (!Array.isArray(value)) continue;
450
+ for (const child of value) if (isNode$1(child)) collectInferTypeParameterNames(child, visitorKeys, names);
451
+ }
452
+ }
453
+ /** Collect type binders that are in scope at a node and can shadow module aliases. */
454
+ function lexicalTypeParameterNames(node, visitorKeys) {
455
+ const names = /* @__PURE__ */ new Set();
456
+ let descendant = node;
457
+ let current = node;
458
+ while (current !== null && current.type !== "Program") {
459
+ if ("typeParameters" in current) for (const parameter of current.typeParameters?.params ?? []) names.add(parameter.name.name);
460
+ if (current.type === "TSMappedType" && (descendant === current.nameType || descendant === current.typeAnnotation)) names.add(current.key.name);
461
+ if (current.type === "TSConditionalType" && descendant === current.trueType) collectInferTypeParameterNames(current.extendsType, visitorKeys, names);
462
+ descendant = current;
463
+ current = current.parent;
464
+ }
465
+ return names;
466
+ }
467
+ //#endregion
468
+ //#region src/shared/type-alias-resolution.ts
469
+ const environmentsByProgram = /* @__PURE__ */ new WeakMap();
470
+ function isNode(value) {
471
+ return typeof value === "object" && value !== null && "type" in value && typeof value.type === "string";
472
+ }
473
+ function enclosingTypeScope(node) {
474
+ let current = node.parent;
475
+ while (current !== null) {
476
+ if (current.type === "Program" || current.type === "BlockStatement" || current.type === "TSModuleBlock" || current.type === "StaticBlock" || current.type === "SwitchStatement") return current;
477
+ current = current.parent;
478
+ }
479
+ return node;
480
+ }
481
+ function declaredTypeBinding(node) {
482
+ if (node.type === "TSTypeAliasDeclaration") return {
483
+ alias: node,
484
+ name: node.id.name
485
+ };
486
+ if (node.type === "TSInterfaceDeclaration" || node.type === "TSEnumDeclaration" || node.type === "ClassDeclaration" || node.type === "ClassExpression") return node.id === null ? null : {
487
+ alias: null,
488
+ name: node.id.name
489
+ };
490
+ if (node.type === "ImportSpecifier" || node.type === "ImportDefaultSpecifier" || node.type === "ImportNamespaceSpecifier") return {
491
+ alias: null,
492
+ name: node.local.name
493
+ };
494
+ return null;
495
+ }
496
+ function collectTypeBindings(node, visitorKeys, bindingsByName, aliases) {
497
+ const declared = declaredTypeBinding(node);
498
+ if (declared !== null) {
499
+ const bindings = bindingsByName.get(declared.name) ?? [];
500
+ bindings.push({
501
+ ...declared,
502
+ scope: enclosingTypeScope(node)
503
+ });
504
+ bindingsByName.set(declared.name, bindings);
505
+ if (declared.alias !== null) aliases.push(declared.alias);
506
+ }
507
+ const fields = node;
508
+ for (const key of visitorKeys[node.type] ?? []) {
509
+ const value = fields[key];
510
+ if (isNode(value)) {
511
+ collectTypeBindings(value, visitorKeys, bindingsByName, aliases);
512
+ continue;
513
+ }
514
+ if (!Array.isArray(value)) continue;
515
+ for (const child of value) if (isNode(child)) collectTypeBindings(child, visitorKeys, bindingsByName, aliases);
516
+ }
517
+ }
518
+ /** Collect every lexical type alias and competing type binding in a program. */
519
+ function createTypeAliasEnvironment(program, visitorKeys) {
520
+ const cached = environmentsByProgram.get(program);
521
+ if (cached !== void 0) return cached;
522
+ const bindingsByName = /* @__PURE__ */ new Map();
523
+ const aliases = [];
524
+ collectTypeBindings(program, visitorKeys, bindingsByName, aliases);
525
+ const environment = {
526
+ aliases,
527
+ bindingsByName,
528
+ visitorKeys
529
+ };
530
+ environmentsByProgram.set(program, environment);
531
+ return environment;
532
+ }
533
+ function ancestorDistance(ancestor, node) {
534
+ let current = node;
535
+ let distance = 0;
536
+ while (current !== null) {
537
+ if (current === ancestor) return distance;
538
+ current = current.parent;
539
+ distance += 1;
540
+ }
541
+ return null;
542
+ }
543
+ function nearestTypeBindings(name, use, environment) {
544
+ const candidates = environment.bindingsByName.get(name) ?? [];
545
+ let nearestDistance = Number.POSITIVE_INFINITY;
546
+ let nearest = [];
547
+ for (const candidate of candidates) {
548
+ const distance = ancestorDistance(candidate.scope, use);
549
+ if (distance === null || distance > nearestDistance) continue;
550
+ if (distance === nearestDistance) {
551
+ nearest.push(candidate);
552
+ continue;
553
+ }
554
+ nearestDistance = distance;
555
+ nearest = [candidate];
556
+ }
557
+ return nearest;
558
+ }
559
+ /** Resolve the nearest visible alias with this name, respecting lexical shadowing. */
560
+ function visibleTypeAlias(name, use, environment) {
561
+ if (lexicalTypeParameterNames(use, environment.visitorKeys).has(name)) return null;
562
+ const bindings = nearestTypeBindings(name, use, environment);
563
+ return bindings.length === 1 ? bindings[0]?.alias ?? null : null;
564
+ }
565
+ /** Return whether a local declaration shadows a built-in type at this use. */
566
+ function hasVisibleTypeBinding(name, use, environment) {
567
+ return lexicalTypeParameterNames(use, environment.visitorKeys).has(name) || nearestTypeBindings(name, use, environment).length > 0;
568
+ }
569
+ function typeReferenceName$3(type) {
570
+ return type.typeName.type === "Identifier" ? type.typeName.name : null;
571
+ }
572
+ function aliasSubstitutions(alias, reference, base) {
573
+ const parameters = alias.typeParameters?.params ?? [];
574
+ const arguments_ = reference.typeArguments?.params ?? [];
575
+ const next = new Map(base);
576
+ for (const [index, parameter] of parameters.entries()) {
577
+ const explicitArgument = arguments_[index];
578
+ const argument = explicitArgument ?? parameter.default;
579
+ if (argument === null || argument === void 0) return null;
580
+ const argumentSubstitutions = explicitArgument === void 0 ? next : base;
581
+ next.set(parameter.name.name, {
582
+ type: argument,
583
+ substitutions: new Map(argumentSubstitutions)
584
+ });
585
+ }
586
+ return next;
587
+ }
588
+ /** Match a type after resolving visible aliases and substituting their type parameters. */
589
+ function resolvedTypeMatches(type, environment, matcher) {
590
+ const evaluate = (current, substitutions, resolvingAliases) => {
591
+ if (current.type === "TSTypeReference") {
592
+ const name = typeReferenceName$3(current);
593
+ if (name !== null) {
594
+ const substitution = substitutions.get(name);
595
+ if (substitution !== void 0 && !current.typeArguments?.params.length) return evaluate(substitution.type, substitution.substitutions, resolvingAliases);
596
+ const alias = visibleTypeAlias(name, current, environment);
597
+ if (alias !== null && !resolvingAliases.has(alias)) {
598
+ const nextSubstitutions = aliasSubstitutions(alias, current, substitutions);
599
+ if (nextSubstitutions !== null) {
600
+ const nextResolving = new Set(resolvingAliases);
601
+ nextResolving.add(alias);
602
+ return evaluate(alias.typeAnnotation, nextSubstitutions, nextResolving);
603
+ }
604
+ }
605
+ }
606
+ }
607
+ return matcher(current, (child) => evaluate(child, substitutions, resolvingAliases));
608
+ };
609
+ return evaluate(type, /* @__PURE__ */ new Map(), /* @__PURE__ */ new Set());
610
+ }
611
+ //#endregion
436
612
  //#region src/shared/dictionary-types.ts
437
613
  const BUILT_INS = /* @__PURE__ */ new Set([
438
614
  "Record",
@@ -453,48 +629,25 @@ const TRANSPARENT_WRAPPERS = /* @__PURE__ */ new Set([
453
629
  function declaredStatement(statement) {
454
630
  return statement.type === "ExportNamedDeclaration" || statement.type === "ExportDefaultDeclaration" ? statement.declaration ?? null : statement;
455
631
  }
456
- function createTypeEnvironment(program) {
457
- const aliases = /* @__PURE__ */ new Map();
632
+ function createTypeEnvironment(program, visitorKeys) {
458
633
  const interfaces = /* @__PURE__ */ new Map();
459
- const shadowedBuiltIns = /* @__PURE__ */ new Set();
460
634
  for (const statement of program.body) {
461
635
  const declaration = declaredStatement(statement);
462
- if (declaration?.type === "ImportDeclaration") {
463
- for (const specifier of declaration.specifiers) if (BUILT_INS.has(specifier.local.name)) shadowedBuiltIns.add(specifier.local.name);
464
- continue;
465
- }
466
- if (declaration?.type === "TSTypeAliasDeclaration") {
467
- if (aliases.get(declaration.id.name) === void 0) aliases.set(declaration.id.name, declaration);
468
- else shadowedBuiltIns.add(declaration.id.name);
469
- if (BUILT_INS.has(declaration.id.name)) shadowedBuiltIns.add(declaration.id.name);
470
- continue;
471
- }
472
- if (declaration?.type === "TSInterfaceDeclaration") {
473
- const declarations = interfaces.get(declaration.id.name) ?? [];
474
- declarations.push(declaration);
475
- interfaces.set(declaration.id.name, declarations);
476
- if (BUILT_INS.has(declaration.id.name)) shadowedBuiltIns.add(declaration.id.name);
477
- continue;
478
- }
479
- if (declaration?.type === "TSEnumDeclaration") {
480
- if (BUILT_INS.has(declaration.id.name)) shadowedBuiltIns.add(declaration.id.name);
481
- continue;
482
- }
483
- if ((declaration?.type === "ClassDeclaration" || declaration?.type === "FunctionDeclaration") && declaration.id !== null) {
484
- if (BUILT_INS.has(declaration.id.name)) shadowedBuiltIns.add(declaration.id.name);
485
- }
636
+ if (declaration?.type !== "TSInterfaceDeclaration") continue;
637
+ const declarations = interfaces.get(declaration.id.name) ?? [];
638
+ declarations.push(declaration);
639
+ interfaces.set(declaration.id.name, declarations);
486
640
  }
487
641
  return {
488
- aliases,
489
642
  interfaces,
490
- shadowedBuiltIns
643
+ typeAliases: createTypeAliasEnvironment(program, visitorKeys)
491
644
  };
492
645
  }
493
646
  function typeReferenceName$2(type) {
494
647
  return type.typeName.type === "Identifier" ? type.typeName.name : null;
495
648
  }
496
- function isBuiltIn(name, environment) {
497
- return BUILT_INS.has(name) && !environment.shadowedBuiltIns.has(name);
649
+ function isBuiltIn(name, use, environment) {
650
+ return BUILT_INS.has(name) && !hasVisibleTypeBinding(name, use, environment.typeAliases);
498
651
  }
499
652
  function isUnappliedReferenceTo(type, name) {
500
653
  const unwrapped = unwrapTransparentType(type);
@@ -556,7 +709,7 @@ function unsafeDirectValue(type, environment, substitutions, resolvingAliases) {
556
709
  if (unwrapped.type !== "TSTypeReference") return null;
557
710
  const name = typeReferenceName$2(unwrapped);
558
711
  if (name === null) return null;
559
- if (TRANSPARENT_WRAPPERS.has(name) && isBuiltIn(name, environment)) {
712
+ if (TRANSPARENT_WRAPPERS.has(name) && isBuiltIn(name, unwrapped, environment)) {
560
713
  const wrapped = unwrapped.typeArguments?.params[0];
561
714
  return wrapped === void 0 ? null : unsafeDirectValue(wrapped, environment, substitutions, resolvingAliases);
562
715
  }
@@ -564,8 +717,8 @@ function unsafeDirectValue(type, environment, substitutions, resolvingAliases) {
564
717
  if (substitution !== void 0) return isUnappliedReferenceTo(substitution, name) ? null : unsafeDirectValue(substitution, environment, substitutions, resolvingAliases);
565
718
  const interfaceDeclarations = environment.interfaces.get(name);
566
719
  if (interfaceDeclarations !== void 0) return isEffectivelyEmptyInterface(interfaceDeclarations) ? "empty-object" : null;
567
- const alias = environment.aliases.get(name);
568
- if (alias === void 0 || resolvingAliases.has(name)) return null;
720
+ const alias = visibleTypeAlias(name, unwrapped, environment.typeAliases);
721
+ if (alias === null || resolvingAliases.has(name)) return null;
569
722
  const nextSubstitutions = aliasSubstitution(alias, unwrapped, substitutions);
570
723
  if (nextSubstitutions === null) return null;
571
724
  const nextResolving = new Set(resolvingAliases);
@@ -587,23 +740,23 @@ function dictionaryValueTypes(type, environment, substitutions, resolvingAliases
587
740
  if (name === null) return [];
588
741
  const substitution = substitutions.get(name);
589
742
  if (substitution !== void 0) return isUnappliedReferenceTo(substitution, name) ? [] : dictionaryValueTypes(substitution, environment, substitutions, resolvingAliases);
590
- if (TRANSPARENT_WRAPPERS.has(name) && isBuiltIn(name, environment)) {
743
+ if (TRANSPARENT_WRAPPERS.has(name) && isBuiltIn(name, unwrapped, environment)) {
591
744
  const wrapped = unwrapped.typeArguments?.params[0];
592
745
  return wrapped === void 0 ? [] : dictionaryValueTypes(wrapped, environment, substitutions, resolvingAliases);
593
746
  }
594
- if (name === "Record" && isBuiltIn(name, environment)) {
747
+ if (name === "Record" && isBuiltIn(name, unwrapped, environment)) {
595
748
  const value = unwrapped.typeArguments?.params[1] ?? null;
596
749
  return value === null ? [] : [{
597
750
  type: value,
598
751
  substitutions
599
752
  }];
600
753
  }
601
- if ((name === "Pick" || name === "Omit") && isBuiltIn(name, environment)) {
754
+ if ((name === "Pick" || name === "Omit") && isBuiltIn(name, unwrapped, environment)) {
602
755
  const source = unwrapped.typeArguments?.params[0];
603
756
  return source === void 0 ? [] : dictionaryValueTypes(source, environment, substitutions, resolvingAliases);
604
757
  }
605
- const alias = environment.aliases.get(name);
606
- if (alias === void 0 || resolvingAliases.has(name)) return [];
758
+ const alias = visibleTypeAlias(name, unwrapped, environment.typeAliases);
759
+ if (alias === null || resolvingAliases.has(name)) return [];
607
760
  const nextSubstitutions = aliasSubstitution(alias, unwrapped, substitutions);
608
761
  if (nextSubstitutions === null) return [];
609
762
  const nextResolving = new Set(resolvingAliases);
@@ -627,9 +780,6 @@ function classifyUnsafeDictionary(type, environment) {
627
780
  }
628
781
  return null;
629
782
  }
630
- function resolvesToDictionary(type, environment, substitutions, resolvingAliases) {
631
- return dictionaryValueTypes(type, environment, substitutions, resolvingAliases).length > 0;
632
- }
633
783
  function classifyWideningTarget(type, environment) {
634
784
  const unwrapped = unwrapTransparentType(type);
635
785
  if (unwrapped.type === "TSUnknownKeyword") return { kind: "unknown" };
@@ -639,31 +789,40 @@ function classifyWideningTarget(type, environment) {
639
789
  if (unwrapped.type !== "TSTypeReference") return null;
640
790
  const name = typeReferenceName$2(unwrapped);
641
791
  if (name === null) return null;
642
- if (TRANSPARENT_WRAPPERS.has(name) && isBuiltIn(name, environment)) {
792
+ if (TRANSPARENT_WRAPPERS.has(name) && isBuiltIn(name, unwrapped, environment)) {
643
793
  const wrapped = unwrapped.typeArguments?.params[0];
644
794
  return wrapped === void 0 ? null : classifyWideningTarget(wrapped, environment);
645
795
  }
646
- if (name === "Record" && isBuiltIn(name, environment)) return { kind: "open dictionary" };
647
- const alias = environment.aliases.get(name);
648
- if (alias === void 0) return null;
796
+ if (name === "Record" && isBuiltIn(name, unwrapped, environment)) return hasBroadRecordKey(unwrapped, environment, /* @__PURE__ */ new Map()) ? { kind: "open dictionary" } : null;
797
+ const alias = visibleTypeAlias(name, unwrapped, environment.typeAliases);
798
+ if (alias === null) return null;
649
799
  if ((alias.typeParameters?.params.length ?? 0) > 0) {
650
800
  const substitutions = aliasSubstitution(alias, unwrapped, /* @__PURE__ */ new Map());
651
- return substitutions !== null && resolvesToDictionary(alias.typeAnnotation, environment, substitutions, /* @__PURE__ */ new Set([name])) ? { kind: "generic container" } : null;
801
+ return (substitutions === null ? null : classifyAliasBroadTarget(alias.typeAnnotation, environment, substitutions, /* @__PURE__ */ new Set([name])))?.kind === "open dictionary" ? { kind: "generic container" } : null;
652
802
  }
653
803
  const substitutions = aliasSubstitution(alias, unwrapped, /* @__PURE__ */ new Map());
654
804
  if (substitutions === null) return null;
655
805
  return classifyAliasBroadTarget(alias.typeAnnotation, environment, substitutions, /* @__PURE__ */ new Set([name]));
656
806
  }
657
- function isBroadMappedKey(type, environment, substitutions) {
807
+ function hasBroadRecordKey(type, environment, substitutions) {
808
+ const key = type.typeArguments?.params[0];
809
+ return key === void 0 || isBroadMappedKey(key, environment, substitutions);
810
+ }
811
+ function isBroadMappedKey(type, environment, substitutions, visitedAliases = /* @__PURE__ */ new Set()) {
658
812
  const unwrapped = unwrapTransparentType(type);
659
813
  if (unwrapped.type === "TSStringKeyword" || unwrapped.type === "TSNumberKeyword" || unwrapped.type === "TSSymbolKeyword") return true;
660
- if (unwrapped.type === "TSUnionType") return unwrapped.types.every((member) => isBroadMappedKey(member, environment, substitutions));
814
+ if (unwrapped.type === "TSUnionType") return unwrapped.types.some((member) => isBroadMappedKey(member, environment, substitutions, visitedAliases));
661
815
  if (unwrapped.type !== "TSTypeReference") return false;
662
816
  const name = typeReferenceName$2(unwrapped);
663
817
  if (name === null) return false;
664
818
  const substitution = substitutions.get(name);
665
- if (substitution !== void 0 && !isUnappliedReferenceTo(substitution, name)) return isBroadMappedKey(substitution, environment, substitutions);
666
- return name === "PropertyKey" && isBuiltIn(name, environment);
819
+ if (substitution !== void 0 && !isUnappliedReferenceTo(substitution, name)) return isBroadMappedKey(substitution, environment, substitutions, visitedAliases);
820
+ if (name === "PropertyKey" && isBuiltIn(name, unwrapped, environment)) return true;
821
+ const alias = visibleTypeAlias(name, unwrapped, environment.typeAliases);
822
+ if (alias === null || (alias.typeParameters?.params.length ?? 0) > 0 || visitedAliases.has(name)) return false;
823
+ const nextVisited = new Set(visitedAliases);
824
+ nextVisited.add(name);
825
+ return isBroadMappedKey(alias.typeAnnotation, environment, substitutions, nextVisited);
667
826
  }
668
827
  function classifyAliasBroadTarget(type, environment, substitutions, resolvingAliases) {
669
828
  const unwrapped = unwrapTransparentType(type);
@@ -676,13 +835,13 @@ function classifyAliasBroadTarget(type, environment, substitutions, resolvingAli
676
835
  if (name === null) return null;
677
836
  const substitution = substitutions.get(name);
678
837
  if (substitution !== void 0) return isUnappliedReferenceTo(substitution, name) ? null : classifyAliasBroadTarget(substitution, environment, substitutions, resolvingAliases);
679
- if (TRANSPARENT_WRAPPERS.has(name) && isBuiltIn(name, environment)) {
838
+ if (TRANSPARENT_WRAPPERS.has(name) && isBuiltIn(name, unwrapped, environment)) {
680
839
  const wrapped = unwrapped.typeArguments?.params[0];
681
840
  return wrapped === void 0 ? null : classifyAliasBroadTarget(wrapped, environment, substitutions, resolvingAliases);
682
841
  }
683
- if (name === "Record" && isBuiltIn(name, environment)) return { kind: "open dictionary" };
684
- const alias = environment.aliases.get(name);
685
- if (alias === void 0 || resolvingAliases.has(name)) return null;
842
+ if (name === "Record" && isBuiltIn(name, unwrapped, environment)) return hasBroadRecordKey(unwrapped, environment, substitutions) ? { kind: "open dictionary" } : null;
843
+ const alias = visibleTypeAlias(name, unwrapped, environment.typeAliases);
844
+ if (alias === null || resolvingAliases.has(name)) return null;
686
845
  const nextSubstitutions = aliasSubstitution(alias, unwrapped, substitutions);
687
846
  if (nextSubstitutions === null) return null;
688
847
  const nextResolving = new Set(resolvingAliases);
@@ -696,6 +855,31 @@ function isKnownEvidenceExpression(expression) {
696
855
  return current.type === "ArrayExpression" || current.type === "ArrowFunctionExpression" || current.type === "ClassExpression" || current.type === "FunctionExpression" || current.type === "NewExpression" || current.type === "Literal" || current.type === "TemplateLiteral" || current.type === "UnaryExpression";
697
856
  }
698
857
  //#endregion
858
+ //#region src/shared/function-parameters.ts
859
+ /** Return whether a type is or contains TypeScript's absorbing unknown top type. */
860
+ function containsUnknownType(type) {
861
+ if (type.type === "TSUnknownKeyword") return true;
862
+ if (type.type === "TSParenthesizedType") return containsUnknownType(type.typeAnnotation);
863
+ return type.type === "TSUnionType" && type.types.some(containsUnknownType);
864
+ }
865
+ /** Return the TypeScript annotation attached to a function parameter or its wrapped binding. */
866
+ function functionParameterTypeAnnotation(parameter) {
867
+ if (parameter.type === "TSParameterProperty") return functionParameterTypeAnnotation(parameter.parameter);
868
+ if (parameter.type === "RestElement") return parameter.typeAnnotation ?? functionParameterTypeAnnotation(parameter.argument);
869
+ if (parameter.type === "AssignmentPattern") return parameter.typeAnnotation ?? functionParameterTypeAnnotation(parameter.left);
870
+ return parameter.typeAnnotation;
871
+ }
872
+ /** Return only a function parameter's local binding, excluding its annotation and default value. */
873
+ function functionParameterBindingName(parameter, sourceCode) {
874
+ if (parameter.type === "TSParameterProperty") return functionParameterBindingName(parameter.parameter, sourceCode);
875
+ if (parameter.type === "AssignmentPattern") return functionParameterBindingName(parameter.left, sourceCode);
876
+ if (parameter.type === "RestElement") return functionParameterBindingName(parameter.argument, sourceCode);
877
+ if (parameter.type === "Identifier") return parameter.name;
878
+ const sourceText = sourceCode.getText(parameter);
879
+ const annotationStart = parameter.typeAnnotation?.start;
880
+ return annotationStart === void 0 ? sourceText : sourceText.slice(0, annotationStart - parameter.start).trimEnd();
881
+ }
882
+ //#endregion
699
883
  //#region src/rules/no-known-value-widening.ts
700
884
  function unwrapExpression(expression) {
701
885
  let current = expression;
@@ -730,6 +914,61 @@ function hasKnownEvidence(sourceCode, expression, visitedVariables = /* @__PURE_
730
914
  visitedVariables.add(variable);
731
915
  return hasKnownEvidence(sourceCode, declarator.init, visitedVariables);
732
916
  }
917
+ function isFunctionExpression(node) {
918
+ return node.type === "ArrowFunctionExpression" || node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "TSDeclareFunction" || node.type === "TSEmptyBodyFunctionExpression";
919
+ }
920
+ function localFunctionForCall(sourceCode, callee) {
921
+ const unwrapped = unwrapExpression(callee);
922
+ if (isFunctionExpression(unwrapped)) return unwrapped;
923
+ if (unwrapped.type !== "Identifier") return null;
924
+ const variable = resolveVariable$2(sourceCode, unwrapped);
925
+ if (variable === null || variable.defs.length !== 1) return null;
926
+ const [definition] = variable.defs;
927
+ if (definition === void 0) return null;
928
+ if (definition.type === "FunctionName" && isFunctionExpression(definition.node)) return definition.node;
929
+ if (definition.type !== "Variable" || definition.node.type !== "VariableDeclarator") return null;
930
+ const initializer = definition.node.init;
931
+ if (initializer === null) return null;
932
+ const unwrappedInitializer = unwrapExpression(initializer);
933
+ return isFunctionExpression(unwrappedInitializer) ? unwrappedInitializer : null;
934
+ }
935
+ function variableTypeAnnotation(sourceCode, variable) {
936
+ if (variable.defs.length !== 1) return null;
937
+ const [definition] = variable.defs;
938
+ if (definition === void 0) return null;
939
+ if (definition.type === "Variable" && definition.node.type === "VariableDeclarator" && definition.node.id.type === "Identifier") return definition.node.id.typeAnnotation ?? null;
940
+ if (definition.type !== "Parameter" || !isFunctionExpression(definition.node)) return null;
941
+ const parameter = definition.node.params.find((candidate) => functionParameterBindingName(candidate, sourceCode) === variable.name);
942
+ return parameter === void 0 ? null : functionParameterTypeAnnotation(parameter) ?? null;
943
+ }
944
+ function hasInformativeType(type, environment) {
945
+ return classifyUnsafeDictionaryValue(type, environment) === null;
946
+ }
947
+ function hasKnownCallArgumentEvidence(sourceCode, expression, environment, visitedVariables = /* @__PURE__ */ new Set()) {
948
+ if (expression.type === "ParenthesizedExpression" || expression.type === "TSNonNullExpression") return hasKnownCallArgumentEvidence(sourceCode, expression.expression, environment, visitedVariables);
949
+ if (expression.type === "TSAsExpression" || expression.type === "TSTypeAssertion") return hasInformativeType(expression.typeAnnotation, environment);
950
+ if (expression.type === "TSSatisfiesExpression") return hasKnownCallArgumentEvidence(sourceCode, expression.expression, environment, visitedVariables);
951
+ if (expression.type === "CallExpression") {
952
+ const returnType = localFunctionForCall(sourceCode, expression.callee)?.returnType?.typeAnnotation;
953
+ return returnType !== void 0 && hasInformativeType(returnType, environment);
954
+ }
955
+ if (expression.type !== "Identifier") return isKnownEvidenceExpression(expression);
956
+ const variable = resolveVariable$2(sourceCode, expression);
957
+ if (variable === null || visitedVariables.has(variable)) return false;
958
+ const annotation = variableTypeAnnotation(sourceCode, variable);
959
+ if (annotation !== null) return hasInformativeType(annotation.typeAnnotation, environment);
960
+ const declarator = variableDeclarator$1(variable);
961
+ if (declarator === null || declarator.init === null || !isStableConstVariable(variable, declarator)) return false;
962
+ visitedVariables.add(variable);
963
+ return hasKnownCallArgumentEvidence(sourceCode, declarator.init, environment, visitedVariables);
964
+ }
965
+ function typePredicateSubjectIndex(sourceCode, owner) {
966
+ const predicate = owner.returnType?.typeAnnotation;
967
+ if (predicate?.type !== "TSTypePredicate" || predicate.parameterName.type !== "Identifier") return null;
968
+ const predicateParameterName = predicate.parameterName.name;
969
+ const index = owner.params.findIndex((parameter) => functionParameterBindingName(parameter, sourceCode) === predicateParameterName);
970
+ return index === -1 ? null : index;
971
+ }
733
972
  function annotationTarget(annotation, environment) {
734
973
  return annotation === null || annotation === void 0 ? null : classifyWideningTarget(annotation.typeAnnotation, environment);
735
974
  }
@@ -789,7 +1028,7 @@ const noKnownValueWideningRule = defineRule({
789
1028
  const targetFromAnnotation = (annotation) => environment === null ? null : annotationTarget(annotation, environment);
790
1029
  return {
791
1030
  Program(node) {
792
- environment = createTypeEnvironment(node);
1031
+ environment = createTypeEnvironment(node, context.sourceCode.visitorKeys);
793
1032
  },
794
1033
  VariableDeclarator(node) {
795
1034
  if (node.init === null || node.id.type !== "Identifier") return;
@@ -811,6 +1050,27 @@ const noKnownValueWideningRule = defineRule({
811
1050
  if (declarator === null || declarator.id.type !== "Identifier") return;
812
1051
  reportFlow(node.right, targetFromAnnotation(declarator.id.typeAnnotation), `binding \`${declarator.id.name}\``);
813
1052
  },
1053
+ CallExpression(node) {
1054
+ if (environment === null) return;
1055
+ const owner = localFunctionForCall(context.sourceCode, node.callee);
1056
+ if (owner === null) return;
1057
+ const parameterIndex = typePredicateSubjectIndex(context.sourceCode, owner);
1058
+ if (parameterIndex === null) return;
1059
+ const parameter = owner.params[parameterIndex];
1060
+ const argument = node.arguments[parameterIndex];
1061
+ if (parameter === void 0 || argument === void 0 || argument.type === "SpreadElement") return;
1062
+ const parameterAnnotation = functionParameterTypeAnnotation(parameter);
1063
+ if (parameterAnnotation === null || parameterAnnotation === void 0 || !containsUnknownType(parameterAnnotation.typeAnnotation)) return;
1064
+ if (!hasKnownCallArgumentEvidence(context.sourceCode, argument, environment)) return;
1065
+ context.report({
1066
+ node: argument,
1067
+ messageId: "widening",
1068
+ data: {
1069
+ subject: `argument for parameter \`${functionParameterBindingName(parameter, context.sourceCode)}\` of \`${functionName(context.sourceCode, owner)}\``,
1070
+ target: "unknown"
1071
+ }
1072
+ });
1073
+ },
814
1074
  ReturnStatement(node) {
815
1075
  if (node.argument === null) return;
816
1076
  const owner = enclosingFunction(node);
@@ -888,48 +1148,7 @@ const noModuleMockingRule = defineRule({
888
1148
  }
889
1149
  });
890
1150
  //#endregion
891
- //#region src/shared/lexical-type-parameters.ts
892
- function isNode(value) {
893
- return typeof value === "object" && value !== null && "type" in value && typeof value.type === "string";
894
- }
895
- function collectInferTypeParameterNames(node, visitorKeys, names) {
896
- if (node.type === "TSInferType") names.add(node.typeParameter.name.name);
897
- const record = node;
898
- for (const key of visitorKeys[node.type] ?? []) {
899
- const value = record[key];
900
- if (isNode(value)) {
901
- collectInferTypeParameterNames(value, visitorKeys, names);
902
- continue;
903
- }
904
- if (!Array.isArray(value)) continue;
905
- for (const child of value) if (isNode(child)) collectInferTypeParameterNames(child, visitorKeys, names);
906
- }
907
- }
908
- /** Collect type binders that are in scope at a node and can shadow module aliases. */
909
- function lexicalTypeParameterNames(node, visitorKeys) {
910
- const names = /* @__PURE__ */ new Set();
911
- let descendant = node;
912
- let current = node;
913
- while (current !== null && current.type !== "Program") {
914
- if ("typeParameters" in current) for (const parameter of current.typeParameters?.params ?? []) names.add(parameter.name.name);
915
- if (current.type === "TSMappedType" && (descendant === current.nameType || descendant === current.typeAnnotation)) names.add(current.key.name);
916
- if (current.type === "TSConditionalType" && descendant === current.trueType) collectInferTypeParameterNames(current.extendsType, visitorKeys, names);
917
- descendant = current;
918
- current = current.parent;
919
- }
920
- return names;
921
- }
922
- //#endregion
923
1151
  //#region src/rules/no-object-parameters.ts
924
- function parameterAnnotation$1(parameter) {
925
- if (parameter.type === "TSParameterProperty") return parameterAnnotation$1(parameter.parameter);
926
- if (parameter.type === "RestElement") return parameter.typeAnnotation ?? parameterAnnotation$1(parameter.argument);
927
- if (parameter.type === "AssignmentPattern") return parameter.typeAnnotation ?? parameter.left.typeAnnotation;
928
- return parameter.typeAnnotation;
929
- }
930
- function parameterName$1(parameter, sourceCode) {
931
- return parameter.type === "Identifier" ? parameter.name : sourceCode.getText(parameter).replace(/\s*:\s*object\s*$/u, "");
932
- }
933
1152
  /** Ban the broad object type on function inputs, including local aliases to object. */
934
1153
  const noObjectParametersRule = defineRule({
935
1154
  meta: {
@@ -938,38 +1157,27 @@ const noObjectParametersRule = defineRule({
938
1157
  messages: { objectParameter: "Parameter `{{parameter}}` uses the broad `object` type. Accept a named owner type; parse external input at its boundary before calling this function." }
939
1158
  },
940
1159
  createOnce(context) {
941
- const aliases = /* @__PURE__ */ new Map();
942
- const resolvesToObject = (type, shadowedAliases, visited = /* @__PURE__ */ new Set()) => {
943
- if (type.type === "TSObjectKeyword") return true;
944
- if (type.type === "TSParenthesizedType") return resolvesToObject(type.typeAnnotation, shadowedAliases, visited);
945
- if (type.type === "TSUnionType") return type.types.some((member) => resolvesToObject(member, shadowedAliases, visited));
946
- if (type.type !== "TSTypeReference" || type.typeName.type !== "Identifier" || type.typeArguments !== null && type.typeArguments !== void 0 && type.typeArguments.params.length > 0 || visited.has(type.typeName.name) || shadowedAliases.has(type.typeName.name)) return false;
947
- const alias = aliases.get(type.typeName.name);
948
- if (alias === void 0) return false;
949
- const nextVisited = new Set(visited);
950
- nextVisited.add(type.typeName.name);
951
- return resolvesToObject(alias, shadowedAliases, nextVisited);
952
- };
1160
+ let environment = null;
1161
+ const resolvesToObject = (type) => environment !== null && resolvedTypeMatches(type, environment, (resolved, matches) => {
1162
+ if (resolved.type === "TSObjectKeyword") return true;
1163
+ if (resolved.type === "TSParenthesizedType") return matches(resolved.typeAnnotation);
1164
+ return resolved.type === "TSUnionType" && resolved.types.some(matches);
1165
+ });
953
1166
  const checkParameters = (node) => {
954
- const shadowedAliases = lexicalTypeParameterNames(node, context.sourceCode.visitorKeys);
955
1167
  for (const parameter of node.params) {
956
- const annotation = parameterAnnotation$1(parameter);
1168
+ const annotation = functionParameterTypeAnnotation(parameter);
957
1169
  if (annotation === null || annotation === void 0) continue;
958
- if (!resolvesToObject(annotation.typeAnnotation, shadowedAliases)) continue;
1170
+ if (!resolvesToObject(annotation.typeAnnotation)) continue;
959
1171
  context.report({
960
1172
  node: annotation.typeAnnotation,
961
1173
  messageId: "objectParameter",
962
- data: { parameter: parameterName$1(parameter, context.sourceCode) }
1174
+ data: { parameter: functionParameterBindingName(parameter, context.sourceCode) }
963
1175
  });
964
1176
  }
965
1177
  };
966
1178
  return {
967
1179
  Program(node) {
968
- aliases.clear();
969
- for (const statement of node.body) {
970
- const declaration = statement.type === "ExportNamedDeclaration" ? statement.declaration : statement;
971
- if (declaration?.type === "TSTypeAliasDeclaration" && (declaration.typeParameters === null || declaration.typeParameters === void 0)) aliases.set(declaration.id.name, declaration.typeAnnotation);
972
- }
1180
+ environment = createTypeAliasEnvironment(node, context.sourceCode.visitorKeys);
973
1181
  },
974
1182
  ArrowFunctionExpression: checkParameters,
975
1183
  FunctionDeclaration: checkParameters,
@@ -1059,6 +1267,19 @@ function isInsideTypeGuard(node) {
1059
1267
  }
1060
1268
  return false;
1061
1269
  }
1270
+ /** Return whether typeof safely probes for the existence of a possibly absent binding. */
1271
+ function isExistenceProbe(node) {
1272
+ const parent = node.parent;
1273
+ if (parent.type !== "BinaryExpression") return false;
1274
+ if (![
1275
+ "===",
1276
+ "!==",
1277
+ "==",
1278
+ "!="
1279
+ ].includes(parent.operator)) return false;
1280
+ const other = parent.left === node ? parent.right : parent.left;
1281
+ return other.type === "Literal" && other.value === "undefined";
1282
+ }
1062
1283
  /** Disallow runtime typeof checks that narrow unparsed values instead of decoding them. */
1063
1284
  const noRuntimeTypeofRule = defineRule({
1064
1285
  meta: {
@@ -1076,7 +1297,7 @@ const noRuntimeTypeofRule = defineRule({
1076
1297
  return { UnaryExpression(node) {
1077
1298
  const option = context.options?.[0];
1078
1299
  const allowInTypeGuards = typeof option === "object" && option !== null && !Array.isArray(option) && option.allowInTypeGuards === true;
1079
- if (node.operator === "typeof" && (!allowInTypeGuards || !isInsideTypeGuard(node))) context.report({
1300
+ if (node.operator === "typeof" && !isExistenceProbe(node) && (!allowInTypeGuards || !isInsideTypeGuard(node))) context.report({
1080
1301
  node,
1081
1302
  messageId: "runtimeTypeof"
1082
1303
  });
@@ -1089,6 +1310,12 @@ const FORBIDDEN_SYMBOL_NAME = "shape";
1089
1310
  function containsForbiddenSymbolName(name) {
1090
1311
  return name.toLowerCase().includes(FORBIDDEN_SYMBOL_NAME);
1091
1312
  }
1313
+ /** Return whether an identifier names a statically accessed member owned by another value. */
1314
+ function isBorrowedMemberName(node) {
1315
+ const parent = node.parent;
1316
+ if (parent === null || parent.type !== "MemberExpression") return false;
1317
+ return parent.property === node && parent.computed === false;
1318
+ }
1092
1319
  /** Ban the case-insensitive substring "shape" in every JavaScript and TypeScript symbol name. */
1093
1320
  const noForbiddenTermInSymbolNamesRule = defineRule({
1094
1321
  meta: {
@@ -1098,7 +1325,7 @@ const noForbiddenTermInSymbolNamesRule = defineRule({
1098
1325
  },
1099
1326
  createOnce(context) {
1100
1327
  const reportForbiddenSymbolName = (node) => {
1101
- if (!containsForbiddenSymbolName(node.name)) return;
1328
+ if (!containsForbiddenSymbolName(node.name) || isBorrowedMemberName(node)) return;
1102
1329
  context.report({
1103
1330
  node,
1104
1331
  messageId: "forbiddenSymbolName",
@@ -1114,32 +1341,25 @@ const noForbiddenTermInSymbolNamesRule = defineRule({
1114
1341
  });
1115
1342
  //#endregion
1116
1343
  //#region src/rules/no-unknown-parameters.ts
1117
- function parameterAnnotation(parameter) {
1118
- if (parameter.type === "TSParameterProperty") return parameterAnnotation(parameter.parameter);
1119
- if (parameter.type === "RestElement") return parameter.typeAnnotation ?? parameterAnnotation(parameter.argument);
1120
- if (parameter.type === "AssignmentPattern") return parameter.typeAnnotation ?? parameter.left.typeAnnotation;
1121
- return parameter.typeAnnotation;
1122
- }
1123
- function parameterName(parameter, sourceText) {
1124
- if (parameter.type === "TSParameterProperty") return parameterName(parameter.parameter, sourceText);
1125
- if (parameter.type === "AssignmentPattern") return parameterName(parameter.left, sourceText);
1126
- if (parameter.type === "RestElement") return parameterName(parameter.argument, sourceText);
1127
- return parameter.type === "Identifier" ? parameter.name : sourceText.replace(/\s*:\s*unknown\s*$/u, "");
1344
+ function isTypePredicateSubject(owner, parameterName) {
1345
+ const predicate = owner.returnType?.typeAnnotation;
1346
+ return predicate?.type === "TSTypePredicate" && predicate.parameterName.type === "Identifier" && predicate.parameterName.name === parameterName;
1128
1347
  }
1129
1348
  /** Disallow unknown inputs except explicitly named error-cause enrichment. */
1130
1349
  const noUnknownParametersRule = defineRule({
1131
1350
  meta: {
1132
1351
  type: "problem",
1133
- docs: { description: "Disallow explicitly unknown function parameters except `cause`; decode unknown input at its I/O boundary instead." },
1352
+ docs: { description: "Disallow explicitly unknown function parameters except `cause` and type-predicate subjects; decode unknown input at its I/O boundary instead." },
1134
1353
  messages: { unknownParameter: "Parameter `{{parameter}}` leaves input unparsed. Accept a named domain type; run the expected schema or parser at the I/O boundary before calling this function." }
1135
1354
  },
1136
1355
  createOnce(context) {
1137
1356
  const checkParameters = (node) => {
1138
1357
  for (const parameter of node.params) {
1139
- const annotation = parameterAnnotation(parameter);
1140
- if (annotation?.typeAnnotation.type !== "TSUnknownKeyword") continue;
1141
- const name = parameterName(parameter, context.sourceCode.getText(parameter));
1142
- if (name === "cause") continue;
1358
+ const annotation = functionParameterTypeAnnotation(parameter);
1359
+ if (annotation === null || annotation === void 0) continue;
1360
+ if (!containsUnknownType(annotation.typeAnnotation)) continue;
1361
+ const name = functionParameterBindingName(parameter, context.sourceCode);
1362
+ if (name === "cause" || isTypePredicateSubject(node, name)) continue;
1143
1363
  context.report({
1144
1364
  node: annotation.typeAnnotation,
1145
1365
  messageId: "unknownParameter",
@@ -1163,11 +1383,6 @@ const noUnknownParametersRule = defineRule({
1163
1383
  });
1164
1384
  //#endregion
1165
1385
  //#region src/rules/no-unknown-returns.ts
1166
- function referencedAliasName$1(type) {
1167
- if (type.type === "TSParenthesizedType") return referencedAliasName$1(type.typeAnnotation);
1168
- if (type.type !== "TSTypeReference" || type.typeName.type !== "Identifier") return null;
1169
- return type.typeArguments === null || type.typeArguments === void 0 || type.typeArguments.params.length === 0 ? type.typeName.name : null;
1170
- }
1171
1386
  /** Ban function contracts that return unknown instead of a parsed domain type. */
1172
1387
  const noUnknownReturnsRule = defineRule({
1173
1388
  meta: {
@@ -1176,27 +1391,19 @@ const noUnknownReturnsRule = defineRule({
1176
1391
  messages: { unknownReturn: "This function exposes `unknown` to its caller. Parse the value at its boundary and return a named domain type." }
1177
1392
  },
1178
1393
  createOnce(context) {
1179
- const aliases = /* @__PURE__ */ new Map();
1180
- const resolvesToUnknown = (type, shadowedAliases, visited = /* @__PURE__ */ new Set()) => {
1181
- if (type.type === "TSUnknownKeyword") return true;
1182
- if (type.type === "TSParenthesizedType") return resolvesToUnknown(type.typeAnnotation, shadowedAliases, visited);
1183
- if (type.type === "TSUnionType") return type.types.some((member) => resolvesToUnknown(member, shadowedAliases, visited));
1184
- if (type.type === "TSTypeReference" && type.typeName.type === "Identifier" && (type.typeName.name === "Promise" || type.typeName.name === "PromiseLike")) {
1185
- const value = type.typeArguments?.params[0];
1186
- return value !== void 0 && resolvesToUnknown(value, shadowedAliases, visited);
1187
- }
1188
- const name = referencedAliasName$1(type);
1189
- if (name === null || visited.has(name) || shadowedAliases.has(name)) return false;
1190
- const alias = aliases.get(name);
1191
- if (alias === void 0 || alias.typeParameters !== null && alias.typeParameters !== void 0) return false;
1192
- const nextVisited = new Set(visited);
1193
- nextVisited.add(name);
1194
- return resolvesToUnknown(alias.typeAnnotation, shadowedAliases, nextVisited);
1195
- };
1394
+ let environment = null;
1395
+ const resolvesToUnknown = (type) => environment !== null && resolvedTypeMatches(type, environment, (resolved, matches) => {
1396
+ if (resolved.type === "TSUnknownKeyword") return true;
1397
+ if (resolved.type === "TSParenthesizedType") return matches(resolved.typeAnnotation);
1398
+ if (resolved.type === "TSUnionType") return resolved.types.some(matches);
1399
+ if (resolved.type !== "TSTypeReference" || resolved.typeName.type !== "Identifier" || resolved.typeName.name !== "Promise" && resolved.typeName.name !== "PromiseLike") return false;
1400
+ const value = resolved.typeArguments?.params[0];
1401
+ return value !== void 0 && matches(value);
1402
+ });
1196
1403
  const checkReturnType = (node) => {
1197
1404
  const annotation = node.returnType;
1198
1405
  if (annotation === null || annotation === void 0) return;
1199
- if (!resolvesToUnknown(annotation.typeAnnotation, lexicalTypeParameterNames(node, context.sourceCode.visitorKeys))) return;
1406
+ if (!resolvesToUnknown(annotation.typeAnnotation)) return;
1200
1407
  context.report({
1201
1408
  node: annotation.typeAnnotation,
1202
1409
  messageId: "unknownReturn"
@@ -1204,11 +1411,7 @@ const noUnknownReturnsRule = defineRule({
1204
1411
  };
1205
1412
  return {
1206
1413
  Program(node) {
1207
- aliases.clear();
1208
- for (const statement of node.body) {
1209
- const declaration = statement.type === "ExportNamedDeclaration" ? statement.declaration : statement;
1210
- if (declaration?.type === "TSTypeAliasDeclaration") aliases.set(declaration.id.name, declaration);
1211
- }
1414
+ environment = createTypeAliasEnvironment(node, context.sourceCode.visitorKeys);
1212
1415
  },
1213
1416
  ArrowFunctionExpression: checkReturnType,
1214
1417
  FunctionDeclaration: checkReturnType,
@@ -1225,11 +1428,6 @@ const noUnknownReturnsRule = defineRule({
1225
1428
  });
1226
1429
  //#endregion
1227
1430
  //#region src/rules/no-unknown-type-aliases.ts
1228
- function referencedAliasName(type) {
1229
- if (type.type === "TSParenthesizedType") return referencedAliasName(type.typeAnnotation);
1230
- if (type.type !== "TSTypeReference" || type.typeName.type !== "Identifier") return null;
1231
- return type.typeArguments === null || type.typeArguments === void 0 || type.typeArguments.params.length === 0 ? type.typeName.name : null;
1232
- }
1233
1431
  /** Ban named aliases that merely conceal TypeScript's unknown top type. */
1234
1432
  const noUnknownTypeAliasesRule = defineRule({
1235
1433
  meta: {
@@ -1238,33 +1436,25 @@ const noUnknownTypeAliasesRule = defineRule({
1238
1436
  messages: { unknownAlias: "Type alias `{{alias}}` hides `unknown`. Keep `unknown` explicit at the parsing boundary or on an allowed `cause` field; otherwise use the parsed owner type." }
1239
1437
  },
1240
1438
  createOnce(context) {
1241
- const aliases = /* @__PURE__ */ new Map();
1242
- const resolvesToUnknown = (type, visited = /* @__PURE__ */ new Set()) => {
1243
- if (type.type === "TSUnknownKeyword") return true;
1244
- if (type.type === "TSParenthesizedType") return resolvesToUnknown(type.typeAnnotation, visited);
1245
- const name = referencedAliasName(type);
1246
- if (name === null || visited.has(name)) return false;
1247
- const alias = aliases.get(name);
1248
- if (alias === void 0 || alias.typeParameters !== null && alias.typeParameters !== void 0) return false;
1249
- const nextVisited = new Set(visited);
1250
- nextVisited.add(name);
1251
- return resolvesToUnknown(alias.typeAnnotation, nextVisited);
1252
- };
1253
- return { Program(node) {
1254
- aliases.clear();
1255
- for (const statement of node.body) {
1256
- const declaration = statement.type === "ExportNamedDeclaration" ? statement.declaration : statement;
1257
- if (declaration?.type === "TSTypeAliasDeclaration") aliases.set(declaration.id.name, declaration);
1258
- }
1259
- for (const alias of aliases.values()) {
1260
- if (!resolvesToUnknown(alias.typeAnnotation, /* @__PURE__ */ new Set([alias.id.name]))) continue;
1439
+ let environment = null;
1440
+ const resolvesToUnknown = (type) => environment !== null && resolvedTypeMatches(type, environment, (resolved, matches) => {
1441
+ if (resolved.type === "TSUnknownKeyword") return true;
1442
+ if (resolved.type === "TSParenthesizedType") return matches(resolved.typeAnnotation);
1443
+ return resolved.type === "TSUnionType" && resolved.types.some(matches);
1444
+ });
1445
+ return {
1446
+ Program(node) {
1447
+ environment = createTypeAliasEnvironment(node, context.sourceCode.visitorKeys);
1448
+ },
1449
+ TSTypeAliasDeclaration(node) {
1450
+ if (!resolvesToUnknown(node.typeAnnotation)) return;
1261
1451
  context.report({
1262
- node: alias.id,
1452
+ node: node.id,
1263
1453
  messageId: "unknownAlias",
1264
- data: { alias: alias.id.name }
1454
+ data: { alias: node.id.name }
1265
1455
  });
1266
1456
  }
1267
- } };
1457
+ };
1268
1458
  }
1269
1459
  });
1270
1460
  //#endregion
@@ -1325,9 +1515,20 @@ function isInsideTypeAliasDeclaration(node) {
1325
1515
  function isPlainAliasConsumerUse(node, environment) {
1326
1516
  if (node.type !== "TSTypeReference" || node.typeArguments?.params.length) return false;
1327
1517
  const name = typeReferenceName$1(node);
1328
- return name !== null && environment.aliases.has(name) && !isInsideTypeAliasDeclaration(node);
1518
+ return name !== null && visibleTypeAlias(name, node, environment.typeAliases) !== null && !isInsideTypeAliasDeclaration(node);
1519
+ }
1520
+ function isInsideTypeParameterConstraint(node) {
1521
+ let child = node;
1522
+ let parent = child.parent;
1523
+ while (parent !== null && parent.type !== "Program") {
1524
+ if (parent.type === "TSTypeParameter" && parent.constraint === child) return true;
1525
+ child = parent;
1526
+ parent = child.parent;
1527
+ }
1528
+ return false;
1329
1529
  }
1330
1530
  function shouldReportType(node, environment) {
1531
+ if (isInsideTypeParameterConstraint(node)) return false;
1331
1532
  if (isPlainAliasConsumerUse(node, environment)) return false;
1332
1533
  if (classifyUnsafeDictionary(node, environment) === null) return false;
1333
1534
  let current = node.parent;
@@ -1361,7 +1562,7 @@ const noUnsafeDictionaryTypeRule = defineRule({
1361
1562
  };
1362
1563
  return {
1363
1564
  Program(node) {
1364
- environment = createTypeEnvironment(node);
1565
+ environment = createTypeEnvironment(node, context.sourceCode.visitorKeys);
1365
1566
  },
1366
1567
  TSTypeReference: reportIfUnsafe,
1367
1568
  TSTypeLiteral: reportIfUnsafe,
@@ -1565,6 +1766,7 @@ const noWidenThenAssertRule = defineRule({
1565
1766
  });
1566
1767
  //#endregion
1567
1768
  //#region src/rules/require-safety-comment-for-type-assertion.ts
1769
+ const DEFAULT_SAFETY_MARKERS = ["SAFETY"];
1568
1770
  const commentOwnerKinds = /* @__PURE__ */ new Set([
1569
1771
  "ExpressionStatement",
1570
1772
  "PropertyDefinition",
@@ -1575,11 +1777,29 @@ const commentOwnerKinds = /* @__PURE__ */ new Set([
1575
1777
  function isConstAssertion(node) {
1576
1778
  return node.typeAnnotation.type === "TSTypeReference" && node.typeAnnotation.typeName.type === "Identifier" && node.typeAnnotation.typeName.name === "const";
1577
1779
  }
1578
- function hasSafetyComment(sourceCode, node) {
1780
+ function configuredSafetyMarkers(option) {
1781
+ if (typeof option !== "object" || option === null || !("markers" in option)) return DEFAULT_SAFETY_MARKERS;
1782
+ const configured = option.markers;
1783
+ if (!Array.isArray(configured)) return DEFAULT_SAFETY_MARKERS;
1784
+ const markers = configured.flatMap((marker) => typeof marker === "string" && marker.trim().length > 0 ? [marker.trim()] : []);
1785
+ return markers.length > 0 ? markers : DEFAULT_SAFETY_MARKERS;
1786
+ }
1787
+ function markerPattern(markers) {
1788
+ const alternation = markers.map((marker) => marker.replaceAll(/[.*+?^${}()|[\]\\]/gu, String.raw`\$&`)).join("|");
1789
+ return new RegExp(String.raw`(?:^|[^\p{L}\p{N}_])(?:${alternation})\s*:\s*\S`, "u");
1790
+ }
1791
+ function hasSafetyJustificationBefore(sourceCode, owner, assertion, pattern) {
1792
+ return sourceCode.getCommentsBefore(owner).some((comment) => comment.end <= assertion.start && pattern.test(comment.value));
1793
+ }
1794
+ function hasSafetyComment(sourceCode, node, pattern) {
1579
1795
  let current = node;
1580
1796
  while (true) {
1581
- if (sourceCode.getCommentsBefore(current).some((comment) => comment.end <= node.start && /\bSAFETY\s*:/u.test(comment.value))) return true;
1582
- if (commentOwnerKinds.has(current.type) || current.parent.type === "Program") return false;
1797
+ if (hasSafetyJustificationBefore(sourceCode, current, node, pattern)) return true;
1798
+ if (commentOwnerKinds.has(current.type)) {
1799
+ const exportDeclaration = current.parent;
1800
+ return exportDeclaration.type === "ExportNamedDeclaration" && exportDeclaration.declaration === current && hasSafetyJustificationBefore(sourceCode, exportDeclaration, node, pattern);
1801
+ }
1802
+ if (current.parent.type === "Program") return false;
1583
1803
  current = current.parent;
1584
1804
  }
1585
1805
  }
@@ -1607,14 +1827,35 @@ const antiSlopPlugin = eslintCompatPlugin({
1607
1827
  meta: {
1608
1828
  type: "problem",
1609
1829
  docs: { description: "Require a nearby SAFETY comment for every TypeScript type assertion except const assertions." },
1610
- messages: { missingSafetyComment: "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement." }
1830
+ messages: { missingSafetyComment: "This type assertion has no `{{marker}}:` justification. State the checked invariant immediately before the assertion or its containing statement." },
1831
+ schema: [{
1832
+ type: "object",
1833
+ properties: { markers: {
1834
+ type: "array",
1835
+ items: {
1836
+ type: "string",
1837
+ minLength: 1
1838
+ },
1839
+ minItems: 1,
1840
+ uniqueItems: true
1841
+ } },
1842
+ additionalProperties: false
1843
+ }],
1844
+ defaultOptions: [{ markers: ["SAFETY"] }]
1611
1845
  },
1612
1846
  createOnce(context) {
1847
+ const patterns = /* @__PURE__ */ new Map();
1613
1848
  const checkAssertion = (node) => {
1614
- if (isConstAssertion(node) || hasSafetyComment(context.sourceCode, node)) return;
1849
+ if (isConstAssertion(node)) return;
1850
+ const markers = configuredSafetyMarkers(context.options?.[0]);
1851
+ const patternKey = markers.join("\0");
1852
+ const pattern = patterns.get(patternKey) ?? markerPattern(markers);
1853
+ patterns.set(patternKey, pattern);
1854
+ if (hasSafetyComment(context.sourceCode, node, pattern)) return;
1615
1855
  context.report({
1616
1856
  node,
1617
- messageId: "missingSafetyComment"
1857
+ messageId: "missingSafetyComment",
1858
+ data: { marker: markers[0] ?? DEFAULT_SAFETY_MARKERS[0] }
1618
1859
  });
1619
1860
  };
1620
1861
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adamantite",
3
- "version": "0.38.0",
3
+ "version": "0.39.0",
4
4
  "description": "An strict and opinionated set of presets for modern TypeScript applications",
5
5
  "keywords": [
6
6
  "adamantite",
@@ -58,9 +58,9 @@
58
58
  },
59
59
  "dependencies": {
60
60
  "@clack/prompts": "1.7.0",
61
- "@effect/platform-node": "4.0.0-rc.112",
61
+ "@effect/platform-node": "4.0.0-rc.115",
62
62
  "defu": "6.1.7",
63
- "effect": "4.0.0-rc.112",
63
+ "effect": "4.0.0-rc.115",
64
64
  "esrap": "2.3.6",
65
65
  "jsonc-parser": "3.3.1",
66
66
  "nypm": "0.6.9",
@@ -69,11 +69,12 @@
69
69
  "devDependencies": {
70
70
  "@changesets/changelog-github": "1.0.0",
71
71
  "@changesets/cli": "3.0.1",
72
- "@effect/vitest": "4.0.0-rc.112",
72
+ "@effect/vitest": "4.0.0-rc.115",
73
73
  "@tanstack/intent": "0.3.7",
74
74
  "@types/figlet": "1.7.0",
75
75
  "@types/node": "22.20.1",
76
- "@vitest/coverage-v8": "4.1.11",
76
+ "@vitest/coverage-v8": "5.0.1",
77
+ "@vitest/ui": "5.0.1",
77
78
  "figlet": "1.11.4",
78
79
  "knip": "6.32.2",
79
80
  "oxfmt": "0.65.0",
@@ -84,7 +85,7 @@
84
85
  "type-fest": "5.8.0",
85
86
  "typescript": "7.0.2",
86
87
  "unplugin-macros": "0.23.2",
87
- "vitest": "4.1.11"
88
+ "vitest": "5.0.1"
88
89
  },
89
90
  "peerDependencies": {
90
91
  "typescript": ">=7"