diff --git a/packages/remanso-cli/src/commands/init.ts b/packages/remanso-cli/src/commands/init.ts index 9f53bfa..05333b7 100644 --- a/packages/remanso-cli/src/commands/init.ts +++ b/packages/remanso-cli/src/commands/init.ts @@ -15,19 +15,20 @@ import { } from "@clack/prompts"; import { AtpAgent } from "@atproto/api"; import { - resolveHandleToPDS, - createPublication, createAgent, -} from "../../../cli/src/lib/atproto"; + createPublication, + resolveHandleToPDS, +} from "../../../cli/src/lib/atproto.ts"; import { - loadCredentials, - saveCredentials, getCredentials, listCredentials, -} from "../../../cli/src/lib/credentials"; -import { exitOnCancel } from "../../../cli/src/lib/prompts"; -import type { RemansoConfig } from "../lib/config"; -import { WORKFLOW_YAML } from "./github"; + loadCredentials, + saveCredentials, +} from "../../../cli/src/lib/credentials.ts"; +import { exitOnCancel } from "../../../cli/src/lib/prompts.ts"; +import type { RemansoConfig } from "../lib/config.ts"; +import { WORKFLOW_YAML } from "./github.ts"; +import process from "node:process"; const CONFIG_FILENAME = ".remanso.json"; const STATE_FILENAME = ".remanso-state.json"; @@ -100,11 +101,6 @@ async function listPublications( return results; } -const onCancel = () => { - outro("Setup cancelled"); - process.exit(0); -}; - export const initCommand = command({ name: "init", description: "Initialize a new Remanso notes configuration", diff --git a/packages/remanso-cli/src/commands/publish.ts b/packages/remanso-cli/src/commands/publish.ts index 6cf7ec0..90cef51 100644 --- a/packages/remanso-cli/src/commands/publish.ts +++ b/packages/remanso-cli/src/commands/publish.ts @@ -2,42 +2,43 @@ import * as fs from "node:fs/promises"; import { command, flag } from "cmd-ts"; import { log, spinner } from "@clack/prompts"; import * as path from "node:path"; -import { findConfig, loadConfig, loadState, saveState } from "../lib/config"; +import { findConfig, loadConfig, loadState, saveState } from "../lib/config.ts"; import { - loadCredentials, - listAllCredentials, getCredentials, -} from "../../../cli/src/lib/credentials"; + listAllCredentials, + loadCredentials, +} from "../../../cli/src/lib/credentials.ts"; import { createAgent, createDocument, - updateDocument, - uploadImage, - resolveImagePath, deleteRecord, listDocuments, parseAtUri, -} from "../../../cli/src/lib/atproto"; + resolveImagePath, + updateDocument, + uploadImage, +} from "../../../cli/src/lib/atproto.ts"; import { - scanContentDirectory, + computeNoteHash, getContentHash, - updateFrontmatterWithAtUri, + scanContentDirectory, slugifyTitle, - computeNoteHash, -} from "../../../cli/src/lib/markdown"; + updateFrontmatterWithAtUri, +} from "../../../cli/src/lib/markdown.ts"; import type { - BlogPost, - BlobObject, AppPasswordCredentials, -} from "../../../cli/src/lib/types"; -import { exitOnCancel } from "../../../cli/src/lib/prompts"; + BlobObject, + BlogPost, +} from "../../../cli/src/lib/types.ts"; +import { exitOnCancel } from "../../../cli/src/lib/prompts.ts"; import { createNote, - updateNote, deleteNote, findPostsWithStaleLinks, type NoteOptions, -} from "../lib/note"; + updateNote, +} from "../lib/note.ts"; +import process from "node:process"; async function fileExists(filePath: string): Promise { try { @@ -115,8 +116,9 @@ export const publishCommand = command({ process.exit(1); } - const { config, configPath: resolvedConfigPath } = - await loadConfig(configPath); + const { config, configPath: resolvedConfigPath } = await loadConfig( + configPath, + ); const configDir = path.dirname(resolvedConfigPath); log.info(`Content directory: ${config.contentDir}`); @@ -262,7 +264,9 @@ export const publishCommand = command({ if (draftPosts.length > 0) { log.info( - `Skipping ${draftPosts.length} draft note${draftPosts.length === 1 ? "" : "s"}`, + `Skipping ${draftPosts.length} draft note${ + draftPosts.length === 1 ? "" : "s" + }`, ); } @@ -385,7 +389,14 @@ export const publishCommand = command({ updateNote: boolean; }> = []; - for (const { post, action, updateDocument: shouldUpdateDoc, updateNote: shouldUpdateNote } of postsToPublish) { + for ( + const { + post, + action, + updateDocument: shouldUpdateDoc, + updateNote: shouldUpdateNote, + } of postsToPublish + ) { const trimmedContent = post.content.trim(); const titleMatch = trimmedContent.match(/^# (.+)$/m); const title = titleMatch ? titleMatch[1] : post.frontmatter.title; @@ -474,8 +485,9 @@ export const publishCommand = command({ noteQueue.push({ post, action, atUri, updateNote: shouldUpdateNote }); } catch (error) { - const errorMessage = - error instanceof Error ? error.message : String(error); + const errorMessage = error instanceof Error + ? error.message + : String(error); s.stop(`Error publishing "${path.basename(post.filePath)}"`); log.error(` ${errorMessage}`); errorCount++; @@ -483,7 +495,9 @@ export const publishCommand = command({ } // Pass 2: Create/update Remanso notes - for (const { post, action, atUri, updateNote: shouldUpdateNote } of noteQueue) { + for ( + const { post, action, atUri, updateNote: shouldUpdateNote } of noteQueue + ) { if (!shouldUpdateNote && action !== "create") continue; const relativeFilePath = path.relative(configDir, post.filePath); try { @@ -499,7 +513,9 @@ export const publishCommand = command({ } } catch (error) { log.warn( - `Failed to create note for "${post.frontmatter.title}": ${error instanceof Error ? error.message : String(error)}`, + `Failed to create note for "${post.frontmatter.title}": ${ + error instanceof Error ? error.message : String(error) + }`, ); } } diff --git a/packages/remanso-cli/src/commands/sync.ts b/packages/remanso-cli/src/commands/sync.ts index 02317c6..336e3e4 100644 --- a/packages/remanso-cli/src/commands/sync.ts +++ b/packages/remanso-cli/src/commands/sync.ts @@ -2,24 +2,28 @@ import * as fs from "node:fs/promises"; import { command, flag } from "cmd-ts"; import { log, spinner } from "@clack/prompts"; import * as path from "node:path"; -import { findConfig, loadConfig, loadState, saveState } from "../lib/config"; +import { findConfig, loadConfig, loadState, saveState } from "../lib/config.ts"; import { - loadCredentials, - listAllCredentials, getCredentials, -} from "../../../cli/src/lib/credentials"; + listAllCredentials, + loadCredentials, +} from "../../../cli/src/lib/credentials.ts"; import type { Agent } from "@atproto/api"; -import { createAgent, listDocuments } from "../../../cli/src/lib/atproto"; -import type { ListDocumentsResult } from "../../../cli/src/lib/atproto"; -import type { BlogPost, AppPasswordCredentials } from "../../../cli/src/lib/types"; +import { createAgent, listDocuments } from "../../../cli/src/lib/atproto.ts"; +import type { ListDocumentsResult } from "../../../cli/src/lib/atproto.ts"; +import type { + AppPasswordCredentials, + BlogPost, +} from "../../../cli/src/lib/types.ts"; import { - scanContentDirectory, + computeNoteHash, getContentHash, getTextContent, + scanContentDirectory, updateFrontmatterWithAtUri, - computeNoteHash, -} from "../../../cli/src/lib/markdown"; -import { exitOnCancel } from "../../../cli/src/lib/prompts"; +} from "../../../cli/src/lib/markdown.ts"; +import { exitOnCancel } from "../../../cli/src/lib/prompts.ts"; +import process from "node:process"; async function matchesPDS( localPost: BlogPost, @@ -62,7 +66,8 @@ async function matchesPDS( }); const noteValue = noteResponse.data.value as Record; const localDiscoverable = localPost.frontmatter.discoverable ?? true; - const noteDiscoverable = (noteValue.discoverable as boolean | undefined) ?? true; + const noteDiscoverable = + (noteValue.discoverable as boolean | undefined) ?? true; if ( (localPost.frontmatter.theme || undefined) !== (noteValue.theme as string | undefined) || @@ -156,8 +161,9 @@ export const syncCommand = command({ process.exit(1); } - const { config, configPath: resolvedConfigPath } = - await loadConfig(configPath); + const { config, configPath: resolvedConfigPath } = await loadConfig( + configPath, + ); const configDir = path.dirname(resolvedConfigPath); log.info(`Publication: ${config.publicationUri}`); @@ -183,7 +189,9 @@ export const syncCommand = command({ // Create agent const s = spinner(); - s.start(`Connecting as ${(credentials as AppPasswordCredentials).pdsUrl}...`); + s.start( + `Connecting as ${(credentials as AppPasswordCredentials).pdsUrl}...`, + ); let agent: Awaited> | undefined; try { agent = await createAgent(credentials); @@ -214,9 +222,7 @@ export const syncCommand = command({ const allScanned = await scanContentDirectory(contentDir, { ignorePatterns: config.ignore, }); - const localPosts = allScanned.filter((p) => - p.filePath.endsWith(".pub.md"), - ); + const localPosts = allScanned.filter((p) => p.filePath.endsWith(".pub.md")); s.stop(`Found ${localPosts.length} publishable notes (.pub.md)`); // Build a map from atUri -> local post for matching @@ -255,9 +261,7 @@ export const syncCommand = command({ contentHash: contentMatchesPDS ? await getContentHash(localPost.rawContent) : "", - noteHash: contentMatchesPDS - ? await computeNoteHash(localPost) - : "", + noteHash: contentMatchesPDS ? await computeNoteHash(localPost) : "", atUri: doc.uri, lastPublished: doc.value.publishedAt, }; diff --git a/packages/remanso-cli/src/lib/config.ts b/packages/remanso-cli/src/lib/config.ts index 3e5b10d..4651efe 100644 --- a/packages/remanso-cli/src/lib/config.ts +++ b/packages/remanso-cli/src/lib/config.ts @@ -1,6 +1,7 @@ import * as fs from "node:fs/promises"; import * as path from "node:path"; -import type { PublisherState } from "../../../cli/src/lib/types"; +import type { PublisherState } from "../../../cli/src/lib/types.ts"; +import process from "node:process"; export interface RemansoConfig { contentDir: string; @@ -64,16 +65,18 @@ export async function loadConfig( const content = await fs.readFile(resolvedPath, "utf-8"); const parsed = JSON.parse(content) as RemansoConfigFile; - if (!parsed.atmosphere) + if (!parsed.atmosphere) { throw new Error( `Invalid config: missing "atmosphere" key in ${resolvedPath}`, ); + } const config = parsed.atmosphere; if (!config.contentDir) throw new Error("contentDir is required in config"); - if (!config.publicationUri) + if (!config.publicationUri) { throw new Error("publicationUri is required in config"); + } return { config, configPath: resolvedPath }; } catch (error) {