pi-claude-code-ui 1.0.83 → 1.0.85
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/CHANGELOG.md +10 -0
- package/README.md +3 -3
- package/extensions/index.ts +514 -119
- package/extensions/settings-path.ts +4 -0
- package/extensions/spinner.ts +63 -18
- package/package.json +4 -2
package/extensions/spinner.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import net from "node:net";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
3
5
|
|
|
4
6
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
5
7
|
import { Loader } from "@earendil-works/pi-tui";
|
|
6
8
|
|
|
9
|
+
import { getUserSettingsPath } from "./settings-path";
|
|
10
|
+
|
|
7
11
|
// ---------------------------------------------------------------------------
|
|
8
12
|
// Patch built-in Loader with Claude/OpenBrawd-style glyphs.
|
|
9
13
|
// Keep animation cadence constant so the spinner doesn't appear to slow down
|
|
@@ -44,7 +48,7 @@ function readSpinnerSettings(): { adaptive: boolean; verbColor: string; statusCo
|
|
|
44
48
|
// orange as the glyph on themes like openAntigravity-dark.
|
|
45
49
|
let verbColor = "borderAccent";
|
|
46
50
|
let statusColor = "muted";
|
|
47
|
-
const paths = [`${process.cwd()}/.pi/settings.json`,
|
|
51
|
+
const paths = [`${process.cwd()}/.pi/settings.json`, getUserSettingsPath()];
|
|
48
52
|
for (const p of paths) {
|
|
49
53
|
try {
|
|
50
54
|
if (!p || !existsSync(p)) continue;
|
|
@@ -517,7 +521,9 @@ function statusText(text: string): string {
|
|
|
517
521
|
// This extension replaces that text with themed spinner verbs (Cooking…,
|
|
518
522
|
// Syncing…, …), so herdr sidebars go idle/stale while pi is actually busy.
|
|
519
523
|
// When running inside herdr (HERDR_ENV=1), report working/idle over the
|
|
520
|
-
// socket
|
|
524
|
+
// socket only when herdr's official pi integration is not installed. The
|
|
525
|
+
// official integration owns the same lifecycle authority and must remain the
|
|
526
|
+
// sole reporter when present. UI is unchanged.
|
|
521
527
|
// ---------------------------------------------------------------------------
|
|
522
528
|
|
|
523
529
|
type HerdrAgentState = "working" | "idle";
|
|
@@ -532,9 +538,33 @@ const HERDR_PANE_ID = process.env.HERDR_PANE_ID;
|
|
|
532
538
|
// Must be exactly "herdr:pi" — herdr only grants full lifecycle authority
|
|
533
539
|
// (skip screen-manifest fallback) to that official source pair with agent "pi".
|
|
534
540
|
const HERDR_SOURCE = "herdr:pi";
|
|
541
|
+
const HERDR_INTEGRATION_MARKER = "HERDR_INTEGRATION_ID=pi";
|
|
542
|
+
let officialHerdrIntegrationInstalled: boolean | undefined;
|
|
543
|
+
|
|
544
|
+
function hasOfficialHerdrIntegration(): boolean {
|
|
545
|
+
if (officialHerdrIntegrationInstalled !== undefined) {
|
|
546
|
+
return officialHerdrIntegrationInstalled;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
const agentDir = process.env.PI_CODING_AGENT_DIR
|
|
550
|
+
|| join(homedir(), ".pi", "agent");
|
|
551
|
+
|
|
552
|
+
try {
|
|
553
|
+
const integrationPath = join(agentDir, "extensions", "herdr-agent-state.ts");
|
|
554
|
+
officialHerdrIntegrationInstalled =
|
|
555
|
+
existsSync(integrationPath)
|
|
556
|
+
&& readFileSync(integrationPath, "utf8").includes(HERDR_INTEGRATION_MARKER);
|
|
557
|
+
} catch {
|
|
558
|
+
officialHerdrIntegrationInstalled = false;
|
|
559
|
+
}
|
|
560
|
+
return officialHerdrIntegrationInstalled;
|
|
561
|
+
}
|
|
535
562
|
|
|
536
563
|
function herdrEnabled(): boolean {
|
|
537
|
-
return HERDR_ENV === "1"
|
|
564
|
+
return HERDR_ENV === "1"
|
|
565
|
+
&& !!HERDR_SOCKET_PATH
|
|
566
|
+
&& !!HERDR_PANE_ID
|
|
567
|
+
&& !hasOfficialHerdrIntegration();
|
|
538
568
|
}
|
|
539
569
|
|
|
540
570
|
function herdrSendAttempt(request: unknown, timeoutMs: number): Promise<boolean> {
|
|
@@ -754,7 +784,12 @@ export default function (pi: ExtensionAPI) {
|
|
|
754
784
|
}
|
|
755
785
|
|
|
756
786
|
function syncWorkingMessage(force = false): void {
|
|
757
|
-
|
|
787
|
+
try {
|
|
788
|
+
if (!activeCtx?.hasUI) return;
|
|
789
|
+
} catch {
|
|
790
|
+
// Session replacement/reload invalidated the captured context.
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
758
793
|
// Re-derive colors on every tick so /cc-spinner verb/status changes
|
|
759
794
|
// take effect within ~250 ms without waiting for the next pi event.
|
|
760
795
|
// applyThemeColors is identity-cached on (theme, verbKey, statusKey) so
|
|
@@ -770,7 +805,12 @@ export default function (pi: ExtensionAPI) {
|
|
|
770
805
|
|
|
771
806
|
function restoreDefaultWorkingMessage(): void {
|
|
772
807
|
lastWorkingMessage = null;
|
|
773
|
-
|
|
808
|
+
try {
|
|
809
|
+
if (!activeCtx?.hasUI) return;
|
|
810
|
+
} catch {
|
|
811
|
+
// Session replacement/reload invalidated the captured context.
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
774
814
|
try {
|
|
775
815
|
activeCtx.ui.setWorkingMessage();
|
|
776
816
|
} catch { /* noop */ }
|
|
@@ -1002,20 +1042,25 @@ export default function (pi: ExtensionAPI) {
|
|
|
1002
1042
|
clearThoughtStatusTimer();
|
|
1003
1043
|
}
|
|
1004
1044
|
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
completionTimer =
|
|
1013
|
-
|
|
1045
|
+
try {
|
|
1046
|
+
if (activeCtx?.hasUI) {
|
|
1047
|
+
const message = `${STATUS_DIM}✻ Turn took ${formatDuration(elapsed)}${RESET}`;
|
|
1048
|
+
lastWorkingMessage = message;
|
|
1049
|
+
try {
|
|
1050
|
+
activeCtx.ui.setWorkingMessage(message);
|
|
1051
|
+
} catch { /* noop */ }
|
|
1052
|
+
completionTimer = setTimeout(() => {
|
|
1053
|
+
completionTimer = null;
|
|
1054
|
+
if (activeTurnId !== turnId) return;
|
|
1055
|
+
restoreDefaultWorkingMessage();
|
|
1056
|
+
}, TURN_COMPLETION_MS);
|
|
1057
|
+
unrefTimer(completionTimer);
|
|
1058
|
+
} else if (typeof thinkingStatus !== "number") {
|
|
1014
1059
|
restoreDefaultWorkingMessage();
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1060
|
+
}
|
|
1061
|
+
} catch {
|
|
1062
|
+
// Session replacement/reload invalidated the captured context.
|
|
1063
|
+
return;
|
|
1019
1064
|
}
|
|
1020
1065
|
|
|
1021
1066
|
responseLength = 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-claude-code-ui",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.85",
|
|
4
4
|
"description": "Claude Code-style grouped tool rows for pi with Ctrl+O/Ctrl+Shift+O previews, math rendering, and consistent built-in, MCP, and custom tool rendering",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -30,13 +30,15 @@
|
|
|
30
30
|
"files": [
|
|
31
31
|
"extensions/index.ts",
|
|
32
32
|
"extensions/spinner.ts",
|
|
33
|
+
"extensions/settings-path.ts",
|
|
33
34
|
"extensions/bash-command.ts",
|
|
34
35
|
"config/config.example.json",
|
|
35
36
|
"README.md",
|
|
36
37
|
"CHANGELOG.md"
|
|
37
38
|
],
|
|
38
39
|
"scripts": {
|
|
39
|
-
"test": "node --experimental-strip-types --test scripts
|
|
40
|
+
"test": "node --experimental-strip-types --test scripts/*.test.ts",
|
|
41
|
+
"test:fullscreen": "node scripts/fullscreen-mouse.test.mjs",
|
|
40
42
|
"typecheck": "tsc --noEmit --target ES2022 --module NodeNext --moduleResolution NodeNext --skipLibCheck extensions/index.ts extensions/spinner.ts",
|
|
41
43
|
"pack:dry-run": "npm pack --dry-run",
|
|
42
44
|
"publish:dry-run": "npm publish --dry-run",
|