homegraph 1.6.2 → 1.6.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 CHANGED
@@ -10,6 +10,16 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
10
10
  ## [Unreleased]
11
11
 
12
12
 
13
+ ## [1.6.3] - 2026-10-22
14
+
15
+ ### Improvements
16
+
17
+ - Release workflow jobs are split so a failed stage can be re-run alone: unit tests, CHANGELOG prepare, GitHub Release, npm publish, long registry verify, then OHOS API db packages.
18
+
19
+ ### Fixes
20
+
21
+ - ArkTS: cross-file `imports` and `extends`/`implements` edges are no longer dropped during per-file persist. They ride the same `crossFileEdges` path as calls. Built-in ArkUI decorators (`@State`, `@Builder`, …) are not fuzzy-matched onto unrelated same-named symbols (Spec 0059).
22
+
13
23
  ## [1.6.2] - 2026-10-19
14
24
 
15
25
  ### New Features
@@ -305,3 +315,4 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
305
315
  [1.6.0]: https://github.com/fujiaxin-coder/homegraph/releases/tag/v1.6.0
306
316
  [1.6.1]: https://github.com/fujiaxin-coder/homegraph/releases/tag/v1.6.1
307
317
  [1.6.2]: https://github.com/fujiaxin-coder/homegraph/releases/tag/v1.6.2
