@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,155 @@
1
+ use std::path::Path;
2
+
3
+ use crate::harness_health::{validate_harness_health, HarnessHealthOptions};
4
+ use crate::models::NaomeError;
5
+ use crate::quality::{check_repository_quality, QualityMode};
6
+ use crate::route::git_ops::{command_output, git_output};
7
+ use crate::route::quality_gate::QualityCheck;
8
+ use crate::task_state::{validate_task_state, TaskStateMode, TaskStateOptions};
9
+ use crate::verification_contract::validate_verification_contract;
10
+
11
+ use super::builtin_context::{run_context_budget_check, template_root};
12
+ use super::builtin_integrity::packaged_harness_integrity;
13
+ use super::builtin_require::{require_builtin_quality_check, require_builtin_quality_check_any};
14
+
15
+ pub(super) fn run_quality_check(
16
+ root: &Path,
17
+ check_id: &str,
18
+ check: &QualityCheck,
19
+ ) -> Result<(), NaomeError> {
20
+ match check_id {
21
+ "installer-tests" => require_builtin_quality_check(
22
+ check_id,
23
+ check,
24
+ "npm run test:naome-installer",
25
+ ),
26
+ "rust-build" => require_builtin_quality_check(check_id, check, "npm run build:rust"),
27
+ "decision-engine-tests" => {
28
+ require_builtin_quality_check(check_id, check, "npm run test:decision-engine")
29
+ }
30
+ "package-dry-run" => require_builtin_quality_check(check_id, check, "npm run pack:dry-run"),
31
+ "diff-check" => {
32
+ require_builtin_quality_check(check_id, check, "git diff --check")?;
33
+ let output = git_output(root, &["diff", "--check"])?;
34
+
35
+ if output.status.success() {
36
+ Ok(())
37
+ } else {
38
+ Err(NaomeError::new(command_output(&output)))
39
+ }
40
+ }
41
+ "naome-harness-health" => {
42
+ require_builtin_quality_check(
43
+ check_id,
44
+ check,
45
+ "node .naome/bin/check-harness-health.js",
46
+ )?;
47
+ run_harness_health_check(root)
48
+ }
49
+ "dogfood-health" => {
50
+ require_builtin_quality_check(check_id, check, "npm run dogfood:health")?;
51
+ run_harness_health_check(root)
52
+ }
53
+ "task-state-check" => {
54
+ require_builtin_quality_check(check_id, check, "npm run check:task-state")?;
55
+ run_template_task_state_check(root)
56
+ }
57
+ "verification-contract-check" => {
58
+ require_builtin_quality_check(
59
+ check_id,
60
+ check,
61
+ "npm run check:verification-contract",
62
+ )?;
63
+ run_template_verification_contract_check(root)
64
+ }
65
+ "context-budget-check" => {
66
+ require_builtin_quality_check(check_id, check, "npm run check:context-budget")?;
67
+ run_context_budget_check(root)
68
+ }
69
+ "repository-quality-check" => {
70
+ require_builtin_quality_check_any(
71
+ check_id,
72
+ check,
73
+ &[
74
+ "naome quality check --changed",
75
+ "node .naome/bin/naome.js quality check --changed",
76
+ "npm run check:repository-quality",
77
+ ],
78
+ )?;
79
+ run_repository_quality_check(root)
80
+ }
81
+ _ => Err(NaomeError::new(format!(
82
+ "Quality check {check_id} is not a built-in safe check; NAOME will not execute repository-controlled verification commands."
83
+ ))),
84
+ }
85
+ }
86
+
87
+ fn run_repository_quality_check(root: &Path) -> Result<(), NaomeError> {
88
+ let report = check_repository_quality(root, QualityMode::Changed)?;
89
+ if report.ok {
90
+ return Ok(());
91
+ }
92
+
93
+ let details = report
94
+ .violations
95
+ .iter()
96
+ .take(20)
97
+ .map(|violation| {
98
+ let location = violation
99
+ .line
100
+ .map(|line| format!("{}:{line}", violation.path))
101
+ .unwrap_or_else(|| violation.path.clone());
102
+ format!("{location} {}: {}", violation.check_id, violation.message)
103
+ })
104
+ .collect::<Vec<_>>()
105
+ .join("\n");
106
+ Err(NaomeError::new(format!(
107
+ "repository-quality-check failed with {} violation(s).\n{}",
108
+ report.violations.len(),
109
+ details
110
+ )))
111
+ }
112
+
113
+ fn run_harness_health_check(root: &Path) -> Result<(), NaomeError> {
114
+ let errors = validate_harness_health(
115
+ root,
116
+ HarnessHealthOptions {
117
+ expected_integrity: packaged_harness_integrity()?,
118
+ ..HarnessHealthOptions::default()
119
+ },
120
+ )?;
121
+ if errors.is_empty() {
122
+ Ok(())
123
+ } else {
124
+ Err(NaomeError::new(errors.join("\n")))
125
+ }
126
+ }
127
+
128
+ fn run_template_task_state_check(root: &Path) -> Result<(), NaomeError> {
129
+ let template_root = template_root(root);
130
+ let report = validate_task_state(
131
+ &template_root,
132
+ TaskStateOptions {
133
+ mode: TaskStateMode::State,
134
+ harness_health: Some(HarnessHealthOptions {
135
+ expected_integrity: packaged_harness_integrity()?,
136
+ allow_missing_archive: true,
137
+ ..HarnessHealthOptions::default()
138
+ }),
139
+ },
140
+ )?;
141
+ if report.errors.is_empty() {
142
+ Ok(())
143
+ } else {
144
+ Err(NaomeError::new(report.errors.join("\n")))
145
+ }
146
+ }
147
+
148
+ fn run_template_verification_contract_check(root: &Path) -> Result<(), NaomeError> {
149
+ let errors = validate_verification_contract(&template_root(root))?;
150
+ if errors.is_empty() {
151
+ Ok(())
152
+ } else {
153
+ Err(NaomeError::new(errors.join("\n")))
154
+ }
155
+ }
@@ -0,0 +1,73 @@
1
+ use std::fs;
2
+ use std::path::{Path, PathBuf};
3
+
4
+ use crate::models::NaomeError;
5
+
6
+ pub(super) fn run_context_budget_check(root: &Path) -> Result<(), NaomeError> {
7
+ let template_root = template_root(root);
8
+ let mut context_files = vec![
9
+ template_root.join("AGENTS.md"),
10
+ template_root.join(".naomeignore"),
11
+ ];
12
+ context_files.extend(markdown_files(&template_root.join("docs").join("naome"))?);
13
+ context_files.sort();
14
+
15
+ let mut errors = Vec::new();
16
+ for path in context_files {
17
+ let content = fs::read_to_string(&path)?;
18
+ let line_count = count_lines(&content);
19
+ if line_count > 200 {
20
+ errors.push(format!(
21
+ "{}: {line_count} lines",
22
+ display_repo_path(root, &path)
23
+ ));
24
+ }
25
+ }
26
+
27
+ if errors.is_empty() {
28
+ Ok(())
29
+ } else {
30
+ Err(NaomeError::new(format!(
31
+ "NAOME context budget exceeded. Limit: 200 lines per file.\n{}",
32
+ errors.join("\n")
33
+ )))
34
+ }
35
+ }
36
+
37
+ pub(super) fn template_root(root: &Path) -> PathBuf {
38
+ root.join("packages")
39
+ .join("naome")
40
+ .join("templates")
41
+ .join("naome-root")
42
+ }
43
+
44
+ fn markdown_files(dir: &Path) -> Result<Vec<PathBuf>, NaomeError> {
45
+ let mut files = Vec::new();
46
+ for entry in fs::read_dir(dir)? {
47
+ let entry = entry?;
48
+ let path = entry.path();
49
+ if path.is_dir() {
50
+ files.extend(markdown_files(&path)?);
51
+ } else if path.is_file() && path.extension().is_some_and(|extension| extension == "md") {
52
+ files.push(path);
53
+ }
54
+ }
55
+ Ok(files)
56
+ }
57
+
58
+ fn count_lines(content: &str) -> usize {
59
+ if content.is_empty() {
60
+ 0
61
+ } else if content.ends_with('\n') {
62
+ content.split('\n').count() - 1
63
+ } else {
64
+ content.split('\n').count()
65
+ }
66
+ }
67
+
68
+ fn display_repo_path(root: &Path, path: &Path) -> String {
69
+ path.strip_prefix(root)
70
+ .unwrap_or(path)
71
+ .to_string_lossy()
72
+ .to_string()
73
+ }
@@ -0,0 +1,49 @@
1
+ use std::collections::HashMap;
2
+
3
+ use crate::models::NaomeError;
4
+
5
+ pub(super) fn packaged_harness_integrity() -> Result<HashMap<String, String>, NaomeError> {
6
+ const CHECKER: &str =
7
+ include_str!("../../../../templates/naome-root/.naome/bin/check-harness-health.js");
8
+ let start_marker = "const expectedMachineOwnedIntegrity = Object.freeze({";
9
+ let start = CHECKER
10
+ .find(start_marker)
11
+ .ok_or_else(|| NaomeError::new("Packaged harness integrity block is missing."))?;
12
+ let body_start = start + start_marker.len();
13
+ let end = CHECKER[body_start..]
14
+ .find("\n});")
15
+ .map(|offset| body_start + offset)
16
+ .ok_or_else(|| NaomeError::new("Packaged harness integrity block is incomplete."))?;
17
+
18
+ let mut integrity = HashMap::new();
19
+ for line in CHECKER[body_start..end].lines() {
20
+ let line = line.trim().trim_end_matches(',').trim();
21
+ if line.is_empty() {
22
+ continue;
23
+ }
24
+ let Some((path, hash)) = line.split_once(':') else {
25
+ return Err(NaomeError::new(format!(
26
+ "Packaged harness integrity entry is invalid: {line}"
27
+ )));
28
+ };
29
+ let path: String = serde_json::from_str(path.trim()).map_err(|error| {
30
+ NaomeError::new(format!(
31
+ "Packaged harness integrity path is invalid: {error}"
32
+ ))
33
+ })?;
34
+ let hash: String = serde_json::from_str(hash.trim()).map_err(|error| {
35
+ NaomeError::new(format!(
36
+ "Packaged harness integrity hash is invalid: {error}"
37
+ ))
38
+ })?;
39
+ integrity.insert(path, hash);
40
+ }
41
+
42
+ if integrity.is_empty() {
43
+ return Err(NaomeError::new(
44
+ "Packaged harness integrity block is empty.",
45
+ ));
46
+ }
47
+
48
+ Ok(integrity)
49
+ }
@@ -0,0 +1,40 @@
1
+ use crate::models::NaomeError;
2
+
3
+ use super::quality_gate::QualityCheck;
4
+
5
+ pub(super) fn require_builtin_quality_check_any(
6
+ check_id: &str,
7
+ check: &QualityCheck,
8
+ expected_commands: &[&str],
9
+ ) -> Result<(), NaomeError> {
10
+ if check.cwd == "."
11
+ && expected_commands
12
+ .iter()
13
+ .any(|expected_command| check.command == *expected_command)
14
+ {
15
+ return Ok(());
16
+ }
17
+
18
+ Err(NaomeError::new(format!(
19
+ "Quality check {check_id} has an unsafe command or cwd; expected one of [{}] with cwd `.`.",
20
+ expected_commands
21
+ .iter()
22
+ .map(|command| format!("`{command}`"))
23
+ .collect::<Vec<_>>()
24
+ .join(", ")
25
+ )))
26
+ }
27
+
28
+ pub(super) fn require_builtin_quality_check(
29
+ check_id: &str,
30
+ check: &QualityCheck,
31
+ expected_command: &str,
32
+ ) -> Result<(), NaomeError> {
33
+ if check.cwd == "." && check.command == expected_command {
34
+ return Ok(());
35
+ }
36
+
37
+ Err(NaomeError::new(format!(
38
+ "Quality check {check_id} has an unsafe command or cwd; expected command `{expected_command}` with cwd `.`."
39
+ )))
40
+ }
@@ -0,0 +1,180 @@
1
+ use crate::intent::IntentDecision;
2
+ use crate::models::Decision;
3
+
4
+ pub(super) fn can_create_task(intent: &IntentDecision, decision: &Decision, execute: bool) -> bool {
5
+ let creation_intent = matches!(
6
+ intent.policy_action.as_str(),
7
+ "create_new_task"
8
+ | "create_new_task_without_auto_baseline"
9
+ | "auto_commit_completed_task_then_create_new_task"
10
+ | "auto_commit_completed_task_then_create_isolated_task_worktree"
11
+ | "auto_commit_harness_refresh_then_completed_task_then_create_new_task"
12
+ | "auto_commit_harness_refresh_then_create_new_task"
13
+ | "auto_commit_harness_refresh_then_create_isolated_task_worktree"
14
+ | "auto_commit_upgrade_baseline_then_create_new_task"
15
+ | "create_isolated_task_worktree"
16
+ );
17
+ if !creation_intent || decision.state != "ready_for_task" || decision.blocked {
18
+ return false;
19
+ }
20
+
21
+ execute
22
+ || matches!(
23
+ intent.policy_action.as_str(),
24
+ "create_new_task" | "create_new_task_without_auto_baseline"
25
+ )
26
+ }
27
+
28
+ pub(super) fn winning_rule(intent: &IntentDecision) -> String {
29
+ match intent.policy_action.as_str() {
30
+ "block_unsafe_intent" => "unsafe_intent_precedence",
31
+ "block_auto_baseline_due_to_no_commit" => "no_commit_blocks_auto_baseline",
32
+ "continue_current_task_without_commit" => "no_commit_continues_active_task",
33
+ "review_task_diff" | "review_diff_first" | "review_current_task_diff" => {
34
+ "explicit_review_overrides_auto_baseline"
35
+ }
36
+ "cancel_task_changes" | "cancel_upgrade_baseline" | "cancel_current_task" => {
37
+ "explicit_cancel_overrides_auto_baseline"
38
+ }
39
+ "auto_commit_completed_task_then_create_new_task" => {
40
+ "completed_task_valid_new_task_auto_baseline"
41
+ }
42
+ "auto_commit_completed_task_then_create_isolated_task_worktree" => {
43
+ "completed_task_valid_with_unrelated_dirty_worktree"
44
+ }
45
+ "auto_commit_harness_refresh_then_completed_task_then_create_new_task" => {
46
+ "completed_task_harness_refresh_split_auto_baseline"
47
+ }
48
+ "auto_commit_harness_refresh_then_create_new_task" => {
49
+ "pure_harness_refresh_new_task_auto_baseline"
50
+ }
51
+ "auto_commit_harness_refresh_then_create_isolated_task_worktree" => {
52
+ "dirty_repo_harness_refresh_worktree_isolation"
53
+ }
54
+ "auto_commit_harness_refresh_baseline" => "dirty_repo_harness_refresh_repair_baseline",
55
+ "auto_commit_upgrade_baseline_then_create_new_task" => "setup_diff_new_task_auto_baseline",
56
+ "reopen_completed_task_revision" | "continue_current_task" => {
57
+ "current_task_revision_continues_task"
58
+ }
59
+ "answer_status_only" => "status_request_read_only",
60
+ "create_new_task" | "create_new_task_without_auto_baseline" => "ready_repo_new_task",
61
+ "create_isolated_task_worktree" => "dirty_repo_new_task_worktree_isolation",
62
+ "commit_user_diff_with_quality_gate" => "explicit_user_diff_commit_quality_gate",
63
+ _ => "fallback_policy",
64
+ }
65
+ .to_string()
66
+ }
67
+
68
+ pub(super) fn discarded_actions(intent: &IntentDecision) -> Vec<String> {
69
+ let Some(actions_note) = intent
70
+ .internal_notes
71
+ .iter()
72
+ .find(|note| note.starts_with("internal_allowed_actions:"))
73
+ else {
74
+ return Vec::new();
75
+ };
76
+ let selected = selected_internal_action(&intent.policy_action);
77
+ actions_note
78
+ .trim_start_matches("internal_allowed_actions:")
79
+ .split(',')
80
+ .filter(|action| !action.is_empty() && Some(*action) != selected.as_deref())
81
+ .map(ToString::to_string)
82
+ .collect()
83
+ }
84
+
85
+ fn selected_internal_action(policy_action: &str) -> Option<String> {
86
+ match policy_action {
87
+ "auto_commit_completed_task_then_create_new_task"
88
+ | "auto_commit_completed_task_then_create_isolated_task_worktree"
89
+ | "commit_task_baseline" => Some("commit_task_baseline".to_string()),
90
+ "auto_commit_harness_refresh_then_create_new_task"
91
+ | "auto_commit_harness_refresh_then_create_isolated_task_worktree"
92
+ | "auto_commit_harness_refresh_baseline" => Some("commit_upgrade_baseline".to_string()),
93
+ "auto_commit_harness_refresh_then_completed_task_then_create_new_task" => {
94
+ Some("commit_task_baseline".to_string())
95
+ }
96
+ "auto_commit_upgrade_baseline_then_create_new_task" | "commit_upgrade_baseline" => {
97
+ Some("commit_upgrade_baseline".to_string())
98
+ }
99
+ other if other.starts_with("review_") || other.starts_with("cancel_") => {
100
+ Some(other.to_string())
101
+ }
102
+ _ => None,
103
+ }
104
+ }
105
+
106
+ pub(super) fn would_mutate(intent: &IntentDecision) -> bool {
107
+ matches!(
108
+ intent.policy_action.as_str(),
109
+ "auto_commit_completed_task_then_create_new_task"
110
+ | "auto_commit_completed_task_then_create_isolated_task_worktree"
111
+ | "auto_commit_upgrade_baseline_then_create_new_task"
112
+ | "auto_commit_harness_refresh_then_completed_task_then_create_new_task"
113
+ | "auto_commit_harness_refresh_then_create_new_task"
114
+ | "auto_commit_harness_refresh_then_create_isolated_task_worktree"
115
+ | "auto_commit_harness_refresh_baseline"
116
+ | "create_isolated_task_worktree"
117
+ | "commit_task_baseline"
118
+ | "commit_upgrade_baseline"
119
+ | "commit_user_diff_with_quality_gate"
120
+ )
121
+ }
122
+
123
+ pub(super) fn required_context_for_route(
124
+ intent: &IntentDecision,
125
+ decision: &Decision,
126
+ ) -> Vec<String> {
127
+ let mut context = required_context_for_intent(intent);
128
+ if decision.state == "ready_for_task" {
129
+ push_unique(&mut context, "docs/naome/agent-workflow.md");
130
+ push_unique(&mut context, "docs/naome/testing.md");
131
+ push_unique(&mut context, ".naome/verification.json");
132
+ }
133
+ context
134
+ }
135
+
136
+ pub(super) fn required_context_for_intent(intent: &IntentDecision) -> Vec<String> {
137
+ let mut context = intent.required_context.clone();
138
+ match intent.policy_action.as_str() {
139
+ "create_new_task" | "create_new_task_without_auto_baseline" => {
140
+ push_unique(&mut context, "docs/naome/agent-workflow.md");
141
+ push_unique(&mut context, "docs/naome/testing.md");
142
+ push_unique(&mut context, ".naome/verification.json");
143
+ push_unique(&mut context, "docs/naome/architecture.md");
144
+ }
145
+ "create_isolated_task_worktree" => {
146
+ push_unique(&mut context, "docs/naome/agent-workflow.md");
147
+ push_unique(&mut context, "docs/naome/testing.md");
148
+ push_unique(&mut context, ".naome/verification.json");
149
+ push_unique(&mut context, "docs/naome/architecture.md");
150
+ }
151
+ "auto_commit_completed_task_then_create_new_task"
152
+ | "auto_commit_completed_task_then_create_isolated_task_worktree"
153
+ | "auto_commit_harness_refresh_then_create_new_task"
154
+ | "auto_commit_harness_refresh_then_create_isolated_task_worktree"
155
+ | "auto_commit_harness_refresh_baseline"
156
+ | "auto_commit_harness_refresh_then_completed_task_then_create_new_task"
157
+ | "reopen_completed_task_revision"
158
+ | "review_task_diff"
159
+ | "cancel_task_changes"
160
+ | "block_auto_baseline_due_to_no_commit" => {
161
+ push_unique(&mut context, "docs/naome/execution.md");
162
+ push_unique(&mut context, ".naome/task-state.json");
163
+ }
164
+ "answer_status_only" => {
165
+ push_unique(&mut context, "docs/naome/index.md");
166
+ }
167
+ "repair_harness_only" => {
168
+ push_unique(&mut context, ".naome/manifest.json");
169
+ push_unique(&mut context, "docs/naome/index.md");
170
+ }
171
+ _ => {}
172
+ }
173
+ context
174
+ }
175
+
176
+ fn push_unique(context: &mut Vec<String>, value: &str) {
177
+ if !context.iter().any(|entry| entry == value) {
178
+ context.push(value.to_string());
179
+ }
180
+ }
@@ -0,0 +1,96 @@
1
+ use std::path::{Path, PathBuf};
2
+
3
+ use crate::intent::IntentDecision;
4
+ use crate::journal::TaskJournalEntry;
5
+ use crate::models::{Decision, NaomeError};
6
+
7
+ use super::execution_baselines::{
8
+ baseline_completed_task, baseline_completed_task_then_worktree, baseline_harness_refresh,
9
+ baseline_harness_refresh_then_completed_task, baseline_harness_refresh_then_worktree,
10
+ baseline_pure_harness_refresh, baseline_setup, commit_upgrade_baseline,
11
+ };
12
+ use super::execution_tasks::{
13
+ commit_user_diff, create_task_worktree, journal_external_baseline_if_needed,
14
+ };
15
+ use super::RouteWorktree;
16
+
17
+ pub(super) struct RouteExecution {
18
+ pub(super) mutation_performed: bool,
19
+ pub(super) executed_actions: Vec<String>,
20
+ pub(super) journal_entry: Option<TaskJournalEntry>,
21
+ pub(super) user_message: String,
22
+ pub(super) task_root: PathBuf,
23
+ pub(super) worktree: Option<RouteWorktree>,
24
+ pub(super) route_allowed: bool,
25
+ pub(super) human_options: Vec<String>,
26
+ }
27
+
28
+ impl RouteExecution {
29
+ pub(super) fn from_intent(root: &Path, intent: &IntentDecision) -> Self {
30
+ Self {
31
+ mutation_performed: false,
32
+ executed_actions: Vec::new(),
33
+ journal_entry: None,
34
+ user_message: intent.user_message.clone(),
35
+ task_root: root.to_path_buf(),
36
+ worktree: None,
37
+ route_allowed: intent.allowed,
38
+ human_options: intent.human_options.clone(),
39
+ }
40
+ }
41
+
42
+ pub(super) fn mark_action(&mut self, action: &str) {
43
+ self.mutation_performed = true;
44
+ self.executed_actions.push(action.to_string());
45
+ }
46
+ }
47
+
48
+ pub(super) fn execute_route_policy(
49
+ root: &Path,
50
+ prompt: &str,
51
+ initial_decision: &Decision,
52
+ intent: &IntentDecision,
53
+ repo_state_before: &str,
54
+ execution: &mut RouteExecution,
55
+ ) -> Result<(), NaomeError> {
56
+ match intent.policy_action.as_str() {
57
+ "auto_commit_completed_task_then_create_new_task" => baseline_completed_task(
58
+ root,
59
+ "route_auto_baseline",
60
+ "NAOME baselined the completed task and is ready to create the next task.",
61
+ execution,
62
+ ),
63
+ "auto_commit_completed_task_then_create_isolated_task_worktree" => {
64
+ baseline_completed_task_then_worktree(root, prompt, execution)
65
+ }
66
+ "auto_commit_harness_refresh_then_completed_task_then_create_new_task" => {
67
+ baseline_harness_refresh_then_completed_task(root, execution)
68
+ }
69
+ "auto_commit_harness_refresh_then_create_isolated_task_worktree" => {
70
+ baseline_harness_refresh_then_worktree(root, prompt, execution)
71
+ }
72
+ "auto_commit_harness_refresh_then_create_new_task" => {
73
+ baseline_pure_harness_refresh(root, execution)
74
+ }
75
+ "auto_commit_harness_refresh_baseline" => baseline_harness_refresh(root, execution),
76
+ "auto_commit_upgrade_baseline_then_create_new_task" => baseline_setup(root, execution),
77
+ "commit_task_baseline" => baseline_completed_task(
78
+ root,
79
+ "naome_commit_baseline",
80
+ "NAOME baselined the completed task and is ready for the next request.",
81
+ execution,
82
+ ),
83
+ "commit_upgrade_baseline" => commit_upgrade_baseline(root, execution),
84
+ "create_isolated_task_worktree" => create_task_worktree(root, prompt, execution),
85
+ "commit_user_diff_with_quality_gate" => commit_user_diff(root, execution),
86
+ "create_new_task" | "create_new_task_without_auto_baseline" => {
87
+ journal_external_baseline_if_needed(
88
+ root,
89
+ initial_decision,
90
+ repo_state_before,
91
+ execution,
92
+ )
93
+ }
94
+ _ => Ok(()),
95
+ }
96
+ }