@lamentis/naome 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +2 -2
- package/bin/naome-node.js +1 -0
- package/crates/naome-cli/Cargo.toml +1 -1
- package/crates/naome-core/Cargo.toml +1 -1
- package/crates/naome-core/src/route.rs +67 -4
- package/crates/naome-core/src/task_state.rs +51 -5
- package/crates/naome-core/tests/route.rs +51 -0
- package/crates/naome-core/tests/task_state.rs +140 -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 +1 -1
- package/templates/naome-root/.naome/upgrade-state.json +1 -1
package/Cargo.lock
CHANGED
|
@@ -76,7 +76,7 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
|
|
76
76
|
|
|
77
77
|
[[package]]
|
|
78
78
|
name = "naome-cli"
|
|
79
|
-
version = "1.1.
|
|
79
|
+
version = "1.1.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.1.
|
|
87
|
+
version = "1.1.1"
|
|
88
88
|
dependencies = [
|
|
89
89
|
"serde",
|
|
90
90
|
"serde_json",
|
package/bin/naome-node.js
CHANGED
|
@@ -513,6 +513,7 @@ async function runFreshInstall() {
|
|
|
513
513
|
patchInstalledMachineOwnedIntegrity();
|
|
514
514
|
ensureBuiltInVerificationChecks();
|
|
515
515
|
patchManifestDate();
|
|
516
|
+
ensureCompleteUpgradeState(null);
|
|
516
517
|
ensureArchiveDirectory();
|
|
517
518
|
takeoverExistingAgents();
|
|
518
519
|
ensureLocalOnlySourceControlBoundary();
|
|
@@ -109,13 +109,19 @@ pub fn evaluate_route(
|
|
|
109
109
|
.to_string();
|
|
110
110
|
}
|
|
111
111
|
"auto_commit_completed_task_then_create_isolated_task_worktree" => {
|
|
112
|
-
let
|
|
112
|
+
let worktree_name_head = task_worktree_name_head(root)?;
|
|
113
|
+
preflight_isolated_task_worktree(root, prompt, &worktree_name_head)?;
|
|
114
|
+
let before = Some(worktree_name_head.clone());
|
|
113
115
|
git_add_completed_task_paths(root)?;
|
|
114
116
|
git_commit(root, "chore(naome): baseline completed task")?;
|
|
115
117
|
let after = git_head(root)?;
|
|
116
118
|
journal_entry =
|
|
117
119
|
append_task_journal(root, "route_auto_baseline", before, after.clone())?;
|
|
118
|
-
let created =
|
|
120
|
+
let created = create_isolated_task_worktree_with_name_head(
|
|
121
|
+
root,
|
|
122
|
+
prompt,
|
|
123
|
+
&worktree_name_head,
|
|
124
|
+
)?;
|
|
119
125
|
task_root = PathBuf::from(&created.path);
|
|
120
126
|
mutation_performed = true;
|
|
121
127
|
executed_actions.push("commit_task_baseline".to_string());
|
|
@@ -147,6 +153,8 @@ pub fn evaluate_route(
|
|
|
147
153
|
user_message = "NAOME baselined the harness refresh and completed task, then admitted the next task.".to_string();
|
|
148
154
|
}
|
|
149
155
|
"auto_commit_harness_refresh_then_create_isolated_task_worktree" => {
|
|
156
|
+
let worktree_name_head = task_worktree_name_head(root)?;
|
|
157
|
+
preflight_isolated_task_worktree(root, prompt, &worktree_name_head)?;
|
|
150
158
|
let Some(split) = harness_refresh_with_unrelated_diff(root)? else {
|
|
151
159
|
return Err(NaomeError::new(
|
|
152
160
|
"Unable to split harness refresh paths from unrelated dirty paths.",
|
|
@@ -154,7 +162,11 @@ pub fn evaluate_route(
|
|
|
154
162
|
};
|
|
155
163
|
git_stage_only_paths(root, &split.harness_paths)?;
|
|
156
164
|
git_commit(root, "chore(naome): baseline harness refresh")?;
|
|
157
|
-
let created =
|
|
165
|
+
let created = create_isolated_task_worktree_with_name_head(
|
|
166
|
+
root,
|
|
167
|
+
prompt,
|
|
168
|
+
&worktree_name_head,
|
|
169
|
+
)?;
|
|
158
170
|
task_root = PathBuf::from(&created.path);
|
|
159
171
|
mutation_performed = true;
|
|
160
172
|
executed_actions.push("commit_harness_refresh_baseline".to_string());
|
|
@@ -848,10 +860,19 @@ fn git_commit(root: &Path, message: &str) -> Result<(), NaomeError> {
|
|
|
848
860
|
}
|
|
849
861
|
|
|
850
862
|
fn create_isolated_task_worktree(root: &Path, prompt: &str) -> Result<RouteWorktree, NaomeError> {
|
|
863
|
+
let name_head = task_worktree_name_head(root)?;
|
|
864
|
+
create_isolated_task_worktree_with_name_head(root, prompt, &name_head)
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
fn create_isolated_task_worktree_with_name_head(
|
|
868
|
+
root: &Path,
|
|
869
|
+
prompt: &str,
|
|
870
|
+
name_head: &str,
|
|
871
|
+
) -> Result<RouteWorktree, NaomeError> {
|
|
851
872
|
let base_head = git_head(root)?.ok_or_else(|| {
|
|
852
873
|
NaomeError::new("Cannot create task worktree because the repository has no HEAD.")
|
|
853
874
|
})?;
|
|
854
|
-
let short_head =
|
|
875
|
+
let short_head = name_head.chars().take(12).collect::<String>();
|
|
855
876
|
let slug = prompt_slug(prompt);
|
|
856
877
|
let common_git_dir = git_common_dir(root)?;
|
|
857
878
|
let worktree_base = common_git_dir.join("naome").join("worktrees");
|
|
@@ -900,6 +921,48 @@ fn create_isolated_task_worktree(root: &Path, prompt: &str) -> Result<RouteWorkt
|
|
|
900
921
|
))
|
|
901
922
|
}
|
|
902
923
|
|
|
924
|
+
fn preflight_isolated_task_worktree(
|
|
925
|
+
root: &Path,
|
|
926
|
+
prompt: &str,
|
|
927
|
+
name_head: &str,
|
|
928
|
+
) -> Result<(), NaomeError> {
|
|
929
|
+
let short_head = name_head.chars().take(12).collect::<String>();
|
|
930
|
+
let slug = prompt_slug(prompt);
|
|
931
|
+
let common_git_dir = git_common_dir(root)?;
|
|
932
|
+
let worktree_base = common_git_dir.join("naome").join("worktrees");
|
|
933
|
+
fs::create_dir_all(&worktree_base)?;
|
|
934
|
+
let worktree_count = existing_naome_task_worktree_count(&worktree_base)?;
|
|
935
|
+
if worktree_count >= MAX_NAOME_TASK_WORKTREES {
|
|
936
|
+
return Err(NaomeError::new(format!(
|
|
937
|
+
"Too many NAOME task worktrees are present ({worktree_count}). Finish or remove old task worktrees before creating another isolated task worktree."
|
|
938
|
+
)));
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
for attempt in 1..100 {
|
|
942
|
+
let suffix = if attempt == 1 {
|
|
943
|
+
String::new()
|
|
944
|
+
} else {
|
|
945
|
+
format!("-{attempt}")
|
|
946
|
+
};
|
|
947
|
+
let name = format!("{slug}-{short_head}{suffix}");
|
|
948
|
+
let branch = format!("naome/task/{name}");
|
|
949
|
+
let path = worktree_base.join(&name);
|
|
950
|
+
if !path.exists() && !git_branch_exists(root, &branch)? {
|
|
951
|
+
return Ok(());
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
Err(NaomeError::new(
|
|
956
|
+
"Cannot create a unique NAOME task worktree after 99 attempts.",
|
|
957
|
+
))
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
fn task_worktree_name_head(root: &Path) -> Result<String, NaomeError> {
|
|
961
|
+
git_head(root)?.ok_or_else(|| {
|
|
962
|
+
NaomeError::new("Cannot create task worktree because the repository has no HEAD.")
|
|
963
|
+
})
|
|
964
|
+
}
|
|
965
|
+
|
|
903
966
|
fn existing_naome_task_worktree_count(worktree_base: &Path) -> Result<usize, NaomeError> {
|
|
904
967
|
let mut count = 0;
|
|
905
968
|
for entry in fs::read_dir(worktree_base)? {
|
|
@@ -1469,10 +1469,10 @@ fn validate_commit_gate(
|
|
|
1469
1469
|
.get("status")
|
|
1470
1470
|
.and_then(Value::as_str)
|
|
1471
1471
|
.unwrap_or("invalid");
|
|
1472
|
-
if status == "complete" &&
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1472
|
+
if status == "complete" && is_deterministic_harness_refresh_diff(&changed_paths) {
|
|
1473
|
+
validate_pending_upgrade(task_state, root, errors)?;
|
|
1474
|
+
validate_completed_task_for_harness_refresh(task_state, root, &staged_entries, errors)?;
|
|
1475
|
+
return Ok(());
|
|
1476
1476
|
}
|
|
1477
1477
|
|
|
1478
1478
|
if status == "complete" {
|
|
@@ -1525,6 +1525,49 @@ fn validate_commit_gate(
|
|
|
1525
1525
|
Ok(())
|
|
1526
1526
|
}
|
|
1527
1527
|
|
|
1528
|
+
fn validate_completed_task_for_harness_refresh(
|
|
1529
|
+
task_state: &Value,
|
|
1530
|
+
root: &Path,
|
|
1531
|
+
staged_entries: &[ChangedEntry],
|
|
1532
|
+
errors: &mut Vec<String>,
|
|
1533
|
+
) -> Result<(), NaomeError> {
|
|
1534
|
+
validate_active_task(task_state.get("activeTask"), errors);
|
|
1535
|
+
validate_active_task_references(task_state.get("activeTask"), root, errors, Some("complete"))?;
|
|
1536
|
+
if !task_state.get("blocker").is_some_and(Value::is_null) {
|
|
1537
|
+
errors.push("complete task state must have blocker set to null.".to_string());
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
let Some(active_task) = task_state.get("activeTask") else {
|
|
1541
|
+
return Ok(());
|
|
1542
|
+
};
|
|
1543
|
+
|
|
1544
|
+
let check_ids = read_verification_check_ids(root, errors)?;
|
|
1545
|
+
validate_required_check_ids(active_task, &check_ids, errors);
|
|
1546
|
+
|
|
1547
|
+
let mut validation_errors = Vec::new();
|
|
1548
|
+
validate_complete_task_against_entries(
|
|
1549
|
+
active_task,
|
|
1550
|
+
root,
|
|
1551
|
+
&check_ids,
|
|
1552
|
+
staged_entries,
|
|
1553
|
+
&mut validation_errors,
|
|
1554
|
+
)?;
|
|
1555
|
+
|
|
1556
|
+
let staged_harness_paths = task_diff_from_entries(active_task, staged_entries).outside_paths;
|
|
1557
|
+
let allowed_scope_error = format!(
|
|
1558
|
+
"Changed files outside allowedPaths: {}",
|
|
1559
|
+
staged_harness_paths.join(", ")
|
|
1560
|
+
);
|
|
1561
|
+
|
|
1562
|
+
errors.extend(
|
|
1563
|
+
validation_errors
|
|
1564
|
+
.into_iter()
|
|
1565
|
+
.filter(|error| error != &allowed_scope_error),
|
|
1566
|
+
);
|
|
1567
|
+
|
|
1568
|
+
Ok(())
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1528
1571
|
fn validate_push_gate(task_state: &Value, errors: &mut Vec<String>) {
|
|
1529
1572
|
let status = task_state
|
|
1530
1573
|
.get("status")
|
|
@@ -1598,8 +1641,11 @@ fn is_safe_harness_refresh_path(path: &str) -> bool {
|
|
|
1598
1641
|
is_packaged_machine_owned_path(path) || is_repair_support_path(path)
|
|
1599
1642
|
}
|
|
1600
1643
|
|
|
1601
|
-
fn
|
|
1644
|
+
fn is_deterministic_harness_refresh_diff(changed_paths: &[String]) -> bool {
|
|
1602
1645
|
!changed_paths.is_empty()
|
|
1646
|
+
&& changed_paths
|
|
1647
|
+
.iter()
|
|
1648
|
+
.any(|path| is_packaged_machine_owned_path(path) || is_repair_archive_path(path))
|
|
1603
1649
|
&& changed_paths
|
|
1604
1650
|
.iter()
|
|
1605
1651
|
.all(|path| is_safe_harness_refresh_path(path))
|
|
@@ -662,6 +662,57 @@ fn execute_route_refuses_to_create_more_than_max_isolated_worktrees() {
|
|
|
662
662
|
.contains("Too many NAOME task worktrees are present"));
|
|
663
663
|
}
|
|
664
664
|
|
|
665
|
+
#[test]
|
|
666
|
+
fn execute_route_preflights_worktree_before_completed_task_baseline() {
|
|
667
|
+
let repo =
|
|
668
|
+
TestRepo::completed_task_with_unrelated_user_edit("route-completed-worktree-preflight");
|
|
669
|
+
let before_head = repo.git_stdout(&["rev-parse", "HEAD"]);
|
|
670
|
+
let before_status = repo.git_status_short();
|
|
671
|
+
let common_dir = repo.git_stdout(&["rev-parse", "--git-common-dir"]);
|
|
672
|
+
let worktree_root = repo.path().join(common_dir).join("naome").join("worktrees");
|
|
673
|
+
fs::create_dir_all(&worktree_root).unwrap();
|
|
674
|
+
for index in 0..25 {
|
|
675
|
+
fs::create_dir_all(worktree_root.join(format!("stale-{index}"))).unwrap();
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
let error = evaluate_route(
|
|
679
|
+
repo.path(),
|
|
680
|
+
"Add another line to README as a new task.",
|
|
681
|
+
RouteOptions {
|
|
682
|
+
execute: true,
|
|
683
|
+
evaluation: EvaluationOptions::offline(),
|
|
684
|
+
},
|
|
685
|
+
)
|
|
686
|
+
.unwrap_err();
|
|
687
|
+
|
|
688
|
+
assert!(error
|
|
689
|
+
.to_string()
|
|
690
|
+
.contains("Too many NAOME task worktrees are present"));
|
|
691
|
+
assert_eq!(repo.git_stdout(&["rev-parse", "HEAD"]), before_head);
|
|
692
|
+
assert_eq!(repo.git_status_short(), before_status);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
#[test]
|
|
696
|
+
fn execute_route_uses_preflighted_worktree_name_after_completed_task_baseline() {
|
|
697
|
+
let repo = TestRepo::completed_task_with_unrelated_user_edit("route-worktree-name-preflight");
|
|
698
|
+
let before_head = repo.git_stdout(&["rev-parse", "HEAD"]);
|
|
699
|
+
let before_short = &before_head[..12];
|
|
700
|
+
|
|
701
|
+
let route = evaluate_route(
|
|
702
|
+
repo.path(),
|
|
703
|
+
"Add another line to README as a new task.",
|
|
704
|
+
RouteOptions {
|
|
705
|
+
execute: true,
|
|
706
|
+
evaluation: EvaluationOptions::offline(),
|
|
707
|
+
},
|
|
708
|
+
)
|
|
709
|
+
.unwrap();
|
|
710
|
+
|
|
711
|
+
let worktree = route.worktree.expect("route should create a worktree");
|
|
712
|
+
assert!(worktree.branch.contains(before_short));
|
|
713
|
+
assert!(worktree.path.contains(before_short));
|
|
714
|
+
}
|
|
715
|
+
|
|
665
716
|
#[test]
|
|
666
717
|
fn dry_route_plans_harness_refresh_split_before_completed_task_baseline() {
|
|
667
718
|
let repo = TestRepo::completed_task_with_harness_refresh_diff("route-dry-harness-refresh");
|
|
@@ -222,6 +222,146 @@ fn commit_gate_allows_staged_harness_refresh_split_from_completed_task() {
|
|
|
222
222
|
assert!(report.errors.is_empty(), "{:#?}", report.errors);
|
|
223
223
|
}
|
|
224
224
|
|
|
225
|
+
#[test]
|
|
226
|
+
fn commit_gate_allows_staged_harness_refresh_after_completed_task_is_baselined() {
|
|
227
|
+
let repo = TaskFixture::new(complete_task_state(json!({
|
|
228
|
+
"allowedPaths": ["README.md"],
|
|
229
|
+
"proofResults": [successful_proof(json!({ "evidence": ["README.md"] }))]
|
|
230
|
+
})));
|
|
231
|
+
repo.install_healthy_harness();
|
|
232
|
+
repo.write("README.md", "# Completed task result\n");
|
|
233
|
+
repo.init_git();
|
|
234
|
+
repo.write("AGENTS.md", "# Agent Instructions\n\nUpdated by sync.\n");
|
|
235
|
+
repo.write_json(
|
|
236
|
+
".naome/manifest.json",
|
|
237
|
+
json!({
|
|
238
|
+
"name": "naome",
|
|
239
|
+
"harnessVersion": "1.1.1",
|
|
240
|
+
"profile": "standard",
|
|
241
|
+
"machineOwned": MACHINE_OWNED_PATHS,
|
|
242
|
+
"projectOwned": PROJECT_OWNED_PATHS,
|
|
243
|
+
"integrity": {}
|
|
244
|
+
}),
|
|
245
|
+
);
|
|
246
|
+
repo.git(["add", "AGENTS.md", ".naome/manifest.json"]);
|
|
247
|
+
|
|
248
|
+
let report = validate_task_state(
|
|
249
|
+
repo.path(),
|
|
250
|
+
TaskStateOptions {
|
|
251
|
+
mode: TaskStateMode::CommitGate,
|
|
252
|
+
..TaskStateOptions::default()
|
|
253
|
+
},
|
|
254
|
+
)
|
|
255
|
+
.unwrap();
|
|
256
|
+
|
|
257
|
+
assert!(report.errors.is_empty(), "{:#?}", report.errors);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
#[test]
|
|
261
|
+
fn commit_gate_rejects_harness_refresh_when_completed_task_proof_is_missing() {
|
|
262
|
+
let repo = TaskFixture::new(complete_task_state(json!({
|
|
263
|
+
"allowedPaths": ["README.md"],
|
|
264
|
+
"proofResults": []
|
|
265
|
+
})));
|
|
266
|
+
repo.install_healthy_harness();
|
|
267
|
+
repo.write("README.md", "# Completed task result\n");
|
|
268
|
+
repo.init_git();
|
|
269
|
+
repo.write("AGENTS.md", "# Agent Instructions\n\nUpdated by sync.\n");
|
|
270
|
+
repo.git(["add", "AGENTS.md"]);
|
|
271
|
+
|
|
272
|
+
let report = validate_task_state(
|
|
273
|
+
repo.path(),
|
|
274
|
+
TaskStateOptions {
|
|
275
|
+
mode: TaskStateMode::CommitGate,
|
|
276
|
+
..TaskStateOptions::default()
|
|
277
|
+
},
|
|
278
|
+
)
|
|
279
|
+
.unwrap();
|
|
280
|
+
|
|
281
|
+
assert!(
|
|
282
|
+
report
|
|
283
|
+
.errors
|
|
284
|
+
.iter()
|
|
285
|
+
.any(|error| error.contains("activeTask.proofResults missing proof result: diff-check")),
|
|
286
|
+
"{:#?}",
|
|
287
|
+
report.errors
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
#[test]
|
|
292
|
+
fn commit_gate_rejects_harness_refresh_with_pending_upgrade_state() {
|
|
293
|
+
let repo = TaskFixture::new(complete_task_state(json!({
|
|
294
|
+
"allowedPaths": ["README.md"],
|
|
295
|
+
"proofResults": [successful_proof(json!({ "evidence": ["README.md"] }))]
|
|
296
|
+
})));
|
|
297
|
+
repo.install_healthy_harness();
|
|
298
|
+
repo.write("README.md", "# Completed task result\n");
|
|
299
|
+
repo.init_git();
|
|
300
|
+
repo.write("AGENTS.md", "# Agent Instructions\n\nUpdated by sync.\n");
|
|
301
|
+
repo.write_json(
|
|
302
|
+
".naome/upgrade-state.json",
|
|
303
|
+
json!({
|
|
304
|
+
"status": "needs_agent_upgrade",
|
|
305
|
+
"fromVersion": "1.1.0",
|
|
306
|
+
"toVersion": "1.1.1",
|
|
307
|
+
"pending": ["manual-step"],
|
|
308
|
+
"completed": []
|
|
309
|
+
}),
|
|
310
|
+
);
|
|
311
|
+
repo.git(["add", "AGENTS.md", ".naome/upgrade-state.json"]);
|
|
312
|
+
|
|
313
|
+
let report = validate_task_state(
|
|
314
|
+
repo.path(),
|
|
315
|
+
TaskStateOptions {
|
|
316
|
+
mode: TaskStateMode::CommitGate,
|
|
317
|
+
..TaskStateOptions::default()
|
|
318
|
+
},
|
|
319
|
+
)
|
|
320
|
+
.unwrap();
|
|
321
|
+
|
|
322
|
+
assert!(
|
|
323
|
+
report
|
|
324
|
+
.errors
|
|
325
|
+
.iter()
|
|
326
|
+
.any(|error| error.contains("NAOME upgrade is pending")),
|
|
327
|
+
"{:#?}",
|
|
328
|
+
report.errors
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
#[test]
|
|
333
|
+
fn commit_gate_rejects_support_only_harness_refresh_after_completed_task_is_baselined() {
|
|
334
|
+
let repo = TaskFixture::new(complete_task_state(json!({
|
|
335
|
+
"allowedPaths": ["README.md"],
|
|
336
|
+
"proofResults": [successful_proof(json!({ "evidence": ["README.md"] }))]
|
|
337
|
+
})));
|
|
338
|
+
repo.install_healthy_harness();
|
|
339
|
+
repo.write("README.md", "# Completed task result\n");
|
|
340
|
+
repo.init_git();
|
|
341
|
+
repo.write_json(
|
|
342
|
+
".naome/upgrade-state.json",
|
|
343
|
+
json!({
|
|
344
|
+
"status": "complete",
|
|
345
|
+
"fromVersion": null,
|
|
346
|
+
"toVersion": "1.1.1",
|
|
347
|
+
"pending": [],
|
|
348
|
+
"completed": []
|
|
349
|
+
}),
|
|
350
|
+
);
|
|
351
|
+
repo.git(["add", ".naome/upgrade-state.json"]);
|
|
352
|
+
|
|
353
|
+
let report = validate_task_state(
|
|
354
|
+
repo.path(),
|
|
355
|
+
TaskStateOptions {
|
|
356
|
+
mode: TaskStateMode::CommitGate,
|
|
357
|
+
..TaskStateOptions::default()
|
|
358
|
+
},
|
|
359
|
+
)
|
|
360
|
+
.unwrap();
|
|
361
|
+
|
|
362
|
+
assert!(!report.errors.is_empty(), "{:#?}", report.errors);
|
|
363
|
+
}
|
|
364
|
+
|
|
225
365
|
#[test]
|
|
226
366
|
fn commit_gate_ignores_unstaged_user_edits_outside_completed_task_scope() {
|
|
227
367
|
let repo = TaskFixture::new(complete_task_state(json!({
|
|
Binary file
|
package/native/linux-x64/naome
CHANGED
|
Binary file
|
package/package.json
CHANGED