kibi-plugin-builtin 0.5.1 → 0.5.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.
- package/CHANGELOG.md +29 -0
- package/dist/symbols/ts-morph-enrichment.d.ts +7 -0
- package/dist/symbols/ts-morph-enrichment.d.ts.map +1 -1
- package/dist/symbols/ts-morph-enrichment.js +68 -8
- package/dist/symbols/ts-morph-extractor.d.ts.map +1 -1
- package/dist/symbols/ts-morph-extractor.js +7 -1
- package/dist/symbols/workspace-path.d.ts +3 -0
- package/dist/symbols/workspace-path.d.ts.map +1 -0
- package/dist/symbols/workspace-path.js +55 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# kibi-plugin-builtin
|
|
2
2
|
|
|
3
|
+
## 0.5.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 25d537e: Symbol coordinate refresh no longer treats `sourceFile` as an unrestricted filesystem path. Absolute paths and `..` escapes are rejected at upsert and refused at read time, so MCP/CLI coordinate refresh cannot probe files outside the workspace.
|
|
8
|
+
|
|
9
|
+
Tighten Prolog `sourceFile` typing to `workspace_relpath` in `kibi-core` (and the CLI schema mirror), add `resolveWorkspaceSourceAbsolute` confinement (with realpath checks), and cover the escape oracle with regression tests in CLI and MCP.
|
|
10
|
+
|
|
11
|
+
## 0.5.2
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- e9b50db: A clean `kibi check` now means the next commit passes `kibi check --staged`, and the staged gate no longer passes symbol coverage that the full check rejects. `kibi check --staged` runs the full-check `symbol-coverage` rule on the staged knowledge for every changed symbol, so a test that verifies a requirement directly no longer counts once that requirement has a scenario. Full `kibi check` adds the blocking rule `symbol-granularity`, which judges every linked symbol against its source file the way the staged gate does, so coarse links, including symbols whose title the extractor never produces, surface before a later commit trips over them; existing knowledge bases can see new violations (see Migration below). Source analysis for symbol checks no longer builds a TypeScript program over the default library files for every file, so the rule adds a few seconds to a full check, and the staged gate and coordinate refresh get faster too. `kibi sync --refresh-symbol-coordinates` no longer binds coordinates to a private class member that the staged extractor never produces; it lists the symbol as failed and says to re-point it to the public owner or remove it.
|
|
16
|
+
|
|
17
|
+
Technical summary: `kb.pl` adds `changed_symbol_no_req_coverage/2`, which restricts `symbol_no_req_coverage/2` to the `changed_symbol/1` overlay facts plus symbols whose staged manifest entry changed, and `checks.pl` adds `check_changed_symbol_coverage/2`, which renders those as `symbol-coverage` violations; the staged flow in `check.ts` calls it through `validateStagedSymbolCoverage` next to `validateStagedSymbols` and creates the temp KB whenever a symbol changed, including manifest-only edits. The rule registry adds the TypeScript rule `symbol-granularity`, evaluated in `executeCheck` by `collectSymbolGranularityViolations`, which reuses `createSymbolGranularityDiagnostics` with every working-tree declaration as a candidate, analyzes only the source files of symbols the rule judges, honours allowed `granularity_reason` values and skips files the analyzers cannot fully analyze; the `kb_check` `rules` enum gains the name. Granularity diagnostics now carry `entityId`, `source` and evidence, and name titles the extractor does not produce. The built-in ts-morph v2 extractor creates its project with `noLib`, `noResolve` and no `types`: it reads only syntactic diagnostics, which are unchanged, and per-file analysis drops from roughly 75 ms to a few milliseconds. The ts-morph coordinate enricher skips private class members and records a transient `coordinateRefreshFailure` that sync prints as the failure reason and never writes to the manifest. The unused `checkSymbolCoverage` helper and its stale "not traceable to any functional requirement" message are removed. kibi-runtime is bumped because it bundles the CLI operations that kibi-mcp serves.
|
|
18
|
+
|
|
19
|
+
Migration: `symbol-granularity` is canonical and blocking, so `kibi check`, `kb_check` and CI fail until its violations are fixed. A symbol violates it when it has `implements`, `covered_by` or `executable_for` links, no allowed `granularity_reason`, and its source file has a narrower behavioral declaration: a member of the symbol's title (a class symbol while its methods exist), or any declaration when the title names nothing the extractor produces (a non-exported helper, a private class member, a removed or renamed declaration). Run `kibi check --rules symbol-granularity` to list them, fix them with `kb_upsert`/`kb_delete` (never by editing `.kb/` files), then run `kibi sync --refresh-symbol-coordinates`:
|
|
20
|
+
|
|
21
|
+
- Title the extractor does not produce: re-point the symbol to its public owner, the exported function or class that owns the behavior. Change its `title` to the owner, or, when a symbol for the owner already exists, add the links to that symbol and delete the helper symbol.
|
|
22
|
+
- Class symbol while its members exist: move the links to the narrow member symbols, or delete the class symbol when its members already carry the same links.
|
|
23
|
+
- Coarse ownership that is intended: add an allowed `granularity_reason` (`module-level-behavior`, `config-artifact`, `extractor-miss`, `test-suite` or `legacy-link`).
|
|
24
|
+
|
|
3
25
|
## 0.5.1
|
|
4
26
|
|
|
5
27
|
### Patch Changes
|
|
@@ -16,6 +38,7 @@
|
|
|
16
38
|
### Minor Changes
|
|
17
39
|
|
|
18
40
|
- ee91b85: Projects with a UI can opt into the experimental `kibi-plugin-ui`, which keeps agents on the agreed design: `kb_check` then requires every React or Angular component to implement a design requirement and blocks a component that loses the class names or test ids marking its agreed pattern, such as a timeline rewritten as cards. `/kibi-bootstrap` offers the plugin when it finds component files, and a declined offer is remembered in `package.json` `kibi.declinedPlugins`. Requirements that only name a UI pattern are now proved by fresh isolated component tests, so pattern rules do not need browser tests. Projects without the plugin see no new blocking findings.
|
|
41
|
+
|
|
19
42
|
- Add the `kibi.check-policy.v1` capability to `kibi-plugin-sdk`: a JSON policy with ownership and pattern-marker rules, validated by `validateCheckPolicyDocument`. `kb_check` reads activated policies as data from the package and never imports plugin code; an unreadable policy blocks. The builtin plugin ships an empty policy.
|
|
20
43
|
- Add the canonical `policy-ownership` and `policy-markers` rules (inert without an activated policy) to the rule registry, the `kb_check` schema and the CLI.
|
|
21
44
|
- Add built-in `ui_pattern`, `same_pattern`, `pattern_marker` and `ui_container` predicate schemas with suggestion keywords.
|
|
@@ -64,6 +87,7 @@
|
|
|
64
87
|
### Patch Changes
|
|
65
88
|
|
|
66
89
|
- 8622782: An impact review prepared on one machine now still validates in CI, and the MCP server and the CLI agree on whether it is current. Checks only block on incomplete source analysis the author can act on: the committed side of a change never blocks, and a known analyzer limitation such as a Rust macro or a Python decorator matters only where it overlaps the changed lines. Syntax, parse, timeout and integrity problems in the staged file still block. Long-running hosts no longer grow memory with every analyzed file, and Tree-sitter analysis reuses warm workers instead of starting one per file.
|
|
90
|
+
|
|
67
91
|
- Identify the impact evaluator by its contract version and the canonical JSON of the schemas it consumes, instead of hashing the installed file tree and `process.version`. Identify the builtin analyzer runtime by its package identity rather than its installed tree.
|
|
68
92
|
- `kibi-runtime` bundles the CLI operations again (`kibi-cli` is a build-time dependency only); it no longer installs `kibi-cli`.
|
|
69
93
|
- Add one shared analysis gate (`analysisObligation`) used by staged checks, impact-review preparation and validation, and impact reports.
|
|
@@ -84,6 +108,7 @@
|
|
|
84
108
|
When you model a new requirement, Kibi now ranks the subjects that already exist and either reuses one or explicitly declares a new one. It also flags claims that look like possible duplicates. An intentional restatement can be recorded with the new `restates` relationship. Skills and docs now recommend naming entities by the behavior they govern (`REQ-cli-gc`) instead of a sequence number (`REQ-042`). Existing numbered IDs stay valid.
|
|
85
109
|
|
|
86
110
|
Predicate schemas can now declare the allowed values for an argument, plus the old spellings that map onto them. New facts must use those values. `kibi check` reports predicate facts that don't match any schema, and `kibi migrate` can fix the mechanical cases after you approve the plan hash. It moves a fact to the only namespace whose schema matches, and rewrites old spellings to the declared value. Everything that needs judgment stays a review item.
|
|
111
|
+
|
|
87
112
|
- core: new `semantic_quality.pl` (`entity-id-style`, `domain-redundancy`, `domain-implication`, `subject-key-identity`, `subject-key-shape`, `ontology-quality`) and `units.pl`. Unit canonicalization is used for comparison only, and unknown or ambiguous units such as `KB` are never equated. Adds the `restates` req→req relationship and an optional `diagnosticSeverity` in the rule registry. Adds `:- encoding(utf8)` to modules that contain non-ASCII text.
|
|
88
113
|
- cli/mcp: `restates` is wired through the extractors, schemas, and mutation paths. `entity-id-style` warnings are reported on `kb_upsert` creates and on staged added or renamed entity files. `kb_model_requirement` returns `vocabularyAlignment` (subject decision, candidates, redundancy candidates, stamps, `fallbackUsed`). Ontology-quality thresholds can be set with `KIBI_ONTOLOGY_QUALITY_MAX_SINGLETON_RATIO` / `KIBI_ONTOLOGY_QUALITY_MIN_FACTS`. `kb_compile_intent` create mode now keeps a caller-supplied `requirementId`. `kibi check --staged` now also prints its pass line when metadata-only staged changes have only advisory findings, matching the staged-symbol path.
|
|
89
114
|
- cli/mcp: `predicate_schema` facts accept `argument_constants` and `argument_aliases`, stored like `rule_ir` as JSON. `kb_upsert` / `kb_validate_upsert` reject malformed vocabularies and predicate facts that use undeclared values or aliases. `kb_suggest_predicates` binds aliases to their constant and leaves undeclared values unbound. The new advisory TypeScript rule `predicate-schema-conformance` checks predicate facts against project schemas and the built-in catalog. Its mechanical repairs become automatic `predicate_schema_alignment` migration actions that carry the exact `kb_upsert` input and re-read the fact before writing.
|
|
@@ -99,6 +124,7 @@
|
|
|
99
124
|
this repository, `kibi status` for a fresh KB drops from about 3 seconds to
|
|
100
125
|
about 1.7, and a command that needs neither schema validation nor symbol
|
|
101
126
|
extraction starts about 0.5 seconds sooner.
|
|
127
|
+
|
|
102
128
|
- `kb_status_json` skips the full-entity stale-reason scan when the KB is
|
|
103
129
|
fresh, because a fresh verdict already rules out every stale reason.
|
|
104
130
|
- `kibi-plugin-builtin` loads ts-morph (the TypeScript compiler) on first
|
|
@@ -113,6 +139,7 @@
|
|
|
113
139
|
### Minor Changes
|
|
114
140
|
|
|
115
141
|
- 783cc75: Coordinate enrichment, granularity candidate collection, and private-member helpers now live in `kibi-plugin-builtin`, so the CLI can analyze TypeScript/JavaScript symbols without depending on `ts-morph` directly. Hosts that only install `kibi-cli` still get the same enrichment and staged-symbol behavior through the builtin plugin.
|
|
142
|
+
|
|
116
143
|
- Export `enrichSymbolCoordinatesWithTsMorph`, `collectGranularityCandidates`, `onlyCandidate`, and `isPrivateClassMember` from `kibi-plugin-builtin`
|
|
117
144
|
- Thin-wrap those helpers from CLI `symbols-ts`, `symbol-granularity`, and `symbol-extract`
|
|
118
145
|
- Drop `ts-morph` from `kibi-cli` runtime dependencies (kept as a test-only devDependency for AST spies)
|
|
@@ -125,10 +152,12 @@
|
|
|
125
152
|
### Patch Changes
|
|
126
153
|
|
|
127
154
|
- b375e8f: This maintenance update brings the affected package code and tests into line with Kibi's Biome checks while preserving runtime behavior. It also replaces MCP non-null assertions with receiver-preserving method calls.
|
|
155
|
+
|
|
128
156
|
- Format affected files, sort imports, and remove unnecessary template literals.
|
|
129
157
|
- Preserve EngineClient `this` when forwarding optional Prolog methods.
|
|
130
158
|
|
|
131
159
|
- e6571b4: External classifiers stay limited to the two allowlisted operations, ontology matches keep their claim keys through host composition, and CLI predicate rule tables now re-export the builtin pack so advisor and modeling cannot drift. Lane selection from the builtin classifier also accepts host snake_case signal shapes, which unblocks typecheck/build for capability-plugin call sites.
|
|
160
|
+
|
|
132
161
|
- fix(builtin): chooseLane accepts kind-only LaneSignal (unblocks analysis-receipt typecheck)
|
|
133
162
|
- feat(cli): stamp claimKey on composed ontology match candidates
|
|
134
163
|
- refactor(cli): re-export predicate rule tables from kibi-plugin-builtin
|
|
@@ -15,6 +15,13 @@ export interface ManifestSymbolEntry {
|
|
|
15
15
|
sourceEndColumn?: number;
|
|
16
16
|
coordinatesGeneratedAt?: string;
|
|
17
17
|
links?: string[];
|
|
18
|
+
/**
|
|
19
|
+
* Transient refresh outcome, never authored: why no coordinates were
|
|
20
|
+
* published for this entry. Set when the title names a declaration the
|
|
21
|
+
* symbol extractor does not produce (a private class member), so a refresh
|
|
22
|
+
* reports it instead of binding a span no other Kibi path recognizes.
|
|
23
|
+
*/
|
|
24
|
+
coordinateRefreshFailure?: string;
|
|
18
25
|
[key: string]: unknown;
|
|
19
26
|
}
|
|
20
27
|
export declare function enrichSymbolCoordinatesWithTsMorph(entries: ManifestSymbolEntry[], workspaceRoot: string): Promise<ManifestSymbolEntry[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ts-morph-enrichment.d.ts","sourceRoot":"","sources":["../../src/symbols/ts-morph-enrichment.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ts-morph-enrichment.d.ts","sourceRoot":"","sources":["../../src/symbols/ts-morph-enrichment.ts"],"names":[],"mappings":"AAqCA,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,sBAAsB,EAAE,MAAM,CAAC;CAChC;AAGD,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB;;;;;OAKG;IACH,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAKD,wBAAsB,kCAAkC,CACtD,OAAO,EAAE,mBAAmB,EAAE,EAC9B,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAuGhC"}
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
import { access, readFile } from "node:fs/promises";
|
|
19
19
|
import * as path from "node:path";
|
|
20
20
|
import { tsMorph } from "./ts-morph-runtime.js";
|
|
21
|
-
import { SUPPORTED_SOURCE_EXTENSIONS, onlyCandidate, } from "./ts-morph-shared.js";
|
|
21
|
+
import { SUPPORTED_SOURCE_EXTENSIONS, isPrivateClassMember, onlyCandidate, } from "./ts-morph-shared.js";
|
|
22
|
+
import { resolveWorkspaceSourceAbsolute } from "./workspace-path.js";
|
|
22
23
|
// implements REQ-capability-plugin-builtin-parity-v1
|
|
23
24
|
export async function enrichSymbolCoordinatesWithTsMorph(entries, workspaceRoot) {
|
|
24
25
|
const project = new (tsMorph().Project)({
|
|
@@ -62,7 +63,12 @@ export async function enrichSymbolCoordinatesWithTsMorph(entries, workspaceRoot)
|
|
|
62
63
|
}
|
|
63
64
|
const match = findNamedDeclaration(sourceFile, entry.title);
|
|
64
65
|
if (!match) {
|
|
65
|
-
enriched.push(entry)
|
|
66
|
+
enriched.push(namesPrivateClassMember(sourceFile, entry.title)
|
|
67
|
+
? {
|
|
68
|
+
...entry,
|
|
69
|
+
coordinateRefreshFailure: privateMemberRefreshFailure(entry.title),
|
|
70
|
+
}
|
|
71
|
+
: entry);
|
|
66
72
|
continue;
|
|
67
73
|
}
|
|
68
74
|
const nameStart = match.getNameNode().getStart();
|
|
@@ -97,9 +103,9 @@ export async function enrichSymbolCoordinatesWithTsMorph(entries, workspaceRoot)
|
|
|
97
103
|
async function resolveSourcePath(sourceFile, workspaceRoot) {
|
|
98
104
|
if (!sourceFile)
|
|
99
105
|
return null;
|
|
100
|
-
const absolute =
|
|
101
|
-
|
|
102
|
-
|
|
106
|
+
const absolute = resolveWorkspaceSourceAbsolute(workspaceRoot, sourceFile);
|
|
107
|
+
if (absolute === null)
|
|
108
|
+
return null;
|
|
103
109
|
const ext = path.extname(absolute).toLowerCase();
|
|
104
110
|
if (!SUPPORTED_SOURCE_EXTENSIONS.has(ext))
|
|
105
111
|
return null;
|
|
@@ -258,6 +264,8 @@ function findNamedDeclaration(sourceFile, title) {
|
|
|
258
264
|
const methodCandidates = [];
|
|
259
265
|
for (const cls of sourceFile.getClasses()) {
|
|
260
266
|
for (const method of cls.getMethods()) {
|
|
267
|
+
if (isPrivateClassMember(method))
|
|
268
|
+
continue;
|
|
261
269
|
if (method.getName() !== title)
|
|
262
270
|
continue;
|
|
263
271
|
const nameNode = method.getNameNode();
|
|
@@ -274,6 +282,8 @@ function findNamedDeclaration(sourceFile, title) {
|
|
|
274
282
|
if (!classExpression)
|
|
275
283
|
continue;
|
|
276
284
|
for (const method of classExpression.getMethods()) {
|
|
285
|
+
if (isPrivateClassMember(method))
|
|
286
|
+
continue;
|
|
277
287
|
if (method.getName() !== title)
|
|
278
288
|
continue;
|
|
279
289
|
const nameNode = method.getNameNode();
|
|
@@ -293,6 +303,8 @@ function findNamedDeclaration(sourceFile, title) {
|
|
|
293
303
|
const memberCandidates = [];
|
|
294
304
|
for (const cls of sourceFile.getClasses()) {
|
|
295
305
|
for (const property of cls.getProperties()) {
|
|
306
|
+
if (isPrivateClassMember(property))
|
|
307
|
+
continue;
|
|
296
308
|
if (property.getName() !== title)
|
|
297
309
|
continue;
|
|
298
310
|
const nameNode = property.getNameNode();
|
|
@@ -304,6 +316,8 @@ function findNamedDeclaration(sourceFile, title) {
|
|
|
304
316
|
...cls.getGetAccessors(),
|
|
305
317
|
...cls.getSetAccessors(),
|
|
306
318
|
]) {
|
|
319
|
+
if (isPrivateClassMember(accessor))
|
|
320
|
+
continue;
|
|
307
321
|
if (accessor.getName() !== title)
|
|
308
322
|
continue;
|
|
309
323
|
const nameNode = accessor.getNameNode();
|
|
@@ -320,6 +334,8 @@ function findNamedDeclaration(sourceFile, title) {
|
|
|
320
334
|
if (!classExpression)
|
|
321
335
|
continue;
|
|
322
336
|
for (const property of classExpression.getProperties()) {
|
|
337
|
+
if (isPrivateClassMember(property))
|
|
338
|
+
continue;
|
|
323
339
|
if (property.getName() !== title)
|
|
324
340
|
continue;
|
|
325
341
|
const nameNode = property.getNameNode();
|
|
@@ -334,6 +350,8 @@ function findNamedDeclaration(sourceFile, title) {
|
|
|
334
350
|
...classExpression.getGetAccessors(),
|
|
335
351
|
...classExpression.getSetAccessors(),
|
|
336
352
|
]) {
|
|
353
|
+
if (isPrivateClassMember(accessor))
|
|
354
|
+
continue;
|
|
337
355
|
if (accessor.getName() !== title)
|
|
338
356
|
continue;
|
|
339
357
|
const nameNode = accessor.getNameNode();
|
|
@@ -355,16 +373,22 @@ function findNamedDeclaration(sourceFile, title) {
|
|
|
355
373
|
candidates.sort((a, b) => a.getNameNode().getStart() - b.getNameNode().getStart());
|
|
356
374
|
return candidates[0] ?? null;
|
|
357
375
|
}
|
|
376
|
+
/**
|
|
377
|
+
* Public members only: the symbol extractor skips private class members, so
|
|
378
|
+
* a coordinate refresh must not bind a span to one either.
|
|
379
|
+
*/
|
|
380
|
+
// implements REQ-capability-plugin-builtin-parity-v1
|
|
358
381
|
function findClassMember(declaration, name) {
|
|
382
|
+
const visible = (member) => !isPrivateClassMember(member);
|
|
359
383
|
for (const method of declaration.getMethods()) {
|
|
360
|
-
if (method.getName() !== name)
|
|
384
|
+
if (method.getName() !== name || !visible(method))
|
|
361
385
|
continue;
|
|
362
386
|
const nameNode = method.getNameNode();
|
|
363
387
|
if (nameNode)
|
|
364
388
|
return { node: method, getNameNode: () => nameNode };
|
|
365
389
|
}
|
|
366
390
|
for (const property of declaration.getProperties()) {
|
|
367
|
-
if (property.getName() !== name)
|
|
391
|
+
if (property.getName() !== name || !visible(property))
|
|
368
392
|
continue;
|
|
369
393
|
const nameNode = property.getNameNode();
|
|
370
394
|
if (nameNode)
|
|
@@ -374,7 +398,7 @@ function findClassMember(declaration, name) {
|
|
|
374
398
|
...declaration.getGetAccessors(),
|
|
375
399
|
...declaration.getSetAccessors(),
|
|
376
400
|
]) {
|
|
377
|
-
if (accessor.getName() !== name)
|
|
401
|
+
if (accessor.getName() !== name || !visible(accessor))
|
|
378
402
|
continue;
|
|
379
403
|
const nameNode = accessor.getNameNode();
|
|
380
404
|
if (nameNode)
|
|
@@ -382,6 +406,42 @@ function findClassMember(declaration, name) {
|
|
|
382
406
|
}
|
|
383
407
|
return null;
|
|
384
408
|
}
|
|
409
|
+
/**
|
|
410
|
+
* True when the title names a private member of a class in this file (as
|
|
411
|
+
* `Class.member` or as a bare member name), which the extractor never emits.
|
|
412
|
+
*/
|
|
413
|
+
// implements REQ-capability-plugin-builtin-parity-v1
|
|
414
|
+
function namesPrivateClassMember(sourceFile, title) {
|
|
415
|
+
const qualified = parseQualifiedMethodTitle(title);
|
|
416
|
+
const classes = [
|
|
417
|
+
...sourceFile.getClasses(),
|
|
418
|
+
];
|
|
419
|
+
for (const statement of sourceFile.getVariableStatements()) {
|
|
420
|
+
for (const declaration of statement.getDeclarations()) {
|
|
421
|
+
const classExpression = declaration.getInitializerIfKind(tsMorph().SyntaxKind.ClassExpression);
|
|
422
|
+
if (classExpression)
|
|
423
|
+
classes.push(classExpression);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
return classes.some((declaration) => {
|
|
427
|
+
const className = declaration.getName() ??
|
|
428
|
+
declaration
|
|
429
|
+
.getParentIfKind(tsMorph().SyntaxKind.VariableDeclaration)
|
|
430
|
+
?.getName();
|
|
431
|
+
if (qualified && qualified.className !== className)
|
|
432
|
+
return false;
|
|
433
|
+
const memberName = qualified ? qualified.methodName : title;
|
|
434
|
+
return [
|
|
435
|
+
...declaration.getMethods(),
|
|
436
|
+
...declaration.getProperties(),
|
|
437
|
+
...declaration.getGetAccessors(),
|
|
438
|
+
...declaration.getSetAccessors(),
|
|
439
|
+
].some((member) => member.getName() === memberName && isPrivateClassMember(member));
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
function privateMemberRefreshFailure(title) {
|
|
443
|
+
return `'${title}' is a private class member; the symbol extractor tracks only public declarations, so no coordinates are published. Re-point the symbol to the public member or class that owns the behavior, or remove it`;
|
|
444
|
+
}
|
|
385
445
|
function parseQualifiedMethodTitle(title) {
|
|
386
446
|
const separatorIndex = title.lastIndexOf(".");
|
|
387
447
|
if (separatorIndex <= 0 || separatorIndex === title.length - 1)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ts-morph-extractor.d.ts","sourceRoot":"","sources":["../../src/symbols/ts-morph-extractor.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EACV,sBAAsB,EAMtB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,iBAAiB,CAAC;AAsDzB;;;GAGG;AAEH,wBAAgB,mCAAmC,IAAI,iBAAiB,CA4CvE;AAED,iFAAiF;AAEjF,wBAAgB,qCAAqC,IAAI,iBAAiB,
|
|
1
|
+
{"version":3,"file":"ts-morph-extractor.d.ts","sourceRoot":"","sources":["../../src/symbols/ts-morph-extractor.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EACV,sBAAsB,EAMtB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,iBAAiB,CAAC;AAsDzB;;;GAGG;AAEH,wBAAgB,mCAAmC,IAAI,iBAAiB,CA4CvE;AAED,iFAAiF;AAEjF,wBAAgB,qCAAqC,IAAI,iBAAiB,CA2HzE;AA+BD,wBAAgB,0CAA0C,IAAI,sBAAsB,CAEnF"}
|
|
@@ -96,9 +96,15 @@ export function createBuiltinTsMorphSymbolExtractor() {
|
|
|
96
96
|
export function createBuiltinTsMorphSymbolExtractorV2() {
|
|
97
97
|
// Like the v1 extractor, build the project (and load the TypeScript
|
|
98
98
|
// compiler) on the first analysis rather than at plugin registration.
|
|
99
|
+
// Only syntactic diagnostics are read, so the program needs neither the
|
|
100
|
+
// default library files nor the file's imports; loading them made every
|
|
101
|
+
// analysis rebuild a program over the whole lib closure.
|
|
99
102
|
let project;
|
|
100
103
|
const getProject = () => {
|
|
101
|
-
project ??= new (tsMorph().Project)({
|
|
104
|
+
project ??= new (tsMorph().Project)({
|
|
105
|
+
skipAddingFilesFromTsConfig: true,
|
|
106
|
+
compilerOptions: { noLib: true, noResolve: true, types: [] },
|
|
107
|
+
});
|
|
102
108
|
return project;
|
|
103
109
|
};
|
|
104
110
|
return {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-path.d.ts","sourceRoot":"","sources":["../../src/symbols/workspace-path.ts"],"names":[],"mappings":"AAoBA,4DAA4D;AAE5D,wBAAgB,8BAA8B,CAC5C,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,GACjB,MAAM,GAAG,IAAI,CA+Bf"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Kibi — repo-local, per-branch, queryable long-term memory for software projects
|
|
3
|
+
Copyright (C) 2026 Piotr Franczyk
|
|
4
|
+
|
|
5
|
+
This program is free software: you can redistribute it and/or modify
|
|
6
|
+
it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
(at your option) any later version.
|
|
9
|
+
|
|
10
|
+
This program is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU Affero General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
import { realpathSync } from "node:fs";
|
|
19
|
+
import path from "node:path";
|
|
20
|
+
/** Return null when `candidate` escapes `workspaceRoot`. */
|
|
21
|
+
// implements REQ-symbol-sourcefile-workspace-confinement
|
|
22
|
+
export function resolveWorkspaceSourceAbsolute(workspaceRoot, sourceFile) {
|
|
23
|
+
if (sourceFile.trim() === "")
|
|
24
|
+
return null;
|
|
25
|
+
let slashed = sourceFile.replaceAll("\\", "/");
|
|
26
|
+
const foreignAbsolute = /^[A-Za-z]:\//.test(slashed) || slashed.startsWith("//");
|
|
27
|
+
if (slashed.startsWith("/") || foreignAbsolute) {
|
|
28
|
+
if (foreignAbsolute && path.sep === "/")
|
|
29
|
+
return null;
|
|
30
|
+
const root = path.resolve(workspaceRoot);
|
|
31
|
+
const relative = path.relative(root, path.resolve(sourceFile));
|
|
32
|
+
if (relative === "" || path.isAbsolute(relative))
|
|
33
|
+
return null;
|
|
34
|
+
slashed = relative.replaceAll("\\", "/");
|
|
35
|
+
}
|
|
36
|
+
const normalized = path.posix.normalize(slashed).replace(/\/+$/, "");
|
|
37
|
+
if (normalized === "" ||
|
|
38
|
+
normalized === "." ||
|
|
39
|
+
normalized === ".." ||
|
|
40
|
+
normalized.startsWith("../")) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
const absolute = path.resolve(workspaceRoot, normalized);
|
|
44
|
+
try {
|
|
45
|
+
const realRoot = realpathSync.native(path.resolve(workspaceRoot));
|
|
46
|
+
const realFile = realpathSync.native(absolute);
|
|
47
|
+
const confined = path.relative(realRoot, realFile);
|
|
48
|
+
if (confined.startsWith("..") || path.isAbsolute(confined))
|
|
49
|
+
return null;
|
|
50
|
+
return realFile;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return absolute;
|
|
54
|
+
}
|
|
55
|
+
}
|
package/package.json
CHANGED