@lamentis/naome 1.3.8 → 1.3.9

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.
@@ -9,8 +9,8 @@ import {
9
9
  } from "node:fs";
10
10
  import { dirname, join, relative } from "node:path";
11
11
 
12
- import { archiveUpgradePath, hasSymlinkInTargetPath } from "./filesystem.js";
13
- import { hasGeneratedIntegrity, machineFileHash } from "./native.js";
12
+ import { archiveUpgradePath, assertWritableArchivePath, hasSymlinkInTargetPath } from "./filesystem.js";
13
+ import { machineFileHash } from "./native.js";
14
14
  import { printError } from "./output.js";
15
15
 
16
16
  export function ensureTemplateFile(ctx, relativePath) {
@@ -55,8 +55,13 @@ export function removeLegacyHarnessFile(ctx, relativePath, archiveDirName) {
55
55
  return;
56
56
  }
57
57
 
58
- const archivePath = archiveUpgradePath(ctx, archiveDirName, relativePath);
58
+ const archivePath = safeArchivePath(ctx, archiveDirName, relativePath);
59
+ if (archivePath === null) {
60
+ failUnsafeArchivePath(ctx, archiveDirName, relativePath);
61
+ }
62
+
59
63
  mkdirSync(dirname(archivePath), { recursive: true });
64
+ assertWritableArchivePath(ctx, archiveDirName, relativePath);
60
65
  copyFileSync(targetPath, archivePath);
61
66
  unlinkSync(targetPath);
62
67
  ctx.updated.push(relativePath);
@@ -128,17 +133,40 @@ function replaceChangedHarnessFile(ctx, relativePath, archiveDirName, sourcePath
128
133
  return;
129
134
  }
130
135
 
131
- const archivePath = archiveUpgradePath(ctx, archiveDirName, relativePath);
136
+ const archivePath = safeArchivePath(ctx, archiveDirName, relativePath);
137
+ if (archivePath === null) {
138
+ failUnsafeArchivePath(ctx, archiveDirName, relativePath);
139
+ }
140
+
132
141
  mkdirSync(dirname(archivePath), { recursive: true });
142
+ assertWritableArchivePath(ctx, archiveDirName, relativePath);
133
143
  copyFileSync(targetPath, archivePath);
134
144
  writeFileSync(targetPath, nextContent);
135
145
  ctx.updated.push(relativePath);
136
146
  ctx.archived.push({ from: relativePath, to: relative(ctx.targetRoot, archivePath) });
137
147
  }
138
148
 
