@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.
Files changed (139) hide show
  1. package/Cargo.lock +2 -2
  2. package/README.md +108 -47
  3. package/bin/naome-node.js +2 -1579
  4. package/bin/naome.js +34 -5
  5. package/crates/naome-cli/Cargo.toml +1 -1
  6. package/crates/naome-cli/src/dispatcher.rs +7 -2
  7. package/crates/naome-cli/src/main.rs +37 -22
  8. package/crates/naome-cli/src/quality_commands.rs +317 -10
  9. package/crates/naome-cli/src/workflow_commands.rs +21 -1
  10. package/crates/naome-core/Cargo.toml +1 -1
  11. package/crates/naome-core/src/decision/checks.rs +64 -0
  12. package/crates/naome-core/src/decision/idle.rs +67 -0
  13. package/crates/naome-core/src/decision/json.rs +36 -0
  14. package/crates/naome-core/src/decision/states.rs +165 -0
  15. package/crates/naome-core/src/decision.rs +131 -353
  16. package/crates/naome-core/src/git.rs +4 -2
  17. package/crates/naome-core/src/install_plan.rs +4 -0
  18. package/crates/naome-core/src/lib.rs +12 -6
  19. package/crates/naome-core/src/paths.rs +3 -1
  20. package/crates/naome-core/src/quality/adapter_support.rs +89 -0
  21. package/crates/naome-core/src/quality/adapters.rs +20 -67
  22. package/crates/naome-core/src/quality/baseline.rs +8 -0
  23. package/crates/naome-core/src/quality/cache.rs +153 -0
  24. package/crates/naome-core/src/quality/checks/duplicate_blocks.rs +25 -11
  25. package/crates/naome-core/src/quality/checks/near_duplicates.rs +4 -2
  26. package/crates/naome-core/src/quality/checks.rs +7 -8
  27. package/crates/naome-core/src/quality/cleanup.rs +48 -3
  28. package/crates/naome-core/src/quality/config.rs +8 -15
  29. package/crates/naome-core/src/quality/config_support.rs +24 -0
  30. package/crates/naome-core/src/quality/mod.rs +72 -6
  31. package/crates/naome-core/src/quality/scanner/analysis/normalize.rs +78 -0
  32. package/crates/naome-core/src/quality/scanner/analysis.rs +160 -0
  33. package/crates/naome-core/src/quality/scanner/repo_paths.rs +39 -3
  34. package/crates/naome-core/src/quality/scanner.rs +200 -215
  35. package/crates/naome-core/src/quality/semantic/checks.rs +134 -0
  36. package/crates/naome-core/src/quality/semantic/extract.rs +158 -0
  37. package/crates/naome-core/src/quality/semantic/model.rs +85 -0
  38. package/crates/naome-core/src/quality/semantic/route.rs +52 -0
  39. package/crates/naome-core/src/quality/semantic.rs +68 -0
  40. package/crates/naome-core/src/quality/structure/adapters.rs +84 -0
  41. package/crates/naome-core/src/quality/structure/checks/basic.rs +153 -0
  42. package/crates/naome-core/src/quality/structure/checks/directory.rs +134 -0
  43. package/crates/naome-core/src/quality/structure/checks/pairing.rs +63 -0
  44. package/crates/naome-core/src/quality/structure/checks.rs +124 -0
  45. package/crates/naome-core/src/quality/structure/classify/roles.rs +188 -0
  46. package/crates/naome-core/src/quality/structure/classify.rs +146 -0
  47. package/crates/naome-core/src/quality/structure/config.rs +89 -0
  48. package/crates/naome-core/src/quality/structure/defaults.rs +107 -0
  49. package/crates/naome-core/src/quality/structure/mod.rs +77 -0
  50. package/crates/naome-core/src/quality/structure/model.rs +131 -0
  51. package/crates/naome-core/src/quality/types.rs +43 -2
  52. package/crates/naome-core/src/route/builtin_checks.rs +141 -0
  53. package/crates/naome-core/src/route/builtin_context.rs +73 -0
  54. package/crates/naome-core/src/route/builtin_integrity.rs +49 -0
  55. package/crates/naome-core/src/route/builtin_require.rs +40 -0
  56. package/crates/naome-core/src/route/context.rs +180 -0
  57. package/crates/naome-core/src/route/execution.rs +96 -0
  58. package/crates/naome-core/src/route/execution_baselines.rs +146 -0
  59. package/crates/naome-core/src/route/execution_support.rs +57 -0
  60. package/crates/naome-core/src/route/execution_tasks.rs +71 -0
  61. package/crates/naome-core/src/route/git_ops.rs +72 -0
  62. package/crates/naome-core/src/route/quality_gate.rs +73 -0
  63. package/crates/naome-core/src/route/quality_gate_config.rs +126 -0
  64. package/crates/naome-core/src/route/quality_gate_snapshot.rs +69 -0
  65. package/crates/naome-core/src/route/worktree.rs +75 -0
  66. package/crates/naome-core/src/route/worktree_files.rs +32 -0
  67. package/crates/naome-core/src/route/worktree_plan.rs +131 -0
  68. package/crates/naome-core/src/route.rs +44 -1217
  69. package/crates/naome-core/src/verification.rs +1 -0
  70. package/crates/naome-core/src/workflow/doctor.rs +144 -0
  71. package/crates/naome-core/src/workflow/mod.rs +2 -0
  72. package/crates/naome-core/src/workflow/mutation.rs +1 -2
  73. package/crates/naome-core/tests/decision.rs +24 -118
  74. package/crates/naome-core/tests/harness_health.rs +2 -0
  75. package/crates/naome-core/tests/install_plan.rs +2 -0
  76. package/crates/naome-core/tests/quality.rs +26 -123
  77. package/crates/naome-core/tests/quality_performance.rs +231 -0
  78. package/crates/naome-core/tests/quality_structure.rs +116 -0
  79. package/crates/naome-core/tests/quality_structure_adapters.rs +98 -0
  80. package/crates/naome-core/tests/quality_structure_policy.rs +144 -0
  81. package/crates/naome-core/tests/quality_structure_support/mod.rs +249 -0
  82. package/crates/naome-core/tests/repo_support/mod.rs +16 -0
  83. package/crates/naome-core/tests/repo_support/repo.rs +113 -0
  84. package/crates/naome-core/tests/repo_support/repo_factories.rs +99 -0
  85. package/crates/naome-core/tests/repo_support/repo_helpers.rs +123 -0
  86. package/crates/naome-core/tests/repo_support/routes.rs +81 -0
  87. package/crates/naome-core/tests/repo_support/verification.rs +168 -0
  88. package/crates/naome-core/tests/repo_support/verification_values.rs +135 -0
  89. package/crates/naome-core/tests/route.rs +1 -1376
  90. package/crates/naome-core/tests/route_baseline.rs +86 -0
  91. package/crates/naome-core/tests/route_completion.rs +141 -0
  92. package/crates/naome-core/tests/route_harness_refresh.rs +135 -0
  93. package/crates/naome-core/tests/route_user_diff.rs +202 -0
  94. package/crates/naome-core/tests/route_worktree.rs +54 -0
  95. package/crates/naome-core/tests/semantic_legacy.rs +140 -0
  96. package/crates/naome-core/tests/task_state.rs +60 -432
  97. package/crates/naome-core/tests/task_state_compact_support/repo.rs +1 -1
  98. package/crates/naome-core/tests/task_state_support/mod.rs +163 -0
  99. package/crates/naome-core/tests/task_state_support/states.rs +84 -0
  100. package/crates/naome-core/tests/verification.rs +4 -45
  101. package/crates/naome-core/tests/verification_contract.rs +22 -78
  102. package/crates/naome-core/tests/workflow_doctor.rs +24 -0
  103. package/crates/naome-core/tests/workflow_policy.rs +6 -1
  104. package/crates/naome-core/tests/workflow_support/mod.rs +1 -1
  105. package/installer/agents.js +90 -0
  106. package/installer/context.js +67 -0
  107. package/installer/filesystem.js +166 -0
  108. package/installer/flows.js +84 -0
  109. package/installer/git-boundary.js +171 -0
  110. package/installer/git-hook-content.js +36 -0
  111. package/installer/git-hooks.js +134 -0
  112. package/installer/git-local.js +2 -0
  113. package/installer/git-shared.js +35 -0
  114. package/installer/harness-file-ops.js +140 -0
  115. package/installer/harness-files.js +56 -0
  116. package/installer/harness-verification.js +123 -0
  117. package/installer/install-plan.js +66 -0
  118. package/installer/main.js +25 -0
  119. package/installer/manifest-state.js +167 -0
  120. package/installer/native-build.js +24 -0
  121. package/installer/native-format.js +6 -0
  122. package/installer/native.js +162 -0
  123. package/installer/output.js +131 -0
  124. package/installer/version.js +32 -0
  125. package/native/darwin-arm64/naome +0 -0
  126. package/native/linux-x64/naome +0 -0
  127. package/package.json +2 -1
  128. package/templates/naome-root/.naome/bin/check-harness-health.js +3 -3
  129. package/templates/naome-root/.naome/bin/check-task-state.js +3 -3
  130. package/templates/naome-root/.naome/bin/naome.js +32 -21
  131. package/templates/naome-root/.naome/manifest.json +5 -3
  132. package/templates/naome-root/.naome/repository-structure.json +90 -0
  133. package/templates/naome-root/.naome/verification.json +1 -0
  134. package/templates/naome-root/.naomeignore +1 -0
  135. package/templates/naome-root/docs/naome/agent-workflow.md +16 -14
  136. package/templates/naome-root/docs/naome/index.md +4 -3
  137. package/templates/naome-root/docs/naome/repository-quality.md +66 -4
  138. package/templates/naome-root/docs/naome/repository-structure.md +51 -0
  139. package/templates/naome-root/docs/naome/testing.md +2 -1
