@neriros/ralphy 2.21.3 → 2.22.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 +9 -1
- package/dist/cli/index.js +54 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -156,7 +156,15 @@ Linear is the source of truth for which issues Ralph has touched. The `linear.in
|
|
|
156
156
|
| `clearConflicted` | `Marker` or `{apply: Marker[]}` | Label(s) removed when a conflict-fix succeeds (status removal is not supported) |
|
|
157
157
|
| `clearReview` | `Marker` or `{apply: Marker[]}` | Label(s) removed when a review pickup happens (status removal is not supported) |
|
|
158
158
|
|
|
159
|
-
A `Marker` is
|
|
159
|
+
A `Marker` is one of three types:
|
|
160
|
+
|
|
161
|
+
| Marker type | Example value | Effect |
|
|
162
|
+
| -------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
163
|
+
| `"label"` | `"ralph:in-progress"` | Adds or removes a Linear label on the issue |
|
|
164
|
+
| `"status"` | `"In Progress"` | Updates the Linear workflow status of the issue |
|
|
165
|
+
| `"attachment"` | `"In Progress"` | Upserts a single **Ralphy** attachment on the issue; `value` becomes the subtitle. The same entry is reused across every lifecycle transition — Ralph creates it on first apply and edits it on subsequent ones, so the issue stays tidy. |
|
|
166
|
+
|
|
167
|
+
Combine with `apply` when one event sets multiple — e.g. `setDone` flipping a status _and_ adding a label _and_ updating the attachment subtitle.
|
|
160
168
|
|
|
161
169
|
Example `ralphy.config.json`:
|
|
162
170
|
|
package/dist/cli/index.js
CHANGED
|
@@ -35029,8 +35029,8 @@ import { readFileSync as readFileSync2 } from "fs";
|
|
|
35029
35029
|
import { resolve } from "path";
|
|
35030
35030
|
function getVersion() {
|
|
35031
35031
|
try {
|
|
35032
|
-
if ("2.
|
|
35033
|
-
return "2.
|
|
35032
|
+
if ("2.22.0")
|
|
35033
|
+
return "2.22.0";
|
|
35034
35034
|
} catch {}
|
|
35035
35035
|
const dirsToTry = [];
|
|
35036
35036
|
try {
|
|
@@ -35079,8 +35079,8 @@ function parseIndicatorArg(raw) {
|
|
|
35079
35079
|
err.key = key;
|
|
35080
35080
|
throw err;
|
|
35081
35081
|
}
|
|
35082
|
-
if (type !== "label" && type !== "status") {
|
|
35083
|
-
const err = new Error("indicator type must be 'label' or '
|
|
35082
|
+
if (type !== "label" && type !== "status" && type !== "attachment") {
|
|
35083
|
+
const err = new Error("indicator type must be 'label', 'status', or 'attachment'");
|
|
35084
35084
|
err.type = type;
|
|
35085
35085
|
throw err;
|
|
35086
35086
|
}
|
|
@@ -35420,7 +35420,9 @@ var init_cli = __esm(() => {
|
|
|
35420
35420
|
" Keys: getTodo, getInProgress, getConflicted, getReview, getAutoMerge,",
|
|
35421
35421
|
" setInProgress, setDone, setError, setConflicted,",
|
|
35422
35422
|
" clearConflicted, clearReview",
|
|
35423
|
-
" Types: label, status",
|
|
35423
|
+
" Types: label, status, attachment",
|
|
35424
|
+
" --indicator setInProgress:attachment:In Progress",
|
|
35425
|
+
" (attachment upserts a single 'Ralphy' entry; value = subtitle)",
|
|
35424
35426
|
" --create-pr Push the worker branch and open a GitHub PR on success (needs --worktree)",
|
|
35425
35427
|
" --fix-ci After opening the PR, re-run on CI failures until green (needs --create-pr)",
|
|
35426
35428
|
" --code-review Watch open tracked PRs for unresolved review comments and prepend a code-review task",
|
|
@@ -59669,12 +59671,16 @@ var MarkerSchema, GetIndicatorSchema, SetIndicatorSchema, IndicatorsSchema, Ralp
|
|
|
59669
59671
|
|
|
59670
59672
|
// Applied when Ralph picks up an issue.
|
|
59671
59673
|
// "setInProgress": { "type": "label", "value": "ralph:in-progress" },
|
|
59674
|
+
// \u2014 or use attachment type to stamp a single "Ralphy" entry on the issue:
|
|
59675
|
+
// "setInProgress": { "type": "attachment", "value": "In Progress" },
|
|
59672
59676
|
|
|
59673
59677
|
// Applied on clean success.
|
|
59674
59678
|
// "setDone": { "type": "status", "value": "In Review" },
|
|
59679
|
+
// "setDone": { "type": "attachment", "value": "Done" },
|
|
59675
59680
|
|
|
59676
59681
|
// Applied when the task exits with an error (quarantine signal).
|
|
59677
59682
|
// "setError": { "type": "label", "value": "ralph:error" },
|
|
59683
|
+
// "setError": { "type": "attachment", "value": "Error" },
|
|
59678
59684
|
|
|
59679
59685
|
// Applied when a PR merge conflict is detected.
|
|
59680
59686
|
// "setConflicted": { "type": "label", "value": "ralph:conflict" },
|
|
@@ -59691,7 +59697,7 @@ var MarkerSchema, GetIndicatorSchema, SetIndicatorSchema, IndicatorsSchema, Ralp
|
|
|
59691
59697
|
var init_config = __esm(() => {
|
|
59692
59698
|
init_zod();
|
|
59693
59699
|
MarkerSchema = exports_external.object({
|
|
59694
|
-
type: exports_external.enum(["label", "status"]),
|
|
59700
|
+
type: exports_external.enum(["label", "status", "attachment"]),
|
|
59695
59701
|
value: exports_external.string().min(1)
|
|
59696
59702
|
});
|
|
59697
59703
|
GetIndicatorSchema = exports_external.object({
|
|
@@ -60007,6 +60013,44 @@ async function fetchIssueComments(apiKey, issueId) {
|
|
|
60007
60013
|
const data = await linearRequest(apiKey, query, { id: issueId });
|
|
60008
60014
|
return data.issue?.comments.nodes ?? [];
|
|
60009
60015
|
}
|
|
60016
|
+
async function createRalphyAttachment(apiKey, issueId, issueUrl, subtitle) {
|
|
60017
|
+
const mutation = `mutation CreateAttachment(
|
|
60018
|
+
$issueId: String!, $url: String!, $title: String!, $subtitle: String!
|
|
60019
|
+
) {
|
|
60020
|
+
attachmentCreate(input: { issueId: $issueId, url: $url, title: $title, subtitle: $subtitle }) {
|
|
60021
|
+
success
|
|
60022
|
+
attachment { id }
|
|
60023
|
+
}
|
|
60024
|
+
}`;
|
|
60025
|
+
const data = await linearRequest(apiKey, mutation, {
|
|
60026
|
+
issueId,
|
|
60027
|
+
url: issueUrl,
|
|
60028
|
+
title: RALPHY_ATTACHMENT_TITLE,
|
|
60029
|
+
subtitle
|
|
60030
|
+
});
|
|
60031
|
+
const attachmentId = data.attachmentCreate.attachment?.id;
|
|
60032
|
+
if (!attachmentId)
|
|
60033
|
+
throw new Error("attachmentCreate returned no attachment id");
|
|
60034
|
+
return attachmentId;
|
|
60035
|
+
}
|
|
60036
|
+
async function updateAttachmentSubtitle(apiKey, attachmentId, subtitle) {
|
|
60037
|
+
const mutation = `mutation UpdateAttachment($id: String!, $subtitle: String!) {
|
|
60038
|
+
attachmentUpdate(id: $id, input: { subtitle: $subtitle }) { success }
|
|
60039
|
+
}`;
|
|
60040
|
+
await linearRequest(apiKey, mutation, {
|
|
60041
|
+
id: attachmentId,
|
|
60042
|
+
subtitle
|
|
60043
|
+
});
|
|
60044
|
+
}
|
|
60045
|
+
async function upsertRalphyAttachment(apiKey, issueId, issueUrl, subtitle) {
|
|
60046
|
+
const attachments = await fetchIssueAttachments(apiKey, issueId);
|
|
60047
|
+
const existing = attachments.find((a) => a.title === RALPHY_ATTACHMENT_TITLE);
|
|
60048
|
+
if (existing) {
|
|
60049
|
+
await updateAttachmentSubtitle(apiKey, existing.id, subtitle);
|
|
60050
|
+
} else {
|
|
60051
|
+
await createRalphyAttachment(apiKey, issueId, issueUrl, subtitle);
|
|
60052
|
+
}
|
|
60053
|
+
}
|
|
60010
60054
|
async function fetchIssueAttachments(apiKey, issueId) {
|
|
60011
60055
|
const query = `query IssueAttachments($id: String!) {
|
|
60012
60056
|
issue(id: $id) {
|
|
@@ -60127,7 +60171,7 @@ async function removeLabelFromIssue(apiKey, issueId, labelId) {
|
|
|
60127
60171
|
labelId
|
|
60128
60172
|
});
|
|
60129
60173
|
}
|
|
60130
|
-
var LINEAR_API = "https://api.linear.app/graphql", BRANCH_LABEL_PREFIX = "ralph:branch:";
|
|
60174
|
+
var LINEAR_API = "https://api.linear.app/graphql", RALPHY_ATTACHMENT_TITLE = "Ralphy", BRANCH_LABEL_PREFIX = "ralph:branch:";
|
|
60131
60175
|
|
|
60132
60176
|
// apps/cli/src/agent/coordinator.ts
|
|
60133
60177
|
class AgentCoordinator {
|
|
@@ -61404,6 +61448,9 @@ function buildAgentCoordinator(input) {
|
|
|
61404
61448
|
}
|
|
61405
61449
|
await updateIssueState(apiKey, issue.id, id);
|
|
61406
61450
|
onLog(` \u2192 ${issue.identifier} status='${m.value}'`, "gray");
|
|
61451
|
+
} else if (m.type === "attachment") {
|
|
61452
|
+
await upsertRalphyAttachment(apiKey, issue.id, issue.url, m.value);
|
|
61453
|
+
onLog(` \u2192 ${issue.identifier} attachment='${m.value}'`, "gray");
|
|
61407
61454
|
} else {
|
|
61408
61455
|
const id = await resolveLabelId(issue, m.value);
|
|
61409
61456
|
if (!id) {
|