@lamentis/naome 1.1.2 → 1.2.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.
Files changed (204) hide show
  1. package/Cargo.lock +2 -2
  2. package/Cargo.toml +1 -1
  3. package/LICENSE +180 -21
  4. package/README.md +49 -6
  5. package/bin/naome-node.js +2 -1579
  6. package/bin/naome.js +68 -16
  7. package/crates/naome-cli/Cargo.toml +1 -1
  8. package/crates/naome-cli/src/check_commands.rs +135 -0
  9. package/crates/naome-cli/src/cli_args.rs +5 -0
  10. package/crates/naome-cli/src/dispatcher.rs +37 -0
  11. package/crates/naome-cli/src/install_bridge.rs +83 -0
  12. package/crates/naome-cli/src/main.rs +60 -341
  13. package/crates/naome-cli/src/prompt_commands.rs +68 -0
  14. package/crates/naome-cli/src/quality_commands.rs +229 -0
  15. package/crates/naome-cli/src/simple_commands.rs +53 -0
  16. package/crates/naome-cli/src/workflow_commands.rs +153 -0
  17. package/crates/naome-core/Cargo.toml +1 -1
  18. package/crates/naome-core/src/decision/checks.rs +64 -0
  19. package/crates/naome-core/src/decision/idle.rs +67 -0
  20. package/crates/naome-core/src/decision/json.rs +36 -0
  21. package/crates/naome-core/src/decision/states.rs +165 -0
  22. package/crates/naome-core/src/decision.rs +131 -353
  23. package/crates/naome-core/src/harness_health/integrity.rs +96 -0
  24. package/crates/naome-core/src/harness_health.rs +14 -126
  25. package/crates/naome-core/src/install_plan.rs +5 -0
  26. package/crates/naome-core/src/intent/classifier.rs +171 -0
  27. package/crates/naome-core/src/intent/envelope.rs +108 -0
  28. package/crates/naome-core/src/intent/legacy.rs +138 -0
  29. package/crates/naome-core/src/intent/legacy_response.rs +76 -0
  30. package/crates/naome-core/src/intent/model.rs +71 -0
  31. package/crates/naome-core/src/intent/patterns.rs +170 -0
  32. package/crates/naome-core/src/intent/resolver.rs +162 -0
  33. package/crates/naome-core/src/intent/resolver_active.rs +17 -0
  34. package/crates/naome-core/src/intent/resolver_baseline.rs +55 -0
  35. package/crates/naome-core/src/intent/resolver_catalog.rs +167 -0
  36. package/crates/naome-core/src/intent/resolver_policy.rs +72 -0
  37. package/crates/naome-core/src/intent/resolver_shared.rs +55 -0
  38. package/crates/naome-core/src/intent/risk.rs +40 -0
  39. package/crates/naome-core/src/intent/segment.rs +170 -0
  40. package/crates/naome-core/src/intent.rs +64 -879
  41. package/crates/naome-core/src/journal.rs +9 -20
  42. package/crates/naome-core/src/lib.rs +15 -0
  43. package/crates/naome-core/src/paths.rs +3 -1
  44. package/crates/naome-core/src/quality/adapter_support.rs +89 -0
  45. package/crates/naome-core/src/quality/adapters.rs +131 -0
  46. package/crates/naome-core/src/quality/baseline.rs +75 -0
  47. package/crates/naome-core/src/quality/checks/duplicate_blocks.rs +175 -0
  48. package/crates/naome-core/src/quality/checks/near_duplicates.rs +130 -0
  49. package/crates/naome-core/src/quality/checks.rs +228 -0
  50. package/crates/naome-core/src/quality/cleanup.rs +84 -0
  51. package/crates/naome-core/src/quality/config.rs +102 -0
  52. package/crates/naome-core/src/quality/config_support.rs +24 -0
  53. package/crates/naome-core/src/quality/mod.rs +108 -0
  54. package/crates/naome-core/src/quality/scanner/repo_paths.rs +103 -0
  55. package/crates/naome-core/src/quality/scanner.rs +379 -0
  56. package/crates/naome-core/src/quality/structure/adapters.rs +84 -0
  57. package/crates/naome-core/src/quality/structure/checks/basic.rs +153 -0
  58. package/crates/naome-core/src/quality/structure/checks/directory.rs +144 -0
  59. package/crates/naome-core/src/quality/structure/checks/pairing.rs +63 -0
  60. package/crates/naome-core/src/quality/structure/checks.rs +124 -0
  61. package/crates/naome-core/src/quality/structure/classify/roles.rs +188 -0
  62. package/crates/naome-core/src/quality/structure/classify.rs +94 -0
  63. package/crates/naome-core/src/quality/structure/config.rs +89 -0
  64. package/crates/naome-core/src/quality/structure/defaults.rs +107 -0
  65. package/crates/naome-core/src/quality/structure/mod.rs +77 -0
  66. package/crates/naome-core/src/quality/structure/model.rs +124 -0
  67. package/crates/naome-core/src/quality/types.rs +292 -0
  68. package/crates/naome-core/src/route/builtin_checks.rs +155 -0
  69. package/crates/naome-core/src/route/builtin_context.rs +73 -0
  70. package/crates/naome-core/src/route/builtin_integrity.rs +49 -0
  71. package/crates/naome-core/src/route/builtin_require.rs +40 -0
  72. package/crates/naome-core/src/route/context.rs +180 -0
  73. package/crates/naome-core/src/route/execution.rs +96 -0
  74. package/crates/naome-core/src/route/execution_baselines.rs +146 -0
  75. package/crates/naome-core/src/route/execution_support.rs +57 -0
  76. package/crates/naome-core/src/route/execution_tasks.rs +71 -0
  77. package/crates/naome-core/src/route/git_ops.rs +72 -0
  78. package/crates/naome-core/src/route/quality_gate.rs +73 -0
  79. package/crates/naome-core/src/route/quality_gate_config.rs +126 -0
  80. package/crates/naome-core/src/route/quality_gate_snapshot.rs +69 -0
  81. package/crates/naome-core/src/route/worktree.rs +75 -0
  82. package/crates/naome-core/src/route/worktree_files.rs +32 -0
  83. package/crates/naome-core/src/route/worktree_plan.rs +131 -0
  84. package/crates/naome-core/src/route.rs +44 -1155
  85. package/crates/naome-core/src/task_state/admission.rs +63 -0
  86. package/crates/naome-core/src/task_state/admission_proof.rs +72 -0
  87. package/crates/naome-core/src/task_state/api.rs +130 -0
  88. package/crates/naome-core/src/task_state/commit_gate.rs +138 -0
  89. package/crates/naome-core/src/task_state/compact_proof.rs +160 -0
  90. package/crates/naome-core/src/task_state/completed_refresh.rs +89 -0
  91. package/crates/naome-core/src/task_state/completion.rs +72 -0
  92. package/crates/naome-core/src/task_state/deleted_paths.rs +47 -0
  93. package/crates/naome-core/src/task_state/diff.rs +95 -0
  94. package/crates/naome-core/src/task_state/evidence.rs +154 -0
  95. package/crates/naome-core/src/task_state/git_io.rs +86 -0
  96. package/crates/naome-core/src/task_state/git_parse.rs +86 -0
  97. package/crates/naome-core/src/task_state/git_refs.rs +37 -0
  98. package/crates/naome-core/src/task_state/human_review_state.rs +31 -0
  99. package/crates/naome-core/src/task_state/mod.rs +38 -0
  100. package/crates/naome-core/src/task_state/process_guard.rs +40 -0
  101. package/crates/naome-core/src/task_state/progress.rs +123 -0
  102. package/crates/naome-core/src/task_state/proof.rs +139 -0
  103. package/crates/naome-core/src/task_state/proof_entry.rs +66 -0
  104. package/crates/naome-core/src/task_state/proof_model.rs +70 -0
  105. package/crates/naome-core/src/task_state/proof_sources.rs +76 -0
  106. package/crates/naome-core/src/task_state/push_gate.rs +49 -0
  107. package/crates/naome-core/src/task_state/reconcile.rs +7 -0
  108. package/crates/naome-core/src/task_state/repair.rs +168 -0
  109. package/crates/naome-core/src/task_state/shape.rs +117 -0
  110. package/crates/naome-core/src/task_state/task_diff_api.rs +170 -0
  111. package/crates/naome-core/src/task_state/task_records.rs +131 -0
  112. package/crates/naome-core/src/task_state/task_references.rs +126 -0
  113. package/crates/naome-core/src/task_state/types.rs +87 -0
  114. package/crates/naome-core/src/task_state/util.rs +137 -0
  115. package/crates/naome-core/src/verification/render.rs +122 -0
  116. package/crates/naome-core/src/verification.rs +177 -58
  117. package/crates/naome-core/src/verification_contract.rs +49 -21
  118. package/crates/naome-core/src/workflow/integrity.rs +123 -0
  119. package/crates/naome-core/src/workflow/integrity_normalize.rs +7 -0
  120. package/crates/naome-core/src/workflow/integrity_support.rs +110 -0
  121. package/crates/naome-core/src/workflow/mod.rs +18 -0
  122. package/crates/naome-core/src/workflow/mutation.rs +68 -0
  123. package/crates/naome-core/src/workflow/output.rs +111 -0
  124. package/crates/naome-core/src/workflow/phase_inference.rs +73 -0
  125. package/crates/naome-core/src/workflow/phases.rs +169 -0
  126. package/crates/naome-core/src/workflow/policy.rs +156 -0
  127. package/crates/naome-core/src/workflow/processes.rs +91 -0
  128. package/crates/naome-core/src/workflow/types.rs +42 -0
  129. package/crates/naome-core/tests/decision.rs +24 -118
  130. package/crates/naome-core/tests/harness_health.rs +5 -0
  131. package/crates/naome-core/tests/intent.rs +97 -792
  132. package/crates/naome-core/tests/intent_support/mod.rs +133 -0
  133. package/crates/naome-core/tests/intent_v2.rs +90 -0
  134. package/crates/naome-core/tests/quality.rs +319 -0
  135. package/crates/naome-core/tests/quality_structure.rs +116 -0
  136. package/crates/naome-core/tests/quality_structure_adapters.rs +98 -0
  137. package/crates/naome-core/tests/quality_structure_policy.rs +125 -0
  138. package/crates/naome-core/tests/quality_structure_support/mod.rs +249 -0
  139. package/crates/naome-core/tests/repo_support/mod.rs +16 -0
  140. package/crates/naome-core/tests/repo_support/repo.rs +113 -0
  141. package/crates/naome-core/tests/repo_support/repo_factories.rs +99 -0
  142. package/crates/naome-core/tests/repo_support/repo_helpers.rs +123 -0
  143. package/crates/naome-core/tests/repo_support/routes.rs +81 -0
  144. package/crates/naome-core/tests/repo_support/verification.rs +168 -0
  145. package/crates/naome-core/tests/repo_support/verification_values.rs +135 -0
  146. package/crates/naome-core/tests/route.rs +1 -1476
  147. package/crates/naome-core/tests/route_baseline.rs +86 -0
  148. package/crates/naome-core/tests/route_completion.rs +141 -0
  149. package/crates/naome-core/tests/route_harness_refresh.rs +135 -0
  150. package/crates/naome-core/tests/route_user_diff.rs +198 -0
  151. package/crates/naome-core/tests/route_worktree.rs +54 -0
  152. package/crates/naome-core/tests/task_state.rs +60 -429
  153. package/crates/naome-core/tests/task_state_compact.rs +110 -0
  154. package/crates/naome-core/tests/task_state_compact_support/mod.rs +5 -0
  155. package/crates/naome-core/tests/task_state_compact_support/repo.rs +130 -0
  156. package/crates/naome-core/tests/task_state_compact_support/states.rs +151 -0
  157. package/crates/naome-core/tests/task_state_support/mod.rs +163 -0
  158. package/crates/naome-core/tests/task_state_support/states.rs +84 -0
  159. package/crates/naome-core/tests/verification.rs +4 -45
  160. package/crates/naome-core/tests/verification_contract.rs +22 -78
  161. package/crates/naome-core/tests/workflow_integrity.rs +85 -0
  162. package/crates/naome-core/tests/workflow_policy.rs +139 -0
  163. package/crates/naome-core/tests/workflow_support/mod.rs +194 -0
  164. package/installer/agents.js +90 -0
  165. package/installer/context.js +67 -0
  166. package/installer/filesystem.js +166 -0
  167. package/installer/flows.js +84 -0
  168. package/installer/git-boundary.js +170 -0
  169. package/installer/git-hook-content.js +36 -0
  170. package/installer/git-hooks.js +134 -0
  171. package/installer/git-local.js +2 -0
  172. package/installer/git-shared.js +35 -0
  173. package/installer/harness-file-ops.js +140 -0
  174. package/installer/harness-files.js +56 -0
  175. package/installer/harness-verification.js +123 -0
  176. package/installer/install-plan.js +66 -0
  177. package/installer/main.js +25 -0
  178. package/installer/manifest-state.js +167 -0
  179. package/installer/native-build.js +24 -0
  180. package/installer/native-format.js +6 -0
  181. package/installer/native.js +162 -0
  182. package/installer/output.js +131 -0
  183. package/installer/version.js +32 -0
  184. package/native/darwin-arm64/naome +0 -0
  185. package/native/linux-x64/naome +0 -0
  186. package/package.json +3 -2
  187. package/templates/naome-root/.naome/bin/check-harness-health.js +66 -85
  188. package/templates/naome-root/.naome/bin/check-task-state.js +9 -10
  189. package/templates/naome-root/.naome/bin/naome.js +51 -76
  190. package/templates/naome-root/.naome/manifest.json +22 -18
  191. package/templates/naome-root/.naome/repository-quality-baseline.json +5 -0
  192. package/templates/naome-root/.naome/repository-quality.json +24 -0
  193. package/templates/naome-root/.naome/repository-structure.json +90 -0
  194. package/templates/naome-root/.naome/task-contract.schema.json +93 -11
  195. package/templates/naome-root/.naome/upgrade-state.json +1 -1
  196. package/templates/naome-root/.naome/verification.json +38 -0
  197. package/templates/naome-root/AGENTS.md +3 -0
  198. package/templates/naome-root/docs/naome/agent-workflow.md +25 -12
  199. package/templates/naome-root/docs/naome/execution.md +25 -21
  200. package/templates/naome-root/docs/naome/index.md +5 -3
  201. package/templates/naome-root/docs/naome/repository-quality.md +46 -0
  202. package/templates/naome-root/docs/naome/repository-structure.md +51 -0
  203. package/templates/naome-root/docs/naome/testing.md +13 -0
  204. package/crates/naome-core/src/task_state.rs +0 -2210
