agentbnb 5.1.9 → 5.1.11

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.
Files changed (30) hide show
  1. package/dist/{chunk-BTTL24TZ.js → chunk-EGUOAHCW.js} +1 -1
  2. package/dist/{chunk-VE3E4AMH.js → chunk-NLAWT4DT.js} +2 -2
  3. package/dist/{chunk-MNO4COST.js → chunk-WTXRY7R2.js} +3 -3
  4. package/dist/cli/index.js +9 -7
  5. package/dist/{conduct-WGTMQND5.js → conduct-6LKIJJKQ.js} +3 -3
  6. package/dist/{conduct-KM6ZNJGE.js → conduct-WU3VEXB6.js} +3 -3
  7. package/dist/{conductor-mode-OL2FNOYY.js → conductor-mode-Q4IIDY5E.js} +2 -2
  8. package/dist/{conductor-mode-VRO7TYW2.js → conductor-mode-ZMTFZGJP.js} +2 -2
  9. package/dist/index.js +2 -2
  10. package/dist/{request-YOWPXVLQ.js → request-VOXBFUOG.js} +4 -4
  11. package/dist/{server-WY7KWD3X.js → server-JVQW2TID.js} +2 -2
  12. package/dist/{service-coordinator-BXVY77J5.js → service-coordinator-EYRDTHL5.js} +2 -3
  13. package/dist/skills/agentbnb/bootstrap.js +4 -4
  14. package/openclaw.plugin.json +1 -1
  15. package/package.json +12 -18
  16. package/skills/agentbnb/SKILL.md +26 -1
  17. package/skills/agentbnb/install.sh +0 -0
  18. package/skills/deep-stock-analyst/package.json +0 -24
  19. package/skills/deep-stock-analyst/src/analysis/financial-health.ts +0 -167
  20. package/skills/deep-stock-analyst/src/analysis/sentiment.ts +0 -68
  21. package/skills/deep-stock-analyst/src/analysis/signal.ts +0 -188
  22. package/skills/deep-stock-analyst/src/analysis/technicals.ts +0 -318
  23. package/skills/deep-stock-analyst/src/analysis/utils.ts +0 -137
  24. package/skills/deep-stock-analyst/src/analysis/valuation.ts +0 -95
  25. package/skills/deep-stock-analyst/src/api/alpha-vantage.ts +0 -133
  26. package/skills/deep-stock-analyst/src/api/types.ts +0 -238
  27. package/skills/deep-stock-analyst/src/index.ts +0 -84
  28. package/skills/deep-stock-analyst/src/llm/thesis.ts +0 -101
  29. package/skills/deep-stock-analyst/src/orchestrator.ts +0 -228
  30. package/skills/deep-stock-analyst/tsconfig.json +0 -21
@@ -233,7 +233,7 @@ var AutoRequestor = class {
233
233
  gatewayUrl: peerConfig.url,
234
234
  token: peerConfig.token,
235
235
  cardId: top.card.id,
236
- params: top.skillId ? { skill_id: top.skillId, ...need.params } : need.params
236
+ params: top.skillId ? { skill_id: top.skillId, ...need.params, requester: this.owner } : { ...need.params, requester: this.owner }
237
237
  });
238
238
  settleEscrow(this.creditDb, escrowId, top.card.owner);
239
239
  if (tier === 2) {
@@ -7,10 +7,10 @@ import {
7
7
  decompose,
8
8
  matchSubTasks,
9
9
  orchestrate
10
- } from "./chunk-MNO4COST.js";
10
+ } from "./chunk-WTXRY7R2.js";
11
11
  import {
12
12
  BudgetManager
13
- } from "./chunk-BTTL24TZ.js";
13
+ } from "./chunk-EGUOAHCW.js";
14
14
  import {
15
15
  loadPeers
16
16
  } from "./chunk-5AH3CMOX.js";
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-3MJT4PZG.js";
4
4
  import {
5
5
  scorePeers
6
- } from "./chunk-BTTL24TZ.js";
6
+ } from "./chunk-EGUOAHCW.js";
7
7
  import {
8
8
  fetchRemoteCards
9
9
  } from "./chunk-ZX5623ER.js";
@@ -343,7 +343,7 @@ async function orchestrate(opts) {
343
343
  gatewayUrl: primary.url,
344
344
  token: gatewayToken,
345
345
  cardId: primary.cardId,
346
- params: interpolatedParams,
346
+ params: { ...interpolatedParams, requester: requesterOwner },
347
347
  timeoutMs
348
348
  });
