@lamentis/naome 1.3.0 → 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.
Files changed (137) 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/journal.rs +2 -7
  23. package/crates/naome-core/src/lib.rs +33 -10
  24. package/crates/naome-core/src/quality/adapter_ios.rs +131 -0
  25. package/crates/naome-core/src/quality/adapter_support.rs +67 -0
  26. package/crates/naome-core/src/quality/adapters.rs +81 -18
  27. package/crates/naome-core/src/quality/cache.rs +7 -9
  28. package/crates/naome-core/src/quality/checks/duplicate_blocks.rs +4 -7
  29. package/crates/naome-core/src/quality/config.rs +21 -3
  30. package/crates/naome-core/src/quality/mod.rs +138 -7
  31. package/crates/naome-core/src/quality/reconcile.rs +138 -0
  32. package/crates/naome-core/src/quality/reconcile_anchors.rs +64 -0
  33. package/crates/naome-core/src/quality/scanner/analysis.rs +20 -5
  34. package/crates/naome-core/src/quality/scanner.rs +62 -17
  35. package/crates/naome-core/src/quality/semantic/checks.rs +17 -0
  36. package/crates/naome-core/src/quality/semantic/route.rs +1 -1
  37. package/crates/naome-core/src/quality/structure/adapter_ios.rs +149 -0
  38. package/crates/naome-core/src/quality/structure/adapters.rs +60 -42
  39. package/crates/naome-core/src/quality/structure/checks/directory.rs +6 -4
  40. package/crates/naome-core/src/quality/structure/classify/roles.rs +51 -5
  41. package/crates/naome-core/src/quality/structure/config.rs +24 -3
  42. package/crates/naome-core/src/quality/structure/mod.rs +3 -0
  43. package/crates/naome-core/src/quality/types.rs +20 -1
  44. package/crates/naome-core/src/repository_model/detect.rs +188 -0
  45. package/crates/naome-core/src/repository_model/explain.rs +121 -0
  46. package/crates/naome-core/src/repository_model/path_scan.rs +67 -0
  47. package/crates/naome-core/src/repository_model/path_support.rs +59 -0
  48. package/crates/naome-core/src/repository_model/types.rs +152 -0
  49. package/crates/naome-core/src/repository_model/world.rs +48 -0
  50. package/crates/naome-core/src/repository_model/world_adapters.rs +145 -0
  51. package/crates/naome-core/src/repository_model/world_path_facts.rs +55 -0
  52. package/crates/naome-core/src/repository_model/world_paths.rs +168 -0
  53. package/crates/naome-core/src/repository_model.rs +164 -0
  54. package/crates/naome-core/src/route/builtin_checks.rs +40 -1
  55. package/crates/naome-core/src/task_ledger/import.rs +142 -0
  56. package/crates/naome-core/src/task_ledger/model.rs +13 -0
  57. package/crates/naome-core/src/task_ledger/proof_record.rs +52 -0
  58. package/crates/naome-core/src/task_ledger/read.rs +118 -0
  59. package/crates/naome-core/src/task_ledger/render.rs +55 -0
  60. package/crates/naome-core/src/task_ledger/write.rs +38 -0
  61. package/crates/naome-core/src/task_ledger.rs +48 -0
  62. package/crates/naome-core/src/task_state/api.rs +4 -2
  63. package/crates/naome-core/src/task_state/completed_refresh.rs +5 -16
  64. package/crates/naome-core/src/task_state/diff.rs +2 -2
  65. package/crates/naome-core/src/task_state/evidence.rs +8 -3
  66. package/crates/naome-core/src/task_state/mod.rs +1 -1
  67. package/crates/naome-core/src/task_state/progress.rs +13 -0
  68. package/crates/naome-core/src/task_state/proof_model.rs +8 -8
  69. package/crates/naome-core/src/task_state/repair.rs +2 -2
  70. package/crates/naome-core/src/task_state/task_diff_api.rs +9 -18
  71. package/crates/naome-core/src/task_state/types.rs +24 -0
  72. package/crates/naome-core/src/verification.rs +29 -18
  73. package/crates/naome-core/src/workflow/agent/capability.rs +194 -0
  74. package/crates/naome-core/src/workflow/agent/context_delta.rs +42 -0
  75. package/crates/naome-core/src/workflow/agent/decision.rs +32 -0
  76. package/crates/naome-core/src/workflow/agent/execution.rs +80 -0
  77. package/crates/naome-core/src/workflow/agent/proof.rs +24 -0
  78. package/crates/naome-core/src/workflow/agent/support.rs +58 -0
  79. package/crates/naome-core/src/workflow/agent/watchdog.rs +47 -0
  80. package/crates/naome-core/src/workflow/agent.rs +34 -0
  81. package/crates/naome-core/src/workflow/agent_types.rs +105 -0
  82. package/crates/naome-core/src/workflow/doctor.rs +39 -0
  83. package/crates/naome-core/src/workflow/mod.rs +11 -0
  84. package/crates/naome-core/src/workflow/output.rs +8 -2
  85. package/crates/naome-core/src/workflow/phase_inference.rs +1 -1
  86. package/crates/naome-core/tests/context.rs +99 -0
  87. package/crates/naome-core/tests/harness_health.rs +4 -0
  88. package/crates/naome-core/tests/install_plan.rs +12 -0
  89. package/crates/naome-core/tests/quality.rs +178 -2
  90. package/crates/naome-core/tests/quality_performance.rs +39 -2
  91. package/crates/naome-core/tests/quality_structure_adapters.rs +39 -0
  92. package/crates/naome-core/tests/repo_support/mod.rs +5 -1
  93. package/crates/naome-core/tests/repo_support/verification_values.rs +55 -0
  94. package/crates/naome-core/tests/repository_model.rs +281 -0
  95. package/crates/naome-core/tests/route_user_diff.rs +49 -1
  96. package/crates/naome-core/tests/semantic_legacy.rs +72 -38
  97. package/crates/naome-core/tests/task_ledger.rs +328 -0
  98. package/crates/naome-core/tests/task_state.rs +28 -0
  99. package/crates/naome-core/tests/verification.rs +29 -36
  100. package/crates/naome-core/tests/workflow_agent.rs +233 -0
  101. package/crates/naome-core/tests/workflow_agent_support/mod.rs +159 -0
  102. package/crates/naome-core/tests/workflow_doctor.rs +21 -0
  103. package/installer/codex-hooks.js +121 -0
  104. package/installer/context.js +10 -0
  105. package/installer/filesystem.js +4 -0
  106. package/installer/flows.js +8 -4
  107. package/installer/harness-files.js +6 -0
  108. package/installer/install-plan.js +4 -0
  109. package/installer/main.js +1 -1
  110. package/installer/native.js +1 -1
  111. package/native/darwin-arm64/naome +0 -0
  112. package/native/linux-x64/naome +0 -0
  113. package/package.json +1 -1
  114. package/templates/naome-root/.codex/config.toml +2 -0
  115. package/templates/naome-root/.codex/hooks.json +70 -0
  116. package/templates/naome-root/.naome/bin/check-harness-health.js +8 -6
  117. package/templates/naome-root/.naome/bin/check-task-state.js +12 -7
  118. package/templates/naome-root/.naome/bin/codex-hook-io.js +122 -0
  119. package/templates/naome-root/.naome/bin/codex-hook-policy.js +180 -0
  120. package/templates/naome-root/.naome/bin/codex-hook-runtime.js +174 -0
  121. package/templates/naome-root/.naome/bin/codex-hook.js +6 -0
  122. package/templates/naome-root/.naome/bin/naome.js +35 -4
  123. package/templates/naome-root/.naome/manifest.json +12 -6
  124. package/templates/naome-root/.naome/repository-model.json +6 -0
  125. package/templates/naome-root/.naome/repository-quality.json +3 -1
  126. package/templates/naome-root/.naome/verification.json +15 -1
  127. package/templates/naome-root/AGENTS.md +38 -83
  128. package/templates/naome-root/docs/naome/agent-workflow.md +54 -18
  129. package/templates/naome-root/docs/naome/codex-hooks.md +82 -0
  130. package/templates/naome-root/docs/naome/context-economy.md +73 -0
  131. package/templates/naome-root/docs/naome/first-run.md +25 -14
  132. package/templates/naome-root/docs/naome/index.md +18 -10
  133. package/templates/naome-root/docs/naome/repository-model.md +92 -0
  134. package/templates/naome-root/docs/naome/repository-quality.md +47 -7
  135. package/templates/naome-root/docs/naome/repository-structure.md +10 -3
  136. package/templates/naome-root/docs/naome/task-ledger.md +71 -0
  137. package/templates/naome-root/docs/naome/testing.md +16 -3
