Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.git
.github
**/.nuxt
**/.output
**/.turbo
**/node_modules
**/dist
**/*.log
.env
.env.*
!.env.example
.claude
.specify
specs
docs
terraform
**/.terraform
*.tfstate
*.tfstate.backup
k3s_kubeconfig.yaml
.DS_Store
7 changes: 7 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ jobs:
DATABASE_URL: postgresql://dummy:dummy@localhost:5432/dummy
run: bunx prisma-import --force && bunx prisma generate

- name: Generate API swagger
working-directory: api
run: bun run build && bun run generate:swagger

- name: Typecheck consoles
run: bunx turbo typecheck --filter=app --filter=admin

- name: Lint
run: bun run lint

Expand Down
2 changes: 1 addition & 1 deletion .specify/feature.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"feature_directory": "specs/005-shimmer-thinking-ui"
"feature_directory": "specs/002-nuxt4-migration"
}
5 changes: 4 additions & 1 deletion admin/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ export default defineNuxtConfig({
devtools: { enabled: false },
extends: [...registerSlices()],
ssr: false,
future: {
compatibilityVersion: 4,
},
runtimeConfig: {
public: {
ranchVersion: rootRanchVersion(),
Expand Down Expand Up @@ -51,5 +54,5 @@ export default defineNuxtConfig({
},
},
modules: ['@nuxt/image'],
compatibilityDate: '2024-10-04',
compatibilityDate: '2026-08-14',
});
14 changes: 9 additions & 5 deletions admin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@
"build": "nuxt build",
"build:api": "openapi-ts",
"preview": "nuxt preview",
"pretypecheck": "openapi-ts",
"typecheck": "nuxt typecheck",
"lint": "echo 'admin lint: not configured (see eslint.config.mjs TODO)'",
"test": "echo 'admin test: no tests yet'"
},
"dependencies": {
"@hey-api/client-axios": "^0.6",
"@nuxt/image": "^1",
"@nuxtjs/i18n": "^9",
"@pinia/nuxt": "^0.9",
"@nuxt/image": "^2.1.0",
"@nuxtjs/i18n": "^10",
"@pinia/nuxt": "^0.11",
"@tabler/icons-vue": "^3.41.1",
"@tanstack/vue-table": "^8.21.3",
"@unovis/ts": "^1.6.4",
Expand All @@ -31,7 +33,7 @@
"graphology-types": "^0.24.8",
"lucide-vue-next": "^1.0.0",
"marked": "^18.0.2",
"nuxt": "^3.16",
"nuxt": "^4",
"pinia": "^3",
"reka-ui": "^2.9.6",
"shadcn-nuxt": "^2.4.3",
Expand All @@ -48,6 +50,8 @@
"@tailwindcss/vite": "^4.2.1",
"@types/dompurify": "^3.2.0",
"tailwindcss": "^4.2.1",
"tw-animate-css": "^1.4.0"
"tw-animate-css": "^1.4.0",
"typescript": "^5",
"vue-tsc": "^3.3.9"
}
}
4 changes: 2 additions & 2 deletions admin/slices/agent/agent/data/agent.gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ function unwrapOrThrow(res: HeyApiResult, action: string): unknown {

function readAccessToken(): string | null {
if (typeof document === 'undefined') return null;
const m = document.cookie.match(/(?:^|;\s*)access_token=([^;]+)/);
return m ? decodeURIComponent(m[1]) : null;
const token = document.cookie.match(/(?:^|;\s*)access_token=([^;]+)/)?.[1];
return token ? decodeURIComponent(token) : null;
}

export class AgentGateway extends BaseGateway implements IAgentGateway {
Expand Down
6 changes: 5 additions & 1 deletion admin/slices/agent/agent/i18n/locales/en.json
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
{}
{
"all_agents": "All Agents",
"restart_agent": "Restart",
"delete_agent": "Delete"
}
5 changes: 0 additions & 5 deletions admin/slices/agent/agent/locales/en.json

This file was deleted.

8 changes: 5 additions & 3 deletions admin/slices/agent/agent/utils/agentLogs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,12 @@ export function parseAgentLogs(raw: string): IAgentLogGroup[] {
let dayLabel: string | null = null;

const m = line.match(TS_LINE_RE);
if (m) {
const d = parseLogTimestamp(m[1]);
const rawTs = m?.[1];
const rawText = m?.[2];
if (rawTs !== undefined && rawText !== undefined) {
const d = parseLogTimestamp(rawTs);
if (d) {
text = m[2].replace(RUNTIME_TIME_PREFIX_RE, '');
text = rawText.replace(RUNTIME_TIME_PREFIX_RE, '');
time = `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}.${String(d.getMilliseconds()).padStart(3, '0')}`;
dayKey = `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`;
dayLabel = d.toLocaleDateString('en-US', {
Expand Down
34 changes: 21 additions & 13 deletions admin/slices/agent/file/components/agentFile/Viewer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,27 @@ import { Button } from '#theme/components/ui/button';
import { IconChevronDown } from '@tabler/icons-vue';
import AgentFileEditor from './Editor.vue';

const props = defineProps<{
path: string | null;
content: string;
loading: boolean;
saving: boolean;
loadError: string | null;
saveError: string | null;
dirty: boolean;
totalSize: number;
loadedSize: number;
hasMore: boolean;
loadingMore: boolean;
}>();
const props = withDefaults(
defineProps<{
path: string | null;
content: string;
loading: boolean;
saving: boolean;
loadError: string | null;
saveError: string | null;
dirty: boolean;
totalSize?: number;
loadedSize?: number;
hasMore?: boolean;
loadingMore?: boolean;
}>(),
{
totalSize: 0,
loadedSize: 0,
hasMore: false,
loadingMore: false,
},
);

const emit = defineEmits<{
(e: 'update:content', v: string): void;
Expand Down
4 changes: 2 additions & 2 deletions admin/slices/agent/file/data/agentFile.gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import { AgentFileMapper } from './agentFile.mapper';

function readAccessToken(): string | null {
if (typeof document === 'undefined') return null;
const m = document.cookie.match(/(?:^|;\s*)access_token=([^;]+)/);
return m ? decodeURIComponent(m[1]) : null;
const token = document.cookie.match(/(?:^|;\s*)access_token=([^;]+)/)?.[1];
return token ? decodeURIComponent(token) : null;
}

export class AgentFileGateway extends BaseGateway implements IAgentFileGateway {
Expand Down
1 change: 1 addition & 0 deletions admin/slices/agent/template/domain/template.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface ITemplateData {
defaultKnowledgeIds: string[];
skillIds: string[];
mcpServerIds: string[];
version?: string;
createdAt: string;
updatedAt: string;
}
Expand Down
5 changes: 4 additions & 1 deletion admin/slices/agent/template/i18n/locales/en.json
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
{}
{
"manage_templates": "Manage Templates",
"create_template": "Create Template"
}
4 changes: 0 additions & 4 deletions admin/slices/agent/template/locales/en.json

This file was deleted.

12 changes: 7 additions & 5 deletions admin/slices/bridle/stores/bridle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ export const useBridleStore = defineStore('bridle', {
}
}
// Anchor after every message on screen — wire ts is agent-clock.
const lastTs = this.messages.length ? this.messages[this.messages.length - 1].ts : 0
const lastTs = this.messages[this.messages.length - 1]?.ts ?? 0
block = {
turnId: e.turnId,
seg: turnBlocks.length,
Expand All @@ -437,8 +437,9 @@ export const useBridleStore = defineStore('bridle', {
const text = data.text ?? ''
const parts = data.parts ?? (text ? [{ type: BridlePartTypes.Text as const, text }] : [])
const idx = this.messages.findIndex(m => m.id === data.messageId)
if (idx >= 0) {
this.messages[idx] = { ...this.messages[idx], text, parts, streaming: true }
const current = this.messages[idx]
if (current) {
this.messages[idx] = { ...current, text, parts, streaming: true }
} else {
// Don't create a fresh bubble for an empty initial chunk — wait
// until the runtime actually has visible content.
Expand Down Expand Up @@ -479,8 +480,9 @@ export const useBridleStore = defineStore('bridle', {
const text = data.text ?? ''
const parts = data.parts ?? (text ? [{ type: BridlePartTypes.Text as const, text }] : [])
const idx = this.messages.findIndex(m => m.id === data.messageId)
if (idx >= 0) {
this.messages[idx] = { ...this.messages[idx], text, parts, streaming: false }
const current = this.messages[idx]
if (current) {
this.messages[idx] = { ...current, text, parts, streaming: false }
} else {
if (!hasVisibleContent(text, parts)) return
this.messages.push({
Expand Down
4 changes: 2 additions & 2 deletions admin/slices/common/composables/useRanchUpdate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ async function fetchLiveCurrent(): Promise<string | null> {
try {
const config = useRuntimeConfig();
const apiUrl = config.public.apiUrl as string;
const match = document.cookie.match(/(?:^|;\s*)access_token=([^;]+)/);
const token = match ? decodeURIComponent(match[1]) : null;
const raw = document.cookie.match(/(?:^|;\s*)access_token=([^;]+)/)?.[1];
const token = raw ? decodeURIComponent(raw) : null;
const res = await fetch(`${apiUrl}/upgrade/status`, {
headers: token ? { Authorization: `Bearer ${token}` } : {},
});
Expand Down
8 changes: 7 additions & 1 deletion admin/slices/common/i18n/locales/en.json
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
{}
{
"app_name": "Ranch Admin",
"nav_agents": "Agents",
"nav_templates": "Templates",
"nav_users": "Users",
"nav_settings": "Settings"
}
7 changes: 0 additions & 7 deletions admin/slices/common/locales/en.json

This file was deleted.

17 changes: 16 additions & 1 deletion admin/slices/llm/i18n/locales/en.json
Original file line number Diff line number Diff line change
@@ -1 +1,16 @@
{}
{
"llms": "LLMs",
"add_credential": "Add credential",
"provider": "Provider",
"model": "Model",
"label": "Label",
"api_key": "API key",
"status": "Status",
"active": "active",
"disabled": "disabled",
"save": "Save",
"cancel": "Cancel",
"delete": "Delete",
"confirm_delete": "Delete this credential?",
"empty": "No LLM credentials yet. Add one to make it available to your agents."
}
16 changes: 0 additions & 16 deletions admin/slices/llm/locales/en.json

This file was deleted.

21 changes: 0 additions & 21 deletions admin/slices/paddock/locales/en.json

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script setup lang="ts">
import type { IndexStatus } from '#reins/stores/knowledge';
import { Badge as UiBadge } from '#theme/components/ui/badge';

const props = defineProps<{ status: IndexStatus }>();

Expand Down Expand Up @@ -35,5 +36,5 @@ const variant = computed<'default' | 'secondary' | 'destructive' | 'outline'>(
</script>

<template>
<Badge :variant="variant">{{ label }}</Badge>
<UiBadge :variant="variant">{{ label }}</UiBadge>
</template>
7 changes: 1 addition & 6 deletions admin/slices/reins/i18n/locales/en.json
Original file line number Diff line number Diff line change
@@ -1,6 +1 @@
{
"reins": {
"title": "Knowledges",
"subtitle": "RAG knowledge bases backed by LightRAG"
}
}
{}
1 change: 0 additions & 1 deletion admin/slices/reins/locales/en.json

This file was deleted.

5 changes: 4 additions & 1 deletion admin/slices/setting/i18n/locales/en.json
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
{}
{
"settings": "Settings",
"resource_quotas": "Resource Quotas"
}
4 changes: 0 additions & 4 deletions admin/slices/setting/locales/en.json

This file was deleted.

4 changes: 2 additions & 2 deletions admin/slices/setup/api/plugins/apiBaseUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ export default defineNuxtPlugin({
requestConfig.baseURL = apiUrl;
}
if (typeof document === 'undefined') return requestConfig;
const match = document.cookie.match(/(?:^|;\s*)access_token=([^;]+)/);
const token = match ? decodeURIComponent(match[1]) : null;
const raw = document.cookie.match(/(?:^|;\s*)access_token=([^;]+)/)?.[1];
const token = raw ? decodeURIComponent(raw) : null;
if (token) {
requestConfig.headers.set('Authorization', `Bearer ${token}`);
}
Expand Down
6 changes: 1 addition & 5 deletions admin/slices/setup/i18n/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,8 @@ const currentDir = dirname(fileURLToPath(import.meta.url));
export default defineNuxtConfig({
modules: ['@nuxtjs/i18n'],
i18n: {
restructureDir: false,
vueI18n: resolve(currentDir, 'configs/i18n.config.ts'),
vueI18n: resolve(currentDir, 'i18n/i18n.config.ts'),
strategy: 'no_prefix',
defaultLocale: 'en',
bundle: {
optimizeTranslationDirective: false,
},
},
});
Loading
Loading