@teemtape/cli 0.1.0 → 0.1.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 +15 -2
- package/dist/index.js +121 -6
- package/dist/index.js.map +1 -1
- package/package.json +14 -3
package/README.md
CHANGED
|
@@ -36,12 +36,25 @@ and `notes` work immediately. Once it's published you'll be able to run it as
|
|
|
36
36
|
| ------- | ------------ |
|
|
37
37
|
| `teemtape init` | Create a new anonymous watchlist; saves the token to your config file |
|
|
38
38
|
| `teemtape list [--symbols A,B]` | Delayed quotes for your watchlist (or specific symbols) |
|
|
39
|
+
| `teemtape search [QUERY]` | Search the SEC symbol catalog by ticker or company name |
|
|
39
40
|
| `teemtape add <SYMBOL>` | Add a symbol to your watchlist |
|
|
40
41
|
| `teemtape notes <SYMBOL>` | Read the anonymous note thread for a symbol |
|
|
41
42
|
| `teemtape note <SYMBOL> -m "…"` | Post an anonymous note (tagged `source: cli`) |
|
|
42
43
|
| `teemtape share` | Print your shareable watchlist link |
|
|
43
44
|
| `teemtape config` | Show resolved config (token masked) |
|
|
44
45
|
|
|
46
|
+
### Symbol search
|
|
47
|
+
|
|
48
|
+
Search the SEC symbol catalog (no watchlist token required):
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
teemtape search nvidia # match ticker or company name
|
|
52
|
+
teemtape search --symbol nv # ticker substring only
|
|
53
|
+
teemtape search --name microsoft # company name substring only
|
|
54
|
+
teemtape search --symbol a --name corp # combine filters (AND)
|
|
55
|
+
teemtape search apple --limit 5 --json
|
|
56
|
+
```
|
|
57
|
+
|
|
45
58
|
### Global flags
|
|
46
59
|
|
|
47
60
|
- `--api-url <url>` — Worker API base URL
|
|
@@ -55,9 +68,9 @@ Resolved with precedence: **CLI flags > env vars > config file > defaults**.
|
|
|
55
68
|
|
|
56
69
|
| Setting | Flag | Env var | Default |
|
|
57
70
|
| ------- | ---- | ------- | ------- |
|
|
58
|
-
| API URL | `--api-url` | `TEEMTAPE_API_URL` | `
|
|
71
|
+
| API URL | `--api-url` | `TEEMTAPE_API_URL` | `https://api.teemtape.com` |
|
|
59
72
|
| Token | `--token` | `TEEMTAPE_TOKEN` | (none) |
|
|
60
|
-
| Web URL | `--web-url` | `TEEMTAPE_WEB_URL` | `https://teemtape.
|
|
73
|
+
| Web URL | `--web-url` | `TEEMTAPE_WEB_URL` | `https://www.teemtape.com` |
|
|
61
74
|
|
|
62
75
|
The config file lives at `~/.config/teemtape/config.json` (or
|
|
63
76
|
`$XDG_CONFIG_HOME/teemtape/config.json`) and is written with `0600` perms. The
|
package/dist/index.js
CHANGED
|
@@ -18,7 +18,7 @@ var TeemtapeClient = class {
|
|
|
18
18
|
constructor(options) {
|
|
19
19
|
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
20
20
|
this.token = options.token;
|
|
21
|
-
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
21
|
+
this.fetchImpl = options.fetch ?? ((input, init) => globalThis.fetch(input, init));
|
|
22
22
|
if (typeof this.fetchImpl !== "function") {
|
|
23
23
|
throw new Error("No fetch implementation available (need Node 18+ or pass options.fetch).");
|
|
24
24
|
}
|
|
@@ -163,6 +163,27 @@ ${c.dim(`# prices delayed ~${mins} min \xB7 source: ${source}`)}
|
|
|
163
163
|
`
|
|
164
164
|
);
|
|
165
165
|
}
|
|
166
|
+
function printSymbolsTable(res) {
|
|
167
|
+
if (res.symbols.length === 0) {
|
|
168
|
+
process.stdout.write(c.dim("No symbols matched. Try a different query.\n"));
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const header = `${pad("TICKER", 8)}${pad("COMPANY", 40)}`;
|
|
172
|
+
process.stdout.write(`${c.dim(header)}
|
|
173
|
+
`);
|
|
174
|
+
for (const s of res.symbols) {
|
|
175
|
+
const row = pad(s.ticker, 8) + pad(truncate(s.title, 39), 40);
|
|
176
|
+
process.stdout.write(`${row}
|
|
177
|
+
`);
|
|
178
|
+
}
|
|
179
|
+
const shown = res.symbols.length;
|
|
180
|
+
const start = res.total === 0 ? 0 : res.offset + 1;
|
|
181
|
+
const end = res.offset + shown;
|
|
182
|
+
const range = res.total === 0 ? "0 matches" : shown === 1 ? `${start} of ${res.total}` : `${start}\u2013${end} of ${res.total}`;
|
|
183
|
+
process.stdout.write(`
|
|
184
|
+
${c.dim(`# ${range}`)}
|
|
185
|
+
`);
|
|
186
|
+
}
|
|
166
187
|
function printNotes(symbol, notes) {
|
|
167
188
|
process.stdout.write(`${c.bold(symbol)} ${c.dim("notes")}
|
|
168
189
|
`);
|
|
@@ -218,8 +239,8 @@ import { mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
|
218
239
|
import { homedir } from "os";
|
|
219
240
|
import { dirname, join } from "path";
|
|
220
241
|
var DEFAULTS = {
|
|
221
|
-
apiUrl: "
|
|
222
|
-
webUrl: "https://teemtape.
|
|
242
|
+
apiUrl: "https://api.teemtape.com",
|
|
243
|
+
webUrl: "https://www.teemtape.com"
|
|
223
244
|
};
|
|
224
245
|
function configFilePath() {
|
|
225
246
|
const base = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
|
|
@@ -355,6 +376,41 @@ async function notesCommand(ctx, symbol) {
|
|
|
355
376
|
printNotes(res.symbol, res.notes);
|
|
356
377
|
}
|
|
357
378
|
|
|
379
|
+
// src/commands/search.ts
|
|
380
|
+
async function searchCommand(ctx, query, opts) {
|
|
381
|
+
const q = query?.trim();
|
|
382
|
+
const symbol = opts.symbol?.trim();
|
|
383
|
+
const name = opts.name?.trim();
|
|
384
|
+
if (!q && !symbol && !name) {
|
|
385
|
+
process.stderr.write(
|
|
386
|
+
`${c.red("error:")} provide a search query, or use --symbol and/or --name.
|
|
387
|
+
`
|
|
388
|
+
);
|
|
389
|
+
process.exitCode = 1;
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
const res = await ctx.client.listSymbols({
|
|
393
|
+
...q ? { q } : {},
|
|
394
|
+
...symbol ? { symbol } : {},
|
|
395
|
+
...name ? { name } : {},
|
|
396
|
+
...opts.limit !== void 0 ? { limit: parsePositiveInt(opts.limit, "limit") } : { limit: 20 },
|
|
397
|
+
...opts.offset !== void 0 ? { offset: parsePositiveInt(opts.offset, "offset") } : {},
|
|
398
|
+
...opts.sort ? { sort: opts.sort } : {}
|
|
399
|
+
});
|
|
400
|
+
if (ctx.json) {
|
|
401
|
+
printJson(res);
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
printSymbolsTable(res);
|
|
405
|
+
}
|
|
406
|
+
function parsePositiveInt(raw, label) {
|
|
407
|
+
const n = Number.parseInt(raw, 10);
|
|
408
|
+
if (!Number.isFinite(n) || n < 0) {
|
|
409
|
+
throw new Error(`invalid ${label}: ${raw}`);
|
|
410
|
+
}
|
|
411
|
+
return n;
|
|
412
|
+
}
|
|
413
|
+
|
|
358
414
|
// src/commands/share.ts
|
|
359
415
|
async function shareCommand(ctx) {
|
|
360
416
|
const token = ctx.config.token;
|
|
@@ -379,7 +435,60 @@ function createContext(flags) {
|
|
|
379
435
|
return { config, json: Boolean(flags.json), client };
|
|
380
436
|
}
|
|
381
437
|
|
|
438
|
+
// src/net.ts
|
|
439
|
+
import { EnvHttpProxyAgent, setGlobalDispatcher } from "undici";
|
|
440
|
+
var PROXY_ENV_VARS = ["HTTPS_PROXY", "https_proxy", "HTTP_PROXY", "http_proxy"];
|
|
441
|
+
function configureProxyFromEnv() {
|
|
442
|
+
const hasProxy = PROXY_ENV_VARS.some((name) => Boolean(process.env[name]));
|
|
443
|
+
if (!hasProxy) return;
|
|
444
|
+
setGlobalDispatcher(new EnvHttpProxyAgent());
|
|
445
|
+
}
|
|
446
|
+
var NETWORK_CODES = /* @__PURE__ */ new Set([
|
|
447
|
+
"ENOTFOUND",
|
|
448
|
+
"EAI_AGAIN",
|
|
449
|
+
"ECONNREFUSED",
|
|
450
|
+
"ECONNRESET",
|
|
451
|
+
"ETIMEDOUT",
|
|
452
|
+
"EPIPE",
|
|
453
|
+
"ENETUNREACH",
|
|
454
|
+
"EHOSTUNREACH",
|
|
455
|
+
"UND_ERR_CONNECT_TIMEOUT",
|
|
456
|
+
"UND_ERR_SOCKET",
|
|
457
|
+
"UND_ERR_HEADERS_TIMEOUT",
|
|
458
|
+
"UND_ERR_BODY_TIMEOUT"
|
|
459
|
+
]);
|
|
460
|
+
var TLS_CODES = /* @__PURE__ */ new Set([
|
|
461
|
+
"CERT_HAS_EXPIRED",
|
|
462
|
+
"DEPTH_ZERO_SELF_SIGNED_CERT",
|
|
463
|
+
"SELF_SIGNED_CERT_IN_CHAIN",
|
|
464
|
+
"UNABLE_TO_VERIFY_LEAF_SIGNATURE",
|
|
465
|
+
"ERR_TLS_CERT_ALTNAME_INVALID"
|
|
466
|
+
]);
|
|
467
|
+
function causeCode(err) {
|
|
468
|
+
const cause = err.cause;
|
|
469
|
+
return typeof cause?.code === "string" ? cause.code : void 0;
|
|
470
|
+
}
|
|
471
|
+
function describeNetworkError(err) {
|
|
472
|
+
if (!(err instanceof Error)) return void 0;
|
|
473
|
+
const code = causeCode(err);
|
|
474
|
+
const isNetworkFailure = err.message === "fetch failed" || code !== void 0 && NETWORK_CODES.has(code);
|
|
475
|
+
if (!isNetworkFailure && !(code !== void 0 && TLS_CODES.has(code))) return void 0;
|
|
476
|
+
const reason = code ? ` (${code})` : "";
|
|
477
|
+
const lines = [`could not reach the API${reason}.`];
|
|
478
|
+
if (code && TLS_CODES.has(code)) {
|
|
479
|
+
lines.push("This is a TLS/certificate problem. If a proxy or antivirus intercepts HTTPS,");
|
|
480
|
+
lines.push("point Node at its root certificate via NODE_EXTRA_CA_CERTS=/path/to/ca.pem.");
|
|
481
|
+
} else {
|
|
482
|
+
lines.push("Check your connection and that the API URL is correct (run `teemtape config`).");
|
|
483
|
+
lines.push("Behind a proxy? Set HTTPS_PROXY (and NO_PROXY for exceptions) and retry \u2014 the CLI");
|
|
484
|
+
lines.push("now honors them, but Node's fetch ignores proxy settings by default (curl does not).");
|
|
485
|
+
}
|
|
486
|
+
lines.push("For local testing run `npm run mock` and pass --api-url http://localhost:8787.");
|
|
487
|
+
return lines.join("\n ");
|
|
488
|
+
}
|
|
489
|
+
|
|
382
490
|
// src/index.ts
|
|
491
|
+
configureProxyFromEnv();
|
|
383
492
|
var program = new Command();
|
|
384
493
|
program.name("teemtape").description("teemtape \u2014 list stocks and post anonymous notes from the terminal.").version("0.0.0").option("--api-url <url>", "Worker API base URL (env: TEEMTAPE_API_URL)").option("--token <token>", "watchlist token (env: TEEMTAPE_TOKEN)").option("--web-url <url>", "web app base URL used for share links (env: TEEMTAPE_WEB_URL)").option("--json", "output machine-readable JSON (handy for agents)").showHelpAfterError();
|
|
385
494
|
function globalsOf(command) {
|
|
@@ -409,9 +518,9 @@ function handleError(err) {
|
|
|
409
518
|
fail(`${err.message} (HTTP ${err.status})`);
|
|
410
519
|
return;
|
|
411
520
|
}
|
|
412
|
-
const
|
|
413
|
-
if (
|
|
414
|
-
fail(
|
|
521
|
+
const networkMessage = describeNetworkError(err);
|
|
522
|
+
if (networkMessage) {
|
|
523
|
+
fail(networkMessage);
|
|
415
524
|
return;
|
|
416
525
|
}
|
|
417
526
|
fail(err instanceof Error ? err.message : String(err));
|
|
@@ -420,6 +529,9 @@ program.command("init").description("create a new anonymous watchlist and save i
|
|
|
420
529
|
program.command("list").description("show delayed quotes for your watchlist (or --symbols)").option("-s, --symbols <list>", "comma-separated symbols to show instead of the watchlist").action(
|
|
421
530
|
async (opts, command) => run(command, (ctx) => listCommand(ctx, opts))
|
|
422
531
|
);
|
|
532
|
+
program.command("search").argument("[query]", "search ticker or company name (substring match)").description("search the SEC symbol catalog by ticker or company name").option("--symbol <text>", "filter by ticker substring only").option("--name <text>", "filter by company name substring only").option("--limit <n>", "max results to return (default 20, max 100)").option("--offset <n>", "skip first n matches (for paging)").option("--sort <field>", "sort by ticker or title", "ticker").action(
|
|
533
|
+
async (query, opts, command) => run(command, (ctx) => searchCommand(ctx, query, opts))
|
|
534
|
+
);
|
|
423
535
|
program.command("add").argument("<symbol>", "ticker symbol, e.g. AAPL").description("add a symbol to your watchlist").action(
|
|
424
536
|
async (symbol, _opts, command) => run(command, (ctx) => addCommand(ctx, symbol))
|
|
425
537
|
);
|
|
@@ -436,6 +548,9 @@ program.addHelpText(
|
|
|
436
548
|
`
|
|
437
549
|
Examples:
|
|
438
550
|
$ teemtape --api-url http://localhost:8787 init
|
|
551
|
+
$ teemtape search nvidia
|
|
552
|
+
$ teemtape search --symbol nv
|
|
553
|
+
$ teemtape search --name microsoft
|
|
439
554
|
$ teemtape add NVDA
|
|
440
555
|
$ teemtape list
|
|
441
556
|
$ teemtape notes NVDA
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../api-client/src/client.ts","../src/index.ts","../src/output.ts","../src/commands/add.ts","../src/config.ts","../src/commands/config.ts","../src/commands/init.ts","../src/commands/list.ts","../src/commands/note.ts","../src/commands/notes.ts","../src/commands/share.ts","../src/context.ts"],"sourcesContent":["import type {\n CreateNoteInput,\n Note,\n NotesResponse,\n QuotesResponse,\n SymbolsListResponse,\n Watchlist,\n} from \"./types.js\";\n\nexport interface ApiClientOptions {\n /** Base URL of the Worker API, e.g. http://localhost:8787 */\n baseUrl: string;\n /** Optional default watchlist token used by watchlist/note calls. */\n token?: string;\n /** Injectable fetch (defaults to global fetch); handy for tests. */\n fetch?: typeof fetch;\n}\n\n/** Thrown for any non-2xx API response. */\nexport class ApiError extends Error {\n readonly status: number;\n readonly body: unknown;\n\n constructor(status: number, message: string, body: unknown) {\n super(message);\n this.name = \"ApiError\";\n this.status = status;\n this.body = body;\n }\n}\n\n/**\n * Minimal typed client for the teemtape Worker API. The same contract is reused\n * by the CLI now and the web/native apps later (see docs/cli-options.md).\n */\nexport class TeemtapeClient {\n private readonly baseUrl: string;\n private readonly token?: string;\n private readonly fetchImpl: typeof fetch;\n\n constructor(options: ApiClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, \"\");\n this.token = options.token;\n this.fetchImpl = options.fetch ?? globalThis.fetch;\n if (typeof this.fetchImpl !== \"function\") {\n throw new Error(\"No fetch implementation available (need Node 18+ or pass options.fetch).\");\n }\n }\n\n /** Delayed quotes for the given symbols. */\n async getQuotes(symbols: string[]): Promise<QuotesResponse> {\n const query = encodeURIComponent(symbols.join(\",\"));\n return this.request<QuotesResponse>(`/api/quotes?symbols=${query}`);\n }\n\n /** Paginated SEC symbol catalog with optional search and sort. */\n async listSymbols(params: {\n offset?: number;\n limit?: number;\n sort?: \"ticker\" | \"title\";\n q?: string;\n symbol?: string;\n name?: string;\n } = {}): Promise<SymbolsListResponse> {\n const search = new URLSearchParams();\n if (params.offset !== undefined) search.set(\"offset\", String(params.offset));\n if (params.limit !== undefined) search.set(\"limit\", String(params.limit));\n if (params.sort) search.set(\"sort\", params.sort);\n if (params.q) search.set(\"q\", params.q);\n if (params.symbol) search.set(\"symbol\", params.symbol);\n if (params.name) search.set(\"name\", params.name);\n const qs = search.toString();\n return this.request<SymbolsListResponse>(`/api/symbols${qs ? `?${qs}` : \"\"}`);\n }\n\n /** Create a new anonymous watchlist and return its MD5 token. */\n async createWatchlist(): Promise<Watchlist> {\n return this.request<Watchlist>(`/api/watchlists`, { method: \"POST\" });\n }\n\n /** Fetch a watchlist (symbols + metadata) by token. */\n async getWatchlist(token = this.requireToken()): Promise<Watchlist> {\n return this.request<Watchlist>(`/api/w/${token}`);\n }\n\n /** Add a symbol to a watchlist. */\n async addSymbol(symbol: string, token = this.requireToken()): Promise<Watchlist> {\n return this.request<Watchlist>(`/api/w/${token}/symbols`, {\n method: \"POST\",\n body: JSON.stringify({ symbol: symbol.toUpperCase() }),\n });\n }\n\n /** Notes for a symbol on a watchlist. */\n async getNotes(symbol: string, token = this.requireToken()): Promise<NotesResponse> {\n const query = encodeURIComponent(symbol.toUpperCase());\n return this.request<NotesResponse>(`/api/w/${token}/notes?symbol=${query}`);\n }\n\n /** Post an anonymous note to a symbol. */\n async addNote(input: CreateNoteInput, token = this.requireToken()): Promise<Note> {\n return this.request<Note>(`/api/w/${token}/notes`, {\n method: \"POST\",\n body: JSON.stringify({ ...input, symbol: input.symbol.toUpperCase() }),\n });\n }\n\n private requireToken(): string {\n if (!this.token) {\n throw new Error(\"A watchlist token is required. Pass --token or set TEEMTAPE_TOKEN.\");\n }\n return this.token;\n }\n\n private async request<T>(path: string, init: RequestInit = {}): Promise<T> {\n const headers = new Headers(init.headers);\n if (init.body && !headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"application/json\");\n }\n headers.set(\"accept\", \"application/json\");\n\n const res = await this.fetchImpl(`${this.baseUrl}${path}`, { ...init, headers });\n const text = await res.text();\n const data = text ? safeJsonParse(text) : undefined;\n\n if (!res.ok) {\n const message =\n (isRecord(data) && typeof data.error === \"string\" && data.error) ||\n `Request to ${path} failed with ${res.status}`;\n throw new ApiError(res.status, message, data);\n }\n return data as T;\n }\n}\n\nfunction safeJsonParse(text: string): unknown {\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n","#!/usr/bin/env node\nimport { ApiError } from \"@teemtape/api-client\";\nimport { Command } from \"commander\";\nimport { addCommand } from \"./commands/add.js\";\nimport { configCommand } from \"./commands/config.js\";\nimport { initCommand } from \"./commands/init.js\";\nimport { listCommand } from \"./commands/list.js\";\nimport { noteCommand } from \"./commands/note.js\";\nimport { notesCommand } from \"./commands/notes.js\";\nimport { shareCommand } from \"./commands/share.js\";\nimport { createContext, type Context, type GlobalFlags } from \"./context.js\";\nimport { c } from \"./output.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"teemtape\")\n .description(\"teemtape — list stocks and post anonymous notes from the terminal.\")\n .version(\"0.0.0\")\n .option(\"--api-url <url>\", \"Worker API base URL (env: TEEMTAPE_API_URL)\")\n .option(\"--token <token>\", \"watchlist token (env: TEEMTAPE_TOKEN)\")\n .option(\"--web-url <url>\", \"web app base URL used for share links (env: TEEMTAPE_WEB_URL)\")\n .option(\"--json\", \"output machine-readable JSON (handy for agents)\")\n .showHelpAfterError();\n\nfunction globalsOf(command: Command): GlobalFlags {\n const o = command.optsWithGlobals();\n return {\n apiUrl: o.apiUrl as string | undefined,\n token: o.token as string | undefined,\n webUrl: o.webUrl as string | undefined,\n json: Boolean(o.json),\n };\n}\n\nasync function run(command: Command, fn: (ctx: Context) => Promise<void>): Promise<void> {\n try {\n const ctx = createContext(globalsOf(command));\n await fn(ctx);\n } catch (err) {\n handleError(err);\n }\n}\n\nfunction fail(message: string): void {\n process.stderr.write(`${c.red(\"error:\")} ${message}\\n`);\n process.exitCode = 1;\n}\n\nfunction handleError(err: unknown): void {\n if (err instanceof ApiError) {\n fail(`${err.message} (HTTP ${err.status})`);\n return;\n }\n const cause = err instanceof Error ? (err.cause as { code?: string } | undefined) : undefined;\n if (cause?.code === \"ECONNREFUSED\" || cause?.code === \"ENOTFOUND\") {\n fail(\"could not reach the API. Is it running? For local testing run `npm run mock` in another terminal.\");\n return;\n }\n fail(err instanceof Error ? err.message : String(err));\n}\n\nprogram\n .command(\"init\")\n .description(\"create a new anonymous watchlist and save its token locally\")\n .action(async (_opts, command: Command) => run(command, (ctx) => initCommand(ctx)));\n\nprogram\n .command(\"list\")\n .description(\"show delayed quotes for your watchlist (or --symbols)\")\n .option(\"-s, --symbols <list>\", \"comma-separated symbols to show instead of the watchlist\")\n .action(async (opts: { symbols?: string }, command: Command) =>\n run(command, (ctx) => listCommand(ctx, opts)),\n );\n\nprogram\n .command(\"add\")\n .argument(\"<symbol>\", \"ticker symbol, e.g. AAPL\")\n .description(\"add a symbol to your watchlist\")\n .action(async (symbol: string, _opts, command: Command) =>\n run(command, (ctx) => addCommand(ctx, symbol)),\n );\n\nprogram\n .command(\"notes\")\n .argument(\"<symbol>\", \"ticker symbol, e.g. AAPL\")\n .description(\"read the anonymous note thread for a symbol\")\n .action(async (symbol: string, _opts, command: Command) =>\n run(command, (ctx) => notesCommand(ctx, symbol)),\n );\n\nprogram\n .command(\"note\")\n .argument(\"<symbol>\", \"ticker symbol, e.g. AAPL\")\n .requiredOption(\"-m, --message <text>\", \"the note to post\")\n .description(\"post an anonymous note to a symbol (tagged as source: cli)\")\n .action(async (symbol: string, opts: { message?: string }, command: Command) =>\n run(command, (ctx) => noteCommand(ctx, symbol, opts)),\n );\n\nprogram\n .command(\"share\")\n .description(\"print your anonymous shareable watchlist link\")\n .action(async (_opts, command: Command) => run(command, (ctx) => shareCommand(ctx)));\n\nprogram\n .command(\"config\")\n .description(\"show the resolved configuration (token masked)\")\n .action(async (_opts, command: Command) => run(command, (ctx) => configCommand(ctx)));\n\nprogram.addHelpText(\n \"after\",\n `\nExamples:\n $ teemtape --api-url http://localhost:8787 init\n $ teemtape add NVDA\n $ teemtape list\n $ teemtape notes NVDA\n $ teemtape note AAPL --message \"Earnings call scheduled.\"\n $ teemtape share\n $ teemtape list --json # machine-readable output for agents\n\nConfig precedence: CLI flags > env vars > ~/.config/teemtape/config.json > defaults\n`,\n);\n\nprogram.parseAsync().catch(handleError);\n","import type { Note, Quote } from \"@teemtape/api-client\";\n\nconst useColor = Boolean(process.stdout.isTTY) && !process.env.NO_COLOR;\n\nconst codes = {\n reset: \"\\x1b[0m\",\n dim: \"\\x1b[2m\",\n bold: \"\\x1b[1m\",\n green: \"\\x1b[32m\",\n red: \"\\x1b[31m\",\n yellow: \"\\x1b[33m\",\n cyan: \"\\x1b[36m\",\n} as const;\n\nfunction paint(code: string, text: string): string {\n return useColor ? `${code}${text}${codes.reset}` : text;\n}\n\nexport const c = {\n dim: (t: string) => paint(codes.dim, t),\n bold: (t: string) => paint(codes.bold, t),\n green: (t: string) => paint(codes.green, t),\n red: (t: string) => paint(codes.red, t),\n yellow: (t: string) => paint(codes.yellow, t),\n cyan: (t: string) => paint(codes.cyan, t),\n};\n\nexport function printJson(value: unknown): void {\n process.stdout.write(`${JSON.stringify(value, null, 2)}\\n`);\n}\n\nfunction money(n: number): string {\n return `$${n.toFixed(2)}`;\n}\n\nfunction signed(n: number): string {\n return `${n >= 0 ? \"+\" : \"\"}${n.toFixed(2)}`;\n}\n\nfunction pad(text: string, width: number): string {\n return text.length >= width ? text : text + \" \".repeat(width - text.length);\n}\n\nfunction padStart(text: string, width: number): string {\n return text.length >= width ? text : \" \".repeat(width - text.length) + text;\n}\n\n/** Render the watchlist quotes as an aligned table. */\nexport function printQuotesTable(quotes: Quote[], delayedSeconds: number, source: string): void {\n if (quotes.length === 0) {\n process.stdout.write(c.dim(\"No symbols on this watchlist yet. Add one with `teemtape add <SYMBOL>`.\\n\"));\n return;\n }\n\n const header = `${pad(\"SYMBOL\", 8)}${pad(\"COMPANY\", 26)}${padStart(\"LAST\", 10)} ${padStart(\"CHANGE\", 18)}`;\n process.stdout.write(`${c.dim(header)}\\n`);\n\n for (const q of quotes) {\n const changeText = `${signed(q.change)} (${signed(q.pct)}%)`;\n const colored = q.change >= 0 ? c.green(changeText) : c.red(changeText);\n const row =\n pad(q.symbol, 8) +\n pad(truncate(q.name, 25), 26) +\n padStart(money(q.price), 10) +\n \" \" +\n padStartColored(colored, changeText, 18);\n process.stdout.write(`${row}\\n`);\n }\n\n const mins = Math.round(delayedSeconds / 60);\n process.stdout.write(\n `\\n${c.dim(`# prices delayed ~${mins} min · source: ${source}`)}\\n`,\n );\n}\n\n/** Render a note thread for a symbol. */\nexport function printNotes(symbol: string, notes: Note[]): void {\n process.stdout.write(`${c.bold(symbol)} ${c.dim(\"notes\")}\\n`);\n process.stdout.write(`${c.dim(\"─\".repeat(44))}\\n`);\n if (notes.length === 0) {\n process.stdout.write(`${c.dim(\"No notes yet. Add one with `teemtape note \" + symbol + ' --message \"…\"`.')}\\n`);\n return;\n }\n for (const n of notes) {\n const src = n.source === \"cli\" ? c.yellow(`(cli, ${rel(n.createdAt)})`) : c.dim(`(web, ${rel(n.createdAt)})`);\n process.stdout.write(`${c.cyan(n.author)} ${src}\\n`);\n process.stdout.write(` ${n.body}\\n`);\n }\n}\n\nfunction truncate(text: string, max: number): string {\n return text.length <= max ? text : `${text.slice(0, max - 1)}…`;\n}\n\n// Right-pad accounting for invisible ANSI codes by padding the plain text width.\nfunction padStartColored(colored: string, plain: string, width: number): string {\n const padding = Math.max(0, width - plain.length);\n return \" \".repeat(padding) + colored;\n}\n\nfunction rel(iso: string): string {\n const then = new Date(iso).getTime();\n if (Number.isNaN(then)) return iso;\n const diffMs = Date.now() - then;\n const mins = Math.round(diffMs / 60000);\n if (mins < 1) return \"just now\";\n if (mins < 60) return `${mins}m ago`;\n const hours = Math.round(mins / 60);\n if (hours < 24) return `${hours}h ago`;\n return `${Math.round(hours / 24)}d ago`;\n}\n","import type { Context } from \"../context.js\";\nimport { c, printJson } from \"../output.js\";\n\n/** `teemtape add <SYMBOL>` — add a symbol to the watchlist. */\nexport async function addCommand(ctx: Context, symbol: string): Promise<void> {\n const watchlist = await ctx.client.addSymbol(symbol);\n if (ctx.json) {\n printJson(watchlist);\n return;\n }\n process.stdout.write(`${c.green(\"✓\")} Added ${c.bold(symbol.toUpperCase())}\\n`);\n process.stdout.write(` ${c.dim(`watchlist: ${watchlist.symbols.join(\", \") || \"(empty)\"}`)}\\n`);\n}\n","import { mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\n/** Resolved runtime configuration for a CLI invocation. */\nexport interface ResolvedConfig {\n apiUrl: string;\n webUrl: string;\n token?: string;\n}\n\nexport interface ConfigFlags {\n apiUrl?: string;\n webUrl?: string;\n token?: string;\n}\n\nconst DEFAULTS = {\n apiUrl: \"http://localhost:8787\",\n webUrl: \"https://teemtape.app\",\n};\n\n/** Path to the persisted config file (XDG-aware, falls back to ~/.config). */\nexport function configFilePath(): string {\n const base = process.env.XDG_CONFIG_HOME || join(homedir(), \".config\");\n return join(base, \"teemtape\", \"config.json\");\n}\n\ninterface StoredConfig {\n apiUrl?: string;\n webUrl?: string;\n token?: string;\n}\n\nfunction readConfigFile(): StoredConfig {\n try {\n return JSON.parse(readFileSync(configFilePath(), \"utf8\")) as StoredConfig;\n } catch {\n return {};\n }\n}\n\n/**\n * Resolve config with precedence: CLI flags > environment > config file > defaults.\n * (See docs/cli-options.md.)\n */\nexport function resolveConfig(flags: ConfigFlags = {}): ResolvedConfig {\n const file = readConfigFile();\n const env = {\n apiUrl: process.env.TEEMTAPE_API_URL,\n webUrl: process.env.TEEMTAPE_WEB_URL,\n token: process.env.TEEMTAPE_TOKEN,\n };\n\n return {\n apiUrl: flags.apiUrl ?? env.apiUrl ?? file.apiUrl ?? DEFAULTS.apiUrl,\n webUrl: flags.webUrl ?? env.webUrl ?? file.webUrl ?? DEFAULTS.webUrl,\n token: flags.token ?? env.token ?? file.token,\n };\n}\n\n/** Persist values to the config file (merges with existing). */\nexport function saveConfig(patch: StoredConfig): string {\n const path = configFilePath();\n const merged = { ...readConfigFile(), ...patch };\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, `${JSON.stringify(merged, null, 2)}\\n`, { mode: 0o600 });\n return path;\n}\n\n/** Mask a token for display so it never gets fully printed/logged. */\nexport function maskToken(token?: string): string {\n if (!token) return \"(none)\";\n if (token.length <= 8) return \"****\";\n return `${token.slice(0, 6)}…${token.slice(-2)}`;\n}\n","import type { Context } from \"../context.js\";\nimport { configFilePath, maskToken } from \"../config.js\";\nimport { c, printJson } from \"../output.js\";\n\n/** `teemtape config` — show the resolved configuration (token masked). */\nexport async function configCommand(ctx: Context): Promise<void> {\n const view = {\n apiUrl: ctx.config.apiUrl,\n webUrl: ctx.config.webUrl,\n token: maskToken(ctx.config.token),\n configFile: configFilePath(),\n };\n if (ctx.json) {\n printJson(view);\n return;\n }\n process.stdout.write(`${c.bold(\"teemtape config\")}\\n`);\n process.stdout.write(` api url : ${view.apiUrl}\\n`);\n process.stdout.write(` web url : ${view.webUrl}\\n`);\n process.stdout.write(` token : ${view.token}\\n`);\n process.stdout.write(` ${c.dim(`config file: ${view.configFile}`)}\\n`);\n}\n","import type { Context } from \"../context.js\";\nimport { saveConfig } from \"../config.js\";\nimport { c, printJson } from \"../output.js\";\n\n/** `teemtape init` — create a new anonymous watchlist and save its token locally. */\nexport async function initCommand(ctx: Context): Promise<void> {\n const watchlist = await ctx.client.createWatchlist();\n const path = saveConfig({ token: watchlist.token });\n const url = `${ctx.config.webUrl.replace(/\\/$/, \"\")}/w/${watchlist.token}`;\n\n if (ctx.json) {\n printJson({ token: watchlist.token, url, configPath: path });\n return;\n }\n process.stdout.write(`${c.green(\"✓\")} Created a new anonymous watchlist\\n`);\n process.stdout.write(` ${c.dim(`token saved to ${path}`)}\\n`);\n process.stdout.write(` ${c.dim(\"share link:\")} ${url}\\n`);\n}\n","import type { Context } from \"../context.js\";\nimport { printJson, printQuotesTable } from \"../output.js\";\n\nexport interface ListOptions {\n symbols?: string;\n}\n\n/** `teemtape list` — show delayed quotes for the watchlist (or --symbols). */\nexport async function listCommand(ctx: Context, opts: ListOptions): Promise<void> {\n let symbols: string[];\n if (opts.symbols) {\n symbols = splitSymbols(opts.symbols);\n } else {\n const watchlist = await ctx.client.getWatchlist();\n symbols = watchlist.symbols;\n }\n\n if (symbols.length === 0) {\n if (ctx.json) {\n printJson({ quotes: [], delayedSeconds: 0, source: \"none\" });\n return;\n }\n process.stdout.write(\"No symbols to show. Add one with `teemtape add <SYMBOL>`.\\n\");\n return;\n }\n\n const res = await ctx.client.getQuotes(symbols);\n if (ctx.json) {\n printJson(res);\n return;\n }\n printQuotesTable(res.quotes, res.delayedSeconds, res.source);\n}\n\nfunction splitSymbols(raw: string): string[] {\n return raw\n .split(\",\")\n .map((s) => s.trim().toUpperCase())\n .filter(Boolean);\n}\n","import type { Context } from \"../context.js\";\nimport { c, printJson } from \"../output.js\";\n\nexport interface NoteOptions {\n message?: string;\n}\n\n/** `teemtape note <SYMBOL> --message \"…\"` — post an anonymous note (source: cli). */\nexport async function noteCommand(ctx: Context, symbol: string, opts: NoteOptions): Promise<void> {\n const body = opts.message?.trim();\n if (!body) {\n throw new Error(\"A note message is required. Use --message \\\"your note\\\".\");\n }\n\n const note = await ctx.client.addNote({ symbol, body, source: \"cli\" });\n if (ctx.json) {\n printJson(note);\n return;\n }\n process.stdout.write(`${c.green(\"✓\")} Note posted to ${c.bold(note.symbol)} as ${c.cyan(note.author)}\\n`);\n process.stdout.write(` ${c.dim(`id: ${note.id} · visible in web & mobile note popups`)}\\n`);\n}\n","import type { Context } from \"../context.js\";\nimport { printJson, printNotes } from \"../output.js\";\n\n/** `teemtape notes <SYMBOL>` — read the note thread for a symbol. */\nexport async function notesCommand(ctx: Context, symbol: string): Promise<void> {\n const res = await ctx.client.getNotes(symbol);\n if (ctx.json) {\n printJson(res);\n return;\n }\n printNotes(res.symbol, res.notes);\n}\n","import type { Context } from \"../context.js\";\nimport { c, printJson } from \"../output.js\";\n\n/** `teemtape share` — print the anonymous shareable watchlist link. */\nexport async function shareCommand(ctx: Context): Promise<void> {\n const token = ctx.config.token;\n if (!token) {\n throw new Error(\"No watchlist token set. Run `teemtape init` to create one, or pass --token.\");\n }\n const url = `${ctx.config.webUrl.replace(/\\/$/, \"\")}/w/${token}`;\n if (ctx.json) {\n printJson({ url, token });\n return;\n }\n process.stdout.write(`${c.dim(\"# your anonymous watchlist link (share with anyone):\")}\\n`);\n process.stdout.write(`${url}\\n`);\n}\n","import { TeemtapeClient } from \"@teemtape/api-client\";\nimport { resolveConfig, type ConfigFlags, type ResolvedConfig } from \"./config.js\";\n\nexport interface GlobalFlags extends ConfigFlags {\n json?: boolean;\n}\n\nexport interface Context {\n config: ResolvedConfig;\n json: boolean;\n client: TeemtapeClient;\n}\n\n/** Build the per-invocation context (resolved config + a ready API client). */\nexport function createContext(flags: GlobalFlags): Context {\n const config = resolveConfig(flags);\n const client = new TeemtapeClient({ baseUrl: config.apiUrl, token: config.token });\n return { config, json: Boolean(flags.json), client };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../api-client/src/client.ts","../src/index.ts","../src/output.ts","../src/commands/add.ts","../src/config.ts","../src/commands/config.ts","../src/commands/init.ts","../src/commands/list.ts","../src/commands/note.ts","../src/commands/notes.ts","../src/commands/search.ts","../src/commands/share.ts","../src/context.ts","../src/net.ts"],"sourcesContent":["import type {\n CreateNoteInput,\n Note,\n NotesResponse,\n QuotesResponse,\n SymbolsListResponse,\n Watchlist,\n} from \"./types.js\";\n\nexport interface ApiClientOptions {\n /** Base URL of the Worker API, e.g. https://api.teemtape.com */\n baseUrl: string;\n /** Optional default watchlist token used by watchlist/note calls. */\n token?: string;\n /** Injectable fetch (defaults to global fetch); handy for tests. */\n fetch?: typeof fetch;\n}\n\n/** Thrown for any non-2xx API response. */\nexport class ApiError extends Error {\n readonly status: number;\n readonly body: unknown;\n\n constructor(status: number, message: string, body: unknown) {\n super(message);\n this.name = \"ApiError\";\n this.status = status;\n this.body = body;\n }\n}\n\n/**\n * Minimal typed client for the teemtape Worker API. The same contract is reused\n * by the CLI now and the web/native apps later (see docs/cli-options.md).\n */\nexport class TeemtapeClient {\n private readonly baseUrl: string;\n private readonly token?: string;\n private readonly fetchImpl: typeof fetch;\n\n constructor(options: ApiClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, \"\");\n this.token = options.token;\n // Wrap default fetch: assigning window.fetch to a variable breaks in browsers\n // (\"Illegal invocation\") unless called with the correct receiver.\n this.fetchImpl =\n options.fetch ?? ((input, init) => globalThis.fetch(input, init));\n if (typeof this.fetchImpl !== \"function\") {\n throw new Error(\"No fetch implementation available (need Node 18+ or pass options.fetch).\");\n }\n }\n\n /** Delayed quotes for the given symbols. */\n async getQuotes(symbols: string[]): Promise<QuotesResponse> {\n const query = encodeURIComponent(symbols.join(\",\"));\n return this.request<QuotesResponse>(`/api/quotes?symbols=${query}`);\n }\n\n /** Paginated SEC symbol catalog with optional search and sort. */\n async listSymbols(params: {\n offset?: number;\n limit?: number;\n sort?: \"ticker\" | \"title\";\n q?: string;\n symbol?: string;\n name?: string;\n } = {}): Promise<SymbolsListResponse> {\n const search = new URLSearchParams();\n if (params.offset !== undefined) search.set(\"offset\", String(params.offset));\n if (params.limit !== undefined) search.set(\"limit\", String(params.limit));\n if (params.sort) search.set(\"sort\", params.sort);\n if (params.q) search.set(\"q\", params.q);\n if (params.symbol) search.set(\"symbol\", params.symbol);\n if (params.name) search.set(\"name\", params.name);\n const qs = search.toString();\n return this.request<SymbolsListResponse>(`/api/symbols${qs ? `?${qs}` : \"\"}`);\n }\n\n /** Create a new anonymous watchlist and return its MD5 token. */\n async createWatchlist(): Promise<Watchlist> {\n return this.request<Watchlist>(`/api/watchlists`, { method: \"POST\" });\n }\n\n /** Fetch a watchlist (symbols + metadata) by token. */\n async getWatchlist(token = this.requireToken()): Promise<Watchlist> {\n return this.request<Watchlist>(`/api/w/${token}`);\n }\n\n /** Add a symbol to a watchlist. */\n async addSymbol(symbol: string, token = this.requireToken()): Promise<Watchlist> {\n return this.request<Watchlist>(`/api/w/${token}/symbols`, {\n method: \"POST\",\n body: JSON.stringify({ symbol: symbol.toUpperCase() }),\n });\n }\n\n /** Notes for a symbol on a watchlist. */\n async getNotes(symbol: string, token = this.requireToken()): Promise<NotesResponse> {\n const query = encodeURIComponent(symbol.toUpperCase());\n return this.request<NotesResponse>(`/api/w/${token}/notes?symbol=${query}`);\n }\n\n /** Post an anonymous note to a symbol. */\n async addNote(input: CreateNoteInput, token = this.requireToken()): Promise<Note> {\n return this.request<Note>(`/api/w/${token}/notes`, {\n method: \"POST\",\n body: JSON.stringify({ ...input, symbol: input.symbol.toUpperCase() }),\n });\n }\n\n private requireToken(): string {\n if (!this.token) {\n throw new Error(\"A watchlist token is required. Pass --token or set TEEMTAPE_TOKEN.\");\n }\n return this.token;\n }\n\n private async request<T>(path: string, init: RequestInit = {}): Promise<T> {\n const headers = new Headers(init.headers);\n if (init.body && !headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"application/json\");\n }\n headers.set(\"accept\", \"application/json\");\n\n const res = await this.fetchImpl(`${this.baseUrl}${path}`, { ...init, headers });\n const text = await res.text();\n const data = text ? safeJsonParse(text) : undefined;\n\n if (!res.ok) {\n const message =\n (isRecord(data) && typeof data.error === \"string\" && data.error) ||\n `Request to ${path} failed with ${res.status}`;\n throw new ApiError(res.status, message, data);\n }\n return data as T;\n }\n}\n\nfunction safeJsonParse(text: string): unknown {\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n","#!/usr/bin/env node\nimport { ApiError } from \"@teemtape/api-client\";\nimport { Command } from \"commander\";\nimport { addCommand } from \"./commands/add.js\";\nimport { configCommand } from \"./commands/config.js\";\nimport { initCommand } from \"./commands/init.js\";\nimport { listCommand } from \"./commands/list.js\";\nimport { noteCommand } from \"./commands/note.js\";\nimport { notesCommand } from \"./commands/notes.js\";\nimport { searchCommand } from \"./commands/search.js\";\nimport { shareCommand } from \"./commands/share.js\";\nimport { createContext, type Context, type GlobalFlags } from \"./context.js\";\nimport { configureProxyFromEnv, describeNetworkError } from \"./net.js\";\nimport { c } from \"./output.js\";\n\nconfigureProxyFromEnv();\n\nconst program = new Command();\n\nprogram\n .name(\"teemtape\")\n .description(\"teemtape — list stocks and post anonymous notes from the terminal.\")\n .version(\"0.0.0\")\n .option(\"--api-url <url>\", \"Worker API base URL (env: TEEMTAPE_API_URL)\")\n .option(\"--token <token>\", \"watchlist token (env: TEEMTAPE_TOKEN)\")\n .option(\"--web-url <url>\", \"web app base URL used for share links (env: TEEMTAPE_WEB_URL)\")\n .option(\"--json\", \"output machine-readable JSON (handy for agents)\")\n .showHelpAfterError();\n\nfunction globalsOf(command: Command): GlobalFlags {\n const o = command.optsWithGlobals();\n return {\n apiUrl: o.apiUrl as string | undefined,\n token: o.token as string | undefined,\n webUrl: o.webUrl as string | undefined,\n json: Boolean(o.json),\n };\n}\n\nasync function run(command: Command, fn: (ctx: Context) => Promise<void>): Promise<void> {\n try {\n const ctx = createContext(globalsOf(command));\n await fn(ctx);\n } catch (err) {\n handleError(err);\n }\n}\n\nfunction fail(message: string): void {\n process.stderr.write(`${c.red(\"error:\")} ${message}\\n`);\n process.exitCode = 1;\n}\n\nfunction handleError(err: unknown): void {\n if (err instanceof ApiError) {\n fail(`${err.message} (HTTP ${err.status})`);\n return;\n }\n const networkMessage = describeNetworkError(err);\n if (networkMessage) {\n fail(networkMessage);\n return;\n }\n fail(err instanceof Error ? err.message : String(err));\n}\n\nprogram\n .command(\"init\")\n .description(\"create a new anonymous watchlist and save its token locally\")\n .action(async (_opts, command: Command) => run(command, (ctx) => initCommand(ctx)));\n\nprogram\n .command(\"list\")\n .description(\"show delayed quotes for your watchlist (or --symbols)\")\n .option(\"-s, --symbols <list>\", \"comma-separated symbols to show instead of the watchlist\")\n .action(async (opts: { symbols?: string }, command: Command) =>\n run(command, (ctx) => listCommand(ctx, opts)),\n );\n\nprogram\n .command(\"search\")\n .argument(\"[query]\", \"search ticker or company name (substring match)\")\n .description(\"search the SEC symbol catalog by ticker or company name\")\n .option(\"--symbol <text>\", \"filter by ticker substring only\")\n .option(\"--name <text>\", \"filter by company name substring only\")\n .option(\"--limit <n>\", \"max results to return (default 20, max 100)\")\n .option(\"--offset <n>\", \"skip first n matches (for paging)\")\n .option(\"--sort <field>\", \"sort by ticker or title\", \"ticker\")\n .action(async (query: string | undefined, opts: SearchCliOptions, command: Command) =>\n run(command, (ctx) => searchCommand(ctx, query, opts)),\n );\n\nprogram\n .command(\"add\")\n .argument(\"<symbol>\", \"ticker symbol, e.g. AAPL\")\n .description(\"add a symbol to your watchlist\")\n .action(async (symbol: string, _opts, command: Command) =>\n run(command, (ctx) => addCommand(ctx, symbol)),\n );\n\nprogram\n .command(\"notes\")\n .argument(\"<symbol>\", \"ticker symbol, e.g. AAPL\")\n .description(\"read the anonymous note thread for a symbol\")\n .action(async (symbol: string, _opts, command: Command) =>\n run(command, (ctx) => notesCommand(ctx, symbol)),\n );\n\nprogram\n .command(\"note\")\n .argument(\"<symbol>\", \"ticker symbol, e.g. AAPL\")\n .requiredOption(\"-m, --message <text>\", \"the note to post\")\n .description(\"post an anonymous note to a symbol (tagged as source: cli)\")\n .action(async (symbol: string, opts: { message?: string }, command: Command) =>\n run(command, (ctx) => noteCommand(ctx, symbol, opts)),\n );\n\nprogram\n .command(\"share\")\n .description(\"print your anonymous shareable watchlist link\")\n .action(async (_opts, command: Command) => run(command, (ctx) => shareCommand(ctx)));\n\nprogram\n .command(\"config\")\n .description(\"show the resolved configuration (token masked)\")\n .action(async (_opts, command: Command) => run(command, (ctx) => configCommand(ctx)));\n\ninterface SearchCliOptions {\n symbol?: string;\n name?: string;\n limit?: string;\n offset?: string;\n sort?: \"ticker\" | \"title\";\n}\n\nprogram.addHelpText(\n \"after\",\n `\nExamples:\n $ teemtape --api-url http://localhost:8787 init\n $ teemtape search nvidia\n $ teemtape search --symbol nv\n $ teemtape search --name microsoft\n $ teemtape add NVDA\n $ teemtape list\n $ teemtape notes NVDA\n $ teemtape note AAPL --message \"Earnings call scheduled.\"\n $ teemtape share\n $ teemtape list --json # machine-readable output for agents\n\nConfig precedence: CLI flags > env vars > ~/.config/teemtape/config.json > defaults\n`,\n);\n\nprogram.parseAsync().catch(handleError);\n","import type { Note, Quote, SymbolsListResponse } from \"@teemtape/api-client\";\n\nconst useColor = Boolean(process.stdout.isTTY) && !process.env.NO_COLOR;\n\nconst codes = {\n reset: \"\\x1b[0m\",\n dim: \"\\x1b[2m\",\n bold: \"\\x1b[1m\",\n green: \"\\x1b[32m\",\n red: \"\\x1b[31m\",\n yellow: \"\\x1b[33m\",\n cyan: \"\\x1b[36m\",\n} as const;\n\nfunction paint(code: string, text: string): string {\n return useColor ? `${code}${text}${codes.reset}` : text;\n}\n\nexport const c = {\n dim: (t: string) => paint(codes.dim, t),\n bold: (t: string) => paint(codes.bold, t),\n green: (t: string) => paint(codes.green, t),\n red: (t: string) => paint(codes.red, t),\n yellow: (t: string) => paint(codes.yellow, t),\n cyan: (t: string) => paint(codes.cyan, t),\n};\n\nexport function printJson(value: unknown): void {\n process.stdout.write(`${JSON.stringify(value, null, 2)}\\n`);\n}\n\nfunction money(n: number): string {\n return `$${n.toFixed(2)}`;\n}\n\nfunction signed(n: number): string {\n return `${n >= 0 ? \"+\" : \"\"}${n.toFixed(2)}`;\n}\n\nfunction pad(text: string, width: number): string {\n return text.length >= width ? text : text + \" \".repeat(width - text.length);\n}\n\nfunction padStart(text: string, width: number): string {\n return text.length >= width ? text : \" \".repeat(width - text.length) + text;\n}\n\n/** Render the watchlist quotes as an aligned table. */\nexport function printQuotesTable(quotes: Quote[], delayedSeconds: number, source: string): void {\n if (quotes.length === 0) {\n process.stdout.write(c.dim(\"No symbols on this watchlist yet. Add one with `teemtape add <SYMBOL>`.\\n\"));\n return;\n }\n\n const header = `${pad(\"SYMBOL\", 8)}${pad(\"COMPANY\", 26)}${padStart(\"LAST\", 10)} ${padStart(\"CHANGE\", 18)}`;\n process.stdout.write(`${c.dim(header)}\\n`);\n\n for (const q of quotes) {\n const changeText = `${signed(q.change)} (${signed(q.pct)}%)`;\n const colored = q.change >= 0 ? c.green(changeText) : c.red(changeText);\n const row =\n pad(q.symbol, 8) +\n pad(truncate(q.name, 25), 26) +\n padStart(money(q.price), 10) +\n \" \" +\n padStartColored(colored, changeText, 18);\n process.stdout.write(`${row}\\n`);\n }\n\n const mins = Math.round(delayedSeconds / 60);\n process.stdout.write(\n `\\n${c.dim(`# prices delayed ~${mins} min · source: ${source}`)}\\n`,\n );\n}\n\n/** Render symbol catalog search results as an aligned table. */\nexport function printSymbolsTable(res: SymbolsListResponse): void {\n if (res.symbols.length === 0) {\n process.stdout.write(c.dim(\"No symbols matched. Try a different query.\\n\"));\n return;\n }\n\n const header = `${pad(\"TICKER\", 8)}${pad(\"COMPANY\", 40)}`;\n process.stdout.write(`${c.dim(header)}\\n`);\n\n for (const s of res.symbols) {\n const row = pad(s.ticker, 8) + pad(truncate(s.title, 39), 40);\n process.stdout.write(`${row}\\n`);\n }\n\n const shown = res.symbols.length;\n const start = res.total === 0 ? 0 : res.offset + 1;\n const end = res.offset + shown;\n const range =\n res.total === 0\n ? \"0 matches\"\n : shown === 1\n ? `${start} of ${res.total}`\n : `${start}–${end} of ${res.total}`;\n process.stdout.write(`\\n${c.dim(`# ${range}`)}\\n`);\n}\n\n/** Render a note thread for a symbol. */\nexport function printNotes(symbol: string, notes: Note[]): void {\n process.stdout.write(`${c.bold(symbol)} ${c.dim(\"notes\")}\\n`);\n process.stdout.write(`${c.dim(\"─\".repeat(44))}\\n`);\n if (notes.length === 0) {\n process.stdout.write(`${c.dim(\"No notes yet. Add one with `teemtape note \" + symbol + ' --message \"…\"`.')}\\n`);\n return;\n }\n for (const n of notes) {\n const src = n.source === \"cli\" ? c.yellow(`(cli, ${rel(n.createdAt)})`) : c.dim(`(web, ${rel(n.createdAt)})`);\n process.stdout.write(`${c.cyan(n.author)} ${src}\\n`);\n process.stdout.write(` ${n.body}\\n`);\n }\n}\n\nfunction truncate(text: string, max: number): string {\n return text.length <= max ? text : `${text.slice(0, max - 1)}…`;\n}\n\n// Right-pad accounting for invisible ANSI codes by padding the plain text width.\nfunction padStartColored(colored: string, plain: string, width: number): string {\n const padding = Math.max(0, width - plain.length);\n return \" \".repeat(padding) + colored;\n}\n\nfunction rel(iso: string): string {\n const then = new Date(iso).getTime();\n if (Number.isNaN(then)) return iso;\n const diffMs = Date.now() - then;\n const mins = Math.round(diffMs / 60000);\n if (mins < 1) return \"just now\";\n if (mins < 60) return `${mins}m ago`;\n const hours = Math.round(mins / 60);\n if (hours < 24) return `${hours}h ago`;\n return `${Math.round(hours / 24)}d ago`;\n}\n","import type { Context } from \"../context.js\";\nimport { c, printJson } from \"../output.js\";\n\n/** `teemtape add <SYMBOL>` — add a symbol to the watchlist. */\nexport async function addCommand(ctx: Context, symbol: string): Promise<void> {\n const watchlist = await ctx.client.addSymbol(symbol);\n if (ctx.json) {\n printJson(watchlist);\n return;\n }\n process.stdout.write(`${c.green(\"✓\")} Added ${c.bold(symbol.toUpperCase())}\\n`);\n process.stdout.write(` ${c.dim(`watchlist: ${watchlist.symbols.join(\", \") || \"(empty)\"}`)}\\n`);\n}\n","import { mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\n/** Resolved runtime configuration for a CLI invocation. */\nexport interface ResolvedConfig {\n apiUrl: string;\n webUrl: string;\n token?: string;\n}\n\nexport interface ConfigFlags {\n apiUrl?: string;\n webUrl?: string;\n token?: string;\n}\n\nconst DEFAULTS = {\n apiUrl: \"https://api.teemtape.com\",\n webUrl: \"https://www.teemtape.com\",\n};\n\n/** Path to the persisted config file (XDG-aware, falls back to ~/.config). */\nexport function configFilePath(): string {\n const base = process.env.XDG_CONFIG_HOME || join(homedir(), \".config\");\n return join(base, \"teemtape\", \"config.json\");\n}\n\ninterface StoredConfig {\n apiUrl?: string;\n webUrl?: string;\n token?: string;\n}\n\nfunction readConfigFile(): StoredConfig {\n try {\n return JSON.parse(readFileSync(configFilePath(), \"utf8\")) as StoredConfig;\n } catch {\n return {};\n }\n}\n\n/**\n * Resolve config with precedence: CLI flags > environment > config file > defaults.\n * (See docs/cli-options.md.)\n */\nexport function resolveConfig(flags: ConfigFlags = {}): ResolvedConfig {\n const file = readConfigFile();\n const env = {\n apiUrl: process.env.TEEMTAPE_API_URL,\n webUrl: process.env.TEEMTAPE_WEB_URL,\n token: process.env.TEEMTAPE_TOKEN,\n };\n\n return {\n apiUrl: flags.apiUrl ?? env.apiUrl ?? file.apiUrl ?? DEFAULTS.apiUrl,\n webUrl: flags.webUrl ?? env.webUrl ?? file.webUrl ?? DEFAULTS.webUrl,\n token: flags.token ?? env.token ?? file.token,\n };\n}\n\n/** Persist values to the config file (merges with existing). */\nexport function saveConfig(patch: StoredConfig): string {\n const path = configFilePath();\n const merged = { ...readConfigFile(), ...patch };\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, `${JSON.stringify(merged, null, 2)}\\n`, { mode: 0o600 });\n return path;\n}\n\n/** Mask a token for display so it never gets fully printed/logged. */\nexport function maskToken(token?: string): string {\n if (!token) return \"(none)\";\n if (token.length <= 8) return \"****\";\n return `${token.slice(0, 6)}…${token.slice(-2)}`;\n}\n","import type { Context } from \"../context.js\";\nimport { configFilePath, maskToken } from \"../config.js\";\nimport { c, printJson } from \"../output.js\";\n\n/** `teemtape config` — show the resolved configuration (token masked). */\nexport async function configCommand(ctx: Context): Promise<void> {\n const view = {\n apiUrl: ctx.config.apiUrl,\n webUrl: ctx.config.webUrl,\n token: maskToken(ctx.config.token),\n configFile: configFilePath(),\n };\n if (ctx.json) {\n printJson(view);\n return;\n }\n process.stdout.write(`${c.bold(\"teemtape config\")}\\n`);\n process.stdout.write(` api url : ${view.apiUrl}\\n`);\n process.stdout.write(` web url : ${view.webUrl}\\n`);\n process.stdout.write(` token : ${view.token}\\n`);\n process.stdout.write(` ${c.dim(`config file: ${view.configFile}`)}\\n`);\n}\n","import type { Context } from \"../context.js\";\nimport { saveConfig } from \"../config.js\";\nimport { c, printJson } from \"../output.js\";\n\n/** `teemtape init` — create a new anonymous watchlist and save its token locally. */\nexport async function initCommand(ctx: Context): Promise<void> {\n const watchlist = await ctx.client.createWatchlist();\n const path = saveConfig({ token: watchlist.token });\n const url = `${ctx.config.webUrl.replace(/\\/$/, \"\")}/w/${watchlist.token}`;\n\n if (ctx.json) {\n printJson({ token: watchlist.token, url, configPath: path });\n return;\n }\n process.stdout.write(`${c.green(\"✓\")} Created a new anonymous watchlist\\n`);\n process.stdout.write(` ${c.dim(`token saved to ${path}`)}\\n`);\n process.stdout.write(` ${c.dim(\"share link:\")} ${url}\\n`);\n}\n","import type { Context } from \"../context.js\";\nimport { printJson, printQuotesTable } from \"../output.js\";\n\nexport interface ListOptions {\n symbols?: string;\n}\n\n/** `teemtape list` — show delayed quotes for the watchlist (or --symbols). */\nexport async function listCommand(ctx: Context, opts: ListOptions): Promise<void> {\n let symbols: string[];\n if (opts.symbols) {\n symbols = splitSymbols(opts.symbols);\n } else {\n const watchlist = await ctx.client.getWatchlist();\n symbols = watchlist.symbols;\n }\n\n if (symbols.length === 0) {\n if (ctx.json) {\n printJson({ quotes: [], delayedSeconds: 0, source: \"none\" });\n return;\n }\n process.stdout.write(\"No symbols to show. Add one with `teemtape add <SYMBOL>`.\\n\");\n return;\n }\n\n const res = await ctx.client.getQuotes(symbols);\n if (ctx.json) {\n printJson(res);\n return;\n }\n printQuotesTable(res.quotes, res.delayedSeconds, res.source);\n}\n\nfunction splitSymbols(raw: string): string[] {\n return raw\n .split(\",\")\n .map((s) => s.trim().toUpperCase())\n .filter(Boolean);\n}\n","import type { Context } from \"../context.js\";\nimport { c, printJson } from \"../output.js\";\n\nexport interface NoteOptions {\n message?: string;\n}\n\n/** `teemtape note <SYMBOL> --message \"…\"` — post an anonymous note (source: cli). */\nexport async function noteCommand(ctx: Context, symbol: string, opts: NoteOptions): Promise<void> {\n const body = opts.message?.trim();\n if (!body) {\n throw new Error(\"A note message is required. Use --message \\\"your note\\\".\");\n }\n\n const note = await ctx.client.addNote({ symbol, body, source: \"cli\" });\n if (ctx.json) {\n printJson(note);\n return;\n }\n process.stdout.write(`${c.green(\"✓\")} Note posted to ${c.bold(note.symbol)} as ${c.cyan(note.author)}\\n`);\n process.stdout.write(` ${c.dim(`id: ${note.id} · visible in web & mobile note popups`)}\\n`);\n}\n","import type { Context } from \"../context.js\";\nimport { printJson, printNotes } from \"../output.js\";\n\n/** `teemtape notes <SYMBOL>` — read the note thread for a symbol. */\nexport async function notesCommand(ctx: Context, symbol: string): Promise<void> {\n const res = await ctx.client.getNotes(symbol);\n if (ctx.json) {\n printJson(res);\n return;\n }\n printNotes(res.symbol, res.notes);\n}\n","import type { Context } from \"../context.js\";\nimport { c, printJson, printSymbolsTable } from \"../output.js\";\n\nexport interface SearchOptions {\n symbol?: string;\n name?: string;\n limit?: string;\n offset?: string;\n sort?: \"ticker\" | \"title\";\n}\n\n/** `teemtape search` — find symbols in the SEC catalog by ticker or company name. */\nexport async function searchCommand(\n ctx: Context,\n query: string | undefined,\n opts: SearchOptions,\n): Promise<void> {\n const q = query?.trim();\n const symbol = opts.symbol?.trim();\n const name = opts.name?.trim();\n\n if (!q && !symbol && !name) {\n process.stderr.write(\n `${c.red(\"error:\")} provide a search query, or use --symbol and/or --name.\\n`,\n );\n process.exitCode = 1;\n return;\n }\n\n const res = await ctx.client.listSymbols({\n ...(q ? { q } : {}),\n ...(symbol ? { symbol } : {}),\n ...(name ? { name } : {}),\n ...(opts.limit !== undefined ? { limit: parsePositiveInt(opts.limit, \"limit\") } : { limit: 20 }),\n ...(opts.offset !== undefined ? { offset: parsePositiveInt(opts.offset, \"offset\") } : {}),\n ...(opts.sort ? { sort: opts.sort } : {}),\n });\n\n if (ctx.json) {\n printJson(res);\n return;\n }\n\n printSymbolsTable(res);\n}\n\nfunction parsePositiveInt(raw: string, label: string): number {\n const n = Number.parseInt(raw, 10);\n if (!Number.isFinite(n) || n < 0) {\n throw new Error(`invalid ${label}: ${raw}`);\n }\n return n;\n}\n","import type { Context } from \"../context.js\";\nimport { c, printJson } from \"../output.js\";\n\n/** `teemtape share` — print the anonymous shareable watchlist link. */\nexport async function shareCommand(ctx: Context): Promise<void> {\n const token = ctx.config.token;\n if (!token) {\n throw new Error(\"No watchlist token set. Run `teemtape init` to create one, or pass --token.\");\n }\n const url = `${ctx.config.webUrl.replace(/\\/$/, \"\")}/w/${token}`;\n if (ctx.json) {\n printJson({ url, token });\n return;\n }\n process.stdout.write(`${c.dim(\"# your anonymous watchlist link (share with anyone):\")}\\n`);\n process.stdout.write(`${url}\\n`);\n}\n","import { TeemtapeClient } from \"@teemtape/api-client\";\nimport { resolveConfig, type ConfigFlags, type ResolvedConfig } from \"./config.js\";\n\nexport interface GlobalFlags extends ConfigFlags {\n json?: boolean;\n}\n\nexport interface Context {\n config: ResolvedConfig;\n json: boolean;\n client: TeemtapeClient;\n}\n\n/** Build the per-invocation context (resolved config + a ready API client). */\nexport function createContext(flags: GlobalFlags): Context {\n const config = resolveConfig(flags);\n const client = new TeemtapeClient({ baseUrl: config.apiUrl, token: config.token });\n return { config, json: Boolean(flags.json), client };\n}\n","import { EnvHttpProxyAgent, setGlobalDispatcher } from \"undici\";\n\nconst PROXY_ENV_VARS = [\"HTTPS_PROXY\", \"https_proxy\", \"HTTP_PROXY\", \"http_proxy\"] as const;\n\n/**\n * Node's built-in `fetch` does not read the standard `HTTP(S)_PROXY` / `NO_PROXY`\n * environment variables the way tools like `curl` do. On networks that require a\n * proxy this shows up as an opaque \"fetch failed\". When a proxy variable is set,\n * route fetch through it so the CLI behaves like the rest of the user's tooling.\n */\nexport function configureProxyFromEnv(): void {\n const hasProxy = PROXY_ENV_VARS.some((name) => Boolean(process.env[name]));\n if (!hasProxy) return;\n // EnvHttpProxyAgent reads HTTP_PROXY/HTTPS_PROXY/NO_PROXY itself.\n setGlobalDispatcher(new EnvHttpProxyAgent());\n}\n\n// Node/undici error codes that mean \"the request never completed\".\nconst NETWORK_CODES = new Set([\n \"ENOTFOUND\",\n \"EAI_AGAIN\",\n \"ECONNREFUSED\",\n \"ECONNRESET\",\n \"ETIMEDOUT\",\n \"EPIPE\",\n \"ENETUNREACH\",\n \"EHOSTUNREACH\",\n \"UND_ERR_CONNECT_TIMEOUT\",\n \"UND_ERR_SOCKET\",\n \"UND_ERR_HEADERS_TIMEOUT\",\n \"UND_ERR_BODY_TIMEOUT\",\n]);\n\nconst TLS_CODES = new Set([\n \"CERT_HAS_EXPIRED\",\n \"DEPTH_ZERO_SELF_SIGNED_CERT\",\n \"SELF_SIGNED_CERT_IN_CHAIN\",\n \"UNABLE_TO_VERIFY_LEAF_SIGNATURE\",\n \"ERR_TLS_CERT_ALTNAME_INVALID\",\n]);\n\nfunction causeCode(err: Error): string | undefined {\n const cause = err.cause as { code?: unknown } | undefined;\n return typeof cause?.code === \"string\" ? cause.code : undefined;\n}\n\n/**\n * Turn the unhelpful `fetch failed` (and friends) into an actionable message that\n * names the underlying cause and points at the most common fixes. Returns\n * `undefined` for anything that is not a network/transport failure.\n */\nexport function describeNetworkError(err: unknown): string | undefined {\n if (!(err instanceof Error)) return undefined;\n const code = causeCode(err);\n const isNetworkFailure = err.message === \"fetch failed\" || (code !== undefined && NETWORK_CODES.has(code));\n if (!isNetworkFailure && !(code !== undefined && TLS_CODES.has(code))) return undefined;\n\n const reason = code ? ` (${code})` : \"\";\n const lines = [`could not reach the API${reason}.`];\n\n if (code && TLS_CODES.has(code)) {\n lines.push(\"This is a TLS/certificate problem. If a proxy or antivirus intercepts HTTPS,\");\n lines.push(\"point Node at its root certificate via NODE_EXTRA_CA_CERTS=/path/to/ca.pem.\");\n } else {\n lines.push(\"Check your connection and that the API URL is correct (run `teemtape config`).\");\n lines.push(\"Behind a proxy? Set HTTPS_PROXY (and NO_PROXY for exceptions) and retry — the CLI\");\n lines.push(\"now honors them, but Node's fetch ignores proxy settings by default (curl does not).\");\n }\n lines.push(\"For local testing run `npm run mock` and pass --api-url http://localhost:8787.\");\n return lines.join(\"\\n \");\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teemtape/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "teemtape CLI — list stocks and post anonymous notes from the terminal.",
|
|
5
5
|
"license": "MIT",
|
|
6
|
+
"homepage": "https://github.com/kiwifellows/teemtape#readme",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/kiwifellows/teemtape.git",
|
|
10
|
+
"directory": "packages/cli"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/kiwifellows/teemtape/issues"
|
|
14
|
+
},
|
|
6
15
|
"type": "module",
|
|
7
16
|
"bin": {
|
|
8
17
|
"teemtape": "./dist/index.js"
|
|
@@ -11,14 +20,16 @@
|
|
|
11
20
|
"dist"
|
|
12
21
|
],
|
|
13
22
|
"scripts": {
|
|
23
|
+
"prebuild": "npm run build -w @teemtape/api-client --prefix ../..",
|
|
14
24
|
"build": "tsup",
|
|
15
25
|
"dev": "tsup --watch",
|
|
16
26
|
"test": "node --test",
|
|
17
27
|
"start": "node dist/index.js"
|
|
18
28
|
},
|
|
19
29
|
"dependencies": {
|
|
20
|
-
"@teemtape/api-client": "
|
|
21
|
-
"commander": "^12.1.0"
|
|
30
|
+
"@teemtape/api-client": "^0.1.2",
|
|
31
|
+
"commander": "^12.1.0",
|
|
32
|
+
"undici": "^7.28.0"
|
|
22
33
|
},
|
|
23
34
|
"devDependencies": {
|
|
24
35
|
"@types/node": "^20.12.0",
|