diff --git a/app/incident/[id].tsx b/app/incident/[id].tsx
index 8980e14..b229aa4 100644
--- a/app/incident/[id].tsx
+++ b/app/incident/[id].tsx
@@ -10,7 +10,7 @@ import {
import { useLocalSearchParams, router, useNavigation } from "expo-router";
import * as Clipboard from "expo-clipboard";
import * as SecureStore from "expo-secure-store";
-import { getIncidentById, updateIncident } from "@/lib/db";
+import { getIncidentById, updateIncident, deleteIncident } from "@/lib/db";
import { renderMarkdown } from "@/lib/markdown";
import { pushIncidentToGit } from "@/lib/git";
import type { GitProvider } from "@/lib/git";
@@ -54,6 +54,25 @@ export default function IncidentDetailScreen() {
}
}, [id]);
+ async function handleDelete() {
+ if (!incident) return;
+ Alert.alert(
+ "Delete incident?",
+ "This action cannot be undone.",
+ [
+ { text: "Cancel", style: "cancel" },
+ {
+ text: "Delete",
+ style: "destructive",
+ onPress: async () => {
+ await deleteIncident(incident.id);
+ router.replace("/");
+ },
+ },
+ ]
+ );
+ }
+
async function handleResolve() {
if (!incident) return;
await updateIncident(incident.id, { status: "resolved" });
@@ -291,6 +310,23 @@ export default function IncidentDetailScreen() {
Edit
+
+
+
+ Delete Incident
+
+
);
diff --git a/app/settings.tsx b/app/settings.tsx
index 5e06173..4fc7593 100644
--- a/app/settings.tsx
+++ b/app/settings.tsx
@@ -17,6 +17,8 @@ const KEYS = {
HOME_VIEW: "pref_home_view",
AI_ENABLED: "pref_ai_enabled",
AI_KEY: "pref_ai_key",
+ AI_BASE_URL: "pref_ai_base_url",
+ AI_MODEL: "pref_ai_model",
MD_TEMPLATE: "md_template",
GIT_PROVIDER: "git_provider",
// Gitea
@@ -75,6 +77,8 @@ export default function SettingsScreen() {
const [homeView, setHomeView] = useState<"dashboard" | "capture">("dashboard");
const [aiEnabled, setAiEnabled] = useState(false);
const [aiKey, setAiKey] = useState("");
+ const [aiBaseUrl, setAiBaseUrl] = useState("");
+ const [aiModel, setAiModel] = useState("");
const [mdTemplate, setMdTemplate] = useState(DEFAULT_TEMPLATE);
const [saved, setSaved] = useState(false);
@@ -97,12 +101,14 @@ export default function SettingsScreen() {
useEffect(() => {
(async () => {
- const [im, hv, ai, key, tpl, gp, gu, gt, go, gr, ghu, ghown, ghrepo, glu, glt, glo, glr] =
+ const [im, hv, ai, key, aiUrl, aiMdl, tpl, gp, gu, gt, go, gr, ghu, ghown, ghrepo, glu, glt, glo, glr] =
await Promise.all([
SecureStore.getItemAsync(KEYS.INPUT_MODE),
SecureStore.getItemAsync(KEYS.HOME_VIEW),
SecureStore.getItemAsync(KEYS.AI_ENABLED),
SecureStore.getItemAsync(KEYS.AI_KEY),
+ SecureStore.getItemAsync(KEYS.AI_BASE_URL),
+ SecureStore.getItemAsync(KEYS.AI_MODEL),
SecureStore.getItemAsync(KEYS.MD_TEMPLATE),
SecureStore.getItemAsync(KEYS.GIT_PROVIDER),
SecureStore.getItemAsync(KEYS.GITEA_URL),
@@ -121,6 +127,8 @@ export default function SettingsScreen() {
if (hv) setHomeView(hv as "dashboard" | "capture");
if (ai) setAiEnabled(ai === "true");
if (key) setAiKey(key);
+ if (aiUrl) setAiBaseUrl(aiUrl);
+ if (aiMdl) setAiModel(aiMdl);
if (tpl) setMdTemplate(tpl);
if (gp) setGitProvider(gp as GitProvider);
if (gu) setGiteaUrl(gu);
@@ -143,6 +151,8 @@ export default function SettingsScreen() {
SecureStore.setItemAsync(KEYS.HOME_VIEW, homeView),
SecureStore.setItemAsync(KEYS.AI_ENABLED, String(aiEnabled)),
SecureStore.setItemAsync(KEYS.AI_KEY, aiKey),
+ SecureStore.setItemAsync(KEYS.AI_BASE_URL, aiBaseUrl),
+ SecureStore.setItemAsync(KEYS.AI_MODEL, aiModel),
SecureStore.setItemAsync(KEYS.MD_TEMPLATE, mdTemplate),
SecureStore.setItemAsync(KEYS.GIT_PROVIDER, gitProvider),
SecureStore.setItemAsync(KEYS.GITEA_URL, giteaUrl),
@@ -300,20 +310,52 @@ export default function SettingsScreen() {
]}
/>
- AI (optional)
+ AI — Root Cause Assistant
+
+
+ When enabled, a button appears on the capture form to suggest a root cause and fix
+ based on the incident title and symptom. Uses any OpenAI-compatible API —
+ set the base URL below to point at a local Ollama instance or leave empty
+ for OpenAI (api.openai.com).
+
+
{aiEnabled && (
-
+ <>
+
+
+
+ >
)}
Git Repository