claudia-mentor 0.2.0 → 0.3.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/README.md +2 -16
- package/package.json +1 -1
- package/scripts/postinstall.js +133 -29
package/README.md
CHANGED
|
@@ -15,27 +15,13 @@ A Claude Code plugin that acts as your technology mentor, security advisor, and
|
|
|
15
15
|
|
|
16
16
|
## Install
|
|
17
17
|
|
|
18
|
-
**Step 1: Get Claudia**
|
|
19
|
-
|
|
20
18
|
```bash
|
|
21
19
|
npm install -g claudia-mentor
|
|
22
20
|
```
|
|
23
21
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
claude --plugin-dir $(npm root -g)/claudia-mentor
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
That's it. Claudia is now loaded. Try `/claudia are you there?` to say hi.
|
|
31
|
-
|
|
32
|
-
**Want her loaded every time?** Add this to your shell config (`~/.zshrc` or `~/.bashrc`):
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
alias claude='claude --plugin-dir $(npm root -g)/claudia-mentor'
|
|
36
|
-
```
|
|
22
|
+
That's it. One command. The installer automatically configures your shell so every `claude` session loads Claudia. Restart your terminal and type `claude` -- she's there.
|
|
37
23
|
|
|
38
|
-
|
|
24
|
+
To verify, type `/claudia-mentor:claudia are you there?` inside Claude Code.
|
|
39
25
|
|
|
40
26
|
## Usage
|
|
41
27
|
|
package/package.json
CHANGED
package/scripts/postinstall.js
CHANGED
|
@@ -1,31 +1,135 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
|
|
7
|
+
// Colors
|
|
8
|
+
const v = "\x1b[31m"; // vermillion
|
|
9
|
+
const p = "\x1b[38;5;203m"; // lighter vermillion/coral
|
|
10
|
+
const d2 = "\x1b[38;5;52m"; // dark red
|
|
11
|
+
const w = "\x1b[37m"; // white
|
|
12
|
+
const d = "\x1b[2m"; // dim
|
|
13
|
+
const b = "\x1b[1m"; // bold
|
|
14
|
+
const g = "\x1b[32m"; // green
|
|
15
|
+
const r = "\x1b[0m"; // reset
|
|
16
|
+
const hide = "\x1b[?25l"; // hide cursor
|
|
17
|
+
const show = "\x1b[?25h"; // show cursor
|
|
18
|
+
|
|
19
|
+
const version = require('../package.json').version;
|
|
20
|
+
const pluginDir = path.resolve(__dirname, '..');
|
|
21
|
+
|
|
22
|
+
// ── Auto-setup: add alias to shell config ──────────────────────
|
|
23
|
+
|
|
24
|
+
function getShellConfig() {
|
|
25
|
+
const shell = process.env.SHELL || '';
|
|
26
|
+
if (shell.includes('zsh')) return path.join(os.homedir(), '.zshrc');
|
|
27
|
+
if (shell.includes('bash')) {
|
|
28
|
+
// macOS uses .bash_profile, Linux uses .bashrc
|
|
29
|
+
const profile = path.join(os.homedir(), '.bash_profile');
|
|
30
|
+
if (fs.existsSync(profile)) return profile;
|
|
31
|
+
return path.join(os.homedir(), '.bashrc');
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const ALIAS_MARKER = '# claudia-mentor';
|
|
37
|
+
const ALIAS_LINE = `alias claude='claude --plugin-dir "${pluginDir}"' ${ALIAS_MARKER}`;
|
|
38
|
+
|
|
39
|
+
let aliasStatus = 'skipped';
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const configFile = getShellConfig();
|
|
43
|
+
if (configFile) {
|
|
44
|
+
const contents = fs.existsSync(configFile) ? fs.readFileSync(configFile, 'utf8') : '';
|
|
45
|
+
|
|
46
|
+
if (contents.includes(ALIAS_MARKER)) {
|
|
47
|
+
// Already installed -- update the path in case it moved
|
|
48
|
+
const updated = contents.replace(
|
|
49
|
+
/alias claude='claude --plugin-dir ".*?"' # claudia-mentor/,
|
|
50
|
+
ALIAS_LINE
|
|
51
|
+
);
|
|
52
|
+
if (updated !== contents) {
|
|
53
|
+
fs.writeFileSync(configFile, updated);
|
|
54
|
+
aliasStatus = 'updated';
|
|
55
|
+
} else {
|
|
56
|
+
aliasStatus = 'exists';
|
|
57
|
+
}
|
|
58
|
+
} else {
|
|
59
|
+
// First install -- append alias
|
|
60
|
+
fs.appendFileSync(configFile, `\n${ALIAS_LINE}\n`);
|
|
61
|
+
aliasStatus = 'added';
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
} catch (e) {
|
|
65
|
+
aliasStatus = 'failed';
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ── Animation ──────────────────────────────────────────────────
|
|
69
|
+
|
|
70
|
+
const icon = [
|
|
71
|
+
` ${p}*${r}`,
|
|
72
|
+
` ${v}│${r}`,
|
|
73
|
+
` ${v}██████${r}`,
|
|
74
|
+
` ${v}██${r}${d2}██${r}${v}██${r}`,
|
|
75
|
+
` ${v}██${r}`,
|
|
76
|
+
` ${v}██${r}${d2}██${r}${v}██${r}`,
|
|
77
|
+
` ${v}██████${r}`,
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
const setupMsg = aliasStatus === 'added'
|
|
81
|
+
? ` ${g}✓${r} ${w}Auto-configured.${r} ${d}Restart your terminal, then just type${r} ${w}claude${r}`
|
|
82
|
+
: aliasStatus === 'updated'
|
|
83
|
+
? ` ${g}✓${r} ${d}Alias updated.${r} ${w}claude${r} ${d}always loads Claudia.${r}`
|
|
84
|
+
: aliasStatus === 'exists'
|
|
85
|
+
? ` ${g}✓${r} ${d}Already configured.${r} ${w}claude${r} ${d}always loads Claudia.${r}`
|
|
86
|
+
: ` ${d}Run:${r} ${w}claude --plugin-dir "${pluginDir}"${r}`;
|
|
87
|
+
|
|
88
|
+
const lines = [
|
|
89
|
+
...icon,
|
|
90
|
+
``,
|
|
91
|
+
` ${w}${b}Claudia${r} ${d}v${version}${r}`,
|
|
92
|
+
` ${d}The senior dev you don't have.${r}`,
|
|
93
|
+
``,
|
|
94
|
+
setupMsg,
|
|
95
|
+
``,
|
|
96
|
+
` ${d}She checks your code automatically.${r}`,
|
|
97
|
+
` ${d}She joins conversations about tech decisions.${r}`,
|
|
98
|
+
` ${d}She teaches you as you build.${r}`,
|
|
99
|
+
``,
|
|
100
|
+
` ${d}Docs:${r} ${w}https://getclaudia.dev${r}`,
|
|
101
|
+
` ${d}Source:${r} ${w}https://github.com/reganomalley/claudia${r}`,
|
|
102
|
+
``,
|
|
103
|
+
` ${d}Every Claude needs a Claudia.${r}`,
|
|
104
|
+
``,
|
|
105
|
+
];
|
|
106
|
+
|
|
107
|
+
async function sleep(ms) {
|
|
108
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function animate() {
|
|
112
|
+
process.stdout.write(hide + '\n');
|
|
113
|
+
|
|
114
|
+
for (let i = 0; i < icon.length; i++) {
|
|
115
|
+
process.stdout.write(lines[i] + '\n');
|
|
116
|
+
await sleep(50);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
await sleep(150);
|
|
120
|
+
|
|
121
|
+
for (let i = icon.length; i < lines.length; i++) {
|
|
122
|
+
process.stdout.write(lines[i] + '\n');
|
|
123
|
+
await sleep(30);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
process.stdout.write(show);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
animate().catch(() => {
|
|
130
|
+
process.stdout.write(show);
|
|
131
|
+
console.log(lines.join('\n'));
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
process.on('exit', () => process.stdout.write(show));
|
|
135
|
+
process.on('SIGINT', () => { process.stdout.write(show); process.exit(); });
|