@happyvertical/smrt-scanner 0.45.1 → 0.45.3

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.
Files changed (2) hide show
  1. package/AGENTS.md +33 -92
  2. package/package.json +1 -1
package/AGENTS.md CHANGED
@@ -63,42 +63,18 @@ argument**. `ScanResults.agentSurface` carries the merged result.
63
63
  Named imports (aliased or not) and namespace imports (`intents.defineIntent`)
64
64
  both resolve; a default import does not, since neither package has one.
65
65
 
66
- **Declaration discovery is NOT bound to the class-scan `include` glob.** A model
67
- scan is routinely narrowed to where models live — the shipped SvelteKit template
68
- uses `src/lib/objects/**/*.ts` but an intent sidecar lives beside the component
69
- that uses it. So `agentSurfaceInclude` (default `**/*.{ts,tsx,js,jsx}`, the
70
- extensions the Vite plugin's own default accepts) is globbed separately, files
71
- the class pass already parsed are skipped so nothing is counted twice, and the
72
- token pre-filter keeps a non-declaring file at one read. Binding the two globs
73
- together made sidecars vanish from every artifact with no diagnostic at all —
74
- the exact silent omission this matcher exists to prevent.
75
-
76
- **`isAgentSurfaceSourcePath` is the single authority on what counts as a
77
- declaration source**, and it is a path predicate, not a glob. Both passes here
78
- and `dev:knowledge-check`'s freshness re-scan call it. That matters because the
79
- two sides disagreeing is not cosmetic: a file the emitter reads but the checker
80
- skips reports as "no longer present in source" forever, and the reverse reports
81
- as "missing from smrt-knowledge.json" forever — neither clearable by a rebuild.
82
- It rejects `.d.ts`, `*.test.*`, `*.spec.*`, any hidden (dot) segment, and
83
- anything under `node_modules`, `dist`, `build`, `coverage`, `__tests__`, or
84
- `__typechecks__` — measured
85
- **relative to the scan root**, via the companion `isPrunedAgentSurfacePath`
86
- (which the `.svelte` passes call directly, since a `.svelte` path is rejected on
87
- extension by the source predicate). Relative matching is load-bearing: against
88
- an absolute path, a checkout that merely LIVES under `build/` — a container with
89
- `WORKDIR /build`, a clone in `~/build/…` — would drop every declaration with no
90
- diagnostic, and the freshness check would apply the same rule and agree, so the
91
- artifact would ship an empty surface and `smrt doctor` would call it healthy.
92
- This is the trap `discovery.ts` rewrites globs relative to `cwd` to avoid.
93
-
94
- `dist` is not paranoia. A caller's `exclude` REPLACES `DEFAULT_EXCLUDE`, and
95
- every real caller passes a narrower one (the Vite plugin sends only test globs
96
- plus `node_modules`), so this whole-project pass would otherwise walk build
97
- output. A transpiling build — `tsc`, `svelte-package`, vite lib mode with
98
- `@happyvertical/*` externalized — keeps both the import specifier and the
99
- module-scope call in its output, so `dist/foo.intents.js` matches this matcher
100
- exactly; and since `dist` sorts before `src`, it would WIN the duplicate tie and
101
- become the recorded source of a declaration nobody wrote there.
66
+ Declaration discovery uses a separate `agentSurfaceInclude` glob (default
67
+ `**/*.{ts,tsx,js,jsx}`), independent of the model `include` glob. Skip files
68
+ already parsed by the class pass; token-prefilter other files before parsing.
69
+
70
+ `isAgentSurfaceSourcePath` is the shared authority for both scanner passes and
71
+ `dev:knowledge-check` freshness scans. It excludes `.d.ts`, tests/specs, hidden
72
+ segments, and `node_modules`, `dist`, `build`, `coverage`, `__tests__`, and
73
+ `__typechecks__`. The companion `isPrunedAgentSurfacePath` applies the same
74
+ prunes to `.svelte` files. Evaluate paths **relative to the scan root** so a
75
+ checkout under an ancestor named `build` or a hidden worktree still scans.
76
+ These prunes apply even when caller `exclude` replaces `DEFAULT_EXCLUDE`:
77
+ build output can retain declarations and otherwise win duplicate resolution.
102
78
 
103
79
  ### What it refuses, always with a diagnostic
104
80
 
@@ -115,43 +91,20 @@ for a tool set genuinely derived from computed or fetched data:
115
91
  | `svelte-declaration` | written inline in a `.svelte` file |
116
92
  | `duplicate-identity` | two modules declare the same `id`/`key`, or two intent ids derive the same WebMCP tool name |
117
93
 
118
- These rules are mirrored from `defineIntent` and `definePlaybook` (this package
119
- cannot depend on `smrt-web` or `smrt-playbooks`), and keeping them in step is
120
- load-bearing: the declaration types `id` as `string`, so `id: 'Orders.Bad'`
121
- type-checks and fails only at page load. An entry the runtime would reject is
122
- worse than no entry, because the artifact and `smrt doctor` would then advertise
123
- an operation that can never register. The same applies to the tool name, which
124
- is `id` with `.`/`-` replaced by `_` and is therefore **not injective** —
125
- `orders.foo_bar` and `orders.foo.bar` collide, and `defineIntent` rejects the
126
- second registration.
94
+ Mirror `defineIntent` and `definePlaybook` validation without importing their
95
+ packages; update the scanner whenever those runtime rules tighten. Reject
96
+ invalid values rather than repairing them: omitted capability gets the
97
+ fail-closed default, malformed capability gets a diagnostic, and invalid
98
+ `planes` never default to `server`. Playbook keys have no pattern restriction.
99
+ WebMCP names replace `.`/`-` with `_`, so distinct intent ids can collide.
127
100
 
128
- Invalid values are **rejected, never repaired**. That matters most for a
129
- playbook's `planes`: `definePlaybook` throws on an empty or unknown-plane list,
130
- so defaulting it here would emit an entry asserting `server` validity the author
131
- never declared — the exact fail-open the plane rule exists to prevent. The same
132
- holds for `capability`: the fail-closed default is for an OMITTED capability,
133
- not a typo'd one, so `{ effect: 'reed' }` is a diagnostic rather than a silent
134
- `destructive`. Playbook *keys* get no pattern check, because `definePlaybook`
135
- imposes none; only uniqueness applies. **If either runtime tightens its rules,
136
- tighten these too.**
101
+ Unlike decorator config extraction, agent-surface extraction never resolves
102
+ spreads: declarations must be visible in one object literal.
137
103
 
138
- This is deliberately narrower than the decorator-config extractor, which
139
- RESOLVES spreads against module-scope constants. That one must, because a
140
- dropped `@smrt({ ...CFG })` key silently reopens an exposure surface. Here the
141
- requirement runs the other way: an emitted entry has to be exactly what an
142
- author can see in one object literal, so a partial resolution would be worse
143
- than a refusal.
144
-
145
- The `.svelte` pass is textual, not a Svelte parse: it requires the import
146
- specifier plus a call, and it exists only to say "move this to a `.ts` sidecar"
147
- — which is the answer regardless of what the declaration contains. It resolves
148
- the local names the file's own import binds, so `defineIntent as declare`
149
- followed by `declare({…})` is caught, and it tolerates whitespace before the
150
- parenthesis; requiring the literal token `defineIntent(` would let exactly the
151
- case this pass exists for slip through unremarked. Any `*.svelte` exclude a
152
- caller passes for the class scan is dropped here, since callers routinely
153
- exclude Svelte because OXC cannot parse it, and honouring that would silence the
154
- one thing the pass is for.
104
+ The `.svelte` pass is textual: resolve named/aliased imports and calls (including
105
+ whitespace before `(`), then diagnose moving the declaration to a `.ts`
106
+ sidecar. Drop caller `*.svelte` class-scan excludes for this pass; otherwise the
107
+ diagnostic would be suppressed merely because OXC cannot parse Svelte.
155
108
 
156
109
  ### Deterministic identity
157
110
 
@@ -174,27 +127,15 @@ place, `toKnowledgeAgentSurface` in `vite-plugin/index.ts`.
174
127
 
175
128
  ## Discovery boundaries
176
129
 
177
- File discovery is the difference between a scan that finishes and one that
178
- exhausts the heap when the scanner is pointed at an application root (#2275):
179
-
180
- - `dot: true` is set so ignore patterns apply beneath dot directories. Without
181
- it a `**` cannot cross a dot segment, so `**/node_modules/**` pruned the root
182
- `node_modules` but nothing under `.svelte-kit/`, `.vercel/`, or `.turbo/`.
183
- - Mandatory excludes (`**/node_modules/**`, `**/.*/**`, `**/.*`) are unioned
184
- with the caller's `exclude` and cannot be overridden. `exclude` REPLACES the
185
- defaults, so every caller that narrowed it had silently reopened
186
- `node_modules`.
187
- - `followSymbolicLinks` defaults to `false`. A pnpm `node_modules` is a symlink
188
- graph with cycles, not a tree, so a link-following walk reaches the same real
189
- directory once per path leading to it. This drops symlinked *files* as well as
190
- directories, so pass `followSymbolicLinks: true` for a project that genuinely
191
- keeps sources behind a link — it is threaded through `smrtPlugin` and
192
- `ManifestBuilderOptions` for the build path.
193
- - Patterns are rewritten relative to `cwd` before globbing. Globs match as text,
194
- so an absolute pattern would hand `**/.*/**` the project's own ancestors and a
195
- checkout under `~/.worktrees` or `~/.cache` would match nothing at all.
196
- - `dot: true` would otherwise widen the result to hidden files, so `**/.*` is in
197
- the mandatory prunes too: hidden files stay out, exactly as before.
130
+ - Set `dot: true` so ignore patterns also prune dependencies under hidden
131
+ directories such as `.svelte-kit`.
132
+ - Union mandatory `**/node_modules/**`, `**/.*/**`, and `**/.*` prunes with
133
+ caller exclusions; caller `exclude` replaces defaults, never mandatory prunes.
134
+ - `followSymbolicLinks` defaults to `false` to bound walks of pnpm's symlink
135
+ graph. It excludes symlinked files as well as directories. Projects with
136
+ linked sources can opt in through `smrtPlugin`/`ManifestBuilderOptions`.
137
+ - Rewrite patterns relative to `cwd` before globbing so hidden checkout
138
+ ancestors do not exclude the entire project.
198
139
 
199
140
  ## How It Works
200
141
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happyvertical/smrt-scanner",
3
- "version": "0.45.1",
3
+ "version": "0.45.3",
4
4
  "description": "High-performance TypeScript scanner using OXC for SMRT manifest generation",
5
5
  "author": "HappyVertical",
6
6
  "type": "module",