@neriros/ralphy 3.10.17 → 3.10.19
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/dist/shell/index.js +1585 -1175
- package/package.json +2 -1
package/dist/shell/index.js
CHANGED
|
@@ -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.
|
|
18932
|
-
return "3.10.
|
|
18931
|
+
if ("3.10.19")
|
|
18932
|
+
return "3.10.19";
|
|
18933
18933
|
} catch {}
|
|
18934
18934
|
const dirsToTry = [];
|
|
18935
18935
|
try {
|
|
@@ -19655,8 +19655,8 @@ var init_fields = __esm(() => {
|
|
|
19655
19655
|
},
|
|
19656
19656
|
{
|
|
19657
19657
|
id: "setupScript",
|
|
19658
|
-
label: "Worktree setup script (runs
|
|
19659
|
-
description: "Part of the worktree flow: a shell script run once
|
|
19658
|
+
label: "Worktree setup script (runs once per worktree)",
|
|
19659
|
+
description: "Part of the worktree flow: a shell script run once when a task's worktree is first created \u2014 e.g. to install dependencies in the new working copy. It does NOT re-run on resume, conflict-fix, ci-fix, or review re-runs that reuse an existing worktree.",
|
|
19660
19660
|
spec: { kind: "text" },
|
|
19661
19661
|
when: worktreeEnabled
|
|
19662
19662
|
},
|
|
@@ -19699,6 +19699,13 @@ var init_fields = __esm(() => {
|
|
|
19699
19699
|
spec: { kind: "text", placeholder: "main" },
|
|
19700
19700
|
when: isOn("createPrOnSuccess")
|
|
19701
19701
|
},
|
|
19702
|
+
{
|
|
19703
|
+
id: "prLabels",
|
|
19704
|
+
label: "PR labels",
|
|
19705
|
+
description: "GitHub labels attached to every pull request Ralph opens. The labels must already exist in the repo; a missing one is skipped, never fatal. One label per entry.",
|
|
19706
|
+
spec: { kind: "list", placeholder: "ralph" },
|
|
19707
|
+
when: isOn("createPrOnSuccess")
|
|
19708
|
+
},
|
|
19702
19709
|
{
|
|
19703
19710
|
id: "stackPrsOnDependencies",
|
|
19704
19711
|
label: "Stack dependent issues' PRs onto their blocker's PR?",
|
|
@@ -81301,6 +81308,20 @@ var init_zod = __esm(() => {
|
|
|
81301
81308
|
});
|
|
81302
81309
|
|
|
81303
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
|
+
}
|
|
81304
81325
|
function foldLegacyAssignee(v) {
|
|
81305
81326
|
if (!v || typeof v !== "object" || Array.isArray(v))
|
|
81306
81327
|
return v;
|
|
@@ -81315,24 +81336,42 @@ function foldLegacyAssignee(v) {
|
|
|
81315
81336
|
}
|
|
81316
81337
|
return rest2;
|
|
81317
81338
|
}
|
|
81318
|
-
var CURRENT_WORKFLOW_VERSION =
|
|
81339
|
+
var CURRENT_WORKFLOW_VERSION = 8, MarkerSchema, FilterMarkerSchema, LinearFilterSchema, SET_INDICATOR_KEYS, GetIndicatorSchema, SetIndicatorSchema, IndicatorsSchema, ProjectSchema, CommandsSchema, DEFAULT_META_ONLY_FILES, BoundariesSchema, WorkflowConfigSchema;
|
|
81319
81340
|
var init_schema = __esm(() => {
|
|
81320
81341
|
init_zod();
|
|
81321
|
-
MarkerSchema = exports_external.discriminatedUnion("type", [
|
|
81342
|
+
MarkerSchema = exports_external.preprocess(normalizeNegationShorthand, exports_external.discriminatedUnion("type", [
|
|
81322
81343
|
exports_external.object({
|
|
81323
81344
|
type: exports_external.literal("label"),
|
|
81324
81345
|
value: exports_external.string().min(1),
|
|
81325
|
-
group: exports_external.string().min(1).optional()
|
|
81346
|
+
group: exports_external.string().min(1).optional(),
|
|
81347
|
+
negate: exports_external.boolean().optional()
|
|
81326
81348
|
}),
|
|
81327
|
-
exports_external.object({
|
|
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(),
|
|
81328
81354
|
exports_external.object({ type: exports_external.literal("attachment"), value: exports_external.string().min(1) }).strict(),
|
|
81329
|
-
exports_external.object({
|
|
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(),
|
|
81330
81360
|
exports_external.object({ type: exports_external.literal("comment"), value: exports_external.string().min(1) }).strict()
|
|
81331
|
-
]);
|
|
81332
|
-
FilterMarkerSchema = exports_external.discriminatedUnion("type", [
|
|
81333
|
-
exports_external.object({
|
|
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(),
|
|
81334
81373
|
exports_external.object({ type: exports_external.literal("assignee"), value: exports_external.string().min(1) }).strict()
|
|
81335
|
-
]);
|
|
81374
|
+
]));
|
|
81336
81375
|
LinearFilterSchema = exports_external.array(FilterMarkerSchema).superRefine((markers, ctx) => {
|
|
81337
81376
|
const assigneeCount = markers.filter((m) => m.type === "assignee").length;
|
|
81338
81377
|
if (assigneeCount > 1) {
|
|
@@ -81341,6 +81380,13 @@ var init_schema = __esm(() => {
|
|
|
81341
81380
|
message: `linear.filter allows at most one "assignee" clause, found ${assigneeCount}.`
|
|
81342
81381
|
});
|
|
81343
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
|
+
}
|
|
81344
81390
|
}).default([{ type: "assignee", value: "me" }]);
|
|
81345
81391
|
SET_INDICATOR_KEYS = [
|
|
81346
81392
|
"setInProgress",
|
|
@@ -81374,6 +81420,14 @@ var init_schema = __esm(() => {
|
|
|
81374
81420
|
continue;
|
|
81375
81421
|
const markers = Array.isArray(clear) ? clear : [clear];
|
|
81376
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
|
+
}
|
|
81377
81431
|
if (m.type === "comment")
|
|
81378
81432
|
continue;
|
|
81379
81433
|
if (m.type !== "label") {
|
|
@@ -81392,6 +81446,14 @@ var init_schema = __esm(() => {
|
|
|
81392
81446
|
continue;
|
|
81393
81447
|
const markers = Array.isArray(set3) ? set3 : [set3];
|
|
81394
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
|
+
}
|
|
81395
81457
|
if (m.type === "comment") {
|
|
81396
81458
|
ctx.addIssue({
|
|
81397
81459
|
code: exports_external.ZodIssueCode.custom,
|
|
@@ -81455,6 +81517,7 @@ var init_schema = __esm(() => {
|
|
|
81455
81517
|
createPrOnSuccess: exports_external.boolean().default(false),
|
|
81456
81518
|
prDraft: exports_external.boolean().default(false),
|
|
81457
81519
|
prBaseBranch: exports_external.string().default("main"),
|
|
81520
|
+
prLabels: exports_external.array(exports_external.string()).default([]),
|
|
81458
81521
|
stackPrsOnDependencies: exports_external.boolean().default(false),
|
|
81459
81522
|
autoMergeStrategy: exports_external.enum(["squash", "merge", "rebase"]).default("squash"),
|
|
81460
81523
|
manualMergeWhenAutoMergeDisabled: exports_external.boolean().default(true),
|
|
@@ -81509,6 +81572,7 @@ var init_schema = __esm(() => {
|
|
|
81509
81572
|
github: exports_external.object({
|
|
81510
81573
|
base_branch: exports_external.string().optional(),
|
|
81511
81574
|
auto_merge_strategy: exports_external.enum(["squash", "merge", "rebase"]).optional(),
|
|
81575
|
+
pr_labels: exports_external.array(exports_external.string()).optional(),
|
|
81512
81576
|
issues: exports_external.object({
|
|
81513
81577
|
repo: exports_external.string().optional(),
|
|
81514
81578
|
label: exports_external.string().optional(),
|
|
@@ -81591,7 +81655,7 @@ var init_schema = __esm(() => {
|
|
|
81591
81655
|
var FRONTMATTER_RE, DEFAULT_WORKFLOW_MD = `---
|
|
81592
81656
|
# WORKFLOW.md schema version \u2014 managed by \`ralphy init\`. When a newer version
|
|
81593
81657
|
# ships, re-running init migrates this file and fills in the new settings.
|
|
81594
|
-
version:
|
|
81658
|
+
version: 8
|
|
81595
81659
|
|
|
81596
81660
|
project:
|
|
81597
81661
|
name: ralphy
|
|
@@ -81643,6 +81707,11 @@ prDraft: true
|
|
|
81643
81707
|
prBaseBranch: main
|
|
81644
81708
|
stackPrsOnDependencies: false
|
|
81645
81709
|
autoMergeStrategy: squash
|
|
81710
|
+
# Labels attached to every PR Ralph opens (best-effort \u2014 a missing label is
|
|
81711
|
+
# logged, never fatal). The labels must already exist in the repo.
|
|
81712
|
+
# prLabels:
|
|
81713
|
+
# - ralph
|
|
81714
|
+
# - automated
|
|
81646
81715
|
|
|
81647
81716
|
prRecovery:
|
|
81648
81717
|
enabled: true
|
|
@@ -82247,34 +82316,64 @@ function describeApprovalMarker(indicator) {
|
|
|
82247
82316
|
}
|
|
82248
82317
|
|
|
82249
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
|
+
}
|
|
82250
82329
|
function resolveLinearFilter(filter2) {
|
|
82251
82330
|
const assigneeClauses = filter2.filter((marker) => marker.type === "assignee");
|
|
82252
82331
|
if (assigneeClauses.length > 1) {
|
|
82253
82332
|
throw new Error(`Invalid linear.filter: at most one "assignee" clause is allowed, found ${assigneeClauses.length}.`);
|
|
82254
82333
|
}
|
|
82255
|
-
const requireAllLabels =
|
|
82256
|
-
const
|
|
82257
|
-
|
|
82258
|
-
|
|
82259
|
-
|
|
82260
|
-
|
|
82261
|
-
|
|
82262
|
-
|
|
82263
|
-
|
|
82264
|
-
|
|
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 };
|
|
82265
82349
|
const assigneeClause = assigneeClauses[0];
|
|
82266
82350
|
if (!assigneeClause)
|
|
82267
|
-
return
|
|
82351
|
+
return base2;
|
|
82268
82352
|
const value = assigneeClause.value.trim();
|
|
82269
82353
|
const lower = value.toLowerCase();
|
|
82270
82354
|
if (lower === "any")
|
|
82271
|
-
return { anyAssignee: true,
|
|
82355
|
+
return { anyAssignee: true, ...base2 };
|
|
82272
82356
|
if (lower === "" || lower === "unassigned") {
|
|
82273
|
-
return { assignee: "unassigned",
|
|
82357
|
+
return { assignee: "unassigned", ...base2 };
|
|
82274
82358
|
}
|
|
82275
82359
|
if (lower === "me")
|
|
82276
|
-
return { assignee: "me",
|
|
82277
|
-
return { assignee: value,
|
|
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;
|
|
82278
82377
|
}
|
|
82279
82378
|
function applyAssigneeOverride(filter2, assignee) {
|
|
82280
82379
|
const trimmed = assignee.trim();
|
|
@@ -82301,6 +82400,7 @@ __export(exports_workflow, {
|
|
|
82301
82400
|
migrateWorkflowMarkdown: () => migrateWorkflowMarkdown,
|
|
82302
82401
|
matchesIndicator: () => matchesIndicator,
|
|
82303
82402
|
loadWorkflow: () => loadWorkflow,
|
|
82403
|
+
linearFilterScope: () => linearFilterScope,
|
|
82304
82404
|
ensureWorkflow: () => ensureWorkflow,
|
|
82305
82405
|
describeApprovalMarker: () => describeApprovalMarker,
|
|
82306
82406
|
computeConfirmationFlags: () => computeConfirmationFlags,
|
|
@@ -82375,6 +82475,9 @@ function applyAliases(cfg) {
|
|
|
82375
82475
|
if (cfg.github.auto_merge_strategy !== undefined && cfg.autoMergeStrategy === "squash") {
|
|
82376
82476
|
cfg.autoMergeStrategy = cfg.github.auto_merge_strategy;
|
|
82377
82477
|
}
|
|
82478
|
+
if (cfg.github.pr_labels !== undefined && cfg.prLabels.length === 0) {
|
|
82479
|
+
cfg.prLabels = cfg.github.pr_labels;
|
|
82480
|
+
}
|
|
82378
82481
|
}
|
|
82379
82482
|
if (cfg.agent) {
|
|
82380
82483
|
if (cfg.agent.engine !== undefined)
|
|
@@ -84691,6 +84794,11 @@ var init_migrations = __esm(() => {
|
|
|
84691
84794
|
"github.issues.statusLabels.done",
|
|
84692
84795
|
"github.issues.statusLabels.error"
|
|
84693
84796
|
]
|
|
84797
|
+
},
|
|
84798
|
+
{
|
|
84799
|
+
version: 8,
|
|
84800
|
+
description: "Pull requests Ralph opens can now carry GitHub labels via `prLabels`. " + "List the labels to attach to every PR (they must already exist in the " + "repo; a missing label is skipped, never fatal). Only asked when " + "PR-creation is enabled \u2014 leave empty to attach no labels.",
|
|
84801
|
+
fields: ["prLabels"]
|
|
84694
84802
|
}
|
|
84695
84803
|
];
|
|
84696
84804
|
LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max2, migration) => Math.max(max2, migration.version), 0);
|
|
@@ -85262,7 +85370,7 @@ function projectLayout(root) {
|
|
|
85262
85370
|
stateFile: (name) => join7(statesDir, name, STATE_FILE)
|
|
85263
85371
|
};
|
|
85264
85372
|
}
|
|
85265
|
-
var STATE_FILE = ".ralph-state.json"
|
|
85373
|
+
var STATE_FILE = ".ralph-state.json";
|
|
85266
85374
|
var init_layout = __esm(() => {
|
|
85267
85375
|
init_context();
|
|
85268
85376
|
});
|
|
@@ -99729,6 +99837,39 @@ var init_example_machine = __esm(() => {
|
|
|
99729
99837
|
});
|
|
99730
99838
|
|
|
99731
99839
|
// packages/core/src/machines/flow.machine.ts
|
|
99840
|
+
function recordDetection(reason) {
|
|
99841
|
+
return ({
|
|
99842
|
+
context,
|
|
99843
|
+
event
|
|
99844
|
+
}) => {
|
|
99845
|
+
const previous = context.data.recovery;
|
|
99846
|
+
return {
|
|
99847
|
+
data: {
|
|
99848
|
+
...context.data,
|
|
99849
|
+
recovery: {
|
|
99850
|
+
attempts: (previous?.attempts ?? 0) + 1,
|
|
99851
|
+
lastReason: reason,
|
|
99852
|
+
firstFailedAt: previous?.firstFailedAt ?? event.at ?? ""
|
|
99853
|
+
}
|
|
99854
|
+
}
|
|
99855
|
+
};
|
|
99856
|
+
};
|
|
99857
|
+
}
|
|
99858
|
+
function reachesQuarantine({ context }) {
|
|
99859
|
+
const max2 = context.data.maxRecoveryAttempts;
|
|
99860
|
+
return max2 > 0 && (context.data.recovery?.attempts ?? 0) + 1 >= max2;
|
|
99861
|
+
}
|
|
99862
|
+
function refreshReason(reason) {
|
|
99863
|
+
return ({ context }) => ({
|
|
99864
|
+
data: {
|
|
99865
|
+
...context.data,
|
|
99866
|
+
recovery: context.data.recovery ? { ...context.data.recovery, lastReason: reason } : { attempts: 0, lastReason: reason, firstFailedAt: "" }
|
|
99867
|
+
}
|
|
99868
|
+
});
|
|
99869
|
+
}
|
|
99870
|
+
function clearRecovery({ context }) {
|
|
99871
|
+
return { data: { ...context.data, recovery: undefined } };
|
|
99872
|
+
}
|
|
99732
99873
|
var preemptionActorLogic, flowMachine;
|
|
99733
99874
|
var init_flow_machine = __esm(() => {
|
|
99734
99875
|
init_xstate_development_cjs();
|
|
@@ -99775,14 +99916,20 @@ var init_flow_machine = __esm(() => {
|
|
|
99775
99916
|
}).createMachine({
|
|
99776
99917
|
id: "flow",
|
|
99777
99918
|
context: ({ input }) => ({
|
|
99778
|
-
|
|
99779
|
-
|
|
99780
|
-
|
|
99781
|
-
|
|
99782
|
-
|
|
99783
|
-
|
|
99784
|
-
|
|
99785
|
-
|
|
99919
|
+
data: {
|
|
99920
|
+
issueId: input?.issueId ?? "",
|
|
99921
|
+
graceMs: input?.graceMs ?? 5000,
|
|
99922
|
+
maxRecoveryAttempts: input?.maxRecoveryAttempts ?? 0,
|
|
99923
|
+
currentAssignment: undefined,
|
|
99924
|
+
pendingAssignment: undefined,
|
|
99925
|
+
recovery: undefined
|
|
99926
|
+
},
|
|
99927
|
+
runtime: {
|
|
99928
|
+
bus: input?.bus ?? createNoopBus(),
|
|
99929
|
+
persist: input?.persist ?? (() => {}),
|
|
99930
|
+
worker: undefined,
|
|
99931
|
+
teardown: undefined
|
|
99932
|
+
}
|
|
99786
99933
|
}),
|
|
99787
99934
|
initial: "idle",
|
|
99788
99935
|
states: {
|
|
@@ -99791,29 +99938,63 @@ var init_flow_machine = __esm(() => {
|
|
|
99791
99938
|
FRESH_PICKED_UP: "working",
|
|
99792
99939
|
RESUME_DETECTED: "working",
|
|
99793
99940
|
REVIEW_TRIGGERED: "review",
|
|
99794
|
-
CONFLICT_DETECTED:
|
|
99795
|
-
|
|
99941
|
+
CONFLICT_DETECTED: [
|
|
99942
|
+
{
|
|
99943
|
+
guard: reachesQuarantine,
|
|
99944
|
+
target: "quarantined",
|
|
99945
|
+
actions: import_xstate_development_cjs.assign(recordDetection("conflicting"))
|
|
99946
|
+
},
|
|
99947
|
+
{ target: "conflict-fix", actions: import_xstate_development_cjs.assign(recordDetection("conflicting")) }
|
|
99948
|
+
],
|
|
99949
|
+
CI_FAILED_DETECTED: [
|
|
99950
|
+
{
|
|
99951
|
+
guard: reachesQuarantine,
|
|
99952
|
+
target: "quarantined",
|
|
99953
|
+
actions: import_xstate_development_cjs.assign(recordDetection("ci_failed"))
|
|
99954
|
+
},
|
|
99955
|
+
{ target: "ci-fix", actions: import_xstate_development_cjs.assign(recordDetection("ci_failed")) }
|
|
99956
|
+
]
|
|
99796
99957
|
}
|
|
99797
99958
|
},
|
|
99798
99959
|
working: {
|
|
99799
99960
|
on: {
|
|
99800
99961
|
AWAITING_DETECTED: "awaiting",
|
|
99801
|
-
CONFLICT_DETECTED:
|
|
99802
|
-
|
|
99962
|
+
CONFLICT_DETECTED: [
|
|
99963
|
+
{
|
|
99964
|
+
guard: reachesQuarantine,
|
|
99965
|
+
target: "quarantined",
|
|
99966
|
+
actions: import_xstate_development_cjs.assign(recordDetection("conflicting"))
|
|
99967
|
+
},
|
|
99968
|
+
{ target: "conflict-fix", actions: import_xstate_development_cjs.assign(recordDetection("conflicting")) }
|
|
99969
|
+
],
|
|
99970
|
+
CI_FAILED_DETECTED: [
|
|
99971
|
+
{
|
|
99972
|
+
guard: reachesQuarantine,
|
|
99973
|
+
target: "quarantined",
|
|
99974
|
+
actions: import_xstate_development_cjs.assign(recordDetection("ci_failed"))
|
|
99975
|
+
},
|
|
99976
|
+
{ target: "ci-fix", actions: import_xstate_development_cjs.assign(recordDetection("ci_failed")) }
|
|
99977
|
+
],
|
|
99803
99978
|
PR_OPENED: "awaiting-ci",
|
|
99804
99979
|
WORKER_SUCCEEDED: "done",
|
|
99805
99980
|
WORKER_FAILED: "error",
|
|
99806
99981
|
PREEMPT: {
|
|
99807
99982
|
target: "preempting",
|
|
99808
99983
|
actions: import_xstate_development_cjs.assign({
|
|
99809
|
-
|
|
99984
|
+
data: ({ context, event }) => ({
|
|
99985
|
+
...context.data,
|
|
99986
|
+
pendingAssignment: event.newAssignment
|
|
99987
|
+
})
|
|
99810
99988
|
})
|
|
99811
99989
|
},
|
|
99812
99990
|
WORKER_SPAWNED: {
|
|
99813
|
-
actions: import_xstate_development_cjs.assign(({ event }) => ({
|
|
99814
|
-
|
|
99815
|
-
|
|
99816
|
-
|
|
99991
|
+
actions: import_xstate_development_cjs.assign(({ context, event }) => ({
|
|
99992
|
+
data: { ...context.data, currentAssignment: event.assignment },
|
|
99993
|
+
runtime: {
|
|
99994
|
+
...context.runtime,
|
|
99995
|
+
worker: event.worker,
|
|
99996
|
+
teardown: event.teardown ?? undefined
|
|
99997
|
+
}
|
|
99817
99998
|
}))
|
|
99818
99999
|
}
|
|
99819
100000
|
}
|
|
@@ -99825,14 +100006,20 @@ var init_flow_machine = __esm(() => {
|
|
|
99825
100006
|
PREEMPT: {
|
|
99826
100007
|
target: "preempting",
|
|
99827
100008
|
actions: import_xstate_development_cjs.assign({
|
|
99828
|
-
|
|
100009
|
+
data: ({ context, event }) => ({
|
|
100010
|
+
...context.data,
|
|
100011
|
+
pendingAssignment: event.newAssignment
|
|
100012
|
+
})
|
|
99829
100013
|
})
|
|
99830
100014
|
},
|
|
99831
100015
|
WORKER_SPAWNED: {
|
|
99832
|
-
actions: import_xstate_development_cjs.assign(({ event }) => ({
|
|
99833
|
-
|
|
99834
|
-
|
|
99835
|
-
|
|
100016
|
+
actions: import_xstate_development_cjs.assign(({ context, event }) => ({
|
|
100017
|
+
data: { ...context.data, currentAssignment: event.assignment },
|
|
100018
|
+
runtime: {
|
|
100019
|
+
...context.runtime,
|
|
100020
|
+
worker: event.worker,
|
|
100021
|
+
teardown: event.teardown ?? undefined
|
|
100022
|
+
}
|
|
99836
100023
|
}))
|
|
99837
100024
|
}
|
|
99838
100025
|
}
|
|
@@ -99844,14 +100031,20 @@ var init_flow_machine = __esm(() => {
|
|
|
99844
100031
|
PREEMPT: {
|
|
99845
100032
|
target: "preempting",
|
|
99846
100033
|
actions: import_xstate_development_cjs.assign({
|
|
99847
|
-
|
|
100034
|
+
data: ({ context, event }) => ({
|
|
100035
|
+
...context.data,
|
|
100036
|
+
pendingAssignment: event.newAssignment
|
|
100037
|
+
})
|
|
99848
100038
|
})
|
|
99849
100039
|
},
|
|
99850
100040
|
WORKER_SPAWNED: {
|
|
99851
|
-
actions: import_xstate_development_cjs.assign(({ event }) => ({
|
|
99852
|
-
|
|
99853
|
-
|
|
99854
|
-
|
|
100041
|
+
actions: import_xstate_development_cjs.assign(({ context, event }) => ({
|
|
100042
|
+
data: { ...context.data, currentAssignment: event.assignment },
|
|
100043
|
+
runtime: {
|
|
100044
|
+
...context.runtime,
|
|
100045
|
+
worker: event.worker,
|
|
100046
|
+
teardown: event.teardown ?? undefined
|
|
100047
|
+
}
|
|
99855
100048
|
}))
|
|
99856
100049
|
}
|
|
99857
100050
|
}
|
|
@@ -99862,7 +100055,10 @@ var init_flow_machine = __esm(() => {
|
|
|
99862
100055
|
PREEMPT: {
|
|
99863
100056
|
target: "preempting",
|
|
99864
100057
|
actions: import_xstate_development_cjs.assign({
|
|
99865
|
-
|
|
100058
|
+
data: ({ context, event }) => ({
|
|
100059
|
+
...context.data,
|
|
100060
|
+
pendingAssignment: event.newAssignment
|
|
100061
|
+
})
|
|
99866
100062
|
})
|
|
99867
100063
|
}
|
|
99868
100064
|
}
|
|
@@ -99870,20 +100066,41 @@ var init_flow_machine = __esm(() => {
|
|
|
99870
100066
|
"awaiting-ci": {
|
|
99871
100067
|
on: {
|
|
99872
100068
|
PR_PASSED: "done",
|
|
99873
|
-
|
|
99874
|
-
|
|
100069
|
+
RECOVERY_CLEARED: { actions: import_xstate_development_cjs.assign(clearRecovery) },
|
|
100070
|
+
CONFLICT_DETECTED: [
|
|
100071
|
+
{
|
|
100072
|
+
guard: reachesQuarantine,
|
|
100073
|
+
target: "quarantined",
|
|
100074
|
+
actions: import_xstate_development_cjs.assign(recordDetection("conflicting"))
|
|
100075
|
+
},
|
|
100076
|
+
{ target: "conflict-fix", actions: import_xstate_development_cjs.assign(recordDetection("conflicting")) }
|
|
100077
|
+
],
|
|
100078
|
+
CI_FAILED_DETECTED: [
|
|
100079
|
+
{
|
|
100080
|
+
guard: reachesQuarantine,
|
|
100081
|
+
target: "quarantined",
|
|
100082
|
+
actions: import_xstate_development_cjs.assign(recordDetection("ci_failed"))
|
|
100083
|
+
},
|
|
100084
|
+
{ target: "ci-fix", actions: import_xstate_development_cjs.assign(recordDetection("ci_failed")) }
|
|
100085
|
+
],
|
|
99875
100086
|
REVIEW_TRIGGERED: "review",
|
|
99876
100087
|
PREEMPT: {
|
|
99877
100088
|
target: "preempting",
|
|
99878
100089
|
actions: import_xstate_development_cjs.assign({
|
|
99879
|
-
|
|
100090
|
+
data: ({ context, event }) => ({
|
|
100091
|
+
...context.data,
|
|
100092
|
+
pendingAssignment: event.newAssignment
|
|
100093
|
+
})
|
|
99880
100094
|
})
|
|
99881
100095
|
},
|
|
99882
100096
|
WORKER_SPAWNED: {
|
|
99883
|
-
actions: import_xstate_development_cjs.assign(({ event }) => ({
|
|
99884
|
-
|
|
99885
|
-
|
|
99886
|
-
|
|
100097
|
+
actions: import_xstate_development_cjs.assign(({ context, event }) => ({
|
|
100098
|
+
data: { ...context.data, currentAssignment: event.assignment },
|
|
100099
|
+
runtime: {
|
|
100100
|
+
...context.runtime,
|
|
100101
|
+
worker: event.worker,
|
|
100102
|
+
teardown: event.teardown ?? undefined
|
|
100103
|
+
}
|
|
99887
100104
|
}))
|
|
99888
100105
|
}
|
|
99889
100106
|
}
|
|
@@ -99894,10 +100111,13 @@ var init_flow_machine = __esm(() => {
|
|
|
99894
100111
|
PR_OPENED: "awaiting-ci",
|
|
99895
100112
|
WORKER_FAILED: "error",
|
|
99896
100113
|
WORKER_SPAWNED: {
|
|
99897
|
-
actions: import_xstate_development_cjs.assign(({ event }) => ({
|
|
99898
|
-
|
|
99899
|
-
|
|
99900
|
-
|
|
100114
|
+
actions: import_xstate_development_cjs.assign(({ context, event }) => ({
|
|
100115
|
+
data: { ...context.data, currentAssignment: event.assignment },
|
|
100116
|
+
runtime: {
|
|
100117
|
+
...context.runtime,
|
|
100118
|
+
worker: event.worker,
|
|
100119
|
+
teardown: event.teardown ?? undefined
|
|
100120
|
+
}
|
|
99901
100121
|
}))
|
|
99902
100122
|
}
|
|
99903
100123
|
}
|
|
@@ -99906,20 +100126,19 @@ var init_flow_machine = __esm(() => {
|
|
|
99906
100126
|
invoke: {
|
|
99907
100127
|
src: "preemption",
|
|
99908
100128
|
input: ({ context }) => ({
|
|
99909
|
-
graceMs: context.graceMs,
|
|
99910
|
-
bus: context.bus,
|
|
99911
|
-
persist: context.persist,
|
|
99912
|
-
issueId: context.issueId,
|
|
99913
|
-
newAssignment: context.pendingAssignment,
|
|
99914
|
-
...context.currentAssignment !== undefined ? { from: context.currentAssignment.flowId } : {},
|
|
99915
|
-
...context.worker !== undefined ? { worker: context.worker } : {},
|
|
99916
|
-
...context.teardown !== undefined ? { teardown: context.teardown } : {}
|
|
100129
|
+
graceMs: context.data.graceMs,
|
|
100130
|
+
bus: context.runtime.bus,
|
|
100131
|
+
persist: context.runtime.persist,
|
|
100132
|
+
issueId: context.data.issueId,
|
|
100133
|
+
newAssignment: context.data.pendingAssignment,
|
|
100134
|
+
...context.data.currentAssignment !== undefined ? { from: context.data.currentAssignment.flowId } : {},
|
|
100135
|
+
...context.runtime.worker !== undefined ? { worker: context.runtime.worker } : {},
|
|
100136
|
+
...context.runtime.teardown !== undefined ? { teardown: context.runtime.teardown } : {}
|
|
99917
100137
|
}),
|
|
99918
100138
|
onDone: {
|
|
99919
100139
|
actions: import_xstate_development_cjs.assign(({ context }) => ({
|
|
99920
|
-
|
|
99921
|
-
teardown: undefined
|
|
99922
|
-
currentAssignment: context.pendingAssignment
|
|
100140
|
+
data: { ...context.data, currentAssignment: context.data.pendingAssignment },
|
|
100141
|
+
runtime: { ...context.runtime, worker: undefined, teardown: undefined }
|
|
99923
100142
|
})),
|
|
99924
100143
|
target: "routing-after-preempt"
|
|
99925
100144
|
},
|
|
@@ -99929,32 +100148,40 @@ var init_flow_machine = __esm(() => {
|
|
|
99929
100148
|
"routing-after-preempt": {
|
|
99930
100149
|
always: [
|
|
99931
100150
|
{
|
|
99932
|
-
guard: ({ context }) => context.pendingAssignment?.flowId === "conflict-fix",
|
|
100151
|
+
guard: ({ context }) => context.data.pendingAssignment?.flowId === "conflict-fix",
|
|
99933
100152
|
target: "conflict-fix"
|
|
99934
100153
|
},
|
|
99935
100154
|
{
|
|
99936
|
-
guard: ({ context }) => context.pendingAssignment?.flowId === "ci-fix",
|
|
100155
|
+
guard: ({ context }) => context.data.pendingAssignment?.flowId === "ci-fix",
|
|
99937
100156
|
target: "ci-fix"
|
|
99938
100157
|
},
|
|
99939
100158
|
{
|
|
99940
|
-
guard: ({ context }) => context.pendingAssignment?.flowId === "awaiting-ci",
|
|
100159
|
+
guard: ({ context }) => context.data.pendingAssignment?.flowId === "awaiting-ci",
|
|
99941
100160
|
target: "awaiting-ci"
|
|
99942
100161
|
},
|
|
99943
100162
|
{
|
|
99944
|
-
guard: ({ context }) => context.pendingAssignment?.flowId === "confirmation",
|
|
100163
|
+
guard: ({ context }) => context.data.pendingAssignment?.flowId === "confirmation",
|
|
99945
100164
|
target: "awaiting"
|
|
99946
100165
|
},
|
|
99947
100166
|
{
|
|
99948
|
-
guard: ({ context }) => context.pendingAssignment?.flowId === "review-followup",
|
|
100167
|
+
guard: ({ context }) => context.data.pendingAssignment?.flowId === "review-followup",
|
|
99949
100168
|
target: "review"
|
|
99950
100169
|
},
|
|
99951
100170
|
{
|
|
99952
|
-
guard: ({ context }) => context.pendingAssignment?.flowId === "idle",
|
|
100171
|
+
guard: ({ context }) => context.data.pendingAssignment?.flowId === "idle",
|
|
99953
100172
|
target: "idle"
|
|
99954
100173
|
},
|
|
99955
100174
|
{ target: "working" }
|
|
99956
100175
|
]
|
|
99957
100176
|
},
|
|
100177
|
+
quarantined: {
|
|
100178
|
+
on: {
|
|
100179
|
+
PR_PASSED: "done",
|
|
100180
|
+
QUARANTINE_CLEARED: { target: "idle", actions: import_xstate_development_cjs.assign(clearRecovery) },
|
|
100181
|
+
CONFLICT_DETECTED: { actions: import_xstate_development_cjs.assign(refreshReason("conflicting")) },
|
|
100182
|
+
CI_FAILED_DETECTED: { actions: import_xstate_development_cjs.assign(refreshReason("ci_failed")) }
|
|
100183
|
+
}
|
|
100184
|
+
},
|
|
99958
100185
|
done: {
|
|
99959
100186
|
type: "final"
|
|
99960
100187
|
},
|
|
@@ -99983,17 +100210,22 @@ class FlowActorStore {
|
|
|
99983
100210
|
...this.deps ? {
|
|
99984
100211
|
bus: this.deps.bus,
|
|
99985
100212
|
persist: this.deps.persist,
|
|
99986
|
-
...this.deps.graceMs !== undefined ? { graceMs: this.deps.graceMs } : {}
|
|
100213
|
+
...this.deps.graceMs !== undefined ? { graceMs: this.deps.graceMs } : {},
|
|
100214
|
+
...this.deps.maxRecoveryAttempts !== undefined ? { maxRecoveryAttempts: this.deps.maxRecoveryAttempts } : {}
|
|
99987
100215
|
} : {}
|
|
99988
100216
|
};
|
|
100217
|
+
const inspector = this.deps?.onTransition ? this.makeInspect(key, changeDir) : null;
|
|
99989
100218
|
if (changeDir) {
|
|
99990
100219
|
const snapshot = await this.loadSnapshot(changeDir);
|
|
99991
100220
|
if (snapshot !== null && this.isValidSnapshot(snapshot)) {
|
|
99992
100221
|
try {
|
|
100222
|
+
const restored = this.withRestoredRuntime(snapshot);
|
|
99993
100223
|
const a2 = import_xstate_development_cjs.createActor(this.machine, {
|
|
99994
|
-
snapshot,
|
|
99995
|
-
input
|
|
100224
|
+
snapshot: restored,
|
|
100225
|
+
input,
|
|
100226
|
+
...inspector ? { inspect: inspector.inspect } : {}
|
|
99996
100227
|
});
|
|
100228
|
+
inspector?.setRoot(a2);
|
|
99997
100229
|
a2.start();
|
|
99998
100230
|
if (a2.getSnapshot().value !== undefined) {
|
|
99999
100231
|
this.actors.set(key, a2);
|
|
@@ -100005,11 +100237,61 @@ class FlowActorStore {
|
|
|
100005
100237
|
} catch {}
|
|
100006
100238
|
}
|
|
100007
100239
|
}
|
|
100008
|
-
const a = import_xstate_development_cjs.createActor(this.machine, {
|
|
100240
|
+
const a = import_xstate_development_cjs.createActor(this.machine, {
|
|
100241
|
+
input,
|
|
100242
|
+
...inspector ? { inspect: inspector.inspect } : {}
|
|
100243
|
+
});
|
|
100244
|
+
inspector?.setRoot(a);
|
|
100009
100245
|
a.start();
|
|
100010
100246
|
this.actors.set(key, a);
|
|
100011
100247
|
return a;
|
|
100012
100248
|
}
|
|
100249
|
+
buildRuntime() {
|
|
100250
|
+
return {
|
|
100251
|
+
bus: this.deps?.bus ?? createNoopBus(),
|
|
100252
|
+
persist: this.deps?.persist ?? (() => {}),
|
|
100253
|
+
worker: undefined,
|
|
100254
|
+
teardown: undefined
|
|
100255
|
+
};
|
|
100256
|
+
}
|
|
100257
|
+
withRestoredRuntime(snapshot) {
|
|
100258
|
+
if (!snapshot || typeof snapshot !== "object")
|
|
100259
|
+
return snapshot;
|
|
100260
|
+
const snap = snapshot;
|
|
100261
|
+
const context = snap.context ?? {};
|
|
100262
|
+
const data = context.data && typeof context.data === "object" ? context.data : {
|
|
100263
|
+
issueId: context.issueId,
|
|
100264
|
+
graceMs: context.graceMs ?? 5000,
|
|
100265
|
+
maxRecoveryAttempts: this.deps?.maxRecoveryAttempts ?? 0,
|
|
100266
|
+
currentAssignment: context.currentAssignment,
|
|
100267
|
+
pendingAssignment: context.pendingAssignment,
|
|
100268
|
+
recovery: undefined
|
|
100269
|
+
};
|
|
100270
|
+
return { ...snap, context: { data, runtime: this.buildRuntime() } };
|
|
100271
|
+
}
|
|
100272
|
+
makeInspect(issueId, changeDir) {
|
|
100273
|
+
let root;
|
|
100274
|
+
let previous;
|
|
100275
|
+
const inspect = (event) => {
|
|
100276
|
+
if (event.type !== "@xstate.snapshot" || event.actorRef !== root)
|
|
100277
|
+
return;
|
|
100278
|
+
const value = event.snapshot.value;
|
|
100279
|
+
const to = typeof value === "string" ? value : JSON.stringify(value);
|
|
100280
|
+
const eventType = event.event.type ?? "?";
|
|
100281
|
+
if (previous !== undefined && previous !== to) {
|
|
100282
|
+
try {
|
|
100283
|
+
this.deps?.onTransition?.(issueId, changeDir, { from: previous, event: eventType, to });
|
|
100284
|
+
} catch {}
|
|
100285
|
+
}
|
|
100286
|
+
previous = to;
|
|
100287
|
+
};
|
|
100288
|
+
return {
|
|
100289
|
+
inspect,
|
|
100290
|
+
setRoot: (actor) => {
|
|
100291
|
+
root = actor;
|
|
100292
|
+
}
|
|
100293
|
+
};
|
|
100294
|
+
}
|
|
100013
100295
|
peekActor(key) {
|
|
100014
100296
|
return this.actors.get(key) ?? null;
|
|
100015
100297
|
}
|
|
@@ -100065,6 +100347,7 @@ var init_flow_actor_store = __esm(() => {
|
|
|
100065
100347
|
init_xstate_development_cjs();
|
|
100066
100348
|
init_flow_machine();
|
|
100067
100349
|
init_store();
|
|
100350
|
+
init_src2();
|
|
100068
100351
|
});
|
|
100069
100352
|
|
|
100070
100353
|
// packages/core/src/machines/loop.machine.ts
|
|
@@ -102921,6 +103204,9 @@ function formatTicketError(err) {
|
|
|
102921
103204
|
parts.push(`configured team: ${e.team}`);
|
|
102922
103205
|
return parts.length > 0 ? `${e.message} (${parts.join(", ")})` : e.message;
|
|
102923
103206
|
}
|
|
103207
|
+
function openBlockersFromInverse(nodes) {
|
|
103208
|
+
return (nodes ?? []).filter((r) => r.type === "blocks" && !DONE_BLOCKER_STATE_TYPES.has(r.issue.state.type)).map((r) => ({ id: r.issue.id, identifier: r.issue.identifier }));
|
|
103209
|
+
}
|
|
102924
103210
|
function partition2(markers) {
|
|
102925
103211
|
const statuses = [];
|
|
102926
103212
|
const labels = [];
|
|
@@ -102951,6 +103237,39 @@ function applyRequiredLabels(where, requireAllLabels) {
|
|
|
102951
103237
|
}
|
|
102952
103238
|
where.and = and2;
|
|
102953
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
|
+
}
|
|
102954
103273
|
function buildIssueFilter(spec) {
|
|
102955
103274
|
const where = {};
|
|
102956
103275
|
if (spec.team)
|
|
@@ -102969,9 +103288,13 @@ function buildIssueFilter(spec) {
|
|
|
102969
103288
|
if (spec.numbers && spec.numbers.length > 0) {
|
|
102970
103289
|
where.number = { in: spec.numbers };
|
|
102971
103290
|
}
|
|
102972
|
-
const
|
|
103291
|
+
const incAll = spec.include ?? [];
|
|
103292
|
+
const inc = incAll.filter((m) => !isNegatedMarker(m));
|
|
103293
|
+
const negatedInc = incAll.filter(isNegatedMarker);
|
|
103294
|
+
let pinnedStatus = false;
|
|
102973
103295
|
if (inc.length > 0) {
|
|
102974
103296
|
const { statuses, labels, attachmentSubtitles, projects } = partition2(inc);
|
|
103297
|
+
pinnedStatus = statuses.length > 0;
|
|
102975
103298
|
const branches = [];
|
|
102976
103299
|
if (statuses.length > 0)
|
|
102977
103300
|
branches.push({ state: { name: { in: statuses } } });
|
|
@@ -102991,10 +103314,16 @@ function buildIssueFilter(spec) {
|
|
|
102991
103314
|
branches.push({ project: { name: { in: projects } } });
|
|
102992
103315
|
for (const b of branches)
|
|
102993
103316
|
Object.assign(where, b);
|
|
102994
|
-
}
|
|
103317
|
+
}
|
|
103318
|
+
if (!pinnedStatus) {
|
|
102995
103319
|
where.state = { type: { in: ["unstarted", "started", "backlog"] } };
|
|
102996
103320
|
}
|
|
102997
|
-
const exc =
|
|
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
|
+
];
|
|
102998
103327
|
if (exc.length > 0) {
|
|
102999
103328
|
const {
|
|
103000
103329
|
statuses,
|
|
@@ -103050,12 +103379,13 @@ function buildIssueFilter(spec) {
|
|
|
103050
103379
|
}
|
|
103051
103380
|
}
|
|
103052
103381
|
applyRequiredLabels(where, spec.requireAllLabels);
|
|
103382
|
+
applyRequiredProject(where, spec.requireProject);
|
|
103053
103383
|
return where;
|
|
103054
103384
|
}
|
|
103055
103385
|
function clauseFromMarkers(markers) {
|
|
103056
103386
|
if (markers.length === 0)
|
|
103057
103387
|
return null;
|
|
103058
|
-
const { statuses, labels, attachmentSubtitles, projects } = partition2(markers);
|
|
103388
|
+
const { statuses, labels, attachmentSubtitles, projects } = partition2(markers.filter((m) => !isNegatedMarker(m)));
|
|
103059
103389
|
const parts = {};
|
|
103060
103390
|
if (statuses.length > 0)
|
|
103061
103391
|
parts.state = { name: { in: statuses } };
|
|
@@ -103071,6 +103401,16 @@ function clauseFromMarkers(markers) {
|
|
|
103071
103401
|
}
|
|
103072
103402
|
if (projects.length > 0)
|
|
103073
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;
|
|
103074
103414
|
return Object.keys(parts).length > 0 ? parts : null;
|
|
103075
103415
|
}
|
|
103076
103416
|
function mapNodeProject(node2) {
|
|
@@ -103131,6 +103471,8 @@ async function fetchMentionScanIssues(apiKey, spec) {
|
|
|
103131
103471
|
where.number = { in: spec.numbers };
|
|
103132
103472
|
}
|
|
103133
103473
|
applyRequiredLabels(where, spec.requireAllLabels);
|
|
103474
|
+
applyRequiredProject(where, spec.requireProject);
|
|
103475
|
+
applyGlobalExcludes(where, spec.excludeLabels, spec.excludeProjects);
|
|
103134
103476
|
const query = `query MentionScanIssues($filter: IssueFilter) {
|
|
103135
103477
|
issues(filter: $filter, first: 50) {
|
|
103136
103478
|
nodes {
|
|
@@ -103140,8 +103482,8 @@ async function fetchMentionScanIssues(apiKey, spec) {
|
|
|
103140
103482
|
project { id name priority }
|
|
103141
103483
|
projectMilestone { id name sortOrder targetDate }
|
|
103142
103484
|
labels { nodes { name } }
|
|
103143
|
-
|
|
103144
|
-
nodes { type
|
|
103485
|
+
inverseRelations(first: 50) {
|
|
103486
|
+
nodes { type issue { id identifier state { type } } }
|
|
103145
103487
|
}
|
|
103146
103488
|
comments(first: 50) {
|
|
103147
103489
|
nodes { id body createdAt user { name email } }
|
|
@@ -103152,24 +103494,26 @@ async function fetchMentionScanIssues(apiKey, spec) {
|
|
|
103152
103494
|
const data = await linearRequest(apiKey, query, {
|
|
103153
103495
|
filter: where
|
|
103154
103496
|
});
|
|
103155
|
-
|
|
103156
|
-
|
|
103157
|
-
|
|
103158
|
-
|
|
103159
|
-
|
|
103160
|
-
|
|
103161
|
-
|
|
103162
|
-
|
|
103163
|
-
|
|
103164
|
-
|
|
103165
|
-
|
|
103166
|
-
|
|
103167
|
-
|
|
103168
|
-
|
|
103169
|
-
|
|
103170
|
-
|
|
103171
|
-
|
|
103172
|
-
|
|
103497
|
+
return data.issues.nodes.map((n) => {
|
|
103498
|
+
const blockers = openBlockersFromInverse(n.inverseRelations?.nodes);
|
|
103499
|
+
return {
|
|
103500
|
+
id: n.id,
|
|
103501
|
+
identifier: n.identifier,
|
|
103502
|
+
title: n.title,
|
|
103503
|
+
description: n.description,
|
|
103504
|
+
url: n.url,
|
|
103505
|
+
state: n.state,
|
|
103506
|
+
assignee: n.assignee,
|
|
103507
|
+
project: mapNodeProject(n),
|
|
103508
|
+
...milestoneSpread(n),
|
|
103509
|
+
labels: n.labels.nodes.map((l) => l.name),
|
|
103510
|
+
priority: n.priority,
|
|
103511
|
+
createdAt: n.createdAt ?? "",
|
|
103512
|
+
blockedByIds: blockers.map((b) => b.id),
|
|
103513
|
+
blockedByIdentifiers: blockers.map((b) => b.identifier),
|
|
103514
|
+
comments: n.comments?.nodes ?? []
|
|
103515
|
+
};
|
|
103516
|
+
});
|
|
103173
103517
|
}
|
|
103174
103518
|
async function fetchOpenIssues(apiKey, spec, options) {
|
|
103175
103519
|
const where = buildIssueFilter(spec);
|
|
@@ -103186,10 +103530,10 @@ async function fetchOpenIssues(apiKey, spec, options) {
|
|
|
103186
103530
|
project { id name priority }
|
|
103187
103531
|
projectMilestone { id name sortOrder targetDate }
|
|
103188
103532
|
labels { nodes { name } }
|
|
103189
|
-
|
|
103533
|
+
inverseRelations(first: 50) {
|
|
103190
103534
|
nodes {
|
|
103191
103535
|
type
|
|
103192
|
-
|
|
103536
|
+
issue { id identifier state { type } }
|
|
103193
103537
|
}
|
|
103194
103538
|
}
|
|
103195
103539
|
${commentsSlice}
|
|
@@ -103199,24 +103543,26 @@ async function fetchOpenIssues(apiKey, spec, options) {
|
|
|
103199
103543
|
const data = await linearRequest(apiKey, query, {
|
|
103200
103544
|
filter: where
|
|
103201
103545
|
});
|
|
103202
|
-
|
|
103203
|
-
|
|
103204
|
-
|
|
103205
|
-
|
|
103206
|
-
|
|
103207
|
-
|
|
103208
|
-
|
|
103209
|
-
|
|
103210
|
-
|
|
103211
|
-
|
|
103212
|
-
|
|
103213
|
-
|
|
103214
|
-
|
|
103215
|
-
|
|
103216
|
-
|
|
103217
|
-
|
|
103218
|
-
|
|
103219
|
-
|
|
103546
|
+
return data.issues.nodes.map((n) => {
|
|
103547
|
+
const blockers = openBlockersFromInverse(n.inverseRelations?.nodes);
|
|
103548
|
+
return {
|
|
103549
|
+
id: n.id,
|
|
103550
|
+
identifier: n.identifier,
|
|
103551
|
+
title: n.title,
|
|
103552
|
+
description: n.description,
|
|
103553
|
+
url: n.url,
|
|
103554
|
+
state: n.state,
|
|
103555
|
+
assignee: n.assignee,
|
|
103556
|
+
project: mapNodeProject(n),
|
|
103557
|
+
...milestoneSpread(n),
|
|
103558
|
+
labels: n.labels.nodes.map((l) => l.name),
|
|
103559
|
+
priority: n.priority,
|
|
103560
|
+
createdAt: n.createdAt ?? "",
|
|
103561
|
+
blockedByIds: blockers.map((b) => b.id),
|
|
103562
|
+
blockedByIdentifiers: blockers.map((b) => b.identifier),
|
|
103563
|
+
...includeComments ? { comments: n.comments?.nodes ?? [] } : {}
|
|
103564
|
+
};
|
|
103565
|
+
});
|
|
103220
103566
|
}
|
|
103221
103567
|
function isRetryableStatus(status) {
|
|
103222
103568
|
return status >= 500 && status <= 599;
|
|
@@ -103530,17 +103876,15 @@ async function fetchBlockedByForIssues(apiKey, issueIds) {
|
|
|
103530
103876
|
issues(filter: { id: { in: $ids } }, first: 250) {
|
|
103531
103877
|
nodes {
|
|
103532
103878
|
id
|
|
103533
|
-
|
|
103534
|
-
nodes { type
|
|
103879
|
+
inverseRelations(first: 50) {
|
|
103880
|
+
nodes { type issue { id identifier state { type } } }
|
|
103535
103881
|
}
|
|
103536
103882
|
}
|
|
103537
103883
|
}
|
|
103538
103884
|
}`;
|
|
103539
103885
|
const data = await linearRequest(apiKey, query, { ids: issueIds });
|
|
103540
|
-
const DONE_STATE_TYPES = new Set(["completed", "cancelled"]);
|
|
103541
103886
|
for (const node2 of data.issues.nodes) {
|
|
103542
|
-
|
|
103543
|
-
out.set(node2.id, blockers);
|
|
103887
|
+
out.set(node2.id, openBlockersFromInverse(node2.inverseRelations?.nodes));
|
|
103544
103888
|
}
|
|
103545
103889
|
return out;
|
|
103546
103890
|
}
|
|
@@ -103656,7 +104000,7 @@ function issueMatchesGetIndicator(issue2, indicator) {
|
|
|
103656
104000
|
const labels = new Set(issue2.labels.map((l) => l.toLowerCase()));
|
|
103657
104001
|
const stateName = issue2.state.name.toLowerCase();
|
|
103658
104002
|
const projectName = issue2.project?.name.toLowerCase() ?? null;
|
|
103659
|
-
|
|
104003
|
+
const baseMatch = (m) => {
|
|
103660
104004
|
if (m.type === "label")
|
|
103661
104005
|
return labels.has(m.value.toLowerCase());
|
|
103662
104006
|
if (m.type === "status")
|
|
@@ -103676,7 +104020,8 @@ function issueMatchesGetIndicator(issue2, indicator) {
|
|
|
103676
104020
|
return comments.some((c) => !isRalphComment(c.body) && c.body.toLowerCase().includes(needle));
|
|
103677
104021
|
}
|
|
103678
104022
|
return false;
|
|
103679
|
-
}
|
|
104023
|
+
};
|
|
104024
|
+
return indicator.filter.some((m) => isNegatedMarker(m) ? !baseMatch(m) : baseMatch(m));
|
|
103680
104025
|
}
|
|
103681
104026
|
async function fetchProjectIdByName(apiKey, name) {
|
|
103682
104027
|
const query = `query ProjectId($name: String!) {
|
|
@@ -103754,12 +104099,13 @@ async function removeLabelFromIssue(apiKey, issueId, labelId) {
|
|
|
103754
104099
|
labelId
|
|
103755
104100
|
});
|
|
103756
104101
|
}
|
|
103757
|
-
var LINEAR_API = "https://api.linear.app/graphql", TICKET_IDENTIFIER_RE, TICKET_BARE_NUMBER_RE, RALPHY_ATTACHMENT_TITLE_FILTER = "Ralphy", linearRequestInternals, MAX_LINEAR_ATTEMPTS = 3, MAX_RETRY_AFTER_MS = 2000, BODY_TRUNCATE_CHARS = 512, RALPHY_ATTACHMENT_TITLE = "Ralphy", BRANCH_LABEL_PREFIX = "ralph:branch:";
|
|
104102
|
+
var LINEAR_API = "https://api.linear.app/graphql", TICKET_IDENTIFIER_RE, TICKET_BARE_NUMBER_RE, DONE_BLOCKER_STATE_TYPES, RALPHY_ATTACHMENT_TITLE_FILTER = "Ralphy", linearRequestInternals, MAX_LINEAR_ATTEMPTS = 3, MAX_RETRY_AFTER_MS = 2000, BODY_TRUNCATE_CHARS = 512, RALPHY_ATTACHMENT_TITLE = "Ralphy", BRANCH_LABEL_PREFIX = "ralph:branch:";
|
|
103758
104103
|
var init_linear_client = __esm(() => {
|
|
103759
104104
|
init_types2();
|
|
103760
104105
|
init_ralph_comment();
|
|
103761
104106
|
TICKET_IDENTIFIER_RE = /^([A-Za-z]+)-(\d+)(?:-.*)?$/;
|
|
103762
104107
|
TICKET_BARE_NUMBER_RE = /^(\d+)$/;
|
|
104108
|
+
DONE_BLOCKER_STATE_TYPES = new Set(["completed", "cancelled"]);
|
|
103763
104109
|
linearRequestInternals = {
|
|
103764
104110
|
sleep: (ms) => Bun.sleep(ms)
|
|
103765
104111
|
};
|
|
@@ -103866,7 +104212,7 @@ async function provisionWorktree(projectRoot, changeName, baseBranch, runner) {
|
|
|
103866
104212
|
if (list.stdout.includes(`worktree ${cwd2}
|
|
103867
104213
|
`)) {
|
|
103868
104214
|
await installPrePushHook(cwd2, runner);
|
|
103869
|
-
return { cwd: cwd2, branch };
|
|
104215
|
+
return { cwd: cwd2, branch, created: false };
|
|
103870
104216
|
}
|
|
103871
104217
|
let branchExists = true;
|
|
103872
104218
|
try {
|
|
@@ -103877,12 +104223,12 @@ async function provisionWorktree(projectRoot, changeName, baseBranch, runner) {
|
|
|
103877
104223
|
if (branchExists) {
|
|
103878
104224
|
await runner.run(["worktree", "add", cwd2, branch], projectRoot);
|
|
103879
104225
|
await installPrePushHook(cwd2, runner);
|
|
103880
|
-
return { cwd: cwd2, branch };
|
|
104226
|
+
return { cwd: cwd2, branch, created: true };
|
|
103881
104227
|
}
|
|
103882
104228
|
await runner.run(["fetch", "origin", baseBranch], projectRoot);
|
|
103883
104229
|
await runner.run(["worktree", "add", "-b", branch, cwd2, `origin/${baseBranch}`], projectRoot);
|
|
103884
104230
|
await installPrePushHook(cwd2, runner);
|
|
103885
|
-
return { cwd: cwd2, branch };
|
|
104231
|
+
return { cwd: cwd2, branch, created: true };
|
|
103886
104232
|
}
|
|
103887
104233
|
async function installPrePushHook(cwd2, runner) {
|
|
103888
104234
|
const hookPath = join22(cwd2, ".ralph-hooks", "pre-push");
|
|
@@ -104188,6 +104534,14 @@ async function branchAlreadyMerged(runner, cwd2, branch, base2) {
|
|
|
104188
104534
|
} catch {}
|
|
104189
104535
|
return false;
|
|
104190
104536
|
}
|
|
104537
|
+
async function applyPrLabels(runner, cwd2, prRef, labels) {
|
|
104538
|
+
const clean = labels.map((l) => l.trim()).filter(Boolean);
|
|
104539
|
+
if (clean.length === 0 || !prRef)
|
|
104540
|
+
return;
|
|
104541
|
+
try {
|
|
104542
|
+
await runner.run(["gh", "pr", "edit", prRef, "--add-label", clean.join(",")], cwd2);
|
|
104543
|
+
} catch {}
|
|
104544
|
+
}
|
|
104191
104545
|
async function createPullRequest(input, runner) {
|
|
104192
104546
|
const base2 = input.base ?? "main";
|
|
104193
104547
|
const log3 = await runner.run(["git", "log", "--oneline", `${base2}..HEAD`, "--no-merges"], input.cwd);
|
|
@@ -104224,8 +104578,10 @@ async function createPullRequest(input, runner) {
|
|
|
104224
104578
|
".[0].url // empty"
|
|
104225
104579
|
], input.cwd);
|
|
104226
104580
|
const existingUrl = existing.stdout.trim();
|
|
104227
|
-
if (existingUrl)
|
|
104581
|
+
if (existingUrl) {
|
|
104582
|
+
await applyPrLabels(runner, input.cwd, existingUrl, input.labels ?? []);
|
|
104228
104583
|
return { url: existingUrl, created: false };
|
|
104584
|
+
}
|
|
104229
104585
|
const title = defaultTitle(input.issue);
|
|
104230
104586
|
const body = defaultBody(input.issue, input.branch, input.stackedOn);
|
|
104231
104587
|
const createArgs = ["gh", "pr", "create", "--base", base2, "--title", title, "--body", body];
|
|
@@ -104234,6 +104590,7 @@ async function createPullRequest(input, runner) {
|
|
|
104234
104590
|
const created = await runner.run(createArgs, input.cwd);
|
|
104235
104591
|
const url2 = created.stdout.trim().split(`
|
|
104236
104592
|
`).pop() ?? "";
|
|
104593
|
+
await applyPrLabels(runner, input.cwd, url2, input.labels ?? []);
|
|
104237
104594
|
return { url: url2, created: true };
|
|
104238
104595
|
}
|
|
104239
104596
|
var init_pr = __esm(() => {
|
|
@@ -104787,7 +105144,7 @@ function emitFeatureSkipped(bus, id, reason) {
|
|
|
104787
105144
|
var init_run_feature = () => {};
|
|
104788
105145
|
|
|
104789
105146
|
// apps/agent/src/agent/post-task.ts
|
|
104790
|
-
import { join as join23
|
|
105147
|
+
import { join as join23 } from "path";
|
|
104791
105148
|
function summarizeUncommittedStatus(stdout) {
|
|
104792
105149
|
const lines = stdout.split(`
|
|
104793
105150
|
`).filter((line) => line.length > 0);
|
|
@@ -104914,6 +105271,7 @@ async function createPrWithRetry(ctx, issue2) {
|
|
|
104914
105271
|
base: base2,
|
|
104915
105272
|
metaOnlyFiles: ctx.cfg.metaOnlyFiles ?? [],
|
|
104916
105273
|
draft: ctx.cfg.prDraft ?? false,
|
|
105274
|
+
labels: ctx.cfg.prLabels ?? [],
|
|
104917
105275
|
...ctx.stackedOn ? {
|
|
104918
105276
|
stackedOn: {
|
|
104919
105277
|
prUrl: ctx.stackedOn.prUrl,
|
|
@@ -105285,17 +105643,6 @@ async function runValidateOnlyPhase(input, deps) {
|
|
|
105285
105643
|
await reactivateState(stateFilePath, log3, changeName);
|
|
105286
105644
|
return respawnWorker();
|
|
105287
105645
|
}
|
|
105288
|
-
async function recordGaveUp(stateFilePath, log3, changeName) {
|
|
105289
|
-
const path = join23(dirname9(stateFilePath), GAVEUP_COUNT_FILE);
|
|
105290
|
-
try {
|
|
105291
|
-
const file2 = Bun.file(path);
|
|
105292
|
-
const current = await file2.exists() ? Number.parseInt(await file2.text(), 10) || 0 : 0;
|
|
105293
|
-
await Bun.write(path, String(current + 1) + `
|
|
105294
|
-
`);
|
|
105295
|
-
} catch (err) {
|
|
105296
|
-
log3(`! could not record gave-up for ${changeName}: ${err.message}`, "yellow");
|
|
105297
|
-
}
|
|
105298
|
-
}
|
|
105299
105646
|
async function runPostTask(input, deps) {
|
|
105300
105647
|
const { log: log3, cmd, git: git2, runScript } = deps;
|
|
105301
105648
|
const emit3 = (phase, detail) => deps.onPhase?.(phase, detail);
|
|
@@ -105338,8 +105685,6 @@ async function runPostTask(input, deps) {
|
|
|
105338
105685
|
respawnWorker
|
|
105339
105686
|
});
|
|
105340
105687
|
emit3(effectiveCode === 0 ? "done" : "gave-up", effectiveCode !== 0 ? `exit ${effectiveCode}` : undefined);
|
|
105341
|
-
if (effectiveCode !== 0)
|
|
105342
|
-
await recordGaveUp(stateFilePath, log3, changeName);
|
|
105343
105688
|
await runWorktreeCleanupPhase({ changeName, cwd: cwd2, projectRoot, useWorktree, effectiveCode, cfg }, { git: git2, log: log3, emit: emit3 });
|
|
105344
105689
|
await runTeardownPhase({ cwd: cwd2, teardownScript: cfg.teardownScript }, { runScript, log: log3, emit: emit3 });
|
|
105345
105690
|
return effectiveCode;
|
|
@@ -105362,7 +105707,6 @@ async function runPostTask(input, deps) {
|
|
|
105362
105707
|
if (checked && aheadCount > 0) {
|
|
105363
105708
|
log3(`! ${identifier}: conflict-fix worker left ${aheadCount} unpushed commit(s) ahead of ` + `origin/${branch} \u2014 the resolution never reached the PR. Failing the iteration so it ` + `is retried instead of reported as resolved.`, "red");
|
|
105364
105709
|
emit3("gave-up", "unpushed conflict resolution");
|
|
105365
|
-
await recordGaveUp(stateFilePath, log3, changeName);
|
|
105366
105710
|
await runWorktreeCleanupPhase({ changeName, cwd: cwd2, projectRoot, useWorktree, effectiveCode: PR_FAILED_EXIT, cfg }, { git: git2, log: log3, emit: emit3 });
|
|
105367
105711
|
await runTeardownPhase({ cwd: cwd2, teardownScript: cfg.teardownScript }, { runScript, log: log3, emit: emit3 });
|
|
105368
105712
|
return PR_FAILED_EXIT;
|
|
@@ -105432,8 +105776,6 @@ async function runPostTask(input, deps) {
|
|
|
105432
105776
|
}
|
|
105433
105777
|
const succeeded = effectiveCode === 0 || effectiveCode === NO_CHANGES_EXIT;
|
|
105434
105778
|
emit3(succeeded ? "done" : "gave-up", succeeded ? undefined : `exit ${effectiveCode}`);
|
|
105435
|
-
if (!succeeded)
|
|
105436
|
-
await recordGaveUp(stateFilePath, log3, changeName);
|
|
105437
105779
|
await deps.runRetrospective?.({
|
|
105438
105780
|
changeName,
|
|
105439
105781
|
cwd: cwd2,
|
|
@@ -105460,7 +105802,6 @@ var PR_FAILED_EXIT = 71, MAX_PR_CREATE_ATTEMPTS = 5, NO_CHANGES_EXIT = 72, repoA
|
|
|
105460
105802
|
return { exitCode: proc.exitCode ?? 1, output };
|
|
105461
105803
|
};
|
|
105462
105804
|
var init_post_task = __esm(() => {
|
|
105463
|
-
init_layout();
|
|
105464
105805
|
init_tasks_md();
|
|
105465
105806
|
init_fs_change();
|
|
105466
105807
|
init_git2();
|
|
@@ -105474,6 +105815,309 @@ var init_post_task = __esm(() => {
|
|
|
105474
105815
|
repoAutoMergeCache = new Map;
|
|
105475
105816
|
});
|
|
105476
105817
|
|
|
105818
|
+
// apps/agent/src/shared/capabilities/gh-client.ts
|
|
105819
|
+
var init_gh_client = () => {};
|
|
105820
|
+
|
|
105821
|
+
// apps/agent/src/shared/capabilities/github/github-client.ts
|
|
105822
|
+
var STARTED_LABEL_NAMES, ISSUE_FIELDS = "id,number,title,body,state,stateReason,labels,assignees,author,createdAt,url", ISSUE_FIELDS_WITH_COMMENTS;
|
|
105823
|
+
var init_github_client = __esm(() => {
|
|
105824
|
+
init_worktree();
|
|
105825
|
+
init_gh_client();
|
|
105826
|
+
STARTED_LABEL_NAMES = new Set(["in progress", "in-progress", "started"]);
|
|
105827
|
+
ISSUE_FIELDS_WITH_COMMENTS = `${ISSUE_FIELDS},comments`;
|
|
105828
|
+
});
|
|
105829
|
+
|
|
105830
|
+
// apps/agent/src/shared/capabilities/github/identifier-strategy.ts
|
|
105831
|
+
function linearChangeName(issue2) {
|
|
105832
|
+
const slug = issue2.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 40).replace(/^-+|-+$/g, "");
|
|
105833
|
+
return slug ? `${issue2.identifier.toLowerCase()}-${slug}` : issue2.identifier.toLowerCase();
|
|
105834
|
+
}
|
|
105835
|
+
var linearIdentifierStrategy;
|
|
105836
|
+
var init_identifier_strategy = __esm(() => {
|
|
105837
|
+
init_worktree();
|
|
105838
|
+
init_github_client();
|
|
105839
|
+
linearIdentifierStrategy = {
|
|
105840
|
+
scopeKey: (issue2) => issue2.identifier.split("-")[0],
|
|
105841
|
+
changeName: linearChangeName,
|
|
105842
|
+
branchName: (issue2) => branchForChange(linearChangeName(issue2))
|
|
105843
|
+
};
|
|
105844
|
+
});
|
|
105845
|
+
|
|
105846
|
+
// apps/agent/src/agent/scaffold.ts
|
|
105847
|
+
import { join as join24 } from "path";
|
|
105848
|
+
function changeNameForIssue(issue2) {
|
|
105849
|
+
return linearIdentifierStrategy.changeName(issue2);
|
|
105850
|
+
}
|
|
105851
|
+
async function scaffoldChangeForIssue(tasksDir, statesDir, issue2, comments = [], appendPrompt = "", attachments = []) {
|
|
105852
|
+
const name = changeNameForIssue(issue2);
|
|
105853
|
+
const changeDir = join24(tasksDir, name);
|
|
105854
|
+
const stateDir = join24(statesDir, name);
|
|
105855
|
+
const commentsBlock = comments.length > 0 ? [
|
|
105856
|
+
"",
|
|
105857
|
+
"## Linear comments",
|
|
105858
|
+
"",
|
|
105859
|
+
...comments.flatMap((c) => [
|
|
105860
|
+
`**${c.user?.name ?? "unknown"}** \u2014 ${c.createdAt}`,
|
|
105861
|
+
"",
|
|
105862
|
+
c.body.trim(),
|
|
105863
|
+
""
|
|
105864
|
+
])
|
|
105865
|
+
] : [];
|
|
105866
|
+
const attachmentsBlock = attachments.length > 0 ? [
|
|
105867
|
+
"",
|
|
105868
|
+
"## Ticket Attachments",
|
|
105869
|
+
"",
|
|
105870
|
+
...attachments.map((a) => `- [${a.title ?? "Attachment"}](${a.url})`)
|
|
105871
|
+
] : [];
|
|
105872
|
+
const descriptionBody = issue2.description?.trim() || "_No description provided in Linear._";
|
|
105873
|
+
const proposal = [
|
|
105874
|
+
`# ${issue2.identifier}: ${issue2.title}`,
|
|
105875
|
+
"",
|
|
105876
|
+
`Source: [${issue2.identifier}](${issue2.url})`,
|
|
105877
|
+
`Status: ${issue2.state.name}`,
|
|
105878
|
+
issue2.assignee ? `Assignee: ${issue2.assignee.name}` : "",
|
|
105879
|
+
issue2.labels.length ? `Labels: ${issue2.labels.join(", ")}` : "",
|
|
105880
|
+
"",
|
|
105881
|
+
"## Why",
|
|
105882
|
+
"",
|
|
105883
|
+
descriptionBody,
|
|
105884
|
+
"",
|
|
105885
|
+
"## What Changes",
|
|
105886
|
+
"",
|
|
105887
|
+
"_Describe the concrete changes this proposal introduces (one bullet per change)._",
|
|
105888
|
+
...commentsBlock,
|
|
105889
|
+
...attachmentsBlock,
|
|
105890
|
+
...appendPrompt.trim() ? ["", "## Additional instructions", "", appendPrompt.trim()] : [],
|
|
105891
|
+
"",
|
|
105892
|
+
"## Steering",
|
|
105893
|
+
"",
|
|
105894
|
+
"_Add steering notes here as the loop runs._",
|
|
105895
|
+
""
|
|
105896
|
+
].filter((l) => l !== "").join(`
|
|
105897
|
+
`);
|
|
105898
|
+
const tasks = [
|
|
105899
|
+
`# Tasks for ${issue2.identifier}`,
|
|
105900
|
+
"",
|
|
105901
|
+
"## Planning",
|
|
105902
|
+
"",
|
|
105903
|
+
`- [ ] Read the Linear issue at ${issue2.url} and research the codebase to understand the mission and its scope`,
|
|
105904
|
+
`- [ ] Refine proposal.md with the problem statement, approach, and acceptance criteria derived from the research`,
|
|
105905
|
+
`- [ ] Fill in \`## Why\` and \`## What Changes\` in proposal.md so \`openspec validate\` passes (these sections are required by the validator)`,
|
|
105906
|
+
`- [ ] Add at least one spec delta under \`specs/<capability>/spec.md\` describing the behavior added/modified/removed by this change`,
|
|
105907
|
+
`- [ ] Fill in design.md with the technical design (files to touch, data flow, edge cases). design.md holds prose and tables ONLY \u2014 never a task checklist; the implementation tasks belong in this tasks.md file (next item).`,
|
|
105908
|
+
`- [ ] Append an \`## Implementation\` section to **this tasks.md file** (below the \`## Planning\` section above \u2014 NOT in design.md) with concrete mission-specific tasks derived from the plan, including tests and \`bun run lint\` / \`bun run test\`. Every item in the new section MUST start as \`- [ ]\` (unchecked) \u2014 do not pre-check items even if you already did the work during planning. The loop ticks them off in later iterations after each one is verified.`,
|
|
105909
|
+
`- [ ] Is there anything else to add? Review the complete change context and document any additional edge cases, constraints, or open questions not captured above.`,
|
|
105910
|
+
""
|
|
105911
|
+
].join(`
|
|
105912
|
+
`);
|
|
105913
|
+
const design = [
|
|
105914
|
+
`# Design for ${issue2.identifier}`,
|
|
105915
|
+
"",
|
|
105916
|
+
"_Fill in the technical design as you work through the issue._",
|
|
105917
|
+
""
|
|
105918
|
+
].join(`
|
|
105919
|
+
`);
|
|
105920
|
+
await runCapability(fsChange.scaffold, {
|
|
105921
|
+
changeDir,
|
|
105922
|
+
stateDir,
|
|
105923
|
+
proposal,
|
|
105924
|
+
tasks,
|
|
105925
|
+
design
|
|
105926
|
+
});
|
|
105927
|
+
return name;
|
|
105928
|
+
}
|
|
105929
|
+
var init_scaffold = __esm(() => {
|
|
105930
|
+
init_fs_change();
|
|
105931
|
+
init_identifier_strategy();
|
|
105932
|
+
});
|
|
105933
|
+
|
|
105934
|
+
// apps/agent/src/components/task-pipeline.ts
|
|
105935
|
+
function stages(todo, confirmation, work, pr, ci, done) {
|
|
105936
|
+
return [
|
|
105937
|
+
{ node: "todo", status: todo },
|
|
105938
|
+
{ node: "confirmation", status: confirmation },
|
|
105939
|
+
{ node: "work", status: work },
|
|
105940
|
+
{ node: "PR", status: pr },
|
|
105941
|
+
{ node: "CI", status: ci },
|
|
105942
|
+
{ node: "done", status: done }
|
|
105943
|
+
];
|
|
105944
|
+
}
|
|
105945
|
+
function pipelineStages(row) {
|
|
105946
|
+
const state = row.state;
|
|
105947
|
+
switch (state) {
|
|
105948
|
+
case "todo":
|
|
105949
|
+
return stages("current", "pending", "pending", "pending", "pending", "pending");
|
|
105950
|
+
case "awaiting":
|
|
105951
|
+
return stages("done", "current", "pending", "pending", "pending", "pending");
|
|
105952
|
+
case "queued":
|
|
105953
|
+
case "working":
|
|
105954
|
+
case "in-progress":
|
|
105955
|
+
return stages("done", "done", "current", "pending", "pending", "pending");
|
|
105956
|
+
case "awaiting-ci":
|
|
105957
|
+
return stages("done", "done", "done", "done", "current", "pending");
|
|
105958
|
+
case "conflict-fix":
|
|
105959
|
+
return stages("done", "done", "done", "failed", "pending", "pending");
|
|
105960
|
+
case "ci-fix":
|
|
105961
|
+
return stages("done", "done", "done", "done", "failed", "pending");
|
|
105962
|
+
case "review":
|
|
105963
|
+
return stages("done", "done", "current", "done", "done", "pending");
|
|
105964
|
+
case "quarantined":
|
|
105965
|
+
return row.recovery?.lastReason === "conflicting" ? stages("done", "done", "done", "bailed", "pending", "pending") : stages("done", "done", "done", "done", "bailed", "pending");
|
|
105966
|
+
case "done":
|
|
105967
|
+
return stages("done", "done", "done", "done", "done", "done");
|
|
105968
|
+
case "error":
|
|
105969
|
+
return stages("done", "done", "failed", "pending", "pending", "pending");
|
|
105970
|
+
default: {
|
|
105971
|
+
const exhaustive = state;
|
|
105972
|
+
return exhaustive;
|
|
105973
|
+
}
|
|
105974
|
+
}
|
|
105975
|
+
}
|
|
105976
|
+
function attemptCount(plural) {
|
|
105977
|
+
return `${plural} fix attempt${plural === 1 ? "" : "s"}`;
|
|
105978
|
+
}
|
|
105979
|
+
function statusLabel(row) {
|
|
105980
|
+
const state = row.state;
|
|
105981
|
+
switch (state) {
|
|
105982
|
+
case "todo":
|
|
105983
|
+
return "todo";
|
|
105984
|
+
case "queued":
|
|
105985
|
+
return "queued";
|
|
105986
|
+
case "working":
|
|
105987
|
+
return "working";
|
|
105988
|
+
case "in-progress":
|
|
105989
|
+
return "in progress";
|
|
105990
|
+
case "awaiting":
|
|
105991
|
+
return "awaiting confirmation";
|
|
105992
|
+
case "awaiting-ci":
|
|
105993
|
+
return "awaiting CI";
|
|
105994
|
+
case "conflict-fix":
|
|
105995
|
+
return `conflict \xB7 ${attemptCount(row.recovery?.attempts ?? 0)}`;
|
|
105996
|
+
case "ci-fix":
|
|
105997
|
+
return `CI red \xB7 ${attemptCount(row.recovery?.attempts ?? 0)}`;
|
|
105998
|
+
case "review":
|
|
105999
|
+
return "addressing review";
|
|
106000
|
+
case "quarantined": {
|
|
106001
|
+
const tries = row.recovery?.attempts ?? 0;
|
|
106002
|
+
const reason = row.recovery?.lastReason === "conflicting" ? "conflict" : "CI";
|
|
106003
|
+
return `quarantined \xB7 ${tries} tries (${reason}), bailed`;
|
|
106004
|
+
}
|
|
106005
|
+
case "done":
|
|
106006
|
+
return "done";
|
|
106007
|
+
case "error":
|
|
106008
|
+
return "error";
|
|
106009
|
+
default: {
|
|
106010
|
+
const exhaustive = state;
|
|
106011
|
+
return exhaustive;
|
|
106012
|
+
}
|
|
106013
|
+
}
|
|
106014
|
+
}
|
|
106015
|
+
function orderActiveWorkersFirst(rows, activeWorkerIds) {
|
|
106016
|
+
if (activeWorkerIds.size === 0)
|
|
106017
|
+
return rows.slice();
|
|
106018
|
+
const active = [];
|
|
106019
|
+
const rest2 = [];
|
|
106020
|
+
for (const r of rows)
|
|
106021
|
+
(activeWorkerIds.has(r.id) ? active : rest2).push(r);
|
|
106022
|
+
return [...active, ...rest2];
|
|
106023
|
+
}
|
|
106024
|
+
function buildBoardTree(rows) {
|
|
106025
|
+
const byId = new Map(rows.map((r) => [r.id, r]));
|
|
106026
|
+
const orderIndex = new Map(rows.map((r, i) => [r.id, i]));
|
|
106027
|
+
const blockersOf = (r) => (r.blockedByIds ?? []).filter((id) => id !== r.id && byId.has(id));
|
|
106028
|
+
const childrenOf = new Map;
|
|
106029
|
+
for (const r of rows) {
|
|
106030
|
+
for (const blockerId of blockersOf(r)) {
|
|
106031
|
+
const list = childrenOf.get(blockerId);
|
|
106032
|
+
if (list)
|
|
106033
|
+
list.push(r);
|
|
106034
|
+
else
|
|
106035
|
+
childrenOf.set(blockerId, [r]);
|
|
106036
|
+
}
|
|
106037
|
+
}
|
|
106038
|
+
for (const list of childrenOf.values()) {
|
|
106039
|
+
list.sort((a, b) => orderIndex.get(a.id) - orderIndex.get(b.id));
|
|
106040
|
+
}
|
|
106041
|
+
const emitted = new Set;
|
|
106042
|
+
const depthById = new Map;
|
|
106043
|
+
const result2 = [];
|
|
106044
|
+
const blockerIdentifiersOf = (r) => blockersOf(r).map((id) => byId.get(id).identifier);
|
|
106045
|
+
const tryEmit = (r) => {
|
|
106046
|
+
if (emitted.has(r.id))
|
|
106047
|
+
return;
|
|
106048
|
+
const blockers = blockersOf(r);
|
|
106049
|
+
if (!blockers.every((id) => emitted.has(id)))
|
|
106050
|
+
return;
|
|
106051
|
+
const depth = blockers.length === 0 ? 0 : Math.max(...blockers.map((id) => depthById.get(id))) + 1;
|
|
106052
|
+
depthById.set(r.id, depth);
|
|
106053
|
+
emitted.add(r.id);
|
|
106054
|
+
result2.push({ row: r, depth, blockerIdentifiers: blockerIdentifiersOf(r) });
|
|
106055
|
+
for (const child of childrenOf.get(r.id) ?? [])
|
|
106056
|
+
tryEmit(child);
|
|
106057
|
+
};
|
|
106058
|
+
for (const r of rows) {
|
|
106059
|
+
if (blockersOf(r).length === 0)
|
|
106060
|
+
tryEmit(r);
|
|
106061
|
+
}
|
|
106062
|
+
for (const r of rows) {
|
|
106063
|
+
if (emitted.has(r.id))
|
|
106064
|
+
continue;
|
|
106065
|
+
depthById.set(r.id, 0);
|
|
106066
|
+
emitted.add(r.id);
|
|
106067
|
+
result2.push({ row: r, depth: 0, blockerIdentifiers: blockerIdentifiersOf(r) });
|
|
106068
|
+
for (const child of childrenOf.get(r.id) ?? [])
|
|
106069
|
+
tryEmit(child);
|
|
106070
|
+
}
|
|
106071
|
+
return result2;
|
|
106072
|
+
}
|
|
106073
|
+
function machineStateToTicketState(value) {
|
|
106074
|
+
switch (value) {
|
|
106075
|
+
case "idle":
|
|
106076
|
+
return "in-progress";
|
|
106077
|
+
case "working":
|
|
106078
|
+
return "working";
|
|
106079
|
+
case "conflict-fix":
|
|
106080
|
+
return "conflict-fix";
|
|
106081
|
+
case "ci-fix":
|
|
106082
|
+
return "ci-fix";
|
|
106083
|
+
case "awaiting":
|
|
106084
|
+
return "awaiting";
|
|
106085
|
+
case "awaiting-ci":
|
|
106086
|
+
return "awaiting-ci";
|
|
106087
|
+
case "review":
|
|
106088
|
+
return "review";
|
|
106089
|
+
case "quarantined":
|
|
106090
|
+
return "quarantined";
|
|
106091
|
+
case "preempting":
|
|
106092
|
+
case "routing-after-preempt":
|
|
106093
|
+
return "working";
|
|
106094
|
+
case "done":
|
|
106095
|
+
return "done";
|
|
106096
|
+
case "error":
|
|
106097
|
+
return "error";
|
|
106098
|
+
default:
|
|
106099
|
+
return "working";
|
|
106100
|
+
}
|
|
106101
|
+
}
|
|
106102
|
+
var STATUS_GLYPH, PIPELINE_NODES;
|
|
106103
|
+
var init_task_pipeline = __esm(() => {
|
|
106104
|
+
STATUS_GLYPH = {
|
|
106105
|
+
done: "\u2713",
|
|
106106
|
+
current: "\u25CF",
|
|
106107
|
+
pending: "\u25CB",
|
|
106108
|
+
failed: "\u2717",
|
|
106109
|
+
bailed: "\u26D4"
|
|
106110
|
+
};
|
|
106111
|
+
PIPELINE_NODES = [
|
|
106112
|
+
"todo",
|
|
106113
|
+
"confirmation",
|
|
106114
|
+
"work",
|
|
106115
|
+
"PR",
|
|
106116
|
+
"CI",
|
|
106117
|
+
"done"
|
|
106118
|
+
];
|
|
106119
|
+
});
|
|
106120
|
+
|
|
105477
106121
|
// packages/core/src/ordering/hierarchical-order.ts
|
|
105478
106122
|
function rank(priority) {
|
|
105479
106123
|
return !priority ? Number.POSITIVE_INFINITY : priority;
|
|
@@ -105735,12 +106379,13 @@ var init_queue_order = __esm(() => {
|
|
|
105735
106379
|
});
|
|
105736
106380
|
|
|
105737
106381
|
// apps/agent/src/runtime/coordinator.ts
|
|
106382
|
+
import { appendFile as appendFile2 } from "fs/promises";
|
|
105738
106383
|
function emitCapture(bus, event, properties) {
|
|
105739
106384
|
capture(event, properties);
|
|
105740
106385
|
bus.emit({ type: event, ...properties });
|
|
105741
106386
|
}
|
|
105742
106387
|
function completionCommentBody(args) {
|
|
105743
|
-
const { noChanges, ok, trigger, changeName, code } = args;
|
|
106388
|
+
const { noChanges, ok, trigger, changeName, code, reachedDone } = args;
|
|
105744
106389
|
if (noChanges) {
|
|
105745
106390
|
return buildRalphyComment({
|
|
105746
106391
|
type: "completed-noop",
|
|
@@ -105767,6 +106412,23 @@ function completionCommentBody(args) {
|
|
|
105767
106412
|
fields: { change: changeName }
|
|
105768
106413
|
});
|
|
105769
106414
|
}
|
|
106415
|
+
if (trigger === "ci-fix") {
|
|
106416
|
+
return buildRalphyComment({
|
|
106417
|
+
type: "ci-fix-pushed",
|
|
106418
|
+
action: "pushed a CI fix",
|
|
106419
|
+
body: `Pushed a fix for the failing CI on this PR \u2014 re-checking the checks on the ` + `next poll before marking this done. Change: \`${changeName}\``,
|
|
106420
|
+
fields: { change: changeName }
|
|
106421
|
+
});
|
|
106422
|
+
}
|
|
106423
|
+
if (!reachedDone) {
|
|
106424
|
+
const isReview = trigger === "review";
|
|
106425
|
+
return buildRalphyComment({
|
|
106426
|
+
type: "awaiting-ci",
|
|
106427
|
+
action: isReview ? "addressed review feedback" : "opened a PR",
|
|
106428
|
+
body: (isReview ? `Pushed changes for the review feedback to this PR. ` : `Finished the work and opened a PR. `) + `Awaiting CI, review, and a clean merge state before marking this done. ` + `Change: \`${changeName}\``,
|
|
106429
|
+
fields: { change: changeName }
|
|
106430
|
+
});
|
|
106431
|
+
}
|
|
105770
106432
|
return buildRalphyComment({
|
|
105771
106433
|
type: "completed",
|
|
105772
106434
|
action: "completed work",
|
|
@@ -105799,7 +106461,19 @@ class AgentCoordinator {
|
|
|
105799
106461
|
this.opts = opts;
|
|
105800
106462
|
this.bus = deps.bus ?? createNoopBus();
|
|
105801
106463
|
const providedMachine = flowMachine.provide({ actors: { preemption: preemptionActorLogic } });
|
|
105802
|
-
this.flowStore = new FlowActorStore({
|
|
106464
|
+
this.flowStore = new FlowActorStore({
|
|
106465
|
+
bus: this.bus,
|
|
106466
|
+
persist: () => {},
|
|
106467
|
+
maxRecoveryAttempts: this.opts.prRecovery?.maxRecoverySessions ?? 0,
|
|
106468
|
+
onTransition: (_issueId, changeDir, transition2) => {
|
|
106469
|
+
if (!changeDir)
|
|
106470
|
+
return;
|
|
106471
|
+
const path = `${changeDir}/.ralph-state.flow-history.jsonl`;
|
|
106472
|
+
const line = `${JSON.stringify({ ts: new Date().toISOString(), ...transition2 })}
|
|
106473
|
+
`;
|
|
106474
|
+
appendFile2(path, line).catch(() => {});
|
|
106475
|
+
}
|
|
106476
|
+
}, providedMachine);
|
|
105803
106477
|
}
|
|
105804
106478
|
get activeCount() {
|
|
105805
106479
|
return this.workers.length;
|
|
@@ -105871,7 +106545,15 @@ class AgentCoordinator {
|
|
|
105871
106545
|
awaiting: awaitingCount
|
|
105872
106546
|
};
|
|
105873
106547
|
const found2 = buckets2.todo + buckets2.inProgress + buckets2.mentions + buckets2.awaiting;
|
|
105874
|
-
return {
|
|
106548
|
+
return {
|
|
106549
|
+
found: found2,
|
|
106550
|
+
added: 0,
|
|
106551
|
+
buckets: buckets2,
|
|
106552
|
+
prStatus: emptyPrStatus(),
|
|
106553
|
+
phase: {},
|
|
106554
|
+
flow: {},
|
|
106555
|
+
board: []
|
|
106556
|
+
};
|
|
105875
106557
|
}
|
|
105876
106558
|
const maxT = this.opts.maxTickets ?? 0;
|
|
105877
106559
|
const atTicketLimit = () => {
|
|
@@ -105950,7 +106632,7 @@ class AgentCoordinator {
|
|
|
105950
106632
|
added += 1;
|
|
105951
106633
|
this.deps.onLog(` \u21B3 ${issue2.identifier} queued (fresh)`, "gray");
|
|
105952
106634
|
}
|
|
105953
|
-
const prStatus = await this.scanPrMergeStates();
|
|
106635
|
+
const { counts: prStatus, prByIssue } = await this.scanPrMergeStates();
|
|
105954
106636
|
if (this.queue.length > 0) {
|
|
105955
106637
|
this.queue = orderQueueEntries(this.queue, this.opts.getAutoMerge);
|
|
105956
106638
|
}
|
|
@@ -105980,7 +106662,103 @@ class AgentCoordinator {
|
|
|
105980
106662
|
flow2[w.changeName] = "working";
|
|
105981
106663
|
}
|
|
105982
106664
|
}
|
|
105983
|
-
|
|
106665
|
+
const board = await this.buildBoard({
|
|
106666
|
+
todo,
|
|
106667
|
+
inProgress,
|
|
106668
|
+
mentions,
|
|
106669
|
+
prByIssue,
|
|
106670
|
+
awaitingIds: awaitingClaimed
|
|
106671
|
+
});
|
|
106672
|
+
return { found, added, buckets, prStatus, phase: {}, flow: flow2, board };
|
|
106673
|
+
}
|
|
106674
|
+
async buildBoard(args) {
|
|
106675
|
+
const { todo, inProgress, mentions, prByIssue, awaitingIds } = args;
|
|
106676
|
+
const order = [
|
|
106677
|
+
...this.workers.map((w) => ({
|
|
106678
|
+
issue: w.issue,
|
|
106679
|
+
kind: "worker",
|
|
106680
|
+
changeName: w.changeName
|
|
106681
|
+
})),
|
|
106682
|
+
...this.queue.map((q) => ({
|
|
106683
|
+
issue: q.issue,
|
|
106684
|
+
kind: "queued",
|
|
106685
|
+
changeName: changeNameForIssue(q.issue)
|
|
106686
|
+
})),
|
|
106687
|
+
...inProgress.map((issue2) => ({
|
|
106688
|
+
issue: issue2,
|
|
106689
|
+
kind: awaitingIds.has(issue2.id) ? "awaiting" : "in-progress",
|
|
106690
|
+
changeName: changeNameForIssue(issue2)
|
|
106691
|
+
})),
|
|
106692
|
+
...todo.map((issue2) => ({
|
|
106693
|
+
issue: issue2,
|
|
106694
|
+
kind: "todo",
|
|
106695
|
+
changeName: changeNameForIssue(issue2)
|
|
106696
|
+
})),
|
|
106697
|
+
...mentions.map((m) => ({
|
|
106698
|
+
issue: m.issue,
|
|
106699
|
+
kind: "mention",
|
|
106700
|
+
changeName: changeNameForIssue(m.issue)
|
|
106701
|
+
}))
|
|
106702
|
+
];
|
|
106703
|
+
const seen = new Set;
|
|
106704
|
+
const rows = [];
|
|
106705
|
+
for (const src of order) {
|
|
106706
|
+
if (seen.has(src.issue.id))
|
|
106707
|
+
continue;
|
|
106708
|
+
seen.add(src.issue.id);
|
|
106709
|
+
const row = await this.resolveBoardRow(src.issue, src.kind, src.changeName, prByIssue);
|
|
106710
|
+
if (row)
|
|
106711
|
+
rows.push(row);
|
|
106712
|
+
}
|
|
106713
|
+
return rows;
|
|
106714
|
+
}
|
|
106715
|
+
async resolveBoardRow(issue2, kind, changeName, prByIssue) {
|
|
106716
|
+
let state;
|
|
106717
|
+
let recovery;
|
|
106718
|
+
if (kind === "todo") {
|
|
106719
|
+
state = "todo";
|
|
106720
|
+
} else if (kind === "mention") {
|
|
106721
|
+
state = "review";
|
|
106722
|
+
} else if (kind === "awaiting") {
|
|
106723
|
+
state = "awaiting";
|
|
106724
|
+
} else if (kind !== "worker" && issue2.blockedByIds.length > 0) {
|
|
106725
|
+
state = "todo";
|
|
106726
|
+
} else {
|
|
106727
|
+
const changeDir = this.deps.getChangeDir?.(issue2) ?? undefined;
|
|
106728
|
+
const actor = await this.flowStore.getActor(issue2.id, changeDir);
|
|
106729
|
+
const snapshot = actor.getSnapshot();
|
|
106730
|
+
state = machineStateToTicketState(snapshot.value);
|
|
106731
|
+
if (state === "done")
|
|
106732
|
+
return null;
|
|
106733
|
+
if (kind === "queued" && (state === "working" || state === "in-progress"))
|
|
106734
|
+
state = "queued";
|
|
106735
|
+
const flowRecovery = snapshot.context.data.recovery;
|
|
106736
|
+
if (flowRecovery) {
|
|
106737
|
+
recovery = {
|
|
106738
|
+
attempts: flowRecovery.attempts,
|
|
106739
|
+
bailed: state === "quarantined",
|
|
106740
|
+
firstFailedAt: flowRecovery.firstFailedAt,
|
|
106741
|
+
lastReason: flowRecovery.lastReason
|
|
106742
|
+
};
|
|
106743
|
+
if (state === "awaiting-ci" || state === "in-progress" || state === "working") {
|
|
106744
|
+
state = flowRecovery.lastReason === "conflicting" ? "conflict-fix" : "ci-fix";
|
|
106745
|
+
}
|
|
106746
|
+
}
|
|
106747
|
+
}
|
|
106748
|
+
const prUrl = prByIssue.get(issue2.id)?.url;
|
|
106749
|
+
return {
|
|
106750
|
+
changeName,
|
|
106751
|
+
id: issue2.id,
|
|
106752
|
+
identifier: issue2.identifier,
|
|
106753
|
+
title: issue2.title,
|
|
106754
|
+
url: issue2.url,
|
|
106755
|
+
priority: issue2.priority,
|
|
106756
|
+
state,
|
|
106757
|
+
blockedByIds: issue2.blockedByIds,
|
|
106758
|
+
blockedByIdentifiers: issue2.blockedByIdentifiers ?? [],
|
|
106759
|
+
...recovery ? { recovery } : {},
|
|
106760
|
+
...prUrl ? { prUrl } : {}
|
|
106761
|
+
};
|
|
105984
106762
|
}
|
|
105985
106763
|
async walkRegistryForInProgress(inProgress) {
|
|
105986
106764
|
const claimed = new Map;
|
|
@@ -106191,20 +106969,20 @@ class AgentCoordinator {
|
|
|
106191
106969
|
}
|
|
106192
106970
|
async scanPrMergeStates() {
|
|
106193
106971
|
const counts = emptyPrStatus();
|
|
106972
|
+
const prByIssue = new Map;
|
|
106194
106973
|
if (!this.opts.prRecovery?.enabled)
|
|
106195
|
-
return counts;
|
|
106974
|
+
return { counts, prByIssue };
|
|
106196
106975
|
let candidates = [];
|
|
106197
106976
|
try {
|
|
106198
106977
|
candidates = await this.deps.fetchDoneCandidates();
|
|
106199
106978
|
} catch (err) {
|
|
106200
106979
|
this.deps.onLog(`! PR merge-state scan fetch failed: ${err.message}`, "yellow");
|
|
106201
|
-
return counts;
|
|
106980
|
+
return { counts, prByIssue };
|
|
106202
106981
|
}
|
|
106203
106982
|
if (candidates.length === 0)
|
|
106204
|
-
return counts;
|
|
106983
|
+
return { counts, prByIssue };
|
|
106205
106984
|
const preQueue = this.queue.map((q) => ({ id: q.issue.id, trigger: q.trigger }));
|
|
106206
106985
|
const preWorkers = this.workers.map((w) => ({ id: w.issueId, trigger: w.trigger }));
|
|
106207
|
-
const tracker = this.opts.prTracker;
|
|
106208
106986
|
for (const issue2 of candidates) {
|
|
106209
106987
|
if (this.workers.some((w) => w.issueId === issue2.id))
|
|
106210
106988
|
continue;
|
|
@@ -106212,12 +106990,17 @@ class AgentCoordinator {
|
|
|
106212
106990
|
continue;
|
|
106213
106991
|
if (this.queue.some((q) => q.issue.id === issue2.id))
|
|
106214
106992
|
continue;
|
|
106215
|
-
|
|
106216
|
-
|
|
106993
|
+
const changeDir = this.deps.getChangeDir?.(issue2) ?? undefined;
|
|
106994
|
+
const actor = await this.flowStore.getActor(issue2.id, changeDir);
|
|
106995
|
+
const stateValue = () => actor.getSnapshot().value;
|
|
106996
|
+
if (stateValue() === "quarantined" && this.errorMarkerCleared(issue2)) {
|
|
106997
|
+
actor.send({ type: "QUARANTINE_CLEARED" });
|
|
106998
|
+
if (changeDir)
|
|
106999
|
+
await this.flowStore.persistActor(issue2.id, changeDir).catch(() => {});
|
|
106217
107000
|
this.conflictNotified.delete(issue2.id);
|
|
106218
107001
|
this.ciFailedNotified.delete(issue2.id);
|
|
106219
107002
|
this.conflictPromoted.delete(issue2.id);
|
|
106220
|
-
this.deps.onLog(` ${issue2.identifier}:
|
|
107003
|
+
this.deps.onLog(` ${issue2.identifier}: quarantine cleared (ralph:error removed) \u2014 retrying recovery`, "cyan");
|
|
106221
107004
|
}
|
|
106222
107005
|
let pr;
|
|
106223
107006
|
try {
|
|
@@ -106228,45 +107011,47 @@ class AgentCoordinator {
|
|
|
106228
107011
|
}
|
|
106229
107012
|
if (!pr)
|
|
106230
107013
|
continue;
|
|
107014
|
+
prByIssue.set(issue2.id, pr);
|
|
106231
107015
|
if (pr.status === "mergeable")
|
|
106232
107016
|
counts.mergeable += 1;
|
|
106233
|
-
if (pr.status === "mergeable" && this.opts.prTracker) {
|
|
106234
|
-
try {
|
|
106235
|
-
await this.opts.prTracker.clear(issue2.identifier);
|
|
106236
|
-
} catch (err) {
|
|
106237
|
-
this.deps.onLog(`! pr-tracker clear failed for ${issue2.identifier}: ${err.message}`, "yellow");
|
|
106238
|
-
}
|
|
106239
|
-
}
|
|
106240
107017
|
if (pr.status === "mergeable") {
|
|
106241
|
-
const
|
|
106242
|
-
|
|
106243
|
-
if (actor.getSnapshot().value === "awaiting-ci") {
|
|
107018
|
+
const value = stateValue();
|
|
107019
|
+
if (value === "awaiting-ci" || value === "quarantined") {
|
|
106244
107020
|
if (this.issueInSetDoneState(issue2)) {
|
|
107021
|
+
actor.send({ type: "RECOVERY_CLEARED" });
|
|
106245
107022
|
actor.send({ type: "PR_PASSED" });
|
|
106246
107023
|
if (changeDir)
|
|
106247
107024
|
await this.flowStore.persistActor(issue2.id, changeDir).catch(() => {});
|
|
106248
|
-
if (
|
|
107025
|
+
if (stateValue() === "done")
|
|
106249
107026
|
this.flowStore.disposeActor(issue2.id);
|
|
106250
|
-
}
|
|
106251
107027
|
} else {
|
|
106252
107028
|
await this.advancePrToDone(issue2, pr.url, actor, changeDir);
|
|
106253
107029
|
}
|
|
107030
|
+
} else {
|
|
107031
|
+
actor.send({ type: "RECOVERY_CLEARED" });
|
|
107032
|
+
if (changeDir)
|
|
107033
|
+
await this.flowStore.persistActor(issue2.id, changeDir).catch(() => {});
|
|
106254
107034
|
}
|
|
106255
107035
|
continue;
|
|
106256
107036
|
}
|
|
106257
107037
|
if (pr.status === "conflicted") {
|
|
106258
107038
|
if (!this.opts.prRecovery?.fixConflicts)
|
|
106259
107039
|
continue;
|
|
106260
|
-
if (
|
|
107040
|
+
if (stateValue() === "quarantined") {
|
|
106261
107041
|
counts.quarantined += 1;
|
|
106262
107042
|
continue;
|
|
106263
107043
|
}
|
|
106264
107044
|
counts.conflicted += 1;
|
|
106265
107045
|
if (this.conflictNotified.has(issue2.id))
|
|
106266
107046
|
continue;
|
|
106267
|
-
|
|
107047
|
+
actor.send({ type: "RESUME_DETECTED" });
|
|
107048
|
+
actor.send({ type: "CONFLICT_DETECTED", at: new Date().toISOString() });
|
|
107049
|
+
if (changeDir)
|
|
107050
|
+
await this.flowStore.persistActor(issue2.id, changeDir).catch(() => {});
|
|
107051
|
+
if (stateValue() === "quarantined") {
|
|
106268
107052
|
counts.conflicted -= 1;
|
|
106269
107053
|
counts.quarantined += 1;
|
|
107054
|
+
await this.quarantineBail(issue2, pr.url, "conflicting", actor);
|
|
106270
107055
|
continue;
|
|
106271
107056
|
}
|
|
106272
107057
|
emitCapture(this.bus, "agent_conflict_detected", { issue_identifier: issue2.identifier });
|
|
@@ -106284,9 +107069,6 @@ class AgentCoordinator {
|
|
|
106284
107069
|
this.deps.onLog(`! Linear conflict comment failed for ${issue2.identifier}: ${err.message}`, "yellow");
|
|
106285
107070
|
}
|
|
106286
107071
|
}
|
|
106287
|
-
const conflictActor = await this.flowStore.getActor(issue2.id, this.deps.getChangeDir?.(issue2) ?? undefined);
|
|
106288
|
-
conflictActor.send({ type: "RESUME_DETECTED" });
|
|
106289
|
-
conflictActor.send({ type: "CONFLICT_DETECTED" });
|
|
106290
107072
|
this.queue.push({
|
|
106291
107073
|
issue: issue2,
|
|
106292
107074
|
trigger: "conflict-fix",
|
|
@@ -106297,16 +107079,21 @@ class AgentCoordinator {
|
|
|
106297
107079
|
if (pr.status === "ci_failed") {
|
|
106298
107080
|
if (!this.opts.prRecovery?.fixCi)
|
|
106299
107081
|
continue;
|
|
106300
|
-
if (
|
|
107082
|
+
if (stateValue() === "quarantined") {
|
|
106301
107083
|
counts.quarantined += 1;
|
|
106302
107084
|
continue;
|
|
106303
107085
|
}
|
|
106304
107086
|
counts.ciFailed += 1;
|
|
106305
107087
|
if (this.ciFailedNotified.has(issue2.id))
|
|
106306
107088
|
continue;
|
|
106307
|
-
|
|
107089
|
+
actor.send({ type: "RESUME_DETECTED" });
|
|
107090
|
+
actor.send({ type: "CI_FAILED_DETECTED", at: new Date().toISOString() });
|
|
107091
|
+
if (changeDir)
|
|
107092
|
+
await this.flowStore.persistActor(issue2.id, changeDir).catch(() => {});
|
|
107093
|
+
if (stateValue() === "quarantined") {
|
|
106308
107094
|
counts.ciFailed -= 1;
|
|
106309
107095
|
counts.quarantined += 1;
|
|
107096
|
+
await this.quarantineBail(issue2, pr.url, "ci_failed", actor);
|
|
106310
107097
|
continue;
|
|
106311
107098
|
}
|
|
106312
107099
|
emitCapture(this.bus, "agent_ci_failed_detected", { issue_identifier: issue2.identifier });
|
|
@@ -106324,9 +107111,6 @@ class AgentCoordinator {
|
|
|
106324
107111
|
this.deps.onLog(`! Linear ci-failed comment failed for ${issue2.identifier}: ${err.message}`, "yellow");
|
|
106325
107112
|
}
|
|
106326
107113
|
}
|
|
106327
|
-
const ciActor = await this.flowStore.getActor(issue2.id, this.deps.getChangeDir?.(issue2) ?? undefined);
|
|
106328
|
-
ciActor.send({ type: "RESUME_DETECTED" });
|
|
106329
|
-
ciActor.send({ type: "CI_FAILED_DETECTED" });
|
|
106330
107114
|
this.queue.push({
|
|
106331
107115
|
issue: issue2,
|
|
106332
107116
|
trigger: "ci-fix",
|
|
@@ -106346,7 +107130,7 @@ class AgentCoordinator {
|
|
|
106346
107130
|
else if (w.trigger === "ci-fix")
|
|
106347
107131
|
counts.ciFailed += 1;
|
|
106348
107132
|
}
|
|
106349
|
-
return counts;
|
|
107133
|
+
return { counts, prByIssue };
|
|
106350
107134
|
}
|
|
106351
107135
|
issueInSetDoneState(issue2) {
|
|
106352
107136
|
const sd = this.opts.setDone;
|
|
@@ -106356,6 +107140,7 @@ class AgentCoordinator {
|
|
|
106356
107140
|
}
|
|
106357
107141
|
async advancePrToDone(issue2, prUrl, actor, changeDir) {
|
|
106358
107142
|
this.deps.onLog(` ${issue2.identifier}: PR ${prUrl} mergeable \u2014 moving to done`, "green");
|
|
107143
|
+
actor.send({ type: "RECOVERY_CLEARED" });
|
|
106359
107144
|
if (this.opts.setDone) {
|
|
106360
107145
|
try {
|
|
106361
107146
|
await this.deps.applyIndicator(issue2, this.opts.setDone);
|
|
@@ -106367,6 +107152,8 @@ class AgentCoordinator {
|
|
|
106367
107152
|
issue_identifier: issue2.identifier,
|
|
106368
107153
|
error: err.message
|
|
106369
107154
|
});
|
|
107155
|
+
if (changeDir)
|
|
107156
|
+
await this.flowStore.persistActor(issue2.id, changeDir).catch(() => {});
|
|
106370
107157
|
return;
|
|
106371
107158
|
}
|
|
106372
107159
|
if (this.opts.setInProgress) {
|
|
@@ -106406,48 +107193,34 @@ class AgentCoordinator {
|
|
|
106406
107193
|
const have = new Set(issue2.labels.map((l) => l.toLowerCase()));
|
|
106407
107194
|
return !wantLabels.some((v) => have.has(v));
|
|
106408
107195
|
}
|
|
106409
|
-
async
|
|
106410
|
-
const
|
|
106411
|
-
|
|
106412
|
-
|
|
106413
|
-
|
|
106414
|
-
|
|
106415
|
-
|
|
106416
|
-
}
|
|
106417
|
-
|
|
106418
|
-
|
|
106419
|
-
|
|
106420
|
-
|
|
106421
|
-
|
|
106422
|
-
if (decision.firstBail) {
|
|
106423
|
-
this.deps.onLog(` ${issue2.identifier}: pr-tracker bailing after ${decision.attempts} recovery attempts (${reason}) \u2014 applying setError`, "red");
|
|
106424
|
-
emitCapture(this.bus, "agent_pr_tracker_bailed", {
|
|
106425
|
-
issue_identifier: issue2.identifier,
|
|
106426
|
-
reason,
|
|
106427
|
-
attempts: decision.attempts
|
|
106428
|
-
});
|
|
106429
|
-
if (this.opts.setError) {
|
|
106430
|
-
try {
|
|
106431
|
-
await this.deps.applyIndicator(issue2, this.opts.setError);
|
|
106432
|
-
} catch (err) {
|
|
106433
|
-
this.deps.onLog(`! Linear setError failed for ${issue2.identifier}: ${err.message}`, "yellow");
|
|
106434
|
-
}
|
|
107196
|
+
async quarantineBail(issue2, prUrl, reason, actor) {
|
|
107197
|
+
const attempts = actor.getSnapshot().context.data.recovery?.attempts ?? 0;
|
|
107198
|
+
this.deps.onLog(` ${issue2.identifier}: quarantined after ${attempts} recovery attempts (${reason}) \u2014 applying setError`, "red");
|
|
107199
|
+
emitCapture(this.bus, "agent_pr_tracker_bailed", {
|
|
107200
|
+
issue_identifier: issue2.identifier,
|
|
107201
|
+
reason,
|
|
107202
|
+
attempts
|
|
107203
|
+
});
|
|
107204
|
+
if (this.opts.setError) {
|
|
107205
|
+
try {
|
|
107206
|
+
await this.deps.applyIndicator(issue2, this.opts.setError);
|
|
107207
|
+
} catch (err) {
|
|
107208
|
+
this.deps.onLog(`! Linear setError failed for ${issue2.identifier}: ${err.message}`, "yellow");
|
|
106435
107209
|
}
|
|
106436
|
-
|
|
106437
|
-
|
|
106438
|
-
|
|
106439
|
-
|
|
106440
|
-
|
|
106441
|
-
|
|
106442
|
-
|
|
106443
|
-
|
|
106444
|
-
}
|
|
106445
|
-
}
|
|
106446
|
-
|
|
106447
|
-
}
|
|
107210
|
+
}
|
|
107211
|
+
if (this.opts.postComments !== false) {
|
|
107212
|
+
const human = reason === "conflicting" ? "merge conflicts" : "failing CI";
|
|
107213
|
+
try {
|
|
107214
|
+
await this.deps.postComment(issue2, buildRalphyComment({
|
|
107215
|
+
type: "recovery-gaveup",
|
|
107216
|
+
action: "gave up auto-recovering PR",
|
|
107217
|
+
body: `Gave up auto-recovering this PR (${prUrl}) after ${attempts} attempts \u2014 last failure: ${human}. The \`ralph:error\` label has been applied; clear it (or merge the PR) once a human has looked at it.`,
|
|
107218
|
+
fields: { pr: extractPrNumber(prUrl) ?? prUrl, attempts }
|
|
107219
|
+
}));
|
|
107220
|
+
} catch (err) {
|
|
107221
|
+
this.deps.onLog(`! Linear bail comment failed for ${issue2.identifier}: ${err.message}`, "yellow");
|
|
106448
107222
|
}
|
|
106449
107223
|
}
|
|
106450
|
-
return true;
|
|
106451
107224
|
}
|
|
106452
107225
|
spawnNext() {
|
|
106453
107226
|
if (this.stopped)
|
|
@@ -106762,7 +107535,14 @@ class AgentCoordinator {
|
|
|
106762
107535
|
}
|
|
106763
107536
|
}
|
|
106764
107537
|
if (this.opts.postComments !== false) {
|
|
106765
|
-
const body = completionCommentBody({
|
|
107538
|
+
const body = completionCommentBody({
|
|
107539
|
+
noChanges,
|
|
107540
|
+
ok,
|
|
107541
|
+
trigger,
|
|
107542
|
+
changeName,
|
|
107543
|
+
code,
|
|
107544
|
+
reachedDone: exitActorState === "done"
|
|
107545
|
+
});
|
|
106766
107546
|
try {
|
|
106767
107547
|
await this.deps.postComment(issue2, body);
|
|
106768
107548
|
this.deps.onLog(` ${issue2.identifier}: posted completion comment`, "gray");
|
|
@@ -106856,12 +107636,15 @@ var emptyPrStatus = () => ({
|
|
|
106856
107636
|
},
|
|
106857
107637
|
prStatus: emptyPrStatus(),
|
|
106858
107638
|
phase: {},
|
|
106859
|
-
flow: {}
|
|
107639
|
+
flow: {},
|
|
107640
|
+
board: []
|
|
106860
107641
|
});
|
|
106861
107642
|
var init_coordinator = __esm(() => {
|
|
106862
107643
|
init_types2();
|
|
106863
107644
|
init_linear_client();
|
|
106864
107645
|
init_post_task();
|
|
107646
|
+
init_scaffold();
|
|
107647
|
+
init_task_pipeline();
|
|
106865
107648
|
init_queue_order();
|
|
106866
107649
|
init_src();
|
|
106867
107650
|
init_src2();
|
|
@@ -106876,122 +107659,6 @@ var init_coordinator2 = __esm(() => {
|
|
|
106876
107659
|
init_coordinator();
|
|
106877
107660
|
});
|
|
106878
107661
|
|
|
106879
|
-
// apps/agent/src/shared/capabilities/gh-client.ts
|
|
106880
|
-
var init_gh_client = () => {};
|
|
106881
|
-
|
|
106882
|
-
// apps/agent/src/shared/capabilities/github/github-client.ts
|
|
106883
|
-
var STARTED_LABEL_NAMES, ISSUE_FIELDS = "id,number,title,body,state,stateReason,labels,assignees,author,createdAt,url", ISSUE_FIELDS_WITH_COMMENTS;
|
|
106884
|
-
var init_github_client = __esm(() => {
|
|
106885
|
-
init_worktree();
|
|
106886
|
-
init_gh_client();
|
|
106887
|
-
STARTED_LABEL_NAMES = new Set(["in progress", "in-progress", "started"]);
|
|
106888
|
-
ISSUE_FIELDS_WITH_COMMENTS = `${ISSUE_FIELDS},comments`;
|
|
106889
|
-
});
|
|
106890
|
-
|
|
106891
|
-
// apps/agent/src/shared/capabilities/github/identifier-strategy.ts
|
|
106892
|
-
function linearChangeName(issue2) {
|
|
106893
|
-
const slug = issue2.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 40).replace(/^-+|-+$/g, "");
|
|
106894
|
-
return slug ? `${issue2.identifier.toLowerCase()}-${slug}` : issue2.identifier.toLowerCase();
|
|
106895
|
-
}
|
|
106896
|
-
var linearIdentifierStrategy;
|
|
106897
|
-
var init_identifier_strategy = __esm(() => {
|
|
106898
|
-
init_worktree();
|
|
106899
|
-
init_github_client();
|
|
106900
|
-
linearIdentifierStrategy = {
|
|
106901
|
-
scopeKey: (issue2) => issue2.identifier.split("-")[0],
|
|
106902
|
-
changeName: linearChangeName,
|
|
106903
|
-
branchName: (issue2) => branchForChange(linearChangeName(issue2))
|
|
106904
|
-
};
|
|
106905
|
-
});
|
|
106906
|
-
|
|
106907
|
-
// apps/agent/src/agent/scaffold.ts
|
|
106908
|
-
import { join as join24 } from "path";
|
|
106909
|
-
function changeNameForIssue(issue2) {
|
|
106910
|
-
return linearIdentifierStrategy.changeName(issue2);
|
|
106911
|
-
}
|
|
106912
|
-
async function scaffoldChangeForIssue(tasksDir, statesDir, issue2, comments = [], appendPrompt = "", attachments = []) {
|
|
106913
|
-
const name = changeNameForIssue(issue2);
|
|
106914
|
-
const changeDir = join24(tasksDir, name);
|
|
106915
|
-
const stateDir = join24(statesDir, name);
|
|
106916
|
-
const commentsBlock = comments.length > 0 ? [
|
|
106917
|
-
"",
|
|
106918
|
-
"## Linear comments",
|
|
106919
|
-
"",
|
|
106920
|
-
...comments.flatMap((c) => [
|
|
106921
|
-
`**${c.user?.name ?? "unknown"}** \u2014 ${c.createdAt}`,
|
|
106922
|
-
"",
|
|
106923
|
-
c.body.trim(),
|
|
106924
|
-
""
|
|
106925
|
-
])
|
|
106926
|
-
] : [];
|
|
106927
|
-
const attachmentsBlock = attachments.length > 0 ? [
|
|
106928
|
-
"",
|
|
106929
|
-
"## Ticket Attachments",
|
|
106930
|
-
"",
|
|
106931
|
-
...attachments.map((a) => `- [${a.title ?? "Attachment"}](${a.url})`)
|
|
106932
|
-
] : [];
|
|
106933
|
-
const descriptionBody = issue2.description?.trim() || "_No description provided in Linear._";
|
|
106934
|
-
const proposal = [
|
|
106935
|
-
`# ${issue2.identifier}: ${issue2.title}`,
|
|
106936
|
-
"",
|
|
106937
|
-
`Source: [${issue2.identifier}](${issue2.url})`,
|
|
106938
|
-
`Status: ${issue2.state.name}`,
|
|
106939
|
-
issue2.assignee ? `Assignee: ${issue2.assignee.name}` : "",
|
|
106940
|
-
issue2.labels.length ? `Labels: ${issue2.labels.join(", ")}` : "",
|
|
106941
|
-
"",
|
|
106942
|
-
"## Why",
|
|
106943
|
-
"",
|
|
106944
|
-
descriptionBody,
|
|
106945
|
-
"",
|
|
106946
|
-
"## What Changes",
|
|
106947
|
-
"",
|
|
106948
|
-
"_Describe the concrete changes this proposal introduces (one bullet per change)._",
|
|
106949
|
-
...commentsBlock,
|
|
106950
|
-
...attachmentsBlock,
|
|
106951
|
-
...appendPrompt.trim() ? ["", "## Additional instructions", "", appendPrompt.trim()] : [],
|
|
106952
|
-
"",
|
|
106953
|
-
"## Steering",
|
|
106954
|
-
"",
|
|
106955
|
-
"_Add steering notes here as the loop runs._",
|
|
106956
|
-
""
|
|
106957
|
-
].filter((l) => l !== "").join(`
|
|
106958
|
-
`);
|
|
106959
|
-
const tasks = [
|
|
106960
|
-
`# Tasks for ${issue2.identifier}`,
|
|
106961
|
-
"",
|
|
106962
|
-
"## Planning",
|
|
106963
|
-
"",
|
|
106964
|
-
`- [ ] Read the Linear issue at ${issue2.url} and research the codebase to understand the mission and its scope`,
|
|
106965
|
-
`- [ ] Refine proposal.md with the problem statement, approach, and acceptance criteria derived from the research`,
|
|
106966
|
-
`- [ ] Fill in \`## Why\` and \`## What Changes\` in proposal.md so \`openspec validate\` passes (these sections are required by the validator)`,
|
|
106967
|
-
`- [ ] Add at least one spec delta under \`specs/<capability>/spec.md\` describing the behavior added/modified/removed by this change`,
|
|
106968
|
-
`- [ ] Fill in design.md with the technical design (files to touch, data flow, edge cases). design.md holds prose and tables ONLY \u2014 never a task checklist; the implementation tasks belong in this tasks.md file (next item).`,
|
|
106969
|
-
`- [ ] Append an \`## Implementation\` section to **this tasks.md file** (below the \`## Planning\` section above \u2014 NOT in design.md) with concrete mission-specific tasks derived from the plan, including tests and \`bun run lint\` / \`bun run test\`. Every item in the new section MUST start as \`- [ ]\` (unchecked) \u2014 do not pre-check items even if you already did the work during planning. The loop ticks them off in later iterations after each one is verified.`,
|
|
106970
|
-
`- [ ] Is there anything else to add? Review the complete change context and document any additional edge cases, constraints, or open questions not captured above.`,
|
|
106971
|
-
""
|
|
106972
|
-
].join(`
|
|
106973
|
-
`);
|
|
106974
|
-
const design = [
|
|
106975
|
-
`# Design for ${issue2.identifier}`,
|
|
106976
|
-
"",
|
|
106977
|
-
"_Fill in the technical design as you work through the issue._",
|
|
106978
|
-
""
|
|
106979
|
-
].join(`
|
|
106980
|
-
`);
|
|
106981
|
-
await runCapability(fsChange.scaffold, {
|
|
106982
|
-
changeDir,
|
|
106983
|
-
stateDir,
|
|
106984
|
-
proposal,
|
|
106985
|
-
tasks,
|
|
106986
|
-
design
|
|
106987
|
-
});
|
|
106988
|
-
return name;
|
|
106989
|
-
}
|
|
106990
|
-
var init_scaffold = __esm(() => {
|
|
106991
|
-
init_fs_change();
|
|
106992
|
-
init_identifier_strategy();
|
|
106993
|
-
});
|
|
106994
|
-
|
|
106995
107662
|
// packages/core/src/detections/tasks.ts
|
|
106996
107663
|
function hasUnchecked(content) {
|
|
106997
107664
|
return /^- \[ \]/m.test(content);
|
|
@@ -107033,13 +107700,8 @@ function gateActive(inputs) {
|
|
|
107033
107700
|
}
|
|
107034
107701
|
|
|
107035
107702
|
// packages/core/src/detections/mention.ts
|
|
107036
|
-
function buildMentionAckComment(
|
|
107037
|
-
|
|
107038
|
-
return buildRalphyComment({
|
|
107039
|
-
type: "mention-ack",
|
|
107040
|
-
action: "picked up your mention",
|
|
107041
|
-
body: greeting
|
|
107042
|
-
});
|
|
107703
|
+
function buildMentionAckComment() {
|
|
107704
|
+
return buildRalphyMarker("mention-ack", { status: "handled" });
|
|
107043
107705
|
}
|
|
107044
107706
|
var init_mention2 = __esm(() => {
|
|
107045
107707
|
init_src8();
|
|
@@ -107051,7 +107713,7 @@ var init_detections = __esm(() => {
|
|
|
107051
107713
|
});
|
|
107052
107714
|
|
|
107053
107715
|
// apps/agent/src/features/confirmation/state.ts
|
|
107054
|
-
import { dirname as
|
|
107716
|
+
import { dirname as dirname9, join as join25 } from "path";
|
|
107055
107717
|
async function readInlineConfirmation(statePath) {
|
|
107056
107718
|
const f2 = Bun.file(statePath);
|
|
107057
107719
|
if (!await f2.exists())
|
|
@@ -107064,7 +107726,7 @@ async function readInlineConfirmation(statePath) {
|
|
|
107064
107726
|
}
|
|
107065
107727
|
}
|
|
107066
107728
|
async function readConfirmationState(statePath) {
|
|
107067
|
-
const changeDir =
|
|
107729
|
+
const changeDir = dirname9(statePath);
|
|
107068
107730
|
const sidecar = await readSlotSidecar(changeDir, "confirmation");
|
|
107069
107731
|
const existing = sidecar ?? await readInlineConfirmation(statePath) ?? null;
|
|
107070
107732
|
const confirmation = {
|
|
@@ -107080,7 +107742,7 @@ async function readConfirmationState(statePath) {
|
|
|
107080
107742
|
return { stateObj: {}, confirmation };
|
|
107081
107743
|
}
|
|
107082
107744
|
async function writeConfirmationState(statePath, _stateObj, confirmation) {
|
|
107083
|
-
await writeSlotField(
|
|
107745
|
+
await writeSlotField(dirname9(statePath), "confirmation", confirmation);
|
|
107084
107746
|
}
|
|
107085
107747
|
async function restartFromDesign(changeDir, changeName) {
|
|
107086
107748
|
const designStub = [
|
|
@@ -107794,7 +108456,7 @@ function createOpenDraftPr(deps) {
|
|
|
107794
108456
|
if (!branch)
|
|
107795
108457
|
return null;
|
|
107796
108458
|
const base2 = baseBranchFromLabels(issue2.labels) ?? deps.prBaseBranch;
|
|
107797
|
-
const result2 = await create3({ cwd: cwd2, branch, issue: issue2, base: base2, draft: true }, deps.cmdRunner);
|
|
108459
|
+
const result2 = await create3({ cwd: cwd2, branch, issue: issue2, base: base2, draft: true, labels: deps.prLabels ?? [] }, deps.cmdRunner);
|
|
107798
108460
|
const url2 = result2?.url ?? null;
|
|
107799
108461
|
if (url2) {
|
|
107800
108462
|
deps.prByChange.set(changeName, url2);
|
|
@@ -107926,7 +108588,7 @@ var init_indicators = __esm(() => {
|
|
|
107926
108588
|
|
|
107927
108589
|
// apps/agent/src/agent/wire/linear-resolvers.ts
|
|
107928
108590
|
function createLinearResolvers(input) {
|
|
107929
|
-
const { apiKey, team, assignee, anyAssignee,
|
|
108591
|
+
const { apiKey, team, assignee, anyAssignee, scope, diag } = input;
|
|
107930
108592
|
const ticketNumbers = input.ticketNumbers ?? [];
|
|
107931
108593
|
const stateCache = new Map;
|
|
107932
108594
|
const labelCache = new Map;
|
|
@@ -108061,7 +108723,7 @@ function createLinearResolvers(input) {
|
|
|
108061
108723
|
team,
|
|
108062
108724
|
assignee,
|
|
108063
108725
|
anyAssignee,
|
|
108064
|
-
|
|
108726
|
+
...scope,
|
|
108065
108727
|
include,
|
|
108066
108728
|
exclude: excl,
|
|
108067
108729
|
...ticketNumbers.length > 0 ? { numbers: ticketNumbers } : {}
|
|
@@ -108084,18 +108746,18 @@ function createLinearResolvers(input) {
|
|
|
108084
108746
|
resolveLabelIdForTeam
|
|
108085
108747
|
};
|
|
108086
108748
|
}
|
|
108087
|
-
function doneCandidateSpec(team, assignee, anyAssignee,
|
|
108749
|
+
function doneCandidateSpec(team, assignee, anyAssignee, scope, include, ticketNumbers) {
|
|
108088
108750
|
return {
|
|
108089
108751
|
team,
|
|
108090
108752
|
assignee,
|
|
108091
108753
|
anyAssignee,
|
|
108092
|
-
|
|
108754
|
+
...scope,
|
|
108093
108755
|
include,
|
|
108094
108756
|
exclude: [],
|
|
108095
108757
|
...ticketNumbers && ticketNumbers.length > 0 ? { numbers: ticketNumbers } : {}
|
|
108096
108758
|
};
|
|
108097
108759
|
}
|
|
108098
|
-
async function fetchDoneCandidatesWith(apiKey, team, assignee, anyAssignee,
|
|
108760
|
+
async function fetchDoneCandidatesWith(apiKey, team, assignee, anyAssignee, scope, indicators, ticketNumbers) {
|
|
108099
108761
|
const getIndicators = [
|
|
108100
108762
|
indicators.getTodo,
|
|
108101
108763
|
indicators.getInProgress,
|
|
@@ -108114,7 +108776,7 @@ async function fetchDoneCandidatesWith(apiKey, team, assignee, anyAssignee, requ
|
|
|
108114
108776
|
const include = ind.filter ?? [];
|
|
108115
108777
|
if (include.length === 0)
|
|
108116
108778
|
return;
|
|
108117
|
-
const issues = await fetchOpenIssues(apiKey, doneCandidateSpec(team, assignee, anyAssignee,
|
|
108779
|
+
const issues = await fetchOpenIssues(apiKey, doneCandidateSpec(team, assignee, anyAssignee, scope, include, ticketNumbers));
|
|
108118
108780
|
for (const issue2 of issues) {
|
|
108119
108781
|
if (!seen.has(issue2.id)) {
|
|
108120
108782
|
seen.add(issue2.id);
|
|
@@ -108295,7 +108957,7 @@ function createLinearTrackerProvider(input) {
|
|
|
108295
108957
|
team,
|
|
108296
108958
|
assignee,
|
|
108297
108959
|
anyAssignee,
|
|
108298
|
-
|
|
108960
|
+
scope,
|
|
108299
108961
|
indicators,
|
|
108300
108962
|
resolvers,
|
|
108301
108963
|
fetchMentions,
|
|
@@ -108308,7 +108970,7 @@ function createLinearTrackerProvider(input) {
|
|
|
108308
108970
|
fetchInProgress: () => resolvers.fetchByGet(indicators.getInProgress, excludeFromInProgress),
|
|
108309
108971
|
fetchReview: () => resolvers.fetchByGet(indicators.getReview, []),
|
|
108310
108972
|
fetchMentions,
|
|
108311
|
-
fetchDoneCandidates: () => fetchDoneCandidatesWith(apiKey, team, assignee, anyAssignee,
|
|
108973
|
+
fetchDoneCandidates: () => fetchDoneCandidatesWith(apiKey, team, assignee, anyAssignee, scope, indicators, ticketNumbers && ticketNumbers.length > 0 ? ticketNumbers : undefined),
|
|
108312
108974
|
applyIndicator: resolvers.applyIndicator,
|
|
108313
108975
|
removeIndicator: resolvers.removeIndicator,
|
|
108314
108976
|
postComment: (issue2, body) => addIssueComment(apiKey, issue2.id, body),
|
|
@@ -108360,7 +109022,7 @@ function createPrepareHelpers(input) {
|
|
|
108360
109022
|
let scaffoldStatesDir = statesDir;
|
|
108361
109023
|
let branch = null;
|
|
108362
109024
|
if (!useWorktree)
|
|
108363
|
-
return { workerCwd, scaffoldTasksDir, scaffoldStatesDir, branch };
|
|
109025
|
+
return { workerCwd, scaffoldTasksDir, scaffoldStatesDir, branch, worktreeCreated: null };
|
|
108364
109026
|
const probeName = worktreeDirNameForIssue(issue2);
|
|
108365
109027
|
const baseBranch = baseBranchFromLabels(issue2.labels) ?? cfg.prBaseBranch;
|
|
108366
109028
|
let wt;
|
|
@@ -108389,10 +109051,10 @@ function createPrepareHelpers(input) {
|
|
|
108389
109051
|
} catch (err) {
|
|
108390
109052
|
diag("worktree", `! seeding .mcp.json failed for ${issue2.identifier}: ${err.message}`, "yellow");
|
|
108391
109053
|
}
|
|
108392
|
-
return { workerCwd, scaffoldTasksDir, scaffoldStatesDir, branch };
|
|
109054
|
+
return { workerCwd, scaffoldTasksDir, scaffoldStatesDir, branch, worktreeCreated: wt.created };
|
|
108393
109055
|
}
|
|
108394
109056
|
async function prepare(issue2) {
|
|
108395
|
-
const { workerCwd, scaffoldTasksDir, scaffoldStatesDir, branch } = await setupWorktree(issue2);
|
|
109057
|
+
const { workerCwd, scaffoldTasksDir, scaffoldStatesDir, branch, worktreeCreated } = await setupWorktree(issue2);
|
|
108396
109058
|
let changeName;
|
|
108397
109059
|
const wtLayoutPre = projectLayout(workerCwd);
|
|
108398
109060
|
const derivedName = changeNameForIssue(issue2);
|
|
@@ -108441,7 +109103,8 @@ function createPrepareHelpers(input) {
|
|
|
108441
109103
|
maps.issueByChange.set(changeName, issue2);
|
|
108442
109104
|
if (branch)
|
|
108443
109105
|
maps.branchByChange.set(changeName, branch);
|
|
108444
|
-
|
|
109106
|
+
const runSetup = worktreeCreated ?? isFresh;
|
|
109107
|
+
if (cfg.setupScript && runSetup) {
|
|
108445
109108
|
await runScript("setup", cfg.setupScript, workerCwd);
|
|
108446
109109
|
}
|
|
108447
109110
|
return {
|
|
@@ -108790,6 +109453,18 @@ function createPrDiscovery(input) {
|
|
|
108790
109453
|
} catch (err) {
|
|
108791
109454
|
diag("ci", `! gh pr checks ${prUrl} failed (PR scan): ${err.message}`, "yellow");
|
|
108792
109455
|
}
|
|
109456
|
+
try {
|
|
109457
|
+
const readiness = await getPollContext().fetchPrOnce(prUrl, ["isDraft", "reviewDecision"], cmdRunner, projectRoot);
|
|
109458
|
+
const isDraft = readiness.isDraft === true;
|
|
109459
|
+
const reviewDecision = readiness.reviewDecision?.toUpperCase();
|
|
109460
|
+
const awaitingApproval = reviewDecision === "REVIEW_REQUIRED" || reviewDecision === "CHANGES_REQUESTED";
|
|
109461
|
+
if (isDraft || awaitingApproval) {
|
|
109462
|
+
diag("pr", ` ${issue2.identifier}: PR ${prUrl} is green + conflict-free but ${isDraft ? "still a draft" : "awaiting review approval"} \u2014 holding (not done) until it is ready`, "gray");
|
|
109463
|
+
return { url: prUrl, status: "unknown" };
|
|
109464
|
+
}
|
|
109465
|
+
} catch (err) {
|
|
109466
|
+
diag("pr", `! gh pr view ${prUrl} readiness check failed (PR scan): ${err.message} \u2014 treating as ready`, "yellow");
|
|
109467
|
+
}
|
|
108793
109468
|
return { url: prUrl, status: "mergeable" };
|
|
108794
109469
|
}
|
|
108795
109470
|
async function resolvePrUrlForIssue(issue2) {
|
|
@@ -108829,17 +109504,17 @@ var init_pr_discovery = __esm(() => {
|
|
|
108829
109504
|
});
|
|
108830
109505
|
|
|
108831
109506
|
// apps/agent/src/features/review-followup/scan.ts
|
|
108832
|
-
import { dirname as
|
|
109507
|
+
import { dirname as dirname10, join as join28 } from "path";
|
|
108833
109508
|
async function resolveReviewStateDir(changeName, deps) {
|
|
108834
109509
|
const root = deps.cwdOf(changeName);
|
|
108835
109510
|
if (root)
|
|
108836
|
-
return
|
|
109511
|
+
return dirname10(projectLayout(root).stateFile(changeName));
|
|
108837
109512
|
if (!deps.useWorktree)
|
|
108838
|
-
return
|
|
109513
|
+
return dirname10(projectLayout(deps.projectRoot).stateFile(changeName));
|
|
108839
109514
|
const wtPath = join28(worktreesDir2(deps.projectRoot), changeName);
|
|
108840
109515
|
const statePath = projectLayout(wtPath).stateFile(changeName);
|
|
108841
109516
|
if (await Bun.file(statePath).exists())
|
|
108842
|
-
return
|
|
109517
|
+
return dirname10(statePath);
|
|
108843
109518
|
return null;
|
|
108844
109519
|
}
|
|
108845
109520
|
async function readReviewWatermark(stateDir) {
|
|
@@ -109086,7 +109761,7 @@ function createMentionScanner(input) {
|
|
|
109086
109761
|
team,
|
|
109087
109762
|
assignee,
|
|
109088
109763
|
anyAssignee,
|
|
109089
|
-
|
|
109764
|
+
scope,
|
|
109090
109765
|
indicators,
|
|
109091
109766
|
projectRoot,
|
|
109092
109767
|
useWorktree,
|
|
@@ -109111,7 +109786,7 @@ function createMentionScanner(input) {
|
|
|
109111
109786
|
team,
|
|
109112
109787
|
assignee,
|
|
109113
109788
|
anyAssignee,
|
|
109114
|
-
...
|
|
109789
|
+
...scope,
|
|
109115
109790
|
...ticketNumbers && ticketNumbers.length > 0 ? { numbers: ticketNumbers } : {},
|
|
109116
109791
|
indicators: {
|
|
109117
109792
|
...indicators.getTodo !== undefined ? { getTodo: indicators.getTodo } : {},
|
|
@@ -109172,7 +109847,7 @@ function createMentionScanner(input) {
|
|
|
109172
109847
|
}
|
|
109173
109848
|
if (cfg.linear.postComments !== false) {
|
|
109174
109849
|
try {
|
|
109175
|
-
await createIssueComment(apiKey, issue2.id, buildMentionAckComment(
|
|
109850
|
+
await createIssueComment(apiKey, issue2.id, buildMentionAckComment());
|
|
109176
109851
|
} catch (err) {
|
|
109177
109852
|
diag("mention", `! mention scan: ack comment failed for ${issue2.identifier}: ${formatLinearError(err)}`, "yellow");
|
|
109178
109853
|
}
|
|
@@ -109221,7 +109896,7 @@ function createMentionScanner(input) {
|
|
|
109221
109896
|
}
|
|
109222
109897
|
}
|
|
109223
109898
|
if (cfg.linear.postComments !== false) {
|
|
109224
|
-
await postGithubPrComment(cmdRunner, projectRoot, prUrl, buildMentionAckComment(
|
|
109899
|
+
await postGithubPrComment(cmdRunner, projectRoot, prUrl, buildMentionAckComment(), onLog);
|
|
109225
109900
|
}
|
|
109226
109901
|
}
|
|
109227
109902
|
queued.add(issue2.id);
|
|
@@ -109636,6 +110311,7 @@ function buildPostTaskInput(input) {
|
|
|
109636
110311
|
finalizeNoOpAsDone: cfg.finalizeNoOpAsDone,
|
|
109637
110312
|
manualMergeWhenAutoMergeDisabled: cfg.manualMergeWhenAutoMergeDisabled,
|
|
109638
110313
|
prDraft: cfg.prDraft,
|
|
110314
|
+
prLabels: cfg.prLabels,
|
|
109639
110315
|
validateCommands: [cfg.commands.test, cfg.commands.lint, cfg.commands.typecheck].filter((c) => Boolean(c))
|
|
109640
110316
|
},
|
|
109641
110317
|
respawnWorker: input.respawnWorker
|
|
@@ -110226,7 +110902,7 @@ var init_linear_sync = __esm(() => {
|
|
|
110226
110902
|
});
|
|
110227
110903
|
|
|
110228
110904
|
// apps/agent/src/agent/linear-sync/comment-sync.ts
|
|
110229
|
-
import { dirname as
|
|
110905
|
+
import { dirname as dirname11, join as join34 } from "path";
|
|
110230
110906
|
async function readInlineLinearComments(statePath) {
|
|
110231
110907
|
const file2 = Bun.file(statePath);
|
|
110232
110908
|
if (!await file2.exists())
|
|
@@ -110239,7 +110915,7 @@ async function readInlineLinearComments(statePath) {
|
|
|
110239
110915
|
}
|
|
110240
110916
|
}
|
|
110241
110917
|
async function readComments(statePath) {
|
|
110242
|
-
const changeDir =
|
|
110918
|
+
const changeDir = dirname11(statePath);
|
|
110243
110919
|
const raw = await readSlotSidecar(changeDir, "linearComments") ?? await readInlineLinearComments(statePath) ?? {};
|
|
110244
110920
|
const r = raw;
|
|
110245
110921
|
return {
|
|
@@ -110252,7 +110928,7 @@ async function readComments(statePath) {
|
|
|
110252
110928
|
async function patchComments(statePath, patch) {
|
|
110253
110929
|
const current = await readComments(statePath);
|
|
110254
110930
|
const next = { ...current, ...patch };
|
|
110255
|
-
await writeSlotField(
|
|
110931
|
+
await writeSlotField(dirname11(statePath), "linearComments", next);
|
|
110256
110932
|
}
|
|
110257
110933
|
function isCommentNotFoundError(err) {
|
|
110258
110934
|
if (!err)
|
|
@@ -262362,22 +263038,20 @@ function renderCodeBlock(doc2, token, indent) {
|
|
|
262362
263038
|
const text = token.text ?? "";
|
|
262363
263039
|
const x2 = MARGIN + indent;
|
|
262364
263040
|
const width = doc2.page.width - 2 * MARGIN - indent;
|
|
263041
|
+
const textWidth = width - 2 * CODE_PADDING_X;
|
|
262365
263042
|
doc2.font(FONT_MONO).fontSize(CODE_SIZE).fillColor(COLOR_TEXT);
|
|
262366
|
-
const lineHeight = doc2.currentLineHeight(true);
|
|
262367
263043
|
const lines = text.split(/\r?\n/);
|
|
262368
263044
|
doc2.y += CODE_PADDING_Y / 2;
|
|
262369
263045
|
for (const line of lines) {
|
|
262370
|
-
|
|
263046
|
+
const safe = toPdfSafe(line.length > 0 ? line : " ");
|
|
263047
|
+
const lineHeight = doc2.heightOfString(safe, { width: textWidth, lineBreak: true });
|
|
263048
|
+
if (doc2.y + lineHeight + CODE_PADDING_Y > doc2.page.height - MARGIN && doc2.y > doc2.page.margins.top) {
|
|
262371
263049
|
doc2.addPage();
|
|
262372
263050
|
}
|
|
262373
263051
|
const yTop = doc2.y;
|
|
262374
|
-
const safe = toPdfSafe(line);
|
|
262375
263052
|
doc2.rect(x2, yTop, width, lineHeight).fill(COLOR_CODE_BG);
|
|
262376
263053
|
doc2.fillColor(COLOR_TEXT);
|
|
262377
|
-
doc2.text(safe
|
|
262378
|
-
width: width - 2 * CODE_PADDING_X,
|
|
262379
|
-
lineBreak: false
|
|
262380
|
-
});
|
|
263054
|
+
doc2.text(safe, x2 + CODE_PADDING_X, yTop, { width: textWidth, lineBreak: true });
|
|
262381
263055
|
doc2.y = yTop + lineHeight;
|
|
262382
263056
|
}
|
|
262383
263057
|
doc2.y += CODE_PADDING_Y / 2;
|
|
@@ -262465,38 +263139,85 @@ function flattenInline(tokens, flags = {}) {
|
|
|
262465
263139
|
}
|
|
262466
263140
|
return out;
|
|
262467
263141
|
}
|
|
263142
|
+
function applyInlineStyle(doc2, run) {
|
|
263143
|
+
if (run.code) {
|
|
263144
|
+
doc2.font(FONT_MONO).fontSize(BODY_SIZE).fillColor(COLOR_INLINE_CODE_FG);
|
|
263145
|
+
return;
|
|
263146
|
+
}
|
|
263147
|
+
doc2.fontSize(BODY_SIZE).fillColor(COLOR_TEXT);
|
|
263148
|
+
if (run.bold && run.italic)
|
|
263149
|
+
doc2.font(FONT_BOLD_ITALIC);
|
|
263150
|
+
else if (run.bold)
|
|
263151
|
+
doc2.font(FONT_BOLD);
|
|
263152
|
+
else if (run.italic)
|
|
263153
|
+
doc2.font(FONT_ITALIC);
|
|
263154
|
+
else
|
|
263155
|
+
doc2.font(FONT_BODY);
|
|
263156
|
+
}
|
|
263157
|
+
function atomizeInline(flat) {
|
|
263158
|
+
const atoms = [];
|
|
263159
|
+
for (const run of flat) {
|
|
263160
|
+
const safe = toPdfSafe(run.text);
|
|
263161
|
+
for (const part of safe.split(/(\n|[ \t]+)/)) {
|
|
263162
|
+
if (part === "")
|
|
263163
|
+
continue;
|
|
263164
|
+
if (part === `
|
|
263165
|
+
`)
|
|
263166
|
+
atoms.push({ text: "", run, space: false, br: true });
|
|
263167
|
+
else if (/^[ \t]+$/.test(part))
|
|
263168
|
+
atoms.push({ text: part, run, space: true, br: false });
|
|
263169
|
+
else
|
|
263170
|
+
atoms.push({ text: part, run, space: false, br: false });
|
|
263171
|
+
}
|
|
263172
|
+
}
|
|
263173
|
+
return atoms;
|
|
263174
|
+
}
|
|
262468
263175
|
function emitInline(doc2, tokens, x2, width) {
|
|
262469
263176
|
const flat = flattenInline(tokens);
|
|
262470
263177
|
if (flat.length === 0)
|
|
262471
263178
|
return;
|
|
262472
|
-
|
|
262473
|
-
|
|
262474
|
-
|
|
262475
|
-
|
|
262476
|
-
|
|
262477
|
-
|
|
262478
|
-
|
|
262479
|
-
|
|
262480
|
-
|
|
262481
|
-
|
|
262482
|
-
|
|
262483
|
-
|
|
262484
|
-
|
|
262485
|
-
|
|
262486
|
-
|
|
262487
|
-
|
|
262488
|
-
|
|
262489
|
-
doc2.font(FONT_ITALIC);
|
|
262490
|
-
else
|
|
262491
|
-
doc2.font(FONT_BODY);
|
|
263179
|
+
const atoms = atomizeInline(flat);
|
|
263180
|
+
if (atoms.length === 0)
|
|
263181
|
+
return;
|
|
263182
|
+
doc2.font(FONT_BODY).fontSize(BODY_SIZE);
|
|
263183
|
+
const lineHeight = doc2.currentLineHeight(true);
|
|
263184
|
+
const right = x2 + width;
|
|
263185
|
+
const bottom = doc2.page.height - MARGIN;
|
|
263186
|
+
let cursorX = x2;
|
|
263187
|
+
let cursorY = doc2.y;
|
|
263188
|
+
let pendingSpace = 0;
|
|
263189
|
+
const newLine = () => {
|
|
263190
|
+
cursorX = x2;
|
|
263191
|
+
cursorY += lineHeight;
|
|
263192
|
+
pendingSpace = 0;
|
|
263193
|
+
if (cursorY + lineHeight > bottom) {
|
|
263194
|
+
doc2.addPage();
|
|
263195
|
+
cursorY = doc2.page.margins.top;
|
|
262492
263196
|
}
|
|
262493
|
-
|
|
262494
|
-
|
|
262495
|
-
|
|
263197
|
+
};
|
|
263198
|
+
for (const atom of atoms) {
|
|
263199
|
+
if (atom.br) {
|
|
263200
|
+
newLine();
|
|
263201
|
+
continue;
|
|
263202
|
+
}
|
|
263203
|
+
applyInlineStyle(doc2, atom.run);
|
|
263204
|
+
if (atom.space) {
|
|
263205
|
+
if (cursorX > x2)
|
|
263206
|
+
pendingSpace += doc2.widthOfString(atom.text);
|
|
263207
|
+
continue;
|
|
263208
|
+
}
|
|
263209
|
+
const wordWidth = doc2.widthOfString(atom.text);
|
|
263210
|
+
if (cursorX > x2 && cursorX + pendingSpace + wordWidth > right + 0.01) {
|
|
263211
|
+
newLine();
|
|
262496
263212
|
} else {
|
|
262497
|
-
|
|
263213
|
+
cursorX += pendingSpace;
|
|
263214
|
+
pendingSpace = 0;
|
|
262498
263215
|
}
|
|
263216
|
+
applyInlineStyle(doc2, atom.run);
|
|
263217
|
+
doc2.text(atom.text, cursorX, cursorY, { lineBreak: false, continued: false });
|
|
263218
|
+
cursorX += wordWidth;
|
|
262499
263219
|
}
|
|
263220
|
+
doc2.y = cursorY + lineHeight;
|
|
262500
263221
|
doc2.font(FONT_BODY).fontSize(BODY_SIZE).fillColor(COLOR_TEXT);
|
|
262501
263222
|
}
|
|
262502
263223
|
function plainInline(tokens) {
|
|
@@ -262676,7 +263397,7 @@ var init_render_pdf = __esm(() => {
|
|
|
262676
263397
|
});
|
|
262677
263398
|
|
|
262678
263399
|
// apps/agent/src/agent/linear-sync/spec-attachments.ts
|
|
262679
|
-
import { dirname as
|
|
263400
|
+
import { dirname as dirname12, join as join35 } from "path";
|
|
262680
263401
|
function describeLinearError(err) {
|
|
262681
263402
|
const e = err;
|
|
262682
263403
|
const parts = [e.message ?? String(err)];
|
|
@@ -262691,7 +263412,7 @@ function describeLinearError(err) {
|
|
|
262691
263412
|
return parts.join(" ");
|
|
262692
263413
|
}
|
|
262693
263414
|
function stateDirOf(statePath) {
|
|
262694
|
-
return
|
|
263415
|
+
return dirname12(statePath);
|
|
262695
263416
|
}
|
|
262696
263417
|
async function readInlineSpecAttachments(statePath) {
|
|
262697
263418
|
const file2 = Bun.file(statePath);
|
|
@@ -262709,7 +263430,7 @@ async function readInlineSpecAttachments(statePath) {
|
|
|
262709
263430
|
}
|
|
262710
263431
|
}
|
|
262711
263432
|
async function readSpecAttachmentsSubtree(statePath) {
|
|
262712
|
-
const sidecar = await readSlotSidecar(
|
|
263433
|
+
const sidecar = await readSlotSidecar(dirname12(statePath), "specAttachments");
|
|
262713
263434
|
return sidecar ?? await readInlineSpecAttachments(statePath);
|
|
262714
263435
|
}
|
|
262715
263436
|
function asRevisions(value) {
|
|
@@ -263201,105 +263922,8 @@ var init_comment_sync2 = __esm(() => {
|
|
|
263201
263922
|
init_linear();
|
|
263202
263923
|
});
|
|
263203
263924
|
|
|
263204
|
-
// apps/agent/src/features/pr-tracker/state.ts
|
|
263205
|
-
import { join as join36 } from "path";
|
|
263206
|
-
async function readState2(projectRoot) {
|
|
263207
|
-
const path = join36(projectRoot, PR_TRACKER_STATE_RELPATH);
|
|
263208
|
-
const file2 = Bun.file(path);
|
|
263209
|
-
if (!await file2.exists())
|
|
263210
|
-
return {};
|
|
263211
|
-
try {
|
|
263212
|
-
const raw = await file2.text();
|
|
263213
|
-
const parsed = JSON.parse(raw);
|
|
263214
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
263215
|
-
return parsed;
|
|
263216
|
-
}
|
|
263217
|
-
return {};
|
|
263218
|
-
} catch {
|
|
263219
|
-
return {};
|
|
263220
|
-
}
|
|
263221
|
-
}
|
|
263222
|
-
async function writeState2(projectRoot, state) {
|
|
263223
|
-
const path = join36(projectRoot, PR_TRACKER_STATE_RELPATH);
|
|
263224
|
-
await Bun.write(path, JSON.stringify(state, null, 2));
|
|
263225
|
-
}
|
|
263226
|
-
var PR_TRACKER_STATE_RELPATH = ".ralph/pr-tracker-state.json";
|
|
263227
|
-
var init_state3 = () => {};
|
|
263228
|
-
|
|
263229
|
-
// apps/agent/src/features/pr-tracker/tracker.ts
|
|
263230
|
-
class PrTracker {
|
|
263231
|
-
opts;
|
|
263232
|
-
state = {};
|
|
263233
|
-
loaded = false;
|
|
263234
|
-
now;
|
|
263235
|
-
constructor(opts) {
|
|
263236
|
-
this.opts = opts;
|
|
263237
|
-
this.now = opts.now ?? (() => new Date);
|
|
263238
|
-
}
|
|
263239
|
-
async load() {
|
|
263240
|
-
if (this.loaded)
|
|
263241
|
-
return;
|
|
263242
|
-
this.state = await readState2(this.opts.projectRoot);
|
|
263243
|
-
this.loaded = true;
|
|
263244
|
-
}
|
|
263245
|
-
snapshot() {
|
|
263246
|
-
return JSON.parse(JSON.stringify(this.state));
|
|
263247
|
-
}
|
|
263248
|
-
isBailed(identifier) {
|
|
263249
|
-
return this.state[identifier]?.bailed === true;
|
|
263250
|
-
}
|
|
263251
|
-
getAttempts(identifier) {
|
|
263252
|
-
return this.state[identifier]?.attempts ?? 0;
|
|
263253
|
-
}
|
|
263254
|
-
async recordFailure(identifier, reason) {
|
|
263255
|
-
await this.load();
|
|
263256
|
-
const nowIso = this.now().toISOString();
|
|
263257
|
-
const existing = this.state[identifier];
|
|
263258
|
-
if (existing?.bailed) {
|
|
263259
|
-
existing.lastReason = reason;
|
|
263260
|
-
await this.flush();
|
|
263261
|
-
return { kind: "bail", attempts: existing.attempts, firstBail: false };
|
|
263262
|
-
}
|
|
263263
|
-
const attempts = (existing?.attempts ?? 0) + 1;
|
|
263264
|
-
const entry = {
|
|
263265
|
-
attempts,
|
|
263266
|
-
firstFailedAt: existing?.firstFailedAt ?? nowIso,
|
|
263267
|
-
lastDemotedAt: nowIso,
|
|
263268
|
-
lastReason: reason
|
|
263269
|
-
};
|
|
263270
|
-
if (attempts >= this.opts.maxRecoveryAttempts) {
|
|
263271
|
-
entry.bailed = true;
|
|
263272
|
-
this.state[identifier] = entry;
|
|
263273
|
-
await this.flush();
|
|
263274
|
-
return { kind: "bail", attempts, firstBail: true };
|
|
263275
|
-
}
|
|
263276
|
-
this.state[identifier] = entry;
|
|
263277
|
-
await this.flush();
|
|
263278
|
-
return { kind: "demote", attempts };
|
|
263279
|
-
}
|
|
263280
|
-
async clear(identifier) {
|
|
263281
|
-
await this.load();
|
|
263282
|
-
if (!(identifier in this.state))
|
|
263283
|
-
return;
|
|
263284
|
-
delete this.state[identifier];
|
|
263285
|
-
await this.flush();
|
|
263286
|
-
}
|
|
263287
|
-
async flush() {
|
|
263288
|
-
await writeState2(this.opts.projectRoot, this.state);
|
|
263289
|
-
}
|
|
263290
|
-
}
|
|
263291
|
-
var init_tracker = __esm(() => {
|
|
263292
|
-
init_state3();
|
|
263293
|
-
});
|
|
263294
|
-
|
|
263295
|
-
// apps/agent/src/features/pr-tracker/index.ts
|
|
263296
|
-
var init_pr_tracker = __esm(() => {
|
|
263297
|
-
init_tracker();
|
|
263298
|
-
init_state3();
|
|
263299
|
-
});
|
|
263300
|
-
|
|
263301
263925
|
// apps/agent/src/agent/wire.ts
|
|
263302
|
-
import { join as
|
|
263926
|
+
import { join as join36 } from "path";
|
|
263303
263927
|
function buildAgentCoordinator(input) {
|
|
263304
263928
|
const {
|
|
263305
263929
|
args,
|
|
@@ -263318,7 +263942,7 @@ function buildAgentCoordinator(input) {
|
|
|
263318
263942
|
onWorkerCmd,
|
|
263319
263943
|
onAwaitingTicket
|
|
263320
263944
|
} = input;
|
|
263321
|
-
const logsDir =
|
|
263945
|
+
const logsDir = join36(projectRoot, ".ralph", "logs");
|
|
263322
263946
|
const bus = createBus();
|
|
263323
263947
|
subscribeAgentDiag(bus, onLog);
|
|
263324
263948
|
const diag = (area, message, color) => {
|
|
@@ -263329,7 +263953,9 @@ function buildAgentCoordinator(input) {
|
|
|
263329
263953
|
const isGithubTracker = cfg.tracker.kind === "github";
|
|
263330
263954
|
const indicators = isGithubTracker ? githubIndicators(cfg.github?.issues) : mergeIndicators(cfg.linear.indicators, args.indicators);
|
|
263331
263955
|
const team = args.linearTeam || cfg.linear.team;
|
|
263332
|
-
const
|
|
263956
|
+
const resolvedFilter = resolveLinearFilter(applyAssigneeOverride(cfg.linear.filter, args.linearAssignee));
|
|
263957
|
+
const { assignee, anyAssignee, requireAllLabels } = resolvedFilter;
|
|
263958
|
+
const scope = linearFilterScope(resolvedFilter);
|
|
263333
263959
|
const ticketNumbers = resolveTicketNumbers(args.ticketTokens, team);
|
|
263334
263960
|
const excludeFromTodo = isGithubTracker ? unionMarkers(indicators.setDone, indicators.setError, indicators.setInProgress) : unionMarkers(indicators.setDone, indicators.setError);
|
|
263335
263961
|
const gitRunner = input.runners?.git ?? bunGitRunner;
|
|
@@ -263371,7 +263997,7 @@ function buildAgentCoordinator(input) {
|
|
|
263371
263997
|
team,
|
|
263372
263998
|
assignee,
|
|
263373
263999
|
anyAssignee,
|
|
263374
|
-
|
|
264000
|
+
scope,
|
|
263375
264001
|
diag,
|
|
263376
264002
|
...ticketNumbers.length > 0 ? { ticketNumbers } : {}
|
|
263377
264003
|
});
|
|
@@ -263382,7 +264008,7 @@ function buildAgentCoordinator(input) {
|
|
|
263382
264008
|
diag
|
|
263383
264009
|
}) : {
|
|
263384
264010
|
...resolvers,
|
|
263385
|
-
fetchDoneCandidates: () => fetchDoneCandidatesWith(apiKey, team, assignee, anyAssignee,
|
|
264011
|
+
fetchDoneCandidates: () => fetchDoneCandidatesWith(apiKey, team, assignee, anyAssignee, scope, indicators, ticketNumbers.length > 0 ? ticketNumbers : undefined)
|
|
263386
264012
|
};
|
|
263387
264013
|
if (ticketNumbers.length > 0) {
|
|
263388
264014
|
const hasGetIndicator = [indicators.getTodo, indicators.getInProgress].some((ind) => ind && ind.filter.length > 0);
|
|
@@ -263421,7 +264047,7 @@ function buildAgentCoordinator(input) {
|
|
|
263421
264047
|
team,
|
|
263422
264048
|
assignee,
|
|
263423
264049
|
anyAssignee,
|
|
263424
|
-
|
|
264050
|
+
scope,
|
|
263425
264051
|
indicators,
|
|
263426
264052
|
projectRoot,
|
|
263427
264053
|
useWorktree,
|
|
@@ -263449,7 +264075,7 @@ function buildAgentCoordinator(input) {
|
|
|
263449
264075
|
team,
|
|
263450
264076
|
assignee,
|
|
263451
264077
|
anyAssignee,
|
|
263452
|
-
|
|
264078
|
+
scope,
|
|
263453
264079
|
indicators,
|
|
263454
264080
|
resolvers,
|
|
263455
264081
|
fetchMentions,
|
|
@@ -263498,6 +264124,7 @@ function buildAgentCoordinator(input) {
|
|
|
263498
264124
|
prByChange,
|
|
263499
264125
|
cmdRunner,
|
|
263500
264126
|
prBaseBranch: cfg.prBaseBranch,
|
|
264127
|
+
prLabels: cfg.prLabels,
|
|
263501
264128
|
invalidatePrUrlForIssue: (issueId) => prDiscovery.invalidatePrUrlForIssue(issueId)
|
|
263502
264129
|
});
|
|
263503
264130
|
const confirmationCaps = {
|
|
@@ -263537,10 +264164,6 @@ function buildAgentCoordinator(input) {
|
|
|
263537
264164
|
};
|
|
263538
264165
|
}
|
|
263539
264166
|
const prRecoveryEnabled = args.prRecoveryEnabled === undefined ? cfg.prRecovery.enabled : args.prRecoveryEnabled;
|
|
263540
|
-
const prTracker = prRecoveryEnabled ? new PrTracker({
|
|
263541
|
-
projectRoot,
|
|
263542
|
-
maxRecoveryAttempts: cfg.prRecovery.maxRecoverySessions
|
|
263543
|
-
}) : null;
|
|
263544
264167
|
const commentSync = isGithubTracker ? { enabled: false } : createCommentSyncHooks({
|
|
263545
264168
|
apiKey,
|
|
263546
264169
|
cfg,
|
|
@@ -263586,7 +264209,7 @@ function buildAgentCoordinator(input) {
|
|
|
263586
264209
|
const changeDir = projectLayout(root).changeDir(changeName);
|
|
263587
264210
|
const parts = [];
|
|
263588
264211
|
for (const name of ["tasks.md", "proposal.md", "design.md"]) {
|
|
263589
|
-
const file2 = Bun.file(
|
|
264212
|
+
const file2 = Bun.file(join36(changeDir, name));
|
|
263590
264213
|
if (!await file2.exists())
|
|
263591
264214
|
continue;
|
|
263592
264215
|
parts.push(`${name}:${file2.lastModified}:${file2.size}`);
|
|
@@ -263605,11 +264228,11 @@ function buildAgentCoordinator(input) {
|
|
|
263605
264228
|
commentEveryIterations: cfg.linear.updateEveryIterations,
|
|
263606
264229
|
...args.maxTickets > 0 ? { maxTickets: args.maxTickets } : {},
|
|
263607
264230
|
createsPrs: args.createPr || cfg.createPrOnSuccess,
|
|
263608
|
-
...prTracker ? { prTracker } : {},
|
|
263609
264231
|
prRecovery: {
|
|
263610
264232
|
enabled: prRecoveryEnabled,
|
|
263611
264233
|
fixCi: cfg.prRecovery.fixCi,
|
|
263612
|
-
fixConflicts: cfg.prRecovery.fixConflicts
|
|
264234
|
+
fixConflicts: cfg.prRecovery.fixConflicts,
|
|
264235
|
+
maxRecoverySessions: cfg.prRecovery.maxRecoverySessions
|
|
263613
264236
|
}
|
|
263614
264237
|
});
|
|
263615
264238
|
coordRef.current = coord;
|
|
@@ -263633,19 +264256,7 @@ function buildAgentCoordinator(input) {
|
|
|
263633
264256
|
pollInterval,
|
|
263634
264257
|
getWorkerCwd: (changeName) => cwdByChange.get(changeName),
|
|
263635
264258
|
syncTasksEnabled: commentSync.enabled,
|
|
263636
|
-
runBaselineGate: runBaselineGateOnce
|
|
263637
|
-
getGaveUpTotal: async () => {
|
|
263638
|
-
let total = 0;
|
|
263639
|
-
for (const [changeName, root] of cwdByChange) {
|
|
263640
|
-
const file2 = Bun.file(join37(projectLayout(root).taskStateDir(changeName), GAVEUP_COUNT_FILE));
|
|
263641
|
-
if (!await file2.exists())
|
|
263642
|
-
continue;
|
|
263643
|
-
try {
|
|
263644
|
-
total += Number.parseInt(await file2.text(), 10) || 0;
|
|
263645
|
-
} catch {}
|
|
263646
|
-
}
|
|
263647
|
-
return total;
|
|
263648
|
-
}
|
|
264259
|
+
runBaselineGate: runBaselineGateOnce
|
|
263649
264260
|
};
|
|
263650
264261
|
}
|
|
263651
264262
|
var init_wire = __esm(() => {
|
|
@@ -263669,18 +264280,17 @@ var init_wire = __esm(() => {
|
|
|
263669
264280
|
init_worker();
|
|
263670
264281
|
init_baseline();
|
|
263671
264282
|
init_comment_sync2();
|
|
263672
|
-
init_pr_tracker();
|
|
263673
264283
|
});
|
|
263674
264284
|
|
|
263675
264285
|
// apps/agent/src/agent/json-log/json-log-file.ts
|
|
263676
|
-
import { mkdir as mkdir11, appendFile as
|
|
263677
|
-
import { dirname as
|
|
264286
|
+
import { mkdir as mkdir11, appendFile as appendFile3 } from "fs/promises";
|
|
264287
|
+
import { dirname as dirname13 } from "path";
|
|
263678
264288
|
function createJsonLogFileSink(path) {
|
|
263679
264289
|
if (!path)
|
|
263680
264290
|
return { emit: () => {} };
|
|
263681
264291
|
let chain = (async () => {
|
|
263682
264292
|
try {
|
|
263683
|
-
await mkdir11(
|
|
264293
|
+
await mkdir11(dirname13(path), { recursive: true });
|
|
263684
264294
|
await Bun.write(path, "");
|
|
263685
264295
|
} catch {}
|
|
263686
264296
|
})();
|
|
@@ -263690,7 +264300,7 @@ function createJsonLogFileSink(path) {
|
|
|
263690
264300
|
`;
|
|
263691
264301
|
chain = chain.then(async () => {
|
|
263692
264302
|
try {
|
|
263693
|
-
await
|
|
264303
|
+
await appendFile3(path, line);
|
|
263694
264304
|
} catch {}
|
|
263695
264305
|
});
|
|
263696
264306
|
}
|
|
@@ -263926,7 +264536,7 @@ var init_output_utils = __esm(() => {
|
|
|
263926
264536
|
});
|
|
263927
264537
|
|
|
263928
264538
|
// apps/agent/src/agent/state/worker-state-poll.ts
|
|
263929
|
-
import { join as
|
|
264539
|
+
import { join as join37 } from "path";
|
|
263930
264540
|
function parseSubtasks(tasksMd) {
|
|
263931
264541
|
const out = [];
|
|
263932
264542
|
let skipSection = false;
|
|
@@ -263959,7 +264569,7 @@ function initialWorkerSnapshot() {
|
|
|
263959
264569
|
async function readWorkerSnapshot(input) {
|
|
263960
264570
|
const next = { ...input.prev };
|
|
263961
264571
|
try {
|
|
263962
|
-
const file2 = Bun.file(
|
|
264572
|
+
const file2 = Bun.file(join37(input.statesDir, input.changeName, ".ralph-state.json"));
|
|
263963
264573
|
if (await file2.exists()) {
|
|
263964
264574
|
const json2 = await file2.json();
|
|
263965
264575
|
next.iter = json2.iteration ?? next.iter;
|
|
@@ -263968,10 +264578,10 @@ async function readWorkerSnapshot(input) {
|
|
|
263968
264578
|
} catch {}
|
|
263969
264579
|
if (input.changeDir) {
|
|
263970
264580
|
try {
|
|
263971
|
-
const tasksFile = Bun.file(
|
|
263972
|
-
const proposalFile = Bun.file(
|
|
263973
|
-
const designFile = Bun.file(
|
|
263974
|
-
const reviewFindingsFile = Bun.file(
|
|
264581
|
+
const tasksFile = Bun.file(join37(input.changeDir, "tasks.md"));
|
|
264582
|
+
const proposalFile = Bun.file(join37(input.changeDir, "proposal.md"));
|
|
264583
|
+
const designFile = Bun.file(join37(input.changeDir, "design.md"));
|
|
264584
|
+
const reviewFindingsFile = Bun.file(join37(input.changeDir, "review-findings.md"));
|
|
263975
264585
|
const [tasksText, proposalText, designText, reviewFindingsText] = await Promise.all([
|
|
263976
264586
|
tasksFile.exists().then((ok) => ok ? tasksFile.text() : null),
|
|
263977
264587
|
proposalFile.exists().then((ok) => ok ? proposalFile.text() : null),
|
|
@@ -264034,7 +264644,7 @@ var init_worker_state_poll = __esm(() => {
|
|
|
264034
264644
|
});
|
|
264035
264645
|
|
|
264036
264646
|
// apps/agent/src/components/AgentMode.tsx
|
|
264037
|
-
import { join as
|
|
264647
|
+
import { join as join38 } from "path";
|
|
264038
264648
|
async function appendSteeringImpl(changeDir, message) {
|
|
264039
264649
|
await runWithContext(createDefaultContext(), async () => {
|
|
264040
264650
|
appendSteeringMessage(changeDir, message);
|
|
@@ -264051,16 +264661,6 @@ function orderSubtasksForCappedDisplay(subtasks) {
|
|
|
264051
264661
|
(s.done ? done : pending).push(s);
|
|
264052
264662
|
return [...pending, ...done];
|
|
264053
264663
|
}
|
|
264054
|
-
function pickLatestGatedTicket(tickets) {
|
|
264055
|
-
if (tickets.size === 0)
|
|
264056
|
-
return { top: null, moreCount: 0 };
|
|
264057
|
-
const sorted = Array.from(tickets.entries()).sort(([, a], [, b2]) => {
|
|
264058
|
-
const aTime = a.since ? new Date(a.since).getTime() : 0;
|
|
264059
|
-
const bTime = b2.since ? new Date(b2.since).getTime() : 0;
|
|
264060
|
-
return bTime - aTime;
|
|
264061
|
-
});
|
|
264062
|
-
return { top: sorted[0], moreCount: sorted.length - 1 };
|
|
264063
|
-
}
|
|
264064
264664
|
function fmtCmd(argv) {
|
|
264065
264665
|
const joined = argv.join(" ");
|
|
264066
264666
|
return joined.length > CMD_DISPLAY_MAX ? joined.slice(0, CMD_DISPLAY_MAX - 1) + "\u2026" : joined;
|
|
@@ -264156,20 +264756,6 @@ function Link({ url: url2, label, color }) {
|
|
|
264156
264756
|
}, undefined, false, undefined, this)
|
|
264157
264757
|
}, undefined, false, undefined, this);
|
|
264158
264758
|
}
|
|
264159
|
-
function priorityBadge(p) {
|
|
264160
|
-
switch (p) {
|
|
264161
|
-
case 1:
|
|
264162
|
-
return { text: "\u25B2", color: "red", label: "URGENT" };
|
|
264163
|
-
case 2:
|
|
264164
|
-
return { text: "\u2191", color: "yellow", label: "HIGH" };
|
|
264165
|
-
case 3:
|
|
264166
|
-
return { text: "\xB7", color: "blue", label: "MED" };
|
|
264167
|
-
case 4:
|
|
264168
|
-
return { text: "\u2193", color: "gray", label: "LOW" };
|
|
264169
|
-
default:
|
|
264170
|
-
return { text: " ", color: "gray", label: "" };
|
|
264171
|
-
}
|
|
264172
|
-
}
|
|
264173
264759
|
function modeBadge(mode) {
|
|
264174
264760
|
switch (mode) {
|
|
264175
264761
|
case "fresh":
|
|
@@ -264246,14 +264832,52 @@ function workerBorderColor(phase2) {
|
|
|
264246
264832
|
return "gray";
|
|
264247
264833
|
}
|
|
264248
264834
|
}
|
|
264249
|
-
function
|
|
264250
|
-
|
|
264251
|
-
|
|
264252
|
-
|
|
264253
|
-
|
|
264254
|
-
|
|
264255
|
-
|
|
264256
|
-
|
|
264835
|
+
function focusedCardTailLines(termHeight, fixedOverhead) {
|
|
264836
|
+
return Math.max(3, termHeight - fixedOverhead);
|
|
264837
|
+
}
|
|
264838
|
+
function glyphColor(status) {
|
|
264839
|
+
switch (status) {
|
|
264840
|
+
case "done":
|
|
264841
|
+
return "green";
|
|
264842
|
+
case "current":
|
|
264843
|
+
return "cyan";
|
|
264844
|
+
case "pending":
|
|
264845
|
+
return "gray";
|
|
264846
|
+
case "failed":
|
|
264847
|
+
return "red";
|
|
264848
|
+
case "bailed":
|
|
264849
|
+
return "magenta";
|
|
264850
|
+
}
|
|
264851
|
+
}
|
|
264852
|
+
function PipelineCells({
|
|
264853
|
+
glyphs
|
|
264854
|
+
}) {
|
|
264855
|
+
return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
264856
|
+
children: PIPELINE_NODES.map((node2, i) => {
|
|
264857
|
+
const isHeader = glyphs === null;
|
|
264858
|
+
const status = isHeader ? null : glyphs[i];
|
|
264859
|
+
const content = isHeader ? NODE_LABELS[node2] : STATUS_GLYPH[status];
|
|
264860
|
+
return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
264861
|
+
children: [
|
|
264862
|
+
i > 0 && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264863
|
+
dimColor: true,
|
|
264864
|
+
children: PIPELINE_CONNECTOR
|
|
264865
|
+
}, undefined, false, undefined, this),
|
|
264866
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
264867
|
+
width: NODE_CELL_WIDTH,
|
|
264868
|
+
justifyContent: "center",
|
|
264869
|
+
children: isHeader ? /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264870
|
+
dimColor: true,
|
|
264871
|
+
children: content
|
|
264872
|
+
}, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264873
|
+
color: glyphColor(status),
|
|
264874
|
+
children: content
|
|
264875
|
+
}, undefined, false, undefined, this)
|
|
264876
|
+
}, undefined, false, undefined, this)
|
|
264877
|
+
]
|
|
264878
|
+
}, node2, true, undefined, this);
|
|
264879
|
+
})
|
|
264880
|
+
}, undefined, false, undefined, this);
|
|
264257
264881
|
}
|
|
264258
264882
|
function AgentMode({
|
|
264259
264883
|
args,
|
|
@@ -264287,24 +264911,19 @@ function AgentMode({
|
|
|
264287
264911
|
}, [awaitingClose]);
|
|
264288
264912
|
const [, setTick] = import_react63.useState(0);
|
|
264289
264913
|
const [clock, setClock] = import_react63.useState(0);
|
|
264290
|
-
const [
|
|
264914
|
+
const [focusedId, setFocusedId] = import_react63.useState(null);
|
|
264291
264915
|
const [showPendingTasks, setShowPendingTasks] = import_react63.useState(false);
|
|
264292
264916
|
const [showAllSubtasks, setShowAllSubtasks] = import_react63.useState(false);
|
|
264293
|
-
const [gaveUpCount, setGaveUpCount] = import_react63.useState(0);
|
|
264294
264917
|
const coordRef = import_react63.useRef(null);
|
|
264295
264918
|
const workerMetaRef = import_react63.useRef(new Map);
|
|
264296
|
-
const gatedTicketsRef = import_react63.useRef(new Map);
|
|
264297
264919
|
const nextPollAtRef = import_react63.useRef(0);
|
|
264298
264920
|
const cfgRef = import_react63.useRef(null);
|
|
264299
264921
|
const [effective, setEffective] = import_react63.useState(null);
|
|
264300
264922
|
const [pollStatus, setPollStatus] = import_react63.useState({
|
|
264301
264923
|
state: "idle",
|
|
264302
|
-
lastFound: null,
|
|
264303
|
-
lastAdded: null,
|
|
264304
264924
|
lastAt: null,
|
|
264305
264925
|
filterDesc: "",
|
|
264306
|
-
|
|
264307
|
-
lastPrStatus: null
|
|
264926
|
+
lastBoard: []
|
|
264308
264927
|
});
|
|
264309
264928
|
function appendLog(text, color, workerLogFile) {
|
|
264310
264929
|
setLogs((prev) => [...prev, { id: nextId(), text, color }]);
|
|
@@ -264340,7 +264959,7 @@ function AgentMode({
|
|
|
264340
264959
|
setFatalExit(2);
|
|
264341
264960
|
return;
|
|
264342
264961
|
}
|
|
264343
|
-
const { coord: coord2, filterDesc, concurrency, pollInterval, runBaselineGate: runBaselineGate2
|
|
264962
|
+
const { coord: coord2, filterDesc, concurrency, pollInterval, runBaselineGate: runBaselineGate2 } = buildCoordinator({
|
|
264344
264963
|
args,
|
|
264345
264964
|
cfg: cfg2,
|
|
264346
264965
|
projectRoot,
|
|
@@ -264447,13 +265066,6 @@ function AgentMode({
|
|
|
264447
265066
|
since: info.since,
|
|
264448
265067
|
round: info.round
|
|
264449
265068
|
});
|
|
264450
|
-
gatedTicketsRef.current.set(info.changeName, {
|
|
264451
|
-
issueIdentifier: info.issueIdentifier,
|
|
264452
|
-
issueUrl: info.issueUrl,
|
|
264453
|
-
issueTitle: info.issueTitle,
|
|
264454
|
-
since: info.since,
|
|
264455
|
-
round: info.round
|
|
264456
|
-
});
|
|
264457
265069
|
}
|
|
264458
265070
|
});
|
|
264459
265071
|
setEffective({ concurrency, pollInterval });
|
|
@@ -264481,28 +265093,18 @@ function AgentMode({
|
|
|
264481
265093
|
}
|
|
264482
265094
|
if (cancelled)
|
|
264483
265095
|
return;
|
|
264484
|
-
|
|
264485
|
-
const { found, added, buckets, prStatus } = await coord2.pollOnce();
|
|
265096
|
+
const { found, added, buckets, prStatus, board: board2 } = await coord2.pollOnce();
|
|
264486
265097
|
if (cancelled)
|
|
264487
265098
|
return;
|
|
264488
265099
|
fileEmit({ type: "poll_done", found, added, buckets, prStatus });
|
|
264489
|
-
getGaveUpTotal().then((total) => {
|
|
264490
|
-
if (!cancelled)
|
|
264491
|
-
setGaveUpCount(total);
|
|
264492
|
-
}).catch(() => {
|
|
264493
|
-
return;
|
|
264494
|
-
});
|
|
264495
265100
|
if (added > 0) {
|
|
264496
265101
|
appendLog(` ${added} new issue${added === 1 ? "" : "s"} queued (found ${found} open)`);
|
|
264497
265102
|
}
|
|
264498
265103
|
setPollStatus({
|
|
264499
265104
|
state: "idle",
|
|
264500
|
-
lastFound: found,
|
|
264501
|
-
lastAdded: added,
|
|
264502
265105
|
lastAt: Date.now(),
|
|
264503
265106
|
filterDesc,
|
|
264504
|
-
|
|
264505
|
-
lastPrStatus: prStatus
|
|
265107
|
+
lastBoard: board2
|
|
264506
265108
|
});
|
|
264507
265109
|
nextPollAtRef.current = Date.now() + pollInterval * 1000;
|
|
264508
265110
|
pollTimer = setTimeout(tick, pollInterval * 1000);
|
|
@@ -264617,10 +265219,22 @@ function AgentMode({
|
|
|
264617
265219
|
const spinnerFrame = SPINNER_FRAMES[clock % SPINNER_FRAMES.length];
|
|
264618
265220
|
const now2 = Date.now();
|
|
264619
265221
|
const secsToNextPoll = nextPollAtRef.current ? Math.max(0, Math.ceil((nextPollAtRef.current - now2) / 1000)) : null;
|
|
265222
|
+
const pollState = pollStatus.state === "polling" ? "polling\u2026" : pollStatus.lastAt !== null ? "idle" : "starting\u2026";
|
|
265223
|
+
const tasksLiveness = `${pollState}${secsToNextPoll !== null ? ` \xB7 ${secsToNextPoll}s \u21BB` : ""}`;
|
|
264620
265224
|
const activeCount = coord?.activeCount ?? 0;
|
|
264621
265225
|
const termWidth = columns - 2;
|
|
264622
265226
|
const termHeight = rows;
|
|
264623
|
-
const
|
|
265227
|
+
const board = pollStatus.lastBoard;
|
|
265228
|
+
const liveWorkerIds = new Set(coordRef.current?.activeWorkers.map((w2) => w2.issueId) ?? []);
|
|
265229
|
+
const tree = buildBoardTree(orderActiveWorkersFirst(board, liveWorkerIds));
|
|
265230
|
+
const focusedIndex = (() => {
|
|
265231
|
+
if (tree.length === 0)
|
|
265232
|
+
return -1;
|
|
265233
|
+
const i = tree.findIndex((t) => t.row.id === focusedId);
|
|
265234
|
+
return i >= 0 ? i : 0;
|
|
265235
|
+
})();
|
|
265236
|
+
const focusedRow = focusedIndex >= 0 ? tree[focusedIndex].row : undefined;
|
|
265237
|
+
const focusedWorker = focusedRow ? coordRef.current?.activeWorkers.find((w2) => w2.issueId === focusedRow.id) : undefined;
|
|
264624
265238
|
const steeringFocusedRef = import_react63.useRef(false);
|
|
264625
265239
|
const steeringBufferRef = import_react63.useRef("");
|
|
264626
265240
|
const steeringCursorRef = import_react63.useRef(0);
|
|
@@ -264638,26 +265252,23 @@ function AgentMode({
|
|
|
264638
265252
|
setShowPendingTasks((v2) => !v2);
|
|
264639
265253
|
return;
|
|
264640
265254
|
}
|
|
264641
|
-
if (
|
|
265255
|
+
if (tree.length === 0)
|
|
264642
265256
|
return;
|
|
264643
|
-
|
|
264644
|
-
|
|
264645
|
-
|
|
264646
|
-
|
|
265257
|
+
const idx = focusedIndex < 0 ? 0 : focusedIndex;
|
|
265258
|
+
if (key.tab || key.downArrow) {
|
|
265259
|
+
setFocusedId(tree[(idx + 1) % tree.length].row.id);
|
|
265260
|
+
} else if (key.upArrow) {
|
|
265261
|
+
setFocusedId(tree[(idx - 1 + tree.length) % tree.length].row.id);
|
|
264647
265262
|
} else {
|
|
264648
265263
|
const n = parseInt(input, 10);
|
|
264649
|
-
if (!isNaN(n) && n >= 1 && n <=
|
|
264650
|
-
|
|
264651
|
-
}
|
|
264652
|
-
}, { isActive: isRawModeSupported &&
|
|
264653
|
-
const
|
|
264654
|
-
const steeringActive = isRawModeSupported && activeCount > 0 && focusedWorker !== undefined;
|
|
264655
|
-
const nonFocusedCount = Math.max(0, activeCount - 1);
|
|
264656
|
-
const tasksBoxLines = activeCount > 1 ? 5 : 0;
|
|
265264
|
+
if (!isNaN(n) && n >= 1 && n <= Math.min(9, tree.length))
|
|
265265
|
+
setFocusedId(tree[n - 1].row.id);
|
|
265266
|
+
}
|
|
265267
|
+
}, { isActive: isRawModeSupported && board.length > 0 });
|
|
265268
|
+
const steeringActive = isRawModeSupported && focusedWorker !== undefined;
|
|
264657
265269
|
const steeringBoxLines = steeringActive ? 3 : 0;
|
|
264658
|
-
const FIXED_OVERHEAD = 5 +
|
|
264659
|
-
const focusedTailLines =
|
|
264660
|
-
const compactTailLines = displayTailLines(activeCount);
|
|
265270
|
+
const FIXED_OVERHEAD = 5 + (4 + board.length) + 8 + steeringBoxLines;
|
|
265271
|
+
const focusedTailLines = focusedCardTailLines(termHeight, FIXED_OVERHEAD);
|
|
264661
265272
|
if (preflightError) {
|
|
264662
265273
|
return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
264663
265274
|
flexDirection: "column",
|
|
@@ -264811,14 +265422,7 @@ function AgentMode({
|
|
|
264811
265422
|
cfg.useWorktree && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264812
265423
|
color: "green",
|
|
264813
265424
|
children: " \u25CF worktree"
|
|
264814
|
-
}, undefined, false, undefined, this)
|
|
264815
|
-
gaveUpCount > 0 && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264816
|
-
color: "red",
|
|
264817
|
-
children: [
|
|
264818
|
-
" \u2502 gave-up \xD7",
|
|
264819
|
-
gaveUpCount
|
|
264820
|
-
]
|
|
264821
|
-
}, undefined, true, undefined, this)
|
|
265425
|
+
}, undefined, false, undefined, this)
|
|
264822
265426
|
]
|
|
264823
265427
|
}, undefined, true, undefined, this)
|
|
264824
265428
|
]
|
|
@@ -264845,418 +265449,196 @@ function AgentMode({
|
|
|
264845
265449
|
})()
|
|
264846
265450
|
]
|
|
264847
265451
|
}, undefined, true, undefined, this),
|
|
264848
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
264849
|
-
flexDirection: "row",
|
|
264850
|
-
gap: 1,
|
|
264851
|
-
marginTop: 0,
|
|
264852
|
-
width: termWidth,
|
|
264853
|
-
children: [
|
|
264854
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(LabeledBox, {
|
|
264855
|
-
label: "POLL STATUS",
|
|
264856
|
-
borderColor: "gray",
|
|
264857
|
-
width: termWidth - 17,
|
|
264858
|
-
paddingX: 1,
|
|
264859
|
-
flexDirection: "column",
|
|
264860
|
-
children: [
|
|
264861
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
264862
|
-
gap: 2,
|
|
264863
|
-
children: [
|
|
264864
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264865
|
-
color: "gray",
|
|
264866
|
-
children: spinnerFrame
|
|
264867
|
-
}, undefined, false, undefined, this),
|
|
264868
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264869
|
-
children: pollStatus.state === "polling" ? "Polling Linear\u2026" : pollStatus.lastAt !== null ? "Idle" : "Starting\u2026"
|
|
264870
|
-
}, undefined, false, undefined, this),
|
|
264871
|
-
pollStatus.lastAt !== null && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(jsx_dev_runtime11.Fragment, {
|
|
264872
|
-
children: pollStatus.lastBuckets && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(jsx_dev_runtime11.Fragment, {
|
|
264873
|
-
children: [
|
|
264874
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264875
|
-
dimColor: true,
|
|
264876
|
-
children: "\u2502"
|
|
264877
|
-
}, undefined, false, undefined, this),
|
|
264878
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264879
|
-
dimColor: true,
|
|
264880
|
-
children: "todo"
|
|
264881
|
-
}, undefined, false, undefined, this),
|
|
264882
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264883
|
-
color: "white",
|
|
264884
|
-
children: pollStatus.lastBuckets.todo
|
|
264885
|
-
}, undefined, false, undefined, this),
|
|
264886
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264887
|
-
dimColor: true,
|
|
264888
|
-
children: "\xB7"
|
|
264889
|
-
}, undefined, false, undefined, this),
|
|
264890
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264891
|
-
dimColor: true,
|
|
264892
|
-
children: "resume"
|
|
264893
|
-
}, undefined, false, undefined, this),
|
|
264894
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264895
|
-
color: pollStatus.lastBuckets.inProgress > 0 ? "cyan" : "white",
|
|
264896
|
-
children: pollStatus.lastBuckets.inProgress
|
|
264897
|
-
}, undefined, false, undefined, this),
|
|
264898
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264899
|
-
dimColor: true,
|
|
264900
|
-
children: "\xB7"
|
|
264901
|
-
}, undefined, false, undefined, this),
|
|
264902
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264903
|
-
dimColor: true,
|
|
264904
|
-
children: "review"
|
|
264905
|
-
}, undefined, false, undefined, this),
|
|
264906
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264907
|
-
color: pollStatus.lastBuckets.review > 0 ? "yellow" : "white",
|
|
264908
|
-
children: pollStatus.lastBuckets.review
|
|
264909
|
-
}, undefined, false, undefined, this),
|
|
264910
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264911
|
-
dimColor: true,
|
|
264912
|
-
children: "\xB7"
|
|
264913
|
-
}, undefined, false, undefined, this),
|
|
264914
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264915
|
-
dimColor: true,
|
|
264916
|
-
children: "mentions"
|
|
264917
|
-
}, undefined, false, undefined, this),
|
|
264918
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264919
|
-
color: pollStatus.lastBuckets.mentions > 0 ? "magenta" : "white",
|
|
264920
|
-
children: pollStatus.lastBuckets.mentions
|
|
264921
|
-
}, undefined, false, undefined, this),
|
|
264922
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264923
|
-
dimColor: true,
|
|
264924
|
-
children: "\xB7"
|
|
264925
|
-
}, undefined, false, undefined, this),
|
|
264926
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264927
|
-
dimColor: true,
|
|
264928
|
-
children: "awaiting"
|
|
264929
|
-
}, undefined, false, undefined, this),
|
|
264930
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264931
|
-
color: pollStatus.lastBuckets.awaiting > 0 ? "yellow" : "white",
|
|
264932
|
-
children: pollStatus.lastBuckets.awaiting
|
|
264933
|
-
}, undefined, false, undefined, this)
|
|
264934
|
-
]
|
|
264935
|
-
}, undefined, true, undefined, this)
|
|
264936
|
-
}, undefined, false, undefined, this)
|
|
264937
|
-
]
|
|
264938
|
-
}, undefined, true, undefined, this),
|
|
264939
|
-
pollStatus.lastAt !== null && pollStatus.lastPrStatus && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
264940
|
-
gap: 2,
|
|
264941
|
-
children: [
|
|
264942
|
-
secsToNextPoll !== null ? /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
264943
|
-
gap: 1,
|
|
264944
|
-
width: 7,
|
|
264945
|
-
children: [
|
|
264946
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264947
|
-
dimColor: true,
|
|
264948
|
-
children: "\u21BA"
|
|
264949
|
-
}, undefined, false, undefined, this),
|
|
264950
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264951
|
-
color: "gray",
|
|
264952
|
-
children: [
|
|
264953
|
-
secsToNextPoll,
|
|
264954
|
-
"s"
|
|
264955
|
-
]
|
|
264956
|
-
}, undefined, true, undefined, this)
|
|
264957
|
-
]
|
|
264958
|
-
}, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264959
|
-
children: " ".repeat(7)
|
|
264960
|
-
}, undefined, false, undefined, this),
|
|
264961
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264962
|
-
dimColor: true,
|
|
264963
|
-
children: "\u2502"
|
|
264964
|
-
}, undefined, false, undefined, this),
|
|
264965
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264966
|
-
dimColor: true,
|
|
264967
|
-
children: "mergeable"
|
|
264968
|
-
}, undefined, false, undefined, this),
|
|
264969
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264970
|
-
color: pollStatus.lastPrStatus.mergeable > 0 ? "green" : "white",
|
|
264971
|
-
children: pollStatus.lastPrStatus.mergeable
|
|
264972
|
-
}, undefined, false, undefined, this),
|
|
264973
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264974
|
-
dimColor: true,
|
|
264975
|
-
children: "\xB7"
|
|
264976
|
-
}, undefined, false, undefined, this),
|
|
264977
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264978
|
-
dimColor: true,
|
|
264979
|
-
children: "conflicted"
|
|
264980
|
-
}, undefined, false, undefined, this),
|
|
264981
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264982
|
-
color: pollStatus.lastPrStatus.conflicted > 0 ? "red" : "white",
|
|
264983
|
-
children: pollStatus.lastPrStatus.conflicted
|
|
264984
|
-
}, undefined, false, undefined, this),
|
|
264985
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264986
|
-
dimColor: true,
|
|
264987
|
-
children: "\xB7"
|
|
264988
|
-
}, undefined, false, undefined, this),
|
|
264989
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264990
|
-
dimColor: true,
|
|
264991
|
-
children: "ci-failed"
|
|
264992
|
-
}, undefined, false, undefined, this),
|
|
264993
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264994
|
-
color: pollStatus.lastPrStatus.ciFailed > 0 ? "red" : "white",
|
|
264995
|
-
children: pollStatus.lastPrStatus.ciFailed
|
|
264996
|
-
}, undefined, false, undefined, this),
|
|
264997
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264998
|
-
dimColor: true,
|
|
264999
|
-
children: "\xB7"
|
|
265000
|
-
}, undefined, false, undefined, this),
|
|
265001
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265002
|
-
dimColor: true,
|
|
265003
|
-
children: "quarantined"
|
|
265004
|
-
}, undefined, false, undefined, this),
|
|
265005
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265006
|
-
color: pollStatus.lastPrStatus.quarantined > 0 ? "magenta" : "white",
|
|
265007
|
-
bold: true,
|
|
265008
|
-
children: pollStatus.lastPrStatus.quarantined
|
|
265009
|
-
}, undefined, false, undefined, this)
|
|
265010
|
-
]
|
|
265011
|
-
}, undefined, true, undefined, this)
|
|
265012
|
-
]
|
|
265013
|
-
}, undefined, true, undefined, this),
|
|
265014
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(LabeledBox, {
|
|
265015
|
-
label: "WORKERS",
|
|
265016
|
-
borderColor: "gray",
|
|
265017
|
-
width: 16,
|
|
265018
|
-
paddingX: 1,
|
|
265019
|
-
flexDirection: "column",
|
|
265020
|
-
children: [
|
|
265021
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
265022
|
-
gap: 1,
|
|
265023
|
-
children: [
|
|
265024
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265025
|
-
dimColor: true,
|
|
265026
|
-
children: "active"
|
|
265027
|
-
}, undefined, false, undefined, this),
|
|
265028
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265029
|
-
color: activeCount > 0 ? "cyan" : "gray",
|
|
265030
|
-
bold: true,
|
|
265031
|
-
children: activeCount
|
|
265032
|
-
}, undefined, false, undefined, this)
|
|
265033
|
-
]
|
|
265034
|
-
}, undefined, true, undefined, this),
|
|
265035
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
265036
|
-
gap: 1,
|
|
265037
|
-
children: [
|
|
265038
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265039
|
-
dimColor: true,
|
|
265040
|
-
children: "queue"
|
|
265041
|
-
}, undefined, false, undefined, this),
|
|
265042
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265043
|
-
color: (coord?.queuedCount ?? 0) > 0 ? "yellow" : "gray",
|
|
265044
|
-
bold: true,
|
|
265045
|
-
children: coord?.queuedCount ?? 0
|
|
265046
|
-
}, undefined, false, undefined, this)
|
|
265047
|
-
]
|
|
265048
|
-
}, undefined, true, undefined, this)
|
|
265049
|
-
]
|
|
265050
|
-
}, undefined, true, undefined, this)
|
|
265051
|
-
]
|
|
265052
|
-
}, undefined, true, undefined, this),
|
|
265053
|
-
activeCount > 1 && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(LabeledBox, {
|
|
265054
|
-
label: `TASKS${activeCount > 1 ? " Tab/\u2190 \u2192 \xB7 1-9" : ""}`,
|
|
265055
|
-
borderColor: "gray",
|
|
265056
|
-
width: termWidth,
|
|
265057
|
-
paddingX: 1,
|
|
265058
|
-
flexDirection: "column",
|
|
265059
|
-
children: /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
265060
|
-
gap: 3,
|
|
265061
|
-
flexWrap: "wrap",
|
|
265062
|
-
children: coord?.activeWorkers.map((w2, idx) => {
|
|
265063
|
-
const meta3 = workerMetaRef.current.get(w2.changeName);
|
|
265064
|
-
const phase2 = meta3?.phase ?? "working";
|
|
265065
|
-
const pBadge = priorityBadge(w2.issue.priority);
|
|
265066
|
-
const isFocused = idx === safeFocusedIdx;
|
|
265067
|
-
return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
265068
|
-
gap: 1,
|
|
265069
|
-
children: [
|
|
265070
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265071
|
-
color: isFocused ? "white" : "gray",
|
|
265072
|
-
bold: isFocused,
|
|
265073
|
-
children: [
|
|
265074
|
-
"[",
|
|
265075
|
-
idx + 1,
|
|
265076
|
-
"]"
|
|
265077
|
-
]
|
|
265078
|
-
}, undefined, true, undefined, this),
|
|
265079
|
-
pBadge.label && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265080
|
-
color: pBadge.color,
|
|
265081
|
-
children: [
|
|
265082
|
-
pBadge.text,
|
|
265083
|
-
" ",
|
|
265084
|
-
pBadge.label
|
|
265085
|
-
]
|
|
265086
|
-
}, undefined, true, undefined, this),
|
|
265087
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Link, {
|
|
265088
|
-
url: w2.issue.url,
|
|
265089
|
-
label: w2.issueIdentifier,
|
|
265090
|
-
color: isFocused ? "cyan" : "gray"
|
|
265091
|
-
}, undefined, false, undefined, this),
|
|
265092
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265093
|
-
color: phaseColor(phase2),
|
|
265094
|
-
dimColor: !isFocused,
|
|
265095
|
-
children: phase2
|
|
265096
|
-
}, undefined, false, undefined, this),
|
|
265097
|
-
isFocused && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265098
|
-
color: "white",
|
|
265099
|
-
children: "\u25C0"
|
|
265100
|
-
}, undefined, false, undefined, this)
|
|
265101
|
-
]
|
|
265102
|
-
}, w2.changeName, true, undefined, this);
|
|
265103
|
-
})
|
|
265104
|
-
}, undefined, false, undefined, this)
|
|
265105
|
-
}, undefined, false, undefined, this),
|
|
265106
265452
|
(() => {
|
|
265107
|
-
const
|
|
265108
|
-
|
|
265109
|
-
|
|
265110
|
-
|
|
265111
|
-
|
|
265112
|
-
|
|
265113
|
-
|
|
265114
|
-
|
|
265115
|
-
|
|
265116
|
-
|
|
265117
|
-
|
|
265118
|
-
const labelParts = [];
|
|
265119
|
-
entries.forEach(([, g3], i) => {
|
|
265120
|
-
labelParts.push(/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Link, {
|
|
265121
|
-
url: g3.issueUrl,
|
|
265122
|
-
label: g3.issueIdentifier,
|
|
265123
|
-
color: "yellow"
|
|
265124
|
-
}, g3.issueIdentifier, false, undefined, this));
|
|
265125
|
-
if (i < entries.length - 1) {
|
|
265126
|
-
labelParts.push(/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265127
|
-
color: "yellow",
|
|
265128
|
-
children: " \xB7 "
|
|
265129
|
-
}, `sep-${i}`, false, undefined, this));
|
|
265130
|
-
}
|
|
265131
|
-
});
|
|
265132
|
-
const multiLabelNode = /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(jsx_dev_runtime11.Fragment, {
|
|
265453
|
+
const tasksInnerWidth = Math.max(0, termWidth - 2);
|
|
265454
|
+
const lead = "\u2500 ";
|
|
265455
|
+
const hint = " Tab/\u2191\u2193\xB71-9 ";
|
|
265456
|
+
const live = ` ${tasksLiveness} `;
|
|
265457
|
+
const trail = "\u2500";
|
|
265458
|
+
const fixed = lead.length + "TASKS".length + hint.length + live.length + trail.length;
|
|
265459
|
+
const fill2 = Math.max(1, tasksInnerWidth - fixed);
|
|
265460
|
+
return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(LabeledBox, {
|
|
265461
|
+
labelVisualWidth: tasksInnerWidth,
|
|
265462
|
+
labelNode: /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
265463
|
+
flexDirection: "row",
|
|
265133
265464
|
children: [
|
|
265134
265465
|
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265135
|
-
color: "
|
|
265136
|
-
children:
|
|
265466
|
+
color: "gray",
|
|
265467
|
+
children: lead
|
|
265137
265468
|
}, undefined, false, undefined, this),
|
|
265138
|
-
labelParts,
|
|
265139
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265140
|
-
color: "yellow",
|
|
265141
|
-
children: " "
|
|
265142
|
-
}, undefined, false, undefined, this)
|
|
265143
|
-
]
|
|
265144
|
-
}, undefined, true, undefined, this);
|
|
265145
|
-
return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(LabeledBox, {
|
|
265146
|
-
labelNode: multiLabelNode,
|
|
265147
|
-
labelVisualWidth: multiLabelWidth,
|
|
265148
|
-
borderColor: "yellow",
|
|
265149
|
-
paddingX: 1,
|
|
265150
|
-
gap: 2,
|
|
265151
|
-
width: termWidth,
|
|
265152
|
-
children: [
|
|
265153
265469
|
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265154
|
-
color: "yellow",
|
|
265155
265470
|
bold: true,
|
|
265156
|
-
children: "
|
|
265157
|
-
}, undefined, false, undefined, this),
|
|
265158
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265159
|
-
color: "yellow",
|
|
265160
|
-
children: "Awaiting confirmation"
|
|
265471
|
+
children: "TASKS"
|
|
265161
265472
|
}, undefined, false, undefined, this),
|
|
265162
265473
|
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265163
265474
|
dimColor: true,
|
|
265164
|
-
children:
|
|
265475
|
+
children: hint
|
|
265165
265476
|
}, undefined, false, undefined, this),
|
|
265166
265477
|
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265167
|
-
color: "
|
|
265168
|
-
|
|
265169
|
-
children: gated.size
|
|
265478
|
+
color: "gray",
|
|
265479
|
+
children: "\u2500".repeat(fill2)
|
|
265170
265480
|
}, undefined, false, undefined, this),
|
|
265171
265481
|
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265172
265482
|
dimColor: true,
|
|
265173
|
-
children:
|
|
265483
|
+
children: live
|
|
265484
|
+
}, undefined, false, undefined, this),
|
|
265485
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265486
|
+
color: "gray",
|
|
265487
|
+
children: trail
|
|
265174
265488
|
}, undefined, false, undefined, this)
|
|
265175
265489
|
]
|
|
265176
|
-
}, undefined, true, undefined, this)
|
|
265177
|
-
|
|
265178
|
-
const { top } = pickLatestGatedTicket(gated);
|
|
265179
|
-
if (!top)
|
|
265180
|
-
return null;
|
|
265181
|
-
const [changeName, g2] = top;
|
|
265182
|
-
const askedAgo = g2.since ? fmtElapsed(now2 - Date.parse(g2.since)) : "just now";
|
|
265183
|
-
const cardLabelWidth = g2.issueIdentifier.length + 2;
|
|
265184
|
-
const cardLabelNode = /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(jsx_dev_runtime11.Fragment, {
|
|
265185
|
-
children: [
|
|
265186
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265187
|
-
color: "yellow",
|
|
265188
|
-
children: " "
|
|
265189
|
-
}, undefined, false, undefined, this),
|
|
265190
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Link, {
|
|
265191
|
-
url: g2.issueUrl,
|
|
265192
|
-
label: g2.issueIdentifier,
|
|
265193
|
-
color: "yellow"
|
|
265194
|
-
}, undefined, false, undefined, this),
|
|
265195
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265196
|
-
color: "yellow",
|
|
265197
|
-
children: " "
|
|
265198
|
-
}, undefined, false, undefined, this)
|
|
265199
|
-
]
|
|
265200
|
-
}, undefined, true, undefined, this);
|
|
265201
|
-
return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(LabeledBox, {
|
|
265202
|
-
labelNode: cardLabelNode,
|
|
265203
|
-
labelVisualWidth: cardLabelWidth,
|
|
265204
|
-
borderColor: "yellow",
|
|
265205
|
-
paddingX: 1,
|
|
265206
|
-
gap: 2,
|
|
265490
|
+
}, undefined, true, undefined, this),
|
|
265491
|
+
borderColor: "gray",
|
|
265207
265492
|
width: termWidth,
|
|
265208
|
-
|
|
265209
|
-
|
|
265210
|
-
|
|
265211
|
-
|
|
265212
|
-
|
|
265213
|
-
|
|
265214
|
-
|
|
265215
|
-
|
|
265216
|
-
|
|
265217
|
-
|
|
265218
|
-
|
|
265219
|
-
|
|
265220
|
-
|
|
265221
|
-
|
|
265222
|
-
|
|
265223
|
-
|
|
265224
|
-
|
|
265225
|
-
|
|
265226
|
-
|
|
265227
|
-
|
|
265228
|
-
|
|
265229
|
-
children:
|
|
265230
|
-
|
|
265231
|
-
|
|
265232
|
-
|
|
265233
|
-
|
|
265234
|
-
|
|
265235
|
-
|
|
265236
|
-
|
|
265237
|
-
|
|
265238
|
-
|
|
265239
|
-
|
|
265240
|
-
|
|
265241
|
-
|
|
265242
|
-
|
|
265243
|
-
|
|
265244
|
-
|
|
265245
|
-
|
|
265246
|
-
|
|
265247
|
-
|
|
265248
|
-
|
|
265249
|
-
|
|
265250
|
-
|
|
265251
|
-
|
|
265252
|
-
|
|
265253
|
-
|
|
265254
|
-
|
|
265255
|
-
|
|
265256
|
-
|
|
265493
|
+
paddingX: 1,
|
|
265494
|
+
flexDirection: "column",
|
|
265495
|
+
children: board.length === 0 ? /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265496
|
+
dimColor: true,
|
|
265497
|
+
children: "no active tickets"
|
|
265498
|
+
}, undefined, false, undefined, this) : (() => {
|
|
265499
|
+
const idColWidth = Math.max(8, ...tree.map((t) => t.depth * 2 + t.row.identifier.length));
|
|
265500
|
+
const idxWidth = String(tree.length).length + 3;
|
|
265501
|
+
const prefixWidth = 2 + idxWidth + idColWidth + 1;
|
|
265502
|
+
const advancing = activeCount > 0 || tree.some((t) => ADVANCING_STATES.has(t.row.state));
|
|
265503
|
+
const hasStartableTodo = tree.some((t) => t.row.state === "todo" && !(t.row.blockedByIds?.length ?? 0));
|
|
265504
|
+
const stalled = !advancing && !hasStartableTodo;
|
|
265505
|
+
const blockedCount = tree.filter((t) => t.row.state === "todo" && (t.row.blockedByIds?.length ?? 0) > 0).length;
|
|
265506
|
+
const awaitingCount = tree.filter((t) => t.row.state === "awaiting").length;
|
|
265507
|
+
const quarantinedCount = tree.filter((t) => t.row.state === "quarantined").length;
|
|
265508
|
+
const stallParts = [
|
|
265509
|
+
blockedCount > 0 ? `${blockedCount} blocked` : null,
|
|
265510
|
+
awaitingCount > 0 ? `${awaitingCount} awaiting confirmation` : null,
|
|
265511
|
+
quarantinedCount > 0 ? `${quarantinedCount} quarantined` : null
|
|
265512
|
+
].filter((p) => p !== null);
|
|
265513
|
+
return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(jsx_dev_runtime11.Fragment, {
|
|
265514
|
+
children: [
|
|
265515
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
265516
|
+
children: [
|
|
265517
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265518
|
+
children: " ".repeat(prefixWidth)
|
|
265519
|
+
}, undefined, false, undefined, this),
|
|
265520
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(PipelineCells, {
|
|
265521
|
+
glyphs: null
|
|
265522
|
+
}, undefined, false, undefined, this)
|
|
265523
|
+
]
|
|
265524
|
+
}, undefined, true, undefined, this),
|
|
265525
|
+
tree.map(({ row, depth }, i) => {
|
|
265526
|
+
const isFocused = row.id === focusedRow?.id;
|
|
265527
|
+
const indent = depth > 0 ? " ".repeat(depth - 1) + "\u2514 " : "";
|
|
265528
|
+
const blockers = row.blockedByIdentifiers ?? [];
|
|
265529
|
+
const activeW = coordRef.current?.activeWorkers.find((w2) => w2.issueId === row.id);
|
|
265530
|
+
const meta3 = activeW ? workerMetaRef.current.get(activeW.changeName) : undefined;
|
|
265531
|
+
const waitingForWorker = !activeW && WORKER_WAIT_STATES.has(row.state);
|
|
265532
|
+
let age = "\u2013";
|
|
265533
|
+
if (meta3?.startedAt) {
|
|
265534
|
+
age = fmtElapsed(now2 - meta3.startedAt);
|
|
265535
|
+
} else if (!waitingForWorker && row.recovery?.firstFailedAt) {
|
|
265536
|
+
const failedAt = Date.parse(row.recovery.firstFailedAt);
|
|
265537
|
+
if (!Number.isNaN(failedAt))
|
|
265538
|
+
age = fmtElapsed(now2 - failedAt);
|
|
265539
|
+
}
|
|
265540
|
+
const prUrl = meta3?.prUrl ?? row.prUrl ?? null;
|
|
265541
|
+
return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
265542
|
+
children: [
|
|
265543
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
265544
|
+
width: 2,
|
|
265545
|
+
children: /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265546
|
+
color: "white",
|
|
265547
|
+
bold: true,
|
|
265548
|
+
children: isFocused ? "\u25B6" : " "
|
|
265549
|
+
}, undefined, false, undefined, this)
|
|
265550
|
+
}, undefined, false, undefined, this),
|
|
265551
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
265552
|
+
width: idxWidth,
|
|
265553
|
+
children: /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265554
|
+
dimColor: !isFocused,
|
|
265555
|
+
children: [
|
|
265556
|
+
"[",
|
|
265557
|
+
i + 1,
|
|
265558
|
+
"]"
|
|
265559
|
+
]
|
|
265560
|
+
}, undefined, true, undefined, this)
|
|
265561
|
+
}, undefined, false, undefined, this),
|
|
265562
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
265563
|
+
width: idColWidth + 1,
|
|
265564
|
+
children: [
|
|
265565
|
+
indent && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265566
|
+
dimColor: true,
|
|
265567
|
+
children: indent
|
|
265568
|
+
}, undefined, false, undefined, this),
|
|
265569
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Link, {
|
|
265570
|
+
url: row.url,
|
|
265571
|
+
label: row.identifier,
|
|
265572
|
+
color: isFocused ? "cyan" : "gray"
|
|
265573
|
+
}, undefined, false, undefined, this)
|
|
265574
|
+
]
|
|
265575
|
+
}, undefined, true, undefined, this),
|
|
265576
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(PipelineCells, {
|
|
265577
|
+
glyphs: pipelineStages(row).map((s) => s.status)
|
|
265578
|
+
}, undefined, false, undefined, this),
|
|
265579
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265580
|
+
color: isFocused ? "white" : "gray",
|
|
265581
|
+
dimColor: !isFocused,
|
|
265582
|
+
children: [
|
|
265583
|
+
" ",
|
|
265584
|
+
statusLabel(row)
|
|
265585
|
+
]
|
|
265586
|
+
}, undefined, true, undefined, this),
|
|
265587
|
+
blockers.length > 0 && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265588
|
+
color: "yellow",
|
|
265589
|
+
dimColor: !isFocused,
|
|
265590
|
+
children: [
|
|
265591
|
+
" \u26D3 ",
|
|
265592
|
+
trunc(blockers.join(", "), 28)
|
|
265593
|
+
]
|
|
265594
|
+
}, undefined, true, undefined, this),
|
|
265595
|
+
waitingForWorker ? /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265596
|
+
color: "yellow",
|
|
265597
|
+
children: " waiting for worker"
|
|
265598
|
+
}, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265599
|
+
dimColor: true,
|
|
265600
|
+
children: [
|
|
265601
|
+
" ",
|
|
265602
|
+
age
|
|
265603
|
+
]
|
|
265604
|
+
}, undefined, true, undefined, this),
|
|
265605
|
+
prUrl && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(jsx_dev_runtime11.Fragment, {
|
|
265606
|
+
children: [
|
|
265607
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265608
|
+
dimColor: true,
|
|
265609
|
+
children: " \u2197"
|
|
265610
|
+
}, undefined, false, undefined, this),
|
|
265611
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Link, {
|
|
265612
|
+
url: prUrl,
|
|
265613
|
+
label: prLabel(prUrl),
|
|
265614
|
+
color: "green"
|
|
265615
|
+
}, undefined, false, undefined, this)
|
|
265616
|
+
]
|
|
265617
|
+
}, undefined, true, undefined, this)
|
|
265618
|
+
]
|
|
265619
|
+
}, row.id, true, undefined, this);
|
|
265620
|
+
}),
|
|
265621
|
+
stalled && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
265622
|
+
marginTop: 1,
|
|
265623
|
+
children: [
|
|
265624
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265625
|
+
color: "yellow",
|
|
265626
|
+
bold: true,
|
|
265627
|
+
children: "\u23F8 nothing can start"
|
|
265628
|
+
}, undefined, false, undefined, this),
|
|
265629
|
+
stallParts.length > 0 && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265630
|
+
color: "yellow",
|
|
265631
|
+
children: ` \u2014 ${stallParts.join(" \xB7 ")}`
|
|
265632
|
+
}, undefined, false, undefined, this)
|
|
265633
|
+
]
|
|
265634
|
+
}, undefined, true, undefined, this)
|
|
265635
|
+
]
|
|
265636
|
+
}, undefined, true, undefined, this);
|
|
265637
|
+
})()
|
|
265638
|
+
}, undefined, false, undefined, this);
|
|
265257
265639
|
})(),
|
|
265258
|
-
|
|
265259
|
-
const
|
|
265640
|
+
focusedWorker && (() => {
|
|
265641
|
+
const w2 = focusedWorker;
|
|
265260
265642
|
const meta3 = workerMetaRef.current.get(w2.changeName);
|
|
265261
265643
|
const elapsed = meta3 ? fmtElapsed(now2 - meta3.startedAt) : "\u2013";
|
|
265262
265644
|
const iter = meta3?.iter ?? 0;
|
|
@@ -265270,122 +265652,10 @@ function AgentMode({
|
|
|
265270
265652
|
const taskProgress = meta3?.taskProgress ?? null;
|
|
265271
265653
|
const openspecPhase = meta3?.openspecPhase ?? null;
|
|
265272
265654
|
const subtasks = meta3?.subtasks ?? [];
|
|
265273
|
-
const pBadge = priorityBadge(w2.issue.priority);
|
|
265274
265655
|
const mBadge = modeBadge(w2.trigger);
|
|
265275
265656
|
const pColor = phaseColor(phase2);
|
|
265276
|
-
const bColor =
|
|
265277
|
-
const visibleTailLines =
|
|
265278
|
-
if (!isFocused && activeCount > 1) {
|
|
265279
|
-
const cardLabelWidth2 = (prUrl ? prLabel(prUrl).length + 3 : 0) + w2.issueIdentifier.length + 2;
|
|
265280
|
-
const cardLabelNode2 = /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(jsx_dev_runtime11.Fragment, {
|
|
265281
|
-
children: [
|
|
265282
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265283
|
-
color: "gray",
|
|
265284
|
-
children: " "
|
|
265285
|
-
}, undefined, false, undefined, this),
|
|
265286
|
-
prUrl && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Link, {
|
|
265287
|
-
url: prUrl,
|
|
265288
|
-
label: prLabel(prUrl),
|
|
265289
|
-
color: "green"
|
|
265290
|
-
}, undefined, false, undefined, this),
|
|
265291
|
-
prUrl && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265292
|
-
color: "gray",
|
|
265293
|
-
children: " \xB7 "
|
|
265294
|
-
}, undefined, false, undefined, this),
|
|
265295
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Link, {
|
|
265296
|
-
url: w2.issue.url,
|
|
265297
|
-
label: w2.issueIdentifier,
|
|
265298
|
-
color: "cyan"
|
|
265299
|
-
}, undefined, false, undefined, this),
|
|
265300
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265301
|
-
color: "gray",
|
|
265302
|
-
children: " "
|
|
265303
|
-
}, undefined, false, undefined, this)
|
|
265304
|
-
]
|
|
265305
|
-
}, undefined, true, undefined, this);
|
|
265306
|
-
return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(LabeledBox, {
|
|
265307
|
-
labelNode: cardLabelNode2,
|
|
265308
|
-
labelVisualWidth: cardLabelWidth2,
|
|
265309
|
-
borderColor: "gray",
|
|
265310
|
-
paddingX: 1,
|
|
265311
|
-
gap: 2,
|
|
265312
|
-
width: termWidth,
|
|
265313
|
-
children: [
|
|
265314
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265315
|
-
dimColor: true,
|
|
265316
|
-
children: [
|
|
265317
|
-
"[",
|
|
265318
|
-
idx + 1,
|
|
265319
|
-
"]"
|
|
265320
|
-
]
|
|
265321
|
-
}, undefined, true, undefined, this),
|
|
265322
|
-
pBadge.label && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265323
|
-
color: pBadge.color,
|
|
265324
|
-
children: pBadge.text
|
|
265325
|
-
}, undefined, false, undefined, this),
|
|
265326
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265327
|
-
color: "gray",
|
|
265328
|
-
bold: true,
|
|
265329
|
-
children: w2.issueIdentifier
|
|
265330
|
-
}, undefined, false, undefined, this),
|
|
265331
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265332
|
-
dimColor: true,
|
|
265333
|
-
children: trunc(w2.issue.title, 40)
|
|
265334
|
-
}, undefined, false, undefined, this),
|
|
265335
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265336
|
-
dimColor: true,
|
|
265337
|
-
children: "\u2502"
|
|
265338
|
-
}, undefined, false, undefined, this),
|
|
265339
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265340
|
-
color: pColor,
|
|
265341
|
-
dimColor: true,
|
|
265342
|
-
children: phase2
|
|
265343
|
-
}, undefined, false, undefined, this),
|
|
265344
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265345
|
-
dimColor: true,
|
|
265346
|
-
children: "\u2502"
|
|
265347
|
-
}, undefined, false, undefined, this),
|
|
265348
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265349
|
-
dimColor: true,
|
|
265350
|
-
children: elapsed
|
|
265351
|
-
}, undefined, false, undefined, this),
|
|
265352
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265353
|
-
dimColor: true,
|
|
265354
|
-
children: "\xB7"
|
|
265355
|
-
}, undefined, false, undefined, this),
|
|
265356
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265357
|
-
dimColor: true,
|
|
265358
|
-
children: [
|
|
265359
|
-
"\u21BA ",
|
|
265360
|
-
iter
|
|
265361
|
-
]
|
|
265362
|
-
}, undefined, true, undefined, this),
|
|
265363
|
-
currentTask && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(jsx_dev_runtime11.Fragment, {
|
|
265364
|
-
children: [
|
|
265365
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265366
|
-
dimColor: true,
|
|
265367
|
-
children: "\u2502"
|
|
265368
|
-
}, undefined, false, undefined, this),
|
|
265369
|
-
openspecPhase && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265370
|
-
color: openspecPhaseColor(openspecPhase),
|
|
265371
|
-
children: [
|
|
265372
|
-
"[",
|
|
265373
|
-
openspecPhase,
|
|
265374
|
-
"]"
|
|
265375
|
-
]
|
|
265376
|
-
}, undefined, true, undefined, this),
|
|
265377
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265378
|
-
dimColor: true,
|
|
265379
|
-
children: [
|
|
265380
|
-
"\u25B6 ",
|
|
265381
|
-
trunc(currentTask, 40)
|
|
265382
|
-
]
|
|
265383
|
-
}, undefined, true, undefined, this)
|
|
265384
|
-
]
|
|
265385
|
-
}, undefined, true, undefined, this)
|
|
265386
|
-
]
|
|
265387
|
-
}, w2.changeName, true, undefined, this);
|
|
265388
|
-
}
|
|
265657
|
+
const bColor = workerBorderColor(phase2);
|
|
265658
|
+
const visibleTailLines = focusedTailLines;
|
|
265389
265659
|
const cardLabelWidth = (prUrl ? prLabel(prUrl).length + 3 : 0) + w2.issueIdentifier.length + 2;
|
|
265390
265660
|
const cardLabelNode = /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(jsx_dev_runtime11.Fragment, {
|
|
265391
265661
|
children: [
|
|
@@ -265610,7 +265880,7 @@ function AgentMode({
|
|
|
265610
265880
|
}, undefined, false, undefined, this)
|
|
265611
265881
|
]
|
|
265612
265882
|
}, undefined, true, undefined, this),
|
|
265613
|
-
steeringActive &&
|
|
265883
|
+
steeringActive && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
265614
265884
|
marginTop: 0,
|
|
265615
265885
|
children: /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(SteeringField, {
|
|
265616
265886
|
active: steeringActive,
|
|
@@ -265628,8 +265898,12 @@ function AgentMode({
|
|
|
265628
265898
|
},
|
|
265629
265899
|
onSubmit: async (message) => {
|
|
265630
265900
|
try {
|
|
265631
|
-
await appendSteering2(
|
|
265632
|
-
fileEmit({
|
|
265901
|
+
await appendSteering2(join38(tasksDir, w2.changeName), message);
|
|
265902
|
+
fileEmit({
|
|
265903
|
+
type: "steering_submitted",
|
|
265904
|
+
changeName: w2.changeName,
|
|
265905
|
+
message
|
|
265906
|
+
});
|
|
265633
265907
|
} catch (err) {
|
|
265634
265908
|
const text = err.message;
|
|
265635
265909
|
fileEmit({
|
|
@@ -265705,7 +265979,108 @@ function AgentMode({
|
|
|
265705
265979
|
})()
|
|
265706
265980
|
]
|
|
265707
265981
|
}, w2.changeName, true, undefined, this);
|
|
265708
|
-
})
|
|
265982
|
+
})(),
|
|
265983
|
+
!focusedWorker && focusedRow && (() => {
|
|
265984
|
+
const row = focusedRow;
|
|
265985
|
+
let age = "\u2013";
|
|
265986
|
+
if (row.recovery?.firstFailedAt) {
|
|
265987
|
+
const failedAt = Date.parse(row.recovery.firstFailedAt);
|
|
265988
|
+
if (!Number.isNaN(failedAt))
|
|
265989
|
+
age = fmtElapsed(now2 - failedAt);
|
|
265990
|
+
}
|
|
265991
|
+
const prUrl = row.prUrl ?? null;
|
|
265992
|
+
const cardLabelWidth = (prUrl ? prLabel(prUrl).length + 3 : 0) + row.identifier.length + 2;
|
|
265993
|
+
const cardLabelNode = /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(jsx_dev_runtime11.Fragment, {
|
|
265994
|
+
children: [
|
|
265995
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265996
|
+
color: "gray",
|
|
265997
|
+
children: " "
|
|
265998
|
+
}, undefined, false, undefined, this),
|
|
265999
|
+
prUrl && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Link, {
|
|
266000
|
+
url: prUrl,
|
|
266001
|
+
label: prLabel(prUrl),
|
|
266002
|
+
color: "green"
|
|
266003
|
+
}, undefined, false, undefined, this),
|
|
266004
|
+
prUrl && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
266005
|
+
color: "gray",
|
|
266006
|
+
children: " \xB7 "
|
|
266007
|
+
}, undefined, false, undefined, this),
|
|
266008
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Link, {
|
|
266009
|
+
url: row.url,
|
|
266010
|
+
label: row.identifier,
|
|
266011
|
+
color: "cyan"
|
|
266012
|
+
}, undefined, false, undefined, this),
|
|
266013
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
266014
|
+
color: "gray",
|
|
266015
|
+
children: " "
|
|
266016
|
+
}, undefined, false, undefined, this)
|
|
266017
|
+
]
|
|
266018
|
+
}, undefined, true, undefined, this);
|
|
266019
|
+
return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(LabeledBox, {
|
|
266020
|
+
labelNode: cardLabelNode,
|
|
266021
|
+
labelVisualWidth: cardLabelWidth,
|
|
266022
|
+
borderColor: "gray",
|
|
266023
|
+
flexDirection: "column",
|
|
266024
|
+
paddingX: 1,
|
|
266025
|
+
width: termWidth,
|
|
266026
|
+
children: [
|
|
266027
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
266028
|
+
color: "white",
|
|
266029
|
+
bold: true,
|
|
266030
|
+
children: trunc(row.title, Math.max(20, termWidth - 20))
|
|
266031
|
+
}, undefined, false, undefined, this),
|
|
266032
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
266033
|
+
marginTop: 0,
|
|
266034
|
+
children: [
|
|
266035
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(PipelineCells, {
|
|
266036
|
+
glyphs: pipelineStages(row).map((s) => s.status)
|
|
266037
|
+
}, undefined, false, undefined, this),
|
|
266038
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
266039
|
+
color: "white",
|
|
266040
|
+
children: [
|
|
266041
|
+
" ",
|
|
266042
|
+
statusLabel(row)
|
|
266043
|
+
]
|
|
266044
|
+
}, undefined, true, undefined, this)
|
|
266045
|
+
]
|
|
266046
|
+
}, undefined, true, undefined, this),
|
|
266047
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
266048
|
+
gap: 2,
|
|
266049
|
+
marginTop: 0,
|
|
266050
|
+
children: [
|
|
266051
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
266052
|
+
dimColor: true,
|
|
266053
|
+
children: "parked \xB7 no live worker"
|
|
266054
|
+
}, undefined, false, undefined, this),
|
|
266055
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
266056
|
+
dimColor: true,
|
|
266057
|
+
children: "\u2502"
|
|
266058
|
+
}, undefined, false, undefined, this),
|
|
266059
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
266060
|
+
dimColor: true,
|
|
266061
|
+
children: [
|
|
266062
|
+
"age ",
|
|
266063
|
+
age
|
|
266064
|
+
]
|
|
266065
|
+
}, undefined, true, undefined, this),
|
|
266066
|
+
prUrl && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(jsx_dev_runtime11.Fragment, {
|
|
266067
|
+
children: [
|
|
266068
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
266069
|
+
dimColor: true,
|
|
266070
|
+
children: "\u2502"
|
|
266071
|
+
}, undefined, false, undefined, this),
|
|
266072
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Link, {
|
|
266073
|
+
url: prUrl,
|
|
266074
|
+
label: prLabel(prUrl),
|
|
266075
|
+
color: "green"
|
|
266076
|
+
}, undefined, false, undefined, this)
|
|
266077
|
+
]
|
|
266078
|
+
}, undefined, true, undefined, this)
|
|
266079
|
+
]
|
|
266080
|
+
}, undefined, true, undefined, this)
|
|
266081
|
+
]
|
|
266082
|
+
}, row.id, true, undefined, this);
|
|
266083
|
+
})()
|
|
265709
266084
|
]
|
|
265710
266085
|
}, undefined, true, undefined, this),
|
|
265711
266086
|
awaitingClose && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
@@ -265715,13 +266090,14 @@ function AgentMode({
|
|
|
265715
266090
|
]
|
|
265716
266091
|
}, resizeKey, true, undefined, this);
|
|
265717
266092
|
}
|
|
265718
|
-
var import_react63, jsx_dev_runtime11, lineCounter = 0, TAIL_BUFFER_SIZE = 30, CMD_DISPLAY_MAX = 80, MAX_PENDING_DISPLAY = 15, SPINNER_FRAMES, HYPERLINKS_SUPPORTED, SESSION_START;
|
|
266093
|
+
var import_react63, jsx_dev_runtime11, lineCounter = 0, TAIL_BUFFER_SIZE = 30, CMD_DISPLAY_MAX = 80, MAX_PENDING_DISPLAY = 15, SPINNER_FRAMES, WORKER_WAIT_STATES, ADVANCING_STATES, HYPERLINKS_SUPPORTED, NODE_LABELS, NODE_CELL_WIDTH = 4, PIPELINE_CONNECTOR = "\u2500\u2500", SESSION_START;
|
|
265719
266094
|
var init_AgentMode = __esm(async () => {
|
|
265720
266095
|
init_cli2();
|
|
265721
266096
|
init_config();
|
|
265722
266097
|
init_wire();
|
|
265723
266098
|
init_preflight();
|
|
265724
266099
|
init_json_log_file();
|
|
266100
|
+
init_task_pipeline();
|
|
265725
266101
|
init_phase();
|
|
265726
266102
|
init_log();
|
|
265727
266103
|
init_useTerminalSize();
|
|
@@ -265737,7 +266113,32 @@ var init_AgentMode = __esm(async () => {
|
|
|
265737
266113
|
import_react63 = __toESM(require_react(), 1);
|
|
265738
266114
|
jsx_dev_runtime11 = __toESM(require_jsx_dev_runtime(), 1);
|
|
265739
266115
|
SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
266116
|
+
WORKER_WAIT_STATES = new Set([
|
|
266117
|
+
"queued",
|
|
266118
|
+
"working",
|
|
266119
|
+
"in-progress",
|
|
266120
|
+
"conflict-fix",
|
|
266121
|
+
"ci-fix",
|
|
266122
|
+
"review"
|
|
266123
|
+
]);
|
|
266124
|
+
ADVANCING_STATES = new Set([
|
|
266125
|
+
"queued",
|
|
266126
|
+
"working",
|
|
266127
|
+
"in-progress",
|
|
266128
|
+
"conflict-fix",
|
|
266129
|
+
"ci-fix",
|
|
266130
|
+
"review",
|
|
266131
|
+
"awaiting-ci"
|
|
266132
|
+
]);
|
|
265740
266133
|
HYPERLINKS_SUPPORTED = !process.env["TMUX"];
|
|
266134
|
+
NODE_LABELS = {
|
|
266135
|
+
todo: "todo",
|
|
266136
|
+
confirmation: "conf",
|
|
266137
|
+
work: "work",
|
|
266138
|
+
PR: "PR",
|
|
266139
|
+
CI: "CI",
|
|
266140
|
+
done: "done"
|
|
266141
|
+
};
|
|
265741
266142
|
SESSION_START = new Date().toISOString();
|
|
265742
266143
|
});
|
|
265743
266144
|
|
|
@@ -265937,7 +266338,7 @@ __export(exports_list, {
|
|
|
265937
266338
|
buildBuckets: () => buildBuckets,
|
|
265938
266339
|
backlogRankByIssueId: () => backlogRankByIssueId
|
|
265939
266340
|
});
|
|
265940
|
-
import { join as
|
|
266341
|
+
import { join as join39 } from "path";
|
|
265941
266342
|
function countTaskItems(content) {
|
|
265942
266343
|
const checked = (content.match(/^- \[x\]/gm) ?? []).length;
|
|
265943
266344
|
const unchecked = (content.match(/^- \[ \]/gm) ?? []).length;
|
|
@@ -265953,13 +266354,13 @@ function buildLocalRows() {
|
|
|
265953
266354
|
const sources = [{ dir: statesDir, label: "main" }];
|
|
265954
266355
|
const worktreesRoot = worktreesDir2(projectRoot);
|
|
265955
266356
|
for (const wt of storage.list(worktreesRoot)) {
|
|
265956
|
-
sources.push({ dir:
|
|
266357
|
+
sources.push({ dir: join39(worktreesRoot, wt, ".ralph", "tasks"), label: `wt:${wt}` });
|
|
265957
266358
|
}
|
|
265958
266359
|
for (const { dir, label } of sources) {
|
|
265959
266360
|
for (const entry of storage.list(dir)) {
|
|
265960
266361
|
if (seen.has(entry))
|
|
265961
266362
|
continue;
|
|
265962
|
-
const raw = storage.read(
|
|
266363
|
+
const raw = storage.read(join39(dir, entry, ".ralph-state.json"));
|
|
265963
266364
|
if (raw === null)
|
|
265964
266365
|
continue;
|
|
265965
266366
|
let state;
|
|
@@ -265974,7 +266375,7 @@ function buildLocalRows() {
|
|
|
265974
266375
|
const firstLine = promptRaw.split(`
|
|
265975
266376
|
`).find((l3) => l3.trim() !== "") ?? "";
|
|
265976
266377
|
let progress = "\u2014";
|
|
265977
|
-
const tasksContent = storage.read(
|
|
266378
|
+
const tasksContent = storage.read(join39(dir, entry, "tasks.md"));
|
|
265978
266379
|
if (tasksContent !== null) {
|
|
265979
266380
|
const { checked, unchecked } = countTaskItems(tasksContent);
|
|
265980
266381
|
const total = checked + unchecked;
|
|
@@ -266037,14 +266438,14 @@ function buildBuckets(indicators) {
|
|
|
266037
266438
|
{ label: "auto-merge", indicator: indicators.getAutoMerge, exclude: [] }
|
|
266038
266439
|
];
|
|
266039
266440
|
}
|
|
266040
|
-
async function fetchBucketIssues(apiKey, bucket, team, assignee, anyAssignee,
|
|
266441
|
+
async function fetchBucketIssues(apiKey, bucket, team, assignee, anyAssignee, scope, ticketNumbers) {
|
|
266041
266442
|
if (!bucket.indicator || bucket.indicator.filter.length === 0)
|
|
266042
266443
|
return [];
|
|
266043
266444
|
const spec = {
|
|
266044
266445
|
team,
|
|
266045
266446
|
assignee,
|
|
266046
266447
|
anyAssignee,
|
|
266047
|
-
|
|
266448
|
+
...scope,
|
|
266048
266449
|
include: bucket.indicator.filter,
|
|
266049
266450
|
exclude: bucket.exclude,
|
|
266050
266451
|
...ticketNumbers.length > 0 ? { numbers: ticketNumbers } : {}
|
|
@@ -266097,13 +266498,13 @@ function backlogRankByIssueId(issues) {
|
|
|
266097
266498
|
ordered.forEach((o, i) => rankById.set(o.id, i));
|
|
266098
266499
|
return rankById;
|
|
266099
266500
|
}
|
|
266100
|
-
async function fetchAndPrintLinear(apiKey, buckets, team, assignee, anyAssignee,
|
|
266501
|
+
async function fetchAndPrintLinear(apiKey, buckets, team, assignee, anyAssignee, scope, cwd2, runner, ignoreCiChecks = [], checks3 = false, review = false, ticketNumbers = []) {
|
|
266101
266502
|
const bucketResults = await Promise.all(buckets.map(async (bucket) => {
|
|
266102
266503
|
if (!bucket.indicator || bucket.indicator.filter.length === 0) {
|
|
266103
266504
|
return { bucket, issues: [], error: null };
|
|
266104
266505
|
}
|
|
266105
266506
|
try {
|
|
266106
|
-
const issues = await fetchBucketIssues(apiKey, bucket, team, assignee, anyAssignee,
|
|
266507
|
+
const issues = await fetchBucketIssues(apiKey, bucket, team, assignee, anyAssignee, scope, ticketNumbers);
|
|
266107
266508
|
return { bucket, issues, error: null };
|
|
266108
266509
|
} catch (err) {
|
|
266109
266510
|
return {
|
|
@@ -266239,7 +266640,9 @@ async function runList(input) {
|
|
|
266239
266640
|
const apiKey = process.env["LINEAR_API_KEY"];
|
|
266240
266641
|
const indicators = cfg.linear.indicators;
|
|
266241
266642
|
const team = input.linearTeamOverride || cfg.linear.team;
|
|
266242
|
-
const
|
|
266643
|
+
const resolved = resolveLinearFilter(applyAssigneeOverride(cfg.linear.filter, input.linearAssigneeOverride));
|
|
266644
|
+
const { assignee, anyAssignee } = resolved;
|
|
266645
|
+
const scope = linearFilterScope(resolved);
|
|
266243
266646
|
const buckets = buildBuckets(indicators);
|
|
266244
266647
|
const anyConfigured = buckets.some((b2) => b2.indicator && b2.indicator.filter.length > 0);
|
|
266245
266648
|
if (!anyConfigured) {
|
|
@@ -266279,7 +266682,7 @@ team: ${team}
|
|
|
266279
266682
|
if (ticketNumbers.length > 0)
|
|
266280
266683
|
process.stdout.write(`ticket: ${ticketNumbers.join(", ")}
|
|
266281
266684
|
`);
|
|
266282
|
-
await fetchAndPrintLinear(apiKey, buckets, team, assignee, anyAssignee,
|
|
266685
|
+
await fetchAndPrintLinear(apiKey, buckets, team, assignee, anyAssignee, scope, projectRoot, localCmdRunner, cfg.prRecovery.ignoreChecks, input.checks, input.review, ticketNumbers);
|
|
266283
266686
|
}
|
|
266284
266687
|
function normalizeIdentifier(input) {
|
|
266285
266688
|
let parsed;
|
|
@@ -266307,8 +266710,8 @@ async function fetchIssueByIdentifier(apiKey, identifier) {
|
|
|
266307
266710
|
team { key }
|
|
266308
266711
|
labels { nodes { name } }
|
|
266309
266712
|
attachments(first: 25) { nodes { title subtitle } }
|
|
266310
|
-
|
|
266311
|
-
nodes { type
|
|
266713
|
+
inverseRelations(first: 50) {
|
|
266714
|
+
nodes { type issue { id identifier state { type } } }
|
|
266312
266715
|
}
|
|
266313
266716
|
}
|
|
266314
266717
|
}
|
|
@@ -266362,7 +266765,7 @@ async function runListDebug(input) {
|
|
|
266362
266765
|
const cfg = await loadRalphyConfig(projectRoot, getArgs().workflowFile);
|
|
266363
266766
|
const indicators = cfg.linear.indicators;
|
|
266364
266767
|
const team = input.linearTeamOverride || cfg.linear.team;
|
|
266365
|
-
const { assignee, anyAssignee, requireAllLabels } = resolveLinearFilter(applyAssigneeOverride(cfg.linear.filter, input.linearAssigneeOverride));
|
|
266768
|
+
const { assignee, anyAssignee, requireAllLabels, excludeLabels } = resolveLinearFilter(applyAssigneeOverride(cfg.linear.filter, input.linearAssigneeOverride));
|
|
266366
266769
|
const assigneeLabel = anyAssignee ? "any" : assignee ?? "*";
|
|
266367
266770
|
const normalized = normalizeIdentifier(identifier);
|
|
266368
266771
|
if (!normalized) {
|
|
@@ -266387,7 +266790,7 @@ Found ${issue2.identifier} \u2014 "${issue2.title}"
|
|
|
266387
266790
|
` + ` assignee: ${issue2.assignee ? `${issue2.assignee.name} <${issue2.assignee.email ?? "no-email"}>` : "(unassigned)"}
|
|
266388
266791
|
` + ` labels: ${issue2.labels.nodes.map((l3) => l3.name).join(", ") || "(none)"}
|
|
266389
266792
|
`);
|
|
266390
|
-
const blockedBy = issue2.
|
|
266793
|
+
const blockedBy = issue2.inverseRelations.nodes.filter((r) => r.type === "blocks" && r.issue.state.type !== "completed" && r.issue.state.type !== "cancelled").map((r) => r.issue.identifier);
|
|
266391
266794
|
process.stdout.write(`
|
|
266392
266795
|
Per-bucket diagnostics:
|
|
266393
266796
|
`);
|
|
@@ -266413,6 +266816,13 @@ Per-bucket diagnostics:
|
|
|
266413
266816
|
reasons.push(`missing required linear.filter label(s): ${missing.join(", ")}`);
|
|
266414
266817
|
}
|
|
266415
266818
|
}
|
|
266819
|
+
if (excludeLabels && excludeLabels.length > 0) {
|
|
266820
|
+
const issueLabels = new Set(issue2.labels.nodes.map((l3) => l3.name));
|
|
266821
|
+
const present = excludeLabels.filter((label) => issueLabels.has(label));
|
|
266822
|
+
if (present.length > 0) {
|
|
266823
|
+
reasons.push(`carries excluded linear.filter label(s): ${present.join(", ")}`);
|
|
266824
|
+
}
|
|
266825
|
+
}
|
|
266416
266826
|
const includeMatches = bucket.indicator.filter.some((m2) => markerMatches(issue2, m2));
|
|
266417
266827
|
if (!includeMatches) {
|
|
266418
266828
|
const want = bucket.indicator.filter.map((m2) => `${m2.type}:${m2.value}`).join(" OR ");
|
|
@@ -266477,7 +266887,7 @@ var exports_json_runner = {};
|
|
|
266477
266887
|
__export(exports_json_runner, {
|
|
266478
266888
|
runAgentJson: () => runAgentJson
|
|
266479
266889
|
});
|
|
266480
|
-
import { join as
|
|
266890
|
+
import { join as join40 } from "path";
|
|
266481
266891
|
import { mkdir as mkdir12 } from "fs/promises";
|
|
266482
266892
|
import { homedir as homedir8 } from "os";
|
|
266483
266893
|
function makeEmit(fileSink) {
|
|
@@ -266499,7 +266909,7 @@ async function runAgentJson({
|
|
|
266499
266909
|
tasksDir,
|
|
266500
266910
|
runPreflight: runPreflight2 = runPreflight
|
|
266501
266911
|
}) {
|
|
266502
|
-
await mkdir12(
|
|
266912
|
+
await mkdir12(join40(homedir8(), ".ralph"), { recursive: true }).catch(() => {
|
|
266503
266913
|
return;
|
|
266504
266914
|
});
|
|
266505
266915
|
const fileSink = createJsonLogFileSink(args.jsonLogFile);
|
|
@@ -266719,7 +267129,7 @@ __export(exports_src3, {
|
|
|
266719
267129
|
main: () => main3
|
|
266720
267130
|
});
|
|
266721
267131
|
import { mkdir as mkdir13 } from "fs/promises";
|
|
266722
|
-
import { join as
|
|
267132
|
+
import { join as join41 } from "path";
|
|
266723
267133
|
async function main3(argv) {
|
|
266724
267134
|
if (argv.includes("--help") || argv.includes("-h")) {
|
|
266725
267135
|
printAgentHelp();
|
|
@@ -266784,7 +267194,7 @@ async function main3(argv) {
|
|
|
266784
267194
|
}
|
|
266785
267195
|
await mkdir13(statesDir, { recursive: true });
|
|
266786
267196
|
await mkdir13(tasksDir, { recursive: true });
|
|
266787
|
-
await mkdir13(
|
|
267197
|
+
await mkdir13(join41(projectRoot, ".ralph"), { recursive: true });
|
|
266788
267198
|
if (shouldFallbackToJsonOutput(args, process.stdin.isTTY)) {
|
|
266789
267199
|
process.stderr.write(`agent: stdin is not a TTY \u2014 falling back to --json-output mode.
|
|
266790
267200
|
`);
|