@@ -0,0 +1,162 @@
1
+ import { createHash } from "node:crypto";
2
+ import {
3
+ chmodSync,
4
+ copyFileSync,
5
+ existsSync,
6
+ lstatSync,
7
+ mkdirSync,
8
+ readFileSync,
9
+ writeFileSync,
10
+ } from "node:fs";
11
+ import { dirname, join, resolve } from "node:path";
12
+
13
+ import { hasSymlinkInTargetPath } from "./filesystem.js";
14
+ import { buildNativeDecisionBinary } from "./native-build.js";
15
+ import { formatExpectedIntegrityBlock } from "./native-format.js";
16
+ import { printError } from "./output.js";
17
+
18
+ export function installNativeDecisionBinary(ctx) {
19
+ const targetPath = join(ctx.targetRoot, ctx.nativeBinaryRelativePath);
20
+
21
+ if (hasSymlinkInTargetPath(ctx, ctx.nativeBinaryRelativePath)) {
22
+ ctx.skipped.push(ctx.nativeBinaryRelativePath);
23
+ ctx.unsafeSkipped.push(ctx.nativeBinaryRelativePath);
24
+ return;
25
+ }
26
+
27
+ const sourcePath = findNativeDecisionBinary(ctx);
28
+ if (!sourcePath) {
29
+ printError(ctx, "NAOME native decision binary is unavailable.");
30
+ console.error("Install Cargo or provide NAOME_NATIVE_BIN with a built naome binary, then rerun naome sync.");
31
+ process.exit(1);
32
+ }
33
+
34
+ if (usesSourceNativeFallback(ctx)) {
35
+ patchNaomeCommandNativeIntegrity(ctx, "sha256:generated");
36
+ ctx.skipped.push(ctx.nativeBinaryRelativePath);
37
+ return;
38
+ }
39
+
40
+ mkdirSync(dirname(targetPath), { recursive: true });
41
+ const sourceHash = sha256(readFileSync(sourcePath));
42
+ const targetHash =
43
+ existsSync(targetPath) && lstatSync(targetPath).isFile()
44
+ ? sha256(readFileSync(targetPath))
45
+ : null;
46
+
47
+ if (sourceHash !== targetHash) {
48
+ copyFileSync(sourcePath, targetPath);
49
+ ctx.updated.push(ctx.nativeBinaryRelativePath);
50
+ } else {
51
+ ctx.skipped.push(ctx.nativeBinaryRelativePath);
52
+ }
53
+
54
+ chmodSync(targetPath, 0o755);
55
+ patchNaomeCommandNativeIntegrity(ctx, `sha256:${sourceHash}`);
56
+ }
57
+
58
+ export function findNativeDecisionBinary(ctx) {
59
+ const candidates = [];
60
+
61
+ if (process.env.NAOME_NATIVE_BIN) {
62
+ candidates.push(resolve(ctx.targetRoot, process.env.NAOME_NATIVE_BIN));
63
+ }
64
+
65
+ candidates.push(join(ctx.packageRoot, "native", `${process.platform}-${process.arch}`, ctx.nativeBinaryName));
66
+ candidates.push(join(ctx.packageRoot, "target", "release", ctx.nativeBinaryName));
67
+
68
+ for (const candidate of candidates) {
69
+ if (existsSync(candidate) && lstatSync(candidate).isFile()) {
70
+ return candidate;
71
+ }
72
+ }
73
+
74
+ return buildNativeDecisionBinary(ctx);
75
+ }
76
+
77
+ export function patchInstalledMachineOwnedIntegrity(ctx) {
78
+ const integrityBlock = formatExpectedIntegrityBlock(templateIntegrity(ctx));
79
+
80
+ for (const relativePath of [ctx.healthCheckerRelativePath, ctx.taskStateCheckerRelativePath]) {
81
+ const targetPath = join(ctx.targetRoot, relativePath);
82
+ if (!existsSync(targetPath) || hasSymlinkInTargetPath(ctx, relativePath)) {
83
+ continue;
84
+ }
85
+
86
+ const content = readFileSync(targetPath, "utf8");
87
+ const nextContent = content.replace(ctx.integrityBlockPattern, integrityBlock);
88
+ if (nextContent !== content) {
89
+ writeFileSync(targetPath, nextContent);
90
+ ctx.updated.push(relativePath);
91
+ }
92
+ }
93
+ }
94
+
95
+ export function usesSourceNativeFallback(ctx) {
96
+ return existsSync(join(ctx.targetRoot, "packages", "naome", "Cargo.toml"))
97
+ && existsSync(join(ctx.targetRoot, "packages", "naome", "crates", "naome-cli", "src", "main.rs"));
98
+ }
99
+
100
+ export function installedNativeBinaryHash(ctx) {
101
+ const targetPath = join(ctx.targetRoot, ctx.nativeBinaryRelativePath);
102
+ if (
103
+ !existsSync(targetPath) ||
104
+ hasSymlinkInTargetPath(ctx, ctx.nativeBinaryRelativePath) ||
105
+ !lstatSync(targetPath).isFile()
106
+ ) {
107
+ return null;
108
+ }
109
+
110
+ return sha256(readFileSync(targetPath));
111
+ }
112
+
113
+ export function templateIntegrity(ctx) {
114
+ const integrity = {};
115
+
116
+ for (const relativePath of ctx.machineOwnedPaths) {
117
+ const sourcePath = join(ctx.templateRoot, relativePath);
118
+ integrity[relativePath] = `sha256:${machineFileHash(ctx, relativePath, readFileSync(sourcePath))}`;
119
+ }
120
+
121
+ return integrity;
122
+ }
123
+
124
+ export function sha256(content) {
125
+ return createHash("sha256").update(content).digest("hex");
126
+ }
127
+
128
+ export function machineFileHash(ctx, relativePath, content) {
129
+ let normalized = content;
130
+
131
+ if (hasGeneratedIntegrity(ctx, relativePath)) {
132
+ normalized = normalized.toString("utf8").replace(ctx.integrityBlockPattern, ctx.normalizedIntegrityBlock);
133
+ }
134
+
135
+ if (relativePath === ctx.naomeCommandRelativePath) {
136
+ normalized = normalized.toString("utf8").replace(ctx.nativeIntegrityPattern, ctx.normalizedNativeIntegrity);
137
+ }
138
+
139
+ return sha256(normalized);
140
+ }
141
+
142
+ export function hasGeneratedIntegrity(ctx, relativePath) {
143
+ return relativePath === ctx.healthCheckerRelativePath || relativePath === ctx.taskStateCheckerRelativePath;
144
+ }
145
+
146
+ function patchNaomeCommandNativeIntegrity(ctx, expectedIntegrity) {
147
+ const commandPath = join(ctx.targetRoot, ctx.naomeCommandRelativePath);
148
+ if (!existsSync(commandPath) || hasSymlinkInTargetPath(ctx, ctx.naomeCommandRelativePath)) {
149
+ return;
150
+ }
151
+
152
+ const content = readFileSync(commandPath, "utf8");
153
+ const nextContent = content.replace(
154
+ ctx.nativeIntegrityPattern,
155
+ `const expectedNativeBinaryIntegrity = "${expectedIntegrity}";\n`,
156
+ );
157
+
158
+ if (nextContent !== content) {
159
+ writeFileSync(commandPath, nextContent);
160
+ ctx.updated.push(ctx.naomeCommandRelativePath);
161
+ }
162
+ }
@@ -0,0 +1,131 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+
4
+ export function printHeader(ctx) {
5
+ console.log("");
6
+ console.log(`${ctx.color.bold("NAOME")} ${ctx.color.dim(`v${ctx.packageVersion}`)}`);
7
+ console.log(ctx.color.dim("AI coding-agent harness installer"));
8
+ console.log("");
9
+ console.log(`${ctx.color.dim("target ")} ${ctx.targetRoot}`);
10
+ }
11
+
12
+ export function printSection(ctx, title) {
13
+ console.log("");
14
+ console.log(ctx.color.bold(title));
15
+ }
16
+
17
+ export function printList(ctx, items, marker) {
18
+ for (const item of uniqueStrings(items)) {
19
+ console.log(`${ctx.color.dim(marker)} ${item}`);
20
+ }
21
+ }
22
+
23
+ export function uniqueStrings(items) {
24
+ return Array.from(new Set(items));
25
+ }
26
+
27
+ export function printError(ctx, message) {
28
+ console.error("");
29
+ console.error(`${ctx.color.red("x")} ${message}`);
30
+ }
31
+
32
+ export function printCancelled(ctx, message) {
33
+ console.log("");
34
+ console.log(`${ctx.color.yellow("-")} ${message}`);
35
+ }
36
+
37
+ export function printCommandFailure(ctx, message, result) {
38
+ printError(ctx, message);
39
+ if (result.stdout.trim()) {
40
+ console.error(result.stdout.trim());
41
+ }
42
+ if (result.stderr.trim()) {
43
+ console.error(result.stderr.trim());
44
+ }
45
+ process.exit(1);
46
+ }
47
+
48
+ export function printSummary(ctx, existingInstall) {
49
+ console.log("");
50
+ console.log(`${ctx.color.green("+")} ${ctx.summaryTitle}`);
51
+
52
+ const detailedOutput = shouldPrintDetailedSummary(ctx, existingInstall);
53
+ if (!detailedOutput) {
54
+ printCompactSummary(ctx);
55
+ }
56
+
57
+ printDetailedSummary(ctx, detailedOutput);
58
+ if (ctx.unsafeSkipped.length > 0) {
59
+ printSection(ctx, "Skipped unsafe symlinked paths");
60
+ printList(ctx, ctx.unsafeSkipped, "!");
61
+ }
62
+
63
+ if (isRepositoryInitialized(ctx)) {
64
+ console.log("");
65
+ return;
66
+ }
67
+
68
+ printSection(ctx, "Next step");
69
+ console.log("Copy this into your coding agent:");
70
+ console.log("");
71
+ console.log(ctx.color.dim("```"));
72
+ console.log(ctx.nextStepPrompt);
73
+ console.log(ctx.color.dim("```"));
74
+ console.log("");
75
+ }
76
+
77
+ function printDetailedSummary(ctx, detailedOutput) {
78
+ if (detailedOutput && ctx.installed.length > 0) {
79
+ const items = uniqueStrings(ctx.installed);
80
+ printSection(ctx, `Installed ${items.length} ${items.length === 1 ? "item" : "items"}`);
81
+ printList(ctx, ctx.installed, "+");
82
+ }
83
+
84
+ if (detailedOutput && ctx.updated.length > 0) {
85
+ const items = uniqueStrings(ctx.updated);
86
+ printSection(ctx, `Updated ${items.length} ${items.length === 1 ? "item" : "items"}`);
87
+ printList(ctx, ctx.updated, "~");
88
+ }
89
+
90
+ if (detailedOutput && ctx.archived.length > 0) {
91
+ printSection(ctx, "Archived");
92
+ for (const entry of ctx.archived) {
93
+ console.log(`${ctx.color.dim(">")} ${entry.from} -> ${entry.to}`);
94
+ }
95
+ }
96
+
97
+ if (detailedOutput && ctx.skipped.length > 0) {
98
+ const items = uniqueStrings(ctx.skipped);
99
+ printSection(ctx, `Skipped ${items.length} existing ${items.length === 1 ? "path" : "paths"}`);
100
+ printList(ctx, ctx.skipped, "-");
101
+ }
102
+ }
103
+
104
+ function shouldPrintDetailedSummary(ctx, existingInstall) {
105
+ return ctx.verboseOutput || !existingInstall;
106
+ }
107
+
108
+ function printCompactSummary(ctx) {
109
+ const installedCount = uniqueStrings(ctx.installed).length;
110
+ const updatedCount = uniqueStrings(ctx.updated).length;
111
+ const archivedCount = ctx.archived.length;
112
+
113
+ if (installedCount > 0) {
114
+ console.log(`${ctx.color.dim("installed")} ${installedCount}`);
115
+ }
116
+ if (updatedCount > 0) {
117
+ console.log(`${ctx.color.dim("updated")} ${updatedCount}`);
118
+ }
119
+ if (archivedCount > 0) {
120
+ console.log(`${ctx.color.dim("archived")} ${archivedCount}`);
121
+ }
122
+ }
123
+
124
+ function isRepositoryInitialized(ctx) {
125
+ try {
126
+ const initState = JSON.parse(readFileSync(join(ctx.targetRoot, ".naome", "init-state.json"), "utf8"));
127
+ return initState.initialized === true;
128
+ } catch {
129
+ return false;
130
+ }
131
+ }
@@ -0,0 +1,32 @@
1
+ import { printError } from "./output.js";
2
+
3
+ export function compareVersions(ctx, left, right) {
4
+ const leftParts = parseVersion(ctx, left);
5
+ const rightParts = parseVersion(ctx, right);
6
+
7
+ for (let index = 0; index < 3; index += 1) {
8
+ if (leftParts[index] > rightParts[index]) {
9
+ return 1;
10
+ }
11
+
12
+ if (leftParts[index] < rightParts[index]) {
13
+ return -1;
14
+ }
15
+ }
16
+
17
+ return 0;
18
+ }
19
+
20
+ export function isVersion(version) {
21
+ return typeof version === "string" && /^\d+\.\d+\.\d+$/.test(version);
22
+ }
23
+
24
+ function parseVersion(ctx, version) {
25
+ const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(version);
26
+ if (!match) {
27
+ printError(ctx, `Invalid NAOME version: ${version}`);
28
+ process.exit(1);
29
+ }
30
+
31
+ return match.slice(1).map((part) => Number.parseInt(part, 10));
32
+ }
Binary file
Binary file
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@lamentis/naome",
3
- "version": "1.1.2",
3
+ "version": "1.2.1",
4
4
  "description": "Native-first CLI for the NAOME agent harness.",
