@lamentis/naome 1.2.1 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +2 -2
- package/README.md +117 -47
- package/bin/naome.js +65 -12
- package/crates/naome-cli/Cargo.toml +1 -1
- package/crates/naome-cli/src/context_commands.rs +47 -0
- package/crates/naome-cli/src/dispatcher.rs +12 -2
- package/crates/naome-cli/src/main.rs +78 -29
- package/crates/naome-cli/src/quality_commands.rs +238 -34
- package/crates/naome-cli/src/quality_output.rs +34 -0
- package/crates/naome-cli/src/quality_reconcile_command.rs +45 -0
- package/crates/naome-cli/src/repository_model_commands.rs +84 -0
- package/crates/naome-cli/src/task_commands.rs +62 -0
- package/crates/naome-cli/src/workflow_commands.rs +120 -3
- package/crates/naome-core/Cargo.toml +1 -1
- package/crates/naome-core/src/context/helpers.rs +75 -0
- package/crates/naome-core/src/context/select.rs +134 -0
- package/crates/naome-core/src/context/types.rs +43 -0
- package/crates/naome-core/src/context.rs +6 -0
- package/crates/naome-core/src/decision/states.rs +1 -1
- package/crates/naome-core/src/decision.rs +4 -1
- package/crates/naome-core/src/git.rs +4 -2
- package/crates/naome-core/src/install_plan.rs +20 -0
- package/crates/naome-core/src/journal.rs +2 -7
- package/crates/naome-core/src/lib.rs +35 -8
- package/crates/naome-core/src/quality/adapter_ios.rs +131 -0
- package/crates/naome-core/src/quality/adapter_support.rs +67 -0
- package/crates/naome-core/src/quality/adapters.rs +81 -18
- package/crates/naome-core/src/quality/baseline.rs +8 -0
- package/crates/naome-core/src/quality/cache.rs +151 -0
- package/crates/naome-core/src/quality/checks/duplicate_blocks.rs +19 -8
- package/crates/naome-core/src/quality/checks/near_duplicates.rs +4 -2
- package/crates/naome-core/src/quality/checks.rs +7 -8
- package/crates/naome-core/src/quality/cleanup.rs +36 -3
- package/crates/naome-core/src/quality/config.rs +21 -3
- package/crates/naome-core/src/quality/mod.rs +189 -10
- package/crates/naome-core/src/quality/reconcile.rs +138 -0
- package/crates/naome-core/src/quality/reconcile_anchors.rs +64 -0
- package/crates/naome-core/src/quality/scanner/analysis/normalize.rs +78 -0
- package/crates/naome-core/src/quality/scanner/analysis.rs +175 -0
- package/crates/naome-core/src/quality/scanner/repo_paths.rs +39 -3
- package/crates/naome-core/src/quality/scanner.rs +235 -217
- package/crates/naome-core/src/quality/semantic/checks.rs +151 -0
- package/crates/naome-core/src/quality/semantic/extract.rs +158 -0
- package/crates/naome-core/src/quality/semantic/model.rs +85 -0
- package/crates/naome-core/src/quality/semantic/route.rs +52 -0
- package/crates/naome-core/src/quality/semantic.rs +68 -0
- package/crates/naome-core/src/quality/structure/adapter_ios.rs +149 -0
- package/crates/naome-core/src/quality/structure/adapters.rs +60 -42
- package/crates/naome-core/src/quality/structure/checks/directory.rs +13 -21
- package/crates/naome-core/src/quality/structure/checks.rs +1 -1
- package/crates/naome-core/src/quality/structure/classify/roles.rs +51 -5
- package/crates/naome-core/src/quality/structure/classify.rs +52 -0
- package/crates/naome-core/src/quality/structure/config.rs +24 -3
- package/crates/naome-core/src/quality/structure/mod.rs +5 -2
- package/crates/naome-core/src/quality/structure/model.rs +8 -1
- package/crates/naome-core/src/quality/types.rs +59 -2
- package/crates/naome-core/src/repository_model/detect.rs +188 -0
- package/crates/naome-core/src/repository_model/explain.rs +121 -0
- package/crates/naome-core/src/repository_model/path_scan.rs +67 -0
- package/crates/naome-core/src/repository_model/path_support.rs +59 -0
- package/crates/naome-core/src/repository_model/types.rs +152 -0
- package/crates/naome-core/src/repository_model/world.rs +48 -0
- package/crates/naome-core/src/repository_model/world_adapters.rs +145 -0
- package/crates/naome-core/src/repository_model/world_path_facts.rs +55 -0
- package/crates/naome-core/src/repository_model/world_paths.rs +168 -0
- package/crates/naome-core/src/repository_model.rs +164 -0
- package/crates/naome-core/src/route/builtin_checks.rs +41 -16
- package/crates/naome-core/src/task_ledger/import.rs +142 -0
- package/crates/naome-core/src/task_ledger/model.rs +13 -0
- package/crates/naome-core/src/task_ledger/proof_record.rs +52 -0
- package/crates/naome-core/src/task_ledger/read.rs +118 -0
- package/crates/naome-core/src/task_ledger/render.rs +55 -0
- package/crates/naome-core/src/task_ledger/write.rs +38 -0
- package/crates/naome-core/src/task_ledger.rs +48 -0
- package/crates/naome-core/src/task_state/api.rs +4 -2
- package/crates/naome-core/src/task_state/completed_refresh.rs +5 -16
- package/crates/naome-core/src/task_state/diff.rs +2 -2
- package/crates/naome-core/src/task_state/evidence.rs +8 -3
- package/crates/naome-core/src/task_state/mod.rs +1 -1
- package/crates/naome-core/src/task_state/progress.rs +13 -0
- package/crates/naome-core/src/task_state/proof_model.rs +8 -8
- package/crates/naome-core/src/task_state/repair.rs +2 -2
- package/crates/naome-core/src/task_state/task_diff_api.rs +9 -18
- package/crates/naome-core/src/task_state/types.rs +24 -0
- package/crates/naome-core/src/verification.rs +29 -18
- package/crates/naome-core/src/workflow/agent/capability.rs +194 -0
- package/crates/naome-core/src/workflow/agent/context_delta.rs +42 -0
- package/crates/naome-core/src/workflow/agent/decision.rs +32 -0
- package/crates/naome-core/src/workflow/agent/execution.rs +80 -0
- package/crates/naome-core/src/workflow/agent/proof.rs +24 -0
- package/crates/naome-core/src/workflow/agent/support.rs +58 -0
- package/crates/naome-core/src/workflow/agent/watchdog.rs +47 -0
- package/crates/naome-core/src/workflow/agent.rs +34 -0
- package/crates/naome-core/src/workflow/agent_types.rs +105 -0
- package/crates/naome-core/src/workflow/doctor.rs +183 -0
- package/crates/naome-core/src/workflow/mod.rs +13 -0
- package/crates/naome-core/src/workflow/mutation.rs +1 -2
- package/crates/naome-core/src/workflow/output.rs +8 -2
- package/crates/naome-core/src/workflow/phase_inference.rs +1 -1
- package/crates/naome-core/tests/context.rs +99 -0
- package/crates/naome-core/tests/harness_health.rs +4 -0
- package/crates/naome-core/tests/install_plan.rs +14 -0
- package/crates/naome-core/tests/quality.rs +190 -5
- package/crates/naome-core/tests/quality_performance.rs +268 -0
- package/crates/naome-core/tests/quality_structure_adapters.rs +39 -0
- package/crates/naome-core/tests/quality_structure_policy.rs +19 -0
- package/crates/naome-core/tests/repo_support/mod.rs +5 -1
- package/crates/naome-core/tests/repo_support/verification_values.rs +55 -0
- package/crates/naome-core/tests/repository_model.rs +281 -0
- package/crates/naome-core/tests/route_user_diff.rs +59 -7
- package/crates/naome-core/tests/semantic_legacy.rs +174 -0
- package/crates/naome-core/tests/task_ledger.rs +328 -0
- package/crates/naome-core/tests/task_state.rs +28 -0
- package/crates/naome-core/tests/verification.rs +29 -36
- package/crates/naome-core/tests/workflow_agent.rs +233 -0
- package/crates/naome-core/tests/workflow_agent_support/mod.rs +159 -0
- package/crates/naome-core/tests/workflow_doctor.rs +45 -0
- package/crates/naome-core/tests/workflow_policy.rs +6 -1
- package/installer/codex-hooks.js +121 -0
- package/installer/context.js +10 -0
- package/installer/filesystem.js +4 -0
- package/installer/flows.js +8 -4
- package/installer/git-boundary.js +1 -0
- package/installer/harness-files.js +6 -0
- package/installer/install-plan.js +4 -0
- package/installer/main.js +1 -1
- package/installer/native.js +1 -1
- package/native/darwin-arm64/naome +0 -0
- package/native/linux-x64/naome +0 -0
- package/package.json +1 -1
- package/templates/naome-root/.codex/config.toml +2 -0
- package/templates/naome-root/.codex/hooks.json +70 -0
- package/templates/naome-root/.naome/bin/check-harness-health.js +8 -6
- package/templates/naome-root/.naome/bin/check-task-state.js +12 -7
- package/templates/naome-root/.naome/bin/codex-hook-io.js +122 -0
- package/templates/naome-root/.naome/bin/codex-hook-policy.js +180 -0
- package/templates/naome-root/.naome/bin/codex-hook-runtime.js +174 -0
- package/templates/naome-root/.naome/bin/codex-hook.js +6 -0
- package/templates/naome-root/.naome/bin/naome.js +45 -7
- package/templates/naome-root/.naome/manifest.json +12 -6
- package/templates/naome-root/.naome/repository-model.json +6 -0
- package/templates/naome-root/.naome/repository-quality.json +3 -1
- package/templates/naome-root/.naome/verification.json +15 -1
- package/templates/naome-root/.naomeignore +1 -0
- package/templates/naome-root/AGENTS.md +38 -83
- package/templates/naome-root/docs/naome/agent-workflow.md +66 -28
- package/templates/naome-root/docs/naome/codex-hooks.md +82 -0
- package/templates/naome-root/docs/naome/context-economy.md +73 -0
- package/templates/naome-root/docs/naome/first-run.md +25 -14
- package/templates/naome-root/docs/naome/index.md +18 -10
- package/templates/naome-root/docs/naome/repository-model.md +92 -0
- package/templates/naome-root/docs/naome/repository-quality.md +104 -5
- package/templates/naome-root/docs/naome/repository-structure.md +10 -3
- package/templates/naome-root/docs/naome/task-ledger.md +71 -0
- package/templates/naome-root/docs/naome/testing.md +16 -3
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
use std::path::Path;
|
|
2
2
|
|
|
3
3
|
use naome_core::{
|
|
4
|
-
classify_mutations,
|
|
5
|
-
|
|
4
|
+
agent_run_plan, classify_mutations, context_delta_report, decision_gate, doctor_report,
|
|
5
|
+
edit_session_watchdog, proof_plan_for_task, refresh_integrity, repository_capability_graph,
|
|
6
|
+
safe_rg_args, summarize_command_output, tracked_process_report, validate_search_command,
|
|
7
|
+
verification_phase_plan,
|
|
6
8
|
};
|
|
7
9
|
|
|
8
10
|
use crate::cli_args::option_value;
|
|
@@ -30,7 +32,7 @@ pub fn run_workflow_command(
|
|
|
30
32
|
args: &[String],
|
|
31
33
|
) -> Result<(), Box<dyn std::error::Error>> {
|
|
32
34
|
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());
|
|
35
|
+
return Err("naome workflow requires agent-plan, context-delta, proof-plan, capabilities, edit-watchdog, decision-gate, digest, search-profile, check-search, phases, processes, or mutations.".into());
|
|
34
36
|
};
|
|
35
37
|
let json = args.iter().any(|arg| arg == "--json");
|
|
36
38
|
|
|
@@ -50,6 +52,29 @@ pub fn run_workflow_command(
|
|
|
50
52
|
}
|
|
51
53
|
}
|
|
52
54
|
"check-search" => run_check_search(root, args, json)?,
|
|
55
|
+
"agent-plan" => print_json_or_label(
|
|
56
|
+
serde_json::to_value(agent_run_plan(root)?)?,
|
|
57
|
+
json,
|
|
58
|
+
"NAOME agent plan ready.",
|
|
59
|
+
)?,
|
|
60
|
+
"context-delta" => run_context_delta(root, args, json)?,
|
|
61
|
+
"proof-plan" => print_json_or_label(
|
|
62
|
+
serde_json::to_value(proof_plan_for_task(root, &[])?)?,
|
|
63
|
+
json,
|
|
64
|
+
"NAOME proof plan ready.",
|
|
65
|
+
)?,
|
|
66
|
+
"capabilities" => print_json_or_label(
|
|
67
|
+
serde_json::to_value(repository_capability_graph(root)?)?,
|
|
68
|
+
json,
|
|
69
|
+
"NAOME capability graph ready.",
|
|
70
|
+
)?,
|
|
71
|
+
"edit-watchdog" => run_edit_watchdog(root, args, json)?,
|
|
72
|
+
"decision-gate" => print_json_or_label(
|
|
73
|
+
serde_json::to_value(decision_gate(root)?)?,
|
|
74
|
+
json,
|
|
75
|
+
"NAOME decision gate ready.",
|
|
76
|
+
)?,
|
|
77
|
+
"digest" => run_digest(root, args, json)?,
|
|
53
78
|
"phases" => {
|
|
54
79
|
let plan = verification_phase_plan(root, &[])?;
|
|
55
80
|
if json {
|
|
@@ -83,6 +108,26 @@ pub fn run_workflow_command(
|
|
|
83
108
|
Ok(())
|
|
84
109
|
}
|
|
85
110
|
|
|
111
|
+
pub fn run_doctor(root: &Path, args: &[String]) -> Result<(), Box<dyn std::error::Error>> {
|
|
112
|
+
let report = doctor_report(root)?;
|
|
113
|
+
if args.iter().any(|arg| arg == "--json") {
|
|
114
|
+
println!("{}", serde_json::to_string_pretty(&report)?);
|
|
115
|
+
} else {
|
|
116
|
+
println!(
|
|
117
|
+
"NAOME doctor: {}",
|
|
118
|
+
if report.ok { "ok" } else { "attention needed" }
|
|
119
|
+
);
|
|
120
|
+
println!("{}", report.next_action);
|
|
121
|
+
if !report.recommended_check_ids.is_empty() {
|
|
122
|
+
println!(
|
|
123
|
+
"Recommended checks: {}",
|
|
124
|
+
report.recommended_check_ids.join(", ")
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
Ok(())
|
|
129
|
+
}
|
|
130
|
+
|
|
86
131
|
fn run_check_search(
|
|
87
132
|
root: &Path,
|
|
88
133
|
args: &[String],
|
|
@@ -134,6 +179,78 @@ fn run_mutations(
|
|
|
134
179
|
Ok(())
|
|
135
180
|
}
|
|
136
181
|
|
|
182
|
+
fn run_context_delta(
|
|
183
|
+
root: &Path,
|
|
184
|
+
args: &[String],
|
|
185
|
+
json: bool,
|
|
186
|
+
) -> Result<(), Box<dyn std::error::Error>> {
|
|
187
|
+
let read_paths = repeated_values(args, "--read-path");
|
|
188
|
+
print_json_or_label(
|
|
189
|
+
serde_json::to_value(context_delta_report(root, &read_paths)?)?,
|
|
190
|
+
json,
|
|
191
|
+
"NAOME context delta ready.",
|
|
192
|
+
)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
fn run_edit_watchdog(
|
|
196
|
+
root: &Path,
|
|
197
|
+
args: &[String],
|
|
198
|
+
json: bool,
|
|
199
|
+
) -> Result<(), Box<dyn std::error::Error>> {
|
|
200
|
+
let paths = repeated_values(args, "--path");
|
|
201
|
+
if paths.is_empty() {
|
|
202
|
+
return Err("naome workflow edit-watchdog requires --path <path>.".into());
|
|
203
|
+
}
|
|
204
|
+
print_json_or_label(
|
|
205
|
+
serde_json::to_value(edit_session_watchdog(root, &paths)?)?,
|
|
206
|
+
json,
|
|
207
|
+
"NAOME edit watchdog ready.",
|
|
208
|
+
)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
fn run_digest(root: &Path, args: &[String], json: bool) -> Result<(), Box<dyn std::error::Error>> {
|
|
212
|
+
let command = option_value(args, "--command").unwrap_or_else(|| "unknown".to_string());
|
|
213
|
+
let cwd = option_value(args, "--cwd").unwrap_or_else(|| ".".to_string());
|
|
214
|
+
let exit_code = option_value(args, "--exit-code")
|
|
215
|
+
.and_then(|value| value.parse::<i32>().ok())
|
|
216
|
+
.unwrap_or(1);
|
|
217
|
+
let max_lines = option_value(args, "--max-lines")
|
|
218
|
+
.and_then(|value| value.parse::<usize>().ok())
|
|
219
|
+
.unwrap_or(12);
|
|
220
|
+
let output = if let Some(path) = option_value(args, "--output-file") {
|
|
221
|
+
std::fs::read_to_string(root.join(path))?
|
|
222
|
+
} else {
|
|
223
|
+
option_value(args, "--output").unwrap_or_default()
|
|
224
|
+
};
|
|
225
|
+
print_json_or_label(
|
|
226
|
+
serde_json::to_value(summarize_command_output(
|
|
227
|
+
&command, &cwd, exit_code, &output, max_lines,
|
|
228
|
+
))?,
|
|
229
|
+
json,
|
|
230
|
+
"NAOME output digest ready.",
|
|
231
|
+
)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
fn repeated_values(args: &[String], flag: &str) -> Vec<String> {
|
|
235
|
+
args.windows(2)
|
|
236
|
+
.filter(|window| window[0] == flag)
|
|
237
|
+
.map(|window| window[1].clone())
|
|
238
|
+
.collect()
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
fn print_json_or_label(
|
|
242
|
+
value: serde_json::Value,
|
|
243
|
+
json: bool,
|
|
244
|
+
label: &str,
|
|
245
|
+
) -> Result<(), Box<dyn std::error::Error>> {
|
|
246
|
+
if json {
|
|
247
|
+
println!("{}", serde_json::to_string_pretty(&value)?);
|
|
248
|
+
} else {
|
|
249
|
+
println!("{label}");
|
|
250
|
+
}
|
|
251
|
+
Ok(())
|
|
252
|
+
}
|
|
253
|
+
|
|
137
254
|
fn empty_label(values: &[String]) -> String {
|
|
138
255
|
if values.is_empty() {
|
|
139
256
|
"none".to_string()
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
use std::collections::BTreeSet;
|
|
2
|
+
use std::fs;
|
|
3
|
+
use std::path::Path;
|
|
4
|
+
|
|
5
|
+
use super::types::{ContextCapsule, ContextItem};
|
|
6
|
+
|
|
7
|
+
pub(super) fn normalize_paths(paths: Vec<String>) -> Vec<String> {
|
|
8
|
+
let normalized = paths
|
|
9
|
+
.into_iter()
|
|
10
|
+
.filter(|path| !path.trim().is_empty())
|
|
11
|
+
.map(|path| path.trim_start_matches("./").replace('\\', "/"))
|
|
12
|
+
.collect::<BTreeSet<_>>()
|
|
13
|
+
.into_iter()
|
|
14
|
+
.collect::<Vec<_>>();
|
|
15
|
+
let task_paths = normalized
|
|
16
|
+
.iter()
|
|
17
|
+
.filter(|path| !is_context_noise(path))
|
|
18
|
+
.cloned()
|
|
19
|
+
.collect::<Vec<_>>();
|
|
20
|
+
if task_paths.is_empty() {
|
|
21
|
+
normalized
|
|
22
|
+
} else {
|
|
23
|
+
task_paths
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
pub(super) fn context_item(root: &Path, path: &str, reason: &str, priority: &str) -> ContextItem {
|
|
28
|
+
ContextItem {
|
|
29
|
+
path: path.to_string(),
|
|
30
|
+
reason: reason.to_string(),
|
|
31
|
+
priority: priority.to_string(),
|
|
32
|
+
estimated_lines: fs::read_to_string(root.join(path))
|
|
33
|
+
.map(|content| content.lines().count().max(1))
|
|
34
|
+
.unwrap_or(1),
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
pub(super) fn capsule_for_paths(paths: &[String]) -> ContextCapsule {
|
|
39
|
+
let id = if paths.iter().any(|path| path.contains("quality")) {
|
|
40
|
+
"quality-work"
|
|
41
|
+
} else if paths
|
|
42
|
+
.iter()
|
|
43
|
+
.any(|path| path.contains("/route") || path.contains("/intent"))
|
|
44
|
+
{
|
|
45
|
+
"routing-work"
|
|
46
|
+
} else if paths.iter().any(|path| is_source_path(path)) {
|
|
47
|
+
"source-work"
|
|
48
|
+
} else if paths
|
|
49
|
+
.iter()
|
|
50
|
+
.any(|path| path.ends_with(".md") || path.contains("/docs/"))
|
|
51
|
+
{
|
|
52
|
+
"docs-work"
|
|
53
|
+
} else {
|
|
54
|
+
"general-work"
|
|
55
|
+
};
|
|
56
|
+
ContextCapsule {
|
|
57
|
+
id: id.to_string(),
|
|
58
|
+
task_type: id.trim_end_matches("-work").to_string(),
|
|
59
|
+
summary: format!("Compact context capsule for {id}."),
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
pub(super) fn is_source_path(path: &str) -> bool {
|
|
64
|
+
let lower = path.to_ascii_lowercase();
|
|
65
|
+
[
|
|
66
|
+
".rs", ".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".py", ".go", ".swift", ".kt",
|
|
67
|
+
".java", ".c", ".cc", ".cpp", ".h", ".hpp", ".rb", ".php", ".cs", ".sh",
|
|
68
|
+
]
|
|
69
|
+
.iter()
|
|
70
|
+
.any(|extension| lower.ends_with(extension))
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
fn is_context_noise(path: &str) -> bool {
|
|
74
|
+
matches!(path, ".naome/task-state.json" | ".naome/manifest.json") || path.contains("/native/")
|
|
75
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
use std::path::Path;
|
|
2
|
+
|
|
3
|
+
use crate::{git, models::NaomeError};
|
|
4
|
+
|
|
5
|
+
use super::helpers::{capsule_for_paths, context_item, is_source_path, normalize_paths};
|
|
6
|
+
use super::types::{ContextBudgetLedger, ContextItem, ContextSelection};
|
|
7
|
+
|
|
8
|
+
const MAX_CONTEXT_FILES: usize = 12;
|
|
9
|
+
|
|
10
|
+
pub fn select_context_for_changed_paths(root: &Path) -> Result<ContextSelection, NaomeError> {
|
|
11
|
+
let paths = git::changed_paths(root)?;
|
|
12
|
+
Ok(selection_for_paths(root, "changed", paths))
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
pub fn select_context_for_prompt(
|
|
16
|
+
root: &Path,
|
|
17
|
+
prompt: impl AsRef<str>,
|
|
18
|
+
) -> Result<ContextSelection, NaomeError> {
|
|
19
|
+
Ok(selection_for_paths(
|
|
20
|
+
root,
|
|
21
|
+
"prompt",
|
|
22
|
+
mentioned_paths(prompt.as_ref()),
|
|
23
|
+
))
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
fn selection_for_paths(root: &Path, mode: &str, paths: Vec<String>) -> ContextSelection {
|
|
27
|
+
let target_paths = normalize_paths(paths);
|
|
28
|
+
let capsule = capsule_for_paths(&target_paths);
|
|
29
|
+
let mut required_context = target_paths
|
|
30
|
+
.iter()
|
|
31
|
+
.take(MAX_CONTEXT_FILES)
|
|
32
|
+
.map(|path| context_item(root, path, "changed_path", "required"))
|
|
33
|
+
.collect::<Vec<_>>();
|
|
34
|
+
if required_context.is_empty() {
|
|
35
|
+
required_context.push(context_item(
|
|
36
|
+
root,
|
|
37
|
+
".naome/verification.json",
|
|
38
|
+
"minimal_harness_policy",
|
|
39
|
+
"required",
|
|
40
|
+
));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let avoided_files = target_paths.len().saturating_sub(required_context.len());
|
|
44
|
+
ContextSelection {
|
|
45
|
+
schema: "naome.context-selection.v1".to_string(),
|
|
46
|
+
mode: mode.to_string(),
|
|
47
|
+
optional_context: optional_context(root, &capsule.id),
|
|
48
|
+
forbidden_context: forbidden_context(),
|
|
49
|
+
commands: commands_for_paths(&target_paths),
|
|
50
|
+
budget_ledger: budget_ledger(&required_context, avoided_files),
|
|
51
|
+
notes: vec![
|
|
52
|
+
"Read requiredContext first; read optionalContext only when the task is blocked without it.".to_string(),
|
|
53
|
+
"Use path-scoped checks during implementation and keep the final changed gate before completion.".to_string(),
|
|
54
|
+
],
|
|
55
|
+
capsule,
|
|
56
|
+
required_context,
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
fn optional_context(root: &Path, capsule_id: &str) -> Vec<ContextItem> {
|
|
61
|
+
let candidates = match capsule_id {
|
|
62
|
+
"quality-work" => vec!["docs/naome/repository-quality.md", "docs/naome/testing.md"],
|
|
63
|
+
"routing-work" => vec!["docs/naome/agent-workflow.md", "docs/naome/testing.md"],
|
|
64
|
+
"docs-work" => vec!["docs/naome/index.md", "docs/naome/testing.md"],
|
|
65
|
+
_ => vec!["docs/naome/repository-quality.md", "docs/naome/testing.md"],
|
|
66
|
+
};
|
|
67
|
+
candidates
|
|
68
|
+
.into_iter()
|
|
69
|
+
.filter(|path| root.join(path).is_file())
|
|
70
|
+
.map(|path| context_item(root, path, "optional_capsule_context", "optional"))
|
|
71
|
+
.collect()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
fn budget_ledger(required_context: &[ContextItem], avoided_files: usize) -> ContextBudgetLedger {
|
|
75
|
+
let estimated_lines = required_context
|
|
76
|
+
.iter()
|
|
77
|
+
.map(|item| item.estimated_lines)
|
|
78
|
+
.sum::<usize>();
|
|
79
|
+
ContextBudgetLedger {
|
|
80
|
+
max_context_files: MAX_CONTEXT_FILES,
|
|
81
|
+
selected_files: required_context.len(),
|
|
82
|
+
avoided_files,
|
|
83
|
+
estimated_lines,
|
|
84
|
+
estimated_tokens: estimated_lines.saturating_mul(8),
|
|
85
|
+
reason_codes: if avoided_files > 0 {
|
|
86
|
+
vec!["context_file_budget_reached".to_string()]
|
|
87
|
+
} else {
|
|
88
|
+
Vec::new()
|
|
89
|
+
},
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
fn commands_for_paths(paths: &[String]) -> Vec<String> {
|
|
94
|
+
let mut commands = paths
|
|
95
|
+
.iter()
|
|
96
|
+
.filter(|path| is_source_path(path))
|
|
97
|
+
.take(6)
|
|
98
|
+
.map(|path| format!("node .naome/bin/naome.js quality check --path {path}"))
|
|
99
|
+
.collect::<Vec<_>>();
|
|
100
|
+
commands.push("node .naome/bin/naome.js quality check --changed".to_string());
|
|
101
|
+
commands.push("git diff --check".to_string());
|
|
102
|
+
commands.sort();
|
|
103
|
+
commands.dedup();
|
|
104
|
+
commands
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
fn forbidden_context() -> Vec<String> {
|
|
108
|
+
[
|
|
109
|
+
".git/**",
|
|
110
|
+
".naome/archive/**",
|
|
111
|
+
".naome/cache/**",
|
|
112
|
+
"node_modules/**",
|
|
113
|
+
"target/**",
|
|
114
|
+
"dist/**",
|
|
115
|
+
"build/**",
|
|
116
|
+
]
|
|
117
|
+
.into_iter()
|
|
118
|
+
.map(str::to_string)
|
|
119
|
+
.collect()
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
fn mentioned_paths(prompt: &str) -> Vec<String> {
|
|
123
|
+
prompt
|
|
124
|
+
.split_whitespace()
|
|
125
|
+
.map(|token| {
|
|
126
|
+
token.trim_matches(|ch: char| {
|
|
127
|
+
matches!(ch, '"' | '\'' | '`' | ',' | ';' | ':' | ')' | '(')
|
|
128
|
+
})
|
|
129
|
+
})
|
|
130
|
+
.filter(|token| token.contains('/') || is_source_path(token) || token.ends_with(".md"))
|
|
131
|
+
.filter(|token| !token.starts_with('-') && !token.starts_with("http"))
|
|
132
|
+
.map(|token| token.trim_start_matches("./").replace('\\', "/"))
|
|
133
|
+
.collect()
|
|
134
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
use serde::Serialize;
|
|
2
|
+
|
|
3
|
+
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
|
|
4
|
+
#[serde(rename_all = "camelCase")]
|
|
5
|
+
pub struct ContextSelection {
|
|
6
|
+
pub schema: String,
|
|
7
|
+
pub mode: String,
|
|
8
|
+
pub capsule: ContextCapsule,
|
|
9
|
+
pub required_context: Vec<ContextItem>,
|
|
10
|
+
pub optional_context: Vec<ContextItem>,
|
|
11
|
+
pub forbidden_context: Vec<String>,
|
|
12
|
+
pub commands: Vec<String>,
|
|
13
|
+
pub budget_ledger: ContextBudgetLedger,
|
|
14
|
+
pub notes: Vec<String>,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
|
|
18
|
+
#[serde(rename_all = "camelCase")]
|
|
19
|
+
pub struct ContextCapsule {
|
|
20
|
+
pub id: String,
|
|
21
|
+
pub summary: String,
|
|
22
|
+
pub task_type: String,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
|
|
26
|
+
#[serde(rename_all = "camelCase")]
|
|
27
|
+
pub struct ContextItem {
|
|
28
|
+
pub path: String,
|
|
29
|
+
pub reason: String,
|
|
30
|
+
pub priority: String,
|
|
31
|
+
pub estimated_lines: usize,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
|
|
35
|
+
#[serde(rename_all = "camelCase")]
|
|
36
|
+
pub struct ContextBudgetLedger {
|
|
37
|
+
pub max_context_files: usize,
|
|
38
|
+
pub selected_files: usize,
|
|
39
|
+
pub avoided_files: usize,
|
|
40
|
+
pub estimated_lines: usize,
|
|
41
|
+
pub estimated_tokens: usize,
|
|
42
|
+
pub reason_codes: Vec<String>,
|
|
43
|
+
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
use std::path::Path;
|
|
2
2
|
|
|
3
|
+
use serde_json::Value;
|
|
4
|
+
|
|
3
5
|
use crate::git;
|
|
4
6
|
use crate::models::{CheckDecision, Decision, NaomeError, TaskDecision};
|
|
7
|
+
use crate::task_ledger::read_task_state_projection;
|
|
5
8
|
|
|
6
9
|
mod checks;
|
|
7
10
|
mod idle;
|
|
@@ -40,7 +43,7 @@ pub fn evaluate_decision(root: &Path, options: EvaluationOptions) -> Result<Deci
|
|
|
40
43
|
return Ok(decision);
|
|
41
44
|
}
|
|
42
45
|
|
|
43
|
-
let task_state =
|
|
46
|
+
let task_state = read_task_state_projection(root)?.unwrap_or(Value::Null);
|
|
44
47
|
if let Some(decision) = setup_block_decision(root, &changed_paths, &harness_health)? {
|
|
45
48
|
return Ok(decision);
|
|
46
49
|
}
|
|
@@ -63,12 +63,14 @@ fn read_naomeignore_patterns(root: &Path) -> Vec<String> {
|
|
|
63
63
|
return Vec::new();
|
|
64
64
|
};
|
|
65
65
|
|
|
66
|
-
content
|
|
66
|
+
let mut patterns = content
|
|
67
67
|
.lines()
|
|
68
68
|
.map(str::trim)
|
|
69
69
|
.filter(|line| !line.is_empty() && !line.starts_with('#') && !line.starts_with('!'))
|
|
70
70
|
.map(normalize_ignore_pattern)
|
|
71
|
-
.collect()
|
|
71
|
+
.collect::<Vec<_>>();
|
|
72
|
+
patterns.push(".naome/cache/**".to_string());
|
|
73
|
+
patterns
|
|
72
74
|
}
|
|
73
75
|
|
|
74
76
|
fn normalize_ignore_pattern(pattern: &str) -> String {
|
|
@@ -10,6 +10,8 @@ pub const MACHINE_OWNED_PATHS: &[&str] = &[
|
|
|
10
10
|
"docs/naome/index.md",
|
|
11
11
|
"docs/naome/first-run.md",
|
|
12
12
|
"docs/naome/agent-workflow.md",
|
|
13
|
+
"docs/naome/context-economy.md",
|
|
14
|
+
"docs/naome/task-ledger.md",
|
|
13
15
|
"docs/naome/execution.md",
|
|
14
16
|
"docs/naome/upgrade.md",
|
|
15
17
|
];
|
|
@@ -21,12 +23,14 @@ pub const PROJECT_OWNED_PATHS: &[&str] = &[
|
|
|
21
23
|
".naome/task-state.json",
|
|
22
24
|
".naome/upgrade-state.json",
|
|
23
25
|
".naome/verification.json",
|
|
26
|
+
".naome/repository-model.json",
|
|
24
27
|
".naome/repository-quality.json",
|
|
25
28
|
".naome/repository-structure.json",
|
|
26
29
|
".naome/repository-quality-baseline.json",
|
|
27
30
|
"docs/naome/architecture.md",
|
|
28
31
|
"docs/naome/decisions.md",
|
|
29
32
|
"docs/naome/repo-profile.md",
|
|
33
|
+
"docs/naome/repository-model.md",
|
|
30
34
|
"docs/naome/repository-quality.md",
|
|
31
35
|
"docs/naome/repository-structure.md",
|
|
32
36
|
"docs/naome/security.md",
|
|
@@ -42,6 +46,8 @@ pub const LOCAL_ONLY_MACHINE_OWNED_PATHS: &[&str] = &[
|
|
|
42
46
|
"docs/naome/index.md",
|
|
43
47
|
"docs/naome/first-run.md",
|
|
44
48
|
"docs/naome/agent-workflow.md",
|
|
49
|
+
"docs/naome/context-economy.md",
|
|
50
|
+
"docs/naome/task-ledger.md",
|
|
45
51
|
"docs/naome/execution.md",
|
|
46
52
|
"docs/naome/upgrade.md",
|
|
47
53
|
];
|
|
@@ -50,9 +56,20 @@ pub const LOCAL_NATIVE_BINARY_PATHS: &[&str] = &[
|
|
|
50
56
|
".naome/bin/naome-rust",
|
|
51
57
|
".naome/bin/naome-rust.exe",
|
|
52
58
|
".naome/archive",
|
|
59
|
+
".naome/cache",
|
|
53
60
|
".naome/task-journal.jsonl",
|
|
54
61
|
];
|
|
55
62
|
|
|
63
|
+
pub const OPTIONAL_CODEX_HOOK_PATHS: &[&str] = &[
|
|
64
|
+
".codex/config.toml",
|
|
65
|
+
".codex/hooks.json",
|
|
66
|
+
".naome/bin/codex-hook.js",
|
|
67
|
+
".naome/bin/codex-hook-io.js",
|
|
68
|
+
".naome/bin/codex-hook-policy.js",
|
|
69
|
+
".naome/bin/codex-hook-runtime.js",
|
|
70
|
+
"docs/naome/codex-hooks.md",
|
|
71
|
+
];
|
|
72
|
+
|
|
56
73
|
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
|
|
57
74
|
#[serde(rename_all = "camelCase")]
|
|
58
75
|
pub struct InstallPlan {
|
|
@@ -61,6 +78,7 @@ pub struct InstallPlan {
|
|
|
61
78
|
pub machine_owned: Vec<&'static str>,
|
|
62
79
|
pub project_owned: Vec<&'static str>,
|
|
63
80
|
pub local_only_machine_owned: Vec<&'static str>,
|
|
81
|
+
pub optional_codex_hook_paths: Vec<&'static str>,
|
|
64
82
|
pub gitignore_entries: Vec<&'static str>,
|
|
65
83
|
pub git_exclude_entries: Vec<&'static str>,
|
|
66
84
|
pub git_untrack_paths: Vec<&'static str>,
|
|
@@ -72,6 +90,7 @@ pub fn install_plan(harness_version: impl Into<String>) -> InstallPlan {
|
|
|
72
90
|
"# NAOME local machine-owned harness files.",
|
|
73
91
|
".naome/archive/",
|
|
74
92
|
".naome/bin/naome-rust*",
|
|
93
|
+
".naome/cache/",
|
|
75
94
|
".naome/task-journal.jsonl",
|
|
76
95
|
];
|
|
77
96
|
git_exclude_entries.extend_from_slice(LOCAL_ONLY_MACHINE_OWNED_PATHS);
|
|
@@ -85,6 +104,7 @@ pub fn install_plan(harness_version: impl Into<String>) -> InstallPlan {
|
|
|
85
104
|
machine_owned: MACHINE_OWNED_PATHS.to_vec(),
|
|
86
105
|
project_owned: PROJECT_OWNED_PATHS.to_vec(),
|
|
87
106
|
local_only_machine_owned: LOCAL_ONLY_MACHINE_OWNED_PATHS.to_vec(),
|
|
107
|
+
optional_codex_hook_paths: OPTIONAL_CODEX_HOOK_PATHS.to_vec(),
|
|
88
108
|
gitignore_entries,
|
|
89
109
|
git_exclude_entries,
|
|
90
110
|
git_untrack_paths,
|
|
@@ -8,6 +8,7 @@ use serde::Serialize;
|
|
|
8
8
|
use serde_json::Value;
|
|
9
9
|
|
|
10
10
|
use crate::models::NaomeError;
|
|
11
|
+
use crate::task_ledger::read_task_state_projection;
|
|
11
12
|
use crate::task_state::canonical_proof_check_ids;
|
|
12
13
|
|
|
13
14
|
const JOURNAL_PATH: &str = ".naome/task-journal.jsonl";
|
|
@@ -35,7 +36,7 @@ pub fn append_task_journal(
|
|
|
35
36
|
commit_after: Option<String>,
|
|
36
37
|
) -> Result<Option<TaskJournalEntry>, NaomeError> {
|
|
37
38
|
ensure_journal_is_local_only(root)?;
|
|
38
|
-
let task_state =
|
|
39
|
+
let task_state = read_task_state_projection(root)?.unwrap_or(Value::Null);
|
|
39
40
|
let Some(active_task) = task_state
|
|
40
41
|
.get("activeTask")
|
|
41
42
|
.filter(|value| !value.is_null())
|
|
@@ -125,12 +126,6 @@ fn proof_summary(active_task: &Value) -> Vec<String> {
|
|
|
125
126
|
canonical_proof_check_ids(active_task)
|
|
126
127
|
}
|
|
127
128
|
|
|
128
|
-
fn read_json(root: &Path, relative_path: &str) -> Result<Value, NaomeError> {
|
|
129
|
-
Ok(serde_json::from_str(&fs::read_to_string(
|
|
130
|
-
root.join(relative_path),
|
|
131
|
-
)?)?)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
129
|
fn string_at(value: &Value, key: &str) -> Option<String> {
|
|
135
130
|
value
|
|
136
131
|
.get(key)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
mod context;
|
|
1
2
|
mod decision;
|
|
2
3
|
mod git;
|
|
3
4
|
mod harness_health;
|
|
@@ -7,12 +8,18 @@ mod journal;
|
|
|
7
8
|
mod models;
|
|
8
9
|
mod paths;
|
|
9
10
|
mod quality;
|
|
11
|
+
mod repository_model;
|
|
10
12
|
mod route;
|
|
13
|
+
mod task_ledger;
|
|
11
14
|
mod task_state;
|
|
12
15
|
mod verification;
|
|
13
16
|
mod verification_contract;
|
|
14
17
|
mod workflow;
|
|
15
18
|
|
|
19
|
+
pub use context::{
|
|
20
|
+
select_context_for_changed_paths, select_context_for_prompt, ContextBudgetLedger,
|
|
21
|
+
ContextCapsule, ContextItem, ContextSelection,
|
|
22
|
+
};
|
|
16
23
|
pub use decision::{evaluate_decision, format_decision, EvaluationOptions};
|
|
17
24
|
pub use harness_health::{validate_harness_health, HarnessHealthOptions};
|
|
18
25
|
pub use install_plan::{install_plan, InstallPlan};
|
|
@@ -21,12 +28,27 @@ pub use intent::{evaluate_intent, format_intent, IntentDecision, PromptEvidence}
|
|
|
21
28
|
pub use journal::{append_task_journal, TaskJournalEntry};
|
|
22
29
|
pub use models::{Decision, NaomeError};
|
|
23
30
|
pub use quality::{
|
|
24
|
-
check_repository_quality,
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
31
|
+
check_repository_quality, check_repository_quality_paths, check_semantic_legacy,
|
|
32
|
+
check_semantic_legacy_paths,
|
|
33
|
+
clear_quality_cache, explain_repository_structure, init_repository_quality,
|
|
34
|
+
init_repository_quality_with_mode, plan_quality_cleanup, quality_cache_status,
|
|
35
|
+
reconcile_repository_quality, route_quality_cleanup, semantic_route_for_finding,
|
|
36
|
+
QualityCacheStatus, QualityCleanupPlan, QualityCleanupRoute, QualityCleanupTask,
|
|
37
|
+
QualityInitMode, QualityInitResult, QualityMode, QualityReconcileReport, QualityReport,
|
|
38
|
+
QualitySummary, QualityViolation, RepositoryQualityConfig, RepositoryStructureConfig,
|
|
39
|
+
SemanticFinding, SemanticReport, StructurePathExplanation,
|
|
40
|
+
};
|
|
41
|
+
pub use repository_model::{
|
|
42
|
+
explain_repository_model_path, refresh_repository_model, repository_model_drift,
|
|
43
|
+
RepositoryEntity, RepositoryFact, RepositoryModel, RepositoryModelDrift,
|
|
44
|
+
RepositoryModelRefresh, RepositoryPathExplanation, RepositoryPathFact, RepositoryRoot,
|
|
45
|
+
RepositoryVerificationCheck, RepositoryWorldSignal,
|
|
28
46
|
};
|
|
29
47
|
pub use route::{evaluate_route, explain_route, ExplainDecision, RouteDecision, RouteOptions};
|
|
48
|
+
pub use task_ledger::{
|
|
49
|
+
migrate_task_state_to_ledger, read_task_state_projection, render_task_state_from_ledger,
|
|
50
|
+
TaskLedgerProjection, TaskLedgerStatus,
|
|
51
|
+
};
|
|
30
52
|
pub use task_state::{
|
|
31
53
|
completed_task_commit_paths, validate_task_state, TaskStateMode, TaskStateOptions,
|
|
32
54
|
TaskStateReport,
|
|
@@ -34,8 +56,13 @@ pub use task_state::{
|
|
|
34
56
|
pub use verification::seed_builtin_verification_checks;
|
|
35
57
|
pub use verification_contract::validate_verification_contract;
|
|
36
58
|
pub use workflow::{
|
|
37
|
-
classify_mutations,
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
59
|
+
agent_run_plan, classify_mutations, context_delta_report, decision_gate, doctor_report,
|
|
60
|
+
edit_session_watchdog, proof_plan_for_task, refresh_integrity, repository_capability_graph,
|
|
61
|
+
safe_rg_args, summarize_command_output, tracked_process_report, validate_read_boundaries,
|
|
62
|
+
validate_search_command, verification_phase_plan, AgentRunPlan, CapabilityGraph,
|
|
63
|
+
CapabilityRoot, CommandCheckResult, CommandOutputSummary, ContextDeltaReport, DecisionGate,
|
|
64
|
+
DoctorReport, DoctorSection, EditSessionWatchdog, ExecutionPlanLedger, ExecutionPlanStep,
|
|
65
|
+
IntegrityRefreshReport, MutationClassification, ProcessReport, ProofPlan, ReadActivity,
|
|
66
|
+
RepositoryCapability, RepositoryPolicySection, VerificationEdge, VerificationPhasePlan,
|
|
67
|
+
WorkflowFinding,
|
|
41
68
|
};
|