nemoris 0.1.5 → 0.1.6
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/SECURITY.md +1 -1
- package/package.json +1 -1
- package/src/auth/auth-profiles.js +13 -8
- package/src/cli-main.js +35 -34
- package/src/onboarding/auth/api-key.js +1 -1
- package/src/tui/socket-client.js +1 -1
package/SECURITY.md
CHANGED
|
@@ -23,7 +23,7 @@ You will receive an acknowledgement within 48 hours. We aim to provide a substan
|
|
|
23
23
|
|
|
24
24
|
Nemoris runs locally on your machine. Key security properties:
|
|
25
25
|
|
|
26
|
-
- **API keys** are stored in `~/.nemoris/.env` with `0600` permissions (owner read/write only)
|
|
26
|
+
- **API keys** are stored in `~/.nemoris-data/.env` with `0600` permissions (owner read/write only)
|
|
27
27
|
- **Keys are never logged** — the runtime redacts secrets from all log output
|
|
28
28
|
- **Exec approval gates** require human confirmation before shell commands execute
|
|
29
29
|
- **SSRF protection** on all URL-intake surfaces
|
package/package.json
CHANGED
|
@@ -11,16 +11,21 @@ function dedupe(items = []) {
|
|
|
11
11
|
|
|
12
12
|
export function resolveInstallDir({ env = process.env, cwd: _cwd = process.cwd() } = {}) {
|
|
13
13
|
if (env.NEMORIS_INSTALL_DIR) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return _cwd;
|
|
14
|
+
const resolved = env.NEMORIS_INSTALL_DIR;
|
|
15
|
+
if (fs.existsSync(path.join(resolved, "package.json"))) {
|
|
16
|
+
throw new Error(
|
|
17
|
+
`NEMORIS_INSTALL_DIR "${resolved}" looks like a source repo.\n` +
|
|
18
|
+
`Set NEMORIS_INSTALL_DIR to a clean data directory (e.g. ~/.nemoris-data).`
|
|
19
|
+
);
|
|
21
20
|
}
|
|
21
|
+
return resolved;
|
|
22
|
+
}
|
|
23
|
+
// Dev mode: when CWD is the source repo, use it as install dir
|
|
24
|
+
if (_cwd && fs.existsSync(path.join(_cwd, "package.json")) &&
|
|
25
|
+
fs.existsSync(path.join(_cwd, "src", "cli.js"))) {
|
|
26
|
+
return _cwd;
|
|
22
27
|
}
|
|
23
|
-
return path.join(os.homedir(), ".nemoris");
|
|
28
|
+
return path.join(os.homedir(), ".nemoris-data");
|
|
24
29
|
}
|
|
25
30
|
|
|
26
31
|
export function resolveAuthProfilesPath({ env = process.env, cwd = process.cwd() } = {}) {
|
package/src/cli-main.js
CHANGED
|
@@ -53,51 +53,52 @@ import {
|
|
|
53
53
|
import { resolveAuthProfilesPath, resolveInstallDir } from "./auth/auth-profiles.js";
|
|
54
54
|
|
|
55
55
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
56
|
-
const projectRoot = path.join(__dirname, "..");
|
|
57
|
-
const
|
|
58
|
-
const
|
|
56
|
+
const projectRoot = path.join(__dirname, ".."); // npm package dir — only for package.json reads
|
|
57
|
+
const installDir = resolveRuntimeInstallDir(); // user data dir — all runtime state lives here
|
|
58
|
+
const stateRoot = path.join(installDir, "state", "memory");
|
|
59
|
+
const liveRoot = resolveLiveRoot(installDir);
|
|
59
60
|
const scheduler = new Scheduler({
|
|
60
|
-
projectRoot,
|
|
61
|
+
projectRoot: installDir,
|
|
61
62
|
liveRoot,
|
|
62
|
-
stateRoot: path.join(
|
|
63
|
+
stateRoot: path.join(installDir, "state")
|
|
63
64
|
});
|
|
64
65
|
const executor = new Executor({
|
|
65
|
-
projectRoot,
|
|
66
|
+
projectRoot: installDir,
|
|
66
67
|
liveRoot,
|
|
67
|
-
stateRoot: path.join(
|
|
68
|
+
stateRoot: path.join(installDir, "state")
|
|
68
69
|
});
|
|
69
70
|
const daemon = new SchedulerDaemon({
|
|
70
|
-
projectRoot,
|
|
71
|
+
projectRoot: installDir,
|
|
71
72
|
liveRoot,
|
|
72
|
-
stateRoot: path.join(
|
|
73
|
+
stateRoot: path.join(installDir, "state")
|
|
73
74
|
});
|
|
74
75
|
const reviewer = new RunReviewer({
|
|
75
|
-
stateRoot: path.join(
|
|
76
|
+
stateRoot: path.join(installDir, "state")
|
|
76
77
|
});
|
|
77
78
|
const deliveryManager = new DeliveryManager({
|
|
78
|
-
projectRoot,
|
|
79
|
+
projectRoot: installDir,
|
|
79
80
|
liveRoot,
|
|
80
|
-
stateRoot: path.join(
|
|
81
|
+
stateRoot: path.join(installDir, "state")
|
|
81
82
|
});
|
|
82
83
|
const evaluator = new Evaluator({
|
|
83
|
-
projectRoot,
|
|
84
|
+
projectRoot: installDir,
|
|
84
85
|
liveRoot,
|
|
85
|
-
stateRoot: path.join(
|
|
86
|
+
stateRoot: path.join(installDir, "state")
|
|
86
87
|
});
|
|
87
88
|
const improvementHarness = new ImprovementHarness({
|
|
88
|
-
projectRoot,
|
|
89
|
-
stateRoot: path.join(
|
|
89
|
+
projectRoot: installDir,
|
|
90
|
+
stateRoot: path.join(installDir, "state"),
|
|
90
91
|
executor,
|
|
91
92
|
evaluator
|
|
92
93
|
});
|
|
93
94
|
const dependencyHealth = new DependencyHealth({
|
|
94
|
-
projectRoot,
|
|
95
|
+
projectRoot: installDir,
|
|
95
96
|
liveRoot
|
|
96
97
|
});
|
|
97
98
|
const peerReadinessProbe = new PeerReadinessProbe({ liveRoot });
|
|
98
|
-
const embeddingService = new EmbeddingService({ projectRoot });
|
|
99
|
+
const embeddingService = new EmbeddingService({ projectRoot: installDir });
|
|
99
100
|
const embeddingIndex = new EmbeddingIndex({
|
|
100
|
-
rootDir: path.join(
|
|
101
|
+
rootDir: path.join(installDir, "state", "memory"),
|
|
101
102
|
embeddingService
|
|
102
103
|
});
|
|
103
104
|
|
|
@@ -465,7 +466,7 @@ async function deliverNotificationFile(mode = "shadow", notificationFilePath = n
|
|
|
465
466
|
}
|
|
466
467
|
const resolvedPath = path.isAbsolute(notificationFilePath)
|
|
467
468
|
? notificationFilePath
|
|
468
|
-
: path.resolve(
|
|
469
|
+
: path.resolve(installDir, notificationFilePath);
|
|
469
470
|
const result = await deliveryManager.deliverPending({
|
|
470
471
|
mode,
|
|
471
472
|
limit: 1,
|
|
@@ -506,7 +507,7 @@ async function chooseHandoffPeer(notificationFilePath, peerId, deliveryProfile =
|
|
|
506
507
|
}
|
|
507
508
|
const resolvedPath = path.isAbsolute(notificationFilePath)
|
|
508
509
|
? notificationFilePath
|
|
509
|
-
: path.resolve(
|
|
510
|
+
: path.resolve(installDir, notificationFilePath);
|
|
510
511
|
const result = await deliveryManager.chooseHandoffPeer(resolvedPath, peerId, {
|
|
511
512
|
deliveryProfile
|
|
512
513
|
});
|
|
@@ -519,7 +520,7 @@ async function chooseTopHandoffPeer(notificationFilePath, deliveryProfile = null
|
|
|
519
520
|
}
|
|
520
521
|
const resolvedPath = path.isAbsolute(notificationFilePath)
|
|
521
522
|
? notificationFilePath
|
|
522
|
-
: path.resolve(
|
|
523
|
+
: path.resolve(installDir, notificationFilePath);
|
|
523
524
|
const result = await deliveryManager.chooseTopSuggestedPeer(resolvedPath, {
|
|
524
525
|
deliveryProfile
|
|
525
526
|
});
|
|
@@ -530,7 +531,7 @@ async function serveTransport(port = "4318") {
|
|
|
530
531
|
const authToken = process.env.NEMORIS_TRANSPORT_TOKEN || null;
|
|
531
532
|
const runtime = await scheduler.loadRuntime();
|
|
532
533
|
const server = new StandaloneTransportServer({
|
|
533
|
-
stateRoot: path.join(
|
|
534
|
+
stateRoot: path.join(installDir, "state"),
|
|
534
535
|
authToken,
|
|
535
536
|
retention: runtime.runtime?.retention?.transportInbox || {},
|
|
536
537
|
requestTimeoutMs: runtime.runtime?.shutdown?.transportShutdownTimeoutMs || 5000
|
|
@@ -1383,7 +1384,7 @@ async function serveDaemon(mode = "dry-run", intervalMs = "30000", installDir =
|
|
|
1383
1384
|
|
|
1384
1385
|
async function pruneState(scope = "all") {
|
|
1385
1386
|
const runtime = await scheduler.loadRuntime();
|
|
1386
|
-
const statePath = path.join(
|
|
1387
|
+
const statePath = path.join(installDir, "state");
|
|
1387
1388
|
const operations = [];
|
|
1388
1389
|
|
|
1389
1390
|
if (scope === "all" || scope === "runs") {
|
|
@@ -1428,7 +1429,7 @@ async function pruneState(scope = "all") {
|
|
|
1428
1429
|
|
|
1429
1430
|
async function reviewInbox(limit = "10") {
|
|
1430
1431
|
const server = new StandaloneTransportServer({
|
|
1431
|
-
stateRoot: path.join(
|
|
1432
|
+
stateRoot: path.join(installDir, "state")
|
|
1432
1433
|
});
|
|
1433
1434
|
const items = await server.listInbox(Number(limit) || 10);
|
|
1434
1435
|
console.log(JSON.stringify(items, null, 2));
|
|
@@ -1606,7 +1607,7 @@ async function reportFallbackReadiness(jobId = "workspace-health") {
|
|
|
1606
1607
|
|
|
1607
1608
|
async function configValidate() {
|
|
1608
1609
|
const config = await scheduler.loadRuntime();
|
|
1609
|
-
const schemaResult = validateAllConfigs(config, path.join(
|
|
1610
|
+
const schemaResult = validateAllConfigs(config, path.join(installDir, "config"));
|
|
1610
1611
|
console.log(
|
|
1611
1612
|
JSON.stringify(
|
|
1612
1613
|
{
|
|
@@ -2246,7 +2247,7 @@ async function runtimeStatus(jsonFlag = false) {
|
|
|
2246
2247
|
|
|
2247
2248
|
async function mcpList() {
|
|
2248
2249
|
const { ConfigLoader } = await import("./config/loader.js");
|
|
2249
|
-
const loader = new ConfigLoader({ rootDir: path.join(
|
|
2250
|
+
const loader = new ConfigLoader({ rootDir: path.join(installDir, "config") });
|
|
2250
2251
|
const mcp = await loader.loadMcp();
|
|
2251
2252
|
|
|
2252
2253
|
if (!mcp.servers || Object.keys(mcp.servers).length === 0) {
|
|
@@ -2283,9 +2284,9 @@ async function listTools() {
|
|
|
2283
2284
|
const { ToolRegistry } = await import("./tools/registry.js");
|
|
2284
2285
|
const { registerMicroToolHandlers } = await import("./tools/micro/index.js");
|
|
2285
2286
|
const registry = new ToolRegistry();
|
|
2286
|
-
registerMicroToolHandlers(registry, { workspaceRoot:
|
|
2287
|
+
registerMicroToolHandlers(registry, { workspaceRoot: installDir });
|
|
2287
2288
|
try {
|
|
2288
|
-
const toolsDir = path.join(
|
|
2289
|
+
const toolsDir = path.join(installDir, "config", "tools");
|
|
2289
2290
|
await registry.loadTools(toolsDir);
|
|
2290
2291
|
} catch { /* no tools dir is fine */ }
|
|
2291
2292
|
console.log("Configured tools:\n");
|
|
@@ -2306,7 +2307,7 @@ async function addTool(toolId) {
|
|
|
2306
2307
|
process.exitCode = 1;
|
|
2307
2308
|
return;
|
|
2308
2309
|
}
|
|
2309
|
-
const toolsDir = path.join(
|
|
2310
|
+
const toolsDir = path.join(installDir, "config", "tools");
|
|
2310
2311
|
await mkdirAsync(toolsDir, { recursive: true });
|
|
2311
2312
|
const lines = [
|
|
2312
2313
|
`[tool]`,
|
|
@@ -2336,7 +2337,7 @@ async function addTool(toolId) {
|
|
|
2336
2337
|
async function listSkills() {
|
|
2337
2338
|
const { SkillsLoader } = await import("./skills/loader.js");
|
|
2338
2339
|
const loader = new SkillsLoader();
|
|
2339
|
-
const skillsDir = path.join(
|
|
2340
|
+
const skillsDir = path.join(installDir, "config", "skills");
|
|
2340
2341
|
await loader.loadSkills(skillsDir);
|
|
2341
2342
|
const all = loader.listAll();
|
|
2342
2343
|
if (all.length === 0) {
|
|
@@ -2353,8 +2354,8 @@ async function listSkills() {
|
|
|
2353
2354
|
async function listImprovements() {
|
|
2354
2355
|
const { readdir: readdirAsync } = await import("node:fs/promises");
|
|
2355
2356
|
const { ImprovementEngine } = await import("./runtime/improvement-engine.js");
|
|
2356
|
-
const engine = new ImprovementEngine({ stateRoot: path.join(
|
|
2357
|
-
const tuningsRoot = path.join(
|
|
2357
|
+
const engine = new ImprovementEngine({ stateRoot: path.join(installDir, "state") });
|
|
2358
|
+
const tuningsRoot = path.join(installDir, "state", "tunings");
|
|
2358
2359
|
try {
|
|
2359
2360
|
const jobDirs = await readdirAsync(tuningsRoot);
|
|
2360
2361
|
let found = false;
|
|
@@ -2557,7 +2558,7 @@ export async function main(argv = process.argv) {
|
|
|
2557
2558
|
const { runMigration } = await import("./runtime/migration.js");
|
|
2558
2559
|
const dryRun = rest.includes("--dry-run");
|
|
2559
2560
|
const liveRoot = process.env.NEMORIS_LIVE_ROOT || path.join(process.env.HOME || os.homedir(), ".openclaw");
|
|
2560
|
-
const result = await runMigration({ installDir
|
|
2561
|
+
const result = await runMigration({ installDir, liveRoot, dryRun });
|
|
2561
2562
|
console.log(JSON.stringify(result, null, 2));
|
|
2562
2563
|
return 0;
|
|
2563
2564
|
} else if (command === "review-inbox") {
|
|
@@ -20,7 +20,7 @@ function defaultSearchPaths() {
|
|
|
20
20
|
const installDir = resolveInstallDir();
|
|
21
21
|
return [
|
|
22
22
|
path.join(installDir, ".env"),
|
|
23
|
-
path.join(os.homedir(), ".nemoris", ".env"),
|
|
23
|
+
path.join(os.homedir(), ".nemoris-data", ".env"),
|
|
24
24
|
path.join(os.homedir(), ".openclaw", ".env"),
|
|
25
25
|
];
|
|
26
26
|
}
|
package/src/tui/socket-client.js
CHANGED
|
@@ -7,7 +7,7 @@ export function resolveSocketPath({ platform = process.platform, stateDir, homed
|
|
|
7
7
|
if (platform === "win32") {
|
|
8
8
|
return "\\\\.\\pipe\\nemoris-daemon";
|
|
9
9
|
}
|
|
10
|
-
const root = stateDir || path.join(homedir(), ".nemoris", "state");
|
|
10
|
+
const root = stateDir || path.join(homedir(), ".nemoris-data", "state");
|
|
11
11
|
return path.join(root, "daemon.sock");
|
|
12
12
|
}
|
|
13
13
|
|