@karmaniverous/stan-core 0.5.1 → 0.6.1

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/README.md CHANGED
@@ -2,16 +2,17 @@
2
2
 
3
3
  # @karmaniverous/stan-core (engine)
4
4
 
5
- [![npm version](https://img.shields.io/npm/v/@karmaniverous/stan-core.svg)](https://www.npmjs.com/package/@karmaniverous/stan-core) ![Node Current](https://img.shields.io/node/v/@karmaniverous/stan-core) <!-- TYPEDOC_EXCLUDE --> [![docs](https://img.shields.io/badge/docs-website-blue)](https://docs.karmanivero.us/stan-core) [![changelog](https://img.shields.io/badge/changelog-latest-blue.svg)](https://github.com/karmaniverous/stan-core/tree/main/CHANGELOG.md)<!-- /TYPEDOC_EXCLUDE --> [![license](https://img.shields.io/badge/license-BSD--3--Clause-blue.svg)](https://github.com/karmaniverous/stan-core/tree/main/LICENSE.md)
5
+ [![npm version](https://img.shields.io/npm/v/@karmaniverous/stan-core.svg)](https://www.npmjs.com/package/@karmaniverous/stan-core) ![Node Current](https://img.shields.io/node/v/@karmaniverous/stan-core) <!-- TYPEDOC_EXCLUDE --> [![docs](https://img.shields.io/badge/docs-website-blue)](https://docs.karmanivero.us/stan-core) [![changelog](https://img.shields.io/badge/changelog-latest-blue.svg)](https://github.com/karmaniverous/stan-core/tree/main/CHANGELOG.md)<!-- /TYPEDOC_EXCLUDE --> [![license](https://img.shields.io/badge/license-BSD--3--Clause-blue.svg)](https://github.com/karmaniverous/stan-core/tree/main/LICENSE)
6
6
 
7
7
  This package exposes the STAN engine as a library:
8
8
 
9
9
  - File selection (gitignore + includes/excludes + reserved workspace rules)
10
10
  - Archiving: full archive.tar and diff archive.diff.tar (binary screening)
11
11
  - Patch engine: worktree‑first git apply cascade with jsdiff fallback
12
- - File Ops: safe mv/rm/rmdir/mkdirp block as “pre‑ops”
12
+ - File Ops: safe mv/cp/rm/rmdir/mkdirp block as “pre‑ops”
13
13
  - Config loading/validation (top‑level `stan-core` in stan.config.yml|json)
14
14
  - Imports staging under <stanPath>/imports/<label>/…
15
+ - Imports safety: patch + File Ops refuse to modify <stanPath>/imports/** when the correct stanPath is provided
15
16
  - Response‑format validator (optional)
16
17
 
17
18
  For the CLI and TTY runner, see @karmaniverous/stan-cli.
@@ -25,13 +26,14 @@ pnpm add @karmaniverous/stan-core
25
26
 
26
27
  Node: >= 20
27
28
 
29
+ This package is ESM-only (no CommonJS `require()` entrypoint).
30
+
28
31
  ## Quick examples
29
32
 
30
33
  Create a full archive (binary‑safe) and a diff archive:
31
34
 
32
35
  ```ts
33
- import { createArchive } from '@karmaniverous/stan-core/stan';
34
- import { createArchiveDiff } from '@karmaniverous/stan-core/stan/diff';
36
+ import { createArchive, createArchiveDiff } from '@karmaniverous/stan-core';
35
37
 
36
38
  const cwd = process.cwd();
37
39
  const stanPath = '.stan';
@@ -57,7 +59,7 @@ import {
57
59
  detectAndCleanPatch,
58
60
  executeFileOps,
59
61
  parseFileOpsBlock,
60
- } from '@karmaniverous/stan-core/stan/patch';
62
+ } from '@karmaniverous/stan-core';
61
63
 
62
64
  const cwd = process.cwd();
63
65
 
@@ -111,7 +113,7 @@ stan-core:
111
113
  TypeScript:
112
114
 
113
115
  ```ts
114
- import { loadConfig } from '@karmaniverous/stan-core/stan/config';
116
+ import { loadConfig } from '@karmaniverous/stan-core';
115
117
 
116
118
  const cfg = await loadConfig(process.cwd());
117
119
  // cfg has the minimal engine shape:
@@ -124,7 +126,7 @@ const cfg = await loadConfig(process.cwd());
124
126
  Stage external imports under <stanPath>/imports/<label>/… before archiving:
125
127
 
126
128
  ```ts
127
- import { prepareImports } from '@karmaniverous/stan-core/stan';
129
+ import { prepareImports } from '@karmaniverous/stan-core';
128
130
  await prepareImports({
129
131
  cwd: process.cwd(),
130
132
  stanPath: '.stan',
@@ -137,14 +139,14 @@ await prepareImports({
137
139
  Validate assistant responses (optional utility):
138
140
 
139
141
  ```ts
140
- import { validateResponseMessage } from '@karmaniverous/stan-core/stan';
142
+ import { validateResponseMessage } from '@karmaniverous/stan-core';
141
143
  const res = validateResponseMessage(replyBody);
142
144
  if (!res.ok) console.error(res.errors.join('\n'));
143
145
  ```
144
146
 
145
147
  ## API surface
146
148
 
147
- Top‑level (via `import '@karmaniverous/stan-core/stan'`):
149
+ Top‑level (via `import '@karmaniverous/stan-core'`):
148
150
 
149
151
  - Archiving/diff/snapshot: `createArchive`, `createArchiveDiff`, `writeArchiveSnapshot`
150
152
  - Selection/FS: `listFiles`, `filterFiles`
@@ -155,7 +157,7 @@ Top‑level (via `import '@karmaniverous/stan-core/stan'`):
155
157
 
156
158
  See CHANGELOG for behavior changes. Typedoc site is generated from source.
157
159
 
158
- ## Selection precedence and anchors
160
+ ## Selection precedence
159
161
 
160
162
  Core file selection applies in this order:
161
163
 
@@ -163,17 +165,19 @@ Core file selection applies in this order:
163
165
  - `.git/**`, `<stanPath>/diff/**`, `<stanPath>/patch/**`,
164
166
  - archive outputs under `<stanPath>/output/…`,
165
167
  - binary screening during archive classification.
166
- - `includes` override `.gitignore` (but not `excludes`).
167
- - `excludes` override `includes`.
168
- - `anchors` (optional) re‑include paths after excludes and `.gitignore`, subject to reserved denials and binary screening.
169
-
170
- APIs that accept anchors:
171
-
172
- - `filterFiles(files, { …, anchors?: string[] })`
173
- - `createArchive(cwd, stanPath, { …, anchors?: string[] })`
174
- - `createArchiveDiff({ …, anchors?: string[] })`
175
- - `writeArchiveSnapshot({ …, anchors?: string[] })`
176
-
168
+ - `includes` are additive and can re-include paths ignored by `.gitignore`.
169
+ - `excludes` are hard denials and override `includes`.
170
+
171
+ ## Meta archive (context-mode thread opener)
172
+
173
+ When dependency graph mode is enabled, the engine can create a small `archive.meta.tar` (via `createMetaArchive`) intended as a thread opener:
174
+
175
+ - Includes `<stanPath>/system/**` (excluding `<stanPath>/system/.docs.meta.json`)
176
+ - Includes `<stanPath>/context/dependency.meta.json` (required)
177
+ - Includes `<stanPath>/context/dependency.state.json` when present
178
+ - Includes repo-root (top-level) base files selected by current selection config
179
+ - Excludes staged payloads under `<stanPath>/context/{npm,abs}/**` by omission
180
+
177
181
  ## Environment variables
178
182
 
179
183
  See [Env Vars](./guides/env-vars.md) for a complete list of environment variable switches observed by the engine, tests, and release scripts.
@@ -189,3 +193,7 @@ stan init # offers to refactor legacy → namespaced; supports --dry-run and ba
189
193
  ## License
190
194
 
191
195
  BSD‑3‑Clause
196
+
197
+ ---
198
+
199
+ Built for you with ❤️ on Bali! Find more great tools & templates on [my GitHub Profile](https://github.com/karmaniverous).
@@ -0,0 +1 @@
1
+ import e from"node:path";import t,{stat as n}from"node:fs/promises";import{createHash as i}from"node:crypto";import s,{createReadStream as r}from"node:fs";import{a as o,r as a,d}from"./index-DEnUXENF.js";import{createRequire as c,builtinModules as l}from"node:module";import u from"node:process";import{fileURLToPath as p}from"node:url";import"fs-extra";import"process";import"buffer";import"node:child_process";import"os";import"path";import"util";import"stream";import"events";import"fs";const f=e=>"\n"===e||"\r"===e,m=(e,t)=>{let n=t;for(;n<e.length&&!f(e[n]);)n++;return n},g=(e,t)=>{for(let n=t;n<e.length-1;n++)if("*"===e[n]&&"/"===e[n+1])return n+2;return null},h=["@module","@packageDocumentation"],y=/^@\w+$/,b=e=>{const t=(Array.isArray(e)?e:[]).filter(e=>"string"==typeof e).map(e=>e.trim()).filter(e=>y.test(e)),n=new Set,i=[];for(const e of t)n.has(e)||(n.add(e),i.push(e));return i.length?i:[...h]},x=e=>e.replace(/^\s*\/\*\*/,"").replace(/\*\/\s*$/,"").replace(/\r\n?/g,"\n").split("\n").map(e=>e.replace(/^\s*\*\s?/,"")).map(e=>e.trim()),w=e=>{const t=x(e).filter(e=>{const t=e.trim();return!!t&&!t.startsWith("@")});if(!t.length)return;const n=(e=>{let t=e.replace(/\{@(?:link|linkcode|linkplain)\s+([^}|]+)(?:\s*\|\s*([^}]+))?\}/g,(e,t,n)=>(n??t).trim());return t=t.replace(/\{@\w+[^}]*\}/g,""),t=t.replace(/\[([^\]]+)\]\([^)]+\)/g,"$1"),t=t.replace(/`([^`]*)`/g,"$1"),t})(t.join(" ")).replace(/\s+/g," ").trim();return n||void 0},k=e=>{const t=e.nodeDescriptionLimit;if(!Number.isFinite(t)||t<=0)return{tag:e.tag,present:!1,usable:!1};const n=e.tag.trim();if(!y.test(n))return{tag:e.tag,present:!1,usable:!1};let i=!1,s=null;for(const t of(e=>{const t=[],n=[{kind:"code"}],i=()=>n[n.length-1],s=e=>n.push(e),r=()=>{n.length>1&&n.pop()};for(let n=0;n<e.length;n++){const o=i(),a=e[n],d=e[n+1];if("single"!==o.kind)if("double"!==o.kind)if("template"!==o.kind)if("templateExpr"!==o.kind)if("'"!==a)if('"'!==a)if("`"!==a)if("/"!==a||"/"!==d){if("/"===a&&"*"===d){const i="*"===e[n+2],s=g(e,n+2);if(null===s)return t;i&&t.push(e.slice(n,s)),n=s-1;continue}}else n=m(e,n+2)-1;else s({kind:"template"});else s({kind:"double"});else s({kind:"single"});else{if("'"===a){s({kind:"single"});continue}if('"'===a){s({kind:"double"});continue}if("`"===a){s({kind:"template"});continue}if("/"===a&&"/"===d){n=m(e,n+2)-1;continue}if("/"===a&&"*"===d){const i="*"===e[n+2],s=g(e,n+2);if(null===s)return t;i&&t.push(e.slice(n,s)),n=s-1;continue}if("{"===a){o.braceDepth++;continue}if("}"===a){o.braceDepth--,o.braceDepth<=0&&r();continue}}else{if("\\"===a){n++;continue}if("`"===a){r();continue}if("$"===a&&"{"===d){s({kind:"templateExpr",braceDepth:1}),n++;continue}}else{if("\\"===a){n++;continue}'"'===a&&r()}else{if("\\"===a){n++;continue}"'"===a&&r()}}return t})(e.sourceText)){const e=x(t),r=new Set;for(const t of e){const e=t.match(/^@\w+/);e&&y.test(e[0])&&r.add(e[0])}if(!r.has(n))continue;i=!0;const o=w(t);if(!o)continue;const a=o.length;(!s||a>s.len)&&(s={prose:o,len:a})}if(!i)return{tag:e.tag,present:!1,usable:!1};if(!s)return{tag:e.tag,present:!0,usable:!1};const r=((e,t)=>{const n=t;return!Number.isFinite(n)||n<=0?"":e.length<=n?e:`${e.slice(0,n)}...`})(s.prose,t);return r?{tag:e.tag,present:!0,usable:!0,description:r}:{tag:e.tag,present:!0,usable:!1}},S=e=>{const t=e.nodeDescriptionLimit;if(!Number.isFinite(t)||t<=0)return;const n=b(e.tags);let i=null;for(const s of n){const n=k({sourceText:e.sourceText,tag:s,nodeDescriptionLimit:t});n.present&&n.usable&&(!i||n.description.length>i.description.length)&&(i={tag:s,description:n.description})}return i?.description},N=e=>e.replace(/\\/g,"/"),I=(t,n)=>{const i=e.resolve(t),s=e.resolve(n),r=N(i),o=N(s).replace(/\/+$/,"");if(r===o)return{id:"",isOutsideRoot:!1};if(r.startsWith(`${o}/`)){return{id:(a=r.slice(o.length+1),a.startsWith("./")?a.slice(2):a),isOutsideRoot:!1}}var a;return{id:r,isOutsideRoot:!0}},E=(t,n)=>n.startsWith("node:")?null:(e=>e.startsWith("/")||/^[a-zA-Z]:\//.test(e))(n)?n:e.join(t,N(n)),D=e=>!("source"!==e.kind&&"external"!==e.kind||"ts"!==e.language&&"js"!==e.language),F=async e=>{const n=e.nodeDescriptionLimit;if(!Number.isFinite(n)||n<=0)return e.nodes;const i={...e.nodes};for(const[s,r]of Object.entries(e.nodes)){if(!D(r))continue;const o=E(e.cwd,s);if(!o)continue;let a;try{a=await t.readFile(o,"utf8")}catch{continue}const d=e.describeSourceText({sourceText:a,nodeDescriptionLimit:n});if("string"!=typeof d){if("string"==typeof r.description){const e={...r};delete e.description,i[s]=e}}else{if(d===r.description)continue;i[s]={...r,description:d}}}return i},v=(e,t)=>{if(!Number.isFinite(t))return e;const n=Math.max(0,Math.floor(t));if(0===n)return[];if(e.length<=n)return e;if(1===n)return[`errors truncated: ${String(e.length)} total`];const i=n-1;return[...e.slice(0,i),`errors truncated: showing ${String(i)} of ${String(e.length)}`]},C=async e=>{const t=await n(e),s=i("sha256");return await new Promise((t,n)=>{const i=r(e);i.on("data",e=>s.update(e)),i.on("error",n),i.on("end",()=>{t()})}),{size:t.size,hash:s.digest("hex")}},P=async e=>{try{return await C(e)}catch{return null}},O=e=>e.replace(/\\/g,"/"),$=e=>{const{hash:t,isOutsideRoot:n,size:i}=e,s={};return t&&(s.hash=t),n&&(s.isOutsideRoot=!0),"number"==typeof i&&(s.size=i),Object.keys(s).length?s:void 0},j=e=>({..."string"==typeof e.description&&e.description.trim()?{description:e.description.trim()}:{},id:e.id,kind:e.kind,language:e.language,...e.metadata?{metadata:e.metadata}:{}}),K=async t=>{const{id:n,isOutsideRoot:i}=((t,n)=>{const i=e.resolve(t),s=e.resolve(n),r=O(i),o=O(s).replace(/\/+$/,"");return r===o?{id:"",isOutsideRoot:!1}:r.startsWith(`${o}/`)?{id:(a=r.slice(o.length+1),a.startsWith("./")?a.slice(2):a),isOutsideRoot:!1}:{id:r,isOutsideRoot:!0};var a})(t.absPath,t.cwd),{size:s,hash:r}=await C(t.absPath),o=(e=>{const t=e.toLowerCase();return t.endsWith(".d.ts")||t.endsWith(".ts")||t.endsWith(".tsx")?"ts":t.endsWith(".js")||t.endsWith(".jsx")?"js":t.endsWith(".json")?"json":t.endsWith(".md")?"md":"other"})(n);return j({id:n,kind:t.kind,language:o,metadata:$({hash:r,isOutsideRoot:i,size:s})})},A=e=>{const t={};for(const n of Object.keys(e).sort((e,t)=>e.localeCompare(t)))t[n]=e[n];return t},L=e=>{const t=e.metadata?$({hash:e.metadata.hash,isOutsideRoot:!0===e.metadata.isOutsideRoot,size:e.metadata.size}):void 0,n="string"==typeof e.description&&e.description.trim()?e.description.trim():void 0;return j({id:e.id,kind:e.kind,language:e.language,...n?{description:n}:{},...t?{metadata:t}:{}})},z=e=>{const t=new Set,n=[];for(const i of e){const e=`${i.target}\0${i.kind}\0${i.resolution}`;t.has(e)||(t.add(e),n.push(i))}return n.sort((e,t)=>{const n=e.target.localeCompare(t.target);if(n)return n;return e.kind.localeCompare(t.kind)||e.resolution.localeCompare(t.resolution)}),n},M=e=>{const t={};for(const[n,i]of Object.entries(e.nodes))t[n]=L(i);const n=A(t),i={};for(const t of Object.keys(n))i[t]=z(e.edges[t]??[]);return{nodes:n,edges:A(i)}},W=(t,n)=>n.startsWith("node:")?null:(e=>e.startsWith("/")||/^[a-zA-Z]:\//.test(e))(n)?n:e.join(t,n.replace(/\\/g,"/")),T=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),R=(e,t)=>T(e,t)?e[t]:void 0,B=e=>("source"===e.kind||"external"===e.kind)&&"string"==typeof e.metadata?.hash,q=async e=>{const t=new Set(e.analyzableSourceIds);if(!e.previousGraph)return{dirtySourceIds:new Set(e.analyzableSourceIds),reusedEdgesBySource:{},carriedNodes:{},changedNodeIds:new Set(e.analyzableSourceIds)};const n=e.previousGraph,i=(e=>{const t=new Map;for(const[n,i]of Object.entries(e))for(const e of i){const i=t.get(e.target)??new Set;i.add(n),t.set(e.target,i)}return t})(n.edges),s=new Set;for(const[t,i]of Object.entries(e.currentNodes)){if(!B(i))continue;const e=R(n.nodes,t)?.metadata?.hash;e!==i.metadata?.hash&&s.add(t)}for(const[t,i]of Object.entries(n.nodes))"source"===i.kind&&(T(e.currentNodes,t)||s.add(t));for(const[t,i]of Object.entries(n.nodes)){if(!B(i))continue;const n=W(e.cwd,t);if(!n)continue;const r=await P(n);r&&r.hash!==i.metadata?.hash&&s.add(t)}const r=((e,t)=>{const n=new Set,i=[];for(const t of e)n.has(t)||(n.add(t),i.push(t));for(;i.length;){const e=i.shift(),s=t.get(e);if(s)for(const e of s)n.has(e)||(n.add(e),i.push(e))}return n})(s,i),o=new Set;for(const e of r)t.has(e)&&o.add(e);const a={};for(const t of e.analyzableSourceIds)o.has(t)||T(n.edges,t)&&(a[t]=n.edges[t]);const d=new Set;for(const[e,t]of Object.entries(a)){d.add(e);for(const e of t)d.add(e.target)}const c={};for(const t of d){if(T(e.currentNodes,t))continue;const i=R(n.nodes,t);i&&(c[t]=i)}return{dirtySourceIds:o,reusedEdgesBySource:a,carriedNodes:c,changedNodeIds:s}},G=e=>Array.from(new Set(e)).sort((e,t)=>e.localeCompare(t)),H=e=>{const t=(e??[]).filter(Boolean);if(!t.length)return()=>!1;const n=d(t,{dot:!0});return e=>n(e)},_=async n=>{const{cwd:i}=n,s=n.config??{},r=(s.includes??[]).map(N),d=(s.excludes??[]).map(N),c=(s.anchors??[]).map(N),l=H(r),u=H(d),p=H(c),f=await(async n=>{const i=o();try{const s=await t.readFile(e.join(n,".gitignore"),"utf8");i.add(s)}catch{}return i})(i),m=await a("**/*",{cwd:i,dot:!0,onlyFiles:!0,unique:!0,followSymbolicLinks:!0,ignore:[".git/**","node_modules/**"]}),g=G([...r,...c]).filter(e=>e&&"**/*"!==e),h=g.length>0?await a(g,{cwd:i,dot:!0,onlyFiles:!0,unique:!0,followSymbolicLinks:!0,ignore:[".git/**"]}):[],y=G([...m.map(N),...h.map(N)]),b=[];for(const e of y){if(".git"===e||e.startsWith(".git/"))continue;const t=l(e)||p(e);if(("node_modules"===e||e.startsWith("node_modules/"))&&!t)continue;let n=!1;f.ignores(e)||(n=!0),l(e)&&(n=!0),u(e)&&(n=!1),p(e)&&(n=!0),n&&b.push(e)}return G(b)},J=(e,t)=>t.phaseModifier===e.SyntaxKind.TypeKeyword,V=(e,t)=>e.isStringLiteral(t)||e.isNoSubstitutionTemplateLiteral(t),Z=(e,t)=>{const n=t.importClause;return n&&(((e,t)=>t.phaseModifier===e.SyntaxKind.TypeKeyword)(e,n)||n.namedBindings&&e.isNamedImports(n.namedBindings)&&n.namedBindings.elements.every(t=>J(e,t))&&!n.name)?"type":"runtime"},U=(e,t)=>{if(t.phaseModifier===e.SyntaxKind.TypeKeyword)return!0;const n=t.exportClause;return!(!n||!e.isNamedExports(n))&&n.elements.every(t=>t.phaseModifier===e.SyntaxKind.TypeKeyword)},Q=e=>{const{ts:t,sourceFile:n}=e,i=[],s=[];for(const e of n.statements){if(t.isImportDeclaration(e)){if(!V(t,e.moduleSpecifier))continue;const n=e.moduleSpecifier.text,r=Z(t,e);i.push({specifier:n,kind:r});const o=e.importClause;if(!o)continue;if(o.namedBindings&&t.isNamespaceImport(o.namedBindings))continue;if(o.name&&s.push({specifier:n,kind:r,exportName:"default"}),o.namedBindings&&t.isNamedImports(o.namedBindings))for(const e of o.namedBindings.elements){const i=J(t,e),o="type"===r||i?"type":r,a=e.propertyName?.text??e.name.text;s.push({specifier:n,kind:o,exportName:a})}}if(t.isExportDeclaration(e)&&e.moduleSpecifier){if(!V(t,e.moduleSpecifier))continue;const n=U(t,e)?"type":"runtime";i.push({specifier:e.moduleSpecifier.text,kind:n})}if(t.isImportEqualsDeclaration(e)){const n=e.moduleReference;if(t.isExternalModuleReference(n)){const e=n.expression;if(!V(t,e))continue;i.push({specifier:e.text,kind:"runtime"})}}}const r=(e,n)=>{const s=t.isFunctionLike(e)||t.isMethodDeclaration(e)?n+1:n;if(t.isCallExpression(e)){if(e.expression.kind===t.SyntaxKind.ImportKeyword){const n=e.arguments.at(0);n&&V(t,n)&&i.push({specifier:n.text,kind:"dynamic"})}if(t.isIdentifier(e.expression)&&"require"===e.expression.text){const s=e.arguments.at(0);s&&V(t,s)&&i.push({specifier:s.text,kind:n>0?"dynamic":"runtime"})}}t.forEachChild(e,e=>{r(e,s)})};return r(n,0),{explicit:i,tunnels:s}},X=new Set([...l,...l.map(e=>e.startsWith("node:")?e:`node:${e}`)]),Y=e=>e.startsWith("node:")?e:`node:${e}`,ee={fileExists:e=>s.existsSync(e),readFile:e=>s.readFileSync(e,"utf8"),directoryExists:e=>s.existsSync(e)&&s.statSync(e).isDirectory(),getCurrentDirectory:()=>process.cwd(),getDirectories:t=>s.readdirSync(t,{withFileTypes:!0}).filter(e=>e.isDirectory()).map(n=>e.join(t,n.name)),realpath:e=>s.realpathSync(e)},te=e=>{const{ts:t,specifier:n}=e;if(i=n,X.has(i)||X.has(`node:${i}`))return{kind:"builtin",id:Y(n)};var i;const s=t.resolveModuleName(n,e.fromAbsPath,e.compilerOptions,ee).resolvedModule;return s?.resolvedFileName?{kind:"file",absPath:s.resolvedFileName,isExternalLibraryImport:!0===s.isExternalLibraryImport}:{kind:"missing",id:n}},ne=e=>e instanceof URL?p(e):e;const ie=(e,t)=>e.isStringLiteral(t)||e.isNoSubstitutionTemplateLiteral(t),se=(e,t)=>(e.isIdentifier(t),t.text),re=(e,t,n)=>{if(!e.canHaveModifiers(t))return!1;const i=e.getModifiers(t);return i?.some(e=>e.kind===n)??!1},oe=(e,t)=>re(e,t,e.SyntaxKind.ExportKeyword),ae=()=>({memo:new Map}),de=e=>{const{ts:t,entrySourceFile:n,resolveAbsPath:i,getSourceFile:s}=e,r=e.cache??ae(),o=(e,n,a)=>{const d=`${e.fileName}\0${n}`,c=r.memo.get(d);if(c)return c;if(a.has(d))return[];a.add(d);const l=(e=>{const{ts:t,sourceFile:n}=e,i=new Set;for(const e of n.statements)if(t.isFunctionDeclaration(e)&&e.name&&i.add(e.name.text),t.isClassDeclaration(e)&&e.name&&i.add(e.name.text),t.isInterfaceDeclaration(e)&&i.add(e.name.text),t.isTypeAliasDeclaration(e)&&i.add(e.name.text),t.isEnumDeclaration(e)&&i.add(e.name.text),t.isModuleDeclaration(e)&&t.isIdentifier(e.name)&&i.add(e.name.text),t.isVariableStatement(e))for(const n of e.declarationList.declarations)t.isIdentifier(n.name)&&i.add(n.name.text);return i})({ts:t,sourceFile:e}),u=(e=>{const{ts:t,sourceFile:n}=e,i=new Map;for(const e of n.statements){if(!t.isImportDeclaration(e))continue;if(!e.importClause)continue;if(!ie(t,e.moduleSpecifier))continue;const n=e.moduleSpecifier.text;e.importClause.name&&i.set(e.importClause.name.text,{kind:"default",specifier:n});const s=e.importClause.namedBindings;if(s)if(t.isNamespaceImport(s))i.set(s.name.text,{kind:"namespace",specifier:n});else if(t.isNamedImports(s))for(const e of s.elements){const s=e.name.text,r=e.propertyName?se(t,e.propertyName):e.name.text;i.set(s,{kind:"named",specifier:n,importName:r})}}return i})({ts:t,sourceFile:e}),p=[];(e=>{const{ts:t,sourceFile:n,exportName:i,localNames:s}=e;if("default"===i){for(const e of n.statements){if(t.isExportAssignment(e)&&!0!==e.isExportEquals)return!0;if(t.isFunctionDeclaration(e)&&oe(t,e)&&re(t,e,t.SyntaxKind.DefaultKeyword))return!0;if(t.isClassDeclaration(e)&&oe(t,e)&&re(t,e,t.SyntaxKind.DefaultKeyword))return!0}return!1}for(const e of n.statements){if(oe(t,e)){if((t.isFunctionDeclaration(e)||t.isClassDeclaration(e)||t.isInterfaceDeclaration(e)||t.isTypeAliasDeclaration(e)||t.isEnumDeclaration(e))&&e.name?.text===i)return!0;if(t.isVariableStatement(e))for(const n of e.declarationList.declarations)if(t.isIdentifier(n.name)&&n.name.text===i)return!0}if(t.isExportDeclaration(e)&&!e.moduleSpecifier&&e.exportClause){if(!t.isNamedExports(e.exportClause))continue;for(const n of e.exportClause.elements){if(n.name.text!==i)continue;const e=n.propertyName?se(t,n.propertyName):n.name.text;if(s.has(e))return!0}}}return!1})({ts:t,sourceFile:e,exportName:n,localNames:l})&&p.push({kind:"symbol",absPath:e.fileName,exportName:n});const f=(e=>{const{ts:t,sourceFile:n,exportName:i}=e,s=[];for(const r of n.statements)if(t.isExportDeclaration(r)){if(r.moduleSpecifier&&ie(t,r.moduleSpecifier)){const e=r.moduleSpecifier.text;if(!r.exportClause){s.push({kind:"symbol",specifier:e,importName:i});continue}if(t.isNamespaceExport(r.exportClause)){r.exportClause.name.text===i&&s.push({kind:"module",specifier:e});continue}if(t.isNamedExports(r.exportClause))for(const n of r.exportClause.elements){if(n.name.text!==i)continue;const r=n.propertyName?se(t,n.propertyName):n.name.text;s.push({kind:"symbol",specifier:e,importName:r})}continue}if(r.exportClause&&t.isNamedExports(r.exportClause))for(const n of r.exportClause.elements){if(n.name.text!==i)continue;const r=n.propertyName?se(t,n.propertyName):n.name.text;if(e.localNames.has(r))continue;const o=e.imports.get(r);if(!o)continue;if("namespace"===o.kind){s.push({kind:"module",specifier:o.specifier});continue}const a="default"===o.kind?"default":o.importName;s.push({kind:"symbol",specifier:o.specifier,importName:a})}}return s})({ts:t,sourceFile:e,exportName:n,localNames:l,imports:u});for(const t of f){const n=i(e.fileName,t.specifier);if(!n)continue;const r=s(n);r&&("module"!==t.kind?p.push(...o(r,t.importName,a)):p.push({kind:"module",absPath:r.fileName}))}const m=((e,t)=>{const n=new Set,i=[];for(const s of e){const e=t(s);n.has(e)||(n.add(e),i.push(s))}return i})(p,e=>"module"===e.kind?`module\0${e.absPath}`:`symbol\0${e.absPath}\0${e.exportName}`);return r.memo.set(d,m),a.delete(d),m};return o(n,e.exportName,new Set)},ce=new Map,le=t=>{const n=e.dirname(t);if(ce.has(n))return ce.get(n);const i=function({cwd:t}={}){const n=function(t,{cwd:n=u.cwd(),type:i="file",stopAt:r}={}){let o=e.resolve(ne(n)??"");const{root:a}=e.parse(o);r=e.resolve(o,ne(r)??a);const d=e.isAbsolute(t);for(;o;){const n=d?t:e.join(o,t);try{const e=s.statSync(n,{throwIfNoEntry:!1});if("file"===i&&e?.isFile()||"directory"===i&&e?.isDirectory())return n}catch{}if(o===r||o===a)break;o=e.dirname(o)}}("package.json",{cwd:t});return n&&e.dirname(n)}({cwd:n})??null;return ce.set(n,i),i},ue=e=>{const t=new Set,n=ae();for(const i of e.exportNames){const s=de({ts:e.ts,entrySourceFile:e.barrelSourceFile,exportName:i,resolveAbsPath:e.resolveAbsPath,getSourceFile:e.getSourceFile,cache:n});for(const n of s){if("module"===n.kind){t.add(n.absPath);continue}const i=e.getSourceFile(n.absPath);if(!i){t.add(n.absPath);continue}const s=e.checker.getSymbolAtLocation(i);if(!s){t.add(n.absPath);continue}let r=[];try{r=e.checker.getExportsOfModule(s)}catch{t.add(n.absPath);continue}const o=r.find(e=>e.getName()===n.exportName);if(!o){t.add(n.absPath);continue}const a=o.getDeclarations()??[];if(a.length)for(const e of a)t.add(e.getSourceFile().fileName);else t.add(n.absPath)}}return Array.from(t)},pe=e=>{const t=le(e.barrelAbsPath);return t?e.declarationAbsPaths.filter(e=>{const n=le(e);return null!==n&&n===t}):e.declarationAbsPaths},fe=e=>N(e).includes("/node_modules/"),me=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),ge=async e=>{const{id:t}=I(e.absPath,e.cwd),n=(i=e.existing,me(i,s=t)?i[s]:void 0);var i,s;if(n){const e=n.metadata;if(e&&"string"==typeof e.hash&&"number"==typeof e.size)return n}const r=await K({absPath:e.absPath,cwd:e.cwd,kind:e.kindHint});return e.existing[t]=r,r},he=(e,t)=>{me(e,t)||(e[t]=j({id:t,kind:"builtin",language:"other"}))},ye=(e,t)=>{me(e,t)||(e[t]=j({id:t,kind:"missing",language:"other"}))},be=c(import.meta.url),xe=["@module","@packageDocumentation"],we=e=>{const t=e.toLowerCase();return t.endsWith(".d.ts")||t.endsWith(".ts")||t.endsWith(".tsx")||t.endsWith(".js")||t.endsWith(".jsx")},ke=e=>{if("ignore"===e.mode)return[];const t=[];for(const n of Object.values(e.graph.nodes))("source"===n.kind||"external"===n.kind)&&"string"==typeof n.metadata?.hash&&"number"!=typeof n.metadata?.size&&t.push(n.id);const n=t.sort((e,t)=>e.localeCompare(t));if(!n.length)return[];if("error"===e.mode){const e=n.slice(0,10).join(", ");throw new Error(`metadata.size missing for hashed nodes (${String(n.length)}): ${e}${n.length>10?" ...":""}`)}return n.map(e=>`warning: metadata.size missing for hashed node ${e}`)},Se=async t=>{const n=[],i=t.cwd,s="number"==typeof t.nodeDescriptionLimit?t.nodeDescriptionLimit:160,r=t.nodeDescriptionTags&&t.nodeDescriptionTags.length?t.nodeDescriptionTags:Array.from(xe),o="number"==typeof t.maxErrors?t.maxErrors:50,a=t.hashSizeEnforcement??"warn",d=await _({cwd:i,config:t.config}),c=d.filter(we),l={};for(const t of d){const n=e.join(i,t);l[t]=await K({absPath:n,cwd:i,kind:"source"})}const u=await q({cwd:i,analyzableSourceIds:c,currentNodes:l,previousGraph:t.previousGraph}),p={...u.carriedNodes,...l},f={...u.reusedEdgesBySource},m=(()=>{try{return be("typescript")}catch{return null}})();if(!m){n.push("typescript peer dependency not found; returning nodes-only graph");const e=await F({cwd:i,nodes:p,nodeDescriptionLimit:s,describeSourceText:e=>S({...e,tags:r})}),t=M({nodes:e,edges:f});return n.push(...ke({graph:t,mode:a})),{graph:t,stats:{modules:Object.keys(t.nodes).length,edges:Object.values(t.edges).reduce((e,t)=>e+t.length,0),dirty:u.dirtySourceIds.size},errors:v(n,o)}}const g=(t=>{const{ts:n,cwd:i}=t,s={allowJs:!0,skipLibCheck:!0,target:n.ScriptTarget.ES2022,module:n.ModuleKind.ESNext,moduleResolution:n.ModuleResolutionKind.Node16},r=n.findConfigFile(i,e=>n.sys.fileExists(e),"tsconfig.json");if(!r)return s;const o=n.readConfigFile(r,e=>n.sys.readFile(e));if(o.error)return s;const a=n.parseJsonConfigFileContent(o.config,n.sys,e.dirname(r),void 0,r);return{...s,...a.options}})({ts:m,cwd:i}),h=await(async t=>{const{ts:n,cwd:i}=t,s={...t.baseNodes},r={},o=t.universeSourceIds.map(t=>e.resolve(i,t)),a=n.createCompilerHost(t.compilerOptions,!0);a.getCurrentDirectory=()=>i;const d=n.createProgram({rootNames:o,options:t.compilerOptions,host:a}),c=d.getTypeChecker(),l=t=>{const n=e.resolve(t),i=[t,n,N(t),N(n)];for(const e of i){const t=d.getSourceFile(e);if(t)return t}},u=new Map,p=e=>{const t=l(e);if(t)return t;const i=u.get(e);if(i)return i;const s=n.sys.readFile(e);if("string"!=typeof s)return;const r=n.createSourceFile(e,s,n.ScriptTarget.ES2022,!0);return u.set(e,r),r};for(const o of t.dirtySourceIds){const a=e.resolve(i,o),d=l(a);if(!d)continue;const{explicit:u,tunnels:f}=Q({ts:n,sourceFile:d}),m=[];for(const e of u){const r=te({ts:n,fromAbsPath:a,specifier:e.specifier,compilerOptions:t.compilerOptions});if("builtin"===r.kind){he(s,r.id),m.push({target:r.id,kind:e.kind,resolution:"explicit"});continue}if("missing"===r.kind){ye(s,r.id),m.push({target:r.id,kind:e.kind,resolution:"explicit"});continue}const{id:o}=I(r.absPath,i),d=me(s,o)&&"source"===s[o].kind||!r.isExternalLibraryImport&&!fe(r.absPath)?"source":"external";await ge({cwd:i,existing:s,absPath:r.absPath,kindHint:d}),m.push({target:o,kind:e.kind,resolution:"explicit"})}for(const e of f){const r=te({ts:n,fromAbsPath:a,specifier:e.specifier,compilerOptions:t.compilerOptions});if("file"!==r.kind)continue;const o=p(r.absPath);if(!o)continue;const d=ue({ts:n,checker:c,barrelSourceFile:o,exportNames:[e.exportName],resolveAbsPath:(e,i)=>{const s=te({ts:n,fromAbsPath:e,specifier:i,compilerOptions:t.compilerOptions});return"file"===s.kind?s.absPath:null},getSourceFile:e=>p(e)}),l=r.isExternalLibraryImport||fe(r.absPath)?pe({barrelAbsPath:r.absPath,declarationAbsPaths:d}):d;for(const t of l){const{id:n}=I(t,i),o=me(s,n)&&"source"===s[n].kind||!fe(t)&&!r.isExternalLibraryImport?"source":"external";await ge({cwd:i,existing:s,absPath:t,kindHint:o}),m.push({target:n,kind:e.kind,resolution:"implicit"})}}r[o]=m}return{nodes:s,edgesBySource:r,errors:[]}})({ts:m,cwd:i,compilerOptions:g,universeSourceIds:c,dirtySourceIds:u.dirtySourceIds,baseNodes:p}),y={...f,...h.edgesBySource},b=await F({cwd:i,nodes:h.nodes,nodeDescriptionLimit:s,describeSourceText:e=>S({...e,tags:r})}),x=M({nodes:b,edges:y});return n.push(...ke({graph:x,mode:a})),{graph:x,stats:{modules:Object.keys(x.nodes).length,edges:Object.values(x.edges).reduce((e,t)=>e+t.length,0),dirty:u.dirtySourceIds.size},errors:v([...n,...h.errors],o)}},Ne=["runtime","type","dynamic"],Ie=new Set(Ne),Ee=[...Ne],De=["builtin","missing"],Fe=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),ve=(e,t)=>Fe(e,t)?e[t]:void 0,Ce=e=>Array.from(new Set(e)),Pe=(e,t)=>{const n="number"==typeof e&&Number.isFinite(e)?Math.floor(e):Number.NaN;return Number.isFinite(n)?Math.max(t,n):t},Oe=e=>{const t=new Set,n=new Map,i=[],s=e=>{const t=n.get(e.id)??-1;e.remaining<=t||(n.set(e.id,e.remaining),i.push(e))};for(e.entries.forEach((n,i)=>{const r=(e=>{const t=`entry[${String(e.index)}]`;if("string"==typeof e.entry)return{nodeId:e.entry,depth:0,edgeKinds:e.defaultEdgeKinds};const n=e.entry[0],i=Pe(e.entry[1],0),s=(e=>{if(void 0===e.raw)return e.fallback;if(!Array.isArray(e.raw))return e.warnings.add(`Invalid edgeKinds for ${e.entryLabel}: expected array; using none.`),[];const t=e.raw.filter(e=>"string"==typeof e&&Ie.has(e)),n=Ce(t),i=e.raw.filter(e=>"string"==typeof e).filter(e=>!Ie.has(e));for(const t of Ce(i))e.warnings.add(`Invalid edgeKind for ${e.entryLabel}: ${t}; ignoring.`);return e.raw.length>0&&0===n.length&&e.warnings.add(`No valid edgeKinds for ${e.entryLabel}; no edges will be traversed.`),n})({raw:e.entry[2],fallback:e.defaultEdgeKinds,warnings:e.warnings,entryLabel:t});return"string"==typeof n&&n.trim()?(e.entry[1]!==i&&("number"!=typeof e.entry[1]||!Number.isFinite(e.entry[1])||e.entry[1]<0||Math.floor(e.entry[1])!==e.entry[1])&&e.warnings.add(`Invalid depth for ${t}: expected integer >= 0; using ${String(i)}.`),{nodeId:n,depth:i,edgeKinds:s}):(e.warnings.add(`Invalid nodeId for ${t}: expected non-empty string.`),{nodeId:"",depth:0,edgeKinds:[]})})({entry:n,defaultEdgeKinds:e.defaultEdgeKinds,warnings:e.warnings,index:i});r.nodeId&&(t.add(r.nodeId),s({id:r.nodeId,remaining:r.depth,edgeKinds:r.edgeKinds}))});i.length;){const n=i.shift();if(n.remaining<=0)continue;if(0===n.edgeKinds.length)continue;const r=ve(e.graph.edges,n.id)??[];for(const e of r)n.edgeKinds.includes(e.kind)&&(t.add(e.target),s({id:e.target,remaining:n.remaining-1,edgeKinds:n.edgeKinds}))}return t},$e=e=>("source"===e.kind||"external"===e.kind)&&"string"==typeof e.metadata?.hash,je=e=>{const t=e?.metadata?.size;return"number"==typeof t&&Number.isFinite(t)?t:0},Ke=e=>{const t=new Set,n=Ce(e.options?.defaultEdgeKinds?.filter(e=>Ie.has(e))??Ee),i=Ce(e.options?.dropNodeKinds??De),s="number"==typeof e.options?.maxTop?Pe(e.options.maxTop,0):10,r=e.options?.hashSizeEnforcement??"warn",o=Oe({graph:e.graph,entries:e.include,defaultEdgeKinds:n,warnings:t}),a=Oe({graph:e.graph,entries:e.exclude??[],defaultEdgeKinds:n,warnings:t});for(const e of a)o.delete(e);const d=[];for(const t of Array.from(o)){const n=ve(e.graph.nodes,t);n&&("builtin"===n.kind&&i.includes("builtin")||"missing"===n.kind&&i.includes("missing"))&&(o.delete(t),d.push({id:t,kind:n.kind}))}d.sort((e,t)=>e.id.localeCompare(t.id)).forEach(e=>{t.add(`Dropped ${e.kind} node from selection: ${e.id}`)});const c=Array.from(o).sort((e,t)=>e.localeCompare(t));for(const n of c)Fe(e.graph.nodes,n)||t.add(`Selected nodeId not present in graph.nodes: ${n}`);const l=[],u=[];let p=0;const f=[];for(const t of c){const n=ve(e.graph.nodes,t),i=je(n);if(p+=i,f.push({nodeId:t,bytes:i}),!n)continue;const s="source"===n.kind||"external"===n.kind,r="number"!=typeof n.metadata?.size;s&&r&&u.push(t),$e(n)&&r&&l.push(t)}const m=Ce(l).sort((e,t)=>e.localeCompare(t)),g=new Set(m),h=Ce(u).filter(e=>!g.has(e)).sort((e,t)=>e.localeCompare(t));switch(r){case"error":if(m.length>0){const e=m.slice(0,10).join(", "),t=m.length>10?" ...":"";throw new Error(`metadata.size missing for hashed nodes (${String(m.length)}): ${e}${t}`)}break;case"warn":for(const e of m)t.add(`metadata.size missing for hashed node: ${e}`)}for(const e of h)t.add(`metadata.size missing for file node: ${e}`);const y=f.slice().sort((e,t)=>t.bytes-e.bytes||e.nodeId.localeCompare(t.nodeId)).slice(0,s);return{selectedNodeIds:c,selectedCount:c.length,totalBytes:p,largest:y,warnings:Array.from(t).sort((e,t)=>e.localeCompare(t))}};export{Se as generateDependencyGraph,Ke as summarizeDependencySelection};