@adityaaria/spark 6.0.21 → 6.0.22

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adityaaria/spark",
3
- "version": "6.0.21",
3
+ "version": "6.0.22",
4
4
  "description": "SPARK skills and runtime bootstrap for coding agents",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -11,7 +11,12 @@ Use this skill to scan and document a codebase's architecture, operational rules
11
11
 
12
12
  **Announce at start:** "spark detection 💥 Using project-scanner to analyze repository DNA"
13
13
 
14
- **Save findings to:** The `.docs/` directory. **You must physically create this directory and save the files to disk using your tools. Do NOT just print the output to the user.** For large projects, break down the documentation logically (e.g., `.docs/PROJECT_SCAN.md`, `.docs/API_CONTRACT.md`, `.docs/DOMAINS/`) instead of creating one massive monolithic file.
14
+ **Save findings to:** The `.docs/` directory. **You must physically create this directory and save the files to disk using your tools. Do NOT just print the output to the user.**
15
+
16
+ ## Multi-Project Workspaces (CRITICAL)
17
+ If the workspace contains multiple independent projects or repositories (e.g., a `frontend` folder and a `backend` folder), you MUST generate a separate `.docs/` directory inside EACH project's root folder (e.g., `frontend/.docs/`, `backend/.docs/`). Do NOT combine them into a single global `.docs/` or dump everything into just one project's folder. Treat each independent project as its own ecosystem that requires its own documentation.
18
+
19
+ For large projects, break down the documentation logically (e.g., `.docs/PROJECT_SCAN.md`, `.docs/API_CONTRACT.md`, `.docs/DOMAINS/`) instead of creating one massive monolithic file.
15
20
 
16
21
  ## Handling Massive Codebases (Subagent Delegation)
17
22
  If the repository is extremely large and analyzing all four pillars sequentially risks exceeding context limits or taking too long:
@@ -53,7 +58,8 @@ Identify conventions, rules, and technical debt enforced or found in the codebas
53
58
  ## Execution Checklist
54
59
 
55
60
  - `[ ]` **Step 1:** Announce skill usage exactly as required.
56
- - `[ ]` **Step 2:** Scan root configuration files and prioritize searching for Swagger/OpenAPI specifications.
57
- - `[ ]` **Step 3:** Scan source directory structures to infer the language, framework, and architectural patterns.
58
- - `[ ]` **Step 4:** Analyze testing frameworks, CI/CD workflows, and actively hunt for anti-patterns and legacy traps.
59
- - `[ ]` **Step 5 (CRITICAL):** You MUST use your file-writing tools to physically create the `.docs/` directory and save the markdown files (e.g. `PROJECT_SCAN.md`, `API_CONTRACT.md`) into it. DO NOT just print the summary into the chat! You must physically write the files to disk.
61
+ - `[ ]` **Step 2:** Identify if the workspace contains multiple independent projects (e.g., frontend vs backend). If so, plan to scan and generate `.docs/` for EACH project separately.
62
+ - `[ ]` **Step 3:** Scan root configuration files and prioritize searching for Swagger/OpenAPI specifications.
63
+ - `[ ]` **Step 4:** Scan source directory structures to infer the language, framework, and architectural patterns.
64
+ - `[ ]` **Step 5:** Analyze testing frameworks, CI/CD workflows, and actively hunt for anti-patterns and legacy traps.
65
+ - `[ ]` **Step 6 (CRITICAL):** You MUST use your file-writing tools to physically create the `.docs/` directory (inside each project root if multi-repo) and save the markdown files (e.g. `PROJECT_SCAN.md`, `API_CONTRACT.md`) into it. DO NOT just print the summary into the chat! You must physically write the files to disk.
@@ -621,19 +621,81 @@ ${steps}
621
621
  return;
622
622
  }
623
623
 
