specsmd 0.1.71 → 0.1.72
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.
|
@@ -710,12 +710,16 @@ function createSetDataMessage(data) {
|
|
|
710
710
|
};
|
|
711
711
|
}
|
|
712
712
|
|
|
713
|
-
const
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
713
|
+
const availableFlows = (data.availableFlows && data.availableFlows.length > 0
|
|
714
|
+
? data.availableFlows
|
|
715
|
+
: [data.flow])
|
|
716
|
+
.filter(Boolean)
|
|
717
|
+
.map((flow) => ({
|
|
718
|
+
id: flow,
|
|
719
|
+
displayName: flowDisplayName(flow),
|
|
720
|
+
icon: flowIcon(flow),
|
|
721
|
+
rootFolder: flowRootFolder(flow)
|
|
722
|
+
}));
|
|
719
723
|
|
|
720
724
|
if (data.flow === 'fire') {
|
|
721
725
|
return {
|
|
@@ -737,7 +741,7 @@ function createSetDataMessage(data) {
|
|
|
737
741
|
specsHtml: '',
|
|
738
742
|
overviewHtml: '',
|
|
739
743
|
fireData: buildFireViewData(data.snapshot),
|
|
740
|
-
availableFlows
|
|
744
|
+
availableFlows,
|
|
741
745
|
activeFlowId: data.flow
|
|
742
746
|
};
|
|
743
747
|
}
|
|
@@ -761,7 +765,7 @@ function createSetDataMessage(data) {
|
|
|
761
765
|
},
|
|
762
766
|
specsHtml: getSpecsViewHtml(webviewData),
|
|
763
767
|
overviewHtml: getOverviewViewHtml(webviewData),
|
|
764
|
-
availableFlows
|
|
768
|
+
availableFlows,
|
|
765
769
|
activeFlowId: data.flow
|
|
766
770
|
};
|
|
767
771
|
}
|
|
@@ -6167,6 +6167,31 @@
|
|
|
6167
6167
|
|
|
6168
6168
|
<!-- Resources Footer -->
|
|
6169
6169
|
<div class="resources-footer">
|
|
6170
|
+
<div class="fabriqa-card">
|
|
6171
|
+
<div class="fabriqa-brand">
|
|
6172
|
+
<div class="fabriqa-mark">FA</div>
|
|
6173
|
+
<div>
|
|
6174
|
+
<div class="fabriqa-title">specs.md by Fabriqa.AI</div>
|
|
6175
|
+
<div class="fabriqa-subtitle">Spec-native agentic development environment</div>
|
|
6176
|
+
</div>
|
|
6177
|
+
</div>
|
|
6178
|
+
<div class="fabriqa-copy">
|
|
6179
|
+
Use Fabriqa.AI with your existing AI subscription to design, run, and reuse agentic workflows around your specs. It is free to try.
|
|
6180
|
+
</div>
|
|
6181
|
+
<div class="fabriqa-actions">
|
|
6182
|
+
<div class="fabriqa-link" @click=${() => this._openExternal("https://fabriqa.ai")}>Explore Fabriqa.AI</div>
|
|
6183
|
+
<div class="fabriqa-link secondary" @click=${() => this._openExternal("https://specs.md")}>Open specs.md</div>
|
|
6184
|
+
</div>
|
|
6185
|
+
</div>
|
|
6186
|
+
<div class="dashboard-tip">
|
|
6187
|
+
<div class="dashboard-tip-title">Did you know?</div>
|
|
6188
|
+
<div class="dashboard-tip-copy">
|
|
6189
|
+
You can use the specs.md dashboard outside VS Code and VS Code variants. Run <code>npx specsmd@latest dashboard</code> from your project folder.
|
|
6190
|
+
</div>
|
|
6191
|
+
<div class="fabriqa-actions">
|
|
6192
|
+
<div class="fabriqa-link secondary" @click=${() => this._openExternal("https://specs.md/getting-started/cli-dashboard")}>Dashboard docs</div>
|
|
6193
|
+
</div>
|
|
6194
|
+
</div>
|
|
6170
6195
|
<div class="resources-title">Links</div>
|
|
6171
6196
|
<div class="resources-links">
|
|
6172
6197
|
<div class="resource-link" @click=${() => this._openExternal("https://specs.md")} title="Website">
|
|
@@ -6497,6 +6522,104 @@
|
|
|
6497
6522
|
.feedback-link:hover {
|
|
6498
6523
|
opacity: 0.8;
|
|
6499
6524
|
}
|
|
6525
|
+
|
|
6526
|
+
.fabriqa-card {
|
|
6527
|
+
padding: 12px;
|
|
6528
|
+
margin-bottom: 12px;
|
|
6529
|
+
border: 1px solid rgba(249, 115, 22, 0.35);
|
|
6530
|
+
border-radius: 6px;
|
|
6531
|
+
background: linear-gradient(135deg, rgba(249, 115, 22, 0.12), rgba(34, 197, 94, 0.08));
|
|
6532
|
+
}
|
|
6533
|
+
|
|
6534
|
+
.fabriqa-brand {
|
|
6535
|
+
display: flex;
|
|
6536
|
+
align-items: center;
|
|
6537
|
+
gap: 10px;
|
|
6538
|
+
margin-bottom: 8px;
|
|
6539
|
+
}
|
|
6540
|
+
|
|
6541
|
+
.fabriqa-mark {
|
|
6542
|
+
display: flex;
|
|
6543
|
+
align-items: center;
|
|
6544
|
+
justify-content: center;
|
|
6545
|
+
flex: 0 0 30px;
|
|
6546
|
+
height: 30px;
|
|
6547
|
+
border-radius: 6px;
|
|
6548
|
+
background: var(--status-active);
|
|
6549
|
+
color: #ffffff;
|
|
6550
|
+
font-size: 11px;
|
|
6551
|
+
font-weight: 700;
|
|
6552
|
+
}
|
|
6553
|
+
|
|
6554
|
+
.fabriqa-title {
|
|
6555
|
+
font-size: 13px;
|
|
6556
|
+
font-weight: 700;
|
|
6557
|
+
color: var(--foreground);
|
|
6558
|
+
}
|
|
6559
|
+
|
|
6560
|
+
.fabriqa-subtitle,
|
|
6561
|
+
.fabriqa-copy,
|
|
6562
|
+
.dashboard-tip-copy {
|
|
6563
|
+
font-size: 11px;
|
|
6564
|
+
line-height: 1.45;
|
|
6565
|
+
color: var(--description-foreground);
|
|
6566
|
+
}
|
|
6567
|
+
|
|
6568
|
+
.fabriqa-copy {
|
|
6569
|
+
margin-bottom: 10px;
|
|
6570
|
+
}
|
|
6571
|
+
|
|
6572
|
+
.fabriqa-actions {
|
|
6573
|
+
display: flex;
|
|
6574
|
+
flex-wrap: wrap;
|
|
6575
|
+
gap: 8px;
|
|
6576
|
+
}
|
|
6577
|
+
|
|
6578
|
+
.fabriqa-link {
|
|
6579
|
+
display: inline-flex;
|
|
6580
|
+
align-items: center;
|
|
6581
|
+
justify-content: center;
|
|
6582
|
+
padding: 6px 9px;
|
|
6583
|
+
border-radius: 5px;
|
|
6584
|
+
background: var(--status-active);
|
|
6585
|
+
color: #ffffff;
|
|
6586
|
+
font-size: 11px;
|
|
6587
|
+
font-weight: 600;
|
|
6588
|
+
cursor: pointer;
|
|
6589
|
+
}
|
|
6590
|
+
|
|
6591
|
+
.fabriqa-link.secondary {
|
|
6592
|
+
border: 1px solid var(--border-color);
|
|
6593
|
+
background: var(--editor-background);
|
|
6594
|
+
color: var(--foreground);
|
|
6595
|
+
}
|
|
6596
|
+
|
|
6597
|
+
.fabriqa-link:hover {
|
|
6598
|
+
opacity: 0.86;
|
|
6599
|
+
}
|
|
6600
|
+
|
|
6601
|
+
.dashboard-tip {
|
|
6602
|
+
padding: 10px;
|
|
6603
|
+
margin-bottom: 12px;
|
|
6604
|
+
border: 1px solid var(--border-color);
|
|
6605
|
+
border-radius: 6px;
|
|
6606
|
+
background: var(--editor-background);
|
|
6607
|
+
}
|
|
6608
|
+
|
|
6609
|
+
.dashboard-tip-title {
|
|
6610
|
+
margin-bottom: 4px;
|
|
6611
|
+
color: var(--foreground);
|
|
6612
|
+
font-size: 11px;
|
|
6613
|
+
font-weight: 700;
|
|
6614
|
+
}
|
|
6615
|
+
|
|
6616
|
+
.dashboard-tip code {
|
|
6617
|
+
padding: 1px 4px;
|
|
6618
|
+
border-radius: 4px;
|
|
6619
|
+
background: var(--background);
|
|
6620
|
+
color: var(--foreground);
|
|
6621
|
+
font-family: var(--font-family);
|
|
6622
|
+
}
|
|
6500
6623
|
`
|
|
6501
6624
|
];
|
|
6502
6625
|
__decorateClass([
|
|
@@ -5,7 +5,7 @@ const { URL } = require('url');
|
|
|
5
5
|
const { spawn } = require('child_process');
|
|
6
6
|
const crypto = require('crypto');
|
|
7
7
|
const { createWatchRuntime } = require('../runtime/watch-runtime');
|
|
8
|
-
const { detectFlow } = require('../flow-detect');
|
|
8
|
+
const { detectAvailableFlows, detectFlow } = require('../flow-detect');
|
|
9
9
|
const { loadWebDashboardData } = require('./snapshot');
|
|
10
10
|
|
|
11
11
|
const PUBLIC_DIR = path.join(__dirname, 'public');
|
|
@@ -179,9 +179,13 @@ async function startDashboardWeb(options = {}) {
|
|
|
179
179
|
const clients = new Set();
|
|
180
180
|
let watcher = null;
|
|
181
181
|
let lastData = null;
|
|
182
|
+
let activeFlow = options.flow || null;
|
|
182
183
|
|
|
183
184
|
async function loadAndBroadcast() {
|
|
184
|
-
lastData = await loadWebDashboardData({ workspacePath, flow:
|
|
185
|
+
lastData = await loadWebDashboardData({ workspacePath, flow: activeFlow });
|
|
186
|
+
if (lastData.flow) {
|
|
187
|
+
activeFlow = lastData.flow;
|
|
188
|
+
}
|
|
185
189
|
const message = lastData.webviewMessage || lastData;
|
|
186
190
|
const payload = `event: message\ndata: ${JSON.stringify(message)}\n\n`;
|
|
187
191
|
for (const client of clients) {
|
|
@@ -218,6 +222,19 @@ async function startDashboardWeb(options = {}) {
|
|
|
218
222
|
sendJson(res, 200, { ok: true, data });
|
|
219
223
|
return;
|
|
220
224
|
}
|
|
225
|
+
if (message.type === 'switchFlow') {
|
|
226
|
+
const availableFlows = detectAvailableFlows(workspacePath);
|
|
227
|
+
const requestedFlow = typeof message.flowId === 'string' ? message.flowId : null;
|
|
228
|
+
if (requestedFlow && availableFlows.includes(requestedFlow)) {
|
|
229
|
+
activeFlow = requestedFlow;
|
|
230
|
+
} else if (availableFlows.length > 0) {
|
|
231
|
+
const currentIndex = availableFlows.indexOf(activeFlow);
|
|
232
|
+
activeFlow = availableFlows[(currentIndex + 1) % availableFlows.length];
|
|
233
|
+
}
|
|
234
|
+
const data = await loadAndBroadcast();
|
|
235
|
+
sendJson(res, 200, { ok: true, data });
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
221
238
|
if (message.type === 'openExternal') {
|
|
222
239
|
const opened = openExternal(message.url);
|
|
223
240
|
sendJson(res, opened ? 200 : 400, opened
|
|
@@ -308,14 +325,9 @@ async function startDashboardWeb(options = {}) {
|
|
|
308
325
|
|
|
309
326
|
const initialData = await loadAndBroadcast();
|
|
310
327
|
if (options.watch !== false && initialData.flow) {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
} catch {
|
|
315
|
-
detection = null;
|
|
316
|
-
}
|
|
317
|
-
const flow = detection?.flow || initialData.flow;
|
|
318
|
-
const roots = buildWatchRoots(workspacePath, flow).filter((root) => fs.existsSync(root));
|
|
328
|
+
const roots = detectAvailableFlows(workspacePath)
|
|
329
|
+
.flatMap((flow) => buildWatchRoots(workspacePath, flow))
|
|
330
|
+
.filter((root) => fs.existsSync(root));
|
|
319
331
|
if (roots.length > 0) {
|
|
320
332
|
watcher = createWatchRuntime({
|
|
321
333
|
rootPaths: roots,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specsmd",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.72",
|
|
4
4
|
"description": "Multi-agent orchestration system for AI-native software development. Delivers AI-DLC, Agile, and custom SDLC flows as markdown-based agent systems.",
|
|
5
5
|
"main": "lib/installer.js",
|
|
6
6
|
"bin": {
|