@jellyos/agent 0.1.8 → 0.2.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/bin/jellyos-mcp CHANGED
File without changes
package/dist/cli.js CHANGED
@@ -12,6 +12,7 @@ import { Registry } from "./api/Registry.js";
12
12
  import { loadExtension } from "./loader.js";
13
13
  import { App } from "./tui/App.js";
14
14
  import { T } from "./tui/theme.js";
15
+ import { wireNotify, safeLog } from "./util/safeLog.js";
15
16
  import { modelRegistry } from "./models/ModelRegistry.js";
16
17
  import { CostTracker } from "./models/CostTracker.js";
17
18
  import { AgentRunner } from "./runner/AgentRunner.js";
@@ -212,10 +213,19 @@ else {
212
213
  chain,
213
214
  modelReg: modelRegistry,
214
215
  costTracker,
215
- onNotifyReady: (fn) => { _notifyFn = fn; },
216
+ onNotifyReady: (fn) => { _notifyFn = fn; wireNotify(fn); },
216
217
  onStatusReady: (fn) => { _setStatusFn = fn; },
217
218
  onModelSelectorReady: (fn) => { _showModelSelectorFn = fn; },
218
219
  }), { exitOnCtrlC: false });
220
+ // Ink owns the terminal from this point on. Any console.log/error/warn
221
+ // writes raw bytes to stdout, bypassing Ink's rendering buffer. Ink's
222
+ // cursor-up calculation becomes wrong → stacked border lines.
223
+ // NOTE: process.stdout.write is intentionally NOT patched — Ink uses it
224
+ // for every render frame; intercepting it globally would break Ink output.
225
+ process.prependListener("SIGWINCH", () => { process.stdout.write("\x1B[2J\x1B[H"); });
226
+ console.log = safeLog;
227
+ console.error = safeLog;
228
+ console.warn = safeLog;
219
229
  })();
220
230
  } // end headless else
221
231
  //# sourceMappingURL=cli.js.map
package/dist/loader.js CHANGED
@@ -80,6 +80,26 @@ export async function loadExtension(extensionPath, registry, opts = {}) {
80
80
  if (typeof fn !== "function") {
81
81
  throw new Error(`Extension must export a default function. Got: ${typeof fn} from ${abs}`);
82
82
  }
83
- await fn(api);
83
+ // Intercept console.log/error/warn during extension load so that any
84
+ // stray prints in the extension (e.g. loadSkills logging) are routed
85
+ // through ui.notify instead of raw stdout writes that corrupt the TUI.
86
+ const _origLog = console.log;
87
+ const _origError = console.error;
88
+ const _origWarn = console.warn;
89
+ const _extLog = (...args) => {
90
+ const msg = args.map(a => (typeof a === "string" ? a : String(a))).join(" ");
91
+ ui.notify(msg);
92
+ };
93
+ console.log = _extLog;
94
+ console.error = _extLog;
95
+ console.warn = _extLog;
96
+ try {
97
+ await fn(api);
98
+ }
99
+ finally {
100
+ console.log = _origLog;
101
+ console.error = _origError;
102
+ console.warn = _origWarn;
103
+ }
84
104
  }
85
105
  //# sourceMappingURL=loader.js.map
@@ -12,6 +12,8 @@ import { mkdirSync } from "node:fs";
12
12
  import { join } from "node:path";
13
13
  import { homedir } from "node:os";
14
14
  const JELLY_HOME = process.env.JELLYOS_HOME ?? join(homedir(), ".jelly");
