mirror of
https://github.com/github/awesome-copilot.git
synced 2026-08-26 18:45:12 +00:00
69 lines
2.9 KiB
JavaScript
69 lines
2.9 KiB
JavaScript
// User preferences for the Sentry Triage canvas, persisted to a small on-disk
|
|
// JSON file so an explicit choice (currently: the default org) survives canvas
|
|
// reopens. There is no first-class "extension preferences" API in the Copilot
|
|
// SDK, so we own this file ourselves. Design constraints we deliberately keep:
|
|
// - Only ever written on an explicit user action (never silently).
|
|
// - Only stores low-sensitivity data (an org slug) — never tokens/secrets.
|
|
// - Versioned + minimal shape so it's easy to reason about and migrate later.
|
|
// - Never throws: unreadable/corrupt/missing prefs fall back to empty defaults
|
|
// so the canvas keeps working.
|
|
// - Atomic writes (temp file + rename) so a crash mid-write can't leave a
|
|
// half-written file behind.
|
|
// Stored OUTSIDE ~/.copilot/extensions/sentry-triage/ (the redeploy target) so
|
|
// `npm run deploy` can't clobber the user's saved preference.
|
|
|
|
import { homedir } from 'node:os'
|
|
import { join } from 'node:path'
|
|
import { readFileSync, writeFileSync, mkdirSync, renameSync } from 'node:fs'
|
|
|
|
// Where the prefs file lives. Resolved lazily (not a module constant) so tests
|
|
// can point it at a temp directory via SENTRY_TRIAGE_PREFS_DIR and never touch a
|
|
// developer's real ~/.copilot/sentry-triage/preferences.json.
|
|
function prefsDir() {
|
|
return process.env.SENTRY_TRIAGE_PREFS_DIR || join(homedir(), '.copilot', 'sentry-triage')
|
|
}
|
|
function prefsPath() {
|
|
return join(prefsDir(), 'preferences.json')
|
|
}
|
|
// Shown to the user in the UI so the write is transparent (no leaked home dir).
|
|
export const PREFS_DISPLAY_PATH = join('~', '.copilot', 'sentry-triage', 'preferences.json')
|
|
const PREFS_VERSION = 1
|
|
|
|
function normalizeSlug(slug) {
|
|
return typeof slug === 'string' ? slug.trim().toLowerCase() : ''
|
|
}
|
|
|
|
// Read + normalize the prefs file. Always returns a well-formed object, even if
|
|
// the file is missing or corrupt.
|
|
export function readPrefs() {
|
|
try {
|
|
const data = JSON.parse(readFileSync(prefsPath(), 'utf-8'))
|
|
if (!data || typeof data !== 'object') return { version: PREFS_VERSION, defaultOrg: '' }
|
|
return {
|
|
version: PREFS_VERSION,
|
|
defaultOrg: normalizeSlug(data.defaultOrg),
|
|
}
|
|
} catch {
|
|
return { version: PREFS_VERSION, defaultOrg: '' }
|
|
}
|
|
}
|
|
|
|
export function getDefaultOrg() {
|
|
return readPrefs().defaultOrg
|
|
}
|
|
|
|
// Persist the user's chosen default org. Passing an empty/blank slug clears the
|
|
// saved default. Returns the normalized slug that was saved (or '' when cleared).
|
|
// Throws if the atomic write fails, so callers can report a real error instead of
|
|
// showing a success toast for a preference that never landed on disk.
|
|
export function saveDefaultOrg(slug) {
|
|
const value = normalizeSlug(slug)
|
|
const payload = JSON.stringify({ version: PREFS_VERSION, defaultOrg: value }, null, 2) + '\n'
|
|
mkdirSync(prefsDir(), { recursive: true })
|
|
const path = prefsPath()
|
|
const tmp = `${path}.${process.pid}.tmp`
|
|
writeFileSync(tmp, payload, 'utf-8')
|
|
renameSync(tmp, path)
|
|
return value
|
|
}
|