@cat-factory/app 0.49.2 → 0.50.1

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.
@@ -1,195 +0,0 @@
1
- <script setup lang="ts">
2
- // Local-mode-only settings: the warm-container pool + per-repo checkout reuse. These are
3
- // a per-DEPLOYMENT singleton stored in the DB (they replaced the LOCAL_POOL_* / HARNESS_*
4
- // env vars), so a developer tunes them here instead of editing .env. The warm pool keeps
5
- // idle harness containers ready and re-leases one (preferring repo affinity) to each run —
6
- // far faster startup than a cold container per run. Saving applies the new sizing to the
7
- // running service immediately (the pool is resized live — no restart needed); in-flight
8
- // runs keep the container they already hold, and the checkout config applies to containers
9
- // started after the save.
10
- import { reactive, ref, watch } from 'vue'
11
-
12
- const { t } = useI18n()
13
- const ui = useUiStore()
14
- const store = useLocalSettingsStore()
15
- const toast = useToast()
16
-
17
- const open = computed({
18
- get: () => ui.localModeSettingsOpen,
19
- set: (v: boolean) => (v ? ui.openLocalModeSettings() : ui.closeLocalModeSettings()),
20
- })
21
-
22
- const saving = ref(false)
23
-
24
- // Editable draft. `idleMinutes` and `cleanKeep` are friendlier renderings of the stored
25
- // `pool.idleTtlMs` (ms) and `checkout.cleanKeep` (string[]).
26
- const draft = reactive({
27
- size: 0,
28
- minWarm: 0,
29
- max: null as number | null,
30
- idleMinutes: 10,
31
- workspaceRoot: '/workspace',
32
- cleanKeep: 'node_modules,.venv,target,.gradle,.pnpm-store',
33
- })
34
-
35
- function syncDraft() {
36
- const s = store.settings
37
- if (!s) return
38
- draft.size = s.pool.size
39
- draft.minWarm = s.pool.minWarm
40
- draft.max = s.pool.max
41
- draft.idleMinutes = Math.round(s.pool.idleTtlMs / 60_000)
42
- draft.workspaceRoot = s.checkout.workspaceRoot
43
- draft.cleanKeep = s.checkout.cleanKeep.join(',')
44
- }
45
-
46
- // Load + hydrate the draft whenever the panel opens.
47
- watch(
48
- open,
49
- (isOpen) => {
50
- if (isOpen) void store.load().then(syncDraft)
51
- },
52
- { immediate: true },
53
- )
54
- watch(() => store.settings, syncDraft)
55
-
56
- async function save() {
57
- const cleanKeep = draft.cleanKeep
58
- .split(',')
59
- .map((s) => s.trim())
60
- .filter(Boolean)
61
- saving.value = true
62
- try {
63
- await store.save({
64
- pool: {
65
- size: Math.max(0, Math.floor(draft.size)),
66
- minWarm: Math.max(0, Math.floor(draft.minWarm)),
67
- max: draft.max == null ? null : Math.max(0, Math.floor(draft.max)),
68
- idleTtlMs: Math.max(0, Math.floor(draft.idleMinutes * 60_000)),
69
- },
70
- checkout: { workspaceRoot: draft.workspaceRoot.trim() || '/workspace', cleanKeep },
71
- })
72
- toast.add({
73
- title: t('settings.localMode.toast.saved'),
74
- icon: 'i-lucide-check',
75
- color: 'success',
76
- })
77
- } catch (e) {
78
- toast.add({
79
- title: t('settings.localMode.toast.saveFailed'),
80
- description: e instanceof Error ? e.message : String(e),
81
- icon: 'i-lucide-triangle-alert',
82
- color: 'error',
83
- })
84
- } finally {
85
- saving.value = false
86
- }
87
- }
88
- </script>
89
-
90
- <template>
91
- <UModal v-model:open="open" :title="t('settings.localMode.title')" :ui="{ content: 'max-w-2xl' }">
92
- <template #body>
93
- <div class="space-y-6">
94
- <i18n-t
95
- keypath="settings.localMode.intro"
96
- tag="p"
97
- class="text-xs text-slate-400"
98
- scope="global"
99
- >
100
- <template #poolVars>
101
- <code>LOCAL_POOL_*</code>
102
- </template>
103
- <template #harnessVars>
104
- <code>HARNESS_*</code>
105
- </template>
106
- </i18n-t>
107
-
108
- <!-- Warm container pool -->
109
- <section class="space-y-3">
110
- <div>
111
- <h4 class="text-sm font-semibold text-slate-200">
112
- {{ t('settings.localMode.pool.heading') }}
113
- </h4>
114
- <i18n-t
115
- keypath="settings.localMode.pool.description"
116
- tag="p"
117
- class="text-[11px] text-slate-400"
118
- scope="global"
119
- >
120
- <template #appleContainer>
121
- <code>container</code>
122
- </template>
123
- </i18n-t>
124
- </div>
125
- <div class="grid grid-cols-1 gap-3 sm:grid-cols-2">
126
- <UFormField
127
- :label="t('settings.localMode.pool.size.label')"
128
- :help="t('settings.localMode.pool.size.help')"
129
- >
130
- <UInput v-model.number="draft.size" type="number" :min="0" size="sm" />
131
- </UFormField>
132
- <UFormField
133
- :label="t('settings.localMode.pool.minWarm.label')"
134
- :help="t('settings.localMode.pool.minWarm.help')"
135
- >
136
- <UInput v-model.number="draft.minWarm" type="number" :min="0" size="sm" />
137
- </UFormField>
138
- <UFormField
139
- :label="t('settings.localMode.pool.max.label')"
140
- :help="t('settings.localMode.pool.max.help')"
141
- >
142
- <UInput
143
- v-model.number="draft.max"
144
- type="number"
145
- :min="0"
146
- size="sm"
147
- :placeholder="t('settings.localMode.pool.max.placeholder')"
148
- />
149
- </UFormField>
150
- <UFormField
151
- :label="t('settings.localMode.pool.idleTimeout.label')"
152
- :help="t('settings.localMode.pool.idleTimeout.help')"
153
- >
154
- <UInput v-model.number="draft.idleMinutes" type="number" :min="0" size="sm" />
155
- </UFormField>
156
- </div>
157
- </section>
158
-
159
- <!-- Checkout reuse -->
160
- <section class="space-y-3 border-t border-slate-800 pt-6">
161
- <div>
162
- <h4 class="text-sm font-semibold text-slate-200">
163
- {{ t('settings.localMode.checkout.heading') }}
164
- </h4>
165
- <p class="text-[11px] text-slate-400">
166
- {{ t('settings.localMode.checkout.description') }}
167
- </p>
168
- </div>
169
- <UFormField
170
- :label="t('settings.localMode.checkout.workspaceRoot.label')"
171
- :help="t('settings.localMode.checkout.workspaceRoot.help')"
172
- >
173
- <UInput v-model="draft.workspaceRoot" size="sm" placeholder="/workspace" />
174
- </UFormField>
175
- <UFormField
176
- :label="t('settings.localMode.checkout.cleanKeep.label')"
177
- :help="t('settings.localMode.checkout.cleanKeep.help')"
178
- >
179
- <UInput
180
- v-model="draft.cleanKeep"
181
- size="sm"
182
- placeholder="node_modules,.venv,target,.gradle,.pnpm-store"
183
- />
184
- </UFormField>
185
- </section>
186
-
187
- <div class="flex justify-end">
188
- <UButton color="primary" icon="i-lucide-save" :loading="saving" @click="save">
189
- {{ t('common.save') }}
190
- </UButton>
191
- </div>
192
- </div>
193
- </template>
194
- </UModal>
195
- </template>