@lamentis/naome 1.3.6 → 1.3.8
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 +9 -3
- package/crates/naome-cli/Cargo.toml +1 -1
- package/crates/naome-core/Cargo.toml +1 -1
- package/crates/naome-core/src/context/select.rs +58 -4
- package/crates/naome-core/src/git.rs +1 -26
- package/crates/naome-core/src/information_architecture.rs +15 -26
- package/crates/naome-core/src/install_plan.rs +2 -0
- package/crates/naome-core/src/intent/classifier.rs +56 -81
- package/crates/naome-core/src/intent/envelope.rs +173 -19
- package/crates/naome-core/src/intent/legacy_response.rs +2 -0
- package/crates/naome-core/src/intent/model.rs +6 -0
- package/crates/naome-core/src/intent/resolver.rs +25 -0
- package/crates/naome-core/src/intent/risk.rs +11 -1
- package/crates/naome-core/src/intent.rs +1 -1
- package/crates/naome-core/src/lib.rs +1 -0
- package/crates/naome-core/src/paths.rs +27 -0
- package/crates/naome-core/src/quality/scanner/repo_paths.rs +2 -47
- package/crates/naome-core/src/repo_paths.rs +76 -0
- package/crates/naome-core/src/repository_model/path_scan.rs +2 -23
- package/crates/naome-core/src/route/context.rs +8 -0
- package/crates/naome-core/src/task_ledger/write.rs +6 -0
- package/crates/naome-core/src/task_ledger.rs +50 -2
- package/crates/naome-core/src/task_state/util.rs +21 -17
- package/crates/naome-core/tests/context.rs +92 -0
- package/crates/naome-core/tests/decision.rs +2 -10
- package/crates/naome-core/tests/information_architecture.rs +7 -10
- package/crates/naome-core/tests/install_plan.rs +2 -0
- package/crates/naome-core/tests/intent.rs +98 -18
- package/crates/naome-core/tests/intent_support/mod.rs +39 -1
- package/crates/naome-core/tests/intent_v2.rs +299 -10
- package/crates/naome-core/tests/quality_structure_support/mod.rs +6 -25
- package/crates/naome-core/tests/repo_support/mod.rs +3 -5
- package/crates/naome-core/tests/repo_support/repo_helpers.rs +2 -9
- package/crates/naome-core/tests/repo_support/routes.rs +8 -2
- package/crates/naome-core/tests/repo_support/verification.rs +1 -8
- package/crates/naome-core/tests/repo_support/verification_values.rs +20 -18
- package/crates/naome-core/tests/route_baseline.rs +29 -0
- package/crates/naome-core/tests/route_completion.rs +26 -5
- package/crates/naome-core/tests/route_harness_refresh.rs +7 -1
- package/crates/naome-core/tests/route_user_diff.rs +1 -1
- package/crates/naome-core/tests/task_ledger.rs +69 -1
- package/crates/naome-core/tests/task_state_compact.rs +7 -1
- package/crates/naome-core/tests/task_state_compact_support/states.rs +10 -8
- package/crates/naome-core/tests/task_state_support/states.rs +8 -8
- package/crates/naome-core/tests/workflow_support/mod.rs +2 -0
- package/native/darwin-arm64/naome +0 -0
- package/native/linux-x64/naome +0 -0
- package/package.json +1 -1
- package/templates/naome-root/.naome/manifest.json +3 -3
- package/templates/naome-root/.naomeignore +1 -0
- package/templates/naome-root/docs/naome/agent-workflow.md +22 -15
- package/templates/naome-root/docs/naome/architecture.md +17 -8
- package/templates/naome-root/docs/naome/task-ledger.md +20 -17
- package/crates/naome-core/src/intent/patterns.rs +0 -170
|
@@ -9,6 +9,12 @@ use repo_support::{
|
|
|
9
9
|
TestRepo,
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
fn repair_prompt(prompt: &str) -> String {
|
|
13
|
+
format!(
|
|
14
|
+
"```naome-prompt-envelope-v1\n{{\"schema\":\"naome.prompt-envelope.v1\",\"requestKind\":\"fix\",\"mutationIntent\":\"modify_files\",\"workflowAction\":\"repair_request\",\"taskIntent\":\"none\",\"risk\":\"none\",\"requestedActions\":[\"repair\"],\"referencedPaths\":[],\"constraints\":[],\"uncertainties\":[]}}\n```\n\n{prompt}"
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
|
|
12
18
|
#[test]
|
|
13
19
|
fn execute_route_baselines_harness_refresh_before_dirty_repo_worktree() {
|
|
14
20
|
let repo = TestRepo::dirty_harness_refresh_repo("route-dirty-harness-refresh-worktree", true);
|
|
@@ -66,7 +72,7 @@ fn execute_route_repair_request_baselines_harness_refresh_only() {
|
|
|
66
72
|
|
|
67
73
|
let route = evaluate_route(
|
|
68
74
|
repo.path(),
|
|
69
|
-
"please repair all",
|
|
75
|
+
&repair_prompt("please repair all"),
|
|
70
76
|
RouteOptions {
|
|
71
77
|
execute: true,
|
|
72
78
|
evaluation: EvaluationOptions::offline(),
|
|
@@ -27,7 +27,7 @@ fn execute_route_does_not_mutate_or_offer_clear_commit_for_dirty_unowned_diff()
|
|
|
27
27
|
)
|
|
28
28
|
.unwrap();
|
|
29
29
|
|
|
30
|
-
assert_eq!(route.policy_action, "
|
|
30
|
+
assert_eq!(route.policy_action, "normalize_prompt_first");
|
|
31
31
|
assert!(!route.mutation_performed);
|
|
32
32
|
assert!(!route.can_create_task);
|
|
33
33
|
assert_eq!(route.executed_actions, Vec::<String>::new());
|
|
@@ -190,6 +190,70 @@ fn task_state_validation_reports_stale_rendered_projection_when_ledger_exists()
|
|
|
190
190
|
}));
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
+
#[test]
|
|
194
|
+
fn ignored_local_runtime_ledger_does_not_stale_committed_projection() {
|
|
195
|
+
let repo = TestRepo::new("ignored-runtime-ledger");
|
|
196
|
+
repo.init_git();
|
|
197
|
+
repo.write_file(".naomeignore", ".naome/archive/\n.naome/tasks/\n");
|
|
198
|
+
repo.write_file("README.md", "# Baseline\n");
|
|
199
|
+
repo.write_base_harness(Some(idle_state()));
|
|
200
|
+
repo.git(&["add", "."]);
|
|
201
|
+
repo.git(&["commit", "-m", "baseline"]);
|
|
202
|
+
let head = repo.git_stdout(&["rev-parse", "HEAD"]);
|
|
203
|
+
repo.write_complete_ledger(&head);
|
|
204
|
+
repo.write_naome_json("task-state.json", compact_complete_state(&head));
|
|
205
|
+
repo.write_file("README.md", "# Changed\n");
|
|
206
|
+
|
|
207
|
+
let report = validate_task_state(repo.path(), TaskStateOptions::default()).unwrap();
|
|
208
|
+
|
|
209
|
+
assert!(report.errors.is_empty(), "{:?}", report.errors);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
#[test]
|
|
213
|
+
fn compact_completed_task_state_survives_incomplete_local_runtime_ledger() {
|
|
214
|
+
let repo = TestRepo::new("compact-over-runtime-ledger");
|
|
215
|
+
repo.init_git();
|
|
216
|
+
repo.write_file("README.md", "# Baseline\n");
|
|
217
|
+
repo.write_base_harness(Some(idle_state()));
|
|
218
|
+
repo.git(&["add", "."]);
|
|
219
|
+
repo.git(&["commit", "-m", "baseline"]);
|
|
220
|
+
let head = repo.git_stdout(&["rev-parse", "HEAD"]);
|
|
221
|
+
repo.write_naome_json("task-state.json", compact_complete_state(&head));
|
|
222
|
+
repo.write_file(
|
|
223
|
+
".naome/tasks/active.json",
|
|
224
|
+
&format_json(object([
|
|
225
|
+
("schema", json!("naome.task-ledger-active.v1")),
|
|
226
|
+
("version", json!(1)),
|
|
227
|
+
("primaryTaskId", json!("old-local-task")),
|
|
228
|
+
(
|
|
229
|
+
"worklanes",
|
|
230
|
+
json!([{ "id": "default", "taskId": "old-local-task", "status": "active" }]),
|
|
231
|
+
),
|
|
232
|
+
])),
|
|
233
|
+
);
|
|
234
|
+
repo.write_file(
|
|
235
|
+
".naome/tasks/old-local-task/task.json",
|
|
236
|
+
&format_json(task_spec_record_with_id(&head, "old-local-task")),
|
|
237
|
+
);
|
|
238
|
+
repo.write_file(
|
|
239
|
+
".naome/tasks/old-local-task/events.jsonl",
|
|
240
|
+
concat!(
|
|
241
|
+
"{\"schema\":\"naome.task-ledger-event.v1\",\"type\":\"status\",\"status\":\"implementing\",\"recordedAt\":\"2026-05-08T00:00:01.000Z\"}\n",
|
|
242
|
+
"{\"schema\":\"naome.task-ledger-event.v1\",\"type\":\"status\",\"status\":\"complete\",\"recordedAt\":\"2026-05-08T00:00:02.000Z\"}\n"
|
|
243
|
+
),
|
|
244
|
+
);
|
|
245
|
+
repo.write_file("README.md", "# Changed\n");
|
|
246
|
+
|
|
247
|
+
let projected = read_task_state_projection(repo.path()).unwrap().unwrap();
|
|
248
|
+
|
|
249
|
+
assert_eq!(
|
|
250
|
+
projected["activeTask"]["proofBatches"][0]["proofs"][0]["checkId"],
|
|
251
|
+
"diff-check"
|
|
252
|
+
);
|
|
253
|
+
let report = validate_task_state(repo.path(), TaskStateOptions::default()).unwrap();
|
|
254
|
+
assert!(report.errors.is_empty(), "{:?}", report.errors);
|
|
255
|
+
}
|
|
256
|
+
|
|
193
257
|
trait LedgerHarness {
|
|
194
258
|
fn write_base_harness(&self, task_state: Option<Value>);
|
|
195
259
|
fn write_complete_ledger(&self, admission_head: &str);
|
|
@@ -298,10 +362,14 @@ fn compact_active_task(admission_head: &str) -> Value {
|
|
|
298
362
|
}
|
|
299
363
|
|
|
300
364
|
fn task_spec_record(admission_head: &str) -> Value {
|
|
365
|
+
task_spec_record_with_id(admission_head, "readme-task")
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
fn task_spec_record_with_id(admission_head: &str, task_id: &str) -> Value {
|
|
301
369
|
object([
|
|
302
370
|
("schema", json!("naome.task-ledger-task.v1")),
|
|
303
371
|
("version", json!(1)),
|
|
304
|
-
("id", json!(
|
|
372
|
+
("id", json!(task_id)),
|
|
305
373
|
("request", json!("Update README.")),
|
|
306
374
|
("userPrompt", user_prompt()),
|
|
307
375
|
("admission", admission_record(admission_head)),
|
|
@@ -6,6 +6,12 @@ use task_state_compact_support::{
|
|
|
6
6
|
compact_state, large_compact_state, large_expanded_state, legacy_state, MiniRepo,
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
+
fn new_task_prompt(prompt: &str) -> String {
|
|
10
|
+
format!(
|
|
11
|
+
"```naome-prompt-envelope-v1\n{{\"schema\":\"naome.prompt-envelope.v1\",\"requestKind\":\"implementation\",\"mutationIntent\":\"modify_files\",\"workflowAction\":\"none\",\"taskIntent\":\"new_task\",\"risk\":\"none\",\"requestedActions\":[],\"referencedPaths\":[],\"constraints\":[],\"uncertainties\":[]}}\n```\n\n{prompt}"
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
|
|
9
15
|
#[test]
|
|
10
16
|
fn legacy_v1_proof_results_remain_valid() {
|
|
11
17
|
let repo = MiniRepo::new();
|
|
@@ -30,7 +36,7 @@ fn compact_path_sets_and_batches_cover_completion_commit_and_route() {
|
|
|
30
36
|
|
|
31
37
|
let route = evaluate_route(
|
|
32
38
|
repo.path(),
|
|
33
|
-
"new task",
|
|
39
|
+
&new_task_prompt("new task"),
|
|
34
40
|
RouteOptions {
|
|
35
41
|
execute: false,
|
|
36
42
|
evaluation: EvaluationOptions::offline(),
|
|
@@ -129,14 +129,16 @@ fn base_state(admission_head: &str, proof_payload: Value) -> Value {
|
|
|
129
129
|
task.as_object_mut()
|
|
130
130
|
.unwrap()
|
|
131
131
|
.extend(proof_payload.as_object().unwrap().clone());
|
|
132
|
-
|
|
133
|
-
"
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
132
|
+
let mut state: Value = serde_json::from_str(include_str!(
|
|
133
|
+
"../../../../templates/naome-root/.naome/task-state.json"
|
|
134
|
+
))
|
|
135
|
+
.unwrap();
|
|
136
|
+
state["schema"] = json!("naome.task-state.v2");
|
|
137
|
+
state["version"] = json!(2);
|
|
138
|
+
state["status"] = json!("complete");
|
|
139
|
+
state["activeTask"] = task;
|
|
140
|
+
state["updatedAt"] = json!(T0);
|
|
141
|
+
state
|
|
140
142
|
}
|
|
141
143
|
|
|
142
144
|
fn proof(check_id: &str, command: &str, cwd: &str) -> Value {
|
|
@@ -13,14 +13,14 @@ pub fn complete_task_state(overrides: Value) -> Value {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
fn task_state_record(status: &str, active_task: Value, updated_at: Value) -> Value {
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
let mut state: Value = serde_json::from_str(include_str!(
|
|
17
|
+
"../../../../templates/naome-root/.naome/task-state.json"
|
|
18
|
+
))
|
|
19
|
+
.unwrap();
|
|
20
|
+
state["status"] = json!(status);
|
|
21
|
+
state["activeTask"] = active_task;
|
|
22
|
+
state["updatedAt"] = updated_at;
|
|
23
|
+
state
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
pub fn active_task(overrides: Value) -> Value {
|
|
Binary file
|
package/native/linux-x64/naome
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"harnessVersion": "1.
|
|
2
|
+
"harnessVersion": "1.3.8",
|
|
3
3
|
"installedAt": null,
|
|
4
4
|
"integrity": {
|
|
5
5
|
".naome/bin/check-harness-health.js": "sha256:dc4de52b79c69600b9ba47b924e2c2b8de61a2cbfab6d1ccc0f1924d963db657",
|
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
|
|
9
9
|
".naome/task-contract.schema.json": "sha256:1b3b62350328d0d6d660e36d1d1baaa2b88718530db774f9ab2a9e2fcba369c8",
|
|
10
10
|
"AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
|
|
11
|
-
"docs/naome/agent-workflow.md": "sha256:
|
|
11
|
+
"docs/naome/agent-workflow.md": "sha256:0be1c29adfbcd3fd73c4f904080ffc67237692fe413871a30243538c4db38ac7",
|
|
12
12
|
"docs/naome/context-economy.md": "sha256:3ed5075815ecf4ada46a5e65438769310307c35759fcd46b13dc0b96e02bebd9",
|
|
13
13
|
"docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
|
|
14
14
|
"docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
|
|
15
15
|
"docs/naome/index.md": "sha256:07ef776f49130319a5280bdb3ae38af22141708253f38eb983a4336fbae1b25a",
|
|
16
|
-
"docs/naome/task-ledger.md": "sha256:
|
|
16
|
+
"docs/naome/task-ledger.md": "sha256:6ca7222c80079b4662fb718d3c71d686770646f1fa52b83b0e90aed1c5a1101b",
|
|
17
17
|
"docs/naome/upgrade.md": "sha256:2c60f0441bbd98bd528d109b30a7ded4b0ad55d61ffb9f52edac9e93b7999cb1"
|
|
18
18
|
},
|
|
19
19
|
"machineOwned": [
|
|
@@ -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,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
|
@@ -110,22 +119,20 @@ Use this workflow after first-run intake is complete.
|
|
|
110
119
|
1. Identify changed files.
|
|
111
120
|
2. Match them against `.naome/verification.json`.
|
|
112
121
|
3. Run the required checks when available.
|
|
113
|
-
4. Prefer ledger-backed task updates. `naome sync` migrates active legacy
|
|
122
|
+
4. Prefer local ledger-backed task updates. `naome sync` migrates active legacy
|
|
114
123
|
task-state automatically; if a legacy-only active task is still present, run
|
|
115
124
|
`node .naome/bin/naome.js task migrate-ledger --write --json` before adding
|
|
116
125
|
completion proof.
|
|
117
|
-
5. Record proof as compact `proofPathSets` and `proofBatches` in
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
and include every changed in-scope path reported by git in expanded proof
|
|
123
|
-
evidence.
|
|
126
|
+
5. Record proof as compact `proofPathSets` and `proofBatches` in the local
|
|
127
|
+
ledger when many checks share evidence paths. Use local per-check proof files
|
|
128
|
+
only when separate writers need them during the run. The committed release
|
|
129
|
+
artifact is `.naome/task-state.json`; include every changed in-scope path
|
|
130
|
+
reported by git in expanded proof evidence.
|
|
124
131
|
6. Run `node .naome/bin/naome.js task render-state --write --json` before
|
|
125
132
|
external compatibility checks. Do not hand-edit the rendered projection when
|
|
126
133
|
`.naome/tasks/active.json` exists.
|
|
127
|
-
7. Do not list `.naome/task-state.json` or
|
|
128
|
-
proof evidence.
|
|
134
|
+
7. Do not list `.naome/task-state.json` or local task runtime folders as task
|
|
135
|
+
scope or proof evidence.
|
|
129
136
|
8. Stop tracked long-running processes or mark them explicitly allowed in
|
|
130
137
|
`.naome/processes.json`.
|
|
131
138
|
9. Set task status to `complete` in the ledger event stream or legacy task
|
|
@@ -8,16 +8,25 @@ Status: Uninitialized
|
|
|
8
8
|
|
|
9
9
|
## Known Boundaries
|
|
10
10
|
|
|
11
|
-
- NAOME information falls into durable project state,
|
|
12
|
-
|
|
11
|
+
- NAOME information falls into durable project state, generated projection,
|
|
12
|
+
local runtime state, run evidence, and product source.
|
|
13
13
|
- Durable project state is committed repository or package state needed to
|
|
14
14
|
reinstall or reconstruct the harness.
|
|
15
|
-
- `.naome/task-state.json` is
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
- `.naome/task-state.json` is the committed compact task-state projection.
|
|
16
|
+
- `.naome/tmp/` and `.naome/tasks/` are local runtime state and must not be
|
|
17
|
+
committed.
|
|
18
|
+
- Per-check proof files are local run evidence. Prefer compact proof batches in
|
|
19
|
+
the committed task-state projection when many release checks share the same
|
|
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,8 +1,9 @@
|
|
|
1
1
|
# Task Ledger
|
|
2
2
|
|
|
3
|
-
NAOME task state is moving from one mutable aggregate file to a
|
|
4
|
-
ledger. The compatibility file `.naome/task-state.json` remains
|
|
5
|
-
|
|
3
|
+
NAOME task state is moving from one mutable aggregate file to a local task
|
|
4
|
+
ledger. The compatibility file `.naome/task-state.json` remains the compact
|
|
5
|
+
committed projection, while `.naome/tasks/` is machine-local runtime state for
|
|
6
|
+
efficient task updates.
|
|
6
7
|
|
|
7
8
|
## Layout
|
|
8
9
|
|
|
@@ -33,9 +34,10 @@ new deterministic task tooling can use `.naome/tasks/` as the source of truth.
|
|
|
33
34
|
## Compatibility
|
|
34
35
|
|
|
35
36
|
Existing `naome.task-state.v1` and `naome.task-state.v2` files remain valid. If
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
a current local ledger exists, NAOME readers build a canonical task model from
|
|
38
|
+
it and render a `naome.task-state.v2` projection. If no local ledger is present,
|
|
39
|
+
or an older local completed ledger lacks proof detail that the committed compact
|
|
40
|
+
projection still has, readers fall back to `.naome/task-state.json`.
|
|
39
41
|
|
|
40
42
|
Use this command when an external tool needs the compatibility file refreshed:
|
|
41
43
|
|
|
@@ -44,21 +46,22 @@ node .naome/bin/naome.js task render-state --write --json
|
|
|
44
46
|
```
|
|
45
47
|
|
|
46
48
|
`naome sync` automatically splits an active legacy `task-state` file into the
|
|
47
|
-
ledger layout. The explicit command remains available for repair or
|
|
49
|
+
local ledger layout. The explicit command remains available for repair or
|
|
50
|
+
tests:
|
|
48
51
|
|
|
49
52
|
```text
|
|
50
53
|
node .naome/bin/naome.js task migrate-ledger --write --json
|
|
51
54
|
```
|
|
52
55
|
|
|
53
56
|
After `.naome/tasks/active.json` exists, `.naome/task-state.json` is a rendered
|
|
54
|
-
compatibility projection. NAOME gates reject a stale projection and
|
|
55
|
-
render command instead of accepting hand-edited aggregate state.
|
|
57
|
+
compatibility projection. NAOME gates reject a stale active projection and
|
|
58
|
+
report the render command instead of accepting hand-edited aggregate state.
|
|
56
59
|
|
|
57
60
|
## Conflict Policy
|
|
58
61
|
|
|
59
|
-
`.naome/tasks/` is NAOME
|
|
60
|
-
|
|
61
|
-
whether product changes stay inside `allowedPaths`.
|
|
62
|
+
`.naome/tasks/` is local NAOME runtime state. It is ignored, untracked by
|
|
63
|
+
`naome sync`, and not task feature scope or proof evidence. Gates ignore ledger
|
|
64
|
+
control files when checking whether product changes stay inside `allowedPaths`.
|
|
62
65
|
|
|
63
66
|
The intended long-term model is:
|
|
64
67
|
|
|
@@ -76,8 +79,8 @@ instead of all competing for `.naome/task-state.json`.
|
|
|
76
79
|
## Information Policy
|
|
77
80
|
|
|
78
81
|
Use `node .naome/bin/naome.js workflow information --path <path> --json` before
|
|
79
|
-
changing NAOME control files whose retention is unclear. Durable configuration
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
changing NAOME control files whose retention is unclear. Durable configuration
|
|
83
|
+
and templates are restored from repository or package state.
|
|
84
|
+
`.naome/task-state.json` is the committed compact task projection. `.naome/tmp/`
|
|
85
|
+
and `.naome/tasks/` are local runtime state. Compact release proof batches keep
|
|
86
|
+
release diffs readable without tracking per-task runtime folders.
|
|
@@ -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
|
-
}
|