@lamentis/naome 1.1.1 → 1.2.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 (126) 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 +44 -4
  6. package/bin/naome.js +54 -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 +36 -0
  11. package/crates/naome-cli/src/install_bridge.rs +83 -0
  12. package/crates/naome-cli/src/main.rs +57 -341
  13. package/crates/naome-cli/src/prompt_commands.rs +68 -0
  14. package/crates/naome-cli/src/quality_commands.rs +141 -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/harness_health/integrity.rs +96 -0
  19. package/crates/naome-core/src/harness_health.rs +14 -126
  20. package/crates/naome-core/src/install_plan.rs +3 -0
  21. package/crates/naome-core/src/intent/classifier.rs +171 -0
  22. package/crates/naome-core/src/intent/envelope.rs +108 -0
  23. package/crates/naome-core/src/intent/legacy.rs +138 -0
  24. package/crates/naome-core/src/intent/legacy_response.rs +76 -0
  25. package/crates/naome-core/src/intent/model.rs +71 -0
  26. package/crates/naome-core/src/intent/patterns.rs +170 -0
  27. package/crates/naome-core/src/intent/resolver.rs +162 -0
  28. package/crates/naome-core/src/intent/resolver_active.rs +17 -0
  29. package/crates/naome-core/src/intent/resolver_baseline.rs +55 -0
  30. package/crates/naome-core/src/intent/resolver_catalog.rs +167 -0
  31. package/crates/naome-core/src/intent/resolver_policy.rs +72 -0
  32. package/crates/naome-core/src/intent/resolver_shared.rs +55 -0
  33. package/crates/naome-core/src/intent/risk.rs +40 -0
  34. package/crates/naome-core/src/intent/segment.rs +170 -0
  35. package/crates/naome-core/src/intent.rs +64 -879
  36. package/crates/naome-core/src/journal.rs +9 -20
  37. package/crates/naome-core/src/lib.rs +13 -0
  38. package/crates/naome-core/src/quality/adapters.rs +178 -0
  39. package/crates/naome-core/src/quality/baseline.rs +75 -0
  40. package/crates/naome-core/src/quality/checks/duplicate_blocks.rs +175 -0
  41. package/crates/naome-core/src/quality/checks/near_duplicates.rs +130 -0
  42. package/crates/naome-core/src/quality/checks.rs +228 -0
  43. package/crates/naome-core/src/quality/cleanup.rs +72 -0
  44. package/crates/naome-core/src/quality/config.rs +109 -0
  45. package/crates/naome-core/src/quality/mod.rs +90 -0
  46. package/crates/naome-core/src/quality/scanner/repo_paths.rs +103 -0
  47. package/crates/naome-core/src/quality/scanner.rs +367 -0
  48. package/crates/naome-core/src/quality/types.rs +289 -0
  49. package/crates/naome-core/src/route.rs +292 -17
  50. package/crates/naome-core/src/task_state/admission.rs +63 -0
  51. package/crates/naome-core/src/task_state/admission_proof.rs +72 -0
  52. package/crates/naome-core/src/task_state/api.rs +130 -0
  53. package/crates/naome-core/src/task_state/commit_gate.rs +138 -0
  54. package/crates/naome-core/src/task_state/compact_proof.rs +160 -0
  55. package/crates/naome-core/src/task_state/completed_refresh.rs +89 -0
  56. package/crates/naome-core/src/task_state/completion.rs +72 -0
  57. package/crates/naome-core/src/task_state/deleted_paths.rs +47 -0
  58. package/crates/naome-core/src/task_state/diff.rs +95 -0
  59. package/crates/naome-core/src/task_state/evidence.rs +154 -0
  60. package/crates/naome-core/src/task_state/git_io.rs +86 -0
  61. package/crates/naome-core/src/task_state/git_parse.rs +86 -0
  62. package/crates/naome-core/src/task_state/git_refs.rs +37 -0
  63. package/crates/naome-core/src/task_state/human_review_state.rs +31 -0
  64. package/crates/naome-core/src/task_state/mod.rs +38 -0
  65. package/crates/naome-core/src/task_state/process_guard.rs +40 -0
  66. package/crates/naome-core/src/task_state/progress.rs +123 -0
  67. package/crates/naome-core/src/task_state/proof.rs +139 -0
  68. package/crates/naome-core/src/task_state/proof_entry.rs +66 -0
  69. package/crates/naome-core/src/task_state/proof_model.rs +70 -0
  70. package/crates/naome-core/src/task_state/proof_sources.rs +76 -0
  71. package/crates/naome-core/src/task_state/push_gate.rs +49 -0
  72. package/crates/naome-core/src/task_state/reconcile.rs +7 -0
  73. package/crates/naome-core/src/task_state/repair.rs +168 -0
  74. package/crates/naome-core/src/task_state/shape.rs +117 -0
  75. package/crates/naome-core/src/task_state/task_diff_api.rs +170 -0
  76. package/crates/naome-core/src/task_state/task_records.rs +131 -0
  77. package/crates/naome-core/src/task_state/task_references.rs +126 -0
  78. package/crates/naome-core/src/task_state/types.rs +87 -0
  79. package/crates/naome-core/src/task_state/util.rs +137 -0
  80. package/crates/naome-core/src/verification/render.rs +122 -0
  81. package/crates/naome-core/src/verification.rs +176 -58
  82. package/crates/naome-core/src/verification_contract.rs +49 -21
  83. package/crates/naome-core/src/workflow/integrity.rs +123 -0
  84. package/crates/naome-core/src/workflow/integrity_normalize.rs +7 -0
  85. package/crates/naome-core/src/workflow/integrity_support.rs +110 -0
  86. package/crates/naome-core/src/workflow/mod.rs +18 -0
  87. package/crates/naome-core/src/workflow/mutation.rs +68 -0
  88. package/crates/naome-core/src/workflow/output.rs +111 -0
  89. package/crates/naome-core/src/workflow/phase_inference.rs +73 -0
  90. package/crates/naome-core/src/workflow/phases.rs +169 -0
  91. package/crates/naome-core/src/workflow/policy.rs +156 -0
  92. package/crates/naome-core/src/workflow/processes.rs +91 -0
  93. package/crates/naome-core/src/workflow/types.rs +42 -0
  94. package/crates/naome-core/tests/harness_health.rs +3 -0
  95. package/crates/naome-core/tests/intent.rs +97 -792
  96. package/crates/naome-core/tests/intent_support/mod.rs +133 -0
  97. package/crates/naome-core/tests/intent_v2.rs +90 -0
  98. package/crates/naome-core/tests/quality.rs +425 -0
  99. package/crates/naome-core/tests/route.rs +221 -4
  100. package/crates/naome-core/tests/task_state.rs +3 -0
  101. package/crates/naome-core/tests/task_state_compact.rs +110 -0
  102. package/crates/naome-core/tests/task_state_compact_support/mod.rs +5 -0
  103. package/crates/naome-core/tests/task_state_compact_support/repo.rs +130 -0
  104. package/crates/naome-core/tests/task_state_compact_support/states.rs +151 -0
  105. package/crates/naome-core/tests/workflow_integrity.rs +85 -0
  106. package/crates/naome-core/tests/workflow_policy.rs +139 -0
  107. package/crates/naome-core/tests/workflow_support/mod.rs +194 -0
  108. package/native/darwin-arm64/naome +0 -0
  109. package/native/linux-x64/naome +0 -0
  110. package/package.json +2 -2
  111. package/templates/naome-root/.naome/bin/check-harness-health.js +66 -85
  112. package/templates/naome-root/.naome/bin/check-task-state.js +9 -10
  113. package/templates/naome-root/.naome/bin/naome.js +34 -63
  114. package/templates/naome-root/.naome/manifest.json +20 -18
  115. package/templates/naome-root/.naome/repository-quality-baseline.json +5 -0
  116. package/templates/naome-root/.naome/repository-quality.json +24 -0
  117. package/templates/naome-root/.naome/task-contract.schema.json +93 -11
  118. package/templates/naome-root/.naome/upgrade-state.json +1 -1
  119. package/templates/naome-root/.naome/verification.json +37 -0
  120. package/templates/naome-root/AGENTS.md +3 -0
  121. package/templates/naome-root/docs/naome/agent-workflow.md +25 -12
  122. package/templates/naome-root/docs/naome/execution.md +25 -21
  123. package/templates/naome-root/docs/naome/index.md +4 -3
  124. package/templates/naome-root/docs/naome/repository-quality.md +43 -0
  125. package/templates/naome-root/docs/naome/testing.md +12 -0
  126. package/crates/naome-core/src/task_state.rs +0 -2210