349
349
  }
@@ -368,7 +368,7 @@ async function orchestrate(opts) {
368
368
  gatewayUrl: altAgent.url,
369
369
  token: gatewayToken,
370
370
  cardId: altAgent.cardId,
371
- params: interpolatedParams,
371
+ params: { ...interpolatedParams, requester: requesterOwner },
372
372
  timeoutMs
373
373
  });
374
374
  }
package/dist/cli/index.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  AutoRequestor,
18
18
  BudgetManager,
19
19
  DEFAULT_BUDGET_CONFIG
20
- } from "../chunk-BTTL24TZ.js";
20
+ } from "../chunk-EGUOAHCW.js";
21
21
  import {
22
22
  DEFAULT_AUTONOMY_CONFIG
23
23
  } from "../chunk-CSATDXZC.js";
@@ -571,14 +571,16 @@ function getLanIp() {
571
571
  }
572
572
  var program = new Command();
573
573
  program.name("agentbnb").description("P2P Agent Capability Sharing Protocol \u2014 Airbnb for AI agent pipelines").version(pkg.version);
574
- program.command("init").description("Initialize AgentBnB config and create agent identity").option("--owner <name>", "Agent owner name").option("--port <port>", "Gateway port", "7700").option("--host <ip>", "Override gateway host IP (default: auto-detected LAN IP)").option("--yes", "Auto-confirm all draft cards (non-interactive)").option("--no-detect", "Skip API key detection").option("--from <file>", "Parse a specific file for capability detection").option("--json", "Output as JSON").action(async (opts) => {
574
+ program.command("init").description("Initialize AgentBnB config and create agent identity").option("--owner <name>", "Agent owner name").option("--agent-id <id>", "Agent identity (alias for --owner, for genesis-template compat)").option("--port <port>", "Gateway port", "7700").option("--host <ip>", "Override gateway host IP (default: auto-detected LAN IP)").option("--yes", "Auto-confirm all draft cards (non-interactive)").option("--non-interactive", "Non-interactive mode (alias for --yes)").option("--no-detect", "Skip API key detection").option("--from <file>", "Parse a specific file for capability detection").option("--json", "Output as JSON").action(async (opts) => {
575
575
  const configDir = getConfigDir();
576
576
  const dbPath = join2(configDir, "registry.db");
577
577
  const creditDbPath = join2(configDir, "credit.db");
578
578
  const port = parseInt(opts.port, 10);
579
579
  const ip = opts.host ?? getLanIp();
580
+ const yesMode = opts.yes ?? opts.nonInteractive ?? false;
581
+ opts.yes = yesMode;
580
582
  const existingConfig = loadConfig();
581
- const owner = opts.owner ?? existingConfig?.owner ?? `agent-${randomBytes(4).toString("hex")}`;
583
+ const owner = opts.agentId ?? opts.owner ?? existingConfig?.owner ?? `agent-${randomBytes(4).toString("hex")}`;
582
584
  const config = {
583
585
  ...existingConfig,
584
586
  // Preserve all existing keys (registry, autonomy, budget, etc.)
@@ -1267,7 +1269,7 @@ Batch Results (${res.results.length} items):`);
1267
1269
  } finally {
1268
1270
  db.close();
1269
1271
  }
1270
- if (localCard) {
1272
+ if (localCard && localCard.owner === config.owner) {
1271
1273
  gatewayUrl = config.gateway_url;
1272
1274
  token = config.token;
1273
1275
  } else {
@@ -1559,7 +1561,7 @@ program.command("serve").description("Start the AgentBnB gateway server").option
1559
1561
  process.exit(1);
1560
1562
  }
1561
1563
  const { ProcessGuard } = await import("../process-guard-CC7CNRQJ.js");
1562
- const { ServiceCoordinator } = await import("../service-coordinator-BXVY77J5.js");
1564
+ const { ServiceCoordinator } = await import("../service-coordinator-EYRDTHL5.js");
1563
1565
  const port = opts.port ? parseInt(opts.port, 10) : config.gateway_port;
1564
1566
  const registryPort = parseInt(opts.registryPort, 10);
1565
1567
  if (!Number.isFinite(port) || !Number.isFinite(registryPort)) {
@@ -1817,7 +1819,7 @@ openclaw.command("rules").description("Print HEARTBEAT.md rules block (or inject
1817
1819
  }
1818
1820
  });
1819
1821
  program.command("conduct <task>").description("Orchestrate a complex task across the AgentBnB network").option("--plan-only", "Show execution plan without executing").option("--max-budget <credits>", "Maximum credits to spend", "100").option("--json", "Output as JSON").action(async (task, opts) => {
1820
- const { conductAction } = await import("../conduct-WGTMQND5.js");
1822
+ const { conductAction } = await import("../conduct-6LKIJJKQ.js");
1821
1823
  const result = await conductAction(task, opts);
1822
1824
  if (opts.json) {
1823
1825
  console.log(JSON.stringify(result, null, 2));
@@ -1928,7 +1930,7 @@ Feedback for skill: ${opts.skill} (${feedbacks.length} entries)
1928
1930
  }
1929
1931
  });
1930
1932
  program.command("mcp-server").description("Start an MCP (Model Context Protocol) server for IDE integration").action(async () => {
1931
- const { startMcpServer } = await import("../server-WY7KWD3X.js");
1933
+ const { startMcpServer } = await import("../server-JVQW2TID.js");
1932
1934
  await startMcpServer();
1933
1935
  });
1934
1936
  await program.parseAsync(process.argv);
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  conductAction
3
- } from "./chunk-VE3E4AMH.js";
3
+ } from "./chunk-NLAWT4DT.js";
4
4
  import "./chunk-JOY533UH.js";
5
5
  import "./chunk-QT7TEVNV.js";
6
- import "./chunk-MNO4COST.js";
6
+ import "./chunk-WTXRY7R2.js";
7
7
  import "./chunk-3MJT4PZG.js";
8
- import "./chunk-BTTL24TZ.js";
8
+ import "./chunk-EGUOAHCW.js";
9
9
  import "./chunk-CSATDXZC.js";
10
10
  import "./chunk-ZX5623ER.js";
11
11
  import "./chunk-NH2FIERR.js";
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  conductAction
3
- } from "./chunk-VE3E4AMH.js";
3
+ } from "./chunk-NLAWT4DT.js";
4
4
  import "./chunk-JOY533UH.js";
5
5
  import "./chunk-QT7TEVNV.js";
6
- import "./chunk-MNO4COST.js";
6
+ import "./chunk-WTXRY7R2.js";
7
7
  import "./chunk-3MJT4PZG.js";
8
- import "./chunk-BTTL24TZ.js";
8
+ import "./chunk-EGUOAHCW.js";
9
9
  import "./chunk-CSATDXZC.js";
10
10
  import "./chunk-ZX5623ER.js";
11
11
  import "./chunk-NH2FIERR.js";
@@ -3,11 +3,11 @@ import {
3
3
  decompose,
4
4
  matchSubTasks,
5
5
  orchestrate
6
- } from "./chunk-MNO4COST.js";
6
+ } from "./chunk-WTXRY7R2.js";
7
7
  import "./chunk-3MJT4PZG.js";
8
8
  import {
9
9
  BudgetManager
10
- } from "./chunk-BTTL24TZ.js";
10
+ } from "./chunk-EGUOAHCW.js";
11
11
  import "./chunk-CSATDXZC.js";
12
12
  import "./chunk-ZX5623ER.js";
13
13
  import "./chunk-NH2FIERR.js";
@@ -426,7 +426,7 @@ async function orchestrate(opts) {
426
426
  gatewayUrl: primary.url,
427
427
  token: gatewayToken,
428
428
  cardId: primary.cardId,
429
- params: interpolatedParams,
429
+ params: { ...interpolatedParams, requester: requesterOwner },
430
430
  timeoutMs
431
431
  });
432
432
  }
@@ -451,7 +451,7 @@ async function orchestrate(opts) {
451
451
  gatewayUrl: altAgent.url,
452
452
  token: gatewayToken,
453
453
  cardId: altAgent.cardId,
454
- params: interpolatedParams,
454
+ params: { ...interpolatedParams, requester: requesterOwner },
455
455
  timeoutMs
456
456
  });
457
457
  }
package/dist/index.js CHANGED
@@ -2637,7 +2637,7 @@ async function orchestrate(opts) {
2637
2637
  gatewayUrl: primary.url,
2638
2638
  token: gatewayToken,
2639
2639
  cardId: primary.cardId,
2640
- params: interpolatedParams,
2640
+ params: { ...interpolatedParams, requester: requesterOwner },
2641
2641
  timeoutMs
2642
2642
  });
2643
2643
  }
@@ -2662,7 +2662,7 @@ async function orchestrate(opts) {
2662
2662
  gatewayUrl: altAgent.url,
2663
2663
  token: gatewayToken,
2664
2664
  cardId: altAgent.cardId,
2665
- params: interpolatedParams,
2665
+ params: { ...interpolatedParams, requester: requesterOwner },
2666
2666
  timeoutMs
2667
2667
  });
2668
2668
  }
@@ -9,7 +9,7 @@ import {
9
9
  AutoRequestor,
10
10
  BudgetManager,
11
11
  DEFAULT_BUDGET_CONFIG
12
- } from "./chunk-BTTL24TZ.js";
12
+ } from "./chunk-EGUOAHCW.js";
13
13
  import {
14
14
  DEFAULT_AUTONOMY_CONFIG
15
15
  } from "./chunk-CSATDXZC.js";
@@ -87,12 +87,12 @@ async function handleRequest(args, ctx) {
87
87
  } finally {
88
88
  db.close();
89
89
  }
90
- if (localCard) {
90
+ if (localCard && localCard.owner === ctx.config.owner) {
91
91
  const result = await requestCapability({
92
92
  gatewayUrl: ctx.config.gateway_url,
93
93
  token: ctx.config.token,
94
94
  cardId,
95
- params: { ...args.params ?? {}, ...args.skill_id ? { skill_id: args.skill_id } : {} }
95
+ params: { ...args.params ?? {}, ...args.skill_id ? { skill_id: args.skill_id } : {}, requester: ctx.config.owner }
96
96
  });
97
97
  return {
98
98
  content: [{ type: "text", text: JSON.stringify({ success: true, result }, null, 2) }]
@@ -134,7 +134,7 @@ async function handleRequest(args, ctx) {
134
134
  gatewayUrl,
135
135
  token: "",
136
136
  cardId,
137
- params: { ...args.params ?? {}, ...args.skill_id ? { skill_id: args.skill_id } : {} }
137
+ params: { ...args.params ?? {}, ...args.skill_id ? { skill_id: args.skill_id } : {}, requester: ctx.config.owner }
138
138
  });
139
139
  await ledger.settle(escrowId, targetOwner ?? "unknown");
140
140
  return {
@@ -275,8 +275,8 @@ async function startMcpServer() {
275
275
  registerDiscoverTool(server, ctx);
276
276
  registerStatusTool(server, ctx);
277
277
  registerPublishTool(server, ctx);
278
- const { registerRequestTool } = await import("./request-YOWPXVLQ.js");
279
- const { registerConductTool } = await import("./conduct-KM6ZNJGE.js");
278
+ const { registerRequestTool } = await import("./request-VOXBFUOG.js");
279
+ const { registerConductTool } = await import("./conduct-WU3VEXB6.js");
280
280
  const { registerServeSkillTool } = await import("./serve-skill-IH7UAJNR.js");
281
281
  registerRequestTool(server, ctx);
282
282
  registerConductTool(server, ctx);
@@ -914,7 +914,7 @@ var AgentRuntime = class {
914
914
  }
915
915
  const modes = /* @__PURE__ */ new Map();
916
916
  if (this.conductorEnabled) {
917
- const { ConductorMode } = await import("./conductor-mode-OL2FNOYY.js");
917
+ const { ConductorMode } = await import("./conductor-mode-Q4IIDY5E.js");
918
918
  const { registerConductorCard, CONDUCTOR_OWNER } = await import("./card-RSGDCHCV.js");
919
919
  const { loadPeers } = await import("./peers-K7FSHPN3.js");
920
920
  registerConductorCard(this.registryDb);
@@ -4400,7 +4400,6 @@ import { createRequire } from "module";
4400
4400
  import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
4401
4401
  import { fileURLToPath as fileURLToPath2 } from "url";
4402
4402
  import { dirname as dirname2, join as join2, resolve } from "path";
4403
- import { homedir } from "os";
4404
4403
  import { randomUUID as randomUUID5 } from "crypto";
4405
4404
  var ServiceCoordinator = class {
4406
4405
  config;
@@ -4517,7 +4516,7 @@ var ServiceCoordinator = class {
4517
4516
  return {
4518
4517
  port: opts?.port ?? this.config.gateway_port,
4519
4518
  handlerUrl: opts?.handlerUrl ?? "http://localhost:8080",
4520
- skillsYamlPath: opts?.skillsYamlPath ?? join2(homedir(), ".agentbnb", "skills.yaml"),
4519
+ skillsYamlPath: opts?.skillsYamlPath ?? join2(getConfigDir(), "skills.yaml"),
4521
4520
  registryPort: opts?.registryPort ?? 7701,
4522
4521
  registryUrl: opts?.registryUrl ?? this.config.registry ?? "",
4523
4522
  relay: opts?.relay ?? true,
@@ -1071,7 +1071,7 @@ var AgentRuntime = class {
1071
1071
  }
1072
1072
  const modes = /* @__PURE__ */ new Map();
1073
1073
  if (this.conductorEnabled) {
1074
- const { ConductorMode } = await import("../../conductor-mode-VRO7TYW2.js");
1074
+ const { ConductorMode } = await import("../../conductor-mode-ZMTFZGJP.js");
1075
1075
  const { registerConductorCard, CONDUCTOR_OWNER } = await import("../../card-RSGDCHCV.js");
1076
1076
  const { loadPeers } = await import("../../peers-CJ7T4RJO.js");
1077
1077
  registerConductorCard(this.registryDb);
@@ -5238,7 +5238,6 @@ import { createRequire } from "module";
5238
5238
  import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
5239
5239
  import { fileURLToPath as fileURLToPath2 } from "url";
5240
5240
  import { dirname as dirname3, join as join4, resolve } from "path";
5241
- import { homedir as homedir2 } from "os";
5242
5241
  import { randomUUID as randomUUID6 } from "crypto";
5243
5242
  var ServiceCoordinator = class {
5244
5243
  config;
@@ -5355,7 +5354,7 @@ var ServiceCoordinator = class {
5355
5354
  return {
5356
5355
  port: opts?.port ?? this.config.gateway_port,
5357
5356
  handlerUrl: opts?.handlerUrl ?? "http://localhost:8080",
5358
- skillsYamlPath: opts?.skillsYamlPath ?? join4(homedir2(), ".agentbnb", "skills.yaml"),
5357
+ skillsYamlPath: opts?.skillsYamlPath ?? join4(getConfigDir(), "skills.yaml"),
5359
5358
  registryPort: opts?.registryPort ?? 7701,
5360
5359
  registryUrl: opts?.registryUrl ?? this.config.registry ?? "",
5361
5360
  relay: opts?.relay ?? true,
@@ -5868,7 +5867,8 @@ var AgentBnBService = class {
5868
5867
  try {
5869
5868
  const requestParams = {
5870
5869
  ...params.taskParams,
5871
- ...params.skillId ? { skill_id: params.skillId } : {}
5870
+ ...params.skillId ? { skill_id: params.skillId } : {},
5871
+ requester: this.config.owner
5872
5872
  };
5873
5873
  let result;
5874
5874
  if (!target.gatewayUrl) {
@@ -2,7 +2,7 @@
2
2
  "id": "agentbnb",
3
3
  "name": "AgentBnB",
4
4
  "description": "P2P agent capability sharing — join the network, share idle skills, earn credits, and access capabilities from peers. Agents run autonomously on their own will.",
5
- "version": "4.0.3",
5
+ "version": "5.1.11",
6
6
  "kind": "tools",
7
7
  "configSchema": {
8
8
  "type": "object",
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "workspaces": [
4
4
  "packages/*"
5
5
  ],
6
- "version": "5.1.9",
6
+ "version": "5.1.11",
7
7
  "description": "P2P Agent Capability Sharing Protocol — Airbnb for AI agent pipelines",
8
8
  "type": "module",
9
9
  "main": "dist/index.js",
@@ -15,7 +15,7 @@
15
15
  "dist",
16
16
  "README.md",
17
17
  "LICENSE",
18
- "skills",
18
+ "skills/agentbnb",
19
19
  "openclaw.plugin.json"
20
20
  ],
21
21
  "exports": {
@@ -32,17 +32,6 @@
32
32
  "import": "./dist/identity/index.js"
33
33
  }
34
34
  },
35
- "scripts": {
36
- "build": "tsup",
37
- "build:hub": "cd hub && pnpm install && pnpm build",
38
- "build:all": "pnpm build && pnpm build:hub",
39
- "dev": "tsx watch src/cli/index.ts",
40
- "test": "vitest",
41
- "test:run": "vitest run",
42
- "lint": "eslint src/",
43
- "typecheck": "tsc --noEmit",
44
- "prepublishOnly": "pnpm run build && pnpm run typecheck && pnpm run test:run"
45
- },
46
35
  "keywords": [
47
36
  "ai",
48
37
  "agent",
@@ -91,9 +80,14 @@
91
80
  "engines": {
92
81
  "node": ">=20.0.0"
93
82
  },
94
- "pnpm": {
95
- "onlyBuiltDependencies": [
96
- "better-sqlite3"
97
- ]
83
+ "scripts": {
84
+ "build": "tsup",
85
+ "build:hub": "cd hub && pnpm install && pnpm build",
86
+ "build:all": "pnpm build && pnpm build:hub",
87
+ "dev": "tsx watch src/cli/index.ts",
88
+ "test": "vitest",
89
+ "test:run": "vitest run",
90
+ "lint": "eslint src/",
91
+ "typecheck": "tsc --noEmit"
98
92
  }
99
- }
93
+ }
@@ -5,12 +5,37 @@ license: MIT
5
5
  compatibility: "Requires Node.js >= 20 and pnpm. Designed for OpenClaw agents. Compatible with Claude Code, Gemini CLI, and other AgentSkills-compatible tools."
6
6
  metadata:
7
7
  author: "Cheng Wen Chen"
8
- version: "5.1.9"
8
+ version: "5.1.11"
9
9
  tags: "ai-agent-skill,claude-code,agent-skills,p2p,capability-sharing"
10
+ openclaw:
11
+ emoji: "🏠"
12
+ homepage: "https://agentbnb.dev"
13
+ requires:
14
+ bins:
15
+ - node
16
+ install:
17
+ - type: node
18
+ pkg: agentbnb
19
+ bins:
20
+ - agentbnb
10
21
  ---
11
22
 
12
23
  This skill connects your agent to the AgentBnB P2P capability sharing network.
13
24
 
25
+ ## Security & Permissions
26
+
27
+ This skill requires elevated installation permissions. Here is exactly what it does and why:
28
+
29
+ | Action | Why | Scope |
30
+ |--------|-----|-------|
31
+ | `npm install -g agentbnb` | Installs the AgentBnB CLI globally for all agent commands | One-time install |
32
+ | Creates `~/.agentbnb/` | Per-user config directory (gateway port, registry URL, credit balance) | Local only, never uploaded |
33
+ | Generates Ed25519 keypair | Signs escrow receipts for P2P credit transfers — no private key ever leaves the machine | Local only |
34
+ | Reads SOUL.md → publishes capability card | Agent declares its skills to the network. **Only runs if SOUL.md exists.** Opt-in. | Public registry |
35
+ | Persists `~/.agentbnb/runtime.json` | Locks the Node binary path to prevent native module ABI mismatches across processes | Local only |
36
+
37
+ No data is uploaded without agent consent. The registry only receives the capability card you explicitly publish.
38
+
14
39
  ## Quick Start
15
40
 
16
41
  **Step 1: Run the install script.**
File without changes
@@ -1,24 +0,0 @@
1
- {
2
- "name": "@agentbnb/skill-deep-stock-analyst",
3
- "version": "1.0.0",
4
- "description": "Deep quantitative stock analysis: 12-endpoint Alpha Vantage pipeline + 5 analysis modules + Gemini thesis",
5
- "type": "module",
6
- "main": "dist/index.js",
7
- "scripts": {
8
- "build": "tsc",
9
- "start": "node dist/index.js",
10
- "test": "node --experimental-vm-modules node_modules/.bin/jest --testPathPattern=tests/",
11
- "dev": "tsx src/index.ts"
12
- },
13
- "dependencies": {
14
- "@google/generative-ai": "^0.21.0"
15
- },
16
- "devDependencies": {
17
- "@types/node": "^22.0.0",
18
- "typescript": "^5.5.0",
19
- "tsx": "^4.19.0"
20
- },
21
- "engines": {
22
- "node": ">=20.0.0"
23
- }
24
- }
@@ -1,167 +0,0 @@
1
- import type {
2
- AVOverview,
3
- AVIncomeStatement,
4
- AVBalanceSheet,
5
- AVCashFlow,
6
- AVEarnings,
7
- } from '../api/types.js';
8
- import {
9
- scoreMetric,
10
- scoreMetricInverse,
11
- weightedAvg,
12
- calcYoYGrowth,
13
- scoreGrowth,
14
- scoreSurprise,
15
- countConsecutiveBeats,
16
- sp,
17
- } from './utils.js';
18
-
19
- export interface FinancialHealth {
20
- profitability_score: number;
21
- growth_score: number;
22
- leverage_score: number;
23
- efficiency_score: number;
24
- composite: number;
25
- red_flags: string[];
26
- green_flags: string[];
27
- raw: {
28
- grossMarginPct: number;
29
- operatingMarginPct: number;
30
- netMarginPct: number;
31
- roe: number;
32
- debtToEquity: number;
33
- currentRatio: number;
34
- revenueGrowthPct: number;
35
- earningsGrowthPct: number;
36
- lastSurpisePct: number;
37
- consecutiveBeats: number;
38
- };
39
- }
40
-
41
- function calcInterestCoverage(report: AVIncomeStatement['annualReports'][number] | undefined): number {
42
- if (!report) return 5;
43
- const ebit = sp(report.ebit);
44
- const interest = sp(report.interestExpense);
45
- if (interest === 0) return 10; // no debt
46
- return Math.abs(ebit / interest);
47
- }
48
-
49
- function calcROIC(
50
- income: AVIncomeStatement['annualReports'][number] | undefined,
51
- balance: AVBalanceSheet['annualReports'][number] | undefined,
52
- ): number {
53
- if (!income || !balance) return 0;
54
- const nopat = sp(income.ebit) * 0.79; // rough 21% tax
55
- const investedCapital =
56
- sp(balance.totalShareholderEquity) + sp(balance.longTermDebt) + sp(balance.shortTermDebt);
57
- if (investedCapital === 0) return 0;
58
- return nopat / investedCapital;
59
- }
60
-
61
- export function analyzeFinancialHealth(
62
- overview: AVOverview,
63
- income: AVIncomeStatement,
64
- balance: AVBalanceSheet,
65
- cashflow: AVCashFlow,
66
- earnings: AVEarnings,
67
- ): FinancialHealth {
68
- const red_flags: string[] = [];
69
- const green_flags: string[] = [];
70
-
71
- // === Profitability ===
72
- const grossProfit = sp(overview.GrossProfitTTM);
73
- const revenue = sp(overview.RevenueTTM);
74
- const grossMarginPct = revenue > 0 ? (grossProfit / revenue) * 100 : 0;
75
- const operatingMarginPct = sp(overview.OperatingMarginTTM) * 100;
76
- const netMarginPct = sp(overview.ProfitMargin) * 100;
77
- const roe = sp(overview.ReturnOnEquityTTM) * 100;
78
-
79
- if (grossMarginPct > 60) green_flags.push(`Gross margin ${grossMarginPct.toFixed(1)}% — strong pricing power`);
80
- if (netMarginPct < 0) red_flags.push(`Net margin negative at ${netMarginPct.toFixed(1)}%`);
81
- if (roe > 20) green_flags.push(`ROE ${roe.toFixed(1)}% — excellent capital efficiency`);
82
- if (roe < 0) red_flags.push(`ROE negative at ${roe.toFixed(1)}% — destroying shareholder value`);
83
-
84
- const profitability_score = weightedAvg([
85
- [scoreMetricInverse(grossMarginPct, { excellent: 60, good: 40, fair: 25, poor: 10 }), 0.30],
86
- [scoreMetricInverse(operatingMarginPct, { excellent: 25, good: 15, fair: 8, poor: 0 }), 0.35],
87
- [scoreMetricInverse(roe, { excellent: 25, good: 15, fair: 8, poor: 0 }), 0.35],
88
- ]);
89
-
90
- // === Growth ===
91
- const revenueGrowthPct = calcYoYGrowth(income.quarterlyReports, 'totalRevenue');
92
- const earningsGrowthPct = calcYoYGrowth(income.quarterlyReports, 'netIncome');
93
- const fcfGrowthPct = calcYoYGrowth(cashflow.quarterlyReports, 'operatingCashflow');
94
-
95
- const lastEarnings = earnings.quarterlyEarnings[0];
96
- const lastSurpisePct = sp(lastEarnings?.surprisePercentage);
97
- if (lastSurpisePct > 10) green_flags.push(`Last earnings beat estimates by ${lastSurpisePct.toFixed(1)}%`);
98
- if (lastSurpisePct < -10) red_flags.push(`Last earnings missed estimates by ${Math.abs(lastSurpisePct).toFixed(1)}%`);
99
-
100
- const consecutiveBeats = countConsecutiveBeats(earnings.quarterlyEarnings);
101
- if (consecutiveBeats >= 4) green_flags.push(`${consecutiveBeats} consecutive quarters of earnings beats`);
102
- if (revenueGrowthPct > 20) green_flags.push(`Revenue growing ${revenueGrowthPct.toFixed(1)}% YoY`);
103
- if (revenueGrowthPct < -10) red_flags.push(`Revenue declining ${Math.abs(revenueGrowthPct).toFixed(1)}% YoY`);
104
-
105
- const growth_score = weightedAvg([
106
- [scoreGrowth(revenueGrowthPct), 0.35],
107
- [scoreGrowth(earningsGrowthPct), 0.35],
108
- [scoreGrowth(fcfGrowthPct), 0.20],
109
- [scoreSurprise(lastSurpisePct), 0.10],
110
- ]);
111
-
112
- // === Leverage ===
113
- const debtToEquity = sp(overview.DebtToEquity);
114
- const currentRatio = sp(overview.CurrentRatio);
115
- const interestCoverage = calcInterestCoverage(income.annualReports[0]);
116
-
117
- if (debtToEquity > 2.0) red_flags.push(`Debt/Equity ${debtToEquity.toFixed(2)} — heavily leveraged`);
118
- if (currentRatio < 1.0) red_flags.push(`Current ratio ${currentRatio.toFixed(2)} — potential liquidity risk`);
119
- if (currentRatio > 2.0) green_flags.push(`Current ratio ${currentRatio.toFixed(2)} — strong liquidity`);
120
- if (interestCoverage < 2.0) red_flags.push(`Interest coverage ${interestCoverage.toFixed(1)}x — thin margin`);
121
- if (debtToEquity < 0.3) green_flags.push(`Low leverage: Debt/Equity ${debtToEquity.toFixed(2)}`);
122
-
123
- const leverage_score = weightedAvg([
124
- [scoreMetric(debtToEquity, { excellent: 0.3, good: 0.8, fair: 1.5, poor: 3.0 }), 0.40],
125
- [scoreMetricInverse(currentRatio, { excellent: 2.5, good: 1.5, fair: 1.0, poor: 0.5 }), 0.30],
126
- [scoreMetricInverse(interestCoverage, { excellent: 10, good: 5, fair: 2, poor: 1 }), 0.30],
127
- ]);
128
-
129
- // === Efficiency ===
130
- const totalAssets = sp(balance.annualReports[0]?.totalAssets);
131
- const assetTurnover = totalAssets > 0 ? revenue / totalAssets : 0;
132
- const roic = calcROIC(income.annualReports[0], balance.annualReports[0]);
133
-
134
- const efficiency_score = weightedAvg([
135
- [scoreMetricInverse(assetTurnover, { excellent: 1.5, good: 1.0, fair: 0.5, poor: 0.2 }), 0.50],
136
- [scoreMetricInverse(roic * 100, { excellent: 20, good: 12, fair: 7, poor: 0 }), 0.50],
137
- ]);
138
-
139
- const composite = weightedAvg([
140
- [profitability_score, 0.30],
141
- [growth_score, 0.30],
142
- [leverage_score, 0.20],
143
- [efficiency_score, 0.20],
144
- ]);
145
-
146
- return {
147
- profitability_score,
148
- growth_score,
149
- leverage_score,
150
- efficiency_score,
151
- composite,
152
- red_flags,
153
- green_flags,
154
- raw: {
155
- grossMarginPct,
156
- operatingMarginPct,
157
- netMarginPct,
158
- roe,
159
- debtToEquity,
160
- currentRatio,
161
- revenueGrowthPct,
162
- earningsGrowthPct,
163
- lastSurpisePct,
164
- consecutiveBeats,
165
- },
166
- };
167
- }