@a5c-ai/babysitter-omp 0.1.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 +80 -0
- package/bin/cli.cjs +78 -0
- package/bin/install.cjs +144 -0
- package/bin/uninstall.cjs +40 -0
- package/commands/babysitter-call.md +12 -0
- package/commands/babysitter-doctor.md +10 -0
- package/commands/babysitter-resume.md +16 -0
- package/commands/babysitter-status.md +15 -0
- package/extensions/babysitter/cli-wrapper.ts +95 -0
- package/extensions/babysitter/constants.ts +77 -0
- package/extensions/babysitter/custom-tools.ts +208 -0
- package/extensions/babysitter/effect-executor.ts +362 -0
- package/extensions/babysitter/guards.ts +257 -0
- package/extensions/babysitter/index.ts +554 -0
- package/extensions/babysitter/loop-driver.ts +256 -0
- package/extensions/babysitter/result-poster.ts +115 -0
- package/extensions/babysitter/sdk-bridge.ts +243 -0
- package/extensions/babysitter/session-binder.ts +284 -0
- package/extensions/babysitter/status-line.ts +54 -0
- package/extensions/babysitter/task-interceptor.ts +82 -0
- package/extensions/babysitter/todo-replacement.ts +125 -0
- package/extensions/babysitter/tool-renderer.ts +263 -0
- package/extensions/babysitter/tui-widgets.ts +164 -0
- package/extensions/babysitter/types.ts +222 -0
- package/package.json +57 -0
- package/scripts/setup.sh +74 -0
- package/scripts/sync-command-docs.cjs +115 -0
- package/skills/babysitter/SKILL.md +45 -0
package/README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# @a5c-ai/babysitter-omp
|
|
2
|
+
|
|
3
|
+
Babysitter integration plugin for `oh-my-pi`. This package owns the
|
|
4
|
+
oh-my-pi-specific install surface, command docs, and skill wiring while sharing
|
|
5
|
+
compatible runtime internals with the upstream Pi-family.
|
|
6
|
+
|
|
7
|
+
## Integration Model
|
|
8
|
+
|
|
9
|
+
The oh-my-pi plugin keeps Babysitter as the orchestration layer for omp
|
|
10
|
+
sessions:
|
|
11
|
+
|
|
12
|
+
- session lifecycle hooks prepare and bind run state
|
|
13
|
+
- omp commands start or resume runs
|
|
14
|
+
- the harness advances one orchestration phase at a time
|
|
15
|
+
- the plugin runtime records effect outcomes and updates the run state
|
|
16
|
+
- completion requires the emitted `completionProof`
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
Install the published oh-my-pi plugin globally:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx @a5c-ai/babysitter-omp install
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Install into a specific workspace instead of the user profile:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx @a5c-ai/babysitter-omp install --workspace /path/to/repo
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Or use the Babysitter SDK helper:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
babysitter harness:install-plugin oh-my-pi
|
|
36
|
+
babysitter harness:install-plugin oh-my-pi --workspace /path/to/repo
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
This package installs under:
|
|
40
|
+
|
|
41
|
+
```text
|
|
42
|
+
~/.omp/plugins/babysitter
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
If the workspace does not already have an active process-library binding, the
|
|
46
|
+
installer bootstraps the shared global SDK process library automatically:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
babysitter process-library:active --json
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Commands
|
|
53
|
+
|
|
54
|
+
The plugin exposes oh-my-pi-facing Babysitter commands such as:
|
|
55
|
+
|
|
56
|
+
- `/babysitter:call`
|
|
57
|
+
- `/babysitter:status`
|
|
58
|
+
- `/babysitter:resume`
|
|
59
|
+
- `/babysitter:doctor`
|
|
60
|
+
|
|
61
|
+
## Troubleshooting
|
|
62
|
+
|
|
63
|
+
- `babysitter harness:discover --json` is the supported way to verify whether
|
|
64
|
+
`oh-my-pi` is installed from the current environment.
|
|
65
|
+
- If discovery reports `oh-my-pi` as installed but a direct invocation fails,
|
|
66
|
+
validate the current shell `PATH` first with `where omp` on Windows.
|
|
67
|
+
|
|
68
|
+
## Tests
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
cd plugins/babysitter-omp
|
|
72
|
+
npm test
|
|
73
|
+
npm run test:integration
|
|
74
|
+
npm run test:harness
|
|
75
|
+
npm run test:tui
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## License
|
|
79
|
+
|
|
80
|
+
MIT
|
package/bin/cli.cjs
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { spawnSync } = require('child_process');
|
|
6
|
+
|
|
7
|
+
const PACKAGE_ROOT = path.resolve(__dirname, '..');
|
|
8
|
+
|
|
9
|
+
function printUsage() {
|
|
10
|
+
console.error([
|
|
11
|
+
'Usage:',
|
|
12
|
+
' babysitter-omp install [--global]',
|
|
13
|
+
' babysitter-omp install --workspace [path]',
|
|
14
|
+
' babysitter-omp uninstall [--global]',
|
|
15
|
+
' babysitter-omp uninstall --workspace [path]',
|
|
16
|
+
].join('\n'));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function parseArgs(argv) {
|
|
20
|
+
let workspace = null;
|
|
21
|
+
|
|
22
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
23
|
+
const arg = argv[i];
|
|
24
|
+
if (arg === '--workspace') {
|
|
25
|
+
const next = argv[i + 1];
|
|
26
|
+
if (next && !next.startsWith('-')) {
|
|
27
|
+
workspace = path.resolve(next);
|
|
28
|
+
i += 1;
|
|
29
|
+
} else {
|
|
30
|
+
workspace = process.cwd();
|
|
31
|
+
}
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (arg === '--global') {
|
|
35
|
+
workspace = null;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
throw new Error(`unknown argument: ${arg}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return { workspace };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function runNodeScript(scriptPath, args) {
|
|
45
|
+
const result = spawnSync(process.execPath, [scriptPath, ...args], {
|
|
46
|
+
cwd: process.cwd(),
|
|
47
|
+
stdio: 'inherit',
|
|
48
|
+
env: process.env,
|
|
49
|
+
});
|
|
50
|
+
process.exitCode = result.status ?? 1;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function main() {
|
|
54
|
+
const [command, ...rest] = process.argv.slice(2);
|
|
55
|
+
if (!command || command === '--help' || command === '-h' || command === 'help') {
|
|
56
|
+
printUsage();
|
|
57
|
+
process.exitCode = command ? 0 : 1;
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (command !== 'install' && command !== 'uninstall') {
|
|
62
|
+
printUsage();
|
|
63
|
+
process.exitCode = 1;
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const parsed = parseArgs(rest);
|
|
68
|
+
const args = [];
|
|
69
|
+
if (parsed.workspace) {
|
|
70
|
+
args.push('--workspace', parsed.workspace);
|
|
71
|
+
} else {
|
|
72
|
+
args.push('--global');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
runNodeScript(path.join(PACKAGE_ROOT, 'bin', `${command}.cjs`), args);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
main();
|
package/bin/install.cjs
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const { spawnSync } = require('child_process');
|
|
8
|
+
|
|
9
|
+
const PACKAGE_ROOT = path.resolve(__dirname, '..');
|
|
10
|
+
const INSTALL_ENTRIES = [
|
|
11
|
+
{ source: 'package.json', required: true },
|
|
12
|
+
{ source: 'extensions', required: true },
|
|
13
|
+
{ source: 'skills', required: true },
|
|
14
|
+
{ source: 'commands', required: true },
|
|
15
|
+
{ source: 'scripts', required: true },
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
function parseArgs(argv) {
|
|
19
|
+
const args = {
|
|
20
|
+
workspace: null,
|
|
21
|
+
};
|
|
22
|
+
for (let i = 2; i < argv.length; i += 1) {
|
|
23
|
+
if (argv[i] === '--workspace' && argv[i + 1]) {
|
|
24
|
+
args.workspace = path.resolve(argv[++i]);
|
|
25
|
+
} else if (argv[i] === '--global') {
|
|
26
|
+
args.workspace = null;
|
|
27
|
+
} else {
|
|
28
|
+
throw new Error(`unknown argument: ${argv[i]}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return args;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function getGlobalStateDir() {
|
|
35
|
+
if (process.env.BABYSITTER_GLOBAL_STATE_DIR) {
|
|
36
|
+
return path.resolve(process.env.BABYSITTER_GLOBAL_STATE_DIR);
|
|
37
|
+
}
|
|
38
|
+
return path.join(os.homedir(), '.a5c');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function getPluginRoot(args) {
|
|
42
|
+
const base = args.workspace ? path.resolve(args.workspace) : os.homedir();
|
|
43
|
+
return path.join(base, '.omp', 'plugins', 'babysitter');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function copyRecursive(src, dest) {
|
|
47
|
+
const stat = fs.statSync(src);
|
|
48
|
+
if (stat.isDirectory()) {
|
|
49
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
50
|
+
for (const entry of fs.readdirSync(src)) {
|
|
51
|
+
if (['node_modules', '.git', 'test', '.gitignore', 'state'].includes(entry)) continue;
|
|
52
|
+
copyRecursive(path.join(src, entry), path.join(dest, entry));
|
|
53
|
+
}
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
57
|
+
fs.copyFileSync(src, dest);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function resolveBabysitterCommand(packageRoot) {
|
|
61
|
+
if (process.env.BABYSITTER_SDK_CLI) {
|
|
62
|
+
return {
|
|
63
|
+
command: process.execPath,
|
|
64
|
+
argsPrefix: [path.resolve(process.env.BABYSITTER_SDK_CLI)],
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
return {
|
|
69
|
+
command: process.execPath,
|
|
70
|
+
argsPrefix: [
|
|
71
|
+
require.resolve('@a5c-ai/babysitter-sdk/dist/cli/main.js', {
|
|
72
|
+
paths: [packageRoot],
|
|
73
|
+
}),
|
|
74
|
+
],
|
|
75
|
+
};
|
|
76
|
+
} catch {
|
|
77
|
+
return {
|
|
78
|
+
command: 'babysitter',
|
|
79
|
+
argsPrefix: [],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function runBabysitterCli(packageRoot, cliArgs) {
|
|
85
|
+
const resolved = resolveBabysitterCommand(packageRoot);
|
|
86
|
+
const result = spawnSync(resolved.command, [...resolved.argsPrefix, ...cliArgs], {
|
|
87
|
+
cwd: packageRoot,
|
|
88
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
89
|
+
encoding: 'utf8',
|
|
90
|
+
env: process.env,
|
|
91
|
+
});
|
|
92
|
+
if (result.status !== 0) {
|
|
93
|
+
const stderr = (result.stderr || '').trim();
|
|
94
|
+
const stdout = (result.stdout || '').trim();
|
|
95
|
+
throw new Error(
|
|
96
|
+
`babysitter ${cliArgs.join(' ')} failed` +
|
|
97
|
+
(stderr ? `: ${stderr}` : stdout ? `: ${stdout}` : ''),
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
return result.stdout;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function ensureGlobalProcessLibrary() {
|
|
104
|
+
const active = JSON.parse(
|
|
105
|
+
runBabysitterCli(
|
|
106
|
+
PACKAGE_ROOT,
|
|
107
|
+
['process-library:active', '--state-dir', getGlobalStateDir(), '--json'],
|
|
108
|
+
),
|
|
109
|
+
);
|
|
110
|
+
console.log(`[babysitter] process library: ${active.binding?.dir}`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function installEntry(pluginRoot, entry) {
|
|
114
|
+
const src = path.join(PACKAGE_ROOT, entry.source);
|
|
115
|
+
const dest = path.join(pluginRoot, entry.source);
|
|
116
|
+
if (!fs.existsSync(src)) {
|
|
117
|
+
if (entry.required) throw new Error(`required install payload is missing: ${src}`);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
copyRecursive(src, dest);
|
|
121
|
+
console.log(`[babysitter] ${entry.source}${fs.statSync(src).isDirectory() ? '/' : ''}`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function main() {
|
|
125
|
+
const args = parseArgs(process.argv);
|
|
126
|
+
const pluginRoot = getPluginRoot(args);
|
|
127
|
+
console.log(`[babysitter] Installing oh-my-pi plugin to ${pluginRoot}`);
|
|
128
|
+
|
|
129
|
+
try {
|
|
130
|
+
fs.rmSync(pluginRoot, { recursive: true, force: true });
|
|
131
|
+
fs.mkdirSync(pluginRoot, { recursive: true });
|
|
132
|
+
for (const entry of INSTALL_ENTRIES) {
|
|
133
|
+
installEntry(pluginRoot, entry);
|
|
134
|
+
}
|
|
135
|
+
fs.mkdirSync(path.join(pluginRoot, 'state'), { recursive: true });
|
|
136
|
+
ensureGlobalProcessLibrary();
|
|
137
|
+
console.log('[babysitter] Installation complete!');
|
|
138
|
+
} catch (err) {
|
|
139
|
+
console.error(`[babysitter] Failed to install plugin files: ${err.message}`);
|
|
140
|
+
process.exitCode = 1;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
main();
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
|
|
8
|
+
function parseArgs(argv) {
|
|
9
|
+
const args = {
|
|
10
|
+
workspace: null,
|
|
11
|
+
};
|
|
12
|
+
for (let i = 2; i < argv.length; i += 1) {
|
|
13
|
+
if (argv[i] === '--workspace' && argv[i + 1]) {
|
|
14
|
+
args.workspace = path.resolve(argv[++i]);
|
|
15
|
+
} else if (argv[i] === '--global') {
|
|
16
|
+
args.workspace = null;
|
|
17
|
+
} else {
|
|
18
|
+
throw new Error(`unknown argument: ${argv[i]}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return args;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function getPluginRoot(args) {
|
|
25
|
+
const base = args.workspace ? path.resolve(args.workspace) : os.homedir();
|
|
26
|
+
return path.join(base, '.omp', 'plugins', 'babysitter');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function main() {
|
|
30
|
+
const args = parseArgs(process.argv);
|
|
31
|
+
const pluginRoot = getPluginRoot(args);
|
|
32
|
+
if (!fs.existsSync(pluginRoot)) {
|
|
33
|
+
console.log('[babysitter] Nothing to uninstall.');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
fs.rmSync(pluginRoot, { recursive: true, force: true });
|
|
37
|
+
console.log(`[babysitter] Removed ${pluginRoot}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
main();
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: babysitter:call
|
|
3
|
+
description: Start a babysitter orchestration run
|
|
4
|
+
arguments:
|
|
5
|
+
- name: prompt
|
|
6
|
+
description: The task to orchestrate
|
|
7
|
+
required: true
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Start a babysitter orchestration run. Creates a new run using the SDK, binds it to the current session, and begins iteration.
|
|
11
|
+
|
|
12
|
+
This command initialises a fresh babysitter run with the given prompt, associates it with the active oh-my-pi session, and kicks off the first orchestration iteration. The loop driver will continue iterating automatically on subsequent `agent_end` events until the run completes, fails, or a guard trips.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: babysitter:doctor
|
|
3
|
+
description: Diagnose the health of a babysitter run
|
|
4
|
+
arguments:
|
|
5
|
+
- name: runId
|
|
6
|
+
description: Optional run ID to diagnose (defaults to the active run)
|
|
7
|
+
required: false
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Run diagnostic checks against a babysitter run to identify potential issues. Inspects run metadata, journal integrity, state cache, lock files, and effect health.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: babysitter:resume
|
|
3
|
+
description: Resume a previously stopped or interrupted babysitter run
|
|
4
|
+
arguments:
|
|
5
|
+
- name: runId
|
|
6
|
+
description: The run ID to resume
|
|
7
|
+
required: true
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Resume an existing babysitter orchestration run that was previously stopped, interrupted, or is in a waiting state. Re-binds the run to the current session and continues iteration from where it left off.
|
|
11
|
+
|
|
12
|
+
## Behaviour
|
|
13
|
+
|
|
14
|
+
1. Locates the run directory for the given run ID.
|
|
15
|
+
2. Reads run metadata and journal to determine current state.
|
|
16
|
+
3. Re-binds the run to the active oh-my-pi session.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: babysitter:status
|
|
3
|
+
description: Check the status of the active babysitter run
|
|
4
|
+
arguments:
|
|
5
|
+
- name: runId
|
|
6
|
+
description: Optional run ID to check (defaults to the active run)
|
|
7
|
+
required: false
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Check the current status of a babysitter orchestration run.
|
|
11
|
+
|
|
12
|
+
## Notes
|
|
13
|
+
|
|
14
|
+
- When called without arguments, reports on the run bound to the current session.
|
|
15
|
+
- If discovery reports `oh-my-pi` as installed but direct invocation fails, validate `where omp`.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Babysitter CLI invocation helper.
|
|
3
|
+
*
|
|
4
|
+
* Spawns the `babysitter` CLI as a child process, captures stdout/stderr,
|
|
5
|
+
* parses JSON output, and surfaces structured errors. Every other module
|
|
6
|
+
* that needs to talk to babysitter goes through here so there is exactly
|
|
7
|
+
* one place to handle timeouts, env vars, and error mapping.
|
|
8
|
+
*
|
|
9
|
+
* @deprecated Use `sdk-bridge.ts` instead. This module spawns a child
|
|
10
|
+
* process to communicate with babysitter. The SDK bridge imports the
|
|
11
|
+
* runtime directly, avoiding subprocess overhead and JSON parsing.
|
|
12
|
+
* This file is retained only for backward compatibility and will be
|
|
13
|
+
* removed in a future release.
|
|
14
|
+
*
|
|
15
|
+
* @module cli-wrapper
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { execFile } from 'node:child_process';
|
|
19
|
+
import { CLI_COMMAND, CLI_TIMEOUT_MS } from './constants';
|
|
20
|
+
|
|
21
|
+
/** Structured result from a CLI invocation. */
|
|
22
|
+
export interface CliResult<T = unknown> {
|
|
23
|
+
/** Whether the process exited with code 0. */
|
|
24
|
+
success: boolean;
|
|
25
|
+
/** Parsed JSON from stdout (when `--json` flag is used). */
|
|
26
|
+
data?: T;
|
|
27
|
+
/** Raw stdout string. */
|
|
28
|
+
stdout: string;
|
|
29
|
+
/** Raw stderr string. */
|
|
30
|
+
stderr: string;
|
|
31
|
+
/** Process exit code (null when killed by signal). */
|
|
32
|
+
exitCode: number | null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Invoke the babysitter CLI with the given command and arguments.
|
|
37
|
+
*
|
|
38
|
+
* The `--json` flag is appended automatically so callers always get
|
|
39
|
+
* machine-readable output. Errors are captured rather than thrown --
|
|
40
|
+
* inspect `CliResult.success` to decide how to proceed.
|
|
41
|
+
*
|
|
42
|
+
* @param command - The babysitter sub-command (e.g. `"run:iterate"`).
|
|
43
|
+
* @param args - Additional positional / flag arguments.
|
|
44
|
+
* @param options - Optional overrides for timeout and env.
|
|
45
|
+
* @returns A promise that resolves to the structured CLI result.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* const res = await runCli('run:iterate', ['--run-id', runId]);
|
|
50
|
+
* if (res.success && res.data) {
|
|
51
|
+
* console.log(res.data);
|
|
52
|
+
* }
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export async function runCli<T = unknown>(
|
|
56
|
+
command: string,
|
|
57
|
+
args: string[] = [],
|
|
58
|
+
options: { timeoutMs?: number; env?: Record<string, string> } = {},
|
|
59
|
+
): Promise<CliResult<T>> {
|
|
60
|
+
const timeout = options.timeoutMs ?? CLI_TIMEOUT_MS;
|
|
61
|
+
const fullArgs = [command, '--json', ...args];
|
|
62
|
+
|
|
63
|
+
return new Promise<CliResult<T>>((resolve) => {
|
|
64
|
+
const child = execFile(
|
|
65
|
+
CLI_COMMAND,
|
|
66
|
+
fullArgs,
|
|
67
|
+
{
|
|
68
|
+
timeout,
|
|
69
|
+
maxBuffer: 10 * 1024 * 1024, // 10 MiB
|
|
70
|
+
env: { ...process.env, ...options.env },
|
|
71
|
+
},
|
|
72
|
+
(error, stdout, stderr) => {
|
|
73
|
+
const exitCode =
|
|
74
|
+
error && 'code' in error ? (error.code as number | null) : child.exitCode;
|
|
75
|
+
|
|
76
|
+
let data: T | undefined;
|
|
77
|
+
try {
|
|
78
|
+
if (stdout.trim()) {
|
|
79
|
+
data = JSON.parse(stdout) as T;
|
|
80
|
+
}
|
|
81
|
+
} catch {
|
|
82
|
+
// stdout was not valid JSON -- leave data undefined
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
resolve({
|
|
86
|
+
success: exitCode === 0,
|
|
87
|
+
data,
|
|
88
|
+
stdout: String(stdout),
|
|
89
|
+
stderr: String(stderr),
|
|
90
|
+
exitCode: typeof exitCode === 'number' ? exitCode : null,
|
|
91
|
+
});
|
|
92
|
+
},
|
|
93
|
+
);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration constants for the babysitter oh-my-pi extension.
|
|
3
|
+
*
|
|
4
|
+
* Centralises magic strings, default timeouts, environment variable names,
|
|
5
|
+
* and widget keys so the rest of the extension can remain blissfully ignorant
|
|
6
|
+
* of where these values come from.
|
|
7
|
+
*
|
|
8
|
+
* @module constants
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// CLI
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
/** Path (or bare command name) used to invoke the babysitter CLI. */
|
|
16
|
+
export const CLI_COMMAND = process.env['BABYSITTER_CLI_PATH'] ?? 'babysitter';
|
|
17
|
+
|
|
18
|
+
/** Default timeout (ms) applied to every CLI invocation. */
|
|
19
|
+
export const CLI_TIMEOUT_MS = 120_000;
|
|
20
|
+
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Orchestration limits (mirrors BABYSITTER_MAX_ITERATIONS etc.)
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
/** Default maximum orchestration iterations per run. */
|
|
26
|
+
export const DEFAULT_MAX_ITERATIONS = 256;
|
|
27
|
+
|
|
28
|
+
/** Default maximum wall-clock time (ms) for a single run. */
|
|
29
|
+
export const DEFAULT_MAX_DURATION_MS = 30 * 60 * 1_000; // 30 minutes
|
|
30
|
+
|
|
31
|
+
/** Consecutive errors before the guard trips. */
|
|
32
|
+
export const DEFAULT_ERROR_THRESHOLD = 5;
|
|
33
|
+
|
|
34
|
+
/** Number of identical iteration digests that signal a doom loop. */
|
|
35
|
+
export const DEFAULT_DOOM_LOOP_WINDOW = 4;
|
|
36
|
+
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// Timeouts
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
|
|
41
|
+
/** Timeout (ms) for a single effect execution. */
|
|
42
|
+
export const EFFECT_TIMEOUT_MS = 900_000; // 15 minutes, matches NODE_TASK_TIMEOUT
|
|
43
|
+
|
|
44
|
+
/** Timeout (ms) for posting a task result back. */
|
|
45
|
+
export const POST_RESULT_TIMEOUT_MS = 30_000;
|
|
46
|
+
|
|
47
|
+
/** Delay (ms) for a sleep effect (placeholder; real value comes from the effect). */
|
|
48
|
+
export const DEFAULT_SLEEP_MS = 5_000;
|
|
49
|
+
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
// Environment variable names
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
|
|
54
|
+
export const ENV_RUNS_DIR = 'BABYSITTER_RUNS_DIR';
|
|
55
|
+
export const ENV_MAX_ITERATIONS = 'BABYSITTER_MAX_ITERATIONS';
|
|
56
|
+
export const ENV_QUALITY_THRESHOLD = 'BABYSITTER_QUALITY_THRESHOLD';
|
|
57
|
+
export const ENV_TIMEOUT = 'BABYSITTER_TIMEOUT';
|
|
58
|
+
export const ENV_LOG_LEVEL = 'BABYSITTER_LOG_LEVEL';
|
|
59
|
+
export const ENV_HOOK_TIMEOUT = 'BABYSITTER_HOOK_TIMEOUT';
|
|
60
|
+
export const ENV_NODE_TASK_TIMEOUT = 'BABYSITTER_NODE_TASK_TIMEOUT';
|
|
61
|
+
export const ENV_CLI_PATH = 'BABYSITTER_CLI_PATH';
|
|
62
|
+
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
// Widget keys (for registerMessageRenderer / TUI identification)
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
|
|
67
|
+
export const WIDGET_RUN_PROGRESS = 'babysitter:run-progress';
|
|
68
|
+
export const WIDGET_TASK_STATUS = 'babysitter:task-status';
|
|
69
|
+
export const WIDGET_QUALITY_SCORE = 'babysitter:quality-score';
|
|
70
|
+
export const WIDGET_PHASE_INDICATOR = 'babysitter:phase-indicator';
|
|
71
|
+
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
// Extension metadata
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
|
|
76
|
+
export const EXTENSION_NAME = 'babysitter';
|
|
77
|
+
export const EXTENSION_VERSION = '0.1.0';
|