@h-rig/cli 0.0.6-alpha.77 → 0.0.6-alpha.78
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/bin/rig.js +10165 -9284
- package/dist/src/app/board.js +1783 -0
- package/dist/src/app/drone-ui.js +294 -0
- package/dist/src/{commands/_tui-theme.js → app/theme.js} +16 -1
- package/dist/src/commands/_async-ui.js +74 -3
- package/dist/src/commands/_cli-format.js +26 -8
- package/dist/src/commands/_doctor-checks.js +3 -1
- package/dist/src/commands/_help-catalog.js +8 -70
- package/dist/src/commands/_operator-view.js +184 -7
- package/dist/src/commands/_pi-frontend.js +184 -7
- package/dist/src/commands/_preflight.js +3 -1
- package/dist/src/commands/_server-client.js +3 -1
- package/dist/src/commands/_snapshot-upload.js +3 -1
- package/dist/src/commands/_task-picker.js +132 -7
- package/dist/src/commands/browser.js +306 -30
- package/dist/src/commands/connect.js +130 -64
- package/dist/src/commands/doctor.js +77 -4
- package/dist/src/commands/github.js +77 -4
- package/dist/src/commands/inbox.js +101 -78
- package/dist/src/commands/init.js +349 -9
- package/dist/src/commands/inspect.js +77 -4
- package/dist/src/commands/run.js +195 -69
- package/dist/src/commands/server.js +133 -65
- package/dist/src/commands/setup.js +77 -4
- package/dist/src/commands/stats.js +56 -113
- package/dist/src/commands/task-report-bug.js +231 -40
- package/dist/src/commands/task-run-driver.js +3 -1
- package/dist/src/commands/task.js +340 -229
- package/dist/src/commands.js +10159 -9278
- package/dist/src/index.js +10161 -9280
- package/package.json +8 -9
- package/dist/src/commands/_operator-board.js +0 -730
|
@@ -311,7 +311,9 @@ ${failure.contextLine}`, 1, { hint: failure.hint });
|
|
|
311
311
|
})() : null;
|
|
312
312
|
if (!response.ok) {
|
|
313
313
|
const diagnostics = diagnosticMessage(payload);
|
|
314
|
-
const
|
|
314
|
+
const rawDetail = diagnostics ?? (text || response.statusText);
|
|
315
|
+
const detail = diagnostics ? rawDetail : rawDetail.split(`
|
|
316
|
+
`).map((line) => line.trim()).find((line) => line.length > 0)?.slice(0, 200) ?? response.statusText;
|
|
315
317
|
const failure = await buildServerFailureContext(context.projectRoot, server);
|
|
316
318
|
throw new CliError(`Rig server request failed (${response.status}): ${detail}
|
|
317
319
|
${failure.contextLine}`, 1, { hint: failure.hint });
|
|
@@ -569,8 +571,8 @@ function createOperatorSurface(options = {}) {
|
|
|
569
571
|
}
|
|
570
572
|
|
|
571
573
|
// packages/cli/src/commands/_pi-frontend.ts
|
|
572
|
-
import { mkdtempSync, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
573
|
-
import { tmpdir } from "os";
|
|
574
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, mkdtempSync, readFileSync as readFileSync3, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
575
|
+
import { homedir as homedir2, tmpdir } from "os";
|
|
574
576
|
import { join } from "path";
|
|
575
577
|
import { main as runPiMain } from "@earendil-works/pi-coding-agent";
|
|
576
578
|
import createPiRigExtension from "@rig/pi-rig";
|
|
@@ -639,8 +641,79 @@ function createTtySpinner(input) {
|
|
|
639
641
|
};
|
|
640
642
|
}
|
|
641
643
|
|
|
644
|
+
// packages/cli/src/app/theme.ts
|
|
645
|
+
var RIG_PALETTE = {
|
|
646
|
+
ink: "#f2f3f6",
|
|
647
|
+
ink2: "#aeb0ba",
|
|
648
|
+
ink3: "#6c6e79",
|
|
649
|
+
ink4: "#44464f",
|
|
650
|
+
accent: "#ccff4d",
|
|
651
|
+
accentDim: "#a9d63f",
|
|
652
|
+
cyan: "#56d8ff",
|
|
653
|
+
red: "#ff5d5d",
|
|
654
|
+
yellow: "#ffd24d"
|
|
655
|
+
};
|
|
656
|
+
function hexToRgb(hex) {
|
|
657
|
+
const value = hex.replace("#", "");
|
|
658
|
+
return [
|
|
659
|
+
Number.parseInt(value.slice(0, 2), 16),
|
|
660
|
+
Number.parseInt(value.slice(2, 4), 16),
|
|
661
|
+
Number.parseInt(value.slice(4, 6), 16)
|
|
662
|
+
];
|
|
663
|
+
}
|
|
664
|
+
function fg(hex) {
|
|
665
|
+
const [r, g, b] = hexToRgb(hex);
|
|
666
|
+
return (text) => `\x1B[38;2;${r};${g};${b}m${text}\x1B[39m`;
|
|
667
|
+
}
|
|
668
|
+
var ink = fg(RIG_PALETTE.ink);
|
|
669
|
+
var ink2 = fg(RIG_PALETTE.ink2);
|
|
670
|
+
var ink3 = fg(RIG_PALETTE.ink3);
|
|
671
|
+
var ink4 = fg(RIG_PALETTE.ink4);
|
|
672
|
+
var accent = fg(RIG_PALETTE.accent);
|
|
673
|
+
var accentDim = fg(RIG_PALETTE.accentDim);
|
|
674
|
+
var cyan = fg(RIG_PALETTE.cyan);
|
|
675
|
+
var red = fg(RIG_PALETTE.red);
|
|
676
|
+
var yellow = fg(RIG_PALETTE.yellow);
|
|
677
|
+
function bold(text) {
|
|
678
|
+
return `\x1B[1m${text}\x1B[22m`;
|
|
679
|
+
}
|
|
680
|
+
var DRONE_ART = [
|
|
681
|
+
" .-=-. .-=-. ",
|
|
682
|
+
" ( !!! ) ( !!! ) ",
|
|
683
|
+
" '-=-'._ _.'-=-' ",
|
|
684
|
+
" '._ _.' ",
|
|
685
|
+
" '=$$$$$$$=.' ",
|
|
686
|
+
" =$$$$$$$$$$$= ",
|
|
687
|
+
" $$$@@@@@@@@@@$$$ ",
|
|
688
|
+
" $$$@@ @@$$$ ",
|
|
689
|
+
" $$@ ? @$$$ ",
|
|
690
|
+
" $$$@ '-' @$$$ ",
|
|
691
|
+
" $$$@@ @@$$$ ",
|
|
692
|
+
" $$$@@@@@@@@@@$$$ ",
|
|
693
|
+
" =$$$$$$$$$$$= ",
|
|
694
|
+
" '=$$$$$$$=.' ",
|
|
695
|
+
" _.' '._ ",
|
|
696
|
+
" .-=-.' '.-=-. ",
|
|
697
|
+
" ( !!! ) ( !!! ) ",
|
|
698
|
+
" '-=-' '-=-' "
|
|
699
|
+
];
|
|
700
|
+
var EYE_FRAMES = ["@", "o", "."];
|
|
701
|
+
var DRONE_WIDTH = DRONE_ART[0].length;
|
|
702
|
+
var DRONE_HEIGHT = DRONE_ART.length;
|
|
703
|
+
var MICRO_BLADES = ["---", "\\\\\\", "|||", "///"];
|
|
704
|
+
function microDroneFrame(tick) {
|
|
705
|
+
const blade = MICRO_BLADES[tick % MICRO_BLADES.length];
|
|
706
|
+
const eye = EYE_FRAMES[Math.floor(tick / 2) % EYE_FRAMES.length];
|
|
707
|
+
return `(${blade})${eye}(${blade})`;
|
|
708
|
+
}
|
|
709
|
+
var MICRO_DRONE_FRAMES = Array.from({ length: 12 }, (_, index) => microDroneFrame(index));
|
|
710
|
+
function renderMicroDroneFrame(tick) {
|
|
711
|
+
const blade = MICRO_BLADES[tick % MICRO_BLADES.length];
|
|
712
|
+
const eye = EYE_FRAMES[Math.floor(tick / 2) % EYE_FRAMES.length];
|
|
713
|
+
return `${ink4("(")}${cyan(blade)}${ink4(")")}${bold(accent(eye))}${ink4("(")}${cyan(blade)}${ink4(")")}`;
|
|
714
|
+
}
|
|
715
|
+
|
|
642
716
|
// packages/cli/src/commands/_async-ui.ts
|
|
643
|
-
var CLACK_SPINNER_FRAMES = ["\u25D2", "\u25D0", "\u25D3", "\u25D1"];
|
|
644
717
|
var DONE_SYMBOL = pc.green("\u25C7");
|
|
645
718
|
var FAIL_SYMBOL = pc.red("\u25A0");
|
|
646
719
|
var activeUpdate = null;
|
|
@@ -674,8 +747,8 @@ async function withSpinner(label, work, options = {}) {
|
|
|
674
747
|
const spinner = createTtySpinner({
|
|
675
748
|
label,
|
|
676
749
|
output,
|
|
677
|
-
frames:
|
|
678
|
-
styleFrame: (frame) =>
|
|
750
|
+
frames: MICRO_DRONE_FRAMES,
|
|
751
|
+
styleFrame: (frame) => renderMicroDroneFrame(Math.max(0, MICRO_DRONE_FRAMES.indexOf(frame)))
|
|
679
752
|
});
|
|
680
753
|
const update = (next) => {
|
|
681
754
|
lastLabel = next;
|
|
@@ -716,6 +789,7 @@ function buildOperatorPiEnv(input) {
|
|
|
716
789
|
return {
|
|
717
790
|
PI_CODING_AGENT_SESSION_DIR: input.sessionDir,
|
|
718
791
|
PI_SKIP_VERSION_CHECK: "1",
|
|
792
|
+
PI_HIDDEN_COMMANDS: "import,fork,clone,tree,new,resume,trust",
|
|
719
793
|
RIG_PI_OPERATOR_SESSION: "1",
|
|
720
794
|
RIG_RUN_ID: input.runId,
|
|
721
795
|
RIG_SERVER_URL: input.serverUrl,
|
|
@@ -725,6 +799,10 @@ function buildOperatorPiEnv(input) {
|
|
|
725
799
|
}
|
|
726
800
|
async function prepareOperatorConsole(context, runId, tempSessionDir) {
|
|
727
801
|
const server = await ensureServerForCli(context.projectRoot);
|
|
802
|
+
const localCwd = join(homedir2(), ".rig", "drones", runId.slice(0, 8));
|
|
803
|
+
mkdirSync2(localCwd, { recursive: true });
|
|
804
|
+
trustDroneCwd(localCwd);
|
|
805
|
+
installRigPiTheme();
|
|
728
806
|
let sessionFileArg = [];
|
|
729
807
|
try {
|
|
730
808
|
const payload = await requestServerJson(context, `/api/runs/${encodeURIComponent(runId)}/session-file`);
|
|
@@ -738,7 +816,7 @@ async function prepareOperatorConsole(context, runId, tempSessionDir) {
|
|
|
738
816
|
try {
|
|
739
817
|
const header = JSON.parse(line);
|
|
740
818
|
if (header.type === "session" && typeof header.cwd === "string") {
|
|
741
|
-
return JSON.stringify({ ...header, cwd:
|
|
819
|
+
return JSON.stringify({ ...header, cwd: localCwd });
|
|
742
820
|
}
|
|
743
821
|
} catch {}
|
|
744
822
|
return line;
|
|
@@ -750,6 +828,105 @@ async function prepareOperatorConsole(context, runId, tempSessionDir) {
|
|
|
750
828
|
} catch {}
|
|
751
829
|
return { server, sessionFileArg };
|
|
752
830
|
}
|
|
831
|
+
var RIG_PI_THEME = {
|
|
832
|
+
$schema: "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
|
|
833
|
+
name: "rig",
|
|
834
|
+
vars: {
|
|
835
|
+
acid: "#ccff4d",
|
|
836
|
+
acidDim: "#a9d63f",
|
|
837
|
+
cyan: "#56d8ff",
|
|
838
|
+
red: "#ff5d5d",
|
|
839
|
+
yellow: "#ffd24d",
|
|
840
|
+
ink: "#f2f3f6",
|
|
841
|
+
ink2: "#aeb0ba",
|
|
842
|
+
ink3: "#6c6e79",
|
|
843
|
+
ink4: "#44464f",
|
|
844
|
+
panel: "#101115",
|
|
845
|
+
panelUser: "#14161b",
|
|
846
|
+
toolPending: "#0e1013",
|
|
847
|
+
toolSuccess: "#10150c",
|
|
848
|
+
toolError: "#1a0f0f",
|
|
849
|
+
customMsg: "#0f1410"
|
|
850
|
+
},
|
|
851
|
+
colors: {
|
|
852
|
+
accent: "acid",
|
|
853
|
+
border: "ink4",
|
|
854
|
+
borderAccent: "acid",
|
|
855
|
+
borderMuted: "ink4",
|
|
856
|
+
success: "acid",
|
|
857
|
+
error: "red",
|
|
858
|
+
warning: "yellow",
|
|
859
|
+
muted: "ink3",
|
|
860
|
+
dim: "ink4",
|
|
861
|
+
text: "ink",
|
|
862
|
+
thinkingText: "ink3",
|
|
863
|
+
selectedBg: "panel",
|
|
864
|
+
userMessageBg: "panelUser",
|
|
865
|
+
userMessageText: "ink",
|
|
866
|
+
customMessageBg: "customMsg",
|
|
867
|
+
customMessageText: "ink2",
|
|
868
|
+
customMessageLabel: "acidDim",
|
|
869
|
+
toolPendingBg: "toolPending",
|
|
870
|
+
toolSuccessBg: "toolSuccess",
|
|
871
|
+
toolErrorBg: "toolError",
|
|
872
|
+
toolTitle: "ink",
|
|
873
|
+
toolOutput: "ink3",
|
|
874
|
+
mdHeading: "acid",
|
|
875
|
+
mdLink: "cyan",
|
|
876
|
+
mdLinkUrl: "ink4",
|
|
877
|
+
mdCode: "acidDim",
|
|
878
|
+
mdCodeBlock: "ink2",
|
|
879
|
+
mdCodeBlockBorder: "ink4",
|
|
880
|
+
mdQuote: "ink3",
|
|
881
|
+
mdQuoteBorder: "ink4",
|
|
882
|
+
mdHr: "ink4",
|
|
883
|
+
mdListBullet: "acid",
|
|
884
|
+
toolDiffAdded: "acid",
|
|
885
|
+
toolDiffRemoved: "red",
|
|
886
|
+
toolDiffContext: "ink3",
|
|
887
|
+
syntaxComment: "ink3",
|
|
888
|
+
syntaxKeyword: "cyan",
|
|
889
|
+
syntaxFunction: "acid",
|
|
890
|
+
syntaxVariable: "ink",
|
|
891
|
+
syntaxString: "acidDim",
|
|
892
|
+
syntaxNumber: "yellow",
|
|
893
|
+
syntaxType: "cyan",
|
|
894
|
+
syntaxOperator: "ink2",
|
|
895
|
+
syntaxPunctuation: "ink3",
|
|
896
|
+
thinkingOff: "ink4",
|
|
897
|
+
thinkingMinimal: "ink3",
|
|
898
|
+
thinkingLow: "ink2",
|
|
899
|
+
thinkingMedium: "cyan",
|
|
900
|
+
thinkingHigh: "acidDim",
|
|
901
|
+
thinkingXhigh: "acid",
|
|
902
|
+
bashMode: "cyan"
|
|
903
|
+
}
|
|
904
|
+
};
|
|
905
|
+
function trustDroneCwd(localCwd) {
|
|
906
|
+
try {
|
|
907
|
+
const agentDir = join(homedir2(), ".pi", "agent");
|
|
908
|
+
mkdirSync2(agentDir, { recursive: true });
|
|
909
|
+
const trustPath = join(agentDir, "trust.json");
|
|
910
|
+
const store = existsSync3(trustPath) ? JSON.parse(readFileSync3(trustPath, "utf8")) : {};
|
|
911
|
+
if (store[localCwd] !== true) {
|
|
912
|
+
store[localCwd] = true;
|
|
913
|
+
writeFileSync2(trustPath, `${JSON.stringify(store, null, "\t")}
|
|
914
|
+
`);
|
|
915
|
+
}
|
|
916
|
+
} catch {}
|
|
917
|
+
}
|
|
918
|
+
function installRigPiTheme() {
|
|
919
|
+
try {
|
|
920
|
+
const themesDir = join(homedir2(), ".pi", "agent", "themes");
|
|
921
|
+
mkdirSync2(themesDir, { recursive: true });
|
|
922
|
+
const themePath = join(themesDir, "rig.json");
|
|
923
|
+
const next = `${JSON.stringify(RIG_PI_THEME, null, "\t")}
|
|
924
|
+
`;
|
|
925
|
+
if (!existsSync3(themePath) || readFileSync3(themePath, "utf8") !== next) {
|
|
926
|
+
writeFileSync2(themePath, next);
|
|
927
|
+
}
|
|
928
|
+
} catch {}
|
|
929
|
+
}
|
|
753
930
|
async function attachRunBundledPiFrontend(context, input) {
|
|
754
931
|
const tempSessionDir = mkdtempSync(join(tmpdir(), "rig-pi-frontend-sessions-"));
|
|
755
932
|
const { server, sessionFileArg } = await withSpinner(`Opening Pi console for run ${input.runId}\u2026`, () => prepareOperatorConsole(context, input.runId, tempSessionDir), { outputMode: context.outputMode });
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/cli/src/commands/_pi-frontend.ts
|
|
3
|
-
import { mkdtempSync, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
4
|
-
import { tmpdir } from "os";
|
|
3
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, mkdtempSync, readFileSync as readFileSync3, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
4
|
+
import { homedir as homedir2, tmpdir } from "os";
|
|
5
5
|
import { join } from "path";
|
|
6
6
|
import { main as runPiMain } from "@earendil-works/pi-coding-agent";
|
|
7
7
|
import createPiRigExtension from "@rig/pi-rig";
|
|
@@ -318,7 +318,9 @@ ${failure.contextLine}`, 1, { hint: failure.hint });
|
|
|
318
318
|
})() : null;
|
|
319
319
|
if (!response.ok) {
|
|
320
320
|
const diagnostics = diagnosticMessage(payload);
|
|
321
|
-
const
|
|
321
|
+
const rawDetail = diagnostics ?? (text || response.statusText);
|
|
322
|
+
const detail = diagnostics ? rawDetail : rawDetail.split(`
|
|
323
|
+
`).map((line) => line.trim()).find((line) => line.length > 0)?.slice(0, 200) ?? response.statusText;
|
|
322
324
|
const failure = await buildServerFailureContext(context.projectRoot, server);
|
|
323
325
|
throw new CliError(`Rig server request failed (${response.status}): ${detail}
|
|
324
326
|
${failure.contextLine}`, 1, { hint: failure.hint });
|
|
@@ -405,8 +407,79 @@ function createTtySpinner(input) {
|
|
|
405
407
|
};
|
|
406
408
|
}
|
|
407
409
|
|
|
410
|
+
// packages/cli/src/app/theme.ts
|
|
411
|
+
var RIG_PALETTE = {
|
|
412
|
+
ink: "#f2f3f6",
|
|
413
|
+
ink2: "#aeb0ba",
|
|
414
|
+
ink3: "#6c6e79",
|
|
415
|
+
ink4: "#44464f",
|
|
416
|
+
accent: "#ccff4d",
|
|
417
|
+
accentDim: "#a9d63f",
|
|
418
|
+
cyan: "#56d8ff",
|
|
419
|
+
red: "#ff5d5d",
|
|
420
|
+
yellow: "#ffd24d"
|
|
421
|
+
};
|
|
422
|
+
function hexToRgb(hex) {
|
|
423
|
+
const value = hex.replace("#", "");
|
|
424
|
+
return [
|
|
425
|
+
Number.parseInt(value.slice(0, 2), 16),
|
|
426
|
+
Number.parseInt(value.slice(2, 4), 16),
|
|
427
|
+
Number.parseInt(value.slice(4, 6), 16)
|
|
428
|
+
];
|
|
429
|
+
}
|
|
430
|
+
function fg(hex) {
|
|
431
|
+
const [r, g, b] = hexToRgb(hex);
|
|
432
|
+
return (text) => `\x1B[38;2;${r};${g};${b}m${text}\x1B[39m`;
|
|
433
|
+
}
|
|
434
|
+
var ink = fg(RIG_PALETTE.ink);
|
|
435
|
+
var ink2 = fg(RIG_PALETTE.ink2);
|
|
436
|
+
var ink3 = fg(RIG_PALETTE.ink3);
|
|
437
|
+
var ink4 = fg(RIG_PALETTE.ink4);
|
|
438
|
+
var accent = fg(RIG_PALETTE.accent);
|
|
439
|
+
var accentDim = fg(RIG_PALETTE.accentDim);
|
|
440
|
+
var cyan = fg(RIG_PALETTE.cyan);
|
|
441
|
+
var red = fg(RIG_PALETTE.red);
|
|
442
|
+
var yellow = fg(RIG_PALETTE.yellow);
|
|
443
|
+
function bold(text) {
|
|
444
|
+
return `\x1B[1m${text}\x1B[22m`;
|
|
445
|
+
}
|
|
446
|
+
var DRONE_ART = [
|
|
447
|
+
" .-=-. .-=-. ",
|
|
448
|
+
" ( !!! ) ( !!! ) ",
|
|
449
|
+
" '-=-'._ _.'-=-' ",
|
|
450
|
+
" '._ _.' ",
|
|
451
|
+
" '=$$$$$$$=.' ",
|
|
452
|
+
" =$$$$$$$$$$$= ",
|
|
453
|
+
" $$$@@@@@@@@@@$$$ ",
|
|
454
|
+
" $$$@@ @@$$$ ",
|
|
455
|
+
" $$@ ? @$$$ ",
|
|
456
|
+
" $$$@ '-' @$$$ ",
|
|
457
|
+
" $$$@@ @@$$$ ",
|
|
458
|
+
" $$$@@@@@@@@@@$$$ ",
|
|
459
|
+
" =$$$$$$$$$$$= ",
|
|
460
|
+
" '=$$$$$$$=.' ",
|
|
461
|
+
" _.' '._ ",
|
|
462
|
+
" .-=-.' '.-=-. ",
|
|
463
|
+
" ( !!! ) ( !!! ) ",
|
|
464
|
+
" '-=-' '-=-' "
|
|
465
|
+
];
|
|
466
|
+
var EYE_FRAMES = ["@", "o", "."];
|
|
467
|
+
var DRONE_WIDTH = DRONE_ART[0].length;
|
|
468
|
+
var DRONE_HEIGHT = DRONE_ART.length;
|
|
469
|
+
var MICRO_BLADES = ["---", "\\\\\\", "|||", "///"];
|
|
470
|
+
function microDroneFrame(tick) {
|
|
471
|
+
const blade = MICRO_BLADES[tick % MICRO_BLADES.length];
|
|
472
|
+
const eye = EYE_FRAMES[Math.floor(tick / 2) % EYE_FRAMES.length];
|
|
473
|
+
return `(${blade})${eye}(${blade})`;
|
|
474
|
+
}
|
|
475
|
+
var MICRO_DRONE_FRAMES = Array.from({ length: 12 }, (_, index) => microDroneFrame(index));
|
|
476
|
+
function renderMicroDroneFrame(tick) {
|
|
477
|
+
const blade = MICRO_BLADES[tick % MICRO_BLADES.length];
|
|
478
|
+
const eye = EYE_FRAMES[Math.floor(tick / 2) % EYE_FRAMES.length];
|
|
479
|
+
return `${ink4("(")}${cyan(blade)}${ink4(")")}${bold(accent(eye))}${ink4("(")}${cyan(blade)}${ink4(")")}`;
|
|
480
|
+
}
|
|
481
|
+
|
|
408
482
|
// packages/cli/src/commands/_async-ui.ts
|
|
409
|
-
var CLACK_SPINNER_FRAMES = ["\u25D2", "\u25D0", "\u25D3", "\u25D1"];
|
|
410
483
|
var DONE_SYMBOL = pc.green("\u25C7");
|
|
411
484
|
var FAIL_SYMBOL = pc.red("\u25A0");
|
|
412
485
|
var activeUpdate = null;
|
|
@@ -440,8 +513,8 @@ async function withSpinner(label, work, options = {}) {
|
|
|
440
513
|
const spinner = createTtySpinner({
|
|
441
514
|
label,
|
|
442
515
|
output,
|
|
443
|
-
frames:
|
|
444
|
-
styleFrame: (frame) =>
|
|
516
|
+
frames: MICRO_DRONE_FRAMES,
|
|
517
|
+
styleFrame: (frame) => renderMicroDroneFrame(Math.max(0, MICRO_DRONE_FRAMES.indexOf(frame)))
|
|
445
518
|
});
|
|
446
519
|
const update = (next) => {
|
|
447
520
|
lastLabel = next;
|
|
@@ -482,6 +555,7 @@ function buildOperatorPiEnv(input) {
|
|
|
482
555
|
return {
|
|
483
556
|
PI_CODING_AGENT_SESSION_DIR: input.sessionDir,
|
|
484
557
|
PI_SKIP_VERSION_CHECK: "1",
|
|
558
|
+
PI_HIDDEN_COMMANDS: "import,fork,clone,tree,new,resume,trust",
|
|
485
559
|
RIG_PI_OPERATOR_SESSION: "1",
|
|
486
560
|
RIG_RUN_ID: input.runId,
|
|
487
561
|
RIG_SERVER_URL: input.serverUrl,
|
|
@@ -491,6 +565,10 @@ function buildOperatorPiEnv(input) {
|
|
|
491
565
|
}
|
|
492
566
|
async function prepareOperatorConsole(context, runId, tempSessionDir) {
|
|
493
567
|
const server = await ensureServerForCli(context.projectRoot);
|
|
568
|
+
const localCwd = join(homedir2(), ".rig", "drones", runId.slice(0, 8));
|
|
569
|
+
mkdirSync2(localCwd, { recursive: true });
|
|
570
|
+
trustDroneCwd(localCwd);
|
|
571
|
+
installRigPiTheme();
|
|
494
572
|
let sessionFileArg = [];
|
|
495
573
|
try {
|
|
496
574
|
const payload = await requestServerJson(context, `/api/runs/${encodeURIComponent(runId)}/session-file`);
|
|
@@ -504,7 +582,7 @@ async function prepareOperatorConsole(context, runId, tempSessionDir) {
|
|
|
504
582
|
try {
|
|
505
583
|
const header = JSON.parse(line);
|
|
506
584
|
if (header.type === "session" && typeof header.cwd === "string") {
|
|
507
|
-
return JSON.stringify({ ...header, cwd:
|
|
585
|
+
return JSON.stringify({ ...header, cwd: localCwd });
|
|
508
586
|
}
|
|
509
587
|
} catch {}
|
|
510
588
|
return line;
|
|
@@ -516,6 +594,105 @@ async function prepareOperatorConsole(context, runId, tempSessionDir) {
|
|
|
516
594
|
} catch {}
|
|
517
595
|
return { server, sessionFileArg };
|
|
518
596
|
}
|
|
597
|
+
var RIG_PI_THEME = {
|
|
598
|
+
$schema: "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
|
|
599
|
+
name: "rig",
|
|
600
|
+
vars: {
|
|
601
|
+
acid: "#ccff4d",
|
|
602
|
+
acidDim: "#a9d63f",
|
|
603
|
+
cyan: "#56d8ff",
|
|
604
|
+
red: "#ff5d5d",
|
|
605
|
+
yellow: "#ffd24d",
|
|
606
|
+
ink: "#f2f3f6",
|
|
607
|
+
ink2: "#aeb0ba",
|
|
608
|
+
ink3: "#6c6e79",
|
|
609
|
+
ink4: "#44464f",
|
|
610
|
+
panel: "#101115",
|
|
611
|
+
panelUser: "#14161b",
|
|
612
|
+
toolPending: "#0e1013",
|
|
613
|
+
toolSuccess: "#10150c",
|
|
614
|
+
toolError: "#1a0f0f",
|
|
615
|
+
customMsg: "#0f1410"
|
|
616
|
+
},
|
|
617
|
+
colors: {
|
|
618
|
+
accent: "acid",
|
|
619
|
+
border: "ink4",
|
|
620
|
+
borderAccent: "acid",
|
|
621
|
+
borderMuted: "ink4",
|
|
622
|
+
success: "acid",
|
|
623
|
+
error: "red",
|
|
624
|
+
warning: "yellow",
|
|
625
|
+
muted: "ink3",
|
|
626
|
+
dim: "ink4",
|
|
627
|
+
text: "ink",
|
|
628
|
+
thinkingText: "ink3",
|
|
629
|
+
selectedBg: "panel",
|
|
630
|
+
userMessageBg: "panelUser",
|
|
631
|
+
userMessageText: "ink",
|
|
632
|
+
customMessageBg: "customMsg",
|
|
633
|
+
customMessageText: "ink2",
|
|
634
|
+
customMessageLabel: "acidDim",
|
|
635
|
+
toolPendingBg: "toolPending",
|
|
636
|
+
toolSuccessBg: "toolSuccess",
|
|
637
|
+
toolErrorBg: "toolError",
|
|
638
|
+
toolTitle: "ink",
|
|
639
|
+
toolOutput: "ink3",
|
|
640
|
+
mdHeading: "acid",
|
|
641
|
+
mdLink: "cyan",
|
|
642
|
+
mdLinkUrl: "ink4",
|
|
643
|
+
mdCode: "acidDim",
|
|
644
|
+
mdCodeBlock: "ink2",
|
|
645
|
+
mdCodeBlockBorder: "ink4",
|
|
646
|
+
mdQuote: "ink3",
|
|
647
|
+
mdQuoteBorder: "ink4",
|
|
648
|
+
mdHr: "ink4",
|
|
649
|
+
mdListBullet: "acid",
|
|
650
|
+
toolDiffAdded: "acid",
|
|
651
|
+
toolDiffRemoved: "red",
|
|
652
|
+
toolDiffContext: "ink3",
|
|
653
|
+
syntaxComment: "ink3",
|
|
654
|
+
syntaxKeyword: "cyan",
|
|
655
|
+
syntaxFunction: "acid",
|
|
656
|
+
syntaxVariable: "ink",
|
|
657
|
+
syntaxString: "acidDim",
|
|
658
|
+
syntaxNumber: "yellow",
|
|
659
|
+
syntaxType: "cyan",
|
|
660
|
+
syntaxOperator: "ink2",
|
|
661
|
+
syntaxPunctuation: "ink3",
|
|
662
|
+
thinkingOff: "ink4",
|
|
663
|
+
thinkingMinimal: "ink3",
|
|
664
|
+
thinkingLow: "ink2",
|
|
665
|
+
thinkingMedium: "cyan",
|
|
666
|
+
thinkingHigh: "acidDim",
|
|
667
|
+
thinkingXhigh: "acid",
|
|
668
|
+
bashMode: "cyan"
|
|
669
|
+
}
|
|
670
|
+
};
|
|
671
|
+
function trustDroneCwd(localCwd) {
|
|
672
|
+
try {
|
|
673
|
+
const agentDir = join(homedir2(), ".pi", "agent");
|
|
674
|
+
mkdirSync2(agentDir, { recursive: true });
|
|
675
|
+
const trustPath = join(agentDir, "trust.json");
|
|
676
|
+
const store = existsSync3(trustPath) ? JSON.parse(readFileSync3(trustPath, "utf8")) : {};
|
|
677
|
+
if (store[localCwd] !== true) {
|
|
678
|
+
store[localCwd] = true;
|
|
679
|
+
writeFileSync2(trustPath, `${JSON.stringify(store, null, "\t")}
|
|
680
|
+
`);
|
|
681
|
+
}
|
|
682
|
+
} catch {}
|
|
683
|
+
}
|
|
684
|
+
function installRigPiTheme() {
|
|
685
|
+
try {
|
|
686
|
+
const themesDir = join(homedir2(), ".pi", "agent", "themes");
|
|
687
|
+
mkdirSync2(themesDir, { recursive: true });
|
|
688
|
+
const themePath = join(themesDir, "rig.json");
|
|
689
|
+
const next = `${JSON.stringify(RIG_PI_THEME, null, "\t")}
|
|
690
|
+
`;
|
|
691
|
+
if (!existsSync3(themePath) || readFileSync3(themePath, "utf8") !== next) {
|
|
692
|
+
writeFileSync2(themePath, next);
|
|
693
|
+
}
|
|
694
|
+
} catch {}
|
|
695
|
+
}
|
|
519
696
|
async function attachRunBundledPiFrontend(context, input) {
|
|
520
697
|
const tempSessionDir = mkdtempSync(join(tmpdir(), "rig-pi-frontend-sessions-"));
|
|
521
698
|
const { server, sessionFileArg } = await withSpinner(`Opening Pi console for run ${input.runId}\u2026`, () => prepareOperatorConsole(context, input.runId, tempSessionDir), { outputMode: context.outputMode });
|
|
@@ -305,7 +305,9 @@ ${failure.contextLine}`, 1, { hint: failure.hint });
|
|
|
305
305
|
})() : null;
|
|
306
306
|
if (!response.ok) {
|
|
307
307
|
const diagnostics = diagnosticMessage(payload);
|
|
308
|
-
const
|
|
308
|
+
const rawDetail = diagnostics ?? (text || response.statusText);
|
|
309
|
+
const detail = diagnostics ? rawDetail : rawDetail.split(`
|
|
310
|
+
`).map((line) => line.trim()).find((line) => line.length > 0)?.slice(0, 200) ?? response.statusText;
|
|
309
311
|
const failure = await buildServerFailureContext(context.projectRoot, server);
|
|
310
312
|
throw new CliError(`Rig server request failed (${response.status}): ${detail}
|
|
311
313
|
${failure.contextLine}`, 1, { hint: failure.hint });
|
|
@@ -325,7 +325,9 @@ ${failure.contextLine}`, 1, { hint: failure.hint });
|
|
|
325
325
|
})() : null;
|
|
326
326
|
if (!response.ok) {
|
|
327
327
|
const diagnostics = diagnosticMessage(payload);
|
|
328
|
-
const
|
|
328
|
+
const rawDetail = diagnostics ?? (text || response.statusText);
|
|
329
|
+
const detail = diagnostics ? rawDetail : rawDetail.split(`
|
|
330
|
+
`).map((line) => line.trim()).find((line) => line.length > 0)?.slice(0, 200) ?? response.statusText;
|
|
329
331
|
const failure = await buildServerFailureContext(context.projectRoot, server);
|
|
330
332
|
throw new CliError(`Rig server request failed (${response.status}): ${detail}
|
|
331
333
|
${failure.contextLine}`, 1, { hint: failure.hint });
|
|
@@ -310,7 +310,9 @@ ${failure.contextLine}`, 1, { hint: failure.hint });
|
|
|
310
310
|
})() : null;
|
|
311
311
|
if (!response.ok) {
|
|
312
312
|
const diagnostics = diagnosticMessage(payload);
|
|
313
|
-
const
|
|
313
|
+
const rawDetail = diagnostics ?? (text || response.statusText);
|
|
314
|
+
const detail = diagnostics ? rawDetail : rawDetail.split(`
|
|
315
|
+
`).map((line) => line.trim()).find((line) => line.length > 0)?.slice(0, 200) ?? response.statusText;
|
|
314
316
|
const failure = await buildServerFailureContext(context.projectRoot, server);
|
|
315
317
|
throw new CliError(`Rig server request failed (${response.status}): ${detail}
|
|
316
318
|
${failure.contextLine}`, 1, { hint: failure.hint });
|
|
@@ -1,6 +1,131 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
// packages/cli/src/
|
|
3
|
-
import {
|
|
2
|
+
// packages/cli/src/app/drone-ui.ts
|
|
3
|
+
import { ProcessTerminal, TUI, Text, Input, SelectList, matchesKey } from "@earendil-works/pi-tui";
|
|
4
|
+
|
|
5
|
+
// packages/cli/src/app/theme.ts
|
|
6
|
+
var RIG_PALETTE = {
|
|
7
|
+
ink: "#f2f3f6",
|
|
8
|
+
ink2: "#aeb0ba",
|
|
9
|
+
ink3: "#6c6e79",
|
|
10
|
+
ink4: "#44464f",
|
|
11
|
+
accent: "#ccff4d",
|
|
12
|
+
accentDim: "#a9d63f",
|
|
13
|
+
cyan: "#56d8ff",
|
|
14
|
+
red: "#ff5d5d",
|
|
15
|
+
yellow: "#ffd24d"
|
|
16
|
+
};
|
|
17
|
+
function hexToRgb(hex) {
|
|
18
|
+
const value = hex.replace("#", "");
|
|
19
|
+
return [
|
|
20
|
+
Number.parseInt(value.slice(0, 2), 16),
|
|
21
|
+
Number.parseInt(value.slice(2, 4), 16),
|
|
22
|
+
Number.parseInt(value.slice(4, 6), 16)
|
|
23
|
+
];
|
|
24
|
+
}
|
|
25
|
+
function fg(hex) {
|
|
26
|
+
const [r, g, b] = hexToRgb(hex);
|
|
27
|
+
return (text) => `\x1B[38;2;${r};${g};${b}m${text}\x1B[39m`;
|
|
28
|
+
}
|
|
29
|
+
var ink = fg(RIG_PALETTE.ink);
|
|
30
|
+
var ink2 = fg(RIG_PALETTE.ink2);
|
|
31
|
+
var ink3 = fg(RIG_PALETTE.ink3);
|
|
32
|
+
var ink4 = fg(RIG_PALETTE.ink4);
|
|
33
|
+
var accent = fg(RIG_PALETTE.accent);
|
|
34
|
+
var accentDim = fg(RIG_PALETTE.accentDim);
|
|
35
|
+
var cyan = fg(RIG_PALETTE.cyan);
|
|
36
|
+
var red = fg(RIG_PALETTE.red);
|
|
37
|
+
var yellow = fg(RIG_PALETTE.yellow);
|
|
38
|
+
function bold(text) {
|
|
39
|
+
return `\x1B[1m${text}\x1B[22m`;
|
|
40
|
+
}
|
|
41
|
+
var DRONE_ART = [
|
|
42
|
+
" .-=-. .-=-. ",
|
|
43
|
+
" ( !!! ) ( !!! ) ",
|
|
44
|
+
" '-=-'._ _.'-=-' ",
|
|
45
|
+
" '._ _.' ",
|
|
46
|
+
" '=$$$$$$$=.' ",
|
|
47
|
+
" =$$$$$$$$$$$= ",
|
|
48
|
+
" $$$@@@@@@@@@@$$$ ",
|
|
49
|
+
" $$$@@ @@$$$ ",
|
|
50
|
+
" $$@ ? @$$$ ",
|
|
51
|
+
" $$$@ '-' @$$$ ",
|
|
52
|
+
" $$$@@ @@$$$ ",
|
|
53
|
+
" $$$@@@@@@@@@@$$$ ",
|
|
54
|
+
" =$$$$$$$$$$$= ",
|
|
55
|
+
" '=$$$$$$$=.' ",
|
|
56
|
+
" _.' '._ ",
|
|
57
|
+
" .-=-.' '.-=-. ",
|
|
58
|
+
" ( !!! ) ( !!! ) ",
|
|
59
|
+
" '-=-' '-=-' "
|
|
60
|
+
];
|
|
61
|
+
var EYE_FRAMES = ["@", "o", "."];
|
|
62
|
+
var DRONE_WIDTH = DRONE_ART[0].length;
|
|
63
|
+
var DRONE_HEIGHT = DRONE_ART.length;
|
|
64
|
+
var MICRO_BLADES = ["---", "\\\\\\", "|||", "///"];
|
|
65
|
+
function microDroneFrame(tick) {
|
|
66
|
+
const blade = MICRO_BLADES[tick % MICRO_BLADES.length];
|
|
67
|
+
const eye = EYE_FRAMES[Math.floor(tick / 2) % EYE_FRAMES.length];
|
|
68
|
+
return `(${blade})${eye}(${blade})`;
|
|
69
|
+
}
|
|
70
|
+
var MICRO_DRONE_FRAMES = Array.from({ length: 12 }, (_, index) => microDroneFrame(index));
|
|
71
|
+
|
|
72
|
+
// packages/cli/src/app/drone-ui.ts
|
|
73
|
+
var isTty = () => Boolean(process.stdout.isTTY);
|
|
74
|
+
function droneCancel(text) {
|
|
75
|
+
console.log(` ${red("\u2716")} ${ink3(text)}`);
|
|
76
|
+
}
|
|
77
|
+
var SELECT_THEME = {
|
|
78
|
+
selectedPrefix: (text) => accent(text),
|
|
79
|
+
selectedText: (text) => bold(ink(text)),
|
|
80
|
+
description: (text) => ink3(text),
|
|
81
|
+
scrollInfo: (text) => ink4(text),
|
|
82
|
+
noMatch: (text) => ink3(text)
|
|
83
|
+
};
|
|
84
|
+
async function runMiniTui(build) {
|
|
85
|
+
const terminal = new ProcessTerminal;
|
|
86
|
+
const tui = new TUI(terminal);
|
|
87
|
+
let settled = false;
|
|
88
|
+
return await new Promise((resolve) => {
|
|
89
|
+
const finish = (result) => {
|
|
90
|
+
if (settled)
|
|
91
|
+
return;
|
|
92
|
+
settled = true;
|
|
93
|
+
tui.stop();
|
|
94
|
+
resolve(result);
|
|
95
|
+
};
|
|
96
|
+
build(tui, finish);
|
|
97
|
+
tui.start();
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
async function droneSelect(input) {
|
|
101
|
+
if (!isTty() || input.options.length === 0) {
|
|
102
|
+
return input.initialValue ?? input.options[0]?.value ?? null;
|
|
103
|
+
}
|
|
104
|
+
return runMiniTui((tui, finish) => {
|
|
105
|
+
tui.addChild(new Text(` ${accent("\u258D")}${bold(ink(input.message))}`));
|
|
106
|
+
const items = input.options.map((option) => ({
|
|
107
|
+
value: option.value,
|
|
108
|
+
label: option.label,
|
|
109
|
+
...option.hint ? { description: option.hint } : {}
|
|
110
|
+
}));
|
|
111
|
+
const list = new SelectList(items, Math.min(items.length, 12), SELECT_THEME);
|
|
112
|
+
const initialIndex = input.initialValue ? items.findIndex((item) => item.value === input.initialValue) : -1;
|
|
113
|
+
if (initialIndex > 0)
|
|
114
|
+
list.setSelectedIndex(initialIndex);
|
|
115
|
+
list.onSelect = (item) => finish(item.value);
|
|
116
|
+
list.onCancel = () => finish(null);
|
|
117
|
+
tui.addChild(list);
|
|
118
|
+
tui.addChild(new Text(ink4(" \u2191\u2193 navigate \xB7 enter select \xB7 esc cancel")));
|
|
119
|
+
tui.setFocus(list);
|
|
120
|
+
tui.addInputListener((data) => {
|
|
121
|
+
if (matchesKey(data, "ctrl+c") || matchesKey(data, "escape")) {
|
|
122
|
+
finish(null);
|
|
123
|
+
return { consume: true };
|
|
124
|
+
}
|
|
125
|
+
return;
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
}
|
|
4
129
|
|
|
5
130
|
// packages/cli/src/commands/_operator-surface.ts
|
|
6
131
|
import { createInterface as createPromptInterface } from "readline/promises";
|
|
@@ -34,8 +159,8 @@ async function selectTaskWithTextPicker(tasks, io = {}) {
|
|
|
34
159
|
return null;
|
|
35
160
|
if (tasks.length === 1)
|
|
36
161
|
return tasks[0];
|
|
37
|
-
const
|
|
38
|
-
if (!
|
|
162
|
+
const isTty2 = io.isTty ?? Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
163
|
+
if (!isTty2) {
|
|
39
164
|
throw new Error("task run requires an interactive terminal to pick a task; pass --task <id>, --next, or --detach with a task id.");
|
|
40
165
|
}
|
|
41
166
|
if (io.prompt || io.renderer) {
|
|
@@ -59,12 +184,12 @@ async function selectTaskWithTextPicker(tasks, io = {}) {
|
|
|
59
184
|
label: `${taskId2(task)} \xB7 ${typeof task.title === "string" && task.title.trim() ? task.title.trim() : "Untitled task"}`,
|
|
60
185
|
hint: typeof task.status === "string" && task.status.trim() ? task.status.trim() : undefined
|
|
61
186
|
}));
|
|
62
|
-
const answer = await
|
|
187
|
+
const answer = await droneSelect({
|
|
63
188
|
message: "Select Rig task",
|
|
64
189
|
options
|
|
65
190
|
});
|
|
66
|
-
if (
|
|
67
|
-
|
|
191
|
+
if (answer === null) {
|
|
192
|
+
droneCancel("No task selected.");
|
|
68
193
|
return null;
|
|
69
194
|
}
|
|
70
195
|
const index = Number.parseInt(String(answer), 10);
|