@lamentis/naome 1.3.0 → 1.3.2

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 (149) hide show
  1. package/Cargo.lock +2 -2
  2. package/README.md +11 -2
  3. package/bin/naome.js +62 -24
  4. package/crates/naome-cli/Cargo.toml +1 -1
  5. package/crates/naome-cli/src/context_commands.rs +47 -0
  6. package/crates/naome-cli/src/dispatcher.rs +6 -0
  7. package/crates/naome-cli/src/main.rs +43 -6
  8. package/crates/naome-cli/src/quality_commands.rs +31 -46
  9. package/crates/naome-cli/src/quality_output.rs +34 -0
  10. package/crates/naome-cli/src/quality_reconcile_command.rs +45 -0
  11. package/crates/naome-cli/src/repository_model_commands.rs +84 -0
  12. package/crates/naome-cli/src/task_commands.rs +62 -0
  13. package/crates/naome-cli/src/workflow_commands.rs +100 -3
  14. package/crates/naome-core/Cargo.toml +1 -1
  15. package/crates/naome-core/src/context/helpers.rs +75 -0
  16. package/crates/naome-core/src/context/select.rs +134 -0
  17. package/crates/naome-core/src/context/types.rs +43 -0
  18. package/crates/naome-core/src/context.rs +6 -0
  19. package/crates/naome-core/src/decision/states.rs +1 -1
  20. package/crates/naome-core/src/decision.rs +4 -1
  21. package/crates/naome-core/src/install_plan.rs +18 -0
  22. package/crates/naome-core/src/intent/resolver_catalog/active.rs +38 -0
  23. package/crates/naome-core/src/intent/resolver_catalog/baseline.rs +44 -0
  24. package/crates/naome-core/src/intent/resolver_catalog/completed.rs +56 -0
  25. package/crates/naome-core/src/intent/resolver_catalog/dirty.rs +32 -0
  26. package/crates/naome-core/src/intent/resolver_catalog/ready.rs +32 -0
  27. package/crates/naome-core/src/intent/resolver_catalog/system.rs +20 -0
  28. package/crates/naome-core/src/intent/resolver_catalog.rs +12 -166
  29. package/crates/naome-core/src/journal.rs +2 -7
  30. package/crates/naome-core/src/lib.rs +33 -10
  31. package/crates/naome-core/src/quality/adapter_ios.rs +131 -0
  32. package/crates/naome-core/src/quality/adapter_support.rs +67 -0
  33. package/crates/naome-core/src/quality/adapters.rs +81 -18
  34. package/crates/naome-core/src/quality/cache.rs +7 -9
  35. package/crates/naome-core/src/quality/checks/duplicate_blocks.rs +4 -7
  36. package/crates/naome-core/src/quality/config.rs +21 -3
  37. package/crates/naome-core/src/quality/mod.rs +138 -7
  38. package/crates/naome-core/src/quality/reconcile.rs +138 -0
  39. package/crates/naome-core/src/quality/reconcile_anchors.rs +64 -0
  40. package/crates/naome-core/src/quality/scanner/analysis.rs +20 -5
  41. package/crates/naome-core/src/quality/scanner.rs +62 -17
  42. package/crates/naome-core/src/quality/semantic/checks.rs +17 -0
  43. package/crates/naome-core/src/quality/semantic/route.rs +1 -1
  44. package/crates/naome-core/src/quality/structure/adapter_ios.rs +149 -0
  45. package/crates/naome-core/src/quality/structure/adapters.rs +60 -42
  46. package/crates/naome-core/src/quality/structure/checks/directory.rs +6 -4
  47. package/crates/naome-core/src/quality/structure/classify/roles.rs +51 -5
  48. package/crates/naome-core/src/quality/structure/config.rs +24 -3
  49. package/crates/naome-core/src/quality/structure/mod.rs +3 -0
  50. package/crates/naome-core/src/quality/types.rs +20 -1
  51. package/crates/naome-core/src/repository_model/detect.rs +188 -0
  52. package/crates/naome-core/src/repository_model/explain.rs +121 -0
  53. package/crates/naome-core/src/repository_model/path_scan.rs +67 -0
  54. package/crates/naome-core/src/repository_model/path_support.rs +59 -0
  55. package/crates/naome-core/src/repository_model/types.rs +152 -0
  56. package/crates/naome-core/src/repository_model/world.rs +48 -0
  57. package/crates/naome-core/src/repository_model/world_adapters.rs +145 -0
  58. package/crates/naome-core/src/repository_model/world_path_facts.rs +55 -0
  59. package/crates/naome-core/src/repository_model/world_paths.rs +168 -0
  60. package/crates/naome-core/src/repository_model.rs +164 -0
  61. package/crates/naome-core/src/route/builtin_checks.rs +40 -1
  62. package/crates/naome-core/src/task_ledger/import.rs +142 -0
  63. package/crates/naome-core/src/task_ledger/model.rs +13 -0
  64. package/crates/naome-core/src/task_ledger/proof_record.rs +52 -0
  65. package/crates/naome-core/src/task_ledger/read.rs +118 -0
  66. package/crates/naome-core/src/task_ledger/render.rs +55 -0
  67. package/crates/naome-core/src/task_ledger/write.rs +38 -0
  68. package/crates/naome-core/src/task_ledger.rs +48 -0
  69. package/crates/naome-core/src/task_state/api.rs +4 -2
  70. package/crates/naome-core/src/task_state/completed_refresh.rs +5 -16
  71. package/crates/naome-core/src/task_state/diff.rs +2 -2
  72. package/crates/naome-core/src/task_state/evidence.rs +8 -3
  73. package/crates/naome-core/src/task_state/mod.rs +1 -1
  74. package/crates/naome-core/src/task_state/progress.rs +13 -0
  75. package/crates/naome-core/src/task_state/proof_model.rs +8 -8
  76. package/crates/naome-core/src/task_state/repair.rs +2 -2
  77. package/crates/naome-core/src/task_state/task_diff_api.rs +9 -18
  78. package/crates/naome-core/src/task_state/types.rs +24 -0
  79. package/crates/naome-core/src/verification.rs +29 -18
  80. package/crates/naome-core/src/workflow/agent/capability.rs +194 -0
  81. package/crates/naome-core/src/workflow/agent/context_delta.rs +42 -0
  82. package/crates/naome-core/src/workflow/agent/decision.rs +32 -0
  83. package/crates/naome-core/src/workflow/agent/execution.rs +80 -0
  84. package/crates/naome-core/src/workflow/agent/proof.rs +24 -0
  85. package/crates/naome-core/src/workflow/agent/support.rs +58 -0
  86. package/crates/naome-core/src/workflow/agent/watchdog.rs +47 -0
  87. package/crates/naome-core/src/workflow/agent.rs +34 -0
  88. package/crates/naome-core/src/workflow/agent_types.rs +105 -0
  89. package/crates/naome-core/src/workflow/doctor.rs +39 -0
  90. package/crates/naome-core/src/workflow/mod.rs +11 -0
  91. package/crates/naome-core/src/workflow/output.rs +8 -2
  92. package/crates/naome-core/src/workflow/phase_inference.rs +1 -1
  93. package/crates/naome-core/tests/context.rs +99 -0
  94. package/crates/naome-core/tests/harness_health.rs +33 -40
  95. package/crates/naome-core/tests/install_plan.rs +12 -0
  96. package/crates/naome-core/tests/quality.rs +178 -2
  97. package/crates/naome-core/tests/quality_performance.rs +39 -2
  98. package/crates/naome-core/tests/quality_structure_adapters.rs +39 -0
  99. package/crates/naome-core/tests/repo_support/mod.rs +7 -1
  100. package/crates/naome-core/tests/repo_support/verification_values.rs +148 -1
  101. package/crates/naome-core/tests/repository_model.rs +281 -0
  102. package/crates/naome-core/tests/route_user_diff.rs +49 -1
  103. package/crates/naome-core/tests/semantic_legacy.rs +72 -38
  104. package/crates/naome-core/tests/task_ledger.rs +328 -0
  105. package/crates/naome-core/tests/task_state.rs +34 -14
  106. package/crates/naome-core/tests/task_state_support/mod.rs +2 -1
  107. package/crates/naome-core/tests/task_state_support/states.rs +28 -11
  108. package/crates/naome-core/tests/verification.rs +14 -39
  109. package/crates/naome-core/tests/verification_contract.rs +6 -52
  110. package/crates/naome-core/tests/workflow_agent.rs +233 -0
  111. package/crates/naome-core/tests/workflow_agent_support/mod.rs +159 -0
  112. package/crates/naome-core/tests/workflow_doctor.rs +21 -0
  113. package/crates/naome-core/tests/workflow_integrity.rs +2 -20
  114. package/crates/naome-core/tests/workflow_support/mod.rs +59 -20
  115. package/installer/codex-hooks.js +121 -0
  116. package/installer/context.js +10 -0
  117. package/installer/filesystem.js +4 -0
  118. package/installer/flows.js +8 -4
  119. package/installer/harness-files.js +6 -0
  120. package/installer/install-plan.js +4 -0
  121. package/installer/main.js +1 -1
  122. package/installer/native.js +1 -1
  123. package/native/darwin-arm64/naome +0 -0
  124. package/native/linux-x64/naome +0 -0
  125. package/package.json +1 -1
  126. package/templates/naome-root/.codex/config.toml +2 -0
  127. package/templates/naome-root/.codex/hooks.json +70 -0
  128. package/templates/naome-root/.naome/bin/check-harness-health.js +8 -6
  129. package/templates/naome-root/.naome/bin/check-task-state.js +12 -7
  130. package/templates/naome-root/.naome/bin/codex-hook-io.js +122 -0
  131. package/templates/naome-root/.naome/bin/codex-hook-policy.js +180 -0
  132. package/templates/naome-root/.naome/bin/codex-hook-runtime.js +174 -0
  133. package/templates/naome-root/.naome/bin/codex-hook.js +6 -0
  134. package/templates/naome-root/.naome/bin/naome.js +35 -4
  135. package/templates/naome-root/.naome/manifest.json +12 -6
  136. package/templates/naome-root/.naome/repository-model.json +6 -0
  137. package/templates/naome-root/.naome/repository-quality.json +3 -1
  138. package/templates/naome-root/.naome/verification.json +15 -1
  139. package/templates/naome-root/AGENTS.md +38 -83
  140. package/templates/naome-root/docs/naome/agent-workflow.md +54 -18
  141. package/templates/naome-root/docs/naome/codex-hooks.md +82 -0
  142. package/templates/naome-root/docs/naome/context-economy.md +73 -0
  143. package/templates/naome-root/docs/naome/first-run.md +25 -14
  144. package/templates/naome-root/docs/naome/index.md +18 -10
  145. package/templates/naome-root/docs/naome/repository-model.md +92 -0
  146. package/templates/naome-root/docs/naome/repository-quality.md +47 -7
  147. package/templates/naome-root/docs/naome/repository-structure.md +10 -3
  148. package/templates/naome-root/docs/naome/task-ledger.md +71 -0
  149. package/templates/naome-root/docs/naome/testing.md +16 -3
