@neriros/ralphy 2.7.2 → 2.7.3
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 +4 -1
- package/dist/cli/index.js +55 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -83,7 +83,7 @@ What it does on each tick:
|
|
|
83
83
|
2. Dedupes against `.ralph/agent-state.json` (already processed) plus any in-flight workers
|
|
84
84
|
3. For each new issue: fetches existing comments, scaffolds `openspec/changes/<id-slug>/{proposal.md,tasks.md,design.md}` (with the comments embedded so the worker sees prior discussion), then spawns `ralph task --name <id-slug>` up to the concurrency cap
|
|
85
85
|
4. Posts a "🤖 started" comment on the Linear issue and (optionally) moves it to `inProgressStatus`
|
|
86
|
-
5. On worker exit, posts a success/failure comment and (on success) moves the issue to `doneStatus`
|
|
86
|
+
5. On worker exit, posts a success/failure comment and (on success) moves the issue to `doneStatus` and/or applies `doneLabel`
|
|
87
87
|
|
|
88
88
|
Defaults are written to `ralphy.config.json` on first run; CLI flags override config values per invocation.
|
|
89
89
|
|
|
@@ -102,11 +102,14 @@ Defaults are written to `ralphy.config.json` on first run; CLI flags override co
|
|
|
102
102
|
"labels": ["ralph", "automation"],
|
|
103
103
|
"inProgressStatus": "In Progress",
|
|
104
104
|
"doneStatus": "In Review",
|
|
105
|
+
"doneLabel": "ralphy-done",
|
|
105
106
|
"postComments": true,
|
|
106
107
|
},
|
|
107
108
|
}
|
|
108
109
|
```
|
|
109
110
|
|
|
111
|
+
`doneStatus` and `doneLabel` are independent — set either, both, or neither. Use `doneLabel` if your team marks completion via a label rather than a workflow state.
|
|
112
|
+
|
|
110
113
|
Failed workers (non-zero exit) are not marked processed, so they'll be retried on the next poll. SIGINT/SIGTERM cleanly stops polling and kills active workers. All Linear side effects are best-effort — failures log a warning but never block the task loop.
|
|
111
114
|
|
|
112
115
|
## CLI Options
|
package/dist/cli/index.js
CHANGED
|
@@ -69685,6 +69685,26 @@ async function updateIssueState(apiKey, issueId, stateId) {
|
|
|
69685
69685
|
stateId
|
|
69686
69686
|
});
|
|
69687
69687
|
}
|
|
69688
|
+
async function fetchIssueLabels(apiKey, teamKey) {
|
|
69689
|
+
const query = `query Labels($team: String!) {
|
|
69690
|
+
issueLabels(filter: { team: { key: { eq: $team } } }, first: 250) {
|
|
69691
|
+
nodes { id name }
|
|
69692
|
+
}
|
|
69693
|
+
}`;
|
|
69694
|
+
const data = await linearRequest(apiKey, query, {
|
|
69695
|
+
team: teamKey
|
|
69696
|
+
});
|
|
69697
|
+
return data.issueLabels.nodes;
|
|
69698
|
+
}
|
|
69699
|
+
async function addLabelToIssue(apiKey, issueId, labelId) {
|
|
69700
|
+
const mutation = `mutation AddLabel($id: String!, $labelId: String!) {
|
|
69701
|
+
issueAddLabel(id: $id, labelId: $labelId) { success }
|
|
69702
|
+
}`;
|
|
69703
|
+
await linearRequest(apiKey, mutation, {
|
|
69704
|
+
id: issueId,
|
|
69705
|
+
labelId
|
|
69706
|
+
});
|
|
69707
|
+
}
|
|
69688
69708
|
|
|
69689
69709
|
// apps/cli/src/agent/state.ts
|
|
69690
69710
|
import { join as join10 } from "path";
|
|
@@ -69790,6 +69810,7 @@ var RalphyConfigSchema = exports_external.object({
|
|
|
69790
69810
|
labels: exports_external.union([exports_external.array(exports_external.string()), exports_external.string()]).transform((v) => typeof v === "string" ? [v] : v).default([]),
|
|
69791
69811
|
inProgressStatus: exports_external.string().optional(),
|
|
69792
69812
|
doneStatus: exports_external.string().optional(),
|
|
69813
|
+
doneLabel: exports_external.string().optional(),
|
|
69793
69814
|
postComments: exports_external.boolean().default(true)
|
|
69794
69815
|
}).default({ statuses: [], labels: [], postComments: true })
|
|
69795
69816
|
}).default({
|
|
@@ -69959,6 +69980,27 @@ class AgentCoordinator {
|
|
|
69959
69980
|
if (ok && this.opts.doneStatus) {
|
|
69960
69981
|
await this.moveIssue(issue, this.opts.doneStatus);
|
|
69961
69982
|
}
|
|
69983
|
+
if (ok && this.opts.doneLabel) {
|
|
69984
|
+
await this.tagIssue(issue, this.opts.doneLabel);
|
|
69985
|
+
}
|
|
69986
|
+
}
|
|
69987
|
+
async tagIssue(issue, labelName) {
|
|
69988
|
+
const updater = this.deps.updater;
|
|
69989
|
+
if (!updater.resolveLabelId || !updater.addLabel) {
|
|
69990
|
+
this.deps.onLog(`! Linear updater does not support labels (cannot tag ${issue.identifier} with '${labelName}')`, "yellow");
|
|
69991
|
+
return;
|
|
69992
|
+
}
|
|
69993
|
+
try {
|
|
69994
|
+
const labelId = await updater.resolveLabelId(issue, labelName);
|
|
69995
|
+
if (!labelId) {
|
|
69996
|
+
this.deps.onLog(`! Linear label '${labelName}' not found for ${issue.identifier}`, "yellow");
|
|
69997
|
+
return;
|
|
69998
|
+
}
|
|
69999
|
+
await updater.addLabel(issue, labelId);
|
|
70000
|
+
this.deps.onLog(` \u2192 ${issue.identifier} tagged with '${labelName}'`, "gray");
|
|
70001
|
+
} catch (err) {
|
|
70002
|
+
this.deps.onLog(`! Linear label add failed for ${issue.identifier}: ${err.message}`, "red");
|
|
70003
|
+
}
|
|
69962
70004
|
}
|
|
69963
70005
|
async moveIssue(issue, stateName) {
|
|
69964
70006
|
const updater = this.deps.updater;
|
|
@@ -70022,6 +70064,7 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
|
|
|
70022
70064
|
labels: args.linearLabel.length ? args.linearLabel : cfg.linear.labels
|
|
70023
70065
|
};
|
|
70024
70066
|
const stateCache = new Map;
|
|
70067
|
+
const labelCache = new Map;
|
|
70025
70068
|
const teamKeyOf = (issue) => issue.identifier.split("-")[0];
|
|
70026
70069
|
const coord2 = new AgentCoordinator({
|
|
70027
70070
|
fetchIssues: (f2) => fetchOpenIssues(apiKey, f2),
|
|
@@ -70075,6 +70118,17 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
|
|
|
70075
70118
|
stateCache.set(team, map2);
|
|
70076
70119
|
}
|
|
70077
70120
|
return map2.get(stateName.toLowerCase()) ?? null;
|
|
70121
|
+
},
|
|
70122
|
+
addLabel: (issue, labelId) => addLabelToIssue(apiKey, issue.id, labelId),
|
|
70123
|
+
resolveLabelId: async (issue, labelName) => {
|
|
70124
|
+
const team = teamKeyOf(issue);
|
|
70125
|
+
let map2 = labelCache.get(team);
|
|
70126
|
+
if (!map2) {
|
|
70127
|
+
const labels = await fetchIssueLabels(apiKey, team);
|
|
70128
|
+
map2 = new Map(labels.map((l) => [l.name.toLowerCase(), l.id]));
|
|
70129
|
+
labelCache.set(team, map2);
|
|
70130
|
+
}
|
|
70131
|
+
return map2.get(labelName.toLowerCase()) ?? null;
|
|
70078
70132
|
}
|
|
70079
70133
|
}
|
|
70080
70134
|
}, {
|
|
@@ -70082,6 +70136,7 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
|
|
|
70082
70136
|
filter: filter2,
|
|
70083
70137
|
inProgressStatus: cfg.linear.inProgressStatus,
|
|
70084
70138
|
doneStatus: cfg.linear.doneStatus,
|
|
70139
|
+
doneLabel: cfg.linear.doneLabel,
|
|
70085
70140
|
postComments: cfg.linear.postComments
|
|
70086
70141
|
});
|
|
70087
70142
|
coordRef.current = coord2;
|