@ouro.bot/cli 0.1.0-alpha.363 → 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
CHANGED
|
@@ -186,7 +186,7 @@ ouro hook <event> --agent <name> # fire a lifecycle hook (SessionStart,
|
|
|
186
186
|
|
|
187
187
|
## Setting Up On Another Machine
|
|
188
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,
|
|
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
190
|
|
|
191
191
|
## The Agent's Inner Life
|
|
192
192
|
|
package/changelog.json
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
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
|
+
},
|
|
4
12
|
{
|
|
5
13
|
"version": "0.1.0-alpha.363",
|
|
6
14
|
"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,7 +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
|
|
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.`);
|
|
386
386
|
if (channel === "cli") {
|
|
387
387
|
lines.push("i introduce myself on boot with a fun random greeting.");
|
|
388
388
|
}
|
package/package.json
CHANGED
|
@@ -83,6 +83,16 @@ Most read-only tools work without the daemon (reads filesystem directly). For wr
|
|
|
83
83
|
- Ensure `dist/` is built: `npm run build`
|
|
84
84
|
- Check that the entry point path is correct (setup auto-detects this)
|
|
85
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
|
+
|
|
86
96
|
### Removing
|
|
87
97
|
```bash
|
|
88
98
|
claude mcp remove ouro-<agent-name>
|