@nudojs/service 1.0.1 → 2.0.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/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { Node, File } from '@babel/types';
2
- import { Abs, PolyFn, AbsModuleExports, AstEnv, Phi, BMemberDiag, BCallRecord, TranspiledCallResult, NudoConstraint } from '@nudojs/core';
2
+ import { FormalParam, Abs, InterfaceSource, InterfaceTierOpts, PolyFn, AbsModuleExports, AstEnv, Phi, BMemberDiag, BCallRecord, TranspiledCallResult, NudoConstraint } from '@nudojs/core';
3
3
  export { AbsInlay, BMemberDiag, collectAbsInlays } from '@nudojs/core';
4
- import { C as CallRecord } from './config-NqDRWWpn.js';
5
- export { I as InterfaceConfig, N as NudoConfig, f as findProjectConfig, i as interfaceConfig, m as matchesEmitAllowlist } from './config-NqDRWWpn.js';
4
+ import { C as CallRecord, D as DiagnosticsLevel, A as AnalysisConfig } from './config-Cqj8zeZH.js';
5
+ export { a as AnalysisMode, b as DEFAULT_ANALYSIS_MODE, I as InterfaceConfig, N as NudoConfig, c as analysisConfig, d as clearPathEnvCaches, e as diskCacheRoot, f as findProjectConfig, i as interfaceConfig, m as matchesEmitAllowlist } from './config-Cqj8zeZH.js';
6
6
  import { HarvestedEnv } from '@nudojs/harvester';
7
7
  import { FunctionWithDirectives } from '@nudojs/parser';
8
8
 
