@lamentis/naome 1.3.7 → 1.3.9

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 (48) hide show
  1. package/Cargo.lock +2 -2
  2. package/README.md +5 -0
  3. package/crates/naome-cli/Cargo.toml +1 -1
  4. package/crates/naome-cli/src/install_bridge.rs +56 -8
  5. package/crates/naome-core/Cargo.toml +1 -1
  6. package/crates/naome-core/src/context/select.rs +58 -4
  7. package/crates/naome-core/src/harness_health/integrity.rs +41 -23
  8. package/crates/naome-core/src/harness_health/manifest.rs +97 -0
  9. package/crates/naome-core/src/harness_health.rs +58 -106
  10. package/crates/naome-core/src/intent/classifier.rs +56 -81
  11. package/crates/naome-core/src/intent/envelope.rs +173 -19
  12. package/crates/naome-core/src/intent/legacy_response.rs +2 -0
  13. package/crates/naome-core/src/intent/model.rs +6 -0
  14. package/crates/naome-core/src/intent/resolver.rs +25 -0
  15. package/crates/naome-core/src/intent/risk.rs +11 -1
  16. package/crates/naome-core/src/intent.rs +1 -1
  17. package/crates/naome-core/src/quality/cache.rs +122 -19
  18. package/crates/naome-core/src/quality/scanner/analysis.rs +4 -2
  19. package/crates/naome-core/src/quality/scanner/repo_paths.rs +27 -3
  20. package/crates/naome-core/src/quality/scanner.rs +5 -2
  21. package/crates/naome-core/src/route/context.rs +8 -0
  22. package/crates/naome-core/src/workflow/integrity_support.rs +10 -3
  23. package/crates/naome-core/tests/context.rs +92 -0
  24. package/crates/naome-core/tests/harness_health.rs +149 -0
  25. package/crates/naome-core/tests/intent.rs +98 -18
  26. package/crates/naome-core/tests/intent_support/mod.rs +39 -1
  27. package/crates/naome-core/tests/intent_v2.rs +299 -10
  28. package/crates/naome-core/tests/quality_performance.rs +63 -2
  29. package/crates/naome-core/tests/repo_support/routes.rs +8 -2
  30. package/crates/naome-core/tests/route_baseline.rs +29 -0
  31. package/crates/naome-core/tests/route_completion.rs +26 -5
  32. package/crates/naome-core/tests/route_harness_refresh.rs +7 -1
  33. package/crates/naome-core/tests/route_user_diff.rs +1 -1
  34. package/crates/naome-core/tests/task_state_compact.rs +7 -1
  35. package/installer/filesystem.js +38 -0
  36. package/installer/flows.js +6 -1
  37. package/installer/harness-file-ops.js +36 -8
  38. package/installer/manifest-state.js +2 -2
  39. package/installer/native.js +63 -18
  40. package/native/darwin-arm64/naome +0 -0
  41. package/native/linux-x64/naome +0 -0
  42. package/package.json +1 -1
  43. package/templates/naome-root/.naome/bin/check-harness-health.js +25 -21
  44. package/templates/naome-root/.naome/bin/check-task-state.js +35 -42
  45. package/templates/naome-root/.naome/manifest.json +10 -10
  46. package/templates/naome-root/docs/naome/agent-workflow.md +14 -5
  47. package/templates/naome-root/docs/naome/architecture.md +9 -0
  48. package/crates/naome-core/src/intent/patterns.rs +0 -170
@@ -7,20 +7,21 @@ const path = require("node:path");
7
7
 
8
8
  const nativeBinaryPath = process.platform === "win32" ? ".naome/bin/naome-rust.exe" : ".naome/bin/naome-rust";
9
9
  const nativeBinaryName = process.platform === "win32" ? "naome.exe" : "naome";
10
+ const expectedNativeBinaryIntegrity = "sha256:generated";
10
11
 
