@lamentis/naome 1.0.0
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 +199 -0
- package/Cargo.toml +11 -0
- package/LICENSE +21 -0
- package/README.md +6 -0
- package/bin/naome-node.js +1424 -0
- package/bin/naome.js +129 -0
- package/crates/naome-cli/Cargo.toml +14 -0
- package/crates/naome-cli/src/main.rs +341 -0
- package/crates/naome-core/Cargo.toml +11 -0
- package/crates/naome-core/src/decision.rs +432 -0
- package/crates/naome-core/src/git.rs +70 -0
- package/crates/naome-core/src/harness_health.rs +557 -0
- package/crates/naome-core/src/install_plan.rs +82 -0
- package/crates/naome-core/src/lib.rs +17 -0
- package/crates/naome-core/src/models.rs +99 -0
- package/crates/naome-core/src/paths.rs +72 -0
- package/crates/naome-core/src/task_state.rs +1859 -0
- package/crates/naome-core/src/verification.rs +217 -0
- package/crates/naome-core/src/verification_contract.rs +406 -0
- package/crates/naome-core/tests/decision.rs +297 -0
- package/crates/naome-core/tests/harness_health.rs +232 -0
- package/crates/naome-core/tests/install_plan.rs +35 -0
- package/crates/naome-core/tests/task_state.rs +588 -0
- package/crates/naome-core/tests/verification.rs +165 -0
- package/crates/naome-core/tests/verification_contract.rs +181 -0
- package/native/darwin-arm64/naome +0 -0
- package/package.json +44 -0
- package/templates/naome-root/.naome/bin/check-harness-health.js +163 -0
- package/templates/naome-root/.naome/bin/check-task-state.js +180 -0
- package/templates/naome-root/.naome/bin/naome.js +306 -0
- package/templates/naome-root/.naome/init-state.json +13 -0
- package/templates/naome-root/.naome/manifest.json +45 -0
- package/templates/naome-root/.naome/package.json +3 -0
- package/templates/naome-root/.naome/task-contract.schema.json +174 -0
- package/templates/naome-root/.naome/task-state.json +8 -0
- package/templates/naome-root/.naome/upgrade-state.json +7 -0
- package/templates/naome-root/.naome/verification.json +45 -0
- package/templates/naome-root/.naomeignore +4 -0
- package/templates/naome-root/AGENTS.md +77 -0
- package/templates/naome-root/docs/naome/agent-workflow.md +82 -0
- package/templates/naome-root/docs/naome/architecture.md +37 -0
- package/templates/naome-root/docs/naome/decisions.md +18 -0
- package/templates/naome-root/docs/naome/execution.md +192 -0
- package/templates/naome-root/docs/naome/first-run.md +135 -0
- package/templates/naome-root/docs/naome/index.md +67 -0
- package/templates/naome-root/docs/naome/repo-profile.md +51 -0
- package/templates/naome-root/docs/naome/security.md +60 -0
- package/templates/naome-root/docs/naome/testing.md +51 -0
- package/templates/naome-root/docs/naome/upgrade.md +20 -0
package/bin/naome.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
import { dirname, join, resolve } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
9
|
+
const nativeBinaryName = process.platform === "win32" ? "naome.exe" : "naome";
|
|
10
|
+
const args = process.argv.slice(2);
|
|
11
|
+
const [command] = args;
|
|
12
|
+
|
|
13
|
+
if (isHelpRequest(args)) {
|
|
14
|
+
printHelp();
|
|
15
|
+
process.exit(0);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (command === "install" || command === "sync") {
|
|
19
|
+
runNativePackageCommand(args);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const commandPath = findHarnessCommand(process.cwd());
|
|
23
|
+
|
|
24
|
+
if (!commandPath) {
|
|
25
|
+
console.error("NAOME: installed harness command not found. Run this inside a repository with .naome/bin/naome.js.");
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const result = spawnSync(process.execPath, [commandPath, ...process.argv.slice(2)], {
|
|
30
|
+
cwd: process.cwd(),
|
|
31
|
+
encoding: "utf8",
|
|
32
|
+
stdio: "inherit",
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
process.exit(result.status === null ? 1 : result.status);
|
|
36
|
+
|
|
37
|
+
function isHelpRequest(args) {
|
|
38
|
+
return ["help", "--help", "-h"].includes(args[0]) || ["help", "--help", "-h"].includes(args[1]);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function printHelp() {
|
|
42
|
+
console.log("Usage:");
|
|
43
|
+
console.log(" naome status [--json]");
|
|
44
|
+
console.log(" naome next [--json]");
|
|
45
|
+
console.log(" naome install");
|
|
46
|
+
console.log(" naome sync");
|
|
47
|
+
console.log(" naome commit -m \"type(scope): message\"");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function runNativePackageCommand(args) {
|
|
51
|
+
const nativeBinary = resolveNativePackageBinary();
|
|
52
|
+
if (!nativeBinary) {
|
|
53
|
+
console.error("NAOME: native CLI is unavailable.");
|
|
54
|
+
console.error("Install Cargo or provide NAOME_NATIVE_BIN with a built naome binary.");
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const result = spawnSync(nativeBinary, [
|
|
59
|
+
...args,
|
|
60
|
+
"--package-root",
|
|
61
|
+
packageRoot,
|
|
62
|
+
"--installer-js",
|
|
63
|
+
join(packageRoot, "bin", "naome-node.js")
|
|
64
|
+
], {
|
|
65
|
+
cwd: process.cwd(),
|
|
66
|
+
encoding: "utf8",
|
|
67
|
+
env: {
|
|
68
|
+
...process.env,
|
|
69
|
+
NAOME_NODE_BIN: process.execPath
|
|
70
|
+
},
|
|
71
|
+
stdio: "inherit"
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
process.exit(result.status === null ? 1 : result.status);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function resolveNativePackageBinary() {
|
|
78
|
+
const candidates = [
|
|
79
|
+
process.env.NAOME_NATIVE_BIN && resolve(process.cwd(), process.env.NAOME_NATIVE_BIN),
|
|
80
|
+
join(packageRoot, "native", `${process.platform}-${process.arch}`, nativeBinaryName),
|
|
81
|
+
join(packageRoot, "target", "release", nativeBinaryName)
|
|
82
|
+
].filter(Boolean);
|
|
83
|
+
|
|
84
|
+
for (const candidate of candidates) {
|
|
85
|
+
if (existsSync(candidate)) {
|
|
86
|
+
return candidate;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const built = buildNativePackageBinary();
|
|
91
|
+
return built && existsSync(built) ? built : null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function buildNativePackageBinary() {
|
|
95
|
+
const manifestPath = join(packageRoot, "Cargo.toml");
|
|
96
|
+
if (!existsSync(manifestPath)) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const result = spawnSync("cargo", ["build", "--release", "--manifest-path", manifestPath, "-p", "naome-cli"], {
|
|
101
|
+
cwd: packageRoot,
|
|
102
|
+
encoding: "utf8",
|
|
103
|
+
stdio: "inherit"
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
if (result.status !== 0) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return join(packageRoot, "target", "release", nativeBinaryName);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function findHarnessCommand(startPath) {
|
|
114
|
+
let current = resolve(startPath);
|
|
115
|
+
|
|
116
|
+
while (true) {
|
|
117
|
+
const candidate = join(current, ".naome", "bin", "naome.js");
|
|
118
|
+
if (existsSync(candidate)) {
|
|
119
|
+
return candidate;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const parent = dirname(current);
|
|
123
|
+
if (parent === current) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
current = parent;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "naome-cli"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
edition.workspace = true
|
|
5
|
+
license.workspace = true
|
|
6
|
+
repository.workspace = true
|
|
7
|
+
|
|
8
|
+
[[bin]]
|
|
9
|
+
name = "naome"
|
|
10
|
+
path = "src/main.rs"
|
|
11
|
+
|
|
12
|
+
[dependencies]
|
|
13
|
+
naome-core = { path = "../naome-core" }
|
|
14
|
+
serde_json = "1"
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
use std::path::{Path, PathBuf};
|
|
3
|
+
use std::process::Command;
|
|
4
|
+
|
|
5
|
+
use naome_core::{
|
|
6
|
+
evaluate_decision, format_decision, install_plan, seed_builtin_verification_checks,
|
|
7
|
+
validate_harness_health, validate_task_state, validate_verification_contract,
|
|
8
|
+
EvaluationOptions, HarnessHealthOptions, TaskStateMode, TaskStateOptions,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
fn main() {
|
|
12
|
+
if let Err(error) = run() {
|
|
13
|
+
eprintln!("NAOME: {error}");
|
|
14
|
+
std::process::exit(1);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
fn run() -> Result<(), Box<dyn std::error::Error>> {
|
|
19
|
+
let args: Vec<String> = std::env::args().skip(1).collect();
|
|
20
|
+
let Some(command) = args.first().map(String::as_str) else {
|
|
21
|
+
print_help();
|
|
22
|
+
return Ok(());
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
if is_help_request(&args) {
|
|
26
|
+
print_help();
|
|
27
|
+
return Ok(());
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if command != "status"
|
|
31
|
+
&& command != "next"
|
|
32
|
+
&& command != "seed-verification"
|
|
33
|
+
&& command != "install-plan"
|
|
34
|
+
&& command != "install"
|
|
35
|
+
&& command != "sync"
|
|
36
|
+
&& command != "check-harness-health"
|
|
37
|
+
&& command != "check-task-state"
|
|
38
|
+
&& command != "validate-verification"
|
|
39
|
+
{
|
|
40
|
+
print_help();
|
|
41
|
+
return Err(format!("unknown command: {command}").into());
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let root = if command == "install-plan" || command == "install" || command == "sync" {
|
|
45
|
+
std::env::current_dir()?
|
|
46
|
+
} else if command == "validate-verification"
|
|
47
|
+
|| command == "check-harness-health"
|
|
48
|
+
|| command == "check-task-state"
|
|
49
|
+
{
|
|
50
|
+
option_value(&args, "--root")
|
|
51
|
+
.map(PathBuf::from)
|
|
52
|
+
.or_else(|| find_manifest_root(&std::env::current_dir().ok()?))
|
|
53
|
+
.unwrap_or(std::env::current_dir()?)
|
|
54
|
+
} else {
|
|
55
|
+
find_harness_root(&std::env::current_dir()?).ok_or(
|
|
56
|
+
"NAOME harness root not found. Run this inside a repository with .naome/task-state.json.",
|
|
57
|
+
)?
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
if command == "install" || command == "sync" {
|
|
61
|
+
run_install_bridge(command, &args)?;
|
|
62
|
+
return Ok(());
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if command == "install-plan" {
|
|
66
|
+
let harness_version = option_value(&args, "--harness-version")
|
|
67
|
+
.or_else(|| option_value(&args, "--version"))
|
|
68
|
+
.unwrap_or_else(|| env!("CARGO_PKG_VERSION").to_string());
|
|
69
|
+
println!(
|
|
70
|
+
"{}",
|
|
71
|
+
serde_json::to_string_pretty(&install_plan(harness_version))?
|
|
72
|
+
);
|
|
73
|
+
return Ok(());
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if command == "seed-verification" {
|
|
77
|
+
if seed_builtin_verification_checks(&root)? {
|
|
78
|
+
println!("NAOME verification checks updated.");
|
|
79
|
+
} else {
|
|
80
|
+
println!("NAOME verification checks already present.");
|
|
81
|
+
}
|
|
82
|
+
return Ok(());
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if command == "check-harness-health" {
|
|
86
|
+
let options = HarnessHealthOptions {
|
|
87
|
+
expected_integrity: expected_integrity_from_env()?,
|
|
88
|
+
allow_missing_integrity: std::env::var("NAOME_ALLOW_MISSING_INTEGRITY")
|
|
89
|
+
.is_ok_and(|value| value == "1"),
|
|
90
|
+
allow_missing_archive: args.iter().any(|arg| arg == "--allow-missing-archive"),
|
|
91
|
+
};
|
|
92
|
+
let errors = validate_harness_health(&root, options)?;
|
|
93
|
+
if errors.is_empty() {
|
|
94
|
+
println!("NAOME harness health OK.");
|
|
95
|
+
return Ok(());
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
eprintln!("NAOME harness health check failed.");
|
|
99
|
+
for error in errors {
|
|
100
|
+
eprintln!("- {error}");
|
|
101
|
+
}
|
|
102
|
+
std::process::exit(1);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if command == "check-task-state" {
|
|
106
|
+
let mode = if args.iter().any(|arg| arg == "--admission") {
|
|
107
|
+
TaskStateMode::Admission
|
|
108
|
+
} else if args.iter().any(|arg| arg == "--progress") {
|
|
109
|
+
TaskStateMode::Progress
|
|
110
|
+
} else if args.iter().any(|arg| arg == "--commit-gate") {
|
|
111
|
+
TaskStateMode::CommitGate
|
|
112
|
+
} else if args.iter().any(|arg| arg == "--push-gate") {
|
|
113
|
+
TaskStateMode::PushGate
|
|
114
|
+
} else {
|
|
115
|
+
TaskStateMode::State
|
|
116
|
+
};
|
|
117
|
+
let expected_integrity = expected_integrity_from_env()?;
|
|
118
|
+
let harness_health = if expected_integrity.is_empty()
|
|
119
|
+
&& std::env::var("NAOME_ALLOW_MISSING_INTEGRITY").is_err()
|
|
120
|
+
{
|
|
121
|
+
None
|
|
122
|
+
} else {
|
|
123
|
+
Some(HarnessHealthOptions {
|
|
124
|
+
expected_integrity,
|
|
125
|
+
allow_missing_integrity: std::env::var("NAOME_ALLOW_MISSING_INTEGRITY")
|
|
126
|
+
.is_ok_and(|value| value == "1"),
|
|
127
|
+
allow_missing_archive: args.iter().any(|arg| arg == "--allow-missing-archive"),
|
|
128
|
+
})
|
|
129
|
+
};
|
|
130
|
+
let report = validate_task_state(
|
|
131
|
+
&root,
|
|
132
|
+
TaskStateOptions {
|
|
133
|
+
mode,
|
|
134
|
+
harness_health,
|
|
135
|
+
},
|
|
136
|
+
)?;
|
|
137
|
+
if report.errors.is_empty() {
|
|
138
|
+
println!("{}", task_state_success_message(mode));
|
|
139
|
+
for notice in report.notices {
|
|
140
|
+
println!("- {notice}");
|
|
141
|
+
}
|
|
142
|
+
return Ok(());
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
eprintln!("{}", task_state_failure_message(mode));
|
|
146
|
+
for error in report.errors {
|
|
147
|
+
eprintln!("- {error}");
|
|
148
|
+
}
|
|
149
|
+
std::process::exit(1);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if command == "validate-verification" {
|
|
153
|
+
let errors = validate_verification_contract(&root)?;
|
|
154
|
+
if errors.is_empty() {
|
|
155
|
+
println!("NAOME verification contract OK.");
|
|
156
|
+
return Ok(());
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
eprintln!("NAOME verification contract failed.");
|
|
160
|
+
for error in errors {
|
|
161
|
+
eprintln!("- {error}");
|
|
162
|
+
}
|
|
163
|
+
std::process::exit(1);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
let decision = evaluate_decision(&root, EvaluationOptions::online())?;
|
|
167
|
+
|
|
168
|
+
if args.iter().any(|arg| arg == "--json") {
|
|
169
|
+
println!("{}", serde_json::to_string_pretty(&decision)?);
|
|
170
|
+
} else {
|
|
171
|
+
print!("{}", format_decision(&decision, command));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
Ok(())
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
fn is_help_request(args: &[String]) -> bool {
|
|
178
|
+
matches!(args.first().map(String::as_str), Some("help" | "--help" | "-h"))
|
|
179
|
+
|| args
|
|
180
|
+
.get(1)
|
|
181
|
+
.is_some_and(|arg| arg == "--help" || arg == "-h" || arg == "help")
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
fn find_harness_root(start: &Path) -> Option<PathBuf> {
|
|
185
|
+
let mut current = start.to_path_buf();
|
|
186
|
+
loop {
|
|
187
|
+
if current.join(".naome").join("task-state.json").is_file() {
|
|
188
|
+
return Some(current);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if !current.pop() {
|
|
192
|
+
return None;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
fn find_manifest_root(start: &Path) -> Option<PathBuf> {
|
|
198
|
+
let mut current = start.to_path_buf();
|
|
199
|
+
loop {
|
|
200
|
+
if current.join(".naome").join("manifest.json").is_file() {
|
|
201
|
+
return Some(current);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if !current.pop() {
|
|
205
|
+
return None;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
fn print_help() {
|
|
211
|
+
println!("Usage:");
|
|
212
|
+
println!(" naome status [--json]");
|
|
213
|
+
println!(" naome next [--json]");
|
|
214
|
+
println!(" naome install [--package-root <path>] [--installer-js <path>]");
|
|
215
|
+
println!(" naome sync [--package-root <path>] [--installer-js <path>]");
|
|
216
|
+
println!(" naome install-plan [--harness-version <version>]");
|
|
217
|
+
println!(" naome seed-verification");
|
|
218
|
+
println!(" naome check-harness-health [--root <path>] [--allow-missing-archive]");
|
|
219
|
+
println!(" naome check-task-state [--root <path>] [--admission|--progress|--commit-gate|--push-gate] [--allow-missing-archive]");
|
|
220
|
+
println!(" naome validate-verification [--root <path>]");
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
fn option_value(args: &[String], option: &str) -> Option<String> {
|
|
224
|
+
args.windows(2)
|
|
225
|
+
.find(|window| window[0] == option)
|
|
226
|
+
.map(|window| window[1].clone())
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
fn run_install_bridge(command: &str, args: &[String]) -> Result<(), Box<dyn std::error::Error>> {
|
|
230
|
+
let package_root = option_value(args, "--package-root")
|
|
231
|
+
.map(PathBuf::from)
|
|
232
|
+
.or_else(|| std::env::var("NAOME_PACKAGE_ROOT").ok().map(PathBuf::from))
|
|
233
|
+
.or_else(resolve_package_root_from_exe)
|
|
234
|
+
.or_else(resolve_package_root_from_cwd);
|
|
235
|
+
let installer_js = option_value(args, "--installer-js")
|
|
236
|
+
.map(PathBuf::from)
|
|
237
|
+
.or_else(|| std::env::var("NAOME_INSTALLER_JS").ok().map(PathBuf::from))
|
|
238
|
+
.or_else(|| {
|
|
239
|
+
package_root
|
|
240
|
+
.as_ref()
|
|
241
|
+
.map(|root| root.join("bin").join("naome-node.js"))
|
|
242
|
+
});
|
|
243
|
+
let Some(installer_js) = installer_js.filter(|path| path.is_file()) else {
|
|
244
|
+
return Err(format!(
|
|
245
|
+
"native {command} needs naome-node.js. Install the naome npm package, or pass --package-root/--installer-js."
|
|
246
|
+
)
|
|
247
|
+
.into());
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
let node_bin = std::env::var("NAOME_NODE_BIN").unwrap_or_else(|_| "node".to_string());
|
|
251
|
+
let pass_through_args = strip_install_bridge_options(args);
|
|
252
|
+
let status = Command::new(node_bin)
|
|
253
|
+
.arg(installer_js)
|
|
254
|
+
.args(pass_through_args)
|
|
255
|
+
.status()?;
|
|
256
|
+
|
|
257
|
+
if status.success() {
|
|
258
|
+
return Ok(());
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
std::process::exit(status.code().unwrap_or(1));
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
fn strip_install_bridge_options(args: &[String]) -> Vec<String> {
|
|
265
|
+
let mut result = Vec::new();
|
|
266
|
+
let mut index = 1;
|
|
267
|
+
while index < args.len() {
|
|
268
|
+
let arg = &args[index];
|
|
269
|
+
if arg == "--package-root" || arg == "--installer-js" {
|
|
270
|
+
index += 2;
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if arg.starts_with("--package-root=") || arg.starts_with("--installer-js=") {
|
|
275
|
+
index += 1;
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
result.push(arg.clone());
|
|
280
|
+
index += 1;
|
|
281
|
+
}
|
|
282
|
+
result
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
fn resolve_package_root_from_exe() -> Option<PathBuf> {
|
|
286
|
+
let exe = std::env::current_exe().ok()?;
|
|
287
|
+
let platform_dir = exe.parent()?;
|
|
288
|
+
let native_dir = platform_dir.parent()?;
|
|
289
|
+
if native_dir.file_name().and_then(|value| value.to_str()) == Some("native") {
|
|
290
|
+
let package_root = native_dir.parent()?.to_path_buf();
|
|
291
|
+
if package_root
|
|
292
|
+
.join("bin")
|
|
293
|
+
.join("naome-node.js")
|
|
294
|
+
.is_file()
|
|
295
|
+
{
|
|
296
|
+
return Some(package_root);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
None
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
fn resolve_package_root_from_cwd() -> Option<PathBuf> {
|
|
303
|
+
let current = std::env::current_dir().ok()?;
|
|
304
|
+
for candidate in [
|
|
305
|
+
current.join("packages").join("naome"),
|
|
306
|
+
current.clone(),
|
|
307
|
+
] {
|
|
308
|
+
if candidate.join("bin").join("naome-node.js").is_file() {
|
|
309
|
+
return Some(candidate);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
None
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
fn expected_integrity_from_env() -> Result<HashMap<String, String>, Box<dyn std::error::Error>> {
|
|
316
|
+
let Ok(value) = std::env::var("NAOME_EXPECTED_INTEGRITY_JSON") else {
|
|
317
|
+
return Ok(HashMap::new());
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
Ok(serde_json::from_str(&value)?)
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
fn task_state_failure_message(mode: TaskStateMode) -> &'static str {
|
|
324
|
+
match mode {
|
|
325
|
+
TaskStateMode::Admission => "NAOME task admission check failed.",
|
|
326
|
+
TaskStateMode::Progress => "NAOME task progress check failed.",
|
|
327
|
+
TaskStateMode::CommitGate => "NAOME commit gate failed.",
|
|
328
|
+
TaskStateMode::PushGate => "NAOME push gate failed.",
|
|
329
|
+
TaskStateMode::State => "NAOME task state check failed.",
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
fn task_state_success_message(mode: TaskStateMode) -> &'static str {
|
|
334
|
+
match mode {
|
|
335
|
+
TaskStateMode::Admission => "NAOME task admission OK.",
|
|
336
|
+
TaskStateMode::Progress => "NAOME task progress OK.",
|
|
337
|
+
TaskStateMode::CommitGate => "NAOME commit gate OK.",
|
|
338
|
+
TaskStateMode::PushGate => "NAOME push gate OK.",
|
|
339
|
+
TaskStateMode::State => "NAOME task state OK.",
|
|
340
|
+
}
|
|
341
|
+
}
|