@neriros/ralphy 3.10.18 → 3.10.20

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.
Files changed (2) hide show
  1. package/dist/shell/index.js +220 -55
  2. package/package.json +1 -1
@@ -18928,8 +18928,8 @@ import { readFileSync } from "fs";
18928
18928
  import { resolve } from "path";
18929
18929
  function getVersion() {
18930
18930
  try {
18931
- if ("3.10.18")
18932
- return "3.10.18";
18931
+ if ("3.10.20")
18932
+ return "3.10.20";
18933
18933
  } catch {}
18934
18934
  const dirsToTry = [];
18935
18935
  try {
@@ -81308,6 +81308,20 @@ var init_zod = __esm(() => {
81308
81308
  });
81309
81309
 
81310
81310
  // packages/workflow/src/schema.ts
81311
+ function normalizeNegationShorthand(v) {
81312
+ if (!v || typeof v !== "object" || Array.isArray(v))
81313
+ return v;
81314
+ const obj = v;
81315
+ const t = obj["type"];
81316
+ const negatable = t === "label" || t === "status" || t === "project";
81317
+ if (!negatable || obj["negate"] !== undefined)
81318
+ return v;
81319
+ const value = obj["value"];
81320
+ if (typeof value === "string" && value.startsWith("!")) {
81321
+ return { ...obj, value: value.slice(1), negate: true };
81322
+ }
81323
+ return v;
81324
+ }
81311
81325
  function foldLegacyAssignee(v) {
81312
81326
  if (!v || typeof v !== "object" || Array.isArray(v))
81313
81327
  return v;
@@ -81325,21 +81339,39 @@ function foldLegacyAssignee(v) {
81325
81339
  var CURRENT_WORKFLOW_VERSION = 8, MarkerSchema, FilterMarkerSchema, LinearFilterSchema, SET_INDICATOR_KEYS, GetIndicatorSchema, SetIndicatorSchema, IndicatorsSchema, ProjectSchema, CommandsSchema, DEFAULT_META_ONLY_FILES, BoundariesSchema, WorkflowConfigSchema;
81326
81340
  var init_schema = __esm(() => {
81327
81341
  init_zod();
81328
- MarkerSchema = exports_external.discriminatedUnion("type", [
81342
+ MarkerSchema = exports_external.preprocess(normalizeNegationShorthand, exports_external.discriminatedUnion("type", [
81329
81343
  exports_external.object({
81330
81344
  type: exports_external.literal("label"),
81331
81345
  value: exports_external.string().min(1),
81332
- group: exports_external.string().min(1).optional()
81346
+ group: exports_external.string().min(1).optional(),
81347
+ negate: exports_external.boolean().optional()
81333
81348
  }),
81334
- exports_external.object({ type: exports_external.literal("status"), value: exports_external.string().min(1) }).strict(),
81349
+ exports_external.object({
81350
+ type: exports_external.literal("status"),
81351
+ value: exports_external.string().min(1),
81352
+ negate: exports_external.boolean().optional()
81353
+ }).strict(),
81335
81354
  exports_external.object({ type: exports_external.literal("attachment"), value: exports_external.string().min(1) }).strict(),
81336
- exports_external.object({ type: exports_external.literal("project"), value: exports_external.string().min(1) }).strict(),
81355
+ exports_external.object({
81356
+ type: exports_external.literal("project"),
81357
+ value: exports_external.string().min(1),
81358
+ negate: exports_external.boolean().optional()
81359
+ }).strict(),
81337
81360
  exports_external.object({ type: exports_external.literal("comment"), value: exports_external.string().min(1) }).strict()
81338
- ]);
81339
- FilterMarkerSchema = exports_external.discriminatedUnion("type", [
81340
- exports_external.object({ type: exports_external.literal("label"), value: exports_external.string().min(1) }).strict(),
81361
+ ]));
81362
+ FilterMarkerSchema = exports_external.preprocess(normalizeNegationShorthand, exports_external.discriminatedUnion("type", [
81363
+ exports_external.object({
81364
+ type: exports_external.literal("label"),
81365
+ value: exports_external.string().min(1),
81366
+ negate: exports_external.boolean().optional()
81367
+ }).strict(),
81368
+ exports_external.object({
81369
+ type: exports_external.literal("project"),
81370
+ value: exports_external.string().min(1),
81371
+ negate: exports_external.boolean().optional()
81372
+ }).strict(),
81341
81373
  exports_external.object({ type: exports_external.literal("assignee"), value: exports_external.string().min(1) }).strict()
81342
- ]);
81374
+ ]));
81343
81375
  LinearFilterSchema = exports_external.array(FilterMarkerSchema).superRefine((markers, ctx) => {
81344
81376
  const assigneeCount = markers.filter((m) => m.type === "assignee").length;
81345
81377
  if (assigneeCount > 1) {
@@ -81348,6 +81380,13 @@ var init_schema = __esm(() => {
81348
81380
  message: `linear.filter allows at most one "assignee" clause, found ${assigneeCount}.`
81349
81381
  });
81350
81382
  }
81383
+ const positiveProjects = markers.filter((m) => m.type === "project" && !m.negate).length;
81384
+ if (positiveProjects > 1) {
81385
+ ctx.addIssue({
81386
+ code: exports_external.ZodIssueCode.custom,
81387
+ message: `linear.filter allows at most one positive "project" clause, found ${positiveProjects}.`
81388
+ });
81389
+ }
81351
81390
  }).default([{ type: "assignee", value: "me" }]);
81352
81391
  SET_INDICATOR_KEYS = [
81353
81392
  "setInProgress",
@@ -81381,6 +81420,14 @@ var init_schema = __esm(() => {
81381
81420
  continue;
81382
81421
  const markers = Array.isArray(clear) ? clear : [clear];
81383
81422
  for (const m of markers) {
81423
+ if ("negate" in m && m.negate) {
81424
+ ctx.addIssue({
81425
+ code: exports_external.ZodIssueCode.custom,
81426
+ path: [key],
81427
+ message: `${key} cannot use a negated marker \u2014 negation is only meaningful in getX filters`
81428
+ });
81429
+ break;
81430
+ }
81384
81431
  if (m.type === "comment")
81385
81432
  continue;
81386
81433
  if (m.type !== "label") {
@@ -81399,6 +81446,14 @@ var init_schema = __esm(() => {
81399
81446
  continue;
81400
81447
  const markers = Array.isArray(set3) ? set3 : [set3];
81401
81448
  for (const m of markers) {
81449
+ if ("negate" in m && m.negate) {
81450
+ ctx.addIssue({
81451
+ code: exports_external.ZodIssueCode.custom,
81452
+ path: [key],
81453
+ message: `${key} cannot use a negated marker \u2014 negation is only meaningful in getX filters`
81454
+ });
81455
+ break;
81456
+ }
81402
81457
  if (m.type === "comment") {
81403
81458
  ctx.addIssue({
81404
81459
  code: exports_external.ZodIssueCode.custom,
@@ -82261,34 +82316,64 @@ function describeApprovalMarker(indicator) {
82261
82316
  }
82262
82317
 
82263
82318
  // packages/workflow/src/linear-filter.ts
82319
+ function linearFilterScope(resolved) {
82320
+ const scope = { requireAllLabels: resolved.requireAllLabels };
82321
+ if (resolved.excludeLabels)
82322
+ scope.excludeLabels = resolved.excludeLabels;
82323
+ if (resolved.requireProject)
82324
+ scope.requireProject = resolved.requireProject;
82325
+ if (resolved.excludeProjects)
82326
+ scope.excludeProjects = resolved.excludeProjects;
82327
+ return scope;
82328
+ }
82264
82329
  function resolveLinearFilter(filter2) {
82265
82330
  const assigneeClauses = filter2.filter((marker) => marker.type === "assignee");
82266
82331
  if (assigneeClauses.length > 1) {
82267
82332
  throw new Error(`Invalid linear.filter: at most one "assignee" clause is allowed, found ${assigneeClauses.length}.`);
82268
82333
  }
82269
- const requireAllLabels = [];
82270
- const seenLabels = new Set;
82271
- for (const marker of filter2) {
82272
- if (marker.type !== "label")
82273
- continue;
82274
- if (seenLabels.has(marker.value))
82275
- continue;
82276
- seenLabels.add(marker.value);
82277
- requireAllLabels.push(marker.value);
82278
- }
82334
+ const requireAllLabels = collectDeduped(filter2, "label", false);
82335
+ const excludeLabels = collectDeduped(filter2, "label", true);
82336
+ const requireProjects = collectDeduped(filter2, "project", false);
82337
+ const excludeProjects = collectDeduped(filter2, "project", true);
82338
+ if (requireProjects.length > 1) {
82339
+ throw new Error(`Invalid linear.filter: at most one positive "project" clause is allowed, found ${requireProjects.length}.`);
82340
+ }
82341
+ const optional2 = {};
82342
+ if (excludeLabels.length > 0)
82343
+ optional2.excludeLabels = excludeLabels;
82344
+ if (requireProjects[0] !== undefined)
82345
+ optional2.requireProject = requireProjects[0];
82346
+ if (excludeProjects.length > 0)
82347
+ optional2.excludeProjects = excludeProjects;
82348
+ const base2 = { requireAllLabels, ...optional2 };
82279
82349
  const assigneeClause = assigneeClauses[0];
82280
82350
  if (!assigneeClause)
82281
- return { requireAllLabels };
82351
+ return base2;
82282
82352
  const value = assigneeClause.value.trim();
82283
82353
  const lower = value.toLowerCase();
82284
82354
  if (lower === "any")
82285
- return { anyAssignee: true, requireAllLabels };
82355
+ return { anyAssignee: true, ...base2 };
82286
82356
  if (lower === "" || lower === "unassigned") {
82287
- return { assignee: "unassigned", requireAllLabels };
82357
+ return { assignee: "unassigned", ...base2 };
82288
82358
  }
82289
82359
  if (lower === "me")
82290
- return { assignee: "me", requireAllLabels };
82291
- return { assignee: value, requireAllLabels };
82360
+ return { assignee: "me", ...base2 };
82361
+ return { assignee: value, ...base2 };
82362
+ }
82363
+ function collectDeduped(filter2, type, negated) {
82364
+ const out = [];
82365
+ const seen = new Set;
82366
+ for (const marker of filter2) {
82367
+ if (marker.type !== type)
82368
+ continue;
82369
+ if (Boolean(marker.negate) !== negated)
82370
+ continue;
82371
+ if (seen.has(marker.value))
82372
+ continue;
82373
+ seen.add(marker.value);
82374
+ out.push(marker.value);
82375
+ }
82376
+ return out;
82292
82377
  }
82293
82378
  function applyAssigneeOverride(filter2, assignee) {
82294
82379
  const trimmed = assignee.trim();
@@ -82315,6 +82400,7 @@ __export(exports_workflow, {
82315
82400
  migrateWorkflowMarkdown: () => migrateWorkflowMarkdown,
82316
82401
  matchesIndicator: () => matchesIndicator,
82317
82402
  loadWorkflow: () => loadWorkflow,
82403
+ linearFilterScope: () => linearFilterScope,
82318
82404
  ensureWorkflow: () => ensureWorkflow,
82319
82405
  describeApprovalMarker: () => describeApprovalMarker,
82320
82406
  computeConfirmationFlags: () => computeConfirmationFlags,
@@ -103151,6 +103237,39 @@ function applyRequiredLabels(where, requireAllLabels) {
103151
103237
  }
103152
103238
  where.and = and2;
103153
103239
  }
103240
+ function isNegatedMarker(m) {
103241
+ return "negate" in m && Boolean(m.negate);
103242
+ }
103243
+ function applyRequiredProject(where, requireProject) {
103244
+ if (!requireProject)
103245
+ return;
103246
+ const clause = { project: { name: { in: [requireProject] } } };
103247
+ const existing = where.project;
103248
+ if (existing === undefined) {
103249
+ const and3 = where.and;
103250
+ if (and3 !== undefined)
103251
+ and3.push(clause);
103252
+ else
103253
+ where.project = clause.project;
103254
+ return;
103255
+ }
103256
+ const and2 = where.and ?? [];
103257
+ and2.push({ project: existing }, clause);
103258
+ delete where.project;
103259
+ where.and = and2;
103260
+ }
103261
+ function applyGlobalExcludes(where, excludeLabels, excludeProjects) {
103262
+ if (excludeLabels && excludeLabels.length > 0) {
103263
+ const and2 = where.and ?? [];
103264
+ and2.push({ labels: { every: { name: { nin: excludeLabels } } } });
103265
+ where.and = and2;
103266
+ }
103267
+ if (excludeProjects && excludeProjects.length > 0) {
103268
+ const and2 = where.and ?? [];
103269
+ and2.push({ project: { name: { nin: excludeProjects } } });
103270
+ where.and = and2;
103271
+ }
103272
+ }
103154
103273
  function buildIssueFilter(spec) {
103155
103274
  const where = {};
103156
103275
  if (spec.team)
@@ -103169,9 +103288,13 @@ function buildIssueFilter(spec) {
103169
103288
  if (spec.numbers && spec.numbers.length > 0) {
103170
103289
  where.number = { in: spec.numbers };
103171
103290
  }
103172
- const inc = spec.include ?? [];
103291
+ const incAll = spec.include ?? [];
103292
+ const inc = incAll.filter((m) => !isNegatedMarker(m));
103293
+ const negatedInc = incAll.filter(isNegatedMarker);
103294
+ let pinnedStatus = false;
103173
103295
  if (inc.length > 0) {
103174
103296
  const { statuses, labels, attachmentSubtitles, projects } = partition2(inc);
103297
+ pinnedStatus = statuses.length > 0;
103175
103298
  const branches = [];
103176
103299
  if (statuses.length > 0)
103177
103300
  branches.push({ state: { name: { in: statuses } } });
@@ -103191,10 +103314,16 @@ function buildIssueFilter(spec) {
103191
103314
  branches.push({ project: { name: { in: projects } } });
103192
103315
  for (const b of branches)
103193
103316
  Object.assign(where, b);
103194
- } else {
103317
+ }
103318
+ if (!pinnedStatus) {
103195
103319
  where.state = { type: { in: ["unstarted", "started", "backlog"] } };
103196
103320
  }
103197
- const exc = spec.exclude ?? [];
103321
+ const exc = [
103322
+ ...spec.exclude ?? [],
103323
+ ...negatedInc,
103324
+ ...(spec.excludeLabels ?? []).map((value) => ({ type: "label", value })),
103325
+ ...(spec.excludeProjects ?? []).map((value) => ({ type: "project", value }))
103326
+ ];
103198
103327
  if (exc.length > 0) {
103199
103328
  const {
103200
103329
  statuses,
@@ -103250,12 +103379,13 @@ function buildIssueFilter(spec) {
103250
103379
  }
103251
103380
  }
103252
103381
  applyRequiredLabels(where, spec.requireAllLabels);
103382
+ applyRequiredProject(where, spec.requireProject);
103253
103383
  return where;
103254
103384
  }
103255
103385
  function clauseFromMarkers(markers) {
103256
103386
  if (markers.length === 0)
103257
103387
  return null;
103258
- const { statuses, labels, attachmentSubtitles, projects } = partition2(markers);
103388
+ const { statuses, labels, attachmentSubtitles, projects } = partition2(markers.filter((m) => !isNegatedMarker(m)));
103259
103389
  const parts = {};
103260
103390
  if (statuses.length > 0)
103261
103391
  parts.state = { name: { in: statuses } };
@@ -103271,6 +103401,16 @@ function clauseFromMarkers(markers) {
103271
103401
  }
103272
103402
  if (projects.length > 0)
103273
103403
  parts.project = { name: { in: projects } };
103404
+ const negated = partition2(markers.filter(isNegatedMarker));
103405
+ const negClauses = [];
103406
+ if (negated.statuses.length > 0)
103407
+ negClauses.push({ state: { name: { nin: negated.statuses } } });
103408
+ if (negated.labels.length > 0)
103409
+ negClauses.push({ labels: { every: { name: { nin: negated.labels } } } });
103410
+ if (negated.projects.length > 0)
103411
+ negClauses.push({ project: { name: { nin: negated.projects } } });
103412
+ if (negClauses.length > 0)
103413
+ parts.and = negClauses;
103274
103414
  return Object.keys(parts).length > 0 ? parts : null;
103275
103415
  }
103276
103416
  function mapNodeProject(node2) {
@@ -103331,6 +103471,8 @@ async function fetchMentionScanIssues(apiKey, spec) {
103331
103471
  where.number = { in: spec.numbers };
103332
103472
  }
103333
103473
  applyRequiredLabels(where, spec.requireAllLabels);
103474
+ applyRequiredProject(where, spec.requireProject);
103475
+ applyGlobalExcludes(where, spec.excludeLabels, spec.excludeProjects);
103334
103476
  const query = `query MentionScanIssues($filter: IssueFilter) {
103335
103477
  issues(filter: $filter, first: 50) {
103336
103478
  nodes {
@@ -103858,7 +104000,7 @@ function issueMatchesGetIndicator(issue2, indicator) {
103858
104000
  const labels = new Set(issue2.labels.map((l) => l.toLowerCase()));
103859
104001
  const stateName = issue2.state.name.toLowerCase();
103860
104002
  const projectName = issue2.project?.name.toLowerCase() ?? null;
103861
- return indicator.filter.some((m) => {
104003
+ const baseMatch = (m) => {
103862
104004
  if (m.type === "label")
103863
104005
  return labels.has(m.value.toLowerCase());
103864
104006
  if (m.type === "status")
@@ -103878,7 +104020,8 @@ function issueMatchesGetIndicator(issue2, indicator) {
103878
104020
  return comments.some((c) => !isRalphComment(c.body) && c.body.toLowerCase().includes(needle));
103879
104021
  }
103880
104022
  return false;
103881
- });
104023
+ };
104024
+ return indicator.filter.some((m) => isNegatedMarker(m) ? !baseMatch(m) : baseMatch(m));
103882
104025
  }
103883
104026
  async function fetchProjectIdByName(apiKey, name) {
103884
104027
  const query = `query ProjectId($name: String!) {
@@ -105807,6 +105950,7 @@ function pipelineStages(row) {
105807
105950
  case "awaiting":
105808
105951
  return stages("done", "current", "pending", "pending", "pending", "pending");
105809
105952
  case "queued":
105953
+ return stages("done", "done", "pending", "pending", "pending", "pending");
105810
105954
  case "working":
105811
105955
  case "in-progress":
105812
105956
  return stages("done", "done", "current", "pending", "pending", "pending");
@@ -105869,6 +106013,15 @@ function statusLabel(row) {
105869
106013
  }
105870
106014
  }
105871
106015
  }
106016
+ function orderActiveWorkersFirst(rows, activeWorkerIds) {
106017
+ if (activeWorkerIds.size === 0)
106018
+ return rows.slice();
106019
+ const active = [];
106020
+ const rest2 = [];
106021
+ for (const r of rows)
106022
+ (activeWorkerIds.has(r.id) ? active : rest2).push(r);
106023
+ return [...active, ...rest2];
106024
+ }
105872
106025
  function buildBoardTree(rows) {
105873
106026
  const byId = new Map(rows.map((r) => [r.id, r]));
105874
106027
  const orderIndex = new Map(rows.map((r, i) => [r.id, i]));
@@ -106578,7 +106731,7 @@ class AgentCoordinator {
106578
106731
  state = machineStateToTicketState(snapshot.value);
106579
106732
  if (state === "done")
106580
106733
  return null;
106581
- if (kind === "queued" && state === "in-progress")
106734
+ if (kind === "queued" && (state === "working" || state === "in-progress"))
106582
106735
  state = "queued";
106583
106736
  const flowRecovery = snapshot.context.data.recovery;
106584
106737
  if (flowRecovery) {
@@ -108436,7 +108589,7 @@ var init_indicators = __esm(() => {
108436
108589
 
108437
108590
  // apps/agent/src/agent/wire/linear-resolvers.ts
108438
108591
  function createLinearResolvers(input) {
108439
- const { apiKey, team, assignee, anyAssignee, requireAllLabels, diag } = input;
108592
+ const { apiKey, team, assignee, anyAssignee, scope, diag } = input;
108440
108593
  const ticketNumbers = input.ticketNumbers ?? [];
108441
108594
  const stateCache = new Map;
108442
108595
  const labelCache = new Map;
@@ -108571,7 +108724,7 @@ function createLinearResolvers(input) {
108571
108724
  team,
108572
108725
  assignee,
108573
108726
  anyAssignee,
108574
- requireAllLabels,
108727
+ ...scope,
108575
108728
  include,
108576
108729
  exclude: excl,
108577
108730
  ...ticketNumbers.length > 0 ? { numbers: ticketNumbers } : {}
@@ -108594,18 +108747,18 @@ function createLinearResolvers(input) {
108594
108747
  resolveLabelIdForTeam
108595
108748
  };
108596
108749
  }
108597
- function doneCandidateSpec(team, assignee, anyAssignee, requireAllLabels, include, ticketNumbers) {
108750
+ function doneCandidateSpec(team, assignee, anyAssignee, scope, include, ticketNumbers) {
108598
108751
  return {
108599
108752
  team,
108600
108753
  assignee,
108601
108754
  anyAssignee,
108602
- requireAllLabels,
108755
+ ...scope,
108603
108756
  include,
108604
108757
  exclude: [],
108605
108758
  ...ticketNumbers && ticketNumbers.length > 0 ? { numbers: ticketNumbers } : {}
108606
108759
  };
108607
108760
  }
108608
- async function fetchDoneCandidatesWith(apiKey, team, assignee, anyAssignee, requireAllLabels, indicators, ticketNumbers) {
108761
+ async function fetchDoneCandidatesWith(apiKey, team, assignee, anyAssignee, scope, indicators, ticketNumbers) {
108609
108762
  const getIndicators = [
108610
108763
  indicators.getTodo,
108611
108764
  indicators.getInProgress,
@@ -108624,7 +108777,7 @@ async function fetchDoneCandidatesWith(apiKey, team, assignee, anyAssignee, requ
108624
108777
  const include = ind.filter ?? [];
108625
108778
  if (include.length === 0)
108626
108779
  return;
108627
- const issues = await fetchOpenIssues(apiKey, doneCandidateSpec(team, assignee, anyAssignee, requireAllLabels, include, ticketNumbers));
108780
+ const issues = await fetchOpenIssues(apiKey, doneCandidateSpec(team, assignee, anyAssignee, scope, include, ticketNumbers));
108628
108781
  for (const issue2 of issues) {
108629
108782
  if (!seen.has(issue2.id)) {
108630
108783
  seen.add(issue2.id);
@@ -108805,7 +108958,7 @@ function createLinearTrackerProvider(input) {
108805
108958
  team,
108806
108959
  assignee,
108807
108960
  anyAssignee,
108808
- requireAllLabels,
108961
+ scope,
108809
108962
  indicators,
108810
108963
  resolvers,
108811
108964
  fetchMentions,
@@ -108818,7 +108971,7 @@ function createLinearTrackerProvider(input) {
108818
108971
  fetchInProgress: () => resolvers.fetchByGet(indicators.getInProgress, excludeFromInProgress),
108819
108972
  fetchReview: () => resolvers.fetchByGet(indicators.getReview, []),
108820
108973
  fetchMentions,
108821
- fetchDoneCandidates: () => fetchDoneCandidatesWith(apiKey, team, assignee, anyAssignee, requireAllLabels, indicators, ticketNumbers && ticketNumbers.length > 0 ? ticketNumbers : undefined),
108974
+ fetchDoneCandidates: () => fetchDoneCandidatesWith(apiKey, team, assignee, anyAssignee, scope, indicators, ticketNumbers && ticketNumbers.length > 0 ? ticketNumbers : undefined),
108822
108975
  applyIndicator: resolvers.applyIndicator,
108823
108976
  removeIndicator: resolvers.removeIndicator,
108824
108977
  postComment: (issue2, body) => addIssueComment(apiKey, issue2.id, body),
@@ -109609,7 +109762,7 @@ function createMentionScanner(input) {
109609
109762
  team,
109610
109763
  assignee,
109611
109764
  anyAssignee,
109612
- requireAllLabels,
109765
+ scope,
109613
109766
  indicators,
109614
109767
  projectRoot,
109615
109768
  useWorktree,
@@ -109634,7 +109787,7 @@ function createMentionScanner(input) {
109634
109787
  team,
109635
109788
  assignee,
109636
109789
  anyAssignee,
109637
- ...requireAllLabels && requireAllLabels.length > 0 ? { requireAllLabels } : {},
109790
+ ...scope,
109638
109791
  ...ticketNumbers && ticketNumbers.length > 0 ? { numbers: ticketNumbers } : {},
109639
109792
  indicators: {
109640
109793
  ...indicators.getTodo !== undefined ? { getTodo: indicators.getTodo } : {},
@@ -263801,7 +263954,9 @@ function buildAgentCoordinator(input) {
263801
263954
  const isGithubTracker = cfg.tracker.kind === "github";
263802
263955
  const indicators = isGithubTracker ? githubIndicators(cfg.github?.issues) : mergeIndicators(cfg.linear.indicators, args.indicators);
263803
263956
  const team = args.linearTeam || cfg.linear.team;
263804
- const { assignee, anyAssignee, requireAllLabels } = resolveLinearFilter(applyAssigneeOverride(cfg.linear.filter, args.linearAssignee));
263957
+ const resolvedFilter = resolveLinearFilter(applyAssigneeOverride(cfg.linear.filter, args.linearAssignee));
263958
+ const { assignee, anyAssignee, requireAllLabels } = resolvedFilter;
263959
+ const scope = linearFilterScope(resolvedFilter);
263805
263960
  const ticketNumbers = resolveTicketNumbers(args.ticketTokens, team);
263806
263961
  const excludeFromTodo = isGithubTracker ? unionMarkers(indicators.setDone, indicators.setError, indicators.setInProgress) : unionMarkers(indicators.setDone, indicators.setError);
263807
263962
  const gitRunner = input.runners?.git ?? bunGitRunner;
@@ -263843,7 +263998,7 @@ function buildAgentCoordinator(input) {
263843
263998
  team,
263844
263999
  assignee,
263845
264000
  anyAssignee,
263846
- requireAllLabels,
264001
+ scope,
263847
264002
  diag,
263848
264003
  ...ticketNumbers.length > 0 ? { ticketNumbers } : {}
263849
264004
  });
@@ -263854,7 +264009,7 @@ function buildAgentCoordinator(input) {
263854
264009
  diag
263855
264010
  }) : {
263856
264011
  ...resolvers,
263857
- fetchDoneCandidates: () => fetchDoneCandidatesWith(apiKey, team, assignee, anyAssignee, requireAllLabels, indicators, ticketNumbers.length > 0 ? ticketNumbers : undefined)
264012
+ fetchDoneCandidates: () => fetchDoneCandidatesWith(apiKey, team, assignee, anyAssignee, scope, indicators, ticketNumbers.length > 0 ? ticketNumbers : undefined)
263858
264013
  };
263859
264014
  if (ticketNumbers.length > 0) {
263860
264015
  const hasGetIndicator = [indicators.getTodo, indicators.getInProgress].some((ind) => ind && ind.filter.length > 0);
@@ -263893,7 +264048,7 @@ function buildAgentCoordinator(input) {
263893
264048
  team,
263894
264049
  assignee,
263895
264050
  anyAssignee,
263896
- requireAllLabels,
264051
+ scope,
263897
264052
  indicators,
263898
264053
  projectRoot,
263899
264054
  useWorktree,
@@ -263921,7 +264076,7 @@ function buildAgentCoordinator(input) {
263921
264076
  team,
263922
264077
  assignee,
263923
264078
  anyAssignee,
263924
- requireAllLabels,
264079
+ scope,
263925
264080
  indicators,
263926
264081
  resolvers,
263927
264082
  fetchMentions,
@@ -265071,7 +265226,8 @@ function AgentMode({
265071
265226
  const termWidth = columns - 2;
265072
265227
  const termHeight = rows;
265073
265228
  const board = pollStatus.lastBoard;
265074
- const tree = buildBoardTree(board);
265229
+ const liveWorkerIds = new Set(coordRef.current?.activeWorkers.map((w2) => w2.issueId) ?? []);
265230
+ const tree = buildBoardTree(orderActiveWorkersFirst(board, liveWorkerIds));
265075
265231
  const focusedIndex = (() => {
265076
265232
  if (tree.length === 0)
265077
265233
  return -1;
@@ -266283,14 +266439,14 @@ function buildBuckets(indicators) {
266283
266439
  { label: "auto-merge", indicator: indicators.getAutoMerge, exclude: [] }
266284
266440
  ];
266285
266441
  }
266286
- async function fetchBucketIssues(apiKey, bucket, team, assignee, anyAssignee, requireAllLabels, ticketNumbers) {
266442
+ async function fetchBucketIssues(apiKey, bucket, team, assignee, anyAssignee, scope, ticketNumbers) {
266287
266443
  if (!bucket.indicator || bucket.indicator.filter.length === 0)
266288
266444
  return [];
266289
266445
  const spec = {
266290
266446
  team,
266291
266447
  assignee,
266292
266448
  anyAssignee,
266293
- requireAllLabels,
266449
+ ...scope,
266294
266450
  include: bucket.indicator.filter,
266295
266451
  exclude: bucket.exclude,
266296
266452
  ...ticketNumbers.length > 0 ? { numbers: ticketNumbers } : {}
@@ -266343,13 +266499,13 @@ function backlogRankByIssueId(issues) {
266343
266499
  ordered.forEach((o, i) => rankById.set(o.id, i));
266344
266500
  return rankById;
266345
266501
  }
266346
- async function fetchAndPrintLinear(apiKey, buckets, team, assignee, anyAssignee, requireAllLabels, cwd2, runner, ignoreCiChecks = [], checks3 = false, review = false, ticketNumbers = []) {
266502
+ async function fetchAndPrintLinear(apiKey, buckets, team, assignee, anyAssignee, scope, cwd2, runner, ignoreCiChecks = [], checks3 = false, review = false, ticketNumbers = []) {
266347
266503
  const bucketResults = await Promise.all(buckets.map(async (bucket) => {
266348
266504
  if (!bucket.indicator || bucket.indicator.filter.length === 0) {
266349
266505
  return { bucket, issues: [], error: null };
266350
266506
  }
266351
266507
  try {
266352
- const issues = await fetchBucketIssues(apiKey, bucket, team, assignee, anyAssignee, requireAllLabels, ticketNumbers);
266508
+ const issues = await fetchBucketIssues(apiKey, bucket, team, assignee, anyAssignee, scope, ticketNumbers);
266353
266509
  return { bucket, issues, error: null };
266354
266510
  } catch (err) {
266355
266511
  return {
@@ -266485,7 +266641,9 @@ async function runList(input) {
266485
266641
  const apiKey = process.env["LINEAR_API_KEY"];
266486
266642
  const indicators = cfg.linear.indicators;
266487
266643
  const team = input.linearTeamOverride || cfg.linear.team;
266488
- const { assignee, anyAssignee, requireAllLabels } = resolveLinearFilter(applyAssigneeOverride(cfg.linear.filter, input.linearAssigneeOverride));
266644
+ const resolved = resolveLinearFilter(applyAssigneeOverride(cfg.linear.filter, input.linearAssigneeOverride));
266645
+ const { assignee, anyAssignee } = resolved;
266646
+ const scope = linearFilterScope(resolved);
266489
266647
  const buckets = buildBuckets(indicators);
266490
266648
  const anyConfigured = buckets.some((b2) => b2.indicator && b2.indicator.filter.length > 0);
266491
266649
  if (!anyConfigured) {
@@ -266525,7 +266683,7 @@ team: ${team}
266525
266683
  if (ticketNumbers.length > 0)
266526
266684
  process.stdout.write(`ticket: ${ticketNumbers.join(", ")}
266527
266685
  `);
266528
- await fetchAndPrintLinear(apiKey, buckets, team, assignee, anyAssignee, requireAllLabels, projectRoot, localCmdRunner, cfg.prRecovery.ignoreChecks, input.checks, input.review, ticketNumbers);
266686
+ await fetchAndPrintLinear(apiKey, buckets, team, assignee, anyAssignee, scope, projectRoot, localCmdRunner, cfg.prRecovery.ignoreChecks, input.checks, input.review, ticketNumbers);
266529
266687
  }
266530
266688
  function normalizeIdentifier(input) {
266531
266689
  let parsed;
@@ -266608,7 +266766,7 @@ async function runListDebug(input) {
266608
266766
  const cfg = await loadRalphyConfig(projectRoot, getArgs().workflowFile);
266609
266767
  const indicators = cfg.linear.indicators;
266610
266768
  const team = input.linearTeamOverride || cfg.linear.team;
266611
- const { assignee, anyAssignee, requireAllLabels } = resolveLinearFilter(applyAssigneeOverride(cfg.linear.filter, input.linearAssigneeOverride));
266769
+ const { assignee, anyAssignee, requireAllLabels, excludeLabels } = resolveLinearFilter(applyAssigneeOverride(cfg.linear.filter, input.linearAssigneeOverride));
266612
266770
  const assigneeLabel = anyAssignee ? "any" : assignee ?? "*";
266613
266771
  const normalized = normalizeIdentifier(identifier);
266614
266772
  if (!normalized) {
@@ -266659,6 +266817,13 @@ Per-bucket diagnostics:
266659
266817
  reasons.push(`missing required linear.filter label(s): ${missing.join(", ")}`);
266660
266818
  }
266661
266819
  }
266820
+ if (excludeLabels && excludeLabels.length > 0) {
266821
+ const issueLabels = new Set(issue2.labels.nodes.map((l3) => l3.name));
266822
+ const present = excludeLabels.filter((label) => issueLabels.has(label));
266823
+ if (present.length > 0) {
266824
+ reasons.push(`carries excluded linear.filter label(s): ${present.join(", ")}`);
266825
+ }
266826
+ }
266662
266827
  const includeMatches = bucket.indicator.filter.some((m2) => markerMatches(issue2, m2));
266663
266828
  if (!includeMatches) {
266664
266829
  const want = bucket.indicator.filter.map((m2) => `${m2.type}:${m2.value}`).join(" OR ");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neriros/ralphy",
3
- "version": "3.10.18",
3
+ "version": "3.10.20",
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",