pi-firecode 1.0.1 → 1.0.2
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/README.md +5 -1
- package/README.zh-CN.md +5 -1
- package/dist/index.js +77 -98
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,6 +5,11 @@
|
|
|
5
5
|
</picture>
|
|
6
6
|
</p>
|
|
7
7
|
|
|
8
|
+
<p align="center">
|
|
9
|
+
<a href="README.md"><img alt="English" src="https://img.shields.io/badge/English-2b2b2b?style=for-the-badge"></a>
|
|
10
|
+
<a href="README.zh-CN.md"><img alt="简体中文" src="https://img.shields.io/badge/%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87-FF7A0F?style=for-the-badge"></a>
|
|
11
|
+
</p>
|
|
12
|
+
|
|
8
13
|
<h3 align="center">Install one extension. Uninstall the rest.</h3>
|
|
9
14
|
|
|
10
15
|
<p align="center">Parallel sub-agents, multi-model code review and a cleaner terminal for <a href="https://pi.dev">Pi</a>. One install, works out of the box.</p>
|
|
@@ -13,7 +18,6 @@
|
|
|
13
18
|
<a href="https://www.npmjs.com/package/pi-firecode"><img alt="npm" src="https://img.shields.io/npm/v/pi-firecode?color=FF7A0F"></a>
|
|
14
19
|
<a href="https://github.com/Suge8/firecode/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/Suge8/firecode/actions/workflows/ci.yml/badge.svg"></a>
|
|
15
20
|
<a href="LICENSE"><img alt="MIT" src="https://img.shields.io/badge/license-MIT-blue"></a>
|
|
16
|
-
· <a href="README.zh-CN.md">中文</a>
|
|
17
21
|
</p>
|
|
18
22
|
|
|
19
23
|
<p align="center"><img alt="The commander dispatching three sub-agents in parallel" src="https://raw.githubusercontent.com/Suge8/firecode/main/design/promo/hero.gif" width="860"></p>
|
package/README.zh-CN.md
CHANGED
|
@@ -5,6 +5,11 @@
|
|
|
5
5
|
</picture>
|
|
6
6
|
</p>
|
|
7
7
|
|
|
8
|
+
<p align="center">
|
|
9
|
+
<a href="README.md"><img alt="English" src="https://img.shields.io/badge/English-FF7A0F?style=for-the-badge"></a>
|
|
10
|
+
<a href="README.zh-CN.md"><img alt="简体中文" src="https://img.shields.io/badge/%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87-2b2b2b?style=for-the-badge"></a>
|
|
11
|
+
</p>
|
|
12
|
+
|
|
8
13
|
<h3 align="center">装这一个,其余扩展都可以卸了。</h3>
|
|
9
14
|
|
|
10
15
|
<p align="center">给 <a href="https://pi.dev">Pi</a> 加上并行子代理、多模型代码审查和更干净的终端界面。装一个就够,开箱即用。</p>
|
|
@@ -13,7 +18,6 @@
|
|
|
13
18
|
<a href="https://www.npmjs.com/package/pi-firecode"><img alt="npm" src="https://img.shields.io/npm/v/pi-firecode?color=FF7A0F"></a>
|
|
14
19
|
<a href="https://github.com/Suge8/firecode/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/Suge8/firecode/actions/workflows/ci.yml/badge.svg"></a>
|
|
15
20
|
<a href="LICENSE"><img alt="MIT" src="https://img.shields.io/badge/license-MIT-blue"></a>
|
|
16
|
-
· <a href="README.md">English</a>
|
|
17
21
|
</p>
|
|
18
22
|
|
|
19
23
|
<p align="center"><img alt="指挥官并行派出三个子代理" src="https://raw.githubusercontent.com/Suge8/firecode/main/design/promo/hero.zh.gif" width="860"></p>
|
package/dist/index.js
CHANGED
|
@@ -720,94 +720,83 @@ function formatModelName(id) {
|
|
|
720
720
|
}
|
|
721
721
|
|
|
722
722
|
// header.ts
|
|
723
|
-
var
|
|
724
|
-
var
|
|
725
|
-
var
|
|
726
|
-
var
|
|
723
|
+
var WORD = "firecode";
|
|
724
|
+
var IGNITE_END = 0.6;
|
|
725
|
+
var REVEAL_START = 0.2;
|
|
726
|
+
var SETTLE_END = 1;
|
|
727
727
|
var TINY_FLAME_PHASE = 0.4;
|
|
728
|
+
var LOGO_GAP = 3;
|
|
729
|
+
var FLAME_RED_END = 0.45;
|
|
730
|
+
var WORD_TOP = 3;
|
|
728
731
|
var FADE_FROM = [20, 19, 18];
|
|
729
732
|
var RULE2 = [60, 57, 53];
|
|
730
733
|
var TINY_SUBTITLE_MIN = 8;
|
|
731
734
|
var TINY_RULE_MIN = 3;
|
|
732
735
|
var clamp2 = (value) => Math.min(1, Math.max(0, value));
|
|
733
736
|
var ease = (k) => 1 - (1 - clamp2(k)) ** 3;
|
|
734
|
-
var
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
return lines;
|
|
753
|
-
}
|
|
754
|
-
function roundFlame(widthPx, heightPx, t) {
|
|
755
|
-
const radius = widthPx / 2;
|
|
756
|
-
const belly = 0.36;
|
|
757
|
-
const tall = 0.9 + 0.1 * flicker(0.2, t);
|
|
758
|
-
return Array.from({ length: heightPx }, (_, y) => {
|
|
759
|
-
const row = Array(widthPx).fill(undefined);
|
|
760
|
-
const v = (heightPx - 0.5 - y) / heightPx / tall;
|
|
761
|
-
if (v > 1)
|
|
762
|
-
return row;
|
|
763
|
-
const half = v < belly ? radius * Math.sqrt(1 - ((belly - v) / belly) ** 2) : radius * ((1 - v) / (1 - belly)) ** 1.25;
|
|
764
|
-
const sway = 1.3 * v * v * Math.sin(Math.PI * 2 * 0.6 * t) + 0.4 * v * Math.sin(Math.PI * 2 * (1.7 * t + v * 2));
|
|
765
|
-
const reach = half + 0.25 * flicker(v * 3.1, t) * v;
|
|
766
|
-
for (let x = 0;x < widthPx; x++) {
|
|
767
|
-
const distance = Math.abs(x + 0.5 - radius - sway);
|
|
768
|
-
if (distance > reach)
|
|
769
|
-
continue;
|
|
770
|
-
const core = 1 - distance / (reach + 0.01);
|
|
771
|
-
row[x] = heat(0.12 + 0.55 * core * (1 - v * 0.6) + 0.45 * (1 - v) ** 2);
|
|
772
|
-
}
|
|
773
|
-
return row;
|
|
774
|
-
});
|
|
775
|
-
}
|
|
737
|
+
var FLAME = [
|
|
738
|
+
"......#......",
|
|
739
|
+
"......##.....",
|
|
740
|
+
".....###.....",
|
|
741
|
+
".....####....",
|
|
742
|
+
"....#####....",
|
|
743
|
+
"...######..#.",
|
|
744
|
+
"..#######.##.",
|
|
745
|
+
".###########.",
|
|
746
|
+
"#############",
|
|
747
|
+
"##..#########",
|
|
748
|
+
"###..########",
|
|
749
|
+
"####..#######",
|
|
750
|
+
"###..########",
|
|
751
|
+
"##..##.....##",
|
|
752
|
+
".###########.",
|
|
753
|
+
"...#######..."
|
|
754
|
+
];
|
|
776
755
|
var FONT = {
|
|
777
|
-
|
|
778
|
-
i: ["
|
|
779
|
-
r: ["....", "....", "
|
|
780
|
-
e: ["
|
|
781
|
-
|
|
782
|
-
o: ["
|
|
783
|
-
d: ["
|
|
756
|
+
f: ["..###", ".####", ".##..", "#####", "#####", ".##..", ".##..", ".##..", ".##..", ".##.."],
|
|
757
|
+
i: ["..", "##", "..", "##", "##", "##", "##", "##", "##", "##"],
|
|
758
|
+
r: ["....", "....", "....", "##.##", "#####", "###..", "##...", "##...", "##...", "##..."],
|
|
759
|
+
e: ["......", "......", "......", ".####.", "######", "##..##", "######", "##....", "######", ".####."],
|
|
760
|
+
c: ["......", "......", "......", ".####.", "######", "##..#.", "##....", "##..#.", "######", ".####."],
|
|
761
|
+
o: ["......", "......", "......", ".####.", "######", "##..##", "##..##", "##..##", "######", ".####."],
|
|
762
|
+
d: ["....##", "....##", "....##", ".#####", "######", "##..##", "##..##", "##..##", "######", ".#####"]
|
|
784
763
|
};
|
|
785
|
-
var
|
|
786
|
-
var
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
var
|
|
791
|
-
function
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
return
|
|
797
|
-
if (!on || x > edge)
|
|
798
|
-
return;
|
|
799
|
-
const half = width / 2;
|
|
800
|
-
const base = x < half ? mix(HEAT_COLORS.red, HEAT_COLORS.orange, x / half) : mix(HEAT_COLORS.orange, HEAT_COLORS.gold, (x - half) / half);
|
|
801
|
-
const hotEdge = t < REVEAL_END ? clamp2(1 - (edge - x) / 6) : 0;
|
|
802
|
-
const shine = t > REVEAL_END && t < SWEEP_END ? clamp2(1 - Math.abs(x - y * 0.6 - sweep) / 4.5) : 0;
|
|
803
|
-
return mix(base, HEAT_COLORS.white, Math.max(hotEdge, shine * 0.9));
|
|
804
|
-
}));
|
|
764
|
+
var WORD_ROWS = FONT.f.map((_, y) => [...WORD].map((char) => FONT[char][y]).join("."));
|
|
765
|
+
var FLAME_WIDTH = FLAME[0].length;
|
|
766
|
+
var WORD_LEFT = FLAME_WIDTH + LOGO_GAP;
|
|
767
|
+
var LOGO_WIDTH = WORD_LEFT + WORD_ROWS[0].length;
|
|
768
|
+
var LARGE_MIN_WIDTH = LOGO_WIDTH + 2;
|
|
769
|
+
var background = (color) => `\x1B[48;2;${color[0] | 0};${color[1] | 0};${color[2] | 0}m`;
|
|
770
|
+
function cell(top, bottom) {
|
|
771
|
+
if (top && bottom)
|
|
772
|
+
return `${background(bottom)}${paint(top, "▀")}\x1B[49m`;
|
|
773
|
+
if (top)
|
|
774
|
+
return paint(top, "▀");
|
|
775
|
+
return bottom ? paint(bottom, "▄") : " ";
|
|
805
776
|
}
|
|
806
|
-
function
|
|
807
|
-
const
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
777
|
+
function halfBlocks(pixels) {
|
|
778
|
+
const rows = [];
|
|
779
|
+
for (let y = 0;y < pixels.length; y += 2)
|
|
780
|
+
rows.push(pixels[y].map((top, x) => cell(top, pixels[y + 1]?.[x])));
|
|
781
|
+
return rows;
|
|
782
|
+
}
|
|
783
|
+
function flameHeat(y) {
|
|
784
|
+
const v = y / (FLAME.length - 1);
|
|
785
|
+
return v < FLAME_RED_END ? mix(HEAT_COLORS.red, HEAT_COLORS.orange, v / FLAME_RED_END) : mix(HEAT_COLORS.orange, HEAT_COLORS.gold, (v - FLAME_RED_END) / (1 - FLAME_RED_END));
|
|
786
|
+
}
|
|
787
|
+
function logo(t) {
|
|
788
|
+
const flameLine = ease(t / IGNITE_END) * (FLAME.length + 4);
|
|
789
|
+
const wordWidth = WORD_ROWS[0].length;
|
|
790
|
+
const wordEdge = (t - REVEAL_START) / (SETTLE_END - REVEAL_START) * wordWidth;
|
|
791
|
+
return FLAME.map((row, y) => {
|
|
792
|
+
const burnt = flameLine - (FLAME.length - y);
|
|
793
|
+
const color = mix(HEAT_COLORS.white, flameHeat(y), clamp2(burnt / 4));
|
|
794
|
+
const pixels = [...row].map((dot) => dot === "#" && burnt >= 0 ? color : undefined);
|
|
795
|
+
pixels.push(...Array(LOGO_GAP).fill(undefined));
|
|
796
|
+
const word = WORD_ROWS[y - WORD_TOP] ?? "";
|
|
797
|
+
for (let x = 0;x < wordWidth; x++)
|
|
798
|
+
pixels.push(word[x] === "#" && x < wordEdge ? mix(HEAT_COLORS.orange, HEAT_COLORS.gold, x / wordWidth) : undefined);
|
|
799
|
+
return pixels;
|
|
811
800
|
});
|
|
812
801
|
}
|
|
813
802
|
function fitSubtitle({ version, cwd }, width) {
|
|
@@ -826,45 +815,35 @@ function subtitleLine(subtitle, width, t) {
|
|
|
826
815
|
return paint(mix(FADE_FROM, HEAT_COLORS.ash, ease((t - 0.4) / 0.6)), fitSubtitle(subtitle, width));
|
|
827
816
|
}
|
|
828
817
|
function large(t, subtitle) {
|
|
829
|
-
const
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
function mid(t, subtitle) {
|
|
833
|
-
const word = halfBlocks(wordmark(1, t));
|
|
834
|
-
return sideBySide(halfBlocks(roundFlame(6, 8, t)), [...word, subtitleLine(subtitle, visibleWidth2(word[0]), t)], 2);
|
|
818
|
+
const rows = halfBlocks(logo(t));
|
|
819
|
+
const last = rows.pop().slice(0, WORD_LEFT).join("") + subtitleLine(subtitle, LOGO_WIDTH - WORD_LEFT, t);
|
|
820
|
+
return [...rows.map((row) => row.join("").trimEnd()), last];
|
|
835
821
|
}
|
|
836
822
|
function tiny(width, t, glyph, subtitle) {
|
|
837
|
-
const
|
|
838
|
-
const letters = [...WORD].map((char, index) =>
|
|
839
|
-
if (t <= index / WORD.length * REVEAL_END)
|
|
840
|
-
return " ";
|
|
841
|
-
const shine = t > REVEAL_END && t < SWEEP_END ? clamp2(1 - Math.abs(index - sweep) / 2) : 0;
|
|
842
|
-
return paint(mix(mix(HEAT_COLORS.orange, HEAT_COLORS.gold, index / (WORD.length - 1)), HEAT_COLORS.white, shine), char);
|
|
843
|
-
}).join("");
|
|
823
|
+
const shown = Math.ceil((t - REVEAL_START) / (SETTLE_END - REVEAL_START) * WORD.length);
|
|
824
|
+
const letters = [...WORD].map((char, index) => index < shown ? char : " ").join("");
|
|
844
825
|
const word = `${glyph} \x1B[1m${letters}\x1B[22m `;
|
|
845
826
|
const room = width - visibleWidth2(word) - 1 - TINY_RULE_MIN;
|
|
846
827
|
const head = room >= TINY_SUBTITLE_MIN ? `${word}${subtitleLine(subtitle, room, t)} ` : word;
|
|
847
828
|
const length = width - visibleWidth2(head);
|
|
848
|
-
const reveal = clamp2((t -
|
|
829
|
+
const reveal = clamp2((t - REVEAL_START) / (SETTLE_END - REVEAL_START));
|
|
849
830
|
let rule = "";
|
|
850
831
|
for (let index = 0;index < length; index++)
|
|
851
832
|
rule += index / length <= reveal ? paint(mix(HEAT_COLORS.gold, RULE2, ease(index / Math.max(8, length * 0.7))), "─") : " ";
|
|
852
833
|
return clip(head + rule, width, "end", "");
|
|
853
834
|
}
|
|
854
835
|
function center(lines, width) {
|
|
855
|
-
const pad = " ".repeat(Math.max(0, Math.floor((width -
|
|
836
|
+
const pad = " ".repeat(Math.max(0, Math.floor((width - LOGO_WIDTH) / 2)));
|
|
856
837
|
return lines.map((line) => clip(pad + line, width, "end", ""));
|
|
857
838
|
}
|
|
858
839
|
function banner(width, t, glyph, subtitle) {
|
|
859
840
|
if (width >= LARGE_MIN_WIDTH)
|
|
860
841
|
return ["", ...center(large(t, subtitle), width), ""];
|
|
861
|
-
if (width >= MID_MIN_WIDTH)
|
|
862
|
-
return ["", ...center(mid(t, subtitle), width), ""];
|
|
863
842
|
return [tiny(width, t, glyph, subtitle), ""];
|
|
864
843
|
}
|
|
865
844
|
function createBanner(tui, subtitle) {
|
|
866
845
|
const start = Date.now();
|
|
867
|
-
const elapsed = () => Math.min(
|
|
846
|
+
const elapsed = () => Math.min(SETTLE_END, (Date.now() - start) / 1000);
|
|
868
847
|
let unsubscribe;
|
|
869
848
|
const dispose = () => {
|
|
870
849
|
unsubscribe?.();
|
|
@@ -872,7 +851,7 @@ function createBanner(tui, subtitle) {
|
|
|
872
851
|
};
|
|
873
852
|
unsubscribe = onFrame(() => {
|
|
874
853
|
tui.requestRender();
|
|
875
|
-
if (elapsed() >=
|
|
854
|
+
if (elapsed() >= SETTLE_END)
|
|
876
855
|
dispose();
|
|
877
856
|
});
|
|
878
857
|
let frozenGlyph;
|
|
@@ -882,7 +861,7 @@ function createBanner(tui, subtitle) {
|
|
|
882
861
|
dispose,
|
|
883
862
|
render(width) {
|
|
884
863
|
const t = elapsed();
|
|
885
|
-
if (t <
|
|
864
|
+
if (t < SETTLE_END)
|
|
886
865
|
return banner(width, t, flame(3, TINY_FLAME_PHASE), subtitle);
|
|
887
866
|
if (frozen?.width !== width) {
|
|
888
867
|
frozenGlyph ??= flame(3, TINY_FLAME_PHASE);
|