package/Cargo.lock CHANGED
@@ -76,7 +76,7 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
76
76
 
77
77
  [[package]]
78
78
  name = "naome-cli"
79
- version = "1.3.0"
79
+ version = "1.3.1"
80
80
  dependencies = [
81
81
  "naome-core",
82
82
  "serde_json",
@@ -84,7 +84,7 @@ dependencies = [
84
84
 
85
85
  [[package]]
86
86
  name = "naome-core"
87
- version = "1.3.0"
87
+ version = "1.3.1"
88
88
  dependencies = [
89
89
  "serde",
90
90
  "serde_json",
package/README.md CHANGED
@@ -50,6 +50,8 @@ naome route --prompt-file /path/to/prompt.txt --execute --json
50
50
  perfect on day one.
51
51
  - Records verification proof before a task can be treated as complete.
52
52
  - Keeps sync fast by making baseline and deep quality scans explicit.
53
+ - Can install optional Codex hooks for earlier agent feedback without making
54
+ hooks a human workflow requirement.
53
55
 
54
56
  ## Safety Model
55
57
 
@@ -77,12 +79,15 @@ naome quality init --baseline
77
79
  naome quality report
78
80
  naome quality report --deep
79
81
  naome quality check --changed
82
+ naome semantic check --changed
83
+ naome task render-state --write --json
80
84
  naome commit -m "type(scope): summary"
81
85
  ```
82
86
 
83
87
  `naome sync` installs or repairs the local harness files. It does not run a
84
- hidden full-repository quality scan. If quality policy is newly seeded, run
85
- `naome quality init --baseline` deliberately; use `--deep` or
88
+ hidden full-repository quality scan. It also migrates any active legacy
89
+ task-state into the task ledger automatically. If quality policy is newly
90
+ seeded, run `naome quality init --baseline` deliberately; use `--deep` or
86
91
  `--deep-baseline` only when you want expensive repository-wide checks.
87
92
 
88
93
  ## Repository Docs
@@ -94,6 +99,8 @@ After sync, NAOME writes the agent-facing workflow into `docs/naome/`:
94
99
  - `docs/naome/testing.md` maps change types to required checks.
95
100
  - `docs/naome/repository-quality.md` explains quality, structure, and cleanup
96
101
  policy.
102
+ - `docs/naome/codex-hooks.md` explains the optional Codex hook acceleration
103
+ layer.
97
104
 
98
105
  Agents should follow the repository's NAOME docs instead of guessing workflow
99
106
  rules from generic project files.
@@ -109,6 +116,7 @@ The main local policy files are:
109
116
  - `.naome/repository-structure.json` for path role, module, and directory
110
117
  structure policy.
111
118
  - `.naome/task-state.json` for active task state and proof.
119
+ - `.codex/hooks.json` only when optional Codex hooks were explicitly enabled.
112
120
 
113
121
  Product defaults stay generic. Repository-specific policy belongs in the local
114
122
  `.naome/` config files.
@@ -123,6 +131,7 @@ npm run test:decision-engine
123
131
  npm run test:naome-installer
124
132
  npm run pack:dry-run
125
133
  node .naome/bin/naome.js quality check --changed --json
134
+ node .naome/bin/naome.js semantic check --changed --json
126
135
  git diff --check
127
136
  ```
128
137
 
package/bin/naome.js CHANGED
@@ -12,7 +12,7 @@ const packageVersion = packageMetadata.version;
12
12
  const nativeBinaryName = process.platform === "win32" ? "naome.exe" : "naome";
13
13
  const args = process.argv.slice(2);
14
14
  const [command] = args;
15
- const helpCommands = "status [--json]|next [--json]|intent --prompt-file <path> [--json]|intent --prompt <text> [--json]|route --prompt-file <path> [--execute] [--json]|route --prompt <text> [--execute] [--json]|explain --prompt-file <path> [--json]|explain --prompt <text> [--json]|doctor [--json]|install|sync [--check-update]|update [--json] [--execute]|quality init [--baseline|--deep-baseline] [--json]|quality check --changed [--include-scanned-paths] [--json]|quality report [--deep] [--include-scanned-paths] [--json]|quality cache status [--json]|quality cache clear|semantic report [--deep] [--json]|semantic check --changed [--json]|semantic route --finding <id> [--json]|semantic loop [--json]|structure report [--json]|structure explain --path <path> [--json]|cleanup plan [--json]|cleanup route --path <path> [--json]|refresh-integrity [--json]|workflow search-profile|check-search|phases|processes|mutations [--json]|commit -m \"type(scope): message\"".split("|");
15
+ const helpCommands = "status [--json]|next [--json]|intent --prompt-file <path> [--json]|intent --prompt <text> [--json]|route --prompt-file <path> [--execute] [--json]|route --prompt <text> [--execute] [--json]|explain --prompt-file <path> [--json]|explain --prompt <text> [--json]|context select --changed [--json]|context select --prompt-file <path> [--json]|context select --prompt <text> [--json]|doctor [--json]|install|sync [--check-update]|update [--json] [--execute]|task render-state [--write] [--json]|task migrate-ledger [--write] [--json]|quality init [--baseline|--deep-baseline] [--json]|quality reconcile [--write] [--json]|quality check --changed [--include-scanned-paths] [--json]|quality check --path <path> [--path <path>...] [--include-scanned-paths] [--json]|quality report [--deep] [--include-scanned-paths] [--json]|quality cache status [--json]|quality cache clear|semantic report [--deep] [--json]|semantic check --changed [--json]|semantic check --path <path> [--path <path>...] [--json]|semantic route --finding <id> [--json]|semantic loop [--json]|repo model [--write] [--json]|repo check [--json]|repo explain --path <path> [--json]|structure report [--json]|structure explain --path <path> [--json]|cleanup plan [--json]|cleanup route --path <path> [--json]|refresh-integrity [--json]|workflow agent-plan|context-delta|proof-plan|capabilities|edit-watchdog|decision-gate|digest [--json]|workflow search-profile|check-search|phases|processes|mutations [--json]|commit -m \"type(scope): message\"".split("|");
16
16
 
17
17
  if (isHelpRequest(args)) {
18
18
  printHelp();
@@ -31,6 +31,7 @@ if (command === "install" || command === "sync") {
31
31
  const qualityConfigExisted = existsSync(repositoryQualityConfigPath(process.cwd()));
32
32
  const result = runNativePackageCommand(args.filter((arg) => arg !== "--check-update"));
33
33
  if (result.status === 0) {
34
+ ensureTaskLedgerMigrated(result.nativeBinary);
34
35
  ensureRepositoryQualityInitialized(result.nativeBinary, qualityConfigExisted);
35
36
  }
36
37
  process.exit(result.status === null ? 1 : result.status);
@@ -281,27 +282,11 @@ function ensureRepositoryQualityInitialized(nativeBinary, qualityConfigExisted)
281
282
  }
282
283
  }
283
284
 
284
- const result = spawnSync(nativeBinary, ["quality", "init", "--json"], {
285
- cwd: root,
286
- encoding: "utf8",
287
- env: {
288
- ...process.env,
289
- NAOME_NODE_BIN: process.execPath
290
- }
291
- });
292
-
293
- if (result.status !== 0) {
294
- console.error("NAOME: repository quality initialization failed.");
295
- if (result.stdout.trim()) {
296
- console.error(result.stdout.trim());
297
- }
298
- if (result.stderr.trim()) {
299
- console.error(result.stderr.trim());
300
- }
301
- process.exit(result.status === null ? 1 : result.status);
302
- }
303
-
304
- const output = result.stdout.trim();
285
+ const output = runNativeJsonCommand(
286
+ nativeBinary,
287
+ ["quality", "init", "--json"],
288
+ "repository quality initialization failed"
289
+ );
305
290
  if (output) {
306
291
  try {
307
292
  const init = JSON.parse(output);
@@ -317,6 +302,59 @@ function ensureRepositoryQualityInitialized(nativeBinary, qualityConfigExisted)
317
302
  }
318
303
  }
319
304
 
305
+ function ensureTaskLedgerMigrated(nativeBinary) {
306
+ const root = process.cwd();
307
+ if (!existsSync(join(root, ".naome"))) {
308
+ return;
309
+ }
310
+
311
+ const output = runNativeJsonCommand(
312
+ nativeBinary,
313
+ ["task", "migrate-ledger", "--write", "--json"],
314
+ "task ledger migration failed"
315
+ );
316
+ if (!output) {
317
+ return;
318
+ }
319
+
320
+ try {
321
+ const migration = JSON.parse(output);
322
+ if (migration.updated && migration.migration?.source === "task-state") {
323
+ console.log("task ledger migrated from task-state");
324
+ }
325
+ } catch (_error) {
326
+ console.log(output);
327
+ }
328
+ }
329
+
330
+ function runNativeJsonCommand(nativeBinary, commandArgs, failureLabel) {
331
+ const result = spawnSync(nativeBinary, commandArgs, {
332
+ cwd: process.cwd(),
333
+ encoding: "utf8",
334
+ env: {
335
+ ...process.env,
336
+ NAOME_NODE_BIN: process.execPath
337
+ }
338
+ });
339
+
340
+ if (result.status !== 0) {
341
+ exitNativeJsonFailure(failureLabel, result);
342
+ }
343
+
344
+ return result.stdout.trim();
345
+ }
346
+
347
+ function exitNativeJsonFailure(label, result) {
348
+ console.error(`NAOME: ${label}.`);
349
+ for (const stream of [result.stdout, result.stderr]) {
350
+ const text = stream.trim();
351
+ if (text) {
352
+ console.error(text);
353
+ }
354
+ }
355
+ process.exit(result.status === null ? 1 : result.status);
356
+ }
357
+
320
358
  function repositoryQualityConfigPath(root) {
321
359
  return join(root, ".naome", "repository-quality.json");
322
360
  }
@@ -339,8 +377,8 @@ function repositoryQualitySupportFilesExist(root) {
339
377
  function resolveNativePackageBinary() {
340
378
  const candidates = [
341
379
  process.env.NAOME_NATIVE_BIN && resolve(process.cwd(), process.env.NAOME_NATIVE_BIN),
342
- join(packageRoot, "native", `${process.platform}-${process.arch}`, nativeBinaryName),
343
- join(packageRoot, "target", "release", nativeBinaryName)
380
+ join(packageRoot, "target", "release", nativeBinaryName),
381
+ join(packageRoot, "native", `${process.platform}-${process.arch}`, nativeBinaryName)
344
382
  ].filter(Boolean);
345
383
 
346
384
  for (const candidate of candidates) {
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "naome-cli"
3
- version = "1.3.0"
3
+ version = "1.3.1"
4
4
  edition.workspace = true
5
5
  license.workspace = true
6
6
  repository.workspace = true
@@ -0,0 +1,47 @@
1
+ use std::fs;
2
+ use std::path::Path;
3
+
4
+ use naome_core::{select_context_for_changed_paths, select_context_for_prompt};
5
+
6
+ use crate::cli_args::option_value;
7
+
8
+ pub fn run_context_command(root: &Path, args: &[String]) -> Result<(), Box<dyn std::error::Error>> {
9
+ let Some(subcommand) = args.get(1).map(String::as_str) else {
10
+ return Err("naome context requires select.".into());
11
+ };
12
+ match subcommand {
13
+ "select" => run_context_select(root, args)?,
14
+ _ => return Err(format!("unknown naome context command: {subcommand}").into()),
15
+ }
16
+ Ok(())
17
+ }
18
+
19
+ fn run_context_select(root: &Path, args: &[String]) -> Result<(), Box<dyn std::error::Error>> {
20
+ let selection = if args.iter().any(|arg| arg == "--changed") {
21
+ select_context_for_changed_paths(root)?
22
+ } else if let Some(prompt) = option_value(args, "--prompt") {
23
+ select_context_for_prompt(root, prompt)?
24
+ } else if let Some(prompt_file) = option_value(args, "--prompt-file") {
25
+ select_context_for_prompt(root, fs::read_to_string(prompt_file)?)?
26
+ } else {
27
+ return Err(
28
+ "naome context select requires --changed, --prompt <text>, or --prompt-file <path>."
29
+ .into(),
30
+ );
31
+ };
32
+
33
+ if args.iter().any(|arg| arg == "--json") {
34
+ println!("{}", serde_json::to_string_pretty(&selection)?);
35
+ } else {
36
+ println!(
37
+ "NAOME context capsule: {} ({} file(s), ~{} token(s))",
38
+ selection.capsule.id,
39
+ selection.budget_ledger.selected_files,
40
+ selection.budget_ledger.estimated_tokens
41
+ );
42
+ for item in &selection.required_context {
43
+ println!("- {}", item.path);
44
+ }
45
+ }
46
+ Ok(())
47
+ }
@@ -1,14 +1,17 @@
1
1
  use std::path::Path;
2
2
 
3
3
  use crate::check_commands::{run_harness_health, run_task_state, run_verification_contract};
4
+ use crate::context_commands::run_context_command;
4
5
  use crate::install_bridge::run_install_bridge;
5
6
  use crate::prompt_commands::{run_explain, run_intent, run_route};
6
7
  use crate::quality_commands::{
7
8
  run_cleanup_command, run_quality_command, run_semantic_command, run_structure_command,
8
9
  };
10
+ use crate::repository_model_commands::run_repo_command;
9
11
  use crate::simple_commands::{
10
12
  print_install_plan, run_commit_paths, run_journal_task, seed_verification,
11
13
  };
14
+ use crate::task_commands::run_task_command;
12
15
  use crate::workflow_commands::{run_doctor, run_refresh_integrity, run_workflow_command};
13
16
 
14
17
  pub fn dispatch_command(
@@ -20,10 +23,13 @@ pub fn dispatch_command(
20
23
  "install" | "sync" => run_install_bridge(command, args)?,
21
24
  "install-plan" => print_install_plan(args)?,
22
25
  "seed-verification" => seed_verification(root)?,
26
+ "task" => run_task_command(root, args)?,
23
27
  "refresh-integrity" => run_refresh_integrity(root, args)?,
28
+ "context" => run_context_command(root, args)?,
24
29
  "doctor" => run_doctor(root, args)?,
25
30
  "quality" => run_quality_command(root, args)?,
26
31
  "semantic" => run_semantic_command(root, args)?,
32
+ "repo" => run_repo_command(root, args)?,
27
33
  "structure" => run_structure_command(root, args)?,
28
34
  "cleanup" => run_cleanup_command(root, args)?,
29
35
  "workflow" => run_workflow_command(root, args)?,
@@ -1,10 +1,15 @@
1
1
  mod check_commands;
2
2
  mod cli_args;
3
+ mod context_commands;
3
4
  mod dispatcher;
4
5
  mod install_bridge;
5
6
  mod prompt_commands;
6
7
  mod quality_commands;
8
+ mod quality_output;
9
+ mod quality_reconcile_command;
10
+ mod repository_model_commands;
7
11
  mod simple_commands;
12
+ mod task_commands;
8
13
  mod workflow_commands;
9
14
 
10
15
  use std::path::{Path, PathBuf};
@@ -22,26 +27,44 @@ const HELP: &str = r#"Usage:
22
27
  naome route --prompt <text> [--execute] [--json]
23
28
  naome explain --prompt-file <path> [--json]
24
29
  naome explain --prompt <text> [--json]
30
+ naome context select --changed [--json]
31
+ naome context select --prompt-file <path> [--json]
32
+ naome context select --prompt <text> [--json]
25
33
  naome doctor [--json]
26
34
  naome install [--package-root <path>] [--installer-js <path>]
27
35
  naome sync [--package-root <path>] [--installer-js <path>]
28
36
  naome install-plan [--harness-version <version>]
29
37
  naome seed-verification
38
+ naome task render-state [--write] [--json]
39
+ naome task migrate-ledger [--write] [--json]
30
40
  naome refresh-integrity [--root <path>] [--json]
31
41
  naome quality init [--baseline|--deep-baseline] [--json]
42
+ naome quality reconcile [--write] [--json]
32
43
  naome quality check --changed [--include-scanned-paths] [--json]
44
+ naome quality check --path <path> [--path <path>...] [--include-scanned-paths] [--json]
33
45
  naome quality report [--deep] [--include-scanned-paths] [--json]
34
46
  naome quality cache status [--json]
35
47
  naome quality cache clear
36
48
  naome semantic report [--deep] [--json]
37
49
  naome semantic check --changed [--json]
50
+ naome semantic check --path <path> [--path <path>...] [--json]
38
51
  naome semantic route --finding <id> [--json]
39
52
  naome semantic loop [--json]
53
+ naome repo model [--write] [--json]
54
+ naome repo check [--json]
55
+ naome repo explain --path <path> [--json]
40
56
  naome structure report [--json]
41
57
  naome structure explain --path <path> [--json]
42
58
  naome cleanup plan [--json]
43
59
  naome cleanup route --path <path> [--json]
44
60
  naome workflow search-profile [--json]
61
+ naome workflow agent-plan [--json]
62
+ naome workflow context-delta [--read-path <path>...] [--json]
63
+ naome workflow proof-plan [--json]
64
+ naome workflow capabilities [--json]
65
+ naome workflow edit-watchdog --path <path> [--path <path>...] [--json]
66
+ naome workflow decision-gate [--json]
67
+ naome workflow digest --command <cmd> --exit-code <code> [--output <text>|--output-file <path>] [--json]
45
68
  naome workflow check-search --command <cmd> [--json]
46
69
  naome workflow phases [--json]
47
70
  naome workflow processes [--json]
@@ -60,10 +83,13 @@ const PUBLIC_COMMANDS: &[&str] = &[
60
83
  "journal-task",
61
84
  "commit-paths",
62
85
  "seed-verification",
86
+ "task",
63
87
  "refresh-integrity",
88
+ "context",
64
89
  "workflow",
65
90
  "quality",
66
91
  "semantic",
92
+ "repo",
67
93
  "structure",
68
94
  "cleanup",
69
95
  "install-plan",
@@ -140,7 +166,13 @@ fn is_help_request(args: &[String]) -> bool {
140
166
  }
141
167
 
142
168
  fn find_harness_root(start: &Path) -> Option<PathBuf> {
143
- find_root_with_marker(start, &[".naome", "task-state.json"])
169
+ find_root_with_any_marker(
170
+ start,
171
+ &[
172
+ &[".naome", "task-state.json"],
173
+ &[".naome", "tasks", "active.json"],
174
+ ],
175
+ )
144
176
  }
145
177
 
146
178
  fn find_manifest_root(start: &Path) -> Option<PathBuf> {
@@ -148,13 +180,18 @@ fn find_manifest_root(start: &Path) -> Option<PathBuf> {
148
180
  }
149
181
 
150
182
  fn find_root_with_marker(start: &Path, marker: &[&str]) -> Option<PathBuf> {
183
+ find_root_with_any_marker(start, &[marker])
184
+ }
185
+
186
+ fn find_root_with_any_marker(start: &Path, markers: &[&[&str]]) -> Option<PathBuf> {
151
187
  let mut current = start.to_path_buf();
152
188
  loop {
153
- if marker
154
- .iter()
155
- .fold(current.clone(), |path, part| path.join(part))
156
- .is_file()
157
- {
189
+ if markers.iter().any(|marker| {
190
+ marker
191
+ .iter()
192
+ .fold(current.clone(), |path, part| path.join(part))
193
+ .is_file()
194
+ }) {
158
195
  return Some(current);
159
196
  }
160
197
 
@@ -1,17 +1,19 @@
1
1
  use std::path::Path;
2
2
 
3
3
  use naome_core::{
4
- check_repository_quality, check_semantic_legacy, clear_quality_cache,
5
- explain_repository_structure, init_repository_quality_with_mode, plan_quality_cleanup,
6
- quality_cache_status, route_quality_cleanup, semantic_route_for_finding, QualityInitMode,
7
- QualityMode,
4
+ check_repository_quality, check_repository_quality_paths, check_semantic_legacy, check_semantic_legacy_paths,
5
+ clear_quality_cache, explain_repository_structure, init_repository_quality_with_mode,
6
+ plan_quality_cleanup, quality_cache_status, route_quality_cleanup, semantic_route_for_finding,
7
+ QualityInitMode, QualityMode,
8
8
  };
9
9
 
10
10
  use crate::cli_args::option_value;
11
+ use crate::quality_output::{is_structure_check, print_quality_violation, report_json};
12
+ use crate::quality_reconcile_command::run_quality_reconcile;
11
13
 
12
14
  pub fn run_quality_command(root: &Path, args: &[String]) -> Result<(), Box<dyn std::error::Error>> {
13
15
  let Some(subcommand) = args.get(1).map(String::as_str) else {
14
- return Err("naome quality requires init, check, report, or cache.".into());
16
+ return Err("naome quality requires init, reconcile, check, report, or cache.".into());
15
17
  };
16
18
  let json = args.iter().any(|arg| arg == "--json");
17
19
 
@@ -30,6 +32,7 @@ pub fn run_quality_command(root: &Path, args: &[String]) -> Result<(), Box<dyn s
30
32
  }
31
33
  }
32
34
  }
35
+ "reconcile" => run_quality_reconcile(root, args, json)?,
33
36
  "check" => run_quality_check(root, args, json)?,
34
37
  "report" => run_quality_report(root, args, json)?,
35
38
  "cache" => run_quality_cache(root, args, json)?,
@@ -93,10 +96,15 @@ fn run_quality_check(
93
96
  args: &[String],
94
97
  json: bool,
95
98
  ) -> Result<(), Box<dyn std::error::Error>> {
96
- if !args.iter().any(|arg| arg == "--changed") {
97
- return Err("naome quality check requires --changed.".into());
98
- }
99
- let report = check_repository_quality(root, QualityMode::ChangedFast)?;
99
+ let paths = option_values(args, "--path");
100
+ let report = if paths.is_empty() {
101
+ if !args.iter().any(|arg| arg == "--changed") {
102
+ return Err("naome quality check requires --changed or --path <path>.".into());
103
+ }
104
+ check_repository_quality(root, QualityMode::ChangedFast)?
105
+ } else {
106
+ check_repository_quality_paths(root, &paths)?
107
+ };
100
108
  if json {
101
109
  println!("{}", report_json(&report, args)?);
102
110
  } else if report.ok {
@@ -303,10 +311,15 @@ fn run_semantic_check(
303
311
  args: &[String],
304
312
  json: bool,
305
313
  ) -> Result<(), Box<dyn std::error::Error>> {
306
- if !args.iter().any(|arg| arg == "--changed") {
307
- return Err("naome semantic check requires --changed.".into());
308
- }
309
- let report = check_semantic_legacy(root, QualityMode::ChangedFast)?;
314
+ let paths = option_values(args, "--path");
315
+ let report = if paths.is_empty() {
316
+ if !args.iter().any(|arg| arg == "--changed") {
317
+ return Err("naome semantic check requires --changed or --path <path>.".into());
318
+ }
319
+ check_semantic_legacy(root, QualityMode::ChangedFast)?
320
+ } else {
321
+ check_semantic_legacy_paths(root, &paths)?
322
+ };
310
323
  if json {
311
324
  println!("{}", serde_json::to_string_pretty(&report)?);
312
325
  } else if report.ok {
@@ -397,20 +410,6 @@ fn run_semantic_loop(root: &Path, json: bool) -> Result<(), Box<dyn std::error::
397
410
  Ok(())
398
411
  }
399
412
 
400
- fn is_structure_check(check_id: &str) -> bool {
401
- matches!(
402
- check_id,
403
- "directory-role-mixing"
404
- | "misplaced-file-role"
405
- | "root-file-sprawl"
406
- | "dumping-ground-directory"
407
- | "directory-size"
408
- | "path-depth"
409
- | "case-collision"
410
- | "test-source-pairing"
411
- )
412
- }
413
-
414
413
  fn quality_init_mode(args: &[String]) -> Result<QualityInitMode, Box<dyn std::error::Error>> {
415
414
  let baseline = args.iter().any(|arg| arg == "--baseline");
416
415
  let deep_baseline = args.iter().any(|arg| arg == "--deep-baseline");
@@ -426,23 +425,9 @@ fn quality_init_mode(args: &[String]) -> Result<QualityInitMode, Box<dyn std::er
426
425
  })
427
426
  }
428
427
 
429
- fn report_json(
430
- report: &naome_core::QualityReport,
431
- args: &[String],
432
- ) -> Result<String, Box<dyn std::error::Error>> {
433
- let mut value = serde_json::to_value(report)?;
434
- if !args.iter().any(|arg| arg == "--include-scanned-paths") {
435
- if let Some(object) = value.as_object_mut() {
436
- object.remove("scannedPaths");
437
- }
438
- }
439
- Ok(serde_json::to_string_pretty(&value)?)
440
- }
441
-
442
- fn print_quality_violation(violation: &naome_core::QualityViolation) {
443
- let location = violation
444
- .line
445
- .map(|line| format!("{}:{line}", violation.path))
446
- .unwrap_or_else(|| violation.path.clone());
447
- eprintln!("- {location} {}: {}", violation.check_id, violation.message);
428
+ fn option_values(args: &[String], name: &str) -> Vec<String> {
429
+ args.windows(2)
430
+ .filter(|window| window[0] == name)
431
+ .map(|window| window[1].clone())
432
+ .collect()
448
433
  }
@@ -0,0 +1,34 @@
1
+ pub fn report_json(
2
+ report: &naome_core::QualityReport,
3
+ args: &[String],
4
+ ) -> Result<String, Box<dyn std::error::Error>> {
5
+ let mut value = serde_json::to_value(report)?;
6
+ if !args.iter().any(|arg| arg == "--include-scanned-paths") {
7
+ if let Some(object) = value.as_object_mut() {
8
+ object.remove("scannedPaths");
9
+ }
10
+ }
11
+ Ok(serde_json::to_string_pretty(&value)?)
12
+ }
13
+
14
+ pub fn print_quality_violation(violation: &naome_core::QualityViolation) {
15
+ let location = violation
16
+ .line
17
+ .map(|line| format!("{}:{line}", violation.path))
18
+ .unwrap_or_else(|| violation.path.clone());
19
+ eprintln!("- {location} {}: {}", violation.check_id, violation.message);
20
+ }
21
+
22
+ pub fn is_structure_check(check_id: &str) -> bool {
23
+ matches!(
24
+ check_id,
25
+ "directory-role-mixing"
26
+ | "misplaced-file-role"
27
+ | "root-file-sprawl"
28
+ | "dumping-ground-directory"
29
+ | "directory-size"
30
+ | "path-depth"
31
+ | "case-collision"
32
+ | "test-source-pairing"
33
+ )
34
+ }
@@ -0,0 +1,45 @@
1
+ use std::collections::BTreeSet;
2
+ use std::path::Path;
3
+
4
+ use naome_core::reconcile_repository_quality;
5
+
6
+ pub fn run_quality_reconcile(
7
+ root: &Path,
8
+ args: &[String],
9
+ json: bool,
10
+ ) -> Result<(), Box<dyn std::error::Error>> {
11
+ let write = args.iter().any(|arg| arg == "--write");
12
+ let report = reconcile_repository_quality(root, write)?;
13
+ if json {
14
+ println!("{}", serde_json::to_string_pretty(&report)?);
15
+ } else if report.ok && report.updated_paths.is_empty() {
16
+ println!("NAOME repository quality adapter policy is current.");
17
+ } else if report.ok {
18
+ println!(
19
+ "NAOME repository quality adapter policy updated: {}",
20
+ report.updated_paths.join(", ")
21
+ );
22
+ } else {
23
+ eprintln!(
24
+ "NAOME repository quality adapter policy is stale. Missing adapter(s): {}",
25
+ missing_adapters(&report)
26
+ );
27
+ eprintln!("Run: naome quality reconcile --write");
28
+ }
29
+ if !report.ok {
30
+ std::process::exit(1);
31
+ }
32
+ Ok(())
33
+ }
34
+
35
+ fn missing_adapters(report: &naome_core::QualityReconcileReport) -> String {
36
+ report
37
+ .missing_quality_adapters
38
+ .iter()
39
+ .chain(report.missing_structure_adapters.iter())
40
+ .cloned()
41
+ .collect::<BTreeSet<_>>()
42
+ .into_iter()
43
+ .collect::<Vec<_>>()
44
+ .join(", ")
45
+ }