gitnexus 1.6.10-aptos.0 → 1.6.10-aptos.1
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/README.md +25 -0
- package/dist/cli/analyze.js +8 -0
- package/dist/core/ingestion/pipeline-phases/standalone-ingest.d.ts +6 -0
- package/dist/core/ingestion/pipeline.js +9 -0
- package/dist/core/move/consistency.d.ts +47 -1
- package/dist/core/move/consistency.js +84 -0
- package/dist/core/move/move-ingest.d.ts +3 -0
- package/dist/core/move/move-ingest.js +91 -8
- package/dist/core/run-analyze.d.ts +6 -0
- package/dist/core/run-analyze.js +1 -0
- package/dist/types/pipeline.d.ts +7 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -375,6 +375,31 @@ described in [Move compiler provisioning](#move-compiler-provisioning) —
|
|
|
375
375
|
including the `MOVE_FLOW` override and `GITNEXUS_SKIP_MOVE_FLOW=1` for
|
|
376
376
|
air-gapped hosts.
|
|
377
377
|
|
|
378
|
+
### Analyzing real-world Move repositories
|
|
379
|
+
|
|
380
|
+
Real repos routinely contain Move packages that cannot build standalone (test
|
|
381
|
+
fixtures, examples, fuzzer corpora — `aptos-core` alone has 470+). `analyze`
|
|
382
|
+
handles them per package instead of giving up:
|
|
383
|
+
|
|
384
|
+
- **Unbuildable packages are skipped with a warning**, not fatal: their
|
|
385
|
+
`.move` files stay out of the graph and the final summary names each skipped
|
|
386
|
+
package with the compiler's first diagnostic. Set `GITNEXUS_MOVE_STRICT=1`
|
|
387
|
+
to make any build failure abort the analyze instead.
|
|
388
|
+
- **`_` placeholder addresses** (`econia = "_"` in `[addresses]`) are caught
|
|
389
|
+
pre-flight — MoveFlow has no dev-mode build, so set concrete addresses in
|
|
390
|
+
`Move.toml` or exclude the package.
|
|
391
|
+
- **Builds with compiler errors still yield facts, at reduced fidelity**: the
|
|
392
|
+
MoveFlow compiler silently omits inferred `acquires` data from erroring
|
|
393
|
+
builds, so such packages are ingested with a persistent
|
|
394
|
+
"compiled with errors" warning. A common cause is a framework dependency
|
|
395
|
+
newer than MoveFlow's pinned compiler (e.g. unrecognized spec pragmas).
|
|
396
|
+
- **`.gitnexusignore`** (gitignore syntax, repo root) excludes directories from
|
|
397
|
+
analysis entirely — the fastest way to scope large repos to the packages you
|
|
398
|
+
care about, and the remedy the skip warnings suggest.
|
|
399
|
+
- **Cold builds of git-based framework dependencies can exceed the 5-minute
|
|
400
|
+
compile budget**; raise it with `GITNEXUS_MOVE_FLOW_TIMEOUT_MS` (e.g.
|
|
401
|
+
`1800000` for 30 min) for the first analyze.
|
|
402
|
+
|
|
378
403
|
## Release candidates
|
|
379
404
|
|
|
380
405
|
Stable releases publish to the default `latest` dist-tag. When a pull request
|
package/dist/cli/analyze.js
CHANGED
|
@@ -1193,6 +1193,14 @@ const analyzeCommandImpl = async (inputPath, cliOptions, runnerIdentityAtBootstr
|
|
|
1193
1193
|
` Install it once with network access (GITNEXUS_LBUG_EXTENSION_INSTALL=auto) then rerun, or\n` +
|
|
1194
1194
|
` run \`gitnexus analyze --repair-fts\` when connected. Run \`gitnexus doctor\` for details.`);
|
|
1195
1195
|
}
|
|
1196
|
+
// Standalone-ingest warnings (skipped/degraded Move packages) share the
|
|
1197
|
+
// FTS warning's rationale: mid-run progress lines scroll away, so anything
|
|
1198
|
+
// the operator must act on has to reappear in the final summary.
|
|
1199
|
+
if (result.ingestWarnings && result.ingestWarnings.length > 0) {
|
|
1200
|
+
for (const warning of result.ingestWarnings) {
|
|
1201
|
+
console.log(`\n Warning: ${warning}`);
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1196
1204
|
try {
|
|
1197
1205
|
await fs.access(getGlobalRegistryPath());
|
|
1198
1206
|
}
|
|
@@ -5,6 +5,12 @@ import type { PipelinePhase } from './types.js';
|
|
|
5
5
|
*/
|
|
6
6
|
export interface StandaloneIngestOutput {
|
|
7
7
|
readonly ingestedFiles: ReadonlySet<string>;
|
|
8
|
+
/**
|
|
9
|
+
* Operator-actionable warnings the ingester wants surfaced in the persistent
|
|
10
|
+
* CLI summary (e.g. a package it had to skip or ingest at degraded fidelity).
|
|
11
|
+
* Language-neutral: the pipeline passes these through without interpreting.
|
|
12
|
+
*/
|
|
13
|
+
readonly ingestWarnings?: readonly string[];
|
|
8
14
|
}
|
|
9
15
|
/** Default no-op used when the caller does not supply a standalone ingester. */
|
|
10
16
|
export declare const emptyStandaloneIngestPhase: PipelinePhase<StandaloneIngestOutput>;
|
|
@@ -81,6 +81,14 @@ export const runPipelineFromRepo = async (repoPath, onProgress, options) => {
|
|
|
81
81
|
const { totalFiles, usedWorkerPool } = getPhaseOutput(results, 'parse');
|
|
82
82
|
let communityResult;
|
|
83
83
|
let processResult;
|
|
84
|
+
// Standalone-ingest warnings, passed through opaquely (language-neutral).
|
|
85
|
+
let ingestWarnings;
|
|
86
|
+
try {
|
|
87
|
+
ingestWarnings = getPhaseOutput(results, 'standaloneIngest').ingestWarnings;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
/* phase filtered out of this run — nothing to surface */
|
|
91
|
+
}
|
|
84
92
|
const scopeResolutionOutput = getPhaseOutput(results, 'scopeResolution');
|
|
85
93
|
const resolutionOutcomes = scopeResolutionOutput.resolutionOutcomes;
|
|
86
94
|
// Streamed PDG-emit manifest (#2202): present only when streaming was on.
|
|
@@ -110,5 +118,6 @@ export const runPipelineFromRepo = async (repoPath, onProgress, options) => {
|
|
|
110
118
|
resolutionOutcomes,
|
|
111
119
|
usedWorkerPool,
|
|
112
120
|
pdgEmitManifest,
|
|
121
|
+
ingestWarnings,
|
|
113
122
|
};
|
|
114
123
|
};
|
|
@@ -6,7 +6,15 @@ export interface MoveConsistencyIssue {
|
|
|
6
6
|
code: 'missing-owned-caller' | 'missing-owned-callee' | 'malformed-source-evidence' | 'unresolved-resource-target'
|
|
7
7
|
/** Package with .move sources returned facts `{}` - severity policy in
|
|
8
8
|
* `emptyFactsIssue` below. */
|
|
9
|
-
| 'empty-package-facts'
|
|
9
|
+
| 'empty-package-facts'
|
|
10
|
+
/** Package skipped: move-flow could not build it (skip-and-warn, #2624). */
|
|
11
|
+
| 'package-build-failed'
|
|
12
|
+
/** Package skipped pre-flight: Move.toml [addresses] has `_` placeholders
|
|
13
|
+
* move-flow cannot resolve (it has no dev-mode build). */
|
|
14
|
+
| 'unresolved-named-address'
|
|
15
|
+
/** Package ingested, but its build carries compiler errors - move-flow
|
|
16
|
+
* silently omits inferred facts (acquires) from such builds. */
|
|
17
|
+
| 'degraded-package-facts';
|
|
10
18
|
severity: MoveConsistencySeverity;
|
|
11
19
|
message: string;
|
|
12
20
|
details?: Record<string, unknown>;
|
|
@@ -25,4 +33,42 @@ export interface EmptyFactsPackage {
|
|
|
25
33
|
* error. Pure mapping - probing the status (client I/O) stays in the phase.
|
|
26
34
|
*/
|
|
27
35
|
export declare function emptyFactsIssue(pkg: EmptyFactsPackage): MoveConsistencyIssue;
|
|
36
|
+
/**
|
|
37
|
+
* A package skipped because move-flow could not build it (skip-and-warn).
|
|
38
|
+
* Warning, not error: the analyze continues and the skip is surfaced in the
|
|
39
|
+
* CLI summary; GITNEXUS_MOVE_STRICT=1 restores the historical fatal behavior.
|
|
40
|
+
*/
|
|
41
|
+
export declare function buildFailedIssue(pkg: {
|
|
42
|
+
pkgRoot: string;
|
|
43
|
+
moveFileCount: number;
|
|
44
|
+
diagnostics: string;
|
|
45
|
+
}): MoveConsistencyIssue;
|
|
46
|
+
/**
|
|
47
|
+
* A package skipped pre-flight: its Move.toml `[addresses]` contains `_`
|
|
48
|
+
* placeholders. move-flow's `move_package_query` has no dev-mode, so the build
|
|
49
|
+
* would always fail with "Unresolved addresses" - skip with the remedy instead.
|
|
50
|
+
*/
|
|
51
|
+
export declare function unresolvedAddressIssue(pkg: {
|
|
52
|
+
pkgRoot: string;
|
|
53
|
+
moveFileCount: number;
|
|
54
|
+
placeholders: string[];
|
|
55
|
+
}): MoveConsistencyIssue;
|
|
56
|
+
/**
|
|
57
|
+
* A package that WAS ingested but whose build carries compiler errors.
|
|
58
|
+
* move-flow still serves structurally complete facts for such builds but
|
|
59
|
+
* silently drops inference-stage output (`acquiresInferred`), so the graph is
|
|
60
|
+
* missing ACQUIRES edges/properties — surface it instead of implying full
|
|
61
|
+
* fidelity. (Commonly: a framework dependency newer than move-flow's pinned
|
|
62
|
+
* compiler, e.g. spec pragmas it does not recognize.)
|
|
63
|
+
*/
|
|
64
|
+
export declare function degradedFactsIssue(pkg: {
|
|
65
|
+
pkgRoot: string;
|
|
66
|
+
diagnostics: string;
|
|
67
|
+
}): MoveConsistencyIssue;
|
|
68
|
+
/**
|
|
69
|
+
* The persistent CLI-summary warnings for a run's Move issues: the three
|
|
70
|
+
* skip/degrade codes are operator-actionable and must survive past the
|
|
71
|
+
* scrolling progress bar (same rationale as the FTS warning, #1161).
|
|
72
|
+
*/
|
|
73
|
+
export declare function cliWarningsFromIssues(issues: readonly MoveConsistencyIssue[]): string[];
|
|
28
74
|
export declare function validateMoveIngestOutput(graph: KnowledgeGraph, moveIngest: MoveIngestOutput): MoveConsistencyIssue[];
|
|
@@ -35,6 +35,90 @@ export function emptyFactsIssue(pkg) {
|
|
|
35
35
|
details: { packageRoot: pkgRoot, moveFileCount, diagnostics: status.diagnostics },
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
|
+
/** First non-empty line of a compiler diagnostic blob (for one-line summaries). */
|
|
39
|
+
function firstDiagnosticLine(diagnostics) {
|
|
40
|
+
if (!diagnostics)
|
|
41
|
+
return '';
|
|
42
|
+
for (const line of diagnostics.split('\n')) {
|
|
43
|
+
const trimmed = line.trim();
|
|
44
|
+
if (trimmed)
|
|
45
|
+
return trimmed;
|
|
46
|
+
}
|
|
47
|
+
return '';
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* A package skipped because move-flow could not build it (skip-and-warn).
|
|
51
|
+
* Warning, not error: the analyze continues and the skip is surfaced in the
|
|
52
|
+
* CLI summary; GITNEXUS_MOVE_STRICT=1 restores the historical fatal behavior.
|
|
53
|
+
*/
|
|
54
|
+
export function buildFailedIssue(pkg) {
|
|
55
|
+
const firstLine = firstDiagnosticLine(pkg.diagnostics);
|
|
56
|
+
return {
|
|
57
|
+
code: 'package-build-failed',
|
|
58
|
+
severity: 'warning',
|
|
59
|
+
message: `Move package skipped — move-flow could not build it` +
|
|
60
|
+
(firstLine ? ` (${firstLine})` : '') +
|
|
61
|
+
`: ${pkg.pkgRoot}. Fix the package or exclude its directory via .gitnexusignore; ` +
|
|
62
|
+
`set GITNEXUS_MOVE_STRICT=1 to make build failures fatal.`,
|
|
63
|
+
details: {
|
|
64
|
+
packageRoot: pkg.pkgRoot,
|
|
65
|
+
moveFileCount: pkg.moveFileCount,
|
|
66
|
+
diagnostics: pkg.diagnostics,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* A package skipped pre-flight: its Move.toml `[addresses]` contains `_`
|
|
72
|
+
* placeholders. move-flow's `move_package_query` has no dev-mode, so the build
|
|
73
|
+
* would always fail with "Unresolved addresses" - skip with the remedy instead.
|
|
74
|
+
*/
|
|
75
|
+
export function unresolvedAddressIssue(pkg) {
|
|
76
|
+
return {
|
|
77
|
+
code: 'unresolved-named-address',
|
|
78
|
+
severity: 'warning',
|
|
79
|
+
message: `Move package skipped — named address(es) ${pkg.placeholders.join(', ')} are "_" ` +
|
|
80
|
+
`placeholders in Move.toml (move-flow cannot build dev-mode): ${pkg.pkgRoot}. ` +
|
|
81
|
+
`Set concrete addresses in [addresses] or exclude the directory via .gitnexusignore.`,
|
|
82
|
+
details: {
|
|
83
|
+
packageRoot: pkg.pkgRoot,
|
|
84
|
+
moveFileCount: pkg.moveFileCount,
|
|
85
|
+
placeholders: pkg.placeholders,
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* A package that WAS ingested but whose build carries compiler errors.
|
|
91
|
+
* move-flow still serves structurally complete facts for such builds but
|
|
92
|
+
* silently drops inference-stage output (`acquiresInferred`), so the graph is
|
|
93
|
+
* missing ACQUIRES edges/properties — surface it instead of implying full
|
|
94
|
+
* fidelity. (Commonly: a framework dependency newer than move-flow's pinned
|
|
95
|
+
* compiler, e.g. spec pragmas it does not recognize.)
|
|
96
|
+
*/
|
|
97
|
+
export function degradedFactsIssue(pkg) {
|
|
98
|
+
const firstLine = firstDiagnosticLine(pkg.diagnostics);
|
|
99
|
+
return {
|
|
100
|
+
code: 'degraded-package-facts',
|
|
101
|
+
severity: 'warning',
|
|
102
|
+
message: `Move package compiled with errors — compiler-inferred facts (acquires) may be ` +
|
|
103
|
+
`incomplete` +
|
|
104
|
+
(firstLine ? ` (${firstLine})` : '') +
|
|
105
|
+
`: ${pkg.pkgRoot}`,
|
|
106
|
+
details: { packageRoot: pkg.pkgRoot, diagnostics: pkg.diagnostics },
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* The persistent CLI-summary warnings for a run's Move issues: the three
|
|
111
|
+
* skip/degrade codes are operator-actionable and must survive past the
|
|
112
|
+
* scrolling progress bar (same rationale as the FTS warning, #1161).
|
|
113
|
+
*/
|
|
114
|
+
export function cliWarningsFromIssues(issues) {
|
|
115
|
+
const surfaced = [
|
|
116
|
+
'package-build-failed',
|
|
117
|
+
'unresolved-named-address',
|
|
118
|
+
'degraded-package-facts',
|
|
119
|
+
];
|
|
120
|
+
return issues.filter((i) => surfaced.includes(i.code)).map((i) => i.message);
|
|
121
|
+
}
|
|
38
122
|
export function validateMoveIngestOutput(graph, moveIngest) {
|
|
39
123
|
const issues = [];
|
|
40
124
|
for (const [moduleQualified, filePath] of moveIngest.moduleFileMap) {
|
|
@@ -45,5 +45,8 @@ export interface MoveIngestOutput extends StandaloneIngestOutput {
|
|
|
45
45
|
}[];
|
|
46
46
|
/** Non-fatal consistency issues found after Move ingestion. */
|
|
47
47
|
consistencyIssues: MoveConsistencyIssue[];
|
|
48
|
+
/** Operator-actionable warnings for the persistent CLI summary (skipped or
|
|
49
|
+
* degraded packages). Part of the neutral StandaloneIngestOutput contract. */
|
|
50
|
+
ingestWarnings?: readonly string[];
|
|
48
51
|
}
|
|
49
52
|
export declare function createMoveIngestPhase(client: MoveFlowClient | null): PipelinePhase<MoveIngestOutput>;
|
|
@@ -19,12 +19,13 @@
|
|
|
19
19
|
* ACQUIRES/USES_TYPE/ENTRY_POINT_OF/IMPORTS edges)
|
|
20
20
|
*/
|
|
21
21
|
import * as path from 'node:path';
|
|
22
|
+
import { readFile } from 'node:fs/promises';
|
|
22
23
|
import { getPhaseOutput } from '../ingestion/pipeline-phases/types.js';
|
|
23
24
|
import { MOVE_EDGE_REASON, moveRepoRelativePath } from './constants.js';
|
|
24
25
|
import { MoveFlowToolCallError, } from './mcp-client.js';
|
|
25
26
|
import { buildLocalNameIndex, mapFactsToGraph, resolveFriendEdges, resolveLambdaHostEdges, resolveResourceEdges, resolveTypeRefEdges, } from './facts-mapper.js';
|
|
26
27
|
import { moveModuleNodeId, moveModuleQualifiedName, moveRelId } from './symbol-id.js';
|
|
27
|
-
import { emptyFactsIssue, validateMoveIngestOutput, } from './consistency.js';
|
|
28
|
+
import { buildFailedIssue, cliWarningsFromIssues, degradedFactsIssue, emptyFactsIssue, unresolvedAddressIssue, validateMoveIngestOutput, } from './consistency.js';
|
|
28
29
|
import { createMoveEntryPointEdges } from './entry-points.js';
|
|
29
30
|
function createState() {
|
|
30
31
|
return {
|
|
@@ -54,8 +55,49 @@ function toOutput(state, packageRoots, consistencyIssues = []) {
|
|
|
54
55
|
callGraphByPackage: state.callGraphByPackage,
|
|
55
56
|
droppedResourceRefs: state.droppedResourceRefs,
|
|
56
57
|
consistencyIssues,
|
|
58
|
+
ingestWarnings: cliWarningsFromIssues(consistencyIssues),
|
|
57
59
|
};
|
|
58
60
|
}
|
|
61
|
+
/** GITNEXUS_MOVE_STRICT=1|true restores the historical fatal-on-build-failure
|
|
62
|
+
* behavior instead of skip-and-warn. */
|
|
63
|
+
function isStrictMove() {
|
|
64
|
+
const v = process.env.GITNEXUS_MOVE_STRICT?.trim().toLowerCase();
|
|
65
|
+
return v === '1' || v === 'true';
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Named addresses assigned the `_` placeholder in a package's Move.toml
|
|
69
|
+
* `[addresses]` section. Deliberately a line-oriented scan, not a TOML parser:
|
|
70
|
+
* the two token shapes involved (`[section]`, `name = "_"`) are stable across
|
|
71
|
+
* every Move manifest and a full parser dependency buys nothing here.
|
|
72
|
+
* Unreadable/absent manifest → `[]` (the build itself will surface that).
|
|
73
|
+
*/
|
|
74
|
+
async function findPlaceholderAddresses(pkgRoot) {
|
|
75
|
+
let text;
|
|
76
|
+
try {
|
|
77
|
+
text = await readFile(path.join(pkgRoot, 'Move.toml'), 'utf8');
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
const placeholders = [];
|
|
83
|
+
let section = '';
|
|
84
|
+
for (const raw of text.split('\n')) {
|
|
85
|
+
const line = raw.replace(/#.*$/, '').trim();
|
|
86
|
+
if (!line)
|
|
87
|
+
continue;
|
|
88
|
+
const sectionMatch = line.match(/^\[(.+)\]$/);
|
|
89
|
+
if (sectionMatch) {
|
|
90
|
+
section = sectionMatch[1].trim();
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (section !== 'addresses')
|
|
94
|
+
continue;
|
|
95
|
+
const kv = line.match(/^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*["']_["']$/);
|
|
96
|
+
if (kv)
|
|
97
|
+
placeholders.push(kv[1]);
|
|
98
|
+
}
|
|
99
|
+
return placeholders;
|
|
100
|
+
}
|
|
59
101
|
/** Add a mapped package's nodes/edges to the graph and merge its identity maps. */
|
|
60
102
|
function applyMapped(graph, mapped, pkgRoot, state) {
|
|
61
103
|
for (const node of mapped.nodes)
|
|
@@ -121,6 +163,8 @@ export function createMoveIngestPhase(client) {
|
|
|
121
163
|
moveFilesByPackage.set(owner, files);
|
|
122
164
|
}
|
|
123
165
|
const emptyFactsPackages = [];
|
|
166
|
+
const packageIssues = [];
|
|
167
|
+
const strictMove = isStrictMove();
|
|
124
168
|
// Pass 1: per-package nodes/edges (all packages first, so cross-package
|
|
125
169
|
// CALLS in Pass 2 can resolve callees in later packages).
|
|
126
170
|
for (const pkgRoot of packageRoots) {
|
|
@@ -130,6 +174,14 @@ export function createMoveIngestPhase(client) {
|
|
|
130
174
|
message: `Ingesting Move package: ${path.basename(pkgRoot)}`,
|
|
131
175
|
stats: { filesProcessed: 0, totalFiles, nodesCreated: ctx.graph.nodeCount },
|
|
132
176
|
});
|
|
177
|
+
const pkgMoveFiles = moveFilesByPackage.get(pkgRoot) ?? [];
|
|
178
|
+
// Pre-flight: `_` placeholder addresses always fail the build (move-flow
|
|
179
|
+
// has no dev-mode), so skip before spending a compile on the known outcome.
|
|
180
|
+
const placeholders = await findPlaceholderAddresses(pkgRoot);
|
|
181
|
+
if (placeholders.length > 0) {
|
|
182
|
+
packageIssues.push(unresolvedAddressIssue({ pkgRoot, moveFileCount: pkgMoveFiles.length, placeholders }));
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
133
185
|
let callGraphData;
|
|
134
186
|
let factsMap;
|
|
135
187
|
try {
|
|
@@ -138,14 +190,30 @@ export function createMoveIngestPhase(client) {
|
|
|
138
190
|
}
|
|
139
191
|
catch (err) {
|
|
140
192
|
if (err instanceof MoveFlowToolCallError) {
|
|
141
|
-
//
|
|
142
|
-
//
|
|
143
|
-
//
|
|
144
|
-
|
|
193
|
+
// A Move package that does not build (bad manifest, missing
|
|
194
|
+
// dependency, unresolved address) is an operator problem, not a
|
|
195
|
+
// code bug. Default: skip the package (its files stay un-ingested,
|
|
196
|
+
// like the empty-facts path) and surface a persistent warning —
|
|
197
|
+
// one broken auxiliary package must not abort the whole analyze.
|
|
198
|
+
if (strictMove) {
|
|
199
|
+
// userActionable: rendered as a one-liner without a stack.
|
|
200
|
+
throw Object.assign(new Error(`move-flow could not build Move package ${pkgRoot}: ${err.message}`), { userActionable: true });
|
|
201
|
+
}
|
|
202
|
+
packageIssues.push(buildFailedIssue({
|
|
203
|
+
pkgRoot,
|
|
204
|
+
moveFileCount: pkgMoveFiles.length,
|
|
205
|
+
diagnostics: err.message,
|
|
206
|
+
}));
|
|
207
|
+
ctx.onProgress({
|
|
208
|
+
phase: 'moveIngest',
|
|
209
|
+
percent: 18,
|
|
210
|
+
message: `Skipping Move package (build failed): ${path.basename(pkgRoot)}`,
|
|
211
|
+
stats: { filesProcessed: 0, totalFiles, nodesCreated: ctx.graph.nodeCount },
|
|
212
|
+
});
|
|
213
|
+
continue;
|
|
145
214
|
}
|
|
146
215
|
throw err;
|
|
147
216
|
}
|
|
148
|
-
const pkgMoveFiles = moveFilesByPackage.get(pkgRoot) ?? [];
|
|
149
217
|
if (Object.keys(factsMap).length === 0 && pkgMoveFiles.length > 0) {
|
|
150
218
|
// Facts `{}` is ambiguous: syntax-broken packages return it as a
|
|
151
219
|
// SUCCESS (the compiler diagnostic only surfaces via
|
|
@@ -166,6 +234,14 @@ export function createMoveIngestPhase(client) {
|
|
|
166
234
|
for (const rel of pkgMoveFiles)
|
|
167
235
|
state.ingestedFiles.add(rel);
|
|
168
236
|
applyMapped(ctx.graph, mapFactsToGraph(factsMap, pkgRoot, ctx.repoPath), pkgRoot, state);
|
|
237
|
+
// Facts arrived, but move-flow serves structurally complete facts even
|
|
238
|
+
// for builds with compiler errors — and such builds silently lose the
|
|
239
|
+
// inference stage (`acquiresInferred`, hence ACQUIRES edges). Probe the
|
|
240
|
+
// build status so the degraded fidelity is surfaced, not implied away.
|
|
241
|
+
const status = await probePackageStatus(client, pkgRoot, hasStatusTool);
|
|
242
|
+
if (status && !status.ok) {
|
|
243
|
+
packageIssues.push(degradedFactsIssue({ pkgRoot, diagnostics: status.diagnostics }));
|
|
244
|
+
}
|
|
169
245
|
}
|
|
170
246
|
// Pass 2+: link edges that need the full cross-package node index.
|
|
171
247
|
linkCallEdges(ctx.graph, state);
|
|
@@ -175,10 +251,17 @@ export function createMoveIngestPhase(client) {
|
|
|
175
251
|
linkFileModuleContains(ctx.graph, state);
|
|
176
252
|
const output = toOutput(state, packageRoots);
|
|
177
253
|
createMoveEntryPointEdges(ctx.graph, output);
|
|
178
|
-
const consistencyIssues =
|
|
254
|
+
const consistencyIssues = [
|
|
255
|
+
...packageIssues,
|
|
256
|
+
...emptyFactsPackages.map(emptyFactsIssue),
|
|
257
|
+
];
|
|
179
258
|
consistencyIssues.push(...validateMoveIngestOutput(ctx.graph, output));
|
|
180
259
|
reportConsistencyIssues(ctx, consistencyIssues);
|
|
181
|
-
return {
|
|
260
|
+
return {
|
|
261
|
+
...output,
|
|
262
|
+
consistencyIssues,
|
|
263
|
+
ingestWarnings: cliWarningsFromIssues(consistencyIssues),
|
|
264
|
+
};
|
|
182
265
|
},
|
|
183
266
|
};
|
|
184
267
|
}
|
|
@@ -175,6 +175,12 @@ export interface AnalyzeResult {
|
|
|
175
175
|
* the persisted meta surface the degraded state instead of reporting healthy.
|
|
176
176
|
*/
|
|
177
177
|
ftsSkipped?: boolean;
|
|
178
|
+
/**
|
|
179
|
+
* Operator-actionable warnings from the standalone ingest phase (e.g. Move
|
|
180
|
+
* packages skipped or ingested at degraded fidelity). Rendered persistently
|
|
181
|
+
* in the CLI summary — same rationale as the FTS warning (#1161).
|
|
182
|
+
*/
|
|
183
|
+
ingestWarnings?: readonly string[];
|
|
178
184
|
/**
|
|
179
185
|
* True when the index this run produced/validated is the flat workspace
|
|
180
186
|
* slot (#2106 R2, inverted by #2354 to follow the checked-out branch).
|
package/dist/core/run-analyze.js
CHANGED
|
@@ -2091,6 +2091,7 @@ export async function runFullAnalysis(repoPath, options, callbacks, runnerIdenti
|
|
|
2091
2091
|
stats: meta.stats,
|
|
2092
2092
|
pipelineResult,
|
|
2093
2093
|
ftsSkipped: !ftsReady,
|
|
2094
|
+
ingestWarnings: pipelineResult.ingestWarnings,
|
|
2094
2095
|
isPrimaryBranch: !placement.branch,
|
|
2095
2096
|
};
|
|
2096
2097
|
}
|
package/dist/types/pipeline.d.ts
CHANGED
|
@@ -34,4 +34,11 @@ export interface PipelineResult {
|
|
|
34
34
|
* layer (if any) is resident in `graph` and persists via the whole-graph emit.
|
|
35
35
|
*/
|
|
36
36
|
pdgEmitManifest?: PdgEmitManifest;
|
|
37
|
+
/**
|
|
38
|
+
* Operator-actionable warnings from the standalone ingest phase (skipped or
|
|
39
|
+
* degraded-fidelity packages). Passed through opaquely — the pipeline does
|
|
40
|
+
* not know which language produced them — so the CLI summary can render them
|
|
41
|
+
* persistently (same rationale as the FTS warning).
|
|
42
|
+
*/
|
|
43
|
+
ingestWarnings?: readonly string[];
|
|
37
44
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gitnexus",
|
|
3
|
-
"version": "1.6.10-aptos.
|
|
3
|
+
"version": "1.6.10-aptos.1",
|
|
4
4
|
"description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
|
|
5
5
|
"author": "Abhigyan Patwari",
|
|
6
6
|
"license": "PolyForm-Noncommercial-1.0.0",
|