@lamentis/naome 1.2.0 → 1.3.0
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 +108 -47
- package/bin/naome-node.js +2 -1579
- package/bin/naome.js +34 -5
- package/crates/naome-cli/Cargo.toml +1 -1
- package/crates/naome-cli/src/dispatcher.rs +7 -2
- package/crates/naome-cli/src/main.rs +37 -22
- package/crates/naome-cli/src/quality_commands.rs +317 -10
- package/crates/naome-cli/src/workflow_commands.rs +21 -1
- 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/git.rs +4 -2
- package/crates/naome-core/src/install_plan.rs +4 -0
- package/crates/naome-core/src/lib.rs +12 -6
- 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 +20 -67
- package/crates/naome-core/src/quality/baseline.rs +8 -0
- package/crates/naome-core/src/quality/cache.rs +153 -0
- package/crates/naome-core/src/quality/checks/duplicate_blocks.rs +25 -11
- 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 +48 -3
- package/crates/naome-core/src/quality/config.rs +8 -15
- package/crates/naome-core/src/quality/config_support.rs +24 -0
- package/crates/naome-core/src/quality/mod.rs +72 -6
- package/crates/naome-core/src/quality/scanner/analysis/normalize.rs +78 -0
- package/crates/naome-core/src/quality/scanner/analysis.rs +160 -0
- package/crates/naome-core/src/quality/scanner/repo_paths.rs +39 -3
- package/crates/naome-core/src/quality/scanner.rs +200 -215
- package/crates/naome-core/src/quality/semantic/checks.rs +134 -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/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 +134 -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 +146 -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 +131 -0
- package/crates/naome-core/src/quality/types.rs +43 -2
- package/crates/naome-core/src/route/builtin_checks.rs +141 -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 -1217
- package/crates/naome-core/src/verification.rs +1 -0
- package/crates/naome-core/src/workflow/doctor.rs +144 -0
- package/crates/naome-core/src/workflow/mod.rs +2 -0
- package/crates/naome-core/src/workflow/mutation.rs +1 -2
- package/crates/naome-core/tests/decision.rs +24 -118
- package/crates/naome-core/tests/harness_health.rs +2 -0
- package/crates/naome-core/tests/install_plan.rs +2 -0
- package/crates/naome-core/tests/quality.rs +26 -123
- package/crates/naome-core/tests/quality_performance.rs +231 -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 +144 -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 -1376
- 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 +202 -0
- package/crates/naome-core/tests/route_worktree.rs +54 -0
- package/crates/naome-core/tests/semantic_legacy.rs +140 -0
- package/crates/naome-core/tests/task_state.rs +60 -432
- package/crates/naome-core/tests/task_state_compact_support/repo.rs +1 -1
- 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_doctor.rs +24 -0
- package/crates/naome-core/tests/workflow_policy.rs +6 -1
- package/crates/naome-core/tests/workflow_support/mod.rs +1 -1
- 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 +171 -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 +2 -1
- package/templates/naome-root/.naome/bin/check-harness-health.js +3 -3
- package/templates/naome-root/.naome/bin/check-task-state.js +3 -3
- package/templates/naome-root/.naome/bin/naome.js +32 -21
- package/templates/naome-root/.naome/manifest.json +5 -3
- package/templates/naome-root/.naome/repository-structure.json +90 -0
- package/templates/naome-root/.naome/verification.json +1 -0
- package/templates/naome-root/.naomeignore +1 -0
- package/templates/naome-root/docs/naome/agent-workflow.md +16 -14
- package/templates/naome-root/docs/naome/index.md +4 -3
- package/templates/naome-root/docs/naome/repository-quality.md +66 -4
- package/templates/naome-root/docs/naome/repository-structure.md +51 -0
- package/templates/naome-root/docs/naome/testing.md +2 -1
package/bin/naome.js
CHANGED
|
@@ -12,7 +12,7 @@ const packageVersion = packageMetadata.version;
|
|
|
12
12
|
const nativeBinaryName = process.platform === "win32" ? "naome.exe" : "naome";
|
|
13
13
|
const args = process.argv.slice(2);
|
|
14
14
|
const [command] = args;
|
|
15
|
-
const helpCommands = "status [--json]|next [--json]|intent --prompt-file <path> [--json]|intent --prompt <text> [--json]|route --prompt-file <path> [--execute] [--json]|route --prompt <text> [--execute] [--json]|explain --prompt-file <path> [--json]|explain --prompt <text> [--json]|install|sync [--check-update]|update [--json] [--execute]|quality init [--json]|quality check --changed [--json]|quality report [--json]|cleanup plan [--json]|cleanup route --path <path> [--json]|refresh-integrity [--json]|workflow search-profile|check-search|phases|processes|mutations [--json]|commit -m \"type(scope): message\"".split("|");
|
|
15
|
+
const helpCommands = "status [--json]|next [--json]|intent --prompt-file <path> [--json]|intent --prompt <text> [--json]|route --prompt-file <path> [--execute] [--json]|route --prompt <text> [--execute] [--json]|explain --prompt-file <path> [--json]|explain --prompt <text> [--json]|doctor [--json]|install|sync [--check-update]|update [--json] [--execute]|quality init [--baseline|--deep-baseline] [--json]|quality check --changed [--include-scanned-paths] [--json]|quality report [--deep] [--include-scanned-paths] [--json]|quality cache status [--json]|quality cache clear|semantic report [--deep] [--json]|semantic check --changed [--json]|semantic route --finding <id> [--json]|semantic loop [--json]|structure report [--json]|structure explain --path <path> [--json]|cleanup plan [--json]|cleanup route --path <path> [--json]|refresh-integrity [--json]|workflow search-profile|check-search|phases|processes|mutations [--json]|commit -m \"type(scope): message\"".split("|");
|
|
16
16
|
|
|
17
17
|
if (isHelpRequest(args)) {
|
|
18
18
|
printHelp();
|
|
@@ -265,13 +265,19 @@ function runNativePackageCommand(args) {
|
|
|
265
265
|
|
|
266
266
|
function ensureRepositoryQualityInitialized(nativeBinary, qualityConfigExisted) {
|
|
267
267
|
const root = process.cwd();
|
|
268
|
-
if (
|
|
268
|
+
if (!existsSync(join(root, ".naome"))) {
|
|
269
269
|
return;
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
272
|
+
if (qualityConfigExisted && repositoryQualitySupportFilesExist(root)) {
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (!qualityConfigExisted) {
|
|
277
|
+
for (const path of repositoryQualityPaths(root)) {
|
|
278
|
+
if (existsSync(path)) {
|
|
279
|
+
unlinkSync(path);
|
|
280
|
+
}
|
|
275
281
|
}
|
|
276
282
|
}
|
|
277
283
|
|
|
@@ -294,6 +300,21 @@ function ensureRepositoryQualityInitialized(nativeBinary, qualityConfigExisted)
|
|
|
294
300
|
}
|
|
295
301
|
process.exit(result.status === null ? 1 : result.status);
|
|
296
302
|
}
|
|
303
|
+
|
|
304
|
+
const output = result.stdout.trim();
|
|
305
|
+
if (output) {
|
|
306
|
+
try {
|
|
307
|
+
const init = JSON.parse(output);
|
|
308
|
+
if (init.configWritten || init.structureConfigWritten) {
|
|
309
|
+
console.log("repository quality policy initialized");
|
|
310
|
+
}
|
|
311
|
+
if (init.baselinePending) {
|
|
312
|
+
console.log("baseline pending: run naome quality init --baseline");
|
|
313
|
+
}
|
|
314
|
+
} catch (_error) {
|
|
315
|
+
console.log(output);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
297
318
|
}
|
|
298
319
|
|
|
299
320
|
function repositoryQualityConfigPath(root) {
|
|
@@ -303,10 +324,18 @@ function repositoryQualityConfigPath(root) {
|
|
|
303
324
|
function repositoryQualityPaths(root) {
|
|
304
325
|
return [
|
|
305
326
|
repositoryQualityConfigPath(root),
|
|
327
|
+
join(root, ".naome", "repository-structure.json"),
|
|
306
328
|
join(root, ".naome", "repository-quality-baseline.json")
|
|
307
329
|
];
|
|
308
330
|
}
|
|
309
331
|
|
|
332
|
+
function repositoryQualitySupportFilesExist(root) {
|
|
333
|
+
return [
|
|
334
|
+
join(root, ".naome", "repository-structure.json"),
|
|
335
|
+
join(root, ".naome", "repository-quality-baseline.json")
|
|
336
|
+
].every((path) => existsSync(path));
|
|
337
|
+
}
|
|
338
|
+
|
|
310
339
|
function resolveNativePackageBinary() {
|
|
311
340
|
const candidates = [
|
|
312
341
|
process.env.NAOME_NATIVE_BIN && resolve(process.cwd(), process.env.NAOME_NATIVE_BIN),
|
|
@@ -3,11 +3,13 @@ use std::path::Path;
|
|
|
3
3
|
use crate::check_commands::{run_harness_health, run_task_state, run_verification_contract};
|
|
4
4
|
use crate::install_bridge::run_install_bridge;
|
|
5
5
|
use crate::prompt_commands::{run_explain, run_intent, run_route};
|
|
6
|
-
use crate::quality_commands::{
|
|
6
|
+
use crate::quality_commands::{
|
|
7
|
+
run_cleanup_command, run_quality_command, run_semantic_command, run_structure_command,
|
|
8
|
+
};
|
|
7
9
|
use crate::simple_commands::{
|
|
8
10
|
print_install_plan, run_commit_paths, run_journal_task, seed_verification,
|
|
9
11
|
};
|
|
10
|
-
use crate::workflow_commands::{run_refresh_integrity, run_workflow_command};
|
|
12
|
+
use crate::workflow_commands::{run_doctor, run_refresh_integrity, run_workflow_command};
|
|
11
13
|
|
|
12
14
|
pub fn dispatch_command(
|
|
13
15
|
root: &Path,
|
|
@@ -19,7 +21,10 @@ pub fn dispatch_command(
|
|
|
19
21
|
"install-plan" => print_install_plan(args)?,
|
|
20
22
|
"seed-verification" => seed_verification(root)?,
|
|
21
23
|
"refresh-integrity" => run_refresh_integrity(root, args)?,
|
|
24
|
+
"doctor" => run_doctor(root, args)?,
|
|
22
25
|
"quality" => run_quality_command(root, args)?,
|
|
26
|
+
"semantic" => run_semantic_command(root, args)?,
|
|
27
|
+
"structure" => run_structure_command(root, args)?,
|
|
23
28
|
"cleanup" => run_cleanup_command(root, args)?,
|
|
24
29
|
"workflow" => run_workflow_command(root, args)?,
|
|
25
30
|
"check-harness-health" => run_harness_health(root, args)?,
|
|
@@ -22,14 +22,23 @@ const HELP: &str = r#"Usage:
|
|
|
22
22
|
naome route --prompt <text> [--execute] [--json]
|
|
23
23
|
naome explain --prompt-file <path> [--json]
|
|
24
24
|
naome explain --prompt <text> [--json]
|
|
25
|
+
naome doctor [--json]
|
|
25
26
|
naome install [--package-root <path>] [--installer-js <path>]
|
|
26
27
|
naome sync [--package-root <path>] [--installer-js <path>]
|
|
27
28
|
naome install-plan [--harness-version <version>]
|
|
28
29
|
naome seed-verification
|
|
29
30
|
naome refresh-integrity [--root <path>] [--json]
|
|
30
|
-
naome quality init [--json]
|
|
31
|
-
naome quality check --changed [--json]
|
|
32
|
-
naome quality report [--json]
|
|
31
|
+
naome quality init [--baseline|--deep-baseline] [--json]
|
|
32
|
+
naome quality check --changed [--include-scanned-paths] [--json]
|
|
33
|
+
naome quality report [--deep] [--include-scanned-paths] [--json]
|
|
34
|
+
naome quality cache status [--json]
|
|
35
|
+
naome quality cache clear
|
|
36
|
+
naome semantic report [--deep] [--json]
|
|
37
|
+
naome semantic check --changed [--json]
|
|
38
|
+
naome semantic route --finding <id> [--json]
|
|
39
|
+
naome semantic loop [--json]
|
|
40
|
+
naome structure report [--json]
|
|
41
|
+
naome structure explain --path <path> [--json]
|
|
33
42
|
naome cleanup plan [--json]
|
|
34
43
|
naome cleanup route --path <path> [--json]
|
|
35
44
|
naome workflow search-profile [--json]
|
|
@@ -41,6 +50,30 @@ const HELP: &str = r#"Usage:
|
|
|
41
50
|
naome check-task-state [--root <path>] [--admission|--progress|--commit-gate|--push-gate] [--allow-missing-archive]
|
|
42
51
|
naome validate-verification [--root <path>]"#;
|
|
43
52
|
|
|
53
|
+
const PUBLIC_COMMANDS: &[&str] = &[
|
|
54
|
+
"status",
|
|
55
|
+
"next",
|
|
56
|
+
"intent",
|
|
57
|
+
"route",
|
|
58
|
+
"explain",
|
|
59
|
+
"doctor",
|
|
60
|
+
"journal-task",
|
|
61
|
+
"commit-paths",
|
|
62
|
+
"seed-verification",
|
|
63
|
+
"refresh-integrity",
|
|
64
|
+
"workflow",
|
|
65
|
+
"quality",
|
|
66
|
+
"semantic",
|
|
67
|
+
"structure",
|
|
68
|
+
"cleanup",
|
|
69
|
+
"install-plan",
|
|
70
|
+
"install",
|
|
71
|
+
"sync",
|
|
72
|
+
"check-harness-health",
|
|
73
|
+
"check-task-state",
|
|
74
|
+
"validate-verification",
|
|
75
|
+
];
|
|
76
|
+
|
|
44
77
|
fn main() {
|
|
45
78
|
if let Err(error) = run() {
|
|
46
79
|
eprintln!("NAOME: {error}");
|
|
@@ -60,25 +93,7 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
|
|
|
60
93
|
return Ok(());
|
|
61
94
|
}
|
|
62
95
|
|
|
63
|
-
if command
|
|
64
|
-
&& command != "next"
|
|
65
|
-
&& command != "intent"
|
|
66
|
-
&& command != "route"
|
|
67
|
-
&& command != "explain"
|
|
68
|
-
&& command != "journal-task"
|
|
69
|
-
&& command != "commit-paths"
|
|
70
|
-
&& command != "seed-verification"
|
|
71
|
-
&& command != "refresh-integrity"
|
|
72
|
-
&& command != "workflow"
|
|
73
|
-
&& command != "quality"
|
|
74
|
-
&& command != "cleanup"
|
|
75
|
-
&& command != "install-plan"
|
|
76
|
-
&& command != "install"
|
|
77
|
-
&& command != "sync"
|
|
78
|
-
&& command != "check-harness-health"
|
|
79
|
-
&& command != "check-task-state"
|
|
80
|
-
&& command != "validate-verification"
|
|
81
|
-
{
|
|
96
|
+
if !PUBLIC_COMMANDS.contains(&command) {
|
|
82
97
|
print_help();
|
|
83
98
|
return Err(format!("unknown command: {command}").into());
|
|
84
99
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
use std::path::Path;
|
|
2
2
|
|
|
3
3
|
use naome_core::{
|
|
4
|
-
check_repository_quality,
|
|
4
|
+
check_repository_quality, check_semantic_legacy, clear_quality_cache,
|
|
5
|
+
explain_repository_structure, init_repository_quality_with_mode, plan_quality_cleanup,
|
|
6
|
+
quality_cache_status, route_quality_cleanup, semantic_route_for_finding, QualityInitMode,
|
|
5
7
|
QualityMode,
|
|
6
8
|
};
|
|
7
9
|
|
|
@@ -9,22 +11,28 @@ use crate::cli_args::option_value;
|
|
|
9
11
|
|
|
10
12
|
pub fn run_quality_command(root: &Path, args: &[String]) -> Result<(), Box<dyn std::error::Error>> {
|
|
11
13
|
let Some(subcommand) = args.get(1).map(String::as_str) else {
|
|
12
|
-
return Err("naome quality requires init, check, or
|
|
14
|
+
return Err("naome quality requires init, check, report, or cache.".into());
|
|
13
15
|
};
|
|
14
16
|
let json = args.iter().any(|arg| arg == "--json");
|
|
15
17
|
|
|
16
18
|
match subcommand {
|
|
17
19
|
"init" => {
|
|
18
|
-
let result =
|
|
20
|
+
let result = init_repository_quality_with_mode(root, quality_init_mode(args)?)?;
|
|
19
21
|
if json {
|
|
20
22
|
println!("{}", serde_json::to_string_pretty(&result)?);
|
|
21
23
|
} else {
|
|
22
24
|
println!("NAOME repository quality initialized.");
|
|
23
|
-
|
|
25
|
+
if result.baseline_pending {
|
|
26
|
+
println!("repository quality policy initialized");
|
|
27
|
+
println!("baseline pending: run naome quality init --baseline");
|
|
28
|
+
} else {
|
|
29
|
+
println!("Baseline violations: {}", result.baseline_violations);
|
|
30
|
+
}
|
|
24
31
|
}
|
|
25
32
|
}
|
|
26
33
|
"check" => run_quality_check(root, args, json)?,
|
|
27
|
-
"report" => run_quality_report(root, json)?,
|
|
34
|
+
"report" => run_quality_report(root, args, json)?,
|
|
35
|
+
"cache" => run_quality_cache(root, args, json)?,
|
|
28
36
|
_ => return Err(format!("unknown naome quality command: {subcommand}").into()),
|
|
29
37
|
}
|
|
30
38
|
Ok(())
|
|
@@ -44,6 +52,42 @@ pub fn run_cleanup_command(root: &Path, args: &[String]) -> Result<(), Box<dyn s
|
|
|
44
52
|
Ok(())
|
|
45
53
|
}
|
|
46
54
|
|
|
55
|
+
pub fn run_structure_command(
|
|
56
|
+
root: &Path,
|
|
57
|
+
args: &[String],
|
|
58
|
+
) -> Result<(), Box<dyn std::error::Error>> {
|
|
59
|
+
let Some(subcommand) = args.get(1).map(String::as_str) else {
|
|
60
|
+
return Err("naome structure requires report or explain.".into());
|
|
61
|
+
};
|
|
62
|
+
let json = args.iter().any(|arg| arg == "--json");
|
|
63
|
+
|
|
64
|
+
match subcommand {
|
|
65
|
+
"report" => run_structure_report(root, json)?,
|
|
66
|
+
"explain" => run_structure_explain(root, args, json)?,
|
|
67
|
+
_ => return Err(format!("unknown naome structure command: {subcommand}").into()),
|
|
68
|
+
}
|
|
69
|
+
Ok(())
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
pub fn run_semantic_command(
|
|
73
|
+
root: &Path,
|
|
74
|
+
args: &[String],
|
|
75
|
+
) -> Result<(), Box<dyn std::error::Error>> {
|
|
76
|
+
let Some(subcommand) = args.get(1).map(String::as_str) else {
|
|
77
|
+
return Err("naome semantic requires report, check, route, or loop.".into());
|
|
78
|
+
};
|
|
79
|
+
let json = args.iter().any(|arg| arg == "--json");
|
|
80
|
+
|
|
81
|
+
match subcommand {
|
|
82
|
+
"report" => run_semantic_report(root, args, json)?,
|
|
83
|
+
"check" => run_semantic_check(root, args, json)?,
|
|
84
|
+
"route" => run_semantic_route(root, args, json)?,
|
|
85
|
+
"loop" => run_semantic_loop(root, json)?,
|
|
86
|
+
_ => return Err(format!("unknown naome semantic command: {subcommand}").into()),
|
|
87
|
+
}
|
|
88
|
+
Ok(())
|
|
89
|
+
}
|
|
90
|
+
|
|
47
91
|
fn run_quality_check(
|
|
48
92
|
root: &Path,
|
|
49
93
|
args: &[String],
|
|
@@ -52,9 +96,9 @@ fn run_quality_check(
|
|
|
52
96
|
if !args.iter().any(|arg| arg == "--changed") {
|
|
53
97
|
return Err("naome quality check requires --changed.".into());
|
|
54
98
|
}
|
|
55
|
-
let report = check_repository_quality(root, QualityMode::
|
|
99
|
+
let report = check_repository_quality(root, QualityMode::ChangedFast)?;
|
|
56
100
|
if json {
|
|
57
|
-
println!("{}",
|
|
101
|
+
println!("{}", report_json(&report, args)?);
|
|
58
102
|
} else if report.ok {
|
|
59
103
|
println!("NAOME repository quality OK.");
|
|
60
104
|
} else {
|
|
@@ -72,10 +116,19 @@ fn run_quality_check(
|
|
|
72
116
|
Ok(())
|
|
73
117
|
}
|
|
74
118
|
|
|
75
|
-
fn run_quality_report(
|
|
76
|
-
|
|
119
|
+
fn run_quality_report(
|
|
120
|
+
root: &Path,
|
|
121
|
+
args: &[String],
|
|
122
|
+
json: bool,
|
|
123
|
+
) -> Result<(), Box<dyn std::error::Error>> {
|
|
124
|
+
let mode = if args.iter().any(|arg| arg == "--deep") {
|
|
125
|
+
QualityMode::DeepReport
|
|
126
|
+
} else {
|
|
127
|
+
QualityMode::Report
|
|
128
|
+
};
|
|
129
|
+
let report = check_repository_quality(root, mode)?;
|
|
77
130
|
if json {
|
|
78
|
-
println!("{}",
|
|
131
|
+
println!("{}", report_json(&report, args)?);
|
|
79
132
|
} else if report.violations.is_empty() {
|
|
80
133
|
println!("NAOME repository quality report: no debt found.");
|
|
81
134
|
} else {
|
|
@@ -91,6 +144,32 @@ fn run_quality_report(root: &Path, json: bool) -> Result<(), Box<dyn std::error:
|
|
|
91
144
|
Ok(())
|
|
92
145
|
}
|
|
93
146
|
|
|
147
|
+
fn run_quality_cache(
|
|
148
|
+
root: &Path,
|
|
149
|
+
args: &[String],
|
|
150
|
+
json: bool,
|
|
151
|
+
) -> Result<(), Box<dyn std::error::Error>> {
|
|
152
|
+
let Some(action) = args.get(2).map(String::as_str) else {
|
|
153
|
+
return Err("naome quality cache requires status or clear.".into());
|
|
154
|
+
};
|
|
155
|
+
let status = match action {
|
|
156
|
+
"status" => quality_cache_status(root)?,
|
|
157
|
+
"clear" => clear_quality_cache(root)?,
|
|
158
|
+
_ => return Err(format!("unknown naome quality cache command: {action}").into()),
|
|
159
|
+
};
|
|
160
|
+
if json {
|
|
161
|
+
println!("{}", serde_json::to_string_pretty(&status)?);
|
|
162
|
+
} else if action == "clear" {
|
|
163
|
+
println!("NAOME quality cache cleared.");
|
|
164
|
+
} else {
|
|
165
|
+
println!(
|
|
166
|
+
"NAOME quality cache: {} entrie(s), {} byte(s).",
|
|
167
|
+
status.entry_count, status.bytes
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
Ok(())
|
|
171
|
+
}
|
|
172
|
+
|
|
94
173
|
fn run_cleanup_plan(root: &Path, json: bool) -> Result<(), Box<dyn std::error::Error>> {
|
|
95
174
|
let plan = plan_quality_cleanup(root)?;
|
|
96
175
|
if json {
|
|
@@ -132,6 +211,234 @@ fn run_cleanup_route(
|
|
|
132
211
|
Ok(())
|
|
133
212
|
}
|
|
134
213
|
|
|
214
|
+
fn run_structure_report(root: &Path, json: bool) -> Result<(), Box<dyn std::error::Error>> {
|
|
215
|
+
let mut report = check_repository_quality(root, QualityMode::Report)?;
|
|
216
|
+
report
|
|
217
|
+
.violations
|
|
218
|
+
.retain(|violation| is_structure_check(&violation.check_id));
|
|
219
|
+
report.summary.violation_count = report.violations.len();
|
|
220
|
+
report.summary.blocking_violation_count = report.violations.len();
|
|
221
|
+
report.summary.baseline_violation_count = report
|
|
222
|
+
.violations
|
|
223
|
+
.iter()
|
|
224
|
+
.filter(|violation| violation.baseline)
|
|
225
|
+
.count();
|
|
226
|
+
report.ok = report.violations.is_empty();
|
|
227
|
+
report.schema = "naome.repository-structure-report.v1".to_string();
|
|
228
|
+
|
|
229
|
+
if json {
|
|
230
|
+
println!("{}", serde_json::to_string_pretty(&report)?);
|
|
231
|
+
} else if report.violations.is_empty() {
|
|
232
|
+
println!("NAOME repository structure report: no debt found.");
|
|
233
|
+
} else {
|
|
234
|
+
println!(
|
|
235
|
+
"NAOME repository structure report: {} violation(s).",
|
|
236
|
+
report.violations.len()
|
|
237
|
+
);
|
|
238
|
+
for violation in report.violations.iter().take(20) {
|
|
239
|
+
print_quality_violation(violation);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
Ok(())
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
fn run_structure_explain(
|
|
246
|
+
root: &Path,
|
|
247
|
+
args: &[String],
|
|
248
|
+
json: bool,
|
|
249
|
+
) -> Result<(), Box<dyn std::error::Error>> {
|
|
250
|
+
let Some(path) = option_value(args, "--path") else {
|
|
251
|
+
return Err("naome structure explain requires --path <path>.".into());
|
|
252
|
+
};
|
|
253
|
+
let explanation = explain_repository_structure(root, path)?;
|
|
254
|
+
if json {
|
|
255
|
+
println!("{}", serde_json::to_string_pretty(&explanation)?);
|
|
256
|
+
} else {
|
|
257
|
+
println!(
|
|
258
|
+
"{} role={} layer={} directory={}",
|
|
259
|
+
explanation.path, explanation.role, explanation.layer, explanation.directory
|
|
260
|
+
);
|
|
261
|
+
if let Some(language) = explanation.language {
|
|
262
|
+
println!("language={language}");
|
|
263
|
+
}
|
|
264
|
+
if let Some(module) = explanation.module {
|
|
265
|
+
println!("module={module}");
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
Ok(())
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
fn run_semantic_report(
|
|
272
|
+
root: &Path,
|
|
273
|
+
args: &[String],
|
|
274
|
+
json: bool,
|
|
275
|
+
) -> Result<(), Box<dyn std::error::Error>> {
|
|
276
|
+
let mode = if args.iter().any(|arg| arg == "--deep") {
|
|
277
|
+
QualityMode::DeepReport
|
|
278
|
+
} else {
|
|
279
|
+
QualityMode::Report
|
|
280
|
+
};
|
|
281
|
+
let report = check_semantic_legacy(root, mode)?;
|
|
282
|
+
if json {
|
|
283
|
+
println!("{}", serde_json::to_string_pretty(&report)?);
|
|
284
|
+
} else if report.findings.is_empty() {
|
|
285
|
+
println!("NAOME semantic legacy report: no cleanup candidates found.");
|
|
286
|
+
} else {
|
|
287
|
+
println!(
|
|
288
|
+
"NAOME semantic legacy report: {} finding(s).",
|
|
289
|
+
report.findings.len()
|
|
290
|
+
);
|
|
291
|
+
for finding in report.findings.iter().take(20) {
|
|
292
|
+
println!(
|
|
293
|
+
"- {} {}: {}",
|
|
294
|
+
finding.kind, finding.occurrences[0].path, finding.summary
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
Ok(())
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
fn run_semantic_check(
|
|
302
|
+
root: &Path,
|
|
303
|
+
args: &[String],
|
|
304
|
+
json: bool,
|
|
305
|
+
) -> Result<(), Box<dyn std::error::Error>> {
|
|
306
|
+
if !args.iter().any(|arg| arg == "--changed") {
|
|
307
|
+
return Err("naome semantic check requires --changed.".into());
|
|
308
|
+
}
|
|
309
|
+
let report = check_semantic_legacy(root, QualityMode::ChangedFast)?;
|
|
310
|
+
if json {
|
|
311
|
+
println!("{}", serde_json::to_string_pretty(&report)?);
|
|
312
|
+
} else if report.ok {
|
|
313
|
+
println!("NAOME semantic legacy check OK.");
|
|
314
|
+
} else {
|
|
315
|
+
eprintln!(
|
|
316
|
+
"NAOME semantic legacy check failed with {} finding(s).",
|
|
317
|
+
report.findings.len()
|
|
318
|
+
);
|
|
319
|
+
for finding in report.findings.iter().take(20) {
|
|
320
|
+
eprintln!(
|
|
321
|
+
"- {} {}: {}",
|
|
322
|
+
finding.kind, finding.occurrences[0].path, finding.summary
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if !report.ok {
|
|
327
|
+
std::process::exit(1);
|
|
328
|
+
}
|
|
329
|
+
Ok(())
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
fn run_semantic_route(
|
|
333
|
+
root: &Path,
|
|
334
|
+
args: &[String],
|
|
335
|
+
json: bool,
|
|
336
|
+
) -> Result<(), Box<dyn std::error::Error>> {
|
|
337
|
+
let Some(finding_id) = option_value(args, "--finding") else {
|
|
338
|
+
return Err("naome semantic route requires --finding <id>.".into());
|
|
339
|
+
};
|
|
340
|
+
let report = check_semantic_legacy(root, QualityMode::DeepReport)?;
|
|
341
|
+
let Some(finding) = semantic_route_for_finding(&report, &finding_id) else {
|
|
342
|
+
return Err(format!("semantic finding not found: {finding_id}").into());
|
|
343
|
+
};
|
|
344
|
+
if json {
|
|
345
|
+
println!("{}", serde_json::to_string_pretty(&finding)?);
|
|
346
|
+
} else {
|
|
347
|
+
println!("NAOME semantic cleanup route for {}", finding.id);
|
|
348
|
+
println!("{}", finding.cleanup_route.intent);
|
|
349
|
+
for instruction in &finding.cleanup_route.agent_instructions {
|
|
350
|
+
println!("- {instruction}");
|
|
351
|
+
}
|
|
352
|
+
let paths = finding
|
|
353
|
+
.occurrences
|
|
354
|
+
.iter()
|
|
355
|
+
.map(|occurrence| occurrence.path.as_str())
|
|
356
|
+
.collect::<Vec<_>>()
|
|
357
|
+
.join(", ");
|
|
358
|
+
println!("Affected paths: {paths}");
|
|
359
|
+
}
|
|
360
|
+
Ok(())
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
fn run_semantic_loop(root: &Path, json: bool) -> Result<(), Box<dyn std::error::Error>> {
|
|
364
|
+
let changed = check_semantic_legacy(root, QualityMode::ChangedFast)?;
|
|
365
|
+
let (action, finding) = if let Some(finding) = changed.findings.first().cloned() {
|
|
366
|
+
("cleanup_changed_finding", Some(finding))
|
|
367
|
+
} else {
|
|
368
|
+
let report = check_semantic_legacy(root, QualityMode::Report)?;
|
|
369
|
+
if let Some(finding) = report.findings.first().cloned() {
|
|
370
|
+
("report_legacy_debt", Some(finding))
|
|
371
|
+
} else {
|
|
372
|
+
("complete", None)
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
if json {
|
|
377
|
+
println!(
|
|
378
|
+
"{}",
|
|
379
|
+
serde_json::to_string_pretty(&serde_json::json!({
|
|
380
|
+
"schema": "naome.semantic-loop.v1",
|
|
381
|
+
"ok": action != "cleanup_changed_finding",
|
|
382
|
+
"action": action,
|
|
383
|
+
"finding": finding
|
|
384
|
+
}))?
|
|
385
|
+
);
|
|
386
|
+
} else {
|
|
387
|
+
match finding {
|
|
388
|
+
Some(finding) => {
|
|
389
|
+
println!("NAOME semantic loop action: {action}");
|
|
390
|
+
println!("{} {}", finding.kind, finding.id);
|
|
391
|
+
println!("{}", finding.summary);
|
|
392
|
+
println!("Run: naome semantic route --finding {} --json", finding.id);
|
|
393
|
+
}
|
|
394
|
+
None => println!("NAOME semantic loop complete: no semantic cleanup candidates found."),
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
Ok(())
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
fn is_structure_check(check_id: &str) -> bool {
|
|
401
|
+
matches!(
|
|
402
|
+
check_id,
|
|
403
|
+
"directory-role-mixing"
|
|
404
|
+
| "misplaced-file-role"
|
|
405
|
+
| "root-file-sprawl"
|
|
406
|
+
| "dumping-ground-directory"
|
|
407
|
+
| "directory-size"
|
|
408
|
+
| "path-depth"
|
|
409
|
+
| "case-collision"
|
|
410
|
+
| "test-source-pairing"
|
|
411
|
+
)
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
fn quality_init_mode(args: &[String]) -> Result<QualityInitMode, Box<dyn std::error::Error>> {
|
|
415
|
+
let baseline = args.iter().any(|arg| arg == "--baseline");
|
|
416
|
+
let deep_baseline = args.iter().any(|arg| arg == "--deep-baseline");
|
|
417
|
+
if baseline && deep_baseline {
|
|
418
|
+
return Err("naome quality init accepts only one baseline mode.".into());
|
|
419
|
+
}
|
|
420
|
+
Ok(if deep_baseline {
|
|
421
|
+
QualityInitMode::DeepBaseline
|
|
422
|
+
} else if baseline {
|
|
423
|
+
QualityInitMode::Baseline
|
|
424
|
+
} else {
|
|
425
|
+
QualityInitMode::SeedOnly
|
|
426
|
+
})
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
fn report_json(
|
|
430
|
+
report: &naome_core::QualityReport,
|
|
431
|
+
args: &[String],
|
|
432
|
+
) -> Result<String, Box<dyn std::error::Error>> {
|
|
433
|
+
let mut value = serde_json::to_value(report)?;
|
|
434
|
+
if !args.iter().any(|arg| arg == "--include-scanned-paths") {
|
|
435
|
+
if let Some(object) = value.as_object_mut() {
|
|
436
|
+
object.remove("scannedPaths");
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
Ok(serde_json::to_string_pretty(&value)?)
|
|
440
|
+
}
|
|
441
|
+
|
|
135
442
|
fn print_quality_violation(violation: &naome_core::QualityViolation) {
|
|
136
443
|
let location = violation
|
|
137
444
|
.line
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
use std::path::Path;
|
|
2
2
|
|
|
3
3
|
use naome_core::{
|
|
4
|
-
classify_mutations, refresh_integrity, safe_rg_args, tracked_process_report,
|
|
4
|
+
classify_mutations, doctor_report, refresh_integrity, safe_rg_args, tracked_process_report,
|
|
5
5
|
validate_search_command, verification_phase_plan,
|
|
6
6
|
};
|
|
7
7
|
|
|
@@ -83,6 +83,26 @@ pub fn run_workflow_command(
|
|
|
83
83
|
Ok(())
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
pub fn run_doctor(root: &Path, args: &[String]) -> Result<(), Box<dyn std::error::Error>> {
|
|
87
|
+
let report = doctor_report(root)?;
|
|
88
|
+
if args.iter().any(|arg| arg == "--json") {
|
|
89
|
+
println!("{}", serde_json::to_string_pretty(&report)?);
|
|
90
|
+
} else {
|
|
91
|
+
println!(
|
|
92
|
+
"NAOME doctor: {}",
|
|
93
|
+
if report.ok { "ok" } else { "attention needed" }
|
|
94
|
+
);
|
|
95
|
+
println!("{}", report.next_action);
|
|
96
|
+
if !report.recommended_check_ids.is_empty() {
|
|
97
|
+
println!(
|
|
98
|
+
"Recommended checks: {}",
|
|
99
|
+
report.recommended_check_ids.join(", ")
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
Ok(())
|
|
104
|
+
}
|
|
105
|
+
|
|
86
106
|
fn run_check_search(
|
|
87
107
|
root: &Path,
|
|
88
108
|
args: &[String],
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
use std::ffi::OsString;
|
|
2
|
+
use std::path::Path;
|
|
3
|
+
use std::process::Command;
|
|
4
|
+
|
|
5
|
+
use crate::models::{CheckDecision, NaomeError};
|
|
6
|
+
|
|
7
|
+
pub(super) fn run_node_check(
|
|
8
|
+
root: &Path,
|
|
9
|
+
script: &str,
|
|
10
|
+
args: &[&str],
|
|
11
|
+
) -> Result<CheckDecision, NaomeError> {
|
|
12
|
+
let mut command_args = vec![script.to_string()];
|
|
13
|
+
command_args.extend(args.iter().map(ToString::to_string));
|
|
14
|
+
let node_bin = std::env::var_os("NAOME_NODE_BIN").unwrap_or_else(|| OsString::from("node"));
|
|
15
|
+
let output = Command::new(&node_bin)
|
|
16
|
+
.args(&command_args)
|
|
17
|
+
.current_dir(root)
|
|
18
|
+
.output()?;
|
|
19
|
+
let mut combined = String::new();
|
|
20
|
+
combined.push_str(&String::from_utf8_lossy(&output.stdout));
|
|
21
|
+
combined.push_str(&String::from_utf8_lossy(&output.stderr));
|
|
22
|
+
|
|
23
|
+
Ok(CheckDecision {
|
|
24
|
+
command: format!(
|
|
25
|
+
"{} {}{}",
|
|
26
|
+
node_bin.to_string_lossy(),
|
|
27
|
+
script,
|
|
28
|
+
if args.is_empty() {
|
|
29
|
+
String::new()
|
|
30
|
+
} else {
|
|
31
|
+
format!(" {}", args.join(" "))
|
|
32
|
+
}
|
|
33
|
+
),
|
|
34
|
+
exit_code: output.status.code(),
|
|
35
|
+
ok: output.status.success(),
|
|
36
|
+
output: combined.trim().to_string(),
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
pub(super) fn extract_known_actions(output: &str) -> Vec<&'static str> {
|
|
41
|
+
const KNOWN: [&str; 11] = [
|
|
42
|
+
"commit_task_baseline",
|
|
43
|
+
"review_task_diff",
|
|
44
|
+
"request_task_changes",
|
|
45
|
+
"cancel_task_changes",
|
|
46
|
+
"commit_upgrade_baseline",
|
|
47
|
+
"review_diff_first",
|
|
48
|
+
"cancel_upgrade_baseline",
|
|
49
|
+
"run_first_run_protocol",
|
|
50
|
+
"run_upgrade_protocol",
|
|
51
|
+
"review_unowned_diff",
|
|
52
|
+
"create_task",
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
let actions: Vec<&'static str> = KNOWN
|
|
56
|
+
.into_iter()
|
|
57
|
+
.filter(|action| output.contains(action))
|
|
58
|
+
.collect();
|
|
59
|
+
if actions.is_empty() {
|
|
60
|
+
vec!["review_task_admission"]
|
|
61
|
+
} else {
|
|
62
|
+
actions
|
|
63
|
+
}
|
|
64
|
+
}
|