birdclaw 0.8.3 → 0.8.4
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/CHANGELOG.md +17 -0
- package/README.md +10 -8
- package/bin/birdclaw.mjs +4 -66
- package/dist/cli/birdclaw.js +28165 -0
- package/dist/client/assets/AvatarChip-DLoqM5xD.js +1 -0
- package/dist/client/assets/ProfilePreview-BejAuYsJ.js +1 -0
- package/dist/client/assets/SavedTimelineView-BIS7HKpp.js +1 -0
- package/dist/client/assets/SmartTimestamp-BR0-9se2.js +1 -0
- package/dist/client/assets/TimelineRouteFrame-CyGPj0eM.js +1 -0
- package/dist/client/assets/blocks-7UDKQp8H.js +1 -0
- package/dist/client/assets/bookmarks-CbBkMvXk.js +1 -0
- package/dist/client/assets/chunk-C0phanGV.js +1 -0
- package/dist/client/assets/circle-check-C_Vq3ElD.js +1 -0
- package/dist/client/assets/client-stream-contracts-ys3XhWG4.js +5 -0
- package/dist/client/assets/createLucideIcon-JV8isFFR.js +1 -0
- package/dist/client/assets/data-sources-Cm2bpNvg.js +1 -0
- package/dist/client/assets/discuss-DTjaOugw.js +1 -0
- package/dist/client/assets/dms-CGd6Eogq.js +1 -0
- package/dist/client/assets/inbox-BHlGuOy2.js +1 -0
- package/dist/client/assets/index-CEIG7S6s.js +31 -0
- package/dist/client/assets/index-bpFrQ5yG.css +1 -0
- package/dist/client/assets/likes-cLrcAQem.js +1 -0
- package/dist/client/assets/links-CM9QO1LC.js +1 -0
- package/dist/client/assets/mapbox-BxTlqXt9.js +2 -0
- package/dist/client/assets/mapbox-gl-dgf_hX3a.js +3215 -0
- package/dist/client/assets/mentions-CxKCgzIf.js +1 -0
- package/dist/client/assets/network-map-B5a3whqj.js +2 -0
- package/dist/client/assets/profile-analyze-CRtNEwlb.js +1 -0
- package/dist/client/assets/profile-hydration-client-YEtJsNTv.js +1 -0
- package/dist/client/assets/profiles._handle-C82_HoKX.js +1 -0
- package/dist/client/assets/query-client-fYu2rzRC.js +17 -0
- package/dist/client/assets/rate-limits-ScaEwdVK.js +1 -0
- package/dist/client/assets/react-dom-DHl6Ug7F.js +1 -0
- package/dist/client/assets/react-nBylq1U5.js +1 -0
- package/dist/client/assets/repeat-2-xCwHM9hD.js +1 -0
- package/dist/client/assets/routes-q7ZaW4En.js +1 -0
- package/dist/client/assets/schemas-I9r6F6ya.js +64 -0
- package/dist/client/assets/search-Dq5kYsxA.js +1 -0
- package/dist/client/assets/sparkles-CQVlvHsZ.js +1 -0
- package/dist/client/assets/styles-B8s3tt3r.css +2 -0
- package/dist/client/assets/today-CeG1O7Py.js +1 -0
- package/dist/client/assets/triangle-alert-CBL7s2pf.js +1 -0
- package/dist/client/assets/useTimelineRouteData-1HsqgvUi.js +1 -0
- package/dist/client/assets/users-CHbKlqUr.js +1 -0
- package/dist/server/assets/AvatarChip-zUDAEmjL.js +105 -0
- package/dist/server/assets/FeedState-ntW0Q2GB.js +214 -0
- package/dist/server/assets/ProfileAnalysisStream-BFvhVdhn.js +198 -0
- package/dist/server/assets/ProfilePreview-C6gAor_j.js +752 -0
- package/dist/server/assets/SavedTimelineView-BG1jnBp1.js +64 -0
- package/dist/server/assets/SmartTimestamp-DfwE1NGf.js +45 -0
- package/dist/server/assets/SyncNowButton-BOn_IBXS.js +76 -0
- package/dist/server/assets/TimelineRouteFrame-CU7ilM7U.js +85 -0
- package/dist/server/assets/TweetRichText-DhCVv1-6.js +74 -0
- package/dist/server/assets/_tanstack-start-manifest_v-C-ZRnG_n.js +148 -0
- package/dist/server/assets/account-selection-CTdFGWRk.js +44 -0
- package/dist/server/assets/blocks-C1mgGTB3.js +299 -0
- package/dist/server/assets/blocks-DSgQghqP.js +17 -0
- package/dist/server/assets/bookmarks-BJN8tykY.js +14 -0
- package/dist/server/assets/client-stream-contracts-C2xbWVjm.js +769 -0
- package/dist/server/assets/data-sources-BnA1Q94p.js +180 -0
- package/dist/server/assets/discuss-CJ1dau1j.js +15 -0
- package/dist/server/assets/discuss-QTo08NCN.js +338 -0
- package/dist/server/assets/dms-BuLj4bp8.js +368 -0
- package/dist/server/assets/dms-DAyQrVM2.js +240 -0
- package/dist/server/assets/empty-plugin-adapters-DzrEkdBF.js +5 -0
- package/dist/server/assets/inbox-CkGOaW1q.js +214 -0
- package/dist/server/assets/inbox-DpWd1EzC.js +146 -0
- package/dist/server/assets/likes-DBOAtsJU.js +14 -0
- package/dist/server/assets/links-DAhSjynu.js +240 -0
- package/dist/server/assets/links-DmH5lxHO.js +468 -0
- package/dist/server/assets/mentions-BH2MzKtB.js +26 -0
- package/dist/server/assets/network-map-D3CzRcC4.js +224 -0
- package/dist/server/assets/network-map-D5DoLOwR.js +582 -0
- package/dist/server/assets/profile-analyze-BP65PED0.js +90 -0
- package/dist/server/assets/profile-analyze-C1NoM0tV.js +9 -0
- package/dist/server/assets/profile-hydration-client-GJ4kwJS8.js +133 -0
- package/dist/server/assets/profiles._handle-DjwlN_ac.js +184 -0
- package/dist/server/assets/profiles._handle-DsLNj2Ca.js +12 -0
- package/dist/server/assets/query-client-BdauHBgd.js +923 -0
- package/dist/server/assets/rate-limits-VAr2qzYD.js +262 -0
- package/dist/server/assets/route-search-BUlQ5lGM.js +117 -0
- package/dist/server/assets/router-DqkwSPiM.js +17026 -0
- package/dist/server/assets/routes-A9c9ZhwN.js +26 -0
- package/dist/server/assets/start-FaDOTmto.js +4 -0
- package/dist/server/assets/today-B5hVM57Z.js +17 -0
- package/dist/server/assets/today-fvGiZ7ud.js +303 -0
- package/dist/server/assets/ui-qbmcMSSX.js +137 -0
- package/{src/components/useDebouncedValue.ts → dist/server/assets/useDebouncedValue-DOnA6Xcy.js} +4 -4
- package/dist/server/assets/useTimelineRouteData-27cxynxa.js +1101 -0
- package/dist/server/server.js +5520 -0
- package/package.json +26 -34
- package/playwright.config.ts +0 -35
- package/scripts/browser-perf.mjs +0 -427
- package/scripts/build-docs-site.mjs +0 -967
- package/scripts/docs-site-assets.mjs +0 -311
- package/scripts/run-vitest.mjs +0 -21
- package/scripts/sanitize-node-options.mjs +0 -23
- package/scripts/start-test-server.mjs +0 -42
- package/src/cli/command-context.ts +0 -17
- package/src/cli/register-analysis.ts +0 -500
- package/src/cli/register-compose.ts +0 -40
- package/src/cli/register-graph.ts +0 -132
- package/src/cli/register-inbox.ts +0 -41
- package/src/cli/register-storage.ts +0 -106
- package/src/cli-moderation.ts +0 -210
- package/src/cli.ts +0 -1616
- package/src/components/AccountSwitcher.tsx +0 -178
- package/src/components/AppNav.tsx +0 -118
- package/src/components/AvatarChip.tsx +0 -58
- package/src/components/AvatarPreload.ts +0 -149
- package/src/components/BrandMark.tsx +0 -67
- package/src/components/ConversationThread.tsx +0 -131
- package/src/components/DmWorkspace.tsx +0 -286
- package/src/components/EmbeddedTweetCard.tsx +0 -55
- package/src/components/FeedState.tsx +0 -147
- package/src/components/FloatingPreview.tsx +0 -382
- package/src/components/InboxCard.tsx +0 -152
- package/src/components/LinkPreviewCard.tsx +0 -292
- package/src/components/MarkdownCitations.tsx +0 -680
- package/src/components/MarkdownViewer.tsx +0 -111
- package/src/components/ProfileAnalysisClient.ts +0 -191
- package/src/components/ProfileAnalysisStream.tsx +0 -259
- package/src/components/ProfilePreview.tsx +0 -131
- package/src/components/SavedTimelineView.tsx +0 -155
- package/src/components/SmartTimestamp.tsx +0 -72
- package/src/components/SyncNowButton.tsx +0 -140
- package/src/components/ThemeSlider.tsx +0 -80
- package/src/components/TimelineCard.tsx +0 -533
- package/src/components/TimelineRouteFrame.tsx +0 -186
- package/src/components/TweetArticleCard.tsx +0 -66
- package/src/components/TweetMediaGrid.tsx +0 -185
- package/src/components/TweetRichText.tsx +0 -159
- package/src/components/account-selection.ts +0 -64
- package/src/components/links-controller.ts +0 -162
- package/src/components/links-model.ts +0 -198
- package/src/components/network-map-controller.ts +0 -84
- package/src/components/network-map-model.ts +0 -255
- package/src/components/useTimelineRouteData.ts +0 -193
- package/src/lib/account-sync-job.ts +0 -666
- package/src/lib/actions-transport.ts +0 -300
- package/src/lib/analysis-runtime.ts +0 -238
- package/src/lib/api-client.ts +0 -220
- package/src/lib/api-contracts.ts +0 -328
- package/src/lib/archive-finder.ts +0 -185
- package/src/lib/archive-import-plan.ts +0 -102
- package/src/lib/archive-import.ts +0 -2695
- package/src/lib/authored-live.ts +0 -1027
- package/src/lib/avatar-cache.ts +0 -349
- package/src/lib/backup.ts +0 -2652
- package/src/lib/bird-actions.ts +0 -294
- package/src/lib/bird-command.ts +0 -130
- package/src/lib/bird.ts +0 -1140
- package/src/lib/blocklist.ts +0 -136
- package/src/lib/blocks-write.ts +0 -171
- package/src/lib/blocks.ts +0 -387
- package/src/lib/bookmark-sync-job.ts +0 -536
- package/src/lib/config.ts +0 -224
- package/src/lib/conversation-surface.ts +0 -205
- package/src/lib/data-sources.ts +0 -219
- package/src/lib/database-metrics.ts +0 -88
- package/src/lib/database-migrations.ts +0 -34
- package/src/lib/database-schema.ts +0 -312
- package/src/lib/database-writer.ts +0 -69
- package/src/lib/db.ts +0 -889
- package/src/lib/dm-read-model.ts +0 -533
- package/src/lib/dms-live.ts +0 -870
- package/src/lib/effect-runtime.ts +0 -45
- package/src/lib/follow-graph.ts +0 -1087
- package/src/lib/geocoding.ts +0 -296
- package/src/lib/http-effect.ts +0 -222
- package/src/lib/identity-search-index.ts +0 -369
- package/src/lib/import-repository.ts +0 -138
- package/src/lib/inbox.ts +0 -242
- package/src/lib/link-index.ts +0 -641
- package/src/lib/link-insights.ts +0 -860
- package/src/lib/link-preview-metadata.ts +0 -754
- package/src/lib/live-sync-engine.ts +0 -209
- package/src/lib/live-transport-gateway.ts +0 -128
- package/src/lib/location.ts +0 -137
- package/src/lib/media-fetch.ts +0 -860
- package/src/lib/media-includes.ts +0 -165
- package/src/lib/mention-threads-live.ts +0 -830
- package/src/lib/mentions-export.ts +0 -147
- package/src/lib/mentions-live.ts +0 -1114
- package/src/lib/moderation-target.ts +0 -227
- package/src/lib/moderation-write.ts +0 -131
- package/src/lib/mutes-write.ts +0 -171
- package/src/lib/mutes.ts +0 -84
- package/src/lib/ndjson-stream.ts +0 -106
- package/src/lib/network-map.ts +0 -382
- package/src/lib/openai-response-runtime.ts +0 -251
- package/src/lib/openai.ts +0 -117
- package/src/lib/paginated-sync.ts +0 -93
- package/src/lib/period-digest.ts +0 -1364
- package/src/lib/present.ts +0 -118
- package/src/lib/profile-affiliation-hydration.ts +0 -228
- package/src/lib/profile-affiliations.ts +0 -262
- package/src/lib/profile-analysis.ts +0 -1198
- package/src/lib/profile-bio-entities.ts +0 -318
- package/src/lib/profile-history.ts +0 -164
- package/src/lib/profile-hydration.ts +0 -180
- package/src/lib/profile-replies.ts +0 -77
- package/src/lib/profile-resolver.ts +0 -650
- package/src/lib/queries.ts +0 -6
- package/src/lib/query-actions.ts +0 -437
- package/src/lib/query-client.tsx +0 -47
- package/src/lib/query-read-model-shared.ts +0 -52
- package/src/lib/query-read-models.ts +0 -5
- package/src/lib/query-resource.ts +0 -41
- package/src/lib/query-status.ts +0 -164
- package/src/lib/research.ts +0 -652
- package/src/lib/runtime-services.ts +0 -20
- package/src/lib/search-discussion.ts +0 -812
- package/src/lib/seed.ts +0 -613
- package/src/lib/server-runtime-services.ts +0 -30
- package/src/lib/sqlite.ts +0 -183
- package/src/lib/streaming-ingestion.ts +0 -240
- package/src/lib/sync-cache.ts +0 -70
- package/src/lib/sync-plan.ts +0 -175
- package/src/lib/theme-transition.ts +0 -113
- package/src/lib/theme.tsx +0 -165
- package/src/lib/timeline-collections-live.ts +0 -407
- package/src/lib/timeline-live.ts +0 -302
- package/src/lib/timeline-read-model.ts +0 -1191
- package/src/lib/tweet-account-edges.ts +0 -48
- package/src/lib/tweet-lookup.ts +0 -46
- package/src/lib/tweet-render.ts +0 -430
- package/src/lib/tweet-repository.ts +0 -156
- package/src/lib/tweet-search-live.ts +0 -462
- package/src/lib/types.ts +0 -723
- package/src/lib/ui.ts +0 -529
- package/src/lib/url-expansion-store.ts +0 -110
- package/src/lib/url-expansion.ts +0 -343
- package/src/lib/url-safety.ts +0 -220
- package/src/lib/web-sync.ts +0 -533
- package/src/lib/whois.ts +0 -1080
- package/src/lib/x-profile.ts +0 -365
- package/src/lib/x-web.ts +0 -199
- package/src/lib/xurl-rate-limits.ts +0 -267
- package/src/lib/xurl.ts +0 -1677
- package/src/routeTree.gen.ts +0 -723
- package/src/router.tsx +0 -20
- package/src/routes/__root.tsx +0 -82
- package/src/routes/api/action.tsx +0 -147
- package/src/routes/api/avatar.tsx +0 -50
- package/src/routes/api/blocks.tsx +0 -35
- package/src/routes/api/conversation.tsx +0 -45
- package/src/routes/api/data-sources.tsx +0 -24
- package/src/routes/api/inbox.tsx +0 -43
- package/src/routes/api/link-insights.tsx +0 -85
- package/src/routes/api/link-preview.tsx +0 -47
- package/src/routes/api/network-map.tsx +0 -55
- package/src/routes/api/period-digest.tsx +0 -101
- package/src/routes/api/profile-analysis.tsx +0 -97
- package/src/routes/api/profile-hydrate.tsx +0 -54
- package/src/routes/api/query.tsx +0 -121
- package/src/routes/api/search-discussion.tsx +0 -113
- package/src/routes/api/status.tsx +0 -30
- package/src/routes/api/sync.tsx +0 -108
- package/src/routes/api/xurl-rate-limits.tsx +0 -24
- package/src/routes/blocks.tsx +0 -343
- package/src/routes/bookmarks.tsx +0 -18
- package/src/routes/data-sources.tsx +0 -249
- package/src/routes/discuss.tsx +0 -419
- package/src/routes/dms.tsx +0 -415
- package/src/routes/inbox.tsx +0 -232
- package/src/routes/index.tsx +0 -32
- package/src/routes/likes.tsx +0 -18
- package/src/routes/links.tsx +0 -631
- package/src/routes/mentions.tsx +0 -32
- package/src/routes/network-map.tsx +0 -732
- package/src/routes/profile-analyze.tsx +0 -112
- package/src/routes/profiles.$handle.tsx +0 -228
- package/src/routes/rate-limits.tsx +0 -305
- package/src/routes/today.tsx +0 -511
- package/src/styles.css +0 -257
- package/tsconfig.json +0 -29
- package/vite.config.ts +0 -29
- /package/{public → dist/client}/birdclaw-mark.png +0 -0
- /package/{public → dist/client}/favicon.ico +0 -0
- /package/{public → dist/client}/logo192.png +0 -0
- /package/{public → dist/client}/logo512.png +0 -0
- /package/{public → dist/client}/manifest.json +0 -0
- /package/{public → dist/client}/robots.txt +0 -0
|
@@ -1,500 +0,0 @@
|
|
|
1
|
-
import type { CliCommandContext } from "./command-context";
|
|
2
|
-
import {
|
|
3
|
-
normalizeDigestLanguage,
|
|
4
|
-
streamPeriodDigest,
|
|
5
|
-
type PeriodDigestOptions,
|
|
6
|
-
type PeriodDigestPreset,
|
|
7
|
-
} from "#/lib/period-digest";
|
|
8
|
-
import {
|
|
9
|
-
streamProfileAnalysis,
|
|
10
|
-
type ProfileAnalysisOptions,
|
|
11
|
-
} from "#/lib/profile-analysis";
|
|
12
|
-
import { runResearchMode } from "#/lib/research";
|
|
13
|
-
import {
|
|
14
|
-
streamSearchDiscussion,
|
|
15
|
-
type SearchDiscussionOptions,
|
|
16
|
-
type SearchDiscussionSource,
|
|
17
|
-
} from "#/lib/search-discussion";
|
|
18
|
-
|
|
19
|
-
export function registerAnalysisCommands({
|
|
20
|
-
program,
|
|
21
|
-
print,
|
|
22
|
-
autoUpdateBeforeRead,
|
|
23
|
-
parseNonNegativeIntegerOption,
|
|
24
|
-
parsePositiveIntegerOption,
|
|
25
|
-
}: CliCommandContext) {
|
|
26
|
-
function printError(error: string) {
|
|
27
|
-
console.error(JSON.stringify({ error }));
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function parseDigestLiveModeOption(
|
|
31
|
-
value: string | undefined,
|
|
32
|
-
): PeriodDigestOptions["liveSyncMode"] {
|
|
33
|
-
const normalized = (value ?? "xurl").trim().toLowerCase();
|
|
34
|
-
if (
|
|
35
|
-
normalized === "auto" ||
|
|
36
|
-
normalized === "bird" ||
|
|
37
|
-
normalized === "xurl"
|
|
38
|
-
) {
|
|
39
|
-
return normalized;
|
|
40
|
-
}
|
|
41
|
-
printError("--live-mode must be auto, bird, or xurl");
|
|
42
|
-
process.exitCode = 1;
|
|
43
|
-
return undefined;
|
|
44
|
-
}
|
|
45
|
-
function parseDigestPeriod(value: string | undefined): PeriodDigestPreset {
|
|
46
|
-
const normalized = value?.trim().toLowerCase();
|
|
47
|
-
if (normalized === "yesterday") return "yesterday";
|
|
48
|
-
if (normalized === "24h" || normalized === "day") return "24h";
|
|
49
|
-
if (normalized === "week" || normalized === "7d") return "week";
|
|
50
|
-
return "today";
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function buildDigestOptions(
|
|
54
|
-
period: string | undefined,
|
|
55
|
-
options: {
|
|
56
|
-
account?: string;
|
|
57
|
-
includeDms?: boolean;
|
|
58
|
-
model?: string;
|
|
59
|
-
language?: string;
|
|
60
|
-
refresh?: boolean;
|
|
61
|
-
since?: string;
|
|
62
|
-
until?: string;
|
|
63
|
-
maxTweets?: string;
|
|
64
|
-
maxLinks?: string;
|
|
65
|
-
liveSync?: boolean;
|
|
66
|
-
liveMode?: string;
|
|
67
|
-
},
|
|
68
|
-
): PeriodDigestOptions | null {
|
|
69
|
-
const maxTweets = parseNonNegativeIntegerOption(
|
|
70
|
-
options.maxTweets,
|
|
71
|
-
"--max-tweets",
|
|
72
|
-
);
|
|
73
|
-
if (options.maxTweets !== undefined && maxTweets === undefined) {
|
|
74
|
-
return null;
|
|
75
|
-
}
|
|
76
|
-
const maxLinks = parseNonNegativeIntegerOption(
|
|
77
|
-
options.maxLinks,
|
|
78
|
-
"--max-links",
|
|
79
|
-
);
|
|
80
|
-
if (options.maxLinks !== undefined && maxLinks === undefined) {
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
const liveSyncMode = parseDigestLiveModeOption(options.liveMode);
|
|
84
|
-
if (liveSyncMode === undefined) {
|
|
85
|
-
return null;
|
|
86
|
-
}
|
|
87
|
-
let language: string | undefined;
|
|
88
|
-
try {
|
|
89
|
-
language = normalizeDigestLanguage(options.language);
|
|
90
|
-
} catch (error) {
|
|
91
|
-
printError(error instanceof Error ? error.message : String(error));
|
|
92
|
-
process.exitCode = 1;
|
|
93
|
-
return null;
|
|
94
|
-
}
|
|
95
|
-
return {
|
|
96
|
-
period: parseDigestPeriod(period),
|
|
97
|
-
since: options.since,
|
|
98
|
-
until: options.until,
|
|
99
|
-
account: options.account,
|
|
100
|
-
includeDms: Boolean(options.includeDms),
|
|
101
|
-
refresh: Boolean(options.refresh),
|
|
102
|
-
model: options.model,
|
|
103
|
-
language,
|
|
104
|
-
maxTweets,
|
|
105
|
-
maxLinks,
|
|
106
|
-
liveSync: options.liveSync !== false,
|
|
107
|
-
liveSyncMode,
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function runDigestCli(options: PeriodDigestOptions) {
|
|
112
|
-
const asJson = Boolean(program.opts().json);
|
|
113
|
-
return streamPeriodDigest(options, {
|
|
114
|
-
onDelta: asJson
|
|
115
|
-
? undefined
|
|
116
|
-
: (delta) => {
|
|
117
|
-
process.stdout.write(delta);
|
|
118
|
-
},
|
|
119
|
-
}).then((result) => {
|
|
120
|
-
if (asJson) {
|
|
121
|
-
print(result, true);
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
if (!result.markdown.endsWith("\n")) {
|
|
125
|
-
process.stdout.write("\n");
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function parseSearchDiscussionSource(
|
|
131
|
-
value: string | undefined,
|
|
132
|
-
): SearchDiscussionSource | undefined {
|
|
133
|
-
const normalized = (value ?? "all").trim().toLowerCase();
|
|
134
|
-
if (
|
|
135
|
-
normalized === "all" ||
|
|
136
|
-
normalized === "home" ||
|
|
137
|
-
normalized === "mentions" ||
|
|
138
|
-
normalized === "authored" ||
|
|
139
|
-
normalized === "search" ||
|
|
140
|
-
normalized === "likes" ||
|
|
141
|
-
normalized === "bookmarks"
|
|
142
|
-
) {
|
|
143
|
-
return normalized;
|
|
144
|
-
}
|
|
145
|
-
printError(
|
|
146
|
-
"--source must be all, search, home, mentions, authored, likes, or bookmarks",
|
|
147
|
-
);
|
|
148
|
-
process.exitCode = 1;
|
|
149
|
-
return undefined;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function parseTweetSearchMode(value: string | undefined) {
|
|
153
|
-
const normalized = (value ?? "auto").trim().toLowerCase();
|
|
154
|
-
if (
|
|
155
|
-
normalized === "auto" ||
|
|
156
|
-
normalized === "bird" ||
|
|
157
|
-
normalized === "xurl" ||
|
|
158
|
-
normalized === "local"
|
|
159
|
-
) {
|
|
160
|
-
return normalized;
|
|
161
|
-
}
|
|
162
|
-
printError("--mode must be auto, bird, xurl, or local");
|
|
163
|
-
process.exitCode = 1;
|
|
164
|
-
return undefined;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
function buildSearchDiscussionOptions(
|
|
168
|
-
query: string,
|
|
169
|
-
options: {
|
|
170
|
-
account?: string;
|
|
171
|
-
source?: string;
|
|
172
|
-
includeDms?: boolean;
|
|
173
|
-
since?: string;
|
|
174
|
-
until?: string;
|
|
175
|
-
question?: string;
|
|
176
|
-
originalsOnly?: boolean;
|
|
177
|
-
hideLowQuality?: boolean;
|
|
178
|
-
mode?: string;
|
|
179
|
-
model?: string;
|
|
180
|
-
refresh?: boolean;
|
|
181
|
-
limit?: string;
|
|
182
|
-
maxPages?: string;
|
|
183
|
-
},
|
|
184
|
-
): SearchDiscussionOptions | null {
|
|
185
|
-
const source = parseSearchDiscussionSource(options.source);
|
|
186
|
-
if (!source) return null;
|
|
187
|
-
const mode = parseTweetSearchMode(options.mode);
|
|
188
|
-
if (!mode) return null;
|
|
189
|
-
const limit = parsePositiveIntegerOption(options.limit, "--limit");
|
|
190
|
-
if (options.limit !== undefined && limit === undefined) {
|
|
191
|
-
return null;
|
|
192
|
-
}
|
|
193
|
-
const maxPages = parsePositiveIntegerOption(
|
|
194
|
-
options.maxPages,
|
|
195
|
-
"--max-pages",
|
|
196
|
-
);
|
|
197
|
-
if (options.maxPages !== undefined && maxPages === undefined) {
|
|
198
|
-
return null;
|
|
199
|
-
}
|
|
200
|
-
return {
|
|
201
|
-
query,
|
|
202
|
-
account: options.account,
|
|
203
|
-
source,
|
|
204
|
-
includeDms: Boolean(options.includeDms),
|
|
205
|
-
since: options.since,
|
|
206
|
-
until: options.until,
|
|
207
|
-
question: options.question,
|
|
208
|
-
originalsOnly: Boolean(options.originalsOnly),
|
|
209
|
-
hideLowQuality: Boolean(options.hideLowQuality),
|
|
210
|
-
mode,
|
|
211
|
-
model: options.model,
|
|
212
|
-
refresh: Boolean(options.refresh),
|
|
213
|
-
limit,
|
|
214
|
-
maxPages,
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
function runSearchDiscussionCli(options: SearchDiscussionOptions) {
|
|
219
|
-
const asJson = Boolean(program.opts().json);
|
|
220
|
-
return streamSearchDiscussion(options, {
|
|
221
|
-
onDelta: asJson
|
|
222
|
-
? undefined
|
|
223
|
-
: (delta) => {
|
|
224
|
-
process.stdout.write(delta);
|
|
225
|
-
},
|
|
226
|
-
}).then((result) => {
|
|
227
|
-
if (asJson) {
|
|
228
|
-
print(result, true);
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
if (!result.markdown.endsWith("\n")) {
|
|
232
|
-
process.stdout.write("\n");
|
|
233
|
-
}
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
function buildProfileAnalysisOptions(
|
|
238
|
-
handle: string,
|
|
239
|
-
options: {
|
|
240
|
-
account?: string;
|
|
241
|
-
model?: string;
|
|
242
|
-
refresh?: boolean;
|
|
243
|
-
maxTweets?: string;
|
|
244
|
-
maxPages?: string;
|
|
245
|
-
maxConversations?: string;
|
|
246
|
-
maxConversationPages?: string;
|
|
247
|
-
conversationDelayMs?: string;
|
|
248
|
-
rateLimitRetryMs?: string;
|
|
249
|
-
rateLimitRetries?: string;
|
|
250
|
-
},
|
|
251
|
-
): ProfileAnalysisOptions | null {
|
|
252
|
-
const maxTweets = parsePositiveIntegerOption(
|
|
253
|
-
options.maxTweets,
|
|
254
|
-
"--max-tweets",
|
|
255
|
-
);
|
|
256
|
-
if (options.maxTweets !== undefined && maxTweets === undefined) {
|
|
257
|
-
return null;
|
|
258
|
-
}
|
|
259
|
-
const maxPages = parsePositiveIntegerOption(
|
|
260
|
-
options.maxPages,
|
|
261
|
-
"--max-pages",
|
|
262
|
-
);
|
|
263
|
-
if (options.maxPages !== undefined && maxPages === undefined) {
|
|
264
|
-
return null;
|
|
265
|
-
}
|
|
266
|
-
const maxConversations = parsePositiveIntegerOption(
|
|
267
|
-
options.maxConversations,
|
|
268
|
-
"--max-conversations",
|
|
269
|
-
);
|
|
270
|
-
if (
|
|
271
|
-
options.maxConversations !== undefined &&
|
|
272
|
-
maxConversations === undefined
|
|
273
|
-
) {
|
|
274
|
-
return null;
|
|
275
|
-
}
|
|
276
|
-
const maxConversationPages = parsePositiveIntegerOption(
|
|
277
|
-
options.maxConversationPages,
|
|
278
|
-
"--max-conversation-pages",
|
|
279
|
-
);
|
|
280
|
-
if (
|
|
281
|
-
options.maxConversationPages !== undefined &&
|
|
282
|
-
maxConversationPages === undefined
|
|
283
|
-
) {
|
|
284
|
-
return null;
|
|
285
|
-
}
|
|
286
|
-
const conversationDelayMs = parseNonNegativeIntegerOption(
|
|
287
|
-
options.conversationDelayMs,
|
|
288
|
-
"--conversation-delay-ms",
|
|
289
|
-
);
|
|
290
|
-
if (
|
|
291
|
-
options.conversationDelayMs !== undefined &&
|
|
292
|
-
conversationDelayMs === undefined
|
|
293
|
-
) {
|
|
294
|
-
return null;
|
|
295
|
-
}
|
|
296
|
-
const rateLimitRetryMs = parseNonNegativeIntegerOption(
|
|
297
|
-
options.rateLimitRetryMs,
|
|
298
|
-
"--rate-limit-retry-ms",
|
|
299
|
-
);
|
|
300
|
-
if (
|
|
301
|
-
options.rateLimitRetryMs !== undefined &&
|
|
302
|
-
rateLimitRetryMs === undefined
|
|
303
|
-
) {
|
|
304
|
-
return null;
|
|
305
|
-
}
|
|
306
|
-
const rateLimitMaxRetries = parseNonNegativeIntegerOption(
|
|
307
|
-
options.rateLimitRetries,
|
|
308
|
-
"--rate-limit-retries",
|
|
309
|
-
);
|
|
310
|
-
if (
|
|
311
|
-
options.rateLimitRetries !== undefined &&
|
|
312
|
-
rateLimitMaxRetries === undefined
|
|
313
|
-
) {
|
|
314
|
-
return null;
|
|
315
|
-
}
|
|
316
|
-
return {
|
|
317
|
-
handle,
|
|
318
|
-
account: options.account,
|
|
319
|
-
model: options.model,
|
|
320
|
-
refresh: Boolean(options.refresh),
|
|
321
|
-
maxTweets,
|
|
322
|
-
maxPages,
|
|
323
|
-
maxConversations,
|
|
324
|
-
maxConversationPages,
|
|
325
|
-
conversationDelayMs,
|
|
326
|
-
rateLimitRetryMs,
|
|
327
|
-
rateLimitMaxRetries,
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
function runProfileAnalysisCli(options: ProfileAnalysisOptions) {
|
|
332
|
-
const asJson = Boolean(program.opts().json);
|
|
333
|
-
return streamProfileAnalysis(options, {
|
|
334
|
-
onDelta: asJson
|
|
335
|
-
? undefined
|
|
336
|
-
: (delta) => {
|
|
337
|
-
process.stdout.write(delta);
|
|
338
|
-
},
|
|
339
|
-
onEvent: asJson
|
|
340
|
-
? undefined
|
|
341
|
-
: (event) => {
|
|
342
|
-
if (event.type === "status") {
|
|
343
|
-
process.stderr.write(
|
|
344
|
-
event.detail
|
|
345
|
-
? `${event.label}: ${event.detail}\n`
|
|
346
|
-
: `${event.label}\n`,
|
|
347
|
-
);
|
|
348
|
-
}
|
|
349
|
-
},
|
|
350
|
-
}).then((result) => {
|
|
351
|
-
if (asJson) {
|
|
352
|
-
print(result, true);
|
|
353
|
-
return;
|
|
354
|
-
}
|
|
355
|
-
if (!result.markdown.endsWith("\n")) {
|
|
356
|
-
process.stdout.write("\n");
|
|
357
|
-
}
|
|
358
|
-
});
|
|
359
|
-
}
|
|
360
|
-
program
|
|
361
|
-
.command("research [query]")
|
|
362
|
-
.description("Build a markdown research brief from bookmarked threads")
|
|
363
|
-
.option("--account <accountId>", "Account id")
|
|
364
|
-
.option("--limit <n>", "Seed bookmark limit", "20")
|
|
365
|
-
.option("--thread-depth <n>", "Maximum ancestor walk depth", "10")
|
|
366
|
-
.option("--out <path>", "Write the markdown brief to a file")
|
|
367
|
-
.action(async (query, options) => {
|
|
368
|
-
await autoUpdateBeforeRead();
|
|
369
|
-
const report = await runResearchMode({
|
|
370
|
-
account: options.account,
|
|
371
|
-
query,
|
|
372
|
-
limit: Number(options.limit),
|
|
373
|
-
maxThreadDepth: Number(options.threadDepth),
|
|
374
|
-
outPath: options.out,
|
|
375
|
-
});
|
|
376
|
-
print(
|
|
377
|
-
program.opts().json ? report : report.markdown,
|
|
378
|
-
program.opts().json ?? false,
|
|
379
|
-
);
|
|
380
|
-
});
|
|
381
|
-
|
|
382
|
-
program
|
|
383
|
-
.command("discuss <query>")
|
|
384
|
-
.description("Search live/local tweets and summarize the results with AI")
|
|
385
|
-
.option("--account <accountId>", "Account id")
|
|
386
|
-
.option(
|
|
387
|
-
"--source <source>",
|
|
388
|
-
"all, search, home, mentions, authored, likes, or bookmarks",
|
|
389
|
-
"search",
|
|
390
|
-
)
|
|
391
|
-
.option("--mode <mode>", "auto, bird, xurl, or local", "xurl")
|
|
392
|
-
.option("--include-dms", "Include private DM search matches")
|
|
393
|
-
.option(
|
|
394
|
-
"--since <isoDate>",
|
|
395
|
-
"Include matches created at or after this date",
|
|
396
|
-
)
|
|
397
|
-
.option("--until <isoDate>", "Include matches created before this date")
|
|
398
|
-
.option("--question <prompt>", "Discussion question or angle")
|
|
399
|
-
.option("--originals-only", "Exclude authored replies that start with @")
|
|
400
|
-
.option("--hide-low-quality", "Hide RTs, tiny replies, and link-only noise")
|
|
401
|
-
.option("--model <model>", "OpenAI model id")
|
|
402
|
-
.option("--refresh", "Bypass the local discussion cache")
|
|
403
|
-
.option("--limit <n>", "Maximum tweet context", "20000")
|
|
404
|
-
.option("--max-pages <n>", "Maximum live search pages", "200")
|
|
405
|
-
.action(async (query, options) => {
|
|
406
|
-
await autoUpdateBeforeRead();
|
|
407
|
-
const discussionOptions = buildSearchDiscussionOptions(query, options);
|
|
408
|
-
if (!discussionOptions) return;
|
|
409
|
-
await runSearchDiscussionCli(discussionOptions);
|
|
410
|
-
});
|
|
411
|
-
|
|
412
|
-
program
|
|
413
|
-
.command("profile-analyze <handle>")
|
|
414
|
-
.alias("profile-analyse")
|
|
415
|
-
.description("Backfill a profile with xurl and summarize it with AI")
|
|
416
|
-
.option("--account <accountId>", "Account id")
|
|
417
|
-
.option("--model <model>", "OpenAI model id")
|
|
418
|
-
.option("--refresh", "Bypass profile fetch and analysis caches")
|
|
419
|
-
.option("--max-tweets <n>", "Maximum profile tweets", "10000")
|
|
420
|
-
.option("--max-pages <n>", "Maximum profile timeline pages", "100")
|
|
421
|
-
.option(
|
|
422
|
-
"--max-conversations <n>",
|
|
423
|
-
"Maximum conversations to backfill",
|
|
424
|
-
"80",
|
|
425
|
-
)
|
|
426
|
-
.option(
|
|
427
|
-
"--max-conversation-pages <n>",
|
|
428
|
-
"Maximum pages per conversation",
|
|
429
|
-
"3",
|
|
430
|
-
)
|
|
431
|
-
.option(
|
|
432
|
-
"--conversation-delay-ms <n>",
|
|
433
|
-
"Delay between conversation search calls",
|
|
434
|
-
)
|
|
435
|
-
.option(
|
|
436
|
-
"--rate-limit-retry-ms <n>",
|
|
437
|
-
"Delay before retrying conversation 429s",
|
|
438
|
-
)
|
|
439
|
-
.option("--rate-limit-retries <n>", "Conversation 429 retry count")
|
|
440
|
-
.action(async (handle, options) => {
|
|
441
|
-
await autoUpdateBeforeRead();
|
|
442
|
-
const analysisOptions = buildProfileAnalysisOptions(handle, options);
|
|
443
|
-
if (!analysisOptions) return;
|
|
444
|
-
await runProfileAnalysisCli(analysisOptions);
|
|
445
|
-
});
|
|
446
|
-
|
|
447
|
-
program
|
|
448
|
-
.command("today")
|
|
449
|
-
.description("Stream an AI digest of what happened today")
|
|
450
|
-
.option("--account <accountId>", "Account id")
|
|
451
|
-
.option("--include-dms", "Include private DM context")
|
|
452
|
-
.option("--model <model>", "OpenAI model id")
|
|
453
|
-
.option(
|
|
454
|
-
"--language <tag>",
|
|
455
|
-
"Report language as a Unicode locale id, e.g. zh-CN (env: BIRDCLAW_DIGEST_LANGUAGE)",
|
|
456
|
-
)
|
|
457
|
-
.option("--refresh", "Bypass the local digest cache")
|
|
458
|
-
.option("--max-tweets <n>", "Maximum tweet context", "5000")
|
|
459
|
-
.option("--max-links <n>", "Maximum linked articles", "12")
|
|
460
|
-
.option("--no-live-sync", "Use only the local database")
|
|
461
|
-
.option(
|
|
462
|
-
"--live-mode <mode>",
|
|
463
|
-
"Live timeline mode: xurl, bird, or auto",
|
|
464
|
-
"xurl",
|
|
465
|
-
)
|
|
466
|
-
.action(async (options) => {
|
|
467
|
-
await autoUpdateBeforeRead();
|
|
468
|
-
const digestOptions = buildDigestOptions("today", options);
|
|
469
|
-
if (!digestOptions) return;
|
|
470
|
-
await runDigestCli(digestOptions);
|
|
471
|
-
});
|
|
472
|
-
|
|
473
|
-
program
|
|
474
|
-
.command("digest [period]")
|
|
475
|
-
.description("Stream an AI digest for today, 24h, yesterday, or week")
|
|
476
|
-
.option("--account <accountId>", "Account id")
|
|
477
|
-
.option("--include-dms", "Include private DM context")
|
|
478
|
-
.option("--since <isoDate>", "Start of explicit window")
|
|
479
|
-
.option("--until <isoDate>", "End of explicit window")
|
|
480
|
-
.option("--model <model>", "OpenAI model id")
|
|
481
|
-
.option(
|
|
482
|
-
"--language <tag>",
|
|
483
|
-
"Report language as a Unicode locale id, e.g. zh-CN (env: BIRDCLAW_DIGEST_LANGUAGE)",
|
|
484
|
-
)
|
|
485
|
-
.option("--refresh", "Bypass the local digest cache")
|
|
486
|
-
.option("--max-tweets <n>", "Maximum tweet context", "5000")
|
|
487
|
-
.option("--max-links <n>", "Maximum linked articles", "12")
|
|
488
|
-
.option("--no-live-sync", "Use only the local database")
|
|
489
|
-
.option(
|
|
490
|
-
"--live-mode <mode>",
|
|
491
|
-
"Live timeline mode: xurl, bird, or auto",
|
|
492
|
-
"xurl",
|
|
493
|
-
)
|
|
494
|
-
.action(async (period, options) => {
|
|
495
|
-
await autoUpdateBeforeRead();
|
|
496
|
-
const digestOptions = buildDigestOptions(period, options);
|
|
497
|
-
if (!digestOptions) return;
|
|
498
|
-
await runDigestCli(digestOptions);
|
|
499
|
-
});
|
|
500
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { createDmReply, createPost, createTweetReply } from "#/lib/queries";
|
|
2
|
-
import type { CliCommandContext } from "./command-context";
|
|
3
|
-
|
|
4
|
-
export function registerComposeCommands({
|
|
5
|
-
program,
|
|
6
|
-
print,
|
|
7
|
-
asJson,
|
|
8
|
-
autoSyncAfterWrite,
|
|
9
|
-
}: CliCommandContext) {
|
|
10
|
-
const composeCommand = program
|
|
11
|
-
.command("compose")
|
|
12
|
-
.description("Create local/xurl actions");
|
|
13
|
-
|
|
14
|
-
composeCommand
|
|
15
|
-
.command("post <text>")
|
|
16
|
-
.option("--account <accountId>", "Account id", "acct_primary")
|
|
17
|
-
.action(async (text, options) => {
|
|
18
|
-
const result = await createPost(options.account, text);
|
|
19
|
-
await autoSyncAfterWrite();
|
|
20
|
-
print(result, asJson());
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
composeCommand
|
|
24
|
-
.command("reply <tweetId> <text>")
|
|
25
|
-
.option("--account <accountId>", "Account id", "acct_primary")
|
|
26
|
-
.action(async (tweetId, text, options) => {
|
|
27
|
-
const result = await createTweetReply(options.account, tweetId, text);
|
|
28
|
-
await autoSyncAfterWrite();
|
|
29
|
-
print(result, asJson());
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
composeCommand
|
|
33
|
-
.command("dm <conversationId> <text>")
|
|
34
|
-
.description("Reply inside an existing DM conversation")
|
|
35
|
-
.action(async (conversationId, text) => {
|
|
36
|
-
const result = await createDmReply(conversationId, text);
|
|
37
|
-
await autoSyncAfterWrite();
|
|
38
|
-
print(result, asJson());
|
|
39
|
-
});
|
|
40
|
-
}
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getFollowGraphSummary,
|
|
3
|
-
listFollowEvents,
|
|
4
|
-
listMutuals,
|
|
5
|
-
listNonMutualFollowing,
|
|
6
|
-
listTopFollowers,
|
|
7
|
-
listUnfollowedSince,
|
|
8
|
-
} from "#/lib/follow-graph";
|
|
9
|
-
import type { CliCommandContext } from "./command-context";
|
|
10
|
-
|
|
11
|
-
export function registerGraphCommands({
|
|
12
|
-
program,
|
|
13
|
-
print,
|
|
14
|
-
autoUpdateBeforeRead,
|
|
15
|
-
}: CliCommandContext) {
|
|
16
|
-
const graphCommand = program
|
|
17
|
-
.command("graph")
|
|
18
|
-
.description("Query the local cache-only follow graph");
|
|
19
|
-
|
|
20
|
-
graphCommand
|
|
21
|
-
.command("summary")
|
|
22
|
-
.description(
|
|
23
|
-
"Summarize cached followers, following, mutuals, and snapshots",
|
|
24
|
-
)
|
|
25
|
-
.option("--account <accountId>", "Account id")
|
|
26
|
-
.action(async (options) => {
|
|
27
|
-
await autoUpdateBeforeRead();
|
|
28
|
-
print(getFollowGraphSummary({ account: options.account }), true);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
graphCommand
|
|
32
|
-
.command("top-followers")
|
|
33
|
-
.description("List current followers sorted by their follower count")
|
|
34
|
-
.option("--account <accountId>", "Account id")
|
|
35
|
-
.option("--limit <n>", "Limit results", "20")
|
|
36
|
-
.action(async (options) => {
|
|
37
|
-
await autoUpdateBeforeRead();
|
|
38
|
-
print(
|
|
39
|
-
listTopFollowers({
|
|
40
|
-
account: options.account,
|
|
41
|
-
limit: Number(options.limit),
|
|
42
|
-
}),
|
|
43
|
-
true,
|
|
44
|
-
);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
graphCommand
|
|
48
|
-
.command("unfollowed")
|
|
49
|
-
.description("List cached ended follow edges since a date")
|
|
50
|
-
.requiredOption("--date <date>", "YYYY-MM-DD or ISO timestamp")
|
|
51
|
-
.option("--account <accountId>", "Account id")
|
|
52
|
-
.option("--direction <direction>", "followers or following", "followers")
|
|
53
|
-
.option("--limit <n>", "Limit results", "100")
|
|
54
|
-
.action(async (options) => {
|
|
55
|
-
await autoUpdateBeforeRead();
|
|
56
|
-
print(
|
|
57
|
-
listUnfollowedSince({
|
|
58
|
-
account: options.account,
|
|
59
|
-
date: options.date,
|
|
60
|
-
direction:
|
|
61
|
-
options.direction === "following" ? "following" : "followers",
|
|
62
|
-
limit: Number(options.limit),
|
|
63
|
-
}),
|
|
64
|
-
true,
|
|
65
|
-
);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
graphCommand
|
|
69
|
-
.command("events")
|
|
70
|
-
.description("List cached append-only follow graph events")
|
|
71
|
-
.option("--account <accountId>", "Account id")
|
|
72
|
-
.option("--direction <direction>", "followers or following")
|
|
73
|
-
.option("--kind <kind>", "started or ended")
|
|
74
|
-
.option("--since <date>", "YYYY-MM-DD or ISO timestamp")
|
|
75
|
-
.option("--until <date>", "YYYY-MM-DD or ISO timestamp")
|
|
76
|
-
.option("--limit <n>", "Limit results", "100")
|
|
77
|
-
.action(async (options) => {
|
|
78
|
-
await autoUpdateBeforeRead();
|
|
79
|
-
print(
|
|
80
|
-
listFollowEvents({
|
|
81
|
-
account: options.account,
|
|
82
|
-
direction:
|
|
83
|
-
options.direction === "followers" ||
|
|
84
|
-
options.direction === "following"
|
|
85
|
-
? options.direction
|
|
86
|
-
: undefined,
|
|
87
|
-
kind:
|
|
88
|
-
options.kind === "started" || options.kind === "ended"
|
|
89
|
-
? options.kind
|
|
90
|
-
: undefined,
|
|
91
|
-
since: options.since,
|
|
92
|
-
until: options.until,
|
|
93
|
-
limit: Number(options.limit),
|
|
94
|
-
}),
|
|
95
|
-
true,
|
|
96
|
-
);
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
graphCommand
|
|
100
|
-
.command("non-mutual-following")
|
|
101
|
-
.description("List current following who are not current followers")
|
|
102
|
-
.option("--account <accountId>", "Account id")
|
|
103
|
-
.option("--sort <mode>", "followers or handle", "followers")
|
|
104
|
-
.option("--limit <n>", "Limit results", "100")
|
|
105
|
-
.action(async (options) => {
|
|
106
|
-
await autoUpdateBeforeRead();
|
|
107
|
-
print(
|
|
108
|
-
listNonMutualFollowing({
|
|
109
|
-
account: options.account,
|
|
110
|
-
sort: options.sort === "handle" ? "handle" : "followers",
|
|
111
|
-
limit: Number(options.limit),
|
|
112
|
-
}),
|
|
113
|
-
true,
|
|
114
|
-
);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
graphCommand
|
|
118
|
-
.command("mutuals")
|
|
119
|
-
.description("List profiles that are both followers and following")
|
|
120
|
-
.option("--account <accountId>", "Account id")
|
|
121
|
-
.option("--limit <n>", "Limit results", "100")
|
|
122
|
-
.action(async (options) => {
|
|
123
|
-
await autoUpdateBeforeRead();
|
|
124
|
-
print(
|
|
125
|
-
listMutuals({
|
|
126
|
-
account: options.account,
|
|
127
|
-
limit: Number(options.limit),
|
|
128
|
-
}),
|
|
129
|
-
true,
|
|
130
|
-
);
|
|
131
|
-
});
|
|
132
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { listInboxItems, scoreInbox } from "#/lib/inbox";
|
|
2
|
-
import type { CliCommandContext } from "./command-context";
|
|
3
|
-
|
|
4
|
-
export function registerInboxCommand({
|
|
5
|
-
program,
|
|
6
|
-
print,
|
|
7
|
-
asJson,
|
|
8
|
-
autoSyncAfterWrite,
|
|
9
|
-
autoUpdateBeforeRead,
|
|
10
|
-
}: CliCommandContext) {
|
|
11
|
-
program
|
|
12
|
-
.command("inbox")
|
|
13
|
-
.option("--kind <kind>", "mixed, mentions, or dms", "mixed")
|
|
14
|
-
.option("--min-score <n>", "Minimum rank", "0")
|
|
15
|
-
.option("--hide-low-signal", "Hide low-signal items")
|
|
16
|
-
.option("--score", "Score top items with OpenAI before listing")
|
|
17
|
-
.option("--limit <n>", "Limit results", "20")
|
|
18
|
-
.action(async (options) => {
|
|
19
|
-
await autoUpdateBeforeRead();
|
|
20
|
-
const kind =
|
|
21
|
-
options.kind === "mentions" || options.kind === "dms"
|
|
22
|
-
? options.kind
|
|
23
|
-
: "mixed";
|
|
24
|
-
if (options.score) {
|
|
25
|
-
await scoreInbox({
|
|
26
|
-
kind,
|
|
27
|
-
limit: Number(options.limit),
|
|
28
|
-
});
|
|
29
|
-
await autoSyncAfterWrite();
|
|
30
|
-
}
|
|
31
|
-
print(
|
|
32
|
-
listInboxItems({
|
|
33
|
-
kind,
|
|
34
|
-
minScore: Number(options.minScore),
|
|
35
|
-
hideLowSignal: Boolean(options.hideLowSignal),
|
|
36
|
-
limit: Number(options.limit),
|
|
37
|
-
}),
|
|
38
|
-
asJson(),
|
|
39
|
-
);
|
|
40
|
-
});
|
|
41
|
-
}
|