ralphctl 0.7.2 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.mjs +167 -40
- package/dist/manifest.json +1 -1
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { Command } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/application/ui/tui/launch.ts
|
|
7
|
-
import
|
|
7
|
+
import React66 from "react";
|
|
8
8
|
|
|
9
9
|
// src/application/bootstrap/storage-paths.ts
|
|
10
10
|
import { promises as fs } from "fs";
|
|
@@ -4360,7 +4360,7 @@ var createNpmVersionChecker = (deps) => {
|
|
|
4360
4360
|
// package.json
|
|
4361
4361
|
var package_default = {
|
|
4362
4362
|
name: "ralphctl",
|
|
4363
|
-
version: "0.7.
|
|
4363
|
+
version: "0.7.3",
|
|
4364
4364
|
description: "Agent harness for long-running AI coding tasks \u2014 orchestrates Claude Code & GitHub Copilot across repositories",
|
|
4365
4365
|
homepage: "https://github.com/lukas-grigis/ralphctl",
|
|
4366
4366
|
type: "module",
|
|
@@ -5219,7 +5219,7 @@ var getRunInTerminal = () => (fn) => ref.current(fn);
|
|
|
5219
5219
|
|
|
5220
5220
|
// src/application/ui/tui/App.tsx
|
|
5221
5221
|
import "react";
|
|
5222
|
-
import { Box as
|
|
5222
|
+
import { Box as Box50 } from "ink";
|
|
5223
5223
|
|
|
5224
5224
|
// src/application/ui/tui/runtime/deps-context.tsx
|
|
5225
5225
|
import { createContext, useContext } from "react";
|
|
@@ -6497,10 +6497,17 @@ var spinnerGlyph = (frame) => glyphs.spinner[frame % glyphs.spinner.length] ?? "
|
|
|
6497
6497
|
|
|
6498
6498
|
// src/application/ui/tui/components/spinner.tsx
|
|
6499
6499
|
import { jsxs as jsxs6 } from "react/jsx-runtime";
|
|
6500
|
-
var Spinner = ({ label, color = inkColors.info }) => {
|
|
6501
|
-
const frame = useSpinnerFrame();
|
|
6500
|
+
var Spinner = ({ label, color = inkColors.info, active = true, dim }) => {
|
|
6501
|
+
const frame = useSpinnerFrame(active);
|
|
6502
|
+
const glyph = spinnerGlyph(frame);
|
|
6503
|
+
if (dim === true) {
|
|
6504
|
+
return /* @__PURE__ */ jsxs6(Text7, { dimColor: true, children: [
|
|
6505
|
+
glyph,
|
|
6506
|
+
label !== void 0 && label.length > 0 ? ` ${label}` : ""
|
|
6507
|
+
] });
|
|
6508
|
+
}
|
|
6502
6509
|
return /* @__PURE__ */ jsxs6(Text7, { color, children: [
|
|
6503
|
-
|
|
6510
|
+
glyph,
|
|
6504
6511
|
label !== void 0 && label.length > 0 ? ` ${label}` : ""
|
|
6505
6512
|
] });
|
|
6506
6513
|
};
|
|
@@ -17819,20 +17826,20 @@ import { Box as Box34, Text as Text36, useInput as useInput15 } from "ink";
|
|
|
17819
17826
|
import { useMemo as useMemo10 } from "react";
|
|
17820
17827
|
import { Box as Box30, Text as Text32 } from "ink";
|
|
17821
17828
|
import { jsx as jsx42, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
17822
|
-
var glyphFor = (status
|
|
17829
|
+
var glyphFor = (status) => {
|
|
17823
17830
|
switch (status) {
|
|
17824
17831
|
case "completed":
|
|
17825
|
-
return
|
|
17832
|
+
return { kind: "static", glyph: glyphs.phaseDone, color: inkColors.success };
|
|
17826
17833
|
case "failed":
|
|
17827
|
-
return
|
|
17834
|
+
return { kind: "static", glyph: glyphs.cross, color: inkColors.error };
|
|
17828
17835
|
case "aborted":
|
|
17829
|
-
return
|
|
17836
|
+
return { kind: "static", glyph: glyphs.warningGlyph, color: inkColors.warning };
|
|
17830
17837
|
case "skipped":
|
|
17831
|
-
return
|
|
17838
|
+
return { kind: "static", glyph: glyphs.phaseDisabled, color: inkColors.muted };
|
|
17832
17839
|
case "running":
|
|
17833
|
-
return
|
|
17840
|
+
return { kind: "spinner", color: inkColors.info };
|
|
17834
17841
|
case "pending":
|
|
17835
|
-
return
|
|
17842
|
+
return { kind: "static", glyph: glyphs.phasePending, color: inkColors.muted };
|
|
17836
17843
|
}
|
|
17837
17844
|
};
|
|
17838
17845
|
var trailingLabelFor = (status) => {
|
|
@@ -17882,7 +17889,6 @@ var StepTrace = ({
|
|
|
17882
17889
|
inFlightLabel,
|
|
17883
17890
|
plan
|
|
17884
17891
|
}) => {
|
|
17885
|
-
const frame = useSpinnerFrame(running);
|
|
17886
17892
|
const traceLastEntry = trace[trace.length - 1];
|
|
17887
17893
|
const merged = useMemo10(
|
|
17888
17894
|
() => plan !== void 0 ? mergePlanWithTrace(plan, trace, running) : traceToRows(trace),
|
|
@@ -17896,11 +17902,11 @@ var StepTrace = ({
|
|
|
17896
17902
|
const rows = runningIdx >= 0 ? filtered.slice(Math.max(0, runningIdx - Math.floor(maxRows / 2))).slice(0, maxRows) : filtered.slice(-maxRows);
|
|
17897
17903
|
return /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", children: [
|
|
17898
17904
|
rows.map((row, i) => {
|
|
17899
|
-
const
|
|
17905
|
+
const instruction = glyphFor(row.status);
|
|
17900
17906
|
const trailing = trailingLabelFor(row.status);
|
|
17901
17907
|
const dimRow = row.status === "pending";
|
|
17902
17908
|
return /* @__PURE__ */ jsxs31(Box30, { paddingX: spacing.indent, children: [
|
|
17903
|
-
/* @__PURE__ */ jsx42(Text32, { color, bold: true, children:
|
|
17909
|
+
instruction.kind === "spinner" ? /* @__PURE__ */ jsx42(Spinner, { active: running, color: instruction.color }) : /* @__PURE__ */ jsx42(Text32, { color: instruction.color, bold: true, children: instruction.glyph }),
|
|
17904
17910
|
/* @__PURE__ */ jsxs31(Text32, { dimColor: dimRow, children: [
|
|
17905
17911
|
" ",
|
|
17906
17912
|
row.name
|
|
@@ -17911,7 +17917,7 @@ var StepTrace = ({
|
|
|
17911
17917
|
" ",
|
|
17912
17918
|
fmtDuration(row.durationMs)
|
|
17913
17919
|
] }),
|
|
17914
|
-
trailing !== void 0 && /* @__PURE__ */ jsxs31(Text32, { color, children: [
|
|
17920
|
+
trailing !== void 0 && /* @__PURE__ */ jsxs31(Text32, { color: instruction.color, children: [
|
|
17915
17921
|
" ",
|
|
17916
17922
|
glyphs.emDash,
|
|
17917
17923
|
" ",
|
|
@@ -17926,7 +17932,7 @@ var StepTrace = ({
|
|
|
17926
17932
|
] }, `${row.name}-${String(i)}`);
|
|
17927
17933
|
}),
|
|
17928
17934
|
plan === void 0 && running && inFlightLabel !== void 0 && /* @__PURE__ */ jsxs31(Box30, { paddingX: spacing.indent, children: [
|
|
17929
|
-
/* @__PURE__ */ jsx42(
|
|
17935
|
+
/* @__PURE__ */ jsx42(Spinner, { active: running, color: inkColors.info }),
|
|
17930
17936
|
/* @__PURE__ */ jsxs31(Text32, { dimColor: true, children: [
|
|
17931
17937
|
" ",
|
|
17932
17938
|
inFlightLabel
|
|
@@ -18062,14 +18068,9 @@ var EvaluationLine = ({ evaluation }) => {
|
|
|
18062
18068
|
evaluation.dimensions.length > 0 && /* @__PURE__ */ jsx43(Box31, { paddingLeft: 6, children: /* @__PURE__ */ jsx43(Text33, { dimColor: true, children: evaluation.dimensions.map((d) => `${d.dimension}: ${String(d.score)}/5 ${d.passed ? glyphs.check : glyphs.cross}`).join(` ${glyphs.bullet} `) }) })
|
|
18063
18069
|
] });
|
|
18064
18070
|
};
|
|
18065
|
-
var SubStepLine = ({
|
|
18066
|
-
sub,
|
|
18067
|
-
running,
|
|
18068
|
-
spinner
|
|
18069
|
-
}) => {
|
|
18071
|
+
var SubStepLine = ({ sub, running }) => {
|
|
18070
18072
|
const presentation = SUB_STEP_PRESENTATION[sub.status];
|
|
18071
18073
|
const glyph = running && sub.status === "completed" ? presentation.glyph : presentation.glyph;
|
|
18072
|
-
void spinner;
|
|
18073
18074
|
return /* @__PURE__ */ jsxs32(Box31, { children: [
|
|
18074
18075
|
/* @__PURE__ */ jsxs32(Text33, { color: presentation.color, bold: true, children: [
|
|
18075
18076
|
glyphs.activityArrow,
|
|
@@ -18098,15 +18099,20 @@ var TaskBlock = ({
|
|
|
18098
18099
|
task,
|
|
18099
18100
|
running,
|
|
18100
18101
|
display,
|
|
18101
|
-
maxSignals
|
|
18102
|
+
maxSignals,
|
|
18103
|
+
maxSubSteps,
|
|
18104
|
+
maxEvaluations
|
|
18102
18105
|
}) => {
|
|
18103
18106
|
const presentation = STATUS_PRESENTATION[task.status];
|
|
18104
|
-
const
|
|
18105
|
-
const glyph = task.status === "running" ? spinnerGlyph(frame) : presentation.glyph;
|
|
18107
|
+
const isSpinning = task.status === "running";
|
|
18106
18108
|
const signalRows = task.signals.slice(-maxSignals);
|
|
18109
|
+
const subStepRows = task.subSteps.slice(-maxSubSteps);
|
|
18110
|
+
const subStepElided = task.subSteps.length - subStepRows.length;
|
|
18111
|
+
const evalRows = task.evaluations.slice(-maxEvaluations);
|
|
18112
|
+
const evalElided = task.evaluations.length - evalRows.length;
|
|
18107
18113
|
return /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", marginBottom: spacing.section, children: [
|
|
18108
18114
|
/* @__PURE__ */ jsxs32(Box31, { children: [
|
|
18109
|
-
/* @__PURE__ */ jsx43(Text33, { color: presentation.color, bold: true, children: glyph }),
|
|
18115
|
+
isSpinning ? /* @__PURE__ */ jsx43(Spinner, { active: running, color: presentation.color }) : /* @__PURE__ */ jsx43(Text33, { color: presentation.color, bold: true, children: presentation.glyph }),
|
|
18110
18116
|
/* @__PURE__ */ jsxs32(Text33, { bold: true, children: [
|
|
18111
18117
|
" ",
|
|
18112
18118
|
display
|
|
@@ -18132,8 +18138,14 @@ var TaskBlock = ({
|
|
|
18132
18138
|
] })
|
|
18133
18139
|
] }),
|
|
18134
18140
|
task.errorMessage !== void 0 && /* @__PURE__ */ jsx43(Box31, { paddingLeft: 2, children: /* @__PURE__ */ jsx43(Text33, { color: inkColors.error, children: task.errorMessage }) }),
|
|
18135
|
-
|
|
18136
|
-
|
|
18141
|
+
subStepRows.length > 0 && /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", paddingLeft: 2, children: [
|
|
18142
|
+
subStepElided > 0 && /* @__PURE__ */ jsx43(Text33, { dimColor: true, children: `\u2026 ${String(subStepElided)} earlier sub-steps` }),
|
|
18143
|
+
subStepRows.map((s, i) => /* @__PURE__ */ jsx43(SubStepLine, { sub: s, running }, `${task.id}-sub-${String(i)}`))
|
|
18144
|
+
] }),
|
|
18145
|
+
evalRows.length > 0 && /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", paddingLeft: 2, marginTop: 1, children: [
|
|
18146
|
+
evalElided > 0 && /* @__PURE__ */ jsx43(Text33, { dimColor: true, children: `\u2026 ${String(evalElided)} earlier evaluations` }),
|
|
18147
|
+
evalRows.map((e, i) => /* @__PURE__ */ jsx43(EvaluationLine, { evaluation: e }, `${task.id}-eval-${String(i)}`))
|
|
18148
|
+
] }),
|
|
18137
18149
|
signalRows.length > 0 && /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", paddingLeft: 2, marginTop: 1, children: [
|
|
18138
18150
|
/* @__PURE__ */ jsx43(Text33, { dimColor: true, children: "signals" }),
|
|
18139
18151
|
/* @__PURE__ */ jsx43(Box31, { flexDirection: "column", paddingLeft: 2, children: signalRows.map((s, i) => /* @__PURE__ */ jsx43(SignalLine, { signal: s }, `${task.id}-sig-${String(i)}`)) })
|
|
@@ -18159,7 +18171,9 @@ var TasksPanel = ({
|
|
|
18159
18171
|
running,
|
|
18160
18172
|
nameById,
|
|
18161
18173
|
maxSignalsPerTask = 8,
|
|
18162
|
-
maxOrphanSignals = 6
|
|
18174
|
+
maxOrphanSignals = 6,
|
|
18175
|
+
maxSubStepsPerTask = 12,
|
|
18176
|
+
maxEvaluationsPerTask = 6
|
|
18163
18177
|
}) => {
|
|
18164
18178
|
if (bucketed.tasks.length === 0 && bucketed.orphanSignals.length === 0) {
|
|
18165
18179
|
return /* @__PURE__ */ jsx43(Box31, { paddingX: spacing.indent, children: /* @__PURE__ */ jsx43(Text33, { dimColor: true, children: "(no tasks yet)" }) });
|
|
@@ -18169,7 +18183,18 @@ var TasksPanel = ({
|
|
|
18169
18183
|
/* @__PURE__ */ jsx43(OrphanSignals, { signals: bucketed.orphanSignals, max: maxOrphanSignals }),
|
|
18170
18184
|
bucketed.tasks.map((task) => {
|
|
18171
18185
|
const display = nameById?.get(task.id) ?? `${task.id.slice(0, 8)}\u2026`;
|
|
18172
|
-
return /* @__PURE__ */ jsx43(
|
|
18186
|
+
return /* @__PURE__ */ jsx43(
|
|
18187
|
+
TaskBlock,
|
|
18188
|
+
{
|
|
18189
|
+
task,
|
|
18190
|
+
running,
|
|
18191
|
+
display,
|
|
18192
|
+
maxSignals: maxSignalsPerTask,
|
|
18193
|
+
maxSubSteps: maxSubStepsPerTask,
|
|
18194
|
+
maxEvaluations: maxEvaluationsPerTask
|
|
18195
|
+
},
|
|
18196
|
+
task.id
|
|
18197
|
+
);
|
|
18173
18198
|
})
|
|
18174
18199
|
] });
|
|
18175
18200
|
};
|
|
@@ -18480,7 +18505,6 @@ var ExecuteView = () => {
|
|
|
18480
18505
|
filter: (e) => "chainId" in e && e.chainId === sessionId2,
|
|
18481
18506
|
limit: 2e3
|
|
18482
18507
|
});
|
|
18483
|
-
const frame = useSpinnerFrame(session?.descriptor.status === "running");
|
|
18484
18508
|
const term = useTerminalSize();
|
|
18485
18509
|
const isRunning = session?.descriptor.status === "running";
|
|
18486
18510
|
useViewHints(
|
|
@@ -18573,10 +18597,7 @@ var ExecuteView = () => {
|
|
|
18573
18597
|
String(tasksTotal)
|
|
18574
18598
|
] })
|
|
18575
18599
|
] }),
|
|
18576
|
-
isRunning && /* @__PURE__ */ jsx46(Box34, { marginLeft: 2, children: /* @__PURE__ */
|
|
18577
|
-
spinnerGlyph(frame),
|
|
18578
|
-
" live"
|
|
18579
|
-
] }) })
|
|
18600
|
+
isRunning && /* @__PURE__ */ jsx46(Box34, { marginLeft: 2, children: /* @__PURE__ */ jsx46(Spinner, { active: isRunning, color: inkColors.info, label: "live" }) })
|
|
18580
18601
|
] }),
|
|
18581
18602
|
currentTask !== void 0 && currentTaskName !== void 0 && /* @__PURE__ */ jsxs35(Box34, { children: [
|
|
18582
18603
|
/* @__PURE__ */ jsxs35(Text36, { dimColor: true, children: [
|
|
@@ -21120,8 +21141,40 @@ var useGlobalKeys = (opts = {}) => {
|
|
|
21120
21141
|
});
|
|
21121
21142
|
};
|
|
21122
21143
|
|
|
21144
|
+
// src/application/ui/tui/components/memory-pressure-banner.tsx
|
|
21145
|
+
import { useEffect as useEffect34, useState as useState41 } from "react";
|
|
21146
|
+
import { Box as Box49, Text as Text51 } from "ink";
|
|
21147
|
+
import { jsxs as jsxs50 } from "react/jsx-runtime";
|
|
21148
|
+
var formatMb = (bytes) => `${(bytes / 1048576).toFixed(0)} MB`;
|
|
21149
|
+
var formatPercent = (ratio) => `${Math.round(ratio * 100)}%`;
|
|
21150
|
+
var MemoryPressureBanner = () => {
|
|
21151
|
+
const deps = useDeps();
|
|
21152
|
+
const [latest, setLatest] = useState41(void 0);
|
|
21153
|
+
useEffect34(() => {
|
|
21154
|
+
const unsub = deps.eventBus.subscribe((event) => {
|
|
21155
|
+
if (event.type === "memory-pressure") setLatest(event);
|
|
21156
|
+
});
|
|
21157
|
+
return unsub;
|
|
21158
|
+
}, [deps.eventBus]);
|
|
21159
|
+
if (latest === void 0 || latest.severity === "recovered") return null;
|
|
21160
|
+
const tone = latest.severity === "critical" ? inkColors.error : inkColors.warning;
|
|
21161
|
+
const headline = latest.severity === "critical" ? `memory critical \u2014 ${formatPercent(latest.ratio)} of heap; auto-cleared in-memory buffers` : `memory pressure \u2014 ${formatPercent(latest.ratio)} of heap used; consider aborting and restarting`;
|
|
21162
|
+
const detail = `(${formatMb(latest.heapUsed)} / ${formatMb(latest.heapLimit)})`;
|
|
21163
|
+
return /* @__PURE__ */ jsxs50(Box49, { paddingX: spacing.indent, flexDirection: "row", children: [
|
|
21164
|
+
/* @__PURE__ */ jsxs50(Text51, { bold: true, color: tone, children: [
|
|
21165
|
+
glyphs.warningGlyph,
|
|
21166
|
+
" ",
|
|
21167
|
+
headline
|
|
21168
|
+
] }),
|
|
21169
|
+
/* @__PURE__ */ jsxs50(Text51, { dimColor: true, children: [
|
|
21170
|
+
" ",
|
|
21171
|
+
detail
|
|
21172
|
+
] })
|
|
21173
|
+
] });
|
|
21174
|
+
};
|
|
21175
|
+
|
|
21123
21176
|
// src/application/ui/tui/App.tsx
|
|
21124
|
-
import { jsx as jsx62 } from "react/jsx-runtime";
|
|
21177
|
+
import { jsx as jsx62, jsxs as jsxs51 } from "react/jsx-runtime";
|
|
21125
21178
|
var App = ({
|
|
21126
21179
|
deps,
|
|
21127
21180
|
storage: storage2,
|
|
@@ -21144,7 +21197,10 @@ var Layout = ({ children }) => {
|
|
|
21144
21197
|
const ui = useUiState();
|
|
21145
21198
|
const { rows } = useTerminalSize();
|
|
21146
21199
|
useGlobalKeys({ disabled: ui.promptActive });
|
|
21147
|
-
return /* @__PURE__ */
|
|
21200
|
+
return /* @__PURE__ */ jsxs51(Box50, { flexDirection: "column", height: rows, children: [
|
|
21201
|
+
/* @__PURE__ */ jsx62(MemoryPressureBanner, {}),
|
|
21202
|
+
children
|
|
21203
|
+
] });
|
|
21148
21204
|
};
|
|
21149
21205
|
|
|
21150
21206
|
// src/application/ui/tui/launch-routing.ts
|
|
@@ -21228,6 +21284,69 @@ var createLogLevelGate = (initial) => {
|
|
|
21228
21284
|
};
|
|
21229
21285
|
};
|
|
21230
21286
|
|
|
21287
|
+
// src/integration/observability/heap-watchdog.ts
|
|
21288
|
+
import * as v8 from "v8";
|
|
21289
|
+
var MIN_INTERVAL_MS = 1e3;
|
|
21290
|
+
var DEFAULT_INTERVAL_MS = 1e4;
|
|
21291
|
+
var DEFAULT_WARNING_RATIO = 0.8;
|
|
21292
|
+
var DEFAULT_CRITICAL_RATIO = 0.95;
|
|
21293
|
+
var defaultReadHeap = () => {
|
|
21294
|
+
const stats = v8.getHeapStatistics();
|
|
21295
|
+
return { heapUsed: stats.used_heap_size, heapLimit: stats.heap_size_limit };
|
|
21296
|
+
};
|
|
21297
|
+
var classify = (ratio, warning, critical) => {
|
|
21298
|
+
if (ratio >= critical) return "critical";
|
|
21299
|
+
if (ratio >= warning) return "warning";
|
|
21300
|
+
return "ok";
|
|
21301
|
+
};
|
|
21302
|
+
var startHeapWatchdog = (deps) => {
|
|
21303
|
+
const intervalMs = Math.max(MIN_INTERVAL_MS, deps.intervalMs ?? DEFAULT_INTERVAL_MS);
|
|
21304
|
+
const warning = deps.warningRatio ?? DEFAULT_WARNING_RATIO;
|
|
21305
|
+
const critical = deps.criticalRatio ?? DEFAULT_CRITICAL_RATIO;
|
|
21306
|
+
const clock = deps.clock ?? IsoTimestamp.now;
|
|
21307
|
+
const readHeap = deps.readHeap ?? defaultReadHeap;
|
|
21308
|
+
let stopped = false;
|
|
21309
|
+
let previousBand = "ok";
|
|
21310
|
+
const emit = (severity, reading, ratio) => {
|
|
21311
|
+
deps.eventBus.publish({
|
|
21312
|
+
type: "memory-pressure",
|
|
21313
|
+
severity,
|
|
21314
|
+
ratio,
|
|
21315
|
+
heapUsed: reading.heapUsed,
|
|
21316
|
+
heapLimit: reading.heapLimit,
|
|
21317
|
+
at: clock()
|
|
21318
|
+
});
|
|
21319
|
+
};
|
|
21320
|
+
const sample = () => {
|
|
21321
|
+
if (stopped) return;
|
|
21322
|
+
const reading = readHeap();
|
|
21323
|
+
const ratio = reading.heapLimit > 0 ? reading.heapUsed / reading.heapLimit : 0;
|
|
21324
|
+
const band = classify(ratio, warning, critical);
|
|
21325
|
+
if (band === previousBand) return;
|
|
21326
|
+
if (band === "warning") emit("warning", reading, ratio);
|
|
21327
|
+
else if (band === "critical") {
|
|
21328
|
+
emit("critical", reading, ratio);
|
|
21329
|
+
try {
|
|
21330
|
+
deps.onCritical?.();
|
|
21331
|
+
} catch (err) {
|
|
21332
|
+
console.warn("[heap-watchdog] onCritical threw:", err);
|
|
21333
|
+
}
|
|
21334
|
+
} else {
|
|
21335
|
+
emit("recovered", reading, ratio);
|
|
21336
|
+
}
|
|
21337
|
+
previousBand = band;
|
|
21338
|
+
};
|
|
21339
|
+
const handle = setInterval(sample, intervalMs);
|
|
21340
|
+
handle.unref?.();
|
|
21341
|
+
return {
|
|
21342
|
+
stop() {
|
|
21343
|
+
if (stopped) return;
|
|
21344
|
+
stopped = true;
|
|
21345
|
+
clearInterval(handle);
|
|
21346
|
+
}
|
|
21347
|
+
};
|
|
21348
|
+
};
|
|
21349
|
+
|
|
21231
21350
|
// src/application/ui/tui/launch.ts
|
|
21232
21351
|
var bootstrap = async () => {
|
|
21233
21352
|
const paths = resolveStoragePaths();
|
|
@@ -21251,6 +21370,13 @@ var bootstrap = async () => {
|
|
|
21251
21370
|
const unsubLogForward = deps.eventBus.subscribe((event) => {
|
|
21252
21371
|
if (event.type === "log" && passesLogLevel(event.level, logLevelGate.get())) logBus.emit(event);
|
|
21253
21372
|
});
|
|
21373
|
+
const heapWatchdog = startHeapWatchdog({
|
|
21374
|
+
eventBus: deps.eventBus,
|
|
21375
|
+
onCritical: () => {
|
|
21376
|
+
harnessBus.clear();
|
|
21377
|
+
logBus.clear();
|
|
21378
|
+
}
|
|
21379
|
+
});
|
|
21254
21380
|
const sessions = createSessionManager();
|
|
21255
21381
|
const queue = createPromptQueue();
|
|
21256
21382
|
void createInkInteractivePrompt(queue);
|
|
@@ -21287,6 +21413,7 @@ var bootstrap = async () => {
|
|
|
21287
21413
|
drain: () => {
|
|
21288
21414
|
queue.drain(new Error("TUI shutting down"));
|
|
21289
21415
|
unsubLogForward();
|
|
21416
|
+
heapWatchdog.stop();
|
|
21290
21417
|
}
|
|
21291
21418
|
};
|
|
21292
21419
|
};
|
|
@@ -21301,7 +21428,7 @@ var launchTui = async () => {
|
|
|
21301
21428
|
process.exitCode = 1;
|
|
21302
21429
|
return;
|
|
21303
21430
|
}
|
|
21304
|
-
const appElement =
|
|
21431
|
+
const appElement = React66.createElement(App, booted.app);
|
|
21305
21432
|
const host = createInkHost({ appElement });
|
|
21306
21433
|
setRunInTerminal(host.runInTerminal);
|
|
21307
21434
|
try {
|
package/dist/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ralphctl",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.3",
|
|
4
4
|
"description": "Agent harness for long-running AI coding tasks — orchestrates Claude Code & GitHub Copilot across repositories",
|
|
5
5
|
"homepage": "https://github.com/lukas-grigis/ralphctl",
|
|
6
6
|
"type": "module",
|