11
12
  const expectedMachineOwnedIntegrity = Object.freeze({
12
- ".naome/bin/check-harness-health.js": "sha256:dc4de52b79c69600b9ba47b924e2c2b8de61a2cbfab6d1ccc0f1924d963db657",
13
- ".naome/bin/check-task-state.js": "sha256:df54489a22b426180266e5e0fb5f9ec381477419f688435248afbf2b9b38ea81",
14
- ".naome/bin/naome.js": "sha256:a34c2e50a68d15ff2722a57590ccddc504e025d3c98ea62fd700d7ec1a789b9a",
13
+ "AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
15
14
  ".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
15
+ ".naome/bin/naome.js": "sha256:a34c2e50a68d15ff2722a57590ccddc504e025d3c98ea62fd700d7ec1a789b9a",
16
+ ".naome/bin/check-task-state.js": "sha256:2612577b7e4ab45d9d39dd5ac54c8e7ed749d237d78f1a8d252f4dfa0b4eaaab",
17
+ ".naome/bin/check-harness-health.js": "sha256:802d7419774981a6af1826b3882270ff8f41259d516f98c52a02b4ddc184c467",
16
18
  ".naome/task-contract.schema.json": "sha256:1b3b62350328d0d6d660e36d1d1baaa2b88718530db774f9ab2a9e2fcba369c8",
17
- "AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
18
- "docs/naome/agent-workflow.md": "sha256:2fd1fd02eb6849133b9e8227421914580b1c469a60388a063c1b6ed48016b48d",
19
+ "docs/naome/index.md": "sha256:07ef776f49130319a5280bdb3ae38af22141708253f38eb983a4336fbae1b25a",
20
+ "docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
21
+ "docs/naome/agent-workflow.md": "sha256:0be1c29adfbcd3fd73c4f904080ffc67237692fe413871a30243538c4db38ac7",
19
22
  "docs/naome/context-economy.md": "sha256:3ed5075815ecf4ada46a5e65438769310307c35759fcd46b13dc0b96e02bebd9",
23
+ "docs/naome/task-ledger.md": "sha256:6ca7222c80079b4662fb718d3c71d686770646f1fa52b83b0e90aed1c5a1101b",
20
24
  "docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
21
- "docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
22
- "docs/naome/index.md": "sha256:07ef776f49130319a5280bdb3ae38af22141708253f38eb983a4336fbae1b25a",
23
- "docs/naome/task-ledger.md": "sha256:ac637a31abdd13eee15a49086594e63f5c88fe12a5cf621b227310788ae7e583",
24
25
  "docs/naome/upgrade.md": "sha256:2c60f0441bbd98bd528d109b30a7ded4b0ad55d61ffb9f52edac9e93b7999cb1"
25
26
  });
26
27
 
