mirror of
https://github.com/jackwener/OpenCLI.git
synced 2026-09-14 18:25:42 +08:00
68485cc54e
* feat(devto): surface article id + published_at on listings, add `read <id>` Agent-native gap: devto listings (`top`/`tag`/`user`) didn't include the article `id`, so an agent couldn't round-trip from a listing into a body read. They also dropped `reading_time` and `published_at`, which are cheap signals the API gives you for free. Changes: - `top` / `tag` / `user`: add `id`, `reading_time`, `published_at` columns alongside existing rank/title/etc. `user` keeps its no-author shape since it's already user-scoped. - New `devto read <id>`: hits `dev.to/api/articles/<id>` and returns one row with the article body (truncated by `--max-length`, default 20000, min 100). DEV.to's public API does not expose comments yet, so this is intentionally a single-row reader rather than a HN/lobsters-style threaded tree — if/when comments become public we can extend to POST + L0/L1. - Typed fail-fast: `ArgumentError` for non-numeric id and for `--max-length` below 100; `EmptyResultError` on 404; `CommandExecutionError` for other non-2xx HTTP statuses. No silent clamps. - Defensive tag normalization: the `/api/articles/<id>` endpoint returns `tag_list` as a comma-string and `tags` as an array (the opposite shape from listing endpoints). Caught this on live verification — both shapes now collapse to a comma-joined string. Tests: 12 vitest assertions covering listing column shape (all 3) + register/args/strategy + typed-error fail-fast paths + happy-path body extraction + truncation marker + alternate tag_list shape. Live verification: `devto top --limit 3` and `devto read 3602287` both return the expected agent-native shape. * fix(devto): harden article read contract
35 lines
1.3 KiB
JavaScript
35 lines
1.3 KiB
JavaScript
import { cli, Strategy } from '@jackwener/opencli/registry';
|
|
cli({
|
|
site: 'devto',
|
|
name: 'user',
|
|
description: 'Recent DEV.to articles from a specific user',
|
|
domain: 'dev.to',
|
|
strategy: Strategy.PUBLIC,
|
|
browser: false,
|
|
args: [
|
|
{
|
|
name: 'username',
|
|
required: true,
|
|
positional: true,
|
|
help: 'DEV.to username (e.g. ben, thepracticaldev)',
|
|
},
|
|
{ name: 'limit', type: 'int', default: 20, help: 'Number of articles' },
|
|
],
|
|
columns: ['rank', 'id', 'title', 'reactions', 'comments', 'reading_time', 'published_at', 'tags', 'url'],
|
|
pipeline: [
|
|
{ fetch: { url: 'https://dev.to/api/articles?username=${{ args.username }}&per_page=${{ args.limit }}' } },
|
|
{ map: {
|
|
rank: '${{ index + 1 }}',
|
|
id: '${{ item.id }}',
|
|
title: '${{ item.title }}',
|
|
reactions: '${{ item.public_reactions_count }}',
|
|
comments: '${{ item.comments_count }}',
|
|
reading_time: '${{ item.reading_time_minutes }}',
|
|
published_at: '${{ item.published_at }}',
|
|
tags: `\${{ item.tag_list | join(', ') }}`,
|
|
url: '${{ item.url }}',
|
|
} },
|
|
{ limit: '${{ args.limit }}' },
|
|
],
|
|
});
|