@lamentis/naome 1.3.9 → 1.3.10
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 +5 -0
- package/bin/naome.js +1 -1
- package/crates/naome-cli/Cargo.toml +1 -1
- package/crates/naome-cli/src/architecture_commands.rs +123 -0
- package/crates/naome-cli/src/cli_args.rs +4 -0
- package/crates/naome-cli/src/dispatcher.rs +2 -0
- package/crates/naome-cli/src/main.rs +6 -0
- package/crates/naome-core/Cargo.toml +1 -1
- package/crates/naome-core/src/architecture/config/parser/scalar.rs +26 -0
- package/crates/naome-core/src/architecture/config/parser/sections.rs +137 -0
- package/crates/naome-core/src/architecture/config/parser.rs +96 -0
- package/crates/naome-core/src/architecture/config.rs +114 -0
- package/crates/naome-core/src/architecture/model.rs +80 -0
- package/crates/naome-core/src/architecture/output.rs +178 -0
- package/crates/naome-core/src/architecture/rules.rs +140 -0
- package/crates/naome-core/src/architecture/scan/graph_builder/emit.rs +56 -0
- package/crates/naome-core/src/architecture/scan/graph_builder/facts.rs +88 -0
- package/crates/naome-core/src/architecture/scan/graph_builder.rs +134 -0
- package/crates/naome-core/src/architecture/scan/path_scan.rs +92 -0
- package/crates/naome-core/src/architecture/scan.rs +75 -0
- package/crates/naome-core/src/architecture.rs +31 -0
- package/crates/naome-core/src/install_plan.rs +2 -0
- package/crates/naome-core/src/lib.rs +16 -8
- package/crates/naome-core/tests/architecture.rs +209 -0
- package/crates/naome-core/tests/harness_health.rs +1 -0
- package/installer/harness-files.js +3 -0
- package/native/darwin-arm64/naome +0 -0
- package/native/linux-x64/naome +0 -0
- package/package.json +1 -1
- package/templates/naome-root/.naome/bin/check-harness-health.js +7 -7
- package/templates/naome-root/.naome/bin/check-task-state.js +7 -7
- package/templates/naome-root/.naome/bin/naome.js +2 -2
- package/templates/naome-root/.naome/manifest.json +10 -8
- package/templates/naome-root/.naome/verification.json +15 -1
- package/templates/naome-root/docs/naome/architecture-fitness.md +97 -0
- package/templates/naome-root/docs/naome/index.md +4 -3
- package/templates/naome-root/docs/naome/testing.md +6 -3
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
use std::fs;
|
|
2
|
+
use std::path::Path;
|
|
3
|
+
|
|
4
|
+
use crate::models::NaomeError;
|
|
5
|
+
use crate::paths;
|
|
6
|
+
|
|
7
|
+
use crate::architecture::config::ArchitectureConfig;
|
|
8
|
+
|
|
9
|
+
pub(super) fn repository_files(
|
|
10
|
+
root: &Path,
|
|
11
|
+
config: &ArchitectureConfig,
|
|
12
|
+
) -> Result<Vec<String>, NaomeError> {
|
|
13
|
+
let ignored_patterns = ignored_patterns(root, config);
|
|
14
|
+
let mut files = Vec::new();
|
|
15
|
+
collect_files(root, root, &ignored_patterns, &mut files)?;
|
|
16
|
+
files.sort();
|
|
17
|
+
Ok(files)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
fn collect_files(
|
|
21
|
+
root: &Path,
|
|
22
|
+
dir: &Path,
|
|
23
|
+
ignored_patterns: &[String],
|
|
24
|
+
files: &mut Vec<String>,
|
|
25
|
+
) -> Result<(), NaomeError> {
|
|
26
|
+
for entry in fs::read_dir(dir)? {
|
|
27
|
+
let entry = entry?;
|
|
28
|
+
let path = entry.path();
|
|
29
|
+
let relative = normalize_path(path.strip_prefix(root).unwrap_or(&path));
|
|
30
|
+
if is_ignored(&relative, ignored_patterns) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
let metadata = fs::symlink_metadata(&path)?;
|
|
34
|
+
if metadata.is_symlink() {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if metadata.is_dir() {
|
|
38
|
+
collect_files(root, &path, ignored_patterns, files)?;
|
|
39
|
+
} else if metadata.is_file() {
|
|
40
|
+
files.push(relative);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
Ok(())
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
fn is_ignored(path: &str, ignored_patterns: &[String]) -> bool {
|
|
47
|
+
path.is_empty() || is_default_ignored_path(path) || paths::matches_any(path, ignored_patterns)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
fn ignored_patterns(root: &Path, config: &ArchitectureConfig) -> Vec<String> {
|
|
51
|
+
let mut patterns = paths::naomeignore_patterns(root);
|
|
52
|
+
patterns.extend([
|
|
53
|
+
".git/**".to_string(),
|
|
54
|
+
".naome/archive/**".to_string(),
|
|
55
|
+
".naome/cache/**".to_string(),
|
|
56
|
+
".naome/local/**".to_string(),
|
|
57
|
+
".naome/tasks/**".to_string(),
|
|
58
|
+
"node_modules/**".to_string(),
|
|
59
|
+
"target/**".to_string(),
|
|
60
|
+
"dist/**".to_string(),
|
|
61
|
+
"build/**".to_string(),
|
|
62
|
+
]);
|
|
63
|
+
patterns.extend(config.ignore.iter().map(|rule| rule.path.clone()));
|
|
64
|
+
patterns
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
fn is_default_ignored_path(path: &str) -> bool {
|
|
68
|
+
path == ".git"
|
|
69
|
+
|| path.starts_with(".git/")
|
|
70
|
+
|| path == ".naome/archive"
|
|
71
|
+
|| path.starts_with(".naome/archive/")
|
|
72
|
+
|| path == ".naome/cache"
|
|
73
|
+
|| path.starts_with(".naome/cache/")
|
|
74
|
+
|| path == ".naome/local"
|
|
75
|
+
|| path.starts_with(".naome/local/")
|
|
76
|
+
|| path == ".naome/tasks"
|
|
77
|
+
|| path.starts_with(".naome/tasks/")
|
|
78
|
+
|| path == ".npm"
|
|
79
|
+
|| path.starts_with(".npm/")
|
|
80
|
+
|| path == "node_modules"
|
|
81
|
+
|| path.contains("/node_modules/")
|
|
82
|
+
|| path == "target"
|
|
83
|
+
|| path.contains("/target/")
|
|
84
|
+
|| path == "dist"
|
|
85
|
+
|| path.contains("/dist/")
|
|
86
|
+
|| path == "build"
|
|
87
|
+
|| path.contains("/build/")
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
fn normalize_path(path: impl AsRef<Path>) -> String {
|
|
91
|
+
path.as_ref().to_string_lossy().replace('\\', "/")
|
|
92
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
use std::collections::BTreeMap;
|
|
2
|
+
use std::path::{Path, PathBuf};
|
|
3
|
+
|
|
4
|
+
use serde::Serialize;
|
|
5
|
+
|
|
6
|
+
use crate::git;
|
|
7
|
+
use crate::models::NaomeError;
|
|
8
|
+
|
|
9
|
+
use super::config::{read_architecture_config, ArchitectureConfig};
|
|
10
|
+
use super::model::ArchitectureGraph;
|
|
11
|
+
|
|
12
|
+
mod graph_builder;
|
|
13
|
+
mod path_scan;
|
|
14
|
+
|
|
15
|
+
#[derive(Debug, Clone, Default)]
|
|
16
|
+
pub struct ArchitectureScanOptions {
|
|
17
|
+
pub config_path: Option<PathBuf>,
|
|
18
|
+
pub changed_only: bool,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
#[derive(Debug, Clone, Serialize)]
|
|
22
|
+
#[serde(rename_all = "camelCase")]
|
|
23
|
+
pub struct ArchitectureScanReport {
|
|
24
|
+
pub schema: String,
|
|
25
|
+
pub graph: ArchitectureGraph,
|
|
26
|
+
pub files_scanned: usize,
|
|
27
|
+
pub changed_only_requested: bool,
|
|
28
|
+
pub changed_only_degraded_to_full_scan: bool,
|
|
29
|
+
pub changed_paths: Vec<String>,
|
|
30
|
+
#[serde(skip_serializing)]
|
|
31
|
+
pub config: ArchitectureConfig,
|
|
32
|
+
#[serde(skip_serializing)]
|
|
33
|
+
pub file_facts: BTreeMap<String, FileFact>,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
#[derive(Debug, Clone, Serialize)]
|
|
37
|
+
#[serde(rename_all = "camelCase")]
|
|
38
|
+
pub struct FileFact {
|
|
39
|
+
pub path: String,
|
|
40
|
+
pub language: Option<String>,
|
|
41
|
+
pub line_count: usize,
|
|
42
|
+
pub layers: Vec<String>,
|
|
43
|
+
pub contexts: Vec<String>,
|
|
44
|
+
pub ignored: Option<String>,
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
pub fn scan_architecture(
|
|
48
|
+
root: &Path,
|
|
49
|
+
options: ArchitectureScanOptions,
|
|
50
|
+
) -> Result<ArchitectureScanReport, NaomeError> {
|
|
51
|
+
let config = read_architecture_config(root, options.config_path.as_deref())?;
|
|
52
|
+
let changed_paths = changed_paths(root, options.changed_only)?;
|
|
53
|
+
let files = path_scan::repository_files(root, &config)?;
|
|
54
|
+
let (mut graph, file_facts) = graph_builder::build_path_graph(root, files, &config);
|
|
55
|
+
|
|
56
|
+
graph.sort_stable();
|
|
57
|
+
Ok(ArchitectureScanReport {
|
|
58
|
+
schema: "naome.arch.scan.v1".to_string(),
|
|
59
|
+
files_scanned: file_facts.len(),
|
|
60
|
+
graph,
|
|
61
|
+
changed_only_requested: options.changed_only,
|
|
62
|
+
changed_only_degraded_to_full_scan: options.changed_only,
|
|
63
|
+
changed_paths,
|
|
64
|
+
config,
|
|
65
|
+
file_facts,
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
fn changed_paths(root: &Path, changed_only: bool) -> Result<Vec<String>, NaomeError> {
|
|
70
|
+
if changed_only {
|
|
71
|
+
git::changed_paths(root)
|
|
72
|
+
} else {
|
|
73
|
+
Ok(Vec::new())
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
mod config;
|
|
2
|
+
mod model;
|
|
3
|
+
mod output;
|
|
4
|
+
mod rules;
|
|
5
|
+
mod scan;
|
|
6
|
+
|
|
7
|
+
use std::path::Path;
|
|
8
|
+
|
|
9
|
+
use crate::models::NaomeError;
|
|
10
|
+
|
|
11
|
+
pub use config::{
|
|
12
|
+
default_architecture_config_text, ArchitectureConfig, ContextConfig, LayerConfig, RuleConfig,
|
|
13
|
+
};
|
|
14
|
+
pub use model::{
|
|
15
|
+
ArchitectureEdge, ArchitectureEdgeKind, ArchitectureGraph, ArchitectureMetadata,
|
|
16
|
+
ArchitectureNode, ArchitectureNodeKind, SourceRange,
|
|
17
|
+
};
|
|
18
|
+
pub use output::{
|
|
19
|
+
format_architecture_explain, format_architecture_scan, format_architecture_validation,
|
|
20
|
+
ArchitectureAgentFeedback, ArchitectureValidation, ArchitectureViolation, Severity,
|
|
21
|
+
ViolationSummary,
|
|
22
|
+
};
|
|
23
|
+
pub use scan::{scan_architecture, ArchitectureScanOptions, ArchitectureScanReport};
|
|
24
|
+
|
|
25
|
+
pub fn validate_architecture(
|
|
26
|
+
root: &Path,
|
|
27
|
+
options: ArchitectureScanOptions,
|
|
28
|
+
) -> Result<ArchitectureValidation, NaomeError> {
|
|
29
|
+
let scan = scan_architecture(root, options)?;
|
|
30
|
+
Ok(rules::validate_scan(scan))
|
|
31
|
+
}
|
|
@@ -12,6 +12,7 @@ pub const MACHINE_OWNED_PATHS: &[&str] = &[
|
|
|
12
12
|
"docs/naome/agent-workflow.md",
|
|
13
13
|
"docs/naome/context-economy.md",
|
|
14
14
|
"docs/naome/task-ledger.md",
|
|
15
|
+
"docs/naome/architecture-fitness.md",
|
|
15
16
|
"docs/naome/execution.md",
|
|
16
17
|
"docs/naome/upgrade.md",
|
|
17
18
|
];
|
|
@@ -48,6 +49,7 @@ pub const LOCAL_ONLY_MACHINE_OWNED_PATHS: &[&str] = &[
|
|
|
48
49
|
"docs/naome/agent-workflow.md",
|
|
49
50
|
"docs/naome/context-economy.md",
|
|
50
51
|
"docs/naome/task-ledger.md",
|
|
52
|
+
"docs/naome/architecture-fitness.md",
|
|
51
53
|
"docs/naome/execution.md",
|
|
52
54
|
"docs/naome/upgrade.md",
|
|
53
55
|
];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
mod architecture;
|
|
1
2
|
mod context;
|
|
2
3
|
mod decision;
|
|
3
4
|
mod git;
|
|
@@ -19,6 +20,14 @@ mod verification_contract;
|
|
|
19
20
|
mod verification_contract_policy;
|
|
20
21
|
mod workflow;
|
|
21
22
|
|
|
23
|
+
pub use architecture::{
|
|
24
|
+
default_architecture_config_text, format_architecture_explain, format_architecture_scan,
|
|
25
|
+
format_architecture_validation, scan_architecture, validate_architecture,
|
|
26
|
+
ArchitectureAgentFeedback, ArchitectureConfig, ArchitectureEdge, ArchitectureEdgeKind,
|
|
27
|
+
ArchitectureGraph, ArchitectureMetadata, ArchitectureNode, ArchitectureNodeKind,
|
|
28
|
+
ArchitectureScanOptions, ArchitectureScanReport, ArchitectureValidation, ArchitectureViolation,
|
|
29
|
+
ContextConfig, LayerConfig, RuleConfig, Severity, SourceRange, ViolationSummary,
|
|
30
|
+
};
|
|
22
31
|
pub use context::{
|
|
23
32
|
select_context_for_changed_paths, select_context_for_prompt, ContextBudgetLedger,
|
|
24
33
|
ContextCapsule, ContextItem, ContextSelection,
|
|
@@ -36,14 +45,13 @@ pub use journal::{append_task_journal, TaskJournalEntry};
|
|
|
36
45
|
pub use models::{Decision, NaomeError};
|
|
37
46
|
pub use quality::{
|
|
38
47
|
check_repository_quality, check_repository_quality_paths, check_semantic_legacy,
|
|
39
|
-
check_semantic_legacy_paths,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
SemanticFinding, SemanticReport, StructurePathExplanation,
|
|
48
|
+
check_semantic_legacy_paths, clear_quality_cache, explain_repository_structure,
|
|
49
|
+
init_repository_quality, init_repository_quality_with_mode, plan_quality_cleanup,
|
|
50
|
+
quality_cache_status, reconcile_repository_quality, route_quality_cleanup,
|
|
51
|
+
semantic_route_for_finding, QualityCacheStatus, QualityCleanupPlan, QualityCleanupRoute,
|
|
52
|
+
QualityCleanupTask, QualityInitMode, QualityInitResult, QualityMode, QualityReconcileReport,
|
|
53
|
+
QualityReport, QualitySummary, QualityViolation, RepositoryQualityConfig,
|
|
54
|
+
RepositoryStructureConfig, SemanticFinding, SemanticReport, StructurePathExplanation,
|
|
47
55
|
};
|
|
48
56
|
pub use repository_model::{
|
|
49
57
|
explain_repository_model_path, refresh_repository_model, repository_model_drift,
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
use std::fs;
|
|
2
|
+
use std::path::{Path, PathBuf};
|
|
3
|
+
use std::process::Command;
|
|
4
|
+
use std::sync::atomic::{AtomicU64, Ordering};
|
|
5
|
+
use std::time::{SystemTime, UNIX_EPOCH};
|
|
6
|
+
|
|
7
|
+
use naome_core::{
|
|
8
|
+
default_architecture_config_text, scan_architecture, validate_architecture, ArchitectureConfig,
|
|
9
|
+
ArchitectureScanOptions,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
static FIXTURE_COUNTER: AtomicU64 = AtomicU64::new(0);
|
|
13
|
+
|
|
14
|
+
#[test]
|
|
15
|
+
fn parses_starter_architecture_config() {
|
|
16
|
+
let config = ArchitectureConfig::parse(default_architecture_config_text(), "test").unwrap();
|
|
17
|
+
|
|
18
|
+
assert!(config.layers.contains_key("application"));
|
|
19
|
+
assert_eq!(
|
|
20
|
+
config.rule("max_file_lines").value,
|
|
21
|
+
Some(400),
|
|
22
|
+
"starter config should seed a production file-size budget"
|
|
23
|
+
);
|
|
24
|
+
assert_eq!(
|
|
25
|
+
config.ignore[0].reason,
|
|
26
|
+
"Generated code is not architecture-owned."
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#[test]
|
|
31
|
+
fn path_extractor_builds_language_agnostic_graph_for_mixed_repo() {
|
|
32
|
+
let repo = FixtureRepo::new();
|
|
33
|
+
repo.write("src/domain/event.ts", "export const event = 1;\n");
|
|
34
|
+
repo.write("src/infrastructure/db.py", "client = object()\n");
|
|
35
|
+
repo.write("cmd/server/main.go", "package main\n");
|
|
36
|
+
repo.write(
|
|
37
|
+
"naome.arch.yaml",
|
|
38
|
+
r#"
|
|
39
|
+
layers:
|
|
40
|
+
domain:
|
|
41
|
+
paths:
|
|
42
|
+
- "src/domain/**"
|
|
43
|
+
infrastructure:
|
|
44
|
+
paths:
|
|
45
|
+
- "src/infrastructure/**"
|
|
46
|
+
contexts:
|
|
47
|
+
app:
|
|
48
|
+
paths:
|
|
49
|
+
- "src/**"
|
|
50
|
+
public_api:
|
|
51
|
+
- "src/index.ts"
|
|
52
|
+
rules:
|
|
53
|
+
max_file_lines:
|
|
54
|
+
enabled: true
|
|
55
|
+
value: 400
|
|
56
|
+
severity: warning
|
|
57
|
+
"#,
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
let scan = scan_architecture(repo.path(), ArchitectureScanOptions::default()).unwrap();
|
|
61
|
+
|
|
62
|
+
assert!(scan
|
|
63
|
+
.graph
|
|
64
|
+
.nodes
|
|
65
|
+
.iter()
|
|
66
|
+
.any(|node| node.id == "file:src/domain/event.ts"));
|
|
67
|
+
assert!(scan
|
|
68
|
+
.graph
|
|
69
|
+
.nodes
|
|
70
|
+
.iter()
|
|
71
|
+
.any(|node| node.id == "layer:domain"));
|
|
72
|
+
assert!(scan
|
|
73
|
+
.graph
|
|
74
|
+
.edges
|
|
75
|
+
.iter()
|
|
76
|
+
.any(|edge| { edge.from == "layer:domain" && edge.to == "file:src/domain/event.ts" }));
|
|
77
|
+
assert_eq!(
|
|
78
|
+
scan.file_facts
|
|
79
|
+
.get("cmd/server/main.go")
|
|
80
|
+
.unwrap()
|
|
81
|
+
.language
|
|
82
|
+
.as_deref(),
|
|
83
|
+
Some("go")
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
#[test]
|
|
88
|
+
fn validates_file_size_budget_with_stable_json_shape() {
|
|
89
|
+
let repo = FixtureRepo::new();
|
|
90
|
+
repo.write(
|
|
91
|
+
"naome.arch.yaml",
|
|
92
|
+
r#"
|
|
93
|
+
rules:
|
|
94
|
+
max_file_lines:
|
|
95
|
+
enabled: true
|
|
96
|
+
value: 2
|
|
97
|
+
severity: error
|
|
98
|
+
"#,
|
|
99
|
+
);
|
|
100
|
+
repo.write("src/too_big.rs", "one\ntwo\nthree\n");
|
|
101
|
+
|
|
102
|
+
let report = validate_architecture(repo.path(), ArchitectureScanOptions::default()).unwrap();
|
|
103
|
+
let json = serde_json::to_string(&report).unwrap();
|
|
104
|
+
|
|
105
|
+
assert_eq!(report.status, "fail");
|
|
106
|
+
assert!(json.contains("\"schema\":\"naome.arch.validation.v1\""));
|
|
107
|
+
assert!(json.contains("\"id\":\"arch.max_file_lines\""));
|
|
108
|
+
let violation = report
|
|
109
|
+
.violations
|
|
110
|
+
.iter()
|
|
111
|
+
.find(|violation| violation.path.as_deref() == Some("src/too_big.rs"))
|
|
112
|
+
.expect("expected src/too_big.rs file-size violation");
|
|
113
|
+
assert_eq!(violation.agent_instruction, "Reduce src/too_big.rs below 2 lines or add a justified generated-code ignore rule if it is not manually owned.");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
#[test]
|
|
117
|
+
fn changed_only_generated_boundary_reports_changed_generated_file() {
|
|
118
|
+
let repo = FixtureRepo::new();
|
|
119
|
+
repo.init_git();
|
|
120
|
+
repo.write(
|
|
121
|
+
"naome.arch.yaml",
|
|
122
|
+
r#"
|
|
123
|
+
rules:
|
|
124
|
+
generated_manual_boundary:
|
|
125
|
+
enabled: true
|
|
126
|
+
severity: error
|
|
127
|
+
ignore:
|
|
128
|
+
- path: "generated/**"
|
|
129
|
+
reason: "Generated code is not manually edited."
|
|
130
|
+
"#,
|
|
131
|
+
);
|
|
132
|
+
repo.write("generated/client.ts", "export const generated = true;\n");
|
|
133
|
+
|
|
134
|
+
let report = validate_architecture(
|
|
135
|
+
repo.path(),
|
|
136
|
+
ArchitectureScanOptions {
|
|
137
|
+
changed_only: true,
|
|
138
|
+
config_path: None,
|
|
139
|
+
},
|
|
140
|
+
)
|
|
141
|
+
.unwrap();
|
|
142
|
+
|
|
143
|
+
assert_eq!(report.status, "fail");
|
|
144
|
+
assert!(report.changed_only_degraded_to_full_scan);
|
|
145
|
+
assert_eq!(report.violations[0].id, "arch.generated_manual_boundary");
|
|
146
|
+
assert_eq!(
|
|
147
|
+
report.violations[0].path.as_deref(),
|
|
148
|
+
Some("generated/client.ts")
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
struct FixtureRepo {
|
|
153
|
+
root: PathBuf,
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
impl FixtureRepo {
|
|
157
|
+
fn new() -> Self {
|
|
158
|
+
let nonce = SystemTime::now()
|
|
159
|
+
.duration_since(UNIX_EPOCH)
|
|
160
|
+
.unwrap()
|
|
161
|
+
.as_nanos();
|
|
162
|
+
let counter = FIXTURE_COUNTER.fetch_add(1, Ordering::Relaxed);
|
|
163
|
+
let root = std::env::temp_dir().join(format!(
|
|
164
|
+
"naome-arch-fixture-{}-{nonce}-{counter}",
|
|
165
|
+
std::process::id()
|
|
166
|
+
));
|
|
167
|
+
fs::create_dir_all(&root).unwrap();
|
|
168
|
+
fs::write(
|
|
169
|
+
root.join(".naomeignore"),
|
|
170
|
+
".naome/archive/\n.naome/tasks/\n",
|
|
171
|
+
)
|
|
172
|
+
.unwrap();
|
|
173
|
+
Self { root }
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
fn path(&self) -> &Path {
|
|
177
|
+
&self.root
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
fn write(&self, relative_path: &str, content: &str) {
|
|
181
|
+
let path = self.root.join(relative_path);
|
|
182
|
+
fs::create_dir_all(path.parent().unwrap()).unwrap();
|
|
183
|
+
fs::write(path, content).unwrap();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
fn init_git(&self) {
|
|
187
|
+
run_git(&self.root, &["init"]);
|
|
188
|
+
run_git(&self.root, &["config", "user.email", "naome@example.com"]);
|
|
189
|
+
run_git(&self.root, &["config", "user.name", "NAOME Test"]);
|
|
190
|
+
self.write("README.md", "# Fixture\n");
|
|
191
|
+
run_git(&self.root, &["add", "."]);
|
|
192
|
+
run_git(&self.root, &["commit", "-m", "baseline"]);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
fn run_git(root: &Path, args: &[&str]) {
|
|
197
|
+
let result = Command::new("git")
|
|
198
|
+
.args(args)
|
|
199
|
+
.current_dir(root)
|
|
200
|
+
.output()
|
|
201
|
+
.unwrap();
|
|
202
|
+
assert!(
|
|
203
|
+
result.status.success(),
|
|
204
|
+
"git {:?} failed: {}{}",
|
|
205
|
+
args,
|
|
206
|
+
String::from_utf8_lossy(&result.stdout),
|
|
207
|
+
String::from_utf8_lossy(&result.stderr)
|
|
208
|
+
);
|
|
209
|
+
}
|
|
@@ -19,6 +19,7 @@ const MACHINE_OWNED_PATHS: &[&str] = &[
|
|
|
19
19
|
"docs/naome/first-run.md",
|
|
20
20
|
"docs/naome/agent-workflow.md",
|
|
21
21
|
"docs/naome/context-economy.md",
|
|
22
|
+
"docs/naome/architecture-fitness.md",
|
|
22
23
|
"docs/naome/execution.md",
|
|
23
24
|
"docs/naome/task-ledger.md",
|
|
24
25
|
"docs/naome/upgrade.md",
|
|
@@ -22,6 +22,7 @@ export function ensureCoreHarnessFiles(ctx, archiveDirName) {
|
|
|
22
22
|
replaceHarnessFile(ctx, "docs/naome/task-ledger.md", archiveDirName);
|
|
23
23
|
ensureTemplateFile(ctx, "docs/naome/repository-model.md");
|
|
24
24
|
ensureTemplateFile(ctx, "docs/naome/security.md");
|
|
25
|
+
ensureTemplateFile(ctx, "docs/naome/architecture-fitness.md");
|
|
25
26
|
replaceHarnessFile(ctx, "docs/naome/upgrade.md", archiveDirName);
|
|
26
27
|
}
|
|
27
28
|
|
|
@@ -39,6 +40,7 @@ export function ensureTaskControlHarnessFiles(ctx, archiveDirName) {
|
|
|
39
40
|
replaceHarnessFile(ctx, "docs/naome/agent-workflow.md", archiveDirName);
|
|
40
41
|
replaceHarnessFile(ctx, "docs/naome/context-economy.md", archiveDirName);
|
|
41
42
|
replaceHarnessFile(ctx, "docs/naome/execution.md", archiveDirName);
|
|
43
|
+
ensureTemplateFile(ctx, "docs/naome/architecture-fitness.md");
|
|
42
44
|
replaceHarnessFile(ctx, "docs/naome/upgrade.md", archiveDirName);
|
|
43
45
|
}
|
|
44
46
|
|
|
@@ -57,6 +59,7 @@ export function ensureHarnessHealthFiles(ctx, archiveDirName) {
|
|
|
57
59
|
replaceHarnessFile(ctx, "docs/naome/context-economy.md", archiveDirName);
|
|
58
60
|
replaceHarnessFile(ctx, "docs/naome/execution.md", archiveDirName);
|
|
59
61
|
ensureTemplateFile(ctx, "docs/naome/security.md");
|
|
62
|
+
ensureTemplateFile(ctx, "docs/naome/architecture-fitness.md");
|
|
60
63
|
replaceHarnessFile(ctx, "docs/naome/upgrade.md", archiveDirName);
|
|
61
64
|
ensureNaomeIgnore(ctx);
|
|
62
65
|
}
|
|
Binary file
|
package/native/linux-x64/naome
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -10,18 +10,18 @@ const nativeBinaryName = process.platform === "win32" ? "naome.exe" : "naome";
|
|
|
10
10
|
const expectedNativeBinaryIntegrity = "sha256:generated";
|
|
11
11
|
|
|
12
12
|
const expectedMachineOwnedIntegrity = Object.freeze({
|
|
13
|
-
"AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
|
|
14
|
-
".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
|
|
15
|
-
".naome/bin/naome.js": "sha256:a34c2e50a68d15ff2722a57590ccddc504e025d3c98ea62fd700d7ec1a789b9a",
|
|
16
|
-
".naome/bin/check-task-state.js": "sha256:2612577b7e4ab45d9d39dd5ac54c8e7ed749d237d78f1a8d252f4dfa0b4eaaab",
|
|
17
13
|
".naome/bin/check-harness-health.js": "sha256:802d7419774981a6af1826b3882270ff8f41259d516f98c52a02b4ddc184c467",
|
|
14
|
+
".naome/bin/check-task-state.js": "sha256:2612577b7e4ab45d9d39dd5ac54c8e7ed749d237d78f1a8d252f4dfa0b4eaaab",
|
|
15
|
+
".naome/bin/naome.js": "sha256:f129c580fb70b3a1d92d0ab0de9fa6c131b2fc51a8dcdebe9d6f5a812a3be61b",
|
|
16
|
+
".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
|
|
18
17
|
".naome/task-contract.schema.json": "sha256:1b3b62350328d0d6d660e36d1d1baaa2b88718530db774f9ab2a9e2fcba369c8",
|
|
19
|
-
"
|
|
20
|
-
"docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
|
|
18
|
+
"AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
|
|
21
19
|
"docs/naome/agent-workflow.md": "sha256:0be1c29adfbcd3fd73c4f904080ffc67237692fe413871a30243538c4db38ac7",
|
|
22
20
|
"docs/naome/context-economy.md": "sha256:3ed5075815ecf4ada46a5e65438769310307c35759fcd46b13dc0b96e02bebd9",
|
|
23
|
-
"docs/naome/task-ledger.md": "sha256:6ca7222c80079b4662fb718d3c71d686770646f1fa52b83b0e90aed1c5a1101b",
|
|
24
21
|
"docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
|
|
22
|
+
"docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
|
|
23
|
+
"docs/naome/index.md": "sha256:cac748ed375d86d288460456fc5d606b29bd99d91148522c303d5400a083dbc5",
|
|
24
|
+
"docs/naome/task-ledger.md": "sha256:6ca7222c80079b4662fb718d3c71d686770646f1fa52b83b0e90aed1c5a1101b",
|
|
25
25
|
"docs/naome/upgrade.md": "sha256:2c60f0441bbd98bd528d109b30a7ded4b0ad55d61ffb9f52edac9e93b7999cb1"
|
|
26
26
|
});
|
|
27
27
|
|
|
@@ -10,18 +10,18 @@ const nativeBinaryName = process.platform === "win32" ? "naome.exe" : "naome";
|
|
|
10
10
|
const expectedNativeBinaryIntegrity = "sha256:generated";
|
|
11
11
|
|
|
12
12
|
const expectedMachineOwnedIntegrity = Object.freeze({
|
|
13
|
-
"AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
|
|
14
|
-
".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
|
|
15
|
-
".naome/bin/naome.js": "sha256:a34c2e50a68d15ff2722a57590ccddc504e025d3c98ea62fd700d7ec1a789b9a",
|
|
16
|
-
".naome/bin/check-task-state.js": "sha256:2612577b7e4ab45d9d39dd5ac54c8e7ed749d237d78f1a8d252f4dfa0b4eaaab",
|
|
17
13
|
".naome/bin/check-harness-health.js": "sha256:802d7419774981a6af1826b3882270ff8f41259d516f98c52a02b4ddc184c467",
|
|
14
|
+
".naome/bin/check-task-state.js": "sha256:2612577b7e4ab45d9d39dd5ac54c8e7ed749d237d78f1a8d252f4dfa0b4eaaab",
|
|
15
|
+
".naome/bin/naome.js": "sha256:f129c580fb70b3a1d92d0ab0de9fa6c131b2fc51a8dcdebe9d6f5a812a3be61b",
|
|
16
|
+
".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
|
|
18
17
|
".naome/task-contract.schema.json": "sha256:1b3b62350328d0d6d660e36d1d1baaa2b88718530db774f9ab2a9e2fcba369c8",
|
|
19
|
-
"
|
|
20
|
-
"docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
|
|
18
|
+
"AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
|
|
21
19
|
"docs/naome/agent-workflow.md": "sha256:0be1c29adfbcd3fd73c4f904080ffc67237692fe413871a30243538c4db38ac7",
|
|
22
20
|
"docs/naome/context-economy.md": "sha256:3ed5075815ecf4ada46a5e65438769310307c35759fcd46b13dc0b96e02bebd9",
|
|
23
|
-
"docs/naome/task-ledger.md": "sha256:6ca7222c80079b4662fb718d3c71d686770646f1fa52b83b0e90aed1c5a1101b",
|
|
24
21
|
"docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
|
|
22
|
+
"docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
|
|
23
|
+
"docs/naome/index.md": "sha256:cac748ed375d86d288460456fc5d606b29bd99d91148522c303d5400a083dbc5",
|
|
24
|
+
"docs/naome/task-ledger.md": "sha256:6ca7222c80079b4662fb718d3c71d686770646f1fa52b83b0e90aed1c5a1101b",
|
|
25
25
|
"docs/naome/upgrade.md": "sha256:2c60f0441bbd98bd528d109b30a7ded4b0ad55d61ffb9f52edac9e93b7999cb1"
|
|
26
26
|
});
|
|
27
27
|
|
|
@@ -27,7 +27,7 @@ function main(argv) {
|
|
|
27
27
|
return;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
if (["status", "next", "intent", "route", "explain", "context", "doctor", "task", "quality", "semantic", "repo", "structure", "cleanup", "refresh-integrity", "workflow"].includes(command)) {
|
|
30
|
+
if (["status", "next", "intent", "route", "explain", "context", "doctor", "task", "quality", "semantic", "arch", "repo", "structure", "cleanup", "refresh-integrity", "workflow"].includes(command)) {
|
|
31
31
|
runNativeDecisionCommand(command, args);
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
@@ -367,7 +367,7 @@ function findAncestorWithAnyMarker(startPath, markers) {
|
|
|
367
367
|
}
|
|
368
368
|
|
|
369
369
|
function printHelp() {
|
|
370
|
-
const commands = "naome status [--json]|naome next [--json]|naome intent --prompt-file <path> [--json]|naome intent --prompt <text> [--json]|naome route --prompt-file <path> [--execute] [--json]|naome route --prompt <text> [--execute] [--json]|naome explain --prompt-file <path> [--json]|naome explain --prompt <text> [--json]|naome context select --changed [--json]|naome context select --prompt-file <path> [--json]|naome context select --prompt <text> [--json]|naome doctor [--json]|naome task render-state [--write] [--json]|naome task migrate-ledger [--write] [--json]|naome quality init [--baseline|--deep-baseline] [--json]|naome quality check --changed [--include-scanned-paths] [--json]|naome quality check --path <path> [--path <path>...] [--include-scanned-paths] [--json]|naome quality report [--deep] [--include-scanned-paths] [--json]|naome quality cache status [--json]|naome quality cache clear|naome semantic report [--deep] [--json]|naome semantic check --changed [--json]|naome semantic check --path <path> [--path <path>...] [--json]|naome semantic route --finding <id> [--json]|naome semantic loop [--json]|naome repo model [--write] [--json]|naome repo check [--json]|naome repo explain --path <path> [--json]|naome structure report [--json]|naome structure explain --path <path> [--json]|naome cleanup plan [--json]|naome cleanup route --path <path> [--json]|naome refresh-integrity [--json]|naome workflow agent-plan|context-delta|proof-plan|capabilities|edit-watchdog|decision-gate|digest [--json]|naome workflow search-profile|check-search|phases|processes|mutations [--json]|naome install|naome sync|naome commit -m \"type(scope): message\"|node .naome/bin/naome.js commit -m \"type(scope): message\"".split("|");
|
|
370
|
+
const commands = "naome status [--json]|naome next [--json]|naome intent --prompt-file <path> [--json]|naome intent --prompt <text> [--json]|naome route --prompt-file <path> [--execute] [--json]|naome route --prompt <text> [--execute] [--json]|naome explain --prompt-file <path> [--json]|naome explain --prompt <text> [--json]|naome context select --changed [--json]|naome context select --prompt-file <path> [--json]|naome context select --prompt <text> [--json]|naome doctor [--json]|naome task render-state [--write] [--json]|naome task migrate-ledger [--write] [--json]|naome quality init [--baseline|--deep-baseline] [--json]|naome quality check --changed [--include-scanned-paths] [--json]|naome quality check --path <path> [--path <path>...] [--include-scanned-paths] [--json]|naome quality report [--deep] [--include-scanned-paths] [--json]|naome quality cache status [--json]|naome quality cache clear|naome semantic report [--deep] [--json]|naome semantic check --changed [--json]|naome semantic check --path <path> [--path <path>...] [--json]|naome semantic route --finding <id> [--json]|naome semantic loop [--json]|naome arch init [--config <path>] [--json]|naome arch explain [--config <path>] [--json]|naome arch scan [--config <path>] [--changed-only] [--write] [--output <path>] [--json]|naome arch validate [--config <path>] [--changed-only] [--json|--agent-feedback]|naome repo model [--write] [--json]|naome repo check [--json]|naome repo explain --path <path> [--json]|naome structure report [--json]|naome structure explain --path <path> [--json]|naome cleanup plan [--json]|naome cleanup route --path <path> [--json]|naome refresh-integrity [--json]|naome workflow agent-plan|context-delta|proof-plan|capabilities|edit-watchdog|decision-gate|digest [--json]|naome workflow search-profile|check-search|phases|processes|mutations [--json]|naome install|naome sync|naome commit -m \"type(scope): message\"|node .naome/bin/naome.js commit -m \"type(scope): message\"".split("|");
|
|
371
371
|
console.log(["Usage:", ...commands.map((command) => ` ${command}`)].join("\n"));
|
|
372
372
|
}
|
|
373
373
|
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
{
|
|
2
|
-
"harnessVersion": "1.3.
|
|
2
|
+
"harnessVersion": "1.3.10",
|
|
3
3
|
"installedAt": null,
|
|
4
4
|
"integrity": {
|
|
5
|
-
"AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
|
|
6
|
-
".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
|
|
7
|
-
".naome/bin/naome.js": "sha256:a34c2e50a68d15ff2722a57590ccddc504e025d3c98ea62fd700d7ec1a789b9a",
|
|
8
|
-
".naome/bin/check-task-state.js": "sha256:2612577b7e4ab45d9d39dd5ac54c8e7ed749d237d78f1a8d252f4dfa0b4eaaab",
|
|
9
5
|
".naome/bin/check-harness-health.js": "sha256:802d7419774981a6af1826b3882270ff8f41259d516f98c52a02b4ddc184c467",
|
|
6
|
+
".naome/bin/check-task-state.js": "sha256:2612577b7e4ab45d9d39dd5ac54c8e7ed749d237d78f1a8d252f4dfa0b4eaaab",
|
|
7
|
+
".naome/bin/naome.js": "sha256:f129c580fb70b3a1d92d0ab0de9fa6c131b2fc51a8dcdebe9d6f5a812a3be61b",
|
|
8
|
+
".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
|
|
10
9
|
".naome/task-contract.schema.json": "sha256:1b3b62350328d0d6d660e36d1d1baaa2b88718530db774f9ab2a9e2fcba369c8",
|
|
11
|
-
"
|
|
12
|
-
"docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
|
|
10
|
+
"AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
|
|
13
11
|
"docs/naome/agent-workflow.md": "sha256:0be1c29adfbcd3fd73c4f904080ffc67237692fe413871a30243538c4db38ac7",
|
|
12
|
+
"docs/naome/architecture-fitness.md": "sha256:ec2cff9f2090d9b6bfeb2464a650cff97790c4d3e626fd40a42374d5f79c7c38",
|
|
14
13
|
"docs/naome/context-economy.md": "sha256:3ed5075815ecf4ada46a5e65438769310307c35759fcd46b13dc0b96e02bebd9",
|
|
15
|
-
"docs/naome/task-ledger.md": "sha256:6ca7222c80079b4662fb718d3c71d686770646f1fa52b83b0e90aed1c5a1101b",
|
|
16
14
|
"docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
|
|
15
|
+
"docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
|
|
16
|
+
"docs/naome/index.md": "sha256:cac748ed375d86d288460456fc5d606b29bd99d91148522c303d5400a083dbc5",
|
|
17
|
+
"docs/naome/task-ledger.md": "sha256:6ca7222c80079b4662fb718d3c71d686770646f1fa52b83b0e90aed1c5a1101b",
|
|
17
18
|
"docs/naome/upgrade.md": "sha256:2c60f0441bbd98bd528d109b30a7ded4b0ad55d61ffb9f52edac9e93b7999cb1"
|
|
18
19
|
},
|
|
19
20
|
"machineOwned": [
|
|
@@ -28,6 +29,7 @@
|
|
|
28
29
|
"docs/naome/agent-workflow.md",
|
|
29
30
|
"docs/naome/context-economy.md",
|
|
30
31
|
"docs/naome/task-ledger.md",
|
|
32
|
+
"docs/naome/architecture-fitness.md",
|
|
31
33
|
"docs/naome/execution.md",
|
|
32
34
|
"docs/naome/upgrade.md"
|
|
33
35
|
],
|
|
@@ -65,6 +65,19 @@
|
|
|
65
65
|
".naome/repository-quality-baseline.json"
|
|
66
66
|
],
|
|
67
67
|
"lastVerified": null
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"id": "architecture-fitness-check",
|
|
71
|
+
"command": "node .naome/bin/naome.js arch validate --changed-only",
|
|
72
|
+
"cwd": ".",
|
|
73
|
+
"purpose": "Validate changed files against deterministic NAOME architecture fitness rules.",
|
|
74
|
+
"cost": "fast",
|
|
75
|
+
"source": "NAOME built-in",
|
|
76
|
+
"evidence": [
|
|
77
|
+
"naome.arch.yaml",
|
|
78
|
+
"docs/naome/architecture-fitness.md"
|
|
79
|
+
],
|
|
80
|
+
"lastVerified": null
|
|
68
81
|
}
|
|
69
82
|
],
|
|
70
83
|
"phases": [
|
|
@@ -81,7 +94,8 @@
|
|
|
81
94
|
"order": 20,
|
|
82
95
|
"checkIds": [
|
|
83
96
|
"repository-quality-check",
|
|
84
|
-
"repository-semantic-check"
|
|
97
|
+
"repository-semantic-check",
|
|
98
|
+
"architecture-fitness-check"
|
|
85
99
|
]
|
|
86
100
|
},
|
|
87
101
|
{
|