@neriros/ralphy 2.9.1 → 2.9.2

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
@@ -1,5 +1,12 @@
1
1
  # Ralphy
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/@neriros/ralphy.svg)](https://www.npmjs.com/package/@neriros/ralphy)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@neriros/ralphy.svg)](https://www.npmjs.com/package/@neriros/ralphy)
5
+ [![license](https://img.shields.io/npm/l/@neriros/ralphy.svg)](https://github.com/NeriRos/ralphy/blob/main/LICENSE)
6
+ [![GitHub stars](https://img.shields.io/github/stars/NeriRos/ralphy.svg?style=social)](https://github.com/NeriRos/ralphy)
7
+ [![GitHub issues](https://img.shields.io/github/issues/NeriRos/ralphy.svg)](https://github.com/NeriRos/ralphy/issues)
8
+ [![Bun](https://img.shields.io/badge/runtime-Bun-fbf0df.svg)](https://bun.sh)
9
+
3
10
  An iterative AI task execution framework. Ralphy orchestrates multi-phase autonomous work using Claude or Codex engines, with built-in state management, progress tracking, and cost safeguards.
4
11
 
5
12
  ## How It Works
@@ -19,9 +26,9 @@ Each iteration reads the `## Steering` section of `proposal.md`, picks the first
19
26
  ### npm (global)
20
27
 
21
28
  ```bash
22
- npm install -g ralphy
29
+ npm install -g @neriros/ralphy
23
30
  # or
24
- bunx ralphy
31
+ bunx @neriros/ralphy
25
32
  ```
26
33
 
27
34
  Requires [Bun](https://bun.sh) as the runtime.
package/dist/cli/index.js CHANGED
@@ -56407,7 +56407,7 @@ function log(msg) {
56407
56407
  // package.json
56408
56408
  var package_default = {
56409
56409
  name: "@neriros/ralphy",
56410
- version: "2.9.1",
56410
+ version: "2.9.2",
56411
56411
  description: "An iterative AI task execution framework. Orchestrates multi-phase autonomous work using Claude or Codex engines.",
56412
56412
  keywords: [
56413
56413
  "agent",
@@ -70606,6 +70606,42 @@ async function createWorktree(projectRoot, changeName, runner) {
70606
70606
  async function removeWorktree(projectRoot, cwd2, runner) {
70607
70607
  await runner.run(["worktree", "remove", "--force", cwd2], projectRoot);
70608
70608
  }
70609
+ async function isWorktreeSafeToRemove(cwd2, base2, runner) {
70610
+ const status = await runner.run(["status", "--porcelain"], cwd2);
70611
+ const dirty = status.stdout.trim();
70612
+ let unpushedCommits = "";
70613
+ try {
70614
+ const log2 = await runner.run(["log", "--oneline", `${base2}..HEAD`, "--no-merges"], cwd2);
70615
+ unpushedCommits = log2.stdout.trim();
70616
+ } catch {
70617
+ unpushedCommits = "<unknown: failed to compare against base>";
70618
+ }
70619
+ if (dirty && unpushedCommits) {
70620
+ return {
70621
+ safe: false,
70622
+ reason: "uncommitted changes AND unpushed commits present",
70623
+ dirty,
70624
+ unpushedCommits
70625
+ };
70626
+ }
70627
+ if (dirty) {
70628
+ return {
70629
+ safe: false,
70630
+ reason: "uncommitted or untracked files present",
70631
+ dirty,
70632
+ unpushedCommits
70633
+ };
70634
+ }
70635
+ if (unpushedCommits) {
70636
+ return {
70637
+ safe: false,
70638
+ reason: `commits ahead of ${base2} were not pushed/PR'd`,
70639
+ dirty,
70640
+ unpushedCommits
70641
+ };
70642
+ }
70643
+ return { safe: true, dirty, unpushedCommits };
70644
+ }
70609
70645
 
70610
70646
  // apps/cli/src/agent/pr.ts
70611
70647
  function defaultTitle(issue) {
@@ -71012,18 +71048,45 @@ ${stamped}
71012
71048
  } catch (err) {
71013
71049
  const e = err;
71014
71050
  const detail = e.stderr?.trim() || e.message;
71015
- appendLog(`! PR create failed for ${changeName}: ${detail}`, "red");
71051
+ const combined = `${e.stdout ?? ""}
71052
+ ${e.stderr ?? ""}`;
71053
+ const pushRejected = /failed to push some refs|pre-push hook|hook declined/i.test(combined);
71054
+ if (pushRejected) {
71055
+ appendLog(`! push rejected for ${changeName} (host repo pre-push hook failed) \u2014 worktree preserved at ${cwd2}`, "red");
71056
+ appendLog(` detail: ${detail}`, "red");
71057
+ } else {
71058
+ appendLog(`! PR create failed for ${changeName}: ${detail}`, "red");
71059
+ }
71016
71060
  effectiveCode = PR_FAILED_EXIT;
71017
71061
  }
71018
71062
  }
71019
71063
  }
71020
71064
  if (useWorktree && cwd2 !== projectRoot) {
71021
71065
  if (effectiveCode === 0 && cfg.cleanupWorktreeOnSuccess) {
71022
- try {
71023
- await removeWorktree(projectRoot, cwd2, bunGitRunner);
71024
- appendLog(` removed worktree ${cwd2}`, "gray");
71025
- } catch (err) {
71026
- appendLog(`! worktree remove failed for ${changeName}: ${err.message}`, "yellow");
71066
+ const check = await isWorktreeSafeToRemove(cwd2, cfg.prBaseBranch, bunGitRunner).catch((err) => ({
71067
+ safe: false,
71068
+ reason: `safety check failed: ${err.message}`,
71069
+ dirty: "",
71070
+ unpushedCommits: ""
71071
+ }));
71072
+ if (!check.safe) {
71073
+ appendLog(`! preserving worktree for ${changeName}: ${check.reason}`, "yellow");
71074
+ if (check.dirty) {
71075
+ appendLog(` uncommitted:
71076
+ ${check.dirty}`, "yellow");
71077
+ }
71078
+ if (check.unpushedCommits) {
71079
+ appendLog(` commits:
71080
+ ${check.unpushedCommits}`, "yellow");
71081
+ }
71082
+ appendLog(` path: ${cwd2}`, "yellow");
71083
+ } else {
71084
+ try {
71085
+ await removeWorktree(projectRoot, cwd2, bunGitRunner);
71086
+ appendLog(` removed worktree ${cwd2}`, "gray");
71087
+ } catch (err) {
71088
+ appendLog(`! worktree remove failed for ${changeName}: ${err.message}`, "yellow");
71089
+ }
71027
71090
  }
71028
71091
  }
71029
71092
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neriros/ralphy",
3
- "version": "2.9.1",
3
+ "version": "2.9.2",
4
4
  "description": "An iterative AI task execution framework. Orchestrates multi-phase autonomous work using Claude or Codex engines.",
5
5
  "keywords": [
6
6
  "agent",