@@ -39,7 +40,7 @@ const result = childProcess.spawnSync(binary, ["check-harness-health", "--root",
39
40
  process.exit(result.status === null ? 1 : result.status);
40
41
 
41
42
  function selectBinary(rootDir) {
42
- const wantedHash = manifestNativeHash(rootDir);
43
+ const wantedHash = expectedNativeHash();
43
44
  const candidates = [
44
45
  process.env.NAOME_NATIVE_BIN,
45
46
  path.join(rootDir, nativeBinaryPath),
@@ -47,13 +48,13 @@ function selectBinary(rootDir) {
47
48
  path.join(rootDir, "packages", "naome", "target", "debug", nativeBinaryName)
48
49
  ].filter(Boolean);
49
50
 
50
- for (const candidate of candidates) {
51
- if (canRun(candidate, rootDir, wantedHash)) {
52
- return candidate;
51
+ if (wantedHash) {
52
+ for (const candidate of candidates) {
53
+ if (canRun(candidate, rootDir, wantedHash)) {
54
+ return candidate;
55
+ }
53
56
  }
54
- }
55
57
 
56
- if (wantedHash) {
57
58
  stop(`No runnable NAOME native harness health binary matched ${wantedHash}. Run naome sync again.`);
58
59
  }
59
60
 
@@ -62,20 +63,19 @@ function selectBinary(rootDir) {
62
63
  return built;
63
64
  }
64
65
 
65
- stop("NAOME native harness health binary is missing or incompatible. Run naome sync again.");
66
+ stop("NAOME native harness health binary has no trusted packaged integrity. Run naome sync again.");
66
67
  }
67
68
 
68
- function manifestNativeHash(rootDir) {
69
+ function expectedNativeHash() {
69
70
  if (isSha(process.env.NAOME_EXPECTED_NATIVE_INTEGRITY)) {
70
71
  return process.env.NAOME_EXPECTED_NATIVE_INTEGRITY;
71
72
  }
72
73
 
73
- try {
74
- const manifest = JSON.parse(fs.readFileSync(path.join(rootDir, ".naome", "manifest.json"), "utf8"));
75
- return isSha(manifest.integrity?.[nativeBinaryPath]) ? manifest.integrity[nativeBinaryPath] : null;
76
- } catch {
77
- return null;
74
+ if (isSha(expectedNativeBinaryIntegrity)) {
75
+ return expectedNativeBinaryIntegrity;
78
76
  }
77
+
78
+ return null;
79
79
  }
80
80
 
81
81
  function canRun(candidate, rootDir, wantedHash) {
@@ -96,6 +96,10 @@ function canRun(candidate, rootDir, wantedHash) {
96
96
  }
97
97
 
98
98
  function buildFromSource(rootDir) {
99
+ if (expectedNativeBinaryIntegrity !== "sha256:generated") {
100
+ return null;
101
+ }
102
+
99
103
  const manifest = path.join(rootDir, "packages", "naome", "Cargo.toml");
100
104
  if (!fs.existsSync(manifest)) {
101
105
  return null;
@@ -7,20 +7,21 @@ const { spawnSync } = require("node:child_process");
7
7
 
8
8
  const nativeBinaryRelativePath = process.platform === "win32" ? ".naome/bin/naome-rust.exe" : ".naome/bin/naome-rust";
9
9
  const nativeBinaryName = process.platform === "win32" ? "naome.exe" : "naome";
10
+ const expectedNativeBinaryIntegrity = "sha256:generated";
10
11
 
11
12
  const expectedMachineOwnedIntegrity = Object.freeze({
12
- ".naome/bin/check-harness-health.js": "sha256:dc4de52b79c69600b9ba47b924e2c2b8de61a2cbfab6d1ccc0f1924d963db657",
13
- ".naome/bin/check-task-state.js": "sha256:df54489a22b426180266e5e0fb5f9ec381477419f688435248afbf2b9b38ea81",
14
- ".naome/bin/naome.js": "sha256:a34c2e50a68d15ff2722a57590ccddc504e025d3c98ea62fd700d7ec1a789b9a",
13
+ "AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
15
14
  ".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
15
+ ".naome/bin/naome.js": "sha256:a34c2e50a68d15ff2722a57590ccddc504e025d3c98ea62fd700d7ec1a789b9a",
16
+ ".naome/bin/check-task-state.js": "sha256:2612577b7e4ab45d9d39dd5ac54c8e7ed749d237d78f1a8d252f4dfa0b4eaaab",
17
+ ".naome/bin/check-harness-health.js": "sha256:802d7419774981a6af1826b3882270ff8f41259d516f98c52a02b4ddc184c467",
16
18
  ".naome/task-contract.schema.json": "sha256:1b3b62350328d0d6d660e36d1d1baaa2b88718530db774f9ab2a9e2fcba369c8",
17
- "AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
18
- "docs/naome/agent-workflow.md": "sha256:2fd1fd02eb6849133b9e8227421914580b1c469a60388a063c1b6ed48016b48d",
19
+ "docs/naome/index.md": "sha256:07ef776f49130319a5280bdb3ae38af22141708253f38eb983a4336fbae1b25a",
20
+ "docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
21
+ "docs/naome/agent-workflow.md": "sha256:0be1c29adfbcd3fd73c4f904080ffc67237692fe413871a30243538c4db38ac7",
19
22
  "docs/naome/context-economy.md": "sha256:3ed5075815ecf4ada46a5e65438769310307c35759fcd46b13dc0b96e02bebd9",
23
+ "docs/naome/task-ledger.md": "sha256:6ca7222c80079b4662fb718d3c71d686770646f1fa52b83b0e90aed1c5a1101b",
20
24
  "docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
21
- "docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
22
- "docs/naome/index.md": "sha256:07ef776f49130319a5280bdb3ae38af22141708253f38eb983a4336fbae1b25a",
23
- "docs/naome/task-ledger.md": "sha256:ac637a31abdd13eee15a49086594e63f5c88fe12a5cf621b227310788ae7e583",
24
25
  "docs/naome/upgrade.md": "sha256:2c60f0441bbd98bd528d109b30a7ded4b0ad55d61ffb9f52edac9e93b7999cb1"
25
26
  });
26
27
 
@@ -62,7 +63,7 @@ function modeArgs(argv) {
62
63
  }
63
64
 
64
65
  function resolveNativeDecisionBinary(root) {
65
- const expectedIntegrity = expectedNativeIntegrity(root);
66
+ const expectedIntegrity = expectedNativeIntegrity();
66
67
  const candidates = [
67
68
  process.env.NAOME_NATIVE_BIN,
68
69
  join(root, nativeBinaryRelativePath),
@@ -70,13 +71,13 @@ function resolveNativeDecisionBinary(root) {
70
71
  join(root, "packages", "naome", "target", "debug", nativeBinaryName)
71
72
  ].filter(Boolean);
72
73
 
73
- for (const candidate of candidates) {
74
- if (isUsableNativeBinary(candidate, root, expectedIntegrity)) {
75
- return candidate;
74
+ if (expectedIntegrity) {
75
+ for (const candidate of candidates) {
76
+ if (isUsableNativeBinary(candidate, root, expectedIntegrity)) {
77
+ return candidate;
78
+ }
76
79
  }
77
- }
78
80
 
79
- if (expectedIntegrity) {
80
81
  fail(`No runnable NAOME native task-state binary matched ${expectedIntegrity}. Run naome sync again.`);
81
82
  }
82
83
 
@@ -88,29 +89,16 @@ function resolveNativeDecisionBinary(root) {
88
89
  fail("NAOME native task-state binary is missing or incompatible. Run naome sync again.");
89
90
  }
90
91
 
91
- function expectedNativeIntegrity(root) {
92
+ function expectedNativeIntegrity() {
92
93
  if (isIntegrityHash(process.env.NAOME_EXPECTED_NATIVE_INTEGRITY)) {
93
94
  return process.env.NAOME_EXPECTED_NATIVE_INTEGRITY;
94
95
  }
95
96
 
96
- const manifestPath = join(root, ".naome", "manifest.json");
97
- if (!existsSync(manifestPath)) {
98
- return null;
99
- }
100
-
101
- let manifest;
102
- try {
103
- manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
104
- } catch {
105
- return null;
106
- }
107
-
108
- const expected = manifest.integrity?.[nativeBinaryRelativePath];
109
- if (!isIntegrityHash(expected)) {
97
+ if (expectedNativeBinaryIntegrity === "sha256:generated") {
110
98
  return null;
111
99
  }
112
100
 
113
- return expected;
101
+ return expectedNativeBinaryIntegrity;
114
102
  }
115
103
 
116
104
  function isUsableNativeBinary(candidate, root, expectedIntegrity) {
@@ -125,30 +113,35 @@ function isUsableNativeBinary(candidate, root, expectedIntegrity) {
125
113
  }
126
114
  }
127
115
 
128
- const probe = spawnSync(candidate, [], {
129
- cwd: root,
130
- encoding: "utf8",
131
- stdio: "ignore"
132
- });
116
+ const probe = spawnSync(candidate, [], { cwd: root, stdio: ["ignore", "ignore", "ignore"] });
133
117
  return !probe.error && probe.status !== null;
134
118
  }
135
119
 
136
120
  function buildSourceNativeBinary(root) {
137
- const manifestPath = join(root, "packages", "naome", "Cargo.toml");
121
+ if (expectedNativeBinaryIntegrity !== "sha256:generated") {
122
+ return null;
123
+ }
124
+
125
+ const packageRoot = join(root, "packages", "naome");
126
+ const manifestPath = join(packageRoot, "Cargo.toml");
138
127
  if (!existsSync(manifestPath)) {
139
128
  return null;
140
129
  }
141
130
 
142
- const result = spawnSync("cargo", ["build", "--release", "--manifest-path", manifestPath, "-p", "naome-cli"], {
143
- cwd: root,
144
- encoding: "utf8",
145
- stdio: "ignore"
146
- });
131
+ const result = spawnSync(
132
+ "cargo",
133
+ ["build", "--release", "--manifest-path", manifestPath, "-p", "naome-cli"],
134
+ {
135
+ cwd: root,
136
+ encoding: "utf8",
137
+ stdio: "ignore"
138
+ }
139
+ );
147
140
  if (result.status !== 0) {
148
141
  return null;
149
142
  }
150
143
 
151
- const builtPath = join(root, "packages", "naome", "target", "release", nativeBinaryName);
144
+ const builtPath = join(packageRoot, "target", "release", nativeBinaryName);
152
145
  return existsSync(builtPath) ? builtPath : null;
153
146
  }
154
147
 
@@ -1,19 +1,19 @@
1
1
  {
2
- "harnessVersion": "1.2.0",
2
+ "harnessVersion": "1.3.9",
3
3
  "installedAt": null,
4
4
  "integrity": {
5
- ".naome/bin/check-harness-health.js": "sha256:dc4de52b79c69600b9ba47b924e2c2b8de61a2cbfab6d1ccc0f1924d963db657",
6
- ".naome/bin/check-task-state.js": "sha256:df54489a22b426180266e5e0fb5f9ec381477419f688435248afbf2b9b38ea81",
7
- ".naome/bin/naome.js": "sha256:a34c2e50a68d15ff2722a57590ccddc504e025d3c98ea62fd700d7ec1a789b9a",
5
+ "AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
8
6
  ".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
7
+ ".naome/bin/naome.js": "sha256:a34c2e50a68d15ff2722a57590ccddc504e025d3c98ea62fd700d7ec1a789b9a",
8
+ ".naome/bin/check-task-state.js": "sha256:2612577b7e4ab45d9d39dd5ac54c8e7ed749d237d78f1a8d252f4dfa0b4eaaab",
9
+ ".naome/bin/check-harness-health.js": "sha256:802d7419774981a6af1826b3882270ff8f41259d516f98c52a02b4ddc184c467",
9
10
  ".naome/task-contract.schema.json": "sha256:1b3b62350328d0d6d660e36d1d1baaa2b88718530db774f9ab2a9e2fcba369c8",
10
- "AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
11
- "docs/naome/agent-workflow.md": "sha256:cbef6dee1543b4c74111f8dc23e81a5bf092a9585a342504678bfc9c9d0655ea",
12
- "docs/naome/context-economy.md": "sha256:3ed5075815ecf4ada46a5e65438769310307c35759fcd46b13dc0b96e02bebd9",
13
- "docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
14
- "docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
15
11
  "docs/naome/index.md": "sha256:07ef776f49130319a5280bdb3ae38af22141708253f38eb983a4336fbae1b25a",
12
+ "docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
13
+ "docs/naome/agent-workflow.md": "sha256:0be1c29adfbcd3fd73c4f904080ffc67237692fe413871a30243538c4db38ac7",
14
+ "docs/naome/context-economy.md": "sha256:3ed5075815ecf4ada46a5e65438769310307c35759fcd46b13dc0b96e02bebd9",
16
15
  "docs/naome/task-ledger.md": "sha256:6ca7222c80079b4662fb718d3c71d686770646f1fa52b83b0e90aed1c5a1101b",
16
+ "docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
17
17
  "docs/naome/upgrade.md": "sha256:2c60f0441bbd98bd528d109b30a7ded4b0ad55d61ffb9f52edac9e93b7999cb1"
18
18
  },
19
19
  "machineOwned": [
@@ -27,8 +27,8 @@
27
27
  "docs/naome/first-run.md",
28
28
  "docs/naome/agent-workflow.md",
29
29
  "docs/naome/context-economy.md",
30
- "docs/naome/execution.md",
31
30
  "docs/naome/task-ledger.md",
31
+ "docs/naome/execution.md",
32
32
  "docs/naome/upgrade.md"
33
33
  ],
34
34
  "name": "naome",
@@ -11,11 +11,20 @@ Use this workflow after first-run intake is complete.
11
11
  `canCreateTask` fields instead of inventing routing or final-response text.
12
12
  If route returns a `taskRoot` different from the current directory, continue
13
13
  the task from that path and leave the original worktree untouched.
14
- When preparing the route prompt file, prepend a fenced `naome-intent-v2`
15
- JSON envelope that states `workflowAction`, `taskIntent`, and `risk` using
16
- canonical NAOME schema constants such as `commit_request`,
17
- `task_revision`, and `credential_context`. Keep the original user text below
18
- it. Do not derive workflow actions from natural-language keywords.
14
+ When preparing the route prompt file, first normalize the user's raw prompt
15
+ into a fenced `naome-prompt-envelope-v1` JSON envelope. The envelope is the
16
+ routing input; the raw user text below it is audit text. Use canonical NAOME
17
+ schema fields such as `requestKind`, `mutationIntent`,
18
+ `publicationIntent`, `requestedActions`, `referencedPaths`, `constraints`,
19
+ `uncertainties`, `workflowAction`, `taskIntent`, and `risk`. Do not derive
20
+ workflow actions from natural-language keywords, localized words, or the
21
+ prompt's prose language. If a prompt file has no envelope, route returns a
22
+ non-mutating `normalize_prompt_first` decision and the agent must add the
23
+ deterministic envelope before retrying. `naome-intent-v2` is not supported.
24
+ Unknown envelope values require normalization, and conflicting envelope
25
+ fields block as ambiguous instead of mutating. Put concrete files in
26
+ `referencedPaths`; prompt context selection treats those paths as the
27
+ primary source of path intent.
19
28
  3. Use `node .naome/bin/naome.js explain --prompt-file <path> --json` only when
20
29
  debugging why a policy won.
21
30
  4. Run `node .naome/bin/naome.js status --json` when reporting state without
@@ -18,6 +18,15 @@ Status: Uninitialized
18
18
  - Per-check proof files are local run evidence. Prefer compact proof batches in
19
19
  the committed task-state projection when many release checks share the same
20
20
  evidence paths.
21
+ - Prompt routing uses fenced `naome-prompt-envelope-v1` JSON envelopes as the
22
+ deterministic routing input. Raw natural-language prompts are audit text and
23
+ must not be treated as workflow authority until an agent normalizes them into
24
+ canonical fields such as `requestKind`, `mutationIntent`,
25
+ `publicationIntent`, `requestedActions`, `workflowAction`, `taskIntent`, and
26
+ `risk`. Legacy `naome-intent-v2` envelopes are not supported. Unknown
27
+ envelope values require prompt normalization, conflicting fields block as
28
+ ambiguous, and `referencedPaths` is the primary context-selection source for
29
+ prompt-mentioned files.
21
30
 
22
31
  ## Assumed Boundaries
23
32
 
@@ -1,170 +0,0 @@
1
- use super::model::IntentKind;
2
-
3
- pub(crate) fn normalized(text: &str) -> String {
4
- text.to_lowercase()
5
- .chars()
6
- .map(|ch| if ch.is_alphanumeric() { ch } else { ' ' })
7
- .collect::<String>()
8
- .split_whitespace()
9
- .collect::<Vec<_>>()
10
- .join(" ")
11
- }
12
-
13
- pub(crate) fn lexical_tokens(text: &str) -> Vec<String> {
14
- text.split_whitespace()
15
- .map(|token| {
16
- token
17
- .trim_matches(|ch: char| !ch.is_alphanumeric() && ch != '_' && ch != '-')
18
- .to_lowercase()
19
- })
20
- .filter(|token| !token.is_empty())
21
- .collect()
22
- }
23
-
24
- pub(crate) fn structured_workflow_intents(text: &str) -> Vec<IntentKind> {
25
- let tokens = lexical_tokens(text);
26
- let mut intents = Vec::new();
27
-
28
- if let Some(intent) = structured_action(&tokens) {
29
- intents.push(intent);
30
- }
31
- if let Some(intent) = legacy_v1_short_action_request(&tokens) {
32
- intents.push(intent);
33
- }
34
- if legacy_v1_no_commit(&tokens) {
35
- intents.push(IntentKind::NoCommitRequest);
36
- }
37
- if has_structured_token(&tokens, &["no_commit", "without_commit"]) {
38
- intents.push(IntentKind::NoCommitRequest);
39
- }
40
-
41
- intents.sort_by_key(|kind| kind.as_str());
42
- intents.dedup();
43
- intents
44
- }
45
-
46
- pub(crate) fn command_workflow_intents(text: &str) -> Vec<IntentKind> {
47
- let tokens = lexical_tokens(text);
48
- let mut intents = Vec::new();
49
- if let Some(intent) = cli_action(&tokens) {
50
- intents.push(intent);
51
- }
52
- intents
53
- }
54
-
55
- pub(crate) fn explicit_task_intent(text: &str) -> Option<IntentKind> {
56
- let tokens = lexical_tokens(text);
57
- if has_structured_token(&tokens, &["task_revision", "current_task", "active_task"]) {
58
- return Some(IntentKind::TaskRevision);
59
- }
60
- if has_structured_token(&tokens, &["new_task", "create_new_task", "separate_task"]) {
61
- return Some(IntentKind::NewTask);
62
- }
63
- None
64
- }
65
-
66
- pub(crate) fn is_generic_work_request(text: &str) -> bool {
67
- !lexical_tokens(text).is_empty()
68
- }
69
-
70
- fn structured_action(tokens: &[String]) -> Option<IntentKind> {
71
- policy_action(tokens)
72
- }
73
-
74
- fn policy_action(tokens: &[String]) -> Option<IntentKind> {
75
- for token in tokens {
76
- let intent = match token.as_str() {
77
- "commit_task_baseline" | "commit_user_diff" | "commit_upgrade_baseline" => {
78
- IntentKind::CommitRequest
79
- }
80
- "review_task_diff" | "review_current_task_diff" | "review_unowned_diff" => {
81
- IntentKind::ReviewRequest
82
- }
83
- "repair_harness" | "repair_harness_only" => IntentKind::RepairRequest,
84
- "cancel_task_changes" | "cancel_current_task" => IntentKind::CancelRequest,
85
- "continue_current_task" | "task_complete" | "complete_task" => {
86
- IntentKind::TaskCompletion
87
- }
88
- "answer_status_only" => IntentKind::StatusQuestion,
89
- "clear_or_commit_unowned_diff" => IntentKind::Ambiguous,
90
- _ => continue,
91
- };
92
- return Some(intent);
93
- }
94
- None
95
- }
96
-
97
- fn cli_action(tokens: &[String]) -> Option<IntentKind> {
98
- match (
99
- tokens.first().map(String::as_str),
100
- tokens.get(1).map(String::as_str),
101
- ) {
102
- (Some("naome"), Some("commit")) => Some(IntentKind::CommitRequest),
103
- (Some("naome"), Some("status")) => Some(IntentKind::StatusQuestion),
104
- (Some("naome"), Some("sync" | "update" | "install")) => Some(IntentKind::RepairRequest),
105
- (Some("git"), Some("commit")) => Some(IntentKind::CommitRequest),
106
- _ => None,
107
- }
108
- }
109
-
110
- // Kept only so pre-v2 route callers keep their existing conservative behavior.
111
- // A naome-intent-v2 envelope clears these candidates before policy resolution.
112
- fn legacy_v1_short_action_request(tokens: &[String]) -> Option<IntentKind> {
113
- let action_index = tokens
114
- .iter()
115
- .position(|token| legacy_v1_action_intent(token).is_some())?;
116
- if action_index > 1 || tokens.len() > 6 {
117
- return None;
118
- }
119
-
120
- let intent = legacy_v1_action_intent(&tokens[action_index])?;
121
- if intent == IntentKind::StatusQuestion || tokens.len() <= 3 {
122
- return Some(intent);
123
- }
124
- if tokens.len() <= 2 || legacy_v1_has_action_scope(tokens) {
125
- return Some(intent);
126
- }
127
- None
128
- }
129
-
130
- fn legacy_v1_no_commit(tokens: &[String]) -> bool {
131
- tokens
132
- .windows(3)
133
- .any(|window| window[0] == "do" && window[1] == "not" && window[2] == "commit")
134
- || tokens
135
- .windows(2)
136
- .any(|window| matches!(window[0].as_str(), "no" | "without") && window[1] == "commit")
137
- }
138
-
139
- fn legacy_v1_action_intent(token: &str) -> Option<IntentKind> {
140
- match token {
141
- "commit" | "baseline" => Some(IntentKind::CommitRequest),
142
- "review" => Some(IntentKind::ReviewRequest),
143
- "repair" | "sync" => Some(IntentKind::RepairRequest),
144
- "cancel" => Some(IntentKind::CancelRequest),
145
- "complete" | "completion" => Some(IntentKind::TaskCompletion),
146
- "status" => Some(IntentKind::StatusQuestion),
147
- _ => None,
148
- }
149
- }
150
-
151
- fn legacy_v1_has_action_scope(tokens: &[String]) -> bool {
152
- has_structured_token(
153
- tokens,
154
- &[
155
- "task",
156
- "diff",
157
- "harness",
158
- "baseline",
159
- "state",
160
- "current_task",
161
- "active_task",
162
- ],
163
- )
164
- }
165
-
166
- fn has_structured_token(tokens: &[String], accepted: &[&str]) -> bool {
167
- tokens
168
- .iter()
169
- .any(|token| accepted.iter().any(|accepted| token == accepted))
170
- }