@lamentis/naome 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +2 -2
- package/README.md +16 -2
- package/bin/naome-node.js +118 -3
- package/crates/naome-cli/Cargo.toml +1 -1
- package/crates/naome-core/Cargo.toml +1 -1
- package/crates/naome-core/src/install_plan.rs +5 -2
- package/crates/naome-core/tests/install_plan.rs +5 -4
- 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.0.
|
|
79
|
+
version = "1.0.2"
|
|
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.0.
|
|
87
|
+
version = "1.0.2"
|
|
88
88
|
dependencies = [
|
|
89
89
|
"serde",
|
|
90
90
|
"serde_json",
|
package/README.md
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
|
-
#
|
|
1
|
+
# NAOME
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@lamentis/naome)
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
|
|
6
|
-
NAOME gives coding agents a deterministic repository harness:
|
|
6
|
+
NAOME gives coding agents a deterministic repository harness: project intake, task admission, proof gates, Rust-backed next-step decisions, health checks, and Git guardrails so an agent learns a repo before changing it and proves work before committing.
|
|
7
|
+
|
|
8
|
+
Install:
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
npm install -g @lamentis/naome
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Set up a repository:
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
naome sync
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Then paste the printed first-run prompt into your coding agent. Use `naome status`, `naome next`, and `naome commit` to inspect state, choose the next safe action, and baseline completed work.
|
package/bin/naome-node.js
CHANGED
|
@@ -34,6 +34,7 @@ let machineOwnedPaths = [];
|
|
|
34
34
|
let projectOwnedPaths = [];
|
|
35
35
|
let localOnlyMachineOwnedPaths = [];
|
|
36
36
|
let localOnlyGitIgnoreEntries = [];
|
|
37
|
+
let localOnlyGitExcludeEntries = [];
|
|
37
38
|
let localOnlyGitUntrackPaths = [];
|
|
38
39
|
|
|
39
40
|
const executableMachineOwnedPaths = new Set([
|
|
@@ -363,12 +364,14 @@ function loadInstallPlan() {
|
|
|
363
364
|
assertInstallPlanArray("projectOwned");
|
|
364
365
|
assertInstallPlanArray("localOnlyMachineOwned");
|
|
365
366
|
assertInstallPlanArray("gitignoreEntries");
|
|
367
|
+
assertInstallPlanArray("gitExcludeEntries");
|
|
366
368
|
assertInstallPlanArray("gitUntrackPaths");
|
|
367
369
|
|
|
368
370
|
machineOwnedPaths = installPlan.machineOwned;
|
|
369
371
|
projectOwnedPaths = installPlan.projectOwned;
|
|
370
372
|
localOnlyMachineOwnedPaths = installPlan.localOnlyMachineOwned;
|
|
371
373
|
localOnlyGitIgnoreEntries = installPlan.gitignoreEntries;
|
|
374
|
+
localOnlyGitExcludeEntries = installPlan.gitExcludeEntries;
|
|
372
375
|
localOnlyGitUntrackPaths = installPlan.gitUntrackPaths;
|
|
373
376
|
|
|
374
377
|
return installPlan;
|
|
@@ -820,11 +823,19 @@ function ensureNaomeIgnore() {
|
|
|
820
823
|
}
|
|
821
824
|
|
|
822
825
|
function ensureLocalOnlySourceControlBoundary() {
|
|
823
|
-
|
|
826
|
+
if (!isInsideGitWorkTree()) {
|
|
827
|
+
ensureLocalOnlyGitIgnoreFallback();
|
|
828
|
+
skipped.push("local git exclude");
|
|
829
|
+
skipped.push("local-only git index cleanup");
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
cleanupLegacyLocalOnlyGitIgnore();
|
|
834
|
+
ensureLocalOnlyGitExclude();
|
|
824
835
|
untrackLocalOnlyGitPaths();
|
|
825
836
|
}
|
|
826
837
|
|
|
827
|
-
function
|
|
838
|
+
function ensureLocalOnlyGitIgnoreFallback() {
|
|
828
839
|
const relativePath = ".gitignore";
|
|
829
840
|
const targetPath = join(targetRoot, relativePath);
|
|
830
841
|
|
|
@@ -841,7 +852,7 @@ function ensureLocalOnlyGitIgnore() {
|
|
|
841
852
|
|
|
842
853
|
const content = existsSync(targetPath) ? readFileSync(targetPath, "utf8") : "";
|
|
843
854
|
const existingLines = new Set(content.split(/\r?\n/).map((line) => line.trim()));
|
|
844
|
-
const missingEntries =
|
|
855
|
+
const missingEntries = legacyLocalOnlyGitIgnoreEntries().filter((entry) => !existingLines.has(entry));
|
|
845
856
|
|
|
846
857
|
if (missingEntries.length === 0) {
|
|
847
858
|
skipped.push(relativePath);
|
|
@@ -857,6 +868,110 @@ function ensureLocalOnlyGitIgnore() {
|
|
|
857
868
|
}
|
|
858
869
|
}
|
|
859
870
|
|
|
871
|
+
function cleanupLegacyLocalOnlyGitIgnore() {
|
|
872
|
+
const relativePath = ".gitignore";
|
|
873
|
+
const targetPath = join(targetRoot, relativePath);
|
|
874
|
+
|
|
875
|
+
if (!existsSync(targetPath)) {
|
|
876
|
+
skipped.push(relativePath);
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
if (hasSymlinkInTargetPath(relativePath)) {
|
|
881
|
+
printError("NAOME cannot clean up .gitignore safely.");
|
|
882
|
+
console.error(".gitignore must be a regular file or must not exist.");
|
|
883
|
+
process.exit(1);
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
if (!lstatSync(targetPath).isFile()) {
|
|
887
|
+
printError("NAOME cannot update .gitignore because that path is not a file.");
|
|
888
|
+
process.exit(1);
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
const content = readFileSync(targetPath, "utf8");
|
|
892
|
+
const legacyEntries = new Set(legacyLocalOnlyGitIgnoreEntries());
|
|
893
|
+
const nextContent = cleanBlankLines(content
|
|
894
|
+
.split(/\r?\n/)
|
|
895
|
+
.filter((line) => !legacyEntries.has(line.trim()))
|
|
896
|
+
.join("\n"));
|
|
897
|
+
|
|
898
|
+
if (nextContent === content) {
|
|
899
|
+
skipped.push(relativePath);
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
if (nextContent.trim().length === 0) {
|
|
904
|
+
unlinkSync(targetPath);
|
|
905
|
+
} else {
|
|
906
|
+
writeFileSync(targetPath, nextContent);
|
|
907
|
+
}
|
|
908
|
+
updated.push(relativePath);
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
function ensureLocalOnlyGitExclude() {
|
|
912
|
+
if (!isInsideGitWorkTree()) {
|
|
913
|
+
skipped.push("local git exclude");
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
const gitDirResult = spawnSync("git", ["rev-parse", "--absolute-git-dir"], {
|
|
918
|
+
cwd: targetRoot,
|
|
919
|
+
encoding: "utf8",
|
|
920
|
+
});
|
|
921
|
+
|
|
922
|
+
if (gitDirResult.status !== 0 || !gitDirResult.stdout.trim()) {
|
|
923
|
+
skipped.push("local git exclude");
|
|
924
|
+
unsafeSkipped.push("local git exclude");
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
const excludePath = join(gitDirResult.stdout.trim(), "info", "exclude");
|
|
929
|
+
mkdirSync(dirname(excludePath), { recursive: true });
|
|
930
|
+
|
|
931
|
+
if (existsSync(excludePath) && !lstatSync(excludePath).isFile()) {
|
|
932
|
+
printError("NAOME cannot update local git exclude because that path is not a file.");
|
|
933
|
+
process.exit(1);
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
const content = existsSync(excludePath) ? readFileSync(excludePath, "utf8") : "";
|
|
937
|
+
const existingLines = new Set(content.split(/\r?\n/).map((line) => line.trim()));
|
|
938
|
+
const missingEntries = localOnlyGitExcludeEntries.filter((entry) => !existingLines.has(entry));
|
|
939
|
+
|
|
940
|
+
if (missingEntries.length === 0) {
|
|
941
|
+
skipped.push(".git/info/exclude");
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
const nextContent = `${content.trimEnd()}${content.trimEnd() ? "\n\n" : ""}${missingEntries.join("\n")}\n`;
|
|
946
|
+
writeFileSync(excludePath, nextContent);
|
|
947
|
+
updated.push(".git/info/exclude");
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
function legacyLocalOnlyGitIgnoreEntries() {
|
|
951
|
+
return [
|
|
952
|
+
"# NAOME local machine-owned harness files.",
|
|
953
|
+
".naome/archive/",
|
|
954
|
+
".naome/bin/naome-rust*",
|
|
955
|
+
...localOnlyMachineOwnedPaths,
|
|
956
|
+
...localOnlyGitIgnoreEntries,
|
|
957
|
+
];
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
function cleanBlankLines(content) {
|
|
961
|
+
const lines = content.split(/\r?\n/);
|
|
962
|
+
const cleaned = [];
|
|
963
|
+
|
|
964
|
+
for (const line of lines) {
|
|
965
|
+
if (line.trim() === "" && cleaned.at(-1)?.trim() === "") {
|
|
966
|
+
continue;
|
|
967
|
+
}
|
|
968
|
+
cleaned.push(line);
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
const trimmed = cleaned.join("\n").trimEnd();
|
|
972
|
+
return trimmed ? `${trimmed}\n` : "";
|
|
973
|
+
}
|
|
974
|
+
|
|
860
975
|
function untrackLocalOnlyGitPaths() {
|
|
861
976
|
if (!isInsideGitWorkTree()) {
|
|
862
977
|
skipped.push("local-only git index cleanup");
|
|
@@ -56,16 +56,18 @@ pub struct InstallPlan {
|
|
|
56
56
|
pub project_owned: Vec<&'static str>,
|
|
57
57
|
pub local_only_machine_owned: Vec<&'static str>,
|
|
58
58
|
pub gitignore_entries: Vec<&'static str>,
|
|
59
|
+
pub git_exclude_entries: Vec<&'static str>,
|
|
59
60
|
pub git_untrack_paths: Vec<&'static str>,
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
pub fn install_plan(harness_version: impl Into<String>) -> InstallPlan {
|
|
63
|
-
let
|
|
64
|
+
let gitignore_entries = Vec::new();
|
|
65
|
+
let mut git_exclude_entries = vec![
|
|
64
66
|
"# NAOME local machine-owned harness files.",
|
|
65
67
|
".naome/archive/",
|
|
66
68
|
".naome/bin/naome-rust*",
|
|
67
69
|
];
|
|
68
|
-
|
|
70
|
+
git_exclude_entries.extend_from_slice(LOCAL_ONLY_MACHINE_OWNED_PATHS);
|
|
69
71
|
|
|
70
72
|
let mut git_untrack_paths = LOCAL_ONLY_MACHINE_OWNED_PATHS.to_vec();
|
|
71
73
|
git_untrack_paths.extend_from_slice(LOCAL_NATIVE_BINARY_PATHS);
|
|
@@ -77,6 +79,7 @@ pub fn install_plan(harness_version: impl Into<String>) -> InstallPlan {
|
|
|
77
79
|
project_owned: PROJECT_OWNED_PATHS.to_vec(),
|
|
78
80
|
local_only_machine_owned: LOCAL_ONLY_MACHINE_OWNED_PATHS.to_vec(),
|
|
79
81
|
gitignore_entries,
|
|
82
|
+
git_exclude_entries,
|
|
80
83
|
git_untrack_paths,
|
|
81
84
|
}
|
|
82
85
|
}
|
|
@@ -21,13 +21,14 @@ fn install_plan_marks_machine_docs_and_bins_local_only() {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
#[test]
|
|
24
|
-
fn
|
|
24
|
+
fn install_plan_includes_git_exclude_and_untrack_policy() {
|
|
25
25
|
let plan = install_plan("1.0.0");
|
|
26
26
|
|
|
27
|
-
assert!(plan.gitignore_entries.
|
|
28
|
-
assert!(plan.
|
|
27
|
+
assert!(plan.gitignore_entries.is_empty());
|
|
28
|
+
assert!(plan.git_exclude_entries.contains(&".naome/archive/"));
|
|
29
|
+
assert!(plan.git_exclude_entries.contains(&".naome/bin/naome-rust*"));
|
|
29
30
|
assert!(plan
|
|
30
|
-
.
|
|
31
|
+
.git_exclude_entries
|
|
31
32
|
.contains(&".naome/bin/check-harness-health.js"));
|
|
32
33
|
assert!(plan.git_untrack_paths.contains(&".naome/archive"));
|
|
33
34
|
assert!(plan.git_untrack_paths.contains(&".naome/bin/naome-rust"));
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED