@lamentis/naome 1.3.17 → 1.4.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/crates/naome-cli/Cargo.toml +1 -1
- package/crates/naome-cli/src/architecture_commands.rs +16 -3
- package/crates/naome-cli/src/main.rs +10 -1
- package/crates/naome-cli/src/task_commands/common.rs +32 -0
- package/crates/naome-cli/src/task_commands/readiness.rs +40 -0
- package/crates/naome-cli/src/task_commands/record.rs +134 -0
- package/crates/naome-cli/src/task_commands/repair.rs +30 -0
- package/crates/naome-cli/src/task_commands/scope_request.rs +24 -0
- package/crates/naome-cli/src/task_commands/timeline.rs +71 -0
- package/crates/naome-cli/src/task_commands.rs +69 -1
- package/crates/naome-cli/tests/task_cli.rs +58 -0
- package/crates/naome-cli/tests/task_cli_agent_controls.rs +217 -0
- package/crates/naome-cli/tests/task_cli_control.rs +126 -0
- package/crates/naome-cli/tests/task_cli_support/mod.rs +150 -0
- package/crates/naome-core/Cargo.toml +1 -1
- package/crates/naome-core/src/architecture/output.rs +196 -0
- package/crates/naome-core/src/architecture/scan/cache.rs +1 -1
- package/crates/naome-core/src/architecture.rs +1 -0
- package/crates/naome-core/src/lib.rs +15 -9
- package/crates/naome-core/src/task_state/mod.rs +10 -0
- package/crates/naome-core/src/task_state/status/agent_model.rs +76 -0
- package/crates/naome-core/src/task_state/status/control/action.rs +87 -0
- package/crates/naome-core/src/task_state/status/control/exit_code.rs +32 -0
- package/crates/naome-core/src/task_state/status/control/loop_state.rs +70 -0
- package/crates/naome-core/src/task_state/status/control/policy.rs +31 -0
- package/crates/naome-core/src/task_state/status/control/proof_recording.rs +25 -0
- package/crates/naome-core/src/task_state/status/control/recovery.rs +19 -0
- package/crates/naome-core/src/task_state/status/control/repair.rs +125 -0
- package/crates/naome-core/src/task_state/status/control/shared.rs +25 -0
- package/crates/naome-core/src/task_state/status/control.rs +16 -0
- package/crates/naome-core/src/task_state/status/git.rs +133 -0
- package/crates/naome-core/src/task_state/status/model.rs +150 -0
- package/crates/naome-core/src/task_state/status/proof.rs +167 -0
- package/crates/naome-core/src/task_state/status/proof_read.rs +150 -0
- package/crates/naome-core/src/task_state/status/report.rs +148 -0
- package/crates/naome-core/src/task_state/status/report_context.rs +126 -0
- package/crates/naome-core/src/task_state/status/report_support.rs +117 -0
- package/crates/naome-core/src/task_state/status/scope.rs +111 -0
- package/crates/naome-core/src/task_state/status/transition.rs +73 -0
- package/crates/naome-core/src/task_state/status.rs +23 -0
- package/crates/naome-core/src/task_state/status_output.rs +103 -0
- package/crates/naome-core/tests/architecture_cache.rs +1 -1
- package/crates/naome-core/tests/architecture_config.rs +68 -1
- package/crates/naome-core/tests/task_state_support/mod.rs +15 -1
- package/crates/naome-core/tests/task_state_support/states.rs +4 -0
- package/crates/naome-core/tests/task_status.rs +301 -0
- package/crates/naome-core/tests/task_status_git.rs +141 -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 +1 -1
- package/templates/naome-root/.naome/bin/check-task-state.js +1 -1
- package/templates/naome-root/.naome/manifest.json +2 -2
- package/templates/naome-root/docs/naome/architecture-fitness.md +23 -23
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
#![allow(dead_code, unused_imports)]
|
|
2
|
+
|
|
3
|
+
use std::fs;
|
|
4
|
+
|
|
5
|
+
use naome_core::{task_status_exit_code, task_status_report};
|
|
6
|
+
use serde_json::json;
|
|
7
|
+
|
|
8
|
+
mod task_state_support;
|
|
9
|
+
|
|
10
|
+
use task_state_support::{active_task, task_state_with_status, TaskFixture};
|
|
11
|
+
|
|
12
|
+
#[test]
|
|
13
|
+
fn task_status_reports_git_recovery_findings() {
|
|
14
|
+
let repo = TaskFixture::new(task_state_with_status(
|
|
15
|
+
"implementing",
|
|
16
|
+
active_task(json!({
|
|
17
|
+
"allowedPaths": ["**"],
|
|
18
|
+
"requiredCheckIds": [],
|
|
19
|
+
"proofResults": []
|
|
20
|
+
})),
|
|
21
|
+
));
|
|
22
|
+
repo.init_git();
|
|
23
|
+
repo.set_admission_head("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
|
|
24
|
+
|
|
25
|
+
let status = task_status_report(repo.path()).unwrap();
|
|
26
|
+
|
|
27
|
+
assert_eq!(status.git.admission_head_reachable, false);
|
|
28
|
+
assert!(status
|
|
29
|
+
.findings
|
|
30
|
+
.iter()
|
|
31
|
+
.any(|finding| finding.id == "task.git.admission_head_missing"));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
#[test]
|
|
35
|
+
fn task_status_reports_unreachable_existing_admission_head() {
|
|
36
|
+
let repo = TaskFixture::new(task_state_with_status(
|
|
37
|
+
"implementing",
|
|
38
|
+
active_task(json!({})),
|
|
39
|
+
));
|
|
40
|
+
repo.init_git();
|
|
41
|
+
let admission_head = repo.git(["rev-parse", "HEAD"]).trim().to_string();
|
|
42
|
+
repo.git(["checkout", "--orphan", "other"]);
|
|
43
|
+
repo.write("OTHER.md", "other\n");
|
|
44
|
+
repo.git(["add", "."]);
|
|
45
|
+
repo.git(["commit", "-m", "other"]);
|
|
46
|
+
repo.set_admission_head(&admission_head);
|
|
47
|
+
|
|
48
|
+
let status = task_status_report(repo.path()).unwrap();
|
|
49
|
+
|
|
50
|
+
assert!(status.findings.iter().any(|finding| {
|
|
51
|
+
finding.id == "task.git.admission_head_not_reachable"
|
|
52
|
+
&& finding.suggested_fix.contains("Rebase")
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
#[test]
|
|
57
|
+
fn task_status_reports_operation_in_progress_and_conflict_markers() {
|
|
58
|
+
let repo = TaskFixture::new(task_state_with_status(
|
|
59
|
+
"implementing",
|
|
60
|
+
active_task(json!({})),
|
|
61
|
+
));
|
|
62
|
+
repo.init_git();
|
|
63
|
+
let merge_head = repo.git(["rev-parse", "--git-path", "MERGE_HEAD"]);
|
|
64
|
+
fs::write(repo.path().join(merge_head.trim()), "deadbeef\n").unwrap();
|
|
65
|
+
|
|
66
|
+
let status = task_status_report(repo.path()).unwrap();
|
|
67
|
+
assert!(status
|
|
68
|
+
.findings
|
|
69
|
+
.iter()
|
|
70
|
+
.any(|finding| finding.id == "task.git.operation_in_progress"));
|
|
71
|
+
|
|
72
|
+
fs::write(
|
|
73
|
+
repo.path().join(".naome/task-state.json"),
|
|
74
|
+
"<<<<<<< HEAD\n{}\n=======\n{}\n>>>>>>> branch\n",
|
|
75
|
+
)
|
|
76
|
+
.unwrap();
|
|
77
|
+
let status = task_status_report(repo.path()).unwrap();
|
|
78
|
+
assert!(status
|
|
79
|
+
.findings
|
|
80
|
+
.iter()
|
|
81
|
+
.any(|finding| finding.id == "task.state.conflict_markers"));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
#[test]
|
|
85
|
+
fn task_status_reports_branch_divergence_when_upstream_split() {
|
|
86
|
+
let repo = TaskFixture::new(task_state_with_status(
|
|
87
|
+
"implementing",
|
|
88
|
+
active_task(json!({
|
|
89
|
+
"allowedPaths": ["**"],
|
|
90
|
+
"requiredCheckIds": [],
|
|
91
|
+
"proofResults": []
|
|
92
|
+
})),
|
|
93
|
+
));
|
|
94
|
+
repo.init_git();
|
|
95
|
+
let remote = repo.path().join("remote.git");
|
|
96
|
+
let branch = repo.git(["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
97
|
+
let branch = branch.trim();
|
|
98
|
+
repo.git(["init", "--bare", remote.to_str().unwrap()]);
|
|
99
|
+
repo.git(["remote", "add", "origin", remote.to_str().unwrap()]);
|
|
100
|
+
repo.git(["push", "-u", "origin", branch]);
|
|
101
|
+
|
|
102
|
+
repo.write("LOCAL.md", "local\n");
|
|
103
|
+
repo.git(["add", "."]);
|
|
104
|
+
repo.git(["commit", "-m", "local"]);
|
|
105
|
+
|
|
106
|
+
let clone = std::env::temp_dir().join(format!(
|
|
107
|
+
"naome-task-status-remote-work-{}",
|
|
108
|
+
std::process::id()
|
|
109
|
+
));
|
|
110
|
+
let _ = fs::remove_dir_all(&clone);
|
|
111
|
+
repo.git(["clone", remote.to_str().unwrap(), clone.to_str().unwrap()]);
|
|
112
|
+
git_in(&clone, ["config", "user.email", "naome@example.com"]);
|
|
113
|
+
git_in(&clone, ["config", "user.name", "NAOME Test"]);
|
|
114
|
+
fs::write(clone.join("REMOTE.md"), "remote\n").unwrap();
|
|
115
|
+
git_in(&clone, ["add", "."]);
|
|
116
|
+
git_in(&clone, ["commit", "-m", "remote"]);
|
|
117
|
+
git_in(&clone, ["push"]);
|
|
118
|
+
repo.git(["fetch", "origin"]);
|
|
119
|
+
|
|
120
|
+
let status = task_status_report(repo.path()).unwrap();
|
|
121
|
+
assert_eq!(status.git.ahead, 1);
|
|
122
|
+
assert_eq!(status.git.behind, 1);
|
|
123
|
+
assert!(status
|
|
124
|
+
.findings
|
|
125
|
+
.iter()
|
|
126
|
+
.any(|finding| finding.id == "task.git.branch_diverged"));
|
|
127
|
+
assert_eq!(task_status_exit_code(&status.findings, &status.proof), 0);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
fn git_in<const N: usize>(root: &std::path::Path, args: [&str; N]) {
|
|
131
|
+
let output = std::process::Command::new("git")
|
|
132
|
+
.args(args)
|
|
133
|
+
.current_dir(root)
|
|
134
|
+
.output()
|
|
135
|
+
.unwrap();
|
|
136
|
+
assert!(
|
|
137
|
+
output.status.success(),
|
|
138
|
+
"{}",
|
|
139
|
+
String::from_utf8_lossy(&output.stderr)
|
|
140
|
+
);
|
|
141
|
+
}
|
|
Binary file
|
package/native/linux-x64/naome
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -17,7 +17,7 @@ const expectedMachineOwnedIntegrity = Object.freeze({
|
|
|
17
17
|
".naome/task-contract.schema.json": "sha256:1b3b62350328d0d6d660e36d1d1baaa2b88718530db774f9ab2a9e2fcba369c8",
|
|
18
18
|
"AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
|
|
19
19
|
"docs/naome/agent-workflow.md": "sha256:0be1c29adfbcd3fd73c4f904080ffc67237692fe413871a30243538c4db38ac7",
|
|
20
|
-
"docs/naome/architecture-fitness.md": "sha256:
|
|
20
|
+
"docs/naome/architecture-fitness.md": "sha256:be38e0c6dea8b1ebeee3bfd4a2e4e17008829360b1b4649ef45f2ce61e7287bd",
|
|
21
21
|
"docs/naome/context-economy.md": "sha256:3ed5075815ecf4ada46a5e65438769310307c35759fcd46b13dc0b96e02bebd9",
|
|
22
22
|
"docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
|
|
23
23
|
"docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
|
|
@@ -17,7 +17,7 @@ const expectedMachineOwnedIntegrity = Object.freeze({
|
|
|
17
17
|
".naome/task-contract.schema.json": "sha256:1b3b62350328d0d6d660e36d1d1baaa2b88718530db774f9ab2a9e2fcba369c8",
|
|
18
18
|
"AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
|
|
19
19
|
"docs/naome/agent-workflow.md": "sha256:0be1c29adfbcd3fd73c4f904080ffc67237692fe413871a30243538c4db38ac7",
|
|
20
|
-
"docs/naome/architecture-fitness.md": "sha256:
|
|
20
|
+
"docs/naome/architecture-fitness.md": "sha256:be38e0c6dea8b1ebeee3bfd4a2e4e17008829360b1b4649ef45f2ce61e7287bd",
|
|
21
21
|
"docs/naome/context-economy.md": "sha256:3ed5075815ecf4ada46a5e65438769310307c35759fcd46b13dc0b96e02bebd9",
|
|
22
22
|
"docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
|
|
23
23
|
"docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"harnessVersion": "1.
|
|
2
|
+
"harnessVersion": "1.4.0",
|
|
3
3
|
"installedAt": null,
|
|
4
4
|
"integrity": {
|
|
5
5
|
".naome/bin/check-harness-health.js": "sha256:802d7419774981a6af1826b3882270ff8f41259d516f98c52a02b4ddc184c467",
|
|
@@ -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:be38e0c6dea8b1ebeee3bfd4a2e4e17008829360b1b4649ef45f2ce61e7287bd",
|
|
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",
|
|
@@ -14,6 +14,8 @@ facts instead of prompt text.
|
|
|
14
14
|
- `naome arch validate` runs architecture rules with human output.
|
|
15
15
|
- `naome arch validate --json` emits stable machine-readable output.
|
|
16
16
|
- `naome arch validate --agent-feedback` emits compact repair instructions.
|
|
17
|
+
- `naome arch validate --sarif [--output architecture.sarif]` emits SARIF 2.1.0
|
|
18
|
+
for CI code-scanning while preserving failing exit codes.
|
|
17
19
|
- `naome arch validate --changed-only` uses changed paths with the persistent
|
|
18
20
|
architecture cache when available and safely degrades to a full scan when the
|
|
19
21
|
cache cannot prove graph-level soundness.
|
|
@@ -110,15 +112,14 @@ edges as clean architecture.
|
|
|
110
112
|
|
|
111
113
|
## Configuration Findings
|
|
112
114
|
|
|
113
|
-
Validation can pass while still reporting configuration findings
|
|
114
|
-
|
|
115
|
+
Validation can pass while still reporting non-blocking configuration findings
|
|
116
|
+
about weak architecture policy, such as:
|
|
115
117
|
|
|
116
118
|
- broad catch-all layers or contexts overlapping narrower boundaries;
|
|
117
119
|
- layers or contexts whose path patterns match no files;
|
|
118
120
|
- unresolved imports that could hide real dependency edges.
|
|
119
121
|
|
|
120
|
-
Use
|
|
121
|
-
`configFindings` deterministically in CI or agent loops.
|
|
122
|
+
Use JSON output to inspect `configFindings` deterministically in CI or agents.
|
|
122
123
|
|
|
123
124
|
## Incremental Cache
|
|
124
125
|
|
|
@@ -148,7 +149,11 @@ The command is deterministic in both cache-backed and fallback modes; CI can
|
|
|
148
149
|
inspect the JSON fields above when it needs to distinguish performance from
|
|
149
150
|
soundness fallbacks.
|
|
150
151
|
|
|
151
|
-
|
|
152
|
+
Use `node .naome/bin/naome.js arch validate --sarif --output architecture.sarif`
|
|
153
|
+
when CI can upload SARIF. It contains blocking violations, configuration
|
|
154
|
+
findings, unresolved imports, and `agentInstruction` properties for repair loops.
|
|
155
|
+
|
|
156
|
+
For v1.4.0, architecture fitness is a release gate whenever source,
|
|
152
157
|
manifest, alias, config, or structure changes can alter dependency edges. Treat
|
|
153
158
|
error-level violations as blocking. Warning-level config findings are advisory
|
|
154
159
|
unless the repository chooses stricter policy, but unresolved imports should be
|
|
@@ -156,29 +161,24 @@ triaged before claiming a clean architecture result.
|
|
|
156
161
|
|
|
157
162
|
## Language Support
|
|
158
163
|
|
|
159
|
-
The v1.
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
It also extracts package and dependency facts from `package.json`,
|
|
171
|
-
`Cargo.toml`, `pyproject.toml`, `go.mod`, lightweight `pom.xml` / Gradle
|
|
172
|
-
manifests, `Package.swift`, and `.xcodeproj/project.pbxproj`, then emits
|
|
173
|
-
manifest-identity package nodes and manifest-owned `DependsOn` edges to
|
|
174
|
-
external dependencies.
|
|
164
|
+
The v1.4.0 foundation classifies TypeScript, JavaScript, Rust, Python, Go, Java,
|
|
165
|
+
Kotlin, and Swift files by path extension. It extracts imports for TypeScript,
|
|
166
|
+
JavaScript, Rust, Python, Go, and Swift, resolving relative paths,
|
|
167
|
+
repository-absolute aliases, TS/JS `paths`, Python package roots, Go modules,
|
|
168
|
+
SwiftPM targets, and Rust crate/self/super module paths where possible.
|
|
169
|
+
Unresolved imports become explicit graph nodes. Swift/iOS repositories get Apple
|
|
170
|
+
framework imports, SwiftPM manifests, and Xcode Swift package references in the
|
|
171
|
+
normalized graph; Apple SDK frameworks are treated as platform APIs. Manifest
|
|
172
|
+
facts from `package.json`, `Cargo.toml`, `pyproject.toml`, `go.mod`, lightweight
|
|
173
|
+
`pom.xml` / Gradle manifests, `Package.swift`, and `.xcodeproj/project.pbxproj`
|
|
174
|
+
emit manifest-identity package nodes and manifest-owned dependency edges.
|
|
175
175
|
Architecture rules now cover layers, bounded contexts, public APIs, cycles,
|
|
176
176
|
transitive layer reach, import/fan-out budgets, and external dependency
|
|
177
177
|
policies.
|
|
178
178
|
|
|
179
179
|
## Acceptance Coverage
|
|
180
180
|
|
|
181
|
-
v1.4 readiness is covered with deterministic fixture repositories for
|
|
181
|
+
v1.4.0 readiness is covered with deterministic fixture repositories for
|
|
182
182
|
TypeScript/JavaScript aliases, Rust crate paths, Python package roots, Go
|
|
183
183
|
modules, Swift/iOS targets, and mixed monorepos. These fixtures assert both
|
|
184
184
|
positive local-edge resolution and negative forbidden-dependency findings.
|
|
@@ -187,7 +187,7 @@ positive local-edge resolution and negative forbidden-dependency findings.
|
|
|
187
187
|
|
|
188
188
|
This release intentionally keeps validation file-graph based. Manifest
|
|
189
189
|
extractors are dependency-owner oriented and do not yet parse every build-tool
|
|
190
|
-
feature. Deep symbol-level call analysis
|
|
190
|
+
feature. Deep symbol-level call analysis remains follow-up work.
|
|
191
191
|
|
|
192
192
|
## v1.4 Migration Checklist
|
|
193
193
|
|