@cat-factory/app 0.44.0 → 0.45.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.
@@ -11,7 +11,8 @@
11
11
  // button is disabled with a hint. Linking needs the block id,
12
12
  // so chosen items are staged locally and import-and-linked once the task is created
13
13
  // (see useContextLinking) — the same context the agents see for every step of the run.
14
- import type { CreateTaskType, TaskSourceKind, TaskTypeFields } from '~/types/domain'
14
+ import type { CreateTaskType, DocKind, TaskSourceKind, TaskTypeFields } from '~/types/domain'
15
+ import { DOC_KINDS } from '~/types/domain'
15
16
  import ContextDocumentPicker from '~/components/documents/ContextDocumentPicker.vue'
16
17
  import ContextIssuePicker from '~/components/tasks/ContextIssuePicker.vue'
17
18
  import { mergePresetOptionLabel, mergePresetThresholds } from '~/utils/mergePreset'
@@ -64,9 +65,13 @@ const isRecurring = computed(() => taskType.value === 'recurring')
64
65
  const severity = ref<'low' | 'medium' | 'high' | 'critical' | ''>('')
65
66
  const stepsToReproduce = ref('')
66
67
  const timeboxHours = ref<number | undefined>(undefined)
67
- const docKind = ref<'prd' | 'rfc' | 'runbook' | 'reference' | 'other' | ''>('')
68
+ // `DOC_KINDS` (and the `DocKind` type) are owned by the contracts package re-exported via
69
+ // `~/types/domain` — so the picker and the create payload can't drift from the backend list.
70
+ const docKind = ref<DocKind | ''>('')
71
+ const docAudience = ref('')
72
+ const docTargetPath = ref('')
73
+ const docOutlineHints = ref('')
68
74
  const SEVERITIES = ['low', 'medium', 'high', 'critical'] as const
69
- const DOC_KINDS = ['prd', 'rfc', 'runbook', 'reference', 'other'] as const
70
75
 
