@appchy/jarvis 0.1.4 → 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/dist/bin.js CHANGED
@@ -1,10 +1,14 @@
1
1
  // src/bin.ts
2
2
  import dotenv from "dotenv";
3
- import fs7 from "fs";
4
- import path7 from "path";
3
+ import fs8 from "fs";
4
+ import path8 from "path";
5
5
 
6
6
  // src/cli.ts
7
7
  import { Command } from "commander";
8
+ import { spawn as spawn2, execSync } from "child_process";
9
+ import fs7 from "fs";
10
+ import path7 from "path";
11
+ import os4 from "os";
8
12
 
9
13
  // src/config.ts
10
14
  import fs from "fs";
@@ -384,7 +388,7 @@ function claudeCodeProvider(config = {}) {
384
388
  options: {
385
389
  model: req.model,
386
390
  systemPrompt: systemPromptOption,
387
- maxTurns: config.maxTurns ?? 50,
391
+ ...config.maxTurns ? { maxTurns: config.maxTurns } : {},
388
392
  ...permissionOptions,
389
393
  ...config.mcpServers ? { mcpServers: config.mcpServers } : {},
390
394
  ...config.workingDirectory ? { cwd: config.workingDirectory } : {},
@@ -553,7 +557,7 @@ function claudeCodeProvider(config = {}) {
553
557
  options: {
554
558
  model: req.model,
555
559
  systemPrompt: streamSystemPromptOption,
556
- maxTurns: config.maxTurns ?? 50,
560
+ ...config.maxTurns ? { maxTurns: config.maxTurns } : {},
557
561
  ...permissionOptions,
558
562
  ...config.mcpServers ? { mcpServers: config.mcpServers } : {},
559
563
  ...config.workingDirectory ? { cwd: config.workingDirectory } : {},
@@ -2052,7 +2056,7 @@ function createWsProgressHandlers(deps) {
2052
2056
  id: `status-plan-${crypto2.randomUUID()}`,
2053
2057
  role: "assistant",
2054
2058
  type: "status",
2055
- content: "Planning...",
2059
+ content: "Planning",
2056
2060
  isPartial: true,
2057
2061
  createdAt: now
2058
2062
  });
@@ -2234,7 +2238,7 @@ function createAgent(deps) {
2234
2238
  systemPrompt: systemMsg?.content ?? "",
2235
2239
  workingDirectory: wsPath,
2236
2240
  tools: claudeCodeTools,
2237
- maxTurns: msg.maxTurns ?? 200,
2241
+ ...msg.maxTurns ? { maxTurns: msg.maxTurns } : {},
2238
2242
  userId: deps.userId,
2239
2243
  abortController,
2240
2244
  heartbeat: () => {
@@ -2262,7 +2266,7 @@ function createAgent(deps) {
2262
2266
  ...deps.useSubscription ? { useSubscription: true } : { apiKey: deps.anthropicApiKey },
2263
2267
  workingDirectory: wsPath,
2264
2268
  tools: claudeCodeTools,
2265
- maxTurns: msg.maxTurns ?? 200,
2269
+ ...msg.maxTurns ? { maxTurns: msg.maxTurns } : {},
2266
2270
  userId: deps.userId,
2267
2271
  abortController,
2268
2272
  heartbeat: () => {
@@ -4660,8 +4664,39 @@ async function waitForAgent(port, maxAttempts = 30) {
4660
4664
  }
4661
4665
 
4662
4666
  // src/cli.ts
4667
+ import { createRequire } from "module";
4668
+ var _require = createRequire(import.meta.url);
4669
+ var PKG_VERSION = _require("../package.json").version ?? "dev";
4670
+ var LOG_DIR = path7.join(os4.homedir(), ".jarvis");
4671
+ var LOG_FILE = path7.join(LOG_DIR, "agent.log");
4672
+ var PID_FILE = path7.join(LOG_DIR, "agent.pid");
4673
+ function savePid(pid) {
4674
+ fs7.mkdirSync(LOG_DIR, { recursive: true });
4675
+ fs7.writeFileSync(PID_FILE, String(pid));
4676
+ }
4677
+ function readPid() {
4678
+ try {
4679
+ const pid = parseInt(fs7.readFileSync(PID_FILE, "utf-8").trim(), 10);
4680
+ if (isNaN(pid)) return null;
4681
+ try {
4682
+ process.kill(pid, 0);
4683
+ return pid;
4684
+ } catch {
4685
+ fs7.unlinkSync(PID_FILE);
4686
+ return null;
4687
+ }
4688
+ } catch {
4689
+ return null;
4690
+ }
4691
+ }
4692
+ function clearPid() {
4693
+ try {
4694
+ fs7.unlinkSync(PID_FILE);
4695
+ } catch {
4696
+ }
4697
+ }
4663
4698
  function createCli() {
4664
- const program = new Command().name("jarvis").description("Jarvis local agent \u2014 runs Claude Code on your machine").version("0.0.0");
4699
+ const program = new Command().name("jarvis").description("Jarvis local agent \u2014 runs Claude Code on your machine").version(PKG_VERSION);
4665
4700
  program.command("connect <token>").description("Connect to Jarvis cloud using a token from the web UI").option("-w, --workspace <path>", "Workspace root path for repo operations").action((token, opts) => {
4666
4701
  try {
4667
4702
  const parsed = parseConnectToken(token);
@@ -4687,15 +4722,13 @@ function createCli() {
4687
4722
  process.exit(1);
4688
4723
  }
4689
4724
  });
4690
- program.command("start").description("Start the local agent").option("-p, --port <port>", "Local WS server port", "7862").option("-w, --workspace <path>", "Workspace root path").option("--api-key <key>", "Anthropic API key (for local-only use)").option("--no-upstream", "Don't connect to cloud (local-only mode)").action(async (opts) => {
4725
+ program.command("start").description("Start the local agent (runs as background daemon)").option("-p, --port <port>", "Local WS server port", "7862").option("-w, --workspace <path>", "Workspace root path").option("--api-key <key>", "Anthropic API key (for local-only use)").option("--no-upstream", "Don't connect to cloud (local-only mode)").option("--foreground", "Run in foreground (don't daemonize)").action(async (opts) => {
4691
4726
  const config = loadConfig();
4692
4727
  const port = parseInt(opts.port, 10);
4693
4728
  const alreadyRunning = await isPortInUse(port);
4694
4729
  if (alreadyRunning) {
4695
- console.log(`
4696
- Jarvis agent is already running on ws://127.0.0.1:${port}`);
4697
- console.log(`Clients (jarvis chat, VSCode) can connect to it.
4698
- `);
4730
+ console.log(`Jarvis agent is already running on ws://127.0.0.1:${port}`);
4731
+ console.log(`Use 'jarvis restart' to restart, or 'jarvis logs' to view logs.`);
4699
4732
  return;
4700
4733
  }
4701
4734
  const workspacePath = opts.workspace ?? config?.workspacePath ?? process.cwd();
@@ -4704,35 +4737,153 @@ Jarvis agent is already running on ws://127.0.0.1:${port}`);
4704
4737
  if (!anthropicApiKey && !config?.useSubscription) {
4705
4738
  console.warn("Warning: No Anthropic API key set. Using subscription mode.");
4706
4739
  }
4707
- await startAgent({
4708
- port,
4709
- workspacePath,
4710
- anthropicApiKey,
4711
- useSubscription: !anthropicApiKey,
4712
- userId,
4713
- upstream: opts.upstream && config?.apiUrl && config?.token ? { apiUrl: config.apiUrl, token: config.token } : void 0
4714
- });
4740
+ if (opts.foreground) {
4741
+ await startAgent({
4742
+ port,
4743
+ workspacePath,
4744
+ anthropicApiKey,
4745
+ useSubscription: !anthropicApiKey,
4746
+ userId,
4747
+ upstream: opts.upstream && config?.apiUrl && config?.token ? { apiUrl: config.apiUrl, token: config.token } : void 0
4748
+ });
4749
+ return;
4750
+ }
4751
+ fs7.mkdirSync(LOG_DIR, { recursive: true });
4752
+ const logFd = fs7.openSync(LOG_FILE, "a");
4753
+ const args = [
4754
+ "start",
4755
+ "--foreground",
4756
+ "--port",
4757
+ String(port),
4758
+ "--workspace",
4759
+ workspacePath
4760
+ ];
4761
+ if (!opts.upstream) {
4762
+ args.push("--no-upstream");
4763
+ }
4764
+ if (anthropicApiKey) {
4765
+ args.push("--api-key", anthropicApiKey);
4766
+ }
4767
+ const binPath = process.argv[1];
4768
+ const cliRoot = path7.resolve(path7.dirname(binPath), "..");
4769
+ const distEntry = path7.join(cliRoot, "dist", "bin.js");
4770
+ const useDistEntry = fs7.existsSync(distEntry);
4771
+ const child = spawn2(
4772
+ process.execPath,
4773
+ useDistEntry ? [distEntry, ...args] : [binPath, ...args],
4774
+ {
4775
+ detached: true,
4776
+ stdio: ["ignore", logFd, logFd],
4777
+ cwd: workspacePath,
4778
+ env: { ...process.env, NODE_NO_WARNINGS: "1" }
4779
+ }
4780
+ );
4781
+ child.unref();
4782
+ fs7.closeSync(logFd);
4783
+ savePid(child.pid);
4784
+ console.log(`Jarvis agent started (PID: ${child.pid})`);
4785
+ console.log(` Local: ws://127.0.0.1:${port}`);
4786
+ console.log(` Workspace: ${workspacePath}`);
4787
+ console.log(` Logs: ${LOG_FILE}`);
4788
+ if (config?.apiUrl) {
4789
+ console.log(` Cloud: ${config.apiUrl}`);
4790
+ }
4791
+ console.log();
4792
+ console.log(`Commands:`);
4793
+ console.log(` jarvis logs \u2014 View agent logs`);
4794
+ console.log(` jarvis stop \u2014 Stop the agent`);
4795
+ console.log(` jarvis restart \u2014 Restart the agent`);
4796
+ });
4797
+ program.command("stop").description("Stop the running agent").action(async () => {
4798
+ const pid = readPid();
4799
+ if (pid) {
4800
+ try {
4801
+ process.kill(pid, "SIGTERM");
4802
+ clearPid();
4803
+ console.log(`Agent stopped (PID: ${pid})`);
4804
+ } catch {
4805
+ clearPid();
4806
+ console.log("Agent process not found. Cleaned up PID file.");
4807
+ }
4808
+ return;
4809
+ }
4810
+ const running = await isPortInUse(7862);
4811
+ if (running) {
4812
+ try {
4813
+ const output = execSync("lsof -ti :7862", { encoding: "utf-8" }).trim();
4814
+ if (output) {
4815
+ const pids = output.split("\n");
4816
+ for (const p of pids) {
4817
+ try {
4818
+ process.kill(parseInt(p, 10), "SIGTERM");
4819
+ } catch {
4820
+ }
4821
+ }
4822
+ console.log("Agent stopped.");
4823
+ return;
4824
+ }
4825
+ } catch {
4826
+ }
4827
+ }
4828
+ console.log("No agent is running.");
4829
+ });
4830
+ program.command("restart").description("Restart the agent").action(async () => {
4831
+ const pid = readPid();
4832
+ if (pid) {
4833
+ try {
4834
+ process.kill(pid, "SIGTERM");
4835
+ } catch {
4836
+ }
4837
+ clearPid();
4838
+ console.log(`Stopped agent (PID: ${pid})`);
4839
+ await new Promise((r) => setTimeout(r, 1e3));
4840
+ }
4841
+ console.log("Starting agent...");
4842
+ await program.parseAsync(["node", "jarvis", "start"]);
4843
+ });
4844
+ program.command("logs").description("View agent logs").option("-f, --follow", "Follow log output (like tail -f)").option("-n, --lines <n>", "Number of lines to show", "50").action((opts) => {
4845
+ if (!fs7.existsSync(LOG_FILE)) {
4846
+ console.log("No log file found. Start the agent first: jarvis start");
4847
+ return;
4848
+ }
4849
+ if (opts.follow) {
4850
+ const tail = spawn2("tail", ["-f", "-n", opts.lines, LOG_FILE], {
4851
+ stdio: "inherit"
4852
+ });
4853
+ process.on("SIGINT", () => {
4854
+ tail.kill();
4855
+ process.exit(0);
4856
+ });
4857
+ tail.on("exit", () => process.exit(0));
4858
+ } else {
4859
+ const content = execSync(`tail -n ${opts.lines} "${LOG_FILE}"`, { encoding: "utf-8" });
4860
+ process.stdout.write(content);
4861
+ }
4715
4862
  });
4716
4863
  program.command("chat").description("Interactive TUI \u2014 chat with Jarvis in your terminal").option("--model <id>", "Model (e.g., claude-opus-4-20250514)").option("--mode <mode>", "Permission mode: supervised|auto|plan|yolo").option("--thinking <config>", "Thinking: adaptive|enabled|disabled").option("--thinking-budget <n>", "Token budget when thinking=enabled").option("--max-turns <n>", "Max turns per task").option("-p, --port <port>", "Agent server port", "7862").option("-w, --workspace <path>", "Workspace root path").option("--no-server", "Connect to existing server, don't auto-start").action(async (opts) => {
4717
4864
  await launchChat(opts);
4718
4865
  });
4719
- program.command("status").description("Show agent configuration and connection status").action(() => {
4866
+ program.command("status").description("Show agent configuration and connection status").action(async () => {
4720
4867
  const config = loadConfig();
4721
- if (!config) {
4722
- console.log("No configuration found.");
4723
- console.log(`Run 'jarvis connect <token>' to set up.`);
4724
- return;
4725
- }
4726
- console.log("Jarvis Agent Config:");
4868
+ const pid = readPid();
4869
+ const port = config?.port ?? 7862;
4870
+ const running = await isPortInUse(port);
4871
+ console.log(`Jarvis Agent v${PKG_VERSION}:`);
4872
+ console.log(` Status: ${running ? `\x1B[32mrunning\x1B[0m` : `\x1B[31mstopped\x1B[0m`}${pid ? ` (PID: ${pid})` : ""}`);
4873
+ console.log(` Port: ${port}`);
4727
4874
  console.log(` Config: ${getConfigPath()}`);
4728
- console.log(` User: ${config.userId}`);
4729
- console.log(` Env: ${config.envId ?? "local"}`);
4730
- console.log(` Workspace: ${config.workspacePath ?? "(cwd)"}`);
4731
- console.log(` Port: ${config.port ?? 7862}`);
4732
- console.log(` Cloud: ${config.apiUrl ?? "(not connected)"}`);
4733
- if (config.connectedAt) {
4734
- console.log(` Connected: ${config.connectedAt}`);
4875
+ if (config) {
4876
+ console.log(` User: ${config.userId}`);
4877
+ console.log(` Env: ${config.envId ?? "local"}`);
4878
+ console.log(` Workspace: ${config.workspacePath ?? "(cwd)"}`);
4879
+ console.log(` Cloud: ${config.apiUrl ?? "(not connected)"}`);
4880
+ if (config.connectedAt) {
4881
+ console.log(` Connected: ${config.connectedAt}`);
4882
+ }
4883
+ } else {
4884
+ console.log(` Config: Not set up. Run 'jarvis connect <token>'`);
4735
4885
  }
4886
+ console.log(` Logs: ${LOG_FILE}`);
4736
4887
  });
4737
4888
  program.command("logout").description("Clear saved configuration").action(() => {
4738
4889
  clearConfig();
@@ -4744,10 +4895,10 @@ Jarvis agent is already running on ws://127.0.0.1:${port}`);
4744
4895
  // src/bin.ts
4745
4896
  function findEnv() {
4746
4897
  let dir = process.cwd();
4747
- while (dir !== path7.dirname(dir)) {
4748
- const envPath = path7.join(dir, ".env");
4749
- if (fs7.existsSync(envPath)) return envPath;
4750
- dir = path7.dirname(dir);
4898
+ while (dir !== path8.dirname(dir)) {
4899
+ const envPath = path8.join(dir, ".env");
4900
+ if (fs8.existsSync(envPath)) return envPath;
4901
+ dir = path8.dirname(dir);
4751
4902
  }
4752
4903
  return void 0;
4753
4904
  }