substrate-ai 0.2.21 → 0.2.23
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/index.js +15 -19
- package/dist/{event-bus-BMxhfxfT.js → errors-CswS7Mzg.js} +93 -715
- package/dist/event-bus-CAvDMst7.js +734 -0
- package/dist/index.js +2 -2
- package/dist/{run-BLIgARum.js → run-BaAws8IQ.js} +180 -39
- package/dist/run-BenC8JuM.js +7 -0
- package/package.json +1 -1
- package/dist/errors-BPqtzQ4U.js +0 -111
- package/dist/run-gmS6DsGT.js +0 -7
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { exec } from "child_process";
|
|
2
2
|
import { promisify } from "util";
|
|
3
|
-
import * as readline from "node:readline";
|
|
4
|
-
import { EventEmitter } from "node:events";
|
|
5
3
|
|
|
6
4
|
//#region src/adapters/claude-adapter.ts
|
|
7
5
|
const execAsync$2 = promisify(exec);
|
|
@@ -816,734 +814,114 @@ var AdapterRegistry = class {
|
|
|
816
814
|
};
|
|
817
815
|
|
|
818
816
|
//#endregion
|
|
819
|
-
//#region src/
|
|
817
|
+
//#region src/core/errors.ts
|
|
820
818
|
/**
|
|
821
|
-
*
|
|
822
|
-
*
|
|
823
|
-
* Provides cursor control, color, and screen manipulation utilities.
|
|
824
|
-
*/
|
|
825
|
-
const ANSI = {
|
|
826
|
-
RESET: "\x1B[0m",
|
|
827
|
-
BOLD: "\x1B[1m",
|
|
828
|
-
DIM: "\x1B[2m",
|
|
829
|
-
BLACK: "\x1B[30m",
|
|
830
|
-
RED: "\x1B[31m",
|
|
831
|
-
GREEN: "\x1B[32m",
|
|
832
|
-
YELLOW: "\x1B[33m",
|
|
833
|
-
BLUE: "\x1B[34m",
|
|
834
|
-
MAGENTA: "\x1B[35m",
|
|
835
|
-
CYAN: "\x1B[36m",
|
|
836
|
-
WHITE: "\x1B[37m",
|
|
837
|
-
BRIGHT_BLACK: "\x1B[90m",
|
|
838
|
-
BRIGHT_RED: "\x1B[91m",
|
|
839
|
-
BRIGHT_GREEN: "\x1B[92m",
|
|
840
|
-
BRIGHT_YELLOW: "\x1B[93m",
|
|
841
|
-
BRIGHT_BLUE: "\x1B[94m",
|
|
842
|
-
BRIGHT_MAGENTA: "\x1B[95m",
|
|
843
|
-
BRIGHT_CYAN: "\x1B[96m",
|
|
844
|
-
BRIGHT_WHITE: "\x1B[97m",
|
|
845
|
-
BG_BLACK: "\x1B[40m",
|
|
846
|
-
BG_WHITE: "\x1B[47m",
|
|
847
|
-
BG_BLUE: "\x1B[44m",
|
|
848
|
-
BG_BRIGHT_BLACK: "\x1B[100m",
|
|
849
|
-
HIDE_CURSOR: "\x1B[?25l",
|
|
850
|
-
SHOW_CURSOR: "\x1B[?25h",
|
|
851
|
-
CLEAR_SCREEN: "\x1B[2J",
|
|
852
|
-
HOME: "\x1B[H",
|
|
853
|
-
CLEAR_LINE: "\x1B[2K",
|
|
854
|
-
ERASE_DOWN: "\x1B[J",
|
|
855
|
-
ALT_SCREEN_ENTER: "\x1B[?1049h",
|
|
856
|
-
ALT_SCREEN_EXIT: "\x1B[?1049l"
|
|
857
|
-
};
|
|
858
|
-
/** Check if color output is supported. */
|
|
859
|
-
function supportsColor(isTTY) {
|
|
860
|
-
if (process.env.NO_COLOR !== void 0) return false;
|
|
861
|
-
return isTTY;
|
|
862
|
-
}
|
|
863
|
-
/** Wrap text with an ANSI color code (only if color is enabled). */
|
|
864
|
-
function colorize(text, code, useColor) {
|
|
865
|
-
if (!useColor) return text;
|
|
866
|
-
return `${code}${text}${ANSI.RESET}`;
|
|
867
|
-
}
|
|
868
|
-
/** Bold text. */
|
|
869
|
-
function bold(text, useColor) {
|
|
870
|
-
if (!useColor) return text;
|
|
871
|
-
return `${ANSI.BOLD}${text}${ANSI.RESET}`;
|
|
872
|
-
}
|
|
873
|
-
/**
|
|
874
|
-
* Get current terminal dimensions.
|
|
875
|
-
* Returns { cols, rows } with fallback defaults if unavailable.
|
|
876
|
-
*/
|
|
877
|
-
function getTerminalSize() {
|
|
878
|
-
const cols = process.stdout.columns ?? 80;
|
|
879
|
-
const rows = process.stdout.rows ?? 24;
|
|
880
|
-
return {
|
|
881
|
-
cols,
|
|
882
|
-
rows
|
|
883
|
-
};
|
|
884
|
-
}
|
|
885
|
-
/**
|
|
886
|
-
* Truncate a string to fit within maxWidth characters.
|
|
887
|
-
* Adds ellipsis if truncated.
|
|
888
|
-
*/
|
|
889
|
-
function truncate(text, maxWidth) {
|
|
890
|
-
if (maxWidth <= 0) return "";
|
|
891
|
-
if (text.length <= maxWidth) return text;
|
|
892
|
-
if (maxWidth <= 3) return text.slice(0, maxWidth);
|
|
893
|
-
return text.slice(0, maxWidth - 3) + "...";
|
|
894
|
-
}
|
|
895
|
-
/**
|
|
896
|
-
* Pad or truncate a string to exactly `width` characters.
|
|
897
|
-
*/
|
|
898
|
-
function padOrTruncate(text, width, padChar = " ") {
|
|
899
|
-
if (text.length > width) return truncate(text, width);
|
|
900
|
-
return text.padEnd(width, padChar);
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
//#endregion
|
|
904
|
-
//#region src/tui/story-panel.ts
|
|
905
|
-
const COL_KEY_WIDTH = 12;
|
|
906
|
-
const COL_PHASE_WIDTH = 8;
|
|
907
|
-
const COL_STATUS_WIDTH = 30;
|
|
908
|
-
/**
|
|
909
|
-
* Get ANSI color code for a story status.
|
|
910
|
-
*/
|
|
911
|
-
function statusColor(status) {
|
|
912
|
-
switch (status) {
|
|
913
|
-
case "pending": return ANSI.BRIGHT_BLACK;
|
|
914
|
-
case "in_progress": return ANSI.YELLOW;
|
|
915
|
-
case "succeeded": return ANSI.GREEN;
|
|
916
|
-
case "failed":
|
|
917
|
-
case "escalated": return ANSI.RED;
|
|
918
|
-
default: return ANSI.RESET;
|
|
919
|
-
}
|
|
920
|
-
}
|
|
921
|
-
/**
|
|
922
|
-
* Get status indicator symbol for a story status.
|
|
923
|
-
*/
|
|
924
|
-
function statusSymbol(status) {
|
|
925
|
-
switch (status) {
|
|
926
|
-
case "pending": return "○";
|
|
927
|
-
case "in_progress": return "◉";
|
|
928
|
-
case "succeeded": return "✓";
|
|
929
|
-
case "failed":
|
|
930
|
-
case "escalated": return "✗";
|
|
931
|
-
default: return "·";
|
|
932
|
-
}
|
|
933
|
-
}
|
|
934
|
-
/**
|
|
935
|
-
* Render the story panel header row.
|
|
936
|
-
*/
|
|
937
|
-
function renderStoryPanelHeader(useColor) {
|
|
938
|
-
const key = padOrTruncate("STORY", COL_KEY_WIDTH);
|
|
939
|
-
const phase = padOrTruncate("PHASE", COL_PHASE_WIDTH);
|
|
940
|
-
const status = "STATUS";
|
|
941
|
-
const header = ` ${key} ${phase} ${status}`;
|
|
942
|
-
return bold(colorize(header, ANSI.BRIGHT_WHITE, useColor), useColor);
|
|
943
|
-
}
|
|
944
|
-
/**
|
|
945
|
-
* Render a single story row.
|
|
946
|
-
*/
|
|
947
|
-
function renderStoryRow(story, isSelected, useColor, width) {
|
|
948
|
-
const symbol = statusSymbol(story.status);
|
|
949
|
-
const color = statusColor(story.status);
|
|
950
|
-
const keyCol = padOrTruncate(story.key, COL_KEY_WIDTH);
|
|
951
|
-
const phaseCol = padOrTruncate(story.phase, COL_PHASE_WIDTH);
|
|
952
|
-
const statusCol = padOrTruncate(story.statusLabel, COL_STATUS_WIDTH);
|
|
953
|
-
const maxWidth = Math.max(width - 2, 10);
|
|
954
|
-
let row = `${symbol} ${keyCol} ${phaseCol} ${statusCol}`;
|
|
955
|
-
row = row.slice(0, maxWidth);
|
|
956
|
-
if (useColor) row = `${color}${row}${ANSI.RESET}`;
|
|
957
|
-
if (isSelected && useColor) row = `${ANSI.BG_BRIGHT_BLACK}${row}${ANSI.RESET}`;
|
|
958
|
-
else if (isSelected) row = `> ${row.slice(2)}`;
|
|
959
|
-
return row;
|
|
960
|
-
}
|
|
961
|
-
/**
|
|
962
|
-
* Render the complete story panel.
|
|
963
|
-
*
|
|
964
|
-
* Returns an array of lines to be written to the terminal.
|
|
965
|
-
*/
|
|
966
|
-
function renderStoryPanel(options) {
|
|
967
|
-
const { stories, selectedIndex, useColor, width } = options;
|
|
968
|
-
const lines = [];
|
|
969
|
-
lines.push(bold(colorize(" Story Status", ANSI.CYAN, useColor), useColor));
|
|
970
|
-
lines.push(renderStoryPanelHeader(useColor));
|
|
971
|
-
lines.push(" " + "─".repeat(Math.max(width - 4, 20)));
|
|
972
|
-
if (stories.length === 0) lines.push(colorize(" (no stories)", ANSI.BRIGHT_BLACK, useColor));
|
|
973
|
-
else for (let i = 0; i < stories.length; i++) {
|
|
974
|
-
const story = stories[i];
|
|
975
|
-
if (story !== void 0) lines.push(renderStoryRow(story, i === selectedIndex, useColor, width));
|
|
976
|
-
}
|
|
977
|
-
return lines;
|
|
978
|
-
}
|
|
979
|
-
|
|
980
|
-
//#endregion
|
|
981
|
-
//#region src/tui/log-panel.ts
|
|
982
|
-
/**
|
|
983
|
-
* Format a log entry timestamp to a short HH:MM:SS format.
|
|
984
|
-
*/
|
|
985
|
-
function formatTimestamp(ts) {
|
|
986
|
-
try {
|
|
987
|
-
const date = new Date(ts);
|
|
988
|
-
const hh = date.getHours().toString().padStart(2, "0");
|
|
989
|
-
const mm = date.getMinutes().toString().padStart(2, "0");
|
|
990
|
-
const ss = date.getSeconds().toString().padStart(2, "0");
|
|
991
|
-
return `${hh}:${mm}:${ss}`;
|
|
992
|
-
} catch {
|
|
993
|
-
return ts.slice(11, 19);
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
/**
|
|
997
|
-
* Render a single log entry line.
|
|
819
|
+
* Error definitions for Substrate
|
|
820
|
+
* Provides structured error hierarchy for all toolkit operations
|
|
998
821
|
*/
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
function renderLogPanel(options) {
|
|
1019
|
-
const { entries, maxLines, useColor, width, filterKey } = options;
|
|
1020
|
-
const lines = [];
|
|
1021
|
-
const title = filterKey !== void 0 ? ` Logs for ${filterKey}` : " Live Logs";
|
|
1022
|
-
lines.push(bold(colorize(title, ANSI.CYAN, useColor), useColor));
|
|
1023
|
-
lines.push(" " + "─".repeat(Math.max(width - 4, 20)));
|
|
1024
|
-
const filtered = filterKey !== void 0 ? entries.filter((e) => e.key === filterKey) : entries;
|
|
1025
|
-
if (filtered.length === 0) {
|
|
1026
|
-
lines.push(colorize(" (no log entries)", ANSI.BRIGHT_BLACK, useColor));
|
|
1027
|
-
return lines;
|
|
1028
|
-
}
|
|
1029
|
-
const visibleEntries = filtered.slice(-maxLines);
|
|
1030
|
-
for (const entry of visibleEntries) lines.push(" " + renderLogEntry(entry, useColor, width - 2));
|
|
1031
|
-
return lines;
|
|
1032
|
-
}
|
|
1033
|
-
|
|
1034
|
-
//#endregion
|
|
1035
|
-
//#region src/tui/detail-view.ts
|
|
1036
|
-
/**
|
|
1037
|
-
* Render the full detail view for a story.
|
|
1038
|
-
*
|
|
1039
|
-
* Returns an array of lines to be written to the terminal.
|
|
1040
|
-
*/
|
|
1041
|
-
function renderDetailView(options) {
|
|
1042
|
-
const { story, allLogs, maxLogLines, useColor, width, height } = options;
|
|
1043
|
-
const lines = [];
|
|
1044
|
-
const titleBar = ` Story Detail: ${story.key}`;
|
|
1045
|
-
lines.push(bold(colorize(titleBar, ANSI.BRIGHT_WHITE, useColor), useColor));
|
|
1046
|
-
lines.push(" " + "═".repeat(Math.max(width - 4, 20)));
|
|
1047
|
-
lines.push("");
|
|
1048
|
-
const phaseLabel = padOrTruncate("Phase:", 12);
|
|
1049
|
-
const statusLabel = padOrTruncate("Status:", 12);
|
|
1050
|
-
const cyclesLabel = padOrTruncate("Review Cycles:", 12);
|
|
1051
|
-
lines.push(` ${bold(phaseLabel, useColor)} ${colorize(story.phase, ANSI.CYAN, useColor)}`);
|
|
1052
|
-
lines.push(` ${bold(statusLabel, useColor)} ${colorize(story.statusLabel, ANSI.WHITE, useColor)}`);
|
|
1053
|
-
lines.push(` ${bold(cyclesLabel, useColor)} ${story.reviewCycles}`);
|
|
1054
|
-
if (story.escalationReason !== void 0) lines.push(` ${bold(padOrTruncate("Escalated:", 12), useColor)} ${colorize(story.escalationReason, ANSI.RED, useColor)}`);
|
|
1055
|
-
lines.push("");
|
|
1056
|
-
lines.push(" " + "─".repeat(Math.max(width - 4, 20)));
|
|
1057
|
-
const availableLogLines = Math.max(height - lines.length - 4, 3);
|
|
1058
|
-
const logLines = renderLogPanel({
|
|
1059
|
-
entries: allLogs,
|
|
1060
|
-
maxLines: Math.min(maxLogLines, availableLogLines),
|
|
1061
|
-
useColor,
|
|
1062
|
-
width,
|
|
1063
|
-
filterKey: story.key
|
|
1064
|
-
});
|
|
1065
|
-
lines.push(...logLines);
|
|
1066
|
-
lines.push("");
|
|
1067
|
-
lines.push(colorize(" [Esc] Back to overview", ANSI.BRIGHT_BLACK, useColor));
|
|
1068
|
-
return lines;
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
//#endregion
|
|
1072
|
-
//#region src/tui/help-overlay.ts
|
|
1073
|
-
/** All keyboard bindings shown in the help overlay. */
|
|
1074
|
-
const KEY_BINDINGS = [
|
|
1075
|
-
{
|
|
1076
|
-
key: "↑ / ↓",
|
|
1077
|
-
description: "Navigate between stories"
|
|
1078
|
-
},
|
|
1079
|
-
{
|
|
1080
|
-
key: "Enter",
|
|
1081
|
-
description: "Drill into selected story detail view"
|
|
1082
|
-
},
|
|
1083
|
-
{
|
|
1084
|
-
key: "Esc",
|
|
1085
|
-
description: "Return to overview from detail view"
|
|
1086
|
-
},
|
|
1087
|
-
{
|
|
1088
|
-
key: "q",
|
|
1089
|
-
description: "Quit TUI (pipeline completes in background)"
|
|
1090
|
-
},
|
|
1091
|
-
{
|
|
1092
|
-
key: "?",
|
|
1093
|
-
description: "Show/hide this help overlay"
|
|
1094
|
-
}
|
|
1095
|
-
];
|
|
1096
|
-
/**
|
|
1097
|
-
* Render the help overlay.
|
|
1098
|
-
*
|
|
1099
|
-
* Returns an array of lines to be written to the terminal.
|
|
1100
|
-
*/
|
|
1101
|
-
function renderHelpOverlay(options) {
|
|
1102
|
-
const { useColor, width } = options;
|
|
1103
|
-
const lines = [];
|
|
1104
|
-
const boxWidth = Math.min(56, Math.max(width - 4, 30));
|
|
1105
|
-
const horizontalBorder = "─".repeat(boxWidth - 2);
|
|
1106
|
-
lines.push(colorize(` ┌${horizontalBorder}┐`, ANSI.CYAN, useColor));
|
|
1107
|
-
lines.push(colorize(` │${padOrTruncate(" Keyboard Shortcuts", boxWidth - 2)}│`, ANSI.CYAN, useColor));
|
|
1108
|
-
lines.push(colorize(` ├${horizontalBorder}┤`, ANSI.CYAN, useColor));
|
|
1109
|
-
for (const binding of KEY_BINDINGS) {
|
|
1110
|
-
const keyPart = bold(padOrTruncate(binding.key, 12), useColor);
|
|
1111
|
-
const descPart = padOrTruncate(binding.description, boxWidth - 16);
|
|
1112
|
-
lines.push(useColor ? `${ANSI.CYAN} │${ANSI.RESET} ${keyPart} ${descPart}${ANSI.CYAN}│${ANSI.RESET}` : ` │ ${keyPart} ${descPart}│`);
|
|
1113
|
-
}
|
|
1114
|
-
lines.push(colorize(` └${horizontalBorder}┘`, ANSI.CYAN, useColor));
|
|
1115
|
-
lines.push(colorize(" Press ? to close", ANSI.BRIGHT_BLACK, useColor));
|
|
1116
|
-
return lines;
|
|
1117
|
-
}
|
|
1118
|
-
|
|
1119
|
-
//#endregion
|
|
1120
|
-
//#region src/tui/app.ts
|
|
1121
|
-
/** Minimum terminal width for TUI to render properly. */
|
|
1122
|
-
const MIN_COLS = 80;
|
|
1123
|
-
/** Minimum terminal height for TUI to render properly. */
|
|
1124
|
-
const MIN_ROWS = 24;
|
|
1125
|
-
/** Maximum log entries to keep in memory. */
|
|
1126
|
-
const MAX_LOG_ENTRIES = 500;
|
|
1127
|
-
function mapPhaseToLabel(phase) {
|
|
1128
|
-
switch (phase) {
|
|
1129
|
-
case "create-story": return "create";
|
|
1130
|
-
case "dev-story": return "dev";
|
|
1131
|
-
case "code-review": return "review";
|
|
1132
|
-
case "fix": return "fix";
|
|
1133
|
-
default: return "wait";
|
|
1134
|
-
}
|
|
1135
|
-
}
|
|
1136
|
-
function mapPhaseToStatus(phase, eventStatus) {
|
|
1137
|
-
if (eventStatus === "failed") return "failed";
|
|
1138
|
-
if (eventStatus === "in_progress") return "in_progress";
|
|
1139
|
-
if (eventStatus === "complete") {
|
|
1140
|
-
if (phase === "done") return "succeeded";
|
|
1141
|
-
return "in_progress";
|
|
1142
|
-
}
|
|
1143
|
-
return "pending";
|
|
1144
|
-
}
|
|
1145
|
-
function makeStatusLabel(phase, eventStatus, verdict) {
|
|
1146
|
-
if (eventStatus === "failed") return "failed";
|
|
1147
|
-
if (eventStatus === "in_progress") switch (phase) {
|
|
1148
|
-
case "create": return "creating story...";
|
|
1149
|
-
case "dev": return "implementing...";
|
|
1150
|
-
case "review": return "reviewing...";
|
|
1151
|
-
case "fix": return "fixing issues...";
|
|
1152
|
-
default: return "in progress...";
|
|
1153
|
-
}
|
|
1154
|
-
if (eventStatus === "complete") switch (phase) {
|
|
1155
|
-
case "create": return "story created";
|
|
1156
|
-
case "dev": return "implemented";
|
|
1157
|
-
case "review": return verdict !== void 0 ? `reviewed (${verdict})` : "reviewed";
|
|
1158
|
-
case "fix": return "fixes applied";
|
|
1159
|
-
default: return "complete";
|
|
1160
|
-
}
|
|
1161
|
-
return "queued";
|
|
1162
|
-
}
|
|
1163
|
-
/**
|
|
1164
|
-
* Factory that creates a TUI application instance.
|
|
1165
|
-
*
|
|
1166
|
-
* @param output - Writable stream for rendering (typically process.stdout)
|
|
1167
|
-
* @param input - Readable stream for keyboard input (typically process.stdin)
|
|
1168
|
-
*/
|
|
1169
|
-
function createTuiApp(output, input) {
|
|
1170
|
-
const isTTY = output.isTTY === true;
|
|
1171
|
-
const useColor = supportsColor(isTTY);
|
|
1172
|
-
const state = {
|
|
1173
|
-
headerLine: "",
|
|
1174
|
-
storyOrder: [],
|
|
1175
|
-
stories: new Map(),
|
|
1176
|
-
logs: [],
|
|
1177
|
-
selectedIndex: 0,
|
|
1178
|
-
view: "overview",
|
|
1179
|
-
pipelineComplete: false
|
|
1180
|
-
};
|
|
1181
|
-
let exitResolve;
|
|
1182
|
-
const exitPromise = new Promise((resolve) => {
|
|
1183
|
-
exitResolve = resolve;
|
|
1184
|
-
});
|
|
1185
|
-
let rl;
|
|
1186
|
-
function write(text) {
|
|
1187
|
-
try {
|
|
1188
|
-
output.write(text);
|
|
1189
|
-
} catch {}
|
|
822
|
+
/** Base error class for all Substrate errors */
|
|
823
|
+
var AdtError = class AdtError extends Error {
|
|
824
|
+
code;
|
|
825
|
+
context;
|
|
826
|
+
constructor(message, code, context = {}) {
|
|
827
|
+
super(message);
|
|
828
|
+
this.name = "AdtError";
|
|
829
|
+
this.code = code;
|
|
830
|
+
this.context = context;
|
|
831
|
+
if (Error.captureStackTrace) Error.captureStackTrace(this, AdtError);
|
|
832
|
+
}
|
|
833
|
+
toJSON() {
|
|
834
|
+
return {
|
|
835
|
+
name: this.name,
|
|
836
|
+
message: this.message,
|
|
837
|
+
code: this.code,
|
|
838
|
+
context: this.context,
|
|
839
|
+
stack: this.stack
|
|
840
|
+
};
|
|
1190
841
|
}
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
return false;
|
|
1198
|
-
}
|
|
1199
|
-
return true;
|
|
842
|
+
};
|
|
843
|
+
/** Error thrown when task configuration is invalid */
|
|
844
|
+
var TaskConfigError = class extends AdtError {
|
|
845
|
+
constructor(message, context = {}) {
|
|
846
|
+
super(message, "TASK_CONFIG_ERROR", context);
|
|
847
|
+
this.name = "TaskConfigError";
|
|
1200
848
|
}
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
write(ANSI.CLEAR_SCREEN + ANSI.HOME);
|
|
1208
|
-
const lines = [];
|
|
1209
|
-
if (state.view === "help") renderHelpView(lines, cols, rows);
|
|
1210
|
-
else if (state.view === "detail") renderDetailViewLayout(lines, cols, rows);
|
|
1211
|
-
else renderOverviewLayout(lines, cols, rows);
|
|
1212
|
-
for (const line of lines) write(line + "\n");
|
|
849
|
+
};
|
|
850
|
+
/** Error thrown when a worker/agent operation fails */
|
|
851
|
+
var WorkerError = class extends AdtError {
|
|
852
|
+
constructor(message, context = {}) {
|
|
853
|
+
super(message, "WORKER_ERROR", context);
|
|
854
|
+
this.name = "WorkerError";
|
|
1213
855
|
}
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
stories: Array.from(state.storyOrder).map((k) => state.stories.get(k)).filter((s) => s !== void 0),
|
|
1221
|
-
selectedIndex: state.selectedIndex,
|
|
1222
|
-
useColor,
|
|
1223
|
-
width: cols
|
|
1224
|
-
});
|
|
1225
|
-
lines.push(...storyPanelLines.slice(0, storyPanelHeight));
|
|
1226
|
-
lines.push("");
|
|
1227
|
-
lines.push(" " + "─".repeat(Math.max(cols - 4, 20)));
|
|
1228
|
-
lines.push("");
|
|
1229
|
-
const usedLines = lines.length + 3;
|
|
1230
|
-
const logPanelHeight = Math.max(rows - usedLines, 3);
|
|
1231
|
-
const logLines = renderLogPanel({
|
|
1232
|
-
entries: state.logs,
|
|
1233
|
-
maxLines: logPanelHeight,
|
|
1234
|
-
useColor,
|
|
1235
|
-
width: cols
|
|
1236
|
-
});
|
|
1237
|
-
lines.push(...logLines);
|
|
1238
|
-
lines.push("");
|
|
1239
|
-
const footerParts = [
|
|
1240
|
-
colorize("[↑↓] Navigate", ANSI.BRIGHT_BLACK, useColor),
|
|
1241
|
-
colorize("[Enter] Details", ANSI.BRIGHT_BLACK, useColor),
|
|
1242
|
-
colorize("[q] Quit", ANSI.BRIGHT_BLACK, useColor),
|
|
1243
|
-
colorize("[?] Help", ANSI.BRIGHT_BLACK, useColor)
|
|
1244
|
-
];
|
|
1245
|
-
if (state.pipelineComplete) lines.push(colorize(" Pipeline complete. Press q to exit.", ANSI.GREEN, useColor));
|
|
1246
|
-
lines.push(" " + footerParts.join(" "));
|
|
856
|
+
};
|
|
857
|
+
/** Error thrown when a worker/agent cannot be found */
|
|
858
|
+
var WorkerNotFoundError = class extends AdtError {
|
|
859
|
+
constructor(agentId) {
|
|
860
|
+
super(`Worker agent not found: ${agentId}`, "WORKER_NOT_FOUND", { agentId });
|
|
861
|
+
this.name = "WorkerNotFoundError";
|
|
1247
862
|
}
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
}
|
|
1255
|
-
const detailLines = renderDetailView({
|
|
1256
|
-
story,
|
|
1257
|
-
allLogs: state.logs,
|
|
1258
|
-
maxLogLines: Math.max(rows - 10, 5),
|
|
1259
|
-
useColor,
|
|
1260
|
-
width: cols,
|
|
1261
|
-
height: rows
|
|
1262
|
-
});
|
|
1263
|
-
lines.push(...detailLines);
|
|
863
|
+
};
|
|
864
|
+
/** Error thrown when a task graph is invalid */
|
|
865
|
+
var TaskGraphError = class extends AdtError {
|
|
866
|
+
constructor(message, context = {}) {
|
|
867
|
+
super(message, "TASK_GRAPH_ERROR", context);
|
|
868
|
+
this.name = "TaskGraphError";
|
|
1264
869
|
}
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
});
|
|
1272
|
-
lines.push(...helpLines);
|
|
870
|
+
};
|
|
871
|
+
/** Error thrown when a task graph has cycles (deadlock) */
|
|
872
|
+
var TaskGraphCycleError = class extends TaskGraphError {
|
|
873
|
+
constructor(cycle) {
|
|
874
|
+
super(`Circular dependency detected in task graph: ${cycle.join(" -> ")}`, { cycle });
|
|
875
|
+
this.name = "TaskGraphCycleError";
|
|
1273
876
|
}
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
readline.emitKeypressEvents(input);
|
|
1283
|
-
const stdin = input;
|
|
1284
|
-
const onKeypress = (chunk, key) => {
|
|
1285
|
-
if (key === void 0) return;
|
|
1286
|
-
handleKeypress(key);
|
|
1287
|
-
};
|
|
1288
|
-
stdin.on("keypress", onKeypress);
|
|
1289
|
-
rl.on("close", () => {
|
|
1290
|
-
exit();
|
|
877
|
+
};
|
|
878
|
+
/** Error thrown when a budget limit is exceeded */
|
|
879
|
+
var BudgetExceededError = class extends AdtError {
|
|
880
|
+
constructor(limit, current, context = {}) {
|
|
881
|
+
super(`Budget cap exceeded: current=${String(current)}, limit=${String(limit)}`, "BUDGET_EXCEEDED", {
|
|
882
|
+
limit,
|
|
883
|
+
current,
|
|
884
|
+
...context
|
|
1291
885
|
});
|
|
886
|
+
this.name = "BudgetExceededError";
|
|
1292
887
|
}
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
case "q":
|
|
1300
|
-
exit();
|
|
1301
|
-
return;
|
|
1302
|
-
case "up":
|
|
1303
|
-
if (state.view === "overview") {
|
|
1304
|
-
state.selectedIndex = Math.max(0, state.selectedIndex - 1);
|
|
1305
|
-
render();
|
|
1306
|
-
}
|
|
1307
|
-
break;
|
|
1308
|
-
case "down":
|
|
1309
|
-
if (state.view === "overview") {
|
|
1310
|
-
state.selectedIndex = Math.min(Math.max(0, state.storyOrder.length - 1), state.selectedIndex + 1);
|
|
1311
|
-
render();
|
|
1312
|
-
}
|
|
1313
|
-
break;
|
|
1314
|
-
case "return":
|
|
1315
|
-
case "enter":
|
|
1316
|
-
if (state.view === "overview" && state.storyOrder.length > 0) {
|
|
1317
|
-
state.view = "detail";
|
|
1318
|
-
render();
|
|
1319
|
-
}
|
|
1320
|
-
break;
|
|
1321
|
-
case "escape":
|
|
1322
|
-
if (state.view === "detail" || state.view === "help") {
|
|
1323
|
-
state.view = "overview";
|
|
1324
|
-
render();
|
|
1325
|
-
}
|
|
1326
|
-
break;
|
|
1327
|
-
case "?":
|
|
1328
|
-
state.view = state.view === "help" ? "overview" : "help";
|
|
1329
|
-
render();
|
|
1330
|
-
break;
|
|
1331
|
-
default:
|
|
1332
|
-
if (key.sequence === "?") {
|
|
1333
|
-
state.view = state.view === "help" ? "overview" : "help";
|
|
1334
|
-
render();
|
|
1335
|
-
}
|
|
1336
|
-
break;
|
|
1337
|
-
}
|
|
1338
|
-
}
|
|
1339
|
-
function onResize() {
|
|
1340
|
-
render();
|
|
1341
|
-
}
|
|
1342
|
-
function init() {
|
|
1343
|
-
write(ANSI.ALT_SCREEN_ENTER);
|
|
1344
|
-
write(ANSI.HIDE_CURSOR);
|
|
1345
|
-
setupKeyboard();
|
|
1346
|
-
const resizeEmitter = typeof output.on === "function" ? output : process.stdout;
|
|
1347
|
-
resizeEmitter.on("resize", onResize);
|
|
1348
|
-
render();
|
|
1349
|
-
}
|
|
1350
|
-
function exit() {
|
|
1351
|
-
cleanup();
|
|
1352
|
-
if (exitResolve !== void 0) {
|
|
1353
|
-
exitResolve();
|
|
1354
|
-
exitResolve = void 0;
|
|
1355
|
-
}
|
|
1356
|
-
}
|
|
1357
|
-
function cleanup() {
|
|
1358
|
-
write(ANSI.SHOW_CURSOR);
|
|
1359
|
-
write(ANSI.ALT_SCREEN_EXIT);
|
|
1360
|
-
const resizeEmitter = typeof output.on === "function" ? output : process.stdout;
|
|
1361
|
-
resizeEmitter.off("resize", onResize);
|
|
1362
|
-
if (rl !== void 0) {
|
|
1363
|
-
try {
|
|
1364
|
-
rl.close();
|
|
1365
|
-
} catch {}
|
|
1366
|
-
rl = void 0;
|
|
1367
|
-
}
|
|
1368
|
-
if (input.isTTY === true) try {
|
|
1369
|
-
input.setRawMode(false);
|
|
1370
|
-
} catch {}
|
|
1371
|
-
}
|
|
1372
|
-
function handleEvent(event) {
|
|
1373
|
-
switch (event.type) {
|
|
1374
|
-
case "pipeline:start":
|
|
1375
|
-
state.headerLine = `${event.stories.length} stories, concurrency ${event.concurrency}, run ${event.run_id.slice(0, 8)}...`;
|
|
1376
|
-
for (const key of event.stories) {
|
|
1377
|
-
state.storyOrder.push(key);
|
|
1378
|
-
state.stories.set(key, {
|
|
1379
|
-
key,
|
|
1380
|
-
phase: "wait",
|
|
1381
|
-
status: "pending",
|
|
1382
|
-
statusLabel: "queued",
|
|
1383
|
-
reviewCycles: 0
|
|
1384
|
-
});
|
|
1385
|
-
}
|
|
1386
|
-
break;
|
|
1387
|
-
case "story:phase": {
|
|
1388
|
-
let story = state.stories.get(event.key);
|
|
1389
|
-
if (story === void 0) {
|
|
1390
|
-
state.storyOrder.push(event.key);
|
|
1391
|
-
story = {
|
|
1392
|
-
key: event.key,
|
|
1393
|
-
phase: "wait",
|
|
1394
|
-
status: "pending",
|
|
1395
|
-
statusLabel: "queued",
|
|
1396
|
-
reviewCycles: 0
|
|
1397
|
-
};
|
|
1398
|
-
state.stories.set(event.key, story);
|
|
1399
|
-
}
|
|
1400
|
-
const phaseLabel = mapPhaseToLabel(event.phase);
|
|
1401
|
-
story.phase = phaseLabel;
|
|
1402
|
-
story.status = mapPhaseToStatus(phaseLabel, event.status);
|
|
1403
|
-
story.statusLabel = makeStatusLabel(phaseLabel, event.status, event.verdict);
|
|
1404
|
-
break;
|
|
1405
|
-
}
|
|
1406
|
-
case "story:done": {
|
|
1407
|
-
let story = state.stories.get(event.key);
|
|
1408
|
-
if (story === void 0) {
|
|
1409
|
-
state.storyOrder.push(event.key);
|
|
1410
|
-
story = {
|
|
1411
|
-
key: event.key,
|
|
1412
|
-
phase: "done",
|
|
1413
|
-
status: event.result === "success" ? "succeeded" : "failed",
|
|
1414
|
-
statusLabel: event.result === "success" ? "SHIP_IT" : "FAILED",
|
|
1415
|
-
reviewCycles: event.review_cycles
|
|
1416
|
-
};
|
|
1417
|
-
state.stories.set(event.key, story);
|
|
1418
|
-
} else {
|
|
1419
|
-
story.phase = event.result === "success" ? "done" : "failed";
|
|
1420
|
-
story.status = event.result === "success" ? "succeeded" : "failed";
|
|
1421
|
-
const cycleWord = event.review_cycles === 1 ? "cycle" : "cycles";
|
|
1422
|
-
story.statusLabel = event.result === "success" ? `SHIP_IT (${event.review_cycles} ${cycleWord})` : "FAILED";
|
|
1423
|
-
story.reviewCycles = event.review_cycles;
|
|
1424
|
-
}
|
|
1425
|
-
break;
|
|
1426
|
-
}
|
|
1427
|
-
case "story:escalation": {
|
|
1428
|
-
let story = state.stories.get(event.key);
|
|
1429
|
-
if (story === void 0) {
|
|
1430
|
-
state.storyOrder.push(event.key);
|
|
1431
|
-
story = {
|
|
1432
|
-
key: event.key,
|
|
1433
|
-
phase: "escalated",
|
|
1434
|
-
status: "escalated",
|
|
1435
|
-
statusLabel: `ESCALATED — ${event.reason}`,
|
|
1436
|
-
reviewCycles: event.cycles,
|
|
1437
|
-
escalationReason: event.reason
|
|
1438
|
-
};
|
|
1439
|
-
state.stories.set(event.key, story);
|
|
1440
|
-
} else {
|
|
1441
|
-
story.phase = "escalated";
|
|
1442
|
-
story.status = "escalated";
|
|
1443
|
-
story.statusLabel = `ESCALATED — ${event.reason}`;
|
|
1444
|
-
story.reviewCycles = event.cycles;
|
|
1445
|
-
story.escalationReason = event.reason;
|
|
1446
|
-
}
|
|
1447
|
-
break;
|
|
1448
|
-
}
|
|
1449
|
-
case "story:warn": {
|
|
1450
|
-
const logEntry = {
|
|
1451
|
-
ts: event.ts,
|
|
1452
|
-
key: event.key,
|
|
1453
|
-
msg: `[WARN] ${event.msg}`,
|
|
1454
|
-
level: "warn"
|
|
1455
|
-
};
|
|
1456
|
-
state.logs.push(logEntry);
|
|
1457
|
-
if (state.logs.length > MAX_LOG_ENTRIES) state.logs.splice(0, state.logs.length - MAX_LOG_ENTRIES);
|
|
1458
|
-
break;
|
|
1459
|
-
}
|
|
1460
|
-
case "story:log": {
|
|
1461
|
-
const logEntry = {
|
|
1462
|
-
ts: event.ts,
|
|
1463
|
-
key: event.key,
|
|
1464
|
-
msg: event.msg,
|
|
1465
|
-
level: "log"
|
|
1466
|
-
};
|
|
1467
|
-
state.logs.push(logEntry);
|
|
1468
|
-
if (state.logs.length > MAX_LOG_ENTRIES) state.logs.splice(0, state.logs.length - MAX_LOG_ENTRIES);
|
|
1469
|
-
break;
|
|
1470
|
-
}
|
|
1471
|
-
case "pipeline:complete":
|
|
1472
|
-
state.pipelineComplete = true;
|
|
1473
|
-
state.completionStats = {
|
|
1474
|
-
succeeded: event.succeeded,
|
|
1475
|
-
failed: event.failed,
|
|
1476
|
-
escalated: event.escalated
|
|
1477
|
-
};
|
|
1478
|
-
setTimeout(() => {
|
|
1479
|
-
if (exitResolve !== void 0) render();
|
|
1480
|
-
}, 500);
|
|
1481
|
-
break;
|
|
1482
|
-
default: break;
|
|
1483
|
-
}
|
|
1484
|
-
render();
|
|
888
|
+
};
|
|
889
|
+
/** Error thrown when git operations fail */
|
|
890
|
+
var GitError = class extends AdtError {
|
|
891
|
+
constructor(message, context = {}) {
|
|
892
|
+
super(message, "GIT_ERROR", context);
|
|
893
|
+
this.name = "GitError";
|
|
1485
894
|
}
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
}
|
|
1493
|
-
/**
|
|
1494
|
-
* Check whether the TUI can run in the current environment.
|
|
1495
|
-
*
|
|
1496
|
-
* Returns true if stdout is a TTY, false otherwise.
|
|
1497
|
-
* If false, the caller should print a warning and use default output.
|
|
1498
|
-
*/
|
|
1499
|
-
function isTuiCapable() {
|
|
1500
|
-
return process.stdout.isTTY === true;
|
|
1501
|
-
}
|
|
1502
|
-
/**
|
|
1503
|
-
* Print the non-TTY fallback warning message.
|
|
1504
|
-
*/
|
|
1505
|
-
function printNonTtyWarning() {
|
|
1506
|
-
process.stderr.write("TUI requires an interactive terminal. Falling back to default output.\n");
|
|
1507
|
-
}
|
|
1508
|
-
|
|
1509
|
-
//#endregion
|
|
1510
|
-
//#region src/core/event-bus.ts
|
|
1511
|
-
/**
|
|
1512
|
-
* Concrete implementation of TypedEventBus backed by Node.js EventEmitter.
|
|
1513
|
-
*
|
|
1514
|
-
* @example
|
|
1515
|
-
* const bus = new TypedEventBusImpl()
|
|
1516
|
-
* bus.on('task:complete', ({ taskId, result }) => {
|
|
1517
|
-
* console.log(`Task ${taskId} finished`)
|
|
1518
|
-
* })
|
|
1519
|
-
* bus.emit('task:complete', { taskId: 'abc', result: { exitCode: 0 } })
|
|
1520
|
-
*/
|
|
1521
|
-
var TypedEventBusImpl = class {
|
|
1522
|
-
_emitter;
|
|
1523
|
-
constructor() {
|
|
1524
|
-
this._emitter = new EventEmitter();
|
|
1525
|
-
this._emitter.setMaxListeners(100);
|
|
895
|
+
};
|
|
896
|
+
/** Error thrown when configuration is invalid or missing */
|
|
897
|
+
var ConfigError = class extends AdtError {
|
|
898
|
+
constructor(message, context = {}) {
|
|
899
|
+
super(message, "CONFIG_ERROR", context);
|
|
900
|
+
this.name = "ConfigError";
|
|
1526
901
|
}
|
|
1527
|
-
|
|
1528
|
-
|
|
902
|
+
};
|
|
903
|
+
/** Error thrown when state recovery fails */
|
|
904
|
+
var RecoveryError = class extends AdtError {
|
|
905
|
+
constructor(message, context = {}) {
|
|
906
|
+
super(message, "RECOVERY_ERROR", context);
|
|
907
|
+
this.name = "RecoveryError";
|
|
1529
908
|
}
|
|
1530
|
-
|
|
1531
|
-
|
|
909
|
+
};
|
|
910
|
+
/** Error thrown when a config file uses an incompatible format version */
|
|
911
|
+
var ConfigIncompatibleFormatError = class extends AdtError {
|
|
912
|
+
constructor(message, context = {}) {
|
|
913
|
+
super(message, "CONFIG_INCOMPATIBLE_FORMAT", context);
|
|
914
|
+
this.name = "ConfigIncompatibleFormatError";
|
|
1532
915
|
}
|
|
1533
|
-
|
|
1534
|
-
|
|
916
|
+
};
|
|
917
|
+
/** Error thrown when a task graph file uses an incompatible format version */
|
|
918
|
+
var TaskGraphIncompatibleFormatError = class extends AdtError {
|
|
919
|
+
constructor(message, context = {}) {
|
|
920
|
+
super(message, "TASK_GRAPH_INCOMPATIBLE_FORMAT", context);
|
|
921
|
+
this.name = "TaskGraphIncompatibleFormatError";
|
|
1535
922
|
}
|
|
1536
923
|
};
|
|
1537
|
-
/**
|
|
1538
|
-
* Create a new TypedEventBus instance.
|
|
1539
|
-
*
|
|
1540
|
-
* @example
|
|
1541
|
-
* const bus = createEventBus()
|
|
1542
|
-
*/
|
|
1543
|
-
function createEventBus() {
|
|
1544
|
-
return new TypedEventBusImpl();
|
|
1545
|
-
}
|
|
1546
924
|
|
|
1547
925
|
//#endregion
|
|
1548
|
-
export { AdapterRegistry, ClaudeCodeAdapter, CodexCLIAdapter, GeminiCLIAdapter,
|
|
1549
|
-
//# sourceMappingURL=
|
|
926
|
+
export { AdapterRegistry, AdtError, BudgetExceededError, ClaudeCodeAdapter, CodexCLIAdapter, ConfigError, ConfigIncompatibleFormatError, GeminiCLIAdapter, GitError, RecoveryError, TaskConfigError, TaskGraphCycleError, TaskGraphError, TaskGraphIncompatibleFormatError, WorkerError, WorkerNotFoundError };
|
|
927
|
+
//# sourceMappingURL=errors-CswS7Mzg.js.map
|