@a5c-ai/babysitter-cursor 0.1.5-staging.f6cb97d6 → 5.0.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/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 +7 -7
- package/commands/contrib.md +31 -31
- package/commands/doctor.md +5 -5
- package/commands/forever.md +6 -6
- package/commands/help.md +245 -244
- package/commands/observe.md +12 -12
- package/commands/plan.md +7 -7
- package/commands/plugins.md +249 -249
- package/commands/project-install.md +10 -10
- package/commands/resume.md +8 -8
- package/commands/retrospect.md +55 -55
- package/commands/user-install.md +10 -10
- package/commands/yolo.md +7 -7
- package/hooks/babysitter-proxied-session-start.ps1 +12 -0
- package/hooks/babysitter-proxied-session-start.sh +11 -0
- package/hooks/babysitter-proxied-stop.ps1 +12 -0
- package/hooks/babysitter-proxied-stop.sh +3 -0
- package/hooks/hooks-cursor.json +4 -4
- package/hooks.json +4 -4
- package/package.json +20 -21
- package/plugin.json +7 -5
- package/scripts/create-release-tag.mjs +18 -0
- package/scripts/publish-from-tag.mjs +12 -0
- package/scripts/team-install.js +14 -72
- package/skills/babysit/SKILL.md +2 -0
- package/skills/cleanup/SKILL.md +21 -0
- package/skills/contrib/SKILL.md +34 -0
- package/skills/doctor/SKILL.md +5 -5
- package/skills/forever/SKILL.md +8 -0
- package/skills/help/SKILL.md +3 -2
- package/skills/observe/SKILL.md +1 -1
- package/skills/plugins/SKILL.md +257 -0
- package/skills/project-install/SKILL.md +18 -0
- package/skills/yolo/SKILL.md +8 -0
- package/versions.json +2 -1
- package/.cursor-plugin/plugin.json +0 -22
- package/.cursorrules +0 -55
- package/hooks/session-start.ps1 +0 -115
- package/hooks/session-start.sh +0 -105
- package/hooks/stop-hook.ps1 +0 -72
- package/hooks/stop-hook.sh +0 -64
- package/scripts/sync-command-surfaces.js +0 -62
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.0",
|
|
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
|
}
|
package/bin/uninstall.js
CHANGED
|
@@ -2,39 +2,23 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
const fs = require('fs');
|
|
5
|
-
const
|
|
6
|
-
getCursorHome,
|
|
7
|
-
getHomeMarketplacePath,
|
|
8
|
-
getHomePluginRoot,
|
|
9
|
-
removeManagedHooks,
|
|
10
|
-
removeMarketplaceEntry,
|
|
11
|
-
} = require('./install-shared');
|
|
5
|
+
const shared = require('./install-shared');
|
|
12
6
|
|
|
13
7
|
function main() {
|
|
14
|
-
const
|
|
15
|
-
const pluginRoot = getHomePluginRoot();
|
|
16
|
-
const marketplacePath = getHomeMarketplacePath();
|
|
17
|
-
let removedPlugin = false;
|
|
8
|
+
const pluginRoot = shared.getHomePluginRoot();
|
|
18
9
|
|
|
19
|
-
if (fs.existsSync(pluginRoot)) {
|
|
20
|
-
|
|
21
|
-
fs.rmSync(pluginRoot, { recursive: true, force: true });
|
|
22
|
-
console.log(`[babysitter] Removed ${pluginRoot}`);
|
|
23
|
-
removedPlugin = true;
|
|
24
|
-
} catch (err) {
|
|
25
|
-
console.warn(`[babysitter] Warning: Could not remove plugin directory ${pluginRoot}: ${err.message}`);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
removeMarketplaceEntry(marketplacePath);
|
|
30
|
-
removeManagedHooks(cursorHome);
|
|
31
|
-
|
|
32
|
-
if (!removedPlugin) {
|
|
33
|
-
console.log('[babysitter] Plugin directory not found, config and hooks cleaned if present.');
|
|
10
|
+
if (!fs.existsSync(pluginRoot)) {
|
|
11
|
+
console.log(`[${shared.PLUGIN_NAME}] Plugin not installed at ${pluginRoot}`);
|
|
34
12
|
return;
|
|
35
13
|
}
|
|
36
14
|
|
|
37
|
-
|
|
15
|
+
try {
|
|
16
|
+
fs.rmSync(pluginRoot, { recursive: true, force: true });
|
|
17
|
+
console.log(`[${shared.PLUGIN_NAME}] Uninstalled from ${pluginRoot}`);
|
|
18
|
+
} catch (err) {
|
|
19
|
+
console.error(`[${shared.PLUGIN_NAME}] Failed to uninstall: ${err.message}`);
|
|
20
|
+
process.exitCode = 1;
|
|
21
|
+
}
|
|
38
22
|
}
|
|
39
23
|
|
|
40
24
|
main();
|
package/commands/call.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Orchestrate a babysitter run. use this command to start babysitting a complex workflow.
|
|
3
|
-
argument-hint: Specific instructions for the run.
|
|
4
|
-
allowed-tools: Read, Grep, Write, Task, Bash, Edit, Grep, Glob, WebFetch, WebSearch, Search, AskUserQuestion, TodoWrite, TodoRead, Skill, BashOutput, KillShell, MultiEdit, LS
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
Invoke the babysitter:babysit skill (using the Skill tool) and follow its instructions (SKILL.md).
|
|
1
|
+
---
|
|
2
|
+
description: Orchestrate a babysitter run. use this command to start babysitting a complex workflow.
|
|
3
|
+
argument-hint: Specific instructions for the run.
|
|
4
|
+
allowed-tools: Read, Grep, Write, Task, Bash, Edit, Grep, Glob, WebFetch, WebSearch, Search, AskUserQuestion, TodoWrite, TodoRead, Skill, BashOutput, KillShell, MultiEdit, LS
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Invoke the babysitter:babysit skill (using the Skill tool) and follow its instructions (SKILL.md).
|
package/commands/contrib.md
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Submit feedback or contribute to babysitter project
|
|
3
|
-
argument-hint: Specific instructions for the run.
|
|
4
|
-
allowed-tools: Read, Grep, Write, Task, Bash, Edit, Grep, Glob, WebFetch, WebSearch, Search, AskUserQuestion, TodoWrite, TodoRead, Skill, BashOutput, KillShell, MultiEdit, LS
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
Invoke the babysitter:babysit skill (using the Skill tool) and follow its instructions (SKILL.md).
|
|
8
|
-
|
|
9
|
-
## Process Routing
|
|
10
|
-
|
|
1
|
+
---
|
|
2
|
+
description: Submit feedback or contribute to babysitter project
|
|
3
|
+
argument-hint: Specific instructions for the run.
|
|
4
|
+
allowed-tools: Read, Grep, Write, Task, Bash, Edit, Grep, Glob, WebFetch, WebSearch, Search, AskUserQuestion, TodoWrite, TodoRead, Skill, BashOutput, KillShell, MultiEdit, LS
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Invoke the babysitter:babysit skill (using the Skill tool) and follow its instructions (SKILL.md).
|
|
8
|
+
|
|
9
|
+
## Process Routing
|
|
10
|
+
|
|
11
11
|
Contribution processes live under the active process library's `cradle/` directory. Resolve the active library root with `babysitter process-library:active --json` and route based on arguments:
|
|
12
|
-
|
|
13
|
-
### Issue-based (opens a GitHub issue in a5c-ai/babysitter)
|
|
14
|
-
* **Bug report** → `cradle/bug-report.js#process` — Report a bug in the SDK, CLI, process library, etc.
|
|
15
|
-
* **Feature request** → `cradle/feature-request.js#process` — Request a new feature or enhancement
|
|
16
|
-
* **Documentation question** → `cradle/documentation-question.js#process` — Ask about undocumented behavior or missing docs
|
|
17
|
-
|
|
18
|
-
### PR-based (forks repo, creates branch, submits PR to a5c-ai/babysitter)
|
|
19
|
-
* **Bugfix** → `cradle/bugfix.js#process` — User already has the fix for a bug
|
|
20
|
-
* **Feature implementation** → `cradle/feature-implementation-contribute.js#process` — User already has a feature implementation
|
|
21
|
-
* **Harness integration** → `cradle/feature-harness-integration-contribute.js#process` — User has a harness (CI/CD, IDE, editor) integration
|
|
22
|
-
* **Library contribution** → `cradle/library-contribution.js#process` — New or improved process/skill/subagent for the library
|
|
23
|
-
* **Documentation answer** → `cradle/documentation-contribute-answer.js#process` — User has an answer for an unanswered docs question
|
|
24
|
-
|
|
25
|
-
### Router (when arguments are empty or general)
|
|
26
|
-
* **Contribute** → `cradle/contribute.js#process` — Explains contribution types and routes to the specific process
|
|
27
|
-
|
|
28
|
-
## Contribution Rules
|
|
29
|
-
|
|
30
|
-
* PR-based contributions: fork the babysitter repo (a5c-ai/babysitter) for the user, ask to star if not already starred, perform changes, submit PR
|
|
31
|
-
* Issue-based contributions: gather details, search for duplicates, review, then open an issue in a5c-ai/babysitter
|
|
32
|
-
* Add breakpoints (permissions) before ALL gh actions (fork, star, submit PR/issue) to allow user review and cancellation
|
|
12
|
+
|
|
13
|
+
### Issue-based (opens a GitHub issue in a5c-ai/babysitter)
|
|
14
|
+
* **Bug report** → `cradle/bug-report.js#process` — Report a bug in the SDK, CLI, process library, etc.
|
|
15
|
+
* **Feature request** → `cradle/feature-request.js#process` — Request a new feature or enhancement
|
|
16
|
+
* **Documentation question** → `cradle/documentation-question.js#process` — Ask about undocumented behavior or missing docs
|
|
17
|
+
|
|
18
|
+
### PR-based (forks repo, creates branch, submits PR to a5c-ai/babysitter)
|
|
19
|
+
* **Bugfix** → `cradle/bugfix.js#process` — User already has the fix for a bug
|
|
20
|
+
* **Feature implementation** → `cradle/feature-implementation-contribute.js#process` — User already has a feature implementation
|
|
21
|
+
* **Harness integration** → `cradle/feature-harness-integration-contribute.js#process` — User has a harness (CI/CD, IDE, editor) integration
|
|
22
|
+
* **Library contribution** → `cradle/library-contribution.js#process` — New or improved process/skill/subagent for the library
|
|
23
|
+
* **Documentation answer** → `cradle/documentation-contribute-answer.js#process` — User has an answer for an unanswered docs question
|
|
24
|
+
|
|
25
|
+
### Router (when arguments are empty or general)
|
|
26
|
+
* **Contribute** → `cradle/contribute.js#process` — Explains contribution types and routes to the specific process
|
|
27
|
+
|
|
28
|
+
## Contribution Rules
|
|
29
|
+
|
|
30
|
+
* PR-based contributions: fork the babysitter repo (a5c-ai/babysitter) for the user, ask to star if not already starred, perform changes, submit PR
|
|
31
|
+
* Issue-based contributions: gather details, search for duplicates, review, then open an issue in a5c-ai/babysitter
|
|
32
|
+
* Add breakpoints (permissions) before ALL gh actions (fork, star, submit PR/issue) to allow user review and cancellation
|
|
33
33
|
* If arguments are empty: use the `contribute.js` router process to show options and route accordingly
|