@teemtape/cli 0.1.0 → 0.1.1

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 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` | `http://localhost:8787` |
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.app` |
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: "http://localhost:8787",
222
- webUrl: "https://teemtape.app"
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;
@@ -420,6 +476,9 @@ program.command("init").description("create a new anonymous watchlist and save i
420
476
  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
477
  async (opts, command) => run(command, (ctx) => listCommand(ctx, opts))
422
478
  );
479
+ 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(
480
+ async (query, opts, command) => run(command, (ctx) => searchCommand(ctx, query, opts))
481
+ );
423
482
  program.command("add").argument("<symbol>", "ticker symbol, e.g. AAPL").description("add a symbol to your watchlist").action(
424
483
  async (symbol, _opts, command) => run(command, (ctx) => addCommand(ctx, symbol))
425
484
  );
@@ -436,6 +495,9 @@ program.addHelpText(
436
495
  `
437
496
  Examples:
438
497
  $ teemtape --api-url http://localhost:8787 init
498
+ $ teemtape search nvidia
499
+ $ teemtape search --symbol nv
500
+ $ teemtape search --name microsoft
439
501
  $ teemtape add NVDA
440
502
  $ teemtape list
441
503
  $ 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"],"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 { 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(\"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"],"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.0",
3
+ "version": "0.1.1",
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"
@@ -17,7 +26,7 @@
17
26
  "start": "node dist/index.js"
18
27
  },
19
28
  "dependencies": {
20
- "@teemtape/api-client": "*",
29
+ "@teemtape/api-client": "^0.1.1",
21
30
  "commander": "^12.1.0"
22
31
  },
23
32
  "devDependencies": {