@usejarvis/brain 0.1.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/LICENSE +153 -0
- package/README.md +278 -0
- package/bin/jarvis.ts +413 -0
- package/package.json +74 -0
- package/scripts/ensure-bun.cjs +8 -0
- package/src/actions/README.md +421 -0
- package/src/actions/app-control/desktop-controller.test.ts +26 -0
- package/src/actions/app-control/desktop-controller.ts +438 -0
- package/src/actions/app-control/interface.ts +64 -0
- package/src/actions/app-control/linux.ts +273 -0
- package/src/actions/app-control/macos.ts +54 -0
- package/src/actions/app-control/sidecar-launcher.test.ts +23 -0
- package/src/actions/app-control/sidecar-launcher.ts +286 -0
- package/src/actions/app-control/windows.ts +44 -0
- package/src/actions/browser/cdp.ts +138 -0
- package/src/actions/browser/chrome-launcher.ts +252 -0
- package/src/actions/browser/session.ts +437 -0
- package/src/actions/browser/stealth.ts +49 -0
- package/src/actions/index.ts +20 -0
- package/src/actions/terminal/executor.ts +157 -0
- package/src/actions/terminal/wsl-bridge.ts +126 -0
- package/src/actions/test.ts +93 -0
- package/src/actions/tools/agents.ts +321 -0
- package/src/actions/tools/builtin.ts +846 -0
- package/src/actions/tools/commitments.ts +192 -0
- package/src/actions/tools/content.ts +217 -0
- package/src/actions/tools/delegate.ts +147 -0
- package/src/actions/tools/desktop.test.ts +55 -0
- package/src/actions/tools/desktop.ts +305 -0
- package/src/actions/tools/goals.ts +376 -0
- package/src/actions/tools/local-tools-guard.ts +20 -0
- package/src/actions/tools/registry.ts +171 -0
- package/src/actions/tools/research.ts +111 -0
- package/src/actions/tools/sidecar-list.ts +57 -0
- package/src/actions/tools/sidecar-route.ts +105 -0
- package/src/actions/tools/workflows.ts +216 -0
- package/src/agents/agent.ts +132 -0
- package/src/agents/delegation.ts +107 -0
- package/src/agents/hierarchy.ts +113 -0
- package/src/agents/index.ts +19 -0
- package/src/agents/messaging.ts +125 -0
- package/src/agents/orchestrator.ts +576 -0
- package/src/agents/role-discovery.ts +61 -0
- package/src/agents/sub-agent-runner.ts +307 -0
- package/src/agents/task-manager.ts +151 -0
- package/src/authority/approval-delivery.ts +59 -0
- package/src/authority/approval.ts +196 -0
- package/src/authority/audit.ts +158 -0
- package/src/authority/authority.test.ts +519 -0
- package/src/authority/deferred-executor.ts +103 -0
- package/src/authority/emergency.ts +66 -0
- package/src/authority/engine.ts +297 -0
- package/src/authority/index.ts +12 -0
- package/src/authority/learning.ts +111 -0
- package/src/authority/tool-action-map.ts +74 -0
- package/src/awareness/analytics.ts +466 -0
- package/src/awareness/awareness.test.ts +332 -0
- package/src/awareness/capture-engine.ts +305 -0
- package/src/awareness/context-graph.ts +130 -0
- package/src/awareness/context-tracker.ts +349 -0
- package/src/awareness/index.ts +25 -0
- package/src/awareness/intelligence.ts +321 -0
- package/src/awareness/ocr-engine.ts +88 -0
- package/src/awareness/service.ts +528 -0
- package/src/awareness/struggle-detector.ts +342 -0
- package/src/awareness/suggestion-engine.ts +476 -0
- package/src/awareness/types.ts +201 -0
- package/src/cli/autostart.ts +241 -0
- package/src/cli/deps.ts +449 -0
- package/src/cli/doctor.ts +230 -0
- package/src/cli/helpers.ts +401 -0
- package/src/cli/onboard.ts +580 -0
- package/src/comms/README.md +329 -0
- package/src/comms/auth-error.html +48 -0
- package/src/comms/channels/discord.ts +228 -0
- package/src/comms/channels/signal.ts +56 -0
- package/src/comms/channels/telegram.ts +316 -0
- package/src/comms/channels/whatsapp.ts +60 -0
- package/src/comms/channels.test.ts +173 -0
- package/src/comms/desktop-notify.ts +114 -0
- package/src/comms/example.ts +129 -0
- package/src/comms/index.ts +129 -0
- package/src/comms/streaming.ts +142 -0
- package/src/comms/voice.test.ts +152 -0
- package/src/comms/voice.ts +291 -0
- package/src/comms/websocket.test.ts +409 -0
- package/src/comms/websocket.ts +473 -0
- package/src/config/README.md +387 -0
- package/src/config/index.ts +6 -0
- package/src/config/loader.test.ts +137 -0
- package/src/config/loader.ts +142 -0
- package/src/config/types.ts +260 -0
- package/src/daemon/README.md +232 -0
- package/src/daemon/agent-service-interface.ts +9 -0
- package/src/daemon/agent-service.ts +600 -0
- package/src/daemon/api-routes.ts +2119 -0
- package/src/daemon/background-agent-service.ts +396 -0
- package/src/daemon/background-agent.test.ts +78 -0
- package/src/daemon/channel-service.ts +201 -0
- package/src/daemon/commitment-executor.ts +297 -0
- package/src/daemon/event-classifier.ts +239 -0
- package/src/daemon/event-coalescer.ts +123 -0
- package/src/daemon/event-reactor.ts +214 -0
- package/src/daemon/health.ts +220 -0
- package/src/daemon/index.ts +1004 -0
- package/src/daemon/llm-settings.ts +316 -0
- package/src/daemon/observer-service.ts +150 -0
- package/src/daemon/pid.ts +98 -0
- package/src/daemon/research-queue.ts +155 -0
- package/src/daemon/services.ts +175 -0
- package/src/daemon/ws-service.ts +788 -0
- package/src/goals/accountability.ts +240 -0
- package/src/goals/awareness-bridge.ts +185 -0
- package/src/goals/estimator.ts +185 -0
- package/src/goals/events.ts +28 -0
- package/src/goals/goals.test.ts +400 -0
- package/src/goals/integration.test.ts +329 -0
- package/src/goals/nl-builder.test.ts +220 -0
- package/src/goals/nl-builder.ts +256 -0
- package/src/goals/rhythm.test.ts +177 -0
- package/src/goals/rhythm.ts +275 -0
- package/src/goals/service.test.ts +135 -0
- package/src/goals/service.ts +348 -0
- package/src/goals/types.ts +106 -0
- package/src/goals/workflow-bridge.ts +96 -0
- package/src/integrations/google-api.ts +134 -0
- package/src/integrations/google-auth.ts +175 -0
- package/src/llm/README.md +291 -0
- package/src/llm/anthropic.ts +386 -0
- package/src/llm/gemini.ts +371 -0
- package/src/llm/index.ts +19 -0
- package/src/llm/manager.ts +153 -0
- package/src/llm/ollama.ts +307 -0
- package/src/llm/openai.ts +350 -0
- package/src/llm/provider.test.ts +231 -0
- package/src/llm/provider.ts +60 -0
- package/src/llm/test.ts +87 -0
- package/src/observers/README.md +278 -0
- package/src/observers/calendar.ts +113 -0
- package/src/observers/clipboard.ts +136 -0
- package/src/observers/email.ts +109 -0
- package/src/observers/example.ts +58 -0
- package/src/observers/file-watcher.ts +124 -0
- package/src/observers/index.ts +159 -0
- package/src/observers/notifications.ts +197 -0
- package/src/observers/observers.test.ts +203 -0
- package/src/observers/processes.ts +225 -0
- package/src/personality/README.md +61 -0
- package/src/personality/adapter.ts +196 -0
- package/src/personality/index.ts +20 -0
- package/src/personality/learner.ts +209 -0
- package/src/personality/model.ts +132 -0
- package/src/personality/personality.test.ts +236 -0
- package/src/roles/README.md +252 -0
- package/src/roles/authority.ts +119 -0
- package/src/roles/example-usage.ts +198 -0
- package/src/roles/index.ts +42 -0
- package/src/roles/loader.ts +143 -0
- package/src/roles/prompt-builder.ts +194 -0
- package/src/roles/test-multi.ts +102 -0
- package/src/roles/test-role.yaml +77 -0
- package/src/roles/test-utils.ts +93 -0
- package/src/roles/test.ts +106 -0
- package/src/roles/tool-guide.ts +190 -0
- package/src/roles/types.ts +36 -0
- package/src/roles/utils.ts +200 -0
- package/src/scripts/google-setup.ts +168 -0
- package/src/sidecar/connection.ts +179 -0
- package/src/sidecar/index.ts +6 -0
- package/src/sidecar/manager.ts +542 -0
- package/src/sidecar/protocol.ts +85 -0
- package/src/sidecar/rpc.ts +161 -0
- package/src/sidecar/scheduler.ts +136 -0
- package/src/sidecar/types.ts +112 -0
- package/src/sidecar/validator.ts +144 -0
- package/src/vault/README.md +110 -0
- package/src/vault/awareness.ts +341 -0
- package/src/vault/commitments.ts +299 -0
- package/src/vault/content-pipeline.ts +260 -0
- package/src/vault/conversations.ts +173 -0
- package/src/vault/entities.ts +180 -0
- package/src/vault/extractor.test.ts +356 -0
- package/src/vault/extractor.ts +345 -0
- package/src/vault/facts.ts +190 -0
- package/src/vault/goals.ts +477 -0
- package/src/vault/index.ts +87 -0
- package/src/vault/keychain.ts +99 -0
- package/src/vault/observations.ts +115 -0
- package/src/vault/relationships.ts +178 -0
- package/src/vault/retrieval.test.ts +126 -0
- package/src/vault/retrieval.ts +227 -0
- package/src/vault/schema.ts +658 -0
- package/src/vault/settings.ts +38 -0
- package/src/vault/vectors.ts +92 -0
- package/src/vault/workflows.ts +403 -0
- package/src/workflows/auto-suggest.ts +290 -0
- package/src/workflows/engine.ts +366 -0
- package/src/workflows/events.ts +24 -0
- package/src/workflows/executor.ts +207 -0
- package/src/workflows/nl-builder.ts +198 -0
- package/src/workflows/nodes/actions/agent-task.ts +73 -0
- package/src/workflows/nodes/actions/calendar-action.ts +85 -0
- package/src/workflows/nodes/actions/code-execution.ts +73 -0
- package/src/workflows/nodes/actions/discord.ts +77 -0
- package/src/workflows/nodes/actions/file-write.ts +73 -0
- package/src/workflows/nodes/actions/gmail.ts +69 -0
- package/src/workflows/nodes/actions/http-request.ts +117 -0
- package/src/workflows/nodes/actions/notification.ts +85 -0
- package/src/workflows/nodes/actions/run-tool.ts +55 -0
- package/src/workflows/nodes/actions/send-message.ts +82 -0
- package/src/workflows/nodes/actions/shell-command.ts +76 -0
- package/src/workflows/nodes/actions/telegram.ts +60 -0
- package/src/workflows/nodes/builtin.ts +119 -0
- package/src/workflows/nodes/error/error-handler.ts +37 -0
- package/src/workflows/nodes/error/fallback.ts +47 -0
- package/src/workflows/nodes/error/retry.ts +82 -0
- package/src/workflows/nodes/logic/delay.ts +42 -0
- package/src/workflows/nodes/logic/if-else.ts +41 -0
- package/src/workflows/nodes/logic/loop.ts +90 -0
- package/src/workflows/nodes/logic/merge.ts +38 -0
- package/src/workflows/nodes/logic/race.ts +40 -0
- package/src/workflows/nodes/logic/switch.ts +59 -0
- package/src/workflows/nodes/logic/template-render.ts +53 -0
- package/src/workflows/nodes/logic/variable-get.ts +37 -0
- package/src/workflows/nodes/logic/variable-set.ts +59 -0
- package/src/workflows/nodes/registry.ts +99 -0
- package/src/workflows/nodes/transform/aggregate.ts +99 -0
- package/src/workflows/nodes/transform/csv-parse.ts +70 -0
- package/src/workflows/nodes/transform/json-parse.ts +63 -0
- package/src/workflows/nodes/transform/map-filter.ts +84 -0
- package/src/workflows/nodes/transform/regex-match.ts +89 -0
- package/src/workflows/nodes/triggers/calendar.ts +33 -0
- package/src/workflows/nodes/triggers/clipboard.ts +32 -0
- package/src/workflows/nodes/triggers/cron.ts +40 -0
- package/src/workflows/nodes/triggers/email.ts +40 -0
- package/src/workflows/nodes/triggers/file-change.ts +45 -0
- package/src/workflows/nodes/triggers/git.ts +46 -0
- package/src/workflows/nodes/triggers/manual.ts +23 -0
- package/src/workflows/nodes/triggers/poll.ts +81 -0
- package/src/workflows/nodes/triggers/process.ts +44 -0
- package/src/workflows/nodes/triggers/screen-event.ts +37 -0
- package/src/workflows/nodes/triggers/webhook.ts +39 -0
- package/src/workflows/safe-eval.ts +139 -0
- package/src/workflows/template.ts +118 -0
- package/src/workflows/triggers/cron.ts +311 -0
- package/src/workflows/triggers/manager.ts +285 -0
- package/src/workflows/triggers/observer-bridge.ts +172 -0
- package/src/workflows/triggers/poller.ts +201 -0
- package/src/workflows/triggers/screen-condition.ts +218 -0
- package/src/workflows/triggers/triggers.test.ts +740 -0
- package/src/workflows/triggers/webhook.ts +191 -0
- package/src/workflows/types.ts +133 -0
- package/src/workflows/variables.ts +72 -0
- package/src/workflows/workflows.test.ts +383 -0
- package/src/workflows/yaml.ts +104 -0
- package/ui/dist/index-j75njzc1.css +1199 -0
- package/ui/dist/index-p2zh407q.js +80603 -0
- package/ui/dist/index.html +13 -0
- package/ui/public/openwakeword/models/embedding_model.onnx +0 -0
- package/ui/public/openwakeword/models/hey_jarvis_v0.1.onnx +0 -0
- package/ui/public/openwakeword/models/melspectrogram.onnx +0 -0
- package/ui/public/openwakeword/models/silero_vad.onnx +0 -0
- package/ui/public/ort/ort-wasm-simd-threaded.jsep.mjs +106 -0
- package/ui/public/ort/ort-wasm-simd-threaded.jsep.wasm +0 -0
- package/ui/public/ort/ort-wasm-simd-threaded.mjs +59 -0
- package/ui/public/ort/ort-wasm-simd-threaded.wasm +0 -0
package/bin/jarvis.ts
ADDED
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* J.A.R.V.I.S. CLI Entry Point
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* jarvis start [--port N] [-d|--detach] Start the daemon
|
|
7
|
+
* jarvis stop Stop the running daemon
|
|
8
|
+
* jarvis status Show daemon status
|
|
9
|
+
* jarvis onboard Interactive setup wizard
|
|
10
|
+
* jarvis doctor Check environment & connectivity
|
|
11
|
+
* jarvis version Print version
|
|
12
|
+
* jarvis help Show this help
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { join } from 'node:path';
|
|
16
|
+
import { readFileSync, existsSync, openSync } from 'node:fs';
|
|
17
|
+
import { spawn } from 'node:child_process';
|
|
18
|
+
import { writePid, clearPid, isRunning, getLogPath } from '../src/daemon/pid.ts';
|
|
19
|
+
import { c } from '../src/cli/helpers.ts';
|
|
20
|
+
|
|
21
|
+
const PACKAGE_ROOT = join(import.meta.dir, '..');
|
|
22
|
+
|
|
23
|
+
function getVersion(): string {
|
|
24
|
+
try {
|
|
25
|
+
const pkg = JSON.parse(readFileSync(join(PACKAGE_ROOT, 'package.json'), 'utf-8'));
|
|
26
|
+
return pkg.version || '0.0.0';
|
|
27
|
+
} catch {
|
|
28
|
+
return '0.0.0';
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function printHelp(): void {
|
|
33
|
+
console.log(`
|
|
34
|
+
${c.cyan('J.A.R.V.I.S.')} ${c.dim(`v${getVersion()}`)}
|
|
35
|
+
Just A Rather Very Intelligent System
|
|
36
|
+
|
|
37
|
+
${c.bold('Usage:')}
|
|
38
|
+
jarvis <command> [options]
|
|
39
|
+
|
|
40
|
+
${c.bold('Commands:')}
|
|
41
|
+
${c.cyan('start')} Start the JARVIS daemon
|
|
42
|
+
${c.cyan('stop')} Stop the running daemon
|
|
43
|
+
${c.cyan('restart')} Restart the daemon (stop + start)
|
|
44
|
+
${c.cyan('status')} Show daemon status
|
|
45
|
+
${c.cyan('logs')} Tail the daemon log file
|
|
46
|
+
${c.cyan('update')} Update JARVIS to the latest version
|
|
47
|
+
${c.cyan('onboard')} Interactive first-time setup wizard
|
|
48
|
+
${c.cyan('doctor')} Check environment and connectivity
|
|
49
|
+
${c.cyan('version')} Print version number
|
|
50
|
+
${c.cyan('help')} Show this help message
|
|
51
|
+
|
|
52
|
+
${c.bold('Start options:')}
|
|
53
|
+
--port <N> Override daemon port (default: 3142)
|
|
54
|
+
-d, --detach Run as background daemon
|
|
55
|
+
--no-open Don't auto-open dashboard in browser
|
|
56
|
+
|
|
57
|
+
${c.bold('Logs options:')}
|
|
58
|
+
-f, --follow Follow log output (like tail -f)
|
|
59
|
+
-n, --lines <N> Number of lines to show (default: 50)
|
|
60
|
+
|
|
61
|
+
${c.bold('Examples:')}
|
|
62
|
+
jarvis start Start in foreground
|
|
63
|
+
jarvis start -d Start as background daemon
|
|
64
|
+
jarvis start --port 8080 Start on custom port
|
|
65
|
+
jarvis restart Restart with same settings
|
|
66
|
+
jarvis logs -f Follow live log output
|
|
67
|
+
jarvis update Update to latest version
|
|
68
|
+
jarvis onboard Run the setup wizard
|
|
69
|
+
jarvis doctor Check if everything is working
|
|
70
|
+
`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function cmdStart(args: string[]): Promise<void> {
|
|
74
|
+
const detach = args.includes('--detach') || args.includes('-d');
|
|
75
|
+
const noOpen = args.includes('--no-open');
|
|
76
|
+
|
|
77
|
+
// Parse --port
|
|
78
|
+
let port: number | undefined;
|
|
79
|
+
const portIdx = args.indexOf('--port');
|
|
80
|
+
if (portIdx !== -1 && args[portIdx + 1]) {
|
|
81
|
+
port = parseInt(args[portIdx + 1]!, 10);
|
|
82
|
+
if (isNaN(port) || port < 1 || port > 65535) {
|
|
83
|
+
console.error(c.red('Error: --port requires a number between 1 and 65535'));
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Check if already running
|
|
89
|
+
const existingPid = isRunning();
|
|
90
|
+
if (existingPid) {
|
|
91
|
+
console.log(c.yellow(`JARVIS is already running (PID ${existingPid})`));
|
|
92
|
+
console.log(c.dim(` Stop it first with: jarvis stop`));
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!detach) {
|
|
97
|
+
// Run in foreground — just import and call startDaemon
|
|
98
|
+
writePid(process.pid);
|
|
99
|
+
process.on('exit', () => clearPid());
|
|
100
|
+
process.on('SIGINT', () => { clearPid(); process.exit(0); });
|
|
101
|
+
process.on('SIGTERM', () => { clearPid(); process.exit(0); });
|
|
102
|
+
|
|
103
|
+
const { startDaemon } = await import('../src/daemon/index.ts');
|
|
104
|
+
await startDaemon({ port, ...(port ? {} : {}) });
|
|
105
|
+
|
|
106
|
+
if (!noOpen) {
|
|
107
|
+
openDashboard(port ?? 3142);
|
|
108
|
+
}
|
|
109
|
+
} else {
|
|
110
|
+
// Run in background — spawn a detached child process with log file
|
|
111
|
+
console.log(c.cyan('Starting J.A.R.V.I.S. daemon...'));
|
|
112
|
+
|
|
113
|
+
const logPath = getLogPath();
|
|
114
|
+
const logFile = Bun.file(logPath);
|
|
115
|
+
|
|
116
|
+
const daemonArgs = [join(PACKAGE_ROOT, 'bin/jarvis.ts'), 'start', '--no-open'];
|
|
117
|
+
if (port) daemonArgs.push('--port', String(port));
|
|
118
|
+
|
|
119
|
+
const logFd = openSync(logPath, 'a');
|
|
120
|
+
const child = spawn('bun', daemonArgs, {
|
|
121
|
+
detached: true,
|
|
122
|
+
stdio: ['ignore', logFd, logFd],
|
|
123
|
+
env: { ...process.env },
|
|
124
|
+
});
|
|
125
|
+
child.unref();
|
|
126
|
+
|
|
127
|
+
// Poll for the daemon to write its PID (up to 10s)
|
|
128
|
+
let runningPid: number | null = null;
|
|
129
|
+
for (let i = 0; i < 20; i++) {
|
|
130
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
131
|
+
runningPid = isRunning();
|
|
132
|
+
if (runningPid) break;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (runningPid) {
|
|
136
|
+
console.log(c.green(`✓ JARVIS daemon started (PID ${runningPid})`));
|
|
137
|
+
console.log(c.dim(` Dashboard: http://localhost:${port ?? 3142}`));
|
|
138
|
+
console.log(c.dim(` Logs: ${logPath}`));
|
|
139
|
+
console.log(c.dim(` Stop with: jarvis stop`));
|
|
140
|
+
|
|
141
|
+
if (!noOpen) {
|
|
142
|
+
openDashboard(port ?? 3142);
|
|
143
|
+
}
|
|
144
|
+
} else {
|
|
145
|
+
console.log(c.red('✗ Failed to start daemon. Check logs:'));
|
|
146
|
+
console.log(c.dim(` ${logPath}`));
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async function cmdStop(): Promise<void> {
|
|
153
|
+
const pid = isRunning();
|
|
154
|
+
if (!pid) {
|
|
155
|
+
console.log(c.yellow('JARVIS is not running.'));
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
console.log(c.cyan(`Stopping JARVIS daemon (PID ${pid})...`));
|
|
160
|
+
try {
|
|
161
|
+
process.kill(pid, 'SIGTERM');
|
|
162
|
+
|
|
163
|
+
// Wait up to 5s for graceful shutdown, then SIGKILL
|
|
164
|
+
let alive = true;
|
|
165
|
+
for (let i = 0; i < 10; i++) {
|
|
166
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
167
|
+
try { process.kill(pid, 0); } catch { alive = false; break; }
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (alive) {
|
|
171
|
+
console.log(c.dim(' Process still alive, sending SIGKILL...'));
|
|
172
|
+
try { process.kill(pid, 'SIGKILL'); } catch { /* already gone */ }
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
clearPid();
|
|
176
|
+
console.log(c.green('✓ JARVIS daemon stopped.'));
|
|
177
|
+
} catch (err) {
|
|
178
|
+
console.error(c.red(`Failed to stop process ${pid}: ${err}`));
|
|
179
|
+
clearPid();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function cmdStatus(): void {
|
|
184
|
+
const pid = isRunning();
|
|
185
|
+
if (pid) {
|
|
186
|
+
console.log(`${c.green('●')} JARVIS is ${c.green('running')} (PID ${pid})`);
|
|
187
|
+
|
|
188
|
+
// Try to read the port from config
|
|
189
|
+
try {
|
|
190
|
+
const { homedir } = require('node:os');
|
|
191
|
+
const configPath = join(homedir(), '.jarvis', 'config.yaml');
|
|
192
|
+
const YAML = require('yaml');
|
|
193
|
+
const text = readFileSync(configPath, 'utf-8');
|
|
194
|
+
const cfg = YAML.parse(text);
|
|
195
|
+
const port = cfg?.daemon?.port ?? 3142;
|
|
196
|
+
console.log(c.dim(` Dashboard: http://localhost:${port}`));
|
|
197
|
+
} catch {
|
|
198
|
+
console.log(c.dim(` Dashboard: http://localhost:3142`));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
console.log(c.dim(` Stop with: jarvis stop`));
|
|
202
|
+
} else {
|
|
203
|
+
console.log(`${c.red('●')} JARVIS is ${c.red('stopped')}`);
|
|
204
|
+
console.log(c.dim(` Start with: jarvis start`));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
async function cmdOnboard(): Promise<void> {
|
|
209
|
+
const { runOnboard } = await import('../src/cli/onboard.ts');
|
|
210
|
+
await runOnboard();
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async function cmdDoctor(): Promise<void> {
|
|
214
|
+
const { runDoctor } = await import('../src/cli/doctor.ts');
|
|
215
|
+
await runDoctor();
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
async function cmdRestart(args: string[]): Promise<void> {
|
|
219
|
+
const pid = isRunning();
|
|
220
|
+
if (pid) {
|
|
221
|
+
await cmdStop();
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
console.log('');
|
|
225
|
+
await cmdStart(args);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function cmdLogs(args: string[]): void {
|
|
229
|
+
const logPath = getLogPath();
|
|
230
|
+
|
|
231
|
+
if (!existsSync(logPath)) {
|
|
232
|
+
console.log(c.yellow('No log file found. Start the daemon first: jarvis start'));
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const follow = args.includes('-f') || args.includes('--follow');
|
|
237
|
+
|
|
238
|
+
// Parse --lines / -n
|
|
239
|
+
let lines = 50;
|
|
240
|
+
const nIdx = args.indexOf('-n') !== -1 ? args.indexOf('-n') : args.indexOf('--lines');
|
|
241
|
+
if (nIdx !== -1 && args[nIdx + 1]) {
|
|
242
|
+
const n = parseInt(args[nIdx + 1], 10);
|
|
243
|
+
if (!isNaN(n) && n > 0) lines = n;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
console.log(c.dim(`Log file: ${logPath}\n`));
|
|
247
|
+
|
|
248
|
+
if (follow) {
|
|
249
|
+
// tail -f equivalent
|
|
250
|
+
const tailProc = Bun.spawn(['tail', '-f', '-n', String(lines), logPath], {
|
|
251
|
+
stdio: ['ignore', 'inherit', 'inherit'],
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
process.on('SIGINT', () => {
|
|
255
|
+
tailProc.kill();
|
|
256
|
+
process.exit(0);
|
|
257
|
+
});
|
|
258
|
+
} else {
|
|
259
|
+
// Just show last N lines
|
|
260
|
+
const tailProc = Bun.spawnSync(['tail', '-n', String(lines), logPath]);
|
|
261
|
+
process.stdout.write(tailProc.stdout);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
async function cmdUpdate(): Promise<void> {
|
|
266
|
+
console.log(c.cyan('Checking for updates...\n'));
|
|
267
|
+
|
|
268
|
+
// Get current version
|
|
269
|
+
const currentVersion = getVersion();
|
|
270
|
+
console.log(` Current version: ${c.bold(currentVersion)}`);
|
|
271
|
+
|
|
272
|
+
// Check if daemon is running (we'll restart it after update)
|
|
273
|
+
const wasRunning = isRunning();
|
|
274
|
+
|
|
275
|
+
// Stop daemon if running
|
|
276
|
+
if (wasRunning) {
|
|
277
|
+
console.log(c.dim(' Stopping daemon before update...'));
|
|
278
|
+
try {
|
|
279
|
+
process.kill(wasRunning, 'SIGTERM');
|
|
280
|
+
clearPid();
|
|
281
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
282
|
+
} catch {
|
|
283
|
+
clearPid();
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Update via git pull + bun install (not npm — package is not published)
|
|
288
|
+
console.log('');
|
|
289
|
+
const gitPull = Bun.spawnSync(['git', 'pull', '--ff-only'], {
|
|
290
|
+
cwd: PACKAGE_ROOT,
|
|
291
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
292
|
+
env: { ...process.env },
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
if (gitPull.exitCode !== 0) {
|
|
296
|
+
const stderr = gitPull.stderr.toString();
|
|
297
|
+
// If not a git repo, try the install dir
|
|
298
|
+
const installDir = join(require('node:os').homedir(), '.jarvis', 'daemon');
|
|
299
|
+
const gitPull2 = Bun.spawnSync(['git', 'pull', '--ff-only'], {
|
|
300
|
+
cwd: installDir,
|
|
301
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
302
|
+
env: { ...process.env },
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
if (gitPull2.exitCode !== 0) {
|
|
306
|
+
console.log(c.red('✗ Update failed (git pull):'));
|
|
307
|
+
console.log(c.dim(` ${gitPull2.stderr.toString().trim() || stderr.trim()}`));
|
|
308
|
+
if (wasRunning) {
|
|
309
|
+
console.log(c.dim('\n Restarting daemon...'));
|
|
310
|
+
await cmdStart(['--no-open']);
|
|
311
|
+
}
|
|
312
|
+
process.exit(1);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Reinstall dependencies
|
|
317
|
+
const bunInstall = Bun.spawnSync(['bun', 'install'], {
|
|
318
|
+
cwd: PACKAGE_ROOT,
|
|
319
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
320
|
+
env: { ...process.env },
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
if (bunInstall.exitCode !== 0) {
|
|
324
|
+
console.log(c.yellow('! Dependencies may need manual refresh: bun install'));
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Get new version
|
|
328
|
+
const newVersion = getVersion();
|
|
329
|
+
if (newVersion === currentVersion) {
|
|
330
|
+
console.log(c.green(`✓ Already on the latest version (${currentVersion})`));
|
|
331
|
+
} else {
|
|
332
|
+
console.log(c.green(`✓ Updated: ${currentVersion} → ${newVersion}`));
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Restart daemon if it was running
|
|
336
|
+
if (wasRunning) {
|
|
337
|
+
console.log(c.dim('\nRestarting daemon...'));
|
|
338
|
+
await cmdStart(['--no-open']);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function openDashboard(port: number): void {
|
|
343
|
+
const url = `http://localhost:${port}`;
|
|
344
|
+
try {
|
|
345
|
+
const platform = process.platform;
|
|
346
|
+
if (platform === 'darwin') {
|
|
347
|
+
Bun.spawn(['open', url], { stdio: ['ignore', 'ignore', 'ignore'] });
|
|
348
|
+
} else {
|
|
349
|
+
// Check WSL first
|
|
350
|
+
const { readFileSync } = require('node:fs');
|
|
351
|
+
try {
|
|
352
|
+
const version = readFileSync('/proc/version', 'utf-8');
|
|
353
|
+
if (version.toLowerCase().includes('microsoft')) {
|
|
354
|
+
Bun.spawn(['wslview', url], { stdio: ['ignore', 'ignore', 'ignore'] });
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
} catch {}
|
|
358
|
+
// Regular Linux
|
|
359
|
+
Bun.spawn(['xdg-open', url], { stdio: ['ignore', 'ignore', 'ignore'] });
|
|
360
|
+
}
|
|
361
|
+
} catch {
|
|
362
|
+
// Silently fail — user can open manually
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// ── Main ─────────────────────────────────────────────────────────────
|
|
367
|
+
|
|
368
|
+
const args = process.argv.slice(2);
|
|
369
|
+
const command = args[0] || 'help';
|
|
370
|
+
const commandArgs = args.slice(1);
|
|
371
|
+
|
|
372
|
+
switch (command) {
|
|
373
|
+
case 'start':
|
|
374
|
+
await cmdStart(commandArgs);
|
|
375
|
+
break;
|
|
376
|
+
case 'stop':
|
|
377
|
+
await cmdStop();
|
|
378
|
+
break;
|
|
379
|
+
case 'restart':
|
|
380
|
+
await cmdRestart(commandArgs);
|
|
381
|
+
break;
|
|
382
|
+
case 'status':
|
|
383
|
+
cmdStatus();
|
|
384
|
+
break;
|
|
385
|
+
case 'logs':
|
|
386
|
+
case 'log':
|
|
387
|
+
cmdLogs(commandArgs);
|
|
388
|
+
break;
|
|
389
|
+
case 'update':
|
|
390
|
+
case 'upgrade':
|
|
391
|
+
await cmdUpdate();
|
|
392
|
+
break;
|
|
393
|
+
case 'onboard':
|
|
394
|
+
await cmdOnboard();
|
|
395
|
+
break;
|
|
396
|
+
case 'doctor':
|
|
397
|
+
await cmdDoctor();
|
|
398
|
+
break;
|
|
399
|
+
case 'version':
|
|
400
|
+
case '-v':
|
|
401
|
+
case '--version':
|
|
402
|
+
console.log(getVersion());
|
|
403
|
+
break;
|
|
404
|
+
case 'help':
|
|
405
|
+
case '-h':
|
|
406
|
+
case '--help':
|
|
407
|
+
printHelp();
|
|
408
|
+
break;
|
|
409
|
+
default:
|
|
410
|
+
console.error(c.red(`Unknown command: ${command}`));
|
|
411
|
+
console.log(c.dim('Run "jarvis help" for usage information.'));
|
|
412
|
+
process.exit(1);
|
|
413
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@usejarvis/brain",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "J.A.R.V.I.S. — Just A Rather Very Intelligent System. An always-on autonomous AI daemon.",
|
|
5
|
+
"module": "src/daemon/index.ts",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"jarvis": "bin/jarvis.ts"
|
|
9
|
+
},
|
|
10
|
+
"engines": {
|
|
11
|
+
"bun": ">=1.0.0"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/vierisid/jarvis.git"
|
|
16
|
+
},
|
|
17
|
+
"license": "Apache-2.0",
|
|
18
|
+
"keywords": [
|
|
19
|
+
"jarvis",
|
|
20
|
+
"ai",
|
|
21
|
+
"daemon",
|
|
22
|
+
"assistant",
|
|
23
|
+
"cli"
|
|
24
|
+
],
|
|
25
|
+
"files": [
|
|
26
|
+
"bin/",
|
|
27
|
+
"src/",
|
|
28
|
+
"ui/dist/",
|
|
29
|
+
"ui/public/",
|
|
30
|
+
"scripts/ensure-bun.cjs",
|
|
31
|
+
"README.md"
|
|
32
|
+
],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"start": "bun run src/daemon/index.ts",
|
|
35
|
+
"dev": "bun --hot run src/daemon/index.ts",
|
|
36
|
+
"copy:models": "mkdir -p ui/public/openwakeword/models ui/public/ort && cp node_modules/openwakeword-wasm-browser/models/melspectrogram.onnx node_modules/openwakeword-wasm-browser/models/embedding_model.onnx node_modules/openwakeword-wasm-browser/models/silero_vad.onnx node_modules/openwakeword-wasm-browser/models/hey_jarvis_v0.1.onnx ui/public/openwakeword/models/ && cp node_modules/onnxruntime-web/dist/ort-wasm-simd-threaded.jsep.wasm node_modules/onnxruntime-web/dist/ort-wasm-simd-threaded.wasm node_modules/onnxruntime-web/dist/ort-wasm-simd-threaded.jsep.mjs node_modules/onnxruntime-web/dist/ort-wasm-simd-threaded.mjs ui/public/ort/",
|
|
37
|
+
"prebuild:ui": "bun run copy:models",
|
|
38
|
+
"build:ui": "bun build ui/index.html --outdir ui/dist",
|
|
39
|
+
"test": "bun test",
|
|
40
|
+
"db:init": "bun run src/vault/schema.ts",
|
|
41
|
+
"setup": "bun run scripts/setup-config.ts",
|
|
42
|
+
"test:llm": "bun run src/llm/test.ts",
|
|
43
|
+
"examples": "bun run examples/llm-integration.ts",
|
|
44
|
+
"setup:google": "bun run src/scripts/google-setup.ts",
|
|
45
|
+
"postinstall": "node scripts/ensure-bun.cjs && bun run copy:models 2>/dev/null || true",
|
|
46
|
+
"prepare": "git config core.hooksPath .githooks 2>/dev/null || true",
|
|
47
|
+
"prepublishOnly": "bun run copy:models && bun run build:ui"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@types/react": "^19.2.14",
|
|
51
|
+
"@types/react-dom": "^19.2.3",
|
|
52
|
+
"@xyflow/react": "^12.10.1",
|
|
53
|
+
"discord.js": "^14.25.1",
|
|
54
|
+
"edge-tts-universal": "^1.4.0",
|
|
55
|
+
"highlight.js": "^11.11.1",
|
|
56
|
+
"jose": "^6.2.0",
|
|
57
|
+
"openwakeword-wasm-browser": "^0.1.1",
|
|
58
|
+
"react": "^19.2.4",
|
|
59
|
+
"react-dom": "^19.2.4",
|
|
60
|
+
"react-markdown": "^10.1.0",
|
|
61
|
+
"rehype-highlight": "^7.0.2",
|
|
62
|
+
"remark-gfm": "^4.0.1",
|
|
63
|
+
"sharp": "^0.34.5",
|
|
64
|
+
"tailwindcss": "^4.2.1",
|
|
65
|
+
"tesseract.js": "^7.0.0",
|
|
66
|
+
"yaml": "^2.7.0"
|
|
67
|
+
},
|
|
68
|
+
"devDependencies": {
|
|
69
|
+
"@types/bun": "latest"
|
|
70
|
+
},
|
|
71
|
+
"peerDependencies": {
|
|
72
|
+
"typescript": "^5"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const { execSync } = require('child_process');
|
|
3
|
+
try {
|
|
4
|
+
execSync('bun --version', { stdio: 'ignore' });
|
|
5
|
+
} catch {
|
|
6
|
+
console.log('Bun runtime not found. Installing...');
|
|
7
|
+
execSync('curl -fsSL https://bun.sh/install | bash', { stdio: 'inherit' });
|
|
8
|
+
}
|