@lamentis/naome 1.2.1 → 1.3.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/README.md +117 -47
- package/bin/naome.js +65 -12
- package/crates/naome-cli/Cargo.toml +1 -1
- package/crates/naome-cli/src/context_commands.rs +47 -0
- package/crates/naome-cli/src/dispatcher.rs +12 -2
- package/crates/naome-cli/src/main.rs +78 -29
- package/crates/naome-cli/src/quality_commands.rs +238 -34
- package/crates/naome-cli/src/quality_output.rs +34 -0
- package/crates/naome-cli/src/quality_reconcile_command.rs +45 -0
- package/crates/naome-cli/src/repository_model_commands.rs +84 -0
- package/crates/naome-cli/src/task_commands.rs +62 -0
- package/crates/naome-cli/src/workflow_commands.rs +120 -3
- package/crates/naome-core/Cargo.toml +1 -1
- package/crates/naome-core/src/context/helpers.rs +75 -0
- package/crates/naome-core/src/context/select.rs +134 -0
- package/crates/naome-core/src/context/types.rs +43 -0
- package/crates/naome-core/src/context.rs +6 -0
- package/crates/naome-core/src/decision/states.rs +1 -1
- package/crates/naome-core/src/decision.rs +4 -1
- package/crates/naome-core/src/git.rs +4 -2
- package/crates/naome-core/src/install_plan.rs +20 -0
- package/crates/naome-core/src/journal.rs +2 -7
- package/crates/naome-core/src/lib.rs +35 -8
- package/crates/naome-core/src/quality/adapter_ios.rs +131 -0
- package/crates/naome-core/src/quality/adapter_support.rs +67 -0
- package/crates/naome-core/src/quality/adapters.rs +81 -18
- package/crates/naome-core/src/quality/baseline.rs +8 -0
- package/crates/naome-core/src/quality/cache.rs +151 -0
- package/crates/naome-core/src/quality/checks/duplicate_blocks.rs +19 -8
- package/crates/naome-core/src/quality/checks/near_duplicates.rs +4 -2
- package/crates/naome-core/src/quality/checks.rs +7 -8
- package/crates/naome-core/src/quality/cleanup.rs +36 -3
- package/crates/naome-core/src/quality/config.rs +21 -3
- package/crates/naome-core/src/quality/mod.rs +189 -10
- package/crates/naome-core/src/quality/reconcile.rs +138 -0
- package/crates/naome-core/src/quality/reconcile_anchors.rs +64 -0
- package/crates/naome-core/src/quality/scanner/analysis/normalize.rs +78 -0
- package/crates/naome-core/src/quality/scanner/analysis.rs +175 -0
- package/crates/naome-core/src/quality/scanner/repo_paths.rs +39 -3
- package/crates/naome-core/src/quality/scanner.rs +235 -217
- package/crates/naome-core/src/quality/semantic/checks.rs +151 -0
- package/crates/naome-core/src/quality/semantic/extract.rs +158 -0
- package/crates/naome-core/src/quality/semantic/model.rs +85 -0
- package/crates/naome-core/src/quality/semantic/route.rs +52 -0
- package/crates/naome-core/src/quality/semantic.rs +68 -0
- package/crates/naome-core/src/quality/structure/adapter_ios.rs +149 -0
- package/crates/naome-core/src/quality/structure/adapters.rs +60 -42
- package/crates/naome-core/src/quality/structure/checks/directory.rs +13 -21
- package/crates/naome-core/src/quality/structure/checks.rs +1 -1
- package/crates/naome-core/src/quality/structure/classify/roles.rs +51 -5
- package/crates/naome-core/src/quality/structure/classify.rs +52 -0
- package/crates/naome-core/src/quality/structure/config.rs +24 -3
- package/crates/naome-core/src/quality/structure/mod.rs +5 -2
- package/crates/naome-core/src/quality/structure/model.rs +8 -1
- package/crates/naome-core/src/quality/types.rs +59 -2
- package/crates/naome-core/src/repository_model/detect.rs +188 -0
- package/crates/naome-core/src/repository_model/explain.rs +121 -0
- package/crates/naome-core/src/repository_model/path_scan.rs +67 -0
- package/crates/naome-core/src/repository_model/path_support.rs +59 -0
- package/crates/naome-core/src/repository_model/types.rs +152 -0
- package/crates/naome-core/src/repository_model/world.rs +48 -0
- package/crates/naome-core/src/repository_model/world_adapters.rs +145 -0
- package/crates/naome-core/src/repository_model/world_path_facts.rs +55 -0
- package/crates/naome-core/src/repository_model/world_paths.rs +168 -0
- package/crates/naome-core/src/repository_model.rs +164 -0
- package/crates/naome-core/src/route/builtin_checks.rs +41 -16
- package/crates/naome-core/src/task_ledger/import.rs +142 -0
- package/crates/naome-core/src/task_ledger/model.rs +13 -0
- package/crates/naome-core/src/task_ledger/proof_record.rs +52 -0
- package/crates/naome-core/src/task_ledger/read.rs +118 -0
- package/crates/naome-core/src/task_ledger/render.rs +55 -0
- package/crates/naome-core/src/task_ledger/write.rs +38 -0
- package/crates/naome-core/src/task_ledger.rs +48 -0
- package/crates/naome-core/src/task_state/api.rs +4 -2
- package/crates/naome-core/src/task_state/completed_refresh.rs +5 -16
- package/crates/naome-core/src/task_state/diff.rs +2 -2
- package/crates/naome-core/src/task_state/evidence.rs +8 -3
- package/crates/naome-core/src/task_state/mod.rs +1 -1
- package/crates/naome-core/src/task_state/progress.rs +13 -0
- package/crates/naome-core/src/task_state/proof_model.rs +8 -8
- package/crates/naome-core/src/task_state/repair.rs +2 -2
- package/crates/naome-core/src/task_state/task_diff_api.rs +9 -18
- package/crates/naome-core/src/task_state/types.rs +24 -0
- package/crates/naome-core/src/verification.rs +29 -18
- package/crates/naome-core/src/workflow/agent/capability.rs +194 -0
- package/crates/naome-core/src/workflow/agent/context_delta.rs +42 -0
- package/crates/naome-core/src/workflow/agent/decision.rs +32 -0
- package/crates/naome-core/src/workflow/agent/execution.rs +80 -0
- package/crates/naome-core/src/workflow/agent/proof.rs +24 -0
- package/crates/naome-core/src/workflow/agent/support.rs +58 -0
- package/crates/naome-core/src/workflow/agent/watchdog.rs +47 -0
- package/crates/naome-core/src/workflow/agent.rs +34 -0
- package/crates/naome-core/src/workflow/agent_types.rs +105 -0
- package/crates/naome-core/src/workflow/doctor.rs +183 -0
- package/crates/naome-core/src/workflow/mod.rs +13 -0
- package/crates/naome-core/src/workflow/mutation.rs +1 -2
- package/crates/naome-core/src/workflow/output.rs +8 -2
- package/crates/naome-core/src/workflow/phase_inference.rs +1 -1
- package/crates/naome-core/tests/context.rs +99 -0
- package/crates/naome-core/tests/harness_health.rs +4 -0
- package/crates/naome-core/tests/install_plan.rs +14 -0
- package/crates/naome-core/tests/quality.rs +190 -5
- package/crates/naome-core/tests/quality_performance.rs +268 -0
- package/crates/naome-core/tests/quality_structure_adapters.rs +39 -0
- package/crates/naome-core/tests/quality_structure_policy.rs +19 -0
- package/crates/naome-core/tests/repo_support/mod.rs +5 -1
- package/crates/naome-core/tests/repo_support/verification_values.rs +55 -0
- package/crates/naome-core/tests/repository_model.rs +281 -0
- package/crates/naome-core/tests/route_user_diff.rs +59 -7
- package/crates/naome-core/tests/semantic_legacy.rs +174 -0
- package/crates/naome-core/tests/task_ledger.rs +328 -0
- package/crates/naome-core/tests/task_state.rs +28 -0
- package/crates/naome-core/tests/verification.rs +29 -36
- package/crates/naome-core/tests/workflow_agent.rs +233 -0
- package/crates/naome-core/tests/workflow_agent_support/mod.rs +159 -0
- package/crates/naome-core/tests/workflow_doctor.rs +45 -0
- package/crates/naome-core/tests/workflow_policy.rs +6 -1
- package/installer/codex-hooks.js +121 -0
- package/installer/context.js +10 -0
- package/installer/filesystem.js +4 -0
- package/installer/flows.js +8 -4
- package/installer/git-boundary.js +1 -0
- package/installer/harness-files.js +6 -0
- package/installer/install-plan.js +4 -0
- package/installer/main.js +1 -1
- package/installer/native.js +1 -1
- package/native/darwin-arm64/naome +0 -0
- package/native/linux-x64/naome +0 -0
- package/package.json +1 -1
- package/templates/naome-root/.codex/config.toml +2 -0
- package/templates/naome-root/.codex/hooks.json +70 -0
- package/templates/naome-root/.naome/bin/check-harness-health.js +8 -6
- package/templates/naome-root/.naome/bin/check-task-state.js +12 -7
- package/templates/naome-root/.naome/bin/codex-hook-io.js +122 -0
- package/templates/naome-root/.naome/bin/codex-hook-policy.js +180 -0
- package/templates/naome-root/.naome/bin/codex-hook-runtime.js +174 -0
- package/templates/naome-root/.naome/bin/codex-hook.js +6 -0
- package/templates/naome-root/.naome/bin/naome.js +45 -7
- package/templates/naome-root/.naome/manifest.json +12 -6
- package/templates/naome-root/.naome/repository-model.json +6 -0
- package/templates/naome-root/.naome/repository-quality.json +3 -1
- package/templates/naome-root/.naome/verification.json +15 -1
- package/templates/naome-root/.naomeignore +1 -0
- package/templates/naome-root/AGENTS.md +38 -83
- package/templates/naome-root/docs/naome/agent-workflow.md +66 -28
- package/templates/naome-root/docs/naome/codex-hooks.md +82 -0
- package/templates/naome-root/docs/naome/context-economy.md +73 -0
- package/templates/naome-root/docs/naome/first-run.md +25 -14
- package/templates/naome-root/docs/naome/index.md +18 -10
- package/templates/naome-root/docs/naome/repository-model.md +92 -0
- package/templates/naome-root/docs/naome/repository-quality.md +104 -5
- package/templates/naome-root/docs/naome/repository-structure.md +10 -3
- package/templates/naome-root/docs/naome/task-ledger.md +71 -0
- package/templates/naome-root/docs/naome/testing.md +16 -3
|
@@ -1,30 +1,41 @@
|
|
|
1
1
|
use std::path::Path;
|
|
2
2
|
|
|
3
3
|
use naome_core::{
|
|
4
|
-
check_repository_quality,
|
|
5
|
-
|
|
4
|
+
check_repository_quality, check_repository_quality_paths, check_semantic_legacy, check_semantic_legacy_paths,
|
|
5
|
+
clear_quality_cache, explain_repository_structure, init_repository_quality_with_mode,
|
|
6
|
+
plan_quality_cleanup, quality_cache_status, route_quality_cleanup, semantic_route_for_finding,
|
|
7
|
+
QualityInitMode, QualityMode,
|
|
6
8
|
};
|
|
7
9
|
|
|
8
10
|
use crate::cli_args::option_value;
|
|
11
|
+
use crate::quality_output::{is_structure_check, print_quality_violation, report_json};
|
|
12
|
+
use crate::quality_reconcile_command::run_quality_reconcile;
|
|
9
13
|
|
|
10
14
|
pub fn run_quality_command(root: &Path, args: &[String]) -> Result<(), Box<dyn std::error::Error>> {
|
|
11
15
|
let Some(subcommand) = args.get(1).map(String::as_str) else {
|
|
12
|
-
return Err("naome quality requires init, check, or
|
|
16
|
+
return Err("naome quality requires init, reconcile, check, report, or cache.".into());
|
|
13
17
|
};
|
|
14
18
|
let json = args.iter().any(|arg| arg == "--json");
|
|
15
19
|
|
|
16
20
|
match subcommand {
|
|
17
21
|
"init" => {
|
|
18
|
-
let result =
|
|
22
|
+
let result = init_repository_quality_with_mode(root, quality_init_mode(args)?)?;
|
|
19
23
|
if json {
|
|
20
24
|
println!("{}", serde_json::to_string_pretty(&result)?);
|
|
21
25
|
} else {
|
|
22
26
|
println!("NAOME repository quality initialized.");
|
|
23
|
-
|
|
27
|
+
if result.baseline_pending {
|
|
28
|
+
println!("repository quality policy initialized");
|
|
29
|
+
println!("baseline pending: run naome quality init --baseline");
|
|
30
|
+
} else {
|
|
31
|
+
println!("Baseline violations: {}", result.baseline_violations);
|
|
32
|
+
}
|
|
24
33
|
}
|
|
25
34
|
}
|
|
35
|
+
"reconcile" => run_quality_reconcile(root, args, json)?,
|
|
26
36
|
"check" => run_quality_check(root, args, json)?,
|
|
27
|
-
"report" => run_quality_report(root, json)?,
|
|
37
|
+
"report" => run_quality_report(root, args, json)?,
|
|
38
|
+
"cache" => run_quality_cache(root, args, json)?,
|
|
28
39
|
_ => return Err(format!("unknown naome quality command: {subcommand}").into()),
|
|
29
40
|
}
|
|
30
41
|
Ok(())
|
|
@@ -61,17 +72,41 @@ pub fn run_structure_command(
|
|
|
61
72
|
Ok(())
|
|
62
73
|
}
|
|
63
74
|
|
|
75
|
+
pub fn run_semantic_command(
|
|
76
|
+
root: &Path,
|
|
77
|
+
args: &[String],
|
|
78
|
+
) -> Result<(), Box<dyn std::error::Error>> {
|
|
79
|
+
let Some(subcommand) = args.get(1).map(String::as_str) else {
|
|
80
|
+
return Err("naome semantic requires report, check, route, or loop.".into());
|
|
81
|
+
};
|
|
82
|
+
let json = args.iter().any(|arg| arg == "--json");
|
|
83
|
+
|
|
84
|
+
match subcommand {
|
|
85
|
+
"report" => run_semantic_report(root, args, json)?,
|
|
86
|
+
"check" => run_semantic_check(root, args, json)?,
|
|
87
|
+
"route" => run_semantic_route(root, args, json)?,
|
|
88
|
+
"loop" => run_semantic_loop(root, json)?,
|
|
89
|
+
_ => return Err(format!("unknown naome semantic command: {subcommand}").into()),
|
|
90
|
+
}
|
|
91
|
+
Ok(())
|
|
92
|
+
}
|
|
93
|
+
|
|
64
94
|
fn run_quality_check(
|
|
65
95
|
root: &Path,
|
|
66
96
|
args: &[String],
|
|
67
97
|
json: bool,
|
|
68
98
|
) -> Result<(), Box<dyn std::error::Error>> {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
99
|
+
let paths = option_values(args, "--path");
|
|
100
|
+
let report = if paths.is_empty() {
|
|
101
|
+
if !args.iter().any(|arg| arg == "--changed") {
|
|
102
|
+
return Err("naome quality check requires --changed or --path <path>.".into());
|
|
103
|
+
}
|
|
104
|
+
check_repository_quality(root, QualityMode::ChangedFast)?
|
|
105
|
+
} else {
|
|
106
|
+
check_repository_quality_paths(root, &paths)?
|
|
107
|
+
};
|
|
73
108
|
if json {
|
|
74
|
-
println!("{}",
|
|
109
|
+
println!("{}", report_json(&report, args)?);
|
|
75
110
|
} else if report.ok {
|
|
76
111
|
println!("NAOME repository quality OK.");
|
|
77
112
|
} else {
|
|
@@ -89,10 +124,19 @@ fn run_quality_check(
|
|
|
89
124
|
Ok(())
|
|
90
125
|
}
|
|
91
126
|
|
|
92
|
-
fn run_quality_report(
|
|
93
|
-
|
|
127
|
+
fn run_quality_report(
|
|
128
|
+
root: &Path,
|
|
129
|
+
args: &[String],
|
|
130
|
+
json: bool,
|
|
131
|
+
) -> Result<(), Box<dyn std::error::Error>> {
|
|
132
|
+
let mode = if args.iter().any(|arg| arg == "--deep") {
|
|
133
|
+
QualityMode::DeepReport
|
|
134
|
+
} else {
|
|
135
|
+
QualityMode::Report
|
|
136
|
+
};
|
|
137
|
+
let report = check_repository_quality(root, mode)?;
|
|
94
138
|
if json {
|
|
95
|
-
println!("{}",
|
|
139
|
+
println!("{}", report_json(&report, args)?);
|
|
96
140
|
} else if report.violations.is_empty() {
|
|
97
141
|
println!("NAOME repository quality report: no debt found.");
|
|
98
142
|
} else {
|
|
@@ -108,6 +152,32 @@ fn run_quality_report(root: &Path, json: bool) -> Result<(), Box<dyn std::error:
|
|
|
108
152
|
Ok(())
|
|
109
153
|
}
|
|
110
154
|
|
|
155
|
+
fn run_quality_cache(
|
|
156
|
+
root: &Path,
|
|
157
|
+
args: &[String],
|
|
158
|
+
json: bool,
|
|
159
|
+
) -> Result<(), Box<dyn std::error::Error>> {
|
|
160
|
+
let Some(action) = args.get(2).map(String::as_str) else {
|
|
161
|
+
return Err("naome quality cache requires status or clear.".into());
|
|
162
|
+
};
|
|
163
|
+
let status = match action {
|
|
164
|
+
"status" => quality_cache_status(root)?,
|
|
165
|
+
"clear" => clear_quality_cache(root)?,
|
|
166
|
+
_ => return Err(format!("unknown naome quality cache command: {action}").into()),
|
|
167
|
+
};
|
|
168
|
+
if json {
|
|
169
|
+
println!("{}", serde_json::to_string_pretty(&status)?);
|
|
170
|
+
} else if action == "clear" {
|
|
171
|
+
println!("NAOME quality cache cleared.");
|
|
172
|
+
} else {
|
|
173
|
+
println!(
|
|
174
|
+
"NAOME quality cache: {} entrie(s), {} byte(s).",
|
|
175
|
+
status.entry_count, status.bytes
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
Ok(())
|
|
179
|
+
}
|
|
180
|
+
|
|
111
181
|
fn run_cleanup_plan(root: &Path, json: bool) -> Result<(), Box<dyn std::error::Error>> {
|
|
112
182
|
let plan = plan_quality_cleanup(root)?;
|
|
113
183
|
if json {
|
|
@@ -206,24 +276,158 @@ fn run_structure_explain(
|
|
|
206
276
|
Ok(())
|
|
207
277
|
}
|
|
208
278
|
|
|
209
|
-
fn
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
279
|
+
fn run_semantic_report(
|
|
280
|
+
root: &Path,
|
|
281
|
+
args: &[String],
|
|
282
|
+
json: bool,
|
|
283
|
+
) -> Result<(), Box<dyn std::error::Error>> {
|
|
284
|
+
let mode = if args.iter().any(|arg| arg == "--deep") {
|
|
285
|
+
QualityMode::DeepReport
|
|
286
|
+
} else {
|
|
287
|
+
QualityMode::Report
|
|
288
|
+
};
|
|
289
|
+
let report = check_semantic_legacy(root, mode)?;
|
|
290
|
+
if json {
|
|
291
|
+
println!("{}", serde_json::to_string_pretty(&report)?);
|
|
292
|
+
} else if report.findings.is_empty() {
|
|
293
|
+
println!("NAOME semantic legacy report: no cleanup candidates found.");
|
|
294
|
+
} else {
|
|
295
|
+
println!(
|
|
296
|
+
"NAOME semantic legacy report: {} finding(s).",
|
|
297
|
+
report.findings.len()
|
|
298
|
+
);
|
|
299
|
+
for finding in report.findings.iter().take(20) {
|
|
300
|
+
println!(
|
|
301
|
+
"- {} {}: {}",
|
|
302
|
+
finding.kind, finding.occurrences[0].path, finding.summary
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
Ok(())
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
fn run_semantic_check(
|
|
310
|
+
root: &Path,
|
|
311
|
+
args: &[String],
|
|
312
|
+
json: bool,
|
|
313
|
+
) -> Result<(), Box<dyn std::error::Error>> {
|
|
314
|
+
let paths = option_values(args, "--path");
|
|
315
|
+
let report = if paths.is_empty() {
|
|
316
|
+
if !args.iter().any(|arg| arg == "--changed") {
|
|
317
|
+
return Err("naome semantic check requires --changed or --path <path>.".into());
|
|
318
|
+
}
|
|
319
|
+
check_semantic_legacy(root, QualityMode::ChangedFast)?
|
|
320
|
+
} else {
|
|
321
|
+
check_semantic_legacy_paths(root, &paths)?
|
|
322
|
+
};
|
|
323
|
+
if json {
|
|
324
|
+
println!("{}", serde_json::to_string_pretty(&report)?);
|
|
325
|
+
} else if report.ok {
|
|
326
|
+
println!("NAOME semantic legacy check OK.");
|
|
327
|
+
} else {
|
|
328
|
+
eprintln!(
|
|
329
|
+
"NAOME semantic legacy check failed with {} finding(s).",
|
|
330
|
+
report.findings.len()
|
|
331
|
+
);
|
|
332
|
+
for finding in report.findings.iter().take(20) {
|
|
333
|
+
eprintln!(
|
|
334
|
+
"- {} {}: {}",
|
|
335
|
+
finding.kind, finding.occurrences[0].path, finding.summary
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
if !report.ok {
|
|
340
|
+
std::process::exit(1);
|
|
341
|
+
}
|
|
342
|
+
Ok(())
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
fn run_semantic_route(
|
|
346
|
+
root: &Path,
|
|
347
|
+
args: &[String],
|
|
348
|
+
json: bool,
|
|
349
|
+
) -> Result<(), Box<dyn std::error::Error>> {
|
|
350
|
+
let Some(finding_id) = option_value(args, "--finding") else {
|
|
351
|
+
return Err("naome semantic route requires --finding <id>.".into());
|
|
352
|
+
};
|
|
353
|
+
let report = check_semantic_legacy(root, QualityMode::DeepReport)?;
|
|
354
|
+
let Some(finding) = semantic_route_for_finding(&report, &finding_id) else {
|
|
355
|
+
return Err(format!("semantic finding not found: {finding_id}").into());
|
|
356
|
+
};
|
|
357
|
+
if json {
|
|
358
|
+
println!("{}", serde_json::to_string_pretty(&finding)?);
|
|
359
|
+
} else {
|
|
360
|
+
println!("NAOME semantic cleanup route for {}", finding.id);
|
|
361
|
+
println!("{}", finding.cleanup_route.intent);
|
|
362
|
+
for instruction in &finding.cleanup_route.agent_instructions {
|
|
363
|
+
println!("- {instruction}");
|
|
364
|
+
}
|
|
365
|
+
let paths = finding
|
|
366
|
+
.occurrences
|
|
367
|
+
.iter()
|
|
368
|
+
.map(|occurrence| occurrence.path.as_str())
|
|
369
|
+
.collect::<Vec<_>>()
|
|
370
|
+
.join(", ");
|
|
371
|
+
println!("Affected paths: {paths}");
|
|
372
|
+
}
|
|
373
|
+
Ok(())
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
fn run_semantic_loop(root: &Path, json: bool) -> Result<(), Box<dyn std::error::Error>> {
|
|
377
|
+
let changed = check_semantic_legacy(root, QualityMode::ChangedFast)?;
|
|
378
|
+
let (action, finding) = if let Some(finding) = changed.findings.first().cloned() {
|
|
379
|
+
("cleanup_changed_finding", Some(finding))
|
|
380
|
+
} else {
|
|
381
|
+
let report = check_semantic_legacy(root, QualityMode::Report)?;
|
|
382
|
+
if let Some(finding) = report.findings.first().cloned() {
|
|
383
|
+
("report_legacy_debt", Some(finding))
|
|
384
|
+
} else {
|
|
385
|
+
("complete", None)
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
if json {
|
|
390
|
+
println!(
|
|
391
|
+
"{}",
|
|
392
|
+
serde_json::to_string_pretty(&serde_json::json!({
|
|
393
|
+
"schema": "naome.semantic-loop.v1",
|
|
394
|
+
"ok": action != "cleanup_changed_finding",
|
|
395
|
+
"action": action,
|
|
396
|
+
"finding": finding
|
|
397
|
+
}))?
|
|
398
|
+
);
|
|
399
|
+
} else {
|
|
400
|
+
match finding {
|
|
401
|
+
Some(finding) => {
|
|
402
|
+
println!("NAOME semantic loop action: {action}");
|
|
403
|
+
println!("{} {}", finding.kind, finding.id);
|
|
404
|
+
println!("{}", finding.summary);
|
|
405
|
+
println!("Run: naome semantic route --finding {} --json", finding.id);
|
|
406
|
+
}
|
|
407
|
+
None => println!("NAOME semantic loop complete: no semantic cleanup candidates found."),
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
Ok(())
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
fn quality_init_mode(args: &[String]) -> Result<QualityInitMode, Box<dyn std::error::Error>> {
|
|
414
|
+
let baseline = args.iter().any(|arg| arg == "--baseline");
|
|
415
|
+
let deep_baseline = args.iter().any(|arg| arg == "--deep-baseline");
|
|
416
|
+
if baseline && deep_baseline {
|
|
417
|
+
return Err("naome quality init accepts only one baseline mode.".into());
|
|
418
|
+
}
|
|
419
|
+
Ok(if deep_baseline {
|
|
420
|
+
QualityInitMode::DeepBaseline
|
|
421
|
+
} else if baseline {
|
|
422
|
+
QualityInitMode::Baseline
|
|
423
|
+
} else {
|
|
424
|
+
QualityInitMode::SeedOnly
|
|
425
|
+
})
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
fn option_values(args: &[String], name: &str) -> Vec<String> {
|
|
429
|
+
args.windows(2)
|
|
430
|
+
.filter(|window| window[0] == name)
|
|
431
|
+
.map(|window| window[1].clone())
|
|
432
|
+
.collect()
|
|
229
433
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
pub fn report_json(
|
|
2
|
+
report: &naome_core::QualityReport,
|
|
3
|
+
args: &[String],
|
|
4
|
+
) -> Result<String, Box<dyn std::error::Error>> {
|
|
5
|
+
let mut value = serde_json::to_value(report)?;
|
|
6
|
+
if !args.iter().any(|arg| arg == "--include-scanned-paths") {
|
|
7
|
+
if let Some(object) = value.as_object_mut() {
|
|
8
|
+
object.remove("scannedPaths");
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
Ok(serde_json::to_string_pretty(&value)?)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
pub fn print_quality_violation(violation: &naome_core::QualityViolation) {
|
|
15
|
+
let location = violation
|
|
16
|
+
.line
|
|
17
|
+
.map(|line| format!("{}:{line}", violation.path))
|
|
18
|
+
.unwrap_or_else(|| violation.path.clone());
|
|
19
|
+
eprintln!("- {location} {}: {}", violation.check_id, violation.message);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
pub fn is_structure_check(check_id: &str) -> bool {
|
|
23
|
+
matches!(
|
|
24
|
+
check_id,
|
|
25
|
+
"directory-role-mixing"
|
|
26
|
+
| "misplaced-file-role"
|
|
27
|
+
| "root-file-sprawl"
|
|
28
|
+
| "dumping-ground-directory"
|
|
29
|
+
| "directory-size"
|
|
30
|
+
| "path-depth"
|
|
31
|
+
| "case-collision"
|
|
32
|
+
| "test-source-pairing"
|
|
33
|
+
)
|
|
34
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
use std::collections::BTreeSet;
|
|
2
|
+
use std::path::Path;
|
|
3
|
+
|
|
4
|
+
use naome_core::reconcile_repository_quality;
|
|
5
|
+
|
|
6
|
+
pub fn run_quality_reconcile(
|
|
7
|
+
root: &Path,
|
|
8
|
+
args: &[String],
|
|
9
|
+
json: bool,
|
|
10
|
+
) -> Result<(), Box<dyn std::error::Error>> {
|
|
11
|
+
let write = args.iter().any(|arg| arg == "--write");
|
|
12
|
+
let report = reconcile_repository_quality(root, write)?;
|
|
13
|
+
if json {
|
|
14
|
+
println!("{}", serde_json::to_string_pretty(&report)?);
|
|
15
|
+
} else if report.ok && report.updated_paths.is_empty() {
|
|
16
|
+
println!("NAOME repository quality adapter policy is current.");
|
|
17
|
+
} else if report.ok {
|
|
18
|
+
println!(
|
|
19
|
+
"NAOME repository quality adapter policy updated: {}",
|
|
20
|
+
report.updated_paths.join(", ")
|
|
21
|
+
);
|
|
22
|
+
} else {
|
|
23
|
+
eprintln!(
|
|
24
|
+
"NAOME repository quality adapter policy is stale. Missing adapter(s): {}",
|
|
25
|
+
missing_adapters(&report)
|
|
26
|
+
);
|
|
27
|
+
eprintln!("Run: naome quality reconcile --write");
|
|
28
|
+
}
|
|
29
|
+
if !report.ok {
|
|
30
|
+
std::process::exit(1);
|
|
31
|
+
}
|
|
32
|
+
Ok(())
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
fn missing_adapters(report: &naome_core::QualityReconcileReport) -> String {
|
|
36
|
+
report
|
|
37
|
+
.missing_quality_adapters
|
|
38
|
+
.iter()
|
|
39
|
+
.chain(report.missing_structure_adapters.iter())
|
|
40
|
+
.cloned()
|
|
41
|
+
.collect::<BTreeSet<_>>()
|
|
42
|
+
.into_iter()
|
|
43
|
+
.collect::<Vec<_>>()
|
|
44
|
+
.join(", ")
|
|
45
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
use std::path::Path;
|
|
2
|
+
|
|
3
|
+
use naome_core::{explain_repository_model_path, refresh_repository_model, RepositoryModelRefresh};
|
|
4
|
+
|
|
5
|
+
use crate::cli_args::option_value;
|
|
6
|
+
|
|
7
|
+
pub fn run_repo_command(root: &Path, args: &[String]) -> Result<(), Box<dyn std::error::Error>> {
|
|
8
|
+
let Some(subcommand) = args.get(1).map(String::as_str) else {
|
|
9
|
+
return Err("naome repo requires model, check, or explain.".into());
|
|
10
|
+
};
|
|
11
|
+
let json = args.iter().any(|arg| arg == "--json");
|
|
12
|
+
|
|
13
|
+
match subcommand {
|
|
14
|
+
"model" => run_model(root, args, json)?,
|
|
15
|
+
"check" => run_check(root, json)?,
|
|
16
|
+
"explain" => run_explain(root, args, json)?,
|
|
17
|
+
_ => return Err(format!("unknown naome repo command: {subcommand}").into()),
|
|
18
|
+
}
|
|
19
|
+
Ok(())
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
fn run_model(root: &Path, args: &[String], json: bool) -> Result<(), Box<dyn std::error::Error>> {
|
|
23
|
+
let report = refresh_repository_model(root, args.iter().any(|arg| arg == "--write"))?;
|
|
24
|
+
print_refresh_report(&report, json)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
fn run_check(root: &Path, json: bool) -> Result<(), Box<dyn std::error::Error>> {
|
|
28
|
+
let report = refresh_repository_model(root, false)?;
|
|
29
|
+
print_refresh_report(&report, json)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
fn print_refresh_report(
|
|
33
|
+
report: &RepositoryModelRefresh,
|
|
34
|
+
json: bool,
|
|
35
|
+
) -> Result<(), Box<dyn std::error::Error>> {
|
|
36
|
+
if json {
|
|
37
|
+
println!("{}", serde_json::to_string_pretty(&report)?);
|
|
38
|
+
} else if !report.updated_paths.is_empty() {
|
|
39
|
+
println!(
|
|
40
|
+
"NAOME repository model updated: {}.",
|
|
41
|
+
report.updated_paths.join(", ")
|
|
42
|
+
);
|
|
43
|
+
} else if report.ok {
|
|
44
|
+
println!("NAOME repository model is current.");
|
|
45
|
+
} else {
|
|
46
|
+
println!("NAOME repository model is stale.");
|
|
47
|
+
println!("Run naome repo model --write to refresh deterministic repository facts.");
|
|
48
|
+
}
|
|
49
|
+
if !report.ok {
|
|
50
|
+
std::process::exit(1);
|
|
51
|
+
}
|
|
52
|
+
Ok(())
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
fn run_explain(root: &Path, args: &[String], json: bool) -> Result<(), Box<dyn std::error::Error>> {
|
|
56
|
+
let Some(path) = option_value(args, "--path") else {
|
|
57
|
+
return Err("naome repo explain requires --path <path>.".into());
|
|
58
|
+
};
|
|
59
|
+
let explanation = explain_repository_model_path(root, path)?;
|
|
60
|
+
if json {
|
|
61
|
+
println!("{}", serde_json::to_string_pretty(&explanation)?);
|
|
62
|
+
} else {
|
|
63
|
+
println!(
|
|
64
|
+
"{} role={} language={} module={} entity={}",
|
|
65
|
+
explanation.path,
|
|
66
|
+
explanation.role.as_deref().unwrap_or("unknown"),
|
|
67
|
+
explanation.language.as_deref().unwrap_or("unknown"),
|
|
68
|
+
explanation.module.as_deref().unwrap_or("unknown"),
|
|
69
|
+
explanation.entity.as_deref().unwrap_or("unknown")
|
|
70
|
+
);
|
|
71
|
+
if !explanation.facts.is_empty() {
|
|
72
|
+
println!(
|
|
73
|
+
"Facts: {}",
|
|
74
|
+
explanation
|
|
75
|
+
.facts
|
|
76
|
+
.iter()
|
|
77
|
+
.map(|fact| fact.id.as_str())
|
|
78
|
+
.collect::<Vec<_>>()
|
|
79
|
+
.join(", ")
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
Ok(())
|
|
84
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
use std::path::Path;
|
|
2
|
+
|
|
3
|
+
use naome_core::{migrate_task_state_to_ledger, render_task_state_from_ledger};
|
|
4
|
+
|
|
5
|
+
pub fn run_task_command(root: &Path, args: &[String]) -> Result<(), Box<dyn std::error::Error>> {
|
|
6
|
+
match args.get(1).map(String::as_str) {
|
|
7
|
+
Some("render-state") => render_state(root, args),
|
|
8
|
+
Some("migrate-ledger") => migrate_ledger(root, args),
|
|
9
|
+
_ => Err("unknown task command".into()),
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
fn render_state(root: &Path, args: &[String]) -> Result<(), Box<dyn std::error::Error>> {
|
|
14
|
+
let write = args.iter().any(|arg| arg == "--write");
|
|
15
|
+
let json = args.iter().any(|arg| arg == "--json");
|
|
16
|
+
let rendered = render_task_state_from_ledger(root, write)?;
|
|
17
|
+
|
|
18
|
+
if json {
|
|
19
|
+
println!(
|
|
20
|
+
"{}",
|
|
21
|
+
serde_json::to_string_pretty(&serde_json::json!({
|
|
22
|
+
"schema": "naome.task-render-state.v1",
|
|
23
|
+
"updated": write && rendered.is_some(),
|
|
24
|
+
"source": if rendered.is_some() { "ledger" } else { "task-state" },
|
|
25
|
+
"taskState": rendered
|
|
26
|
+
}))?
|
|
27
|
+
);
|
|
28
|
+
} else if rendered.is_some() {
|
|
29
|
+
println!("NAOME task-state projection rendered from task ledger.");
|
|
30
|
+
} else {
|
|
31
|
+
println!(
|
|
32
|
+
"NAOME task ledger not found; existing task-state compatibility mode remains active."
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
Ok(())
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
fn migrate_ledger(root: &Path, args: &[String]) -> Result<(), Box<dyn std::error::Error>> {
|
|
40
|
+
let write = args.iter().any(|arg| arg == "--write");
|
|
41
|
+
let json = args.iter().any(|arg| arg == "--json");
|
|
42
|
+
let migrated = migrate_task_state_to_ledger(root, write)?;
|
|
43
|
+
|
|
44
|
+
if json {
|
|
45
|
+
println!(
|
|
46
|
+
"{}",
|
|
47
|
+
serde_json::to_string_pretty(&serde_json::json!({
|
|
48
|
+
"schema": "naome.task-migrate-ledger.v1",
|
|
49
|
+
"updated": write && migrated.is_some(),
|
|
50
|
+
"migration": migrated
|
|
51
|
+
}))?
|
|
52
|
+
);
|
|
53
|
+
} else if migrated.is_some() && write {
|
|
54
|
+
println!("NAOME task ledger migrated from task-state.");
|
|
55
|
+
} else if migrated.is_some() {
|
|
56
|
+
println!("NAOME task ledger migration is available; rerun with --write to apply it.");
|
|
57
|
+
} else {
|
|
58
|
+
println!("NAOME task ledger migration skipped; no active task-state task exists.");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
Ok(())
|
|
62
|
+
}
|