71
76
  function buildTypeFields(): TaskTypeFields | undefined {
72
77
  if (taskType.value === 'bug') {
@@ -85,7 +90,12 @@ function buildTypeFields(): TaskTypeFields | undefined {
85
90
  : undefined
86
91
  }
87
92
  if (taskType.value === 'document') {
88
- return docKind.value ? { docKind: docKind.value } : undefined
93
+ const f: TaskTypeFields = {}
94
+ if (docKind.value) f.docKind = docKind.value
95
+ if (docAudience.value.trim()) f.audience = docAudience.value.trim()
96
+ if (docTargetPath.value.trim()) f.targetPath = docTargetPath.value.trim()
97
+ if (docOutlineHints.value.trim()) f.outlineHints = docOutlineHints.value.trim()
98
+ return Object.keys(f).length ? f : undefined
89
99
  }
90
100
  return undefined
91
101
  }
@@ -284,6 +294,9 @@ watch(open, (isOpen) => {
284
294
  stepsToReproduce.value = ''
285
295
  timeboxHours.value = undefined
286
296
  docKind.value = ''
297
+ docAudience.value = ''
298
+ docTargetPath.value = ''
299
+ docOutlineHints.value = ''
287
300
  mergePresetId.value = ''
288
301
  modelPresetId.value = ''
289
302
  pipelineId.value = ''
@@ -505,21 +518,47 @@ async function add() {
505
518
  />
506
519
  </UFormField>
507
520
 
508
- <UFormField v-else-if="taskType === 'document'" label="Document kind">
509
- <div class="flex flex-wrap gap-1">
510
- <UButton
511
- v-for="k in DOC_KINDS"
512
- :key="k"
513
- :color="docKind === k ? 'primary' : 'neutral'"
514
- :variant="docKind === k ? 'soft' : 'ghost'"
515
- size="xs"
516
- class="uppercase"
517
- @click="docKind = docKind === k ? '' : k"
518
- >
519
- {{ k }}
520
- </UButton>
521
+ <div v-else-if="taskType === 'document'" class="space-y-3">
522
+ <UFormField label="Document kind">
523
+ <div class="flex flex-wrap gap-1">
524
+ <UButton
525
+ v-for="k in DOC_KINDS"
526
+ :key="k"
527
+ :color="docKind === k ? 'primary' : 'neutral'"
528
+ :variant="docKind === k ? 'soft' : 'ghost'"
529
+ size="xs"
530
+ class="uppercase"
531
+ @click="docKind = docKind === k ? '' : k"
532
+ >
533
+ {{ k }}
534
+ </UButton>
535
+ </div>
536
+ </UFormField>
537
+ <div class="grid grid-cols-2 gap-3">
538
+ <UFormField label="Audience" hint="optional">
539
+ <UInput
540
+ v-model="docAudience"
541
+ placeholder="e.g. platform engineers"
542
+ class="w-full"
543
+ />
544
+ </UFormField>
545
+ <UFormField label="Target path" hint="optional">
546
+ <UInput
547
+ v-model="docTargetPath"
548
+ placeholder="e.g. docs/rfcs/0001-foo.md"
549
+ class="w-full"
550
+ />
551
+ </UFormField>
521
552
  </div>
522
- </UFormField>
553
+ <UFormField label="Outline hints" hint="optional">
554
+ <UTextarea
555
+ v-model="docOutlineHints"
556
+ :rows="2"
557
+ placeholder="Sections or points the document should cover"
558
+ class="w-full"
559
+ />
560
+ </UFormField>
561
+ </div>
523
562
 
524
563
  <div class="grid grid-cols-2 gap-3">
525
564
  <UFormField label="Pipeline">
@@ -22,6 +22,7 @@ export type {
22
22
  TaskType,
23
23
  CreateTaskType,
24
24
  TaskTypeFields,
25
+ DocKind,
25
26
  Block,
26
27
  PullRequestRef,
27
28
  CloudProvider,
@@ -53,6 +54,10 @@ export type {
53
54
 
54
55
  import type { AgentCategory, AgentKind } from '@cat-factory/contracts'
55
56
 
57
+ // The document-kind list is a runtime value (used to render the picker), so it is re-exported
58
+ // as a value — the single source of truth lives in the contracts package.
59
+ export { DOC_KINDS } from '@cat-factory/contracts'
60
+
56
61
  /** A draggable agent definition shown in the agent palette. Frontend-only. */
57
62
  export interface AgentArchetype {
58
63
  kind: AgentKind
@@ -28,6 +28,7 @@ const AGENT_KINDS: AgentKind[] = [
28
28
  'integrator',
29
29
  'architect-companion',
30
30
  'spec-companion',
31
+ 'doc-reviewer',
31
32
  'playwright',
32
33
  'mocker',
33
34
  'business-documenter',
@@ -251,6 +251,14 @@ export const COMPANION_ARCHETYPES: AgentArchetype[] = [
251
251
  description:
252
252
  'Reviews the spec — especially acceptance-scenario coverage — rating it and looping the Spec Writer back for automatic rework below the threshold, instead of requiring a human review.',
253
253
  },
254
+ {
255
+ kind: 'doc-reviewer',
256
+ label: 'Doc Reviewer',
257
+ icon: 'i-lucide-file-search',
258
+ color: '#818cf8',
259
+ description:
260
+ 'Reviews the drafted document for completeness, clarity, accuracy and structure, looping the Doc Writer back for automatic rework below the threshold.',
261
+ },
254
262
  ]
255
263
 
256
264
  /**
@@ -262,6 +270,7 @@ export const COMPANION_FOR_PRODUCER: Record<string, AgentKind> = {
262
270
  coder: 'reviewer',
263
271
  architect: 'architect-companion',
264
272
  'spec-writer': 'spec-companion',
273
+ 'doc-writer': 'doc-reviewer',
265
274
  }
266
275
 
267
276
  const COMPANION_KINDS: ReadonlySet<string> = new Set(COMPANION_ARCHETYPES.map((a) => a.kind))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/app",
3
- "version": "0.44.0",
3
+ "version": "0.45.0",
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",
@@ -34,7 +34,7 @@
34
34
  "pinia-plugin-persistedstate": "^4.7.1",
35
35
  "vue": "^3.5.38",
36
36
  "wretch": "^3.0.9",
37
- "@cat-factory/contracts": "0.41.0"
37
+ "@cat-factory/contracts": "0.42.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@toad-contracts/testing": "0.3.1",