624
- // Create some dummy nodes for architecture visualization (in a real scenario we'd parse .docs/)
625
- const nodes = new vis.DataSet([
626
- { id: 1, label: 'Client App', color: '#00ffaa', shape: 'box' },
627
- { id: 2, label: 'API Gateway', color: '#00ffaa', shape: 'box' },
628
- { id: 3, label: 'Auth Service', color: '#ff4757', shape: 'box' },
629
- { id: 4, label: 'Database', color: '#f1f5f9', shape: 'database' },
630
- ]);
631
- const edges = new vis.DataSet([
632
- { from: 1, to: 2, arrows: 'to' },
633
- { from: 2, to: 3, arrows: 'to', label: 'verify token' },
634
- { from: 3, to: 4, arrows: 'to' },
635
- ]);
636
-
624
+ // Dynamic Mermaid Parser
625
+ let nodesMap = new Map();
626
+ let edgesList = [];
627
+ let nodeIdCounter = 1;
628
+
629
+ function parseNode(str) {
630
+ const match = str.trim().match(/^([a-zA-Z0-9_-]+)(.*)$/);
631
+ if (!match) return null;
632
+ const rawId = match[1];
633
+ let label = rawId;
634
+ let shape = 'box';
635
+ const rest = match[2].trim();
636
+ if (rest) {
637
+ const labelMatch = rest.match(/[\[\(\{]+(.*?)[\]\}\)]+/);
638
+ if (labelMatch) label = labelMatch[1].replace(/["']/g, '');
639
+ if (rest.includes('[((') || rest.includes('[([')) shape = 'database';
640
+ else if (rest.includes('{')) shape = 'diamond';
641
+ else if (rest.includes('((')) shape = 'ellipse';
642
+ }
643
+ return { rawId, label, shape };
644
+ }
645
+
646
+ docsData.forEach(doc => {
647
+ const mermaidRegex = /```mermaid\s+([\s\S]*?)```/g;
648
+ let match;
649
+ while ((match = mermaidRegex.exec(doc.content)) !== null) {
650
+ const lines = match[1].split('\n');
651
+ lines.forEach(line => {
652
+ let l = line.trim();
653
+ if (!l || l.startsWith('graph') || l.startsWith('flowchart') || l.startsWith('subgraph') || l.startsWith('end')) return;
654
+
655
+ const parts = l.split('-->');
656
+ if (parts.length >= 2) {
657
+ let fromPart = parts[0].trim();
658
+ let toPart = parts.slice(1).join('-->').trim();
659
+
660
+ let edgeLabel = '';
661
+ if (toPart.startsWith('|')) {
662
+ const pipeEnd = toPart.indexOf('|', 1);
663
+ if (pipeEnd > -1) {
664
+ edgeLabel = toPart.substring(1, pipeEnd).trim();
665
+ toPart = toPart.substring(pipeEnd + 1).trim();
666
+ }
667
+ }
668
+
669
+ const fNode = parseNode(fromPart);
670
+ const tNode = parseNode(toPart);
671
+
672
+ if (fNode && tNode) {
673
+ if (!nodesMap.has(fNode.rawId)) {
674
+ nodesMap.set(fNode.rawId, { id: nodeIdCounter++, label: fNode.label, shape: fNode.shape, color: { background: '#151515', border: '#2a2a2a' } });
675
+ }
676
+ if (!nodesMap.has(tNode.rawId)) {
677
+ nodesMap.set(tNode.rawId, { id: nodeIdCounter++, label: tNode.label, shape: tNode.shape, color: { background: '#151515', border: '#2a2a2a' } });
678
+ }
679
+
680
+ edgesList.push({
681
+ from: nodesMap.get(fNode.rawId).id,
682
+ to: nodesMap.get(tNode.rawId).id,
683
+ arrows: 'to',
684
+ label: edgeLabel
685
+ });
686
+ }
687
+ }
688
+ });
689
+ }
690
+ });
691
+
692
+ if (nodesMap.size === 0) {
693
+ container.innerHTML = '<div style="padding: 40px; text-align: center; color: var(--text-muted);">No Mermaid architecture graphs found in .docs/ files. Run the project-scanner skill first.</div>';
694
+ return;
695
+ }
696
+
697
+ const nodes = new vis.DataSet(Array.from(nodesMap.values()));
698
+ const edges = new vis.DataSet(edgesList);
637
699
  const data = { nodes, edges };
638
700
  const options = {
639
701
  nodes: {
@@ -742,8 +804,15 @@ ${steps}
742
804
  },
743
805
  response: [{
744
806
  name: "Success",
807
+ originalRequest: {
808
+ method: ep.method,
809
+ header: [{ key: "Authorization", value: "Bearer {{token}}" }, { key: "Content-Type", value: "application/json" }],
810
+ body: ep.method !== 'GET' ? { mode: "raw", raw: JSON.stringify(mock, null, 2) } : undefined,
811
+ url: { raw: `{{baseUrl}}/${pathArr.join('/')}`, host: ["{{baseUrl}}"], path: pathArr }
812
+ },
745
813
  status: "OK",
746
814
  code: 200,
815
+ _postman_previewlanguage: "json",
747
816
  header: [{ key: "Content-Type", value: "application/json" }],
748
817
  body: JSON.stringify({ success: true, data: mock }, null, 2)
749
818
  }]
@@ -758,8 +827,15 @@ ${steps}
758
827
  },
759
828
  response: [{
760
829
  name: "Bad Request",
830
+ originalRequest: {
831
+ method: ep.method,
832
+ header: [{ key: "Authorization", value: "Bearer {{token}}" }, { key: "Content-Type", value: "application/json" }],
833
+ body: ep.method !== 'GET' ? { mode: "raw", raw: "{}" } : undefined,
834
+ url: { raw: `{{baseUrl}}/${pathArr.join('/')}`, host: ["{{baseUrl}}"], path: pathArr }
835
+ },
761
836
  status: "Bad Request",
762
837
  code: 400,
838
+ _postman_previewlanguage: "json",
763
839
  header: [{ key: "Content-Type", value: "application/json" }],
764
840
  body: JSON.stringify({ success: false, error: { code: "VALIDATION_ERROR", message: "Invalid parameters provided" } }, null, 2)
765
841
  }]
@@ -773,8 +849,14 @@ ${steps}
773
849
  },
774
850
  response: [{
775
851
  name: "Unauthorized",
852
+ originalRequest: {
853
+ method: ep.method,
854
+ header: [], // No auth
855
+ url: { raw: `{{baseUrl}}/${pathArr.join('/')}`, host: ["{{baseUrl}}"], path: pathArr }
856
+ },
776
857
  status: "Unauthorized",
777
858
  code: 401,
859
+ _postman_previewlanguage: "json",
778
860
  header: [{ key: "Content-Type", value: "application/json" }],
779
861
  body: JSON.stringify({ success: false, error: { code: "UNAUTHORIZED", message: "Missing or invalid token" } }, null, 2)
780
862
  }]