@@ -0,0 +1,36 @@
1
+ use std::path::Path;
2
+
3
+ use crate::check_commands::{run_harness_health, run_task_state, run_verification_contract};
4
+ use crate::install_bridge::run_install_bridge;
5
+ use crate::prompt_commands::{run_explain, run_intent, run_route};
6
+ use crate::quality_commands::{run_cleanup_command, run_quality_command};
7
+ use crate::simple_commands::{
8
+ print_install_plan, run_commit_paths, run_journal_task, seed_verification,
9
+ };
10
+ use crate::workflow_commands::{run_refresh_integrity, run_workflow_command};
11
+
12
+ pub fn dispatch_command(
13
+ root: &Path,
14
+ command: &str,
15
+ args: &[String],
16
+ ) -> Result<bool, Box<dyn std::error::Error>> {
17
+ match command {
18
+ "install" | "sync" => run_install_bridge(command, args)?,
19
+ "install-plan" => print_install_plan(args)?,
20
+ "seed-verification" => seed_verification(root)?,
21
+ "refresh-integrity" => run_refresh_integrity(root, args)?,
22
+ "quality" => run_quality_command(root, args)?,
23
+ "cleanup" => run_cleanup_command(root, args)?,
24
+ "workflow" => run_workflow_command(root, args)?,
25
+ "check-harness-health" => run_harness_health(root, args)?,
26
+ "check-task-state" => run_task_state(root, args)?,
27
+ "validate-verification" => run_verification_contract(root)?,
28
+ "intent" => run_intent(root, args)?,
29
+ "route" => run_route(root, args)?,
30
+ "explain" => run_explain(root, args)?,
31
+ "journal-task" => run_journal_task(root, args)?,
32
+ "commit-paths" => run_commit_paths(root, args)?,
33
+ _ => return Ok(false),
34
+ }
35
+ Ok(true)
36
+ }
@@ -0,0 +1,83 @@
1
+ use std::path::PathBuf;
2
+ use std::process::Command;
3
+
4
+ use crate::cli_args::option_value;
5
+
6
+ pub fn run_install_bridge(
7
+ command: &str,
8
+ args: &[String],
9
+ ) -> Result<(), Box<dyn std::error::Error>> {
10
+ let package_root = option_value(args, "--package-root")
11
+ .map(PathBuf::from)
12
+ .or_else(|| std::env::var("NAOME_PACKAGE_ROOT").ok().map(PathBuf::from))
13
+ .or_else(resolve_package_root_from_exe)
14
+ .or_else(resolve_package_root_from_cwd);
15
+ let installer_js = option_value(args, "--installer-js")
16
+ .map(PathBuf::from)
17
+ .or_else(|| std::env::var("NAOME_INSTALLER_JS").ok().map(PathBuf::from))
18
+ .or_else(|| {
19
+ package_root
20
+ .as_ref()
21
+ .map(|root| root.join("bin").join("naome-node.js"))
22
+ });
23
+ let Some(installer_js) = installer_js.filter(|path| path.is_file()) else {
24
+ return Err(format!(
25
+ "native {command} needs naome-node.js. Install the naome npm package, or pass --package-root/--installer-js."
26
+ )
27
+ .into());
28
+ };
29
+
30
+ let node_bin = std::env::var("NAOME_NODE_BIN").unwrap_or_else(|_| "node".to_string());
31
+ let status = Command::new(node_bin)
32
+ .arg(installer_js)
33
+ .args(strip_install_bridge_options(args))
34
+ .status()?;
35
+
36
+ if status.success() {
37
+ return Ok(());
38
+ }
39
+
40
+ std::process::exit(status.code().unwrap_or(1));
41
+ }
42
+
43
+ fn strip_install_bridge_options(args: &[String]) -> Vec<String> {
44
+ let mut result = Vec::new();
45
+ let mut index = 1;
46
+ while index < args.len() {
47
+ let arg = &args[index];
48
+ if arg == "--package-root" || arg == "--installer-js" {
49
+ index += 2;
50
+ continue;
51
+ }
52
+ if arg.starts_with("--package-root=") || arg.starts_with("--installer-js=") {
53
+ index += 1;
54
+ continue;
55
+ }
56
+ result.push(arg.clone());
57
+ index += 1;
58
+ }
59
+ result
60
+ }
61
+
62
+ fn resolve_package_root_from_exe() -> Option<PathBuf> {
63
+ let exe = std::env::current_exe().ok()?;
64
+ let platform_dir = exe.parent()?;
65
+ let native_dir = platform_dir.parent()?;
66
+ if native_dir.file_name().and_then(|value| value.to_str()) == Some("native") {
67
+ let package_root = native_dir.parent()?.to_path_buf();
68
+ if package_root.join("bin").join("naome-node.js").is_file() {
69
+ return Some(package_root);
70
+ }
71
+ }
72
+ None
73
+ }
74
+
75
+ fn resolve_package_root_from_cwd() -> Option<PathBuf> {
76
+ let current = std::env::current_dir().ok()?;
77
+ for candidate in [current.join("packages").join("naome"), current] {
78
+ if candidate.join("bin").join("naome-node.js").is_file() {
79
+ return Some(candidate);
80
+ }
81
+ }
82
+ None
83
+ }
@@ -1,13 +1,45 @@
1
- use std::collections::HashMap;
2
- use std::fs;
1
+ mod check_commands;
2
+ mod cli_args;
3
+ mod dispatcher;
4
+ mod install_bridge;
5
+ mod prompt_commands;
6
+ mod quality_commands;
7
+ mod simple_commands;
8
+ mod workflow_commands;
9
+
3
10
  use std::path::{Path, PathBuf};
