carrick 0.3.118 → 0.3.119

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.118",
3
+ "version": "0.3.119",
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.118",
117
- "@carrick-tools/cli-darwin-x64": "0.3.118",
118
- "@carrick-tools/cli-linux-arm64": "0.3.118",
119
- "@carrick-tools/cli-linux-x64": "0.3.118",
120
- "@carrick-tools/cli-win32-x64": "0.3.118"
116
+ "@carrick-tools/cli-darwin-arm64": "0.3.119",
117
+ "@carrick-tools/cli-darwin-x64": "0.3.119",
118
+ "@carrick-tools/cli-linux-arm64": "0.3.119",
119
+ "@carrick-tools/cli-linux-x64": "0.3.119",
120
+ "@carrick-tools/cli-win32-x64": "0.3.119"
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.118",
4
+ "version": "0.3.119",
5
5
  "author": {
6
6
  "name": "Carrick",
7
7
  "email": "hello@carrick.tools"
@@ -89,6 +89,20 @@ const RUNTIME_TYPE_PACKAGES = new Set([
89
89
  * package's, never the runtime module.
90
90
  */
91
91
  const RUNTIME_MODULE = /^node:/;
92
+ /**
93
+ * A key for the language's own library (carrick#2445): `lib:<lib file>`
94
+ * (`lib:lib.dom.d.ts`) names the globals that default-library file declares.
95
+ * Its installed version is the compiler's, so the store keys it
96
+ * `lib:lib.dom.d.ts@<typescript version>`. A global has no specifier: the
97
+ * probe reads it as `globalThis.<name>`, and its home is the default-library
98
+ * file set (`DEFAULT_LIBRARY_HOME`).
99
+ */
100
+ const DEFAULT_LIBRARY = /^lib:/;
101
+ /**
102
+ * The owner a home names for every default-library file. No package name
103
+ * holds a `:`, so only a `lib:` key's home ever holds it.
104
+ */
105
+ const DEFAULT_LIBRARY_HOME = 'lib:';
92
106
  /** A dependency range that names the service's own source, not a registry release. */
93
107
  const LOCAL_RANGE = /^(workspace|file|link|portal):/;
94
108
  /** A resolved module lands on TypeScript: a declaration file or source. */
@@ -283,7 +297,7 @@ export class LibraryClaimsVerifier {
283
297
  }
284
298
  const importLines = importKeys.map((key, i) => {
285
299
  const [pkg, name] = JSON.parse(key);
286
- return importLine(pkg, name, `__carrick_e${i}`);
300
+ return probeLine(pkg, name, `__carrick_e${i}`);
287
301
  });
288
302
  // One statement per receiver a message check's maker or scope claim
289
303
  // builds, after the imports: that receiver built with no argument and no
@@ -322,7 +336,8 @@ export class LibraryClaimsVerifier {
322
336
  const exportReads = new Map();
323
337
  const httpReceivers = new Map();
324
338
  const judged = new Map();
325
- const declarationOf = (check) => file.statements[importIndex.get(exportKey(check))];
339
+ /** The probe's import of the check's export, or its read of a global (`probeLine`). */
340
+ const statementOf = (check) => file.statements[importIndex.get(exportKey(check))];
326
341
  /** The probe's no-argument build of `receiver` on the check's export, resolved. */
327
342
  const atDefaults = (check, receiver) => {
328
343
  const index = builtIndex.get(builtKey(check, receiver));
@@ -333,7 +348,9 @@ export class LibraryClaimsVerifier {
333
348
  const key = `${runtimeModules}\u0000${check.package}`;
334
349
  let moduleRead = moduleReads.get(key);
335
350
  if (!moduleRead) {
336
- moduleRead = reader.readModule(check.package, declarationOf(check), runtimeModules);
351
+ moduleRead = DEFAULT_LIBRARY.test(check.package)
352
+ ? reader.readDefaultLibrary(check.package)
353
+ : reader.readModule(check.package, statementOf(check), runtimeModules);
337
354
  moduleReads.set(key, moduleRead);
338
355
  }
339
356
  return moduleRead;
@@ -342,7 +359,9 @@ export class LibraryClaimsVerifier {
342
359
  const key = exportKey(check);
343
360
  let exportRead = exportReads.get(key);
344
361
  if (!exportRead) {
345
- exportRead = reader.readExport(declarationOf(check));
362
+ exportRead = DEFAULT_LIBRARY.test(check.package)
363
+ ? reader.readGlobal(check.package, statementOf(check))
364
+ : reader.readExport(statementOf(check));
346
365
  exportReads.set(key, exportRead);
347
366
  }
348
367
  return exportRead;
@@ -534,15 +553,25 @@ export class LibraryClaimsVerifier {
534
553
  return { surfaces: [], surface_sha256: fullSurfaceSha256([]) };
535
554
  // Each specifier twice: as a namespace, which holds its named exports, and
536
555
  // as a default import, which is how a module that exports a value whole
537
- // (`export =`) is imported as `default`.
538
- const imports = packages.flatMap((pkg, i) => [
539
- `import * as __carrick_ns${i} from ${JSON.stringify(pkg)};`,
540
- importLine(pkg, 'default', `__carrick_d${i}`),
541
- ]);
542
- const probeOf = (file, i) => ({
543
- namespace: file.statements[2 * i],
544
- defaultImport: file.statements[2 * i + 1],
556
+ // (`export =`) is imported as `default`. A `lib:` key imports nothing: its
557
+ // globals are read from the file it names.
558
+ const imports = [];
559
+ const importAt = packages.map((pkg, i) => {
560
+ if (DEFAULT_LIBRARY.test(pkg))
561
+ return undefined;
562
+ const at = imports.length;
563
+ imports.push(`import * as __carrick_ns${i} from ${JSON.stringify(pkg)};`, importLine(pkg, 'default', `__carrick_d${i}`));
564
+ return at;
545
565
  });
566
+ const probeOf = (file, i) => {
567
+ const at = importAt[i];
568
+ return at === undefined
569
+ ? { defaultLibrary: packages[i] }
570
+ : {
571
+ namespace: file.statements[at],
572
+ defaultImport: file.statements[at + 1],
573
+ };
574
+ };
546
575
  const makers = this.readProbe(fromDir, imports, (_checker, reader, file) => packages.map((pkg, i) => reader.makersOf(pkg, probeOf(file, i), only[pkg])));
547
576
  const importLines = [];
548
577
  const buildLines = [];
@@ -550,7 +579,7 @@ export class LibraryClaimsVerifier {
550
579
  packages.forEach((pkg, i) => {
551
580
  for (const { export: name, receivers } of makers[i]) {
552
581
  const local = `__carrick_e${importLines.length}`;
553
- importLines.push(importLine(pkg, name, local));
582
+ importLines.push(probeLine(pkg, name, local));
554
583
  for (const receiver of receivers) {
555
584
  const expression = receiverExpression(local, receiver);
556
585
  if (expression === undefined)
@@ -744,6 +773,18 @@ function typeSymbols(type) {
744
773
  }
745
774
  return symbols;
746
775
  }
776
+ /**
777
+ * The probe's read of one export, bound to `local`: its import, or for a
778
+ * `lib:` key the global itself, as `globalThis` holds it. A block-scoped
779
+ * global (`declare const`) is not on `globalThis`; no default-library file
780
+ * declares one.
781
+ */
782
+ function probeLine(pkg, name, local) {
783
+ if (!DEFAULT_LIBRARY.test(pkg))
784
+ return importLine(pkg, name, local);
785
+ const access = IDENTIFIER.test(name) ? `.${name}` : `[${JSON.stringify(name)}]`;
786
+ return `const ${local} = globalThis${access};`;
787
+ }
747
788
  /** The probe's import of one export, bound to `local`. */
748
789
  function importLine(pkg, name, local) {
749
790
  const specifier = JSON.stringify(pkg);
@@ -943,6 +984,54 @@ class DeclarationReader {
943
984
  ?.redirectInfo?.redirectTarget;
944
985
  return target === file && this.isInstalledFile(file.fileName);
945
986
  }
987
+ /**
988
+ * A `lib:` key: the default-library file it names, as the program's own
989
+ * `lib` setting loads it, read by the compiler that built the program. A
990
+ * file the program does not load is no module reason: each global answers
991
+ * `export_missing` (`readGlobal`).
992
+ */
993
+ readDefaultLibrary(pkg) {
994
+ const entry = { package: pkg, installed_version: ts.version };
995
+ const file = this.defaultLibraryFile(pkg);
996
+ if (file)
997
+ entry.resolved_file = file.fileName;
998
+ return { entry };
999
+ }
1000
+ /** The default-library file a `lib:` key names, when the program loads it. */
1001
+ defaultLibraryFile(pkg) {
1002
+ const name = pkg.slice('lib:'.length);
1003
+ return this.program
1004
+ .getSourceFiles()
1005
+ .find(file => this.program.isSourceFileDefaultLibrary(file) && path.basename(file.fileName) === name);
1006
+ }
1007
+ /**
1008
+ * `T` for a global (`probeLine`'s `globalThis` read): the type the probe's
1009
+ * local gets, and the global it names. The global must be a value the
1010
+ * key's lib file declares; one only another file declares (the runtime's
1011
+ * types, the service) is missing from it.
1012
+ */
1013
+ readGlobal(pkg, statement) {
1014
+ const declaration = statement && ts.isVariableStatement(statement) ? statement.declarationList.declarations[0] : undefined;
1015
+ const access = declaration?.initializer;
1016
+ const name = access && ts.isPropertyAccessExpression(access)
1017
+ ? access.name
1018
+ : access && ts.isElementAccessExpression(access)
1019
+ ? access.argumentExpression
1020
+ : undefined;
1021
+ const target = name ? this.checker.getSymbolAtLocation(name) : undefined;
1022
+ const file = this.defaultLibraryFile(pkg);
1023
+ if (!declaration ||
1024
+ !target ||
1025
+ !file ||
1026
+ !(target.flags & ts.SymbolFlags.Value) ||
1027
+ !(target.declarations ?? []).some(each => each.getSourceFile() === file)) {
1028
+ return { reason: 'export_missing' };
1029
+ }
1030
+ const type = this.checker.getTypeAtLocation(declaration.name);
1031
+ if (this.isOpenTop(type))
1032
+ return { reason: 'export_untyped' };
1033
+ return { value: { type, target } };
1034
+ }
946
1035
  /** `T`: the type the probe's import gets, and the declaration it names. */
947
1036
  readExport(declaration) {
948
1037
  const clause = declaration.importClause;
@@ -1038,6 +1127,9 @@ class DeclarationReader {
1038
1127
  * sub-object's, along a claim's `path`).
1039
1128
  */
1040
1129
  homeOf(pkg, symbols, base) {
1130
+ // A global's home is the default-library file set, and only that.
1131
+ if (DEFAULT_LIBRARY.test(pkg))
1132
+ return base ?? new Set([DEFAULT_LIBRARY_HOME]);
1041
1133
  const named = packageNameOf(pkg);
1042
1134
  const home = new Set(base ?? [named, typesPackageOf(named)]);
1043
1135
  const runtime = RUNTIME_MODULE.test(pkg) || RUNTIME_TYPE_PACKAGES.has(named) || RUNTIME_TYPE_PACKAGES.has(typesPackageOf(named));
@@ -1061,6 +1153,8 @@ class DeclarationReader {
1061
1153
  return installed === undefined ? undefined : installed.packageName ?? installed.directoryName;
1062
1154
  }
1063
1155
  isOwnFile(file, home) {
1156
+ if (this.program.isSourceFileDefaultLibrary(file))
1157
+ return home.has(DEFAULT_LIBRARY_HOME);
1064
1158
  const owner = this.packageOf(file);
1065
1159
  return owner !== undefined && home.has(owner);
1066
1160
  }
@@ -2231,7 +2325,7 @@ class DeclarationReader {
2231
2325
  this.setPackage(pkg);
2232
2326
  // Runtime modules on: a `node:` specifier is listed from the runtime's
2233
2327
  // types package, as the message roles read it.
2234
- const moduleRead = this.readModule(pkg, probe.namespace, true);
2328
+ const moduleRead = 'defaultLibrary' in probe ? this.readDefaultLibrary(pkg) : this.readModule(pkg, probe.namespace, true);
2235
2329
  const surface = { package: pkg, truncated: 0, exports: [] };
2236
2330
  if (moduleRead.entry.resolved_file)
2237
2331
  surface.resolved_file = moduleRead.entry.resolved_file;
@@ -2294,7 +2388,7 @@ class DeclarationReader {
2294
2388
  */
2295
2389
  makersOf(pkg, probe, only) {
2296
2390
  this.setPackage(pkg);
2297
- if (this.readModule(pkg, probe.namespace, true).reason)
2391
+ if ('namespace' in probe && this.readModule(pkg, probe.namespace, true).reason)
2298
2392
  return [];
2299
2393
  return (this.listedExports(probe, only) ?? [])
2300
2394
  .filter(({ type }) => !this.isOpenTop(type))
@@ -2314,6 +2408,8 @@ class DeclarationReader {
2314
2408
  * resolves to no module symbol.
2315
2409
  */
2316
2410
  listedExports(probe, only) {
2411
+ if ('defaultLibrary' in probe)
2412
+ return this.listedGlobals(probe.defaultLibrary, only);
2317
2413
  const moduleSymbol = this.checker.getSymbolAtLocation(probe.namespace.moduleSpecifier);
2318
2414
  if (!moduleSymbol)
2319
2415
  return undefined;
@@ -2339,6 +2435,23 @@ class DeclarationReader {
2339
2435
  }
2340
2436
  return listed.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
2341
2437
  }
2438
+ /**
2439
+ * The value globals a `lib:` key's file declares (every one, or only those
2440
+ * `only` names), sorted by name, each with its declared type: none when the
2441
+ * program's `lib` setting does not load the file.
2442
+ */
2443
+ listedGlobals(pkg, only) {
2444
+ const file = this.defaultLibraryFile(pkg);
2445
+ if (!file)
2446
+ return [];
2447
+ return this.checker
2448
+ .getSymbolsInScope(this.probe, ts.SymbolFlags.Value)
2449
+ .filter(symbol => (symbol.flags & ts.SymbolFlags.Prototype) === 0 &&
2450
+ (only === undefined || only.includes(symbol.getName())) &&
2451
+ (symbol.declarations ?? []).some(declaration => declaration.getSourceFile() === file))
2452
+ .map(symbol => ({ name: symbol.getName(), target: symbol, type: this.checker.getTypeOfSymbol(symbol) }))
2453
+ .sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
2454
+ }
2342
2455
  /**
2343
2456
  * The ways an export makes a receiver, in listing order: calling it
2344
2457
  * (`instance:()`), constructing it (`instance:new`), then calling or
@@ -55,6 +55,15 @@ export declare const FLAG_CHECKER_THREW = 4;
55
55
  export declare const FLAG_DECLARATION_UNNAMED = 8;
56
56
  /** An `impl` row standing for more implementations than {@link IMPL_CAP}; it names none. */
57
57
  export declare const FLAG_TOO_MANY = 16;
58
+ /**
59
+ * The declaration is published under the row's symbol name: its module
60
+ * exports it by that name, or it is a global (a script's top-level
61
+ * declaration, or one in `declare global`). A member of a class, interface,
62
+ * type literal or object literal never is (carrick#2508).
63
+ */
64
+ export declare const FLAG_PUBLISHED = 32;
65
+ /** The declaration is what its module exports as `export =` or `default` (carrick#2508). */
66
+ export declare const FLAG_MODULE_DEFAULT = 64;
58
67
  /** The most implementations one declaration's `impl` rows list. */
59
68
  export declare const IMPL_CAP = 16;
60
69
  /** The kinds {@link kindOf} gives a node; `impl` and `jsx` rows are written beside them. */
@@ -60,6 +60,15 @@ export const FLAG_CHECKER_THREW = 4;
60
60
  export const FLAG_DECLARATION_UNNAMED = 8;
61
61
  /** An `impl` row standing for more implementations than {@link IMPL_CAP}; it names none. */
62
62
  export const FLAG_TOO_MANY = 16;
63
+ /**
64
+ * The declaration is published under the row's symbol name: its module
65
+ * exports it by that name, or it is a global (a script's top-level
66
+ * declaration, or one in `declare global`). A member of a class, interface,
67
+ * type literal or object literal never is (carrick#2508).
68
+ */
69
+ export const FLAG_PUBLISHED = 32;
70
+ /** The declaration is what its module exports as `export =` or `default` (carrick#2508). */
71
+ export const FLAG_MODULE_DEFAULT = 64;
63
72
  /** The most implementations one declaration's `impl` rows list. */
64
73
  export const IMPL_CAP = 16;
65
74
  const COMPARE_OPERATORS = new Set([
@@ -379,6 +388,8 @@ class PositionWalker {
379
388
  implementations = new Map();
380
389
  /** The same for a member whose symbol has no declaration, keyed by symbol. */
381
390
  undeclaredImplementations = new Map();
391
+ /** Each module's exports by name, and its `export =` and `default` targets, aliases followed. */
392
+ moduleExports = new Map();
382
393
  constructor(program, service, paths, loader) {
383
394
  this.program = program;
384
395
  this.service = service;
@@ -424,6 +435,9 @@ class PositionWalker {
424
435
  this.ownerDeclaration(kind, node, symbol);
425
436
  if (!declaration)
426
437
  return [kind, start, end, ts.symbolName(symbol), null, null, null, typeText, flags];
438
+ // A declaration named through its owner's type is a member.
439
+ if ((symbol.declarations ?? []).includes(declaration))
440
+ flags |= this.publication(symbol, declaration);
427
441
  // A file's own module symbol is named by the compiler as the quoted
428
442
  // absolute file name (`"/<checkout>/pkg/index"`). Name it as `decl_file`
429
443
  // names the file. A symbol that merely lives in a file (CommonJS
@@ -580,6 +594,68 @@ class PositionWalker {
580
594
  const owner = holders[0].getSymbol() ?? holders[0].aliasSymbol;
581
595
  return attributedDeclaration(() => this.program, owner?.declarations ?? []);
582
596
  }
597
+ /**
598
+ * How `declaration`'s module publishes `symbol`: {@link FLAG_PUBLISHED}
599
+ * when under the symbol's own name (or as a global), and
600
+ * {@link FLAG_MODULE_DEFAULT} when as the module's `export =` or `default`.
601
+ * The module is the nearest ambient `declare module "…"` or the file.
602
+ */
603
+ publication(symbol, declaration) {
604
+ let container = declaration.parent;
605
+ while (container && !ts.isSourceFile(container) && !ts.isModuleBlock(container)) {
606
+ // Anything but a statement list between the declaration and its module
607
+ // (a class, interface, type or object literal, a function body) makes
608
+ // it a member or a local.
609
+ if (!ts.isVariableDeclarationList(container) && !ts.isVariableStatement(container))
610
+ return 0;
611
+ container = container.parent;
612
+ }
613
+ if (!container)
614
+ return 0;
615
+ const block = ts.isModuleBlock(container) ? container.parent : undefined;
616
+ if (block && block.flags & ts.NodeFlags.GlobalAugmentation)
617
+ return FLAG_PUBLISHED;
618
+ // A namespace's member is published when the module its file is publishes it.
619
+ if (block && !ts.isStringLiteral(block.name))
620
+ return this.publishedByExports(symbol, declaration);
621
+ const moduleSymbol = this.checker.getSymbolAtLocation(block ? block.name : container);
622
+ if (moduleSymbol)
623
+ return this.publishedIn(moduleSymbol, symbol);
624
+ // A script's top-level declaration is a global.
625
+ return ts.isSourceFile(container) && !ts.isExternalModule(container) ? FLAG_PUBLISHED : 0;
626
+ }
627
+ /** A namespace member, found among the exports of the module it sits in. */
628
+ publishedByExports(symbol, declaration) {
629
+ for (let node = declaration.parent; node; node = node.parent) {
630
+ if (ts.isModuleDeclaration(node) && ts.isStringLiteral(node.name)) {
631
+ const moduleSymbol = this.checker.getSymbolAtLocation(node.name);
632
+ return moduleSymbol ? this.publishedIn(moduleSymbol, symbol) : 0;
633
+ }
634
+ if (ts.isSourceFile(node)) {
635
+ const moduleSymbol = this.checker.getSymbolAtLocation(node);
636
+ return moduleSymbol ? this.publishedIn(moduleSymbol, symbol) & FLAG_PUBLISHED : 0;
637
+ }
638
+ }
639
+ return 0;
640
+ }
641
+ publishedIn(moduleSymbol, symbol) {
642
+ let exports = this.moduleExports.get(moduleSymbol);
643
+ if (!exports) {
644
+ const resolve = (s) => s.flags & ts.SymbolFlags.Alias ? this.checker.getAliasedSymbol(s) : s;
645
+ const byName = new Map();
646
+ for (const exported of this.checker.getExportsOfModule(moduleSymbol)) {
647
+ byName.set(exported.getName(), resolve(exported));
648
+ }
649
+ const wholes = [ts.InternalSymbolName.ExportEquals, ts.InternalSymbolName.Default]
650
+ .map((key) => moduleSymbol.exports?.get(key))
651
+ .filter((own) => own !== undefined)
652
+ .map(resolve);
653
+ exports = { byName, wholes };
654
+ this.moduleExports.set(moduleSymbol, exports);
655
+ }
656
+ return ((exports.byName.get(symbol.getName()) === symbol ? FLAG_PUBLISHED : 0) |
657
+ (exports.wholes.includes(symbol) ? FLAG_MODULE_DEFAULT : 0));
658
+ }
583
659
  /** The row's symbol, following aliases to a target that has a declaration. */
584
660
  symbolOf(kind, node) {
585
661
  let symbol;