@lamentis/naome 1.1.2 → 1.2.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.
Files changed (204) hide show
  1. package/Cargo.lock +2 -2
  2. package/Cargo.toml +1 -1
  3. package/LICENSE +180 -21
  4. package/README.md +49 -6
  5. package/bin/naome-node.js +2 -1579
  6. package/bin/naome.js +68 -16
  7. package/crates/naome-cli/Cargo.toml +1 -1
  8. package/crates/naome-cli/src/check_commands.rs +135 -0
  9. package/crates/naome-cli/src/cli_args.rs +5 -0
  10. package/crates/naome-cli/src/dispatcher.rs +37 -0
  11. package/crates/naome-cli/src/install_bridge.rs +83 -0
  12. package/crates/naome-cli/src/main.rs +60 -341
  13. package/crates/naome-cli/src/prompt_commands.rs +68 -0
  14. package/crates/naome-cli/src/quality_commands.rs +229 -0
  15. package/crates/naome-cli/src/simple_commands.rs +53 -0
  16. package/crates/naome-cli/src/workflow_commands.rs +153 -0
  17. package/crates/naome-core/Cargo.toml +1 -1
  18. package/crates/naome-core/src/decision/checks.rs +64 -0
  19. package/crates/naome-core/src/decision/idle.rs +67 -0
  20. package/crates/naome-core/src/decision/json.rs +36 -0
  21. package/crates/naome-core/src/decision/states.rs +165 -0
  22. package/crates/naome-core/src/decision.rs +131 -353
  23. package/crates/naome-core/src/harness_health/integrity.rs +96 -0
  24. package/crates/naome-core/src/harness_health.rs +14 -126
  25. package/crates/naome-core/src/install_plan.rs +5 -0
  26. package/crates/naome-core/src/intent/classifier.rs +171 -0
  27. package/crates/naome-core/src/intent/envelope.rs +108 -0
  28. package/crates/naome-core/src/intent/legacy.rs +138 -0
  29. package/crates/naome-core/src/intent/legacy_response.rs +76 -0
  30. package/crates/naome-core/src/intent/model.rs +71 -0
  31. package/crates/naome-core/src/intent/patterns.rs +170 -0
  32. package/crates/naome-core/src/intent/resolver.rs +162 -0
  33. package/crates/naome-core/src/intent/resolver_active.rs +17 -0
  34. package/crates/naome-core/src/intent/resolver_baseline.rs +55 -0
  35. package/crates/naome-core/src/intent/resolver_catalog.rs +167 -0
  36. package/crates/naome-core/src/intent/resolver_policy.rs +72 -0
  37. package/crates/naome-core/src/intent/resolver_shared.rs +55 -0
  38. package/crates/naome-core/src/intent/risk.rs +40 -0
  39. package/crates/naome-core/src/intent/segment.rs +170 -0
  40. package/crates/naome-core/src/intent.rs +64 -879
  41. package/crates/naome-core/src/journal.rs +9 -20
  42. package/crates/naome-core/src/lib.rs +15 -0
  43. package/crates/naome-core/src/paths.rs +3 -1
  44. package/crates/naome-core/src/quality/adapter_support.rs +89 -0
  45. package/crates/naome-core/src/quality/adapters.rs +131 -0
  46. package/crates/naome-core/src/quality/baseline.rs +75 -0
  47. package/crates/naome-core/src/quality/checks/duplicate_blocks.rs +175 -0
  48. package/crates/naome-core/src/quality/checks/near_duplicates.rs +130 -0
  49. package/crates/naome-core/src/quality/checks.rs +228 -0
  50. package/crates/naome-core/src/quality/cleanup.rs +84 -0
  51. package/crates/naome-core/src/quality/config.rs +102 -0
  52. package/crates/naome-core/src/quality/config_support.rs +24 -0
  53. package/crates/naome-core/src/quality/mod.rs +108 -0
  54. package/crates/naome-core/src/quality/scanner/repo_paths.rs +103 -0
  55. package/crates/naome-core/src/quality/scanner.rs +379 -0
  56. package/crates/naome-core/src/quality/structure/adapters.rs +84 -0
  57. package/crates/naome-core/src/quality/structure/checks/basic.rs +153 -0
  58. package/crates/naome-core/src/quality/structure/checks/directory.rs +144 -0
  59. package/crates/naome-core/src/quality/structure/checks/pairing.rs +63 -0
  60. package/crates/naome-core/src/quality/structure/checks.rs +124 -0
  61. package/crates/naome-core/src/quality/structure/classify/roles.rs +188 -0
  62. package/crates/naome-core/src/quality/structure/classify.rs +94 -0
  63. package/crates/naome-core/src/quality/structure/config.rs +89 -0
  64. package/crates/naome-core/src/quality/structure/defaults.rs +107 -0
  65. package/crates/naome-core/src/quality/structure/mod.rs +77 -0
  66. package/crates/naome-core/src/quality/structure/model.rs +124 -0
  67. package/crates/naome-core/src/quality/types.rs +292 -0
  68. package/crates/naome-core/src/route/builtin_checks.rs +155 -0
  69. package/crates/naome-core/src/route/builtin_context.rs +73 -0
  70. package/crates/naome-core/src/route/builtin_integrity.rs +49 -0
  71. package/crates/naome-core/src/route/builtin_require.rs +40 -0
  72. package/crates/naome-core/src/route/context.rs +180 -0
  73. package/crates/naome-core/src/route/execution.rs +96 -0
  74. package/crates/naome-core/src/route/execution_baselines.rs +146 -0
  75. package/crates/naome-core/src/route/execution_support.rs +57 -0
  76. package/crates/naome-core/src/route/execution_tasks.rs +71 -0
  77. package/crates/naome-core/src/route/git_ops.rs +72 -0
  78. package/crates/naome-core/src/route/quality_gate.rs +73 -0
  79. package/crates/naome-core/src/route/quality_gate_config.rs +126 -0
  80. package/crates/naome-core/src/route/quality_gate_snapshot.rs +69 -0
  81. package/crates/naome-core/src/route/worktree.rs +75 -0
  82. package/crates/naome-core/src/route/worktree_files.rs +32 -0
  83. package/crates/naome-core/src/route/worktree_plan.rs +131 -0
  84. package/crates/naome-core/src/route.rs +44 -1155
  85. package/crates/naome-core/src/task_state/admission.rs +63 -0
  86. package/crates/naome-core/src/task_state/admission_proof.rs +72 -0
  87. package/crates/naome-core/src/task_state/api.rs +130 -0
  88. package/crates/naome-core/src/task_state/commit_gate.rs +138 -0
  89. package/crates/naome-core/src/task_state/compact_proof.rs +160 -0
  90. package/crates/naome-core/src/task_state/completed_refresh.rs +89 -0
  91. package/crates/naome-core/src/task_state/completion.rs +72 -0
  92. package/crates/naome-core/src/task_state/deleted_paths.rs +47 -0
  93. package/crates/naome-core/src/task_state/diff.rs +95 -0
  94. package/crates/naome-core/src/task_state/evidence.rs +154 -0
  95. package/crates/naome-core/src/task_state/git_io.rs +86 -0
  96. package/crates/naome-core/src/task_state/git_parse.rs +86 -0
  97. package/crates/naome-core/src/task_state/git_refs.rs +37 -0
  98. package/crates/naome-core/src/task_state/human_review_state.rs +31 -0
  99. package/crates/naome-core/src/task_state/mod.rs +38 -0
  100. package/crates/naome-core/src/task_state/process_guard.rs +40 -0
  101. package/crates/naome-core/src/task_state/progress.rs +123 -0
  102. package/crates/naome-core/src/task_state/proof.rs +139 -0
  103. package/crates/naome-core/src/task_state/proof_entry.rs +66 -0
  104. package/crates/naome-core/src/task_state/proof_model.rs +70 -0
  105. package/crates/naome-core/src/task_state/proof_sources.rs +76 -0
  106. package/crates/naome-core/src/task_state/push_gate.rs +49 -0
  107. package/crates/naome-core/src/task_state/reconcile.rs +7 -0
  108. package/crates/naome-core/src/task_state/repair.rs +168 -0
  109. package/crates/naome-core/src/task_state/shape.rs +117 -0
  110. package/crates/naome-core/src/task_state/task_diff_api.rs +170 -0
  111. package/crates/naome-core/src/task_state/task_records.rs +131 -0
  112. package/crates/naome-core/src/task_state/task_references.rs +126 -0
  113. package/crates/naome-core/src/task_state/types.rs +87 -0
  114. package/crates/naome-core/src/task_state/util.rs +137 -0
  115. package/crates/naome-core/src/verification/render.rs +122 -0
  116. package/crates/naome-core/src/verification.rs +177 -58
  117. package/crates/naome-core/src/verification_contract.rs +49 -21
  118. package/crates/naome-core/src/workflow/integrity.rs +123 -0
  119. package/crates/naome-core/src/workflow/integrity_normalize.rs +7 -0
  120. package/crates/naome-core/src/workflow/integrity_support.rs +110 -0
  121. package/crates/naome-core/src/workflow/mod.rs +18 -0
  122. package/crates/naome-core/src/workflow/mutation.rs +68 -0
  123. package/crates/naome-core/src/workflow/output.rs +111 -0
  124. package/crates/naome-core/src/workflow/phase_inference.rs +73 -0
  125. package/crates/naome-core/src/workflow/phases.rs +169 -0
  126. package/crates/naome-core/src/workflow/policy.rs +156 -0
  127. package/crates/naome-core/src/workflow/processes.rs +91 -0
  128. package/crates/naome-core/src/workflow/types.rs +42 -0
  129. package/crates/naome-core/tests/decision.rs +24 -118
  130. package/crates/naome-core/tests/harness_health.rs +5 -0
  131. package/crates/naome-core/tests/intent.rs +97 -792
  132. package/crates/naome-core/tests/intent_support/mod.rs +133 -0
  133. package/crates/naome-core/tests/intent_v2.rs +90 -0
  134. package/crates/naome-core/tests/quality.rs +319 -0
  135. package/crates/naome-core/tests/quality_structure.rs +116 -0
  136. package/crates/naome-core/tests/quality_structure_adapters.rs +98 -0
  137. package/crates/naome-core/tests/quality_structure_policy.rs +125 -0
  138. package/crates/naome-core/tests/quality_structure_support/mod.rs +249 -0
  139. package/crates/naome-core/tests/repo_support/mod.rs +16 -0
  140. package/crates/naome-core/tests/repo_support/repo.rs +113 -0
  141. package/crates/naome-core/tests/repo_support/repo_factories.rs +99 -0
  142. package/crates/naome-core/tests/repo_support/repo_helpers.rs +123 -0
  143. package/crates/naome-core/tests/repo_support/routes.rs +81 -0
  144. package/crates/naome-core/tests/repo_support/verification.rs +168 -0
  145. package/crates/naome-core/tests/repo_support/verification_values.rs +135 -0
  146. package/crates/naome-core/tests/route.rs +1 -1476
  147. package/crates/naome-core/tests/route_baseline.rs +86 -0
  148. package/crates/naome-core/tests/route_completion.rs +141 -0
  149. package/crates/naome-core/tests/route_harness_refresh.rs +135 -0
  150. package/crates/naome-core/tests/route_user_diff.rs +198 -0
  151. package/crates/naome-core/tests/route_worktree.rs +54 -0
  152. package/crates/naome-core/tests/task_state.rs +60 -429
  153. package/crates/naome-core/tests/task_state_compact.rs +110 -0
  154. package/crates/naome-core/tests/task_state_compact_support/mod.rs +5 -0
  155. package/crates/naome-core/tests/task_state_compact_support/repo.rs +130 -0
  156. package/crates/naome-core/tests/task_state_compact_support/states.rs +151 -0
  157. package/crates/naome-core/tests/task_state_support/mod.rs +163 -0
  158. package/crates/naome-core/tests/task_state_support/states.rs +84 -0
  159. package/crates/naome-core/tests/verification.rs +4 -45
  160. package/crates/naome-core/tests/verification_contract.rs +22 -78
  161. package/crates/naome-core/tests/workflow_integrity.rs +85 -0
  162. package/crates/naome-core/tests/workflow_policy.rs +139 -0
  163. package/crates/naome-core/tests/workflow_support/mod.rs +194 -0
  164. package/installer/agents.js +90 -0
  165. package/installer/context.js +67 -0
  166. package/installer/filesystem.js +166 -0
  167. package/installer/flows.js +84 -0
  168. package/installer/git-boundary.js +170 -0
  169. package/installer/git-hook-content.js +36 -0
  170. package/installer/git-hooks.js +134 -0
  171. package/installer/git-local.js +2 -0
  172. package/installer/git-shared.js +35 -0
  173. package/installer/harness-file-ops.js +140 -0
  174. package/installer/harness-files.js +56 -0
  175. package/installer/harness-verification.js +123 -0
  176. package/installer/install-plan.js +66 -0
  177. package/installer/main.js +25 -0
  178. package/installer/manifest-state.js +167 -0
  179. package/installer/native-build.js +24 -0
  180. package/installer/native-format.js +6 -0
  181. package/installer/native.js +162 -0
  182. package/installer/output.js +131 -0
  183. package/installer/version.js +32 -0
  184. package/native/darwin-arm64/naome +0 -0
  185. package/native/linux-x64/naome +0 -0
  186. package/package.json +3 -2
  187. package/templates/naome-root/.naome/bin/check-harness-health.js +66 -85
  188. package/templates/naome-root/.naome/bin/check-task-state.js +9 -10
  189. package/templates/naome-root/.naome/bin/naome.js +51 -76
  190. package/templates/naome-root/.naome/manifest.json +22 -18
  191. package/templates/naome-root/.naome/repository-quality-baseline.json +5 -0
  192. package/templates/naome-root/.naome/repository-quality.json +24 -0
  193. package/templates/naome-root/.naome/repository-structure.json +90 -0
  194. package/templates/naome-root/.naome/task-contract.schema.json +93 -11
  195. package/templates/naome-root/.naome/upgrade-state.json +1 -1
  196. package/templates/naome-root/.naome/verification.json +38 -0
  197. package/templates/naome-root/AGENTS.md +3 -0
  198. package/templates/naome-root/docs/naome/agent-workflow.md +25 -12
  199. package/templates/naome-root/docs/naome/execution.md +25 -21
  200. package/templates/naome-root/docs/naome/index.md +5 -3
  201. package/templates/naome-root/docs/naome/repository-quality.md +46 -0
  202. package/templates/naome-root/docs/naome/repository-structure.md +51 -0
  203. package/templates/naome-root/docs/naome/testing.md +13 -0
  204. package/crates/naome-core/src/task_state.rs +0 -2210
