@cat-factory/app 0.273.0 → 0.273.2
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.
- package/app/components/environments/EnvironmentStatusPanel.vue +20 -5
- package/app/components/layout/AccountModelPolicySettings.vue +2 -0
- package/app/components/panels/AgentStepDetail.vue +14 -9
- package/app/components/panels/StepContainerStatus.vue +21 -2
- package/app/components/panels/StepMetadataCard.vue +8 -1
- package/app/components/providers/ApiKeysSection.vue +7 -0
- package/app/components/provisioning/ProvisioningLogsDrawer.vue +16 -10
- package/app/components/testing/TestReportWindow.vue +12 -9
- package/app/types/execution.ts +1 -0
- package/app/utils/pipelineRender.spec.ts +37 -2
- package/app/utils/pipelineRender.ts +30 -1
- package/i18n/locales/de.json +7 -1
- package/i18n/locales/en.json +7 -1
- package/i18n/locales/es.json +7 -1
- package/i18n/locales/fr.json +7 -1
- package/i18n/locales/he.json +7 -1
- package/i18n/locales/it.json +7 -1
- package/i18n/locales/ja.json +7 -1
- package/i18n/locales/pl.json +7 -1
- package/i18n/locales/tr.json +7 -1
- package/i18n/locales/uk.json +7 -1
- package/package.json +2 -2
|
@@ -6,7 +6,18 @@
|
|
|
6
6
|
import type { InfraEngine, ProvisionType } from '@cat-factory/contracts'
|
|
7
7
|
import type { RunEnvironment, HumanTestEnvironmentStatus } from '~/types/execution'
|
|
8
8
|
|
|
9
|
-
const props = defineProps<{
|
|
9
|
+
const props = defineProps<{
|
|
10
|
+
environment: RunEnvironment | null
|
|
11
|
+
/**
|
|
12
|
+
* Whether the enclosing run is still being driven (`runIsActive`). A transitional status
|
|
13
|
+
* (`provisioning` / `tearing_down`) keeps its label once the run stops, because that is the
|
|
14
|
+
* last thing the provider reported, but its icon stops spinning: nothing is standing this
|
|
15
|
+
* environment up any more. Required rather than defaulted so a new call site has to say which
|
|
16
|
+
* run it is rendering, instead of silently inheriting a perpetual spinner.
|
|
17
|
+
*/
|
|
18
|
+
runActive: boolean
|
|
19
|
+
degradedReason?: string | null
|
|
20
|
+
}>()
|
|
10
21
|
|
|
11
22
|
const { t, d } = useI18n()
|
|
12
23
|
|
|
@@ -74,6 +85,13 @@ const ENV_STATUS_META = computed<
|
|
|
74
85
|
icon: 'i-lucide-circle-off',
|
|
75
86
|
},
|
|
76
87
|
}))
|
|
88
|
+
|
|
89
|
+
// The two statuses that describe a transition IN FLIGHT. Only these ever animate, and only
|
|
90
|
+
// while the run driving the transition is still being driven itself.
|
|
91
|
+
const envInTransition = computed(
|
|
92
|
+
() =>
|
|
93
|
+
props.environment?.status === 'provisioning' || props.environment?.status === 'tearing_down',
|
|
94
|
+
)
|
|
77
95
|
</script>
|
|
78
96
|
|
|
79
97
|
<template>
|
|
@@ -88,10 +106,7 @@ const ENV_STATUS_META = computed<
|
|
|
88
106
|
class="h-3.5 w-3.5"
|
|
89
107
|
:class="[
|
|
90
108
|
ENV_STATUS_META[environment.status].color,
|
|
91
|
-
{
|
|
92
|
-
'animate-spin':
|
|
93
|
-
environment.status === 'provisioning' || environment.status === 'tearing_down',
|
|
94
|
-
},
|
|
109
|
+
{ 'animate-spin': runActive && envInTransition },
|
|
95
110
|
]"
|
|
96
111
|
/>
|
|
97
112
|
<span :class="ENV_STATUS_META[environment.status].color">{{
|
|
@@ -31,6 +31,7 @@ const FAMILIES = [
|
|
|
31
31
|
'kimi',
|
|
32
32
|
'deepseek',
|
|
33
33
|
'glm',
|
|
34
|
+
'grok',
|
|
34
35
|
] as const satisfies readonly ModelFamily[]
|
|
35
36
|
const REGIONS = ['usa', 'europe', 'china', 'other'] as const satisfies readonly AccountRegion[]
|
|
36
37
|
const MODES = ['off', 'blocklist', 'allowlist'] as const satisfies readonly ModelPolicyMode[]
|
|
@@ -47,6 +48,7 @@ const familyLabels = computed<Record<ModelFamily, string>>(() => ({
|
|
|
47
48
|
kimi: t('settings.modelPolicy.families.kimi'),
|
|
48
49
|
deepseek: t('settings.modelPolicy.families.deepseek'),
|
|
49
50
|
glm: t('settings.modelPolicy.families.glm'),
|
|
51
|
+
grok: t('settings.modelPolicy.families.grok'),
|
|
50
52
|
}))
|
|
51
53
|
const regionLabels = computed<Record<AccountRegion, string>>(() => ({
|
|
52
54
|
usa: t('settings.modelPolicy.regions.usa'),
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
REDIRECT_PARK_PRESENTATION,
|
|
26
26
|
type RedirectParkView,
|
|
27
27
|
dedicatedParkView,
|
|
28
|
+
runIsActive,
|
|
28
29
|
} from '~/utils/pipelineRender'
|
|
29
30
|
import InputGateNotice from '~/components/inputGate/InputGateNotice.vue'
|
|
30
31
|
|
|
@@ -125,13 +126,12 @@ const showHistory = ref(false)
|
|
|
125
126
|
// "spinning up" phase, no spinner.
|
|
126
127
|
const runFailed = computed(() => instance.value?.status === 'failed')
|
|
127
128
|
|
|
128
|
-
// Whether the
|
|
129
|
-
//
|
|
130
|
-
//
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
})
|
|
129
|
+
// Whether the engine is still driving this run, and so can still spin infrastructure up or down.
|
|
130
|
+
// One shared predicate drives every infra surface below: the attempts drawer's background poll
|
|
131
|
+
// (manual refresh stays available regardless), the container card's cold-boot spinner, and the
|
|
132
|
+
// environment panel's transition spinner. A run that is terminal OR parked has nothing in flight,
|
|
133
|
+
// so none of those may keep animating.
|
|
134
|
+
const runActive = computed(() => runIsActive(instance.value?.status))
|
|
135
135
|
|
|
136
136
|
// Live elapsed-time clock for the open step.
|
|
137
137
|
const { isRunning, durationLabel } = useStepTimer({
|
|
@@ -497,6 +497,7 @@ async function copyOutput() {
|
|
|
497
497
|
<StepMetadataCard
|
|
498
498
|
:step="step"
|
|
499
499
|
:run-failed="runFailed"
|
|
500
|
+
:run-active="runActive"
|
|
500
501
|
:duration-label="durationLabel"
|
|
501
502
|
:is-running="isRunning"
|
|
502
503
|
:step-number="stepNumber"
|
|
@@ -592,7 +593,11 @@ async function copyOutput() {
|
|
|
592
593
|
|
|
593
594
|
<!-- ephemeral environment lifecycle (spinning up / running / shut down /
|
|
594
595
|
errored + the exact error), when this step runs against one -->
|
|
595
|
-
<EnvironmentStatusPanel
|
|
596
|
+
<EnvironmentStatusPanel
|
|
597
|
+
v-if="stepEnvironment"
|
|
598
|
+
:environment="stepEnvironment"
|
|
599
|
+
:run-active="runActive"
|
|
600
|
+
/>
|
|
596
601
|
|
|
597
602
|
<!-- frontend UI-test: how the frame's backend bindings resolved (env var →
|
|
598
603
|
live URL | mocked) + the run-start advisories (duplicate env vars /
|
|
@@ -639,7 +644,7 @@ async function copyOutput() {
|
|
|
639
644
|
v-if="showProvisioning"
|
|
640
645
|
class="mt-2"
|
|
641
646
|
:execution-id="executionId"
|
|
642
|
-
:live="
|
|
647
|
+
:live="runActive"
|
|
643
648
|
/>
|
|
644
649
|
</div>
|
|
645
650
|
|
|
@@ -8,7 +8,18 @@ import { containerPhaseLabel } from '~/utils/pipelineRender'
|
|
|
8
8
|
// making calls), and the container's id + reachable URL once up. Shared by the generic
|
|
9
9
|
// step detail (StepMetadataCard) and the dedicated Tester window so both surface WHAT the
|
|
10
10
|
// container is doing and WHERE it lives instead of a bare "working" — identical parity.
|
|
11
|
-
const props = defineProps<{
|
|
11
|
+
const props = defineProps<{
|
|
12
|
+
step: PipelineStep
|
|
13
|
+
runFailed: boolean
|
|
14
|
+
/**
|
|
15
|
+
* Whether the enclosing run is still being driven (`runIsActive`). Distinct from
|
|
16
|
+
* {@link runFailed}, which answers whether the container was RECLAIMED: a run parked on a
|
|
17
|
+
* human decision or a spend budget has reclaimed nothing, so its container keeps whatever
|
|
18
|
+
* status it stopped at. A `starting` one is no longer cold-booting, though, so it must not
|
|
19
|
+
* keep spinning as though it were.
|
|
20
|
+
*/
|
|
21
|
+
runActive: boolean
|
|
22
|
+
}>()
|
|
12
23
|
|
|
13
24
|
const { t, te } = useI18n()
|
|
14
25
|
|
|
@@ -59,6 +70,14 @@ const CONTAINER_STATUS_META: Record<
|
|
|
59
70
|
},
|
|
60
71
|
}
|
|
61
72
|
|
|
73
|
+
// Whether the status icon animates: only a cold-boot genuinely in flight, i.e. one whose run is
|
|
74
|
+
// still being driven. A `starting` container on a parked or terminated run keeps its label and
|
|
75
|
+
// freezes, the same way a mid-flight subtask item does (`subtaskIconClass`).
|
|
76
|
+
const spinIcon = computed(
|
|
77
|
+
() =>
|
|
78
|
+
props.runActive && !!containerStatus.value && CONTAINER_STATUS_META[containerStatus.value].spin,
|
|
79
|
+
)
|
|
80
|
+
|
|
62
81
|
// The friendly phase label (clone → "Preparing workspace", …); only meaningful while up.
|
|
63
82
|
const phaseLabel = computed(() => containerPhaseLabel(props.step.container?.phase, { t, te }))
|
|
64
83
|
|
|
@@ -82,7 +101,7 @@ const { copy: copyText } = useCopyToClipboard()
|
|
|
82
101
|
<UIcon
|
|
83
102
|
:name="CONTAINER_STATUS_META[containerStatus].icon"
|
|
84
103
|
class="h-4 w-4 shrink-0"
|
|
85
|
-
:class="
|
|
104
|
+
:class="spinIcon ? 'animate-spin' : ''"
|
|
86
105
|
/>
|
|
87
106
|
<span class="font-medium">{{ t(CONTAINER_STATUS_KEYS[containerStatus]) }}</span>
|
|
88
107
|
<template v-if="phaseLabel && containerStatus === 'up'">
|
|
@@ -20,6 +20,8 @@ import MarkdownProse from '~/components/common/MarkdownProse.vue'
|
|
|
20
20
|
const props = defineProps<{
|
|
21
21
|
step: PipelineStep
|
|
22
22
|
runFailed: boolean
|
|
23
|
+
/** Whether the run is still being driven; passed through so its container card can freeze. */
|
|
24
|
+
runActive: boolean
|
|
23
25
|
durationLabel: string | null
|
|
24
26
|
isRunning: boolean
|
|
25
27
|
stepNumber: number
|
|
@@ -246,7 +248,12 @@ async function copyRunId() {
|
|
|
246
248
|
|
|
247
249
|
<!-- container lifecycle (status / live phase / id + url) — shared with the Tester
|
|
248
250
|
window so both surface what the container is doing and where it lives. -->
|
|
249
|
-
<StepContainerStatus
|
|
251
|
+
<StepContainerStatus
|
|
252
|
+
:step="step"
|
|
253
|
+
:run-failed="runFailed"
|
|
254
|
+
:run-active="runActive"
|
|
255
|
+
class="mt-4"
|
|
256
|
+
/>
|
|
250
257
|
|
|
251
258
|
<!-- live subtask breakdown -->
|
|
252
259
|
<div v-if="step.subtasks && step.subtasks.total > 0" class="mt-4">
|
|
@@ -110,6 +110,13 @@ const DIRECT_PROVIDERS = computed<ProviderMeta[]>(() => [
|
|
|
110
110
|
t('providers.apiKeys.providers.moonshot.step2'),
|
|
111
111
|
],
|
|
112
112
|
},
|
|
113
|
+
{
|
|
114
|
+
value: 'xai',
|
|
115
|
+
label: t('providers.apiKeys.providers.xai.label'),
|
|
116
|
+
url: 'https://console.x.ai/',
|
|
117
|
+
steps: [t('providers.apiKeys.providers.xai.step1'), t('providers.apiKeys.providers.xai.step2')],
|
|
118
|
+
caches: true,
|
|
119
|
+
},
|
|
113
120
|
])
|
|
114
121
|
|
|
115
122
|
/** Proxies / gateways: one key fronts many vendors. These are intermediaries, not vendors. */
|
|
@@ -6,13 +6,16 @@
|
|
|
6
6
|
// panels' drawer, or `executionId` for a run's "Infrastructure attempts" drawer (which
|
|
7
7
|
// surfaces that run's container/runner/env attempts).
|
|
8
8
|
//
|
|
9
|
-
// In `executionId` mode the drawer LIVE-tracks: while the
|
|
10
|
-
// silently re-polls so each container spin-up / tear-down appears with
|
|
11
|
-
// it happens, and it does one final poll when the run
|
|
12
|
-
// tear-down row (written just before the terminal event), after which the
|
|
13
|
-
// stops.
|
|
14
|
-
//
|
|
15
|
-
//
|
|
9
|
+
// In `executionId` mode the drawer LIVE-tracks: while the engine is driving the run (`live`,
|
|
10
|
+
// from `runIsActive`) it silently re-polls so each container spin-up / tear-down appears with
|
|
11
|
+
// its timestamp as it happens, and it does one final poll when the run stops being driven, to
|
|
12
|
+
// catch the last tear-down row (written just before the terminal event), after which the
|
|
13
|
+
// auto-poll stops. "Stops being driven" covers a PARK as well as a terminal state: a run waiting
|
|
14
|
+
// on a human decision or a raised spend budget writes no further attempts until it resumes, and
|
|
15
|
+
// the same watch restarts the poll when it does. Background polls never spin the refresh button
|
|
16
|
+
// (they're silent), but the manual refresh control stays available even once the run is terminal,
|
|
17
|
+
// so a tear-down row that was missed or not yet persisted at the terminal instant can always be
|
|
18
|
+
// refetched.
|
|
16
19
|
import { onBeforeUnmount, onMounted, watch } from 'vue'
|
|
17
20
|
import type {
|
|
18
21
|
ProvisioningOperation,
|
|
@@ -23,7 +26,10 @@ import type {
|
|
|
23
26
|
const props = defineProps<{
|
|
24
27
|
subsystem?: ProvisioningSubsystem
|
|
25
28
|
executionId?: string
|
|
26
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* Run-details mode only: whether the engine is still driving the run (`runIsActive`), which
|
|
31
|
+
* drives the background poll. A terminal OR parked run writes no further attempts.
|
|
32
|
+
*/
|
|
27
33
|
live?: boolean
|
|
28
34
|
}>()
|
|
29
35
|
|
|
@@ -68,8 +74,8 @@ watch(
|
|
|
68
74
|
// clears, `live` and `executionId` fall away in the same tick, so stop the interval
|
|
69
75
|
// unconditionally or it leaks (firing no-op reloads) for the component's lifetime.
|
|
70
76
|
stopPolling()
|
|
71
|
-
// On the active→
|
|
72
|
-
// tear-down row the engine writes just before it emits
|
|
77
|
+
// On the active→stopped transition (parked or terminal), poll once more (silently) to pick
|
|
78
|
+
// up the tear-down row the engine writes just before it emits that state.
|
|
73
79
|
if (wasLive && props.executionId != null) reload(true)
|
|
74
80
|
},
|
|
75
81
|
{ immediate: true },
|
|
@@ -21,6 +21,7 @@ import AttemptEntryHeader from '~/components/panels/AttemptEntryHeader.vue'
|
|
|
21
21
|
import EnvironmentStatusPanel from '~/components/environments/EnvironmentStatusPanel.vue'
|
|
22
22
|
import ProvisioningLogsDrawer from '~/components/provisioning/ProvisioningLogsDrawer.vue'
|
|
23
23
|
import MarkdownProse from '~/components/common/MarkdownProse.vue'
|
|
24
|
+
import { runIsActive } from '~/utils/pipelineRender'
|
|
24
25
|
|
|
25
26
|
const board = useBoardStore()
|
|
26
27
|
const execution = useExecutionStore()
|
|
@@ -65,12 +66,10 @@ const qualityVerdicts = computed(() => [...(quality.value?.verdicts ?? [])].reve
|
|
|
65
66
|
// run's infrastructure attempts + logs (container/runner/env spin-up), not just the
|
|
66
67
|
// report. The container/subtask signals already flow onto the step via the generic poll.
|
|
67
68
|
const runFailed = computed(() => instance.value?.status === 'failed')
|
|
68
|
-
// A terminal
|
|
69
|
-
// background
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return status != null && status !== 'done' && status !== 'failed'
|
|
73
|
-
})
|
|
69
|
+
// Whether the engine is still driving this run. A run that is terminal OR parked can't spin more
|
|
70
|
+
// infra, so the attempts drawer stops its background poll (manual refresh stays available) and
|
|
71
|
+
// neither the container card nor the environment panel keeps animating over it.
|
|
72
|
+
const runActive = computed(() => runIsActive(instance.value?.status))
|
|
74
73
|
const stepEnvironment = computed(() => step.value?.environment ?? null)
|
|
75
74
|
const executionId = computed(() => instance.value?.id ?? null)
|
|
76
75
|
// The infra-attempts log drawer is opened on demand (it fetches the per-run log rows).
|
|
@@ -355,8 +354,12 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
355
354
|
<h3 class="text-[11px] font-semibold uppercase tracking-wide text-slate-500">
|
|
356
355
|
{{ t('testing.infrastructure') }}
|
|
357
356
|
</h3>
|
|
358
|
-
<StepContainerStatus :step="step" :run-failed="runFailed" />
|
|
359
|
-
<EnvironmentStatusPanel
|
|
357
|
+
<StepContainerStatus :step="step" :run-failed="runFailed" :run-active="runActive" />
|
|
358
|
+
<EnvironmentStatusPanel
|
|
359
|
+
v-if="stepEnvironment"
|
|
360
|
+
:environment="stepEnvironment"
|
|
361
|
+
:run-active="runActive"
|
|
362
|
+
/>
|
|
360
363
|
|
|
361
364
|
<!-- In-container docker-compose dependency stand-up (local-infra tester): the
|
|
362
365
|
outcome + the captured `docker compose up` logs. This is the stand-up that
|
|
@@ -459,7 +462,7 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
459
462
|
v-if="showProvisioning"
|
|
460
463
|
class="mt-2"
|
|
461
464
|
:execution-id="executionId"
|
|
462
|
-
:live="
|
|
465
|
+
:live="runActive"
|
|
463
466
|
/>
|
|
464
467
|
</div>
|
|
465
468
|
</section>
|
package/app/types/execution.ts
CHANGED
|
@@ -115,6 +115,7 @@ export type {
|
|
|
115
115
|
VisualConfirmDesignReferences,
|
|
116
116
|
VisualConfirmRound,
|
|
117
117
|
ExecutionInstance,
|
|
118
|
+
ExecutionStatus,
|
|
118
119
|
// The historical frontend name for a per-block review comment is the contract's
|
|
119
120
|
// StepReviewComment; the env-status union is the contract's EnvironmentStatus.
|
|
120
121
|
StepReviewComment as ReviewComment,
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
binaryCandidateStatusSchema,
|
|
4
|
+
executionStatusSchema,
|
|
5
|
+
stepSkipReasonSchema,
|
|
6
|
+
} from '@cat-factory/contracts'
|
|
3
7
|
import type { ExecutionInstance, PipelineStep } from '~/types/execution'
|
|
4
8
|
import { missingI18nKeys } from '../../test/i18nKeys'
|
|
5
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
REDIRECT_PARK_PRESENTATION,
|
|
11
|
+
dedicatedParkView,
|
|
12
|
+
runIsActive,
|
|
13
|
+
stepSkipReasonKey,
|
|
14
|
+
} from './pipelineRender'
|
|
6
15
|
|
|
7
16
|
/** A minimal coder step; the predicate only reads approval/followUps/forkDecision. */
|
|
8
17
|
const step = (over: Partial<PipelineStep>): PipelineStep =>
|
|
@@ -229,3 +238,29 @@ describe('stepSkipReasonKey', () => {
|
|
|
229
238
|
expect(missingI18nKeys([...keys, 'pipeline.progress.skipped.unknown'])).toEqual([])
|
|
230
239
|
})
|
|
231
240
|
})
|
|
241
|
+
|
|
242
|
+
describe('runIsActive', () => {
|
|
243
|
+
it('answers true for exactly the one status the engine is driving under', () => {
|
|
244
|
+
// Derived from the vocabulary the engine writes, not a hand-listed set: a status added to the
|
|
245
|
+
// picklist fails here until someone decides whether infrastructure can move under it. That
|
|
246
|
+
// decision is what every animated infra indicator is gated on, so defaulting a new member
|
|
247
|
+
// either way silently is the failure this pins.
|
|
248
|
+
expect(executionStatusSchema.options.filter(runIsActive)).toEqual(['running'])
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
it('treats a PARK as inactive, not only a terminal state', () => {
|
|
252
|
+
// The distinction that makes this more than `status !== 'done' && status !== 'failed'`: a run
|
|
253
|
+
// waiting on a human decision (`blocked`) or on a raised spend budget (`paused`) is asleep in
|
|
254
|
+
// the durable driver. Nothing is cold-booting or being torn down under it, so a container left
|
|
255
|
+
// `starting` or an environment left `provisioning` must stop claiming otherwise.
|
|
256
|
+
expect(runIsActive('blocked')).toBe(false)
|
|
257
|
+
expect(runIsActive('paused')).toBe(false)
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
it('answers false when the run has no status to read', () => {
|
|
261
|
+
// The overlays render before/after their run resolves, and an unknown run is not a running
|
|
262
|
+
// one: the indicator must start still and begin turning once the run says it is being driven.
|
|
263
|
+
expect(runIsActive(null)).toBe(false)
|
|
264
|
+
expect(runIsActive(undefined)).toBe(false)
|
|
265
|
+
})
|
|
266
|
+
})
|
|
@@ -2,9 +2,38 @@
|
|
|
2
2
|
// TaskPipelineMini, AgentStepDetail), so the "is this step still live?" logic stays
|
|
3
3
|
// in one place rather than being re-derived as inline ternaries per component.
|
|
4
4
|
|
|
5
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
AgentState,
|
|
7
|
+
ExecutionInstance,
|
|
8
|
+
ExecutionStatus,
|
|
9
|
+
PipelineStep,
|
|
10
|
+
} from '~/types/execution'
|
|
6
11
|
import { isStepSkipReason } from '@cat-factory/contracts'
|
|
7
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Whether the engine is presently DRIVING this run, which is the one condition under which
|
|
15
|
+
* infrastructure can still be moving (a container cold-booting, an environment coming up or
|
|
16
|
+
* being torn down, a fresh provisioning attempt landing in the log).
|
|
17
|
+
*
|
|
18
|
+
* `running` is that condition and nothing else is. `done`/`failed` are terminal, and the other
|
|
19
|
+
* two are parks where the durable driver is asleep on an event: `blocked` waits on a human
|
|
20
|
+
* decision, `paused` on a spend budget that has to be raised. A parked run holds whatever infra
|
|
21
|
+
* state it stopped at, so nothing about it is in flight.
|
|
22
|
+
*
|
|
23
|
+
* This is what every ANIMATED infra indicator is gated on. A spinner is a claim that something is
|
|
24
|
+
* happening right now, so a container left `starting` or an environment left `provisioning` when
|
|
25
|
+
* its run stopped must keep its label (that IS the last thing the provider reported) and stop
|
|
26
|
+
* turning: the run's own status says why it stopped, and a perpetual spinner over a run nobody is
|
|
27
|
+
* driving reads as a live cold-boot that is simply taking a while. The same rule governs the
|
|
28
|
+
* infra-attempts drawer's background poll, which has nothing to re-read off a parked run.
|
|
29
|
+
*
|
|
30
|
+
* The step-level sibling is `stepIsRunning` (`useStepTimer`), which answers the narrower question
|
|
31
|
+
* of whether one step's clock should tick; this one is about the run as a whole.
|
|
32
|
+
*/
|
|
33
|
+
export function runIsActive(status: ExecutionStatus | null | undefined): boolean {
|
|
34
|
+
return status === 'running'
|
|
35
|
+
}
|
|
36
|
+
|
|
8
37
|
/**
|
|
9
38
|
* Visual state of a conditionally-run companion attached to a gate step (today the
|
|
10
39
|
* Tester's `fixer`): it MIGHT run (`possible`), is running now (`running`), ran at
|
package/i18n/locales/de.json
CHANGED
|
@@ -1240,7 +1240,8 @@
|
|
|
1240
1240
|
"qwen": "Qwen (Alibaba)",
|
|
1241
1241
|
"kimi": "Kimi (Moonshot)",
|
|
1242
1242
|
"deepseek": "DeepSeek",
|
|
1243
|
-
"glm": "GLM (Z.ai)"
|
|
1243
|
+
"glm": "GLM (Z.ai)",
|
|
1244
|
+
"grok": "Grok (xAI)"
|
|
1244
1245
|
},
|
|
1245
1246
|
"regions": {
|
|
1246
1247
|
"usa": "Vereinigte Staaten",
|
|
@@ -3394,6 +3395,11 @@
|
|
|
3394
3395
|
"step1": "Öffnen Sie platform.moonshot.ai → API Keys und erstellen Sie einen Schlüssel.",
|
|
3395
3396
|
"step2": "Kopieren Sie den Schlüssel; er authentifiziert den OpenAI-kompatiblen Moonshot-Endpunkt."
|
|
3396
3397
|
},
|
|
3398
|
+
"xai": {
|
|
3399
|
+
"label": "xAI (Grok API)",
|
|
3400
|
+
"step1": "Öffnen Sie console.x.ai → API Keys und erstellen Sie einen Schlüssel.",
|
|
3401
|
+
"step2": "Kopieren Sie den Schlüssel; er authentifiziert den OpenAI-kompatiblen xAI-Endpunkt."
|
|
3402
|
+
},
|
|
3397
3403
|
"openrouter": {
|
|
3398
3404
|
"label": "OpenRouter",
|
|
3399
3405
|
"step1": "Öffnen Sie openrouter.ai → Keys und erstellen Sie einen API-Schlüssel.",
|
package/i18n/locales/en.json
CHANGED
|
@@ -4001,7 +4001,8 @@
|
|
|
4001
4001
|
"qwen": "Qwen (Alibaba)",
|
|
4002
4002
|
"kimi": "Kimi (Moonshot)",
|
|
4003
4003
|
"deepseek": "DeepSeek",
|
|
4004
|
-
"glm": "GLM (Z.ai)"
|
|
4004
|
+
"glm": "GLM (Z.ai)",
|
|
4005
|
+
"grok": "Grok (xAI)"
|
|
4005
4006
|
},
|
|
4006
4007
|
"regions": {
|
|
4007
4008
|
"usa": "United States",
|
|
@@ -4280,6 +4281,11 @@
|
|
|
4280
4281
|
"step1": "Open platform.moonshot.ai → API Keys and create a key.",
|
|
4281
4282
|
"step2": "Copy the key; it authenticates the OpenAI-compatible Moonshot endpoint."
|
|
4282
4283
|
},
|
|
4284
|
+
"xai": {
|
|
4285
|
+
"label": "xAI (Grok API)",
|
|
4286
|
+
"step1": "Open console.x.ai → API Keys and create a key.",
|
|
4287
|
+
"step2": "Copy the key; it authenticates the OpenAI-compatible xAI endpoint."
|
|
4288
|
+
},
|
|
4283
4289
|
"openrouter": {
|
|
4284
4290
|
"label": "OpenRouter",
|
|
4285
4291
|
"step1": "Open openrouter.ai → Keys and create an API key.",
|
package/i18n/locales/es.json
CHANGED
|
@@ -3861,7 +3861,8 @@
|
|
|
3861
3861
|
"qwen": "Qwen (Alibaba)",
|
|
3862
3862
|
"kimi": "Kimi (Moonshot)",
|
|
3863
3863
|
"deepseek": "DeepSeek",
|
|
3864
|
-
"glm": "GLM (Z.ai)"
|
|
3864
|
+
"glm": "GLM (Z.ai)",
|
|
3865
|
+
"grok": "Grok (xAI)"
|
|
3865
3866
|
},
|
|
3866
3867
|
"regions": {
|
|
3867
3868
|
"usa": "Estados Unidos",
|
|
@@ -4137,6 +4138,11 @@
|
|
|
4137
4138
|
"step1": "Abre platform.moonshot.ai → API Keys y crea una clave.",
|
|
4138
4139
|
"step2": "Copia la clave; autentica el endpoint de Moonshot compatible con OpenAI."
|
|
4139
4140
|
},
|
|
4141
|
+
"xai": {
|
|
4142
|
+
"label": "xAI (API de Grok)",
|
|
4143
|
+
"step1": "Abre console.x.ai → API Keys y crea una clave.",
|
|
4144
|
+
"step2": "Copia la clave; autentica el endpoint de xAI compatible con OpenAI."
|
|
4145
|
+
},
|
|
4140
4146
|
"openrouter": {
|
|
4141
4147
|
"label": "OpenRouter",
|
|
4142
4148
|
"step1": "Abre openrouter.ai → Keys y crea una clave de API.",
|
package/i18n/locales/fr.json
CHANGED
|
@@ -3861,7 +3861,8 @@
|
|
|
3861
3861
|
"qwen": "Qwen (Alibaba)",
|
|
3862
3862
|
"kimi": "Kimi (Moonshot)",
|
|
3863
3863
|
"deepseek": "DeepSeek",
|
|
3864
|
-
"glm": "GLM (Z.ai)"
|
|
3864
|
+
"glm": "GLM (Z.ai)",
|
|
3865
|
+
"grok": "Grok (xAI)"
|
|
3865
3866
|
},
|
|
3866
3867
|
"regions": {
|
|
3867
3868
|
"usa": "États-Unis",
|
|
@@ -4137,6 +4138,11 @@
|
|
|
4137
4138
|
"step1": "Ouvrez platform.moonshot.ai → API Keys et créez une clé.",
|
|
4138
4139
|
"step2": "Copiez la clé ; elle authentifie l'endpoint Moonshot compatible OpenAI."
|
|
4139
4140
|
},
|
|
4141
|
+
"xai": {
|
|
4142
|
+
"label": "xAI (API Grok)",
|
|
4143
|
+
"step1": "Ouvrez console.x.ai → API Keys et créez une clé.",
|
|
4144
|
+
"step2": "Copiez la clé ; elle authentifie l'endpoint xAI compatible OpenAI."
|
|
4145
|
+
},
|
|
4140
4146
|
"openrouter": {
|
|
4141
4147
|
"label": "OpenRouter",
|
|
4142
4148
|
"step1": "Ouvrez openrouter.ai → Keys et créez une clé d'API.",
|
package/i18n/locales/he.json
CHANGED
|
@@ -3861,7 +3861,8 @@
|
|
|
3861
3861
|
"qwen": "Qwen (Alibaba)",
|
|
3862
3862
|
"kimi": "Kimi (Moonshot)",
|
|
3863
3863
|
"deepseek": "DeepSeek",
|
|
3864
|
-
"glm": "GLM (Z.ai)"
|
|
3864
|
+
"glm": "GLM (Z.ai)",
|
|
3865
|
+
"grok": "Grok (xAI)"
|
|
3865
3866
|
},
|
|
3866
3867
|
"regions": {
|
|
3867
3868
|
"usa": "ארצות הברית",
|
|
@@ -4137,6 +4138,11 @@
|
|
|
4137
4138
|
"step1": "פתח את platform.moonshot.ai → API Keys וצור מפתח.",
|
|
4138
4139
|
"step2": "העתק את המפתח; הוא מאמת את נקודת הקצה של Moonshot התואמת ל-OpenAI."
|
|
4139
4140
|
},
|
|
4141
|
+
"xai": {
|
|
4142
|
+
"label": "xAI (Grok API)",
|
|
4143
|
+
"step1": "פתח את console.x.ai → API Keys וצור מפתח.",
|
|
4144
|
+
"step2": "העתק את המפתח; הוא מאמת את נקודת הקצה של xAI התואמת ל-OpenAI."
|
|
4145
|
+
},
|
|
4140
4146
|
"openrouter": {
|
|
4141
4147
|
"label": "OpenRouter",
|
|
4142
4148
|
"step1": "פתח את openrouter.ai → Keys וצור מפתח API.",
|
package/i18n/locales/it.json
CHANGED
|
@@ -1240,7 +1240,8 @@
|
|
|
1240
1240
|
"qwen": "Qwen (Alibaba)",
|
|
1241
1241
|
"kimi": "Kimi (Moonshot)",
|
|
1242
1242
|
"deepseek": "DeepSeek",
|
|
1243
|
-
"glm": "GLM (Z.ai)"
|
|
1243
|
+
"glm": "GLM (Z.ai)",
|
|
1244
|
+
"grok": "Grok (xAI)"
|
|
1244
1245
|
},
|
|
1245
1246
|
"regions": {
|
|
1246
1247
|
"usa": "Stati Uniti",
|
|
@@ -3394,6 +3395,11 @@
|
|
|
3394
3395
|
"step1": "Apri platform.moonshot.ai → API Keys e crea una chiave.",
|
|
3395
3396
|
"step2": "Copia la chiave; autentica l'endpoint Moonshot compatibile con OpenAI."
|
|
3396
3397
|
},
|
|
3398
|
+
"xai": {
|
|
3399
|
+
"label": "xAI (Grok API)",
|
|
3400
|
+
"step1": "Apri console.x.ai → API Keys e crea una chiave.",
|
|
3401
|
+
"step2": "Copia la chiave; autentica l'endpoint xAI compatibile con OpenAI."
|
|
3402
|
+
},
|
|
3397
3403
|
"openrouter": {
|
|
3398
3404
|
"label": "OpenRouter",
|
|
3399
3405
|
"step1": "Apri openrouter.ai → Keys e crea una chiave API.",
|
package/i18n/locales/ja.json
CHANGED
|
@@ -3861,7 +3861,8 @@
|
|
|
3861
3861
|
"qwen": "Qwen (Alibaba)",
|
|
3862
3862
|
"kimi": "Kimi (Moonshot)",
|
|
3863
3863
|
"deepseek": "DeepSeek",
|
|
3864
|
-
"glm": "GLM (Z.ai)"
|
|
3864
|
+
"glm": "GLM (Z.ai)",
|
|
3865
|
+
"grok": "Grok (xAI)"
|
|
3865
3866
|
},
|
|
3866
3867
|
"regions": {
|
|
3867
3868
|
"usa": "アメリカ合衆国",
|
|
@@ -4137,6 +4138,11 @@
|
|
|
4137
4138
|
"step1": "platform.moonshot.ai → API Keys を開き、キーを作成します。",
|
|
4138
4139
|
"step2": "キーをコピーします。OpenAI 互換の Moonshot エンドポイントを認証します。"
|
|
4139
4140
|
},
|
|
4141
|
+
"xai": {
|
|
4142
|
+
"label": "xAI (Grok API)",
|
|
4143
|
+
"step1": "console.x.ai → API Keys を開き、キーを作成します。",
|
|
4144
|
+
"step2": "キーをコピーします。OpenAI 互換の xAI エンドポイントを認証します。"
|
|
4145
|
+
},
|
|
4140
4146
|
"openrouter": {
|
|
4141
4147
|
"label": "OpenRouter",
|
|
4142
4148
|
"step1": "openrouter.ai → Keys を開き、API キーを作成します。",
|
package/i18n/locales/pl.json
CHANGED
|
@@ -3861,7 +3861,8 @@
|
|
|
3861
3861
|
"qwen": "Qwen (Alibaba)",
|
|
3862
3862
|
"kimi": "Kimi (Moonshot)",
|
|
3863
3863
|
"deepseek": "DeepSeek",
|
|
3864
|
-
"glm": "GLM (Z.ai)"
|
|
3864
|
+
"glm": "GLM (Z.ai)",
|
|
3865
|
+
"grok": "Grok (xAI)"
|
|
3865
3866
|
},
|
|
3866
3867
|
"regions": {
|
|
3867
3868
|
"usa": "Stany Zjednoczone",
|
|
@@ -4137,6 +4138,11 @@
|
|
|
4137
4138
|
"step1": "Otwórz platform.moonshot.ai → API Keys i utwórz klucz.",
|
|
4138
4139
|
"step2": "Skopiuj klucz; uwierzytelnia on zgodny z OpenAI endpoint Moonshot."
|
|
4139
4140
|
},
|
|
4141
|
+
"xai": {
|
|
4142
|
+
"label": "xAI (API Grok)",
|
|
4143
|
+
"step1": "Otwórz console.x.ai → API Keys i utwórz klucz.",
|
|
4144
|
+
"step2": "Skopiuj klucz; uwierzytelnia on zgodny z OpenAI endpoint xAI."
|
|
4145
|
+
},
|
|
4140
4146
|
"openrouter": {
|
|
4141
4147
|
"label": "OpenRouter",
|
|
4142
4148
|
"step1": "Otwórz openrouter.ai → Keys i utwórz klucz API.",
|
package/i18n/locales/tr.json
CHANGED
|
@@ -3861,7 +3861,8 @@
|
|
|
3861
3861
|
"qwen": "Qwen (Alibaba)",
|
|
3862
3862
|
"kimi": "Kimi (Moonshot)",
|
|
3863
3863
|
"deepseek": "DeepSeek",
|
|
3864
|
-
"glm": "GLM (Z.ai)"
|
|
3864
|
+
"glm": "GLM (Z.ai)",
|
|
3865
|
+
"grok": "Grok (xAI)"
|
|
3865
3866
|
},
|
|
3866
3867
|
"regions": {
|
|
3867
3868
|
"usa": "Amerika Birleşik Devletleri",
|
|
@@ -4137,6 +4138,11 @@
|
|
|
4137
4138
|
"step1": "platform.moonshot.ai → API Keys adresini açın ve bir anahtar oluşturun.",
|
|
4138
4139
|
"step2": "Anahtarı kopyalayın; OpenAI uyumlu Moonshot uç noktasının kimliğini doğrular."
|
|
4139
4140
|
},
|
|
4141
|
+
"xai": {
|
|
4142
|
+
"label": "xAI (Grok API)",
|
|
4143
|
+
"step1": "console.x.ai → API Keys adresini açın ve bir anahtar oluşturun.",
|
|
4144
|
+
"step2": "Anahtarı kopyalayın; OpenAI uyumlu xAI uç noktasının kimliğini doğrular."
|
|
4145
|
+
},
|
|
4140
4146
|
"openrouter": {
|
|
4141
4147
|
"label": "OpenRouter",
|
|
4142
4148
|
"step1": "openrouter.ai → Keys adresini açın ve bir API anahtarı oluşturun.",
|
package/i18n/locales/uk.json
CHANGED
|
@@ -3861,7 +3861,8 @@
|
|
|
3861
3861
|
"qwen": "Qwen (Alibaba)",
|
|
3862
3862
|
"kimi": "Kimi (Moonshot)",
|
|
3863
3863
|
"deepseek": "DeepSeek",
|
|
3864
|
-
"glm": "GLM (Z.ai)"
|
|
3864
|
+
"glm": "GLM (Z.ai)",
|
|
3865
|
+
"grok": "Grok (xAI)"
|
|
3865
3866
|
},
|
|
3866
3867
|
"regions": {
|
|
3867
3868
|
"usa": "Сполучені Штати",
|
|
@@ -4137,6 +4138,11 @@
|
|
|
4137
4138
|
"step1": "Відкрийте platform.moonshot.ai → API Keys і створіть ключ.",
|
|
4138
4139
|
"step2": "Скопіюйте ключ; він автентифікує сумісний з OpenAI endpoint Moonshot."
|
|
4139
4140
|
},
|
|
4141
|
+
"xai": {
|
|
4142
|
+
"label": "xAI (API Grok)",
|
|
4143
|
+
"step1": "Відкрийте console.x.ai → API Keys і створіть ключ.",
|
|
4144
|
+
"step2": "Скопіюйте ключ; він автентифікує сумісний з OpenAI endpoint xAI."
|
|
4145
|
+
},
|
|
4140
4146
|
"openrouter": {
|
|
4141
4147
|
"label": "OpenRouter",
|
|
4142
4148
|
"step1": "Відкрийте openrouter.ai → Keys і створіть ключ API.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/app",
|
|
3
|
-
"version": "0.273.
|
|
3
|
+
"version": "0.273.2",
|
|
4
4
|
"description": "Reusable Nuxt layer for the Agent Architecture Board SPA (components, stores, composables, pages). Consume it from a thin deployment app via `extends: ['@cat-factory/app']` and point it at your backend with NUXT_PUBLIC_API_BASE. See deploy/frontend for an example.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"valibot": "^1.4.2",
|
|
41
41
|
"vue": "3.5.41",
|
|
42
42
|
"wretch": "^3.0.9",
|
|
43
|
-
"@cat-factory/contracts": "0.
|
|
43
|
+
"@cat-factory/contracts": "0.313.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@toad-contracts/testing": "0.3.2",
|