@cat-factory/app 0.147.7 → 0.148.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.
@@ -5,6 +5,7 @@ import type {
5
5
  AgentKind,
6
6
  BlockStatus,
7
7
  BlockType,
8
+ TaskTypeMeta,
8
9
  } from '~/types/domain'
9
10
 
10
11
  /** Simple unique id helper (fine for a client-only prototype). */
@@ -698,6 +699,112 @@ export function isKnownAgentKind(kind: string): boolean {
698
699
  return kind in AGENT_BY_KIND || kind in SYSTEM_AGENT_META || kind in customAgentKindMeta.value
699
700
  }
700
701
 
702
+ // ---------------------------------------------------------------------------
703
+ // Task-type presentation (frontend-extension-mechanism initiative, slice B) — the exact twin of
704
+ // the agent-kind read-model above: a frozen BUILT-IN map + a reactive CUSTOM projection fed by the
705
+ // task-types store, resolved through {@link taskTypeMeta} so the card badge + create-task picker
706
+ // render a built-in OR a deployment-registered custom type — and an UNREGISTERED namespaced type
707
+ // (stale data after an extension was removed) degrades to the `feature` presentation, never a crash.
708
+ // ---------------------------------------------------------------------------
709
+
710
+ /**
711
+ * The BUILT-IN task-type presentations, keyed by type. Icons mirror the create-task picker's old
712
+ * hardcoded list; `labelKey` is the i18n key the renderer resolves (built-in labels are localized,
713
+ * unlike a custom type's literal wire label). `recurring` is not human-creatable but is stamped on
714
+ * the reused schedule block, so it needs a badge too.
715
+ */
716
+ export const TASK_TYPE_META: Record<string, TaskTypeMeta> = {
717
+ feature: {
718
+ taskType: 'feature',
719
+ icon: 'i-lucide-sparkles',
720
+ color: '#38bdf8',
721
+ labelKey: 'board.addTask.types.feature',
722
+ },
723
+ bug: {
724
+ taskType: 'bug',
725
+ icon: 'i-lucide-bug',
726
+ color: '#f87171',
727
+ labelKey: 'board.addTask.types.bug',
728
+ },
729
+ document: {
730
+ taskType: 'document',
731
+ icon: 'i-lucide-file-text',
732
+ color: '#c084fc',
733
+ labelKey: 'board.addTask.types.document',
734
+ },
735
+ spike: {
736
+ taskType: 'spike',
737
+ icon: 'i-lucide-flask-conical',
738
+ color: '#fbbf24',
739
+ labelKey: 'board.addTask.types.spike',
740
+ },
741
+ review: {
742
+ taskType: 'review',
743
+ icon: 'i-lucide-clipboard-check',
744
+ color: '#34d399',
745
+ labelKey: 'board.addTask.types.review',
746
+ },
747
+ ralph: {
748
+ taskType: 'ralph',
749
+ icon: 'i-lucide-infinity',
750
+ color: '#a78bfa',
751
+ labelKey: 'board.addTask.types.ralph',
752
+ },
753
+ recurring: {
754
+ taskType: 'recurring',
755
+ icon: 'i-lucide-repeat',
756
+ color: '#94a3b8',
757
+ labelKey: 'board.addTask.types.recurring',
758
+ },
759
+ }
760
+
761
+ /**
762
+ * Reactive read-model of the deployment's CUSTOM task types (consumer-slot + backend
763
+ * remote-manifest), kept in sync by the task-types store — the exact twin of
764
+ * {@link customAgentKindMeta}. The store is the source of truth; this `shallowRef` is its
765
+ * synchronous projection so {@link taskTypeMeta} / {@link isKnownTaskType} resolve a custom type
766
+ * WITHOUT importing the store (circular) or mutating {@link TASK_TYPE_META}.
767
+ */
768
+ const customTaskTypeMeta = shallowRef<Record<string, TaskTypeMeta>>({})
769
+
770
+ /** Replace the custom task-type projection (called only by the task-types store). */
771
+ export function setCustomTaskTypeMeta(map: Record<string, TaskTypeMeta>): void {
772
+ customTaskTypeMeta.value = map
773
+ }
774
+
775
+ /** Test-only: clear the custom task-type projection so a spec starts from built-ins only. */
776
+ export function __resetCustomTaskTypeMetaForTest(): void {
777
+ customTaskTypeMeta.value = {}
778
+ }
779
+
780
+ /**
781
+ * Resolve display metadata for ANY task type — a BUILT-IN ({@link TASK_TYPE_META}), a deployment
782
+ * CUSTOM type (projected into {@link customTaskTypeMeta} by the task-types store), or an
783
+ * UNREGISTERED namespaced one (stale data after its extension was removed) — ALWAYS returning a
784
+ * usable icon/color/label. An unregistered/unknown type falls back to the `feature` presentation
785
+ * (its icon/color) but keeps the raw id as its literal label, so a leftover string renders a badge
786
+ * instead of breaking the card. Reading `customTaskTypeMeta` reactively means a component computed
787
+ * re-runs when the custom catalog changes.
788
+ */
789
+ export function taskTypeMeta(taskType: string | undefined): TaskTypeMeta {
790
+ if (!taskType) return TASK_TYPE_META.feature!
791
+ return (
792
+ TASK_TYPE_META[taskType] ??
793
+ customTaskTypeMeta.value[taskType] ?? {
794
+ taskType,
795
+ icon: TASK_TYPE_META.feature!.icon,
796
+ color: TASK_TYPE_META.feature!.color,
797
+ // Unregistered namespaced type: no i18n key, so show its raw id rather than a blank badge.
798
+ label: taskType,
799
+ }
800
+ )
801
+ }
802
+
803
+ /** Whether a task type is known to this build — a built-in or a projected custom type. */
804
+ export function isKnownTaskType(taskType: string): boolean {
805
+ return taskType in TASK_TYPE_META || taskType in customTaskTypeMeta.value
806
+ }
807
+
701
808
  type BlockTypeMeta = { label: string; icon: string; accent: string }
702
809
 
703
810
  /** Visual metadata for each architecture block type. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/app",
3
- "version": "0.147.7",
3
+ "version": "0.148.1",
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.40",
42
42
  "wretch": "^3.0.9",
43
- "@cat-factory/contracts": "0.154.2"
43
+ "@cat-factory/contracts": "0.156.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@toad-contracts/testing": "0.3.2",