Skip to content

Instantly share code, notes, and snippets.

@benmj
Created June 27, 2024 21:20
Show Gist options
  • Save benmj/389a292c5a29dd1126a46c8f0afaa5df to your computer and use it in GitHub Desktop.
Save benmj/389a292c5a29dd1126a46c8f0afaa5df to your computer and use it in GitHub Desktop.
An example of basic productivity tooling built on top of Reflect.app
#!/usr/bin/env node
import { Command } from 'commander';
import { format } from 'date-fns';
const program = new Command();
const REFLECT_API_KEY = 'REDACTED_API_KEY';
const GRAPH_NAME = 'REDACTED_GRAPH_NAME';
program
.name('cli')
.description('A command line tool for reflection, Linear, and Git operations')
.version('0.1.0');
program
.command('log <entry>')
.description('Log a timestamped note to daily log in Reflect.app')
.action(async (entry: string) => {
console.log('Starting daily reflection...');
await addLogEntry(entry);
console.log('Added');
});
program
.command('note <title>')
.description('Receive piped input from STDIN and create a new note with a backlink to the current daily note')
.action(async (title: string) => {
if (process.stdin.isTTY) {
console.error('No input received. `cli note` command expects piped input, e.x.: echo "hello world" | cli note')
process.exit(1);
}
const contents = await readFromStdin();
await createNote(title, contents);
await addLogEntry(`Added note: [[${title}]]`);
});
async function readFromStdin(): Promise<string> {
return new Promise<string>((resolve, reject) => {
let data = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', chunk => {
data += chunk;
});
process.stdin.on('end', () => {
resolve(data);
});
process.stdin.on('error', err => {
reject(err);
});
});
}
async function createNote(title: string, contents: string) {
const url = `https://reflect.app/api/graphs/${GRAPH_NAME}/notes`;
const now = new Date();
const data = {
subject: title,
content_markdown: `# ${title}\n\n \n\n${contents}`
}
const options = {
method: 'POST',
headers: {
'Authorization': `Bearer ${REFLECT_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
}
console.log(`url: ${url}`)
console.log(`options`, JSON.stringify(options, null, 2))
try {
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`Network response was not ok ${response.statusText}`);
}
console.log(JSON.stringify(response.json(), null, 2));
} catch (error) {
console.error('There was a problem with the fetch operation:', error);
}
}
async function addLogEntry(entry: string) {
const now = new Date();
const url = `https://reflect.app/api/graphs/${GRAPH_NAME}/daily-notes`;
const data = {
date: format(now, 'yyyy-MM-dd'),
text: `${format(now, 'h:mmaaa')} ${entry}`,
transform_type: "list-append",
list_name: "[[REDACTED_LOG_NAME]]"
};
const options = {
method: 'PUT',
headers: {
'Authorization': `Bearer ${REFLECT_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
};
console.log(`options`, JSON.stringify(options, null, 2));
try {
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`Network response was not ok ${response.statusText}`);
}
console.log(JSON.stringify(response.json(), null, 2));
} catch (error) {
console.error('There was a problem with the fetch operation:', error);
}
}
program.parse(process.argv);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment