clean: remove .pi/ config from calvana repo — lives in pi-vs-claude-code now

- Removed all .pi/ (agents, themes, extensions, skills, observatory)
- Removed CLAUDE.md (belongs in parent pi repo)
- Added .pi/ and CLAUDE.md to .gitignore
- Added .pi/ to pledge-now-pay-later/.gitignore
This commit is contained in:
2026-03-04 17:32:20 +08:00
parent ef37ca0c18
commit 59485579ec
46 changed files with 31 additions and 5291 deletions

View File

@@ -41,3 +41,4 @@ next-env.d.ts
# SQLite dev database
*.db
*.db-journal
.pi/

File diff suppressed because it is too large Load Diff

View File

@@ -1,629 +0,0 @@
{
"totalSessions": 4,
"totalEvents": 1539,
"totalToolCalls": 704,
"totalAgentTurns": 67,
"totalErrors": 0,
"totalBlocked": 0,
"totalTokensIn": 9949,
"totalTokensOut": 65517,
"totalCost": 10.289527999999995,
"toolCounts": {
"bash": 284,
"read": 274,
"write": 23,
"edit": 123
},
"toolDurations": {
"bash": [
80,
22554,
28417,
31752,
12155,
31018,
29238,
23209,
116,
92,
92,
95,
30195,
31334,
31809,
32722,
12438,
12724,
18027,
234,
26520,
15779,
13584,
12063,
11889,
31800,
31495,
114,
26556,
106,
125,
110,
58,
79,
92,
102,
131,
115,
106,
90,
100,
4112,
2374,
122,
87,
2360,
89,
1419,
251,
90,
92,
103,
2365,
75,
304,
122,
567,
774,
104,
782,
175,
702,
163,
238,
1479,
322,
409,
149,
144,
85,
2416,
102,
76,
85,
2385,
111,
108,
108,
2412,
115,
2372,
104,
68,
82,
114,
69,
2386,
86,
63,
82,
2346,
141,
2537,
2387,
2390,
110,
133,
75,
88,
90,
2328,
2356,
2383,
2351,
2370,
2368,
2307,
2332,
2362,
2353,
11793,
2377,
2260,
2275,
3295,
850,
15197,
88,
480,
606,
82,
105,
2303,
2354,
2409,
2333,
2433,
2363,
2285,
1779,
15165,
2401,
2779,
474,
490,
96,
4529,
91,
91,
120,
111,
459,
1155,
4729,
464,
2467,
2397,
2368,
2515,
90,
3085,
461,
2506,
2521,
108,
2433,
5339,
2386,
2349,
2333,
2348,
2340,
10149,
2494,
2452,
2335,
2328,
2417,
2449,
3537,
2386,
15127,
2361,
2321,
4433,
3043,
4861,
3690,
3553,
3867,
10120,
2307,
23217,
2494,
3349,
2354,
7740,
1573,
10377,
92,
93,
76,
1615,
109,
2205,
2273,
600,
48957,
796,
128
],
"read": [
25,
26,
28,
36,
44,
39,
40,
37,
40,
28,
27,
27,
36,
44,
40,
35,
42,
40,
36,
40,
40,
66,
38,
39,
38,
44,
37,
40,
53,
40,
39,
43,
41,
39,
43,
53,
42,
43,
40,
25,
27,
26,
35,
41,
66,
39,
53,
42,
45,
59,
48,
51,
24,
25,
27,
30,
30,
33,
28,
25,
30,
29,
5,
46,
19,
4,
14,
12,
24,
27,
27,
29,
29,
29,
3,
5,
5,
40,
43,
40,
41,
44,
57,
52,
41,
6,
3,
58,
5,
24,
29,
16,
6,
14,
5,
35,
46,
41,
51,
43,
54,
37,
4,
3,
7,
5,
3,
3,
3,
9,
6,
5,
4,
3,
9,
5,
12,
17,
5,
9,
4,
3,
3,
4,
10,
4,
7,
5,
6,
3,
7,
4,
4,
6,
3,
3,
4,
5,
6,
5,
6,
5,
5,
3,
3,
4,
7,
3,
4,
4,
5,
4,
5,
2,
3,
18,
53,
2,
25,
45,
40,
5,
12,
22,
21,
3,
18,
18,
11,
3,
16,
6,
2,
12,
13,
2,
8,
3,
5,
5,
6,
4,
10,
9,
6,
13,
7,
10,
19,
10,
19,
5,
5,
5,
13,
3,
8,
29,
3,
5
],
"write": [
15,
22,
7,
18,
9,
7,
15,
33,
8,
30,
6,
14,
8,
9,
6,
7,
6,
19,
12,
9,
10,
7,
3
],
"edit": [
147,
13,
13,
19,
22,
14,
16,
6,
9,
6,
10,
18,
13,
14,
13,
24,
11,
32,
35,
30,
16,
32,
9,
9,
10,
7,
8,
9,
8,
8,
8,
9,
6,
6,
5,
6,
6,
5,
23,
9,
9,
10,
8,
7,
8,
6,
4,
8,
28,
10,
6,
16,
9,
21,
29,
17,
14,
11,
6,
8,
7,
6,
8,
16,
38,
12,
24,
14,
11,
14,
16,
21,
10,
10,
10,
15,
16,
16,
36,
15,
31,
25,
7,
15,
16,
10,
15,
17,
18,
14,
14,
21,
8,
18,
10,
37,
11,
17,
14,
13,
22,
15,
20,
9,
11,
12,
10,
11,
9,
11,
8,
11,
9,
15,
9,
21,
8,
8,
33,
24,
6,
12,
4
]
},
"toolBlocked": {},
"sessions": [
{
"sessionId": "zlkjkn",
"startedAt": 1772554827283,
"model": "claude-opus-4-6",
"toolCalls": 390,
"agentTurns": 43,
"errors": 0,
"blocked": 0,
"tokensIn": 2192,
"tokensOut": 57348,
"cost": 8.716851999999998,
"peakContextPercent": 92
},
{
"sessionId": "tu9mo8",
"startedAt": 1772569015383,
"model": "claude-opus-4-6",
"toolCalls": 213,
"agentTurns": 21,
"errors": 0,
"blocked": 0,
"tokensIn": 2071,
"tokensOut": 6552,
"cost": 1.3847744999999998,
"peakContextPercent": 94
},
{
"sessionId": "yemv0x",
"startedAt": 1772573646207,
"model": "claude-opus-4-6",
"toolCalls": 94,
"agentTurns": 1,
"errors": 0,
"blocked": 0,
"tokensIn": 0,
"tokensOut": 0,
"cost": 0,
"peakContextPercent": 21
},
{
"sessionId": "n1rfud",
"startedAt": 1772574770468,
"model": "claude-opus-4-6",
"toolCalls": 7,
"agentTurns": 2,
"errors": 0,
"blocked": 0,
"tokensIn": 5686,
"tokensOut": 1617,
"cost": 0.18790150000000003,
"peakContextPercent": 9
}
],
"lastUpdated": 1772603919532
}

View File

@@ -37,8 +37,9 @@ incus exec ${CONTAINER} -- bash -c '
# BuildKit build with npm + Next.js cache mounts
docker buildx build -t pnpl-app:latest --load . 2>&1 | tail -8
# Rolling restart
docker service update --force --image pnpl-app:latest pnpl_app 2>&1 | tail -2
# Restart via docker compose (matches Dokploy)
cd /etc/dokploy/compose/pnpl/code
docker compose -p pnpl up -d --force-recreate app 2>&1 | tail -4
# Clean dangling only (preserve build cache!)
docker image prune -f 2>&1 | tail -1

View File

@@ -115,104 +115,52 @@ const GALLERY_IMAGES = [
{ src: "/images/brand/youth-01-workshop.jpg", alt: "Youth workshop in full swing" },
]
/* Slide directions: [incoming start offset, outgoing end offset] as CSS translate values */
const SLIDES: [string, string][] = [
["translateX(100%)", "translateX(-100%)"], // from right
["translateX(-100%)", "translateX(100%)"], // from left
["translateY(100%)", "translateY(-100%)"], // from bottom
["translateY(-100%)", "translateY(100%)"], // from top
]
const DURATION = 420 // ms — snappy
const INTERVAL = 3500
const SLIDE_DIR: [string, string] = ["translateX(100%)", "translateX(-100%)"] // slide from right
const SLIDE_SPEED = 150 // ms — fast snap-slide
const SLIDE_INTERVAL = 3500
function GallerySlideshow() {
const [idx, setIdx] = useState(0)
const [prevIdx, setPrevIdx] = useState(-1)
const [phase, setPhase] = useState<"idle" | "prep" | "go">("idle")
const dirRef = useRef(SLIDES[0])
const dirRef = useRef(SLIDE_DIR)
const inRef = useRef<HTMLDivElement>(null)
const outRef = useRef<HTMLDivElement>(null)
// Pick random direction and kick off transition
const advance = useCallback(() => {
dirRef.current = SLIDES[Math.floor(Math.random() * SLIDES.length)]
setIdx((i) => {
setPrevIdx(i)
return (i + 1) % GALLERY_IMAGES.length
})
setPhase("prep") // frame 1: position incoming off-screen
setIdx((i) => { setPrevIdx(i); return (i + 1) % GALLERY_IMAGES.length })
setPhase("prep")
}, [])
// Two-frame trick: prep → go
useEffect(() => {
if (phase === "prep") {
// Position incoming element at its start offset (no transition)
const el = inRef.current
if (el) {
el.style.transition = "none"
el.style.transform = dirRef.current[0]
}
const oel = outRef.current
if (oel) {
oel.style.transition = "none"
oel.style.transform = "translate(0,0)"
}
// Next frame: enable transition and snap to final position
requestAnimationFrame(() => {
requestAnimationFrame(() => setPhase("go"))
})
if (inRef.current) { inRef.current.style.transition = "none"; inRef.current.style.transform = dirRef.current[0] }
if (outRef.current) { outRef.current.style.transition = "none"; outRef.current.style.transform = "translate(0,0)" }
requestAnimationFrame(() => requestAnimationFrame(() => setPhase("go")))
}
if (phase === "go") {
const ease = `transform ${DURATION}ms cubic-bezier(0.25, 1, 0.5, 1)`
const el = inRef.current
if (el) {
el.style.transition = ease
el.style.transform = "translate(0,0)"
}
const oel = outRef.current
if (oel) {
oel.style.transition = ease
oel.style.transform = dirRef.current[1]
}
const t = setTimeout(() => {
setPrevIdx(-1)
setPhase("idle")
}, DURATION + 20)
return () => clearTimeout(t)
const t = `transform ${SLIDE_SPEED}ms cubic-bezier(0.16, 1, 0.3, 1)`
if (inRef.current) { inRef.current.style.transition = t; inRef.current.style.transform = "translate(0,0)" }
if (outRef.current) { outRef.current.style.transition = t; outRef.current.style.transform = dirRef.current[1] }
const timer = setTimeout(() => { setPrevIdx(-1); setPhase("idle") }, SLIDE_SPEED + 10)
return () => clearTimeout(timer)
}
}, [phase])
// Auto-advance timer
useEffect(() => {
const t = setInterval(advance, INTERVAL)
const t = setInterval(advance, SLIDE_INTERVAL)
return () => clearInterval(t)
}, [advance])
return (
<div className="relative min-h-[280px] md:min-h-[360px] overflow-hidden bg-gray-100">
{/* Outgoing image */}
{prevIdx !== -1 && (
<div ref={outRef} className="absolute inset-0 z-[1] will-change-transform">
<Image
src={GALLERY_IMAGES[prevIdx].src}
alt={GALLERY_IMAGES[prevIdx].alt}
fill
className="object-cover"
sizes="(max-width: 768px) 100vw, 50vw"
/>
<Image src={GALLERY_IMAGES[prevIdx].src} alt={GALLERY_IMAGES[prevIdx].alt} fill className="object-cover" sizes="(max-width: 768px) 100vw, 50vw" />
</div>
)}
{/* Incoming / current image */}
<div ref={inRef} className="absolute inset-0 z-[2] will-change-transform">
<Image
src={GALLERY_IMAGES[idx].src}
alt={GALLERY_IMAGES[idx].alt}
fill
className="object-cover"
sizes="(max-width: 768px) 100vw, 50vw"
priority={idx === 0}
/>
<Image src={GALLERY_IMAGES[idx].src} alt={GALLERY_IMAGES[idx].alt} fill className="object-cover" sizes="(max-width: 768px) 100vw, 50vw" priority={idx === 0} />
</div>
</div>
)