nemoris 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +49 -49
- package/LICENSE +21 -21
- package/README.md +209 -209
- package/SECURITY.md +59 -119
- package/bin/nemoris +46 -46
- package/config/agents/agent.toml.example +28 -28
- package/config/agents/content.toml +23 -0
- package/config/agents/default.toml +22 -22
- package/config/agents/heartbeat.toml +35 -0
- package/config/agents/iris.toml +23 -0
- package/config/agents/lab.toml +23 -0
- package/config/agents/main.toml +45 -0
- package/config/agents/nemo.toml +21 -0
- package/config/agents/ops.toml +38 -0
- package/config/agents/orchestrator.toml +18 -18
- package/config/agents/revenue.toml +23 -0
- package/config/agents/testyboo.toml +19 -0
- package/config/delivery.toml +73 -73
- package/config/embeddings.toml +5 -5
- package/config/identity/content-purpose.md +11 -0
- package/config/identity/content-soul.md +45 -0
- package/config/identity/default-purpose.md +1 -1
- package/config/identity/default-soul.md +3 -3
- package/config/identity/heartbeat-purpose.md +9 -0
- package/config/identity/heartbeat-soul.md +16 -0
- package/config/identity/iris-purpose.md +17 -0
- package/config/identity/iris-soul.md +68 -0
- package/config/identity/lab-purpose.md +10 -0
- package/config/identity/lab-soul.md +38 -0
- package/config/identity/main-purpose.md +17 -0
- package/config/identity/main-soul.md +66 -0
- package/config/identity/main-user.md +22 -0
- package/config/identity/ops-purpose.md +9 -0
- package/config/identity/ops-soul.md +16 -0
- package/config/identity/orchestrator-purpose.md +1 -1
- package/config/identity/orchestrator-soul.md +1 -1
- package/config/identity/revenue-purpose.md +9 -0
- package/config/identity/revenue-soul.md +41 -0
- package/config/identity/testyboo-purpose.md +13 -0
- package/config/identity/testyboo-soul.md +20 -0
- package/config/improvement-targets.toml +15 -15
- package/config/jobs/heartbeat-check.toml +30 -30
- package/config/jobs/memory-rollup.toml +46 -46
- package/config/jobs/workspace-health.toml +63 -63
- package/config/mcp.toml +16 -16
- package/config/output-contracts.toml +17 -17
- package/config/peers.toml +32 -32
- package/config/peers.toml.example +32 -32
- package/config/policies/memory-default.toml +10 -10
- package/config/policies/memory-heartbeat.toml +5 -5
- package/config/policies/memory-ops.toml +10 -10
- package/config/policies/tools-heartbeat-minimal.toml +8 -8
- package/config/policies/tools-interactive-safe.toml +8 -8
- package/config/policies/tools-ops-bounded.toml +8 -8
- package/config/policies/tools-orchestrator.toml +7 -7
- package/config/providers/anthropic.toml +15 -15
- package/config/providers/ollama.toml +5 -5
- package/config/providers/openai-codex.toml +9 -9
- package/config/providers/openrouter.toml +5 -5
- package/config/router.toml +22 -22
- package/config/runtime.toml +114 -114
- package/config/skills/self-improvement.toml +15 -15
- package/config/skills/telegram-onboarding-spec.md +240 -240
- package/config/skills/workspace-monitor.toml +15 -15
- package/config/task-router.toml +42 -42
- package/install.sh +50 -50
- package/package.json +91 -90
- package/src/auth/auth-profiles.js +169 -169
- package/src/auth/openai-codex-oauth.js +285 -285
- package/src/battle.js +449 -449
- package/src/cli/help.js +265 -265
- package/src/cli/output-filter.js +49 -49
- package/src/cli/runtime-control.js +704 -704
- package/src/cli-main.js +2763 -2763
- package/src/cli.js +78 -78
- package/src/config/loader.js +332 -332
- package/src/config/schema-validator.js +214 -214
- package/src/config/toml-lite.js +8 -8
- package/src/daemon/action-handlers.js +71 -71
- package/src/daemon/healing-tick.js +87 -87
- package/src/daemon/health-probes.js +90 -90
- package/src/daemon/notifier.js +57 -57
- package/src/daemon/nurse.js +218 -218
- package/src/daemon/repair-log.js +106 -106
- package/src/daemon/rule-staging.js +90 -90
- package/src/daemon/rules.js +29 -29
- package/src/daemon/telegram-commands.js +54 -54
- package/src/daemon/updater.js +85 -85
- package/src/jobs/job-runner.js +78 -78
- package/src/mcp/consumer.js +129 -129
- package/src/memory/active-recall.js +171 -171
- package/src/memory/backend-manager.js +97 -97
- package/src/memory/backends/file-backend.js +38 -38
- package/src/memory/backends/qmd-backend.js +219 -219
- package/src/memory/embedding-guards.js +24 -24
- package/src/memory/embedding-index.js +118 -118
- package/src/memory/embedding-service.js +179 -179
- package/src/memory/file-index.js +177 -177
- package/src/memory/memory-signature.js +5 -5
- package/src/memory/memory-store.js +648 -648
- package/src/memory/retrieval-planner.js +66 -66
- package/src/memory/scoring.js +145 -145
- package/src/memory/simhash.js +78 -78
- package/src/memory/sqlite-active-store.js +824 -824
- package/src/memory/write-policy.js +36 -36
- package/src/onboarding/aliases.js +33 -33
- package/src/onboarding/auth/api-key.js +224 -224
- package/src/onboarding/auth/ollama-detect.js +42 -42
- package/src/onboarding/clack-prompter.js +77 -77
- package/src/onboarding/doctor.js +530 -530
- package/src/onboarding/lock.js +42 -42
- package/src/onboarding/model-catalog.js +344 -344
- package/src/onboarding/phases/auth.js +576 -589
- package/src/onboarding/phases/build.js +130 -130
- package/src/onboarding/phases/choose.js +82 -82
- package/src/onboarding/phases/detect.js +98 -98
- package/src/onboarding/phases/hatch.js +216 -216
- package/src/onboarding/phases/identity.js +79 -79
- package/src/onboarding/phases/ollama.js +345 -345
- package/src/onboarding/phases/scaffold.js +99 -99
- package/src/onboarding/phases/telegram.js +377 -377
- package/src/onboarding/phases/validate.js +204 -204
- package/src/onboarding/phases/verify.js +206 -206
- package/src/onboarding/platform.js +482 -482
- package/src/onboarding/status-bar.js +95 -95
- package/src/onboarding/templates.js +794 -794
- package/src/onboarding/toml-writer.js +38 -38
- package/src/onboarding/tui.js +250 -250
- package/src/onboarding/uninstall.js +153 -153
- package/src/onboarding/wizard.js +516 -499
- package/src/providers/anthropic.js +168 -168
- package/src/providers/base.js +247 -247
- package/src/providers/circuit-breaker.js +136 -136
- package/src/providers/ollama.js +163 -163
- package/src/providers/openai-codex.js +149 -149
- package/src/providers/openrouter.js +136 -136
- package/src/providers/registry.js +36 -36
- package/src/providers/router.js +16 -16
- package/src/runtime/bootstrap-cache.js +47 -47
- package/src/runtime/capabilities-prompt.js +25 -25
- package/src/runtime/completion-ping.js +99 -99
- package/src/runtime/config-validator.js +121 -121
- package/src/runtime/context-ledger.js +360 -360
- package/src/runtime/cutover-readiness.js +42 -42
- package/src/runtime/daemon.js +729 -729
- package/src/runtime/delivery-ack.js +195 -195
- package/src/runtime/delivery-adapters/local-file.js +41 -41
- package/src/runtime/delivery-adapters/openclaw-cli.js +94 -94
- package/src/runtime/delivery-adapters/openclaw-peer.js +98 -98
- package/src/runtime/delivery-adapters/shadow.js +13 -13
- package/src/runtime/delivery-adapters/standalone-http.js +98 -98
- package/src/runtime/delivery-adapters/telegram.js +104 -104
- package/src/runtime/delivery-adapters/tui.js +128 -128
- package/src/runtime/delivery-manager.js +807 -807
- package/src/runtime/delivery-store.js +168 -168
- package/src/runtime/dependency-health.js +118 -118
- package/src/runtime/envelope.js +114 -114
- package/src/runtime/evaluation.js +1089 -1089
- package/src/runtime/exec-approvals.js +216 -216
- package/src/runtime/executor.js +500 -500
- package/src/runtime/failure-ping.js +67 -67
- package/src/runtime/flows.js +83 -83
- package/src/runtime/guards.js +45 -45
- package/src/runtime/handoff.js +51 -51
- package/src/runtime/identity-cache.js +28 -28
- package/src/runtime/improvement-engine.js +109 -109
- package/src/runtime/improvement-harness.js +581 -581
- package/src/runtime/input-sanitiser.js +72 -72
- package/src/runtime/interaction-contract.js +347 -347
- package/src/runtime/lane-readiness.js +226 -226
- package/src/runtime/migration.js +323 -323
- package/src/runtime/model-resolution.js +78 -78
- package/src/runtime/network.js +64 -64
- package/src/runtime/notification-store.js +97 -97
- package/src/runtime/notifier.js +256 -256
- package/src/runtime/orchestrator.js +53 -53
- package/src/runtime/orphan-reaper.js +41 -41
- package/src/runtime/output-contract-schema.js +139 -139
- package/src/runtime/output-contract-validator.js +439 -439
- package/src/runtime/peer-readiness.js +69 -69
- package/src/runtime/peer-registry.js +133 -133
- package/src/runtime/pilot-status.js +108 -108
- package/src/runtime/prompt-builder.js +261 -261
- package/src/runtime/provider-attempt.js +582 -582
- package/src/runtime/report-fallback.js +71 -71
- package/src/runtime/result-normalizer.js +183 -183
- package/src/runtime/retention.js +74 -74
- package/src/runtime/review.js +244 -244
- package/src/runtime/route-job.js +15 -15
- package/src/runtime/run-store.js +38 -38
- package/src/runtime/schedule.js +88 -88
- package/src/runtime/scheduler-state.js +434 -434
- package/src/runtime/scheduler.js +656 -656
- package/src/runtime/session-compactor.js +182 -182
- package/src/runtime/session-search.js +155 -155
- package/src/runtime/slack-inbound.js +249 -249
- package/src/runtime/ssrf.js +102 -102
- package/src/runtime/status-aggregator.js +330 -330
- package/src/runtime/task-contract.js +140 -140
- package/src/runtime/task-packet.js +107 -107
- package/src/runtime/task-router.js +140 -140
- package/src/runtime/telegram-inbound.js +1565 -1565
- package/src/runtime/token-counter.js +134 -134
- package/src/runtime/token-estimator.js +59 -59
- package/src/runtime/tool-loop.js +200 -200
- package/src/runtime/transport-server.js +311 -311
- package/src/runtime/tui-server.js +411 -411
- package/src/runtime/ulid.js +44 -44
- package/src/security/ssrf-check.js +197 -197
- package/src/setup.js +369 -369
- package/src/shadow/bridge.js +303 -303
- package/src/skills/loader.js +84 -84
- package/src/tools/catalog.json +49 -49
- package/src/tools/cli-delegate.js +44 -44
- package/src/tools/mcp-client.js +106 -106
- package/src/tools/micro/cancel-task.js +6 -6
- package/src/tools/micro/complete-task.js +6 -6
- package/src/tools/micro/fail-task.js +6 -6
- package/src/tools/micro/http-fetch.js +74 -74
- package/src/tools/micro/index.js +36 -36
- package/src/tools/micro/lcm-recall.js +60 -60
- package/src/tools/micro/list-dir.js +17 -17
- package/src/tools/micro/list-skills.js +46 -46
- package/src/tools/micro/load-skill.js +38 -38
- package/src/tools/micro/memory-search.js +45 -45
- package/src/tools/micro/read-file.js +11 -11
- package/src/tools/micro/session-search.js +54 -54
- package/src/tools/micro/shell-exec.js +43 -43
- package/src/tools/micro/trigger-job.js +79 -79
- package/src/tools/micro/web-search.js +58 -58
- package/src/tools/micro/workspace-paths.js +39 -39
- package/src/tools/micro/write-file.js +14 -14
- package/src/tools/micro/write-memory.js +41 -41
- package/src/tools/registry.js +348 -348
- package/src/tools/tool-result-contract.js +36 -36
- package/src/tui/chat.js +835 -835
- package/src/tui/renderer.js +175 -175
- package/src/tui/socket-client.js +217 -217
- package/src/utils/canonical-json.js +29 -29
- package/src/utils/compaction.js +30 -30
- package/src/utils/env-loader.js +5 -5
- package/src/utils/errors.js +80 -80
- package/src/utils/fs.js +101 -101
- package/src/utils/ids.js +5 -5
- package/src/utils/model-context-limits.js +30 -30
- package/src/utils/token-budget.js +74 -74
- package/src/utils/usage-cost.js +25 -25
- package/src/utils/usage-metrics.js +14 -14
|
@@ -1,206 +1,206 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { validateScaffold } from "./validate.js";
|
|
4
|
-
import { sendHatchMessage } from "./telegram.js";
|
|
5
|
-
import { writeDaemonUnit, loadDaemon } from "../platform.js";
|
|
6
|
-
import { green, yellow, dim, cyan, treeItem, sectionHeader, confirm, bold } from "../tui.js";
|
|
7
|
-
|
|
8
|
-
export function getCommandsWorthKnowing({ telegramConfigured = false } = {}) {
|
|
9
|
-
const commands = [
|
|
10
|
-
["nemoris status", "see what your agent is doing"],
|
|
11
|
-
["nemoris doctor", "run a health check"],
|
|
12
|
-
["nemoris logs", "watch live daemon output"],
|
|
13
|
-
];
|
|
14
|
-
if (telegramConfigured) {
|
|
15
|
-
commands.push(["/help", "show commands in Telegram"]);
|
|
16
|
-
}
|
|
17
|
-
return commands;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Verify phase — dry-run health check + "what's next" output.
|
|
22
|
-
* Replaces the old hatch phase egg animation.
|
|
23
|
-
*
|
|
24
|
-
* In non-interactive mode, returns JSON summary.
|
|
25
|
-
*/
|
|
26
|
-
export async function verify({
|
|
27
|
-
installDir,
|
|
28
|
-
agentName,
|
|
29
|
-
userName,
|
|
30
|
-
agentId,
|
|
31
|
-
mode,
|
|
32
|
-
providers = [],
|
|
33
|
-
providerFlags: _providerFlags = {},
|
|
34
|
-
nonInteractive = false,
|
|
35
|
-
skipHealthcheck = false,
|
|
36
|
-
importStats = null,
|
|
37
|
-
telegramConfigured = false,
|
|
38
|
-
telegramVerified = false,
|
|
39
|
-
telegramBotUsername = null,
|
|
40
|
-
telegramBotToken = null,
|
|
41
|
-
telegramOperatorChatId = null,
|
|
42
|
-
userGoal = "",
|
|
43
|
-
}) {
|
|
44
|
-
const result = {
|
|
45
|
-
status: "ok",
|
|
46
|
-
mode,
|
|
47
|
-
agent: agentId,
|
|
48
|
-
provider: providers[0] || "none",
|
|
49
|
-
...(mode === "shadow" && importStats ? { imported: importStats } : {}),
|
|
50
|
-
healthcheck: "skip",
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
// Run validation / health check
|
|
54
|
-
if (!skipHealthcheck) {
|
|
55
|
-
try {
|
|
56
|
-
const validation = await validateScaffold(installDir);
|
|
57
|
-
result.healthcheck = validation.configValid ? "pass" : "fail";
|
|
58
|
-
if (!validation.configValid) {
|
|
59
|
-
result.status = "warning";
|
|
60
|
-
result.errors = validation.errors;
|
|
61
|
-
}
|
|
62
|
-
} catch {
|
|
63
|
-
result.healthcheck = "fail";
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Non-interactive: return JSON
|
|
68
|
-
if (nonInteractive) {
|
|
69
|
-
if (!process.env.NEMORIS_QUIET) {
|
|
70
|
-
console.log(JSON.stringify(result));
|
|
71
|
-
}
|
|
72
|
-
return result;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Interactive: structured output
|
|
76
|
-
console.log(`\n${sectionHeader("First Run (dry)")}`);
|
|
77
|
-
console.log(treeItem("provider", providers[0] || "none"));
|
|
78
|
-
if (mode === "shadow" && importStats) {
|
|
79
|
-
console.log(treeItem("memory", `${importStats.memory} entries loaded`));
|
|
80
|
-
} else {
|
|
81
|
-
console.log(treeItem("memory", "empty · first run"));
|
|
82
|
-
}
|
|
83
|
-
console.log(treeItem("contract", "HealthCheck"));
|
|
84
|
-
|
|
85
|
-
if (result.healthcheck === "pass") {
|
|
86
|
-
const suffix = mode === "shadow" ? `${agentName} is home` : "your agent is alive";
|
|
87
|
-
console.log(` ${green("✓")} healthy — ${suffix}`);
|
|
88
|
-
} else if (result.healthcheck === "skip") {
|
|
89
|
-
console.log(` ${dim("⊘")} health check skipped`);
|
|
90
|
-
} else {
|
|
91
|
-
console.log(` ${dim("!")} health check had issues (run nemoris doctor)`);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Telegram status
|
|
95
|
-
if (telegramConfigured && telegramVerified) {
|
|
96
|
-
console.log(treeItem("telegram", `connected · @${telegramBotUsername || "bot"}`, "pass"));
|
|
97
|
-
} else if (telegramConfigured && !telegramVerified) {
|
|
98
|
-
console.log(` ${yellow("!")} Telegram configured but not verified — run ${cyan("nemoris setup telegram")} to test`);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
console.log(`\n ${green("✓")} Nemoris is ready`);
|
|
102
|
-
|
|
103
|
-
// Auto-start daemon
|
|
104
|
-
let daemonStarted = false;
|
|
105
|
-
let hatchSent = false;
|
|
106
|
-
let unitWritten = false;
|
|
107
|
-
|
|
108
|
-
try {
|
|
109
|
-
const unitResult = await writeDaemonUnit(installDir);
|
|
110
|
-
unitWritten = unitResult.ok;
|
|
111
|
-
} catch (err) {
|
|
112
|
-
console.log(` ${yellow("!")} Couldn't write daemon unit: ${err.message}`);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (unitWritten) {
|
|
116
|
-
const start = await confirm("Start your agent now?", true);
|
|
117
|
-
if (start) {
|
|
118
|
-
const loadResult = await loadDaemon(installDir);
|
|
119
|
-
if (loadResult.ok) {
|
|
120
|
-
daemonStarted = true;
|
|
121
|
-
|
|
122
|
-
// Send hatch message to Telegram
|
|
123
|
-
if (telegramConfigured && telegramVerified && telegramOperatorChatId && telegramBotToken) {
|
|
124
|
-
try {
|
|
125
|
-
// Load identity content + provider config for AI-generated greeting
|
|
126
|
-
let soulContent = "";
|
|
127
|
-
let purposeContent = "";
|
|
128
|
-
let providerConfig = null;
|
|
129
|
-
|
|
130
|
-
try {
|
|
131
|
-
const effectiveId = agentId || agentName.toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
132
|
-
const identityDir = path.join(installDir, "config", "identity");
|
|
133
|
-
soulContent = fs.readFileSync(path.join(identityDir, `${effectiveId}-soul.md`), "utf8");
|
|
134
|
-
purposeContent = fs.readFileSync(path.join(identityDir, `${effectiveId}-purpose.md`), "utf8");
|
|
135
|
-
} catch {
|
|
136
|
-
// Identity files may not exist yet — use defaults
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (providers.length > 0) {
|
|
140
|
-
try {
|
|
141
|
-
const { ConfigLoader } = await import("../../config/loader.js");
|
|
142
|
-
const loader = new ConfigLoader({ rootDir: path.join(installDir, "config") });
|
|
143
|
-
const providerMap = await loader.loadProviders();
|
|
144
|
-
providerConfig = providerMap[providers[0]] || null;
|
|
145
|
-
} catch {
|
|
146
|
-
// Provider config may not be loadable — fall back to static greeting
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// Detect migrated vs fresh: shadow mode or existing memory = migrated agent
|
|
151
|
-
const isMigrated = mode === "shadow" || (importStats && importStats.memory > 0);
|
|
152
|
-
|
|
153
|
-
const hatched = await sendHatchMessage({
|
|
154
|
-
token: telegramBotToken,
|
|
155
|
-
chatId: telegramOperatorChatId,
|
|
156
|
-
agentName,
|
|
157
|
-
userName,
|
|
158
|
-
installDir,
|
|
159
|
-
agentId,
|
|
160
|
-
userGoal,
|
|
161
|
-
soulContent,
|
|
162
|
-
purposeContent,
|
|
163
|
-
providerConfig,
|
|
164
|
-
migrated: isMigrated,
|
|
165
|
-
});
|
|
166
|
-
if (hatched) {
|
|
167
|
-
hatchSent = true;
|
|
168
|
-
}
|
|
169
|
-
} catch {
|
|
170
|
-
// best-effort, don't fail setup if this errors
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
} else {
|
|
174
|
-
console.log(` ${yellow("!")} ${loadResult.message || "Couldn't auto-start"} — run ${cyan("nemoris start")} manually`);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// Final Output
|
|
180
|
-
console.log(`\n ${dim("──────────────────────────────────────────────")}`);
|
|
181
|
-
console.log(` ${bold("Your agent is live.")}\n`);
|
|
182
|
-
|
|
183
|
-
if (daemonStarted) {
|
|
184
|
-
console.log(` ${green("✓")} Daemon running in the background`);
|
|
185
|
-
} else {
|
|
186
|
-
console.log(` ${yellow("!")} Run ${cyan("nemoris start")} to bring your agent online`);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
if (hatchSent && telegramBotUsername) {
|
|
190
|
-
console.log(` ${green("✓")} First message sent to @${telegramBotUsername} — check your phone`);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
if (daemonStarted) {
|
|
194
|
-
console.log(`\n When you're done here, your agent is waiting in Telegram.`);
|
|
195
|
-
}
|
|
196
|
-
console.log(` ${dim("──────────────────────────────────────────────")}`);
|
|
197
|
-
|
|
198
|
-
console.log(`\n ${bold("Commands worth knowing:")}`);
|
|
199
|
-
for (const [command, description] of getCommandsWorthKnowing({ telegramConfigured })) {
|
|
200
|
-
console.log(` ${command.padEnd(19)} ${description}`);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
console.log(`\n ${dim("docs: https://github.com/amzer24/nemoris#readme")}\n`);
|
|
204
|
-
|
|
205
|
-
return result;
|
|
206
|
-
}
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { validateScaffold } from "./validate.js";
|
|
4
|
+
import { sendHatchMessage } from "./telegram.js";
|
|
5
|
+
import { writeDaemonUnit, loadDaemon } from "../platform.js";
|
|
6
|
+
import { green, yellow, dim, cyan, treeItem, sectionHeader, confirm, bold } from "../tui.js";
|
|
7
|
+
|
|
8
|
+
export function getCommandsWorthKnowing({ telegramConfigured = false } = {}) {
|
|
9
|
+
const commands = [
|
|
10
|
+
["nemoris status", "see what your agent is doing"],
|
|
11
|
+
["nemoris doctor", "run a health check"],
|
|
12
|
+
["nemoris logs", "watch live daemon output"],
|
|
13
|
+
];
|
|
14
|
+
if (telegramConfigured) {
|
|
15
|
+
commands.push(["/help", "show commands in Telegram"]);
|
|
16
|
+
}
|
|
17
|
+
return commands;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Verify phase — dry-run health check + "what's next" output.
|
|
22
|
+
* Replaces the old hatch phase egg animation.
|
|
23
|
+
*
|
|
24
|
+
* In non-interactive mode, returns JSON summary.
|
|
25
|
+
*/
|
|
26
|
+
export async function verify({
|
|
27
|
+
installDir,
|
|
28
|
+
agentName,
|
|
29
|
+
userName,
|
|
30
|
+
agentId,
|
|
31
|
+
mode,
|
|
32
|
+
providers = [],
|
|
33
|
+
providerFlags: _providerFlags = {},
|
|
34
|
+
nonInteractive = false,
|
|
35
|
+
skipHealthcheck = false,
|
|
36
|
+
importStats = null,
|
|
37
|
+
telegramConfigured = false,
|
|
38
|
+
telegramVerified = false,
|
|
39
|
+
telegramBotUsername = null,
|
|
40
|
+
telegramBotToken = null,
|
|
41
|
+
telegramOperatorChatId = null,
|
|
42
|
+
userGoal = "",
|
|
43
|
+
}) {
|
|
44
|
+
const result = {
|
|
45
|
+
status: "ok",
|
|
46
|
+
mode,
|
|
47
|
+
agent: agentId,
|
|
48
|
+
provider: providers[0] || "none",
|
|
49
|
+
...(mode === "shadow" && importStats ? { imported: importStats } : {}),
|
|
50
|
+
healthcheck: "skip",
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// Run validation / health check
|
|
54
|
+
if (!skipHealthcheck) {
|
|
55
|
+
try {
|
|
56
|
+
const validation = await validateScaffold(installDir);
|
|
57
|
+
result.healthcheck = validation.configValid ? "pass" : "fail";
|
|
58
|
+
if (!validation.configValid) {
|
|
59
|
+
result.status = "warning";
|
|
60
|
+
result.errors = validation.errors;
|
|
61
|
+
}
|
|
62
|
+
} catch {
|
|
63
|
+
result.healthcheck = "fail";
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Non-interactive: return JSON
|
|
68
|
+
if (nonInteractive) {
|
|
69
|
+
if (!process.env.NEMORIS_QUIET) {
|
|
70
|
+
console.log(JSON.stringify(result));
|
|
71
|
+
}
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Interactive: structured output
|
|
76
|
+
console.log(`\n${sectionHeader("First Run (dry)")}`);
|
|
77
|
+
console.log(treeItem("provider", providers[0] || "none"));
|
|
78
|
+
if (mode === "shadow" && importStats) {
|
|
79
|
+
console.log(treeItem("memory", `${importStats.memory} entries loaded`));
|
|
80
|
+
} else {
|
|
81
|
+
console.log(treeItem("memory", "empty · first run"));
|
|
82
|
+
}
|
|
83
|
+
console.log(treeItem("contract", "HealthCheck"));
|
|
84
|
+
|
|
85
|
+
if (result.healthcheck === "pass") {
|
|
86
|
+
const suffix = mode === "shadow" ? `${agentName} is home` : "your agent is alive";
|
|
87
|
+
console.log(` ${green("✓")} healthy — ${suffix}`);
|
|
88
|
+
} else if (result.healthcheck === "skip") {
|
|
89
|
+
console.log(` ${dim("⊘")} health check skipped`);
|
|
90
|
+
} else {
|
|
91
|
+
console.log(` ${dim("!")} health check had issues (run nemoris doctor)`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Telegram status
|
|
95
|
+
if (telegramConfigured && telegramVerified) {
|
|
96
|
+
console.log(treeItem("telegram", `connected · @${telegramBotUsername || "bot"}`, "pass"));
|
|
97
|
+
} else if (telegramConfigured && !telegramVerified) {
|
|
98
|
+
console.log(` ${yellow("!")} Telegram configured but not verified — run ${cyan("nemoris setup telegram")} to test`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
console.log(`\n ${green("✓")} Nemoris is ready`);
|
|
102
|
+
|
|
103
|
+
// Auto-start daemon
|
|
104
|
+
let daemonStarted = false;
|
|
105
|
+
let hatchSent = false;
|
|
106
|
+
let unitWritten = false;
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
const unitResult = await writeDaemonUnit(installDir);
|
|
110
|
+
unitWritten = unitResult.ok;
|
|
111
|
+
} catch (err) {
|
|
112
|
+
console.log(` ${yellow("!")} Couldn't write daemon unit: ${err.message}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (unitWritten) {
|
|
116
|
+
const start = await confirm("Start your agent now?", true);
|
|
117
|
+
if (start) {
|
|
118
|
+
const loadResult = await loadDaemon(installDir);
|
|
119
|
+
if (loadResult.ok) {
|
|
120
|
+
daemonStarted = true;
|
|
121
|
+
|
|
122
|
+
// Send hatch message to Telegram
|
|
123
|
+
if (telegramConfigured && telegramVerified && telegramOperatorChatId && telegramBotToken) {
|
|
124
|
+
try {
|
|
125
|
+
// Load identity content + provider config for AI-generated greeting
|
|
126
|
+
let soulContent = "";
|
|
127
|
+
let purposeContent = "";
|
|
128
|
+
let providerConfig = null;
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
const effectiveId = agentId || agentName.toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
132
|
+
const identityDir = path.join(installDir, "config", "identity");
|
|
133
|
+
soulContent = fs.readFileSync(path.join(identityDir, `${effectiveId}-soul.md`), "utf8");
|
|
134
|
+
purposeContent = fs.readFileSync(path.join(identityDir, `${effectiveId}-purpose.md`), "utf8");
|
|
135
|
+
} catch {
|
|
136
|
+
// Identity files may not exist yet — use defaults
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (providers.length > 0) {
|
|
140
|
+
try {
|
|
141
|
+
const { ConfigLoader } = await import("../../config/loader.js");
|
|
142
|
+
const loader = new ConfigLoader({ rootDir: path.join(installDir, "config") });
|
|
143
|
+
const providerMap = await loader.loadProviders();
|
|
144
|
+
providerConfig = providerMap[providers[0]] || null;
|
|
145
|
+
} catch {
|
|
146
|
+
// Provider config may not be loadable — fall back to static greeting
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Detect migrated vs fresh: shadow mode or existing memory = migrated agent
|
|
151
|
+
const isMigrated = mode === "shadow" || (importStats && importStats.memory > 0);
|
|
152
|
+
|
|
153
|
+
const hatched = await sendHatchMessage({
|
|
154
|
+
token: telegramBotToken,
|
|
155
|
+
chatId: telegramOperatorChatId,
|
|
156
|
+
agentName,
|
|
157
|
+
userName,
|
|
158
|
+
installDir,
|
|
159
|
+
agentId,
|
|
160
|
+
userGoal,
|
|
161
|
+
soulContent,
|
|
162
|
+
purposeContent,
|
|
163
|
+
providerConfig,
|
|
164
|
+
migrated: isMigrated,
|
|
165
|
+
});
|
|
166
|
+
if (hatched) {
|
|
167
|
+
hatchSent = true;
|
|
168
|
+
}
|
|
169
|
+
} catch {
|
|
170
|
+
// best-effort, don't fail setup if this errors
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
console.log(` ${yellow("!")} ${loadResult.message || "Couldn't auto-start"} — run ${cyan("nemoris start")} manually`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Final Output
|
|
180
|
+
console.log(`\n ${dim("──────────────────────────────────────────────")}`);
|
|
181
|
+
console.log(` ${bold("Your agent is live.")}\n`);
|
|
182
|
+
|
|
183
|
+
if (daemonStarted) {
|
|
184
|
+
console.log(` ${green("✓")} Daemon running in the background`);
|
|
185
|
+
} else {
|
|
186
|
+
console.log(` ${yellow("!")} Run ${cyan("nemoris start")} to bring your agent online`);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (hatchSent && telegramBotUsername) {
|
|
190
|
+
console.log(` ${green("✓")} First message sent to @${telegramBotUsername} — check your phone`);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (daemonStarted) {
|
|
194
|
+
console.log(`\n When you're done here, your agent is waiting in Telegram.`);
|
|
195
|
+
}
|
|
196
|
+
console.log(` ${dim("──────────────────────────────────────────────")}`);
|
|
197
|
+
|
|
198
|
+
console.log(`\n ${bold("Commands worth knowing:")}`);
|
|
199
|
+
for (const [command, description] of getCommandsWorthKnowing({ telegramConfigured })) {
|
|
200
|
+
console.log(` ${command.padEnd(19)} ${description}`);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
console.log(`\n ${dim("docs: https://github.com/amzer24/nemoris#readme")}\n`);
|
|
204
|
+
|
|
205
|
+
return result;
|
|
206
|
+
}
|