@neriros/ralphy 3.10.16 → 3.10.18
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 +2044 -1160
- package/package.json +3 -2
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.18")
|
|
18932
|
+
return "3.10.18";
|
|
18933
18933
|
} catch {}
|
|
18934
18934
|
const dirsToTry = [];
|
|
18935
18935
|
try {
|
|
@@ -19395,7 +19395,7 @@ function modelOptionValues() {
|
|
|
19395
19395
|
const field = findField("model");
|
|
19396
19396
|
return field && field.spec.kind === "select" ? field.spec.options.map((o) => o.value) : [];
|
|
19397
19397
|
}
|
|
19398
|
-
var PROMPT_BODY_FIELD_ID = "promptBody", REPO_LINK_FIELD_ID = "repo.link", yes = () => ({ kind: "confirm", defaultChoice: "confirm" }), no = () => ({ kind: "confirm", defaultChoice: "cancel" }), PROJECT_NAME, LINEAR_TEAM, REPO_LINK, LINEAR_ASSIGNEE_CHOICE_FIELD_ID = "linear.assigneeChoice", LINEAR_ASSIGNEE_VALUE_FIELD_ID = "linear.assigneeValue", LINEAR_FILTER_DESCRIPTION, LINEAR_ASSIGNEE_CHOICE, LINEAR_ASSIGNEE_VALUE, QUICK_FIELDS, isOn = (id) => (answers) => answers[id] === true, concurrencyForcesWorktree = (answers) => {
|
|
19398
|
+
var PROMPT_BODY_FIELD_ID = "promptBody", REPO_LINK_FIELD_ID = "repo.link", yes = () => ({ kind: "confirm", defaultChoice: "confirm" }), no = () => ({ kind: "confirm", defaultChoice: "cancel" }), PROJECT_NAME, LINEAR_TEAM, REPO_LINK, LINEAR_ASSIGNEE_CHOICE_FIELD_ID = "linear.assigneeChoice", LINEAR_ASSIGNEE_VALUE_FIELD_ID = "linear.assigneeValue", LINEAR_FILTER_DESCRIPTION, LINEAR_ASSIGNEE_CHOICE, LINEAR_ASSIGNEE_VALUE, QUICK_FIELDS, isOn = (id) => (answers) => answers[id] === true, trackerIsGithub = (answers) => answers["tracker.kind"] === "github", concurrencyForcesWorktree = (answers) => {
|
|
19399
19399
|
const value = answers["concurrency"];
|
|
19400
19400
|
return typeof value === "number" && value > 1;
|
|
19401
19401
|
}, worktreeEnabled = (answers) => answers["useWorktree"] === true || concurrencyForcesWorktree(answers), HIDDEN_FIELD_IDS, CUSTOMIZED_FIELDS, COMMON_CLI_OPTIONS, FIELD_DESCRIPTIONS;
|
|
@@ -19537,6 +19537,66 @@ var init_fields = __esm(() => {
|
|
|
19537
19537
|
description: "Show detailed per-task output (passes --verbose to the task sub-process) for extra diagnostics.",
|
|
19538
19538
|
spec: no()
|
|
19539
19539
|
},
|
|
19540
|
+
{
|
|
19541
|
+
id: "tracker.kind",
|
|
19542
|
+
label: "Issue tracker",
|
|
19543
|
+
description: "Which issue tracker drives the loop: 'linear' (the default) or 'github' (GitHub Issues, via the gh CLI).",
|
|
19544
|
+
spec: {
|
|
19545
|
+
kind: "select",
|
|
19546
|
+
options: [
|
|
19547
|
+
{ label: "Linear", value: "linear" },
|
|
19548
|
+
{ label: "GitHub", value: "github" }
|
|
19549
|
+
]
|
|
19550
|
+
}
|
|
19551
|
+
},
|
|
19552
|
+
{
|
|
19553
|
+
id: "github.issues.repo",
|
|
19554
|
+
label: "GitHub repository (owner/name)",
|
|
19555
|
+
hint: "blank = detected from origin",
|
|
19556
|
+
description: "The owner/name of the GitHub repo whose issues drive the loop. Leave blank to use the repo detected from the git 'origin' remote.",
|
|
19557
|
+
emptyLabel: "detected from origin",
|
|
19558
|
+
spec: { kind: "text", placeholder: "owner/name" },
|
|
19559
|
+
when: trackerIsGithub
|
|
19560
|
+
},
|
|
19561
|
+
{
|
|
19562
|
+
id: "github.issues.label",
|
|
19563
|
+
label: "Todo label",
|
|
19564
|
+
hint: "blank = any open issue",
|
|
19565
|
+
description: "Only pick up GitHub issues carrying this label. Leave blank to consider every open issue.",
|
|
19566
|
+
emptyLabel: "any open issue",
|
|
19567
|
+
spec: { kind: "text", placeholder: "ralph:todo" },
|
|
19568
|
+
when: trackerIsGithub
|
|
19569
|
+
},
|
|
19570
|
+
{
|
|
19571
|
+
id: "github.issues.assignee",
|
|
19572
|
+
label: "Assignee filter",
|
|
19573
|
+
hint: "blank = any assignee; @me = you",
|
|
19574
|
+
description: "Only pick up GitHub issues assigned to this login. Use '@me' for yourself; leave blank to ignore the assignee.",
|
|
19575
|
+
emptyLabel: "any assignee",
|
|
19576
|
+
spec: { kind: "text", placeholder: "@me" },
|
|
19577
|
+
when: trackerIsGithub
|
|
19578
|
+
},
|
|
19579
|
+
{
|
|
19580
|
+
id: "github.issues.statusLabels.inProgress",
|
|
19581
|
+
label: "In-progress label",
|
|
19582
|
+
description: "GitHub label applied to an issue while Ralphy is actively working on it (and removed from the todo label).",
|
|
19583
|
+
spec: { kind: "text", placeholder: "ralph:in-progress" },
|
|
19584
|
+
when: trackerIsGithub
|
|
19585
|
+
},
|
|
19586
|
+
{
|
|
19587
|
+
id: "github.issues.statusLabels.done",
|
|
19588
|
+
label: "Done label",
|
|
19589
|
+
description: "GitHub label applied to an issue when its work completes; the issue is also closed.",
|
|
19590
|
+
spec: { kind: "text", placeholder: "ralph:done" },
|
|
19591
|
+
when: trackerIsGithub
|
|
19592
|
+
},
|
|
19593
|
+
{
|
|
19594
|
+
id: "github.issues.statusLabels.error",
|
|
19595
|
+
label: "Error label",
|
|
19596
|
+
description: "GitHub label applied to an issue when Ralphy quarantines it after repeated failures.",
|
|
19597
|
+
spec: { kind: "text", placeholder: "ralph:error" },
|
|
19598
|
+
when: trackerIsGithub
|
|
19599
|
+
},
|
|
19540
19600
|
{
|
|
19541
19601
|
id: "concurrency",
|
|
19542
19602
|
label: "Concurrency (parallel tasks)",
|
|
@@ -19595,8 +19655,8 @@ var init_fields = __esm(() => {
|
|
|
19595
19655
|
},
|
|
19596
19656
|
{
|
|
19597
19657
|
id: "setupScript",
|
|
19598
|
-
label: "Worktree setup script (runs
|
|
19599
|
-
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.",
|
|
19600
19660
|
spec: { kind: "text" },
|
|
19601
19661
|
when: worktreeEnabled
|
|
19602
19662
|
},
|
|
@@ -19639,6 +19699,13 @@ var init_fields = __esm(() => {
|
|
|
19639
19699
|
spec: { kind: "text", placeholder: "main" },
|
|
19640
19700
|
when: isOn("createPrOnSuccess")
|
|
19641
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
|
+
},
|
|
19642
19709
|
{
|
|
19643
19710
|
id: "stackPrsOnDependencies",
|
|
19644
19711
|
label: "Stack dependent issues' PRs onto their blocker's PR?",
|
|
@@ -81255,7 +81322,7 @@ function foldLegacyAssignee(v) {
|
|
|
81255
81322
|
}
|
|
81256
81323
|
return rest2;
|
|
81257
81324
|
}
|
|
81258
|
-
var CURRENT_WORKFLOW_VERSION =
|
|
81325
|
+
var CURRENT_WORKFLOW_VERSION = 8, MarkerSchema, FilterMarkerSchema, LinearFilterSchema, SET_INDICATOR_KEYS, GetIndicatorSchema, SetIndicatorSchema, IndicatorsSchema, ProjectSchema, CommandsSchema, DEFAULT_META_ONLY_FILES, BoundariesSchema, WorkflowConfigSchema;
|
|
81259
81326
|
var init_schema = __esm(() => {
|
|
81260
81327
|
init_zod();
|
|
81261
81328
|
MarkerSchema = exports_external.discriminatedUnion("type", [
|
|
@@ -81395,12 +81462,16 @@ var init_schema = __esm(() => {
|
|
|
81395
81462
|
createPrOnSuccess: exports_external.boolean().default(false),
|
|
81396
81463
|
prDraft: exports_external.boolean().default(false),
|
|
81397
81464
|
prBaseBranch: exports_external.string().default("main"),
|
|
81465
|
+
prLabels: exports_external.array(exports_external.string()).default([]),
|
|
81398
81466
|
stackPrsOnDependencies: exports_external.boolean().default(false),
|
|
81399
81467
|
autoMergeStrategy: exports_external.enum(["squash", "merge", "rebase"]).default("squash"),
|
|
81400
81468
|
manualMergeWhenAutoMergeDisabled: exports_external.boolean().default(true),
|
|
81401
81469
|
finalizeNoOpAsDone: exports_external.boolean().default(true),
|
|
81402
81470
|
engine: exports_external.enum(["claude", "codex"]).default("claude"),
|
|
81403
81471
|
model: exports_external.enum(["haiku", "sonnet", "opus"]).default("opus"),
|
|
81472
|
+
tracker: exports_external.object({
|
|
81473
|
+
kind: exports_external.enum(["linear", "github"]).default("linear")
|
|
81474
|
+
}).strict().default({ kind: "linear" }),
|
|
81404
81475
|
linear: exports_external.preprocess(foldLegacyAssignee, exports_external.object({
|
|
81405
81476
|
team: exports_external.string().optional(),
|
|
81406
81477
|
filter: LinearFilterSchema,
|
|
@@ -81445,7 +81516,22 @@ var init_schema = __esm(() => {
|
|
|
81445
81516
|
}),
|
|
81446
81517
|
github: exports_external.object({
|
|
81447
81518
|
base_branch: exports_external.string().optional(),
|
|
81448
|
-
auto_merge_strategy: exports_external.enum(["squash", "merge", "rebase"]).optional()
|
|
81519
|
+
auto_merge_strategy: exports_external.enum(["squash", "merge", "rebase"]).optional(),
|
|
81520
|
+
pr_labels: exports_external.array(exports_external.string()).optional(),
|
|
81521
|
+
issues: exports_external.object({
|
|
81522
|
+
repo: exports_external.string().optional(),
|
|
81523
|
+
label: exports_external.string().optional(),
|
|
81524
|
+
assignee: exports_external.string().optional(),
|
|
81525
|
+
statusLabels: exports_external.object({
|
|
81526
|
+
inProgress: exports_external.string().default("ralph:in-progress"),
|
|
81527
|
+
done: exports_external.string().default("ralph:done"),
|
|
81528
|
+
error: exports_external.string().default("ralph:error")
|
|
81529
|
+
}).strict().default({
|
|
81530
|
+
inProgress: "ralph:in-progress",
|
|
81531
|
+
done: "ralph:done",
|
|
81532
|
+
error: "ralph:error"
|
|
81533
|
+
})
|
|
81534
|
+
}).strict().optional()
|
|
81449
81535
|
}).strict().optional(),
|
|
81450
81536
|
agent: exports_external.object({
|
|
81451
81537
|
engine: exports_external.enum(["claude", "codex"]).optional(),
|
|
@@ -81514,7 +81600,7 @@ var init_schema = __esm(() => {
|
|
|
81514
81600
|
var FRONTMATTER_RE, DEFAULT_WORKFLOW_MD = `---
|
|
81515
81601
|
# WORKFLOW.md schema version \u2014 managed by \`ralphy init\`. When a newer version
|
|
81516
81602
|
# ships, re-running init migrates this file and fills in the new settings.
|
|
81517
|
-
version:
|
|
81603
|
+
version: 8
|
|
81518
81604
|
|
|
81519
81605
|
project:
|
|
81520
81606
|
name: ralphy
|
|
@@ -81566,6 +81652,11 @@ prDraft: true
|
|
|
81566
81652
|
prBaseBranch: main
|
|
81567
81653
|
stackPrsOnDependencies: false
|
|
81568
81654
|
autoMergeStrategy: squash
|
|
81655
|
+
# Labels attached to every PR Ralph opens (best-effort \u2014 a missing label is
|
|
81656
|
+
# logged, never fatal). The labels must already exist in the repo.
|
|
81657
|
+
# prLabels:
|
|
81658
|
+
# - ralph
|
|
81659
|
+
# - automated
|
|
81569
81660
|
|
|
81570
81661
|
prRecovery:
|
|
81571
81662
|
enabled: true
|
|
@@ -81581,6 +81672,16 @@ preExistingErrorCheck:
|
|
|
81581
81672
|
label: "ralph:pre-existing-error"
|
|
81582
81673
|
outputCharLimit: 4000
|
|
81583
81674
|
|
|
81675
|
+
tracker:
|
|
81676
|
+
kind: linear
|
|
81677
|
+
|
|
81678
|
+
github:
|
|
81679
|
+
issues:
|
|
81680
|
+
statusLabels:
|
|
81681
|
+
inProgress: "ralph:in-progress"
|
|
81682
|
+
done: "ralph:done"
|
|
81683
|
+
error: "ralph:error"
|
|
81684
|
+
|
|
81584
81685
|
linear:
|
|
81585
81686
|
# Global filter ANDed into every Linear query (and the GitHub PR searches
|
|
81586
81687
|
# rooted at those issues). A marker list of \`assignee\` and \`label\` clauses;
|
|
@@ -82288,6 +82389,9 @@ function applyAliases(cfg) {
|
|
|
82288
82389
|
if (cfg.github.auto_merge_strategy !== undefined && cfg.autoMergeStrategy === "squash") {
|
|
82289
82390
|
cfg.autoMergeStrategy = cfg.github.auto_merge_strategy;
|
|
82290
82391
|
}
|
|
82392
|
+
if (cfg.github.pr_labels !== undefined && cfg.prLabels.length === 0) {
|
|
82393
|
+
cfg.prLabels = cfg.github.pr_labels;
|
|
82394
|
+
}
|
|
82291
82395
|
}
|
|
82292
82396
|
if (cfg.agent) {
|
|
82293
82397
|
if (cfg.agent.engine !== undefined)
|
|
@@ -83405,6 +83509,12 @@ function buildFromAnswers(mode, answers, build = buildWorkflowMarkdown) {
|
|
|
83405
83509
|
}
|
|
83406
83510
|
}
|
|
83407
83511
|
}
|
|
83512
|
+
if (values2["tracker.kind"] !== "github") {
|
|
83513
|
+
for (const id of Object.keys(values2)) {
|
|
83514
|
+
if (id.startsWith("github.issues."))
|
|
83515
|
+
delete values2[id];
|
|
83516
|
+
}
|
|
83517
|
+
}
|
|
83408
83518
|
const linkRepo = values2[REPO_LINK_FIELD_ID] === true;
|
|
83409
83519
|
delete values2[REPO_LINK_FIELD_ID];
|
|
83410
83520
|
if (!linkRepo) {
|
|
@@ -84585,6 +84695,24 @@ var init_migrations = __esm(() => {
|
|
|
84585
84695
|
version: 6,
|
|
84586
84696
|
description: "PR recovery is unified under one `prRecovery` block (replacing " + "`prTracker`, `fixCiOnFailure`, `maxCiFixAttempts`, `ciPollIntervalSeconds`, " + "and `ignoreCiChecks`). Workers now open the PR and leave the ticket " + "in-review; a single background watcher advances it to done once the PR is " + "mergeable (CI green, no conflicts) and recovers red PRs \u2014 resolving merge " + "conflicts AND fixing failing CI (both `prRecovery.fixConflicts` and " + "`prRecovery.fixCi` default on; tune them in WORKFLOW.md). " + "`prRecovery.enabled: false` turns the watcher off everywhere and marks the " + "ticket done immediately on PR open. Your old values are migrated " + "automatically; review them here or keep them.",
|
|
84587
84697
|
fields: ["prRecovery.enabled", "prRecovery.maxRecoverySessions", "prRecovery.ignoreChecks"]
|
|
84698
|
+
},
|
|
84699
|
+
{
|
|
84700
|
+
version: 7,
|
|
84701
|
+
description: "Pick your issue tracker: Linear (default) or GitHub Issues. The new " + "`tracker.kind` switch selects the provider; choosing GitHub drives the " + "loop off `gh` issues, filtered by `github.issues.label`/`assignee` and " + "moved through the `github.issues.statusLabels` (in-progress / done / " + "error). Existing files default to Linear, so nothing changes unless you " + "switch.",
|
|
84702
|
+
fields: [
|
|
84703
|
+
"tracker.kind",
|
|
84704
|
+
"github.issues.repo",
|
|
84705
|
+
"github.issues.label",
|
|
84706
|
+
"github.issues.assignee",
|
|
84707
|
+
"github.issues.statusLabels.inProgress",
|
|
84708
|
+
"github.issues.statusLabels.done",
|
|
84709
|
+
"github.issues.statusLabels.error"
|
|
84710
|
+
]
|
|
84711
|
+
},
|
|
84712
|
+
{
|
|
84713
|
+
version: 8,
|
|
84714
|
+
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.",
|
|
84715
|
+
fields: ["prLabels"]
|
|
84588
84716
|
}
|
|
84589
84717
|
];
|
|
84590
84718
|
LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max2, migration) => Math.max(max2, migration.version), 0);
|
|
@@ -85156,7 +85284,7 @@ function projectLayout(root) {
|
|
|
85156
85284
|
stateFile: (name) => join7(statesDir, name, STATE_FILE)
|
|
85157
85285
|
};
|
|
85158
85286
|
}
|
|
85159
|
-
var STATE_FILE = ".ralph-state.json"
|
|
85287
|
+
var STATE_FILE = ".ralph-state.json";
|
|
85160
85288
|
var init_layout = __esm(() => {
|
|
85161
85289
|
init_context();
|
|
85162
85290
|
});
|
|
@@ -99623,6 +99751,39 @@ var init_example_machine = __esm(() => {
|
|
|
99623
99751
|
});
|
|
99624
99752
|
|
|
99625
99753
|
// packages/core/src/machines/flow.machine.ts
|
|
99754
|
+
function recordDetection(reason) {
|
|
99755
|
+
return ({
|
|
99756
|
+
context,
|
|
99757
|
+
event
|
|
99758
|
+
}) => {
|
|
99759
|
+
const previous = context.data.recovery;
|
|
99760
|
+
return {
|
|
99761
|
+
data: {
|
|
99762
|
+
...context.data,
|
|
99763
|
+
recovery: {
|
|
99764
|
+
attempts: (previous?.attempts ?? 0) + 1,
|
|
99765
|
+
lastReason: reason,
|
|
99766
|
+
firstFailedAt: previous?.firstFailedAt ?? event.at ?? ""
|
|
99767
|
+
}
|
|
99768
|
+
}
|
|
99769
|
+
};
|
|
99770
|
+
};
|
|
99771
|
+
}
|
|
99772
|
+
function reachesQuarantine({ context }) {
|
|
99773
|
+
const max2 = context.data.maxRecoveryAttempts;
|
|
99774
|
+
return max2 > 0 && (context.data.recovery?.attempts ?? 0) + 1 >= max2;
|
|
99775
|
+
}
|
|
99776
|
+
function refreshReason(reason) {
|
|
99777
|
+
return ({ context }) => ({
|
|
99778
|
+
data: {
|
|
99779
|
+
...context.data,
|
|
99780
|
+
recovery: context.data.recovery ? { ...context.data.recovery, lastReason: reason } : { attempts: 0, lastReason: reason, firstFailedAt: "" }
|
|
99781
|
+
}
|
|
99782
|
+
});
|
|
99783
|
+
}
|
|
99784
|
+
function clearRecovery({ context }) {
|
|
99785
|
+
return { data: { ...context.data, recovery: undefined } };
|
|
99786
|
+
}
|
|
99626
99787
|
var preemptionActorLogic, flowMachine;
|
|
99627
99788
|
var init_flow_machine = __esm(() => {
|
|
99628
99789
|
init_xstate_development_cjs();
|
|
@@ -99669,14 +99830,20 @@ var init_flow_machine = __esm(() => {
|
|
|
99669
99830
|
}).createMachine({
|
|
99670
99831
|
id: "flow",
|
|
99671
99832
|
context: ({ input }) => ({
|
|
99672
|
-
|
|
99673
|
-
|
|
99674
|
-
|
|
99675
|
-
|
|
99676
|
-
|
|
99677
|
-
|
|
99678
|
-
|
|
99679
|
-
|
|
99833
|
+
data: {
|
|
99834
|
+
issueId: input?.issueId ?? "",
|
|
99835
|
+
graceMs: input?.graceMs ?? 5000,
|
|
99836
|
+
maxRecoveryAttempts: input?.maxRecoveryAttempts ?? 0,
|
|
99837
|
+
currentAssignment: undefined,
|
|
99838
|
+
pendingAssignment: undefined,
|
|
99839
|
+
recovery: undefined
|
|
99840
|
+
},
|
|
99841
|
+
runtime: {
|
|
99842
|
+
bus: input?.bus ?? createNoopBus(),
|
|
99843
|
+
persist: input?.persist ?? (() => {}),
|
|
99844
|
+
worker: undefined,
|
|
99845
|
+
teardown: undefined
|
|
99846
|
+
}
|
|
99680
99847
|
}),
|
|
99681
99848
|
initial: "idle",
|
|
99682
99849
|
states: {
|
|
@@ -99685,29 +99852,63 @@ var init_flow_machine = __esm(() => {
|
|
|
99685
99852
|
FRESH_PICKED_UP: "working",
|
|
99686
99853
|
RESUME_DETECTED: "working",
|
|
99687
99854
|
REVIEW_TRIGGERED: "review",
|
|
99688
|
-
CONFLICT_DETECTED:
|
|
99689
|
-
|
|
99855
|
+
CONFLICT_DETECTED: [
|
|
99856
|
+
{
|
|
99857
|
+
guard: reachesQuarantine,
|
|
99858
|
+
target: "quarantined",
|
|
99859
|
+
actions: import_xstate_development_cjs.assign(recordDetection("conflicting"))
|
|
99860
|
+
},
|
|
99861
|
+
{ target: "conflict-fix", actions: import_xstate_development_cjs.assign(recordDetection("conflicting")) }
|
|
99862
|
+
],
|
|
99863
|
+
CI_FAILED_DETECTED: [
|
|
99864
|
+
{
|
|
99865
|
+
guard: reachesQuarantine,
|
|
99866
|
+
target: "quarantined",
|
|
99867
|
+
actions: import_xstate_development_cjs.assign(recordDetection("ci_failed"))
|
|
99868
|
+
},
|
|
99869
|
+
{ target: "ci-fix", actions: import_xstate_development_cjs.assign(recordDetection("ci_failed")) }
|
|
99870
|
+
]
|
|
99690
99871
|
}
|
|
99691
99872
|
},
|
|
99692
99873
|
working: {
|
|
99693
99874
|
on: {
|
|
99694
99875
|
AWAITING_DETECTED: "awaiting",
|
|
99695
|
-
CONFLICT_DETECTED:
|
|
99696
|
-
|
|
99876
|
+
CONFLICT_DETECTED: [
|
|
99877
|
+
{
|
|
99878
|
+
guard: reachesQuarantine,
|
|
99879
|
+
target: "quarantined",
|
|
99880
|
+
actions: import_xstate_development_cjs.assign(recordDetection("conflicting"))
|
|
99881
|
+
},
|
|
99882
|
+
{ target: "conflict-fix", actions: import_xstate_development_cjs.assign(recordDetection("conflicting")) }
|
|
99883
|
+
],
|
|
99884
|
+
CI_FAILED_DETECTED: [
|
|
99885
|
+
{
|
|
99886
|
+
guard: reachesQuarantine,
|
|
99887
|
+
target: "quarantined",
|
|
99888
|
+
actions: import_xstate_development_cjs.assign(recordDetection("ci_failed"))
|
|
99889
|
+
},
|
|
99890
|
+
{ target: "ci-fix", actions: import_xstate_development_cjs.assign(recordDetection("ci_failed")) }
|
|
99891
|
+
],
|
|
99697
99892
|
PR_OPENED: "awaiting-ci",
|
|
99698
99893
|
WORKER_SUCCEEDED: "done",
|
|
99699
99894
|
WORKER_FAILED: "error",
|
|
99700
99895
|
PREEMPT: {
|
|
99701
99896
|
target: "preempting",
|
|
99702
99897
|
actions: import_xstate_development_cjs.assign({
|
|
99703
|
-
|
|
99898
|
+
data: ({ context, event }) => ({
|
|
99899
|
+
...context.data,
|
|
99900
|
+
pendingAssignment: event.newAssignment
|
|
99901
|
+
})
|
|
99704
99902
|
})
|
|
99705
99903
|
},
|
|
99706
99904
|
WORKER_SPAWNED: {
|
|
99707
|
-
actions: import_xstate_development_cjs.assign(({ event }) => ({
|
|
99708
|
-
|
|
99709
|
-
|
|
99710
|
-
|
|
99905
|
+
actions: import_xstate_development_cjs.assign(({ context, event }) => ({
|
|
99906
|
+
data: { ...context.data, currentAssignment: event.assignment },
|
|
99907
|
+
runtime: {
|
|
99908
|
+
...context.runtime,
|
|
99909
|
+
worker: event.worker,
|
|
99910
|
+
teardown: event.teardown ?? undefined
|
|
99911
|
+
}
|
|
99711
99912
|
}))
|
|
99712
99913
|
}
|
|
99713
99914
|
}
|
|
@@ -99719,14 +99920,20 @@ var init_flow_machine = __esm(() => {
|
|
|
99719
99920
|
PREEMPT: {
|
|
99720
99921
|
target: "preempting",
|
|
99721
99922
|
actions: import_xstate_development_cjs.assign({
|
|
99722
|
-
|
|
99923
|
+
data: ({ context, event }) => ({
|
|
99924
|
+
...context.data,
|
|
99925
|
+
pendingAssignment: event.newAssignment
|
|
99926
|
+
})
|
|
99723
99927
|
})
|
|
99724
99928
|
},
|
|
99725
99929
|
WORKER_SPAWNED: {
|
|
99726
|
-
actions: import_xstate_development_cjs.assign(({ event }) => ({
|
|
99727
|
-
|
|
99728
|
-
|
|
99729
|
-
|
|
99930
|
+
actions: import_xstate_development_cjs.assign(({ context, event }) => ({
|
|
99931
|
+
data: { ...context.data, currentAssignment: event.assignment },
|
|
99932
|
+
runtime: {
|
|
99933
|
+
...context.runtime,
|
|
99934
|
+
worker: event.worker,
|
|
99935
|
+
teardown: event.teardown ?? undefined
|
|
99936
|
+
}
|
|
99730
99937
|
}))
|
|
99731
99938
|
}
|
|
99732
99939
|
}
|
|
@@ -99738,14 +99945,20 @@ var init_flow_machine = __esm(() => {
|
|
|
99738
99945
|
PREEMPT: {
|
|
99739
99946
|
target: "preempting",
|
|
99740
99947
|
actions: import_xstate_development_cjs.assign({
|
|
99741
|
-
|
|
99948
|
+
data: ({ context, event }) => ({
|
|
99949
|
+
...context.data,
|
|
99950
|
+
pendingAssignment: event.newAssignment
|
|
99951
|
+
})
|
|
99742
99952
|
})
|
|
99743
99953
|
},
|
|
99744
99954
|
WORKER_SPAWNED: {
|
|
99745
|
-
actions: import_xstate_development_cjs.assign(({ event }) => ({
|
|
99746
|
-
|
|
99747
|
-
|
|
99748
|
-
|
|
99955
|
+
actions: import_xstate_development_cjs.assign(({ context, event }) => ({
|
|
99956
|
+
data: { ...context.data, currentAssignment: event.assignment },
|
|
99957
|
+
runtime: {
|
|
99958
|
+
...context.runtime,
|
|
99959
|
+
worker: event.worker,
|
|
99960
|
+
teardown: event.teardown ?? undefined
|
|
99961
|
+
}
|
|
99749
99962
|
}))
|
|
99750
99963
|
}
|
|
99751
99964
|
}
|
|
@@ -99756,7 +99969,10 @@ var init_flow_machine = __esm(() => {
|
|
|
99756
99969
|
PREEMPT: {
|
|
99757
99970
|
target: "preempting",
|
|
99758
99971
|
actions: import_xstate_development_cjs.assign({
|
|
99759
|
-
|
|
99972
|
+
data: ({ context, event }) => ({
|
|
99973
|
+
...context.data,
|
|
99974
|
+
pendingAssignment: event.newAssignment
|
|
99975
|
+
})
|
|
99760
99976
|
})
|
|
99761
99977
|
}
|
|
99762
99978
|
}
|
|
@@ -99764,20 +99980,41 @@ var init_flow_machine = __esm(() => {
|
|
|
99764
99980
|
"awaiting-ci": {
|
|
99765
99981
|
on: {
|
|
99766
99982
|
PR_PASSED: "done",
|
|
99767
|
-
|
|
99768
|
-
|
|
99983
|
+
RECOVERY_CLEARED: { actions: import_xstate_development_cjs.assign(clearRecovery) },
|
|
99984
|
+
CONFLICT_DETECTED: [
|
|
99985
|
+
{
|
|
99986
|
+
guard: reachesQuarantine,
|
|
99987
|
+
target: "quarantined",
|
|
99988
|
+
actions: import_xstate_development_cjs.assign(recordDetection("conflicting"))
|
|
99989
|
+
},
|
|
99990
|
+
{ target: "conflict-fix", actions: import_xstate_development_cjs.assign(recordDetection("conflicting")) }
|
|
99991
|
+
],
|
|
99992
|
+
CI_FAILED_DETECTED: [
|
|
99993
|
+
{
|
|
99994
|
+
guard: reachesQuarantine,
|
|
99995
|
+
target: "quarantined",
|
|
99996
|
+
actions: import_xstate_development_cjs.assign(recordDetection("ci_failed"))
|
|
99997
|
+
},
|
|
99998
|
+
{ target: "ci-fix", actions: import_xstate_development_cjs.assign(recordDetection("ci_failed")) }
|
|
99999
|
+
],
|
|
99769
100000
|
REVIEW_TRIGGERED: "review",
|
|
99770
100001
|
PREEMPT: {
|
|
99771
100002
|
target: "preempting",
|
|
99772
100003
|
actions: import_xstate_development_cjs.assign({
|
|
99773
|
-
|
|
100004
|
+
data: ({ context, event }) => ({
|
|
100005
|
+
...context.data,
|
|
100006
|
+
pendingAssignment: event.newAssignment
|
|
100007
|
+
})
|
|
99774
100008
|
})
|
|
99775
100009
|
},
|
|
99776
100010
|
WORKER_SPAWNED: {
|
|
99777
|
-
actions: import_xstate_development_cjs.assign(({ event }) => ({
|
|
99778
|
-
|
|
99779
|
-
|
|
99780
|
-
|
|
100011
|
+
actions: import_xstate_development_cjs.assign(({ context, event }) => ({
|
|
100012
|
+
data: { ...context.data, currentAssignment: event.assignment },
|
|
100013
|
+
runtime: {
|
|
100014
|
+
...context.runtime,
|
|
100015
|
+
worker: event.worker,
|
|
100016
|
+
teardown: event.teardown ?? undefined
|
|
100017
|
+
}
|
|
99781
100018
|
}))
|
|
99782
100019
|
}
|
|
99783
100020
|
}
|
|
@@ -99788,10 +100025,13 @@ var init_flow_machine = __esm(() => {
|
|
|
99788
100025
|
PR_OPENED: "awaiting-ci",
|
|
99789
100026
|
WORKER_FAILED: "error",
|
|
99790
100027
|
WORKER_SPAWNED: {
|
|
99791
|
-
actions: import_xstate_development_cjs.assign(({ event }) => ({
|
|
99792
|
-
|
|
99793
|
-
|
|
99794
|
-
|
|
100028
|
+
actions: import_xstate_development_cjs.assign(({ context, event }) => ({
|
|
100029
|
+
data: { ...context.data, currentAssignment: event.assignment },
|
|
100030
|
+
runtime: {
|
|
100031
|
+
...context.runtime,
|
|
100032
|
+
worker: event.worker,
|
|
100033
|
+
teardown: event.teardown ?? undefined
|
|
100034
|
+
}
|
|
99795
100035
|
}))
|
|
99796
100036
|
}
|
|
99797
100037
|
}
|
|
@@ -99800,20 +100040,19 @@ var init_flow_machine = __esm(() => {
|
|
|
99800
100040
|
invoke: {
|
|
99801
100041
|
src: "preemption",
|
|
99802
100042
|
input: ({ context }) => ({
|
|
99803
|
-
graceMs: context.graceMs,
|
|
99804
|
-
bus: context.bus,
|
|
99805
|
-
persist: context.persist,
|
|
99806
|
-
issueId: context.issueId,
|
|
99807
|
-
newAssignment: context.pendingAssignment,
|
|
99808
|
-
...context.currentAssignment !== undefined ? { from: context.currentAssignment.flowId } : {},
|
|
99809
|
-
...context.worker !== undefined ? { worker: context.worker } : {},
|
|
99810
|
-
...context.teardown !== undefined ? { teardown: context.teardown } : {}
|
|
100043
|
+
graceMs: context.data.graceMs,
|
|
100044
|
+
bus: context.runtime.bus,
|
|
100045
|
+
persist: context.runtime.persist,
|
|
100046
|
+
issueId: context.data.issueId,
|
|
100047
|
+
newAssignment: context.data.pendingAssignment,
|
|
100048
|
+
...context.data.currentAssignment !== undefined ? { from: context.data.currentAssignment.flowId } : {},
|
|
100049
|
+
...context.runtime.worker !== undefined ? { worker: context.runtime.worker } : {},
|
|
100050
|
+
...context.runtime.teardown !== undefined ? { teardown: context.runtime.teardown } : {}
|
|
99811
100051
|
}),
|
|
99812
100052
|
onDone: {
|
|
99813
100053
|
actions: import_xstate_development_cjs.assign(({ context }) => ({
|
|
99814
|
-
|
|
99815
|
-
teardown: undefined
|
|
99816
|
-
currentAssignment: context.pendingAssignment
|
|
100054
|
+
data: { ...context.data, currentAssignment: context.data.pendingAssignment },
|
|
100055
|
+
runtime: { ...context.runtime, worker: undefined, teardown: undefined }
|
|
99817
100056
|
})),
|
|
99818
100057
|
target: "routing-after-preempt"
|
|
99819
100058
|
},
|
|
@@ -99823,32 +100062,40 @@ var init_flow_machine = __esm(() => {
|
|
|
99823
100062
|
"routing-after-preempt": {
|
|
99824
100063
|
always: [
|
|
99825
100064
|
{
|
|
99826
|
-
guard: ({ context }) => context.pendingAssignment?.flowId === "conflict-fix",
|
|
100065
|
+
guard: ({ context }) => context.data.pendingAssignment?.flowId === "conflict-fix",
|
|
99827
100066
|
target: "conflict-fix"
|
|
99828
100067
|
},
|
|
99829
100068
|
{
|
|
99830
|
-
guard: ({ context }) => context.pendingAssignment?.flowId === "ci-fix",
|
|
100069
|
+
guard: ({ context }) => context.data.pendingAssignment?.flowId === "ci-fix",
|
|
99831
100070
|
target: "ci-fix"
|
|
99832
100071
|
},
|
|
99833
100072
|
{
|
|
99834
|
-
guard: ({ context }) => context.pendingAssignment?.flowId === "awaiting-ci",
|
|
100073
|
+
guard: ({ context }) => context.data.pendingAssignment?.flowId === "awaiting-ci",
|
|
99835
100074
|
target: "awaiting-ci"
|
|
99836
100075
|
},
|
|
99837
100076
|
{
|
|
99838
|
-
guard: ({ context }) => context.pendingAssignment?.flowId === "confirmation",
|
|
100077
|
+
guard: ({ context }) => context.data.pendingAssignment?.flowId === "confirmation",
|
|
99839
100078
|
target: "awaiting"
|
|
99840
100079
|
},
|
|
99841
100080
|
{
|
|
99842
|
-
guard: ({ context }) => context.pendingAssignment?.flowId === "review-followup",
|
|
100081
|
+
guard: ({ context }) => context.data.pendingAssignment?.flowId === "review-followup",
|
|
99843
100082
|
target: "review"
|
|
99844
100083
|
},
|
|
99845
100084
|
{
|
|
99846
|
-
guard: ({ context }) => context.pendingAssignment?.flowId === "idle",
|
|
100085
|
+
guard: ({ context }) => context.data.pendingAssignment?.flowId === "idle",
|
|
99847
100086
|
target: "idle"
|
|
99848
100087
|
},
|
|
99849
100088
|
{ target: "working" }
|
|
99850
100089
|
]
|
|
99851
100090
|
},
|
|
100091
|
+
quarantined: {
|
|
100092
|
+
on: {
|
|
100093
|
+
PR_PASSED: "done",
|
|
100094
|
+
QUARANTINE_CLEARED: { target: "idle", actions: import_xstate_development_cjs.assign(clearRecovery) },
|
|
100095
|
+
CONFLICT_DETECTED: { actions: import_xstate_development_cjs.assign(refreshReason("conflicting")) },
|
|
100096
|
+
CI_FAILED_DETECTED: { actions: import_xstate_development_cjs.assign(refreshReason("ci_failed")) }
|
|
100097
|
+
}
|
|
100098
|
+
},
|
|
99852
100099
|
done: {
|
|
99853
100100
|
type: "final"
|
|
99854
100101
|
},
|
|
@@ -99877,17 +100124,22 @@ class FlowActorStore {
|
|
|
99877
100124
|
...this.deps ? {
|
|
99878
100125
|
bus: this.deps.bus,
|
|
99879
100126
|
persist: this.deps.persist,
|
|
99880
|
-
...this.deps.graceMs !== undefined ? { graceMs: this.deps.graceMs } : {}
|
|
100127
|
+
...this.deps.graceMs !== undefined ? { graceMs: this.deps.graceMs } : {},
|
|
100128
|
+
...this.deps.maxRecoveryAttempts !== undefined ? { maxRecoveryAttempts: this.deps.maxRecoveryAttempts } : {}
|
|
99881
100129
|
} : {}
|
|
99882
100130
|
};
|
|
100131
|
+
const inspector = this.deps?.onTransition ? this.makeInspect(key, changeDir) : null;
|
|
99883
100132
|
if (changeDir) {
|
|
99884
100133
|
const snapshot = await this.loadSnapshot(changeDir);
|
|
99885
100134
|
if (snapshot !== null && this.isValidSnapshot(snapshot)) {
|
|
99886
100135
|
try {
|
|
100136
|
+
const restored = this.withRestoredRuntime(snapshot);
|
|
99887
100137
|
const a2 = import_xstate_development_cjs.createActor(this.machine, {
|
|
99888
|
-
snapshot,
|
|
99889
|
-
input
|
|
100138
|
+
snapshot: restored,
|
|
100139
|
+
input,
|
|
100140
|
+
...inspector ? { inspect: inspector.inspect } : {}
|
|
99890
100141
|
});
|
|
100142
|
+
inspector?.setRoot(a2);
|
|
99891
100143
|
a2.start();
|
|
99892
100144
|
if (a2.getSnapshot().value !== undefined) {
|
|
99893
100145
|
this.actors.set(key, a2);
|
|
@@ -99899,11 +100151,61 @@ class FlowActorStore {
|
|
|
99899
100151
|
} catch {}
|
|
99900
100152
|
}
|
|
99901
100153
|
}
|
|
99902
|
-
const a = import_xstate_development_cjs.createActor(this.machine, {
|
|
100154
|
+
const a = import_xstate_development_cjs.createActor(this.machine, {
|
|
100155
|
+
input,
|
|
100156
|
+
...inspector ? { inspect: inspector.inspect } : {}
|
|
100157
|
+
});
|
|
100158
|
+
inspector?.setRoot(a);
|
|
99903
100159
|
a.start();
|
|
99904
100160
|
this.actors.set(key, a);
|
|
99905
100161
|
return a;
|
|
99906
100162
|
}
|
|
100163
|
+
buildRuntime() {
|
|
100164
|
+
return {
|
|
100165
|
+
bus: this.deps?.bus ?? createNoopBus(),
|
|
100166
|
+
persist: this.deps?.persist ?? (() => {}),
|
|
100167
|
+
worker: undefined,
|
|
100168
|
+
teardown: undefined
|
|
100169
|
+
};
|
|
100170
|
+
}
|
|
100171
|
+
withRestoredRuntime(snapshot) {
|
|
100172
|
+
if (!snapshot || typeof snapshot !== "object")
|
|
100173
|
+
return snapshot;
|
|
100174
|
+
const snap = snapshot;
|
|
100175
|
+
const context = snap.context ?? {};
|
|
100176
|
+
const data = context.data && typeof context.data === "object" ? context.data : {
|
|
100177
|
+
issueId: context.issueId,
|
|
100178
|
+
graceMs: context.graceMs ?? 5000,
|
|
100179
|
+
maxRecoveryAttempts: this.deps?.maxRecoveryAttempts ?? 0,
|
|
100180
|
+
currentAssignment: context.currentAssignment,
|
|
100181
|
+
pendingAssignment: context.pendingAssignment,
|
|
100182
|
+
recovery: undefined
|
|
100183
|
+
};
|
|
100184
|
+
return { ...snap, context: { data, runtime: this.buildRuntime() } };
|
|
100185
|
+
}
|
|
100186
|
+
makeInspect(issueId, changeDir) {
|
|
100187
|
+
let root;
|
|
100188
|
+
let previous;
|
|
100189
|
+
const inspect = (event) => {
|
|
100190
|
+
if (event.type !== "@xstate.snapshot" || event.actorRef !== root)
|
|
100191
|
+
return;
|
|
100192
|
+
const value = event.snapshot.value;
|
|
100193
|
+
const to = typeof value === "string" ? value : JSON.stringify(value);
|
|
100194
|
+
const eventType = event.event.type ?? "?";
|
|
100195
|
+
if (previous !== undefined && previous !== to) {
|
|
100196
|
+
try {
|
|
100197
|
+
this.deps?.onTransition?.(issueId, changeDir, { from: previous, event: eventType, to });
|
|
100198
|
+
} catch {}
|
|
100199
|
+
}
|
|
100200
|
+
previous = to;
|
|
100201
|
+
};
|
|
100202
|
+
return {
|
|
100203
|
+
inspect,
|
|
100204
|
+
setRoot: (actor) => {
|
|
100205
|
+
root = actor;
|
|
100206
|
+
}
|
|
100207
|
+
};
|
|
100208
|
+
}
|
|
99907
100209
|
peekActor(key) {
|
|
99908
100210
|
return this.actors.get(key) ?? null;
|
|
99909
100211
|
}
|
|
@@ -99959,6 +100261,7 @@ var init_flow_actor_store = __esm(() => {
|
|
|
99959
100261
|
init_xstate_development_cjs();
|
|
99960
100262
|
init_flow_machine();
|
|
99961
100263
|
init_store();
|
|
100264
|
+
init_src2();
|
|
99962
100265
|
});
|
|
99963
100266
|
|
|
99964
100267
|
// packages/core/src/machines/loop.machine.ts
|
|
@@ -100164,7 +100467,7 @@ function normalizeNewlyAppendedSectionWithReport(previous, current) {
|
|
|
100164
100467
|
});
|
|
100165
100468
|
return { text: count > 0 ? out.join("") : current, headings, count };
|
|
100166
100469
|
}
|
|
100167
|
-
var MISSION_TASKS_FILENAME = "tasks.md", AGENT_TASKS_FILENAME = "agent-tasks.md", FLOW_TASK_HEADING_PREFIXES;
|
|
100470
|
+
var MISSION_TASKS_FILENAME = "tasks.md", AGENT_TASKS_FILENAME = "agent-tasks.md", HANDOFF_FILENAME = "handoff.md", FLOW_TASK_HEADING_PREFIXES;
|
|
100168
100471
|
var init_tasks_md = __esm(() => {
|
|
100169
100472
|
FLOW_TASK_HEADING_PREFIXES = [
|
|
100170
100473
|
"Fix failing CI checks",
|
|
@@ -100417,6 +100720,20 @@ function buildTaskPrompt(state, taskDir, reviewPhase) {
|
|
|
100417
100720
|
`;
|
|
100418
100721
|
}
|
|
100419
100722
|
}
|
|
100723
|
+
const handoffContent = storage.read(join15(taskDir, HANDOFF_FILENAME));
|
|
100724
|
+
if (handoffContent !== null && handoffContent.trim()) {
|
|
100725
|
+
prompt += `---
|
|
100726
|
+
`;
|
|
100727
|
+
prompt += `# Previous Iteration Handoff (context from the last iteration)
|
|
100728
|
+
|
|
100729
|
+
`;
|
|
100730
|
+
prompt += handoffContent.trim() + `
|
|
100731
|
+
|
|
100732
|
+
`;
|
|
100733
|
+
prompt += `---
|
|
100734
|
+
|
|
100735
|
+
`;
|
|
100736
|
+
}
|
|
100420
100737
|
const agentTasksPath = join15(taskDir, AGENT_TASKS_FILENAME);
|
|
100421
100738
|
const missionTasksPath = join15(taskDir, MISSION_TASKS_FILENAME);
|
|
100422
100739
|
const agentTasksContent = storage.read(agentTasksPath);
|
|
@@ -100564,6 +100881,22 @@ When all tasks are complete and all files are committed, push your branch and op
|
|
|
100564
100881
|
prompt += `Use the change name as the PR title and write a concise summary of the implementation in the body.
|
|
100565
100882
|
`;
|
|
100566
100883
|
}
|
|
100884
|
+
const handoffPath = join15(taskDir, HANDOFF_FILENAME);
|
|
100885
|
+
prompt += `
|
|
100886
|
+
---
|
|
100887
|
+
|
|
100888
|
+
## Write Handoff (do this LAST, before you finish)
|
|
100889
|
+
`;
|
|
100890
|
+
prompt += `Before ending this iteration, record a handoff for the next iteration:
|
|
100891
|
+
`;
|
|
100892
|
+
prompt += `- If a \`handoff\` skill is available, invoke it; otherwise write the document yourself.
|
|
100893
|
+
`;
|
|
100894
|
+
prompt += `- Save it to \`${handoffPath}\` (OVERWRITE the existing file \u2014 do NOT append, do NOT save to a temp dir).
|
|
100895
|
+
`;
|
|
100896
|
+
prompt += `- Keep it compact: what you did this iteration, what remains, key decisions, and any blockers/gotchas. Reference artifacts by path instead of duplicating them.
|
|
100897
|
+
`;
|
|
100898
|
+
prompt += `- This file is loop scratch \u2014 do NOT commit it.
|
|
100899
|
+
`;
|
|
100567
100900
|
return prompt;
|
|
100568
100901
|
}
|
|
100569
100902
|
function buildSteeringBlock(taskDir) {
|
|
@@ -102600,13 +102933,91 @@ class PollContext {
|
|
|
102600
102933
|
}
|
|
102601
102934
|
}
|
|
102602
102935
|
|
|
102603
|
-
//
|
|
102604
|
-
function
|
|
102936
|
+
// packages/comms/src/index.ts
|
|
102937
|
+
function sanitizeMarkerValue(value) {
|
|
102938
|
+
return value.replace(/--+>?/g, "-").replace(/\s+/g, "_").trim();
|
|
102939
|
+
}
|
|
102940
|
+
function buildRalphyMarker(type, fields) {
|
|
102941
|
+
const pairs = [`v=${RALPHY_MARKER_VERSION}`, `type=${type}`];
|
|
102942
|
+
for (const [key, raw] of Object.entries(fields ?? {})) {
|
|
102943
|
+
if (raw === undefined || raw === null || raw === "")
|
|
102944
|
+
continue;
|
|
102945
|
+
pairs.push(`${key}=${sanitizeMarkerValue(String(raw))}`);
|
|
102946
|
+
}
|
|
102947
|
+
return `<!-- ralphy:${pairs.join(" ")} -->`;
|
|
102948
|
+
}
|
|
102949
|
+
function parseRalphyMarker(body) {
|
|
102950
|
+
const match = /<!--\s*ralphy:([^>]*?\btype=[^>]*?)\s*-->/.exec(body);
|
|
102951
|
+
if (!match)
|
|
102952
|
+
return null;
|
|
102953
|
+
const fields = {};
|
|
102954
|
+
let type = "";
|
|
102955
|
+
let version3 = 0;
|
|
102956
|
+
for (const token of match[1].trim().split(/\s+/)) {
|
|
102957
|
+
const eq = token.indexOf("=");
|
|
102958
|
+
if (eq < 0)
|
|
102959
|
+
continue;
|
|
102960
|
+
const key = token.slice(0, eq);
|
|
102961
|
+
const value = token.slice(eq + 1);
|
|
102962
|
+
if (key === "v")
|
|
102963
|
+
version3 = Number(value) || 0;
|
|
102964
|
+
else if (key === "type")
|
|
102965
|
+
type = value;
|
|
102966
|
+
else
|
|
102967
|
+
fields[key] = value;
|
|
102968
|
+
}
|
|
102969
|
+
if (!type)
|
|
102970
|
+
return null;
|
|
102971
|
+
return { version: version3, type, fields };
|
|
102972
|
+
}
|
|
102973
|
+
function buildRalphyComment(input) {
|
|
102974
|
+
const lines = [`${RALPHY_TITLE_PREFIX}${input.action}`];
|
|
102975
|
+
const body = input.body?.trim();
|
|
102976
|
+
if (body)
|
|
102977
|
+
lines.push("", body);
|
|
102978
|
+
lines.push("", buildRalphyMarker(input.type, input.fields));
|
|
102979
|
+
return lines.join(`
|
|
102980
|
+
`);
|
|
102981
|
+
}
|
|
102982
|
+
function isRalphyComment(body) {
|
|
102605
102983
|
const trimmed = body.trimStart();
|
|
102606
|
-
if (
|
|
102984
|
+
if (trimmed.startsWith(RALPHY_BRAND))
|
|
102985
|
+
return true;
|
|
102986
|
+
if (parseRalphyMarker(body))
|
|
102607
102987
|
return true;
|
|
102608
|
-
|
|
102988
|
+
if (LEGACY_RALPH_LEAD.test(trimmed))
|
|
102989
|
+
return true;
|
|
102990
|
+
return LEGACY_MENTION_ACK.test(trimmed);
|
|
102609
102991
|
}
|
|
102992
|
+
function isPickupComment(body) {
|
|
102993
|
+
if (parseRalphyMarker(body)?.type === "review-pickup")
|
|
102994
|
+
return true;
|
|
102995
|
+
return /^\uD83D\uDD01\s*Ralph picked up/u.test(body.trimStart());
|
|
102996
|
+
}
|
|
102997
|
+
function isStartedComment(body) {
|
|
102998
|
+
if (parseRalphyMarker(body)?.type === "started")
|
|
102999
|
+
return true;
|
|
103000
|
+
return /^\uD83E\uDD16\s*Ralph started working/u.test(body.trimStart());
|
|
103001
|
+
}
|
|
103002
|
+
function isMentionAckComment(body) {
|
|
103003
|
+
if (parseRalphyMarker(body)?.type === "mention-ack")
|
|
103004
|
+
return true;
|
|
103005
|
+
return LEGACY_MENTION_ACK.test(body.trimStart());
|
|
103006
|
+
}
|
|
103007
|
+
var RALPHY_BRAND = "\uD83E\uDD16 Ralphy", RALPHY_TITLE_PREFIX, RALPHY_MARKER_VERSION = 1, LEGACY_RALPH_LEAD, LEGACY_MENTION_ACK;
|
|
103008
|
+
var init_src8 = __esm(() => {
|
|
103009
|
+
RALPHY_TITLE_PREFIX = `${RALPHY_BRAND} \xB7 `;
|
|
103010
|
+
LEGACY_RALPH_LEAD = /^(\uD83E\uDD16|\uD83D\uDD04|\u2705|\u2717|\u274C|\u26A0\uFE0F?|\uD83D\uDD01|\uD83D\uDCCB|\u23F0|\u2139\uFE0F)\s*Ralphy?\b/u;
|
|
103011
|
+
LEGACY_MENTION_ACK = /^\uD83D\uDC40\s*(Got it\b|Acknowledged\b)/u;
|
|
103012
|
+
});
|
|
103013
|
+
|
|
103014
|
+
// apps/agent/src/shared/utils/ralph-comment.ts
|
|
103015
|
+
function isRalphComment(body) {
|
|
103016
|
+
return isRalphyComment(body);
|
|
103017
|
+
}
|
|
103018
|
+
var init_ralph_comment = __esm(() => {
|
|
103019
|
+
init_src8();
|
|
103020
|
+
});
|
|
102610
103021
|
|
|
102611
103022
|
// apps/agent/src/shared/capabilities/linear-client.ts
|
|
102612
103023
|
var exports_linear_client = {};
|
|
@@ -102707,6 +103118,9 @@ function formatTicketError(err) {
|
|
|
102707
103118
|
parts.push(`configured team: ${e.team}`);
|
|
102708
103119
|
return parts.length > 0 ? `${e.message} (${parts.join(", ")})` : e.message;
|
|
102709
103120
|
}
|
|
103121
|
+
function openBlockersFromInverse(nodes) {
|
|
103122
|
+
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 }));
|
|
103123
|
+
}
|
|
102710
103124
|
function partition2(markers) {
|
|
102711
103125
|
const statuses = [];
|
|
102712
103126
|
const labels = [];
|
|
@@ -102926,8 +103340,8 @@ async function fetchMentionScanIssues(apiKey, spec) {
|
|
|
102926
103340
|
project { id name priority }
|
|
102927
103341
|
projectMilestone { id name sortOrder targetDate }
|
|
102928
103342
|
labels { nodes { name } }
|
|
102929
|
-
|
|
102930
|
-
nodes { type
|
|
103343
|
+
inverseRelations(first: 50) {
|
|
103344
|
+
nodes { type issue { id identifier state { type } } }
|
|
102931
103345
|
}
|
|
102932
103346
|
comments(first: 50) {
|
|
102933
103347
|
nodes { id body createdAt user { name email } }
|
|
@@ -102938,24 +103352,26 @@ async function fetchMentionScanIssues(apiKey, spec) {
|
|
|
102938
103352
|
const data = await linearRequest(apiKey, query, {
|
|
102939
103353
|
filter: where
|
|
102940
103354
|
});
|
|
102941
|
-
|
|
102942
|
-
|
|
102943
|
-
|
|
102944
|
-
|
|
102945
|
-
|
|
102946
|
-
|
|
102947
|
-
|
|
102948
|
-
|
|
102949
|
-
|
|
102950
|
-
|
|
102951
|
-
|
|
102952
|
-
|
|
102953
|
-
|
|
102954
|
-
|
|
102955
|
-
|
|
102956
|
-
|
|
102957
|
-
|
|
102958
|
-
|
|
103355
|
+
return data.issues.nodes.map((n) => {
|
|
103356
|
+
const blockers = openBlockersFromInverse(n.inverseRelations?.nodes);
|
|
103357
|
+
return {
|
|
103358
|
+
id: n.id,
|
|
103359
|
+
identifier: n.identifier,
|
|
103360
|
+
title: n.title,
|
|
103361
|
+
description: n.description,
|
|
103362
|
+
url: n.url,
|
|
103363
|
+
state: n.state,
|
|
103364
|
+
assignee: n.assignee,
|
|
103365
|
+
project: mapNodeProject(n),
|
|
103366
|
+
...milestoneSpread(n),
|
|
103367
|
+
labels: n.labels.nodes.map((l) => l.name),
|
|
103368
|
+
priority: n.priority,
|
|
103369
|
+
createdAt: n.createdAt ?? "",
|
|
103370
|
+
blockedByIds: blockers.map((b) => b.id),
|
|
103371
|
+
blockedByIdentifiers: blockers.map((b) => b.identifier),
|
|
103372
|
+
comments: n.comments?.nodes ?? []
|
|
103373
|
+
};
|
|
103374
|
+
});
|
|
102959
103375
|
}
|
|
102960
103376
|
async function fetchOpenIssues(apiKey, spec, options) {
|
|
102961
103377
|
const where = buildIssueFilter(spec);
|
|
@@ -102972,10 +103388,10 @@ async function fetchOpenIssues(apiKey, spec, options) {
|
|
|
102972
103388
|
project { id name priority }
|
|
102973
103389
|
projectMilestone { id name sortOrder targetDate }
|
|
102974
103390
|
labels { nodes { name } }
|
|
102975
|
-
|
|
103391
|
+
inverseRelations(first: 50) {
|
|
102976
103392
|
nodes {
|
|
102977
103393
|
type
|
|
102978
|
-
|
|
103394
|
+
issue { id identifier state { type } }
|
|
102979
103395
|
}
|
|
102980
103396
|
}
|
|
102981
103397
|
${commentsSlice}
|
|
@@ -102985,24 +103401,26 @@ async function fetchOpenIssues(apiKey, spec, options) {
|
|
|
102985
103401
|
const data = await linearRequest(apiKey, query, {
|
|
102986
103402
|
filter: where
|
|
102987
103403
|
});
|
|
102988
|
-
|
|
102989
|
-
|
|
102990
|
-
|
|
102991
|
-
|
|
102992
|
-
|
|
102993
|
-
|
|
102994
|
-
|
|
102995
|
-
|
|
102996
|
-
|
|
102997
|
-
|
|
102998
|
-
|
|
102999
|
-
|
|
103000
|
-
|
|
103001
|
-
|
|
103002
|
-
|
|
103003
|
-
|
|
103004
|
-
|
|
103005
|
-
|
|
103404
|
+
return data.issues.nodes.map((n) => {
|
|
103405
|
+
const blockers = openBlockersFromInverse(n.inverseRelations?.nodes);
|
|
103406
|
+
return {
|
|
103407
|
+
id: n.id,
|
|
103408
|
+
identifier: n.identifier,
|
|
103409
|
+
title: n.title,
|
|
103410
|
+
description: n.description,
|
|
103411
|
+
url: n.url,
|
|
103412
|
+
state: n.state,
|
|
103413
|
+
assignee: n.assignee,
|
|
103414
|
+
project: mapNodeProject(n),
|
|
103415
|
+
...milestoneSpread(n),
|
|
103416
|
+
labels: n.labels.nodes.map((l) => l.name),
|
|
103417
|
+
priority: n.priority,
|
|
103418
|
+
createdAt: n.createdAt ?? "",
|
|
103419
|
+
blockedByIds: blockers.map((b) => b.id),
|
|
103420
|
+
blockedByIdentifiers: blockers.map((b) => b.identifier),
|
|
103421
|
+
...includeComments ? { comments: n.comments?.nodes ?? [] } : {}
|
|
103422
|
+
};
|
|
103423
|
+
});
|
|
103006
103424
|
}
|
|
103007
103425
|
function isRetryableStatus(status) {
|
|
103008
103426
|
return status >= 500 && status <= 599;
|
|
@@ -103316,17 +103734,15 @@ async function fetchBlockedByForIssues(apiKey, issueIds) {
|
|
|
103316
103734
|
issues(filter: { id: { in: $ids } }, first: 250) {
|
|
103317
103735
|
nodes {
|
|
103318
103736
|
id
|
|
103319
|
-
|
|
103320
|
-
nodes { type
|
|
103737
|
+
inverseRelations(first: 50) {
|
|
103738
|
+
nodes { type issue { id identifier state { type } } }
|
|
103321
103739
|
}
|
|
103322
103740
|
}
|
|
103323
103741
|
}
|
|
103324
103742
|
}`;
|
|
103325
103743
|
const data = await linearRequest(apiKey, query, { ids: issueIds });
|
|
103326
|
-
const DONE_STATE_TYPES = new Set(["completed", "cancelled"]);
|
|
103327
103744
|
for (const node2 of data.issues.nodes) {
|
|
103328
|
-
|
|
103329
|
-
out.set(node2.id, blockers);
|
|
103745
|
+
out.set(node2.id, openBlockersFromInverse(node2.inverseRelations?.nodes));
|
|
103330
103746
|
}
|
|
103331
103747
|
return out;
|
|
103332
103748
|
}
|
|
@@ -103540,11 +103956,13 @@ async function removeLabelFromIssue(apiKey, issueId, labelId) {
|
|
|
103540
103956
|
labelId
|
|
103541
103957
|
});
|
|
103542
103958
|
}
|
|
103543
|
-
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:";
|
|
103959
|
+
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:";
|
|
103544
103960
|
var init_linear_client = __esm(() => {
|
|
103545
103961
|
init_types2();
|
|
103962
|
+
init_ralph_comment();
|
|
103546
103963
|
TICKET_IDENTIFIER_RE = /^([A-Za-z]+)-(\d+)(?:-.*)?$/;
|
|
103547
103964
|
TICKET_BARE_NUMBER_RE = /^(\d+)$/;
|
|
103965
|
+
DONE_BLOCKER_STATE_TYPES = new Set(["completed", "cancelled"]);
|
|
103548
103966
|
linearRequestInternals = {
|
|
103549
103967
|
sleep: (ms) => Bun.sleep(ms)
|
|
103550
103968
|
};
|
|
@@ -103651,7 +104069,7 @@ async function provisionWorktree(projectRoot, changeName, baseBranch, runner) {
|
|
|
103651
104069
|
if (list.stdout.includes(`worktree ${cwd2}
|
|
103652
104070
|
`)) {
|
|
103653
104071
|
await installPrePushHook(cwd2, runner);
|
|
103654
|
-
return { cwd: cwd2, branch };
|
|
104072
|
+
return { cwd: cwd2, branch, created: false };
|
|
103655
104073
|
}
|
|
103656
104074
|
let branchExists = true;
|
|
103657
104075
|
try {
|
|
@@ -103662,12 +104080,12 @@ async function provisionWorktree(projectRoot, changeName, baseBranch, runner) {
|
|
|
103662
104080
|
if (branchExists) {
|
|
103663
104081
|
await runner.run(["worktree", "add", cwd2, branch], projectRoot);
|
|
103664
104082
|
await installPrePushHook(cwd2, runner);
|
|
103665
|
-
return { cwd: cwd2, branch };
|
|
104083
|
+
return { cwd: cwd2, branch, created: true };
|
|
103666
104084
|
}
|
|
103667
104085
|
await runner.run(["fetch", "origin", baseBranch], projectRoot);
|
|
103668
104086
|
await runner.run(["worktree", "add", "-b", branch, cwd2, `origin/${baseBranch}`], projectRoot);
|
|
103669
104087
|
await installPrePushHook(cwd2, runner);
|
|
103670
|
-
return { cwd: cwd2, branch };
|
|
104088
|
+
return { cwd: cwd2, branch, created: true };
|
|
103671
104089
|
}
|
|
103672
104090
|
async function installPrePushHook(cwd2, runner) {
|
|
103673
104091
|
const hookPath = join22(cwd2, ".ralph-hooks", "pre-push");
|
|
@@ -103885,7 +104303,7 @@ function stackedOnLine(stackedOn) {
|
|
|
103885
104303
|
return `> \uD83E\uDD5E Stacked on ${prRef}${ticket} \u2014 review/merge that PR first. Base is its branch, not the default branch.`;
|
|
103886
104304
|
}
|
|
103887
104305
|
function defaultBody(issue2, branch, stackedOn) {
|
|
103888
|
-
|
|
104306
|
+
const detail = [
|
|
103889
104307
|
`Auto-generated by Ralph for ${issue2.identifier}.`,
|
|
103890
104308
|
stackedOn ? stackedOnLine(stackedOn) : "",
|
|
103891
104309
|
`Source: ${issue2.url}`,
|
|
@@ -103896,6 +104314,12 @@ function defaultBody(issue2, branch, stackedOn) {
|
|
|
103896
104314
|
${issue2.description.trim()}` : ""
|
|
103897
104315
|
].filter(Boolean).join(`
|
|
103898
104316
|
`);
|
|
104317
|
+
return buildRalphyComment({
|
|
104318
|
+
type: "pr-body",
|
|
104319
|
+
action: "opened PR",
|
|
104320
|
+
body: detail,
|
|
104321
|
+
fields: { issue: issue2.identifier }
|
|
104322
|
+
});
|
|
103899
104323
|
}
|
|
103900
104324
|
async function diffFilesAgainstBase(runner, cwd2, base2) {
|
|
103901
104325
|
let raw = "";
|
|
@@ -103967,6 +104391,14 @@ async function branchAlreadyMerged(runner, cwd2, branch, base2) {
|
|
|
103967
104391
|
} catch {}
|
|
103968
104392
|
return false;
|
|
103969
104393
|
}
|
|
104394
|
+
async function applyPrLabels(runner, cwd2, prRef, labels) {
|
|
104395
|
+
const clean = labels.map((l) => l.trim()).filter(Boolean);
|
|
104396
|
+
if (clean.length === 0 || !prRef)
|
|
104397
|
+
return;
|
|
104398
|
+
try {
|
|
104399
|
+
await runner.run(["gh", "pr", "edit", prRef, "--add-label", clean.join(",")], cwd2);
|
|
104400
|
+
} catch {}
|
|
104401
|
+
}
|
|
103970
104402
|
async function createPullRequest(input, runner) {
|
|
103971
104403
|
const base2 = input.base ?? "main";
|
|
103972
104404
|
const log3 = await runner.run(["git", "log", "--oneline", `${base2}..HEAD`, "--no-merges"], input.cwd);
|
|
@@ -104003,8 +104435,10 @@ async function createPullRequest(input, runner) {
|
|
|
104003
104435
|
".[0].url // empty"
|
|
104004
104436
|
], input.cwd);
|
|
104005
104437
|
const existingUrl = existing.stdout.trim();
|
|
104006
|
-
if (existingUrl)
|
|
104438
|
+
if (existingUrl) {
|
|
104439
|
+
await applyPrLabels(runner, input.cwd, existingUrl, input.labels ?? []);
|
|
104007
104440
|
return { url: existingUrl, created: false };
|
|
104441
|
+
}
|
|
104008
104442
|
const title = defaultTitle(input.issue);
|
|
104009
104443
|
const body = defaultBody(input.issue, input.branch, input.stackedOn);
|
|
104010
104444
|
const createArgs = ["gh", "pr", "create", "--base", base2, "--title", title, "--body", body];
|
|
@@ -104013,9 +104447,12 @@ async function createPullRequest(input, runner) {
|
|
|
104013
104447
|
const created = await runner.run(createArgs, input.cwd);
|
|
104014
104448
|
const url2 = created.stdout.trim().split(`
|
|
104015
104449
|
`).pop() ?? "";
|
|
104450
|
+
await applyPrLabels(runner, input.cwd, url2, input.labels ?? []);
|
|
104016
104451
|
return { url: url2, created: true };
|
|
104017
104452
|
}
|
|
104018
|
-
var init_pr = () => {
|
|
104453
|
+
var init_pr = __esm(() => {
|
|
104454
|
+
init_src8();
|
|
104455
|
+
});
|
|
104019
104456
|
|
|
104020
104457
|
// apps/agent/src/shared/pr/ci-classify.ts
|
|
104021
104458
|
async function runGhWithRetry(cmd, runner, cwd2, onRetry, sleep2 = (ms) => new Promise((r) => setTimeout(r, ms))) {
|
|
@@ -104564,7 +105001,7 @@ function emitFeatureSkipped(bus, id, reason) {
|
|
|
104564
105001
|
var init_run_feature = () => {};
|
|
104565
105002
|
|
|
104566
105003
|
// apps/agent/src/agent/post-task.ts
|
|
104567
|
-
import { join as join23
|
|
105004
|
+
import { join as join23 } from "path";
|
|
104568
105005
|
function summarizeUncommittedStatus(stdout) {
|
|
104569
105006
|
const lines = stdout.split(`
|
|
104570
105007
|
`).filter((line) => line.length > 0);
|
|
@@ -104691,6 +105128,7 @@ async function createPrWithRetry(ctx, issue2) {
|
|
|
104691
105128
|
base: base2,
|
|
104692
105129
|
metaOnlyFiles: ctx.cfg.metaOnlyFiles ?? [],
|
|
104693
105130
|
draft: ctx.cfg.prDraft ?? false,
|
|
105131
|
+
labels: ctx.cfg.prLabels ?? [],
|
|
104694
105132
|
...ctx.stackedOn ? {
|
|
104695
105133
|
stackedOn: {
|
|
104696
105134
|
prUrl: ctx.stackedOn.prUrl,
|
|
@@ -105062,17 +105500,6 @@ async function runValidateOnlyPhase(input, deps) {
|
|
|
105062
105500
|
await reactivateState(stateFilePath, log3, changeName);
|
|
105063
105501
|
return respawnWorker();
|
|
105064
105502
|
}
|
|
105065
|
-
async function recordGaveUp(stateFilePath, log3, changeName) {
|
|
105066
|
-
const path = join23(dirname9(stateFilePath), GAVEUP_COUNT_FILE);
|
|
105067
|
-
try {
|
|
105068
|
-
const file2 = Bun.file(path);
|
|
105069
|
-
const current = await file2.exists() ? Number.parseInt(await file2.text(), 10) || 0 : 0;
|
|
105070
|
-
await Bun.write(path, String(current + 1) + `
|
|
105071
|
-
`);
|
|
105072
|
-
} catch (err) {
|
|
105073
|
-
log3(`! could not record gave-up for ${changeName}: ${err.message}`, "yellow");
|
|
105074
|
-
}
|
|
105075
|
-
}
|
|
105076
105503
|
async function runPostTask(input, deps) {
|
|
105077
105504
|
const { log: log3, cmd, git: git2, runScript } = deps;
|
|
105078
105505
|
const emit3 = (phase, detail) => deps.onPhase?.(phase, detail);
|
|
@@ -105115,8 +105542,6 @@ async function runPostTask(input, deps) {
|
|
|
105115
105542
|
respawnWorker
|
|
105116
105543
|
});
|
|
105117
105544
|
emit3(effectiveCode === 0 ? "done" : "gave-up", effectiveCode !== 0 ? `exit ${effectiveCode}` : undefined);
|
|
105118
|
-
if (effectiveCode !== 0)
|
|
105119
|
-
await recordGaveUp(stateFilePath, log3, changeName);
|
|
105120
105545
|
await runWorktreeCleanupPhase({ changeName, cwd: cwd2, projectRoot, useWorktree, effectiveCode, cfg }, { git: git2, log: log3, emit: emit3 });
|
|
105121
105546
|
await runTeardownPhase({ cwd: cwd2, teardownScript: cfg.teardownScript }, { runScript, log: log3, emit: emit3 });
|
|
105122
105547
|
return effectiveCode;
|
|
@@ -105126,6 +105551,24 @@ async function runPostTask(input, deps) {
|
|
|
105126
105551
|
}
|
|
105127
105552
|
if (input.mode === "conflict-fix" && effectiveCode === 0) {
|
|
105128
105553
|
const identifier = issue2?.identifier ?? changeName;
|
|
105554
|
+
if (branch) {
|
|
105555
|
+
let aheadCount = 0;
|
|
105556
|
+
let checked = true;
|
|
105557
|
+
try {
|
|
105558
|
+
const r = await cmd.run(["git", "rev-list", "--count", `origin/${branch}..HEAD`], cwd2);
|
|
105559
|
+
aheadCount = Number.parseInt(r.stdout.trim(), 10) || 0;
|
|
105560
|
+
} catch (err) {
|
|
105561
|
+
checked = false;
|
|
105562
|
+
log3(`! ${identifier}: could not check for unpushed conflict-fix commits: ${err.message}`, "yellow");
|
|
105563
|
+
}
|
|
105564
|
+
if (checked && aheadCount > 0) {
|
|
105565
|
+
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");
|
|
105566
|
+
emit3("gave-up", "unpushed conflict resolution");
|
|
105567
|
+
await runWorktreeCleanupPhase({ changeName, cwd: cwd2, projectRoot, useWorktree, effectiveCode: PR_FAILED_EXIT, cfg }, { git: git2, log: log3, emit: emit3 });
|
|
105568
|
+
await runTeardownPhase({ cwd: cwd2, teardownScript: cfg.teardownScript }, { runScript, log: log3, emit: emit3 });
|
|
105569
|
+
return PR_FAILED_EXIT;
|
|
105570
|
+
}
|
|
105571
|
+
}
|
|
105129
105572
|
let prUrl = input.prUrl ?? null;
|
|
105130
105573
|
if (!prUrl && branch) {
|
|
105131
105574
|
prUrl = await findExistingOpenPrUrl(cmd, cwd2, branch);
|
|
@@ -105190,8 +105633,6 @@ async function runPostTask(input, deps) {
|
|
|
105190
105633
|
}
|
|
105191
105634
|
const succeeded = effectiveCode === 0 || effectiveCode === NO_CHANGES_EXIT;
|
|
105192
105635
|
emit3(succeeded ? "done" : "gave-up", succeeded ? undefined : `exit ${effectiveCode}`);
|
|
105193
|
-
if (!succeeded)
|
|
105194
|
-
await recordGaveUp(stateFilePath, log3, changeName);
|
|
105195
105636
|
await deps.runRetrospective?.({
|
|
105196
105637
|
changeName,
|
|
105197
105638
|
cwd: cwd2,
|
|
@@ -105218,7 +105659,6 @@ var PR_FAILED_EXIT = 71, MAX_PR_CREATE_ATTEMPTS = 5, NO_CHANGES_EXIT = 72, repoA
|
|
|
105218
105659
|
return { exitCode: proc.exitCode ?? 1, output };
|
|
105219
105660
|
};
|
|
105220
105661
|
var init_post_task = __esm(() => {
|
|
105221
|
-
init_layout();
|
|
105222
105662
|
init_tasks_md();
|
|
105223
105663
|
init_fs_change();
|
|
105224
105664
|
init_git2();
|
|
@@ -105232,6 +105672,300 @@ var init_post_task = __esm(() => {
|
|
|
105232
105672
|
repoAutoMergeCache = new Map;
|
|
105233
105673
|
});
|
|
105234
105674
|
|
|
105675
|
+
// apps/agent/src/shared/capabilities/gh-client.ts
|
|
105676
|
+
var init_gh_client = () => {};
|
|
105677
|
+
|
|
105678
|
+
// apps/agent/src/shared/capabilities/github/github-client.ts
|
|
105679
|
+
var STARTED_LABEL_NAMES, ISSUE_FIELDS = "id,number,title,body,state,stateReason,labels,assignees,author,createdAt,url", ISSUE_FIELDS_WITH_COMMENTS;
|
|
105680
|
+
var init_github_client = __esm(() => {
|
|
105681
|
+
init_worktree();
|
|
105682
|
+
init_gh_client();
|
|
105683
|
+
STARTED_LABEL_NAMES = new Set(["in progress", "in-progress", "started"]);
|
|
105684
|
+
ISSUE_FIELDS_WITH_COMMENTS = `${ISSUE_FIELDS},comments`;
|
|
105685
|
+
});
|
|
105686
|
+
|
|
105687
|
+
// apps/agent/src/shared/capabilities/github/identifier-strategy.ts
|
|
105688
|
+
function linearChangeName(issue2) {
|
|
105689
|
+
const slug = issue2.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 40).replace(/^-+|-+$/g, "");
|
|
105690
|
+
return slug ? `${issue2.identifier.toLowerCase()}-${slug}` : issue2.identifier.toLowerCase();
|
|
105691
|
+
}
|
|
105692
|
+
var linearIdentifierStrategy;
|
|
105693
|
+
var init_identifier_strategy = __esm(() => {
|
|
105694
|
+
init_worktree();
|
|
105695
|
+
init_github_client();
|
|
105696
|
+
linearIdentifierStrategy = {
|
|
105697
|
+
scopeKey: (issue2) => issue2.identifier.split("-")[0],
|
|
105698
|
+
changeName: linearChangeName,
|
|
105699
|
+
branchName: (issue2) => branchForChange(linearChangeName(issue2))
|
|
105700
|
+
};
|
|
105701
|
+
});
|
|
105702
|
+
|
|
105703
|
+
// apps/agent/src/agent/scaffold.ts
|
|
105704
|
+
import { join as join24 } from "path";
|
|
105705
|
+
function changeNameForIssue(issue2) {
|
|
105706
|
+
return linearIdentifierStrategy.changeName(issue2);
|
|
105707
|
+
}
|
|
105708
|
+
async function scaffoldChangeForIssue(tasksDir, statesDir, issue2, comments = [], appendPrompt = "", attachments = []) {
|
|
105709
|
+
const name = changeNameForIssue(issue2);
|
|
105710
|
+
const changeDir = join24(tasksDir, name);
|
|
105711
|
+
const stateDir = join24(statesDir, name);
|
|
105712
|
+
const commentsBlock = comments.length > 0 ? [
|
|
105713
|
+
"",
|
|
105714
|
+
"## Linear comments",
|
|
105715
|
+
"",
|
|
105716
|
+
...comments.flatMap((c) => [
|
|
105717
|
+
`**${c.user?.name ?? "unknown"}** \u2014 ${c.createdAt}`,
|
|
105718
|
+
"",
|
|
105719
|
+
c.body.trim(),
|
|
105720
|
+
""
|
|
105721
|
+
])
|
|
105722
|
+
] : [];
|
|
105723
|
+
const attachmentsBlock = attachments.length > 0 ? [
|
|
105724
|
+
"",
|
|
105725
|
+
"## Ticket Attachments",
|
|
105726
|
+
"",
|
|
105727
|
+
...attachments.map((a) => `- [${a.title ?? "Attachment"}](${a.url})`)
|
|
105728
|
+
] : [];
|
|
105729
|
+
const descriptionBody = issue2.description?.trim() || "_No description provided in Linear._";
|
|
105730
|
+
const proposal = [
|
|
105731
|
+
`# ${issue2.identifier}: ${issue2.title}`,
|
|
105732
|
+
"",
|
|
105733
|
+
`Source: [${issue2.identifier}](${issue2.url})`,
|
|
105734
|
+
`Status: ${issue2.state.name}`,
|
|
105735
|
+
issue2.assignee ? `Assignee: ${issue2.assignee.name}` : "",
|
|
105736
|
+
issue2.labels.length ? `Labels: ${issue2.labels.join(", ")}` : "",
|
|
105737
|
+
"",
|
|
105738
|
+
"## Why",
|
|
105739
|
+
"",
|
|
105740
|
+
descriptionBody,
|
|
105741
|
+
"",
|
|
105742
|
+
"## What Changes",
|
|
105743
|
+
"",
|
|
105744
|
+
"_Describe the concrete changes this proposal introduces (one bullet per change)._",
|
|
105745
|
+
...commentsBlock,
|
|
105746
|
+
...attachmentsBlock,
|
|
105747
|
+
...appendPrompt.trim() ? ["", "## Additional instructions", "", appendPrompt.trim()] : [],
|
|
105748
|
+
"",
|
|
105749
|
+
"## Steering",
|
|
105750
|
+
"",
|
|
105751
|
+
"_Add steering notes here as the loop runs._",
|
|
105752
|
+
""
|
|
105753
|
+
].filter((l) => l !== "").join(`
|
|
105754
|
+
`);
|
|
105755
|
+
const tasks = [
|
|
105756
|
+
`# Tasks for ${issue2.identifier}`,
|
|
105757
|
+
"",
|
|
105758
|
+
"## Planning",
|
|
105759
|
+
"",
|
|
105760
|
+
`- [ ] Read the Linear issue at ${issue2.url} and research the codebase to understand the mission and its scope`,
|
|
105761
|
+
`- [ ] Refine proposal.md with the problem statement, approach, and acceptance criteria derived from the research`,
|
|
105762
|
+
`- [ ] Fill in \`## Why\` and \`## What Changes\` in proposal.md so \`openspec validate\` passes (these sections are required by the validator)`,
|
|
105763
|
+
`- [ ] Add at least one spec delta under \`specs/<capability>/spec.md\` describing the behavior added/modified/removed by this change`,
|
|
105764
|
+
`- [ ] 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).`,
|
|
105765
|
+
`- [ ] 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.`,
|
|
105766
|
+
`- [ ] Is there anything else to add? Review the complete change context and document any additional edge cases, constraints, or open questions not captured above.`,
|
|
105767
|
+
""
|
|
105768
|
+
].join(`
|
|
105769
|
+
`);
|
|
105770
|
+
const design = [
|
|
105771
|
+
`# Design for ${issue2.identifier}`,
|
|
105772
|
+
"",
|
|
105773
|
+
"_Fill in the technical design as you work through the issue._",
|
|
105774
|
+
""
|
|
105775
|
+
].join(`
|
|
105776
|
+
`);
|
|
105777
|
+
await runCapability(fsChange.scaffold, {
|
|
105778
|
+
changeDir,
|
|
105779
|
+
stateDir,
|
|
105780
|
+
proposal,
|
|
105781
|
+
tasks,
|
|
105782
|
+
design
|
|
105783
|
+
});
|
|
105784
|
+
return name;
|
|
105785
|
+
}
|
|
105786
|
+
var init_scaffold = __esm(() => {
|
|
105787
|
+
init_fs_change();
|
|
105788
|
+
init_identifier_strategy();
|
|
105789
|
+
});
|
|
105790
|
+
|
|
105791
|
+
// apps/agent/src/components/task-pipeline.ts
|
|
105792
|
+
function stages(todo, confirmation, work, pr, ci, done) {
|
|
105793
|
+
return [
|
|
105794
|
+
{ node: "todo", status: todo },
|
|
105795
|
+
{ node: "confirmation", status: confirmation },
|
|
105796
|
+
{ node: "work", status: work },
|
|
105797
|
+
{ node: "PR", status: pr },
|
|
105798
|
+
{ node: "CI", status: ci },
|
|
105799
|
+
{ node: "done", status: done }
|
|
105800
|
+
];
|
|
105801
|
+
}
|
|
105802
|
+
function pipelineStages(row) {
|
|
105803
|
+
const state = row.state;
|
|
105804
|
+
switch (state) {
|
|
105805
|
+
case "todo":
|
|
105806
|
+
return stages("current", "pending", "pending", "pending", "pending", "pending");
|
|
105807
|
+
case "awaiting":
|
|
105808
|
+
return stages("done", "current", "pending", "pending", "pending", "pending");
|
|
105809
|
+
case "queued":
|
|
105810
|
+
case "working":
|
|
105811
|
+
case "in-progress":
|
|
105812
|
+
return stages("done", "done", "current", "pending", "pending", "pending");
|
|
105813
|
+
case "awaiting-ci":
|
|
105814
|
+
return stages("done", "done", "done", "done", "current", "pending");
|
|
105815
|
+
case "conflict-fix":
|
|
105816
|
+
return stages("done", "done", "done", "failed", "pending", "pending");
|
|
105817
|
+
case "ci-fix":
|
|
105818
|
+
return stages("done", "done", "done", "done", "failed", "pending");
|
|
105819
|
+
case "review":
|
|
105820
|
+
return stages("done", "done", "current", "done", "done", "pending");
|
|
105821
|
+
case "quarantined":
|
|
105822
|
+
return row.recovery?.lastReason === "conflicting" ? stages("done", "done", "done", "bailed", "pending", "pending") : stages("done", "done", "done", "done", "bailed", "pending");
|
|
105823
|
+
case "done":
|
|
105824
|
+
return stages("done", "done", "done", "done", "done", "done");
|
|
105825
|
+
case "error":
|
|
105826
|
+
return stages("done", "done", "failed", "pending", "pending", "pending");
|
|
105827
|
+
default: {
|
|
105828
|
+
const exhaustive = state;
|
|
105829
|
+
return exhaustive;
|
|
105830
|
+
}
|
|
105831
|
+
}
|
|
105832
|
+
}
|
|
105833
|
+
function attemptCount(plural) {
|
|
105834
|
+
return `${plural} fix attempt${plural === 1 ? "" : "s"}`;
|
|
105835
|
+
}
|
|
105836
|
+
function statusLabel(row) {
|
|
105837
|
+
const state = row.state;
|
|
105838
|
+
switch (state) {
|
|
105839
|
+
case "todo":
|
|
105840
|
+
return "todo";
|
|
105841
|
+
case "queued":
|
|
105842
|
+
return "queued";
|
|
105843
|
+
case "working":
|
|
105844
|
+
return "working";
|
|
105845
|
+
case "in-progress":
|
|
105846
|
+
return "in progress";
|
|
105847
|
+
case "awaiting":
|
|
105848
|
+
return "awaiting confirmation";
|
|
105849
|
+
case "awaiting-ci":
|
|
105850
|
+
return "awaiting CI";
|
|
105851
|
+
case "conflict-fix":
|
|
105852
|
+
return `conflict \xB7 ${attemptCount(row.recovery?.attempts ?? 0)}`;
|
|
105853
|
+
case "ci-fix":
|
|
105854
|
+
return `CI red \xB7 ${attemptCount(row.recovery?.attempts ?? 0)}`;
|
|
105855
|
+
case "review":
|
|
105856
|
+
return "addressing review";
|
|
105857
|
+
case "quarantined": {
|
|
105858
|
+
const tries = row.recovery?.attempts ?? 0;
|
|
105859
|
+
const reason = row.recovery?.lastReason === "conflicting" ? "conflict" : "CI";
|
|
105860
|
+
return `quarantined \xB7 ${tries} tries (${reason}), bailed`;
|
|
105861
|
+
}
|
|
105862
|
+
case "done":
|
|
105863
|
+
return "done";
|
|
105864
|
+
case "error":
|
|
105865
|
+
return "error";
|
|
105866
|
+
default: {
|
|
105867
|
+
const exhaustive = state;
|
|
105868
|
+
return exhaustive;
|
|
105869
|
+
}
|
|
105870
|
+
}
|
|
105871
|
+
}
|
|
105872
|
+
function buildBoardTree(rows) {
|
|
105873
|
+
const byId = new Map(rows.map((r) => [r.id, r]));
|
|
105874
|
+
const orderIndex = new Map(rows.map((r, i) => [r.id, i]));
|
|
105875
|
+
const blockersOf = (r) => (r.blockedByIds ?? []).filter((id) => id !== r.id && byId.has(id));
|
|
105876
|
+
const childrenOf = new Map;
|
|
105877
|
+
for (const r of rows) {
|
|
105878
|
+
for (const blockerId of blockersOf(r)) {
|
|
105879
|
+
const list = childrenOf.get(blockerId);
|
|
105880
|
+
if (list)
|
|
105881
|
+
list.push(r);
|
|
105882
|
+
else
|
|
105883
|
+
childrenOf.set(blockerId, [r]);
|
|
105884
|
+
}
|
|
105885
|
+
}
|
|
105886
|
+
for (const list of childrenOf.values()) {
|
|
105887
|
+
list.sort((a, b) => orderIndex.get(a.id) - orderIndex.get(b.id));
|
|
105888
|
+
}
|
|
105889
|
+
const emitted = new Set;
|
|
105890
|
+
const depthById = new Map;
|
|
105891
|
+
const result2 = [];
|
|
105892
|
+
const blockerIdentifiersOf = (r) => blockersOf(r).map((id) => byId.get(id).identifier);
|
|
105893
|
+
const tryEmit = (r) => {
|
|
105894
|
+
if (emitted.has(r.id))
|
|
105895
|
+
return;
|
|
105896
|
+
const blockers = blockersOf(r);
|
|
105897
|
+
if (!blockers.every((id) => emitted.has(id)))
|
|
105898
|
+
return;
|
|
105899
|
+
const depth = blockers.length === 0 ? 0 : Math.max(...blockers.map((id) => depthById.get(id))) + 1;
|
|
105900
|
+
depthById.set(r.id, depth);
|
|
105901
|
+
emitted.add(r.id);
|
|
105902
|
+
result2.push({ row: r, depth, blockerIdentifiers: blockerIdentifiersOf(r) });
|
|
105903
|
+
for (const child of childrenOf.get(r.id) ?? [])
|
|
105904
|
+
tryEmit(child);
|
|
105905
|
+
};
|
|
105906
|
+
for (const r of rows) {
|
|
105907
|
+
if (blockersOf(r).length === 0)
|
|
105908
|
+
tryEmit(r);
|
|
105909
|
+
}
|
|
105910
|
+
for (const r of rows) {
|
|
105911
|
+
if (emitted.has(r.id))
|
|
105912
|
+
continue;
|
|
105913
|
+
depthById.set(r.id, 0);
|
|
105914
|
+
emitted.add(r.id);
|
|
105915
|
+
result2.push({ row: r, depth: 0, blockerIdentifiers: blockerIdentifiersOf(r) });
|
|
105916
|
+
for (const child of childrenOf.get(r.id) ?? [])
|
|
105917
|
+
tryEmit(child);
|
|
105918
|
+
}
|
|
105919
|
+
return result2;
|
|
105920
|
+
}
|
|
105921
|
+
function machineStateToTicketState(value) {
|
|
105922
|
+
switch (value) {
|
|
105923
|
+
case "idle":
|
|
105924
|
+
return "in-progress";
|
|
105925
|
+
case "working":
|
|
105926
|
+
return "working";
|
|
105927
|
+
case "conflict-fix":
|
|
105928
|
+
return "conflict-fix";
|
|
105929
|
+
case "ci-fix":
|
|
105930
|
+
return "ci-fix";
|
|
105931
|
+
case "awaiting":
|
|
105932
|
+
return "awaiting";
|
|
105933
|
+
case "awaiting-ci":
|
|
105934
|
+
return "awaiting-ci";
|
|
105935
|
+
case "review":
|
|
105936
|
+
return "review";
|
|
105937
|
+
case "quarantined":
|
|
105938
|
+
return "quarantined";
|
|
105939
|
+
case "preempting":
|
|
105940
|
+
case "routing-after-preempt":
|
|
105941
|
+
return "working";
|
|
105942
|
+
case "done":
|
|
105943
|
+
return "done";
|
|
105944
|
+
case "error":
|
|
105945
|
+
return "error";
|
|
105946
|
+
default:
|
|
105947
|
+
return "working";
|
|
105948
|
+
}
|
|
105949
|
+
}
|
|
105950
|
+
var STATUS_GLYPH, PIPELINE_NODES;
|
|
105951
|
+
var init_task_pipeline = __esm(() => {
|
|
105952
|
+
STATUS_GLYPH = {
|
|
105953
|
+
done: "\u2713",
|
|
105954
|
+
current: "\u25CF",
|
|
105955
|
+
pending: "\u25CB",
|
|
105956
|
+
failed: "\u2717",
|
|
105957
|
+
bailed: "\u26D4"
|
|
105958
|
+
};
|
|
105959
|
+
PIPELINE_NODES = [
|
|
105960
|
+
"todo",
|
|
105961
|
+
"confirmation",
|
|
105962
|
+
"work",
|
|
105963
|
+
"PR",
|
|
105964
|
+
"CI",
|
|
105965
|
+
"done"
|
|
105966
|
+
];
|
|
105967
|
+
});
|
|
105968
|
+
|
|
105235
105969
|
// packages/core/src/ordering/hierarchical-order.ts
|
|
105236
105970
|
function rank(priority) {
|
|
105237
105971
|
return !priority ? Number.POSITIVE_INFINITY : priority;
|
|
@@ -105493,26 +106227,62 @@ var init_queue_order = __esm(() => {
|
|
|
105493
106227
|
});
|
|
105494
106228
|
|
|
105495
106229
|
// apps/agent/src/runtime/coordinator.ts
|
|
106230
|
+
import { appendFile as appendFile2 } from "fs/promises";
|
|
105496
106231
|
function emitCapture(bus, event, properties) {
|
|
105497
106232
|
capture(event, properties);
|
|
105498
106233
|
bus.emit({ type: event, ...properties });
|
|
105499
106234
|
}
|
|
105500
106235
|
function completionCommentBody(args) {
|
|
105501
|
-
const { noChanges, ok, trigger, changeName, code } = args;
|
|
106236
|
+
const { noChanges, ok, trigger, changeName, code, reachedDone } = args;
|
|
105502
106237
|
if (noChanges) {
|
|
105503
|
-
return
|
|
106238
|
+
return buildRalphyComment({
|
|
106239
|
+
type: "completed-noop",
|
|
106240
|
+
action: "completed \u2014 no code changes",
|
|
106241
|
+
body: `Completed all tasks for this issue but produced no code changes \u2014 the requested ` + `work appears to already be present on the base branch (or was a no-op). No PR was ` + `opened. Change: \`${changeName}\`
|
|
105504
106242
|
|
|
105505
|
-
` + `Marking this done; please verify the work is genuinely in place. If it is not, ` + `reopen the issue with more specifics
|
|
106243
|
+
` + `Marking this done; please verify the work is genuinely in place. If it is not, ` + `reopen the issue with more specifics.`,
|
|
106244
|
+
fields: { change: changeName }
|
|
106245
|
+
});
|
|
105506
106246
|
}
|
|
105507
106247
|
if (!ok) {
|
|
105508
|
-
return
|
|
105509
|
-
|
|
105510
|
-
|
|
106248
|
+
return buildRalphyComment({
|
|
106249
|
+
type: "exited",
|
|
106250
|
+
action: `exited with code ${code}`,
|
|
106251
|
+
body: `This issue has been quarantined and will not be auto-resumed on the next poll. ` + `Inspect the worktree at \`~/.ralph/<project>/worktrees/${changeName}\`, fix the ` + `underlying failure, then remove the error marker on this Linear issue (or run ` + `\`ralph clean --name ${changeName}\`) to clear the quarantine. Change: \`${changeName}\``,
|
|
106252
|
+
fields: { change: changeName, code }
|
|
106253
|
+
});
|
|
105511
106254
|
}
|
|
105512
106255
|
if (trigger === "conflict-fix") {
|
|
105513
|
-
return
|
|
106256
|
+
return buildRalphyComment({
|
|
106257
|
+
type: "conflicts-resolved",
|
|
106258
|
+
action: "resolved merge conflicts",
|
|
106259
|
+
body: `Change: \`${changeName}\``,
|
|
106260
|
+
fields: { change: changeName }
|
|
106261
|
+
});
|
|
105514
106262
|
}
|
|
105515
|
-
|
|
106263
|
+
if (trigger === "ci-fix") {
|
|
106264
|
+
return buildRalphyComment({
|
|
106265
|
+
type: "ci-fix-pushed",
|
|
106266
|
+
action: "pushed a CI fix",
|
|
106267
|
+
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}\``,
|
|
106268
|
+
fields: { change: changeName }
|
|
106269
|
+
});
|
|
106270
|
+
}
|
|
106271
|
+
if (!reachedDone) {
|
|
106272
|
+
const isReview = trigger === "review";
|
|
106273
|
+
return buildRalphyComment({
|
|
106274
|
+
type: "awaiting-ci",
|
|
106275
|
+
action: isReview ? "addressed review feedback" : "opened a PR",
|
|
106276
|
+
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}\``,
|
|
106277
|
+
fields: { change: changeName }
|
|
106278
|
+
});
|
|
106279
|
+
}
|
|
106280
|
+
return buildRalphyComment({
|
|
106281
|
+
type: "completed",
|
|
106282
|
+
action: "completed work",
|
|
106283
|
+
body: `Change: \`${changeName}\``,
|
|
106284
|
+
fields: { change: changeName }
|
|
106285
|
+
});
|
|
105516
106286
|
}
|
|
105517
106287
|
function extractPrNumber(url2) {
|
|
105518
106288
|
const m = /\/pull\/(\d+)(?:[/?#]|$)/.exec(url2);
|
|
@@ -105539,7 +106309,19 @@ class AgentCoordinator {
|
|
|
105539
106309
|
this.opts = opts;
|
|
105540
106310
|
this.bus = deps.bus ?? createNoopBus();
|
|
105541
106311
|
const providedMachine = flowMachine.provide({ actors: { preemption: preemptionActorLogic } });
|
|
105542
|
-
this.flowStore = new FlowActorStore({
|
|
106312
|
+
this.flowStore = new FlowActorStore({
|
|
106313
|
+
bus: this.bus,
|
|
106314
|
+
persist: () => {},
|
|
106315
|
+
maxRecoveryAttempts: this.opts.prRecovery?.maxRecoverySessions ?? 0,
|
|
106316
|
+
onTransition: (_issueId, changeDir, transition2) => {
|
|
106317
|
+
if (!changeDir)
|
|
106318
|
+
return;
|
|
106319
|
+
const path = `${changeDir}/.ralph-state.flow-history.jsonl`;
|
|
106320
|
+
const line = `${JSON.stringify({ ts: new Date().toISOString(), ...transition2 })}
|
|
106321
|
+
`;
|
|
106322
|
+
appendFile2(path, line).catch(() => {});
|
|
106323
|
+
}
|
|
106324
|
+
}, providedMachine);
|
|
105543
106325
|
}
|
|
105544
106326
|
get activeCount() {
|
|
105545
106327
|
return this.workers.length;
|
|
@@ -105611,7 +106393,15 @@ class AgentCoordinator {
|
|
|
105611
106393
|
awaiting: awaitingCount
|
|
105612
106394
|
};
|
|
105613
106395
|
const found2 = buckets2.todo + buckets2.inProgress + buckets2.mentions + buckets2.awaiting;
|
|
105614
|
-
return {
|
|
106396
|
+
return {
|
|
106397
|
+
found: found2,
|
|
106398
|
+
added: 0,
|
|
106399
|
+
buckets: buckets2,
|
|
106400
|
+
prStatus: emptyPrStatus(),
|
|
106401
|
+
phase: {},
|
|
106402
|
+
flow: {},
|
|
106403
|
+
board: []
|
|
106404
|
+
};
|
|
105615
106405
|
}
|
|
105616
106406
|
const maxT = this.opts.maxTickets ?? 0;
|
|
105617
106407
|
const atTicketLimit = () => {
|
|
@@ -105690,7 +106480,7 @@ class AgentCoordinator {
|
|
|
105690
106480
|
added += 1;
|
|
105691
106481
|
this.deps.onLog(` \u21B3 ${issue2.identifier} queued (fresh)`, "gray");
|
|
105692
106482
|
}
|
|
105693
|
-
const prStatus = await this.scanPrMergeStates();
|
|
106483
|
+
const { counts: prStatus, prByIssue } = await this.scanPrMergeStates();
|
|
105694
106484
|
if (this.queue.length > 0) {
|
|
105695
106485
|
this.queue = orderQueueEntries(this.queue, this.opts.getAutoMerge);
|
|
105696
106486
|
}
|
|
@@ -105720,7 +106510,103 @@ class AgentCoordinator {
|
|
|
105720
106510
|
flow2[w.changeName] = "working";
|
|
105721
106511
|
}
|
|
105722
106512
|
}
|
|
105723
|
-
|
|
106513
|
+
const board = await this.buildBoard({
|
|
106514
|
+
todo,
|
|
106515
|
+
inProgress,
|
|
106516
|
+
mentions,
|
|
106517
|
+
prByIssue,
|
|
106518
|
+
awaitingIds: awaitingClaimed
|
|
106519
|
+
});
|
|
106520
|
+
return { found, added, buckets, prStatus, phase: {}, flow: flow2, board };
|
|
106521
|
+
}
|
|
106522
|
+
async buildBoard(args) {
|
|
106523
|
+
const { todo, inProgress, mentions, prByIssue, awaitingIds } = args;
|
|
106524
|
+
const order = [
|
|
106525
|
+
...this.workers.map((w) => ({
|
|
106526
|
+
issue: w.issue,
|
|
106527
|
+
kind: "worker",
|
|
106528
|
+
changeName: w.changeName
|
|
106529
|
+
})),
|
|
106530
|
+
...this.queue.map((q) => ({
|
|
106531
|
+
issue: q.issue,
|
|
106532
|
+
kind: "queued",
|
|
106533
|
+
changeName: changeNameForIssue(q.issue)
|
|
106534
|
+
})),
|
|
106535
|
+
...inProgress.map((issue2) => ({
|
|
106536
|
+
issue: issue2,
|
|
106537
|
+
kind: awaitingIds.has(issue2.id) ? "awaiting" : "in-progress",
|
|
106538
|
+
changeName: changeNameForIssue(issue2)
|
|
106539
|
+
})),
|
|
106540
|
+
...todo.map((issue2) => ({
|
|
106541
|
+
issue: issue2,
|
|
106542
|
+
kind: "todo",
|
|
106543
|
+
changeName: changeNameForIssue(issue2)
|
|
106544
|
+
})),
|
|
106545
|
+
...mentions.map((m) => ({
|
|
106546
|
+
issue: m.issue,
|
|
106547
|
+
kind: "mention",
|
|
106548
|
+
changeName: changeNameForIssue(m.issue)
|
|
106549
|
+
}))
|
|
106550
|
+
];
|
|
106551
|
+
const seen = new Set;
|
|
106552
|
+
const rows = [];
|
|
106553
|
+
for (const src of order) {
|
|
106554
|
+
if (seen.has(src.issue.id))
|
|
106555
|
+
continue;
|
|
106556
|
+
seen.add(src.issue.id);
|
|
106557
|
+
const row = await this.resolveBoardRow(src.issue, src.kind, src.changeName, prByIssue);
|
|
106558
|
+
if (row)
|
|
106559
|
+
rows.push(row);
|
|
106560
|
+
}
|
|
106561
|
+
return rows;
|
|
106562
|
+
}
|
|
106563
|
+
async resolveBoardRow(issue2, kind, changeName, prByIssue) {
|
|
106564
|
+
let state;
|
|
106565
|
+
let recovery;
|
|
106566
|
+
if (kind === "todo") {
|
|
106567
|
+
state = "todo";
|
|
106568
|
+
} else if (kind === "mention") {
|
|
106569
|
+
state = "review";
|
|
106570
|
+
} else if (kind === "awaiting") {
|
|
106571
|
+
state = "awaiting";
|
|
106572
|
+
} else if (kind !== "worker" && issue2.blockedByIds.length > 0) {
|
|
106573
|
+
state = "todo";
|
|
106574
|
+
} else {
|
|
106575
|
+
const changeDir = this.deps.getChangeDir?.(issue2) ?? undefined;
|
|
106576
|
+
const actor = await this.flowStore.getActor(issue2.id, changeDir);
|
|
106577
|
+
const snapshot = actor.getSnapshot();
|
|
106578
|
+
state = machineStateToTicketState(snapshot.value);
|
|
106579
|
+
if (state === "done")
|
|
106580
|
+
return null;
|
|
106581
|
+
if (kind === "queued" && state === "in-progress")
|
|
106582
|
+
state = "queued";
|
|
106583
|
+
const flowRecovery = snapshot.context.data.recovery;
|
|
106584
|
+
if (flowRecovery) {
|
|
106585
|
+
recovery = {
|
|
106586
|
+
attempts: flowRecovery.attempts,
|
|
106587
|
+
bailed: state === "quarantined",
|
|
106588
|
+
firstFailedAt: flowRecovery.firstFailedAt,
|
|
106589
|
+
lastReason: flowRecovery.lastReason
|
|
106590
|
+
};
|
|
106591
|
+
if (state === "awaiting-ci" || state === "in-progress" || state === "working") {
|
|
106592
|
+
state = flowRecovery.lastReason === "conflicting" ? "conflict-fix" : "ci-fix";
|
|
106593
|
+
}
|
|
106594
|
+
}
|
|
106595
|
+
}
|
|
106596
|
+
const prUrl = prByIssue.get(issue2.id)?.url;
|
|
106597
|
+
return {
|
|
106598
|
+
changeName,
|
|
106599
|
+
id: issue2.id,
|
|
106600
|
+
identifier: issue2.identifier,
|
|
106601
|
+
title: issue2.title,
|
|
106602
|
+
url: issue2.url,
|
|
106603
|
+
priority: issue2.priority,
|
|
106604
|
+
state,
|
|
106605
|
+
blockedByIds: issue2.blockedByIds,
|
|
106606
|
+
blockedByIdentifiers: issue2.blockedByIdentifiers ?? [],
|
|
106607
|
+
...recovery ? { recovery } : {},
|
|
106608
|
+
...prUrl ? { prUrl } : {}
|
|
106609
|
+
};
|
|
105724
106610
|
}
|
|
105725
106611
|
async walkRegistryForInProgress(inProgress) {
|
|
105726
106612
|
const claimed = new Map;
|
|
@@ -105811,7 +106697,12 @@ class AgentCoordinator {
|
|
|
105811
106697
|
const prNum = extractPrNumber(pr.url);
|
|
105812
106698
|
const ref = prNum !== null ? `PR #${prNum}` : `PR ${pr.url}`;
|
|
105813
106699
|
try {
|
|
105814
|
-
await this.deps.postComment(issue2,
|
|
106700
|
+
await this.deps.postComment(issue2, buildRalphyComment({
|
|
106701
|
+
type: "promoted",
|
|
106702
|
+
action: `promoted to ${trigger} flow`,
|
|
106703
|
+
body: `${ref} is ${stateLabel} \u2014 promoted to ${trigger} flow.`,
|
|
106704
|
+
fields: { trigger, pr: extractPrNumber(pr.url) ?? pr.url }
|
|
106705
|
+
}));
|
|
105815
106706
|
this.deps.onLog(` ${issue2.identifier}: posted ${trigger}-promotion comment`, "gray");
|
|
105816
106707
|
} catch (err) {
|
|
105817
106708
|
this.deps.onLog(`! Linear ${trigger}-promotion comment failed for ${issue2.identifier}: ${err.message}`, "yellow");
|
|
@@ -105864,7 +106755,12 @@ class AgentCoordinator {
|
|
|
105864
106755
|
if (currMilestone <= lastMilestone)
|
|
105865
106756
|
continue;
|
|
105866
106757
|
try {
|
|
105867
|
-
await this.deps.postComment(w.issue,
|
|
106758
|
+
await this.deps.postComment(w.issue, buildRalphyComment({
|
|
106759
|
+
type: "progress",
|
|
106760
|
+
action: `progress update \u2014 iteration ${count}`,
|
|
106761
|
+
body: `Iteration ${count} on \`${w.changeName}\``,
|
|
106762
|
+
fields: { change: w.changeName, iter: count }
|
|
106763
|
+
}));
|
|
105868
106764
|
w.lastReportedIteration = count;
|
|
105869
106765
|
this.deps.onLog(` ${w.issueIdentifier}: posted progress comment (iteration ${count})`, "gray");
|
|
105870
106766
|
} catch (err) {
|
|
@@ -105921,20 +106817,20 @@ class AgentCoordinator {
|
|
|
105921
106817
|
}
|
|
105922
106818
|
async scanPrMergeStates() {
|
|
105923
106819
|
const counts = emptyPrStatus();
|
|
106820
|
+
const prByIssue = new Map;
|
|
105924
106821
|
if (!this.opts.prRecovery?.enabled)
|
|
105925
|
-
return counts;
|
|
106822
|
+
return { counts, prByIssue };
|
|
105926
106823
|
let candidates = [];
|
|
105927
106824
|
try {
|
|
105928
106825
|
candidates = await this.deps.fetchDoneCandidates();
|
|
105929
106826
|
} catch (err) {
|
|
105930
106827
|
this.deps.onLog(`! PR merge-state scan fetch failed: ${err.message}`, "yellow");
|
|
105931
|
-
return counts;
|
|
106828
|
+
return { counts, prByIssue };
|
|
105932
106829
|
}
|
|
105933
106830
|
if (candidates.length === 0)
|
|
105934
|
-
return counts;
|
|
106831
|
+
return { counts, prByIssue };
|
|
105935
106832
|
const preQueue = this.queue.map((q) => ({ id: q.issue.id, trigger: q.trigger }));
|
|
105936
106833
|
const preWorkers = this.workers.map((w) => ({ id: w.issueId, trigger: w.trigger }));
|
|
105937
|
-
const tracker = this.opts.prTracker;
|
|
105938
106834
|
for (const issue2 of candidates) {
|
|
105939
106835
|
if (this.workers.some((w) => w.issueId === issue2.id))
|
|
105940
106836
|
continue;
|
|
@@ -105942,12 +106838,17 @@ class AgentCoordinator {
|
|
|
105942
106838
|
continue;
|
|
105943
106839
|
if (this.queue.some((q) => q.issue.id === issue2.id))
|
|
105944
106840
|
continue;
|
|
105945
|
-
|
|
105946
|
-
|
|
106841
|
+
const changeDir = this.deps.getChangeDir?.(issue2) ?? undefined;
|
|
106842
|
+
const actor = await this.flowStore.getActor(issue2.id, changeDir);
|
|
106843
|
+
const stateValue = () => actor.getSnapshot().value;
|
|
106844
|
+
if (stateValue() === "quarantined" && this.errorMarkerCleared(issue2)) {
|
|
106845
|
+
actor.send({ type: "QUARANTINE_CLEARED" });
|
|
106846
|
+
if (changeDir)
|
|
106847
|
+
await this.flowStore.persistActor(issue2.id, changeDir).catch(() => {});
|
|
105947
106848
|
this.conflictNotified.delete(issue2.id);
|
|
105948
106849
|
this.ciFailedNotified.delete(issue2.id);
|
|
105949
106850
|
this.conflictPromoted.delete(issue2.id);
|
|
105950
|
-
this.deps.onLog(` ${issue2.identifier}:
|
|
106851
|
+
this.deps.onLog(` ${issue2.identifier}: quarantine cleared (ralph:error removed) \u2014 retrying recovery`, "cyan");
|
|
105951
106852
|
}
|
|
105952
106853
|
let pr;
|
|
105953
106854
|
try {
|
|
@@ -105958,45 +106859,47 @@ class AgentCoordinator {
|
|
|
105958
106859
|
}
|
|
105959
106860
|
if (!pr)
|
|
105960
106861
|
continue;
|
|
106862
|
+
prByIssue.set(issue2.id, pr);
|
|
105961
106863
|
if (pr.status === "mergeable")
|
|
105962
106864
|
counts.mergeable += 1;
|
|
105963
|
-
if (pr.status === "mergeable" && this.opts.prTracker) {
|
|
105964
|
-
try {
|
|
105965
|
-
await this.opts.prTracker.clear(issue2.identifier);
|
|
105966
|
-
} catch (err) {
|
|
105967
|
-
this.deps.onLog(`! pr-tracker clear failed for ${issue2.identifier}: ${err.message}`, "yellow");
|
|
105968
|
-
}
|
|
105969
|
-
}
|
|
105970
106865
|
if (pr.status === "mergeable") {
|
|
105971
|
-
const
|
|
105972
|
-
|
|
105973
|
-
if (actor.getSnapshot().value === "awaiting-ci") {
|
|
106866
|
+
const value = stateValue();
|
|
106867
|
+
if (value === "awaiting-ci" || value === "quarantined") {
|
|
105974
106868
|
if (this.issueInSetDoneState(issue2)) {
|
|
106869
|
+
actor.send({ type: "RECOVERY_CLEARED" });
|
|
105975
106870
|
actor.send({ type: "PR_PASSED" });
|
|
105976
106871
|
if (changeDir)
|
|
105977
106872
|
await this.flowStore.persistActor(issue2.id, changeDir).catch(() => {});
|
|
105978
|
-
if (
|
|
106873
|
+
if (stateValue() === "done")
|
|
105979
106874
|
this.flowStore.disposeActor(issue2.id);
|
|
105980
|
-
}
|
|
105981
106875
|
} else {
|
|
105982
106876
|
await this.advancePrToDone(issue2, pr.url, actor, changeDir);
|
|
105983
106877
|
}
|
|
106878
|
+
} else {
|
|
106879
|
+
actor.send({ type: "RECOVERY_CLEARED" });
|
|
106880
|
+
if (changeDir)
|
|
106881
|
+
await this.flowStore.persistActor(issue2.id, changeDir).catch(() => {});
|
|
105984
106882
|
}
|
|
105985
106883
|
continue;
|
|
105986
106884
|
}
|
|
105987
106885
|
if (pr.status === "conflicted") {
|
|
105988
106886
|
if (!this.opts.prRecovery?.fixConflicts)
|
|
105989
106887
|
continue;
|
|
105990
|
-
if (
|
|
106888
|
+
if (stateValue() === "quarantined") {
|
|
105991
106889
|
counts.quarantined += 1;
|
|
105992
106890
|
continue;
|
|
105993
106891
|
}
|
|
105994
106892
|
counts.conflicted += 1;
|
|
105995
106893
|
if (this.conflictNotified.has(issue2.id))
|
|
105996
106894
|
continue;
|
|
105997
|
-
|
|
106895
|
+
actor.send({ type: "RESUME_DETECTED" });
|
|
106896
|
+
actor.send({ type: "CONFLICT_DETECTED", at: new Date().toISOString() });
|
|
106897
|
+
if (changeDir)
|
|
106898
|
+
await this.flowStore.persistActor(issue2.id, changeDir).catch(() => {});
|
|
106899
|
+
if (stateValue() === "quarantined") {
|
|
105998
106900
|
counts.conflicted -= 1;
|
|
105999
106901
|
counts.quarantined += 1;
|
|
106902
|
+
await this.quarantineBail(issue2, pr.url, "conflicting", actor);
|
|
106000
106903
|
continue;
|
|
106001
106904
|
}
|
|
106002
106905
|
emitCapture(this.bus, "agent_conflict_detected", { issue_identifier: issue2.identifier });
|
|
@@ -106004,14 +106907,16 @@ class AgentCoordinator {
|
|
|
106004
106907
|
this.deps.onLog(` ${issue2.identifier}: PR ${pr.url} conflicting \u2014 queued (conflict-fix)`, "yellow");
|
|
106005
106908
|
if (this.opts.postComments !== false) {
|
|
106006
106909
|
try {
|
|
106007
|
-
await this.deps.postComment(issue2,
|
|
106910
|
+
await this.deps.postComment(issue2, buildRalphyComment({
|
|
106911
|
+
type: "conflict-detected",
|
|
106912
|
+
action: "detected merge conflicts",
|
|
106913
|
+
body: `Detected merge conflicts on this PR (${pr.url}) \u2014 re-running to resolve.`,
|
|
106914
|
+
fields: { pr: extractPrNumber(pr.url) ?? pr.url }
|
|
106915
|
+
}));
|
|
106008
106916
|
} catch (err) {
|
|
106009
106917
|
this.deps.onLog(`! Linear conflict comment failed for ${issue2.identifier}: ${err.message}`, "yellow");
|
|
106010
106918
|
}
|
|
106011
106919
|
}
|
|
106012
|
-
const conflictActor = await this.flowStore.getActor(issue2.id, this.deps.getChangeDir?.(issue2) ?? undefined);
|
|
106013
|
-
conflictActor.send({ type: "RESUME_DETECTED" });
|
|
106014
|
-
conflictActor.send({ type: "CONFLICT_DETECTED" });
|
|
106015
106920
|
this.queue.push({
|
|
106016
106921
|
issue: issue2,
|
|
106017
106922
|
trigger: "conflict-fix",
|
|
@@ -106022,16 +106927,21 @@ class AgentCoordinator {
|
|
|
106022
106927
|
if (pr.status === "ci_failed") {
|
|
106023
106928
|
if (!this.opts.prRecovery?.fixCi)
|
|
106024
106929
|
continue;
|
|
106025
|
-
if (
|
|
106930
|
+
if (stateValue() === "quarantined") {
|
|
106026
106931
|
counts.quarantined += 1;
|
|
106027
106932
|
continue;
|
|
106028
106933
|
}
|
|
106029
106934
|
counts.ciFailed += 1;
|
|
106030
106935
|
if (this.ciFailedNotified.has(issue2.id))
|
|
106031
106936
|
continue;
|
|
106032
|
-
|
|
106937
|
+
actor.send({ type: "RESUME_DETECTED" });
|
|
106938
|
+
actor.send({ type: "CI_FAILED_DETECTED", at: new Date().toISOString() });
|
|
106939
|
+
if (changeDir)
|
|
106940
|
+
await this.flowStore.persistActor(issue2.id, changeDir).catch(() => {});
|
|
106941
|
+
if (stateValue() === "quarantined") {
|
|
106033
106942
|
counts.ciFailed -= 1;
|
|
106034
106943
|
counts.quarantined += 1;
|
|
106944
|
+
await this.quarantineBail(issue2, pr.url, "ci_failed", actor);
|
|
106035
106945
|
continue;
|
|
106036
106946
|
}
|
|
106037
106947
|
emitCapture(this.bus, "agent_ci_failed_detected", { issue_identifier: issue2.identifier });
|
|
@@ -106039,14 +106949,16 @@ class AgentCoordinator {
|
|
|
106039
106949
|
this.deps.onLog(` ${issue2.identifier}: PR ${pr.url} CI failing \u2014 queued (ci-fix)`, "yellow");
|
|
106040
106950
|
if (this.opts.postComments !== false) {
|
|
106041
106951
|
try {
|
|
106042
|
-
await this.deps.postComment(issue2,
|
|
106952
|
+
await this.deps.postComment(issue2, buildRalphyComment({
|
|
106953
|
+
type: "ci-failed",
|
|
106954
|
+
action: "detected failing CI",
|
|
106955
|
+
body: `Detected failing CI on this PR (${pr.url}) \u2014 re-running to fix.`,
|
|
106956
|
+
fields: { pr: extractPrNumber(pr.url) ?? pr.url }
|
|
106957
|
+
}));
|
|
106043
106958
|
} catch (err) {
|
|
106044
106959
|
this.deps.onLog(`! Linear ci-failed comment failed for ${issue2.identifier}: ${err.message}`, "yellow");
|
|
106045
106960
|
}
|
|
106046
106961
|
}
|
|
106047
|
-
const ciActor = await this.flowStore.getActor(issue2.id, this.deps.getChangeDir?.(issue2) ?? undefined);
|
|
106048
|
-
ciActor.send({ type: "RESUME_DETECTED" });
|
|
106049
|
-
ciActor.send({ type: "CI_FAILED_DETECTED" });
|
|
106050
106962
|
this.queue.push({
|
|
106051
106963
|
issue: issue2,
|
|
106052
106964
|
trigger: "ci-fix",
|
|
@@ -106066,7 +106978,7 @@ class AgentCoordinator {
|
|
|
106066
106978
|
else if (w.trigger === "ci-fix")
|
|
106067
106979
|
counts.ciFailed += 1;
|
|
106068
106980
|
}
|
|
106069
|
-
return counts;
|
|
106981
|
+
return { counts, prByIssue };
|
|
106070
106982
|
}
|
|
106071
106983
|
issueInSetDoneState(issue2) {
|
|
106072
106984
|
const sd = this.opts.setDone;
|
|
@@ -106076,6 +106988,7 @@ class AgentCoordinator {
|
|
|
106076
106988
|
}
|
|
106077
106989
|
async advancePrToDone(issue2, prUrl, actor, changeDir) {
|
|
106078
106990
|
this.deps.onLog(` ${issue2.identifier}: PR ${prUrl} mergeable \u2014 moving to done`, "green");
|
|
106991
|
+
actor.send({ type: "RECOVERY_CLEARED" });
|
|
106079
106992
|
if (this.opts.setDone) {
|
|
106080
106993
|
try {
|
|
106081
106994
|
await this.deps.applyIndicator(issue2, this.opts.setDone);
|
|
@@ -106087,6 +107000,8 @@ class AgentCoordinator {
|
|
|
106087
107000
|
issue_identifier: issue2.identifier,
|
|
106088
107001
|
error: err.message
|
|
106089
107002
|
});
|
|
107003
|
+
if (changeDir)
|
|
107004
|
+
await this.flowStore.persistActor(issue2.id, changeDir).catch(() => {});
|
|
106090
107005
|
return;
|
|
106091
107006
|
}
|
|
106092
107007
|
if (this.opts.setInProgress) {
|
|
@@ -106105,7 +107020,12 @@ class AgentCoordinator {
|
|
|
106105
107020
|
}
|
|
106106
107021
|
if (this.opts.postComments !== false) {
|
|
106107
107022
|
try {
|
|
106108
|
-
await this.deps.postComment(issue2,
|
|
107023
|
+
await this.deps.postComment(issue2, buildRalphyComment({
|
|
107024
|
+
type: "verified",
|
|
107025
|
+
action: "verified PR mergeable",
|
|
107026
|
+
body: `Verified this PR (${prUrl}) is mergeable (CI green, no conflicts) \u2014 moving to done.`,
|
|
107027
|
+
fields: { pr: extractPrNumber(prUrl) ?? prUrl }
|
|
107028
|
+
}));
|
|
106109
107029
|
} catch (err) {
|
|
106110
107030
|
this.deps.onLog(`! Linear done comment failed for ${issue2.identifier}: ${err.message}`, "yellow");
|
|
106111
107031
|
}
|
|
@@ -106121,43 +107041,34 @@ class AgentCoordinator {
|
|
|
106121
107041
|
const have = new Set(issue2.labels.map((l) => l.toLowerCase()));
|
|
106122
107042
|
return !wantLabels.some((v) => have.has(v));
|
|
106123
107043
|
}
|
|
106124
|
-
async
|
|
106125
|
-
const
|
|
106126
|
-
|
|
106127
|
-
|
|
106128
|
-
|
|
106129
|
-
|
|
106130
|
-
|
|
106131
|
-
}
|
|
106132
|
-
|
|
106133
|
-
|
|
106134
|
-
|
|
106135
|
-
|
|
106136
|
-
|
|
106137
|
-
if (decision.firstBail) {
|
|
106138
|
-
this.deps.onLog(` ${issue2.identifier}: pr-tracker bailing after ${decision.attempts} recovery attempts (${reason}) \u2014 applying setError`, "red");
|
|
106139
|
-
emitCapture(this.bus, "agent_pr_tracker_bailed", {
|
|
106140
|
-
issue_identifier: issue2.identifier,
|
|
106141
|
-
reason,
|
|
106142
|
-
attempts: decision.attempts
|
|
106143
|
-
});
|
|
106144
|
-
if (this.opts.setError) {
|
|
106145
|
-
try {
|
|
106146
|
-
await this.deps.applyIndicator(issue2, this.opts.setError);
|
|
106147
|
-
} catch (err) {
|
|
106148
|
-
this.deps.onLog(`! Linear setError failed for ${issue2.identifier}: ${err.message}`, "yellow");
|
|
106149
|
-
}
|
|
107044
|
+
async quarantineBail(issue2, prUrl, reason, actor) {
|
|
107045
|
+
const attempts = actor.getSnapshot().context.data.recovery?.attempts ?? 0;
|
|
107046
|
+
this.deps.onLog(` ${issue2.identifier}: quarantined after ${attempts} recovery attempts (${reason}) \u2014 applying setError`, "red");
|
|
107047
|
+
emitCapture(this.bus, "agent_pr_tracker_bailed", {
|
|
107048
|
+
issue_identifier: issue2.identifier,
|
|
107049
|
+
reason,
|
|
107050
|
+
attempts
|
|
107051
|
+
});
|
|
107052
|
+
if (this.opts.setError) {
|
|
107053
|
+
try {
|
|
107054
|
+
await this.deps.applyIndicator(issue2, this.opts.setError);
|
|
107055
|
+
} catch (err) {
|
|
107056
|
+
this.deps.onLog(`! Linear setError failed for ${issue2.identifier}: ${err.message}`, "yellow");
|
|
106150
107057
|
}
|
|
106151
|
-
|
|
106152
|
-
|
|
106153
|
-
|
|
106154
|
-
|
|
106155
|
-
|
|
106156
|
-
|
|
106157
|
-
|
|
107058
|
+
}
|
|
107059
|
+
if (this.opts.postComments !== false) {
|
|
107060
|
+
const human = reason === "conflicting" ? "merge conflicts" : "failing CI";
|
|
107061
|
+
try {
|
|
107062
|
+
await this.deps.postComment(issue2, buildRalphyComment({
|
|
107063
|
+
type: "recovery-gaveup",
|
|
107064
|
+
action: "gave up auto-recovering PR",
|
|
107065
|
+
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.`,
|
|
107066
|
+
fields: { pr: extractPrNumber(prUrl) ?? prUrl, attempts }
|
|
107067
|
+
}));
|
|
107068
|
+
} catch (err) {
|
|
107069
|
+
this.deps.onLog(`! Linear bail comment failed for ${issue2.identifier}: ${err.message}`, "yellow");
|
|
106158
107070
|
}
|
|
106159
107071
|
}
|
|
106160
|
-
return true;
|
|
106161
107072
|
}
|
|
106162
107073
|
spawnNext() {
|
|
106163
107074
|
if (this.stopped)
|
|
@@ -106238,7 +107149,12 @@ class AgentCoordinator {
|
|
|
106238
107149
|
if (trigger === "review" && this.opts.postComments !== false) {
|
|
106239
107150
|
const sourceTag = mention ? mention.source === "github" ? " (GitHub @mention)" : mention.source === "github-review" ? " (GitHub code review)" : " (Linear @mention)" : "";
|
|
106240
107151
|
try {
|
|
106241
|
-
await this.deps.postComment(issue2,
|
|
107152
|
+
await this.deps.postComment(issue2, buildRalphyComment({
|
|
107153
|
+
type: "review-pickup",
|
|
107154
|
+
action: "picked up review comments",
|
|
107155
|
+
body: `Picked up new review comments${sourceTag}. Tracking change: \`${prep.changeName}\``,
|
|
107156
|
+
fields: { change: prep.changeName }
|
|
107157
|
+
}));
|
|
106242
107158
|
} catch (err) {
|
|
106243
107159
|
this.deps.onLog(`! Linear review comment failed for ${issue2.identifier}: ${err.message}`, "yellow");
|
|
106244
107160
|
}
|
|
@@ -106247,13 +107163,18 @@ class AgentCoordinator {
|
|
|
106247
107163
|
let alreadyPosted = false;
|
|
106248
107164
|
try {
|
|
106249
107165
|
const comments = await this.deps.fetchComments(issue2.id);
|
|
106250
|
-
alreadyPosted = comments.some((c) => c.body
|
|
107166
|
+
alreadyPosted = comments.some((c) => isStartedComment(c.body));
|
|
106251
107167
|
} catch (err) {
|
|
106252
107168
|
this.deps.onLog(`! Linear comment fetch failed for ${issue2.identifier}: ${err.message}`, "yellow");
|
|
106253
107169
|
}
|
|
106254
107170
|
if (!alreadyPosted) {
|
|
106255
107171
|
try {
|
|
106256
|
-
await this.deps.postComment(issue2,
|
|
107172
|
+
await this.deps.postComment(issue2, buildRalphyComment({
|
|
107173
|
+
type: "started",
|
|
107174
|
+
action: "started working",
|
|
107175
|
+
body: `Tracking change: \`${prep.changeName}\``,
|
|
107176
|
+
fields: { change: prep.changeName }
|
|
107177
|
+
}));
|
|
106257
107178
|
this.deps.onLog(` ${issue2.identifier}: posted "started" comment`, "gray");
|
|
106258
107179
|
} catch (err) {
|
|
106259
107180
|
this.deps.onLog(`! Linear comment failed for ${issue2.identifier}: ${err.message}`, "red");
|
|
@@ -106462,7 +107383,14 @@ class AgentCoordinator {
|
|
|
106462
107383
|
}
|
|
106463
107384
|
}
|
|
106464
107385
|
if (this.opts.postComments !== false) {
|
|
106465
|
-
const body = completionCommentBody({
|
|
107386
|
+
const body = completionCommentBody({
|
|
107387
|
+
noChanges,
|
|
107388
|
+
ok,
|
|
107389
|
+
trigger,
|
|
107390
|
+
changeName,
|
|
107391
|
+
code,
|
|
107392
|
+
reachedDone: exitActorState === "done"
|
|
107393
|
+
});
|
|
106466
107394
|
try {
|
|
106467
107395
|
await this.deps.postComment(issue2, body);
|
|
106468
107396
|
this.deps.onLog(` ${issue2.identifier}: posted completion comment`, "gray");
|
|
@@ -106556,18 +107484,22 @@ var emptyPrStatus = () => ({
|
|
|
106556
107484
|
},
|
|
106557
107485
|
prStatus: emptyPrStatus(),
|
|
106558
107486
|
phase: {},
|
|
106559
|
-
flow: {}
|
|
107487
|
+
flow: {},
|
|
107488
|
+
board: []
|
|
106560
107489
|
});
|
|
106561
107490
|
var init_coordinator = __esm(() => {
|
|
106562
107491
|
init_types2();
|
|
106563
107492
|
init_linear_client();
|
|
106564
107493
|
init_post_task();
|
|
107494
|
+
init_scaffold();
|
|
107495
|
+
init_task_pipeline();
|
|
106565
107496
|
init_queue_order();
|
|
106566
107497
|
init_src();
|
|
106567
107498
|
init_src2();
|
|
106568
107499
|
init_registry();
|
|
106569
107500
|
init_run_feature();
|
|
106570
107501
|
init_machines();
|
|
107502
|
+
init_src8();
|
|
106571
107503
|
});
|
|
106572
107504
|
|
|
106573
107505
|
// apps/agent/src/agent/coordinator.ts
|
|
@@ -106575,94 +107507,6 @@ var init_coordinator2 = __esm(() => {
|
|
|
106575
107507
|
init_coordinator();
|
|
106576
107508
|
});
|
|
106577
107509
|
|
|
106578
|
-
// apps/agent/src/agent/scaffold.ts
|
|
106579
|
-
import { join as join24 } from "path";
|
|
106580
|
-
function changeNameForIssue(issue2) {
|
|
106581
|
-
const slug = issue2.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 40).replace(/^-+|-+$/g, "");
|
|
106582
|
-
return slug ? `${issue2.identifier.toLowerCase()}-${slug}` : issue2.identifier.toLowerCase();
|
|
106583
|
-
}
|
|
106584
|
-
async function scaffoldChangeForIssue(tasksDir, statesDir, issue2, comments = [], appendPrompt = "", attachments = []) {
|
|
106585
|
-
const name = changeNameForIssue(issue2);
|
|
106586
|
-
const changeDir = join24(tasksDir, name);
|
|
106587
|
-
const stateDir = join24(statesDir, name);
|
|
106588
|
-
const commentsBlock = comments.length > 0 ? [
|
|
106589
|
-
"",
|
|
106590
|
-
"## Linear comments",
|
|
106591
|
-
"",
|
|
106592
|
-
...comments.flatMap((c) => [
|
|
106593
|
-
`**${c.user?.name ?? "unknown"}** \u2014 ${c.createdAt}`,
|
|
106594
|
-
"",
|
|
106595
|
-
c.body.trim(),
|
|
106596
|
-
""
|
|
106597
|
-
])
|
|
106598
|
-
] : [];
|
|
106599
|
-
const attachmentsBlock = attachments.length > 0 ? [
|
|
106600
|
-
"",
|
|
106601
|
-
"## Ticket Attachments",
|
|
106602
|
-
"",
|
|
106603
|
-
...attachments.map((a) => `- [${a.title ?? "Attachment"}](${a.url})`)
|
|
106604
|
-
] : [];
|
|
106605
|
-
const descriptionBody = issue2.description?.trim() || "_No description provided in Linear._";
|
|
106606
|
-
const proposal = [
|
|
106607
|
-
`# ${issue2.identifier}: ${issue2.title}`,
|
|
106608
|
-
"",
|
|
106609
|
-
`Source: [${issue2.identifier}](${issue2.url})`,
|
|
106610
|
-
`Status: ${issue2.state.name}`,
|
|
106611
|
-
issue2.assignee ? `Assignee: ${issue2.assignee.name}` : "",
|
|
106612
|
-
issue2.labels.length ? `Labels: ${issue2.labels.join(", ")}` : "",
|
|
106613
|
-
"",
|
|
106614
|
-
"## Why",
|
|
106615
|
-
"",
|
|
106616
|
-
descriptionBody,
|
|
106617
|
-
"",
|
|
106618
|
-
"## What Changes",
|
|
106619
|
-
"",
|
|
106620
|
-
"_Describe the concrete changes this proposal introduces (one bullet per change)._",
|
|
106621
|
-
...commentsBlock,
|
|
106622
|
-
...attachmentsBlock,
|
|
106623
|
-
...appendPrompt.trim() ? ["", "## Additional instructions", "", appendPrompt.trim()] : [],
|
|
106624
|
-
"",
|
|
106625
|
-
"## Steering",
|
|
106626
|
-
"",
|
|
106627
|
-
"_Add steering notes here as the loop runs._",
|
|
106628
|
-
""
|
|
106629
|
-
].filter((l) => l !== "").join(`
|
|
106630
|
-
`);
|
|
106631
|
-
const tasks = [
|
|
106632
|
-
`# Tasks for ${issue2.identifier}`,
|
|
106633
|
-
"",
|
|
106634
|
-
"## Planning",
|
|
106635
|
-
"",
|
|
106636
|
-
`- [ ] Read the Linear issue at ${issue2.url} and research the codebase to understand the mission and its scope`,
|
|
106637
|
-
`- [ ] Refine proposal.md with the problem statement, approach, and acceptance criteria derived from the research`,
|
|
106638
|
-
`- [ ] Fill in \`## Why\` and \`## What Changes\` in proposal.md so \`openspec validate\` passes (these sections are required by the validator)`,
|
|
106639
|
-
`- [ ] Add at least one spec delta under \`specs/<capability>/spec.md\` describing the behavior added/modified/removed by this change`,
|
|
106640
|
-
`- [ ] 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).`,
|
|
106641
|
-
`- [ ] 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.`,
|
|
106642
|
-
`- [ ] Is there anything else to add? Review the complete change context and document any additional edge cases, constraints, or open questions not captured above.`,
|
|
106643
|
-
""
|
|
106644
|
-
].join(`
|
|
106645
|
-
`);
|
|
106646
|
-
const design = [
|
|
106647
|
-
`# Design for ${issue2.identifier}`,
|
|
106648
|
-
"",
|
|
106649
|
-
"_Fill in the technical design as you work through the issue._",
|
|
106650
|
-
""
|
|
106651
|
-
].join(`
|
|
106652
|
-
`);
|
|
106653
|
-
await runCapability(fsChange.scaffold, {
|
|
106654
|
-
changeDir,
|
|
106655
|
-
stateDir,
|
|
106656
|
-
proposal,
|
|
106657
|
-
tasks,
|
|
106658
|
-
design
|
|
106659
|
-
});
|
|
106660
|
-
return name;
|
|
106661
|
-
}
|
|
106662
|
-
var init_scaffold = __esm(() => {
|
|
106663
|
-
init_fs_change();
|
|
106664
|
-
});
|
|
106665
|
-
|
|
106666
107510
|
// packages/core/src/detections/tasks.ts
|
|
106667
107511
|
function hasUnchecked(content) {
|
|
106668
107512
|
return /^- \[ \]/m.test(content);
|
|
@@ -106704,23 +107548,20 @@ function gateActive(inputs) {
|
|
|
106704
107548
|
}
|
|
106705
107549
|
|
|
106706
107550
|
// packages/core/src/detections/mention.ts
|
|
106707
|
-
function buildMentionAckComment(
|
|
106708
|
-
|
|
106709
|
-
`)[0];
|
|
106710
|
-
const truncated = firstLine.slice(0, 200);
|
|
106711
|
-
const excerpt = truncated + (truncated.length < firstLine.length ? "\u2026" : "");
|
|
106712
|
-
const greeting = author ? `\uD83D\uDC40 Got it, ${author}! I've picked up your mention and queued a review pass.` : `\uD83D\uDC40 Acknowledged! I've picked up your mention and queued a review pass.`;
|
|
106713
|
-
return `${greeting}
|
|
106714
|
-
|
|
106715
|
-
> ${excerpt}`;
|
|
107551
|
+
function buildMentionAckComment() {
|
|
107552
|
+
return buildRalphyMarker("mention-ack", { status: "handled" });
|
|
106716
107553
|
}
|
|
107554
|
+
var init_mention2 = __esm(() => {
|
|
107555
|
+
init_src8();
|
|
107556
|
+
});
|
|
106717
107557
|
// packages/core/src/detections/index.ts
|
|
106718
107558
|
var init_detections = __esm(() => {
|
|
106719
107559
|
init_phase2();
|
|
107560
|
+
init_mention2();
|
|
106720
107561
|
});
|
|
106721
107562
|
|
|
106722
107563
|
// apps/agent/src/features/confirmation/state.ts
|
|
106723
|
-
import { dirname as
|
|
107564
|
+
import { dirname as dirname9, join as join25 } from "path";
|
|
106724
107565
|
async function readInlineConfirmation(statePath) {
|
|
106725
107566
|
const f2 = Bun.file(statePath);
|
|
106726
107567
|
if (!await f2.exists())
|
|
@@ -106733,7 +107574,7 @@ async function readInlineConfirmation(statePath) {
|
|
|
106733
107574
|
}
|
|
106734
107575
|
}
|
|
106735
107576
|
async function readConfirmationState(statePath) {
|
|
106736
|
-
const changeDir =
|
|
107577
|
+
const changeDir = dirname9(statePath);
|
|
106737
107578
|
const sidecar = await readSlotSidecar(changeDir, "confirmation");
|
|
106738
107579
|
const existing = sidecar ?? await readInlineConfirmation(statePath) ?? null;
|
|
106739
107580
|
const confirmation = {
|
|
@@ -106749,7 +107590,7 @@ async function readConfirmationState(statePath) {
|
|
|
106749
107590
|
return { stateObj: {}, confirmation };
|
|
106750
107591
|
}
|
|
106751
107592
|
async function writeConfirmationState(statePath, _stateObj, confirmation) {
|
|
106752
|
-
await writeSlotField(
|
|
107593
|
+
await writeSlotField(dirname9(statePath), "confirmation", confirmation);
|
|
106753
107594
|
}
|
|
106754
107595
|
async function restartFromDesign(changeDir, changeName) {
|
|
106755
107596
|
const designStub = [
|
|
@@ -106839,7 +107680,17 @@ function buildMentionTaskBody(trigger, issueUrl) {
|
|
|
106839
107680
|
function findLastRalphPickupISO(comments) {
|
|
106840
107681
|
let latest = null;
|
|
106841
107682
|
for (const c of comments) {
|
|
106842
|
-
if (
|
|
107683
|
+
if (!isPickupComment(c.body))
|
|
107684
|
+
continue;
|
|
107685
|
+
if (latest === null || c.createdAt > latest)
|
|
107686
|
+
latest = c.createdAt;
|
|
107687
|
+
}
|
|
107688
|
+
return latest;
|
|
107689
|
+
}
|
|
107690
|
+
function findLastMentionAckISO(comments) {
|
|
107691
|
+
let latest = null;
|
|
107692
|
+
for (const c of comments) {
|
|
107693
|
+
if (!isMentionAckComment(c.body))
|
|
106843
107694
|
continue;
|
|
106844
107695
|
if (latest === null || c.createdAt > latest)
|
|
106845
107696
|
latest = c.createdAt;
|
|
@@ -106875,7 +107726,10 @@ function githubReactionSlug(emoji3) {
|
|
|
106875
107726
|
return emoji3;
|
|
106876
107727
|
}
|
|
106877
107728
|
}
|
|
106878
|
-
var init_task_bodies = () => {
|
|
107729
|
+
var init_task_bodies = __esm(() => {
|
|
107730
|
+
init_src8();
|
|
107731
|
+
init_ralph_comment();
|
|
107732
|
+
});
|
|
106879
107733
|
|
|
106880
107734
|
// apps/agent/src/features/confirmation/inspect.ts
|
|
106881
107735
|
function buildReviseRegex(handle) {
|
|
@@ -106902,7 +107756,12 @@ async function inspectAwaitingTicket(state, cfg, deps) {
|
|
|
106902
107756
|
if (!next.stuckPostedAt) {
|
|
106903
107757
|
if (cfg.postComments) {
|
|
106904
107758
|
try {
|
|
106905
|
-
await deps.postComment(
|
|
107759
|
+
await deps.postComment(buildRalphyComment({
|
|
107760
|
+
type: "confirmation-stuck",
|
|
107761
|
+
action: "confirmation gate stuck",
|
|
107762
|
+
body: `Confirmation gate stuck after ${next.rounds} revise round(s) ` + `(max ${cfg.maxConfirmationRounds}). Applying \`ralph:stuck\` \u2014 ` + `clear the label to retry, or apply the approval marker to proceed.`,
|
|
107763
|
+
fields: { rounds: next.rounds }
|
|
107764
|
+
}));
|
|
106906
107765
|
} catch (err) {
|
|
106907
107766
|
deps.log(`! plan-stuck comment failed: ${err.message}`, "yellow");
|
|
106908
107767
|
}
|
|
@@ -106947,7 +107806,12 @@ ${revise.reason}`);
|
|
|
106947
107806
|
}
|
|
106948
107807
|
if (cfg.postComments) {
|
|
106949
107808
|
try {
|
|
106950
|
-
await deps.postComment(
|
|
107809
|
+
await deps.postComment(buildRalphyComment({
|
|
107810
|
+
type: "revise-ack",
|
|
107811
|
+
action: "revise request acknowledged",
|
|
107812
|
+
body: `Revise request acknowledged \u2014 restarting at design (round ${next.rounds + 1}/${cfg.maxConfirmationRounds}).`,
|
|
107813
|
+
fields: { round: next.rounds + 1 }
|
|
107814
|
+
}));
|
|
106951
107815
|
} catch (err) {
|
|
106952
107816
|
deps.log(`! revise ack comment failed: ${err.message}`, "yellow");
|
|
106953
107817
|
}
|
|
@@ -106976,7 +107840,12 @@ ${revise.reason}`);
|
|
|
106976
107840
|
const limitMs = cfg.timeoutHours * 60 * 60 * 1000;
|
|
106977
107841
|
if (elapsedMs >= limitMs && cfg.postComments) {
|
|
106978
107842
|
try {
|
|
106979
|
-
await deps.postComment(
|
|
107843
|
+
await deps.postComment(buildRalphyComment({
|
|
107844
|
+
type: "confirmation-reminder",
|
|
107845
|
+
action: "awaiting confirmation",
|
|
107846
|
+
body: `Still awaiting confirmation on this plan (round ${next.rounds + 1}/${cfg.maxConfirmationRounds}). ` + `Approve to continue or reply \`${cfg.mentionHandle} revise: <reason>\` to send it back.`,
|
|
107847
|
+
fields: { round: next.rounds + 1 }
|
|
107848
|
+
}));
|
|
106980
107849
|
next.lastReminderAt = nowIso;
|
|
106981
107850
|
} catch (err) {
|
|
106982
107851
|
deps.log(`! reminder comment failed: ${err.message}`, "yellow");
|
|
@@ -106986,6 +107855,7 @@ ${revise.reason}`);
|
|
|
106986
107855
|
return { outcome: "stay-awaiting", next };
|
|
106987
107856
|
}
|
|
106988
107857
|
var init_inspect = __esm(() => {
|
|
107858
|
+
init_src8();
|
|
106989
107859
|
init_task_bodies();
|
|
106990
107860
|
});
|
|
106991
107861
|
|
|
@@ -107028,7 +107898,12 @@ async function postPlanReadyCommentOnce(issue2, statePath, changeName, deps) {
|
|
|
107028
107898
|
return;
|
|
107029
107899
|
const approvalSentence = describeApprovalMarker(deps.cfg.linear.indicators.getApproved);
|
|
107030
107900
|
const handle = deps.cfg.linear.mentionHandle;
|
|
107031
|
-
const body =
|
|
107901
|
+
const body = buildRalphyComment({
|
|
107902
|
+
type: "plan-ready",
|
|
107903
|
+
action: "plan ready",
|
|
107904
|
+
body: `Plan ready for \`${changeName}\` \u2014 review proposal.md / design.md / tasks.md ` + `and ${approvalSentence} to continue, ` + `or reply with \`${handle} revise: <reason>\` to send it back to design.`,
|
|
107905
|
+
fields: { change: changeName }
|
|
107906
|
+
});
|
|
107032
107907
|
try {
|
|
107033
107908
|
await addIssueComment(deps.apiKey, issue2.id, body);
|
|
107034
107909
|
} catch (err) {
|
|
@@ -107307,11 +108182,13 @@ async function processAwaitingForIssue(issue2, deps) {
|
|
|
107307
108182
|
}
|
|
107308
108183
|
var init_awaiting = __esm(() => {
|
|
107309
108184
|
init_layout();
|
|
108185
|
+
init_src8();
|
|
107310
108186
|
init_detections();
|
|
107311
108187
|
init_phase();
|
|
107312
108188
|
init_worktree();
|
|
107313
108189
|
init_scaffold();
|
|
107314
108190
|
init_linear();
|
|
108191
|
+
init_ralph_comment();
|
|
107315
108192
|
init_types2();
|
|
107316
108193
|
init_workflow();
|
|
107317
108194
|
init_state2();
|
|
@@ -107427,7 +108304,7 @@ function createOpenDraftPr(deps) {
|
|
|
107427
108304
|
if (!branch)
|
|
107428
108305
|
return null;
|
|
107429
108306
|
const base2 = baseBranchFromLabels(issue2.labels) ?? deps.prBaseBranch;
|
|
107430
|
-
const result2 = await create3({ cwd: cwd2, branch, issue: issue2, base: base2, draft: true }, deps.cmdRunner);
|
|
108307
|
+
const result2 = await create3({ cwd: cwd2, branch, issue: issue2, base: base2, draft: true, labels: deps.prLabels ?? [] }, deps.cmdRunner);
|
|
107431
108308
|
const url2 = result2?.url ?? null;
|
|
107432
108309
|
if (url2) {
|
|
107433
108310
|
deps.prByChange.set(changeName, url2);
|
|
@@ -107538,10 +108415,13 @@ function unionMarkers(...sets) {
|
|
|
107538
108415
|
}
|
|
107539
108416
|
return out;
|
|
107540
108417
|
}
|
|
107541
|
-
function describeIndicators(indicators, team, assignee, anyAssignee) {
|
|
108418
|
+
function describeIndicators(indicators, team, assignee, anyAssignee, requireAllLabels) {
|
|
107542
108419
|
const parts = [];
|
|
107543
108420
|
parts.push(`team=${team ?? "*"}`);
|
|
107544
108421
|
parts.push(`assignee=${anyAssignee ? "any" : assignee ?? "*"}`);
|
|
108422
|
+
if (requireAllLabels && requireAllLabels.length > 0) {
|
|
108423
|
+
parts.push(`labels=[${requireAllLabels.join(",")}]`);
|
|
108424
|
+
}
|
|
107545
108425
|
if (indicators.getTodo) {
|
|
107546
108426
|
parts.push(`todo=[${indicators.getTodo.filter.map((m) => `${m.type}:${m.value}`).join(",")}]`);
|
|
107547
108427
|
}
|
|
@@ -107561,7 +108441,7 @@ function createLinearResolvers(input) {
|
|
|
107561
108441
|
const stateCache = new Map;
|
|
107562
108442
|
const labelCache = new Map;
|
|
107563
108443
|
const teamIdCache = new Map;
|
|
107564
|
-
const teamKeyOf = (issue2) =>
|
|
108444
|
+
const teamKeyOf = (issue2) => linearIdentifierStrategy.scopeKey(issue2);
|
|
107565
108445
|
async function resolveStateId(issue2, name) {
|
|
107566
108446
|
const t = teamKeyOf(issue2);
|
|
107567
108447
|
let map3 = stateCache.get(t);
|
|
@@ -107757,6 +108637,201 @@ async function fetchDoneCandidatesWith(apiKey, team, assignee, anyAssignee, requ
|
|
|
107757
108637
|
var init_linear_resolvers = __esm(() => {
|
|
107758
108638
|
init_types2();
|
|
107759
108639
|
init_linear();
|
|
108640
|
+
init_identifier_strategy();
|
|
108641
|
+
});
|
|
108642
|
+
|
|
108643
|
+
// apps/agent/src/agent/wire/tracker/github.ts
|
|
108644
|
+
function identifierForNumber(n) {
|
|
108645
|
+
return `issue-${n}`;
|
|
108646
|
+
}
|
|
108647
|
+
function toLinearIssue(gh) {
|
|
108648
|
+
const open = (gh.state ?? "OPEN").toUpperCase() === "OPEN";
|
|
108649
|
+
return {
|
|
108650
|
+
id: String(gh.number),
|
|
108651
|
+
identifier: identifierForNumber(gh.number),
|
|
108652
|
+
title: gh.title,
|
|
108653
|
+
description: gh.body ?? null,
|
|
108654
|
+
url: gh.url,
|
|
108655
|
+
state: { name: open ? "Open" : "Closed", type: open ? "started" : "completed" },
|
|
108656
|
+
assignee: null,
|
|
108657
|
+
project: null,
|
|
108658
|
+
labels: (gh.labels ?? []).map((l) => l.name),
|
|
108659
|
+
priority: 0,
|
|
108660
|
+
createdAt: gh.createdAt ?? "",
|
|
108661
|
+
blockedByIds: []
|
|
108662
|
+
};
|
|
108663
|
+
}
|
|
108664
|
+
function labelValues(markers) {
|
|
108665
|
+
return markers.filter((m) => m.type === "label").map((m) => m.value);
|
|
108666
|
+
}
|
|
108667
|
+
function createGithubTrackerProvider(input) {
|
|
108668
|
+
const { cmdRunner, projectRoot, diag } = input;
|
|
108669
|
+
const statusLabels = input.issues?.statusLabels ?? DEFAULT_STATUS_LABELS;
|
|
108670
|
+
const todoLabel = input.issues?.label;
|
|
108671
|
+
const assignee = input.issues?.assignee;
|
|
108672
|
+
const configuredRepo = input.issues?.repo;
|
|
108673
|
+
let repoPromise = null;
|
|
108674
|
+
async function repo() {
|
|
108675
|
+
if (configuredRepo && configuredRepo.trim() !== "")
|
|
108676
|
+
return configuredRepo.trim();
|
|
108677
|
+
if (!repoPromise) {
|
|
108678
|
+
repoPromise = (async () => {
|
|
108679
|
+
try {
|
|
108680
|
+
const { stdout } = await cmdRunner.run(["gh", "repo", "view", "--json", "nameWithOwner", "-q", ".nameWithOwner"], projectRoot);
|
|
108681
|
+
const detected = stdout.trim();
|
|
108682
|
+
if (!detected)
|
|
108683
|
+
throw new Error("empty");
|
|
108684
|
+
diag("github-tracker", ` using detected GitHub repo ${detected}`, "gray");
|
|
108685
|
+
return detected;
|
|
108686
|
+
} catch (err) {
|
|
108687
|
+
throw new Error("github tracker: could not determine the repository \u2014 set " + "`github.issues.repo` (owner/name) in WORKFLOW.md or run inside a " + `repo with a GitHub 'origin' remote (${err.message})`);
|
|
108688
|
+
}
|
|
108689
|
+
})();
|
|
108690
|
+
}
|
|
108691
|
+
return repoPromise;
|
|
108692
|
+
}
|
|
108693
|
+
async function listIssues(args) {
|
|
108694
|
+
const r = await repo();
|
|
108695
|
+
const { stdout } = await cmdRunner.run([
|
|
108696
|
+
"gh",
|
|
108697
|
+
"issue",
|
|
108698
|
+
"list",
|
|
108699
|
+
"--repo",
|
|
108700
|
+
r,
|
|
108701
|
+
"--state",
|
|
108702
|
+
"open",
|
|
108703
|
+
"--json",
|
|
108704
|
+
"number,title,url,body,state,createdAt,labels",
|
|
108705
|
+
"--limit",
|
|
108706
|
+
"100",
|
|
108707
|
+
...args
|
|
108708
|
+
], projectRoot);
|
|
108709
|
+
const parsed = JSON.parse(stdout.trim() || "[]");
|
|
108710
|
+
return parsed.map(toLinearIssue);
|
|
108711
|
+
}
|
|
108712
|
+
async function fetchByGet(inc, excl) {
|
|
108713
|
+
if (!inc)
|
|
108714
|
+
return [];
|
|
108715
|
+
const include = !Array.isArray(inc) && "filter" in inc ? inc.filter : [];
|
|
108716
|
+
const wantLabels = labelValues(include);
|
|
108717
|
+
const args = [];
|
|
108718
|
+
for (const label of wantLabels)
|
|
108719
|
+
args.push("--label", label);
|
|
108720
|
+
if (assignee && assignee.trim() !== "")
|
|
108721
|
+
args.push("--assignee", assignee.trim());
|
|
108722
|
+
const issues = await listIssues(args);
|
|
108723
|
+
const excludeLabels = new Set(labelValues(excl));
|
|
108724
|
+
if (excludeLabels.size === 0)
|
|
108725
|
+
return issues;
|
|
108726
|
+
return issues.filter((issue2) => !issue2.labels.some((l) => excludeLabels.has(l)));
|
|
108727
|
+
}
|
|
108728
|
+
async function ghIssue(issueNumber, ...args) {
|
|
108729
|
+
const r = await repo();
|
|
108730
|
+
await cmdRunner.run(["gh", "issue", ...args, issueNumber, "--repo", r], projectRoot);
|
|
108731
|
+
}
|
|
108732
|
+
async function applyMarker(issue2, m) {
|
|
108733
|
+
if (m.type === "comment") {
|
|
108734
|
+
await ghIssue(issue2.id, "comment", "--body", m.value);
|
|
108735
|
+
diag("github-marker", ` \u2192 ${issue2.identifier} comment`, "gray");
|
|
108736
|
+
return;
|
|
108737
|
+
}
|
|
108738
|
+
if (m.type !== "label") {
|
|
108739
|
+
diag("github-marker", `! ${issue2.identifier}: '${m.type}' markers are not supported by the GitHub tracker \u2014 skipped`, "yellow");
|
|
108740
|
+
return;
|
|
108741
|
+
}
|
|
108742
|
+
await ghIssue(issue2.id, "edit", "--add-label", m.value);
|
|
108743
|
+
diag("github-marker", ` \u2192 ${issue2.identifier} +label='${m.value}'`, "gray");
|
|
108744
|
+
if (m.value === statusLabels.inProgress && todoLabel && todoLabel.trim() !== "") {
|
|
108745
|
+
await ghIssue(issue2.id, "edit", "--remove-label", todoLabel.trim());
|
|
108746
|
+
diag("github-marker", ` \u2192 ${issue2.identifier} -label='${todoLabel.trim()}'`, "gray");
|
|
108747
|
+
}
|
|
108748
|
+
if (m.value === statusLabels.done) {
|
|
108749
|
+
await ghIssue(issue2.id, "close");
|
|
108750
|
+
diag("github-marker", ` \u2192 ${issue2.identifier} closed`, "gray");
|
|
108751
|
+
}
|
|
108752
|
+
}
|
|
108753
|
+
async function applyIndicator(issue2, ind) {
|
|
108754
|
+
for (const m of markersOf(ind))
|
|
108755
|
+
await applyMarker(issue2, m);
|
|
108756
|
+
}
|
|
108757
|
+
async function removeIndicator(issue2, ind) {
|
|
108758
|
+
for (const m of markersOf(ind)) {
|
|
108759
|
+
if (m.type !== "label")
|
|
108760
|
+
continue;
|
|
108761
|
+
await ghIssue(issue2.id, "edit", "--remove-label", m.value);
|
|
108762
|
+
diag("github-marker", ` \u2192 ${issue2.identifier} -label='${m.value}'`, "gray");
|
|
108763
|
+
}
|
|
108764
|
+
}
|
|
108765
|
+
async function fetchDoneCandidates() {
|
|
108766
|
+
return listIssues(["--label", statusLabels.inProgress]);
|
|
108767
|
+
}
|
|
108768
|
+
async function resolveLabelIdForTeam() {
|
|
108769
|
+
return null;
|
|
108770
|
+
}
|
|
108771
|
+
return {
|
|
108772
|
+
fetchByGet,
|
|
108773
|
+
applyIndicator,
|
|
108774
|
+
removeIndicator,
|
|
108775
|
+
applyMarker,
|
|
108776
|
+
fetchDoneCandidates,
|
|
108777
|
+
resolveLabelIdForTeam
|
|
108778
|
+
};
|
|
108779
|
+
}
|
|
108780
|
+
function githubIndicators(issues) {
|
|
108781
|
+
const statusLabels = issues?.statusLabels ?? DEFAULT_STATUS_LABELS;
|
|
108782
|
+
const todoLabel = issues?.label?.trim();
|
|
108783
|
+
return {
|
|
108784
|
+
getTodo: { filter: todoLabel ? [{ type: "label", value: todoLabel }] : [] },
|
|
108785
|
+
getInProgress: { filter: [{ type: "label", value: statusLabels.inProgress }] },
|
|
108786
|
+
setInProgress: { type: "label", value: statusLabels.inProgress },
|
|
108787
|
+
setDone: { type: "label", value: statusLabels.done },
|
|
108788
|
+
setError: { type: "label", value: statusLabels.error }
|
|
108789
|
+
};
|
|
108790
|
+
}
|
|
108791
|
+
var DEFAULT_STATUS_LABELS;
|
|
108792
|
+
var init_github = __esm(() => {
|
|
108793
|
+
init_types2();
|
|
108794
|
+
DEFAULT_STATUS_LABELS = {
|
|
108795
|
+
inProgress: "ralph:in-progress",
|
|
108796
|
+
done: "ralph:done",
|
|
108797
|
+
error: "ralph:error"
|
|
108798
|
+
};
|
|
108799
|
+
});
|
|
108800
|
+
|
|
108801
|
+
// apps/agent/src/agent/wire/tracker/linear-tracker-provider.ts
|
|
108802
|
+
function createLinearTrackerProvider(input) {
|
|
108803
|
+
const {
|
|
108804
|
+
apiKey,
|
|
108805
|
+
team,
|
|
108806
|
+
assignee,
|
|
108807
|
+
anyAssignee,
|
|
108808
|
+
requireAllLabels,
|
|
108809
|
+
indicators,
|
|
108810
|
+
resolvers,
|
|
108811
|
+
fetchMentions,
|
|
108812
|
+
ticketNumbers
|
|
108813
|
+
} = input;
|
|
108814
|
+
const excludeFromTodo = unionMarkers(indicators.setDone, indicators.setError);
|
|
108815
|
+
const excludeFromInProgress = unionMarkers(indicators.setError);
|
|
108816
|
+
return {
|
|
108817
|
+
fetchTodo: () => resolvers.fetchByGet(indicators.getTodo, excludeFromTodo),
|
|
108818
|
+
fetchInProgress: () => resolvers.fetchByGet(indicators.getInProgress, excludeFromInProgress),
|
|
108819
|
+
fetchReview: () => resolvers.fetchByGet(indicators.getReview, []),
|
|
108820
|
+
fetchMentions,
|
|
108821
|
+
fetchDoneCandidates: () => fetchDoneCandidatesWith(apiKey, team, assignee, anyAssignee, requireAllLabels, indicators, ticketNumbers && ticketNumbers.length > 0 ? ticketNumbers : undefined),
|
|
108822
|
+
applyIndicator: resolvers.applyIndicator,
|
|
108823
|
+
removeIndicator: resolvers.removeIndicator,
|
|
108824
|
+
postComment: (issue2, body) => addIssueComment(apiKey, issue2.id, body),
|
|
108825
|
+
fetchComments: async (issueId) => {
|
|
108826
|
+
const c = await fetchIssueComments(apiKey, issueId);
|
|
108827
|
+
return c.map((x) => ({ body: x.body }));
|
|
108828
|
+
}
|
|
108829
|
+
};
|
|
108830
|
+
}
|
|
108831
|
+
var init_linear_tracker_provider = __esm(() => {
|
|
108832
|
+
init_linear();
|
|
108833
|
+
init_indicators();
|
|
108834
|
+
init_linear_resolvers();
|
|
107760
108835
|
});
|
|
107761
108836
|
|
|
107762
108837
|
// apps/agent/src/agent/wire/prepare.ts
|
|
@@ -107795,7 +108870,7 @@ function createPrepareHelpers(input) {
|
|
|
107795
108870
|
let scaffoldStatesDir = statesDir;
|
|
107796
108871
|
let branch = null;
|
|
107797
108872
|
if (!useWorktree)
|
|
107798
|
-
return { workerCwd, scaffoldTasksDir, scaffoldStatesDir, branch };
|
|
108873
|
+
return { workerCwd, scaffoldTasksDir, scaffoldStatesDir, branch, worktreeCreated: null };
|
|
107799
108874
|
const probeName = worktreeDirNameForIssue(issue2);
|
|
107800
108875
|
const baseBranch = baseBranchFromLabels(issue2.labels) ?? cfg.prBaseBranch;
|
|
107801
108876
|
let wt;
|
|
@@ -107824,10 +108899,10 @@ function createPrepareHelpers(input) {
|
|
|
107824
108899
|
} catch (err) {
|
|
107825
108900
|
diag("worktree", `! seeding .mcp.json failed for ${issue2.identifier}: ${err.message}`, "yellow");
|
|
107826
108901
|
}
|
|
107827
|
-
return { workerCwd, scaffoldTasksDir, scaffoldStatesDir, branch };
|
|
108902
|
+
return { workerCwd, scaffoldTasksDir, scaffoldStatesDir, branch, worktreeCreated: wt.created };
|
|
107828
108903
|
}
|
|
107829
108904
|
async function prepare(issue2) {
|
|
107830
|
-
const { workerCwd, scaffoldTasksDir, scaffoldStatesDir, branch } = await setupWorktree(issue2);
|
|
108905
|
+
const { workerCwd, scaffoldTasksDir, scaffoldStatesDir, branch, worktreeCreated } = await setupWorktree(issue2);
|
|
107831
108906
|
let changeName;
|
|
107832
108907
|
const wtLayoutPre = projectLayout(workerCwd);
|
|
107833
108908
|
const derivedName = changeNameForIssue(issue2);
|
|
@@ -107876,7 +108951,8 @@ function createPrepareHelpers(input) {
|
|
|
107876
108951
|
maps.issueByChange.set(changeName, issue2);
|
|
107877
108952
|
if (branch)
|
|
107878
108953
|
maps.branchByChange.set(changeName, branch);
|
|
107879
|
-
|
|
108954
|
+
const runSetup = worktreeCreated ?? isFresh;
|
|
108955
|
+
if (cfg.setupScript && runSetup) {
|
|
107880
108956
|
await runScript("setup", cfg.setupScript, workerCwd);
|
|
107881
108957
|
}
|
|
107882
108958
|
return {
|
|
@@ -108225,6 +109301,18 @@ function createPrDiscovery(input) {
|
|
|
108225
109301
|
} catch (err) {
|
|
108226
109302
|
diag("ci", `! gh pr checks ${prUrl} failed (PR scan): ${err.message}`, "yellow");
|
|
108227
109303
|
}
|
|
109304
|
+
try {
|
|
109305
|
+
const readiness = await getPollContext().fetchPrOnce(prUrl, ["isDraft", "reviewDecision"], cmdRunner, projectRoot);
|
|
109306
|
+
const isDraft = readiness.isDraft === true;
|
|
109307
|
+
const reviewDecision = readiness.reviewDecision?.toUpperCase();
|
|
109308
|
+
const awaitingApproval = reviewDecision === "REVIEW_REQUIRED" || reviewDecision === "CHANGES_REQUESTED";
|
|
109309
|
+
if (isDraft || awaitingApproval) {
|
|
109310
|
+
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");
|
|
109311
|
+
return { url: prUrl, status: "unknown" };
|
|
109312
|
+
}
|
|
109313
|
+
} catch (err) {
|
|
109314
|
+
diag("pr", `! gh pr view ${prUrl} readiness check failed (PR scan): ${err.message} \u2014 treating as ready`, "yellow");
|
|
109315
|
+
}
|
|
108228
109316
|
return { url: prUrl, status: "mergeable" };
|
|
108229
109317
|
}
|
|
108230
109318
|
async function resolvePrUrlForIssue(issue2) {
|
|
@@ -108264,17 +109352,17 @@ var init_pr_discovery = __esm(() => {
|
|
|
108264
109352
|
});
|
|
108265
109353
|
|
|
108266
109354
|
// apps/agent/src/features/review-followup/scan.ts
|
|
108267
|
-
import { dirname as
|
|
109355
|
+
import { dirname as dirname10, join as join28 } from "path";
|
|
108268
109356
|
async function resolveReviewStateDir(changeName, deps) {
|
|
108269
109357
|
const root = deps.cwdOf(changeName);
|
|
108270
109358
|
if (root)
|
|
108271
|
-
return
|
|
109359
|
+
return dirname10(projectLayout(root).stateFile(changeName));
|
|
108272
109360
|
if (!deps.useWorktree)
|
|
108273
|
-
return
|
|
109361
|
+
return dirname10(projectLayout(deps.projectRoot).stateFile(changeName));
|
|
108274
109362
|
const wtPath = join28(worktreesDir2(deps.projectRoot), changeName);
|
|
108275
109363
|
const statePath = projectLayout(wtPath).stateFile(changeName);
|
|
108276
109364
|
if (await Bun.file(statePath).exists())
|
|
108277
|
-
return
|
|
109365
|
+
return dirname10(statePath);
|
|
108278
109366
|
return null;
|
|
108279
109367
|
}
|
|
108280
109368
|
async function readReviewWatermark(stateDir) {
|
|
@@ -108371,7 +109459,12 @@ async function maybePingStaleReviewer(issue2, prUrl, state, newestReviewerActivi
|
|
|
108371
109459
|
if (!m)
|
|
108372
109460
|
return;
|
|
108373
109461
|
const [, owner, repo, num] = m;
|
|
108374
|
-
const body =
|
|
109462
|
+
const body = buildRalphyComment({
|
|
109463
|
+
type: "reviewer-ping",
|
|
109464
|
+
action: "nudging reviewer",
|
|
109465
|
+
body: `@${reviewer} \u2014 Ralph has been waiting ${elapsedH.toFixed(0)}h on a re-review for ${prUrl}. Could you take another look when you have a moment?`,
|
|
109466
|
+
fields: { reviewer }
|
|
109467
|
+
});
|
|
108375
109468
|
try {
|
|
108376
109469
|
await deps.cmdRunner.run(["gh", "api", `repos/${owner}/${repo}/issues/${num}/comments`, "-f", `body=${body}`], deps.projectRoot);
|
|
108377
109470
|
deps.stalePingedAt.set(prUrl, now2);
|
|
@@ -108437,6 +109530,7 @@ async function scanCodeReview(issue2, prUrl, lastRalphPickup, deps) {
|
|
|
108437
109530
|
var init_scan = __esm(() => {
|
|
108438
109531
|
init_layout();
|
|
108439
109532
|
init_store();
|
|
109533
|
+
init_src8();
|
|
108440
109534
|
init_scaffold();
|
|
108441
109535
|
init_worktree();
|
|
108442
109536
|
});
|
|
@@ -108486,7 +109580,7 @@ async function fetchPrIssueComments(cmdRunner, projectRoot, prUrl, onLog) {
|
|
|
108486
109580
|
return [];
|
|
108487
109581
|
}
|
|
108488
109582
|
}
|
|
108489
|
-
var
|
|
109583
|
+
var init_github2 = __esm(() => {
|
|
108490
109584
|
init_linear();
|
|
108491
109585
|
init_task_bodies();
|
|
108492
109586
|
});
|
|
@@ -108494,6 +109588,19 @@ var init_github = __esm(() => {
|
|
|
108494
109588
|
// apps/agent/src/agent/wire/mention-scan.ts
|
|
108495
109589
|
import { readdir as readdir2 } from "fs/promises";
|
|
108496
109590
|
import { join as join29 } from "path";
|
|
109591
|
+
function latestIso(...values2) {
|
|
109592
|
+
let latest = null;
|
|
109593
|
+
for (const value of values2) {
|
|
109594
|
+
if (value && (latest === null || value > latest))
|
|
109595
|
+
latest = value;
|
|
109596
|
+
}
|
|
109597
|
+
return latest;
|
|
109598
|
+
}
|
|
109599
|
+
function isAlreadyReactedError(err) {
|
|
109600
|
+
const e = err;
|
|
109601
|
+
const text = [...e?.messages ?? [], e?.message ?? ""].join(" ").toLowerCase();
|
|
109602
|
+
return text.includes("conflict on insert of reaction") || text.includes("already exists") || text.includes("already reacted");
|
|
109603
|
+
}
|
|
108497
109604
|
function createMentionScanner(input) {
|
|
108498
109605
|
const {
|
|
108499
109606
|
apiKey,
|
|
@@ -108555,13 +109662,14 @@ function createMentionScanner(input) {
|
|
|
108555
109662
|
for (const issue2 of candidates) {
|
|
108556
109663
|
const comments = issue2.comments ?? [];
|
|
108557
109664
|
const lastRalphPickup = findLastRalphPickupISO(comments);
|
|
109665
|
+
const linearMentionGate = latestIso(lastRalphPickup, findLastMentionAckISO(comments));
|
|
108558
109666
|
if (wantMention) {
|
|
108559
109667
|
for (const c of comments) {
|
|
108560
109668
|
if (isRalphComment(c.body))
|
|
108561
109669
|
continue;
|
|
108562
109670
|
if (!containsHandle(c.body, handle))
|
|
108563
109671
|
continue;
|
|
108564
|
-
if (
|
|
109672
|
+
if (linearMentionGate && c.createdAt <= linearMentionGate)
|
|
108565
109673
|
continue;
|
|
108566
109674
|
out.push({
|
|
108567
109675
|
issue: issue2,
|
|
@@ -108581,11 +109689,13 @@ function createMentionScanner(input) {
|
|
|
108581
109689
|
queued.add(issue2.id);
|
|
108582
109690
|
break;
|
|
108583
109691
|
}
|
|
108584
|
-
|
|
109692
|
+
if (!isAlreadyReactedError(err)) {
|
|
109693
|
+
diag("mention", `! mention scan: Linear reaction failed for ${issue2.identifier}: ${formatLinearError(err)}`, "yellow");
|
|
109694
|
+
}
|
|
108585
109695
|
}
|
|
108586
109696
|
if (cfg.linear.postComments !== false) {
|
|
108587
109697
|
try {
|
|
108588
|
-
await createIssueComment(apiKey, issue2.id, buildMentionAckComment(
|
|
109698
|
+
await createIssueComment(apiKey, issue2.id, buildMentionAckComment());
|
|
108589
109699
|
} catch (err) {
|
|
108590
109700
|
diag("mention", `! mention scan: ack comment failed for ${issue2.identifier}: ${formatLinearError(err)}`, "yellow");
|
|
108591
109701
|
}
|
|
@@ -108605,11 +109715,14 @@ function createMentionScanner(input) {
|
|
|
108605
109715
|
continue;
|
|
108606
109716
|
if (wantMention) {
|
|
108607
109717
|
const ghComments = await fetchPrIssueComments(cmdRunner, projectRoot, prUrl, onLog);
|
|
109718
|
+
const ghMentionGate = latestIso(lastRalphPickup, findLastMentionAckISO(ghComments));
|
|
108608
109719
|
const prMatch = /^https:\/\/github\.com\/([^/]+)\/([^/]+)\/pull\/\d+/.exec(prUrl);
|
|
108609
109720
|
for (const c of ghComments) {
|
|
109721
|
+
if (isRalphComment(c.body))
|
|
109722
|
+
continue;
|
|
108610
109723
|
if (!containsHandle(c.body, handle))
|
|
108611
109724
|
continue;
|
|
108612
|
-
if (
|
|
109725
|
+
if (ghMentionGate && c.createdAt <= ghMentionGate)
|
|
108613
109726
|
continue;
|
|
108614
109727
|
out.push({
|
|
108615
109728
|
issue: issue2,
|
|
@@ -108626,10 +109739,12 @@ function createMentionScanner(input) {
|
|
|
108626
109739
|
try {
|
|
108627
109740
|
await addGithubReactionToComment(cmdRunner, projectRoot, { owner, repo, kind: "issue" }, c.id, "\uD83D\uDC40");
|
|
108628
109741
|
} catch (err) {
|
|
108629
|
-
|
|
109742
|
+
if (!isAlreadyReactedError(err)) {
|
|
109743
|
+
diag("mention", `! mention scan: GitHub reaction failed for ${prUrl}: ${formatLinearError(err)}`, "yellow");
|
|
109744
|
+
}
|
|
108630
109745
|
}
|
|
108631
109746
|
if (cfg.linear.postComments !== false) {
|
|
108632
|
-
await postGithubPrComment(cmdRunner, projectRoot, prUrl, buildMentionAckComment(
|
|
109747
|
+
await postGithubPrComment(cmdRunner, projectRoot, prUrl, buildMentionAckComment(), onLog);
|
|
108633
109748
|
}
|
|
108634
109749
|
}
|
|
108635
109750
|
queued.add(issue2.id);
|
|
@@ -108680,7 +109795,7 @@ var init_mention_scan = __esm(() => {
|
|
|
108680
109795
|
init_detections();
|
|
108681
109796
|
init_scaffold();
|
|
108682
109797
|
init_scan();
|
|
108683
|
-
|
|
109798
|
+
init_github2();
|
|
108684
109799
|
init_task_bodies();
|
|
108685
109800
|
});
|
|
108686
109801
|
|
|
@@ -109044,6 +110159,7 @@ function buildPostTaskInput(input) {
|
|
|
109044
110159
|
finalizeNoOpAsDone: cfg.finalizeNoOpAsDone,
|
|
109045
110160
|
manualMergeWhenAutoMergeDisabled: cfg.manualMergeWhenAutoMergeDisabled,
|
|
109046
110161
|
prDraft: cfg.prDraft,
|
|
110162
|
+
prLabels: cfg.prLabels,
|
|
109047
110163
|
validateCommands: [cfg.commands.test, cfg.commands.lint, cfg.commands.typecheck].filter((c) => Boolean(c))
|
|
109048
110164
|
},
|
|
109049
110165
|
respawnWorker: input.respawnWorker
|
|
@@ -109634,7 +110750,7 @@ var init_linear_sync = __esm(() => {
|
|
|
109634
110750
|
});
|
|
109635
110751
|
|
|
109636
110752
|
// apps/agent/src/agent/linear-sync/comment-sync.ts
|
|
109637
|
-
import { dirname as
|
|
110753
|
+
import { dirname as dirname11, join as join34 } from "path";
|
|
109638
110754
|
async function readInlineLinearComments(statePath) {
|
|
109639
110755
|
const file2 = Bun.file(statePath);
|
|
109640
110756
|
if (!await file2.exists())
|
|
@@ -109647,7 +110763,7 @@ async function readInlineLinearComments(statePath) {
|
|
|
109647
110763
|
}
|
|
109648
110764
|
}
|
|
109649
110765
|
async function readComments(statePath) {
|
|
109650
|
-
const changeDir =
|
|
110766
|
+
const changeDir = dirname11(statePath);
|
|
109651
110767
|
const raw = await readSlotSidecar(changeDir, "linearComments") ?? await readInlineLinearComments(statePath) ?? {};
|
|
109652
110768
|
const r = raw;
|
|
109653
110769
|
return {
|
|
@@ -109660,7 +110776,7 @@ async function readComments(statePath) {
|
|
|
109660
110776
|
async function patchComments(statePath, patch) {
|
|
109661
110777
|
const current = await readComments(statePath);
|
|
109662
110778
|
const next = { ...current, ...patch };
|
|
109663
|
-
await writeSlotField(
|
|
110779
|
+
await writeSlotField(dirname11(statePath), "linearComments", next);
|
|
109664
110780
|
}
|
|
109665
110781
|
function isCommentNotFoundError(err) {
|
|
109666
110782
|
if (!err)
|
|
@@ -109688,7 +110804,12 @@ async function readTasksMd(changeDir, log3) {
|
|
|
109688
110804
|
}
|
|
109689
110805
|
}
|
|
109690
110806
|
function renderTasksCommentBody(tasksMd, changeName, iteration) {
|
|
109691
|
-
return
|
|
110807
|
+
return buildRalphyComment({
|
|
110808
|
+
type: "tasks",
|
|
110809
|
+
action: "task progress",
|
|
110810
|
+
body: renderTasksBlock(tasksMd, { changeName, iteration }),
|
|
110811
|
+
fields: { change: changeName, iter: iteration }
|
|
110812
|
+
});
|
|
109692
110813
|
}
|
|
109693
110814
|
async function postOrUpdateTasksComment(deps) {
|
|
109694
110815
|
const tasksMd = await readTasksMd(deps.changeDir, deps.log);
|
|
@@ -109799,8 +110920,13 @@ async function postPlanCommentOnce(deps) {
|
|
|
109799
110920
|
if (designSummary) {
|
|
109800
110921
|
parts.push("", "**Design**", "", designSummary);
|
|
109801
110922
|
}
|
|
109802
|
-
const body =
|
|
109803
|
-
|
|
110923
|
+
const body = buildRalphyComment({
|
|
110924
|
+
type: "plan",
|
|
110925
|
+
action: "plan",
|
|
110926
|
+
body: parts.join(`
|
|
110927
|
+
`),
|
|
110928
|
+
fields: { change: deps.changeName }
|
|
110929
|
+
});
|
|
109804
110930
|
let id;
|
|
109805
110931
|
try {
|
|
109806
110932
|
id = await deps.mutations.createIssueComment(deps.apiKey, deps.issueId, body);
|
|
@@ -109817,9 +110943,14 @@ async function postPlanCommentOnce(deps) {
|
|
|
109817
110943
|
}
|
|
109818
110944
|
async function postSteeringAndRefreshTasks(deps) {
|
|
109819
110945
|
const firstLine = deps.message.split(/\r?\n/, 1)[0].trim() || deps.message.trim();
|
|
109820
|
-
const steeringBody =
|
|
110946
|
+
const steeringBody = buildRalphyComment({
|
|
110947
|
+
type: "steering",
|
|
110948
|
+
action: "steering",
|
|
110949
|
+
body: `### ${STEERING_COMMENT_TITLE}
|
|
109821
110950
|
|
|
109822
|
-
${deps.message.trim()}
|
|
110951
|
+
${deps.message.trim()}`,
|
|
110952
|
+
fields: { change: deps.changeName }
|
|
110953
|
+
});
|
|
109823
110954
|
try {
|
|
109824
110955
|
await deps.mutations.createIssueComment(deps.apiKey, deps.issueId, steeringBody);
|
|
109825
110956
|
deps.log(` comment-sync: posted steering comment (${firstLine})`, "gray");
|
|
@@ -109852,6 +110983,7 @@ ${deps.message.trim()}`;
|
|
|
109852
110983
|
var PLAN_COMMENT_TITLE = "\uD83D\uDCCB Ralph plan", STEERING_COMMENT_TITLE = "\uD83E\uDDED Ralph steering";
|
|
109853
110984
|
var init_comment_sync = __esm(() => {
|
|
109854
110985
|
init_store();
|
|
110986
|
+
init_src8();
|
|
109855
110987
|
init_linear_sync();
|
|
109856
110988
|
});
|
|
109857
110989
|
|
|
@@ -261754,22 +262886,20 @@ function renderCodeBlock(doc2, token, indent) {
|
|
|
261754
262886
|
const text = token.text ?? "";
|
|
261755
262887
|
const x2 = MARGIN + indent;
|
|
261756
262888
|
const width = doc2.page.width - 2 * MARGIN - indent;
|
|
262889
|
+
const textWidth = width - 2 * CODE_PADDING_X;
|
|
261757
262890
|
doc2.font(FONT_MONO).fontSize(CODE_SIZE).fillColor(COLOR_TEXT);
|
|
261758
|
-
const lineHeight = doc2.currentLineHeight(true);
|
|
261759
262891
|
const lines = text.split(/\r?\n/);
|
|
261760
262892
|
doc2.y += CODE_PADDING_Y / 2;
|
|
261761
262893
|
for (const line of lines) {
|
|
261762
|
-
|
|
262894
|
+
const safe = toPdfSafe(line.length > 0 ? line : " ");
|
|
262895
|
+
const lineHeight = doc2.heightOfString(safe, { width: textWidth, lineBreak: true });
|
|
262896
|
+
if (doc2.y + lineHeight + CODE_PADDING_Y > doc2.page.height - MARGIN && doc2.y > doc2.page.margins.top) {
|
|
261763
262897
|
doc2.addPage();
|
|
261764
262898
|
}
|
|
261765
262899
|
const yTop = doc2.y;
|
|
261766
|
-
const safe = toPdfSafe(line);
|
|
261767
262900
|
doc2.rect(x2, yTop, width, lineHeight).fill(COLOR_CODE_BG);
|
|
261768
262901
|
doc2.fillColor(COLOR_TEXT);
|
|
261769
|
-
doc2.text(safe
|
|
261770
|
-
width: width - 2 * CODE_PADDING_X,
|
|
261771
|
-
lineBreak: false
|
|
261772
|
-
});
|
|
262902
|
+
doc2.text(safe, x2 + CODE_PADDING_X, yTop, { width: textWidth, lineBreak: true });
|
|
261773
262903
|
doc2.y = yTop + lineHeight;
|
|
261774
262904
|
}
|
|
261775
262905
|
doc2.y += CODE_PADDING_Y / 2;
|
|
@@ -261857,38 +262987,85 @@ function flattenInline(tokens, flags = {}) {
|
|
|
261857
262987
|
}
|
|
261858
262988
|
return out;
|
|
261859
262989
|
}
|
|
262990
|
+
function applyInlineStyle(doc2, run) {
|
|
262991
|
+
if (run.code) {
|
|
262992
|
+
doc2.font(FONT_MONO).fontSize(BODY_SIZE).fillColor(COLOR_INLINE_CODE_FG);
|
|
262993
|
+
return;
|
|
262994
|
+
}
|
|
262995
|
+
doc2.fontSize(BODY_SIZE).fillColor(COLOR_TEXT);
|
|
262996
|
+
if (run.bold && run.italic)
|
|
262997
|
+
doc2.font(FONT_BOLD_ITALIC);
|
|
262998
|
+
else if (run.bold)
|
|
262999
|
+
doc2.font(FONT_BOLD);
|
|
263000
|
+
else if (run.italic)
|
|
263001
|
+
doc2.font(FONT_ITALIC);
|
|
263002
|
+
else
|
|
263003
|
+
doc2.font(FONT_BODY);
|
|
263004
|
+
}
|
|
263005
|
+
function atomizeInline(flat) {
|
|
263006
|
+
const atoms = [];
|
|
263007
|
+
for (const run of flat) {
|
|
263008
|
+
const safe = toPdfSafe(run.text);
|
|
263009
|
+
for (const part of safe.split(/(\n|[ \t]+)/)) {
|
|
263010
|
+
if (part === "")
|
|
263011
|
+
continue;
|
|
263012
|
+
if (part === `
|
|
263013
|
+
`)
|
|
263014
|
+
atoms.push({ text: "", run, space: false, br: true });
|
|
263015
|
+
else if (/^[ \t]+$/.test(part))
|
|
263016
|
+
atoms.push({ text: part, run, space: true, br: false });
|
|
263017
|
+
else
|
|
263018
|
+
atoms.push({ text: part, run, space: false, br: false });
|
|
263019
|
+
}
|
|
263020
|
+
}
|
|
263021
|
+
return atoms;
|
|
263022
|
+
}
|
|
261860
263023
|
function emitInline(doc2, tokens, x2, width) {
|
|
261861
263024
|
const flat = flattenInline(tokens);
|
|
261862
263025
|
if (flat.length === 0)
|
|
261863
263026
|
return;
|
|
261864
|
-
|
|
261865
|
-
|
|
261866
|
-
|
|
261867
|
-
|
|
261868
|
-
|
|
261869
|
-
|
|
261870
|
-
|
|
261871
|
-
|
|
261872
|
-
|
|
261873
|
-
|
|
261874
|
-
|
|
261875
|
-
|
|
261876
|
-
|
|
261877
|
-
|
|
261878
|
-
|
|
261879
|
-
|
|
261880
|
-
|
|
261881
|
-
doc2.font(FONT_ITALIC);
|
|
261882
|
-
else
|
|
261883
|
-
doc2.font(FONT_BODY);
|
|
263027
|
+
const atoms = atomizeInline(flat);
|
|
263028
|
+
if (atoms.length === 0)
|
|
263029
|
+
return;
|
|
263030
|
+
doc2.font(FONT_BODY).fontSize(BODY_SIZE);
|
|
263031
|
+
const lineHeight = doc2.currentLineHeight(true);
|
|
263032
|
+
const right = x2 + width;
|
|
263033
|
+
const bottom = doc2.page.height - MARGIN;
|
|
263034
|
+
let cursorX = x2;
|
|
263035
|
+
let cursorY = doc2.y;
|
|
263036
|
+
let pendingSpace = 0;
|
|
263037
|
+
const newLine = () => {
|
|
263038
|
+
cursorX = x2;
|
|
263039
|
+
cursorY += lineHeight;
|
|
263040
|
+
pendingSpace = 0;
|
|
263041
|
+
if (cursorY + lineHeight > bottom) {
|
|
263042
|
+
doc2.addPage();
|
|
263043
|
+
cursorY = doc2.page.margins.top;
|
|
261884
263044
|
}
|
|
261885
|
-
|
|
261886
|
-
|
|
261887
|
-
|
|
263045
|
+
};
|
|
263046
|
+
for (const atom of atoms) {
|
|
263047
|
+
if (atom.br) {
|
|
263048
|
+
newLine();
|
|
263049
|
+
continue;
|
|
263050
|
+
}
|
|
263051
|
+
applyInlineStyle(doc2, atom.run);
|
|
263052
|
+
if (atom.space) {
|
|
263053
|
+
if (cursorX > x2)
|
|
263054
|
+
pendingSpace += doc2.widthOfString(atom.text);
|
|
263055
|
+
continue;
|
|
263056
|
+
}
|
|
263057
|
+
const wordWidth = doc2.widthOfString(atom.text);
|
|
263058
|
+
if (cursorX > x2 && cursorX + pendingSpace + wordWidth > right + 0.01) {
|
|
263059
|
+
newLine();
|
|
261888
263060
|
} else {
|
|
261889
|
-
|
|
263061
|
+
cursorX += pendingSpace;
|
|
263062
|
+
pendingSpace = 0;
|
|
261890
263063
|
}
|
|
263064
|
+
applyInlineStyle(doc2, atom.run);
|
|
263065
|
+
doc2.text(atom.text, cursorX, cursorY, { lineBreak: false, continued: false });
|
|
263066
|
+
cursorX += wordWidth;
|
|
261891
263067
|
}
|
|
263068
|
+
doc2.y = cursorY + lineHeight;
|
|
261892
263069
|
doc2.font(FONT_BODY).fontSize(BODY_SIZE).fillColor(COLOR_TEXT);
|
|
261893
263070
|
}
|
|
261894
263071
|
function plainInline(tokens) {
|
|
@@ -262068,7 +263245,7 @@ var init_render_pdf = __esm(() => {
|
|
|
262068
263245
|
});
|
|
262069
263246
|
|
|
262070
263247
|
// apps/agent/src/agent/linear-sync/spec-attachments.ts
|
|
262071
|
-
import { dirname as
|
|
263248
|
+
import { dirname as dirname12, join as join35 } from "path";
|
|
262072
263249
|
function describeLinearError(err) {
|
|
262073
263250
|
const e = err;
|
|
262074
263251
|
const parts = [e.message ?? String(err)];
|
|
@@ -262083,7 +263260,7 @@ function describeLinearError(err) {
|
|
|
262083
263260
|
return parts.join(" ");
|
|
262084
263261
|
}
|
|
262085
263262
|
function stateDirOf(statePath) {
|
|
262086
|
-
return
|
|
263263
|
+
return dirname12(statePath);
|
|
262087
263264
|
}
|
|
262088
263265
|
async function readInlineSpecAttachments(statePath) {
|
|
262089
263266
|
const file2 = Bun.file(statePath);
|
|
@@ -262101,7 +263278,7 @@ async function readInlineSpecAttachments(statePath) {
|
|
|
262101
263278
|
}
|
|
262102
263279
|
}
|
|
262103
263280
|
async function readSpecAttachmentsSubtree(statePath) {
|
|
262104
|
-
const sidecar = await readSlotSidecar(
|
|
263281
|
+
const sidecar = await readSlotSidecar(dirname12(statePath), "specAttachments");
|
|
262105
263282
|
return sidecar ?? await readInlineSpecAttachments(statePath);
|
|
262106
263283
|
}
|
|
262107
263284
|
function asRevisions(value) {
|
|
@@ -262593,105 +263770,8 @@ var init_comment_sync2 = __esm(() => {
|
|
|
262593
263770
|
init_linear();
|
|
262594
263771
|
});
|
|
262595
263772
|
|
|
262596
|
-
// apps/agent/src/features/pr-tracker/state.ts
|
|
262597
|
-
import { join as join36 } from "path";
|
|
262598
|
-
async function readState2(projectRoot) {
|
|
262599
|
-
const path = join36(projectRoot, PR_TRACKER_STATE_RELPATH);
|
|
262600
|
-
const file2 = Bun.file(path);
|
|
262601
|
-
if (!await file2.exists())
|
|
262602
|
-
return {};
|
|
262603
|
-
try {
|
|
262604
|
-
const raw = await file2.text();
|
|
262605
|
-
const parsed = JSON.parse(raw);
|
|
262606
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
262607
|
-
return parsed;
|
|
262608
|
-
}
|
|
262609
|
-
return {};
|
|
262610
|
-
} catch {
|
|
262611
|
-
return {};
|
|
262612
|
-
}
|
|
262613
|
-
}
|
|
262614
|
-
async function writeState2(projectRoot, state) {
|
|
262615
|
-
const path = join36(projectRoot, PR_TRACKER_STATE_RELPATH);
|
|
262616
|
-
await Bun.write(path, JSON.stringify(state, null, 2));
|
|
262617
|
-
}
|
|
262618
|
-
var PR_TRACKER_STATE_RELPATH = ".ralph/pr-tracker-state.json";
|
|
262619
|
-
var init_state3 = () => {};
|
|
262620
|
-
|
|
262621
|
-
// apps/agent/src/features/pr-tracker/tracker.ts
|
|
262622
|
-
class PrTracker {
|
|
262623
|
-
opts;
|
|
262624
|
-
state = {};
|
|
262625
|
-
loaded = false;
|
|
262626
|
-
now;
|
|
262627
|
-
constructor(opts) {
|
|
262628
|
-
this.opts = opts;
|
|
262629
|
-
this.now = opts.now ?? (() => new Date);
|
|
262630
|
-
}
|
|
262631
|
-
async load() {
|
|
262632
|
-
if (this.loaded)
|
|
262633
|
-
return;
|
|
262634
|
-
this.state = await readState2(this.opts.projectRoot);
|
|
262635
|
-
this.loaded = true;
|
|
262636
|
-
}
|
|
262637
|
-
snapshot() {
|
|
262638
|
-
return JSON.parse(JSON.stringify(this.state));
|
|
262639
|
-
}
|
|
262640
|
-
isBailed(identifier) {
|
|
262641
|
-
return this.state[identifier]?.bailed === true;
|
|
262642
|
-
}
|
|
262643
|
-
getAttempts(identifier) {
|
|
262644
|
-
return this.state[identifier]?.attempts ?? 0;
|
|
262645
|
-
}
|
|
262646
|
-
async recordFailure(identifier, reason) {
|
|
262647
|
-
await this.load();
|
|
262648
|
-
const nowIso = this.now().toISOString();
|
|
262649
|
-
const existing = this.state[identifier];
|
|
262650
|
-
if (existing?.bailed) {
|
|
262651
|
-
existing.lastReason = reason;
|
|
262652
|
-
await this.flush();
|
|
262653
|
-
return { kind: "bail", attempts: existing.attempts, firstBail: false };
|
|
262654
|
-
}
|
|
262655
|
-
const attempts = (existing?.attempts ?? 0) + 1;
|
|
262656
|
-
const entry = {
|
|
262657
|
-
attempts,
|
|
262658
|
-
firstFailedAt: existing?.firstFailedAt ?? nowIso,
|
|
262659
|
-
lastDemotedAt: nowIso,
|
|
262660
|
-
lastReason: reason
|
|
262661
|
-
};
|
|
262662
|
-
if (attempts >= this.opts.maxRecoveryAttempts) {
|
|
262663
|
-
entry.bailed = true;
|
|
262664
|
-
this.state[identifier] = entry;
|
|
262665
|
-
await this.flush();
|
|
262666
|
-
return { kind: "bail", attempts, firstBail: true };
|
|
262667
|
-
}
|
|
262668
|
-
this.state[identifier] = entry;
|
|
262669
|
-
await this.flush();
|
|
262670
|
-
return { kind: "demote", attempts };
|
|
262671
|
-
}
|
|
262672
|
-
async clear(identifier) {
|
|
262673
|
-
await this.load();
|
|
262674
|
-
if (!(identifier in this.state))
|
|
262675
|
-
return;
|
|
262676
|
-
delete this.state[identifier];
|
|
262677
|
-
await this.flush();
|
|
262678
|
-
}
|
|
262679
|
-
async flush() {
|
|
262680
|
-
await writeState2(this.opts.projectRoot, this.state);
|
|
262681
|
-
}
|
|
262682
|
-
}
|
|
262683
|
-
var init_tracker = __esm(() => {
|
|
262684
|
-
init_state3();
|
|
262685
|
-
});
|
|
262686
|
-
|
|
262687
|
-
// apps/agent/src/features/pr-tracker/index.ts
|
|
262688
|
-
var init_pr_tracker = __esm(() => {
|
|
262689
|
-
init_tracker();
|
|
262690
|
-
init_state3();
|
|
262691
|
-
});
|
|
262692
|
-
|
|
262693
263773
|
// apps/agent/src/agent/wire.ts
|
|
262694
|
-
import { join as
|
|
263774
|
+
import { join as join36 } from "path";
|
|
262695
263775
|
function buildAgentCoordinator(input) {
|
|
262696
263776
|
const {
|
|
262697
263777
|
args,
|
|
@@ -262710,7 +263790,7 @@ function buildAgentCoordinator(input) {
|
|
|
262710
263790
|
onWorkerCmd,
|
|
262711
263791
|
onAwaitingTicket
|
|
262712
263792
|
} = input;
|
|
262713
|
-
const logsDir =
|
|
263793
|
+
const logsDir = join36(projectRoot, ".ralph", "logs");
|
|
262714
263794
|
const bus = createBus();
|
|
262715
263795
|
subscribeAgentDiag(bus, onLog);
|
|
262716
263796
|
const diag = (area, message, color) => {
|
|
@@ -262718,11 +263798,12 @@ function buildAgentCoordinator(input) {
|
|
|
262718
263798
|
};
|
|
262719
263799
|
const concurrency = args.concurrency || cfg.concurrency;
|
|
262720
263800
|
const pollInterval = args.pollInterval || cfg.pollIntervalSeconds;
|
|
262721
|
-
const
|
|
263801
|
+
const isGithubTracker = cfg.tracker.kind === "github";
|
|
263802
|
+
const indicators = isGithubTracker ? githubIndicators(cfg.github?.issues) : mergeIndicators(cfg.linear.indicators, args.indicators);
|
|
262722
263803
|
const team = args.linearTeam || cfg.linear.team;
|
|
262723
263804
|
const { assignee, anyAssignee, requireAllLabels } = resolveLinearFilter(applyAssigneeOverride(cfg.linear.filter, args.linearAssignee));
|
|
262724
263805
|
const ticketNumbers = resolveTicketNumbers(args.ticketTokens, team);
|
|
262725
|
-
const excludeFromTodo = unionMarkers(indicators.setDone, indicators.setError);
|
|
263806
|
+
const excludeFromTodo = isGithubTracker ? unionMarkers(indicators.setDone, indicators.setError, indicators.setInProgress) : unionMarkers(indicators.setDone, indicators.setError);
|
|
262726
263807
|
const gitRunner = input.runners?.git ?? bunGitRunner;
|
|
262727
263808
|
const cmdRunner = input.runners?.cmd ?? bunCmdRunner;
|
|
262728
263809
|
const cwdByChange = new Map;
|
|
@@ -262757,7 +263838,7 @@ function buildAgentCoordinator(input) {
|
|
|
262757
263838
|
}
|
|
262758
263839
|
return code;
|
|
262759
263840
|
});
|
|
262760
|
-
const resolvers = createLinearResolvers({
|
|
263841
|
+
const resolvers = isGithubTracker ? null : createLinearResolvers({
|
|
262761
263842
|
apiKey,
|
|
262762
263843
|
team,
|
|
262763
263844
|
assignee,
|
|
@@ -262766,6 +263847,15 @@ function buildAgentCoordinator(input) {
|
|
|
262766
263847
|
diag,
|
|
262767
263848
|
...ticketNumbers.length > 0 ? { ticketNumbers } : {}
|
|
262768
263849
|
});
|
|
263850
|
+
const provider = isGithubTracker ? createGithubTrackerProvider({
|
|
263851
|
+
issues: cfg.github?.issues,
|
|
263852
|
+
cmdRunner,
|
|
263853
|
+
projectRoot,
|
|
263854
|
+
diag
|
|
263855
|
+
}) : {
|
|
263856
|
+
...resolvers,
|
|
263857
|
+
fetchDoneCandidates: () => fetchDoneCandidatesWith(apiKey, team, assignee, anyAssignee, requireAllLabels, indicators, ticketNumbers.length > 0 ? ticketNumbers : undefined)
|
|
263858
|
+
};
|
|
262769
263859
|
if (ticketNumbers.length > 0) {
|
|
262770
263860
|
const hasGetIndicator = [indicators.getTodo, indicators.getInProgress].some((ind) => ind && ind.filter.length > 0);
|
|
262771
263861
|
if (!hasGetIndicator) {
|
|
@@ -262796,7 +263886,7 @@ function buildAgentCoordinator(input) {
|
|
|
262796
263886
|
scriptRunner,
|
|
262797
263887
|
...input.runners?.worktree ? { worktreeProvider: input.runners.worktree } : {}
|
|
262798
263888
|
});
|
|
262799
|
-
const fetchMentions = createMentionScanner({
|
|
263889
|
+
const fetchMentions = isGithubTracker ? async () => [] : createMentionScanner({
|
|
262800
263890
|
apiKey,
|
|
262801
263891
|
args,
|
|
262802
263892
|
cfg,
|
|
@@ -262816,6 +263906,27 @@ function buildAgentCoordinator(input) {
|
|
|
262816
263906
|
lastHandledReviewActivity,
|
|
262817
263907
|
resolvePrUrlForIssue: prDiscovery.resolvePrUrlForIssue
|
|
262818
263908
|
});
|
|
263909
|
+
const tracker = isGithubTracker ? {
|
|
263910
|
+
fetchTodo: () => provider.fetchByGet(indicators.getTodo, excludeFromTodo),
|
|
263911
|
+
fetchInProgress: () => provider.fetchByGet(indicators.getInProgress, unionMarkers(indicators.setError)),
|
|
263912
|
+
fetchReview: async () => [],
|
|
263913
|
+
fetchMentions,
|
|
263914
|
+
fetchDoneCandidates: () => provider.fetchDoneCandidates(),
|
|
263915
|
+
applyIndicator: provider.applyIndicator,
|
|
263916
|
+
removeIndicator: provider.removeIndicator,
|
|
263917
|
+
postComment: (issue2, body) => provider.applyMarker(issue2, { type: "comment", value: body }),
|
|
263918
|
+
fetchComments: async () => []
|
|
263919
|
+
} : createLinearTrackerProvider({
|
|
263920
|
+
apiKey,
|
|
263921
|
+
team,
|
|
263922
|
+
assignee,
|
|
263923
|
+
anyAssignee,
|
|
263924
|
+
requireAllLabels,
|
|
263925
|
+
indicators,
|
|
263926
|
+
resolvers,
|
|
263927
|
+
fetchMentions,
|
|
263928
|
+
...ticketNumbers.length > 0 ? { ticketNumbers } : {}
|
|
263929
|
+
});
|
|
262819
263930
|
const spawnWorker = createSpawnWorker({
|
|
262820
263931
|
args,
|
|
262821
263932
|
cfg,
|
|
@@ -262827,7 +263938,7 @@ function buildAgentCoordinator(input) {
|
|
|
262827
263938
|
indicators,
|
|
262828
263939
|
cmdRunner,
|
|
262829
263940
|
gitRunner,
|
|
262830
|
-
applyIndicator:
|
|
263941
|
+
applyIndicator: provider.applyIndicator,
|
|
262831
263942
|
bus,
|
|
262832
263943
|
onLog,
|
|
262833
263944
|
diag,
|
|
@@ -262859,6 +263970,7 @@ function buildAgentCoordinator(input) {
|
|
|
262859
263970
|
prByChange,
|
|
262860
263971
|
cmdRunner,
|
|
262861
263972
|
prBaseBranch: cfg.prBaseBranch,
|
|
263973
|
+
prLabels: cfg.prLabels,
|
|
262862
263974
|
invalidatePrUrlForIssue: (issueId) => prDiscovery.invalidatePrUrlForIssue(issueId)
|
|
262863
263975
|
});
|
|
262864
263976
|
const confirmationCaps = {
|
|
@@ -262871,8 +263983,8 @@ function buildAgentCoordinator(input) {
|
|
|
262871
263983
|
cwdOf: (cn) => cwdByChange.get(cn),
|
|
262872
263984
|
awaitingChangeSet,
|
|
262873
263985
|
reapForAwaiting: (cn) => coordRef.current?.reapForAwaiting(cn),
|
|
262874
|
-
applyIndicator:
|
|
262875
|
-
applyMarker:
|
|
263986
|
+
applyIndicator: provider.applyIndicator,
|
|
263987
|
+
applyMarker: provider.applyMarker,
|
|
262876
263988
|
openDraftPr,
|
|
262877
263989
|
...onAwaitingTicket ? { onAwaitingTicket } : {},
|
|
262878
263990
|
onLog
|
|
@@ -262898,11 +264010,7 @@ function buildAgentCoordinator(input) {
|
|
|
262898
264010
|
};
|
|
262899
264011
|
}
|
|
262900
264012
|
const prRecoveryEnabled = args.prRecoveryEnabled === undefined ? cfg.prRecovery.enabled : args.prRecoveryEnabled;
|
|
262901
|
-
const
|
|
262902
|
-
projectRoot,
|
|
262903
|
-
maxRecoveryAttempts: cfg.prRecovery.maxRecoverySessions
|
|
262904
|
-
}) : null;
|
|
262905
|
-
const commentSync = createCommentSyncHooks({
|
|
264013
|
+
const commentSync = isGithubTracker ? { enabled: false } : createCommentSyncHooks({
|
|
262906
264014
|
apiKey,
|
|
262907
264015
|
cfg,
|
|
262908
264016
|
projectRoot,
|
|
@@ -262915,20 +264023,18 @@ function buildAgentCoordinator(input) {
|
|
|
262915
264023
|
beforePoll: () => {
|
|
262916
264024
|
pollContext = new PollContext;
|
|
262917
264025
|
},
|
|
262918
|
-
fetchTodo:
|
|
262919
|
-
fetchInProgress:
|
|
262920
|
-
fetchMentions,
|
|
262921
|
-
fetchDoneCandidates:
|
|
264026
|
+
fetchTodo: tracker.fetchTodo,
|
|
264027
|
+
fetchInProgress: tracker.fetchInProgress,
|
|
264028
|
+
fetchMentions: tracker.fetchMentions,
|
|
264029
|
+
fetchDoneCandidates: tracker.fetchDoneCandidates,
|
|
264030
|
+
fetchReview: tracker.fetchReview,
|
|
262922
264031
|
prepare: prep.prepare,
|
|
262923
264032
|
prepareTaskForTrigger: prep.prepareTaskForTrigger,
|
|
262924
264033
|
spawnWorker,
|
|
262925
|
-
applyIndicator:
|
|
262926
|
-
removeIndicator:
|
|
262927
|
-
postComment:
|
|
262928
|
-
fetchComments:
|
|
262929
|
-
const c = await fetchIssueComments(apiKey, issueId);
|
|
262930
|
-
return c.map((x2) => ({ body: x2.body }));
|
|
262931
|
-
},
|
|
264034
|
+
applyIndicator: tracker.applyIndicator,
|
|
264035
|
+
removeIndicator: tracker.removeIndicator,
|
|
264036
|
+
postComment: tracker.postComment,
|
|
264037
|
+
fetchComments: tracker.fetchComments,
|
|
262932
264038
|
checkPrStatus: prDiscovery.checkPrStatus,
|
|
262933
264039
|
hasPrForChange: (changeName) => prByChange.has(changeName),
|
|
262934
264040
|
isChangeArchivedForIssue: (issue2) => isChangeArchivedForIssue(issue2, cwdByChange, projectRoot),
|
|
@@ -262949,7 +264055,7 @@ function buildAgentCoordinator(input) {
|
|
|
262949
264055
|
const changeDir = projectLayout(root).changeDir(changeName);
|
|
262950
264056
|
const parts = [];
|
|
262951
264057
|
for (const name of ["tasks.md", "proposal.md", "design.md"]) {
|
|
262952
|
-
const file2 = Bun.file(
|
|
264058
|
+
const file2 = Bun.file(join36(changeDir, name));
|
|
262953
264059
|
if (!await file2.exists())
|
|
262954
264060
|
continue;
|
|
262955
264061
|
parts.push(`${name}:${file2.lastModified}:${file2.size}`);
|
|
@@ -262968,15 +264074,15 @@ function buildAgentCoordinator(input) {
|
|
|
262968
264074
|
commentEveryIterations: cfg.linear.updateEveryIterations,
|
|
262969
264075
|
...args.maxTickets > 0 ? { maxTickets: args.maxTickets } : {},
|
|
262970
264076
|
createsPrs: args.createPr || cfg.createPrOnSuccess,
|
|
262971
|
-
...prTracker ? { prTracker } : {},
|
|
262972
264077
|
prRecovery: {
|
|
262973
264078
|
enabled: prRecoveryEnabled,
|
|
262974
264079
|
fixCi: cfg.prRecovery.fixCi,
|
|
262975
|
-
fixConflicts: cfg.prRecovery.fixConflicts
|
|
264080
|
+
fixConflicts: cfg.prRecovery.fixConflicts,
|
|
264081
|
+
maxRecoverySessions: cfg.prRecovery.maxRecoverySessions
|
|
262976
264082
|
}
|
|
262977
264083
|
});
|
|
262978
264084
|
coordRef.current = coord;
|
|
262979
|
-
const filterDesc = describeIndicators(indicators, team, assignee, anyAssignee);
|
|
264085
|
+
const filterDesc = describeIndicators(indicators, team, assignee, anyAssignee, requireAllLabels);
|
|
262980
264086
|
const runBaselineGateOnce = createBaselineGateRunner({
|
|
262981
264087
|
args,
|
|
262982
264088
|
cfg,
|
|
@@ -262987,7 +264093,7 @@ function buildAgentCoordinator(input) {
|
|
|
262987
264093
|
gitRunner,
|
|
262988
264094
|
coord,
|
|
262989
264095
|
onLog,
|
|
262990
|
-
resolveLabelIdForTeam:
|
|
264096
|
+
resolveLabelIdForTeam: provider.resolveLabelIdForTeam
|
|
262991
264097
|
});
|
|
262992
264098
|
return {
|
|
262993
264099
|
coord,
|
|
@@ -262996,26 +264102,13 @@ function buildAgentCoordinator(input) {
|
|
|
262996
264102
|
pollInterval,
|
|
262997
264103
|
getWorkerCwd: (changeName) => cwdByChange.get(changeName),
|
|
262998
264104
|
syncTasksEnabled: commentSync.enabled,
|
|
262999
|
-
runBaselineGate: runBaselineGateOnce
|
|
263000
|
-
getGaveUpTotal: async () => {
|
|
263001
|
-
let total = 0;
|
|
263002
|
-
for (const [changeName, root] of cwdByChange) {
|
|
263003
|
-
const file2 = Bun.file(join37(projectLayout(root).taskStateDir(changeName), GAVEUP_COUNT_FILE));
|
|
263004
|
-
if (!await file2.exists())
|
|
263005
|
-
continue;
|
|
263006
|
-
try {
|
|
263007
|
-
total += Number.parseInt(await file2.text(), 10) || 0;
|
|
263008
|
-
} catch {}
|
|
263009
|
-
}
|
|
263010
|
-
return total;
|
|
263011
|
-
}
|
|
264105
|
+
runBaselineGate: runBaselineGateOnce
|
|
263012
264106
|
};
|
|
263013
264107
|
}
|
|
263014
264108
|
var init_wire = __esm(() => {
|
|
263015
264109
|
init_workflow();
|
|
263016
264110
|
init_src2();
|
|
263017
264111
|
init_coordinator2();
|
|
263018
|
-
init_linear();
|
|
263019
264112
|
init_layout();
|
|
263020
264113
|
init_scaffold();
|
|
263021
264114
|
init_awaiting();
|
|
@@ -263024,6 +264117,8 @@ var init_wire = __esm(() => {
|
|
|
263024
264117
|
init_indicators();
|
|
263025
264118
|
init_task_bodies();
|
|
263026
264119
|
init_linear_resolvers();
|
|
264120
|
+
init_github();
|
|
264121
|
+
init_linear_tracker_provider();
|
|
263027
264122
|
init_linear_client();
|
|
263028
264123
|
init_prepare();
|
|
263029
264124
|
init_pr_discovery();
|
|
@@ -263031,18 +264126,17 @@ var init_wire = __esm(() => {
|
|
|
263031
264126
|
init_worker();
|
|
263032
264127
|
init_baseline();
|
|
263033
264128
|
init_comment_sync2();
|
|
263034
|
-
init_pr_tracker();
|
|
263035
264129
|
});
|
|
263036
264130
|
|
|
263037
264131
|
// apps/agent/src/agent/json-log/json-log-file.ts
|
|
263038
|
-
import { mkdir as mkdir11, appendFile as
|
|
263039
|
-
import { dirname as
|
|
264132
|
+
import { mkdir as mkdir11, appendFile as appendFile3 } from "fs/promises";
|
|
264133
|
+
import { dirname as dirname13 } from "path";
|
|
263040
264134
|
function createJsonLogFileSink(path) {
|
|
263041
264135
|
if (!path)
|
|
263042
264136
|
return { emit: () => {} };
|
|
263043
264137
|
let chain = (async () => {
|
|
263044
264138
|
try {
|
|
263045
|
-
await mkdir11(
|
|
264139
|
+
await mkdir11(dirname13(path), { recursive: true });
|
|
263046
264140
|
await Bun.write(path, "");
|
|
263047
264141
|
} catch {}
|
|
263048
264142
|
})();
|
|
@@ -263052,7 +264146,7 @@ function createJsonLogFileSink(path) {
|
|
|
263052
264146
|
`;
|
|
263053
264147
|
chain = chain.then(async () => {
|
|
263054
264148
|
try {
|
|
263055
|
-
await
|
|
264149
|
+
await appendFile3(path, line);
|
|
263056
264150
|
} catch {}
|
|
263057
264151
|
});
|
|
263058
264152
|
}
|
|
@@ -263288,7 +264382,7 @@ var init_output_utils = __esm(() => {
|
|
|
263288
264382
|
});
|
|
263289
264383
|
|
|
263290
264384
|
// apps/agent/src/agent/state/worker-state-poll.ts
|
|
263291
|
-
import { join as
|
|
264385
|
+
import { join as join37 } from "path";
|
|
263292
264386
|
function parseSubtasks(tasksMd) {
|
|
263293
264387
|
const out = [];
|
|
263294
264388
|
let skipSection = false;
|
|
@@ -263321,7 +264415,7 @@ function initialWorkerSnapshot() {
|
|
|
263321
264415
|
async function readWorkerSnapshot(input) {
|
|
263322
264416
|
const next = { ...input.prev };
|
|
263323
264417
|
try {
|
|
263324
|
-
const file2 = Bun.file(
|
|
264418
|
+
const file2 = Bun.file(join37(input.statesDir, input.changeName, ".ralph-state.json"));
|
|
263325
264419
|
if (await file2.exists()) {
|
|
263326
264420
|
const json2 = await file2.json();
|
|
263327
264421
|
next.iter = json2.iteration ?? next.iter;
|
|
@@ -263330,10 +264424,10 @@ async function readWorkerSnapshot(input) {
|
|
|
263330
264424
|
} catch {}
|
|
263331
264425
|
if (input.changeDir) {
|
|
263332
264426
|
try {
|
|
263333
|
-
const tasksFile = Bun.file(
|
|
263334
|
-
const proposalFile = Bun.file(
|
|
263335
|
-
const designFile = Bun.file(
|
|
263336
|
-
const reviewFindingsFile = Bun.file(
|
|
264427
|
+
const tasksFile = Bun.file(join37(input.changeDir, "tasks.md"));
|
|
264428
|
+
const proposalFile = Bun.file(join37(input.changeDir, "proposal.md"));
|
|
264429
|
+
const designFile = Bun.file(join37(input.changeDir, "design.md"));
|
|
264430
|
+
const reviewFindingsFile = Bun.file(join37(input.changeDir, "review-findings.md"));
|
|
263337
264431
|
const [tasksText, proposalText, designText, reviewFindingsText] = await Promise.all([
|
|
263338
264432
|
tasksFile.exists().then((ok) => ok ? tasksFile.text() : null),
|
|
263339
264433
|
proposalFile.exists().then((ok) => ok ? proposalFile.text() : null),
|
|
@@ -263396,7 +264490,7 @@ var init_worker_state_poll = __esm(() => {
|
|
|
263396
264490
|
});
|
|
263397
264491
|
|
|
263398
264492
|
// apps/agent/src/components/AgentMode.tsx
|
|
263399
|
-
import { join as
|
|
264493
|
+
import { join as join38 } from "path";
|
|
263400
264494
|
async function appendSteeringImpl(changeDir, message) {
|
|
263401
264495
|
await runWithContext(createDefaultContext(), async () => {
|
|
263402
264496
|
appendSteeringMessage(changeDir, message);
|
|
@@ -263413,16 +264507,6 @@ function orderSubtasksForCappedDisplay(subtasks) {
|
|
|
263413
264507
|
(s.done ? done : pending).push(s);
|
|
263414
264508
|
return [...pending, ...done];
|
|
263415
264509
|
}
|
|
263416
|
-
function pickLatestGatedTicket(tickets) {
|
|
263417
|
-
if (tickets.size === 0)
|
|
263418
|
-
return { top: null, moreCount: 0 };
|
|
263419
|
-
const sorted = Array.from(tickets.entries()).sort(([, a], [, b2]) => {
|
|
263420
|
-
const aTime = a.since ? new Date(a.since).getTime() : 0;
|
|
263421
|
-
const bTime = b2.since ? new Date(b2.since).getTime() : 0;
|
|
263422
|
-
return bTime - aTime;
|
|
263423
|
-
});
|
|
263424
|
-
return { top: sorted[0], moreCount: sorted.length - 1 };
|
|
263425
|
-
}
|
|
263426
264510
|
function fmtCmd(argv) {
|
|
263427
264511
|
const joined = argv.join(" ");
|
|
263428
264512
|
return joined.length > CMD_DISPLAY_MAX ? joined.slice(0, CMD_DISPLAY_MAX - 1) + "\u2026" : joined;
|
|
@@ -263518,20 +264602,6 @@ function Link({ url: url2, label, color }) {
|
|
|
263518
264602
|
}, undefined, false, undefined, this)
|
|
263519
264603
|
}, undefined, false, undefined, this);
|
|
263520
264604
|
}
|
|
263521
|
-
function priorityBadge(p) {
|
|
263522
|
-
switch (p) {
|
|
263523
|
-
case 1:
|
|
263524
|
-
return { text: "\u25B2", color: "red", label: "URGENT" };
|
|
263525
|
-
case 2:
|
|
263526
|
-
return { text: "\u2191", color: "yellow", label: "HIGH" };
|
|
263527
|
-
case 3:
|
|
263528
|
-
return { text: "\xB7", color: "blue", label: "MED" };
|
|
263529
|
-
case 4:
|
|
263530
|
-
return { text: "\u2193", color: "gray", label: "LOW" };
|
|
263531
|
-
default:
|
|
263532
|
-
return { text: " ", color: "gray", label: "" };
|
|
263533
|
-
}
|
|
263534
|
-
}
|
|
263535
264605
|
function modeBadge(mode) {
|
|
263536
264606
|
switch (mode) {
|
|
263537
264607
|
case "fresh":
|
|
@@ -263608,14 +264678,52 @@ function workerBorderColor(phase2) {
|
|
|
263608
264678
|
return "gray";
|
|
263609
264679
|
}
|
|
263610
264680
|
}
|
|
263611
|
-
function
|
|
263612
|
-
|
|
263613
|
-
|
|
263614
|
-
|
|
263615
|
-
|
|
263616
|
-
|
|
263617
|
-
|
|
263618
|
-
|
|
264681
|
+
function focusedCardTailLines(termHeight, fixedOverhead) {
|
|
264682
|
+
return Math.max(3, termHeight - fixedOverhead);
|
|
264683
|
+
}
|
|
264684
|
+
function glyphColor(status) {
|
|
264685
|
+
switch (status) {
|
|
264686
|
+
case "done":
|
|
264687
|
+
return "green";
|
|
264688
|
+
case "current":
|
|
264689
|
+
return "cyan";
|
|
264690
|
+
case "pending":
|
|
264691
|
+
return "gray";
|
|
264692
|
+
case "failed":
|
|
264693
|
+
return "red";
|
|
264694
|
+
case "bailed":
|
|
264695
|
+
return "magenta";
|
|
264696
|
+
}
|
|
264697
|
+
}
|
|
264698
|
+
function PipelineCells({
|
|
264699
|
+
glyphs
|
|
264700
|
+
}) {
|
|
264701
|
+
return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
264702
|
+
children: PIPELINE_NODES.map((node2, i) => {
|
|
264703
|
+
const isHeader = glyphs === null;
|
|
264704
|
+
const status = isHeader ? null : glyphs[i];
|
|
264705
|
+
const content = isHeader ? NODE_LABELS[node2] : STATUS_GLYPH[status];
|
|
264706
|
+
return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
264707
|
+
children: [
|
|
264708
|
+
i > 0 && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264709
|
+
dimColor: true,
|
|
264710
|
+
children: PIPELINE_CONNECTOR
|
|
264711
|
+
}, undefined, false, undefined, this),
|
|
264712
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
264713
|
+
width: NODE_CELL_WIDTH,
|
|
264714
|
+
justifyContent: "center",
|
|
264715
|
+
children: isHeader ? /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264716
|
+
dimColor: true,
|
|
264717
|
+
children: content
|
|
264718
|
+
}, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264719
|
+
color: glyphColor(status),
|
|
264720
|
+
children: content
|
|
264721
|
+
}, undefined, false, undefined, this)
|
|
264722
|
+
}, undefined, false, undefined, this)
|
|
264723
|
+
]
|
|
264724
|
+
}, node2, true, undefined, this);
|
|
264725
|
+
})
|
|
264726
|
+
}, undefined, false, undefined, this);
|
|
263619
264727
|
}
|
|
263620
264728
|
function AgentMode({
|
|
263621
264729
|
args,
|
|
@@ -263649,24 +264757,19 @@ function AgentMode({
|
|
|
263649
264757
|
}, [awaitingClose]);
|
|
263650
264758
|
const [, setTick] = import_react63.useState(0);
|
|
263651
264759
|
const [clock, setClock] = import_react63.useState(0);
|
|
263652
|
-
const [
|
|
264760
|
+
const [focusedId, setFocusedId] = import_react63.useState(null);
|
|
263653
264761
|
const [showPendingTasks, setShowPendingTasks] = import_react63.useState(false);
|
|
263654
264762
|
const [showAllSubtasks, setShowAllSubtasks] = import_react63.useState(false);
|
|
263655
|
-
const [gaveUpCount, setGaveUpCount] = import_react63.useState(0);
|
|
263656
264763
|
const coordRef = import_react63.useRef(null);
|
|
263657
264764
|
const workerMetaRef = import_react63.useRef(new Map);
|
|
263658
|
-
const gatedTicketsRef = import_react63.useRef(new Map);
|
|
263659
264765
|
const nextPollAtRef = import_react63.useRef(0);
|
|
263660
264766
|
const cfgRef = import_react63.useRef(null);
|
|
263661
264767
|
const [effective, setEffective] = import_react63.useState(null);
|
|
263662
264768
|
const [pollStatus, setPollStatus] = import_react63.useState({
|
|
263663
264769
|
state: "idle",
|
|
263664
|
-
lastFound: null,
|
|
263665
|
-
lastAdded: null,
|
|
263666
264770
|
lastAt: null,
|
|
263667
264771
|
filterDesc: "",
|
|
263668
|
-
|
|
263669
|
-
lastPrStatus: null
|
|
264772
|
+
lastBoard: []
|
|
263670
264773
|
});
|
|
263671
264774
|
function appendLog(text, color, workerLogFile) {
|
|
263672
264775
|
setLogs((prev) => [...prev, { id: nextId(), text, color }]);
|
|
@@ -263702,7 +264805,7 @@ function AgentMode({
|
|
|
263702
264805
|
setFatalExit(2);
|
|
263703
264806
|
return;
|
|
263704
264807
|
}
|
|
263705
|
-
const { coord: coord2, filterDesc, concurrency, pollInterval, runBaselineGate: runBaselineGate2
|
|
264808
|
+
const { coord: coord2, filterDesc, concurrency, pollInterval, runBaselineGate: runBaselineGate2 } = buildCoordinator({
|
|
263706
264809
|
args,
|
|
263707
264810
|
cfg: cfg2,
|
|
263708
264811
|
projectRoot,
|
|
@@ -263809,13 +264912,6 @@ function AgentMode({
|
|
|
263809
264912
|
since: info.since,
|
|
263810
264913
|
round: info.round
|
|
263811
264914
|
});
|
|
263812
|
-
gatedTicketsRef.current.set(info.changeName, {
|
|
263813
|
-
issueIdentifier: info.issueIdentifier,
|
|
263814
|
-
issueUrl: info.issueUrl,
|
|
263815
|
-
issueTitle: info.issueTitle,
|
|
263816
|
-
since: info.since,
|
|
263817
|
-
round: info.round
|
|
263818
|
-
});
|
|
263819
264915
|
}
|
|
263820
264916
|
});
|
|
263821
264917
|
setEffective({ concurrency, pollInterval });
|
|
@@ -263843,28 +264939,18 @@ function AgentMode({
|
|
|
263843
264939
|
}
|
|
263844
264940
|
if (cancelled)
|
|
263845
264941
|
return;
|
|
263846
|
-
|
|
263847
|
-
const { found, added, buckets, prStatus } = await coord2.pollOnce();
|
|
264942
|
+
const { found, added, buckets, prStatus, board: board2 } = await coord2.pollOnce();
|
|
263848
264943
|
if (cancelled)
|
|
263849
264944
|
return;
|
|
263850
264945
|
fileEmit({ type: "poll_done", found, added, buckets, prStatus });
|
|
263851
|
-
getGaveUpTotal().then((total) => {
|
|
263852
|
-
if (!cancelled)
|
|
263853
|
-
setGaveUpCount(total);
|
|
263854
|
-
}).catch(() => {
|
|
263855
|
-
return;
|
|
263856
|
-
});
|
|
263857
264946
|
if (added > 0) {
|
|
263858
264947
|
appendLog(` ${added} new issue${added === 1 ? "" : "s"} queued (found ${found} open)`);
|
|
263859
264948
|
}
|
|
263860
264949
|
setPollStatus({
|
|
263861
264950
|
state: "idle",
|
|
263862
|
-
lastFound: found,
|
|
263863
|
-
lastAdded: added,
|
|
263864
264951
|
lastAt: Date.now(),
|
|
263865
264952
|
filterDesc,
|
|
263866
|
-
|
|
263867
|
-
lastPrStatus: prStatus
|
|
264953
|
+
lastBoard: board2
|
|
263868
264954
|
});
|
|
263869
264955
|
nextPollAtRef.current = Date.now() + pollInterval * 1000;
|
|
263870
264956
|
pollTimer = setTimeout(tick, pollInterval * 1000);
|
|
@@ -263979,10 +265065,21 @@ function AgentMode({
|
|
|
263979
265065
|
const spinnerFrame = SPINNER_FRAMES[clock % SPINNER_FRAMES.length];
|
|
263980
265066
|
const now2 = Date.now();
|
|
263981
265067
|
const secsToNextPoll = nextPollAtRef.current ? Math.max(0, Math.ceil((nextPollAtRef.current - now2) / 1000)) : null;
|
|
265068
|
+
const pollState = pollStatus.state === "polling" ? "polling\u2026" : pollStatus.lastAt !== null ? "idle" : "starting\u2026";
|
|
265069
|
+
const tasksLiveness = `${pollState}${secsToNextPoll !== null ? ` \xB7 ${secsToNextPoll}s \u21BB` : ""}`;
|
|
263982
265070
|
const activeCount = coord?.activeCount ?? 0;
|
|
263983
265071
|
const termWidth = columns - 2;
|
|
263984
265072
|
const termHeight = rows;
|
|
263985
|
-
const
|
|
265073
|
+
const board = pollStatus.lastBoard;
|
|
265074
|
+
const tree = buildBoardTree(board);
|
|
265075
|
+
const focusedIndex = (() => {
|
|
265076
|
+
if (tree.length === 0)
|
|
265077
|
+
return -1;
|
|
265078
|
+
const i = tree.findIndex((t) => t.row.id === focusedId);
|
|
265079
|
+
return i >= 0 ? i : 0;
|
|
265080
|
+
})();
|
|
265081
|
+
const focusedRow = focusedIndex >= 0 ? tree[focusedIndex].row : undefined;
|
|
265082
|
+
const focusedWorker = focusedRow ? coordRef.current?.activeWorkers.find((w2) => w2.issueId === focusedRow.id) : undefined;
|
|
263986
265083
|
const steeringFocusedRef = import_react63.useRef(false);
|
|
263987
265084
|
const steeringBufferRef = import_react63.useRef("");
|
|
263988
265085
|
const steeringCursorRef = import_react63.useRef(0);
|
|
@@ -264000,26 +265097,23 @@ function AgentMode({
|
|
|
264000
265097
|
setShowPendingTasks((v2) => !v2);
|
|
264001
265098
|
return;
|
|
264002
265099
|
}
|
|
264003
|
-
if (
|
|
265100
|
+
if (tree.length === 0)
|
|
264004
265101
|
return;
|
|
264005
|
-
|
|
264006
|
-
|
|
264007
|
-
|
|
264008
|
-
|
|
265102
|
+
const idx = focusedIndex < 0 ? 0 : focusedIndex;
|
|
265103
|
+
if (key.tab || key.downArrow) {
|
|
265104
|
+
setFocusedId(tree[(idx + 1) % tree.length].row.id);
|
|
265105
|
+
} else if (key.upArrow) {
|
|
265106
|
+
setFocusedId(tree[(idx - 1 + tree.length) % tree.length].row.id);
|
|
264009
265107
|
} else {
|
|
264010
265108
|
const n = parseInt(input, 10);
|
|
264011
|
-
if (!isNaN(n) && n >= 1 && n <=
|
|
264012
|
-
|
|
264013
|
-
}
|
|
264014
|
-
}, { isActive: isRawModeSupported &&
|
|
264015
|
-
const
|
|
264016
|
-
const steeringActive = isRawModeSupported && activeCount > 0 && focusedWorker !== undefined;
|
|
264017
|
-
const nonFocusedCount = Math.max(0, activeCount - 1);
|
|
264018
|
-
const tasksBoxLines = activeCount > 1 ? 5 : 0;
|
|
265109
|
+
if (!isNaN(n) && n >= 1 && n <= Math.min(9, tree.length))
|
|
265110
|
+
setFocusedId(tree[n - 1].row.id);
|
|
265111
|
+
}
|
|
265112
|
+
}, { isActive: isRawModeSupported && board.length > 0 });
|
|
265113
|
+
const steeringActive = isRawModeSupported && focusedWorker !== undefined;
|
|
264019
265114
|
const steeringBoxLines = steeringActive ? 3 : 0;
|
|
264020
|
-
const FIXED_OVERHEAD = 5 +
|
|
264021
|
-
const focusedTailLines =
|
|
264022
|
-
const compactTailLines = displayTailLines(activeCount);
|
|
265115
|
+
const FIXED_OVERHEAD = 5 + (4 + board.length) + 8 + steeringBoxLines;
|
|
265116
|
+
const focusedTailLines = focusedCardTailLines(termHeight, FIXED_OVERHEAD);
|
|
264023
265117
|
if (preflightError) {
|
|
264024
265118
|
return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
264025
265119
|
flexDirection: "column",
|
|
@@ -264173,14 +265267,7 @@ function AgentMode({
|
|
|
264173
265267
|
cfg.useWorktree && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264174
265268
|
color: "green",
|
|
264175
265269
|
children: " \u25CF worktree"
|
|
264176
|
-
}, undefined, false, undefined, this)
|
|
264177
|
-
gaveUpCount > 0 && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264178
|
-
color: "red",
|
|
264179
|
-
children: [
|
|
264180
|
-
" \u2502 gave-up \xD7",
|
|
264181
|
-
gaveUpCount
|
|
264182
|
-
]
|
|
264183
|
-
}, undefined, true, undefined, this)
|
|
265270
|
+
}, undefined, false, undefined, this)
|
|
264184
265271
|
]
|
|
264185
265272
|
}, undefined, true, undefined, this)
|
|
264186
265273
|
]
|
|
@@ -264207,418 +265294,196 @@ function AgentMode({
|
|
|
264207
265294
|
})()
|
|
264208
265295
|
]
|
|
264209
265296
|
}, undefined, true, undefined, this),
|
|
264210
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
264211
|
-
flexDirection: "row",
|
|
264212
|
-
gap: 1,
|
|
264213
|
-
marginTop: 0,
|
|
264214
|
-
width: termWidth,
|
|
264215
|
-
children: [
|
|
264216
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(LabeledBox, {
|
|
264217
|
-
label: "POLL STATUS",
|
|
264218
|
-
borderColor: "gray",
|
|
264219
|
-
width: termWidth - 17,
|
|
264220
|
-
paddingX: 1,
|
|
264221
|
-
flexDirection: "column",
|
|
264222
|
-
children: [
|
|
264223
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
264224
|
-
gap: 2,
|
|
264225
|
-
children: [
|
|
264226
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264227
|
-
color: "gray",
|
|
264228
|
-
children: spinnerFrame
|
|
264229
|
-
}, undefined, false, undefined, this),
|
|
264230
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264231
|
-
children: pollStatus.state === "polling" ? "Polling Linear\u2026" : pollStatus.lastAt !== null ? "Idle" : "Starting\u2026"
|
|
264232
|
-
}, undefined, false, undefined, this),
|
|
264233
|
-
pollStatus.lastAt !== null && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(jsx_dev_runtime11.Fragment, {
|
|
264234
|
-
children: pollStatus.lastBuckets && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(jsx_dev_runtime11.Fragment, {
|
|
264235
|
-
children: [
|
|
264236
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264237
|
-
dimColor: true,
|
|
264238
|
-
children: "\u2502"
|
|
264239
|
-
}, undefined, false, undefined, this),
|
|
264240
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264241
|
-
dimColor: true,
|
|
264242
|
-
children: "todo"
|
|
264243
|
-
}, undefined, false, undefined, this),
|
|
264244
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264245
|
-
color: "white",
|
|
264246
|
-
children: pollStatus.lastBuckets.todo
|
|
264247
|
-
}, undefined, false, undefined, this),
|
|
264248
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264249
|
-
dimColor: true,
|
|
264250
|
-
children: "\xB7"
|
|
264251
|
-
}, undefined, false, undefined, this),
|
|
264252
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264253
|
-
dimColor: true,
|
|
264254
|
-
children: "resume"
|
|
264255
|
-
}, undefined, false, undefined, this),
|
|
264256
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264257
|
-
color: pollStatus.lastBuckets.inProgress > 0 ? "cyan" : "white",
|
|
264258
|
-
children: pollStatus.lastBuckets.inProgress
|
|
264259
|
-
}, undefined, false, undefined, this),
|
|
264260
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264261
|
-
dimColor: true,
|
|
264262
|
-
children: "\xB7"
|
|
264263
|
-
}, undefined, false, undefined, this),
|
|
264264
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264265
|
-
dimColor: true,
|
|
264266
|
-
children: "review"
|
|
264267
|
-
}, undefined, false, undefined, this),
|
|
264268
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264269
|
-
color: pollStatus.lastBuckets.review > 0 ? "yellow" : "white",
|
|
264270
|
-
children: pollStatus.lastBuckets.review
|
|
264271
|
-
}, undefined, false, undefined, this),
|
|
264272
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264273
|
-
dimColor: true,
|
|
264274
|
-
children: "\xB7"
|
|
264275
|
-
}, undefined, false, undefined, this),
|
|
264276
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264277
|
-
dimColor: true,
|
|
264278
|
-
children: "mentions"
|
|
264279
|
-
}, undefined, false, undefined, this),
|
|
264280
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264281
|
-
color: pollStatus.lastBuckets.mentions > 0 ? "magenta" : "white",
|
|
264282
|
-
children: pollStatus.lastBuckets.mentions
|
|
264283
|
-
}, undefined, false, undefined, this),
|
|
264284
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264285
|
-
dimColor: true,
|
|
264286
|
-
children: "\xB7"
|
|
264287
|
-
}, undefined, false, undefined, this),
|
|
264288
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264289
|
-
dimColor: true,
|
|
264290
|
-
children: "awaiting"
|
|
264291
|
-
}, undefined, false, undefined, this),
|
|
264292
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264293
|
-
color: pollStatus.lastBuckets.awaiting > 0 ? "yellow" : "white",
|
|
264294
|
-
children: pollStatus.lastBuckets.awaiting
|
|
264295
|
-
}, undefined, false, undefined, this)
|
|
264296
|
-
]
|
|
264297
|
-
}, undefined, true, undefined, this)
|
|
264298
|
-
}, undefined, false, undefined, this)
|
|
264299
|
-
]
|
|
264300
|
-
}, undefined, true, undefined, this),
|
|
264301
|
-
pollStatus.lastAt !== null && pollStatus.lastPrStatus && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
264302
|
-
gap: 2,
|
|
264303
|
-
children: [
|
|
264304
|
-
secsToNextPoll !== null ? /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
264305
|
-
gap: 1,
|
|
264306
|
-
width: 7,
|
|
264307
|
-
children: [
|
|
264308
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264309
|
-
dimColor: true,
|
|
264310
|
-
children: "\u21BA"
|
|
264311
|
-
}, undefined, false, undefined, this),
|
|
264312
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264313
|
-
color: "gray",
|
|
264314
|
-
children: [
|
|
264315
|
-
secsToNextPoll,
|
|
264316
|
-
"s"
|
|
264317
|
-
]
|
|
264318
|
-
}, undefined, true, undefined, this)
|
|
264319
|
-
]
|
|
264320
|
-
}, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264321
|
-
children: " ".repeat(7)
|
|
264322
|
-
}, undefined, false, undefined, this),
|
|
264323
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264324
|
-
dimColor: true,
|
|
264325
|
-
children: "\u2502"
|
|
264326
|
-
}, undefined, false, undefined, this),
|
|
264327
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264328
|
-
dimColor: true,
|
|
264329
|
-
children: "mergeable"
|
|
264330
|
-
}, undefined, false, undefined, this),
|
|
264331
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264332
|
-
color: pollStatus.lastPrStatus.mergeable > 0 ? "green" : "white",
|
|
264333
|
-
children: pollStatus.lastPrStatus.mergeable
|
|
264334
|
-
}, undefined, false, undefined, this),
|
|
264335
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264336
|
-
dimColor: true,
|
|
264337
|
-
children: "\xB7"
|
|
264338
|
-
}, undefined, false, undefined, this),
|
|
264339
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264340
|
-
dimColor: true,
|
|
264341
|
-
children: "conflicted"
|
|
264342
|
-
}, undefined, false, undefined, this),
|
|
264343
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264344
|
-
color: pollStatus.lastPrStatus.conflicted > 0 ? "red" : "white",
|
|
264345
|
-
children: pollStatus.lastPrStatus.conflicted
|
|
264346
|
-
}, undefined, false, undefined, this),
|
|
264347
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264348
|
-
dimColor: true,
|
|
264349
|
-
children: "\xB7"
|
|
264350
|
-
}, undefined, false, undefined, this),
|
|
264351
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264352
|
-
dimColor: true,
|
|
264353
|
-
children: "ci-failed"
|
|
264354
|
-
}, undefined, false, undefined, this),
|
|
264355
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264356
|
-
color: pollStatus.lastPrStatus.ciFailed > 0 ? "red" : "white",
|
|
264357
|
-
children: pollStatus.lastPrStatus.ciFailed
|
|
264358
|
-
}, undefined, false, undefined, this),
|
|
264359
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264360
|
-
dimColor: true,
|
|
264361
|
-
children: "\xB7"
|
|
264362
|
-
}, undefined, false, undefined, this),
|
|
264363
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264364
|
-
dimColor: true,
|
|
264365
|
-
children: "quarantined"
|
|
264366
|
-
}, undefined, false, undefined, this),
|
|
264367
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264368
|
-
color: pollStatus.lastPrStatus.quarantined > 0 ? "magenta" : "white",
|
|
264369
|
-
bold: true,
|
|
264370
|
-
children: pollStatus.lastPrStatus.quarantined
|
|
264371
|
-
}, undefined, false, undefined, this)
|
|
264372
|
-
]
|
|
264373
|
-
}, undefined, true, undefined, this)
|
|
264374
|
-
]
|
|
264375
|
-
}, undefined, true, undefined, this),
|
|
264376
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(LabeledBox, {
|
|
264377
|
-
label: "WORKERS",
|
|
264378
|
-
borderColor: "gray",
|
|
264379
|
-
width: 16,
|
|
264380
|
-
paddingX: 1,
|
|
264381
|
-
flexDirection: "column",
|
|
264382
|
-
children: [
|
|
264383
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
264384
|
-
gap: 1,
|
|
264385
|
-
children: [
|
|
264386
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264387
|
-
dimColor: true,
|
|
264388
|
-
children: "active"
|
|
264389
|
-
}, undefined, false, undefined, this),
|
|
264390
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264391
|
-
color: activeCount > 0 ? "cyan" : "gray",
|
|
264392
|
-
bold: true,
|
|
264393
|
-
children: activeCount
|
|
264394
|
-
}, undefined, false, undefined, this)
|
|
264395
|
-
]
|
|
264396
|
-
}, undefined, true, undefined, this),
|
|
264397
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
264398
|
-
gap: 1,
|
|
264399
|
-
children: [
|
|
264400
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264401
|
-
dimColor: true,
|
|
264402
|
-
children: "queue"
|
|
264403
|
-
}, undefined, false, undefined, this),
|
|
264404
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264405
|
-
color: (coord?.queuedCount ?? 0) > 0 ? "yellow" : "gray",
|
|
264406
|
-
bold: true,
|
|
264407
|
-
children: coord?.queuedCount ?? 0
|
|
264408
|
-
}, undefined, false, undefined, this)
|
|
264409
|
-
]
|
|
264410
|
-
}, undefined, true, undefined, this)
|
|
264411
|
-
]
|
|
264412
|
-
}, undefined, true, undefined, this)
|
|
264413
|
-
]
|
|
264414
|
-
}, undefined, true, undefined, this),
|
|
264415
|
-
activeCount > 1 && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(LabeledBox, {
|
|
264416
|
-
label: `TASKS${activeCount > 1 ? " Tab/\u2190 \u2192 \xB7 1-9" : ""}`,
|
|
264417
|
-
borderColor: "gray",
|
|
264418
|
-
width: termWidth,
|
|
264419
|
-
paddingX: 1,
|
|
264420
|
-
flexDirection: "column",
|
|
264421
|
-
children: /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
264422
|
-
gap: 3,
|
|
264423
|
-
flexWrap: "wrap",
|
|
264424
|
-
children: coord?.activeWorkers.map((w2, idx) => {
|
|
264425
|
-
const meta3 = workerMetaRef.current.get(w2.changeName);
|
|
264426
|
-
const phase2 = meta3?.phase ?? "working";
|
|
264427
|
-
const pBadge = priorityBadge(w2.issue.priority);
|
|
264428
|
-
const isFocused = idx === safeFocusedIdx;
|
|
264429
|
-
return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
264430
|
-
gap: 1,
|
|
264431
|
-
children: [
|
|
264432
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264433
|
-
color: isFocused ? "white" : "gray",
|
|
264434
|
-
bold: isFocused,
|
|
264435
|
-
children: [
|
|
264436
|
-
"[",
|
|
264437
|
-
idx + 1,
|
|
264438
|
-
"]"
|
|
264439
|
-
]
|
|
264440
|
-
}, undefined, true, undefined, this),
|
|
264441
|
-
pBadge.label && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264442
|
-
color: pBadge.color,
|
|
264443
|
-
children: [
|
|
264444
|
-
pBadge.text,
|
|
264445
|
-
" ",
|
|
264446
|
-
pBadge.label
|
|
264447
|
-
]
|
|
264448
|
-
}, undefined, true, undefined, this),
|
|
264449
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Link, {
|
|
264450
|
-
url: w2.issue.url,
|
|
264451
|
-
label: w2.issueIdentifier,
|
|
264452
|
-
color: isFocused ? "cyan" : "gray"
|
|
264453
|
-
}, undefined, false, undefined, this),
|
|
264454
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264455
|
-
color: phaseColor(phase2),
|
|
264456
|
-
dimColor: !isFocused,
|
|
264457
|
-
children: phase2
|
|
264458
|
-
}, undefined, false, undefined, this),
|
|
264459
|
-
isFocused && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264460
|
-
color: "white",
|
|
264461
|
-
children: "\u25C0"
|
|
264462
|
-
}, undefined, false, undefined, this)
|
|
264463
|
-
]
|
|
264464
|
-
}, w2.changeName, true, undefined, this);
|
|
264465
|
-
})
|
|
264466
|
-
}, undefined, false, undefined, this)
|
|
264467
|
-
}, undefined, false, undefined, this),
|
|
264468
265297
|
(() => {
|
|
264469
|
-
const
|
|
264470
|
-
|
|
264471
|
-
|
|
264472
|
-
|
|
264473
|
-
|
|
264474
|
-
|
|
264475
|
-
|
|
264476
|
-
|
|
264477
|
-
|
|
264478
|
-
|
|
264479
|
-
|
|
264480
|
-
const labelParts = [];
|
|
264481
|
-
entries.forEach(([, g3], i) => {
|
|
264482
|
-
labelParts.push(/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Link, {
|
|
264483
|
-
url: g3.issueUrl,
|
|
264484
|
-
label: g3.issueIdentifier,
|
|
264485
|
-
color: "yellow"
|
|
264486
|
-
}, g3.issueIdentifier, false, undefined, this));
|
|
264487
|
-
if (i < entries.length - 1) {
|
|
264488
|
-
labelParts.push(/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264489
|
-
color: "yellow",
|
|
264490
|
-
children: " \xB7 "
|
|
264491
|
-
}, `sep-${i}`, false, undefined, this));
|
|
264492
|
-
}
|
|
264493
|
-
});
|
|
264494
|
-
const multiLabelNode = /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(jsx_dev_runtime11.Fragment, {
|
|
265298
|
+
const tasksInnerWidth = Math.max(0, termWidth - 2);
|
|
265299
|
+
const lead = "\u2500 ";
|
|
265300
|
+
const hint = " Tab/\u2191\u2193\xB71-9 ";
|
|
265301
|
+
const live = ` ${tasksLiveness} `;
|
|
265302
|
+
const trail = "\u2500";
|
|
265303
|
+
const fixed = lead.length + "TASKS".length + hint.length + live.length + trail.length;
|
|
265304
|
+
const fill2 = Math.max(1, tasksInnerWidth - fixed);
|
|
265305
|
+
return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(LabeledBox, {
|
|
265306
|
+
labelVisualWidth: tasksInnerWidth,
|
|
265307
|
+
labelNode: /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
265308
|
+
flexDirection: "row",
|
|
264495
265309
|
children: [
|
|
264496
265310
|
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264497
|
-
color: "
|
|
264498
|
-
children:
|
|
265311
|
+
color: "gray",
|
|
265312
|
+
children: lead
|
|
264499
265313
|
}, undefined, false, undefined, this),
|
|
264500
|
-
labelParts,
|
|
264501
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264502
|
-
color: "yellow",
|
|
264503
|
-
children: " "
|
|
264504
|
-
}, undefined, false, undefined, this)
|
|
264505
|
-
]
|
|
264506
|
-
}, undefined, true, undefined, this);
|
|
264507
|
-
return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(LabeledBox, {
|
|
264508
|
-
labelNode: multiLabelNode,
|
|
264509
|
-
labelVisualWidth: multiLabelWidth,
|
|
264510
|
-
borderColor: "yellow",
|
|
264511
|
-
paddingX: 1,
|
|
264512
|
-
gap: 2,
|
|
264513
|
-
width: termWidth,
|
|
264514
|
-
children: [
|
|
264515
265314
|
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264516
|
-
color: "yellow",
|
|
264517
265315
|
bold: true,
|
|
264518
|
-
children: "
|
|
264519
|
-
}, undefined, false, undefined, this),
|
|
264520
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264521
|
-
color: "yellow",
|
|
264522
|
-
children: "Awaiting confirmation"
|
|
265316
|
+
children: "TASKS"
|
|
264523
265317
|
}, undefined, false, undefined, this),
|
|
264524
265318
|
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264525
265319
|
dimColor: true,
|
|
264526
|
-
children:
|
|
265320
|
+
children: hint
|
|
264527
265321
|
}, undefined, false, undefined, this),
|
|
264528
265322
|
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264529
|
-
color: "
|
|
264530
|
-
|
|
264531
|
-
children: gated.size
|
|
265323
|
+
color: "gray",
|
|
265324
|
+
children: "\u2500".repeat(fill2)
|
|
264532
265325
|
}, undefined, false, undefined, this),
|
|
264533
265326
|
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264534
265327
|
dimColor: true,
|
|
264535
|
-
children:
|
|
265328
|
+
children: live
|
|
265329
|
+
}, undefined, false, undefined, this),
|
|
265330
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265331
|
+
color: "gray",
|
|
265332
|
+
children: trail
|
|
264536
265333
|
}, undefined, false, undefined, this)
|
|
264537
265334
|
]
|
|
264538
|
-
}, undefined, true, undefined, this)
|
|
264539
|
-
|
|
264540
|
-
const { top } = pickLatestGatedTicket(gated);
|
|
264541
|
-
if (!top)
|
|
264542
|
-
return null;
|
|
264543
|
-
const [changeName, g2] = top;
|
|
264544
|
-
const askedAgo = g2.since ? fmtElapsed(now2 - Date.parse(g2.since)) : "just now";
|
|
264545
|
-
const cardLabelWidth = g2.issueIdentifier.length + 2;
|
|
264546
|
-
const cardLabelNode = /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(jsx_dev_runtime11.Fragment, {
|
|
264547
|
-
children: [
|
|
264548
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264549
|
-
color: "yellow",
|
|
264550
|
-
children: " "
|
|
264551
|
-
}, undefined, false, undefined, this),
|
|
264552
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Link, {
|
|
264553
|
-
url: g2.issueUrl,
|
|
264554
|
-
label: g2.issueIdentifier,
|
|
264555
|
-
color: "yellow"
|
|
264556
|
-
}, undefined, false, undefined, this),
|
|
264557
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264558
|
-
color: "yellow",
|
|
264559
|
-
children: " "
|
|
264560
|
-
}, undefined, false, undefined, this)
|
|
264561
|
-
]
|
|
264562
|
-
}, undefined, true, undefined, this);
|
|
264563
|
-
return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(LabeledBox, {
|
|
264564
|
-
labelNode: cardLabelNode,
|
|
264565
|
-
labelVisualWidth: cardLabelWidth,
|
|
264566
|
-
borderColor: "yellow",
|
|
264567
|
-
paddingX: 1,
|
|
264568
|
-
gap: 2,
|
|
265335
|
+
}, undefined, true, undefined, this),
|
|
265336
|
+
borderColor: "gray",
|
|
264569
265337
|
width: termWidth,
|
|
264570
|
-
|
|
264571
|
-
|
|
264572
|
-
|
|
264573
|
-
|
|
264574
|
-
|
|
264575
|
-
|
|
264576
|
-
|
|
264577
|
-
|
|
264578
|
-
|
|
264579
|
-
|
|
264580
|
-
|
|
264581
|
-
|
|
264582
|
-
|
|
264583
|
-
|
|
264584
|
-
|
|
264585
|
-
|
|
264586
|
-
|
|
264587
|
-
|
|
264588
|
-
|
|
264589
|
-
|
|
264590
|
-
|
|
264591
|
-
children:
|
|
264592
|
-
|
|
264593
|
-
|
|
264594
|
-
|
|
264595
|
-
|
|
264596
|
-
|
|
264597
|
-
|
|
264598
|
-
|
|
264599
|
-
|
|
264600
|
-
|
|
264601
|
-
|
|
264602
|
-
|
|
264603
|
-
|
|
264604
|
-
|
|
264605
|
-
|
|
264606
|
-
|
|
264607
|
-
|
|
264608
|
-
|
|
264609
|
-
|
|
264610
|
-
|
|
264611
|
-
|
|
264612
|
-
|
|
264613
|
-
|
|
264614
|
-
|
|
264615
|
-
|
|
264616
|
-
|
|
264617
|
-
|
|
264618
|
-
|
|
265338
|
+
paddingX: 1,
|
|
265339
|
+
flexDirection: "column",
|
|
265340
|
+
children: board.length === 0 ? /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265341
|
+
dimColor: true,
|
|
265342
|
+
children: "no active tickets"
|
|
265343
|
+
}, undefined, false, undefined, this) : (() => {
|
|
265344
|
+
const idColWidth = Math.max(8, ...tree.map((t) => t.depth * 2 + t.row.identifier.length));
|
|
265345
|
+
const idxWidth = String(tree.length).length + 3;
|
|
265346
|
+
const prefixWidth = 2 + idxWidth + idColWidth + 1;
|
|
265347
|
+
const advancing = activeCount > 0 || tree.some((t) => ADVANCING_STATES.has(t.row.state));
|
|
265348
|
+
const hasStartableTodo = tree.some((t) => t.row.state === "todo" && !(t.row.blockedByIds?.length ?? 0));
|
|
265349
|
+
const stalled = !advancing && !hasStartableTodo;
|
|
265350
|
+
const blockedCount = tree.filter((t) => t.row.state === "todo" && (t.row.blockedByIds?.length ?? 0) > 0).length;
|
|
265351
|
+
const awaitingCount = tree.filter((t) => t.row.state === "awaiting").length;
|
|
265352
|
+
const quarantinedCount = tree.filter((t) => t.row.state === "quarantined").length;
|
|
265353
|
+
const stallParts = [
|
|
265354
|
+
blockedCount > 0 ? `${blockedCount} blocked` : null,
|
|
265355
|
+
awaitingCount > 0 ? `${awaitingCount} awaiting confirmation` : null,
|
|
265356
|
+
quarantinedCount > 0 ? `${quarantinedCount} quarantined` : null
|
|
265357
|
+
].filter((p) => p !== null);
|
|
265358
|
+
return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(jsx_dev_runtime11.Fragment, {
|
|
265359
|
+
children: [
|
|
265360
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
265361
|
+
children: [
|
|
265362
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265363
|
+
children: " ".repeat(prefixWidth)
|
|
265364
|
+
}, undefined, false, undefined, this),
|
|
265365
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(PipelineCells, {
|
|
265366
|
+
glyphs: null
|
|
265367
|
+
}, undefined, false, undefined, this)
|
|
265368
|
+
]
|
|
265369
|
+
}, undefined, true, undefined, this),
|
|
265370
|
+
tree.map(({ row, depth }, i) => {
|
|
265371
|
+
const isFocused = row.id === focusedRow?.id;
|
|
265372
|
+
const indent = depth > 0 ? " ".repeat(depth - 1) + "\u2514 " : "";
|
|
265373
|
+
const blockers = row.blockedByIdentifiers ?? [];
|
|
265374
|
+
const activeW = coordRef.current?.activeWorkers.find((w2) => w2.issueId === row.id);
|
|
265375
|
+
const meta3 = activeW ? workerMetaRef.current.get(activeW.changeName) : undefined;
|
|
265376
|
+
const waitingForWorker = !activeW && WORKER_WAIT_STATES.has(row.state);
|
|
265377
|
+
let age = "\u2013";
|
|
265378
|
+
if (meta3?.startedAt) {
|
|
265379
|
+
age = fmtElapsed(now2 - meta3.startedAt);
|
|
265380
|
+
} else if (!waitingForWorker && row.recovery?.firstFailedAt) {
|
|
265381
|
+
const failedAt = Date.parse(row.recovery.firstFailedAt);
|
|
265382
|
+
if (!Number.isNaN(failedAt))
|
|
265383
|
+
age = fmtElapsed(now2 - failedAt);
|
|
265384
|
+
}
|
|
265385
|
+
const prUrl = meta3?.prUrl ?? row.prUrl ?? null;
|
|
265386
|
+
return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
265387
|
+
children: [
|
|
265388
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
265389
|
+
width: 2,
|
|
265390
|
+
children: /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265391
|
+
color: "white",
|
|
265392
|
+
bold: true,
|
|
265393
|
+
children: isFocused ? "\u25B6" : " "
|
|
265394
|
+
}, undefined, false, undefined, this)
|
|
265395
|
+
}, undefined, false, undefined, this),
|
|
265396
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
265397
|
+
width: idxWidth,
|
|
265398
|
+
children: /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265399
|
+
dimColor: !isFocused,
|
|
265400
|
+
children: [
|
|
265401
|
+
"[",
|
|
265402
|
+
i + 1,
|
|
265403
|
+
"]"
|
|
265404
|
+
]
|
|
265405
|
+
}, undefined, true, undefined, this)
|
|
265406
|
+
}, undefined, false, undefined, this),
|
|
265407
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
265408
|
+
width: idColWidth + 1,
|
|
265409
|
+
children: [
|
|
265410
|
+
indent && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265411
|
+
dimColor: true,
|
|
265412
|
+
children: indent
|
|
265413
|
+
}, undefined, false, undefined, this),
|
|
265414
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Link, {
|
|
265415
|
+
url: row.url,
|
|
265416
|
+
label: row.identifier,
|
|
265417
|
+
color: isFocused ? "cyan" : "gray"
|
|
265418
|
+
}, undefined, false, undefined, this)
|
|
265419
|
+
]
|
|
265420
|
+
}, undefined, true, undefined, this),
|
|
265421
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(PipelineCells, {
|
|
265422
|
+
glyphs: pipelineStages(row).map((s) => s.status)
|
|
265423
|
+
}, undefined, false, undefined, this),
|
|
265424
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265425
|
+
color: isFocused ? "white" : "gray",
|
|
265426
|
+
dimColor: !isFocused,
|
|
265427
|
+
children: [
|
|
265428
|
+
" ",
|
|
265429
|
+
statusLabel(row)
|
|
265430
|
+
]
|
|
265431
|
+
}, undefined, true, undefined, this),
|
|
265432
|
+
blockers.length > 0 && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265433
|
+
color: "yellow",
|
|
265434
|
+
dimColor: !isFocused,
|
|
265435
|
+
children: [
|
|
265436
|
+
" \u26D3 ",
|
|
265437
|
+
trunc(blockers.join(", "), 28)
|
|
265438
|
+
]
|
|
265439
|
+
}, undefined, true, undefined, this),
|
|
265440
|
+
waitingForWorker ? /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265441
|
+
color: "yellow",
|
|
265442
|
+
children: " waiting for worker"
|
|
265443
|
+
}, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265444
|
+
dimColor: true,
|
|
265445
|
+
children: [
|
|
265446
|
+
" ",
|
|
265447
|
+
age
|
|
265448
|
+
]
|
|
265449
|
+
}, undefined, true, undefined, this),
|
|
265450
|
+
prUrl && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(jsx_dev_runtime11.Fragment, {
|
|
265451
|
+
children: [
|
|
265452
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265453
|
+
dimColor: true,
|
|
265454
|
+
children: " \u2197"
|
|
265455
|
+
}, undefined, false, undefined, this),
|
|
265456
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Link, {
|
|
265457
|
+
url: prUrl,
|
|
265458
|
+
label: prLabel(prUrl),
|
|
265459
|
+
color: "green"
|
|
265460
|
+
}, undefined, false, undefined, this)
|
|
265461
|
+
]
|
|
265462
|
+
}, undefined, true, undefined, this)
|
|
265463
|
+
]
|
|
265464
|
+
}, row.id, true, undefined, this);
|
|
265465
|
+
}),
|
|
265466
|
+
stalled && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
265467
|
+
marginTop: 1,
|
|
265468
|
+
children: [
|
|
265469
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265470
|
+
color: "yellow",
|
|
265471
|
+
bold: true,
|
|
265472
|
+
children: "\u23F8 nothing can start"
|
|
265473
|
+
}, undefined, false, undefined, this),
|
|
265474
|
+
stallParts.length > 0 && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265475
|
+
color: "yellow",
|
|
265476
|
+
children: ` \u2014 ${stallParts.join(" \xB7 ")}`
|
|
265477
|
+
}, undefined, false, undefined, this)
|
|
265478
|
+
]
|
|
265479
|
+
}, undefined, true, undefined, this)
|
|
265480
|
+
]
|
|
265481
|
+
}, undefined, true, undefined, this);
|
|
265482
|
+
})()
|
|
265483
|
+
}, undefined, false, undefined, this);
|
|
264619
265484
|
})(),
|
|
264620
|
-
|
|
264621
|
-
const
|
|
265485
|
+
focusedWorker && (() => {
|
|
265486
|
+
const w2 = focusedWorker;
|
|
264622
265487
|
const meta3 = workerMetaRef.current.get(w2.changeName);
|
|
264623
265488
|
const elapsed = meta3 ? fmtElapsed(now2 - meta3.startedAt) : "\u2013";
|
|
264624
265489
|
const iter = meta3?.iter ?? 0;
|
|
@@ -264632,122 +265497,10 @@ function AgentMode({
|
|
|
264632
265497
|
const taskProgress = meta3?.taskProgress ?? null;
|
|
264633
265498
|
const openspecPhase = meta3?.openspecPhase ?? null;
|
|
264634
265499
|
const subtasks = meta3?.subtasks ?? [];
|
|
264635
|
-
const pBadge = priorityBadge(w2.issue.priority);
|
|
264636
265500
|
const mBadge = modeBadge(w2.trigger);
|
|
264637
265501
|
const pColor = phaseColor(phase2);
|
|
264638
|
-
const bColor =
|
|
264639
|
-
const visibleTailLines =
|
|
264640
|
-
if (!isFocused && activeCount > 1) {
|
|
264641
|
-
const cardLabelWidth2 = (prUrl ? prLabel(prUrl).length + 3 : 0) + w2.issueIdentifier.length + 2;
|
|
264642
|
-
const cardLabelNode2 = /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(jsx_dev_runtime11.Fragment, {
|
|
264643
|
-
children: [
|
|
264644
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264645
|
-
color: "gray",
|
|
264646
|
-
children: " "
|
|
264647
|
-
}, undefined, false, undefined, this),
|
|
264648
|
-
prUrl && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Link, {
|
|
264649
|
-
url: prUrl,
|
|
264650
|
-
label: prLabel(prUrl),
|
|
264651
|
-
color: "green"
|
|
264652
|
-
}, undefined, false, undefined, this),
|
|
264653
|
-
prUrl && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264654
|
-
color: "gray",
|
|
264655
|
-
children: " \xB7 "
|
|
264656
|
-
}, undefined, false, undefined, this),
|
|
264657
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Link, {
|
|
264658
|
-
url: w2.issue.url,
|
|
264659
|
-
label: w2.issueIdentifier,
|
|
264660
|
-
color: "cyan"
|
|
264661
|
-
}, undefined, false, undefined, this),
|
|
264662
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264663
|
-
color: "gray",
|
|
264664
|
-
children: " "
|
|
264665
|
-
}, undefined, false, undefined, this)
|
|
264666
|
-
]
|
|
264667
|
-
}, undefined, true, undefined, this);
|
|
264668
|
-
return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(LabeledBox, {
|
|
264669
|
-
labelNode: cardLabelNode2,
|
|
264670
|
-
labelVisualWidth: cardLabelWidth2,
|
|
264671
|
-
borderColor: "gray",
|
|
264672
|
-
paddingX: 1,
|
|
264673
|
-
gap: 2,
|
|
264674
|
-
width: termWidth,
|
|
264675
|
-
children: [
|
|
264676
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264677
|
-
dimColor: true,
|
|
264678
|
-
children: [
|
|
264679
|
-
"[",
|
|
264680
|
-
idx + 1,
|
|
264681
|
-
"]"
|
|
264682
|
-
]
|
|
264683
|
-
}, undefined, true, undefined, this),
|
|
264684
|
-
pBadge.label && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264685
|
-
color: pBadge.color,
|
|
264686
|
-
children: pBadge.text
|
|
264687
|
-
}, undefined, false, undefined, this),
|
|
264688
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264689
|
-
color: "gray",
|
|
264690
|
-
bold: true,
|
|
264691
|
-
children: w2.issueIdentifier
|
|
264692
|
-
}, undefined, false, undefined, this),
|
|
264693
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264694
|
-
dimColor: true,
|
|
264695
|
-
children: trunc(w2.issue.title, 40)
|
|
264696
|
-
}, undefined, false, undefined, this),
|
|
264697
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264698
|
-
dimColor: true,
|
|
264699
|
-
children: "\u2502"
|
|
264700
|
-
}, undefined, false, undefined, this),
|
|
264701
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264702
|
-
color: pColor,
|
|
264703
|
-
dimColor: true,
|
|
264704
|
-
children: phase2
|
|
264705
|
-
}, undefined, false, undefined, this),
|
|
264706
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264707
|
-
dimColor: true,
|
|
264708
|
-
children: "\u2502"
|
|
264709
|
-
}, undefined, false, undefined, this),
|
|
264710
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264711
|
-
dimColor: true,
|
|
264712
|
-
children: elapsed
|
|
264713
|
-
}, undefined, false, undefined, this),
|
|
264714
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264715
|
-
dimColor: true,
|
|
264716
|
-
children: "\xB7"
|
|
264717
|
-
}, undefined, false, undefined, this),
|
|
264718
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264719
|
-
dimColor: true,
|
|
264720
|
-
children: [
|
|
264721
|
-
"\u21BA ",
|
|
264722
|
-
iter
|
|
264723
|
-
]
|
|
264724
|
-
}, undefined, true, undefined, this),
|
|
264725
|
-
currentTask && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(jsx_dev_runtime11.Fragment, {
|
|
264726
|
-
children: [
|
|
264727
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264728
|
-
dimColor: true,
|
|
264729
|
-
children: "\u2502"
|
|
264730
|
-
}, undefined, false, undefined, this),
|
|
264731
|
-
openspecPhase && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264732
|
-
color: openspecPhaseColor(openspecPhase),
|
|
264733
|
-
children: [
|
|
264734
|
-
"[",
|
|
264735
|
-
openspecPhase,
|
|
264736
|
-
"]"
|
|
264737
|
-
]
|
|
264738
|
-
}, undefined, true, undefined, this),
|
|
264739
|
-
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
264740
|
-
dimColor: true,
|
|
264741
|
-
children: [
|
|
264742
|
-
"\u25B6 ",
|
|
264743
|
-
trunc(currentTask, 40)
|
|
264744
|
-
]
|
|
264745
|
-
}, undefined, true, undefined, this)
|
|
264746
|
-
]
|
|
264747
|
-
}, undefined, true, undefined, this)
|
|
264748
|
-
]
|
|
264749
|
-
}, w2.changeName, true, undefined, this);
|
|
264750
|
-
}
|
|
265502
|
+
const bColor = workerBorderColor(phase2);
|
|
265503
|
+
const visibleTailLines = focusedTailLines;
|
|
264751
265504
|
const cardLabelWidth = (prUrl ? prLabel(prUrl).length + 3 : 0) + w2.issueIdentifier.length + 2;
|
|
264752
265505
|
const cardLabelNode = /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(jsx_dev_runtime11.Fragment, {
|
|
264753
265506
|
children: [
|
|
@@ -264972,7 +265725,7 @@ function AgentMode({
|
|
|
264972
265725
|
}, undefined, false, undefined, this)
|
|
264973
265726
|
]
|
|
264974
265727
|
}, undefined, true, undefined, this),
|
|
264975
|
-
steeringActive &&
|
|
265728
|
+
steeringActive && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
264976
265729
|
marginTop: 0,
|
|
264977
265730
|
children: /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(SteeringField, {
|
|
264978
265731
|
active: steeringActive,
|
|
@@ -264990,8 +265743,12 @@ function AgentMode({
|
|
|
264990
265743
|
},
|
|
264991
265744
|
onSubmit: async (message) => {
|
|
264992
265745
|
try {
|
|
264993
|
-
await appendSteering2(
|
|
264994
|
-
fileEmit({
|
|
265746
|
+
await appendSteering2(join38(tasksDir, w2.changeName), message);
|
|
265747
|
+
fileEmit({
|
|
265748
|
+
type: "steering_submitted",
|
|
265749
|
+
changeName: w2.changeName,
|
|
265750
|
+
message
|
|
265751
|
+
});
|
|
264995
265752
|
} catch (err) {
|
|
264996
265753
|
const text = err.message;
|
|
264997
265754
|
fileEmit({
|
|
@@ -265067,7 +265824,108 @@ function AgentMode({
|
|
|
265067
265824
|
})()
|
|
265068
265825
|
]
|
|
265069
265826
|
}, w2.changeName, true, undefined, this);
|
|
265070
|
-
})
|
|
265827
|
+
})(),
|
|
265828
|
+
!focusedWorker && focusedRow && (() => {
|
|
265829
|
+
const row = focusedRow;
|
|
265830
|
+
let age = "\u2013";
|
|
265831
|
+
if (row.recovery?.firstFailedAt) {
|
|
265832
|
+
const failedAt = Date.parse(row.recovery.firstFailedAt);
|
|
265833
|
+
if (!Number.isNaN(failedAt))
|
|
265834
|
+
age = fmtElapsed(now2 - failedAt);
|
|
265835
|
+
}
|
|
265836
|
+
const prUrl = row.prUrl ?? null;
|
|
265837
|
+
const cardLabelWidth = (prUrl ? prLabel(prUrl).length + 3 : 0) + row.identifier.length + 2;
|
|
265838
|
+
const cardLabelNode = /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(jsx_dev_runtime11.Fragment, {
|
|
265839
|
+
children: [
|
|
265840
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265841
|
+
color: "gray",
|
|
265842
|
+
children: " "
|
|
265843
|
+
}, undefined, false, undefined, this),
|
|
265844
|
+
prUrl && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Link, {
|
|
265845
|
+
url: prUrl,
|
|
265846
|
+
label: prLabel(prUrl),
|
|
265847
|
+
color: "green"
|
|
265848
|
+
}, undefined, false, undefined, this),
|
|
265849
|
+
prUrl && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265850
|
+
color: "gray",
|
|
265851
|
+
children: " \xB7 "
|
|
265852
|
+
}, undefined, false, undefined, this),
|
|
265853
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Link, {
|
|
265854
|
+
url: row.url,
|
|
265855
|
+
label: row.identifier,
|
|
265856
|
+
color: "cyan"
|
|
265857
|
+
}, undefined, false, undefined, this),
|
|
265858
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265859
|
+
color: "gray",
|
|
265860
|
+
children: " "
|
|
265861
|
+
}, undefined, false, undefined, this)
|
|
265862
|
+
]
|
|
265863
|
+
}, undefined, true, undefined, this);
|
|
265864
|
+
return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(LabeledBox, {
|
|
265865
|
+
labelNode: cardLabelNode,
|
|
265866
|
+
labelVisualWidth: cardLabelWidth,
|
|
265867
|
+
borderColor: "gray",
|
|
265868
|
+
flexDirection: "column",
|
|
265869
|
+
paddingX: 1,
|
|
265870
|
+
width: termWidth,
|
|
265871
|
+
children: [
|
|
265872
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265873
|
+
color: "white",
|
|
265874
|
+
bold: true,
|
|
265875
|
+
children: trunc(row.title, Math.max(20, termWidth - 20))
|
|
265876
|
+
}, undefined, false, undefined, this),
|
|
265877
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
265878
|
+
marginTop: 0,
|
|
265879
|
+
children: [
|
|
265880
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(PipelineCells, {
|
|
265881
|
+
glyphs: pipelineStages(row).map((s) => s.status)
|
|
265882
|
+
}, undefined, false, undefined, this),
|
|
265883
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265884
|
+
color: "white",
|
|
265885
|
+
children: [
|
|
265886
|
+
" ",
|
|
265887
|
+
statusLabel(row)
|
|
265888
|
+
]
|
|
265889
|
+
}, undefined, true, undefined, this)
|
|
265890
|
+
]
|
|
265891
|
+
}, undefined, true, undefined, this),
|
|
265892
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
265893
|
+
gap: 2,
|
|
265894
|
+
marginTop: 0,
|
|
265895
|
+
children: [
|
|
265896
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265897
|
+
dimColor: true,
|
|
265898
|
+
children: "parked \xB7 no live worker"
|
|
265899
|
+
}, undefined, false, undefined, this),
|
|
265900
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265901
|
+
dimColor: true,
|
|
265902
|
+
children: "\u2502"
|
|
265903
|
+
}, undefined, false, undefined, this),
|
|
265904
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265905
|
+
dimColor: true,
|
|
265906
|
+
children: [
|
|
265907
|
+
"age ",
|
|
265908
|
+
age
|
|
265909
|
+
]
|
|
265910
|
+
}, undefined, true, undefined, this),
|
|
265911
|
+
prUrl && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(jsx_dev_runtime11.Fragment, {
|
|
265912
|
+
children: [
|
|
265913
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
265914
|
+
dimColor: true,
|
|
265915
|
+
children: "\u2502"
|
|
265916
|
+
}, undefined, false, undefined, this),
|
|
265917
|
+
/* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Link, {
|
|
265918
|
+
url: prUrl,
|
|
265919
|
+
label: prLabel(prUrl),
|
|
265920
|
+
color: "green"
|
|
265921
|
+
}, undefined, false, undefined, this)
|
|
265922
|
+
]
|
|
265923
|
+
}, undefined, true, undefined, this)
|
|
265924
|
+
]
|
|
265925
|
+
}, undefined, true, undefined, this)
|
|
265926
|
+
]
|
|
265927
|
+
}, row.id, true, undefined, this);
|
|
265928
|
+
})()
|
|
265071
265929
|
]
|
|
265072
265930
|
}, undefined, true, undefined, this),
|
|
265073
265931
|
awaitingClose && /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text, {
|
|
@@ -265077,13 +265935,14 @@ function AgentMode({
|
|
|
265077
265935
|
]
|
|
265078
265936
|
}, resizeKey, true, undefined, this);
|
|
265079
265937
|
}
|
|
265080
|
-
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;
|
|
265938
|
+
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;
|
|
265081
265939
|
var init_AgentMode = __esm(async () => {
|
|
265082
265940
|
init_cli2();
|
|
265083
265941
|
init_config();
|
|
265084
265942
|
init_wire();
|
|
265085
265943
|
init_preflight();
|
|
265086
265944
|
init_json_log_file();
|
|
265945
|
+
init_task_pipeline();
|
|
265087
265946
|
init_phase();
|
|
265088
265947
|
init_log();
|
|
265089
265948
|
init_useTerminalSize();
|
|
@@ -265099,7 +265958,32 @@ var init_AgentMode = __esm(async () => {
|
|
|
265099
265958
|
import_react63 = __toESM(require_react(), 1);
|
|
265100
265959
|
jsx_dev_runtime11 = __toESM(require_jsx_dev_runtime(), 1);
|
|
265101
265960
|
SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
265961
|
+
WORKER_WAIT_STATES = new Set([
|
|
265962
|
+
"queued",
|
|
265963
|
+
"working",
|
|
265964
|
+
"in-progress",
|
|
265965
|
+
"conflict-fix",
|
|
265966
|
+
"ci-fix",
|
|
265967
|
+
"review"
|
|
265968
|
+
]);
|
|
265969
|
+
ADVANCING_STATES = new Set([
|
|
265970
|
+
"queued",
|
|
265971
|
+
"working",
|
|
265972
|
+
"in-progress",
|
|
265973
|
+
"conflict-fix",
|
|
265974
|
+
"ci-fix",
|
|
265975
|
+
"review",
|
|
265976
|
+
"awaiting-ci"
|
|
265977
|
+
]);
|
|
265102
265978
|
HYPERLINKS_SUPPORTED = !process.env["TMUX"];
|
|
265979
|
+
NODE_LABELS = {
|
|
265980
|
+
todo: "todo",
|
|
265981
|
+
confirmation: "conf",
|
|
265982
|
+
work: "work",
|
|
265983
|
+
PR: "PR",
|
|
265984
|
+
CI: "CI",
|
|
265985
|
+
done: "done"
|
|
265986
|
+
};
|
|
265103
265987
|
SESSION_START = new Date().toISOString();
|
|
265104
265988
|
});
|
|
265105
265989
|
|
|
@@ -265299,7 +266183,7 @@ __export(exports_list, {
|
|
|
265299
266183
|
buildBuckets: () => buildBuckets,
|
|
265300
266184
|
backlogRankByIssueId: () => backlogRankByIssueId
|
|
265301
266185
|
});
|
|
265302
|
-
import { join as
|
|
266186
|
+
import { join as join39 } from "path";
|
|
265303
266187
|
function countTaskItems(content) {
|
|
265304
266188
|
const checked = (content.match(/^- \[x\]/gm) ?? []).length;
|
|
265305
266189
|
const unchecked = (content.match(/^- \[ \]/gm) ?? []).length;
|
|
@@ -265315,13 +266199,13 @@ function buildLocalRows() {
|
|
|
265315
266199
|
const sources = [{ dir: statesDir, label: "main" }];
|
|
265316
266200
|
const worktreesRoot = worktreesDir2(projectRoot);
|
|
265317
266201
|
for (const wt of storage.list(worktreesRoot)) {
|
|
265318
|
-
sources.push({ dir:
|
|
266202
|
+
sources.push({ dir: join39(worktreesRoot, wt, ".ralph", "tasks"), label: `wt:${wt}` });
|
|
265319
266203
|
}
|
|
265320
266204
|
for (const { dir, label } of sources) {
|
|
265321
266205
|
for (const entry of storage.list(dir)) {
|
|
265322
266206
|
if (seen.has(entry))
|
|
265323
266207
|
continue;
|
|
265324
|
-
const raw = storage.read(
|
|
266208
|
+
const raw = storage.read(join39(dir, entry, ".ralph-state.json"));
|
|
265325
266209
|
if (raw === null)
|
|
265326
266210
|
continue;
|
|
265327
266211
|
let state;
|
|
@@ -265336,7 +266220,7 @@ function buildLocalRows() {
|
|
|
265336
266220
|
const firstLine = promptRaw.split(`
|
|
265337
266221
|
`).find((l3) => l3.trim() !== "") ?? "";
|
|
265338
266222
|
let progress = "\u2014";
|
|
265339
|
-
const tasksContent = storage.read(
|
|
266223
|
+
const tasksContent = storage.read(join39(dir, entry, "tasks.md"));
|
|
265340
266224
|
if (tasksContent !== null) {
|
|
265341
266225
|
const { checked, unchecked } = countTaskItems(tasksContent);
|
|
265342
266226
|
const total = checked + unchecked;
|
|
@@ -265669,8 +266553,8 @@ async function fetchIssueByIdentifier(apiKey, identifier) {
|
|
|
265669
266553
|
team { key }
|
|
265670
266554
|
labels { nodes { name } }
|
|
265671
266555
|
attachments(first: 25) { nodes { title subtitle } }
|
|
265672
|
-
|
|
265673
|
-
nodes { type
|
|
266556
|
+
inverseRelations(first: 50) {
|
|
266557
|
+
nodes { type issue { id identifier state { type } } }
|
|
265674
266558
|
}
|
|
265675
266559
|
}
|
|
265676
266560
|
}
|
|
@@ -265749,7 +266633,7 @@ Found ${issue2.identifier} \u2014 "${issue2.title}"
|
|
|
265749
266633
|
` + ` assignee: ${issue2.assignee ? `${issue2.assignee.name} <${issue2.assignee.email ?? "no-email"}>` : "(unassigned)"}
|
|
265750
266634
|
` + ` labels: ${issue2.labels.nodes.map((l3) => l3.name).join(", ") || "(none)"}
|
|
265751
266635
|
`);
|
|
265752
|
-
const blockedBy = issue2.
|
|
266636
|
+
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);
|
|
265753
266637
|
process.stdout.write(`
|
|
265754
266638
|
Per-bucket diagnostics:
|
|
265755
266639
|
`);
|
|
@@ -265839,7 +266723,7 @@ var exports_json_runner = {};
|
|
|
265839
266723
|
__export(exports_json_runner, {
|
|
265840
266724
|
runAgentJson: () => runAgentJson
|
|
265841
266725
|
});
|
|
265842
|
-
import { join as
|
|
266726
|
+
import { join as join40 } from "path";
|
|
265843
266727
|
import { mkdir as mkdir12 } from "fs/promises";
|
|
265844
266728
|
import { homedir as homedir8 } from "os";
|
|
265845
266729
|
function makeEmit(fileSink) {
|
|
@@ -265861,7 +266745,7 @@ async function runAgentJson({
|
|
|
265861
266745
|
tasksDir,
|
|
265862
266746
|
runPreflight: runPreflight2 = runPreflight
|
|
265863
266747
|
}) {
|
|
265864
|
-
await mkdir12(
|
|
266748
|
+
await mkdir12(join40(homedir8(), ".ralph"), { recursive: true }).catch(() => {
|
|
265865
266749
|
return;
|
|
265866
266750
|
});
|
|
265867
266751
|
const fileSink = createJsonLogFileSink(args.jsonLogFile);
|
|
@@ -266081,7 +266965,7 @@ __export(exports_src3, {
|
|
|
266081
266965
|
main: () => main3
|
|
266082
266966
|
});
|
|
266083
266967
|
import { mkdir as mkdir13 } from "fs/promises";
|
|
266084
|
-
import { join as
|
|
266968
|
+
import { join as join41 } from "path";
|
|
266085
266969
|
async function main3(argv) {
|
|
266086
266970
|
if (argv.includes("--help") || argv.includes("-h")) {
|
|
266087
266971
|
printAgentHelp();
|
|
@@ -266146,7 +267030,7 @@ async function main3(argv) {
|
|
|
266146
267030
|
}
|
|
266147
267031
|
await mkdir13(statesDir, { recursive: true });
|
|
266148
267032
|
await mkdir13(tasksDir, { recursive: true });
|
|
266149
|
-
await mkdir13(
|
|
267033
|
+
await mkdir13(join41(projectRoot, ".ralph"), { recursive: true });
|
|
266150
267034
|
if (shouldFallbackToJsonOutput(args, process.stdin.isTTY)) {
|
|
266151
267035
|
process.stderr.write(`agent: stdin is not a TTY \u2014 falling back to --json-output mode.
|
|
266152
267036
|
`);
|
|
@@ -266187,7 +267071,7 @@ async function main3(argv) {
|
|
|
266187
267071
|
return typeof process.exitCode === "number" ? process.exitCode : 0;
|
|
266188
267072
|
}
|
|
266189
267073
|
var import_react64;
|
|
266190
|
-
var
|
|
267074
|
+
var init_src9 = __esm(async () => {
|
|
266191
267075
|
init_context();
|
|
266192
267076
|
init_layout();
|
|
266193
267077
|
init_paths();
|
|
@@ -266245,7 +267129,7 @@ async function dispatch(subcommand, rest2) {
|
|
|
266245
267129
|
return main4(rest2);
|
|
266246
267130
|
}
|
|
266247
267131
|
if (subcommand === "agent") {
|
|
266248
|
-
const { main: main4 } = await
|
|
267132
|
+
const { main: main4 } = await init_src9().then(() => exports_src3);
|
|
266249
267133
|
return main4(rest2);
|
|
266250
267134
|
}
|
|
266251
267135
|
if (subcommand === "task") {
|