@adityaaria/spark 6.0.6 → 6.0.7
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
package/src/cli/install.js
CHANGED
|
@@ -139,12 +139,14 @@ function interpolatePlanText(text, metadata) {
|
|
|
139
139
|
function buildReadyLines(adapter, plan, metadata) {
|
|
140
140
|
const lines = [];
|
|
141
141
|
|
|
142
|
-
if (metadata.relativeTargetRoot) {
|
|
142
|
+
if (metadata.relativeTargetRoot && adapter.id === 'vscode') {
|
|
143
|
+
lines.push(bullet(`Local VS Code bundle prepared at ${pathText(metadata.relativeTargetRoot)}.`));
|
|
144
|
+
} else if (metadata.relativeTargetRoot) {
|
|
143
145
|
lines.push(bullet(`Plugin bundle staged at ${pathText(metadata.relativeTargetRoot)}.`));
|
|
144
146
|
}
|
|
145
147
|
|
|
146
148
|
if (metadata.relativeMarketplaceRoot) {
|
|
147
|
-
lines.push(bullet(`Local
|
|
149
|
+
lines.push(bullet(`Local marketplace staged at ${pathText(metadata.relativeMarketplaceRoot)}.`));
|
|
148
150
|
}
|
|
149
151
|
|
|
150
152
|
if (adapter.id === 'codex') {
|
|
@@ -152,6 +154,14 @@ function buildReadyLines(adapter, plan, metadata) {
|
|
|
152
154
|
return lines;
|
|
153
155
|
}
|
|
154
156
|
|
|
157
|
+
if (adapter.id === 'vscode') {
|
|
158
|
+
if (metadata.relativeSettingsPath) {
|
|
159
|
+
lines.push(bullet(`VS Code plugin registration was written to ${pathText(metadata.relativeSettingsPath)}.`));
|
|
160
|
+
}
|
|
161
|
+
lines.push(bullet('Open a fresh VS Code agent session to confirm using-spark loads before coding.'));
|
|
162
|
+
return lines;
|
|
163
|
+
}
|
|
164
|
+
|
|
155
165
|
lines.push(bullet('Start a fresh session in the selected harness to confirm using-spark loads before coding.'));
|
|
156
166
|
return lines;
|
|
157
167
|
}
|
package/src/cli/output.js
CHANGED
|
@@ -24,7 +24,7 @@ export function printHelp() {
|
|
|
24
24
|
printLine('');
|
|
25
25
|
printMuted('Without --harness, the installer will ask which AI assistance to target.');
|
|
26
26
|
printLine('');
|
|
27
|
-
printLine(labelValue('Supported', 'Codex,
|
|
27
|
+
printLine(labelValue('Supported', 'Claude Code, Codex CLI, VS Code, Cursor, Copilot CLI, OpenCode, Gemini CLI, Pi, Antigravity'));
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
export function printCommandHeader(title) {
|
|
@@ -101,9 +101,15 @@ export function formatPromptPrefix() {
|
|
|
101
101
|
return `${styled('◆', 'spark')} ${styled('Select', 'pink', true)} ${styled('›', 'dimGray')} `;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
export function promptOption(index, label, id, hint = null) {
|
|
104
|
+
export function promptOption(index, label, id, hint = null, detail = null) {
|
|
105
105
|
const base = `${styled(`${index}.`, 'spark', true)} ${styled(label, 'white', true)} ${styled(`(${id})`, 'dimGray')}`;
|
|
106
|
-
|
|
106
|
+
const header = hint ? `${base} ${styled(hint, 'warning')}` : base;
|
|
107
|
+
|
|
108
|
+
if (!detail) {
|
|
109
|
+
return header;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return `${header}\n ${styled(detail, 'dimGray')}`;
|
|
107
113
|
}
|
|
108
114
|
|
|
109
115
|
function styled(text, tone, bold = false) {
|
|
@@ -2,6 +2,7 @@ import { createAdapter } from './common.js';
|
|
|
2
2
|
import { stageClaudePlugin } from './claude-staging.js';
|
|
3
3
|
import { stageCodexPlugin } from './codex-staging.js';
|
|
4
4
|
import { installCursorPlugin } from './cursor-staging.js';
|
|
5
|
+
import { installVsCodePlugin } from './vscode-staging.js';
|
|
5
6
|
import { dirname, resolve } from 'node:path';
|
|
6
7
|
import { fileURLToPath } from 'node:url';
|
|
7
8
|
|
|
@@ -42,14 +43,14 @@ export function createClaudeCodeAdapter() {
|
|
|
42
43
|
export function createCodexAdapter() {
|
|
43
44
|
return createAdapter({
|
|
44
45
|
id: 'codex',
|
|
45
|
-
label: 'Codex',
|
|
46
|
+
label: 'Codex CLI',
|
|
46
47
|
kind: 'shell-hook',
|
|
47
48
|
envKeys: ['CLAUDE_PLUGIN_ROOT'],
|
|
48
49
|
binaryNames: ['codex'],
|
|
49
50
|
bootstrap: 'shell hook -> hooks/session-start-codex -> using-spark',
|
|
50
51
|
installHint: '.codex-plugin/plugin.json + hooks/hooks-codex.json + hooks/session-start-codex',
|
|
51
52
|
verifyHint: 'Run a fresh Codex session and confirm using-spark loads before coding.',
|
|
52
|
-
successMessage: 'Installed SPARK for Codex.',
|
|
53
|
+
successMessage: 'Installed SPARK for Codex CLI.',
|
|
53
54
|
commands: [
|
|
54
55
|
{
|
|
55
56
|
file: 'codex',
|
|
@@ -71,6 +72,26 @@ export function createCodexAdapter() {
|
|
|
71
72
|
});
|
|
72
73
|
}
|
|
73
74
|
|
|
75
|
+
export function createVsCodeAdapter() {
|
|
76
|
+
return createAdapter({
|
|
77
|
+
id: 'vscode',
|
|
78
|
+
label: 'VS Code',
|
|
79
|
+
kind: 'shell-hook',
|
|
80
|
+
bootstrap: 'workspace plugin bundle -> VS Code chat.pluginLocations -> hooks/session-start -> using-spark',
|
|
81
|
+
installHint: 'A Claude-compatible plugin bundle is staged locally and registered through .vscode/settings.json chat.pluginLocations.',
|
|
82
|
+
verifyHint: 'Open a fresh VS Code agent session and confirm using-spark loads before coding.',
|
|
83
|
+
successMessage: 'SPARK is ready in VS Code.',
|
|
84
|
+
automatedSteps: [
|
|
85
|
+
'Prepare a local VS Code plugin bundle at .spark/vscode-plugin.',
|
|
86
|
+
'Register that bundle in .vscode/settings.json via chat.pluginLocations.',
|
|
87
|
+
'Start a fresh VS Code agent session so using-spark loads before coding.',
|
|
88
|
+
],
|
|
89
|
+
customInstall({ cwd, dryRun }) {
|
|
90
|
+
return installVsCodePlugin({ cwd, packageRoot, dryRun });
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
74
95
|
export function createCursorAdapter() {
|
|
75
96
|
return createAdapter({
|
|
76
97
|
id: 'cursor',
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
const VSCODE_PLUGIN_DIR = path.join('.spark', 'vscode-plugin');
|
|
5
|
+
const SETTINGS_PATH = path.join('.vscode', 'settings.json');
|
|
6
|
+
const COPY_PATHS = [
|
|
7
|
+
'.claude-plugin',
|
|
8
|
+
'assets',
|
|
9
|
+
path.join('hooks', 'hooks.json'),
|
|
10
|
+
path.join('hooks', 'run-hook.cmd'),
|
|
11
|
+
path.join('hooks', 'session-start'),
|
|
12
|
+
'skills',
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
export function installVsCodePlugin({ cwd = process.cwd(), packageRoot, dryRun = false }) {
|
|
16
|
+
const targetRoot = path.join(cwd, VSCODE_PLUGIN_DIR);
|
|
17
|
+
const settingsPath = path.join(cwd, SETTINGS_PATH);
|
|
18
|
+
|
|
19
|
+
if (!dryRun) {
|
|
20
|
+
fs.mkdirSync(targetRoot, { recursive: true });
|
|
21
|
+
|
|
22
|
+
for (const relativePath of COPY_PATHS) {
|
|
23
|
+
const sourcePath = path.join(packageRoot, relativePath);
|
|
24
|
+
const targetPath = path.join(targetRoot, relativePath);
|
|
25
|
+
const stat = fs.statSync(sourcePath);
|
|
26
|
+
|
|
27
|
+
if (stat.isDirectory()) {
|
|
28
|
+
fs.cpSync(sourcePath, targetPath, { recursive: true });
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
33
|
+
fs.copyFileSync(sourcePath, targetPath);
|
|
34
|
+
fs.chmodSync(targetPath, stat.mode);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
writeVsCodeSettings(settingsPath, targetRoot);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
targetRoot,
|
|
42
|
+
relativeTargetRoot: VSCODE_PLUGIN_DIR,
|
|
43
|
+
settingsPath,
|
|
44
|
+
relativeSettingsPath: SETTINGS_PATH,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function writeVsCodeSettings(settingsPath, targetRoot) {
|
|
49
|
+
fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
|
|
50
|
+
|
|
51
|
+
let settings = {};
|
|
52
|
+
if (fs.existsSync(settingsPath)) {
|
|
53
|
+
settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const pluginLocations = isPlainObject(settings['chat.pluginLocations'])
|
|
57
|
+
? { ...settings['chat.pluginLocations'] }
|
|
58
|
+
: {};
|
|
59
|
+
|
|
60
|
+
pluginLocations[targetRoot] = true;
|
|
61
|
+
settings['chat.pluginLocations'] = pluginLocations;
|
|
62
|
+
|
|
63
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf8');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function isPlainObject(value) {
|
|
67
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
68
|
+
}
|
package/src/installer/detect.js
CHANGED
|
@@ -164,7 +164,15 @@ function renderPrompt(candidates, validationMessage = null) {
|
|
|
164
164
|
|
|
165
165
|
for (const [index, candidate] of candidates.entries()) {
|
|
166
166
|
const hint = recommendedIds.has(candidate.id) ? 'recommended' : null;
|
|
167
|
-
lines.push(
|
|
167
|
+
lines.push(
|
|
168
|
+
promptOption(
|
|
169
|
+
index + 1,
|
|
170
|
+
candidate.label,
|
|
171
|
+
candidate.id,
|
|
172
|
+
hint,
|
|
173
|
+
describeHarness(candidate.id)
|
|
174
|
+
)
|
|
175
|
+
);
|
|
168
176
|
}
|
|
169
177
|
|
|
170
178
|
return formatPromptBlock(
|
|
@@ -189,6 +197,42 @@ function resolvePromptAnswer(answer, candidates) {
|
|
|
189
197
|
return getAdapterById(exact.id);
|
|
190
198
|
}
|
|
191
199
|
|
|
200
|
+
function describeHarness(id) {
|
|
201
|
+
const descriptions = {
|
|
202
|
+
claude: 'Best for Claude Code sessions and project-local plugin workflows.',
|
|
203
|
+
codex: 'For the Codex CLI plugin marketplace flow in terminal sessions.',
|
|
204
|
+
vscode: 'One install path for VS Code agent sessions across Claude, Copilot, GPT, and other supported models.',
|
|
205
|
+
cursor: 'Native Cursor plugin install for fresh Agent sessions.',
|
|
206
|
+
copilot: 'For GitHub Copilot CLI in terminal-based agent sessions.',
|
|
207
|
+
opencode: 'Registers the OpenCode plugin in your local config directory.',
|
|
208
|
+
gemini: 'Installs the Gemini CLI extension and loads SPARK at startup.',
|
|
209
|
+
pi: 'Installs the Pi extension from the SPARK repository.',
|
|
210
|
+
antigravity: 'Installs the Antigravity plugin and loads SPARK on new sessions.',
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
return descriptions[id] ?? null;
|
|
214
|
+
}
|
|
215
|
+
|
|
192
216
|
function normalizeHarness(value) {
|
|
193
|
-
|
|
217
|
+
const normalized = String(value ?? '').trim().toLowerCase();
|
|
218
|
+
|
|
219
|
+
if (!normalized) {
|
|
220
|
+
return '';
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const aliases = new Map([
|
|
224
|
+
['codex cli', 'codex'],
|
|
225
|
+
['codex-cli', 'codex'],
|
|
226
|
+
['codex vscode', 'vscode'],
|
|
227
|
+
['codex vs code', 'vscode'],
|
|
228
|
+
['codex-vs-code', 'vscode'],
|
|
229
|
+
['codex app', 'vscode'],
|
|
230
|
+
['copilot vscode', 'vscode'],
|
|
231
|
+
['copilot vs code', 'vscode'],
|
|
232
|
+
['copilot-vs-code', 'vscode'],
|
|
233
|
+
['vscode agent', 'vscode'],
|
|
234
|
+
['vs code', 'vscode'],
|
|
235
|
+
]);
|
|
236
|
+
|
|
237
|
+
return aliases.get(normalized) ?? normalized;
|
|
194
238
|
}
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
createCodexAdapter,
|
|
4
4
|
createCopilotAdapter,
|
|
5
5
|
createCursorAdapter,
|
|
6
|
+
createVsCodeAdapter,
|
|
6
7
|
} from './adapters/shell-hook.js';
|
|
7
8
|
import {
|
|
8
9
|
createAntigravityAdapter,
|
|
@@ -14,6 +15,7 @@ import {
|
|
|
14
15
|
const ADAPTERS = [
|
|
15
16
|
createClaudeCodeAdapter(),
|
|
16
17
|
createCodexAdapter(),
|
|
18
|
+
createVsCodeAdapter(),
|
|
17
19
|
createCursorAdapter(),
|
|
18
20
|
createCopilotAdapter(),
|
|
19
21
|
createOpenCodeAdapter(),
|