5
- "license": "MIT",
5
+ "license": "Apache-2.0",
6
6
  "type": "module",
7
7
  "keywords": [
8
8
  "agent",
@@ -31,6 +31,7 @@
31
31
  "Cargo.lock",
32
32
  "Cargo.toml",
33
33
  "crates",
34
+ "installer",
34
35
  "native",
35
36
  "templates",
36
37
  "README.md"
@@ -1,158 +1,141 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { existsSync, readFileSync } = require("node:fs");
4
- const { createHash } = require("node:crypto");
5
- const { dirname, join, resolve } = require("node:path");
6
- const { spawnSync } = require("node:child_process");
3
+ const fs = require("node:fs");
4
+ const crypto = require("node:crypto");
5
+ const childProcess = require("node:child_process");
6
+ const path = require("node:path");
7
7
 
8
- const nativeBinaryRelativePath = process.platform === "win32" ? ".naome/bin/naome-rust.exe" : ".naome/bin/naome-rust";
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
10
 
11
11
  const expectedMachineOwnedIntegrity = Object.freeze({
12
- "AGENTS.md": "sha256:84ce882fa6798a144c8c74673d4304fc6bf235b1cc417f7649eea9f7461775de",
13
- ".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
14
- ".naome/bin/naome.js": "sha256:7894690ad47700a9a5e7ecb5a94ba42c1a12e2637d2c9f41f0023b1bd8bd22b6",
12
+ ".naome/bin/check-harness-health.js": "sha256:dc4de52b79c69600b9ba47b924e2c2b8de61a2cbfab6d1ccc0f1924d963db657",
15
13
  ".naome/bin/check-task-state.js": "sha256:43c02868072d0d13499aefba2e9a5ec9517d59539fd19ff0f11e3e4623a51b44",
16
- ".naome/bin/check-harness-health.js": "sha256:dce2a380022dd63d86bd762869debafbc635ab3d7e8fae985e2d429d8ee437ad",
17
- ".naome/task-contract.schema.json": "sha256:c806416d4944eaed6dc48b3760fd0dd5b9b5a7c9ab895697fe36b54c41c1332f",
18
- "docs/naome/index.md": "sha256:d04691b25ed377c2a3aa2c56965d0db276539aeadcfdd2a2ec1be7ff7706dd6f",
14
+ ".naome/bin/naome.js": "sha256:87eabd690bf55f0b0195446db46fa7c19bfa17395d31c2f34a9ef9339d2229e2",
15
+ ".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
16
+ ".naome/task-contract.schema.json": "sha256:1b3b62350328d0d6d660e36d1d1baaa2b88718530db774f9ab2a9e2fcba369c8",
17
+ "AGENTS.md": "sha256:9192ea81f90bb19f8043513c49b5da9e9598ee694da8356f345e7ccbca0e28df",
18
+ "docs/naome/agent-workflow.md": "sha256:802eb34cf268fc9c5e7aefc28192efef4bf60302d30b3f78e5a61b876ce8a098",
19
+ "docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
19
20
  "docs/naome/first-run.md": "sha256:a1dd0bd17ec9d71955a473cd2c4a615538e89a7d81e8f4e1015a50ab9efe3558",
20
- "docs/naome/agent-workflow.md": "sha256:43ba8a6814068e1b932b12a392de70b39841dc82df0acdaac459d6714c501b9d",
21
- "docs/naome/execution.md": "sha256:ad66611b2878d1ba8fe05ddc4cfe9de7fd41de172a0de8295c36227a2700631a",
22
- "docs/naome/upgrade.md": "sha256:2c60f0441bbd98bd528d109b30a7ded4b0ad55d61ffb9f52edac9e93b7999cb1",
23
- ".naome/bin/naome-rust": "sha256:cc754ae59477577dfc0130cc21c286beaf3f19e2852278bb8f1e8724277eb44b"
21
+ "docs/naome/index.md": "sha256:a674102cc801702dc77102afb59be0f5ab189dc638caf0bef358b9d6087d0742",
22
+ "docs/naome/upgrade.md": "sha256:2c60f0441bbd98bd528d109b30a7ded4b0ad55d61ffb9f52edac9e93b7999cb1"
24
23
  });
25
24
 
26
- function main() {
27
- const root = findHarnessRoot(process.cwd()) || resolve(__dirname, "..", "..");
28
- const nativeBinary = resolveNativeDecisionBinary(root);
25
+ const root = findRoot(process.cwd()) || path.resolve(__dirname, "..", "..");
26
+ const binary = selectBinary(root);
27
+ const result = childProcess.spawnSync(binary, ["check-harness-health", "--root", root], {
28
+ cwd: root,
29
+ encoding: "utf8",
30
+ env: {
31
+ ...process.env,
32
+ NAOME_EXPECTED_INTEGRITY_JSON: JSON.stringify(expectedMachineOwnedIntegrity)
33
+ },
34
+ stdio: "inherit"
35
+ });
29
36
 
30
- const result = spawnSync(nativeBinary, ["check-harness-health", "--root", root], {
31
- cwd: root,
32
- encoding: "utf8",
33
- env: {
34
- ...process.env,
35
- NAOME_EXPECTED_INTEGRITY_JSON: JSON.stringify(expectedMachineOwnedIntegrity)
36
- },
37
- stdio: "inherit"
38
- });
37
+ process.exit(result.status === null ? 1 : result.status);
39
38
 
40
- process.exit(result.status === null ? 1 : result.status);
41
- }
42
-
43
- function resolveNativeDecisionBinary(root) {
44
- const expectedIntegrity = expectedNativeIntegrity(root);
39
+ function selectBinary(rootDir) {
40
+ const wantedHash = manifestNativeHash(rootDir);
45
41
  const candidates = [
46
42
  process.env.NAOME_NATIVE_BIN,
47
- join(root, nativeBinaryRelativePath),
48
- join(root, "packages", "naome", "target", "release", nativeBinaryName),
49
- join(root, "packages", "naome", "target", "debug", nativeBinaryName)
43
+ path.join(rootDir, nativeBinaryPath),
44
+ path.join(rootDir, "packages", "naome", "target", "release", nativeBinaryName),
45
+ path.join(rootDir, "packages", "naome", "target", "debug", nativeBinaryName)
50
46
  ].filter(Boolean);
51
47
 
52
48
  for (const candidate of candidates) {
53
- if (isUsableNativeBinary(candidate, root, expectedIntegrity)) {
49
+ if (canRun(candidate, rootDir, wantedHash)) {
54
50
  return candidate;
55
51
  }
56
52
  }
57
53
 
58
- if (expectedIntegrity) {
59
- fail(`No runnable NAOME native harness health binary matched ${expectedIntegrity}. Run naome sync again.`);
54
+ if (wantedHash) {
55
+ stop(`No runnable NAOME native harness health binary matched ${wantedHash}. Run naome sync again.`);
60
56
  }
61
57
 
62
- const built = buildSourceNativeBinary(root);
63
- if (built && isUsableNativeBinary(built, root, null)) {
58
+ const built = buildFromSource(rootDir);
59
+ if (built && canRun(built, rootDir, null)) {
64
60
  return built;
65
61
  }
66
62
 
67
- fail("NAOME native harness health binary is missing or incompatible. Run naome sync again.");
63
+ stop("NAOME native harness health binary is missing or incompatible. Run naome sync again.");
68
64
  }
69
65
 
70
- function expectedNativeIntegrity(root) {
71
- if (isIntegrityHash(process.env.NAOME_EXPECTED_NATIVE_INTEGRITY)) {
66
+ function manifestNativeHash(rootDir) {
67
+ if (isSha(process.env.NAOME_EXPECTED_NATIVE_INTEGRITY)) {
72
68
  return process.env.NAOME_EXPECTED_NATIVE_INTEGRITY;
73
69
  }
74
70
 
75
- const manifestPath = join(root, ".naome", "manifest.json");
76
- if (!existsSync(manifestPath)) {
77
- return null;
78
- }
79
-
80
- let manifest;
81
71
  try {
82
- manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
72
+ const manifest = JSON.parse(fs.readFileSync(path.join(rootDir, ".naome", "manifest.json"), "utf8"));
73
+ return isSha(manifest.integrity?.[nativeBinaryPath]) ? manifest.integrity[nativeBinaryPath] : null;
83
74
  } catch {
84
75
  return null;
85
76
  }
86
-
87
- const expected = manifest.integrity?.[nativeBinaryRelativePath];
88
- if (!isIntegrityHash(expected)) {
89
- return null;
90
- }
91
-
92
- return expected;
93
77
  }
94
78
 
95
- function isUsableNativeBinary(candidate, root, expectedIntegrity) {
96
- if (!candidate || !existsSync(candidate)) {
79
+ function canRun(candidate, rootDir, wantedHash) {
80
+ if (!candidate || !fs.existsSync(candidate)) {
97
81
  return false;
98
82
  }
99
83
 
100
- if (expectedIntegrity) {
101
- const actual = `sha256:${createHash("sha256").update(readFileSync(candidate)).digest("hex")}`;
102
- if (actual !== expectedIntegrity) {
103
- return false;
104
- }
84
+ if (wantedHash && fileSha(candidate) !== wantedHash) {
85
+ return false;
105
86
  }
106
87
 
107
- const probe = spawnSync(candidate, [], {
108
- cwd: root,
88
+ const probe = childProcess.spawnSync(candidate, [], {
89
+ cwd: rootDir,
109
90
  encoding: "utf8",
110
91
  stdio: "ignore"
111
92
  });
112
93
  return !probe.error && probe.status !== null;
113
94
  }
114
95
 
115
- function buildSourceNativeBinary(root) {
116
- const manifestPath = join(root, "packages", "naome", "Cargo.toml");
117
- if (!existsSync(manifestPath)) {
96
+ function buildFromSource(rootDir) {
97
+ const manifest = path.join(rootDir, "packages", "naome", "Cargo.toml");
98
+ if (!fs.existsSync(manifest)) {
118
99
  return null;
119
100
  }
120
101
 
121
- const result = spawnSync("cargo", ["build", "--release", "--manifest-path", manifestPath, "-p", "naome-cli"], {
122
- cwd: root,
102
+ const build = childProcess.spawnSync("cargo", ["build", "--release", "--manifest-path", manifest, "-p", "naome-cli"], {
103
+ cwd: rootDir,
123
104
  encoding: "utf8",
124
105
  stdio: "ignore"
125
106
  });
126
- if (result.status !== 0) {
107
+ if (build.status !== 0) {
127
108
  return null;
128
109
  }
129
110
 
130
- const builtPath = join(root, "packages", "naome", "target", "release", nativeBinaryName);
131
- return existsSync(builtPath) ? builtPath : null;
111
+ const binaryPath = path.join(rootDir, "packages", "naome", "target", "release", nativeBinaryName);
112
+ return fs.existsSync(binaryPath) ? binaryPath : null;
132
113
  }
133
114
 
134
- function findHarnessRoot(startPath) {
135
- let current = resolve(startPath);
136
-
137
- while (true) {
138
- if (existsSync(join(current, ".naome", "manifest.json"))) {
115
+ function findRoot(startDir) {
116
+ for (let current = path.resolve(startDir); ;) {
117
+ if (fs.existsSync(path.join(current, ".naome", "manifest.json"))) {
139
118
  return current;
140
119
  }
141
120
 
142
- const parent = dirname(current);
121
+ const parent = path.dirname(current);
143
122
  if (parent === current) {
144
123
  return null;
145
124
  }
146
-
147
125
  current = parent;
148
126
  }
149
127
  }
150
128
 
151
- function isIntegrityHash(value) {
129
+ function isSha(value) {
152
130
  return typeof value === "string" && /^sha256:[a-f0-9]{64}$/.test(value);
153
131
  }
154
132
 
155
- function fail(message) {
133
+ function fileSha(filePath) {
134
+ const digest = crypto.createHash("sha256").update(fs.readFileSync(filePath)).digest("hex");
135
+ return `sha256:${digest}`;
136
+ }
137
+
138
+ function stop(message) {
156
139
  console.error("NAOME harness health check failed.");
157
140
  console.error(`- ${message}`);
158
141
  console.error("");
@@ -160,5 +143,3 @@ function fail(message) {
160
143
  console.error("Run naome sync to repair machine-owned files after review.");
161
144
  process.exit(1);
162
145
  }
163
-
164
- main();
@@ -9,18 +9,17 @@ const nativeBinaryRelativePath = process.platform === "win32" ? ".naome/bin/naom
9
9
  const nativeBinaryName = process.platform === "win32" ? "naome.exe" : "naome";
10
10
 
11
11
  const expectedMachineOwnedIntegrity = Object.freeze({
12
- "AGENTS.md": "sha256:84ce882fa6798a144c8c74673d4304fc6bf235b1cc417f7649eea9f7461775de",
13
- ".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
14
- ".naome/bin/naome.js": "sha256:7894690ad47700a9a5e7ecb5a94ba42c1a12e2637d2c9f41f0023b1bd8bd22b6",
12
+ ".naome/bin/check-harness-health.js": "sha256:dc4de52b79c69600b9ba47b924e2c2b8de61a2cbfab6d1ccc0f1924d963db657",
15
13
  ".naome/bin/check-task-state.js": "sha256:43c02868072d0d13499aefba2e9a5ec9517d59539fd19ff0f11e3e4623a51b44",
16
- ".naome/bin/check-harness-health.js": "sha256:dce2a380022dd63d86bd762869debafbc635ab3d7e8fae985e2d429d8ee437ad",
17
- ".naome/task-contract.schema.json": "sha256:c806416d4944eaed6dc48b3760fd0dd5b9b5a7c9ab895697fe36b54c41c1332f",
18
- "docs/naome/index.md": "sha256:d04691b25ed377c2a3aa2c56965d0db276539aeadcfdd2a2ec1be7ff7706dd6f",
14
+ ".naome/bin/naome.js": "sha256:87eabd690bf55f0b0195446db46fa7c19bfa17395d31c2f34a9ef9339d2229e2",
15
+ ".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
16
+ ".naome/task-contract.schema.json": "sha256:1b3b62350328d0d6d660e36d1d1baaa2b88718530db774f9ab2a9e2fcba369c8",
17
+ "AGENTS.md": "sha256:9192ea81f90bb19f8043513c49b5da9e9598ee694da8356f345e7ccbca0e28df",
18
+ "docs/naome/agent-workflow.md": "sha256:802eb34cf268fc9c5e7aefc28192efef4bf60302d30b3f78e5a61b876ce8a098",
19
+ "docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
19
20
  "docs/naome/first-run.md": "sha256:a1dd0bd17ec9d71955a473cd2c4a615538e89a7d81e8f4e1015a50ab9efe3558",
20
- "docs/naome/agent-workflow.md": "sha256:43ba8a6814068e1b932b12a392de70b39841dc82df0acdaac459d6714c501b9d",
21
- "docs/naome/execution.md": "sha256:ad66611b2878d1ba8fe05ddc4cfe9de7fd41de172a0de8295c36227a2700631a",
22
- "docs/naome/upgrade.md": "sha256:2c60f0441bbd98bd528d109b30a7ded4b0ad55d61ffb9f52edac9e93b7999cb1",
23
- ".naome/bin/naome-rust": "sha256:cc754ae59477577dfc0130cc21c286beaf3f19e2852278bb8f1e8724277eb44b"
21
+ "docs/naome/index.md": "sha256:a674102cc801702dc77102afb59be0f5ab189dc638caf0bef358b9d6087d0742",
22
+ "docs/naome/upgrade.md": "sha256:2c60f0441bbd98bd528d109b30a7ded4b0ad55d61ffb9f52edac9e93b7999cb1"
24
23
  });
25
24
 
26
25
  function main(argv) {