@@ -0,0 +1,67 @@
1
+ use std::path::Path;
2
+
3
+ use crate::models::{Decision, NaomeError};
4
+ use crate::paths;
5
+ use crate::task_state::harness_refresh_diff;
6
+
7
+ pub(super) fn idle_diff_decision(
8
+ root: &Path,
9
+ changed_paths: &[String],
10
+ machine_owned: &[String],
11
+ known_harness_paths: &[String],
12
+ ) -> Result<Decision, NaomeError> {
13
+ let all_machine_owned = !machine_owned.is_empty()
14
+ && changed_paths
15
+ .iter()
16
+ .all(|path| paths::matches_any(path, machine_owned));
17
+ let all_harness_owned = !known_harness_paths.is_empty()
18
+ && changed_paths
19
+ .iter()
20
+ .all(|path| paths::matches_any(path, known_harness_paths));
21
+
22
+ if harness_refresh_diff(root)?.is_some_and(|diff| diff.unrelated_paths.is_empty()) {
23
+ Ok(harness_repair_decision(
24
+ "Machine-owned NAOME harness refresh files changed outside an active task.",
25
+ "Run NAOME intent for the next natural-language request; deterministic policy can baseline a pure harness refresh automatically.",
26
+ ))
27
+ } else if all_machine_owned {
28
+ Ok(harness_repair_decision(
29
+ "Machine-owned NAOME harness files changed outside an active task.",
30
+ "Review and baseline the harness repair or cancel it before feature work.",
31
+ ))
32
+ } else if all_harness_owned {
33
+ Ok(Decision::new(
34
+ "install_or_upgrade_unbaselined",
35
+ true,
36
+ "NAOME setup or upgrade files changed outside an active task.",
37
+ vec![
38
+ "commit_upgrade_baseline",
39
+ "review_diff_first",
40
+ "cancel_upgrade_baseline",
41
+ ],
42
+ "Resolve the setup or upgrade diff before feature work.",
43
+ ))
44
+ } else {
45
+ Ok(Decision::new(
46
+ "dirty_unowned_diff",
47
+ true,
48
+ "The repository has changes not owned by an active NAOME task.",
49
+ vec!["review_unowned_diff"],
50
+ "Review the unowned diff, or route a new task so NAOME can isolate task work without touching it.",
51
+ ))
52
+ }
53
+ }
54
+
55
+ fn harness_repair_decision(user_message: &str, next_action: &str) -> Decision {
56
+ Decision::new(
57
+ "harness_repair_unbaselined",
58
+ true,
59
+ user_message,
60
+ vec![
61
+ "commit_upgrade_baseline",
62
+ "review_diff_first",
63
+ "cancel_upgrade_baseline",
64
+ ],
65
+ next_action,
66
+ )
67
+ }
@@ -0,0 +1,36 @@
1
+ use std::fs;
2
+ use std::path::Path;
3
+
4
+ use serde_json::Value;
5
+
6
+ use crate::models::NaomeError;
7
+
8
+ pub(super) fn read_json(root: &Path, relative_path: &str) -> Result<Value, NaomeError> {
9
+ let content = fs::read_to_string(root.join(relative_path))?;
10
+ Ok(serde_json::from_str(&content)?)
11
+ }
12
+
13
+ pub(super) fn json_bool(value: &Value, key: &str) -> Option<bool> {
14
+ value.get(key).and_then(Value::as_bool)
15
+ }
16
+
17
+ pub(super) fn json_string(value: &Value, key: &str) -> Option<String> {
18
+ value
19
+ .get(key)
20
+ .and_then(Value::as_str)
21
+ .map(ToString::to_string)
22
+ }
23
+
24
+ pub(super) fn string_array_at(value: &Value, key: &str) -> Vec<String> {
25
+ value
26
+ .get(key)
27
+ .and_then(Value::as_array)
28
+ .map(|values| {
29
+ values
30
+ .iter()
31
+ .filter_map(Value::as_str)
32
+ .map(ToString::to_string)
33
+ .collect()
34
+ })
35
+ .unwrap_or_default()
36
+ }
@@ -0,0 +1,165 @@
1
+ use std::path::Path;
2
+
3
+ use serde_json::Value;
4
+
5
+ use crate::models::{Decision, NaomeError, TaskDecision};
6
+ use crate::paths;
7
+ use crate::task_state::harness_refresh_diff;
8
+
9
+ use super::idle::idle_diff_decision;
10
+ use super::json::{json_string, read_json, string_array_at};
11
+
12
+ pub(super) fn completed_task_decision(
13
+ root: &Path,
14
+ changed_paths: Vec<String>,
15
+ task: Option<&TaskDecision>,
16
+ ) -> Result<Decision, NaomeError> {
17
+ let mut decision = if changed_paths.is_empty() {
18
+ Decision::new(
19
+ "ready_for_task",
20
+ false,
21
+ "The last completed NAOME task has no open diff.",
22
+ vec!["create_task"],
23
+ "Task admission is clear; create the next task before feature work.",
24
+ )
25
+ } else if has_completed_task_owned_paths(task, &changed_paths) {
26
+ Decision::new(
27
+ "completed_task_unbaselined",
28
+ true,
29
+ "A completed NAOME task is verified and waiting for the next routing decision.",
30
+ vec![
31
+ "commit_task_baseline",
32
+ "review_task_diff",
33
+ "request_task_changes",
34
+ "cancel_task_changes",
35
+ ],
36
+ "Run NAOME intent for the next natural-language request; deterministic policy can baseline a valid completed task automatically.",
37
+ )
38
+ } else if harness_refresh_diff(root)?.is_some_and(|diff| diff.unrelated_paths.is_empty()) {
39
+ Decision::new(
40
+ "harness_repair_unbaselined",
41
+ true,
42
+ "Machine-owned NAOME harness refresh files changed outside an active task.",
43
+ vec![
44
+ "commit_upgrade_baseline",
45
+ "review_diff_first",
46
+ "cancel_upgrade_baseline",
47
+ ],
48
+ "Run NAOME intent for the next natural-language request; deterministic policy can baseline a pure harness refresh automatically.",
49
+ )
50
+ } else {
51
+ Decision::new(
52
+ "dirty_unowned_diff",
53
+ true,
54
+ "The completed NAOME task has been baselined, but unrelated user changes remain.",
55
+ vec!["review_unowned_diff"],
56
+ "Review the unrelated diff, or route a new task so NAOME can isolate task work without touching it.",
57
+ )
58
+ };
59
+
60
+ decision.changed_paths = changed_paths;
61
+ decision.required_context = vec![
62
+ "docs/naome/execution.md".to_string(),
63
+ ".naome/task-state.json".to_string(),
64
+ "docs/naome/agent-workflow.md".to_string(),
65
+ "docs/naome/testing.md".to_string(),
66
+ ];
67
+ Ok(decision)
68
+ }
69
+
70
+ pub(super) fn active_task_decision(
71
+ changed_paths: Vec<String>,
72
+ task: Option<&TaskDecision>,
73
+ ) -> Decision {
74
+ let allowed_paths = task
75
+ .map(|task| task.allowed_paths.clone())
76
+ .unwrap_or_default();
77
+ let out_of_scope: Vec<String> = changed_paths
78
+ .iter()
79
+ .filter(|path| !is_control_state_path(path) && !paths::matches_any(path, &allowed_paths))
80
+ .cloned()
81
+ .collect();
82
+
83
+ let mut decision = if out_of_scope.is_empty() {
84
+ Decision::new(
85
+ "active_task_in_progress",
86
+ false,
87
+ "A NAOME task is active and the current diff is inside its declared scope.",
88
+ vec!["continue_task", "request_task_changes", "complete_task"],
89
+ "Continue the active task and keep proof current.",
90
+ )
91
+ } else {
92
+ Decision::new(
93
+ "active_task_blocked",
94
+ true,
95
+ "A NAOME task is active, but the current diff includes paths outside its declared scope.",
96
+ vec![
97
+ "revise_task_scope",
98
+ "revert_out_of_scope_diff",
99
+ "request_human_review",
100
+ ],
101
+ "Resolve out-of-scope changes before completing this task.",
102
+ )
103
+ };
104
+ decision.changed_paths = if out_of_scope.is_empty() {
105
+ changed_paths
106
+ } else {
107
+ out_of_scope
108
+ };
109
+ decision.required_context = vec![
110
+ "docs/naome/execution.md".to_string(),
111
+ ".naome/task-state.json".to_string(),
112
+ "docs/naome/testing.md".to_string(),
113
+ ];
114
+ decision
115
+ }
116
+
117
+ pub(super) fn classify_idle_diff(
118
+ root: &Path,
119
+ changed_paths: Vec<String>,
120
+ ) -> Result<Decision, NaomeError> {
121
+ let manifest = read_json(root, ".naome/manifest.json").unwrap_or(Value::Null);
122
+ let machine_owned = string_array_at(&manifest, "machineOwned");
123
+ let project_owned = string_array_at(&manifest, "projectOwned");
124
+
125
+ let mut known_harness_paths = machine_owned.clone();
126
+ known_harness_paths.extend(project_owned);
127
+ let mut decision =
128
+ idle_diff_decision(root, &changed_paths, &machine_owned, &known_harness_paths)?;
129
+
130
+ decision.changed_paths = changed_paths;
131
+ decision.required_context = vec![
132
+ "docs/naome/execution.md".to_string(),
133
+ ".naome/task-state.json".to_string(),
134
+ ];
135
+ Ok(decision)
136
+ }
137
+
138
+ pub(super) fn task_decision(task_state: &Value, status: &str) -> Option<TaskDecision> {
139
+ let active_task = task_state.get("activeTask")?;
140
+ if active_task.is_null() {
141
+ return None;
142
+ }
143
+
144
+ Some(TaskDecision {
145
+ id: json_string(active_task, "id"),
146
+ status: status.to_string(),
147
+ request: json_string(active_task, "request"),
148
+ allowed_paths: string_array_at(active_task, "allowedPaths"),
149
+ required_check_ids: string_array_at(active_task, "requiredCheckIds"),
150
+ })
151
+ }
152
+
153
+ fn has_completed_task_owned_paths(task: Option<&TaskDecision>, changed_paths: &[String]) -> bool {
154
+ let Some(task) = task else {
155
+ return false;
156
+ };
157
+
158
+ changed_paths
159
+ .iter()
160
+ .any(|path| is_control_state_path(path) || paths::matches_any(path, &task.allowed_paths))
161
+ }
162
+
163
+ fn is_control_state_path(path: &str) -> bool {
164
+ path == ".naome/task-state.json"
165
+ }