popilot 0.6.0 → 0.8.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.
- package/bin/cli.mjs +204 -2
- package/lib/doctor.mjs +38 -1
- package/lib/hydrate.mjs +15 -0
- package/lib/scaffold.mjs +5 -0
- package/lib/setup-wizard.mjs +35 -2
- package/package.json +1 -1
- package/scaffold/.context/project.yaml.example +19 -0
- package/scaffold/mcp-notification-server/package.json +18 -0
- package/scaffold/mcp-notification-server/src/index.ts +275 -0
- package/scaffold/mcp-notification-server/src/turso-client.ts +142 -0
- package/scaffold/mcp-notification-server/tsconfig.json +14 -0
- package/scaffold/mcp-pm/package.json +19 -0
- package/scaffold/mcp-pm/src/api-client.ts +69 -0
- package/scaffold/mcp-pm/src/index.ts +660 -0
- package/scaffold/mcp-pm/tsconfig.json +14 -0
- package/scaffold/pm-api/package.json +21 -0
- package/scaffold/pm-api/sql/001-memo-v2.sql +49 -0
- package/scaffold/pm-api/sql/002-notifications.sql +18 -0
- package/scaffold/pm-api/sql/003-content.sql +66 -0
- package/scaffold/pm-api/sql/004-agent-events.sql +21 -0
- package/scaffold/pm-api/sql/005-epic-sprint-decoupling.sql +6 -0
- package/scaffold/pm-api/sql/schema-core.sql +331 -0
- package/scaffold/pm-api/sql/schema-docs.sql +25 -0
- package/scaffold/pm-api/sql/schema-meetings.sql +17 -0
- package/scaffold/pm-api/sql/schema-rewards.sql +16 -0
- package/scaffold/pm-api/src/auth.ts +28 -0
- package/scaffold/pm-api/src/blockchain/adapter.ts +20 -0
- package/scaffold/pm-api/src/blockchain/tron.ts +62 -0
- package/scaffold/pm-api/src/db/adapter.ts +36 -0
- package/scaffold/pm-api/src/db/turso.ts +147 -0
- package/scaffold/pm-api/src/index.ts +114 -0
- package/scaffold/pm-api/src/mcp-tools/dashboard.ts +40 -0
- package/scaffold/pm-api/src/mcp-tools/epic.ts +67 -0
- package/scaffold/pm-api/src/mcp-tools/event.ts +89 -0
- package/scaffold/pm-api/src/mcp-tools/index.ts +11 -0
- package/scaffold/pm-api/src/mcp-tools/initiative.ts +51 -0
- package/scaffold/pm-api/src/mcp-tools/memo.ts +164 -0
- package/scaffold/pm-api/src/mcp-tools/notification.ts +37 -0
- package/scaffold/pm-api/src/mcp-tools/retro.ts +183 -0
- package/scaffold/pm-api/src/mcp-tools/sprint.ts +204 -0
- package/scaffold/pm-api/src/mcp-tools/standup.ts +136 -0
- package/scaffold/pm-api/src/mcp-tools/story.ts +230 -0
- package/scaffold/pm-api/src/mcp-tools/task.ts +187 -0
- package/scaffold/pm-api/src/mcp-tools/utils.ts +83 -0
- package/scaffold/pm-api/src/mcp.ts +871 -0
- package/scaffold/pm-api/src/nudge.ts +283 -0
- package/scaffold/pm-api/src/routes/auth.ts +32 -0
- package/scaffold/pm-api/src/routes/v2-activity.ts +27 -0
- package/scaffold/pm-api/src/routes/v2-admin.ts +165 -0
- package/scaffold/pm-api/src/routes/v2-dashboard.ts +189 -0
- package/scaffold/pm-api/src/routes/v2-docs.ts +34 -0
- package/scaffold/pm-api/src/routes/v2-initiatives.ts +118 -0
- package/scaffold/pm-api/src/routes/v2-kickoff.ts +265 -0
- package/scaffold/pm-api/src/routes/v2-meetings.ts +324 -0
- package/scaffold/pm-api/src/routes/v2-memos.ts +257 -0
- package/scaffold/pm-api/src/routes/v2-nav.ts +260 -0
- package/scaffold/pm-api/src/routes/v2-notifications.ts +79 -0
- package/scaffold/pm-api/src/routes/v2-page-content.ts +35 -0
- package/scaffold/pm-api/src/routes/v2-pm.ts +380 -0
- package/scaffold/pm-api/src/routes/v2-policy.ts +58 -0
- package/scaffold/pm-api/src/routes/v2-retro.ts +221 -0
- package/scaffold/pm-api/src/routes/v2-rewards.ts +132 -0
- package/scaffold/pm-api/src/routes/v2-scenarios.ts +48 -0
- package/scaffold/pm-api/src/routes/v2-search.ts +32 -0
- package/scaffold/pm-api/src/routes/v2-standup.ts +127 -0
- package/scaffold/pm-api/src/routes/v2-user.ts +38 -0
- package/scaffold/pm-api/src/types.ts +11 -0
- package/scaffold/pm-api/src/utils/activity.ts +22 -0
- package/scaffold/pm-api/src/utils/admin.ts +9 -0
- package/scaffold/pm-api/src/utils/agent-notify.ts +62 -0
- package/scaffold/pm-api/src/utils/assignee.ts +69 -0
- package/scaffold/pm-api/src/utils/db.ts +45 -0
- package/scaffold/pm-api/src/utils/initiative.ts +23 -0
- package/scaffold/pm-api/src/utils/retro-link.ts +32 -0
- package/scaffold/pm-api/src/utils/sprint-lifecycle.ts +96 -0
- package/scaffold/pm-api/tsconfig.json +15 -0
- package/scaffold/pm-api/wrangler.toml.hbs +11 -0
- package/scaffold/spec-site/package-lock.json +892 -0
- package/scaffold/spec-site/package.json +15 -1
- package/scaffold/spec-site/src/api/types.ts +6 -0
- package/scaffold/spec-site/src/components/AppHeader.vue +429 -55
- package/scaffold/spec-site/src/components/AuthGate.vue +117 -0
- package/scaffold/spec-site/src/components/BurndownChart.vue +78 -0
- package/scaffold/spec-site/src/components/DocComments.vue +137 -0
- package/scaffold/spec-site/src/components/DocEditor.vue +118 -0
- package/scaffold/spec-site/src/components/DocExportBar.vue +110 -0
- package/scaffold/spec-site/src/components/DocsSidebar.vue +309 -0
- package/scaffold/spec-site/src/components/EmptyState.vue +30 -0
- package/scaffold/spec-site/src/components/ErrorBanner.vue +38 -0
- package/scaffold/spec-site/src/components/Icon.vue +58 -0
- package/scaffold/spec-site/src/components/MemberSelect.vue +48 -0
- package/scaffold/spec-site/src/components/MemoChecklist.vue +88 -0
- package/scaffold/spec-site/src/components/MemoGraph.vue +75 -0
- package/scaffold/spec-site/src/components/MemoItem.vue +353 -0
- package/scaffold/spec-site/src/components/MemoRelations.vue +101 -0
- package/scaffold/spec-site/src/components/MemoTimeline.vue +53 -0
- package/scaffold/spec-site/src/components/MentionInput.vue +174 -0
- package/scaffold/spec-site/src/components/NotificationDropdown.vue +116 -0
- package/scaffold/spec-site/src/components/PriorityBadge.vue +23 -0
- package/scaffold/spec-site/src/components/SearchModal.vue +102 -0
- package/scaffold/spec-site/src/components/SlashCommand.ts +123 -0
- package/scaffold/spec-site/src/components/StateDisplay.vue +54 -0
- package/scaffold/spec-site/src/components/TreeNode.vue +82 -0
- package/scaffold/spec-site/src/components/UserAvatar.vue +24 -0
- package/scaffold/spec-site/src/components/VelocityChart.vue +77 -0
- package/scaffold/spec-site/src/composables/navTypes.ts +3 -0
- package/scaffold/spec-site/src/composables/pmTypes.ts +15 -2
- package/scaffold/spec-site/src/composables/useBottomSheet.ts +103 -0
- package/scaffold/spec-site/src/composables/useDashboard.ts +221 -0
- package/scaffold/spec-site/src/composables/useMediaQuery.ts +28 -0
- package/scaffold/spec-site/src/composables/useMemo.ts +39 -0
- package/scaffold/spec-site/src/composables/useNotification.ts +200 -0
- package/scaffold/spec-site/src/composables/usePmStore.ts +48 -1
- package/scaffold/spec-site/src/composables/useRetro.ts +6 -0
- package/scaffold/spec-site/src/composables/useStandup.ts +201 -0
- package/scaffold/spec-site/src/composables/useTheme.ts +37 -0
- package/scaffold/spec-site/src/composables/useTurso.ts +17 -0
- package/scaffold/spec-site/src/composables/useUser.ts +19 -1
- package/scaffold/spec-site/src/composables/useViewport.ts +26 -0
- package/scaffold/spec-site/src/features.ts +108 -0
- package/scaffold/spec-site/src/mockup/ComponentPalette.vue +61 -0
- package/scaffold/spec-site/src/mockup/MockupCanvas.vue +459 -0
- package/scaffold/spec-site/src/mockup/PropertyPanel.vue +217 -0
- package/scaffold/spec-site/src/mockup/componentCatalog.ts +68 -0
- package/scaffold/spec-site/src/mockup/useScenarios.ts +67 -0
- package/scaffold/spec-site/src/pages/AdminPage.vue +299 -0
- package/scaffold/spec-site/src/pages/DashboardPage.vue +650 -0
- package/scaffold/spec-site/src/pages/DocsEditor.vue +119 -0
- package/scaffold/spec-site/src/pages/DocsHub.vue +157 -0
- package/scaffold/spec-site/src/pages/DocsPage.vue +444 -0
- package/scaffold/spec-site/src/pages/InboxPage.vue +156 -0
- package/scaffold/spec-site/src/pages/MeetingsPage.vue +294 -0
- package/scaffold/spec-site/src/pages/MemosPage.vue +857 -0
- package/scaffold/spec-site/src/pages/MockupEditorPage.vue +611 -0
- package/scaffold/spec-site/src/pages/MockupListPage.vue +121 -0
- package/scaffold/spec-site/src/pages/MockupViewerPage.vue +199 -0
- package/scaffold/spec-site/src/pages/MyPage.vue +343 -0
- package/scaffold/spec-site/src/pages/NotificationSettingsPage.vue +59 -0
- package/scaffold/spec-site/src/pages/RewardsPage.vue +266 -0
- package/scaffold/spec-site/src/pages/SprintAdmin.vue +521 -0
- package/scaffold/spec-site/src/pages/SprintTimeline.vue +159 -0
- package/scaffold/spec-site/src/pages/board/BoardAdmin.vue +422 -0
- package/scaffold/spec-site/src/pages/board/BoardEpicSection.vue +54 -0
- package/scaffold/spec-site/src/pages/board/BoardPage.vue +884 -0
- package/scaffold/spec-site/src/pages/board/BoardStoryCard.vue +67 -0
- package/scaffold/spec-site/src/pages/board/BoardTaskItem.vue +52 -0
- package/scaffold/spec-site/src/pages/board/KanbanBoard.vue +93 -0
- package/scaffold/spec-site/src/pages/board/MyTasksPage.vue +202 -0
- package/scaffold/spec-site/src/pages/board/SprintClose.vue +167 -0
- package/scaffold/spec-site/src/pages/board/SprintColumn.vue +49 -0
- package/scaffold/spec-site/src/pages/board/SprintKickoff.vue +389 -0
- package/scaffold/spec-site/src/pages/board/StatusBadge.vue +52 -0
- package/scaffold/spec-site/src/pages/board/StoryDetailPanel.vue +495 -0
- package/scaffold/spec-site/src/pages/board/TaskCard.vue +42 -0
- package/scaffold/spec-site/src/pages/retro/RetroCard.vue +36 -2
- package/scaffold/spec-site/src/pages/retro/RetroHeader.vue +82 -66
- package/scaffold/spec-site/src/pages/retro/RetroPage.vue +47 -18
- package/scaffold/spec-site/src/pages/standup/StandupEntryCard.vue +551 -0
- package/scaffold/spec-site/src/pages/standup/StandupForm.vue +68 -0
- package/scaffold/spec-site/src/pages/standup/StandupList.vue +71 -0
- package/scaffold/spec-site/src/pages/standup/StandupPage.vue +225 -0
- package/scaffold/spec-site/src/router.ts +141 -0
- package/scaffold/spec-site/src/styles/buttons.css +124 -0
- package/scaffold/spec-site/src/utils/parseMentions.ts +56 -0
- package/scaffold/spec-site/src/utils/timezone.ts +18 -0
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, computed } from 'vue'
|
|
3
|
+
import { apiGet, apiPatch, isStaticMode } from '@/api/client'
|
|
4
|
+
import { useAuth } from '@/composables/useAuth'
|
|
5
|
+
|
|
6
|
+
const { authUser, isAuthenticated } = useAuth()
|
|
7
|
+
|
|
8
|
+
const token = computed(() => localStorage.getItem('spec-auth-token') || '')
|
|
9
|
+
const maskedToken = computed(() => token.value ? `${token.value.substring(0, 8)}...${token.value.substring(token.value.length - 4)}` : '')
|
|
10
|
+
const showFullToken = ref(false)
|
|
11
|
+
|
|
12
|
+
const copiedId = ref<string | null>(null)
|
|
13
|
+
|
|
14
|
+
// Webhook URL
|
|
15
|
+
const webhookUrl = ref('')
|
|
16
|
+
const savingWebhook = ref(false)
|
|
17
|
+
const webhookSaved = ref(false)
|
|
18
|
+
|
|
19
|
+
async function loadWebhookUrl() {
|
|
20
|
+
if (isStaticMode()) return
|
|
21
|
+
try {
|
|
22
|
+
const { data } = await apiGet<{ members: Array<{ webhook_url: string | null; display_name: string }> }>('/api/v2/admin/members')
|
|
23
|
+
if (data?.members) {
|
|
24
|
+
const me = data.members.find(m => m.display_name === authUser.value)
|
|
25
|
+
if (me?.webhook_url) webhookUrl.value = me.webhook_url
|
|
26
|
+
}
|
|
27
|
+
} catch (_) { /* ignore */ }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function saveWebhookUrl() {
|
|
31
|
+
savingWebhook.value = true
|
|
32
|
+
webhookSaved.value = false
|
|
33
|
+
try {
|
|
34
|
+
const { data } = await apiGet<{ members: Array<{ id: number; display_name: string }> }>('/api/v2/admin/members')
|
|
35
|
+
const me = data?.members?.find(m => m.display_name === authUser.value)
|
|
36
|
+
if (me) {
|
|
37
|
+
await apiPatch(`/api/v2/admin/members/${me.id}`, { webhook_url: webhookUrl.value || null })
|
|
38
|
+
webhookSaved.value = true
|
|
39
|
+
setTimeout(() => { webhookSaved.value = false }, 3000)
|
|
40
|
+
}
|
|
41
|
+
} catch (_) { /* ignore */ }
|
|
42
|
+
savingWebhook.value = false
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
loadWebhookUrl()
|
|
46
|
+
|
|
47
|
+
function copyText(text: string, id: string) {
|
|
48
|
+
navigator.clipboard.writeText(text)
|
|
49
|
+
copiedId.value = id
|
|
50
|
+
setTimeout(() => { copiedId.value = null }, 2000)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const apiUrl = import.meta.env.VITE_API_URL as string
|
|
54
|
+
|
|
55
|
+
const claudeCodeConfig = computed(() => JSON.stringify({
|
|
56
|
+
mcpServers: {
|
|
57
|
+
'mcp-pm': {
|
|
58
|
+
type: 'http',
|
|
59
|
+
url: `${apiUrl}/mcp`,
|
|
60
|
+
headers: {
|
|
61
|
+
Authorization: `Bearer ${token.value || '<your-token>'}`
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}, null, 2))
|
|
66
|
+
|
|
67
|
+
const codexConfig = computed(() => {
|
|
68
|
+
const t = token.value || '<your-token>'
|
|
69
|
+
return `[mcp_servers.mcp-pm]
|
|
70
|
+
url = "${apiUrl}/mcp"
|
|
71
|
+
http_headers = { "Authorization" = "Bearer ${t}" }`
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
const activeTab = ref<'claude' | 'codex'>('claude')
|
|
75
|
+
</script>
|
|
76
|
+
|
|
77
|
+
<template>
|
|
78
|
+
<div class="my-page" v-if="isAuthenticated">
|
|
79
|
+
<h1>My Profile</h1>
|
|
80
|
+
<p class="subtitle">Hello, {{ authUser }}</p>
|
|
81
|
+
|
|
82
|
+
<!-- Token Section -->
|
|
83
|
+
<section class="card">
|
|
84
|
+
<h2>My Token</h2>
|
|
85
|
+
<p class="card-desc">Personal token used for authentication and MCP connections.</p>
|
|
86
|
+
<div class="token-row">
|
|
87
|
+
<code class="token-display" @click="showFullToken = !showFullToken">
|
|
88
|
+
{{ showFullToken ? token : maskedToken }}
|
|
89
|
+
</code>
|
|
90
|
+
<button class="btn btn--primary" @click="copyText(token, 'token')">{{ copiedId === 'token' ? 'Copied!' : 'Copy' }}</button>
|
|
91
|
+
</div>
|
|
92
|
+
<p class="hint">Click to show full token</p>
|
|
93
|
+
</section>
|
|
94
|
+
|
|
95
|
+
<!-- Webhook URL Section -->
|
|
96
|
+
<section class="card">
|
|
97
|
+
<h2>Notification Webhook URL</h2>
|
|
98
|
+
<p class="card-desc">Set a Discord/Slack webhook URL to receive memo/story notifications.</p>
|
|
99
|
+
<div class="token-row">
|
|
100
|
+
<input v-model="webhookUrl" class="webhook-input" placeholder="https://discord.com/api/webhooks/..." />
|
|
101
|
+
<button class="btn btn--primary" @click="saveWebhookUrl" :disabled="savingWebhook">
|
|
102
|
+
{{ savingWebhook ? 'Saving...' : 'Save' }}
|
|
103
|
+
</button>
|
|
104
|
+
</div>
|
|
105
|
+
<p v-if="webhookSaved" class="hint" style="color: #16a34a;">Saved successfully</p>
|
|
106
|
+
</section>
|
|
107
|
+
|
|
108
|
+
<!-- MCP Guide Section -->
|
|
109
|
+
<section class="card">
|
|
110
|
+
<h2>MCP Connection Guide</h2>
|
|
111
|
+
<p class="card-desc">Use PM tools (tasks, standup, memos, events) directly from your AI coding assistant.</p>
|
|
112
|
+
|
|
113
|
+
<!-- Tab Selector -->
|
|
114
|
+
<div class="tab-bar">
|
|
115
|
+
<button class="tab" :class="{ 'tab--active': activeTab === 'claude' }" @click="activeTab = 'claude'">Claude Code</button>
|
|
116
|
+
<button class="tab" :class="{ 'tab--active': activeTab === 'codex' }" @click="activeTab = 'codex'">Codex CLI</button>
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<!-- Claude Code Tab -->
|
|
120
|
+
<div v-if="activeTab === 'claude'" class="tab-content">
|
|
121
|
+
<div class="step">
|
|
122
|
+
<span class="step-num">1</span>
|
|
123
|
+
<div class="step-body">
|
|
124
|
+
<p>Add the following to <code>.mcp.json</code> in your project root (or create it):</p>
|
|
125
|
+
<div class="code-block">
|
|
126
|
+
<button class="code-copy" @click="copyText(claudeCodeConfig, 'claude-config')">{{ copiedId === 'claude-config' ? 'Copied!' : 'Copy' }}</button>
|
|
127
|
+
<pre>{{ claudeCodeConfig }}</pre>
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
<div class="step">
|
|
132
|
+
<span class="step-num">2</span>
|
|
133
|
+
<div class="step-body">
|
|
134
|
+
<p>Restart Claude Code to connect to the MCP server automatically.</p>
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
<div class="step">
|
|
138
|
+
<span class="step-num">3</span>
|
|
139
|
+
<div class="step-body">
|
|
140
|
+
<p>Verify connection:</p>
|
|
141
|
+
<div class="code-block">
|
|
142
|
+
<button class="code-copy" @click="copyText('claude "Show my dashboard"', 'claude-test')">{{ copiedId === 'claude-test' ? 'Copied!' : 'Copy' }}</button>
|
|
143
|
+
<pre>claude "Show my dashboard"</pre>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
|
|
149
|
+
<!-- Codex Tab -->
|
|
150
|
+
<div v-if="activeTab === 'codex'" class="tab-content">
|
|
151
|
+
<div class="step">
|
|
152
|
+
<span class="step-num">1</span>
|
|
153
|
+
<div class="step-body">
|
|
154
|
+
<p>Add to <code>~/.codex/config.toml</code> (global) or project-level <code>.codex/config.toml</code>:</p>
|
|
155
|
+
<div class="code-block">
|
|
156
|
+
<button class="code-copy" @click="copyText(codexConfig, 'codex-config')">{{ copiedId === 'codex-config' ? 'Copied!' : 'Copy' }}</button>
|
|
157
|
+
<pre>{{ codexConfig }}</pre>
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
<div class="step">
|
|
162
|
+
<span class="step-num">2</span>
|
|
163
|
+
<div class="step-body">
|
|
164
|
+
<p>Or add via CLI:</p>
|
|
165
|
+
<div class="code-block">
|
|
166
|
+
<button class="code-copy" @click="copyText(`codex mcp add mcp-pm --transport http --url ${apiUrl}/mcp`, 'codex-add')">{{ copiedId === 'codex-add' ? 'Copied!' : 'Copy' }}</button>
|
|
167
|
+
<pre>codex mcp add mcp-pm --transport http \
|
|
168
|
+
--url {{ apiUrl }}/mcp</pre>
|
|
169
|
+
</div>
|
|
170
|
+
<p>Then manually add the Authorization header to <code>~/.codex/config.toml</code> under <code>http_headers</code>.</p>
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
|
+
<div class="step">
|
|
174
|
+
<span class="step-num">3</span>
|
|
175
|
+
<div class="step-body">
|
|
176
|
+
<p>Verify connection:</p>
|
|
177
|
+
<div class="code-block">
|
|
178
|
+
<button class="code-copy" @click="copyText('codex "Show my dashboard"', 'codex-test')">{{ copiedId === 'codex-test' ? 'Copied!' : 'Copy' }}</button>
|
|
179
|
+
<pre>codex "Show my dashboard"</pre>
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
|
|
185
|
+
<!-- Common Notes -->
|
|
186
|
+
<div class="note-box">
|
|
187
|
+
<strong>Notes</strong>
|
|
188
|
+
<ul>
|
|
189
|
+
<li>Sprint is auto-detected (no manual setup required)</li>
|
|
190
|
+
<li>User name is auto-extracted from your token</li>
|
|
191
|
+
<li>DB credentials stay on the server only -- <code>.mcp.json</code> has no secrets</li>
|
|
192
|
+
<li>Add <code>.mcp.json</code> to <code>.gitignore</code> (contains personal token)</li>
|
|
193
|
+
</ul>
|
|
194
|
+
</div>
|
|
195
|
+
</section>
|
|
196
|
+
|
|
197
|
+
<!-- Available MCP Tools -->
|
|
198
|
+
<section class="card">
|
|
199
|
+
<h2>MCP Tools</h2>
|
|
200
|
+
<p class="card-desc">Tools your AI agent can call. Just use natural language and the agent will pick the right tool.</p>
|
|
201
|
+
|
|
202
|
+
<table class="tool-table">
|
|
203
|
+
<thead>
|
|
204
|
+
<tr>
|
|
205
|
+
<th>Tool</th>
|
|
206
|
+
<th>Description</th>
|
|
207
|
+
<th>Example</th>
|
|
208
|
+
</tr>
|
|
209
|
+
</thead>
|
|
210
|
+
<tbody>
|
|
211
|
+
<tr class="tool-group-row"><td colspan="3">Dashboard & Navigation</td></tr>
|
|
212
|
+
<tr><td><code>my_dashboard</code></td><td>Overview of your tasks, unread memos, notifications, and standup status</td><td class="tool-example">"Show my status"</td></tr>
|
|
213
|
+
<tr><td><code>list_sprints</code></td><td>List all sprints (active sprint highlighted)</td><td class="tool-example">"Sprint list"</td></tr>
|
|
214
|
+
<tr><td><code>activate_sprint</code></td><td>Activate a sprint (deactivates others)</td><td class="tool-example">"Activate sprint s55"</td></tr>
|
|
215
|
+
<tr><td><code>sprint_summary</code></td><td>Progress by epic, workload by member, blockers</td><td class="tool-example">"Sprint summary"</td></tr>
|
|
216
|
+
<tr><td><code>list_team_members</code></td><td>List active team members</td><td class="tool-example">"Who's on the team?"</td></tr>
|
|
217
|
+
|
|
218
|
+
<tr class="tool-group-row"><td colspan="3">Epics</td></tr>
|
|
219
|
+
<tr><td><code>list_epics</code></td><td>All epics with story counts</td><td class="tool-example">"Show epics"</td></tr>
|
|
220
|
+
<tr><td><code>add_epic</code></td><td>Create a new epic</td><td class="tool-example">"Add epic: AI Diagnostics"</td></tr>
|
|
221
|
+
<tr><td><code>update_epic</code></td><td>Update epic (title, description, status, owner)</td><td class="tool-example">"Set epic 3 to completed"</td></tr>
|
|
222
|
+
<tr><td><code>delete_epic</code></td><td>Delete epic (child stories get epic_id=null)</td><td class="tool-example">"Delete epic 5"</td></tr>
|
|
223
|
+
|
|
224
|
+
<tr class="tool-group-row"><td colspan="3">Stories</td></tr>
|
|
225
|
+
<tr><td><code>list_stories</code></td><td>Stories with sprint/epic/status/assignee filters</td><td class="tool-example">"s55 stories"</td></tr>
|
|
226
|
+
<tr><td><code>add_story</code></td><td>Create a story under an epic</td><td class="tool-example">"Add story to epic 2: API Design"</td></tr>
|
|
227
|
+
<tr><td><code>update_story</code></td><td>Update story (title, status, assignee, points)</td><td class="tool-example">"Set story 10 to in-progress"</td></tr>
|
|
228
|
+
<tr><td><code>delete_story</code></td><td>Delete story and its tasks</td><td class="tool-example">"Delete story 15"</td></tr>
|
|
229
|
+
|
|
230
|
+
<tr class="tool-group-row"><td colspan="3">Tasks</td></tr>
|
|
231
|
+
<tr><td><code>list_my_tasks</code></td><td>Task tree: epic > story > task, filterable by status</td><td class="tool-example">"In-progress tasks only"</td></tr>
|
|
232
|
+
<tr><td><code>get_task</code></td><td>Task details + parent story + sibling tasks</td><td class="tool-example">"Task 42 details"</td></tr>
|
|
233
|
+
<tr><td><code>update_task_status</code></td><td>Change status (todo > in-progress > done)</td><td class="tool-example">"Mark task 42 done"</td></tr>
|
|
234
|
+
<tr><td><code>update_task</code></td><td>Update task (title, assignee, status, description)</td><td class="tool-example">"Assign task 42 to Alex"</td></tr>
|
|
235
|
+
<tr><td><code>add_task</code></td><td>Add task under a story; auto-assigns to you if unspecified</td><td class="tool-example">"Add task to story 10: API integration"</td></tr>
|
|
236
|
+
<tr><td><code>delete_task</code></td><td>Delete a task</td><td class="tool-example">"Delete task 50"</td></tr>
|
|
237
|
+
|
|
238
|
+
<tr class="tool-group-row"><td colspan="3">Standup</td></tr>
|
|
239
|
+
<tr><td><code>get_standup</code></td><td>Get standup for a date (default: today)</td><td class="tool-example">"Yesterday's standup"</td></tr>
|
|
240
|
+
<tr><td><code>save_standup</code></td><td>Save today's standup (done/planned/blockers); overwrites if exists</td><td class="tool-example">"Standup: done API, plan FE integration"</td></tr>
|
|
241
|
+
<tr><td><code>list_standup_entries</code></td><td>Standup entries (sprint/date filter)</td><td class="tool-example">"This sprint's standups"</td></tr>
|
|
242
|
+
|
|
243
|
+
<tr class="tool-group-row"><td colspan="3">Memos</td></tr>
|
|
244
|
+
<tr><td><code>send_memo</code></td><td>Send memo to team members (comma-separated recipients)</td><td class="tool-example">"Send API spec review request to Alex, Jordan"</td></tr>
|
|
245
|
+
<tr><td><code>list_my_memos</code></td><td>My memos; filter for unread</td><td class="tool-example">"Any unread memos?"</td></tr>
|
|
246
|
+
<tr><td><code>read_memo</code></td><td>Read memo + replies; marks as read</td><td class="tool-example">"Read memo 15"</td></tr>
|
|
247
|
+
<tr><td><code>reply_memo</code></td><td>Reply to a memo</td><td class="tool-example">"Reply to memo 15: acknowledged"</td></tr>
|
|
248
|
+
<tr><td><code>resolve_memo</code></td><td>Mark memo as resolved</td><td class="tool-example">"Resolve memo 15"</td></tr>
|
|
249
|
+
|
|
250
|
+
<tr class="tool-group-row"><td colspan="3">Retrospective</td></tr>
|
|
251
|
+
<tr><td><code>get_retro_session</code></td><td>Retro session with items + actions</td><td class="tool-example">"Show this sprint's retro"</td></tr>
|
|
252
|
+
<tr><td><code>add_retro_item</code></td><td>Add retro item (keep/problem/try)</td><td class="tool-example">"Add to keep: great code reviews"</td></tr>
|
|
253
|
+
<tr><td><code>vote_retro_item</code></td><td>Vote/unvote retro item</td><td class="tool-example">"Vote for item 3"</td></tr>
|
|
254
|
+
<tr><td><code>change_retro_phase</code></td><td>Change phase (collect > vote > discuss > action > done)</td><td class="tool-example">"Move retro to vote phase"</td></tr>
|
|
255
|
+
<tr><td><code>add_retro_action</code></td><td>Add retro action item</td><td class="tool-example">"Action: PR reviews within 24h"</td></tr>
|
|
256
|
+
<tr><td><code>update_retro_action_status</code></td><td>Update action status (todo > in-progress > done)</td><td class="tool-example">"Complete action 2"</td></tr>
|
|
257
|
+
<tr><td><code>export_retro</code></td><td>Export retro summary (keep/problem/try + actions + votes)</td><td class="tool-example">"Export retro results"</td></tr>
|
|
258
|
+
|
|
259
|
+
<tr class="tool-group-row"><td colspan="3">Agent Events (Push-Native)</td></tr>
|
|
260
|
+
<tr><td><code>emit_event</code></td><td>Emit event to agent/user; delivered via SSE in real-time</td><td class="tool-example">"Notify Oscar about sprint"</td></tr>
|
|
261
|
+
<tr><td><code>poll_events</code></td><td>Poll pending events (fallback for non-SSE clients)</td><td class="tool-example">"Check my events"</td></tr>
|
|
262
|
+
<tr><td><code>ack_event</code></td><td>Acknowledge event; unacked events get retried</td><td class="tool-example">"Ack event 3"</td></tr>
|
|
263
|
+
|
|
264
|
+
<tr class="tool-group-row"><td colspan="3">Notifications</td></tr>
|
|
265
|
+
<tr><td><code>check_notifications</code></td><td>Check notifications (unread first)</td><td class="tool-example">"Check notifications"</td></tr>
|
|
266
|
+
<tr><td><code>mark_notification_read</code></td><td>Mark notification as read</td><td class="tool-example">"Mark notification 5 read"</td></tr>
|
|
267
|
+
<tr><td><code>mark_all_notifications_read</code></td><td>Mark all notifications read</td><td class="tool-example">"Mark all read"</td></tr>
|
|
268
|
+
</tbody>
|
|
269
|
+
</table>
|
|
270
|
+
</section>
|
|
271
|
+
</div>
|
|
272
|
+
|
|
273
|
+
<!-- Not Authenticated -->
|
|
274
|
+
<div class="my-page" v-else>
|
|
275
|
+
<div class="card" style="text-align: center; padding: 48px 24px;">
|
|
276
|
+
<h2>Login Required</h2>
|
|
277
|
+
<p class="card-desc">Access via a token link or contact your administrator.</p>
|
|
278
|
+
</div>
|
|
279
|
+
</div>
|
|
280
|
+
</template>
|
|
281
|
+
|
|
282
|
+
<style scoped>
|
|
283
|
+
.my-page { max-width: 720px; margin: 0 auto; padding: 32px 24px; height: calc(100vh - var(--header-height, 48px)); overflow-y: auto; }
|
|
284
|
+
h1 { font-size: 24px; font-weight: 700; color: #1e293b; margin-bottom: 4px; }
|
|
285
|
+
.subtitle { font-size: 14px; color: #64748b; margin-bottom: 28px; }
|
|
286
|
+
|
|
287
|
+
.card { background: #fff; border: 1px solid #e2e8f0; border-radius: 12px; padding: 24px; margin-bottom: 20px; min-width: 0; }
|
|
288
|
+
.card h2 { font-size: 16px; font-weight: 600; color: #1e293b; margin-bottom: 4px; }
|
|
289
|
+
.card-desc { font-size: 13px; color: #94a3b8; margin-bottom: 16px; }
|
|
290
|
+
|
|
291
|
+
/* Token */
|
|
292
|
+
.token-row { display: flex; gap: 8px; align-items: center; }
|
|
293
|
+
.token-display { flex: 1; padding: 10px 14px; background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px; font-family: monospace; font-size: 14px; color: #334155; cursor: pointer; user-select: all; word-break: break-all; }
|
|
294
|
+
.token-display:hover { background: #f1f5f9; }
|
|
295
|
+
.webhook-input { flex: 1; padding: 8px 12px; border: 1px solid rgba(0,0,0,0.08); border-radius: 8px; font-size: 13px; font-family: monospace; }
|
|
296
|
+
.hint { font-size: 11px; color: #94a3b8; margin-top: 6px; }
|
|
297
|
+
|
|
298
|
+
/* Tabs */
|
|
299
|
+
.tab-bar { display: flex; gap: 0; border-bottom: 2px solid #e2e8f0; margin-bottom: 20px; }
|
|
300
|
+
.tab { padding: 8px 20px; border: none; background: none; cursor: pointer; font-size: 13px; font-weight: 500; color: #94a3b8; border-bottom: 2px solid transparent; margin-bottom: -2px; transition: all 0.15s; }
|
|
301
|
+
.tab:hover { color: #475569; }
|
|
302
|
+
.tab--active { color: #1e293b; border-bottom-color: #1e293b; }
|
|
303
|
+
|
|
304
|
+
/* Steps */
|
|
305
|
+
.step { display: flex; gap: 12px; margin-bottom: 20px; }
|
|
306
|
+
.step-num { flex-shrink: 0; width: 24px; height: 24px; border-radius: 50%; background: #1e293b; color: #fff; font-size: 12px; font-weight: 700; display: flex; align-items: center; justify-content: center; margin-top: 2px; }
|
|
307
|
+
.step-body { flex: 1; min-width: 0; }
|
|
308
|
+
.step-body p { font-size: 13px; color: #475569; margin-bottom: 8px; line-height: 1.5; }
|
|
309
|
+
.step-body code { background: #f1f5f9; padding: 1px 6px; border-radius: 4px; font-size: 12px; }
|
|
310
|
+
|
|
311
|
+
.code-block { position: relative; background: #1e293b; border-radius: 8px; padding: 16px; overflow: auto; max-width: 100%; }
|
|
312
|
+
.code-block pre { margin: 0; color: #e2e8f0; font-family: monospace; font-size: 12px; line-height: 1.6; white-space: pre; }
|
|
313
|
+
.code-copy { position: absolute; top: 8px; right: 8px; padding: 4px 10px; border: 1px solid #475569; border-radius: 4px; background: #334155; color: #94a3b8; font-size: 11px; cursor: pointer; transition: all 0.15s; }
|
|
314
|
+
.code-copy:hover { background: #475569; color: #fff; }
|
|
315
|
+
|
|
316
|
+
/* Note */
|
|
317
|
+
.note-box { margin-top: 20px; padding: 14px 18px; background: #fffbeb; border: 1px solid #fde68a; border-radius: 8px; font-size: 13px; color: #92400e; }
|
|
318
|
+
.note-box strong { display: block; margin-bottom: 6px; }
|
|
319
|
+
.note-box ul { margin: 0; padding-left: 18px; }
|
|
320
|
+
.note-box li { margin-bottom: 4px; line-height: 1.5; }
|
|
321
|
+
.note-box code { background: #fef3c7; padding: 1px 4px; border-radius: 3px; font-size: 11px; }
|
|
322
|
+
|
|
323
|
+
/* Tools table */
|
|
324
|
+
.tool-table { width: 100%; border-collapse: collapse; font-size: 13px; }
|
|
325
|
+
.tool-table th { text-align: left; padding: 8px 10px; font-size: 11px; font-weight: 600; color: #64748b; text-transform: uppercase; letter-spacing: 0.5px; border-bottom: 2px solid #e2e8f0; }
|
|
326
|
+
.tool-table td { padding: 8px 10px; border-bottom: 1px solid #f1f5f9; color: #475569; vertical-align: top; }
|
|
327
|
+
.tool-table code { background: #f1f5f9; padding: 2px 6px; border-radius: 4px; font-family: monospace; font-size: 11px; color: #1e293b; white-space: nowrap; }
|
|
328
|
+
.tool-table tr:hover td { background: #f8fafc; }
|
|
329
|
+
.tool-group-row td { font-size: 11px; font-weight: 700; color: #94a3b8; text-transform: uppercase; letter-spacing: 0.5px; padding-top: 14px; border-bottom: 1px solid #e2e8f0; background: none !important; }
|
|
330
|
+
.tool-example { font-size: 12px; color: #94a3b8; font-style: italic; white-space: nowrap; }
|
|
331
|
+
|
|
332
|
+
/* Buttons */
|
|
333
|
+
.btn { padding: 8px 16px; border: 1px solid #e2e8f0; border-radius: 6px; font-size: 13px; font-weight: 500; cursor: pointer; background: #fff; color: #475569; white-space: nowrap; transition: all 0.15s; }
|
|
334
|
+
.btn:hover { background: #f1f5f9; }
|
|
335
|
+
.btn--primary { background: #1e293b; color: #fff; border-color: #1e293b; }
|
|
336
|
+
.btn--primary:hover { background: #334155; }
|
|
337
|
+
|
|
338
|
+
@media (max-width: 767px) {
|
|
339
|
+
.my-page { padding: 16px; }
|
|
340
|
+
.token-row { flex-direction: column; }
|
|
341
|
+
.tab { padding: 8px 14px; font-size: 12px; }
|
|
342
|
+
}
|
|
343
|
+
</style>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, onMounted } from 'vue'
|
|
3
|
+
import { apiGet, apiPut } from '@/composables/useTurso'
|
|
4
|
+
import { useAuth } from '@/composables/useAuth'
|
|
5
|
+
|
|
6
|
+
const { authUser } = useAuth()
|
|
7
|
+
const settings = ref({ mention: true, story_update: true, pr_review: true, sprint_event: true })
|
|
8
|
+
const saved = ref(false)
|
|
9
|
+
|
|
10
|
+
onMounted(async () => {
|
|
11
|
+
const user = authUser.value
|
|
12
|
+
if (!user) return
|
|
13
|
+
const { data } = await apiGet(`/api/v2/notifications/settings?user=${encodeURIComponent(user)}`)
|
|
14
|
+
if (data?.settings) {
|
|
15
|
+
const s = data.settings as any
|
|
16
|
+
settings.value = { mention: !!s.mention, story_update: !!s.story_update, pr_review: !!s.pr_review, sprint_event: !!s.sprint_event }
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
async function save() {
|
|
21
|
+
const user = authUser.value
|
|
22
|
+
if (!user) return
|
|
23
|
+
await apiPut('/api/v2/notifications/settings', { user, ...settings.value })
|
|
24
|
+
saved.value = true
|
|
25
|
+
setTimeout(() => { saved.value = false }, 2000)
|
|
26
|
+
}
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<template>
|
|
30
|
+
<div class="settings-page">
|
|
31
|
+
<h1>Notification Settings</h1>
|
|
32
|
+
<div class="settings-card">
|
|
33
|
+
<label class="setting-row">
|
|
34
|
+
<span>@Mention Notifications</span>
|
|
35
|
+
<input type="checkbox" v-model="settings.mention" />
|
|
36
|
+
</label>
|
|
37
|
+
<label class="setting-row">
|
|
38
|
+
<span>Story Updates</span>
|
|
39
|
+
<input type="checkbox" v-model="settings.story_update" />
|
|
40
|
+
</label>
|
|
41
|
+
<label class="setting-row">
|
|
42
|
+
<span>PR Review Requests</span>
|
|
43
|
+
<input type="checkbox" v-model="settings.pr_review" />
|
|
44
|
+
</label>
|
|
45
|
+
<label class="setting-row">
|
|
46
|
+
<span>Sprint Events</span>
|
|
47
|
+
<input type="checkbox" v-model="settings.sprint_event" />
|
|
48
|
+
</label>
|
|
49
|
+
<button class="btn btn--primary" @click="save">{{ saved ? 'Saved ✓' : 'Save' }}</button>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
</template>
|
|
53
|
+
|
|
54
|
+
<style scoped>
|
|
55
|
+
.settings-page { padding: 24px; max-width: 480px; }
|
|
56
|
+
h1 { font-size: 20px; font-weight: 700; margin-bottom: 20px; }
|
|
57
|
+
.settings-card { background: var(--bg-card); border-radius: var(--radius-lg); padding: 20px; display: flex; flex-direction: column; gap: 16px; }
|
|
58
|
+
.setting-row { display: flex; justify-content: space-between; align-items: center; font-size: 14px; cursor: pointer; }
|
|
59
|
+
</style>
|