← Public packages
@kentcdodds/devin
Start, monitor, and manage Devin sessions, knowledge, playbooks, and schedules via the Devin v3 API
src/knowledge.ts
148 lines · 3.6 KB · TypeScriptimport {
clampInt,
compact,
devinOrgApi,
type Paginated,
trimString,
} from './lib/client.ts'
export type KnowledgeNote = {
note_id: string
name: string
body: string
trigger: string
folder_id: string | null
folder_path: string
is_enabled: boolean
pinned_repo: string | null
macro: string | null
access_type: 'org' | 'enterprise' | string
org_id: string | null
created_at: number
updated_at: number
}
export type KnowledgeFolder = {
folder_id?: string | null
name?: string | null
path?: string | null
[key: string]: unknown
}
export async function listNotes(params: {
orgId?: string
first?: number
after?: string
search?: string
folderPath?: string
pinnedRepo?: string
} = {}) {
return devinOrgApi<Paginated<KnowledgeNote>>({
orgId: params.orgId,
path: '/knowledge/notes',
query: compact({
first: params.first === undefined ? undefined : clampInt(params.first, 1, 200, 50),
after: params.after,
search: params.search,
folder_path: params.folderPath,
pinned_repo: params.pinnedRepo,
}),
})
}
export async function getNote(params: { noteId: string; orgId?: string }) {
return devinOrgApi<KnowledgeNote>({
orgId: params.orgId,
path: `/knowledge/notes/${encodeURIComponent(params.noteId)}`,
})
}
export type NoteInput = {
orgId?: string
name: string
body: string
/** When Devin should pull this note in, e.g. "When working in owner/repo". */
trigger: string
folderId?: string
pinnedRepo?: string
isEnabled?: boolean
}
function noteBody(params: NoteInput) {
const name = trimString(params.name)
const body = trimString(params.body)
const trigger = trimString(params.trigger)
if (!name || !body || !trigger) {
throw new Error('Knowledge notes require name, body, and trigger')
}
return compact({
name,
body,
trigger,
folder_id: params.folderId,
pinned_repo: params.pinnedRepo,
is_enabled: params.isEnabled,
})
}
export async function createNote(params: NoteInput) {
return devinOrgApi<KnowledgeNote>({
orgId: params.orgId,
path: '/knowledge/notes',
method: 'POST',
body: noteBody(params),
})
}
/** Full replace — Devin's PUT takes the same shape as create. */
export async function updateNote(params: NoteInput & { noteId: string }) {
return devinOrgApi<KnowledgeNote>({
orgId: params.orgId,
path: `/knowledge/notes/${encodeURIComponent(params.noteId)}`,
method: 'PUT',
body: noteBody(params),
})
}
/** Destructive — confirm the note id before calling. */
export async function deleteNote(params: { noteId: string; orgId?: string }) {
return devinOrgApi<unknown>({
orgId: params.orgId,
path: `/knowledge/notes/${encodeURIComponent(params.noteId)}`,
method: 'DELETE',
})
}
export async function listFolders(params: { orgId?: string } = {}) {
return devinOrgApi<{ items: KnowledgeFolder[] } | KnowledgeFolder[]>({
orgId: params.orgId,
path: '/knowledge/folders',
})
}
/**
* List Devin knowledge notes for the configured org (default `./knowledge` action).
* Use when browsing or searching notes; named exports cover get/create/update/delete.
*
* @param params.orgId - Optional org override (else stored destOrgId)
* @param params.search - Optional note search string
* @param params.first - Page size (1–200)
* @returns Paginated knowledge notes
*
* @example
* import listNotes from 'kody:@kentcdodds/devin/knowledge'
* const page = await listNotes({ first: 20 })
* // => { items: [{ note_id: '...', name: '...', ... }], ... }
*/
export default async function listNotesDefault(
params: {
orgId?: string
first?: number
after?: string
search?: string
folderPath?: string
pinnedRepo?: string
} = {},
) {
return await listNotes(params)
}