@lamentis/naome 1.3.11 → 1.3.12
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/crates/naome-cli/Cargo.toml +1 -1
- package/crates/naome-cli/src/architecture_commands.rs +2 -6
- package/crates/naome-cli/tests/architecture_cli.rs +60 -0
- package/crates/naome-core/Cargo.toml +1 -1
- package/crates/naome-core/src/architecture/config/parser/sections.rs +44 -1
- package/crates/naome-core/src/architecture/config/parser.rs +1 -0
- package/crates/naome-core/src/architecture/config.rs +35 -0
- package/crates/naome-core/src/architecture/output.rs +15 -1
- package/crates/naome-core/src/architecture/rules/budgets.rs +179 -0
- package/crates/naome-core/src/architecture/rules/context.rs +138 -0
- package/crates/naome-core/src/architecture/rules/cycles.rs +39 -0
- package/crates/naome-core/src/architecture/rules/external.rs +185 -0
- package/crates/naome-core/src/architecture/rules/graph.rs +177 -0
- package/crates/naome-core/src/architecture/rules/transitive.rs +89 -0
- package/crates/naome-core/src/architecture/rules.rs +13 -39
- package/crates/naome-core/src/architecture/scan/imports/extractors.rs +4 -7
- package/crates/naome-core/src/architecture/scan/imports/resolver.rs +3 -21
- package/crates/naome-core/src/architecture/scan/imports.rs +16 -0
- package/crates/naome-core/src/architecture.rs +1 -1
- package/crates/naome-core/src/lib.rs +1 -0
- package/crates/naome-core/tests/architecture.rs +53 -85
- package/crates/naome-core/tests/architecture_rules.rs +498 -0
- package/crates/naome-core/tests/architecture_support/mod.rs +78 -0
- package/installer/harness-files.js +3 -3
- package/native/darwin-arm64/naome +0 -0
- package/native/linux-x64/naome +0 -0
- package/package.json +1 -1
- package/templates/naome-root/.naome/manifest.json +1 -1
- package/templates/naome-root/docs/naome/architecture-fitness.md +49 -6
|
@@ -0,0 +1,78 @@
|
|
|
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::{ArchitectureEdgeKind, ArchitectureScanReport};
|
|
8
|
+
|
|
9
|
+
static FIXTURE_COUNTER: AtomicU64 = AtomicU64::new(0);
|
|
10
|
+
|
|
11
|
+
pub struct FixtureRepo {
|
|
12
|
+
root: PathBuf,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
impl FixtureRepo {
|
|
16
|
+
pub fn new() -> Self {
|
|
17
|
+
let nonce = SystemTime::now()
|
|
18
|
+
.duration_since(UNIX_EPOCH)
|
|
19
|
+
.unwrap()
|
|
20
|
+
.as_nanos();
|
|
21
|
+
let counter = FIXTURE_COUNTER.fetch_add(1, Ordering::Relaxed);
|
|
22
|
+
let root = std::env::temp_dir().join(format!(
|
|
23
|
+
"naome-arch-fixture-{}-{nonce}-{counter}",
|
|
24
|
+
std::process::id()
|
|
25
|
+
));
|
|
26
|
+
fs::create_dir_all(&root).unwrap();
|
|
27
|
+
fs::write(
|
|
28
|
+
root.join(".naomeignore"),
|
|
29
|
+
".naome/archive/\n.naome/tasks/\n",
|
|
30
|
+
)
|
|
31
|
+
.unwrap();
|
|
32
|
+
Self { root }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
pub fn path(&self) -> &Path {
|
|
36
|
+
&self.root
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
pub fn write(&self, relative_path: &str, content: &str) {
|
|
40
|
+
let fixture_path = self.root.join(relative_path);
|
|
41
|
+
if let Some(parent) = fixture_path.parent() {
|
|
42
|
+
if !parent.exists() {
|
|
43
|
+
fs::create_dir_all(parent).unwrap();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
fs::write(&fixture_path, content.as_bytes()).unwrap();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
pub fn init_git(&self) {
|
|
50
|
+
run_git(&self.root, &["init"]);
|
|
51
|
+
run_git(&self.root, &["config", "user.email", "naome@example.com"]);
|
|
52
|
+
run_git(&self.root, &["config", "user.name", "NAOME Test"]);
|
|
53
|
+
self.write("README.md", "# Fixture\n");
|
|
54
|
+
run_git(&self.root, &["add", "."]);
|
|
55
|
+
run_git(&self.root, &["commit", "-m", "baseline"]);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
pub fn has_import_edge(scan: &ArchitectureScanReport, from: &str, to: &str) -> bool {
|
|
60
|
+
scan.graph.edges.iter().any(|edge| {
|
|
61
|
+
edge.kind == ArchitectureEdgeKind::Imports && edge.from == from && edge.to == to
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
fn run_git(root: &Path, args: &[&str]) {
|
|
66
|
+
let result = Command::new("git")
|
|
67
|
+
.args(args)
|
|
68
|
+
.current_dir(root)
|
|
69
|
+
.output()
|
|
70
|
+
.unwrap();
|
|
71
|
+
assert!(
|
|
72
|
+
result.status.success(),
|
|
73
|
+
"git {:?} failed: {}{}",
|
|
74
|
+
args,
|
|
75
|
+
String::from_utf8_lossy(&result.stdout),
|
|
76
|
+
String::from_utf8_lossy(&result.stderr)
|
|
77
|
+
);
|
|
78
|
+
}
|
|
@@ -22,7 +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
|
-
|
|
25
|
+
replaceHarnessFile(ctx, "docs/naome/architecture-fitness.md", archiveDirName);
|
|
26
26
|
replaceHarnessFile(ctx, "docs/naome/upgrade.md", archiveDirName);
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -40,7 +40,7 @@ export function ensureTaskControlHarnessFiles(ctx, archiveDirName) {
|
|
|
40
40
|
replaceHarnessFile(ctx, "docs/naome/agent-workflow.md", archiveDirName);
|
|
41
41
|
replaceHarnessFile(ctx, "docs/naome/context-economy.md", archiveDirName);
|
|
42
42
|
replaceHarnessFile(ctx, "docs/naome/execution.md", archiveDirName);
|
|
43
|
-
|
|
43
|
+
replaceHarnessFile(ctx, "docs/naome/architecture-fitness.md", archiveDirName);
|
|
44
44
|
replaceHarnessFile(ctx, "docs/naome/upgrade.md", archiveDirName);
|
|
45
45
|
}
|
|
46
46
|
|
|
@@ -59,7 +59,7 @@ export function ensureHarnessHealthFiles(ctx, archiveDirName) {
|
|
|
59
59
|
replaceHarnessFile(ctx, "docs/naome/context-economy.md", archiveDirName);
|
|
60
60
|
replaceHarnessFile(ctx, "docs/naome/execution.md", archiveDirName);
|
|
61
61
|
ensureTemplateFile(ctx, "docs/naome/security.md");
|
|
62
|
-
|
|
62
|
+
replaceHarnessFile(ctx, "docs/naome/architecture-fitness.md", archiveDirName);
|
|
63
63
|
replaceHarnessFile(ctx, "docs/naome/upgrade.md", archiveDirName);
|
|
64
64
|
ensureNaomeIgnore(ctx);
|
|
65
65
|
}
|
|
Binary file
|
package/native/linux-x64/naome
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
".naome/task-contract.schema.json": "sha256:1b3b62350328d0d6d660e36d1d1baaa2b88718530db774f9ab2a9e2fcba369c8",
|
|
10
10
|
"AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
|
|
11
11
|
"docs/naome/agent-workflow.md": "sha256:0be1c29adfbcd3fd73c4f904080ffc67237692fe413871a30243538c4db38ac7",
|
|
12
|
-
"docs/naome/architecture-fitness.md": "sha256:
|
|
12
|
+
"docs/naome/architecture-fitness.md": "sha256:3963d9a92d6481d4e72815a4dd749549320f23c45100b4821e75b7e6f3ffd00b",
|
|
13
13
|
"docs/naome/context-economy.md": "sha256:3ed5075815ecf4ada46a5e65438769310307c35759fcd46b13dc0b96e02bebd9",
|
|
14
14
|
"docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
|
|
15
15
|
"docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
|
|
@@ -53,6 +53,29 @@ rules:
|
|
|
53
53
|
no_forbidden_layer_dependencies:
|
|
54
54
|
enabled: true
|
|
55
55
|
severity: error
|
|
56
|
+
no_cross_context_internal_imports:
|
|
57
|
+
enabled: true
|
|
58
|
+
severity: error
|
|
59
|
+
public_api_boundary:
|
|
60
|
+
enabled: true
|
|
61
|
+
severity: error
|
|
62
|
+
no_cycles:
|
|
63
|
+
enabled: true
|
|
64
|
+
severity: error
|
|
65
|
+
no_transitive_forbidden_layer_dependencies:
|
|
66
|
+
enabled: true
|
|
67
|
+
severity: error
|
|
68
|
+
max_imports_per_file:
|
|
69
|
+
enabled: true
|
|
70
|
+
value: 20
|
|
71
|
+
severity: warning
|
|
72
|
+
max_fan_out:
|
|
73
|
+
enabled: true
|
|
74
|
+
value: 20
|
|
75
|
+
severity: warning
|
|
76
|
+
external_dependency_policy:
|
|
77
|
+
enabled: true
|
|
78
|
+
severity: error
|
|
56
79
|
max_file_lines:
|
|
57
80
|
enabled: true
|
|
58
81
|
value: 400
|
|
@@ -66,6 +89,14 @@ allowed_dependencies:
|
|
|
66
89
|
infrastructure:
|
|
67
90
|
- domain
|
|
68
91
|
|
|
92
|
+
external_dependencies:
|
|
93
|
+
domain:
|
|
94
|
+
allow: []
|
|
95
|
+
infrastructure:
|
|
96
|
+
allow:
|
|
97
|
+
- "stripe"
|
|
98
|
+
- "@supabase/*"
|
|
99
|
+
|
|
69
100
|
ignore:
|
|
70
101
|
- path: "generated/**"
|
|
71
102
|
reason: "Generated code is not architecture-owned."
|
|
@@ -79,6 +110,17 @@ ignore:
|
|
|
79
110
|
change.
|
|
80
111
|
- `arch.no_forbidden_layer_dependencies` rejects import edges whose source
|
|
81
112
|
layer is not allowed to depend on the imported file's layer.
|
|
113
|
+
- `arch.no_cross_context_internal_imports` rejects imports into another bounded
|
|
114
|
+
context's internal files.
|
|
115
|
+
- `arch.public_api_boundary` requires cross-context imports to target declared
|
|
116
|
+
`public_api` paths.
|
|
117
|
+
- `arch.no_cycles` detects file-level import cycles.
|
|
118
|
+
- `arch.no_transitive_forbidden_layer_dependencies` catches indirect reachability
|
|
119
|
+
from a layer to a forbidden layer.
|
|
120
|
+
- `arch.max_imports_per_file` and `arch.max_fan_out` enforce local dependency
|
|
121
|
+
budgets.
|
|
122
|
+
- `arch.external_dependency_policy` enforces allowed external packages per layer
|
|
123
|
+
or context.
|
|
82
124
|
|
|
83
125
|
## Agent Integration
|
|
84
126
|
|
|
@@ -95,15 +137,16 @@ fails only on configured error rules.
|
|
|
95
137
|
|
|
96
138
|
## Language Support
|
|
97
139
|
|
|
98
|
-
The v1.3.
|
|
140
|
+
The v1.3.12 foundation classifies TypeScript, JavaScript, Rust, Python, Go,
|
|
99
141
|
Java, Kotlin, and Swift files by path extension. It extracts import facts for
|
|
100
142
|
TypeScript, JavaScript, Rust, Python, and Go, resolves relative imports and
|
|
101
143
|
simple repository-absolute aliases, and represents unresolved imports
|
|
102
|
-
explicitly as graph nodes instead of dropping them.
|
|
144
|
+
explicitly as graph nodes instead of dropping them. Architecture rules now
|
|
145
|
+
cover layers, bounded contexts, public APIs, cycles, transitive layer reach,
|
|
146
|
+
import/fan-out budgets, and external dependency policies.
|
|
103
147
|
|
|
104
148
|
## Limitations
|
|
105
149
|
|
|
106
|
-
This release intentionally
|
|
107
|
-
extractors,
|
|
108
|
-
|
|
109
|
-
follow-up slices before v1.4.0.
|
|
150
|
+
This release intentionally keeps validation file-graph based. Manifest
|
|
151
|
+
extractors, SARIF output, persistent scan caching, and deeper symbol-level call
|
|
152
|
+
analysis remain planned follow-up slices before v1.4.0.
|