@@ -0,0 +1,80 @@
1
+ use std::path::Path;
2
+
3
+ use serde_json::Value;
4
+
5
+ use crate::models::NaomeError;
6
+ use crate::workflow::agent_types::{ExecutionPlanLedger, ExecutionPlanStep};
7
+
8
+ use super::support::{read_task_state, required_context};
9
+
10
+ pub fn execution_plan(
11
+ root: &Path,
12
+ changed_paths: &[String],
13
+ ) -> Result<ExecutionPlanLedger, NaomeError> {
14
+ let task_state = read_task_state(root)?;
15
+ let status = task_state
16
+ .get("status")
17
+ .and_then(Value::as_str)
18
+ .unwrap_or("invalid")
19
+ .to_string();
20
+ let mut steps = vec![read_context_step(root)];
21
+
22
+ let task_paths = changed_paths
23
+ .iter()
24
+ .filter(|path| path.as_str() != ".naome/task-state.json")
25
+ .cloned()
26
+ .collect::<Vec<_>>();
27
+ if !task_paths.is_empty() {
28
+ steps.push(path_quality_step(&task_paths));
29
+ }
30
+ steps.push(task_state_step(&status));
31
+
32
+ Ok(ExecutionPlanLedger {
33
+ task_state: status,
34
+ changed_paths: changed_paths.to_vec(),
35
+ steps,
36
+ })
37
+ }
38
+
39
+ fn read_context_step(root: &Path) -> ExecutionPlanStep {
40
+ ExecutionPlanStep {
41
+ id: "read-required-context".to_string(),
42
+ phase: "shape".to_string(),
43
+ paths: required_context(root),
44
+ commands: Vec::new(),
45
+ reason_codes: vec!["token-economy".to_string()],
46
+ }
47
+ }
48
+
49
+ fn path_quality_step(changed_paths: &[String]) -> ExecutionPlanStep {
50
+ ExecutionPlanStep {
51
+ id: "run-path-quality".to_string(),
52
+ phase: "quality".to_string(),
53
+ paths: changed_paths.to_vec(),
54
+ commands: changed_paths
55
+ .iter()
56
+ .map(|path| format!("node .naome/bin/naome.js quality check --path {path}"))
57
+ .collect(),
58
+ reason_codes: vec!["early-touched-file-gate".to_string()],
59
+ }
60
+ }
61
+
62
+ fn task_state_step(status: &str) -> ExecutionPlanStep {
63
+ let implementing = status == "implementing";
64
+ ExecutionPlanStep {
65
+ id: if implementing {
66
+ "run-progress-gate"
67
+ } else {
68
+ "run-admission-or-status"
69
+ }
70
+ .to_string(),
71
+ phase: "shape".to_string(),
72
+ paths: vec![".naome/task-state.json".to_string()],
73
+ commands: vec![if implementing {
74
+ "node .naome/bin/check-task-state.js --progress".to_string()
75
+ } else {
76
+ "node .naome/bin/check-task-state.js --admission".to_string()
77
+ }],
78
+ reason_codes: vec!["scope-drift-prevention".to_string()],
79
+ }
80
+ }
@@ -0,0 +1,24 @@
1
+ use std::path::Path;
2
+
3
+ use crate::models::NaomeError;
4
+
5
+ use super::support::changed_paths;
6
+ use crate::workflow::agent_types::ProofPlan;
7
+ use crate::workflow::phases::{verification_phase_plan, CommandCheckResult};
8
+
9
+ pub fn proof_plan_for_task(
10
+ root: &Path,
11
+ completed: &[CommandCheckResult],
12
+ ) -> Result<ProofPlan, NaomeError> {
13
+ let phase_plan = verification_phase_plan(root, completed)?;
14
+ Ok(ProofPlan {
15
+ schema: "naome.proof-plan.v1".to_string(),
16
+ recommended_check_ids: phase_plan.recommended_check_ids,
17
+ withheld_check_ids: phase_plan.withheld_check_ids,
18
+ evidence_paths: changed_paths(root)?
19
+ .into_iter()
20
+ .filter(|path| path != ".naome/task-state.json")
21
+ .collect(),
22
+ reason_codes: vec!["phase-ordered-minimal-proof".to_string()],
23
+ })
24
+ }
@@ -0,0 +1,58 @@
1
+ use std::collections::BTreeSet;
2
+ use std::path::Path;
3
+
4
+ use serde_json::Value;
5
+
6
+ use crate::git;
7
+ use crate::models::NaomeError;
8
+ use crate::task_ledger::read_task_state_projection;
9
+
10
+ pub(super) fn required_context(root: &Path) -> Vec<String> {
11
+ let mut paths = vec![
12
+ ".naome/task-state.json".to_string(),
13
+ ".naome/verification.json".to_string(),
14
+ "docs/naome/testing.md".to_string(),
15
+ ];
16
+ if root.join("docs/naome/context-economy.md").is_file() {
17
+ paths.push("docs/naome/context-economy.md".to_string());
18
+ }
19
+ paths
20
+ }
21
+
22
+ pub(super) fn read_task_state(root: &Path) -> Result<Value, NaomeError> {
23
+ Ok(read_task_state_projection(root)?.unwrap_or(Value::Null))
24
+ }
25
+
26
+ pub(super) fn active_allowed_paths(root: &Path) -> Result<Vec<String>, NaomeError> {
27
+ let task_state = read_task_state(root)?;
28
+ Ok(task_state
29
+ .get("activeTask")
30
+ .and_then(|task| task.get("allowedPaths"))
31
+ .and_then(Value::as_array)
32
+ .into_iter()
33
+ .flatten()
34
+ .filter_map(Value::as_str)
35
+ .map(ToString::to_string)
36
+ .collect())
37
+ }
38
+
39
+ pub(super) fn changed_paths(root: &Path) -> Result<Vec<String>, NaomeError> {
40
+ Ok(git::changed_paths(root)
41
+ .unwrap_or_default()
42
+ .into_iter()
43
+ .filter(|path| !path.trim().is_empty())
44
+ .collect())
45
+ }
46
+
47
+ pub(super) fn normalize_paths(paths: &[String]) -> Vec<String> {
48
+ paths
49
+ .iter()
50
+ .map(|path| normalize_path(path))
51
+ .collect::<BTreeSet<_>>()
52
+ .into_iter()
53
+ .collect()
54
+ }
55
+
56
+ pub(super) fn normalize_path(path: &str) -> String {
57
+ path.trim_start_matches("./").replace('\\', "/")
58
+ }
@@ -0,0 +1,47 @@
1
+ use std::path::Path;
2
+
3
+ use crate::models::NaomeError;
4
+ use crate::paths;
5
+ use crate::workflow::agent_types::EditSessionWatchdog;
6
+ use crate::workflow::types::WorkflowFinding;
7
+
8
+ use super::support::{active_allowed_paths, normalize_paths};
9
+
10
+ pub fn edit_session_watchdog(
11
+ root: &Path,
12
+ touched_paths: &[String],
13
+ ) -> Result<EditSessionWatchdog, NaomeError> {
14
+ let touched_paths = normalize_paths(touched_paths)
15
+ .into_iter()
16
+ .filter(|path| path != ".naome/task-state.json")
17
+ .collect::<Vec<_>>();
18
+ let allowed_paths = active_allowed_paths(root)?;
19
+ let out_of_scope = touched_paths
20
+ .iter()
21
+ .filter(|path| !allowed_paths.is_empty() && !paths::matches_any(path, &allowed_paths))
22
+ .cloned()
23
+ .collect::<Vec<_>>();
24
+ let mut next_commands = touched_paths
25
+ .iter()
26
+ .map(|path| format!("node .naome/bin/naome.js quality check --path {path}"))
27
+ .collect::<Vec<_>>();
28
+ next_commands.push("node .naome/bin/check-task-state.js --progress".to_string());
29
+
30
+ let findings = if out_of_scope.is_empty() {
31
+ Vec::new()
32
+ } else {
33
+ vec![WorkflowFinding::blocking(
34
+ "scope-drift",
35
+ "Touched paths are outside the active task scope.",
36
+ out_of_scope,
37
+ None,
38
+ )]
39
+ };
40
+
41
+ Ok(EditSessionWatchdog {
42
+ schema: "naome.edit-session-watchdog.v1".to_string(),
43
+ touched_paths,
44
+ next_commands,
45
+ findings,
46
+ })
47
+ }
@@ -0,0 +1,34 @@
1
+ mod capability;
2
+ mod context_delta;
3
+ mod decision;
4
+ mod execution;
5
+ mod proof;
6
+ mod support;
7
+ mod watchdog;
8
+
9
+ use std::path::Path;
10
+
11
+ use crate::models::NaomeError;
12
+
13
+ use super::agent_types::AgentRunPlan;
14
+ use super::phases::CommandCheckResult;
15
+
16
+ pub use capability::repository_capability_graph;
17
+ pub use context_delta::context_delta_report;
18
+ pub use decision::decision_gate;
19
+ pub use execution::execution_plan;
20
+ pub use proof::proof_plan_for_task;
21
+ pub use watchdog::edit_session_watchdog;
22
+
23
+ pub fn agent_run_plan(root: &Path) -> Result<AgentRunPlan, NaomeError> {
24
+ let changed_paths = support::changed_paths(root)?;
25
+ Ok(AgentRunPlan {
26
+ schema: "naome.agent-run-plan.v1".to_string(),
27
+ execution_plan: execution_plan(root, &changed_paths)?,
28
+ context_delta: context_delta_report(root, &[])?,
29
+ proof_plan: proof_plan_for_task(root, &[] as &[CommandCheckResult])?,
30
+ capability_graph: repository_capability_graph(root)?,
31
+ edit_watchdog: edit_session_watchdog(root, &changed_paths)?,
32
+ decision_gate: decision_gate(root)?,
33
+ })
34
+ }
@@ -0,0 +1,105 @@
1
+ use serde::{Deserialize, Serialize};
2
+
3
+ use super::types::WorkflowFinding;
4
+
5
+ #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
6
+ #[serde(rename_all = "camelCase")]
7
+ pub struct AgentRunPlan {
8
+ pub schema: String,
9
+ pub execution_plan: ExecutionPlanLedger,
10
+ pub context_delta: ContextDeltaReport,
11
+ pub proof_plan: ProofPlan,
12
+ pub capability_graph: CapabilityGraph,
13
+ pub edit_watchdog: EditSessionWatchdog,
14
+ pub decision_gate: DecisionGate,
15
+ }
16
+
17
+ #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
18
+ #[serde(rename_all = "camelCase")]
19
+ pub struct ExecutionPlanLedger {
20
+ pub task_state: String,
21
+ pub changed_paths: Vec<String>,
22
+ pub steps: Vec<ExecutionPlanStep>,
23
+ }
24
+
25
+ #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
26
+ #[serde(rename_all = "camelCase")]
27
+ pub struct ExecutionPlanStep {
28
+ pub id: String,
29
+ pub phase: String,
30
+ pub paths: Vec<String>,
31
+ pub commands: Vec<String>,
32
+ pub reason_codes: Vec<String>,
33
+ }
34
+
35
+ #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
36
+ #[serde(rename_all = "camelCase")]
37
+ pub struct ContextDeltaReport {
38
+ pub schema: String,
39
+ pub reusable_context: Vec<String>,
40
+ pub stale_context: Vec<String>,
41
+ pub unread_required_context: Vec<String>,
42
+ pub reason_codes: Vec<String>,
43
+ }
44
+
45
+ #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
46
+ #[serde(rename_all = "camelCase")]
47
+ pub struct ProofPlan {
48
+ pub schema: String,
49
+ pub recommended_check_ids: Vec<String>,
50
+ pub withheld_check_ids: Vec<String>,
51
+ pub evidence_paths: Vec<String>,
52
+ pub reason_codes: Vec<String>,
53
+ }
54
+
55
+ #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
56
+ #[serde(rename_all = "camelCase")]
57
+ pub struct CapabilityGraph {
58
+ pub schema: String,
59
+ pub capabilities: Vec<RepositoryCapability>,
60
+ pub roots: Vec<CapabilityRoot>,
61
+ pub verification_edges: Vec<VerificationEdge>,
62
+ }
63
+
64
+ #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
65
+ #[serde(rename_all = "camelCase")]
66
+ pub struct RepositoryCapability {
67
+ pub id: String,
68
+ pub kind: String,
69
+ pub value: String,
70
+ pub evidence: Vec<String>,
71
+ }
72
+
73
+ #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
74
+ #[serde(rename_all = "camelCase")]
75
+ pub struct CapabilityRoot {
76
+ pub role: String,
77
+ pub path: String,
78
+ }
79
+
80
+ #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
81
+ #[serde(rename_all = "camelCase")]
82
+ pub struct VerificationEdge {
83
+ pub check_id: String,
84
+ pub command: String,
85
+ pub evidence: Vec<String>,
86
+ }
87
+
88
+ #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
89
+ #[serde(rename_all = "camelCase")]
90
+ pub struct EditSessionWatchdog {
91
+ pub schema: String,
92
+ pub touched_paths: Vec<String>,
93
+ pub next_commands: Vec<String>,
94
+ pub findings: Vec<WorkflowFinding>,
95
+ }
96
+
97
+ #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
98
+ #[serde(rename_all = "camelCase")]
99
+ pub struct DecisionGate {
100
+ pub schema: String,
101
+ pub action: String,
102
+ pub reason_codes: Vec<String>,
103
+ pub human_options: Vec<String>,
104
+ pub next_action: String,
105
+ }
@@ -5,6 +5,7 @@ use serde::Serialize;
5
5
 
