@jikida/init 0.3.0 → 0.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/bin/init.js +80 -9
- package/package.json +1 -1
package/bin/init.js
CHANGED
|
@@ -117,13 +117,42 @@ function installSkill() {
|
|
|
117
117
|
// Master skill (full body) + one thin bootstrap per assistant, so "install into
|
|
118
118
|
// every editor you already use" actually holds — Cursor, Windsurf, Cline,
|
|
119
119
|
// Copilot, Aider, Continue, Claude, Gemini, plus the generic AGENTS.md.
|
|
120
|
+
// The Continue.dev config is YAML with a `rules:` block, not free prose — wrap
|
|
121
|
+
// the bootstrap so it drops in as a valid rule instead of breaking the parser.
|
|
122
|
+
const continueYaml =
|
|
123
|
+
'name: Jikida security\n' +
|
|
124
|
+
'version: 0.0.1\n' +
|
|
125
|
+
'rules:\n' +
|
|
126
|
+
' - >\n' +
|
|
127
|
+
bootstrap.split('\n').map((l) => ' ' + l).join('\n') + '\n';
|
|
128
|
+
|
|
129
|
+
// A Claude Code slash command: `/jikida-scan` in the editor kicks off the
|
|
130
|
+
// guided repo scan without the user remembering the phrasing.
|
|
131
|
+
const scanCommand =
|
|
132
|
+
'---\n' +
|
|
133
|
+
'description: Scan this repo for leaked secrets, exposed rules, and vulnerabilities (Jikida)\n' +
|
|
134
|
+
'---\n\n' +
|
|
135
|
+
'Read `.claude/skills/jikida/SKILL.md`, then run a full security pass on this\n' +
|
|
136
|
+
'repository: committed secrets (.env, serviceAccountKey.json, *.pem, API keys),\n' +
|
|
137
|
+
'open Supabase/Firebase rules, missing auth checks, injection, and out-of-date\n' +
|
|
138
|
+
'dependencies with known CVEs. Walk the 25-category catalog. Report findings\n' +
|
|
139
|
+
'worst-first with a one-line fix each, and apply fixes at the lowest safe\n' +
|
|
140
|
+
'intervention level. Ask before anything destructive. Record what you find in\n' +
|
|
141
|
+
'`memory-security.md`.\n';
|
|
142
|
+
|
|
143
|
+
// `managed: true` = a Jikida-owned file we fully (re)write on every run so
|
|
144
|
+
// updates land and re-running never appends a duplicate (SKILL.md, our own
|
|
145
|
+
// .mdc/command/continue files). The rest are shared assistant files we only
|
|
146
|
+
// append-if-missing so we never clobber a user's own rules.
|
|
120
147
|
const targets = [
|
|
121
|
-
[join(cwd, '.claude', 'skills', 'jikida', 'SKILL.md'), body],
|
|
148
|
+
[join(cwd, '.claude', 'skills', 'jikida', 'SKILL.md'), body, true],
|
|
149
|
+
[join(cwd, '.claude', 'commands', 'jikida-scan.md'), scanCommand, true],
|
|
150
|
+
[join(cwd, '.cursor', 'rules', 'jikida.mdc'), mdc, true],
|
|
151
|
+
[join(cwd, '.continue', 'config.yaml'), continueYaml, true],
|
|
122
152
|
[join(cwd, 'AGENTS.md'), bootstrap],
|
|
123
153
|
[join(cwd, 'CLAUDE.md'), bootstrap],
|
|
124
154
|
[join(cwd, 'GEMINI.md'), bootstrap],
|
|
125
155
|
[join(cwd, '.cursorrules'), bootstrap],
|
|
126
|
-
[join(cwd, '.cursor', 'rules', 'jikida.mdc'), mdc],
|
|
127
156
|
[join(cwd, '.windsurfrules'), bootstrap],
|
|
128
157
|
[join(cwd, '.clinerules'), bootstrap],
|
|
129
158
|
[join(cwd, '.aider.conf.yml'), bootstrap],
|
|
@@ -134,14 +163,14 @@ function installSkill() {
|
|
|
134
163
|
log(' ----------------------------');
|
|
135
164
|
const MARK = 'Jikida security skill';
|
|
136
165
|
let wrote = 0, skipped = 0;
|
|
137
|
-
for (const [target, content] of targets) {
|
|
166
|
+
for (const [target, content, managed] of targets) {
|
|
138
167
|
const rel = target.replace(cwd + '/', '');
|
|
139
168
|
try {
|
|
140
169
|
mkdirSync(dirname(target), { recursive: true });
|
|
141
|
-
//
|
|
142
|
-
// assistant files are APPEND-if-present,
|
|
143
|
-
// a user's
|
|
144
|
-
if (
|
|
170
|
+
// Managed (Jikida-owned) files are always (re)written so updates land and
|
|
171
|
+
// re-runs never duplicate. Shared assistant files are APPEND-if-present,
|
|
172
|
+
// skip-if-already-ours — never clobber a user's own rules, never double-add.
|
|
173
|
+
if (managed) {
|
|
145
174
|
writeFileSync(target, content);
|
|
146
175
|
done(rel); wrote++;
|
|
147
176
|
} else if (!existsSync(target)) {
|
|
@@ -171,11 +200,53 @@ function installSkill() {
|
|
|
171
200
|
}
|
|
172
201
|
} catch (e) { warn(`Could not copy checklists: ${e.message}`); }
|
|
173
202
|
|
|
203
|
+
// Harden .gitignore: a security skill install should also stop the classic
|
|
204
|
+
// leaks it scans for from ever being committed. Append only the lines that are
|
|
205
|
+
// missing, under one clearly-marked block — never duplicate, never reorder the
|
|
206
|
+
// user's file.
|
|
207
|
+
try {
|
|
208
|
+
const giPath = join(cwd, '.gitignore');
|
|
209
|
+
const current = existsSync(giPath) ? readFileSync(giPath, 'utf8') : '';
|
|
210
|
+
const wanted = [
|
|
211
|
+
'.env', '.env.*', '!.env.example',
|
|
212
|
+
'*.pem', '*.key', '*.p8', '*.p12', '*.keystore',
|
|
213
|
+
'serviceAccountKey.json', '*-firebase-adminsdk-*.json', 'google-services.json',
|
|
214
|
+
'*.mobileprovision', 'secrets.*', '.jikida/',
|
|
215
|
+
];
|
|
216
|
+
const missing = wanted.filter((line) => {
|
|
217
|
+
const re = new RegExp('^' + line.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '\\s*$', 'm');
|
|
218
|
+
return !re.test(current);
|
|
219
|
+
});
|
|
220
|
+
if (missing.length) {
|
|
221
|
+
const block = (current && !current.endsWith('\n') ? '\n' : '')
|
|
222
|
+
+ '\n# Jikida security — do not commit secrets\n' + missing.join('\n') + '\n';
|
|
223
|
+
appendFileSync(giPath, block);
|
|
224
|
+
done(`.gitignore (+${missing.length} security entr${missing.length === 1 ? 'y' : 'ies'})`); wrote++;
|
|
225
|
+
}
|
|
226
|
+
} catch (e) { warn(`Could not update .gitignore: ${e.message}`); }
|
|
227
|
+
|
|
228
|
+
// A persistent findings log the assistant appends to across sessions, so a
|
|
229
|
+
// scan's results and the "still to fix" list survive context resets.
|
|
230
|
+
try {
|
|
231
|
+
const memPath = join(cwd, 'memory-security.md');
|
|
232
|
+
if (!existsSync(memPath)) {
|
|
233
|
+
writeFileSync(memPath,
|
|
234
|
+
'# Security memory (Jikida)\n\n' +
|
|
235
|
+
'The assistant appends findings and their status here as it scans and fixes.\n' +
|
|
236
|
+
'Read this at the start of a security pass so nothing is re-flagged or lost.\n\n' +
|
|
237
|
+
'## Open findings\n\n_none yet — run `/jikida-scan` or ask your AI to scan the repo._\n\n' +
|
|
238
|
+
'## Fixed\n\n');
|
|
239
|
+
done('memory-security.md'); wrote++;
|
|
240
|
+
}
|
|
241
|
+
} catch (e) { warn(`Could not write memory-security.md: ${e.message}`); }
|
|
242
|
+
|
|
174
243
|
if (wrote > 0 || skipped > 0) {
|
|
175
244
|
log('');
|
|
176
245
|
if (skipped > 0) { log(` ${skipped} file(s) already had the skill — left untouched.`); }
|
|
177
|
-
log(' Done. Your AI editors now know Jikida
|
|
178
|
-
log('
|
|
246
|
+
log(' Done. Your AI editors now know Jikida. Restart them, then:');
|
|
247
|
+
log('');
|
|
248
|
+
log(' ⚡ Run /jikida-scan in Claude Code — or ask any AI to');
|
|
249
|
+
log(' "scan my repo for leaked secrets and open rules".');
|
|
179
250
|
log('');
|
|
180
251
|
}
|
|
181
252
|
process.exit((wrote > 0 || skipped > 0) ? 0 : 1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jikida/init",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "One command to install a production Web Application Firewall. Detects Node (Next.js / Express / Fastify), PHP (Laravel / Symfony), and Python (Django / FastAPI / Flask), installs the right Jikida SDK, wires the middleware, writes JIKIDA_TOKEN to .env. $0 to start. Fails open. Playground + MCP for Claude Code / Cursor / Windsurf included.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|