hermes-web-ui 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/bin/hermes-web-ui.mjs +114 -19
  2. package/dist/assets/ChatView-DrzZz5ex.css +1 -0
  3. package/dist/assets/ChatView-WnNeYrS7.js +38 -0
  4. package/dist/assets/JobsView-BF9wWdwU.js +831 -0
  5. package/dist/assets/JobsView-BhwwXuLt.css +1 -0
  6. package/dist/assets/Modal-CQVLL_Oc.js +276 -0
  7. package/dist/assets/_plugin-vue_export-helper-D5N3Hfca.js +231 -0
  8. package/dist/assets/chat-640V6r6N.js +1 -0
  9. package/dist/assets/client-BxIiwrqC.js +1 -0
  10. package/dist/assets/index-4iFlrAYJ.js +307 -0
  11. package/dist/assets/index-CMJKLUKk.css +1 -0
  12. package/dist/assets/jobs-Cuol6Mqb.js +1 -0
  13. package/dist/assets/use-message-B8ClBznx.js +117 -0
  14. package/dist/favicon.ico +0 -0
  15. package/dist/index.html +21 -0
  16. package/package.json +3 -11
  17. package/index.html +0 -13
  18. package/src/App.vue +0 -54
  19. package/src/api/chat.ts +0 -87
  20. package/src/api/client.ts +0 -44
  21. package/src/api/jobs.ts +0 -100
  22. package/src/api/system.ts +0 -25
  23. package/src/assets/hero.png +0 -0
  24. package/src/assets/vite.svg +0 -1
  25. package/src/components/chat/ChatInput.vue +0 -123
  26. package/src/components/chat/ChatPanel.vue +0 -289
  27. package/src/components/chat/MarkdownRenderer.vue +0 -187
  28. package/src/components/chat/MessageItem.vue +0 -189
  29. package/src/components/chat/MessageList.vue +0 -94
  30. package/src/components/jobs/JobCard.vue +0 -244
  31. package/src/components/jobs/JobFormModal.vue +0 -188
  32. package/src/components/jobs/JobsPanel.vue +0 -58
  33. package/src/components/layout/AppSidebar.vue +0 -169
  34. package/src/composables/useKeyboard.ts +0 -39
  35. package/src/env.d.ts +0 -7
  36. package/src/main.ts +0 -10
  37. package/src/router/index.ts +0 -24
  38. package/src/stores/app.ts +0 -66
  39. package/src/stores/chat.ts +0 -344
  40. package/src/stores/jobs.ts +0 -72
  41. package/src/styles/global.scss +0 -60
  42. package/src/styles/theme.ts +0 -71
  43. package/src/styles/variables.scss +0 -56
  44. package/src/views/ChatView.vue +0 -25
  45. package/src/views/JobsView.vue +0 -93
  46. package/src/views/SettingsView.vue +0 -257
  47. package/tsconfig.app.json +0 -17
  48. package/tsconfig.json +0 -7
  49. package/tsconfig.node.json +0 -24
  50. package/vite.config.ts +0 -39
  51. /package/{assets/logo.png → dist/assets/logo-BAarh-tH.png} +0 -0
  52. /package/{public → dist}/favicon.svg +0 -0
  53. /package/{public → dist}/icons.svg +0 -0
