@cat-factory/app 1.0.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 (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +88 -0
  3. package/app/app.config.ts +8 -0
  4. package/app/app.vue +11 -0
  5. package/app/assets/css/main.css +100 -0
  6. package/app/components/auth/AuthGate.vue +24 -0
  7. package/app/components/auth/LoginScreen.vue +18 -0
  8. package/app/components/auth/UserMenu.vue +39 -0
  9. package/app/components/board/AgentFailureCard.vue +97 -0
  10. package/app/components/board/AgentStopButton.vue +61 -0
  11. package/app/components/board/BoardCanvas.vue +146 -0
  12. package/app/components/board/TaskDependencyEdges.vue +132 -0
  13. package/app/components/board/nodes/AgentChip.vue +59 -0
  14. package/app/components/board/nodes/BlockNode.vue +347 -0
  15. package/app/components/board/nodes/DecisionBadge.vue +21 -0
  16. package/app/components/board/nodes/DraggableTask.vue +69 -0
  17. package/app/components/board/nodes/ModuleFrame.vue +70 -0
  18. package/app/components/board/nodes/TaskCard.vue +237 -0
  19. package/app/components/bootstrap/BootstrapModal.vue +665 -0
  20. package/app/components/documents/DocumentImportModal.vue +161 -0
  21. package/app/components/documents/DocumentSourceConnectModal.vue +127 -0
  22. package/app/components/documents/SpawnPreviewModal.vue +161 -0
  23. package/app/components/documents/TaskContextDocs.vue +83 -0
  24. package/app/components/focus/BlockFocusView.vue +161 -0
  25. package/app/components/fragments/FragmentLibraryPanel.vue +340 -0
  26. package/app/components/github/GitHubConnect.vue +183 -0
  27. package/app/components/github/GitHubPanel.vue +584 -0
  28. package/app/components/layout/BoardSwitcher.vue +202 -0
  29. package/app/components/layout/BoardToolbar.vue +109 -0
  30. package/app/components/layout/SideBar.vue +193 -0
  31. package/app/components/layout/SpendWarningBanner.vue +107 -0
  32. package/app/components/palettes/AgentPalette.vue +33 -0
  33. package/app/components/palettes/BlockPalette.vue +41 -0
  34. package/app/components/palettes/PipelinePalette.vue +74 -0
  35. package/app/components/panels/DecisionModal.vue +71 -0
  36. package/app/components/panels/InspectorPanel.vue +296 -0
  37. package/app/components/panels/inspector/ContainerSummary.vue +74 -0
  38. package/app/components/panels/inspector/TaskDependencies.vue +70 -0
  39. package/app/components/panels/inspector/TaskExecution.vue +175 -0
  40. package/app/components/panels/inspector/TaskModelSettings.vue +128 -0
  41. package/app/components/panels/inspector/TaskStructure.vue +139 -0
  42. package/app/components/pipeline/PipelineBuilder.vue +227 -0
  43. package/app/components/pipeline/PipelineProgress.vue +246 -0
  44. package/app/components/requirements/RequirementReviewModal.vue +328 -0
  45. package/app/components/scenarios/FeatureScenarios.vue +162 -0
  46. package/app/components/scenarios/ScenarioCard.vue +109 -0
  47. package/app/components/tasks/TaskContextIssues.vue +88 -0
  48. package/app/components/tasks/TaskImportModal.vue +140 -0
  49. package/app/components/tasks/TaskSourceConnectModal.vue +122 -0
  50. package/app/composables/useApi.ts +535 -0
  51. package/app/composables/useBlockDrag.ts +75 -0
  52. package/app/composables/useBlockQueries.ts +136 -0
  53. package/app/composables/useBoardFlow.ts +11 -0
  54. package/app/composables/useDepLabels.ts +26 -0
  55. package/app/composables/useSemanticZoom.ts +16 -0
  56. package/app/composables/useWorkspaceStream.ts +125 -0
  57. package/app/docs/architecture.md +31 -0
  58. package/app/pages/index.vue +80 -0
  59. package/app/stores/accounts.ts +64 -0
  60. package/app/stores/agentRuns.ts +117 -0
  61. package/app/stores/agents.ts +40 -0
  62. package/app/stores/auth.ts +97 -0
  63. package/app/stores/board.spec.ts +197 -0
  64. package/app/stores/board.ts +147 -0
  65. package/app/stores/bootstrap.ts +97 -0
  66. package/app/stores/documents.ts +165 -0
  67. package/app/stores/execution.ts +115 -0
  68. package/app/stores/fragmentLibrary.ts +147 -0
  69. package/app/stores/fragments.ts +40 -0
  70. package/app/stores/github.ts +291 -0
  71. package/app/stores/models.ts +48 -0
  72. package/app/stores/pipelines.ts +77 -0
  73. package/app/stores/requirements.ts +133 -0
  74. package/app/stores/scenarios.spec.ts +82 -0
  75. package/app/stores/scenarios.ts +196 -0
  76. package/app/stores/tasks.spec.ts +71 -0
  77. package/app/stores/tasks.ts +149 -0
  78. package/app/stores/ui.ts +204 -0
  79. package/app/stores/workspace.ts +201 -0
  80. package/app/types/accounts.ts +38 -0
  81. package/app/types/bootstrap.ts +83 -0
  82. package/app/types/documents.ts +92 -0
  83. package/app/types/domain.ts +216 -0
  84. package/app/types/execution.ts +110 -0
  85. package/app/types/fragments.ts +72 -0
  86. package/app/types/github.ts +153 -0
  87. package/app/types/models.ts +48 -0
  88. package/app/types/requirements.ts +38 -0
  89. package/app/types/scenarios.ts +36 -0
  90. package/app/types/tasks.ts +67 -0
  91. package/app/utils/catalog.spec.ts +82 -0
  92. package/app/utils/catalog.ts +185 -0
  93. package/app/utils/dnd.ts +29 -0
  94. package/nuxt.config.ts +43 -0
  95. package/package.json +43 -0
@@ -0,0 +1,185 @@
1
+ import type { AgentArchetype, AgentKind, BlockStatus, BlockType } from '~/types/domain'
2
+
3
+ /** Simple unique id helper (fine for a client-only prototype). */
4
+ export function uid(prefix = 'id'): string {
5
+ return `${prefix}_${Math.random().toString(36).slice(2, 9)}`
6
+ }
7
+
8
+ /** The agent palette — the building blocks of a development pipeline. */
9
+ export const AGENT_ARCHETYPES: AgentArchetype[] = [
10
+ {
11
+ kind: 'architect',
12
+ label: 'Architect',
13
+ icon: 'i-lucide-drafting-compass',
14
+ color: '#a78bfa',
15
+ description: 'Designs the shape of the solution and breaks down the work.',
16
+ },
17
+ {
18
+ kind: 'researcher',
19
+ label: 'Researcher',
20
+ icon: 'i-lucide-telescope',
21
+ color: '#38bdf8',
22
+ description: 'Investigates prior art, libraries and constraints.',
23
+ },
24
+ {
25
+ kind: 'coder',
26
+ label: 'Coder',
27
+ icon: 'i-lucide-code-xml',
28
+ color: '#34d399',
29
+ description: 'Implements the block according to the design.',
30
+ },
31
+ {
32
+ kind: 'tester',
33
+ label: 'Tester',
34
+ icon: 'i-lucide-flask-conical',
35
+ color: '#fbbf24',
36
+ description: 'Writes and runs tests, reports failures.',
37
+ },
38
+ {
39
+ kind: 'reviewer',
40
+ label: 'Reviewer',
41
+ icon: 'i-lucide-scan-eye',
42
+ color: '#f472b6',
43
+ description: 'Reviews the implementation for quality and correctness.',
44
+ },
45
+ {
46
+ kind: 'documenter',
47
+ label: 'Documenter',
48
+ icon: 'i-lucide-book-open-text',
49
+ color: '#818cf8',
50
+ description: 'Produces docs and usage examples.',
51
+ },
52
+ {
53
+ kind: 'integrator',
54
+ label: 'Integrator',
55
+ icon: 'i-lucide-plug-zap',
56
+ color: '#fb923c',
57
+ description: 'Wires the block into the surrounding system.',
58
+ },
59
+ {
60
+ kind: 'acceptance',
61
+ label: 'Acceptance Author',
62
+ icon: 'i-lucide-clipboard-check',
63
+ color: '#2dd4bf',
64
+ description: 'Turns requirements / PRDs into Given/When/Then acceptance scenarios.',
65
+ },
66
+ {
67
+ kind: 'playwright',
68
+ label: 'Acceptance Test Author',
69
+ icon: 'i-lucide-theater',
70
+ color: '#e879f9',
71
+ description:
72
+ "Turns scenarios into runnable tests — Playwright for frontend, the project's own framework for backend; adds only new ones.",
73
+ },
74
+ {
75
+ kind: 'mocker',
76
+ label: 'Mock Builder',
77
+ icon: 'i-lucide-server-cog',
78
+ color: '#fb7185',
79
+ description: 'Builds WireMock mocks for external services and wires them into local/CI runs.',
80
+ },
81
+ {
82
+ kind: 'business-documenter',
83
+ label: 'Domain Rules Documenter',
84
+ icon: 'i-lucide-scroll-text',
85
+ color: '#84cc16',
86
+ description:
87
+ 'Reads the implementation and writes/updates business-logic & domain-rule docs in the repo, weaving in linked context documents.',
88
+ },
89
+ {
90
+ kind: 'business-reviewer',
91
+ label: 'Domain Rules Reviewer',
92
+ icon: 'i-lucide-shield-alert',
93
+ color: '#ef4444',
94
+ description:
95
+ 'Reviews a change against the documented domain rules and reports violations, undocumented changes and unexpected drift.',
96
+ },
97
+ ]
98
+
99
+ export const AGENT_BY_KIND: Record<AgentKind, AgentArchetype> = Object.fromEntries(
100
+ AGENT_ARCHETYPES.map((a) => [a.kind, a]),
101
+ ) as Record<AgentKind, AgentArchetype>
102
+
103
+ /** Visual metadata for each architecture block type. */
104
+ export const BLOCK_TYPE_META: Record<BlockType, { label: string; icon: string; accent: string }> = {
105
+ frontend: { label: 'Frontend', icon: 'i-lucide-monitor', accent: '#60a5fa' },
106
+ service: { label: 'Service', icon: 'i-lucide-server', accent: '#a78bfa' },
107
+ api: { label: 'API', icon: 'i-lucide-route', accent: '#22d3ee' },
108
+ database: { label: 'Database', icon: 'i-lucide-database', accent: '#34d399' },
109
+ queue: { label: 'Queue', icon: 'i-lucide-list-ordered', accent: '#fbbf24' },
110
+ integration: {
111
+ label: 'Integration',
112
+ icon: 'i-lucide-workflow',
113
+ accent: '#fb923c',
114
+ },
115
+ external: { label: 'External', icon: 'i-lucide-globe', accent: '#94a3b8' },
116
+ environment: {
117
+ label: 'Environment',
118
+ icon: 'i-lucide-container',
119
+ accent: '#2dd4bf',
120
+ },
121
+ }
122
+
123
+ /** Color + iconography for each block status. */
124
+ export const STATUS_META: Record<
125
+ BlockStatus,
126
+ { label: string; color: string; chip: string; icon: string }
127
+ > = {
128
+ planned: {
129
+ label: 'Planned',
130
+ color: '#64748b',
131
+ chip: 'neutral',
132
+ icon: 'i-lucide-circle-dashed',
133
+ },
134
+ ready: {
135
+ label: 'Ready',
136
+ color: '#3b82f6',
137
+ chip: 'info',
138
+ icon: 'i-lucide-circle-play',
139
+ },
140
+ in_progress: {
141
+ label: 'In progress',
142
+ color: '#6366f1',
143
+ chip: 'primary',
144
+ icon: 'i-lucide-loader',
145
+ },
146
+ blocked: {
147
+ label: 'Decision needed',
148
+ color: '#f59e0b',
149
+ chip: 'warning',
150
+ icon: 'i-lucide-circle-help',
151
+ },
152
+ pr_ready: {
153
+ label: 'PR ready',
154
+ color: '#22c55e',
155
+ chip: 'success',
156
+ icon: 'i-lucide-git-pull-request',
157
+ },
158
+ done: {
159
+ label: 'Done',
160
+ color: '#16a34a',
161
+ chip: 'success',
162
+ icon: 'i-lucide-circle-check',
163
+ },
164
+ }
165
+
166
+ /** Default confidence threshold for a new task (auto-merge at/above this). */
167
+ export const DEFAULT_CONFIDENCE_THRESHOLD = 0.8
168
+
169
+ /** Visual metadata for module sub-frames. */
170
+ export const MODULE_META = { icon: 'i-lucide-package', color: '#a78bfa' }
171
+
172
+ /** Visual metadata for the "feature" tag tasks carry. */
173
+ export const FEATURE_META = { icon: 'i-lucide-puzzle', color: '#34d399' }
174
+
175
+ /** Sample task names used to seed / quick-add tasks inside a frame. */
176
+ export const TASK_NAME_BANK = [
177
+ 'Login endpoint',
178
+ 'Token refresh',
179
+ 'Password reset',
180
+ 'Session store',
181
+ 'Rate limiter',
182
+ 'Health checks',
183
+ 'Schema migration',
184
+ 'Error handling',
185
+ ]
@@ -0,0 +1,29 @@
1
+ import type { BlockType } from '~/types/domain'
2
+
3
+ /** MIME-ish key used to carry palette payloads across the HTML5 DnD boundary. */
4
+ export const DND_MIME = 'application/agent-board'
5
+
6
+ export type DndPayload =
7
+ | { kind: 'block'; blockType: BlockType }
8
+ | { kind: 'pipeline'; pipelineId: string }
9
+
10
+ export function setDndPayload(event: DragEvent, payload: DndPayload) {
11
+ event.dataTransfer?.setData(DND_MIME, JSON.stringify(payload))
12
+ if (event.dataTransfer) event.dataTransfer.effectAllowed = 'copy'
13
+ }
14
+
15
+ export function readDndPayload(event: DragEvent): DndPayload | null {
16
+ const raw = event.dataTransfer?.getData(DND_MIME)
17
+ if (!raw) return null
18
+ try {
19
+ return JSON.parse(raw) as DndPayload
20
+ } catch {
21
+ return null
22
+ }
23
+ }
24
+
25
+ /** Walk up from the drop target to find the block it landed on, if any. */
26
+ export function blockIdFromEvent(event: DragEvent): string | null {
27
+ const el = (event.target as HTMLElement | null)?.closest('[data-block-id]')
28
+ return el?.getAttribute('data-block-id') ?? null
29
+ }
package/nuxt.config.ts ADDED
@@ -0,0 +1,43 @@
1
+ // https://nuxt.com/docs/api/configuration/nuxt-config
2
+ import { dirname, join } from 'node:path'
3
+ import { fileURLToPath } from 'node:url'
4
+
5
+ // This is a Nuxt *layer*: a consuming app `extends` it. Config file paths must
6
+ // resolve against THIS layer's directory, not the consumer's — `~`/`@` rebind to
7
+ // the consumer's srcDir, so an asset referenced as `~/assets/...` would be looked
8
+ // up in the consumer. Use an absolute path anchored here instead.
9
+ const layerDir = dirname(fileURLToPath(import.meta.url))
10
+
11
+ export default defineNuxtConfig({
12
+ compatibilityDate: '2025-06-01',
13
+ devtools: { enabled: true },
14
+
15
+ // Render as a pure client-side SPA that talks to the cat-factory backend.
16
+ ssr: false,
17
+
18
+ runtimeConfig: {
19
+ public: {
20
+ // Base URL of the cat-factory worker API. Defaults to the local wrangler
21
+ // dev server; override per-environment with NUXT_PUBLIC_API_BASE.
22
+ apiBase: 'http://localhost:8787',
23
+ },
24
+ },
25
+
26
+ modules: ['@nuxt/ui', '@pinia/nuxt', 'pinia-plugin-persistedstate/nuxt'],
27
+
28
+ css: [
29
+ '@vue-flow/core/dist/style.css',
30
+ '@vue-flow/core/dist/theme-default.css',
31
+ '@vue-flow/controls/dist/style.css',
32
+ '@vue-flow/minimap/dist/style.css',
33
+ '@vue-flow/node-resizer/dist/style.css',
34
+ join(layerDir, 'app/assets/css/main.css'),
35
+ ],
36
+
37
+ app: {
38
+ head: {
39
+ title: 'Agent Architecture Board',
40
+ meta: [{ name: 'viewport', content: 'width=device-width, initial-scale=1' }],
41
+ },
42
+ },
43
+ })
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@cat-factory/app",
3
+ "version": "1.0.0",
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
+ "files": [
6
+ "app",
7
+ "nuxt.config.ts"
8
+ ],
9
+ "type": "module",
10
+ "main": "./nuxt.config.ts",
11
+ "publishConfig": {
12
+ "access": "public"
13
+ },
14
+ "dependencies": {
15
+ "@nuxt/ui": "^4.8.2",
16
+ "@pinia/nuxt": "^0.11.3",
17
+ "@vue-flow/background": "^1.3.2",
18
+ "@vue-flow/controls": "^1.1.3",
19
+ "@vue-flow/core": "^1.48.2",
20
+ "@vue-flow/minimap": "^1.5.4",
21
+ "@vue-flow/node-resizer": "^1.5.1",
22
+ "@vueuse/core": "^14.3.0",
23
+ "pinia": "^3.0.4",
24
+ "pinia-plugin-persistedstate": "^4.7.1",
25
+ "vue": "^3.5.38"
26
+ },
27
+ "devDependencies": {
28
+ "happy-dom": "^15.11.7",
29
+ "nuxt": "^4.4.8",
30
+ "typescript": "^6.0.3",
31
+ "vitest": "^4.1.8",
32
+ "vue-tsc": "^3.3.4"
33
+ },
34
+ "peerDependencies": {
35
+ "nuxt": "^4.4.8"
36
+ },
37
+ "scripts": {
38
+ "postinstall": "nuxt prepare",
39
+ "typecheck": "nuxt typecheck",
40
+ "test": "vitest",
41
+ "test:run": "vitest run"
42
+ }
43
+ }