engineering-intelligence 1.2.0 → 1.4.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/dist/adapters/index.js +4 -4
- package/dist/adapters/index.js.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/templates.d.ts +1 -1
- package/dist/templates.d.ts.map +1 -1
- package/dist/templates.js +33 -0
- package/dist/templates.js.map +1 -1
- package/dist/visualizer/index.d.ts +1 -1
- package/dist/visualizer/index.d.ts.map +1 -1
- package/dist/visualizer/index.js +724 -57
- package/dist/visualizer/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/canonical/rules/engineering-intelligence.md +5 -1
- package/templates/canonical/skills/aidlc-lifecycle-engine/SKILL.md +39 -0
- package/templates/canonical/skills/api-backward-compatibility-engine/SKILL.md +80 -0
- package/templates/canonical/skills/context-sync-engine/SKILL.md +15 -4
- package/templates/canonical/skills/database-migration-safety-engine/SKILL.md +79 -0
- package/templates/canonical/skills/engineering-intelligence-skill/SKILL.md +59 -2
- package/templates/canonical/skills/graph-engine/SKILL.md +22 -5
- package/templates/canonical/skills/impact-analysis-engine/SKILL.md +20 -4
- package/templates/canonical/skills/knowledge-base-validator/SKILL.md +19 -3
- package/templates/canonical/skills/memory-sync-engine/SKILL.md +16 -0
- package/templates/canonical/skills/operations-readiness-engine/SKILL.md +15 -4
- package/templates/canonical/skills/requirement-scoper/SKILL.md +9 -0
- package/templates/canonical/skills/security-audit-engine/SKILL.md +10 -3
- package/templates/canonical/skills/staleness-detector/SKILL.md +19 -0
- package/templates/canonical/skills/testing-intelligence-engine/SKILL.md +37 -1
- package/templates/canonical/skills/type-safety-engine/SKILL.md +81 -0
- package/templates/canonical/workflows/engineering-intelligence.md +6 -4
- package/templates/canonical/workflows/initialize-engineering-intelligence.md +3 -2
package/dist/visualizer/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { readTemplate, SKILL_NAMES, AGENT_NAMES, WORKFLOW_NAMES } from "../templates.js";
|
|
2
4
|
const SKILL_CATALOG = {
|
|
3
5
|
"initialize-intelligence-skill": {
|
|
4
6
|
name: "Initialize Intelligence",
|
|
@@ -302,7 +304,84 @@ const WORKFLOW_CATALOG = [
|
|
|
302
304
|
],
|
|
303
305
|
},
|
|
304
306
|
];
|
|
305
|
-
|
|
307
|
+
async function scanWorkspaceFiles(dir, baseDir) {
|
|
308
|
+
const results = {};
|
|
309
|
+
try {
|
|
310
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
311
|
+
for (const entry of entries) {
|
|
312
|
+
const fullPath = path.join(dir, entry.name);
|
|
313
|
+
const relPath = path.relative(baseDir, fullPath);
|
|
314
|
+
if (entry.name === "node_modules" || entry.name === ".git") {
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
if (entry.isDirectory()) {
|
|
318
|
+
const subResults = await scanWorkspaceFiles(fullPath, baseDir);
|
|
319
|
+
Object.assign(results, subResults);
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
const ext = path.extname(entry.name).toLowerCase();
|
|
323
|
+
if ([".md", ".json", ".txt", ".yaml", ".yml"].includes(ext)) {
|
|
324
|
+
try {
|
|
325
|
+
const content = await readFile(fullPath, "utf8");
|
|
326
|
+
results[relPath] = content;
|
|
327
|
+
}
|
|
328
|
+
catch {
|
|
329
|
+
// ignore
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
catch {
|
|
336
|
+
// ignore
|
|
337
|
+
}
|
|
338
|
+
return results;
|
|
339
|
+
}
|
|
340
|
+
async function readWorkspaceIntelligence(projectRoot) {
|
|
341
|
+
const files = {};
|
|
342
|
+
for (const sub of ["knowledge-base", ".changes", ".engineering-intelligence"]) {
|
|
343
|
+
const dir = path.join(projectRoot, sub);
|
|
344
|
+
const scanned = await scanWorkspaceFiles(dir, projectRoot);
|
|
345
|
+
Object.assign(files, scanned);
|
|
346
|
+
}
|
|
347
|
+
return files;
|
|
348
|
+
}
|
|
349
|
+
export async function generateDashboardHTML(projectRoot) {
|
|
350
|
+
const vaultName = path.basename(projectRoot);
|
|
351
|
+
// Read all canonical template contents
|
|
352
|
+
const templates = {};
|
|
353
|
+
for (const name of SKILL_NAMES) {
|
|
354
|
+
try {
|
|
355
|
+
templates[`skills/${name}`] = await readTemplate("skills", name);
|
|
356
|
+
}
|
|
357
|
+
catch {
|
|
358
|
+
templates[`skills/${name}`] = "";
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
for (const name of WORKFLOW_NAMES) {
|
|
362
|
+
try {
|
|
363
|
+
templates[`workflows/${name}`] = await readTemplate("workflows", name);
|
|
364
|
+
}
|
|
365
|
+
catch {
|
|
366
|
+
templates[`workflows/${name}`] = "";
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
for (const name of AGENT_NAMES) {
|
|
370
|
+
try {
|
|
371
|
+
templates[`agents/${name}`] = await readTemplate("agents", name);
|
|
372
|
+
}
|
|
373
|
+
catch {
|
|
374
|
+
templates[`agents/${name}`] = "";
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
try {
|
|
378
|
+
templates["rules/engineering-intelligence"] = await readTemplate("rules", "engineering-intelligence");
|
|
379
|
+
}
|
|
380
|
+
catch {
|
|
381
|
+
templates["rules/engineering-intelligence"] = "";
|
|
382
|
+
}
|
|
383
|
+
// Read workspace intelligence files
|
|
384
|
+
const workspaceFiles = await readWorkspaceIntelligence(projectRoot);
|
|
306
385
|
const skillCards = Object.entries(SKILL_CATALOG)
|
|
307
386
|
.map(([id, info]) => {
|
|
308
387
|
const color = CATEGORY_COLORS[info.category] ?? "#888";
|
|
@@ -323,6 +402,11 @@ export function generateDashboardHTML() {
|
|
|
323
402
|
<div class="dep-row"><span class="dep-label">Depends on:</span>${deps}</div>
|
|
324
403
|
<div class="dep-row"><span class="dep-label">Used by:</span>${consumers}</div>
|
|
325
404
|
</div>
|
|
405
|
+
<div class="skill-actions">
|
|
406
|
+
<button class="btn btn-sm btn-view" onclick="viewTemplate('skills/${id}', '${info.name}')">View Template</button>
|
|
407
|
+
<button class="btn btn-sm btn-view-workspace" id="ws-btn-${id}" style="display:none;" onclick="viewSkillInWorkspace('${id}')">View Workspace</button>
|
|
408
|
+
<a class="btn btn-sm btn-obsidian" id="obsidian-btn-${id}" style="display:none;" target="_blank">Obsidian</a>
|
|
409
|
+
</div>
|
|
326
410
|
</div>`;
|
|
327
411
|
})
|
|
328
412
|
.join("\n");
|
|
@@ -344,7 +428,14 @@ export function generateDashboardHTML() {
|
|
|
344
428
|
: '<span class="wf-badge wf-readwrite">Read-Write</span>';
|
|
345
429
|
return `<div class="wf-card">
|
|
346
430
|
<div class="wf-header">
|
|
347
|
-
|
|
431
|
+
<div class="wf-header-top">
|
|
432
|
+
${typeBadge}
|
|
433
|
+
<div class="wf-actions">
|
|
434
|
+
<button class="btn btn-sm btn-view" onclick="viewTemplate('workflows/${wf.name}', '${wf.name}')">View Template</button>
|
|
435
|
+
<button class="btn btn-sm btn-view-workspace" id="ws-btn-${wf.name}" style="display:none;" onclick="viewWorkflowInWorkspace('${wf.name}')">View Workspace</button>
|
|
436
|
+
<a class="btn btn-sm btn-obsidian" id="obsidian-btn-${wf.name}" style="display:none;" target="_blank">Obsidian</a>
|
|
437
|
+
</div>
|
|
438
|
+
</div>
|
|
348
439
|
<h3>${wf.name}</h3>
|
|
349
440
|
<p>${wf.description}</p>
|
|
350
441
|
</div>
|
|
@@ -352,31 +443,22 @@ export function generateDashboardHTML() {
|
|
|
352
443
|
</div>`;
|
|
353
444
|
}).join("\n");
|
|
354
445
|
const agentCards = [
|
|
355
|
-
{ name: "Engineering Orchestrator", role: "Classifies requests, routes work, coordinates agents", skills: "All skills", color: "#6366f1" },
|
|
356
|
-
{ name: "Change Agent", role: "Implements code changes, adds tests, collects evidence", skills: "engineering-intelligence-skill, testing-intelligence-engine", color: "#22c55e" },
|
|
357
|
-
{ name: "Quality Agent", role: "Validates correctness, runs tests, reviews architecture", skills: "engineering-change-review, testing-intelligence-engine", color: "#ef4444" },
|
|
358
|
-
{ name: "Knowledge Agent", role: "Maintains all intelligence artifacts", skills: "All sync engines, graph-engine, change-history-engine", color: "#06b6d4" },
|
|
359
|
-
{ name: "Product Analyst", role: "Scopes requirements, asks clarifying questions, generates prompts", skills: "requirement-scoper, deep-project-knowledge-extractor", color: "#a855f7" },
|
|
446
|
+
{ name: "Engineering Orchestrator", role: "Classifies requests, routes work, coordinates agents", id: "engineering-orchestrator", skills: "All skills", color: "#6366f1" },
|
|
447
|
+
{ name: "Change Agent", role: "Implements code changes, adds tests, collects evidence", id: "change-agent", skills: "engineering-intelligence-skill, testing-intelligence-engine", color: "#22c55e" },
|
|
448
|
+
{ name: "Quality Agent", role: "Validates correctness, runs tests, reviews architecture", id: "quality-agent", skills: "engineering-change-review, testing-intelligence-engine", color: "#ef4444" },
|
|
449
|
+
{ name: "Knowledge Agent", role: "Maintains all intelligence artifacts", id: "knowledge-agent", skills: "All sync engines, graph-engine, change-history-engine", color: "#06b6d4" },
|
|
450
|
+
{ name: "Product Analyst", role: "Scopes requirements, asks clarifying questions, generates prompts", id: "product-analyst", skills: "requirement-scoper, deep-project-knowledge-extractor", color: "#a855f7" },
|
|
360
451
|
].map((agent) => `<div class="agent-card">
|
|
361
452
|
<div class="agent-icon" style="background:${agent.color}">${agent.name.charAt(0)}</div>
|
|
362
453
|
<div class="agent-body">
|
|
363
|
-
<
|
|
454
|
+
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:0.25rem;">
|
|
455
|
+
<h3>${agent.name}</h3>
|
|
456
|
+
<button class="btn btn-sm btn-view" onclick="viewTemplate('agents/${agent.id}', '${agent.name}')">View Instruction</button>
|
|
457
|
+
</div>
|
|
364
458
|
<p>${agent.role}</p>
|
|
365
459
|
<div class="agent-skills"><strong>Skills:</strong> ${agent.skills}</div>
|
|
366
460
|
</div>
|
|
367
461
|
</div>`).join("\n");
|
|
368
|
-
const artifactTree = `
|
|
369
|
-
<div class="tree">
|
|
370
|
-
<div class="tree-node root">knowledge-base/<span class="tree-count">22 documents</span></div>
|
|
371
|
-
<div class="tree-node root">.engineering-intelligence/
|
|
372
|
-
<div class="tree-node">memory/<span class="tree-count">5 documents</span></div>
|
|
373
|
-
<div class="tree-node">context/<span class="tree-count">6 maps</span></div>
|
|
374
|
-
<div class="tree-node">events/<span class="tree-count">6 guides</span></div>
|
|
375
|
-
<div class="tree-node">graph/<span class="tree-count">5 JSON + 1 map</span></div>
|
|
376
|
-
<div class="tree-node">reports/<span class="tree-count">IMP-*/REV-*/DISCOVERY/FRESHNESS/GIT/DEBUG reports</span></div>
|
|
377
|
-
</div>
|
|
378
|
-
<div class="tree-node root">.changes/<span class="tree-count">CHG-* records</span></div>
|
|
379
|
-
</div>`;
|
|
380
462
|
const categoryFilters = Object.entries(CATEGORY_LABELS)
|
|
381
463
|
.map(([id, label]) => `<button class="filter-btn active" data-filter="${id}" style="--btn-color:${CATEGORY_COLORS[id]}">${label}</button>`)
|
|
382
464
|
.join("\n");
|
|
@@ -386,6 +468,8 @@ export function generateDashboardHTML() {
|
|
|
386
468
|
<meta charset="UTF-8">
|
|
387
469
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
388
470
|
<title>Engineering Intelligence — Dashboard</title>
|
|
471
|
+
<!-- Prism.js for code highlight -->
|
|
472
|
+
<link href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism-tomorrow.min.css" rel="stylesheet" />
|
|
389
473
|
<style>
|
|
390
474
|
:root {
|
|
391
475
|
--bg: #0a0a0f;
|
|
@@ -395,6 +479,7 @@ export function generateDashboardHTML() {
|
|
|
395
479
|
--text: #e4e4ef;
|
|
396
480
|
--text-dim: #8888a0;
|
|
397
481
|
--accent: #6366f1;
|
|
482
|
+
--accent-hover: #4f46e5;
|
|
398
483
|
--radius: 12px;
|
|
399
484
|
--glass: rgba(18, 18, 26, 0.8);
|
|
400
485
|
}
|
|
@@ -425,6 +510,13 @@ body {
|
|
|
425
510
|
margin-bottom: 0.5rem;
|
|
426
511
|
}
|
|
427
512
|
.header p { color: var(--text-dim); font-size: 1.1rem; }
|
|
513
|
+
.header .header-controls {
|
|
514
|
+
margin-top: 1.5rem;
|
|
515
|
+
display: flex;
|
|
516
|
+
justify-content: center;
|
|
517
|
+
gap: 0.75rem;
|
|
518
|
+
flex-wrap: wrap;
|
|
519
|
+
}
|
|
428
520
|
.header .stats {
|
|
429
521
|
display: flex;
|
|
430
522
|
justify-content: center;
|
|
@@ -441,6 +533,47 @@ body {
|
|
|
441
533
|
.stat-num { font-size: 2rem; font-weight: 700; color: var(--accent); }
|
|
442
534
|
.stat-label { font-size: 0.85rem; color: var(--text-dim); }
|
|
443
535
|
|
|
536
|
+
/* Buttons */
|
|
537
|
+
.btn {
|
|
538
|
+
padding: 0.5rem 1rem;
|
|
539
|
+
border-radius: 6px;
|
|
540
|
+
border: 1px solid var(--border);
|
|
541
|
+
background: var(--surface);
|
|
542
|
+
color: var(--text);
|
|
543
|
+
font-size: 0.85rem;
|
|
544
|
+
cursor: pointer;
|
|
545
|
+
transition: all 0.2s;
|
|
546
|
+
text-decoration: none;
|
|
547
|
+
display: inline-flex;
|
|
548
|
+
align-items: center;
|
|
549
|
+
gap: 0.4rem;
|
|
550
|
+
}
|
|
551
|
+
.btn:hover {
|
|
552
|
+
background: var(--surface-hover);
|
|
553
|
+
border-color: var(--accent);
|
|
554
|
+
}
|
|
555
|
+
.btn-primary {
|
|
556
|
+
background: var(--accent);
|
|
557
|
+
border-color: var(--accent);
|
|
558
|
+
}
|
|
559
|
+
.btn-primary:hover {
|
|
560
|
+
background: var(--accent-hover);
|
|
561
|
+
border-color: var(--accent-hover);
|
|
562
|
+
}
|
|
563
|
+
.btn-sm {
|
|
564
|
+
padding: 0.25rem 0.6rem;
|
|
565
|
+
font-size: 0.75rem;
|
|
566
|
+
border-radius: 4px;
|
|
567
|
+
}
|
|
568
|
+
.btn-obsidian {
|
|
569
|
+
border-color: #a855f7;
|
|
570
|
+
color: #d8b4fe;
|
|
571
|
+
}
|
|
572
|
+
.btn-obsidian:hover {
|
|
573
|
+
background: rgba(168, 85, 247, 0.1);
|
|
574
|
+
border-color: #c084fc;
|
|
575
|
+
}
|
|
576
|
+
|
|
444
577
|
/* Tabs */
|
|
445
578
|
.tabs {
|
|
446
579
|
display: flex;
|
|
@@ -490,6 +623,9 @@ body {
|
|
|
490
623
|
border: 1px solid var(--border);
|
|
491
624
|
border-radius: var(--radius);
|
|
492
625
|
padding: 1.25rem;
|
|
626
|
+
display: flex;
|
|
627
|
+
flex-direction: column;
|
|
628
|
+
justify-content: space-between;
|
|
493
629
|
transition: all 0.2s;
|
|
494
630
|
}
|
|
495
631
|
.skill-card:hover { background: var(--surface-hover); border-color: var(--accent); transform: translateY(-2px); }
|
|
@@ -509,11 +645,12 @@ body {
|
|
|
509
645
|
.skill-desc { color: var(--text-dim); font-size: 0.9rem; margin-bottom: 0.75rem; }
|
|
510
646
|
.skill-id { margin-bottom: 0.75rem; }
|
|
511
647
|
.skill-id code { background: var(--bg); padding: 0.2rem 0.5rem; border-radius: 4px; font-size: 0.8rem; color: var(--accent); }
|
|
512
|
-
.skill-deps { font-size: 0.85rem; }
|
|
648
|
+
.skill-deps { font-size: 0.85rem; margin-bottom: 1rem; }
|
|
513
649
|
.dep-row { margin-bottom: 0.4rem; display: flex; flex-wrap: wrap; align-items: center; gap: 0.3rem; }
|
|
514
650
|
.dep-label { color: var(--text-dim); font-weight: 500; margin-right: 0.3rem; }
|
|
515
651
|
.dep-tag { background: var(--bg); padding: 0.15rem 0.5rem; border-radius: 4px; font-size: 0.75rem; }
|
|
516
652
|
.dep-none { color: var(--text-dim); font-size: 0.75rem; font-style: italic; }
|
|
653
|
+
.skill-actions { display: flex; gap: 0.4rem; flex-wrap: wrap; }
|
|
517
654
|
|
|
518
655
|
/* Workflow cards */
|
|
519
656
|
.wf-grid { display: flex; flex-direction: column; gap: 1.5rem; }
|
|
@@ -526,6 +663,7 @@ body {
|
|
|
526
663
|
}
|
|
527
664
|
.wf-card:hover { border-color: var(--accent); }
|
|
528
665
|
.wf-header { margin-bottom: 1rem; }
|
|
666
|
+
.wf-header-top { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem; }
|
|
529
667
|
.wf-header h3 { font-size: 1.1rem; margin-bottom: 0.25rem; }
|
|
530
668
|
.wf-header p { color: var(--text-dim); font-size: 0.9rem; }
|
|
531
669
|
.wf-badge {
|
|
@@ -535,7 +673,6 @@ body {
|
|
|
535
673
|
font-size: 0.7rem;
|
|
536
674
|
font-weight: 600;
|
|
537
675
|
text-transform: uppercase;
|
|
538
|
-
margin-bottom: 0.5rem;
|
|
539
676
|
}
|
|
540
677
|
.wf-readonly { background: #1e3a5f; color: #60a5fa; }
|
|
541
678
|
.wf-readwrite { background: #1a3d2a; color: #4ade80; }
|
|
@@ -571,11 +708,12 @@ body {
|
|
|
571
708
|
.step-name { font-size: 0.85rem; font-weight: 600; }
|
|
572
709
|
.step-skill { font-size: 0.75rem; }
|
|
573
710
|
.step-arrow { color: var(--text-dim); font-size: 1.2rem; flex-shrink: 0; }
|
|
711
|
+
.wf-actions { display: flex; gap: 0.4rem; }
|
|
574
712
|
|
|
575
713
|
/* Agent cards */
|
|
576
714
|
.agent-grid {
|
|
577
715
|
display: grid;
|
|
578
|
-
grid-template-columns: repeat(auto-fill, minmax(
|
|
716
|
+
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
|
|
579
717
|
gap: 1rem;
|
|
580
718
|
}
|
|
581
719
|
.agent-card {
|
|
@@ -600,45 +738,265 @@ body {
|
|
|
600
738
|
color: white;
|
|
601
739
|
flex-shrink: 0;
|
|
602
740
|
}
|
|
603
|
-
.agent-body
|
|
741
|
+
.agent-body { flex: 1; }
|
|
742
|
+
.agent-body h3 { font-size: 1rem; }
|
|
604
743
|
.agent-body p { color: var(--text-dim); font-size: 0.85rem; margin-bottom: 0.5rem; }
|
|
605
744
|
.agent-skills { font-size: 0.8rem; color: var(--text-dim); }
|
|
606
745
|
|
|
607
|
-
/*
|
|
608
|
-
.
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
746
|
+
/* Explorer Layout */
|
|
747
|
+
.explorer-layout {
|
|
748
|
+
display: grid;
|
|
749
|
+
grid-template-columns: 280px 1fr;
|
|
750
|
+
gap: 1.5rem;
|
|
751
|
+
background: var(--surface);
|
|
752
|
+
border: 1px solid var(--border);
|
|
753
|
+
border-radius: var(--radius);
|
|
754
|
+
min-height: 600px;
|
|
755
|
+
overflow: hidden;
|
|
756
|
+
}
|
|
757
|
+
.explorer-sidebar {
|
|
758
|
+
border-right: 1px solid var(--border);
|
|
759
|
+
padding: 1.25rem;
|
|
760
|
+
display: flex;
|
|
761
|
+
flex-direction: column;
|
|
762
|
+
gap: 1rem;
|
|
763
|
+
background: rgba(10, 10, 15, 0.3);
|
|
764
|
+
}
|
|
765
|
+
.explorer-sidebar h3 {
|
|
766
|
+
font-size: 0.95rem;
|
|
767
|
+
text-transform: uppercase;
|
|
768
|
+
letter-spacing: 0.05em;
|
|
769
|
+
color: var(--text-dim);
|
|
770
|
+
}
|
|
771
|
+
.file-list {
|
|
772
|
+
display: flex;
|
|
773
|
+
flex-direction: column;
|
|
774
|
+
gap: 1rem;
|
|
775
|
+
overflow-y: auto;
|
|
776
|
+
max-height: 550px;
|
|
777
|
+
}
|
|
778
|
+
.file-group-header {
|
|
779
|
+
font-size: 0.8rem;
|
|
780
|
+
font-weight: 700;
|
|
781
|
+
color: var(--accent);
|
|
782
|
+
margin-bottom: 0.4rem;
|
|
783
|
+
text-transform: capitalize;
|
|
784
|
+
}
|
|
785
|
+
.file-group-items {
|
|
786
|
+
display: flex;
|
|
787
|
+
flex-direction: column;
|
|
788
|
+
gap: 0.2rem;
|
|
789
|
+
padding-left: 0.5rem;
|
|
790
|
+
}
|
|
791
|
+
.file-item {
|
|
792
|
+
padding: 0.4rem 0.6rem;
|
|
793
|
+
border-radius: 6px;
|
|
613
794
|
font-family: 'JetBrains Mono', 'Fira Code', monospace;
|
|
614
|
-
font-size: 0.
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
795
|
+
font-size: 0.8rem;
|
|
796
|
+
cursor: pointer;
|
|
797
|
+
color: var(--text-dim);
|
|
798
|
+
transition: all 0.15s;
|
|
799
|
+
display: flex;
|
|
800
|
+
align-items: center;
|
|
801
|
+
gap: 0.4rem;
|
|
802
|
+
}
|
|
803
|
+
.file-item::before {
|
|
804
|
+
content: '📄';
|
|
805
|
+
font-size: 0.75rem;
|
|
806
|
+
}
|
|
807
|
+
.file-item:hover {
|
|
808
|
+
background: rgba(255,255,255,0.05);
|
|
809
|
+
color: var(--text);
|
|
810
|
+
}
|
|
811
|
+
.file-item.active {
|
|
812
|
+
background: rgba(99, 102, 241, 0.15);
|
|
813
|
+
color: #818cf8;
|
|
628
814
|
font-weight: 600;
|
|
815
|
+
}
|
|
816
|
+
.explorer-content {
|
|
817
|
+
display: flex;
|
|
818
|
+
flex-direction: column;
|
|
819
|
+
height: 650px;
|
|
820
|
+
}
|
|
821
|
+
.explorer-header {
|
|
822
|
+
padding: 1rem 1.5rem;
|
|
823
|
+
border-bottom: 1px solid var(--border);
|
|
824
|
+
display: flex;
|
|
825
|
+
justify-content: space-between;
|
|
826
|
+
align-items: center;
|
|
827
|
+
background: rgba(10, 10, 15, 0.2);
|
|
828
|
+
}
|
|
829
|
+
.explorer-path {
|
|
830
|
+
font-family: 'JetBrains Mono', 'Fira Code', monospace;
|
|
831
|
+
font-size: 0.85rem;
|
|
629
832
|
color: var(--accent);
|
|
630
|
-
margin-top: 0.75rem;
|
|
631
833
|
}
|
|
632
|
-
.
|
|
633
|
-
.
|
|
834
|
+
.explorer-body {
|
|
835
|
+
padding: 1.5rem;
|
|
836
|
+
overflow-y: auto;
|
|
837
|
+
flex: 1;
|
|
838
|
+
background: rgba(10,10,15,0.1);
|
|
839
|
+
}
|
|
840
|
+
.empty-state {
|
|
841
|
+
display: flex;
|
|
842
|
+
flex-direction: column;
|
|
843
|
+
align-items: center;
|
|
844
|
+
justify-content: center;
|
|
845
|
+
height: 100%;
|
|
634
846
|
color: var(--text-dim);
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
847
|
+
text-align: center;
|
|
848
|
+
padding: 2rem;
|
|
849
|
+
}
|
|
850
|
+
.empty-icon { font-size: 3rem; margin-bottom: 1rem; opacity: 0.5; }
|
|
851
|
+
.empty-state p { max-width: 400px; font-size: 0.9rem; }
|
|
852
|
+
|
|
853
|
+
/* Modal */
|
|
854
|
+
.modal {
|
|
855
|
+
display: none;
|
|
856
|
+
position: fixed;
|
|
857
|
+
z-index: 1000;
|
|
858
|
+
left: 0;
|
|
859
|
+
top: 0;
|
|
860
|
+
width: 100%;
|
|
861
|
+
height: 100%;
|
|
862
|
+
background: rgba(0, 0, 0, 0.75);
|
|
863
|
+
backdrop-filter: blur(4px);
|
|
864
|
+
align-items: center;
|
|
865
|
+
justify-content: center;
|
|
866
|
+
}
|
|
867
|
+
.modal.active { display: flex; }
|
|
868
|
+
.modal-content {
|
|
869
|
+
background: var(--surface);
|
|
870
|
+
border: 1px solid var(--border);
|
|
871
|
+
border-radius: var(--radius);
|
|
872
|
+
width: 90%;
|
|
873
|
+
max-width: 900px;
|
|
874
|
+
height: 80vh;
|
|
875
|
+
display: flex;
|
|
876
|
+
flex-direction: column;
|
|
877
|
+
box-shadow: 0 20px 25px -5px rgba(0,0,0,0.5);
|
|
878
|
+
animation: modalEnter 0.2s ease-out;
|
|
879
|
+
}
|
|
880
|
+
@keyframes modalEnter {
|
|
881
|
+
from { transform: scale(0.95); opacity: 0; }
|
|
882
|
+
to { transform: scale(1); opacity: 1; }
|
|
883
|
+
}
|
|
884
|
+
.modal-header {
|
|
885
|
+
padding: 1.25rem 1.5rem;
|
|
886
|
+
border-bottom: 1px solid var(--border);
|
|
887
|
+
display: flex;
|
|
888
|
+
justify-content: space-between;
|
|
889
|
+
align-items: center;
|
|
890
|
+
}
|
|
891
|
+
.modal-header h3 { font-size: 1.2rem; font-weight: 700; color: var(--accent); }
|
|
892
|
+
.modal-actions { display: flex; align-items: center; gap: 1rem; }
|
|
893
|
+
.modal-close {
|
|
894
|
+
background: transparent;
|
|
895
|
+
border: none;
|
|
896
|
+
color: var(--text-dim);
|
|
897
|
+
font-size: 1.8rem;
|
|
898
|
+
cursor: pointer;
|
|
899
|
+
transition: color 0.15s;
|
|
900
|
+
line-height: 1;
|
|
901
|
+
}
|
|
902
|
+
.modal-close:hover { color: var(--text); }
|
|
903
|
+
.modal-body {
|
|
904
|
+
padding: 1.5rem;
|
|
905
|
+
overflow-y: auto;
|
|
906
|
+
flex: 1;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
/* Markdown Rendering Custom Styles */
|
|
910
|
+
.markdown-body {
|
|
911
|
+
font-size: 0.95rem;
|
|
912
|
+
color: var(--text);
|
|
913
|
+
}
|
|
914
|
+
.markdown-body h1, .markdown-body h2, .markdown-body h3 {
|
|
915
|
+
margin-top: 1.5rem;
|
|
916
|
+
margin-bottom: 0.8rem;
|
|
917
|
+
font-weight: 700;
|
|
918
|
+
border-bottom: 1px solid var(--border);
|
|
919
|
+
padding-bottom: 0.3rem;
|
|
920
|
+
color: #fff;
|
|
921
|
+
}
|
|
922
|
+
.markdown-body h1 { font-size: 1.6rem; }
|
|
923
|
+
.markdown-body h2 { font-size: 1.3rem; }
|
|
924
|
+
.markdown-body h3 { font-size: 1.1rem; }
|
|
925
|
+
.markdown-body p, .markdown-body ul, .markdown-body ol {
|
|
926
|
+
margin-bottom: 1rem;
|
|
927
|
+
color: #c9c9d6;
|
|
928
|
+
}
|
|
929
|
+
.markdown-body ul, .markdown-body ol {
|
|
930
|
+
padding-left: 1.5rem;
|
|
931
|
+
}
|
|
932
|
+
.markdown-body li { margin-bottom: 0.25rem; }
|
|
933
|
+
.markdown-body pre {
|
|
934
|
+
background: #1e1e2f !important;
|
|
935
|
+
border: 1px solid var(--border);
|
|
936
|
+
border-radius: 8px;
|
|
937
|
+
padding: 1rem;
|
|
938
|
+
margin-bottom: 1rem;
|
|
939
|
+
overflow-x: auto;
|
|
940
|
+
}
|
|
941
|
+
.markdown-body code {
|
|
942
|
+
font-family: 'JetBrains Mono', 'Fira Code', monospace;
|
|
943
|
+
font-size: 0.85rem;
|
|
944
|
+
background: rgba(255,255,255,0.06);
|
|
945
|
+
padding: 0.15rem 0.3rem;
|
|
946
|
+
border-radius: 4px;
|
|
947
|
+
color: #f472b6;
|
|
948
|
+
}
|
|
949
|
+
.markdown-body pre code {
|
|
950
|
+
background: transparent;
|
|
951
|
+
padding: 0;
|
|
952
|
+
color: inherit;
|
|
953
|
+
}
|
|
954
|
+
.markdown-body table {
|
|
955
|
+
width: 100%;
|
|
956
|
+
border-collapse: collapse;
|
|
957
|
+
margin-bottom: 1.5rem;
|
|
958
|
+
font-size: 0.85rem;
|
|
959
|
+
}
|
|
960
|
+
.markdown-body th, .markdown-body td {
|
|
961
|
+
border: 1px solid var(--border);
|
|
962
|
+
padding: 0.5rem 0.75rem;
|
|
963
|
+
text-align: left;
|
|
964
|
+
}
|
|
965
|
+
.markdown-body th {
|
|
966
|
+
background: rgba(255,255,255,0.03);
|
|
967
|
+
font-weight: 600;
|
|
968
|
+
}
|
|
969
|
+
.markdown-body blockquote {
|
|
970
|
+
border-left: 4px solid var(--accent);
|
|
971
|
+
padding-left: 1rem;
|
|
972
|
+
margin-bottom: 1rem;
|
|
973
|
+
color: var(--text-dim);
|
|
974
|
+
font-style: italic;
|
|
975
|
+
}
|
|
976
|
+
.markdown-body a {
|
|
977
|
+
color: #38bdf8;
|
|
978
|
+
text-decoration: none;
|
|
979
|
+
}
|
|
980
|
+
.markdown-body a:hover {
|
|
981
|
+
text-decoration: underline;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
/* Mermaid Graph Rendering styling */
|
|
985
|
+
.mermaid {
|
|
986
|
+
background: rgba(255,255,255,0.02);
|
|
987
|
+
border: 1px solid var(--border);
|
|
988
|
+
border-radius: var(--radius);
|
|
989
|
+
padding: 1.5rem;
|
|
990
|
+
margin-bottom: 1.5rem;
|
|
991
|
+
display: flex;
|
|
992
|
+
justify-content: center;
|
|
638
993
|
}
|
|
639
994
|
|
|
640
995
|
/* Responsive */
|
|
641
|
-
@media (max-width:
|
|
996
|
+
@media (max-width: 900px) {
|
|
997
|
+
.explorer-layout { grid-template-columns: 1fr; }
|
|
998
|
+
.explorer-sidebar { border-right: none; border-bottom: 1px solid var(--border); height: 250px; }
|
|
999
|
+
.explorer-content { height: 450px; }
|
|
642
1000
|
.header h1 { font-size: 1.8rem; }
|
|
643
1001
|
.header .stats { flex-wrap: wrap; }
|
|
644
1002
|
.skill-grid { grid-template-columns: 1fr; }
|
|
@@ -652,11 +1010,16 @@ body {
|
|
|
652
1010
|
<div class="header">
|
|
653
1011
|
<h1>Engineering Intelligence OS</h1>
|
|
654
1012
|
<p>Graph-backed engineering intelligence toolkit</p>
|
|
1013
|
+
<div class="header-controls">
|
|
1014
|
+
<button class="btn btn-primary" onclick="viewTemplate('rules/engineering-intelligence', 'Engineering Intelligence Rules')">View Rules Template</button>
|
|
1015
|
+
<button class="btn btn-view-workspace" id="ws-rules-btn" style="display:none;" onclick="viewRulesInWorkspace()">View Workspace Rules</button>
|
|
1016
|
+
<a class="btn btn-obsidian" id="obsidian-rules-btn" style="display:none;" target="_blank">Open Rules in Obsidian</a>
|
|
1017
|
+
</div>
|
|
655
1018
|
<div class="stats">
|
|
656
1019
|
<div class="stat"><div class="stat-num">${SKILL_NAMES.length}</div><div class="stat-label">Skills</div></div>
|
|
657
1020
|
<div class="stat"><div class="stat-num">${AGENT_NAMES.length}</div><div class="stat-label">Agents</div></div>
|
|
658
1021
|
<div class="stat"><div class="stat-num">${WORKFLOW_NAMES.length}</div><div class="stat-label">Workflows</div></div>
|
|
659
|
-
<div class="stat"><div class="stat-num">
|
|
1022
|
+
<div class="stat"><div class="stat-num" id="workspace-files-count">0</div><div class="stat-label">Workspace Files</div></div>
|
|
660
1023
|
</div>
|
|
661
1024
|
</div>
|
|
662
1025
|
|
|
@@ -664,7 +1027,7 @@ body {
|
|
|
664
1027
|
<button class="tab active" data-tab="skills">Skills</button>
|
|
665
1028
|
<button class="tab" data-tab="workflows">Workflows</button>
|
|
666
1029
|
<button class="tab" data-tab="agents">Agents</button>
|
|
667
|
-
<button class="tab" data-tab="artifacts">
|
|
1030
|
+
<button class="tab" data-tab="artifacts">Workspace Explorer</button>
|
|
668
1031
|
</div>
|
|
669
1032
|
|
|
670
1033
|
<div class="tab-content active" id="skills">
|
|
@@ -681,21 +1044,89 @@ body {
|
|
|
681
1044
|
</div>
|
|
682
1045
|
|
|
683
1046
|
<div class="tab-content" id="artifacts">
|
|
684
|
-
<
|
|
685
|
-
|
|
686
|
-
|
|
1047
|
+
<div class="explorer-layout">
|
|
1048
|
+
<div class="explorer-sidebar">
|
|
1049
|
+
<h3>Intelligence Artifacts</h3>
|
|
1050
|
+
<div id="fileList" class="file-list"></div>
|
|
1051
|
+
</div>
|
|
1052
|
+
<div class="explorer-content">
|
|
1053
|
+
<div class="explorer-header">
|
|
1054
|
+
<span id="explorerFilePath" class="explorer-path">Select an artifact to view</span>
|
|
1055
|
+
<a id="explorerObsidianLink" href="#" class="btn btn-obsidian hidden" target="_blank">Open in Obsidian</a>
|
|
1056
|
+
</div>
|
|
1057
|
+
<div id="explorerFileContent" class="explorer-body">
|
|
1058
|
+
<div class="empty-state">
|
|
1059
|
+
<div class="empty-icon">📁</div>
|
|
1060
|
+
<p>Choose an intelligence or lifecycle artifact from the list to view its contents, Mermaid architecture map, or open it in Obsidian.</p>
|
|
1061
|
+
</div>
|
|
1062
|
+
</div>
|
|
1063
|
+
</div>
|
|
1064
|
+
</div>
|
|
1065
|
+
</div>
|
|
1066
|
+
</div>
|
|
1067
|
+
|
|
1068
|
+
<!-- Modal File Viewer -->
|
|
1069
|
+
<div id="fileModal" class="modal">
|
|
1070
|
+
<div class="modal-content">
|
|
1071
|
+
<div class="modal-header">
|
|
1072
|
+
<h3 id="modalTitle">File Viewer</h3>
|
|
1073
|
+
<div class="modal-actions">
|
|
1074
|
+
<a id="modalObsidianLink" href="#" class="btn btn-obsidian hidden" target="_blank">Open in Obsidian</a>
|
|
1075
|
+
<button class="modal-close" onclick="closeModal()">×</button>
|
|
1076
|
+
</div>
|
|
1077
|
+
</div>
|
|
1078
|
+
<div id="modalBody" class="modal-body markdown-body"></div>
|
|
687
1079
|
</div>
|
|
688
1080
|
</div>
|
|
689
1081
|
|
|
1082
|
+
<!-- Scripts -->
|
|
1083
|
+
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
1084
|
+
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/prism.min.js"></script>
|
|
1085
|
+
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-markdown.min.js"></script>
|
|
1086
|
+
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-json.min.js"></script>
|
|
1087
|
+
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
|
|
1088
|
+
|
|
690
1089
|
<script>
|
|
1090
|
+
// Data payloads injected from server-side
|
|
1091
|
+
const TEMPLATES = ${JSON.stringify(templates)};
|
|
1092
|
+
const WORKSPACE_FILES = ${JSON.stringify(workspaceFiles)};
|
|
1093
|
+
const VAULT_NAME = ${JSON.stringify(vaultName)};
|
|
1094
|
+
const SKILL_CATALOG = ${JSON.stringify(SKILL_CATALOG)};
|
|
1095
|
+
const WORKFLOW_CATALOG = ${JSON.stringify(WORKFLOW_CATALOG)};
|
|
1096
|
+
|
|
1097
|
+
// Initialize Mermaid
|
|
1098
|
+
mermaid.initialize({ startOnLoad: false, theme: 'dark', securityLevel: 'loose' });
|
|
1099
|
+
|
|
1100
|
+
// Marked custom renderer to intercept Mermaid blocks
|
|
1101
|
+
const renderer = new marked.Renderer();
|
|
1102
|
+
renderer.code = function(code, lang) {
|
|
1103
|
+
if (lang === 'mermaid') {
|
|
1104
|
+
return \`<div class="mermaid">\${code}</div>\`;
|
|
1105
|
+
}
|
|
1106
|
+
return \`<pre><code class="language-\${lang}">\${code}</code></pre>\`;
|
|
1107
|
+
};
|
|
1108
|
+
marked.setOptions({ renderer });
|
|
1109
|
+
|
|
1110
|
+
// Tab Switching
|
|
691
1111
|
document.querySelectorAll('.tab').forEach(tab => {
|
|
692
1112
|
tab.addEventListener('click', () => {
|
|
693
1113
|
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
|
|
694
1114
|
document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
|
|
695
1115
|
tab.classList.add('active');
|
|
696
1116
|
document.getElementById(tab.dataset.tab).classList.add('active');
|
|
1117
|
+
|
|
1118
|
+
// Auto-select first workspace file if explorer is opened and empty
|
|
1119
|
+
if (tab.dataset.tab === 'artifacts') {
|
|
1120
|
+
const activeFile = document.querySelector('.file-item.active');
|
|
1121
|
+
if (!activeFile) {
|
|
1122
|
+
const firstFile = document.querySelector('.file-item');
|
|
1123
|
+
if (firstFile) firstFile.click();
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
697
1126
|
});
|
|
698
1127
|
});
|
|
1128
|
+
|
|
1129
|
+
// Category filtering on skills
|
|
699
1130
|
document.querySelectorAll('.filter-btn').forEach(btn => {
|
|
700
1131
|
btn.addEventListener('click', () => {
|
|
701
1132
|
btn.classList.toggle('active');
|
|
@@ -705,6 +1136,242 @@ document.querySelectorAll('.filter-btn').forEach(btn => {
|
|
|
705
1136
|
});
|
|
706
1137
|
});
|
|
707
1138
|
});
|
|
1139
|
+
|
|
1140
|
+
// Modal Actions
|
|
1141
|
+
function closeModal() {
|
|
1142
|
+
document.getElementById('fileModal').classList.remove('active');
|
|
1143
|
+
document.getElementById('modalBody').innerHTML = '';
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
function openModal(title, renderedContent, obsidianLink = null) {
|
|
1147
|
+
document.getElementById('modalTitle').innerText = title;
|
|
1148
|
+
document.getElementById('modalBody').innerHTML = renderedContent;
|
|
1149
|
+
|
|
1150
|
+
const obsLink = document.getElementById('modalObsidianLink');
|
|
1151
|
+
if (obsLink) {
|
|
1152
|
+
if (obsidianLink) {
|
|
1153
|
+
obsLink.href = obsidianLink;
|
|
1154
|
+
obsLink.classList.remove('hidden');
|
|
1155
|
+
} else {
|
|
1156
|
+
obsLink.classList.add('hidden');
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
document.getElementById('fileModal').classList.add('active');
|
|
1161
|
+
|
|
1162
|
+
// Highlight code blocks
|
|
1163
|
+
Prism.highlightAllUnder(document.getElementById('modalBody'));
|
|
1164
|
+
|
|
1165
|
+
// Render mermaid graphs
|
|
1166
|
+
if (window.mermaid) {
|
|
1167
|
+
try {
|
|
1168
|
+
mermaid.run({ nodes: document.getElementById('modalBody').querySelectorAll('.mermaid') });
|
|
1169
|
+
} catch (e) {
|
|
1170
|
+
console.error(e);
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
// Find files in workspace
|
|
1176
|
+
function findWorkspaceSkillPath(skillId) {
|
|
1177
|
+
for (const filePath of Object.keys(WORKSPACE_FILES)) {
|
|
1178
|
+
if (filePath.includes(\`/skills/\${skillId}/\`) || filePath.endsWith(\`/\${skillId}/SKILL.md\`)) {
|
|
1179
|
+
return filePath;
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
return null;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
function findWorkspaceWorkflowPath(wfName) {
|
|
1186
|
+
for (const filePath of Object.keys(WORKSPACE_FILES)) {
|
|
1187
|
+
if (filePath.includes(\`/workflows/\${wfName}.md\`) || filePath.endsWith(\`/\${wfName}.md\`)) {
|
|
1188
|
+
return filePath;
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
return null;
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
function findWorkspaceRulesPath() {
|
|
1195
|
+
for (const filePath of Object.keys(WORKSPACE_FILES)) {
|
|
1196
|
+
if (filePath.includes("engineering-intelligence.md") && (filePath.includes("/rules/") || filePath.includes("/rules"))) {
|
|
1197
|
+
return filePath;
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
return null;
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
function getObsidianUrl(filePath) {
|
|
1204
|
+
return \`obsidian://open?vault=\${encodeURIComponent(VAULT_NAME)}&file=\${encodeURIComponent(filePath)}\`;
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
// View Content Functions
|
|
1208
|
+
function viewTemplate(key, title) {
|
|
1209
|
+
const content = TEMPLATES[key] || "Template content empty or missing.";
|
|
1210
|
+
const rendered = marked.parse(content);
|
|
1211
|
+
openModal(title, rendered);
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
function viewSkillInWorkspace(skillId) {
|
|
1215
|
+
const filePath = findWorkspaceSkillPath(skillId);
|
|
1216
|
+
if (filePath) viewWorkspaceFileInModal(filePath);
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
function viewWorkflowInWorkspace(wfName) {
|
|
1220
|
+
const filePath = findWorkspaceWorkflowPath(wfName);
|
|
1221
|
+
if (filePath) viewWorkspaceFileInModal(filePath);
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
function viewRulesInWorkspace() {
|
|
1225
|
+
const filePath = findWorkspaceRulesPath();
|
|
1226
|
+
if (filePath) viewWorkspaceFileInModal(filePath);
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
function viewWorkspaceFileInModal(filePath) {
|
|
1230
|
+
const content = WORKSPACE_FILES[filePath] || "";
|
|
1231
|
+
const obsidianUrl = getObsidianUrl(filePath);
|
|
1232
|
+
let rendered = "";
|
|
1233
|
+
if (filePath.toLowerCase().endsWith(".json")) {
|
|
1234
|
+
rendered = \`<pre><code class="language-json">\${content}</code></pre>\`;
|
|
1235
|
+
} else {
|
|
1236
|
+
rendered = marked.parse(content);
|
|
1237
|
+
}
|
|
1238
|
+
openModal(filePath, rendered, obsidianUrl);
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
// Sidebar Explorer Functions
|
|
1242
|
+
function viewWorkspaceFile(filePath) {
|
|
1243
|
+
const content = WORKSPACE_FILES[filePath] || "";
|
|
1244
|
+
const obsidianUrl = getObsidianUrl(filePath);
|
|
1245
|
+
const container = document.getElementById('explorerFileContent');
|
|
1246
|
+
|
|
1247
|
+
document.getElementById('explorerFilePath').innerText = filePath;
|
|
1248
|
+
const obsLink = document.getElementById('explorerObsidianLink');
|
|
1249
|
+
obsLink.href = obsidianUrl;
|
|
1250
|
+
obsLink.classList.remove('hidden');
|
|
1251
|
+
|
|
1252
|
+
let rendered = "";
|
|
1253
|
+
if (filePath.toLowerCase().endsWith(".json")) {
|
|
1254
|
+
rendered = \`<pre><code class="language-json">\${content}</code></pre>\`;
|
|
1255
|
+
} else {
|
|
1256
|
+
rendered = marked.parse(content);
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
container.innerHTML = rendered;
|
|
1260
|
+
|
|
1261
|
+
// Highlight code
|
|
1262
|
+
Prism.highlightAllUnder(container);
|
|
1263
|
+
|
|
1264
|
+
// Render mermaid
|
|
1265
|
+
if (window.mermaid) {
|
|
1266
|
+
try {
|
|
1267
|
+
mermaid.run({ nodes: container.querySelectorAll('.mermaid') });
|
|
1268
|
+
} catch (e) {
|
|
1269
|
+
console.error(e);
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
function renderFileList() {
|
|
1275
|
+
const fileListContainer = document.getElementById('fileList');
|
|
1276
|
+
fileListContainer.innerHTML = '';
|
|
1277
|
+
|
|
1278
|
+
const filesCount = Object.keys(WORKSPACE_FILES).length;
|
|
1279
|
+
document.getElementById('workspace-files-count').innerText = filesCount;
|
|
1280
|
+
|
|
1281
|
+
if (filesCount === 0) {
|
|
1282
|
+
fileListContainer.innerHTML = '<div style="color:var(--text-dim);font-size:0.8rem;text-align:center;padding:1rem;">No workspace files detected. Run /initialize-engineering-intelligence first.</div>';
|
|
1283
|
+
return;
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
// Group files by top-level directories
|
|
1287
|
+
const groups = {};
|
|
1288
|
+
for (const filePath of Object.keys(WORKSPACE_FILES)) {
|
|
1289
|
+
const parts = filePath.split('/');
|
|
1290
|
+
const groupName = parts[0];
|
|
1291
|
+
if (!groups[groupName]) {
|
|
1292
|
+
groups[groupName] = [];
|
|
1293
|
+
}
|
|
1294
|
+
groups[groupName].push(filePath);
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
// Sort groups and files, and append
|
|
1298
|
+
Object.keys(groups).sort().forEach(groupName => {
|
|
1299
|
+
const paths = groups[groupName];
|
|
1300
|
+
|
|
1301
|
+
const groupDiv = document.createElement('div');
|
|
1302
|
+
groupDiv.className = 'file-group';
|
|
1303
|
+
|
|
1304
|
+
const header = document.createElement('div');
|
|
1305
|
+
header.className = 'file-group-header';
|
|
1306
|
+
header.innerText = groupName === 'knowledge-base' ? 'Knowledge Base' : groupName === '.engineering-intelligence' ? 'Intelligence Graph & Core' : groupName;
|
|
1307
|
+
groupDiv.appendChild(header);
|
|
1308
|
+
|
|
1309
|
+
const itemsDiv = document.createElement('div');
|
|
1310
|
+
itemsDiv.className = 'file-group-items';
|
|
1311
|
+
|
|
1312
|
+
paths.sort().forEach(filePath => {
|
|
1313
|
+
const item = document.createElement('div');
|
|
1314
|
+
item.className = 'file-item';
|
|
1315
|
+
const basename = filePath.substring(filePath.lastIndexOf('/') + 1);
|
|
1316
|
+
item.innerHTML = \`<span class="file-name">\${basename}</span>\`;
|
|
1317
|
+
item.addEventListener('click', () => {
|
|
1318
|
+
document.querySelectorAll('.file-item').forEach(el => el.classList.remove('active'));
|
|
1319
|
+
item.classList.add('active');
|
|
1320
|
+
viewWorkspaceFile(filePath);
|
|
1321
|
+
});
|
|
1322
|
+
itemsDiv.appendChild(item);
|
|
1323
|
+
});
|
|
1324
|
+
|
|
1325
|
+
groupDiv.appendChild(itemsDiv);
|
|
1326
|
+
fileListContainer.appendChild(groupDiv);
|
|
1327
|
+
});
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
// Initialize workspace components
|
|
1331
|
+
document.addEventListener("DOMContentLoaded", () => {
|
|
1332
|
+
// Populate workspace file tree
|
|
1333
|
+
renderFileList();
|
|
1334
|
+
|
|
1335
|
+
// Bind workspace file buttons on skills cards
|
|
1336
|
+
for (const skillId of Object.keys(SKILL_CATALOG || {})) {
|
|
1337
|
+
const wsPath = findWorkspaceSkillPath(skillId);
|
|
1338
|
+
if (wsPath) {
|
|
1339
|
+
const wsBtn = document.getElementById(\`ws-btn-\${skillId}\`);
|
|
1340
|
+
const obsBtn = document.getElementById(\`obsidian-btn-\${skillId}\`);
|
|
1341
|
+
if (wsBtn) wsBtn.style.display = 'inline-block';
|
|
1342
|
+
if (obsBtn) {
|
|
1343
|
+
obsBtn.style.display = 'inline-block';
|
|
1344
|
+
obsBtn.href = getObsidianUrl(wsPath);
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
// Bind workspace file buttons on workflows cards
|
|
1350
|
+
for (const wf of WORKFLOW_CATALOG || []) {
|
|
1351
|
+
const wsPath = findWorkspaceWorkflowPath(wf.name);
|
|
1352
|
+
if (wsPath) {
|
|
1353
|
+
const wsBtn = document.getElementById(\`ws-btn-\${wf.name}\`);
|
|
1354
|
+
const obsBtn = document.getElementById(\`obsidian-btn-\${wf.name}\`);
|
|
1355
|
+
if (wsBtn) wsBtn.style.display = 'inline-block';
|
|
1356
|
+
if (obsBtn) {
|
|
1357
|
+
obsBtn.style.display = 'inline-block';
|
|
1358
|
+
obsBtn.href = getObsidianUrl(wsPath);
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
// Bind workspace rules controls
|
|
1364
|
+
const rulesPath = findWorkspaceRulesPath();
|
|
1365
|
+
if (rulesPath) {
|
|
1366
|
+
const wsBtn = document.getElementById('ws-rules-btn');
|
|
1367
|
+
const obsBtn = document.getElementById('obsidian-rules-btn');
|
|
1368
|
+
if (wsBtn) wsBtn.style.display = 'inline-block';
|
|
1369
|
+
if (obsBtn) {
|
|
1370
|
+
obsBtn.style.display = 'inline-block';
|
|
1371
|
+
obsBtn.href = getObsidianUrl(rulesPath);
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
});
|
|
708
1375
|
</script>
|
|
709
1376
|
</body>
|
|
710
1377
|
</html>`;
|