@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 CHANGED
@@ -76,7 +76,7 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
76
76
 
77
77
  [[package]]
78
78
  name = "naome-cli"
79
- version = "1.0.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.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
- # naome
1
+ # NAOME
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@lamentis/naome.svg)](https://www.npmjs.com/package/@lamentis/naome)
4
4
  [![license: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
5
5
 
6
- NAOME gives coding agents a deterministic repository harness: it installs project intake docs, task admission and proof gates, Rust-backed next-step decisions, harness health checks, and Git guardrails so an agent can learn a repo before changing it and prove work before committing; install it with `npm install -g @lamentis/naome`, run `naome sync` in the target repository, then paste the printed first-run prompt into your agent.
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
- ensureLocalOnlyGitIgnore();
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 ensureLocalOnlyGitIgnore() {
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 = localOnlyGitIgnoreEntries.filter((entry) => !existingLines.has(entry));
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");
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "naome-cli"
3
- version = "1.0.0"
3
+ version = "1.0.2"
4
4
  edition.workspace = true
5
5
  license.workspace = true
6
6
  repository.workspace = true
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "naome-core"
3
- version = "1.0.0"
3
+ version = "1.0.2"
4
4
  edition.workspace = true
5
5
  license.workspace = true
6
6
  repository.workspace = true
@@ -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 mut gitignore_entries = vec![
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
- gitignore_entries.extend_from_slice(LOCAL_ONLY_MACHINE_OWNED_PATHS);
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 install_plan_includes_gitignore_and_untrack_policy() {
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.contains(&".naome/archive/"));
28
- assert!(plan.gitignore_entries.contains(&".naome/bin/naome-rust*"));
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
- .gitignore_entries
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lamentis/naome",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Native-first CLI for the NAOME agent harness.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "naome",
3
- "harnessVersion": "1.0.0",
3
+ "harnessVersion": "1.0.2",
4
4
  "profile": "standard",
5
5
  "installedAt": null,
6
6
  "machineOwned": [
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "status": "complete",
3
3
  "fromVersion": null,
4
- "toVersion": "1.0.0",
4
+ "toVersion": "1.0.2",
5
5
  "pending": [],
6
6
  "completed": []
7
7
  }