6
6
  use crate::harness_health::{validate_harness_health, HarnessHealthOptions};
7
7
  use crate::models::NaomeError;
8
+ use crate::repository_model_drift;
8
9
  use crate::task_state::{validate_task_state, TaskStateMode, TaskStateOptions};
9
10
  use crate::verification_contract::validate_verification_contract;
10
11
 
@@ -18,6 +19,7 @@ pub struct DoctorReport {
18
19
  pub harness_health: DoctorSection,
19
20
  pub task_state: DoctorSection,
20
21
  pub verification: DoctorSection,
22
+ pub repository_model: RepositoryPolicySection,
21
23
  pub repository_quality: RepositoryPolicySection,
22
24
  pub repository_structure: RepositoryPolicySection,
23
25
  pub recommended_check_ids: Vec<String>,
@@ -38,6 +40,7 @@ pub struct RepositoryPolicySection {
38
40
  pub config_present: bool,
39
41
  pub baseline_present: bool,
40
42
  pub status: String,
43
+ pub messages: Vec<String>,
41
44
  }
42
45
 
43
46
  pub fn doctor_report(root: &Path) -> Result<DoctorReport, NaomeError> {
@@ -59,6 +62,7 @@ pub fn doctor_report(root: &Path) -> Result<DoctorReport, NaomeError> {
59
62
  let verification_errors = validate_verification_contract(root)?;
60
63
  let phase_plan = verification_phase_plan(root, &[])?;
61
64
 
65
+ let repository_model = repository_model_section(root)?;
62
66
  let repository_quality = policy_section(
63
67
  root,
64
68
  ".naome/repository-quality.json",
@@ -72,12 +76,14 @@ pub fn doctor_report(root: &Path) -> Result<DoctorReport, NaomeError> {
72
76
  let ok = harness_health.status == "ok"
73
77
  && task_state.status == "ok"
74
78
  && verification.status == "ok"
79
+ && repository_model.status == "ok"
75
80
  && repository_quality.status == "ok"
76
81
  && repository_structure.status == "ok";
77
82
  let next_action = next_action(
78
83
  &harness_health,
79
84
  &task_state,
80
85
  &verification,
86
+ &repository_model,
81
87
  &repository_quality,
82
88
  &repository_structure,
83
89
  );
@@ -88,6 +94,7 @@ pub fn doctor_report(root: &Path) -> Result<DoctorReport, NaomeError> {
88
94
  harness_health,
89
95
  task_state,
90
96
  verification,
97
+ repository_model,
91
98
  repository_quality,
92
99
  repository_structure,
93
100
  recommended_check_ids: phase_plan.recommended_check_ids,
@@ -117,13 +124,38 @@ fn policy_section(root: &Path, config_path: &str, baseline_path: &str) -> Reposi
117
124
  "missing"
118
125
  }
119
126
  .to_string(),
127
+ messages: Vec::new(),
120
128
  }
121
129
  }
122
130
 
131
+ fn repository_model_section(root: &Path) -> Result<RepositoryPolicySection, NaomeError> {
132
+ let drift = repository_model_drift(root)?;
133
+ let config_present = drift.model_present;
134
+ let status = if !config_present {
135
+ "missing"
136
+ } else if drift.stale {
137
+ "stale"
138
+ } else {
139
+ "ok"
140
+ };
141
+ let messages = if !config_present {
142
+ vec!["NAOME repository model is missing; run naome repo model --write.".to_string()]
143
+ } else {
144
+ drift.messages
145
+ };
146
+ Ok(RepositoryPolicySection {
147
+ config_present,
148
+ baseline_present: true,
149
+ status: status.to_string(),
150
+ messages,
151
+ })
152
+ }
153
+
123
154
  fn next_action(
124
155
  harness_health: &DoctorSection,
125
156
  task_state: &DoctorSection,
126
157
  verification: &DoctorSection,
158
+ repository_model: &RepositoryPolicySection,
127
159
  repository_quality: &RepositoryPolicySection,
128
160
  repository_structure: &RepositoryPolicySection,
129
161
  ) -> String {
@@ -136,6 +168,13 @@ fn next_action(
136
168
  if verification.status != "ok" {
137
169
  return "Fix .naome/verification.json before relying on gates.".to_string();
138
170
  }
171
+ if repository_model.status == "stale" {
172
+ return "Run naome repo model --write to refresh deterministic repository facts."
173
+ .to_string();
174
+ }
175
+ if repository_model.status != "ok" {
176
+ return "Run naome repo model --write to seed deterministic repository facts.".to_string();
177
+ }
139
178
  if repository_quality.status != "ok" || repository_structure.status != "ok" {
140
179
  return "Run naome quality init or naome sync to seed repository quality policy."
141
180
  .to_string();
@@ -1,3 +1,5 @@
1
+ mod agent;
2
+ mod agent_types;
1
3
  mod doctor;
2
4
  mod integrity;
3
5
  mod integrity_normalize;
@@ -10,6 +12,15 @@ mod policy;
10
12
  mod processes;
11
13
  mod types;
12
14
 
15
+ pub use agent::{
16
+ agent_run_plan, context_delta_report, decision_gate, edit_session_watchdog,
17
+ proof_plan_for_task, repository_capability_graph,
18
+ };
19
+ pub use agent_types::{
20
+ AgentRunPlan, CapabilityGraph, CapabilityRoot, ContextDeltaReport, DecisionGate,
21
+ EditSessionWatchdog, ExecutionPlanLedger, ExecutionPlanStep, ProofPlan, RepositoryCapability,
22
+ VerificationEdge,
23
+ };
13
24
  pub use doctor::{doctor_report, DoctorReport, DoctorSection, RepositoryPolicySection};
14
25
  pub use integrity::{refresh_integrity, IntegrityRefreshReport};
15
26
  pub use mutation::classify_mutations;
@@ -71,6 +71,8 @@ fn is_relevant_line(line: &str) -> bool {
71
71
  "outside allowedpaths",
72
72
  "denied",
73
73
  "missing",
74
+ ".log",
75
+ "artifact",
74
76
  ]
75
77
  .iter()
76
78
  .any(|needle| lower.contains(needle))
@@ -86,8 +88,12 @@ fn collect_paths(lines: &[String]) -> Vec<String> {
86
88
  '"' | '\'' | '`' | ':' | ',' | ';' | '(' | ')' | '[' | ']'
87
89
  )
88
90
  });
89
- if looks_like_path(cleaned) {
90
- paths.insert(cleaned.replace('\\', "/"));
91
+ let path_token = cleaned
92
+ .split_once(':')
93
+ .map(|(path, _)| path)
94
+ .unwrap_or(cleaned);
95
+ if looks_like_path(path_token) {
96
+ paths.insert(path_token.replace('\\', "/"));
91
97
  }
92
98
  }
93
99
  }
@@ -54,7 +54,7 @@ fn inferred_phase<'a>(check: &'a CheckDefinition, release_gate_ids: &HashSet<&st
54
54
  if id == "diff-check" || command.contains("diff --check") {
55
55
  return "diff-check";
56
56
  }
57
- if id.contains("quality") {
57
+ if id.contains("quality") || id.contains("semantic") {
58
58
  return "quality";
59
59
  }
60
60
  if id.contains("health") || id.contains("task-state") || command.contains("check-task-state") {
@@ -0,0 +1,99 @@
1
+ mod repo_support;
2
+
3
+ use naome_core::{select_context_for_changed_paths, select_context_for_prompt};
4
+
5
+ use repo_support::{verification_value, TestRepo};
6
+
7
+ #[test]
8
+ fn changed_context_selects_touched_files_and_compact_quality_capsule() {
9
+ let repo = context_repo("context-changed-quality");
10
+ repo.write_file("packages/tool/src/quality/scanner.rs", "pub fn scan() {}\n");
11
+ repo.write_file("docs/naome/testing.md", "# Testing\n");
12
+ repo.commit_all("baseline");
13
+ repo.write_file(
14
+ "packages/tool/src/quality/scanner.rs",
15
+ "pub fn scan() {}\npub fn changed() {}\n",
16
+ );
17
+ repo.write_file("docs/naome/testing.md", "# Testing\n\nchanged\n");
18
+
19
+ let selection = select_context_for_changed_paths(repo.path()).unwrap();
20
+
21
+ assert_eq!(selection.schema, "naome.context-selection.v1");
22
+ assert_eq!(selection.mode, "changed");
23
+ assert_eq!(selection.capsule.id, "quality-work");
24
+ assert!(selection.required_context.iter().any(|item| {
25
+ item.path == "packages/tool/src/quality/scanner.rs" && item.reason == "changed_path"
26
+ }));
27
+ assert!(selection.commands.iter().any(|command| {
28
+ command == "node .naome/bin/naome.js quality check --path packages/tool/src/quality/scanner.rs"
29
+ }));
30
+ assert!(selection
31
+ .commands
32
+ .contains(&"node .naome/bin/naome.js quality check --changed".to_string()));
33
+ assert!(selection
34
+ .forbidden_context
35
+ .contains(&".naome/archive/**".to_string()));
36
+ assert!(selection.budget_ledger.selected_files < 6);
37
+ assert!(selection.budget_ledger.estimated_tokens > 0);
38
+ }
39
+
40
+ #[test]
41
+ fn prompt_context_uses_file_mentions_without_broad_markdown_context() {
42
+ let repo = context_repo("context-prompt-paths");
43
+ repo.write_file("packages/app/src/lib.rs", "pub fn app() {}\n");
44
+ repo.write_file("docs/naome/repository-quality.md", "# Quality\n");
45
+ repo.commit_all("baseline");
46
+
47
+ let selection = select_context_for_prompt(
48
+ repo.path(),
49
+ "Please update packages/app/src/lib.rs and run a path-scoped quality check.",
50
+ )
51
+ .unwrap();
52
+
53
+ assert_eq!(selection.mode, "prompt");
54
+ assert_eq!(selection.capsule.id, "source-work");
55
+ assert_eq!(
56
+ selection.required_context[0].path,
57
+ "packages/app/src/lib.rs"
58
+ );
59
+ assert!(!selection
60
+ .required_context
61
+ .iter()
62
+ .any(|item| item.path == "docs/naome/repository-quality.md"));
63
+ assert!(selection
64
+ .optional_context
65
+ .iter()
66
+ .any(|item| item.path == "docs/naome/repository-quality.md"));
67
+ }
68
+
69
+ #[test]
70
+ fn context_selection_reports_over_budget_when_many_paths_change() {
71
+ let repo = context_repo("context-budget");
72
+ for index in 0..20 {
73
+ repo.write_file(&format!("src/file_{index}.rs"), "pub fn before() {}\n");
74
+ }
75
+ repo.commit_all("baseline");
76
+ for index in 0..20 {
77
+ repo.write_file(&format!("src/file_{index}.rs"), "pub fn after() {}\n");
78
+ }
79
+
80
+ let selection = select_context_for_changed_paths(repo.path()).unwrap();
81
+
82
+ assert_eq!(selection.budget_ledger.selected_files, 12);
83
+ assert!(selection.budget_ledger.avoided_files >= 8);
84
+ assert!(selection
85
+ .budget_ledger
86
+ .reason_codes
87
+ .contains(&"context_file_budget_reached".to_string()));
88
+ }
89
+
90
+ fn context_repo(name: &str) -> TestRepo {
91
+ let repo = TestRepo::new(name);
92
+ repo.init_git();
93
+ repo.write_file(".naomeignore", ".naome/archive/\n.naome/cache/\n");
94
+ repo.write_naome_json(
95
+ "verification.json",
96
+ verification_value("ready", vec![], vec![]),
97
+ );
98
+ repo
99
+ }