658348f208
Adds rulebooks.always_on (migration 0058) and a new list_always_on_rules MCP tool so a session-start eager pull can fetch standing rules without needing an active-project notion. Updates _INSTRUCTIONS so Claude calls the new tool at session start and codifies engineering rules in Scribe rather than CLAUDE.md / auto-memory. Seeds FabledSword family rulebook to always_on=true on migrate, matching its design role as the cross-project standards rulebook. Frontend: badge in RulebookListPane for always-on rulebooks; toggle in RulebookDetailPane header bound to a new toggleAlwaysOn store action. This is S1+S2 of the rules-consolidation plan (Scribe task #508). S3 (project-scoped rules) and S4 (enter_project handshake) follow. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
77 lines
2.5 KiB
Vue
77 lines
2.5 KiB
Vue
<script setup lang="ts">
|
|
import { ref } from "vue";
|
|
import { useRulebooksStore } from "@/stores/rulebooks";
|
|
import type { Rulebook } from "@/api/rulebooks";
|
|
|
|
defineProps<{ rulebooks: Rulebook[]; selectedId: number | null }>();
|
|
const emit = defineEmits<{ select: [id: number] }>();
|
|
|
|
const store = useRulebooksStore();
|
|
const isCreating = ref(false);
|
|
const newTitle = ref("");
|
|
|
|
async function submitNew() {
|
|
const title = newTitle.value.trim();
|
|
if (!title) return;
|
|
const rb = await store.createRulebook({ title });
|
|
newTitle.value = "";
|
|
isCreating.value = false;
|
|
emit("select", rb.id);
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<aside class="pane">
|
|
<header><h2>Rulebooks</h2></header>
|
|
<ul>
|
|
<li
|
|
v-for="rb in rulebooks"
|
|
:key="rb.id"
|
|
:class="{ active: rb.id === selectedId }"
|
|
@click="emit('select', rb.id)"
|
|
>
|
|
<span class="title">{{ rb.title }}</span>
|
|
<span v-if="rb.always_on" class="always-on-badge" title="Loaded at session start">always on</span>
|
|
</li>
|
|
</ul>
|
|
<div class="new-rulebook">
|
|
<button v-if="!isCreating" @click="isCreating = true">+ New rulebook</button>
|
|
<form v-else @submit.prevent="submitNew">
|
|
<input v-model="newTitle" autofocus placeholder="Rulebook title" />
|
|
<div class="form-buttons">
|
|
<button type="submit">Create</button>
|
|
<button type="button" @click="isCreating = false">Cancel</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</aside>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.pane { background: var(--color-surface, #18181b); padding: 1rem; overflow-y: auto; }
|
|
header h2 { font-family: Fraunces, serif; font-style: italic; margin: 0 0 0.5rem 0; }
|
|
ul { list-style: none; padding: 0; margin: 1rem 0; }
|
|
li { padding: 0.5rem; cursor: pointer; border-radius: 6px; display: flex; align-items: center; gap: 0.5rem; }
|
|
li.active { background: var(--color-primary-bg, rgba(99,102,241,0.15)); }
|
|
li:hover { background: var(--color-hover, rgba(255,255,255,0.05)); }
|
|
.always-on-badge {
|
|
font-size: 0.7rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
padding: 0.1rem 0.4rem;
|
|
border-radius: 3px;
|
|
background: var(--color-accent, rgba(91,74,138,0.25));
|
|
color: var(--color-accent-fg, inherit);
|
|
margin-left: auto;
|
|
}
|
|
.new-rulebook { margin-top: 1rem; }
|
|
.new-rulebook input {
|
|
width: 100%; margin-bottom: 0.5rem;
|
|
background: var(--color-bg, #111113); color: inherit;
|
|
border: 1px solid var(--color-border, #2a2a2e); border-radius: 6px;
|
|
padding: 0.5rem;
|
|
}
|
|
.form-buttons { display: flex; gap: 0.5rem; }
|
|
button { cursor: pointer; }
|
|
</style>
|