@@ -76,6 +76,8 @@ type FunctionAnalysis = {
76
76
  name: string;
77
77
  loc: SourceLocation;
78
78
  paramNames: string[];
79
+ /** C4.1 形参表面:draft/契约对齐(解构 placeholder + bound 名) */
80
+ formals?: FormalParam[];
79
81
  cases: CaseResult[];
80
82
  /** cases 结果 Abs 的 join;dts 返回位源 */
81
83
  combinedAbs?: Abs;
@@ -90,6 +92,24 @@ type FunctionAnalysis = {
90
92
  noDeclaration?: boolean;
91
93
  /** absolute path of the module this function is imported from (externalFunctions only) */
92
94
  fromModule?: string;
95
+ /**
96
+ * HOF / entry shape 关系快照(generalizeFromAst),供 dts 泛型投影(C3.3)。
97
+ * 只存投影所需的 Abs,不挂 PolyFn 本体(缓存可克隆)。
98
+ */
99
+ hof?: {
100
+ /** 函数形参:外延关系 Abs(fn 形状,paramTypes/returnType) */
101
+ fnRels?: Array<{
102
+ param: string;
103
+ abs: Abs;
104
+ }>;
105
+ /** 值形参提升快照(如 items → arr(A1)) */
106
+ entryShapes?: Array<{
107
+ param: string;
108
+ abs: Abs;
109
+ }>;
110
+ /** 符号返回 Abs(含自由 α / B:param) */
111
+ symbolic?: Abs;
112
+ };
93
113
  };
94
114
  type BindingInfo = {
95
115
  /** 无损 Abs */
@@ -152,14 +172,18 @@ declare function buildModuleGraph(files: string[], cache?: ModuleGraphCache): {
152
172
  declare function computeDirtySet(dependents: Map<string, Set<string>>, changedFile: string): string[];
153
173
  /** Topological order with dependencies before dependents (only imports edges internal to dirty; cycles tolerated — remaining files appended in arbitrary order). */
154
174
  declare function topoSortDirty(imports: Map<string, Set<string>>, dirty: string[]): string[];
175
+ /** Optional module loader for analysis (sidecar / relative imports). */
176
+ type AnalyzeLoadModule = (spec: string, fromFile: string) => string | undefined;
155
177
  /**
156
178
  * Async entry to analyzeFile: preloads path-based env files
157
179
  * (`/// @nudo:env ./nudo-harvest-node.ts`) via dynamic import — impossible
158
180
  * synchronously in ESM — then runs the sync analysis, which picks the
159
- * preloaded factories up from the env-loader cache. The sync analyzeFile
160
- * signature is unchanged for existing consumers (LSP, MCP, vite-plugin).
181
+ * preloaded factories up from the env-loader cache.
182
+ * `loadModule` is optional; when provided it is used for relative imports /
183
+ * sidecar ambient bindings (LSP buffer-aware path). Default remains
184
+ * `defaultLoadModule` (disk).
161
185
  */
162
- declare function analyzeFileAsync(filePath: string, source: string, activeCases?: Map<string, number>, externalCallRecords?: CallRecord[]): Promise<AnalysisResult>;
186
+ declare function analyzeFileAsync(filePath: string, source: string, activeCases?: Map<string, number>, externalCallRecords?: CallRecord[], loadModule?: AnalyzeLoadModule): Promise<AnalysisResult>;
163
187
  /**
164
188
  * 调用点发现(阶段一):在"使用现场"文件(测试 / 上层应用)中求值
165
189
  * 顶层代码,收集它对(外部模块导出的)函数的调用记录。每条记录带
@@ -171,16 +195,32 @@ declare function analyzeFileAsync(filePath: string, source: string, activeCases?
171
195
  * 依赖未 mock 的全局,收集不到就收集不到,不能拖垮主分析)。
172
196
  */
173
197
  declare function collectCallRecords(filePath: string, source: string): CallRecord[];
198
+ declare function analysisFileCacheKey(filePath: string, source: string, activeCases?: Map<string, number>, externalCallRecords?: CallRecord[], analysisCfg?: {
199
+ mode: string;
200
+ evalMissingSlot: string;
201
+ callSiteBudget: number;
202
+ diagnostics: string;
203
+ }, loadModule?: AnalyzeLoadModule, projectEnvNames?: string[],
204
+ /** ambient 侧车绑定:变更必须 miss(dep 指纹故意不编码 autoBind) */
205
+ autoBind?: boolean): {
206
+ filePath: string;
207
+ source: string;
208
+ auxKey: string;
209
+ noCache?: boolean;
210
+ };
174
211
  /**
175
212
  * 整文件分析。同 (path, source, cases, external) 命中 memo → O(1)。
176
213
  * 不再每次 clearBPathCache:B 路径按本文件 source 键控。
177
214
  *
215
+ * `loadModule`:可选;提供时用于相对 import / 侧车 ambient(LSP
216
+ * buffer-aware)。未提供时走 defaultLoadModule(磁盘)。
217
+ *
178
218
  * 宿主契约:入口 source 未变但依赖模块内容变了时,必须调用
179
219
  * `evictBPathCacheForFiles` / `evictAnalysisFileCacheForFiles` /
180
220
  * `evictFnAnalysisCacheForFiles`(LSP 已接好)。非 LSP 宿主
181
221
  * (CLI watch / vite-plugin)在 dep 变更时应 `clearBPathCache()` 或上述逐出。
182
222
  */
183
- declare function analyzeFile(filePath: string, source: string, activeCases?: Map<string, number>, externalCallRecords?: CallRecord[]): AnalysisResult;
223
+ declare function analyzeFile(filePath: string, source: string, activeCases?: Map<string, number>, externalCallRecords?: CallRecord[], loadModule?: AnalyzeLoadModule): AnalysisResult;
184
224
 
185
225
  type CaseInfo = {
186
226
  functionName: string;
@@ -214,7 +254,13 @@ type HoverInfo = {
214
254
  abs?: string;
215
255
  /** 无损 Abs 多行展示 */
216
256
  absMultiline?: string;
257
+ /** CodeLens `● interface` 同源档位(A7);仅本地 named export */
258
+ interfaceSource?: InterfaceSource;
259
+ /** 有效契约展示(handwritten/generated);implicit 为 undefined */
260
+ interfaceDisplay?: string;
217
261
  };
262
+ /** A7:hover/inlay 与 CodeLens interface 档同源(design-refine-derivation §8) */
263
+ type HoverInterfaceOpts = InterfaceTierOpts;
218
264
  /**
219
265
  * LSP hover:优先无损 Abs(类型即计算本体)。
220
266
  * 节点表也是 Abs(collectAbsNodeTypes),不经 bridge。
@@ -223,8 +269,12 @@ type HoverInfo = {
223
269
  * intension 一律走 generalize/formatPoly(HOF fnRels 在这里);
224
270
  * typeText 仍落 B-path Abs(调用点显示结果类型,不是函数签名)。
225
271
  * 禁止用 B-path 的 arity-only fn Abs 冒充权威关系源。
272
+ *
273
+ * A7 default 档:函数名 hover 附带 interfaceTierOf 来源 + 契约展示,
274
+ * 与 CodeLens `● interface / <source>` 同源;选 case 时 body 仍走
275
+ * activeCases 重放,interface 档标注不变。
226
276
  */
227
- declare function getHoverAtPosition(filePath: string, source: string, line: number, column: number, activeCases?: Map<string, number>): HoverInfo | null;
277
+ declare function getHoverAtPosition(filePath: string, source: string, line: number, column: number, activeCases?: Map<string, number>, opts?: HoverInterfaceOpts): HoverInfo | null;
228
278
  declare function getCompletionsAtPosition(filePath: string, source: string, line: number, column: number): CompletionItem[];
229
279
 
230
280
  /**
@@ -305,8 +355,10 @@ declare function serializeInferJson(result: AnalysisResult, file: string): Infer
305
355
  * 一律 false。显式排除:
306
356
  * - .d.ts —— 类型声明文件(harvester 的输入),不是可求值的实现源码;
307
357
  * - .tsx / .jsx —— JSX 构造的求值超出 nudo 推断器范围;
308
- * - *.nudo.js / *.nudo.ts —— 侧车契约模块(interface 绑定源),不是源码
309
- * 推断目标;目录级 check/infer/doctor 展开不得把它们当实现分析。
358
+ * - *.nudo.js / *.nudo.mjs / *.nudo.ts —— 侧车契约模块(interface 绑定源),
359
+ * 不是源码推断目标;目录级 check/infer/doctor 展开不得把它们当实现分析;
360
+ * - *.nudo.draft.js / *.nudo.draft.mjs / *.nudo.draft.ts —— draft 产物,
361
+ * 明确不被 ambient 绑定,也不得当实现源码分析。
310
362
  *
311
363
  * 消费方:CLI 的 collectNudoFiles/watch 过滤/doctor 目录展开(.ts 放开后统一
312
364
  * 走本函数,避免各处手写 endsWith 漂移),以及 LSP 的 isNudoFile(接线由
@@ -314,6 +366,51 @@ declare function serializeInferJson(result: AnalysisResult, file: string): Infer
314
366
  */
315
367
  declare function isNudoTargetPath(path: string): boolean;
316
368
 
369
+ /** Formal sidecar contracts only — drafts never ambient-bind and need not reanalyze */
370
+ declare function isSidecarPath(path: string): boolean;
371
+ declare function isProjectConfigPath(path: string): boolean;
372
+ /** Watch accept gate: analysis targets + sidecar/config/env-template invalidators */
373
+ declare function isWatchRelevantPath(path: string): boolean;
374
+ /** `lib.nudo.js|ts` → candidate ambient sources next to it */
375
+ declare function ambientSourcesOfSidecar(sidecarPath: string): string[];
376
+
377
+ /** 源码里的 path-based load specs 解析为绝对路径后登记反向边 */
378
+ declare function noteEnvPathDeps(sourcePath: string, source: string): void;
379
+ /** 依赖该 env 模板的源文件列表 */
380
+ declare function envPathDependents(envPath: string): string[];
381
+ declare function clearEnvPathDeps(): void;
382
+ /** watch 门禁:env 模板变更必须可被接收(即便扩展名不进 isNudoTargetPath) */
383
+ declare function isEnvTemplatePath(path: string): boolean;
384
+
385
+ /**
386
+ * 分析范围判定(A1/A2,design-analysis-scope.md)。
387
+ * CLI 显式路径不受 mode 限制;本模块供 LSP/watch 自动验证使用。
388
+ */
389
+
390
+ /**
391
+ * 按 analysis.diagnostics 档过滤 evaluator/check **显示路径**诊断。
392
+ * - off:显示层全静音(与 errors 档区分)。check 门禁(CLI `nudo check` /
393
+ * checkSource)独立于本过滤,不受 off 影响。
394
+ * - errors:只发 severity=error
395
+ * - default:error + warning(静音 NOISY_WARNING_CODES)
396
+ * - verbose:全量
397
+ */
398
+ declare function filterDiagnosticsByLevel<T extends {
399
+ severity: string;
400
+ code?: string;
401
+ }>(diags: T[], level: DiagnosticsLevel): T[];
402
+ declare function diagnosticsLevelForFile(filePath: string): DiagnosticsLevel;
403
+ declare function hasNudoDirectives(source: string): boolean;
404
+ /**
405
+ * 是否应对该文件跑分析(自动路径,如 LSP validate)。
406
+ * - 非 target 路径 → false
407
+ * - exclude 命中 / include 未命中 → false
408
+ * - mode=directives → 仅有指令
409
+ * - mode=exports → 指令 | export | 同名侧车
410
+ * - mode=all → true
411
+ */
412
+ declare function shouldAnalyzeFile(filePath: string, source: string | undefined, config?: AnalysisConfig): boolean;
413
+
317
414
  /**
318
415
  * 相对/绝对 specifier → 模块源码。
319
416
  * CLI / LSP / vite / check 共用同一扩展名表,避免门禁结果分叉。
@@ -565,6 +662,129 @@ declare function clearAnalysisSessionCaches(): void;
565
662
  /** 比 clearAnalysisSessionCaches 更彻底:再丢 AST LRU(测试 / 进程复用场景) */
566
663
  declare function resetAllAnalysisCaches(): void;
567
664
 
665
+ /**
666
+ * B5:workspace 级 AnalysisSession——LSP 与 CLI(同进程)共享的分析 memo 面。
667
+ *
668
+ * core/service 的 analyzeFile / B-path / generalize / checkSource 都是
669
+ * 进程级模块缓存;本模块把「清空 / 定向逐出 / 依赖变更」收成一个显式
670
+ * session 对象,避免宿主各接一套失效逻辑,也便于测试隔离。
671
+ *
672
+ * 宿主契约:
673
+ * - 依赖内容变更 → `session.evictForDependents(files)`
674
+ * - 全量重置(watch 批前 / vite buildStart)→ `session.clear()`
675
+ * - LSP validate 与 agent check/hover/interface 在同一进程共用默认 session
676
+ */
677
+
678
+ type AnalysisSession = {
679
+ /** 依赖变更:按「以这些文件为入口」的路径定向逐出 */
680
+ evictForDependents(files: string[]): void;
681
+ /** 清空 service+core 会话 memo(不含 AST LRU) */
682
+ clear(): void;
683
+ /** 彻底重置(含 AST LRU) */
684
+ reset(): void;
685
+ /**
686
+ * 与 analyzeFile 同源,但强制走本 session 的 memo(进程内默认即共享)。
687
+ * LSP / CLI / agent 工具都应调用这里,而不是旁路第二套缓存。
688
+ */
689
+ analyze(filePath: string, source: string, activeCases?: Map<string, number>, externalCallRecords?: unknown): AnalysisResult;
690
+ };
691
+ /** 进程内默认 AnalysisSession(LSP server / CLI watch / agent tools 共用) */
692
+ declare function getAnalysisSession(): AnalysisSession;
693
+ /** 测试:替换默认 session(返回旧值以便恢复) */
694
+ declare function setAnalysisSession(session: AnalysisSession | undefined): AnalysisSession | undefined;
695
+
696
+ /**
697
+ * 磁盘内容寻址缓存(B3,design-persistent-cache.md L1 骨架)。
698
+ * - 键:sha256(analysisAbi + relative paths + content hashes + import deps)
699
+ * - fail-open:读写失败/版本不符 → miss,绝不 throw
700
+ * - 不存 Abs;只存可 JSON 再执行投影(如 CheckJson)
701
+ * - 缓存根解析见 `evaluator/config.ts` 的 `diskCacheRoot`(唯一入口)
702
+ */
703
+ /**
704
+ * 带包版本:升级 @nudojs/* 后旧 CheckJson 不得继续命中。
705
+ * 语义大改仍可手工再抬 major(`nudo-check-cache-v3`)。
706
+ */
707
+ declare const ANALYSIS_ABI: string;
708
+ type DiskCacheOptions = {
709
+ /** 缓存根目录;undefined = 禁用 */
710
+ root?: string | undefined;
711
+ /** 命名空间子目录(check / interface …) */
712
+ namespace: string;
713
+ };
714
+ declare function sha256Hex(data: string | Buffer): string;
715
+ /** 相对化路径,避免绝对路径进磁盘键;树外路径用稳定内容 hash */
716
+ declare function relativizePath(p: string, root?: string): string;
717
+ declare class DiskCache {
718
+ private readonly root;
719
+ private readonly ns;
720
+ enabled: boolean;
721
+ constructor(opts: DiskCacheOptions);
722
+ private pathFor;
723
+ get<T>(key: string): T | undefined;
724
+ set(key: string, value: unknown): void;
725
+ clearNamespace(): void;
726
+ }
727
+ /**
728
+ * check 报告键:abi + 相对路径 + 源码 sha + autoBind + **侧车 sha** +
729
+ * **@nudo:import / 传递契约依赖内容 sha**(依赖变更必须 miss)。
730
+ * dep 路径同样相对化(`relativizePath`):绝对路径进键会让同内容在不同
731
+ * 机器/checkout 上键不同,缓存无法跨环境复用。
732
+ */
733
+ declare function checkCacheKey(filePath: string, source: string, opts: {
734
+ autoBind: boolean;
735
+ projectDir?: string;
736
+ sidecarContent?: string | null;
737
+ depContents?: Array<{
738
+ path: string;
739
+ content: string | null;
740
+ }>;
741
+ /** package.json#nudo.env 等项目维(named env 不在 path-dep 指纹里) */
742
+ projectEnvNames?: string[];
743
+ /** analysis knobs that can change check surface */
744
+ analysisCfg?: {
745
+ mode?: string;
746
+ evalMissingSlot?: string;
747
+ callSiteBudget?: number;
748
+ };
749
+ }): string;
750
+ /**
751
+ * effectiveInterface 表键(L1 Phase B,design-persistent-cache)。
752
+ * 维度:相对路径 + 源码 sha256 + autoBind + 侧车内容 sha256 + import 依赖
753
+ * (dep 路径相对化,与 checkCacheKey 同口径)。
754
+ * **不含** emit allowlist(白名单不影响契约读取)。
755
+ */
756
+ declare function ifaceCacheKey(filePath: string, source: string, opts: {
757
+ autoBind: boolean;
758
+ projectDir?: string;
759
+ /** 侧车源码(已读入);undefined = 无侧车或 autoBind 关 */
760
+ sidecarSource?: string | undefined;
761
+ depContents?: Array<{
762
+ path: string;
763
+ content: string | null;
764
+ }>;
765
+ projectEnvNames?: string[];
766
+ }): string;
767
+ /** 从源码提取 `@nudo:import` / `@nudo:import * as` 的 specifier */
768
+ declare function extractNudoImportSpecs(source: string): string[];
769
+
770
+ /**
771
+ * check/iface 磁盘缓存键的依赖内容采集。
772
+ * 走 core `loadModuleDepsFingerprint`:覆盖 ESM from / require / dynamic import /
773
+ * `@nudo:import` / ambient 侧车闭包——不只 `@nudo:import` 注释。
774
+ *
775
+ * 内容必须优先取 loadModule 解析结果(fingerprint.contents),不得回读磁盘:
776
+ * LSP buffer-aware loadModule 与自定义 loader 的内容可能与磁盘不一致,
777
+ * 回读会让缓存键分叉(buffer 编辑后仍命中磁盘旧内容)。
778
+ */
779
+ type DepContent = {
780
+ path: string;
781
+ content: string | null;
782
+ };
783
+ declare function collectLoadDepContents(filePath: string, source: string, loadModule: (spec: string, fromFile: string) => string | undefined): {
784
+ depContents: DepContent[];
785
+ truncated: boolean;
786
+ };
787
+
568
788
  /**
569
789
  * B 路径静态诊断(AST,不执行):
570
790
  * - unreachable:同块 return/throw 之后的语句
@@ -626,10 +846,11 @@ declare function summarizeNodeEnv(env: HarvestedEnv): {
626
846
  * 与 LSP server capabilities 里声明的 legend 必须逐字对齐——server.ts 直接
627
847
  * 导入本常量注册,保证「提取端索引」与「客户端图例」单一来源。
628
848
  * 顺序沿用 lsp 包原 legend(function/variable/parameter/property 在前),
629
- * 末尾追加 method(对象字面量方法键),只追加不重排,客户端索引稳定。
849
+ * 末尾追加 method(对象字面量方法键)与 interface 档 modifier(A7),
850
+ * 只追加不重排,客户端索引稳定。
630
851
  */
631
852
  declare const SEMANTIC_TOKEN_TYPES: readonly ["function", "variable", "parameter", "property", "type", "keyword", "string", "number", "comment", "decorator", "method"];
632
- declare const SEMANTIC_TOKEN_MODIFIERS: readonly ["declaration", "readonly", "deprecated", "unreachable"];
853
+ declare const SEMANTIC_TOKEN_MODIFIERS: readonly ["declaration", "readonly", "deprecated", "unreachable", "contract", "generated", "derived"];
633
854
  type SemanticToken = {
634
855
  line: number;
635
856
  char: number;
@@ -639,6 +860,11 @@ type SemanticToken = {
639
860
  };
640
861
  /** LSP 标准相对五元组编码:deltaLine/deltaStartChar/length/tokenType/tokenModifiers。 */
641
862
  declare function encodeSemanticTokens(tokens: SemanticToken[]): number[];
863
+ /** A7:interface 档 → semantic token modifier(与 CodeLens 同源) */
864
+ declare function interfaceTierModifierBit(src: InterfaceSource): number;
865
+ type BuildSemanticTokensOpts = InterfaceTierOpts & {
866
+ loadModule?: (spec: string, fromFile: string) => string | undefined;
867
+ };
642
868
  /**
643
869
  * 从源码提取 semantic tokens 并按 LSP 相对编码返回扁平 number[]。
644
870
  *
@@ -648,15 +874,24 @@ declare function encodeSemanticTokens(tokens: SemanticToken[]): number[];
648
874
  * - 函数声明/函数表达式的名字 → function;所有函数的参数 → parameter;
649
875
  * - 对象字面量的键:值为函数 → method,否则 property。
650
876
  *
877
+ * A7:本地 named export 的函数绑定额外带 interface 档 modifier
878
+ * (contract / generated / derived),与 CodeLens `● interface` 同源。
879
+ * 非导出绑定只带 declaration,不假装进档。
880
+ *
651
881
  * 推断优先 Abs 模块图绑定(TypeValue 退出主路径);失败时复用
652
882
  * evaluateProgram。解析失败返回 []。
653
883
  */
654
- declare function buildSemanticTokens(filePath: string, source: string): number[];
884
+ declare function buildSemanticTokens(filePath: string, source: string, opts?: BuildSemanticTokensOpts): number[];
655
885
 
656
- /** Abs → TS 类型串。有损:pred / 非 lit term 落到 shape 基类型。 */
657
- declare function absToTSType(a: Abs): string;
886
+ /**
887
+ * Abs → TS 类型串。有损:pred / 非 lit term 落到 shape 基类型。
888
+ * `typeVars`:term var id → TS 类型参数名(HOF 泛型投影时传入;
889
+ * `any`+var 在此映射下渲染为该参数名,否则 `unknown`)。
890
+ */
891
+ declare function absToTSType(a: Abs, typeVars?: Map<string, string>): string;
658
892
  /**
659
893
  * 为单个函数生成 .d.ts 声明行(JSDoc + 单一 widen 主签名)。
894
+ * 有 hof 关系时优先泛型投影(C3.3);否则 case-widen。
660
895
  * service 的 generateDts 与 CLI `--dts`(infer/watch)共用本函数,
661
896
  * 两条路径输出保持一致。
662
897
  */
@@ -748,6 +983,10 @@ declare function mockDirectivesToAbsSeeds(functions: Array<{
748
983
  * autoBind 沿 package.json#nudo.interface(findProjectConfig → interfaceConfig)
749
984
  * 下传,可用 opts 覆盖(测试 / CLI 显式开关);读盘用 defaultLoadModule
750
985
  * (与 check 的 refine 解析同一扩展名表)。
986
+ *
987
+ * B3 Phase B:`nudo.cache` / NUDO_CACHE_DIR 打开时,整文件 effectiveInterface
988
+ * 表(含 implicit 负缓存 null)落盘;二次冷启动跳过侧车 exec / 契约合并。
989
+ * 缓存只服务打印/表面,不加速 B-path 分析(design-persistent-cache §0)。
751
990
  */
752
991
 
753
992
  type InterfaceSurfaceEntry = {
@@ -768,6 +1007,8 @@ type InterfaceSurfaceOpts = {
768
1007
  loadModule?: LoadModule;
769
1008
  /** 跨文件调用记录(--callsites 采集):implicit 展示的实参域原料 */
770
1009
  records?: CallRecord[];
1010
+ /** 打开 buffer 覆盖磁盘源码(E5:agent/LSP 与 hover 同口径) */
1011
+ source?: string;
771
1012
  };
772
1013
  /** 单条 interface 打印行(CLI runInterface 与 LSP agent 面共用) */
773
1014
  declare function formatInterfaceSurfaceLine(e: InterfaceSurfaceEntry): string;
@@ -816,6 +1057,10 @@ type EmitInterfaceOpts = {
816
1057
  * 外部使用现场记录)的投影原料;缺省时仅用本文件调用点证据。
817
1058
  */
818
1059
  records?: CallRecord[];
1060
+ /** 缓冲源(E5:agent/LSP 与 validate 同源);缺省读盘 */
1061
+ source?: string;
1062
+ /** 模块装载器(buffer-aware 侧车可见);缺省 defaultLoadModule */
1063
+ loadModule?: (spec: string, fromFile: string) => string | undefined;
819
1064
  };
820
1065
  type EmitInterfaceResult = {
821
1066
  written: string[];
@@ -849,6 +1094,112 @@ declare function emitInterface(filePath: string, opts: EmitInterfaceOpts): Promi
849
1094
  */
850
1095
  declare function formatEmitSummary(sourcePath: string, sidecarRel: string, result: EmitInterfaceResult): string[];
851
1096
 
1097
+ /**
1098
+ * `nudo interface --draft`:从已有 JS **逻辑** 生成 interface 草稿。
1099
+ *
1100
+ * 产品位(代码优先 / 迁移):先写实现,再反推可审阅的 `fn({…}, …)` 草稿;
1101
+ * 人审后迁入 `*.nudo.js` 才成为契约。
1102
+ *
1103
+ * 证据分层(与 C0 一致:草稿 ≠ ambient 义务):
1104
+ * - callsite / directive case → joinThenProject 值域(迁移最可信)
1105
+ * - body 触达(**仅草稿展示**)→ 参数上被读到的字段名建议;不进 check
1106
+ * - generalize symbolic → 返回位兜底
1107
+ * - 无证据 → 参数槽省略 + 注释 TODO(不发明义务)
1108
+ * - 已有 handwritten 契约 → **跳过**(手写优先,不覆盖)
1109
+ *
1110
+ * 写盘:默认只打印;`--write` 写入 `<file>.nudo.draft.js`——**不会**被
1111
+ * sidecar 自动绑定(loadModule 只认 `*.nudo.js`)。审阅后复制进正式侧车。
1112
+ */
1113
+
1114
+ /**
1115
+ * DraftEvidence `body` = 仅来自函数体对形参的成员读取(草稿建议,非义务)。
1116
+ * check / effectiveInterface **永不**消费该档。
1117
+ */
1118
+ type DraftEvidence = "callsite" | "directive" | "symbolic" | "body" | "none";
1119
+ type InterfaceDraftEntry = {
1120
+ fn: string;
1121
+ /** 全部形参(含无证据槽,便于人读) */
1122
+ params: Array<{
1123
+ name: string;
1124
+ constraint?: NudoConstraint;
1125
+ display: string;
1126
+ /** false = 无证据,DSL 对象里省略该槽 */
1127
+ projected: boolean;
1128
+ /** 函数体读到的字段名(草稿建议;与 projected 无关) */
1129
+ bodyAccesses?: string[];
1130
+ }>;
1131
+ returns?: {
1132
+ constraint?: NudoConstraint;
1133
+ display: string;
1134
+ projected: boolean;
1135
+ };
1136
+ paramEvidence: DraftEvidence;
1137
+ returnEvidence: DraftEvidence;
1138
+ skipped?: "handwritten" | "not-an-export";
1139
+ /** 草稿 DSL:`fn({ … }, …)`;handwritten / 非导出时 undefined */
1140
+ dsl?: string;
1141
+ };
1142
+ type InterfaceDraftOpts = {
1143
+ fnNames?: string[];
1144
+ records?: CallRecord[];
1145
+ loadModule?: LoadModule;
1146
+ /**
1147
+ * Accepted for API compatibility; **ignored**. The handwritten-contract probe
1148
+ * always uses `effectiveInterface(..., { autoBind: true })` so draft skips
1149
+ * disk sidecars even when ambient autoBind is off (product: draft asks
1150
+ * "does a contract already exist?", not "is ambient binding on?").
1151
+ */
1152
+ autoBind?: boolean;
1153
+ /** 默认 true:收集 body 成员读取作草稿建议(永不进 check) */
1154
+ bodyAccesses?: boolean;
1155
+ /** 打开 buffer 源(E5:与 hover/interface 同口径) */
1156
+ source?: string;
1157
+ };
1158
+ type InterfaceDraftResult = {
1159
+ file: string;
1160
+ entries: InterfaceDraftEntry[];
1161
+ draftSource: string;
1162
+ sidecarPath: string;
1163
+ };
1164
+ /**
1165
+ * Draft-only:收集每个顶层函数形参上的成员读取键(`user.name` → name)。
1166
+ * **不是** C0 禁止的 body→义务通道——只进草稿注释/建议,check 不读此表。
1167
+ */
1168
+ declare function collectParamBodyAccesses(source: string): Map<string, Map<string, Set<string>>>;
1169
+ /**
1170
+ * 为单文件顶层导出生成 interface 草稿(不写盘)。
1171
+ * handwritten 跳过;已有 @generated 仍出草稿(便于对照)。
1172
+ */
1173
+ declare function draftInterface(filePath: string, opts?: InterfaceDraftOpts): Promise<InterfaceDraftResult>;
1174
+ /** 草稿模块文本(人读 + 可复制到 *.nudo.js / *.nudo.ts) */
1175
+ declare function formatDraftModule(filePath: string, entries: InterfaceDraftEntry[], sidecarPath?: string): string;
1176
+ /** `lib.js|ts` → `lib.nudo.draft.js|ts`(不进 ambient sidecar 表) */
1177
+ declare function sidecarDraftPath(filePath: string): string;
1178
+ type WriteDraftResult = {
1179
+ draftPath: string;
1180
+ written: boolean;
1181
+ changed: boolean;
1182
+ draftable: boolean;
1183
+ draftSource: string;
1184
+ };
1185
+ /** Parse-layer draftable: at least one entry has generated DSL and was not skipped */
1186
+ declare function isDraftableEntry(entries: ReadonlyArray<Pick<InterfaceDraftEntry, "dsl" | "skipped">>): boolean;
1187
+ /**
1188
+ * 写入 `*.nudo.draft.js`(覆盖草稿文件本身;不碰正式 `*.nudo.js`)。
1189
+ * 基础路径防护:拒绝 node_modules;拒绝 draft 路径与正式侧车重合;
1190
+ * 拒绝 draft 路径落在源文件目录之外的穿越。
1191
+ *
1192
+ * `opts.entries` / `opts.draftable`:解析层判定(优先)。缺省时用 Unicode
1193
+ * 感知 export 正则兜底——`\w` 会静默丢掉 `计算` 这类标识符。
1194
+ */
1195
+ declare function writeInterfaceDraft(filePath: string, draftSource: string, opts?: {
1196
+ dryRun?: boolean;
1197
+ projectDir?: string;
1198
+ entries?: ReadonlyArray<Pick<InterfaceDraftEntry, "dsl" | "skipped">>;
1199
+ draftable?: boolean;
1200
+ }): WriteDraftResult;
1201
+ declare function formatDraftSummary(sourceRel: string, draftRel: string, result: InterfaceDraftResult, write?: WriteDraftResult): string[];
1202
+
852
1203
  /**
853
1204
  * Root 驱动的契约下行(design-refine-derivation §4.2 / §11 Phase 2)。
854
1205
  *
@@ -970,4 +1321,4 @@ declare function emitDerivedFromRoot(rootFile: string, opts: {
970
1321
  refreshExistingOnly?: boolean;
971
1322
  }): EmitDerivedResult;
972
1323
 
973
- export { type AbsGraphOptions, type AbsMockSeeds, type AbsModuleCacheEntry, type AbsModuleGraphResult, type AbsModuleLoadIssue, type AnalysisResult, type BPathBuiltinUnknown, type BPathDiagnostics, type BPathRunResult, type BPathUnreachable, type BindingInfo, CallRecord, type CaseHint, type CaseInfo, type CaseResult, type CompletionItem, type ConstraintSourceExpr, type DerivedExport, type DerivedParam, type Diagnostic, type DiagnosticSeverity, type DiagnosticTag, type EmitDerivedResult, type EmitInterfaceOpts, type EmitInterfaceResult, type EmitInterfaceSkipReason, type EmitResult, type EmitSkipReason, type FunctionAnalysis, type HoverInfo, type InferJson, type InferJsonCase, type InferJsonFunction, type InterfaceSurfaceEntry, type InterfaceSurfaceOpts, type LoadModule, type ModuleExports, type ModuleGraphCache, type NodeEnvResult, type PackageHarvest, type ReferenceInfo, type RootDeriveOpts, type RootDeriveResult, SEMANTIC_TOKEN_MODIFIERS, SEMANTIC_TOKEN_TYPES, type SemanticToken, type SourceLocation, type SymbolInfo, type SymbolTable, absToTSType, absToZodSchema, analyzeExportsFromSource, analyzeFile, analyzeFileAsync, autoHarvestModules, barePackageName, bareSpecToAbsModules, buildCaseDirective, buildModuleGraph, buildSemanticTokens, clearAbsModuleCache, clearAnalysisFileCache, clearAnalysisSessionCaches, clearBPathCache, clearFnAnalysisCache, clearHarvestCache, collectAbsBindingsFromGraph, collectBPathDiagnostics, collectBPathReplacements, collectBarePackages, collectCallRecords, collectDependencySpecs, collectDtsFromEntry, collectEnvGlobals, collectEnvModules, collectStaticImports, computeDirtySet, defaultAbsLoadModule, defaultLoadModule, deriveFromRoot, emitDerivedFromRoot, emitInterface, encodeSemanticTokens, evalAbsModuleGraph, evalProgramAbsWithModules, evictAbsModuleCacheFiles, evictAnalysisCachesForFiles, evictAnalysisFileCacheForFiles, evictBPathCacheForFiles, evictFnAnalysisCacheForFiles, extractFnConstraintSources, formatDerivedSection, formatEmitSummary, formatHarvestSummary, formatInterfaceSurfaceLine, generateDts, generateFunctionDtsLines, generateGuardFunction, generateGuardFunctionFromAbs, getAbsAtPosition, getAbsAtPositionAsync, getAnalysisFileCacheSize, getCasesForFile, getCompletionsAtPosition, getHoverAtPosition, getTypeAtPosition, getTypeAtPositionAsync, harvestNodeTypes, harvestPackage, harvestPackageCached, harvestToAbsModules, harvestedValueToAbs, insertGeneratedCaseDirectives, interfaceSurface, isBPathCapable, isNudoTargetPath, lookupHarvested, mockDirectivesToAbsSeeds, packageHarvestToAbsModules, resetAllAnalysisCaches, resolvePackageRoot, serializeCaseArg, serializeInferJson, stripGeneratedCaseDirectives, summarizeNodeEnv, topoSortDirty, tryBPathCall, tryBPathCallFull, tryRunBPath, unifiedDiff };
1324
+ export { ANALYSIS_ABI, type AbsGraphOptions, type AbsMockSeeds, type AbsModuleCacheEntry, type AbsModuleGraphResult, type AbsModuleLoadIssue, AnalysisConfig, type AnalysisResult, type AnalysisSession, type BPathBuiltinUnknown, type BPathDiagnostics, type BPathRunResult, type BPathUnreachable, type BindingInfo, type BuildSemanticTokensOpts, CallRecord, type CaseHint, type CaseInfo, type CaseResult, type CompletionItem, type ConstraintSourceExpr, type DepContent, type DerivedExport, type DerivedParam, type Diagnostic, type DiagnosticSeverity, type DiagnosticTag, DiagnosticsLevel, DiskCache, type DiskCacheOptions, type DraftEvidence, type EmitDerivedResult, type EmitInterfaceOpts, type EmitInterfaceResult, type EmitInterfaceSkipReason, type EmitResult, type EmitSkipReason, type FunctionAnalysis, type HoverInfo, type InferJson, type InferJsonCase, type InferJsonFunction, type InterfaceDraftEntry, type InterfaceDraftOpts, type InterfaceDraftResult, type InterfaceSurfaceEntry, type InterfaceSurfaceOpts, type LoadModule, type ModuleExports, type ModuleGraphCache, type NodeEnvResult, type PackageHarvest, type ReferenceInfo, type RootDeriveOpts, type RootDeriveResult, SEMANTIC_TOKEN_MODIFIERS, SEMANTIC_TOKEN_TYPES, type SemanticToken, type SourceLocation, type SymbolInfo, type SymbolTable, type WriteDraftResult, absToTSType, absToZodSchema, ambientSourcesOfSidecar, analysisFileCacheKey, analyzeExportsFromSource, analyzeFile, analyzeFileAsync, autoHarvestModules, barePackageName, bareSpecToAbsModules, buildCaseDirective, buildModuleGraph, buildSemanticTokens, checkCacheKey, clearAbsModuleCache, clearAnalysisFileCache, clearAnalysisSessionCaches, clearBPathCache, clearEnvPathDeps, clearFnAnalysisCache, clearHarvestCache, collectAbsBindingsFromGraph, collectBPathDiagnostics, collectBPathReplacements, collectBarePackages, collectCallRecords, collectDependencySpecs, collectDtsFromEntry, collectEnvGlobals, collectEnvModules, collectLoadDepContents, collectParamBodyAccesses, collectStaticImports, computeDirtySet, defaultAbsLoadModule, defaultLoadModule, deriveFromRoot, diagnosticsLevelForFile, draftInterface, emitDerivedFromRoot, emitInterface, encodeSemanticTokens, envPathDependents, evalAbsModuleGraph, evalProgramAbsWithModules, evictAbsModuleCacheFiles, evictAnalysisCachesForFiles, evictAnalysisFileCacheForFiles, evictBPathCacheForFiles, evictFnAnalysisCacheForFiles, extractFnConstraintSources, extractNudoImportSpecs, filterDiagnosticsByLevel, formatDerivedSection, formatDraftModule, formatDraftSummary, formatEmitSummary, formatHarvestSummary, formatInterfaceSurfaceLine, generateDts, generateFunctionDtsLines, generateGuardFunction, generateGuardFunctionFromAbs, getAbsAtPosition, getAbsAtPositionAsync, getAnalysisFileCacheSize, getAnalysisSession, getCasesForFile, getCompletionsAtPosition, getHoverAtPosition, getTypeAtPosition, getTypeAtPositionAsync, harvestNodeTypes, harvestPackage, harvestPackageCached, harvestToAbsModules, harvestedValueToAbs, ifaceCacheKey, insertGeneratedCaseDirectives, interfaceSurface, interfaceTierModifierBit, isBPathCapable, isDraftableEntry, isEnvTemplatePath, isNudoTargetPath, isProjectConfigPath, isSidecarPath, isWatchRelevantPath, lookupHarvested, mockDirectivesToAbsSeeds, noteEnvPathDeps, packageHarvestToAbsModules, relativizePath, resetAllAnalysisCaches, resolvePackageRoot, serializeCaseArg, serializeInferJson, setAnalysisSession, sha256Hex, shouldAnalyzeFile, sidecarDraftPath, hasNudoDirectives as sourceHasNudoDirectives, stripGeneratedCaseDirectives, summarizeNodeEnv, topoSortDirty, tryBPathCall, tryBPathCallFull, tryRunBPath, unifiedDiff, writeInterfaceDraft };