carrick 0.3.122 → 0.3.123

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "carrick",
3
- "version": "0.3.122",
3
+ "version": "0.3.123",
4
4
  "carrickCache": {
5
5
  "cache_version": 22,
6
6
  "intent_cache_version": 2
@@ -113,11 +113,11 @@
113
113
  "zod": "^3.23.0"
114
114
  },
115
115
  "optionalDependencies": {
116
- "@carrick-tools/cli-darwin-arm64": "0.3.122",
117
- "@carrick-tools/cli-darwin-x64": "0.3.122",
118
- "@carrick-tools/cli-linux-arm64": "0.3.122",
119
- "@carrick-tools/cli-linux-x64": "0.3.122",
120
- "@carrick-tools/cli-win32-x64": "0.3.122"
116
+ "@carrick-tools/cli-darwin-arm64": "0.3.123",
117
+ "@carrick-tools/cli-darwin-x64": "0.3.123",
118
+ "@carrick-tools/cli-linux-arm64": "0.3.123",
119
+ "@carrick-tools/cli-linux-x64": "0.3.123",
120
+ "@carrick-tools/cli-win32-x64": "0.3.123"
121
121
  },
122
122
  "devDependencies": {
123
123
  "@types/node": "^24.13.3"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "carrick",
3
3
  "description": "Claude Code plugin for Carrick, which indexes TypeScript codebases across service and repository boundaries. After each edit it adds the file's routes, calls, and cross-service type mismatches to the session, and it registers Carrick's language server. It pairs with the Carrick MCP server, which lets agents search functions by intent rather than name.",
4
- "version": "0.3.122",
4
+ "version": "0.3.123",
5
5
  "author": {
6
6
  "name": "Carrick",
7
7
  "email": "hello@carrick.tools"
@@ -13,29 +13,26 @@
13
13
  * | `member` | property or element access | the name or the argument | the access |
14
14
  * | `compare` | `=== !== == != < > <= >= instanceof in` | the left operand | the left operand |
15
15
  * | `ident` | an identifier in expression position | itself | itself |
16
- * | `impl` | a `call` or `member` whose declaration has no body | an implementation of it | nothing |
17
16
  * | `decl` | a `call` or `member` on a union of declaring types | one of those declarations | nothing |
18
17
  * | `jsx` | a JSX opening or self-closing element's tag | the tag's name | the tag |
19
18
  *
20
- * An `impl` row (version 2, carrick#2430) follows the `call` or `member` row
21
- * it belongs to and has its span: one per declaration that go-to-implementation
22
- * names for that row's declaration, when that declaration is an interface's
23
- * or type literal's method, a function-typed property signature, an abstract
24
- * member, or a function-typed class property or parameter with no
25
- * initializer. Its `decl_*` name the implementing declaration. Past
26
- * {@link IMPL_CAP} the row is one, with {@link FLAG_TOO_MANY} and nothing else.
27
- *
28
19
  * A `decl` row (version 3, carrick#2448) follows the `call` or `member` row
29
- * it belongs to, before its `impl` rows, and has its span: one per
20
+ * it belongs to and has its span: one per
30
21
  * declaration of the member when the receiver is a union whose constituents
31
22
  * declare it at more than one place (`(pick ? a : b).get()` with two
32
23
  * classes). That row names only the first of them. Each constituent's
33
24
  * declaration is its own member's, or, for a member with none (a mapped
34
- * type's), the declaration of the constituent type itself. Sorted and capped
35
- * as `impl` rows are; `type_text` is `null`.
25
+ * type's), the declaration of the constituent type itself. Sorted by file and
26
+ * position; past {@link DECL_CAP} the row is one, with {@link FLAG_TOO_MANY}
27
+ * and nothing else. `type_text` is `null`.
28
+ *
29
+ * Version 4 (carrick#2561) dropped the `impl` rows of versions 2 and 3: the
30
+ * go-to-implementation search behind them was most of the walk's time, and
31
+ * nothing read them. Implementations are asked for where discovery stops
32
+ * (carrick#2432).
36
33
  *
37
- * A row's key is `(start, end, kind)`, except that several `impl` rows, and
38
- * several `decl` rows, share one: TypeScript `getStart()`/`getEnd()` of the
34
+ * A row's key is `(start, end, kind)`, except that several `decl` rows share
35
+ * one: TypeScript `getStart()`/`getEnd()` of the
39
36
  * node, in UTF-16 code units from the start of the file, which is what the scanner's `sidecar_position`
40
37
  * gives for an SWC span. Every path written is relative to the scanned repo's
41
38
  * root, with `/` separators.
@@ -54,7 +51,7 @@ import { ts } from 'ts-morph';
54
51
  import type { ProjectLoader } from './project-loader.js';
55
52
  import type { PositionRowsCounts } from './types.js';
56
53
  /** The format's version, written in the header. */
57
- export declare const POSITION_ROWS_VERSION = 3;
54
+ export declare const POSITION_ROWS_VERSION = 4;
58
55
  /** The type is `any`, declared or inferred. Never set with the error type. */
59
56
  export declare const FLAG_ANY = 1;
60
57
  /** The type is the compiler's error type: something did not resolve. */
@@ -63,7 +60,7 @@ export declare const FLAG_ERROR_TYPE = 2;
63
60
  export declare const FLAG_CHECKER_THREW = 4;
64
61
  /** The declaration is outside the checkout, not the default library and in no installed package. */
65
62
  export declare const FLAG_DECLARATION_UNNAMED = 8;
66
- /** An `impl` or `decl` row standing for more than {@link IMPL_CAP} rows of its kind; it names none. */
63
+ /** A `decl` row standing for more than {@link DECL_CAP} rows; it names none. */
67
64
  export declare const FLAG_TOO_MANY = 16;
68
65
  /**
69
66
  * The declaration is published under the row's symbol name: its module
@@ -74,11 +71,11 @@ export declare const FLAG_TOO_MANY = 16;
74
71
  export declare const FLAG_PUBLISHED = 32;
75
72
  /** The declaration is what its module exports as `export =` or `default` (carrick#2508). */
76
73
  export declare const FLAG_MODULE_DEFAULT = 64;
77
- /** The most `impl` rows one declaration lists, and the most `decl` rows one position lists. */
78
- export declare const IMPL_CAP = 16;
79
- /** The kinds {@link kindOf} gives a node; `impl`, `decl` and `jsx` rows are written beside them. */
74
+ /** The most `decl` rows one position lists. */
75
+ export declare const DECL_CAP = 16;
76
+ /** The kinds {@link kindOf} gives a node; `decl` and `jsx` rows are written beside them. */
80
77
  export type NodeKind = 'call' | 'member' | 'compare' | 'ident';
81
- export type PositionKind = NodeKind | 'impl' | 'decl' | 'jsx';
78
+ export type PositionKind = NodeKind | 'decl' | 'jsx';
82
79
  /** `[kind, start, end, symbol, decl_file, decl_line, decl_package, type_text, flags]` */
83
80
  export type PositionRow = [
84
81
  PositionKind,
@@ -13,29 +13,26 @@
13
13
  * | `member` | property or element access | the name or the argument | the access |
14
14
  * | `compare` | `=== !== == != < > <= >= instanceof in` | the left operand | the left operand |
15
15
  * | `ident` | an identifier in expression position | itself | itself |
16
- * | `impl` | a `call` or `member` whose declaration has no body | an implementation of it | nothing |
17
16
  * | `decl` | a `call` or `member` on a union of declaring types | one of those declarations | nothing |
18
17
  * | `jsx` | a JSX opening or self-closing element's tag | the tag's name | the tag |
19
18
  *
20
- * An `impl` row (version 2, carrick#2430) follows the `call` or `member` row
21
- * it belongs to and has its span: one per declaration that go-to-implementation
22
- * names for that row's declaration, when that declaration is an interface's
23
- * or type literal's method, a function-typed property signature, an abstract
24
- * member, or a function-typed class property or parameter with no
25
- * initializer. Its `decl_*` name the implementing declaration. Past
26
- * {@link IMPL_CAP} the row is one, with {@link FLAG_TOO_MANY} and nothing else.
27
- *
28
19
  * A `decl` row (version 3, carrick#2448) follows the `call` or `member` row
29
- * it belongs to, before its `impl` rows, and has its span: one per
20
+ * it belongs to and has its span: one per
30
21
  * declaration of the member when the receiver is a union whose constituents
31
22
  * declare it at more than one place (`(pick ? a : b).get()` with two
32
23
  * classes). That row names only the first of them. Each constituent's
33
24
  * declaration is its own member's, or, for a member with none (a mapped
34
- * type's), the declaration of the constituent type itself. Sorted and capped
35
- * as `impl` rows are; `type_text` is `null`.
25
+ * type's), the declaration of the constituent type itself. Sorted by file and
26
+ * position; past {@link DECL_CAP} the row is one, with {@link FLAG_TOO_MANY}
27
+ * and nothing else. `type_text` is `null`.
28
+ *
29
+ * Version 4 (carrick#2561) dropped the `impl` rows of versions 2 and 3: the
30
+ * go-to-implementation search behind them was most of the walk's time, and
31
+ * nothing read them. Implementations are asked for where discovery stops
32
+ * (carrick#2432).
36
33
  *
37
- * A row's key is `(start, end, kind)`, except that several `impl` rows, and
38
- * several `decl` rows, share one: TypeScript `getStart()`/`getEnd()` of the
34
+ * A row's key is `(start, end, kind)`, except that several `decl` rows share
35
+ * one: TypeScript `getStart()`/`getEnd()` of the
39
36
  * node, in UTF-16 code units from the start of the file, which is what the scanner's `sidecar_position`
40
37
  * gives for an SWC span. Every path written is relative to the scanned repo's
41
38
  * root, with `/` separators.
@@ -59,7 +56,7 @@ import { WriteGuard, installedPackageDirectory, isDeclarationFileName, moduleExp
59
56
  import { attributedDeclaration, installedPackageOf } from './declaration-attribution.js';
60
57
  import { typeToStringAsDeclared } from './print-type.js';
61
58
  /** The format's version, written in the header. */
62
- export const POSITION_ROWS_VERSION = 3;
59
+ export const POSITION_ROWS_VERSION = 4;
63
60
  /** The type is `any`, declared or inferred. Never set with the error type. */
64
61
  export const FLAG_ANY = 1;
65
62
  /** The type is the compiler's error type: something did not resolve. */
@@ -68,7 +65,7 @@ export const FLAG_ERROR_TYPE = 2;
68
65
  export const FLAG_CHECKER_THREW = 4;
69
66
  /** The declaration is outside the checkout, not the default library and in no installed package. */
70
67
  export const FLAG_DECLARATION_UNNAMED = 8;
71
- /** An `impl` or `decl` row standing for more than {@link IMPL_CAP} rows of its kind; it names none. */
68
+ /** A `decl` row standing for more than {@link DECL_CAP} rows; it names none. */
72
69
  export const FLAG_TOO_MANY = 16;
73
70
  /**
74
71
  * The declaration is published under the row's symbol name: its module
@@ -79,8 +76,8 @@ export const FLAG_TOO_MANY = 16;
79
76
  export const FLAG_PUBLISHED = 32;
80
77
  /** The declaration is what its module exports as `export =` or `default` (carrick#2508). */
81
78
  export const FLAG_MODULE_DEFAULT = 64;
82
- /** The most `impl` rows one declaration lists, and the most `decl` rows one position lists. */
83
- export const IMPL_CAP = 16;
79
+ /** The most `decl` rows one position lists. */
80
+ export const DECL_CAP = 16;
84
81
  const COMPARE_OPERATORS = new Set([
85
82
  ts.SyntaxKind.EqualsEqualsEqualsToken,
86
83
  ts.SyntaxKind.ExclamationEqualsEqualsToken,
@@ -113,7 +110,6 @@ export function writePositionRows(options) {
113
110
  resolved: 0,
114
111
  any: 0,
115
112
  error_type: 0,
116
- impl: 0,
117
113
  jsx: 0,
118
114
  bytes: 0,
119
115
  load_ms: 0,
@@ -164,15 +160,15 @@ export function writePositionRows(options) {
164
160
  read.set(index, sourceFile?.getFilePath());
165
161
  }
166
162
  // Built once, after every file the group adds. The language service's
167
- // program is the one walked, so go-to-implementation answers over it
168
- // and no second program is built.
163
+ // program is the one walked, as it was when go-to-implementation answered
164
+ // over it (carrick#2430, dropped in #2561): its rows are pinned.
169
165
  const service = project.getLanguageService().compilerObject;
170
166
  const program = service.getProgram();
171
167
  if (!program)
172
168
  throw new Error('the language service built no program');
173
169
  counts.load_ms += performance.now() - loadStarted;
174
170
  const walkStarted = performance.now();
175
- const walker = new PositionWalker(program, service, paths, loader);
171
+ const walker = new PositionWalker(program, paths, loader);
176
172
  const missed = [];
177
173
  for (const index of indexes) {
178
174
  if (!read.has(index))
@@ -192,8 +188,6 @@ export function writePositionRows(options) {
192
188
  counts.any += 1;
193
189
  if (row[8] & FLAG_ERROR_TYPE)
194
190
  counts.error_type += 1;
195
- if (row[0] === 'impl')
196
- counts.impl += 1;
197
191
  if (row[0] === 'jsx')
198
192
  counts.jsx += 1;
199
193
  }
@@ -386,23 +380,13 @@ function toSlashes(p) {
386
380
  /** The rows of one program's files. */
387
381
  class PositionWalker {
388
382
  program;
389
- service;
390
383
  paths;
391
384
  loader;
392
385
  checker;
393
- /**
394
- * Each bodyless declaration's implementations, as `impl` rows with no span
395
- * yet (`start` and `end` are 0): go-to-implementation searches the whole
396
- * program, so it is asked once per declaration, never per call.
397
- */
398
- implementations = new Map();
399
- /** The same for a member whose symbol has no declaration, keyed by symbol. */
400
- undeclaredImplementations = new Map();
401
386
  /** Each module's exports by name, and its `export =` and `default` targets, aliases followed. */
402
387
  moduleExports = new Map();
403
- constructor(program, service, paths, loader) {
388
+ constructor(program, paths, loader) {
404
389
  this.program = program;
405
- this.service = service;
406
390
  this.paths = paths;
407
391
  this.loader = loader;
408
392
  this.checker = program.getTypeChecker();
@@ -417,8 +401,6 @@ class PositionWalker {
417
401
  if ((kind === 'call' || kind === 'member') && !(row[8] & FLAG_CHECKER_THREW)) {
418
402
  for (const decl of this.declRows(kind, node))
419
403
  rows.push(['decl', row[1], row[2], ...tail(decl)]);
420
- for (const impl of this.implRows(kind, node))
421
- rows.push(['impl', row[1], row[2], ...tail(impl)]);
422
404
  }
423
405
  }
424
406
  if (ts.isJsxOpeningElement(node) || ts.isJsxSelfClosingElement(node)) {
@@ -491,97 +473,6 @@ class PositionWalker {
491
473
  const declPackage = this.paths.declaringPackage(declaringFile.fileName, (file) => this.loader.packageOf(file));
492
474
  return { declFile, declLine, declPackage };
493
475
  }
494
- /**
495
- * The `impl` rows of a `call` or `member` row (spans unset): none unless the
496
- * row's declaration has no body of its own ({@link isBodyless}). Its own
497
- * search, apart from the row's: a throw here writes one `impl` row flagged
498
- * {@link FLAG_CHECKER_THREW} and leaves the row as it was.
499
- */
500
- implRows(kind, node) {
501
- let declaration;
502
- try {
503
- const symbol = this.symbolOf(kind, node);
504
- if (symbol && (symbol.declarations ?? []).length === 0)
505
- return this.undeclaredImplRows(kind, node, symbol);
506
- declaration = symbol ? attributedDeclaration(() => this.program, symbol.declarations ?? []) : undefined;
507
- if (!declaration || !isBodyless(declaration, this.checker))
508
- return [];
509
- }
510
- catch {
511
- return [];
512
- }
513
- let rows = this.implementations.get(declaration);
514
- if (!rows) {
515
- try {
516
- rows = this.implementationsOf(declaration);
517
- }
518
- catch {
519
- rows = [['impl', 0, 0, null, null, null, null, null, FLAG_CHECKER_THREW]];
520
- }
521
- this.implementations.set(declaration, rows);
522
- }
523
- return rows;
524
- }
525
- /**
526
- * The `impl` rows of a member whose symbol has no declaration (a mapped
527
- * type's member): there is no declaration name to ask at, so the answer is
528
- * asked at the use site's name, once per symbol. Same shape as
529
- * {@link implementationsOf}; nothing of the symbol's own is filtered out.
530
- */
531
- undeclaredImplRows(kind, node, symbol) {
532
- const cached = this.undeclaredImplementations.get(symbol);
533
- if (cached)
534
- return cached;
535
- let rows;
536
- try {
537
- const named = nameNodeOf(kind, node);
538
- rows = named ? this.implementationRows(named, []) : [];
539
- }
540
- catch {
541
- rows = [['impl', 0, 0, null, null, null, null, null, FLAG_CHECKER_THREW]];
542
- }
543
- this.undeclaredImplementations.set(symbol, rows);
544
- return rows;
545
- }
546
- /**
547
- * What go-to-implementation names for `declaration`, asked at its name:
548
- * every declaration the language service answers, except the symbol's own
549
- * (an overloaded method answers with its other signatures), in file and
550
- * position order.
551
- */
552
- implementationsOf(declaration) {
553
- const name = ts.getNameOfDeclaration(declaration) ?? declaration;
554
- const own = (this.checker.getSymbolAtLocation(name) ?? declaration.symbol)
555
- ?.declarations ?? [declaration];
556
- return this.implementationRows(name, own);
557
- }
558
- /** Go-to-implementation at `name`, minus results inside `own`, as sorted `impl` rows. */
559
- implementationRows(name, own) {
560
- const declaringFile = name.getSourceFile();
561
- const found = new Map();
562
- for (const location of this.service.getImplementationAtPosition(declaringFile.fileName, name.getStart(declaringFile)) ?? []) {
563
- const file = this.program.getSourceFile(location.fileName);
564
- if (!file)
565
- continue;
566
- const start = location.textSpan.start;
567
- if (own.some((d) => d.getSourceFile() === file && d.pos <= start && start < d.end))
568
- continue;
569
- found.set(`${location.fileName}\u0000${start}`, { file, start });
570
- }
571
- if (found.size === 0)
572
- return [];
573
- if (found.size > IMPL_CAP)
574
- return [['impl', 0, 0, null, null, null, null, null, FLAG_TOO_MANY]];
575
- const rows = [...found.values()].map(({ file, start }) => {
576
- const { declFile, declLine, declPackage } = this.located(file, start);
577
- const named = nodeStartingAt(file, start);
578
- const symbol = named ? this.checker.getSymbolAtLocation(named) : undefined;
579
- const flags = declFile === null ? FLAG_DECLARATION_UNNAMED : 0;
580
- return { start, row: ['impl', 0, 0, symbol ? ts.symbolName(symbol) : null, declFile, declLine, declPackage, null, flags] };
581
- });
582
- rows.sort((a, b) => compareNames(a.row[4], b.row[4]) || a.start - b.start);
583
- return rows.map(({ row }) => row);
584
- }
585
476
  /**
586
477
  * The declaration a member with none is attributed to (carrick#2448): the
587
478
  * mapped type node, or the alias naming it, of the receiver's type. A
@@ -709,7 +600,7 @@ class PositionWalker {
709
600
  }
710
601
  if (found.size < 2)
711
602
  return [];
712
- if (found.size > IMPL_CAP)
603
+ if (found.size > DECL_CAP)
713
604
  return [['decl', 0, 0, null, null, null, null, null, FLAG_TOO_MANY]];
714
605
  const rows = [...found].map((declaration) => {
715
606
  const file = declaration.getSourceFile();
@@ -858,40 +749,6 @@ function compareNames(a, b) {
858
749
  return -1;
859
750
  return a < b ? -1 : 1;
860
751
  }
861
- /**
862
- * Whether a declaration has no body for a call to run: an interface's or type
863
- * literal's method, a function-typed property signature, an abstract method or
864
- * property, or a function-typed class property or parameter with no
865
- * initializer. Its implementations are what go-to-implementation names.
866
- */
867
- function isBodyless(declaration, checker) {
868
- const functionTyped = () => checker.getTypeAtLocation(declaration).getNonNullableType().getCallSignatures().length > 0;
869
- if (ts.isMethodSignature(declaration))
870
- return true;
871
- if (ts.isPropertySignature(declaration))
872
- return functionTyped();
873
- if (ts.isMethodDeclaration(declaration) || ts.isPropertyDeclaration(declaration)) {
874
- if (ts.getCombinedModifierFlags(declaration) & ts.ModifierFlags.Abstract)
875
- return true;
876
- return ts.isPropertyDeclaration(declaration) && !declaration.initializer && functionTyped();
877
- }
878
- if (ts.isParameter(declaration))
879
- return !declaration.initializer && functionTyped();
880
- return false;
881
- }
882
- /** The innermost node of `file` that starts at `position` (an implementation's name). */
883
- function nodeStartingAt(file, position) {
884
- let found;
885
- const visit = (node) => {
886
- if (position < node.getStart(file) || position >= node.getEnd())
887
- return;
888
- if (node.getStart(file) === position)
889
- found = node;
890
- ts.forEachChild(node, visit);
891
- };
892
- ts.forEachChild(file, visit);
893
- return found;
894
- }
895
752
  /** The kind of row a node gives, if any (exported for the editor-parity test, carrick#2418). */
896
753
  export function kindOf(node) {
897
754
  if (ts.isCallExpression(node) || ts.isNewExpression(node) || ts.isTaggedTemplateExpression(node)) {
@@ -918,7 +775,6 @@ function nameNodeOf(kind, node) {
918
775
  return referenceName(node.left);
919
776
  case 'ident':
920
777
  return node;
921
- case 'impl':
922
778
  case 'decl':
923
779
  return undefined;
924
780
  case 'jsx':
@@ -765,8 +765,6 @@ export interface PositionRowsCounts {
765
765
  any: number;
766
766
  /** Rows whose type is the compiler's error type (flag 2). */
767
767
  error_type: number;
768
- /** `impl` rows: implementations of a bodyless declaration, or one past the cap (carrick#2430). */
769
- impl: number;
770
768
  /** `jsx` rows: one per JSX opening or self-closing element. */
771
769
  jsx: number;
772
770
  /** The rows file's size on disk, compressed. */