@thxgg/steward 0.1.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 (154) hide show
  1. package/.env.example +7 -0
  2. package/LICENSE +21 -0
  3. package/README.md +175 -0
  4. package/app/app.vue +14 -0
  5. package/app/assets/css/main.css +129 -0
  6. package/app/components/CommandPalette.vue +182 -0
  7. package/app/components/ShortcutsHelp.vue +85 -0
  8. package/app/components/git/ChangesMinimap.vue +143 -0
  9. package/app/components/git/CommitList.vue +224 -0
  10. package/app/components/git/DiffPanel.vue +402 -0
  11. package/app/components/git/DiffViewer.vue +803 -0
  12. package/app/components/layout/RepoSelector.vue +358 -0
  13. package/app/components/layout/Sidebar.vue +91 -0
  14. package/app/components/prd/Meta.vue +69 -0
  15. package/app/components/prd/Viewer.vue +285 -0
  16. package/app/components/tasks/Board.vue +86 -0
  17. package/app/components/tasks/Card.vue +108 -0
  18. package/app/components/tasks/Column.vue +108 -0
  19. package/app/components/tasks/Detail.vue +291 -0
  20. package/app/components/ui/badge/Badge.vue +26 -0
  21. package/app/components/ui/badge/index.ts +26 -0
  22. package/app/components/ui/button/Button.vue +29 -0
  23. package/app/components/ui/button/index.ts +38 -0
  24. package/app/components/ui/card/Card.vue +22 -0
  25. package/app/components/ui/card/CardAction.vue +17 -0
  26. package/app/components/ui/card/CardContent.vue +17 -0
  27. package/app/components/ui/card/CardDescription.vue +17 -0
  28. package/app/components/ui/card/CardFooter.vue +17 -0
  29. package/app/components/ui/card/CardHeader.vue +17 -0
  30. package/app/components/ui/card/CardTitle.vue +17 -0
  31. package/app/components/ui/card/index.ts +7 -0
  32. package/app/components/ui/combobox/Combobox.vue +19 -0
  33. package/app/components/ui/combobox/ComboboxAnchor.vue +23 -0
  34. package/app/components/ui/combobox/ComboboxEmpty.vue +21 -0
  35. package/app/components/ui/combobox/ComboboxGroup.vue +27 -0
  36. package/app/components/ui/combobox/ComboboxInput.vue +42 -0
  37. package/app/components/ui/combobox/ComboboxItem.vue +24 -0
  38. package/app/components/ui/combobox/ComboboxItemIndicator.vue +23 -0
  39. package/app/components/ui/combobox/ComboboxList.vue +33 -0
  40. package/app/components/ui/combobox/ComboboxSeparator.vue +21 -0
  41. package/app/components/ui/combobox/ComboboxTrigger.vue +24 -0
  42. package/app/components/ui/combobox/ComboboxViewport.vue +23 -0
  43. package/app/components/ui/combobox/index.ts +13 -0
  44. package/app/components/ui/command/Command.vue +103 -0
  45. package/app/components/ui/command/CommandDialog.vue +33 -0
  46. package/app/components/ui/command/CommandEmpty.vue +27 -0
  47. package/app/components/ui/command/CommandGroup.vue +45 -0
  48. package/app/components/ui/command/CommandInput.vue +54 -0
  49. package/app/components/ui/command/CommandItem.vue +76 -0
  50. package/app/components/ui/command/CommandList.vue +25 -0
  51. package/app/components/ui/command/CommandSeparator.vue +21 -0
  52. package/app/components/ui/command/CommandShortcut.vue +17 -0
  53. package/app/components/ui/command/index.ts +25 -0
  54. package/app/components/ui/dialog/Dialog.vue +19 -0
  55. package/app/components/ui/dialog/DialogClose.vue +15 -0
  56. package/app/components/ui/dialog/DialogContent.vue +53 -0
  57. package/app/components/ui/dialog/DialogDescription.vue +23 -0
  58. package/app/components/ui/dialog/DialogFooter.vue +15 -0
  59. package/app/components/ui/dialog/DialogHeader.vue +17 -0
  60. package/app/components/ui/dialog/DialogOverlay.vue +21 -0
  61. package/app/components/ui/dialog/DialogScrollContent.vue +59 -0
  62. package/app/components/ui/dialog/DialogTitle.vue +23 -0
  63. package/app/components/ui/dialog/DialogTrigger.vue +15 -0
  64. package/app/components/ui/dialog/index.ts +10 -0
  65. package/app/components/ui/input/Input.vue +33 -0
  66. package/app/components/ui/input/index.ts +1 -0
  67. package/app/components/ui/scroll-area/ScrollArea.vue +33 -0
  68. package/app/components/ui/scroll-area/ScrollBar.vue +32 -0
  69. package/app/components/ui/scroll-area/index.ts +2 -0
  70. package/app/components/ui/separator/Separator.vue +29 -0
  71. package/app/components/ui/separator/index.ts +1 -0
  72. package/app/components/ui/sheet/Sheet.vue +19 -0
  73. package/app/components/ui/sheet/SheetClose.vue +15 -0
  74. package/app/components/ui/sheet/SheetContent.vue +62 -0
  75. package/app/components/ui/sheet/SheetDescription.vue +21 -0
  76. package/app/components/ui/sheet/SheetFooter.vue +16 -0
  77. package/app/components/ui/sheet/SheetHeader.vue +15 -0
  78. package/app/components/ui/sheet/SheetOverlay.vue +21 -0
  79. package/app/components/ui/sheet/SheetTitle.vue +21 -0
  80. package/app/components/ui/sheet/SheetTrigger.vue +15 -0
  81. package/app/components/ui/sheet/index.ts +8 -0
  82. package/app/components/ui/tabs/Tabs.vue +24 -0
  83. package/app/components/ui/tabs/TabsContent.vue +21 -0
  84. package/app/components/ui/tabs/TabsList.vue +24 -0
  85. package/app/components/ui/tabs/TabsTrigger.vue +26 -0
  86. package/app/components/ui/tabs/index.ts +4 -0
  87. package/app/components/ui/tooltip/Tooltip.vue +19 -0
  88. package/app/components/ui/tooltip/TooltipContent.vue +34 -0
  89. package/app/components/ui/tooltip/TooltipProvider.vue +14 -0
  90. package/app/components/ui/tooltip/TooltipTrigger.vue +15 -0
  91. package/app/components/ui/tooltip/index.ts +4 -0
  92. package/app/composables/useFileWatch.ts +78 -0
  93. package/app/composables/useGit.ts +180 -0
  94. package/app/composables/useKeyboard.ts +180 -0
  95. package/app/composables/usePrd.ts +86 -0
  96. package/app/composables/useRepos.ts +108 -0
  97. package/app/composables/useThemeMode.ts +38 -0
  98. package/app/composables/useToast.ts +31 -0
  99. package/app/layouts/default.vue +197 -0
  100. package/app/lib/utils.ts +7 -0
  101. package/app/pages/[repo]/[prd].vue +263 -0
  102. package/app/pages/index.vue +257 -0
  103. package/app/types/git.ts +81 -0
  104. package/app/types/index.ts +29 -0
  105. package/app/types/prd.ts +49 -0
  106. package/app/types/repo.ts +37 -0
  107. package/app/types/task.ts +134 -0
  108. package/bin/prd +21 -0
  109. package/components.json +21 -0
  110. package/dist/app/types/git.js +1 -0
  111. package/dist/app/types/prd.js +1 -0
  112. package/dist/app/types/repo.js +1 -0
  113. package/dist/app/types/task.js +1 -0
  114. package/dist/host/src/api/git.js +96 -0
  115. package/dist/host/src/api/index.js +4 -0
  116. package/dist/host/src/api/prds.js +195 -0
  117. package/dist/host/src/api/repos.js +47 -0
  118. package/dist/host/src/api/state.js +63 -0
  119. package/dist/host/src/executor.js +109 -0
  120. package/dist/host/src/index.js +95 -0
  121. package/dist/host/src/mcp.js +62 -0
  122. package/dist/host/src/ui.js +64 -0
  123. package/dist/server/utils/db.js +125 -0
  124. package/dist/server/utils/git.js +396 -0
  125. package/dist/server/utils/prd-state.js +229 -0
  126. package/dist/server/utils/repos.js +256 -0
  127. package/docs/MCP.md +180 -0
  128. package/nuxt.config.ts +34 -0
  129. package/package.json +88 -0
  130. package/public/favicon.ico +0 -0
  131. package/public/robots.txt +1 -0
  132. package/server/api/browse.get.ts +52 -0
  133. package/server/api/repos/[repoId]/git/commits.get.ts +103 -0
  134. package/server/api/repos/[repoId]/git/diff.get.ts +77 -0
  135. package/server/api/repos/[repoId]/git/file-content.get.ts +66 -0
  136. package/server/api/repos/[repoId]/git/file-diff.get.ts +109 -0
  137. package/server/api/repos/[repoId]/prd/[prdSlug]/progress.get.ts +36 -0
  138. package/server/api/repos/[repoId]/prd/[prdSlug]/tasks/[taskId]/commits.get.ts +146 -0
  139. package/server/api/repos/[repoId]/prd/[prdSlug]/tasks.get.ts +36 -0
  140. package/server/api/repos/[repoId]/prd/[prdSlug].get.ts +97 -0
  141. package/server/api/repos/[repoId]/prds.get.ts +85 -0
  142. package/server/api/repos/[repoId]/refresh-git-repos.post.ts +42 -0
  143. package/server/api/repos/[repoId].delete.ts +27 -0
  144. package/server/api/repos/index.get.ts +5 -0
  145. package/server/api/repos/index.post.ts +39 -0
  146. package/server/api/watch.get.ts +63 -0
  147. package/server/plugins/migrate-legacy-state.ts +19 -0
  148. package/server/tsconfig.json +3 -0
  149. package/server/utils/db.ts +169 -0
  150. package/server/utils/git.ts +478 -0
  151. package/server/utils/prd-state.ts +335 -0
  152. package/server/utils/repos.ts +322 -0
  153. package/server/utils/watcher.ts +179 -0
  154. package/tsconfig.json +4 -0