4
- use std::process::Command;
5
11
 
6
- use naome_core::{
7
- evaluate_decision, format_decision, install_plan, seed_builtin_verification_checks,
8
- validate_harness_health, validate_task_state, validate_verification_contract,
9
- EvaluationOptions, HarnessHealthOptions, TaskStateMode, TaskStateOptions,
10
- };
12
+ use cli_args::option_value;
13
+ use dispatcher::dispatch_command;
14
+ use naome_core::{evaluate_decision, format_decision, EvaluationOptions};
15
+
16
+ const HELP: &str = r#"Usage:
17
+ naome status [--json]
18
+ naome next [--json]
19
+ naome intent --prompt-file <path> [--json]
20
+ naome intent --prompt <text> [--json]
21
+ naome route --prompt-file <path> [--execute] [--json]
22
+ naome route --prompt <text> [--execute] [--json]
23
+ naome explain --prompt-file <path> [--json]
24
+ naome explain --prompt <text> [--json]
25
+ naome install [--package-root <path>] [--installer-js <path>]
26
+ naome sync [--package-root <path>] [--installer-js <path>]
27
+ naome install-plan [--harness-version <version>]
28
+ naome seed-verification
29
+ naome refresh-integrity [--root <path>] [--json]
30
+ naome quality init [--json]
31
+ naome quality check --changed [--json]
32
+ naome quality report [--json]
33
+ naome cleanup plan [--json]
34
+ naome cleanup route --path <path> [--json]
35
+ naome workflow search-profile [--json]
36
+ naome workflow check-search --command <cmd> [--json]
37
+ naome workflow phases [--json]
38
+ naome workflow processes [--json]
39
+ naome workflow mutations --path <path> [path...] [--json]
40
+ naome check-harness-health [--root <path>] [--allow-missing-archive]
41
+ naome check-task-state [--root <path>] [--admission|--progress|--commit-gate|--push-gate] [--allow-missing-archive]
42
+ naome validate-verification [--root <path>]"#;
11
43
 
