@a5c-ai/babysitter-cursor 5.0.1-staging.e4f17eff → 5.0.1-staging.e920fef118ef
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 +23 -17
- package/bin/cli.js +8 -16
- package/bin/install-shared.js +236 -120
- package/bin/install.js +12 -28
- package/bin/uninstall.js +11 -27
- package/commands/call.md +5 -1
- package/commands/cleanup.md +30 -8
- package/commands/doctor.md +7 -8
- package/commands/help.md +246 -244
- package/commands/observe.md +17 -12
- package/commands/yolo.md +11 -7
- package/hooks/babysitter-proxied-post-tool-use.ps1 +12 -0
- package/hooks/babysitter-proxied-post-tool-use.sh +3 -0
- package/hooks/babysitter-proxied-pre-tool-use.ps1 +12 -0
- package/hooks/babysitter-proxied-pre-tool-use.sh +3 -0
- package/hooks/babysitter-proxied-session-end.ps1 +12 -0
- package/hooks/babysitter-proxied-session-end.sh +3 -0
- package/hooks/babysitter-proxied-session-start.ps1 +10 -194
- package/hooks/babysitter-proxied-session-start.sh +7 -170
- package/hooks/babysitter-proxied-stop.ps1 +12 -0
- package/hooks/babysitter-proxied-stop.sh +3 -0
- package/hooks/babysitter-proxied-user-prompt-submit.ps1 +12 -0
- package/hooks/babysitter-proxied-user-prompt-submit.sh +3 -0
- package/hooks/hooks-cursor.json +34 -2
- package/hooks.json +34 -2
- package/package.json +20 -21
- package/plugin.json +7 -5
- package/scripts/create-release-tag.mjs +18 -0
- package/scripts/publish-from-tag.mjs +41 -0
- package/scripts/team-install.js +14 -72
- package/skills/babysit/SKILL.md +2 -4
- package/skills/call/SKILL.md +5 -1
- package/skills/cleanup/SKILL.md +43 -0
- package/skills/contrib/SKILL.md +34 -0
- package/skills/doctor/SKILL.md +7 -8
- package/skills/forever/SKILL.md +8 -0
- package/skills/help/SKILL.md +4 -2
- package/skills/observe/SKILL.md +7 -2
- package/skills/plugins/SKILL.md +257 -0
- package/skills/project-install/SKILL.md +18 -0
- package/skills/resume/SKILL.md +1 -1
- package/skills/retrospect/SKILL.md +48 -48
- package/skills/user-install/SKILL.md +3 -3
- package/skills/yolo/SKILL.md +12 -0
- package/versions.json +2 -1
- package/.cursor-plugin/plugin.json +0 -22
- package/.cursorrules +0 -55
- package/hooks/babysitter-proxied-stop-hook.ps1 +0 -125
- package/hooks/babysitter-proxied-stop-hook.sh +0 -112
- package/hooks/hooks-cursor.json.legacy +0 -21
- package/hooks/proxied-hooks.json +0 -22
- package/hooks/session-start.ps1 +0 -116
- package/hooks/session-start.sh +0 -106
- package/hooks/stop-hook.ps1 +0 -73
- package/hooks/stop-hook.sh +0 -61
- package/scripts/sync-command-surfaces.js +0 -62
package/README.md
CHANGED
|
@@ -19,13 +19,13 @@ hooks so Cursor can execute Babysitter commands and hook scripts directly.
|
|
|
19
19
|
|
|
20
20
|
## Installation
|
|
21
21
|
|
|
22
|
-
Install the
|
|
22
|
+
Install the Babysitter CLI once:
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
|
-
npm install -g @a5c-ai/babysitter
|
|
25
|
+
npm install -g @a5c-ai/babysitter
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
### Via Cursor Marketplace
|
|
28
|
+
### Via Cursor Marketplace
|
|
29
29
|
|
|
30
30
|
Install through Cursor's marketplace UI using the repo-root
|
|
31
31
|
`/.cursor-plugin/marketplace.json` manifest:
|
|
@@ -34,10 +34,16 @@ Install through Cursor's marketplace UI using the repo-root
|
|
|
34
34
|
2. Open the marketplace entry named **a5c-ai**
|
|
35
35
|
3. Install the plugin named **babysitter**
|
|
36
36
|
|
|
37
|
-
### Via Babysitter harness install
|
|
37
|
+
### Via Babysitter harness install (recommended for automation)
|
|
38
|
+
|
|
39
|
+
Use the SDK helper for scriptable global or workspace installs. This resolves to `npx --yes @a5c-ai/babysitter-cursor install ...` under the hood:
|
|
38
40
|
|
|
39
41
|
```bash
|
|
42
|
+
# Global install
|
|
40
43
|
babysitter harness:install-plugin cursor
|
|
44
|
+
|
|
45
|
+
# Workspace install
|
|
46
|
+
babysitter harness:install-plugin cursor --workspace /path/to/repo
|
|
41
47
|
```
|
|
42
48
|
|
|
43
49
|
If the workspace does not already have an active process-library binding, the
|
|
@@ -51,18 +57,18 @@ babysitter process-library:active --json
|
|
|
51
57
|
|
|
52
58
|
For local development or environments without marketplace access:
|
|
53
59
|
|
|
54
|
-
#### Via
|
|
60
|
+
#### Via the published package installer
|
|
55
61
|
|
|
56
62
|
```bash
|
|
57
|
-
|
|
58
|
-
babysitter-cursor install
|
|
63
|
+
npx --yes @a5c-ai/babysitter-cursor install --global
|
|
64
|
+
npx --yes @a5c-ai/babysitter-cursor install --workspace /path/to/repo
|
|
59
65
|
```
|
|
60
66
|
|
|
61
|
-
#### From source
|
|
67
|
+
#### From generated source
|
|
62
68
|
|
|
63
69
|
```bash
|
|
64
|
-
|
|
65
|
-
node bin/install.js
|
|
70
|
+
npm run generate:plugins
|
|
71
|
+
node artifacts/generated-plugins/cursor/bin/install.js
|
|
66
72
|
```
|
|
67
73
|
|
|
68
74
|
#### Manual installation
|
|
@@ -70,9 +76,9 @@ node bin/install.js
|
|
|
70
76
|
Copy the plugin directory to your local Cursor plugins path:
|
|
71
77
|
|
|
72
78
|
```bash
|
|
73
|
-
cp -r plugins/
|
|
79
|
+
cp -r artifacts/generated-plugins/cursor ~/.cursor/plugins/local/babysitter-cursor
|
|
74
80
|
# Or symlink for faster iteration:
|
|
75
|
-
ln -s "$(pwd)/plugins/
|
|
81
|
+
ln -s "$(pwd)/artifacts/generated-plugins/cursor" ~/.cursor/plugins/local/babysitter-cursor
|
|
76
82
|
```
|
|
77
83
|
|
|
78
84
|
## Uninstallation
|
|
@@ -90,7 +96,7 @@ npm uninstall -g @a5c-ai/babysitter-cursor
|
|
|
90
96
|
## Plugin Structure (Directory Layout)
|
|
91
97
|
|
|
92
98
|
```
|
|
93
|
-
plugins/
|
|
99
|
+
artifacts/generated-plugins/cursor/
|
|
94
100
|
.cursor-plugin/
|
|
95
101
|
plugin.json # Cursor plugin manifest (skills, commands, hooks, metadata)
|
|
96
102
|
plugin.json # Babysitter plugin manifest (skills dir, hooks path, metadata)
|
|
@@ -311,7 +317,7 @@ The Cursor marketplace manifest lives at `.cursor-plugin/plugin.json`:
|
|
|
311
317
|
"email": "support@a5c.ai",
|
|
312
318
|
"url": "https://github.com/a5c-ai/babysitter"
|
|
313
319
|
},
|
|
314
|
-
"homepage": "https://github.com/a5c-ai/babysitter/tree/main/plugins/babysitter-cursor#readme",
|
|
320
|
+
"homepage": "https://github.com/a5c-ai/babysitter/tree/main/plugins/babysitter-unified/per-harness/cursor#readme",
|
|
315
321
|
"repository": "https://github.com/a5c-ai/babysitter",
|
|
316
322
|
"license": "MIT",
|
|
317
323
|
"skills": "skills/",
|
|
@@ -438,14 +444,14 @@ or WSL. The Cursor hook manifest includes explicit `powershell` entries alongsid
|
|
|
438
444
|
git clone https://github.com/a5c-ai/babysitter.git
|
|
439
445
|
cd babysitter
|
|
440
446
|
npm install
|
|
441
|
-
|
|
447
|
+
npm run generate:plugins
|
|
442
448
|
node bin/install.js
|
|
443
449
|
```
|
|
444
450
|
|
|
445
451
|
### Publishing
|
|
446
452
|
|
|
447
453
|
```bash
|
|
448
|
-
cd plugins/
|
|
454
|
+
cd artifacts/generated-plugins/cursor
|
|
449
455
|
npm run deploy # Publish to npm (public)
|
|
450
456
|
npm run deploy:staging # Publish to npm with staging tag
|
|
451
457
|
```
|
|
@@ -453,7 +459,7 @@ npm run deploy:staging # Publish to npm with staging tag
|
|
|
453
459
|
### Team installation
|
|
454
460
|
|
|
455
461
|
```bash
|
|
456
|
-
cd plugins/
|
|
462
|
+
cd artifacts/generated-plugins/cursor
|
|
457
463
|
npm run team:install
|
|
458
464
|
```
|
|
459
465
|
|
package/bin/cli.js
CHANGED
|
@@ -5,6 +5,8 @@ const path = require('path');
|
|
|
5
5
|
const { spawnSync } = require('child_process');
|
|
6
6
|
|
|
7
7
|
const PACKAGE_ROOT = path.resolve(__dirname, '..');
|
|
8
|
+
let shared;
|
|
9
|
+
try { shared = require('./install-shared'); } catch {}
|
|
8
10
|
|
|
9
11
|
function printUsage() {
|
|
10
12
|
console.error([
|
|
@@ -23,16 +25,10 @@ function parseInstallArgs(argv) {
|
|
|
23
25
|
for (let i = 0; i < argv.length; i += 1) {
|
|
24
26
|
const arg = argv[i];
|
|
25
27
|
if (arg === '--global') {
|
|
26
|
-
if (scope === 'workspace') {
|
|
27
|
-
throw new Error('install accepts either --global or --workspace, not both');
|
|
28
|
-
}
|
|
29
28
|
scope = 'global';
|
|
30
29
|
continue;
|
|
31
30
|
}
|
|
32
31
|
if (arg === '--workspace') {
|
|
33
|
-
if (scope === 'global' && workspace !== null) {
|
|
34
|
-
throw new Error('install accepts either --global or --workspace, not both');
|
|
35
|
-
}
|
|
36
32
|
scope = 'workspace';
|
|
37
33
|
const next = argv[i + 1];
|
|
38
34
|
if (next && !next.startsWith('-')) {
|
|
@@ -46,21 +42,14 @@ function parseInstallArgs(argv) {
|
|
|
46
42
|
passthrough.push(arg);
|
|
47
43
|
}
|
|
48
44
|
|
|
49
|
-
return {
|
|
50
|
-
scope,
|
|
51
|
-
workspace,
|
|
52
|
-
passthrough,
|
|
53
|
-
};
|
|
45
|
+
return { scope, workspace, passthrough };
|
|
54
46
|
}
|
|
55
47
|
|
|
56
48
|
function runNodeScript(scriptPath, args, extraEnv = {}) {
|
|
57
49
|
const result = spawnSync(process.execPath, [scriptPath, ...args], {
|
|
58
50
|
cwd: process.cwd(),
|
|
59
51
|
stdio: 'inherit',
|
|
60
|
-
env: {
|
|
61
|
-
...process.env,
|
|
62
|
-
...extraEnv,
|
|
63
|
-
},
|
|
52
|
+
env: { ...process.env, ...extraEnv },
|
|
64
53
|
});
|
|
65
54
|
process.exitCode = result.status ?? 1;
|
|
66
55
|
}
|
|
@@ -74,6 +63,9 @@ function main() {
|
|
|
74
63
|
}
|
|
75
64
|
|
|
76
65
|
if (command === 'install') {
|
|
66
|
+
if (shared && typeof shared.harnessCliRoute === 'function' && shared.harnessCliRoute(rest, PACKAGE_ROOT, runNodeScript)) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
77
69
|
const parsed = parseInstallArgs(rest);
|
|
78
70
|
if (parsed.scope === 'workspace') {
|
|
79
71
|
const args = [];
|
|
@@ -84,7 +76,7 @@ function main() {
|
|
|
84
76
|
runNodeScript(
|
|
85
77
|
path.join(PACKAGE_ROOT, 'scripts', 'team-install.js'),
|
|
86
78
|
args,
|
|
87
|
-
{
|
|
79
|
+
{ PLUGIN_PACKAGE_ROOT: PACKAGE_ROOT },
|
|
88
80
|
);
|
|
89
81
|
return;
|
|
90
82
|
}
|
package/bin/install-shared.js
CHANGED
|
@@ -5,14 +5,205 @@ const os = require('os');
|
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const { spawnSync } = require('child_process');
|
|
7
7
|
|
|
8
|
-
const PLUGIN_NAME =
|
|
8
|
+
const PLUGIN_NAME = "babysitter";
|
|
9
9
|
const PLUGIN_CATEGORY = 'Coding';
|
|
10
|
+
|
|
11
|
+
function getUserHome() {
|
|
12
|
+
return os.homedir();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function getHarnessHome() {
|
|
16
|
+
return path.join(os.homedir(), ".cursor");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function getHomePluginRoot(scope) {
|
|
20
|
+
if (scope === 'workspace') return path.join(process.cwd(), '.a5c', 'plugins', PLUGIN_NAME);
|
|
21
|
+
return path.join(path.join(getHarnessHome(), 'plugins'), PLUGIN_NAME);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function getHomeMarketplacePath() {
|
|
25
|
+
return path.join(getHarnessHome(), 'plugins', 'marketplace.json');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function writeFileIfChanged(filePath, contents) {
|
|
29
|
+
try {
|
|
30
|
+
const existing = fs.readFileSync(filePath, 'utf8');
|
|
31
|
+
if (existing === contents) return false;
|
|
32
|
+
} catch {}
|
|
33
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
34
|
+
fs.writeFileSync(filePath, contents);
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function copyRecursive(src, dest) {
|
|
39
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
40
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
41
|
+
if (entry.name === 'node_modules' || entry.name === '.git') continue;
|
|
42
|
+
const s = path.join(src, entry.name);
|
|
43
|
+
const d = path.join(dest, entry.name);
|
|
44
|
+
if (entry.isDirectory()) {
|
|
45
|
+
copyRecursive(s, d);
|
|
46
|
+
} else {
|
|
47
|
+
fs.copyFileSync(s, d);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function copyPluginBundle(packageRoot, pluginRoot) {
|
|
53
|
+
const bundleEntries = fs.readdirSync(packageRoot).filter(
|
|
54
|
+
e => !['node_modules', '.git', 'test', 'dist'].includes(e)
|
|
55
|
+
);
|
|
56
|
+
fs.mkdirSync(pluginRoot, { recursive: true });
|
|
57
|
+
for (const entry of bundleEntries) {
|
|
58
|
+
const src = path.join(packageRoot, entry);
|
|
59
|
+
const dest = path.join(pluginRoot, entry);
|
|
60
|
+
const stat = fs.statSync(src);
|
|
61
|
+
if (stat.isDirectory()) {
|
|
62
|
+
copyRecursive(src, dest);
|
|
63
|
+
} else {
|
|
64
|
+
fs.copyFileSync(src, dest);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function readJson(filePath) {
|
|
70
|
+
try {
|
|
71
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
72
|
+
} catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function writeJson(filePath, value) {
|
|
78
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
79
|
+
fs.writeFileSync(filePath, JSON.stringify(value, null, 2) + '\n');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function ensureExecutable(filePath) {
|
|
83
|
+
try {
|
|
84
|
+
fs.chmodSync(filePath, 0o755);
|
|
85
|
+
} catch {}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function normalizeMarketplaceSourcePath(source, marketplacePath) {
|
|
89
|
+
if (typeof source === 'string') {
|
|
90
|
+
return path.relative(path.dirname(marketplacePath), source).replace(/\\/g, '/');
|
|
91
|
+
}
|
|
92
|
+
return source;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function ensureMarketplaceEntry(marketplacePath, pluginRoot) {
|
|
96
|
+
let marketplace = readJson(marketplacePath) || {
|
|
97
|
+
name: "a5c.ai",
|
|
98
|
+
plugins: [],
|
|
99
|
+
};
|
|
100
|
+
if (!Array.isArray(marketplace.plugins)) marketplace.plugins = [];
|
|
101
|
+
const idx = marketplace.plugins.findIndex(p => p.name === PLUGIN_NAME);
|
|
102
|
+
const relSource = './' + normalizeMarketplaceSourcePath(pluginRoot, marketplacePath);
|
|
103
|
+
const entry = {
|
|
104
|
+
name: PLUGIN_NAME,
|
|
105
|
+
source: relSource,
|
|
106
|
+
description: "Orchestrate complex, multi-step workflows with event-sourced state management, hook-based extensibility, and human-in-the-loop approval",
|
|
107
|
+
version: "5.0.1-staging.e920fef118ef",
|
|
108
|
+
author: { name: "a5c.ai" },
|
|
109
|
+
};
|
|
110
|
+
if (idx >= 0) marketplace.plugins[idx] = entry;
|
|
111
|
+
else marketplace.plugins.push(entry);
|
|
112
|
+
writeJson(marketplacePath, marketplace);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function removeMarketplaceEntry(marketplacePath) {
|
|
116
|
+
const marketplace = readJson(marketplacePath);
|
|
117
|
+
if (!marketplace || !Array.isArray(marketplace.plugins)) return;
|
|
118
|
+
marketplace.plugins = marketplace.plugins.filter(p => p.name !== PLUGIN_NAME);
|
|
119
|
+
writeJson(marketplacePath, marketplace);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function warnWindowsHooks() {
|
|
123
|
+
if (process.platform === 'win32') {
|
|
124
|
+
console.warn('[' + PLUGIN_NAME + '] Windows detected — shell hooks (.sh) require Git Bash or WSL.');
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function runPostInstall(pluginRoot) {
|
|
129
|
+
const postInstall = path.join(pluginRoot, 'scripts', 'post-install.js');
|
|
130
|
+
if (fs.existsSync(postInstall)) {
|
|
131
|
+
spawnSync(process.execPath, [postInstall], {
|
|
132
|
+
cwd: pluginRoot, stdio: 'inherit',
|
|
133
|
+
env: { ...process.env, PLUGIN_ROOT: pluginRoot },
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function getGlobalStateDir() {
|
|
139
|
+
return process.env.BABYSITTER_GLOBAL_STATE_DIR || path.join(getUserHome(), '.a5c');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function resolveCliCommand(packageRoot) {
|
|
143
|
+
try {
|
|
144
|
+
const result = spawnSync('babysitter', ['--version'], { stdio: 'pipe', timeout: 10000 });
|
|
145
|
+
if (result.status === 0) return 'babysitter';
|
|
146
|
+
} catch {}
|
|
147
|
+
const versionsPath = path.join(packageRoot, 'versions.json');
|
|
148
|
+
const versions = readJson(versionsPath) || {};
|
|
149
|
+
const ver = versions.sdkVersion || 'latest';
|
|
150
|
+
return `npx -y @a5c-ai/babysitter-sdk@${ver}`;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function runCli(packageRoot, cliArgs, options = {}) {
|
|
154
|
+
const cmd = resolveCliCommand(packageRoot);
|
|
155
|
+
const parts = cmd.split(' ');
|
|
156
|
+
const result = spawnSync(parts[0], [...parts.slice(1), ...cliArgs], {
|
|
157
|
+
stdio: options.stdio || 'inherit',
|
|
158
|
+
timeout: options.timeout || 120000,
|
|
159
|
+
cwd: options.cwd || process.cwd(),
|
|
160
|
+
env: { ...process.env, ...options.env },
|
|
161
|
+
});
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function ensureGlobalProcessLibrary(packageRoot) {
|
|
166
|
+
const stateDir = getGlobalStateDir();
|
|
167
|
+
const activeFile = path.join(stateDir, 'active', 'process-library.json');
|
|
168
|
+
let active = readJson(activeFile);
|
|
169
|
+
if (active && active.binding && active.binding.dir) {
|
|
170
|
+
return active;
|
|
171
|
+
}
|
|
172
|
+
const defaultSpec = readJson(path.join(stateDir, 'process-library-defaults.json'));
|
|
173
|
+
const cloneDir = defaultSpec && defaultSpec.cloneDir
|
|
174
|
+
? defaultSpec.cloneDir
|
|
175
|
+
: path.join(stateDir, 'process-library', PLUGIN_NAME + '-repo');
|
|
176
|
+
runCli(packageRoot, [
|
|
177
|
+
'process-library:clone',
|
|
178
|
+
'--dir', cloneDir,
|
|
179
|
+
'--state-dir', stateDir,
|
|
180
|
+
'--json',
|
|
181
|
+
], { stdio: 'pipe' });
|
|
182
|
+
runCli(packageRoot, [
|
|
183
|
+
'process-library:use',
|
|
184
|
+
'--dir', cloneDir,
|
|
185
|
+
'--state-dir', stateDir,
|
|
186
|
+
'--json',
|
|
187
|
+
], { stdio: 'pipe' });
|
|
188
|
+
active = readJson(activeFile);
|
|
189
|
+
return {
|
|
190
|
+
binding: active && active.binding ? active.binding : { dir: cloneDir },
|
|
191
|
+
defaultSpec: defaultSpec || { cloneDir },
|
|
192
|
+
stateFile: activeFile,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
// Cursor-specific install surface.
|
|
198
|
+
// Appended after the compiler base and SDK surface — can override base functions.
|
|
199
|
+
|
|
10
200
|
const HOOK_SCRIPT_NAMES = [
|
|
11
|
-
'session-start.sh',
|
|
12
|
-
'session-start.ps1',
|
|
13
|
-
'stop
|
|
14
|
-
'stop
|
|
201
|
+
'babysitter-proxied-session-start.sh',
|
|
202
|
+
'babysitter-proxied-session-start.ps1',
|
|
203
|
+
'babysitter-proxied-stop.sh',
|
|
204
|
+
'babysitter-proxied-stop.ps1',
|
|
15
205
|
];
|
|
206
|
+
|
|
16
207
|
const DEFAULT_MARKETPLACE = {
|
|
17
208
|
name: 'local-plugins',
|
|
18
209
|
interface: {
|
|
@@ -20,10 +211,12 @@ const DEFAULT_MARKETPLACE = {
|
|
|
20
211
|
},
|
|
21
212
|
plugins: [],
|
|
22
213
|
};
|
|
214
|
+
|
|
23
215
|
const MANAGED_HOOKS_CONFIG_PATHS = [
|
|
24
216
|
path.join('hooks', 'hooks-cursor.json'),
|
|
25
217
|
'hooks.json',
|
|
26
218
|
];
|
|
219
|
+
|
|
27
220
|
const PLUGIN_BUNDLE_ENTRIES = [
|
|
28
221
|
'.cursor-plugin',
|
|
29
222
|
'plugin.json',
|
|
@@ -40,19 +233,6 @@ function getCursorHome() {
|
|
|
40
233
|
return path.join(os.homedir(), '.cursor');
|
|
41
234
|
}
|
|
42
235
|
|
|
43
|
-
function getUserHome() {
|
|
44
|
-
if (process.env.USERPROFILE) return path.resolve(process.env.USERPROFILE);
|
|
45
|
-
if (process.env.HOME) return path.resolve(process.env.HOME);
|
|
46
|
-
return os.homedir();
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function getGlobalStateDir() {
|
|
50
|
-
if (process.env.BABYSITTER_GLOBAL_STATE_DIR) {
|
|
51
|
-
return path.resolve(process.env.BABYSITTER_GLOBAL_STATE_DIR);
|
|
52
|
-
}
|
|
53
|
-
return path.join(getUserHome(), '.a5c');
|
|
54
|
-
}
|
|
55
|
-
|
|
56
236
|
function getHomePluginRoot() {
|
|
57
237
|
if (process.env.BABYSITTER_CURSOR_PLUGIN_DIR) {
|
|
58
238
|
return path.resolve(process.env.BABYSITTER_CURSOR_PLUGIN_DIR, PLUGIN_NAME);
|
|
@@ -67,18 +247,6 @@ function getHomeMarketplacePath() {
|
|
|
67
247
|
return path.join(getUserHome(), '.agents', 'plugins', 'marketplace.json');
|
|
68
248
|
}
|
|
69
249
|
|
|
70
|
-
function writeFileIfChanged(filePath, contents) {
|
|
71
|
-
if (fs.existsSync(filePath)) {
|
|
72
|
-
const current = fs.readFileSync(filePath, 'utf8');
|
|
73
|
-
if (current === contents) {
|
|
74
|
-
return false;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
78
|
-
fs.writeFileSync(filePath, contents, 'utf8');
|
|
79
|
-
return true;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
250
|
function copyRecursive(src, dest) {
|
|
83
251
|
const stat = fs.statSync(src);
|
|
84
252
|
if (stat.isDirectory()) {
|
|
@@ -90,6 +258,7 @@ function copyRecursive(src, dest) {
|
|
|
90
258
|
return;
|
|
91
259
|
}
|
|
92
260
|
|
|
261
|
+
// Strip UTF-8 BOM from SKILL.md files
|
|
93
262
|
if (path.basename(src) === 'SKILL.md') {
|
|
94
263
|
const file = fs.readFileSync(src);
|
|
95
264
|
const hasBom = file.length >= 3 && file[0] === 0xef && file[1] === 0xbb && file[2] === 0xbf;
|
|
@@ -116,14 +285,6 @@ function copyPluginBundle(packageRoot, pluginRoot) {
|
|
|
116
285
|
}
|
|
117
286
|
}
|
|
118
287
|
|
|
119
|
-
function ensureExecutable(filePath) {
|
|
120
|
-
try {
|
|
121
|
-
fs.chmodSync(filePath, 0o755);
|
|
122
|
-
} catch {
|
|
123
|
-
// Best-effort only. Windows and some filesystems may ignore mode changes.
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
288
|
function normalizeMarketplaceSourcePath(marketplacePath, pluginSourcePath) {
|
|
128
289
|
let next = pluginSourcePath;
|
|
129
290
|
if (path.isAbsolute(next)) {
|
|
@@ -136,24 +297,6 @@ function normalizeMarketplaceSourcePath(marketplacePath, pluginSourcePath) {
|
|
|
136
297
|
return next;
|
|
137
298
|
}
|
|
138
299
|
|
|
139
|
-
function readJson(filePath) {
|
|
140
|
-
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function getManagedHooksConfigPath(packageRoot) {
|
|
144
|
-
for (const relativePath of MANAGED_HOOKS_CONFIG_PATHS) {
|
|
145
|
-
const candidate = path.join(packageRoot, relativePath);
|
|
146
|
-
if (fs.existsSync(candidate)) {
|
|
147
|
-
return candidate;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
return null;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function writeJson(filePath, value) {
|
|
154
|
-
writeFileIfChanged(filePath, `${JSON.stringify(value, null, 2)}\n`);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
300
|
function normalizeMarketplaceName(name) {
|
|
158
301
|
const raw = String(name || '').trim();
|
|
159
302
|
const sanitized = raw
|
|
@@ -208,6 +351,16 @@ function removeMarketplaceEntry(marketplacePath) {
|
|
|
208
351
|
writeJson(marketplacePath, marketplace);
|
|
209
352
|
}
|
|
210
353
|
|
|
354
|
+
function getManagedHooksConfigPath(packageRoot) {
|
|
355
|
+
for (const relativePath of MANAGED_HOOKS_CONFIG_PATHS) {
|
|
356
|
+
const candidate = path.join(packageRoot, relativePath);
|
|
357
|
+
if (fs.existsSync(candidate)) {
|
|
358
|
+
return candidate;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
363
|
+
|
|
211
364
|
function mergeManagedHooksConfig(packageRoot, cursorHome) {
|
|
212
365
|
const hooksJsonPath = getManagedHooksConfigPath(packageRoot);
|
|
213
366
|
if (!hooksJsonPath) return;
|
|
@@ -313,62 +466,6 @@ function installCursorSurface(packageRoot, cursorHome) {
|
|
|
313
466
|
}
|
|
314
467
|
}
|
|
315
468
|
|
|
316
|
-
function resolveBabysitterCommand(packageRoot) {
|
|
317
|
-
if (process.env.BABYSITTER_SDK_CLI) {
|
|
318
|
-
return {
|
|
319
|
-
command: process.execPath,
|
|
320
|
-
argsPrefix: [path.resolve(process.env.BABYSITTER_SDK_CLI)],
|
|
321
|
-
};
|
|
322
|
-
}
|
|
323
|
-
try {
|
|
324
|
-
return {
|
|
325
|
-
command: process.execPath,
|
|
326
|
-
argsPrefix: [
|
|
327
|
-
require.resolve('@a5c-ai/babysitter-sdk/dist/cli/main.js', {
|
|
328
|
-
paths: [packageRoot],
|
|
329
|
-
}),
|
|
330
|
-
],
|
|
331
|
-
};
|
|
332
|
-
} catch {
|
|
333
|
-
return {
|
|
334
|
-
command: 'babysitter',
|
|
335
|
-
argsPrefix: [],
|
|
336
|
-
};
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
function runBabysitterCli(packageRoot, cliArgs, options = {}) {
|
|
341
|
-
const resolved = resolveBabysitterCommand(packageRoot);
|
|
342
|
-
const result = spawnSync(resolved.command, [...resolved.argsPrefix, ...cliArgs], {
|
|
343
|
-
cwd: options.cwd || process.cwd(),
|
|
344
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
345
|
-
encoding: 'utf8',
|
|
346
|
-
env: {
|
|
347
|
-
...process.env,
|
|
348
|
-
...(options.env || {}),
|
|
349
|
-
},
|
|
350
|
-
});
|
|
351
|
-
if (result.status !== 0) {
|
|
352
|
-
const stderr = (result.stderr || '').trim();
|
|
353
|
-
const stdout = (result.stdout || '').trim();
|
|
354
|
-
throw new Error(
|
|
355
|
-
`babysitter ${cliArgs.join(' ')} failed` +
|
|
356
|
-
(stderr ? `: ${stderr}` : stdout ? `: ${stdout}` : ''),
|
|
357
|
-
);
|
|
358
|
-
}
|
|
359
|
-
return result.stdout;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
function ensureGlobalProcessLibrary(packageRoot) {
|
|
363
|
-
return JSON.parse(
|
|
364
|
-
runBabysitterCli(
|
|
365
|
-
packageRoot,
|
|
366
|
-
['process-library:active', '--state-dir', getGlobalStateDir(), '--json'],
|
|
367
|
-
{ cwd: packageRoot },
|
|
368
|
-
),
|
|
369
|
-
);
|
|
370
|
-
}
|
|
371
|
-
|
|
372
469
|
function warnWindowsHooks() {
|
|
373
470
|
if (process.platform !== 'win32') {
|
|
374
471
|
return;
|
|
@@ -377,18 +474,37 @@ function warnWindowsHooks() {
|
|
|
377
474
|
console.warn(`[${PLUGIN_NAME}] Both bash (.sh) and PowerShell (.ps1) hook scripts are included.`);
|
|
378
475
|
}
|
|
379
476
|
|
|
477
|
+
|
|
380
478
|
module.exports = {
|
|
381
|
-
|
|
479
|
+
PLUGIN_NAME,
|
|
480
|
+
PLUGIN_CATEGORY,
|
|
481
|
+
getUserHome,
|
|
482
|
+
getHarnessHome,
|
|
483
|
+
writeFileIfChanged,
|
|
484
|
+
readJson,
|
|
485
|
+
writeJson,
|
|
486
|
+
ensureExecutable,
|
|
487
|
+
runPostInstall,
|
|
488
|
+
getGlobalStateDir,
|
|
489
|
+
resolveCliCommand,
|
|
490
|
+
runCli,
|
|
382
491
|
ensureGlobalProcessLibrary,
|
|
492
|
+
PLUGIN_BUNDLE_ENTRIES,
|
|
493
|
+
copyRecursive,
|
|
494
|
+
copyPluginBundle,
|
|
495
|
+
DEFAULT_MARKETPLACE,
|
|
496
|
+
normalizeMarketplaceSourcePath,
|
|
497
|
+
normalizeMarketplaceName,
|
|
383
498
|
ensureMarketplaceEntry,
|
|
384
|
-
|
|
499
|
+
removeMarketplaceEntry,
|
|
500
|
+
mergeManagedHooksConfig,
|
|
501
|
+
warnWindowsHooks,
|
|
502
|
+
HOOK_SCRIPT_NAMES,
|
|
503
|
+
MANAGED_HOOKS_CONFIG_PATHS,
|
|
385
504
|
getCursorHome,
|
|
386
|
-
getHomeMarketplacePath,
|
|
387
505
|
getHomePluginRoot,
|
|
388
|
-
|
|
506
|
+
getHomeMarketplacePath,
|
|
507
|
+
getManagedHooksConfigPath,
|
|
389
508
|
removeManagedHooks,
|
|
390
|
-
|
|
391
|
-
warnWindowsHooks,
|
|
392
|
-
writeJson,
|
|
393
|
-
normalizeMarketplaceName,
|
|
509
|
+
installCursorSurface,
|
|
394
510
|
};
|
package/bin/install.js
CHANGED
|
@@ -2,43 +2,27 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
const path = require('path');
|
|
5
|
-
const
|
|
6
|
-
copyPluginBundle,
|
|
7
|
-
ensureGlobalProcessLibrary,
|
|
8
|
-
ensureMarketplaceEntry,
|
|
9
|
-
getCursorHome,
|
|
10
|
-
getHomeMarketplacePath,
|
|
11
|
-
getHomePluginRoot,
|
|
12
|
-
installCursorSurface,
|
|
13
|
-
warnWindowsHooks,
|
|
14
|
-
} = require('./install-shared');
|
|
5
|
+
const shared = require('./install-shared');
|
|
15
6
|
|
|
16
7
|
const PACKAGE_ROOT = path.resolve(__dirname, '..');
|
|
17
8
|
|
|
18
9
|
function main() {
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const marketplacePath = getHomeMarketplacePath();
|
|
10
|
+
const pluginRoot = shared.getHomePluginRoot();
|
|
11
|
+
const marketplacePath = shared.getHomeMarketplacePath();
|
|
22
12
|
|
|
23
|
-
console.log(`[
|
|
13
|
+
console.log(`[${shared.PLUGIN_NAME}] Installing plugin to ${pluginRoot}`);
|
|
24
14
|
|
|
25
15
|
try {
|
|
26
|
-
copyPluginBundle(PACKAGE_ROOT, pluginRoot);
|
|
27
|
-
ensureMarketplaceEntry(marketplacePath, pluginRoot);
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const active = ensureGlobalProcessLibrary(PACKAGE_ROOT);
|
|
31
|
-
console.log(`[babysitter] marketplace: ${marketplacePath}`);
|
|
32
|
-
console.log(`[babysitter] process library: ${active.binding?.dir}`);
|
|
33
|
-
if (active.defaultSpec?.cloneDir) {
|
|
34
|
-
console.log(`[babysitter] process library clone: ${active.defaultSpec.cloneDir}`);
|
|
16
|
+
shared.copyPluginBundle(PACKAGE_ROOT, pluginRoot);
|
|
17
|
+
shared.ensureMarketplaceEntry(marketplacePath, pluginRoot);
|
|
18
|
+
if (typeof shared.harnessInstall === 'function') {
|
|
19
|
+
shared.harnessInstall(PACKAGE_ROOT, pluginRoot);
|
|
35
20
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
console.log(
|
|
39
|
-
console.log('[babysitter] Restart Cursor to pick up the installed plugin and config changes.');
|
|
21
|
+
shared.runPostInstall && shared.runPostInstall(pluginRoot);
|
|
22
|
+
console.log(`[${shared.PLUGIN_NAME}] Installation complete!`);
|
|
23
|
+
console.log(`[${shared.PLUGIN_NAME}] Restart your IDE/CLI to pick up the plugin.`);
|
|
40
24
|
} catch (err) {
|
|
41
|
-
console.error(`[
|
|
25
|
+
console.error(`[${shared.PLUGIN_NAME}] Failed to install: ${err.message}`);
|
|
42
26
|
process.exitCode = 1;
|
|
43
27
|
}
|
|
44
28
|
}
|