139
- function unchangedMachineHash(ctx, relativePath, currentContent, nextContent) {
140
- return (
141
- !hasGeneratedIntegrity(ctx, relativePath) &&
142
- machineFileHash(ctx, relativePath, currentContent) === machineFileHash(ctx, relativePath, nextContent)
149
+ function safeArchivePath(ctx, archiveDirName, relativePath) {
150
+ const archivePath = archiveUpgradePath(ctx, archiveDirName, relativePath);
151
+ const archiveParent = relative(ctx.targetRoot, dirname(archivePath));
152
+ if (hasSymlinkInTargetPath(ctx, archiveParent)) {
153
+ return null;
154
+ }
155
+ if (existsSync(archivePath)) {
156
+ return null;
157
+ }
158
+
159
+ return archivePath;
160
+ }
161
+
162
+ function failUnsafeArchivePath(ctx, archiveDirName, relativePath) {
163
+ printError(ctx, `NAOME cannot archive ${relativePath} safely.`);
164
+ console.error(
165
+ `${relative(ctx.targetRoot, archiveUpgradePath(ctx, archiveDirName, relativePath))} must not contain symlinks or pre-existing files.`
143
166
  );
167
+ process.exit(1);
168
+ }
169
+
170
+ function unchangedMachineHash(ctx, relativePath, currentContent, nextContent) {
171
+ return machineFileHash(ctx, relativePath, currentContent) === machineFileHash(ctx, relativePath, nextContent);
144
172
  }
@@ -2,7 +2,7 @@ import { existsSync, lstatSync, mkdirSync, readFileSync, writeFileSync } from "n
2
2
  import { dirname, join } from "node:path";
3
3
 
4
4
  import { hasSymlinkInTargetPath } from "./filesystem.js";
5
- import { installedNativeBinaryHash, templateIntegrity, usesSourceNativeFallback } from "./native.js";
5
+ import { installedMachineOwnedIntegrity, installedNativeBinaryHash, usesSourceNativeFallback } from "./native.js";
6
6
  import { printError } from "./output.js";
7
7
  import { isVersion } from "./version.js";
8
8
 
@@ -118,7 +118,7 @@ function applyManifestHealthMetadata(ctx, manifest) {
118
118
  manifest.harnessVersion = ctx.packageVersion;
119
119
  manifest.machineOwned = [...ctx.machineOwnedPaths];
120
120
  manifest.projectOwned = ctx.projectOwnedPaths;
121
- manifest.integrity = templateIntegrity(ctx);
121
+ manifest.integrity = installedMachineOwnedIntegrity(ctx);
122
122
 
123
123
  const nativeHash = installedNativeBinaryHash(ctx);
124
124
  if (!usesSourceNativeFallback(ctx) && nativeHash) {
@@ -6,6 +6,7 @@ import {
6
6
  lstatSync,
7
7
  mkdirSync,
8
8
  readFileSync,
9
+ unlinkSync,
9
10
  writeFileSync,
10
11
  } from "node:fs";
11
12
  import { dirname, join, resolve } from "node:path";
@@ -32,8 +33,8 @@ export function installNativeDecisionBinary(ctx) {
32
33
  }
33
34
 
34
35
  if (usesSourceNativeFallback(ctx)) {
35
- patchNaomeCommandNativeIntegrity(ctx, "sha256:generated");
36
- ctx.skipped.push(ctx.nativeBinaryRelativePath);
36
+ removeInstalledNativeDecisionBinary(ctx);
37
+ patchInstalledNativeIntegrity(ctx, "sha256:generated");
37
38
  return;
38
39
  }
39
40
 
@@ -52,7 +53,7 @@ export function installNativeDecisionBinary(ctx) {
52
53
  }
53
54
 
54
55
  chmodSync(targetPath, 0o755);
55
- patchNaomeCommandNativeIntegrity(ctx, `sha256:${sourceHash}`);
56
+ patchInstalledNativeIntegrity(ctx, `sha256:${sourceHash}`);
56
57
  }
57
58
 
58
59
  export function findNativeDecisionBinary(ctx) {
@@ -75,7 +76,7 @@ export function findNativeDecisionBinary(ctx) {
75
76
  }
76
77
 
77
78
  export function patchInstalledMachineOwnedIntegrity(ctx) {
78
- const integrityBlock = formatExpectedIntegrityBlock(templateIntegrity(ctx));
79
+ const integrityBlock = formatExpectedIntegrityBlock(installedMachineOwnedIntegrity(ctx));
79
80
 
80
81
  for (const relativePath of [ctx.healthCheckerRelativePath, ctx.taskStateCheckerRelativePath]) {
81
82
  const targetPath = join(ctx.targetRoot, relativePath);
@@ -110,6 +111,23 @@ export function installedNativeBinaryHash(ctx) {
110
111
  return sha256(readFileSync(targetPath));
111
112
  }
112
113
 
114
+ function removeInstalledNativeDecisionBinary(ctx) {
115
+ const targetPath = join(ctx.targetRoot, ctx.nativeBinaryRelativePath);
116
+ if (!existsSync(targetPath)) {
117
+ ctx.skipped.push(ctx.nativeBinaryRelativePath);
118
+ return;
119
+ }
120
+
121
+ if (hasSymlinkInTargetPath(ctx, ctx.nativeBinaryRelativePath) || !lstatSync(targetPath).isFile()) {
122
+ ctx.skipped.push(ctx.nativeBinaryRelativePath);
123
+ ctx.unsafeSkipped.push(ctx.nativeBinaryRelativePath);
124
+ return;
125
+ }
126
+
127
+ unlinkSync(targetPath);
128
+ ctx.updated.push(ctx.nativeBinaryRelativePath);
129
+ }
130
+
113
131
  export function templateIntegrity(ctx) {
114
132
  const integrity = {};
115
133
 
@@ -121,6 +139,17 @@ export function templateIntegrity(ctx) {
121
139
  return integrity;
122
140
  }
123
141
 
142
+ export function installedMachineOwnedIntegrity(ctx) {
143
+ const integrity = templateIntegrity(ctx);
144
+ const nativeHash = installedNativeBinaryHash(ctx);
145
+
146
+ if (!usesSourceNativeFallback(ctx) && nativeHash) {
147
+ integrity[ctx.nativeBinaryRelativePath] = `sha256:${nativeHash}`;
148
+ }
149
+
150
+ return integrity;
151
+ }
152
+
124
153
  export function sha256(content) {
125
154
  return createHash("sha256").update(content).digest("hex");
126
155
  }
@@ -132,7 +161,7 @@ export function machineFileHash(ctx, relativePath, content) {
132
161
  normalized = normalized.toString("utf8").replace(ctx.integrityBlockPattern, ctx.normalizedIntegrityBlock);
133
162
  }
134
163
 
135
- if (relativePath === ctx.naomeCommandRelativePath) {
164
+ if (hasGeneratedNativeIntegrity(ctx, relativePath)) {
136
165
  normalized = normalized.toString("utf8").replace(ctx.nativeIntegrityPattern, ctx.normalizedNativeIntegrity);
137
166
  }
138
167
 
@@ -143,20 +172,36 @@ export function hasGeneratedIntegrity(ctx, relativePath) {
143
172
  return relativePath === ctx.healthCheckerRelativePath || relativePath === ctx.taskStateCheckerRelativePath;
144
173
  }
145
174
 
146
- function patchNaomeCommandNativeIntegrity(ctx, expectedIntegrity) {
147
- const commandPath = join(ctx.targetRoot, ctx.naomeCommandRelativePath);
148
- if (!existsSync(commandPath) || hasSymlinkInTargetPath(ctx, ctx.naomeCommandRelativePath)) {
149
- return;
150
- }
175
+ export function hasGeneratedNativeIntegrity(ctx, relativePath) {
176
+ return [
177
+ ctx.healthCheckerRelativePath,
178
+ ctx.taskStateCheckerRelativePath,
179
+ ctx.naomeCommandRelativePath,
180
+ ].includes(relativePath);
181
+ }
182
+
183
+ function patchInstalledNativeIntegrity(ctx, expectedIntegrity) {
184
+ const nativeIntegrityPaths = [
185
+ ctx.healthCheckerRelativePath,
186
+ ctx.taskStateCheckerRelativePath,
187
+ ctx.naomeCommandRelativePath,
188
+ ];
189
+
190
+ for (const relativePath of nativeIntegrityPaths) {
191
+ const targetPath = join(ctx.targetRoot, relativePath);
192
+ if (!existsSync(targetPath) || hasSymlinkInTargetPath(ctx, relativePath)) {
193
+ continue;
194
+ }
151
195
 
152
- const content = readFileSync(commandPath, "utf8");
153
- const nextContent = content.replace(
154
- ctx.nativeIntegrityPattern,
155
- `const expectedNativeBinaryIntegrity = "${expectedIntegrity}";\n`,
156
- );
196
+ const content = readFileSync(targetPath, "utf8");
197
+ const nextContent = content.replace(
198
+ ctx.nativeIntegrityPattern,
199
+ `const expectedNativeBinaryIntegrity = "${expectedIntegrity}";\n`,
200
+ );
157
201
 
158
- if (nextContent !== content) {
159
- writeFileSync(commandPath, nextContent);
160
- ctx.updated.push(ctx.naomeCommandRelativePath);
202
+ if (nextContent !== content) {
203
+ writeFileSync(targetPath, nextContent);
204
+ ctx.updated.push(relativePath);
205
+ }
161
206
  }
162
207
  }
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lamentis/naome",
3
- "version": "1.3.8",
3
+ "version": "1.3.9",
4
4
  "description": "Native-first CLI for the NAOME agent harness.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -7,20 +7,21 @@ const path = require("node:path");
7
7
 
8
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
+ const expectedNativeBinaryIntegrity = "sha256:generated";
10
11
 
11
12
  const expectedMachineOwnedIntegrity = Object.freeze({
12
- ".naome/bin/check-harness-health.js": "sha256:dc4de52b79c69600b9ba47b924e2c2b8de61a2cbfab6d1ccc0f1924d963db657",
13
- ".naome/bin/check-task-state.js": "sha256:df54489a22b426180266e5e0fb5f9ec381477419f688435248afbf2b9b38ea81",
14
- ".naome/bin/naome.js": "sha256:a34c2e50a68d15ff2722a57590ccddc504e025d3c98ea62fd700d7ec1a789b9a",
13
+ "AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
15
14
  ".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
15
+ ".naome/bin/naome.js": "sha256:a34c2e50a68d15ff2722a57590ccddc504e025d3c98ea62fd700d7ec1a789b9a",
16
+ ".naome/bin/check-task-state.js": "sha256:2612577b7e4ab45d9d39dd5ac54c8e7ed749d237d78f1a8d252f4dfa0b4eaaab",
17
+ ".naome/bin/check-harness-health.js": "sha256:802d7419774981a6af1826b3882270ff8f41259d516f98c52a02b4ddc184c467",
16
18
  ".naome/task-contract.schema.json": "sha256:1b3b62350328d0d6d660e36d1d1baaa2b88718530db774f9ab2a9e2fcba369c8",
17
- "AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
18
- "docs/naome/agent-workflow.md": "sha256:2fd1fd02eb6849133b9e8227421914580b1c469a60388a063c1b6ed48016b48d",
19
+ "docs/naome/index.md": "sha256:07ef776f49130319a5280bdb3ae38af22141708253f38eb983a4336fbae1b25a",
20
+ "docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
21
+ "docs/naome/agent-workflow.md": "sha256:0be1c29adfbcd3fd73c4f904080ffc67237692fe413871a30243538c4db38ac7",
19
22
  "docs/naome/context-economy.md": "sha256:3ed5075815ecf4ada46a5e65438769310307c35759fcd46b13dc0b96e02bebd9",
23
+ "docs/naome/task-ledger.md": "sha256:6ca7222c80079b4662fb718d3c71d686770646f1fa52b83b0e90aed1c5a1101b",
20
24
  "docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
21
- "docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
22
- "docs/naome/index.md": "sha256:07ef776f49130319a5280bdb3ae38af22141708253f38eb983a4336fbae1b25a",
23
- "docs/naome/task-ledger.md": "sha256:ac637a31abdd13eee15a49086594e63f5c88fe12a5cf621b227310788ae7e583",
24
25
  "docs/naome/upgrade.md": "sha256:2c60f0441bbd98bd528d109b30a7ded4b0ad55d61ffb9f52edac9e93b7999cb1"
25
26
  });
26
27
 
@@ -39,7 +40,7 @@ const result = childProcess.spawnSync(binary, ["check-harness-health", "--root",
39
40
  process.exit(result.status === null ? 1 : result.status);
40
41
 
41
42
  function selectBinary(rootDir) {
42
- const wantedHash = manifestNativeHash(rootDir);
43
+ const wantedHash = expectedNativeHash();
43
44
  const candidates = [
44
45
  process.env.NAOME_NATIVE_BIN,
45
46
  path.join(rootDir, nativeBinaryPath),
@@ -47,13 +48,13 @@ function selectBinary(rootDir) {
47
48
  path.join(rootDir, "packages", "naome", "target", "debug", nativeBinaryName)
48
49
  ].filter(Boolean);
49
50
 
50
- for (const candidate of candidates) {
51
- if (canRun(candidate, rootDir, wantedHash)) {
52
- return candidate;
51
+ if (wantedHash) {
52
+ for (const candidate of candidates) {
53
+ if (canRun(candidate, rootDir, wantedHash)) {
54
+ return candidate;
55
+ }
53
56
  }
54
- }
55
57
 
56
- if (wantedHash) {
57
58
  stop(`No runnable NAOME native harness health binary matched ${wantedHash}. Run naome sync again.`);
58
59
  }
59
60
 
@@ -62,20 +63,19 @@ function selectBinary(rootDir) {
62
63
  return built;
63
64
  }
64
65
 
65
- stop("NAOME native harness health binary is missing or incompatible. Run naome sync again.");
66
+ stop("NAOME native harness health binary has no trusted packaged integrity. Run naome sync again.");
66
67
  }
67
68
 
68
- function manifestNativeHash(rootDir) {
69
+ function expectedNativeHash() {
69
70
  if (isSha(process.env.NAOME_EXPECTED_NATIVE_INTEGRITY)) {
70
71
  return process.env.NAOME_EXPECTED_NATIVE_INTEGRITY;
71
72
  }
72
73
 
73
- try {
74
- const manifest = JSON.parse(fs.readFileSync(path.join(rootDir, ".naome", "manifest.json"), "utf8"));
75
- return isSha(manifest.integrity?.[nativeBinaryPath]) ? manifest.integrity[nativeBinaryPath] : null;
76
- } catch {
77
- return null;
74
+ if (isSha(expectedNativeBinaryIntegrity)) {
75
+ return expectedNativeBinaryIntegrity;
78
76
  }
77
+
78
+ return null;
79
79
  }
80
80
 
81
81
  function canRun(candidate, rootDir, wantedHash) {
@@ -96,6 +96,10 @@ function canRun(candidate, rootDir, wantedHash) {
96
96
  }
97
97
 
98
98
  function buildFromSource(rootDir) {
99
+ if (expectedNativeBinaryIntegrity !== "sha256:generated") {
100
+ return null;
101
+ }
102
+
99
103
  const manifest = path.join(rootDir, "packages", "naome", "Cargo.toml");
100
104
  if (!fs.existsSync(manifest)) {
101
105
  return null;
@@ -7,20 +7,21 @@ const { spawnSync } = require("node:child_process");
7
7
 
8
8
  const nativeBinaryRelativePath = process.platform === "win32" ? ".naome/bin/naome-rust.exe" : ".naome/bin/naome-rust";
9
9
  const nativeBinaryName = process.platform === "win32" ? "naome.exe" : "naome";
10
+ const expectedNativeBinaryIntegrity = "sha256:generated";
10
11
 
11
12
  const expectedMachineOwnedIntegrity = Object.freeze({
12
- ".naome/bin/check-harness-health.js": "sha256:dc4de52b79c69600b9ba47b924e2c2b8de61a2cbfab6d1ccc0f1924d963db657",
13
- ".naome/bin/check-task-state.js": "sha256:df54489a22b426180266e5e0fb5f9ec381477419f688435248afbf2b9b38ea81",
14
- ".naome/bin/naome.js": "sha256:a34c2e50a68d15ff2722a57590ccddc504e025d3c98ea62fd700d7ec1a789b9a",
13
+ "AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
15
14
  ".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
15
+ ".naome/bin/naome.js": "sha256:a34c2e50a68d15ff2722a57590ccddc504e025d3c98ea62fd700d7ec1a789b9a",
16
+ ".naome/bin/check-task-state.js": "sha256:2612577b7e4ab45d9d39dd5ac54c8e7ed749d237d78f1a8d252f4dfa0b4eaaab",
17
+ ".naome/bin/check-harness-health.js": "sha256:802d7419774981a6af1826b3882270ff8f41259d516f98c52a02b4ddc184c467",
16
18
  ".naome/task-contract.schema.json": "sha256:1b3b62350328d0d6d660e36d1d1baaa2b88718530db774f9ab2a9e2fcba369c8",
17
- "AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
18
- "docs/naome/agent-workflow.md": "sha256:2fd1fd02eb6849133b9e8227421914580b1c469a60388a063c1b6ed48016b48d",
19
+ "docs/naome/index.md": "sha256:07ef776f49130319a5280bdb3ae38af22141708253f38eb983a4336fbae1b25a",
20
+ "docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
21
+ "docs/naome/agent-workflow.md": "sha256:0be1c29adfbcd3fd73c4f904080ffc67237692fe413871a30243538c4db38ac7",
19
22
  "docs/naome/context-economy.md": "sha256:3ed5075815ecf4ada46a5e65438769310307c35759fcd46b13dc0b96e02bebd9",
23
+ "docs/naome/task-ledger.md": "sha256:6ca7222c80079b4662fb718d3c71d686770646f1fa52b83b0e90aed1c5a1101b",
20
24
  "docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
21
- "docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
22
- "docs/naome/index.md": "sha256:07ef776f49130319a5280bdb3ae38af22141708253f38eb983a4336fbae1b25a",
23
- "docs/naome/task-ledger.md": "sha256:ac637a31abdd13eee15a49086594e63f5c88fe12a5cf621b227310788ae7e583",
24
25
  "docs/naome/upgrade.md": "sha256:2c60f0441bbd98bd528d109b30a7ded4b0ad55d61ffb9f52edac9e93b7999cb1"
25
26
  });
26
27
 
@@ -62,7 +63,7 @@ function modeArgs(argv) {
62
63
  }
63
64
 
64
65
  function resolveNativeDecisionBinary(root) {
65
- const expectedIntegrity = expectedNativeIntegrity(root);
66
+ const expectedIntegrity = expectedNativeIntegrity();
66
67
  const candidates = [
67
68
  process.env.NAOME_NATIVE_BIN,
68
69
  join(root, nativeBinaryRelativePath),
@@ -70,13 +71,13 @@ function resolveNativeDecisionBinary(root) {
70
71
  join(root, "packages", "naome", "target", "debug", nativeBinaryName)
71
72
  ].filter(Boolean);
72
73
 
73
- for (const candidate of candidates) {
74
- if (isUsableNativeBinary(candidate, root, expectedIntegrity)) {
75
- return candidate;
74
+ if (expectedIntegrity) {
75
+ for (const candidate of candidates) {
76
+ if (isUsableNativeBinary(candidate, root, expectedIntegrity)) {
77
+ return candidate;
78
+ }
76
79
  }
77
- }
78
80
 
79
- if (expectedIntegrity) {
80
81
  fail(`No runnable NAOME native task-state binary matched ${expectedIntegrity}. Run naome sync again.`);
81
82
  }
82
83
 
@@ -88,29 +89,16 @@ function resolveNativeDecisionBinary(root) {
88
89
  fail("NAOME native task-state binary is missing or incompatible. Run naome sync again.");
89
90
  }
90
91
 
91
- function expectedNativeIntegrity(root) {
92
+ function expectedNativeIntegrity() {
92
93
  if (isIntegrityHash(process.env.NAOME_EXPECTED_NATIVE_INTEGRITY)) {
93
94
  return process.env.NAOME_EXPECTED_NATIVE_INTEGRITY;
94
95
  }
95
96
 
96
- const manifestPath = join(root, ".naome", "manifest.json");
97
- if (!existsSync(manifestPath)) {
98
- return null;
99
- }
100
-
101
- let manifest;
102
- try {
103
- manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
104
- } catch {
105
- return null;
106
- }
107
-
108
- const expected = manifest.integrity?.[nativeBinaryRelativePath];
109
- if (!isIntegrityHash(expected)) {
97
+ if (expectedNativeBinaryIntegrity === "sha256:generated") {
110
98
  return null;
111
99
  }
112
100
 
113
- return expected;
101
+ return expectedNativeBinaryIntegrity;
114
102
  }
115
103
 
116
104
  function isUsableNativeBinary(candidate, root, expectedIntegrity) {
@@ -125,30 +113,35 @@ function isUsableNativeBinary(candidate, root, expectedIntegrity) {
125
113
  }
126
114
  }
127
115
 
128
- const probe = spawnSync(candidate, [], {
129
- cwd: root,
130
- encoding: "utf8",
131
- stdio: "ignore"
132
- });
116
+ const probe = spawnSync(candidate, [], { cwd: root, stdio: ["ignore", "ignore", "ignore"] });
133
117
  return !probe.error && probe.status !== null;
134
118
  }
135
119
 
136
120
  function buildSourceNativeBinary(root) {
137
- const manifestPath = join(root, "packages", "naome", "Cargo.toml");
121
+ if (expectedNativeBinaryIntegrity !== "sha256:generated") {
122
+ return null;
123
+ }
124
+
125
+ const packageRoot = join(root, "packages", "naome");
126
+ const manifestPath = join(packageRoot, "Cargo.toml");
138
127
  if (!existsSync(manifestPath)) {
139
128
  return null;
140
129
  }
141
130
 
142
- const result = spawnSync("cargo", ["build", "--release", "--manifest-path", manifestPath, "-p", "naome-cli"], {
143
- cwd: root,
144
- encoding: "utf8",
145
- stdio: "ignore"
146
- });
131
+ const result = spawnSync(
132
+ "cargo",
133
+ ["build", "--release", "--manifest-path", manifestPath, "-p", "naome-cli"],
134
+ {
135
+ cwd: root,
136
+ encoding: "utf8",
137
+ stdio: "ignore"
138
+ }
139
+ );
147
140
  if (result.status !== 0) {
148
141
  return null;
149
142
  }
150
143
 
151
- const builtPath = join(root, "packages", "naome", "target", "release", nativeBinaryName);
144
+ const builtPath = join(packageRoot, "target", "release", nativeBinaryName);
152
145
  return existsSync(builtPath) ? builtPath : null;
153
146
  }
154
147
 
@@ -1,19 +1,19 @@
1
1
  {
2
- "harnessVersion": "1.3.8",
2
+ "harnessVersion": "1.3.9",
3
3
  "installedAt": null,
4
4
  "integrity": {
5
- ".naome/bin/check-harness-health.js": "sha256:dc4de52b79c69600b9ba47b924e2c2b8de61a2cbfab6d1ccc0f1924d963db657",
6
- ".naome/bin/check-task-state.js": "sha256:df54489a22b426180266e5e0fb5f9ec381477419f688435248afbf2b9b38ea81",
7
- ".naome/bin/naome.js": "sha256:a34c2e50a68d15ff2722a57590ccddc504e025d3c98ea62fd700d7ec1a789b9a",
5
+ "AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
8
6
  ".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
7
+ ".naome/bin/naome.js": "sha256:a34c2e50a68d15ff2722a57590ccddc504e025d3c98ea62fd700d7ec1a789b9a",
8
+ ".naome/bin/check-task-state.js": "sha256:2612577b7e4ab45d9d39dd5ac54c8e7ed749d237d78f1a8d252f4dfa0b4eaaab",
9
+ ".naome/bin/check-harness-health.js": "sha256:802d7419774981a6af1826b3882270ff8f41259d516f98c52a02b4ddc184c467",
9
10
  ".naome/task-contract.schema.json": "sha256:1b3b62350328d0d6d660e36d1d1baaa2b88718530db774f9ab2a9e2fcba369c8",
10
- "AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
11
+ "docs/naome/index.md": "sha256:07ef776f49130319a5280bdb3ae38af22141708253f38eb983a4336fbae1b25a",
12
+ "docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
11
13
  "docs/naome/agent-workflow.md": "sha256:0be1c29adfbcd3fd73c4f904080ffc67237692fe413871a30243538c4db38ac7",
12
14
  "docs/naome/context-economy.md": "sha256:3ed5075815ecf4ada46a5e65438769310307c35759fcd46b13dc0b96e02bebd9",
13
- "docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
14
- "docs/naome/first-run.md": "sha256:1466ce8c65e19a1514885f917db14e8a772350e3f6d1c03a66326963365919e1",
15
- "docs/naome/index.md": "sha256:07ef776f49130319a5280bdb3ae38af22141708253f38eb983a4336fbae1b25a",
16
15
  "docs/naome/task-ledger.md": "sha256:6ca7222c80079b4662fb718d3c71d686770646f1fa52b83b0e90aed1c5a1101b",
16
+ "docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
17
17
  "docs/naome/upgrade.md": "sha256:2c60f0441bbd98bd528d109b30a7ded4b0ad55d61ffb9f52edac9e93b7999cb1"
18
18
  },
19
19
  "machineOwned": [
@@ -27,8 +27,8 @@
27
27
  "docs/naome/first-run.md",
28
28
  "docs/naome/agent-workflow.md",
29
29
  "docs/naome/context-economy.md",
30
- "docs/naome/execution.md",
31
30
  "docs/naome/task-ledger.md",
31
+ "docs/naome/execution.md",
32
32
  "docs/naome/upgrade.md"
33
33
  ],
34
34
  "name": "naome",