vibeops-tracker 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.
- package/AUTHORS +10 -0
- package/LICENSE +21 -0
- package/README.md +209 -0
- package/bin/cli.mjs +75 -0
- package/lib/api.mjs +140 -0
- package/lib/data-dir.mjs +46 -0
- package/lib/prompt.mjs +96 -0
- package/lib/store.mjs +569 -0
- package/mcp-server.mjs +247 -0
- package/package.json +62 -0
- package/public/app.js +733 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/favicon-32.png +0 -0
- package/public/favicon.svg +56 -0
- package/public/help.html +214 -0
- package/public/icon-192.png +0 -0
- package/public/icon-512.png +0 -0
- package/public/icon.svg +56 -0
- package/public/index.html +33 -0
- package/public/manifest.webmanifest +12 -0
- package/public/styles.css +420 -0
- package/public/widget.js +554 -0
- package/server.mjs +75 -0
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
|
|
2
|
+
<!-- Tab favicon: same art as icon.svg, pre-rounded with transparent corners
|
|
3
|
+
(browsers don't mask favicons). Keep in sync with icon.svg. -->
|
|
4
|
+
<defs>
|
|
5
|
+
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
|
|
6
|
+
<stop offset="0" stop-color="#222840"/>
|
|
7
|
+
<stop offset="0.55" stop-color="#12151f"/>
|
|
8
|
+
<stop offset="1" stop-color="#0b0d12"/>
|
|
9
|
+
</linearGradient>
|
|
10
|
+
<linearGradient id="wing" x1="0.18" y1="0" x2="0.82" y2="1">
|
|
11
|
+
<stop offset="0" stop-color="#a5acff"/>
|
|
12
|
+
<stop offset="0.5" stop-color="#6a6df5"/>
|
|
13
|
+
<stop offset="1" stop-color="#4d43d6"/>
|
|
14
|
+
</linearGradient>
|
|
15
|
+
<radialGradient id="sheen" cx="0.36" cy="0.28" r="0.8">
|
|
16
|
+
<stop offset="0" stop-color="#ffffff" stop-opacity="0.34"/>
|
|
17
|
+
<stop offset="0.45" stop-color="#ffffff" stop-opacity="0.08"/>
|
|
18
|
+
<stop offset="1" stop-color="#ffffff" stop-opacity="0"/>
|
|
19
|
+
</radialGradient>
|
|
20
|
+
<filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
|
|
21
|
+
<feGaussianBlur stdDeviation="85"/>
|
|
22
|
+
</filter>
|
|
23
|
+
<filter id="soft" x="-50%" y="-50%" width="200%" height="200%">
|
|
24
|
+
<feGaussianBlur stdDeviation="26"/>
|
|
25
|
+
</filter>
|
|
26
|
+
<clipPath id="rounded">
|
|
27
|
+
<rect width="1024" height="1024" rx="230"/>
|
|
28
|
+
</clipPath>
|
|
29
|
+
</defs>
|
|
30
|
+
|
|
31
|
+
<g clip-path="url(#rounded)">
|
|
32
|
+
<rect width="1024" height="1024" fill="url(#bg)"/>
|
|
33
|
+
<circle cx="512" cy="520" r="400" fill="#818cf8" opacity="0.26" filter="url(#glow)"/>
|
|
34
|
+
|
|
35
|
+
<g transform="translate(512 540) scale(1.07) translate(-512 -540)">
|
|
36
|
+
<ellipse cx="512" cy="874" rx="268" ry="44" fill="#000000" opacity="0.45" filter="url(#soft)"/>
|
|
37
|
+
|
|
38
|
+
<path d="M 466 246 Q 420 158 364 122" stroke="#4d5779" stroke-width="22" stroke-linecap="round" fill="none"/>
|
|
39
|
+
<path d="M 558 246 Q 604 158 660 122" stroke="#4d5779" stroke-width="22" stroke-linecap="round" fill="none"/>
|
|
40
|
+
<circle cx="364" cy="122" r="21" fill="#4d5779"/>
|
|
41
|
+
<circle cx="660" cy="122" r="21" fill="#4d5779"/>
|
|
42
|
+
|
|
43
|
+
<circle cx="512" cy="318" r="118" fill="#323a5e"/>
|
|
44
|
+
|
|
45
|
+
<circle cx="512" cy="565" r="285" fill="url(#wing)"/>
|
|
46
|
+
<circle cx="512" cy="565" r="285" fill="url(#sheen)"/>
|
|
47
|
+
|
|
48
|
+
<line x1="512" y1="280" x2="512" y2="850" stroke="#12151f" stroke-width="22"/>
|
|
49
|
+
|
|
50
|
+
<circle cx="398" cy="455" r="50" fill="#3b82f6"/>
|
|
51
|
+
<circle cx="372" cy="650" r="62" fill="#f97316"/>
|
|
52
|
+
<circle cx="633" cy="448" r="54" fill="#f59e0b"/>
|
|
53
|
+
<circle cx="650" cy="655" r="70" fill="#ef4444"/>
|
|
54
|
+
</g>
|
|
55
|
+
</g>
|
|
56
|
+
</svg>
|
package/public/help.html
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>VibeOps Tracker — Help</title>
|
|
7
|
+
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
|
8
|
+
<link rel="icon" href="/favicon-32.png" type="image/png" sizes="32x32" />
|
|
9
|
+
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
|
10
|
+
<link rel="manifest" href="/manifest.webmanifest" />
|
|
11
|
+
<meta name="theme-color" content="#161a22" />
|
|
12
|
+
<link rel="stylesheet" href="/styles.css" />
|
|
13
|
+
<style>
|
|
14
|
+
#help { max-width: 880px; margin: 0 auto; padding: 24px 20px 80px; }
|
|
15
|
+
#help h2 { font-size: 20px; margin: 36px 0 10px; border-bottom: 1px solid var(--border); padding-bottom: 8px; }
|
|
16
|
+
#help h3 { font-size: 15px; margin: 22px 0 8px; color: var(--text); }
|
|
17
|
+
#help p, #help li { color: var(--text); line-height: 1.6; }
|
|
18
|
+
#help .note { color: var(--muted); font-size: 13px; }
|
|
19
|
+
#help pre {
|
|
20
|
+
background: #0b0d11; border: 1px solid var(--border); border-radius: 10px;
|
|
21
|
+
padding: 12px 14px; overflow-x: auto; font-size: 12.5px; line-height: 1.5; position: relative;
|
|
22
|
+
}
|
|
23
|
+
#help pre.prompt { border-left: 3px solid var(--accent); }
|
|
24
|
+
#help code { font-family: ui-monospace, SFMono-Regular, monospace; }
|
|
25
|
+
#help p > code, #help li > code { background: var(--panel-2); border: 1px solid var(--border); border-radius: 5px; padding: 1px 6px; font-size: 12.5px; }
|
|
26
|
+
.copy-btn {
|
|
27
|
+
position: absolute; top: 8px; right: 8px; background: var(--panel-2); color: var(--muted);
|
|
28
|
+
border: 1px solid var(--border); border-radius: 6px; padding: 3px 10px; font-size: 11px; cursor: pointer;
|
|
29
|
+
}
|
|
30
|
+
.copy-btn:hover { color: var(--text); border-color: var(--accent); }
|
|
31
|
+
.toc { background: var(--panel); border: 1px solid var(--border); border-radius: 10px; padding: 14px 18px; margin-top: 16px; }
|
|
32
|
+
.toc a { color: var(--accent); text-decoration: none; }
|
|
33
|
+
.toc li { margin: 4px 0; }
|
|
34
|
+
</style>
|
|
35
|
+
</head>
|
|
36
|
+
<body>
|
|
37
|
+
<header id="topbar">
|
|
38
|
+
<h1>VibeOps Tracker — Help</h1>
|
|
39
|
+
<a class="btn" href="/" style="margin-left:auto; text-decoration:none;">← Back to board</a>
|
|
40
|
+
</header>
|
|
41
|
+
|
|
42
|
+
<main id="help">
|
|
43
|
+
<p>VibeOps Tracker is a standalone app on <code>http://localhost:4400</code>. Issues live as one markdown
|
|
44
|
+
file each under <code>data/<project>/issues/</code> in the tracker repo — readable and greppable by
|
|
45
|
+
you and by agents. Projects' own repos contain <strong>one line</strong> of tracker-related code: the widget script tag.</p>
|
|
46
|
+
|
|
47
|
+
<div class="toc">
|
|
48
|
+
<ul>
|
|
49
|
+
<li><a href="#install">Install on a new project</a></li>
|
|
50
|
+
<li><a href="#disable">Disable / Enable / Remove</a></li>
|
|
51
|
+
<li><a href="#agents">Set up agent access (MCP)</a></li>
|
|
52
|
+
<li><a href="#usage">Ways to use it</a></li>
|
|
53
|
+
<li><a href="#prompts">Ready-made agent prompts</a></li>
|
|
54
|
+
<li><a href="#gotchas">Things to be aware of</a></li>
|
|
55
|
+
</ul>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<h2 id="install">Install on a new project</h2>
|
|
59
|
+
<p>1. Add one script tag to the project's frontend HTML (any framework, or none):</p>
|
|
60
|
+
<pre><code><script src="http://localhost:4400/widget.js" data-project="my-project" defer></script></code></pre>
|
|
61
|
+
<p>That's the whole install. A floating 🐞 button appears; submitting the dialog posts the issue
|
|
62
|
+
here with an automatic context snapshot: what you're looking at (URL, viewport, highlighted text)
|
|
63
|
+
is always attached, while the activity trail (last 10 clicks, last 10 fetches, recent JS errors
|
|
64
|
+
and failed requests) is a dialog checkbox — on by default for bugs, off for other types.
|
|
65
|
+
The project key auto-registers on first capture.</p>
|
|
66
|
+
|
|
67
|
+
<p>2. <em>Recommended:</em> tell the tracker where the project's repo lives, so generated prompts
|
|
68
|
+
point agents at the right working directory:</p>
|
|
69
|
+
<pre><code>curl -X POST http://localhost:4400/api/projects \
|
|
70
|
+
-H 'Content-Type: application/json' \
|
|
71
|
+
-d '{"key": "my-project", "name": "My Project", "repo_path": "/absolute/path/to/repo"}'</code></pre>
|
|
72
|
+
|
|
73
|
+
<p>3. <em>Optional:</em> enrich captures with app state and git info (great for worktree workflows —
|
|
74
|
+
captures then record which branch/worktree they came from):</p>
|
|
75
|
+
<pre><code><script>
|
|
76
|
+
window.IssueTracker.configure({
|
|
77
|
+
context: () => ({
|
|
78
|
+
// anything useful: current tab, selected record, feature flags…
|
|
79
|
+
git: { branch: "...", commit: "...", worktree: "..." } // if the host can know it
|
|
80
|
+
})
|
|
81
|
+
});
|
|
82
|
+
</script></code></pre>
|
|
83
|
+
|
|
84
|
+
<h2 id="disable">Disable / Enable / Remove</h2>
|
|
85
|
+
<h3>Disable temporarily</h3>
|
|
86
|
+
<p>Comment out the script tag (the only integration point), or just stop the tracker server —
|
|
87
|
+
the widget fails safe and never breaks the host app:</p>
|
|
88
|
+
<pre><code><!-- <script src="http://localhost:4400/widget.js" data-project="my-project" defer></script> --></code></pre>
|
|
89
|
+
<h3>Enable / re-enable</h3>
|
|
90
|
+
<p>Uncomment (or re-add) the script tag, and make sure VibeOps Tracker is running: <code>cd /path/to/vibeops-tracker && npm start</code> (or <code>npx vibeops-tracker</code>).</p>
|
|
91
|
+
<h3>Remove completely</h3>
|
|
92
|
+
<p>Delete the script tag and any <code>window.IssueTracker.configure</code> block from the project.
|
|
93
|
+
Nothing else lives in the project. The project's issues stay safely in the tracker's
|
|
94
|
+
<code>data/</code> dir; sweep or ignore them as you like.</p>
|
|
95
|
+
|
|
96
|
+
<h2 id="agents">Set up agent access (MCP)</h2>
|
|
97
|
+
<p>Register once (user scope = available in every project's Claude Code sessions):</p>
|
|
98
|
+
<pre><code>claude mcp add vibeops -- npx -y -p vibeops-tracker vibeops-mcp</code></pre>
|
|
99
|
+
<p>Tools: <code>get_tracker_instructions</code> (the workflow doctrine — agents should call it first),
|
|
100
|
+
<code>list_projects</code>, <code>list_issues</code>, <code>search_issues</code>, <code>get_issue</code>,
|
|
101
|
+
<code>create_issue</code>, <code>update_issue</code>, <code>add_comment</code>,
|
|
102
|
+
<code>resolve_issue</code>, <code>delete_issue</code> (permanent — requires <code>confirm: true</code>).
|
|
103
|
+
The MCP server reads the markdown files directly, so it works even when
|
|
104
|
+
the web server is down.</p>
|
|
105
|
+
|
|
106
|
+
<h2 id="usage">Ways to use it</h2>
|
|
107
|
+
<h3>Manual capture → paste into a session</h3>
|
|
108
|
+
<ol>
|
|
109
|
+
<li>Hit the 🐞 button in any app when something is off; describe seeing/expecting; submit.
|
|
110
|
+
<em>Tip:</em> highlight the exact text you're talking about <em>before</em> hitting 🐞 — it's
|
|
111
|
+
attached to the report (previewed in the dialog, removable) and quoted prominently in the
|
|
112
|
+
agent prompt. For non-bug reports the click/network/error trail is left off by default;
|
|
113
|
+
tick "Include activity trail" if it matters.</li>
|
|
114
|
+
<li>On the board, prioritize by dragging cards (order is saved into each issue's file).</li>
|
|
115
|
+
<li>Open a card → <strong>Copy Prompt</strong> → paste into a Claude Code session in that project.
|
|
116
|
+
The prompt carries the full issue, context summary, repo path, and the API workflow
|
|
117
|
+
(in-progress → resolve → in-review).</li>
|
|
118
|
+
<li>When the agent resolves, the card shows up in <strong>In Review</strong> with a PR-style
|
|
119
|
+
resolution and the list of files it touched. Verify, drag to Done, and occasionally
|
|
120
|
+
<strong>Sweep</strong> the Done column into the Archive.</li>
|
|
121
|
+
</ol>
|
|
122
|
+
<h3>Agent-driven (MCP)</h3>
|
|
123
|
+
<p>With the MCP server registered, you don't need to copy anything — just tell any session what
|
|
124
|
+
to do (see prompts below). Agents can also file issues themselves mid-task when they notice
|
|
125
|
+
something out of scope.</p>
|
|
126
|
+
<h3>Filing without a frontend</h3>
|
|
127
|
+
<p><strong>+ New issue</strong> on the board, or <code>create_issue</code> via MCP, or plain curl:</p>
|
|
128
|
+
<pre><code>curl -X POST http://localhost:4400/api/issues -H 'Content-Type: application/json' \
|
|
129
|
+
-d '{"project": "my-project", "title": "...", "type": "feature", "seeing": "...", "expecting": "..."}'</code></pre>
|
|
130
|
+
|
|
131
|
+
<h2 id="prompts">Ready-made agent prompts</h2>
|
|
132
|
+
<p class="note">Paste these into a Claude Code session running in the relevant project. Click a block to select it.</p>
|
|
133
|
+
|
|
134
|
+
<h3>Install the widget in this project</h3>
|
|
135
|
+
<pre class="prompt"><code>Install the issue-tracker capture widget into this project's frontend. Add
|
|
136
|
+
<script src="http://localhost:4400/widget.js" data-project="<project-key>" defer></script>
|
|
137
|
+
to the main HTML page(s), choosing a short kebab-case project key. Then register the repo path:
|
|
138
|
+
curl -X POST http://localhost:4400/api/projects -H 'Content-Type: application/json' -d '{"key": "<project-key>", "name": "<Readable Name>", "repo_path": "<absolute repo path>"}'
|
|
139
|
+
If the app knows its own state (current view, record ids, git branch), also add a
|
|
140
|
+
window.IssueTracker.configure({ context: () => ({...}) }) block to enrich captures.
|
|
141
|
+
Verify by loading the app and checking the 🐞 button appears bottom-right.</code></pre>
|
|
142
|
+
|
|
143
|
+
<h3>Disable or remove the widget from this project</h3>
|
|
144
|
+
<pre class="prompt"><code>Remove the issue-tracker widget from this project: find and delete the script tag that loads
|
|
145
|
+
http://localhost:4400/widget.js (and any window.IssueTracker.configure block next to it).
|
|
146
|
+
To disable temporarily instead of removing, comment the tag out. Make no other changes.</code></pre>
|
|
147
|
+
|
|
148
|
+
<h3>Pick up the next ticket and work it</h3>
|
|
149
|
+
<pre class="prompt"><code>You have access to my issue tracker via the issue-tracker MCP server. Call
|
|
150
|
+
get_tracker_instructions first, then list_issues for project "<project-key>" with status
|
|
151
|
+
"backlog" and pick the FIRST one (it's the highest priority). Read it fully with get_issue,
|
|
152
|
+
reproduce from the captured context, mark it in-progress, fix it, and finish with
|
|
153
|
+
resolve_issue (resolution summary + modified files). Then stop for my review — do not pick
|
|
154
|
+
up another ticket unless I say so.</code></pre>
|
|
155
|
+
|
|
156
|
+
<h3>Triage what's on the board</h3>
|
|
157
|
+
<pre class="prompt"><code>Using the issue-tracker MCP server, list all issues for project "<project-key>" and give me
|
|
158
|
+
a triage: which backlog items look quick vs. deep, anything that's probably a duplicate
|
|
159
|
+
(use search_issues), anything in-review waiting on me, and what you'd tackle first and why.
|
|
160
|
+
Don't change anything yet.</code></pre>
|
|
161
|
+
|
|
162
|
+
<h3>Migrate a roadmap / TODO file into the tracker</h3>
|
|
163
|
+
<pre class="prompt"><code>This project has roadmap/TODO files (ROADMAP.md, TODO.md, or similar — find them). Migrate
|
|
164
|
+
their open items into my issue tracker via the issue-tracker MCP server (or curl to
|
|
165
|
+
http://localhost:4400/api/issues if MCP is unavailable):
|
|
166
|
+
1. Call get_tracker_instructions, then search_issues per item to skip anything already filed.
|
|
167
|
+
2. For each open item, create_issue with project "<project-key>": title = the item;
|
|
168
|
+
seeing = current state/why it matters (quote the source file and line); expecting = done
|
|
169
|
+
criteria as concretely as the source allows; type = feature/improvement/bug as appropriate;
|
|
170
|
+
severity from any priority markers (default 3); tags = ["roadmap"] or ["todo"] plus topical tags.
|
|
171
|
+
3. Keep one issue per actionable item — split grouped bullets, skip completed ones.
|
|
172
|
+
4. When finished, report a table of created ids → titles, then UPDATE the source files: mark
|
|
173
|
+
migrated items with their new issue id (e.g. "→ tracked as <id>") instead of deleting them.
|
|
174
|
+
Do not start working on any of the issues.</code></pre>
|
|
175
|
+
|
|
176
|
+
<h2 id="gotchas">Things to be aware of</h2>
|
|
177
|
+
<ul>
|
|
178
|
+
<li><strong>The tracker must be running</strong> for captures, the board, and Copy Prompt:
|
|
179
|
+
<code>npm start</code> in the tracker repo (the MCP tools work even without it).</li>
|
|
180
|
+
<li><strong>Capture-time context goes stale.</strong> Snapshots record the branch/worktree/port
|
|
181
|
+
at capture time; by pickup time the repo may have moved on. Prompts and instructions tell
|
|
182
|
+
agents to verify against current state.</li>
|
|
183
|
+
<li><strong>Issue files are the source of truth</strong>, stored under <code>data/</code> on your
|
|
184
|
+
machine. That directory is gitignored — it's real local tracker data, not versioned with the code,
|
|
185
|
+
so deletes are permanent (no git history to restore from). Don't hand-edit while the server is
|
|
186
|
+
mid-write; prefer the API/MCP (agents are told this).</li>
|
|
187
|
+
<li><strong>Deletion is manual and permanent.</strong> Open any issue and use <strong>Delete issue</strong>
|
|
188
|
+
in the drawer's Danger zone (two-step confirm) to remove stale, test, or junk issues for good —
|
|
189
|
+
this works on archived issues too. Agents can delete as well, via the MCP <code>delete_issue</code>
|
|
190
|
+
tool (guarded by a required <code>confirm: true</code> flag); the doctrine tells them to reserve it
|
|
191
|
+
for clearly stale/test/duplicate issues. For real issues you've resolved, prefer Done →
|
|
192
|
+
<strong>Sweep</strong> to the Archive over deleting; link duplicates with <code>related_to</code>.</li>
|
|
193
|
+
<li><strong>Statuses:</strong> backlog → in-progress → in-review → done. Agents never set
|
|
194
|
+
<em>done</em> — that's your verification step.</li>
|
|
195
|
+
<li><strong>localhost-only by design</strong> — the API has no auth and allows any origin; don't
|
|
196
|
+
expose port 4400 beyond your machine.</li>
|
|
197
|
+
</ul>
|
|
198
|
+
</main>
|
|
199
|
+
|
|
200
|
+
<script>
|
|
201
|
+
for (const pre of document.querySelectorAll('#help pre')) {
|
|
202
|
+
const btn = document.createElement('button');
|
|
203
|
+
btn.className = 'copy-btn';
|
|
204
|
+
btn.textContent = 'Copy';
|
|
205
|
+
btn.addEventListener('click', async () => {
|
|
206
|
+
await navigator.clipboard.writeText(pre.querySelector('code').innerText);
|
|
207
|
+
btn.textContent = 'Copied!';
|
|
208
|
+
setTimeout(() => (btn.textContent = 'Copy'), 1500);
|
|
209
|
+
});
|
|
210
|
+
pre.appendChild(btn);
|
|
211
|
+
}
|
|
212
|
+
</script>
|
|
213
|
+
</body>
|
|
214
|
+
</html>
|
|
Binary file
|
|
Binary file
|
package/public/icon.svg
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
|
|
2
|
+
<!-- Issue Tracker app icon (master, full-bleed: macOS/iOS apply their own corner mask).
|
|
3
|
+
Geometric ladybug in the brand indigo; spots are the severity colors (sev2-5). -->
|
|
4
|
+
<defs>
|
|
5
|
+
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
|
|
6
|
+
<stop offset="0" stop-color="#222840"/>
|
|
7
|
+
<stop offset="0.55" stop-color="#12151f"/>
|
|
8
|
+
<stop offset="1" stop-color="#0b0d12"/>
|
|
9
|
+
</linearGradient>
|
|
10
|
+
<linearGradient id="wing" x1="0.18" y1="0" x2="0.82" y2="1">
|
|
11
|
+
<stop offset="0" stop-color="#a5acff"/>
|
|
12
|
+
<stop offset="0.5" stop-color="#6a6df5"/>
|
|
13
|
+
<stop offset="1" stop-color="#4d43d6"/>
|
|
14
|
+
</linearGradient>
|
|
15
|
+
<radialGradient id="sheen" cx="0.36" cy="0.28" r="0.8">
|
|
16
|
+
<stop offset="0" stop-color="#ffffff" stop-opacity="0.34"/>
|
|
17
|
+
<stop offset="0.45" stop-color="#ffffff" stop-opacity="0.08"/>
|
|
18
|
+
<stop offset="1" stop-color="#ffffff" stop-opacity="0"/>
|
|
19
|
+
</radialGradient>
|
|
20
|
+
<filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
|
|
21
|
+
<feGaussianBlur stdDeviation="85"/>
|
|
22
|
+
</filter>
|
|
23
|
+
<filter id="soft" x="-50%" y="-50%" width="200%" height="200%">
|
|
24
|
+
<feGaussianBlur stdDeviation="26"/>
|
|
25
|
+
</filter>
|
|
26
|
+
</defs>
|
|
27
|
+
|
|
28
|
+
<rect width="1024" height="1024" fill="url(#bg)"/>
|
|
29
|
+
<circle cx="512" cy="520" r="400" fill="#818cf8" opacity="0.26" filter="url(#glow)"/>
|
|
30
|
+
|
|
31
|
+
<g id="bug" transform="translate(512 540) scale(1.07) translate(-512 -540)">
|
|
32
|
+
<ellipse cx="512" cy="874" rx="268" ry="44" fill="#000000" opacity="0.45" filter="url(#soft)"/>
|
|
33
|
+
|
|
34
|
+
<!-- antennae -->
|
|
35
|
+
<path d="M 466 246 Q 420 158 364 122" stroke="#4d5779" stroke-width="22" stroke-linecap="round" fill="none"/>
|
|
36
|
+
<path d="M 558 246 Q 604 158 660 122" stroke="#4d5779" stroke-width="22" stroke-linecap="round" fill="none"/>
|
|
37
|
+
<circle cx="364" cy="122" r="21" fill="#4d5779"/>
|
|
38
|
+
<circle cx="660" cy="122" r="21" fill="#4d5779"/>
|
|
39
|
+
|
|
40
|
+
<!-- head -->
|
|
41
|
+
<circle cx="512" cy="318" r="118" fill="#323a5e"/>
|
|
42
|
+
|
|
43
|
+
<!-- body -->
|
|
44
|
+
<circle cx="512" cy="565" r="285" fill="url(#wing)"/>
|
|
45
|
+
<circle cx="512" cy="565" r="285" fill="url(#sheen)"/>
|
|
46
|
+
|
|
47
|
+
<!-- wing split -->
|
|
48
|
+
<line x1="512" y1="280" x2="512" y2="850" stroke="#12151f" stroke-width="22"/>
|
|
49
|
+
|
|
50
|
+
<!-- spots: severity colors -->
|
|
51
|
+
<circle cx="398" cy="455" r="50" fill="#3b82f6"/>
|
|
52
|
+
<circle cx="372" cy="650" r="62" fill="#f97316"/>
|
|
53
|
+
<circle cx="633" cy="448" r="54" fill="#f59e0b"/>
|
|
54
|
+
<circle cx="650" cy="655" r="70" fill="#ef4444"/>
|
|
55
|
+
</g>
|
|
56
|
+
</svg>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>VibeOps Tracker</title>
|
|
7
|
+
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
|
8
|
+
<link rel="icon" href="/favicon-32.png" type="image/png" sizes="32x32" />
|
|
9
|
+
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
|
10
|
+
<link rel="manifest" href="/manifest.webmanifest" />
|
|
11
|
+
<meta name="theme-color" content="#161a22" />
|
|
12
|
+
<link rel="stylesheet" href="/styles.css" />
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<header id="topbar">
|
|
16
|
+
<h1>VibeOps Tracker</h1>
|
|
17
|
+
<select id="project-select" aria-label="Project"></select>
|
|
18
|
+
<input id="search" type="search" placeholder="Search cards…" aria-label="Search issues" />
|
|
19
|
+
<span id="issue-count"></span>
|
|
20
|
+
<nav id="view-toggle">
|
|
21
|
+
<button id="view-board" class="toggle-btn on">Board</button>
|
|
22
|
+
<button id="view-archive" class="toggle-btn">Archive</button>
|
|
23
|
+
</nav>
|
|
24
|
+
<button id="new-issue" class="btn btn-primary">+ New issue</button>
|
|
25
|
+
<a id="help-link" class="btn" href="/help.html">Help</a>
|
|
26
|
+
</header>
|
|
27
|
+
<main id="board"></main>
|
|
28
|
+
<aside id="drawer" hidden></aside>
|
|
29
|
+
<div id="drawer-backdrop" hidden></div>
|
|
30
|
+
<div id="modal-root"></div>
|
|
31
|
+
<script src="/app.js"></script>
|
|
32
|
+
</body>
|
|
33
|
+
</html>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "VibeOps Tracker",
|
|
3
|
+
"short_name": "VibeOps",
|
|
4
|
+
"start_url": "/",
|
|
5
|
+
"display": "standalone",
|
|
6
|
+
"background_color": "#0f1115",
|
|
7
|
+
"theme_color": "#161a22",
|
|
8
|
+
"icons": [
|
|
9
|
+
{ "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" },
|
|
10
|
+
{ "src": "/icon-512.png", "sizes": "512x512", "type": "image/png" }
|
|
11
|
+
]
|
|
12
|
+
}
|