ineedcodes 1.7.1 → 1.7.2
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 +1 -1
- package/src/cli.js +32 -0
- package/src/session.js +6 -4
- package/src/skills.js +17 -3
- package/src/ui.js +1 -1
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
// First open asks for provider setup. After that, just say what you want.
|
|
4
4
|
|
|
5
5
|
import { spawn } from 'node:child_process';
|
|
6
|
+
import * as fs from 'node:fs';
|
|
7
|
+
import * as os from 'node:os';
|
|
8
|
+
import * as path from 'node:path';
|
|
6
9
|
|
|
7
10
|
const [MAJOR] = process.versions.node.split('.').map(Number);
|
|
8
11
|
if (!(MAJOR >= 20)) {
|
|
@@ -27,6 +30,7 @@ ${bold('ineed')} ${dim(`v${VERSION}`)} - your terminal, now autonomous
|
|
|
27
30
|
|
|
28
31
|
${green('ineed')} interactive session (first open: setup)
|
|
29
32
|
${green('ineed "fix the build errors"')} one-shot task
|
|
33
|
+
${green('ineed unlock')} enable gated skills on this machine
|
|
30
34
|
${green('ineed --reset')} redo provider setup
|
|
31
35
|
${green('ineed --version')} show version
|
|
32
36
|
|
|
@@ -35,6 +39,34 @@ Inside a session, ${dim('/help')} lists the shortcuts. Or just talk to it.
|
|
|
35
39
|
process.exit(0);
|
|
36
40
|
}
|
|
37
41
|
|
|
42
|
+
// unlock: store the developer keyword locally so gated security skills activate here
|
|
43
|
+
if (args[0] === 'unlock') {
|
|
44
|
+
const readline = await import('node:readline');
|
|
45
|
+
const { makeInput, dim, gray } = await import('./ui.js');
|
|
46
|
+
const keywordDir = process.env.INEED_CONFIG_DIR || path.join(os.homedir(), '.ineedcodes');
|
|
47
|
+
const keywordFile = path.join(keywordDir, 'keyword');
|
|
48
|
+
const given = args[1];
|
|
49
|
+
let keyword = '';
|
|
50
|
+
if (given) {
|
|
51
|
+
keyword = given.trim();
|
|
52
|
+
} else {
|
|
53
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
54
|
+
const ask = makeInput(rl);
|
|
55
|
+
keyword = (await ask('Developer keyword: ', { secret: true })).trim();
|
|
56
|
+
rl.close();
|
|
57
|
+
}
|
|
58
|
+
if (!keyword) {
|
|
59
|
+
console.error(red('No keyword given. Nothing saved.'));
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
fs.mkdirSync(keywordDir, { recursive: true });
|
|
63
|
+
fs.writeFileSync(keywordFile, keyword, { mode: 0o600 });
|
|
64
|
+
try { fs.chmodSync(keywordFile, 0o600); } catch {}
|
|
65
|
+
console.log(green('Gated skills unlocked on this machine.'));
|
|
66
|
+
console.log(dim('Saved to ' + keywordFile + ' (0600). Use them by mentioning the keyword in a task, e.g. /skills or "use the sqli skill".'));
|
|
67
|
+
process.exit(0);
|
|
68
|
+
}
|
|
69
|
+
|
|
38
70
|
// internal: one-shot worker. Spawned by the branch below, never run by users.
|
|
39
71
|
if (args[0] === '--child') {
|
|
40
72
|
const task = args.slice(1).join(' ');
|
package/src/session.js
CHANGED
|
@@ -12,7 +12,7 @@ import { saveSession, listSessions, loadSession } from './sessions.js';
|
|
|
12
12
|
import * as boost from './boost.js';
|
|
13
13
|
import { spawnSync } from 'node:child_process';
|
|
14
14
|
import { mcpConfigured } from './mcp.js';
|
|
15
|
-
import { listSkills, findSkill } from './skills.js';
|
|
15
|
+
import { listSkills, findSkill, devKeyword } from './skills.js';
|
|
16
16
|
|
|
17
17
|
function currentBranch(cwd) {
|
|
18
18
|
const r = spawnSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd, encoding: 'utf8' });
|
|
@@ -483,10 +483,12 @@ export async function startSession(cfg, { fresh = false, resume = null } = {}) {
|
|
|
483
483
|
else say(red(`No skill named ${arg}.`));
|
|
484
484
|
return;
|
|
485
485
|
}
|
|
486
|
-
const
|
|
487
|
-
const
|
|
486
|
+
const machineUnlocked = devKeyword() !== '';
|
|
487
|
+
const all = listSkills(process.cwd(), machineUnlocked ? devKeyword() : input);
|
|
488
|
+
const gated = machineUnlocked ? all.filter(x => x.gated).length : -1;
|
|
488
489
|
say(all.length ? all.map(s => ` ${cyan(s.name)} ${dim('(' + s.scope + ')')} ${s.description}`).join('\n') : yellow('No skills installed.'));
|
|
489
|
-
if (gated) say(dim(` (+${gated} gated security skills)`));
|
|
490
|
+
if (gated > 0) say(dim(` (+${gated} gated security skills unlocked on this machine)`));
|
|
491
|
+
else if (!machineUnlocked) say(dim(` gated security skills are locked on this machine - run ${bold('ineed unlock')} to enable`));
|
|
490
492
|
return;
|
|
491
493
|
}
|
|
492
494
|
if (input === '/new') {
|
package/src/skills.js
CHANGED
|
@@ -34,9 +34,23 @@ function parseFrontmatter(raw) {
|
|
|
34
34
|
const m = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
35
35
|
if (!m) return null;
|
|
36
36
|
const meta = {};
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
const lines = m[1].split('\n');
|
|
38
|
+
for (let i = 0; i < lines.length; i++) {
|
|
39
|
+
const kv = lines[i].match(/^(\w+):\s*(.*)$/);
|
|
40
|
+
if (!kv) continue;
|
|
41
|
+
// folded scalar (>-, >): join the indented continuation lines into one paragraph
|
|
42
|
+
if (/^(description|summary)$/.test(kv[1]) && ['', '>-', '>', '|', '|-'].includes(kv[2])) {
|
|
43
|
+
const parts = [];
|
|
44
|
+
let j = i + 1;
|
|
45
|
+
for (; j < lines.length; j++) {
|
|
46
|
+
if (/^\S/.test(lines[j])) break;
|
|
47
|
+
parts.push(lines[j].trim());
|
|
48
|
+
}
|
|
49
|
+
meta[kv[1]] = parts.join(' ').trim();
|
|
50
|
+
i = j - 1;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
meta[kv[1]] = kv[2].trim();
|
|
40
54
|
}
|
|
41
55
|
if (!meta.name) return null;
|
|
42
56
|
return {
|
package/src/ui.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// ui.js: terminal helpers. No dependencies, respects NO_COLOR and non-TTY.
|
|
2
2
|
|
|
3
|
-
export const VERSION = '1.7.
|
|
3
|
+
export const VERSION = '1.7.2';
|
|
4
4
|
|
|
5
5
|
const USE_COLOR = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
6
6
|
const wrap = (code, t) => USE_COLOR ? `\x1b[${code}m${t}\x1b[0m` : String(t);
|