@lamentis/naome 1.1.2 → 1.2.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/Cargo.lock +2 -2
- package/Cargo.toml +1 -1
- package/LICENSE +180 -21
- package/README.md +49 -6
- package/bin/naome-node.js +2 -1579
- package/bin/naome.js +68 -16
- package/crates/naome-cli/Cargo.toml +1 -1
- package/crates/naome-cli/src/check_commands.rs +135 -0
- package/crates/naome-cli/src/cli_args.rs +5 -0
- package/crates/naome-cli/src/dispatcher.rs +37 -0
- package/crates/naome-cli/src/install_bridge.rs +83 -0
- package/crates/naome-cli/src/main.rs +60 -341
- package/crates/naome-cli/src/prompt_commands.rs +68 -0
- package/crates/naome-cli/src/quality_commands.rs +229 -0
- package/crates/naome-cli/src/simple_commands.rs +53 -0
- package/crates/naome-cli/src/workflow_commands.rs +153 -0
- package/crates/naome-core/Cargo.toml +1 -1
- package/crates/naome-core/src/decision/checks.rs +64 -0
- package/crates/naome-core/src/decision/idle.rs +67 -0
- package/crates/naome-core/src/decision/json.rs +36 -0
- package/crates/naome-core/src/decision/states.rs +165 -0
- package/crates/naome-core/src/decision.rs +131 -353
- package/crates/naome-core/src/harness_health/integrity.rs +96 -0
- package/crates/naome-core/src/harness_health.rs +14 -126
- package/crates/naome-core/src/install_plan.rs +5 -0
- package/crates/naome-core/src/intent/classifier.rs +171 -0
- package/crates/naome-core/src/intent/envelope.rs +108 -0
- package/crates/naome-core/src/intent/legacy.rs +138 -0
- package/crates/naome-core/src/intent/legacy_response.rs +76 -0
- package/crates/naome-core/src/intent/model.rs +71 -0
- package/crates/naome-core/src/intent/patterns.rs +170 -0
- package/crates/naome-core/src/intent/resolver.rs +162 -0
- package/crates/naome-core/src/intent/resolver_active.rs +17 -0
- package/crates/naome-core/src/intent/resolver_baseline.rs +55 -0
- package/crates/naome-core/src/intent/resolver_catalog.rs +167 -0
- package/crates/naome-core/src/intent/resolver_policy.rs +72 -0
- package/crates/naome-core/src/intent/resolver_shared.rs +55 -0
- package/crates/naome-core/src/intent/risk.rs +40 -0
- package/crates/naome-core/src/intent/segment.rs +170 -0
- package/crates/naome-core/src/intent.rs +64 -879
- package/crates/naome-core/src/journal.rs +9 -20
- package/crates/naome-core/src/lib.rs +15 -0
- package/crates/naome-core/src/paths.rs +3 -1
- package/crates/naome-core/src/quality/adapter_support.rs +89 -0
- package/crates/naome-core/src/quality/adapters.rs +131 -0
- package/crates/naome-core/src/quality/baseline.rs +75 -0
- package/crates/naome-core/src/quality/checks/duplicate_blocks.rs +175 -0
- package/crates/naome-core/src/quality/checks/near_duplicates.rs +130 -0
- package/crates/naome-core/src/quality/checks.rs +228 -0
- package/crates/naome-core/src/quality/cleanup.rs +84 -0
- package/crates/naome-core/src/quality/config.rs +102 -0
- package/crates/naome-core/src/quality/config_support.rs +24 -0
- package/crates/naome-core/src/quality/mod.rs +108 -0
- package/crates/naome-core/src/quality/scanner/repo_paths.rs +103 -0
- package/crates/naome-core/src/quality/scanner.rs +379 -0
- package/crates/naome-core/src/quality/structure/adapters.rs +84 -0
- package/crates/naome-core/src/quality/structure/checks/basic.rs +153 -0
- package/crates/naome-core/src/quality/structure/checks/directory.rs +144 -0
- package/crates/naome-core/src/quality/structure/checks/pairing.rs +63 -0
- package/crates/naome-core/src/quality/structure/checks.rs +124 -0
- package/crates/naome-core/src/quality/structure/classify/roles.rs +188 -0
- package/crates/naome-core/src/quality/structure/classify.rs +94 -0
- package/crates/naome-core/src/quality/structure/config.rs +89 -0
- package/crates/naome-core/src/quality/structure/defaults.rs +107 -0
- package/crates/naome-core/src/quality/structure/mod.rs +77 -0
- package/crates/naome-core/src/quality/structure/model.rs +124 -0
- package/crates/naome-core/src/quality/types.rs +292 -0
- package/crates/naome-core/src/route/builtin_checks.rs +155 -0
- package/crates/naome-core/src/route/builtin_context.rs +73 -0
- package/crates/naome-core/src/route/builtin_integrity.rs +49 -0
- package/crates/naome-core/src/route/builtin_require.rs +40 -0
- package/crates/naome-core/src/route/context.rs +180 -0
- package/crates/naome-core/src/route/execution.rs +96 -0
- package/crates/naome-core/src/route/execution_baselines.rs +146 -0
- package/crates/naome-core/src/route/execution_support.rs +57 -0
- package/crates/naome-core/src/route/execution_tasks.rs +71 -0
- package/crates/naome-core/src/route/git_ops.rs +72 -0
- package/crates/naome-core/src/route/quality_gate.rs +73 -0
- package/crates/naome-core/src/route/quality_gate_config.rs +126 -0
- package/crates/naome-core/src/route/quality_gate_snapshot.rs +69 -0
- package/crates/naome-core/src/route/worktree.rs +75 -0
- package/crates/naome-core/src/route/worktree_files.rs +32 -0
- package/crates/naome-core/src/route/worktree_plan.rs +131 -0
- package/crates/naome-core/src/route.rs +44 -1155
- package/crates/naome-core/src/task_state/admission.rs +63 -0
- package/crates/naome-core/src/task_state/admission_proof.rs +72 -0
- package/crates/naome-core/src/task_state/api.rs +130 -0
- package/crates/naome-core/src/task_state/commit_gate.rs +138 -0
- package/crates/naome-core/src/task_state/compact_proof.rs +160 -0
- package/crates/naome-core/src/task_state/completed_refresh.rs +89 -0
- package/crates/naome-core/src/task_state/completion.rs +72 -0
- package/crates/naome-core/src/task_state/deleted_paths.rs +47 -0
- package/crates/naome-core/src/task_state/diff.rs +95 -0
- package/crates/naome-core/src/task_state/evidence.rs +154 -0
- package/crates/naome-core/src/task_state/git_io.rs +86 -0
- package/crates/naome-core/src/task_state/git_parse.rs +86 -0
- package/crates/naome-core/src/task_state/git_refs.rs +37 -0
- package/crates/naome-core/src/task_state/human_review_state.rs +31 -0
- package/crates/naome-core/src/task_state/mod.rs +38 -0
- package/crates/naome-core/src/task_state/process_guard.rs +40 -0
- package/crates/naome-core/src/task_state/progress.rs +123 -0
- package/crates/naome-core/src/task_state/proof.rs +139 -0
- package/crates/naome-core/src/task_state/proof_entry.rs +66 -0
- package/crates/naome-core/src/task_state/proof_model.rs +70 -0
- package/crates/naome-core/src/task_state/proof_sources.rs +76 -0
- package/crates/naome-core/src/task_state/push_gate.rs +49 -0
- package/crates/naome-core/src/task_state/reconcile.rs +7 -0
- package/crates/naome-core/src/task_state/repair.rs +168 -0
- package/crates/naome-core/src/task_state/shape.rs +117 -0
- package/crates/naome-core/src/task_state/task_diff_api.rs +170 -0
- package/crates/naome-core/src/task_state/task_records.rs +131 -0
- package/crates/naome-core/src/task_state/task_references.rs +126 -0
- package/crates/naome-core/src/task_state/types.rs +87 -0
- package/crates/naome-core/src/task_state/util.rs +137 -0
- package/crates/naome-core/src/verification/render.rs +122 -0
- package/crates/naome-core/src/verification.rs +177 -58
- package/crates/naome-core/src/verification_contract.rs +49 -21
- package/crates/naome-core/src/workflow/integrity.rs +123 -0
- package/crates/naome-core/src/workflow/integrity_normalize.rs +7 -0
- package/crates/naome-core/src/workflow/integrity_support.rs +110 -0
- package/crates/naome-core/src/workflow/mod.rs +18 -0
- package/crates/naome-core/src/workflow/mutation.rs +68 -0
- package/crates/naome-core/src/workflow/output.rs +111 -0
- package/crates/naome-core/src/workflow/phase_inference.rs +73 -0
- package/crates/naome-core/src/workflow/phases.rs +169 -0
- package/crates/naome-core/src/workflow/policy.rs +156 -0
- package/crates/naome-core/src/workflow/processes.rs +91 -0
- package/crates/naome-core/src/workflow/types.rs +42 -0
- package/crates/naome-core/tests/decision.rs +24 -118
- package/crates/naome-core/tests/harness_health.rs +5 -0
- package/crates/naome-core/tests/intent.rs +97 -792
- package/crates/naome-core/tests/intent_support/mod.rs +133 -0
- package/crates/naome-core/tests/intent_v2.rs +90 -0
- package/crates/naome-core/tests/quality.rs +319 -0
- package/crates/naome-core/tests/quality_structure.rs +116 -0
- package/crates/naome-core/tests/quality_structure_adapters.rs +98 -0
- package/crates/naome-core/tests/quality_structure_policy.rs +125 -0
- package/crates/naome-core/tests/quality_structure_support/mod.rs +249 -0
- package/crates/naome-core/tests/repo_support/mod.rs +16 -0
- package/crates/naome-core/tests/repo_support/repo.rs +113 -0
- package/crates/naome-core/tests/repo_support/repo_factories.rs +99 -0
- package/crates/naome-core/tests/repo_support/repo_helpers.rs +123 -0
- package/crates/naome-core/tests/repo_support/routes.rs +81 -0
- package/crates/naome-core/tests/repo_support/verification.rs +168 -0
- package/crates/naome-core/tests/repo_support/verification_values.rs +135 -0
- package/crates/naome-core/tests/route.rs +1 -1476
- package/crates/naome-core/tests/route_baseline.rs +86 -0
- package/crates/naome-core/tests/route_completion.rs +141 -0
- package/crates/naome-core/tests/route_harness_refresh.rs +135 -0
- package/crates/naome-core/tests/route_user_diff.rs +198 -0
- package/crates/naome-core/tests/route_worktree.rs +54 -0
- package/crates/naome-core/tests/task_state.rs +60 -429
- package/crates/naome-core/tests/task_state_compact.rs +110 -0
- package/crates/naome-core/tests/task_state_compact_support/mod.rs +5 -0
- package/crates/naome-core/tests/task_state_compact_support/repo.rs +130 -0
- package/crates/naome-core/tests/task_state_compact_support/states.rs +151 -0
- package/crates/naome-core/tests/task_state_support/mod.rs +163 -0
- package/crates/naome-core/tests/task_state_support/states.rs +84 -0
- package/crates/naome-core/tests/verification.rs +4 -45
- package/crates/naome-core/tests/verification_contract.rs +22 -78
- package/crates/naome-core/tests/workflow_integrity.rs +85 -0
- package/crates/naome-core/tests/workflow_policy.rs +139 -0
- package/crates/naome-core/tests/workflow_support/mod.rs +194 -0
- package/installer/agents.js +90 -0
- package/installer/context.js +67 -0
- package/installer/filesystem.js +166 -0
- package/installer/flows.js +84 -0
- package/installer/git-boundary.js +170 -0
- package/installer/git-hook-content.js +36 -0
- package/installer/git-hooks.js +134 -0
- package/installer/git-local.js +2 -0
- package/installer/git-shared.js +35 -0
- package/installer/harness-file-ops.js +140 -0
- package/installer/harness-files.js +56 -0
- package/installer/harness-verification.js +123 -0
- package/installer/install-plan.js +66 -0
- package/installer/main.js +25 -0
- package/installer/manifest-state.js +167 -0
- package/installer/native-build.js +24 -0
- package/installer/native-format.js +6 -0
- package/installer/native.js +162 -0
- package/installer/output.js +131 -0
- package/installer/version.js +32 -0
- package/native/darwin-arm64/naome +0 -0
- package/native/linux-x64/naome +0 -0
- package/package.json +3 -2
- package/templates/naome-root/.naome/bin/check-harness-health.js +66 -85
- package/templates/naome-root/.naome/bin/check-task-state.js +9 -10
- package/templates/naome-root/.naome/bin/naome.js +51 -76
- package/templates/naome-root/.naome/manifest.json +22 -18
- package/templates/naome-root/.naome/repository-quality-baseline.json +5 -0
- package/templates/naome-root/.naome/repository-quality.json +24 -0
- package/templates/naome-root/.naome/repository-structure.json +90 -0
- package/templates/naome-root/.naome/task-contract.schema.json +93 -11
- package/templates/naome-root/.naome/upgrade-state.json +1 -1
- package/templates/naome-root/.naome/verification.json +38 -0
- package/templates/naome-root/AGENTS.md +3 -0
- package/templates/naome-root/docs/naome/agent-workflow.md +25 -12
- package/templates/naome-root/docs/naome/execution.md +25 -21
- package/templates/naome-root/docs/naome/index.md +5 -3
- package/templates/naome-root/docs/naome/repository-quality.md +46 -0
- package/templates/naome-root/docs/naome/repository-structure.md +51 -0
- package/templates/naome-root/docs/naome/testing.md +13 -0
- package/crates/naome-core/src/task_state.rs +0 -2210
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
use super::model::{RepositoryStructureConfig, StructureLimits};
|
|
2
|
+
|
|
3
|
+
pub fn default_structure_config() -> RepositoryStructureConfig {
|
|
4
|
+
RepositoryStructureConfig {
|
|
5
|
+
schema: "naome.repository-structure.v1".to_string(),
|
|
6
|
+
version: 1,
|
|
7
|
+
status: "ready".to_string(),
|
|
8
|
+
enabled_adapters: Vec::new(),
|
|
9
|
+
source_roots: string_list(DEFAULT_SOURCE_ROOTS),
|
|
10
|
+
test_roots: string_list(DEFAULT_TEST_ROOTS),
|
|
11
|
+
docs_roots: string_list(DEFAULT_DOCS_ROOTS),
|
|
12
|
+
generated_roots: string_list(DEFAULT_GENERATED_ROOTS),
|
|
13
|
+
artifact_roots: string_list(DEFAULT_ARTIFACT_ROOTS),
|
|
14
|
+
module_roots: string_list(DEFAULT_MODULE_ROOTS),
|
|
15
|
+
allowed_root_files: string_list(DEFAULT_ALLOWED_ROOT_FILES),
|
|
16
|
+
directory_role_rules: Vec::new(),
|
|
17
|
+
layer_rules: Vec::new(),
|
|
18
|
+
ignored_paths: string_list(DEFAULT_IGNORED_PATHS),
|
|
19
|
+
disabled_checks: Vec::new(),
|
|
20
|
+
changed_code_policy: default_changed_policy(),
|
|
21
|
+
debt_policy: default_debt_policy(),
|
|
22
|
+
limits: StructureLimits::default(),
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
pub fn default_changed_policy() -> String {
|
|
27
|
+
"block".to_string()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
pub fn default_debt_policy() -> String {
|
|
31
|
+
"report".to_string()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const DEFAULT_SOURCE_ROOTS: &[&str] = &[
|
|
35
|
+
"src/**",
|
|
36
|
+
"app/**",
|
|
37
|
+
"apps/*/src/**",
|
|
38
|
+
"packages/*/src/**",
|
|
39
|
+
"crates/*/src/**",
|
|
40
|
+
"**/src/**",
|
|
41
|
+
"lib/**",
|
|
42
|
+
];
|
|
43
|
+
const DEFAULT_TEST_ROOTS: &[&str] = &[
|
|
44
|
+
"test/**",
|
|
45
|
+
"tests/**",
|
|
46
|
+
"__tests__/**",
|
|
47
|
+
"packages/*/test/**",
|
|
48
|
+
"packages/*/tests/**",
|
|
49
|
+
"crates/*/tests/**",
|
|
50
|
+
"**/tests/**",
|
|
51
|
+
"scripts/*.test.js",
|
|
52
|
+
];
|
|
53
|
+
const DEFAULT_DOCS_ROOTS: &[&str] = &["docs/**", "doc/**"];
|
|
54
|
+
const DEFAULT_GENERATED_ROOTS: &[&str] = &[
|
|
55
|
+
"**/generated/**",
|
|
56
|
+
"**/__generated__/**",
|
|
57
|
+
"**/codegen/**",
|
|
58
|
+
"**/*.generated.*",
|
|
59
|
+
];
|
|
60
|
+
const DEFAULT_ARTIFACT_ROOTS: &[&str] = &[
|
|
61
|
+
"dist/**",
|
|
62
|
+
"build/**",
|
|
63
|
+
"coverage/**",
|
|
64
|
+
".next/**",
|
|
65
|
+
"target/**",
|
|
66
|
+
"**/dist/**",
|
|
67
|
+
"**/build/**",
|
|
68
|
+
];
|
|
69
|
+
const DEFAULT_MODULE_ROOTS: &[&str] = &[
|
|
70
|
+
"src/**",
|
|
71
|
+
"app/**",
|
|
72
|
+
"packages/*/src/**",
|
|
73
|
+
"crates/*/src/**",
|
|
74
|
+
"**/src/**",
|
|
75
|
+
];
|
|
76
|
+
const DEFAULT_ALLOWED_ROOT_FILES: &[&str] = &[
|
|
77
|
+
"README.md",
|
|
78
|
+
"LICENSE",
|
|
79
|
+
"NOTICE",
|
|
80
|
+
"CHANGELOG.md",
|
|
81
|
+
"CONTRIBUTING.md",
|
|
82
|
+
"SECURITY.md",
|
|
83
|
+
"AGENTS.md",
|
|
84
|
+
"package.json",
|
|
85
|
+
"Cargo.toml",
|
|
86
|
+
"pyproject.toml",
|
|
87
|
+
"go.mod",
|
|
88
|
+
"go.sum",
|
|
89
|
+
"Makefile",
|
|
90
|
+
".gitignore",
|
|
91
|
+
".naomeignore",
|
|
92
|
+
];
|
|
93
|
+
const DEFAULT_IGNORED_PATHS: &[&str] = &[
|
|
94
|
+
".git/**",
|
|
95
|
+
"node_modules/**",
|
|
96
|
+
"vendor/**",
|
|
97
|
+
"target/**",
|
|
98
|
+
"**/target/**",
|
|
99
|
+
"dist/**",
|
|
100
|
+
"build/**",
|
|
101
|
+
"coverage/**",
|
|
102
|
+
".next/**",
|
|
103
|
+
];
|
|
104
|
+
|
|
105
|
+
fn string_list(values: &[&str]) -> Vec<String> {
|
|
106
|
+
values.iter().map(|value| (*value).to_string()).collect()
|
|
107
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
mod adapters;
|
|
2
|
+
mod checks;
|
|
3
|
+
mod classify;
|
|
4
|
+
mod config;
|
|
5
|
+
mod defaults;
|
|
6
|
+
mod model;
|
|
7
|
+
|
|
8
|
+
use std::collections::HashSet;
|
|
9
|
+
use std::path::Path;
|
|
10
|
+
|
|
11
|
+
use crate::models::NaomeError;
|
|
12
|
+
|
|
13
|
+
use super::scanner::QualityContext;
|
|
14
|
+
use super::types::{QualityMode, QualityViolation};
|
|
15
|
+
use checks::run_structure_checks;
|
|
16
|
+
use classify::build_structure_model;
|
|
17
|
+
use config::read_structure_config;
|
|
18
|
+
pub use config::{structure_config_relative_path, write_default_structure_config_if_missing};
|
|
19
|
+
pub use model::{RepositoryStructureConfig, StructurePathExplanation};
|
|
20
|
+
|
|
21
|
+
pub fn run_repository_structure_checks(
|
|
22
|
+
root: &Path,
|
|
23
|
+
context: &QualityContext,
|
|
24
|
+
baseline_fingerprints: &HashSet<String>,
|
|
25
|
+
) -> Result<Vec<QualityViolation>, NaomeError> {
|
|
26
|
+
let model = structure_model(root, context, baseline_fingerprints)?;
|
|
27
|
+
let mut violations = run_structure_checks(&model, context.mode);
|
|
28
|
+
violations.retain(|violation| {
|
|
29
|
+
violation.check_id != "test-source-pairing"
|
|
30
|
+
|| context
|
|
31
|
+
.files
|
|
32
|
+
.iter()
|
|
33
|
+
.find(|file| file.path == violation.path)
|
|
34
|
+
.is_some_and(|file| !file.symbols.is_empty())
|
|
35
|
+
});
|
|
36
|
+
if context.mode == QualityMode::Report {
|
|
37
|
+
for violation in &mut violations {
|
|
38
|
+
violation.baseline = baseline_fingerprints.contains(&violation.fingerprint);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
Ok(violations)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
pub fn explain_repository_structure(
|
|
45
|
+
root: &Path,
|
|
46
|
+
path: impl AsRef<str>,
|
|
47
|
+
) -> Result<StructurePathExplanation, NaomeError> {
|
|
48
|
+
let repo_paths = super::scanner::collect_repo_paths(root)?;
|
|
49
|
+
let changed_paths = crate::git::changed_paths(root)?;
|
|
50
|
+
let config = read_structure_config(root, &repo_paths)?;
|
|
51
|
+
let model = build_structure_model(config, &repo_paths, &changed_paths, &HashSet::new());
|
|
52
|
+
let normalized = path.as_ref().replace('\\', "/");
|
|
53
|
+
model
|
|
54
|
+
.paths
|
|
55
|
+
.into_iter()
|
|
56
|
+
.find(|entry| entry.explanation.path == normalized)
|
|
57
|
+
.map(|entry| entry.explanation)
|
|
58
|
+
.ok_or_else(|| {
|
|
59
|
+
NaomeError::new(format!(
|
|
60
|
+
"{normalized} is not visible to structure analysis."
|
|
61
|
+
))
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
fn structure_model(
|
|
66
|
+
root: &Path,
|
|
67
|
+
context: &QualityContext,
|
|
68
|
+
baseline_fingerprints: &HashSet<String>,
|
|
69
|
+
) -> Result<model::RepositoryStructureModel, NaomeError> {
|
|
70
|
+
let config = read_structure_config(root, &context.repo_paths)?;
|
|
71
|
+
Ok(build_structure_model(
|
|
72
|
+
config,
|
|
73
|
+
&context.repo_paths,
|
|
74
|
+
&context.changed_paths,
|
|
75
|
+
baseline_fingerprints,
|
|
76
|
+
))
|
|
77
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
use std::collections::BTreeSet;
|
|
2
|
+
|
|
3
|
+
use serde::{Deserialize, Serialize};
|
|
4
|
+
|
|
5
|
+
use super::defaults::{default_changed_policy, default_debt_policy, default_structure_config};
|
|
6
|
+
|
|
7
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
8
|
+
#[serde(rename_all = "camelCase")]
|
|
9
|
+
pub struct StructureLimits {
|
|
10
|
+
pub max_directory_files: usize,
|
|
11
|
+
pub max_path_depth: usize,
|
|
12
|
+
pub max_directory_roles: usize,
|
|
13
|
+
pub max_dumping_ground_files: usize,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
impl Default for StructureLimits {
|
|
17
|
+
fn default() -> Self {
|
|
18
|
+
Self {
|
|
19
|
+
max_directory_files: 40,
|
|
20
|
+
max_path_depth: 10,
|
|
21
|
+
max_directory_roles: 2,
|
|
22
|
+
max_dumping_ground_files: 12,
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
28
|
+
#[serde(rename_all = "camelCase")]
|
|
29
|
+
pub struct DirectoryRoleRule {
|
|
30
|
+
pub id: String,
|
|
31
|
+
pub paths: Vec<String>,
|
|
32
|
+
#[serde(default)]
|
|
33
|
+
pub allowed_roles: Vec<String>,
|
|
34
|
+
#[serde(default)]
|
|
35
|
+
pub max_roles: Option<usize>,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
39
|
+
#[serde(rename_all = "camelCase")]
|
|
40
|
+
pub struct LayerRule {
|
|
41
|
+
pub id: String,
|
|
42
|
+
pub paths: Vec<String>,
|
|
43
|
+
pub layer: String,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
47
|
+
#[serde(rename_all = "camelCase")]
|
|
48
|
+
pub struct RepositoryStructureConfig {
|
|
49
|
+
pub schema: String,
|
|
50
|
+
pub version: u32,
|
|
51
|
+
pub status: String,
|
|
52
|
+
#[serde(default)]
|
|
53
|
+
pub enabled_adapters: Vec<String>,
|
|
54
|
+
#[serde(default)]
|
|
55
|
+
pub source_roots: Vec<String>,
|
|
56
|
+
#[serde(default)]
|
|
57
|
+
pub test_roots: Vec<String>,
|
|
58
|
+
#[serde(default)]
|
|
59
|
+
pub docs_roots: Vec<String>,
|
|
60
|
+
#[serde(default)]
|
|
61
|
+
pub generated_roots: Vec<String>,
|
|
62
|
+
#[serde(default)]
|
|
63
|
+
pub artifact_roots: Vec<String>,
|
|
64
|
+
#[serde(default)]
|
|
65
|
+
pub module_roots: Vec<String>,
|
|
66
|
+
#[serde(default)]
|
|
67
|
+
pub allowed_root_files: Vec<String>,
|
|
68
|
+
#[serde(default)]
|
|
69
|
+
pub directory_role_rules: Vec<DirectoryRoleRule>,
|
|
70
|
+
#[serde(default)]
|
|
71
|
+
pub layer_rules: Vec<LayerRule>,
|
|
72
|
+
#[serde(default)]
|
|
73
|
+
pub ignored_paths: Vec<String>,
|
|
74
|
+
#[serde(default)]
|
|
75
|
+
pub disabled_checks: Vec<String>,
|
|
76
|
+
#[serde(default = "default_changed_policy")]
|
|
77
|
+
pub changed_code_policy: String,
|
|
78
|
+
#[serde(default = "default_debt_policy")]
|
|
79
|
+
pub debt_policy: String,
|
|
80
|
+
#[serde(default)]
|
|
81
|
+
pub limits: StructureLimits,
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
impl Default for RepositoryStructureConfig {
|
|
85
|
+
fn default() -> Self {
|
|
86
|
+
default_structure_config()
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
#[derive(Debug, Clone, Serialize)]
|
|
91
|
+
#[serde(rename_all = "camelCase")]
|
|
92
|
+
pub struct StructurePathExplanation {
|
|
93
|
+
pub path: String,
|
|
94
|
+
pub role: String,
|
|
95
|
+
pub module: Option<String>,
|
|
96
|
+
pub layer: String,
|
|
97
|
+
pub language: Option<String>,
|
|
98
|
+
pub generated: bool,
|
|
99
|
+
pub debt: bool,
|
|
100
|
+
pub changed: bool,
|
|
101
|
+
pub directory: String,
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
#[derive(Debug, Clone)]
|
|
105
|
+
pub struct StructurePath {
|
|
106
|
+
pub explanation: StructurePathExplanation,
|
|
107
|
+
pub segments: Vec<String>,
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
#[derive(Debug, Clone)]
|
|
111
|
+
pub struct StructureDirectory {
|
|
112
|
+
pub path: String,
|
|
113
|
+
pub roles: BTreeSet<String>,
|
|
114
|
+
pub modules: BTreeSet<String>,
|
|
115
|
+
pub file_count: usize,
|
|
116
|
+
pub direct_changed_paths: Vec<String>,
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
#[derive(Debug, Clone)]
|
|
120
|
+
pub struct RepositoryStructureModel {
|
|
121
|
+
pub config: RepositoryStructureConfig,
|
|
122
|
+
pub paths: Vec<StructurePath>,
|
|
123
|
+
pub directories: Vec<StructureDirectory>,
|
|
124
|
+
}
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
use serde::{Deserialize, Serialize};
|
|
2
|
+
|
|
3
|
+
use crate::paths;
|
|
4
|
+
|
|
5
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
6
|
+
pub enum QualityMode {
|
|
7
|
+
Changed,
|
|
8
|
+
Report,
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
impl QualityMode {
|
|
12
|
+
pub fn as_str(self) -> &'static str {
|
|
13
|
+
match self {
|
|
14
|
+
Self::Changed => "changed",
|
|
15
|
+
Self::Report => "report",
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
21
|
+
#[serde(rename_all = "camelCase")]
|
|
22
|
+
pub struct QualityLimits {
|
|
23
|
+
pub max_file_lines: usize,
|
|
24
|
+
pub max_new_file_lines: usize,
|
|
25
|
+
pub max_diff_added_lines: usize,
|
|
26
|
+
pub max_function_lines: usize,
|
|
27
|
+
pub max_top_level_symbols: usize,
|
|
28
|
+
pub duplicate_block_lines: usize,
|
|
29
|
+
pub near_duplicate_similarity: f64,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
impl Default for QualityLimits {
|
|
33
|
+
fn default() -> Self {
|
|
34
|
+
Self {
|
|
35
|
+
max_file_lines: 450,
|
|
36
|
+
max_new_file_lines: 300,
|
|
37
|
+
max_diff_added_lines: 180,
|
|
38
|
+
max_function_lines: 100,
|
|
39
|
+
max_top_level_symbols: 30,
|
|
40
|
+
duplicate_block_lines: 10,
|
|
41
|
+
near_duplicate_similarity: 0.9,
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
impl QualityLimits {
|
|
47
|
+
pub fn with_overrides(&self, overrides: &QualityLimitOverrides) -> Self {
|
|
48
|
+
Self {
|
|
49
|
+
max_file_lines: overrides.max_file_lines.unwrap_or(self.max_file_lines),
|
|
50
|
+
max_new_file_lines: overrides
|
|
51
|
+
.max_new_file_lines
|
|
52
|
+
.unwrap_or(self.max_new_file_lines),
|
|
53
|
+
max_diff_added_lines: overrides
|
|
54
|
+
.max_diff_added_lines
|
|
55
|
+
.unwrap_or(self.max_diff_added_lines),
|
|
56
|
+
max_function_lines: overrides
|
|
57
|
+
.max_function_lines
|
|
58
|
+
.unwrap_or(self.max_function_lines),
|
|
59
|
+
max_top_level_symbols: overrides
|
|
60
|
+
.max_top_level_symbols
|
|
61
|
+
.unwrap_or(self.max_top_level_symbols),
|
|
62
|
+
duplicate_block_lines: overrides
|
|
63
|
+
.duplicate_block_lines
|
|
64
|
+
.unwrap_or(self.duplicate_block_lines),
|
|
65
|
+
near_duplicate_similarity: overrides
|
|
66
|
+
.near_duplicate_similarity
|
|
67
|
+
.unwrap_or(self.near_duplicate_similarity),
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
|
73
|
+
#[serde(rename_all = "camelCase")]
|
|
74
|
+
pub struct QualityLimitOverrides {
|
|
75
|
+
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
76
|
+
pub max_file_lines: Option<usize>,
|
|
77
|
+
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
78
|
+
pub max_new_file_lines: Option<usize>,
|
|
79
|
+
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
80
|
+
pub max_diff_added_lines: Option<usize>,
|
|
81
|
+
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
82
|
+
pub max_function_lines: Option<usize>,
|
|
83
|
+
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
84
|
+
pub max_top_level_symbols: Option<usize>,
|
|
85
|
+
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
86
|
+
pub duplicate_block_lines: Option<usize>,
|
|
87
|
+
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
88
|
+
pub near_duplicate_similarity: Option<f64>,
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
92
|
+
#[serde(rename_all = "camelCase")]
|
|
93
|
+
pub struct QualityPathRule {
|
|
94
|
+
pub id: String,
|
|
95
|
+
pub paths: Vec<String>,
|
|
96
|
+
#[serde(default, skip_serializing_if = "QualityLimitOverrides::is_empty")]
|
|
97
|
+
pub limits: QualityLimitOverrides,
|
|
98
|
+
#[serde(default)]
|
|
99
|
+
pub disabled_checks: Vec<String>,
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
impl QualityLimitOverrides {
|
|
103
|
+
pub fn is_empty(&self) -> bool {
|
|
104
|
+
self.max_file_lines.is_none()
|
|
105
|
+
&& self.max_new_file_lines.is_none()
|
|
106
|
+
&& self.max_diff_added_lines.is_none()
|
|
107
|
+
&& self.max_function_lines.is_none()
|
|
108
|
+
&& self.max_top_level_symbols.is_none()
|
|
109
|
+
&& self.duplicate_block_lines.is_none()
|
|
110
|
+
&& self.near_duplicate_similarity.is_none()
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
115
|
+
#[serde(rename_all = "camelCase")]
|
|
116
|
+
pub struct RepositoryQualityConfig {
|
|
117
|
+
pub schema: String,
|
|
118
|
+
pub version: u32,
|
|
119
|
+
pub status: String,
|
|
120
|
+
pub limits: QualityLimits,
|
|
121
|
+
#[serde(default)]
|
|
122
|
+
pub enabled_adapters: Vec<String>,
|
|
123
|
+
#[serde(default)]
|
|
124
|
+
pub disabled_checks: Vec<String>,
|
|
125
|
+
#[serde(default)]
|
|
126
|
+
pub ignored_paths: Vec<String>,
|
|
127
|
+
#[serde(default)]
|
|
128
|
+
pub generated_paths: Vec<String>,
|
|
129
|
+
#[serde(default)]
|
|
130
|
+
pub path_rules: Vec<QualityPathRule>,
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
impl Default for RepositoryQualityConfig {
|
|
134
|
+
fn default() -> Self {
|
|
135
|
+
Self {
|
|
136
|
+
schema: "naome.repository-quality.v1".to_string(),
|
|
137
|
+
version: 1,
|
|
138
|
+
status: "ready".to_string(),
|
|
139
|
+
limits: QualityLimits::default(),
|
|
140
|
+
enabled_adapters: Vec::new(),
|
|
141
|
+
disabled_checks: Vec::new(),
|
|
142
|
+
ignored_paths: default_ignored_paths(),
|
|
143
|
+
generated_paths: default_generated_paths(),
|
|
144
|
+
path_rules: Vec::new(),
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
impl RepositoryQualityConfig {
|
|
150
|
+
pub fn limits_for_path(&self, path: &str) -> QualityLimits {
|
|
151
|
+
self.path_rules
|
|
152
|
+
.iter()
|
|
153
|
+
.filter(|rule| paths::matches_any(path, &rule.paths))
|
|
154
|
+
.fold(self.limits.clone(), |limits, rule| {
|
|
155
|
+
limits.with_overrides(&rule.limits)
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
pub fn check_enabled_for_path(&self, check_id: &str, path: &str) -> bool {
|
|
160
|
+
!self
|
|
161
|
+
.disabled_checks
|
|
162
|
+
.iter()
|
|
163
|
+
.any(|disabled| disabled == check_id)
|
|
164
|
+
&& !self.path_rules.iter().any(|rule| {
|
|
165
|
+
paths::matches_any(path, &rule.paths)
|
|
166
|
+
&& rule
|
|
167
|
+
.disabled_checks
|
|
168
|
+
.iter()
|
|
169
|
+
.any(|disabled| disabled == check_id)
|
|
170
|
+
})
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
#[derive(Debug, Clone, Serialize)]
|
|
175
|
+
#[serde(rename_all = "camelCase")]
|
|
176
|
+
pub struct QualityReport {
|
|
177
|
+
pub schema: String,
|
|
178
|
+
pub mode: String,
|
|
179
|
+
pub ok: bool,
|
|
180
|
+
pub changed_paths: Vec<String>,
|
|
181
|
+
pub scanned_paths: Vec<String>,
|
|
182
|
+
pub summary: QualitySummary,
|
|
183
|
+
pub violations: Vec<QualityViolation>,
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
#[derive(Debug, Clone, Serialize)]
|
|
187
|
+
#[serde(rename_all = "camelCase")]
|
|
188
|
+
pub struct QualitySummary {
|
|
189
|
+
pub scanned_files: usize,
|
|
190
|
+
pub violation_count: usize,
|
|
191
|
+
pub baseline_violation_count: usize,
|
|
192
|
+
pub blocking_violation_count: usize,
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
#[derive(Debug, Clone, Serialize)]
|
|
196
|
+
#[serde(rename_all = "camelCase")]
|
|
197
|
+
pub struct QualityViolation {
|
|
198
|
+
pub check_id: String,
|
|
199
|
+
pub severity: String,
|
|
200
|
+
pub path: String,
|
|
201
|
+
pub line: Option<usize>,
|
|
202
|
+
pub message: String,
|
|
203
|
+
pub value: Option<f64>,
|
|
204
|
+
pub limit: Option<f64>,
|
|
205
|
+
pub fingerprint: String,
|
|
206
|
+
pub related_paths: Vec<String>,
|
|
207
|
+
pub baseline: bool,
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
#[derive(Debug, Clone, Serialize)]
|
|
211
|
+
#[serde(rename_all = "camelCase")]
|
|
212
|
+
pub struct QualityInitResult {
|
|
213
|
+
pub schema: String,
|
|
214
|
+
pub config_written: bool,
|
|
215
|
+
pub structure_config_written: bool,
|
|
216
|
+
pub baseline_written: bool,
|
|
217
|
+
pub baseline_violations: usize,
|
|
218
|
+
pub config_path: String,
|
|
219
|
+
pub structure_config_path: String,
|
|
220
|
+
pub baseline_path: String,
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
#[derive(Debug, Clone, Serialize)]
|
|
224
|
+
#[serde(rename_all = "camelCase")]
|
|
225
|
+
pub struct QualityCleanupPlan {
|
|
226
|
+
pub schema: String,
|
|
227
|
+
pub tasks: Vec<QualityCleanupTask>,
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
#[derive(Debug, Clone, Serialize)]
|
|
231
|
+
#[serde(rename_all = "camelCase")]
|
|
232
|
+
pub struct QualityCleanupTask {
|
|
233
|
+
pub path: String,
|
|
234
|
+
pub violation_count: usize,
|
|
235
|
+
pub check_ids: Vec<String>,
|
|
236
|
+
pub summary: String,
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
#[derive(Debug, Clone, Serialize)]
|
|
240
|
+
#[serde(rename_all = "camelCase")]
|
|
241
|
+
pub struct QualityCleanupRoute {
|
|
242
|
+
pub schema: String,
|
|
243
|
+
pub path: String,
|
|
244
|
+
pub violations: Vec<QualityViolation>,
|
|
245
|
+
pub related_paths: Vec<String>,
|
|
246
|
+
pub agent_instructions: String,
|
|
247
|
+
pub required_checks: Vec<String>,
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
pub fn default_ignored_paths() -> Vec<String> {
|
|
251
|
+
listed_paths(DEFAULT_IGNORED_PATHS)
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
pub fn default_generated_paths() -> Vec<String> {
|
|
255
|
+
listed_paths(DEFAULT_GENERATED_PATHS)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const DEFAULT_IGNORED_PATHS: &str = r#"
|
|
259
|
+
.git/**
|
|
260
|
+
.naome/archive/**
|
|
261
|
+
.naome/task-state.json
|
|
262
|
+
.naome/task-journal.jsonl
|
|
263
|
+
.naome/repository-quality.json
|
|
264
|
+
.naome/repository-structure.json
|
|
265
|
+
.naome/repository-quality-baseline.json
|
|
266
|
+
node_modules/**
|
|
267
|
+
.npm/**
|
|
268
|
+
target/**
|
|
269
|
+
**/target/**
|
|
270
|
+
**/Cargo.lock
|
|
271
|
+
package-lock.json
|
|
272
|
+
pnpm-lock.yaml
|
|
273
|
+
yarn.lock
|
|
274
|
+
*.tgz
|
|
275
|
+
*.lock
|
|
276
|
+
"#;
|
|
277
|
+
|
|
278
|
+
const DEFAULT_GENERATED_PATHS: &str = r#"
|
|
279
|
+
**/*.min.js
|
|
280
|
+
**/*.map
|
|
281
|
+
**/dist/**
|
|
282
|
+
**/build/**
|
|
283
|
+
"#;
|
|
284
|
+
|
|
285
|
+
fn listed_paths(paths: &str) -> Vec<String> {
|
|
286
|
+
paths
|
|
287
|
+
.lines()
|
|
288
|
+
.map(str::trim)
|
|
289
|
+
.filter(|path| !path.is_empty())
|
|
290
|
+
.map(ToString::to_string)
|
|
291
|
+
.collect()
|
|
292
|
+
}
|