capture-inbox.mjs
sha256:8915fe406161f95c1681f9469375e7bae5b28c884f00bedbdef65e4b0cd0738d
docs(flow): commit FLOW-V0-SPEC.md hygiene for 7A-INT merge
Human
16 hours ago
| 1 | /** |
| 2 | * Fast inbox capture (Issue #1 Phase C3). No AIR — inbox exempt. |
| 3 | */ |
| 4 | |
| 5 | import { loadConfig } from './config.mjs'; |
| 6 | import { writeNote } from './write.mjs'; |
| 7 | import { normalizeSlug, normalizeTags } from './vault.mjs'; |
| 8 | |
| 9 | function slugFromText(text, maxLen = 48) { |
| 10 | const base = String(text || '') |
| 11 | .toLowerCase() |
| 12 | .replace(/[^a-z0-9]+/g, '-') |
| 13 | .replace(/^-|-$/g, '') |
| 14 | .slice(0, maxLen); |
| 15 | return base || 'capture'; |
| 16 | } |
| 17 | |
| 18 | /** |
| 19 | * Build vault-relative path, body, and inbox frontmatter for a fast capture (local disk or hosted canister write). |
| 20 | * |
| 21 | * @param {string} text |
| 22 | * @param {{ source?: string, project?: string, tags?: string[] }} options |
| 23 | * @param {Date} [now] - defaults to `new Date()`; inject in tests for stable paths |
| 24 | * @returns {{ path: string, body: string, frontmatter: Record<string, unknown> }} |
| 25 | */ |
| 26 | export function buildCaptureInboxWritePayload(text, options = {}, now = new Date()) { |
| 27 | const dateStr = now.toISOString().slice(0, 10); |
| 28 | const hh = String(now.getHours()).padStart(2, '0'); |
| 29 | const mm = String(now.getMinutes()).padStart(2, '0'); |
| 30 | const ss = String(now.getSeconds()).padStart(2, '0'); |
| 31 | const timeStr = `${hh}${mm}${ss}`; |
| 32 | const slug = slugFromText(text); |
| 33 | |
| 34 | let relDir = 'inbox'; |
| 35 | if (options.project) { |
| 36 | const proj = normalizeSlug(String(options.project)); |
| 37 | if (proj) relDir = `projects/${proj}/inbox`; |
| 38 | } |
| 39 | |
| 40 | const filename = `${dateStr}-${timeStr}-${slug}.md`.replace(/-+/g, '-'); |
| 41 | const relativePath = `${relDir}/${filename}`; |
| 42 | |
| 43 | const tags = options.tags?.length ? normalizeTags(options.tags) : []; |
| 44 | const tagStr = tags.length ? tags.join(', ') : undefined; |
| 45 | |
| 46 | /** @type {Record<string, unknown>} */ |
| 47 | const frontmatter = { |
| 48 | source: options.source || 'mcp-capture', |
| 49 | date: dateStr, |
| 50 | inbox: true, |
| 51 | }; |
| 52 | if (tagStr) frontmatter.tags = tagStr; |
| 53 | if (options.project) frontmatter.project = normalizeSlug(String(options.project)); |
| 54 | |
| 55 | return { |
| 56 | path: relativePath, |
| 57 | body: String(text || '').trim(), |
| 58 | frontmatter, |
| 59 | }; |
| 60 | } |
| 61 | |
| 62 | /** |
| 63 | * @param {string} text |
| 64 | * @param {{ source?: string, project?: string, tags?: string[] }} options |
| 65 | * @returns {Promise<{ path: string, written: boolean }>} |
| 66 | */ |
| 67 | export async function runCaptureInbox(text, options = {}) { |
| 68 | const config = loadConfig(); |
| 69 | const { path, body, frontmatter } = buildCaptureInboxWritePayload(text, options); |
| 70 | return writeNote(config.vault_path, path, { |
| 71 | body, |
| 72 | frontmatter, |
| 73 | }); |
| 74 | } |
File History
1 commit
sha256:8915fe406161f95c1681f9469375e7bae5b28c884f00bedbdef65e4b0cd0738d
docs(flow): commit FLOW-V0-SPEC.md hygiene for 7A-INT merge
Human
16 hours ago