@@ -0,0 +1,257 @@
1
+ <script setup lang="ts">
2
+ import { FolderOpen, FileText, ArrowRight, Folder } from 'lucide-vue-next'
3
+ import { Button } from '~/components/ui/button'
4
+ import { Input } from '~/components/ui/input'
5
+
6
+ const router = useRouter()
7
+ const { repos, currentRepo, currentRepoId, addRepo, status: reposStatus } = useRepos()
8
+ const { prds, prdsStatus } = usePrd()
9
+ const { showSuccess } = useToast()
10
+
11
+ // Onboarding state
12
+ const newRepoPath = ref('')
13
+ const addError = ref<string | null>(null)
14
+ const isAdding = ref(false)
15
+
16
+ // Directory browser state (reused from RepoSelector pattern)
17
+ const showBrowser = ref(false)
18
+ const browserPath = ref('')
19
+ const browserDirs = ref<{ name: string; path: string }[]>([])
20
+ const browserLoading = ref(false)
21
+
22
+ async function browseDirectory(path?: string) {
23
+ browserLoading.value = true
24
+ try {
25
+ const data = await $fetch('/api/browse', {
26
+ query: { path: path || browserPath.value || undefined }
27
+ })
28
+ browserPath.value = data.current
29
+ browserDirs.value = data.directories
30
+ } catch {
31
+ // Silently fail - directory browser will show empty state
32
+ } finally {
33
+ browserLoading.value = false
34
+ }
35
+ }
36
+
37
+ function openBrowser() {
38
+ showBrowser.value = true
39
+ browseDirectory(newRepoPath.value || undefined)
40
+ }
41
+
42
+ function selectDirectory(path: string) {
43
+ newRepoPath.value = path
44
+ showBrowser.value = false
45
+ addError.value = null
46
+ }
47
+
48
+ function navigateUp() {
49
+ const parent = browserPath.value.split('/').slice(0, -1).join('/') || '/'
50
+ browseDirectory(parent)
51
+ }
52
+
53
+ async function handleAddRepo() {
54
+ if (!newRepoPath.value.trim()) {
55
+ addError.value = 'Please enter a repository path'
56
+ return
57
+ }
58
+
59
+ isAdding.value = true
60
+ addError.value = null
61
+
62
+ try {
63
+ const repo = await addRepo(newRepoPath.value.trim())
64
+ newRepoPath.value = ''
65
+ showSuccess('Repository added', repo?.name || 'Successfully added repository')
66
+ } catch (error) {
67
+ if (error instanceof Error) {
68
+ const fetchError = error as { data?: { message?: string } }
69
+ addError.value = fetchError.data?.message || error.message
70
+ } else {
71
+ addError.value = 'Failed to add repository'
72
+ }
73
+ } finally {
74
+ isAdding.value = false
75
+ }
76
+ }
77
+
78
+ // Determine what state we're in
79
+ const showOnboarding = computed(() => {
80
+ return reposStatus.value !== 'pending' && (!repos.value || repos.value.length === 0)
81
+ })
82
+
83
+ const showSelectPrompt = computed(() => {
84
+ return repos.value && repos.value.length > 0 && !currentRepoId.value
85
+ })
86
+
87
+ const showWelcome = computed(() => {
88
+ return currentRepoId.value && (!prds.value || prds.value.length === 0)
89
+ })
90
+
91
+ const showPrdList = computed(() => {
92
+ return currentRepoId.value && prds.value && prds.value.length > 0
93
+ })
94
+
95
+ // Auto-navigate to first PRD when repo is selected and has documents
96
+ watch(
97
+ [currentRepoId, prds, prdsStatus],
98
+ ([repoId, prdList, status]) => {
99
+ const firstPrd = prdList?.[0]
100
+ if (repoId && status === 'success' && firstPrd) {
101
+ router.push(`/${repoId}/${firstPrd.slug}`)
102
+ }
103
+ },
104
+ { immediate: true }
105
+ )
106
+ </script>
107
+
108
+ <template>
109
+ <div class="flex h-full items-center justify-center p-6 md:p-8">
110
+ <!-- Onboarding: No repos configured -->
111
+ <div v-if="showOnboarding" class="mx-auto max-w-md text-center">
112
+ <div class="mx-auto mb-6 flex size-16 items-center justify-center rounded-full bg-primary/10">
113
+ <FolderOpen class="size-8 text-primary" />
114
+ </div>
115
+ <h2 class="text-2xl font-semibold tracking-tight">
116
+ Welcome to PRD Viewer
117
+ </h2>
118
+ <p class="mt-2 text-muted-foreground">
119
+ Add a repository to get started. The repository should contain PRD documents in a <code class="rounded bg-muted px-1.5 py-0.5 text-sm">docs/prd/</code> directory.
120
+ </p>
121
+
122
+ <form class="mt-6 space-y-4 text-left" @submit.prevent="handleAddRepo">
123
+ <div class="space-y-2">
124
+ <label for="repo-path" class="text-sm font-medium">
125
+ Repository Path
126
+ </label>
127
+ <div class="flex gap-2">
128
+ <Input
129
+ id="repo-path"
130
+ v-model="newRepoPath"
131
+ placeholder="/path/to/your/project"
132
+ :disabled="isAdding"
133
+ class="flex-1"
134
+ />
135
+ <Button
136
+ type="button"
137
+ variant="outline"
138
+ size="icon"
139
+ :disabled="isAdding"
140
+ @click="openBrowser"
141
+ >
142
+ <Folder class="size-4" />
143
+ </Button>
144
+ </div>
145
+ <p v-if="addError" class="text-sm text-destructive">
146
+ {{ addError }}
147
+ </p>
148
+ </div>
149
+
150
+ <!-- Directory Browser -->
151
+ <div v-if="showBrowser" class="space-y-2 rounded-md border p-3">
152
+ <div class="flex items-center gap-2 text-sm">
153
+ <button
154
+ type="button"
155
+ class="hover:text-foreground text-muted-foreground"
156
+ :disabled="browserPath === '/'"
157
+ @click="navigateUp"
158
+ >
159
+ ..
160
+ </button>
161
+ <span class="flex-1 truncate font-mono text-xs text-muted-foreground">
162
+ {{ browserPath }}
163
+ </span>
164
+ <Button
165
+ type="button"
166
+ variant="ghost"
167
+ size="sm"
168
+ class="h-7 text-xs"
169
+ @click="selectDirectory(browserPath)"
170
+ >
171
+ Select
172
+ </Button>
173
+ </div>
174
+ <div class="max-h-[200px] overflow-y-auto">
175
+ <div v-if="browserLoading" class="py-2 text-center text-sm text-muted-foreground">
176
+ Loading...
177
+ </div>
178
+ <div v-else-if="!browserDirs.length" class="py-2 text-center text-sm text-muted-foreground">
179
+ No subdirectories
180
+ </div>
181
+ <button
182
+ v-for="dir in browserDirs"
183
+ v-else
184
+ :key="dir.path"
185
+ type="button"
186
+ class="flex w-full items-center gap-2 rounded px-2 py-1 text-sm hover:bg-accent"
187
+ @click="browseDirectory(dir.path)"
188
+ >
189
+ <Folder class="size-4 text-muted-foreground" />
190
+ <span class="truncate">{{ dir.name }}</span>
191
+ </button>
192
+ </div>
193
+ </div>
194
+
195
+ <Button type="submit" class="w-full" :disabled="isAdding">
196
+ <span v-if="isAdding">Adding...</span>
197
+ <span v-else>Add Repository</span>
198
+ </Button>
199
+ </form>
200
+ </div>
201
+
202
+ <!-- Select prompt: Repos exist but none selected -->
203
+ <div v-else-if="showSelectPrompt" class="mx-auto max-w-md text-center">
204
+ <div class="mx-auto mb-6 flex size-16 items-center justify-center rounded-full bg-primary/10">
205
+ <FolderOpen class="size-8 text-primary" />
206
+ </div>
207
+ <h2 class="text-2xl font-semibold tracking-tight">
208
+ Select a Repository
209
+ </h2>
210
+ <p class="mt-2 text-muted-foreground">
211
+ Choose a repository from the dropdown in the header to view its PRD documents.
212
+ </p>
213
+ <div class="mt-6 flex items-center justify-center gap-2 text-sm text-muted-foreground">
214
+ <ArrowRight class="size-4" />
215
+ <span>Use the repository selector above</span>
216
+ </div>
217
+ </div>
218
+
219
+ <!-- Welcome: Repo selected but no PRDs -->
220
+ <div v-else-if="showWelcome" class="mx-auto max-w-md text-center">
221
+ <div class="mx-auto mb-6 flex size-16 items-center justify-center rounded-full bg-muted">
222
+ <FileText class="size-8 text-muted-foreground" />
223
+ </div>
224
+ <h2 class="text-2xl font-semibold tracking-tight">
225
+ No PRDs Found
226
+ </h2>
227
+ <p class="mt-2 text-muted-foreground">
228
+ This repository doesn't have any PRD documents yet. Add markdown files to <code class="rounded bg-muted px-1.5 py-0.5 text-sm">docs/prd/</code> to get started.
229
+ </p>
230
+ </div>
231
+
232
+ <!-- PRD list: Repo selected with PRDs - show welcome with PRD count -->
233
+ <div v-else-if="showPrdList" class="mx-auto max-w-md text-center">
234
+ <div class="mx-auto mb-6 flex size-16 items-center justify-center rounded-full bg-primary/10">
235
+ <FileText class="size-8 text-primary" />
236
+ </div>
237
+ <h2 class="text-2xl font-semibold tracking-tight">
238
+ {{ currentRepo?.name }}
239
+ </h2>
240
+ <p class="mt-2 text-muted-foreground">
241
+ {{ prds?.length }} PRD{{ prds?.length === 1 ? '' : 's' }} available. Select one from the sidebar to view details.
242
+ </p>
243
+ <div class="mt-6 flex items-center justify-center gap-2 text-sm text-muted-foreground">
244
+ <ArrowRight class="size-4 rotate-180" />
245
+ <span>Choose a PRD from the sidebar</span>
246
+ </div>
247
+ </div>
248
+
249
+ <!-- Loading state -->
250
+ <div v-else class="mx-auto max-w-md text-center">
251
+ <div class="mx-auto mb-6 flex size-16 items-center justify-center">
252
+ <div class="size-8 animate-spin rounded-full border-4 border-primary border-t-transparent" />
253
+ </div>
254
+ <p class="text-muted-foreground">Loading...</p>
255
+ </div>
256
+ </div>
257
+ </template>
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Git commit information
3
+ */
4
+ export interface GitCommit {
5
+ /** Full commit SHA */
6
+ sha: string
7
+ /** Short commit SHA (7 characters) */
8
+ shortSha: string
9
+ /** Commit message (first line) */
10
+ message: string
11
+ /** Author name */
12
+ author: string
13
+ /** Commit date as ISO string */
14
+ date: string
15
+ /** Number of files changed */
16
+ filesChanged: number
17
+ /** Total lines added */
18
+ additions: number
19
+ /** Total lines deleted */
20
+ deletions: number
21
+ /** Relative path to git repo for pseudo-monorepos (e.g., "code-hospitality-backend") */
22
+ repoPath?: string
23
+ }
24
+
25
+ /**
26
+ * File change status in a commit
27
+ */
28
+ export type FileStatus = 'added' | 'modified' | 'deleted' | 'renamed'
29
+
30
+ /**
31
+ * File diff summary within a commit
32
+ */
33
+ export interface FileDiff {
34
+ /** Current file path */
35
+ path: string
36
+ /** Change status */
37
+ status: FileStatus
38
+ /** Original file path (for renames) */
39
+ oldPath?: string
40
+ /** Lines added in this file */
41
+ additions: number
42
+ /** Lines deleted in this file */
43
+ deletions: number
44
+ /** Whether this is a binary file */
45
+ binary?: boolean
46
+ }
47
+
48
+ /**
49
+ * Type of diff line
50
+ */
51
+ export type DiffLineType = 'add' | 'remove' | 'context'
52
+
53
+ /**
54
+ * Single line in a diff hunk
55
+ */
56
+ export interface DiffLine {
57
+ /** Line type: addition, removal, or context */
58
+ type: DiffLineType
59
+ /** Line content (without +/- prefix) */
60
+ content: string
61
+ /** Line number in old file (for remove/context lines) */
62
+ oldNumber?: number
63
+ /** Line number in new file (for add/context lines) */
64
+ newNumber?: number
65
+ }
66
+
67
+ /**
68
+ * A hunk (section) of a diff
69
+ */
70
+ export interface DiffHunk {
71
+ /** Starting line in old file */
72
+ oldStart: number
73
+ /** Number of lines from old file */
74
+ oldLines: number
75
+ /** Starting line in new file */
76
+ newStart: number
77
+ /** Number of lines in new file */
78
+ newLines: number
79
+ /** Lines in this hunk */
80
+ lines: DiffLine[]
81
+ }
@@ -0,0 +1,29 @@
1
+ // Repository types
2
+ export type { RepoConfig, AddRepoRequest, GitRepoInfo } from './repo'
3
+
4
+ // PRD types
5
+ export type { PrdListItem, PrdMetadata, PrdDocument } from './prd'
6
+
7
+ // Task types
8
+ export type {
9
+ TaskCategory,
10
+ TaskPriority,
11
+ TaskStatus,
12
+ Task,
13
+ TasksPrdInfo,
14
+ TasksFile,
15
+ ProgressPattern,
16
+ CommitRef,
17
+ TaskLog,
18
+ ProgressFile,
19
+ } from './task'
20
+
21
+ // Git types
22
+ export type {
23
+ GitCommit,
24
+ FileStatus,
25
+ FileDiff,
26
+ DiffLineType,
27
+ DiffLine,
28
+ DiffHunk,
29
+ } from './git'
@@ -0,0 +1,49 @@
1
+ /**
2
+ * PRD list item returned when listing PRDs in a repository
3
+ */
4
+ export interface PrdListItem {
5
+ /** URL-safe identifier (derived from filename) */
6
+ slug: string
7
+ /** PRD title extracted from markdown H1 */
8
+ name: string
9
+ /** Relative path to the .md file */
10
+ source: string
11
+ /** Whether tracked task/progress state exists for this PRD */
12
+ hasState: boolean
13
+ /** Total number of tasks if state exists */
14
+ taskCount?: number
15
+ /** Number of completed tasks if state exists */
16
+ completedCount?: number
17
+ /** File modification timestamp (ms since epoch) */
18
+ modifiedAt: number
19
+ }
20
+
21
+ /**
22
+ * PRD metadata extracted from document header
23
+ */
24
+ export interface PrdMetadata {
25
+ /** Document author */
26
+ author?: string
27
+ /** Creation/update date */
28
+ date?: string
29
+ /** Document status (Draft, In Progress, Complete, etc.) */
30
+ status?: string
31
+ /** Shortcut story ID if linked */
32
+ shortcutStory?: string
33
+ /** Shortcut story URL if linked */
34
+ shortcutUrl?: string
35
+ }
36
+
37
+ /**
38
+ * Full PRD document with content and metadata
39
+ */
40
+ export interface PrdDocument {
41
+ /** URL-safe identifier */
42
+ slug: string
43
+ /** PRD title */
44
+ name: string
45
+ /** Raw markdown content */
46
+ content: string
47
+ /** Extracted metadata */
48
+ metadata: PrdMetadata
49
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Information about a discovered git repository within a pseudo-monorepo
3
+ */
4
+ export interface GitRepoInfo {
5
+ /** Relative path from registered repo root (e.g., "code-hospitality-backend") */
6
+ relativePath: string
7
+ /** Absolute filesystem path to the git repo */
8
+ absolutePath: string
9
+ /** Display name (usually folder name) */
10
+ name: string
11
+ }
12
+
13
+ /**
14
+ * Repository configuration stored server-side
15
+ */
16
+ export interface RepoConfig {
17
+ /** Unique identifier (UUID) */
18
+ id: string
19
+ /** Display name for the repository */
20
+ name: string
21
+ /** Absolute filesystem path to the repository */
22
+ path: string
23
+ /** ISO timestamp when the repo was added */
24
+ addedAt: string
25
+ /** Discovered git repositories for pseudo-monorepos (empty/undefined for standard repos) */
26
+ gitRepos?: GitRepoInfo[]
27
+ }
28
+
29
+ /**
30
+ * Request body for adding a new repository
31
+ */
32
+ export interface AddRepoRequest {
33
+ /** Absolute filesystem path to the repository */
34
+ path: string
35
+ /** Optional display name (defaults to directory name) */
36
+ name?: string
37
+ }
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Task category
3
+ */
4
+ export type TaskCategory = 'setup' | 'feature' | 'integration' | 'testing' | 'documentation'
5
+
6
+ /**
7
+ * Task priority level
8
+ */
9
+ export type TaskPriority = 'critical' | 'high' | 'medium' | 'low'
10
+
11
+ /**
12
+ * Task status
13
+ */
14
+ export type TaskStatus = 'pending' | 'in_progress' | 'completed'
15
+
16
+ /**
17
+ * Individual task from tasks.json
18
+ */
19
+ export interface Task {
20
+ /** Unique task identifier (e.g., "task-001") */
21
+ id: string
22
+ /** Task category */
23
+ category: TaskCategory
24
+ /** Short task title */
25
+ title: string
26
+ /** Detailed description of what needs to be done */
27
+ description: string
28
+ /** Specific implementation steps */
29
+ steps: string[]
30
+ /** Verification criteria for completion */
31
+ passes: string[]
32
+ /** IDs of tasks this task depends on */
33
+ dependencies: string[]
34
+ /** Task priority */
35
+ priority: TaskPriority
36
+ /** Current task status */
37
+ status: TaskStatus
38
+ /** ISO timestamp when task was started */
39
+ startedAt?: string
40
+ /** ISO timestamp when task was completed */
41
+ completedAt?: string
42
+ }
43
+
44
+ /**
45
+ * PRD metadata in tasks.json
46
+ */
47
+ export interface TasksPrdInfo {
48
+ /** PRD name/title */
49
+ name: string
50
+ /** Path to source PRD markdown file */
51
+ source: string
52
+ /** Shortcut story ID if linked */
53
+ shortcutStory?: string
54
+ /** ISO timestamp when tasks were created */
55
+ createdAt: string
56
+ }
57
+
58
+ /**
59
+ * Full tasks.json structure
60
+ */
61
+ export interface TasksFile {
62
+ /** PRD information */
63
+ prd: TasksPrdInfo
64
+ /** Array of tasks */
65
+ tasks: Task[]
66
+ }
67
+
68
+ /**
69
+ * Pattern discovered during implementation
70
+ */
71
+ export interface ProgressPattern {
72
+ /** Pattern name */
73
+ name: string
74
+ /** Pattern description */
75
+ description: string
76
+ }
77
+
78
+ /**
79
+ * Commit reference with repository context for pseudo-monorepos
80
+ */
81
+ export interface CommitRef {
82
+ /** Git commit SHA */
83
+ sha: string
84
+ /** Relative path to git repo from registered repo root (e.g., "code-hospitality-backend") */
85
+ repo: string
86
+ }
87
+
88
+ /**
89
+ * Log entry for a completed task
90
+ */
91
+ export interface TaskLog {
92
+ /** Task ID */
93
+ taskId: string
94
+ /** Task status */
95
+ status: TaskStatus
96
+ /** ISO timestamp when task was started */
97
+ startedAt: string
98
+ /** ISO timestamp when task was completed */
99
+ completedAt?: string
100
+ /** Description of what was implemented */
101
+ implemented?: string
102
+ /** Files that were changed */
103
+ filesChanged?: string[]
104
+ /** Learnings or patterns discovered */
105
+ learnings?: string
106
+ /** Git commit SHAs associated with this task - supports both legacy strings and CommitRef objects */
107
+ commits?: (string | CommitRef)[]
108
+ }
109
+
110
+ /**
111
+ * Progress tracking file structure (progress.json)
112
+ */
113
+ export interface ProgressFile {
114
+ /** PRD name */
115
+ prdName: string
116
+ /** Shortcut story ID if linked */
117
+ shortcutStory?: string
118
+ /** Total number of tasks */
119
+ totalTasks: number
120
+ /** Number of completed tasks */
121
+ completed: number
122
+ /** Number of in-progress tasks */
123
+ inProgress: number
124
+ /** Number of blocked tasks */
125
+ blocked: number
126
+ /** ISO timestamp when work started */
127
+ startedAt: string | null
128
+ /** ISO timestamp of last update */
129
+ lastUpdated: string
130
+ /** Discovered patterns */
131
+ patterns: ProgressPattern[]
132
+ /** Task completion logs */
133
+ taskLogs: TaskLog[]
134
+ }
package/bin/prd ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync } from 'node:fs'
3
+ import { dirname, resolve } from 'node:path'
4
+ import { fileURLToPath, pathToFileURL } from 'node:url'
5
+
6
+ const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..')
7
+ const entryPath = resolve(packageRoot, 'dist', 'host', 'src', 'index.js')
8
+
9
+ if (!existsSync(entryPath)) {
10
+ console.error('Steward host runtime is not built.')
11
+ console.error('Run `npm run build:host` in this package before invoking `prd`.')
12
+ process.exit(1)
13
+ }
14
+
15
+ const { main } = await import(pathToFileURL(entryPath).href)
16
+
17
+ await main(process.argv.slice(2)).catch((error) => {
18
+ const message = error instanceof Error ? error.message : String(error)
19
+ console.error(`Error: ${message}`)
20
+ process.exit(1)
21
+ })
@@ -0,0 +1,21 @@
1
+ {
2
+ "$schema": "https://shadcn-vue.com/schema.json",
3
+ "style": "new-york",
4
+ "typescript": true,
5
+ "tailwind": {
6
+ "config": "",
7
+ "css": "app/assets/css/main.css",
8
+ "baseColor": "neutral",
9
+ "cssVariables": true,
10
+ "prefix": ""
11
+ },
12
+ "iconLibrary": "lucide",
13
+ "aliases": {
14
+ "components": "@/components",
15
+ "utils": "@/lib/utils",
16
+ "ui": "@/components/ui",
17
+ "lib": "@/lib",
18
+ "composables": "@/composables"
19
+ },
20
+ "registries": {}
21
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};