this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

lint

+83 -64
+10 -14
packages/remanso-cli/src/commands/init.ts
··· 15 15 } from "@clack/prompts"; 16 16 import { AtpAgent } from "@atproto/api"; 17 17 import { 18 + createAgent, 19 + createPublication, 18 20 resolveHandleToPDS, 19 - createPublication, 20 - createAgent, 21 - } from "../../../cli/src/lib/atproto"; 21 + } from "../../../cli/src/lib/atproto.ts"; 22 22 import { 23 + getCredentials, 24 + listCredentials, 23 25 loadCredentials, 24 26 saveCredentials, 25 - getCredentials, 26 - listCredentials, 27 - } from "../../../cli/src/lib/credentials"; 28 - import { exitOnCancel } from "../../../cli/src/lib/prompts"; 29 - import type { RemansoConfig } from "../lib/config"; 30 - import { WORKFLOW_YAML } from "./github"; 27 + } from "../../../cli/src/lib/credentials.ts"; 28 + import { exitOnCancel } from "../../../cli/src/lib/prompts.ts"; 29 + import type { RemansoConfig } from "../lib/config.ts"; 30 + import { WORKFLOW_YAML } from "./github.ts"; 31 + import process from "node:process"; 31 32 32 33 const CONFIG_FILENAME = ".remanso.json"; 33 34 const STATE_FILENAME = ".remanso-state.json"; ··· 99 100 100 101 return results; 101 102 } 102 - 103 - const onCancel = () => { 104 - outro("Setup cancelled"); 105 - process.exit(0); 106 - }; 107 103 108 104 export const initCommand = command({ 109 105 name: "init",
+42 -26
packages/remanso-cli/src/commands/publish.ts
··· 2 2 import { command, flag } from "cmd-ts"; 3 3 import { log, spinner } from "@clack/prompts"; 4 4 import * as path from "node:path"; 5 - import { findConfig, loadConfig, loadState, saveState } from "../lib/config"; 5 + import { findConfig, loadConfig, loadState, saveState } from "../lib/config.ts"; 6 6 import { 7 + getCredentials, 8 + listAllCredentials, 7 9 loadCredentials, 8 - listAllCredentials, 9 - getCredentials, 10 - } from "../../../cli/src/lib/credentials"; 10 + } from "../../../cli/src/lib/credentials.ts"; 11 11 import { 12 12 createAgent, 13 13 createDocument, 14 - updateDocument, 15 - uploadImage, 16 - resolveImagePath, 17 14 deleteRecord, 18 15 listDocuments, 19 16 parseAtUri, 20 - } from "../../../cli/src/lib/atproto"; 17 + resolveImagePath, 18 + updateDocument, 19 + uploadImage, 20 + } from "../../../cli/src/lib/atproto.ts"; 21 21 import { 22 - scanContentDirectory, 22 + computeNoteHash, 23 23 getContentHash, 24 + scanContentDirectory, 25 + slugifyTitle, 24 26 updateFrontmatterWithAtUri, 25 - slugifyTitle, 26 - computeNoteHash, 27 - } from "../../../cli/src/lib/markdown"; 27 + } from "../../../cli/src/lib/markdown.ts"; 28 28 import type { 29 + AppPasswordCredentials, 30 + BlobObject, 29 31 BlogPost, 30 - BlobObject, 31 - AppPasswordCredentials, 32 - } from "../../../cli/src/lib/types"; 33 - import { exitOnCancel } from "../../../cli/src/lib/prompts"; 32 + } from "../../../cli/src/lib/types.ts"; 33 + import { exitOnCancel } from "../../../cli/src/lib/prompts.ts"; 34 34 import { 35 35 createNote, 36 - updateNote, 37 36 deleteNote, 38 37 findPostsWithStaleLinks, 39 38 type NoteOptions, 40 - } from "../lib/note"; 39 + updateNote, 40 + } from "../lib/note.ts"; 41 + import process from "node:process"; 41 42 42 43 async function fileExists(filePath: string): Promise<boolean> { 43 44 try { ··· 115 116 process.exit(1); 116 117 } 117 118 118 - const { config, configPath: resolvedConfigPath } = 119 - await loadConfig(configPath); 119 + const { config, configPath: resolvedConfigPath } = await loadConfig( 120 + configPath, 121 + ); 120 122 const configDir = path.dirname(resolvedConfigPath); 121 123 122 124 log.info(`Content directory: ${config.contentDir}`); ··· 262 264 263 265 if (draftPosts.length > 0) { 264 266 log.info( 265 - `Skipping ${draftPosts.length} draft note${draftPosts.length === 1 ? "" : "s"}`, 267 + `Skipping ${draftPosts.length} draft note${ 268 + draftPosts.length === 1 ? "" : "s" 269 + }`, 266 270 ); 267 271 } 268 272 ··· 385 389 updateNote: boolean; 386 390 }> = []; 387 391 388 - for (const { post, action, updateDocument: shouldUpdateDoc, updateNote: shouldUpdateNote } of postsToPublish) { 392 + for ( 393 + const { 394 + post, 395 + action, 396 + updateDocument: shouldUpdateDoc, 397 + updateNote: shouldUpdateNote, 398 + } of postsToPublish 399 + ) { 389 400 const trimmedContent = post.content.trim(); 390 401 const titleMatch = trimmedContent.match(/^# (.+)$/m); 391 402 const title = titleMatch ? titleMatch[1] : post.frontmatter.title; ··· 474 485 475 486 noteQueue.push({ post, action, atUri, updateNote: shouldUpdateNote }); 476 487 } catch (error) { 477 - const errorMessage = 478 - error instanceof Error ? error.message : String(error); 488 + const errorMessage = error instanceof Error 489 + ? error.message 490 + : String(error); 479 491 s.stop(`Error publishing "${path.basename(post.filePath)}"`); 480 492 log.error(` ${errorMessage}`); 481 493 errorCount++; ··· 483 495 } 484 496 485 497 // Pass 2: Create/update Remanso notes 486 - for (const { post, action, atUri, updateNote: shouldUpdateNote } of noteQueue) { 498 + for ( 499 + const { post, action, atUri, updateNote: shouldUpdateNote } of noteQueue 500 + ) { 487 501 if (!shouldUpdateNote && action !== "create") continue; 488 502 const relativeFilePath = path.relative(configDir, post.filePath); 489 503 try { ··· 499 513 } 500 514 } catch (error) { 501 515 log.warn( 502 - `Failed to create note for "${post.frontmatter.title}": ${error instanceof Error ? error.message : String(error)}`, 516 + `Failed to create note for "${post.frontmatter.title}": ${ 517 + error instanceof Error ? error.message : String(error) 518 + }`, 503 519 ); 504 520 } 505 521 }
+25 -21
packages/remanso-cli/src/commands/sync.ts
··· 2 2 import { command, flag } from "cmd-ts"; 3 3 import { log, spinner } from "@clack/prompts"; 4 4 import * as path from "node:path"; 5 - import { findConfig, loadConfig, loadState, saveState } from "../lib/config"; 5 + import { findConfig, loadConfig, loadState, saveState } from "../lib/config.ts"; 6 6 import { 7 - loadCredentials, 8 - listAllCredentials, 9 7 getCredentials, 10 - } from "../../../cli/src/lib/credentials"; 8 + listAllCredentials, 9 + loadCredentials, 10 + } from "../../../cli/src/lib/credentials.ts"; 11 11 import type { Agent } from "@atproto/api"; 12 - import { createAgent, listDocuments } from "../../../cli/src/lib/atproto"; 13 - import type { ListDocumentsResult } from "../../../cli/src/lib/atproto"; 14 - import type { BlogPost, AppPasswordCredentials } from "../../../cli/src/lib/types"; 12 + import { createAgent, listDocuments } from "../../../cli/src/lib/atproto.ts"; 13 + import type { ListDocumentsResult } from "../../../cli/src/lib/atproto.ts"; 14 + import type { 15 + AppPasswordCredentials, 16 + BlogPost, 17 + } from "../../../cli/src/lib/types.ts"; 15 18 import { 16 - scanContentDirectory, 19 + computeNoteHash, 17 20 getContentHash, 18 21 getTextContent, 22 + scanContentDirectory, 19 23 updateFrontmatterWithAtUri, 20 - computeNoteHash, 21 - } from "../../../cli/src/lib/markdown"; 22 - import { exitOnCancel } from "../../../cli/src/lib/prompts"; 24 + } from "../../../cli/src/lib/markdown.ts"; 25 + import { exitOnCancel } from "../../../cli/src/lib/prompts.ts"; 26 + import process from "node:process"; 23 27 24 28 async function matchesPDS( 25 29 localPost: BlogPost, ··· 62 66 }); 63 67 const noteValue = noteResponse.data.value as Record<string, unknown>; 64 68 const localDiscoverable = localPost.frontmatter.discoverable ?? true; 65 - const noteDiscoverable = (noteValue.discoverable as boolean | undefined) ?? true; 69 + const noteDiscoverable = 70 + (noteValue.discoverable as boolean | undefined) ?? true; 66 71 if ( 67 72 (localPost.frontmatter.theme || undefined) !== 68 73 (noteValue.theme as string | undefined) || ··· 156 161 process.exit(1); 157 162 } 158 163 159 - const { config, configPath: resolvedConfigPath } = 160 - await loadConfig(configPath); 164 + const { config, configPath: resolvedConfigPath } = await loadConfig( 165 + configPath, 166 + ); 161 167 const configDir = path.dirname(resolvedConfigPath); 162 168 163 169 log.info(`Publication: ${config.publicationUri}`); ··· 183 189 184 190 // Create agent 185 191 const s = spinner(); 186 - s.start(`Connecting as ${(credentials as AppPasswordCredentials).pdsUrl}...`); 192 + s.start( 193 + `Connecting as ${(credentials as AppPasswordCredentials).pdsUrl}...`, 194 + ); 187 195 let agent: Awaited<ReturnType<typeof createAgent>> | undefined; 188 196 try { 189 197 agent = await createAgent(credentials); ··· 214 222 const allScanned = await scanContentDirectory(contentDir, { 215 223 ignorePatterns: config.ignore, 216 224 }); 217 - const localPosts = allScanned.filter((p) => 218 - p.filePath.endsWith(".pub.md"), 219 - ); 225 + const localPosts = allScanned.filter((p) => p.filePath.endsWith(".pub.md")); 220 226 s.stop(`Found ${localPosts.length} publishable notes (.pub.md)`); 221 227 222 228 // Build a map from atUri -> local post for matching ··· 255 261 contentHash: contentMatchesPDS 256 262 ? await getContentHash(localPost.rawContent) 257 263 : "", 258 - noteHash: contentMatchesPDS 259 - ? await computeNoteHash(localPost) 260 - : "", 264 + noteHash: contentMatchesPDS ? await computeNoteHash(localPost) : "", 261 265 atUri: doc.uri, 262 266 lastPublished: doc.value.publishedAt, 263 267 };
+6 -3
packages/remanso-cli/src/lib/config.ts
··· 1 1 import * as fs from "node:fs/promises"; 2 2 import * as path from "node:path"; 3 - import type { PublisherState } from "../../../cli/src/lib/types"; 3 + import type { PublisherState } from "../../../cli/src/lib/types.ts"; 4 + import process from "node:process"; 4 5 5 6 export interface RemansoConfig { 6 7 contentDir: string; ··· 64 65 const content = await fs.readFile(resolvedPath, "utf-8"); 65 66 const parsed = JSON.parse(content) as RemansoConfigFile; 66 67 67 - if (!parsed.atmosphere) 68 + if (!parsed.atmosphere) { 68 69 throw new Error( 69 70 `Invalid config: missing "atmosphere" key in ${resolvedPath}`, 70 71 ); 72 + } 71 73 72 74 const config = parsed.atmosphere; 73 75 74 76 if (!config.contentDir) throw new Error("contentDir is required in config"); 75 - if (!config.publicationUri) 77 + if (!config.publicationUri) { 76 78 throw new Error("publicationUri is required in config"); 79 + } 77 80 78 81 return { config, configPath: resolvedPath }; 79 82 } catch (error) {