@ouro.bot/cli 0.1.0-alpha.362 → 0.1.0-alpha.364
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 +5 -0
- package/changelog.json +14 -0
- package/dist/heart/daemon/cli-exec.js +88 -13
- package/dist/heart/versioning/ouro-path-installer.js +10 -5
- package/dist/mind/prompt.js +1 -0
- package/package.json +1 -1
- package/skills/configure-dev-tools.md +21 -1
package/README.md
CHANGED
|
@@ -169,6 +169,7 @@ ouro auth --agent <name>
|
|
|
169
169
|
ouro auth --agent <name> --provider <provider>
|
|
170
170
|
ouro use --agent <name> --lane <outward|inner> --provider <provider> --model <model>
|
|
171
171
|
ouro hatch
|
|
172
|
+
ouro clone <remote> [--agent <name>] # clone an existing agent from a git remote (see docs/cross-machine-setup.md)
|
|
172
173
|
ouro chat <agent>
|
|
173
174
|
ouro msg --to <agent> [--session <id>] [--task <ref>] <message>
|
|
174
175
|
ouro poke <agent> --task <task-id>
|
|
@@ -183,6 +184,10 @@ ouro mcp-serve --agent <name> # start MCP server on stdin/stdout (us
|
|
|
183
184
|
ouro hook <event> --agent <name> # fire a lifecycle hook (SessionStart, Stop, PostToolUse)
|
|
184
185
|
```
|
|
185
186
|
|
|
187
|
+
## Setting Up On Another Machine
|
|
188
|
+
|
|
189
|
+
To clone an existing agent onto a new machine (macOS, Linux, or Windows via WSL2), see **[docs/cross-machine-setup.md](docs/cross-machine-setup.md)**. The short version: `npx ouro.bot`, pick "clone", enter the bundle's git remote URL, and follow the guided prompts (auth, daemon start, dev tool setup are all offered inline).
|
|
190
|
+
|
|
186
191
|
## The Agent's Inner Life
|
|
187
192
|
|
|
188
193
|
Agents in Ouroboros aren't just responders — they have an autonomous inner life.
|
package/changelog.json
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
|
|
3
3
|
"versions": [
|
|
4
|
+
{
|
|
5
|
+
"version": "0.1.0-alpha.364",
|
|
6
|
+
"changes": [
|
|
7
|
+
"Cross-machine polish: bash PATH writes to .bashrc on Linux/WSL instead of .bash_profile (which non-login shells skip on Debian/Ubuntu). Shell hint message matches.",
|
|
8
|
+
"Agent prompt: never guess about harness behavior — consult docs first, investigate in code, fix stale docs via PR.",
|
|
9
|
+
"Agent prompt: harness docs pointer distinguishes dev mode (local read) vs production (fetch from GitHub)."
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"version": "0.1.0-alpha.363",
|
|
14
|
+
"changes": [
|
|
15
|
+
"Bootstrap first-install PATH hint is now shell-aware: shows correct source command for zsh, bash, fish, or generic fallback for unknown shells."
|
|
16
|
+
]
|
|
17
|
+
},
|
|
4
18
|
{
|
|
5
19
|
"version": "0.1.0-alpha.362",
|
|
6
20
|
"changes": [
|
|
@@ -492,8 +492,9 @@ async function checkManualCloneBundles(deps) {
|
|
|
492
492
|
message: "bundle appears to be a manually cloned git repo",
|
|
493
493
|
meta: { agent: agentDir, remote: remoteName },
|
|
494
494
|
});
|
|
495
|
-
|
|
496
|
-
|
|
495
|
+
/* v8 ignore next -- ?? fallback: promptInput always returns string in practice @preserve */
|
|
496
|
+
const answer = (await deps.promptInput(`Bundle ${agentDir} appears to be a git clone with a remote. Enable sync? (y/n): `)) ?? "";
|
|
497
|
+
if (answer.trim().toLowerCase() === "y" && fs.existsSync(agentJsonPath)) {
|
|
497
498
|
const raw = fs.readFileSync(agentJsonPath, "utf-8");
|
|
498
499
|
const config = JSON.parse(raw);
|
|
499
500
|
config.sync = { enabled: true, remote: remoteName };
|
|
@@ -1353,10 +1354,15 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
1353
1354
|
message: "user chose clone in first-run flow",
|
|
1354
1355
|
meta: {},
|
|
1355
1356
|
});
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1357
|
+
/* v8 ignore next -- ?? fallback: promptInput always returns string in practice @preserve */
|
|
1358
|
+
const remote = (await deps.promptInput("Enter the git remote URL for the agent bundle: "))?.trim() ?? "";
|
|
1359
|
+
if (!remote) {
|
|
1360
|
+
deps.writeStdout("no remote URL provided — skipping clone");
|
|
1361
|
+
// Fall through to hatch flow
|
|
1362
|
+
}
|
|
1363
|
+
else {
|
|
1364
|
+
return await runOuroCli(["clone", remote], deps);
|
|
1365
|
+
}
|
|
1360
1366
|
}
|
|
1361
1367
|
(0, runtime_1.emitNervesEvent)({
|
|
1362
1368
|
component: "daemon",
|
|
@@ -2787,10 +2793,18 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
2787
2793
|
try {
|
|
2788
2794
|
(0, child_process_1.execFileSync)("git", ["ls-remote", "--exit-code", command.remote], { stdio: "pipe", timeout: 15000 });
|
|
2789
2795
|
}
|
|
2790
|
-
catch {
|
|
2791
|
-
const
|
|
2792
|
-
|
|
2793
|
-
|
|
2796
|
+
catch (lsErr) {
|
|
2797
|
+
const stderr = lsErr?.stderr?.toString() ?? "";
|
|
2798
|
+
const isAuth = stderr.includes("Authentication failed")
|
|
2799
|
+
|| stderr.includes("could not read Username")
|
|
2800
|
+
|| stderr.includes("terminal prompts disabled")
|
|
2801
|
+
|| stderr.includes("403")
|
|
2802
|
+
|| stderr.includes("401");
|
|
2803
|
+
const hint = isAuth
|
|
2804
|
+
? `authentication failed for: ${command.remote}\nSet up credentials first:\n gh auth login (GitHub repos)\n git config credential.helper store (other hosts)`
|
|
2805
|
+
: `could not reach remote: ${command.remote}\nCheck the URL and your network connection.`;
|
|
2806
|
+
deps.writeStdout(hint);
|
|
2807
|
+
return hint;
|
|
2794
2808
|
}
|
|
2795
2809
|
// 5. Clone
|
|
2796
2810
|
(0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.clone_git_clone", message: "cloning agent bundle", meta: { remote: command.remote, targetPath } });
|
|
@@ -2800,18 +2814,79 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
2800
2814
|
(0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.clone_identity_created", message: "machine identity created", meta: {} });
|
|
2801
2815
|
// 7. Enable sync in agent.json
|
|
2802
2816
|
const agentJsonPath = path.join(targetPath, "agent.json");
|
|
2817
|
+
let syncEnabled = false;
|
|
2803
2818
|
if (fs.existsSync(agentJsonPath)) {
|
|
2804
2819
|
const raw = fs.readFileSync(agentJsonPath, "utf-8");
|
|
2805
2820
|
const config = JSON.parse(raw);
|
|
2806
2821
|
config.sync = { enabled: true, remote: "origin" };
|
|
2807
2822
|
fs.writeFileSync(agentJsonPath, JSON.stringify(config, null, 2) + "\n");
|
|
2823
|
+
syncEnabled = true;
|
|
2808
2824
|
(0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.clone_sync_enabled", message: "sync enabled in agent.json", meta: { agentName } });
|
|
2809
2825
|
}
|
|
2826
|
+
else {
|
|
2827
|
+
(0, runtime_1.emitNervesEvent)({ level: "warn", component: "daemon", event: "daemon.clone_no_agent_json", message: "cloned repo has no agent.json — may not be a valid bundle", meta: { agentName, targetPath } });
|
|
2828
|
+
}
|
|
2810
2829
|
// 8. Output success message
|
|
2811
2830
|
(0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.clone_complete", message: "clone complete", meta: { agentName, targetPath } });
|
|
2812
|
-
const
|
|
2813
|
-
deps.writeStdout(
|
|
2814
|
-
|
|
2831
|
+
const syncMsg = syncEnabled ? "\nsync enabled (remote: origin)" : "\nwarning: no agent.json found — this may not be a valid agent bundle";
|
|
2832
|
+
deps.writeStdout(`cloned ${agentName} to ${targetPath}${syncMsg}`);
|
|
2833
|
+
// 9. Guided post-clone flow (when interactive)
|
|
2834
|
+
if (deps.promptInput) {
|
|
2835
|
+
// Auth
|
|
2836
|
+
const authAnswer = await deps.promptInput(`\nSet up provider auth now? (y/n): `) ?? "";
|
|
2837
|
+
if (authAnswer.trim().toLowerCase() === "y") {
|
|
2838
|
+
(0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.clone_chain_auth", message: "chaining auth from clone flow", meta: { agentName } });
|
|
2839
|
+
try {
|
|
2840
|
+
await runOuroCli(["auth", "--agent", agentName], deps);
|
|
2841
|
+
/* v8 ignore start -- chained command failures: tested via interactive clone test, catch branches are defensive @preserve */
|
|
2842
|
+
}
|
|
2843
|
+
catch (e) {
|
|
2844
|
+
deps.writeStdout(`auth setup failed: ${e instanceof Error ? e.message : String(e)}\nYou can retry later with: ouro auth run --agent ${agentName}`);
|
|
2845
|
+
}
|
|
2846
|
+
/* v8 ignore stop */
|
|
2847
|
+
}
|
|
2848
|
+
// Daemon
|
|
2849
|
+
const upAnswer = await deps.promptInput(`\nStart the daemon now? (y/n): `) ?? "";
|
|
2850
|
+
if (upAnswer.trim().toLowerCase() === "y") {
|
|
2851
|
+
(0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.clone_chain_up", message: "chaining daemon start from clone flow", meta: { agentName } });
|
|
2852
|
+
try {
|
|
2853
|
+
await runOuroCli(["up"], deps);
|
|
2854
|
+
/* v8 ignore start -- chained command failures: defensive catch @preserve */
|
|
2855
|
+
}
|
|
2856
|
+
catch (e) {
|
|
2857
|
+
deps.writeStdout(`daemon start failed: ${e instanceof Error ? e.message : String(e)}\nYou can retry later with: ouro up`);
|
|
2858
|
+
}
|
|
2859
|
+
/* v8 ignore stop */
|
|
2860
|
+
}
|
|
2861
|
+
// Dev tool setup
|
|
2862
|
+
const setupAnswer = await deps.promptInput(`\nSet up Claude Code integration? (y/n): `) ?? "";
|
|
2863
|
+
if (setupAnswer.trim().toLowerCase() === "y") {
|
|
2864
|
+
(0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.clone_chain_setup", message: "chaining dev tool setup from clone flow", meta: { agentName } });
|
|
2865
|
+
try {
|
|
2866
|
+
await runOuroCli(["setup", "--tool", "claude-code", "--agent", agentName], deps);
|
|
2867
|
+
/* v8 ignore start -- chained command failures: defensive catch @preserve */
|
|
2868
|
+
}
|
|
2869
|
+
catch (e) {
|
|
2870
|
+
deps.writeStdout(`dev tool setup failed: ${e instanceof Error ? e.message : String(e)}\nYou can retry later with: ouro setup --tool claude-code --agent ${agentName}`);
|
|
2871
|
+
}
|
|
2872
|
+
/* v8 ignore stop */
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2875
|
+
else {
|
|
2876
|
+
deps.writeStdout(`\nnext steps:\n ouro auth run --agent ${agentName}\n ouro up\n ouro setup --tool claude-code --agent ${agentName}`);
|
|
2877
|
+
}
|
|
2878
|
+
/* v8 ignore start -- PATH hint: only fires inside npx, not testable in vitest @preserve */
|
|
2879
|
+
if (process.env.npm_execpath) {
|
|
2880
|
+
const shell = process.env.SHELL ? path.basename(process.env.SHELL) : "";
|
|
2881
|
+
const bashProfile = process.platform === "darwin" ? "~/.bash_profile" : "~/.bashrc";
|
|
2882
|
+
const sourceCmd = shell === "zsh" ? "source ~/.zshrc"
|
|
2883
|
+
: shell === "bash" ? `source ${bashProfile}`
|
|
2884
|
+
: shell === "fish" ? "source ~/.config/fish/config.fish"
|
|
2885
|
+
: "restart your shell";
|
|
2886
|
+
deps.writeStdout(`\ntip: if 'ouro' is not found, run: ${sourceCmd}`);
|
|
2887
|
+
}
|
|
2888
|
+
/* v8 ignore stop */
|
|
2889
|
+
return `clone complete: ${agentName}`;
|
|
2815
2890
|
}
|
|
2816
2891
|
const daemonCommand = toDaemonCommand(command);
|
|
2817
2892
|
let response;
|
|
@@ -63,16 +63,21 @@ function writeWrapperScript(scriptPath, mkdirSync, writeFileSync, chmodSync) {
|
|
|
63
63
|
writeFileSync(scriptPath, WRAPPER_SCRIPT, { mode: 0o755 });
|
|
64
64
|
chmodSync(scriptPath, 0o755);
|
|
65
65
|
}
|
|
66
|
-
function detectShellProfile(homeDir, shell) {
|
|
66
|
+
function detectShellProfile(homeDir, shell, platform) {
|
|
67
67
|
if (!shell)
|
|
68
68
|
return null;
|
|
69
69
|
const base = path.basename(shell);
|
|
70
70
|
if (base === "zsh")
|
|
71
71
|
return path.join(homeDir, ".zshrc");
|
|
72
72
|
if (base === "bash") {
|
|
73
|
-
// macOS uses .bash_profile
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
// macOS uses .bash_profile; Linux/WSL uses .bashrc (the default
|
|
74
|
+
// interactive shell config on Debian/Ubuntu). Writing to .bash_profile
|
|
75
|
+
// on Linux often has no effect because non-login shells skip it.
|
|
76
|
+
/* v8 ignore next -- ?? fallback: callers always pass platform from deps @preserve */
|
|
77
|
+
const effectivePlatform = platform ?? process.platform;
|
|
78
|
+
return effectivePlatform === "darwin"
|
|
79
|
+
? path.join(homeDir, ".bash_profile")
|
|
80
|
+
: path.join(homeDir, ".bashrc");
|
|
76
81
|
}
|
|
77
82
|
if (base === "fish")
|
|
78
83
|
return path.join(homeDir, ".config", "fish", "config.fish");
|
|
@@ -250,7 +255,7 @@ function installOuroCommand(deps = {}) {
|
|
|
250
255
|
const pathReady = isBinDirInPath(binDir, envPath);
|
|
251
256
|
let shellProfileUpdated = null;
|
|
252
257
|
if (!pathReady) {
|
|
253
|
-
const profilePath = detectShellProfile(homeDir, shell);
|
|
258
|
+
const profilePath = detectShellProfile(homeDir, shell, platform);
|
|
254
259
|
if (profilePath) {
|
|
255
260
|
try {
|
|
256
261
|
let existing = "";
|
package/dist/mind/prompt.js
CHANGED
|
@@ -382,6 +382,7 @@ function runtimeInfoSection(channel, options) {
|
|
|
382
382
|
lines.push(`process type: ${processTypeLabel(channel)}`);
|
|
383
383
|
lines.push(`daemon: ${daemonStatus(options?.daemonRunning)}`);
|
|
384
384
|
lines.push(`mcp serve: i can expose my tools to dev tools via \`ouro mcp-serve\`. see the configure-dev-tools skill for setup.`);
|
|
385
|
+
lines.push(`harness docs: the harness repo has docs/ and skills/ with guides for setup, operations, and capabilities. docs/ does NOT ship in the npm package — in production, fetch from https://github.com/ouroborosbot/ouroboros/tree/main/docs instead. in dev mode, read from ${sourceRoot}/docs/. when someone asks about setup, installation, cross-machine cloning, deployment, testing, auth, or how i work — consult the docs first. NEVER guess about how the harness works. if the docs don't answer the question, investigate in code. if i discover the docs are stale or missing coverage, open a PR to fix them — stale docs cause the same damage as wrong answers.`);
|
|
385
386
|
if (channel === "cli") {
|
|
386
387
|
lines.push("i introduce myself on boot with a fun random greeting.");
|
|
387
388
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Configure Dev Tools for MCP Agent Bridge
|
|
2
2
|
|
|
3
|
-
Set up your development tools (Claude Code, Codex) to communicate with Ouroboros agents via MCP. One command does everything.
|
|
3
|
+
Set up your development tools (Claude Code, Codex) to communicate with Ouroboros agents via MCP. One command does everything — including cross-platform WSL2 bridging on Windows.
|
|
4
4
|
|
|
5
5
|
## Setup
|
|
6
6
|
|
|
@@ -15,6 +15,16 @@ This command:
|
|
|
15
15
|
2. Configures lifecycle hooks (SessionStart, Stop, PostToolUse) for passive awareness
|
|
16
16
|
3. Detects dev vs installed mode automatically and uses the correct command path
|
|
17
17
|
|
|
18
|
+
**On WSL2 (Windows):** The command automatically detects the WSL environment and:
|
|
19
|
+
- Calls `claude.exe` (the Windows binary) instead of `claude`
|
|
20
|
+
- Prefixes MCP serve and hook commands with `wsl` so Windows-side Claude Code spawns them through WSL
|
|
21
|
+
- Resolves the Windows-side home directory and writes config to the Windows-side `~/.claude/`
|
|
22
|
+
- After setup, open Claude Code in PowerShell — the agent is there
|
|
23
|
+
|
|
24
|
+
**On native Windows (no WSL):** Not yet supported. The command prints a message directing you to install WSL2.
|
|
25
|
+
|
|
26
|
+
For the full cross-machine setup flow (including cloning an agent to a new machine), see `docs/cross-machine-setup.md` in the harness repo.
|
|
27
|
+
|
|
18
28
|
### Codex
|
|
19
29
|
|
|
20
30
|
```bash
|
|
@@ -73,6 +83,16 @@ Most read-only tools work without the daemon (reads filesystem directly). For wr
|
|
|
73
83
|
- Ensure `dist/` is built: `npm run build`
|
|
74
84
|
- Check that the entry point path is correct (setup auto-detects this)
|
|
75
85
|
|
|
86
|
+
### WSL2-specific issues
|
|
87
|
+
|
|
88
|
+
**`claude.exe` not found** — Windows executables must be accessible from WSL. This is the default, but enterprise environments may disable it via `/etc/wsl.conf` setting `appendWindowsPath = false`. Check with `which claude.exe`. If missing, add Claude Code's install directory to WSL's PATH manually or update `wsl.conf`.
|
|
89
|
+
|
|
90
|
+
**`cmd.exe` or `wslpath` fails** — The setup command resolves the Windows home directory using `cmd.exe /C echo %USERPROFILE%` piped through `wslpath`. If either is unavailable, the setup will fail. `wslpath` ships with all standard WSL distributions. `cmd.exe` requires Windows executables to be on PATH (see above).
|
|
91
|
+
|
|
92
|
+
**MCP server hangs or returns empty** — The MCP server runs inside WSL via `wsl ouro mcp-serve --agent <name>`. If stdio piping between Windows and WSL is broken, check that the WSL distribution is running (`wsl --status`) and that no other process has claimed stdin.
|
|
93
|
+
|
|
94
|
+
**Hooks not firing** — Claude Code hooks use `wsl ouro hook <event> --agent <name>`. If hooks fail silently, check that `ouro` is on PATH inside WSL (run `wsl ouro --version` from PowerShell to verify).
|
|
95
|
+
|
|
76
96
|
### Removing
|
|
77
97
|
```bash
|
|
78
98
|
claude mcp remove ouro-<agent-name>
|