@adityaaria/spark 6.0.20 → 6.0.21

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.
@@ -99,8 +99,8 @@ print_help() {
99
99
  bash bin/spark-install.sh [options]
100
100
 
101
101
  Options:
102
- -g, --global Install to global agent config (~/.agent/skills/)
103
- Default: project scope (./.agent/skills/)
102
+ -g, --global Install to global agent config (~/.agents/skills/)
103
+ Default: project scope (./.agents/skills/)
104
104
  --force Re-install even if already installed
105
105
  --dry-run Show what would be done without making changes
106
106
  -u, --uninstall Safely remove SPARK from agent configs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adityaaria/spark",
3
- "version": "6.0.20",
3
+ "version": "6.0.21",
4
4
  "description": "SPARK skills and runtime bootstrap for coding agents",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -10,7 +10,12 @@ If you were dispatched as a subagent to execute a specific task, skip this skill
10
10
  <EXTREMELY-IMPORTANT>
11
11
  If you think there is even a 1% chance a skill might apply to what you are doing, you ABSOLUTELY MUST invoke the skill.
12
12
 
13
- IF A SKILL APPLIES TO YOUR TASK, YOU DO NOT HAVE A CHOICE. YOU MUST USE IT.
13
+ IF A SKILL APPLIES TO YOUR TASK, OR IF THE USER EXPLICITLY REQUESTS A SKILL, YOU DO NOT HAVE A CHOICE. YOU MUST USE IT IMMEDIATELY.
14
+
15
+ **Do NOT ask clarifying questions first.**
16
+ **Do NOT start a conversation.**
17
+ **Do NOT explain what you are going to do.**
18
+ **JUST EXECUTE THE SKILL DIRECTLY AS YOUR FIRST TOOL CALL.**
14
19
 
15
20
  This is not negotiable. This is not optional. You cannot rationalize your way out of this.
16
21
  </EXTREMELY-IMPORTANT>
@@ -49,6 +54,8 @@ Skills speak in actions ("dispatch a subagent", "create a todo", "read a file")
49
54
 
50
55
  **Invoke relevant or requested skills BEFORE any response or action.** Even a 1% chance a skill might apply means that you should invoke the skill to check. If an invoked skill turns out to be wrong for the situation, you don't need to use it.
51
56
 
57
+ **CRITICAL:** If the user mentions a specific skill by name (e.g., "scan project", "project-scanner", "run deployment"), you MUST invoke that skill IMMEDIATELY as your very first tool call. Do not answer conversationally. Do not ask for confirmation. Execute the skill first.
58
+
52
59
  ## Announcement Format
53
60
  When you invoke a skill, you MUST announce it to the developer using exactly this format as the very first thing you say:
54
61
  `spark detection 💥 Using [skill] to [purpose]`
package/src/cli/output.js CHANGED
@@ -24,7 +24,7 @@ export function printHelp() {
24
24
  printLine('');
25
25
  printMuted('Wraps the native SPARK installer (bin/spark-install.sh).');
26
26
  printLine('');
27
- printLine(labelValue('Options', '-g, --global Install to global agent config (~/.agent/skills/)'));
27
+ printLine(labelValue('Options', '-g, --global Install to global agent config (~/.agents/skills/)'));
28
28
  printLine(labelValue(' ', '--force Re-install even if already installed'));
29
29
  printLine(labelValue(' ', '--dry-run Show what would be done without making changes'));
30
30
  printLine(labelValue(' ', '-h, --help Show this help message'));
@@ -9,9 +9,8 @@
9
9
  <!-- Marked.js for Markdown parsing -->
10
10
  <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
11
11
  <!-- Vis-Network for Interactive Graphs -->
12
- <script type="text/javascript" src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
13
- <!-- Chart.js for Heatmap -->
14
- <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
12
+ <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/vis-network/9.1.9/standalone/umd/vis-network.min.js"></script>
13
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script>
15
14
  <style>
16
15
  :root {
17
16
  --bg-color: #0d0d0d;
@@ -491,9 +490,12 @@
491
490
  totalFiles++;
492
491
  if (isDanger) {
493
492
  dangerFilesCount++;
494
- dangerListHTML += `<div style="padding: 12px 16px; background: var(--bg-color); border: 1px solid var(--glass-border); border-radius: 8px; margin-bottom: 8px; display: flex; justify-content: space-between; align-items: center;">
495
- <span style="font-family: var(--font-mono); font-size: 13px; color: var(--text-main);">${node.path}</span>
496
- <span style="font-size: 10px; color: var(--text-muted); border: 1px solid var(--glass-border); padding: 4px 8px; border-radius: 20px;">Flagged</span>
493
+ dangerListHTML += `<div style="padding: 12px 16px; background: var(--bg-color); border: 1px solid var(--glass-border); border-radius: 8px; margin-bottom: 12px; display: flex; flex-direction: column; gap: 8px;">
494
+ <div style="display: flex; justify-content: space-between; align-items: center;">
495
+ <span style="font-family: var(--font-mono); font-size: 13px; color: var(--text-main);">${node.path}</span>
496
+ <span style="font-size: 10px; color: var(--danger); border: 1px solid var(--glass-border); padding: 4px 8px; border-radius: 20px;">Flagged</span>
497
+ </div>
498
+ <div style="font-size: 12px; color: var(--text-muted); line-height: 1.4;">${node.dangerReason || 'Legacy anti-pattern detected.'}</div>
497
499
  </div>`;
498
500
  }
499
501
  }
@@ -611,9 +613,15 @@ ${steps}
611
613
  }
612
614
 
613
615
  function renderGraph() {
614
- if(networkInstance) return; // already rendered
615
-
616
- // Mock graph data, in a real scenario we'd parse .docs/
616
+ if (networkInstance) return; // Already rendered
617
+
618
+ const container = document.getElementById('network-graph');
619
+ if (typeof vis === 'undefined') {
620
+ container.innerHTML = '<div style="padding: 40px; text-align: center; color: var(--danger);">Failed to load graph library. Please check your internet connection or use a local build.</div>';
621
+ return;
622
+ }
623
+
624
+ // Create some dummy nodes for architecture visualization (in a real scenario we'd parse .docs/)
617
625
  const nodes = new vis.DataSet([
618
626
  { id: 1, label: 'Client App', color: '#00ffaa', shape: 'box' },
619
627
  { id: 2, label: 'API Gateway', color: '#00ffaa', shape: 'box' },
@@ -626,7 +634,6 @@ ${steps}
626
634
  { from: 3, to: 4, arrows: 'to' },
627
635
  ]);
628
636
 
629
- const container = document.getElementById('network-graph');
630
637
  const data = { nodes, edges };
631
638
  const options = {
632
639
  nodes: {
@@ -45,28 +45,60 @@ const server = http.createServer((req, res) => {
45
45
  // API Route: Get File Tree (for Heatmap)
46
46
  if (req.url === '/api/tree' && req.method === 'GET') {
47
47
  res.setHeader('Content-Type', 'application/json');
48
- const ignoreDirs = ['node_modules', '.git', '.docs', '.claude', '.cursor', '.codex', 'dist', 'build'];
49
48
 
50
- function scanDir(dir, base = '') {
51
- let results = [];
52
- try {
53
- const items = fs.readdirSync(dir);
54
- for (const item of items) {
55
- if (ignoreDirs.includes(item) || item.startsWith('.')) continue;
56
- const fullPath = path.join(dir, item);
57
- const relPath = path.join(base, item);
58
- const stat = fs.statSync(fullPath);
59
- if (stat.isDirectory()) {
60
- results.push({ name: item, type: 'dir', path: relPath, children: scanDir(fullPath, relPath) });
61
- } else {
62
- results.push({ name: item, type: 'file', path: relPath });
63
- }
49
+ const getDirectoryTree = (dirPath, relativePath = '') => {
50
+ const items = fs.readdirSync(dirPath);
51
+ let result = [];
52
+
53
+ for (const item of items) {
54
+ if (['node_modules', '.git', '.docs', '.agents', '.spark'].includes(item)) continue;
55
+
56
+ const fullPath = path.join(dirPath, item);
57
+ const itemRelativePath = path.join(relativePath, item);
58
+ const stat = fs.statSync(fullPath);
59
+
60
+ let isDanger = false;
61
+ let dangerReason = '';
62
+
63
+ const lowerItem = item.toLowerCase();
64
+ if (lowerItem.includes('controller')) {
65
+ isDanger = true;
66
+ dangerReason = 'Anti-Pattern: "God Object" tendency. Move business logic to specific Domain Services instead of Controllers.';
67
+ } else if (lowerItem.includes('utils')) {
68
+ isDanger = true;
69
+ dangerReason = 'Legacy Trap: "Utils" folders become untracked dumping grounds for dead code. Use specific domain modules.';
70
+ } else if (lowerItem.includes('helper')) {
71
+ isDanger = true;
72
+ dangerReason = 'Legacy Trap: "Helpers" lack clear boundaries and violate single responsibility principles.';
73
+ } else if (lowerItem.includes('api') && stat.isDirectory()) {
74
+ isDanger = true;
75
+ dangerReason = 'Anti-Pattern: Generic "API" folders often lead to poor separation of concerns. Group by feature/domain instead.';
64
76
  }
65
- } catch (e) {}
66
- return results;
67
- }
77
+
78
+ if (stat.isDirectory()) {
79
+ const children = getDirectoryTree(fullPath, itemRelativePath);
80
+ result.push({
81
+ name: item,
82
+ path: itemRelativePath,
83
+ type: 'dir',
84
+ isDanger,
85
+ dangerReason,
86
+ children
87
+ });
88
+ } else {
89
+ result.push({
90
+ name: item,
91
+ path: itemRelativePath,
92
+ type: 'file',
93
+ isDanger,
94
+ dangerReason
95
+ });
96
+ }
97
+ }
98
+ return result;
99
+ };
68
100
 
69
- return res.end(JSON.stringify({ tree: scanDir(process.cwd()) }));
101
+ return res.end(JSON.stringify({ tree: getDirectoryTree(process.cwd()) }));
70
102
  }
71
103
 
72
104
  // API Route: Get SPARK Readme (for Guide)
@@ -97,7 +129,7 @@ const server = http.createServer((req, res) => {
97
129
  }
98
130
 
99
131
  // 2. Custom skills
100
- const customDir = path.join(process.cwd(), '.agent', 'skills');
132
+ const customDir = path.join(process.cwd(), '.agents', 'skills');
101
133
  if (fs.existsSync(customDir)) {
102
134
  try {
103
135
  const items = fs.readdirSync(customDir);
@@ -119,8 +151,8 @@ const server = http.createServer((req, res) => {
119
151
  }
120
152
 
121
153
  // Save to a safe, user-level directory that SPARK updates won't touch
122
- // The Anthropic standard allows putting skills in .agent/skills/
123
- const customSkillsDir = path.join(process.cwd(), '.agent', 'skills', data.name);
154
+ // The Anthropic/Gemini standard allows putting skills in .agents/skills/
155
+ const customSkillsDir = path.join(process.cwd(), '.agents', 'skills', data.name);
124
156
 
125
157
  try {
126
158
  fs.mkdirSync(customSkillsDir, { recursive: true });