15
+ import { createRequire } from "module";
16
+ const cjsRequire = createRequire(import.meta.url);
15
17
  export class MemoryStore {
16
18
  db = null;
17
19
  available = false;
@@ -22,8 +24,7 @@ export class MemoryStore {
22
24
  try {
23
25
  // node:sqlite is available in Node 22+ (experimental) and Node 24 (stable)
24
26
  // We import it dynamically to avoid a hard crash on older Node versions
25
- // eslint-disable-next-line @typescript-eslint/no-var-requires
26
- const sqlite = require("node:sqlite");
27
+ const sqlite = cjsRequire("node:sqlite");
27
28
  mkdirSync(JELLY_HOME, { recursive: true });
28
29
  this.db = new sqlite.DatabaseSync(join(JELLY_HOME, "memory.db"));
29
30
  this.db.exec(`
@@ -33,7 +34,7 @@ export class MemoryStore {
33
34
  role TEXT NOT NULL,
34
35
  content TEXT NOT NULL,
35
36
  tokens INTEGER DEFAULT 0,
36
- ts INTEGER NOT NULL,
37
+ ts INTEGER NOT NULL,
37
38
  tags TEXT DEFAULT '[]'
38
39
  );
39
40
  CREATE INDEX IF NOT EXISTS idx_session ON messages(sessionId);
package/dist/tui/App.js CHANGED
@@ -6,6 +6,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
6
6
  */
7
7
  import { useState, useCallback, useEffect, useRef, useMemo } from "react";
8
8
  import { Box, Text, useApp, useInput } from "ink";
9
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
10
+ import { join } from "node:path";
11
+ import { homedir } from "node:os";
12
+ import { Type } from "@sinclair/typebox";
9
13
  import { StatusBar } from "./StatusBar.js";
10
14
  import { REPL } from "./REPL.js";
11
15
  import { ModelSelector } from "./ModelSelector.js";
@@ -161,8 +165,8 @@ export function App({ registry, systemPrompt, effectLevel: initialEffect = "norm
161
165
  registry.addTool({ name: "get_defi_tvl", label: "DeFi TVL", description: "DeFiLlama TVL by chain or all chains.", parameters: defiTvlParams, execute: (id, p) => getDefiTvlTool(id, p) });
162
166
  registry.addTool({ name: "get_solana_stats", label: "Solana Stats", description: "Solana network TPS and health.", parameters: solanaStatsParams, execute: () => getSolanaStatsTool() });
163
167
  // #31: Ephemeral task context
164
- registry.addTool({ name: "read_task_context", label: "Read Task Context", description: "Read saved task context from a previous multi-step operation.", parameters: require("@sinclair/typebox").Type.Object({ taskId: require("@sinclair/typebox").Type.String({ description: "Task ID from a previous task reference" }) }), execute: (id, p) => contextStore.readContextTool(id, p) });
165
- registry.addTool({ name: "list_tasks", label: "List Tasks", description: "List active and recent task context folders.", parameters: require("@sinclair/typebox").Type.Object({}), execute: () => contextStore.listTasksTool() });
168
+ registry.addTool({ name: "read_task_context", label: "Read Task Context", description: "Read saved task context from a previous multi-step operation.", parameters: Type.Object({ taskId: Type.String({ description: "Task ID from a previous task reference" }) }), execute: (id, p) => contextStore.readContextTool(id, p) });
169
+ registry.addTool({ name: "list_tasks", label: "List Tasks", description: "List active and recent task context folders.", parameters: Type.Object({}), execute: () => contextStore.listTasksTool() });
166
170
  // #12: Goal management
167
171
  registry.addTool({ name: "set_goal", label: "Set Goal", description: "Set a persistent cross-session goal for the agent to monitor.", parameters: goalManager.setGoalParams, execute: (id, p) => goalManager.setGoalTool(id, p) });
168
172
  registry.addTool({ name: "complete_goal", label: "Complete Goal", description: "Mark a goal as completed.", parameters: goalManager.completeGoalParams, execute: (id, p) => goalManager.completeGoalTool(id, p) });
@@ -223,13 +227,10 @@ export function App({ registry, systemPrompt, effectLevel: initialEffect = "norm
223
227
  }
224
228
  // Read rotation slots from context.json
225
229
  try {
226
- const { existsSync: exists, readFileSync: read } = require("node:fs");
227
- const { join } = require("node:path");
228
- const { homedir } = require("node:os");
229
230
  const JELLY_HOME = process.env.JELLYOS_HOME ?? join(homedir(), ".jelly");
230
231
  const ctxPath = join(JELLY_HOME, "context.json");
231
- if (exists(ctxPath)) {
232
- const store = JSON.parse(read(ctxPath, "utf-8"));
232
+ if (existsSync(ctxPath)) {
233
+ const store = JSON.parse(readFileSync(ctxPath, "utf-8"));
233
234
  if (store.rotationSlots)
234
235
  setRotationSlots(store.rotationSlots);
235
236
  }
@@ -510,9 +511,6 @@ export function App({ registry, systemPrompt, effectLevel: initialEffect = "norm
510
511
  const handleModelSelect = useCallback((modelId) => {
511
512
  setShowModelSelector(false);
512
513
  try {
513
- const { writeFileSync, readFileSync, existsSync, mkdirSync } = require("node:fs");
514
- const { join } = require("node:path");
515
- const { homedir } = require("node:os");
516
514
  const JELLY_HOME = process.env.JELLYOS_HOME ?? join(homedir(), ".jelly");
517
515
  const envFile = join(JELLY_HOME, ".env");
518
516
  mkdirSync(JELLY_HOME, { recursive: true });
@@ -0,0 +1,3 @@
1
+ export declare function wireNotify(fn: (msg: string) => void): void;
2
+ export declare function safeLog(...args: unknown[]): void;
3
+ //# sourceMappingURL=safeLog.d.ts.map
@@ -0,0 +1,21 @@
1
+ import { appendFileSync, mkdirSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { homedir } from "node:os";
4
+ const JELLY_HOME = process.env.JELLYOS_HOME ?? join(homedir(), ".jelly");
5
+ const DEBUG_LOG = join(JELLY_HOME, "debug.log");
6
+ let _notifyFn = null;
7
+ export function wireNotify(fn) { _notifyFn = fn; }
8
+ export function safeLog(...args) {
9
+ const msg = args.map(a => (typeof a === "string" ? a : String(a))).join(" ");
10
+ if (_notifyFn) {
11
+ _notifyFn(msg);
12
+ }
13
+ else {
14
+ try {
15
+ mkdirSync(JELLY_HOME, { recursive: true });
16
+ appendFileSync(DEBUG_LOG, `[${new Date().toISOString()}] ${msg}\n`);
17
+ }
18
+ catch { /* non-fatal */ }
19
+ }
20
+ }
21
+ //# sourceMappingURL=safeLog.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jellyos/agent",
3
- "version": "0.1.8",
3
+ "version": "0.2.0",
4
4
  "description": "JellyOS — standalone AI trading agent. Runs locally, no server required.",
5
5
  "author": "JellyChain",
6
6
  "license": "MIT",
@@ -18,6 +18,9 @@
18
18
  "jellyagent": "./bin/jellyagent",
19
19
  "jellyos-mcp": "./bin/jellyos-mcp"
20
20
  },
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
21
24
  "scripts": {
22
25
  "build": "npx tsc",
23
26
  "build:watch": "tsc --watch",