moshcode 0.29.0 → 0.29.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/README.md +18 -5
- package/package.json +1 -1
- package/plugins/crypto/README.md +15 -9
- package/plugins/crypto/commands/coin.md +1 -1
- package/plugins/crypto/commands/crypto.md +2 -2
- package/plugins/crypto/commands/pairs.md +1 -1
- package/plugins/crypto/commands/spark.md +1 -1
- package/plugins/stocks/README.md +17 -8
- package/plugins/stocks/commands/lookup.md +1 -1
- package/plugins/stocks/commands/reports.md +1 -1
- package/plugins/stocks/commands/research.md +1 -1
- package/src/crypto.mjs +5 -1
- package/src/integrations.mjs +1 -1
- package/src/plugins.mjs +40 -6
package/README.md
CHANGED
|
@@ -376,30 +376,43 @@ moshcode plugin install crypto # add the marketplace + install `crypto`
|
|
|
376
376
|
moshcode plugin remove stocks # take it back off
|
|
377
377
|
```
|
|
378
378
|
|
|
379
|
-
`stocks@moshcode` adds `/stocks`, `/signals`, `/research`,
|
|
380
|
-
`/reports`, and `/discover` — the same advis0r research surface described above,
|
|
379
|
+
`stocks@moshcode` adds `/stocks:stocks`, `/stocks:signals`, `/stocks:research`,
|
|
380
|
+
`/stocks:lookup`, `/stocks:reports`, and `/stocks:discover` — the same advis0r research surface described above,
|
|
381
381
|
driven from inside a coding session.
|
|
382
382
|
|
|
383
|
-
`crypto@moshcode` adds `/crypto`, `/quote`, `/book`,
|
|
384
|
-
`/pairs`, and `/coin`. It ships separately because it is a different surface,
|
|
383
|
+
`crypto@moshcode` adds `/crypto:crypto`, `/crypto:quote`, `/crypto:book`,
|
|
384
|
+
`/crypto:bars`, `/crypto:spark`, `/crypto:pairs`, and `/crypto:coin`. It ships separately because it is a different surface,
|
|
385
385
|
not a mode of the first: live venue reads instead of stored snapshots, and a
|
|
386
386
|
score that must not be ranked against an equity's.
|
|
387
387
|
|
|
388
388
|
Restart the engine after installing either; a newly installed plugin is not live
|
|
389
389
|
in a session that is already running.
|
|
390
390
|
|
|
391
|
+
Plugin commands are namespaced `/<plugin>:<command>` — always, not only when two
|
|
392
|
+
plugins collide — so it is `/stocks:signals AAPL`, and a bare `/signals` answers
|
|
393
|
+
`Unknown command`. Typing `/` and picking from the menu inserts the right form.
|
|
394
|
+
This is the one place the two surfaces differ: inside the moshcode pit the same
|
|
395
|
+
research is plain `/stocks …` and `/crypto …`, because those are moshcode's own
|
|
396
|
+
commands rather than a plugin's.
|
|
397
|
+
|
|
391
398
|
The equivalent by hand:
|
|
392
399
|
|
|
393
400
|
```sh
|
|
394
401
|
claude plugin marketplace add moshcoder/moshcode
|
|
402
|
+
claude plugin marketplace update moshcode # `add` is a no-op if you already have it
|
|
395
403
|
claude plugin install stocks@moshcode
|
|
396
404
|
claude plugin install crypto@moshcode
|
|
397
405
|
```
|
|
398
406
|
|
|
407
|
+
The `update` line matters if you have ever installed from this marketplace
|
|
408
|
+
before: `add` declines to do anything for a marketplace already on disk, so
|
|
409
|
+
without a refresh the install reads a stale copy and fails with "not found in
|
|
410
|
+
any marketplace". `moshcode plugin install` runs both steps for you.
|
|
411
|
+
|
|
399
412
|
### Upgrading from `ticker@moshcode`
|
|
400
413
|
|
|
401
414
|
`stocks` was called `ticker` before v0.29.0. Installing the new id does **not**
|
|
402
|
-
replace the old one — engines install plugins side by side, so `/stocks` would
|
|
415
|
+
replace the old one — engines install plugins side by side, so `/stocks:stocks` would
|
|
403
416
|
come from two plugins at once. Remove the old id first:
|
|
404
417
|
|
|
405
418
|
```sh
|
package/package.json
CHANGED
package/plugins/crypto/README.md
CHANGED
|
@@ -6,17 +6,22 @@ across Alpaca's US crypto venue.
|
|
|
6
6
|
|
|
7
7
|
| command | what it does |
|
|
8
8
|
| --- | --- |
|
|
9
|
-
| `/crypto BTC` | price, technicals, score, supply, order book |
|
|
10
|
-
| `/quote ETH-USD` | latest trade and quote, with the spread in bps |
|
|
11
|
-
| `/book BTC-USD` | top of the order book, both sides |
|
|
12
|
-
| `/bars ETH-USD` | historical OHLCV at any supported timeframe |
|
|
13
|
-
| `/spark BTC ETH SOL` | recent moves across pairs, ranked |
|
|
14
|
-
| `/pairs` | every supported pair, grouped by quote asset |
|
|
15
|
-
| `/coin bitcoin` | asset name → `BTC/USD` |
|
|
9
|
+
| `/crypto:crypto BTC` | price, technicals, score, supply, order book |
|
|
10
|
+
| `/crypto:quote ETH-USD` | latest trade and quote, with the spread in bps |
|
|
11
|
+
| `/crypto:book BTC-USD` | top of the order book, both sides |
|
|
12
|
+
| `/crypto:bars ETH-USD` | historical OHLCV at any supported timeframe |
|
|
13
|
+
| `/crypto:spark BTC ETH SOL` | recent moves across pairs, ranked |
|
|
14
|
+
| `/crypto:pairs` | every supported pair, grouped by quote asset |
|
|
15
|
+
| `/crypto:coin bitcoin` | asset name → `BTC/USD` |
|
|
16
16
|
|
|
17
17
|
Pairs are accepted as `BTC`, `BTC-USD`, `BTC/USD` or `BTCUSD`. A bare asset
|
|
18
18
|
resolves to that asset's USD pair.
|
|
19
19
|
|
|
20
|
+
The `crypto:` prefix is not optional. Claude Code namespaces every plugin
|
|
21
|
+
command as `/<plugin>:<command>` — always, not only when two plugins collide —
|
|
22
|
+
so a bare `/crypto` answers `Unknown command`. Typing `/` and picking from the
|
|
23
|
+
menu inserts the right form for you.
|
|
24
|
+
|
|
20
25
|
## Install
|
|
21
26
|
|
|
22
27
|
```bash
|
|
@@ -27,6 +32,7 @@ Or straight from Claude Code:
|
|
|
27
32
|
|
|
28
33
|
```bash
|
|
29
34
|
claude plugin marketplace add moshcoder/moshcode
|
|
35
|
+
claude plugin marketplace update moshcode # `add` is a no-op if you already have it
|
|
30
36
|
claude plugin install crypto@moshcode
|
|
31
37
|
```
|
|
32
38
|
|
|
@@ -44,9 +50,9 @@ Point the commands at another instance with `MOSHCODE_ADVISOR_URL`.
|
|
|
44
50
|
## Why this is separate from `stocks`
|
|
45
51
|
|
|
46
52
|
They answer different questions from different data, and share only a hostname.
|
|
47
|
-
A `/stocks` report is a **stored snapshot** built from transcripts, SEC
|
|
53
|
+
A `/stocks:stocks` report is a **stored snapshot** built from transcripts, SEC
|
|
48
54
|
fundamentals and extracted signals — its risk is a stale price read as a live
|
|
49
|
-
one. A `/crypto` report is a **live venue read** with no transcripts, no
|
|
55
|
+
one. A `/crypto:crypto` report is a **live venue read** with no transcripts, no
|
|
50
56
|
filings and no signals — its risk is the opposite: a price that is accurate to
|
|
51
57
|
the second and stale by the time you act on it.
|
|
52
58
|
|
|
@@ -28,4 +28,4 @@ Fallback: `curl -sS "https://advis0r.com/api/crypto/lookup?q=<url-encoded>&limit
|
|
|
28
28
|
match is the one they meant.
|
|
29
29
|
- No match: say this venue lists no such pair, and do not invent a symbol. The
|
|
30
30
|
coin may exist and simply not be listed here — those are different answers.
|
|
31
|
-
- Offer `/crypto <PAIR>` for the match you land on.
|
|
31
|
+
- Offer `/crypto:crypto <PAIR>` for the match you land on.
|
|
@@ -42,9 +42,9 @@ resolves to that asset's USD pair.
|
|
|
42
42
|
- Crypto trades 24/7 with no circuit breakers and no market close. Never
|
|
43
43
|
describe a crypto price as "at the close" or "premarket".
|
|
44
44
|
- State `generatedAt` / `fetchedAt`. This is a live read, so it goes stale in
|
|
45
|
-
seconds, not days — the opposite failure mode from a stored `/stocks` report.
|
|
45
|
+
seconds, not days — the opposite failure mode from a stored `/stocks:stocks` report.
|
|
46
46
|
- The score's liquidity component counts venue-local volume only, so it is
|
|
47
|
-
**not comparable** to an equity's score from `/stocks`. Do not rank the two
|
|
47
|
+
**not comparable** to an equity's score from `/stocks:stocks`. Do not rank the two
|
|
48
48
|
against each other.
|
|
49
49
|
- End with the response's own `disclaimer`. This is research, not advice.
|
|
50
50
|
- Link the shareable page: `https://advis0r.com/crypto/<PAIR>`.
|
|
@@ -25,7 +25,7 @@ URL-safe spelling (`BTC-USD`) used in paths; `symbol` is canonical (`BTC/USD`).
|
|
|
25
25
|
different markets with three different liquidity profiles.
|
|
26
26
|
- **`idle` means listed but not currently printing trades** — it is not the same
|
|
27
27
|
as unsupported. Show idle pairs, marked, rather than filtering them out.
|
|
28
|
-
- If the user was looking for a specific coin, use `/coin <name>` instead of
|
|
28
|
+
- If the user was looking for a specific coin, use `/crypto:coin <name>` instead of
|
|
29
29
|
scanning this list for them.
|
|
30
30
|
- This is the coverage of one venue, not of crypto. A coin missing here is
|
|
31
31
|
missing *from Alpaca's US venue*.
|
|
@@ -32,5 +32,5 @@ Fallback: `curl -sS "https://advis0r.com/api/crypto/sparklines?symbols=BTC-USD,E
|
|
|
32
32
|
- Name the window (`start` → `end`) and the period. "Up 5%" over 24h and over 7d
|
|
33
33
|
are different claims.
|
|
34
34
|
- Do not extrapolate a trend from 24 points, and do not call a direction
|
|
35
|
-
"momentum" without the technicals to back it — `/crypto <PAIR>` has those.
|
|
35
|
+
"momentum" without the technicals to back it — `/crypto:crypto <PAIR>` has those.
|
|
36
36
|
- End with the response's own `disclaimer`.
|
package/plugins/stocks/README.md
CHANGED
|
@@ -6,21 +6,29 @@ and ranked watchlists.
|
|
|
6
6
|
|
|
7
7
|
| command | what it does |
|
|
8
8
|
| --- | --- |
|
|
9
|
-
| `/stocks NVDA` | score, technicals, fundamentals, thesis, signals, sources |
|
|
10
|
-
| `/signals AAPL` | what was actually said, quoted and sourced |
|
|
11
|
-
| `/research data center` | full-text search across every indexed transcript |
|
|
12
|
-
| `/lookup rivian` | company name → `RIVN` |
|
|
13
|
-
| `/reports` | every stored report, best score first |
|
|
14
|
-
| `/discover fusion` | a ranked watchlist for a topic (slow) |
|
|
9
|
+
| `/stocks:stocks NVDA` | score, technicals, fundamentals, thesis, signals, sources |
|
|
10
|
+
| `/stocks:signals AAPL` | what was actually said, quoted and sourced |
|
|
11
|
+
| `/stocks:research data center` | full-text search across every indexed transcript |
|
|
12
|
+
| `/stocks:lookup rivian` | company name → `RIVN` |
|
|
13
|
+
| `/stocks:reports` | every stored report, best score first |
|
|
14
|
+
| `/stocks:discover fusion` | a ranked watchlist for a topic (slow) |
|
|
15
|
+
|
|
16
|
+
The `stocks:` prefix is not optional. Claude Code namespaces every plugin
|
|
17
|
+
command as `/<plugin>:<command>` — always, not only when two plugins collide —
|
|
18
|
+
so a bare `/stocks` answers `Unknown command`. Typing `/` and picking from the
|
|
19
|
+
menu inserts the right form for you.
|
|
20
|
+
|
|
21
|
+
(Inside the moshcode pit itself, `/stocks …` *is* bare — that is moshcode's own
|
|
22
|
+
command, not this plugin's.)
|
|
15
23
|
|
|
16
24
|
## Upgrading from `ticker@moshcode`
|
|
17
25
|
|
|
18
26
|
This plugin used to be called `ticker`. Both it and its headline command were
|
|
19
|
-
renamed so the name says which market it covers, now that `/crypto` sits beside
|
|
27
|
+
renamed so the name says which market it covers, now that `/crypto:crypto` sits beside
|
|
20
28
|
it.
|
|
21
29
|
|
|
22
30
|
Installing the new one does **not** replace the old one — engines install
|
|
23
|
-
plugins side by side, so `/stocks` would come from two plugins at once. Remove
|
|
31
|
+
plugins side by side, so `/stocks:stocks` would come from two plugins at once. Remove
|
|
24
32
|
the old id first:
|
|
25
33
|
|
|
26
34
|
```bash
|
|
@@ -41,6 +49,7 @@ Or straight from Claude Code:
|
|
|
41
49
|
|
|
42
50
|
```bash
|
|
43
51
|
claude plugin marketplace add moshcoder/moshcode
|
|
52
|
+
claude plugin marketplace update moshcode # `add` is a no-op if you already have it
|
|
44
53
|
claude plugin install stocks@moshcode
|
|
45
54
|
```
|
|
46
55
|
|
|
@@ -22,6 +22,6 @@ Fallback: `curl -sS "https://advis0r.com/api/lookup?q=<url-encoded>&limit=10"`
|
|
|
22
22
|
## Rules
|
|
23
23
|
|
|
24
24
|
- Show every match with its exchange — "Delta" is an airline and a faucet company.
|
|
25
|
-
- Mark which ones have a report, and offer `/stocks <SYMBOL>` for those.
|
|
25
|
+
- Mark which ones have a report, and offer `/stocks:stocks <SYMBOL>` for those.
|
|
26
26
|
- One unambiguous match: say the symbol and go straight to offering the report.
|
|
27
27
|
- No match: say the *directory* has no match, and do not invent a symbol.
|
|
@@ -26,5 +26,5 @@ generatedAt }`, and `total` is how many exist.
|
|
|
26
26
|
- **`generatedAt` per row, always.** These are snapshots taken at different
|
|
27
27
|
times; a table that hides that reads as one consistent as-of date.
|
|
28
28
|
- A row with no `aiProvider` was scored deterministically, not by a model.
|
|
29
|
-
- Offer `/stocks <SYMBOL>` for anything worth a closer look.
|
|
29
|
+
- Offer `/stocks:stocks <SYMBOL>` for anything worth a closer look.
|
|
30
30
|
- This is a coverage list, not a recommendation list. Rank order is score order.
|
|
@@ -25,5 +25,5 @@ hit is a hit — but relevance is not ranked. Read before summarizing.
|
|
|
25
25
|
- Cluster the hits by ticker and say which companies came up, with dates.
|
|
26
26
|
- Quote sparingly and attribute each quote to its speaker and ticker.
|
|
27
27
|
- If nothing matches, say the *index* has no match — this searches advis0r's
|
|
28
|
-
indexed corpus, not the whole web. Suggest `/lookup` if the query looks like
|
|
28
|
+
indexed corpus, not the whole web. Suggest `/stocks:lookup` if the query looks like
|
|
29
29
|
a company name.
|
package/src/crypto.mjs
CHANGED
|
@@ -488,7 +488,11 @@ function priceLine(snapshot, quote) {
|
|
|
488
488
|
const bits = [bone(price(last, quote))];
|
|
489
489
|
if (change) {
|
|
490
490
|
const paint = changeTone(change.percent);
|
|
491
|
-
|
|
491
|
+
// Sign the magnitude, don't let price() sign it: a signed price puts the
|
|
492
|
+
// minus after the currency mark ("$-186.36"), so a down move reads unlike
|
|
493
|
+
// the up move's "+$186.36". The sign leads, the way pct() already signs.
|
|
494
|
+
const signed = `${change.absolute >= 0 ? "+" : "-"}${price(Math.abs(Number(change.absolute)), quote, { like: last })}`;
|
|
495
|
+
bits.push(paint(signed), paint(`(${pct(change.percent)})`));
|
|
492
496
|
}
|
|
493
497
|
const feed = [
|
|
494
498
|
snapshot?.delayed === false ? "live" : snapshot?.delayed === true ? "delayed" : null,
|
package/src/integrations.mjs
CHANGED
|
@@ -345,7 +345,7 @@ export async function pluginCommand(tokens, { run, installedSet } = {}) {
|
|
|
345
345
|
// A newly installed plugin is not live in an already-running engine, and the
|
|
346
346
|
// first thing anyone does is type the slash command and conclude it failed.
|
|
347
347
|
if (!anyFailed(results) && verb === "install" && results.some((r) => r.status === "installed")) {
|
|
348
|
-
console.log(info(`restart the engine, then try ${acid(
|
|
348
|
+
console.log(info(`restart the engine, then try ${acid(plugin.example ?? plugin.commands[0])}`));
|
|
349
349
|
}
|
|
350
350
|
return anyFailed(results) ? 1 : 0;
|
|
351
351
|
}
|
package/src/plugins.mjs
CHANGED
|
@@ -26,20 +26,40 @@ export function marketplaceSource(env = process.env) {
|
|
|
26
26
|
return String(env.MOSHCODE_PLUGIN_SOURCE || "moshcoder/moshcode").trim() || "moshcoder/moshcode";
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* The plugins this marketplace ships. Mirrors .claude-plugin/marketplace.json.
|
|
31
|
+
*
|
|
32
|
+
* `commands` carry their namespace because that is how they are actually
|
|
33
|
+
* invoked. Claude Code namespaces every plugin command as
|
|
34
|
+
* `/<plugin>:<command>` — always, not only when two plugins collide — so a bare
|
|
35
|
+
* `/crypto` is simply not a command, and advertising one sends people to
|
|
36
|
+
* "Unknown command: /crypto" on their first try.
|
|
37
|
+
* https://code.claude.com/docs/en/plugins
|
|
38
|
+
*
|
|
39
|
+
* `example` exists because the invitation printed after an install has to be
|
|
40
|
+
* runnable. It used to append a hardcoded "NVDA" to whatever came first in
|
|
41
|
+
* `commands`, which told anyone installing the crypto plugin to try a stock.
|
|
42
|
+
*/
|
|
30
43
|
export const PLUGINS = [
|
|
31
44
|
{
|
|
32
45
|
name: "stocks",
|
|
33
46
|
description: "equity research slash commands backed by advis0r.com",
|
|
34
|
-
commands: ["/stocks", "/signals", "/research", "/lookup", "/reports", "/discover"],
|
|
47
|
+
commands: ["/stocks:stocks", "/stocks:signals", "/stocks:research", "/stocks:lookup", "/stocks:reports", "/stocks:discover"],
|
|
48
|
+
example: "/stocks:stocks NVDA",
|
|
35
49
|
},
|
|
36
50
|
{
|
|
37
51
|
name: "crypto",
|
|
38
52
|
description: "crypto market data slash commands backed by advis0r.com",
|
|
39
|
-
commands: ["/crypto", "/quote", "/book", "/bars", "/spark", "/pairs", "/coin"],
|
|
53
|
+
commands: ["/crypto:crypto", "/crypto:quote", "/crypto:book", "/crypto:bars", "/crypto:spark", "/crypto:pairs", "/crypto:coin"],
|
|
54
|
+
example: "/crypto:crypto BTC",
|
|
40
55
|
},
|
|
41
56
|
];
|
|
42
57
|
|
|
58
|
+
/** How Claude Code namespaces a plugin's command. */
|
|
59
|
+
export function pluginCommandName(plugin, file) {
|
|
60
|
+
return `/${plugin}:${String(file).replace(/\.md$/, "")}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
43
63
|
export const DEFAULT_PLUGIN = PLUGINS[0].name;
|
|
44
64
|
|
|
45
65
|
/**
|
|
@@ -82,15 +102,29 @@ export function pluginId(name) {
|
|
|
82
102
|
/**
|
|
83
103
|
* The commands one engine needs to install a plugin.
|
|
84
104
|
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
105
|
+
* Both marketplace steps run every time, and they do different jobs:
|
|
106
|
+
*
|
|
107
|
+
* add — makes the marketplace exist. A no-op when it is already on disk,
|
|
108
|
+
* which is exactly why it is not sufficient on its own.
|
|
109
|
+
* update — re-fetches it. Without this, a machine that added the marketplace
|
|
110
|
+
* before a plugin existed installs from its stale local copy and
|
|
111
|
+
* fails with "not found in any marketplace" — the failure `add` was
|
|
112
|
+
* supposed to prevent and cannot, because it declines to do anything
|
|
113
|
+
* for a marketplace it already has.
|
|
114
|
+
*
|
|
115
|
+
* That gap is not theoretical: it broke `plugin install crypto` in v0.27.0 and
|
|
116
|
+
* `plugin install stocks` in v0.29.0, on every machine that had installed a
|
|
117
|
+
* plugin from this marketplace beforehand — which is all of them.
|
|
118
|
+
*
|
|
119
|
+
* `marketplace update` takes the marketplace *name*, not the source, and
|
|
120
|
+
* accepts no --scope.
|
|
88
121
|
*/
|
|
89
122
|
export function pluginInstallActions(key, { plugin, source, scope }) {
|
|
90
123
|
switch (key) {
|
|
91
124
|
case "claude":
|
|
92
125
|
return [
|
|
93
126
|
{ cmd: "claude", args: ["plugin", "marketplace", "add", source, ...(scope ? ["--scope", scope] : [])] },
|
|
127
|
+
{ cmd: "claude", args: ["plugin", "marketplace", "update", MARKETPLACE_NAME] },
|
|
94
128
|
{ cmd: "claude", args: ["plugin", "install", pluginId(plugin.name), ...(scope ? ["--scope", scope] : [])] },
|
|
95
129
|
];
|
|
96
130
|
default:
|