12
44
  fn main() {
13
45
  if let Err(error) = run() {
@@ -36,6 +68,10 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
36
68
  && command != "journal-task"
37
69
  && command != "commit-paths"
38
70
  && command != "seed-verification"
71
+ && command != "refresh-integrity"
72
+ && command != "workflow"
73
+ && command != "quality"
74
+ && command != "cleanup"
39
75
  && command != "install-plan"
40
76
  && command != "install"
41
77
  && command != "sync"
@@ -52,6 +88,7 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
52
88
  } else if command == "validate-verification"
53
89
  || command == "check-harness-health"
54
90
  || command == "check-task-state"
91
+ || command == "refresh-integrity"
55
92
  {
56
93
  option_value(&args, "--root")
57
94
  .map(PathBuf::from)
@@ -63,187 +100,7 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
63
100
  )?
64
101
  };
65
102
 
66
- if command == "install" || command == "sync" {
67
- run_install_bridge(command, &args)?;
68
- return Ok(());
69
- }
70
-
71
- if command == "install-plan" {
72
- let harness_version = option_value(&args, "--harness-version")
73
- .or_else(|| option_value(&args, "--version"))
74
- .unwrap_or_else(|| env!("CARGO_PKG_VERSION").to_string());
75
- println!(
76
- "{}",
77
- serde_json::to_string_pretty(&install_plan(harness_version))?
78
- );
79
- return Ok(());
80
- }
81
-
82
- if command == "seed-verification" {
83
- if seed_builtin_verification_checks(&root)? {
84
- println!("NAOME verification checks updated.");
85
- } else {
86
- println!("NAOME verification checks already present.");
87
- }
88
- return Ok(());
89
- }
90
-
91
- if command == "check-harness-health" {
92
- let options = HarnessHealthOptions {
93
- expected_integrity: expected_integrity_from_env()?,
94
- allow_missing_integrity: std::env::var("NAOME_ALLOW_MISSING_INTEGRITY")
95
- .is_ok_and(|value| value == "1"),
96
- allow_missing_archive: args.iter().any(|arg| arg == "--allow-missing-archive"),
97
- };
98
- let errors = validate_harness_health(&root, options)?;
99
- if errors.is_empty() {
100
- println!("NAOME harness health OK.");
101
- return Ok(());
102
- }
103
-
104
- eprintln!("NAOME harness health check failed.");
105
- for error in errors {
106
- eprintln!("- {error}");
107
- }
108
- std::process::exit(1);
109
- }
110
-
111
- if command == "check-task-state" {
112
- let mode = if args.iter().any(|arg| arg == "--admission") {
113
- TaskStateMode::Admission
114
- } else if args.iter().any(|arg| arg == "--progress") {
115
- TaskStateMode::Progress
116
- } else if args.iter().any(|arg| arg == "--commit-gate") {
117
- TaskStateMode::CommitGate
118
- } else if args.iter().any(|arg| arg == "--push-gate") {
119
- TaskStateMode::PushGate
120
- } else {
121
- TaskStateMode::State
122
- };
123
- let expected_integrity = expected_integrity_from_env()?;
124
- let harness_health = if expected_integrity.is_empty()
125
- && std::env::var("NAOME_ALLOW_MISSING_INTEGRITY").is_err()
126
- {
127
- None
128
- } else {
129
- Some(HarnessHealthOptions {
130
- expected_integrity,
131
- allow_missing_integrity: std::env::var("NAOME_ALLOW_MISSING_INTEGRITY")
132
- .is_ok_and(|value| value == "1"),
133
- allow_missing_archive: args.iter().any(|arg| arg == "--allow-missing-archive"),
134
- })
135
- };
136
- let report = validate_task_state(
137
- &root,
138
- TaskStateOptions {
139
- mode,
140
- harness_health,
141
- },
142
- )?;
143
- if report.errors.is_empty() {
144
- println!("{}", task_state_success_message(mode));
145
- for notice in report.notices {
146
- println!("- {notice}");
147
- }
148
- return Ok(());
149
- }
150
-
151
- eprintln!("{}", task_state_failure_message(mode));
152
- for error in report.errors {
153
- eprintln!("- {error}");
154
- }
155
- std::process::exit(1);
156
- }
157
-
158
- if command == "validate-verification" {
159
- let errors = validate_verification_contract(&root)?;
160
- if errors.is_empty() {
161
- println!("NAOME verification contract OK.");
162
- return Ok(());
163
- }
164
-
165
- eprintln!("NAOME verification contract failed.");
166
- for error in errors {
167
- eprintln!("- {error}");
168
- }
169
- std::process::exit(1);
170
- }
171
-
172
- if command == "intent" {
173
- let prompt = prompt_from_args(&args)?;
174
- let intent = naome_core::evaluate_intent(&root, &prompt, EvaluationOptions::online())?;
175
- if args.iter().any(|arg| arg == "--json") {
176
- println!("{}", serde_json::to_string_pretty(&intent)?);
177
- } else {
178
- print!("{}", naome_core::format_intent(&intent));
179
- }
180
- return Ok(());
181
- }
182
-
183
- if command == "route" {
184
- let prompt = prompt_from_args(&args)?;
185
- let route = naome_core::evaluate_route(
186
- &root,
187
- &prompt,
188
- naome_core::RouteOptions {
189
- execute: args.iter().any(|arg| arg == "--execute"),
190
- evaluation: EvaluationOptions::online(),
191
- },
192
- )?;
193
- if args.iter().any(|arg| arg == "--json") {
194
- println!("{}", serde_json::to_string_pretty(&route)?);
195
- } else {
196
- println!("{}", route.user_message);
197
- if !route.human_options.is_empty() {
198
- println!("Human options: {}", route.human_options.join(", "));
199
- }
200
- }
201
- return Ok(());
202
- }
203
-
204
- if command == "explain" {
205
- let prompt = prompt_from_args(&args)?;
206
- let explain = naome_core::explain_route(&root, &prompt, EvaluationOptions::online())?;
207
- if args.iter().any(|arg| arg == "--json") {
208
- println!("{}", serde_json::to_string_pretty(&explain)?);
209
- } else {
210
- println!("NAOME explain: {}", explain.winning_rule);
211
- println!("Repo state: {}", explain.repo_state);
212
- println!("Prompt intent: {}", explain.prompt_intent);
213
- println!("Would mutate: {}", explain.would_mutate);
214
- println!("Message: {}", explain.user_message);
215
- if !explain.human_options.is_empty() {
216
- println!("Human options: {}", explain.human_options.join(", "));
217
- }
218
- }
219
- return Ok(());
220
- }
221
-
222
- if command == "journal-task" {
223
- let outcome =
224
- option_value(&args, "--outcome").unwrap_or_else(|| "naome_commit_baseline".to_string());
225
- let commit_before = option_value(&args, "--commit-before");
226
- let commit_after = option_value(&args, "--commit-after");
227
- let entry = naome_core::append_task_journal(&root, &outcome, commit_before, commit_after)?;
228
- if args.iter().any(|arg| arg == "--json") {
229
- println!("{}", serde_json::to_string_pretty(&entry)?);
230
- } else if entry.is_some() {
231
- println!("NAOME task journal updated.");
232
- } else {
233
- println!("NAOME task journal had no active task to record.");
234
- }
235
- return Ok(());
236
- }
237
-
238
- if command == "commit-paths" {
239
- let paths = naome_core::completed_task_commit_paths(&root)?;
240
- if args.iter().any(|arg| arg == "--json") {
241
- println!("{}", serde_json::to_string_pretty(&paths)?);
242
- } else {
243
- for path in paths {
244
- println!("{path}");
245
- }
246
- }
103
+ if dispatch_command(&root, command, &args)? {
247
104
  return Ok(());
248
105
  }
249
106
 
@@ -268,22 +125,21 @@ fn is_help_request(args: &[String]) -> bool {
268
125
  }
269
126
 
270
127
  fn find_harness_root(start: &Path) -> Option<PathBuf> {
271
- let mut current = start.to_path_buf();
272
- loop {
273
- if current.join(".naome").join("task-state.json").is_file() {
274
- return Some(current);
275
- }
276
-
277
- if !current.pop() {
278
- return None;
279
- }
280
- }
128
+ find_root_with_marker(start, &[".naome", "task-state.json"])
281
129
  }
282
130
 
283
131
  fn find_manifest_root(start: &Path) -> Option<PathBuf> {
132
+ find_root_with_marker(start, &[".naome", "manifest.json"])
133
+ }
134
+
135
+ fn find_root_with_marker(start: &Path, marker: &[&str]) -> Option<PathBuf> {
284
136
  let mut current = start.to_path_buf();
285
137
  loop {
286
- if current.join(".naome").join("manifest.json").is_file() {
138
+ if marker
139
+ .iter()
140
+ .fold(current.clone(), |path, part| path.join(part))
141
+ .is_file()
142
+ {
287
143
  return Some(current);
288
144
  }
289
145
 
@@ -294,145 +150,5 @@ fn find_manifest_root(start: &Path) -> Option<PathBuf> {
294
150
  }
295
151
 
296
152
  fn print_help() {
297
- println!("Usage:");
298
- println!(" naome status [--json]");
299
- println!(" naome next [--json]");
300
- println!(" naome intent --prompt-file <path> [--json]");
301
- println!(" naome intent --prompt <text> [--json]");
302
- println!(" naome route --prompt-file <path> [--execute] [--json]");
303
- println!(" naome route --prompt <text> [--execute] [--json]");
304
- println!(" naome explain --prompt-file <path> [--json]");
305
- println!(" naome explain --prompt <text> [--json]");
306
- println!(" naome install [--package-root <path>] [--installer-js <path>]");
307
- println!(" naome sync [--package-root <path>] [--installer-js <path>]");
308
- println!(" naome install-plan [--harness-version <version>]");
309
- println!(" naome seed-verification");
310
- println!(" naome check-harness-health [--root <path>] [--allow-missing-archive]");
311
- println!(" naome check-task-state [--root <path>] [--admission|--progress|--commit-gate|--push-gate] [--allow-missing-archive]");
312
- println!(" naome validate-verification [--root <path>]");
313
- }
314
-
315
- fn option_value(args: &[String], option: &str) -> Option<String> {
316
- args.windows(2)
317
- .find(|window| window[0] == option)
318
- .map(|window| window[1].clone())
319
- }
320
-
321
- fn prompt_from_args(args: &[String]) -> Result<String, Box<dyn std::error::Error>> {
322
- if let Some(prompt_file) = option_value(args, "--prompt-file") {
323
- return Ok(fs::read_to_string(prompt_file)?);
324
- }
325
-
326
- if let Some(prompt) = option_value(args, "--prompt") {
327
- return Ok(prompt);
328
- }
329
-
330
- Err("naome prompt routing requires --prompt-file <path> or --prompt <text>.".into())
331
- }
332
-
333
- fn run_install_bridge(command: &str, args: &[String]) -> Result<(), Box<dyn std::error::Error>> {
334
- let package_root = option_value(args, "--package-root")
335
- .map(PathBuf::from)
336
- .or_else(|| std::env::var("NAOME_PACKAGE_ROOT").ok().map(PathBuf::from))
337
- .or_else(resolve_package_root_from_exe)
338
- .or_else(resolve_package_root_from_cwd);
339
- let installer_js = option_value(args, "--installer-js")
340
- .map(PathBuf::from)
341
- .or_else(|| std::env::var("NAOME_INSTALLER_JS").ok().map(PathBuf::from))
342
- .or_else(|| {
343
- package_root
344
- .as_ref()
345
- .map(|root| root.join("bin").join("naome-node.js"))
346
- });
347
- let Some(installer_js) = installer_js.filter(|path| path.is_file()) else {
348
- return Err(format!(
349
- "native {command} needs naome-node.js. Install the naome npm package, or pass --package-root/--installer-js."
350
- )
351
- .into());
352
- };
353
-
354
- let node_bin = std::env::var("NAOME_NODE_BIN").unwrap_or_else(|_| "node".to_string());
355
- let pass_through_args = strip_install_bridge_options(args);
356
- let status = Command::new(node_bin)
357
- .arg(installer_js)
358
- .args(pass_through_args)
359
- .status()?;
360
-
361
- if status.success() {
362
- return Ok(());
363
- }
364
-
365
- std::process::exit(status.code().unwrap_or(1));
366
- }
367
-
368
- fn strip_install_bridge_options(args: &[String]) -> Vec<String> {
369
- let mut result = Vec::new();
370
- let mut index = 1;
371
- while index < args.len() {
372
- let arg = &args[index];
373
- if arg == "--package-root" || arg == "--installer-js" {
374
- index += 2;
375
- continue;
376
- }
377
-
378
- if arg.starts_with("--package-root=") || arg.starts_with("--installer-js=") {
379
- index += 1;
380
- continue;
381
- }
382
-
383
- result.push(arg.clone());
384
- index += 1;
385
- }
386
- result
387
- }
388
-
389
- fn resolve_package_root_from_exe() -> Option<PathBuf> {
390
- let exe = std::env::current_exe().ok()?;
391
- let platform_dir = exe.parent()?;
392
- let native_dir = platform_dir.parent()?;
393
- if native_dir.file_name().and_then(|value| value.to_str()) == Some("native") {
394
- let package_root = native_dir.parent()?.to_path_buf();
395
- if package_root.join("bin").join("naome-node.js").is_file() {
396
- return Some(package_root);
397
- }
398
- }
399
- None
400
- }
401
-
402
- fn resolve_package_root_from_cwd() -> Option<PathBuf> {
403
- let current = std::env::current_dir().ok()?;
404
- for candidate in [current.join("packages").join("naome"), current.clone()] {
405
- if candidate.join("bin").join("naome-node.js").is_file() {
406
- return Some(candidate);
407
- }
408
- }
409
- None
410
- }
411
-
412
- fn expected_integrity_from_env() -> Result<HashMap<String, String>, Box<dyn std::error::Error>> {
413
- let Ok(value) = std::env::var("NAOME_EXPECTED_INTEGRITY_JSON") else {
414
- return Ok(HashMap::new());
415
- };
416
-
417
- Ok(serde_json::from_str(&value)?)
418
- }
419
-
420
- fn task_state_failure_message(mode: TaskStateMode) -> &'static str {
421
- match mode {
422
- TaskStateMode::Admission => "NAOME task admission check failed.",
423
- TaskStateMode::Progress => "NAOME task progress check failed.",
424
- TaskStateMode::CommitGate => "NAOME commit gate failed.",
425
- TaskStateMode::PushGate => "NAOME push gate failed.",
426
- TaskStateMode::State => "NAOME task state check failed.",
427
- }
428
- }
429
-
430
- fn task_state_success_message(mode: TaskStateMode) -> &'static str {
431
- match mode {
432
- TaskStateMode::Admission => "NAOME task admission OK.",
433
- TaskStateMode::Progress => "NAOME task progress OK.",
434
- TaskStateMode::CommitGate => "NAOME commit gate OK.",
435
- TaskStateMode::PushGate => "NAOME push gate OK.",
436
- TaskStateMode::State => "NAOME task state OK.",
437
- }
153
+ println!("{HELP}");
438
154
  }
@@ -0,0 +1,68 @@
1
+ use std::fs;
2
+ use std::path::Path;
3
+
4
+ use naome_core::EvaluationOptions;
5
+
6
+ use crate::cli_args::option_value;
7
+
8
+ pub fn run_intent(root: &Path, args: &[String]) -> Result<(), Box<dyn std::error::Error>> {
9
+ let prompt = prompt_from_args(args)?;
10
+ let intent = naome_core::evaluate_intent(root, &prompt, EvaluationOptions::online())?;
11
+ if args.iter().any(|arg| arg == "--json") {
12
+ println!("{}", serde_json::to_string_pretty(&intent)?);
13
+ } else {
14
+ print!("{}", naome_core::format_intent(&intent));
15
+ }
16
+ Ok(())
17
+ }
18
+
19
+ pub fn run_route(root: &Path, args: &[String]) -> Result<(), Box<dyn std::error::Error>> {
20
+ let prompt = prompt_from_args(args)?;
21
+ let route = naome_core::evaluate_route(
22
+ root,
23
+ &prompt,
24
+ naome_core::RouteOptions {
25
+ execute: args.iter().any(|arg| arg == "--execute"),
26
+ evaluation: EvaluationOptions::online(),
27
+ },
28
+ )?;
29
+ if args.iter().any(|arg| arg == "--json") {
30
+ println!("{}", serde_json::to_string_pretty(&route)?);
31
+ } else {
32
+ println!("{}", route.user_message);
33
+ if !route.human_options.is_empty() {
34
+ println!("Human options: {}", route.human_options.join(", "));
35
+ }
36
+ }
37
+ Ok(())
38
+ }
39
+
40
+ pub fn run_explain(root: &Path, args: &[String]) -> Result<(), Box<dyn std::error::Error>> {
41
+ let prompt = prompt_from_args(args)?;
42
+ let explain = naome_core::explain_route(root, &prompt, EvaluationOptions::online())?;
43
+ if args.iter().any(|arg| arg == "--json") {
44
+ println!("{}", serde_json::to_string_pretty(&explain)?);
45
+ } else {
46
+ println!("NAOME explain: {}", explain.winning_rule);
47
+ println!("Repo state: {}", explain.repo_state);
48
+ println!("Prompt intent: {}", explain.prompt_intent);
49
+ println!("Would mutate: {}", explain.would_mutate);
50
+ println!("Message: {}", explain.user_message);
51
+ if !explain.human_options.is_empty() {
52
+ println!("Human options: {}", explain.human_options.join(", "));
53
+ }
54
+ }
55
+ Ok(())
56
+ }
57
+
58
+ fn prompt_from_args(args: &[String]) -> Result<String, Box<dyn std::error::Error>> {
59
+ if let Some(prompt_file) = option_value(args, "--prompt-file") {
60
+ return Ok(fs::read_to_string(prompt_file)?);
61
+ }
62
+
63
+ if let Some(prompt) = option_value(args, "--prompt") {
64
+ return Ok(prompt);
65
+ }
66
+
67
+ Err("naome prompt routing requires --prompt-file <path> or --prompt <text>.".into())
68
+ }