318
+ [1.6.3]: https://github.com/fujiaxin-coder/homegraph/releases/tag/v1.6.3
@@ -2026,6 +2026,47 @@ function filesHaveArkUiEntries(files) {
2026
2026
  // ArkUI ViewTree — component tree, @Prop/@Link transfer, event bindings
2027
2027
  // =============================================================================
2028
2028
  const VIEWTREE_CALLBACK_ATTRS = new Set(arkanalyzer_1.CALLBACK_METHOD_NAME);
2029
+ /**
2030
+ * Framework decorators with no project-local definition. Emitting them as
2031
+ * unresolved `decorates` refs lets name-matcher bind @State → enum State, etc.
2032
+ */
2033
+ const ARKUI_BUILTIN_DECORATORS = new Set([
2034
+ 'State',
2035
+ 'Prop',
2036
+ 'Link',
2037
+ 'Provide',
2038
+ 'Consume',
2039
+ 'Watch',
2040
+ 'Builder',
2041
+ 'BuilderParam',
2042
+ 'Styles',
2043
+ 'Extend',
2044
+ 'AnimatableExtend',
2045
+ 'Component',
2046
+ 'ComponentV2',
2047
+ 'Entry',
2048
+ 'CustomDialog',
2049
+ 'Observed',
2050
+ 'ObservedV2',
2051
+ 'ObjectLink',
2052
+ 'LocalStorageLink',
2053
+ 'LocalStorageProp',
2054
+ 'StorageLink',
2055
+ 'StorageProp',
2056
+ 'Track',
2057
+ 'Require',
2058
+ 'Once',
2059
+ 'Reusable',
2060
+ 'Concurrent',
2061
+ 'Sendable',
2062
+ 'Local',
2063
+ 'Param',
2064
+ 'Event',
2065
+ 'Monitor',
2066
+ 'Computed',
2067
+ 'Trace',
2068
+ 'Type',
2069
+ ]);
2029
2070
  /** State decorator kinds on a field (@State, @Prop, @Link, …) from arkanalyzer. */
2030
2071
  function stateDecoratorKinds(field) {
2031
2072
  const decs = field.getStateDecorators?.();
@@ -2727,6 +2768,11 @@ class ArkTSAdapter {
2727
2768
  continue;
2728
2769
  if (!this.scanned.has(rel) || !isArkAnalyzerSourcePath(rel))
2729
2770
  continue;
2771
+ // Already indexed (usually streamed to DB). Re-running indexScannedFile
2772
+ // would hit addNode's nodeIds short-circuit and leave an empty shell;
2773
+ // live IR rebind is handled by bindLiveMapsFromResident.
2774
+ if (this.nodeIds.has(`file:${rel}`))
2775
+ continue;
2730
2776
  this.indexScannedFile(arkFile);
2731
2777
  if (this.fileResults.has(rel))
2732
2778
  seeded.push(rel);
@@ -3279,6 +3325,20 @@ class ArkTSAdapter {
3279
3325
  const result = this.fileResults.get(relativePath);
3280
3326
  return result?.nodes.some((n) => n.id === nodeId) ?? false;
3281
3327
  }
3328
+ /**
3329
+ * Same-file edges stay on the file's ExtractionResult (persistFileResult FK
3330
+ * filter). Cross-file edges go to crossFileEdges and are inserted after all
3331
+ * modules persist — do not require nodeIds.has(target) at emit time (target
3332
+ * may be indexed later in the same batch).
3333
+ */
3334
+ addMaybeCrossFileEdge(result, callerFile, edge) {
3335
+ if (this.nodeInFile(edge.target, callerFile)) {
3336
+ result.edges.push(edge);
3337
+ }
3338
+ else {
3339
+ this.crossFileEdges.push(edge);
3340
+ }
3341
+ }
3282
3342
  ensureFileResult(relativePath, lineCount) {
3283
3343
  let result = this.fileResults.get(relativePath);
3284
3344
  if (!result) {
@@ -3431,6 +3491,10 @@ class ArkTSAdapter {
3431
3491
  const kind = dec.getKind();
3432
3492
  if (!kind)
3433
3493
  continue;
3494
+ // Built-in ArkUI/ArkTS decorators have no project definition; name-match
3495
+ // would falsely link @State → enum State, @Builder → class Builder, etc.
3496
+ if (ARKUI_BUILTIN_DECORATORS.has(kind))
3497
+ continue;
3434
3498
  result.unresolvedReferences.push({
3435
3499
  fromNodeId,
3436
3500
  referenceName: kind,
@@ -3529,17 +3593,62 @@ class ArkTSAdapter {
3529
3593
  if (superName) {
3530
3594
  const superCls = cls.getHeritageClass(superName);
3531
3595
  if (superCls && !superCls.isDefaultArkClass()) {
3532
- const superId = this.classToId.get(superCls);
3596
+ const superId = this.classToId.get(superCls) ?? this.resolveClassNodeId(superCls);
3597
+ const edgeKind = superCls.getCategory() === CLASS_CATEGORY.INTERFACE ? 'implements' : 'extends';
3533
3598
  if (superId) {
3534
- const edgeKind = superCls.getCategory() === CLASS_CATEGORY.INTERFACE ? 'implements' : 'extends';
3535
- result.edges.push(arkEdge(classNode.id, superId, edgeKind));
3599
+ this.addMaybeCrossFileEdge(result, relativePath, arkEdge(classNode.id, superId, edgeKind));
3600
+ }
3601
+ else {
3602
+ const simple = superName.includes('.') ? superName.split('.').pop() : superName;
3603
+ if (simple && simple !== 'Object') {
3604
+ result.unresolvedReferences.push({
3605
+ fromNodeId: classNode.id,
3606
+ referenceName: simple,
3607
+ referenceKind: edgeKind,
3608
+ line,
3609
+ column: col,
3610
+ filePath: relativePath,
3611
+ language,
3612
+ });
3613
+ }
3614
+ }
3615
+ }
3616
+ else if (superName && superName !== 'Object') {
3617
+ const simple = superName.includes('.') ? superName.split('.').pop() : superName;
3618
+ if (simple) {
3619
+ result.unresolvedReferences.push({
3620
+ fromNodeId: classNode.id,
3621
+ referenceName: simple,
3622
+ referenceKind: 'extends',
3623
+ line,
3624
+ column: col,
3625
+ filePath: relativePath,
3626
+ language,
3627
+ });
3536
3628
  }
3537
3629
  }
3538
3630
  }
3539
3631
  for (const ifaceName of cls.getImplementedInterfaceNames()) {
3540
3632
  const iface = cls.getImplementedInterface(ifaceName);
3541
- if (iface && this.classToId.has(iface)) {
3542
- result.edges.push(arkEdge(classNode.id, this.classToId.get(iface), 'implements'));
3633
+ const ifaceId = iface
3634
+ ? (this.classToId.get(iface) ?? this.resolveClassNodeId(iface))
3635
+ : null;
3636
+ if (ifaceId) {
3637
+ this.addMaybeCrossFileEdge(result, relativePath, arkEdge(classNode.id, ifaceId, 'implements'));
3638
+ }
3639
+ else if (ifaceName) {
3640
+ const simple = ifaceName.includes('.') ? ifaceName.split('.').pop() : ifaceName;
3641
+ if (simple) {
3642
+ result.unresolvedReferences.push({
3643
+ fromNodeId: classNode.id,
3644
+ referenceName: simple,
3645
+ referenceKind: 'implements',
3646
+ line,
3647
+ column: col,
3648
+ filePath: relativePath,
3649
+ language,
3650
+ });
3651
+ }
3543
3652
  }
3544
3653
  }
3545
3654
  for (const method of cls.getMethods(true)) {
@@ -4017,12 +4126,34 @@ class ArkTSAdapter {
4017
4126
  const targetFile = exportInfo.getDeclaringArkFile();
4018
4127
  if (targetFile) {
4019
4128
  const targetRel = this.normalizeRelPath(targetFile.getFilePath());
4020
- const targetFileId = `file:${targetRel}`;
4021
- if (this.nodeIds.has(targetFileId)) {
4022
- result.edges.push(arkEdge(importNode.id, targetFileId, 'imports', {
4129
+ if (targetRel) {
4130
+ const targetFileId = `file:${targetRel}`;
4131
+ this.addMaybeCrossFileEdge(result, relativePath, arkEdge(importNode.id, targetFileId, 'imports', {
4023
4132
  metadata: { synthesizedBy: 'arkanalyzer', module: modulePath },
4024
4133
  }));
4025
4134
  }
4135
+ else if (modulePath) {
4136
+ result.unresolvedReferences.push({
4137
+ fromNodeId: importNode.id,
4138
+ referenceName: modulePath,
4139
+ referenceKind: 'imports',
4140
+ line,
4141
+ column: 0,
4142
+ filePath: relativePath,
4143
+ language,
4144
+ });
4145
+ }
4146
+ }
4147
+ else if (modulePath) {
4148
+ result.unresolvedReferences.push({
4149
+ fromNodeId: importNode.id,
4150
+ referenceName: modulePath,
4151
+ referenceKind: 'imports',
4152
+ line,
4153
+ column: 0,
4154
+ filePath: relativePath,
4155
+ language,
4156
+ });
4026
4157
  }
4027
4158
  }
4028
4159
  else if (modulePath) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "homegraph",
3
- "version": "1.6.2",
3
+ "version": "1.6.3",
4
4
  "description": "Supercharge AI coding agents with semantic code intelligence — surgical context, fewer tool calls, faster answers. 100% local.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",