@@ -0,0 +1,229 @@
1
+ use std::path::Path;
2
+
3
+ use naome_core::{
4
+ check_repository_quality, explain_repository_structure, init_repository_quality,
5
+ plan_quality_cleanup, route_quality_cleanup, QualityMode,
6
+ };
7
+
8
+ use crate::cli_args::option_value;
9
+
10
+ pub fn run_quality_command(root: &Path, args: &[String]) -> Result<(), Box<dyn std::error::Error>> {
11
+ let Some(subcommand) = args.get(1).map(String::as_str) else {
12
+ return Err("naome quality requires init, check, or report.".into());
13
+ };
14
+ let json = args.iter().any(|arg| arg == "--json");
15
+
16
+ match subcommand {
17
+ "init" => {
18
+ let result = init_repository_quality(root)?;
19
+ if json {
20
+ println!("{}", serde_json::to_string_pretty(&result)?);
21
+ } else {
22
+ println!("NAOME repository quality initialized.");
23
+ println!("Baseline violations: {}", result.baseline_violations);
24
+ }
25
+ }
26
+ "check" => run_quality_check(root, args, json)?,
27
+ "report" => run_quality_report(root, json)?,
28
+ _ => return Err(format!("unknown naome quality command: {subcommand}").into()),
29
+ }
30
+ Ok(())
31
+ }
32
+
33
+ pub fn run_cleanup_command(root: &Path, args: &[String]) -> Result<(), Box<dyn std::error::Error>> {
34
+ let Some(subcommand) = args.get(1).map(String::as_str) else {
35
+ return Err("naome cleanup requires plan or route.".into());
36
+ };
37
+ let json = args.iter().any(|arg| arg == "--json");
38
+
39
+ match subcommand {
40
+ "plan" => run_cleanup_plan(root, json)?,
41
+ "route" => run_cleanup_route(root, args, json)?,
42
+ _ => return Err(format!("unknown naome cleanup command: {subcommand}").into()),
43
+ }
44
+ Ok(())
45
+ }
46
+
47
+ pub fn run_structure_command(
48
+ root: &Path,
49
+ args: &[String],
50
+ ) -> Result<(), Box<dyn std::error::Error>> {
51
+ let Some(subcommand) = args.get(1).map(String::as_str) else {
52
+ return Err("naome structure requires report or explain.".into());
53
+ };
54
+ let json = args.iter().any(|arg| arg == "--json");
55
+
56
+ match subcommand {
57
+ "report" => run_structure_report(root, json)?,
58
+ "explain" => run_structure_explain(root, args, json)?,
59
+ _ => return Err(format!("unknown naome structure command: {subcommand}").into()),
60
+ }
61
+ Ok(())
62
+ }
63
+
64
+ fn run_quality_check(
65
+ root: &Path,
66
+ args: &[String],
67
+ json: bool,
68
+ ) -> Result<(), Box<dyn std::error::Error>> {
69
+ if !args.iter().any(|arg| arg == "--changed") {
70
+ return Err("naome quality check requires --changed.".into());
71
+ }
72
+ let report = check_repository_quality(root, QualityMode::Changed)?;
73
+ if json {
74
+ println!("{}", serde_json::to_string_pretty(&report)?);
75
+ } else if report.ok {
76
+ println!("NAOME repository quality OK.");
77
+ } else {
78
+ eprintln!(
79
+ "NAOME repository quality failed with {} violation(s).",
80
+ report.violations.len()
81
+ );
82
+ for violation in report.violations.iter().take(20) {
83
+ print_quality_violation(violation);
84
+ }
85
+ }
86
+ if !report.ok {
87
+ std::process::exit(1);
88
+ }
89
+ Ok(())
90
+ }
91
+
92
+ fn run_quality_report(root: &Path, json: bool) -> Result<(), Box<dyn std::error::Error>> {
93
+ let report = check_repository_quality(root, QualityMode::Report)?;
94
+ if json {
95
+ println!("{}", serde_json::to_string_pretty(&report)?);
96
+ } else if report.violations.is_empty() {
97
+ println!("NAOME repository quality report: no debt found.");
98
+ } else {
99
+ println!(
100
+ "NAOME repository quality report: {} violation(s) across {} scanned file(s).",
101
+ report.violations.len(),
102
+ report.summary.scanned_files
103
+ );
104
+ for violation in report.violations.iter().take(20) {
105
+ print_quality_violation(violation);
106
+ }
107
+ }
108
+ Ok(())
109
+ }
110
+
111
+ fn run_cleanup_plan(root: &Path, json: bool) -> Result<(), Box<dyn std::error::Error>> {
112
+ let plan = plan_quality_cleanup(root)?;
113
+ if json {
114
+ println!("{}", serde_json::to_string_pretty(&plan)?);
115
+ } else if plan.tasks.is_empty() {
116
+ println!("NAOME cleanup plan: no repository-quality debt found.");
117
+ } else {
118
+ println!("NAOME cleanup plan:");
119
+ for task in plan.tasks.iter().take(20) {
120
+ println!(
121
+ "- {}: {} violation(s) [{}]",
122
+ task.path,
123
+ task.violation_count,
124
+ task.check_ids.join(", ")
125
+ );
126
+ }
127
+ }
128
+ Ok(())
129
+ }
130
+
131
+ fn run_cleanup_route(
132
+ root: &Path,
133
+ args: &[String],
134
+ json: bool,
135
+ ) -> Result<(), Box<dyn std::error::Error>> {
136
+ let Some(path) = option_value(args, "--path") else {
137
+ return Err("naome cleanup route requires --path <path>.".into());
138
+ };
139
+ let route = route_quality_cleanup(root, path)?;
140
+ if json {
141
+ println!("{}", serde_json::to_string_pretty(&route)?);
142
+ } else {
143
+ println!("NAOME cleanup route for {}", route.path);
144
+ println!("{}", route.agent_instructions);
145
+ if !route.related_paths.is_empty() {
146
+ println!("Related paths: {}", route.related_paths.join(", "));
147
+ }
148
+ }
149
+ Ok(())
150
+ }
151
+
152
+ fn run_structure_report(root: &Path, json: bool) -> Result<(), Box<dyn std::error::Error>> {
153
+ let mut report = check_repository_quality(root, QualityMode::Report)?;
154
+ report
155
+ .violations
156
+ .retain(|violation| is_structure_check(&violation.check_id));
157
+ report.summary.violation_count = report.violations.len();
158
+ report.summary.blocking_violation_count = report.violations.len();
159
+ report.summary.baseline_violation_count = report
160
+ .violations
161
+ .iter()
162
+ .filter(|violation| violation.baseline)
163
+ .count();
164
+ report.ok = report.violations.is_empty();
165
+ report.schema = "naome.repository-structure-report.v1".to_string();
166
+
167
+ if json {
168
+ println!("{}", serde_json::to_string_pretty(&report)?);
169
+ } else if report.violations.is_empty() {
170
+ println!("NAOME repository structure report: no debt found.");
171
+ } else {
172
+ println!(
173
+ "NAOME repository structure report: {} violation(s).",
174
+ report.violations.len()
175
+ );
176
+ for violation in report.violations.iter().take(20) {
177
+ print_quality_violation(violation);
178
+ }
179
+ }
180
+ Ok(())
181
+ }
182
+
183
+ fn run_structure_explain(
184
+ root: &Path,
185
+ args: &[String],
186
+ json: bool,
187
+ ) -> Result<(), Box<dyn std::error::Error>> {
188
+ let Some(path) = option_value(args, "--path") else {
189
+ return Err("naome structure explain requires --path <path>.".into());
190
+ };
191
+ let explanation = explain_repository_structure(root, path)?;
192
+ if json {
193
+ println!("{}", serde_json::to_string_pretty(&explanation)?);
194
+ } else {
195
+ println!(
196
+ "{} role={} layer={} directory={}",
197
+ explanation.path, explanation.role, explanation.layer, explanation.directory
198
+ );
199
+ if let Some(language) = explanation.language {
200
+ println!("language={language}");
201
+ }
202
+ if let Some(module) = explanation.module {
203
+ println!("module={module}");
204
+ }
205
+ }
206
+ Ok(())
207
+ }
208
+
209
+ fn is_structure_check(check_id: &str) -> bool {
210
+ matches!(
211
+ check_id,
212
+ "directory-role-mixing"
213
+ | "misplaced-file-role"
214
+ | "root-file-sprawl"
215
+ | "dumping-ground-directory"
216
+ | "directory-size"
217
+ | "path-depth"
218
+ | "case-collision"
219
+ | "test-source-pairing"
220
+ )
221
+ }
222
+
223
+ fn print_quality_violation(violation: &naome_core::QualityViolation) {
224
+ let location = violation
225
+ .line
226
+ .map(|line| format!("{}:{line}", violation.path))
227
+ .unwrap_or_else(|| violation.path.clone());
228
+ eprintln!("- {location} {}: {}", violation.check_id, violation.message);
229
+ }
@@ -0,0 +1,53 @@
1
+ use std::path::Path;
2
+
3
+ use naome_core::{install_plan, seed_builtin_verification_checks};
4
+
5
+ use crate::cli_args::option_value;
6
+
7
+ pub fn print_install_plan(args: &[String]) -> Result<(), Box<dyn std::error::Error>> {
8
+ let harness_version = option_value(args, "--harness-version")
9
+ .or_else(|| option_value(args, "--version"))
10
+ .unwrap_or_else(|| env!("CARGO_PKG_VERSION").to_string());
11
+ println!(
12
+ "{}",
13
+ serde_json::to_string_pretty(&install_plan(harness_version))?
14
+ );
15
+ Ok(())
16
+ }
17
+
18
+ pub fn seed_verification(root: &Path) -> Result<(), Box<dyn std::error::Error>> {
19
+ if seed_builtin_verification_checks(root)? {
20
+ println!("NAOME verification checks updated.");
21
+ } else {
22
+ println!("NAOME verification checks already present.");
23
+ }
24
+ Ok(())
25
+ }
26
+
27
+ pub fn run_journal_task(root: &Path, args: &[String]) -> Result<(), Box<dyn std::error::Error>> {
28
+ let outcome =
29
+ option_value(args, "--outcome").unwrap_or_else(|| "naome_commit_baseline".to_string());
30
+ let commit_before = option_value(args, "--commit-before");
31
+ let commit_after = option_value(args, "--commit-after");
32
+ let entry = naome_core::append_task_journal(root, &outcome, commit_before, commit_after)?;
33
+ if args.iter().any(|arg| arg == "--json") {
34
+ println!("{}", serde_json::to_string_pretty(&entry)?);
35
+ } else if entry.is_some() {
36
+ println!("NAOME task journal updated.");
37
+ } else {
38
+ println!("NAOME task journal had no active task to record.");
39
+ }
40
+ Ok(())
41
+ }
42
+
43
+ pub fn run_commit_paths(root: &Path, args: &[String]) -> Result<(), Box<dyn std::error::Error>> {
44
+ let paths = naome_core::completed_task_commit_paths(root)?;
45
+ if args.iter().any(|arg| arg == "--json") {
46
+ println!("{}", serde_json::to_string_pretty(&paths)?);
47
+ } else {
48
+ for path in paths {
49
+ println!("{path}");
50
+ }
51
+ }
52
+ Ok(())
53
+ }
@@ -0,0 +1,153 @@
1
+ use std::path::Path;
2
+
3
+ use naome_core::{
4
+ classify_mutations, refresh_integrity, safe_rg_args, tracked_process_report,
5
+ validate_search_command, verification_phase_plan,
6
+ };
7
+
8
+ use crate::cli_args::option_value;
9
+
10
+ pub fn run_refresh_integrity(
11
+ root: &Path,
12
+ args: &[String],
13
+ ) -> Result<(), Box<dyn std::error::Error>> {
14
+ let report = refresh_integrity(root)?;
15
+ if args.iter().any(|arg| arg == "--json") {
16
+ println!("{}", serde_json::to_string_pretty(&report)?);
17
+ } else if report.updated {
18
+ println!(
19
+ "NAOME integrity refreshed: {}.",
20
+ report.changed_paths.join(", ")
21
+ );
22
+ } else {
23
+ println!("NAOME integrity already current.");
24
+ }
25
+ Ok(())
26
+ }
27
+
28
+ pub fn run_workflow_command(
29
+ root: &Path,
30
+ args: &[String],
31
+ ) -> Result<(), Box<dyn std::error::Error>> {
32
+ let Some(subcommand) = args.get(1).map(String::as_str) else {
33
+ return Err("naome workflow requires search-profile, check-search, phases, processes, or mutations.".into());
34
+ };
35
+ let json = args.iter().any(|arg| arg == "--json");
36
+
37
+ match subcommand {
38
+ "search-profile" => {
39
+ let args = safe_rg_args(root)?;
40
+ if json {
41
+ println!("{}", serde_json::to_string_pretty(&args)?);
42
+ } else {
43
+ println!(
44
+ "{}",
45
+ args.iter()
46
+ .map(|arg| shell_quote(arg))
47
+ .collect::<Vec<_>>()
48
+ .join(" ")
49
+ );
50
+ }
51
+ }
52
+ "check-search" => run_check_search(root, args, json)?,
53
+ "phases" => {
54
+ let plan = verification_phase_plan(root, &[])?;
55
+ if json {
56
+ println!("{}", serde_json::to_string_pretty(&plan)?);
57
+ } else {
58
+ println!(
59
+ "Recommended checks: {}",
60
+ empty_label(&plan.recommended_check_ids)
61
+ );
62
+ if !plan.withheld_check_ids.is_empty() {
63
+ println!("Withheld checks: {}", plan.withheld_check_ids.join(", "));
64
+ }
65
+ }
66
+ }
67
+ "processes" => {
68
+ let report = tracked_process_report(root)?;
69
+ if json {
70
+ println!("{}", serde_json::to_string_pretty(&report)?);
71
+ } else if report.active.is_empty() {
72
+ println!("NAOME tracked processes OK.");
73
+ } else {
74
+ println!("Active tracked processes:");
75
+ for process in report.active {
76
+ println!("- {} [{}]", process.command, process.cwd);
77
+ }
78
+ }
79
+ }
80
+ "mutations" => run_mutations(root, args, json)?,
81
+ _ => return Err(format!("unknown naome workflow command: {subcommand}").into()),
82
+ }
83
+ Ok(())
84
+ }
85
+
86
+ fn run_check_search(
87
+ root: &Path,
88
+ args: &[String],
89
+ json: bool,
90
+ ) -> Result<(), Box<dyn std::error::Error>> {
91
+ let Some(command) = option_value(args, "--command") else {
92
+ return Err("naome workflow check-search requires --command <command>.".into());
93
+ };
94
+ let findings = validate_search_command(root, &command)?;
95
+ if !json && findings.is_empty() {
96
+ println!("NAOME search command OK.");
97
+ }
98
+ if json {
99
+ println!("{}", serde_json::to_string_pretty(&findings)?);
100
+ } else {
101
+ for finding in &findings {
102
+ println!("- {}: {}", finding.check_id, finding.message);
103
+ }
104
+ }
105
+ if !findings.is_empty() {
106
+ std::process::exit(1);
107
+ }
108
+ Ok(())
109
+ }
110
+
111
+ fn run_mutations(
112
+ root: &Path,
113
+ args: &[String],
114
+ json: bool,
115
+ ) -> Result<(), Box<dyn std::error::Error>> {
116
+ let paths = args
117
+ .iter()
118
+ .skip_while(|arg| arg.as_str() != "--path")
119
+ .skip(1)
120
+ .filter(|arg| !arg.starts_with("--"))
121
+ .cloned()
122
+ .collect::<Vec<_>>();
123
+ if paths.is_empty() {
124
+ return Err("naome workflow mutations requires --path <path> [path...]".into());
125
+ }
126
+ let classes = classify_mutations(root, &paths)?;
127
+ if json {
128
+ println!("{}", serde_json::to_string_pretty(&classes)?);
129
+ } else {
130
+ for entry in classes {
131
+ println!("{}: {}", entry.path, entry.mutation_class);
132
+ }
133
+ }
134
+ Ok(())
135
+ }
136
+
137
+ fn empty_label(values: &[String]) -> String {
138
+ if values.is_empty() {
139
+ "none".to_string()
140
+ } else {
141
+ values.join(", ")
142
+ }
143
+ }
144
+
145
+ fn shell_quote(value: &str) -> String {
146
+ if value
147
+ .chars()
148
+ .all(|ch| ch.is_ascii_alphanumeric() || matches!(ch, '-' | '_' | '.' | '/' | ':'))
149
+ {
150
+ return value.to_string();
151
+ }
152
+ format!("'{}'", value.replace('\'', "'\\''"))
153
+ }
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "naome-core"
3
- version = "1.1.2"
3
+ version = "1.2.1"
4
4
  edition.workspace = true
5
5
  license.workspace = true
6
6
  repository.workspace = true
@@ -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
+ }
@@ -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
+ }