@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 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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neriros/ralphy",
3
- "version": "2.7.2",
3
+ "version": "2.7.3",
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",