@@ -1,58 +0,0 @@
1
- <script setup lang="ts">
2
- import JobCard from './JobCard.vue'
3
- import { useJobsStore } from '@/stores/jobs'
4
-
5
- const emit = defineEmits<{
6
- edit: [jobId: string]
7
- }>()
8
-
9
- const jobsStore = useJobsStore()
10
- </script>
11
-
12
- <template>
13
- <div v-if="jobsStore.jobs.length === 0" class="empty-state">
14
- <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" class="empty-icon">
15
- <rect x="3" y="4" width="18" height="18" rx="2" ry="2"/>
16
- <line x1="16" y1="2" x2="16" y2="6"/>
17
- <line x1="8" y1="2" x2="8" y2="6"/>
18
- <line x1="3" y1="10" x2="21" y2="10"/>
19
- </svg>
20
- <p>No scheduled jobs yet. Create one to get started.</p>
21
- </div>
22
- <div v-else class="jobs-grid">
23
- <JobCard
24
- v-for="job in jobsStore.jobs"
25
- :key="job.id"
26
- :job="job"
27
- @edit="emit('edit', job.id)"
28
- />
29
- </div>
30
- </template>
31
-
32
- <style scoped lang="scss">
33
- @use '@/styles/variables' as *;
34
-
35
- .empty-state {
36
- display: flex;
37
- flex-direction: column;
38
- align-items: center;
39
- justify-content: center;
40
- height: 100%;
41
- color: $text-muted;
42
- gap: 12px;
43
-
44
- .empty-icon {
45
- opacity: 0.3;
46
- }
47
-
48
- p {
49
- font-size: 14px;
50
- }
51
- }
52
-
53
- .jobs-grid {
54
- display: grid;
55
- grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
56
- gap: 14px;
57
- }
58
- </style>
@@ -1,169 +0,0 @@
1
- <script setup lang="ts">
2
- import { computed } from 'vue'
3
- import { useRoute, useRouter } from 'vue-router'
4
- import { useAppStore } from '@/stores/app'
5
-
6
- const route = useRoute()
7
- const router = useRouter()
8
- const appStore = useAppStore()
9
-
10
- const selectedKey = computed(() => route.name as string)
11
-
12
- function handleNav(key: string) {
13
- router.push({ name: key })
14
- }
15
- </script>
16
-
17
- <template>
18
- <aside class="sidebar">
19
- <div class="sidebar-logo" @click="router.push('/')">
20
- <img src="/assets/logo.png" alt="Hermes" class="logo-img" />
21
- <span class="logo-text">Hermes</span>
22
- </div>
23
-
24
- <nav class="sidebar-nav">
25
- <button
26
- class="nav-item"
27
- :class="{ active: selectedKey === 'chat' }"
28
- @click="handleNav('chat')"
29
- >
30
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
31
- <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
32
- </svg>
33
- <span>Chat</span>
34
- </button>
35
-
36
- <button
37
- class="nav-item"
38
- :class="{ active: selectedKey === 'jobs' }"
39
- @click="handleNav('jobs')"
40
- >
41
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
42
- <rect x="3" y="4" width="18" height="18" rx="2" ry="2" />
43
- <line x1="16" y1="2" x2="16" y2="6" />
44
- <line x1="8" y1="2" x2="8" y2="6" />
45
- <line x1="3" y1="10" x2="21" y2="10" />
46
- </svg>
47
- <span>Jobs</span>
48
- </button>
49
- </nav>
50
-
51
- <div class="sidebar-footer">
52
- <div class="status-indicator" :class="{ connected: appStore.connected, disconnected: !appStore.connected }">
53
- <span class="status-dot"></span>
54
- <span class="status-text">{{ appStore.connected ? 'Connected' : 'Disconnected' }}</span>
55
- </div>
56
- <div class="version-info">Hermes {{ appStore.serverVersion || 'v0.1.0' }}</div>
57
- </div>
58
- </aside>
59
- </template>
60
-
61
- <style scoped lang="scss">
62
- @use '@/styles/variables' as *;
63
-
64
- .sidebar {
65
- width: $sidebar-width;
66
- height: 100vh;
67
- background-color: $bg-sidebar;
68
- border-right: 1px solid $border-color;
69
- display: flex;
70
- flex-direction: column;
71
- padding: 20px 12px;
72
- flex-shrink: 0;
73
- transition: width $transition-normal;
74
- }
75
-
76
- .logo-img {
77
- width: 28px;
78
- height: 28px;
79
- border-radius: 50%;
80
- flex-shrink: 0;
81
- }
82
-
83
- .sidebar-logo {
84
- display: flex;
85
- align-items: center;
86
- gap: 10px;
87
- padding: 4px 12px 20px;
88
- color: $text-primary;
89
- cursor: pointer;
90
-
91
- .logo-text {
92
- font-size: 18px;
93
- font-weight: 600;
94
- letter-spacing: 0.5px;
95
- }
96
- }
97
-
98
- .sidebar-nav {
99
- flex: 1;
100
- display: flex;
101
- flex-direction: column;
102
- gap: 4px;
103
- }
104
-
105
- .nav-item {
106
- display: flex;
107
- align-items: center;
108
- gap: 10px;
109
- padding: 10px 12px;
110
- border: none;
111
- background: none;
112
- color: $text-secondary;
113
- font-size: 14px;
114
- border-radius: $radius-sm;
115
- cursor: pointer;
116
- transition: all $transition-fast;
117
- width: 100%;
118
- text-align: left;
119
-
120
- &:hover {
121
- background-color: rgba($accent-primary, 0.06);
122
- color: $text-primary;
123
- }
124
-
125
- &.active {
126
- background-color: rgba($accent-primary, 0.12);
127
- color: $accent-primary;
128
- }
129
- }
130
-
131
- .sidebar-footer {
132
- padding-top: 16px;
133
- border-top: 1px solid $border-color;
134
- }
135
-
136
- .status-indicator {
137
- display: flex;
138
- align-items: center;
139
- gap: 8px;
140
- padding: 8px 12px;
141
- font-size: 12px;
142
-
143
- .status-dot {
144
- width: 8px;
145
- height: 8px;
146
- border-radius: 50%;
147
- flex-shrink: 0;
148
- }
149
-
150
- &.connected .status-dot {
151
- background-color: $success;
152
- box-shadow: 0 0 6px rgba($success, 0.5);
153
- }
154
-
155
- &.disconnected .status-dot {
156
- background-color: $error;
157
- }
158
-
159
- .status-text {
160
- color: $text-secondary;
161
- }
162
- }
163
-
164
- .version-info {
165
- padding: 4px 12px;
166
- font-size: 11px;
167
- color: $text-muted;
168
- }
169
- </style>
@@ -1,39 +0,0 @@
1
- import { onMounted, onUnmounted } from 'vue'
2
- import { useRouter } from 'vue-router'
3
- import { useChatStore } from '@/stores/chat'
4
-
5
- export function useKeyboard() {
6
- const router = useRouter()
7
- const chatStore = useChatStore()
8
-
9
- function handleKeydown(e: KeyboardEvent) {
10
- const mod = e.ctrlKey || e.metaKey
11
-
12
- if (mod && e.key === 'n') {
13
- e.preventDefault()
14
- chatStore.newChat()
15
- }
16
-
17
- if (mod && e.key === 'j') {
18
- e.preventDefault()
19
- router.push({ name: 'jobs' })
20
- }
21
-
22
- if (e.key === 'Escape') {
23
- // Close any open modals — naive-ui handles this internally
24
- const modal = document.querySelector('.n-modal-mask')
25
- if (modal) {
26
- const closeBtn = modal.querySelector('.n-base-close') as HTMLElement
27
- closeBtn?.click()
28
- }
29
- }
30
- }
31
-
32
- onMounted(() => {
33
- window.addEventListener('keydown', handleKeydown)
34
- })
35
-
36
- onUnmounted(() => {
37
- window.removeEventListener('keydown', handleKeydown)
38
- })
39
- }
package/src/env.d.ts DELETED
@@ -1,7 +0,0 @@
1
- /// <reference types="vite/client" />
2
-
3
- declare module '*.vue' {
4
- import type { DefineComponent } from 'vue'
5
- const component: DefineComponent<{}, {}, any>
6
- export default component
7
- }
package/src/main.ts DELETED
@@ -1,10 +0,0 @@
1
- import { createApp } from 'vue'
2
- import { createPinia } from 'pinia'
3
- import router from './router'
4
- import App from './App.vue'
5
- import './styles/global.scss'
6
-
7
- const app = createApp(App)
8
- app.use(createPinia())
9
- app.use(router)
10
- app.mount('#app')
@@ -1,24 +0,0 @@
1
- import { createRouter, createWebHashHistory } from 'vue-router'
2
-
3
- const router = createRouter({
4
- history: createWebHashHistory(),
5
- routes: [
6
- {
7
- path: '/',
8
- name: 'chat',
9
- component: () => import('@/views/ChatView.vue'),
10
- },
11
- {
12
- path: '/jobs',
13
- name: 'jobs',
14
- component: () => import('@/views/JobsView.vue'),
15
- },
16
- {
17
- path: '/settings',
18
- name: 'settings',
19
- redirect: '/',
20
- },
21
- ],
22
- })
23
-
24
- export default router
package/src/stores/app.ts DELETED
@@ -1,66 +0,0 @@
1
- import { defineStore } from 'pinia'
2
- import { ref } from 'vue'
3
- import { checkHealth, fetchModels } from '@/api/system'
4
- import type { Model } from '@/api/system'
5
-
6
- export const useAppStore = defineStore('app', () => {
7
- const connected = ref(false)
8
- const serverVersion = ref('')
9
- const models = ref<Model[]>([])
10
- const healthPollTimer = ref<ReturnType<typeof setInterval>>()
11
-
12
- // Settings
13
- const streamEnabled = ref(true)
14
- const sessionPersistence = ref(true)
15
- const maxTokens = ref(4096)
16
- const selectedModel = ref('hermes-agent')
17
-
18
- async function checkConnection() {
19
- try {
20
- const res = await checkHealth()
21
- connected.value = true
22
- if (res.version) serverVersion.value = res.version
23
- } catch {
24
- connected.value = false
25
- }
26
- }
27
-
28
- async function loadModels() {
29
- try {
30
- const res = await fetchModels()
31
- models.value = res.data || []
32
- if (models.value.length > 0 && !models.value.find(m => m.id === selectedModel.value)) {
33
- selectedModel.value = models.value[0].id
34
- }
35
- } catch {
36
- // ignore
37
- }
38
- }
39
-
40
- function startHealthPolling(interval = 30000) {
41
- stopHealthPolling()
42
- checkConnection()
43
- healthPollTimer.value = setInterval(checkConnection, interval)
44
- }
45
-
46
- function stopHealthPolling() {
47
- if (healthPollTimer.value) {
48
- clearInterval(healthPollTimer.value)
49
- healthPollTimer.value = undefined
50
- }
51
- }
52
-
53
- return {
54
- connected,
55
- serverVersion,
56
- models,
57
- streamEnabled,
58
- sessionPersistence,
59
- maxTokens,
60
- selectedModel,
61
- checkConnection,
62
- loadModels,
63
- startHealthPolling,
64
- stopHealthPolling,
65
- }
66
- })